数据库性能优化、统计信息与对象统计信息概述收集、扩展统计信息、dbms_stats.get_prefs

数据库性能优化
 相关书籍:
      1.基于成本的Oracle优化法则
      2.Oracle性能诊断艺术
      3.基于Oracle的SQL优化
-----------------------------------------------------------------------------------------
两种优化器:

CBO  cost-base optimizer 
     基于cost 更大适应性/灵活性/10g开始

RBO  rule-base optimizer 
     基于规则 制定了15条/10g以前
-------------------------------------------------------------------------------------------
统计信息:
1.系统统计信息       
  cpu、I/O
  exec dbms_stats.gather_system_stats;
2.数据库对象统计信息 
  表、索引、列、扩展
  exec dbms_stats.gather_table_stats('TEST_USER1','TEST_1');
   --收集表的统计信息(同时会级联收集索引和列的统计信息)
  exec dbms_stats.gather_table_stats('TEST_USER1','TEST_1',cascade=>false);
   --不会联机收集索引和列的统计信息
  exec dbms_stats.gather_index_stats('TEST_USER1','INDEX_NAME');
   --收集索引的统计信息
 
   alter table table_name enable row movement;
   --允许表的行迁移
   alter table table_name shrink space;
   --降低表的高水位线

  exec dbms_stats.gather_database_stats;
   --收集整个数据库的统计信息

-------------------------------------------------------------------------------------------
直方图
扩展统计信息

query rewrite 查询重写
 星形转换
 视图合并
 为此前推
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------

1,统计信息概述
统计信息是oracle CBO计算候选执行计划的cost的基础。因此,获取准确的统计信息,
是oracle能够选择最优执行计划(cost最低)的首要条件。
在oracle 9i的时候,oracle只计算每个执行计划的I/O成本,并将其作为评价执行计划好坏的依据。
从10g开始,oracle将sql执行中消耗的cpu资源,也作为成本计入执行计划的成本计算。
因此,一个执行计划的cost值,包含了cpu和I/O两种资源的成本。

与统计信息相关的几个初始化参数
SQL> show parameter statistics;
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_use_pending_statistics     boolean     FALSE
statistics_level                     string      TYPICAL
timed_os_statistics                  integer     0
timed_statistics                     boolean     TRUE
 
optimizer_use_pending_statistics:
显示CBO是否使用pending状态的统计信息。
一般情况下,我们收集完统计信息,则oracle会默认将新收集到的统计信息置于publish状态,这样CBO可以随时使用。
我们可以使用dbms_stats.DELETE_PENDING_STATS删除处于pending状态的统计信息,也可以使用
dbms_stat.set_*_prefs来设置统计信息是否处于publish状态。

timed_statistics
是否收集与时间相关的统计信息。例如cpu和elapsed times。
  如果STATISTICS_LEVEL设置为TYPICAL或者ALL, 则该参数的默认值为true;
  如果STATISTICS_LEVEL设置为BASIC, 则该参数的默认值为false。
从11.1.0.7.0开始,如果STATISTICS_LEVEL设置为TYPICAL或者ALL,该参数不能被设置为false。

timed_os_statistics
该参数指定了当从客户端生成一个请求,或者完成一个请求的时候,收集系统统计信息的时间间隔(单位为s)。这又分了两种情况:
dedicated 模式
在用户登录和后继客户端通过OCI调用从而作为一个远程过程调用信息进入oracle server时,oracle收集系统统计信息。
shared 模式
在客户端调用oracle完成时,oracle收集系统统计信息。

  如果STATISTICS_LEVEL设置为ALL, 则该参数默认值为5;
  如果STATISTICS_LEVEL设置为BASIC或者TYPICAL, 则该参数默认值为0。

需要注意的是,收集系统统计信息是相当消耗系统资源的活动。oracle强烈建议你在完成系统统计信息收集之后,立即将该参数修改为0。

statistics_level
控制收集统计信息的级别,有三个参数值:
BASIC :收集基本的统计信息
TYPICAL:收集大部分统计信息(数据库的默认设置)
ALL:收集全部统计信息,除了收集typical模式下的所有统计信息之外,还将收集基于时间的os统计信息和执行计划的统计信息。
(执行计划的统计信息包括什么)

