MySQL SELECT работает вечно при изменении соединения - PullRequest
2 голосов
/ 26 августа 2009

У меня есть следующий код SQL:

select val.PersonNo,
       val.event_time,
       clg.number_dialed
  from vicidial_agent_log val
         join
       call_log           clg on date_add('1970-01-01 02:00:00', interval clg.uniqueid second) = val.event_time
 order by val.event_time desc
 limit 100;

, который выполняет и возвращает строки менее чем за 1 секунду. Однако, если я изменю прямое соединение на left outer:

select val.PersonNo,
       val.event_time,
       clg.number_dialed
  from vicidial_agent_log val
         left outer join
       call_log           clg on date_add('1970-01-01 02:00:00', interval clg.uniqueid second) = val.event_time
 order by val.event_time desc
 limit 100;

запрос выполняется вечно и использует ~ 100% ЦП сервера.

Я выполнил explain по обоим запросам, и первый достиг индекса event_time в vicidial_agent_log, а второй игнорирует все индексы. Есть индекс по call_log.uniqueid.

vicidial_agent_log содержит ~ 41 000 строк, call_log содержит ~ 43 000.

Итак, мой вопрос - почему MySQL не затрагивает определенные мной индексы, есть ли способ заставить его это сделать, и если нет, как я могу заставить этот запрос выполняться с приемлемой скоростью?

редактировать

Полное решение:

select val.PersonNo,
       val.event_time,
       cl.number_dialed
  from vicidial_agent_log val
         left outer join
       (select date_add('1970-01-01 02:00:00', interval clg.uniqueid second) as 'converted_date',
               number_dialed
          from call_log clg) cl ON cl.converted_date = val.event_time
 order by val.event_time desc
 limit 100;

Ответы [ 5 ]

3 голосов
/ 26 августа 2009

Когда вы используете LEFT JOIN, таблица LEFT всегда лидирует в MySQL.

В вашем начальном запросе MySQL мог выбрать, какую таблицу сделать ведущим, и он выбрал clg.

Теперь он не может выбирать, и это условие: date_add('1970-01-01 02:00:00', interval clg.uniqueid second) не может быть sargable.

На date_add('1970-01-01 02:00:00', interval clg.uniqueid second) нет индекса, который MySQL мог бы использовать для определения значения val.event_time.

Перепишите ваш запрос следующим образом:

SELECT  val.PersonNo,
        val.event_time,
        clg.number_dialed
FROM    vicidial_agent_log val
LEFT OUTER JOIN
        call_log clg
ON      clg.uniqueid = UNIX_TIMESTAMP(val.event_time) - 7200
ORDER BY
        val.event_time desc
LIMIT 100
1 голос
/ 26 августа 2009

Использование функций в предложениях JOIN или WHERE всегда приводит к хаосу с индексами. Пример:

DATE_ADD('1970-01-01 02:00:00', INTERVAL clg.uniqueid SECOND)

База данных использует индекс uniqueid для поиска значений для преобразования, а не сравнения со столбцом event_time в вашем случае. Если бы это был Oracle с включенными ошибками PLW, вы бы получили уведомление о возможном преобразовании данных из типа данных.

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

JOIN (SELECT DATE_ADD('1970-01-01 02:00:00', INTERVAL clg.uniqueid SECOND) 'converted_date'
        FROM CALL_LOG clg) cl ON cl.converted_date = val.event_time
1 голос
/ 26 августа 2009

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

Решение mck89 может очень хорошо работать, хотя у меня никогда не было причин его использовать ... Мне любопытно, как это получится.

1 голос
/ 26 августа 2009

Первый может использовать индекс, потому что во внутреннем объединении вы фильтруете набор результатов объединения на основе значения столбца (Event_Time), на котором основан индекс ...

Во втором запросе, где вы используете внешнее объединение, вы НЕ фильтруете выходные данные, поэтому необходимо включить все записи в набор результатов независимо от значения event_time, поэтому необходимо выполнить полное сканирование таблицы ...

0 голосов
/ 26 августа 2009

Вы можете использовать ИНДЕКС СИЛЫ

...