SQL Server INSERT,Scope_Identity()和物理写入光盘

The*_*Sky 6 sql-server identity insert scope-identity

我有一个存储过程,除了其他功能之外,还有一些循环内不同表中的插入.请参阅以下示例以更清楚地了解:

INSERT INTO T1 VALUES ('something')

SET @MyID = Scope_Identity()

... some stuff go here

INSERT INTO T2 VALUES (@MyID, 'something else')

... The rest of the procedure
Run Code Online (Sandbox Code Playgroud)

这两个表(T1和T2)在每个表中都有一个IDENTITY(1,1)列,我们称之为ID1和ID2; 但是,在我们的生产数据库(非常繁忙的数据库)中运行该程序并在每个表中有超过6250条记录后,我注意到ID1与ID2不匹配的一个事件!虽然通常对于插入T1中的每个记录,但是在T2中插入了记录,并且两者中的标识列一致地递增.

"错误的"记录是这样的:

ID1     Col1
----    ---------
4709    data-4709
4710    data-4710

ID2     ID1     Col1
----    ----    ---------
4709    4710    data-4710
4710    4709    data-4709
Run Code Online (Sandbox Code Playgroud)

注意第二个表中的"倒"ID1.

在操作中对SQL Server知之甚少,我已经提出了以下"理论",也许有人可以纠正我.

我认为因为循环比物理写入表更快,和/或可能延迟写入过程的其他事情,记录被缓冲.在写它们的时候,它们没有特别的顺序写.

如果没有,那是否可能,如何解释上述情况?

如果是,那么我还有另一个问题要提出来.如果第一个插入(来自上面的代码)被延迟怎么办?这是不是意味着我不会将正确的IDENTITY插入第二个表?如果答案也是肯定的,那么我该怎样做才能确保两个表中的插入将按正确的IDENTITY顺序进行?

我感谢任何有助于我理解这一点的评论和信息.

提前致谢.

ang*_*son 3

您无法依靠 IDENTITY 来解决第二个表的问题。如果您关心该行生成的主键值,则应该自行生成。

IDENTITY 是一种说法,“我不想自己生成密钥,只需为我生成密钥,并且在需要时我会询问生成的值”。

这里可能发生的情况是两个线程同时插入行,但它们都尚未提交,因此您会遇到以下情况:

Thread 1                      Thread 2
get id for table 1 = 4709
                              get id for table 1 = 4710
insert row for table 1
                              insert row for table 1
                              get id for table 2 = 4709
get id for table 2 = 4710
                              insert row for table 2
insert row for table 1
Run Code Online (Sandbox Code Playgroud)

您有两种方法可以解决您的问题:

  1. 删除第二个表中主键的 IDENTITY
  2. 用于SET IDENTITY_INSERT ON允许您为其提供密钥,同时保留 IDENTITY 设置

然而,在这种情况下,我会使用方法 nbr。1. 方法编号。2 通常在将数据导入到空表时使用。您不希望数据库自动生成您稍后想要使用的 ID 的风险(因为它来自第一个表),因此您应该禁用第二个表的主键上的 IDENTITY 设置。

或者您可以尝试完全避免依赖该表的键,因为您有外键引用,您真的需要键值相同吗?