Оптимизировать SQL-запрос - PullRequest
       10

Оптимизировать SQL-запрос

4 голосов
/ 15 февраля 2010

Я пытаюсь оптимизировать этот медленный запрос (> 2 с)

SELECT COUNT(*)
FROM crmentity c, mdcalls_trans_activity_update mtu, mdcalls_trans mt
WHERE (mtu.dept = 'GUN' OR  mtu.dept = 'gun') AND
      mtu.trans_code = mt.trans_code AND
      mt.activityid = c.crmid AND
      MONTH(mtu.ts) = 2 AND
      YEAR(mtu.ts) = YEAR(NOW()) AND
      c.deleted = 0 AND
      c.smownerid = 28

Это вывод, когда я использую EXPLAIN:

id  select_type table   type    possible_keys   key key_len ref rows    Extra   
1   SIMPLE  c   index_merge PRIMARY,crmentity_smownerid_idx,crmentity_deleted_smownerid_idx,crmentity_smownerid_deleted_idx crmentity_smownerid_idx,crmentity_deleted_smownerid_idx 4,8 NULL    91  Using intersect(crmentity_smownerid_idx,crmentity_deleted_smownerid_idx); Using where; Using index
1   SIMPLE  mt  ref activityid  activityid  4   pharex.c.crmid  60  
1   SIMPLE  mtu ref dept_idx    dept_idx    5   const   1530    Using where

Он использует созданный мной индекс (dept_idx), но для выполнения запроса к набору данных из 1380384 записей все равно требуется более 2 секунд. Есть ли другой способ выразить этот запрос оптимальным образом?

ОБНОВЛЕНИЕ : Используя предложения Дэвида, запрос теперь сокращается до нескольких миллисекунд вместо того, чтобы выполняться более 2 секунд (фактически, 51 секунда в версии 5.0 MySQL).

Ответы [ 5 ]

6 голосов
/ 15 февраля 2010

Что является наиболее избирательной частью предложения WHERE? То есть, какое условие удаляет наиболее потенциальные элементы из набора результатов?

Полагаю, это фильтр mtu.ts. Если это так, вам также следует проиндексировать столбец mtu.ts и попытаться ограничить его таким образом, чтобы индекс мог использоваться; например, с помощью оператора BETWEEN.

Другие советы:

  • Присоединяйте предложения о соединении непосредственно к соединению с помощью JOIN ... ON (), это значительно облегчает чтение запроса как для людей, так и для оптимизатора
  • Избегайте вычисления констант в запросе, например YEAR(NOW())
  • Избегайте функций выбранных столбцов в предложении WHERE, например MONTH(mtu.ts). Это уменьшает возможности массового использования индексов.
  • Нормализуйте свои данные, чтобы избежать проблем с оболочкой, таких как mtu.dept = 'GUN' OR mtu.dept = 'gun'; один UPDATE mtu SET dept = lower(dept) и соответствующий CHECK dept = lower(dept) на столе помогут избежать такого безумия.
2 голосов
/ 15 февраля 2010
  1. Я бы переписал запрос, используя соединения. Это более понятно и дает оптимизатору больше шансов.
  2. MONTH (mtu.ts) = 2 AND YEAR (mtu.ts) = YEAR (NOW ()) - лучше использовать mtu.ts между .. и ..
0 голосов
/ 15 февраля 2010

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

То есть, упорядочите свой запрос так, чтобы вначале происходили самые отборные вещи. Что более вероятно в ваших данных, это dept = 'GUN' или что userId будет 28.

Наконец, вы рассматривали возможность присоединиться к MT и MTU вместо фильтрации? Это может сделать ваш запрос намного быстрее, поскольку вы будете ограничивать объем данных, для которых требуется сравнение дат.

0 голосов
/ 15 февраля 2010

Самым очевидным решением, которое я вижу, было бы изменить COUNT (*) так, чтобы оно охватывало только одно имя поля, иначе ваш индекс может оказаться почти бесполезным!

0 голосов
/ 15 февраля 2010

Не могли бы вы изменить текстовую строку на число?

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