Optimizer统计信息管理介绍

1.    前言

在我们的日常维护中受理一些一直以来运行得非常好的系统,突然有一天用户反馈没有做不论什么操作,系统的某个功能模块或者是某个报表曾经仅仅须要几秒。但如今须要几分钟或更长的时间都没有返回结果。在这种情况下,我们一般会分析SQL语句。会发现这个SQL的运行计划已经发生改变,在硬件环境未发生变化的情况下。运行计划发生变化多数原因是因为表的统计信息发生了变化,原本使用的某个索引突然间没有被使用。或者使用了较差的索引,这都是因为统计信息不准备确引起的,因此我们有必要了解统计信息的管理和维护。更好的优化SQL和性能问题处理。

2.    什么是统计信息

统计信息是描写叙述该数据库中的数据和数据库中的对象的集合。这些统计数据所使用的优化选择对每一个SQL语句的最佳运行计划。统计信息存储在数据字典,而且能够使用数据字典视图来訪问诸如USER_TAB_STATISTICS。优化统计数据是从通过V $视图中显示的性能统计信息不同。在V$视图中的信息涉及该系统的状态和SQL负载上运行它。

Oracle 10g之后。Query Optimizer就已经将CBO作为默认优化器,而且Oracle官方不再支持10G曾经的RBO服务。可是,通过优化器參数OPTIMIZER_MODE,我们能够控制Oracle优化器生成不同模式下的运行计划。数据库中的对象能够是不断变化的,统计数据必须定期更新。以便准确地描写叙述这些数据库对象,统计都是由Oracle自己主动地或手动使用DBMS_STATS包完毕,DBMS_STATS还提供了用于管理统计程序。能够保存和恢复副本统计。

能够从一个系统导出统计数据到还有一个系统。

比如,你能够从一个生产数据库将统计信息导出到一个測试系统。此外,我们还能够锁定统计信息。防止这些统计数据的变化统计。


图1存储统计信息字典视图

2.1. 表统计信息

表统计信息包含表中行的数量信息,表使用数据块的数量,以及行在表中的平均行长度。优化器使用这些信息,结合其他统计信息,以计算各种操作的运行计划成本,并预计行的操作将产生的数量。比如,一个表存取的成本是使用数据块和參数DB_FILE_MULTIBLOCK_READ_COUNT的值进行计算,表的统计信息能够在字典视图USER_TAB_STATISTICS查看。

2.2. 列统计信息

列统计信息包含列上不同值的数量,以及在该列中的最小和最大值。能够在字典视图USER_TAB_COL_STATISTICS查看列统计信息。优化器使用列统计信息和表统计信息的行数预计SQL操作返回的结果。

比如。假设一个表有100条记录,而且訪问表列有10个不同的相等谓词,那么优化器,假定数据分布是均匀的,预计的基数为表中的行数不同的值除以该列,即100 / 10 = 10


图2使用基本表和列统计基数计算

2.3. 索引统计信息

索引统计信息提供索引中不同值的数据信息。叶块中的索引数,索引的深度和集群因子数目的数量。优化程序会使用这些信息连同其它统计信息来确定索引訪问的成本。

比如优化器使用B树索引。将会使用叶块数和表统计中的num_rows确定索引范围扫描的成本。

2.4. 直方图统计信息

直方图是一种对被管理对象某一方面质量进行管理的描写叙述工具,在Oracle中自然它也是对Oracle中某个对象质量的描写叙述工具,这个对象就是Oracle中最重要的东西——“数据”。

Oracle中直方图是一种对数据分布质量情况进行描写叙述的工具。它会依照某一列不同值出现数量多少。以及出现的频率高低来绘制数据的分布情况,以便可以指导优化器依据数据的分布做出正确的选择。在某些情况下,表的列中的数值分布将会影响优化器使用索引还是运行全表扫描的决策。当WHERE子句的值具有不成比例数量的数值时,将出现这样的情况。使得全表扫描比索引訪问的成本更低。

这样的情况下假设WHERE子句的过滤谓词列之上有一个合理的,正确的直方图,将会对优化器使用索引还是全表扫描发挥巨大的作用,使得SQL语句运行成本最低从而提升性能。

