云数据库 GAUSSDB-详解:执行计划

时间:2025-03-03 09:51:21

执行计划

以如下SQL语句为例:

1
SELECT * FROM t1, t2 WHERE t1.c1 = t2.c2;

执行EXPLAIN的输出为:

执行计划层级解读(纵向):

  1. 第一层:Seq Scan on t2

    表扫描算子,用Seq Scan的方式扫描表t2。这一层的作用是把表t2的数据从buffer或者磁盘上读上来输送给上层节点参与计算。

  2. 第二层:Hash

    Hash算子,作用是把下层计算输送上来的算子计算hash值,为后续hash join操作做数据准备。

  3. 第三层:Seq Scan on t1

    表扫描算子,用Seq Scan的方式扫描表t1。这一层的作用是把表t1的数据从buffer或者磁盘上读上来输送给上层节点参与hash join计算。

  4. 第四层:Hash Join

    join算子,主要作用是将t1表和t2表的数据通过hash join的方式连接,并输出结果数据。

执行计划中的主要关键字说明:

  1. 表访问方式
    • Seq Scan

      全表顺序扫描。

    • Index Scan

      优化器决定使用两步的规划:最底层的规划节点访问一个索引,找出匹配索引条件的行的位置,然后上层规划节点真实地从表中抓取出那些行。独立地抓取数据行比顺序地读取它们的开销高很多,但是因为并非所有表的页面都被访问了,这么做实际上仍然比一次顺序扫描开销要少。使用两层规划的原因是,上层规划节点在读取索引标识出来的行位置之前,会先将它们按照物理位置排序,这样可以最小化独立抓取的开销。

      如果在WHERE里面使用的好几个字段上都有索引,那么优化器可能会使用索引的AND或OR的组合。但是这么做要求访问两个索引,因此与只使用一个索引,而把另外一个条件只当作过滤器相比,这个方法未必是更优。

      根据索引排序机制的差异,索引扫描可以分为以下几类。

      • Bitmap Index Scan

        使用位图索引抓取数据页。

      • Index Scan using index_name

        使用简单索引搜索,该方式按照索引键的顺序在索引表中抓取数据。该方式最常用于在大数据量表中只抓取少量数据的情况,或者通过ORDER BY条件匹配索引顺序的查询,以减少排序时间。

      • Index-Only Scan

        当需要的所有信息都包含在索引中时,仅索引扫描便可获取所有数据,不需要引用表。

    • Bitmap Heap Scan

      从其他操作创建的位图中读取页面,过滤掉不符合条件的行。位图堆扫描可避免随机I/O,加快读取速度。

    • TID Scan

      通过TupleID扫描表。

    • Index Ctid Scan

      通过Ctid上的索引对表进行扫描。

    • CTE Scan

      CTE对子查询的操作进行评估并将查询结果临时存储,相当于一个临时表。CTE Scan算子对该临时表进行扫描。

    • Foreign Scan

      从远程数据源读取数据。

    • Function Scan

      获取函数返回的结果集,将它们作为从表中读取的行并返回。

    • Sample Scan

      查询并返回采样数据。

    • Subquery Scan

      读取子查询的结果。

    • Values Scan

      作为VALUES命令的一部分读取常量。

    • WorkTable Scan

      工作表扫描。在操作中间阶段读取,通常是使用WITH RECURSIVE声明的递归操作。

    • CS tore Index Ctid Scan

      按照索引的条件进行扫描,返回满足条件的tid集合。

    • CStore Index Heap Scan

      实现tid集合的交、差、并运算,并通过集合的结果获取对应元组。

  2. 表连接方式
    • Nested Loop

      嵌套循环,适用于被连接的数据子集较小的查询。在嵌套循环中,外表驱动内表,外表返回的每一行都要在内表中检索找到它匹配的行,因此整个查询返回的结果集不能太大(不能大于10000),要把返回子集较小的表作为外表,而且在内表的连接字段上建议要有索引。

    • (Sonic) Hash Join

      哈希连接,适用于数据量大的表的连接方式。优化器使用两个表中较小的表,利用连接键在内存中建立hash表,然后扫描较大的表并探测散列,找到与散列匹配的行。Sonic和非Sonic的Hash Join的区别在于所使用hash表结构不同,不影响执行的结果集。

    • Merge Join

      归并连接,通常情况下执行性能差于哈希连接。如果源数据已经被排序过,在执行融合连接时,并不需要再排序,此时融合连接的性能优于哈希连接。

  3. 运算符
    • sort

      对结果集进行排序。

    • filter

      EXPLAIN输出显示WHERE子句当作一个"filter"条件附属于顺序扫描计划节点。这意味着规划节点为它扫描的每一行检查该条件,并且只输出符合条件的行。预计的输出行数降低了,因为有WHERE子句。不过,扫描仍将必须访问所有 10000 行,因此开销没有降低;实际上它还增加了一些(确切的说,通过10000 * cpu_operator_cost)以反映检查WHERE条件的额外CPU时间。

    • LIMIT

      LIMIT限定了执行结果的输出记录数。如果增加了LIMIT,那么不是所有的行都会被检索到。

    • Append

      合并子操作的结果。

    • Aggregate

      将查询行产生的结果进行组合。可以是GROUPBY、UNION、SELECT DISTINCT子句等函数的组合。

    • BitmapAnd

      位图的AND操作,通过该操作组成匹配更复杂条件的位图。

    • BitmapOr

      位图的OR操作,通过该操作组成匹配更复杂条件的位图。

    • Gather

      将并行线程的数据汇总。

    • Group

      对行进行分组,以进行GROUP BY操作。

    • GroupAggregate

      聚合GROUP BY操作的预排序行。

    • Hash

      对查询行进行散列操作,以供父查询使用。通常用于执行JOIN操作。

    • HashAggregate

      使用哈希表聚合GROUP BY的结果行。

    • Merge Append

      以保留排序顺序的方式对子查询结果进行组合,可用于组合表分区中已排序的行。

    • Recursive Union

      对递归函数的所有步骤进行并集操作。

    • SetOp

      集合运算,如INTERSECT或EXCEPT。

    • Unique

      从有序的结果集中删除重复项。

    • HashSetOp

      一种用于 INTERSECT 或 EXCEPT 等集合操作的策略,它使用 Append 来避免预排序的输入。

    • LockRows

      锁定有问题的行以阻止其他查询写入,但允许读。

    • Materialize

      将子查询的结果存储在内存里,以方便父查询快速访问获取。

    • Result

      在不进行扫描的情况下返回一个值(比如硬编码的值)。

    • WindowAgg

      窗口聚合函数,一般由OVER语句触发。

    • Merge

      归并操作。

    • StartWith Operator

      层次查询算子,用于执行递归查询操作。

    • Index Cond

      索引扫描条件。

    • Cstore Index And

      实现tid集合的交运算,和CStore Index Heap Scan搭配使用。

    • Cstore Index Or

      实现tid集合的并运算,和CStore Index Heap Scan搭配使用。

  4. 其他关键字
    • Partitioned

      对具体分区的操作。

    • Partition Iterator

      分区迭代器,通常代表子查询是对分区的操作。

    • InitPlan

      非相关子计划。

support.huaweicloud.com/centralized-devg-v2-gaussdb/gaussdb_42_0227.html