天天看點

SQLServer中重建聚集索引之後會影響到非聚集索引的索引碎片嗎

原文: SQLServer中重建聚集索引之後會影響到非聚集索引的索引碎片嗎 本文出處: http://www.cnblogs.com/wy123/p/7650215.html

(保留出處并非什麼原創作品權利,本人拙作還遠遠達不到,僅僅是為了連結到原文,因為後續對可能存在的一些錯誤進行修正或補充,無他)

上午(20171011)看到qq群裡發了一個雲栖大會的連結,點進去看了一下sqlserver的專場,剛好是提問環節

有人問了一個問題,原話記不清楚了,

大概的意思(他自己認為)就是說:“SQLServer中重建聚集索引之後會影響非聚集索引的碎片情況,也要順帶重建非聚集索引”

我想大概是他自己認為“重建聚集索引之後會影響到非聚集索引的索引碎片”

提問者跟專家交流這個觀點,一開始提問之後還撤了幾句堆表RID,聚集表key值啥的。

專家一開始說這兩者沒有關系(重建聚集索引之後不會影響到非聚集索引的索引碎片),後面被提問之後可能是有點緊張,改口說沒注意過這個問題。

首先抛出結論:對于聚集索引表,重建聚集索引之後不會影響到非聚集索引的索引碎片,重建聚集索引跟非聚集索引碎片之間的沒有關系,完全不搭嘎的。

這些問題,其實嘗試自己測試一下不就清楚了麼?

聚集索引重建之後,對非聚集索引是否有影響

首先,暫且先不扯聚集表堆表啥的了,直接說聚集表,

非聚集索引在葉級直接存儲的是聚集索引的key值,在重建聚集索引(或者重組)前後,非聚集索引存儲的對應的key值是不變的

重建聚集索引之後,資料的屋裡存儲位置可能會發生變化,這是會影響到聚集索引的實體存儲和碎片情況

但是對于非聚集索引來說,非聚集索引存儲的對應的聚集索引的key值是不變的,

那非聚集索引的碎片跟聚集索引的重建與否有個毛的關系。

正如我手機裡記錄了某個人的電話号碼,我隻要撥通這個電話就能找到他,我管他是去北京上班還是去南京出差了,跟他在人具體哪裡(重建聚集索引,實體位置變化)有毛關系。

這些問題如果不确定的話,測試一下就出來結果了啊,我覺得沒有任何疑問的。

測試,測試表TestFragment中,Id1字段類型為uniqueidentifier,建立聚集索引,

利用uniqueidentifier的随機性,大批量寫入資料之後其碎片變得很大

相反,Id2字段類型INT,以遞增的值寫入資料,大批量寫入資料之後其索引碎片會很小

然後重制Id1上的索引,觀察Id2上的索引碎片會不會因為Id1上的索引重建而發生變化

create table TestFragment
(
    Id1 uniqueidentifier,
    Id2 int,
    OtherCol2 varchar(50)
)
go


create unique clustered index IDX_Id1 on TestFragment(Id1);
go

create unique index IDX_Id2 on TestFragment(Id2);
go

begin tran
    declare @i int = 0
    while @i<1000000
    begin
        insert into TestFragment values(NEWID(),@i+1,NEWID());
        set @i = @i+1
    end
commit
go      

寫入100W資料之後觀察兩個索引上的碎片,

對于聚集索引(Id1上的索引IDX_Id1):

很明顯,聚集索引(因為是uniqueidentifier類型的字段),

其avg_fragmentation_in_percent很高(99.2557236469541),同時avg_page_space_used_in_percent較低(68.9408574252533)

對于非聚集索引(Id1上的索引IDX_Id2):

Id2索引因為是遞增的,其avg_fragmentation_in_percent很低(0.528606965174129),也就是說碎片程度很低

SQLServer中重建聚集索引之後會影響到非聚集索引的索引碎片嗎

這裡姑且不管聚集索引與非聚集索引的碎片程度,這裡重點關注“重建聚集索引之後是否會對非聚集索引碎片情況産生影響”

這裡重建聚集索引之後,重新觀察索引碎片情況,看截圖sys.dm_db_index_physical_stats的查詢結果

可以很清楚地發現,重建聚集索引之後,聚集索引本身的碎片發生了很大的變化,碎片基本完全消除(avg_fragmentation_in_percent0.0116986429574169),

但是非聚集索引的碎片情況并沒有發生任何一點變化。

SQLServer中重建聚集索引之後會影響到非聚集索引的索引碎片嗎

從理論上也不難了解:

聚集索引和非聚集索引是兩個完全獨立的實體存儲結構(當然也可以說是邏輯存儲結構)

其唯一的聯系就是非聚集索引B樹葉子節點會存儲聚集索引的Key值

其存儲的聚集索引的key值不是其實體位置,聚集索引或者說資料本身的位置變化并不會因為key值的變化

是以說重建還是重組聚集索引不會影響到非聚集索引的碎片情況

堆表的碎片消除

對于堆表的索引碎片消除,也是可以通過alter table xxx rebuild重建的,

當然也有一種很挫的做法就不想提了(fix heap fragmentation by creating and dropping a clustered index.)

記住這是一種很挫的做法,可能是SQL Server 2008之前的版本中,alter table xxx rebuild文法被支援之前的無奈之舉,

這裡暫不表述這種做法。

對于堆表,alter table xxx rebuild可以通過重建表來消除碎片,但其功能不限于次,還會重建堆表上的非聚集索引

測試示例

create table TestHeapFragment
(
    Id1 uniqueidentifier,
    Id2 int,
    OtherCol2 varchar(50)
)
go

create unique index IDX_Id1 on TestHeapFragment(Id1);
go

create unique index IDX_Id3 on TestHeapFragment(OtherCol2);
go

begin tran
    declare @i int = 0
    while @i<1000000
    begin
        insert into TestHeapFragment values(NEWID(),@i+1,NEWID());
        set @i = @i+1
    end
commit
go      

通過alter table xxx rebuild對堆表重建,發現非聚集索引也會因為堆表的重建而發生索引重建。

SQLServer中重建聚集索引之後會影響到非聚集索引的索引碎片嗎

If you think you can use ALTER TABLE … REBUILD to fix heap fragmentation, you can, but it causes all the nonclustered indexes to be rebuilt as the heap record locations obviously change.

暫時不清楚alter table xxx rebuild的具體實作過程,但是從各種表現來看,他在重建表的過程中确實也重建了非聚集索引。

但是“重建表的過程中确實也重建了非聚集索引”可以認為是“使得非聚集索引變得更加好,而不是變壞”,

這裡要說明的是alter table xxx rebuild重建堆表不會對對表上的非聚集索引産生副作用

強調一點,

對于非聚集表,alter table xxx rebuild會重建所有的非聚集索引

對于聚集表,alter table xxx rebuild隻會重建聚集索引,但是不會重建非聚集索引

說實話,提問者所說的“重建聚集索引之後會影響到非聚集索引碎片”這個觀點我也是第一次聽說,

如果真的了解索引的話,應該知道這兩者(重建聚集索引與非聚集索引碎片)之間沒有必然的關系,

對于莫名其妙的結論,到底是道聽途說還是真有其事,為什麼不自己動手試一試?

參考:

  

https://www.red-gate.com/simple-talk/sql/database-administration/sql-server-heaps-and-their-fragmentation/

  

https://www.sqlskills.com/blogs/paul/a-sql-server-dba-myth-a-day-2930-fixing-heap-fragmentation/