skip to content

An index in a busy production database has been measured as heavily bloated. What are the ways to reclaim that space, and what does each cost in terms of locking, extra disk, duration and risk while the system keeps serving traffic?

level: seniorimportance: must knowfreq 50%

answer

  1. Drop > reorganize > concurrent rebuild > offline rebuild
  2. Concurrent rebuild needs room for two copies
  3. Failed concurrent build can leave an invalid index
  4. It waits on long-running transactions
  5. Partition-level maintenance bounds the work

basics

~20 s

Options: an offline rebuild (fast, needs an exclusive lock), an online/concurrent rebuild (builds a shadow copy while writes continue — slower, needs space for both copies, can fail and leave an unusable index), an in-place reorganize (no full copy, less thorough), or dropping the index if unused.

solid answer

~60 s

Four realistic paths, from cheapest to most disruptive: - **Drop it.** If usage counters show nothing reads it and it enforces no constraint, this is the best outcome: no bloat, no write cost, no maintenance. - **In-place reorganize/compact.** Works through the existing structure, compacting pages and improving leaf ordering without building a second copy. Little extra space, interruptible, but less thorough than a rebuild and typically slower per page. - **Online/concurrent rebuild.** Builds a fresh copy while reads and writes continue, tracking concurrent changes, then swaps it in under a brief exclusive lock. Needs room for both copies plus sort space, takes longer, adds write amplification, and can fail partway — leaving an unusable leftover index that must be cleaned up. It also waits on long-running transactions. - **Offline rebuild.** Fastest and densest, but holds a lock that blocks writes (and often reads) for the duration. Always ask *why* it bloated first. If cleanup is blocked by a long-lived snapshot, or the table is a queue, the rebuild only resets the clock.

go deeper

for a junior

Name the basic options — rebuild the index, or drop it if unused — and know that a plain rebuild locks the table.

for a middle

Contrast offline versus online rebuild on lock scope, duration and extra disk, and know that a reorganize is the lighter in-place option.

for a senior

Sequence a real operation: verify usage, find and clear whatever blocks cleanup, choose the method against available space and write volume, plan for a failed concurrent build, and measure before and after.

for a principal

Argue the structural alternatives — partition-level maintenance, rebuild-on-standby-and-fail-over, dropping redundant indexes — so that routine maintenance never needs a heroic window.

