MySQL ne prend actuellement pas en charge les index conditionnels.
Pour réaliser ce que vous demandez (pas que vous devriez le faire;)), vous pouvez commencer à créer une table auxiliaire:
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`)
);
Ensuite, vous ajoutez trois déclencheurs dans le tableau principal:
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 ;
Nous avons besoin delimiter //
parce que nous voulons utiliser ;
à l'intérieur des déclencheurs.
De cette façon, la table auxiliaire contiendra exactement les ID correspondant aux lignes de la table principale qui contiennent la chaîne "ACTIVE", mises à jour par les déclencheurs.
Pour l'utiliser sur un select
, vous pouvez utiliser l'habituel join
:
SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
ON auxiliary_table.id = main_table.id
ORDER BY auxiliary_table.name;
Si la table principale contient déjà des données, ou si vous effectuez une opération externe qui modifie les données de manière inhabituelle (EG: en dehors de MySQL), vous pouvez corriger la table auxiliaire avec ceci:
INSERT INTO auxiliary_table SET
id = main_table.id,
name = main_table.name,
WHERE main_table.status="ACTIVE";
À propos des performances, vous aurez probablement des insertions, des mises à jour et des suppressions plus lentes. Cela n'a de sens que si vous vous occupez vraiment de quelques cas où la condition souhaitée est positive. Même de cette façon, en testant uniquement, vous pouvez voir si l'espace économisé justifie vraiment cette approche (et si vous économisez vraiment de l'espace).
Vous ne pouvez pas faire d'indexation conditionnelle, mais pour votre exemple, vous pouvez ajouter un index multi-colonnes sur (
name
,status
).Même s'il indexera toutes les données de ces colonnes, il vous aidera quand même à trouver les noms que vous recherchez avec le statut "actif".
la source
Vous pouvez le faire en divisant les données entre deux tables, en utilisant des vues pour unir les deux tables lorsque toutes les données sont nécessaires et en indexant une seule des tables de cette colonne - mais je pense que cela entraînerait des problèmes de performances pour les requêtes qui doivent parcourir toute la table à moins que le planificateur de requêtes ne soit plus intelligent que je ne le pense. Essentiellement, vous devez partitionner manuellement la table (et appliquer l'index à une seule des partitions).
Malheureusement, la fonction de partitionnement de table intégrée ne vous aidera pas dans votre quête car vous ne pouvez pas appliquer d'index à une seule partition.
Vous pouvez conserver une colonne supplémentaire avec un index et n’avoir une valeur dans cette colonne que lorsque la condition sur laquelle vous souhaitez que l’index soit basé est vraie, mais cela est susceptible de nécessiter beaucoup de travail et une valeur limitée (ou négative) en termes de efficacité des requêtes et économie d'espace.
la source
MySQL a maintenant des colonnes virtuelles, qui peuvent être utilisées pour les index.
la source
select count(*) from foo where id is null ;
utiliser un index?)decode(status,'ACTIVE',name,null)
par exemple.