您的位置:首页 > 数据库 > Oracle

Oracle的SYSTEM统计信息

2011-01-25 17:46 387 查看
[align=center]Oracle系统统计信息[/align]

1. 什么是系统统计信息?

我们知道在CBO环境中,Oracle依赖于对象的统计估算成本,以选择正确的SQL执行计划。从Oracle9i开始CBO计算成本(cost)的算法有了变化。Oracle9i以前更多考虑IO(多块读与单块读)成本;9i以后,强化了cpu速度对成本估算的影响。
Oracle提供了dbms_stats.gather_system_stats来收集系统统计信息。系统统计信息让优化器考虑服务器的IO与CPU性能及其利用率,作为计算成本的依据;为每一个可选的执行计划估算IO与CPU成本。因而对于CBO来说,获得准确的系统统计信息对于正确估计成本是非常重要的。Oracle收集的系统统计信息主要内容说明如下:

--cpuspeedNW 表示非负载情况下的cpu速度,在系统启动时自动搜集
--ioseektim IO查找时间,以毫秒表示;缺省为10ms,非负载模式或可以手动设置。
--iotfrspeed IO传输速度,表示Oracle数据库单次读数据的传输速率,单位为bytes/ms,在系统启动时自动收集;默认为4096 bytes/ms
--cpuspeed 表示负载情况下的cpu速度,以平均每秒可提供的cpu周期表示
--maxthr   最大IO吞吐量,单位为bytes/s
--slavethr 从属IO吞吐量,表示并行进程时,从属进程的IO吞吐量,单位为bytes/s
--sreadtim 单块读时间(如索引读取),表示随机读一个Oracle数据块的时间,以ms计算
--mreadtim 多块读时间(主要是指全表扫描),表示连续读取多个Oracle数据库的平均时间,以ms计算 
--mbrc 多块读计数,表示一次多块读的读取的Oracle数据块数量

系统统计信息存储在sys.aux_stats$表中:
[align=left]SQL> select * from sys.aux_stats$;[/align]
[align=left] [/align]
[align=left]SNAME PNAME PVAL1 PVAL2[/align]
[align=left]-------------------- -------------------- ---------- --------------------[/align]
[align=left]SYSSTATS_INFO STATUS COMPLETED[/align]
[align=left]SYSSTATS_INFO DSTART 01-24-2011 18:06[/align]
[align=left]SYSSTATS_INFO DSTOP 01-24-2011 18:06[/align]
[align=left]SYSSTATS_INFO FLAGS 1[/align]
[align=left]SYSSTATS_MAIN CPUSPEEDNW 1970.048[/align]
[align=left]SYSSTATS_MAIN IOSEEKTIM 11.132[/align]
[align=left]SYSSTATS_MAIN IOTFRSPEED 4096[/align]
[align=left]SYSSTATS_MAIN SREADTIM 6[/align]
[align=left]SYSSTATS_MAIN MREADTIM 24[/align]
[align=left]SYSSTATS_MAIN CPUSPEED 1800[/align]
[align=left]SYSSTATS_MAIN MBRC 6[/align]
[align=left] [/align]
[align=left]SNAME PNAME PVAL1 PVAL2[/align]
[align=left]SYSSTATS_MAIN MAXTHR[/align]
SYSSTATS_MAIN SLAVETHR

2. 系统统计信息的收集
Dbms_stats.gather_system_stats的参数如下:
[align=left]SQL> desc dbms_stats.gather_system_stats;[/align]
[align=left]Parameter Type Mode Default? [/align]
[align=left]-------------- -------- ---- -------- [/align]
[align=left]GATHERING_MODE VARCHAR2 IN Y [/align]
[align=left]INTERVAL NUMBER IN Y [/align]
[align=left]STATTAB VARCHAR2 IN Y [/align]
[align=left]STATID VARCHAR2 IN Y [/align]
STATOWN VARCHAR2 IN Y

