【发布时间】:2010-10-12 14:59:23
【问题描述】:
我有一个存储过程,它使用 FAST_FORWARD 游标按时间顺序循环一组约 300k 记录,并根据许多运行变量和标志的状态将它们分配给声明集,部分实现为表变量。我已经对如何基于集合进行了很多思考,但我就是做不到。所以我坚持使用游标方法,需要优化这段代码。
我注意到,前 10% 的进度加载和处理速度非常快(2000 行/秒),接近 20% 的进度已减慢到约 300 行/秒,最后减慢到大约 60 行/秒。
IMO 这可能是由于 4 个原因:
- 光标变慢了,我认为使用 FAST_FORWARD 光标不太可能
- 处理速度变慢。对于我的“组”,我使用插入、更新和删除的表变量。在任何给定时刻都有最大值。这些变量中大约有 10 行。
- 插入目标表的速度变慢。我不明白为什么会这样,我没有在它们上定义触发器,它们只是普通的表。
- 邪恶的魔法
那个或者我的百分比计数器坏了:
SET @curprogress = @curprogress + 1
IF (@curprogress - ((@totprogress / 100) * (FLOOR(@curprogress * 100 / @totprogress)))) BETWEEN 0 AND 1 BEGIN
SET @msg = CAST(FLOOR(@curprogress * 100 / @totprogress) AS VARCHAR)
RAISERROR('%s%s', 0, 1, @msg, '%...') WITH NOWAIT;
END
有没有人知道要查找什么以及如何继续加快此查询的速度?
我的代码的符号摘录:
WHILE....
-- Fetch new record to be assigned to one of the open declaration sets
FETCH NEXT INTO @row_field1, @row_field2....
IF (@flag2 = 1) AND ((@flag1 = 0) OR (@row_field1 <> @prevrow_field1))
BEGIN
-- Logging info: we are closing a child declaration set
INSERT INTO @logtable SELECT '--> LOG MESSAGE'
INSERT INTO @logtable
SELECT format_message(@row_field1, @calc_field2, field3...)
FROM @runningtable_sub S LEFT JOIN @runningtable_main M ON S.MainID = M.ID
-- Update enddate of parent
UPDATE M SET M.enddate = DATEADD(day,365,S.enddate)
FROM @runningtable_sub S
LEFT JOIN @runningtable_main M
ON S.MainID = M.ID
-- close and save child
INSERT INTO outputtable_main
SELECT @field1, COALESCE(Z.Field1,'NULL'), S.startdate, S.enddate,
M.Startdate, M.Enddate
FROM @runningtable_sub S
LEFT JOIN @runningtable_main M ON S.MainID = M.ID
-- delete child from running table
DELETE FROM @runningtable_sub WHERE S.enddate < @curdate
END
【问题讨论】:
标签: sql tsql sql-server-2008 cursor query-optimization