开发DBA,对Oracle大表治理流程如下:
1.创建temp表,与生产环境大表相同表结构;
2.对生产环境大表rename to table_name_bak;
3.对temp表 rename to table_name 生产环境表;
4.此时新的业务表无数据,insert into table_name select * from table_name_bak where date>sysdate-31;
5.对新建的表,同步bak表的索引!
6.SQL测试,发现存在性能问题,非常慢,原本执行SQL很快,大表几十G,新的表才30W条记录???
统计信息的问题,收集后OK
exec dbms_stats.gather_table_stats(ownname=>'A',tabname=>'B',cascade=>true,degree=>6,estimate_percent=>50);
?为啥?
实验测试:
SQL> create table a as select * from dba_objects; SQL> create index a_id on a(object_id); SQL> set autotrace on SQL> select count(*) from a where object_id=7788 order by object_id; COUNT(*) ---------- 1 Execution Plan ---------------------------------------------------------- Plan hash value: 2227953900 ------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 13 | | | |* 2 | INDEX RANGE SCAN| A_ID | 1 | 13 | 1 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=7788) Note ----- - dynamic sampling used for this statement (level=2)
本次测试的举例不太好,因为SQL走了索引,但是为啥SQL走了索引呢? 是由于ORACLE 11G动态采样,ORACLE执行计划选择对了。
但是生产环境,动态采样后,Oracle发现走索引成本更高,走全表扫描了!!!
SQL> SELECT NUM_ROWS,EMPTY_BLOCKS,BLOCKS,LAST_ANALYZED FROM DBA_TABLES WHERE OWNER='YZ' AND TABLE_NAME='A';
NUM_ROWS EMPTY_BLOCKS BLOCKS LAST_ANAL
---------- ------------ ---------- ---------
SQL> SELECT NUM_ROWS,SAMPLE_SIZE,LEAF_BLOCKS,LAST_ANALYZED FROM DBA_INDEXES WHERE TABLE_OWNER='YZ' AND TABLE_NAME='A';
NUM_ROWS SAMPLE_SIZE LEAF_BLOCKS LAST_ANAL
---------- ----------- ----------- ---------
87096 87096 193 28-APR-20
表统计信息0,因此生产环境的问题,就是创建索引,这个只会收集索引统计信息,而非级联表,SQL执行动态采用,数据不准确,导致最终的SQL执行计划选择全表扫描,SQL执行缓慢。 收集统计信息后,表数据量准确,重新生成都执行计划,选择了正确的执行计划!!!