snippetsqlModerate
How to create a conditional index in MySQL?
Viewed 0 times
createconditionalmysqlhowindex
Problem
How to create an index to filter a specific range or subset of the table in MySQL? AFAIK it's impossible to create directly but I think it's possible to simulate this feature.
Example: I want to create an index for
This functionality would be called a filtered index in SQL Server and a partial index in Postgres.
Example: I want to create an index for
NAME column just for rows with STATUS = 'ACTIVE'This functionality would be called a filtered index in SQL Server and a partial index in Postgres.
Solution
MySQL currently doesn't support conditional indexes.
To achive what you are asking (not that you should do it ;) ) you can start creating an auxiliary table:
Then you add three triggers in the main table:
We need
That way, the auxiliary table will contain exactly the IDs corresponding to the main table rows that contain the string "ACTIVE", being updated by the triggers.
To use that on a
If the main table already contains data, or in case you make some external operation that changes data in an unusual way (E.G.: outside MySQL), you can fix the auxiliary table with this:
About the performance, probably you'll have slower inserts, updates and deletes. This can make some sense only if you really deal with few cases where the condition desired is positive. Even that way, probably only testing you can see if the space saved really justifies this aproach (and if you are really saving any space at all).
To achive what you are asking (not that you should do it ;) ) you can start creating an auxiliary table:
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)
);
Then you add three triggers in the main table:
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 ;
We need
delimiter // because we want to use ; inside the triggers.That way, the auxiliary table will contain exactly the IDs corresponding to the main table rows that contain the string "ACTIVE", being updated by the triggers.
To use that on a
select, you can use the usual join:SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
ON auxiliary_table.id = main_table.id
ORDER BY auxiliary_table.name;
If the main table already contains data, or in case you make some external operation that changes data in an unusual way (E.G.: outside MySQL), you can fix the auxiliary table with this:
INSERT INTO auxiliary_table SET
id = main_table.id,
name = main_table.name,
WHERE main_table.status="ACTIVE";
About the performance, probably you'll have slower inserts, updates and deletes. This can make some sense only if you really deal with few cases where the condition desired is positive. Even that way, probably only testing you can see if the space saved really justifies this aproach (and if you are really saving any space at all).
Context
StackExchange Database Administrators Q#43, answer score: 13
Revisions (0)
No revisions yet.