此脚本不依赖统计信息。
当执行计划中出现了 INDEX SKIP SCAN,通常说明需要额外添加一个索引。以下脚本抓出走了 INDEX SKIP SCAN 的 SQL。
select c.sql_text, c.sql_id, b.object_name, d.mb
from v$sql_plan b,
v$sql c,
(select owner, segment_name, sum(bytes / 1024 / 1024) mb
from dba_segments
group by owner, segment_name) d
where b.sql_id = c.sql_id
and b.child_number = c.child_number
and b.object_owner = 'SCOTT'
and b.operation = 'INDEX'
and b.options = 'SKIP SCAN'
and b.object_owner = d.owner
and b.object_name = d.segment_name
order by 4 desc;
在 Scott 账户中创建如下测试表。
create table t_skip as select * from dba_objects;
Table created.
在 owner 字段上创建一个索引。
create index idx_owner_id on t_skip(owner,object_id);
Index created.
对表收集统计信息。
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
tabname => 'T_SKIP',
estimate_percent => 100,
method_opt => 'for all columns size skewonly',
no_invalidate => FALSE,
degree => 1,
cascade => TRUE);
END;
PL/SQL procedure successfully completed.
执行如下 SQL 并且查看执行计划。
select * from t_skip where object_id < 100;
98 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 979686564
-------------------------------------------------------------------------------------
| Id |Operation |Name |Rows| Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 |SELECT STATEMENT | | 91| 8827 | 95 (0)| 00:00:02 |
| 1 | TABLE ACCESS BY INDEX ROWID|T_SKIP | 91| 8827 | 95 (0)| 00:00:02 |
|* 2 | INDEX SKIP SCAN |IDX_OWNER_ID| 91| | 92 (0)| 00:00:02 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"<100)
filter("OBJECT_ID"<100)
通过脚本抓出走了 INDEX SKIP SCAN 的 SQL。
select c.sql_text, c.sql_id, b.object_name, d.mb
from v$sql_plan b,
v$sql c,
(select owner, segment_name, sum(bytes / 1024 / 1024) mb
from dba_segments
group by owner, segment_name) d
where b.sql_id = c.sql_id
and b.child_number = c.child_number
and b.object_owner = 'SCOTT'
and b.operation = 'INDEX'
and b.options = 'SKIP SCAN'
and b.object_owner = d.owner
and b.object_name = d.segment_name
order by 4 desc;
SQL_TEXT SQL_ID OBJECT_NAME MB
------------------------------------------ --------------- --------------- ----------
select * from t_skip where object_id < 100 0837hu8zxha2y IDX_OWNER_ID 2