为什么oracle为什么选择INDEX FULL SCAN,然后选择ACCESS BY INDEX ROWID,而不是只进行一个步骤的全表扫描,并且做同样的事情并且可能更快?
Oracle为什么选择
| 2 | TABLE ACCESS BY INDEX ROWID
| 3 | INDEX FULL SCAN
超过
| 2 | TABLE ACCESS FULL|
为了进一步说明,这是查询和完整的执行计划
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 |
----------------------------------------------------------------------------------------
您会注意到优化器does在EMP表上选择了FULL TABLE SCAN。然后,它使用键EMP.DEPT_NO在DEPT上查找适当的值,因为在这种情况下,执行879次查找显然比在DEPT上执行FULL TABLE SCAN进行查找更快(至少在优化程序看来),而执行879 * 7个比较。
为了有趣,您可以通过查看USER_TABLES或DBA_TABLES视图来查看最近如何收集这些表的统计信息:
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;
通常,表全扫描必须读取到表的高水位线(即,几乎每个表所分配的块都已被表使用)。如果从表中删除了很多内容,则表中可能有10,000个块,其中大部分是空的,必须将其读取。