天天看點

索引深入淺出(7/10):非唯一列上的非聚集索引

在索引深入淺出:非聚集索引的B樹結構在聚集表裡,我們讨論了非聚集索引。我們提到,唯一非聚集索引可以讓所讨論的問題變得簡單很多。我們已經知道了非聚集索引的通用結構,現在我們來看下在非唯一列上的非聚集索引的存儲結構。

在索引深入淺出:選擇正确并合适的聚集索引鍵裡,我們讨論了在非唯一列上如何管理聚集鍵。我們知道SQL Server會給所有發生重複的聚集鍵增加4 bytes的值。同樣,非聚集索引在B樹的所有層增加聚集鍵,讓在下一層的記錄辨別唯一。至于聚集索引,uniquifier 隻在重複時增加。對于非聚集索引,如果建立索引不唯一時,聚集鍵會在所有記錄增加。如果非聚集索引是以唯一定義的,SQL Server隻在葉子層增加聚集鍵,用做書簽查找(bookmark lookup)操作。

我們來看一個例子。

1 SELECT * INTO dbo.SalesOrderDetail FROM AdventureWorks2008r2.Sales.SalesOrderDetail
2 GO
3 CREATE UNIQUE CLUSTERED INDEX ix_SalesOrderDetail ON dbo.SalesOrderDetail(SalesOrderDetailID)
4 GO
5 CREATE INDEX Ix_ProductId ON SalesOrderDetail(ProductId,Salesorderid)      

我們建立了SalesOrderDetail表的副本,在SalesOrderDetailId 列定義了唯一聚集索引,在ProductId和SalesOrderId列定義了非聚集索引。注意,在建立非聚集索引的時候,我有意回避了使用Unique關鍵字,即使這個非聚集索引鍵是唯一的。

我們用DBCC IND看下非聚集索引的頁面配置設定情況,并找出根頁。

1 TRUNCATE TABLE dbo.sp_table_pages
2 INSERT INTO sp_table_pages EXEC('DBCC IND(IndexDB,SalesOrderDetail,2)')
3 GO
4 
5 SELECT * FROM dbo.sp_table_pages ORDER BY IndexLevel DESC --根節點/索引頁      
索引深入淺出(7/10):非唯一列上的非聚集索引

可以看出,5128頁是我們的根頁。我們用DBCC PAGE看下5128頁資訊還有葉子頁的資訊。

1 DBCC TRACEON(3604)
2 DBCC PAGE(IndexDB,1,5128,3)--根頁
3 
4 DBCC TRACEON(3604)
5 DBCC PAGE(IndexDB,1,3760,3)--葉子頁      
索引深入淺出(7/10):非唯一列上的非聚集索引

我們來看上半部分的根頁,聚集鍵(SalesOrderDetailid)被加到了根頁。如果你和索引深入淺出:非聚集索引的B樹結構在聚集表裡的根頁比較,會發現那裡的根頁裡沒有聚集鍵,隻有在葉子頁裡才可以找到聚集鍵。在你把非聚集索引定義為唯一或非唯一(unique or non unique)時,葉子層的頁結構不會發生改變。

我們看下堆表的情況。

1 SELECT * INTO dbo.SalesOrderDetailHeap FROM AdventureWorks2008R2.Sales.SalesOrderDetail
 2 GO
 3 CREATE INDEX Ix_ProductId ON SalesOrderDetailHeap (ProductId,Salesorderid)
 4 GO
 5 SELECT index_id FROM sys.indexes WHERE name='Ix_ProductId' AND 
 6 OBJECT_NAME(OBJECT_ID)='SalesOrderDetailHeap'
 7 GO
 8 DBCC ind('IndexDB','SalesOrderDetailHeap',2)
 9 GO
10 TRUNCATE TABLE dbo.sp_table_pages
11 INSERT INTO sp_table_pages EXEC('DBCC IND(IndexDB,SalesOrderDetailHeap,2)')
12 SELECT * FROM dbo.sp_table_pages ORDER BY IndexLevel DESC --根節點/索引頁
13 DBCC TRACEON(3604)
14 DBCC PAGE(IndexDB,1,1192,3)--根頁
15 
16 DBCC TRACEON(3604)
17 DBCC PAGE(IndexDB,1,1096,3)--葉子頁      
索引深入淺出(7/10):非唯一列上的非聚集索引

在根頁我們看到多了Heap RID列,如果你回去看看索引深入淺出:非聚集索引的B樹結構在堆表,你會發現Heap RID列隻在葉子層裡的頁出現,不在根頁出現。在你把非聚集索引定義為唯一或非唯一(unique or non unique)時,葉子層的頁結構不會發生改變。

你可能已經注意到,在我們上述的例子裡,即使非聚集索引鍵是唯一的,SQL Server還是隻當它是非聚集索引,因為當我們建立非聚集索引時沒加unique關鍵字。在索引所有層增加聚集鍵(或Heap RID)可能會增加更多的索引層IO操作,這個看聚集鍵的大小而定。是以在所有情況下,我們定義非聚集索引時,考慮選擇唯一列(或多列)作為非聚集鍵非常重要。 

參考文章:

http://www.sqlservercentral.com/blogs/practicalsqldba/2013/03/24/sql-server-part-7-non-clustered-index-on-non-unique-column-/

注:此文章為

WoodyTu

學習MS SQL技術,收集整理相關文檔撰寫,歡迎轉載,請在文章頁面明顯位置給出此文連結!

若您覺得這篇文章還不錯請點選下右下角的推薦,有了您的支援才能激發作者更大的寫作熱情,非常感謝!

繼續閱讀