设为首页 加入收藏

TOP

Oracle里另外一些典型的执行计划(一)
2017-02-28 08:15:40 】 浏览:380
Tags:Oracle 另外 一些 典型 执行 计划

1. AND-EQUAL(INDEX MERGE)


AND-EQUAL又称为INDEX MERGE,顾名思义,INDEX MERGE就是指如果where条件里出现了多个针对不同单列的等值条件,并且这些列上都有单键值的索引,则Oracle可能会以相应的单个等值条件去分别扫描这些索引;然后Oracle会合并这些扫描单个索引所得到的rowid集合,如果能从这些集合中找到相同的rowid,那么这个rowid就是目标SQL最终执行结果所对应的rowid。最后,Oracle只需要用这些rowid回表就能得到目标SQL的最终执行结果。


AND-EQUAL在执行计划中对应的关键字就是“AND-EQUAL”,我们可以使用Hint来强制让Oracle走AND-EQUAL。


看一个实例:


从上述显示内容中可以看出,现在此SQL的执行计划走的是对索引IDX_MGR和IDX_DEPTNO的AND-EQUAL。


2. INDEX JOIN


INDEX JOIN很容易引起误解,因为它并不是指通常意义上针对多表的表连接。这里INDEX JOIN指的是针对单表上的不同索引之间的连接。


还以上面的EMP_TEMP为例,已经在列MGR和DEPTNO上分别创建了两个单键值的B*Tree索引,如果此时执行SQL语句“select mgr,deptno from emp_temp”,因为这里要查询的列MGR和DEPTNO均可来源于索引IDX_MGR和IDX_DEPTNO(不考虑NULL值),不用回表,所以除了常规的执行方法之外,Oracle还可以采用如下方法:分别扫描索引IDX_MGR和IDX_DEPTNO,得到的结果集分别记为结果集1和结果集2,然后将结果集1和2做一个连接,连接条件就是“结果集1.rowid=结果集2.rowid”,这样得到的最终连接结果(不用回表)就是上述SQL的执行结果。


很显然,针对上述SQL的INDEX JOIN的执行效率是不如我们直接在列MGR和DEPTNO上建一个组合索引,然后直接扫描该组全索引的效率高。INDEX JOIN只是为CBO提供了一种可选的执行路径,大多数情况下,它只是额外多出的一种选择而已。


看一下例子:


从上述显示内容可以看出,现在目标SQL的执行计划走的是对索引IDX_MGR和IDX_DEPTNO的HASH JOIN。


3. VIEW


Oracle在处理包含视图的SQL时,根据该视图是否能做为视图合并(View Merging),其对应的执行计划有如下两种形式。


看一个实例,还是使用上面的EMP_TEMP表:


从上述显示内容中可以看出,现在SQL的执行计划走的是对表EMP_TEMP的全表扫描,并且全表扫描进的过滤查询条件是filter(("ENAME"='CLARK' AND "JOB"='MANAGER')).显然这里Oracle做了视图合并,直接查询的视图EMP_MGR_VIEW的基表EMP_TEMP,并且把针对视图的where条件推到了视图的内部,和原先创建视图时的限制条件做了合并。


现在修改视图EMP_MGR_VIEW的定义,其创建语句中加入ROWNUM关键字,这样新创建的同名视图EMP_MGR_VIEW将不能再做视图合并:


从上述显示内容中可以看出,现在该SQL的执行计划中包含了关键字“VIEW”,即表明这里Oracle并没有对视图EMP_MGR_VIEW做视图合并,视图EMP_MGR_VIEW被Oracle当作一个整体来独立执行。


4. FILTER


FILTER直译过来就是过滤、筛选的意思,它是一种特殊的执行计划,所对应的执行过程就是如下三步:


得到一个驱动结果集


根据一定的过滤条件从上述驱动结果集中滤除不满足条件的记录


结果集中剩下的记录就会返回给最终用户或者继续参与一下个执行步骤。


看一个实例,还是使用上面的视图EMP_MGR_VIEW:


从上述的显示内容可以看出,现在该SQL的执行计划走的是嵌套循环连接,并没有出现我们希望的FILTER类型的执行计划。这是因为Oracle在这里做了子查询展开(Subquery Unnexting),即把子查询和它外部的SQL做了合并,转化成视图VW_NOS_1和表EMP做连接。


这里使用Hint禁掉子查询展开后重新执行上述SQL:


从上述显示内容中可以看出,现在该SQL走的就是我们希望的FILTER类型执行计划。


FILTER类型的执行计划实际上是种改良的嵌套循环连接,它并不像嵌套循环连接那样,驱动结果集中的有多少记录就得访问多少次被驱动表。


用一个实验验证:


注意到上述显示内容中id=2的执行步骤所对应的列A-Rows的值为3,id=3的执行步骤所对应的列Starts的值为2,说明虽然全表扫描T1所得到的驱动结果集的数量为3,但走Filter类型的执行计划时访问被驱动表T2的实际次数却不是3,而是2.这是因为表T数量虽然是3,但其列COL2的distinct值的数量却只有2,所以在用过滤条件“where col2 in(select /*+ no_unnest */ col2 from t2)”去过滤表T1中的数据时,只用访问两次表T2就可以了。


5. SORT


SORT就是排序的意思,执行计划中的SORT通常会以组合的方式出现,这些组合方式包括但不限于如下这几种:


执行计划中即使出现了关键字“SORT”,也不一定意味着就需要排序,比如SORT AGGREGATE和BUFFER SORT就不一定需要排序。


看一个实例,还是使用上面的EMP_TEMP表:


从上述显示内容可以看出,现在SQL的执行计划走的是SORT AGGREGATE,这里执行的SQL只是求了一个sum值,很显然这里不需要排序的。统计信息中的sort(memroy)和sort(disk)的值均为0,也说明Oracle在执行此SQL时并没有做任何排序操作,所以我们说SORT AGGREGATE并不一定需要排序,这其中的关键字“SORT”具有一定的迷惑性。


下面再做实例:


上述SQL的含义是既要排序又要去重,它对应的执行计划就会是SORT UNIQUE


从上述显示内容中可以看出,现在该SQL的执行计划走的是对EMP和EMP_TEMP的排序合并连接。SORT JOIN类型的执行计划通常会出现在排序合并连接中,它是排序合并连接所对应的执行计划第一步要做的事情。


再执行如下SQL:


上述SQL的含义是只需要单纯的排序,它对应的执行计划就会是SORT ORDER BY:


接着执行下面的SQL:


上述SQL的含义是既要排序又要分组,所以它对应的执行计划就会是SORT GROUP BY:


最后执行如下SQL:


从上述显示内容可以看出,现在该SQL的执行计划走的是对表EMP_TEMP和表EMP上主键PK_EMP的笛卡儿连接,因为上述SQL中没有指定连接条件。此处执行计划的步骤是首先全表扫描表EMP_TEMP,扫描结果记为结果集1;接着对表EMP上的主键PK_EMP做索引快速全扫描,并将扫描结果load进PGA中,然后对结果集1和结果集2做笛卡儿连接,最后笛卡儿连接的结果就是上述SQL的最终执行结果。执行计划中关键字“BUFFER SORT”就是表示Oracle会借用PGA并把扫描结果load进去,这样做的好处是省掉了相应的缓存在SGA中所带来的种种额外开销(如持有、释放相关Latch等)。PGA常常用来做排序,这可能就是“BUFFER SORT

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Oracle 分区表进行shrink操作 下一篇MySQL死锁问题解决一例

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目