11gR2 新特性--待定的统计信息(Pending Statistic)



11gr2开始,可以使用下面类型的操作来收集优化器统计信息:
1.             自动发布收集的统计信息在收集操作结束以后(默认选项publish)
2.             保存新的统计信息,并且待定(暂不发布pending)
这个特性可以将新收集的统计信息置为待定状态,所以可以先验证新统计信息的有效性然后再发布。
可以使用下面的命令来查看是否默认发布新的统计信息。
sys@DAVID> SELECTDBMS_STATS.GET_PREFS('PUBLISH') PUBLISH FROM DUAL;

PUBLISH
----------------------------------------------------------------------------------------------------
TRUE

返回为true或者false。True表示新的统计信息收集后即发布,也就是说优化器会使用新的统计信息来生查询计划,False表示收集的统计信息会被放入USER_TAB_PENDING_STATS和 USER_IND_PENDING_STATS,并且不会立刻被优化器使用,为待定状态。

可以使用下面的包来改变各个级别(global,schema,table)的默认publish选项。
Global
exec Dbms_stats.set_global_prefs(pname =>'PUBLISH' ,pvalue=> 'FALSE') ;

Schema
exec dbms_stats.set_schema_prefs(ownname => 'DEXTER',pname=>'PUBLISH' ,pvalue => 'TRUE') ;

table
Exec dbms_stats.set_table_prefs('DEXTER', 'PUBLISH_TEST','PUBLISH', 'false');

假设你执行了上面的关于table的操作,那么关于schema dexter 上publish_test表的统计信息收集以后就不会立刻应用于优化器上面,而是先置于USER_TAB_PENDING_STATS表里面为待定状态。
设置好默认的publish选项之后,就可以开始验证新统计信息了。
默认的优化器会使用已经发布的存放在数据字典里面的统计信息,可以通过更改初始化参数OPTIMIZER_USE_PENDING_STATISTICS来设定优化器使用哪一种类型的统计信息(published or pending),比如使用下面的操作来更改session级别的优化器统计信息来源(不要写成alter system了)。
alter session set optimizer_use_pending_statistics = TRUE;

这样在session级别内就可以使用待定的统计信息来编译sql语句并且生成查询计划,如果新的统计信息已经被验证,那么可以使用下面的语句发布统计信息。
Execdbms_stats.publish_pending_stats('DEXTER','PUBLISH_TEST');
如果不想使用新的统计信息,那么可以使用下面的语句去删除。
Execdbms_stats.delete_pending_stats('DEXTER','PUBLISH_TEST');

也可以使用dbms_stats.export_pending_stats将待定的统计信息导出,并且导入到测试系统上面运行一个全面的负载测试,以确定问题的根源。
下面是一个完整的示例:
创建测试表

_dexter@DAVID> createtable publish_test (id number , name varchar2(20) ) ;

Table created.

插入数据

_dexter@DAVID> insertinto publish_test select level , 'name' || level from dual connect by level<= 10000 ;

10000 rows created.

_dexter@DAVID> commit ;

Commit complete.

创建索引

_dexter@DAVID> createindex idx_publish_test_id on publish_test(id) ;

Index created.

收集统计信息

_dexter@DAVID> execdbms_stats.gather_table_stats('DEXTER','PUBLISH_TEST') ;

PL/SQL procedure successfully completed.

查看一下历史统计信息(这个表中只显示已经发布过的统计信息)

_dexter@DAVID> selecth.table_name, to_char(h.STATS_UPDATE_TIME, 'yyyymmddhh24miss')

  2   from user_TAB_STATS_HISTORY h

  3  where h.table_name = 'PUBLISH_TEST';

