天天看點

SQL Server2008存儲結構之非聚集索引

非聚集索引與聚集索引具有相同的 B 樹結構,它們之間的顯著差别在于以下兩點:

基礎表的資料行不按非聚集鍵的順序排序和存儲。

非聚集索引的葉層是由索引頁而不是由資料頁組成。

非聚集索引既可以建在堆表結構上也可以建在聚集索引表上;非聚集索引中的每個索引行都包含非聚集鍵值和行定位符。此定位符指向聚集索引或堆中包含該鍵值的資料行。

如果表是堆則行定位器是指向行的指針。該指針由檔案辨別符 (ID)、頁碼和頁上的行數生成。整個指針稱為行 ID (RID)。

如果表包含有聚集索引,則行定位器是行的聚集索引鍵。如果聚集索引不是唯一的索引,SQL Server 将添加在内部生成的值(稱為唯一值)以使所有重複鍵唯一。此四位元組的值對于使用者不可見。僅當需要使聚集鍵唯一以用于非聚集索引中時,才添加該值。SQL Server 通過使用存儲在非聚集索引的葉行内的聚集索引鍵搜尋聚集索引來檢索資料行。

B 樹的頁集合由 sys.system_internals_allocation_units 系統視圖中的 root_page 指針定位。

SQL Server2008存儲結構之非聚集索引

堆表

--建立一張堆表

CREATE TABLE testHeapIndex

(

   name   CHAR(200),

   type1  CHAR(900),

   type2  CHAR(900)

)

--分别建立一個唯一索引和一個非唯一索引

CREATE UNIQUE INDEX idx_testHeapIndex1 ON testHeapIndex(type1)

CREATE INDEX idx_testHeapIndex2 ON testHeapIndex(type2)

--插入測試資料

INSERT INTO testHeapIndex VALUES('A','A1','A2')

INSERT INTO testHeapIndex VALUES('B','B1','B2')

INSERT INTO testHeapIndex VALUES('C','C1','B2')

INSERT INTO testHeapIndex VALUES('D','D1','B2')

INSERT INTO testHeapIndex VALUES('E','E1','C2')

INSERT INTO testHeapIndex VALUES('F','F1','F1')

INSERT INTO testHeapIndex VALUES('G','G1','G1')

INSERT INTO testHeapIndex VALUES('H','H1','G1')

INSERT INTO testHeapIndex VALUES('I','I1','G1')

INSERT INTO testHeapIndex VALUES('J','J1','J1')

--擷取該表的相應頁面資訊

SELECT A.NAME TABLE_NAME,B.NAME INDEX_NAME,B.INDEX_ID

  FROM SYS.OBJECTS A,SYS.INDEXES B

 WHERE A.OBJECT_ID=B.OBJECT_ID AND A.NAME='testHeapIndex'

TRUNCATE TABLE tablepage;

INSERT INTO tablepage EXEC ('DBCC IND(testdb,testHeapIndex,0)');

INSERT INTO tablepage EXEC ('DBCC IND(testdb,testHeapIndex,2)');

INSERT INTO tablepage EXEC ('DBCC IND(testdb,testHeapIndex,3)');

SELECT

  b.name table_name,

  CASE WHEN c.type=0 THEN '堆'

       WHEN c.type=1 THEN '聚集'

       WHEN c.type=2 THEN '非聚集'

       ELSE '其他'

  END index_type, 

  c.name index_name,

  PagePID,IAMPID,ObjectID,IndexID,Pagetype,IndexLevel,

  NextPagePID,PrevPagePID

  FROM tablepage a,sys.objects b,sys.indexes c

 WHERE A.ObjectID=b.object_id

   AND A.ObjectID=c.object_id

   AND a.IndexID=c.index_id

--擷取該表的root頁面位址,聚集索引的根節點必須通過下面腳本才能找到

SELECT c.name,a.type_desc,d.name,

       total_pages,used_pages,data_pages,

       testdb.dbo.f_get_page(first_page) first_page_address,

       testdb.dbo.f_get_page(root_page) root_address,

       testdb.dbo.f_get_page(first_iam_page) IAM_address

  FROM sys.system_internals_allocation_units a,sys.partitions b,sys.objects c,sys.indexes d

 WHERE a.container_id=b.partition_id and b.object_id=c.object_id

   AND d.object_id=b.object_id  AND d.index_id=b.index_id

   AND c.name in ('testHeapIndex')

