Oracle:dbms_stats统计信息在9i和10g上的区别

统计信息参数设置、是否关闭自动收集、回退统计信息、统计信息迁移

==================================================================================================

大约2个月前,一位业内人士问我为什么9i CBO迁移到10g上会出现许多执行计划改变导致的性能,他当然是为了能考考我;实际上我接触过的环境大多在8i/9i下没有使用CBO优化模式,从8i/9i的RBO模式跨越到10g上较为成熟的CBO优化模式,这当中出现执行计划讹误可以说是情理之中的;而9i CBO到10上的CBO问题也不少,我首先想到的是统计信息收集上存在区别,但具体是什么区别却又说不上。那位业内人士听了我的回答,笑,笑而不语。

Oracle十分博大,博大到可以称为Oracle的世界,很多东西长期不用就会遭人淡忘;我们来复习下9i和10g上统计信息收集的一些改动。

 

在9i中收集统计信息时其默认的MOTHOD_OPT模式为’FOR ALL COLUMNS SIZE 1′,使用这种模式时Oracle只收集所有列上最基础的统计信息,包括了最小/大值,distinct值等信息;但是不会收集列上的直方图。对那些数据均匀分布和没有出现在SQL语句中where子句中作为条件的列来说,这样的统计信息完全足够了。然而如果列上的数据分布并不均匀就可能导致CBO的执行计划成本计算不准确,这时我们需要手动对这些列上的直方图进行统计。

10g上对dbms_stats包中默认的METHOD_OPT模式做了修正,这显然是引起9i CBO迁移到10g CBO后易发地执行计划变化的一个重要因素,也是那位业内人士所要问的题眼。

 

新的默认METHOD_OPT值为”FOR ALL COLUMNS SIZE AUTO”,这意味着Oracle将通过内部算法自动决定那些列上需要收集统计信息,而那些列上不需要。是否收集直方图取决于列上数据的分布情况和与对应表相关的工作负载,这种工作负载可以解释为数据库中存在某些需要参考这些列的详细信息来计算执行成本的SQL语句。

这种方式听上去十分理想,似乎Oracle可以默默无闻地为我们抓取所有急需的统计信息。

然而问题是在许多环境中Oracle没有做出是否需要收集列上直方图的正确决定。实践证明Oracle有可能收集许许多多不必要的直方图,同时又放弃了许多需要收集的直方图。

 

在轻量级的应用环境中这种直方图收集不当的问题造成的影响大多数时间不为人们所察觉,相反在performance critical或已经形成性能瓶颈的环境中则可能是一场不大不小的麻烦。

 

此外Oracle还改变了列上密度(density)信息的计算方式。该值常被Oracle用来确定谓词选择性,当突然出现额外不必要的直方图时可能造成的广泛显著地性能影响(当然好的影响也可能出现,只是概率上……)。

显然这些莫名出现的不速之客也会给共享池造成影响,library cache与row cache相关的闩可能短期内车水马龙,如果您的应用数据表上有成百上千的列那么情况可能更糟(所以说开发要遵循范式,没有规矩的最后结果往往是应用不可用,项目失败。别告诉我你的应用苟且地活着,那同样意味着项目失败)!

 

======================================================================================================

 

利用dbms_stats来收集统计信息的时候,其procedure有很多参数是有默认值的。9i的默认值是直接写死在procedure的定义中,而10g的默认值则是一组可以由用户设置的参数值,为此,10g的dbms_stats引入了两个新的procedure:get_param和set_param。

 

9i:

procedure gather_table_stats
    (ownname varchar2,
     tabname varchar2,
     partname varchar2 default null,
     estimate_percent number default null,
     block_sample boolean default FALSE,
     method_opt varchar2 default 'FOR ALL COLUMNS SIZE 1',
     degree number default null,
     granularity varchar2 default 'DEFAULT',
     cascade boolean default FALSE,
     stattab varchar2 default null,
     statid varchar2 default null,
     statown varchar2 default null,
     no_invalidate boolean default FALSE);

