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ライフは劇的に面白くなるはずだ。
次は、このリライタが吐き出したクエリツリーを、オプティマイザがどうやって料理するのか……その話もまた面白いんだが、それはまた今度、コーヒーでも飲みながら話そうか。
何か詰まったら、いつでも聞きに来てくれ。頑張れよ!
コメント