甲骨文执行计划
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。
【讨论】:
以上是关于甲骨文执行计划的主要内容,如果未能解决你的问题,请参考以下文章