SQL: Bulk reloading of clustered columnstore indexes
I recently posted about rebuilding clustered columnstore indexes when they needed maintenance . One of the questions that a reader asked was:
Which is best in performance and CCI packing for fast query:
- Truncate table, drop CCI, insert data, create CCI.
- Truncate table, insert data and therefore keep CCI.
And of course, that’s a great question. Here are the issues:
If I had to just pick one of those, for best query performance and best CCI packing, the first option is usually better:
Truncate table, drop CCI, insert data, create CCI
That approach lets SQL Server build the clustered columnstore index in bulk, producing well-compressed rowgroups with better segment quality.
When you load into a heap or rowstore first and then create the CCI, SQL Server can:
- sort and organize data more efficiently during index creation
- create mostly compressed rowgroups
- avoid lots of rows sitting in the delta store
- usually achieve better rowgroup density
- often produce better segment elimination, depending on load order
- reduce fragmentation in the columnstore structure
For a full reload of a table, this is commonly the cleanest and fastest end state for analytics queries.
Truncate table, insert data and therefore keep CCI
This can still work well, especially for large bulk inserts, but the result depends heavily on batch size and loading method.
If inserts are not large enough, SQL Server may load rows into the delta store first. Later, the tuple mover compresses them into columnstore rowgroups, but you can end up with:
- open or closed delta rowgroups
- smaller compressed rowgroups
- less optimal compression
- more deleted rows over time if the pattern changes
- potentially poorer query performance
For CCI, ideally you want rowgroups close to the maximum size of about 1,048,576 rows per rowgroup. Smaller rowgroups generally mean poorer compression and less efficient scanning.
Practical recommendation
For a complete refresh / reload of a CCI table:
TRUNCATE TABLE dbo.YourTable;
DROP INDEX CCI_YourTable ON dbo.YourTable;
-- bulk insert / insert data
CREATE CLUSTERED COLUMNSTORE INDEX CCI_YourTable
ON dbo.YourTable;
This is usually best when you reload the whole table, when you can afford the CCI rebuild time, when the table is mainly used for reporting/analytics, and when you want best compressed rowgroup quality.
But there is one important exception: if the table is very large and dropping/recreating the CCI takes too long. In that case, the second option may be acceptable if you load data in large batches.
For direct-to-compressed-columnstore loading, aim for batches of at least 102,400 rows, and preferably much larger. Small inserts are the main problem.
Rule of thumb
| Scenario | Better choice |
|---|---|
| Full table reload and query performance matters most | Drop/recreate CCI |
| Incremental daily/hourly loads | Keep CCI and bulk load large batches |
| Small frequent inserts | Avoid direct CCI loading if possible; use staging |
| Need best compression and rowgroup packing | Create CCI after loading |
| Need shortest load process and acceptable query quality | Keep CCI |
2026-08-06