【実務・中級編】 ビットマップヒープスキャン – PostgreSQL

「なぜインデックスがあるのに遅い?」を解決する:PostgreSQLのビットマップヒープスキャンを理解する

やあ。最近、PostgreSQLのパフォーマンスチューニングで悩んでる?
「インデックスを貼ったはずなのに、なぜか期待した速度が出ない」「`EXPLAIN ANALYZE`を見ると、見慣れない `Bitmap Heap Scan` という文字が出てくる……」。

そんな疑問を持つ君のために、今日はPostgreSQLの縁の下の力持ち、「ビットマップヒープスキャン」について深掘りしよう。教科書には載っていない、現場で「なるほど!」と思えるような話を詰め込んだから、コーヒーでも飲みながら読んでいってくれ。

—

1. なぜ「ビットマップ」が必要なのか?

PostgreSQLには主に2つのスキャン方式がある。

  • Index Scan: インデックスを辿って、そのままテーブル(ヒープ)に1行ずつアクセスする。
  • Sequential Scan: テーブル全体を端から端まで読み込む。

これらは極端なんだ。前者は1行ずつ行ったり来たりするから、データ量が増えるとディスクI/Oがランダムアクセスだらけになって遅くなる。後者はデータが多すぎると単純に時間がかかる。

そこで登場するのが Bitmap Heap Scan だ。
これは、「インデックスから得た情報を一度ビットマップ(メモリ上の地図)に書き出し、ヒープを効率よく読み込む」という、いわば「効率化されたランダムアクセス」なんだよ。

2. ビットマップヒープスキャンの仕組み

処理の流れはこうだ。

1. Bitmap Index Scan: まず、インデックスを読んで「条件に合う行はここにあるよ」という位置情報(タプルID)を、メモリ上にビットマップとして展開する。
2. Bitmap Heap Scan: メモリ上のビットマップを元に、ヒープページを「物理的な配置順(ディスク上の並び)」で読み込む。

ここが重要なんだ。「行番号の小さい順」ではなく「ページ番号の小さい順」に読み込むから、ディスクのヘッド移動(あるいはSSDの読み込み効率)が劇的に改善される。

例えるなら、Index Scanが「リストを見ながら、あちこちの棚に本を取りに行く」作業だとすれば、Bitmap Heap Scanは「事前に棚の場所を地図に書き出し、一番近いルートでまとめて本を回収して回る」ようなものだね。

3. こんな時にこいつは現れる

PostgreSQLがどんな時にこいつを選ぶか、具体例を見てみよう。

例えば、ユーザーのアクセスログが数億行あるテーブルで、`WHERE`句に複数の条件を指定したとする。

SELECT FROM access_logs
WHERE status = ‘active’ AND created_at > ‘2023-01-01’;

このとき、`status`と`created_at`に別々のインデックスがあったらどうなるか?
PostgreSQLは、それぞれのインデックスでビットマップを作り、それをメモリ上で論理演算(AND)して、最終的に必要なページだけをヒープから読み込むんだ。これはIndex Scan単体ではできない芸当だよ。

4. パフォーマンスの落とし穴:work_mem

実務で一番ハマりやすいポイントを教えておくよ。それは `work_mem` だ。

ビットマップを作成するメモリ領域(`work_mem`)が足りなくなると、PostgreSQLはビットマップをメモリに収めきれず、ディスクに書き出してしまう(これを「Lossy Bitmap」と呼ぶ)。こうなるとパフォーマンスはガタ落ちだ。

もし実行計画で `Lossy Bitmap` という文字が見えたら、まずは `work_mem` を少し増やして様子を見てみるのが定石だね。

— 設定変更の例(セッション単位で試すのがおすすめ)
SET work_mem = ’64MB’;
EXPLAIN ANALYZE SELECT FROM access_logs WHERE …;

5. まとめ:現場のエンジニアとして

ビットマップヒープスキャンは、決して「遅いスキャン」じゃない。むしろ、大量の行を効率的に捌くための賢い選択肢なんだ。

もし君がチューニングをしていて `Bitmap Heap Scan` に出会ったら、以下をチェックしてみてくれ。

  • インデックスは適切か?(使われていないインデックスがビットマップの生成を邪魔していないか)
  • `work_mem` は十分か?(`Lossy`になっていないか)
  • テーブルの統計情報は最新か?(`ANALYZE`を忘れていないか)

データベースの性能を極めるのは、こうした「エンジンの鼓動」を感じ取れるようになることだ。また何かあればいつでも聞いてくれ。一緒に最高のシステムを作っていこうぜ!

コメント

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