【性能优化】 之 变量邦定

1.用示例说明绑定变量的应用领域是OLTP而不是OLAP。<br>
 2.用示例演示一次硬分析(hard parse)和一次软分析(soft  parse),以及一次更软的分析(softer soft parse),并对给出演示结果。<br>
 3.用示例演示一次分析,多次执行的示例,并对给出演示结果。<br>
 4.演示一个父游标产生3个子游标的示例,并分别说明每个子游标产生的原因。<br>
 5.演示ACS(adaptiver cursor sharing)的效果。<br>

 ==================================================================================
1.用示例说明绑定变量的应用领域是OLTP而不是OLAP。<br>

答:
    1.1 示例说明
    SQL> drop table t1 purge;

    Table dropped.

    SQL> create table t1 as select * from dba_objects;

    Table created.

    SQL> alter session set tracefile_identifier='bind_var';

    Session altered.

    SQL> alter session set sql_trace=true;

    Session altered.

    SQL> begin
      2  for i in 1..100 loop
      3  execute immediate 'select * from t1 where object_id=:i' using i;
      4  end loop;
      5  end;
      6  /

    PL/SQL procedure successfully completed.

    SQL> alter session set sql_trace=false;

    Session altered.

    SQL> select sql_text,pase_calls,loads,executions from v$sql where sql_text like 'select * from t1 where %';
    select sql_text,pase_calls,loads,executions from v$sql where sql_text like 'select * from t1 where %'
                    *
    ERROR at line 1:
    ORA-00904: "PASE_CALLS": invalid identifier


    SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from t1%';

    SQL_TEXT                                    PARSE_CALLS            LOADS    EXECUTIONS
    -----------                                    ----------            ----    ----------
    select * from t1 where object_id=:i            1                    1        100


    从上面的查询中,可以看到,在重复执行了100次的查询中,有1次的硬解析,


    1.2 下面再进行一个非绑定变量的SQL 执行情况:

    SQL> alter session set sql_trace=true;              启动trace功能

    Session altered.

    SQL> begin

    for i in 1..100 loop

    execute immediate 'select * from T where object_id='||i;

    end loop;

    end;

    /

    PL/SQL procedure successfully completed.

    我们对一条sql执行了100次没有采用绑定变量技术,oracle对这条sql要硬解析100次,执行100次,CPU的消耗就有了100次。

    SQL> alter session set sql_trace=false;             关闭trace功能

    Session altered.

    LEO1@LEO1> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from T1 where %' order by 1;

    SQL_TEXT                                PARSE_CALLS      LOADS EXECUTIONS
    ----------------------                    ---------- ---------- ----------
    select * from t1 where object_id=1        1          1          1
    ....
    select * from t1 where object_id=100      1          1          1


    100 rows selected.

    SQL>


    再来查看一下跟踪文件:

    1.3 使用绑定变量跟踪部分:

    D:\app\oracle\diag\rdbms\orcl\orcl\trace>tkprof orcl_ora_5528_bind_var.trc out_b
    ind.log

    TKPROF: Release 11.2.0.3.0 - Development on 星期四 12月 5 17:58:35 2013

    Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.





    SQL ID: 28gj7tsy13xq8 Plan Hash: 3617692013

    select *
    from
     t1 where object_id=:i


    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse        1      0.00       0.00          0          0          0           0
    Execute    100      0.01       0.00          0          1          0           0
    Fetch        0      0.00       0.00          0          0          0           0
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total      101      0.01       0.00          0          1          0           0

    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 84     (recursive depth: 1)
    Number of plan statistics captured: 1

    Rows (1st) Rows (avg) Rows (max)  Row Source Operation
    ---------- ---------- ----------  ---------------------------------------------------
             0          0          0  TABLE ACCESS FULL T1 (cr=0 pr=0 pw=0 time=3 us cost=305 size=2484 card=12)

    ********************************************************************************


    1.4 没使用绑定变量跟踪部分:
    begin
    for i in 1..100 loop
    execute immediate 'select * from t1 where object_id='||i;
    end loop;
    end;

    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse        1      0.00       0.00          0          0          0           0
    Execute      1      0.00       0.01          0          0          0           1
    Fetch        0      0.00       0.00          0          0          0           0
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total        2      0.00       0.02          0          0          0           1

    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 84  
    ********************************************************************************

    SQL ID: 9vx4vjbr7qrnn Plan Hash: 2586623307

    SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE
      NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false')
      NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"),
      NVL(SUM(C2),:"SYS_B_1")
    FROM
     (SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T1") FULL("T1")
      NO_PARALLEL_INDEX("T1") */ :"SYS_B_2" AS C1, CASE WHEN "T1"."OBJECT_ID"=
      :"SYS_B_3" THEN :"SYS_B_4" ELSE :"SYS_B_5" END AS C2 FROM "TANG"."T1"
      SAMPLE BLOCK (:"SYS_B_6" , :"SYS_B_7") SEED (:"SYS_B_8") "T1") SAMPLESUB


    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse      100      0.00       0.01          0          0          0           0
    Execute    100      0.00       0.00          0          0          0           0
    Fetch      100      0.18       0.16          0       6900          0         100
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total      300      0.18       0.17          0       6900          0         100

    Misses in library cache during parse: 1
    Misses in library cache during execute: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 84     (recursive depth: 2)
    Number of plan statistics captured: 3

    Rows (1st) Rows (avg) Rows (max)  Row Source Operation
    ---------- ---------- ----------  ---------------------------------------------------
             1          1          1  SORT AGGREGATE (cr=69 pr=0 pw=0 time=1701 us)
          4452       4452       4452   TABLE ACCESS SAMPLE T1 (cr=69 pr=0 pw=0 time=4608 us cost=19 size=128650 card=5146)

    ********************************************************************************



    SQL ID: d44dqxf5hgz0j Plan Hash: 3617692013

    select *
    from
     t1 where object_id=1


    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse        1      0.00       0.00          0          1          0           0
    Execute      1      0.00       0.00          0          0          0           0
    Fetch        0      0.00       0.00          0          0          0           0
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total        2      0.00       0.00          0          1          0           0

    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 84     (recursive depth: 1)
    Number of plan statistics captured: 1

    Rows (1st) Rows (avg) Rows (max)  Row Source Operation
    ---------- ---------- ----------  ---------------------------------------------------
             0          0          0  TABLE ACCESS FULL T1 (cr=0 pr=0 pw=0 time=2 us cost=305 size=2484 card=12)

    ********************************************************************************



    从上面使用了绑定变量的方法,可以看到,执行100次,只有一次硬解析。
    而非绑定变量方法,每一次的SQL,都是独立解析及运行的。CPU的消耗也可以看到两者的差异。

    

    1.4.绑定变量的SQL代码优化,主要是减少了SQL 的硬解析。

    1.5 在OLTP 架构中,
        1.5.1 SQL 简单而非常相似,并且结果集非常小,不同的只是谓语部分。所以这种情况下,执行计划都是一样的。
        在执行计划都几乎不变的情况下。ORACLE使用变量来代替谓词,使用同一个执行计划,是非常合理的。

        1.5.2 SQL 重复率很高,或者只是谓词条件不同而已;
        1.5.3 SQL 语句执行条件多,条数越多,CPU的消耗就大,这种情况下,减少硬解析就越有意义了。

    1.6 在OLAP 架构中

        1.6.1 SQL 执行的重复率低,大部分都只是批量,定时加载,
        1.6.2 数据聚合操作频繁;
        1.6.3 SQL 语句执行条数少,SQL 硬解析对系统性能影响较小,更多的瓶颈是IO,
        1.6.3 分区表的查询,相对也不太适合绑定变量技术.
        综上所述,所以说OLAP不适合使用绑定变量。

