SQL Server-为什么在更改表中向表添加可空列会导致重建

问题描述

我们有一个250GB的DB,其中包含一个180GB的表(5500万行,可能是550列),我们通过在表末添加24个新的空白列;

ALTER TABLE [Rpt].[tblHoldings]      
ADD 
    [rating01AgencyCode] VARCHAR (50) NULL,         
    [rating01TypeCode]   VARCHAR (50) NULL,         
    [rating01Code]       VARCHAR (50) NULL,         
    [rating01score]      FLOAT (53)   NULL,         
    [rating02AgencyCode] VARCHAR (50) NULL,         
    [rating02TypeCode]   VARCHAR (50) NULL,         
    [rating02Code]       VARCHAR (50) NULL,         
    [rating02score]      FLOAT (53)   NULL,         
    [rating03AgencyCode] VARCHAR (50) NULL,         
    [rating03TypeCode]   VARCHAR (50) NULL,         
    [rating03Code]       VARCHAR (50) NULL,         
    [rating03score]      FLOAT (53)   NULL,         
    [rating04AgencyCode] VARCHAR (50) NULL,         
    [rating04TypeCode]   VARCHAR (50) NULL,         
    [rating04Code]       VARCHAR (50) NULL,         
    [rating04score]      FLOAT (53)   NULL,         
    [rating05AgencyCode] VARCHAR (50) NULL,         
    [rating05TypeCode]   VARCHAR (50) NULL,         
    [rating05Code]       VARCHAR (50) NULL,         
    [rating05score]      FLOAT (53)   NULL,         
    [rating06AgencyCode] VARCHAR (50) NULL,         
    [rating06TypeCode]   VARCHAR (50) NULL,         
    [rating06Code]       VARCHAR (50) NULL,         
    [rating06score]      FLOAT (53)   NULL ;

我们过去使用相同的方法在此表中添加了75个列,而仅花费了几秒钟。这次在Elastic Azure Pool(800 EDTU)中,我将数据库最大大小设置为 500GB,并且在运行上述查询 6小时后,它的空间不足。 / p>

这似乎是在后台或更多间接地重建表(即使这是不涉及直接复制表的Tsql调用)-更奇怪的是,即使它重建了表,为什么还需要更多比另一个〜180 GB(即250GB +另外180GB应该小于500GB)

注意:这些不是具有任何认值或上面未显示的其他内容的索引列

我对发现这是否是预期的行为非常感兴趣。是否有任何条件在表末尾添加可为空的列以触发重建,如果是这样的话,是什么条件迫使这样做以及为什么它比原始表消耗更多的钱?

解决方法

如果行宽度的总和大于页面大小(大约8KB),则可能需要做一些工作才能尝试使模式适合页面。在所有情况下,固定大小的字段(例如float)都必须在页面上。 SQL确实具有接受一些可变大小的字段并在某些情况下将它们放下的功能。也许这可以解释sizeof(data)操作,尽管实际上只是推测而没有完整的副本。

可能发生的情况是,DDL操作将需要修改所有行以完成该操作。这不是“重建”,因为您可以通过构建一个新索引并将所有数据移至该索引来重建索引。 SQL确实具有在可能的情况下具有“联机”模式操作的逻辑,这意味着如果我们可以避免执行sizeof(data)操作,则可以这样做。这包括添加未定义默认值的列(因此,我们不必触摸表中的所有现有行即可为这些现有行设置新的默认值)。但是,对此有一些限制。请参阅此页面上的WITH(ONLINE = ON)语法的在线文档:

https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-table-transact-sql?view=sql-server-ver15