当前位置: 首页 > news >正文

PostgreSQL 慢 SQL 排查

作者:文若

前言

所谓慢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 会话管理》

更多技术信息请查看云掣官网https://yunche.pro/?t=yrgw

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【MySQL篇】Percona XtraBackup工具备份指南:常用备份命令详解与实践(第二篇,总共五篇)
  • Elasticsearch 批量更新
  • 阿里云国际站:海外视频安全的DRM加密
  • 防溺水预警系统引领水域安全新篇章
  • apache Kylin系列介绍及配置
  • Logback格式简记
  • 026-GeoGebra中级篇-曲线(2)_极坐标曲线、参数化曲面、分段函数曲线、分形曲线、复数平面上的曲线、随机曲线、非线性动力系统的轨迹
  • SpringBoot增加网关服务
  • Linux发行版CentOS 8 利用Docker安装应用
  • 初谈Linux信号-=-信号的产生
  • Kafka Producer发送消息流程之消息异步发送和同步发送
  • 【整体介绍】HTML和JS编写多用户VR应用程序的框架
  • node.js的安装及学习(node/nvm/npm的区别)
  • 【闲聊】-Perl的基础语法
  • Python3 学习——基础语法2
  • 分享一款快速APP功能测试工具
  • Docker: 容器互访的三种方式
  • echarts花样作死的坑
  • JS基础之数据类型、对象、原型、原型链、继承
  • Linux后台研发超实用命令总结
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • supervisor 永不挂掉的进程 安装以及使用
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • $().each和$.each的区别
  • (八)Flask之app.route装饰器函数的参数
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (四)linux文件内容查看
  • (转载)Google Chrome调试JS
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径
  • *算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
  • .Net Core 微服务之Consul(二)-集群搭建
  • .net dataexcel winform控件 更新 日志
  • .net 反编译_.net反编译的相关问题
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET4.0并行计算技术基础(1)
  • .net6Api后台+uniapp导出Excel
  • .NET中分布式服务
  • ??javascript里的变量问题
  • @property python知乎_Python3基础之:property
  • @property括号内属性讲解
  • [1]从概念到实践:电商智能助手在AI Agent技术驱动下的落地实战案例深度剖析(AI Agent技术打造个性化、智能化的用户助手)
  • [BSidesCF 2019]Kookie1
  • [C++]模板与STL简介
  • [COGS 622] [NOIP2011] 玛雅游戏 模拟
  • [c语言]小课堂 day2
  • [dfs搜索寻找矩阵中最长递减序列]魔法森林的秘密路径
  • [Docker]当下实测可用Docker镜像源
  • [Docker]四.Docker部署nodejs项目,部署Mysql,部署Redis,部署Mongodb
  • [Electron] 将应用打包成供Ubuntu、Debian平台下安装的deb包
  • [GN] Vue3.2 快速上手 ---- 核心语法2