Ausführen, ANALYZE
nachdem 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 ANALYZE
Befehl 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
ANALYZE
Vorgänge zu verlassen, insbesondere wenn bekannt ist, dass die Aktualisierungsaktivität für eine Tabelle die Statistik "interessanter" Spalten nicht beeinflusst. Der Daemon plant ANALYZE
ausschließ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 = 0
es 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 reltuples
und relpages
werden nicht im laufenden Betrieb aktualisiert und enthalten daher normalerweise etwas veraltete Werte. Sie zeichnen sich durch aktualisiert VACUUM
, ANALYZE
und 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_class
aktualisiert. Aber nur diese, nicht die detaillierten Statistiken in pg_statistic
:
Einträge in pg_statistic
werden von den aktualisierten ANALYZE
und 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 = 0
tatsächlich ein seltener Fall ist. Daher lohnt es sich, den Index zu verwenden.
Dafür sorgt Autovacuum . Es plant VACUUM
und ANALYZE
automatisch. Zwischen den Schreibvorgängen in die Tabelle und dem nächsten ANALYZE
Durchlauf 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 INSERT
oder unmittelbar nach der Tabellenerstellung der Fall ist , führen Sie diese ANALYZE
manuell 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 ANALYZE
manuell ausführen , wenn Sie sie benötigen:
Ich weiß nicht, wie Sie das Autovakuum konfiguriert haben und ob / wann Sie es ANALYZE
manuell 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 ANALYZE
hinter 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 INDEX
undANALYZE
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 deprovision
in 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 INDEX
wir grundlegende Statistiken, aber immer noch kein Datenhistogramm in pg_statistics
.
Nachdem ANALYZE
wir 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).