使用dbms_stats 还是analyze
自从Oracle8.1.5引入dbms_stats包, Oracle及专家们就推荐使用dbms_stats取代analyze。 理由如下:
1. dbms_stats可以并行分析
2. dbms_stats有自动分析的功能(alter table monitor )
3. analyze 分析统计信息的有些时候不准确
第1,2比较好理解,且第2点实际上在VLDB(Very Large Database)中是最吸引人的;3以前比较模糊,看了metalink236935.1 解释,analyze在分析Partition表的时候,有时候会计算出不准确的Global statistics 。 原因是dbms_stats会实在的去分析表全局统计信息(当指定参数);而analyze是将表分区(局部)的statistics 汇总计算成表全局statistics ,可能导致误差。 没有分区表的情况下两个都可以使用(看个人习惯,当然也可以分区表使用dbms_stats, 其他使用analyze )。
不过在一些论坛上也有看到dbms_stats 分析之后出现统计数据不准确的情况,而且确实有bug 在dbms_stats 上(可能和版本有关,有待查明),应该是少数情况,需要我们注意。 还有,一般不建议analyze 和dbms_stats 混用。 实验: 如果在分区表上用dbms_stats统计后,再使用 analyze table 来统计,就会出现表信息不被更新的问题。 删除统计信息后再分析就更新了,或者直接用dbms_stats分析。 dbms_stats 目前有遇到的bug例子如下: http://www.itpub.net/viewthread.php?tid=959290&highlight=dbms%5C_stats
dbms_stats包可以分析table、Index或者整个用户(schema),数据库,可以并行分析。
不同版本包有些不一样, dbms_utility (8i以前的工具包),dbms_stats (8i或以后提供的工具包) ,具体的dbms_stats 包的众多功能介绍见后面。
对命令与工具包的一些总结:
1、对于分区表,建议使用DBMS_STATS,而不是使用Analyze语句。
a) 可以并行进行,对多个用户,多个Table
b) 可以得到整个分区表的数据和单个分区的数据。
c) 可以在不同级别上Compute Statistics:单个分区,子分区,全表,所有分区
d) 可以导出统计信息
e) 可以用户自动收集统计信息(alter table monitor )
2、DBMS_STATS的缺点:
a) 不能Validate Structure (注意:validate structure 主要在于校验对象的有效性. compute statistics在于统计相关的信息) 。
b) 不能收集CHAINED ROWS(行链接), 不能收集CLUSTER TABLE(簇表)的信息,这两个仍旧需要使用Analyze语句。
c) DBMS_STATS 默认不对索引进行Analyze,因为默认Cascade是False,需要手工指定为True 。即GATHER_TABLE_STATS:分析表信息,当cascade为true时,分析表、列(索引)信息。
Analyze是同时更新表和索引的统计信息,而dbms_stats会先更新表的统计信息,然后再更新索引的统计信息(默认Cascade是False),这里就有一个问题,就是当表的统计信息更新后,而索引的统计信息没有被更新,这时候cbo就有可能选择错误的plan 。
3、对于oracle 9里面的External Table,Analyze不能使用,只能使用DBMS_STATS来收集信息。
Analyze 命令语法如下 :
ANALYZE
{ TABLE [ schema.]table
[ PARTITION ( partition ) | SUBPARTITION ( subpartition ) ]
| INDEX [ schema. ]index
[ PARTITION ( partition ) | SUBPARTITION ( subpartition ) ]
| CLUSTER [ schema. ]cluster
}
{ COMPUTE [ SYSTEM ] STATISTICS [for_clause]
| ESTIMATE [ SYSTEM ] STATISTICS [for_clause][SAMPLE integer { ROWS | PERCENT }]
| validation_clauses
| LIST CHAINED ROWS [ into_clause ]
| DELETE [ SYSTEM ] STATISTICS
} ;
dbms_stats所有的功能包如下:
GATHER_INDEX_STATS:分析索引信息
GATHER_TABLE_STATS:分析表信息,当cascade为true时,分析表、列(索引)信息
GATHER_SCHEMA_STATS:分析方案信息
GATHER_DATABASE_STATS:分析数据库信息
GATHER_SYSTEM_STATS:分析系统信息
EXPORT_COLUMN_STATS:导出列的分析信息
EXPORT_INDEX_STATS:导出索引分析信息
EXPORT_SYSTEM_STATS:导出系统分析信息
EXPORT_TABLE_STATS:导出表分析信息
EXPORT_SCHEMA_STATS:导出方案分析信息
EXPORT_DATABASE_STATS:导出数据库分析信息
IMPORT_COLUMN_STATS:导入列分析信息
IMPORT_INDEX_STATS:导入索引分析信息
IMPORT_SYSTEM_STATS:导入系统分析信息
IMPORT_TABLE_STATS:导入表分析信息
IMPORT_SCHEMA_STATS:导入方案分析信息
IMPORT_DATABASE_STATS:导入数据库分析信息
讨论二: analyze 的使用方法 (分区表建议使用dbms_stats)
可以参考 http://download.oracle.com/docs/cd/B10501_01/server.920/a96540/statements_46a.htm#SQLRF01105
Analyze 的三大功能:
搜集和删除索引、表和簇的统计信息 验证表、索引和簇的结构 鉴定表和簇的行迁移(migrated rows)和行链接(chained rows)
CBO是Oracle推荐使用的优化方式,要想使用好CBO,使SQL语句发挥最大效能,必须保证统计数据的及时性。统计信息的生成可以有完全计算法和抽样估算法。SQL例句如下:
完全计算法: analyze table abc compute statistics;
抽样估算法(抽样20%): analyze table abc estimate statistics sample 20 percent;
对表作完全计算所花的时间相当于做全表扫描,抽样估算法由于采用抽样,比完全计算法的生成统计速度要快,如果不是要求要有非常精确的数据的话,尽量采用抽样分析法。建议对表分析采用抽样估算,对索引分析可以采用完全计算。
Analyze 分析table, index等需要的权限: 必须在你自己的Schema(方案)中或者有ANALYZE ANY 系统权限 。
比如: grant analyze any to tolywang ;
revoke analyze any from tolywang ;
Analyze 使用的局限及改善:
Analyze 命令每次仅仅能影响到一个table(或index), 如果想通过analyze为整个schema或整个数据库中的所有表生成统计数字。可以使用analyze的批处理方式(脚本)。
Analyze 分析命令解析:
ANALYZE
{ TABLE [ schema.]table
[ PARTITION ( partition ) | SUBPARTITION ( subpartition ) ]
| INDEX [ schema. ]index
[ PARTITION ( partition ) | SUBPARTITION ( subpartition ) ]
| CLUSTER [ schema. ]cluster
}
{ COMPUTE [ SYSTEM ] STATISTICS [for_clause]
| ESTIMATE [ SYSTEM ] STATISTICS [for_clause][SAMPLE integer { ROWS | PERCENT }]
| validation_clauses
| LIST CHAINED ROWS [ into_clause ]
| DELETE [ SYSTEM ] STATISTICS
} ;
INDEX index: 对索引进行分析,分析的结果会放在USER_INDEXES, ALL_INDEXES,或 DBA_INDEXES中 。一般仅需要对索引进行统计时用到。
分析的内容:
Depth of the index from its root block to its leaf blocks (BLEVEL) 从索引的根块到其叶块的索引的深度(级数)。
Number of leaf blocks (LEAF_BLOCKS) 叶块的数量,这些块包括了指向表中及索引中行的指针。
Number of distinct index values (DISTINCT_KEYS) 不同索引值的数量 。
Average number of leaf blocks for each index value (AVG_LEAF_BLOCKS_PER_KEY) 包括每一个值的记录的叶块的平均数。
Average number of data blocks for each index value (for an index on a table) (AVG_DATA_BLOCKS_PER_KEY) 被一个索引值指向的数据块的平均数量。
Clustering factor (how well ordered the rows are about the indexed values) (CLUSTERING_FACTOR) 一个簇因子,表明了表中的行的顺序和索引中的顺序相匹配的紧密程度。
LAST_ANALYZED 为索引生成的统计数字的日期。
TABLE table:对表进行分析,分析的结果会放在USER_TABLES, ALL_TABLES 和DBA_TABLES视图中,当为表收集统计数字时,除非以别的方式指明,否则Oracle也为那个表中的索引收集统计数字。还有,在分析表的时候,oracle也会分析基于函数的index所引用的表达式。
分析table产生的内容 (在上面的几个视图列中可以找到):
Number of rows (NUM_ROWS) * 表中行的数量 。
Number of data blocks below the high water mark (that is, the number of data blocks that have been formatted to receive data, regardless whether they currently contain data or are empty) (BLOCKS) 高水位一下的数据块数量(不管是否现在有数据还是空的) 。
* Number of data blocks allocated to the table that have never been used (EMPTY_BLOCKS) 分配给表但未被数据使用的数据块的数量。
Average available free space in each data block in bytes (AVG_SPACE) 在每一块中自由空间数量的平均值(以字节表示)。
Number of chained rows (CHAIN_CNT) 链接行的数量。
Average row length, including the row's overhead, in bytes (AVG_ROW_LEN) 在表中行的平均长度,以字节表示。
LAST_ANALYZED : 为表生成统计数据的日期。
分析表的限制:
不可以分析数据字典表
不可以分析扩展表,但可以用DBMS_STATS来实现这个目的
不可以分析临时表
不可以计算或估计下列字段类型:REFs, varrays, nested tables, LOBs (LOBs are not analyzed, they are skipped), LONGs, or object types.
分析分区表最好使用DBMS_STATS来实现 。
PARTITION | SUBPARTITION:对分区表或索引进行分析
CLUSTER cluster: 对簇进行分析,分析的结果会放在ALL_CLUSTERS, USER_CLUSTERS and DBA_CLUSTERS.
compute_statistics_clause
语法:COMPUTE [ SYSTEM ] STATISTICS [for_clause]
对分析对像进行精确的统计,然后把信息存储的数据字典中。可以选择对表或对字段进行分析。computed和estimated这两种方式的统计数据都被优化器用来影响sql的执行计划
如果指定system选项就只统计系统产生的信息 。
for_clause :
FOR TABLE:只统计表
FOR COLUMNS:只统计某个字段
FOR ALL COLUMNS:统计所有字段
FOR ALL INDEXED COLUMNS:统计索引的所有字段
FOR ALL INDEXES: 只分析索引
FOR ALL LOCAL INDEXES 针对分区表中的本地索引
estimate_statistics_clause
ESTIMATE [ SYSTEM ] STATISTICS [for_clause][SAMPLE integer { ROWS | PERCENT }]
只是对部分行做一个大概的统计。适用于大表
SAMPLE:指定具体统计多少行,如果忽略这个参数的话,oracle会默认为1064行
ROWS causes:行数 Oracle to sample integer rows of the table or cluster or integer entries from the index. The integer must be at least 1.
PERCENT causes:百分数 。 一般情况下,建议在可以得到足够精确的统计的前提下使用最小的百分比 。
validation_clauses
分析REF或是对像的结构
比如 :ANALYZE TABLE employees VALIDATE STRUCTURE CASCADE;
ANALYZE TABLE customers VALIDATE REF UPDATE;
validate structure : ANALYZE INDEX XXXXX VALIDATE STRUCTURE; 检查表里的行数据的完全性,并检查表或者是索引的结构,并把分析过的结果写入INDEX_STATS 数据字典中。
对于cascade , 有如下解释: Specify CASCADE
if you want Oracle to validate the structure of the indexes associated with the table or cluster. If you use this clause when validating a table, then Oracle also validates the table's indexes. If you use this clause when validating a cluster, then Oracle also validates all the clustered tables' indexes, including the cluster index.
---------------------------------------------------------------------------------------------------------------
备注: 需要注意一下各种统计方式的等价性以及执行的先后顺序。 比如:
analyze table t compute statistics = analyze table t compute statistics for table for all indexes
还有,任何时候生成表统计的数字时,都擦掉了任意列的统计数字。 所以需要顺序的执行命令,以免出现问题。
先 analyze table t compute statistics , 然后 analyze table t compute statistics for all indexed columns . 如果顺序错误,那么列相关统计信息就会被覆盖。
另外, for all columns 是对数据列进行直方图统计 。
---------------------------------------------------------------------------------------------------------------
统计分析后的信息存储视图:
一般我们需要养成一种习惯,在分析之前,需要建立备份表,用于备份之前最近的一次统计分析数据,dbms_stats 包提供了专用的导入导出功能 。而Analyze分析之后的统计信息存放在以下几个视图中 :
for table的统计信息存在于视图:user_tables 、all_tables、dba_tables
for all indexes的统计信息存在于视图: user_indexes 、all_indexes、dba_indexes
for all columns的统计信息存在于试图:user_tab_columns、all_tab_columns、dba_tab_columns
统计分析信息的删除 :
当analyze table table_name delete statistics 会从数据字典中删除这个table的所有的statistics以及它的所有index统计信息 。
查看表统计数字: 可以通过在dba_tables, all_tables和user_tables数据字典视图中的列来访问这些统计数字 。当为表收集统计数字时,除非以别的方式指明,否则Oracle也为那个表中的index收集统计信息。
NUM_ROWS 表中行的数量
BLOCKS 高水位一下的数据块数量(不管是否现在有数据还是空的)
EMPTY_BLOCKS 分配给表但未被数据使用的数据块的数量
AVG_SPACE 在每一块中自由空间数量的平均值(以字节表示)
CHAIN_CNT 链接行的数量
AVG_ROW_LEN 在表中行的平均长度,以字节表示
LAST_ANALYZED 为表生成统计数字的日期 。
查看索引统计数字: 可以通过在dba_indexes, all_indexes和user_indexes数据字典视图中的列来访问这些统计数字 。
BLEVEL 从索引的根块到其叶块的索引的深度(级数)。
LEAF_BLOCKS 叶块的数量,这些块包括了指向表中及索引中行的指针。
DISTINCT_KEYS 不同索引值的数量 。
AVG_LEAF_BLOCKS_PER_KEY tolywang
以下应用的具体实例:
CREATE OR REPLACE PROCEDURE common_analyze_table(AN_BUTTON_ID NUMBER, --节点ID
AVC_AREAID VARCHAR2, --区号
AVC_CYCLEID VARCHAR2, --数据周期
AVC_LASTCYCLEID VARCHAR2, --上一次成功数据周期
AVC_TABLENAME VARCHAR2, --表名
an_record OUT NUMBER,
an_return OUT NUMBER,
avc_syserrtext OUT VARCHAR2) IS
------ 公共变量
lerror NUMBER; ------ 是否错误标识 1 target没有配置*/
err_exception EXCEPTION; ------
--lerrorcode VARCHAR2(100);
lerrorcode NUMBER;
strSQL LONG;
------ END 公共变量
/*测试信息*/
lTime NUMBER;
dateStart DATE;
dateEnd DATE;
BEGIN
an_return := 0;
avc_syserrtext := 'OK';
an_record := -1;
dateStart := sysdate;
/*********begin main module***************/
strSQL := 'analyze table '||AVC_TABLENAME||'_'||AVC_CYCLEID||' compute statistics for table for all indexes';
EXECUTE IMMEDIATE strSQL;
dateEnd := SYSDATE;
lTime := (dateEnd - dateStart) * 24 * 60 * 60;
/***********end main module***************/
EXCEPTION WHEN OTHERS THEN
an_return := -1;
avc_syserrtext := 'ERROR: ' || SQLERRM || 'SQL = ' || strsql;
SELECT REPLACE(avc_syserrtext, '''', '/')
INTO avc_syserrtext
FROM dual;
dateEnd := SYSDATE;
lTime := (dateEnd - dateStart) * 24 * 60 * 60;
END;