Oracle SQL谓词推进、视图合并
来源:互联网 发布:图形旋转矩阵 编辑:程序博客网 时间:2024/05/16 01:42
Oracle的查询优化器在评估sql的执行计划成本之前,会对有些sql做等价改写,这个等价指的是语义上是等价的,但是sql结构发生变化。常见的改写包括:
谓词推进(predicate push)
查询重写(query rewrite)
谓词推进
PUSH_PRED
NO_PUSH_PRED
视图合并
MERGE
NO_STAR_TRANSFORMATION
查询重写
REWRITE
这是我们最直观能理解的执行计划,
v是一个内联视图,e是一个表。
第1步:
e表的列employee_id列上有索引,所以从执行计划的行2-3可以看出是通过索引定位到数据。得到 结果集1
第2步:
v这个内联视图的数据通过对表EMPLOYEES进行一次全表扫描获取。执行计划行4-5。得到 结果集2
第3步:
结果集1 和 结果集2 进行循环嵌套连接,得到最终结果
视图合并指的是,在与视图做join的时候,不是先将视图计算出结果,再与其他表或者视图join,而是将视图展开,外部的表等可以直接和视图内部的表发生join的情况。 我们看下这次的执行计划:
第1步:
e表的列employee_id列上有索引,所以从执行计划的行2-3可以看出是通过索引定位到数据。得到 结果集1
第2步:
这次直接对EMPLOYEES表上的索引EMP_MANAGER_IX做了个范围扫描RANGE SCAN,可见优化器发现了视图v的底层表就是EMPLOYEES,而关联字段为manager_id,当然,只需要访问索引就能获取这些信息,得到 结果集2,不需要对表做全表扫描了,可见优化器不再将视图v看做一个黑盒子,而是深入视图内部去寻找更加高效的执行计划,将外部的表和视图进行了合并,融合到了一起。
第3步:
结果集1 和 结果集2 进行循环嵌套连接,得到最终结果
谓词推进指的是视图在与表等做join时,比如有1个关联字段,表在这个关联字段上有谓词过滤,那么这个谓词会被传递、推进到视图里面。
我们看下这次的执行计划:
第1步:
e表的列employee_id列上有索引,所以从执行计划的行2-3可以看出是通过索引定位到数据。得到 结果集1
第2步:
我们用no_merge(v)这个hint禁用了视图合并,所以优化器会将视图v当做一个黑盒子,但是会发现即使这样,还是和第1个执行计划不一样,并没有对表EMPLOYEES做全表扫描,而是直接访问EMP_MANAGER_IX索引,而且在索引上了做了谓词过滤,执行计划第5行,这个就是谓词推进的结果,最终得到 结果集2。最明显的区别是,第1次的执行计划,视图v这个黑盒子返回的结果107行数据,可以看执行计划的rows列,而这次是6行。
第3步:
结果集1 和 结果集2 进行循环嵌套连接,得到最终结果
从第2、3两种情况我们得知,不管是谓词推进或是视图合并,都会让视图v不走全表扫描,
视图合并会发生EMP_MANAGER_IX索引的 FULL SCAN
谓词推进会发生EMP_MANAGER_IX索引的 RANGE SCAN
谓词推进(predicate push)
视图合并(view merge)
子查询展开(subquery unnest)
查询重写(query rewrite)
这次我们来看下其中最常见的两种:谓词推进和视图合并。
谓词推进
PUSH_PRED
NO_PUSH_PRED
视图合并
MERGE
NO_MERGE
子查询展开
UNNEST
NO_UNNEST
星型转换
STAR_TRANSFORMATIONNO_STAR_TRANSFORMATION
查询重写
REWRITE
NO_REWRITE
基础数据准备
[oracle@sean ~]$ sqlplus hr/hrSQL*Plus: Release 11.2.0.4.0 Production on Fri Jul 7 14:48:47 2017Copyright (c) 1982, 2013, Oracle. All rights reserved.Connected to:Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit ProductionWith the Partitioning, OLAP, Data Mining and Real Application Testing optionsHR@sean> desc employees Name Null? Type ----------------------------------------- -------- ---------------------------- EMPLOYEE_ID NOT NULL NUMBER(6) FIRST_NAME VARCHAR2(20) LAST_NAME NOT NULL VARCHAR2(25) EMAIL NOT NULL VARCHAR2(25) PHONE_NUMBER VARCHAR2(20) HIRE_DATE NOT NULL DATE JOB_ID NOT NULL VARCHAR2(10) SALARY NUMBER(8,2) COMMISSION_PCT NUMBER(2,2) MANAGER_ID NUMBER(6) DEPARTMENT_ID NUMBER(4)HR@sean> select EMPLOYEE_ID,FIRST_NAME,LAST_NAME,MANAGER_ID from employees where rownum<10;EMPLOYEE_ID FIRST_NAME LAST_NAME MANAGER_ID----------- -------------------- ------------------------- ---------- 198 Donald OConnell 124 199 Douglas Grant 124 200 Jennifer Whalen 101 201 Michael Hartstein 100 202 Pat Fay 201 203 Susan Mavris 101 204 Hermann Baer 101 205 Shelley Higgins 101 206 William Gietz 2059 rows selected.HR@sean> select INDEX_NAME,TABLE_NAME,COLUMN_NAME from user_ind_columns where table_name='EMPLOYEES';INDEX_NAME TABLE_NAME COLUMN_NAME-------------------- ------------------------------ --------------------EMP_DEPARTMENT_IX EMPLOYEES DEPARTMENT_IDEMP_NAME_IX EMPLOYEES LAST_NAMEEMP_NAME_IX EMPLOYEES FIRST_NAMEEMP_MANAGER_IX EMPLOYEES MANAGER_IDEMP_EMP_ID_PK EMPLOYEES EMPLOYEE_IDEMP_EMAIL_UK EMPLOYEES EMAILEMP_JOB_IX EMPLOYEES JOB_ID7 rows selected.
1. 无视图合并 + 无谓词推进,成本cost=3
HR@sean> set autotrace traceonly expHR@sean> select /*+ no_merge(v) no_push_pred(v) */ * from employees e, (select manager_id from employees) v where e.manager_id = v.manager_id(+) and e.employee_id = 100;Execution Plan----------------------------------------------------------Plan hash value: 1940769814----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 6 | 492 | 3 (0)| 00:00:01 || 1 | NESTED LOOPS OUTER | | 6 | 492 | 3 (0)| 00:00:01 || 2 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 ||* 3 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 ||* 4 | VIEW | | 6 | 78 | 2 (0)| 00:00:01 || 5 | TABLE ACCESS FULL | EMPLOYEES | 107 | 428 | 2 (0)| 00:00:01 |----------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 3 - access("E"."EMPLOYEE_ID"=100) 4 - filter("E"."MANAGER_ID"="V"."MANAGER_ID"(+))
这是我们最直观能理解的执行计划,
v是一个内联视图,e是一个表。
第1步:
e表的列employee_id列上有索引,所以从执行计划的行2-3可以看出是通过索引定位到数据。得到 结果集1
第2步:
v这个内联视图的数据通过对表EMPLOYEES进行一次全表扫描获取。执行计划行4-5。得到 结果集2
第3步:
结果集1 和 结果集2 进行循环嵌套连接,得到最终结果
2. 视图合并 + 无谓词推进,成本cost=3
HR@sean> select /*+ no_push_pred(v) use_merge(v) */ 2 * 3 from employees e, (select manager_id from employees) v 4 where e.manager_id = v.manager_id(+) 5 and e.employee_id = 100; Execution Plan----------------------------------------------------------Plan hash value: 3306627101-----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 6 | 438 | 3 (34)| 00:00:01 || 1 | MERGE JOIN OUTER | | 6 | 438 | 3 (34)| 00:00:01 || 2 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 ||* 3 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 ||* 4 | FILTER | | | | | || 5 | INDEX FULL SCAN | EMP_MANAGER_IX | 107 | 428 | 1 (0)| 00:00:01 |-----------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 3 - access("E"."EMPLOYEE_ID"=100) 4 - filter("E"."MANAGER_ID"="MANAGER_ID"(+))
视图合并指的是,在与视图做join的时候,不是先将视图计算出结果,再与其他表或者视图join,而是将视图展开,外部的表等可以直接和视图内部的表发生join的情况。 我们看下这次的执行计划:
第1步:
e表的列employee_id列上有索引,所以从执行计划的行2-3可以看出是通过索引定位到数据。得到 结果集1
第2步:
这次直接对EMPLOYEES表上的索引EMP_MANAGER_IX做了个范围扫描RANGE SCAN,可见优化器发现了视图v的底层表就是EMPLOYEES,而关联字段为manager_id,当然,只需要访问索引就能获取这些信息,得到 结果集2,不需要对表做全表扫描了,可见优化器不再将视图v看做一个黑盒子,而是深入视图内部去寻找更加高效的执行计划,将外部的表和视图进行了合并,融合到了一起。
第3步:
结果集1 和 结果集2 进行循环嵌套连接,得到最终结果
3. 无视图合并 + 谓词推进,成本cost=2
HR@sean> select /*+ no_merge(v) push_pred(v) */ * from employees e, (select manager_id from employees) v where e.manager_id = v.manager_id(+) and e.employee_id = 100;Execution Plan----------------------------------------------------------Plan hash value: 4259233738-----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 6 | 492 | 2 (0)| 00:00:01 || 1 | NESTED LOOPS OUTER | | 6 | 492 | 2 (0)| 00:00:01 || 2 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 ||* 3 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 || 4 | VIEW PUSHED PREDICATE | | 1 | 13 | 1 (0)| 00:00:01 ||* 5 | INDEX RANGE SCAN | EMP_MANAGER_IX | 6 | 24 | 1 (0)| 00:00:01 |-----------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 3 - access("E"."EMPLOYEE_ID"=100) 5 - access("MANAGER_ID"="E"."MANAGER_ID")
谓词推进指的是视图在与表等做join时,比如有1个关联字段,表在这个关联字段上有谓词过滤,那么这个谓词会被传递、推进到视图里面。
我们看下这次的执行计划:
第1步:
e表的列employee_id列上有索引,所以从执行计划的行2-3可以看出是通过索引定位到数据。得到 结果集1
第2步:
我们用no_merge(v)这个hint禁用了视图合并,所以优化器会将视图v当做一个黑盒子,但是会发现即使这样,还是和第1个执行计划不一样,并没有对表EMPLOYEES做全表扫描,而是直接访问EMP_MANAGER_IX索引,而且在索引上了做了谓词过滤,执行计划第5行,这个就是谓词推进的结果,最终得到 结果集2。最明显的区别是,第1次的执行计划,视图v这个黑盒子返回的结果107行数据,可以看执行计划的rows列,而这次是6行。
第3步:
结果集1 和 结果集2 进行循环嵌套连接,得到最终结果
4. 视图合并 + 谓词推进,成本cost=1
HR@sean> select /*+ merge(v) push_pred(v) */ 2 * 3 from employees e, (select manager_id from employees) v 4 where e.manager_id = v.manager_id(+) 5 and e.employee_id = 100;Execution Plan----------------------------------------------------------Plan hash value: 3100588360-----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 6 | 438 | 1 (0)| 00:00:01 || 1 | NESTED LOOPS OUTER | | 6 | 438 | 1 (0)| 00:00:01 || 2 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 ||* 3 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 ||* 4 | INDEX RANGE SCAN | EMP_MANAGER_IX | 6 | 24 | 0 (0)| 00:00:01 |-----------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 3 - access("E"."EMPLOYEE_ID"=100) 4 - access("E"."MANAGER_ID"="MANAGER_ID"(+))
5. 默认情况,成本cost=1
HR@sean> select * from employees e, (select manager_id from employees) v where e.manager_id = v.manager_id(+) and e.employee_id = 100;Execution Plan----------------------------------------------------------Plan hash value: 3100588360-----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 6 | 438 | 1 (0)| 00:00:01 || 1 | NESTED LOOPS OUTER | | 6 | 438 | 1 (0)| 00:00:01 || 2 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 ||* 3 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 ||* 4 | INDEX RANGE SCAN | EMP_MANAGER_IX | 6 | 24 | 0 (0)| 00:00:01 |-----------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 3 - access("E"."EMPLOYEE_ID"=100) 4 - access("E"."MANAGER_ID"="MANAGER_ID"(+))
从第2、3两种情况我们得知,不管是谓词推进或是视图合并,都会让视图v不走全表扫描,
视图合并会发生EMP_MANAGER_IX索引的 FULL SCAN
谓词推进会发生EMP_MANAGER_IX索引的 RANGE SCAN
阅读全文
1 0
- Oracle SQL谓词推进、视图合并
- oracle谓词推进测试
- 视图合并和谓词推入
- Oracle 使用with要小心了--谓词不能推进
- 谓词推进的测试
- SQL查询---联接---嵌套---计算---分类汇总---量词---谓词---合并
- SQL优化--逻辑优化--视图重写与等价谓词重写
- sql 谓词
- oracle sql分组合并
- 《基于ORACLE的SQL优化读书》笔记 子查询展开/视图合并
- Oracle 内联视图优化,视图合并的抉择
- Oracle谓词推入
- ORACLE 行转列谓词推入
- SQL中的谓词
- ORACLE V$SQL视图说明
- sql ORACLE(七):视图、序列
- ORACLE V$SQL视图说明
- oracle--sql---约束--视图--索引
- 开发团队必备的现代前端开发指南
- Redis使用守护进程启动sentinel并指定其日志目录
- mysql表结构导出成Excel格式带备注
- Linux 基础命令 及 jdk,mysql,tomcat的安装
- Gson解析JSON中动态未知字段key的方法
- Oracle SQL谓词推进、视图合并
- 代理模式
- 编译hadoop2.8.0
- 深入理解RESTful
- 了解Mysql分区
- 正则表达式
- 完成端口IOCP详解
- C++日志库_spdlog
- Python 学习 第二天