【发布时间】:2013-12-20 00:25:40
【问题描述】:
我有一个 SP,它使用 CURSOR 和 FETCH NEXT 更新表中的价格。
光标的查询是一个简单的“选择”,而不是 WHERE - 我加入了一个函数,该函数会带来所有相关的用户 ID。
现在,由于我的 SP 更新了很多不同的表(附件只是其中的一部分),并且在每次更新中我都使用了 users 函数的 JOIN - 我想节省一些时间,并带来用户只列出一次,在 SP 的开头。
如果我加入我的临时表(@t,其中包含用户 ID),我会得到一个无限循环。 最终价格将是无限的。
但是 - 如果我加入函数本身,而不是应该在其中具有完全相同值的临时表,一切都很好。
我评论了有问题的 JOIN。
-- This is my main object, who "holds" a lot of users
DECLARE @DistID INT = 123
DECLARE @t TABLE
(MainDistID int,
DistID int,
UserID int)
INSERT INTO @t
SELECT MainDistID,
DistID,
UserID
FROM [MyScheme].[FnGetAllDistAndUsers] (@DistID)
DECLARE @Bid INT -- Will contain the ID we need to update
DECLARE c CURSOR LOCAL FOR
SELECT ID
FROM BillingDetails AS bd
-- BOTH JOINS SHOULD BE THE SAME:
--JOIN @t AS GUsers -- Infinite loop...
-- ON bd.UserID = GUsers.UserID
JOIN [MyScheme].[FnGetAllDistAndUsers] (@DistID) AS GUsers -- NO infinite loop
ON bd.UserID = GUsers.UserID
OPEN c
FETCH NEXT FROM c
INTO @Bid
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE MyTable
SET Price = Price * 2
WHERE MyTableID = @Bid
FETCH NEXT FROM c
INTO @Bid
END
谢谢!
【问题讨论】:
-
我很确定您不需要使用光标。
-
米奇,我使用游标来防止锁定(更新 100,000 行)。这是我数据库中最繁忙的表。我不将游标用于我的 SP 中的所有其他更新。所以我确实需要使用它。谢谢。
-
您是否尝试过在循环中使用 PRINT 运行它以了解哪里出错了?你可以折腾一个额外的 WHERE 条件,例如
UserId % 100 = 42减少分析行数。 -
如果您的意思是“我正在批量执行以防止阻塞”,请参阅我的第一条评论。
-
Mitch,我运行了 2 个测试: 1. 使用用户 ID 的 JOIN 在一个批次/操作中更新所有 100,000 行。在 35 秒内完成,但锁定了表格,我无法从中选择/插入。 2. 使用游标一次更新一行并获取下一个。 5 分钟内完成(是),但没有锁定桌子。如何在不锁定表(并且不使用光标)的情况下进行此更新?
标签: sql-server tsql cursor infinite-loop