## First: is a rebuild the right action at all? A rebuild is a large, disruptive write operation. Before scheduling one: - **Is the index used?** Per-index usage counters over a representative window (including month-end and batch jobs) may show zero scans. An unused index that enforces no uniqueness constraint should be dropped, not maintained. - **Why did it bloat?** If a long-running transaction, an idle-in-transaction session, or a stale replication slot is holding an old snapshot and blocking dead-entry reclamation, the fresh index will bloat again within days. Fix the blocker first. - **Is the design the problem?** A table where you bulk-delete a date range every month is asking for partitioning: dropping a partition removes its index segment instantly, with no bloat and no rebuild. ## Option 1 — drop the index Instant, frees all its space, and removes its ongoing write cost. The risk is dropping something that turns out to matter: a rarely-run but critical report, a constraint-backing index, or an index the planner uses only for a specific parameter range. Verify usage over a full business cycle, and know how long recreating it would take if you are wrong. ## Option 2 — in-place reorganize / compact The engine walks the existing index, compacting entries into fewer pages and improving the correspondence between key order and physical order, without materializing a second full copy. Characteristics: - **Space:** minimal extra — this is its main advantage when disk is tight. - **Locking:** typically light, often allowing concurrent reads and writes. - **Interruptibility:** usually resumable or safely abortable, keeping the work already done. - **Result quality:** lower than a full rebuild. It improves density and ordering but rarely reaches the compactness of a freshly built structure. - **Duration:** often longer per page than a rebuild, because it works incrementally against live traffic. Good choice for moderate fragmentation, or when there is not enough free space to hold two copies. ## Option 3 — online / concurrent rebuild The engine builds a brand-new index from current data while the table remains readable and writable, recording concurrent modifications and applying them to the new structure, then swaps the new index for the old one under a brief exclusive lock. Costs and hazards: - **Extra disk:** you need room for the old index, the new index, and any sort workspace, simultaneously. On a large index this is the constraint that most often blocks the plan. - **Duration:** substantially longer than an offline build — commonly several times longer — because it does more passes and yields to concurrent work. - **Write amplification:** the whole new structure is written and logged, which propagates to replicas and to backup volume. On a saturated I/O system this alone can degrade the workload. - **Waiting on transactions:** the build must reach a point where it knows all concurrent changes are captured, which typically means waiting for transactions older than a certain point to finish. One long-running reporting query can stall it for hours. - **Failure mode:** if it is cancelled or errors, some engines leave behind an invalid or partially built index that still consumes space and still costs on writes until it is explicitly dropped. Always plan the cleanup step. - **Deadlock/lock-wait risk at swap time:** the final exclusive lock is brief but real; under heavy write traffic it can queue behind or block other statements. ## Option 4 — offline rebuild Rebuild in place, holding a lock that blocks writes and often reads for the duration. Fastest wall-clock time, best resulting density, simplest failure semantics. Appropriate only in a maintenance window, on a standby that is then promoted, or on small indexes where the lock is measured in seconds. ## Related, larger hammers - **Table-level rewrite.** Rewriting the whole table (a full-table reorganize or a copy-and-swap of the table) rebuilds every index on it at once. Efficient when several indexes on the same table are bloated, but a far bigger operation and usually needs table-level locking or a full online-migration mechanism. - **Rebuild on a replica, then fail over.** Do the disruptive work on a standby, then promote. Removes production impact at the cost of a failover and careful sequencing. - **Per-partition maintenance.** On a partitioned table, rebuild one partition's index segment at a time. This is the single most effective way to make index maintenance survivable at scale: the unit of work becomes small and bounded, and old partitions can often be dropped instead of maintained. ## Choosing Unused → drop. Space-constrained or moderate damage → in-place reorganize. Heavily bloated, space available, must stay online → concurrent rebuild, scheduled during a low-write period, with the cleanup path for a failed attempt written down in advance. Maintenance window available or index small → offline rebuild. Repeatedly bloated → stop rebuilding and change the design. ## Before and after Record the size, density and the latency of the affected query shape beforehand, and again afterwards. Without that, nobody can tell whether the maintenance window bought anything — and "we rebuild everything monthly" becomes tradition instead of engineering.

  • The concurrent rebuild has been running for six hours and shows no progress. What is the most likely explanation?
    It is almost certainly waiting on transactions older than a point it needs to pass before it can be sure it has captured all concurrent changes. A long-running analytics query, an idle-in-transaction session, or an open transaction on a replica with feedback enabled will hold it there indefinitely. Find and end the offending transaction; also note that the same blocker is what let the index bloat in the first place.
  • How do you rebuild a very large index when there is not enough free disk for a second copy?
    Prefer an in-place reorganize, which compacts without materializing a full duplicate. If the table is partitioned, do it one partition at a time so the peak extra space is bounded by the largest partition. Otherwise, do the rebuild on a standby and fail over, or add capacity temporarily — attempting a concurrent build that runs out of space mid-flight leaves you worse off than when you started.
  • After a successful rebuild, how do you keep the index from bloating straight back to where it was?
    Remove the cause rather than repeating the cure: ensure background reclamation is not starved and is not blocked by long-lived snapshots or stale replication slots; replace bulk row deletes with partition drops; drop indexes nobody queries; and reconsider indexes on columns that are updated constantly, since every such update kills an entry. Then monitor size against live row count so divergence is detected early rather than rediscovered by a latency incident.

Reshelving a library: closing for the day is fastest (offline), tidying shelf by shelf while patrons browse is slow but non-disruptive (reorganize), and building a duplicate library then switching the doors needs twice the floor space (concurrent rebuild).

saying these in an interview costs you the question

  • "An online rebuild is free" — it costs double space, heavy write and log volume, and a long duration
  • "If the concurrent build fails, nothing is left behind" — a leftover invalid index can persist and must be dropped explicitly
  • "Rebuilding fixes the problem permanently" — it resets the clock; the workload or blocked cleanup will rebuild the bloat
  • "Just rebuild everything monthly, it's safer" — untargeted rebuilds burn I/O and windows on healthy indexes
  • "Drop and recreate is the same as an online rebuild" — dropping first leaves queries with no index and can enforce nothing during the gap, including uniqueness

context