EXPLAIN

Name

EXPLAIN -- 显示一个语句的执行规划

Synopsis

EXPLAIN [ ( option [, ...] ) ] statement
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement

where option can be one of:
                            
    ANALYZE [ boolean ]
    VERBOSE [ boolean ]
    COSTS [ boolean ]
    BUFFERS [ boolean ]
    FORMAT { TEXT | XML | JSON | YAML }

描述

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

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

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

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

BEGIN;
EXPLAIN ANALYZE ...;
ROLLBACK;

只有ANALYZEVERBOSE选项可以被指定, 并且仅仅按那个顺序,不把该选项列在括号内。在PostgreSQL9.0 之前,该unparenthesized语法是唯一支持的。希望所有的新选项仅仅在parenthesized 语法中支持。

参数

ANALYZE

执行命令并显示实际运行时间,此参数缺省FALSE

VERBOSE

显示关于计划的附加信息。尤其,包括计划树中的每个节点的输出列列表,模式修饰的表 和函数名称,总是有射程表别名的表达式的标号变量,并且总是输出显示统计的每个触发 器的名称。该参数默认为FALSE

COSTS

包括预计启动项上的信息和每个计划节点的总成本,以及估计行数和估计的每行的宽度。 该参数默认为TRUE

BUFFERS

包含关于缓冲区使用的信息。尤其,包括共享块触发、读和写的数量,本地块触发、读 和写的数量,以及临时快读和写的数量。共享块、本地块和临时块分别包含表和索引,临时 表和临时索引,以及在排序和物化计划中使用的磁盘块。为上层节点显示的块数包括 所有其子节点使用的块数。该参数仅可能与ANALYZE参数一起使用。 它默认为FALSE

FORMAT

指定输出格式,输出格式可以是 TEXT, XML, JSON,或者YAML。非文本输出包含与文本输出 格式相同的信息,但更容易对程序解析。该参数默认为TEXT

boolean

指定选中的选项是该开启还是关闭。你可以写TRUE, ON, 或者1来启动该选项,并且用FALSE, OFF, 或者0来关闭它。 boolean 值也可以被忽略, 此时假定为 TRUE

statement

你想要查看规划结果的任何SELECTINSERTUPDATEDELETEVALUESEXECUTEDECLARECREATE TABLE AS语句之一。

注意

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

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

为了测量在执行计划中的每个节点的运行时间成本,EXPLAIN ANALYZE 的当前实现可以添加大量剖析开销来查询执行。因此,在一个查询中运行 EXPLAIN ANALYZE有时会花费比常规执行查询的时间明显更长的时间。 开销的数量依赖于查询的性质。

例子

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

EXPLAIN SELECT * FROM foo;

                       QUERY PLAN
---------------------------------------------------------
 Seq Scan on foo  (cost=0.00..155.00 rows=10000 width=4)
(1 row)

Here is the same query, with JSON formatting:

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)

Here is the same query, but in YAML output:

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输出时留给读者作为练习的。

这是成本抑制的相同计划:

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=39.53..39.53 rows=1 width=8) (actual time=0.661..0.672 rows=7 loops=1)
   ->  Index Scan using test_pkey on test  (cost=0.00..32.97 rows=1311 width=8) (actual time=0.050..0.395 rows=99 loops=1)
         Index Cond: ((id > $1) AND (id < $2))
 Total runtime: 0.851 ms
(4 rows)

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

兼容性

在SQL标准中没有EXPLAIN语句。

又见

ANALYZE