「インデックスを貼ったのに、なぜかクエリが遅い……」
DBエンジニアなら一度は直面するこの壁。そんな時、`EXPLAIN`の結果を見て「Bitmap Heap Scan」という文字を見つけたことはありませんか?
「ああ、インデックスがうまく効いてないのか」と溜息をつく前に、ちょっと待ってください。実はそのBitmap Heap Scanこそが、PostgreSQLが過酷なディスクI/O環境で生き残るための「賢い生存戦略」なんです。
今日は、このビットマップヒープスキャンが裏で何を考えているのか、なぜあなたのクエリを救おうとしているのかを、現場の視点から紐解いていきましょう。
—
インデックススキャン vs ビットマップヒープスキャン
まず、基本をおさらいしましょう。通常、私たちがインデックスを使うときは「Index Scan」を期待しますよね。これはインデックスを辿りながら、一つずつテーブルの行(ヒープ)にアクセスする手法です。
しかし、もし「検索対象の行がテーブル全体にバラバラに散らばっていたら?」
一つずつインデックスを辿ってディスクを見に行くと、HDDやSSDはヘッドを行ったり来たりさせる「ランダムI/O」の嵐に巻き込まれます。これが、インデックスを使っているのにクエリが遅くなる主犯です。
そこで登場するのが Bitmap Heap Scan です。
ビットマップヒープスキャンの「賢い仕組み」
この手法は、一度にすべてを解決しようとせず、二段構えで動きます。
1. Bitmap Index Scan: インデックスをスキャンして、条件に合う行の場所(タプルID)を特定し、それを「ビットマップ(0と1の地図)」というメモリ上のデータ構造に変換します。
2. Bitmap Heap Scan: メモリ上のビットマップを「物理的な順序(ディスク上の位置)」に並び替えます。そして、ディスクを先頭から順に走査しながら、ビットマップで「1」になっている場所だけを拾い上げます。
つまり、ランダムアクセスをシーケンシャルアクセスに変換するという荒技なんです。
—
実際にどう動いているか見てみよう
例えば、ある会員テーブルで「登録日が特定範囲」かつ「ステータスがアクティブ」という検索をかけるとします。それぞれの条件にインデックスを貼っていても、Bitmap Heap Scanが選ばれることが多いはずです。
— こんなクエリを投げると…
EXPLAIN ANALYZE
SELECT FROM users
WHERE created_at > ‘2023-01-01’ AND status = ‘active’;
このとき、PostgreSQLはこんな判断をしています。
- 「`created_at`のインデックスで見つけた行」と「`status`のインデックスで見つけた行」をビットマップ上で論理積(AND)をとる。
- 物理的に近い位置にある行をまとめて読み込む。
これにより、バラバラな位置にある1,000行を、ディスクを何往復もして探すのではなく、ディスクの塊をガサッと読み込むだけで済ませるわけです。これが実務において「I/O負荷を劇的に下げる」正体です。
—
「Bitmap Heap Scan」が多発する時の心構え
もし、チューニング中に常にBitmap Heap Scanが出てきて悩んでいるなら、以下のポイントをチェックしてみてください。
- work_memの設定は適切か?
ビットマップはメモリ(`work_mem`)上に作成されます。もしビットマップが大きすぎてメモリに収まらなくなると、ディスクへの書き出し(Lossy Bitmap)が発生し、精度が落ちます。複雑なクエリを叩くなら、`work_mem`を少し多めに積むのが定石です。
- テーブルの断片化(Vaccum)は足りているか?
物理順序を最適化するBitmap Heap Scanといえど、テーブルが物理的にバラバラ(断片化)であれば効果は半減します。`VACUUM ANALYZE`は定期的に、いや、必須で回しましょう。
- 「本当にインデックスが必要か?」を疑う
Bitmap Heap Scanが多発するということは、オプティマイザが「インデックスだけじゃ絞りきれないな(あるいはランダムI/Oが多すぎるな)」と判断している証拠です。複合インデックスを貼ることで、そもそもビットマップ変換の必要がない「Index Scan」に持っていける可能性がないか、一度構成を見直してみる価値はあります。
—
最後に:ツールとしてのデータベースを使いこなす
「Bitmap Heap Scanが出た=インデックス設計の失敗」なんて単純な話ではありません。むしろ、PostgreSQLが物理的な制約を乗り越えるために気を遣ってくれている、ありがたい機能なんです。
データベースはブラックボックスではありません。`EXPLAIN`という鏡を使って、彼らが裏でどう悩み、どう解決しようとしているのか。その「意思」を読み解けるようになると、パフォーマンスチューニングは格段に面白くなりますよ。
現場からは以上です!また何か詰まったら、いつでも聞いてくださいね。
コメント