外观
PostgreSQL 性能分析工具
内置性能分析工具
PostgreSQL 提供了多种内置的性能分析工具,可以帮助识别和解决性能问题。这些工具包括统计视图、系统函数和命令行工具。
EXPLAIN 与 EXPLAIN ANALYZE
EXPLAIN 是 PostgreSQL 最常用的性能分析工具,用于查看查询的执行计划。EXPLAIN ANALYZE 不仅显示执行计划,还会实际执行查询并显示执行时间和其他统计信息。
EXPLAIN 基本用法
sql
-- 查看简单查询的执行计划
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- 查看复杂查询的执行计划
EXPLAIN SELECT u.name, COUNT(o.id) AS order_count
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
GROUP BY u.name
ORDER BY order_count DESC;
-- 查看执行计划的详细信息
EXPLAIN (VERBOSE, COSTS, BUFFERS, FORMAT JSON)
SELECT * FROM users WHERE email = 'test@example.com';EXPLAIN ANALYZE 用法
sql
-- 实际执行查询并查看执行计划
EXPLAIN (ANALYZE, VERBOSE, COSTS, BUFFERS, TIMING)
SELECT * FROM users WHERE email = 'test@example.com';
-- 关闭计时信息(减少开销)
EXPLAIN (ANALYZE, TIMING OFF)
SELECT * FROM users WHERE email = 'test@example.com';
-- 格式化输出为 JSON
EXPLAIN (ANALYZE, FORMAT JSON)
SELECT * FROM users WHERE email = 'test@example.com';执行计划解读
执行计划包含以下关键信息:
- 节点类型:如 Seq Scan、Index Scan、Hash Join 等
- 成本估算:启动成本和总成本
- 行估算:预计返回的行数
- 实际执行时间:每个节点的实际执行时间
- 缓冲区使用情况:共享缓冲区、本地缓冲区和临时缓冲区的使用情况
Seq Scan on users (cost=0.00..100.00 rows=1 width=100) (actual time=0.100..1.000 rows=1 loops=1)
Filter: (email = 'test@example.com'::text)
Rows Removed by Filter: 999
Buffers: shared hit=10pg_stat_statements 扩展
pg_stat_statements 是 PostgreSQL 提供的一个扩展,用于收集和统计 SQL 语句的执行信息。通过 pg_stat_statements,可以识别最消耗资源的查询,包括执行时间、内存使用、IO 操作等。
安装与配置
sql
-- 安装扩展
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- 配置 postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
pgsql.stat_statements.max = 10000
pg_stat_statements.track = all
pg_stat_statements.track_utility = on
pg_stat_statements.save = on基本用法
sql
-- 查看最消耗时间的查询
SELECT
substring(query, 1, 100) AS query,
calls,
round(total_exec_time::numeric, 2) AS total_time,
round(mean_exec_time::numeric, 2) AS avg_time,
rows,
round(100 * shared_blks_hit / NULLIF(shared_blks_hit + shared_blks_read, 0), 2) AS cache_hit_rate
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
-- 查看最频繁执行的查询
SELECT
substring(query, 1, 100) AS query,
calls,
round(total_exec_time::numeric, 2) AS total_time,
round(mean_exec_time::numeric, 2) AS avg_time
FROM pg_stat_statements
ORDER BY calls DESC
LIMIT 20;
-- 查看最消耗IO的查询
SELECT
substring(query, 1, 100) AS query,
shared_blks_read,
shared_blks_hit,
temp_blks_written,
calls,
round(total_exec_time::numeric, 2) AS total_time
FROM pg_stat_statements
ORDER BY shared_blks_read DESC
LIMIT 20;
-- 重置统计信息
SELECT pg_stat_statements_reset();统计视图
PostgreSQL 提供了丰富的统计视图,用于监控数据库的运行状态。
pg_stat_activity
pg_stat_activity 视图显示当前数据库中的活动会话信息,包括查询内容、执行时间、等待事件等。
sql
-- 查看当前活动会话
SELECT
pid,
usename,
application_name,
client_addr,
state,
wait_event_type,
wait_event,
query,
query_start,
now() - query_start AS duration
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC;
-- 查看长时间运行的查询
SELECT
pid,
usename,
query,
now() - query_start AS duration
FROM pg_stat_activity
WHERE now() - query_start > interval '5 minutes'
AND state != 'idle'
ORDER BY duration DESC;
-- 查看等待事件统计
SELECT
wait_event_type,
wait_event,
count(*) AS count,
state
FROM pg_stat_activity
WHERE state = 'active'
GROUP BY wait_event_type, wait_event, state
ORDER BY count DESC;pg_stat_database
pg_stat_database 视图显示数据库级别的统计信息,包括连接数、事务数、IO 操作等。
sql
-- 查看数据库统计信息
SELECT
datname,
numbackends AS active_connections,
xact_commit,
xact_rollback,
blks_read,
blks_hit,
round(100 * blks_hit / NULLIF(blks_hit + blks_read, 0), 2) AS cache_hit_rate,
temp_files,
temp_bytes,
deadlocks
FROM pg_stat_database
WHERE datname NOT IN ('template0', 'template1')
ORDER BY datname;pg_stat_user_tables
pg_stat_user_tables 视图显示用户表的统计信息,包括扫描次数、更新次数、活行和死行数量等。
sql
-- 查看表统计信息
SELECT
relname AS table_name,
seq_scan,
seq_tup_read,
idx_scan,
idx_tup_fetch,
n_tup_ins,
n_tup_upd,
n_tup_del,
n_live_tup,
n_dead_tup,
round(100 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_tuple_ratio,
last_vacuum,
last_autovacuum,
last_analyze,
autovacuum_count
FROM pg_stat_user_tables
ORDER BY seq_scan DESC
LIMIT 20;pg_stat_user_indexes
pg_stat_user_indexes 视图显示用户索引的使用情况,包括扫描次数、索引元组读取次数等。
sql
-- 查看索引使用情况
SELECT
relname AS table_name,
indexrelname AS index_name,
idx_scan,
idx_tup_read,
idx_tup_fetch,
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;
-- 查看未使用的索引
SELECT
relname AS table_name,
indexrelname AS index_name,
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size
FROM pg_stat_user_indexes
WHERE idx_scan = 0
AND pg_relation_size(indexrelid) > 1024 * 1024 -- 只显示大于 1MB 的索引
ORDER BY pg_relation_size(indexrelid) DESC;命令行性能分析工具
PostgreSQL 提供了多种命令行工具,用于监控和分析数据库性能。
pg_stat
pg_stat 是一个命令行工具,用于显示数据库服务器的统计信息。
bash
# 显示数据库统计信息
pg_stat
# 显示指定数据库的统计信息
pg_stat -d app_db
# 显示表统计信息
pg_stat -t userspg_top
pg_top 是一个类似 top 的命令行工具,用于实时监控 PostgreSQL 进程和性能指标。
bash
# 启动 pg_top
pg_top
# 监控特定数据库
pg_top -d app_db
# 显示帮助信息
pg_top -hpg_waldump
pg_waldump 用于查看 WAL 日志的内容,帮助分析 WAL 生成和复制问题。
bash
# 查看 WAL 日志内容
pg_waldump /path/to/wal/000000010000000000000001
# 查看 WAL 日志的统计信息
pg_waldump -s /path/to/wal/000000010000000000000001
# 查看特定 LSN 范围的 WAL 日志
pg_waldump -r 0/12345678 -R 0/87654321 /path/to/wal/vacuumlo
vacuumlo 用于清理数据库中未使用的大型对象(LOBs)。
bash
# 清理指定数据库中的未使用 LOBs
vacuumlo app_db
# 预览要清理的 LOBs
vacuumlo -n app_db
# 删除 LOBs 并记录日志
vacuumlo -v app_db > vacuumlo.log第三方性能分析工具
除了内置工具外,还有许多第三方工具可以帮助分析 PostgreSQL 性能。
pgBadger
pgBadger 是一个功能强大的 PostgreSQL 日志分析工具,可以生成详细的 HTML 报告,包括慢查询统计、错误分析、连接统计等。
安装与使用
bash
# 安装 pgBadger(Debian/Ubuntu)
sudo apt-get install pgbadger
# 分析日志并生成报告
pgbadger /var/lib/postgresql/14/main/log/postgresql-*.log -o /tmp/pgbadger_report.html
# 分析特定时间段的日志
pgbadger --begin "2024-06-01" --end "2024-06-30" /var/lib/postgresql/14/main/log/postgresql-*.log -o /tmp/june_report.html
# 分析慢查询日志
pgbadger --slow-queries 1000 /var/lib/postgresql/14/main/log/postgresql-*.log -o /tmp/slow_queries.html报告解读
pgBadger 报告包含以下主要部分:
- 概览:显示日志的基本统计信息
- 连接统计:显示连接数、用户分布等
- 查询统计:显示查询类型分布、执行时间分布等
- 慢查询:显示执行时间最长的查询
- 错误分析:显示错误类型和频率
- 锁等待:显示锁等待事件
- 事务统计:显示事务提交和回滚情况
pgCluu
pgCluu 是一个 PostgreSQL 性能监控和报告生成工具,可以分析日志文件和系统统计信息,生成全面的 HTML 报告。
安装与使用
bash
# 安装 pgCluu
sudo apt-get install pgcluu
# 收集统计信息
pgcluu_collectd -d /var/lib/postgresql/14/main -o /tmp/pgcluu_data
# 生成报告
pgcluu -i /tmp/pgcluu_data -o /tmp/pgcluu_reportpgbouncer
pgbouncer 是一个 PostgreSQL 连接池工具,可以监控和管理数据库连接,提高系统的并发处理能力。
监控 pgbouncer
bash
# 连接到 pgbouncer 管理数据库
psql -h pgbouncer_host -p 6432 -U pgbouncer pgbouncer
# 查看连接池状态
SHOW pools;
# 查看客户端连接
SHOW clients;
# 查看服务器端连接
SHOW servers;
# 查看统计信息
SHOW stats;pgAdmin
pgAdmin 是 PostgreSQL 的官方图形化管理工具,提供了丰富的性能监控功能。
性能监控功能
- 仪表板:显示数据库的关键性能指标
- 服务器状态:显示连接数、锁等待、事务状态等
- 活动会话:显示当前活动会话的详细信息
- 查询工具:集成了 EXPLAIN 和 EXPLAIN ANALYZE 功能
- 报表:生成各种性能报表
Prometheus + Grafana
Prometheus 和 Grafana 是流行的开源监控组合,可以监控 PostgreSQL 的各种性能指标,并生成直观的可视化仪表板。
配置 PostgreSQL Exporter
PostgreSQL Exporter 用于将 PostgreSQL 的监控指标导出到 Prometheus。
bash
# 下载并运行 PostgreSQL Exporter
docker run -d --name postgres-exporter \
-e DATA_SOURCE_NAME="postgresql://postgres:password@postgres:5432/postgres?sslmode=disable" \
-p 9187:9187 \
prometheuscommunity/postgres-exporter配置 Prometheus
yaml
# prometheus.yml
scrape_configs:
- job_name: 'postgresql'
static_configs:
- targets: ['postgres-exporter:9187']Grafana 仪表板
Grafana 提供了多种 PostgreSQL 监控仪表板模板,如 ID 为 9628 的 PostgreSQL Overview 仪表板。
性能分析最佳实践
1. 建立性能基线
- 收集正常运行时的性能指标
- 确定关键指标的正常范围
- 定期监控和比较性能变化
2. 重点关注慢查询
- 配置慢查询日志,记录执行时间超过阈值的查询
- 使用 pg_stat_statements 识别最消耗资源的查询
- 定期分析慢查询,优化执行计划和查询逻辑
3. 监控资源使用情况
- 监控 CPU、内存、磁盘 I/O 等系统资源
- 监控 PostgreSQL 的连接数、锁等待、事务数等
- 设置告警阈值,及时发现异常情况
4. 定期分析执行计划
- 对于频繁执行的查询,定期检查执行计划
- 当数据分布发生变化时,重新分析执行计划
- 使用 EXPLAIN ANALYZE 验证优化效果
5. 优化索引使用
- 监控索引的使用情况,删除未使用的索引
- 为频繁查询的列创建合适的索引
- 优化复合索引的列顺序
6. 定期维护数据库
- 定期执行 VACUUM 和 ANALYZE 操作
- 监控死元组比例,及时清理
- 定期重建索引,减少索引膨胀
常见问题(FAQ)
Q1: 如何识别慢查询?
A1: 识别慢查询的方法包括:
- 配置慢查询日志:在 postgresql.conf 中设置
log_min_duration_statement = 1000(记录执行时间超过 1 秒的查询) - 使用 pg_stat_statements 扩展:查看最消耗时间的查询
- 使用 EXPLAIN ANALYZE:分析特定查询的执行计划和执行时间
- 使用第三方工具:如 pgBadger、pgCluu 等分析日志
Q2: 如何解读 EXPLAIN 输出?
A2: EXPLAIN 输出包含以下关键信息:
- 节点类型:表示查询的执行方式,如 Seq Scan(顺序扫描)、Index Scan(索引扫描)、Hash Join(哈希连接)等
- 成本估算:启动成本(返回第一行的成本)和总成本(返回所有行的成本)
- 行估算:预计返回的行数
- 实际执行时间:EXPLAIN ANALYZE 显示的实际执行时间
- 缓冲区使用情况:共享缓冲区(shared)、本地缓冲区(local)和临时缓冲区(temp)的使用情况
Q3: 为什么查询执行计划会变化?
A3: 查询执行计划变化的原因包括:
- 统计信息变化:表的行数、数据分布发生变化
- 索引变化:创建、删除或修改索引
- 参数变化:修改了影响执行计划的参数,如 work_mem、random_page_cost 等
- PostgreSQL 版本升级:优化器算法改进
Q4: 如何优化索引使用?
A4: 优化索引使用的方法包括:
- 为频繁查询的列创建索引
- 优化复合索引的列顺序,将选择性高的列放在前面
- 避免创建过多索引,减少写入开销
- 监控索引使用情况,删除未使用的索引
- 定期重建索引,减少索引膨胀
Q5: 如何监控数据库的连接数?
A5: 监控数据库连接数的方法包括:
- 使用 pg_stat_activity 视图:查看当前连接数和连接状态
- 设置连接数告警:当连接数接近 max_connections 时触发告警
- 使用连接池:如 pgbouncer,管理和监控连接数
- 使用监控工具:如 Prometheus + Grafana,可视化连接数变化
Q6: 如何处理锁等待问题?
A6: 处理锁等待问题的方法包括:
- 识别阻塞会话:使用 pg_blocking_pids() 函数找出阻塞者
- 分析锁类型和等待事件:查看 wait_event_type 和 wait_event
- 优化查询逻辑:减少事务持有锁的时间
- 使用适当的隔离级别:避免不必要的锁竞争
- 考虑使用行级锁:减少锁的粒度