如果将默认值typical改为basic,则将停止收集如下对象的统计信息:
Automatic Workload Repository (AWR) Snapshots
Automatic Database Diagnostic Monitor (ADDM)
All server-generated alerts
Automatic SGA Memory Management
Automatic optimizer statistics collection
Object level statistics
End to End Application Tracing (V$CLIENT_STATS)
Database time distribution statistics (V$SESS_TIME_MODEL and V$SYS_TIME_MODEL)
Service level statistics
Buffer cache advisory
MTTR advisory
Shared pool sizing advisory
Segment level statistics
PGA Target advisory
Timed statistics
Monitoring of statistics

可以用如下sql来查看oracle目前收集哪些对象的统计信息:
select * from v$statistics_level
--------------------------------------------------------------------------------------------------------------------------------------
1.1 系统统计信息
除了收集数据库中所有对象的统计信息以外,oracle也可以收集数据库所在主机的统计信息,也就是os级别的统计信息。
这包括主机的cpu性能(频率),系统I/O的吞吐量等。但是,在默认情况下,oracle不会自动的收集系统统计信息。
因此,当完成数据库在服务器主机上的安装配置之后,可以考虑手动收集系统级别的统计信息。
另外,在数据库主机进行硬件升级之后,尤其是是I/O系统进行了重大升级之后,也应该再次手动收集系统级别的统计信息。
可以用如下的命令来手工完成系统统计信息的收集:
SQL> exec dbms_stats.gather_system_stats;
 
PL/SQL procedure successfully completed
 
SQL> select * from sys.aux_stats$;
 
SNAME                          PNAME                               PVAL1 PVAL2
--------------------------------------------------------------------------------------------
SYSSTATS_INFO                  STATUS                                    COMPLETED
SYSSTATS_INFO                  DSTART                                    06-13-2014 16:52
SYSSTATS_INFO                  DSTOP                                     06-13-2014 16:52
SYSSTATS_INFO                  FLAGS                                   1
SYSSTATS_MAIN                  CPUSPEEDNW                           1504
SYSSTATS_MAIN                  IOSEEKTIM                               2
SYSSTATS_MAIN                  IOTFRSPEED                           4096
SYSSTATS_MAIN                  SREADTIM                                 
SYSSTATS_MAIN                  MREADTIM                                 
SYSSTATS_MAIN                  CPUSPEED                                 
SYSSTATS_MAIN                  MBRC                                     
SYSSTATS_MAIN                  MAXTHR                                   
SYSSTATS_MAIN                  SLAVETHR                                 
 
13 rows selected

该过程中的gathering_mode参数可以用来指定收集系统统计信息的模式:
NOWORKLOAD:  无工作负载模式,用于收集系统I/O部分的统计信息。
INTERVAL:    收集某一指定时间间隔内的统计信息。
START | STOP:手动收集一段时间内的统计信息。
在12c中,又引入了EXADATA模式,用来收集类似于exadata这样具有高I/O吞吐量和吞吐能力的系统统计信息。
注:关于该过程所有参数的详细描述,请参考Oracle Database PL/SQL Packages and Types Reference 12c Release 1 (12.1)第153章。

1.2 数据库对象统计信息
除了系统级别的统计信息,oracle还会收集数据库中对象的统计信息。
不同于系统级别的统计信息,oracle默认会自动收集数据库对象的统计信息。

1.2.1 自动收集统计信息
详情参见统计信息自动收集.txt

1.2.1.1部分特例
在11g及以前版本中,创建索引的时候,由于需要进行全表扫描,因此此时Oracle顺便完成了索引的统计信息收集。而创建表时,则没有类似的动作。
在12c中,当用直接路径加载数据,例如create table as select (CTAS)和insert as select(IAS)时,Oracle也顺便搭载了统计信息
的收集工作。这就意味着,在采用这样的方式加载数据之后,不需要额外的全表扫描来收集统计信息了。

1.2.2 手动收集统计信息
1.2.2.1 DBMS_STATS相关过程
oracle的DBMS_STATS包提供了如下收集计信息的过程:
GATHER_DATABASE_STATS;       收集数据库中所有对象的统计信息        
GATHER_DICTIONARY_STATS;     收集'SYS','SYSTEM'和RDBMS组件对象的统计信息
GATHER_FIXED_OBJECTS_STATS;  收集所有动态性能表的统计信息
GATHER_INDEX_STATS;          收集索引的统计信息
GATHER_PROCESSING_RATE;     
GATHER_SCHEMA_STATS;         收集某一用户的所有对象的统计信息
GATHER_SYSTEM_STATS;         收集系统统计信息
GATHER_TABLE_STATS;          收集表的统计信息

 1.2.2.2 统计信息内容
