转载:http://blog.itpub.net/17203031/viewspace-1067620/

本篇我们继续讨论NO_INVALIDATE参数。

从上篇(http://blog.itpub.net/17203031/viewspace-1067312/)讨论情况看,无论是取值true还是false,Oracle进行的行为都是缺乏考量的。如果选择true,表示旧的执行计划会持续的在shared pool中驻留,新的执行计划不会生成,如果系统SQL运行比较频繁、Age Out现象比较少,更好地执行计划也许不会出现。

另一个极端是false取值,Oracle会将新统计量涉及的所有shared pool一次性设置为失效。这样的好处是可以保证更好执行计划的生成,但是也存在一个性能spike现象。通常统计量的收集是一个集中作业过程,也就是说,通常是绝大多数业务数据表同时进行统计量生成过程。如果设置为false,也就意味着在一个短时间内,Oracle Shared Pool中大部分的shared cursor全部失效,又重新生成执行计划。这样,从整体上就会有一个hard parse高峰期,严重的话会影响到业务运行。

4no_invalidate=dbms_stats.auto_invalidate

针对这种左右为难的现象,Oracle 10g引入了参数dbms_stats.auto_invalidate作为NO_INVALIDATE的默认值。从官方解释看,这个参数的作业就是“让Oracle来决定是不是对shared cursor进行失效动作”。那么,其中的算法原则是如何呢?我们本篇来讨论这个取值过程。

Auto_invalidate过程的原则是避免true和false的极端情况,既要实现新执行计划的生成,也要避免性能spike的出现。Oracle选择的策略是“延时”,就是让shared pool中的共享游标不会一次性的失效,而是“慢慢的”、“有差别的”失效。这样就避免了hard parse过程中出现spike。

在auto_invalidate取值进行统计量收集的情况下,shared cursor失效原则如下:

ü  当新对象的统计量获得时,与其有依赖关系的shared cursor对象不是一次性的失效,而是被进行标注。在Oracle中,被称为“Rolling Invalidation”;

ü  当第二次SQL进行解析的时候,会记录时间戳信息。这个时间戳会与系统内部隐含参数“_optimizer_invalidation_period”+一个随机时间秒数进行比较。如果时间差还没有超过这个设定,第二次SQL就会依然使用之前的旧shared cursor。依然是一个软解析过程;

ü  当一个SQL解析过程中,设定的时间超过了时间间隔。Oracle会启动一个硬解析过程,生成一个新的child cusor执行计划。原有的子游标被标注为roll_invalidate,失效。我们可以通过视图v$sql_shared_cursor来查看;

从auto_invalidate的规则看,Oracle不是不进行共享游标的失效过程,而是将其分散在一个时间范围内,隐含参数“_optimizer_invalidation_period”来控制时间范围起点。通过这样的手段算法,来缓解硬解析带来的性能spike现象。

下面我们通过实验来证明结论。为防止11g的自适应游标影响,我们选择简单的10g版本进行测试。

SQL> select * from v$version;

BANNER

-----------------------------------

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE 10.2.0.1.0 Production

TNS for Linux: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 – Production

默认的参数取值为dbms_stats.no_invalidate。

SQL> select dbms_stats.get_param('no_invalidate') from dual;

DBMS_STATS.GET_PARAM('NO_INVAL

-------------------------------------------------

DBMS_STATS.AUTO_INVALIDATE

默认隐含参数取值为18000s,也就是5小时。

SQL> select x.ksppinm name,

2         y.ksppstvl value,

3         y.ksppstdf isdefault,

4         decode(bitand(y.ksppstvf, 7),

5                1,

6                'MODIFIED',

7                4,

8                'SYSTEM_MOD',

9                'FALSE') ismod,

10         decode(bitand(y.ksppstvf, 2), 2, 'TRUE', 'FALSE') isadj

11    from sys.x$ksppi x, sys.x$ksppcv y

12   where x.inst_id = userenv('Instance')

13     and y.inst_id = userenv('Instance')

14     and x.indx = y.indx

15     and x.ksppinm like '_optimizer_invalidation_period';

NAME                           VALUE      ISDEFAULT ISMOD      ISADJ

------------------------------ ---------- --------- ---------- -----

_optimizer_invalidation_period 18000      TRUE      FALSE      FALSE

为了便于实验,我们将这个时间段设置稍短一些。

SQL> alter system set "_optimizer_invalidation_period"=300;

System altered

创建实验数据表T,进行相关设置和第一次统计量收集。

SQL> create table t as select * from dba_objects;

Table created

SQL> create index idx_t_id on t(object_id);

Index created

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

SQL> select to_char(last_analyzed,'yyyy-mm-dd hh24:mi:ss') from dba_tables where table_name='T';

TO_CHAR(LAST_ANALYZED,'YYYY-MM

------------------------------

2014-01-06 10:13:57

第一次执行SQL语句,我们依然使用autotrace平台,结果集合有省略。

SQL> set autotrace traceonly stat

SQL> select /*+demo*/* from t where object_id=1000;

统计信息

---------------------------------------------------------

381  recursive calls

0  db block gets

57  consistent gets

rows processed

Shared Cursor情况如下:

SQL> select sql_id, executions, version_count, first_load_time from v$sqlarea where sql_text like 'select /*+demo*/* from t%';

SQL_ID        EXECUTIONS VERSION_COUNT FIRST_LOAD_TIME

------------- ---------- ------

4rw3pyskdgqtc          1             1 2014-01-06/10:16:55

形成第一个游标共享,执行一次。第二次执行SQL,游标有共享情况。

SQL> select sql_id, executions, version_count, first_load_time, to_char(last_load_time,'yyyy-mm-dd hh24:mi:ss') from v$sqlarea where sql_text like 'select /*+demo*/* from t%';

SQL_ID        EXECUTIONS VERSION_COUNT FIRST_LOAD_TIME      TO_CHAR(LAST_LOAD_TIME,'YYYY-M

------------- ---------- ------------- -------------------- ------------------------------

4rw3pyskdgqtc          2             1 2014-01-06/10:16:55  2014-01-06 10:16:55

此时的执行计划如下:

SQL> select * from table(dbms_xplan.display_cursor('4rw3pyskdgqtc'));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

SQL_ID  4rw3pyskdgqtc, child number 0

-------------------------------------

select /*+demo*/* from t where object_id=1000

Plan hash value: 514881935

--------------------------------------------------------------------------------

| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Ti

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |          |       |       |     2 (100)|

|   1 |  TABLE ACCESS BY INDEX ROWID| T        |     1 |    93 |     2   (0)| 00

|*  2 |   INDEX RANGE SCAN          | IDX_T_ID |     1 |       |     1   (0)| 00

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("OBJECT_ID"=1000)

19 rows selected

执行Index Range Scan路径。在视图v$sql_shared_cursor中,有共享信息。下面修改数据分布,改变布局。

SQL> update t set object_id=1000;

49745 rows updated

SQL> commit;

Commit complete

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true,method_opt => 'for columns size 10 object_id');

PL/SQL procedure successfully completed

默认参数就是auto_invalidate。从经验看,Oracle只有选择FTS才是最优路径。第三次执行SQL语句。

SQL> select /*+demo*/* from t where object_id=1000;

已选择49745行。

统计信息

----------------------------------------------------------

0  recursive calls

0  db block gets

7441  consistent gets

49745  rows processed

此时shared cursor情况如下:

SQL> select sql_id, executions, version_count, first_load_time, to_char(last_load_time,'yyyy-mm-dd hh24:mi:ss') from v$sqlarea where sql_text like 'select /*+demo*/* from t%';

SQL_ID        EXECUTIONS VERSION_COUNT FIRST_LOAD_TIME      TO_CHAR(LAST_LOAD_TIME,'YYYY-M

------------- ---------- ------------- -------------------- ------------------------------

4rw3pyskdgqtc          3             1 2014-01-06/10:16:55  2014-01-06 10:16:55

第三次执行依然使用了原有的Index Range Scan执行计划,没有新的父子游标对象生成,执行次数上增加了一次。

过一会进行第四次执行。

10:23:44 SQL> select /*+demo*/* from t where object_id=1000;

已选择49745行。

统计信息

--------------------------------

0  recursive calls

0  db block gets

7441  consistent gets

0  physical reads

49745  rows processed

SQL> select sql_id, executions, version_count, first_load_time, to_char(last_load_time,'yyyy-mm-dd hh24:mi:ss') from v$sqlarea where sql_text like 'select /*+demo*/* from t%';

SQL_ID        EXECUTIONS VERSION_COUNT FIRST_LOAD_TIME      TO_CHAR(LAST_LOAD_TIME,'YYYY-M

------------- ---------- ------------- -------------------- ------------------------------

4rw3pyskdgqtc          4             1 2014-01-06/10:16:55  2014-01-06 10:16:55

第四次执行之后,Oracle依然没有让游标失效。经过三四分钟之后,执行不同的效果。

10:23:51 SQL> select /*+demo*/* from t where object_id=1000;

已选择49745行。

统计信息

-------------------------------------

173  recursive calls

0  db block gets

3987  consistent gets

49745  rows processed

10:27:16 SQL>

游标共享情况如下:

SQL> select sql_id, executions, version_count, first_load_time, to_char(last_load_time,'yyyy-mm-dd hh24:mi:ss') from v$sqlarea where sql_text like 'select /*+demo*/* from t%';

SQL_ID        EXECUTIONS VERSION_COUNT FIRST_LOAD_TIME      TO_CHAR(LAST_LOAD_TIME,'YYYY-M

------------- ---------- ------------- -------------------- ------------------------------

4rw3pyskdgqtc          5             2 2014-01-06/10:16:55  2014-01-06 10:27:11

形成了一个新的子游标对象,有新的解析动作发生。查看v$sql_shared_cursor视图,可以看到变化。

SQL> select sql_id, child_number,ROLL_INVALID_MISMATCH from v$sql_shared_cursor where sql_id='4rw3pyskdgqtc';

SQL_ID        CHILD_NUMBER ROLL_INVALID_MISMATCH

------------- ------------ ---------------------

4rw3pyskdgqtc            0 N

4rw3pyskdgqtc            1 Y

Child cursor 0号由于Roll Invalidate原因被拒绝共享。游标1信息如下:

SQL> select child_number, executions, first_load_time, last_load_time from v$sql where sql_id='4rw3pyskdgqtc';

CHILD_NUMBER EXECUTIONS FIRST_LOAD_TIME      LAST_LOAD_TIME

------------ ---------- -------------------- ----------------------------------------------------------------------------

0          4 2014-01-06/10:16:55  2014-01-06/10:16:55

1          1 2014-01-06/10:16:55  2014-01-06/10:27:11

子游标1和0分别代表了不同的执行计划。

SQL> select * from table(dbms_xplan.display_cursor('4rw3pyskdgqtc','1'));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

SQL_ID  4rw3pyskdgqtc, child number 1

-------------------------------------

select /*+demo*/* from t where object_id=1000

Plan hash value: 1601196873

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |       |       |   155 (100)|          |

|*  1 |  TABLE ACCESS FULL| T    | 49740 |  4420K|   155   (3)| 00:00:02 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("OBJECT_ID"=1000)

18 rows selected

SQL> select * from table(dbms_xplan.display_cursor('4rw3pyskdgqtc','0'));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

SQL_ID  4rw3pyskdgqtc, child number 0

-------------------------------------

select /*+demo*/* from t where object_id=1000

Plan hash value: 514881935

--------------------------------------------------------------------------------

| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Ti

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |          |       |       |     2 (100)|

|   1 |  TABLE ACCESS BY INDEX ROWID| T        |     1 |    93 |     2   (0)| 00

|*  2 |   INDEX RANGE SCAN          | IDX_T_ID |     1 |       |     1   (0)| 00

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("OBJECT_ID"=1000)

19 rows selected

从上面实验,我们可以得到结论:当统计量收集采用no_invalidate=dbms_stats.auto_invalidate的时候,已经存在的共享游标会在一个时间段之后被失效。这样的策略避免了集中hard sparse出现,保证了系统性能平稳化过程。

5、结论

Oracle统计量对于执行计划至关重要,理解no_invalidate参数含义和设置,可以帮助我们更好地理解Oracle工作原理和设计思路。

Oracle 统计量NO_INVALIDATE参数配置(下)的更多相关文章

  1. Oracle 统计量NO_INVALIDATE参数配置(上)

    转载:http://blog.itpub.net/17203031/viewspace-1067312/ Oracle统计量对于CBO执行是至关重要的.RBO是建立在数据结构的基础上的,DDL结构.约 ...

  2. 静默安装oracle 11g及参数配置优化详解

    一.安装前准备工作1.修改主机名#vi /etc/hosts   //并添加内网IP地址对应的hostname,如下127.0.0.1           localhost::1           ...

  3. Oracle Data Guard 重要配置参数

    Oracle Data Guard主要是通过为生产数据库提供一个或多个备用数据库(是产生数据库的一个副本),以保证在主库不可用或异常时数据不丢失并通过备用数据库继续提供服务.对于Oracle DG的配 ...

  4. 转:浅谈UNIX下Apache的MPM及httpd.conf配置文件中相关参数配置

    为什么要并发处理 以Apache为代表的web服务器中,如果不支持并发,则在一个客户端连接的时候,如果该客户端的任务没有处理完,其他连接的客户端将会一直处于等待状态,这事不可想象的,好像没有为什么要不 ...

  5. Linux 下网卡参数配置

    目录 Linux 下网卡参数配置 第一种:修改 interfaces 文件 网卡配置实例 回环参数配置 DHCP方式配置 静态 IP 地址分配 无线网卡配置 March 17, 2015 7:48 P ...

  6. 关于ffmpeg /iis 8.5 服务器下,视频截取第一帧参数配置

    ffmpeg 视频截取第一帧参数配置: 网站找了很多资料,但是都不能满足要求,然后自己写下解决过程. 首先看自己PHP 版本,安全选项里面 php5.4  跟php5.6 是不一样的.去除里面的sys ...

  7. 通过搭建MySQL掌握k8s(Kubernetes)重要概念(下):参数配置

    本文通过搭建MySQL环境来了解k8s的重要概念,包括持久卷,网络和参数配置.这是下篇,专门讲解参数配置.如果你有些地方不能完全看明白,请先看上篇"通过搭建MySQL掌握k8s(Kubern ...

  8. Oracle的tnsnames.ora配置(PLSQL Developer)

    首先打开tnsnames.ora的存放目录,一般为D:\app\Administrator\product\11.2.0\client_1\network\admin,就看安装具体位置了. 步骤阅读 ...

  9. oracle数据库的TNS配置

    TNS简要介绍与应用 Oracle中TNS的完整定义:transparence Network Substrate透明网络底层,监听服务是它重要的一部分,不是全部,不要把TNS当作只是监听器. TNS ...

随机推荐

  1. 想ACCESS数据库插入新的用户

    public string AddUserN = ""; //定义用户名字符串 public string paswrd1 = ""; //密码1 public ...

  2. 【Android SDK Manager】SDk国内镜像下载地址

    中国科学院开源协会镜像站地址: IPV4/IPV6: http://mirrors.opencas.cn 端口:80 IPV4/IPV6: http://mirrors.opencas.org 端口: ...

  3. HDU 1589 Stars Couple(计算几何求二维平面的最近点对和最远点对)

    Time Limit: 1000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...

  4. HP LoadRunner 12.02 Tutorial T7177-88037教程独家中文版

    HP LoadRunner 12.02 Tutorial T7177-88037教程独家中文版 Tylan独家呕血翻译 转载请注明出自“天外归云”的博客园 Welcome to the LoadRun ...

  5. 20155316 2016-2017-2 《Java程序设计》第5周学习总结

    教材学习内容总结 这周总结 try catch语法 异常继承结构 throw finally AutoCloseable接口 Collection Map Lambda表达式 上周总结 三个关键 类与 ...

  6. 【java编程】java对象copy

    实现java对象Copy的三种方式 一.克隆 implements Cloneable 二.序列化 implements Serializable 三.利用反射机制copy apache的BeanUt ...

  7. 2017年最新cocoapods安装教程(解决淘宝镜像源无效以及其他源下载慢问题)

    首先,先来说一下一般的方法吧,就是把之前的淘宝源替换成一个可用的的源: 使用终端查看当前的源 gem sources -l gem sources -r https://rubygems.org/ # ...

  8. Ionic slides 轮播图

    1. 创建界面 <ion-content> <ion-slides pager class="myslides"> <ion-slide> &l ...

  9. 一个高效的敏感词过滤方法(PHP)

    $badword = array( '张三','张三丰','张三丰田' ); $badword1 = array_combine($badword,array_fill(0,count($badwor ...

  10. Letterbox,Pillarbox和Pan&Scan

    Auto 不改变窗口设置16:9 PillarBox: 4:3的图像,在16:9的显示屏上显示时,上下到顶,左右会添加黑边. 16:9 Pan&Scan 4:3的图像,在16:9的显示屏上显示 ...