Oracle 更新中神秘的笛卡尔积
Mysterious Cartesian product in Oracle UPDATE
我们在生产中遇到了一个独特的问题。我们的 Oracle 12c 数据库有时会在半夜的批处理周期中挂起。我们将不得不重新启动数据库以继续运行 days/weeks。然后它再次发生。
经过一番挖掘,我们将范围缩小到 SQL:
UPDATE c_bill SET reason_desc = (SELECT description FROM codes
WHERE code_group = 'TRANSACTION_TYPE' AND code = c_bill.reason_code);
我已经重命名了 tables - 但代码 table 有代码和描述。开发人员正在尝试将描述从这里复制到 c_bill table.
此 SQL 是存储过程的一部分,该存储过程 运行 每晚作为批处理作业的一部分。开发人员在此之前进行了另一次更新,顺利通过,但是这个 SQL 需要很长时间。
在特定的 运行 期间,table 有 36308 行。当我检查生产数据库时(我查看 v$sql table 中的 SQLs),我看到以下内容:
Rows_processed 第一次更新 36308
Rows_processed 对于上面的更新 1318270864,恰好是 = 36308 * 36308!! (笛卡尔积?)
我们在测试中没有这个问题。当我尝试 UPDATE 并在 TEST 中解释计划时,没问题 - 它在 UPDATE 和 v$sql.
中准确显示 36308 行
这令人费解。有没有人看到 SQL 中有笛卡尔积的可能性?或者您是否知道 Oracle 12c 优化器中的任何错误可能会将其变成笛卡尔积(我们刚刚应用了一些补丁来修复 Group by 的错误!)。
我有相当多的 Oracle 经验 - 我在这里调整查询。我已经建议开发人员添加一个 where 条件来确定。我们尚未对此进行测试。同时,我想绕过 Oracle 专家,听听您的看法。非常感谢comments/suggestions。
更新: 给以后看到这个 post 的人 -
问题不在于笛卡尔积,而是在同一 table 上的游标循环中更新 sql 运行 问题,因此看起来像笛卡尔积。请参阅贾斯汀的回答。
我不知道您在此处描述的行为有任何特殊原因。无论如何,作为一种解决方法,您能否尝试使用替代更新,例如:
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 上实际尝试这个语句。我知道我以前见过这种更新。
我的第一个想法是尝试收集证据来证实或反驳你有一个糟糕的计划正在做笛卡尔积的理论。 executions
在 v$sql
1 中吗?还是36308?如果它是 1,这将支持笛卡尔乘积理论,我将开始在 v$sql_plan
或 dba_hist_sql_plan
中寻找查询计划,具体取决于发生这种情况的时间以及您是否获得使用 AWR 的许可。另一方面,如果它是 36308,则意味着查询正在更新 36308 行,但某些原因导致它被调用 36308 次,因为某些原因试图遍历 table.[=14= 中的每一行]
我们在生产中遇到了一个独特的问题。我们的 Oracle 12c 数据库有时会在半夜的批处理周期中挂起。我们将不得不重新启动数据库以继续运行 days/weeks。然后它再次发生。 经过一番挖掘,我们将范围缩小到 SQL:
UPDATE c_bill SET reason_desc = (SELECT description FROM codes
WHERE code_group = 'TRANSACTION_TYPE' AND code = c_bill.reason_code);
我已经重命名了 tables - 但代码 table 有代码和描述。开发人员正在尝试将描述从这里复制到 c_bill table.
此 SQL 是存储过程的一部分,该存储过程 运行 每晚作为批处理作业的一部分。开发人员在此之前进行了另一次更新,顺利通过,但是这个 SQL 需要很长时间。
在特定的 运行 期间,table 有 36308 行。当我检查生产数据库时(我查看 v$sql table 中的 SQLs),我看到以下内容:
Rows_processed 第一次更新 36308 Rows_processed 对于上面的更新 1318270864,恰好是 = 36308 * 36308!! (笛卡尔积?)
我们在测试中没有这个问题。当我尝试 UPDATE 并在 TEST 中解释计划时,没问题 - 它在 UPDATE 和 v$sql.
中准确显示 36308 行这令人费解。有没有人看到 SQL 中有笛卡尔积的可能性?或者您是否知道 Oracle 12c 优化器中的任何错误可能会将其变成笛卡尔积(我们刚刚应用了一些补丁来修复 Group by 的错误!)。
我有相当多的 Oracle 经验 - 我在这里调整查询。我已经建议开发人员添加一个 where 条件来确定。我们尚未对此进行测试。同时,我想绕过 Oracle 专家,听听您的看法。非常感谢comments/suggestions。
更新: 给以后看到这个 post 的人 - 问题不在于笛卡尔积,而是在同一 table 上的游标循环中更新 sql 运行 问题,因此看起来像笛卡尔积。请参阅贾斯汀的回答。
我不知道您在此处描述的行为有任何特殊原因。无论如何,作为一种解决方法,您能否尝试使用替代更新,例如:
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 上实际尝试这个语句。我知道我以前见过这种更新。
我的第一个想法是尝试收集证据来证实或反驳你有一个糟糕的计划正在做笛卡尔积的理论。 executions
在 v$sql
1 中吗?还是36308?如果它是 1,这将支持笛卡尔乘积理论,我将开始在 v$sql_plan
或 dba_hist_sql_plan
中寻找查询计划,具体取决于发生这种情况的时间以及您是否获得使用 AWR 的许可。另一方面,如果它是 36308,则意味着查询正在更新 36308 行,但某些原因导致它被调用 36308 次,因为某些原因试图遍历 table.[=14= 中的每一行]