Мы обновляем наши системы БД до версии MySQL 5.7, начиная с версии MySQL 5.6, и после обновления несколько запросов стали выполняться очень медленно.
После некоторого исследования мы сузили его до нескольких запросов JOIN, которые внезапно больше не слушают предложение «WHERE» при использовании оператора «больше чем» > или «меньше чем» ‹. При использовании оператора '=' он работает так, как ожидалось. При запросе большой таблицы это вызывало постоянную 100% загрузку ЦП.
Запросы были упрощены, чтобы объяснить проблему под рукой; при использовании объяснения мы получаем следующие результаты:
explain
select * from TableA as A
left join
(
select
DATE_FORMAT(created_at,'%H:%i:00') as `time`
FROM
TableB
WHERE
created_at < DATE_ADD(CURDATE(), INTERVAL -3 HOUR)
)
as V ON V.time = A.time
Вывод
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE A NULL ALL NULL NULL NULL NULL 10080 100.00 NULL
1 SIMPLE TableB NULL index created_at created_at 4 NULL 488389 100.00 Using where; Using index; Using join buffer (Block Nested Loop)
Как видите, он запрашивает/сопоставляет 488389 строк и не использует предложение where, поскольку это общее количество записей в этой таблице.
А теперь запустим тот же запрос, но с помощью команды LIMIT 99999999 или оператора '=':
explain
select * from TableA as A
left join
(
select
DATE_FORMAT(created_at,'%H:%i:00') as `time`
FROM
TableB
WHERE
created_at < DATE_ADD(CURDATE(), INTERVAL -3 HOUR) LIMIT 999999999
)
as V ON V.time = A.time
Вывод
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY A NULL ALL NULL NULL NULL NULL 10080 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 244194 100.00 Using where; Using join buffer (Block Nested Loop)
2 DERIVED TableB NULL range created_at created_at 4 NULL 244194 100.00 Using where; Using index
Вы можете видеть, что внезапно совпадают только строки «244194», которые являются частью таблицы, или с оператором «=»:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE A NULL ALL NULL NULL NULL NULL 10080 100.00 NULL
1 SIMPLE TableB NULL ref created_at created_at 4 const 1 100.00 Using where; Using index
Всего 1 ряд, как и ожидалось.
Итак, вопрос сейчас заключается в том, что мы запрашивали неверным образом и только сейчас выяснили это при обновлении, или что-то изменилось с MySQL 5.6? Кажется странным, что оператор = работает, но ‹ и > почему-то игнорируются, разве что при использовании LIMIT?..
Мы искали вокруг и не смогли найти причину этой проблемы, и мы не хотели бы использовать решение limit 9999999 в нашем коде по очевидным причинам.
Примечание. При выполнении только запроса внутри соединения он также работает должным образом.
Примечание Мы также провели тот же тест на MariaDB 10.1 с той же проблемой.