【免责声明】本公众号文章仅代表个人观点,与任何公司无关。

概述
阅读官方在线文档无疑是学习Oracle最好的方法,本文参考在线文档介绍表连接以及连接树(Join Trees)。
表连接概述
Oralce可以把两个数据集通过一定的关联条件进行结合操作,即表连接(Join)。
Oralce数据库的表连接主要包括两种语法:
1.标准SQL语法:(Ansi Join)
通过JOIN ON语句,进行表连接。例:select emp.deptno,emp.empnofrom emp join depton emp.deptno = dept.deptno;
2.Oracle SQL语法:
通过Where条件,进行表连接。例:select emp.deptno,emp.empnofrom emp,deptwhere emp.deptno=dept.deptno;
连接树(Join Trees)
多个数据集(表)进行连接时,执行过程可以表示成树形结构,即连接树。
根据访问表的顺序不同,连接树可以分为左深树(Left Deep Join Tree)、右深树(Right Deep Join Tree)、浓密树(Bushy Join Tree)。
左深树(Left Deep Join Tree)
如果连接树的每个连接的右节点都是一个表,就是左深树(Left Deep Join Tree)。

左深树(Left Deep Join Tree)一般包括以下特点:
・左深树是Oracle优化器最普遍使用的连接树・嵌套循环连接的连接树仅可能是左深树
右深树(Right Deep Join Tree)
如果连接树的每个连接的左节点都是一个表,就是右深树(Right Deep Join Tree。

右深树(Right Deep Join Tree)一般包括以下特点:
・通常在数据仓库的环境中使用,如:用于连接事实表和多个维度表的连接(星型模式)。・哈希连接和排序合并连接的连接树有可能是右深树。・哈希连接为右深树时,可能会消耗大量的PGA因为哈希连接为右深树时,会同时有多个表被做成Hash表,从而消耗过多的PGA. (Ref Old Bug 4475206)
浓密树(Bushy Join Tree)
如果连接树的左节点或右节点都有可能不是表,就是浓密树(Bushy Join Tree)。

浓密树(Bushy Join Tree)一般包括以下特点:
・优化器无法选择其他树形连接是才会选择浓密树・一般当查询包含子查询或者视图时,可能会产生浓密树。如无法进行视图合并等
连接树的处理
连接树的一般处理规则如下:
・从最左端的叶节点开始处理・左节点的处理优先级高于右节点・左节点驱动右节点・子节点在父节点之前进行处理・子节点处理完获得的数据返回给父节点。
连接树的执行计划例
下面我们创建4个表,通过SQL文和HINT的组合来生成各种连接树的执行计划,以帮助我们加深对连接树的理解。
--准备表SQL> conn scott/tigerSQL> create table t1 (id number,col varchar2(20));SQL> create table t2 (id number,col varchar2(20));SQL> create table t3 (id number,col varchar2(20));SQL> create table t4 (id number,col varchar2(20));--插入数据SQL> beginfor i in 1..100 loopinsert into t1 values(i,i||'t');insert into t1 values(i+10,i||'t');insert into t1 values(i+20,i||'t');insert into t1 values(i+30,i||'t');end loop;commit;end;/SQL> BEGINdbms_stats.gather_table_stats('scott','t1');dbms_stats.gather_table_stats('scott','t2');dbms_stats.gather_table_stats('scott','t3');dbms_stats.gather_table_stats('scott','t4');END;/---查看执行计划SQL> SET AUTOTRACE TRACEONLY EXPLAIN
1.左深树(Hash Join)
SQL> SELECT *+ ordered use_hash(t2,t3,t4) */ t1.*, t2.*, t3.*, t4.*2 FROM t1, t2, t3, t43 WHERE t1.id = t2.id AND t2.id = t3.id AND t3.id = t4.id;执行计划----------------------------------------------------------Plan hash value: 894925296-----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 82 | 9 (0)| 00:00:01 ||* 1 | HASH JOIN | | 1 | 82 | 9 (0)| 00:00:01 ||* 2 | HASH JOIN | | 1 | 57 | 7 (0)| 00:00:01 ||* 3 | HASH JOIN | | 1 | 32 | 5 (0)| 00:00:01 || 4 | TABLE ACCESS FULL| T1 | 400 | 2800 | 3 (0)| 00:00:01 || 5 | TABLE ACCESS FULL| T2 | 1 | 25 | 2 (0)| 00:00:01 || 6 | TABLE ACCESS FULL | T3 | 1 | 25 | 2 (0)| 00:00:01 || 7 | TABLE ACCESS FULL | T4 | 1 | 25 | 2 (0)| 00:00:01 |-----------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------1 - access("T3"."ID"="T4"."ID")2 - access("T2"."ID"="T3"."ID")3 - access("T1"."ID"="T2"."ID")
2. 左深树(Nest loop)
SQL> SELECT *+ ordered use_nl(t2,t3,t4) */ t1.*, t2.*, t3.*, t4.*2 FROM t1, t2, t3, t43 WHERE t1.id = t2.id AND t2.id = t3.id AND t3.id = t4.id;执行计划----------------------------------------------------------Plan hash value: 4050478457-----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 82 | 117 (0)| 00:00:01 || 1 | NESTED LOOPS | | 1 | 82 | 117 (0)| 00:00:01 || 2 | NESTED LOOPS | | 1 | 57 | 115 (0)| 00:00:01 || 3 | NESTED LOOPS | | 1 | 32 | 113 (0)| 00:00:01 || 4 | TABLE ACCESS FULL| T1 | 400 | 2800 | 3 (0)| 00:00:01 ||* 5 | TABLE ACCESS FULL| T2 | 1 | 25 | 0 (0)| 00:00:01 ||* 6 | TABLE ACCESS FULL | T3 | 1 | 25 | 2 (0)| 00:00:01 ||* 7 | TABLE ACCESS FULL | T4 | 1 | 25 | 2 (0)| 00:00:01 |-----------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------5 - filter("T1"."ID"="T2"."ID")6 - filter("T2"."ID"="T3"."ID")7 - filter("T3"."ID"="T4"."ID")
3. 右深树
SQL> SELECT *+ LEADING (t4 t3 t2 t1)2 USE_HASH(t3) SWAP_JOIN_INPUTS(t3)3 USE_HASH(t2) SWAP_JOIN_INPUTS(t2)4 USE_HASH(t1) SWAP_JOIN_INPUTS(t1)5 */ t1.*, t2.*, t3.*, t4.*6 FROM t2, t1, t3, t47 WHERE t1.id = t2.id AND t2.id = t3.id AND t3.id = t4.id;执行计划----------------------------------------------------------Plan hash value: 2117174619-----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 82 | 9 (0)| 00:00:01 ||* 1 | HASH JOIN | | 1 | 82 | 9 (0)| 00:00:01 || 2 | TABLE ACCESS FULL | T1 | 400 | 2800 | 3 (0)| 00:00:01 ||* 3 | HASH JOIN | | 1 | 75 | 6 (0)| 00:00:01 || 4 | TABLE ACCESS FULL | T2 | 1 | 25 | 2 (0)| 00:00:01 ||* 5 | HASH JOIN | | 1 | 50 | 4 (0)| 00:00:01 || 6 | TABLE ACCESS FULL| T3 | 1 | 25 | 2 (0)| 00:00:01 || 7 | TABLE ACCESS FULL| T4 | 1 | 25 | 2 (0)| 00:00:01 |-----------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------1 - access("T1"."ID"="T2"."ID")3 - access("T2"."ID"="T3"."ID")5 - access("T3"."ID"="T4"."ID")
4. 浓密树
SQL> SELECT *+ ordered use_hash(b) */*2 FROM3 (SELECT *+ ordered use_hash(t1) no_merge(a) */ t1.*4 FROM t1,5 (SELECT *+ ordered use_hash(t2 t2) */ t2.*6 FROM t2,7 t38 WHERE t2.id = t3.id) a9 WHERE t1.id = a.id ) b,10 t411 WHERE b.id = t4.id;执行计划----------------------------------------------------------Plan hash value: 1347472701------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 45 | 9 (0)| 00:00:01 ||* 1 | HASH JOIN | | 1 | 45 | 9 (0)| 00:00:01 ||* 2 | HASH JOIN | | 1 | 20 | 7 (0)| 00:00:01 || 3 | TABLE ACCESS FULL | T1 | 400 | 2800 | 3 (0)| 00:00:01 || 4 | VIEW | | 1 | 13 | 4 (0)| 00:00:01 ||* 5 | HASH JOIN | | 1 | 26 | 4 (0)| 00:00:01 || 6 | TABLE ACCESS FULL| T2 | 1 | 13 | 2 (0)| 00:00:01 || 7 | TABLE ACCESS FULL| T3 | 1 | 13 | 2 (0)| 00:00:01 || 8 | TABLE ACCESS FULL | T4 | 1 | 25 | 2 (0)| 00:00:01 |------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------1 - access("T1"."ID"="T4"."ID")2 - access("T1"."ID"="A"."ID")5 - access("T2"."ID"="T3"."ID")Hint Report (identified by operation id Query Block Name Object Alias):Total hints for statement: 5 (U - Unused (5))---------------------------------------------------------------------------1 - SEL$F5BB74E1U - ordered duplicate hint1 - SEL$F5BB74E1 B@SEL$1U - use_hash(b)3 - SEL$F5BB74E1 T1@SEL$2U - use_hash(t1)6 - SEL$3 T2@SEL$3U - use_hash(t2 t2) duplicate hintU - use_hash(t2 t2)SQL>
参考
后续文章更加精彩,欢迎关注本公众号。
——End——
专注于技术不限于技术!
用碎片化的时间,一点一滴地提高数据库技术和个人能力。
欢迎关注!
如果有疑问可以加入SQL和数据库技术交流群和其他小伙伴一起讨论。
小编微信(微信号:TeacherWhat 或 扫描下方二维码)
回复:加群。
(为方便交流,建议备注:行业-职位-城市)
手把手系列(帮助个人技术成长):
手把手教你在Windows 10安装Oracle 19c(详细图文附踩坑指南)
【SQL】实时SQL监控功能(Real-Time SQL Monitoring)
【SQL】历史SQL监控(Historical SQL Monitoring ) 功能(12c)
SQL调优和诊断工具之SQL Trace (10046 Event)介绍
SQL调优和诊断工具之Optimizer Trace(10053 Event)介绍
SQL调优和诊断工具之DBMS_SQLDIAG介绍
网罗收集10046的各种Case,方便trace信息的收集 | Oracle官方博客转载
Oracle SQL 性能调优:使用Hint固定执行计划1(Hash Join)
Oracle SQL 性能调优:使用Hint固定执行计划2(Nested Loop Join)
Oracle SQL 性能调优:使用SqlPatch固定执行计划
Oracle SQL 性能调优:使用SqlPatch固定执行计划(二)19c




