【実務・中級編】 実行計画ツリー – PostgreSQL

やあ。また会ったね。今日は少しだけ「PostgreSQLの深淵」を覗いてみようか。

現場でバリバリコードを書いていると、ふとクエリが遅いことに気づいて `EXPLAIN` を叩く瞬間ってあるよね。でも、そこで出力された膨大なテキストを見て、「ふーん、なんか色々やってるな」で終わらせていないかい?

もしそうなら、それは非常にもったいない。`EXPLAIN` の出力結果である「実行計画ツリー」を読めるようになることは、データベースエンジニアとしての武器を一つ増やすのと同義なんだ。

今日は、この「実行計画ツリー」というパズルをどう解き明かすか、一緒に見ていこう。

—

実行計画ツリーは「料理のレシピ」だと思えばいい

PostgreSQLがクエリを受け取ると、オプティマイザが「一番効率よくデータを集めるにはどうすればいいか?」を必死に考えて、一つの「計画書」を作る。それが実行計画だ。

これは単なる命令の羅列じゃない。「ツリー構造」をしているんだ。

ツリーの末端(葉)にあるノードが、ディスクからデータを拾い上げる最初の一歩。そして、その結果が親ノードに渡され、結合されたりソートされたりしながら、最終的に君たちの画面に結果が返ってくる。

イメージとしては、下から上へ流れる「料理の調理工程」だ。

具体的なツリーを読んでみよう

例えば、こんなクエリを考えよう。

SELECT u.name, o.amount
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.amount > 1000
ORDER BY o.amount DESC;

これに対して `EXPLAIN (ANALYZE, BUFFERS)` を叩くと、こんな感じのツリーが出てくるはずだ。

Sort (cost=…) (actual time=…)
-> Hash Join (cost=…)
-> Seq Scan on orders o
-> Hash (cost=…)
-> Seq Scan on users u

現場で見るべき「ノード」の勘所

初心者はついコストの数字ばかり見がちだけど、現場の僕たちがまず見るのは「ツリーの形」と「ノードの種類」だ。

  • Scan系(Seq Scan, Index Scan):

一番下のノードだ。ここが「フルスキャン」になっていないかを確認する。データ量が多いテーブルで `Seq Scan` が出ているなら、まずはインデックスを疑うのが定石だね。

  • Join系(Hash Join, Nested Loop, Merge Join):

ここがボトルネックになることが多い。`Nested Loop` は小さなテーブル同士なら爆速だけど、数百万行の結合で選ばれると地獄を見る。逆に、`Hash Join` はメモリを食うけど大量データには強い。

  • Sort:

こいつは要注意だ。「メモリでソートしきれずディスクに溢れていないか?」をチェックする必要がある。`work_mem` の設定が適切じゃないと、ここで一気にクエリが遅くなるんだ。

エンジニアとして「ツリーを操作する」技術

ただ眺めるだけじゃなくて、ツリーを変える力も必要だ。

もし実行計画が意図しない方向に進んでいるなら、オプティマイザにヒントを与える必要がある。例えば、「このテーブルは必ずインデックスを使ってほしい」という時は、こんなふうに制御することもあるよね。

— 一時的にNested Loopを強制して挙動を見る(※本番運用では慎重に!)
SET enable_hashjoin = off;
EXPLAIN …

でも、一番大事なのは「なぜオプティマイザがそのツリーを選んだか」を想像すること。統計情報が古いせいで、行数を過小評価していないか? `ANALYZE` を忘れていないか?

「機械が考えた計画を、人間が推敲する」。これがチューニングの醍醐味だよ。

—

最後に:完璧なクエリなんてない

たまに「一番綺麗な実行計画はどう書くべきか?」と聞かれることがあるけれど、答えは「その時のデータ次第」としか言えない。

データが1,000件の時と、1億件の時では、最強の実行計画は全く別物になる。だからこそ、僕たちは「今、このクエリがどういうツリーを描いているか」を常に監視し、変化に対応できるようにしておく必要があるんだ。

次に遅いクエリに出会ったら、焦らず `EXPLAIN` のツリーをじっくり眺めてみてほしい。ノードの一つ一つが、実は君の命令を必死に実行している「小さな働き者」に見えてくるはずさ。

もし読み解きで詰まったら、いつでも相談してくれ。データベースの深淵は、意外と面白い景色が広がっているよ。

それじゃ、また現場で会おう。

コメント

タイトルとURLをコピーしました