os: centos 7.4
postgresql: 9.6.8

explain 是 postgresql 查看执行计划最直接的方式。

explain 语法

EXPLAIN [ ( option [, ...] ) ] statement
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement这里 option可以是:ANALYZE [ boolean ]VERBOSE [ boolean ]COSTS [ boolean ]BUFFERS [ boolean ]TIMING [ boolean ]FORMAT { TEXT | XML | JSON | YAML }

explain 查看

现在有 user,role,user_role 三个表的关联,来获取登录用户的角色权限。
如下

mondb=# explain
SELECT tu.user_id,tu.user_first_name::text || tu.user_last_name::text AS user_name,tr.role_id,tr.role_nameFROM t_base_user tu,t_base_role tr,t_base_user_role turWHERE 1 = 1 AND tu.user_id = tur.user_id AND tr.role_id = tur.role_id AND tu.user_status = '1' AND tr.role_status = '1'ORDER BY tr.role_id, tu.user_id;QUERY PLAN
---------------------------------------------------------------------------------------Sort  (cost=3.94..3.97 rows=9 width=57)Sort Key: tr.role_id, tu.user_id->  Hash Join  (cost=2.41..3.80 rows=9 width=57)Hash Cond: ((tur.role_id)::text = (tr.role_id)::text)->  Hash Join  (cost=1.24..2.48 rows=9 width=19)Hash Cond: ((tur.user_id)::text = (tu.user_id)::text)->  Seq Scan on t_base_user_role tur  (cost=0.00..1.11 rows=11 width=9)->  Hash  (cost=1.12..1.12 rows=9 width=16)->  Seq Scan on t_base_user tu  (cost=0.00..1.12 rows=9 width=16)Filter: ((user_status)::text = '1'::text)->  Hash  (cost=1.09..1.09 rows=7 width=19)->  Seq Scan on t_base_role tr  (cost=0.00..1.09 rows=7 width=19)Filter: ((role_status)::text = '1'::text)
(13 rows)mondb=#

以这一行为例:-> Seq Scan on t_base_user_role tur (cost=0.00..1.11 rows=11 width=9) ,说下每行后面类似 (cost=0.00..1.11 rows=11 width=9) 所代表的含义。
有这个输出是因为 option 的 COSTS 默认为 true,即 explain 等价于 explain (COSTS true)

那这个 COSTS 的具体含义是:包括每一个计划结点的估计启动和总代价,以及估计的行数和每行的宽度。这个参数默认被设置为TRUE。

显示中最重要的部分是估计出的语句执行代价,它是计划器对于该语句要运行多久的猜测(以任意的代价单位度量,但是习惯上表示取磁盘页面的次数)。
事实上会显示两个数字:在第一行能被返回前的启动代价,以及返回所有行的总代价。
对于大部分查询来说总代价是最重要的,但是在一些情景中(如EXISTS中的子查询),计划器将选择更小的启动代价来代替最小的总代价(因为因为执行器将在得到一行后停止)。此外,如果你用一个LIMIT子句限制返回行的数量,计划器会在终端代价之间做出适当的插值来估计到底哪个计划是真正代价最低的。

cost

总时间(单位:毫秒)
cost=0.00..1.11 是怎么计算出来的?估计很多人都想搞清楚。
其中:
0.00代表估计的启动开销。在输出阶段可以开始之前消耗的时间,例如在一个排序结点里执行排序的时间。
1.11代表估计的总开销。这个估计值基于的假设是计划结点会被运行到完成,即所有可用的行都被检索。实际上一个结点的父结点可能很快停止读所有可用的行

这里涉及了postgresql 几个参数:

seq_page_cost:       连续块扫描操作的单个块的cost. 例如全表扫描
random_page_cost:    随机块扫描操作的单个块的cost. 例如索引扫描
cpu_tuple_cost:      处理每条记录的CPU开销(tuple:关系中的一行记录)
cpu_index_tuple_cost:扫描每个索引条目带来的CPU开销
cpu_operator_cost:   操作符或函数带来的CPU开销.(需要注意函数以及操作符对应的函数的三态, 执行计划会根据三态做优化, 关系到多条记录时三态对应的调用次数是需要关心的)

