使用 pg_stat_statements 优化查询

news2024/11/20 14:20:27

使用 pg_stat_statements 优化查询

Using pg_stat_statements to Optimize Queries

就使用量和社区规模而言,PostgreSQL 是增长最快的数据库之一,得到许多专业开发人员的支持,并得到广泛的工具、连接器、库和可视化应用程序生态系统的支持。 PostgreSQL 也是可扩展的:使用 PostgreSQL 扩展,用户可以向 PostgreSQL 的核心添加额外的功能。

今天,我们很高兴与大家分享,最流行和最广泛使用的 PostgreSQL 扩展之一 pg_stat_statements

pg_stat_statements 允许您快速识别有问题或缓慢的 Postgres 查询,从而提供对数据库性能的可观察性。

什么是 pg_stat_statements?

pg_stat_statements 是一个 PostgreSQL 扩展,用于记录有关正在运行的查询的信息。识别数据库中的性能瓶颈,这个过程通常感觉就像一场猫捉老鼠的游戏。快速编写的查询、索引更改或复杂的 ORM 查询生成器可能(并且经常)对数据库和应用程序性能产生负面影响。

如何使用 pg_stat_statements

正如我们将在这篇文章中向您展示的那样, pg_stat_statements 是一个非常宝贵的工具,可以帮助您确定哪些查询执行缓慢且性能不佳以及原因。例如,可以查询 pg_stat_statements 以了解查询被调用了多少次、查询执行时间、查询的命中缓存率(内存中与磁盘上有多少数据可以满足要求)以及其他有用的统计信息,例如查询执行时间的标准差。

如何在postgres中使用 pg_stat_statements

连接到数据库后,从 pg_stat_statements 视图查询 postgres数据库的统计数据非常简单。该视图返回许多数据列(超过 30 列!)。

SELECT * FROM pg_stat_statements;

