我们有许多数据库可以在其中一个表中存储10到100千兆字节的数据。它包含图像数据。问题是很多这些数据库都是不正确地创建的。基本上,主键实际上不是主键。在可空列上使用唯一索引创建。其中一些有一个int作为主键而不是bigint。
所以我们一直在慢慢地修复这些数据库。它们通过SQL Server 2008在SQL Server 2000上运行,尽管大多数具有主键问题的都在SQL Server 2000上。问题是,我们不希望在转换表时将数据库锁定一整天。我们已经完成了几个策略:
告诉SQL Server直接更改列类型。这会锁定桌子直到它完成,并且在很多情况下将它放置一夜之后,它仍然没有完成。
一次性将所有图像插入新表中。这更容易被中断,但整个表基本上都会在此过程中写入日志文件。
在目标表中不存在行的情况下插入100行。好处是,他们可以继续使用数据库进行此操作(性能大幅提升),并且可以在任何时候任意停止和重新启动,并且它可以防止100GB +日志文件。这就是我们目前正在做的事情,但是随着目标表变得越来越大,找到不存在的前100行变得非常慢。 UPDATE STATISTICS和DBCC INDEXDEFRAG帮助相当大,但在最近的尝试中,我们达到了这一点,一次只有100张图像坐在那里没有响应。
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%的工作。
答案 0 :(得分:3)
加入是问题所在。不要那样做。只需使用当前聚簇索引,使用一些合理的时间间隔遍历当前表。类似的东西:
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)。