当前位置: 代码迷 >> Sql Server >> 【SQL Server2005页面存储5之-非聚集索引行在非叶级别存储】解决办法
  详细解决方案

【SQL Server2005页面存储5之-非聚集索引行在非叶级别存储】解决办法

热度:77   发布时间:2016-04-27 17:18:24.0
【SQL Server2005页面存储5之--非聚集索引行在非叶级别存储】
距离上一篇很久很久了。。这个是最后一篇 补上

博客地址:http://blog.csdn.net/feixianxxx/archive/2010/07/17/5741364.aspx

非聚集索引的非叶级的索引行通过非聚集键值和指针去遍历到下层的非聚集索引页来查找实际数据.

这里有种情况,

一种是这个非聚集索引是具有唯一性的,

还有一种则相反(当然也可以再细分,比如聚集索引是否存在,聚集索引是否唯一等)

 

先来说说当非聚集索引定义有唯一性的情况

 

SQL code
/*----------------------------------*auther:Poofly*date:2010.3.14*VERSION:Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) Jul  9 2008 14:43:34 Copyright (c) 1988-2008 Microsoft CorporationEnterprise Evaluation Edition on Windows NT 6.1 <X86> (Build 7600: )*转载请注明出处*更多精彩内容,请进http://blog.csdn.net/feixianxxx------------------------------------*/--建表(表源来自技术内幕)GOCREATE TABLE NC_JNodes (  id int NOT NULL ,  str1 char (5) NOT NULL ,  str2 varchar (10) NULL ); GO--在str2上建立唯一性的聚集索引,在str1上建立具有唯一性的非聚集索引CREATE UNIQUE CLUSTERED INDEX idxcl_str2 on NC_JNodes (str2);CREATE UNIQUE INDEX idxNC ON NC_JNodes (str1); GO--插入数据DECLARE @i int;SET @i = 1240;WHILE @i < 13000 BEGIN  INSERT INTO NC_JNodes   SELECT @i, cast(@i AS char),        cast(cast(@i * rand() AS int) as char);   --打乱了str1的排序  SET @i = @i + 1; END; GO--查看页面分布和页号文件号TRUNCATE TABLE sp_table_pages;INSERT INTO sp_table_pages    EXEC ('dbcc ind (poofly,NC_JNodes, -1)');SELECT PageFID, PagePID, IndexID, IndexLevel, PageType FROM sp_table_pagesWHERE IndexLevel >= 0;/*PageFID PagePID     IndexID IndexLevel PageType------- ----------- ------- ---------- --------5       967         1       0          1                --该条是聚集索引的叶级别的数据页面5       969         2       0          2                --该条是非聚集索引的叶级别的索引页面5       971         1       1          2                --该条是聚集索引的子结点的索引页面5       972         1       0          15       973         2       1          2                --该条是非聚集索引的子结点的索引页面5       974         2       0          25       975         1       0          1*/dbcc traceon(3604)dbcc page(poofly,5,973,1)--非聚集索引的子结点的索引页面/*Slot 0, Offset 0x60, Length 12, DumpStyle BYTE 00000000:   06000000 1000c903 00000500 ?8224 ??8224 ??8224 ??8224 ??8224 ?............   Slot 1, Offset 0x138, Length 12, DumpStyle BYTE 00000000:   06313036 33310304 00000500 ?8224 ??8224 ??8224 ??8224 ??8224 ?.10631......                Slot 2, Offset 0x144, Length 12, DumpStyle BYTE 00000000:   06313132 34340404 00000500 ?8224 ??8224 ??8224 ??8224 ??8224 ?.11244......       */--我们来看下第一个索引行06->状态位A 000000 1000->无效的键值c903 0000->Ox03c9==969 表示指向下一层的第一个非聚集索引页面号0500->文件号--接下来看第二个索引行06->状态位A 313036 3331->'10631' 这个是str1 非聚集索引值,是下一层非聚集索引页的第一个值0304 0000->Ox0403==1027 表示指向下一层的非聚集索引页面号0500->文件号 --可以发现这个非聚集索引的结点行的结构好像跟聚集索引的结点行很像,第一行的所在键值都是无效的,只有从第二行开始有效--我们来验证下这个假设吧dbcc page(poofly,5,1027,1)/*Slot 0, Offset 0x60, Length 23, DumpStyle BYTE 00000000:   36313036 33310200 00010017 00363238 ?10631.......628         00000010:   38202020 202020?8224 ??8224 ??8224 ??8224 ??8224 ??8224 ??8224 ??8224 ??8224 ??8224 ??8224 ?8*/注意看这里的第个到第个字节 3130363331='10631' 正好对应上我们在叶级别存储的那个非聚集值这条记录下面的存储我在以前也说过了就是一般的拥有聚集索引的表的非聚集索引叶级别的存储了,不再多描述

 

