• xplan-打印执行顺序



    -- ----------------------------------------------------------------------------------------------
    --
    -- Script:       xplan.sql
    --
    -- Author:       Adrian Billington
    --              
    --
    -- Description:  Creates a package named XPLAN as a wrapper over DBMS_XPLAN. Provides access to
    --               the following DBMS_XPLAN pipelined functions:
    --
    --                  1. DISPLAY;
    --                  2. DISPLAY_CURSOR;
    --                  3. DISPLAY_AWR (optional - see Notes section for licence implications).
    --
    --               The XPLAN wrapper package has one purpose: to include an "order" column in the
    --               plan output to show the order in which plan operations are performed. See the
    --               following example for details.
    --
    -- Example:      DBMS_XPLAN output (format BASIC):
    --               ------------------------------------------------
    --               | Id  | Operation                    | Name    |
    --               ------------------------------------------------
    --               |   0 | SELECT STATEMENT             |         |
    --               |   1 |  MERGE JOIN                  |         |
    --               |   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |
    --               |   3 |    INDEX FULL SCAN           | PK_DEPT |
    --               |   4 |   SORT JOIN                  |         |
    --               |   5 |    TABLE ACCESS FULL         | EMP     |
    --               ------------------------------------------------
    --
    --               Equivalent XPLAN output (format BASIC):
    --               --------------------------------------------------------
    --               | Id  | Order | Operation                    | Name    |
    --               --------------------------------------------------------
    --               |   0 |     6 | SELECT STATEMENT             |         |
    --               |   1 |     5 |  MERGE JOIN                  |         |
    --               |   2 |     2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |
    --               |   3 |     1 |    INDEX FULL SCAN           | PK_DEPT |
    --               |   4 |     4 |   SORT JOIN                  |         |
    --               |   5 |     3 |    TABLE ACCESS FULL         | EMP     |
    --               --------------------------------------------------------
    --
    -- Usage:        SELECT * FROM TABLE(XPLAN.DISPLAY(...));
    --               SELECT * FROM TABLE(XPLAN.DISPLAY_CURSOR(...));
    --               SELECT * FROM TABLE(XPLAN.DISPLAY_AWR(...));
    --
    --               Usage for XPLAN is exactly the same as for DBMS_XPLAN. See the DBMS_XPLAN
    --               documentation for all options.
    --
    --               Note that the only exception to this is that XPLAN.DISPLAY does not contain
    --               the FILTER_PREDS parameter available in 10.2+ versions of DBMS_XPLAN.DISPLAY
    --               (this parameter enables us to limit the data being returned from an Explain
    --               Plan but is of quite limited use).
    --
    --               See the Notes section for details on the licensing implications of using
    --               XPLAN.DISPLAY_AWR.
    --
    -- Versions:     This utility will work for all versions of 10g and upwards.
    --
    -- Required:     1) PLAN_TABLE of at least 10.1 format
    --
    --               2) Either:
    --                     SELECT ANY DICTIONARY
    --                  Or:
    --                     SELECT on V$DATABASE
    --                     SELECT on V$SQL_PLAN
    --                     SELECT on V$SESSION
    --                     SELECT on V$MYSTAT
    --                     SELECT on DBA_HIST_SQL_PLAN
    --
    --               3) CREATE TYPE, CREATE PROCEDURE
    --
    -- Notes:        *** IMPORTANT: PLEASE READ ***
    --
    --               1) Oracle license implications
    --                  ---------------------------
    --                  The AWR functionality of XPLAN accesses a DBA_HIST% view which means
    --                  that it requires an Oracle Diagnostic Pack license. The XPLAN.DISPLAY_AWR
    --                  pipelined function is therefore disabled by default. It can be included
    --                  by modifying two substitution variables at the start of the script. Please
    --                  ensure that you are licensed to use this feature: the author accepts
    --                  no responsibility for any use of this functionality in an unlicensed database.
    --
    -- Installation: Installation requires SQL*Plus or any IDE that supports substitution
    --               variables and SQL*Plus SET commands. To install, simply run the script in
    --               the target schema.
    --
    -- Creates:      1) XPLAN_OT object type
    --               2) XPLAN_NTT collection type
    --               3) XPLAN package
    --
    -- Removal:      1) DROP PACKAGE xplan;
    --               3) DROP TYPE xplan_ntt;
    --               4) DROP TYPE xplan_ot;
    --
    --
    -- ----------------------------------------------------------------------------------------------

    --
    -- Define the "commenting-out" substitution variables for the AWR elements of this utility. The
    -- default is commented out. To include the AWR functionality, change the variables to " " (i.e.
    -- a single space).
    --

    SET DEFINE ON
    DEFINE _awr_start = "/*"
    DEFINE _awr_end   = "*/"

    --
    -- Supporting types for the pipelined functions...
    --

    CREATE OR REPLACE TYPE xplan_ot AS OBJECT( plan_table_output VARCHAR2(300) );
    /

    CREATE OR REPLACE TYPE xplan_ntt AS  TABLE OF xplan_ot;
    /

    --
    -- Xplan package...
    --

    CREATE OR REPLACE PACKAGE xplan AS

       FUNCTION display( p_table_name   IN VARCHAR2 DEFAULT 'PLAN_TABLE',
                         p_statement_id IN VARCHAR2 DEFAULT NULL,
                         p_format       IN VARCHAR2 DEFAULT 'TYPICAL' )
          RETURN xplan_ntt PIPELINED;

       FUNCTION display_cursor( p_sql_id          IN VARCHAR2 DEFAULT NULL,
                                p_cursor_child_no IN INTEGER  DEFAULT 0,
                                p_format          IN VARCHAR2 DEFAULT 'TYPICAL' )
          RETURN xplan_ntt PIPELINED;

    &&_awr_start
       FUNCTION display_awr( p_sql_id          IN VARCHAR2,
                             p_plan_hash_value IN INTEGER  DEFAULT NULL,
                             p_db_id           IN INTEGER  DEFAULT NULL,
                             p_format          IN VARCHAR2 DEFAULT 'TYPICAL' )
          RETURN xplan_ntt PIPELINED;
    &&_awr_end
         
    END xplan;
    /

    CREATE OR REPLACE PACKAGE BODY xplan AS

       TYPE ntt_order_map_binds IS TABLE OF VARCHAR2(100);

       TYPE aat_order_map IS TABLE OF PLS_INTEGER
          INDEX BY PLS_INTEGER;

       g_map  aat_order_map;
       g_hdrs PLS_INTEGER;
       g_len  PLS_INTEGER;
       g_pad  VARCHAR2(300);

       ----------------------------------------------------------------------------
       PROCEDURE reset_state IS
       BEGIN
          g_hdrs := 0;
          g_len  := 0;
          g_pad  := NULL;
          g_map.DELETE;
       END reset_state;

       ----------------------------------------------------------------------------
       PROCEDURE build_order_map( p_sql   IN VARCHAR2,
                                  p_binds IN ntt_order_map_binds ) IS

          TYPE rt_id_data IS RECORD
          ( id  PLS_INTEGER
          , ord PLS_INTEGER );

          TYPE aat_id_data IS TABLE OF rt_id_data
             INDEX BY PLS_INTEGER;

          aa_ids   aat_id_data;
          v_cursor SYS_REFCURSOR;
          v_sql    VARCHAR2(32767);

       BEGIN

          -- Build SQL template...
          -- ---------------------
          v_sql := 'WITH sql_plan_data AS ( ' ||
                            p_sql || '
                            )
                    ,    hierarchical_sql_plan_data AS (
                            SELECT id
                            FROM   sql_plan_data
                            START WITH id = 0
                            CONNECT BY PRIOR id = parent_id
                            ORDER SIBLINGS BY id DESC
                            )
                    SELECT id
                    ,      ROW_NUMBER() OVER (ORDER BY ROWNUM DESC) AS ord
                    FROM   hierarchical_sql_plan_data';

          -- Binds will differ according to plan type...
          -- -------------------------------------------
          CASE p_binds.COUNT
             WHEN 0
             THEN
                OPEN v_cursor FOR v_sql;
             WHEN 1
             THEN
                OPEN v_cursor FOR v_sql USING p_binds(1);
             WHEN 2
             THEN
                OPEN v_cursor FOR v_sql USING p_binds(1),
                                              TO_NUMBER(p_binds(2));
             WHEN 3
             THEN
                OPEN v_cursor FOR v_sql USING p_binds(1),
                                              TO_NUMBER(p_binds(2)),
                                              TO_NUMBER(p_binds(3));           
          END CASE;

          -- Fetch the ID and order data...
          -- ------------------------------
          FETCH v_cursor BULK COLLECT INTO aa_ids;
          CLOSE v_cursor;

          -- Populate the order map...
          -- -------------------------
          FOR i IN 1 .. aa_ids.COUNT LOOP     
             g_map(aa_ids(i).id) := aa_ids(i).ord;
          END LOOP;

          -- Use the map to determine padding needed to slot in our order column...
          -- ----------------------------------------------------------------------
          IF g_map.COUNT > 0 THEN
             g_len := LEAST(LENGTH(g_map.LAST) + 7, 8);
             g_pad := LPAD('-', g_len, '-');
          END IF;

       END build_order_map;

       ----------------------------------------------------------------------------
       FUNCTION prepare_row( p_curr IN VARCHAR2,
                             p_next IN VARCHAR2 ) RETURN xplan_ot IS

          v_id  PLS_INTEGER;
          v_row VARCHAR2(4000);
          v_hdr VARCHAR2(64) := '%|%Id%|%Operation%|%';

       BEGIN

          -- Intercept the plan section to include a new column for the
          -- the operation order that we mapped earlier. The plan output
          -- itself will be bound by the 2nd, 3rd and 4th dashed lines.
          -- We need to add in additional dashes, the order column heading
          -- and the order value itself...
          -- -------------------------------------------------------------

          IF p_curr LIKE '---%' THEN
     
             IF p_next LIKE v_hdr THEN
                g_hdrs := 1;
                v_row := g_pad || p_curr;
             ELSIF g_hdrs BETWEEN 1 AND 3 THEN
                g_hdrs := g_hdrs + 1;
                v_row := g_pad || p_curr;
             ELSE
                v_row := p_curr;
             END IF;

          ELSIF p_curr LIKE v_hdr THEN

             v_row := REGEXP_REPLACE(
                         p_curr, '|',
                         RPAD('|', GREATEST(g_len-7, 2)) || 'Order |',
                         1, 2
                         );

          ELSIF REGEXP_LIKE(p_curr, '^|[* 0-9]+|') THEN

             v_id := REGEXP_SUBSTR(p_curr, '[0-9]+');
             v_row := REGEXP_REPLACE(
                         p_curr, '|',
                         '|' || LPAD(g_map(v_id), GREATEST(g_len-8, 6)) || ' |',
                         1, 2
                         );
          ELSE
             v_row := p_curr;
          END IF;

          RETURN xplan_ot(v_row);

       END prepare_row;

       ----------------------------------------------------------------------------
       FUNCTION display( p_table_name   IN VARCHAR2 DEFAULT 'PLAN_TABLE',
                         p_statement_id IN VARCHAR2 DEFAULT NULL,
                         p_format       IN VARCHAR2 DEFAULT 'TYPICAL' )
          RETURN xplan_ntt PIPELINED IS

          v_plan_table   VARCHAR2(128) := NVL(p_table_name, 'PLAN_TABLE');
          v_sql          VARCHAR2(512);
          v_binds        ntt_order_map_binds := ntt_order_map_binds();

       BEGIN
      
          reset_state();

          -- Prepare the inputs for the order map...
          -- ---------------------------------------
          v_sql := 'SELECT id, parent_id
                    FROM   ' || v_plan_table || '
                    WHERE  plan_id = (SELECT MAX(plan_id)
                                      FROM   ' || v_plan_table || '
                                      WHERE  id = 0 %bind%)
                    ORDER  BY id';

          IF p_statement_id IS NULL THEN
             v_sql := REPLACE(v_sql, '%bind%');
          ELSE
             v_sql := REPLACE(v_sql, '%bind%', 'AND statement_id = :bv_statement_id');
             v_binds := ntt_order_map_binds(p_statement_id);
          END IF;
         
          -- Build the order map...
          -- --------------------------------------------------
          build_order_map(v_sql, v_binds);

          -- Now we can call DBMS_XPLAN to output the plan...
          -- ------------------------------------------------
          FOR r_plan IN ( SELECT plan_table_output AS p
                          ,      LEAD(plan_table_output) OVER (ORDER BY ROWNUM) AS np
                          FROM   TABLE(
                                    DBMS_XPLAN.DISPLAY(
                                       v_plan_table, p_statement_id, p_format
                                       ))
                          ORDER  BY
                                 ROWNUM)
          LOOP
             IF g_map.COUNT > 0 THEN
                PIPE ROW (prepare_row(r_plan.p, r_plan.np));
             ELSE
                PIPE ROW (xplan_ot(r_plan.p));
             END IF;
          END LOOP;

          reset_state();
          RETURN;

       END display;

       ----------------------------------------------------------------------------
       FUNCTION display_cursor( p_sql_id          IN VARCHAR2 DEFAULT NULL,
                                p_cursor_child_no IN INTEGER  DEFAULT 0,
                                p_format          IN VARCHAR2 DEFAULT 'TYPICAL' )
          RETURN xplan_ntt PIPELINED IS

          v_sql_id   v$sql_plan.sql_id%TYPE;
          v_child_no v$sql_plan.child_number%TYPE;
          v_sql      VARCHAR2(256);
          v_binds    ntt_order_map_binds := ntt_order_map_binds();

       BEGIN

          reset_state();

          -- Set a SQL_ID if default parameters passed...
          -- --------------------------------------------
          IF p_sql_id IS NULL THEN
             SELECT prev_sql_id, prev_child_number
             INTO   v_sql_id, v_child_no
             FROM   v$session
             WHERE  sid = (SELECT m.sid FROM v$mystat m WHERE ROWNUM = 1)
             AND    username IS NOT NULL
             AND    prev_hash_value <> 0;
          ELSE
             v_sql_id := p_sql_id;
             v_child_no := p_cursor_child_no;
          END IF;

          -- Prepare the inputs for the order mapping...
          -- -------------------------------------------
          v_sql := 'SELECT id, parent_id
                    FROM   v$sql_plan
                    WHERE  sql_id = :bv_sql_id
                    AND    child_number = :bv_child_no';

          v_binds := ntt_order_map_binds(v_sql_id, v_child_no);
         
          -- Build the plan order map from the SQL...
          -- ----------------------------------------
          build_order_map(v_sql, v_binds);

          -- Now we can call DBMS_XPLAN to output the plan...
          -- ------------------------------------------------
          FOR r_plan IN ( SELECT plan_table_output AS p
                          ,      LEAD(plan_table_output) OVER (ORDER BY ROWNUM) AS np
                          FROM   TABLE(
                                    DBMS_XPLAN.DISPLAY_CURSOR(
                                       v_sql_id, v_child_no, p_format
                                       ))
                          ORDER  BY
                                 ROWNUM)
          LOOP
             IF g_map.COUNT > 0 THEN
                PIPE ROW (prepare_row(r_plan.p, r_plan.np));
             ELSE
                PIPE ROW (xplan_ot(r_plan.p));
             END IF;
          END LOOP;

          reset_state();
          RETURN;

       END display_cursor;

    &_awr_start
       ----------------------------------------------------------------------------
       FUNCTION display_awr( p_sql_id          IN VARCHAR2,
                             p_plan_hash_value IN INTEGER  DEFAULT NULL,
                             p_db_id           IN INTEGER  DEFAULT NULL,
                             p_format          IN VARCHAR2 DEFAULT 'TYPICAL' )
          RETURN xplan_ntt PIPELINED IS
         
          v_sql      VARCHAR2(256);
          v_binds    ntt_order_map_binds := ntt_order_map_binds();

       BEGIN
      
          reset_state();

          -- Prepare the SQL for the order mapping...
          -- ----------------------------------------
          v_sql := 'SELECT id, parent_id
                    FROM   dba_hist_sql_plan
                    WHERE  sql_id = :bv_sql_id
                    AND    plan_hash_value = :bv_plan_hash_value
                    AND    dbid = :bv_dbid';

          -- Determine all plans for the sql_id...
          -- -------------------------------------     
          FOR r_awr IN (SELECT DISTINCT
                               sql_id
                        ,      plan_hash_value
                        ,      dbid
                        FROM   dba_hist_sql_plan
                        WHERE  sql_id = p_sql_id
                        AND    plan_hash_value = NVL(p_plan_hash_value, plan_hash_value)
                        AND    dbid = NVL(p_db_id, (SELECT dbid FROM v$database))
                        ORDER  BY
                               plan_hash_value)
          LOOP
         
             -- Prepare the binds and build the order map...
             -- --------------------------------------------
             v_binds := ntt_order_map_binds(r_awr.sql_id,
                                            r_awr.plan_hash_value,
                                            r_awr.dbid);
                                          
             -- Build the plan order map from the SQL...
             -- ----------------------------------------
             build_order_map(v_sql, v_binds);

             -- Now we can call DBMS_XPLAN to output the plan...
             -- ------------------------------------------------
             FOR r_plan IN ( SELECT plan_table_output AS p
                             ,      LEAD(plan_table_output) OVER (ORDER BY ROWNUM) AS np
                             FROM   TABLE(
                                       DBMS_XPLAN.DISPLAY_AWR(
                                          r_awr.sql_id, r_awr.plan_hash_value,
                                          r_awr.dbid, p_format
                                          ))
                             ORDER  BY
                                    ROWNUM)
             LOOP
                IF g_map.COUNT > 0 THEN
                   PIPE ROW (prepare_row(r_plan.p, r_plan.np));
                ELSE
                   PIPE ROW (xplan_ot(r_plan.p));
                END IF;
             END LOOP;

          END LOOP;

          reset_state();
          RETURN;
         
       END display_awr;
    &_awr_end

    END xplan;
    /

    UNDEFINE _awr_start
    UNDEFINE _awr_end

  • 相关阅读:
    Linux篇---ftp服务器的搭建
    【Spark篇】---SparkStreaming+Kafka的两种模式receiver模式和Direct模式
    【Spark篇】---Spark故障解决(troubleshooting)
    【Spark篇】---Spark解决数据倾斜问题
    【Spark篇】---Spark调优之代码调优,数据本地化调优,内存调优,SparkShuffle调优,Executor的堆外内存调优
    【Redis篇】Redis持久化方式AOF和RDB
    【Redis篇】Redis集群安装与初始
    【Redis篇】初始Redis与Redis安装
    Git提示“warning: LF will be replaced by CRLF”
    Git 忽略特殊文件
  • 原文地址:https://www.cnblogs.com/wcwen1990/p/6660455.html
Copyright © 2020-2023  润新知