Oracle中常见的表连接方式

日常学习笔记,这两天复工了,实在是太忙。

第五章看了三天,终于有时间记笔记了。

一、嵌套循环(NESTED LOOPS)

嵌套循环的算法:驱动表返回一行数据,通过连接列传值给被驱动表,驱动表返回多少行,被驱动表就要被扫描多少次。(用落总的话就是驱动表多少行,被驱动表就要被干多少次)

加上HINT:FIRST_ROWS,优化器更倾向于嵌套循环。

嵌套循环的驱动表应该返回少量数据。在执行计划中,离NESTED LOOPS关键字最近的表就是驱动表.

如果执行计划走的是嵌套循环,那此时无法更改驱动表,驱动表会被固定为主表。

/*+  use_nl(t1,t2)  */ 

表示让两个表走嵌套循环,在书写HINT的时候,如果表有别名,HINT中一定要使用别名,不然HINT不会生效;如果没有别名,就直接用表名。

判定两个表关联是否走NL应该直接看两表关联返回后的数据量,如果返回的少可以NL,如果多的话就走HASH。

一般情况下,一个小表和大表关联,可以考虑小表NL大表,然后大表的连接列走索引,如果大表有过滤条件,可以和连接列创建组合索引。

二、HASH连接(HASH JOIN)

HASH JOIN连接的算法:两表等值关联,返回大量数据,将较小的表作为驱动表。

哈希连接只支持等值连接。

执行计划中离HASH连接关键字最近的表就是驱动表,嵌套循环中被驱动表需要扫描多次,而HASH连接的被驱动表只需要扫描一次。

执行计划中Used-Mem表示HASH连接消耗了多少PGA,当驱动表太大,PGA装不下就会溢出到临时表空间,产生磁盘HASH连接,这时候性能就会严重下降。嵌套循环不需要消耗PGA。

哈希连接和嵌套循环不同,HASH连接的驱动表和被驱动表的连接列都不需要创建索引。

OLTP环境一般高并发,小事务居多,多以NL为主,因此SGA设置较大,PGA设置较小;而OLAP环境多数SQL都是大规模的ETL,往往HASH连接较多,消耗大量PGA,所以设置的PGA较大。

可以使用以下代码来更改外连接中HASH连接的驱动表。

 /*+ use_hash(t1,t2)  swap_join_inputs(t1) */ 

三、排序合并连接(SORT MERGE JOIN)

排序合并连接的算法:两表关联,先对两个表根据连接列进行排序,将较小的表作为驱动表,然后从驱动表中取出连接列的值,到已经排好序的被驱动表中匹配数据,匹配上数据就算关联成功。驱动表返回多少行,被驱动表就被匹配多少次。类似嵌套循环,但是嵌套循环是从被驱动表的索引中匹配数据,而排列合并连接是PGA中的work area匹配数据。

排序合并连接主要处理两表非等值关联,但是不能用于instr、substr、like、regexp_like关联,instr、substr、like、regexp_like关联只能走嵌套循环。

四、笛卡尔连接(CARTESIAN JOIN)

两表关联没有连接条件时候会产生笛卡尔积,这种表连接方式叫做笛卡尔连接。

执行计划中MERGE JOIN CARTESIAN表示笛卡尔连接,笛卡尔连接后会返回两个表行数的乘积。笛卡尔积连接会对两表中的一个表进行排序,执行计划中BUFFER SORT表示排序。

在多表关联的时候,两个表没有直接的关联条件,但是优化器错误的把某个表返回的ROWS算为一行,这时候也可能发生笛卡尔连接。

添加HINT:ordered 可以使两表进行笛卡尔关联,也可以使用以下HINT禁止笛卡尔连接。

/*+ opt_param('_optimizer_mjc_enabled','false') */

五、标量子查询(SCALAR SUBQUERY)

当一个子查询介于select和from之间,这种子查询就叫标量子查询。标量子查询的连接列要包含在索引中。

当SQL里有标量子查询,我们可以适当的改写为外连接。

在Oracle 12c中,简单的标量子查询会被优化器等价改写为外连接。

六、半连接(SEMI JOIN)

两个表关联只返回一个表的数据叫做半连接。半连接一般就是in和exists。

这里落总写了挺多,没总结明白,我再瞅瞅的,

半连接可以改写外内连接,但要注意主表和子表中的比例关系,要是1:N的话,需要加上GROUP BY 去重,这时候GROUP BY就会消耗性能,半连接的性能高于内连接;如果是1:1的关系的话,性能一样。

七、反连接(ANTI JOIN)

两表关联只返回主表的数据,而且只返回主表和子表没有关联上的数据,这种连接叫做反连接。一般就是指not in 和 not exists。

注意:not in里面如果有null,整个查询会返回空,而in里面有null,查询不受null的影响。

反连接可以改写为 外连接+子表连接条件is null

八、FILTER

如果子查询(in/exists/not in/not exists)没能展开(unnest),在执行计划中就会产生FILTER,FILTER类似嵌套循环,FILTER的算法与标量子查询一模一样。

执行计划中靠近FILTER的可以当做驱动表,和标量子查询一样,驱动表都是固定的,不可更改。

在做SQL有花的时候,一般只需关注FILTER下有两个或者两个以上儿子这种FILTER。

九、总结

1、标量子查询可以改为外连接,此时需要注意表间关系,去重

2、半连接可以改写为内连接,需要注意表间关系,去重

3、反连接可以改写为外连接,不需要考虑表间关系,不需要去重

发布了10 篇原创文章 · 获赞 1 · 访问量 398

猜你喜欢

转载自blog.csdn.net/s4cott/article/details/104807532