【実務・中級編】 インデックスページレイアウト – PostgreSQL

お疲れ様!今日もバリバリ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がどうやって爆速でデータを探しているのか」という息遣いが聞こえてくるはずだよ。

また技術的なことでモヤモヤしたら、いつでも聞いてくれ。一緒に深掘りしていこう!

コメント

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