CREATE TABLE Test (
Id INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
Other VARCHAR(100))
GO
接下来我们插入十条测试数据
DECLARE @counter INT
SELECT @counter = 1
WHILE (@counter <= 10)
BEGIN
INSERT INTO Test
(Other)
SELECT 'other action' + CAST(@counter AS VARCHAR)
SELECT @counter = @counter + 1
END
接下来我们打开两个会话运行如下SQL语句:
DECLARE @queueid INT
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
此时我们看到打开的两个会话会同时处理相同的行。
DECLARE @queueid INT
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test WITH (updlock)
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
DECLARE @queueid INT
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test WITH (updlock)
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test WITH (UPDLOCK, READPAST)
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
通过UPDLOCK+READPAST结合使用将对于处理并发更新时,就像处理队列数据一样,但是不会造成阻塞,此时将给予我们最好的性能。我们结合上述所讲,来查询出数据并删除对应数据且,不会出现重复删除情况且不会导致阻塞,此时代码将变成如下:
SET NOCOUNT ON
DECLARE @queueid INT
WHILE (SELECT COUNT(*) FROM Test WITH (updlock, readpast)) >= 1
BEGIN
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test WITH (updlock, readpast)
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
END