表移除
表移除是优化器处理带多表连接的目标SQL的一种优化手段,它是指优化器会把虽然在目标SQL中存在,但是其存在与否对最终执行结果没有影响的表从该目标SQL中移除,这样优化器至少可以少做一次表连接,进而就能提高原目标SQL的执行效率。
Oracle如何处理SQL语句中的IN
优化器在处理带IN的目标SQL时,可能也会用到査询转换,也即本节要介绍的IN-ListExpansion(又称为ORExpansion,两者等价)。为了能让大家明白IN-ListExpansion的优缺点,本节除了会介绍IN-ListExpansion之外,还会介绍优化器在处理带IN的目标SQL时可能会使用的其他方法。在Oracle数据库里,IN和OR是等价的,优化器在处理带IN的目标SQL时实际上会将其转换为带OR的等价改写SQL,也就是说,本节介绍的处理带IN的目标SQL的方法也同样适用于带OR的目标SQL。
优化器在处理带IN的目标SQL时,通常会采用如下这四种方法:
(1)使用IN-List Iterator。
(2)使用IN-List Expansion。
(3)使用IN-List Filter。
(4)对IN做子査询展开,或者既做子查询展开又做视图合并。
IN-List Iterator
IN-List Iterator是针对IN后面是常量集合的一种处理方法。此时优化器会遍历目标SQL中IN后面的常量集合中的每一个值,然后去做比较,看目标结果集中是否存在和这个值匹配的记录。如果存在匹配记录,则这个记录就会成为该SQL的最终返回结果集中的一员;如果不存在匹配记录,则优化器会继续遍历IN后面的常量集合中的下一个值,直到该常量集合遍历完毕。
关于IN-ListIterator,有如下几点需要注意:
(1)IN-ListIterator是Oracletf对目标SQL的IN后面是常量集合的首选处理方法,它的处理效率通常都会比IN-ListExpansion高。
(2)Oracle能用IN-ListIterator来处理IN的前提条件是IN所在的列上一定要有索引。
(3)不能强制让Oracle走IN-ListIterator类型的执行计划,Oracle里也没有相关的强制走IN-ListIterator的Hint,但可以通过联合设置10142和10157事件来禁掉IN-ListIterator。
IN-List Expansion/OR Expansion
IN-List Expansion/OR Expansion(IN-List Expansion又称为OR Expansion,两者等价)是针对IN后面是常量集合的另外一种处理方法,它是指优化器会把目标SQL中IN后面的常量集合拆开,把里面的每个常量都提出来形成一个分支,各分支之间用UNIONALL来连接,即IN-ListExpansion的本质是把带IN的目标SQL等价改写成以UNIONALL连接的各个分支。
IN-List Expansion的好处是改写成以UNIONALL连接的分支后,各个分支就可以各自走索引、分区修剪(PartitionPruning)、表连接等相关的执行计划而互不干扰。它的坏处是未做IN-ListExpansion之前优化器只需要解析一个目标SQL并决定其执行计划,而一旦做了IN-ListExpansion后优化器就要对等价改写后的每一个UNIONALL分支都执行同样的解析、决定执行计划的工作,也就是说,等价改写后的目标SQL的解析时间会随着UNIONALL分支的递增而递增。这意味着当IN后面的常量集合所包含的元素数量非常多的时候,做IN-ListExpansion仅解析的时间可能就会非常长,这就是IN-ListIterator通常会比FN-ListExpansion的效率高的原因。正是基于上述原因,做了IN-ListExpansion的等价改写SQL的执行效率并不一定会比原SQL高,这也就意味着IN-ListExpansion—定也是基于成本的,即只有当经过IN-ListExpansion后的等价改写SQL的成本值小于原SQL的成本值时,Oracle才会对目标SQL执行IN-ListExpansion。
IN-List Filter
IN-List Filter是针对IN后面是子查询的一种处理方法,优化器会把IN后面的子査询所对应的结果集当作过滤条件,并且走FILTER类型的执行计划IN后面是子查询,意味着IN后面是变量的集合;走的是FILTER类型的执行计划,意味着Oracle并没有对IN后面的子査询做子查询展幵。所以,能走IN-ListFiltei类型的执行计划就意味着目标SQL要满足如下两个条件:
(1)目标SQL的IN后面是子査询而不是常量的集合。
(2)Oracle未对目标SQL的IN后面的子査询做子査询展开。