Skip to content

PostgreSQL 慢查询指标

慢查询日志配置

1. 启用慢查询日志

sql
-- 设置慢查询阈值,单位为毫秒
ALTER SYSTEM SET log_min_duration_statement = 500;

-- 记录所有慢查询,包括被终止的查询
ALTER SYSTEM SET log_min_duration_statement = 0;

-- 关闭慢查询日志
ALTER SYSTEM SET log_min_duration_statement = -1;

-- 验证配置
SHOW log_min_duration_statement;

2. 配置日志格式

sql
-- 设置详细的日志前缀格式
ALTER SYSTEM SET log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ';

-- 设置日志格式为CSV(可选)
ALTER SYSTEM SET log_destination = 'stderr,csvlog';

-- 验证配置
SHOW log_line_prefix;
SHOW log_destination;

3. 配置日志记录内容

sql
-- 记录查询执行计划
ALTER SYSTEM SET log_executor_stats = on;

-- 记录查询规划器统计信息
ALTER SYSTEM SET log_planner_stats = on;

-- 记录缓冲区使用情况
ALTER SYSTEM SET log_bufferings = on;

-- 验证配置
SHOW log_executor_stats;
SHOW log_planner_stats;

pg_stat_statements 扩展

1. 安装和配置

sql
-- 安装扩展
CREATE EXTENSION pg_stat_statements;

-- 配置扩展参数
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
ALTER SYSTEM SET pg_stat_statements.max = 10000;
ALTER SYSTEM SET pg_stat_statements.track = 'all';
ALTER SYSTEM SET pg_stat_statements.track_utility = on;
ALTER SYSTEM SET pg_stat_statements.save = on;

-- 重启数据库使配置生效
-- pg_ctl restart

2. 常用慢查询指标查询

sql
-- 获取执行时间最长的前10个查询
SELECT 
    queryid,
    query,
    calls,
    total_exec_time,
    mean_exec_time,
    max_exec_time,
    rows
FROM 
    pg_stat_statements
ORDER BY 
    total_exec_time DESC
LIMIT 10;

-- 获取调用次数最多的前10个查询
SELECT 
    queryid,
    query,
    calls,
    total_exec_time,
    mean_exec_time,
    rows
FROM 
    pg_stat_statements
ORDER BY 
    calls DESC
LIMIT 10;

-- 获取平均执行时间最长的前10个查询
SELECT 
    queryid,
    query,
    calls,
    total_exec_time,
    mean_exec_time,
    max_exec_time
FROM 
    pg_stat_statements
ORDER BY 
    mean_exec_time DESC
LIMIT 10;

慢查询指标类型

1. 时间相关指标

指标名称描述单位
total_exec_time查询总执行时间毫秒
mean_exec_time查询平均执行时间毫秒
max_exec_time查询最大执行时间毫秒
min_exec_time查询最小执行时间毫秒
stddev_exec_time查询执行时间标准差毫秒

2. 调用相关指标

指标名称描述单位
calls查询调用次数
rows查询返回总行数
rows/sec查询每秒返回行数行/秒
calls/sec查询每秒调用次数次/秒

3. 资源消耗指标

指标名称描述单位
shared_blks_hit共享缓冲区命中次数
shared_blks_read共享缓冲区读取次数
shared_blks_dirtied共享缓冲区修改次数
shared_blks_written共享缓冲区写入次数
local_blks_hit本地缓冲区命中次数
local_blks_read本地缓冲区读取次数
temp_blks_read临时缓冲区读取次数
temp_blks_written临时缓冲区写入次数
blk_read_time块读取时间毫秒
blk_write_time块写入时间毫秒

慢查询指标监控工具

1. 内置工具

sql
-- 使用pg_stat_activity监控当前慢查询
SELECT 
    pid,
    datname,
    usename,
    application_name,
    client_addr,
    backend_start,
    query_start,
    state_change,
    state,
    wait_event_type,
    wait_event,
    query
FROM 
    pg_stat_activity
WHERE 
    state = 'active' 
    AND now() - query_start > interval '500ms';

-- 使用EXPLAIN ANALYZE分析查询执行计划
EXPLAIN ANALYZE 
SELECT * FROM orders 
WHERE order_date >= '2023-01-01' 
ORDER BY total_amount DESC 
LIMIT 100;

