Oracle之SQL优化专题03-如何看懂SQL的执行计划
专题第一篇《Oracle之SQL优化专题01-查看SQL执行计划的方法》讲到了查看SQL执行计划的方法,并介绍了各种方法的应用场景,那么这一篇就主要介绍下如何看懂SQL的执行计划。毕竟如果SQL的执行计划都看不懂,那优化就无从谈起了。
关于如何看懂SQL的执行计划,我把它简单分为3个部分:
1.判断执行计划的执行顺序
**口诀:**先子后父,先上后下。
一般简单的执行计划可以直接根据这个口诀来判断执行计划的执行顺序。类似的口诀还有"最右最上"之类,其表达的意思都是一样的,选择一种自己易接受的口诀记忆即可。
举一个简单的例子:
SQL> show user
USER is "SYS"
SQL> alter session set current_schema=scott;
SQL> alter session set statistics_level = ALL;
SQL> select a.empno, a.ename, b.dname, a.job, a.sal from emp a, dept b
2 where a.deptno = b.deptno and empno = 7788
3 ;
EMPNO ENAME DNAME JOB SAL
---------- ---------- -------------- --------- ----------
7788 SCOTT RESEARCH ANALYST 3000
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 19ktq5t44xsyp, child number 0
-------------------------------------
select a.empno, a.ename, b.dname, a.job, a.sal from emp a, dept b where
a.deptno = b.deptno and empno = 7788
Plan hash value: 2385808155
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 4 |
| 1 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 4 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 3 | INDEX UNIQUE SCAN | PK_EMP | 1 | 1 | 1 |00:00:00.01 | 1 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 5 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 1 | 1 |00:00:00.01 | 1 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPNO"=7788)
5 - access("A"."DEPTNO"="B"."DEPTNO")
24 rows selected.
执行计划的执行顺序(按Id区分)就是 3 -> 2 -> 5 -> 4 -> 1 -> 0.
这里需要特别注意的是:
1)实际上这个所谓的口诀得到的执行顺序只是为了方便我们理解操作数据的顺序,而执行计划其实是按照Id从上往下递归调用的,简单说其实优化器首先判断是一条select语句,涉及多表关联,关联方式采用了NL Join,然后这个NL Join包含分别对EMP和DEPT索引回表的访问。
2)理解了第一点,那对于SQL语句中select部分含有标量子查询的部分不遵循这个口诀就更好理解了(因为实际这个标量子查询是最后执行的)。
举一个简单例子说明这类标量子查询:
SQL> select a.empno, a.ename, b.dname, a.job, a.sal, (select * from dual) x from emp a, dept b
2 where a.deptno = b.deptno and empno = 7788
3 ;
EMPNO ENAME DNAME JOB SAL X
---------- ---------- -------------- --------- ---------- -
7788 SCOTT RESEARCH ANALYST 3000 X
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID dpbagkc0c6ctv, child number 0
-------------------------------------
select a.empno, a.ename, b.dname, a.job, a.sal, (select * from dual) x
from emp a, dept b where a.deptno = b.deptno and empno = 7788
Plan hash value: 1121436124
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 4 |
| 1 | TABLE ACCESS FULL | DUAL | 1 | 1 | 1 |00:00:00.01 | 2 |
| 2 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 4 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 4 | INDEX UNIQUE SCAN | PK_EMP | 1 | 1 | 1 |00:00:00.01 | 1 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 6 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 1 | 1 |00:00:00.01 | 1 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("EMPNO"=7788)
6 - access("A"."DEPTNO"="B"."DEPTNO")
25 rows selected.
执行计划的执行顺序(按Id区分),如果按口诀来看就是 1 -> 4 -> 3 -> 6 -> 5 -> 2 -> 0.
而由于这其中1是标量子查询,实际要最后执行,所以真实的执行顺序为 4 -> 3 -> 6 -> 5 -> 2 -> 1 -> 0.
2.理解执行计划每步的含义
以上面的执行计划为例,要清楚知道每一列代表的含义:
- Id
操作id号;
Operation
这一列,可以看到SQL的每一步操作,深入理解就需要清楚表的主要访问方式(TABLE ACCESS FULL、TABLE ACCESS BY INDEX ROWID、TABLE ACCESS BY USER ROWID),索引的主要访问方式(INDEX UNIQUE SCAN、INDEX RANGE SCAN、INDEX FULL SCAN、INDEX FAST FULL SCAN、INDEX SKIP SCAN),多表查询还需要清楚表连接的方法(NESTED LOOP JOIN、SORT MERGE JOIN、HASH JOIN、MERGE JOIN CARTESIAN)和顺序(先访问驱动表)等知识;Name
这一列,就是操作的具体对象名称;Starts
这一列,代表访问次数;比如在NESTED LOOP JOIN中,被驱动表的具体访问次数就可以依据Starts的数值来判断。E-Rows
预估返回行数;A-Rows
实际返回行数;A-Time
实际执行时间;Buffers
逻辑读块/次;
如果是其他方式,看到的执行计划内容有所不同,比如可能就是下面这样:
Execution Plan
----------------------------------------------------------
Plan hash value: 1121436124
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL | DUAL | 1 | 2 | 2 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 38 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 25 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 13 | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
可以看到,前三列没有区别,后面只有Rows、Bytes、Cost (%CPU)、Time等信息。
3.了解执行计划相关的信息
执行计划下面还有相关的信息,类似如下:
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("EMPNO"=7788)
6 - access("A"."DEPTNO"="B"."DEPTNO")
Note
-----
- SQL plan baseline SQL_PLAN_9sdj6nc4ybu5x2b78d17a used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
879 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
谓词信息(Predicate Information)
标识出哪一步有access、filter这样的操作;Note部分(Note)
如果SQL执行中用到了动态采样、基数反馈、自适应游标共享、SQL_Profile、SPM等,会在这里显示出来;统计信息(Statistics)
这里指的是SQL执行实际发生的递归调用、逻辑读、物理读、排序、处理行数等统计信息。
Oracle之SQL优化专题03-如何看懂SQL的执行计划的更多相关文章
- Oracle之SQL优化专题01-查看SQL执行计划的方法
在我2014年总结的"SQL Tuning 基础概述"中,其实已经介绍了一些查看SQL执行计划的方法,但是不够系统和全面,所以本次SQL优化专题,就首先要系统的介绍一下查看SQL执 ...
- 【重磅干货】看了此文,Oracle SQL优化文章不必再看!
目录 SQL优化的本质 SQL优化Road Map 2.1 制定SQL优化目标 2.2 检查执行计划 2.3 检查统计信息 2.4 检查高效访问结构 2.5 检查影响优化器的参数 2.6 SQL语句编 ...
- 梁敬彬老师的《收获,不止SQL优化》,关于如何缩短SQL调优时间,给出了三个步骤,
梁敬彬老师的<收获,不止SQL优化>,关于如何缩短SQL调优时间,给出了三个步骤, 1. 先获取有助调优的数据库整体信息 2. 快速获取SQL运行台前信息 3. 快速获取SQL关联幕后信息 ...
- SQL Server中参数化SQL写法遇到parameter sniff ,导致不合理执行计划重用的一种解决方案
parameter sniff问题是重用其他参数生成的执行计划,导致当前参数采用该执行计划非最优化的现象.想必熟悉数据的同学都应该知道,产生parameter sniff最典型的问题就是使用了参数化的 ...
- Oracle之SQL优化专题02-稳固SQL执行计划的方法
首先构建一个简单的测试用例来实际演示: create table emp as select * from scott.emp; create table dept as select * from ...
- 数据库sql优化总结之5--数据库SQL优化大总结
数据库SQL优化大总结 小编最近几天一直未出新技术点,是因为小编在忙着总结整理数据库的一些优化方案,特此奉上,优化总结较多,建议分段去消化,一口吃不成pang(胖)纸 一.百万级数据库优化方案 1.对 ...
- 学习如何看懂SQL Server执行计划(三)——连接查询篇
三.连接查询部分 --------------------嵌套循环-------------------- /* UserInfo表数据少.Coupon表数据多嵌套循环可以理解为就是两层For循环,外 ...
- 学习如何看懂SQL Server执行计划(二)——函数计算篇
二.函数计算部分 --------------------标量聚合--------------------/* 标量聚合-主要在聚合函数操作中产生 计算标量:根据行中的现有值计算出一个新值 流聚合:在 ...
- 学习如何看懂SQL Server执行计划(一)——数据查询篇
一.数据查询部分 1. 看到执行计划有两种方式,对sql语句按Ctrl+L,或按Ctrl+M打开显示执行计划窗口每次执行sql都会显示出相应的执行计划 2. 执行计划的图表是从右向左看的 3. SQL ...
随机推荐
- Spring Boot整合Mybatis(注解方式和XML方式)
其实对我个人而言还是不够熟悉JPA.hibernate,所以觉得这两种框架使用起来好麻烦啊. 一直用的Mybatis作为持久层框架, JPA(Hibernate)主张所有的SQL都用Java代码生成, ...
- uniGUI之FirDAC(13)
// uses FireDAC.Phys.SQLite 之后, 可不用添加 TFDPhysSQLiteDriverLink //访问SQLite 文件数据库 procedure TMainForm.U ...
- java对sql server的增删改查
package Database; import java.sql.*; public class DBUtil { //这里可以设置数据库名称 private final static String ...
- OPCDA通信--工作在透明模式下的CISCO ASA 5506-X防火墙配置
尊重原创,转发请声名 inside OPCSERVER 一台 outside OPCCLIENT 一台 route模式 配置没成功,放弃,采用透明模式 !----进入全局配置-- configure ...
- 一 注册功能&登录功能,权限拦截
注册功能: 前端JSP:提供表单注册信息以及访问路径,发送请求到Strus2. Struts2 : 通过模型驱动接收并封装User对象,Spring依赖注入(无参构造+setter方法)获取业务层Us ...
- nodejs,webpack安装以及初步运用
nodejs安装: 1.下载:https://nodejs.org/en/download/ 2.安装node-v6.11.3-x64.msi文件,直接默认安装(next……): 3.验证是否完成安装 ...
- JS监听video视频播放时间
采用原生时间监听element.addEventListener(event, function, useCapture) //监听播放时间 var video = document.getEleme ...
- 【拒绝挂分】盘点蒟蒻ghy的各种sb错误
1.m与n打反(打错) NOIPd2t2 50变15爽不爽啊.jpg 某次信心赛四道sb题里面最sb的一道 sort里面的m打成n 100变40爽不爽啊.jpg(还有40我真的谢谢您了 2.没开lon ...
- luogu P3358 最长k可重区间集问题
网络流建图好难,这题居然是网络流(雾,一般分析来说,有限制的情况最大流情况可以拆点通过capacity来限制,比如只使用一次,把一个点拆成入点出点,capacity为1即可,这题是限制最大k重复,可以 ...
- spring事务传播属性和隔离级别
猫咪咪的Java世界 spring事务传播属性和隔离级别 博客分类: Spring java编程 1 事务的传播属性(Propagation) 1) REQUIRED ,这个是默认的属性 Supp ...