Oracle 统计量NO_INVALIDATE参数配置(下)
转载: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高峰期,严重的话会影响到业务运行。
4、no_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参数配置(下)的更多相关文章
- Oracle 统计量NO_INVALIDATE参数配置(上)
转载:http://blog.itpub.net/17203031/viewspace-1067312/ Oracle统计量对于CBO执行是至关重要的.RBO是建立在数据结构的基础上的,DDL结构.约 ...
- 静默安装oracle 11g及参数配置优化详解
一.安装前准备工作1.修改主机名#vi /etc/hosts //并添加内网IP地址对应的hostname,如下127.0.0.1 localhost::1 ...
- Oracle Data Guard 重要配置参数
Oracle Data Guard主要是通过为生产数据库提供一个或多个备用数据库(是产生数据库的一个副本),以保证在主库不可用或异常时数据不丢失并通过备用数据库继续提供服务.对于Oracle DG的配 ...
- 转:浅谈UNIX下Apache的MPM及httpd.conf配置文件中相关参数配置
为什么要并发处理 以Apache为代表的web服务器中,如果不支持并发,则在一个客户端连接的时候,如果该客户端的任务没有处理完,其他连接的客户端将会一直处于等待状态,这事不可想象的,好像没有为什么要不 ...
- Linux 下网卡参数配置
目录 Linux 下网卡参数配置 第一种:修改 interfaces 文件 网卡配置实例 回环参数配置 DHCP方式配置 静态 IP 地址分配 无线网卡配置 March 17, 2015 7:48 P ...
- 关于ffmpeg /iis 8.5 服务器下,视频截取第一帧参数配置
ffmpeg 视频截取第一帧参数配置: 网站找了很多资料,但是都不能满足要求,然后自己写下解决过程. 首先看自己PHP 版本,安全选项里面 php5.4 跟php5.6 是不一样的.去除里面的sys ...
- 通过搭建MySQL掌握k8s(Kubernetes)重要概念(下):参数配置
本文通过搭建MySQL环境来了解k8s的重要概念,包括持久卷,网络和参数配置.这是下篇,专门讲解参数配置.如果你有些地方不能完全看明白,请先看上篇"通过搭建MySQL掌握k8s(Kubern ...
- Oracle的tnsnames.ora配置(PLSQL Developer)
首先打开tnsnames.ora的存放目录,一般为D:\app\Administrator\product\11.2.0\client_1\network\admin,就看安装具体位置了. 步骤阅读 ...
- oracle数据库的TNS配置
TNS简要介绍与应用 Oracle中TNS的完整定义:transparence Network Substrate透明网络底层,监听服务是它重要的一部分,不是全部,不要把TNS当作只是监听器. TNS ...
随机推荐
- django中的分页器组件
目录 django的组件-分页器 引入分页器 分页器demo 创建数据库模型 url控制器 views视图函数 templates模板 为什么要用分页器 导入分页器 分页器优化1 分页器优化2 有多少 ...
- 题目1003:A+B
题目1003:A+B 时间限制:1 秒内存限制:32 兆 题目描述: 给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号","隔开. 现在请计算A+B的结果,并以正常形式 ...
- 修改类不重启tomcat 自动加载项目
可以修改类不用重启Tomcat加载整个项目(手工启动) 配置reloadable=true(自动重载) 使用Debug模式,前提是仅限于局部修改.(修改类不用重启--热加载) Tomc ...
- asp.net webform 当前上下文中不存在名称“__o”
错误 CS0103 当前上下文中不存在名称“__o” 最近在搞一个webform项目, 再页面写了点<%%>代码, 结果编译下居然出现了这个错误 炸裂啊, 这是什么毛线, 看起来是 In ...
- Magento如何设置产品的打折或者优惠价格
促销是商家的必备武器,手段可以说是花样繁多.其中最有效最具吸引力的就是优惠券了.那么在Magento中如何添加优惠券呢? 修改位置:后台--促销--购物车价格规则 1.点击右上角的 添加新规则 按钮. ...
- 如何快速切换目录cd-linux
前言 cd命令是linux系统中的基本命令行,表示改变工作目录.本文主要介绍几个常用的cd命令. 系统环境 OS:ubuntu16.04. 操作过程 cd www 表示切换到www目录: cd .. ...
- PAT天梯:L1-019. 谁先倒
L1-019. 谁先倒 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 划拳是古老中国酒文化的一个有趣的组成部分.酒桌上两人划拳 ...
- (2)流程控制(for循环、if...else判断、while循环)
for循环 for item in names: #结构语法 print(item) for循环嵌套for循环 for循环配合range()可以直接指定要打印的数量 例:打印一个金字塔 for i ...
- Microsoft - Get Course Order
// "static void main" must be defined in a public class. public class Main { public static ...
- bat根据星期启动程序
原来公司里的由于每次开机时启动的程序比较多,所以打算使用批处理程序,这里只列举了部分.在每周一到周五的时候,开机则启动指定的应用程序,如果是周末的两天则不启动任何程序,所以做了这个脚本.你如果需要,根 ...