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:添加列会比预期增加表大小的主要内容,如果未能解决你的问题,请参考以下文章

Sql Server优化---统计信息维护策略

sql server如何将字段添加到第一列

请教:sql server中如何设置新添加的列为第一列

在SQL Server中为啥不建议使用Not In子查询

sql server新增字段语句

SQL Server 插入多行并增加一个 int 列