UNSELECTIVE INDEXES

Written JP Vijaykumar Oracle DBA
Date April 8th 2013
------------------------------------------------------------------------------------------------------------------------------------------In our OLTP application, I stumbled on an unselective index.
This index was created on a table having 200 million rows.
set timing on linesize 140 autot on exp
select count(1) from PROCESS_EVENT;
COUNT(1)
---------204725547
Elapsed: 00:06:29.47
Execution Plan
---------------------------------------------------------Plan hash value: 178217403
---------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Cost (%CPU)| Time
|
---------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
1 | 529K (2)| 01:45:57 |
| 1 | SORT AGGREGATE
|
|
1 |
|
|
| 2 | TABLE ACCESS FULL| PROCESS_EVENT | 204M| 529K (2)| 01:45:57 |
-----------------------------------------------------------------------------The index was created on the columns(PROCESS_NUM,PROCESS_EVENT_NUM).
PROCESS_NUM column with "0" cardinality is the leading column, followed by
PROCESS_EVENT_NUM with HIGH cardinality in the compound column index.
select count(distinct(PROCESS_NUM)),count(distinct(PROCESS_EVENT_NUM))
from PROCESS_EVENT;
COUNT(DISTINCT(PROCESS_NUM)) COUNT(DISTINCT(PROCESS_EVENT_NUM))
----------------------------- -------------------------2
204725547
Elapsed: 00:22:08.41
Execution Plan
---------------------------------------------------------Plan hash value: 1694662085
----------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
----------------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
1 |
10 | 531K (2)| 01:46:
13 |
| 1 | SORT GROUP BY
|
|
1 |
10 |
|
|
| 2 | TABLE ACCESS FULL| PROCESS_EVENT | 204M| 1952M| 531K (2)| 01:46:
13 |
--------------------------------------------------------------------------------

-----The two distinct values in the PROCESS_NUM columns are 0,1.
select distinct(PROCESS_NUM)from PROCESS_EVENT;
PROCESS_NUM
-----------1
0
Elapsed: 00:09:30.45
Execution Plan
---------------------------------------------------------Plan hash value: 1182932553
----------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
----------------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
2 |
6 | 559K (7)| 01:51:
51 |
| 1 | HASH UNIQUE
|
|
2 |
6 | 559K (7)| 01:51:
51 |
| 2 | TABLE ACCESS FULL| PROCESS_EVENT | 204M| 585M| 531K (2)| 01:46:
13 |
------------------------------------------------------------------------------------A select on the column value of "0" returned about 90% of rows.
--This query used an unselective index.
set timing on linesize 140 autot on exp
select count(1) from PROCESS_EVENT where PROCESS_NUM=0;
COUNT(1)
---------201988352
Elapsed: 00:13:03.31
Execution Plan
---------------------------------------------------------Plan hash value: 222725074
-------------------------------------------------------------------------| Id | Operation
| Name | Rows | Bytes | Cost (%CPU)| Time
|
-------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
1 |
3 | 84619 (1)| 00:16:56 |
| 1 | SORT AGGREGATE |
|
1 |
3 |
|
|
|* 2 | INDEX RANGE SCAN| IDX4 | 102M| 292M| 84619 (1)| 00:16:56 |
-------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("PROCESS_NUM"=0)
--Let us see how the query performs with a full table scan on the table.
select /*+ full(a)*/ count(1) from PROCESS_EVENT a where PROCESS_NUM=0;
COUNT(1)
---------201988352
Elapsed: 00:07:16.14
Execution Plan
---------------------------------------------------------Plan hash value: 178217403
----------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
----------------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
1 |
3 | 532K (2)| 01:46:
27 |
| 1 | SORT AGGREGATE
|
|
1 |
3 |
|
|
|* 2 | TABLE ACCESS FULL| PROCESS_EVENT | 102M| 292M| 532K (2)| 01:46:
27 |
----------------------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------2 - filter("PROCESS_NUM"=0)
--Using both the columns in the index.
select count(1) from PROCESS_EVENT where PROCESS_NUM=0 and PROCESS_EVENT_NUM=180
156510;
COUNT(1)
---------1
Execution Plan
---------------------------------------------------------Plan hash value: 222725074
-------------------------------------------------------------------------| Id | Operation
| Name | Rows | Bytes | Cost (%CPU)| Time
|
-------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
1 |
10 |
1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE |
|
1 |
10 |
|
|
|* 2 | INDEX RANGE SCAN| IDX4 |
1 |
10 |
1 (0)| 00:00:01 |
-------------------------------------------------------------------------Predicate Information (identified by operation id):

