为什么oracle选择INDEX RANGE SCAN超过快速全指数扫描

Sam*_*rdj 2 oracle indexing range database-scan

我已经阅读了一些关于索引的文档,我做了一些例子,现在我有些疑惑.

我创建一个表并插入随机值,(一列有唯一值)列A NOT NULL我在A,B,C上创建一个索引.(B-TREE)

SELECT COUNT(*) FROM DEMO_FULL_INDEX_SCAN;
=1000
Run Code Online (Sandbox Code Playgroud)
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
...
Run Code Online (Sandbox Code Playgroud)

文档说明当所有查询值都在索引中时,值是从索引(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      |       |       |       |
--------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

我必须指定一个提示优化器选择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 |
--------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

另一方面,这个例子显示了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                |       |       |
--------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

我的问题是,在第一个例子中,为什么Oracle选择INDEX RANGE SCAN而不是FAST FULL INDEX SCAN.

Ben*_*Ben 5

由于SQL语句的WHERE子句,您正在执行INDEX RANGE SCAN:

select a,b,c from demo_full_index_scan where a = 1;
Run Code Online (Sandbox Code Playgroud)

我在这里假设你在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);
Run Code Online (Sandbox Code Playgroud)

由于您没有UNIQUE索引,Oracle无法确切知道A中的值始终是唯一的; 但是,Oracle确实知道A是索引中的第一列,并且可以在索引中可用的值范围内找到此值.

如果你的WHERE子句试图根据列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 |
-------------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)