命令 WITH (または CTE — 共通テーブル式) は、一時的にデータセットを作成し、メインの SELECT で使用したり、再帰的に使用したりできます。CTE はクエリを理解しやすくし、可読性を向上させ、中間結果を再利用できるようにします。
通常のサブクエリに対する利点:
例:
WITH high_salary AS ( SELECT id, name FROM employees WHERE salary > 100000 ) SELECT * FROM high_salary WHERE name LIKE 'A%';
“CTE 宣言時に MATERIALIZED/NOT MATERIALIZED を指定することは重要ですか?これがパフォーマンスにどのように影響しますか?”
回答: PostgreSQL では、CTE を明示的に MATERIALIZED (常に CTE を一度計算して保存する、複数回使用される場合でも) または NOT MATERIALIZED (CTE がメインのクエリにインラインされる) と指定できます。通常、オプティマイザーは CTE をマテリアライズするべきか自動的に判断しますが、強制的な指定がパフォーマンスに大きく影響することがあります。
例:
WITH high_salary AS MATERIALIZED ( SELECT id, name FROM employees WHERE salary > 100000 ) SELECT * FROM high_salary WHERE name LIKE 'A%';
逸話
大規模プロジェクトでアナリストが、PostgreSQL 12 未満では CTE が常にマテリアライズされることを知らずにすべてのサブクエリを CTE に置き換えました。その結果、クエリの速度が 2-3 倍遅くなりました。サブクエリに戻すか、新しいバージョンに移行することで問題は解決しました。
逸話
複数のネストされたサブクエリを含むレポートは、同僚には読みづらい結果となりました。意味のある名前を付けた CTE に書き換えたところ、クエリの議論と保守が大幅に簡素化されました。
逸話
同じ名前の 2 つの CTE が大規模なスクリプトで混乱を引き起こしました: CTE はまだ宣言される前に使用されていました。その結果、コンパイルエラーが発生し、原因を追求するのに多くの時間を費やしました。