具有多列的Oracle索引在单列上查询

Ray*_*sen 5 oracle indexing

在我们的Oracle安装的表中,我们有一个表,其中包含两个列(X和Y)的索引.如果我使用where子句仅对表X进行查询,那么Oracle是否能够使用索引?

例如:

表Y:Col_A,Col_B,Col_C,

索引存在于(Col_A,Col_B)

SELECT * FROM Table_Y WHERE Col_A = 'STACKOVERFLOW';
Run Code Online (Sandbox Code Playgroud)

是否会使用索引,还是会进行表扫描?

Ren*_*ger 9

这取决于.

您可以通过让Oracle解释执行计划来检查它:

EXPLAIN PLAN FOR 
   SELECT * FROM Table_Y WHERE Col_A = 'STACKOVERFLOW';
Run Code Online (Sandbox Code Playgroud)

然后

select * from table(dbms_xplan.display);
Run Code Online (Sandbox Code Playgroud)

所以,举例来说

create table table_y (
  col_a varchar2(30),
  col_b varchar2(30),
  col_c varchar2(30)
);

create unique index table_y_ix on table_y (col_a, col_b);
Run Code Online (Sandbox Code Playgroud)

然后一个

explain plan for
  select * from table_y
  where col_a = 'STACKOVERFLOW';

select * from table(dbms_xplan.display);
Run Code Online (Sandbox Code Playgroud)

计划(在我的安装上)看起来像:

------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |     1 |    51 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TABLE_Y    |     1 |    51 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | TABLE_Y_IX |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("COL_A"='STACKOVERFLOW')
Run Code Online (Sandbox Code Playgroud)

ID 2向您显示该索引TABLE_Y_IX确实用于index range scan.

如果在另一个安装上,Oracle选择使用索引依赖很多东西.这是Oracle的查询优化器做出这个决定.

更新如果你觉得自己变得更好(性能明智,那就是)如果Oracle使用了索引,你可能想尝试一下+ index_asc(...)(参见 索引提示)

所以在你的情况下会是这样的

SELECT /*+ index_asc(TABLE_Y TABLE_Y_IX) */ * 
  FROM Table_Y 
 WHERE Col_A = 'STACKOVERFLOW';
Run Code Online (Sandbox Code Playgroud)

另外,我会确保您收集了表及其列的统计信息.您可以使用a检查上次收集统计信息的日期

select last_analyzed from dba_tables where table_name = 'TABLE_Y';
Run Code Online (Sandbox Code Playgroud)

select column_name, last_analyzed from dba_tab_columns where table_name = 'TABLE_Y';
Run Code Online (Sandbox Code Playgroud)

如果没有统计数据或者它们是陈旧的,请熟悉该dbms_stats程序包以收集此类统计信息.

这些统计信息是查询优化器严重依赖的数据来做出决策.