EXPLAIN
EXPLAIN¶
显示语句的查询计划。
- 语法
- ``` sql
EXPLAIN [ ( option [, …] ) ] statement
EXPLAIN [ANALYZE] [VERBOSE] statement
其中`option`可以是以下之一: ``` sql ANALYZE [ boolean ] VERBOSE [ boolean ] COSTS [ boolean ] BUFFERS [ boolean ] TIMING [ boolean ] FORMAT { TEXT | XML | JSON | YAML }
- 描述
-
EXPLAIN
显示SeaboxMPP或Seabox优化器为提供的语句生成的查询计划。 查询计划是节点的查询树计划。计划中的每个节点代表一个单独的操作,例如表扫描,连接,聚合或排序。应从下至上阅读计划,因为每个节点都会向其上方的节点中发送行。 计划的最底层节点通常是表扫描操作(顺序扫描,索引扫描或位图索引扫描)。如果查询需要连接,聚集或排序(或原始行上的其他操作),则扫描节点上方将有其他节点来执行这些操作。最顶层的计划节点通常是SeaboxMPP数据库motion节点(重新分发,显式重新分发,广播或收集motion)。这些操作负责在查询处理期间在executor实例之间移动行。
EXPLAIN
的输出对于计划树中的每个节点都有一行, 显示基本节点类型以及计划者为执行该计划节点而进行的以下成本估算:-
cost — 优化器对运行该语句要花费多长时间的猜测(以任意成本单位衡量,但通常是指磁盘页获取)。显示了两个成本编号:可以返回第一行之前的启动成本,以及返回所有行的总成本。请注意,总成本假定将检索所有行,但并非总是如此(例如,如果使用
LIMIT
)。 -
rows — 此计划节点输出的总行数。这通常少于计划节点处理或扫描的实际行数,反映了任何
WHERE
子句条件的估计选择性。理想情况下,顶级节点估计将近似查询实际返回,更新或删除的行数。 -
width — 此计划节点输出的所有行的总字节数。
重要的是要注意,上级节点的成本包括其所有子节点的成本。 计划的最高节点具有该计划的估计总执行成本。 这是计划者要尽量减少的数字。同样重要的是要意识到,成本只反映查询优化器关心的事情。 特别是,成本不考虑将结果行传输到客户端所花费的时间。
EXPLAIN ANALYZE
导致语句实际执行,而不仅仅是做计划。EXPLAIN ANALYZE
优化器会显示实际结果以及计划者的估计。这对于查看优化器的估计是否接近实际很有用。 除了EXPLAIN
计划中显示的信息之外,EXPLAIN ANALYZE
还将显示以下附加信息:-
运行查询所花费的总时间(以毫秒为单位)。
-
计划节点操作中涉及的workers(executor)数。仅计算返回行的executor。
-
操作产生最多行的executor所返回的最大行数。如果多个executor产生相等数量的行,则结束时间最长的一个就是选择的那个。
-
为一个操作生成最多行的executor的executor ID号。
-
对于相关操作,该操作使用的
work_mem
。如果work_mem
不足以在内存中执行该操作,则该计划将显示有多少数据溢出到磁盘,以及最低性能executor需要多少次数据传递。 例如:
Work_mem used: 64K bytes avg, 64K bytes max (seg0). Work_mem wanted: 90K bytes avg, 90K bytes max (seg0) to abate workfile I/O affecting 2 workers. [seg0] pass 0: 488 groups made from 488 rows; 263 rows written to workfile [seg0] pass 1: 263 groups made from 263 rows
- 从产生最多行的executor中检索第一行所花费的时间(以毫秒为单位),以及从该executor中检索所有行所花费的总时间。如果<time> to first row与<time> to end相同,则可以省略。
重要:使用
ANALYZE
时实际上会执行该语句。 尽管EXPLAIN ANALYZE
将丢弃SELECT
将返回的任何输出,但是该语句的其他副作用将照常发生。 如果希望在DML语句上使用EXPLAIN ANALYZE
而不让命令影响您的数据,请使用以下方法:BEGIN; EXPLAIN ANALYZE ...; ROLLBACK;
仅可以指定
ANALYZE
和VERBOSE
选项,并且只能按该顺序指定,而不要在括号中包含选项列表。 -
- 参数
-
该SQL命令参数说明见下
ANALYZE
- 执行命令并显示实际运行时间和其他统计信息。 如果省略此参数,则默认为
FALSE
。 指定ANALYZE true
可以启用它。 VERBOSE
-
显示有关计划的其他信息。 具体来说,包括计划树中每个节点的输出列列表,模式限定表和函数名称,始终在表达式中使用范围表别名标记变量,并始终打印要显示其统计信息的每个触发器的名称。
如果省略此参数,则默认为
FALSE
; 指定VERBOSE true
启用它。 COSTS
- 包括有关每个计划节点的估计启动成本和总成本以及估计的行数和估计的每行宽度的信息。 如果省略此参数,则默认为
TRUE
;指定COSTS false
禁用它。 BUFFERS
- 包括有关缓冲区使用情况的信息。
具体来说,包括命中,读取,弄脏和写入的共享块的数量,命中,读取,弄脏和写入的局部块的数量以及读写的临时块的数量。命中表示避免读取,因为在需要时已在高速缓存中找到该块。 共享块包含来自常规表和索引的数据;本地块包含来自临时表和索引的数据;临时块包含用于排序,哈希,物化计划节点和类似情况的短期工作数据。被弄脏的块数表示此查询已更改的先前未修改的块数;而写入的块数则表示此后端在查询处理期间从缓存中逐出的先前处理的块数。 上级节点显示的块数包括其所有子节点使用的块数。在文本格式中,仅打印非零值。 仅当还启用了
ANALYZE
时,才可以使用此参数。如果省略此参数,则默认为FALSE
; 指定BUFFERS true
启用它。 TIMING
- 在输出中包括实际的启动时间和在每个节点上花费的时间。 重复读取系统时钟的开销可能会在某些系统上显着降低查询速度,因此,当仅需要实际的行计数而不是确切的时间时,将此参数设置为
FALSE
可能会很有用。即使使用此选项关闭了节点级计时,也始终会测量整个语句的运行时间。 仅当还启用了ANALYZE
时,才可以使用此参数。默认为TRUE
。 FORMAT
- 指定输出格式,可以是
TEXT
,XML
,JSON
或YAML
。 非文本输出包含与文本输出格式相同的信息,但程序更易于解析。此参数默认为TEXT
。 boolean
- 指定是打开还是关闭所选选项。 您可以写入
TRUE
,ON
或1
以启用该选项,而可以写入FALSE
,OFF
或0
以禁用该选项。布尔值也可以省略,在这种情况下,假定为TRUE
。 statement
- 希望查看其执行计划的任何
SELECT
,INSERT
,UPDATE
,DELETE
,VALUES
,EXECUTE
,DECLARE
或CREATE TABLE AS
语句。
- 注解
- 为了使查询优化器在优化查询时能够做出合理的决策,应运行
ANALYZE
语句以记录有关表内数据分布的统计信息。如果您尚未执行此操作(或者自上次运行ANALYZE
以来,表中数据的统计分布已发生重大变化),则估计成本不太可能符合查询的实际属性,因此可能会选一个较差的查询计划。 - 示例
-
为了说明如何读取
EXPLAIN
查询计划,请考虑一个非常简单的查询的示例:EXPLAIN SELECT * FROM names WHERE name = 'Joelle'; QUERY PLAN ------------------------------------------------------------------------------- Gather Motion 3:1 (slice1; executors: 3) (cost=0.00..431.27 rows=1 width=58) -> Seq Scan on names (cost=0.00..431.27 rows=1 width=58) Filter: (name = 'Joelle'::text) Optimizer: SeaboxSQL query optimizer (4 rows)
如果我们自下而上阅读计划,则查询优化器将从对
names
表的顺序扫描开始。 请注意,WHERE
子句被用作过滤条件。这意味着扫描操作将检查其扫描的每一行的条件,并仅输出通过条件的行。扫描操作的结果将传递到gather motion操作。 在SeaboxMPP数据库中,gathermotion是将executor行发送到coordinator。在这种情况下,我们有3个executor实例发送到1个coordinator实例(3:1)。该操作在并行查询执行计划的
slice1
上进行。在SeaboxMPP数据库中,查询计划分为多个切片,以便查询计划的各个部分可以由这些executor并行处理。该计划的估计启动成本为
00.00
(无成本),总成本为431.27
。 优化器估计此查询将返回一行。这是相同的查询,但成本估算被抑制:
EXPLAIN (COSTS FALSE) SELECT * FROM names WHERE name = 'Joelle'; QUERY PLAN ------------------------------------------ Gather Motion 3:1 (slice1; executors: 3) -> Seq Scan on names Filter: (name = 'Joelle'::text) Optimizer: SeaboxSQL query optimizer (4 rows)
这是使用JSON格式的相同查询:
EXPLAIN (FORMAT JSON) SELECT * FROM names WHERE name = 'Joelle'; QUERY PLAN ----------------------------------------------- [ + { + "Plan": { + "Node Type": "Gather Motion", + "Senders": 3, + "Receivers": 1, + "Slice": 1, + "executors": 3, + "Gang Type": "primary reader", + "Startup Cost": 0.00, + "Total Cost": 431.27, + "Plan Rows": 1, + "Plan Width": 58, + "Plans": [ + { + "Node Type": "Seq Scan", + "Parent Relationship": "Outer", + "Slice": 1, + "executors": 3, + "Gang Type": "primary reader", + "Relation Name": "names", + "Alias": "names", + "Startup Cost": 0.00, + "Total Cost": 431.27, + "Plan Rows": 1, + "Plan Width": 58, + "Filter": "(name = 'Joelle'::text)"+ } + ] + }, + "Settings": { + "Optimizer": "SeaboxSQL query optimizer" + } + } + ] (1 row)
如果存在索引,并且我们使用带有可索引
WHERE
条件的查询,则EXPLAIN
可能会显示不同的计划。此查询使用YAML格式生成带有索引扫描的计划:EXPLAIN (FORMAT YAML) SELECT * FROM NAMES WHERE LOCATION='Sydney, Australia'; QUERY PLAN -------------------------------------------------------------- - Plan: + Node Type: "Gather Motion" + Senders: 3 + Receivers: 1 + Slice: 1 + executors: 3 + Gang Type: "primary reader" + Startup Cost: 0.00 + Total Cost: 10.81 + Plan Rows: 10000 + Plan Width: 70 + Plans: + - Node Type: "Index Scan" + Parent Relationship: "Outer" + Slice: 1 + executors: 3 + Gang Type: "primary reader" + Scan Direction: "Forward" + Index Name: "names_idx_loc" + Relation Name: "names" + Alias: "names" + Startup Cost: 0.00 + Total Cost: 7.77 + Plan Rows: 10000 + Plan Width: 70 + Index Cond: "(location = 'Sydney, Australia'::text)"+ Settings: + Optimizer: "SeaboxSQL query optimizer" (1 row)
- 兼容性说明
- 在SQL标准中没有定义
EXPLAIN
语句。 - 相关SQL命令
ANALYZE