暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

解释执行计划 - 操作的类型

原创 不吃草的牛_Nick 2023-11-08
253

    操作的类型

有几百种不同的操作。当然了,要完全理解一个执行计划,你应该知道每一个操作都是用来做什么的。出于我们完成整个执行计划的目的,你只需要考虑四种主要类型的操作:独立操作、迭代操作、无关联组合操作以及关联组合操作。基本上,每种类型都有特定的行为,而了解这种行为就足够阅读执行计划了。

 

除了这四种类型之外,还可以将操作分为阻塞操作和非阻塞操作。简单来说,阻塞操作批量处理数据,非阻塞操作逐行处理数据。举例来说,排序操作是阻塞的,因为只有当所有输入行都被完全处理(排序)后才能返回输出的行,因为第一个输出行可能出现在输入数据集的任何地方。

 

而另一方面,应用简单限制条件的过滤器是非阻塞的,因为它单独验证每一行。很显然对于阻塞操作,必须将数据缓存到内存中(PGA)或磁盘上(临时表空间)。为简单起见,在完成一个执行计划时,你可以认为所有的操作都是阻塞操作。但是记住,大多数的操作实际上是非阻塞的,而且出于明显的原因,SQL引擎会尝试尽可能地避免缓存数据。

 

 独立操作

我将最多拥有一个子操作的所有非迭代操作(迭代操作将在下一节介绍)视为独立操作。大部分操作都是独立的。这使得执行计划的解释变得更容易,因为只有不到24种操作不属于这种类型。控制独立操作运行的规则除了10.3.1节中描述的规则之外,还有下面这条规则:

Ø  一个子操作最多被执行一次。

 

下面是一个查询和它的执行计划的例子,基于stand-alone.sql脚本生成的输出(图10-3提供了关于它的父-子关系的图形表示):

select deptno,count(*) from emp where job='CLERK' and sal<1200 group by deptno;



这个执行计划仅由独立操作组成。通过应用之前描述的规则,你会发现执行计划按照以下方式执行操作。

(1)操作0、操作1和操作2都有一个单独的子操作(分别是1、2和3);它们不可能是最先执行的操作。因此,执行从操作3开始。

(2)操作3通过应用"JOB"='CLERK'访问谓词来扫描emp_job_i索引。这样做时,它从索引上抽取四个rowid(此信息在A-Rows列中给出)并将它们传递给它的父操作(2)。

(3)操作2通过从操作3传递过来的四个rowid访问emp表。对于每个rowid,读取一行数据。接下来,它应用"SAL"<1200过滤谓词。这个过滤器会排除掉一条数据。余下的三条数据传递给它的父操作(1)。

(4)操作1在操作2传递过来的数据上执行一个GROUP BY操作。结果集减少到两条数据并传递给它的父操作(0)。

(5)操作0将数据发送给调用者。

 

注意Starts列是如何清晰地展示每一个操作都执行了一次的。

 

其中一条规则声明子操作在父操作之前被完整地执行。这大体上没错,但是当智能优化被引进来时情况就有些不一样了。可能发生的情况是,父操作判断完全执行子操作没有意义甚至根本不需要执行它。换句话说,父操作控制子操作的执行。我们来看两个常见的案例。注意,两个例子都摘自stand-alone.sql脚本生成的输出。

 

 COUNT STOPKEY 操作的优化

COUNT STOPKEY操作通常用于执行top-n查询。它的目标是一旦所需数据已经返回给了调用者就会停止处理。举例来说,下面查询的目的是只返回在emp表中找到的前10条数据:

select * FROM emp WHERE rownum <= 10;



1 - filter(ROWNUM<=10)

 

在这个执行计划中需要重点关注的是由操作2返回的行数被限制为10。即使操作2是对一个包含超过10条数据(实际上这张表包含14条数据)的表进行全表扫描也是这样的。

 

结果当必要的行数被处理完毕后操作1就停止了操作2的处理工作。但是要小心,因为阻塞操作是无法停止的。事实上,必须在它们向父操作返回数据之前完全处理它们。例如,在下面的查询中,因为ORDER BY子句,会读取emp表的所有行(14):

select * FROM (select * FROM emp ORDER BY sal DESC) WHERE rownum <= 10;



   FILTER操作的优化

FILTER操作不仅会在它的子操作向它传递数据的时候应用过滤条件,此外,它也能决定完全避免子操作以及所有依赖的操作(孙子操作等)的执行。例如,在下面的查询中,从操作1处应用的过滤谓词检查绑定变量的值是否会导致空的结果集。实际上,查询只有在满足:SAL_MIN<=:SAL_MAX过滤谓词的情况下才会返回数据:

select * FROM emp WHERE sal BETWEEN :sal_min AND :sal_max;



根据之前描述的规则,操作2应该是展示的执行计划中第一个被完全执行的操作。在现实中,查看Starts列后可以知道只有操作0和操作1被执行了。优化简单地避免了操作2的处理,因为数据无论如何也没有机会通过操作1应用的过滤条件。






「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论