5

在我们的 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';

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

4

1 回答 1

9

这取决于。

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

EXPLAIN PLAN FOR 
   SELECT * FROM Table_Y WHERE Col_A = 'STACKOVERFLOW';

进而

select * from table(dbms_xplan.display);

所以,例如

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);

然后一个

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

select * from table(dbms_xplan.display);

该计划(在我的安装上)如下所示:

------------------------------------------------------------------------------------------
| 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')

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';

此外,我会确保您已收集有关表及其列的统计信息。您可以使用

select last_analyzed from dba_tables where table_name = 'TABLE_Y';

select column_name, last_analyzed from dba_tab_columns where table_name = 'TABLE_Y';

如果没有统计信息或者它们过时,请让自己熟悉dbms_stats软件包以收集此类统计信息。

这些统计数据是查询优化器在做出决策时严重依赖的数据。

于 2012-08-15T14:43:04.937 回答