一条SQL语句的执行计划,可能会包括多个步骤,为了方便分析和讲解执行计划,我们将这些步骤称为执行计划的节点(Node)。每个节点又包含诸多信息,其中,最核心的信息莫过于节点中的操作(Operation),例如:TABLE ACCESS FULL,HASH JOIN等,节点中其他信息也都是围绕其中的操作。本书通篇统一上述命名方法,不再解释和赘述。我们进行SQL调优时,首先要能读懂进而分析SQL语句的执行计划,而做到这点的前提,就是必须熟悉和理解执行计划节点中的操作,因此,深入理解和掌握这些操作是学习SQL调优最重要的基础之一,更是踏入SQL调优高级殿堂的必备条件。下面,我们从实用性角度,按照大类对执行计划节点中的各操作进行详尽讲解。

1. 表相关操作

该类操作与SQL语句执行计划中访问表中数据的路径和方式相关,主要包括表访问类相关操作。根据不同的具体SQL语句及其他相关因素,如下各操作可能会出现于相关SQL语句的执行计划。

1)TABLE ACCESS FULL

对表相应段高水位线(HWM)下的所有数据块进行一个扫描。该操作的最大特点就是可以并行的读取多个数据块,也正是因为这个特点,该操作产生的数据是无序的。该操作具体如图1-1中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_operator

图1-1 表相关操作TABLE ACCESS FULL示例

2)TABLE ACCESS BY INDEX ROWID

通过从索引中获取到的ROWID访问表中的数据行,这也是通过索引访问表数据的方式。该操作有两个特点,首先,索引的数据是有序的,读数据时,首先读索引块,通过索引块中键值的ROWID再去读表的数据块,以达到读取表数据的目的,因此,该操作产生的数据是有序的。我们在很多场景下调优时,可以通过该操作产生数据的有序性去避免排序,从而达到优化性能的目的;其次,该操作在读取数据时,只能按照每次一个的方式顺序读取数据块,因此,该操作在读取大量数据时,效率要比全表扫描的读取方式低的多。该操作具体如图1-2中节点2所示。

Oracle SQL执行计划操作(1)——表相关操作_operator_02

图1-2 表相关操作TABLE ACCESS BY INDEX ROWID示例

3)TABLE ACCESS BY LOCAL INDEX ROWID

通过从本地索引(Local Index)中获取到的ROWID 访问表中的数据行。该操作和上述操作(TABLE ACCESS BY INDEX ROWID)中的访问方式是一样的,只不过,该操作通过表的本地索引获取到ROWID后,再通过ROWID去读取相应表分区(Partition)的数据块。该操作具体如图1-3中节点2所示。

Oracle SQL执行计划操作(1)——表相关操作_operator_03

图1-3 表相关操作TABLE ACCESS BY LOCAL INDEX ROWID示例

4)TABLE ACCESS BY GLOBAL INDEX ROWID

通过从全局索引(Global Index)中获取到的ROWID 访问表中的数据行。该操作和以上两个操作(TABLE ACCESS BY INDEX ROWID;TABLE ACCESS BY LOCAL INDEX ROWID)中的数据访问方式是一样的,只不过,该操作通过表的全局索引获取到ROWID后,再通过ROWID去读取相应表分区(Partition)的数据块。

--注:

      1)全局索引可以分区,也可以不分区,但即使分区,其与本地索引还是不同,相关具体差别,读者自己了解和思考下。

该操作具体如图1-4中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_plan_04

图1-4 表相关操作TABLE ACCESS BY GLOBAL INDEX ROWID示例

5)TABLE ACCESS BY USER ROWID

通过ROWID访问表中的数据行,ROWID也许被直接指定或来自索引。该操作就不需做过多解释了,因为ROWID是表中数据行的物理地址,其中包含了文件号、块号、块内槽号等信息,通过ROWID查询数据行应该还是比较高效的。该操作具体如图1-5中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_操作_05

图1-5 表相关操作TABLE ACCESS BY USER ROWID示例

6)TABLE ACCESS BY ROWID RANGE

通过指定一段范围的多个ROWID 来访问表中的数据行。该操作本质上和上述操作(TABLE ACCESS BY USER ROWID)是一样的,只不过上述操作中给出的是一个ROWID值,而该操作给出的是一个ROWID范围。该操作具体如图1-6中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_operator_06

图1-6 表相关操作TABLE ACCESS BY USER ROWID示例

7)TABLE ACCESS SAMPLE

以多数据块并行读取方式,对表相应段高水位线(HWM)下的采样数据块进行一个扫描。某些场景中,当我们不需要得到一个精确结果,而只需计算出一个大概结果时,我们就可以用这种采样方式来访问表。该操作又可以分为行采样(row sampling)和块采样(block sampling),也可以指定采样比例等选项,具体读者可参考官方或其他相关文档。语法示例具体如下所示。

SQL> select * from tab_name sample(10);       --取样10%的数据,row或block

SQL> select * from tab_name sample block(10); --取样10%的数据,block,但不能保证,如要保证block,需用full或index_ffs

SQL> select * from tab_name sample(0.1) seed(100);--取样0.1%,每次取样结果相同

该操作具体如图1-7中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_操作_07

图1-7 表相关操作TABLE ACCESS SAMPLE示例

8)TABLE ACCESS SAMPLE BY ROWID RANGE

通过指定一段范围的ROWID,对表相应段高水位线(HWM)下的采样数据块进行一个扫描。该操作具体如图1-8中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_table_08

图1-8 表相关操作TABLE ACCESS SAMPLE示例

9)TABLE ACCESS CLUSTER

通过索引簇键,访问簇表中的数据行。该操作具体如图1-9中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_操作_09

图1-9 表相关操作TABLE ACCESS CLUSTER示例

10)TABLE ACCESS HASH

通过哈希簇键,访问簇表中的数据行。该操作具体如图1-10中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_操作_10

图1-10 表相关操作TABLE ACCESS HASH示例

11)LOAD AS SELECT

以select语句作为行源,向目标表中直接加载数据。该操作有两个特点,一个是直接使用高水位线(HWM)之上的数据块,而不是先寻找高水位线下有空闲空间的数据块;另一个就是直接将数据写入数据文件,而不是先写到数据块缓存(Buffer Cache)里(该操作为直接路径加载,Direct Path)。该操作具体如图1-11中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_SQL_11

图1-11 表相关操作LOAD AS SELECT示例

12)EXTERNAL TABLE ACCESS FULL

从外部表读取数据行。该操作具体如图1-12中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_plan_12

图1-12 表相关操作EXTERNAL TABLE ACCESS FULL示例

13)FIXED TABLE FULL

通过完全扫描的方式访问固定表(名字以“X$”开头的系统内部表)。该操作具体如图1-13中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_plan_13

图1-13 表相关操作FIXED TABLE FULL示例

14)FIXED TABLE FIXED INDEX

通过索引方式访问固定表(名字以“X$”开头的系统内部表)。该操作具体如图1-14中节点1所示。

Oracle SQL执行计划操作(1)——表相关操作_table_14

图1-14 表相关操作FIXED TABLE FIXED INDEX示例