Sql server SQL Server插入、作用域\标识()和对光盘的物理写入
我有一个存储过程,它可以在循环中的不同表中插入一些内容。请参见下面的示例以获得更清晰的理解:Sql server SQL Server插入、作用域\标识()和对光盘的物理写入,sql-server,insert,identity,scope-identity,Sql Server,Insert,Identity,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 这两个表(T1和T2)中的每一个都有一个标识(1,1)列,我们称
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
这两个表(T1和T2)中的每一个都有一个标识(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
注意第二个表中的“倒置”ID1
由于不太了解SQL Server的底层操作,我提出了以下“理论”,也许有人可以纠正我的错误
我认为,由于循环比实际写入表快,并且/或者可能有其他东西延迟了写入过程,所以记录被缓冲了。到了写它们的时候,它们没有特定的顺序
如果不可能,如何解释上述情况
如果是,那么我还有一个问题要提。如果第一次插入(来自上面的代码)被延迟了怎么办?这是否意味着我将无法获得正确的标识以插入到第二个表中?如果答案也是肯定的,我该怎么做才能确保两个表中的插入顺序正确
我感谢任何有助于我理解这一点的评论和信息
提前感谢。您无法依靠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
解决问题有两种方法:
SET IDENTITY\u INSERT ON
可以为其提供密钥,同时保持标识设置- 每当您执行更改数据的操作时,该操作都会立即写入数据库日志中,直到发生这种情况,您才会得到事务确认。这是酸性条件下的D(数据库理论)
- 脏数据库页“在后台”写入磁盘。如果有太多的文件是脏的,则会触发一个检查点,并将它们全部转储出去
下一条语句,另一个线程可以获得优先级;) 当然,您的上述场景是可能的,而且也很有可能 如果您有两个独立的表,都用于查询和插入,都有一个单独的标识(1,1)字段,则绝对不能保证插入一个表和插入第二个表的顺序相同
如果确实需要在两者之间建立链接,请将第一个表的ID作为外键插入第二个表中。不能依赖由标识生成的标识在两个表中相同 不要依赖业务/应用程序逻辑标识列的实际值您只能假设它们是唯一的 这是SQL Server中已知的错误 问题在于,当它生成查询计划时,并行化会导致范围标识不正确 将该部分移动到它自己的过程中,以便传入参数并返回范围标识-现在应该是正确的了 如果我没记错的话,这只会出现在大约有一百万行或更多行的表上
啊哈,这里是知识库:您应该能够通过使用SQL 2005特性,即输出子句来避免这个问题。链接如下
谢谢你的回答。。。这真的让我松了一口气:)然而,我实际上是将第一个表中的e ID作为外键插入另一个表中,但问题是我的ID是IDENTITY列,这导致了问题:)信息量很大。。。谢谢我完全同意你的看法。问题是,我使用的系统具有非常高的传输次数(每天数百万次),而该系统在很大程度上依赖标识列来标识行并将表链接到另一行。这是我无法改变的,我不得不忍受。。。我只是想确保我生活在最安全的一面,或者风险较小的一面:)我不久前读到过这个bug;不过,我不确定这是否与我的问题有关。在我的例子中,ID是在中正确生成的