Результаты запроса, занимающие слишком много времени на 200K базе данных, ускорьте подсказки?

У меня есть sql оператор, где я присоединяюсь приблизительно к 4 таблицам, каждому с 200K строками. Выполнения запроса, но продолжает замораживаться. Когда я делаю соединение на 3 таблицах вместо этого, оно возвращается, строки (сопровождает 10secs). Какое-либо предложение, почему? предложения для ускорения?

Спасибо!

Код

SELECT *
FROM equipment, tiremap, workreference, tirework
WHERE equipment.tiremap = tiremap.`TireID` AND 
      tiremap.`WorkMap` = workreference.`aMap` AND
      workreference.`bMap` = tirework.workmap
LIMIT 5

p.s

и если это помогает кому-либо, я использую sql алхимию, чтобы сгенерировать этот код, код sqlalchemy для этого

query = session.query(equipment, tiremap, workreference, tirework)
query = query.filter(equipment.c.tiremap == tiremap.c.TireID)
query = query.filter(tiremap.c.WorkMap==workreference.c.aMap)
query = query.filter(workreference.c.bMap == tirework.c.workmap)
query = query.limit(5)
query.all()
5
задан Larry Lustig 17 April 2010 в 01:49
поделиться

4 ответа

Убедитесь, что у вас есть индексы:

  • оборудование (карта шин)
  • карта шин (TireID)
  • карта шин (WorkMap)
  • рабочая ссылка (aMap)
  • рабочая ссылка (bMap)
  • шины ( workmap)

Edit: Думаю, для полноты я должен предоставить некоторый контекст для этого.

Оптимизатор SQL просматривает оператор, анализирует его, а затем определяет план выполнения для него на основе запроса, таблиц, на которые имеются ссылки, и доступных индексов. Если вы выполните SELECT * FROM tab1 , тогда будет выполнено полное сканирование таблицы tab1, потому что другого способа выполнить это нет.

Если вы сделаете SELECT * FROM person WHERE lastname LIKE 'V%' и у вас будет миллион записей, запросить каждую строку будет медленно, но если фамилия проиндексирована, она намного эффективнее.

В запросе, подобном вашему, одна из этих таблиц будет управляющей таблицей, которую, независимо от индексов, можно просто выполнить как полное сканирование таблицы. В этом нет ничего плохого. Одна таблица должна управлять запросом. Если есть предложение WHERE (для чего-то другого, кроме условий соединения), это может измениться, но в противном случае это обычно истина.

Из этой управляющей таблицы MySQL затем начнет добавлять объединения в план выполнения. Эти соединения потребуют индексов на другой стороне для эффективной работы.

Таким образом, с тремя таблицами у вас может быть одна таблица, которая не индексируется, но это не имеет значения, потому что она управляет запросом. В четвертой таблице могут быть две неиндексированные таблицы, и теперь это проблема, потому что для каждой строки в одной MySQL придется выполнить полное сканирование таблицы другой.

По сути, вы создаете индекс для каждого внешнего ключа и столбца соединения, чтобы MySQL мог использовать то, что доступно, чтобы составить лучший план выполнения для запроса, который вы ему задаете.

Наконец, большинство инструментов расскажут вам о схеме базы данных. PHPMyAdmin - популярный инструмент для размещенных баз данных. Лично мне нравится настольное приложение для такого рода вещей. Navicat Lite - достойный бесплатный инструмент для этого.

5
ответ дан 14 December 2019 в 13:30
поделиться

Возможно, четвертый стол, к которому вы присоединяетесь, намного больше, чем другие. Также может быть, что столбец, к которому вы присоединяетесь, не имеет индекса.

0
ответ дан 14 December 2019 в 13:30
поделиться

Вы выполняете естественное соединение 4 таблиц. Кроме того, в вашем заявлении "WHERE" нет особых условий.

Механизм базы данных сделает следующее:

Сначала он выполнит рекурсивное произведение всех данных в каждой таблице.

Рассмотрим следующие строки в таблицах A, B и C:

A = rowA1
    rowA2
    rowA3;
B = rowB1
    rowB2
    rowB3;
C = rowC1
    rowC2
    rowC3;

В принципе, если вы выполните естественное соединение этих трех таблиц, движок будет иметь в памяти:

rowA1 - rowB1 - rowC1
rowA1 - rowB1 - rowC2
rowA1 - rowB1 - rowC3
rowA1 - rowB2 - rowC1
rowA1 - rowB2 - rowC2
rowA1 - rowB2 - rowC3
rowA1 - rowB3 - rowC1
rowA1 - rowB3 - rowC2
rowA1 - rowB3 - rowC3
...
...
...
rowA3 - rowB3 - rowC1
rowA3 - rowB3 - rowC2
rowA3 - rowB3 - rowC3

Всего в память помещается 27 строк . Однако нам нужны только 3 строки:

rowA1 - rowB1 - rowC1
rowA2 - rowB2 - rowC2
rowA3 - rowB3 - rowC3

Если ваш механизм базы данных не выполняет оптимизацию сам по себе, естественное объединение 3-х таблиц очень дорого.Для 4 таблиц это немыслимо даже для ограниченного числа строк.

Итак, как мы можем улучшить что-то?

Во-первых, глядя на код, мы знаем, что нам нужно всего 5 значений. Кроме того, при оптимизации базы данных говорится, что вы должны сделать SELECT как можно раньше.

Вот непроверенный код, который должен вам помочь. Возможно, вам придется изменить его, в зависимости от того, какой движок БД вы используете:

SELECT *
FROM (SELECT * FROM equipment LIMIT 5) e, tiremap, workreference, tirework
WHERE e.tiremap = tiremap.TireID AND
      tiremap.WorkMap = workreference.`aMap` AND
      workreference.`bMap` = tirework.workmap

Просто сделав это, вы должны почувствовать, что у нас есть только 3 таблицы, а не 4. Тем не менее, это не совсем то, что вам нужно. Если одна строка «оборудования» не упоминается в других таблицах, в конце вы получите менее 5 строк. Однако это пример, чтобы показать вам, что на самом деле нам могут не понадобиться все строки из всех таблиц.

Я думаю, что вы хотите, может быть следующее:

SELECT * FROM equipment 
INNER JOIN tiremap ON equipment.tiremap = tiremap.TireID
INNER JOIN workreference ON tiremap.WorkMap = workreference.aMap
INNER JOIN tirework ON workreference.bMap = tirework.workmap
LIMIT 5

У вас может быть проблема: если ваш движок не так хорош (mySQL, извините), это может занять много времени.

Если вы действительно хотите провести оптимизацию самостоятельно:

SELECT * FROM tirework, 
   (SELECT * FROM workreference, 
       (SELECT * FROM tiremap,
           (SELECT * FROM equipment) e
        WHERE e.tiremap = tiremap.TireID) t
    WHERE t.WorkMap = workreference.aMap) w
WHERE w.bMap = tirework.workmap
LIMIT 5

И вуаля! Даже если ваш оптимизатор движка не существует, этот запрос не должен занять слишком много времени. Вместо того, чтобы делать большой продукт из всего, ваш движок будет делать по одному продукту за раз и удалять плохие строки, прежде чем объединить его с новой таблицей.

Попробуйте.

1
ответ дан 14 December 2019 в 13:30
поделиться

В большинстве баз данных SQL есть варианты «EXPLAIN PLAN» или «EXPLAIN», которые можно использовать, чтобы увидеть, как выполняется синтаксический анализ запроса. Ищите полное сканирование таблицы как место, где вам нужны индексы.

0
ответ дан 14 December 2019 в 13:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: