2010-02-15 3 views
4

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

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 секунд. Есть ли другой способ выразить этот запрос оптимальным образом?

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

+0

Я бы написал 'WHERE lower (mtu.dept) = 'gun' AND ...', но я предполагаю, что ваша БД уже будет оптимизировать его таким образом. – initall

+0

Я нашел, по крайней мере, в Oracle, используя более низкое значение в запросах, вызванных массовым замедлением. Является ли это причиной более медленного, чем сравнение дополнительных строк ... –

+1

Использование lower() в столбце - хороший способ НЕ использовать любые индексы. Это объясняет ваше замедление. –

ответ

6

Что является наиболее селективной частью статья 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
  1. Я бы переписал запрос, используя соединения. Это более понятно и дает оптимизатору лучшие шансы.
  2. МЕСЯЦ (mtu.ts) = 2 и год (mtu.ts) = YEAR (NOW()) - лучше использовать mtu.ts между .. и ..
+0

Как бы вы переписали это? Еще раз спасибо. – Francis

+1

выберите отсчет (*) из crmentity с внутреннее соединение mdcalls_trans мт на mt.activityid = c.crmid внутреннее соединение mdcalls_trans_activity_update МТУ на mtu.trans_code = mt.trans_code , где mtu.ts между '20100201' и '20100228' и (mtu.dept in ('GUN', 'gun') и c.deleted = 0 и c.smownerid = 28 – burnall

+0

Спасибо за этот пример. Я создал функцию в PHP, чтобы получить дату начала месяца и дату окончания месяца и использовал его в заявлении «BETWEEN». – Francis

0

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

0

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

0

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

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

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

+0

Отправлено слишком быстро, в основном, что говорят Дэвид Шмитт и Бёрнэл! –

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