PostgreSQL执行计划的解析
阅读原文时间:2022年04月04日阅读:1

一个顺序磁盘页面操作的cost值由系统参数seq_page_cost (floating point)参数指定的,由于这个参数默认为1.0,所以我们可以认为一次顺序磁盘页面操作的cost值为1。
下面
osdba=# explain select * from t;
QUERY PLAN
———————————————————-
Seq Scan on t  (cost=0.00 ..4621.00  rows=300000  width=10 )
(1 row)

cost=说明:

  • 第一个数字0.00表示启动cost,这是执行到返回第一行时需要的cost值。
  • 第二个数字4621.00表示执行整个SQL的cost

可以explain后加analyze来通过真实执行这个SQL来获得真实的执行计划和执行时间:.

osdba=# EXPLAIN ANALYZE SELECT * FROM t;

QUERY PLAN

-----------------------------------------------------------------------------------------------------------

Seq Scan on t  (cost=0.00..4621.00 rows=300000 width=10) (actual time=0.022 ..355.380rows=300000 loops=1)

Total runtime: 696.074 ms

actual time=中的第一个数字表示返回第一行需要的时间(叫启动时间),第二个数字表示执行这个整个花的时间。后面的rows=300000是实际的行数。

表顺序扫描由于是立即可以获得第一行,所以启动时间一般都是0,而如果是排序操作,则需要处理完所有行后才能返回第一行,所以排序操作是需要启动时间的,下表列出了哪些操作是需要启动时间的,哪些操作不是需要的:

执行计划运算类型

操作说明

是否有启动时间

Seq Scan

扫描表

无启动时间

Index Scan

索引扫描

无启动时间

Bitmap Index Scan

索引扫描

有启动时间

Bitmap Heap Scan

索引扫描

有启动时间

Subquery Scan

子查询

无启动时间

Tid Scan

ctid = …条件

无启动时间

Function Scan

函数扫描

无启动时间

Nested Loop

循环结合

无启动时间

Merge Join

合并结合

有启动时间

Hash Join

哈希结合

有启动时间

Sort

排序,ORDER BY操作

有启动时间

Hash

哈希运算

有启动时间

Result

函数扫描,和具体的表无关

无启动时间

Unique

DISTINCT,UNION操作

有启动时间

Limit

LIMIT,OFFSET操作

有启动时间

Aggregate

count, sum,avg, stddev集约函数

有启动时间

Group

GROUP BY分组操作

有启动时间

Append

UNION操作

无启动时间

Materialize

子查询

有启动时间

SetOp

INTERCECT,EXCEPT

有启动时

explain select distinct course_id from course where course_term = 'Fal02';
 
NOTICE:  QUERY PLAN:
 
Unique  (cost=12223.09..12339.76 rows=4667 width=4)
 
               -> Sort (cost=12223.09..12223.09 rows=46666 width=4)
 
               ->  Seq Scan on course  (cost=0.00..8279.99 rows=46666 width=4)
1.从下往上读
2.explain报告查询的操作,开启的消耗,查询总的消耗,访问的行数 访问的平均宽度
3.开启时间消耗是输出开始前的时间例如排序的时间
4.消耗包括磁盘检索页,cpu时间 
5.注意,每一步的cost包括上一步的
6.重要的是,explain 不是真正的执行一次查询 只是得到查询执行的计划和估计的花费
 
索引有用条件 当满足特定条件的元组数小于总的数目

1. cost

含义:这个计划节点的预计的启动开销和总开销

详细描述:启动开销是指一个计划节点在返回结果之前花费的开销,如果是在一个排序节点里,那就是指执行排序花费的开销。 总开销是指一个计划节点从开始到运行完成,即所有可用行被检索完后,总共花费的开销。实际上,一个节点的父节点可能会在子节点返回一部分结果后,停止继续读取剩余的行,如Limit节点。

2. rows

含义:这个计划节点的预计输出行数

详细描述:在带有ANALYZE选项时,SQL语句会实际运行,这时一个计划节点的代价输出会包含两部分,前面部分是预计的代价,后面部分是实际的代价。前面部分中rows是指预计输出行数,后面部分是指实际输出行数。如果中间节点返回的数据量过大,最终返回的数据量很小,或许可以考虑将中间节点以下的查询修改成物化视图的形式。

3. width

含义:这个计划节点返回行的预计平均宽度(以字节计算)

详细描述:如果一个扫描节点返回行的平均宽度明显小于子节点返回行的平均宽度,说明从子节点读取的大部分数据是无用的,或许应该考虑一下调整SQL语句或表的相关设计,比如让执行计划尽量选择Index Only Scan,或者对表进行垂直拆分。

4. actual time

含义:这个计划节点的实际启动时间和总运行时间

详细描述:启动时间是指一个计划节点在返回第一行记录之前花费的时间。 总运行时间是指一个计划节点从开始到运行完成,即所有可用行被检索完后,总共花费的时间。

5. loops

含义:这个计划节点的实际重启次数

详细描述:如果一个计划节点在运行过程中,它的相关参数值(如绑定变量)发生了变化,就需要重新运行这个计划节点。

6. Filter

含义:这个扫描节点的过滤条件

详细描述:对于一个表的扫描节点,如果相关的条件表达式不能对应到表上的某个索引,可能需要分析一下具体的原因和影响,比如该表相关的字段在表达式中需要进行隐式类型转换,那么即使在该字段上存在索引,也不可能被使用到。如:((b.intcol)::numeric > 99.0)

7. Index Cond

含义:这个索引扫描节点的索引匹配条件

详细描述:说明用到了表上的某个索引。

8. Rows Removed by Filter

含义:这个扫描节点通过过滤条件过滤掉的行数

详细描述:如果一个扫描节点的实际输出行数明显小于通过过滤条件过滤掉的行数,说明这个计划节点在运行过程中的大量计算是无用的,或者说是没有实际产出的,那么这个SQL语句或者表的相关设计可能不是特别好。