(代码在底部,这是在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;
1条答案
按热度按时间o8x7eapl1#
您的选择是
1.停止更新表以生成密钥。相反,为每个DocType创建一个单独的序列,并使用该序列生成密钥。
1.使用SQL CLR或链接服务器模拟“自治事务”