Вопрос

Как создать индекс для фильтрации определенного диапазона или подмножества таблицы в 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 теперь есть виртуальные столбцы, которые можно использовать для индексов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с dba.stackexchange
scroll top