在sql server 中,如果一張表存在聚集索引的時候,大多數情況下,如果進行select * from TableName查詢,預設的返回順序是按照聚集所在列的順序返回的 但是,在一張表存在聚集索引的時候,並不一定所有的情況都是按照聚集索引列的順序排列的, 下麵開始測試 如下查詢完全沒有問題,正 ...
在sql server 中,如果一張表存在聚集索引的時候,大多數情況下,如果進行select * from TableName查詢,預設的返回順序是按照聚集所在列的順序返回的
但是,在一張表存在聚集索引的時候,並不一定所有的情況都是按照聚集索引列的順序排列的,
下麵開始測試
create table TestDefaultOrder ( Id int identity(1,1) primary key,--主鍵上預設會建立聚集索引 Col2 char(5), COL3 char(5) ) --寫入100000條測試數據 insert into TestDefaultOrder values (SUBSTRING(cast(NEWID() as varchar(50)),1,5),SUBSTRING(cast(NEWID() as varchar(50)),1,5)) go 100000
如下查詢完全沒有問題,正如你所預料的,按照聚集索引所在的列(Id)排序的,完全沒有問題,下麵開始切入正題
--創建一張同樣的對照表 create table TestDefaultOrder_Contrast ( Id int identity(1,1) primary key,--主鍵上預設會建立聚集索引 Col2 char(5), COL3 char(5) ) --將TestDefaultOrder表中的數據寫入進去,目前,兩張表的數據和索引結構一模一樣 insert into TestDefaultOrder_Contrast (Col2,Col3) select Col2,Col3 from TestDefaultOrder --僅僅在對照表上創建一個非聚集索引,這是唯一的不同點 Create Index idx2 on TestDefaultOrder_Contrast(Col2,Col3)
接下來的查詢,或許會有一點一點出乎你的意料,
上面說了,兩張表的數據是一模一樣的,聚集索引結構也是一樣的,只是對照表多個一個非聚集索引
發現對照表的結果返回順序,根本是按照聚集索引的排序返回的
那麼原因在哪裡呢?我們要從不同類似索引占用的空間情況進行分析,通過dm_db_index_physical_stats發現,在數據數據完全一致的情況下,
因為TestDefaultOrder_Contrast這個表上的非聚集索引,占用的空間更少(248個page,而TestDefaultOrder的聚集索引是285個page),
正因為此,sqlserver在進行全表掃描的時候,會選擇一個代價更小的索引(進行掃描),
因為TestDefaultOrder表上只有一個聚集索引,按照聚集索引掃描進行查詢,返回的結果的順序是按照聚集索引列排序的
但是TestDefaultOrder_Contrast就不同了,因為在非聚集索引idx2 上,包含了全部的數據(Col2,Col3以及指向聚集索引鍵值的Id),
但idx2這個索引是占用的空間更小,所以對於TestDefaultOrder_Contrast的查詢,是按照idx2這個非聚集索引進行掃描的
因為,在TestDefaultOrder_Contrast這個表上,
直接select * TestDefaultOrder_Contrast進行查詢的話,
跟對錶TestDefaultOrder進行 select * TestDefaultOrder查詢
是用兩種完全不同的方式進行的,出來的結果自然也就不同了
而事實上,sqlserver在對TestDefaultOrder_Contrast進行查詢的時候,通過走idx2這個索引掃描,代價確實要比TestDefaultOrder的聚集索引掃描,代價要小
如果有興趣的話,再次分析為什麼存儲同樣的數據(TestDefaultOrder上的聚集索引和TestDefaultOrder_Contrast的非聚集索引idx2),
TestDefaultOrder表上的聚集索引,要比TestDefaultOrder_Contrast上的idx2(Create Index idx2 on TestDefaultOrder_Contrast(Col2,Col3))占用的空間大呢
這裡的原因在於,一個表上的聚集索引(於非聚集索引相比),除了要存儲數據,要維護的信息更多的元數據信息,占用的空間自然就較多一點
而sqlserver在進行查詢的時候,總是會選擇一個代價相對較低的方式。
總結:千萬不要以為,只要表上建立了聚集索引,在查詢的時候,返回結果的預設的排序方式,是按照聚集索引來的
後記:為什麼要研究這個問題?
因為之前遇到過,某些查詢沒有顯式指定排序列,但是藉助表上聚集索引,返回結果的時候,會得一個想要的順序。
這種情況其實會潛在一種問題,如果發生類似上面這種情況,想要對查詢結果按照聚集索引的順序排序,而又不顯式制定排序列,查詢結果的顯示順序,可就不一定了。