需要帮助理解为什么我会在执行过程中对具有相同锁定的代码进行肮脏读取



警告:这是旧的代码,我们知道我们应该使用实际的SQL序列,此处的目标是了解为什么一种方法与另一种方法提供不同的结果,因为我们不能只是此时更改为即时的序列。

问题:我们使用一个值的表作为序列对象(创建于2012年之前(来生成并返回需要保证的独特,增量的数字。存储的过程作品起作用,但正在搅动高CPU并在高载荷下引起严重的阻塞。修复看起来好像应该有效,但行不通。CPU和阻止新代码可以缓解,但我们似乎无法防止肮脏的读取,这导致了重复。

这是桌子的外观:

if OBJECT_ID('dbo.Sequence') is not null
    drop table dbo.Sequence;
create table dbo.Sequence (number int Primary Key); 
insert into dbo.Sequence values (1);
GO

此存储的Proc使用可序列化的锁定并获得准确的结果,但是由于阻塞而表现不佳:

CREATE OR ALTER PROC dbo.usp_GetSequence_Serializable @AddSomeNumber INT = 1 AS
BEGIN
declare @return int; --value to be returned and declared within sproc
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
Select @return = number from dbo.Sequence with (updlock) --get initial value plus one
Update dbo.Sequence set number = @return + @AddSomeNumber --increment it
COMMIT TRANSACTION
Select @return + @AddSomeNumber as nextid 
END
GO

这是我们更快的版本可以避免序列化,但是它会不时获得重复的值:

CREATE OR ALTER PROC dbo.usp_GetSequence_DefaultIsolationLevel @AddSomeNumber INT = 1 AS
BEGIN
declare @return int; --value to be returned and declared within sproc
update dbo.Sequence set @return = number = number + @AddSomeNumber --we tried interchanging various locking hints with no change in results (likely due to an exclusive being taken already) 
Select @return as nextid
END
GO

我们该怎么做才能获得第二个(不可隔离(proc的更快性能,同时避免重复生成的ID?

在您无法避免代码中的死锁时,将会出现大量数据库中的时间。该数据库将始终在所有事物上避免争夺。在这些罕见的特殊情况下,您可以使用SQL Server本身使用的高性能锁定 -> sp_getapplock((。您可以以这种方式构建代码,以便在存储过程中对关键部分的独家访问并序列化访问权限。当所有传统锁定提示失败时,SP_GETAPPLOCK绝对不是一件坏事。

DECLARE @MyTimeoutMiliseconds INT =5000--Wait only five seconds max then timeout
BEGIN TRAN
EXEC @LockRequestResult=SP_GETAPPLOCK 'MyCriticalWork','Exclusive','Transaction',@MyTimeoutMiliseconds
IF(@LockRequestResult>=0)BEGIN
            /*
            DO YOUR CRITICAL READS AND WRITES HERE
            You may prefer try finally to release
            */
    COMMIT TRAN -- <--Releases the lock!
END ELSE
    ROLLBACK TRAN --<--Releases the lock!

最新更新