PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)

0    25    1

Tags:

👉 本文共约3789个字,系统预计阅读时间或需15分钟。

一、 问题背景

​ 开发反馈PG中某函数执行时间很长,超过30分钟,想看看慢在其中哪一段SQL。但是如果直接通过pg_stat_activity查询,只能看到上层执行函数的语句,而不像oracle和SqlServer能看到当前在执行什么。咨询群友们得到了几种方法,下面测试和对比一下。
简单模拟如下:

执行函数
PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)
查看运行情况

PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)

二、 方法汇总及对比

PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)

三、 直接分析函数代码

\sf 函数名 可以查看函数代码,这适用于函数非常简单的场景,例如我们的例子
PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)
如果函数中SQL很长,输出可能会错行,不方便分析,可以用psql将其导出成文本。

四、 raise notice打标记

注意raise要用plpgsql语言,像上面用sql会报错,为方便测试稍微做点改造。

本人提供Oracle(OCP、OCM)、MySQL(OCP)、PostgreSQL(PGCA、PGCE、PGCM)等数据库的培训和考证业务,私聊QQ646634621或微信db_bao,谢谢!

输出如下
PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)

五、 auto_explain显示每个SQL执行计划

​ 对于业务量大的库,不适合全局抓取SQL,可以在客户端开启。设置以下参数,核心是log_nested_statements = true,展示函数内所有SQL执行计划。

效果如下

六、 设置pg_stat_statements.track=all

基本上也只适合客户端开启,或者在测试环境reset后单独跑,比auto_explain更难找

PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)

七、 使用plprofiler插件

一、 plProfiler插件简介

​ plProfiler插件使用C和python语言共同开发,可以收集PL/pgSQL语言(不支持SQL语言)的函数和存储过程的profile信息,并生成html报表。报表以火焰图形式展示函数调用堆栈、耗时占比,还可以查看函数中每个SQL的位置、执行次数、最长执行时间、总时间,清晰明了。
​ 由于依赖于python环境,安装、排错较复杂,对python小白不友好。同时,它也并非旁路监控,必须要手动执行对应函数。

二、 plProfiler插件安装

1. 安装准备

  • python环境准备
    ​ 通常Linux环境默认都自带python,不过要注意版本,python 3.2版本以下会在后面踩坑。如果没有的话网上搜索一下怎么安装即可。
  • pip安装
  • 依赖包及python模块安装

    2. plprofiler下载及安装

  • 下载地址GitHub - bigsql/plprofiler
  • 解压安装包,必须放到 源码/contrib 目录下,否则安装会报错
  • 编译安装
  • 安装 plprofiler-client,即plprofiler命令
  • 安装psycopg2模块,用于连接pg数据库
  • 测试安装情况,若有报错,安装对应模块

    3. 数据库中创建插件

    三、 plProfiler插件测试

1. 测试案例准备

安装包中有一个自带的案例

执行该脚本

2. 密码配置

​ 出于安全考虑,plprofiler命令行不提供 --password参数,如果有用户密码,需要配置~/.pgpass文件,或者在pg_hba.conf中配置信任本ip(因为plprofiler只能如果--host ip方式访问,不能通过local方式访问)。
​ 注意应该加在md5那行前面,因为 pg_hba.conf 是匹配到就停止的。
PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)

3. plprofiler调用函数

执行完会弹出以下报表配置内容,可以不改,直接保存退出

[current]
title = PL Profiler Report for current
tabstop = 8
svg_width = 1200
table_width = 80%
desc =

PL Profiler Report for current

4. 报表展示

打开生成的tmp.html文件,以火焰图的形式展示
PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)
点击show可以查看函数内部执行情况
PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)
总的来说格式是最清晰的,适合复杂函数的分析。

四、 常见报错处理

安装和排错过程很坎坷,记录一下...

1. 编译报错