--下面各個例子擷取相關頁面和root頁面的腳本基本相同,不再重複

堆表上的唯一非聚集索引

SQL Server2008存儲結構之非聚集索引

首先堆表是由若幹葉子頁面組成的,互相之間沒有連結關系,完全靠IAM頁面進行管理和維護。

我們可以看到page(1:90)為該唯一非聚集索引的根節點,因為資料量少實際上隻有一個索引節點,即大于等于I1的指向葉子頁面page(1:93),小于I1的則指向葉子頁面page(1:55)頁面。

葉子頁面中則包括每個索引條目的索引值和該索引指向的記錄的位置(檔案号+頁面+插槽号),因為這是唯一索引是以不需要額外的字段來記錄重複值。

堆表上的非唯一非聚集索引

SQL Server2008存儲結構之非聚集索引

我們可以看到page(1:94)為該非唯一非聚集索引的根節點,因為資料量少實際上隻有一個索引節點,即大于等于G1的指向葉子頁面page(1:78),小于G1的則指向葉子頁面page(1:109)頁面。

葉子頁面中則包括每個索引條目的索引值和該索引指向的記錄的位置(檔案号+頁面+插槽号);存儲結構與堆表上的唯一非聚集索引完全一緻,我們可以看出在堆表中盡管索引值不唯一,但通過索引值+指針(檔案号+頁面+插槽号)的方式,也能夠保證該索引條目的唯一性,是以不需要增加額外的輔助字段。

唯一聚集索引表

CREATE TABLE testUniqueClusterIndex

CREATE UNIQUE CLUSTERED INDEX idx_testUniqueClusterIndex_cluster ON testUniqueClusterIndex(name)

CREATE UNIQUE INDEX idx_testUniqueClusterIndex1 ON testUniqueClusterIndex(type1)

CREATE INDEX idx_testUniqueClusterIndex2 ON testUniqueClusterIndex(type2)

INSERT INTO testUniqueClusterIndex VALUES('A','A1','A2')

INSERT INTO testUniqueClusterIndex VALUES('B','B1','B2')

INSERT INTO testUniqueClusterIndex VALUES('C','C1','B2')

INSERT INTO testUniqueClusterIndex VALUES('D','D1','B2')

INSERT INTO testUniqueClusterIndex VALUES('E','E1','C2')

INSERT INTO testUniqueClusterIndex VALUES('F','F1','F1')

INSERT INTO testUniqueClusterIndex VALUES('G','G1','G1')

INSERT INTO testUniqueClusterIndex VALUES('H','H1','G1')

INSERT INTO testUniqueClusterIndex VALUES('I','I1','G1')

INSERT INTO testUniqueClusterIndex VALUES('J','J1','J1')

唯一聚集索引表上的唯一非聚集索引

SQL Server2008存儲結構之非聚集索引

我們首先可以看到page(1:192)為聚集索引的根節點,該根節點包括2個索引值和三個索引指針指向相應的葉子頁面,而聚集索引的葉子頁面則按照聚集索引的排序規則進行存儲。

page(1:194)為該唯一聚集索引表上的唯一非聚集索引的根節點,因為資料量少實際上隻有一個索引節點,即大于等于H1的指向葉子頁面page(1:195),小于H1的則指向葉子頁面page(1:151)頁面。

唯一非聚集索引的葉子頁面中則包括每個索引條目的索引值和其聚集鍵值;因為都是唯一的,是以兩者合起來能夠保證該索引條目的唯一性,是以不需要增加額外的輔助字段。

那麼當對唯一非聚集索引的字段進行查找的時候是如何處理的呢?SQL Server首先從唯一非聚集索引的根節點開始查起,直到找到合适的索引葉子頁面,然後根據該索引條目中的聚集索引鍵值,去聚集索引根節點中進行查找,一直找到正确的聚集葉子頁面為止。

唯一聚集索引表上的非唯一非聚集索引

