在CBO时代,SQL语句的执行计划完全依赖于在数据字典中保存的统计量信息和优化器Optimizer的计算公式参数。从9i开始到现在的11gR2,我们说CBO优化器已经很成熟和完善。在通常情况下,我们的SQL都是可以获取到较好的执行计划以及执行效率的。

在实际工作中,我们经常会遇到执行计划低效的情况。但是这种故障根源中,绝大多数的原因在于统计量的错误或者失效。错误的统计量连带生成的就是不恰当的执行计划,以至于低效的执行过程。在9i时代,RBO和CBO混合使用,让我们经常需要自定义的统计量收集过程。

从10g开始,Oracle引入了自动收集统计量的作业,以保证数据字典中统计量正确反映数据对象状态。这在很大程度上,缓解了由于数据变化导致的统计量过期问题。但是,我们在实际工作中,还是会发现执行计划的突然变化。究其原因,就是某个时间点收集的统计量,也许不能反映数据的全貌(如中间表)。

1、统计量Pending

在系统运维中,我们常常希望维持SQL执行计划的稳定。很多DBA和开发人员对于hint的依赖,很大程度上也是源于对CBO情况下,执行计划对于统计量过于依赖,容易形成不稳定执行计划。

那么,我们SQL语句执行计划的稳定性,就变成统计量的稳定性问题。更进一步,就是新的统计量更新,无论是否手动收集还是自动收集,能否促进SQL语句生成更高效的执行计划。

所以,一种思路是:在新的统计量收集生成时,暂时不要生效投入执行计划生成。等待最后确认统计量正确之后,再投入生产环境。

在Oracle 11g中,推出了统计量管理的一种新技术——Pending Statistic技术,提供了这种功能。

简单的说,我们可以对一系列的数据表设置pending属性。设置pending属性之后,数据的统计量在数据字典中相当于已经锁定Lock住。但新统计量生成之后,不是直接替换原有的数据,而是存放在pending数据字典中。

在pending字典中的统计量,默认情况下是不会参与SQL执行计划的生产的。只有在进行SQL测试通过的时候,经过用户手工的确定,才会将其Publish出来,替换原有的统计量信息。

这样,就给我们运维DBA一种维持执行计划稳定的思路。通过固定统计量,将新统计量pending的方式将原有的统计量固定,从而稳定执行计划。进而,对pending的统计量进行测试,只有在更好执行计划的情况下,才会替换原有的方案。

下面,我们通过实验来验证pending统计量的使用。

2、实验环境构建

我们选择11gR2进行实验。

SQL> select * from v$version;

BANNER

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

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE   11.2.0.1.0 Production

构建数据表T,以及对应的索引。注意,我们首先在数据表中不保存任何数据。

SQL> create table t as select * from dba_objects where 1=0;

Table created

SQL> create index idx_t_owner on t(owner);

Index created

SQL> create index idx_t_id on t(object_id);

Index created

在不显式的收集统计量的情况下,是没有对应的数据表统计量的。

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN

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

SQL> select count(*) from user_tab_col_statistics where table_name='T';

COUNT(*)

----------

0

SQL> select BLEVEL, LEAF_BLOCKS, DISTINCT_KEYS, CLUSTERING_FACTOR  NUM_ROWS from user_ind_statistics where index_name='IDX_T_OWNER';

BLEVEL LEAF_BLOCKS DISTINCT_KEYS  NUM_ROWS

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

0          0            0         0

收集统计量,获取最新的数据分布状况。

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

PL/SQL procedure successfully completed

当我们修改数据内容,没有收集统计量,会存在新旧差异。

SQL> insert into t select * from dba_objects;

72202 rows inserted

SQL> commit;

Commit complete

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN

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

0           0         0         0          0

3、Pending Statistics设置

在11g环境中,数据表、Schema都存在一个统计量相关参数PUBLISH,表示当有新统计量的时候,新统计量是否立即被publish出来,作为最新的统计信息使用。

该参数的默认值为TRUE。

