SQL Server:添加列会使表大小超出预期

时间:2015-08-07 21:29:29

标签: sql-server

要迁移到新架构,我要对表做两件事:

  1. 将VARCHAR列更改为NVARCHAR
  2. 添加BIGINT列
  3. 为了测试这会如何影响大小,我生成了180,000行。我正在更改的VARCHAR列在每一行都设置为null。

    以下是sp_spaceused的结果(所有大小均以KB为单位):

    Final_Mark

    因此数据增长超过9MB。我原本预计它只会增长1.4 MB,因为我添加了一个8字节的数字列。

    如果我只是创建表并生成数据,那么大小看起来更像我期望的那样:

              rows     reserved     data   index_size  unused
              ----     --------     ----   ----------  ------
    before    180000     110976     43168       67288     520
    after     180000     120320     52536       67296     488
    

    那么添加一个列会导致sp_spaceused报告使用的数据多于实际添加的数据吗?

2 个答案:

答案 0 :(得分:1)

没有人真正解释为什么会这样。戴夫古格给了你一个很好的暗示。

SQL在页面中存储行。 (大概是8K,但不完全是)并且一行必须适合一个页面(不是真的,因为长的varchars可以使用指针存储在单独的页面上 - 但是你的全部都是null,所以我们暂时忽略它。)

页面以群集形式分配。

当您插入行时,您有一组很好的新页面和群集,并且行都很整洁。

在进行任何更改时,尤其是添加列时,SQL必须更新每一行。

更新任何行都需要更改一个或多个页面 - 因为更改的行可能不再适合同一页面。事实上,由于回滚的工作方式,我认为有时SQL实际上喜欢将更改的行移动到新页面。

因此,您紧密排列的行已分布并占用了更多页面和群集。随着时间的推移,有很多变化,这是平均值。并非每个更新都会添加页面 - 但添加列会使每一行变大,并且不太可能适合其先前的邻居。

我们不能更具体,因为您没有提供架构。如果有的话,我们会在您更改之前和之后了解每页的预期行数。

答案 1 :(得分:0)

正如大家所料,问题是分裂。生成数据并使用附加列迁移到新模式后,我使用sys.dm_db_index_physical_stats检查了碎片。聚集索引的avg_fragmentation_in_percent为98.8%。重建将其减少到0.4%,sp_spaceused显示数据大小从52MB减少到29MB。

感谢您提供的所有帮助。