我对生产有以下两个疑问:
查询 #1:根据“日期”列从核心表“Table1”中删除旧历史数据的脚本
有约 20 个表通过外键通过级联规则指向“Table1”,因此当您从“Table1”中删除时,数据也会从约 20 个其他表中删除
脚本一次删除 50 行数据,批处理间隔为 1 秒
当批处理只有 50 行时,脚本不会导致排他锁升级为表级锁;它只放置行/页级别 (X) 锁
查询 #2:从“Table1”、“Table2”、“Table3”和其他一些表中提取数据的生产应用程序
这是一个重读查询,它在表上放置共享锁。它不做任何插入/更新/删除
问题:
有时,当Query # 2
(Prod 应用程序)读取数据时会发生死锁,而我同时Query # 1
在 SSMS 中运行(脚本删除旧数据)。Query # 2
始终是受害者,据我了解,这是因为它没有对事务日志进行任何更改,而Query # 1
确实
为了解决这个问题,我添加set deadlock_priority -10
了Query # 1
,希望它会使Query # 1
任何可能的死锁成为受害者
首先它似乎有效,Query # 1
成为死锁情况的受害者,在删除一些批次时抛出错误 1205。
但是-最近我发现有时Query # 2
仍然会成为受害者
问题:
这怎么可能Query # 2
有时甚至在我已经成为受害者set deadlock_priority -10
之后Query # 1
?
有没有办法解决它并确保Query # 1
在 100% 的情况下成为受害者?
更新:在下面添加图表
您可以尝试通过更改事务隔离级别来解决问题。具体开启快照隔离,设置Read Committed Snapshot,让读写不会互相干扰。您也可以只更新生产查询以使用快照隔离而不更新默认数据库隔离级别。
不过要小心并彻底测试它,因为它会在写入行快照时增加 tempdb 上的流量。设置读取提交快照也是整个数据库的默认行为更改,需要回归测试以验证没有意外的副作用。
Microsoft 此处提供了有关此选项的更好解释:https ://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server