如何在 MySQL 中创建条件索引?

Man*_*ero 25 mysql index filtered-index

如何在 MySQL 中创建索引来过滤表的特定范围或子集?AFAIK 无法直接创建,但我认为可以模拟此功能。

示例:我想为NAME列创建一个索引,仅用于行STATUS = 'ACTIVE'

此功能在 SQL Server 中称为过滤索引,在 Postgres 中称为部分索引

Bac*_*cco 11

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`)
);
Run Code Online (Sandbox Code Playgroud)

然后在主表中添加三个触发器:

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 ;
Run Code Online (Sandbox Code Playgroud)

我们需要delimiter //是因为我们想;在触发器内部使用。

这样,辅助表将包含与包含字符串“ACTIVE”的主表行对应的 ID,这些行由触发器更新。

要在 a 上使用它select,您可以使用通常的join

SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
   ON auxiliary_table.id = main_table.id
   ORDER BY auxiliary_table.name;
Run Code Online (Sandbox Code Playgroud)

如果主表已经包含数据,或者如果您进行了一些以异常方式更改数据的外部操作(例如:在 MySQL 之外),您可以使用以下方法修复辅助表:

INSERT INTO auxiliary_table SET
   id = main_table.id,
   name = main_table.name,
   WHERE main_table.status="ACTIVE";
Run Code Online (Sandbox Code Playgroud)

关于性能,可能您的插入、更新和删除速度较慢。只有当您真正处理所需条件为正的少数情况时,这才有意义。即便如此,可能只有测试您才能看到节省的空间是否真的证明这种方法是合理的(以及您是否真的节省了任何空间)。


小智 7

如果我正确理解了这个问题,我认为可以完成您想要做的是在两列 NAME 和 STATUS 上创建索引。这将有效地允许您查询 NAME='SMITH' 和 STATUS='ACTIVE'

  • 好的,但是如果您的状态为 ACTIVE 的行相对较少,那么这不是空间效率。 (2认同)
  • 是的,这不是直接要求,所以我以 OK 开始评论。我正在寻找一些专业的替代品。专业的替代方案总是在寻找最有效的方式来完成您的任务。你的答案可能是最明显的。没有问题。但我完全不同意“磁盘空间便宜”,不是因为它很贵,当然便宜但是内存并不便宜,内存有低限制,索引应该主要存在于内存上才能有效。磁盘访问并不便宜。您的答案当然是实现目标的一种正确方法,但我怀疑它是最好的方法。 (2认同)

Jon*_*han 5

您不能进行条件索引,但对于您的示例,您可以在 ( name, status)上添加多列索引。

即使它会索引这些列中的所有数据,它仍然会帮助您找到状态为“活动”的名称。