PostgreSQL 排查慢 SQL

2023-09-14 16:48:25

前言

所谓 慢 SQL 是指在数据库中执行时间超过指定阈值的语句。慢查询太多,对于业务而言,是有很大风险的,可能随时都会因为某种原因而被触发,并且根据我们的经验,数据库最常出现的问题,都是因为慢查询导致数据库慢了,进而导致整个实例 “雪崩” 从而导致线上故障。 本篇文章将介绍 PostgreSQL 慢 SQL 如何定位排查。

1. 日志参数设置

MySQL 提供为用户提供 slow_query_log 参数来设置慢日志存储:

# 是否开启慢日志
slow_query_log = 1

# 慢日志文件路径
slow_query_log_file = '/logs/slow.log'

# 慢日志阈值,取值范围 [0.000000-3600.000000]
long_query_time = 1

PostgreSQL 也提供相关参数:

# -1 表示不记录语句
log_min_duration_statement = 100ms

# none, ddl, mod, all
# none: 表示不记录慢 SQL
# ddl: ddl 记录所有数据定义语句,例如 CREATE、ALTER 和 DROP 语句
# mod: DDL + INSERT, UPDATE、DELETE、TRUNCATE, 和 COPY FROM
# all: 所有语句都会被记录
log_statement = 'mod'
2023-09-14 14:07:46.695 CST [46385] LOG:  statement: update pgbench_accounts set bid = 11 where abalance = 101;
2023-09-14 14:07:53.698 CST [46385] LOG:  duration: 7003.518 ms

这是将慢 SQL 和错误日志放到一个文件中,个人觉得不太好看,尤其是内容很多的时候,这里如果有人有其他好方法或使用经验,可以评论区发表下。

2. pg_stat_statements 插件

pg_stat_statements 模块提供一种跟踪执行统计服务器执行的所有 SQL 语句的手段。该模块默认是不开启的,如果需要开启需要我们手动对其进进行编译安装,修改配置文件并重启数据库,并在使用前手动载入该模块。

2.1 确认是否安装插件

安装插件之前,要先确认插件是否已经被编译好了,可以到 PostgreSQL 安装目录查看:

ll ./share/extension

输出:

总用量 52
-rw-r--r-- 1 root root 1246 914 15:38 pg_stat_statements--1.0--1.1.sql
-rw-r--r-- 1 root root 1336 914 15:38 pg_stat_statements--1.1--1.2.sql
-rw-r--r-- 1 root root 1454 914 15:38 pg_stat_statements--1.2--1.3.sql
-rw-r--r-- 1 root root  345 914 15:38 pg_stat_statements--1.3--1.4.sql
-rw-r--r-- 1 root root  305 914 15:38 pg_stat_statements--1.4--1.5.sql
-rw-r--r-- 1 root root 1427 914 15:38 pg_stat_statements--1.4.sql
-rw-r--r-- 1 root root  376 914 15:38 pg_stat_statements--1.5--1.6.sql
-rw-r--r-- 1 root root  806 914 15:38 pg_stat_statements--1.6--1.7.sql
-rw-r--r-- 1 root root  191 914 15:38 pg_stat_statements.control
-rw-r--r-- 1 root root  449 914 15:38 pg_stat_statements--unpackaged--1.0.sql
-rw-r--r-- 1 root root  310 95 10:21 plpgsql--1.0.sql
-rw-r--r-- 1 root root  179 95 10:21 plpgsql.control
-rw-r--r-- 1 root root  370 95 10:21 plpgsql--unpackaged--1.0.sql

可以看到一些关于 pg_stat_statements 文件信息,表示插件已被安装完成。如果看到相关文件表示插件没有被编译,需要编译后才能使用。

2.2 编译插件

进入 PostgreSQL 源码目录,后执行下方命令:

# 进入插件目录
cd contrib/pg_stat_statements/

# 编译安装
make && make install

2.3 载入插件

确认编译安装成功后,就可以使用插件了,首先需要修改 postgresql.conf 配置文件:

# 加载动态库
shared_preload_libraries='pg_stat_statements'

# 记录语句的最大行数,默认 5000
pg_stat_statements.max = 10000

# 控制哪些语句会被该模块计数。指定 top 可以跟踪顶层语句(那些直接由客户端发出的语句)
# 指定 all 还可以跟踪嵌套的语句(例如在函数中调用的语句)指定 none 可以禁用语句统计信息收集。
pg_stat_statements.track = all

