Giải pháp thành ngữ trong SQL Server để dự trữ một khối id để sử dụng trong một số lượng lớn là gì?


8

Tôi có một bảng có cột nhận dạng và tôi muốn dự trữ một khối id mà tôi có thể sử dụng để chèn số lượng lớn, trong khi cho phép chèn vẫn xảy ra trong bảng đó.

Lưu ý đây là một phần của một số lượng lớn một số bảng, trong đó các bảng khác liên quan đến các id này thông qua FK. Vì vậy, tôi cần phải chặn chúng để tôi có thể chuẩn bị các mối quan hệ trước.

Tôi đã tìm thấy một giải pháp hoạt động bằng cách khóa trên bàn trong một giao dịch và sau đó thực hiện lại (điều này khá nhanh). Nhưng nó có vẻ hơi khó hiểu đối với tôi - có một mô hình thường được chấp nhận để làm điều này không?

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

Đây là mã để chặn (nhường chỗ cho) một số 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;

Mã của tôi là khối xử lý hàng loạt dữ liệu trong khối khoảng 1000. Tôi có khoảng một tỷ hàng để chèn tổng cộng. Mọi thứ đều hoạt động tốt - cơ sở dữ liệu không phải là cổ chai, việc xử lý hàng loạt rất tốn kém về mặt tính toán và yêu cầu tôi phải thêm một vài máy chủ để chạy song song, vì vậy tôi cần điều chỉnh nhiều hơn một quy trình "chèn hàng loạt" tại cùng một lúc


2
Tại sao không sử dụng INSERT .. SELECT ..với OUTPUT? Không khóa, không gieo hạt. Chỉ cần XÁC NHẬN và nhận ID từ OUTPUT để bạn có thể sử dụng chúng trong các bảng khác.
ypercubeᵀᴹ

@ ypercubeᵀᴹ xin lỗi, tôi thấy tôi không biết bạn có thể chèn hàng loạt với đầu ra. Tôi đang thực hiện thao tác chèn hàng loạt từ mã (c #) kết nối từ xa - Tôi đoán tôi có thể viết ra các tệp và sau đó sử dụng chèn hàng loạt từ một tệp. Điều này có thể là một chút khó khăn.
Daniel James Bryars

3
Đắt tiền, sản xuất / tính toán các hàng là gì? Hoặc bạn đã có dữ liệu trong tệp và chỉ cần chèn chúng? Ngoài ra: có bao nhiêu bảng và các mối quan hệ liên quan là gì? Chỉ cần 2 bảng có FK, nhiều bảng có lược đồ sao, nhiều bảng có lược đồ phức tạp (chu kỳ, nhiều đường dẫn, v.v.)?
ypercubeᵀᴹ

Câu trả lời:


13

Bạn có thể sử dụng quy trình (được giới thiệu trong SQL Server 2012):
sp_sequence_get_range

Để sử dụng nó, bạn cần tạo một đối tượng SEQUENCE và sử dụng nó làm giá trị mặc định thay vì cột IDENTITY.

Có một ví dụ:

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; 

Tài liệu: sp_fterence_get_range

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.