Pick one piece of operational data, say an order status. Now count how many systems depend on it: the ops dashboard, notification service, search index, mobile API, nightly analytics job, an AI agent someone wired up last quarter. Each team added another way to read the same data. Because each path performed well on its own, no one saw the load building across them, and no single team owned the resulting cost.
The same thing that makes this load hard to own, also makes it hard to spot. Most performance debugging hunts for an obvious suspect: a single expensive query, a missing index, or a bad join that you can spot in a slow query log. Repeated reads are easier to miss. Each query might be cheap, execute quickly, and look fine on its own, but when that same query pattern runs thousands or millions of times across different services, the costs add up significantly.
A few things make this harder to catch than a single slow query:
- It hides in aggregate metrics. Total QPS creeps up gradually and gradual growth often doesn't trigger the alert that dashboards are designed to catch.
- The read pattern crosses team boundaries. The cost isn't in any one service, so no single team's dashboard shows the whole picture.
- Every fix is a negotiation. If you do catch the repeated reads, you have to coordinate across multiple different teams. That's slow, and it's why the usual response is to scale the database instead, which slaps a bandaid on the symptom without fixing the cause.
Finding this pattern requires looking past the slow query log:
- Group your queries by normalized pattern to find equivalent queries running with different parameters.
- Rank patterns by call count and total execution time rather than by duration. Postgres exposes this through
pg_stat_statements, and MySQL through the Performance Schema statement summaries.
- Trace the highest-volume patterns back to the services generating them.
With redundant reads, the query worth investigating isn't necessarily the slowest one. It's likely the one running more often and from more sources than anyone realized.
If you're dealing with this pattern, the simplest answer is to add a shared read layer, such as a query cache that stays current as the underlying data changes. It can serve cacheable reads before they reach the primary, so the same queries don't keep adding load to production. That reduces repeated work without requiring six different teams to change how they access the data.
Autopsy of a Postgres Outage
A candid, no-filter writeup of an evening where everything went wrong at the same time: a saturated Postgres database, a high-availability setup that didn't fail over the way it was supposed to, and a cloud storage incident underneath it all.
Why Cloud Outages Are Getting Worse in 2026
A sharp look at why this year has seen more infrastructure failures, with reasons that will interest anyone running a database on a hyperscaler: the big providers are pouring capital into GPU-dense AI capacity while the ordinary x86 and ARM fleets that run everyone's actual workloads get less maintenance and slower refresh cycles.
Your Database Bill Is Climbing Faster Than Your Traffic: Compute stopped getting cheaper this year, and the database is the line item feeling it first. This post breaks down what's driving the increase and what you can do about it without re-architecting.
We're getting more social, catch the latest on Bluesky, X, dev.to, and Medium too.
Know a database aficionado who'd appreciate this? Forward it their way.