• 12 Using_explain_plan


    The row source tree is the core of the execution plan. The tree shows the following information:
        An ordering of the tables referenced by the statement
        An access method for each table mentioned in the statement
        A join method for tables affected by join operations in the statement
        Data operations like filter, sort, or aggregation
        
    注意查询计划, 例如:
        For example, in the following explain plan, the last step is a very unselective range scan that is executed 76563 times, 
        accesses 11432983 rows, throws away 99% of them, and retains 76563 rows. Why access 11432983 rows to realize that only 76563 rows are needed?
                Rows      Execution Plan
            --------  ----------------------------------------------------
                  12  SORT AGGREGATE
                   2   SORT GROUP BY
               76563    NESTED LOOPS
               76575     NESTED LOOPS
                  19      TABLE ACCESS FULL CN_PAYRUNS_ALL
               76570      TABLE ACCESS BY INDEX ROWID CN_POSTING_DETAILS_ALL
               76570       INDEX RANGE SCAN (object id 178321)
               76563     TABLE ACCESS BY INDEX ROWID CN_PAYMENT_WORKSHEETS_ALL
            11432983      INDEX RANGE SCAN (object id 186024)
    
    用 explain 来评估, 评估完以后, 要实测一下, 看执行是否满足要求
    
    如何使用 explain    (我们一般不这么用, 直接用 set autotrace on 或者 通过工具提供的自动就能看到)
        EXPLAIN PLAN FORSELECT last_name FROM employees;
        
        EXPLAIN PLAN
            SET STATEMENT_ID = 'st1' FOR        -- 指定你刚刚执行的statement id, 方便在plan table 中查找到你刚刚执行的statement
            SELECT last_name FROM employees;
    
    直接看 reading
    
        EX:
            SELECT phone_number FROM employees
             WHERE phone_number LIKE '650%';
             ---------------------------------------
            | Id  | Operation         | Name      |
            ---------------------------------------
            |   0 | SELECT STATEMENT  |           |
            |   1 |  TABLE ACCESS FULL| EMPLOYEES |
            ---------------------------------------
            This plan shows execution of a SELECT statement. The table employees is accessed using a full table scan.
            Every row in the table employees is accessed, and the WHERE clause criteria is evaluated for every row.
            The SELECT statement returns the rows meeting the WHERE clause criteria.
    
    Viewing Parallel Execution with EXPLAIN PLAN {先不考虑并行, 感觉用到不多} 并行计划与普通计划的不同, 基本上普通计划与并行计划是一样的, 但是也少部分地方不一样, 比如下边的多表连接 
        普通计划: 多表连接时, 肯定是以小表作为主表(drive table)
        并行计划: 多表连接时, 要以大表最为驱动表(主表)
        一般, 只有数据量非常巨大的情况, 才考虑使用并行查询.
    
        EX:
        
            CREATE TABLE emp2 AS SELECT * FROM employees;
            ALTER TABLE emp2 PARALLEL 2;
    
            EXPLAIN PLAN FOR
              SELECT SUM(salary) FROM emp2 GROUP BY department_id;
            SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());  -- 查看对应的执行计划
            
            --------------------------------------------------------------------------------------------------------
            | Id  | Operation                | Name     | Rows  | Bytes | Cost (%CPU) |    TQ  |IN-OUT| PQ Distrib |
            --------------------------------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT         |          |   107 |  2782 |     3 (34)  |        |      |            |
            |   1 |  PX COORDINATOR          |          |       |       |             |        |      |            |
            |   2 |   PX SEND QC (RANDOM)    | :TQ10001 |   107 |  2782 |     3 (34)  |  Q1,01 | P->S | QC (RAND)  |
            |   3 |    HASH GROUP BY         |          |   107 |  2782 |     3 (34)  |  Q1,01 | PCWP |            |
            |   4 |     PX RECEIVE           |          |   107 |  2782 |     3 (34)  |  Q1,01 | PCWP |            |
            |   5 |      PX SEND HASH        | :TQ10000 |   107 |  2782 |     3 (34)  |  Q1,00 | P->P | HASH       |
            |   6 |       HASH GROUP BY      |          |   107 |  2782 |     3 (34)  |  Q1,00 | PCWP |            |
            |   7 |        PX BLOCK ITERATOR |          |   107 |  2782 |     2 (0)   |  Q1,00 | PCWP |            |
            |   8 |         TABLE ACCESS FULL| EMP2     |   107 |  2782 |     2 (0)   |  Q1,00 | PCWP |            |
            --------------------------------------------------------------------------------------------------------
            The table EMP2 is scanned in parallel by one set of slaves while the aggregation for the GROUP BY is done by the second set. 
            The PX BLOCK ITERATOR row source represents the splitting up of the table EMP2 into pieces so as to divide the scan workload 
            between the parallel scan slaves. The PX SEND and PX RECEIVE row sources represent the pipe that connects the two slave sets 
            as rows flow up from the parallel scan, get repartitioned through the HASH table queue, and then read by and aggregated on the top slave set. 
            The PX SEND QC row source represents the aggregated values being sent to the QC in random (RAND) order. 
            The PX COORDINATOR row source represents the QC or Query Coordinator which controls and schedules the parallel plan appearing below it in the plan tree.
     
    Viewing Bitmap Indexes with EXPLAIN PLAN {先不考虑并行, bitmap索引在OLTP中不考虑}
        EX:
            SELECT * FROM t
            WHERE c1 = 2 
            AND c2 <> 6 
            OR c3 BETWEEN 10 AND 20;
            
        SELECT STATEMENT
           TABLE ACCESS T BY INDEX ROWID
              BITMAP CONVERSION TO ROWID
                 BITMAP OR
                    BITMAP MINUS
                       BITMAP MINUS
                          BITMAP INDEX C1_IND SINGLE VALUE
                          BITMAP INDEX C2_IND SINGLE VALUE
                       BITMAP INDEX C2_IND SINGLE VALUE
                    BITMAP MERGE
                       BITMAP INDEX C3_IND RANGE SCAN
    
    12.9 Viewing Partitioned Objects with EXPLAIN PLAN
        RANGE Partitioning
            CREATE TABLE emp_range 
            PARTITION BY RANGE(hire_date) 
            ( 
            PARTITION emp_p1 VALUES LESS THAN (TO_DATE('1-JAN-1992','DD-MON-YYYY')),
            PARTITION emp_p2 VALUES LESS THAN (TO_DATE('1-JAN-1994','DD-MON-YYYY')),
            PARTITION emp_p3 VALUES LESS THAN (TO_DATE('1-JAN-1996','DD-MON-YYYY')),
            PARTITION emp_p4 VALUES LESS THAN (TO_DATE('1-JAN-1998','DD-MON-YYYY')),
            PARTITION emp_p5 VALUES LESS THAN (TO_DATE('1-JAN-2001','DD-MON-YYYY')) 
            ) 
            AS SELECT * FROM employees; 
            EX 1 :            
            EXPLAIN PLAN FOR 
                SELECT * FROM emp_range;  
            ---------------------------------------------------------------------------------
            | Id  | Operation           | Name      | Rows  | Bytes | Cost  | Pstart| Pstop |
            ---------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT    |           |   105 | 13965 |     2 |       |       |
            |   1 |  PARTITION RANGE ALL|           |   105 | 13965 |     2 |     1 |     5 |
            |   2 |   TABLE ACCESS FULL | EMP_RANGE |   105 | 13965 |     2 |     1 |     5 |
            ---------------------------------------------------------------------------------
            In this example, the partition iterator covers all partitions (option ALL), because a predicate 
            was not used for pruning. The PARTITION_START and PARTITION_STOP columns of the PLAN_TABLE show access to all partitions from 1 to 5.
            EX 2 :
            EXPLAIN PLAN FOR 
              SELECT * FROM emp_range 
              WHERE hire_date >= TO_DATE('1-JAN-1996','DD-MON-YYYY');
            --------------------------------------------------------------------------------------
            | Id  | Operation                | Name      | Rows  | Bytes | Cost  | Pstart| Pstop |
            --------------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT         |           |     3 |   399 |     2 |       |       |
            |   1 |  PARTITION RANGE ITERATOR|           |     3 |   399 |     2 |     4 |     5 |
            |*  2 |   TABLE ACCESS FULL      | EMP_RANGE |     3 |   399 |     2 |     4 |     5 |
            --------------------------------------------------------------------------------------
            In the previous example, the partition row source iterates from partition 4 to 5 because the database prunes the other partitions using a predicate on hire_date
            EX 3 :
            EXPLAIN PLAN FOR 
              SELECT * FROM emp_range 
              WHERE hire_date < TO_DATE('1-JAN-1992','DD-MON-YYYY');
            ------------------------------------------------------------------------------------
            | Id  | Operation              | Name      | Rows  | Bytes | Cost  | Pstart| Pstop |
            ------------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT       |           |     1 |   133 |     2 |       |       |
            |   1 |  PARTITION RANGE SINGLE|           |     1 |   133 |     2 |     1 |     1 |
            |*  2 |   TABLE ACCESS FULL    | EMP_RANGE |     1 |   133 |     2 |     1 |     1 |
            ------------------------------------------------------------------------------------  
            In the previous example, only partition 1 is accessed and known at compile time; thus, there is no need for a partition row source.
        Hash Partitioning
            Oracle Database displays the same information for hash partitioned objects, except the partition row source name is 
            PARTITION HASH instead of PARTITION RANGE. Also, with hash partitioning, pruning is only possible using equality or IN-list predicates.
        还有一些其他类型的, 目前忽略,比如混合Partitioning      
     
    PLAN_TABLE Columns
        PLAN_TABLE 有哪些内容, 可以查看这, 这有详细文档
        
    The row source tree is the core of the execution plan. The tree shows the following information:
        An ordering of the tables referenced by the statement
        An access method for each table mentioned in the statement
        A join method for tables affected by join operations in the statement
        Data operations like filter, sort, or aggregation
        
    注意查询计划, 例如:
        For example, in the following explain plan, the last step is a very unselective range scan that is executed 76563 times, 
        accesses 11432983 rows, throws away 99% of them, and retains 76563 rows. Why access 11432983 rows to realize that only 76563 rows are needed?
                Rows      Execution Plan
            --------  ----------------------------------------------------
                  12  SORT AGGREGATE
                   2   SORT GROUP BY
               76563    NESTED LOOPS
               76575     NESTED LOOPS
                  19      TABLE ACCESS FULL CN_PAYRUNS_ALL
               76570      TABLE ACCESS BY INDEX ROWID CN_POSTING_DETAILS_ALL
               76570       INDEX RANGE SCAN (object id 178321)
               76563     TABLE ACCESS BY INDEX ROWID CN_PAYMENT_WORKSHEETS_ALL
            11432983      INDEX RANGE SCAN (object id 186024)
    
    用 explain 来评估, 评估完以后, 要实测一下, 看执行是否满足要求
    
    如何使用 explain    (我们一般不这么用, 直接用 set autotrace on 或者 通过工具提供的自动就能看到)
        EXPLAIN PLAN FORSELECT last_name FROM employees;
        
        EXPLAIN PLAN
            SET STATEMENT_ID = 'st1' FOR        -- 指定你刚刚执行的statement id, 方便在plan table 中查找到你刚刚执行的statement
            SELECT last_name FROM employees;
    
    直接看 reading
    
        EX:
            SELECT phone_number FROM employees
             WHERE phone_number LIKE '650%';
             ---------------------------------------
            | Id  | Operation         | Name      |
            ---------------------------------------
            |   0 | SELECT STATEMENT  |           |
            |   1 |  TABLE ACCESS FULL| EMPLOYEES |
            ---------------------------------------
            This plan shows execution of a SELECT statement. The table employees is accessed using a full table scan.
            Every row in the table employees is accessed, and the WHERE clause criteria is evaluated for every row.
            The SELECT statement returns the rows meeting the WHERE clause criteria.
    
    Viewing Parallel Execution with EXPLAIN PLAN {先不考虑并行, 感觉用到不多} 并行计划与普通计划的不同, 基本上普通计划与并行计划是一样的, 但是也少部分地方不一样, 比如下边的多表连接 
        普通计划: 多表连接时, 肯定是以小表作为主表(drive table)
        并行计划: 多表连接时, 要以大表最为驱动表(主表)
        一般, 只有数据量非常巨大的情况, 才考虑使用并行查询.
    
        EX:
        
            CREATE TABLE emp2 AS SELECT * FROM employees;
            ALTER TABLE emp2 PARALLEL 2;
    
            EXPLAIN PLAN FOR
              SELECT SUM(salary) FROM emp2 GROUP BY department_id;
            SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());  -- 查看对应的执行计划
            
            --------------------------------------------------------------------------------------------------------
            | Id  | Operation                | Name     | Rows  | Bytes | Cost (%CPU) |    TQ  |IN-OUT| PQ Distrib |
            --------------------------------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT         |          |   107 |  2782 |     3 (34)  |        |      |            |
            |   1 |  PX COORDINATOR          |          |       |       |             |        |      |            |
            |   2 |   PX SEND QC (RANDOM)    | :TQ10001 |   107 |  2782 |     3 (34)  |  Q1,01 | P->S | QC (RAND)  |
            |   3 |    HASH GROUP BY         |          |   107 |  2782 |     3 (34)  |  Q1,01 | PCWP |            |
            |   4 |     PX RECEIVE           |          |   107 |  2782 |     3 (34)  |  Q1,01 | PCWP |            |
            |   5 |      PX SEND HASH        | :TQ10000 |   107 |  2782 |     3 (34)  |  Q1,00 | P->P | HASH       |
            |   6 |       HASH GROUP BY      |          |   107 |  2782 |     3 (34)  |  Q1,00 | PCWP |            |
            |   7 |        PX BLOCK ITERATOR |          |   107 |  2782 |     2 (0)   |  Q1,00 | PCWP |            |
            |   8 |         TABLE ACCESS FULL| EMP2     |   107 |  2782 |     2 (0)   |  Q1,00 | PCWP |            |
            --------------------------------------------------------------------------------------------------------
            The table EMP2 is scanned in parallel by one set of slaves while the aggregation for the GROUP BY is done by the second set. 
            The PX BLOCK ITERATOR row source represents the splitting up of the table EMP2 into pieces so as to divide the scan workload 
            between the parallel scan slaves. The PX SEND and PX RECEIVE row sources represent the pipe that connects the two slave sets 
            as rows flow up from the parallel scan, get repartitioned through the HASH table queue, and then read by and aggregated on the top slave set. 
            The PX SEND QC row source represents the aggregated values being sent to the QC in random (RAND) order. 
            The PX COORDINATOR row source represents the QC or Query Coordinator which controls and schedules the parallel plan appearing below it in the plan tree.
     
    Viewing Bitmap Indexes with EXPLAIN PLAN {先不考虑并行, bitmap索引在OLTP中不考虑}
        EX:
            SELECT * FROM t
            WHERE c1 = 2 
            AND c2 <> 6 
            OR c3 BETWEEN 10 AND 20;
            
        SELECT STATEMENT
           TABLE ACCESS T BY INDEX ROWID
              BITMAP CONVERSION TO ROWID
                 BITMAP OR
                    BITMAP MINUS
                       BITMAP MINUS
                          BITMAP INDEX C1_IND SINGLE VALUE
                          BITMAP INDEX C2_IND SINGLE VALUE
                       BITMAP INDEX C2_IND SINGLE VALUE
                    BITMAP MERGE
                       BITMAP INDEX C3_IND RANGE SCAN
    
    12.9 Viewing Partitioned Objects with EXPLAIN PLAN
        RANGE Partitioning
            CREATE TABLE emp_range 
            PARTITION BY RANGE(hire_date) 
            ( 
            PARTITION emp_p1 VALUES LESS THAN (TO_DATE('1-JAN-1992','DD-MON-YYYY')),
            PARTITION emp_p2 VALUES LESS THAN (TO_DATE('1-JAN-1994','DD-MON-YYYY')),
            PARTITION emp_p3 VALUES LESS THAN (TO_DATE('1-JAN-1996','DD-MON-YYYY')),
            PARTITION emp_p4 VALUES LESS THAN (TO_DATE('1-JAN-1998','DD-MON-YYYY')),
            PARTITION emp_p5 VALUES LESS THAN (TO_DATE('1-JAN-2001','DD-MON-YYYY')) 
            ) 
            AS SELECT * FROM employees; 
            EX 1 :            
            EXPLAIN PLAN FOR 
                SELECT * FROM emp_range;  
            ---------------------------------------------------------------------------------
            | Id  | Operation           | Name      | Rows  | Bytes | Cost  | Pstart| Pstop |
            ---------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT    |           |   105 | 13965 |     2 |       |       |
            |   1 |  PARTITION RANGE ALL|           |   105 | 13965 |     2 |     1 |     5 |
            |   2 |   TABLE ACCESS FULL | EMP_RANGE |   105 | 13965 |     2 |     1 |     5 |
            ---------------------------------------------------------------------------------
            In this example, the partition iterator covers all partitions (option ALL), because a predicate 
            was not used for pruning. The PARTITION_START and PARTITION_STOP columns of the PLAN_TABLE show access to all partitions from 1 to 5.
            EX 2 :
            EXPLAIN PLAN FOR 
              SELECT * FROM emp_range 
              WHERE hire_date >= TO_DATE('1-JAN-1996','DD-MON-YYYY');
            --------------------------------------------------------------------------------------
            | Id  | Operation                | Name      | Rows  | Bytes | Cost  | Pstart| Pstop |
            --------------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT         |           |     3 |   399 |     2 |       |       |
            |   1 |  PARTITION RANGE ITERATOR|           |     3 |   399 |     2 |     4 |     5 |
            |*  2 |   TABLE ACCESS FULL      | EMP_RANGE |     3 |   399 |     2 |     4 |     5 |
            --------------------------------------------------------------------------------------
            In the previous example, the partition row source iterates from partition 4 to 5 because the database prunes the other partitions using a predicate on hire_date
            EX 3 :
            EXPLAIN PLAN FOR 
              SELECT * FROM emp_range 
              WHERE hire_date < TO_DATE('1-JAN-1992','DD-MON-YYYY');
            ------------------------------------------------------------------------------------
            | Id  | Operation              | Name      | Rows  | Bytes | Cost  | Pstart| Pstop |
            ------------------------------------------------------------------------------------
            |   0 | SELECT STATEMENT       |           |     1 |   133 |     2 |       |       |
            |   1 |  PARTITION RANGE SINGLE|           |     1 |   133 |     2 |     1 |     1 |
            |*  2 |   TABLE ACCESS FULL    | EMP_RANGE |     1 |   133 |     2 |     1 |     1 |
            ------------------------------------------------------------------------------------  
            In the previous example, only partition 1 is accessed and known at compile time; thus, there is no need for a partition row source.
        Hash Partitioning
            Oracle Database displays the same information for hash partitioned objects, except the partition row source name is 
            PARTITION HASH instead of PARTITION RANGE. Also, with hash partitioning, pruning is only possible using equality or IN-list predicates.
        还有一些其他类型的, 目前忽略,比如混合Partitioning      
     
    PLAN_TABLE Columns
        PLAN_TABLE 有哪些内容, 可以查看这, 这有详细文档
        
  • 相关阅读:
    用js添加网页标题时,在QQ里无效,标题栏空白
    用css3的@keyframes里设置transform:rotate(); 当控制动画暂停:animation-play-state:paused暂停,在微信和safari里无效
    Python可变序列中的一些坑,记得多注意
    你知道?Python 中的序列类型支持哪些公共操作吗?
    用 python print() 函数实现的三个特效
    教你使用python生成器重构提取数据方法,来优化你的爬虫代码
    python中主线程与子线程的结束顺序,你知道吗?
    python装饰器实现对异常代码出现进行自动监控
    Python教程:高效率遍历文件夹寻找重复文件
    python教程: filter()和reduce()函数用法详解
  • 原文地址:https://www.cnblogs.com/moveofgod/p/4660513.html
Copyright © 2020-2023  润新知