STATTAB、STATID、STATOWN与其他收集统计信息的参数一样,不多做说明。系统统计信息有工作负载与无工作负载两种类型; ioseektim、iotrfspeed、cpuspeednw是无负载的统计信息,也就是说不需要系统有工作负载,可以系统空闲时进行收集。Oracle为在系统启动时间重新设置,或重置为默认值。要手动收集非工作负载统计信息,使用dbms_stats.gather_system_stats(gathering_mode => 'NOWORKLOAD')。当使用dbms_stats.delete_system_stats()删除系统统计信息时间,将只保留非负载时的统计信息:
[align=left]SQL> exec dbms_stats.delete_system_stats();[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
[align=left]SQL> select * from sys.aux_stats$;[/align]
[align=left] [/align]
[align=left]SNAME PNAME PVAL1 PVAL2[/align]
[align=left]-------------------- -------------------- ---------- --------------------[/align]
[align=left]SYSSTATS_INFO STATUS COMPLETED[/align]
[align=left]SYSSTATS_INFO DSTART 01-25-2011 11:37[/align]
[align=left]SYSSTATS_INFO DSTOP 01-25-2011 11:37[/align]
[align=left]SYSSTATS_INFO FLAGS 0[/align]
[align=left]SYSSTATS_MAIN CPUSPEEDNW 2030.679[/align]
[align=left]SYSSTATS_MAIN IOSEEKTIM 10[/align]
[align=left]SYSSTATS_MAIN IOTFRSPEED 4096[/align]
[align=left]SYSSTATS_MAIN SREADTIM[/align]
[align=left]SYSSTATS_MAIN MREADTIM[/align]
[align=left]SYSSTATS_MAIN CPUSPEED[/align]
[align=left]SYSSTATS_MAIN MBRC[/align]
[align=left] [/align]
[align=left]SNAME PNAME PVAL1 PVAL2[/align]
[align=left]-------------------- -------------------- ---------- --------------------[/align]
[align=left]SYSSTATS_MAIN MAXTHR[/align]
[align=left]SYSSTATS_MAIN SLAVETHR[/align]
[align=left] [/align]
[align=left]已选择13行。[/align]

不同压力与不同类型的应用,甚至同一系统的不同时间,cpu与io的能力都是不一样的。比如ZLHIS在8点到11点的压力,明显于大于下午的压力;这时候包括多块读时间、单块读时间的效率都会有差异。理想的情况是,收集不同系统负载下的系统统计信息,存放到特定的统计信息表中,然后在负载发生变化的时候导入到Oracle中,但在类似ZLHIS这种要求高可用的系统,频繁的变更系统统计信息不太现实。大多数情况下,只需要采集系统高峰时段或典型时段的系统统计信息即可。
收集负载情况下的统计信息有两种方式,一种是手工指定收集时段的开始与结束:
[align=left]--启动收集[/align]
[align=left]exec dbms_stats.gather_system_stats(gathering_mode => 'START');[/align]
[align=left].............[/align]
[align=left]--等待系统运行一段时间,等待时间长短根据情况做调整[/align]
[align=left].............[/align]
[align=left]--停止收集[/align]
exec dbms_stats.gather_system_stats(gathering_mode => 'STOP');

另一种方式就是使用间隔模式,指定一个间隔时段,Oracle自动开始与结束信息收集:
[align=left]--以未来10分钟的系统负载,收集系统统计信息。[/align]
exec dbms_stats.gather_system_stats(gathering_mode => 'INTERVAL',interval => 10);
 
需要说明的是收集系统统计信息,并不影响已经缓存的sql语句,只会影响新解析的SQL语句,如果要已经缓存的SQL语句也按新的系统统计信息生成执行计划,只有清空共享池,但这在生产系统上是比较危险的操作。另外需要注意的就是,如果在收集时段内没有相应操作,将不会收集对应的系统统计信息;例如,如果收集时段内没有产生全表扫描的多块读,mbrc(多块读计数)将不会收集。

2. 系统统计信息对CBO成本计算的影响

虽然CBO计算的成本只是对生成何种执行计划有关,并不对真正执行SQL语句的真实代价产生什么影响,但作为CBO估算成本的基础要素,系统统计信息要尽量保证准确。我们通过实验来说明系统统计信息对sql语句成本估算的影响:
   使用dba_objects视图创建一个测试表:
[align=left]SQL> --创建测试表[/align]
[align=left]SQL> create table test as select * from dba_objects;[/align]
[align=left] [/align]
[align=left]表已创建。[/align]
[align=left] [/align]
[align=left]SQL> insert into test select * from test;[/align]
[align=left] [/align]
[align=left]已创建10212行。[/align]
[align=left] [/align]
[align=left]SQL> --收集测试表的统计信息[/align]
[align=left]SQL> exec dbms_stats.gather_table_stats(ownname => user,tabname => 'test',cascade => true);[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]

然后删除删除工作负载的统计信息,只保留非工作负载的统计信息:

exec dbms_stats.delete_system_stats();

我们来看此时的对test全表扫描估算的成本:

[align=left]SQL> explain plan for select count(*) from test;[/align]
[align=left] [/align]
[align=left]已解释。[/align]
[align=left] [/align]
[align=left]SQL> select * from table(dbms_xplan.display());[/align]
[align=left] [/align]
[align=left]PLAN_TABLE_OUTPUT[/align]
[align=left]--------------------------------------------------------------------[/align]
[align=left]Plan hash value: 1950795681[/align]
[align=left] [/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| Id | Operation | Name | Rows | Cost (%CPU)| Time |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| 0 | SELECT STATEMENT | | 1 | 71 (0)| 00:00:01 |[/align]
[align=left]| 1 | SORT AGGREGATE | | 1 | | |[/align]
[align=left]| 2 | TABLE ACCESS FULL| TEST | 20424 | 71 (0)| 00:00:01 |[/align]
[align=left] [/align]
可以看到Oracle在没有负载情况下的系统统计信息时,估算的成本为71。接下为,我们使用导入一些系统统计信息。由于测试环境,没有什么负载,我们使用dbms_stats.set_system_stats过程来手工修改统计信息:
[align=left] [/align]
[align=left]SQL> --创建统计信息表[/align]
[align=left]SQL> exec dbms_stats.create_stat_table(ownname => user,stattab => 'SYSTEM_STATS');[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
[align=left]SQL> --设置相关的统计信息值[/align]
[align=left]SQL> exec dbms_stats.set_system_stats(pname => 'SREADTIM',pvalue => '6' ,stattab => 'system_stats');[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
[align=left]SQL> exec dbms_stats.set_system_stats(pname => 'MREADTIM',pvalue => '12',stattab => 'system_stats');[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
[align=left]SQL> exec dbms_stats.set_system_stats(pname => 'CPUSPEED',pvalue => '1800' ,stattab => 'system_stats');[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
[align=left]SQL> exec dbms_stats.set_system_stats(pname => 'MBRC',pvalue => '16',stattab => 'system_stats');[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
[align=left]SQL> --导入相应统计信息[/align]
[align=left]SQL> exec dbms_stats.import_system_stats(stattab => 'system_stats',statown => user);[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
现在来重新查看sql语句的估算成本:
[align=left]SQL> explain plan for select count(*) from test;[/align]
[align=left] [/align]
[align=left]已解释。[/align]
[align=left] [/align]
[align=left]SQL> select * from table(dbms_xplan.display());[/align]
[align=left] [/align]
[align=left]PLAN_TABLE_OUTPUT[/align]
[align=left]--------------------------------------------------------------------[/align]
[align=left]Plan hash value: 1950795681[/align]
[align=left] [/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| Id | Operation | Name | Rows | Cost (%CPU)| Time |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| 0 | SELECT STATEMENT | | 1 | 33 (0)| 00:00:01 |[/align]
[align=left]| 1 | SORT AGGREGATE | | 1 | | |[/align]
[align=left]| 2 | TABLE ACCESS FULL| TEST | 20424 | 33 (0)| 00:00:01 |[/align]
[align=left] [/align]
这次估算的成本(cost)为33,在收集了系统信息后,CBO估算的成本发生了变化。我们知道Oracle提供了db_file_multiblock_read_count参数,来控制Oracle一次多块读的Oracle数据块数量,也将影响Oracle对全表扫描成本的估算。Oracle既然收集了多块读IO速度(mreadtim)、多块读计数(mbrc)等信息,那db_file_multiblock_read_count的设置与这些统计信息是什么关系呢?答案是:如果存在负载情况下的多块读的相关统计信息,将会忽略db_file_multiblock_read_count的设置,如果不存在相应的系统统计信息,将使用db_file_multiblock_read_count的值对全表扫描成本进行估算。

首先,我们测试一下,不存在相关系统统计信息时,全表扫描的成本:
[align=left]SQL> explain plan for select count(*) from test;[/align]
[align=left] [/align]
[align=left]已解释。[/align]
[align=left] [/align]
[align=left]SQL> select * from table(dbms_xplan.display());[/align]
[align=left] [/align]
[align=left]PLAN_TABLE_OUTPUT[/align]
[align=left]--------------------------------------------------------------------[/align]
[align=left]Plan hash value: 1950795681[/align]
[align=left] [/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| Id | Operation | Name | Rows | Cost (%CPU)| Time |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| 0 | SELECT STATEMENT | | 1 | 71 (0)| 00:00:01 |[/align]
[align=left]| 1 | SORT AGGREGATE | | 1 | | |[/align]
[align=left]| 2 | TABLE ACCESS FULL| TEST | 20424 | 71 (0)| 00:00:01 |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]已选择9行。[/align]
[align=left] [/align]
可以看成本(cost)又回到了未收集系统统计信息时的71,而不是收集后的33,这个时候,我们修改db_file_multiblock_read_count参数,来看看相应的成本cost是否会起变化:
[align=left] [/align]
[align=left]SQL> show parameter db_file_multiblock_read_count;[/align]
[align=left] [/align]
[align=left]NAME TYPE VALUE[/align]
[align=left]------------------------------------ ----------- ---------------------[/align]
[align=left]db_file_multiblock_read_count integer 8[/align]
[align=left]SQL> alter session set db_file_multiblock_read_count=16;[/align]
[align=left] [/align]
[align=left]会话已更改。[/align]
[align=left] [/align]
[align=left]SQL> explain plan for select count(*) from test;[/align]
[align=left] [/align]
[align=left]已解释。[/align]
[align=left] [/align]
[align=left]SQL> select * from table(dbms_xplan.display());[/align]
[align=left] [/align]
[align=left]PLAN_TABLE_OUTPUT[/align]
[align=left]----------------------------------------------------------------------[/align]
[align=left]--------------------[/align]
[align=left]Plan hash value: 1950795681[/align]
[align=left] [/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| Id | Operation | Name | Rows | Cost (%CPU)| Time |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| 0 | SELECT STATEMENT | | 1 | 57 (0)| 00:00:01 |[/align]
[align=left]| 1 | SORT AGGREGATE | | 1 | | |[/align]
[align=left]| 2 | TABLE ACCESS FULL| TEST | 20424 | 57 (0)| 00:00:01 |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left] [/align]
[align=left]已选择9行。[/align]
[align=left] [/align]
[align=left] 可以看到在没有系统统计信息的情况下,设置db_file_multiblock_read_count,可以影响SQL的成本估算,现在变成了57。现在重新导入系统统计信息,看设置db_file_multiblock_read_count能否影响执行计划:[/align]
[align=left] [/align]
[align=left]--重新导入系统统计信息[/align]
[align=left]SQL> exec dbms_stats.import_system_stats(stattab => 'system_stats',statown => user);[/align]
[align=left] [/align]
[align=left]PL/SQL 过程已成功完成。[/align]
[align=left] [/align]
[align=left]SQL> --还原db_file_multiblock_read_count[/align]
[align=left]SQL> alter session set db_file_multiblock_read_count=8;[/align]
[align=left] [/align]
[align=left]会话已更改。[/align]
[align=left] [/align]
[align=left]SQL> explain plan for select count(*) from test;[/align]
[align=left] [/align]
[align=left]已解释。[/align]
[align=left] [/align]
[align=left]SQL> select * from table(dbms_xplan.display());[/align]
[align=left] [/align]
[align=left]PLAN_TABLE_OUTPUT[/align]
[align=left]---------------------------------------------------------------------[/align]
[align=left]Plan hash value: 1950795681[/align]
[align=left] [/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| Id | Operation | Name | Rows | Cost (%CPU)| Time |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| 0 | SELECT STATEMENT | | 1 | 33 (0)| 00:00:01 |[/align]
[align=left]| 1 | SORT AGGREGATE | | 1 | | |[/align]
[align=left]| 2 | TABLE ACCESS FULL| TEST | 20424 | 33 (0)| 00:00:01 |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left] [/align]
[align=left]已选择9行。[/align]
[align=left] [/align]
可以看到,导入系统统计信息后,成本又变成了33,我们再设置db_file_multiblock_read_count,再重新解析sql语句:
[align=left] [/align]
[align=left]SQL> --再设置db_file_multiblock_read_count值[/align]
[align=left]SQL> alter session set db_file_multiblock_read_count=16;[/align]
[align=left] [/align]
[align=left]会话已更改。[/align]
[align=left] [/align]
[align=left]SQL> explain plan for select count(*) from test;[/align]
[align=left] [/align]
[align=left]已解释。[/align]
[align=left] [/align]
[align=left]SQL> select * from table(dbms_xplan.display());[/align]
[align=left] [/align]
[align=left]PLAN_TABLE_OUTPUT[/align]
[align=left]---------------------------------------------------------------------[/align]
[align=left]Plan hash value: 1950795681[/align]
[align=left] [/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| Id | Operation | Name | Rows | Cost (%CPU)| Time |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left]| 0 | SELECT STATEMENT | | 1 | 33 (0)| 00:00:01 |[/align]
[align=left]| 1 | SORT AGGREGATE | | 1 | | |[/align]
[align=left]| 2 | TABLE ACCESS FULL| TEST | 20424 | 33 (0)| 00:00:01 |[/align]
[align=left]-------------------------------------------------------------------[/align]
[align=left] [/align]
[align=left]已选择9行。[/align]
[align=left] [/align]
将db_file_multiblock_read_count从8设置成16时,发现估算的成本没有发生变化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息