Какая особенность MySQL вызывает такую разницу в обработке запросов?

Приветствую. Предположим, что я хочу из таблицы messages получить данные сообщения, которое на сутки (или более) старше текущего (для текущего у меня есть его id).

Пробный запрос:

SELECT * FROM messages WHERE id = 
  (SELECT MAX(id) FROM messages WHERE 
     id < 40000 AND dt <= DATE_SUB('2016-04-18 23:23:23', INTERVAL 24 HOUR));

Функционирует быстро. Есть индекс на поле dt, хотя не уверен, что он используется в DATE_SUB()
А вот при использовании переменной - намертво глохнет:

SET @myid = 40000;
  (SELECT MAX(id) FROM messages WHERE 
     id < @myid AND dt <= DATE_SUB('2016-04-18 23:23:23', INTERVAL 24 HOUR));

Почему?! В чем особенность запроса?
В рабочем коде я использую хранимую процедуру, в которую передаётся myid. И, опять-таки, работает быстро.

DROP PROCEDURE IF EXISTS `TEST`;
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `TEST`(IN myid INT)
BEGIN
  (SELECT MAX(id) FROM messages WHERE 
     id < myid AND dt <= DATE_SUB('2016-04-18 23:23:23', INTERVAL 24 HOUR));
END$$
DELIMITER ;
CALL TEST(40000);
  • Вопрос задан
  • 395 просмотров
Пригласить эксперта
Ответы на вопрос 1
Melkij
@Melkij
PostgreSQL DBA
Посмотрите в explain, что планировщик думает по этим запросам. Есть большое подозрение, что хранимка и константный запрос идут по индексу по id, запрос с переменной - как-то иначе.

Одна очевидная грабля:
Значение переменной может изменяться во время выполнения запроса.
Константное значение в запросе и аргумент хранимки - не могут.
Соответственно моё предположение: глупый оптимизатор не смотрит, что в запросе переменная никак не изменяется, значит не может просто взять индекс по id и надо делать что-то другое. Скорей всего seq scan - судя по названию таблицы, данных подпадающих под условие dt <= дата куда больше, чем данных под него не попадающих. Для хорошей работы по индексу надо обратное свойство.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы