===== aktualisierte Basierend auf dem Feedback =====PostgresSQL CTE/Sub-Abfrage mit generate_series Performance-Probleme
Aufgrund einiger anfänglichen Fragen Klärung suchen, hier ist eine wirklich einfache Version davon.
WITH my_var AS (
SELECT date '2016-01-01' as a_date
--, generate_series(1, 40) as numbers
)
Select generate_series(1, 100000) as numbers, my_var.a_date from my_var
execution time: 411ms
"CTE Scan on my_var (cost=0.01..5.03 rows=1000 width=4)"
" CTE my_var"
" -> Result (cost=0.00..0.01 rows=1 width=0)"
Nun, wenn wir die die generate_series im
WITH my_var AS (
SELECT date '2016-01-01' as a_date
, generate_series(1, 40) as numbers
)
Select generate_series(1, 100000) as numbers, my_var.a_date from my_var
execution time: 16201ms
"CTE Scan on my_var (cost=5.01..5022.51 rows=1000000 width=4)"
" CTE my_var"
" -> Result (cost=0.00..5.01 rows=1000 width=0)"
Der Punkt Kommentar- hier zu sein, ist, wenn die generate_series (1, 40) nur einmal ausgeführt werden soll, warum ist es so braucht lang, bis die Abfrage abgeschlossen ist. In diesem Fall habe ich nicht einmal die 'Nummer' verwendet, die in der Hauptabfrage festgelegt wurde, und es dauerte immer noch und die Zeitspanne wurde verlängert.
===== ===== Original-Anfrage
Ich habe in einem interessanten Leistungsproblem führen mit PostgresSQL 9.x mit Unterabfragen und/oder CTE.
... Und ganz ehrlich, ich bin nicht sicher, ob dies ein "Bug" oder nur ein Benutzer (d. H. Ich) Verständnis von CTE/Sub-Abfragen und oder Verwendung der generate_series-Funktion ist.
Ich habe einige erweiterte und längere Abfragen mit CTE geschrieben. Ich habe eine Technik verwendet, bei der ich eine statische Variable wie Datumsangaben in einen Master-CTE eingefügt habe, der alle zusätzlichen Abfragen durchsucht. Die Idee besteht darin, eine Menge von Änderungen anstelle von vielen durch eine lange Abfrage zu machen, wenn Sie sie mit anderen Parametern ausführen müssen.
Ein Beispiel hierfür ist:
WITH dates AS (
SELECT
date '2013-01-01' AS start_date,
date_trunc('month', current_date) AS end_date
)
SELECT * from dates, sometable where somedate between start_date and end_date
execution time: ~650ms
Also, es ist mein Verständnis, dass ein CTE einmal ausgeführt wird, aber nach einem Performance-Problem ausgeführt wird, ist dies eindeutig nicht, was geschieht. Zum Beispiel, wenn ich den CTE ändern, um eine generate_series enthalten:
WITH dates AS (
SELECT
date '2013-01-01' AS start_date,
date_trunc('month', current_date) AS end_date,
generate_series(1, 10) AS somelist
)
SELECT * from dates, sometable where somedate between start_date and end_date
and myval in (somelist)
execution time: ~23000ms
Aufgrund einiger ernsthaften Performance-Probleme mit diesem (tausendfach langsamer), an dachte ich zuerst die generate_series() wurde die Zuordnung den somelist der „generate_series "Funktion und wird dann als Unterabfrage für jede Zeile in der Hauptabfrage ausgeführt. So bestätigen diese modifizierte ich die Abfrage lautet wie folgt:
WITH dates AS (
SELECT
date '2013-01-01' AS start_date,
date_trunc('month', current_date) AS end_date--,
--generate_series(1, 10) AS somelist
)
SELECT * from dates, sometable where somedate between start_date and end_date
and myval in (generate_series(1, 10))
execution time: ~700ms
Zu meiner Überraschung, das relativ schnell war (und nur 10% langsamer). Die generate_series als Unterabfrage ist eindeutig nicht das Problem.
So ging dann auf die ursprüngliche Abfrage zurückgegangen und nur die generate_series hinzugefügt, aber nie in der Hauptabfrage verwendet. Hier ist diese Abfrage.
WITH dates AS (
SELECT
date '2013-01-01' AS start_date,
date_trunc('month', current_date) AS end_date,
generate_series(1, 10) AS somelist
)
SELECT * from dates, sometable where somedate between start_date and end_date
execution time: ~23000ms
Das ist eindeutig die rauchende Waffe ... aber ich habe keine Ahnung, warum oder was wirklich los ist. Hier sind meine Fragen:
Zusammenfassend verbraucht die Verwendung der generate_series innerhalb einer CTE oder Unterabfrage sehr viel Zeit/Ressourcen (auch wenn das Ergebnis nicht verwendet wird). Ich bekomme die gleichen Ergebnisse in beiden Postgres v9.3 und v9.5. Ich liege gegen 14 Millionen Zeilen. Die Ergebnismenge beträgt nur etwa 275.000.
Ich bin an dieser Stelle ratlos, hat jemand irgendwelche Theorien? (... oder ist es ein Fehler?
)-D
Interessante Frage, aber Sie müssen mehr Informationen über 'someable' wie Index zur Verfügung stellen. Es wird auch gut sein, wenn Sie die 'explain analyze' aller Abfragen einschließen, damit wir verstehen können, was die rdbms macht und zwischen jeder Abfrage vergleichen. –
Fügen Sie Ihren Abfragen Tabellenaliasse hinzu und verwenden Sie sie, wenn Sie auf Spaltennamen verweisen. Es ist völlig vage, woher der Ausdruck kommt, es könnte sogar ein kartesisches Produkt sein. ad anstelle von 'SELECT * aus Daten, beliebig 'könnte man die JOIN-Syntax für zusätzliche Lesbarkeit verwenden. – wildplasser
@Juan - Mein Punkt ist, dass es nicht wichtig ist, Indizes. Es muss kein Ereignis mit einer realen Tabelle verbunden werden. Ich werde ein Update veröffentlichen, um dies zu zeigen. – user2259963