在索引深入淺出:非聚集索引的B樹結構在聚集表里,我們討論了非聚集索引。我們提到,唯一非聚集索引可以讓所討論的問題變得簡單很多。我們已經知道了非聚集索引的通用結構,現在我們來看下在非唯一列上的非聚集索引的存儲結構。
在索引深入淺出:選擇正確并合適的聚集索引鍵里,我們討論了在非唯一列上如何管理聚集鍵。我們知道SQL Server會給所有發生重復的聚集鍵增加4 bytes的值。同樣,非聚集索引在B樹的所有層增加聚集鍵,讓在下一層的記錄標識唯一。至于聚集索引,uniquifier只在重復時增加。對于非聚集索引,如果創建索引不唯一時,聚集鍵會在所有記錄增加。如果非聚集索引是以唯一定義的,SQL Server只在葉子層增加聚集鍵,用做書簽查找(bookmark lookup)操作。
我們來看一個例子。
1 SELECT * INTO dbo.SalesOrderDetail FROM AdventureWorks2008r2.Sales.SalesOrderDetail2 GO3 CREATE UNIQUE CLUSTERED INDEX ix_SalesOrderDetail ON dbo.SalesOrderDetail(SalesOrderDetailID)4 GO5 CREATE INDEX Ix_PRoductId ON SalesOrderDetail(ProductId,Salesorderid)
我們創建了SalesOrderDetail表的副本,在SalesOrderDetailId列定義了唯一聚集索引,在ProductId和SalesOrderId列定義了非聚集索引。注意,在創建非聚集索引的時候,我有意回避了使用Unique關鍵字,即使這個非聚集索引鍵是唯一的。
我們用DBCC IND看下非聚集索引的頁面分配情況,并找出根頁。
1 TRUNCATE TABLE dbo.sp_table_pages2 INSERT INTO sp_table_pages EXEC('DBCC IND(IndexDB,SalesOrderDetail,2)')3 GO4 5 SELECT * FROM dbo.sp_table_pages ORDER BY IndexLevel DESC --根節點/索引頁
可以看出,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)--葉子頁
我們來看上半部分的根頁,聚集鍵(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 GO10 TRUNCATE TABLE dbo.sp_table_pages11 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)--葉子頁
在根頁我們看到多了Heap RID列,如果你回去看看索引深入淺出:非聚集索引的B樹結構在堆表,你會發現Heap RID列只在葉子層里的頁出現,不在根頁出現。在你把非聚集索引定義為唯一或非唯一(unique or non unique)時,葉子層的頁結構不會發生改變。
你可能已經注意到,在我們上述的例子里,即使非聚集索引鍵是唯一的,SQL Server還是只當它是非聚集索引,因為當我們創建非聚集索引時沒加unique關鍵字。在索引所有層增加聚集鍵(或Heap RID)可能會增加更多的索引層IO操作,這個看聚集鍵的大小而定。因此在所有情況下,我們定義非聚集索引時,考慮選擇唯一列(或多列)作為非聚集鍵非常重要。
新聞熱點
疑難解答