2016-02-17 4 views
0

У меня есть запрос на соединение на 2 таблицы. Я делаю этот запрос 2 раза для разбивки на страницы. Я сделал один запрос SQL_CALC_FOUND_ROWS раньше.MySQL Оптимизация запроса

Таблица A содержит 145000 строк Таблица B содержит 91000 строк

Эти MyISAM таблицы.

Таблица А как это:

id  MEDIUMINT(6) UNSIGNED PK 
id_b  MEDIUMINT(6) UNSIGNED INDEX 
rights ENUM ('0', '1', '2', '3', '4', '5', '6', '7', '8') INDEX 
avail  ENUM ('0', '1', '2', '3') INDEX 
del_date DATE INDEX 
... and 40 others fields 

И эти индексы:

rights, avail, del_date 
id_b, rights, avail, del_date 

Таблица B выглядит так:

id  MEDIUMINT(6) UNSIGNED PK 
title  VARCHAR(150) INDEX 
.. and 47 others fields 

Так вот запросы:

SELECT COUNT(*) 
FROM A 
INNER JOIN B ON B.id = A.id_b 
WHERE 
    A.rights NOT IN ('7') 
    AND (A.del_date IS NULL OR A.del_date > '2016-02-17') 
    AND A.avail NOT IN ('0') 
ORDER BY B.title; 

SELECT A.*, B.* 
FROM A 
INNER JOIN B ON B.id = A.id_b 
WHERE 
    A.rights NOT IN ('7') 
    AND (A.del_date IS NULL OR A.del_date > '2016-02-17') 
    AND A.avail NOT IN ('0') 
ORDER BY B.title 
LIMIT 0, 20; 

Первый запрос на самом деле занимает 2 секунды и 2-й 0,3 секунды. Прежде чем пытаться оптимизировать max, который я могу, это иногда занимает 10 секунд или более для запроса SQL_CALC_FOUND_ROWS.

Оптимизация я сделал:

  • подавляют SQL_CALC_FOUND_ROWS и сделать это с 2-запросов.
  • права поля и использовать были TINYINT (4) UNSIGNED, теперь они ENUM
  • Я добавил эти 2 части индексов права, Avail, del_date & id_b, права, воспользоваться, del_date для оптимизации ORDER BY пункт (очень хороший прирост)

Но теперь я заметил, что (A.del_date IS NULL OR A.del_date> '2016-02-17') является причиной медлительности.

Если удалить все это условие (A.del_date IS NULL OR A.del_date> '2016-02-17') или просто A.del_date IS NULL, запрос очень быстро.

Любая помощь будет очень оценена!

+0

Вопросы производительности должны включать в себя «EXPLAIN ANALYZE» и некоторую информацию о размере таблицы, индексе, текущем времени, времени ожидания и т. Д. «Slow» - относительный термин, и нам нужна реальная ценность для сравнения. [MySQL] (http://dba.stackexchange.com/questions/15371/how-do-i-get-the-execution-plan-for-a-view) –

ответ

0

Вместо того, чтобы иметь отдельные индексы столбцов в таблице «A», я бы рекомендовал попробовать составной индекс нескольких полей, соответствующих вашим критериям. Таким образом, движок не требует загрузки всех фактических данных страницы для записи, чтобы подтвердить другие части, но может получить только те, которые содержатся в содержимом, указанном в индексе. Затем те, кто его квалифицирует, считывают фактические страницы данных для остальной части записи.

Глядя на ваш ИНЕКЕ, и так как вы используете НЕ ваши права и флаги готовности, я бы индекс по (del_date, воспользоваться, правами)

Ваш «B» стол, я бы тоже имеют индекс по (id, title) по аналогичным причинам.

+0

Спасибо за ответ. Но, как я писал, у меня есть 2 части индексов: права, avail, del_date и id_b, права, avail, del_date – Amoeba

+1

@ Амеба, да, но из-за НЕ IN, у меня будет del_date в FIRST POSITION, а затем остальные , взгляните на другую должность, где я уточняю индексы и как интерпретируются. http://stackoverflow.com/questions/20460138/mysql-index-usage-query-optimization/20462042#20462042 – DRapp

+0

ok. Сделал это. Запрос счета теперь длится от 1,2 до 1,6 секунды ... Немного лучше. Прочту это сейчас. – Amoeba

1

Первый SELECT, который имеет только COUNT(*), является странным по нескольким причинам ...

  • ORDER BY бесполезен и, возможно, замедляет запрос.
  • Что такое отображение между A и B? Если это 1: 1, то нет необходимости включать что-либо около B. Если есть 0 или 1 B строк для каждого A, тогда вам понадобится JOIN. Если это 1: много, то COUNT будет больше, чем количество строк от A; Это то что ты хочешь? Чтобы исправить это, измените JOIN на EXISTS.

Если вам нужно держать B в запросе, добавьте INDEX(rights, del_date, avail, id_b) (в любом порядке).
Если вам не нужно держать B, то добавьте INDEX(rights, del_date, avail) (в любом порядке).
В любом случае это будет «индекс покрытия» (EXPLAIN скажет «Использование индекса»), и он будет работать быстрее.

OR часто является убийцей производительности - он обычно исключает возможность использования индекса. Пожалуйста, предоставьте EXPLAIN SELECT, чтобы узнать, так ли это здесь.

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

Вам следует подумать о переходе на InnoDB.

При необходимости вы должны избавиться от «из nnn-элементов», тем самым устраняя COUNT(*) или SQL_CALC_FOUND_ROWS.

Для основного запроса проблема заключается в том, что фильтрация находится на одной таблице, а ORDER BY - на другой таблице. Это делает оптимизацию трудной или невозможной.

Смежные вопросы