此脚本依赖统计信息。
如果一个索引选择性很低,说明列数据分布不均衡。当 SQL 走了数据分布不均衡列的索引,很容易走错执行计划,此时我们应该检查 SQL 语句中是否有其他过滤条件,如果有其他过滤条件,可以考虑建立组合索引,将选择性高的列作为引导列;如果没有其他过滤条件,应该检查列是否有收集直方图。以下脚本抓出走了低选择性索引的 SQL。
select c.sql_id,c.sql_text,b.index_name,e.table_name,trunc(d.num_distinct / e.num_rows * 100, 2) selectivity,d.num_distinct,e.num_rowsfrom v$sql_plan a,(select *from (select index_owner,index_name,table_owner,table_name,column_name,count(*) over(partition by index_owner, index_name, table_owner, table_name) cntfrom dba_ind_columns)where cnt = 1) b,v$sql c,dba_tab_col_statistics d,dba_tables ewhere a.object_owner = b.index_ownerand a.object_name = b.index_nameand b.index_owner = 'SCOTT'and a.access_predicates is not nulland a.sql_id = c.sql_idand a.child_number = c.child_numberand d.owner = e.ownerand d.table_name = e.table_nameand b.table_owner = e.ownerand b.table_name = e.table_nameand d.column_name = b.column_nameand d.table_name = b.table_nameand d.num_distinct / e.num_rows < 0.1;
我们在 Scott 账户中执行如下 SQL 并且查看执行计划。
select * from t where owner='SYS';
23654 rows selected.Execution Plan----------------------------------------------------------Plan hash value: 2480948561-------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost(%CPU)|Time |-------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 2346 | 222K| 68 (0)|00:00:01|| 1 | TABLE ACCESS BY INDEX ROWID| T | 2346 | 222K| 68 (0)|00:00:01||* 2 | INDEX RANGE SCAN | IDX_OWNER | 2346 | | 6 (0)|00:00:01|-------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------2 - access("OWNER"='SYS')Statistics----------------------------------------------------------1 recursive calls0 db block gets3819 consistent gets0 physical reads0 redo size2680901 bytes sent via SQL*Net to client17756 bytes received via SQL*Net from client1578 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)23654 rows processed
我们使用脚本将以上 SQL 抓出。
select c.sql_id,c.sql_text,b.index_name,e.table_name,trunc(d.num_distinct / e.num_rows * 100, 2) selectivity,d.num_distinct,e.num_rowsfrom v$sql_plan a,(select *from (select index_owner,index_name,table_owner,table_name,column_name,count(*) over(partition by index_owner, index_name, table_owner, table_name) cntfrom dba_ind_columns)where cnt = 1) b,v$sql c,dba_tab_col_statistics d,dba_tables ewhere a.object_owner = b.index_ownerand a.object_name = b.index_nameand b.index_owner = 'SCOTT'and a.access_predicates is not nulland a.sql_id = c.sql_idand a.child_number = c.child_numberand d.owner = e.ownerand d.table_name = e.table_nameand b.table_owner = e.ownerand b.table_name = e.table_nameand d.column_name = b.column_nameand d.table_name = b.table_nameand d.num_distinct / e.num_rows < 0.1;
SQL_ID SQL_TEXT INDEX_NAME TABLE_NAME SELECTIVITY NUM_DISTINCT NUM_ROWS----------- --------------------------- ---------- ----------- ---- -------- --------6gzd8z5vm5k0t select * from t where owner='SYS' IDX_OWNER T .04 31 72734
