本章提要
----------------------------------------------------工具包 dbms_stats系统统计对象统计通用服务----------------------------------------------------实际上, 仅知道要处理的SQL语句和它引用的对象结构, 查询优化器还是无法提供高效的执行计划, 优化器还必须要量化待处理的数据量.4.1 工具包 dbms_stats 简介 过去, 对象统计是通过SQL语句ANALYZE来收集, 现在不这样了, 现在推荐使用 dbms_stats. 4.2 系统统计(感觉默认就可以了)4.3 对象统计信息(比较重要) 有三种类型的对象统计信息, 表统计, 列统计, 索引统计. 测试, 使用对象统计信息:CREATE TABLE tASSELECT rownum AS id,round(dbms_random.normal*1000) AS val1,100+round(ln(rownum/3.25+2)) AS val2,100+round(ln(rownum/3.25+2)) AS val3,dbms_random.string('p',250) AS padFROM all_objectsWHERE rownum <= 1000ORDER BY dbms_random.value;UPDATE t SET val1 = NULL WHERE val1 < 0;ALTER TABLE t ADD CONSTRAINT t_pk PRIMARY KEY (id);CREATE INDEX t_val1_i ON t (val1);CREATE INDEX t_val2_i ON t (val2);BEGINdbms_stats.gather_table_stats(ownname => user,tabname => 'T',estimate_percent => 100,method_opt => 'for all columns size skewonly',cascade => TRUE);END;/-- ============ 表统计信息 ============= SELECT num_rows, blocks, empty_blocks, avg_space, chain_cnt, avg_row_len FROM user_tab_statistics WHERE table_name = 'T';-- result/*NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN---------- ---------- ------------ ---------- ---------- -----------1000 44 0 0 0 265 num_rows: 表中数据的行数blocks: 高水位下面的数据块个数empty_blocks: 高水位上面的数据块个数, dbms_stats不计算这个值, 设置为0avg_space: 表里数据块的平均空闲空间(字节), dbms_stats不计算这个值, 设置为0chain_cnt: 涉及行链接和行迁移的总行数, dbms_stats不计算这个值, 被设置为0avg_row_len: 表中平均每个记录的长度(字节)*/-- ============ 列统计信息 ============= SELECT column_name AS "NAME", num_distinct AS "#DST", low_value, high_value, density AS "DENS", num_nulls AS "#NULL", avg_col_len AS "AVGLEN", histogram, num_buckets AS "#BKT" FROM user_tab_col_statistics WHERE table_name = 'T';-- result/*NAME #DST LOW_VALUE HIGH_VALUE DENS #NULL AVGLEN HISTOGRAM #BKT---- ----- -------------- -------------- ------- ----- ------ --------------- -----ID 1000 C102 C20B .00100 0 4 NONE 1VAL1 431 C103 C2213E .00254 503 3 HEIGHT BALANCED 254VAL2 6 C20202 C20207 .00050 0 4 FREQUENCY 6VAL3 6 C20202 C20207 .00050 0 4 FREQUENCY 6PAD 1000 202623436F2943 7E79514A202D49 .00100 0 251 HEIGHT BALANCED 2547334237B426574 4649366C744E25336E4A5B302E4F 3F36264C6927554B53236932303A 7A57737C6D4B2221215F46 59414C44num_distinct: 该列中唯一值的数量low_value: 该列中最小值, 这里无法读懂, 需要借助别的函数high_value: 该列中最大值, 这里无法读懂, 需要借助别的函数density: 0-1之间的小树, 接近0表示对于列的过滤操作能去掉大多数行num_nulls: 该列中null的总数avg_col_len: 平均列大小, 以字节表示histogram: 表明是否有直方图统计信息num_buckets: 直方图里桶(bucket)数.-- 直方图关于数据不均匀分布的额外信息叫做直方图, */SELECT endpoint_value, endpoint_number, endpoint_number - lag(endpoint_number,1,0) OVER (ORDER BY endpoint_number) AS frequency FROM user_tab_histograms WHERE table_name = 'T' AND column_name = 'VAL2' ORDER BY endpoint_number;-- result/*ENDPOINT_VALUE ENDPOINT_NUMBER FREQUENCY-------------- --------------- ----------101 8 8102 33 25103 101 68104 286 185105 788 502106 1000 212 */-- =========== 索引统计信息 ===================SELECT index_name AS name, blevel, leaf_blocks AS leaf_blks, distinct_keys AS dst_keys, num_rows, clustering_factor AS clust_fact, avg_leaf_blocks_per_key AS leaf_per_key, avg_data_blocks_per_key AS data_per_key FROM user_ind_statistics WHERE table_name = 'T';-- result/*NAME BLEVEL LEAF_BLKS DST_KEYS NUM_ROWS CLUST_FACT LEAF_PER_KEY DATA_PER_KEY---------- ------ --------- -------- -------- ---------- ------------ ------------T_VAL2_I 1 2 6 1000 153 1 25T_VAL1_I 1 2 431 497 479 1 1T_PK 1 2 1000 1000 980 1 1blevel, 分支数量leaf_blocks, 叶子块数distinct_keys, 键值总数num_rows, 索引中的键值数, 对于主键来说, 等同于distinct_keysclustering_factor: 聚簇因子, 大师的索引一章有介绍这个因子.avg_leaf_blocks_per_key, 存放一个键值的平均叶子块数avg_data_blocks_per_key, 单个键引用的平均数据块数 */
干货
统计信息对优化十分重要, 执行获得准确的统计信息:
1. 系统默认: 11G 以后, 用DBCA创建数据库时, 会默认收集统计信息, 系统会自动做成一个JOB来完成这个工作, 这个工作设定的时间是在晚上22:00, 如果你想修改这个时间, 或者停止自动收集, 请参考如下:
个人强烈建议开启: 自动收集统计信息(默认选项)
- 开启或关闭自动收集的job
开启(默认):
begin dbms_auto_task_admin.enable( client_name => 'auto optimizer stats collection', operation => NULL, window_name => NULL);end;/
关闭:
begin dbms_auto_task_admin.disable( client_name => 'auto optimizer stats collection', operation => NULL, window_name => NULL);end;/
查询是否开启了自动收集统计信息:
select client_name,status from dba_autotask_client;
查看具体的自动 job:
select window_name,duration,next_start_date from dba_scheduler_windows;
查询结果有 3 列, 分别是 name, 持续时间, 下次Job 时间;
由于默认的时间是 22:00, 但是这个时候可能是业务的高峰期, 所以, 我们可以通过以下内容, 修改为凌晨 2 点, 持续 4 个小时
begin sys.dbms_scheduler.set_attribute( name => 'SYS.MONDAY_WINDOW', attribute => 'repeat_interval', value => 'freq=daily;byday=MON;byhour=2;byminute=0; bysecond=0' ); sys.dbms_scheduler.set_attribute( name => 'SYS.MONDAY_WINDOW', attribute => 'duration', value => '0 04:00:00');end;/begin sys.dbms_scheduler.set_attribute( name => 'SYS.TUESDAY_WINDOW', attribute => 'repeat_interval', value => 'freq=daily;byday=MON;byhour=2;byminute=0; bysecond=0' ); sys.dbms_scheduler.set_attribute( name => 'SYS.TUESDAY_WINDOW', attribute => 'duration', value => '0 04:00:00');end;/begin sys.dbms_scheduler.set_attribute( name => 'SYS.WEDNESDAY_WINDOW', attribute => 'repeat_interval', value => 'freq=daily;byday=MON;byhour=2;byminute=0; bysecond=0' ); sys.dbms_scheduler.set_attribute( name => 'SYS.WEDNESDAY_WINDOW', attribute => 'duration', value => '0 04:00:00');end;/begin sys.dbms_scheduler.set_attribute( name => 'SYS.THURSDAY_WINDOW', attribute => 'repeat_interval', value => 'freq=daily;byday=MON;byhour=2;byminute=0; bysecond=0' ); sys.dbms_scheduler.set_attribute( name => 'SYS.THURSDAY_WINDOW', attribute => 'duration', value => '0 04:00:00');end;/begin sys.dbms_scheduler.set_attribute( name => 'SYS.FRIDAY_WINDOW', attribute => 'repeat_interval', value => 'freq=daily;byday=MON;byhour=2;byminute=0; bysecond=0' ); sys.dbms_scheduler.set_attribute( name => 'SYS.FRIDAY_WINDOW', attribute => 'duration', value => '0 04:00:00');end;/begin sys.dbms_scheduler.set_attribute( name => 'SYS.SATURDAY_WINDOW', attribute => 'repeat_interval', value => 'freq=daily;byday=MON;byhour=2;byminute=0; bysecond=0' ); sys.dbms_scheduler.set_attribute( name => 'SYS.SATURDAY_WINDOW', attribute => 'duration', value => '0 04:00:00');end;/begin sys.dbms_scheduler.set_attribute( name => 'SYS.SUNDAY_WINDOW', attribute => 'repeat_interval', value => 'freq=daily;byday=MON;byhour=2;byminute=0; bysecond=0' ); sys.dbms_scheduler.set_attribute( name => 'SYS.SUNDAY_WINDOW', attribute => 'duration', value => '0 04:00:00');end;/
2. 手动收集统计信息
参考上边内容