zoukankan      html  css  js  c++  java
  • cursor_sharing

    CURSOR_SHARING

    PropertyDescription
    Parameter type String
    Syntax CURSOR_SHARING = { EXACT | FORCE }
    Default value EXACT
    Modifiable ALTER SESSIONALTER SYSTEM
    Basic No

    CURSOR_SHARING determines what kind of SQL statements can share the same cursors.

    Values:

    • FORCE

      Allows the creation of a new cursor if sharing an existing cursor, or if the cursor plan is not optimal.

    • EXACT

      Only allows statements with identical text to share the same cursor.

      Notes:

      • If you set CURSOR_SHARING, then Oracle recommends the FORCE setting unless you are in a DSS environment.

      • The value of the CURSOR_SHARING parameter has performance implications. Refer to Oracle Database Performance Tuning Guide before setting this parameter.

    cursor_sharing 参数有三个值可选,exact、similar、force。
    如果参数值为 exact (Oracle默认方式),当一个 statement parse 的时候,首先到 shared pool 区查看是否有 exact statement 存在(就是看是否在shared pool中有和当前要解析的statement完全一样的语句存在),如果不存在,就执行hard parse;
    如果参数值为 similar,那么如果在shared pool中无法找到exact statement的存在的时候,就会在shared pool进行一次新的查找,查找和当前要解析的语句是否是similar statement的语句。(similar statement就是除了value of some literal不同的语句,别的地方都相同的语句。)
    当cursor_sharing设置为similar时,如果在shared pool中查找到这样的语句,就会做下一步的检查,看shared pool中缓存的这个语句的execution plan是否适合当前解析的语句,如果适合,就会使用shared pool的语句,而不去做hard parse。如果cursor_sharing设置为force的时候,当在shared pool中发现了similar statement之后,就不会再去检查执行计划了,而直接使用在shared pool的这个语句了。
    将cursor_sharing设置为force实际上是危险的。这会可能形成sub optimal的执行计划。比如对于一个范围查找的语句,比如对于一个范围查找的语句,比如
    select * from a where a>10 and a<20 这样类型的语句,缓存中的语句的执行计划可能对于正在解析的语句就是不适合的,不是最优的执行计划。
    这样看起来是减少了parse恶的时间,但是大大增大了execution的时间。
    测试数据:
    SQL> select owner,count(*) from t1 group by owner;
    OWNER                            COUNT(*)
    ------------------------------ ----------
    PUBLIC 3360
    TEST 1
    SYSTEM 527
    APPQOSSYS 5
    SYS 9440
    SQL> create index i_t1_owner on t1(owner);
    索引已创建。
    SQL> analyze table t1 compute statistics for table for all indexes for all indexed columns;
    表已分析。

    1、cursor_sharing=exact
    SQL> show parameter cursor_sharing
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ------------------------------
    cursor_sharing string EXACT
    SQL> alter system flush shared_pool;
    系统已更改。
    SQL> select count(*) from t1 where owner='TEST';
      COUNT(*)
    ----------
    1
    SQL> select count(*) from t1 where owner='SYS';
      COUNT(*)
    ----------
    9440

    SQL> select sql_text, sql_id, version_count, executions
    2 from v$sqlarea
    3 where sql_text like 'select count(*) from t1 where owner=%';
    SQL_TEXT                                      SQL_ID          VERSION_COUNT EXECUTIONS
    --------------------------------------------- --------------- ------------- ----------
    select count(*) from t1 where owner='SYS' 6n5pk8mynfa7w 1 1
    select count(*) from t1 where owner='TEST' 4au4u0sr7kz2p 1 1
    v$sqlarea中,version_count是指当前父游标(SQL文本)下的子游标个数,executions指执行次数。
    从v$sqlarea的输出可知,字面量不同,会产生两个不同的父游标和子游标,即执行计划不会共享。
    从下面执行计划看,这两个SQL产生的执行计划完全不同。
    SQL> select * from table(dbms_xplan.display_cursor('6n5pk8mynfa7w',null,null));
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------
    SQL_ID 6n5pk8mynfa7w, child number 0
    -------------------------------------
    select count(*) from t1 where owner='SYS'
    Plan hash value: 1368537905
    ------------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    ------------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | | | 10 (100)| |
    | 1 | SORT AGGREGATE | | 1 | 4 | | |
    |* 2 | INDEX FAST FULL SCAN| I_T1_OWNER | 9440 | 37760 | 10 (0)| 00:00:01 |
    ------------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       2 - filter("OWNER"='SYS')

    已选择19行。
    SQL> select * from table(dbms_xplan.display_cursor('4au4u0sr7kz2p',0,''));
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------
    SQL_ID 4au4u0sr7kz2p, child number 0
    -------------------------------------
    select count(*) from t1 where owner='TEST'
    Plan hash value: 923762106
    --------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    --------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | | | 1 (100)| |
    | 1 | SORT AGGREGATE | | 1 | 4 | | |
    |* 2 | INDEX RANGE SCAN| I_T1_OWNER | 1 | 4 | 1 (0)| 00:00:01 |
    --------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       2 - access("OWNER"='TEST')

    已选择19行。

    2、cursor_sharing=similar
    SQL> alter system flush shared_pool;
    系统已更改。
    SQL> alter session set cursor_sharing=similar;
    会话已更改。
    SQL> select count(*) from t1 where owner='TEST';
      COUNT(*)
    ----------
    1
    SQL> select count(*) from t1 where owner='SYS';
      COUNT(*)
    ----------
    9440
    SQL> select sql_text, sql_id, version_count, executions
    2 from v$sqlarea
    3 where sql_text like 'select count(*) from t1 where owner=%';
    SQL_TEXT                                       SQL_ID          VERSION_COUNT EXECUTIONS
    --------------------------------------------- --------------- ------------- ----------
    select count(*) from t1 where owner=:"SYS_B_0" gf0m7xnstru5z 2 2
    从上面v$sqlarea输出结果可以看出,父游标共享(SQL_ID一样),子游标不同(version_count=2),一共执行两次。
    从下面执行计划可以看出,因为子游标不同,虽然sql_id相同,但是仍然产生两个不同的执行计划。
    SQL> select * from table(dbms_xplan.display_cursor('gf0m7xnstru5z',null,null));
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------
    ------------------------------------------------------------------------------------------------------------------------
    ------------------------------------------------------------
    SQL_ID gf0m7xnstru5z, child number 0
    -------------------------------------
    select count(*) from t1 where owner=:"SYS_B_0"
    Plan hash value: 923762106
    --------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    --------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | | | 1 (100)| |
    | 1 | SORT AGGREGATE | | 1 | 4 | | |
    |* 2 | INDEX RANGE SCAN| I_T1_OWNER | 1 | 4 | 1 (0)| 00:00:01 |
    --------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       2 - access("OWNER"=:SYS_B_0)
    SQL_ID  gf0m7xnstru5z, child number 1
    -------------------------------------
    select count(*) from t1 where owner=:"SYS_B_0"
    Plan hash value: 1368537905
    ------------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    ------------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | | | 10 (100)| |
    | 1 | SORT AGGREGATE | | 1 | 4 | | |
    |* 2 | INDEX FAST FULL SCAN| I_T1_OWNER | 9440 | 37760 | 10 (0)| 00:00:01 |
    ------------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       2 - filter("OWNER"=:SYS_B_0)

    已选择38行。

    3、cursor_sharing=force
    SQL> alter system flush shared_pool;
    系统已更改。
    SQL> alter session set cursor_sharing=force;
    会话已更改。
    SQL> select count(*) from t1 where owner='TEST';
      COUNT(*)
    ----------
    1
    SQL> select count(*) from t1 where owner='SYS';
      COUNT(*)
    ----------
    9440
    SQL> select sql_text, sql_id, version_count, executions
    2 from v$sqlarea
    3 where sql_text like 'select count(*) from t1 where owner=%';
    SQL_TEXT                                      SQL_ID          VERSION_COUNT EXECUTIONS
    --------------------------------------------- --------------- ------------- ----------
    select count(*) from t1 where owner=:"SYS_B_0 gf0m7xnstru5z 1 2
    "
    从上面v$sqlarea可以看出,父游标共享(sql_id相同),子游标共享(version_count=1),执行两次。
    从下面执行计划可以看出,这两个SQL执行计划是一样的,可以认为是第一个SQL共享了第一个SQL的执行计划,也可以认为是绑定变量被窥测了。
    其实这样是很危险的,如果第一个传入的值跟传入的第二个值选取的结果差别很大,那么执行效率将会有很大差别。一定要慎用。
    SQL> select * from table(dbms_xplan.display_cursor('gf0m7xnstru5z',null,null));
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------------------
    ------------------------------------------------------------------------------------------------------------------------
    ------------------------------------------------------------
    SQL_ID gf0m7xnstru5z, child number 0
    -------------------------------------
    select count(*) from t1 where owner=:"SYS_B_0"
    Plan hash value: 923762106
    --------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    --------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | | | 1 (100)| |
    | 1 | SORT AGGREGATE | | 1 | 4 | | |
    |* 2 | INDEX RANGE SCAN| I_T1_OWNER | 1 | 4 | 1 (0)| 00:00:01 |
    --------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       2 - access("OWNER"=:SYS_B_0)

    已选择19行。

    cursor_sharing的取值和参数是Oracle library cache中管理生成乃至共享执行计划的重要参数。EXACT值是默认值,实现了直接使用字面SQL不开启转变绑定变量的功能。

    而FORCE和SIMILAR取值却开启了字面转绑定变量的功能。在这两个模式下,Oracle会自动的将where后面的条件替换为绑定变量,以增加SQL共享的概率。具体实现sharing的方式上,FORCE和SIMILAR取值又有所差异。

    FORCE的sharing原则是共享一切,只生成一个子游标,之后所有都去共享这个子游标的执行计划。随之而来的就是bind peeking问题风险。

    而SIMILAR过于谨慎,对每一个SQL都进行类似bind peeking操作。对每个可能取值都生成单独的子游标执行计划。相同的输入共享相同的执行计划。这个虽然避免了bind peeking问题,却带来了新的多version count问题。
  • 相关阅读:
    JavaScript正则表达式
    web页面全角&半角
    WEB中的GET和POST
    设计模式之观察者模式
    初识numpy的多维数组对象ndarray
    【ACM】求高精度幂
    C++ 变量初始化规则
    浅谈const限定符
    堆和栈的区别(转过无数次的文章)
    【编程小题目8】求解完数
  • 原文地址:https://www.cnblogs.com/zhaoshuangshuang/p/3237761.html
Copyright © 2011-2022 走看看