Как создать условный индекс в MySQL?
-
15-10-2019 - |
Вопрос
Как создать индекс для фильтрации определенного диапазона или подмножества таблицы в MySQL? Afaik, невозможно создать напрямую, но я думаю, что можно имитировать эту функцию.
Пример: я хочу создать индекс для NAME
колонка только для рядов с STATUS = 'ACTIVE'
Эта функциональность будет называться Отфильтрованный индекс в SQL Server и частичный индекс в Postgres.
Решение
MySQL в настоящее время не поддерживает условные индексы.
Чтобы достичь того, что вы спрашиваете (не то, чтобы вы сделали это;)) Вы можете начать создавать вспомогательную таблицу:
CREATE TABLE `my_schema`.`auxiliary_table` (
`id` int unsigned NOT NULL,
`name` varchar(250), /* specify the same way as in your main table */
PRIMARY KEY (`id`),
KEY `name` (`name`)
);
Затем вы добавляете три триггера в основную таблицу:
delimiter //
CREATE TRIGGER example_insert AFTER INSERT ON main_table
FOR EACH ROW
BEGIN
IF NEW.status = 'ACTIVE' THEN
REPLACE auxiliary_table SET
auxiliary_table.id = NEW.id,
auxiliary_table.name = NEW.name;
END IF;
END;//
CREATE TRIGGER example_update AFTER UPDATE ON main_table
FOR EACH ROW
BEGIN
IF NEW.status = 'ACTIVE' THEN
REPLACE auxiliary_table SET
auxiliary_table.id = NEW.id,
auxiliary_table.name = NEW.name;
ELSE
DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
END IF;
END;//
CREATE TRIGGER example_delete AFTER DELETE ON main_table
FOR EACH ROW
BEGIN
DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
END;//
delimiter ;
Нам нужно
delimiter //
Потому что мы хотим использовать;
Внутри триггеров.
Таким образом, вспомогательная таблица будет содержать именно идентификаторы, соответствующие основным рядам таблицы, которые содержат строку «активно», обновляемые триггерами.
Использовать это на select
, вы можете использовать обычный join
:
SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
ON auxiliary_table.id = main_table.id
ORDER BY auxiliary_table.name;
Если основная таблица уже содержит данные или в случае, если вы сделаете некоторую внешнюю операцию, которая необычно изменяет данные (например: вне MySQL), вы можете исправить вспомогательную таблицу с этим:
INSERT INTO auxiliary_table SET
id = main_table.id,
name = main_table.name,
WHERE main_table.status="ACTIVE";
О производительности, вероятно, у вас будут более медленные вставки, обновления и удаления. Это может иметь смысл, только если вы действительно имеете дело с несколькими случаями, когда желаемое условие является положительным. Даже таким образом, вероятно, только тестирование вы можете увидеть, действительно ли пространство оправдывает этот поход (и если вы действительно сохраняете какое -либо пространство).
Другие советы
Если Я правильно понимаю вопрос, я думаю, что достигнет того, что вы пытаетесь сделать, это создать индекс на обоих столбцах, имени и статусе. Это эффективно позволит вам запросить, где name = 'smith' и status = 'Active'
Вы не можете сделать условную индексацию, но для вашего примера вы можете добавить многоцелевой индекс (name
,status
).
Несмотря на то, что он будет индексировать все данные в этих столбцах, это все равно поможет вам найти имена, которые вы ищете со статусом «активны».
Вы можете сделать это, разделив данные между двумя таблицами, используя представления в Соединение двух таблиц, когда все данные необходимы, и индексировав только одну из таблиц на этом столбце - но я думаю, что это вызвало бы проблемы с производительностью для запросов, которые необходимы Запустите всю таблицу, если только планировщик запросов не является более умным, чем я отдаю ему должное. По сути, вы будете вручную разделить таблицу (и придать индекс только одному из раздела).
К сожалению Встроенная функция разделения таблицы Не поможет вам в вашем квесте, так как вы не можете применить индекс к одному разделу.
Вы можете поддерживать дополнительный столбец с индексом и иметь значение в этом столбце только тогда, когда условие, на котором вы хотите, было основано на индексе, является верным, но это, вероятно, будет трудоемким и ограниченным (или отрицательным) значением с точки зрения Эффективность запроса и экономия пространства.
У MySQL теперь есть виртуальные столбцы, которые можно использовать для индексов.