EXPLAIN

Name

EXPLAIN -- 显示语句执行规划

Synopsis

EXPLAIN [ ANALYZE ] [ VERBOSE ] statement

描述

这条命令显示PostgreSQL规划器为所提供的语句生成的执行规划。 执行规划显示语句引用的表是如何被扫描的--- 是简单的顺序扫描,还是索引扫描等 --- 并且如果引用了多个表, 采用了什么样的连接算法从每个输入的表中取出所需要的记录。

显示出来的最关键的部分是预计的语句执行开销, 这就是规划器对运行该语句所需时间的估计(以磁盘页面存取为单位计量)。 实际上显示了两个数字:返回第一行记录前的启动时间, 和返回所有记录的总时间。对于大多数查询而言,关心的是总时间,但是, 在某些环境下,比如一个 EXISTS 子查询里, 规划器将选择最小启动时间而不是最小总时间(因为执行器在获取一条记录后总是要停下来)。 同样,如果你用一条 LIMIT 子句限制返回的记录数, 规划器会在最终的开销上做一个合理的插值以计算哪个规划开销最省。

ANALYZE 选项导致查询被实际执行,而不仅仅是规划。 它在显示中增加了在每个规划节点内部花掉的总时间(以毫秒计)和它实际返回的行数。 这些数据对搜索该规划器的预期是否和现实相近很有帮助。

Important: 要记住的是查询实际上在使用 ANALYZE 的时候是执行的。 尽管 EXPLAIN 会抛弃任何 SELECT 会返回的输出, 但是其它查询的副作用还是一样会发生的。 如果你在 INSERTUPDATEDELETE,或者 EXECUTE 语句里使用 EXPLAIN ANALYZE,而且还不想让查询影响你的数据, 用下面的方法:

BEGIN;
EXPLAIN ANALYZE ...;
ROLLBACK;

参数

ANALYZE

执行命令并显示实际运行时间。

VERBOSE

显示规划树完整的内部表现形式,而不仅仅是一个摘要。通常,这个选项只是在调试 PostgreSQL 的时候有用。 VERBOSE 输出可能是打印得工整的,也可能不是, 具体取决于配置参数 explain_pretty_print

语句

任何SELECTINSERTUPDATEDELETEEXECUTE,或者 DECLARE 语句。

注意

PostgreSQL 里只有很少的一些文档介绍有关优化器计算开销的问题。参考 Section 13.1 获取更多信息。

为了让 PostgreSQL 查询规划器在优化查询的时候做出合理的判断, 我们需要运行 ANALYZE 语句以记录有关数据在表中的分布的统计信息。 如果你没做过这件事情(或者如果自上次 ANALYZE 以来, 表中的数据统计分布发生了显著变化),那么计算出来的开销预计很可能与查询的实际属性并不对应, 因此很可能会选取一个比较差的查询规划。

PostgreSQL 7.3 以前,查询规划是以 NOTICE 消息的形式发出来的。 现在它的显示格式是一个查询结果(格式化成了类似一个有单个文本字段的表。)

例子

显示一个对只有一个 int4 列和 10000 行的表的简单查询的查询规划:

EXPLAIN SELECT * FROM foo;

                       QUERY PLAN
---------------------------------------------------------
 Seq Scan on foo  (cost=0.00..155.00 rows=10000 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)

下面是一个使用了聚集函数的查询的查询规划:

EXPLAIN SELECT sum(i) FROM foo WHERE i < 4;

                             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=39.53..39.53 rows=1 width=8) (actual time=0.66..0.67 rows=7 loops=1)
   ->  Index Scan using test_pkey on test  (cost=0.00..32.97 rows=1311 width=8) (actual time=0.05..0.39 rows=99 loops=1)
         Index Cond: ((id > $1) AND (id < $2))
 Total runtime: 0.85 msec
(4 rows)
   

注意这里显示的数字, 甚至还有选择的查询策略都有可能在各个 PostgreSQL版本之间不同--因为规划器在不断改进。 另外,ANALYZE 命令使用随机的采样来估计数据统计; 因此,一次新的 ANALYZE 运行之后开销估计可能会变化, 即使数据的实际分布没有改变也这样。

兼容性

在 SQL 标准中没有EXPLAIN 语句。