日期:2014-05-18 浏览次数:20595 次
聚集索引在叶级别的存储其实就是以数据页的形式存储的,之前几篇关于堆数据行的存储已经都详细说过了,但是这里因为有了聚集索引, 所以还是有个特殊的地方需要注意的--带有唯一标识符的聚集索引行. 我们如果在建表并为其建立聚集索引时,没有为它指定UNIQUE属性,那么系统在键值遇到重复的时候,会自动增加一个4字节的字段来保证聚集键值的唯一。 至于为什么要保证它聚集键值的唯一,那么因为非聚集索引在引用它作为书签的时候必须要征求唯一性来取到唯一行 /*---------------------------------- *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 Corporation Enterprise Evaluation Edition on Windows NT 6.1 <X86> (Build 7600: ) *转载请注明出处 *更多精彩内容,请进http://blog.csdn.net/feixianxxx ------------------------------------*/ --建表(表源来自技术内幕) CREATE TABLE Clustered_Dupes (Col1 char(5) NOT NULL, Col2 int NOT NULL, Col3 char(3) NULL, Col4 char(6) NOT NULL); GO --在col1上建不唯一的聚集索引 CREATE CLUSTERED INDEX Cl_dupes_col1 ON Clustered_Dupes(col1); go --插入数据 INSERT Clustered_Dupes VALUES ('ABCDE', 123, null, 'CCCC'); GO --运行DBCC 查看各个类型页号 TRUNCATE TABLE sp_table_pages; INSERT INTO sp_table_pages EXEC ('dbcc ind ( tempdb, Clustered_Dupes, -1)' ); SELECT PageFID, PagePID FROM sp_table_pages WHERE PageType = 1 and PrevPageFID = 0 and PrevPagePID = 0; GO dbcc traceon(3604); --查看数据页情况 dbcc page (tempdb,1,151,1) /* 00000000: 10001600 41424344 457b0000 00000000 ?....ABCDE{...... 00000010: 43434343 20200500 08?????????????????CCCC ... */ --这是插入一条记录后的行记录,跟一般数据行的记录并没有区别 go --插入2条主键COL1重复的记录再次查看记录 INSERT Clustered_Dupes VALUES ('ABCDE', 456, null, 'DDDD'); INSERT Clustered_Dupes VALUES ('ABCDE', 64, null, 'EEEE'); go --再次查看 dbcc page (tempdb,1,151,1) /* Slot 0, Offset 0x60, Length 25, DumpStyle BYTE 00000000: 10001600 41424344 457b0000 00000000 ?....ABCDE{...... 00000010: 43434343 20200500 08?????????????????CCCC ... Slot 1, Offset 0x79, Length 33, DumpStyle BYTE 00000000: 30001600 41424344 45c80100 00000000 ?0...ABCDE....... 00000010: 44444444 20200500 08010021 00010000 ?DDDD .....!.... 00000020: 00???????????????????????????????????. Slot 2, Offset 0x9a, Length 33, DumpStyle BYTE 00000000: 30001600 41424344 45400000 00000000 ?0...ABCDE@...... 00000010: 45454545 20200500 08010021 00020000 ?EEEE .....!.... 00000020: 00???????????????????????????????????. */ --我们来看第二条和第三条 他们的都比第一条多了8个字节 第二条的最后面8个字节->>>>010021 00010000 00 第三条的最后面8个字节->>>>010021 00020000 00 分解下第二条: 0100->00000001=1 变成列的数目(原来的表中没有变长列,这列是唯一标识符认为是变长列的原因) 21 00->00100001=33 这列变长列字段结束的位移 即记录的长度 01000000->00000001=1唯一标识符的值为1 对应的我们看到第三条的唯一区别就是 最后的4个字节是02000000=2 小结论:通过每个记录多出来的8个字节 我们就能唯一标识每条记录了 --接下来我再插入几条看下情况 INSERT Clustered_Dupes VALUES ('ABCD', 456, null, 'DDDD'); INSERT Clustered_Dupes VALUES ('ABCD', 64, null, 'EEEE') INSERT Clustered_Dupes VALUES ('ABCD', 6, null, 'EEEE') --再次读PAGE 我们可以发现 --我们发现当新插入的三条跟上面一样,第二 三条是多出了8个字节,而且最后唯一标识符是从1 开始递增 ,并不是接着上面的2开始递增 结论: 当我们在建立聚集索引的时候没有指定唯一性,当聚集键出现重复值的时候,系统会自动为行增加一个4字节的边长列标识符。