Database Administration — Fri Apr 17

← Home | ← database-admin

PostgreSQL - DBA Toolkit - Index Bloat and Health

Fri Apr 17 — Find bloated, unused, and duplicate indexes in PostgreSQL — the silent performance killers that accumulate over time.
#postgresql #dba #monitoring #indexes #bloat #performance #tool-kit

Indexes Get Sick Too

In PostgreSQL, indexes are not automatically compacted.

Every UPDATE and DELETE leaves dead versions of index entries behind. Over time, an index that started lean becomes full of pages pointing to rows that no longer exist. VACUUM removes the dead heap tuples, but index pages only get cleaned up during autovacuum index scans or a full REINDEX.

The result: indexes that are twice the size they need to be, scans that read far more pages than necessary, and write overhead for indexes that nothing is using.

This script identifies bloated indexes, unused indexes, and duplicate coverage so you can rebuild what needs rebuilding and drop what is just costing you.

IndexBloatandHealth.sql
    Loading…
  

Reading the Results

Index Usage Stats (pg_stat_user_indexes)

ColumnWhat It Tells You
schemaname / tablenameWhere the index lives
indexnameIndex name
idx_scanNumber of index scans using this index since last stats reset
idx_tup_readTuples read through this index
idx_tup_fetchHeap fetches triggered by this index
index_sizeDisk space used

Bloat Estimate

ColumnWhat It Tells You
real_sizeActual disk size of the index
extra_sizeEstimated bloat — space that could be reclaimed
bloat_ratioPercentage of the index that is dead space
is_natrue if the estimate is not available for this index type

What to Watch For

SignalWhat It Means
idx_scan = 0 on a large indexIndex has never been used since stats reset — candidate for removal
bloat_ratio > 30%Index has significant dead space — consider REINDEX CONCURRENTLY
Multiple indexes covering the same leading columnsRedundant indexes — every write pays to maintain all of them
index_size > table_sizeOver-indexed table — evaluate which indexes are earning their keep
Bloat on primary key or unique indexesHigh churn table with frequent deletes — schedule regular reindex
Many small indexes with low idx_tup_fetchPartial indexes or highly selective indexes that rarely fire — review selectivity

Rebuilding Bloated Indexes

RebuildingIndexes.sql
    Loading…
  

REINDEX CONCURRENTLY builds a replacement index in the background while the old one stays live. It takes longer but does not block reads or writes.

Note: REINDEX CONCURRENTLY cannot run inside a transaction block.

Gareth Winterman