zoukankan      html  css  js  c++  java
  • Oracle执行计划 讲解(二) .

    现在我们讲讲oracle执行计划里面每个参数的含义

    我们以下面的一个例子来讲解

    这里做个补充:trace的类型一共有以下几种

    序号

    命令

    解释

    1

    SET AUTOTRACE OFF

    此为默认值,即关闭Autotrace 

    2

    SET AUTOTRACE ON EXPLAIN

    只显示执行计划

    3

    SET AUTOTRACE ON STATISTICS

     只显示执行的统计信息

    4

    SET AUTOTRACE ON

     包含2,3两项内容

    5

    SET AUTOTRACE TRACEONLY

     与ON相似,但不显示语句的执行结果

     我喜欢SET AUTOTRACE TRACEONLY,我们以后的例子都是基于这种方式的

    1. SQL> select * from departments a where a.department_id in (select b.department_id from employees b where b.employee_id=205);  
    2.   
    3.   
    4. Execution Plan  
    5. ----------------------------------------------------------   
    6. Plan hash value: 2782876085  
    7.   
    8. ----------------------------------------------------------------------------------------------   
    9. | Id  | Operation                    | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
    10. ----------------------------------------------------------------------------------------------   
    11. |   0 | SELECT STATEMENT             |               |     1 |    27 |     2   (0)| 00:00:01 |  
    12. |   1 |  NESTED LOOPS                |               |     1 |    27 |     2   (0)| 00:00:01 |  
    13. |   2 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |  
    14. |*  3 |    INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
    15. |   4 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS   |    27 |   540 |     1   (0)| 00:00:01 |  
    16. |*  5 |    INDEX UNIQUE SCAN         | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |  
    17. ----------------------------------------------------------------------------------------------   
    18.   
    19. Predicate Information (identified by operation id):  
    20. ---------------------------------------------------   
    21.   
    22.    3 - access("B"."EMPLOYEE_ID"=205)  
    23.    5 - access("A"."DEPARTMENT_ID"="B"."DEPARTMENT_ID")  
    24.   
    25.   
    26. Statistics  
    27. ----------------------------------------------------------   
    28.           1  recursive calls  
    29.           0  db block gets  
    30.           4  consistent gets  
    31.           0  physical reads  
    32.           0  redo size  
    33.         749  bytes sent via SQL*Net to client  
    34.         492  bytes received via SQL*Net from client  
    35.           2  SQL*Net roundtrips to/from client  
    36.           0  sorts (memory)  
    37.           0  sorts (disk)  
    38.           1  rows processed  
    39.    
    SQL> select * from departments a where a.department_id in (select b.department_id from employees b where b.employee_id=205);
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2782876085
    
    ----------------------------------------------------------------------------------------------
    | Id  | Operation                    | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |               |     1 |    27 |     2   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS                |               |     1 |    27 |     2   (0)| 00:00:01 |
    |   2 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |
    |*  3 |    INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |
    |   4 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS   |    27 |   540 |     1   (0)| 00:00:01 |
    |*  5 |    INDEX UNIQUE SCAN         | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |
    ----------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       3 - access("B"."EMPLOYEE_ID"=205)
       5 - access("A"."DEPARTMENT_ID"="B"."DEPARTMENT_ID")
    
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
              4  consistent gets
              0  physical reads
              0  redo size
            749  bytes sent via SQL*Net to client
            492  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
     
    让我们来一行一行的看:

    一、表部分

    1、Plan hash value:

    1. Plan hash value: 2782876085  
    Plan hash value: 2782876085
    这一行是这一条语句的hash值,我们知道oracle对每条语句产生的执行计划放在share pool里面,第一次要经过硬解析,产生hash值。下次再执行该语句时候比较hash值,如果相同就不要执行硬解析。

    2、Operation( 操作)

    这里的东西就多了,就是把sql进行分解,让我一起看看上的sql,这段sql的第一步是employee_id=25,这里我们employee_id上面建了主键,建主键默认创建唯一索引。这里是用“=”进行限制的,所以走的unique scan方式。其他方式参考Oracle执行计划 讲解(一)内容 

    还有一个知识点,就是要知道表链接操作,见我的另外一篇文章()

    3、Name(被操作的对象)

    比如上例中的第二行operation(TABLE ACCESS BY INDEX ROWID)这里的TABLE对象为EMPLOYEES

    4、Row,有的地方也叫Cardinality(用plsqldev里面解释计划窗口)

    这里是数据查询的行数,比如说上个例子第4行,  departments 这张表就要扫描27行,然后和子查询(select b.department_id from employees b where b.employee_id=205)的值进行比较。如果使用=(注:大部分时候是不能用=来替换,这里是特例)就不一样了。

    1. SQL> select * from departments a where a.department_id = (select b.department_id from employees b where b.employee_id=205);  
    2.   
    3.   
    4. Execution Plan  
    5. ----------------------------------------------------------   
    6. Plan hash value: 3449260133  
    7.   
    8. -----------------------------------------------------------------------------------------------   
    9. | Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
    10. -----------------------------------------------------------------------------------------------   
    11. |   0 | SELECT STATEMENT              |               |     1 |    20 |     2   (0)| 00:00:01 |  
    12. |   1 |  TABLE ACCESS BY INDEX ROWID  | DEPARTMENTS   |     1 |    20 |     1   (0)| 00:00:01 |  
    13. |*  2 |   INDEX UNIQUE SCAN           | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |  
    14. |   3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |  
    15. |*  4 |     INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
    16. -----------------------------------------------------------------------------------------------   
    17.   
    18. Predicate Information (identified by operation id):  
    19. ---------------------------------------------------   
    20.   
    21.    2 - access("A"."DEPARTMENT_ID"= (SELECT /*+ */ "B"."DEPARTMENT_ID" FROM "EMPLOYEES"  
    22.               "B" WHERE "B"."EMPLOYEE_ID"=205))  
    23.    4 - access("B"."EMPLOYEE_ID"=205)  
    24.   
    25.   
    26. Statistics  
    27. ----------------------------------------------------------   
    28.           0  recursive calls  
    29.           0  db block gets  
    30.           4  consistent gets  
    31.           0  physical reads  
    32.           0  redo size  
    33.         749  bytes sent via SQL*Net to client  
    34.         492  bytes received via SQL*Net from client  
    35.           2  SQL*Net roundtrips to/from client  
    36.           0  sorts (memory)  
    37.           0  sorts (disk)  
    38.           1  rows processed  
    39.    
    SQL> select * from departments a where a.department_id = (select b.department_id from employees b where b.employee_id=205);
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3449260133
    
    -----------------------------------------------------------------------------------------------
    | Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |               |     1 |    20 |     2   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS BY INDEX ROWID  | DEPARTMENTS   |     1 |    20 |     1   (0)| 00:00:01 |
    |*  2 |   INDEX UNIQUE SCAN           | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |
    |   3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |
    |*  4 |     INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("A"."DEPARTMENT_ID"= (SELECT /*+ */ "B"."DEPARTMENT_ID" FROM "EMPLOYEES"
                  "B" WHERE "B"."EMPLOYEE_ID"=205))
       4 - access("B"."EMPLOYEE_ID"=205)
    
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
              4  consistent gets
              0  physical reads
              0  redo size
            749  bytes sent via SQL*Net to client
            492  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              1  rows processed
     

    5、Byte

    扫描的数据的字节数

    6、Cost

    这里上次讲过了,这里简单说下吧。

    cost没有单位,是一个相对值,是sql文以cbo方式解析执行时,供oracle用来评估cbo成本,选择执行计划用的。

    公式:Cost=(Single block I/O cost+ Multiblock I/O cost+   CPU cost)/sreadtim

    没有明确的含义,不过对比时就非常有用了。

    7、Time

    每段执行的时间

     

    二、Predicate Information

    这里列出的是过滤条件,一共有两种:

    1、索引(access)

    如上例中的access("B"."EMPLOYEE_ID"=205),这里使用索引作为过滤条件

    2、非索引(filter),看下面这里例子

    1. SQL> select employee_id  
    2.                   from employees c  
    3.                  where c.first_name = 'Steven'   2    3  ;  
    4.   
    5.   
    6. Execution Plan  
    7. ----------------------------------------------------------   
    8. Plan hash value: 1445457117  
    9.   
    10. -------------------------------------------------------------------------------   
    11. | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
    12. -------------------------------------------------------------------------------   
    13. |   0 | SELECT STATEMENT  |           |     1 |    11 |     3   (0)| 00:00:01 |  
    14. |*  1 |  TABLE ACCESS FULL| EMPLOYEES |     1 |    11 |     3   (0)| 00:00:01 |  
    15. -------------------------------------------------------------------------------   
    16.   
    17. Predicate Information (identified by operation id):  
    18. ---------------------------------------------------   
    19.   
    20.    1 - filter("C"."FIRST_NAME"='Steven')  
    21.   
    22.   
    23. Statistics  
    24. ----------------------------------------------------------   
    25.           1  recursive calls  
    26.           0  db block gets  
    27.           8  consistent gets  
    28.           0  physical reads  
    29.           0  redo size  
    30.         574  bytes sent via SQL*Net to client  
    31.         492  bytes received via SQL*Net from client  
    32.           2  SQL*Net roundtrips to/from client  
    33.           0  sorts (memory)  
    34.           0  sorts (disk)  
    35.           2  rows processed  
    SQL> select employee_id
                      from employees c
                     where c.first_name = 'Steven'   2    3  ;
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1445457117
    
    -------------------------------------------------------------------------------
    | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |           |     1 |    11 |     3   (0)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| EMPLOYEES |     1 |    11 |     3   (0)| 00:00:01 |
    -------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("C"."FIRST_NAME"='Steven')
    
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
              8  consistent gets
              0  physical reads
              0  redo size
            574  bytes sent via SQL*Net to client
            492  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              2  rows processed
    

    这里的过滤条件是FIRST_NAME,但是FIRST_NAME没有建立索引,这个时候使用filter,做标记。

    三、Statistics(统计信息)

    这里是重点要说的,如果看累了,可以去喝口水。O(∩_∩)O~

     AUTOTRACE Statistics列解释

    序号

    列名

    解释

    1

    recursive calls

    递归调查

    2

    db block gets

    从buffer cache中读取的block的数量

    3

    consistent gets

    从buffer cache中读取的undo数据的block的数量

    4

    physical reads

    从磁盘读取的block的数量

    5

    redo size

    DML生成的redo的大小

    6

    sorts (memory)

    在内存执行的排序量

    7

    sorts (disk)

    在磁盘上执行的排序量

     

    1、recursive calls重点讲解)

    官网对recursive calls 的解释如下:


           Recursive Calls:  Number of recursive calls generated at both the user and system level.    


           Oracle Database maintains tables used for internal processing. When it needs to change these tables, Oracle Database generates an internal SQL statement, which in turn generates a recursive call.In short, recursive calls are basically SQL performed on behalf of your SQL. So, if you had to parse the query, for example, you might have had to run some other queries to get data dictionary information. These would be recursive calls. Space management, security checks, calling PL/SQL from SQL—all incur recursive SQL calls。

           IBM上面也有一篇讲解,有兴趣可以看看

           http://publib.boulder.ibm.com/tividd/td/ITMD/SC23-4724-00/en_US/HTML/oraclepac510rg59.htm

           总结一下:

           当执行一条SQL语句时,产生的对其他SQL语句的调用,这些额外的语句称之为''recursive calls''或''recursive SQL statements''.

           在IBM 的那片文档里讲了触发Recursive Call的6种情况:  

           如:

           (1)我们做一条insert 时,没有足够的空间来保存row记录,Oracle 通过Recursive Call 来动态的分配空间。

           (2)执行DDL语句时,ORACLE总是隐含的发出一些recursive SQL语句,来修改数据字典信息,以便成功的执行该DDL语句。

           (3)当Shared Pool过小,data dictionary cache 也会相应的过小,没有足够的空间存储ORACLE的系统数据字典信息时,会发生Recursive calls,这些Recursive calls会将数据字典信息从硬盘读入内存中。

           (4)存储过程、触发器内如果有SQL调用的话,也会产生recursive SQL。

           在这些情况中,主要是对数据字典的查询,通常发生在第一次执行时,第二次执行一般可显著降低。递归需要消耗大量的资源,如果操作复杂,很容易出现问题!

         现在让我们举例说明:

    1. SQL> select * from employees;  
    2.   
    3. 107 rows selected.  
    4.   
    5.   
    6. Execution Plan  
    7. ----------------------------------------------------------   
    8. Plan hash value: 1445457117  
    9.   
    10. -------------------------------------------------------------------------------   
    11. | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
    12. -------------------------------------------------------------------------------   
    13. |   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |  
    14. |   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |  
    15. -------------------------------------------------------------------------------   
    16.   
    17.   
    18. Statistics  
    19. ----------------------------------------------------------   
    20.           1  recursive calls  
    21.           0  db block gets  
    22.          15  consistent gets  
    23.           0  physical reads  
    24.           0  redo size  
    25.        9997  bytes sent via SQL*Net to client  
    26.         569  bytes received via SQL*Net from client  
    27.           9  SQL*Net roundtrips to/from client  
    28.           0  sorts (memory)  
    29.           0  sorts (disk)  
    30.         107  rows processed  
    31.    
    SQL> select * from employees;
    
    107 rows selected.
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1445457117
    
    -------------------------------------------------------------------------------
    | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |
    -------------------------------------------------------------------------------
    
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
             15  consistent gets
              0  physical reads
              0  redo size
           9997  bytes sent via SQL*Net to client
            569  bytes received via SQL*Net from client
              9  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
            107  rows processed
     

    让我们再执行一遍
    1. SQL> select * from employees;  
    2.   
    3. 107 rows selected.  
    4.   
    5.   
    6. Execution Plan  
    7. ----------------------------------------------------------   
    8. Plan hash value: 1445457117  
    9.   
    10. -------------------------------------------------------------------------------   
    11. | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
    12. -------------------------------------------------------------------------------   
    13. |   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |  
    14. |   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |  
    15. -------------------------------------------------------------------------------   
    16.   
    17.   
    18. Statistics  
    19. ----------------------------------------------------------   
    20.           0  recursive calls  
    21.           0  db block gets  
    22.          15  consistent gets  
    23.           0  physical reads  
    24.           0  redo size  
    25.        9997  bytes sent via SQL*Net to client  
    26.         569  bytes received via SQL*Net from client  
    27.           9  SQL*Net roundtrips to/from client  
    28.           0  sorts (memory)  
    29.           0  sorts (disk)  
    30.         107  rows processed  
    31.    
    SQL> select * from employees;
    
    107 rows selected.
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1445457117
    
    -------------------------------------------------------------------------------
    | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |
    -------------------------------------------------------------------------------
    
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
             15  consistent gets
              0  physical reads
              0  redo size
           9997  bytes sent via SQL*Net to client
            569  bytes received via SQL*Net from client
              9  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
            107  rows processed
     

    在第一次查询employees时,产生了1次recursive Call,第二次查询的时候,因为数据字典的信息信息已经放在cache里,所以第二次的recursive call 为0. 如果第二次也没有完全cache,那么也是会产生recursive call,但次数比第一次少。

    其他的从字面上面就可以看出来了,不需要多解释了吧。

    摘自:http://blog.csdn.net/rulev5/article/details/6988180


  • 相关阅读:
    celery的使用和原理
    内核通知链
    数据流中的中位数
    二叉搜索树的后序遍历序列
    Javascript设计模式系统讲解与应用,JS设计模式详解
    微服务系列之ZooKeeper注册中心和Nacos注册中心
    微信小程序开发详解:小程序入门与实战-纯正商业级应用技术
    Java零基础该怎么去学习Java?学好Java应该如何去做?
    Flutter从入门到进阶实战携程网App项目详解
    Python升级3.6强力Django+杀手级Xadmin打造在线教育平台
  • 原文地址:https://www.cnblogs.com/gtaxmjld/p/5217142.html
Copyright © 2011-2022 走看看