<address id="thnfp"></address>

    <address id="thnfp"><th id="thnfp"><progress id="thnfp"></progress></th></address>
    <listing id="thnfp"><nobr id="thnfp"><meter id="thnfp"></meter></nobr></listing>
    dvbbs
    收藏本頁
    聯系我們
    論壇幫助
    dvbbs

    >> 電腦專業知識交流
    搜一搜相關精彩主題 
    安易免費財務軟件交流論壇專業知識交流電腦知識交流 → SQL Server2008存儲結構之聚集索引

    您是本帖的第 627 個閱讀者
    樹形 打印
    標題:
    SQL Server2008存儲結構之聚集索引
    炙天
    帥哥喲,離線,有人找我嗎?
    等級:論壇游民
    文章:101
    積分:900
    注冊:2011年1月10日
    樓主
      點擊這里發送電子郵件給炙天

    發貼心情
    SQL Server2008存儲結構之聚集索引

    聚集索引即基于數據行的鍵值在表內排序和存儲這些數據行。每個表只能有一個聚集索引,因為數據行本身只能按一個順序存儲。

    從某種程度上,聚集索引即數據,這句話是有道理的;但正如同其他索引一樣,聚集索引也是按 B 樹結構進行組織的。既然是B樹組織,那么就有葉子結點和非葉子節點之分。聚集索引B 樹的頂端節點稱為根節點;聚集索引中的底層節點稱為葉節點。在根節點與葉節點之間的任何索引級別統稱為中間級。在聚集索引中,葉節點包含基礎表的數據頁。根節點和中間級節點包含存有索引行的索引頁。每個索引行包含一個鍵值和一個指針,該指針指向 B 樹上的某一中間級頁或葉級索引中的某個數據行。每級索引中的頁均被鏈接在雙向鏈接列表中。

    因此可以這么說,聚集索引的葉子結點存儲的是按聚集索引順序排列的數據本身,而中間結點和根節點則在維護索引和其層級。

    對于某個聚集索引, sys.system_internals_allocation_units 中的 root_page 列指向該聚集索引某個特定分區的頂部。SQL Server 將從索引中向下移動以查找與某個聚集索引鍵對應的行。為了查找鍵的范圍,SQL Server 將在索引中移動以查找該范圍的起始鍵值,然后用向前或向后指針在數據頁中進行掃描。為了查找數據頁鏈的首頁,SQL Server 將從索引的根節點沿最左邊的指針進行掃描。


    drop table testUniqueCluster

    drop table testNonUniqueCluster

    CREATE TABLE testUniqueCluster

    (

    name CHAR(900),

    remark CHAR(1100)

    )

    CREATE UNIQUE CLUSTERED INDEX ix_testUniqueCluster

    ON testUniqueCluster(name)

    INSERT INTO testUniqueCluster VALUES('B','BBB1')

    INSERT INTO testUniqueCluster VALUES('A','AAA1')

    CREATE TABLE testNonUniqueCluster

    (

    name CHAR(900),

    remark CHAR(1100)

    )

    CREATE CLUSTERED INDEX ix_testNonUniqueCluster

    ON testNonUniqueCluster(name)

    INSERT INTO testNonUniqueCluster VALUES('B','BBB2')

    INSERT INTO testNonUniqueCluster VALUES('B','BBB1')

    INSERT INTO testNonUniqueCluster VALUES('A','AAA1')

    SELECT c.name,a.type_desc,

    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

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

    AND c.name in ('testUniqueCluster','testNonUniqueCluster')

    TRUNCATE TABLE tablepage;

    INSERT INTO tablepage EXEC ('DBCC IND(testdb,testUniqueCluster,1)');

    INSERT INTO tablepage EXEC ('DBCC IND(testdb,testNonUniqueCluster,1)');

    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

    Name

    Type_desc

    Used_pages

    Data_pages

    First_page_address

    Root_address

    IAM_Address

    testUniqueCluster

    IN_ROW_DATA

    2

    1

    1:233

    1:233

    1:234

    testNonUniqueCluster

    IN_ROW_DATA

    2

    1

    1:235

    1:235

    1:236

    下面我們用dbcc命令介紹一下聚集索引的構造。

    DBCC TRACEON(3604)

    DBCC PAGE(testDB,1,233,1)

    m_type = 1

    5E3BC060: 1000d407 42202020 20202020 20202020 ?....B

    ....

    5E3BC3E0: 20202020 20202020 42424231 20202020 ? BBB1

    ...

    5E3BC830: 20202020 0200fc10 00d40741 20202020 ? .......A

    ...

    5E3BCBB0: 20202020 20202020 20202020 20202041 ? A

    5E3BCBC0: 41413120 20202020 20202020 20202020 ?AA1

    ...

    5E3BD000: 20202020 20202020 20202002 00fc0000 ? .....

    OFFSET TABLE:

    Row - Offset

    1 (0x1) - 96 (0x60)

    0 (0x0) - 2103 (0x837)

    DBCC PAGE(testDB,1,235,1)

    5E3BC060: 1000d407 42202020 20202020 20202020 ?....B

    ...

    5E3BC3E0: 20202020 20202020 42424232 20202020 ? BBB2

    ...

    5E3BC830: 20202020 0300f830 00d40742 20202020 ? ...0...B

    ...

    5E3BCBB0: 20202020 20202020 20202020 20202042 ? B

    5E3BCBC0: 42423120 20202020 20202020 20202020 ?BB1

    ...

    5E3BD000: 20202020 20202020 20202003 00f80100 ? .....

    5E3BD010: df070100 00001000 d4074120 20202020 ?..........A

    ...

    5E3BD390: 20202020 20202020 20202020 20204141 ? AA

    5E3BD3A0: 41312020 20202020 20202020 20202020 ?A1

    ...

    5E3BD7E0: 20202020 20202020 20200300 f8000021 ? .....!

    OFFSET TABLE:

    Row - Offset

    2 (0x2) - 2103 (0x837)

    1 (0x1) - 96 (0x60)

    0 (0x0) - 4118 (0x1016)

    其中紅顏色的部分為每行的行頭部分,藍顏色部分為每行的結尾部分。

    大家可以看到m_type=1即數據頁面,大家應該很奇怪吧,為什么明明是聚集索引,卻是數據頁面呢?正如上面所提到,聚集索引的葉子頁面即數據頁面。因為這個表只有2~3條記錄,所以root頁面還達不到需要分為B樹的程度,所以該root頁面也是葉子頁面。

    我們首先來看一下1000d407的行頭部如何解釋

    第0位

    第1-3位

    第4位

    第5位

    第6-7位

    1個字節

    2個字節

    0

    000

    1

    0

    00

    00

    d407

    10

    00

    2004

    始終為0

    0表示主記錄
    3表示索引記錄
    5表示幻影索引記錄

    存在NULL位圖

    存在變長字段

    保留

    狀態B保留

    字段長度

    即該行為不存在變長字段的主記錄,且字段長度為2004個字節。

    那30 00d407該如何解釋呢?即00001100即存在變長字段的主記錄,我們的testNonUniqueCluster怎么會存在變長字段呢?

    在該非唯一聚集索引表中,我們首先插入記錄B、BBB2記錄,再插入B、BBB1記錄,這個時候對于非唯一索引如何去識別呢?SQL Server在重復行的行尾增加了8個額外的字節,稍后我們再分析行尾。

    在testUniqueCluster表中正常的行尾為0200fc,其解釋如下0200表示該表有2個字段,fc則為1111 1100,即前2個字段不為空。

    而對于testNonUniqueCluster表正常的行尾應為0300 f8,其解釋如下0300表示該表有3個字段,f8則為1111 1000,即前3個字段不為空;很顯然SQL Server把非唯一索引的標識符也當做字段了;但的的確確因為B、BBB2和A、AAA1在插入的時候是唯一的,所以不需要這個字段。

    我們接下來看看B、BBB1行的尾部03 00f8 0100 df070100 0000,0300f8解釋同上,0100即1表示該表一共有1個變長字段,df07即2015變長字段結束的位置,最后四個字節0100 0000為非唯一索引的標識符,換算成10進制即1。

    從頁面中記錄的順序我們其實可以看得出來,聚集索引的行的物理順序與行的實際存儲沒有太大關系,而是與記錄槽的順序的有關。

    既然我們再談論聚集索引,那就不能不說聚集索引的中間節點和根節點了,

    為了簡化處理,我們使用testUniqueCluster來做進一步的研究。

    該表包含2個定長字段,合計2000字節,加上相應的頭部的4個管理字節和尾部的3個管理字節,共計2007個字節,頁頭還需要96個字節,每行的偏移量需要2個字節,所以單頁8192字節只能容納大概4條記錄。也就是說當我們完成第五條記錄時就應該產生分頁現象了。

    INSERT INTO testUniqueCluster VALUES('C','CCC1')

    INSERT INTO testUniqueCluster VALUES('D','DDD1')

    INSERT INTO testUniqueCluster VALUES('E','EEE1')

    TRUNCATE TABLE tablepage;

    INSERT INTO tablepage EXEC ('DBCC IND(testdb,testUniqueCluster,1)');

    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

    以下為該表的詳細頁面分布

    index_name

    PagePID

    IAMPID

    IndexID

    Pagetype

    IndexLevel

    NextPagePID

    PrevPagePID

    234

    NULL

    1

    10

    NULL

    0

    0

    233

    234

    1

    1

    0

    248

    0

    239

    234

    1

    2

    1

    0

    0

    248

    234

    1

    1

    0

    0

    233

    我們再用sys.system_internals_allocation_units來看一下該表的頁面概要信息。

    name

    total_pages

    used_pages

    data_pages

    first_address

    root_address

    IAM_address

    testUniqueCluster

    4

    4

    2

    1:233

    1:239

    1:234

    從以上兩個表格,我們可以看出IAM頁面未發生變化,仍舊是第234頁面。

    根節點頁面發生了變化,現在是第239頁面,pagetype=2,即索引頁面,新增加了一個數據頁面第248頁面,第233頁面仍繼續存在;同時在第248和233個頁面之間存在著互鏈的關系。

    同時觀察一下數據,發現在第233頁中存在A、AAA1;B、BBB1;C、CCC1;D、DDD1等4條記錄,而第248頁中則存在E、EEE1記錄,也就是說對于SQL Server來說索引的分裂應該是以最小代價進行,而不是完全均衡策略。

    再讓我們用DBCC PAGE(1,testDB,239,3)觀察一下根節點的內容。

    FileId

    PageId

    Row

    Level

    ChildFileId

    ChildPageId

    name (key)

    KeyHashValue

    1

    239

    0

    1

    1

    233

    NULL

    (6f4251ce1f81)

    1

    239

    1

    1

    1

    248

    E

    (201c8aeace10)

    因為這是個索引的非葉子節點,所以連表現形式都簡化了。

    FieldId為當前頁面的文件ID

    PageId為當前頁面的頁面ID

    Row表示為當前的slot槽

    Level為1表示為當前為非葉子節點

    ChildFieldId表示為插槽號指向的頁面的文件ID

    ChildPageId表示為插槽號指向的頁面的頁面ID

    Name表示為當前索引的鍵值

    KeyHashValue為SQL Server鍵值的內部表示的hash值。

    即E右側的數據指向第248頁面,而左側的則指向第233頁面。

    那么再讓我們插入4條記錄看看根頁面的變化。

    INSERT INTO testUniqueCluster VALUES('C','CCC1')

    INSERT INTO testUniqueCluster VALUES('D','DDD1')

    INSERT INTO testUniqueCluster VALUES('E','EEE1')

    DBCC PAGE(1,testDB,239,3)

    FileId

    PageId

    Row

    Level

    ChildFileId

    ChildPageId

    name (key)

    KeyHashValue

    1

    239

    0

    1

    1

    233

    NULL

    (6f4251ce1f81)

    1

    239

    1

    1

    1

    248

    E

    (201c8aeace10)

    1

    239

    2

    1

    1

    249

    I

    (201cbd800c11)

    現在我們可以看到在根節點上又增加了一個新的鍵值I,凡是大于等于I的記錄均指向第249頁;結合前面的描述,我們可以得到下面的索引結構變化示意圖。

    ip地址已設置保密
    2011/1/13 8:39:20

     1   1   1/1頁      1    
    網上貿易 創造奇跡! 阿里巴巴 Alibaba
    北京安易天地軟件有限公司北方論壇
    聯系電話:010-51268244 13611231185 QQ:511102924
    Powered By Dvbbs Version 7.1.0 Sp1
    頁面執行時間 0.21680 秒, 5 次數據查詢
    Channel