SQL Server 中用于保留用于批量插入的 id 块的惯用解决方案是什么?

Dan*_*ars 8 sql-server identity sql-server-2016 bulk-insert

我有一个带有标识列的表,我想保留一个可用于批量插入的 id 块,同时允许插入仍然发生在该表中。

请注意,这是多个表的批量插入的一部分,其中其他表通过 FK 与这些 id 相关。因此,我需要将它们挡在外面,以便我可以事先准备好关系。

我找到了一个解决方案,它通过在事务中锁定表然后进行重新播种(非常快)来工作。但这对我来说看起来有点老套 - 这样做是否有普遍接受的模式?

create table dbo.test
(
    id bigint not null primary key identity(1,1),
    SomeColumn nvarchar(100) not null
)
Run Code Online (Sandbox Code Playgroud)

这是阻止(为)一些 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;
Run Code Online (Sandbox Code Playgroud)

我的代码是以大约 1000 个块的形式批量处理数据块。我总共有大约 10 亿行要插入。一切正常——数据库不是瓶颈,批处理本身的计算成本很高,需要我添加几台服务器来并行运行,所以我需要在同时。

Pio*_*otr 13

您可以使用过程(在 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; 
Run Code Online (Sandbox Code Playgroud)

文档:sp_sequence_get_range