我有一个 READ_COMMITTED_SNAPSHOT_ISOLATION 设置为 ON 的数据库(无法更改)。
我在许多并行会话上将新行插入到表中,但前提是它们尚不存在(经典左连接检查)。
插入代码如下所示:
INSERT INTO dbo.Destination(OrderID)
SELECT DISTINCT s.OrderID
FROM dbo.Source s
LEFT JOIN dbo.Destination d ON d.OrderID = s.OrderID
WHERE d.OrderID IS NULL;
如果我在许多并行会话上运行它,我会得到很多重复的键错误,因为不同的会话会一遍又一遍地尝试插入相同的 OrderID。
这是预期的,因为 RCSI 下缺少共享锁。
这里推荐的解决方案(根据我的研究)是使用 READCOMMITTEDLOCK 提示,如下所示:
LEFT JOIN dbo.Destination d WITH (READCOMMITTEDLOCK) ON d.OrderID = s.OrderID
这有点工作,因为大大减少了重复的键错误,但(令我惊讶的是)并没有完全消除它们。
作为一个实验,我删除了 Destination 表上的唯一约束,并看到许多重复项在同一毫秒内进入表,来自不同的会话。
似乎尽管有表格提示,但我仍然在存在检查时得到误报,并且冗余插入触发。
我尝试了不同的提示(SERIALIZABLE),但它使情况变得更糟,并让我陷入了死锁。
我怎样才能使这个插入在 RCSI 下工作?