MySQL не позволяет создавать индексы на основе выражений / функций, существует обходной путь, который возможен из MySQL 5.7+ с сгенерированными столбцами , которые можно индексировать.Обязательно создайте таблицы как InnoDB, которые могут создавать индексы для несохраненных сгенерированных столбцов.
CREATE TABLE t (
d DATETIME
, dy INT AS (YEAR(d))
, dm INT AS (MONTH(d))
, INDEX(dy, dm)
) Engine = InnoDB ;
Объясните
EXPLAIN
SELECT
*
FROM
t
WHERE
MONTH(d) = MONTH(CURDATE())
AND
YEAR(d) = YEAR(CURDATE())
Результат
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
| --- | ----------- | ----- | ---------- | ---- | ------------- | --- | ------- | --- | ---- | -------- | ----------- |
| 1 | SIMPLE | t | | ALL | dy | | | | 19 | 78.95 | Using where |
см. демо
Да, я знаю, что написано ALL
, но MySQL прямо здесь.В результате возвращено 15 записей, в таблице 19 записей.
Кроме того, вам нужно знать, что выходные строки в выходных данных объяснения - это ожидаемое число отключенных записей для механизма InnoDB, а не действительное число.
Но в 15 раз произвольный дисковый ввод-вывод (6 мс * 15) и потоковая передача (много) обходятся дороже, чем полное сканирование таблицы, которое выполняет один случайный дисковый ввод-вывод (6 мс * 1) и может передавать данные за одинидти.
Оптимизатор / выполнение MySQL основан на затратах, которые вычисляют относительные затраты на основе случайных дисковых операций ввода-вывода, которые являются самыми дорогими.
Но обратите внимание, что он сказал возможный ключ dy
MySQL знает, что он может использоватьиндекс теперь для
WHERE
MONTH(d) = MONTH(CURDATE())
AND
YEAR(d) = YEAR(CURDATE())
Только MySQL думал, что я не собираюсь делать больше работы, читая индекс.
Все еще жду, пока MySQL поддержит выражения / функциональные индексывозможно они добавляют позже версию MySQL 8.MySQL 8 все еще работает и получает обновления.
CREATE INDEX index_name ON table (YEAR(d));
Но я думаю, что в ближайшее время этого не произойдет, MySQL поддерживает его более или менее с помощью обходного пути, который я использовал, поэтому он не думает, что они спешат реализоватьэто ..
MySQL до MySQL 8.0.16 также не поддерживал ограничения CHECK, они также не спешили его реализовывать, потому что MySQL уже поддерживал его более или менее с VIEW с CHECKВАРИАНТ , чтобы привести хороший пример.
Редактировать:
Похоже, скоро я говорил, что MySQL не будет поддерживать это выражение функции / функциональные индексы в ближайшее время.
я заметил MySQL 8.0.13 обновить добавленные выражения / функциональные индексы.
Функциональные ключевые части
«Нормальный» индекс индексирует значения столбцов или префиксы значений столбцов.Например, в следующей таблице запись индекса для данной строки t1 включает полное значение col1 и префикс значения col2, состоящий из его первых 10 символов:
MySQL 8.0.13 и выше поддерживает функциональный ключчасти, которые индексируют значения выражения, а не значения префикса столбца или столбца.Использование функциональных ключевых частей позволяет индексировать значения, которые не хранятся непосредственно в таблице.Примеры:
CREATE TABLE t1 (col1 INT, col2 INT, INDEX func_index ((ABS(col1))));
CREATE INDEX idx1 ON t1 ((col1 + col2)); CREATE INDEX idx2 ON t1
((col1 + col2), (col1 - col2), col1); ALTER TABLE t1 ADD INDEX ((col1
* 40) DESC);
см. source
В MySQL 8.0.13+ вы можете сделать
CREATE INDEX index_name ON table (YEAR(created), MONTH(created));