其中,表、列、索引统计信息分别包含如下内容:
表统计信息(user_tables/all_tables/dba_tables):
NUM_ROWS                记录行数  
BLOCKS                  高水位线以下的数据块数
EMPTY_BLOCKS            高水位线以上数据块数,dbms_stat不统计.
AVG_SPACE               平均空闲空间,不统计
CHAIN_CNT               行迁移行数,不统计
    注:本记录实际上会记录发生行迁移或者行链接现象的所有行数,但是dbms_stats中的任意收集统计信息的过程都不处理这些信息,而只是简单的将该值置为0.可以使用
    ANALYZE TABLE orders LIST CHAINED ROWS INTO chained_rows;
    来获取关于行迁移和行链接的相关信息。其中chained_rows 可以通过
    $ORACLE_HOME/rdbms/admin/utlchain.sql脚本来创建。
AVG_ROW_LEN             行平均长度

列统计信息(user_tab_columns):
NUM_DISTINCT            唯一值数量
LOW_VALUE               该列最小值
HIGH_VALUE              该列最大值
DENSITY                 表示该列数据的重复率,0到1的小数,越接近0表示重复率越低。
NUM_NULLS               该列null值的数量
AVG_COL_LEN             列平均长度,以字节为单位
HISTOGRAM               是否有直方图统计信息,
        none:          没有
        frequency:     频率直方图
        height balanced 高度直方图
NUM_BUCKETS             直方图桶数
 
索引统计信息(user_indexes):
BLEVEL                  索引的深度,也就是层数
LEAF_BLOCKS             叶子块数目
DISTINCT_KEYS           索引distinct键值数目
AVG_LEAF_BLOCKS_PER_KEY 每一个键值的平均叶子块数目
AVG_DATA_BLOCKS_PER_KEY 每一个键值的平均数据块数目
CLUSTERING_FACTOR       簇聚因子 (反映行与索引键值的有序性)

注:统计信息包括但不局限于以上内容。

1.2.2.3 扩展统计信息
在数据库中,oracle默认同一个表的不同列之间,它们的关系是相互独立的。
也就是说,某一列的取值,不会影响到其他列的取值,也不会受到其他列取值的影响。
而在实际当中,往往会存在取值互相影响或者制约的列之间的关系。
比如我们有一个雇员表,其中一列为出生月份,另外一列为星座。显然这两列之间,是存在一定关系的。
为处理这样的问题,oracle引入了扩展统计信息(extension statistics)的概念。
在oracle中,此处的扩展,指的是列的组合,或者是基于列的表达式。
有如下的例子:
HR@ORCL> alter table hr.employees no flashback archive;

HR@ORCL> select dbms_stats.create_extended_stats('hr','employees','(first_name,last_name,job_id)') from dual;

HR@ORCL> exec dbms_stats.gather_table_stats('hr','employees',method_opt=>'for all columns size 1,for columns (first_name,last_name,job_id) size auto');

HR@ORCL> select * from user_stat_extensions where table_name='EMPLOYEES';

注:扩展统计信息中的列组,与复合索引;
扩展统计信息中的基于列的表达式,与函数索引
它们在影响执行计划的时候有何不同?

另注:自动收集统计信息时,不会收集扩展统计信息。

1.2.2.4 estimate_percent参数分析

GATHER_DATABASE_STATS          
GATHER_DICTIONARY_STATS
GATHER_INDEX_STATS
GATHER_SCHEMA_STATS       
GATHER_TABLE_STATS
以上五个收集统计信息的过程,都包含了estimate_percent这个参数。
在12.1的官方文档中,oracle对该参数的解释如下:
 该参数指定了在收集统计信息时对行采样的百分比(NULL表示全部采样)。其可用值的范围为【0.000001,100】。
可以使用常量DBMS_STATS.AUTO_SAMPLE_SIZE来让oracle自己决定采取适当的数值来收集统计信息。这也是默认行为。
该默认值可以通过
SET_DATABASE_PREFS,
SET_GLOBAL_PREFS,
SET_SCHEMA_PREFS,
SET_TABLE_PREFS进行修改。

注:在设置这些默认项之后,也会作用于统计信息的自动收集。

