将具有默认值的列添加到大表

时间:2013-11-19 23:48:04

标签: sql sql-server performance

我有一张40mil记录的表格。我需要在该表中添加一个新的INT NOT NULL列,默认值为= 0

使用以下内容添加此列时:

ALTER TABLE myTable ADD NewColumnID int NOT NULL CONSTRAINT DF_Constraint DEFAULT 0

它将所有记录的NewColumnID设置为0。在我们的具有40mil记录的prod表上运行此查询时,这需要很长时间吗?因为我知道做以下事情需要非常长的时间:

UPDATE myTable SET NewColumnID = 0

6 个答案:

答案 0 :(得分:3)

主要问题是这需要写入每一行,这些行被大量记录为单个事务。最小化对日志的影响的一种方法(如果您的日志文件中没有愚蠢的10%自动增长设置,这种方法效果最好)是尽可能地分解工作:

  1. 添加NULlable列:

    ALTER TABLE dbo.myTable 
     ADD NewColumnID INT CONSTRAINT DF_Constraint DEFAULT 0;
    
  2. 批量更新行,一次说10K行(这样可以最大限度地减少日志影响 - 请参阅this blog post for background):

    BEGIN TRANSACTION;
    SELECT 1;
    WHILE @@ROWCOUNT > 0
    BEGIN
      COMMIT TRANSACTION;
      BEGIN TRANSACTION;
    
      UPDATE TOP (10000) dbo.myTable SET NewColumnID = 0;
    END
    COMMIT TRANSACTION;
    
  3. 添加检查约束(see these answers for more detail):

    ALTER TABLE dbo.myTable WITH CHECK
      ADD CONSTRAINT NewCol_Not_Null
      CHECK (NewColumnID IS NOT NULL); 
    

    您可以在此使用NOCHECK节省一些时间,但as Martin explained in his answer可以节省一段时间,这可能会让您在长期内感到头疼。

  4. 这在this previous question中得到了解决,但是那里接受的答案使用了NOCHECK而没有关于不受信任的约束如何影响执行计划的任何免责声明。

答案 1 :(得分:1)

更新查询运行所需的时间完全取决于底层硬件,此处没有人能给您一个明确的答案。更新4000万条记录可能需要数秒或数天,具体取决于硬件......具体而言,机器内存量和硬盘速度。

也就是说,如果您所显示的简单更新需要“非常长时间”,那么alter语句可能需要更长或更长时间。

答案 2 :(得分:0)

如果您可以将NULL视为0,则可以将其添加为稀疏列 - 那么在您实际添加值之前,不需要添加任何存储:

ALTER TABLE myTable 
ADD NewColumnID int SPARSE NULL 
CONSTRAINT DF_Constraint

否则Aaron的方法可能是最不具侵入性的 - 它仍然需要很长时间,但可以“在线”完成

答案 3 :(得分:0)

不,从SQL Server 2012开始,这将是即时的:

  

在SQL Server 2012之前添加新的非NULLable列时   发生大小数据操作的现有表的默认值:   表中的每一行都会更新,以添加新的默认值   柱。对于小桌子,这是微不足道的,但对于大桌子   这可能是完全禁止操作的问题。   但从SQL Server 2012开始,在大多数情况下,操作是   瞬时:只更改表元数据,没有行   更新。

http://rusanu.com/2011/07/13/online-non-null-with-values-column-add-in-sql-server-11/

答案 4 :(得分:-1)

感谢Aaron的详细方法,但我做了一个快速测试,简单的方法是做以下事情:

一些背景知识。我正在向现有的大表添加CompanyID。 ID指的是记录所属的公司。默认值为0.但由于这是进入现有客户prod数据库,因此他们的公司ID为1.我们为所有客户提供了一个通用的升级脚本,对这个特定客户稍微修改了这个脚本,从而产生了显着的性能改进。

INSTEAD OF:

ALTER TABLE myTable ADD CompanyID int NOT NULL CONSTRAINT DF_Constraint DEFAULT 0 (takes about 1min to complete)
UPDATE myTable SET CompanyID = 1 (will take over an hour)

我只是这样做:

ALTER TABLE myTable ADD CompanyID int NOT NULL CONSTRAINT DF_Constraint DEFAULT 1 (takes about 1min to complete)

然后将默认值设置回0.现在,对于所有记录,表格的CompanyID = 1。 BOOM!

答案 5 :(得分:-1)

最好删除列并再次添加。这样可以最大程度地减少所有开销,例如表上的任何触发器或约束。

相关问题