---------------------------------------------------------------------------------------------
 2.用示例演示一次硬分析(hard parse)和一次软分析(soft  parse),以及一次更软的分析(softer soft parse),并对给出演示结果。<br>

    ORACLE SQL 执行过程:
     数据库端收到一个sql 请求后,会建立一个进程,与用户进程组成一个会话,在pga区处理sql 请求。
     然后开始访问sga的sharl pool,并解析SQL,生成执行计划;
    
     如果一条SQL 在share pool中已经存在,那么ORACLE 只需奖已存在的执行计划应用到当前SQL上,去访问数据即可。这种情况称之为软解析(SOFT PARSE);
    如果在共享汇中没有找到SQL的执行计划,ORACLE就会对SQL 进行: 语法解析,语义解析,生成执行计划等动作,这些解析步骤就总称为硬解析(HARD PARSE);
    而这些解析步骤是比较消耗资源的。

    还有另外一种解析是:缓存游标信息,后续的SQL不用再去打开一个新的cursor,而是直接去share pool 中找到已查询过的数据,这样就更省资源,
    成为更软的解析(SOFTER SOFT PARSE).

    2.1 演示数据准备及第一次执行效果
    SQL> drop table t2 purge;

    Table dropped.

    SQL> create table t2 as select * from dba_objects;

    Table created.

    SQL> select count(0) from t2;

      COUNT(0)
    ----------
         76429

    查询SQL 运行情况
    SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by

    SQL_TEXT                           PARSE_CALLS        LOADS        EXECUTIONS
    --------------------------------- -----------        ----------    ----------
    select count(0) from t2                     1        1          1

    
    可以看到总解析 1次;硬解析 1次,执行次数 1 次;
    下面我们再执行一次:

    2.2 第二次执行效果

    SQL> select count(0) from t2;

      COUNT(0)
    ----------
         76429

    SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by

    SQL_TEXT                           PARSE_CALLS        LOADS        EXECUTIONS
    --------------------------------- -----------        ----------    ----------
    select count(0) from t2                     2        1          2

    这时可以看到总解析 2次;硬解析 1次,执行次数 2 次;    第2次没有进行硬解析,就是因为SQL 放在
    SHARED_POOL中,进行了一次软解析;
    
    2.3 我们再把SHARED_POOL清空,看看效果:


    SQL> alter system flush shared_pool;

    System altered.

    SQL> select count(0) from t2;

      COUNT(0)
    ----------
         76429

    SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by

    SQL_TEXT                            PARSE_CALLS      LOADS        EXECUTIONS
    --------------------------------- -----------        ----------    ----------
    select count(0) from t2                1                1            1


    这时,ORACLE 认为是一条新的SQL了。所以又有一次硬解析。

    2.4 softer_soft_parse 会话对游标的缓存

        SQL> alter session set tracefile_identifier='tang';
        Session altered.

        SQL> alter system flush shared_pool;

        System altered.

        SQL> alter session set events '10046 trace name context forever,level 12';

        Session altered.

        SQL> alter session set sql_trace=true;

        Session altered.

        SQL>


        SQL> show parameter session_cached_cursors;

        NAME                                 TYPE
        ------------------------------------ ---------------------------------
        VALUE
        ------------------------------
        session_cached_cursors               integer
        50
        SQL> set linesize 100;


        SQL> select 'STAT-'||name,value from v$sysstat where name like '%parse%' or name like'%cursor%'
          2  union all select 'LATCH-'||name,gets from v$latch where name = 'shared pool';

        'STAT-'||NAME                 VALUE
        ----------    ------------------------------
        STAT-opened cursors cumulative        10897
        STAT-opened cursors current        28
        STAT-pinned cursors current        12
        STAT-session cursor cache hits        12908
        STAT-session cursor cache count        882
        STAT-cursor authentications        237
        STAT-parse time cpu            91
        STAT-parse time elapsed            224
        STAT-parse count (total)        1752
        STAT-parse count (hard)            1271
        STAT-parse count (failures)        0
        STAT-parse count (describe)        0
        LATCH-shared pool            98158

        13 rows selected.

        SQL>


        SQL> select count(0) from t10;

          COUNT(0)
        ----------
             76432

        SQL> begin
          2  for i in 1..10000 loop
          3  execute immediate 'select count(0) from t10';
          4  end loop;
          5  end;
          6  /

        PL/SQL procedure successfully completed.

        SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' un
        ets from v$latch where name = 'shared pool';

        NAME                VALUE
        ----------------------------------------
        STAT-opened cursors cumulative        21492
        STAT-opened cursors current        29
        STAT-pinned cursors current        11
        STAT-session cursor cache hits        23418
        STAT-session cursor cache count        1033
        STAT-cursor authentications        262
        STAT-parse time cpu            96
        STAT-parse time elapsed            230
        STAT-parse count (total)        1887
        STAT-parse count (hard)            1290
        STAT-parse count (failures)        0
        STAT-parse count (describe)        0
        LATCH-shared pool            118288


        13 rows selected.

        SQL>


        SQL> alter system flush shared_pool;

        System altered.

        SQL> alter session set session_cached_cursors=0;

        Session altered.


        SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' union all
        ets from v$latch where name = 'shared pool';

        NAME                    VALUE
        -------------------------------------------
        STAT-opened cursors cumulative        26250
        STAT-opened cursors current        28
        STAT-pinned cursors current        11
        STAT-session cursor cache hits        28300
        STAT-session cursor cache count        1671
        STAT-cursor authentications        363
        STAT-parse time cpu            148
        STAT-parse time elapsed            300
        STAT-parse count (total)        2855
        STAT-parse count (hard)            1620
        STAT-parse count (failures)        0
        STAT-parse count (describe)        0
        LATCH-shared pool            153871

        13 rows selected.


        SQL> select count(0) from t10;

          COUNT(0)
        ----------
             76432

        
        SQL> begin
          2  for i in 1..10000 loop
          3  execute immediate 'select count(0) from t10';
          4  end loop;
          5  end;
          6  /

        PL/SQL procedure successfully completed.

        SQL>

        SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' union all
        ets from v$latch where name = 'shared pool';

        NAME                 VALUE
        ----------------------------------------
        STAT-opened cursors cumulative        39364
        STAT-opened cursors current        30
        STAT-pinned cursors current        10
        STAT-session cursor cache hits        34321
        STAT-session cursor cache count        1912
        STAT-cursor authentications        442
        STAT-parse time cpu            184
        STAT-parse time elapsed            337
        STAT-parse count (total)        13302
        STAT-parse count (hard)            1814
        STAT-parse count (failures)        0
        STAT-parse count (describe)        0
        LATCH-shared pool            177749


        13 rows selected.

        SQL>




 ---------------------------------------------------------------------------------------------
 3.用示例演示一次分析,多次执行的示例,并对给出演示结果。<br>
 
 
    3.1 使用不绑定变量,执行3次不同的SQL,是各自进行硬分析的:
    SQL>  alter system flush shared_pool;

    System altered.

    SQL> select object_id from t10 where object_id=100;

     OBJECT_ID
    ----------
           100

    SQL> select object_id from t10 where object_id=200;

     OBJECT_ID
    ----------
           200

    SQL> select object_id from t10 where object_id=300;

     OBJECT_ID
    ----------
           300


    SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%'

    SQL_TEXT                                            PARSE_CALLS      LOADS EXECUTIONS
    -----------                                            ---------- ---------- ----------
    select object_id from t10 where object_id=300          1          1          1

    select object_id from t10 where object_id=200          1          1          1

    select object_id from t10 where object_id=100          1          1          1


    SQL>

    3.2 使用绑定变量

    SQL> var vid number;
    SQL> execute :vid:=100;

    PL/SQL procedure successfully completed.

    SQL> select object_id from t10 where object_id:=vid;
    select object_id from t10 where object_id:=vid
                                             *
    ERROR at line 1:
    ORA-00920: invalid relational operator


    SQL> select object_id from t10 where object_id=:vid;

     OBJECT_ID
    ----------
           100

    SQL> execute :vid:=150;

    PL/SQL procedure successfully completed.

    SQL> select object_id from t10 where object_id=:vid;

     OBJECT_ID
    ----------
           150

    SQL> execute :vid:=160;

    PL/SQL procedure successfully completed.

    SQL> select object_id from t10 where object_id=:vid;

     OBJECT_ID
    ----------
           160

    SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%';

    SQL_TEXT                                        PARSE_CALLS      LOADS EXECUTIONS
    ----------------------                            ----------- ---------- ----------
    select object_id from t10 where object_id=300           1          1          1

    select object_id from t10 where object_id=200          1          1          1

    select object_id from t10 where object_id=:vid          3          1          3

    select object_id from t10 where object_id=100          1          1          1


    SQL>

    从上面最后的查询看到,最后一次使用变量的方式执行的3次SQL,只进行了一次硬分析
    Oracle认为这3条SQL是完全一样的(除了谓词部分)所以第一次执行的时候做一次硬解析后续2条SQL只做软解析,比上一个少了2次硬解析,性能提高


    绑定变量2


    SQL> begin
      2  for i in 1..3 loop
      3  execute immediate 'select object_id from t10 where object_id=:i' using i;
      4  end loop;
      5  end;
      6  /

    PL/SQL procedure successfully completed.

    SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%';

    SQL_TEXT                                        PARSE_CALLS      LOADS EXECUTIONS
    --------------------------------------------    ----------- ---------- ----------
    select object_id from t10 where object_id=300              1          1          1

    select object_id from t10 where object_id=200              1          1          1

    select object_id from t10 where object_id=:i              1          1          3

    select object_id from t10 where object_id=:vid              3          1          3

    select object_id from t10 where object_id=100              1          1          1


    SQL>

    Oracle认为这3条SQL是完全一样的(除了谓词部分),和上面不同的是只做了1次硬解析没有软解析,反复执行了3次。
    我们做了一个循环,用leo变量代替谓词常量,每次都用相同的执行计划(执行计划不需要重新生成),只是改变一下常量值而已。
    
    上面3种执行方法,从上面的查询中,很好的看出各自的不同,优点最明显的就是最后一次的SQL.



 ---------------------------------------------------------------------------------------------
 4.演示一个父游标产生3个子游标的示例,并分别说明每个子游标产生的原因。<br>

    4.1 把用户TANG.10 的查询权限赋给 test,scott;

    SQL> grant select on t10 to test;
    Grant succeeded

    SQL> grant select on t10 to scott;
    Grant succeeded

    SQL>
    
    4.2 在test,scott 用户下各建立T10表;

    C:\Users\Administrator>sqlplus test/test@orcl

    SQL*Plus: Release 11.2.0.1.0 Production on Fri Dec 6 17:27:31 2013

    Copyright (c) 1982, 2010, Oracle.  All rights reserved.


    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options


    SQL> create table t10 as select * from tang.t10;

    Table created.

    SQL> select count(1) from t10;

      COUNT(1)
    ----------
         76430

    SQL>

    C:\Users\Administrator>sqlplus scott/scott@orcl

    SQL*Plus: Release 11.2.0.1.0 Production on Fri Dec 6 17:30:24 2013

    Copyright (c) 1982, 2010, Oracle.  All rights reserved.


    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options

    SQL> create table t10 as select * from tang.t10;

    Table created.

    SQL> select count(1) from t10;

      COUNT(1)
    ----------
         76430

    SQL>


    4.3 在用用户tang 查询表


