A PostgreSQL query does not need a single index that represents every useful predicate. The planner can scan separate indexes, turn their matching tuple locations into bitmaps, combine those bitmaps, and then visit the required heap pages. This is the basis of bitmap index scans and Bitmap Heap Scan plans.

The mechanism sits between two familiar choices. A sequential scan reads the table broadly, while a plain index scan follows index entries to heap tuples as it encounters them. A bitmap plan first gathers locations, then performs heap access as a distinct phase.

Bitmap scans separate matching from heap access

Consider a table with independent indexes:

CREATE INDEX orders_status_idx ON orders (status);
CREATE INDEX orders_region_idx ON orders (region);

A query can constrain both columns:

SELECT id, status, region
FROM orders
WHERE status = 'open'
  AND region = 'east';

PostgreSQL may scan both indexes. Each bitmap index scan identifies tuple locations matching one condition. A BitmapAnd node intersects the sets, leaving locations reported by both scans. The parent Bitmap Heap Scan then retrieves table rows for the resulting locations.

A representative plan shape is:

Bitmap Heap Scan on orders
  Recheck Cond: ((status = 'open') AND (region = 'east'))
  -> BitmapAnd
       -> Bitmap Index Scan on orders_status_idx
       -> Bitmap Index Scan on orders_region_idx

The planner is not joining rows from two indexes. It is combining references to candidate heap tuples before fetching those tuples.

AND and OR can combine index results

Bitmap operations are not limited to intersections. PostgreSQL can use BitmapAnd for conjunctive conditions and BitmapOr for alternatives.

With separate indexes on status and priority, a predicate such as:

WHERE status = 'open' OR priority = 1

can produce bitmap matches from each index and union them before heap access. PostgreSQL can also use the same index more than once when separate conditions make that useful.

This capability changes the index-design space. Separate single-column indexes can sometimes serve queries that filter on combinations of those columns without requiring a dedicated multicolumn index for every combination.

That does not make bitmap combination equivalent to a multicolumn index. A multicolumn B-tree can often narrow a matching range directly when predicates align with its key order. Combining indexes requires multiple index scans plus bitmap construction and merging. The planner estimates those costs for each query.

Heap visits follow physical location order

The bitmap is organized around heap locations. Once candidate locations have been collected, PostgreSQL can visit table pages in physical order rather than repeatedly moving between heap locations in index-key order.

This property is a central distinction from a plain index scan. When many qualifying tuples are spread across the heap, collecting locations first can make table access less scattered.

The ordering also has a consequence: index ordering is not preserved through the bitmap operation. A query with ORDER BY cannot rely on a bitmap scan to emit rows in B-tree key order. If ordered output is required, the plan may need a separate sort.

For queries where an index can both filter rows and supply the requested order, a plain index scan can therefore retain an advantage even when a bitmap alternative exists.

The bitmap can become lossy

Bitmap memory is finite. PostgreSQL can represent exact tuple locations for heap pages, but under memory pressure it can switch some bitmap entries to a lossy representation that records only that a heap page may contain matches.

A lossy page entry means the heap scan must inspect tuples on that page and recheck the relevant conditions. EXPLAIN ANALYZE can expose this behavior through exact and lossy heap-block counts and rows removed by index recheck.

Lossy representation preserves query correctness. It changes the amount of work performed during the heap phase: less detail is retained in the bitmap, so more candidate tuples may need condition evaluation after the page is read.

The available work_mem setting can affect bitmap precision, but raising it solely to alter one plan deserves care because the setting also applies to other operations and can be consumed by multiple nodes or sessions.

Bitmap plans remain cost-based choices

Having two usable indexes does not imply that PostgreSQL will combine them. The planner can choose one index and apply the other predicate as a filter, select a multicolumn index, use a sequential scan, or form a bitmap plan.

Selectivity matters. If one predicate already narrows the result to a tiny set, scanning a second index and intersecting bitmaps may cost more than checking the second condition on the few fetched rows. At the other extreme, a predicate matching a large fraction of the table can make index-driven access unattractive.

Table statistics, estimated row counts, heap layout, index costs, and requested ordering all feed into that decision. Bitmap scanning is an execution option, not a directive attached to the presence of multiple indexes.

Separate indexes and composite indexes serve different shapes

Suppose applications issue three common forms:

WHERE status = 'open'

WHERE region = 'east'

WHERE status = 'open' AND region = 'east'

Separate indexes on each column remain directly usable for the first two forms and can potentially be combined for the third. An index on (status, region) is naturally aligned with predicates beginning at status, and can be more direct for the combined form, but its behavior for a condition on region alone depends on B-tree key ordering and planner choices.

The useful design follows the workload rather than a rule that favors either separate or composite indexes. Write cost also remains part of the structure: every additional index must be maintained as indexed data changes.

Bitmap scans make independent indexes more composable than their definitions might suggest. Their value is clearest when several predicates each identify meaningful candidate sets and collecting heap locations before table access costs less than following each match immediately. The final plan still depends on current statistics and data distribution, so EXPLAIN remains the concrete view of which access path PostgreSQL selected.