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 //
потому что мы хотим использовать ;
внутри триггеров.
Таким образом, вспомогательная таблица будет содержать в точности идентификаторы, соответствующие строкам основной таблицы, которые содержат строку «ACTIVE», обновляемую триггерами.
Чтобы использовать это на 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
,status
).Несмотря на то, что он будет индексировать все данные в этих столбцах, он все равно поможет вам найти искомые имена со статусом «активный».
источник
Вы могли бы сделать это, разделив данные между двумя таблицами, используя представления для объединения двух таблиц, когда нужны все данные, и индексируя только одну из таблиц в этом столбце - но я думаю, что это вызовет проблемы с производительностью для запросов, которые должны бегите по всей таблице, если планировщик запросов не является более умным, чем я считаю. По сути, вы бы вручную разбили таблицу (и применили индекс только к одному из разделов).
К сожалению, встроенная функция разделения таблиц не поможет вам в ваших поисках, так как вы не можете применить индекс к одному разделу.
Вы могли бы поддерживать дополнительный столбец с индексом и иметь значение в этом столбце только в том случае, если условие, на котором вы хотите, чтобы индекс основывался, является истинным, но это, вероятно, будет трудоемким и ограниченным (или отрицательным) значением с точки зрения эффективность запросов и экономия места.
источник
MySQL теперь имеет виртуальные столбцы, которые можно использовать для индексов.
источник
select count(*) from foo where id is null ;
decode(status,'ACTIVE',name,null)
например, может быть включен виртуальный столбец .