优化统计信息是为了更详细的描述数据库及数据库对象而收集的数据,这些信息被用于为sql语句选择最优的执行计划。优化统计信息包括的项有:
Table statistics(表统计信息):Number of rows、Number of blocks、Average row length;
Column statistics(列统计信息):Number of distinct values (NDV) in column、Number of nulls in column、Data distribution (histogram);
Index statistics(索引统计信息):Number of leaf blocks、Levels、Clustering factor;
System statistics(系统统计信息):I/O performance and utilization、CPU performance and utilization。
其中表、列和索引统计信息都可以通过统计信息自动收集功能来收集,系统统计信息在oracle 10g中只能通过手动收集来完成。
Orcale 10g中,STATISTICS由GATHER_STATS_JOB作业收集得到,只有当数据库对象没有统计信息或者统计信息已经过期(Oracle 10G中是否过期的标准是数据库对象被修改的记录行数超过10%,该信息由Modification Monitoring来追踪完成)时才对该对象进行信息统计,该作业在数据库创建或升级时由Scheduler自动创建,这些作业可以从视图DBA_SCHEDULER_JOBS中查到。
如:SELECT d.owner,d.job_name,d.program_name,d.schedule_type,d.comments FROM DBA_SCHEDULER_JOBS d
结果:
默认情况下,Scheduler在维护窗口(maintenance window,默认启动时间为周内晚上10:00至次日早上6:00及整个周六周日)打开时运行GATHER_STATS_JOB作业,作业GATHER_STATS_JOB则是通过调用系统内部过程DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC来完成信息统计的,该过程可根据数据库对象统计信息需求的优先级(即数据库对象被修改的多少)按先后顺序来完成统计信息收集任务。GATHER_STATS_JOB作业是否随维护窗口的关闭而关闭则由属性stop_on_window_close决定,stop_on_window_close的默认值为TRUE,此时GATHER_STATS_JOB作业随维护窗口的关闭而关闭。统计信息的收集是资源相当密集的工作,因此您可能希望确保它不影响数据库的正常操作。
统计信息收集还可由过程DBMS_STATS.GATHER_DATABASE_STATS应用GATHER AUTO选项,来完成,与系统地内部过程DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC相比,DBMS_STATS.GATHER_DATABASE_STATS不区分数据库对象统计信息需求的优先级。
非默认情况时,Oracle10g可通过设置初始化参数 STATISTIC_LEVEL,来控制是否启用统计信息自动收集功能。STATISTIC_LEVEL参数的信息如(表-1):
参数类型 | String |
语法 | STATISTICS_LEVEL = {ALL | TYPICAL | BASIC} |
默认值 | TYPICAL |
参数类别 | 动态ALTER SESSION , ALTER SYSTEM |
(表-1)
该参数用于控制数据库统计信息收集的级别。当其为默认值TYPICAL时,系统将自动收集所有主要的有关自身管理的信息以使系统提供最优性能,该值适合于绝大多数情况;当取值ALL时,相对TYPICAL值系统增加timed OS statistics和plan execution statistics两项信息统计;当取值 BASIC时:有关系统特性和功能的许多信息统计功能都将被关闭(详细见附录1)。因此oracle强烈建意参数STATISTICS_LEVEL
的值尽量不要设成
BASIC。同时当修改参数以语法“alter system set statistics_level='typical';”完成时,修改后的STATISTICS_LEVEL的作用范围为整个系统,但当使用“ALTER SESSION
”时,
STATISTICS_LEVEL的作用范围仅为本SESSION
。
STATISTIC_LEVEL参数所控制的所有统计、报告功能的状态信息都可以从视图V$STATISTICS_LEVEL中得到,具体有关视图V$STATISTICS_LEVEL各字段的含义可参见网页http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14237/dynviews_2135.htm#I1030264。
举例如下:
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET statistics_level=all';
END;--设置本session statistics_level为‘all’
SELECT v.STATISTICS_NAME,v.SESSION_STATUS,v.SYSTEM_STATUS,v.ACTIVATION_LEVEL,v.SESSION_SETTABLE FROM V$STATISTICS_LEVEL v;
结果如下:
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET statistics_level=basic';
END;--设置本session statistics_level为‘basic’
SELECT v.STATISTICS_NAME,v.SESSION_STATUS,v.SYSTEM_STATUS,v.ACTIVATION_LEVEL,v.SESSION_SETTABLE FROM V$STATISTICS_LEVEL v;
结果如下:
在优化器收集统计信息时可能出现原来的优化方法在收集统计信息之前一直工作良好,但是在此之后,由于新收集的统计信息产生了不良计划,导致查询突然出错或效率降低。为避免这种情况,统计信息的收集作业在收集新信息之前保存当前的统计信息。如果出现问题,则可以返回到原有的统计信息,或者通过历史统计检查二者之间的不同之处,以解决问题。
例如,假设在 5 月 31 日晚上 10:00 开始运行表 emp 上的统计信息收集作业,而随后查询的性能变差。Oracle 保存了原有的统计信息,可以通过执行以下命令重新获取这些信息:
begin
dbms_stats.restore_table_stats (
'ARUP',
'REVENUE',
'10-DEC-08 10.00.00.000000000 PM -04:00');
end;
此命令将统计信息恢复到 12月 10 日晚上 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
---------------------------------------------------------------------
10-DEC-08 09.21.33.594053000 PM -04:00
该查询表明可用的最陈旧统计信息日期为 12 月 10 日上午9:21。 同时,也可以通过执行内建的函数将保留时间设为不同的值。例如,要将其设为 45 天,可使用:
execute DBMS_STATS.ALTER_STATS_HISTORY_RETENTION (45)
表、索引一击列的统计信息都存储在数据字典里,可以通过选取数据字典视图的某些字段来查看相应统计信息,此处具体涉及到的数据字典视图见附件2。具体各视图各字段的含义可见网页:http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14237/toc.htm。
此处就以列统计信息为列,说明查看列统计信息。
列统计信息可以按柱状统计图的形式存储,柱状统计图为列数据提供了准确的描述信息,尤其是在数据列有倾斜(列为某种值的记录行数非常多,而某种值的记录行数又非常少)的时候。Oracle中包含两种柱状统计图,高度正方图(height-balanced)和频率直方图(frequency histograms),该类型存储在视图*TAB_COL_STATISTICS (* 可为USER或 DBA),其取值为HEIGHT BALANCED, FREQUENCY或 NONE
高度直方图中,数据列的值被分成组,每组包含的数据数据可数基本相等。比如有一个列c其值在1到100之间,当均匀分布,其列的高度直方图如下图:
每个间隔中都包含数据列的10行数据;当不均匀分布时其列直方图如下图
这时,大多数数据行的值为5。查询时最有价值的统计信息就是各个组范围的两个端点的值.
查看统计信息的语法如下:
BEGIN
DBMS_STATS.GATHER_table_STATS (OWNNAME => 'scott', TABNAME => 'EMP',
METHOD_OPT => 'FOR COLUMNS SIZE 6 SAL');
END;
/
SELECT column_name, num_distinct, num_buckets, histogram
FROM USER_TAB_COL_STATISTICS
WHERE table_name = 'EMP' AND column_name = 'SAL';
结果:
SELECT endpoint_number, endpoint_value
FROM USER_HISTOGRAMS
WHERE table_name = 'EMP' and column_name = 'SAL'
ORDER BY endpoint_number;
结果:
上图中,每行对应高度直方图中的每个间隔。
在频率直方图中,列中每个唯一数据相当于高度直方图中的每个间隔,其高度对应该数据在列中出现的次数。当列中distinct值得个数小于或等于直方图的分格段的个数(即num_buckets的值)时,频率直方图会被自动建立。查看频率直方图的语法如下:
BEGIN
DBMS_STATS.GATHER_table_STATS (OWNNAME => 'scott', TABNAME => 'EMP',
METHOD_OPT => 'FOR COLUMNS SIZE 12 SAL');
END;
SELECT column_name, num_distinct, num_buckets, histogram
FROM USER_TAB_COL_STATISTICS
WHERE table_name = 'EMP' AND column_name = 'SAL';
结果:
SELECT endpoint_number, endpoint_value
FROM USER_HISTOGRAMS
WHERE table_name = 'EMP' and column_name = 'SAL'
ORDER BY endpoint_number;
结果:
注意1:上文曾提到过Modification Monitoring功能,其由statistics_level设为‘typical’或‘all’来启动,而统计信息自动收集功能是依据这些监控信息来判断是否对该表进行统计信息收集,如果Modification Monitoring功能关闭,则统计信息自动收集就无法确认表的统计信息是否已经过期,因此此时需要手工收集统计信息。
此外,USER_TAB_MODIFICATIONS表中记录了所有被监控表的数据被更改的信息。该信息的更新将会稍微滞后于真实的修改,可以通过DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO存储过程来立刻将更改的信息更新到USER_TAB_MODIFICATIONS表中。对于更新之后再rollback的记录,仍然算为已经受影响的记录,Oracle不会在rollback之后再去更新USER_TAB_MODIFICATIONS表,因此此点需引起注意。
举例如下(以系统自带的练习用户scott中的数据为例,直接在command window中运行):
SQL> select * from user_tab_modifications where table_name='EMP';
--no rows selected
SQL> select count(*) from emp;
COUNT(*)
----------
14
SQL> update emp set sal=sal+100;
14 rows updated.
SQL> select * from user_tab_modifications where table_name='EMP';
--no rows selected
SQL> exec DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO();
PL/SQL procedure successfully completed.
SQL> select inserts,updates,deletes from user_tab_modifications where table_name ='EMP';
INSERTS UPDATES DELETES
---------- ---------- ----------
0 14 0
SQL> rollback;
Rollback complete.
SQL> exec DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO();
PL/SQL procedure successfully completed.
SQL> select inserts,updates,deletes from user_tab_modifications where table_name ='EMP';
INSERTS UPDATES DELETES
---------- ---------- ----------
0 14 0
注意2:oracle强烈建意参数STATISTICS_LEVEL
的值尽量不要设成
BASIC,所以当需要将自动统计信息功能关闭时,最好采用以下方法:
方法一: SYSDBA登录
exec dbms_scheduler.disable('SYS.GATHER_STATS_JOB');
exec dbms_scheduler.enable('SYS.GATHER_STATS_JOB');
方法二:以SYSDBA身份登陆
alter system set "_optimizer_autostats_job"=false scope=spfile;
alter system set "_optimizer_autostats_job"=true scope=spfile;
Pfile可以直接修改初始化参数文件
然后重新启动数据库。
注意3:
不是所有的数据库对象都适合使用统计信息自动收集功能,如当在如下情况时,统计信息自动收集功能就无法达到需求:
(1) 某些表在工作时间内被删除(delete)或截断(truncate)并且被重新创建;
(2) 某些重负荷表在工作时间内被大量修改(insert、update),修改量超过10%。
对于这些修改频率较高的表,要保持其统计信息不过期,可采用如下两个方法:
对于(1)可采用下方法:
方法1:将这些表的统计信息设为NULL,这样Oracle会以查询优化的一部分来动态的收集这些无统计信息表的统计信息。Oracle动态收集统计信息功能由参数OPTIMIZER_DYNAMIC_SAMPLING控制,并且只有当该参数的值大于或等于2时(默认值为2),Oracle动态收集统计信息功能才能启动。
要将数据库对象统计信息设为NULL,只需删除原有的统计信息,然后给其统计信息功能加锁,语法如下:
BEGIN
DBMS_STATS.DELETE_TABLE_STATS('OE','ORDERS');--删除统计信息
DBMS_STATS.LOCK_TABLE_STATS('OE','ORDERS'); --不再收集统计信息
END;
类似的加锁、解锁还有LOCK_SCHEMA_STATS、LOCK_TABLE_STATS、UNLOCK_SCHEMA_STATS、UNLOCK_TABLE_STATS。
方法2:将数据库表的最能代表该表状况的典型统计信息固定,以作为该表优化统计信息。我们可以在任何时候去收集这些典型的信息并将其锁定,这样就可达到目的,这样的统计信息有可能比统计信息自动收集功能在晚上所收集到的统计信息更能表达数据表的状况。
对问题(2)可采用如下方法:
对于那些修改量较大的表,统计信息的收集最好是能紧跟在修改操作之后,而作为sql程序或者数据库作业的一部分来手动完成;
注意4:
在下述情况时需要手工来完成统计信息的收集。
(1)对于外部表,其统计信息不会在作业GATHER_SCHEMA_STATS, GATHER_DATABASE_STATS和统计信息自动收集作业中被收集,因为数据操作在外部表上是被禁止的,因此在对应数据改变是须手动收集外部表的统计信息。
(2)当统计信息自动收集功能停用时。
(3)另外还有的就是系统统计信息(system statistics)了。
(4)固定对象,如动态性能表(dynamic performance table)需要被收集当数据库有明显操作时,用GATHER_FIXED_OBJECTS_STATS过程。
(1)Oracle 10g中,可能存在某些情况,你需要用自己的脚本来收集某些特殊对象的统计信息。但是由于你采用了自动收集统计信息,oracle就会对所有对象使用相同的选项来收集统计信息,这样你就失去了对某个对象的控制权。当你发现缺省的统计信息收集方式对某个对象不是很合适时,你必须锁定该对象的统计信息,并使用一个特殊的选项值对该对象来收集统计信息。
比如,某个表的列的数据倾斜的非常严重,这时如果采用标准的采样率:ESTIMATE_PERCCENT=AUTO_SAMPLE_SIZE可能就不适合了。这时你就需要单独指定该对象的采样率。我们知道,在11g之前的收集统计信息方面,oracle提供的类似的其他选项还包括:CASCADE、DEGREE、METHOD_OPT、NO_INVALIDATE、GRANULARITY。到了11g里,则提供了更大的灵活性,从而使得你可以很简单的处理上面所说的这种情况。在11g里,上面说的这些选项可以在不同的级别上分别设置,级别由高到低分别为:global级别、数据库级别、schema级别、表级别。其中,低级别的选项覆盖高级别的选项。
如,对于上面所举的例子来说,如果要对你的一个特殊的、列上的值倾斜的很严重的表收集统计信息时,你只需要简单的调用如下的存储过程来设置该表级别上的的ESTIMATE_PERCCENT=100即可,如下所示:
SQL> exec dbms_stats.set_table_prefs('Schema_name','Table_name','ESTIMATE_PERCCENT','100');
这样设置以后,当数据库在自动收集统计信息时,对于其他没有单独设置采样率的表来说,采样率会采用AUTO_SAMPLE_SIZE,而对于你单独设置的Table_name表,则会使用100的采样率来收集统计信息。类似的,如果需要设置global级别上的选项,则调用dbms_stats.set_global_prefs;如果要设置数据库级别上的选项,则调用dbms_stats.set_database_prefs;如果要设置schema级别上的选项,则调用dbms_stats.set_schema_prefs即可。
(2)11g中,除了上面提到的这些选项以外,还添加了另外三种新的选项:PUBLISH、INCREMENTAL、STALE_PERCENT。其中:
1) PUBLISH:收集完统计信息以后是否立即将统计信息发布到数据字典里,还是将它们存放在私有区域里。TRUE表示立即发布,FALSE表示存放到私有区域里。
2) STALE_PERCENT:确定某个对象的统计信息过时的上限,如果过时就需要重新收集统计信息,缺省为10。计算某个表的统计信息是否过时,oracle会计算自从上一次收集该表的统计信息以来,该表中被修改的数据行数占该表的总行数的百分比。然后用得出的百分比值与该选项配置的值(如果缺省,就是10)进行比较,大于10,则说明该表的统计信息过时了,需要重新收集统计信息;否则就认为该表的统计信息不过时,不用再次收集。
3) INCREMENTAL:在分区表上收集global的统计信息时(将GRANULARITY设置为GLOBAL),采用增量方式完成。使用该选项是因为对于某些分区表来说,比如按照月份进行范围分区的分区表来说,除了代表当前月的分区里的数据会经常变化以外,其他分区里的数据不会变动。因此在收集该分区表上的global的统计信息时,就没有必要再次扫描那些非当前月的分区了。如果你将INCREMENTAL设置为TRUE时,则在收集统计信息时,就不会扫描那些非当前月的分区里的数据,而只会扫描当前月的分区里的数据。最后将非当前月的分区上已经存在的统计信息加上当前月新算出来的统计信息合并就得出了分区表的global的统计信息。可以从视图:DBA_TAB_STAT_PREFS里看到所有的收集统计信息时的各个选项的值。
(3)在Oracle10g版本(包括最新的10.2.0.4)中没有已知的修改10%这个阀值的方法。但是在Oracle11g中则提供了SET_TABLE_PREFS等函数。
以下命令将指定表的STALE默认值从10%改为5%,该值可以从新的dba_tab_stat_prefs数据字典中查询获得。
--仅限于Oracle11g版本
BEGIN
DBMS_STATS.SET_TABLE_PREFS ( ownname =>'scott', tabname =>'EMP', pname =>'SAL', pvalue =>'5');
END;
/
SQL> select * from dba_tab_stat_prefs;
OWNER TABLE_NAME PREFERENCE_NAME PREFE
---------- ---------- -------------------- -----
scott EMP SAL 5
文章对oracle 10g的统计信息自动收集功能做了详细的解读,并附带了部分的实际实践。但是由于本地数据库的数据量非常有限,关于统计信息自动收集功能如何来提高数据库系统的运行效率方面还缺乏实验,在后面的学习和开发中将会注意到此点,可能会以实际的应用未基础来说明统计信息自动收集功能对系统效率的影响。
1 | Automatic Workload Repository (AWR) Snapshots |
2 | Automatic Database Diagnostic Monitor (ADDM) |
3 | All server-generated alerts |
4 | Automatic SGA Memory Management |
5 | Automatic optimizer statistics collection |
6 | Object level statistics |
7 | End to End Application Tracing (V$CLIENT_STATS) |
8 | Database time distribution statistics (V$SESS_TIME_MODEL and V$SYS_TIME_MODEL) |
9 | Service level statistics |
10 | Buffer cache advisory |
11 | MTTR advisory |
12 | Shared pool sizing advisory |
13 | Segment level statistics |
14 | PGA Target advisory |
15 | Timed statistics |
16 | Monitoring of statistics |