需要单独的事务,而不是嵌套的事务[sqlserver]

yyyllmsg  于 2022-10-22  发布在  其他
关注(0)|答案(1)|浏览(109)

(代码在底部,这是在SQL Server 2019上)
我有一个创建月度报表的脚本有问题。脚本很长,单个事务处理每个发票可能需要几秒钟。由于服务器本身利用率不足,我试图将这一个脚本拆分为几个可以同时运行的脚本,每个脚本运行客户记录的一部分并生成语句。
问题是,生成ID的过程碰到了一个非常小的表,并导致了死锁。从Ticker获取ID的第一个进程会获取一个锁,并在语句完成之前不会释放它,其中一些过程可能需要一分钟以上才能完成。这将创建一个巨大的锁,使每个人都无法更新特定的ID,直到进程完成。这一直是EOM计费过程中的一个问题,试图将其拆分为多个进程只会使情况变得更糟。
我正在尝试找到一种方法,将此表作为单独的事务进行更新,以便在更新时立即释放锁,而不是等待漫长的过程完成。我不需要这些ID是连续的,所以我不在乎ID是否在处理过程中被其他线程抓取。我只需要以这样的方式获取一个ID,即它不会强制其他所有事情都等到所有事情都完成,而只需锁定该行,以便单独更新该表,并且在外部事务完成之前不要保持锁定。
有什么想法吗?

CREATE TABLE [dbo].[Ticker](
    [DocType] [char](4) NOT NULL,
    [NextDocID] [int] NOT NULL,
    [RowID] [int] IDENTITY(1,1) NOT NULL,
    [Prefix] [varchar](8) NULL,
    [Size] [tinyint] NULL,
    [Description] [varchar](100) NULL,
 CONSTRAINT [PK_TICKER] PRIMARY KEY NONCLUSTERED 
(
    [DocType] ASC
)
)
INSERT  [dbo].[Ticker]
           ([DocType]
           ,[NextDocID]
           ,[Prefix]
           ,[Size]
           ,[Description])
     VALUES
           ('CHRG'
           ,50
           ,'CHRG'
           ,11
           ,'Charge Records')

go
go
CREATE proc [dbo].[GetNextChargeID]
    @DocID char(15) = '' OUTPUT
as

set nocount on

/*DESCRIPTION: This proc will update the CHRG ticker and return the full
               15 character document value*/
begin
BEGIN TRANSACTION
update Ticker WITH (ROWLOCK) set NextDocID = NextDocID + 1, @DocID = NextDocID
    where DocType = 'CHRG' 

select @DocID = 'CHRG' + replicate('0', 11 - len(rtrim(@DocID))) + @DocID

COMMIT TRANSACTION
end
GO
/* run a copy of this in two windows*/
begin tran
exec GinormousTran
waitfor delay '00:00:20'
commit;
o8x7eapl

o8x7eapl1#

您的选择是
1.停止更新表以生成密钥。相反,为每个DocType创建一个单独的序列,并使用该序列生成密钥。
1.使用SQL CLR或链接服务器模拟“自治事务”

相关问题