可以使用dbms_stats.get_prefs获取当前系统与统计信息相关的参数的默认值。
可以获取的参数包括
             ■ AUTOSTATS_TARGET
             ■ CASCADE
             ■ CONCURRENT
             ■ DEGREE
             ■ ESTIMATE_PERCENT
             ■ METHOD_OPT
             ■ NO_INVALIDATE
             ■ GRANULARITY
             ■ PUBLISH
             ■ INCREMENTAL
             ■ INCREMENTAL_LEVEL
             ■ INCREMENTAL_STALENESS
             ■ STALE_PERCENT
             ■ GLOBAL_TEMP_TABLE_STATS
             ■ TABLE_CACHED_BLOCKS
             ■ OPTIONS

其中,       
get_prefs用于获取全局的统计信息收集配置选项。
要获取对象级别的统计信息配置选项:
SELECT * FROM DBA_TAB_STAT_PREFS; 

          
例子如下:
SQL> select dbms_stats.get_prefs('estimate_percent') name from dual;
 
NAME
--------------------------------------------------------------------------------
DBMS_STATS.AUTO_SAMPLE_SIZE

按照oracle的解释,AUTO_SAMPLE_SIZE为一个常量,其值可以通过如下方式获取:
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.1.0
Connected as sys@ORCL AS SYSDBA
 
SQL> create table t_val (name varchar2(30),value number);

Table created

SQL> begin
  2  insert into t_val values ('AUTO_SAMPLE_SIZE',DBMS_STATS.AUTO_SAMPLE_SIZE);
  3  end;
  4  /
 
PL/SQL procedure successfully completed
 
SQL> select * from t_val;
 
NAME                        VALUE
--------------------------- ----------
AUTO_SAMPLE_SIZE                     0

显然这不是我们想要的值。
按照oracle的说明,该值的取值范围,也应该在【0.000001,100】之间。
我们可以设计一个实验,来获取该值的一个近似值。

SQL> create table t as select * from dba_objects;
 
Table created

SQL> set timing on;
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE);
 
PL/SQL procedure successfully completed
 
Executed in 0.608 seconds
 
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',estimate_percent => NULL);
 
PL/SQL procedure successfully completed
 
Executed in 0.999 seconds
 
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',estimate_percent => 100);
 
PL/SQL procedure successfully completed
 
Executed in 0.889 seconds
 
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',estimate_percent => 50);
 
PL/SQL procedure successfully completed
 
Executed in 0.483 seconds
 
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T');
 
PL/SQL procedure successfully completed
 
Executed in 0.234 seconds
 
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',estimate_percent => 60);
 
PL/SQL procedure successfully completed
 
Executed in 0.577 seconds
 
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',estimate_percent => 62);
 
PL/SQL procedure successfully completed
 
Executed in 0.593 seconds
 
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',estimate_percent => 65);
 
PL/SQL procedure successfully completed
 
Executed in 0.608 seconds

SQL> set timing off;

由上述实验可知,estimate_percent 设置为null时,为全部采样,也就是100。
当将其设置为其默认值DBMS_STATS.AUTO_SAMPLE_SIZE时,收集统计信息消耗的时间与将其设置为65时相同。
鉴于本实验是在12.1的数据库中测试,所以我们基本可以断定:
在12.1中,estimate_percent的默认采样比例,大致在65%。


1.2.2.5 统计信息锁定与force选项
为预防由于统计信息不规则变化影响执行计划,我们可以选择锁定某些对象的统计信息。
oracle提供了如下锁定统计信息的过程:
LOCK_PARTITION_STATS
LOCK_SCHEMA_STATS
LOCK_TABLE_STATS
对应的,也有如下解除锁定的过程:
UNLOCK_PARTITION_STATS
UNLOCK_SCHEMA_STATS
UNLOCK_TABLE_STATS

我们以前面测试estimate_percent中创建的测试表T为例,显示表统计信息的锁定与解锁问题。

SQL> exec dbms_stats.lock_table_stats(ownname => 'SYS',tabname => 'T');

PL/SQL procedure successfully completed

