PG10とPG12を比較して、会社のSQLのいくつかでパフォーマンスベンチマークを行っていました。コードではたくさんのCTEを使用しており、PG12はCTEをネイティブに最適化していなかったため、PG10とPG12でパフォーマンスは同じでした。
私の次の実験は、CTEにNOT MATERIALIZED
ディレクティブを追加することでした。その結果は驚異的でした。クエリ時間を劇的に削減しました(場合によっては半分にした)。
私は here を読みましたMATERIALIZED
はPG12より前のデフォルトの機能でした。そして、その機能は、CTEのすべてのコンテンツを一時的な場所に書き込みます。
だから私の質問は主にNOT MATERIALIZED
についてです:
MATERIALIZED
とは対照的に、NOT MATERIALIZED
機能は舞台裏のデータをどのように処理しますか?NOT MATERIALIZED
への副作用はありますか?ドキュメント で詳しく説明されています。
WITHクエリの有用なプロパティは、親クエリまたは兄弟WITHクエリによって複数回参照されている場合でも、通常は親クエリの実行ごとに1回だけ評価されることです。したがって、複数の場所で必要となる高価な計算をWITHクエリ内に配置して、冗長な作業を回避できます。別の可能なアプリケーションは、副作用のある関数の不要な複数の評価を防ぐことです。
これまでのところ、[〜#〜]しかし[〜#〜]:
ただし、このコインのもう一方の側面は、オプティマイザが親クエリから複数参照のWITHクエリに制限をプッシュできないことです。これは、WITHクエリの出力のすべての使用に影響する可能性がある場合に影響する可能性があるためです。多重参照されたWITHクエリは、親クエリが後で破棄する可能性のある行を抑制することなく、書き込まれたとおりに評価されます。
したがって、上記の例で指摘したように、次のようなクエリがある場合:
WITH w AS (
SELECT * FROM big_table -- big_table has an INDEX on a field called key!
)
SELECT * FROM w AS w1
JOIN w AS w2 ON w1.key = w2.ref -- w is called TWICE, so DEFAULT is MATERIALIZED
-- PostgreSQL can't take advantage of big_table.key
WHERE w2.key = 123;
したがって、この場合:
wITHクエリが具体化され、big_tableの一時的なコピーが生成されます。次に、それ自体と結合されます。インデックスの利点はありません。
持っている方がはるかに良い:
WITH w AS NOT MATERIALIZED (
SELECT * FROM big_table
)
SELECT * FROM w AS w1 JOIN w AS w2 ON w1.key = w2.ref
WHERE w2.key = 123;
オプティマイザがCTEクエリをメインクエリに「フォールディング」して、big_table
のINDEX
フィールドでkey
を使用できるようにするためです。
再NOT MATERIALIZED
のDEFAULT
:
ただし、WITHクエリが再帰的ではなく、副作用がない場合(つまり、揮発性関数を含まないSELECTの場合)、親クエリに折りたたむことができるため、2つのクエリレベルを同時に最適化できます。既定では、これは親クエリがWITHクエリを1回だけ参照する場合に発生しますが、WITHクエリを複数回参照する場合には発生しません。
したがって、DEFAULT
はNOT MATERIALIZED
です。
the_query IS NOT recursive
AND the_query is_side_effect_free
AND the_query is_run_only_once
それ以外の場合は、PostgreSQLにNOT MATERIALIZED
を使用するように指示する必要があります。
私が目にする唯一の小さな問題は、NOT MATERIALIZED
が改善であるかどうかを確認するためにテストが必要になるということです。テーブルサイズ、選択したフィールド、CTEで使用するフィールドとテーブルのインデックスに応じて、2つの間でバランスが変動する状況を確認できます。つまり、知識と経験に代わるものはありません。 DBAはまだ死んではいません。 :-)
唯一の副作用はパフォーマンスに関連している必要があります(これにより、副作用ではなく、それが主な効果になります)。他の副作用がある場合、それらはバグでなければなりません。 「プランナーが決める」設定がないことは少し奇妙です。