在SQL Server数据库中将一列复制到另一列超过十亿行

Adi*_*dit 9 sql t-sql sql-server sql-server-2005 large-data-volumes

数据库:SQL Server 2005

问题:将值从一列复制到同一个表中的另一列,其中包含十亿+行.

test_table (int id, bigint bigid)
Run Code Online (Sandbox Code Playgroud)

事情尝试1:更新查询

update test_table set bigid = id 
Run Code Online (Sandbox Code Playgroud)

填充事务日志并由于缺少事务日志空间而回滚.

尝试2 - 以下行的程序

set nocount on
set rowcount = 500000
while @rowcount > 0
begin
 update test_table set bigid = id where bigid is null
 set @rowcount = @@rowcount
 set @rowupdated = @rowsupdated + @rowcount
end
print @rowsupdated
Run Code Online (Sandbox Code Playgroud)

上述过程随着进行而开始减慢.

尝试3 - 创建游标以进行更新.

通常不鼓励SQL Server文档,这种方法一次更新一行,这太耗时了.

是否有一种方法可以加速将值从一列复制到另一列.基本上我正在寻找一些"魔术"关键字或逻辑,它将允许更新查询按顺序一次撕掉50亿行.

任何提示,指针将非常感激.

OMG*_*ies 5

UPDATE语句中使用TOP :

UPDATE TOP (@row_limit) dbo.test_table
   SET bigid = id 
 WHERE bigid IS NULL
Run Code Online (Sandbox Code Playgroud)


Bra*_*adC 5

我猜想您即将达到21亿个列的人工键上INT数据类型的限制。是的,那很痛苦。比实际达到该限制之前要容易得多,而在尝试解决此问题时,生产就会关闭:)

无论如何,这里的一些想法是可行的。不过,让我们谈谈速度,效率,索引和日志大小。

对数增长

该日志最初被炸毁是因为它试图一次提交所有2b行。其他帖子中有关“分块”的建议将起作用,但是可能无法完全解决日志问题。

如果数据库处于“简单”模式,您会没事的(每次批处理后日志将重新使用)。如果数据库处于FULL或BULK_LOGGED恢复模式,则必须在运行操作期间频繁运行日志备份,以便SQL可以重新使用日志空间。这可能意味着在此期间增加备份频率,或者仅在运行时监视日志使用情况。

索引和速度

where bigid is null随着表的填充,所有答案都会放慢速度,因为(大概)新的BIGID字段上没有索引。您可以(当然)仅在BIGID上添加索引,但是我不认为这是正确的答案。

键(双关语意味)是我的假设,即原始ID字段可能是主键或聚集索引,或两者兼有。在这种情况下,让我们利用这一事实,对Jess的想法进行一些修改:

set @counter = 1
while @counter < 2000000000 --or whatever
begin
  update test_table set bigid = id 
  where id between @counter and (@counter + 499999) --BETWEEN is inclusive
  set @counter = @counter + 500000
end
Run Code Online (Sandbox Code Playgroud)

由于ID上已有索引,因此这应该非常快。

无论如何,实际上没有必要进行ISNULL检查,间隔上的我(-1)也不是。如果我们在两次调用之间重复一些行,那没什么大不了的。