插入的记录是否始终接收连续的标识值

时间:2010-11-18 20:22:48

标签: sql-server sql-server-2005

考虑以下SQL:

CREATE TABLE Foo
(
    ID int IDENTITY(1,1),
    Data nvarchar(max)
)

INSERT INTO Foo (Data)
SELECT TOP 1000 Data
FROM SomeOtherTable
WHERE SomeColumn = @SomeParameter

DECLARE @LastID int
SET @LastID = SCOPE_IDENTITY()

我想知道我是否可以依赖于我插入表Foo中的具有连续标识值的1000行。换句话说,如果这个SQL块产生的@LastID为2000,我能否确定我插入的第一条记录的ID是1001?我主要是对多个语句同时将记录插入表Foo感到好奇。

我知道我可以在insert语句周围添加一个可序列化的事务来确保我想要的行为,但我真的需要吗?我担心引入可序列化的事务会降低性能,但如果SQL Server在此语句运行时不允许其他语句插入到表Foo中,那么我不必担心它。

5 个答案:

答案 0 :(得分:7)

我不同意接受的答案。通过运行以下内容,可以轻松测试和反驳这一点。

<强>设置

USE tempdb

CREATE TABLE Foo
(
    ID int IDENTITY(1,1),
    Data nvarchar(max)
)

连接1

USE tempdb

SET NOCOUNT ON
WHILE NOT EXISTS(SELECT * FROM master..sysprocesses WHERE context_info = CAST('stop' AS VARBINARY(128) ))
 BEGIN
 INSERT INTO Foo (Data)
 VALUES ('blah')
 END

连接2

USE tempdb

SET NOCOUNT ON
SET CONTEXT_INFO 0x

DECLARE @Output TABLE(ID INT)

WHILE 1 = 1
BEGIN
    /*Clear out table variable from previous loop*/
    DELETE FROM  @Output

    /*Insert 1000 records*/
    INSERT INTO Foo (Data)
    OUTPUT inserted.ID INTO @Output
    SELECT TOP 1000 NEWID()
    FROM sys.all_columns

    IF EXISTS(SELECT * FROM @Output HAVING MAX(ID) - MIN(ID) <> 999 )
        BEGIN
        /*Set Context Info so other connection inserting 
          a single record in a loop terminates itself*/
        DECLARE @stop VARBINARY(128) 
        SET @stop = CAST('stop' AS VARBINARY(128))
        SET CONTEXT_INFO @stop

        /*Return results for inspection*/
        SELECT ID, DENSE_RANK() OVER (ORDER BY Grp) AS ContigSection
        FROM 
          (SELECT ID, ID - ROW_NUMBER() OVER (ORDER BY [ID]) AS Grp
           FROM @Output) O
        ORDER BY ID

        RETURN
        END
END

答案 1 :(得分:6)

是的,它们将是连续的,因为INSERT是原子的:完全成功或完全回滚。它也作为一个单独的工作单元执行:你不会与其他进程“交错”

然而(或者让你放松心情!),请考虑OUTPUT clause

DECLARE @KeyStore TABLE (ID int NOT NULL)

INSERT INTO Foo (Data)
OUTPUT INSERTED.ID INTO @KeyStore (ID) --this line
SELECT TOP 1000 Data
FROM SomeOtherTable
WHERE SomeColumn = @SomeParameter

答案 2 :(得分:3)

如果您想要多行的Identity值,请使用OUTPUT:

DECLARE @NewIDs table (PKColumn int)
INSERT INTO Foo (Data)
    OUTPUT INSERTED.PKColumn
    INTO @NewIDs
SELECT TOP 1000 Data
FROM SomeOtherTable
WHERE SomeColumn = @SomeParameter

您现在拥有@NewIDs表中的整个值集。您可以将Foo表中的任何列添加到@NewIDs表中,也可以插入这些列。

答案 3 :(得分:1)

将任何形式的意义附加到身份价值上并不是一种好的做法。你应该假设它们只不过是在表范围内保证唯一的整数。

答案 4 :(得分:0)

尝试添加以下内容:

option(maxdop 1)