Задать вопрос

Какая особенность 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 просмотров
Подписаться 4 Оценить 1 комментарий
Пригласить эксперта
Ответы на вопрос 1
Melkij
@Melkij
PostgreSQL DBA
Посмотрите в explain, что планировщик думает по этим запросам. Есть большое подозрение, что хранимка и константный запрос идут по индексу по id, запрос с переменной - как-то иначе.

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

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

Похожие вопросы