Почему индекс (по столбцу первичного ключа) не используется?

0

У меня есть таблица с 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 секунд, я знал, что что-то было подозрительным, и похоже, причина в том, что индекс в столбце первичного ключа не используется. Вот мои результаты (извините за использование изображения вместо копирования запросов, но я подумал, что для этого достаточно кратким, а запросы краткие/простые):

Изображение 174551

Прежде всего, странно, что BETWEEN работает иначе, чем с помощью >= и <=. Во-вторых, похоже, что индекс используется только для постоянных значений. Если вы посмотрите внимательно, вы увидите, что с правой стороны (где >= и <= используется), он показывает ~ 9K строк, что составляет половину строк в таблице (таблица имеет около ~ 18k строк, даты от 2000-01-01 до '2050-12-31).

  • 0
    Имеет ли это значение, если вы храните LAST_DAY(SYSDATE()) в переменной и используете это вместо этого в запросе?
  • 3
    Вы знаете, что такое первичный ключ?
Показать ещё 9 комментариев
Теги:
indexing
between
primary-key

2 ответа

0
Лучший ответ

Похоже, если я использую 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());

Дайте тот же результат:

Изображение 174551

Я приму свой ответ как решение, но я все еще ищу объяснения. Я думал, что это может что-то сделать, SYSDATE() не является DATE, но NOW() также не является DATE...

EDIT: Забыл добавить, BETWEEN также работает, как я вижу.

  • 0
    Разве они не все на самом деле DATETIME ? Или это просто DATE ?
  • 0
    dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html - NOW () и SYSDATE () - это DATETIME, но CURRENT_DATE () - это просто DATE. Я не скажу, что понимаю это (и вы даже не можете использовать SYSDATE () как DATE, это не сработает), но ... по крайней мере, это работает.
1

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().

Ещё вопросы

Сообщество Overcoder
Наверх
Меню