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

Wann sind (SELECT) Abfragen geplant?

Ich kann nicht über die clientseitige Perl-Schnittstelle selbst sprechen, aber ich kann etwas Licht in die PostgreSQL-Serverseite bringen.

PostgreSQL hat vorbereitete Anweisungen und nicht vorbereitete Anweisungen. Unvorbereitete Anweisungen werden analysiert, geplant und sofort ausgeführt. Sie tun es auch nicht Parameterersetzung unterstützen. Auf einem einfachen psql Shell können Sie ihren Abfrageplan wie folgt anzeigen:

tmpdb> explain select * from sometable where flag = true;

Auf der anderen Seite gibt es vorbereitete Anweisungen:Sie werden normalerweise (siehe "Ausnahme" unten) in einem Schritt geparst und geplant und in einem zweiten Schritt ausgeführt. Sie können mehrmals mit anderen Parametern erneut ausgeführt werden, weil sie es tun Parameterersetzung unterstützen. Das Äquivalent in psql ist das:

tmpdb> prepare foo as select * from sometable where flag = $1;
tmpdb> explain execute foo(true);

Sie sehen vielleicht, dass sich der Plan von dem Plan in der unprepared-Anweisung unterscheidet, weil die Planung bereits in prepare stattgefunden hat Phase wie in der Dokumentation für PREPARE beschrieben :

Das bedeutet auch, dass der Plan NICHT ist optimiert für die ersetzten Parameter:In den ersten Beispielen könnte ein Index für flag verwendet werden denn PostgreSQL weiß, dass von einer Million Einträgen nur zehn den Wert true haben . Diese Argumentation ist unmöglich, wenn PostgreSQL eine vorbereitete Anweisung verwendet. In diesem Fall wird ein Plan erstellt, der für alle möglichen Parameterwerte so gut wie möglich funktioniert. Das vielleicht Schließen Sie den erwähnten Index aus, da das Abrufen des größten Teils der vollständigen Tabelle per Direktzugriff (aufgrund des Index) langsamer ist als ein einfacher sequenzieller Scan. Das VORBEREITEN doc bestätigt dies:

Übrigens - In Bezug auf Plan-Caching PREPARE doc hat auch was zu sagen:

Außerdem gibt es kein automatisches Plan-Caching und kein Caching/Wiederverwendung über mehrere Verbindungen.

AUSNAHME :Ich habe "normalerweise" erwähnt. Die gezeigte psql Beispiele sind nicht das Zeug, das ein Client-Adapter wie Perl DBI wirklich verwendet. Es verwendet ein bestimmtes Protokoll . Hier entspricht der Begriff „einfache Abfrage“ der „unvorbereiteten Abfrage“ in psql , der Begriff "erweiterte Abfrage " entspricht "prepared query" mit einer Ausnahme:Es wird zwischen (einem) "unbenannten Statement" und (ggf. mehreren) "benannten Statements" unterschieden. Bei benannten Statements ist die doc sagt:

und auch:

In diesem Fall erfolgt die Planung also ohne Parameter wie oben für PREPARE beschrieben - nichts Neues.

Die erwähnte Ausnahme ist die "unbenannte Anweisung". Das Dokument sagt:

Und hier ist der Vorteil:Obwohl die unbenannte Anweisung "vorbereitet" ist (d. h. eine Parameterersetzung haben kann), kann sie auch den Abfrageplan an die tatsächlichen Parameter anpassen.

Übrigens:Die genaue Behandlung der unbenannten Anweisung hat sich in den vergangenen Versionen des PostgreSQL-Servers mehrmals geändert. Sie können in den alten Dokumenten nach Einzelheiten suchen, wenn Sie wirklich wollen.

Begründung – Perl / jeder Client :

Wie ein Kunde wie Perl das Protokoll verwendet, ist eine ganz andere Frage. Einige Clients wie der JDBC-Treiber für Java sagen grundsätzlich:Selbst wenn der Programmierer eine vorbereitete Anweisung verwendet, werden die ersten fünf (oder so) Ausführungen intern auf eine "einfache Abfrage" abgebildet (d. h. effektiv unvorbereitet), danach wechselt der Treiber zu " benannte Aussage“.

Ein Client hat also diese Wahlmöglichkeiten:

  • Erzwingen Sie jedes Mal eine (Neu-)Planung, indem Sie das "einfache Abfrage"-Protokoll verwenden.
  • Planen einmal, mehrfach ausführen mit dem "extended query"-Protokoll und dem "named statement" (Plan kann schlecht sein, da die Planung ohne Parameter erfolgt).
  • Parsen Planen Sie einmal für jede Ausführung (mit der aktuellen PostgreSQL-Version), indem Sie das "erweiterte Abfrage"-Protokoll und die "unbenannte Anweisung" verwenden und einige weitere Dinge beachten (geben Sie einige Parameter während der "Parse"-Nachricht an)
  • Spielen Sie ganz andere Tricks wie der JDBC-Treiber.

Was Perl derzeit macht:Ich weiß es nicht. Aber die erwähnte "Ablenkungsmanöver" ist nicht sehr unwahrscheinlich.