PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Leistungseinfluss der Ansicht auf die Aggregatfunktion im Vergleich zur Begrenzung der Ergebnismenge

Abfragen nicht unbedingt gleichwertig

Um den Zusammenhang deutlich zu machen:

  • max(id) schließt NULL aus Werte. Aber ORDER BY ... LIMIT 1 nicht.
  • NULL Werte sortieren in aufsteigender Sortierreihenfolge zuletzt und in absteigender Reihenfolge zuerst. Also ein Index Scan Backward findet möglicherweise nicht den größten Wert (gemäß max() ) zuerst, aber eine beliebige Anzahl von NULL Werte.

Das formale Äquivalent von:

SELECT max(id) FROM testview;

ist nicht:

SELECT id FROM testview ORDER BY id DESC LIMIT 1;

aber:

SELECT id FROM testview ORDER BY id DESC NULLS LAST LIMIT 1;

Die letztere Abfrage erhält nicht den schnellen Abfrageplan. Aber es wäre mit einem Index mit passender Sortierreihenfolge:(id DESC NULLS LAST) .

Anders bei den Aggregatfunktionen min() und max() . Diese erhalten einen schnellen Plan, wenn sie auf die Tabelle test1 abzielen direkt mit dem einfachen PK-Index auf (id) . Aber nicht, wenn es auf der Ansicht basiert (oder direkt auf der zugrunde liegenden Join-Abfrage - die Ansicht ist nicht der Blocker). Ein Index, der NULL-Werte an der richtigen Stelle sortiert, hat kaum Auswirkungen.

Wir Kennen Sie diese id in dieser Abfrage darf niemals NULL sein . Die Spalte ist NOT NULL definiert . Und der Join in der Ansicht ist effektiv ein INNER JOIN die NULL nicht einführen kann Werte für id .
Wir auch wissen, dass der Index auf test.id kann keine NULL-Werte enthalten.
Aber der Postgres-Abfrageplaner ist keine KI. (Das versucht es auch nicht, das könnte schnell außer Kontrolle geraten.) Ich sehe zwei Mängel :

  • min() und max() den schnellen Plan nur erhalten, wenn auf die Tabelle abgezielt wird, unabhängig von der Sortierreihenfolge des Indexes, wird eine Indexbedingung hinzugefügt:Index Cond: (id IS NOT NULL)
  • ORDER BY ... LIMIT 1 bekommt den schnellen Plan nur mit der exakt passenden Index-Sortierreihenfolge.

Nicht sicher, ob das (einfach) verbessert werden könnte.

db<>fiddle hier - Demonstrieren aller oben genannten Punkte

Indizes

Dieser Index ist völlig nutzlos:

CREATE INDEX ON "test" ("id");

Die PK auf test.id wird mit einem eindeutigen Index auf der Spalte implementiert, der bereits alles abdeckt, was der zusätzliche Index für Sie tun könnte.

Möglicherweise gibt es noch mehr, die darauf warten, dass die Frage geklärt wird.

Verzerrter Testfall

Der Testfall ist zu weit vom tatsächlichen Anwendungsfall entfernt, um sinnvoll zu sein.

Im Testaufbau hat jede Tabelle 100.000 Zeilen, es gibt keine Garantie dafür, dass jeder Wert in joincol enthalten ist hat eine Übereinstimmung auf der anderen Seite, und beide Spalten können NULL sein

Ihr realer Fall hat 10 Millionen Zeilen in table1 und <100 Zeilen in table2 , jeder Wert in table1.joincol hat eine Übereinstimmung in table2.joincol , beide sind definiert NOT NULL und table2.joincol ist einzigartig. Eine klassische Eins-zu-Viele-Beziehung. Es sollte einen UNIQUE geben Beschränkung auf table2.joincol und eine FK-Einschränkung t1.joincol --> t2.joincol .

Aber das ist derzeit alles in der Frage verdreht. Bereitstehen, bis das aufgeräumt ist.