MySQL unterstützt derzeit keine bedingten Indizes.
Um zu erreichen, wonach Sie fragen (nicht, dass Sie es tun sollten;)), können Sie eine Hilfstabelle erstellen:
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`)
);
Dann fügen Sie drei Trigger in die Haupttabelle ein:
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 ;
Wir brauchen, delimiter //
weil wir ;
in den Triggern verwenden wollen.
Auf diese Weise enthält die Hilfstabelle genau die IDs, die den Haupttabellenzeilen entsprechen, die die Zeichenfolge "ACTIVE" enthalten und von den Triggern aktualisiert werden.
Um das auf einem zu benutzen, select
können Sie das übliche benutzen join
:
SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
ON auxiliary_table.id = main_table.id
ORDER BY auxiliary_table.name;
Wenn die Haupttabelle bereits Daten enthält oder Sie eine externe Operation ausführen, die Daten auf ungewöhnliche Weise ändert (z. B. außerhalb von MySQL), können Sie die Hilfstabelle folgendermaßen reparieren:
INSERT INTO auxiliary_table SET
id = main_table.id,
name = main_table.name,
WHERE main_table.status="ACTIVE";
In Bezug auf die Leistung werden Sie wahrscheinlich langsamere Einfügungen, Aktualisierungen und Löschvorgänge haben. Dies kann nur dann sinnvoll sein, wenn Sie sich wirklich mit wenigen Fällen befassen, in denen der gewünschte Zustand positiv ist. Selbst auf diese Weise können Sie wahrscheinlich nur beim Testen feststellen, ob der gespeicherte Speicherplatz diesen Ansatz wirklich rechtfertigt (und ob Sie überhaupt wirklich Speicherplatz sparen).
Sie können keine bedingte Indizierung durchführen, aber für Ihr Beispiel können Sie einen mehrspaltigen Index für (
name
,status
) hinzufügen .Obwohl es alle Daten in diesen Spalten indiziert, hilft es Ihnen dennoch, die gesuchten Namen mit dem Status "aktiv" zu finden.
quelle
Sie könnten dies tun, indem Sie die Daten auf zwei Tabellen aufteilen, die beiden Tabellen mithilfe von Ansichten zusammenfassen, wenn alle Daten benötigt werden, und nur eine der Tabellen in dieser Spalte indizieren - aber ich denke, dies würde zu Leistungsproblemen bei Abfragen führen, die erforderlich sind Durchsuchen Sie die gesamte Tabelle, es sei denn, der Abfrageplaner ist schlauer, als ich es zu schätzen weiß. Im Wesentlichen würden Sie die Tabelle manuell partitionieren (und den Index nur auf eine der Partitionen anwenden).
Leider hilft Ihnen die integrierte Tabellenpartitionierungsfunktion bei Ihrer Suche nicht, da Sie keinen Index auf eine einzelne Partition anwenden können.
Sie könnten eine zusätzliche Spalte mit einem Index pflegen und nur dann einen Wert in dieser Spalte haben, wenn die Bedingung erfüllt ist, auf der der Index basieren soll. Dies ist jedoch wahrscheinlich arbeitsintensiv und von begrenztem (oder negativem) Wert in Bezug auf Abfrageeffizienz und Platzersparnis.
quelle
MySQL verfügt nun über virtuelle Spalten, die für Indizes verwendet werden können.
quelle
select count(*) from foo where id is null ;
decode(status,'ACTIVE',name,null)
beispielsweise aktiviert sein .