我在 SQL Server 2005技术内幕:存储引擎 的拆分页部分看到以下内容:When you inspect the original page after the split, you might find that it contains either the first half of the rows from the original page or the second half. SQL Server normally moves the rows so the new row to be inserted goes on the new page. Because the rows are moving anyway, it makes more sense to adjust their positions to accommodate the new inserted row.我自己的解释是:
    当你检查拆分后的原始分页时,你可能发现它既可能有原始分页的上半部分,也可能有下半部分。 为了即将插入的新行,SQL Server通常移动一些行到新的分页。因为这些行总是要移动的,所以这些移动的行调整位置以便新记录插入其中将显得更高效。
文中提到拆分之后的原始分页上既可能有拆分之前原始分页的上半部分和下半部分,但做了几个测试,都没有遇到会在拆分后的原始分页里留下拆分前原始分页的下半部分的数据。是否我理解这句话有误,还是测试的例子不对,望高手给予指点,如有测试记录最好

解决方案 »

  1.   

    从原文来看,似乎是表明移动行与填充有些关系.为了使得行的填充合理,它总是会移动的,只不过迟早不同而已.楼主的测试不知道是什么样的,或许是因为你已有的行数太少了,不足以使SQLSERVER觉得为了合理分布而需要移动那些行.
      

  2.   

    其实我的测试也是在技术内幕的列子上的use test;
    goif object_id('bigrows', 'U') is not null
    drop table bigrows;
    go/*
    测试设计1.创建一个简单的表,两个字段即可,一个定长,一个变长,使之具有普遍性
    2.第一个字段使用整形,并作为主键
    3.第二个字段使用变长,取值1600字符,这样能用少量的记录行就能填充一个数据页
    */
    create table bigrows
    (
    a int primary key,
    b varchar(1600)
    );
    go/*
    记录长度计算假设变长列全部占用record-len = TagA + TagB + FSize + FData + Ncol + Nullbits 
    + VarCount + VarOffset + VarData + RowOffset
       = 1 + 1 + 2 + 4 + 2 + 1 + 2 + 2 + 1600 + 2
       = 1617 byte一个数据页可以容纳的记录行数row-count = 8096 / 1617 ≈ 5为了使得聚集索引还有插入的空间 a 使用等差数列 差为5 以5开头
    */
    insert into bigrows
    values(5, replicate('a', 1600));insert into bigrows
    values(10, replicate('b', 1600));insert into bigrows
    values(15, replicate('c', 1600));insert into bigrows
    values(20, replicate('d', 1600));insert into bigrows
    values(25, replicate('e', 1600));--用dbcc ind命令查看数据页情况
    dbcc ind(test, bigrows, -1)
    go
    /*
    执行结果PageFID PagePID     IAMFID IAMPID       IndexID      PageType IndexLevel 
    ------- ----------- ------ -----------  -----------  -------- ---------- 
    1       78          NULL   NULL         1            10       NULL       
    1       41          1      78           1            1        0  只显示了有用的列
    得到聚集索引叶子层的一个数据页 1:41        
    */--查看数据页详细情况
    dbcc traceon(3604);
    go
    dbcc page(test, 1, 41, 1);
    go
    /*
    Row - Offset                         
    4 (0x4) - 6556 (0x199c)    ---a = 25             
    3 (0x3) - 4941 (0x134d)    ---a = 20           
    2 (0x2) - 3326 (0xcfe)     ---a = 15         
    1 (0x1) - 1711 (0x6af)     ---a = 10         
    0 (0x0) - 96 (0x60)    ---a = 5
    */--插入第六行导致数据页拆分
    insert into bigrows
    values(7, replicate('x', 1600));dbcc ind(test, bigrows, -1);
    go
    /*得到 1:126
     1:41
    */--先查看原始分页的情况
    dbcc page(test, 1, 41, 1);
    go
    /*
    Row - Offset                         
    2 (0x2) - 1711 (0x6af)  a = 10             
    1 (0x1) - 3326 (0xcfe)  a = 7             
    0 (0x0) - 96 (0x60)     a = 5
    */
    --在查看新分页
    dbcc page(test, 1, 126, 1);
    go
    /*
    Row - Offset                         
    2 (0x2) - 3326 (0xcfe)   a = 25              
    1 (0x1) - 1711 (0x6af)   a = 20           
    0 (0x0) - 96 (0x60)  a = 15
    *//*
    可以看出原始分页发生了拆分,前两行留在了原始分页
    page 41,新记录 a = 7 这两行的中间原始分页的后三行被移动到了新的分页 page = 126
    */--改变插入的位置,重头来,插入 a = 22的记录
    --得到的结果是前三行依然留在原始分页,后两行移动到新分页,新记录插在它们中间
    --过程省略--疑问:什么时候才能出现记录的前半段被移动到新页呢?