我们有两张桌子
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
但这些都没有给我想要的理解:)
我有一项任务要更新生产表中的 500 万行,而无需长时间锁定整个表
所以,我使用了多次帮助我的方法 - 一次更新前 (N) 行,块之间的间隔为 1-N 秒
这次从一次更新前 (1000) 行开始,监视扩展事件会话中的lock_escalation事件
lock_escalation在每次更新操作期间出现,所以我开始将每个块1000 -> 500 -> 200 -> 100 -> 50行的行数降低到 1
之前(不是使用这个表,并且对于删除操作 - 不是更新),将行数降低到 200 或 100,有助于摆脱lock_escalation事件
但是这一次,即使每 1 次更新操作有 1 行,表lock_escalation仍然显示。每次更新操作的持续时间大致相同,无论是一次 1 行还是 1000 行
在我的情况下如何摆脱表锁升级?
@@TRANCOUNT 为零
扩展事件:
代码:
set nocount on
declare
@ChunkSize int = 1000, -- count rows to remove in 1 chunk
@TimeBetweenChunks char(8) = '00:00:01', -- interval between chunks
@Start datetime,
@End …Run Code Online (Sandbox Code Playgroud) sql-server extended-events lock-escalation sql-server-2017 batch-processing
sql-server ×2