巨大なデータの海で迷子にならないために。PostgreSQLの「BRINインデックス」という秘密兵器の話
こんにちは!日々のデータベース開発、お疲れ様です。
皆さんは、何億行もあるような巨大なテーブルを扱ったことはありますか?
「最新のデータをサッと取り出したいだけなのに、検索が全然終わらない……」
「インデックスを貼ったら、今度はインデックスだけでディスクをパンパンに埋め尽くしてしまった……」
そんな絶望的な状況を救ってくれる、ちょっと「賢い」インデックスがあるんです。それが、PostgreSQLのBRIN(Block Range Index)。
今日は、このBRINの魅力を、専門用語を抜きにして、皆さんと一緒に紐解いていこうと思います。
—
「図書館の本」で例えるインデックスの仕組み
まず、普通のインデックスを「図書館の索引」だと思ってください。「Aさんという名前の本はどこ?」と聞かれたら、索引が「Aさんは3番の棚の、2段目の右から5冊目だよ!」と事細かに教えてくれますよね。これが通常のB-treeインデックスです。
でも、もし図書館に本が100億冊あったらどうでしょう? 索引そのものが巨大になりすぎて、索引を探すだけで日が暮れてしまいますよね。
ここで登場するのがBRINです。
BRINは、もっとざっくりした「地図」のようなもの。
「Aさんの本? うーん、たぶんこの辺りの『30番から40番の棚』にあると思うよ!」と、広い範囲で教えてくれるんです。
なぜ「ざっくり」だと嬉しいのか?
「えっ、ピンポイントで教えてくれないなら意味がないのでは?」と思いましたか?
実は、ここが時系列データにおいては最強の武器になるんです。
例えば、「時刻順」にデータが保存されているログテーブルを想像してください。
- 新しいデータほど、物理的に後ろのほうに保存される。
- 古いデータは、前のほうに保存される。
この場合、データが最初から「並んでいる」状態ですよね。
BRINは「この範囲(ブロック)には、2023年10月のデータが入っているよ」という情報を、ほんのわずかなサイズで記録します。
- 通常のインデックス: 巨大すぎて、インデックス自体がディスクを食いつぶす。
- BRIN: 驚くほど小さい。数GBのデータでも、数MBのインデックスで済むことも珍しくありません。
—
「pages_per_range」という調整つまみ
BRINを使うとき、唯一と言っていいほど大事なのが`pages_per_range`という設定です。これは「どれくらいの広さを一つの範囲としてまとめるか」という「粒度」を決めるつまみです。
- 範囲を小さくする(細かい地図): 検索は速くなるけど、地図(インデックス)の枚数が増えて少し重くなる。
- 範囲を大きくする(大雑把な地図): 地図はめちゃくちゃ小さくなるけど、探すときに「この範囲の中を全部見なきゃいけない」から少し手間がかかる。
この「粒度」をどう決めるか。これがエンジニアの腕の見せ所です!
最初はデフォルトの設定で試してみて、「もう少し速くしたいな」とか「もう少しインデックスを小さくしたいな」という感覚に合わせて調整していくのが、一番の近道ですよ。
—
注意点:BRINを使っちゃいけない時
一つだけ、気をつけてほしいことがあります。
BRINはあくまで「データが物理的に並んでいる」からこそ力を発揮するんです。
もし、ランダムなID順にデータがバラバラに保存されているテーブルにBRINを貼ったらどうなるか……。「この範囲の中に、ID 1番も100万番も混ざってるよ!」という、役に立たない地図ができあがってしまいます。これだと検索効率はガタ落ちです。
- 時系列データ(ログ、計測値など): BRINはまさに「神」です。
- ランダムなキー: 素直に通常のB-treeインデックスを使いましょう。
—
最後に
データベースの設計は、完璧な正解を最初から出すことよりも、データの性格を見極めて「どれが今の自分たちに最適かな?」と選ぶプロセスそのものが面白いですよね。
BRINは、巨大なデータを扱うときの「小さくて賢い味方」です。もし皆さんの環境に、何千万行ものログテーブルが眠っていたら、ぜひ一度試してみてください。
「おっ、こんなに軽くなるんだ!」という驚きを、ぜひ体験してほしいなと思います。
また次回の技術談義でお会いしましょう!質問があれば、いつでもコメントしてくださいね。
コメント