欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

Oracle 11g Release 优化器的访问路径介绍

程序员文章站 2022-05-29 21:50:00
...

本文内容
•全表扫描(Full Table Scans)
•物理 ID 扫描(Rowid Scans)
•索引扫描(Index Scans)
•聚簇访问(Cluster Access)
•哈希访问(Hash Access)
•采样表扫描(Sample Table Scans)
•查询优化器如何选择访问路径
•备注

访问路径(Access paths)是从数据库检索数据的方式。一般地,索引访问路径(index access paths)用于检索表数据行一个小的子集语句,而当访问表的一个大部分时,全表扫描(full scans)更有效率。在线事务处理(Online transaction processing,OLTP)应用程序,它是由具有高选择性的短期运行的 SQL 语句组成,通常用索引访问路径。另一个方面,决策支持系统(Decision support systems)倾向于使用分区表,执行相关分区的全表扫描。

全表扫描

--------------------------------------------------------------------------------

全表扫描读取表的所有行,并过滤掉那些不符合选择条件的行。执行全表扫描期间,表中高水位线(high water mark,HWM)以下的所有数据块都会被扫描。高水位以下的所有数据表示已使用的空间数量(插入数据后),或收到数据已被格式化的空间(插入数据后,再删除的空间)。检查每个行是否满足 WHERE 子句。

当Oracle 执行全表扫描时,顺序地读取块。因为块是相邻的,所以 I/O 调用要比单块大,加速了处理。读取调用大小的范围从 1 个块到初始化参数 DB_FILE_MULTIBLOCK_READ_COUNT 指定的块数量。使用多块读取意味着,全表扫描以很高的效率执行。每个块只被读取一次。

为什么全表扫描对于访问大数据量更快?
当访问表中块的很大一部分时,全表扫描要比索引范围扫描更划算。这是因为,全表扫描可以使用更大的 I/O 调用,而次数少却较大的 I/O 调用要比次数多却小的调用代价更小。

优化器何时使用全表扫描?
优化器在以下情况使用全表扫描:

•没有索引
若查询不能使用任何现存的索引,则使用全表扫描。例如,如果查询中有一个在已索引列上使用函数,那么,优化器就不能使用索引,而是使用全表扫描。

如果你需要使用索引来进行不依赖大小写的检索,那么,或者在检索中不允许大小写混合,或是在检索列上创建一个基于函数的索引,如 UPPER(last_name)。参考 “使用基于函数索引的性能”。

•大数据量
若优化器认为,查询会访问表中的大多数块,则使用全表扫描,即使有索引可用。

•小的表
若一个表高水位线以下包含比 DB_FILE_MULTIBLOCK_READ_COUNT 参数小块,它们可以在一个单 I/O 调用读取,那么全表扫描比索引范围扫描更划算,而不管可被访问表的其他部分,或现在的索引。

•高并行度
一个表的高并行度会使优化器倾向于全表扫描,而不是范围扫描。检查 ALL_TABLES 表的 DEGREE 列以确定并行程度。

全表扫描提示
使用 FULL(table alias) 来命令优化器使用全表扫描。参考“指示访问路径”。

可以使用 CACHE 和 NOCACHE 指示已检索的块是否放在缓冲区缓存。CACHE 命令优化器,当执行全表扫描时,把已检索的块放在缓冲区高速缓存 LRU 列表最近使用的末尾。

小的表 1 根据下表的准则自动缓存。

表 1 缓存表的准则

表大小 大小准则 缓存
小 块的数量大于 20 个,或已缓存的块达到总数的 2%,不管多大 如果 STATISTICS_LEVEL 设置为 TYPICAL 或更高,Oracle 确定是否依赖表的扫描记录缓存一个表。只有之后表扫描可能查找已缓存的块,表才会被缓存。若 STATISTICS_LEVEL 设置成 BASIC,则表不被缓存。
中 比上面的大,并且已缓存的块小于总数的 10% Oracle 确定是否基于表的扫描和负载记录缓存一个表。只有之后的扫描可能查找已缓存的块,才会缓存表。
大 已缓存的块大于总数的 10% 不被缓存。

对于用 CACHE 属性创建或变更的表,禁用小表的自动缓存。

并行查询的执行
当需要全表扫描时,通过多并行执行服务来扫描表已提高响应时间。并行查询通常用于低并发数据的数据仓库环境。

物理 ID(Rowids)扫描

--------------------------------------------------------------------------------

一个行的物理 ID 指定数据文件(datafile),以及包含行的数据块和块中行位置的数据块。通过指定行的物理 ID 定位行是检索一个单独行的最快方式,因为在数据库中指定了行的精确定位。为了通过物理 ID 访问一个表,Oracle 首先获得已选定行的物理 ID,无论是从语句的 WHERE 子句,还是通过一个或多个表索引的索引扫描。之后,Oracle 基于它们的物理 ID 在表中定位每个选择的行。

优化器何时使用 Rowids
一般地,这是从一个索引检索物理 ID 后的第二步。访问的表可能在语句中要求任何列,而这些列并不在索引中。

