闲谈Oracle执行计划的步骤顺序
经过长时间学习Oracle,于是和大家分享一下,看完本文你肯定有不少收获,希望本文能教会你更多东西。Oracle执行计划的每一步返回一组行,它们或者为下一步所使用,或者在最后一步时返回给发出SQL语句的用户或应用。由每一步返回的一组行叫做行源(row
source)。下面得树状图显示了从一步到另一步行数据的流动情况。每步的编号反映了在你观察Oracle执行计划时所示步骤的顺序(如何观察Oracle执行计划将被简短地说明)。一般来说这并不是每一步被执行的先后顺序。
Oracle执行计划的每一步或者从数据库中检索行,或者接收来自一个或多个行源的行数据作为输入:
由红色字框指出的步骤从数据库中的数据文件中物理检索数据。这种步骤被称之为存取路径,后面会详细介绍在Oracle可以使用的存取路径:
◆第3步和第6步分别的从EMP表和SALGRADE表读所有的行。
◆第5步在PK_DEPTNO索引中查找由步骤3返回的每个DEPTNO值。它找出与DEPT表中相关联的那些行的ROWID。
◆第4步从DEPT表中检索出ROWID为第5步返回的那些行。
由黑色字框指出的步骤在行源上操作,如做2表之间的关联,排序,或过滤等操作,后面也会给出详细的介绍:
◆第2步实现嵌套的循环操作(相当于C语句中的嵌套循环),接收从第3步和第4步来的行源,把来自第3步源的每一行与它第4步中相应的行连接在一起,返回结果行到第1步。
◆第1步完成一个过滤器操作。它接收来自第2步和第6步的行源,消除掉第2步中来的,在第6步有相应行的那些行,并将来自第2步的剩下的行返回给发出语句的用户或应用。
实现Oracle执行计划步骤的顺序
Oracle执行计划中的步骤不是按照它们编号的顺序来实现的:Oracle首先实现树结构图形里作为叶子出现的那些步骤(例如步骤3、5、6)。由每一步返回的行称为它下一步骤的行源。然后Oracle实现父步骤。
举例来说,为了执行图5-1中的语句,Oracle以下列顺序实现这些步骤: 首先,Oracle实现步骤3,并一行一行地将结果行返回给第2步。 对第3步返回的每一行,Oracle实现这些步骤:
◆Oracle实现步骤5,并将结果ROWID返回给第4步。
◆Oracle实现步骤4,并将结果行返回给第2步。
◆Oracle实现步骤2,将接受来自第3步的一行和来自第4步的一行,并返回给第1步一行。
◆Oracle实现步骤6,如果有结果行的话,将它返回给第1步。
◆Oracle实现步骤1,如果从步骤6返回行,Oracle将来自第2步的行返回给发出SQL语句的用户。
注意Oracle对由第3步返回的每一行实现步骤5,4,2,6一次。许多父步骤在它们能执行之前只需要来自它们子步骤的单一行。对这样的父步骤来说,只要从子步骤已返回单一行时立即实现父步骤(可能还有Oracle执行计划的其余部分)。如果该父步骤的父步骤同样可以通过单一行返回激活的话,那么它也同样被执行。所以,执行可以在树上串联上去,可能包含Oracle执行计划的余下部分。对于这样的操作,可以使用first_rows作为优化目标以便于实现快速响应用户的请求。
对每个由子步骤依次检索出来的每一行,Oracle就实现父步骤及所有串联在一起的步骤一次。对由子步骤返回的每一行所触发的父步骤包括表存取,索引存取,嵌套的循环连接和过滤器。
有些父步骤在它们被实现之前需要来自子步骤的所有行。对这样的父步骤,直到所有行从子步骤返回之前Oracle不能实现该父步骤。这样的父步骤包括排序,排序一合并的连接,组功能和总计。对于这样的操作,不能使用first_rows作为优化目标,而可以用all_rows作为优化目标,使该中类型的操作耗费的资源最少。
有时语句执行时,并不是象上面说的那样一步一步有先有后的进行,而是可能并行运行,如在实际环境中,3、5、4步可能并行运行,以便取得更好的效率。从上面的树型图上,是很难看出各个操作执行的先后顺序,而通过Oracle生成的另一种形式的Oracle执行计划,则可以很容易的看出哪个操作先执行,哪个后执行,这样的Oracle执行计划是我们真正需要的,后面会给出详细说明。现在先来看一些预备知识。