Sql-Server

SQL Server 中用於保留 id 塊以用於批量插入的慣用解決方案是什麼?

  • September 26, 2019

我有一個帶有標識列的表,我想保留一個可用於批量插入的 id 塊,同時允許插入仍然發生在該表中。

請注意,這是多個表的批量插入的一部分,其中那些其他表通過 FK 與這些 id 相關。因此,我需要阻止它們,以便我可以事先準備好關係。

我找到了一個解決方案,該解決方案通過在事務中鎖定表然後進行重新播種(這非常快)。但這對我來說看起來有點 hacky - 是否有一個普遍接受的模式來做到這一點?

create table dbo.test
(
   id bigint not null primary key identity(1,1),
   SomeColumn nvarchar(100) not null
)

這是阻止(騰出空間)一些 id 的程式碼:

declare @numRowsToMakeRoomFor int = 100

BEGIN TRANSACTION;

       SELECT  MAX(Id) FROM dbo.test WITH (  XLOCK, TABLOCK ) -- will exclusively lock the table whilst this tran is in progress, 
       --another instance of this query will not be able to pass this line until this instance commits

       --get the next id in the block to reserve
       DECLARE @firstId BIGINT = (SELECT IDENT_CURRENT( 'dbo.test' )  +1);

       --calculate the block range
       DECLARE @lastId BIGINT = @firstId + (@numRowsToMakeRoomFor -1);

       --reseed the table
       DBCC CHECKIDENT ('dbo.test',RESEED, @lastId);

COMMIT TRANSACTION;    

select @firstId;

我的程式碼是批量處理大約 1000 個塊的數據塊。我總共有大約 10 億行要插入。一切正常 - 數據庫不是瓶頸,批處理本身的計算成本很高,並且需要我添加幾台伺服器以並行執行,因此我需要在同時。

您可以使用過程(在 SQL Server 2012 中引入):

sp_sequence_get_range

要使用它,您需要創建一個 SEQUENCE 對象並將其用作預設值而不是 IDENTITY 列。

有一個例子:

CREATE SCHEMA Test ;  
GO  

CREATE SEQUENCE Test.RangeSeq  
   AS int   
   START WITH 1  
   INCREMENT BY 1  
   CACHE 10  
;

CREATE TABLE Test.ProcessEvents  
(  
   EventID int PRIMARY KEY CLUSTERED   
       DEFAULT (NEXT VALUE FOR Test.RangeSeq),  
   EventTime datetime NOT NULL DEFAULT (getdate()),  
   EventCode nvarchar(5) NOT NULL,  
   Description nvarchar(300) NULL  
) ;


DECLARE 
  @range_first_value_output sql_variant ;  

EXEC sp_sequence_get_range  
@sequence_name = N'Test.RangeSeq'  
, @range_size = 4  
, @range_first_value = @range_first_value_output OUTPUT ;

SELECT @range_first_value_output; 

文件:sp_sequence_get_range

引用自:https://dba.stackexchange.com/questions/249625