【问题标题】:Why does oracle chose INDEX FULL SCAN followed by ACCESS BY INDEX ROWID vs FULL TABLE SCAN?为什么 oracle 选择 INDEX FULL SCAN 然后 ACCESS BY INDEX ROWID vs FULL TABLE SCAN?
【发布时间】:2020-04-23 11:02:49
【问题描述】:

为什么 oracle 选择 INDEX FULL SCAN 然后选择 ACCESS BY INDEX ROWID 而不是全表扫描,它是一步完成的,而且可能更快?

为什么选择甲骨文

|   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 |
----------------------------------------------------------------------------------------

【问题讨论】:

  • 只有在索引部分符合条件时才会读取表数据。取决于预期的结果集是不是更快
  • 你能多展示一点执行计划吗? INDEX FULL SCAN 的一个可能优点是它按顺序读取数据,这样可以避免排序。查询中是否有ORDER BY
  • 我们不知道您正在运行什么查询,正在访问哪些表,或者表中有哪些数据,因此无法回答您的问题。
  • 嗨,我已经编辑了问题以澄清,感谢 cmets

标签: oracle sql-execution-plan


【解决方案1】:

通常,表全扫描必须读取到表的高水位线(即几乎所有已分配的块都被表使用)。如果表中有一个大删除,表中可能有 10,000 个块,大部分是空的,它必须通读。

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

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

【讨论】:

    【解决方案2】:

    您会注意到优化器确实在 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;
    

    【讨论】:

    • 没有迹象表明它是“使用键 EMP.DEPT_NO 在 DEPT 上查找适当的值”。这是一个没有指示过滤器的 INDEX FULL SCAN 和一个后续的 MERGE JOIN
    猜你喜欢
    • 2014-12-06
    • 2020-01-12
    • 1970-01-01
    • 2013-06-30
    • 2017-04-06
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多