userid|dbid |queryid             |query                         
------+-----+--------------------+------------------------------
 16422|16434| 8157083652167883764|SELECT pg_size_pretty(total_by
    10|13445|                    |<insufficient privilege>      
 16422|16434|-5803236267637064108|SELECT game, author_handle, gu
 16422|16434|-8694415320949103613|SELECT c.oid,c.*,d.description
    10|16434|                    |<insufficient privilege>      
    10|13445|                    |<insufficient privilege>   
 ...  |...  |...                 |...  

如果当前 用户无权访问的查询将隐藏查询文本和标识符,该列显示 <insufficient privilege>

pg_stat_statements收集所有数据库和用户的数据,如果允许任何用户查询性能数据,则会对安全带来挑战。因此,尽管任何用户都可以从视图中查询数据,但只有超级用户和专门授予 pg_read_all_stats 权限的用户才能查看所有用户级别的详细信息,包括 queryidquery

尽管您使用的当前用户拥有数据库并拥有很多权限,但如果它不是超级用户,无法查看服务集群内所有其他查询的详细信息。

因此,对于您想要执行的任何查询,最好按 userid 过滤 pg_stat_statements 数据。

-- current_user will provide the rolname of the authenticated user
SELECT * FROM pg_stat_statements pss
    JOIN pg_roles pr ON (userid=oid)
WHERE rolname = current_user;


userid|dbid |queryid             |query                         
------+-----+--------------------+------------------------------
 16422|16434| 8157083652167883764|SELECT pg_size_pretty(total_by
 16422|16434|-5803236267637064108|SELECT game, author_handle, gu
 16422|16434|-8694415320949103613|SELECT c.oid,c.*,d.description
 ...  |...  |...                 |...           

仅查询 current_user 用户,显示所有详细信息和统计信息

添加过滤器后,仅显示您有权访问的数据。如果您在服务中为特定应用程序创建了其他帐户,您还可以过滤到这些帐户。

为了使我们的示例查询的其余部分更易于使用,建议您将此基本查询与CTE 结合使用。此查询表单将返回相同的数据,但使查询的其余部分更容易编写。

-- current_user will provide the rolname of the authenticated user
WITH statements AS (
SELECT * FROM pg_stat_statements pss
        JOIN pg_roles pr ON (userid=oid)
WHERE rolname = current_user
)
SELECT * FROM statements;

userid|dbid |queryid             |query                         
------+-----+--------------------+------------------------------
 16422|16434| 8157083652167883764|SELECT pg_size_pretty(total_by
 16422|16434|-5803236267637064108|SELECT game, author_handle, gu
 16422|16434|-8694415320949103613|SELECT c.oid,c.*,d.description
 ...  |...  |...                 |...            

显示与之前相同结果的查询,但这次使用 CTE 中的基本查询,以便稍后进行更简洁的查询

现在我们知道如何仅查询我们有权访问的数据,让我们回顾一下对于发现查询潜在问题最有用的一些列。

  • calls: 调用此查询的次数。
  • total_exec_time: 执行查询所花费的总时间(以毫秒为单位)。
  • rows: 此查询检索到的总行数。
  • shared_blks_hit:查询读取时已缓存的块数。
  • shared_blks_read: 为满足对此查询表单的所有调用而必须从磁盘读取的块数。

关于上述数据列的三个快速提醒:

  1. 自上次启动服务或超级用户手动重置这些值以来,所有值都是累积的。

你可以使用 SELECT pg_stat_statements_reset(); 重置统计信息
2. 在参数化查询后,所有值都针对相同的查询语句,并基于生成的散列 queryid
3. 由于增加的开销很小,当前配置不跟踪查询计划统计信息。将来我们可能会通过用户配置允许这样做。

使用这些数据列,让我们看一些常见的查询,它们可以帮助您缩小有问题的查询的范围。

长时间运行的 PostgreSQL 查询

查找值得您关注的慢 Postgres 查询的最快方法之一是查看每个查询的平均总时间。这不是时间加权平均值,因为数据是累积的,但它仍然有助于构建从哪里开始的相关背景。

调整 calls 值以满足您的特定应用程序需求。查询更高(或更低)的调用总数可以帮助您识别不经常运行但非常昂贵的查询,或者运行频率比您预期高得多且运行时间比应有的时间长的查询。

-- query the 10 longest running queries with more than 500 calls
WITH statements AS (
SELECT * FROM pg_stat_statements pss
        JOIN pg_roles pr ON (userid=oid)
WHERE rolname = current_user
)
SELECT calls, 
    mean_exec_time, 
    query
FROM statements
WHERE calls > 500
AND shared_blks_hit > 0
ORDER BY mean_exec_time DESC
LIMIT 10;


calls|mean_exec_time |total_exec_time | query
-----+---------------+----------------+-----------
 2094|        346.93 |      726479.51 | SELECT time FROM nft_sales ORDER BY time ASC LIMIT $1 |
 3993|         5.728 |       22873.52 | CREATE TEMPORARY TABLE temp_table ... |
 3141|          4.79 |       15051.06 | SELECT name, setting FROM pg_settings WHERE ... |
60725|          3.64 |      221240.88 | CREATE TEMPORARY TABLE temp_table ... |   
  801|          1.33 |        1070.61 | SELECT pp.oid, pp.* FROM pg_catalog.pg_proc p  ...|
 ... |...            |...                 |           

平均执行时间最长的查询

我们用于这些查询的示例数据库基于 NFT 销售数据。作为正常过程的一部分,您可以看到创建了一个 TEMPORARY TABLE 来读取新数据并更新现有记录,作为轻量级提取-转换-加载过程的一部分。

自该服务启动以来,该查询已被调用 60,725 次,并且创建该表花费了大约 4.5 分钟的总执行时间。相比之下,显示的第一个查询平均执行时间最长,每次大约 350 毫秒。它检索 nft_sales 表中最旧的时间戳,并且自服务器启动以来已使用超过 12 分钟的执行时间。

从工作角度来看,找到提高第一个查询性能的方法将对整体服务器工作负载产生更显着的影响。

Hit Cache Ratio 缓存命中率

与计算中的几乎所有事物一样,当可以在内存中查询数据而不是访问外部磁盘存储时,数据库往往会表现最佳。如果 PostgreSQL 必须从存储中检索数据来满足查询,那么通常会比所有需要的数据都已加载到 PostgreSQL 的保留内存空间中要慢。我们可以通过称为缓存命中率的值来测量查询执行此操作的频率。

缓存命中率是对满足查询所需的数据在内存中可用的频率的度量。较高的百分比意味着数据已经可用并且不必从磁盘读取,而较低的值可能表明服务器存在内存压力并且无法跟上当前的工作负载。

如果 PostgreSQL 必须不断地从磁盘读取数据来满足相同的查询,则意味着其他操作和数据会优先,并且每次都会将查询所需的数据“推送”回磁盘。

这是时间序列工作负载的常见场景,因为较新的数据首先写入内存,如果没有足够的可用缓冲区空间,则使用较少的数据将被逐出。如果您的应用程序查询大量历史数据,较旧的超表块可能无法加载到内存中并准备好快速服务查询。

一个好的起点是经常运行且缓存命中率低于 98% 的查询。这些查询是否倾向于提取长时间段的数据?如果是这样,这可能表明没有足够的 RAM 来有效地存储这些数据足够长的时间,然后再将其逐出以获取新数据。

根据应用程序查询模式,您可以通过增加服务器资源来提高命中缓存率,考虑调整索引以减少表存储,或对定期查询的旧块使用 数据库 压缩。

-- query the 10 longest running queries
WITH statements AS (
SELECT * FROM pg_stat_statements pss
        JOIN pg_roles pr ON (userid=oid)
WHERE rolname = current_user
)
SELECT calls, 
    shared_blks_hit,
    shared_blks_read,
    shared_blks_hit/(shared_blks_hit+shared_blks_read)::NUMERIC*100 hit_cache_ratio,
    query
FROM statements
WHERE calls > 500
AND shared_blks_hit > 0
ORDER BY calls DESC, hit_cache_ratio ASC
LIMIT 10;


calls | shared_blks_hit | shared_blks_read | hit_cache_ratio |query
------+-----------------+------------------+-----------------+--------------
  118|            441126|                 0|           100.00| SELECT bucket, slug, volume AS "volume (count)", volume_eth...
  261|          62006272|             22678|            99.96| SELECT slug FROM streamlit_collections_daily cagg...¶        I
 2094|         107188031|           7148105|            93.75| SELECT time FROM nft_sales ORDER BY time ASC LIMIT $1...      
  152|          41733229|                 1|            99.99| SELECT slug FROM streamlit_collections_daily cagg...¶        I
  154|          36846841|             32338|            99.91| SELECT a.img_url, a.name, MAX(s.total_price) AS price, time...

 ... |...               |...               | ...             | ...

显示每个查询的缓存命中率的查询,包括从磁盘或内存中准备好满足查询的缓冲区数量

该示例数据库不是很活跃,因此与传统应用程序可能显示的相比,总体查询计数不是很高。在上面的示例数据中,调用次数超过 500 次的查询是“常用查询”。

我们可以从上面看到,最昂贵的查询之一也恰好具有最低的缓存命中率,为 93.75%。这意味着大约 6% 的时间,PostgreSQL 必须从磁盘检索数据来满足查询。虽然这看起来可能不是很多,但在大多数情况下,最常调用的查询的比例应该为 99% 或更高。

如果仔细观察,您会发现这与我们第一个示例中突出的查询相同,该示例展示了如何查找长时间运行的查询。很快我们就发现我们可以通过某种方式调整这个查询来获得更好的性能。就目前而言,它是每次调用最慢的查询,并且它始终必须从磁盘而不是内存中读取一些数据。

具有高标准差的查询

作为最后一个示例,让我们看另一种方法,使用查询执行时间的标准差来判断哪些查询通常具有最大的改进机会。

查找最慢的查询是一个很好的起点。然而,平均值只是故事的一部分。尽管 pg_stat_statements 没有提供跟踪时间加权平均值的方法,但它确实跟踪所有调用和执行时间的标准偏差。

这有什么作用?

标准差是一种评估每个查询执行所花费的时间与总体平均值相比的方法。如果标准偏差值很小,则所有查询的执行时间都相似。如果标准偏差值很大,则表明查询的执行时间在不同请求之间存在显着差异

确定特定查询的标准差好坏需要更多数据,而不仅仅是平均值和标准差。为了充分利用这些数字,我们至少需要添加查询的最小和最大执行时间。通过这样做,我们可以开始形成查询所需的总体执行时间的心理模型。

在下面的示例结果中,我们仅显示一个查询的数据,以便于阅读,这与我们在上一个示例输出中看到的 ORDER BY time LIMIT 1 查询相同。

-- query the 10 longest running queries
WITH statements AS (
SELECT * FROM pg_stat_statements pss
        JOIN pg_roles pr ON (userid=oid)
WHERE rolname = current_user
)
SELECT calls, 
    min_exec_time,
    max_exec_time, 
    mean_exec_time,
    stddev_exec_time,
    (stddev_exec_time/mean_exec_time) AS coeff_of_variance,
    query
FROM statements
WHERE calls > 500
AND shared_blks_hit > 0
ORDER BY mean_exec_time DESC
LIMIT 10;


Name              |Value                                                |
------------------+-----------------------------------------------------+
calls             |2094                                                 |
min_exec_time     |0.060303                                             |
max_exec_time     |1468.401726                                          |
mean_exec_time    |346.9338636657108                                    |
stddev_exec_time  |212.3896857655582                                    |
coeff_of_variance |0.612190702635494                                    |
query             |SELECT time FROM nft_sales ORDER BY time ASC LIMIT $1|     

显示每个查询的最小值、最大值、平均值和标准差的查询

在这种情况下,我们可以从这些统计数据中推断出一些事情:

  • 对于我们的应用程序,此查询会被频繁调用(请记住,对于此示例数据库来说,超过 500 次调用就已经很多了)。
  • 如果我们结合平均值查看整个执行时间范围,我们会发现平均值不居中。这可能意味着存在执行时间异常值或数据存在偏差。两者都是进一步研究该查询的执行时间的充分理由。
  • 此外,如果我们查看变异系数列(coefficient of variation column),即标准差与平均值之间的比率(也称为变异系数),我们会得到 0.612,这是相当高的。一般来说,如果这个比率高于 0.3,那么数据的变化就相当大。由于我们发现数据差异很大,这似乎意味着,不是一些异常值扭曲了均值,而是有许多执行时间比应有的时间要长。这进一步确认应进一步调查该查询的执行时间。

当我一起检查这三个查询的输出时,这个特定的 ORDER BY time LIMIT 1 查询似乎很突出。它的每次调用速度比大多数其他查询要慢,它通常需要数据库从磁盘检索数据,并且执行时间似乎随着时间的推移而发生巨大变化。只要我了解此查询的使用位置以及应用程序可能受到的影响,我就会发现肯定会把这个“第一点”查询放在我需要改进的事情列表中。

加快 PostgreSQL 查询速度

pg_stat_statements 扩展是一个非常宝贵的监视工具,特别是当您了解如何在数据库和应用程序上下文中使用统计数据时。

例如,每天或每月调用几次的昂贵查询可能不值得立即进行调整。相反,每小时调用数百次(或更多)的中等速度的查询可能会更好地利用您的查询调优工作。

如果您想了解如何定期存储指标快照以及如何从静态累积信息转移到时间序列数据以实现更高效的数据库监控,请查看博客文章Point-in-Time PostgreSQL Database and Query Monitoring With pg_stat_statements。


原文连接

参考文章:

PostgreSQL高耗sql利器pg_stat_statements部署使用分享 - UCloud云社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1358353.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实现HSRP-热备份路由协议

实现HSRP-热备份路由协议 <HSRP多组实现> 网络工程师必会的企业网络常用双机热备协议之HSRP。 实验拓扑: 实验目的: 通过配置多组HSRP实现网关自动切换和链接负载均衡,既当网络正常时PC1,PC3通过R1到达R3,PC2,PC4通过R2到达R3,当R1或R2发生故障时网关能自动切换,以确…

企业微信开发:自建应用:获取企业微信IP段(用于防火墙配置)

概述 在企业微信开发流程中&#xff0c;为了确保与企业微信API的网络通信安全&#xff0c;并适应防火墙配置要求&#xff0c;开发者需要获取企业微信API服务的IP地址范围。这样&#xff0c;仅允许与企业微信官方通信的合法请求通过防火墙&#xff0c;从而保障数据传输的安全性…

教学目标是什么

教学目标&#xff0c;作为教学活动的灵魂之所在&#xff0c;对于教育者和学生都至关重要。然而&#xff0c;你是否曾对此产生过疑问&#xff1a;教学目标究竟是什么&#xff1f;它又如何影响我们的教学活动呢&#xff1f; 教学目标就像一座灯塔&#xff0c;为教学活动指明方向&…

MapInfo Pro和Python基础知识

MapInfo Pro用户长期以来一直使用MapBasic脚本语言来自动化任务、构建自定义应用程序、创建Pro的特定领域自定义、将Pro与其他工具集成等。 MapBasic主要是一种编译语言&#xff0c;这对非程序员来说有点障碍。 我们确实有MapBasic窗口&#xff0c;它允许MapBasic语句和代码直接…

罗德与施瓦茨FSVA40信号和频谱分析仪

罗德与施瓦茨FSVA40是一款功能信号和频谱分析仪&#xff0c;适用于从事射频系统的开发、生产、安装和服务的用户。FSVA40信号和频谱分析仪系列始终提供最佳的价格和性能组合&#xff0c;无论是根据最新通信标准测试生产中的无线设备&#xff0c;还是测量低相位噪声、高灵敏度和…

根本记不住MySQL进阶查询语句

1 MySQL进阶查询 1.1 MySQL进阶查询的语句 全文以数据库location和Store_Info为实例 ---- SELECT ----显示表格中一个或数个字段的所有数据记录 语法&#xff1a;SELECT "字段" FROM "表名"; select 列名 from 表名 ; ---- DISTINCT ----不显示重复的数…

农业银行RPA实践 3大典型案例分析

零接触开放金融服务在疫情之下被越来越多的银行和客户所认同&#xff0c;引起了更广泛的持续关注&#xff0c;各家银行纷纷开展产品服务创新&#xff0c;加速渠道迁移&#xff0c;同时通过远程办公、构建金融生态等方式积极推进零接触开放金融体系建设。 随着商业银行科技力量的…

后端开发——JDBC的学习(三)

本篇继续对JDBC进行总结&#xff1a; ①通过Service层与Dao层实现转账的练习&#xff1b; ②重点&#xff1a;由于每次使用连接就手动创建连接&#xff0c;用完后就销毁&#xff0c;这样会导致资源浪费&#xff0c;因此引入连接池&#xff0c;练习连接池的使用&#xff1b; …

新年福利|这款价值数万的报表工具永久免费了

随着数据资产的价值逐渐凸显&#xff0c;越来越多的企业会希望采用报表工具来处理数据分析&#xff0c;了解业务经营状况&#xff0c;从而辅助经营决策。不过&#xff0c;企业在选型报表工具的时候经常会遇到以下几个问题&#xff1a; 各个报表工具有很多功能和特性&#xff0c…

Python数据处理库之tablib详解

概要 Python 提供了许多库和工具来处理数据&#xff0c;其中之一就是 tablib。tablib 是一个功能强大且易于使用的库&#xff0c;用于处理各种数据格式&#xff0c;包括Excel、CSV、JSON等。它不仅可以用于数据导入和导出&#xff0c;还支持数据转换、过滤、合并等操作。本文将…

《C++语言程序设计(第5版)》(清华大学出版社,郑莉 董渊编著)习题——第2章 C++语言简单程序设计

2-28 用穷举法找出1~100的质数并显示出来。分别使用while、do-while、for循环语句实现。 // 使用while循环#include <iostream>using namespace std;int main() {int number 2;cout << "1~100之间的质数有&#xff1a;";while (number < 100) {int …

HarmonyOS应用开发之ArkTS语言学习记录

1、ArkTS介绍 ArkTS是鸿蒙生态的应用开发语言。它在保持TypeScript&#xff08;简称TS&#xff09;基本语法风格的基础上&#xff0c;对TS的动态类型特性施加更严格的约束&#xff0c;引入静态类型。同时&#xff0c;提供了声明式UI、状态管理等相应的能力&#xff0c;让开发者…

Xcode15在iOS12系统上崩溃的原因

1.1.崩溃在_dyld_start&#xff0c;如图&#xff1a; 崩溃截图 解决办法&#xff1a;在other link flags添加-ld64 注意&#xff1a;该办法只能解决运行真机&#xff0c;archive出来的包依然报错闪退...... 1.2 SwiftUI导致iOS12及以下系统闪退问题 SwiftUI是iOS13开始使用&…

MongoDB 启动时:服务名无效

1.问题场景 电脑睡眠后&#xff0c;再连接服务发现无法连接&#xff0c;启动服务报&#xff1a;服务名无效。 2.打开服务管理&#xff1a; 发现服务中没有MongoDB的服务 3.解决 &#xff08;1&#xff09;先找打MongoDB安装路径&#xff0c;把data文件夹下所有文件删除 &a…

Python之安装和环境配置

python的下载 1.可以去python官网下载&#xff0c;https://www.python.org/ 2.下载完成后&#xff0c;安装即可。 python的检测 1.打开开始-运行-cmd&#xff08;快捷键winR&#xff09;。 如果是mac&#xff0c;打开使用工具-终端。 2.在终端里输入python&#xff0c;以下…

魔法少女小Scarlet#洛谷

题目描述 Scarlet 最近学会了一个数组魔法&#xff0c;她会在 n n n\times n nn 二维数组上将一个奇数阶方阵按照顺时针或者逆时针旋转 9 0 ∘ 90^\circ 90∘。 首先&#xff0c;Scarlet 会把 1 1 1 到 n 2 n^2 n2 的正整数按照从左往右&#xff0c;从上至下的顺序填入初…

「Vue3面试系列」Vue3 所采用的 Composition Api 与 Vue2 使用的 Options Api 有什么不同?

文章目录 开始之前正文一、Options Api二、Composition Api三、对比逻辑组织Options APICompostion API 逻辑复用 小结 开始之前 Composition API 可以说是Vue3的最大特点&#xff0c;那么为什么要推出Composition Api&#xff0c;解决了什么问题&#xff1f; 通常使用Vue2开…

山西电力市场日前价格预测【2024-01-06】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-01-06&#xff09;山西电力市场全天平均日前电价为261.48元/MWh。其中&#xff0c;最高日前电价为424.18元/MWh&#xff0c;预计出现在18:00。最低日前电价为0.00元/MWh&#xff0c;预计出…

vivado non-project

https://www.xilinx.com/video/hardware/using-the-non-project-batch-flow.html --video https://cloud.tencent.com/developer/article/1169476 bd related run_my_design.tcl 交互模式 start_gui stop_gui

图解设计模式-中介者模式(Mediator)

中介者模式 定义 使用一个中介者对象&#xff08;mediator&#xff09;集中封装多个具有依赖/关联关系的对象&#xff08;colleague&#xff0c;同事对象&#xff09;之间的交互&#xff0c;使各对象之间不再互相引用&#xff0c;降低对象之间的强耦合程度&#xff0c;对象之…