Результаты запроса занимают слишком много времени на базе данных 200K, советы по ускорению? - PullRequest
5 голосов
/ 17 апреля 2010

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

Спасибо!

код

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 alchemy для генерации этого кода, код 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()

Ответы [ 4 ]

5 голосов
/ 17 апреля 2010

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

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

Редактировать: Полагаю, я должен предоставить некоторый контекст для полноты.

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

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

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

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

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

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

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

1 голос
/ 17 апреля 2010

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

Ядро базы данных сделает следующее:

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

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

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

По сути, если вы выполните естественное объединение этих 3 таблиц, ядро ​​будет иметь в памяти:

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

Если ваш движок базы данных не выполняет оптимизацию сам по себе, естественное объединение трех таблиц очень дорого. Для 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

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

Попробуй.

0 голосов
/ 17 апреля 2010

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

0 голосов
/ 17 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...