postgresql慢查询排查和复现
一. 介绍一张表:pg_stat_activity
pg_stat_activity
是 PostgreSQL 中一个非常有用的系统视图,提供了有关当前数据库连接和活动查询的信息。通过查询这个视图,你可以获取有关正在执行的查询、连接的用户、进程 ID 等信息。以下是 pg_stat_activity
视图中的一些关键列:
datid
: 数据库标识符,表示正在连接的数据库的唯一标识符。datname
: 数据库名称。pid
: 进程 ID,表示数据库连接的唯一标识符。usesysid
: 连接用户的系统标识符。usename
: 连接用户名。application_name
: 连接的应用程序名称(如果应用程序设置了名称)。client_addr
: 客户端的 IP 地址。client_hostname
: 客户端的主机名。client_port
: 客户端连接使用的端口。backend_start
: 连接开始时的时间戳。xact_start
: 事务开始时的时间戳。query_start
: 查询开始执行的时间戳。state
: 连接状态(例如,idle、active、idle in transaction 等)。active
: 表示当前连接正在执行查询或事务。idle
: 表示当前连接处于空闲状态,没有正在执行的查询或事务。idle in transaction
: 表示当前连接处于事务中,但没有正在执行的查询。可能是事务开始后一段时间没有活动。idle in transaction (aborted)
: 表示当前连接处于事务中,但由于某种原因事务已被中止。fastpath function call
: 表示当前连接正在执行一个快速路径函数调用。disabled
: 表示当前连接的活动状态已被禁用。
query
: 当前正在执行的查询文本。waiting
: 是否在等待锁。
用 pg_stat_activity
视图,可以监视当前数据库连接的活动状态,了解哪些查询正在执行及运行时间等信息。
二. 复现慢查询
在查询中引入延迟,pg_sleep()
是 PostgreSQL 中的一个函数,用于在查询中引入延迟。这个函数会使查询进程休眠指定的秒数。如果不提供参数,默认为 0 秒。切记不要再生产环境使用
.
SELECT pg_sleep(100); -- 这将使查询休眠100秒钟
三. 排查慢查询语句
总的来说,这个查询可以识别数据库中运行时间较长的查询(下面是排查超过30秒的sql,可根据实际需要修改)。
SELECT pid, datname, usename, query, extract(epoch from (now() - query_start)) as total_time, count(1) AS slowsql_count FROM pg_stat_activity where state not in('idle') and query !='' and extract(epoch from (now() - query_start)) > 30 GROUP BY pid, datname, usename, query, total_time;
SELECT pid, datname, usename, query, extract(epoch from (now() - query_start)) as total_time, count(1) AS slowsql_count
pid
: 进程ID,表示数据库连接的唯一标识符。datname
: 数据库名称。usename
: 执行查询的用户名称。query
: 正在执行的查询文本。extract(epoch from (now() - query_start)) as total_time
: 通过计算当前时间与查询开始时间的差值,获取查询已运行的总时间(以秒为单位)。count(1) AS slowsql_count
: 用于计算相同查询的数量,即慢查询的数量。
FROM pg_stat_activity
- 从 PostgreSQL 的
pg_stat_activity
视图中选择活跃的数据库连接信息。这个视图包含了关于当前数据库会话和查询的统计信息。
- 从 PostgreSQL 的
WHERE state NOT IN ('idle') AND query != '' AND extract(epoch from (now() - query_start)) > 10
state NOT IN ('idle')
: 确保排除处于空闲状态的数据库连接,只选择活跃的连接。query != ''
: 排除空查询,确保只选择正在执行的查询。extract(epoch from (now() - query_start)) > 30
: 选择运行时间超过30秒的查询。
GROUP BY pid, datname, usename, query, total_time
- 对选择的结果进行分组,以便聚合相同查询的统计信息。
查询结果:成功定位到慢查询语句:SELECT pg_sleep(100);
四. 慢查询优化方案
- 查询优化:
- 通过使用
EXPLAIN
分析查询计划,了解 PostgreSQL 是如何执行查询的。优化查询计划可以提高查询性能。 - 调整查询,避免不必要的全表扫描,确保正确使用索引。
- 通过使用
- 索引优化:
- 确保表上的索引是合理的,并涵盖了查询中用于筛选和排序的列。
- 避免过多的索引,因为它们可能会导致性能下降。
- 统计信息更新:
- 确保 PostgreSQL 统计信息是最新的。自动化统计信息更新可以通过 PostgreSQL 的自动统计信息收集器来完成。
- 分区表:
- 对大型表进行分区,可以提高查询性能,尤其是对那些经常使用范围查询的表。
- 调整内存配置:
- 调整
shared_buffers
和effective_cache_size
参数,以确保数据库能够充分利用系统内存。
- 调整
- 定期维护:
- 定期执行
VACUUM
和ANALYZE
操作,以确保表的空间得到优化,同时更新统计信息。
- 定期执行
- 使用连接池:
- 考虑使用连接池,例如 PgBouncer,以减轻数据库服务器的负载。
- 日志和监控:
- 启用 PostgreSQL 的查询日志,并使用工具如 pgBadger 分析日志,以便及时发现慢查询。
- 使用监控工具,如 pg_stat_statements 扩展,监视查询性能。
- 升级 PostgreSQL 版本:
- 考虑升级到最新的 PostgreSQL 版本,因为新版本通常包含性能改进和优化。
- 使用扩展:
- 考虑使用一些性能优化的扩展,例如
pg_repack
用于表重组,pg_partman
用于表分区等。
- 考虑使用一些性能优化的扩展,例如
常包含性能改进和优化。
10. 使用扩展:
- 考虑使用一些性能优化的扩展,例如 pg_repack
用于表重组,pg_partman
用于表分区等。