TABLE_NAME                    TO_CHAR(H.STAT

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

PUBLISH_TEST                  20121120161308

进行一个简单查询,可以看到,走索引的效率还是比较高的

_dexter@DAVID> set autotrace on

_dexter@DAVID> select p.id,p.name from publish_test p whereid=1 ;

ID NAME

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

1 name1

Execution Plan

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

Plan hash value: 1085097009

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

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

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

|   0 | SELECTSTATEMENT            |                     |     1 |   13 |     2   (0)| 00:00:01 |

|   1 | TABLE ACCESS BY INDEX ROWID| PUBLISH_TEST        |    1 |    13 |     2  (0)| 00:00:01 |

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

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

Predicate Information (identified by operation id):

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

2 -access("ID"=1)

Statistics

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

0  recursive calls

0  db block gets

4  consistent gets

0  physical reads

0  redo size

596  bytes sent via SQL*Net to client

524  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

设定一下表的publish选项

_dexter@DAVID>  Exec dbms_stats.set_table_prefs('DEXTER','PUBLISH_TEST', 'PUBLISH', 'false');

PL/SQL procedure successfully completed.

_dexter@DAVID> selectdbms_stats.get_prefs('PUBLISH','DEXTER','PUBLISH_TEST') FROM DUAL ;

DBMS_STATS.GET_PREFS('PUBLISH','DEXTER','PUBLISH_TEST')

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

FALSE

再次向表中插入数据

_dexter@DAVID> insertinto publish_test(id,name) select 1, 'name' || level from dual connect by level<= 10000 ;

10000 rows created.

_dexter@DAVID> commit ;

Commit complete.

在没有再次收集统计信息之前查看一下执行计划,可以看到,依旧使用旧的统计信息

_dexter@DAVID> select p.id,p.name from publish_test p whereid=1 ;

Execution Plan

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

Plan hash value: 1085097009

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

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

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

|   0 | SELECTSTATEMENT            |                     |     1 |   13 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID|PUBLISH_TEST        |     1 |   13 |     2   (0)| 00:00:01 |

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

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

Predicate Information (identified by operation id):

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

2 -access("ID"=1)

Statistics

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

0  recursive calls

0  db block gets

1424  consistent gets

0 physical reads

2644  redo size

293416  bytes sent via SQL*Net to client

7850  bytes received via SQL*Net from client

668  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

10001  rows processed

再次收集一下统计信息,这个时候收集的统计信息不会立刻被优化器使用

_dexter@DAVID>  execdbms_stats.gather_table_stats('DEXTER','PUBLISH_TEST') ;

PL/SQL procedure successfully completed.

如所料,这里还是使用旧的统计信息,依旧使用index rangescan 代价比较高

_dexter@DAVID> select p.id,p.name from publish_test p whereid=1 ;

Execution Plan

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

Plan hash value: 1085097009

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

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

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

|   0 | SELECTSTATEMENT            |                     |     1 |   13 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID|PUBLISH_TEST        |     1 |   13 |     2   (0)| 00:00:01 |

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

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

Predicate Information (identified by operation id):

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

2 -access("ID"=1)

Statistics

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

0  recursive calls

0  db block gets

1391  consistent gets

0  physical reads

0  redo size

293416  bytes sent via SQL*Net to client

7850  bytes received via SQL*Net from client

668  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

10001  rows processed

看一下统计信息的情况,已经发布的统计信息还是比较老的,而如下所示pending表里面的统计信息表示新收集的待定的统计信息

_dexter@DAVID> select 'publish' as stat,t.NUM_ROWS,t.BLOCKS,to_char(t.LAST_ANALYZED,'yyyymmddhh24miss')  from USER_TAB_STATISTICS t  where table_name='PUBLISH_TEST'

2  union

3  select 'pending' as stat,s.num_rows,s.blocks,to_char(s.LAST_ANALYZED,'yyyymmddhh24miss') fromUSER_TAB_PENDING_STATS s where table_name='PUBLISH_TEST'

4  ;

STAT      NUM_ROWS     BLOCKS TO_CHAR(T.LAST

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

pending      20000         50 20121120162534

publish      10000         28 20121120161308

下面我们来验证一下新的统计信息是否有助于改善sql语句的执行

_dexter@DAVID>  alter session setoptimizer_use_pending_statistics = TRUE;

Session altered.

可以看到,使用优化器使用待定的统计信息生成的查询计划使用的是全表扫描,更加有效率

_dexter@DAVID> select p.id,p.name from publish_test p whereid=1 ;

Execution Plan

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

Plan hash value: 3346034967

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

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

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

|   0 | SELECTSTATEMENT  |              | 9921 |   116K|    15  (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| PUBLISH_TEST |  9921 |  116K|    15   (0)| 00:00:01 |

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

Predicate Information (identified by operation id):

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

1 -filter("ID"=1)

Statistics

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

148  recursive calls

0  db block gets

750  consistent gets

0  physical reads

0  redo size

261413  bytes sent via SQL*Net to client

7850  bytes received via SQL*Net from client

668  SQL*Net roundtrips to/from client

3  sorts (memory)

0  sorts (disk)

10001  rows processed

验证结束,无误,可以发布新的统计信息了

_dexter@DAVID> Execdbms_stats.publish_pending_stats('DEXTER','PUBLISH_TEST');

PL/SQL procedure successfully completed.

_dexter@DAVID> altersession set optimizer_use_pending_statistics = false;

Session altered.

可以看到pending的统计信息已经发布并且从user_tab_pending_stats表中删除,user_tab_statistics表中的last_analyzed时间显示的是统计信息收集的时间

_dexter@DAVID> select 'publish' as stat ,t.NUM_ROWS,t.BLOCKS,to_char(t.LAST_ANALYZED,'yyyymmddhh24miss')  from USER_TAB_STATISTICS t  where table_name='PUBLISH_TEST'

2  union

3  select 'pending' as stat,s.num_rows,s.blocks,to_char(s.LAST_ANALYZED,'yyyymmddhh24miss') fromUSER_TAB_PENDING_STATS s where table_name='PUBLISH_TEST'

4  ;

STAT      NUM_ROWS     BLOCKS TO_CHAR(T.LAST

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

publish      20000         50 20121120162534

可以看到user_tab_stats_history表中的stats_update_time收集的是统计信息发布的时间

_dexter@DAVID> select h.table_name,to_char(h.STATS_UPDATE_TIME, 'yyyymmddhh24miss')

2   from user_TAB_STATS_HISTORYh

3   where h.table_name = 'PUBLISH_TEST';

TABLE_NAME                    TO_CHAR(H.STAT

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

PUBLISH_TEST                   20121120161308

PUBLISH_TEST                  20121120163017

好验证结束

如果已经发布了统计信息,想要恢复从前的统计信息,可以根据user_TAB_STATS_HISTORY中的stats_update_time,来确定timestamp,执行下面的操作,最后一个参数as_of_timestamp指的是恢复在这个时间点生效的统计信息,所以不能写20121120161308因为在这个时间点内它的统计信息是空的

SQL> execdbms_stats.restore_table_stats(ownname => 'DEXTER',tabname =>'PUBLISH_TEST',as_of_timestamp => to_date('20121120161309','yyyymmddhh24miss'));

PL/SQL procedure successfully completed

_dexter@DAVID> select 'publish' as stat,t.NUM_ROWS,t.BLOCKS,to_char(t.LAST_ANALYZED,'yyyymmddhh24miss')  from USER_TAB_STATISTICS t  where table_name='PUBLISH_TEST'

2  union

3  select 'pending' as stat,s.num_rows,s.blocks,to_char(s.LAST_ANALYZED,'yyyymmddhh24miss') fromUSER_TAB_PENDING_STATS s where table_name='PUBLISH_TEST' ;

STAT      NUM_ROWS     BLOCKS TO_CHAR(T.LAST

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

publish      10000         28 20121120161308

_dexter@DAVID> select h.table_name,to_char(h.STATS_UPDATE_TIME, 'yyyymmddhh24miss')

2    from user_TAB_STATS_HISTORY h

3   where h.table_name = 'PUBLISH_TEST';

TABLE_NAME                    TO_CHAR(H.STAT

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

PUBLISH_TEST                  20121120161308

PUBLISH_TEST                  20121120163017

PUBLISH_TEST                  20121120165341

附录

dbms_stats.restore_table_stats参数说明

--

-- This procedure enables the user to restore statisticsof a table as of

-- a specified timestamp (as_of_timestamp). The procedurewill restore

-- statistics of associated indexes and columns as well.If the table

-- statistics were locked at the specified timestamp theprocedure will

-- lock the statistics.

-- Note:

--   The proceduremay not restore statistics correctly if analyze interface

--   is used forcomputing/deleting statistics.

--   Old statisticsversions are not saved when SYSAUX tablespace is

--   offline, thisaffects restore functionality.

--   The proceduremay not restore statistics if the table defn is

--   changed (eg:column added/deleted, partition exchanged etc).

--   Also it willnot restore stats if the object is created after

--   the specifiedtimestamp.

--   The procedurewill not restore user defined statistics.

-- Input arguments:

--   ownname  - schema of table for which statistics to berestored

--   tabname  - table name

--   as_of_timestamp- statistics as of this timestamp will be restored.

--  restore_cluster_index - If the table is part of a cluster,

--     restorestatistics of the cluster index if set to TRUE.

--   force -restore statistics even if the table statistics are locked.

--           if thetable statistics were not locked at the specified

--          timestamp, it will unlock the statistics

--   no_invalidate- Do not invalide the dependent cursors if set to TRUE.

--      Theprocedure invalidates the dependent cursors immediately

--      if set toFALSE.

--      Theprocedure invalidates the dependent cursors immediately

--      if set toFALSE.

--      UseDBMS_STATS.AUTO_INVALIDATE to have oracle decide when to

--      invalidatedependend cursors. This is the default. The default

--      can bechanged using set_param procedure.

--

-- Exceptions:

--   ORA-20000:Object does not exist or insufficient privileges

--   ORA-20001:Invalid or inconsistent values

--   ORA-20006: Unable to restorestatistics , statistics history not available




在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的方法,可以在生产运维和稳定优化执行计划方面,给我们提供帮助。



About Me

...............................................................................................................................

● 本文作者:小麦苗,只专注于数据库的技术,更注重技术的运用

● 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/

● 本文博客园地址:http://www.cnblogs.com/lhrbest

● 本文pdf版及小麦苗云盘地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 数据库笔试面试题库及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● QQ群:230161599     微信群:私聊

● 联系我请加QQ好友(646634621),注明添加缘由

● 于 2017-06-02 09:00 ~ 2017-06-30 22:00 在魔都完成

● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解

● 版权所有,欢迎分享本文,转载请保留出处

...............................................................................................................................

拿起手机使用微信客户端扫描下边的左边图片来关注小麦苗的微信公众号:xiaomaimiaolhr,扫描右边的二维码加入小麦苗的QQ群,学习最实用的数据库技术。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26736162/viewspace-2140300/,如需转载,请注明出处,否则将追究法律责任。

11gR2 新特性--待定的统计信息(Pending Statistic)相关推荐

  1. oracle exacc,【学习笔记】Oracle 11GR2新特性Adaptive Cursor Sharing(ACS)

    天萃荷净 Oracle研究中心学习笔记:分享一篇关于Oracle 11.2.0.1 11Gr2数据库最新版本中最新特性Adaptive Cursor Sharing(ACS)深入研究笔记. 本站文章除 ...

  2. Oracle 11gR2新特性--延迟段创建(Deferred Segment Creation)和exp不能导出空表

    Oracle 11gR2新特性--延迟段创建(Deferred Segment Creation)和exp不能导出空表 真题1. 什么是延迟段创建(Deferred Segment Creation) ...

  3. oracle flash_cache,11gR2新特性之二 - Flash Cache 的SSD支持

    11gR2新特性之二 - Flash Cache 的SSD支持 Flash Cache的新特性就早已经被释放出来,该特性允许使用SSD硬盘作为Buffer Cache的二级缓存,以在磁盘和内存之间增加 ...

  4. (转)11gR2新特性:Heavy swapping observed on system in last 5 mins

    http://www.oracledatabase12g.com/archives/11gr2-dbrm-collect-swap-info.html 在11gR2中DBRM(database res ...

  5. oracle heavy swapping,11gR2新特性:Heavy swapping observed on system in last 5 mins.

    在11gR2中DBRM(database resource manager,11gR2中新的后台进程,见<Learning 11g New Background Processes>)会在 ...

  6. 手机耗电统计app_Android O新特性:精确统计APP电量消耗

    5月19日消息由于安卓生态的开放性,软件随意获得不必要的权限,驻留后台消耗电量成为安卓用户的吐槽点,从安卓6.0时代开始,谷歌开始在安卓系统当中原生内置软件权限管理功能,在最新的AndroidO当中谷 ...

  7. 手机耗电统计app_Android O 新特性:精确统计 APP 电量消耗

    IT之家5月19日消息 由于安卓生态的开放性,软件随意获得不必要的权限,驻留后台消耗电量成为安卓用户的吐槽点,从安卓6.0时代开始,谷歌开始在安卓系统当中原生内置软件权限管理功能,在最新的Androi ...

  8. Oracle 11g 新特性简介

    Oracle 11g于2007年7月11日美国东部时间11时(北京时间11日22时)正式发布,11g是甲骨文公司30年来发布的最重要的数据库版本,根据用户的需求实现了信息生命周期管理(Informat ...

  9. 快讯:Oracle 19c 新特性及官方文档抢鲜下载

    随着2月的春风吹拂,Oracle 19c 的第一个 Exadata 版本发布将马上发布出来,等待可测试版本的朋友们马上即可如愿了. 目前官方文档已经可以公开下载到,我为大家整理了一些重要文档,包括概念 ...

  10. 圣诞快乐:Oracle Database 19c 的10大新特性一览

    在 ACOUG 年会的活动上,分享了一些从前未曾分享过的内容,想起,今年还欠下一篇文章,就整理和回顾一下,分享我所见到的Oracle 19c的一些重要改变(本文内容来自OOW大会演讲,关注本公众号回复 ...

最新文章

  1. 为何把日志打印到控制台很慢?
  2. ajax请求的步骤,ajax请求的五个步骤
  3. 802.11 帧格式及类型
  4. 永信至诚携 “企业安全人才培养解决方案”惊艳WOT技术峰会
  5. linux 系统频率,Linux下CPU的手动频率设定
  6. 信息安全产业爆发在即 十三五年均增长将达20%以上
  7. Mac AE2018软件安装及破解
  8. 发动机冒黑烟_发动机冒黑烟的原因和解决方法
  9. 《挑战不可能之加油中国》中越边境广西段扫雷队整装亮相
  10. mac如何挂载移动硬盘、U盘
  11. 2022-2028年中国罐头行业市场专项调研及发展策略分析报告
  12. 数据库语言,转载自:红黑联盟
  13. 程序员面试必问:你为什么要离开上一家公司。你会怎么回答?
  14. html知识点整理(全)
  15. 字节跳动否认完成支付牌照收购,但金融野心一直有...
  16. 幼儿园体育游戏电子计算机教案,幼儿园体育游戏《学会跳绳》教案三篇
  17. 如何入驻832优选平台
  18. shopee跨境店铺怎么申请入驻-跨境知道
  19. 57q/5oCn5Luj5pWw5Y+K5YW25bqU55So56ysNeeJiOS4reaWh1BERui1hOa6kA==
  20. 姚洋:建议国家购买三四线空置房 再低价出售给进城农民

热门文章

  1. 木子-前端-ajax传值与接收最简单的方式
  2. 如何用MATLAB编写简单的音乐程序
  3. 新的分享之路开启,感谢您的陪伴
  4. Idea中发布JAR包到中央仓库报错问题处理 unable to find valid certification path to requested target
  5. 如何在简历中使用STAR法则
  6. ccf b类论文相当于sci几区_你写SCI论文是否也经历了这三个阶段?
  7. 乖乖小网安-网络安全之ARP初探
  8. 爱剪辑如何解决分段视频在串接处快两秒的问题
  9. 各证件号码(身份证、护照、军官证、驾驶证、港澳台湾通行证、户口簿)正则表达式校验 完整正确
  10. 2022.3月份工作记录【日记】