执行计划
oracle的执行计划也就是execution plandatabase执行一条sql语句所使用的步骤的集合。

每一步,或者从物理的行数据中检索,或者使用用户发布的sql语句。



Oracle优化器 optimizer


为了搞明白oracle如何处理sql语句,有必要搞明白oracleoptimizer部分(也称之为query 优化器和成本优化器)。所有的sql语句都是用optimizer来决定到达指定数据的最有效的方法。



优化器的使用


执行一条DML语句,oracle database可能需要执行很多步骤。每一步,或者从物理的行数据中检索,或者使用用户发布的sql语句。

执行一个DML语句可能有很多种方式,比如访问表和索引的顺序可以不同。Oracle选择执行语句的步骤会在很大程度上左右这条语句的执行速度。优化器在描述可能的执行办法的时候会生成一个执行计划。



Access path:意思是数据从数据库中检索出来的方法。比如:使用索引的查询和使用全表扫描的查询使用不同的访问路径。




综合考虑多方因素:包括查询条件,可用的访问路径,系统收集的数据,和hints。对于任何的sql语句执行的时候,优化器都会做下面的操作。



表达和条件的预估

检查×××的限制,来了解更多关于数据和基于元数据的优化

声明转换

优化目标的选择

访问路径的选择

Join顺序的选择




优化器生成执行一个查询的最多的方法,然后给每一个步骤分配一个执行计划的成本,最低成本的计划会被选择为要执行的计划。


你可以在执行sql之前就获得一个执行的计划。只有database真正用来执行一个查询的执行计划才被称之为一个查询计划。

你可以通过设定优化器的目标来影响优化器的选择,通过收集优化器的代表数据。比如你可以把优化器的目标设置为如下:


全部输入


ALL_ROWS暗示领导优化器来找到最后一行的结果的最快选择


初始响应时间:


第一行暗示引导优化器得到第一行结果的最快选择。



一个典型的end-user,交互式的应用汇从optimizerinitial response time中收益,

一个非交互式的应用会从optimizer throughput中收益。


oracle执行计划_第1张图片


输入到优化器的东西是一个解析的查询。优化器会做下面的操作:



优化器接收解析过的查询,省城一系列的可能的执行sql的计划基于可用的访问路径和暗示。

2:优化器预估基于数据字典中的数据的每个计划的成本。

成本是一个和期望的执行语句的资源使用的预估比例。

3:优化器会比较执行的成本,选择最低成本的计划,作为查询计划,传递给row source generator




Query transformer


Query transformer决定是否改变查询的形式,来让优化器生成一个更好的执行计划。输入到query transformer的是一个解析过的查询,室友一系列的查询块来表述。





Estimator



Estimator决定的事一个给定的执行计划的总体的成本。Estimator使用三种不同的方法来完成这个目标:


选择率:这个方法代表了在行集中的一部分row。选择率和一个查询谓语有关,比如last_name=’Smith’,或者是一个谓语的集合。


基数


这个方法代表的是row setrow的数量。


成本


这种方法代表的是资源消耗的单位,这儿查询优化器使用disk IO,CPU使用率和内存使用率来当做单位。



如果数据可用,而且estimator使用数据来计算成本,数据可以提升方法的准确性。




计划生成器


计划生成器会尝试不同的提交的查询的计划,选择最低成本的计划。优化器会为每一个嵌套的子查询和没有合并的视图生成子计划,使用一个另外的查询block。计划生车呢工期搜索不同的计划为每一个不同的query block探索不同的plan,通过尝试不同的访问路径,join方法,和join顺序。



优化器自动管理计划,确保只有特定的计划被执行。Sql计划管理工具只会在B计划证明比A计划性能更好的时候才会更新执行计划。


Explain plan声明让你可以查看被优化器选择的执行计划。Explainplan展示的是在当前session中正在被执行的sql查询的执行计划。




Access path

访问路径是数据从database被检索的路径。比如,使用index的查询和不用index的查询不一样。大体上说:对于一个table rows的小子部分,索引access path是最好的选择。

检索一张table的很大一部分,使用全表扫描会更快。



Database可以使用很多不同的方法从table中检索出数据来。方法包括:


全表扫描:

这种扫描是需要读出一张table里的所有row,过滤出不满足选择要求的rowDatabase按照顺序扫描在segment中的所有 data block,包括在high water mark之下的data block ,区分使用和未使用的部分也要扫描。



Rowid 扫描


一个rowrowid指定的是data file和包括这个行的data block,还有在block中的row的位置。

Oracle从选中的row中取出rowid来,使用where语句或者index scan,然后基于rowid来定位每一个选定的row

SQL 解析

SQL处理的第一阶段是解析。这个阶段包括:把一条SQL语句分成可以被其他程序处理的数据结构。当被应用指导的时候,database解析一条SQL,也就是说,只有应用能够减少解析的次数,而不是database




当应用发布一条SQL,应用会调用oracle来解析sql,准备执行这条SQL。这条解析打开或者创建一个cursor,这是一个存放解析过得SQL语句和其他正在处理信息的指定sessionprivate SQL area

游标和private SQL area存放在PGA中。




Private SQL area

内存的一块区域存放的是解析过的语句和其他的正在处理的信息。Private SQL area包括绑定变量的值,查询执行状态信息,查询执行工作区域。






解析调用过程中,database执行以下的检查


语法检查

语义检查

共享池检查


上述的检查会在sql执行之前找到可以发现的错误。


1:语法检查


Oracle database检查每一条sql语句是否语法上是有效的。一条sql没有遵守sql语法,检查就会失败。




语义检查

语义检查决定是否一条sql有意义。比如,sql语句中的一些对象是否存在。如果一张表不存在的话,semantic检查就会失败。


共享池检查在解析过程中,database会执行一个shared_pool_check来决定是否它可以跳过资源密集型的语句处理。执行完之后,database会使用一个hashing算法来为每一条sql语句生成一个hash valueSql语句的hash  value是在 v$SQL.SQL_ID视图中的SQL_ID


用户提交一条sql的时候,database会查询 shared sql  area来查看是否存在解析的sql拥有相同的hash  value。一条sqlhash value和下面的值是有区别的。


Sql语句的内存地址


Oracle database使用sql id来执行一个查找表中的键控读。使用这种方式,database获得sql的内存地址。


Sql执行计划的hash value

Sql语句在shared pool中可以有多个计划。每一个计划有一个不同的hash value。如果相同的SQL ID有多个hash  valuesdatabase就会知道这个SQL ID对应的sql有多个计划存在。



解析操作有以下两种,基于提交的sql的类型,还有hash检查的结果。



硬解析:

如果oracle database不能重复利用存在的code,那么它必须要建立一个新的应用代码的执行版本。这种操作称之为hard  parse,或者是librarycache missDatabase经常对DDL做硬解析。


硬解析过程中, database多次访问library cachedata dictionary cache来检查数据字典。当database访问到这些区域的时候,使用一个叫做latch的连续化的设备在需要的对象上,这样他们的定义就不会改变。Latch会减少数据并发,增加sql执行时间,(这是个systemlock,用来保证数据的完整性。




软解析


非硬解析都是软解析。如果提交的sql和在shared pool中的可用sql一样的话,oracle就会重新使用存在的代码。代码的reuse叫做library cache hit


软解析在工作量上不同,比如配置shared sql areasession有时候会减少软解析的latch,让她更软。


软解析比硬解析要好,因为database会跳过optimizerrow source generation步骤,直接执行。


下图展示的是shared pool check在一条uptate的语句

oracle执行计划_第2张图片