Oracle composite index column ordering

转载 2013年12月05日 15:14:26

Question:  I have a SQL with multiple columns in my where clause.  I know that Oracle can only choose one index, and I know about multi-column composite indexes, but I do not know how to determine the optimal column order for a composite index with multiple column values.  What is the secret for creating a composite index with the columns in the proper sequence?

Answer: You are correct that the column sequence matters!  This is an empirical question, and you need to run diagnostic scripts against your SQL workload (STATSPACK or AWR) to examine how frequently a specific index column was needed by SQL.  Remember, it's the SQL workload that drives your choice of composite indexes, and the order of the columns within the index.

See these important scripts to display multi-column index usage using AWR.

  • In general, when using a multi-column index, you want to put the most restrictive column value first (the column with the highest unique values) because this will trim-down the result set.
  • Because Oracle can only access one index, your job is to examine your historical SQL workload and build a single composite index that satisfies the majority of the SQL queries.
  • The Oracle optimizer may try to make single column  indexes behave as-if they were a single composite index.  Prior to 10g, this could be done with the "and_equal" hint.
  • Beware that indexes have overhead and see my notes on detecting duplicate index columns. 
  • You can run scripts to monitor the invocation count for each column in a multiple column composite index (see counting column usage from a SQL workload) 

I have more complete details on composite index usage monitoring in my bookAdvanced Oracle SQL Tuning: The Definitive Reference.  Also, see my related notes on tuning with composite bitmap indexes and my scripts to monitor which columns of a composite index are used, and counting index column usage from AWR and STATSPACK.   

Large Multi-column Composite Indexes

Multi-column indexes with more than 3 columns may not provide more efficient access than a two-column index.  The objective of the index is to reduce the amount of rows returned from a table access.  Therefore each added column must substantially reduce the number of returned rows to be effective.  For example, assuming a large table, on a query with 5 or more WHERE (AND) clauses using a 5-column index may return only 1 row.  However using a 3-column index may return only 50 rows.  A two-column index returns 200 rows.  The time it takes to extract the one row from the 200 rows using nested-loops is negligible. 

Thus the two-column index may be almost as efficient (fast) as the 5-column index.  The key is to index the most restrictive columns.  Another tradeoff is a table with multiple column indexes where the leading column(s) are the same.  For instance, a table with four 3-column indexes where the leading two columns are the same may work very efficiently on select statements but cause a heavy penalty on inserts and updates.  Just one 2-column index on the leading two columns may provide acceptable query performance while greatly improving DML.

Small tables with two or three columns may benefit by being rebuilt as an Index Organized Table (IOT).  A 2-column table with a primary key and a two-column index has 1.5 times the data in indexes that are in the table.  Making the table an Index Organized Table reduced the need for indexes because the table is the index.  Also IOTs can have indexes on non-leading columns if required.   Again this has to be balanced with the overhead of maintaining the IOT.

Lastly, do not be afraid to use temporary indexes.  If you run a nightly report that requires 6 hours to run, but will run in 30 mins with a specific index, you might want to create the index before running the report and drop it upon completion.  I work with clients that drop certain indexes to expedite the bill run, then recreate then for the normal application.  They create indexes each night and drop them in the morning.  There is nothing wrong with dynamically changing you database to respond to varying tasks if it results in efficiency.


Script for tracking composite index column usage

These scripts will only track SQL that you have directed Oracle to capture via your threshold settings in AWR or STATSPACK. STATSPACK and AWR will not collect "transient SQL" that did not appear in v$sql at snapshot time.  Hence, not all SQL will appear in these reports.  See my notes here on adjusting the SQL capture thresholds.


col c1 heading ‘Begin|Interval|time’ format a20
col c2 heading ‘Search Columns’      format 999
col c3 heading ‘Invocation|Count’    format 99,999,999
break on c1 skip 2
accept idxname char prompt ‘Enter Index Name: ‘
ttitle ‘Invocation Counts for index|&idxname’
   to_char(sn.begin_interval_time,'yy-mm-dd hh24')  c1,
   p.search_columns                                 c2,
   count(*)                                         c3
   dba_hist_snapshot  sn,
   dba_hist_sql_plan   p,
   dba_hist_sqlstat   st
   st.sql_id = p.sql_id
   sn.snap_id = st.snap_id   
   p.object_name = ‘&idxname'
