什么是统计信息
统计信息主要是描述数据库中表,索引的大小,规模,数据分布状况等的一类信息。比如,表的行数,块数,平均每行的大小,索引的leaf blocks,索引字段的行数,不同值的大小等,都属于统计信息。CBO正是根据这些统计信息数据,计算出不同访问路径下,不同join 方式下,各种计划的成本,最后选择出成本最小的计划。
统计信息是存放在数据字段表中的,如dba_tab_statistics
如何搜集统计信息
统计信息搜集也是有多种方法,推荐大家使用DBMS_STATS 表来进行统计信息搜集及进行一般的统计信息维护工作。
DBMS-STATS 包,主要提供了搜集,删除,导出,导入,修改统计信息的方法,分别对应于gather系列,delete系列,export 系列,import系列,set系列的子过程。一般可能主要是使用统计信息的搜集,以及导出导入这样的功能。具体来说,主要会使用到如下几个子过程:
GATHER_INDEX_STATS Procedure
Gathers index statistics.
GATHER_TABLE_STATS Procedure
Gathers table and column (and index) statistics.
CREATE_STAT_TABLE Procedure
Creates a table with name stattab in ownname's schema which is capable of holding statistics.
EXPORT_TABLE_STATS Procedure
Retrieves statistics for a particular table and stores them in the user stat table.
EXPORT_SCHEMA_STATS Procedure
Retrieves statistics for all objects in the schema identified by ownname and stores them in the user stat table identified by stattab.
IMPORT_INDEX_STATS Procedure
Retrieves statistics for a particular index from the user stat table identified by stattab and stores them in the dictionary.
IMPORT_TABLE_STATS Procedure
Retrieves statistics for a particular table from the user stat table identified by stattab and stores them in the dictionary.
IMPORT_SCHEMA_STATS Procedure
Retrieves statistics for all objects in the schema identified by ownname from the user stat table and stores them in the dictionary.
对于统计信息的搜集,谈谈个人的几点理解:
? 统计信息默认是存放在数据字典表中的,也只有数据字典中的统计信息,才会影响到CBO。
? DBMS_STATS 提供的CREATE_STAT_TABLE 过程,只是生成一个用户自定义的特定格式的表,用来存放统计信息罢了,这个表中的统计信息是不会影响到统计信息的。
? GATHER 系列过程中,如果指定stattab,statid,statown 参数(也可以不指定),则是搜集的统计信息除了更新到数据字典外,还在statown 用户下的stattab 表中存放一份,标示为 statid;
? EXPORT和IMPORT 系列的过程中,stattab,statid,statown 参数不能为空,分别表示把数据字典中的当前统计信息导出到用户自定义的表中,以及把用户表中的统计信息导入到数据字典中,很明显可以看出,这里的导入操作和上面GATHER 操作会改变统计信息,可能会引起执行执行计划的改变,因此要慎重操作。
? 每次统计信息搜集前,将旧的统计信息备份起来是很有必要的;特别是保留一份或多份系统在稳定时期的统计信息也是很有必要的。
? 多长时间搜集一次统计信息,对于统计信息如何备份和保留,搜集统计信息时如何选择合适的采样,并行,直方图设置等都比较重要,需要设计一个较好的统计信息搜集策略。
统计信息包括下面几类:
表统计:包括记录数、block数和记录平均长度。
列统计:列中不同值的数量(NVD)、空值的数量和数据分布(HISTOGRAM)。
索引统计:索引叶块的数量、索引的层数和聚集因子(CLUSTERING FACTOR)。
系统统计:I/O性能和利用率和CPU性能和利用率。
生成统计信息:
统计信息生成技术包括三种:
基于数据采样的估计方式
精确计算方式
用户自定义的统计信息收集方式
其中采用估算方式可以指定总记录数的估算百分比或者总块数的估算百分比。
分区表的统计信息分为几级:分区表的整体信息、分区的统计信息和子分区的统计信息。
最常用的收集统计信息的方式包括:DBMS_STATS包和ANALYZE语句,Oracle推荐使用DBMS_STATS包来收集统计信息。
DBMS_STATS包中用于收集统计信息的过程包括:
dbms_stats.gather_table_stats 收集表、列和索引的统计信息;
dbms_stats.gather_schema_stats 收集SCHEMA下所有对象的统计信息;
dbms_stats.gather_index_stats 收集索引的统计信息;
dbms_stats.gather_system_stats 收集系统统计信息。
dbms_stats.delete_table_stats 删除表的统计信息
dbms_stats.export_table_stats 输出表的统计信息
dbms_stats.create_state_table
dbms_stats.set_table_stats 设置 表的统计
dbms_stats.auto_sample_size
dbms_stats.gather_database_stats:收集数据库中所有对象的统计信息;
在CREATE INDEX和ALTER INDEX REBUILD时可以指定COMPUTE STATISTICS语句,对于非分区表重建索引时会收集表、列和索引的统计信息。对于分区表,只收集索引信息,不会收集表和列信息。
可以在将METHOD_OPT参数设置为“FOR ALL HIDDEN COLUMNS SIZE N”来收集函数索引的索引表达式信息。
Oracle根据下列条件来决定使用哪些索引:
索引中的记录数;
索引中不同键值的数量;
索引的层数;
索引中的叶块数;
聚集因子;
每个键值平均叶块数;
如果两个索引的选择性、查询代价和集势都相同,那么优化器会根据索引名称的字母顺序选
使用analyze命令收集oracle统计信息
ORACLE数据库的PL/SQL语句执行的优化器,有基于代价的优化器(CBO)和基于规则的优化器(RBO)。
RBO:依赖于一套严格的语法规则,只要按照规则写出的语句,不管数据表和索引的内容是否发生变化,不会影响PL/SQL语句的"执行计划"。
CBO:自ORACLE7版被引入,ORACLE自7版以来采用的许多新技术都是只基于CBO的,
如星型连接排列查询,哈希连接查询,反向索引,索引表,分区表和并行查询等。
CBO计算各种可能"执行计划"的"代价",即cost,从中选用cost最低的方案,作为实际运行方案。
各"执行计划"的cost的计算根据,依赖于数据表中数据的统计分布,ORACLE数据库本身对该统计分布是不清楚的,
须要分析表和相关的索引,才能搜集到CBO所需的数据。
CBO是ORACLE推荐使用的优化方式,要想使用好CBO,使SQL语句发挥最大效能,必须保证统计数据的及时性。
统计信息的生成可以有完全计算法和抽样估算法。SQL例句如下:
完全计算法: analyze table abc compute statistics;
抽样估算法(抽样20%): analyze table abc estimate statistics sample 20 percent;
对表作完全计算所花的时间相当于做全表扫描,抽样估算法由于采用抽样,比完全计算法的生成统计速度要快,如果不是要求要有精确数据的话,尽量采用抽样分析法。
建议对表分析采用抽样估算,对索引分析可以采用完全计算。
我们可以采用以下两种方法,对数据库的表和索引及簇表定期分析生成统计信息,保证应用的正常性能。
1. 在系统设置定时任务,执行分析脚本。
在数据库服务器端,我们以UNIX用户oracle,运行脚本analyze,在analyze中,我们生成待执行sql脚本,并运行。(假设我们要分析scott用户下的所有表和索引)
Analyze脚本内容如下:
sqlplus scott/tiger << EOF
set pagesize 5000
set heading off
SPOOL ANALYTAB.SQL
SELECT "ANALYZE TABLE SCOTT."||TABLE_NAME||" ESTIMATE STATISTICS SAMPLE 20 PERCENT ;" FROM USER_TABLES;
SPOOL OFF
SPOOL ANALYIND.SQL
SELECT "ANALYZE TABLE SCOTT."||TABLE_NAME||" ESTIMATE STATISTICS SAMPLE 20 PERCENT FOR ALL INDEXES;" FROM USER_TABLES;
SPOOL OFF
SPOOL ANALYZE.LOG
@ANALYTAB.SQL
@ANALYIND.SQL
SPOOL OFF
EXIT
在UNIX平台上crontab加入,以上文件,设置为每个月或合适的时间段运行。
或者将如下脚本保存成analyze.sql,然后在sqlplus里面执行:
set pagesize 5000
set linesize 300
set trims on
set heading off
set feedback off
SPOOL analyTab.sql
SELECT 'ANALYZE TABLE ZFMI.'||TABLE_NAME||' COMPUTE STATISTICS ;'
FROM USER_TABLES;
SPOOL OFF
SPOOL analyIdx.sql
SELECT 'ANALYZE TABLE ZFMI.'||TABLE_NAME||' COMPUTE STATISTICS
FOR ALL INDEXES;' FROM USER_TABLES;
SPOOL OFF
SPOOL analyLog.log
@@analyTab.sql
@@analyIdx.sql
SPOOL OFF
2. 利用ORACLE提供的程序包(PACKAGE)对相关的数据库对象进行分析。
有以下的程序包可以对表,索引,簇表进行分析。
包中的存储过程的相关参数解释如下:
TYPE可以是:TABLE,INDEX,CLUSTER中其一。
SCHEMA为:TABLE,INDEX,CLUSTER的所有者,NULL为当前用户。
NAME为:相关对象的名称。
METHOD是:ESTIMATE,COMPUTE,DELETE中其一,当选用ESTIMATE,
下面两项,ESTIMATE_ROWS和ESTIMATE_PERCENT不能同时为空值。
ESTIMATE_ROWS是:估算的抽样行数。
ESTIMATE_PERCENT是:估算的抽样百分比。
当ESTIMATE_PERCENT参数是手动指定的,如果手动指定的参数过小,不能收集到足够的信息,那么DBMS_STATS可能会自动增长ESTIMATE_PERCENT的值,这样就能确保收集到足够的统计信息。
控制采样的参数是ESTIMATE_PERCENT,采样的参数可以设置任意值(当然要在范围内),不过ORACLE公司推荐设置ESTIMATE_PERCENT为DBMS_STATS.AUTO_SAMPLE_SIZE。
AUTO_SAMPLE_SILE可以让ORACLE自己决定最好的采样值,因为不同类型(table,index,column)的统计信息有不同的需求。
METHOD_OPT是:有以下选项,
FOR TABLE /*只统计表*/
[FOR ALL [INDEXED] COLUMNS] [SIZE N] /*只统计有索引的表列*/
FOR ALL INDEXES /*只分析统计相关索引*/
参数METHOD_OPT控制柱状图的收集。ORACLE公司推荐设置METHOD_OPT为FOR ALL COLUMNS SIZE AUTO。这样设置过后ORACLE会自动的判断哪一列需要收集柱状图,并且自动的设置柱状图
的bucket。你同样可以手动的设置哪一列需要收集柱状图,以及柱状图的bucket。
PARTNAME是:指定要分析的分区名称。
DEGREE:控制DBMS_STATS是否使用并行特征。
ORACLE公司推荐将DEGREE参数设置为DBMS_STATS.AUTO_DEGREE。这样设置过后,ORACLE就能够根据OBJECT的SIZE,以及与并行有关的init参数来决定一个恰当的并行度
收集统计信息。注意:cluster index,domain index,bitmap join index不能使用并行特征。
补充
对于分区表和分区索引,DBMS_STATS既可以单独的收集分区统计信息,也可以收集整个表/索引的统计信息。对于组合分区,DBMS_STATS也能够收集子分区,分区,以及整个表/索引的统计信息。参数GRANULARITY控制分区统计信息的收集。因为分区统计信息,全局统计信息对于大多数系统来说都是非常重要的,所以ORACLE公司推荐将其设置为AUTO来收集分区,以及全局的统计信息。
当对表收集统计信息的时候,DBMS_STATS会收集列的数据分布信息。数据分布最基本的统计信息就是这个列的最大值与最小值。如果这一列是倾斜的,那么优化器仅仅根据列最大值与最小值是无法制定出准确的执行计划的。对于倾斜的数据分布,我们可以收集列的直方图/柱状图统计信息,这样可以让优化器制定出更加准确的执行计划。
为了知道统计信息是否过期,ORACLE提供了表监控功能。将init参数STATISTICS_LEVEL设置为ALL或者TYPICAL(默认),就开启了表监控的功能(10g已经不需要alter table monitor了)。表监控功能跟踪表的insert,update,delete,truncate,操作,并且记录在DBA_TAB_MODIFICATIONS视图里面。
我们在查询DBA_TAB_MODIFICATIONS视图的时候有可能查询不到结果,或者查询的结果不准确,这个时候需要用DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO过程将内存中的信息刷新到该视图中。
OPTIONS参数设置为GATHER STALE或者GATHER AUTO,就会让DBMS_STATS判断表的统计信息是否过期
(注意GATHER_TABLE_STATS中没有这个参数,只有GATHER_DATABASE_STATS,GATHER_SCHEMA_STATS过程中有这个参数)。
判断表的统计信息是否过期的依据是是否有10%以上的数据被修改过,如果被修改过了,那么ORACLE就认为之前的统计信息过期了,ORACLE会重新收集统计信息。
在我们创建了函数索引之后,我们要为列收集统计信息,这个时候我们需要设置参数METHOD_OPT为FOR ALL HIDDEN COLUMNS。
例子
1)
DBMS_DDL.ANALYZE_OBJECT(
TYPE VARCHAR2,
SCHEMA VARCHAR2,
NAME VARCHAR2,
METHOD VARCHAR2,
ESTIMATE_ROWS NUMBER DEFAULT NULL,
ESTIMATE_PERCENT NUMBER DEFAULT NULL,
METHOD_OPT VARCHAR2 DEFAULT NULL,
PARTNAME VARCHAR2 DEFAULT NULL ) ;
该存储过程可对特定的表,索引和簇表进行分析。例如,对SCOTT用户的EMP表,进行50%的抽样分析,参数如下:
DBMS_DDL.ANALYZE_OBJECT("TABLE", "SCOTT", "EMP", "ESTIMATE", NULL,50);
2)
DBMS_UTILITY.ANALYZE_SCHEMA (
SCHEMA VARCHAR2,
METHOD VARCHAR2,
ESTIMATE_ROWS NUMBER DEFAULT NULL,
ESTIMATE_PERCENT NUMBER DEFAULT NULL,
METHOD_OPT VARCHAR2 DEFAULT NULL ) ;
DBMS_UTILITY.ANALYZE_DATABASE (
METHOD VARCHAR2,
ESTIMATE_ROWS NUMBER DEFAULT NULL,
ESTIMATE_PERCENT NUMBER DEFAULT NULL,
METHOD_OPT VARCHAR2 DEFAULT NULL );
其中,ANALYZE_SCHEMA用于对某个用户拥有的所有TABLE,INDEX和CLUSTER的分析统计。ANALYZE_DATABASE用于对整个数据库进行分析统计。
3) DBMS_STATS是在ORACLE8I中新增的程序包,它使统计数据的生成和处理更加灵活方便,并且可以并行方式生成统计数据。在程序包中的以下过程分别分析统计TABLE,INDEX,SCHEMA,DATABASE级别的信息。
DBMS_STATS.GATHER_TABLE_STATS
DBMS_STATS.GATHER_INDEX_STATS
DBMS_STATS.GATHER_SCHEMA_STATS
DBMS_STATS.GATHER_DATABASE_STATS
在这里,我们以数据库JOB的方式,定时对数据库中SCOTT模式下所有的表和索引进行分析:
在SQL*PLUS下运行:
VARIABLE jobno number;
BEGIN
DBMS_JOBS.SUBMIT ( :jobno ,
" dbms_utility.analyze_schema ( "scott", "estimate", NULL, 20) ; ",
sysdate, "sysdate+30");
commit;
end;
/
Statement processed.
Print jobno
JOBNO
-------------
16
以上作业,每隔一个月用DBMS_UTILITY.ANALYZE_SCHEMA对用户SCOTT的所有表,簇表和索引作统计分析。
收集统计信息的策略
通常情况下,我们会将ORACLE自动收集统计信息功能给关闭,我们会采用手动的方式给数据库收集统计信息。至于收集统计信息的策略需要根据系统来确定。下面说说几种常见的情况:
如果你系统中的表的数据是增量(有规律)的增加,也就是说你几乎不做任何的批量处理操作,比如批量删除,批量加载操作。对于这样的表收集统计信息是非常简单的。你可以通过查看DBA_TAB_MODIFICATIONS视图来观察表的变化情况,观察表中数据量的变化是否超过了10%,并且记录下天数。这样你就可以每隔这样的时间间隔对其收集一次统计信息。你可以用CRONTAB,或者JOB调用GATHER_SCHEMA_STATS或者GATHER_TABLE_STATS过程来收集统计信息。
对于经常批量操作的表,那么表的统计信息就必须在批量操作之后对其收集统计信息。
对于分区表,通常只有一个分区被修改,这种情况下可以只收集单独分区的统计信息,不过收集整个表的统计信息还是非常有必要的。