访问表的方法:
全表扫描:从该表所占用的第一个区(EXTENT)的第一个块(BLOCK)开始扫描,一直扫描到该表的高水位线(HWM)。oracle会对这期间读到的所有数据施加目标SQL的where条件中指定的过滤条件,最后只返回那些满足过滤条件的数据。(使用多块读的方式)
ROWID扫描:通过数据所在的ROWID去定位并访问这些数据。严格来说,ROWID扫描有两层含义:一种是根据用户在SQL语句中输入的ROWID值直接访问。另外一种是先去访问相关的索引,然后根据访问索引后得到的ROWID再回表去访问对应的数据行记录。
访问索引的方法:(全表扫描会随着数据的增多而增大消耗。索引扫描是可控的、基本稳定的)
索引唯一性扫描(INDEX UNIQUE SCAN):是针对唯一性索引的扫描,它只适用于条件里是等值查询的目标SQL,扫描结果至多只返回一条记录。
索引范围扫描(INDEX RANGE SCAN):根据where中的条件进行范围扫描。对于范围扫描而言,因为其扫描结果可能会返回多条记录,同时又因为目标索引的索引行数量大于1,oracle为了确定索引范围扫描的扫描终点,就不得不去多次访问相关的叶子块。所以在同等条件下,索引范围扫描所耗费的逻辑读至少会比相应的索引唯一性扫描的逻辑读多1。(是单块读)
索引全扫描(INDEX FULL SCAN):要扫描目标索引所有的叶子块,但这并不意味着需要扫描所有的分支块。在默认情况下,oracle在做索引全扫描时,只需要通过访问必要的分支块定位到该索引最左边的叶子块的第一行索引行,就可以利用该索引叶子块之间的双向指针链表,从左至右依次顺序扫描该索引所有叶子块的所有索引行了。是有序的。
索引快速全扫描(INDEX FAST FULL SCAN):需要扫描目标索引所有叶子块的所有索引行。只适用于CBO;可以使用多块读,并行执行;不一定是有序的。
索引跳跃式扫描(INDEX SKIP SCAN):适用于复合B树索引,它使那些在where条件中没有对目标索引的前导列指定查询条件但同时又对该索引的非前导列指定了查询条件的目标SQL依然可以用上该索引。(有点像扫描该索引时跳过了它的前导列,但实际并非如此);只适用于目标索引前导列的distinct值数量较少的情形;
表连接:
排序合并连接(Sort Merge Join):是一种两个表在做表连接时用排序操作和合并操作(merge)来得到连接结果集的表连接方法。
(1)首先以目标SQL中指定的谓词条件(如果有的话)去访问表T1,然后对访问结果按照表T1中的连接列来排序,排好序后的结果集我们记为结果集1。
(2)接着以目标SQL中指定的谓词条件(如果有的话)去访问表T2,然后对访问结果按照表T2中的连接列来排序,排好序后的结果集我们记为结果集2。
(3)最后对结果集1和结果集2执行合并操作,从中取出匹配记录来作为排序合并连接的最终执行结果。
嵌套循环连接(Nested Loops Join):
(1)首先,优化器会按照一定的规则来决定表T1和T2中谁是驱动表、谁是被驱动表。驱动表用于外层循环,被驱动表用于内层循环。这里假设驱动表是T1,被驱动表是T2。
(2)接着以目标SQL中指定的谓词条件(如果有的话)去访问驱动表T1,访问驱动表T1后得到的结果集我们记为驱动结果集1。
(3)然后遍历驱动结果集1并同时遍历被驱动表T2,即先取出驱动结果集1中的第1条记录,接着遍历被驱动表T2并按照连接条件去判断T2中是否存在匹配的记录,然后再取出驱动结果集1中的第2条记录,按照同样的连接条件再去遍历被驱动表T2并判断T2中是否还存在匹配的记录,直到遍历完驱动结果集1中所有的记录为止。这里的外层循环是指遍历驱动结果集1所对应的循环,内层循环是指遍历被驱动表T2所对应的循环。显然,外层循环所对应的驱动结果集1有多少条记录,遍历被驱动表T2的内层循环就要做多少次,这就是所谓的“嵌套循环”的含义。
在11g之后的版本中,Oracle会将原先一批单独块所需要耗费的物理I/O组合起来,然后用一个向量I/O去批量处理它们,这样就提高了效率。(这表现在Nested Loops Join出现两次,因为第一次是得到了单独块并组合起来;第二次进行批量处理。
哈希连接(Hash Join):依靠哈希运算来得到连接结果集的表连接方法。受到隐含参数_HASH_JOIN_ENABLED控制是否哈希连接。 过程较为复杂。
适合于小表和大表之间做表连接且连接结果集的记录数较多的情形。
笛卡尔连接(Cross Join):它是一种两个表在做表连接时没有任何连接条件的表连接方法。(是一种特殊的合并连接);;有可能是漏写了where条件(出现笛卡尔就不太好)
(1)首先以目标SQL中指定的谓词条件(如果有的话)访问表T1,此时得到的结果集我们记为结果集1,这里假设结果集1的记录数为m。
(2)接着以目标SQL中指定的谓词条件(如果有的话)访问表T2,此时得到的结果集我们记为结果集2,这里假设结果集2的记录数为n。
(3)最后对结果集1和结果集2执行合并操作,从中取出匹配记录来作为笛卡儿连接的最终执行结果。这里的特殊之处在于对于笛卡儿连接而言,因为没有表连接条件,所以在对结果集1和结果集2执行合并操作时,对于结果集1中的任意一条记录,结果集2中的所有记录都满足条件,即它们都会是匹配记录,所以上述笛卡儿连接的连接结果的记录数就是m和n的乘积(即m´n)。
查询转换:
子查询展开:
将子查询拆开(即将该子查询中的表、视图从子查询中拿出来,然后再和外部查询中的表\视图做表连接)
要么是不拆开但是会把该子查询转换为一个内嵌式图,然后再和外部查询中的表\视图做表连接。
简单视图合并:一般来说,如果oracle并没有选择对带视图的目标SQL执行视图合并的话,那么在该SQL的执行计划中就会见到"VIEW”关键字,并且该关键字所对应的Name列的值就是该视图的名称
Oracle对包含视图的目标SQL做简单试图合并也是有前提条件的,该SQL所包含视图的视图定义SQL语句中一定不能出现如下内容:UNION,MINUS,CONNECT BY 子句,ROWNUM.....
外连接视图合并:限制:当目标视图在和外部查询的表做外连接时,该目标视图可以做外连接视图合并的前提条件是,要么该视图被作为外连接的驱动表,要么该视图虽然被作为外连接的被驱动表但它的视图定义SQL语句中只包含一个表。
复杂视图合并:视图定义SQL语句中的group by或distinct操作会被推迟执行,也就是说,这种情况下会先做表连接,再做group by或distinct操作。
连接谓词推入:Oracle在做此操作时,会考虑成本值。有着一些限制条件
连接因式分解:是处理带UNION ALL的目标SQL的一种优化手段,会把各个分支中公共的部分提出来作为一个单独的结果集,然后再和原UNION ALL中剩下的部分做表连接。
表扩展:当目标SQL中分区表的某个局部分区索引由于某种原因在某些分区上变得不可用,这会导致所有分区的索引均不能用。在Oracle 11g之后,引出表扩展概念,将SQL等价改写成UNION ALL的形式,除了不可用的分区对应的UNION ALL分支外,其他分区对应的UNION ALL分支还是可以正常使用该局部分区索引。
表移除:指优化器会把虽然在目标SQL中存在,但是其存在与否对最终执行结果没有影响的表从该目标SQL中移除,这样优化器至少可以少做一次表连接。
IN-List Iterator:针对IN后面是常量集合的一种处理方法。优化器会遍历目标SQL中IN后面的常量集合中的每一个值,然后去做比较,看目标结果集中是否存在和这个值匹配的记录。如果存在,则这个记录会成为该SQL的最终返回结果集中的一员;如果不存在,则优化器会继续遍历IN后面的常量集合中的下一个值,直到该常量集合遍历完毕。
前提是IN所在的列上一定要有索引。
IN-List Expansion / OR Expansion:针对IN后面是常量集合的另一种处理方法。优化器会把目标SQL中IN后面的常量集合拆开,把里面的每个常量都提出来形成一个分支。各分支之间用UNION ALL来连接,即IN-List Expansion的本质是把带IN的目标SQL等价改写成以UNION ALL连接的各个分支。Operation的值是"CONCATENATION"。
IN_List Filter:针对IN后面是子查询的一种处理方法。优化器会把IN后面的子查询所对应的结果集当作过滤条件,并且走FILTER类型的执行计划。、
前提:
目标SQL的IN后面是子查询而不是常量的集合。
Oracle未对目标SQL的IN后面的子查询做子查询展开。
统计信息:(存储在数据字典中)
ANALYZE可以收集除CBO之外的信息,如行迁移\行链接,索引的结构信息。要收集于CBO相关的信息最好使用DBMS_STATS包。
索引的统计信息:
聚簇因子:按照索引键值排序的索引行和存储于对应表中数据行的存储顺序的相似程度。
列的统计信息:
直方图:一种特殊的列统计信息,它详细描述了目标列的数据分布情况。直方图实际上存储在数据字典基表HISTGRM$中。它就是专门为了准确评估这种分布不均匀的目标列的可选择率。
FREQUENCY直方图:将distinct值存入数据字典里,这样就知道了列在目标表里的实际数据分布情况。只取头32个字节,将其转换成一个浮点数,然后就将这个浮点数作为其直方图统计信息存储在上述数据字典中。那对于超过32字节的文本型字段,直方图会认为这些记录在该字段的文本值是相同的。
Height Balanced直方图
全局统计信息:仅针对分区表、分区索引有意义。
动态采样:
不管各列有什么样的关联关系,CBO都能相对准确地估算出返回结果集的Cardinality;
在一定程度上解决这种因临时表没有统计信息而导致CBO选错执行计划的问题。
开启动态采样:
将参数OPTIMIZER_DYNAMIC_SAMPLING的值设为大于或等于1;
使用动态采样的Hint;
多列统计信息:为了能准确估算出where条件中出现有关联关系的列时返回结果集,可以人为地指定存在关联关系的一组列为目标表上的一个组合列,然后使用DBMS_STATS包针对这个组合列收集统计信息。(其实就是在表中增加一列,类似于oracle里的函数索引)
系统统计信息:描述了数据库所在数据服务器的系统处理能力的辅助统计信息。主要包括目标数据库服务器的CPU的主频、单块读的平均耗费时间、多块读的平均耗费时间和单次多块读所能读取的数据块的平均值。
数据字典统计信息:用来描述数据字典基表($结尾)、数据字典基表上的索引以及这些数据字典基表的列的详细信息,描述上述数据字典基表的统计信息与描述普通表、索引、列的统计信息没有本质区别。
以数据字典基表TAB$为例,CBO在解析目标SQL生成执行计划的过程中,需要查询TAB$以获得目标SQL中相关表对象的统计信息,但Oracle访问TAB$时,也会需要TAB$的统计信息,以便让CBO知道该以什么样的 方式去访问TAB$。所以,如果收集了数据字典统计信息,则TAB$中会存储它自身的表统计信息。
内部对象统计信息
自动统计信息收集
能够正常运行的前提条件是参数STATISTICS_LEVEL的值为TYPICAL或者ALL。
Oracle 11g:
通过每天执行自动运行任务GARHER_STATS_PROG来实现。实际上是执行DBMS_STATS包里的存储过程GATHER_DATABASE_STATS_JOBS_PROC。
收集作业可配置的维护窗口有7个,分别对应一个星期的七天。
对上述7个维护窗口施加了资源限制,其对应的Resource Plan的名称为DEFAULT_MAINTENANCE_PLAN。




