我已经阅读了一些关于索引的文档,我做了一些例子,现在我有些疑惑。
我创建一个表并插入随机值,(一列具有唯一值)列A NOT NULL 我在A,B,C上创建了一个索引。(B-TREE)
SELECT COUNT(*) FROM DEMO_FULL_INDEX_SCAN;
=1000
SELECT * FROM DEMO_FULL_INDEX_SCAN;
A B C D E F
---------- ---------- ---------- ---------- ---------- ----------
1 7 109 1 1 1
2 12 83 2 2 2
3 21 120 3 3 3
4 13 74 4 4 4
5 2 1 5 5 5
...
文档说当所有查询值都在索引中时,这些值是从索引(INDEX FAST FULL SCAN)收集的,但是优化器正在选择另一个操作。
EXPLAIN PLAN FOR
SELECT A,B,C FROM DEMO_FULL_INDEX_SCAN WHERE A = 1;
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
|* 1 | INDEX RANGE SCAN | FIS_01 | | | |
--------------------------------------------------------------------
我必须指定一个提示优化器选择INDEX FAST FULL SCAN(但我不知道为什么我必须指定它)
EXPLAIN PLAN FOR
SELECT /*+ INDEX_FFS(DEMO_FULL_INDEX_SCAN FIS_01) */A,B,C FROM DEMO_FULL_INDEX_SCAN WHERE A = 1;
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 2 |
|* 1 | INDEX FAST FULL SCAN| FIS_01 | 1 | 11 | 2 |
--------------------------------------------------------------------
另一方面,这个例子显示了oracle文档所说的内容。 当查询中的值不在索引中时,TABLE ACCESS BY INDEX ROWID
访问此值EXPLAIN PLAN FOR
SELECT D FROM DEMO_FULL_INDEX_SCAN WHERE A = 800;
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Co
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |
| 1 | TABLE ACCESS BY INDEX ROWID| DEMO_FULL_INDEX_SCAN | | |
|* 2 | INDEX RANGE SCAN | FIS_01 | | |
--------------------------------------------------------------------------------
我的问题是,在第一个例子中,为什么Oracle选择INDEX RANGE SCAN而不是FAST FULL INDEX SCAN。
答案 0 :(得分:5)
由于SQL语句的WHERE子句,您正在执行INDEX RANGE SCAN:
select a,b,c from demo_full_index_scan where a = 1;
我假设你在A上没有唯一的索引,尽管列的唯一性,即你的表DDL是这样的:
create table demo_full_index_scan (
a number
, b number
, c number
, d number
);
create index i_demo_full_index_scan on demo_full_index_scan (a, b, c);
由于您没有UNIQUE索引,Oracle无法确切知道A中的值始终是唯一的;但是,Oracle确实知道A是索引中的第一列,并且可以在索引中可用的值范围内找到此值。
如果您的WHERE子句要尝试基于C列进行过滤,那么您将在索引中存在C时执行INDEX FULL SCAN,因此您不需要访问该表,但它不是第一列指数:
explain plan for select a,b,c from demo_full_index_scan where c = 1;
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 1 (0)| 00:00:01 |
|* 1 | INDEX FULL SCAN | I_DEMO_FULL_INDEX_SCAN | 1 | 39 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------