值得反复研读的表连接之CARTESIAN JOIN方式

两表关联却无关联条件必会产生笛卡尔积。

[oracle@MaxwellDBA ~]$ sqlplus sys/sys as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Sun Oct 23 10:50:01 2022
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

sys@cdb$root:orclcdb> ALTER SESSION SET CONTAINER=ORCLPDB1;

Session altered.

sys@cdb$root:orclcdb> conn SCOTT/TIGER@ORCLPDB1;
Connected.
scott@orclpdb1:orclcdb>
scott@orclpdb1:orclcdb> set autot trace;
scott@orclpdb1:orclcdb>
scott@orclpdb1:orclcdb> select * from emp,dept;

56 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 2034389985

-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |    56 |  3248 |    10   (0)| 00:00:01 |
|   1 |  MERGE JOIN CARTESIAN|      |    56 |  3248 |    10   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | DEPT |     4 |    80 |     3   (0)| 00:00:01 |
|   3 |   BUFFER SORT        |      |    14 |   532 |     7   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL | EMP  |    14 |   532 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------


Statistics
----------------------------------------------------------
         97  recursive calls
          0  db block gets
        218  consistent gets
         30  physical reads
          0  redo size
       4393  bytes sent via SQL*Net to client
        417  bytes received via SQL*Net from client
          5  SQL*Net roundtrips to/from client
         16  sorts (memory)
          0  sorts (disk)
         56  rows processed

scott@orclpdb1:orclcdb>

执行计划中MERGE JOIN CARTESIAN表明为笛卡尔连接。笛卡尔会返回两个表的乘积。

DEPT 4 rows 

EMP 14 rows

两表的乘积则为56 rows

BUFFER SORT 表示对其中以表进行排序。

在多表关联的时候,两个表没有直接关联条件,但是优化器错误地把某个表返回的Rows算为1行(注意必须是1行),这个时候也可能发生笛卡尔儿连接。

如果两表有直接关联条件,无法控制两个表进行笛卡尔连接。

如果两表没有直接关联条件,可将两个表依次放在from后面并且添加HINT:ordered,就可以使两表进行笛卡尔积关联

scott@orclpdb1:orclcdb> set autot trace
scott@orclpdb1:orclcdb>
scott@orclpdb1:orclcdb> select /*+ ordered */
  2  a.ename, a.sal, a.deptno, b.dname,c.grade
from dept b, salgrade c, emp a
  4  where a.deptno = b.deptno
  5  and a.sal between c.losal and c.hisal;

14 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 2197699399

----------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |    42 |  1512 |    13   (0)| 00:00:01 |
|*  1 |  HASH JOIN            |          |    42 |  1512 |    13   (0)| 00:00:01 |
|   2 |   MERGE JOIN CARTESIAN|          |    20 |   460 |    10   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL  | DEPT     |     4 |    52 |     3   (0)| 00:00:01 |
|   4 |    BUFFER SORT        |          |     5 |    50 |     7   (0)| 00:00:01 |
|   5 |     TABLE ACCESS FULL | SALGRADE |     5 |    50 |     2   (0)| 00:00:01 |
|   6 |   TABLE ACCESS FULL   | EMP      |    14 |   182 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A"."DEPTNO"="B"."DEPTNO")
       filter("A"."SAL"<="C"."HISAL" AND "A"."SAL">="C"."LOSAL")


Statistics
----------------------------------------------------------
         52  recursive calls
          0  db block gets
         62  consistent gets
          8  physical reads
          0  redo size
       1263  bytes sent via SQL*Net to client
        741  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          5  sorts (memory)
          0  sorts (disk)
         14  rows processed

scott@orclpdb1:orclcdb>

DEPT 和 SALGRADE没有直接关联条件,HINT:ordered表示根据SQL语句中from后面表的顺序依次关联。故DEPT与SALGRADE只能进行笛卡尔连接。

Q:当执行计划中有笛卡尔连接应该怎么优化?

Step1: 检查表与表之间是否存在关联条件,如果没有,可咨询开发与业务人员为何没有关联条件。是否是为了满足业务的需求的某种原因而故意不写关联条件。

Step2 : 检查离笛卡尔连接最近的表是否真的返回1行数据,如果返回行数真的只有1行,那么走笛卡尔连接是没有问题的。如果超过一行,说明估算错误,同时要纠正估算错误的Rows。纠正错误的Rows之后,优化器就不会走笛卡尔连接了。

同时,可以使用HINT/*+ opt_param('_optimizer_mjc_enabled','false')*/ 禁止笛卡尔连接。

参考资源链接:[关系代数与SQL实现探析](https://wenku.csdn.net/doc/2aae37098t?utm_source=wenku_answer2doc_content) 关系代数与SQL语言紧密相关,关系代数中的运算在SQL中有直接的方式。为了将这些理论知识应用到实践中,推荐查阅《关系代数与SQL实现探析》这一文档,它将帮助你深入理解关系代数的每一种运算,并指导你如何在SQL中实现它们。 并集运算(Union)在SQL中通过UNION关键字实现,它会合并两个或多个SELECT语句的结果集,并去除重复的行。例如,若有两个table1和table2,要合并这两个中的所有记录,可以使用以下SQL语句: ```sql SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2; ``` 差集运算(Difference)可以通过EXCEPT关键字(在某些数据库系统中可能是MINUS)来实现,它会返回第一个SELECT查询结果集中存在而第二个SELECT查询结果集中不存在的记录。假设有table1和table2两个,若要找出在table1中但不在table2中的记录,可以这样写: ```sql SELECT column_name(s) FROM table1 EXCEPT SELECT column_name(s) FROM table2; ``` 交集运算(Intersection)在SQL中并不直接提供关键字,通常需要借助JOIN语句或INTERSECT关键字(视具体数据库系统而定)来实现。假设我们仍然使用table1和table2,通过INTERSECT找到两个的共有记录: ```sql SELECT column_name(s) FROM table1 INTERSECT SELECT column_name(s) FROM table2; ``` 笛卡尔积(Cartesian Product)在SQL中通常通过不指定连接条件的JOIN操作来实现,结果集中的每一行都是第一条中的所有行与第二条中所有行的组合。例如,对于table1和table2: ```sql SELECT * FROM table1, table2; ``` 或者使用隐式内连接: ```sql SELECT * FROM table1 INNER JOIN table2; ``` 以上示例展示了如何将关系代数的基本操作转换为SQL查询语句。在实际应用中,理解这些基础运算对于数据库查询优化和数据处理至关重要。掌握这些转换规则,能够帮助你更有效地执行复杂的数据查询和维护数据库的完整性。在你熟悉了这些基本概念后,建议进一步研读《关系代数与SQL实现探析》中更深层次的内容,如关系代数在数据库设计和数据完整性方面的应用,以及SQL中更高级的查询技巧和优化方法。 参考资源链接:[关系代数与SQL实现探析](https://wenku.csdn.net/doc/2aae37098t?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值