お疲れ様!今日もバリバリSQL書いてる?
今日は、普段何気なく使っている「インデックス」の裏側、特にPostgreSQLの「ページレイアウト」の話をしようと思う。
ぶっちゃけ、普段の業務で「ページがどうなってるか」なんて意識しなくてもクエリは書ける。でもね、パフォーマンスチューニングの壁にぶち当たったとき、あるいは「なぜこのインデックスが効かないんだ?」と悩んだとき、この構造を知っているかどうかで、エンジニアとしての解像度が全く変わってくるんだ。
よし、深掘りしていこう。
—
1. PostgreSQLにおける「ページ」という単位
PostgreSQLの世界では、データもインデックスもすべて「8KBのページ」という単位で管理されている。この8KBの中に、レコード情報やインデックスのキーが詰め込まれているわけだ。
B-treeインデックスも例外じゃない。このページが階層構造(ツリー)になっていて、僕たちが `SELECT FROM users WHERE id = 123` と叩いたとき、PostgreSQLはこのページを上から下へと辿っているんだ。
2. インデックスページの3つの顔
インデックスのページは、役割によって大きく3つに分類できる。
① メタページ (Meta Page)
これはインデックスの「司令塔」だ。ページの先頭(0番目)に1枚だけ存在して、インデックス全体のルートページがどこにあるか、現在のバージョンはどうなっているかといった「管理情報」を握っている。
- 実務でのヒント: 滅多に意識しないけど、ここが壊れるとインデックス全体が死ぬ。`pg_am` のあたりと連携して動いている重要拠点だと思っておけばOK。
② 内部ページ (Internal Pages)
ツリーの「枝」にあたる部分。ここには「どの範囲の値なら、どのページへ進めばいいか」という道しるべ(キーと子ページへのポインタ)が書かれている。
- 重要: 内部ページには実データへのポインタ(TID)は載っていない。あくまで「道案内」に特化しているのがポイントだね。
③ リーフページ (Leaf Pages)
ここが「末端」。インデックスの検索結果として最終的に辿り着く場所だ。ここには、実際のテーブルデータの場所を示す「TID(Tuple Identifier)」が格納されている。
- ここが肝: `SELECT FROM … WHERE …` でインデックスを使うとき、最後にこのリーフページからTIDを拾い上げ、テーブル側のページへヒョイっと移動する。これが「インデックススキャン」の正体だ。
—
3. 構造を覗き見てみる(pageinspectのすすめ)
「百聞は一見に如かず」ということで、実際に自分の環境でページの中身を覗いてみよう。`pageinspect` という標準拡張モジュールを使うと、PostgreSQLの内部を丸裸にできるよ。
— まず拡張をインストール(権限が必要だよ)
CREATE EXTENSION pageinspect;
— インデックスのメタ情報を見てみる
SELECT FROM bt_metap(‘my_index_name’);
— インデックスの特定のページ(例えばルート)の中身を確認
— page_numberは0から順に試すといい
SELECT FROM bt_page_items(‘my_index_name’, 1);
これを実行すると、`itemoffset`, `ctid`, `key` といった情報がズラッと出てくる。`ctid` が `(0, 1)` みたいに表示されるのを見ると、「ああ、このインデックスはあのページを指しているんだな」と視覚的に理解できるはずだ。
—
4. なぜこの知識が現場で役立つのか?
「で、結局これが何の役に立つの?」と思うかもしれない。でも、この構造を知っていると、チューニング時の視点が変わるんだ。
- インデックスの肥大化対策: 頻繁に更新(UPDATE)が入るカラムにインデックスを貼ると、リーフページがどんどん分割(Page Split)されていく。ページ構造を知っていれば、「あ、これインデックスがスカスカになって読み込み効率が落ちてるな」と推測して `REINDEX` を検討する判断が早くなる。
- 複合インデックスの設計: `(A, B)` という順序でインデックスを貼る意味を、内部ページの「道案内」の仕組みとして理解できるようになる。先頭カラムが重要視される理由が納得できるはずだ。
—
最後に:深みにハマる楽しさ
データベースの内部構造を知ることは、車のエンジンの構造を知ることに似ている。普段は運転(クエリ発行)に集中すればいいけれど、いざトラブルが起きたとき、あるいは最高速を出したいときに、その知識が強力な武器になる。
もし興味が湧いたら、ぜひ `pageinspect` を使って、自分の開発環境のインデックスを覗いてみてほしい。最初は記号の羅列に見えても、じっと見ていると「PostgreSQLがどうやって爆速でデータを探しているのか」という息遣いが聞こえてくるはずだよ。
また技術的なことでモヤモヤしたら、いつでも聞いてくれ。一緒に深掘りしていこう!
コメント