{"post":{"slug":"bloat-monitoring-2026","title":"Bloat Monitoring: Measuring Space You Cannot See","excerpt":"A table twice the size of its live data reads twice as many pages for every scan. Bloat is invisible in ordinary metrics and degrades performance continuously until someone measures it.","category":"code","date":"January 7, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">Q</span>ueries on a particular table have been getting slower for weeks. The plan is unchanged, the row count has grown modestly, and nothing in the application changed.\n\nThe table occupies three times the space its live rows require. Every sequential scan reads three times as many pages, the buffer cache holds a third as much useful data per page, and other queries suffer for the memory it wastes.\n\nNone of that appears in row counts, query plans, or application metrics.\n\n## What changed in 2026\n\n- **Managed platforms surfaced it.** More hosted database services began reporting bloat estimates directly.\n- **Ratio-based alerting became standard.** Alerting on the proportion rather than the absolute size became the norm.\n- **Index bloat got equal attention.** Recognition that indexes bloat worse than tables and are checked less often.\n- **Estimation methods stabilised.** Widely-used estimation queries became well-known enough to be treated as standard tooling.\n\n## What bloat costs\n\nDisk is the least of it.\n\n**Cache pressure** is the real cost. A database's speed comes from serving reads out of memory. A table occupying three times the necessary space fills the cache with pages that are mostly dead rows, evicting data other queries needed. The visible symptom is frequently *other* queries slowing down, which makes diagnosis harder.\n\n**Scan cost** rises directly. A sequential scan reads every page, including the ones that are mostly dead.\n\n**Maintenance cost** rises. Vacuum, backups, and replication all process more data.\n\n**Index effectiveness** falls, since a bloated index means more pages traversed per lookup — see [index bloat](/blog/index-bloat-explained-2026).\n\n| Symptom | Bloat as cause |\n| --- | --- |\n| Gradual slowdown, no plan change | Likely |\n| Other queries slower after one table grew | Cache pressure |\n| Backups taking longer | Contributing |\n| Disk growth exceeding row growth | Direct signal |\n| Sequential scans slower than expected | Direct signal |\n\n## Measuring it\n\nThe metric is a ratio: actual size divided by the size the live rows would require.\n\nAround 1.2 is normal and healthy — some slack is expected and useful, since it gives new rows somewhere to go. Meaningfully above 2 warrants attention. Above 4 is a problem worth acting on.\n\nEstimation is approximate. Computing exact bloat requires reading the whole table, which is expensive, so the standard approach estimates from average row width and page counts. It can be off, particularly on tables with highly variable row sizes, and it is reliably good enough to distinguish a healthy table from a badly bloated one.\n\nTrack the ratio over time rather than sampling once. A stable ratio is fine at almost any level; a rising one means cleanup is losing the race and will keep losing it.\n\nAlso track dead row counts and time since last vacuum per table, which tell you *why* — see [autovacuum tuning](/blog/autovacuum-tuning-2026).\n\n## Acting on it\n\n**First, find out why.** Bloat is a symptom. The usual causes are cleanup falling behind on a high-churn table, or a long-running transaction preventing reclamation entirely. Rebuilding without addressing the cause means doing it again in a month.\n\n**Check the oldest transaction age.** If a transaction has been open for hours, nothing can be reclaimed and no rebuild will hold — see [MVCC explained](/blog/mvcc-explained-2026).\n\n**Tune cleanup for that table specifically.** High-churn tables need per-table settings; global defaults systematically underserve them.\n\n**Rebuild only what needs it.** A rebuild reclaims the space and costs I/O and, depending on method, locking. Rebuilding on a schedule regardless of measurement wastes I/O on tables that were fine.\n\nFor indexes, concurrent rebuilds avoid the write-blocking lock — see [index bloat](/blog/index-bloat-explained-2026).\n\n## Common mistakes\n\n- **Not measuring at all.** The default state, and bloat is invisible without it.\n- **Alerting on absolute size.** Growth is normal; ratio is the signal.\n- **Rebuilding without fixing the cause.** It returns.\n- **Ignoring indexes.** They bloat worse and are checked less.\n- **Treating estimates as exact.** They are approximations.\n- **Scheduled rebuilds.** I/O spent on healthy objects.\n- **Missing the long-transaction cause.** Tuning cannot fix it.\n\n## FAQ\n\n**What ratio should trigger action?**\nAround 2 is a reasonable investigation threshold, 4 an action threshold. More important is the trend — a steadily rising ratio needs attention regardless of the current value.\n\n**How accurate are the estimates?**\nGood enough to distinguish healthy from problematic, and not precise. Do not treat a change from 2.1 to 2.3 as meaningful.\n\n**Does bloat ever resolve itself?**\nThe space is reused for new rows once reclaimed, so a table with steady churn reaches an equilibrium. It does not shrink back without a rebuild — reclaimed space stays allocated to the table.\n\n**Should I monitor every table?**\nMonitor everything, alert on the ones that matter — high-churn tables and anything large. Small stable tables will not surprise you.\n\n## Where to go next\n\nFor keeping cleanup ahead of churn, read [autovacuum tuning](/blog/autovacuum-tuning-2026). For the index-specific case, [index bloat](/blog/index-bloat-explained-2026), and for the mechanism producing dead rows, [MVCC explained](/blog/mvcc-explained-2026).","hue":320,"metaTitle":"Bloat Monitoring: Measuring Space You Cannot See","metaDescription":"How to measure table and index bloat, why the ratio matters more than absolute size, and how bloat degrades performance through cache pressure.","keywords":["bloat monitoring","table bloat measurement","dead tuples tracking","index bloat detection","database space monitoring","vacuum effectiveness","performance degradation","database operations 2026"],"tldr":["**Bloat costs cache, not just disk** — a bloated table evicts useful data from memory.","**Measure the ratio, not the absolute size** — a table growing is normal; a table twice its live size is not.","**Estimates are approximate** — good enough to act on, not precise accounting.","**Indexes usually bloat worse than tables** — and are more often overlooked.","**Skip:** rebuilding on a schedule. Measure, then rebuild what actually needs it."],"readTime":"4 min read","wordCount":832},"related":[{"slug":"autovacuum-tuning-2026","title":"Autovacuum Tuning: Keeping Cleanup Ahead of Churn","excerpt":"The background process reclaiming dead rows is fine until it is not. When it falls behind on a hot table, bloat grows, queries slow, and nothing in your application changed.","category":"code","date":"January 6, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":310},{"slug":"index-bloat-explained-2026","title":"Index Bloat: Why Your Indexes Get Slower Over Time","excerpt":"The index was fast when you built it. A year of updates later it is three times the size, half empty, and the queries using it have quietly degraded.","category":"code","date":"August 18, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":316},{"slug":"mvcc-explained-2026","title":"MVCC Explained: How Readers Stop Blocking Writers","excerpt":"Your database serves a consistent snapshot to every transaction without locking anything. The trick is keeping several versions of every row, and it has a cost.","category":"code","date":"August 14, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":301}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"best-databases-for-ai-applications-2026","title":"Best databases for AI applications in 2026: vector + traditional ranked","excerpt":"Honest 2026 comparison of databases for AI apps — Postgres + pgvector vs Pinecone vs Qdrant vs Weaviate. When you need a dedicated vector DB and when you don't.","category":"code","date":"January 7, 2026","author":"ByteLedger Team","readTime":"2 min read","hue":320},"older":{"slug":"disaggregated-serving-2026","title":"Disaggregated Serving: Separating Prefill From Decode","excerpt":"Processing a prompt and generating tokens have opposite hardware profiles. Running them on the same machine means one of them is always using the wrong resource.","category":"ai","date":"January 7, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":219}}