首页 > 数据库 > > SQL执行计划介绍-详解
如SQL执行计划概述节中所说,EXPLAIN会显示执行计划,但并不会实际执行SQL语句。EXPLAIN ANALYZE和EXPLAIN PERFORMANCE两者都会实际执行SQL语句并返回执行信息。在这一节将详细解释执行计划及执行信息。
以如下SQL语句为例:
select
cjxh,
count(1)
from dwcjk
group by cjxh;
执行EXPLAIN的输出为:

执行计划字段解读(横向):
Vector前缀的算子是指向量化执行引擎算子,一般出现含有列存表的Query中。
执行计划层级解读(纵向):
表扫描算子,用CStore Scan的方式扫描表dwcjk。这一层的作用是把表dwcjk的数据从buffer或者磁盘上读上来输送给上层节点参与计算。
聚合算子,作用是把下层计算输送上来的算子做聚合操作(group by)。
Shuffle算子,此处GATHER类型的Shuffle算子作用是把数据从DN汇聚到CN。
存储格式转化算子,主要作用是把内存中列式格式数据转为行式数据,以便客户端展示。
需要注意的是最顶层算子为Data Node Scan时,需要设置enable_fast_query_shipping为off才能看到具体的执行计划,如下面这个计划:
explain select cjxh, count(1) from dwcjk group by cjxh;
QUERY PLAN
--------------------------------------------------
Data Node Scan (cost=0.00..0.00 rows=0 width=0)
Node/s: All datanodes
(2 rows)
设置enable_fast_query_shipping参数之后,执行计划显示如下:

执行计划中的关键字说明:
全表顺序扫描。
优化器决定使用两步的规划:最底层的规划节点访问一个索引,找出匹配索引条件的行的位置,然后上层规划节点真实地从表中抓取出那些行。独立地抓取数据行比顺序地读取它们的开销高很多,但是因为并非所有表的页面都被访问了,这么做实际上仍然比一次顺序扫描开销要少。使用两层规划的原因是,上层规划节点在读取索引标识出来的行位置之前,会先将它们按照物理位置排序,这样可以最小化独立抓取的开销。
如果在WHERE里面使用的好几个字段上都有索引,那么优化器可能会使用索引的AND或OR的组合。但是这么做要求访问两个索引,因此与只使用一个索引,而把另外一个条件只当作过滤器相比,这个方法未必是更优。
索引扫描可以分为以下几类,他们之间的差异在于索引的排序机制。
使用位图索引抓取数据页。
使用简单索引搜索,该方式表的数据行是以索引顺序抓取的,这样就令读取它们的开销更大,但是这里的行少得可怜,因此对行位置的额外排序并不值得。最常见的就是看到这种规划类型只抓取一行,以及那些要求ORDER BY条件匹配索引顺序的查询。因为那时候没有多余的排序步骤是必要的以满足ORDER BY。
嵌套循环,适用于被连接的数据子集较小的查询。在嵌套循环中,外表驱动内表,外表返回的每一行都要在内表中检索找到它匹配的行,因此整个查询返回的结果集不能太大(不能大于10000),要把返回子集较小的表作为外表,而且在内表的连接字段上建议要有索引。
哈希连接,适用于数据量大的表的连接方式。优化器使用两个表中较小的表,利用连接键在内存中建立hash表,然后扫描较大的表并探测散列,找到与散列匹配的行。Sonic和非Sonic的Hash Join的区别在于所使用hash表结构不同,不影响执行的结果集。
归并连接,通常情况下执行性能差于哈希连接。如果源数据已经被排序过,在执行融合连接时,并不需要再排序,此时融合连接的性能优于哈希连接。
对结果集进行排序。
EXPLAIN输出显示WHERE子句当作一个"filter"条件附属于顺序扫描计划节点。这意味着规划节点为它扫描的每一行检查该条件,并且只输出符合条件的行。预计的输出行数降低了,因为有WHERE子句。不过,扫描仍将必须访问所有 10000 行,因此开销没有降低;实际上它还增加了一些(确切的说,通过10000 * cpu_operator_cost)以反映检查WHERE条件的额外CPU时间。
LIMIT限定了执行结果的输出记录数。如果增加了LIMIT,那么不是所有的行都会被检索到。
在SQL调优过程中经常需要执行EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看SQL语句实际执行信息,通过对比实际执行与优化器的估算之间的差别来为优化提供依据。EXPLAIN PERFORMANCE相对于EXPLAIN ANALYZE增加了每个DN上的执行信息。
以如下SQL语句为例:
select count(1) from dwcjk group by cjxh;执行EXPLAIN PERFORMANCE输出为:



图中显示执行信息分为以下7个部分
这一部分主要显示的是静态信息,即在整个计划执行过程中不会变的信息,主要是一些join条件和一些filter信息。
这一部分显示的是整个计划中会将内存的使用情况打印出来的算子的内存使用信息,主要是Hash、Sort算子,包括算子峰值内存(peak memory),控制内存(control memory),估算内存使用(operator memory),执行时实际宽度(width),内存使用自动扩展次数(auto spread num),是否提前下盘(early spilled),以及下盘信息,包括重复下盘次数(spill Time(s)),内外表下盘分区数(inner/outer partition spill num),下盘文件数(temp file num),下盘数据量及最小和最大分区的下盘数据量(written disk IO [min, max] )。
这一部分显示的是每一个算子输出的目标列。
这一部分会将各个算子的执行时间、CPU、buffer的使用情况全部打印出来。
这一部分显示的是CN和DN、DN和DN建连的时间,以及存储层的一些执行信息。
这一部分主要打印总的执行时间和网络流量,包括了各个DN上初始化和结束阶段的最大最小执行时间、CN上的初始化、执行、结束阶段的时间,以及当前语句执行时系统可用内存、语句估算内存等信息。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69959250/viewspace-3159464/ ,如需转载,请注明出处,否则将追究法律责任。