在分析表或索引时,直方图用于记录数据的分布。通过获得该信息,基于成本的优化器就能够决定使用将返回少量行的索引。而避免使用基于限制条件返回很多行的索引。

直方图的使用不受索引的限制,能够在表的不论什么列上构建直方图。

构造直方图最基本的原因就是帮助优化器在表中数据严重偏斜时做出更好的规划:比如,假设一到两个值构成了表中的大部分数据(数据偏斜),相关的索引就可能无法帮助降低满足查询所需的I/O数量。创建直方图能够让基于成本的优化器知道何时使用索引才最合适,或何时应该依据WHERE子句中的值返回表中80%的记录。

通常情况下在下面场合中建议使用直方图:

1)        Where子句引用了列值分布存在明显偏差的列时:当这样的偏差相当明显时。以至于 WHERE子句中的值将会使优化器选择不同的运行计划。

这时应该使用直方图来帮助优化器来修正运行路径。(注意:假设查询不引用该列,则创建直方图没有意义)

2)        当列值导致不对的推断时:这样的情况一般会发生在多表连接时。比如,如果我们有一个五项的表联接,其结果集仅仅有 10行。Oracle 将会以一种使第一个联接的结果集(集合基数)尽可能小的方式将表联接起来。通过在中间结果集中携带更少的负载。查询将会执行得更快。为了使中间结果最小化,优化器尝试在 SQL执行的分析阶段评估每一个结果集的集合基数。在偏差的列上拥有直方图将会极大地帮助优化器做出正确的决策。

如优化器对中间结果集的大小做出不对的推断,它可能会选择一种未达到最优化的表联接方法。因此向该列加入直方图常常会向优化器提供使用最佳联接方法所需的信息。

Oracle利用直方图来提高非均匀数据分布的选择率和技术的计算精度。可是实际上Oracle会採用另种不同的策略来生成直方图:当中一种是针对包括非常少不同值的数据集;还有一种是针对包括非常多不同的数据集。

Oracle会针对第一种情况生成频率直方图。针对另外一种情况生成高度均衡直方图。通常情况下当BUCTET < 表的NUM_DISTINCT值得到的是HEIGHT BALANCED(高度平衡)直方图。而当BUCTET > 表的NUM_DISTINCT值的时候得到的是FREQUENCY(频率)直方图。

3.    管理统计信息

Oracle 建议启用自己主动优化程序统计信息收集。在这样的情况下,数据库会自己主动收集没有被收集过的统计信息或过时的统计信息。假设一个新表须要收集统计信息,数据库会收集表和关联的索引。

自己主动优化统计信息收集程序执行DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC调用,数据统计信息收集过程DBMS_STATS.GATHER_DATABASE_STATS,该过程使用GATHER AUTO选项收集数据库表的信息和索引信息。使统计信息为最新状态。GATHER_DATABASE_STATS_JOB_PROC过程进行统计信息收集,过程会优先数据库对象统计收集,所以在收集统计信息期间要对数据库的对象更新操作时。须要关闭自己主动统计收集作业。

3.1. 启用和禁用自己主动统计信息收集

