执行计划
oracle的执行计划也就是execution plan是database执行一条sql语句所使用的步骤的集合。
每一步,或者从物理的行数据中检索,或者使用用户发布的sql语句。
Oracle优化器 optimizer
为了搞明白oracle如何处理sql语句,有必要搞明白oracle的optimizer部分(也称之为query 优化器和成本优化器)。所有的sql语句都是用optimizer来决定到达指定数据的最有效的方法。
优化器的使用
执行一条DML语句,oracle database可能需要执行很多步骤。每一步,或者从物理的行数据中检索,或者使用用户发布的sql语句。
执行一个DML语句可能有很多种方式,比如访问表和索引的顺序可以不同。Oracle选择执行语句的步骤会在很大程度上左右这条语句的执行速度。优化器在描述可能的执行办法的时候会生成一个执行计划。
Access path:意思是数据从数据库中检索出来的方法。比如:使用索引的查询和使用全表扫描的查询使用不同的访问路径。
综合考虑多方因素:包括查询条件,可用的访问路径,系统收集的数据,和hints。对于任何的sql语句执行的时候,优化器都会做下面的操作。
表达和条件的预估
检查×××的限制,来了解更多关于数据和基于元数据的优化
声明转换
优化目标的选择
访问路径的选择
Join顺序的选择
优化器生成执行一个查询的最多的方法,然后给每一个步骤分配一个执行计划的成本,最低成本的计划会被选择为要执行的计划。
你可以在执行sql之前就获得一个执行的计划。只有database真正用来执行一个查询的执行计划才被称之为一个查询计划。
你可以通过设定优化器的目标来影响优化器的选择,通过收集优化器的代表数据。比如你可以把优化器的目标设置为如下:
全部输入
ALL_ROWS暗示领导优化器来找到最后一行的结果的最快选择
初始响应时间:
第一行暗示引导优化器得到第一行结果的最快选择。
一个典型的end-user,交互式的应用汇从optimizer的initial response time中收益,
一个非交互式的应用会从optimizer 的throughput中收益。
输入到优化器的东西是一个解析的查询。优化器会做下面的操作:
优化器接收解析过的查询,省城一系列的可能的执行sql的计划基于可用的访问路径和暗示。
2:优化器预估基于数据字典中的数据的每个计划的成本。
成本是一个和期望的执行语句的资源使用的预估比例。
3:优化器会比较执行的成本,选择最低成本的计划,作为查询计划,传递给row source generator。
Query transformer
Query transformer决定是否改变查询的形式,来让优化器生成一个更好的执行计划。输入到query transformer的是一个解析过的查询,室友一系列的查询块来表述。
Estimator
Estimator决定的事一个给定的执行计划的总体的成本。Estimator使用三种不同的方法来完成这个目标:
选择率:这个方法代表了在行集中的一部分row。选择率和一个查询谓语有关,比如last_name=’Smith’,或者是一个谓语的集合。
基数
这个方法代表的是row set中row的数量。
成本
这种方法代表的是资源消耗的单位,这儿查询优化器使用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,过滤出不满足选择要求的row。Database按照顺序扫描在segment中的所有 data block,包括在high water mark之下的data block ,区分使用和未使用的部分也要扫描。
Rowid 扫描
一个row的rowid指定的是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语句和其他正在处理信息的指定session的private 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 value。Sql语句的hash value是在 v$SQL.SQL_ID视图中的SQL_ID
用户提交一条sql的时候,database会查询 shared sql area来查看是否存在解析的sql拥有相同的hash value。一条sql的hash value和下面的值是有区别的。
Sql语句的内存地址
Oracle database使用sql id来执行一个查找表中的键控读。使用这种方式,database获得sql的内存地址。
Sql执行计划的hash value
Sql语句在shared pool中可以有多个计划。每一个计划有一个不同的hash value。如果相同的SQL ID有多个hash values,database就会知道这个SQL ID对应的sql有多个计划存在。
解析操作有以下两种,基于提交的sql的类型,还有hash检查的结果。
硬解析:
如果oracle database不能重复利用存在的code,那么它必须要建立一个新的应用代码的执行版本。这种操作称之为hard parse,或者是librarycache miss。Database经常对DDL做硬解析。
硬解析过程中, database多次访问library cache和data dictionary cache来检查数据字典。当database访问到这些区域的时候,使用一个叫做latch的连续化的设备在需要的对象上,这样他们的定义就不会改变。Latch会减少数据并发,增加sql执行时间,(这是个system的lock,用来保证数据的完整性。
软解析
非硬解析都是软解析。如果提交的sql和在shared pool中的可用sql一样的话,oracle就会重新使用存在的代码。代码的reuse叫做library cache hit。
软解析在工作量上不同,比如配置shared sql area的session有时候会减少软解析的latch,让她更软。
软解析比硬解析要好,因为database会跳过optimizer和row source generation步骤,直接执行。
下图展示的是shared pool check在一条uptate的语句