SQL> select dbms_stats.get_prefs(pname => 'PUBLISH',ownname => 'SYS',tabname => 'T') from dual;

DBMS_STATS.GET_PREFS(PNAME=>'P

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

TRUE

--设置数据表的publish参数取值;

SQL> exec dbms_stats.set_table_prefs(user,'T','PUBLISH','false');

PL/SQL procedure successfully completed

SQL> select dbms_stats.get_prefs('PUBLISH',ownname => 'SYS',tabname => 'T') from dual;

DBMS_STATS.GET_PREFS('PUBLISH'

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

FALSE

此时,数据表中已经包括了七万余条数据,重新收集统计量。

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

PL/SQL procedure successfully completed

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN

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

0           0         0         0          0

当我们将数据表T的PUBLISH参数修改为false之后,我们重新收集统计量,发现原有统计信息并没有连带的更新。

新统计量不是没有收集,而是被记录在了pending信息中。我们可以通过user_ind_pending_stats和user_tab_pending_stats两个视图查看被pending的统计量信息。

SQL> select NUM_ROWS, BLOCKS, AVG_ROW_LEN, SAMPLE_SIZE, LAST_ANALYZED from user_tab_pending_stats where table_name='T';

NUM_ROWS    BLOCKS AVG_ROW_LEN SAMPLE_SIZE LAST_ANALYZED

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

72202      1028         97      72202 2012/6/20 20:

SQL> select index_name, LEAF_BLOCKS, DISTINCT_KEYS, CLUSTERING_FACTOR,LAST_ANALYZED from user_ind_pending_stats where table_name='T';

INDEX_NAME                    LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED

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

IDX_T_OWNER                           293           23             1884 2012/6/20 20:

IDX_T_ID                              256        72202             1665 2012/6/20 20:

4、Pending和SQL执行计划

新的统计量没有被publish出来。那么,在一般情况下,我们的SQL执行计划还是依据正式被publish的统计量生成。

SQL> explain plan for select * from t where wner='SYS';

Explained

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

Plan hash value: 1516787156

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

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

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

|  0 | SELECT STATEMENT           |            |    1 |  207 |    1  (0)|

|  1 | TABLE ACCESS BY INDEX ROWID| T          |    1 |  207 |    1  (0)|

|* 2 |  INDEX RANGE SCAN         | IDX_T_OWNER |    1 |      |    1  (0)|

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

Predicate Information (identified by operation id):

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

2 - access("OWNER"='SYS')

14 rows selected

实际执行情况;

SQL> select * from t where wner='SYS';

已选择58799行。

已用时间: 00: 00: 06.19

执行计划

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

Plan hash value: 1516787156

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

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

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

|  0 | SELECT STATEMENT           |            |    1 |  207 |    1  (0)| 00:00:01 |

|  1 | TABLE ACCESS BY INDEX ROWID| T          |    1 |  207 |    1  (0)| 00:00:01 |

|* 2 |  INDEX RANGE SCAN         | IDX_T_OWNER |    1 |      |    1  (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

2 - access("OWNER"='SYS')

统计信息

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

528 recursive calls

0 db block gets

8962 consistent gets

1108 physical reads

0 redo size

6291375 bytes sent via SQL*Net to client

43520 bytes received via SQL*Net from client

3921 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

58799 rows processed

SQL>

在sys用户下,行数比例超过了数据表T的绝大多数。按照CBO的原则,走全表扫描可能是较好的方法。但是,由于统计量还是在空表的状态下,所以,Oracle CBO认为Index路径会更好。

在Oracle中,存在一个参数optimizer_use_pending_statistics,用来控制当前是否使用pending的统计量来生成执行计划。作为运维DBA,可以通过这个参数暂时性的启用pending统计量,观察一下性能状况。再决定是否启用publish这些统计量。

默认情况下,该参数取值为false。我们可以在session级别设置下该参数为true。

SQL> show parameter optimizer_use_pending

NAME                                TYPE       VALUE

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

optimizer_use_pending_statistics    boolean    FALSE

修改参数为true之后,Oracle CBO在生成执行计划的时候就会使用Pending的统计量。

SQL> alter session set optimizer_use_pending_statistics=true;

Session altered

SQL> select value from v$parameter where name='optimizer_use_pending_statistics';

VALUE

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

TRUE

SQL> explain plan for select * from t where wner='SYS';

Explained

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

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

Plan hash value: 1601196873

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

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

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

|  0 | SELECT STATEMENT |     | 58274 | 5463K|  281  (1)| 00:00:04 |

|* 1 | TABLE ACCESS FULL| T   | 58274 | 5463K|  281  (1)| 00:00:04 |

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

Predicate Information (identified by operation id):

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

1 - filter("OWNER"='SYS')

13 rows selected

SQL> select * from t where wner='SYS';

已选择58799行。

已用时间: 00: 00: 04.68

执行计划

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

Plan hash value: 1601196873

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

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

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

|  0 | SELECT STATEMENT |     | 58274 | 5463K|  281  (1)| 00:00:04 |

|* 1 | TABLE ACCESS FULL| T   | 58274 | 5463K|  281  (1)| 00:00:04 |

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

Predicate Information (identified by operation id):

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

1 - filter("OWNER"='SYS')

统计信息

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

7511 recursive calls

50 db block gets

6599 consistent gets

1118 physical reads

0 redo size

2392962 bytes sent via SQL*Net to client

43520 bytes received via SQL*Net from client

3921 SQL*Net roundtrips to/from client

211 sorts (memory)

0 sorts (disk)

58799 rows processed

果然,设置参数后,Oracle生成了FTS路径,说明更新的统计量起了作用。同时,执行时间减少了近2秒钟,说明结果上也确实是生成了更好的执行计划。

5、Pending统计量的后续处理

在对pending统计量进行合理评估之后,DBA是可以做出删除还是发布统计量的决定的。具体操作如下:

--删除pending信息

SQL> exec dbms_stats.delete_pending_stats(user,'T');

PL/SQL procedure successfully completed

SQL> select count(*) from user_tab_pending_stats;

COUNT(*)

----------

0

--重新收集pending统计量

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

PL/SQL procedure successfully completed

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN

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

0           0         0         0          0

--发布pending统计量

SQL> exec dbms_stats.publish_pending_stats(user,'T');

PL/SQL procedure successfully completed

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN

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

72202        1028         0         0         96

单发布完统计量之后,就可以在正常的情况下使用统计量生成执行计划了。

SQL> show parameter optimizer_use_pen

NAME                                TYPE       VALUE

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

optimizer_use_pending_statistics    boolean    FALSE

SQL> alter session set optimizer_use_pending_statistics=false;

会话已更改。

已用时间: 00: 00: 00.01

SQL> select * from t where wner='SYS';

已选择58799行。

已用时间: 00: 00: 04.33

执行计划

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

Plan hash value: 1601196873

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

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

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

|  0 | SELECT STATEMENT |     | 58794 | 5511K|  281  (1)| 00:00:04 |

|* 1 | TABLE ACCESS FULL| T   | 58794 | 5511K|  281  (1)| 00:00:04 |

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

Predicate Information (identified by operation id):

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

1 - filter("OWNER"='SYS')

统计信息

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

426 recursive calls

0 db block gets

4975 consistent gets

0 physical reads

0 redo size

2392962 bytes sent via SQL*Net to client

43520 bytes received via SQL*Net from client

3921 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

58799 rows processed

6、结论

在11g中提出的pending statistic的方法,可以在生产运维和稳定优化执行计划方面,给我们提供帮助。

Oracle 11g 数据统计量Pending处理相关推荐

  1. oracle dim 00014,配置oracle 11g数据遇到dim

    配置oracle 11g数据遇到dim00014 orical无法打开windows nt服务控制管理器 安装环境windows7 oracle 安装完成后 需要配置建立全局实例 命令cmd - db ...

  2. oracle 11g goldengate与oracle 11g数据同步

    1.下载,安装goldengate软件(两个节都需要安装) glodengate下载地址:http://pan.baidu.com/s/1pLtVTJt 密码:exob [oracle@oracleo ...

  3. 记一次oracle 11g数据导入

    1.ORACLE数据库数据导入到测试库环境 172.15.1.51 root  kic@test 172.15.1.52 root 一般先将数据导入52的环境(配置比较低),再将数据导入51的环境(本 ...

  4. Oracle 11G 数据迁移 到 12C

    版权声明:本文为CSDN博主「lhdz_bj」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/tuning ...

  5. oracle 11g 数据泵导出 19c导入

    1,准备工作 查看dba_directories来查看数据库中已创建的目录 select * from dba_directories; 先使用这个目录: DATA_PUMP_DIR,/home/or ...

  6. oracle 文件头格式,ORACLE 11G 数据文件头格式

    11G版本 BBED> print kcvfh struct kcvfh, 860 bytes @0 struct kcvfhbfh, 20 bytes @0 ub1 type_kcbh @0 ...

  7. oracle 最小系统,基于最小化CENTOS6.6最小化安装,oracle 11g 数据安装过程!

    Linux环境配置 OS:CentOS 6.6 DB:Oracle 11gR2 将Oracle安装到home/oracle目录 配置过程:本文来自Oracle官方文档+网上资料 1. 以root用户登 ...

  8. 安装Oracle 11g数据库服务器类

    <Oracle达人修炼秘籍:Oracle 11g数据库管理与开发指南>第3章Oracle 11g数据库的安装,本章将介绍如何在32位系统结构的Windows 7操作系统平台上对Oracle ...

  9. mysql 1455_关于Oracle 11g导出数据时 报 ORA-1455错误的处理

    关于Oracle 11g导出数据时 报 ORA-1455错误的处理,由于导出的该用户的表可能存在空数据表,那么可能就会出现此其异常. 关于Oracle 11g导出数据时 报 ORA-1455错误的处理 ...

最新文章

  1. android 根据时间获取时间对应的星期
  2. 关于学习tf.random.normal()和tf.random.uniform()的一点小总结
  3. 数据库物理文件 mysql_MYSQL数据库-物理文件
  4. Fragment的setUserVisibleHint方法实现懒加载
  5. python压缩包怎么安装-Python学习笔记-打包发布Python模块或程序,安装包
  6. 成功解决ValueError: Could not interpret input day
  7. java元婴期(23)----java进阶(mybatis(2)---mapper代理mybatis核心配置文件输入输出映射)
  8. 【ABAP】SAP销售订单定价值变更
  9. 写未来的电子计算机的畅想两百字,未来科技作文200字
  10. 如何断开GitLab远程仓库链接
  11. ajax请求怎么判断没有更多内容,怎么知道ajax 请求完了,想在数据没请求完时,页面有一个loading效果...
  12. jszip压缩服务器文件,JSZip压缩与解压的基本使用
  13. word中域代码与题注的结合实现自动编号和超简便交叉引用
  14. zkdemo可以直接调用html,中控指纹机ZKBIOOnline BS开发包 含示例DEMO
  15. button layui-btn 色调
  16. TensorFlow从1到2(十一)变分自动编码器和图片自动生成
  17. 来张券呗 | 打造一款cps小程序《一》
  18. 【php基础入门】小白整理PHP常用的字符串函数使用总结分析(推荐)
  19. SpringBoot+Mybatis-Plus+Shiro整合的RBAC权限系统
  20. 雨听|Mac使用“打印”将文件保存为本地PDF

热门文章

  1. js中onload和jQuery中的ready区别
  2. leetcode412
  3. JavaScript frame跨域获取元素、修改元素属性、调用其他frame页面方法
  4. 查询方式的一般使用1
  5. 基于JDK7 NIO2的高性能web服务器实践之二(转)
  6. java中log4j的详解(转)
  7. RedOffice教你DIY环保小日历
  8. F#学习之路(3) 如何组织程序(下)
  9. matlab解常微分方程,Matlab中解常微分方程的ode45
  10. java date dateformat_Java中SimpleDateFormat的使用方法