【実務・中級編】 クエリ書き換えエンジン – PostgreSQL

そのSQL、実は「書き換え」られている?PostgreSQLのクエリ書き換えエンジンの深淵へ

「なぜか自分の書いたSQLより、PostgreSQLが選んだ実行計画の方が速い」

エンジニアとして経験を積んでくると、一度はこんな感覚に陥りませんか? データベースのチューニングをしていると、どうしても「インデックスをどう貼るか」「統計情報をどう更新するか」といった実行計画(Query Planner)の話ばかりに目が行きがちです。

でも、実はその一歩手前。「パーサが構文を理解した後、プランナーが計画を立てるまでの間」に、PostgreSQLは非常に賢い「書き換え」を行っているんです。今日は、この縁の下の力持ちである「クエリ書き換えエンジン(Query Rewriter)」について、現場の視点からお話ししましょう。

—

1. なぜ「書き換え」が必要なのか?

SQLを投げると、PostgreSQLはまず「パーサ」が構文チェックを行い、次に「クエリツリー」という内部表現に変換します。しかし、この段階のクエリは、まだ「人間が書いたまま」の、いわば素の状態です。

例えば、`VIEW` を使っているとき。PostgreSQLはビューの定義をいちいち物理テーブルに戻して処理しているわけではありません。実は、クエリツリーそのものを改変して、あたかも最初から実テーブルを叩いているかのようなクエリにすり替えているんです。

このプロセスこそが「クエリ書き換え」です。これがあるおかげで、私たちは複雑なビューを気兼ねなく作れるし、ルールシステムによる強力な抽象化が可能になっています。

2. 魔法の正体:ルールシステム(Rewrite Rules)

PostgreSQLには「ルールシステム」という強力な機能が備わっています。これこそが書き換えエンジンの心臓部です。

皆さんが `CREATE RULE` を使う機会は少ないかもしれませんが、実は `VIEW` を作るとき、内部ではこのルールが動いています。

具体例:ビューの書き換え

例えば、こんなビューがあるとします。

CREATE VIEW active_users AS
SELECT FROM users WHERE status = ‘active’;

ここで `SELECT FROM active_users WHERE id = 1;` というクエリを投げると、Rewriterは以下のようにツリーを書き換えます。

  • 元: `SELECT FROM active_users WHERE id = 1`
  • 書き換え後: `SELECT FROM users WHERE status = ‘active’ AND id = 1`

こうすることで、プランナーは「`active_users` という得体の知れない存在」ではなく、「`users` テーブルに対する最適化」を直接考えられるようになる。これ、凄くないですか?

3. 実務で知っておくべき「落とし穴」

この仕組みを理解していると、現場のトラブルシューティングで一歩先を行けます。

(1)「書き換え」によるパフォーマンスの劣化

ルールによる展開は非常に便利ですが、複雑すぎるルールや深い階層のビューを重ねると、Rewriterが生成するクエリツリーが巨大化します。たまに「単純なSQLなのに実行計画作成(Planning)にやたら時間がかかる」というケースがありますが、原因の一つはこれです。

アドバイス: 階層が深すぎるビューや、複雑なUNION ALLを含むビューは、プランナーが最適化の糸口を見失う原因になります。過度な抽象化には注意してください。

(2)INSERT/UPDATE時の「条件付きルール」

`ON INSERT DO INSTEAD` のようなルールを使うと、書き込みの動作を完全に別物にすり替えられます。これを使えば「論理削除」を透過的に扱うこともできますが、デバッグが地獄になります。

「なぜかデータが入らない」「別のテーブルに値が飛んでいる」という時、真っ先に疑うべきはルールです。`\d+ テーブル名` でルールが定義されていないか、確認する癖をつけておきましょう。

4. 最後に:エンジニアとしての視点

クエリ書き換えエンジンは、PostgreSQLというデータベースが持つ「柔軟性」と「厳密さ」を両立させるための、まさに接着剤のような存在です。

普段意識せずとも動いてくれるものですが、いざという時、この「裏側で何が起きているか」を想像できる力は、あなたのチューニングスキルを一段上のレベルへ引き上げてくれます。

「PostgreSQLは、自分のSQLをどう解釈し、どう『翻訳』したのか?」

そう思ったら、`EXPLAIN` を眺めるだけでなく、`log_statement = ‘all’` で出力されるログや、より深い内部構造を覗いてみてください。データベースと会話ができるようになると、エンジニアとしての仕事はもっと面白くなりますよ。

それでは、良いクエリチューニングライフを!

コメント

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