我们正在尝试将约6.5亿条记录迁移到同一台服务器上的新数据库,并且目前正在测试的两种替代方案之间的性能差异极大。第一个脚本位于下面,它使用带有开始和结束时间间隔的引用表以及用于构建insert语句的游标。另一种方法是使用相同的参考表来实际创建~26000个唯一插入语句并执行它们。
选项1(运行16小时,仅移动约占总记录的2%):
--Declare scoped variables
DECLARE @migStart datetime, @migEnd datetime;
--Set up cursor for reference intervals
DECLARE migCur CURSOR FOR
SELECT dttm_interval_start, dttm_interval_end
FROM DBA.dbo.intervalReference
WHERE complete = 0
ORDER BY dttm_interval_start;
OPEN migCur;
--Initialize the cursor
FETCH NEXT FROM migCur
INTO @migStart, @migEnd;
--Iterate through the reference intervals
WHILE (@@FETCH_STATUS = 0)
BEGIN
--Move the records as >= start and < end
INSERT INTO NEW.dbo.new_log(field1, field2, field3, ......, field19)
SELECT field1, field2, field3, ......, field19
FROM OLD.dbo.old_log
WHERE log_dt >= @migStart and log_dt < @migEnd;
--Mark the interval as done, capture record count
UPDATE DBA.dbo.intervalReference
SET complete = 1, records = @@ROWCOUNT
WHERE dttm_interval_start = @migStart and dttm_interval_end = @migEnd;
--Fetch the next cursor item
FETCH NEXT FROM migCur
INTO @migStart, @migEnd;
END;
CLOSE migCur;
DEALLOCATE migCur;
GO
选项2(我们的计算预计这一项在约65小时内完成。其中约有26000个,每个都涵盖不同的时间间隔。)
INSERT INTO new.dbo.new_log(field1, field2, field3, ......, field19)
SELECT field1, field2, field3, ......, field19
FROM OLD.dbo.old_log
WHERE log_dt >= '2013-02-17 12:00:00.000' and log_dt < '2013-02-17 14:00:00.000';
我理解游标不是高性能的,但它们真的太糟糕了,我甚至无法使用它们来遍历引用表来控制查询边界吗?
我已经查看了脚本与各个插入语句的执行计划,并且插入步骤中选项1的预期记录数量约为1.9亿,超过了我们计算的140k记录批量大小的时间间隔。可能是统计数据误导了引擎关于优化的最佳方式吗?
循环中的查询是否得到优化?
为什么选项2的性能比选项1高得多?