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 ...
随机推荐
- Codeforces1300D. Aerodynamic
本题题目有点绕,结合图例大概可知,P(x,y)是以点给出的一个凸包,T是一个点集合,也构成一个凸包,构成的方法就是将原点(0,0)在P(x,y)的边上跑,移动坐标轴,其构成的最远点是个凸包,我们可以画 ...
- SVN提交失败:Changing file 'XXX' is forbidden by the server;Access to 'XXX' forbidden
解决方案:https://blog.csdn.net/m0_38084243/article/details/81503638 个人分析主要是后者,在SVN服务器上添加上我对本项目的读写权限即可: 添 ...
- 让UITextField全选
[textField selectAll:self];
- C 语言入门第五章--循环结构和选择结构
C语言中有三大结构,分别是顺序结构.选择结构和循环结构: 逻辑运算: 与运算: && 或运算:|| 非运算:! ==== #include<stdio.h> int mai ...
- bootloader 详细介绍
Bootloader 对于计算机系统来说,从开机上电到操作系统启动需要一个引导过程.嵌入式Linux系统同样离不开引导程序,这个引导程序就叫作Bootloader. 6.1.1 Bootloader ...
- computed、methods、watch
computed:计算属性将被混入到 Vue 实例中.所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例. methods:methods 将被混入到 Vue 实例中 ...
- OSX10.10 Yosemite安装Metasploit
安装环境 操作时间: 2015/6/8 操作系统: OSX Yosemite 10.10.3 Metasploit版本: v4.11.0-dev [core:4.11.0.pre.dev api:1. ...
- Day2:接着思考和可能的策划
今天早上闹钟还没响呢,老婆就把我叫醒了~说有规律宫缩了! 7点到8点记录了一个小时,宫缩差不多5~6分钟一次! 赶紧收拾东西上医院!正好今天是40周的产检,今天还是预产期! 这孩子终于肯出来了! 结果 ...
- C# 自定义控件容器,设计时可添加控件
本分步指南介绍在将 UserControl 放在 Windows 窗体上之后,如何将 UserControl 对象用作设计时控件容器.可能会有这样的情况:您想将一个控件拖到 UserControl 中 ...
- array_multisort 对关联数组进行排序的问题 PHP
我们在php的数组操作中经常用到对数组进行排序的问题,这里说的是对关联数组进行排序需要用到函数 array_multisort . array_multisort(array_column($arr, ...