Skip to content

Chapter 5 of 7

Index Maintenance and Lifecycle

Indexes accumulate bloat over time as MVCC creates dead tuples, page splits fragment the structure, and updates produce sparse pages. Bloated indexes waste space and slow scans, so PostgreSQL ships contrib tools for diagnostics: pgstattuple and pgstatindex report density and free space ratios, and queries against pg_stats and pg_class can estimate expected versus actual sizes. When bloat becomes excessive, REINDEX INDEX CONCURRENTLY idx_name rebuilds the index without taking an ACCESS EXCLUSIVE lock, which is critical on production systems. Plain REINDEX is faster but blocks all access to the table during the rebuild.

Several storage parameters shape how an index ages. fillfactor leaves a percentage of each page free for future in-place updates, reducing page splits at the cost of a slightly larger initial index; B-trees default to 90, and you can specify WITH (fillfactor = 70) at creation time. Since PostgreSQL 13, B-trees default to deduplicate_items = on, which stores only one copy of adjacent equal key values to save space on indexes with many duplicates such as those on status columns. Large builds can also use parallelism: setting max_parallel_maintenance_workers before CREATE INDEX launches parallel workers (PostgreSQL 11+) to speed up B-tree construction on big tables.

Creating and dropping indexes on busy tables deserves care. CREATE INDEX CONCURRENTLY builds the index without locking writes, at roughly 2-3x the time of a regular build; if it fails, it leaves an INVALID index that must be cleaned up manually. You can check validity through pg_index: indisready means the index is ready for updates while indisvalid means it is visible to query planning, and a failed CONCURRENTLY build typically has indisready = true but indisvalid = false. DROP INDEX CONCURRENTLY performs a similar lock-free removal. Tablespaces add another axis of operational flexibility: CREATE INDEX ... TABLESPACE fast_ssd places an index on fast storage, and ALTER INDEX idx SET TABLESPACE fast_ssd moves an existing one.

All chapters
  1. 1Index Fundamentals
  2. 2The B-tree Family
  3. 3Specialized Access Methods
  4. 4Extensions for Special Workloads
  5. 5Index Maintenance and Lifecycle
  6. 6The Planner, Statistics, and EXPLAIN
  7. 7Indexes Beyond SELECT Queries

Drill it

Reading is not remembering. These come from the Postgresql Indexing Strategies deck:

Q

What is an index in PostgreSQL?

A secondary data structure that lets the planner find rows matching a predicate without scanning the whole table, at the cost of extra storage and write overhea...

Q

What is a B-tree index in PostgreSQL?

The default index type, a balanced tree that keeps keys sorted and supports equality and range predicates, plus IS NULL, IS NOT NULL, and ORDER BY traversal in...

Q

Which index access method is the default in PostgreSQL?

btree.

Q

What index types does PostgreSQL ship with for general use?

B-tree, Hash, GIN, GiST, SP-GiST, BRIN, and the extension-provided Bloom (and others like zombodb, rum, pg_trgm).