こんにちは!データベースの世界へようこそ。
普段、PostgreSQLを使っていると「`WITH`句(CTE)」って便利ですよね。長いクエリをパズルみたいに組み立てられるから、コードがすごく読みやすくなる。僕も大好きです。
でも、ちょっと待ってください。その「読みやすさ」の裏で、データベースがとんでもない回り道をさせられていることがあるって知っていましたか?
今日は、そんな「CTEの裏側でのちょっとしたワガママ」について、お話ししたいと思います。
—
料理店に例えてみよう:CTEは「下ごしらえ」か「出来立て」か?
想像してみてください。あなたは今、大忙しのレストランのシェフです。
「特製オムライス」を作るために、「事前に作ったソース」が必要だとします。
1. 「マテリアライゼーション(先作り)」:作り置き作戦
まず、ソースをあらかじめ大きな鍋で大量に作って、冷蔵庫に入れておく方法。
これがデータベースでいう`MATERIALIZED`(マテリアライズド)です。
- メリット: 一度作れば、注文が入るたびに冷蔵庫から出すだけ。何回使っても早い!
- デメリット: 作りすぎて余ったらもったいないし、冷蔵庫を占領しちゃう。
2. 「インライン化(都度作り)」:その都度調理作戦
次に、注文が入るたびに、その分だけソースを小鍋でさっと作る方法。
これが`NOT MATERIALIZED`(インライン化)です。
- メリット: 必要な分だけフレッシュに作れるから、無駄がない。しかも、もしソースの材料に「特定の野菜」が入っていれば、それと一緒に炒めることで効率を上げられる(最適化)。
- デメリット: 注文が100回入ったら、100回ソースを作らなきゃいけない。これは大変ですよね。
—
どっちが良いの? PostgreSQLの気まぐれ
PostgreSQLは基本的には「賢い子」なので、どっちが良いか自動で判断してくれます。
でも、たまに判断を間違えるんです。
「君、そのソース作り置きしたほうが絶対早いよ!」という場面で、毎回せっせと小鍋で作ろうとしたり。あるいはその逆だったり。
そんな時、エンジニアである私たちが「おい、ここは作り置きにしておいて!」と指示を出してあげるのが、クエリチューニングの醍醐味なんです。
—
実際に指示を出してみよう
PostgreSQL 12以降なら、こんなふうに直接指定することができます。
作り置き(MATERIALIZED)を強制する
WITH my_sauce AS MATERIALIZED (
SELECT FROM huge_table WHERE …
)
SELECT FROM my_sauce …
「このデータは重いから、一度メモリに書き出して固定して!」というメッセージです。
その都度(NOT MATERIALIZED)を強制する
WITH my_sauce AS NOT MATERIALIZED (
SELECT FROM huge_table WHERE …
)
SELECT FROM my_sauce …
「作り置きなんてしなくていい! クエリ全体を一つの料理として見て、効率的に組み合わせて!」というメッセージですね。
—
まとめ:魔法の杖ではないけれど
このテクニック、実は「ここぞ!」という時に使うと劇的に速くなる魔法の杖のようなものです。でも、最初から全部に指定するのはおすすめしません。
まずは、「なんかこのクエリ、遅いな?」と感じた時に、実行計画(EXPLAIN)を見てみてください。そこで「あ、ここで無駄な計算を繰り返してるな」と気づいたら、ぜひこの設定を試してみてください。
データベースと対話する感覚、少しずつわかってくると本当に楽しいですよ。
また何か気になることがあったら、いつでも聞きに来てくださいね!
皆さんのクエリが、今日よりもっと軽快に走りますように。それでは、また!
コメント