jos*_*der 11 sql-server snapshot-isolation
给定两张表
家长
KeyID GroupID Name Active
Run Code Online (Sandbox Code Playgroud)
孩子
KeyID ParentID Name
Run Code Online (Sandbox Code Playgroud)
Child.ParentID 是 FKed Parent.KeyID
我们将Parent和插入Child到单个事务中。
如果在事务处于活动状态Parent时更新了不同的行(例如Active1 -> 0),则会Child INSERT失败:
由于更新冲突,快照隔离事务中止。您不能使用快照隔离直接或间接访问数据库 'Test' 中的表 'dbo.Child' 以更新、删除或插入已被另一个事务修改或删除的行。重试事务或更改更新/删除语句的隔离级别。
据我所知,为什么我会收到“由于更新冲突而中止快照隔离事务”?这可能是由于完全扫描以验证外键。
事实上,删除外键确实允许Child INSERT按预期完成。
话虽如此,Child表上外键上的非聚集索引似乎并没有帮助解决这个问题,所以我有点不知所措。
我们为此数据库打开了 RCSI,并且事务在快照隔离模式下运行。
额外细节
我发现当插入到 Child 的行数大于给定的行数时会出现此问题。此时查询优化器从 a 切换Nested Loops (Left Semi Join)到 a Merge Join (Left Semi Join)。
抱歉没有包括为单个父记录插入多个子记录的事实。
插入sproc大致是这样的:
KeyID GroupID Name Active
Run Code Online (Sandbox Code Playgroud)
并发更新将类似于:
KeyID ParentID Name
Run Code Online (Sandbox Code Playgroud)
OPTION (LOOP JOIN)在INSERT语句中添加提示。
或者使用计划指南(或查询存储)强制嵌套循环半连接计划形状。
你可能会发现这OPTION (FAST 1)也有效。
关键是要避免合并半连接,其中许多(可能是所有)引用表的行都被当前事务触及。如果遇到任何具有更改(包括创建)的父行,则会引发更新冲突错误。
| 归档时间: |
|
| 查看次数: |
797 次 |
| 最近记录: |