查看当前设置

mondb=# select name,setting from pg_settings pswhere ps.name in ('seq_page_cost','random_page_cost','cpu_tuple_cost','cpu_index_tuple_cost','cpu_operator_cost');name         | setting
----------------------+---------cpu_index_tuple_cost | 0.005cpu_operator_cost    | 0.0025cpu_tuple_cost       | 0.01random_page_cost     | 4seq_page_cost        | 1
(5 rows)

总成本=seq_page_cost*relpages+cpu_tuple_cost*reltuples

mondb=# select relpages,reltuples from pg_class where relname='t_base_user_role';
 relpages | reltuples
----------+-----------
        1 |        11
(1 row)

带入公式:

1(seq_page_cost)*1(relpages)+0.01(cpu_tuple_cost)*11(reltuples)=1.11

有过滤条件的公式,比如 >=,多了一个 cpu_operation_cost 的成本。
1(seq_page_cost)*1(relpages)+0.01(cpu_tuple_cost)*11(reltuples)+0.0025(cpu_operation_cost)*11(reltuples)

rows

计划结点输出行数的估计值。同样,也假定该结点能运行到完成。
rows=11

mondb=# select reltuples from pg_class where relname='t_base_user_role';
 reltuples
-----------
        11
(1 row)

width

计划结点输出的行平均宽度(以字节计算)
width=9


mondb=# select sum(length(user_id)),sum(length(role_id)),
       (sum(length(user_id)) + sum(length(role_id))) /count(1)
  from t_base_user_role; sum | sum | ?column?
-----+-----+----------
  59 |  30 |        8
(1 row)

explain analyze

analyze 代表语句真实执行了。所以会有类似 (actual time=0.263..0.265 rows=7 loops=1)的输出

