问题
对下面的语句应用锁有什么好处?
同样,如果不包含这些提示,我们会看到什么问题?i、 e.他们是否会阻止比赛状态,提高表现,或者其他什么?询问,因为他们可能被包括在内,以防止一些我没有考虑的问题,而不是我假设的种族状况。
注意:这是从这里提出的一个问题中溢出的:
SQL Threadsafe UPDATE TOP 1 for FIFO Queue
有关声明
WITH nextRecordToProcess AS
(
SELECT TOP(1) Id, StatusId
FROM DemoQueue
WHERE StatusId = 1
ORDER BY DateSubmitted, Id
)
UPDATE nextRecordToProcess
SET StatusId = 2
OUTPUT Inserted.Id
要求
-
SQL用于从队列中检索未处理的记录。
-
要获取的记录应该是队列中状态为Ready(StatusId=1)的第一条记录。
-
可能有多个工作进程/会话正在处理来自此队列的消息。
-
我们希望确保队列中的每个记录只拾取一次(即由单个工作进程拾取),并且每个工作进程按照消息在队列中出现的顺序处理消息。
-
一个工作人员的工作速度可以比另一个工作人员快(即,如果工作人员A拾取记录1,则工作人员B拾取记录2,如果工作人员B在工作人员A完成记录1之前完成记录2的处理,则可以)。我们只关心在收集记录的情况下。
-
没有正在进行的交易;i、 e.我们只想从队列中提取记录;我们不需要一直锁定它,直到我们回来从
Processing
到
Processed
.
上下文的其他SQL:
CREATE TABLE Statuses
(
Id SMALLINT NOT NULL PRIMARY KEY CLUSTERED
, Name NVARCHAR(32) NOT NULL UNIQUE
)
GO
INSERT Statuses (Id, Name)
VALUES (0,'Draft')
, (1,'Ready')
, (2,'Processing')
, (3,'Processed')
, (4,'Error')
GO
CREATE TABLE DemoQueue
(
Id BIGINT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
, StatusId SMALLINT NOT NULL FOREIGN KEY REFERENCES Statuses(Id)
, DateSubmitted DATETIME
)
GO
建议的声明
在讨论队列的各种博客中,以及引发此讨论的问题中,建议将上述语句更改为包含锁提示,如下所示:
WITH nextRecordToProcess AS
(
SELECT TOP(1) Id, StatusId
FROM DemoQueue WITH (UPDLOCK, ROWLOCK, READPAST)
WHERE StatusId = 1
ORDER BY DateSubmitted, Id
)
UPDATE nextRecordToProcess
SET StatusId = 2
OUTPUT Inserted.Id
我的理解
我知道需要锁定这些提示的好处是:
-
UPDLOCK:因为我们正在选择要更新其状态的记录,所以我们需要确保在读取该记录之后但在更新之前读取该记录的任何其他会话都无法读取要更新的记录(或者更确切地说,这样的语句必须等到我们执行了更新并释放了锁之后,其他会话才能看到我们的记录及其新值)。
-
ROWLOCK:当我们锁定记录时,我们希望确保我们的锁定只影响我们锁定的行;i、 e.由于我们不需要锁定许多资源/我们不想影响其他进程/我们希望其他会话能够读取队列中的下一个可用项目,即使该项目与我们锁定的记录位于同一页面中。
-
READPAST:如果另一个会话已经在从队列中读取项目,而不是等待该会话释放其锁定,那么我们的会话应该选择队列中的下一个可用(未锁定)记录。
i、 e.如果我们运行以下代码,我认为这是有意义的:
DECLARE @nextRecordToProcess BIGINT
BEGIN TRANSACTION
SELECT TOP (1) @nextRecordToProcess = Id
FROM DemoQueue WITH (UPDLOCK, ROWLOCK, READPAST)
WHERE StatusId = 1
ORDER BY DateSubmitted, Id
UPDATE DemoQueue
SET StatusId = 2
WHERE Id = @nextRecordToProcess
COMMIT TRANSACTION
然而,当select和update出现在同一条语句中时,我会假设没有其他会话可以在我们会话的read&使现代化因此,不需要显式锁定提示。
我是否从根本上误解了锁的工作原理;或者这些提示的建议是否与其他类似但不同的用例相关?