游标和存储过程优化
以下存储过程是前一段时间编写的,现在需要修改。
联系不上原开发者,我看了一下。对我来说这个过程似乎过于复杂。难道不能通过简单的更新来完成吗?谁能证明这里使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你是对的 - 这看起来像“过程 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.
如果涉及的触发器会在多个更新的行上爆炸,那么您将需要迭代。但这仍然不能证明使用实际的游标是合理的。
执行单个更新会导致行锁,而不是基于集的更新可能导致的页锁或表锁。由于您正在缩小事务,因此程序员可能会尝试消除由大更新引起的死锁。
注意:我并不提倡这种方法,我只是提出原因。
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.
简单地看一下,我根本看不出有任何理由不通过一次更新来完成此操作。也许(这是一个maaaaaybe)如果有太多记录需要更新,那么这可能是一个原因。无论如何,我会简单地更改它:
编辑以下@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:
edited following @Martin Smith comment
如果一次运行一条记录太慢,并且单个更新会导致阻塞和事务日志增长过多,则第三种替代方法是批处理。使用基于集合的查询,但一次运行 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).