mondb=# explain analyze
SELECT tu.user_id,tu.user_first_name::text || tu.user_last_name::text AS user_name,tr.role_id,tr.role_nameFROM t_base_user tu,t_base_role tr,t_base_user_role turWHERE 1 = 1 AND tu.user_id = tur.user_id AND tr.role_id = tur.role_id AND tu.user_status = '1' AND tr.role_status = '1'ORDER BY tr.role_id, tu.user_id;QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------Sort  (cost=3.94..3.97 rows=9 width=57) (actual time=0.263..0.265 rows=7 loops=1)Sort Key: tr.role_id, tu.user_idSort Method: quicksort  Memory: 25kB->  Hash Join  (cost=2.41..3.80 rows=9 width=57) (actual time=0.194..0.214 rows=7 loops=1)Hash Cond: ((tur.role_id)::text = (tr.role_id)::text)->  Hash Join  (cost=1.24..2.48 rows=9 width=19) (actual time=0.063..0.076 rows=7 loops=1)Hash Cond: ((tur.user_id)::text = (tu.user_id)::text)->  Seq Scan on t_base_user_role tur  (cost=0.00..1.11 rows=11 width=9) (actual time=0.010..0.011 rows=11 loops=1)->  Hash  (cost=1.12..1.12 rows=9 width=16) (actual time=0.029..0.029 rows=7 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 9kB->  Seq Scan on t_base_user tu  (cost=0.00..1.12 rows=9 width=16) (actual time=0.013..0.020 rows=7 loops=1)Filter: ((user_status)::text = '1'::text)->  Hash  (cost=1.09..1.09 rows=7 width=19) (actual time=0.063..0.063 rows=7 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 9kB->  Seq Scan on t_base_role tr  (cost=0.00..1.09 rows=7 width=19) (actual time=0.034..0.041 rows=7 loops=1)Filter: ((role_status)::text = '1'::text)Planning time: 0.607 msExecution time: 0.351 ms
(18 rows)

explain (analyze true)

mondb=# explain (analyze true)
SELECT tu.user_id,tu.user_first_name::text || tu.user_last_name::text AS user_name,tr.role_id,tr.role_nameFROM t_base_user tu,t_base_role tr,t_base_user_role turWHERE 1 = 1 AND tu.user_id = tur.user_id AND tr.role_id = tur.role_id AND tu.user_status = '1' AND tr.role_status = '1'ORDER BY tr.role_id, tu.user_id;QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------Sort  (cost=3.94..3.97 rows=9 width=57) (actual time=0.120..0.120 rows=7 loops=1)Sort Key: tr.role_id, tu.user_idSort Method: quicksort  Memory: 25kB->  Hash Join  (cost=2.41..3.80 rows=9 width=57) (actual time=0.077..0.091 rows=7 loops=1)Hash Cond: ((tur.role_id)::text = (tr.role_id)::text)->  Hash Join  (cost=1.24..2.48 rows=9 width=19) (actual time=0.031..0.040 rows=7 loops=1)Hash Cond: ((tur.user_id)::text = (tu.user_id)::text)->  Seq Scan on t_base_user_role tur  (cost=0.00..1.11 rows=11 width=9) (actual time=0.004..0.005 rows=11 loops=1)->  Hash  (cost=1.12..1.12 rows=9 width=16) (actual time=0.016..0.016 rows=7 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 9kB->  Seq Scan on t_base_user tu  (cost=0.00..1.12 rows=9 width=16) (actual time=0.007..0.011 rows=7 loops=1)Filter: ((user_status)::text = '1'::text)->  Hash  (cost=1.09..1.09 rows=7 width=19) (actual time=0.030..0.030 rows=7 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 9kB->  Seq Scan on t_base_role tr  (cost=0.00..1.09 rows=7 width=19) (actual time=0.015..0.021 rows=7 loops=1)Filter: ((role_status)::text = '1'::text)Planning time: 0.443 msExecution time: 0.187 ms
(18 rows)

从输出上来看 explain analyze 等价于 explain (analyze true),那为什么会有两种表现形式?很容易让人困惑。

对于 EXPLAIN [ ANALYZE ] [ VERBOSE ] statement ,只有 ANALYZE 和 VERBOSE 选项能被指定,并且必须按照上述的顺序,不要把选项列表放在圆括号内。在PostgreSQL 9.0 之前,只支持没有圆括号的语法。
我们期望所有新的选项将只在圆括号语法中支持。

个人感觉没有放到圆括号的 analyze 是为了兼容之前的老版本。

官方文档要好好读!!!
官方文档要好好读!!!
官方文档要好好读!!!

参考
http://www.postgres.cn/docs/9.6/sql-explain.html
http://www.postgres.cn/docs/9.6/using-explain.html

转载于:https://www.cnblogs.com/ctypyb2002/p/9792907.html

postgresql explain的初步分析相关推荐

  1. PostgreSql EXPLAIN 查询计划分析

    1.基本语法 EXPLAIN [ ANALYZE ] [ VERBOSE ] sql语句 各参数含义: analyze:执行语句并显示真正的运行时间和其它统计信息,会真正执行SQL语句: verbos ...

  2. Azure底层架构的初步分析

    之所以要写这样的一篇博文的目的是对于大多数搞IT的人来说,一般都会对这个topic很感兴趣,因为底层架构直接关乎到一个公有云平台的performance,其实最主要的原因是我们的客户对此也非常感兴趣, ...

  3. linux内核的I2C子系统详解3——i2c-core.c初步分析、I2C总线的匹配机制

    以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 5.i2c-core.c初步分析 (1)smbus代码略过:smbus是基于I2C总线发展出来的. (2)模块加载和卸 ...

  4. 驱动框架2——内核驱动框架中LED的基本情况、初步分析

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 一.内核驱动框架中LED的基本情况 1.相关文件 (1)drivers/leds目录 驱动框架规定的LED这种硬件的驱动应该待的地方. (2 ...

  5. 【2017年第3期】大数据服务三农的初步分析与探索

    孙忠富, 褚金翔, 马浚诚, 杜克明, 郑飞翔 中国农业科学院农业环境与可持续发展研究所,北京 100081 摘要:三农问题是当前中国密切关注的社会问题,大数据技术的发展为三农带来了新的机遇.首先,对 ...

  6. tomcat4 请求的处理——初步分析

    tomcat4 请求的处理--初步分析 以tomcat4为例, 每当HttpConnector的ServerSocket得到客户端的连接时,会创建一个Socket. 接下来就处理这个Socket发来的 ...

  7. explain ref_MySQL 性能分析神器 —— EXPLAIN 用法与解读。

    ↑ 点击上面 "时代Java"关注我们,关注新技术,学习新知识! EXPLAIN作为MySQL的性能分析神器,读懂其结果是很有必要的,然而我在各种搜索引擎上竟然找不到特别完整的解读 ...

  8. DirectUI的初步分析-转

    DirectUI的初步分析(一) 最近由于项目的需要学习了一下DirectUI方面的东西,主要借鉴的是一个国外程序员写的代码(见引用一),看了后发现它更多的是探讨一种实现的可能性和思路,和实际应用还是 ...

  9. 2017 Python 问卷调查结果初步分析

    Note:本文在我的个人站点同步发布:2017 Python 问卷调查结果初步分析 · Lee's Space Station,无广告,体验更好. 未经授权,禁止转载. 前言 2017 年末,PSF( ...

最新文章

  1. Matlab绘制小波尺度函数和小波函数
  2. berkeley db mysql_BDB:源自 Berkeley DB,事务型数据库
  3. 浅析如何在Nancy中生成API文档
  4. python中argument函数_PythonStudy——函数的参数 Function argument
  5. magento 1.7 中文语言包
  6. 苹果内地最大代工厂被曝大幅裁员!这家库克曾点赞的企业怎么了?
  7. 新AirPods渲染图曝光:采用黑白灰金四种配色
  8. https://www.jianshu.com/p/5b710cc25f81
  9. 微博android4.1.2,Fuubo微博(新浪微博第三方客户端)app
  10. 【SCI文献下载】手把手教你如何免费下载SCI文献
  11. hdu 1419 最大独立集
  12. 计算机ppt制作教案,教案幻灯片制作
  13. 计算机桌面图标不可以移动怎么调,win10电脑桌面图标不能移动怎么办,win10桌面图标移动不了的解决方法...
  14. protege的下载
  15. spring事务管理总结
  16. 命令行中运行jar包(cmd)
  17. 软件工程 - 项目管理
  18. C语言陷进和缺陷学习心得
  19. 计算机主板 原理,计算机主板的工作原理(二)
  20. notepad++使用正则表达式替换(保留部分内容不变)的方法

热门文章

  1. android 获取文件夹的字节数,android java file 清理垃圾获取文件大小 删除文件等操作...
  2. mysql iso 时间_mysql 中 时间和日期函数
  3. 基于用户的协同过滤算法
  4. Uva 11178 Morley's Theorem 向量旋转+求直线交点
  5. 在web应用程序中使用MemcachedClient
  6. [Case] “凭心而论,在这家公司很敬业的工作了3年多,老板最后给我下的评语,大家都看看吧,千万别和我走同一条路!”(摘自csdn)...
  7. 普通笔记本能运行Linux么,Windows ARM 笔记本电脑现在可以运行 Ubuntu
  8. springboot 多线程_机密文档!阿里产出SpringBoot/Cloud,细节爆炸
  9. 敏捷开发人员结构_开发人员可以在敏捷外观方面发表意见的4种方法
  10. 开源硬件 可穿戴_11个出色的可穿戴开源项目