【发布时间】:2013-11-24 05:56:20
【问题描述】:
当每个会话对主键列id 使用不同的值(在下面的 sn-p 中显示为 ***)同时执行并发 MERGEs 时,如果我在 2 个终端中手动执行,一切都很好会议。
MERGE
INTO x
USING (SELECT *** as id FROM DUAL) MERGE_SRC
ON (x.id = MERGE_SRC.id)
WHEN MATCHED THEN UPDATE SET val = val + 1 WHERE id = ***
WHEN NOT MATCHED THEN INSERT VALUES (***, 99);
COMMIT;
但是,使用 3 个或更多线程运行多线程负载测试,我会相对较快地遇到 ORA-08177 with locked table。这是为什么? (为什么它是不确定的,因为它并不总是在事务重叠时发生?)
该表是使用
创建的create table x (id int primary key, val int);
SQL Server 顺便说一句,在运行相同的实验时,从不使用等效的 MERGE 语句引发异常。甚至在同时处理同一行时也是如此。
是不是因为 MERGE不是原子的,并且可序列化模式乐观地运行,所以比赛可能只显示有足够的争用?不过,为什么即使不同时处理同一行也会发生这种情况?
顺便说一句,我尝试fix this using the strictest lock available 没有成功。因此,非常感谢有关如何使这个原子化的任何想法。看起来放松隔离级别可以让我摆脱异常,但如果同一行上有 2 个更新,则会有不一致的风险(否则为什么它首先会在可序列化模式下停止)。
【问题讨论】:
-
您是否尝试过在单个事务中进行更新和插入,而不是使用合并? (合并可能是一个非常古怪的生物......)。
-
您的意思是
update和if rowcount=0 then insert?在可序列化模式下,我想我也必须手动锁定,对吧? -
你能解释一下为什么你坚持使用seralization吗?如果会话 A 和 B 大致同时执行,并且您需要每个会话对事务开始时存在的状态进行操作,那么序列化就足够了。这就是它的目的。
-
序列化足以让异常发生。但是,我希望我的交易能够成功,同时保持一致的状态。在 serializable 模式 中时,我似乎必须使用 @BobJarvis 建议的笨拙循环来运行它,即使我从未在不同会话中同时在同一行上工作。顺便说一句,“序列化就足够了”你的意思是说“通过使用锁进行序列化,而不实际使用隔离模式 serializable”。这肯定是有道理的。