Oracle MERGE死锁

时间:2013-05-16 15:26:10

标签: sql oracle plsql

我想以指定的顺序插入带有MERGE语句的行,以避免死锁。否则可能发生死锁,因为多个事务将使用重叠的键集调用此语句。请注意,此代码对重复值异常也很敏感,但我通过重试来处理它,这不是我的问题。我正在做以下事情:

MERGE INTO targetTable
USING (
SELECT ...
FROM sourceCollection
ORDER BY <desiredUpdateOrder>
)
WHEN MATCHED THEN 
UPDATE ...
WHEN NOT MATCHED THEN
INSERT ...

现在我仍然得到死锁,所以我不确定oracle是否维持子查询的顺序。有谁知道如何最好地确保oracle在这种情况下以相同的顺序锁定targetTable中的行?在合并之前我是否必须进行SELECT FOR UPDATE? SELECT FOR UPDATE以哪种顺序锁定行? Oracle UPDATE语句有一个ORDER BY子句,MERGE似乎缺失。除了每次以相同的顺序锁定行之外,还有另一种方法可以避免死锁吗?

[编辑] 此查询用于维护某个操作发生频率的计数。当第一次插入行时动作发生,当第二次发生时,“计数”列递增。有数百万种不同的行为,它们经常发生。表锁不起作用。

2 个答案:

答案 0 :(得分:3)

控制目标表行的修改顺序要求您控制USING子查询的查询执行计划。这是一项棘手的业务,取决于您的查询可能会采用何种执行计划。

如果您遇到死锁,那么我猜您正在从源集合到目标表获得嵌套循环连接,因为散列连接可能基于散列源集合并将修改目标表大致在目标表rowid顺序中,因为它将被完全扫描 - 在任何情况下,访问顺序在所有查询执行中都是一致的。

同样,如果两个数据集之间存在排序合并,则可以按访问目标表行的顺序获得一致性。

源集合的排序似乎是可取的,但优化器可能没有应用它,因此请检查执行计划。如果不是,那么尝试使用APPEND和ORDER BY子句将数据插入到全局临时表中,然后在没有order by子句的情况下从那里选择,并探索我们的提示以巩固嵌套循环连接。

答案 1 :(得分:1)

我不相信ORDER BY会影响任何事情(虽然我更愿意被证明是错误的);我认为 MERGE将锁定它所需的一切。

假设我完全错了,假设您使用MERGE获得逐行锁定。您的问题仍未解决,因为您无法保证两个MERGE语句不会同时出现在同一行。事实上,根据给出的信息,您无法保证ORDER BY改善了这种情况;它可能会使情况变得更糟。

尽管没有跳过锁定行语法,因为UPDATE仍有一个简单的答案,停止尝试从不同的事务中更新同一行。如果可行,您可以使用某种形式的并行执行,例如DBMS_PARALLEL_EXECUTE子程序CREATE_CHUNKS_BY_ROWID,并确保您的事务仅适用于表中行的特定子集。

顺便说一句,我对你对这个问题的描述有点担心。你说通过重新运行MERGE可以修复一些重复的错误。如果这些重复项中的数据不同,则需要确保ORDER BY不仅要对要合并的数据进行处理,还要将要合并的数据合并到中。如果不这样做,则无法保证您不会使用较旧的错误数据覆盖正确的数据。