deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Read replicas can't save 'Postgres for everything' when dashboards go concurrent

A dev.to post argues that offloading analytics to a Postgres read replica only isolates compute, not the row-oriented storage that makes concurrent dashboard queries collapse.

Read replicas can't save 'Postgres for everything' when dashboards go concurrent

What happened

A first-person account on dev.to traces the moment the widely repeated advice to "just use Postgres" stopped working for one team: once their dashboards became concurrent, the read replica they had added to shield the primary started buckling under the load itself.

The author's conclusion is that the failure was structural rather than operational, and that replication alone cannot fix it.

Replicas copy the bottleneck, not the format

According to the post, the reflex move is to spin up a read replica, push heavy analytical reads onto it, and consider the problem solved. The post cites a May 2026 guide from ClickHouse's engineering team making the opposite case: replicas help with high availability and horizontal read scaling, but they inherit the row-oriented limits of the primary. They compress data poorly for analytics and still depend on B-tree indexes that consume large amounts of memory.

In the author's framing, the replica moves the work elsewhere but leaves the underlying storage format untouched.

Row storage working against narrow queries

Postgres keeps data in 8 KB pages, with a fixed 23-byte tuple header on every row, the post explains. A dashboard query that needs only two columns still reads entire rows, so narrow aggregations pay full-row I/O costs. Multiply that by concurrent users refreshing dashboards, and the overhead compounds quickly.

Where it actually breaks

The post points to a September 2026 incident retrospective from a data engineering team in which a replica was hit by hundreds of near-identical aggregations firing simultaneously. CPU and memory pressure spiked, and WAL replay competed with fast queries for the same resources, dragging quick queries into noticeable slowness.

The post also cites a July 2026 MotherDuck analysis describing the latency curve behind such incidents: a dashboard aggregation that cost 50 ms early in a product's life stretched to five seconds at tens of millions of rows, and eventually timed out once concurrent load piled on. That sits far outside the sub-100 ms budget the post describes as the threshold at which users perceive analytics as instant.

There is a second-order cost as well. The post notes warnings from Brandur Leach and Gunnar Morling that mixing queue-like workloads with ordinary OLTP traffic in Postgres produces MVCC bloat, index fragmentation and WAL pile-up. The system is not merely slow; it accumulates damage.

The over-provisioning tax

Teams on this path tend to compensate with hardware, the author writes: an AWS r8gd.4xlarge instance sized for dashboard peaks, mostly idle overnight but still billing around the clock. The argument is that resizing a row store does not fix a format mismatch; it converts the mismatch into a recurring invoice.

The landing spot

The account is not an argument against Postgres. The author still keeps transactional data there and defends that choice. The mistake, in this telling, is asking one engine to act as both the ledger and the analytics warehouse when those are differently shaped problems.

The proposed fix is a column-oriented serving layer, with ClickHouse named as the example, that compresses data effectively and reads only the columns a query actually touches, while Postgres remains the system of record.

Why it matters

The "just use Postgres" school of thought has real momentum because it genuinely collapses infrastructure for early-stage products. This account gives it a concrete failure boundary: concurrent dashboard aggregations over tens of millions of rows, where read replicas and bigger instances only delay the reckoning. Teams building customer-facing analytics get a specific signal to watch for, such as replica CPU and memory spikes alongside slowing WAL replay, and a clearer sense of when splitting OLTP from an analytical serving layer stops being optional and becomes necessary.

  • #postgres
  • #databases
  • #analytics
  • #clickhouse
  • #performance

Related posts