Oracle UPDATE中的神秘笛卡尔积

时间:2016-09-02 20:30:34

标签: sql database oracle oracle12c

我们在生产中遇到了一个独特的问题。我们的Oracle 12c数据库偶尔会在半夜的批处理循环中挂起。我们将不得不重新启动数据库以保持数天/周。然后又发生了。 经过一番挖掘,我们将其缩小到这个SQL:

UPDATE c_bill SET reason_desc = (SELECT description FROM codes 
WHERE code_group = 'TRANSACTION_TYPE' AND code = c_bill.reason_code);

我已将这些表重命名 - 但代码表中包含代码和说明。开发人员正在尝试将描述从此复制到c_bill表。

此SQL是存储过程的一部分,该存储过程每晚作为批处理作业的一部分运行。开发人员在此之前做了另一次更新,通过很好,但这个SQL需要很长时间。

在特定运行期间,该表有36308行。当我检查生产数据库(我查看v $ sql表中的SQL)时,我看到以下内容:

第一次更新36308的Rows_processed Rows_processed用于上述更新1318270864,并且很高兴为= 36308 * 36308 !! (笛卡尔积?)

我们在TEST中没有这个问题。当我尝试UPDATE并解释在TEST中计划它时没问题 - 它在UPDATE和v $ sql中都显示了36308行。

这令人费解。有没有人在SQL中看到笛卡尔积的机会?或者您是否了解Oracle 12c优化器中可能将其转换为笛卡尔积的任何错误(我们只是应用了一些补丁来修复分组错误!)。

我对Oracle有相当多的经验 - 我在这里调整查询。我已向开发人员建议添加where条件以确定。我们还没有测试过。与此同时,我想通过Oracle专家来接受它。任何意见/建议都非常赞赏。

更新:以供将来查看此帖子的任何人使用 - 问题不是笛卡尔积,而是问题UPDATE sql在同一个表上的游标循环中运行,因此看起来像笛卡儿。见贾斯汀的回答。

2 个答案:

答案 0 :(得分:1)

我不知道你在这里描述的行为有什么特别的原因。无论如何,作为一种解决方法,你可以尝试使用备用UPDATE,例如:

UPDATE 
    (SELECT c_bill.reason_desc oldDesc, codes.description newDesc
     FROM c_bill INNER JOIN codes ON
         code.code_group = 'TRANSACTION_TYPE' AND 
         codes.code = c_bill.reason_code)
SET oldDesc = newDesc

不幸的是,我现在很难在Oracle上尝试这个声明。我知道我以前见过这种更新。

答案 1 :(得分:1)

我的第一个想法是尝试收集证据,证明或反驳你有一个糟糕的计划做笛卡尔积的理论。 executions 1中的v$sql是?还是36308?如果它是1,那将支持笛卡尔积理论,我将开始在v$sql_plandba_hist_sql_plan中查找查询计划,具体取决于何时发生以及您是否获得使用AWR的许可。另一方面,如果它是36308,则意味着查询正在更新36308行,但有些东西导致它被调用36308次,因为有些东西试图遍历表中的每一行。