通过物理 ID 访问不需要按照每个索引扫描。若索引包含语句需要的所有列,则通过物理 ID 访问可能不会发生。

索引扫描

--------------------------------------------------------------------------------

此方法中,使用语句中指定的已索引的列的值,通过遍历索引来检索行。索引扫描基于索引中的一个或多个值,从索引中检索数据。要执行一个索引扫描,Oracle 为已建立索引列的值检索索引。若语句仅仅访问索引列,则 Oracle 从索引直接读取已索引的列值,而不是从表。

索引不仅包含索引值,而且也包含表中具有该值的行的物理 ID。因此,若语句访问其他没有索引的列,则 Oracle 通过物理 ID 或聚簇扫描查找表中的行。

以下是索引扫描类型:

•通过块访问 I/O,不是行
•索引唯一扫描(Index Unique Scans)
•索引范围扫描(Index Range Scans)
•索引访问递减扫描(Index Range Scans Descending)
•索引滤过扫描(Index Skip Scans)
•全表扫描(Full Scans)
•快速全表索引扫描(Fast Full Index Scans)
•索引连接(Index Joins)
•Bitmap 索引(Bitmap Indexes)

聚簇访问

--------------------------------------------------------------------------------

聚簇扫描用于从存储在已索引聚簇的表中检索具有相同聚簇键值的所有行。要执行聚簇扫描,Oracle 首先通过扫描聚簇索引,获得已选定行的物理 ID。再基于物理 ID 定位行。

哈希访问

--------------------------------------------------------------------------------

哈希扫描用于基于哈希值在哈希聚簇中定位行。在哈希聚簇中,具有相同哈希值的所有行被存储在相同的数据块。要执行哈希扫描,Oracle 首先通过把一个哈希函数应用到一个聚簇键值,来获得哈希值。再扫描包含哈希值的行所在数据块。

采样表扫描

--------------------------------------------------------------------------------

采样(随机)表扫描从一个采样表或是一个复杂的 SELECT 语句检索随机的采样数据。当 FROM 语句包含 SAMPLE 子句或 SAMPLE BLOCK 子句时,使用该访问路径。当用 SAMPLE 子句采样数据时,要执行一个采样表扫描,Oracle 在表中读取一个指定的行百分比。当用 SAMPLE BLOCK 子句采样块时,Oracle 读取一个指定的表块的百分比。

查询优化器如何选择访问路径

--------------------------------------------------------------------------------

查询优化器基于下面因素选择一个访问路径:

•语句可用的访问路径
•通过每个访问路径,或访问路径的结合,评估执行语句的代价
要选择一个访问路径,优化器首先通过检查 WHERE 子句和 FROM 子句的条件来确定哪个访问路径可用。然后,优化器使用访问路径产生一套可能的执行计划,并通过索引、列和访问表语句的统计信息来评估每个执行计划的代价。最后,优化器选择具有最小代价的执行计划。

当选择一个访问路径时,查询优化器受下面影响:

•优化器指示
可以指定优化器使用指定的访问路径,除了包含 SAMPLE 或 SAMPLE BLOCK 的 FROM 子句。

•统计信息
例如,若一个表自创建以来,没有分析过,并且其高水位线下(HWM)的块小于参数 DB_FILE_MULTIBLOCK_READ_COUNT,则优化器认为,这个表比较小,并使用全表扫描。查看 ALL_TABLES 表中的 LAST_ANALYZED 和 BLOCKS 列来检查统计信息。

备注

--------------------------------------------------------------------------------

高水位线(high water mark,HWM)
Oracle 在逻辑存储上分为 4 个粒度——表空间、段、区和块。

•块是最小的存储单位(8K)。Oracle 的每次I/O操作也是按块的。即当 Oracle 读数据时,是读取多少个块,而不是多少行。
•区是由一系列相邻的块组成,这是 Oracle 分配空间的基本单位。比如,当创建一个表时,Oracle 会分配一个区的空间给该表。当该区满了后,Oracle 以区为单位进行扩展,而不是块。
•段是由一系列的区组成。一般地,当创建一个对象时(表或索引),Oracle 会分配一个段给该对象。某种意义上,段是某种特定的数据。如 CREATE TABLE 时,Oracle 为表创建数据段,CREATE INDEX 时,Oracle 还会分配一个段,只是这个段是索引段。
•表空间包含了段、区和块。表空间数据物理上储存在其所在的数据文件中。
Oracle 用高水位线(high water mark,HWM)来界定一个段中使用的块和未使用的块。

比如,当创建一个表时,Oracle 为该对象分配一个段。即使还未插入任何记录,也至少有一个区被分配。第一个区的第一个块称为段头(SEGMENT HEADE)。段头储存了一些信息,如 HWM 信息。HWM 位于第 2 个块。当块放不下新数据,Oracle 用 HWM 之上的块存储,同时,HWM 向上移。当不断插入数据时,HWM 会不断上移。这样,HWM 之下表示使用过的块,HWM 之上的就表示已分配但未使用过的块