Die Postgresql-Funktion wurde wesentlich länger ausgeführt als die gleiche Abfrage

8

Ich benutze PostgreSQL 9.2.9 und habe das folgende Problem.

Es gibt Funktionen:

%Vor%

Gesamtlaufzeit: 242805.085 ms. Aber die Abfrage vom Körper der Funktion wird viel schneller ausgeführt:

%Vor%

Gesamtlaufzeit: 2156.740 ms. Warum wurde die Funktion länger ausgeführt als die gleiche Abfrage? Danke

    
Alina Didenko 17.04.2015, 09:15
quelle

1 Antwort

4

Ihre Abfrage wird schneller ausgeführt, weil die "Variablen" nicht wirklich variabel sind - sie sind statische Werte (IE-Strings in Anführungszeichen). Dies bedeutet, dass der Ausführungsplaner Indizes nutzen kann. Innerhalb Ihrer gespeicherten Prozedur sind Ihre Variablen tatsächliche Variablen und der Planer kann keine Annahmen über Indizes treffen. Zum Beispiel - Sie könnten einen partiellen Index für requeststatushistory haben, wobei "Datum" & lt;="2012-12-31" ist. Der Index kann nur verwendet werden, wenn $ 3 bekannt ist. Da es ein Datum von 2015 enthalten könnte, wäre der Teilindex nutzlos. In der Tat wäre es schädlich.

Ich konstruiere häufig eine Zeichenkette innerhalb meiner Funktionen, in der ich meine Variablen als Literale verkette und dann die Funktion benutze, die etwas wie folgend verwendet:

%Vor%

Die dynamische SQL ist sehr nützlich, weil Sie tatsächlich eine Erklärung der Abfrage bekommen können, wenn ich set client_min_messages=DEBUG; habe Ich kann die Abfrage vom Bildschirm kratzen und wieder einfügen nach EXPLAIN oder EXPLAIN ANALYZE und sehen, was die Ausführungsplaner macht es. Dies ermöglicht Ihnen auch, sehr unterschiedliche Abfragen zu erstellen, um Variablen zu optimieren (IE schließt unnötige Tabellen aus, falls dies gerechtfertigt ist) und pflegen eine gemeinsame API für Ihre Clients.

Sie könnten versucht sein, das dynamische SQL aus Angst vor Performance-Problemen zu vermeiden (ich war zuerst), aber Sie werden erstaunt sein, wie wenig Zeit in die Planung investiert wird, im Vergleich zu einigen der Kosten für ein paar Tabellen-Scans auf Ihrem Sieben-Tisch-Join!

Viel Glück!

Follow-up: Sie könnten auch mit Common Table Expressions (CTEs) für die Leistung experimentieren. Wenn Sie eine Tabelle mit einem niedrigen Signal-Rausch-Verhältnis haben (es enthält sehr viel mehr Datensätze, als Sie tatsächlich zurückgeben möchten), kann ein CTE sehr hilfreich sein. PostgreSQL führt CTEs früh in der Abfrage aus und materialisiert die resultierenden Zeilen im Speicher. Auf diese Weise können Sie dasselbe Ergebnis mehrmals und an mehreren Stellen in Ihrer Abfrage verwenden. Der Nutzen kann wirklich überraschend sein, wenn Sie es richtig entwerfen.

%Vor%

Ein Ausführungsplan zeigt wahrscheinlich an, dass er einen Index für moar_data_tale.moar_data_key verwendet. Dies scheint zu dem zu passen, was ich oben in meiner vorherigen Antwort gesagt habe - abgesehen von der Tatsache, dass die keys_cte Ergebnisse materialisiert sind (und daher nicht durch eine andere Transaktion in einer Race-Condition geändert werden können) - Sie haben Ihre eigene kleine Kopie der Daten für die Verwendung in dieser Abfrage.

Oh - und CTEs können andere CTEs verwenden, die früher in derselben Abfrage deklariert wurden. Ich habe diesen "Trick" verwendet, um Sub-Abfragen in sehr komplexen Joins zu ersetzen und große Verbesserungen zu sehen.

Happy Hacking!

    
matthew.peters 07.05.2015, 04:22
quelle