游标和存储过程优化

发布于 2024-12-18 11:58:08 字数 761 浏览 1 评论 0原文

以下存储过程是前一段时间编写的,现在需要修改。

联系不上原开发者,我看了一下。对我来说这个过程似乎过于复杂。难道不能通过简单的更新来完成吗?谁能证明这里使用 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

The following stored proc has been written some time ago and now requires modification.

Unable to contact the original developer, I had a look. To me this proc seems over-complicated. Couldn't it be done with a straightforward UPDATE? Can anyone justify the use of CURSOR here?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

土豪我们做朋友吧 2024-12-25 11:58:08

你是对的 - 这看起来像“过程 SQL”,来自可能不了解 SQL 和设置操作的人。

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

游标不是必需的,而且确实使存储过程过于复杂。

You are right - this looks like "procedural SQL", from someone who probably doesn't get SQL and set operations.

And converting this to a set based query should help performance.

A cursor is not needed and is indeed over complicating the stored procedure.

牛↙奶布丁 2024-12-25 11:58:08

如果涉及的触发器会在多个更新的行上爆炸,那么您将需要迭代。但这仍然不能证明使用实际的游标是合理的。

执行单个更新会导致行锁,而不是基于集的更新可能导致的页锁或表锁。由于您正在缩小事务,因此程序员可能会尝试消除由大更新引起的死锁。

注意:我并不提倡这种方法,我只是提出原因。

If there are triggers involved that would blow up on multiple updated rows, then you would want to iterate. But that would still not justify using an actual CURSOR.

Doing single updates would cause row locks and not page or table locks that a set based update could. Since you're making the transactions smaller, the programmer could have been attempted to remove deadlocks which were caused by a large update.

NOTE: I am not advocating this method, I am only suggesting reasons.

何以笙箫默 2024-12-25 11:58:08

简单地看一下,我根本看不出有任何理由不通过一次更新来完成此操作。也许(这是一个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评论

Simply looking at it, I don't see any reason at all why this isn't done on a single UPDATE. Maybe (and its a maaaaaybe) if there are too many records to update, then this could be a reason. In any case, I would simply change it with:

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

edited following @Martin Smith comment

小猫一只 2024-12-25 11:58:08

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

If running one record at a time is too slow and a single update causes blocking and too much growth of the transaction log, the third alternative is to batch process. Use a set-based query, but run it through a loop of 1000 records at a time (you may have to experiement to find the optimum size of the batch).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文