For related notes on
duplicates, see how to detect
duplicate
table rows. There are
3 ways to
write duplicate row detection queries.
Detecting Oracle
indexes with duplicate columns
Un-used indexes waste
space and have overhead for DML, and there are alternatives to running scripts
to detect
un-used indexes.
One common misconception by developers is that every predicate in a SQL
where clause should be indexed, but this is not true. Because Oracle
supports multi-column indexes, it’s easy to accidently create “duplicate”
indexes, indexes that add overhead to DML and do not aid in speeding-up SQL
execution.
Management commonly hires clandestine experts to review the technical
ability of a DBA. One sure-fire way to get fired is to waste computing
resources by allowing your database to have duplicate indexes!
Now that we understand how important it is to remove duplicate indexes,
let’s look at some common methods for finding indexes that can be safely
dropped without effecting SQL execution.
You can query the dba_ind_columns view to quickly locate indexes
with duplicate columns, but the real challenge comes when you need to decide
which index to drop: This script looks for indexes on tables with the same
leading column, then for indexes with the same two leading columns.
This duplicate index column report provides a good starting point for
trying to reduce redundancy in indexes.
This sophisticated
script to detect Oracle duplicate index columns from my book Oracle
Tuning: The Definitive Reference.
set linesize 150 trimspool on pagesize 80
column index_owner format a20
column column_name format a30
column position format 9
column nextcol format a18 heading "Next Column Match?"
select
a.index_owner,
a.column_name,
a.index_name index_name1,
b.index_name index_name2,
a.column_position position,
(select
'YES'
from
dba_ind_columns x,
dba_ind_columns y
where
x.index_owner = a.index_owner
and
y.index_owner = b.index_owner
and
x.index_name = a.index_name
and
y.index_name = b.index_name
and
x.column_position = 2
and
y.column_position = 2
and
x.column_name = y.column_name) nextcol
from
dba_ind_columns a,
dba_ind_columns b
where
SEE CODE DEPOT
FOR WORKING SCRIPT
a.index_owner not in ('SYS', 'SYSMAN', 'SYSTEM', 'MDSYS', 'WMSYS',
'TSMSYS', 'DBSNMP')
and
a.index_owner = b.index_owner
and
a.column_name = b.column_name
and
a.table_name = b.table_name
and
a.index_name != b.index_name
and
a.column_position = 1
and
b.column_position = 1
/
Here is a sample of the output from this duplicate column detection
script:
INDEX_OWNER COLUMN_NAME INDEX_NAME1 INDEX_NAME2
POS MT
------------
--------------- ---------------------------- --------------------------
--
ROBOHEAD
MARKUP_STATUS IX_ASSET_VERSION_MRKUP_TYPE
IX_ASSET_VERSION_MRKSCLTYPE 1
ROBOHEAD MARKUP_STATUS IX_ASSET_VERSION_MRKSCLTYPE
IX_ASSET_VERSION_MRKUP_TYPE 1
ROBOHEAD ID
PERF1_C_ASSET_VERSION XPKC_ASSET_VERSION
1
ROBOHEAD
ID XPKC_ASSET_VERSION
PERF1_C_ASSET_VERSION 1
ROBOHEAD TASK_ID
CIX_AUDIT_TASKID
CIX_AUDIT_TASK_ID
1
ROBOHEAD
TASK_ID CIX_AUDIT_TASK_ID
CIX_AUDIT_TASKID
1
ROBOHEAD
ID CIX_FOLDER_FID_PRNT
PERF1_C_FOLDER
1 YES
ROBOHEAD
ID CIX_FOLDER_FID_PRNT
XPKC_FOLDER
1
ROBOHEAD
ID PERF1_C_FOLDER
CIX_FOLDER_FID_PRNT 1 YES
As we see, this query locates indexes with the same leading column and
for indexes with the same two leading columns.
While this query does not provide every possible duplicate column, it
does give you the general idea on how to locate redundant index columns and
it serves as a good starting point for identifying index redundancy.
Here is another
sophisticated script to detect duplicate index columns by
Younes Naguib. He claims that his script will locate all Oracle
indexes with duplicate columns.
select /*+ rule */
a.table_owner,
a.table_name,
a.index_owner,
a.index_name,
column_name_list,
column_name_list_dup,
dup duplicate_indexes,
i.uniqueness,
i.partitioned,
i.leaf_blocks,
i.distinct_keys,
i.num_rows,
i.clustering_factor
from
(
select
table_owner,
table_name,
index_owner,
index_name,
column_name_list_dup,
dup,
max(dup) OVER
(partition by
table_owner, table_name, index_name) dup_mx
from
(
select
table_owner,
table_name,
index_owner,
index_name,
substr(SYS_CONNECT_BY_PATH(column_name, ','),2)
column_name_list_dup,
dup
from
(
select
index_owner,
index_name,
table_owner,
table_name,
column_name,
count(1) OVER
(partition by
index_owner,
index_name) cnt,
ROW_NUMBER () OVER
(partition by
index_owner,
index_name
order by column_position) as seq,
count(1) OVER
(partition by
table_owner,
table_name,
column_name,
column_position) as dup
from
sys.dba_ind_columns
where
index_owner not in ('SYS', 'SYSTEM','DLOBAUGH'))
where
dup!=1
start with seq=1
connect by prior seq+1=seq
and prior
index_owner=index_owner
and prior index_name=index_name
)) a,
(
select
table_owner,
table_name,
index_owner,
index_name,
substr(SYS_CONNECT_BY_PATH(column_name,
','),2) column_name_list
from
(
select index_owner, index_name,
table_owner, table_name, column_name,
count(1) OVER ( partition by
index_owner, index_name) cnt,
ROW_NUMBER () OVER ( partition by
index_owner, index_name order by column_position) as seq
from
sys.dba_ind_columns
where index_owner not in ('SYS', 'SYSTEM'))
where seq=cnt
start with seq=1
connect by prior seq+1=seq
and
prior index_owner=index_owner
and prior index_name=index_name
) b,
dba_indexes i
where
a.dup=a.dup_mx
and
a.index_owner=b.index_owner
and a.index_name=b.index_name
and
a.index_owner=i.owner
and a.index_name=i.index_name
order by
a.table_owner, a.table_name, column_name_list_dup;
Here is his duplicate index column report:
INDEX_OWNER
INDEX_NAME
COLUMN_NAME_LIST
COLUMN_NAME_LIST_DUP
DUPLICATE_INDEXES
--------------- ------------------------------
--------------------------------------------------
------------------------------ -----------------
ROBOHEAD
PERF1_C_ASSET_VERSION
ID,ACTIVE,ASSET_ID,LAST_MODIFY_ID
ID
2
ROBOHEAD
XPKC_ASSET_VERSION
ID
ID
2
ROBOHEAD
IX_ASSET_VERSION_MRKUP_TYPE
MARKUP_STATUS,ASSET_TYPE
MARKUP_STATUS
2
ROBOHEAD
IX_ASSET_VERSION_MRKSCLTYPE
MARKUP_STATUS,SCALE_STATUS,ASSET_TYPE
MARKUP_STATUS
2
ROBOHEAD
CIX_AUDIT_ITEMID
ITEM_ID,ACTION
ITEM_ID,ACTION
6
ROBOHEAD
CIX_AUDIT_LIBFILEID
LIBRARY_FILE_ID,ACTION
LIBRARY_FILE_ID,ACTION
6
ROBOHEAD
CIX_AUDIT_NOTESID
NOTES_ID,ACTION
NOTES_ID,ACTION
6
ROBOHEAD
CIX_AUDIT_POSTID
POSTING_ID,ACTION
POSTING_ID,ACTION
6
ROBOHEAD
CIX_AUDIT_TASK_ID
TASK_ID
TASK_ID
2
ROBOHEAD
CIX_AUDIT_TASKID
TASK_ID,ACTION
TASK_ID,ACTION
6