Oracle中的查询转换简介(上)

来源:互联网 发布:php数组是什么数据结构 编辑:程序博客网 时间:2024/06/03 19:10

Oracle查询转换的概念:
Oracle在解析目标sql时可能会对其对其做等价改写,目的是为了更高效的自行目标sql,即Oracle可能会将目标改写成语义上完全等价的但执行效率更高的形式。

Oracle查询转换的类型有如下:

子查询展开
视图合并: 简单视图合并 外连接视图合并 复杂视图合并
星型连接转换
连接谓词推入
连接因式分解
表扩展
表移除
Oracle处理sql中语句中IN:
In List Iterator
In List Expansion /OR Expansion
In List Filter
对IN做子查询展开、视图合并

以下分别简单解释:

子查询展开:
优化器处理还有子查询的目标sql的一种优化手段。它是指不再将子查询作为一个单独的整体来处理,而是将其转化为自身和外部查询之间等价的表连接。
分为两种情况:一种是将子查询展开; 一种是不拆开但是把子查询转为一个内嵌的视图,再和外部的表,视图做连接。

如果不做子查询展开,那么通常的执行计划是,这个子查询在目标sql的最后一步才执行,并且会走filter类型的执行计划。

Oracle能否做子查询展开取决下面两个条件:
子查询展开所对应的sql在语义上应该和原sql完全等价。否则便不能进行子查询展开(这是理所当然的条件)
对于子查询不展开,而转为一个内嵌试图的子查询展开,只有当经过子查询展开后的等价改写sql的成本值小于原sql的成本值,才会进行此类的子查询展开。

 对于子查询展开的第一种情形,Oracle始终会对其进行子查询展开,而不管经过子查询展开后的sql的成本值是否小于原sql的成本值。

Oracle并不对所有的子查询进行子查询展开,它还有前提条件的,也就是满足了这些条件,才可能考虑进行子查询展开。

Oracle数据库里子查询前的where条件如果是如下这些条件之一,那么这种类型的目标sql在满足了一定条件之后就可以做子查询展开:

single-row (即 = < > <= >= 和<>)
exists
not exists
in
not in
any
all

select t.userid, wm_concat(r.standno) as standno          from TB_PRODUCTCTRL_USERTASKINFO t, (select * from TB_PRODUCTCTRL_LINETASKINFO where ownerworkshop = #{workshop} ) r         where t.taskclose = 'N'           and t.taskstatus = 'N'           and trunc(t.senddate, 'dd') > sysdate - 2           and r.soflseqnr = t.tasksoflseqnr         group by t.userid

上述sql里面也有子查询,但是Oracle不会进行子查询展开,因此子查询会以filter执行计划的方式,在最后一步出现。

这里写图片描述

下面这样写就可以进行子查询展开了, 下面的sql去掉了这个值 wm_concat(r.standno) as standno,是为了方便说明子查询展开限制条件的问题。 这个sql在业务中是不需要子查询就可以完成的。

select t.userid          from TB_PRODUCTCTRL_USERTASKINFO t          where t.taskclose = 'N'           and t.taskstatus = 'N'           and trunc(t.senddate, 'dd') > sysdate - 2           and t.tasksoflseqnr in (select r.soflseqnr from TB_PRODUCTCTRL_LINETASKINFO r where ownerworkshop = 'chang')         group by t.userid

这里写图片描述

视图合并:
视图合并是Oracle处理带有视图的sql的一种优化手段。它的基本原理也是不再将视做为一个单独的视图来处理,而是将其拿出来和外部查询合并。
视图合并分为三种类型:简单视图合并,外连接视图合并,复杂视图合并。对于简单视图合并,只要符合进行简单视图合并的条件,Oracle始终会对其做视图合并,而不管经过视图合并后的等价改写sql的成本值是否小于原sql的成本值。对于复杂视图合并,只有等价改写后的sql的成本值小于原sql的成本值时,Oracle才会对目标sql进行复杂视图合并。

Oracle做简单视图合并后的等价改写只是让优化器有了更多的执行路径可以选择,原来的未做简单视图合并情形下的执行路径还是保留了,所以做了简单视图合并后等价改写sql的成本值一定小于等于未做简单视图合并的原sql的成本值。

**这个和子查询展开的第一张情况并不一样,Oracle始终会做子查询展开,但是展开后存在成本值大于原sql成本值的情况。**

Oracle进行简单视图合并的条件:
视图定义中
不包括外连接,
不包含distinct group by等聚合函数,
不包含集合运算符:union all union intersect (表是两个表的交集) minus (A-B)
不包含:connect by子句
不包含: rownum
……

外连接视图合并:
用来处理使用了外连接,以及视图定义中不存在distinct group byu等聚合函数的sql。

Oracle做外连接视图合并的条件:
当目标视图在和外部查询的表做外连接时,该目标视图可以做外连接视图合并的条件是:
要么该视图作为外连接的驱动表。当该视图作为外连接的被驱动表时,他的视图定义只能包含一个表。

外连接的驱动表,左连接就是左表,右连接就是右表,也就是不增加null行的表。

复杂视图合并:

复杂视图合并就是来处理视图定义总包含distinct group by的语句。

复杂视图合并的基本原理就是推迟执行distinct 或者group by。但是推迟执行distinct 或者group by并不一定能提升执行效率,因为可能distinct 或者group by会过滤掉大部分数据。

因为复杂视图合并并不一定提升Oracle效率的提升,只有当经过复杂视图合并后等价改写sql的成本值小于原sql的成本值时,Oracle才会对目标sql执行复杂视图合并。