# 控制模块 是否 跟踪除了 “增删改查” 之外的命令,默认为 on
pg_stat_statements.track_utility = on

# 指定是否在服务器关闭之后还保存语句统计信息,默认为 on 关机前会持久化保存
pg_stat_statements.save = on

然后 重启数据库 后生效。

然后使用 psql 连接 PostgreSQL 服务,载入插件:

postgres=# create extension pg_stat_statements;     
CREATE EXTENSION

查询插件状态:

postgres=# SELECT * FROM pg_available_extensions WHERE name = 'pg_stat_statements';     
        name        | default_version | installed_version |                          comment                          
--------------------+-----------------+-------------------+-----------------------------------------------------------
 pg_stat_statements | 1.7             | 1.7               | track execution statistics of all SQL statements executed

2.4 插件使用

直接查询插件视图,就可以看到 TOP SQL 情况:

postgres=# select * from  pg_stat_statements limit 1;
-[ RECORD 1 ]-------+------------------------------------------------------------------------
userid              | 10                        //用户id
dbid                | 13547                     //数据库oid
queryid             | 1194713979                //查询id
query               | SELECT * FROM pg_available_extensions WHERE name = 'pg_stat_statements'   //查询SQL
calls               | 1                         //调用次数
total_time          | 53.363875                 //SQL总共执行时间
min_time            | 53.363875                 //SQL最小执行时间
max_time            | 53.363875                 //SQL最大执行时间
mean_time           | 53.363875                 //SQL平均执行时间
stddev_time         | 0                         //SQL花费时间的表中偏差
rows                | 1                         //SQL返回或者影响的行数
shared_blks_hit     | 1                         //SQL在在shared_buffer中命中的块数
shared_blks_read    | 0                         //SQL从page cache或者磁盘中读取的块数
shared_blks_dirtied | 0                         //SQL语句弄脏的shared_buffer的块数
shared_blks_written | 0                         //SQL语句写入的块数
local_blks_hit      | 0                         //临时表中命中的块数
local_blks_read     | 0                         //临时表需要读的块数
local_blks_dirtied  | 0                         //临时表弄脏的块数
local_blks_written  | 0                         //临时表写入的块数
temp_blks_read      | 0                         //从临时文件读取的块数
temp_blks_written   | 0                         //从临时文件写入的数据块数
blk_read_time       | 0                         //从磁盘或者读取花费的时间
blk_write_time      | 0                         //从磁盘写入花费的时间

3. 慢 SQL 排查手段

3.1 查询当前会话

SELECT pgsa.datname AS database_name
    , pgsa.usename AS user_name
    , pgsa.client_addr AS client_addr
    , pgsa.application_name AS application_name
    , pgsa.state AS state
	, pgsa.backend_start AS backend_start
	, pgsa.xact_start AS xact_start
	, extract(epoch FROM now() - pgsa.xact_start) AS xact_time, pgsa.query_start AS query_start
	, extract(epoch FROM now() - pgsa.query_start) AS query_time
	, pgsa.query AS query_sql
FROM pg_stat_activity pgsa
WHERE pgsa.state != 'idle'
	AND pgsa.state != 'idle in transaction'
	AND pgsa.state != 'idle in transaction (aborted)'
ORDER BY query_time DESC
LIMIT 5;

3.2 查看 TOP SQL

重启并重置 pg_stat_statements 插件,让插件重新收集当前的数据:

create extension pg_stat_statements;
select pg_stat_reset();
select pg_stat_statements_reset();

查看 TOP SQL:

-- 总查询时间 TOP
select * from pg_stat_statements order by total_time desc limit 5;
-- 总 IO 消耗 TOP
select * from pg_stat_statements order by blk_read_time+blk_write_time desc limit 5;
-- 总调用次数 TOP
select * from pg_stat_statements order by calls desc limit 5;

当发现异常会话,一般都是先 kill 掉,然后再分析问题原因,kill 会话相关操作,可以参考:《PostgreSQL 会话管理》

更多推荐

高通8295中国首发!智舱再度上演「军备竞赛」,这次有何不同

对于智能座舱来说,上一轮市场红利已经接近尾声。高工智能汽车研究院监测数据显示,2023年1-6月中国市场(不含进出口)乘用车前装标配中控娱乐系统交付856.13万辆,前装标配渗透率已经超过90%,达到92.13%。其中,支持车联网功能主机占比也已经超过80%,达到83.03%。这意味着,车企需要尽快构建下一代座舱的差异

