【问题标题】:How is fill factor physically allocated?填充因子是如何物理分配的?
【发布时间】:2009-09-02 13:02:27
【问题描述】:

我一直在网上搜索书籍和谷歌咒语,试图找出叶页中的实际填充因子(SQL Server 2000 和 2005)。

我知道它是创建索引时页面上剩余的可用空间量,但我没有找到如何实际剩余空间:即,它是否很大块接近页面的末尾,或者它是通过该数据的几个间隙。

例如,[只是为了简单起见],假设一个页面只能容纳 100 行。如果填充因子被声明为 75%,这是否意味着页面的第一个(或最后一个)75% 是数据,其余部分是空闲的,或是每四行空闲一次(即,页面看起来像:数据,数据,数据,免费,数据,数据,数据,免费,...)。

总而言之,我正在掌握在将行插入具有聚簇索引的表时发生的物理操作的确切情况,并且插入没有在最后发生行的。如果在一个页面中留下多个间隙,则插入的影响最小(至少在页面拆分之前),因为可能需要移动以容纳插入的行数被最小化。如果间隙在表中的一大块中,那么处理行的开销(至少在理论上)会显着增加。

如果有人知道 MSDN 参考,请指点我!我现在找不到(虽然仍在寻找)。根据我的阅读,暗示存在许多差距 - 但这似乎没有明确说明。

【问题讨论】:

    标签: sql-server sql-server-2005 sql-server-2000 fillfactor


    【解决方案1】:

    来自MSDN:

    填充因子设置仅在创建或重建索引时应用。 SQL Server Database Engine 不会动态保留页面中指定百分比的空白空间。试图保持数据页上的额外空间会破坏填充因子的目的,因为在输入数据时,Database Engine 必须执行页面拆分以保持每个页面上填充因子指定的可用空间百分比。

    还有:

    将新行添加到完整索引页面时,Database Engine 会将大约一半的行移动到新页面,以便为新行腾出空间。这种重组称为页面拆分。页面拆分为新记录腾出空间,但可能需要时间来执行,并且是一种资源密集型操作。此外,它可能会导致碎片化,从而导致I/O 操作增加。当频繁发生页面拆分时,可以通过使用新的或现有的填充因子值来重新构建索引以重新分配数据。

    SQL Server的数据页由以下元素组成:

    • Page header: 96 字节,已修复。
    • Data:变量
    • Row offset array:变量。

    行偏移数组总是存储在页面的end,并向后增长。

    数组的每个元素都是2-byte 值,保存页面中每一行开头的偏移量。

    行在数据页中没有排序:相反,它们的顺序(在集群存储的情况下)由行偏移数组确定。这是排序的行偏移量。

    比如说,如果我们将一个集群键值为10 的100-byte 行插入到一个集群表中并进入一个空闲页面,它会被插入如下:

    [00   - 95   ]   Header
    [96   - 195  ]   Row 10
    [196  - 8190 ]   Free space
    [8190 - 8191 ]   Row offset array: [96]
    

    然后我们在同一个页面中插入一个新行,这次集群键值为9:

    [00   - 95   ]   Header
    [96   - 195  ]   Row 10
    [196  - 295  ]   Row 9
    [296  - 8188 ]   Free space
    [8188 - 8191 ]   Row offset array: [196] [96]
    

    该行在逻辑上前置,但在物理上附加。

    偏移数组被重新排序以反映行的逻辑顺序。

    鉴于此,我们可以很容易地看到行被附加到空闲空间,从页面的开头开始,而指向行的指针附加到从页面末尾开始的可用空间。

    【讨论】:

    • 是的,我已经看到了,但这并没有说明填充因子最初是如何分布的。
    • @Quassnoi,我想他是在询问当新行“插入”到页面上的空白区域时会发生什么情况。无论是在整个页面中,还是在物理页面的末尾,(他认为)都会影响插入的性能......
    • @Charles -- “认为”有点强 :-) 我正在阅读相互矛盾的博客,有些人说会,有些人说不会。我只是想更深入地了解正在发生的事情......
    • @rangerchris,你是对的,对不起,选词不当!。也许“他的问题”会更好......
    • 我不得不猜测多余的空间都在后面。例如,如果一行包含两个 varchar(100) 列,您如何才能在整个页面中可接受地“分散”空白空间?我喜欢 Charles Bretana 的猜测(每次磁盘写入都会完成工作)。希望知道的人会添加到这些 cmets 中。
    【解决方案2】:

    这是我第一次想到这个,我对这个结论并不肯定,但是,

    既然 SQL Server 可以在单个读取 IO 中检索到的最小数据量是一整页数据,那么为什么首先需要对单页中的任何行进行排序?我敢打赌他们不是,所以即使最后的差距都在一个很大的差距中,新记录也可以在最后添加,无论这是否是正确的排序顺序。 (如果一开始就没有理由对页面上的记录进行排序)

    其次,考虑到 IO 的写入端,我认为最小的写入块也是整个页面,(即使是最小的更改也需要将整个页面写回磁盘)。这意味着每次写入页面时,页面上的所有行都可以在内存中排序,因此即使您插入到单个页面上一组已排序行的开头,整个页面也会被读出,可以将新记录插入到内存集合中的适当插槽中,然后将整个新排序的页面写回磁盘......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多