EXPLAIN
EXPLAIN
显示语句的查询计划。
概要
EXPLAIN [ ( option [, ...] ) ] statement EXPLAIN [ANALYZE] [VERBOSE] statement
ANALYZE [ boolean ] VERBOSE [ boolean ] COSTS [ boolean ] BUFFERS [ boolean ] TIMING [ boolean ] FORMAT { TEXT | XML | JSON | YAML }
描述
EXPLAIN显示Greenplum或Postgres优化器为提供的语句生成的查询计划。 查询计划是节点的查询树计划。 计划中的每个节点代表一个单独的操作,例如表扫描,连接,聚合或排序。
应从下至上阅读计划,因为每个节点都会向其上方的节点中发送行。 计划的最底层节点通常是表扫描操作(顺序扫描,索引扫描或位图索引扫描)。 如果查询需要连接,聚集或排序(或原始行上的其他操作),则扫描节点上方将有其他节点来执行这些操作。 最顶层的计划节点通常是Greenplum数据库motion节点(重新分发,显式重新分发,广播或收集motion)。 这些操作负责在查询处理期间在segment实例之间移动行。
EXPLAIN的输出对于计划树中的每个节点都有一行, 显示基本节点类型以及计划者为执行该计划节点而进行的以下成本估算:
- cost — 优化器对运行该语句要花费多长时间的猜测(以任意成本单位衡量,但通常是指磁盘页获取)。 显示了两个成本编号:可以返回第一行之前的启动成本,以及返回所有行的总成本。 请注意,总成本假定将检索所有行,但并非总是如此(例如,如果使用LIMIT)。
- rows — 此计划节点输出的总行数。 这通常少于计划节点处理或扫描的实际行数,反映了任何WHERE子句条件的估计选择性。 理想情况下,顶级节点估计将近似查询实际返回,更新或删除的行数。
- width — 此计划节点输出的所有行的总字节数。
重要的是要注意,上级节点的成本包括其所有子节点的成本。 计划的最高节点具有该计划的估计总执行成本。 这是计划者要尽量减少的数字。 同样重要的是要意识到,成本只反映查询优化器关心的事情。 特别是,成本不考虑将结果行传输到客户端所花费的时间。
EXPLAIN ANALYZE导致语句实际执行,而不仅仅是做计划。 EXPLAIN ANALYZE优化器会显示实际结果以及计划者的估计。 这对于查看优化器的估计是否接近实际很有用。 除了EXPLAIN计划中显示的信息之外,EXPLAIN ANALYZE还将显示以下附加信息:
- 运行查询所花费的总时间(以毫秒为单位)。
- 计划节点操作中涉及的workers(segment)数。仅计算返回行的segment。
- 操作产生最多行的segment所返回的最大行数。 如果多个segment产生相等数量的行,则结束时间最长的一个就是选择的那个。
- 为一个操作生成最多行的segment的segment ID号。
- 对于相关操作,该操作使用的work_mem。
如果work_mem不足以在内存中执行该操作,则该计划将显示有多少数据溢出到磁盘,
以及最低性能segment需要多少次数据传递。
例如:
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
- 从产生最多行的segment中检索第一行所花费的时间(以毫秒为单位),以及从该segment中检索所有行所花费的总时间。 如果<time> to first row与<time> to end相同,则可以省略。
BEGIN; EXPLAIN ANALYZE ...; ROLLBACK;
仅可以指定ANALYZE和VERBOSE选项,并且只能按该顺序指定,而不要在括号中包含选项列表。
参数
- 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 ANALYZE命令期间运行的SQL语句从Greenplum数据库资源队列中排除。有关查询分析的更多信息,请参阅Greenplum数据库管理员指南中的“查询分析”。 有关资源队列的更多信息,请参阅Greenplum数据库管理员指南中的“使用资源队列进行资源管理”。
示例
为了说明如何读取EXPLAIN查询计划,请考虑一个非常简单的查询的示例:
EXPLAIN SELECT * FROM names WHERE name = 'Joelle'; QUERY PLAN ------------------------------------------------------------------------------- Gather Motion 3:1 (slice1; segments: 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: Pivotal Optimizer (GPORCA) version 3.23.0 (4 rows)
如果我们自下而上阅读计划,则查询优化器将从对names表的顺序扫描开始。 请注意,WHERE子句被用作过滤条件。 这意味着扫描操作将检查其扫描的每一行的条件,并仅输出通过条件的行。
扫描操作的结果将传递到gather motion操作。 在Greenplum数据库中,gather motion是将segment行发送到master。 在这种情况下,我们有3个segment实例发送到1个master实例(3:1)。 该操作在并行查询执行计划的slice1上进行。 在Greenplum数据库中,查询计划分为多个切片,以便查询计划的各个部分可以由这些segment并行处理。
该计划的估计启动成本为00.00(无成本),总成本为431.27。 优化器估计此查询将返回一行。
这是相同的查询,但成本估算被抑制:
EXPLAIN (COSTS FALSE) SELECT * FROM names WHERE name = 'Joelle'; QUERY PLAN ------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) -> Seq Scan on names Filter: (name = 'Joelle'::text) Optimizer: Pivotal Optimizer (GPORCA) version 3.23.0 (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, + "Segments": 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, + "Segments": 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": "Pivotal Optimizer (GPORCA) version 3.23.0" + } + } + ] (1 row)
EXPLAIN (FORMAT YAML) SELECT * FROM NAMES WHERE LOCATION='Sydney, Australia'; QUERY PLAN -------------------------------------------------------------- - Plan: + Node Type: "Gather Motion" + Senders: 3 + Receivers: 1 + Slice: 1 + Segments: 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 + Segments: 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: "Pivotal Optimizer (GPORCA) version 3.23.0" (1 row)
兼容性
在SQL标准中没有定义EXPLAIN语句。