Does rebuild index update statistics?

I recently did a talk to a group of SQL users.  Quite a few facts ended up surprising the audience.   I thought I’d share a few and wanted to start with index rebuild.

If someone asks you the question “Does rebuild index update statistics?”,  you probably will say “of course”.  You may be surprised to know that index rebuild doesn’t update all statistics. 

when you use alter index rebuild, only statistics associated with that index will be updated.   In order to illustrate this better, let’s draw a table

  Index Stats non-index stats
ALTER INDEX REORG NO NO
ALTER INDEX <index_name>  REBUILD yes but only for stats associated with  that index NO
ALTER INDEX ALL  REBUILD yes, stats for all indexes will be updated NO
DBREINDEX (old syntax) YES YES

Note that non-index stats means the statistics associated with a column/columns that are automatically created or manually created.

As you can see from above, don’t assume all of your statistics get updated just because you have a maintenance plan to rebuild index.   Sometimes, non-index statistics are very critical as well.  Manual updating statistics may be necessary because our current trigger threshold is high for large tables (20% in most cases as in KB “Statistical maintenance functionality (autostats) in SQL Server” ) though trace flag 2371 can help (in blog).

 

Demo

Here is a demo that alter index doesn’t update all stats.

first use the following script to setup

if object_id ('t') is not null
    drop table t
go
create table t(c1 int, c2 as c1 & 1)
go

create index t1_indx1 on t(c1 )
go
set nocount on
declare @i int
set @i = 0
while @i < 1000
begin
insert into t (c1) values (@i)
set @i = @i + 1
end
go

update statistics t with fullscan
go

go
--this will create a stats on c2
select count(*) from t where c2 =1

go

Because  I ran update statistics, the follow query will show that the t1_indx1 and _WA_Sys_00000002_162F4418 have the same value for laste_updated

SELECT
    obj.name, stat.name, stat.stats_id, last_updated
FROM sys.objects AS obj
JOIN sys.stats stat ON stat.object_id = obj.object_id
CROSS APPLY sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp
where obj.name = 't'

image

 

Now, I ran alter index all rebuild.

-- alter all indexes
alter index all on t rebuild
--re-organize won't update even stats of the index
--alter index all on t reorganize

 

Then I ran the following query.  Note that  the last_updated for t1_indx1 has newer time stamp than _WA_Sys_00000002_162F4418 because _WA_Sys_00000002_162F4418 never got updated by alter index command.

--run theh following and note that the stats created by auto stats didn't get updated by rebuild
--only the stats from the index got updated

SELECT
    obj.name, stat.name, stat.stats_id, last_updated
FROM sys.objects AS obj
JOIN sys.stats stat ON stat.object_id = obj.object_id
CROSS APPLY sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp
where obj.name = 't'

image

 

Past blog related to statistics: Case of using filtered statistics

 

Jack Li | Senior Escalation Engineer | Microsoft SQL Server Support