「B-treeだけがインデックスじゃない」——巨大データを救うBRINの魔法
やあ。今日はちょっとした「インデックスの使い分け」の話をしようか。
PostgreSQLを触り始めてしばらく経つと、インデックスといえば「B-tree」一択だと思い込んでしまう時期があるよね。もちろん、B-treeは万能だ。でも、数億行、あるいは数十億行に達するような「巨大なテーブル」を扱うとき、B-treeは時として足かせになる。インデックスサイズがメモリに乗り切らなくなって、ディスクI/Oが爆発するからだ。
そんなとき、僕が迷わず切り札として取り出すのがBRIN (Block Range Index) だ。
今日は、この「一風変わった、でも最高にクールなインデックス」について、実務的な視点で深掘りしてみよう。
—
BRINは「辞書」ではなく「付箋」
まず、BRINがどうやって動いているか、イメージで理解しよう。
B-treeが「どの値がどこにあるか」を詳細に記録した辞書だとしたら、BRINは「このページ範囲には、だいたいこのくらいの値が入ってるよ」というアバウトな付箋なんだ。
BRINは、テーブルを一定の「ブロック範囲(デフォルトは128ページ)」で区切り、その範囲内の「最小値」と「最大値」だけをメモリに保持する。検索時には、その範囲を見て「お、探している値はこの範囲に収まっている可能性があるな」というブロックだけをスキャンする仕組みだ。
- メリット: インデックスサイズがB-treeと比べて圧倒的に小さい。数GBのB-treeが、BRINなら数MBで済むことだってある。
- デメリット: 「範囲」で管理しているから、ピンポイントでレコードを特定するのには向かない。あくまで「大まかな絞り込み」用だ。
—
BRINが真価を発揮する「たった一つの条件」
BRINを使う上で絶対に忘れてはいけないルールがある。それは、「テーブルの物理的な格納順序と、インデックスを貼るカラムの値が相関していること」だ。
例えば、`created_at`(タイムスタンプ)のような、時系列でデータが挿入されるカラム。これにはBRINは最強だ。なぜなら、物理的にも過去のデータは前のブロックに、未来のデータは後ろのブロックに並んでいるからだ。
逆に、ランダムなIDやUUIDのように、値がバラバラに挿入されるカラムにBRINを貼っても、各範囲の「最小値・最大値」が全域をカバーしてしまい、結局「全ブロック読み込み」になってしまう。これじゃあ意味がないよね。
—
実践:BRINを作ってみよう
じゃあ、実際にどう使うか見ていこう。巨大なログテーブルを想定してみるよ。
— ログテーブルの作成(数億行あると想像してくれ)
CREATE TABLE access_logs (
id BIGSERIAL,
user_id INT,
created_at TIMESTAMP,
message TEXT
);
— 普通ならここでB-treeを貼るけど、サイズが肥大化してつらい…
— そこでBRINの登場だ!
CREATE INDEX idx_access_logs_created_at
ON access_logs USING BRIN (created_at)
WITH (pages_per_range = 32);
この `pages_per_range` というオプションがミソだ。
- 値を小さくする: 精度は上がるけど、インデックスサイズは少し大きくなる。
- 値を大きくする: インデックスは超軽量になるけど、スキャン効率は落ちる。
ここらへんは、テーブルの総容量と相談しながらチューニングするのがプロの腕の見せ所だ。
—
注意点:運用でハマらないために
現場でBRINを使うときに、必ず後輩に注意していることが2つある。
1. `VACUUM` をサボるな
BRINは、データが更新・削除されると精度が落ちる。`autovacuum` が適切に動いていないと、BRINの付箋情報がどんどん古くなって、検索性能が劣化していくんだ。
2. 「とりあえず全部BRIN」はNG
「B-treeは重いから全部BRINにしよう」なんていうのは悪手だ。頻繁に更新されるカラムや、データが物理的にバラバラなカラムには絶対に使わないこと。
—
まとめ:BRINは「適材適所」の極み
BRINは、いわば「巨大な荒野を走るためのオフロード車」だ。F1カー(B-tree)のように舗装されたサーキットで0.1秒を競うのには向かない。けれど、どこまでも続く巨大なデータという荒野を、少ないリソースで効率よく駆け抜けるには、これ以上の選択肢はない。
「巨大なテーブルでインデックスの容量がヤバい」「時系列データばかり溜まっていく」……そんな悩みを抱えたとき、ぜひ一度BRINを思い出してほしい。
君が扱うデータセットに、BRINという強力な選択肢を加えてみてくれ。きっと、データベースの挙動が今までより少しだけ軽やかに感じられるはずだよ。
それじゃ、また。現場で何か詰まったら、いつでも聞きに来てくれ。
コメント