我们有许多数据库,它们在其中一个表中存储了 10 到 100 GB 的数据。它包含图像数据。问题是许多这些数据库的创建不正确。基本上主键实际上不是主键。是使用可空列上的唯一索引创建的。其中一些将 int 作为主键而不是 bigint。
所以我们一直在慢慢地检查和修复这些数据库。它们在 SQL Server 2000 到 SQL Server 2008 上运行,尽管大多数有主键问题的都在 SQL Server 2000 上。问题是,我们不想在转换表时将数据库锁定一整天。我们经历了几种策略:
INSERT INTO %s
SELECT TOP 100 Source.*
FROM %s AS Source WITH (NOLOCK)
LEFT OUTER JOIN %s AS Target WITH (NOLOCK) ON Source.DocumentID = Target.DocumentID
WHERE Target.DocumentID IS NULL
ORDER BY Source.DocumentID
那么问题来了,有没有一种可以高效且可恢复的方式复制批量数据的选项?它不一定是 100% 准确,只要它完成了 99% 的工作,我们总是可以在最后返回并修复任何差异。
最佳答案
加入是问题所在。不要那样做。只需使用当前的聚集索引,使用一些合理的间隔循环遍历当前表。就像是:
Declare @idrange int;
Set @idrange = 1;
WHILE @idrange < 10000000
INSERT INTO Destination
SELECT *
FROM Source
WHERE DocumentID between @idrange and @idrange + 999
ORDER BY Source.DocumentID
Set @idrange = @idrange + 1000
End
请注意,为了获得最佳速度,请从目标表中删除所有索引(包括聚集索引),然后在插入所有行后添加索引。
编辑 :更改范围间隔以防止重叠(因为 BETWEEN 包括端点)
最后一个澄清:我的示例脚本的总体要点是,您只想以某种合理的顺序遍历当前记录,并将它们分批放入新表中。没有理由每次都继续检查目标表,因为您应该已经知道在那里放了什么,还剩下什么。大多数时候,使用聚集索引(如果有)是有意义的,因为这意味着它可以遍历表的物理顺序,而无需进行书签查找。如果该表没有簇,那么就使用最有意义的(可能是你的 PK)。
关于sql-server-2000 - 更改 100GB 表的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3702701/