Index Bloat in Postgres: Why It Matters, How to Identify, How to Resolve
Index bloat in Postgres can cause problems, but it’s easy to miss.
I’ve written about how vacuum problems can prevent PostgreSQL from …
Read Moreon • 8 min read
The bigger your indexes are, the harder your index maintenance falls. Is it better to rebuild big indexes? Or should you reorganize?
If you’re short on time, scroll down: an article with all the content is below the 23 minute video.
Here’s this week’s question:
Dear SQL DBA,
Any advice for rebuilding indexes on very large tables? We’ve got a large table with over 2 billion rows. Index rebuilds consume over 300GB of transaction log space even though we’re backing up the log every 3 minutes.
To solve this problem, should we reorganize instead of rebuild?
Any issues with never rebuilding indexes – just reorganizing them?
We are using SQL Server 2014 Enterprise Edition.
Index rebuilds have a log lot going for them, but they also have some drawbacks.
ALTER INDEX REBUILD
| Pros | Cons |
|---|---|
| Can use parallelism - which can reduce the runtime (Enterprise Edition) | Single threaded only in Standard Edition |
| ONLINE option (Enterprise Edition) Note: this requires an exclusive lock on the table at the end of the operation. | When performed offline, the entire table is unavailable for the duration of the operation |
| Defragments all levels of the index - leaf and intermediate pages | Rollbacks can be long and excruciating when rebuild fails or is cancelled |
| Also updates statistics on the table with a FULLSCAN of all the data | Causes queries to generate new execution plans when they run again |
| Reapplies options such as fillfactor and compression, and gives you the option to change those settings. | |
| Minimal logging is available under some recovery models |
With very large indexes, rebuilds take longer, generate more log, impact performance more while they’re running.
If you’re using high availability features like Availability Groups or database mirroring that stream the log between replicas, generating a lot of log data very quickly can create problems.
Your replica/ mirrors may fall behind. Depending on the latency between replicas, the size of the indexes rebuilt, and other operations in the database, they may be out of your Recovery Point Objective / Recovery Time objective for a long time.
In this situation, it’s particularly attractive to drip changes into the log more slowly. One of the ways to do this is to use REORGANIZE for those large indexes.
Of course, things aren’t perfect when it comes to REORGANIZE. It has some downsides as well.
ALTER INDEX REORGANIZE
| Pros | Cons |
|---|---|
| Tends to “trickle” changes into the log more slowly (a pro only for specific situations) | Single threaded only - regardless of edition – so it’s slower. |
| Fully online in every edition | |
| If cancelled or killed, it just stops where it is – no giant rollback. | Defragments only the leaf level of the index |
| Does not cause plan recompilation | Does not update statistics - you have to manage that yourself |
| Honors/reapplies existing settings such as fillfactor and compression | Does not allow you to change settings such as fillfactor and compression |
When it comes to giant indexes, the biggest downsides are related to the whole reason you’d use it in the first place: it’s slow!
In cases where REBUILDs on large indexes can’t happen because they put replicas too far behind or cause too heavy of a performance impact, typically these large indexes are manually REORGANIZED in spurts while a DBA team member is around to babysit.
It’s a bit like watching paint dry.
Going through this experience of babysitting large index reorganizes generally causes DBAs to:
It’s worth talking about the “minimal logging” pro for rebuilds. If you don’t need point in time recovery and can lose any changes that occur between full backups and are in the SIMPLE recovery model, you benefit from this all the time.
If you need to limit data loss and are in the FULL recovery model, you may still have to switch to SIMPLE during some outages for large data changes. And during those outages, you might want to fit in some offline index rebuilds if you have the time, because they can be faster.
In the SIMPLE and BULK LOGGED recovery models, ALTER INDEX REBUILD doesn’t have to log every row. There’s a few caveats:
The amount logged under BULK LOGGED and SIMPLE varies depending on whether you’re doing ONLINE or OFFLINE rebuilds. Kalen Delaney has test code and sample numbers in her post, “What Gets Logged for Index Rebuild Operations?”

Rebuilding an index fixes up the whole structure. Picture an index as a triangle, with a root page, intermediate pages, and leaf pages. The rebuild command will defragment all those intermediate pages.
Reorganizing only works on the leaf pages. It doesn’t work on the intermediate pages between the root and the leaf.
Larger indexes have more intermediate levels and pages. These pages can get empty space on them and become out of order over time as well.
Fragmentation in intermediate pages isn’t usually a problem at all – one of the more common confusions of new DBAs looking at fragmentation is that they see that intermediate pages in small indexes are fragmented immediately after a rebuild, no matter what they do. That’s actually normal.
If you never ever rebuild a large index, you could potentially lose some performance due to massive fragmentation in the intermediate level of the indexes– but I think it’d likely be more a difference of microseconds than milliseconds per query.
If it were me, I’d generally consider rebuilding problem “giant” index during outage/maintenance windows every six months or a year. But it’s my inner paranoid, tinfoil hat wearing DBA saying that.
But hey, in some systems microseconds do matter! In that case, breaking up these giant indexes into partitions is probably desirable (more on that soon).
SQL Server allows you to run ALTER INDEX ALL REBUILD, like this:
ALTER INDEX ALL ON Sales.Orders REBUILD;
GO
The syntax is convenient, but as Books Online explains, “When ALL is specified, all indexes on the table are dropped and rebuilt in a single transaction.”
The bigger the transaction, the worse the rollback can be. You definitely want to handle the indexes individually.
This is a little counter-intuitive when you have a short maintenance window, but it can ease some pains.
Adding a “waiting” period between index commands can reduce impact on the instance and Availability Group replicas or Database Mirrors. Many popular index maintenance scripts have an option for this.
I’m not a fan of partitioning for everything – I did a video earlier this year on Why Table Partitioning Doesn’t Speed Up Query Performance.
But table partitioning can be excellent for data management. Everything we’ve talked about so far has had downsides and hasn’t really provided a deep solution for the problem– partitioning isn’t easy, but long term it can really help with these problems.
Two things to know:
By breaking up the table into smaller chunks, partitioning makes it much easier to take advantage of all the strengths of rebuilds without so many downsides. It’s worth investigating if this might be an option (but be careful about query performance).
Copyright (c) 2025, Catalyze SQL, LLC; all rights reserved. Opinions expressed on this site are solely those of Kendra Little of Catalyze SQL, LLC. Content policy: Short excerpts of blog posts (3 sentences) may be republished, but longer excerpts and artwork cannot be shared without explicit permission.