web-dev-qa-db-ja.com

Postgres 12のNOT MATERIALIZEDディレクティブに副作用はありますか?

PG10とPG12を比較して、会社のSQLのいくつかでパフォーマンスベンチマークを行っていました。コードではたくさんのCTEを使用しており、PG12はCTEをネイティブに最適化していなかったため、PG10とPG12でパフォーマンスは同じでした。

私の次の実験は、CTEにNOT MATERIALIZEDディレクティブを追加することでした。その結果は驚異的でした。クエリ時間を劇的に削減しました(場合によっては半分にした)。

私は here を読みましたMATERIALIZEDはPG12より前のデフォルトの機能でした。そして、その機能は、CTEのすべてのコンテンツを一時的な場所に書き込みます。

だから私の質問は主にNOT MATERIALIZEDについてです:

  1. MATERIALIZEDとは対照的に、NOT MATERIALIZED機能は舞台裏のデータをどのように処理しますか?
  2. コードベースをリファクタリングする前に注意する必要があるNOT MATERIALIZEDへの副作用はありますか?
2
sorrell

ドキュメント で詳しく説明されています。

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_tableINDEXフィールドでkeyを使用できるようにするためです。

NOT MATERIALIZEDDEFAULT

ただし、WITHクエリが再帰的ではなく、副作用がない場合(つまり、揮発性関数を含まないSELECTの場合)、親クエリに折りたたむことができるため、2つのクエリレベルを同時に最適化できます。既定では、これは親クエリがWITHクエリを1回だけ参照する場合に発生しますが、WITHクエリを複数回参照する場合には発生しません。

したがって、DEFAULTNOT 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はまだ死んではいません。 :-)

4
Vérace

唯一の副作用はパフォーマンスに関連している必要があります(これにより、副作用ではなく、それが主な効果になります)。他の副作用がある場合、それらはバグでなければなりません。 「プランナーが決める」設定がないことは少し奇妙です。

0
jjanes