“智能制造进园区·浙江站和专家行”活动成功举办

为进一步加强央地联动,强化智能制造系统推进格局,促进重点区域行业智能制造供需对接,2023年9月12日-15日,在工业和信息化部装备工业一司指导下,由国家智能制造专家委员会、浙江省经济和信息化厅、智能制造系统解决方案供应商联盟、中国电子技术标准化研究院、温州市人民政府主办,瑞安市人民政府、温州市经济和信息化局、浙江省技

不得不爱的AI艺术写真头像二维码生成小程序开发

最近什么最火?AI最火!AI里什么最火?艺术写真生成和二维码美化最火。一款小程序集合了高还原度的AI写真艺术照和二维码美化,你们说香还是不香?并且加入了输入心愿就能生成独一无二的个性头像功能,直接拿捏年轻人的心。为了方便小程序运营中裂变效果好,更是加入了分销机制,分享小程序不仅能跟小伙伴分享制作写真的快乐,还能顺带恰点

算法----数组常见知识点

1.在Java中,数组可以分为以下几种类型:一维数组:一维数组是最常见的数组类型,它包含一系列具有相同数据类型的元素。数组中的每个元素可以通过索引访问,索引从0开始。二维数组:二维数组是由一维数组组成的数组。它可以被看作是一个表格或者矩阵,其中的元素可以通过两个索引进行访问。每个元素都是由行索引和列索引确定的。多维数组

【实训项目】你好,教练-校园私教平台的设计与开发

1.设计摘要随着社会的进步,人们的健康意识逐渐提高,越来越多的人选择在闲暇时间健身,在大学生群体中,这一现象犹为明显。在大学城内,有多家健身房供同学选择,也有许多同学选择在操场或者宿舍内自己健身,全民健身已经逐渐成为一种潮流。在2018年,国家体育总局近日推出解决群众健身难的十项举措,包括建设一批健身步道、建设一批体育

回顾每一代 iPhone 的特性升级和创新

文章目录前言初代iPhone(2007)iPhone3G(2008)iPhone3GS(2009)iPhone4(2010)iPhone4S(2011)iPhone5(2012)iPhone5c和5s(2013)iPhone6和6Plus(2014)iPhone6s和6sPlus(2015)iPhone7和7Plus(

DDR模块电路的PCB设计建议

DDR电路简介RK3588DDR控制器接口支持JEDECSDRAM标准接口,原理电路16位数据信号如图8-1所示,地址、控制信号如图8-2所示,电源信号如图8-3所示。电路控制器有如下特点:1、兼容LPDDR4/LPDDR4X/LPDDR5标准;2、支持64bits数据总线宽度,由4个16bits的DDR通道组成,每个

【Vue】Vue中lauch.js的详细介绍,各个参数的内涵

"lauch.js"在Vue中是一个启动文件,通常用来创建Vue实例并配置一些默认设置。下面是常见的"lauch.js"参数及其意义:el:表示要挂载的元素,通常是一个字符串或者一个DOM对象。router:表示使用的路由,通常是一个VueRouter实例。store:表示使用的状态管理器,通常是一个VuexStore

【Linux成长史】Linux权限的详细讲解

🎬博客主页:博主链接🎥本文由Mmalloc原创,首发于CSDN🙉🎄学习专栏推荐:LeetCode刷题集数据库专栏初阶数据结构🏅欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📆未来很长,值得我们全力奔赴更美好的生活✨文章目录😇本章详情😇Linux权限的概念⏳Linux下的两种用户:超级用户(root),普通

讲解socket 网络编程的 5 大隐患

1.忽略返回状态第一个隐患很明显,但它是开发新手最容易犯的一个错误。如果您忽略函数的返回状态,当它们失败或部分成功的时候,您也许会迷失。反过来,这可能传播错误,使定位问题的源头变得困难。捕获并检查每一个返回状态,而不是忽略它们。考虑清单1显示的例子,一个套接字send函数。清单1.忽略API函数返回状态intstatu

【C#】FileInfo类 对文件进行操作

提示:使用FileInfo类时,要引用System.IO命名空间。usingSystem.IO;FileInfo类生成文件删除文件移动文件复制文件获取文件名判断文件是否存在属性列表其它常用方法生成文件Create():在指定路径上创建文件。FileInfomyFile=newFileInfo(@"E:\vsspace\

热文推荐