PostgreSQL 提供了 EXPLAIN
语句,它可以用来分析 SQL 的执行情况。本章将对其进行讨论。
简介
explain
语句返回 PostgreSQL 规划器为给定 SQL 语句生成的执行计划。它显示了一条语句涉及的表将通过索引扫描或顺序扫描等方式进行扫描,以及如果使用多张表,将使用什么样的连接算法。
它的语法如下:
EXPLAIN [ ( 选项 [, ...] ) ] SQL语句;
选项
的可选值是:
以下选项的
boolen
是一个开关,通过传递TRUE
或FALSE
来打开或关闭某个选项。
ANALYZE [ boolean ]
:该选项导致先执行SQL语句
,然后返回实际运行时的统计信息,包括每个计划节点花费的总运行时间以及实际返回的行数。它真实地执行了 SQL 语句,并丢弃执行结果。如果要分析INSERT/UPDATA/DELETE
等语句,并且不想影响实际数据,应该将explain
放在事务中,并进行回滚。VERBOSE [ boolean ]
:显示有关计划的附加信息COSTS [ boolean ]
:包括每个计划节点的估计成功和总成本。以及查询计划中的估计行数和每行的估计宽度。BUFFERS [ boolean ]
:向缓冲区添加信息,仅在ANALYZE
启用是才能使用。TIMING [ boolean ]
:输出实际启动时间和每个节点花费的时间。仅在启用ANALYZE
时才能使用。SUMMARY [ boolean ]
:在查询计划后添加摘要信息,比如总计时。FORMAT { TEXT | XML | JSON | YAML }
:指定查询计划的输出格式,默认为TEXT
。
示例
对 film
进行简单的 EXPLAIN
EXPLAIN SELECT * FROM film;
/*结果
QUERY PLAN
----------------------------------------------------------
Seq Scan on film (cost=0.00..64.00 rows=1000 width=384)
*/
按指定 film_id
返回电影的 EXPLAIN
由于 film_id
已建立索引,所以它使用的是按索引扫描,而不是顺序扫描。
要抑制成本,可以使用 COSTS
选项:
使用聚合函数:
EXPLAIN SELECT COUNT(*) FROM film;
/* 结果
QUERY PLAN
--------------------------------------------------------------
Aggregate (cost=66.50..66.51 rows=1 width=8)
-> Seq Scan on film (cost=0.00..64.00 rows=1000 width=0)
*/
使用多表连接:
EXPLAIN
SELECT
f.film_id,
title,
name category_name
FROM
film f
INNER JOIN film_category fc
ON fc.film_id = f.film_id
INNER JOIN category c
ON c.category_id = fc.category_id
ORDER BY
title;
/* 结果
QUERY PLAN
--------------------------------------------------------------------------------------
Sort (cost=149.64..152.14 rows=1000 width=87)
Sort Key: f.title
-> Hash Join (cost=77.86..99.81 rows=1000 width=87)
Hash Cond: (fc.category_id = c.category_id)
-> Hash Join (cost=76.50..95.14 rows=1000 width=21)
Hash Cond: (fc.film_id = f.film_id)
-> Seq Scan on film_category fc (cost=0.00..16.00 rows=1000 width=4)
-> Hash (cost=64.00..64.00 rows=1000 width=19)
-> Seq Scan on film f (cost=0.00..64.00 rows=1000 width=19)
-> Hash (cost=1.16..1.16 rows=16 width=72)
-> Seq Scan on category c (cost=0.00..1.16 rows=16 width=72)
*/
添加 ANALYZE
,将实际运行时统计信息添加到输出中:
EXPLAIN ANALYZE
SELECT
f.film_id,
title,
name category_name
FROM
film f
INNER JOIN film_category fc
ON fc.film_id = f.film_id
INNER JOIN category c
ON c.category_id = fc.category_id
ORDER BY
title;
/* 结果 QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------
Sort (cost=149.64..152.14 rows=1000 width=87) (actual time=3.652..3.693 rows=1000 loops=1)
Sort Key: f.title
Sort Method: quicksort Memory: 93kB
-> Hash Join (cost=77.86..99.81 rows=1000 width=87) (actual time=2.266..2.769 rows=1000 loops=1)
Hash Cond: (fc.category_id = c.category_id)
-> Hash Join (cost=76.50..95.14 rows=1000 width=21) (actual time=2.022..2.398 rows=1000 loops=1)
Hash Cond: (fc.film_id = f.film_id)
-> Seq Scan on film_category fc (cost=0.00..16.00 rows=1000 width=4) (actual time=0.100..0.151 rows=1000 loops=1)
-> Hash (cost=64.00..64.00 rows=1000 width=19) (actual time=1.894..1.895 rows=1000 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 59kB
-> Seq Scan on film f (cost=0.00..64.00 rows=1000 width=19) (actual time=0.013..1.743 rows=1000 loops=1)
-> Hash (cost=1.16..1.16 rows=16 width=72) (actual time=0.183..0.184 rows=16 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> Seq Scan on category c (cost=0.00..1.16 rows=16 width=72) (actual time=0.137..0.139 rows=16 loops=1)
Planning Time: 0.300 ms
Execution Time: 3.793 ms
*/