Ausführen, ANALYZEnachdem der Index hinzugefügt wurde. Und stellen Sie sicher , dass die Spalte deprovision hat Statistiken. Wie überprüfe ich?
Grundlegende Statistiken in pg_class:
SELECT relname, relkind, reltuples, relpages
FROM pg_class
WHERE oid = 'schema_defs'::regclass;
Datenhistogramme pro Spalte in pg_stats( pg_statistics):
SELECT attname, inherited, n_distinct
, array_to_string(most_common_vals, E'\n') AS most_common_vals
FROM pg_stats
WHERE tablename = 'schema_defs'
AND attname = 'deprovision';
Das Handbuch:
Der PostgreSQL-Abfrageplaner stützt sich auf statistische Informationen zum Inhalt von Tabellen, um gute Pläne für Abfragen zu erstellen. Diese Statistiken werden vom ANALYZEBefehl erfasst, der von sich aus oder als optionaler Schritt aufgerufen werden kann VACUUM. Es ist wichtig, einigermaßen genaue Statistiken zu haben, da sonst eine schlechte Auswahl der Pläne die Datenbankleistung beeinträchtigen kann.
Wenn der Autovacuum-Daemon aktiviert ist, gibt er automatisch ANALYZE
Befehle aus, wenn sich der Inhalt einer Tabelle ausreichend geändert hat. Administratoren ziehen es jedoch möglicherweise vor, sich auf manuell geplante
ANALYZEVorgänge zu verlassen, insbesondere wenn bekannt ist, dass die Aktualisierungsaktivität für eine Tabelle die Statistik "interessanter" Spalten nicht beeinflusst. Der Daemon plant ANALYZEausschließlich in Abhängigkeit von der Anzahl der eingefügten oder aktualisierten Zeilen. Es ist nicht bekannt, ob dies zu bedeutenden statistischen Änderungen führen wird.
In Ihrem Fall würde die Analyse nur einer Spalte die Aufgabe erfüllen:
ANALYZE table_name (deprovision);
Wenn Sie gerade dabei sind, macht es keinen Sinn, den Index für die Spalte zu haben deprovision. In Anbetracht des Prädikats enthält WHERE deprovision = 0es keine zusätzlichen Informationen. Sie können auch einen konstanten Ausdruck verwenden:
CREATE INDEX schema_defs_deprovision ON schema_defs ((true))
WHERE deprovision = 0;
Nur ein Proof of Concept. Dies wäre nicht nützlicher. In diesem speziellen Fall würden Sie einen Index nicht benötigen Spalte überhaupt, aber Sie müssen mindestens eine Spalte oder einen Ausdruck zur Verfügung stellen. Verwenden Sie daher den Primärschlüssel (da er sich nicht ändert und ohnehin indiziert ist, führen Sie keine weiteren Einschränkungen / Gemeinkosten ein) oder eine andere kleine Spalte (<= 8 Byte), die für Abfragen nützlich sein kann.
CREATE INDEX schema_defs_deprovision ON schema_defs (id)
WHERE deprovision = 0;
sqlfiddle.com
Die Demo-Geigen sind irreführend .
Teilindex vor Einfügungen erstellt (Index funktioniert ordnungsgemäß)
Ihre Demo-Tabelle hat nur 4 Zeilen. Postgres sollte nicht mit dem Index sein. Ein ähnliches Problem, genau umgekehrt. Postgres verfügt nicht unmittelbar nach dem Erstellen über Statistiken in der Tabelle - bis zum ersten Durchlauf von ANALYZE. Dann weiß es , dass es nur 4 Zeilen gibt und den Index nicht mehr berührt.
Warum funktioniert es bei Ihrer zweiten Demo richtig? Das Handbuch:
Aus Effizienzgründen reltuplesund relpageswerden nicht im laufenden Betrieb aktualisiert und enthalten daher normalerweise etwas veraltete Werte. Sie zeichnen sich durch aktualisiert VACUUM, ANALYZEund ein paar DDL - Befehle wie
CREATE INDEX .
Meine kühne Betonung. Wenn Sie den Index nach dem Einfügen von Zeilen erstellen , werden diese grundlegenden Statistiken pg_classaktualisiert. Aber nur diese, nicht die detaillierten Statistiken in pg_statistic:
Einträge in pg_statisticwerden von den aktualisierten ANALYZEund VACUUM ANALYZE
Befehlen und werden immer nähern , auch wenn frisch aktualisiert.
Damit Postgres den Teilindex verwendet (insbesondere in seiner ursprünglichen Form, die für nichts anderes nützlich ist), benötigen Sie auch das Datenhistogramm pg_statistic, um den Abfrageplaner darüber zu informieren, dass dies deprovision = 0tatsächlich ein seltener Fall ist. Daher lohnt es sich, den Index zu verwenden.
Dafür sorgt Autovacuum . Es plant VACUUMund ANALYZEautomatisch. Zwischen den Schreibvorgängen in die Tabelle und dem nächsten ANALYZEDurchlauf liegt jedoch ein Zeitrahmen (abhängig von den Einstellungen und der Auslastung) . Wenn Sie Abfragen unmittelbar nach der Tabellenerstellung oder Änderungen an der Tabelle ausführen, werden diese letzten Änderungen noch nicht in der Statistik berücksichtigt. Es ist egal, ob dies die Statistik nicht in relevanter Weise ändert. Wenn dies beispielsweise nach einer großen INSERToder unmittelbar nach der Tabellenerstellung der Fall ist , führen Sie diese ANALYZEmanuell aus, um die richtigen Abfragepläne zu erhalten.
Beachten Sie, dass temporäre Tabellen überhaupt nicht von Autovakuum abgedeckt werden. Sie müssen diese immer ANALYZEmanuell ausführen , wenn Sie sie benötigen:
Ich weiß nicht, wie Sie das Autovakuum konfiguriert haben und ob / wann Sie es ANALYZEmanuell ausführen . Aber ich habe in der Vergangenheit festgestellt, dass sqlfiddle aufgrund fehlender / veralteter Statistiken irreführend sein kann.
Mich würde sehr interessieren, wie ANALYZEhinter den Vorhängen auf sqlfiddle gehandhabt wird. Es ist vielleicht am besten, nichts Besonderes zu tun, aber einige Informationen wären willkommen. Vielleicht eine einfache Webseite pro verfügbarer RDBMS-Version?
Demo
Ich habe eine SQL-Geige erstellt , um die Auswirkungen CREATE INDEXundANALYZE auf die verschiedenen Statistiken zu demonstrieren .
Die Effekte zeigen sich (zumindest) beim ersten Lauf für mich. Bei späteren Läufen möglicherweise nicht reproduzierbar. Sie müssten ein neues Schema erstellen und erneut ausführen.
Zuerst sehen wir keine grundlegenden Statistiken in pg_class:
relname reltuples relpages
schema_defs 0 0
Noch irgendwelche Einträge für deprovisionin pg_statisticsüberhaupt (kein Ergebnis).
Postgres hat keine Ahnung, was in der Tabelle steht, und verwendet standardmäßig den Index - was eine schlechte Wahl ist!
Danach sehen CREATE INDEXwir grundlegende Statistiken, aber immer noch kein Datenhistogramm in pg_statistics.
Nachdem ANALYZEwir beide gesehen haben.
Bei korrekter Statistik verwendet Postgres jetzt einen sequentiellen Scan (gute Wahl, selbst wenn ein Index vorhanden ist - dies wäre für so wenige Zeilen teurer).