On this page
Important
EXPLAIN
解释—显示语句的执行计划
Synopsis
EXPLAIN [ ( option [, ...] ) ] statement
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement
where option can be one of:
ANALYZE [ boolean ]
VERBOSE [ boolean ]
COSTS [ boolean ]
BUFFERS [ boolean ]
TIMING [ boolean ]
SUMMARY [ boolean ]
FORMAT { TEXT | XML | JSON | YAML }
Description
此命令显示 PostgreSQL 计划程序为提供的语句生成的执行计划。执行计划显示了如何扫描语句所引用的表(通过普通 Sequences 扫描,索引扫描等),以及如果引用了多个表,将使用哪种联接算法将每个表中所需的行汇总在一起 Importing 表。
显示中最关键的部分是估计的语句执行成本,这是计划者对运行该语句将花费多长时间的猜测(以任意成本单位衡量,但通常是指磁盘页的获取)。实际上显示了两个数字:可以返回第一行之前的启动成本,以及返回所有行的总成本。对于大多数查询来说,总成本是很重要的,但是在诸如EXISTS
中的子查询之类的情况下,计划者将选择最小的启动成本,而不是最小的总成本(因为 Actuator 无论如何会在获得一行之后停止运行)。另外,如果使用LIMIT
子句限制要返回的行数,则计划程序会在端点成本之间进行适当的插值,以估计哪个计划确实最便宜。
ANALYZE
选项使语句实际执行,而不仅是计划的。然后,将实际的运行时统计信息添加到显示中,包括每个计划节点内花费的总经过时间(以毫秒为单位)及其实际返回的总行数。这对于查看计划者的估计是否接近实际很有用。
Tip
请记住,使用ANALYZE
选项时,该语句实际上已执行。尽管EXPLAIN
会丢弃SELECT
返回的任何输出,但该语句的其他副作用仍会照常发生。如果希望在INSERT
,UPDATE
,DELETE
,CREATE TABLE AS
或EXECUTE
语句上使用EXPLAIN ANALYZE
而不让该命令影响您的数据,请使用以下方法:
BEGIN;
EXPLAIN ANALYZE ...;
ROLLBACK;
只能指定ANALYZE
和VERBOSE
选项,并且只能以此 Sequences 指定,而不要在括号中包含选项列表。在 PostgreSQL 9.0 之前,唯一支持无括号语法。期望所有新选项仅在括号语法中受支持。
Parameters
ANALYZE
- 执行命令并显示实际运行时间和其他统计信息。此参数默认为
FALSE
。
- 执行命令并显示实际运行时间和其他统计信息。此参数默认为
VERBOSE
- 显示有关计划的其他信息。具体来说,包括计划树中每个节点的输出列列表,模式限定表和函数名称,始终在表达式中使用范围表别名标记变量,并始终打印要显示其统计信息的每个触发器的名称。此参数默认为
FALSE
。
- 显示有关计划的其他信息。具体来说,包括计划树中每个节点的输出列列表,模式限定表和函数名称,始终在表达式中使用范围表别名标记变量,并始终打印要显示其统计信息的每个触发器的名称。此参数默认为
COSTS
- 包括有关每个计划节点的估计启动和总成本以及估计的行数和估计的每行宽度的信息。此参数默认为
TRUE
。
- 包括有关每个计划节点的估计启动和总成本以及估计的行数和估计的每行宽度的信息。此参数默认为
BUFFERS
- 包括有关缓冲区使用情况的信息。具体来说,包括命中,读取,弄脏和写入的共享块数,命中,读取,弄脏和写入的本地块数以及读写的临时块数。 * hit *表示避免读取,因为在需要时已在高速缓存中找到该块。共享块包含常规表和索引中的数据;本地块包含来自临时表和索引的数据;而临时块包含用于排序,散列,实体化计划节点和类似情况的短期工作数据。 * dirted *的块数表示此查询已更改的先前未修改的块数; 写入的块数表示此后端在查询处理期间从缓存中逐出的先前处理的块数。上级节点显示的块数包括其所有子节点使用的块数。在文本格式中,仅打印非零值。仅当还启用了
ANALYZE
时,才可以使用此参数。默认为FALSE
。
- 包括有关缓冲区使用情况的信息。具体来说,包括命中,读取,弄脏和写入的共享块数,命中,读取,弄脏和写入的本地块数以及读写的临时块数。 * hit *表示避免读取,因为在需要时已在高速缓存中找到该块。共享块包含常规表和索引中的数据;本地块包含来自临时表和索引的数据;而临时块包含用于排序,散列,实体化计划节点和类似情况的短期工作数据。 * dirted *的块数表示此查询已更改的先前未修改的块数; 写入的块数表示此后端在查询处理期间从缓存中逐出的先前处理的块数。上级节点显示的块数包括其所有子节点使用的块数。在文本格式中,仅打印非零值。仅当还启用了
TIMING
- 在输出中包括实际的启动时间和在每个节点上花费的时间。在某些系统上,重复读取系统时钟的开销可能会大大降低查询的速度,因此,当仅需要实际的行计数而不是确切的时间时,将此参数设置为
FALSE
可能会很有用。即使使用此选项关闭了节点级计时,也始终会测量整个语句的运行时间。仅当还启用了ANALYZE
时,才可以使用此参数。默认为TRUE
。
- 在输出中包括实际的启动时间和在每个节点上花费的时间。在某些系统上,重复读取系统时钟的开销可能会大大降低查询的速度,因此,当仅需要实际的行计数而不是确切的时间时,将此参数设置为
SUMMARY
- 在查询计划之后包括摘要信息(例如,总计计时信息)。使用
ANALYZE
时默认包含摘要信息,否则默认不包含摘要信息,但可以使用此选项启用摘要信息。EXPLAIN EXECUTE
中的计划时间包括从缓存中获取计划所需的时间和重新计划所需的时间(如有必要)。
- 在查询计划之后包括摘要信息(例如,总计计时信息)。使用
FORMAT
- 指定输出格式,可以是 TEXT,XML,JSON 或 YAML。非文本输出包含与文本输出格式相同的信息,但程序更易于解析。此参数默认为
TEXT
。
- 指定输出格式,可以是 TEXT,XML,JSON 或 YAML。非文本输出包含与文本输出格式相同的信息,但程序更易于解析。此参数默认为
boolean
- 指定是打开还是关闭所选选项。您可以编写
TRUE
,ON
或1
启用该选项,并编写FALSE
,OFF
或0
禁用该选项。 *boolean
*的值也可以省略,在这种情况下假定为TRUE
。
- 指定是打开还是关闭所选选项。您可以编写
statement
- 您希望查看其执行计划的任何
SELECT
,INSERT
,UPDATE
,DELETE
,VALUES
,EXECUTE
,DECLARE
,CREATE TABLE AS
或CREATE MATERIALIZED VIEW AS
语句。
- 您希望查看其执行计划的任何
Outputs
命令的结果是为* statement
*选择的计划的 Literals 描述,可以选择在执行统计信息中进行 Comments。 Section 14.1描述了提供的信息。
Notes
为了使 PostgreSQL 查询计划者在优化查询时能够做出合理的决策,对于查询中使用的所有表,pg_statistic数据都应该是最新的。通常autovacuum daemon会自动处理。但是,如果表的内容最近发生了重大变化,则可能需要手动进行ANALYZE,而不是 await 自动清理以适应变化。
为了衡量执行计划中每个节点的运行时成本,当前的EXPLAIN ANALYZE
实现将分析开销添加到查询执行中。结果,在查询上运行EXPLAIN ANALYZE
有时可能比正常执行查询花费更长的时间。开销量取决于查询的性质以及所使用的平台。最坏的情况发生在计划节点本身每次执行只需要很少时间的计划节点上,以及在 os 调用相对较慢的机器上获取一天中的时间的机器上。
Examples
要在具有单个integer
列和 10000 行的表上显示简单查询的计划,请执行以下操作:
EXPLAIN SELECT * FROM foo;
QUERY PLAN
---------------------------------------------------------
Seq Scan on foo (cost=0.00..155.00 rows=10000 width=4)
(1 row)
这是相同的查询,具有 JSON 输出格式:
EXPLAIN (FORMAT JSON) SELECT * FROM foo;
QUERY PLAN
--------------------------------
[ +
{ +
"Plan": { +
"Node Type": "Seq Scan",+
"Relation Name": "foo", +
"Alias": "foo", +
"Startup Cost": 0.00, +
"Total Cost": 155.00, +
"Plan Rows": 10000, +
"Plan Width": 4 +
} +
} +
]
(1 row)
如果存在索引,并且我们使用具有可索引的WHERE
条件的查询,则EXPLAIN
可能会显示不同的计划:
EXPLAIN SELECT * FROM foo WHERE i = 4;
QUERY PLAN
--------------------------------------------------------------
Index Scan using fi on foo (cost=0.00..5.98 rows=1 width=4)
Index Cond: (i = 4)
(2 rows)
这是相同的查询,但格式为 YAML:
EXPLAIN (FORMAT YAML) SELECT * FROM foo WHERE i='4';
QUERY PLAN
-------------------------------
- Plan: +
Node Type: "Index Scan" +
Scan Direction: "Forward"+
Index Name: "fi" +
Relation Name: "foo" +
Alias: "foo" +
Startup Cost: 0.00 +
Total Cost: 5.98 +
Plan Rows: 1 +
Plan Width: 4 +
Index Cond: "(i = 4)"
(1 row)
XML 格式留给 Reader 练习。
这是同一计划,其成本估算被抑制:
EXPLAIN (COSTS FALSE) SELECT * FROM foo WHERE i = 4;
QUERY PLAN
----------------------------
Index Scan using fi on foo
Index Cond: (i = 4)
(2 rows)
这是使用聚合函数进行查询的查询计划示例:
EXPLAIN SELECT sum(i) FROM foo WHERE i < 10;
QUERY PLAN
---------------------------------------------------------------------
Aggregate (cost=23.93..23.93 rows=1 width=4)
-> Index Scan using fi on foo (cost=0.00..23.92 rows=6 width=4)
Index Cond: (i < 10)
(3 rows)
这是使用EXPLAIN EXECUTE
显示准备好的查询的执行计划的示例:
PREPARE query(int, int) AS SELECT sum(bar) FROM test
WHERE id > $1 AND id < $2
GROUP BY foo;
EXPLAIN ANALYZE EXECUTE query(100, 200);
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=9.54..9.54 rows=1 width=8) (actual time=0.156..0.161 rows=11 loops=1)
Group Key: foo
-> Index Scan using test_pkey on test (cost=0.29..9.29 rows=50 width=8) (actual time=0.039..0.091 rows=99 loops=1)
Index Cond: ((id > $1) AND (id < $2))
Planning time: 0.197 ms
Execution time: 0.225 ms
(6 rows)
当然,此处显示的具体数字取决于所涉及表的实际内容。还请注意,由于计划程序的改进,PostgreSQL 版本之间的数字甚至选择的查询策略可能会有所不同。另外,ANALYZE
命令使用随机采样来估计数据统计信息;因此,即使表中的实际数据分配没有变化,也可以在重新运行ANALYZE
之后更改成本估算。
Compatibility
在 SQL 标准中没有定义EXPLAIN
语句。