Plan hash value: 514881935
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)|
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 11 | 2 (0)| 00
|* 2 | INDEX RANGE SCAN | IDX_T_ID | 1 | | 1 (0)| 00
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"=1000)
19 rows selected
此时,最优的执行计划是索引路径。在shared pool中有一个父游标和子游标(version count=1),执行次数为1。
第二次执行之后,Shared Pool中有共享现象。相同的共享游标执行两次。
SQL> select sql_id, executions, version_count from v$sqlarea where sql_text like 'select /*+demo*/%';
SQL_ID EXECUTIONS VERSION_COUNT
------------- ---------- -------------
cnb0ktgvms6vq 2 1
之后,我们更新数据,修改数据分布结构。
SQL> update t set object_id=1000;
72729 rows updated
SQL> commit;
Commit complete
此时,如果执行SQL语句,我们发现依然是使用原有的索引路径。此时全部T表中object_id都是1000,走索引不是好的选择。
SQL> select /*+demo*/object_id, owner from t where object_id=1000;
已选择72729行。
统计信息
------------------------------------------
0 recursive calls
0 db block gets
11157 consistent gets
0 physical reads
72729 rows processed
SQL> select sql_id, executions, version_count from v$sqlarea where sql_text like 'select /*+demo*/%';
SQL_ID EXECUTIONS VERSION_COUNT
------------- ---------- -------------
cnb0ktgvms6vq 3 1
此时的路径依然是Index Range Scan。这个明显是由于统计量的过时,外加游标共享,引起的错误路径。下面我们重新收集一下统计量,采用no_invaliate为true的情况。
SQL> exec dbms_stats.flush_database_monitoring_info;
PL/SQL procedure successfully completed
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true,no_invalidate => true,method_opt => 'for columns size 10 object_id');
PL/SQL procedure successfully completed
新统计量生成,我们使用explain plan查看一下,此时SQL应该采用的执行计划是什么?
SQL> explain plan for select /*+demo*/object_id, owner from t where object_id=1000;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------
Plan hash value: 1601196873
---------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 72722 | 639K| 266 (1)| 00:00:04 |
|* 1 | TABLE ACCESS FULL| T | 72722 | 639K| 266 (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=1000)
13 rows selected
此时,FTS全表扫描是更好的选择。但是我们查看一下实际执行时候,路径情况。
SQL> select /*+demo*/object_id, owner from t where object_id=1000;
已选择72729行。
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
10907 consistent gets
0 physical reads
0 redo size
72729 rows processed
SQL> select sql_id, executions, version_count from v$sqlarea where sql_text like 'select /*+demo*/%';
SQL_ID