ID列を持つテーブルがあり、一括挿入に使用できるIDのブロックを予約し、そのテーブルへの挿入を引き続き許可します。
これは複数のテーブルの一括挿入の一部であり、他のテーブルはFKを介してこれらのIDに関連していることに注意してください。したがって、関係を事前に準備できるように、それらをブロックする必要があります。
トランザクションでテーブルをロックしてから再シードを実行することで機能する解決策を見つけました(これは非常に高速です)。しかし、それは私には少しハックに見えます-これを行うための一般的に受け入れられているパターンはありますか?
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億行を挿入します。すべてが正常に機能しています。データベースはボトルネックではありません。バッチ処理自体は計算コストが高く、並列で実行するサーバーを2台追加する必要があるため、複数のプロセス「バッチ挿入」に対応する必要があります。同時。
次の手順を使用できます(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