Mar*_*ark 9 sql-server snapshot-isolation
我们有两张桌子
Child 与 Parent 有外键关系。
我们启用了数据库级读提交快照隔离。
我们只为父和子插入和删除行(无更新)
我们有一个进程(事务)从 Child(然后是 Parent)中删除旧数据
我们有多个其他进程(事务)将新数据插入父(然后是子)
删除过程会定期(但不是所有时间)回滚,即使插入过程没有插入新的子行,这些子行引用删除要删除的父行 - 它只是创建新的父行和一个或多个引用新父级的新子行
删除父行时的错误是:
由于更新冲突,快照隔离事务中止。您不能使用快照隔离直接或间接访问数据库 'Test' 中的表 'dbo.Child' 以更新、删除或插入已被另一个事务修改或删除的行。重试事务或更改更新/删除语句的隔离级别。
我知道人们建议在外键列上建立索引 - 我们不希望在理想情况下(出于空间/性能原因)这样做 - 除非这是使其工作的唯一可靠方法。
注意到这一点:https : //stackoverflow.com/questions/10718668/snapshot-isolation-transaction-aborted-due-to-update-conflict
和相当不错的文章:https : //sqlperformance.com/2014/06/sql-performance/the-snapshot-isolation-level
但这些都没有给我想要的理解:)
Pau*_*ite 17
从父表中删除时,SQL Server 必须检查是否存在引用该行的任何 FK 子行。当没有合适的子索引时,这个检查会执行子表的全盘扫描:
如果扫描遇到自删除命令的快照事务启动以来已被修改的行,则会因更新冲突(根据定义)而失败。完全扫描显然会触及表格中的每一行。
使用合适的索引,SQL Server 可以定位和测试子表中可以匹配要删除的父表的行。当这些特定行未被修改时,不会发生更新冲突:
请注意,行版本控制隔离级别下的外键检查采用共享锁(为了正确性)以及检测更新冲突。例如,上面关于子表访问的内部提示是:
PhyOp_Range TBL: [dbo].[Child] 提示(READ-COMMITTEDLOCK FORCEDINDEX DETECT-SNAPSHOT-CONFLICT)
遗憾的是,这目前没有在执行计划中公开。
我的相关文章: