Oracle中的merge join Cartesian

在执行计划中,有时会出现CARTESIAN笛卡尔乘积,简单的说一下什么叫cartesian?就是有两个集合,每个集合的任意一个成员都要与另外一个集合的任意一个成员有关联...下面是关于cartesian的一些实验:

SQL> set linesize 2000

SQL> select * from tab;

 

TNAME                          TABTYPE CLUSTERID

------------------------------ ------- ----------

T                              TABLE

REP_T_LOG                      TABLE

 

SQL> select * from t,rep_t_log

 

Execution Plan

----------------------------------------------------------

Plan hash value: 2235198130

 

----------------------------------------------------------------------------------

| Id | Operation            | Name      | Rows | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------

| 0 | SELECT STATEMENT     |           | 20000 |   429K|    16   (7)| 00:00:01 |

|   1 | MERGE JOIN CARTESIAN|           | 20000 |   429K|    16   (7)| 00:00:01 |

|   2 |   TABLE ACCESS FULL | REP_T_LOG |     2 |    30 |     3   (0)| 00:00:01 |

|   3 |   BUFFER SORT        |           | 10000 | 70000 |    13   (8)| 00:00:01 |

|   4 |    TABLE ACCESS FULL | T         | 10000 | 70000 |     6   (0)| 00:00:01 |

----------------------------------------------------------------------------------

 

Note

-----

   - dynamic sampling used for this statement

 

SQL>

如果强制不允许merge join Cartesian出现,可以通过设置隐含参数“_optimizer_mjc_enabled”

SQL> alter session set "_optimizer_mjc_enabled" = false;

 

Session altered.

 

SQL> select * from t,rep_t_log;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 4018263157

 

--------------------------------------------------------------------------------

| Id | Operation          | Name      | Rows | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           | 20000 |   429K|    16   (7)| 00:00:01 |

|   1 | NESTED LOOPS      |           | 20000 |   429K|    16   (7)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| REP_T_LOG |     2 |    30 |     3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| T         | 10000 | 70000 |     6   (0)| 00:00:01 |

--------------------------------------------------------------------------------

 

Note

-----

   - dynamic sampling used for this statement

 

SQL> conn / as sysdba

Connected.

在整个系统级禁用笛卡尔乘积

 

SQL> alter system set "_optimizer_mjc_enabled" = false;

 

System altered.

 

SQL> conn test/test

Connected.

SQL> set autotrace trace exp

SQL> select * from t,rep_t_log;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 4018263157

 

--------------------------------------------------------------------------------

| Id | Operation          | Name      | Rows | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           | 20000 |   429K|    16   (7)| 00:00:01 |

|   1 | NESTED LOOPS      |           | 20000 |   429K|    16   (7)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| REP_T_LOG |     2 |    30 |     3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| T         | 10000 | 70000 |     6   (0)| 00:00:01 |

--------------------------------------------------------------------------------

 

Note

-----

   - dynamic sampling used for this statement

 

当出现merge join Cartesian时,sql的执行效率可能会很低,对于系统的隐藏参数,一般不应该改变。

转自:http://hi.baidu.com/xiaoxiaosir/blog/item/318cec2929cae6f699250abf.html

<think>好的,我现在需要详细解答用户关于Oracle中笛卡尔积的概念、用法以及如何避免的问题。首先,我得先理清楚笛卡尔积的基本定义,然后结合用户提供的引用资料,特别是引用[4]中的具体案例,来深入说明在Oracle中的表现和解决方法。 首先,笛卡尔积在SQL中指的是两个表在没有连接条件的情况下进行连接,导致每个行都与另一个表的所有行组合。这通常会导致结果集行数急剧膨胀,影响性能。用户可能在实际操作中遇到过这种情况,尤其是在忘记写ON条件或者连接条件无效的时候。 接下来,根据引用[4],Oracle中的笛卡尔积可能出现在执行计划中,比如MERGE JOIN CARTESIAN,这可能是因为统计信息过期导致优化器选择了错误的执行计划。例如,如果优化器错误地估计某个表只有一行数据,那么进行笛卡尔积的代价看起来很低,但实际上该表有很多行,从而导致性能问题。这时候需要重新收集统计信息,让优化器能够做出正确的选择。 然后,我需要解释如何避免笛卡尔积。首先,检查SQL语句中是否遗漏了连接条件,确保所有JOIN都有有效的ON子句。其次,在需要显式生成笛卡尔积的情况下,比如生成所有可能的组合,可以使用CROSS JOIN语法,这样代码更清晰。此外,定期更新统计信息也很重要,避免优化器因过时信息做出错误决策。监控执行计划,特别是当查询性能下降时,检查是否有意外的笛卡尔积操作,及时调整。 还要注意用户提供的引用[2]提到的,笛卡尔积可以用于查找连续日期中缺失的数据,这种情况下生成排列组合后再关联目标表。这说明笛卡尔积并非总是无用的,但在大多数联表查询时应避免无意中的笛卡尔积。 最后,整理回答结构,先定义笛卡尔积,再说明其在Oracle中的具体表现,如执行计划中的MERGE JOIN CARTESIAN,结合引用案例解释原因,接着给出避免的方法,包括检查连接条件、使用CROSS JOIN、更新统计信息等。同时,生成相关问题,帮助用户进一步理解。 需要确保回答中用中文,数学公式用$...$,独立公式用$$...$$,并正确引用提供的资料。还要检查是否有遗漏的要点,比如引用[3]提到的外连接语法变化,但用户的问题主要针对笛卡尔积,可能可以简要提及,但重点还是在笛卡尔积本身。 总结步骤: 1. 定义笛卡尔积,说明其在SQL中的表现。 2. 结合引用[4]中的例子,说明Oracle中笛卡尔积的产生原因,如统计信息错误。 3. 提供避免笛卡尔积的方法,包括检查连接条件、使用正确语法、更新统计信息等。 4. 举例说明正确和错误的情况。 5. 生成相关问题,如应用场景、性能影响、执行计划分析等。</think>### Oracle笛卡尔积详解 #### 概念定义 **笛卡尔积**(Cartesian Product)指两个表$A$和$B$在没有连接条件时,所有行的组合结果集。数学上表示为: $$A \times B = \{(a,b) \mid a \in A, b \in B\}$$ 例如,表$A$有$m$行,表$B$有$n$行,结果将包含$m \times n$行。在Oracle中,若SQL语句缺少`JOIN`条件或使用`CROSS JOIN`,就会产生笛卡尔积[^4]。 --- #### Oracle中的表现形式 1. **显式笛卡尔积** 使用`CROSS JOIN`语法显式生成组合: ```sql SELECT * FROM employees CROSS JOIN departments; ``` 2. **隐式笛卡尔积** 因语法错误(如漏写`WHERE`或`ON`条件)导致: ```sql SELECT * FROM employees, departments; -- 隐式笛卡尔积 ``` 3. **执行计划中的标识** 在Oracle执行计划中,笛卡尔积可能显示为`MERGE JOIN CARTESIAN`,通常由优化器估算错误导致。例如,当统计信息过期时,优化器误判表数据量为1行,认为笛卡尔积代价低,实际表有大量数据,最终引发性能问题[^4]。 --- #### 如何避免笛卡尔积 1. **检查连接条件** 确保所有`JOIN`操作包含有效的`ON`或`USING`子句: ```sql SELECT * FROM table1 JOIN table2 ON table1.key = table2.key; -- 正确写法 ``` 2. **显式使用`CROSS JOIN`** 若需生成笛卡尔积,使用明确语法避免歧义: ```sql SELECT * FROM table1 CROSS JOIN table2; -- 明确意图 ``` 3. **更新统计信息** 定期使用`DBMS_STATS`包更新统计信息,避免优化器误判: ```sql EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'TABLE_NAME'); ``` 4. **监控执行计划** 使用`EXPLAIN PLAN`分析查询,若发现`MERGE JOIN CARTESIAN`且非预期,需检查SQL或统计信息: ```sql EXPLAIN PLAN FOR SELECT * FROM table1, table2; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); ``` --- #### 应用场景 尽管需谨慎使用,笛卡尔积在特定场景下有用: - **生成测试数据**:快速创建大量组合数据。 - **填补缺失序列**:如引用[2]所述,生成连续日期后关联目标表,查找缺失数据。 --- #### 示例对比 **错误案例**(隐式笛卡尔积): ```sql SELECT * FROM orders, products; -- 结果集=orders行数×products行数 ``` **正确写法**(带连接条件): ```sql SELECT * FROM orders JOIN products ON orders.product_id = products.id; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值