SQL> select count(1) from t10;

  COUNT(1)
----------
     76430

    4.4 查询子游标记录
 SQL>select sql_id,child_number,sql_text,parse_calls,plan_hash_value,loads from v$sql
 where sql_text='select count(1) from t10';

        SQL_ID    CHILD_NUMBER    SQL_TEXT    PARSE_CALLS    PLAN_HASH_VALUE    LOADS
        -----------------------------------------------------------------------
    1    9z6r9gcz6gnmz    0    select count(1) from t10    3    1331550546    1
    2    9z6r9gcz6gnmz    1    select count(1) from t10    2    1331550546    1
    3    9z6r9gcz6gnmz    2    select count(1) from t10    2    1331550546    1


    SQL_ID 相同,即说明是使用了同一个父游标,用子游标来区分不同属性的相同SQL
    CHILD_NUMBER:这个字段不同,说明oracle知道这是3个用户下的相同SQL语句
    LOADS:都做了1次硬解析,说明oracle知道这是3个不完全相同的SQL语句



     select sql_id,child_number,child_address,sql_text
     from v$sql where sql_text='select count(1) from t10';

            SQL_ID    CHILD_NUMBER    CHILD_ADDRESS    SQL_TEXT
    1    9z6r9gcz6gnmz    0            00000002AF6653C0    select count(1) from t10
    2    9z6r9gcz6gnmz    1            00000002AF778630    select count(1) from t10
    3    9z6r9gcz6gnmz    2            00000002AFD6C328    select count(1) from t10

    CHILD_ADDRESS 值不相同,即3个子游标的不同入口地址。
  ---------------------------------------------------------------------------------------------
 5.演示ACS(adaptiver cursor sharing)的效果。<br>

    5.1 建立测试环境数据    

    SQL> drop table t purge;

    Table dropped.

    SQL> create table t as select case when rownum<=100 then 1 else 2 end as id from dual connect by rownum<1000000;

    Table created.

    SQL> create index idx_t_id on t(id);

    Index created.

    5.2 对表进行统计分析(ACS 要有直方图信息)
    SQL> execute dbms_stats.gather_table_stats(user,'T',method_opt=>'for all columns size 2');

    PL/SQL procedure successfully completed.


    SQL> set autotrace off;
    SQL> select id,count(0) from t group by id;

            ID   COUNT(0)
    ---------- ----------
             1        100
             2     999899


    SQL> set autot trace exp;
    SQL> select count(0) from t where id=1;

    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1700799834

    ------------------------------------------------------------------------------
    | Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |          |     1 |     3 |     3   (0)| 00:00:01 |
    |   1 |  SORT AGGREGATE   |          |     1 |     3 |            |          |
    |*  2 |   INDEX RANGE SCAN| IDX_T_ID |   181 |   543 |     3   (0)| 00:00:01 |
    ------------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------

       2 - access("ID"=1)

    SQL> select count(0) from t where id=2;

    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2966233522

    ---------------------------------------------------------------------------
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |      |     1 |     3 |   433   (3)| 00:00:06 |
    |   1 |  SORT AGGREGATE    |      |     1 |     3 |            |          |
    |*  2 |   TABLE ACCESS FULL| T    |   999K|  2928K|   433   (3)| 00:00:06 |
    ---------------------------------------------------------------------------

    Predicate Information (identified by operation id):
    ---------------------------------------------------

       2 - filter("ID"=2)

    SQL>    
    从上面两个执行计划可以看出,两个执行计划使用了ACS,走了不同的执行计划;

    5.3 使用绑定变量执行SQL,并查看不同变量时的变化
    SQL> alter session set sql_trace=true;

    Session altered.

    SQL>  alter session set tracefile_identifier='tang'
      2  ;

    Session altered.

    SQL> var v_num number;
    SQL> execute :v_num:=2;

    PL/SQL procedure successfully completed.

    SQL> select count(0) from t where id=:v_num;

      COUNT(0)
    ----------
        999899

    SQL> execute :v_num:=1;

    PL/SQL procedure successfully completed.

    SQL> select count(0) from t where id=:v_num;

      COUNT(0)
    ----------
           100

    SQL> select count(0) from t where id=:v_num;

      COUNT(0)
    ----------
           100

    SQL> alter session set sql_trace=false;

    Session altered.

    SQL>  select value from v$diag_info where name='Default Trace File';

    VALUE
    --------------------------------------------------------------------------------
    D:\APP\ORACLE\diag\rdbms\orcl\orcl\trace\orcl_ora_5952_tang.trc

    SQL>

    跟踪文件如下:
    
    5.3.1 定义变量为2 时的执行计划:    
    SQL ID: 9qvxqz87xn8vt Plan Hash: 0

    BEGIN :v_num:=2; END;


    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse        1      0.00       0.00          0          0          0           0
    Execute      1      0.00       0.00          0          0          0           1
    Fetch        0      0.00       0.00          0          0          0           0
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total        2      0.00       0.00          0          0          0           1

    Misses in library cache during parse: 0
    Optimizer mode: ALL_ROWS
    Parsing user id: 84  
    ********************************************************************************

    --执行绑定变量SQL,我们可以看执行计划为全表扫描,这是没有问题的,因为数据比较倾斜,
    id为2的记录很多,之前的测试也是全表扫描
 --但是我们要注意,这个SQL语句执行了2次,也就是全表扫描的方式执行了2次,
 也就是当值为1的第一次执行走的是全表扫描。

 5.3.2 定义变量为1 时, 已重新进行了一个硬分析。走的也是全表扫描,这点和想象的不一样。
 感觉很奇怪,
    SQL ID: fdp2j9cdw8pc5 Plan Hash: 0

    BEGIN :v_num:=1; END;


    call     count       cpu    elapsed       disk      query    current        rows
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    Parse        1      0.00       0.00          0          0          0           0
    Execute      1      0.00       0.00          0          0          0           1
    Fetch        0      0.00       0.00          0          0          0           0
    ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    total        2      0.00       0.00          0          0          0           1

    Misses in library cache during parse: 0
    Optimizer mode: ALL_ROWS
    Parsing user id: 84  
    ********************************************************************************

    再看一下是否有错:
    从下面的测试中看到,不管我使用变量 1或者2 ,走的都是全表扫描。并没有走索引。
    
    查看 is_bind_sensitive
       表示游标是否对绑定变量敏感。数值如果为Y,表示当绑定变量的数值发生变化后,
       优化器有可能会产生一个不同的执行计划,简单说就是ACS生效了。
       我这里就是因为这个,一直是N,如下:
        
    

SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive,is_bind_aware from v$sql where sql_text like 'select count(0) from t where id=:v_n';

SQL_ID                                  CHILD_NUMBER EXECUTIONS      LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x                                      0          0          1
          0 N   N   Y


SQL> exec :n :=2;

PL/SQL procedure successfully completed.

SQL> select count(*) from t where id=:n;

  COUNT(*)
----------
    999899

SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';

SQL_ID                                  CHILD_NUMBER EXECUTIONS      LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x                                      0          1          1
       1527 N   N   Y


SQL> exec :n :=2;

PL/SQL procedure successfully completed.

SQL> select count(*) from t where id=:n;

  COUNT(*)
----------
    999899

SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';

SQL_ID                                  CHILD_NUMBER EXECUTIONS      LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x                                      0          2          1
       3054 N   N   Y


SQL>
SQL> exec :n :=1;

PL/SQL procedure successfully completed.

SQL> select count(*) from t where id=:n;

  COUNT(*)
----------
       100

SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';

SQL_ID                                  CHILD_NUMBER EXECUTIONS      LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x                                      0          3          1
       4581 N   N   Y


SQL>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值