性能分析

159
2023/08/01 11:35:09

PostgreSQL 提供了 EXPLAIN 语句,它可以用来分析 SQL 的执行情况。本章将对其进行讨论。

简介

它返回的最重要和最有用的信息是,返回第一行数据之前的起始成本及返回完整结果集的总成本。

它的语法如下:

EXPLAIN [ ( 选项 [, ...] ) ] SQL语句;

选项 的可选值是:

以下选项的 boolen 是一个开关,通过传递 TRUEFALSE 来打开或关闭某个选项。

  • 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

按指定 film_id 返回电影的 EXPLAIN

EXPLAIN SELECT * FROM film WHERE film_id = 100;

/*结果
                               QUERY PLAN
------------------------------------------------------------------------
 Index Scan using film_pkey on film  (cost=0.28..8.29 rows=1 width=384)
   Index Cond: (film_id = 100)
*/   

由于 film_id 已建立索引,所以它使用的是按索引扫描,而不是顺序扫描。

要抑制成本,可以使用 COSTS 选项:

 EXPLAIN (COSTS FALSE) SELECT * FROM film WHERE film_id = 100;
 /*结果
             QUERY PLAN
------------------------------------
 Index Scan using film_pkey on film
   Index Cond: (film_id = 100)
*/   

使用聚合函数:

使用多表连接:

 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
 */