我有一张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
答案 0 :(得分:3)
主要问题是这需要写入每一行,这些行被大量记录为单个事务。最小化对日志的影响的一种方法(如果您的日志文件中没有愚蠢的10%自动增长设置,这种方法效果最好)是尽可能地分解工作:
添加NULlable列:
ALTER TABLE dbo.myTable
ADD NewColumnID INT CONSTRAINT DF_Constraint DEFAULT 0;
批量更新行,一次说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;
添加检查约束(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可以节省一段时间,这可能会让您在长期内感到头疼。
这在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)
最好删除列并再次添加。这样可以最大程度地减少所有开销,例如表上的任何触发器或约束。