甲骨文执行计划

Posted

技术标签:

【中文标题】甲骨文执行计划【英文标题】: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。计划: 因此,使用子查询我们可以完全访问表,而没有它我们没有。为什么 ?

【问题讨论】:

【参考方案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

【讨论】:

以上是关于甲骨文执行计划的主要内容,如果未能解决你的问题,请参考以下文章

Oracle零售计划与优化——全天候数字培训现已推出!

面向客户编程!为满足新业务定位,谷歌云计算实施裁员计划

AWS彻底抛弃Oracle数据库:计划2020年初完成

Oracle执行计划总结

SQL SERVER如何应用执行计划

获取SQL执行计划的常见几种方法