结论:

在搜索记录的时候,我们可能通过非聚集索引列的值在非叶级别的索引行中找到对应的非聚集键值,然后遍历到叶级别的索引行中

然后利用叶级别的索引行中的书签键值,去遍历聚集索引树,然后找到我们要的数据.


 

接下来说说非聚集索引的非叶级的索引行在其不定义为UNIQUE的情况下的存储
SQL code
 --建表(表源技术内幕系列)CREATE TABLE NC_NU_JNodes (  id int NOT NULL ,  str1 char (5) NOT NULL ,  str2 varchar (10) NULL ); GO--在str2建立CREATE UNIQUE CLUSTERED INDEX idxcl_str2 on NC_NU_JNodes (str2);CREATE  INDEX idxNC ON  NC_NU_JNodes (str1); GOSET NOCOUNT ON;GODECLARE @i int;SET @i = 1240;WHILE @i < 13000 BEGIN  INSERT INTO NC_NU_JNodes   SELECT @i, cast(@i AS char),        cast(cast(@i * rand() AS int) as char);   --打乱了str1的排序  SET @i = @i + 1; END; GO--查看页面分布和页号文件号TRUNCATE TABLE sp_table_pages;INSERT INTO sp_table_pages    EXEC ('dbcc ind (poofly,NC_NU_JNodes, -1)');SELECT PageFID, PagePID, IndexID, IndexLevel, PageType FROM sp_table_pagesWHERE IndexLevel >= 0;/*PageFID PagePID     IndexID IndexLevel PageType------- ----------- ------- ---------- --------5       1051        1       0          15       1053        2       0          25       1055        1       1          25       1104        1       0          15       1105        2       1          25       1106        2       0          25       1107        1       0          1。。。。。*/dbcc traceon(3604)dbcc page(poofly,5,1105,1)/*Slot 0, Offset 0x60, Length 12, DumpStyle BYTE 00000000:   06066161 de001d04 00000500 ?8224 ??8224 ??8224 ??8224 ??8224 ?..aa.......            Slot 1, Offset 0x259, Length 29, DumpStyle BYTE 00000000:   36313036 33318304 00000500 02000001 ?10631..........         00000010:   001d0037 37393920 20202020 20?8224 ??8224 ??8224 ??8224 ?...7799                     Slot 2, Offset 0x276, Length 29, DumpStyle BYTE 00000000:   36313133 30318404 00000500 02000001 ?11301..........         00000010:   001d0031 30303832 20202020 20?8224 ??8224 ??8224 ??8224 ?...10082                       */ --让我们来分析下索引行的第一行06->状态位A 066161 de00->无效的键值1d04 0000->Ox041d==1053 表示指向下一层的第一个非聚集索引页面号0500->文件号 --第二条索引行36->状态位A 313036 3331->=='10631'这个是str1 非聚集索引值,是下一层非聚集索引页的第一个值8304 0000->Ox0483==1155  表示指向下一层的第一个非聚集索引页面号0500->==5 文件号0200->==2该页上的列数00->NULL位图0100->==1变长列的数目1d00->00011101=13+16=29 第一列变长列的结束位置即该索引行的长度37 37393920 20202020 20->=='7799      '聚集键值 --验证下:dbcc page(poofly,5,1155,3)--STYLE 3 可以以表格形式显示一些信息/*FileId PageId      Row    Level  str1 (key) str2 (key) KeyHashValue------ ----------- ------ ------ ---------- ---------- ----------------5      1155        0      0      10631      7799       (f90044db974c)5      1155        1      0      10641      3241       (f500488c99d3)5      1155        2      0      10644      8469       (fd006debfe58)....*/看这里的第一条 str1='10631' str2='7799'  就是上面非聚集索引非叶级别的第二条索引行读出的值
  相关解决方案