生产情景:
大的表,如日志表,每天都有大批量的数据插入,假设上面有id,timed字段上建有索引,id的选择率很高;
生产营运期间经常会报执行计划变化导致的问题;
模拟下场景:
SQL> create table aiki_t1 as select * from dba_objects where object_id is not null;
Table created.
SQL> create index idx_aiki_t1_id on aiki_t1(object_id);
Index created.
SQL> create index idx_aiki_t1_time on aiki_t1(created);
Index created.
SQL> exec dbms_stats.gather_table_stats('AIKI','AIKI_T1',CASCADE=>TRUE,ESTIMATE_PERCENT=>100,METHOD_OPT=>'FOR ALL COLUMNS SIZE 1');
PL/SQL procedure successfully completed.
SQL> SELECT LOW_VALUE,HIGH_VALUE from dba_tab_col_statistics where owner='AIKI' and table_name='AIKI_T1' AND COLUMN_NAME='CREATED';
LOW_VALUE HIGH_VALUE
---------------------------------------------------------------- ----------------------------------------------------------------
78710C030B3C23 7872030A12071F
1 row selected.
--查询字典中记录的最大最小值,读取RAW类型的数值
declare
v1 raw(32):='7872030A12071F';
v2 date;
begin
dbms_stats.convert_raw_value(v1,v2);
dbms_output.put_line(to_char(v2,'yyyy mmdd hh24:mi'));
end;
SQL> declare
2 v1 raw(32):='78710C030B3C23';
3 v2 date;
4 begin
5 dbms_stats.convert_raw_value(v1,v2);
6 dbms_output.put_line(to_char(v2,'yyyy mmdd hh24:mi'));
7 end;
8 /
2013 1203 10:59
PL/SQL procedure successfully completed.
SQL> declare
2 v1 raw(32):='7872030A12071F';
3 v2 date;
4 begin
5 dbms_stats.convert_raw_value(v1,v2);
6 dbms_output.put_line(to_char(v2,'yyyy mmdd hh24:mi'));
7 end;
8 /
2014 0310 17:06
PL/SQL procedure successfully completed.
--创建一临时表模拟数据量在统计后的大批量插入
SQL> create table zbk as select * from dba_objects where object_id is not null;
Table created.
--更改列值
SQL> alter session force parallel dml;
Session altered.
SQL> update zbk set created='2014 0320';
106429 rows updated.
SQL> commit;
Commit complete.
SQL> l
1* commit
SQL> select distinct created from zbk;
CREATED
--------
20140320
1 row selected.
--数据量统计分析后大批插入
SQL> insert into aiki_t1 select * from zbk;
106429 rows created.
SQL> commit;
Commit complete.
--数据量在最大值和最小值范围情况,预估行为56589与实际有出入,但差别明显比超出范围的要小
SQL> set autot traceonly
SQL>
SQL> select object_type from aiki_t1 where created>to_date('20140118','yyyymmdd');
107207 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 335395965
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 56589 | 994K| 436 (1)| 00:00:06 |
|* 1 | TABLE ACCESS FULL| AIKI_T1 | 56589 | 994K| 436 (1)| 00:00:06 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CREATED">TO_DATE(' 2014-01-18 00:00:00', 'syyyy-mm-dd
hh24:mi:ss'))
Statistics
----------------------------------------------------------
1 recursive calls
1 db block gets
10597 consistent gets
1561 physical reads
168 redo size
2330729 bytes sent via SQL*Net to client
79137 bytes received via SQL*Net from client
7149 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107207 rows processed
--列值在最大最小值范围外,预估值44行与实际的结果相差甚远,且成本只有3
SQL> select object_type from aiki_t1 where created>to_date('20140318','yyyymmdd');
106429 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2814400874
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 44 | 792 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| AIKI_T1 | 44 | 792 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_AIKI_T1_TIME | 44 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("CREATED">TO_DATE(' 2014-03-18 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
17018 consistent gets
0 physical reads
39084 redo size
2311172 bytes sent via SQL*Net to client
78565 bytes received via SQL*Net from client
7097 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
106429 rows processed
--没有重复值的索引列的成本也要2
SQL> select object_type from aiki_t1 where created>to_date('20140318','yyyymmdd') and object_id=88998899;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 2361744790
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 23 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| AIKI_T1 | 1 | 23 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_AIKI_T1_ID | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CREATED">TO_DATE(' 2014-03-18 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
2 - access("OBJECT_ID"=88998899)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
7 consistent gets
0 physical reads
156 redo size
339 bytes sent via SQL*Net to client
509 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
--方法
1.后台绑定sql profile或spm
2.程序加HINT解决