我们在生产中遇到了一个独特的问题。我们的 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),我看到以下内容:
Rows_processed 第一次更新 36308 上述更新 1318270864 的 Rows_processed,恰好是 = 36308 * 36308! (笛卡尔积?)
我们在测试中没有这个问题。当我尝试 UPDATE 并在 TEST 中解释计划时,没问题 - 它在 UPDATE 和 v$sql 中准确显示 36308 行。
这很令人费解。有没有人在该 SQL 中看到笛卡尔积的机会?或者您是否知道 Oracle 12c 优化器中的任何错误可能会将其变成笛卡尔积(我们只是应用了一些补丁来修复 Group by 的错误!)。
我有相当多的 Oracle 经验 - 我在这里调整查询。我已经建议开发人员添加一个 where 条件来确定。我们尚未对此进行测试。同时,我想绕过 Oracle 专家,听听您的看法。非常感谢任何意见/建议。
更新:对于将来查看此帖子的任何人 - 问题不是笛卡尔积,而是在同一个表上的游标循环中运行的 UPDATE sql 问题,因此看起来像笛卡尔积。请参阅贾斯汀的回答。
最佳答案
我的第一个想法是尝试收集证据来证实或反驳您有一个执行笛卡尔积的糟糕计划的理论。 executions
在 v$sql
1 中吗?还是36308?如果它是 1,那将支持笛卡尔乘积理论,我将开始在 v$sql_plan
或 dba_hist_sql_plan
中寻找查询计划,具体取决于发生的时间以及您是否获得使用 AWR 的许可。另一方面,如果它是 36308,则意味着查询正在更新 36308 行,但某些原因导致它被调用 36308 次,因为某些原因试图遍历表中的每一行。
关于sql - Oracle 更新中神秘的笛卡尔积,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39300289/