10g:

procedure gather_table_stats
    (ownname varchar2,
     tabname varchar2,
     partname varchar2 default null,
     estimate_percent number default to_estimate_percent_type(get_param('ESTIMATE_PERCENT')),
     block_sample boolean default FALSE,
     method_opt varchar2 default get_param('METHOD_OPT'),
     degree number default to_degree_type(get_param('DEGREE')),
     granularity varchar2 default get_param('GRANULARITY'),
     cascade boolean default to_cascade_type(get_param('CASCADE')),
     stattab varchar2 default null, statid varchar2 default null,
     statown varchar2 default null,
     no_invalidate boolean default to_no_invalidate_type(get_param('NO_INVALIDATE')),
     stattype varchar2 default 'DATA',
     force boolean default FALSE);

The DBMS_STATS.SET_PARAM can be used to set the following parameters:

CASCADE Controls whether indexes are analyzed at the same time Default: TRUE Possible Values:

* TRUE * FALSE

Note: The default value for CASCADE set by SET_PARAM is not used by export/import procedures. It is used only by gather procedures.

Example: exec DBMS_STATS.SET_PARAM(‘CASCADE’,'FALSE’);

 

DEGREE Degree of parallelism. Default: NULL Possible Values:

* NULL – Use the table default value specified by the DEGREE clause in the CREATE TABLE or ALTER TABLE statement. * integer – the integer will be used as degree for all objects

Example: exec DBMS_STATS.SET_PARAM(‘DEGREE’,’5′);

 

ESTIMATE_PERCENT Percentage of rows to estimate Default: DBMS_STATS.AUTO_SAMPLE_SIZE Possible Values:

* Valid range is [0.000001,100] * NULL – compute will be used (100%) * DBMS_STATS.AUTO_SAMPLE_SIZE – sample sizes may vary for different versions, for example, this tends to default to a smaller sample size in 10g than in 11g.

Example: exec DBMS_STATS.SET_PARAM(‘ESTIMATE_PERCENT’,'NULL’); Note: When NULL is unquoted, this sets the parameter to the value Oracle recommends. In the case of the quoted ‘NULL’, this sets the value of the parameter itself to NULL so that the above example indicates that estimate_percent=null (i.e compute) as opposed to NULL without quotes that would imply using the default for this parameter for the specific Oracle version

 

METHOD_OPT Used to gather column statistics Default: FOR ALL COLUMNS SIZE AUTO. Possible Values:

* FOR ALL [INDEXED | HIDDEN] COLUMNS [size_clause] * FOR COLUMNS [size clause] column|attribute [size_clause] [,column|attribute [size_clause]…] size_clause is defined as size_clause := SIZE {integer | REPEAT | AUTO | SKEWONLY} integer : Number of histogram buckets. Must be in the range [1,254]. o REPEAT : Collects histograms only on the columns that already have histograms. o AUTO : Oracle determines the columns to collect histograms based on data distribution and the workload of the columns. o SKEWONLY : Oracle determines the columns to collect histograms based on the data distribution of the columns.

Example: exec DBMS_STATS.SET_PARAM(‘METHOD_OPT’, ‘FOR ALL COLUMNS SIZE 1′);

 

NO_INVALIDATE Determines whether to invalidate dependent cursors or not Default: DBMS_STATS.AUTO_INVALIDATE Possible Values:

* DBMS_STATS.AUTO_INVALIDATE – Oracle decide when to invalidate dependent cursors. * TRUE – Does not invalidate the dependent cursors * FALSE – Invalidates dependent cursors

Example: exec DBMS_STATS.SET_PARAM(‘NO_INVALIDATE’,'FALSE’);

 

GRANULARITY Determines granularity of statistics to collect (only pertinent if the table is partitioned). Default: ‘AUTO’ Possible Values:

* ‘AUTO’ – determines the granularity based on the partitioning type * ‘ALL’ – gathers all (subpartition, partition, and global) statistics * ‘GLOBAL’ – gathers global statistics * ‘GLOBAL AND PARTITION’ – gathers the global and partition level statistics. No subpartition level statistics are gathered even if it is a composite partitioned object. * ‘PARTITION ‘- gathers partition-level statistics * ‘SUBPARTITION’ – gathers subpartition-level statistics.

Note: ‘DEFAULT’ is obsolete. This option gathers global and partition-level statistics It is currently supported, but included in the documentation for legacy reasons only. Use the ‘GLOBAL AND PARTITION’ for this functionality.

Example: exec DBMS_STATS.SET_PARAM(‘GRANULARITY’,'GLOBAL AND PARTITION’);

 

AUTOSTATS_TARGET This parameter is applicable only for auto statistics collection. The value of this parameter controls the objects considered for statistics collection Default: ‘AUTO’ Possible Values:

* ‘AUTO’ – Oracle decides for which objects to collect statistics * ‘ALL’ – Statistics are collected for all objects in the system * ‘ORACLE’ – Statistics are collected for all Oracle owned objects. This option restricts the list of schemas for which the automatic stats gathering job will gather statistics to a list of Oracle component system E.g. SYS, SYSMAN, WMSYS and EXFSYS in a sample database

 

Usage Notes

* To run this procedure, the user must have the SYSDBA or both the ANALYZE ANY DICTIONARY and ANALYZE ANY system privileges. * Note that both arguments are of type VARCHAR2 and the values need to be enclosed in quotes even when they represent numbers. * Note also the difference between NULL and ‘NULL’: o When NULL is unquoted, this sets the parameter to the value Oracle recommends. o In the case of the quoted ‘NULL’, this sets the value of the parameter to NULL.

How to Check Present Values for a Parameter

In order to check the present value for a certain parameter do:

 

========================================================================================================================

 

exec dbms_stats.set_param(‘METHOD_OPT’, ‘FOR ALL COLUMNS SIZE 1′)

select 'cascade:' as param,dbms_stats.get_param('cascade') as value from dual
    union all
    select 'degree:',dbms_stats.get_param('degree') from dual
    union all
    select 'estimate_percent:',dbms_stats.get_param('estimate_percent') from dual
    union all
    select 'method_opt:',dbms_stats.get_param('method_opt') from dual
    union all
    select 'no_invalidate:',dbms_stats.get_param('no_invalidate') from dual
   union all
   select 'granularity:',dbms_stats.get_param('granularity') from dual;

===========================================================================================================================

1.开启或关闭自动收集统计信息:

从Oracle Database 10g开始,通过设置初始化参数 STATISTIC_LEVEL 为 TYPICAL 或 ALL,就可以自动收集统计信息。(默认值为 TYPICAL,因此可以随即启用自动收集统计信息的功能。)

Oracle在建库后就默认创建了一个名为GATHER_STATS_JOB的定时任务,用于自动收集CBO的统计信息。

这个自动任务默认情况下在工作日晚上10:00-6:00和周末全天开启。调用DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC收集统计信息。该过程首先检测统计信息缺失和陈旧的对象。然后确定优先级,再开始进行统计信息。

可以通过以下查询这个JOB的运行情况:

select * from Dba_Scheduler_Jobs where JOB_NAME ='GATHER_STATS_JOB'

 

其实同在10点运行的Job还有一个AUTO_SPACE_ADVISOR_JOB:

SQL> select JOB_NAME,LAST_START_DATE from dba_scheduler_jobs;

 

JOB_NAME                      LAST_START_DATE
------------------------------ ----------------------------------------
AUTO_SPACE_ADVISOR_JOB        04-DEC-07 10.00.00.692269 PM +08:00
GATHER_STATS_JOB              04-DEC-07 10.00.00.701152 PM +08:00
FGR$AUTOPURGE_JOB
PURGE_LOG                      05-DEC-07 03.00.00.169059 AM PRC

 

然而这个自动化功能已经影响了很多系统的正常运行,晚上10点对于大部分生产系统也并非空闲时段。
而自动分析可能导致极为严重的闩锁竞争,进而可能导致数据库Hang或者Crash。

所以建议最好关闭这个自动统计信息收集功能:

exec DBMS_SCHEDULER.DISABLE('GATHER_STATS_JOB');

 

自动化永远而严重的隐患相伴随!


以上是转载盖国强的看法----http://www.eygle.com/archives/2007/12/dbms_scherduler_disable.html
我的DB一直没有关闭这个功能,而且使用的很好,暂时不打算关闭,如果那天确实影响了使用,再决定是否关闭。
关闭及开启自动搜集功能,有两种方法,分别如下:
方法一: 
exec dbms_scheduler.disable('SYS.GATHER_STATS_JOB');
exec dbms_scheduler.enable('SYS.GATHER_STATS_JOB');
方法二:
alter system set "_optimizer_autostats_job"=false scope=spfile;
alter system set "_optimizer_autostats_job"=true scope=spfile;

Pfile可以直接修改初始化参数文件,重新启动数据库。

 

那么您为什么要这样做呢?有很多原因 — 其中一个原因是,虽然表中大部分行发生了变化,但分布情况可能没有改变,这在数据仓库中很常见。在这种情况下,您不希望再次收集统计信息,而只是希望重用原来的统计信息。另一个原因可能是您正在使用分区交换功能来刷新物化视图 (MV),并且不希望收集关于物化视图的统计信息,因为关于被交换表的统计信息也会被导入。但是,您也可以将特定的表排除在自动统计信息收集作业之外,而不需要禁止整个作业。

2.回退统计信息:

在优化器收集统计信息时可能出现的复杂情况之一是执行计划的改变 — 也就是说,原来的优化方法在收集统计信息之前一直工作良好,但是在此之后,由于新收集的统计信息产生了不良计划,导致查询突然出错。这种问题并不少见。

为避免这种灾难,统计信息的收集作业在收集新信息之前保存当前的统计信息。如果出现问题,您总可以返回到原有的统计信息,或者至少可以检查二者之间的不同之处,以便于解决问题。

例如,假设在 5 月 31 日晚上 10:00 开始运行表 REVENUE 上的统计信息收集作业,而随后查询的性能变差。Oracle 保存了原有的统计信息,您可以通过执行以下命令重新获取这些信息:

SQL> exec dbms_stats.restore_table_stats ( 'ARUP', 'REVENUE', '31-MAY-04 10.00.00.000000000 PM -04:00');

此命令恢复到 5 月 31 日晚上 10:00 为止的统计信息,时间信息是以 TIMESTAMP 数据类型提供。这样您就立即还原了由新的统计信息收集程序所作的更改。

您能够恢复的时间长度是由保留参数所决定的。要查看当前的保留参数,可使用以下查询:

SQL> select DBMS_STATS.GET_STATS_HISTORY_RETENTION from dual;

GET_STATS_HISTORY_RETENTION
---------------------------
                         31

在本示例中表示可以保存相当于 31 天的统计信息,但并不能予以保证。要了解统计信息所覆盖到的确切时间和日期,只需使用以下查询:

SQL> select DBMS_STATS.GET_STATS_HISTORY_AVAILABILITY from dual;

GET_STATS_HISTORY_AVAILABILITY
----------------------------------------------------------------
27-10月-08 11.14.20.357622000 下午 +08:00

该查询表明可用的最陈旧统计信息日期为 10 月 27 日下午 11:14。

您可以通过执行内建的函数将保留时间设为不同的值。例如,要将其设为 45 天,可使用:

SQL> exec DBMS_STATS.ALTER_STATS_HISTORY_RETENTION (45);

另外为什么有部分表没有被分析呢, 原因跟表DBA_TAB_MODIFICATIONS有关

 

3.导入导出统计信息: <script type="text/javascript"></script>

你可能感兴趣的:(oracle,sql,算法,cache,performance)