Build1 distinct publisher3 min readPublished
PostgreSQL still reported 0.921 correlation and a 48 kB index at that point, so the damage only showed up in the execution plan, where recheck threw away 3.8 million rows to return 111,112.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Convert the page counts into range summaries and the mechanism stops being mysterious. With `pages_per_range=128`, each BRIN entry covers 128 consecutive heap blocks [3]. The fresh query read 1,536 heap pages, which is about twelve ranges [4][1]. After cumulative updates reached 5% of rows it read 51,268, which is roughly four hundred [9][1]. Assume the standard 8 kB block and the 976 MB heap holds about 124,928 blocks, or 976 ranges in total, so the query went from touching a bit over 1% of the table to 41% of it [2].
The damage is not proportional to churn. Five percent of 10 million rows is 500,000 updated rows, and between the 1% and 5% runs the count of matching ranges rose by roughly 386 [7]. One badly placed tuple is enough to stretch a range's minimum and maximum across the query's date boundary [13]. So 386 well-scattered relocations out of half a million updates would produce the whole result [7]. Sakamuri spent seven years in Oracle R&D and says he co-owned its Zonemaps module, which uses the same minimum and maximum values to decide which blocks a query can skip [15]. That background is what gives weight to his read on this failure: he is looking at a structure of the same kind he used to build.
The invisible constraint is free space. The updated column was not indexed [7], which is the case PostgreSQL can normally satisfy inside the page; the new tuple version lands elsewhere in the heap only when the original page has no room [13]. A bulk load in timestamp order [2] leaves pages with nothing spare. Meanwhile the global correlation statistic keeps measuring broad ordering between column and physical position, which is not what pruning depends on [12]. The catalog keeps reporting 48 kB throughout, a figure that stays accurate even as it stops describing anything useful about the index's behavior.
The two published times for the same 5% run differ by 132.8 milliseconds, about 24% [5]. That matters less for the 5% verdict than for the 20% one. The summary time at 20% churn, 690.6 ms [11], sits within a millisecond of the plan capture at 5%, while lossy pages over that interval rose 25% [6]. Read against the plan number, pruning is mostly finished by 5% and further churn buys little extra damage. That gap between the two figures is left open in the post [10], and it is the open question that decides which reading of the 20% number holds.
For the number to transfer you need several things true at once: a heap loaded in key order with no room on its pages, updates scattered across the key domain rather than piled at the newest end, a predicate narrow relative to the table (one day out of ninety here [2][3]), and a `pages_per_range` large enough that one poisoned range costs 128 page reads [3]. Concentrate the churn at the tail and the poisoned ranges are the ones your queries were already reading. Sakamuri says the run establishes a failure mode rather than a universal rule [17], and the post doubles as a demonstration for DeepSQL, his open-source self-hosted agent that reads slow queries and plans and recommends indexes [16]. The usable output is the monitoring target he names: watch lossy heap pages and rows discarded at recheck in the plan over time, because size and correlation will not tell you [18].
Ranked by verification strength, evidence, and original report placement.
DeepSQL's Venkat Sakamuri published an article dated August 27th showing how quickly a compact PostgreSQL BRIN index can lose its block-skipping advantage when updates disturb the physical order of a table.
Sakamuri loaded 10 million rows covering 90 days into PostgreSQL 17.9, inserting them in timestamp order; the resulting heap occupied 976 MB.
He created a BRIN index on created_at with pages_per_range=128, and used a one-day query that returned 111,112 rows.
On the fresh table the BRIN index occupied 48 kB, and the BRIN query ran in 21.2 milliseconds while touching 1,536 heap pages.
An equivalent B-tree index occupied 214 MB, or 4,570 times as much space as the BRIN index.
PostgreSQL's BRIN documentation describes storing summaries for consecutive physical block ranges rather than one entry per row; ranges whose values cannot satisfy a query are skipped, and PostgreSQL must fetch and recheck every tuple in any range whose summary could match.
Distinct publishers with included, body-backed reporting in this cluster.
1 article · August 27, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
DuckDB is growing a server, and someone on your team will have to run it1 distinct publisher
build
The ICO fines what you cannot prove: Article 32 makes encryption and erasure an engineering liability1 distinct publisher
build
Object or file storage: the wrong pick stays quiet until inode exhaustion1 distinct publisher
build
A foreign-key cycle where every column is NOT NULL cannot take its first row1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Detailed, methodology-disclosed benchmark from one vendor source, unreplicated
The core measurements are specific and internally consistent in direction: heap pages, lossy pages, recheck row counts, index sizes, correlation and the CLUSTER recovery run are all reported with the setup that produced them, and the report discloses the harness's favorable conditions. Evidence quality is capped, not raised, by three things: the benchmark is authored by the vendor whose product it illustrates, no independent party reproduced it, and the source reports two conflicting latencies for the same 5% run.
No deployment or usage evidence supplied
The only observable event in the cluster is a vendor-run synthetic benchmark. The supplied material contains no deployments, user counts, downloads, production incident reports or usage disclosures for DeepSQL, and no evidence about how widely BRIN-on-churning-tables occurs in practice, so adoption cannot be scored without inventing facts.
Framing outruns the numbers modestly; the source hedges much of it back
The 'update cliff' and '28-fold' framings overstate slightly: the 28-fold multiple is taken against the 1% churn run rather than the fresh table (about 33-fold there), the latency series is unreliable because the same run is reported at 558.7 ms and 691.5 ms and the 20% run lands within a millisecond of that plan capture, and the harness ran with fsync off, autovacuum off and sequential scans disabled. Against that, the report explicitly says the result establishes a failure mode rather than a database-wide 5% constant, and the underlying physical-work measurements are large and hard to explain away, so the gap is small and positive rather than severe.
Vendor-authored benchmark that demonstrates the need for the vendor's own agent
The benchmark is written by DeepSQL's founder and the report states the post doubles as a demonstration of the judgment DeepSQL is trying to encode - an index that looks healthy in the catalog while doing far more work than its operator realizes is precisely the problem the product claims to detect. Credentialing (Oracle R&D, Zonemaps co-ownership, Y Combinator-backed Stayflexi) reinforces the promotional frame. Mitigating factors: the harness conditions and scope limits are disclosed, and the product is described as open source and self-hosted, so the incentive is visible rather than concealed.
Mechanism well supported; magnitudes and generality uncertain
Confidence is moderate. The mechanism - tuple relocation widening block-range summaries so BRIN stops pruning while index size and global correlation stay flat - is coherently explained, consistent with documented BRIN behavior, and corroborated by the CLUSTER recovery restoring 1,536 lossy pages. What limits confidence is that all of it comes from one publisher relaying one vendor benchmark, with no independent replication, an unresolved 24% timing discrepancy inside the same run, and an artificial harness that makes the absolute numbers unusable as production expectations.