У меня есть таблица с date
(PK). Сценарий CREATE
находится здесь:
CREATE TABLE date_table (
date DATE
,year INT(4)
,month INT(2)
,day INT(2)
,month_pad VARCHAR(2)
,day_pad VARCHAR(2)
,month_name VARCHAR(10)
,year_month_index INT(6)
,year_month_hypname VARCHAR(7)
,year_month_name VARCHAR(15)
,week_day_index INT(1)
,day_name VARCHAR(9)
,week INT(2)
,week_interval VARCHAR(13)
,weekend_fl INT(1)
,quarter_num INT(1)
,quarter_num_pad VARCHAR(2)
,quarter_name VARCHAR(2)
,year_quarter_index INT(6)
,year_quarter_name VARCHAR(7)
,PRIMARY KEY (date)
);
Теперь я хотел бы выбрать строки из этой таблицы с динамическими значениями, используя LAST_DAY()
или DATE_SUB(DATE_FORMAT(SYSDATE(),'%Y-01-01'), INTERVAL X YEAR)
и т.д.
Когда один из моих запросов потерпел неудачу и не выполнялся через 30 секунд, я знал, что что-то было подозрительным, и похоже, причина в том, что индекс в столбце первичного ключа не используется. Вот мои результаты (извините за использование изображения вместо копирования запросов, но я подумал, что для этого достаточно кратким, а запросы краткие/простые):
Прежде всего, странно, что BETWEEN
работает иначе, чем с помощью >=
и <=
. Во-вторых, похоже, что индекс используется только для постоянных значений. Если вы посмотрите внимательно, вы увидите, что с правой стороны (где >=
и <=
используется), он показывает ~ 9K строк, что составляет половину строк в таблице (таблица имеет около ~ 18k строк, даты от 2000-01-01
до '2050-12-31).
Похоже, если я использую CURRENT_DATE()
(или NOW()
) вместо SYSDATE()
, он работает. Оба этих запроса:
SELECT *
FROM date_table t
WHERE 1 = 1
AND t.ddate >= LAST_DAY(CURRENT_DATE()) AND t.ddate <= LAST_DAY(CURRENT_DATE());
SELECT *
FROM date_table t
WHERE 1 = 1
AND t.ddate >= LAST_DAY(NOW()) AND t.ddate <= LAST_DAY(NOW());
Дайте тот же результат:
Я приму свой ответ как решение, но я все еще ищу объяснения. Я думал, что это может что-то сделать, SYSDATE()
не является DATE
, но NOW()
также не является DATE
...
EDIT: Забыл добавить, BETWEEN
также работает, как я вижу.
DATETIME
? Или это просто DATE
?
SYSDATE() возвращает время, в которое оно выполняется. Это отличается от поведения для NOW(), который возвращает постоянное время, указывающее время начала выполнения оператора. (Внутри хранимой функции или триггера NOW() возвращает время, в которое начинает выполняться инструкция функции или запуска.)
- https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sysdate
То есть Оптимизатор не считает это "константой". В противном случае Оптимизатор с нетерпением оценивает любые "постоянные выражения", а затем пытается воспользоваться знанием значения.
См. Также параметр sysdate_is_now
.
Итог: не используйте SYSDATE()
для обычного использования в режиме SYSDATE()
времени; используйте NOW()
или CURDATE()
.
LAST_DAY(SYSDATE())
в переменной и используете это вместо этого в запросе?