tsql: хранимая процедура и блокировка строк - PullRequest
3 голосов
/ 08 августа 2011

У меня есть параллелизм в многопользовательской системе и хранимая процедура, как показано ниже:

CREATE PROCEDURE dbo.GetWorkitemID
AS
DECLARE @workitem int;

UPDATE workqueue
SET status = 'InProcess', @workitem = workitemid
WHERE workitemid = (SELECT TOP 1 workitemid
FROM workqueue WITH (ROWLOCK,UPDLOCK,READPAST)
WHERE status = 'New' ORDER BY workitemid)

SELECT @workitem

GO

Обновляет статус отдельной записи с «Новый» на «InProcess» и возвращает идентификатор записи.

Вопросы заключаются в следующем: Должен ли я использовать эту хранимую процедуру в области транзакций, чтобы включить ROWLOCK, UPDLOCK и т. Д.?Это обязательно?И второе: действительно ли это потокобезопасно и гарантирует уникальность?

Ответы [ 3 ]

2 голосов
/ 08 августа 2011

Должен ли я использовать эту хранимую процедуру в области транзакции ...

Каждый оператор DML в SQL выполняется в контексте транзакции, независимо от того, открыта она или нет.По умолчанию при выполнении каждой инструкции сервер SQL открывает транзакцию, если она не открыта, выполняет инструкцию, а затем фиксирует транзакцию (если ошибки не возникли) или откатывает ее.

С учетом оговоркиупоминание @Filip (что по-прежнему нет гарантии порядка, в котором элементы будут выбраны), это будет безопасно, и каждый вызов будет возвращать отдельную строку, если она доступна и не заблокирована.

2 голосов
/ 08 августа 2011

Edit:

В качестве контрпримера к Филиппу Де Восу

Обратите внимание на использование индекса покрытия и UPDLOCK, а не XLOCK и тот же запрос

DROP table locktest
create table locktest (id int, workitem int, status varchar(50))
insert into locktest (id, workitem) values (1, 1), (2,2), (3,3)
create index ix_test2 on locktest(workitem) INCLUDE (id, status)

--When I run this on one connection
begin tran 
select top (1) id, status 
from locktest with (rowlock, updlock, readpast) 
ORDER BY workitem

... я получаю ожидаемые результаты в другом соединении с тем же запросом

1 голос
/ 08 августа 2011

Это не надежно.Потому что подсказки блокировки, которые вы дали, это просто подсказки блокировки.Кроме того, в зависимости от способа индексации таблицы результаты могут сильно отличаться.

Например:

create table test (id int, workitem int, status varchar(50))
insert into test (id, workitem) values (1, 1), (2,2), (3,3)
create index ix_test on test(workitem)

Когда я запускаю это на одном соединении

begin tran 
select * from test with (rowlock, xlock, holdlock) where workitem = 1

И я запускаю это на втором соединении:

select top (1) * from test with (rowlock, readpast) order by workitem

Это возвращает:

workitem
--------
3 

То же самое, если я делаю:

update top (1) test with (rowlock, readpast)
set status = 'Proc' 
output inserted.workitem

Итак, вы можете использоватьэто для одновременного получения того, что вам нужно, но это не надежный способ одновременной обработки в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...