Guide · The plan, node by node
Bitmap Heap Scan
A Bitmap Heap Scan is two nodes. The Bitmap Index Scan under it walks the index and, instead
of fetching rows as it goes, marks every matching page in a bitmap. The Bitmap Heap Scan
then reads those pages once each, in physical order, and rechecks the condition on every row.
It is the planner's middle ground: too many rows for an Index Scan to
fetch one at a time, too few for a Seq Scan. SELECT * FROM commerce.orders WHERE status = 'cancelled' on orders_status_placed_idx is the shape, where
status has a correlation of 0.04.
Why it matters
Fine while the bitmap stays exact. It lives in work_mem, and when it outgrows that
PostgreSQL stops tracking rows and tracks whole pages. The scan then reads every row on those
pages, counting the ones that fail as Rows Removed by Index Recheck. EXPLAIN ANALYZE
prints Heap Blocks: exact=N lossy=M, and any lossy above zero means the bitmap
overflowed.
What to do
- If
lossyis above zero, raisework_memfor the session and run again. - If the recheck removes most rows and the bitmap was exact, the index condition is weaker than the filter. Add the filtered column to the index.
- If the scan keeps most of the table, it is a Seq Scan with extra steps. Check the
estimate first. Estimated rows explains the
≈Nlabel.
In the Plan tab
The Bitmap Index Scan is folded into its Bitmap Heap Scan, so you see one node. Its wheel
matches the last of the five patterns the TABLE WHEEL guide draws.
The five ways a scan reaches a table, as the TABLE WHEEL guide draws them.
The five ways a scan reaches a table, as the TABLE WHEEL guide draws them.
Seq Scanreads the whole rim. A bitmap scan that keeps most of the table ends up here with extra steps.Index Scan · in orderfetches rows one at a time through the spokes, in a short arc. When the rows sit together like this, the bitmap buys little.Index Scan · scatteredfetches rows one at a time across the whole rim, in index order. This is the case the bitmap is for: too many rows to fetch one by one.Index Only Scananswers from the hub and never opens the table.Bitmap Heap Scanis this node: the spokes are the page bitmap, not lookups, and the rim is read once, in page order. Lossy pages are drawn as their own rim segments, each read whole and rechecked row by row.
The finding reads Bitmap went lossy, N lossy pages rechecked, with a Retry · button
carrying the next work_mem to try.
Caveats
- A GIN index like
customers_attributes_idxis always used through a bitmap. That one is not a sign of anything.