热门:网页模板.net视频教程JQueryMVCjsonExtJs源码示例三级联动JQuery菜单
您现在的位置:.Net中文社区>> 数据库>>正文内容

非聚集索引行在非叶级别存储

发布时间:2010年07月22日点击数: 佚名

非聚集索引的非叶级的索引行通过非聚集键值和指针去遍历到下层的非聚集索引页来查找实际数据.
这里有种情况,
一种是这个非聚集索引是具有唯一性的,
还有一种则相反(当然也可以再细分,比如聚集索引是否存在,聚集索引是否唯一等)

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

  1. /*---------------------------------------------------------------------- 
  2. *auther:Poofly 
  3. *date:2010.3.14 
  4. *VERSION: 
  5. Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86)  
  6. Jul  9 2008 14:43:34  
  7. Copyright (c) 1988-2008 Microsoft Corporation 
  8. Enterprise Evaluation Edition on Windows NT 6.1 <X86> (Build 7600: ) 
  9. *转载请注明出处 
  10. *更多精彩内容,请进http://blog.csdn.net/feixianxxx 
  11. ------------------------------------------------------------------------*/ 
  12. --建表(表源来自技术内幕) 
  13. GO 
  14. CREATE TABLE NC_JNodes ( 
  15.   id int NOT NULL , 
  16.   str1 char (5) NOT NULL , 
  17.   str2 varchar (10) NULL  
  18. );  
  19. GO 
  20. --在str2上建立唯一性的聚集索引,在str1上建立具有唯一性的非聚集索引 
  21. CREATE UNIQUE CLUSTERED INDEX idxcl_str2 on NC_JNodes (str2); 
  22. CREATE UNIQUE INDEX idxNC ON NC_JNodes (str1);  
  23. GO 
  24. --插入数据 
  25. DECLARE @i int
  26. SET @i = 1240; 
  27. WHILE @i < 13000 BEGIN 
  28.   INSERT INTO NC_JNodes 
  29.    SELECT @i, cast(@i AS char),  
  30.        cast(cast(@i * rand() AS intas char);   --打乱了str1的排序 
  31.   SET @i = @i + 1; 
  32.  END;  
  33. GO 
  34. --查看页面分布和页号文件号 
  35. TRUNCATE TABLE sp_table_pages; 
  36. INSERT INTO sp_table_pages 
  37.     EXEC ('dbcc ind (poofly,NC_JNodes, -1)'); 
  38. SELECT PageFID, PagePID, IndexID, IndexLevel, PageType  
  39. FROM sp_table_pages 
  40. WHERE IndexLevel >= 0; 
  41. /* 
  42. PageFID PagePID     IndexID IndexLevel PageType 
  43. ------- ----------- ------- ---------- -------- 
  44. 5       967         1       0          1                --该条是聚集索引的叶级别的数据页面 
  45. 5       969         2       0          2                --该条是非聚集索引的叶级别的索引页面 
  46. 5       971         1       1          2                --该条是聚集索引的子结点的索引页面 
  47. 5       972         1       0          1 
  48. 5       973         2       1          2                --该条是非聚集索引的子结点的索引页面 
  49. 5       974         2       0          2 
  50. 5       975         1       0          1 
  51. */ 
  52. dbcc traceon(3604) 
  53. dbcc page(poofly,5,973,1)--非聚集索引的子结点的索引页面 
  54. /* 
  55. Slot 0, Offset 0x60, Length 12, DumpStyle BYTE 
  56.   
  57. 00000000:   06000000 1000c903 00000500 †8224 ?†8224 ?†8224 ?†8224 ?†8224 ?............   
  58.   
  59. Slot 1, Offset 0x138, Length 12, DumpStyle BYTE 
  60.   
  61. 00000000:   06313036 33310304 00000500 †8224 ?†8224 ?†8224 ?†8224 ?†8224 ?.10631......              
  62.    
  63.   
  64. Slot 2, Offset 0x144, Length 12, DumpStyle BYTE 
  65.   
  66. 00000000:   06313132 34340404 00000500 †8224 ?†8224 ?†8224 ?†8224 ?†8224 ?.11244......       
  67.   
  68. */ 
  69. --我们来看下第一个索引行 
  70. 06->状态位A  
  71. 000000 1000->无效的键值 
  72. c903 0000->Ox03c9==969 表示指向下一层的第一个非聚集索引页面号 
  73. 0500->文件号 
  74. --接下来看第二个索引行 
  75. 06->状态位A  
  76. 313036 3331->'10631' 这个是str1 非聚集索引值,是下一层非聚集索引页的第一个值 
  77. 0304 0000->Ox0403==1027 表示指向下一层的非聚集索引页面号 
  78. 0500->文件号 
  79.   
  80. --可以发现这个非聚集索引的结点行的结构好像跟聚集索引的结点行很像,第一行的所在键值都是无效的,只有从第二行开始有效 
  81. --我们来验证下这个假设吧 
  82. dbcc page(poofly,5,1027,1) 
  83. /* 
  84. Slot 0, Offset 0x60, Length 23, DumpStyle BYTE 
  85.   
  86. 00000000:   36313036 33310200 00010017 00363238 †10631.......628          
  87. 00000010:   38202020 202020†8224 ?†8224 ?†8224 ?†8224 ?†8224 ?†8224 ?†8224 ?†8224 ?†8224 ?†8224 ?†8224 ?8 
  88. */ 
  89. 注意看这里的第个到第个字节 3130363331='10631' 正好对应上我们在叶级别存储的那个非聚集值 
  90. 这条记录下面的存储我在以前也说过了就是一般的拥有聚集索引的表的非聚集索引叶级别的存储了,不再多描述 

结论:
在搜索记录的时候,我们可能通过非聚集索引列的值在非叶级别的索引行中找到对应的非聚集键值,然后遍历到叶级别的索引行中
然后利用叶级别的索引行中的书签键值,去遍历聚集索引树,然后找到我们要的数据.


接下来说说非聚集索引的非叶级的索引行在其不定义为UNIQUE的情况下的存储

  1. --建表(表源技术内幕系列) 
  2. CREATE TABLE NC_NU_JNodes ( 
  3.   id int NOT NULL , 
  4.   str1 char (5) NOT NULL , 
  5.   str2 varchar (10) NULL  
  6. );  
  7. GO 
  8. --在str2建立 
  9. CREATE UNIQUE CLUSTERED INDEX idxcl_str2 on NC_NU_JNodes (str2); 
  10. CREATE  INDEX idxNC ON  NC_NU_JNodes (str1);  
  11. GO 
  12. SET NOCOUNT ON
  13. GO 
  14. DECLARE @i int
  15. SET @i = 1240; 
  16. WHILE @i < 13000 BEGIN 
  17.   INSERT INTO NC_NU_JNodes 
  18.    SELECT @i, cast(@i AS char),  
  19.        cast(cast(@i * rand() AS intas char);   --打乱了str1的排序 
  20.   SET @i = @i + 1; 
  21.  END;  
  22. GO 
  23. --查看页面分布和页号文件号 
  24. TRUNCATE TABLE sp_table_pages; 
  25. INSERT INTO sp_table_pages 
  26.     EXEC ('dbcc ind (poofly,NC_NU_JNodes, -1)'); 
  27. SELECT PageFID, PagePID, IndexID, IndexLevel, PageType  
  28. FROM sp_table_pages 
  29. WHERE IndexLevel >= 0; 
  30. /* 
  31. PageFID PagePID     IndexID IndexLevel PageType 
  32. ------- ----------- ------- ---------- -------- 
  33. 5       1051        1       0          1 
  34. 5       1053        2       0          2 
  35. 5       1055        1       1          2 
  36. 5       1104        1       0          1 
  37. 5       1105        2       1          2 
  38. 5       1106        2       0          2 
  39. 5       1107        1       0          1 
  40. 。。。。。 
  41. */ 
  42. dbcc traceon(3604) 
  43. dbcc page(poofly,5,1105,1) 
  44. /* 
  45. Slot 0, Offset 0x60, Length 12, DumpStyle BYTE 
  46.   
  47. 00000000:   06066161 de001d04 00000500 †8224 ?†8224 ?†8224 ?†8224 ?†8224 ?..aa.......            
  48.   
  49. Slot 1, Offset 0x259, Length 29, DumpStyle BYTE 
  50.   
  51. 00000000:   36313036 33318304 00000500 02000001 †10631..........          
  52. 00000010:   001d0037 37393920 20202020 20†8224 ?†8224 ?†8224 ?†8224 ?...7799                     
  53.   
  54. Slot 2, Offset 0x276, Length 29, DumpStyle BYTE 
  55.   
  56. 00000000:   36313133 30318404 00000500 02000001 †11301..........          
  57. 00000010:   001d0031 30303832 20202020 20†8224 ?†8224 ?†8224 ?†8224 ?...10082                       
  58.   
  59. */ 
  60.   
  61. --让我们来分析下索引行的第一行 
  62. 06->状态位A  
  63. 066161 de00->无效的键值 
  64. 1d04 0000->Ox041d==1053 表示指向下一层的第一个非聚集索引页面号 
  65. 0500->文件号  
  66. --第二条索引行 
  67. 36->状态位A  
  68. 313036 3331->=='10631'这个是str1 非聚集索引值,是下一层非聚集索引页的第一个值 
  69. 8304 0000->Ox0483==1155  表示指向下一层的第一个非聚集索引页面号 
  70. 0500->==5 文件号 
  71. 0200->==2该页上的列数 
  72. 00->NULL位图 
  73. 0100->==1变长列的数目 
  74. 1d00->00011101=13+16=29 第一列变长列的结束位置即该索引行的长度 
  75. 37 37393920 20202020 20->=='7799      '聚集键值 
  76.   
  77. --验证下: 
  78. dbcc page(poofly,5,1155,3)--STYLE 3 可以以表格形式显示一些信息 
  79. /* 
  80. FileId PageId      Row    Level  str1 (key) str2 (key) KeyHashValue 
  81. ------ ----------- ------ ------ ---------- ---------- ---------------- 
  82. 5      1155        0      0      10631      7799       (f90044db974c) 
  83. 5      1155        1      0      10641      3241       (f500488c99d3) 
  84. 5      1155        2      0      10644      8469       (fd006debfe58) 
  85. .... 
  86. */ 
  87. 看这里的第一条 str1='10631' str2='7799'  就是上面非聚集索引非叶级别的第二条索引行读出的值 

结论:
其实这里跟我在非聚集索引在结点行的存储中说的行结构区别就是后面多了做为聚集索引的变长列所带来的多余字节
其作用也是显而易见的,就是以防止我们的非聚集键值因为不唯一性而带来的遍历不唯一
这里还有一点:如果你的索引没有定义成唯一性,即使所有的列值都是唯一的(就像本例中的str1不可能重复),但是它还是会包含书签。

本站热点业务

更多模板/案例展示

关于我们 | 联系我们 | 团队日志 | 网站地图 | 网站合作