日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

索引键的唯一性(3/4):唯一聚集索引上的唯一和非唯一非聚集索引

發(fā)布時間:2024/4/14 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 索引键的唯一性(3/4):唯一聚集索引上的唯一和非唯一非聚集索引 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在上篇文章里,我討論了唯一和非唯一聚集索引的區(qū)別。我們已經(jīng)知道,SQL Server內(nèi)部使用4 bytes的uniquifier來保證非唯一聚集索引行唯一。今天我們來看下唯一聚集索引上,唯一和非唯一非聚集索引的區(qū)別。當(dāng)我們在表上定義PRIMARY KEY約束時,SQL Server會為我們創(chuàng)建唯一聚集索引;另外我們可以通過CREATE UNIQUE CLUSTERED INDEX語句在表上創(chuàng)建唯一聚集索引。下面的代碼會創(chuàng)建customers表,然后在它上面創(chuàng)建唯一聚集索引,最后在表上創(chuàng)建唯一和非唯一非聚集索引。

1 -- Create a table with 393 length + 7 bytes overhead = 400 bytes 2 -- Therefore 20 records can be stored on one page (8.096 / 400) = 20,24 3 CREATE TABLE Customers 4 ( 5 CustomerID INT NOT NULL, 6 CustomerName CHAR(100) NOT NULL, 7 CustomerAddress CHAR(100) NOT NULL, 8 Comments CHAR(189) NOT NULL 9 ) 10 GO 11 12 -- Create a unique clustered index on the previous created table 13 CREATE UNIQUE CLUSTERED INDEX idx_Customers ON Customers(CustomerID) 14 GO 15 -- Insert 80.000 records 16 DECLARE @i INT = 1 17 WHILE (@i <= 80000) 18 BEGIN 19 INSERT INTO Customers VALUES 20 ( 21 @i, 22 'CustomerName' + CAST(@i AS CHAR), 23 'CustomerAddress' + CAST(@i AS CHAR), 24 'Comments' + CAST(@i AS CHAR) 25 ) 26 SET @i += 1 27 END 28 GO 29 30 -- Create a unique non clustered index on the clustered table 31 CREATE UNIQUE NONCLUSTERED INDEX idx_UniqueNCI_CustomerID 32 ON Customers(CustomerName) 33 GO 34 35 -- Create a non-unique non clustered index on the clustered table 36 CREATE NONCLUSTERED INDEX idx_NonUniqueNCI_CustomerID 37 ON Customers(CustomerName) 38 GO

在2個非聚集索引創(chuàng)建后,我們可以使用DMV sys.dm_db_index_physical_stats來查看索引的相關(guān)信息。

1 -- Retrieve physical information about the unique non-clustered index 2 SELECT * FROM sys.dm_db_index_physical_stats 3 ( 4 DB_ID('ALLOCATIONDB'), 5 OBJECT_ID('Customers'), 6 2, 7 NULL, 8 'DETAILED' 9 ) 10 GO 11 12 -- Retrieve physical information about the non-unique non-clustered index 13 SELECT * FROM sys.dm_db_index_physical_stats 14 ( 15 DB_ID('ALLOCATIONDB'), 16 OBJECT_ID('Customers'), 17 3, 18 NULL, 19 'DETAILED' 20 ) 21 GO

我們可以看到,唯一非聚集索引的記錄長度是107 bytes,非唯一非聚集索引的記錄長度是111 bytes。因此這2個索引的內(nèi)部存儲格式肯定不同。我們從唯一非聚集索引開始分析。

我們可以通過DBCC IND命令找出索引根頁,聚集索引的INDEX ID為1,非聚集索引的INDEX ID從2開始,依次遞增,這里應(yīng)該是2和3。

1 TRUNCATE TABLE dbo.sp_table_pages 2 INSERT INTO dbo.sp_table_pages 3 EXEC('DBCC IND(ALLOCATIONDB, Customers, -1)') 4 5 SELECT * FROM dbo.sp_table_pages ORDER BY IndexLevel DESC

從這里我們可以看出,唯一非聚集索引的根頁是20834,非唯一非聚集索引的根頁是21890。

我們看下唯一非聚集索引的根頁內(nèi)容:

1 DBCC PAGE(ALLOCATIONDB, 1, 20834, 3) 2 GO

從圖中我們可以看到,每條索引記錄包含非聚集鍵(這里是唯一的)——即CustomerName列。

我們換參數(shù)1再來看看根頁信息:

1 DBCC TRACEON(3604) 2 DBCC PAGE(ALLOCATIONDB, 1, 20834, 1) 3 GO

