Oracle 解释执行计划

      一. 执行计划树形结构

      执行计划展示的时候类似于一个表格形式,其实它是一个树形结构。该树形结构不仅阐述了SQL引擎执行操作的顺序,也阐明了它们之间的关系。树上的每一个节点都代表一个操作,比如表访问,连接,排序等。各操作之间存在父子关系,具体规则如下:

        1. 父有一个或多个子

        2. 子只有一个父

        3. 唯一没有父的是根节点

        4. 执行计划显示的时候,子缩进到父的右侧

        5. 父在他孩子前面(父ID小于孩子的ID)

        如下图所示:
    

       对应树形结构

 

 

        下面我们将分类解释各种执行计划

        

       二. 单独型操作

        我们将最多有一个孩子的操作叫做单独型操作,这种执行计划执行的时候符合以下规则:

        1. 孩子在父亲前面执行

        2. 每一个孩子只执行一次

        3. 每一个孩子向它父亲提供输出

        下图是一个例子: 

       

        对应树形结构
  

        根据规则1,孩子节点先执行,那么最先执行的是步骤3.

        1. 操作3通过访问型谓词job = 'clerk'扫描emp_job_i索引,在此过程它从索引中抽取了4个rowid(A-Rows指示为4),并传给操作2

        2. 操作2通过操作3传来的3个rowid访问emp表,对于每一个rowid有一行记录被选出,然后通过过滤型谓词sal<1200过滤。这个过滤导致一条记录被排除,最后将剩下的三条记录传给操作1.

        3. 操作1将操作2传过来的3条记录进行分组,变成两条记录,然后将数据返回给调用者。

 

        三. 非相关联合型操作

        我们把多个相互独立孩子的操作定义为非相关联合型操作,有如下操作属于这类型:and_equal,bitmap and,bitmap or,bitmap minus,concatenation,connect by without filtering,hash join,intersection,merge join,minus,mutil_table,insert,sql model,temp table transformation与union all。如果是这类型的操作,符合下述规则:

        1. 孩子在父亲前面执行。

        2. 孩子按顺序执行,从id最小到id最大。在开始下一个孩子操作之前,当前孩子操作必须全部执行完。

        3. 每一个孩子最多被执行一次,并且与其他孩子独立。

        4. 每一个孩子向他的父亲提供输出。

        下图是一个示例:         
      

         对应树形结构
  
 

        我们可以看出操作2,3,4是相互独立的,先执行操作2,返回14行给操作1。接着执行操作3,返回4行给操作1。最后执行操作4,返回1行给操作1.

 

        四. 相关联合操作

        我们把一个节点有多个孩子,其中一孩子控制其他孩子操作执行的操作定义为相关联合操作。这样的操作有如下几种:nested loops,update,filter,connect by with filtering和bitmap key iteration。

        相关联合操作符合下述规则:

        1. 孩子在父亲前面执行

        2. 最小id的孩子控制其他孩子的执行。

        3. 孩子从最小id执行,到最大id,但并不严格按照从小到大的顺序,比如操作1 开始了,还没结束,操作2也可能开始了。

        4. 只有第一个孩子是最多执行一次,所有的其他孩子或者执行多次,或者根本不执行。

        5. 不是每一个孩子都向父亲提供数据,有些孩子只是用来应用约束而已。

 

        下面就各种操作分别举一个例子:

        1. 嵌套循环(nested loops)操作

         嵌套循环操作用来连接两个记录集,它总是2个孩子。ID较小的孩子叫外循环或驱动行源,ID较大的孩子叫做内循环。这个操作的特征是外循环每返回一条记录内循环就得执行一次。如下图例子所示:
   
      

       对应树图
    

        a. 从树形结构图可以看出,操作1(嵌套循环操作)有2个孩子。其中,操作2的序号较小,所以先执行(开始外循环)

        b. 操作2扫描表emp,根据emp.comm is null 过滤,返回10条数据给父操作(操作1)

        c. 对于操作2返回的10条记录,对每一条记录执行一遍操作3,(内循环)

        d. 内循环由操作3和操作4组成,对于操作2返回的每一条记录先执行操作4,通过访问型谓词emp.deptno = dept.deptno扫描所有dept_pk,返回一个rowid给操作3

        e. 操作3通过操作4返回的一个rowid,访问dept表,一条记录被读取,然后根据过滤型谓词dept.dname <>'sales'过滤。判断这一条记录是否符合要求。

        f. 最终对操作2返回的10条记录,每一条执行一次内循环,过滤了2条,剩余8条返回给了操作1.

 

        2.  过滤(filter)操作

        过滤操作跟嵌套操作的不同点是,支持不定数目的孩子。可以是1个,2个,3个或者多个。如果非1个,它的功能就类似嵌套操作。第1个孩子驱动其他孩子的执行。

        举例说明如下:
    

        对应树形结构如下图所示:
  

 

        可以看出filter操作(操作1)有3个孩子

        a. 三孩子中操作2先执行(ID号最小)操作2扫描emp表,返回14条记录给操作1.

        b. 对于操作2返回的每一条记录都需要执行操作3和操作5,由于缓存的原因我们可以看到,操作3只执行了3次,操作5执行了8次,都小于14次。

        c. 对于操作5这个过滤限制条件,影响不到到操作2返回的14条记录,因为它的rows列为0.

        d. 对于操作3这个限制条件,有一条记录匹配到了操作2中的6条记录。因为操作3的rows列为1,总共有一条记录不符合条件,但是,操作1最终只接收到了8条数据,所以操作3匹配上的那一条数据过滤掉了操作2的6条数据。

        e. 所以通过操作3,和操作5的把关,过滤掉了操作2的6条数据,最终返回给了操作1 8条数据。

 

        3. 更新(update)操作

        例子如下:
      

      对应树形图 
  

          我们可以看到更新操作有3个孩子,孩子2驱动孩子3和孩子5执行

        a. 操作2执行全表扫描,得到14条记录返回给操作1,

        b. 操作2每返回一条记录都要驱动操作3和操作5执行一次

        c. 操作3要执行的话,先执行操作4.最后操作3总共只返回3个值给操作1,说明操作2中返回的14条记录中的deptno只有3个唯一的值,其他都是重复值。

        d. 操作5执行的时候,先执行操作6,但是操作5和6只执行一次,因为跟操作2返回的记录没有关系,尽管操作2要求操作5执行14次,但是每一次执行的结果都一样,所以只执行了一次。

        e. 操作1接收到操作3,操作5的返回值,更新操作2返回的14条记录。

猜你喜欢

转载自liwenshui322.iteye.com/blog/1781748