解决方案
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”的主表行相对应的ID,并由触发器更新。
在 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";
关于性能,您可能会有较慢的插入,更新和删除。仅当您真正处理所需状态是肯定的情况下,这才有意义。即使是这样,也许只能测试您是否可以查看保存的空间是否真的可以证明这种侵犯的合理性(以及您是否真的保存了任何空间)。
其他提示
如果 我正确理解了这个问题,我认为您要完成的工作是在两个列,名称和状态上创建索引。这将有效地允许您查询名称='Smith'和status ='active'的地方
您不能执行有条件的索引,但是就您的示例而言,您可以添加一个多列索引(name
,status
).
即使它将在这些列中索引所有数据,它仍然可以帮助您找到以“活动”状态的名称。
您可以通过将数据分配在两个表之间,使用视图在需要所有数据时使用视图来结合两个表,并在该列上仅索引一个表 - 但是我认为这将导致需要查询的性能问题除非查询计划者比我赋予的荣誉要聪明,否则在整个桌子上运行。从本质上讲,您将手动对表进行分区(并将索引仅适用于其中一个分区)。
不幸的是 内置表分区功能 无法帮助您的任务,因为您无法将索引应用于单个分区。
您可以使用索引维护额外的列,并且在您希望索引的条件基于的条件是正确的情况下,只有在该列中具有值查询效率和节省空间。
MySQL现在具有虚拟列,可用于索引。