EXPLAIN
更新时间:2026-06-25
EXPLAIN
显示语句的查询计划。
语法
SQL
1 EXPLAIN [ ( option [, ...] ) ] statement
2 EXPLAIN [ANALYZE] [VERBOSE] statement
3 ```
4
5
6 其中`option`可以是以下之一:
7
8 ``` sql
9 ANALYZE [ boolean ]
10 VERBOSE [ boolean ]
11 COSTS [ boolean ]
12 BUFFERS [ boolean ]
13 TIMING [ boolean ]
14 FORMAT { TEXT | XML | JSON | YAML }
15 ```
16
17
18
19
20## 描述
21
22`EXPLAIN`显示PalopgMPP或Palopg优化器为提供的语句生成的查询计划。 查询计划是节点的查询树计划。计划中的每个节点代表一个单独的操作,例如表扫描,连接,聚合或排序。
23
24 应从下至上阅读计划,因为每个节点都会向其上方的节点中发送行。 计划的最底层节点通常是表扫描操作(顺序扫描,索引扫描或位图索引扫描)。如果查询需要连接,聚集或排序(或原始行上的其他操作),则扫描节点上方将有其他节点来执行这些操作。最顶层的计划节点通常是PalopgMPP数据库motion节点(重新分发,显式重新分发,广播或收集motion)。这些操作负责在查询处理期间在executor实例之间移动行。
25
26 `EXPLAIN`的输出对于计划树中的每个节点都有一行, 显示基本节点类型以及计划者为执行该计划节点而进行的以下成本估算:
27
28
29 - **cost** — 优化器对运行该语句要花费多长时间的猜测(以任意成本单位衡量,但通常是指磁盘页获取)。显示了两个成本编号:可以返回第一行之前的启动成本,以及返回所有行的总成本。请注意,总成本假定将检索所有行,但并非总是如此(例如,如果使用`LIMIT`)。
30
31 - **rows** — 此计划节点输出的总行数。这通常少于计划节点处理或扫描的实际行数,反映了任何`WHERE`子句条件的估计选择性。理想情况下,顶级节点估计将近似查询实际返回,更新或删除的行数。
32
33 - **width** — 此计划节点输出的所有行的总字节数。
34
35 重要的是要注意,上级节点的成本包括其所有子节点的成本。 计划的最高节点具有该计划的估计总执行成本。 这是计划者要尽量减少的数字。同样重要的是要意识到,成本只反映查询优化器关心的事情。 特别是,成本不考虑将结果行传输到客户端所花费的时间。
36
37 `EXPLAIN ANALYZE`导致语句实际执行,而不仅仅是做计划。 `EXPLAIN ANALYZE`优化器会显示实际结果以及计划者的估计。这对于查看优化器的估计是否接近实际很有用。 除了`EXPLAIN`计划中显示的信息之外,`EXPLAIN ANALYZE`还将显示以下附加信息:
38
39 - 运行查询所花费的总时间(以毫秒为单位)。
40
41 - 计划节点操作中涉及的*workers*(executor)数。仅计算返回行的executor。
42
43 - 操作产生最多行的executor所返回的最大行数。如果多个executor产生相等数量的行,则结束时间最长的一个就是选择的那个。
44
45 - 为一个操作生成最多行的executor的executor ID号。
46
47 - 对于相关操作,该操作使用的`work_mem`。如果`work_mem`不足以在内存中执行该操作,则该计划将显示有多少数据溢出到磁盘,以及最低性能executor需要多少次数据传递。 例如:
48
49 ``` sql
50 Work_mem used: 64K bytes avg, 64K bytes max (seg0).
51 Work_mem wanted: 90K bytes avg, 90K bytes max (seg0) to abate workfile
52 I/O affecting 2 workers.
53 [seg0] pass 0: 488 groups made from 488 rows; 263 rows written to
54 workfile
55 [seg0] pass 1: 263 groups made from 263 rows
56 ```
57
58 - 从产生最多行的executor中检索第一行所花费的时间(以毫秒为单位),以及从该executor中检索所有行所花费的总时间。如果*\<time\> to first row*与*\<time\> to end*相同,则可以省略。
59
60
61 重要:使用`ANALYZE`时实际上会执行该语句。 尽管`EXPLAIN ANALYZE`将丢弃`SELECT`将返回的任何输出,但是该语句的其他副作用将照常发生。 如果希望在DML语句上使用`EXPLAIN ANALYZE`而不让命令影响您的数据,请使用以下方法:
62
63 ``` sql
64 BEGIN;
65 EXPLAIN ANALYZE ...;
66 ROLLBACK;
67 ```
68
69
70 仅可以指定`ANALYZE`和`VERBOSE`选项,并且只能按该顺序指定,而不要在括号中包含选项列表。
71
72
73
74## 参数
75
76该SQL命令参数说明见下
77
78 `ANALYZE`
79 : 执行命令并显示实际运行时间和其他统计信息。 如果省略此参数,则默认为`FALSE`。 指定`ANALYZE true`可以启用它。
80
81 `VERBOSE`
82 : 显示有关计划的其他信息。 具体来说,包括计划树中每个节点的输出列列表,模式限定表和函数名称,始终在表达式中使用范围表别名标记变量,并始终打印要显示其统计信息的每个触发器的名称。
83
84 如果省略此参数,则默认为`FALSE`; 指定`VERBOSE true`启用它。
85
86 `COSTS`
87 : 包括有关每个计划节点的估计启动成本和总成本以及估计的行数和估计的每行宽度的信息。 如果省略此参数,则默认为`TRUE`;指定`COSTS false`禁用它。
88
89 `BUFFERS`
90 : 包括有关缓冲区使用情况的信息。
91 具体来说,包括命中,读取,弄脏和写入的共享块的数量,命中,读取,弄脏和写入的局部块的数量以及读写的临时块的数量。命中表示避免读取,因为在需要时已在高速缓存中找到该块。 共享块包含来自常规表和索引的数据;本地块包含来自临时表和索引的数据;临时块包含用于排序,哈希,物化计划节点和类似情况的短期工作数据。被弄脏的块数表示此查询已更改的先前未修改的块数;而写入的块数则表示此后端在查询处理期间从缓存中逐出的先前处理的块数。 上级节点显示的块数包括其所有子节点使用的块数。在文本格式中,仅打印非零值。 仅当还启用了`ANALYZE`时,才可以使用此参数。如果省略此参数,则默认为`FALSE`; 指定`BUFFERS true`启用它。
92
93 `TIMING`
94 : 在输出中包括实际的启动时间和在每个节点上花费的时间。 重复读取系统时钟的开销可能会在某些系统上显着降低查询速度,因此,当仅需要实际的行计数而不是确切的时间时,将此参数设置为`FALSE`可能会很有用。即使使用此选项关闭了节点级计时,也始终会测量整个语句的运行时间。 仅当还启用了`ANALYZE`时,才可以使用此参数。默认为`TRUE`。
95
96 `FORMAT`
97 : 指定输出格式,可以是`TEXT`,`XML`,`JSON`或`YAML`。 非文本输出包含与文本输出格式相同的信息,但程序更易于解析。此参数默认为`TEXT`。
98
99 `boolean`
100 : 指定是打开还是关闭所选选项。 您可以写入`TRUE`,`ON`或`1`以启用该选项,而可以写入`FALSE`,`OFF`或`0`以禁用该选项。布尔值也可以省略,在这种情况下,假定为`TRUE`。
101
102 `statement`
103 : 希望查看其执行计划的任何`SELECT`,`INSERT`,`UPDATE`,`DELETE`,`VALUES`,`EXECUTE`, `DECLARE`或`CREATE TABLE AS`语句。
104
105
106
107注解
108: 为了使查询优化器在优化查询时能够做出合理的决策,应运行`ANALYZE`语句以记录有关表内数据分布的统计信息。如果您尚未执行此操作(或者自上次运行`ANALYZE`以来,表中数据的统计分布已发生重大变化),则估计成本不太可能符合查询的实际属性,因此可能会选一个较差的查询计划。
109
110
111
112
113## 示例
114
115为了说明如何读取`EXPLAIN`查询计划,请考虑一个非常简单的查询的示例:
116
117 ``` sql
118 EXPLAIN SELECT * FROM names WHERE name = 'Joelle';
119 QUERY PLAN
120 -------------------------------------------------------------------------------
121 Gather Motion 3:1 (slice1; executors: 3) (cost=0.00..431.27 rows=1 width=58)
122 -> Seq Scan on names (cost=0.00..431.27 rows=1 width=58)
123 Filter: (name = 'Joelle'::text)
124 Optimizer: PalopgSQL query optimizer
125 (4 rows)
126 ```
127
128 如果我们自下而上阅读计划,则查询优化器将从对`names`表的顺序扫描开始。 请注意,`WHERE`子句被用作过滤条件。这意味着扫描操作将检查其扫描的每一行的条件,并仅输出通过条件的行。
129
130 扫描操作的结果将传递到*gather motion*操作。 在PalopgMPP数据库中,*gathermotion*是将executor行发送到coordinator。在这种情况下,我们有3个executor实例发送到1个coordinator实例(3:1)。该操作在并行查询执行计划的`slice1`上进行。在PalopgMPP数据库中,查询计划分为多个切片,以便查询计划的各个部分可以由这些executor并行处理。
131
132 该计划的估计启动成本为`00.00`(无成本),总成本为`431.27`。 优化器估计此查询将返回一行。
133
134 这是相同的查询,但成本估算被抑制:
135
136 ``` sql
137 EXPLAIN (COSTS FALSE) SELECT * FROM names WHERE name = 'Joelle';
138 QUERY PLAN
139 ------------------------------------------
140 Gather Motion 3:1 (slice1; executors: 3)
141 -> Seq Scan on names
142 Filter: (name = 'Joelle'::text)
143 Optimizer: PalopgSQL query optimizer
144 (4 rows)
145 ```
146
147 这是使用JSON格式的相同查询:
148
149 ``` sql
150 EXPLAIN (FORMAT JSON) SELECT * FROM names WHERE name = 'Joelle';
151 QUERY PLAN
152 -----------------------------------------------
153 [ +
154 { +
155 "Plan": { +
156 "Node Type": "Gather Motion", +
157 "Senders": 3, +
158 "Receivers": 1, +
159 "Slice": 1, +
160 "executors": 3, +
161 "Gang Type": "primary reader", +
162 "Startup Cost": 0.00, +
163 "Total Cost": 431.27, +
164 "Plan Rows": 1, +
165 "Plan Width": 58, +
166 "Plans": [ +
167 { +
168 "Node Type": "Seq Scan", +
169 "Parent Relationship": "Outer", +
170 "Slice": 1, +
171 "executors": 3, +
172 "Gang Type": "primary reader", +
173 "Relation Name": "names", +
174 "Alias": "names", +
175 "Startup Cost": 0.00, +
176 "Total Cost": 431.27, +
177 "Plan Rows": 1, +
178 "Plan Width": 58, +
179 "Filter": "(name = 'Joelle'::text)"+
180 } +
181 ] +
182 }, +
183 "Settings": { +
184 "Optimizer": "PalopgSQL query optimizer" +
185 } +
186 } +
187 ]
188 (1 row)
189 ```
190
191
192 如果存在索引,并且我们使用带有可索引`WHERE`条件的查询,则`EXPLAIN`可能会显示不同的计划。此查询使用YAML格式生成带有索引扫描的计划:
193
194 ``` sql
195 EXPLAIN (FORMAT YAML) SELECT * FROM NAMES WHERE LOCATION='Sydney, Australia';
196 QUERY PLAN
197 --------------------------------------------------------------
198 - Plan: +
199 Node Type: "Gather Motion" +
200 Senders: 3 +
201 Receivers: 1 +
202 Slice: 1 +
203 executors: 3 +
204 Gang Type: "primary reader" +
205 Startup Cost: 0.00 +
206 Total Cost: 10.81 +
207 Plan Rows: 10000 +
208 Plan Width: 70 +
209 Plans: +
210 - Node Type: "Index Scan" +
211 Parent Relationship: "Outer" +
212 Slice: 1 +
213 executors: 3 +
214 Gang Type: "primary reader" +
215 Scan Direction: "Forward" +
216 Index Name: "names_idx_loc" +
217 Relation Name: "names" +
218 Alias: "names" +
219 Startup Cost: 0.00 +
220 Total Cost: 7.77 +
221 Plan Rows: 10000 +
222 Plan Width: 70 +
223 Index Cond: "(location = 'Sydney, Australia'::text)"+
224 Settings: +
225 Optimizer: "PalopgSQL query optimizer"
226 (1 row)
227 ```
228
229
230
231
232兼容性说明
233: 在SQL标准中没有定义`EXPLAIN`语句。
234
235
236
237相关SQL命令
238: `ANALYZE`
评价此篇文章