2. 第三方工具

  • pgBadger:生成HTML格式的慢查询分析报告
  • pgsi:PostgreSQL日志统计工具
  • pg_stat_monitor:增强版的pg_stat_statements
  • Prometheus + Grafana:集中式监控和可视化
  • Datadog:云原生监控平台
  • New Relic:应用性能监控平台

慢查询指标分析方法

1. 识别关键指标

  • 高总执行时间:影响整体性能的查询
  • 高平均执行时间:单次执行耗时较长的查询
  • 高调用次数:频繁执行的查询
  • 高资源消耗:消耗大量CPU、内存或I/O的查询

2. 分析执行计划

sql
-- 获取查询的执行计划
EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SETTINGS) 
SELECT * FROM orders 
WHERE customer_id = 123 
AND order_date >= '2023-01-01';

-- 比较不同执行计划
EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON) 
SELECT * FROM orders 
WHERE customer_id = 123 
AND order_date >= '2023-01-01';

3. 优化建议生成

根据慢查询指标分析,生成优化建议:

  • 添加索引:为频繁查询的列添加索引
  • 优化查询:重写查询语句,避免全表扫描
  • 调整配置:修改数据库参数,如work_mem、shared_buffers等
  • 重构表结构:分区表、调整数据类型等
  • 使用物化视图:预计算复杂查询结果

慢查询指标告警配置

1. 使用pg_cron定期检查

sql
-- 安装pg_cron扩展
CREATE EXTENSION pg_cron;

-- 配置cron.job_queue_processes
ALTER SYSTEM SET cron.job_queue_processes = 4;

-- 创建慢查询告警任务
SELECT cron.schedule('*/5 * * * *', $$
  INSERT INTO alert_log (alert_type, alert_message, alert_time)
  SELECT 'slow_query', 
         format('Query executed %s times with total time %s ms: %s', 
                calls, total_exec_time, query),
         now()
  FROM pg_stat_statements
  WHERE total_exec_time > 10000 -- 10秒
  ORDER BY total_exec_time DESC
  LIMIT 5;
$$);

-- 查看所有定时任务
SELECT * FROM cron.job;

2. 使用Prometheus和Alertmanager

yaml
# Prometheus配置示例
scrape_configs:
  - job_name: 'postgresql'
    static_configs:
      - targets: ['localhost:9187']

# Alertmanager告警规则示例
groups:
- name: postgresql-alerts
  rules:
  - alert: SlowQuery
    expr: pg_stat_statements_total_exec_time > 10000
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Slow query detected"
      description: "Query {{ $labels.queryid }} has total execution time {{ $value }} ms"

慢查询指标最佳实践

1. 配置建议

场景建议配置
开发环境log_min_duration_statement = 100ms
测试环境log_min_duration_statement = 200ms
生产环境log_min_duration_statement = 500ms
性能调优log_min_duration_statement = 0

2. 监控频率

  • 实时监控:使用pg_stat_activity监控当前慢查询
  • 定期分析:每天或每周生成慢查询报告
  • 趋势分析:每月或每季度进行趋势分析

3. 数据保留

sql
-- 重置pg_stat_statements统计数据
SELECT pg_stat_statements_reset();

-- 定期重置统计数据(使用pg_cron)
SELECT cron.schedule('0 0 * * *', 'SELECT pg_stat_statements_reset();');

4. 安全考虑

  • 限制pg_stat_statements的访问权限
  • 避免在生产环境记录所有查询(log_min_duration_statement = 0)
  • 定期清理慢查询日志,避免磁盘空间不足
  • 加密敏感数据的慢查询日志

常见问题及解决方案

1. 慢查询日志不记录

问题:配置了慢查询日志,但没有记录慢查询

解决方案

sql
-- 检查慢查询阈值配置
SHOW log_min_duration_statement;

-- 检查日志收集器是否启用
SHOW logging_collector;

-- 检查日志级别
SHOW log_min_messages;

-- 检查日志目标
SHOW log_destination;

2. pg_stat_statements不显示数据

问题:安装了pg_stat_statements扩展,但没有统计数据

解决方案

sql
-- 检查扩展是否正确安装
SELECT * FROM pg_extension WHERE extname = 'pg_stat_statements';

-- 检查shared_preload_libraries配置
SHOW shared_preload_libraries;

