为什么oracle选择索引完全扫描,然后是索引ROWID访问,而不是完全表扫描?

为什么oracle选择索引完全扫描,然后是索引ROWID访问,而不是完全表扫描?,oracle,sql-execution-plan,Oracle,Sql Execution Plan,为什么oracle选择索引完全扫描,然后按索引ROWID进行访问,而不是只进行一个完整的表扫描,这是一个步骤,可以做同样的事情,而且可能更快 甲骨文为何选择 | 2 | TABLE ACCESS BY INDEX ROWID | 3 | INDEX FULL SCAN 结束 为了进一步澄清,这是查询和完整执行计划 SELECT EMP_NO, ENAME, SALARY, dname FROM EMP E, DEPT D WHERE E.DEPT_NO=D.DEPT

为什么oracle选择索引完全扫描,然后按索引ROWID进行访问,而不是只进行一个完整的表扫描,这是一个步骤,可以做同样的事情,而且可能更快

甲骨文为何选择

|   2 |   TABLE ACCESS BY INDEX ROWID
|   3 |    INDEX FULL SCAN    
结束

为了进一步澄清,这是查询和完整执行计划

SELECT EMP_NO, ENAME, SALARY, dname 
FROM EMP E, DEPT D
WHERE E.DEPT_NO=D.DEPT_NO;



Execution Plan
----------------------------------------------------------
Plan hash value: 2125045483

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |   879 | 35160 |     8  (13)| 00:00:01 |
|   1 |  MERGE JOIN                  |         |   879 | 35160 |     8  (13)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     7 |    91 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | DEPT_PK |     7 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                  |         |   879 | 23733 |     6  (17)| 00:00:01 |
|   5 |    TABLE ACCESS FULL         | EMP     |   879 | 23733 |     5   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

您会注意到优化器在EMP表上选择了完整的表扫描。然后,它使用键EMP.DEPT_NO在DEPT上查找适当的值,因为在这种情况下,查找879次显然比在DEPT上进行全表扫描并进行879*7比较要快(至少在优化器看来是这样)

为了好玩,您可以通过查看USER_表或DBA_表视图来查看这些表最近的统计数据收集情况:

SELECT TABLE_NAME, LAST_ANALYZED
  FROM USER_TABLES
  WHERE TABLE_NAME IN ('EMP', 'DEPT')
如果你愿意,你可以使用

BEGIN
  DBMS_STATS.GATHER_TABLE_STATISTICS(OWNNAME => 'your_schema_name',
                                     TABNAME => 'EMP',
                                     CASCADE => TRUE);

  DBMS_STATS.GATHER_TABLE_STATISTICS(OWNNAME => 'your_schema_name',
                                     TABNAME => 'DEPT',
                                     CASCADE => TRUE);
END;

通常,表格完整扫描必须读取到表格高水位线(即几乎所有分配给表格的块)。如果表中有一个大的删除,那么表中可能有10000个块,大部分是空的,它必须读取这些块

索引是一种更复杂的结构,但索引完全扫描不必处理空块。此外,索引(因为它们只有列的一个子集)往往更小,并且在缓存中停留的时间更长


在您的示例中,从索引访问索引和表的总成本为3。这相当低,可能表格扫描结果是4或5(也很低,但仍然是第二)

仅当索引部分与条件匹配时,才会读取表数据。根据预期的结果集,这样快吗?您可以再显示一点执行计划吗?索引完全扫描的一个可能优势是它按顺序读取数据,这可以避免排序。查询中是否有ORDER BY?我们不知道您正在运行的查询、访问的表或表中的数据,因此无法回答您的问题。您好,我编辑了问题以澄清,感谢您的评论。没有说明它是“使用EMP.DEPT\u NO键在DEPT上查找适当的值”。这是一个索引完全扫描,没有显示任何筛选器,并且是一个后续合并联接
BEGIN
  DBMS_STATS.GATHER_TABLE_STATISTICS(OWNNAME => 'your_schema_name',
                                     TABNAME => 'EMP',
                                     CASCADE => TRUE);

  DBMS_STATS.GATHER_TABLE_STATISTICS(OWNNAME => 'your_schema_name',
                                     TABNAME => 'DEPT',
                                     CASCADE => TRUE);
END;