SQL Server:添加列会比预期增加表大小
Posted
技术标签:
【中文标题】SQL Server:添加列会比预期增加表大小【英文标题】:SQL Server: Adding a column increases table size more than expected 【发布时间】:2015-08-07 21:29:29 【问题描述】:要迁移到新架构,我对表做了两件事:
-
将 VARCHAR 列更改为 NVARCHAR
添加 BIGINT 列
为了测试这对大小的影响,我生成了 180,000 行。我要更改的 VARCHAR 列在每一行都设置为 null。
以下是 sp_spaceused 的结果(所有大小以 KB 为单位):
rows reserved data index_size unused
---- -------- ---- ---------- ------
before 180000 110976 43168 67288 520
after 180000 120320 52536 67296 488
因此数据增长了 9MB 以上。我原本预计它只会增长 1.4 MB,因为我添加了一个 8 字节的数字列。
如果我只是创建表并生成数据,大小看起来更像我的预期:
rows reserved data index_size unused
---- -------- ---- ---------- ------
180000 117760 46184 71352 224
那么添加一个列是否会导致 sp_spaceused 报告比实际添加的数据更多的正在使用的数据?
【问题讨论】:
表定义是什么?你是如何生成这些行的? 您之后是否重建了聚集索引?通过在每行上需要额外的八个字节,您可能会得到各种页面拆分。检查使用的页数,我敢打赌它增加了不少。 不会将VARCHAR
更改为NVARCHAR
使字符串长度加倍吗?这也可能导致一些转发记录。
@mustaccio 他们说所有的值都是空的,所以这将是零长度。转发的记录仅适用于堆。
【参考方案1】:
没有人真正解释为什么会发生这种情况。 Dave Gugg 给了你一个很好的提示。
SQL 将行存储在页面中。 (大约 8K,但不完全)并且一行必须适合一页(不是真的,鉴于 long varchars 可以使用指针存储在单独的页面上 - 但你的都是空的,所以现在让我们忽略它。)
页面以簇的形式分配。
当您插入行时,您有一组漂亮的新页面和集群,并且行都整齐。
当您进行任何更改时,尤其是像添加列这样的更改时,SQL 必须更新每一行。
更新任何行都需要更改一页或多页 - 因为更改后的行可能不再适合同一页。事实上,由于回滚的工作方式,我认为有时 SQL 实际上喜欢将更改的行移动到新页面。
因此,您紧密排列的行分散并占用了更多页面和集群。随着时间的推移,发生了许多变化,这平均下来了。并非每次更新都会添加页面 - 但添加一列会使每一行变得更大,并且不太可能与之前的邻居相匹配。
我们无法更具体,因为您没有提供架构。如果您有,我们会了解您更改前后每页的预期行数。
【讨论】:
很好的解释。谢谢。【参考方案2】:正如大家所料,问题在于碎片化。在生成数据并使用附加列迁移到新模式后,我使用 sys.dm_db_index_physical_stats 检查了碎片。聚集索引的 avg_fragmentation_in_percent 为 98.8%。重建将其减少到 0.4%,并且 sp_spaceused 显示数据大小从 52MB 下降到 29MB。
感谢大家的大力帮助。
【讨论】:
以上是关于SQL Server:添加列会比预期增加表大小的主要内容,如果未能解决你的问题,请参考以下文章