A PostgreSQL BRIN index can contain block ranges with no summary tuple. Newly completed ranges do not receive an initial summary merely because inserts crossed the range boundary. Until maintenance creates that summary, a BRIN scan cannot use range metadata to exclude the affected heap pages.

This state is normal index maintenance behavior rather than index corruption. It follows from BRIN’s compact design: the index stores summaries for groups of adjacent heap pages instead of one entry per indexed row.

BRIN trades row precision for block-range summaries

A Block Range Index divides a heap relation into consecutive physical page ranges. The pages_per_range storage parameter controls the range size, with 128 pages as the default.

For a common minmax operator class, each summarized range records bounds for values present in that range. A predicate can reject a range when its summary proves that no matching value can be present. Ranges that remain possible candidates are returned through a bitmap scan, and heap tuples are rechecked against the original predicate.

That recheck is fundamental because BRIN is lossy. A summary establishes that a range may contain a match; it does not identify the exact matching tuple.

Physical correlation makes this trade useful. When nearby heap pages also contain nearby indexed values, minmax bounds stay narrow and many ranges can be rejected. Weak correlation produces broad summaries and more candidate pages.

New ranges begin without summary tuples

Index creation scans existing heap pages and creates summaries for their ranges, including the incomplete range at the end of the relation.

Later inserts behave differently. If inserts add tuples to a range that already has a summary, PostgreSQL extends that summary as needed. When growth reaches a new range beyond the last summarized one, PostgreSQL does not synchronously create its initial summary as part of the insertion path.

The new range remains unsummarized until a summarization operation processes it. This separates foreground insert cost from the heap scan needed to construct an initial range summary.

An unsummarized range therefore represents missing pruning metadata, not stale minmax bounds. There is no summary tuple whose bounds can be tested against the scan key.

Unsummarized ranges reduce pruning

A BRIN scan depends on summary information to prove that a block range cannot satisfy its predicates. With no summary for a range, that proof is unavailable.

The safe result is conservative heap access. PostgreSQL cannot discard pages solely from absent metadata, because matching tuples may exist there. The range contributes heap work that a completed summary might have avoided.

This effect can be visible on append-heavy relations. A time-correlated table may have excellent BRIN selectivity across old summarized ranges while a recently appended tail has not yet been summarized. Queries touching that tail can perform more lossy heap rechecks than the physical ordering alone would suggest.

The index can still be valid and useful across the rest of the relation. Summary coverage is a per-range property rather than an all-or-nothing state for the complete index.

VACUUM closes summary gaps

When VACUUM processes a table with a BRIN index, it summarizes existing unsummarized ranges. Autovacuum can provide the same effect when it vacuums the relation.

PostgreSQL also exposes targeted maintenance functions. brin_summarize_new_values(regclass) scans the index for unsummarized ranges and creates their summary tuples. brin_summarize_range(regclass, bigint) restricts the operation to the range containing a specified heap block.

Creating a summary requires reading the corresponding heap pages. The summary cannot be inferred from the BRIN structure because the missing tuple is precisely the metadata being constructed.

Once inserted, that summary becomes available for later scans. Its effectiveness then depends on the operator class and the distribution of values inside the range.

Autosummarize queues work instead of doing it inline

A BRIN index can enable the autosummarize storage parameter. It is off by default.

With autosummarization enabled, insertion at the start of the next block range causes PostgreSQL to request targeted summarization of the preceding completed range. The request is handled by autovacuum infrastructure rather than by the inserting backend performing the heap scan immediately.

This mechanism is asynchronous. A request is fulfilled when an autovacuum worker later finishes work in the same database, so a completed range can remain temporarily unsummarized even with the option enabled.

The request path also has a capacity boundary. If the autosummarization request queue is full, PostgreSQL logs that the request was not recorded. The affected range remains unsummarized until a later regular vacuum or an explicit summarization function processes it.

Autosummarize therefore reduces the expected lifetime of summary gaps; it does not make range completion and summary creation atomic.

Range size changes both metadata density and pruning precision

pages_per_range sets the granularity of the BRIN structure. Smaller ranges produce more summary tuples and a larger index, while giving predicates finer physical regions to reject. Larger ranges reduce index metadata but aggregate more heap pages behind each summary.

Unsummarized ranges inherit the same granularity. If one large range lacks a summary, more heap pages sit behind that missing pruning decision than with a smaller range configuration.

After summarization, range size still matters. A minmax summary spanning many pages can accumulate broad bounds, especially when physical correlation is imperfect. A candidate range then sends all relevant pages to the lossy bitmap path even if only a small subset of tuples matches.

The storage parameter therefore controls both persistent summary density and the unit at which missing summary coverage affects scans.

Desummarization deliberately restores the unsummarized state

PostgreSQL can remove an existing range summary with brin_desummarize_range(regclass, bigint). This is useful when a summary has become a poor representation of the current values and rebuilding it is preferable.

Desummarization removes pruning metadata for that range until a later summarization recreates it. During that interval, scans must again treat the range conservatively.

Rebuilding does not guarantee narrow bounds. If the heap pages contain widely scattered values, a fresh minmax summary will accurately represent that broad distribution. The maintenance operation repairs summary state, not physical ordering.

This distinction separates two sources of excess heap work: absent summaries and valid but nonselective summaries. Both can increase rechecks, but only the first is resolved simply by summarization.

Summary coverage is part of BRIN scan quality

BRIN index size alone does not describe its current pruning capability. Two indexes with the same operator class and range size can produce different heap work when one has unsummarized ranges.

For append-oriented workloads, the newest physical ranges are the natural place for this gap because relation growth creates new ranges continuously. Vacuum cadence, autosummarization behavior, request-queue pressure, and explicit maintenance determine how long those gaps persist.

Once summary coverage is complete, physical correlation and range granularity dominate pruning quality. Before that point, missing summaries impose a stricter boundary: PostgreSQL lacks the metadata needed to rule those ranges out at all.