SQL> desc dba_tab_statistics;
Name                                               Type                         Nullable Default Comments                                                            
------------------------- ------------- -------- ------- --------------------------------------------------------------------
OWNER                                     VARCHAR2(128) Y                Owner of the object                                                 
TABLE_NAME                           VARCHAR2(128) Y                Name of the table                                                   
PARTITION_NAME                   VARCHAR2(128) Y                Name of the partition                                               
PARTITION_POSITION            NUMBER        Y                    Position of the partition within table                              
SUBPARTITION_NAME           VARCHAR2(128) Y                Name of the subpartition                                            
SUBPARTITION_POSITION     NUMBER        Y                    Position of the subpartition within partition                       
OBJECT_TYPE                        VARCHAR2(12)  Y                Type of the object (TABLE, PARTITION, SUBPARTITION)                 
NUM_ROWS                            NUMBER        Y                     The number of rows in the object                                    
BLOCKS                                   NUMBER        Y                     The number of used blocks in the object                             
EMPTY_BLOCKS                    NUMBER        Y                      The number of empty blocks in the object                            
AVG_SPACE                           NUMBER        Y                     The average available free space in the object                      
CHAIN_CNT                            NUMBER        Y                      The number of chained rows in the object                            
AVG_ROW_LEN                      NUMBER        Y                     The average row length, including row overhead                      
AVG_SPACE_FREELIST_BLOCKS    NUMBER        Y        The average freespace of all blocks on a freelist                   
NUM_FREELIST_BLOCKS       NUMBER        Y                   The number of blocks on the freelist                                
AVG_CACHED_BLOCKS         NUMBER        Y                    Average number of blocks in buffer cache                            
AVG_CACHE_HIT_RATIO       NUMBER        Y                    Average cache hit ratio for the object                              
SAMPLE_SIZE                         NUMBER        Y                    The sample size used in analyzing this table                        
LAST_ANALYZED                   DATE          Y                        The date of the most recent time this table was analyzed            
GLOBAL_STATS                     VARCHAR2(3)   Y                 Are the statistics calculated without merging underlying partitions?
USER_STATS                           VARCHAR2(3)   Y                Were the statistics entered directly by the user?                   
STATTYPE_LOCKED            VARCHAR2(5)   Y                  type of statistics lock                                             
STALE_STATS                        VARCHAR2(3)   Y                Whether statistics for the object is stale or not                   
SCOPE                                   VARCHAR2(7)   Y                  whether statistics for the object is shared or session              
 
SQL> col OWNER for a20
SQL> col TABLE_NAME for a20
SQL> col STATTYPE_LOCKED for a20
SQL> select OWNER,TABLE_NAME,STATTYPE_LOCKED from dba_tab_statistics where TABLE_NAME='T';
 
OWNER                TABLE_NAME           STATTYPE_LOCKED
-------------------- -------------------- --------------------
SYS                  T                    ALL
 
在T表的统计信息被锁定之后,是否可以重新搜集该表的统计信息呢?
SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T');
 
begin dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T'); end;
 
ORA-20005: object statistics are locked (stattype = ALL)
ORA-06512: 在 "SYS.DBMS_STATS", line 33859
ORA-06512: 在 line 2

显示该统计信息已经被锁定。
我们此处可以用force参数强制收集。

SQL> exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T',force => true);
 
PL/SQL procedure successfully completed

强制收集之后,该统计信息依然处于锁定状态:

SQL> select OWNER,TABLE_NAME,STATTYPE_LOCKED from dba_tab_statistics where TABLE_NAME='T';
 
OWNER                TABLE_NAME           STATTYPE_LOCKED
-------------------- -------------------- --------------------
SYS                  T                    ALL
 

下次再次收集,依然会报错:

SQL>  exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T');
 
begin dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T'); end;
 
ORA-20005: object statistics are locked (stattype = ALL)
ORA-06512: 在 "SYS.DBMS_STATS", line 33859
ORA-06512: 在 line 2

我们可以解锁该统计信息:
SQL> exec dbms_stats.unlock_table_stats(ownname => 'SYS',tabname => 'T');
 
PL/SQL procedure successfully completed
 
SQL> select OWNER,TABLE_NAME,STATTYPE_LOCKED from dba_tab_statistics where TABLE_NAME='T';
 
OWNER                TABLE_NAME           STATTYPE_LOCKED
-------------------- -------------------- --------------------
SYS                  T                   
 
这样即便不指定force参数,也可以重新收集统计信息了。
SQL>   exec dbms_stats.gather_table_stats(ownname => 'SYS',tabname => 'T');
 
PL/SQL procedure successfully completed


1.2.2.6 用户自定义统计信息表
当我们需要导出存储在系统字典表中的统计信息,
或者打算利用统计信息做一些测试而不影响存储在系统字典表中的统计信息时,
我们就可以创建用户自定义的统计信息表,从而来存储统计信息。


1.2.2.7 12c性能优化白皮书

作者:demonson 发表于2014-9-16 22:08:25 原文链接
阅读:109 评论:0 查看评论

你可能感兴趣的:(数据库,优化,性能)