Oracle自己主动维护任务基础结构(称为 AutoTask调度程序会在维护窗体中自己主动执行该任务。

默认情况下,每周六的晚上。自己主动优化程序统计信息收集作为 AutoTask 的一部分执行,默认启用的在全部的提前定义的维护窗体中执行。

假设对于一些原因自己主动优化程序统计信息收集被禁用,能够使用DBMS_AUTO_TASK_ADMIN包手动启用:

BEGIN

 DBMS_AUTO_TASK_ADMIN.ENABLE(

    client_name => 'auto optimizer stats collection'

,   operation   => NULL

,   window_name => NULL

);

END;

/

假设採用手动管理方式收集统计信息,相同能够使用能够使用DBMS_AUTO_TASK_ADMIN包手动禁用作业:

BEGIN

 DBMS_AUTO_TASK_ADMIN.DISABLE(

    client_name => 'auto optimizer stats collection'

,   operation   => NULL

,   window_name => NULL

);

END;

/

3.2. DBMS_STATS统计信息管理

对于不断变化的数据库对象。必须定期收集统计数据以便他们准确地描写叙述数据库对象。Oracle推荐使用DBMS_STATS过程 包收集统计信息,并代替如今已经过时的统计信息收集命令ANALYZE DBMS_STATS 包包括超过 50 不同的过程。用于收集和管理统计。并且最重要的过程是 GATHER_ * _STATS 程序。

这些过程能够用于收集和管理表、 列和索引的统计信息,必须使用对象的全部者或有不论什么具有系统特权的DBA 角色执行这些程序,下面是DBMS_STATS包中收集统计信息涉及到的过程。

名称

用途描写叙述

GATHER_INDEX_STATS

收集特定用户下指定索引列的统计信息

GATHER_TABLE_STATS

收集特定用户指定表上表行,列和索引列的统计信息

GATHER_SCHEMA_STATS

收集特定用户全部对像的统计信息

GATHER_DICTIONARY_STATS

收集数据库全部数据字典统计信息

GATHER_DATABASE_STATS

收集数据库全部对象统计信息

3.2.1.    手动採集表统计信息

这些程序使用的參数是差点儿同样。因此这里列举 GATHER_TABLE_STATS 过程的參数作为说明,GATHER_TABLE_STATS包过程用于收集表,分区,索引和列的统计信息。这个过程拥有15个不同的參数。我们在收集表的统计信息时,仅仅需指定ownnametabname这两个參数,过程包就能够执行。

假设表是分区表还须要指分区名称。比如我们对住院费用记录表进行统计信息进行收集,使用下面方式就能够收集到该表的统计信息。

SQL> begin

 2   dbms_stats.gather_table_stats(ownname => 'ZLHIS',

 3                              tabname => '药品库存');

 4  end;

 5  /

PL/SQL procedure successfullycompleted

在进行数据採集时我们有时会使用到其他输入參数。在这里我们对过程中的其他输入參数介绍。

ESTIMATE_PERCENT

ESTIMATE_PERCENT參数确定用来计算统计信息行数的百分比,最准确的统计信息收集处理是收集表中的全部行。Oracle 11g使用一种新的採样算法。基于哈希值并提供准确的统计信息。这样的新方法精度接近全部行(100%)样品。但顶多消耗10%样品的成本。

ESTIMATE_PERCENT的默认值设置为AUTO_SAMPLE_SIZE。将使用这样的新算法。

GATHER_ * _STATS 程序。

我们在对ZLHIS对象收集统计信息时,将ESTIMATE_PRECENT參数设置为较低的值,一般是10%的方式收集,这样做以确保将收集统计数据的结果迅速。

当然为了数据库得到更准备统计信息。Oracle强烈建议从 Oracle 11g 起使用ESTIMATE_PRECENT參数的默认值收集统计信息,该參数的取值范围为取值范围[0.000001-100]

演示样例:參数ESTIMATE_PERCENT=10以病人医嘱发送数据表数据10%的比例进行数据收集。

begin

 dbms_stats.gather_table_stats(ownname          => 'ZLHIS',

                                tabname          => '病人医嘱发送',

                               estimate_percent=> 10,

                                method_opt       => 'for all  columns size skewonly',

                                force            => true,

                                cascade          => true,

                                degree           => 4);

end;

METHOD_OPT

这个參数最常见的功能就是控制直方图的收集方式,但实际上它的功能远不及此,它的实际功能例如以下所看到的:

ü 控制哪些列收集主要的统计信息

ü 收集直方图,

ü 收集扩展的统计信息

Method_opt 參数使用方法分为两个部分,例如以下图所看到的:


FOR ALL [indexed | hidden] columns这一部分控制着哪些列将会收集列的基本统计信息。目标列上的最小值,最大值。列上不同值的数量。空值的数量等等。

系统默认值为FOR ALL COLUMNS它将收集表上全部列(包含隐藏列)的主要的统计信息。

指定FOR ALL INDEXED COLUMNS 仅仅收集含有索引字段列的基本统计信息。

一般不推荐使用这个选项值,由于在数据库环境中的全部 SQL语句所使用的字段,比方SELECT 后面的字段,WHERE后面字段,GROUP BY中的字段,并不仅仅是会引用含有索引的字段。

指定FOR ALL HIDDEN COLUMNS收集全部不可见字段基本统计信息,相同在收集统计信息时不推荐使用这个选项值。这个选项值通常仅仅用于在一个全部列的统计信息都是准确的表中新增了一个或几个不可见或者说是虚拟的列,仅仅须要收集这个或者这几个不可见列的统计信息,而不再反复去其它列的统计信息。

Size [size_clause]这一部分控制收集直方图的方式。SIZE 后面能够有下面选项:     

AUTO  Oracle自己决定依据列的统计信息(sys.col_usage$)以及列的数据倾斜程度(均匀分布程度)决定哪些列须要收集直方图。

INTEGER 指定收集直方图的桶数。桶数最小为 1最大为 254 (针对 11g及曾经的版本号, 12c后没有这个限制)。注意假设桶数为 1SIZE 1 意味着不建立直方图,假设已经有直方图的列则会删除该列的直方图。

REPEAT仅仅在已经有直方图的列上又一次收集直方图。REPEAT会确保在全局级别上对已经存在直方图的列又一次收集直方图。一般不推荐使用这个选项,由于新的直方图使用的桶数将不能超过旧的直方图中的桶数。如果当前直方图中桶数为 5当使用SIZE REPEAT又一次收集直方图时,新的直方图使用的桶数将不能超过 5。这钟方式可能不会取得好的效果。

SKEWONLY 仅仅在数据不均匀分布的列上收集直方图。

演示样例:參数METHOD_OPT = 'FOR ALL COLUMNS SIZESKEWONLY'收集病人医嘱分布不均匀列的直方图统计信息。

begin

 dbms_stats.gather_table_stats(ownname          => 'ZLHIS',

                                tabname          => '病人医嘱发送',

                               estimate_percent => 10,

                               method_opt      => 'for all  columns size skewonly',

                                force            => true,

                                cascade          => true,

                                degree           => 4);

end;

 

DEGREE

DEGREE參数控制server并行收集统计数据的进程数。默认情况下,Oracle数据库中的全部表的DEGREE属性为1。我们能够更改这个參数值。加快统计数据的收集。

DEGREE设置值为DMBS_STATS.AUTO_DEGREEOracle依据并行server进程数參数(PARALLEL_MAX_SERVERS)值自己主动分配进程数收集统计信息。

对一个数据量较小的对象,使用缺省值1就可以。对大数据对象的能够使用DBMS_STAT.DEFAULT_DEGREE參数由数据库自己主动分配并行度。

演示样例:DEGREE=44个进程收集病人医嘱发送记录的统计信息。

begin

 dbms_stats.gather_table_stats(ownname          => 'ZLHIS',

                                tabname          => '病人医嘱发送',

                               estimate_percent => 10,

                                method_opt       => 'for all  columns size skewonly',

                                force            => true,

                                cascade          => true,

                               degree          => 4);

end;

CASCADE

在系统上没有执行过索引统计信息收集。使用CASCADE选项相当于在除了收集表和列统计并同一时候执行 GATHER_INDEX_STATS收集索引统计信息。使用參数DBMS_STATS.AUTO_CASCADEORACLE确定是否收集索引统计信息要,參数设置为TRUE强制收集全部索引统计信息,在缺省情况下CASCADE參数值为FALSE

演示样例:强制收集病人医嘱发送上的全部索引统计信息。

begin

 dbms_stats.gather_table_stats(ownname          => 'ZLHIS',

                                tabname          => '病人医嘱发送',

                               estimate_percent => 10,

                                method_opt       => 'for all  columns size skewonly',

                                force            => true,

                               cascade         => true,

                                degree           => 4);

end;

3.2.2.    锁定和解锁一个表统计信息

在某些情况下我们须要锁定一个特定表的统计息不被更新。以保证运行计划的准确性,我们须要使用DBMS_STATS.LOCK_TABLE_STATS锁定统计信息。

要锁定一个表的统计信息我们仅仅须要传入表的拥有者和表名就能够锁定该用户表的统计信息。

反之我们要解锁一个锁定的用户对象使用DBMS_STAT.UNLOCK_TABLE_STATS解锁锁定的统计信息。

演示样例:锁定ZLHIS用户下药品收发记录统计信息。

begin

 DBMS_STATS.LOCK_TABLE_STATS(ownname =>'ZLHIS' , tabname =>'药品收发记录' );

end;

演示样例:解锁被锁定的ZLHIS用户下药品收发记录统计信息。

begin

 DBMS_STATS.UNLOCK_TABLE_STATS(ownname =>'ZLHIS' , tabname =>'药品收发记录' );

end;

3.2.3.    删除统计信息

有的时候我们在收集了统计信息却发现新的统计信息比旧的统计信息还要差,因此我们须要将统计信息删除又一次收集。下面列出删除统计信息相关过程。

名称

用途描写叙述

DELETE_INDEX_STATS

删除特定用户下指定索引列的统计信息

DELETE_TABLE_STATS

删除特定用户指定表上表行,列和索引列的统计信息

DELETE _SCHEMA_STATS

删除特定用户全部对像的统计信息

DELETE _DICTIONARY_STATS

删除数据库全部数据字典统计信息

DELETE _DATABASE_STATS

删除数据库全部对象统计信息

演示样例:删除ZLHIS用户药品收发记录表统计信息

begin

 DBMS_STATS.delete_table_stats(ownname =>'ZLHIS' , tabname =>'药品收发记录' )

end;

3.3. 与统计相关的视图

全部与数据表,列和索引相关的统计信息都能够通过Oracle数据库字典视图查询,常使用的视图有:

名称

用途描写叙述

DBA_TAB_COLUMNS

ALL_TAB_COLUMNS

USER_TAB_COLUMNS

DBA视图描写叙述数据库中全部表列。用户视图仅限于由用户拥有的表,在这些视图中统计信息有关的列由DBMS_STATS 包或ANALYZE语句生成的统计信息。

DBA_TAB_STATISTICS

ALL_TAB_STATISTICS

USER_TAB_STATISTICS

描写叙述表的统计信息

DBA_INDEXES

ALL_INDEXES

USER_INDEXES

DBA 视图描写叙述在数据库中的全部表上的索引。

全部视图都描写叙述在用户可訪问的全部表上的索引。用户视图仅限于由用户拥有的索引。在这些视图中的统计信息有关的列包括由DBMS_STATS 包或ANALYZE语句生成的统计

在这里我们使用USER_TAB_STATISTICS视图为例先了解视图USER_TAB_STATISTICS字段的含义后,使用该视图查看表药品收发记录统计信息。

USER_TAB_STATISTICS

例名

描写叙述

TABLE_NAME               

表名

PARTITION_NAME           

分区表名

PARTITION_POSITION       

分区位置

SUBPARTITION_NAME        

子分区表名

SUBPARTITION_POSITION    

子分区位置

OBJECT_TYPE              

对象类型(表,分区。子分区)

NUM_ROWS                 

对象中的行记录数

BLOCKS                   

对象使用的数据块数

EMPTY_BLOCKS             

对象中的空块数

AVG_SPACE                

对象中的平均可用空间

CHAIN_CNT                

对象中的行连接数

AVG_ROW_LEN              

对象中行记录的平均长度

AVG_SPACE_FREELIST_BLOCKS

在一个自由列表的全部块的平均可用空间

NUM_FREELIST_BLOCKS      

在一个自由列表的块的数量

AVG_CACHED_BLOCKS        

在缓冲区快速缓存中的平均块数

AVG_CACHE_HIT_RATIO      

平均缓存对象的命中率

SAMPLE_SIZE              

採样样本

LAST_ANALYZED            

最后一次表分析时间

GLOBAL_STATS             

没有合并的分区计算的统计?

USER_STATS               

统计信息是否为用户输入

STATTYPE_LOCKED

锁定统计信息类型

STALE_STATS    

统计信息是否过期

比如。我们如今查询药品收发记录的相关统计信息的行数。表分析的採样样本,统计信息是否被锁定,统计信息是否过期这几种情况,能够使用字段NUM_ROWS,SAMPLE_SIZE,LAST_ANALYZED,STATTYPE_LOCKED,STALE_STATS获取相关信息


4.    结束语

通过我们对统计的了解。已经知道统计信息对Oracle是很重要的,它会收集数据库中对象的具体信息。并存储在对应的数据字典里。依据这些统计信息,优化器能够对每一个SQL去选择最好的运行计划,统计信息收集作业由Oracle定期自己主动收集,但某些特殊情况下还须要我们进行手动维护和管理。比如我们产品升级后及时手动採集数据库的统计信息是很有必要的。

原文地址:https://www.cnblogs.com/brucemengbm/p/7227671.html