Build1 distinct publisher3 min readPublished
A nationwide logistics platform's tracking events table crossed a billion rows and new indexes stopped helping. The write-up that followed spends most of its warnings on constraints and the planner, not on latency.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Follow any of these and your For You feed starts watching them — no settings page required.
build
Your "Index Only Scan" Did 2,847 Heap Fetches: Covering Indexes Are a Vacuum Problem1 distinct publisher
build
A NetworkPolicy in another repo broke invoicing while every dashboard reported success1 distinct publisher
build
The optional EntityManager is the bug: moving the transaction boundary into AsyncLocalStorage1 distinct publisher
build
Three attackers hide behind one connect button, and encryption only stops one of them1 distinct publisher
Pruning happens in the planner, before a row is read. The database compares the predicate against each child table's declared range bounds and opens only the children that could hold matching rows, so a query filtered from 2024-03-01 opens March and skips the rest [8]. The author is blunt that this skipping is the entire point, and that everything else is a cost paid to get it [8].
The predicate carries the weight here; the storage layout is just where that weight lands. Omit the partition key from the WHERE clause and there is nothing to prune against, every child gets opened, and one large scan becomes forty smaller ones plus coordination overhead, which the post calls strictly worse than where you started [9]. With monthly ranges, forty children is forty months, a bit over three years of scan events fanned out to answer one query [1].
The change that outlives the migration is in the constraint. The declaration is `PARTITION BY RANGE (created_at)` with one child per month [10], and the primary key then has to carry the key column: `PRIMARY KEY (id, created_at)` [11]. You cannot keep a global unique constraint on `id` alone, because enforcing it would mean checking every partition [12]. That is the same property in both directions. The reason a dated query can ignore 39 children is the reason a uniqueness check cannot. Foreign keys pointing at the partitioned table get awkward, and an ORM that assumes a single-column primary key becomes work [13].
Their billion describes their table's shape, tied to their own access pattern rather than any general rule. Tens of thousands of orders a day, a dozen or more events per parcel, append-only [2]. At the floor of "tens of thousands", 20,000 orders times 12 events is 240,000 rows a day, or roughly 7.2 million in a month [3], and a billion rows divided by a dozen events is around 83 million parcels of history [2]. That shape is what makes the monthly split work, along with an access pattern where dashboards look at today, merchant tracking at the last few weeks, and analytics at a month [14]. The post is explicit that the precondition is access pattern, not size [6].
For the number to transfer, your table needs every hot query bound on the partition column, index maintenance and retention already unschedulable rather than merely slow, and a DELETE of a hundred million rows that you currently cannot run without flattening write throughput for hours [5]. If your queries filter on several dimensions with no dominant one, you get the complexity and none of the pruning [9], and the post's own advice is to index properly instead [4].
Then there is the part with no recipe. Every tutorial shows the CREATE TABLE form; almost none show how to move a live billion-row table into that shape without downtime you cannot afford [15]. The version I read ends mid-word at exactly that sentence, which is a fittingly literal demonstration of the gap [15]. The honest way to file this work is as a schema change with an application-side blast radius, sized by whoever owns the ORM mapping, with the faster query arriving as the closing line of the justification, well after the constraints have had their say.
Ranked by verification strength, evidence, and original report placement.
A dev.to write-up describes partitioning the core tracking events table of a nationwide logistics platform after it crossed a billion rows, framed as what nobody warned the team about beforehand.
The platform processes tens of thousands of orders a day; the tracking events table holds one row per scan, per parcel, per status change; every parcel generates a dozen or more events; the table only ever grew and had crossed a billion rows.
The author describes the trigger for the work: adding an index stopped helping, and in the bad case the index took six hours to build, locked the table while it did, and the query was still slow at the end.
The author states partitioning is not a performance trick to reach for when a query feels sluggish, that it carries real operational cost, and that most tables people want to partition should just be indexed properly.
The listed signals that a table is actually at the partitioning boundary: indexes no longer fit comfortably in memory so index reads hit disk; REINDEX, VACUUM and ANALYZE take so long they cannot be scheduled; deleting old data is impossible in practice because a DELETE of a hundred million rows destroys write throughput for hours; and queries almost always filter on a single obvious dimension, usually time.
The author says the access-pattern signal matters more than the rest, and that the actual precondition is access pattern rather than table size.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 31, 2026
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.
Mechanics verifiable, war story not
The claim carrying the story — that Postgres forces the partition key into the primary key, killing a global unique constraint on id alone — is checkable by anyone with a psql prompt, and the reasoning given for it is correct. Everything situational sits on the other side of the line: an unnamed platform, a table size quoted to one significant figure, a six-hour index build with no schema or hardware behind it, and not one latency figure before or after the cutover. The piece also stops mid-sentence in its last step, so even the author's own outcome is missing.
One self-reported production migration
The evidence of use is a single engineer describing a single unnamed platform's table. Postgres declarative partitioning is doubtless widespread, but nothing in this reporting establishes that, and we will not borrow the assumption. What we do have is specific about mechanism — monthly ranges on created_at, application-level dual-write, throttled backfill — and silent on when it shipped or how it has held up since.
Talks itself down more than it needs to
A piece titled around a billion rows could have been sold on throughput; instead its first substantive move is to tell most readers to go index their table properly and leave partitioning alone. The costs are named before the benefits, the failure mode gets its own paragraph, and the one performance number is a defeat. If anything the framing undersells what is here: the composite-key constraint and the dual-write-plus-backfill sequence are the durable content, and they are buried under a headline about table size.
Reputation, not revenue
No product is being sold and no vendor is named anywhere in the text; the DDL is plain Postgres. What remains is the ordinary pull of practitioner publishing on dev.to — the war story is more quotable when the table is bigger and the index build longer, and the unnamed employer means nobody can check either figure. That shapes the numbers a little. It does not shape the constraint at the centre of the piece, which no incentive could bend.
Trust the constraint, hold the anecdote loosely
Split the story and confidence splits with it. The Postgres semantics, the pruning model and the ORM fallout are the sort of thing a reader can confirm in an afternoon, and we would act on them. The platform narrative — billion rows, tens of thousands of daily orders, days of backfill — comes from one anonymous source with no corroboration and no version numbers, and our own record of where the text ends turned out to be wrong. Single publisher, no second account, so nothing here has been tested against anyone else.