1.执行计划
执行计划是一条查询语句在Oracle中的执行过程或访问路径的描述。
执行计划描述了SQL引擎为执行SQL语句进行的操作;分析SQL语句相关的性能问题或仅仅质疑查询优化器的决定时,必须知道执行计划;所以执行计划常用于sql调优。
2.查看执行计划
2.1、方法一:explain plan for SQL
explain plan for select * from emp;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());
2.2、方法二:AUTOTRACE命令
- SET AUTOTRACE ON
2.2.1、执行 SQL 会显示执行计划
显示执行计划和统计信息:set autotrace traceonly
只显示执行计划:set autotrace traceonly explain
只显示统计信息:set autotrace traceonly statistics
显示结果集,执行计划和统计信息:set autotrace on
显示结果集,执行计划:set autotrace on explain
显示结果集,统计信息:set autotrace on statistics
不过如果是使用PLSQL的话,那就可以使用PLSQL提供的查询执行计划了,也就是按F5
打开PLSQL工具 -> 首选项 -> 窗口类型 -> 计划窗口 ,在这里加入执行计划需要的参数
解释一下这些参数的意思:
- 基数(Rows):Oracle估计的当前步骤的返回结果集行数
- 字节(Bytes):执行SQL对应步骤返回的字节数
- 耗费(COST)、CPU耗费:Oracle估计的该步骤的执行耗费和CPU耗费
- 时间(Time):Oracle估计的执行sql对于步骤需要的时间
2.3 查看真实执行计划
declareb1 date;
beginexecute immediate 'alter session set statistics_level=ALL';b1 := sysdate - 1;for test in (/*业务SQL(sql后面不需要加";")*/select * from emp) loopnull;end loop;for x in (select p.plan_table_outputfrom table(dbms_xplan.display_cursor(null,null,'advanced -bytes -PROJECTION allstats last')) p) loopdbms_output.put_line(x.plan_table_output);end loop;rollback;
end;
关键信息解释:
- Starts:该SQL执行的次数
- E-Rows:为执行计划预计的行数
- A-Rows:实际返回的行数,E-Rows和A-Rows作比较,就可以看出具体那一步执行计划出问题了
- A-Time:每一步实际执行的时间,可以看出耗时的SQL
- Buffers:每一步实际执行的逻辑读或一致性读
2.4 explain执行顺序
所以不管是用F5方式还是set statistics_level=ALL方式,都有Operation参数,Operation表示sql执行过程,查看怎么执行的,有两个规则:
- 根据Operation缩进判断,缩进最多的最先执行;
- Operation缩进相同时,最上面的是最先执行的;
2.5 访问数据的方法
Oracle的优化器共有两种的优化方式,即基于规则的优化方式(Rule-Based Optimization,简称为RBO)和基于代价的优化方式(Cost-Based Optimization,简称为CBO)。
2.5.1 全表扫描(TABLE ACCESS FULL)
全表扫描是Oracle直接访问数据的一种方法,全表扫描时从第一个区(EXTENT)的第一个块(BLOCK)开始扫描,一直扫描的到表的高水位线(High Water Mark),这个范围内的数据块都会扫描
全表扫描是采用多数据块一起扫的,并不是一个个数据库扫的,然后我们经常说全表扫描慢是针对数据量很多的情况,数据量少的话,全表扫描并不慢的,不过随着数据量越多,高水位线也就越高,也就是说需要扫描的数据库越多,自然扫描所需要的IO越多,时间也越多
2.5.2 ROWID扫描(TABLE ACCESS BY ROWID)效率最高
ROWID也就是表数据行所在的物理存储地址,所谓的ROWID扫描是通过ROWID所在的数据行记录去定位。ROWID是一个伪列,数据库里并没有这个列,它是数据库查询过程中获取的一个物理地址,用于表示数据对应的行数。
随意获取一个ROWID序列:AAAWSJAAFAAAWwUAAA,前6位表示对象编号(Data Object number),其后3位文件编号(Relative file number),接着其后6位表示块编号(Block number), 再其后3位表示行编号(Row number)
ROWID编码方法是:A ~ Z表示0到25;a ~ z表示26到51;0~9表示52到61;+表示62;/表示63;刚好64个字符。
访问索引(TABLE ACCESS BY INDEX SCAN)的情况就比较多了,可以分为:
索引唯一扫描(INDEX UNIQUE SCAN)
索引唯一性扫描(INDEX UNIQUE SCAN)是针对唯一性索引(UNIQUE INDEX)来说的,也就是建立唯一性索引才能索引唯一性扫描,唯一性扫描,其结果集只会返回一条记录。
索引范围扫描(INDEX RANGE SCAN)
索引范围扫描(INDEX RANGE SCAN)适用于所有类型的B树索引,一般不包括唯一性索引,因为唯一性索引走索引唯一性扫描。 当扫描的对象是非唯一性索引的情况,where谓词条件为Between、=、<、>等等的情况就是索引范围扫描,注意,可以是等值查询,也可以是范围查询。如果where条件里有一个索引键值列没限定为非空的,那就可以走索引范围扫描,如果索引列是非空的,那就走索引全扫描**
索引全扫描(INDEX FULL SCAN)
索引全扫描(INDEX FULL SCAN)适用于所有类型的B树索引(包括唯一性索引和非唯一性索引)。
索引全扫描是指扫描目标索引所有叶子块的索引行,但不意思着需要扫描所有的分支块,索引全扫描时只需要访问必要的分支块,然后定位到位于该索引最左边的叶子块的第一行索引行,就可以利用该索引叶子块之间的双向指针链表,从左往右依次顺序扫描所有的叶子块的索引行
索引快速全扫描(INDEX FAST FULL SCAN)
索引快速全扫描和索引全扫描很类似,也适用于所有类型的B树索引(包括唯一性索引和非唯一性索引)。和索引全扫描类似,也是扫描所有叶子块的索引行,这些都是索引快速全扫描和索引全扫描的相同点
索引快速全扫描和索引全扫描区别:
- 索引快速全扫描只适应于CBO(基于成本的优化器)
- 索引快速全扫描可以使用多块读,也可以并行执行
- 索引全扫描会按照叶子块排序返回,而索引快速全扫描则是按照索引段内存储块顺序返回
- 索引快速全扫描的执行结果不一定是有序的,而索引全扫描的执行结果是有序的,因为索引快速全扫描是根据索引行在磁盘的物理存储顺序来扫描的,不是根据索引行的逻辑顺序来扫描的
索引跳跃式扫描(INDEX SKIP SCAN)
索引跳跃式扫描(INDEX SKIP SCAN)适用于所有类型的复合B树索引(包括唯一性索引和非唯一性索引),索引跳跃式扫描可以使那些在where条件中没有目标索引的前导列指定查询条件但是有索引的非前导列指定查询条件的目标SQL依然可以使用跳跃索引
2.6 表连接方法
排序合并连接(merge sort join)
merge sort join是先将关联表的关联列各自做排序,然后从各自的排序表中抽取数据,到另一个排序表中做匹配.
经常会使用一些非等值连接一些表关联中,并且如果在关联之前已经对数据排好序,则他的效率是高于hash join.
嵌套循环连接(Nested loop join)
Nested loops 工作方式是循环从一张表中读取数据(驱动表outer table),然后访问另一张表(被查找表 inner table,通常有索引)。驱动表中的每一行与inner表中的相应记录JOIN。类似一个嵌套的循环。对于被连接的数据子集较小的情况,nested loop连接是个较好的选择
哈希连接(Hash join)
散列连接是 CBO 做大数据集连接时的常用方式,优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。
使用场景:1.表的数据量比较小,或者一张大表和一张小表关联。
2.hash连接只适用于等值连接
3. 修改执行计划
hints是Oralce中提供的一种特殊的语法结果,在sql语句中嵌入一些语句,来改变sql语句原来的执行方式。
语句级别:用 Hint (/*+ ... */) 来设定
Select /*+ first_rows(10) */ name from table ;
ALL_ROWS
ALL_ROWS是针对整个目标SQL的Hint,它的含义是让优化器启用CBO,而且在得到目标SQL的执行计划时会选择那些 吞吐量 最佳的执行路径。 FIRST_ROWS(n) FIRST_ROWS(n)
FIRST_ROWS(n)
FIRST_ROWS(n)是针对整个目标SQL的Hint,它的含义是让优化器启用CBO模式,而且在得到目标SQL的执行计划时会选择那些得以最快响应并返回头n条记录的执行路径.如果在UPDATE、DELETE或者含如下内容的查询语句中使用了FIRST_ROWS(n) Hint,则该FIRST_ROWS(n) Hint会被Oracle忽略。
如下内容的查询语句:
- 集合运算(如UNION、INTERSECT、MINUS、UNION ALL等)
- GROUP BY
- FOR UPDATE
- 聚合函数(比如SUM等)
- DISTINCT
- ORDER BY(对应的排序列上没有索引)
RULE
RULE是针对整个SQL的Hint,它表示对目标SQL启用RBO。RULE与其他Hint:RULE通常不能与除DRIVING_SITE以外的Hint联用,当RULE与除DRIVING_SITE以外的Hint联用时,其他的Hint可能会失效。但是,当RULE和DRIVING_SITE联用时,它自身可能会失效,所以RULE Hint最好是单独使用。Oracle早就不支持RBO了,二是因为启用RBO后优化器在执行目标SQL时选择的执行路径将大大减少,很多执行路径RBO根本就不支持(比如哈希连接),这也就意味着启用RBO后目标SQL跑出正确执行计划的概率将大大降低。