--------------------------------------------------2 - access("PROCESS_NUM"=0 AND "PROCESS_EVENT_NUM"=180156510)
--I wanted to reverse the coulumns combination in our unselective index and see
how the query is performing(starting the HIGH CARDINALITY PROCESS_EVENT_NUM co
lumn as
the left most column, followed by the LOW CARDINALITY PROCESS_NUM column).
--Since this table is in production, I can not modify the existing indexes.
--I created a test case to verify the differences.
------------------------------------------------------------------------------------------------------------------------------------------I used these scripts to capture the run_stats for different operations using
different predicate combinations.
set serverout on size 1000000 autot off
declare
v_tab varchar2(30):='BEFORE_JP';
begin
begin
execute immediate 'drop table '||v_tab;
exception
when others then
dbms_output.put_line(v_tab||' '||sqlerrm);
end;
execute immediate 'create table '||v_tab||
' as select '''||'STAT..'||'''|| a.name name, b.value
from v$statname a, v$mystat b
where a.statistic# = b.statistic#
union all
select '''||'LATCH.' ||'''|| name, gets
from v$latch
union all
select '''||'STAT..Elapsed Time'||''', hsecs from v$timer';
end;
/

set serverout on size 1000000 autot off
declare
v_tab varchar2(30):='a';
begin
begin
execute immediate 'drop table '||v_tab;
exception
when others then
dbms_output.put_line(v_tab||' '||sqlerrm);
end;
execute immediate 'create table '||v_tab||' as
with e as (select '''||'STAT..'||'''|| a.name name, b.value
from v$statname a, v$mystat b
where a.statistic# = b.statistic#
union all
select '''||'LATCH.'||''' || name, gets
from v$latch
union all
select '''||'STAT..Elapsed Time'||''', hsecs from v$timer)

select e.name, e.value - nvl(b.value,0) diff
from e, before_jp b
where e.name = b.name (+)
order by 1';
end;
/
column name format a60
--select a.name||','||a.diff ||','||b.diff
select a.name,a.diff,b.diff
--||','||c.diff||','||d.diff
from a,b
--,c,d
where a.name = b.name
--and a.name = c.name
--and a.name = d.name
and (a.diff <> 0 and b.diff <> 0 ) --and c.diff <> 0 and d.diff <> 0 )
order by a.name;
------------------------------------------------------------------------------------------------------------------------------------------created the test table, populated with 10 million rows, created two
indexes with different column combinations.
drop table temp_jp;
create table temp_jp(col1 number,col2 number,col3 varchar2(20));
set serverout on size 1000000 timing on
declare
v_num number;
v_str varchar2(20):='SAKETHRAM';
begin
for i in 1..10000000 loop
if (mod(i,2)=0) then
v_num:=2;
else
v_num:=1;
end if;
if
(v_str = 'SAKETHRAM') then
v_str:='ISHHA';
elsif
(v_str = 'ISHHA') then
v_str:='VEEKSHA';
elsif
(v_str = 'VEEKSHA') then
v_str:='SAKETHRAM';
end if;
insert into temp_jp values(i,v_num,v_str);
end loop;
end;
/
PL/SQL procedure successfully completed.
commit;
--DISTINCT KEY VALUES OF COL1,COL2 & COL3
set autotrace off linesize 140 pagesize 500
select count(distinct(col1)),

count(distinct(col2)),count(distinct(col3)) from temp_jp;
COUNT(DISTINCT(COL1)) COUNT(DISTINCT(COL2)) COUNT(DISTINCT(COL3))
--------------------- --------------------- --------------------10000000
2
3

--SELECTIVENESS OF THE THREE COLUMNS
set autotrace off head off linesize 140 pagesize 500
select
'col1 selectiveness: '||round(count(distinct(col1))*100/count(1),2)||'%',
'col2 selectiveness: '||round(count(distinct(col2))*100/count(1),2)||'%',
'col3 selectiveness: '||round(count(distinct(col3))*100/count(1),2)||'%' from t
emp_jp;
col1 selectiveness: 100%
col2 selectiveness: 0%
col3 selectiveness: 0%
--I performed the following two tests(a and B).
--Before each test, I had shutdown and restarted the database.
A) create index temp_jp_id01 on temp_jp(col1,col3);
set timing on autot on exp linesize 140
select count(1) from temp_jp where col1=890343 and col3='VEEKSHA';
COUNT(1)
---------0
Elapsed: 00:00:00.00
Execution Plan
---------------------------------------------------------Plan hash value: 4206144944
--------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
1 |
14 |
3 (0)| 00:00:01
|
| 1 | SORT AGGREGATE |
|
1 |
14 |
|
|
|* 2 | INDEX RANGE SCAN| TEMP_JP_ID01 |
1 |
14 |
3 (0)| 00:00:01
|
--------------------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------2 - access("COL1"=890343 AND "COL3"='VEEKSHA')
B) create index temp_jp_id03 on temp_jp(col3,col1);

set timing on autot on exp linesize 140
select count(1) from temp_jp where col3='VEEKSHA' and col1=890343;
COUNT(1)
---------0
Execution Plan
---------------------------------------------------------Plan hash value: 260720216
--------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------| 0 | SELECT STATEMENT |
|
1 |
14 |
3 (0)| 00:00:01
|
| 1 | SORT AGGREGATE |
|
1 |
14 |
|
|
|* 2 | INDEX RANGE SCAN| TEMP_JP_ID03 |
1 |
14 |
3 (0)| 00:00:01
|
--------------------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------2 - access("COL3"='VEEKSHA' AND "COL1"=890343)
--From the explain_plan output, both the queries look similar, untill I ran run_
stats.
--The following are the run_stats output for the tests(A & B)(one execution per
query):
NAME
DIFF_A
DIFF_B
-------------------------------------------------------- ---------- ---------LATCH.AQ deq hash table latch
1
1
LATCH.ASM db client latch
48
137
LATCH.ASM map operation hash table
1
1
LATCH.ASM network state latch
1
3
LATCH.Change Notification Hash table latch
23
67
LATCH.Consistent RBA
9
14
LATCH.DML lock allocation
41
63
LATCH.Event Group Locks
3
5
LATCH.FOB s.o list latch
2
6
LATCH.File State Object Pool Parent Latch
1
1
LATCH.I/O Staticstics latch
1
1
LATCH.IPC stats buffer allocation latch
1
1
LATCH.In memory undo latch
32
97
LATCH.JS Sh mem access
1
3
LATCH.JS queue access latch
1
3
LATCH.JS queue state obj latch
504
1564
LATCH.JS slv state obj latch
1
5
LATCH.KFC FX Hash Latch
1
1

LATCH.KFC Hash Latch
LATCH.KFCL LE Freelist
LATCH.KGNFS-NFS:SHM structure
LATCH.KGNFS-NFS:SVR LIST
LATCH.KJC message pool free list
LATCH.KJCT flow control latch
LATCH.KMG MMAN ready and startup request latch
LATCH.Locator state objects pool parent latch
LATCH.Lsod array latch
LATCH.Memory Management Latch
LATCH.Memory Queue
LATCH.Memory Queue Message Subscriber #1
LATCH.Memory Queue Message Subscriber #2
LATCH.Memory Queue Message Subscriber #3
LATCH.Memory Queue Message Subscriber #4
LATCH.Memory Queue Subscriber
LATCH.Mutex
LATCH.Mutex Stats
LATCH.NLS data objects
LATCH.OS process
LATCH.OS process allocation
LATCH.OS process: request allocation
LATCH.PL/SQL warning settings
LATCH.PX hash array latch
LATCH.QMT
LATCH.SGA blob parent
LATCH.SGA bucket locks
LATCH.SGA heap locks
LATCH.SGA pool locks
LATCH.SQL memory manager latch
LATCH.SQL memory manager workarea list latch
LATCH.Shared B-Tree
LATCH.Streams Generic
LATCH.Testing
LATCH.Token Manager
LATCH.WCR: sync
LATCH.Write State Object Pool Parent Latch
LATCH.XDB NFS Security Latch
LATCH.XDB unused session pool
LATCH.XDB used session pool
LATCH.active checkpoint queue latch
LATCH.active service list
LATCH.begin backup scn array
LATCH.buffer pool
LATCH.business card
LATCH.cache buffer handles
LATCH.cache buffers chains
LATCH.cache buffers lru chain
LATCH.cache table scan latch
LATCH.call allocation
LATCH.cas latch
LATCH.change notification client cache latch
LATCH.channel handle pool latch
LATCH.channel operations parent latch
LATCH.checkpoint queue latch
LATCH.client/application info
LATCH.compile environment latch
LATCH.cp cmon/server latch
LATCH.cp pool latch
LATCH.cp server hash latch

1
1
1
1
1
1
23
1
1
1
1
1
1
1
1
1
1
1
3
13
138
2
10
1
1
1
1
1
1
2
1551
3
1
1
1
1
1
1
1
1
82
143
1
1
1
4
16116
100
4
53
1
1
6
403
8838
3
2
1
1
1

1
1
1
1
1
1
67
1
1
1
1
1
1
1
1
1
1
1
3
31
396
6
13
1
1
1
1
1
1
7
4499
8
1
1
1
1
1
1
1
1
216
434
1
1
1
11
20507
136
4
88
1
1
10
1121
25734
14
5
1
1
1

LATCH.cp sga latch
LATCH.cvmap freelist lock
LATCH.deferred cleanup latch
LATCH.dml lock allocation
LATCH.done queue latch
LATCH.dummy allocation
LATCH.enqueue hash chains
LATCH.enqueues
LATCH.fifth spare latch
LATCH.file cache latch
LATCH.flashback copy
LATCH.fourth Audit Vault latch
LATCH.gc element
LATCH.gcs commit scn state
LATCH.gcs partitioned table hash
LATCH.gcs pcm hashed value bucket hash
LATCH.gcs resource freelist
LATCH.gcs resource hash
LATCH.gcs resource scan list
LATCH.gcs shadows freelist
LATCH.ges domain table
LATCH.ges enqueue table freelist
LATCH.ges group table
LATCH.ges process hash list
LATCH.ges process parent latch
LATCH.ges resource hash list
LATCH.ges resource scan list
LATCH.ges resource table freelist
LATCH.ges value block free list
LATCH.global tx hash mapping
LATCH.granule operation
LATCH.hash table modification latch
LATCH.heartbeat check
LATCH.internal temp table object number allocation latch
LATCH.intra txn parallel recovery
LATCH.io pool granule metadata list
LATCH.job workq parent latch
LATCH.job_queue_processes parameter latch
LATCH.k2q lock allocation
LATCH.kdlx hb parent latch
LATCH.kgb parent
LATCH.kgnfs mount latch
LATCH.kokc descriptor allocation latch
LATCH.ksfv messages
LATCH.ksim group membership cache
LATCH.kss move lock
LATCH.ksuosstats global area
LATCH.ksv allocation latch
LATCH.ksv class latch
LATCH.ksv instance latch
LATCH.ksv msg queue latch
LATCH.ksz_so allocation latch
LATCH.ktm global data
LATCH.kwqbsn:qsga
LATCH.lgwr LWN SCN
LATCH.loader state object freelist
LATCH.lob segment dispenser latch
LATCH.lob segment hash table latch
LATCH.lob segment query latch
LATCH.lock DBA buffer during media recovery

1
1
1
2
1
3
1338
1261
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
5
1
1
1
1
1
15
1
1
1
1
6
1
1
3
4
4
3
1
1
2
6
2
29
3
1
3
1
1

3
1
3
4
1
9
3778
3637
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
10
1
1
1
1
2
46
1
1
1
1
6
1
1
3
11
6
3
1
1
6
6
7
76
3
1
3
1
1

LATCH.logical standby cache
LATCH.logminer context allocation
LATCH.logminer work area
LATCH.longop free list parent
LATCH.mapped buffers lru chain
LATCH.message pool operations parent latch
LATCH.messages
LATCH.mostly latch-free SCN
LATCH.msg queue latch
LATCH.multiblock read objects
LATCH.name-service namespace bucket
LATCH.ncodef allocation latch
LATCH.object queue header heap
LATCH.object queue header operation
LATCH.object stats modification
LATCH.parallel query alloc buffer
LATCH.parallel query stats
LATCH.parameter list
LATCH.parameter table management
LATCH.peshm
LATCH.pesom_free_list
LATCH.pesom_hash_node
LATCH.post/wait queue
LATCH.process allocation
LATCH.process group creation
LATCH.process queue
LATCH.process queue reference
LATCH.qmn task queue latch
LATCH.query server freelists
LATCH.queuing load statistics
LATCH.recovery domain hash list
LATCH.redo allocation
LATCH.redo copy
LATCH.redo writing
LATCH.resmgr:active threads
LATCH.resmgr:actses change group
LATCH.resmgr:actses change state
LATCH.resmgr:free threads list
LATCH.resmgr:plan CPU method
LATCH.resmgr:resource group CPU method
LATCH.resmgr:schema config
LATCH.resmgr:session queuing
LATCH.rm cas latch
LATCH.row cache objects
LATCH.second Audit Vault latch
LATCH.second spare latch
LATCH.sequence cache
LATCH.session allocation
LATCH.session idle bit
LATCH.session queue latch
LATCH.session state list latch
LATCH.session switching
LATCH.session timer
LATCH.shared pool
LATCH.shared pool sim alloc
LATCH.shared pool simulator
LATCH.sim partition latch
LATCH.simulator hash latch
LATCH.simulator lru latch
LATCH.sort extent pool

1
1
1
1
1
6
718
29
1
34
1
1
697
2540
24
13
1
2
2
1
1
1
4
4
2
1
1
8
1
1
1
149
1
149
16
3
2
2
1
8
14
1
1
4609
1
1
10
16
76
1
7
2
22
4107
1
190
1
884
1
19

1
1
1
1
1
6
2030
77
1
34
1
3
1802
3824
42
25
1
6
25
1
1
1
5
10
6
1
1
28
1
1
1
285
1
386
51
4
2
8
1
8
43
1
1
7015
1
1
18
26
95
1
17
14
67
7292
2
332
1
1050
1
21

LATCH.space background state object latch
LATCH.space background task latch
LATCH.tablespace key chain
LATCH.temp lob duration state obj allocation
LATCH.temporary table state object allocation
LATCH.test excl. parent l0
LATCH.test excl. parent2 l0
LATCH.third spare latch
LATCH.threshold alerts latch
LATCH.trace latch
LATCH.transaction allocation
LATCH.undo global data
LATCH.virtual circuit buffers
LATCH.virtual circuit holder
LATCH.virtual circuit queues
STAT..Block Cleanout Optim referenced
STAT..CPU used by this session
STAT..CPU used when call started
STAT..DB time
STAT..Elapsed Time
STAT..HSC Heap Segment Block Changes
STAT..Heap Segment Array Updates
STAT..IMU Flushes
STAT..IMU ktichg flush
STAT..IMU undo allocation size
STAT..SQL*Net roundtrips to/from client
STAT..buffer is not pinned count
STAT..buffer is pinned count
STAT..bytes received via SQL*Net from client
STAT..bytes sent via SQL*Net to client
STAT..calls to get snapshot scn: kcmgss
STAT..calls to kcmgas
STAT..calls to kcmgcs
STAT..cell physical IO interconnect bytes
STAT..cleanout - number of ktugct calls
STAT..cleanouts only - consistent read gets
STAT..cluster key scan block gets
STAT..cluster key scans
STAT..commit batch/immediate performed
STAT..commit batch/immediate requested
STAT..commit cleanout failures: block lost
STAT..commit cleanouts
STAT..commit cleanouts successfully completed
STAT..commit immediate performed
STAT..commit immediate requested
STAT..commit txn count during cleanout
STAT..consistent changes
STAT..consistent gets
STAT..consistent gets - examination
STAT..consistent gets from cache
STAT..consistent gets from cache (fastpath)
STAT..cursor authentications
STAT..db block changes
STAT..db block gets
STAT..db block gets direct
STAT..db block gets from cache
STAT..db block gets from cache (fastpath)
STAT..deferred (CURRENT) block cleanout applications
STAT..enqueue conversions
STAT..enqueue releases

2
54
2
1
1
1
1
1
2
1
10
39
1
1
1
4
23
37
63
6871
19
3
1
1
52
16
3444
313
4379
4732
1069
24
44
1343488
2
2
70
44
1
1
1
27
26
1
1
2
29
3966
2046
3966
1770
27
175
191
7
184
46
15
3
88

2
150
2
1
1
1
1
1
3
3
17
57
1
1
1
4
22
39
62
20158
19
3
1
1
52
16
3443
313
4379
4731
1070
27
47
1368064
2
2
69
43
1
1
1
30
29
1
1
2
30
3968
2046
3968
1771
27
181
199
7
192
47
15
3
89

STAT..enqueue requests
STAT..enqueue waits
STAT..execute count
STAT..file io wait time
STAT..free buffer requested
STAT..immediate (CR) block cleanout applications
STAT..immediate (CURRENT) block cleanout applications
STAT..index fetch by key
STAT..index scans kdiixs1
STAT..lob reads
STAT..lob writes
STAT..lob writes unaligned
STAT..messages sent
STAT..min active SCN optimization applied on CR
STAT..no work - consistent read gets
STAT..non-idle wait count
STAT..non-idle wait time
STAT..opened cursors cumulative
STAT..opened cursors current
STAT..parse count (hard)
STAT..parse count (total)
STAT..parse time cpu
STAT..parse time elapsed
STAT..physical read IO requests
STAT..physical read bytes
STAT..physical read total IO requests
STAT..physical read total bytes
STAT..physical reads
STAT..physical reads cache
STAT..physical reads cache prefetch
STAT..physical write IO requests
STAT..physical write bytes
STAT..physical write total IO requests
STAT..physical write total bytes
STAT..physical writes
STAT..physical writes direct
STAT..physical writes non checkpoint
STAT..pinned cursors current
STAT..recursive calls
STAT..recursive cpu usage
STAT..redo entries
STAT..redo size
STAT..redo size for direct writes
STAT..redo synch time (usec)
STAT..redo synch writes
STAT..rows fetched via callback
STAT..session cursor cache count
STAT..session cursor cache hits
STAT..session logical reads
STAT..session pga memory
STAT..session pga memory max
STAT..session uga memory
STAT..session uga memory max
STAT..shared hash latch upgrades - no wait
STAT..sorts (memory)
STAT..sorts (rows)
STAT..sql area purged
STAT..switch current to new buffer
STAT..table fetch by rowid
STAT..table fetch continued row

89
1
528
97689
177
2
4
583
474
47
2
2
8
1
1807
170
11
381
2
41
305
6
6
142
1286144
142
1286144
157
157
15
1
57344
1
57344
7
7
7
2
2922
23
93
22596
96
2659
2
510
1
302
4157
4849664
4915200
851656
1025240
40
175
457
1
5
1328
33

90
1
528
102099
181
2
4
583
474
47
2
2
8
1
1806
173
11
381
2
41
305
7
9
145
1310720
145
1310720
160
160
15
1
57344
1
57344
7
7
7
2
2922
22
96
23344
96
2618
2
510
1
302
4167
4784128
4849664
851656
1025240
40
175
457
1
5
1328
33

STAT..table scan blocks gotten
STAT..table scan rows gotten
STAT..table scans (short tables)
STAT..temp space allocated (bytes)
STAT..undo change vector size
STAT..user I/O wait time
STAT..user calls
STAT..user commits
STAT..workarea executions - optimal
STAT..workarea memory allocated

85
14928
16
4194304
7332
10
27
3
63
187

85
14928
16
4194304
7572
11
27
3
63
139

328 rows selected.
--The query under test A) with a selective index performed well over the query u
nder
test B) with an unselective index.
--Imagine, how much unnecessaery load is put on our database with an unselective
index
on a 200 million row table.
------------------------------------------------------------------------------------------------------------------------------------------THIS SCRIPT TAKES FEW HOURS TO COMPLETE, DEPENDING ON THE SIZE OF THE DB.
IT GENERATES THE SELECTIVENESS% OF EACH INDEX IN A DB.
set serverout on size 1000000 timing on linesize 140
declare
v_cnt number;
v_row number;
v_tab varchar2(30):='';
--v_tab varchar2(30):='X';
--v_ind varchar2(30):='';
v_ind varchar2(30):='X';
--v_col varchar2(30):='';
v_col varchar2(30):='X';
begin
execute immediate 'alter session set cursor_sharing=force';
execute immediate 'alter session set nls_date_format='''||'mm-dd-yyyy hh24:mi:ss
'||''' ';
for c1 in (select table_name from user_tables order by 1) loop
begin
v_tab:=c1.table_name;
v_row:=0;
execute immediate 'select /*+ parallel(a,8)*/ count(1) from '||v_tab||' a ' int
o v_row;
for c2 in (select index_name,column_name from user_ind_columns
where table_name=v_tab and column_position=1 order by 1) loop
begin
v_ind:=c2.index_name;
v_col:=c2.column_name;
v_cnt:=0;
execute immediate 'select /*+ parallel_index(a, '||v_ind||',8) */ count(distinct
('||v_col||')) from '||v_tab||' a ' into v_cnt;
dbms_output.put_line(v_tab||', '||v_row||', '||v_ind||' ,'||v_col||', '||v_cnt||
', '||round(v_cnt*100/(v_row + .0001),2)||'% ,'||sysdate);
exception
when others then
dbms_output.put_line(v_tab||' '||v_ind||' '||v_col||' '||sqlerrm);

end;
end loop;
exception
when others then
dbms_output.put_line(c1.table_name||' '||sqlerrm);
end;
end loop;
end;
/

http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551378329289980
701
http://mattfleming.com/node/192
http://richardfoote.wordpress.com/2008/05/12/index-scan-or-full-table-scan-the-m
agic-number-magic-dance/

Sign up to vote on this title
UsefulNot useful