-- 检查pg_stat_statements参数
SHOW pg_stat_statements.track;
SHOW pg_stat_statements.max;

-- 检查是否有查询执行
SELECT * FROM pg_stat_statements;

3. 慢查询指标过多

问题:pg_stat_statements记录了过多的查询,难以分析

解决方案

sql
-- 增加pg_stat_statements.max值
ALTER SYSTEM SET pg_stat_statements.max = 20000;

-- 调整track参数,只跟踪用户查询
ALTER SYSTEM SET pg_stat_statements.track = 'top';

-- 定期重置统计数据
SELECT pg_stat_statements_reset();

-- 使用pg_stat_statements_filter扩展过滤查询

常见问题(FAQ)

Q1:慢查询阈值设置多少合适?

A1:慢查询阈值的设置取决于业务需求和系统性能:

  • 开发环境:100-200ms,便于开发人员调试
  • 测试环境:200-500ms,接近生产环境
  • 生产环境:500ms-1s,平衡性能和日志量
  • 性能调优:0ms,记录所有查询

Q2:pg_stat_statements和慢查询日志有什么区别?

A2:pg_stat_statements和慢查询日志的区别:

特性pg_stat_statements慢查询日志
存储位置内存文件
数据格式结构化数据文本或CSV
保留时间重启后丢失(可配置保存)取决于日志策略
查询信息统计汇总详细日志
性能影响较低较高
分析难度较易较难

Q3:如何导出慢查询指标?

A3:导出慢查询指标的方法:

sql
-- 导出pg_stat_statements数据
COPY (
  SELECT queryid, query, calls, total_exec_time, mean_exec_time, max_exec_time
  FROM pg_stat_statements
  ORDER BY total_exec_time DESC
  LIMIT 100
) TO '/tmp/slow_queries.csv' WITH CSV HEADER;

-- 使用pg_dump导出
pg_dump -d mydb -t pg_stat_statements -f pg_stat_statements.sql

Q4:慢查询指标会影响数据库性能吗?

A4:慢查询指标的性能影响:

  • 慢查询日志:较高,尤其是log_min_duration_statement = 0时
  • pg_stat_statements:较低,因为只记录统计汇总
  • pg_stat_monitor:中等,提供更详细的监控

Q5:如何自动化分析慢查询指标?

A5:自动化分析慢查询指标的方法:

  1. 使用pg_cron定期生成慢查询报告
  2. 使用pgBadger生成HTML格式的分析报告
  3. 使用Prometheus和Grafana创建可视化仪表板
  4. 集成到CI/CD流程中,自动检测性能回归
  5. 使用机器学习工具预测慢查询

Q6:如何比较不同时间段的慢查询指标?

A6:比较不同时间段慢查询指标的方法:

  1. 定期导出慢查询数据,存储到外部数据库
  2. 使用时间序列数据库(如InfluxDB)存储指标
  3. 使用Grafana创建趋势图,比较不同时间段的指标
  4. 使用自定义脚本比较不同导出文件

案例研究:电商平台慢查询优化

1. 场景描述

某电商平台在促销期间出现性能问题,用户访问速度变慢,数据库CPU使用率高达90%。

2. 问题分析

sql
-- 查看慢查询指标
SELECT 
    queryid,
    query,
    calls,
    total_exec_time,
    mean_exec_time,
    max_exec_time
FROM 
    pg_stat_statements
ORDER BY 
    total_exec_time DESC
LIMIT 5;

-- 分析执行计划
EXPLAIN ANALYZE 
SELECT * FROM orders 
WHERE order_date >= '2023-01-01' 
AND status = 'completed' 
ORDER BY order_date DESC 
LIMIT 1000;

3. 解决方案

sql
-- 添加索引
CREATE INDEX idx_orders_status_date ON orders(status, order_date);

-- 优化查询
EXPLAIN ANALYZE 
SELECT id, order_date, customer_id, total_amount, status 
FROM orders 
WHERE status = 'completed' 
AND order_date >= '2023-01-01' 
ORDER BY order_date DESC 
LIMIT 1000;

-- 调整配置参数
ALTER SYSTEM SET work_mem = '16MB';
ALTER SYSTEM SET random_page_cost = 1.1;

4. 优化效果

指标优化前优化后
总执行时间12000ms800ms
平均执行时间600ms40ms
调用次数2020
CPU使用率90%40%