一、优化统计 (Optimizer Statistics )
优化统计收集了数据库及其对象的详细信息资料,查询优化器使用这些信息,为 SQL 命令选择最优的执行计划。
统计数据包括:
*数据表统计:数据行数、数据区块数、平均数据行长度
*列统计:列中的不同值数量、列中的 NULL 值数量、数据分布 (直方图) 、
扩展统计
*索引统计:叶块(leaf blocks)数量、分级数(Levels)、集群因子(Clustering
factor)
*系统统计:I/O 性能和利用率、CPU 性能和利用率
当参数 STATISTICS_LEVEL = TYPICAL (默认值) 或 ALL 时,Oracle 数据 库在自动任务 (AutoTask) 中默认启用优化统计采集,自动任务在计划调度的维 护窗口 (maintenance windows) 时段自动执行。 自动采集任务可用以下指令控
制:
启用 autotask 的自动优化采集,其中'auto optimizer stats collection' 是 视图 dba_autotask_client 中的预置名称
select client_name,status from dba_autotask_client ;
begin
dbms_auto_task_admin.enable(
client_name => 'auto optimizer stats collection',
operation => null,
window_name => null
) ;
end ;
/
-- 禁用 autotask 的自动优化采集
begin
dbms_auto_task_admin.disable(
client_name => 'auto optimizer stats collection',
operation => null,
window_name => null
) ;
end ;
/
二、手工采集统计
自动优化统计默认是在每天的维护窗口时段采集统计数据,如果在另外的时 段,表数据发生显著变化时,其统计信息将失效,这时将需要手工收集统计信息。 例如:
*不稳定的数据表:在一天内会被删除、或截断和重建
*发生大批量装载数据 (超过 10% 以上) 的对象
手 工 采 集 统 计 数 据 需 要 使 用 DBMS_STATS 程 序 包 中的 子 程 序 , 通 过 dbms_stats 包,可以查看和修改为数据库对象收集的优化器统计信息。Oracle RDBMS 允许收集多种不同类型的统计信息,以帮助提高性能。DBMS_STATS 这个包 只涉及优化器统计信息。Oracle 默认情况下会将此类自动统计信息收集设置为 打开状态,因此此包仅用于专门的手工收集的情况。可以使用 dbms_stats 并行 收集统计信息。
Gathering Optimizer Statistics
gather_database_stats
收集数据库中所有对象的统计信息:
estimate_percent
要估计的行百分比 (空表示计算) :有效范围为[0.000001,100]。
method_opt
FOR ALL [INDEXED | HIDDEN] COLUMNS [size_clause]
FOR COLUMNS [size clause] column [size_clause] [,column [size_clause]...]
size_clause is defined as size_clause := SIZE {integer | REPEAT | AUTO
| SKEWONLY}
- integer : 直方图存储桶数,范围为[1,2048]
- REPEAT : 只收集已经有直方图的列上的直方图。
- AUTO **:**根据数据分布和列的工作负载确定要在其上收集直方图的列。
- SKEWONLY : 根据列的数据分布确定要在其上收集直方图。
Degree
并行度,The default for degree is NULL。
Cascade
收集索引的统计数据。除了收集表和列统计信息外,使用此选项相当于对数据库 中的每个索引运行 GATHER_INDEX_STATS 过程。
no_invalidate
如果设置为 true,则不会使游标无效。如果设置为 false,该过程将立即使游标 失效。
示例:
execute dbms_stats.gather_database_stats(estimate_percent=>null) ; execute dbms_stats.gather_database_stats() ;
exec dbms_stats.gather_database_stats (degree=>4, cascade=>true) ; exec dbms_stats.gather_database_stats (no_invalidate=>true) ;
exec dbms_stats.gather_database_stats (method_opt => 'for all indexed') ; exec dbms_stats.gather_database_stats (method_opt=>'for all columns size auto',cascade=>true) ;
exec dbms_stats.gather_database_stats (method_opt =>'for all columns size 254') ;
exec dbms_stats.gather_database_stats (method_opt =>'for all columns size skewonly') ;
将 integer 即 bucket 的数据设置为 1,可以不使用直方图,如下所示:
exec dbms_stats.gather_database_stats (method_opt =>'for all columns size 1') ;
gather_dictionary_stats
收集 dictionary schemas 'SYS', 'SYSTEM'和 RDBMS 组件架构的统计信息。
示例:
execut dbms_stats.gather_dictionary_stats() ;
execut dbms_stats.gather_dictionary_stats(degree=>4, cascade=>TRUE) ;
gather_fixed_objects_stats
收集所有固定对象 (动态性能表) 的统计信息。
示例:
execut dbms_stats.gather_fixed_objects_stats() ;
execut dbms_stats.gather_fixed_objects_stats(no_invalidate=>true) ;
gather_index_stats
收集索引统计信息。
示例:
查询 scott 模式下的索引
select index_name,table_name from dba_indexes where owner='SCOTT' ;
为表 dept 的主键索引 PK_DEPT 进行统计数据
execute dbms_stats.gather_index_stats('SCOTT','PK_DEPT') ;
验证主键索引是否成功统计
select index_name,last_analyzed from dba_indexes where owner='SCOTT' ;
gather_schema_stats
收集模式中所有对象的统计信息。
示例:
为模式 scott 的所有表统计数据
execut dbms_stats.gather_schema_stats(ownname=>'scott') ;
验证模式 scott 的数据统计是否成功
select last_analyzed,table_name,owner,num_rows,sample_size from dba_tables where owner='SCOTT' ;
exec DBMS_STATS.GATHER_SCHEMA_STATS ('SH', degree=>4, cascade=>TRUE) ; execut dbms_stats.gather_schema_stats('sys') ;
gather_system_stats
收集系统统计信息。当 CBO 选择最佳查询路径时,需要使用数据库对象如表、 索引等的统计数据,以及操作系统的统计数据如 I/O 速度,CPU 周期等进行 SQL 的操作耗时计算,选择花费时间最少的执行计划为最佳执行计划。Oracle 使用 gather_system_stats 过程来统计操作系统数据。
Noworkload 将捕获 I/O 系统的特征。在此期间,Oracle 将估计 I/O 系统的 平均读取寻道时间和传输速度。此模式适用于所有工作负载。
示例:
execut ++++dbms++++ ++++_++++ ++++stats++++ .gather_system_stats(gathering_mode=>'NOWORKLOAD') ;
gather_table_stats
收集表和列 (和索引) 统计信息。
示例:
execute dbms_stats.gather_table_stats('scott','emp') ;
exec dbms_stats.gather_table_stats('sh', 'sales',method_opt=>'for all
columns size auto', cascade=>TRUE) ;
exec dbms_stats.gather_table_stats('sh', 'sales', method_opt=>'for all columns size skewonly') ;
exec dbms_stats.gather_table_stats('sh', 'sales',method_opt=>'for all columns size 254') ;
Deleting Statistics
delete_column_stats
删除与列相关的统计信息。
示例:
exec dbms_stats.delete_column_stats(ownname=>'scott',tabname=>'dept',colna me=>'deptno') ;
delete_database_stats
删除数据库中所有表的统计信息。
示例:
exec dbms_stats.delete_database_stats() ;
delete_dictionary_stats
删除所有字典架构的统计信息 ( "sys" 、"system"和 rdbms 组件架构) 。
示例:
exec dbms_stats.delete_dictionary_stats () ;
delete_fixed_objects_stats
删除所有固定表的统计信息。
示例:
exec dbms_stats.delete_fixed_objects_stats () ;
delete_index_stats
删除与索引相关的统计信息。
示例:
exec dbms_stats.delete_index_stats (ownname=>'scott',indname=>'pk_dept') ;
delete_schema_stats
删除整个模式的统计信息。
示例:
exec dbms_stats.delete_schema_stats(ownname=>'scott') ;
-- 删除 schema 统计
exec dbms_stats.delete_schema_stats('sh') ;
delete_table_stats
删除与表相关的统计信息。
示例:
exec dbms_stats.delete_table_stats (ownname=>'scott',tabname=>'dept') ; -- 删除 table 统计
exec dbms_stats.delete_table_stats('sh','sales') ;
实时统计信息
[oracle@localhost ~]$ sqlplus / as sysdba
show pdbs
conn / as sysdba
alter session set container=PDB2;
startup
show con_name
create user test identified by 123456;
grant dba to test;
conn test/123456@192.168.1.10:1521/PDB2
create table testgather as select * from dba_objects;
set line 200
col table_name for a20
--如果没有收集统计信息,会是空的
select table_name,num_rows,blocks,notes from user_tab_statistics where table_name='TESTGATHER';
--如果没有收集统计信息,会是空的
col column_name for a20
col high_value for a20
col low_value for a20
col notes for a40
select column_name,high_value,low_value,notes from user_tab_col_statistics where table_name='TESTGATHER';
收集表的统计信息
SQL> exec dbms_stats.gather_table_stats('test','testgather',method_opt=>'for all columns size 2');
再执行一次查询,发现在 note 部分什么都没有。说明 real-time statistics 还没有收集。 --表级别
select table_name,num_rows,blocks,notes from user_tab_statistics where table_name='TESTGATHER';
--列级别
set line 200
col column_name for a20
col high_value for a20
col low_value for a20
col notes for a40
select column_name,high_value,low_value,notes from user_tab_col_statistics where
table_name='TESTGATHER';
再次插入数据
insert into testgather select * from testgather;
commit;
--获取执行计划
下图第二个红框中显示 load table conventional ,这表示在刚才插入数据的时候,数据库执 行了实时统计值收集的动作。
SQL > select * from table(dbms_xplan.display_cursor(format = >'typical'));
查看统计信息的表。
--表级别
select table_name,num_rows,blocks,notes from user_tab_statistics where
table_name='TESTGATHER';
列级别
set line 200
col column_name for a20
col high_value for a20
col low_value for a20
col notes for a40
select column_name,high_value,low_value,notes from user_tab_col_statistics where
table_name='TESTGATHER';
因为 19C 实时收集统计信息,其实只开发给 EXDATA 一体机使用,使用隐含参数来模拟。 这个参数是在 CDB 下生效,如果在 PDB 下改会报错,ORA-65040: operation not allowed from within a pluggable database
conn / as sysdba
alter session set container=CDB$ROOT;
alter system set "_exadata_feature_on"=true scope=spfile;
shutdown immediate
startup
alter pluggable database all open;
conn test/123456@192.168.1.10:1521/pdb1
set line 200
col column_name for a20
col high_value for a20
col low_value for a20
col notes for a40
select column_name,high_value,low_value,notes from user_tab_col_statistics where
table_name='TESTGATHER';
再次插入数据
insert into testgather select * from testgather;
commit;
set line 200
col column_name for a20
col high_value for a20
col low_value for a20
col notes for a40
select column_name,high_value,low_value,notes from user_tab_col_statistics where
table_name='TESTGATHER';
select table_name,num_rows,blocks,notes from user_tab_statistics where table_name='TESTGATHER';
手动刷新进去
exec dbms_stats.flush_database_monitoring_info;
select table_name,num_rows,blocks,notes from user_tab_statistics where
table_name='TESTGATHER';
set autotrace on;
select count(*) from testgather;
可以看到 289580=72395+217185,如果创建的表,刚开始没有数据的话。这里是准的。
需要注意
-
使用非 sys 用户
-
这个特性只有 exdata 一体机