【问题标题】:Oracle Execution Plan甲骨文执行计划
【发布时间】:2015-05-07 08:22:13
【问题描述】:

我有以下结构的表 A

create table A {
 id Oracle Execution Plan  primary key,
 value varchar(20)
}

我有以下查询:

select * from a where id in (123) or id in (select 133 from dual);

我得到了这个解释计划:

为什么我们在这里有完整的表访问权限?我的意思是我们正在使用 PK 进行过滤,因此我们知道 PK 已编入索引。此外,我是否将查询更改为

select * from a where id in (123) or id in (55);

我们有以下 exp。计划: 因此,使用子查询我们可以完全访问表,而没有它我们没有。为什么 ?

【问题讨论】:

    标签: sql oracle query-optimization


    【解决方案1】:

    如果您检查 DBMS_Plan 的完整输出,您可能会发现第二个查询已转换为:

    id in (123,55)
    

    ...而第一个查询不是。

    您的表中似乎没有多少数据,而优化器知道这一点,因此索引和全表访问方法之间的成本差异无论如何都非常小。优化器将考虑它认为是 id 列中的最大值和最小值,以及可能还有它们的分布,以确定结果集的可能基数,然后再选择计划。

    您必须非常小心,以确保您处理的是需要优化查询的真实数据集——优化器很难用虚假日期欺骗。

    【讨论】:

      【解决方案2】:

      使用子查询我们可以完全访问表,而没有它我们没有。

      这是因为优化器将 谓词重写OR EXISTS。您可以在 EXPLAIN PLAN 的 filter 中看到相同的内容。

      id in (123) or id in (select 133 from dual)id in (123) or id in (55) 不同,当优化器为查询执行创建最佳计划时。优化器重写谓词中的子查询。

      or id in (select 133 from dual) 改写为 OR EXISTS (SELECT 0 FROM "SYS"."DUAL""DUAL" WHERE :B1=133))

      例如,

      案例#1

      SQL> EXPLAIN PLAN FOR
        2  SELECT * FROM emp WHERE empno = 7369 or empno = 7499;
      
      Explained.
      
      SQL>
      SQL> SELECT * FROM TABLE(dbms_xplan.display);
      
      PLAN_TABLE_OUTPUT
      ----------------------------------------------------------------------------------------
      Plan hash value: 2355049923
      
      ---------------------------------------------------------------------------------------
      | Id  | Operation                    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
      ---------------------------------------------------------------------------------------
      |   0 | SELECT STATEMENT             |        |     2 |    78 |     2   (0)| 00:00:01 |
      |   1 |  INLIST ITERATOR             |        |       |       |            |          |
      |   2 |   TABLE ACCESS BY INDEX ROWID| EMP    |     2 |    78 |     2   (0)| 00:00:01 |
      |*  3 |    INDEX UNIQUE SCAN         | PK_EMP |     2 |       |     1   (0)| 00:00:01 |
      ---------------------------------------------------------------------------------------
      
      
      PLAN_TABLE_OUTPUT
      ----------------------------------------------------------------------------------------
      Predicate Information (identified by operation id):
      ---------------------------------------------------
      
         3 - access("EMPNO"=7369 OR "EMPNO"=7499)
      
      15 rows selected.
      

      案例#2

      SQL> EXPLAIN PLAN FOR
        2  SELECT * FROM emp WHERE empno = 7369 OR empno IN(SELECT 7499 FROM dual);
      
      Explained.
      
      SQL>
      SQL> SELECT * FROM TABLE(dbms_xplan.display);
      
      PLAN_TABLE_OUTPUT
      ----------------------------------------------------------------------------------------
      Plan hash value: 3969125370
      
      ---------------------------------------------------------------------------
      | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
      ---------------------------------------------------------------------------
      |   0 | SELECT STATEMENT   |      |     2 |    78 |     3   (0)| 00:00:01 |
      |*  1 |  FILTER            |      |       |       |            |          |
      |   2 |   TABLE ACCESS FULL| EMP  |    14 |   546 |     3   (0)| 00:00:01 |
      |*  3 |   FILTER           |      |       |       |            |          |
      |   4 |    FAST DUAL       |      |     1 |       |     2   (0)| 00:00:01 |
      ---------------------------------------------------------------------------
      
      PLAN_TABLE_OUTPUT
      ----------------------------------------------------------------------------------------
      
      Predicate Information (identified by operation id):
      ---------------------------------------------------
      
         1 - filter("EMPNO"=7369 OR  EXISTS (SELECT 0 FROM "SYS"."DUAL"
                    "DUAL" WHERE :B1=7499))
         3 - filter(:B1=7499)
      
      18 rows selected.
      

      因此,您会看到查询被重写,过滤器被应用为

      filter("EMPNO"=7369 OR  EXISTS (SELECT 0 FROM "SYS"."DUAL"
                        "DUAL" WHERE :B1=7499))**
      

      现在,让我们执行重写的查询。修改后:

      SQL> EXPLAIN PLAN FOR
        2  SELECT * FROM emp
        3  WHERE EMPNO =7369 OR  EXISTS (SELECT 0 FROM DUAL WHERE :B1=7499);
      
      Explained.
      
      SQL>
      SQL> SELECT * FROM TABLE(dbms_xplan.display);
      
      PLAN_TABLE_OUTPUT
      --------------------------------------------------------------------------
      Plan hash value: 2411523692
      
      --------------------------------------------------------------------------
      | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
      --------------------------------------------------------------------------
      |   0 | SELECT STATEMENT  |      |     2 |    78 |     3   (0)| 00:00:01 |
      |*  1 |  TABLE ACCESS FULL| EMP  |     2 |    78 |     3   (0)| 00:00:01 |
      |*  2 |   FILTER          |      |       |       |            |          |
      |   3 |    FAST DUAL      |      |     1 |       |     2   (0)| 00:00:01 |
      --------------------------------------------------------------------------
      
      
      PLAN_TABLE_OUTPUT
      --------------------------------------------------------------------------
      Predicate Information (identified by operation id):
      ---------------------------------------------------
      
         1 - filter("EMPNO"=7369 OR  EXISTS (SELECT 0 FROM "SYS"."DUAL"
                    "DUAL" WHERE TO_NUMBER(:B1)=7499))
         2 - filter(TO_NUMBER(:B1)=7499)
      
      17 rows selected.
      
      SQL>
      

      因此,您现在可以看到谓词重写和相同的修改查询具有相似的解释计划,并执行 FULL TABLE SCAN

      【讨论】:

        猜你喜欢
        • 2014-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-05
        • 2011-07-19
        相关资源
        最近更新 更多