在我们的 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';
会使用索引,还是会进行表扫描?
这取决于。
您可以通过让 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
软件包以收集此类统计信息。
这些统计数据是查询优化器在做出决策时严重依赖的数据。