SQL Server2008存儲結構之非聚集索引

page(1:196)為該唯一聚集索引表上的非唯一非聚集索引的根節點,因為資料量少實際上隻有一個索引節點,即大于等于G1的指向葉子頁面page(1:174),小于G1的則指向葉子頁面page(1:197)頁面。之是以在196頁面的索引條目中包括聚集索引的鍵值,是因為該索引條目不唯一造成的,從圖中可以看出,Type2=G1的索引條目有2條,是以需要聚集索引鍵值的存在才能保證該索引條目的歧義和唯一性。

非唯一非聚集索引的葉子頁面中則包括每個索引條目的索引值和其聚集鍵值;盡管非聚集索引不唯一,但因為聚集索引是唯一的,是以兩者合起來能夠保證該索引條目的唯一性,是以也不需要增加額外的輔助字段。

非唯一聚集索引表

CREATE TABLE testUnUniqueClusterIndex

CREATE CLUSTERED INDEX idx_testUnUniqueClusterIndex_cluster ON testUnUniqueClusterIndex(name)

CREATE UNIQUE INDEX idx_testUnUniqueClusterIndex1 ON testUnUniqueClusterIndex(type1)

CREATE INDEX idx_testUnUniqueClusterIndex2 ON testUnUniqueClusterIndex(type2)

INSERT INTO testUnUniqueClusterIndex VALUES('A','A1','A2')

INSERT INTO testUnUniqueClusterIndex VALUES('B','B1','B2')

INSERT INTO testUnUniqueClusterIndex VALUES('B','C1','B2')

INSERT INTO testUnUniqueClusterIndex VALUES('D','D1','B2')

INSERT INTO testUnUniqueClusterIndex VALUES('E','E1','C2')

INSERT INTO testUnUniqueClusterIndex VALUES('F','F1','F1')

INSERT INTO testUnUniqueClusterIndex VALUES('F','G1','G1')

INSERT INTO testUnUniqueClusterIndex VALUES('F','H1','G1')

INSERT INTO testUnUniqueClusterIndex VALUES('F','I1','I1')

INSERT INTO testUnUniqueClusterIndex VALUES('J','J1','J1')

非唯一聚集索引表上的唯一非聚集索引

SQL Server2008存儲結構之非聚集索引

我們首先可以看到page(1:205)為聚集索引的根節點,該根節點包括2個索引值和三個索引指針指向相應的葉子頁面,其中第二個索引值後面還帶了一個identifer為3的值,這是因為該聚集索引不唯一,是以必須增加一個唯一辨別才能定位到相應的下級節點中。而聚集索引的葉子頁面則按照聚集索引的排序規則進行存儲;注意在葉子節點中重複鍵值的聚集索引的尾部也帶有相應的唯一辨別值。

page(1:207)為該非唯一聚集索引表上的唯一非聚集索引的根節點,因為資料量少實際上隻有一個索引節點,即大于等于H1的指向葉子頁面page(1:201),小于H1的則指向葉子頁面page(1:208)頁面。

注意非唯一非聚集索引的葉子頁面中則包括每個索引條目的索引值和其聚集鍵值,同時在重複聚集鍵值的後面增加了相應的唯一辨別,是以三者結合起來就能夠保證該索引條目的唯一性了。

非唯一聚集索引表上的非唯一非聚集索引

SQL Server2008存儲結構之非聚集索引

page(1:209)為該非唯一聚集索引表上的非唯一非聚集索引的根節點,因為資料量少實際上隻有一個索引節點,即大于等于G1的指向葉子頁面page(1:210),小于G1的則指向葉子頁面page(1:203)頁面。

注意非唯一非聚集索引的葉子頁面中則包括每個索引條目的索引值和其聚集鍵值,同時在重複聚集鍵值的後面增加了相應的唯一辨別,雖然非唯一聚集索引的索引鍵值是重複的,但因為聚集索引鍵值和唯一辨別已經是唯一的,是以三者結合起來依然能夠保證該索引條目的唯一性。

本文轉自baoqiangwang51CTO部落格,原文連結:http://blog.51cto.com/baoqiangwang/425459,如需轉載請自行聯系原作者