這里的107 bytes包含下列信息:

  • 1 byte: 狀態(tài)位
  • n bytes:非唯一聚集索引鍵——這里是CustomerName列,100 bytes
  • 4 bytes:頁ID(PageID)
  • 2 bytes:文件ID(FileID)

在唯一非聚集索引里,所有非葉子層的每條索引記錄都包含這107 bytes信息。因此,你的非聚集索引鍵大小會影響到每個索引頁可以存儲多少條索引記錄。這樣的話,這個例子的CHAR(100),并不是一個很好的索引鍵。

我們繼續(xù)往下看,索引葉子層的存儲情況:

1 DBCC PAGE(ALLOCATIONDB, 1, 20834, 3)--根層 2 GO 3 4 DBCC PAGE(ALLOCATIONDB, 1, 20833, 3)--中間層 5 GO 6 7 DBCC PAGE(ALLOCATIONDB, 1, 21098, 3)--葉子層 8 GO

從圖中我們可以看到,SQL Server在葉子層這里保存聚集鍵(即CustomerID列的值)。這個值是SQL Server用來指向聚集索引里對應(yīng)記錄的指針。手上有了這個值,SQL Server就可以在聚集索引找到對應(yīng)記錄——通過聚集索引查找(Clustered Index Seek)運算符。這和在堆表上定義的非聚集索引有重大區(qū)別。因為在堆表里,SQL Server使用葉子層的HEAP RID直接指向數(shù)據(jù)頁里存儲的對應(yīng)記錄。因此,SQL Server不用訪問額外索引,就可以直接正確讀取到數(shù)據(jù)頁。

這也意味著SQL Server在堆表上通過非聚集索引找記錄,比在聚集表上通過非聚集索引找記錄快很多,因為SQL Server不需要執(zhí)行額外的聚集索引查找(Clustered Index Seek)運算符。因此在堆表上可以讀取更少的頁正確找到記錄。當(dāng)不要高估這個細(xì)節(jié),想想在堆表通過使用非聚集索引,性能上可以有多少好處。事實上,SQL Server總是盡量把索引頁放在緩存區(qū)管理器里,因此對于SQL Server來說,使用額外的聚集索引查找(Clustered Index Seek)從聚集索引里找回記錄,成本更低。

現(xiàn)在我們來分析下非唯一非聚集索引。先來看看根頁:

1 DBCC PAGE(ALLOCATIONDB, 1, 21890, 3) 2 GO

從上圖可以看出,非唯一非聚集索引根頁里,SQL Server這里保存里非聚集索引鍵和聚集索引鍵,這個和剛才的唯一聚集索引根頁是不一樣的。

SQL Server這里需要使用唯一聚集鍵來使非唯一非聚集索引鍵唯一。這在非唯一非聚集索引的每一層都會保存,從索引根頁到葉子層。這就是說你需要更多的存儲空間來保存索引,因為SQL Server在每條索引記錄里不僅保存唯一聚集鍵,也保存非唯一非聚集索引鍵。因此當(dāng)你選擇不好的聚集鍵(像 CHAR(100)等)時,情況會變得更糟。

1 DBCC PAGE(ALLOCATIONDB, 1, 21890, 3)--根層 2 GO 3 4 DBCC PAGE(ALLOCATIONDB, 1, 21889, 3)--中間層 5 GO 6 7 DBCC PAGE(ALLOCATIONDB, 1, 22087, 3)--葉子層 8 GO

我們換參數(shù)1再來看看根頁信息:

1 DBCC TRACEON(3604) 2 DBCC PAGE(ALLOCATIONDB, 1, 21890, 1) 3 GO

這111 bytes包括:

  • 1 byte:狀態(tài)位
  • n bytes:非唯一非聚集索引鍵——這里是CustomerName列,100 bytes
  • n bytes:唯一聚集索引鍵——這里是CustomerID列,4 bytes
  • 4 bytes:頁ID(PageID)
  • 2 bytes:文件ID(FileID)

當(dāng)你把這些字節(jié)長度匯總后,你就得到了剛才提到的111 bytes。因此在你創(chuàng)建非唯一非聚集索引時,就要考慮到這些額外存儲,因為它會影響到你的非聚集索引的每一層。

在這個系列的下篇文章里,我們最后來看下在非唯一聚集索引上,唯一和非唯一非聚集索引的區(qū)別,請繼續(xù)關(guān)注!

參考文章:

https://www.sqlpassion.at/archive/2010/08/31/unique-and-non-unique-non-clustered-indexes-on-a-unique-clustered-index/

轉(zhuǎn)載于:https://www.cnblogs.com/woodytu/p/4565906.html

總結(jié)

以上是生活随笔為你收集整理的索引键的唯一性(3/4):唯一聚集索引上的唯一和非唯一非聚集索引的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。