group by

The query will produce an output showing a summary count of the index specified during the snapshot interval. This can be compared to the number of times that a table was invoked from SQL.  Here is a sample of the output from the script.

Invocation Counts for cust_index
Interval                             Invocation
time                 Search Columns       Count
-------------------- -------------- -----------
04-10-21 15                       1           3
04-10-10 16                       0           1
04-10-10 19                       1           1
04-10-11 02                       0           2
04-10-11 04                       2           1
04-10-11 06                       3           1
04-10-11 11                       0           1
04-10-11 12                       0           2
04-10-11 13                       2           1
04-10-11 15                       0           3
04-10-11 17                       0          14
04-10-11 18                       4           1
04-10-11 19                       0           1
04-10-11 20                       3           7
04-10-11 21                       0           1

For more complete details on creating a custom composite index monitoring infrastructure, see my latest book Advanced Oracle SQL Tuning: The Definitive Reference.

深入理解Oracle索引(14):Composite Index 两大原理解析

声明:虽然题目是Oracle、但同样适合MySQL InnoDB索引          在大多数情况下、复合索引比单字段索引好     很多系统就是靠新建一些合适的复合索引、使效率大幅度提高     ...
  • linwaterbin
  • linwaterbin
  • 2013年05月21日 12:35
  • 3062

java.sql.Exception invalid column index - ORA-17003

对于这个问题又废了我几个小时,我不把它写下简直对不起老板的money。 又是一个老革命碰到新问题了,这是什么问题?问得好,不就是问号和参数的个数一致嘛,靠。看来晚上写代码是一件危险的事,容易犯错而且进...
  • onlyme
  • onlyme
  • 2006年02月15日 11:30
  • 6992

[Index]组合索引(Composite Index)中多个字段的顺序

一个表中有三个字段,XX,YY,ZZ,如果要建立给这三个字段建组合索引(Composite Index),组合索引中字段的顺序应该遵循怎样一个原则。一般的原则:越离散的字段越靠前。哪个列可以降低索引的...
  • pan_tian
  • pan_tian
  • 2012年12月10日 19:08
  • 8777

表结构变更后出现的ERROR OGG-01161 Bad column index (88)

表结构变更后出现的ERROR OGG-01161 Bad column index (88)
  • f88520402
  • f88520402
  • 2014年07月31日 17:20
  • 2180

hibernate中关于null index column for collection的异常

最近在hibernate级联查询中,抛出这个错误  后来调查半天  原因如下 主表级联明细表的时候  明细表中有个line_no的字段   主表配置如下   ...
  • qw222pzx
  • qw222pzx
  • 2016年03月18日 16:55
  • 1234

java.sql.SQLException: Column Index out of range, 2 > 1.

case1:由于遍历查询结果时,下标是从“1”开始,而不是是从“0”开始,导致出错 case2:public class infoDAO { public ResultSet r...
  • qq_35503293
  • qq_35503293
  • 2017年03月17日 16:47
  • 1995


最近在频繁使用POI生成各种Excel文档,在体验方便的同时也遇到了些问题。 现在使用的仍然是生成Excel2003的Excel文件,由于03对行数(65535)和列数(255)有限制,所以当数据超...
  • mynameiscloud
  • mynameiscloud
  • 2012年03月29日 10:29
  • 7348

Caused by: java.sql.SQLException: Invalid column index

执行的sql正确却报 Invalid column index 错误 仔细检查下发现时问号或参数相互之间不对应造成的...
  • sprita1
  • sprita1
  • 2012年12月25日 03:37
  • 9115

求助: 用list配置双向一对多的关系, list-index 在数据库里是Null

 OtmsStaple表,为一方。 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "
  • jiafugui
  • jiafugui
  • 2009年07月10日 11:56
  • 4703

java.sql.SQLException:Column Index out of range,0<1

1、错误描述 java.sql.SQLException:Column Index out of range,0 2、错误原因 try { Class.forName("com....
  • you23hai45
  • you23hai45
  • 2015年02月11日 21:36
  • 8256
您举报文章:Oracle composite index column ordering