-bash-4.2$ make install
Makefile:26: ../../src/Makefile.global: No such file or directory
Makefile:27: /contrib/contrib-global.mk: No such file or directory
make: *** No rule to make target `/contrib/contrib-global.mk'. Stop.
解决方法:plprofiler 解压到 源码/contrib 目录下

2. plprofiler客户端安装报错

报错1

[root@linux01 python-plprofiler]# python ./setup.py install
Traceback (most recent call last):
File "./setup.py", line 1, in
from setuptools import setup
ImportError: No module named setuptools
解决方法:yum install python-setuptools

报错2

[root@linux01 python-plprofiler]# python ./setup.py install

Couldn't find index page for 'configparser' (maybe misspelled?)
Scanning index of all packages (this may take a while)
Reading https://pypi.python.org/simple/
No local packages or download links found for configparser
error: Could not find suitable distribution for Requirement.parse('configparser')
解决方法:pip install configparser

3. plprofiler命令执行报错

[root@linux01 python-plprofiler]# plprofiler --help
Traceback (most recent call last):
...
File "/usr/lib/python2.7/site-packages/plprofiler_client-4.2-py2.7.egg/plprofiler/plprofiler_report.py", line 4, in
import html
ImportError: No module named html
解决方法:pip install html

4. plprofiler无法识别到

-bash-4.2$ plprofiler run --command="select test_f();" --output=test_f.html
could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
解决方法:加上连接信息
plprofiler run --host=192.168.1.108 --port=5432 --user=postgres --dbname=postgres --command="select test_f();" --output=test_f.html

5. plprofiler要求输入用户密码

plprofiler run --host=192.168.1.108 --port=5432 --user=postgres --dbname=postgres --command="select test_f();" --output=test_f.html

fe_sendauth: no password supplied
解决方法:配置~/.pgpass文件,或者在pg_hba.conf中配置信任本ip(参考前面)

6. plprofiler输出报表为空

报错1

plprofiler run --host=192.168.1.108 --port=5432 --user=postgres --dbname=postgres --command="select test_f();" --output=test_f.html

Traceback (most recent call last):
File "/usr/bin/plprofiler", line 9, in
...
File "/usr/lib/python2.7/site-packages/plprofiler_client-4.2-py2.7.egg/plprofiler/plprofiler.py", line 403, in get_local_report_data
raise Exception("No profiling data found")
Exception: No profiling data found
原因:test_f 函数为sql语言编写(language sql)
解决方法:plprofiler 仅支持 plpgsql语言(LANGUAGE plpgsql)

报错2

plprofiler run --host=192.168.1.108 --port=5432 --user=postgres --dbname=postgres --command "SELECT tpcb(1, 2, 3, -42)" --output tmp.html

"/tmp/tmpGWSbI3.tmp.conf" 10L, 182C written
Traceback (most recent call last):
...
File "/usr/lib/python2.7/site-packages/plprofiler_client-4.2-py2.7.egg/plprofiler/plprofiler_report.py", line 21, in generate
self.out("

%s" %(html.escape(config['title']), ))
AttributeError: 'module' object has no attribute 'escape'

原因:python版本过低(测试的版本为python 2.7),3.2及以上版本才可使用html.escape,旧版本使用cgi.escape
解决方法:修改报错的 /usr/lib/python2.7/site-packages/plprofiler_client-4.2-py2.7.egg/plprofiler/plprofiler_report.py 脚本,加入import cgi,并将html.escape替换为cgi.escape(共两处)

PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)
PG中如何获取函数中正在执行的真实SQL语句(定位存储过程中最耗时部分)

参考

https://blog.csdn.net/Hehuyi_In/article/details/102855303
https://blog.csdn.net/Hehuyi_In/article/details/105039110?spm=1001.2014.3001.5502
https://www.modb.pro/db/86040

标签:

头像

小麦苗

学习或考证,均可联系麦老师,请加微信db_bao或QQ646634621

您可能还喜欢...

发表回复

嘿,我是小麦,需要帮助随时找我哦
  • 18509239930
  • 个人微信

  • 麦老师QQ聊天
  • 个人邮箱
  • 点击加入QQ群
  • 个人微店

  • 回到顶部
返回顶部