迭代操作
我将所有最多拥有一个可以多次执行的子操作的操作都视为迭代操作。你可以认为它们是在执行计划中实现了某种循环的操作。 INLIST ITERATOR和大部分拥有PARTITION前缀的操作(例如, PARTITION
RANGE ITERATOR)都是这种类型的操作。控制迭代操作运行的规则除了之前在10.3.1节中描述的规则之外,还有下面这条规则:
Ø 子操作可能会执行多次,也可能根本不执行。
下面是来自iterative.sql脚本输出的查询及其执行计划的例子:
select * FROM emp WHERE job
IN('CLERK','ANALYST');
这个执行计划与之前在独立操作中讨论的那个类似。唯一的区别是执行计划的一部分,因为INLIST ITERATOR操作的缘故,可以被执行多次。明确地说,迭代操作的子操作可以被执行多次。在本例中,操作2和3为IN条件中的每个不同值都执行了一次。
无关联组合操作
我将拥有多个可以独立执行的子操作的所有操作都称为无关联组合操作。以下这些操作都属于这种类型:AND-EQUAL、BITMAP AND、BITMAP OR、BITMAP MINUS、CONCATENATION、CONNECT BY WITHOUT FILTERING、HASH JOIN、INTERSECTION、MERGE JOIN、MINUS、MULTI-TABLE
INSERT、SQLMODEL、TEMP TABLE TRANSFORMATION 以及UNION-ALL。控制无关联操作的规则除了10.3.1节中描述的规则之外,还包括以下两条规则。
Ø 子操作顺序执行,从拥有最小ID 的操作开始直到拥有最大ID 的操作。在开始处理随后的子操作之前,必须完全执行当前的子操作。
Ø 一个子操作至多执行一次并且独立于其他所有的子操作。
注意 也有特别的情况,就是MERGE JOIN操作的子操作并非严格按照刚刚提到的两个规则执行。
下面是基于unrelated-combine.sql脚本生成输出的样例查询及其执行计划(其父-子关系见图 10-4):
select ename FROM emp
UNION ALL
select dname FROM dept
UNION ALL
select '%' FROM dual;
在这个执行计划中,无关联组合操作是UNION-ALL。其他三个是独立操作。通过应用之前给出的规则,你会发现执行计划执行的操作如下所示。
(1)操作0有一个子操作(1)。它不可能是第一个被执行的操作。
(2)操作1有三个子操作,其中操作2是按升序排列的第一个。因此,执行从操作2开始。
(3)操作2扫描emp表并将14行数据返回给它的父操作(1)。
(4)完全执行操作2之后,操作3开始执行。
(5)操作3扫描dept表并将4行数据返回给它的父操作(1)。
(6)完全执行操作3之后,操作4开始执行。
(7)操作4扫描dual表并将一条数据返回给它的父操作(1)。
(8)操作1基于它从子操作接收到的所有数据构建一个单独的19行数据的结果集,并将它们返回给父操作(0)。
(9)操作0将数据发送给调用者。
注意Starts列是如何清晰地展示每个操作只执行了一次的。
在表10-1中我提到过存在Starts列含义不同的情况。有时候这个列提供的是一个特定的内存结构被访问的次数,而不是执行的次数。正如下例演示的那样,MERGE JOIN操作可以用来展示这样的一个案例。
注意对于操作4,其Starts列的值为4。无论如何,也没有理由将数据排序四次。但其实此内存结构被访问了四次,因此才有了4这个值出现在Starts列上。对于每一行从dept表抽取出来的数据,该内存结构都被访问了一次
之前列出的所有其他操作都与本节展示的UNION-ALL操作拥有相同的行为。简而言之,无关联组合操作顺序执行它的每个子操作一次。很明显,由无关联组合操作自己执行的处理也不尽相同。