游标和存储过程优化

时间:2011-11-29 14:43:44

标签: sql sql-server stored-procedures cursor query-optimization

以前的存储过程已经写好了,现在需要修改。

无法联系原始开发者,我看了一下。对我来说,这个过程似乎过于复杂。难道不能通过简单的UPDATE完成吗?任何人都可以在这里证明使用CURSOR吗?

ALTER PROCEDURE [settle_Stage1]
    @settleBatch int
AS

DECLARE @refDate datetime;
DECLARE @dd int;
DECLARE @uid int;

DECLARE trans_cursor CURSOR FOR 
SELECT uid, refDate FROM tblTransactions WHERE (settle IS NULL ) AND (state IN (  21, 31, 98, 99 ))
OPEN trans_cursor
FETCH FROM trans_cursor INTO @uid, @refDate
WHILE @@FETCH_STATUS = 0
   BEGIN
    SET @dd = DATEDIFF( day, @refDate, getDate())
    IF ( @dd >= '1' )
      BEGIN
        UPDATE tblTransactions
        SET settle = @settleBatch WHERE uid = @uid
      END
    FETCH FROM trans_cursor INTO @uid, @refDate
   END  
CLOSE trans_cursor
DEALLOCATE trans_cursor

4 个答案:

答案 0 :(得分:6)

你是对的 - 这似乎是“程序性SQL”,来自可能没有得到SQL并设置操作的人。

将此转换为基于集合的查询应有助于提高性能。

不需要游标,确实使存储过程复杂化。

答案 1 :(得分:4)

如果涉及的触发器会爆炸多个更新的行,那么您可能希望迭代。但这仍然不能证明使用实际的CURSOR。

执行单个更新会导致行锁定,而不会导致基于集合的更新可能导致的页锁或表锁定。由于你使事务变得更小,程序员可能已经尝试去除由大量更新引起的死锁。

注意:我不是在提倡这种方法,我只是在暗示理由。

答案 2 :(得分:4)

简单地看一下,我没有看到任何理由为什么在单个UPDATE上没有这样做。也许(和它的maaaaaybe)如果有太多的记录要更新,那么这可能是一个原因。无论如何,我只想改变它:

UPDATE tblTransactions
SET settle = @settleBatch
WHERE settle IS NULL 
AND [state] IN (21, 31, 98, 99)
AND DATEDIFF( day, refDate, getDate()) >= 1

编辑以下@Martin Smith评论

答案 3 :(得分:1)

如果一次运行一条记录太慢而且单个更新导致事务日志阻塞和过多增长,则第三种方法是批处理。使用基于集合的查询,但一次运行一次包含1000条记录的循环(您可能需要经验才能找到批次的最佳大小)。