位圖索引掃描 是 PostgreSQL 针對「中等選擇率」查詢的核心優化路徑。本文以實際 EXPLAIN ANALYZE 輸出為例,拆解 Bitmap Index Scan → Bitmap Heap Scan 的兩階段機制。
當查詢條件選擇率介於「全表掃描」與「索引掃描」之間(約 1%~15%),PostgreSQL 會:
Recheck Cond),過濾假陽性。QUERY PLAN
--------------------------------------------------------------------------------------------------
Bitmap Heap Scan on bitmap_test (cost=2023.16..4157.75 rows=99967 width=4)
(actual time=24.373..41.054 rows=100000 loops=1)
Recheck Cond: (is_visible = 'yes'::bpchar)
-> Bitmap Index Scan on idx_bitmap_is_visible (cost=0.00..1998.17 rows=99967 width=0)
(actual time=24.252..24.252 rows=100000 loops=1)
Index Cond: (is_visible = 'yes'::bpchar)
Total runtime: 47.175 ms
| 欄位 | 含義 | 本例數值 |
|---|---|---|
| cost=2023.16..4157.75 | 啟動成本..總成本(規劃器估算單位) | 啟動 2023,總 4157 |
| rows=99967 | 預估回傳列數 | 近 10 萬列 |
| actual time=24.373..41.054 | 實際啟動/總耗時(ms) | 41 ms 完成 |
| rows=100000 | 實際回傳列數 | 與估算極接近,統計資料準確 |
| Recheck Cond | Heap Scan 階段需重新檢查的條件(位圖可能含假陽性) | is_visible = 'yes' |
| Index Cond | Index Scan 階段使用的索引條件 | 同上 |
| 查詢特徵 | 掃描方式 | 理由 |
|---|---|---|
| 高選擇率(< 1%) | Index Scan / Index Only Scan | 隨機 I/O 少,直接走索引最快 |
| 中等選擇率(1%~15%) | Bitmap Index/Heap Scan | 位圖將隨機 I/O 轉為循序 I/O,減少磁碟搜尋 |
| 低選擇率(> 15%) | Seq Scan | 讀全表比跳來跳去更快 |
ANALYZE 或啟用 autovacuum,否則規劃器誤判選擇率導致走錯路徑work_mem 過小會導致位圖「失真」退化為 Bitmap Index Scan -> Heap Scan (lossy),需適度調大(如 64MB~256MB)BRIN 索引替代,空間極小總結: 位圖掃描是 PostgreSQL 「中間地帶」的利器,關鍵在於 work_mem 足夠、統計資料準確、條件選擇率落在最佳區間。