とPostgresSQLのCTE /サブクエリ===== =====更新generate_seriesのパフォーマンスの問題
により明確化を求めているいくつかの初期の質問に、ここではこののは本当に簡単なバージョンがあります。私たちがここにいる
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)"
ポイントでgenerate_seriesコメントを解除した場合
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)"
は今generate_series(1、40)は1回だけ実行されるようになっている場合、なぜそれがそう取るんですクエリが完了するまで長い間。この場合、私はメインクエリで '数字'セットを使用していないし、それでも完了するまでに時間がかかりました。
=====オリジナルお問い合わせ=====
私は、サブクエリおよび/またはCTEを使用してのPostgresSQL 9.xので興味深いパフォーマンスの問題に遭遇しました。
... CTE /サブクエリやgenerate_series関数の使用を「バグ」またはユーザー(つまりMe)が理解できるかどうかは完全に正直ではありません。
私は、CTEを使用して高度な、より長いクエリを書いてきました。私は、すべての追加クエリをフィルタリングするマスターCTEに日付などの静的変数を配置したテクニックを使用してきました。この考え方は、さまざまなパラメータで実行する必要がある場合に、長いクエリで1つの変更を複数の変更よりもむしろ1つ作成することです。
この例は次のとおりです。
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
だから、それはCTEが一度に実行されていることを私の理解ではあるが、パフォーマンスの問題に実行した後に、これは何が起こっているか明確ではありません。例えば、私はCTEを変更した場合generate_series含める:これによって(遅く何千回)といくつかの深刻なパフォーマンスの問題に
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
を、私は、最初の「generate_series somelistを割り当てる)(generate_seriesを思いましたメインクエリでsometable内のすべての行のサブクエリとして実行されます。だから私は、クエリを変更し、これを確認するには、次のとおりです。
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
を私の驚きに、これは比較的高速(とのみ10%遅くなる)でした。サブクエリとしてのgenerate_seriesは明らかに問題ではありません。
その後、元のクエリに戻り、generate_seriesを追加しましたが、メインクエリでこれを使用しませんでした。ここにその質問があります。
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
これは明らかに喫煙銃です...しかし、私は何が本当に起こっているのか、その理由については全く知らないです。要約すると、CTEまたはサブクエリ内でgenerate_seriesを使用すると、(結果が使用されていなくても)膨大な量の時間/リソースを消費しています。 Postgres v9.3とv9.5の両方で同じ結果が得られます。私は約1400万行を実行している私はテーブルです。結果セットはわずか約275Kです。
私はこの時点では無知です、誰にも理論がありますか? (...それともバグですか?)
-D
興味深い質問ですが、インデックスのような 'sometable'についての詳細情報を提供する必要があります。また、すべてのクエリの 'explain analyze'をインクルードして、rdbmsを実行していることを理解し、各クエリを比較すると良いでしょう。 –
クエリにテーブルエイリアスを追加し、カラム名を参照するときに使用してください。それは完全に漠然とした表現であり、それはカルテシアンの製品であってもかまわない。 'SELECT * from dates、sometable'の代わりにJOIN構文を使用して読みやすくすることができます。 – wildplasser
@元 - 私の指摘は、インデックスについては関係ありません。実際のテーブルに接続する必要はありません。私はこれを示すためのアップデートを投稿します。 – user2259963