A multicolumn B-tree is ordered first by its leading key, then by later keys inside each leading-key group. That ordering normally favors predicates that constrain the left side of the index. PostgreSQL 18 can also use skip scan in selected cases where a query constrains a later key and leaves an earlier key without an equality condition.

Skip scan does not turn column order into an irrelevant detail. It changes the cost of some searches by allowing the executor to perform repeated targeted probes instead of reading a large continuous span of the index.

The index still has a leading-key structure

Consider an event table with a B-tree on (status, created_at):

CREATE INDEX event_status_created_idx
    ON event (status, created_at);

Entries are grouped by status, with created_at ordered inside each group. A predicate that supplies both values fits that layout directly:

SELECT id, status, created_at
FROM event
WHERE status = 'queued'
  AND created_at >= TIMESTAMPTZ '2026-09-14 00:00:00+00';

The equality condition on status identifies one leading-key group. The range condition on created_at then identifies a bounded part of that group.

A query on the second key alone has a different shape:

SELECT id, status, created_at
FROM event
WHERE created_at >= TIMESTAMPTZ '2026-09-14 00:00:00+00';

There is no single contiguous region containing every matching row across all status values. Each status group can contain its own matching suffix.

Skip scan performs repeated searches

For a suitable query, PostgreSQL can internally generate equality conditions for values of an omitted prefix column. Conceptually, a search on the later key can act like a series of probes:

status = value_1 AND created_at >= boundary
status = value_2 AND created_at >= boundary
status = value_3 AND created_at >= boundary
...

Those generated conditions are an execution technique, not SQL text added to the statement. Each probe can reposition the B-tree scan near entries that satisfy the later-key predicate. Pages between useful regions can then be bypassed.

This behavior is most attractive when the omitted prefix has relatively few distinct values and the later-key condition excludes substantial parts of each group. If the leading key has a very large number of distinct values, repeated probes can become more expensive than reading the table or using another index.

The planner makes that choice from estimated costs. The presence of a compatible multicolumn index does not guarantee a skip scan plan.

Column order still controls the search space

Skip scan extends the set of cases in which a multicolumn B-tree can be useful, but it does not make (a, b) equivalent to (b, a).

With an index on (status, created_at), a query that filters only created_at may need one probe per relevant status value. An index on (created_at, status) can place a range on created_at at the leading edge and scan that range directly.

That distinction matters for index design. If later-key-only searches dominate a workload, a dedicated index with that key first can still be a better fit. Skip scan is more interesting when the existing composite index already serves common multi-key predicates and the omitted prefix has low enough cardinality for repeated probes to remain cheap.

Separate indexes are another option:

CREATE INDEX event_status_idx ON event (status);
CREATE INDEX event_created_idx ON event (created_at);

PostgreSQL can combine indexes through bitmap operations for some predicates. Bitmap combination has different properties from a multicolumn B-tree scan: it reads multiple indexes, constructs bitmaps, and loses index ordering before visiting heap rows. A composite index, a dedicated single-column index, and skip scan therefore cover overlapping but non-identical access patterns.

Selectivity and prefix cardinality shape the plan

Two data properties have a large effect on skip scan economics.

The first is the number of distinct values in the omitted prefix. An index whose first column contains a small state set such as queued, running, and done gives the executor only a few groups to probe. A first column containing millions of account identifiers presents a very different search space.

The second is the selectivity of the constrained later key. A narrow timestamp boundary or a rare value can let each probe jump over many entries. A condition matching most of the table leaves less index data to bypass, reducing the benefit of repositioning.

Statistics therefore affect whether the planner expects skip scan to pay off. A plan observed on one data distribution should not be treated as a fixed property of the SQL statement.

Later constraints can also refine a partially bounded scan

Skip scan is not limited to the case where every prefix key is unconstrained. A multicolumn index on (a, b, c) can have an equality predicate on a, a range on b, and an additional condition on c.

CREATE INDEX measurement_abc_idx
    ON measurement (a, b, c);

SELECT *
FROM measurement
WHERE a = 5
  AND b >= 42
  AND c < 77;

The normal B-tree boundary starts with a = 5 and b >= 42. Depending on costs and data distribution, PostgreSQL can use skip behavior to reposition across groups inside that broader range when the c condition makes portions of those groups irrelevant.

This is a useful distinction from simple index filtering. A condition checked against index entries can avoid some heap visits without reducing the index region that must be read. Repositioning can reduce index work itself when the planner estimates that skipping is profitable.

Plans remain data-dependent evidence

EXPLAIN is the practical place to check how a specific query is being executed:

EXPLAIN
SELECT id, status, created_at
FROM event
WHERE created_at >= TIMESTAMPTZ '2026-09-14 00:00:00+00';

For runtime measurements, EXPLAIN (ANALYZE, BUFFERS) adds actual timing, row counts, and buffer activity, but it executes the statement. That distinction matters for statements with side effects.

Planner decisions can change as table size, value distribution, statistics, configuration, and PostgreSQL versions change. Index design should therefore follow stable query patterns and observed plans rather than an assumption that one access path will always be selected.

Skip scan makes a composite B-tree useful across more predicate shapes than a strict left-prefix rule suggests. Its boundary is equally significant: repeated probes only make sense when they avoid enough index work to offset their cost. Column order remains part of the physical access strategy, even when PostgreSQL can occasionally bridge a missing prefix condition.