PostgreSQL中EXPLAIN的使用

版权声明:本文为博主原创之文章,未经博主允许谢绝转载。 https://blog.csdn.net/pg_hgdb/article/details/82460225

查询计划的结构是一个计划结点的树。最底层的结点是扫描结点:它们从表中返回未经处理的行。

1.EXPLAIN简介

EXPLAIN给计划树中每个结点都输出一行,显示基本的结点类型和计划器为该计划结点的执行所做的开销估计。 第一行(最上层的结点)是对该计划的总执行开销的估计。

举一个简单的例子来展示EXPLAIN的输出结果:

postgres=# explain select * from test01;
                        QUERY PLAN                        
----------------------------------------------------------
 Seq Scan on test01  (cost=0.00..35.50 rows=2550 width=4)
(1 row)

通常seq_page_cost的值将被设置为1.0,其它开销参数将相对于它来设置。由于示例中的查询没有WHERE子句,必须扫描表中的所有行,因此计划器只能选择使用一个简单的顺序扫描计划。查询计划中的参数从左至右分别为:

1)预估的启动开销。

2)预估的总开销。

3)计划结点输出行数的预估值。行数值不是计划结点处理或扫描过的行数,而是该结点发出的行数。这通常比被扫描的行数少一些, 因为有些被扫描的行会被应用于此结点上的任意WHERE子句条件过滤掉。 

4)计划结点预计输出的行平均宽度(以字节计算)。

开销的计算公式为: (页面读取数*seq_page_cost)+(扫描的行数*cpu_tuple_cost)。

接下来举例说明查询中带WHERE子句时的结果:

postgres=# explain select * from test03 where a < 4000;
                        QUERY PLAN                         
-----------------------------------------------------------
 Seq Scan on test03  (cost=0.00..170.00 rows=8028 width=8)
   Filter: (a < 4000)
(2 rows)

WHERE子句被当做一个“过滤器”条件附加到顺序扫描计划结点。 这意味着该计划结点为它扫描的每一行检查该条件,并且只输出通过该条件的行。物化结点在读取数据时将它保存在内存中,然后在每一次后续执行时从内存返回数据。

如果将WHERE语句中的限制变得更加严格,结果如下:

postgres=# explain select * from test03 where a < 100;
                               QUERY PLAN                                
-------------------------------------------------------------------------
 Bitmap Heap Scan on test03  (cost=5.83..53.31 rows=199 width=8)
   Recheck Cond: (a < 100)
   ->  Bitmap Index Scan on test03_a  (cost=0.00..5.78 rows=199 width=0)
         Index Cond: (a < 100)
(4 rows)

规划器决定使用的查询计划为:子计划结点访问访问一个索引来找出匹配索引条件的行的位置,然后上层计划结点实际地从表中取出那些行。

如果在WHERE子句中增加一个过滤条件,结果如下:

postgres=# explain select * from test03 where a < 100 and b = 4160;
                               QUERY PLAN                                
-------------------------------------------------------------------------
 Bitmap Heap Scan on test03  (cost=5.78..53.76 rows=1 width=8)
   Recheck Cond: (a < 100)
   Filter: (b = 4160)
   ->  Bitmap Index Scan on test03_a  (cost=0.00..5.78 rows=199 width=0)
         Index Cond: (a < 100)
(5 rows)

从结果可以看出,估计的输出行数减少, 但是没有减少开销,因为仍然需要访问相同的行集合。

2.EXPLAIN ANALYZE

可以通过使用EXPLAIN的ANALYZE选项来检查规划器估计值的准确性。通过使用这个选项,EXPLAIN会实际执行该查询,然后显示真实的行计数和在每个计划结点中累计的真实运行时间。

举一个例子展示 EXPLAIN ANALYZE的输出结果:

postgres=# explain analyze select * from test03 where a < 100 and b = 4160;
                                                     QUERY PLAN                 
                                     
--------------------------------------------------------------------------------
-------------------------------------
 Bitmap Heap Scan on test03  (cost=5.78..53.76 rows=1 width=8) (actual time=0.21
4..0.214 rows=0 loops=1)
   Recheck Cond: (a < 100)
   Filter: (b = 4160)
   Rows Removed by Filter: 193
   Heap Blocks: exact=44
   ->  Bitmap Index Scan on test03_a  (cost=0.00..5.78 rows=199 width=0) (actual
 time=0.018..0.018 rows=193 loops=1)
         Index Cond: (a < 100)
 Planning time: 0.062 ms
 Execution time: 0.232 ms
(9 rows)

actual time的值是以毫秒计的真实时间,而cost估计值的单位是虚构的,因此两者之间不太可能匹配上。示例中的结果里还显示了被过滤器移除的行数。
EXPLAIN有一个BUFFERS选项可以和ANALYZE一起使用来得到更多运行时统计信息,例如:

postgres=# explain (analyze,buffers) select * from test03 where a < 100 and b = 4160;
                                                     QUERY PLAN                 
                                     
--------------------------------------------------------------------------------
-------------------------------------
 Bitmap Heap Scan on test03  (cost=5.78..53.76 rows=1 width=8) (actual time=0.08
4..0.084 rows=0 loops=1)
   Recheck Cond: (a < 100)
   Filter: (b = 4160)
   Rows Removed by Filter: 193
   Heap Blocks: exact=44
   Buffers: shared hit=46
   ->  Bitmap Index Scan on test03_a  (cost=0.00..5.78 rows=199 width=0) (actual
 time=0.015..0.015 rows=193 loops=1)
         Index Cond: (a < 100)
         Buffers: shared hit=2
 Planning time: 0.052 ms
 Execution time: 0.099 ms
(11 rows)

BUFFERS提供的数字帮助我们标识查询的哪些部分是对 I/O 最敏感的。
因为EXPLAIN ANALYZE实际运行查询,如果你想要分析一个数据修改查询而不想改变你的表,你可以在分析完后使用回滚命令。
EXPLAIN ANALYZE显示的 Planning time是从一个已解析的查询生成查询计划并进行优化所花费的时间,其中不包括解析和重写。EXPLAIN ANALYZE显示的Execution time包括执行器的启动和关闭时间,以及运行被触发的任何触发器的时间,但是它不包括解析、重写或规划的时间。

By Kalath

猜你喜欢

转载自blog.csdn.net/pg_hgdb/article/details/82460225