为什么这些脚本的性能如此不同?

时间:2015-03-26 15:58:35

标签: sql-server sql-server-2005

我们正在尝试将约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高得多?

0 个答案:

没有答案