【実務・中級編】 クエリリライタ – PostgreSQL

PostgreSQLの「縁の下の力持ち」、クエリリライタと仲良くなる話

やあ。今日はPostgreSQLの心臓部、それも普段はあまり表に出てこない「クエリリライタ(Query Rewriter)」という、ちょっと渋いけど非常に賢いコンポーネントについて話そうと思う。

DBを触っていると、「SQLを書けば、あとはオプティマイザがいい感じにしてくれる」と思いがちだよね。でも、実はその一歩手前で、君が投げたSQLを「別の形に作り変えている」やつがいるんだ。それがクエリリライタだ。

こいつの動きを知っておくと、複雑なビューを扱う時や、運用上の「ちょっとした工夫」を実装する時に、めちゃくちゃ頼りになる相棒になるぞ。

—

クエリリライタって、結局何をしてるの?

一言で言うと、「SQLをDBが解釈しやすい形(クエリツリー)に変換した後、ルールに従ってそれを別のクエリツリーに書き換える」という仕事をしている。

一番わかりやすい例が「ビュー(View)」だ。君が `SELECT FROM my_view` と打ったとき、PostgreSQLは裏で「あ、これはビューだな。定義されているテーブルのクエリに書き換えなきゃ」と判断する。これがリライタの基本動作だ。

実践的な例:ルールシステムでクエリを「横取り」する

PostgreSQLには「ルールシステム(Rule System)」という機能がある。これこそがリライタの主戦場だ。例えば、「特定のテーブルに対するDELETEを、データ消去ではなくフラグ更新(論理削除)にすり替える」なんて荒業も、ルールを使えば一行で終わる。

実際にやってみよう。

— サンプルテーブル
CREATE TABLE users (
id serial PRIMARY KEY,
name text,
is_deleted boolean DEFAULT false
);

— DELETEが呼ばれたら、代わりにUPDATEを発行するルールを作成
CREATE RULE soft_delete AS
ON DELETE TO users
DO INSTEAD (
UPDATE users SET is_deleted = true WHERE id = OLD.id
);

こうしておけば、エンジニアがうっかり `DELETE FROM users WHERE id = 1;` と打っても、リライタが瞬時に検知して、裏で `UPDATE users SET is_deleted = true WHERE id = 1;` に変換してくれる。

ここで注意!現場からのアドバイス

このルールシステム、強力なんだけど「諸刃の剣」だ。
正直に言うと、最近の実務では「トリガー(Trigger)」を使う方が推奨されることが多い。

なぜか?
ルールはクエリそのものを「書き換える」から、デバッグが難しいんだ。特に複雑なルールを重ねると、SQLの実行計画がとんでもないことになったり、想定外の挙動をしたりする。
「ルールは強力だが、デバッグが困難」というこの感覚、ぜひ覚えておいてほしい。

なぜこの仕組みを知っておく必要があるのか

「じゃあルールシステムは使わない方がいいんですか?」と思うかもしれないね。そうじゃない。「PostgreSQL内部で何が起きているか」を理解するために必要不可欠なんだ。

例えば、パフォーマンスチューニングをしているとき、Explainの結果を見て「なんでこんな結合が増えてるんだ?」と悩むことがあるだろう。それは往々にして、Viewの展開(リライト)によってクエリツリーが肥大化していることが原因だったりする。

クエリリライタの存在を意識しているエンジニアは、SQLの構造を見ただけで「あ、ここでViewを展開して結合してるな。ここはインデックスを貼っておかないと重くなるぞ」と、一歩先を予測できるんだ。

まとめ:魔法を「納得」に変えよう

PostgreSQLのクエリリライタは、ユーザーの利便性のためにSQLを裏でこっそり翻訳してくれる優秀な翻訳機だ。

1. クエリリライタは、SQLを別のクエリツリーに書き換える司令塔。
2. Viewの展開やルールシステムによるクエリのすり替えは、すべてリライタが担っている。
3. ルールシステムは強力だが、デバッグや可読性の観点からは慎重に使うこと。

教科書的な知識だけじゃなく、「なぜDBがこう動くのか」を想像できるようになると、君のSQLライフは劇的に面白くなるはずだ。

次は、このリライタが吐き出したクエリツリーを、オプティマイザがどうやって料理するのか……その話もまた面白いんだが、それはまた今度、コーヒーでも飲みながら話そうか。

何か詰まったら、いつでも聞きに来てくれ。頑張れよ!

コメント

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