查找最耗费资源的SQL(Top SQL)
什么是Top SQL?
Top SQL是指在特定时间段内消耗系统资源(CPU、IO、内存)最多或执行频率最高的SQL语句。快速且准确地定位Top SQL是数据库性能优化的关键阶段。
前提条件
Top SQL分析通常依赖pg_stat_statements插件,该插件用于收集SQL语句的执行统计信息。
安装pg_stat_statements插件,请参见使用pg_stat_statements插件。
Top SQL的最佳排查时机
在排查性能问题时,“什么时候查”决定了能够获取的数据是否有效。
| 排查时机 | 适用场景 | 推荐工具/方法 |
|---|---|---|
| 业务高峰期/故障发生时 | 在数据库卡顿、CPU飙升、业务响应慢场景,需立刻定位当前“谁在占用资源”。 | pg_stat_activity(查正在运行的进程) |
| 日常巡检/低负载期 | 在分析长期累积的性能瓶颈,优化全量SQL逻辑的场景,适合分析“哪些SQL历史累计耗时最长”。 | pg_stat_statements(查历史统计视图) |
| 定期快照对比 | 用于对比两个时间点之间的差异,定位新增劣化SQL。 | 定时导出pg_stat_statements数据对比 |
Top SQL定位查询模板
以下为针对不同资源维度的查询模板。这些查询基于pg_stat_statements历史视图,已针对PostgreSQL 14及以上版本调整了列名兼容性。
- 找出最消耗总时间的SQL(CPU飙升)
该类SQL通常是性能优化的首选对象,因为占用时间越长,优化后的收益越大。
-- PostgreSQL 13及更低版本 SELECT userid::regrole, dbid, query FROM pg_stat_statements ORDER BY total_time DESC LIMIT 5; -- PostgreSQL 14及更高版本 SELECT userid::regrole, dbid, query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
- 找出最消耗IO的SQL(磁盘瓶颈)
该类SQL涉及大量的数据块读写,通常意味着缺少索引或存在全表扫描。
-- PostgreSQL 13及更低版本 SELECT userid::regrole, dbid, query FROM pg_stat_statements ORDER BY (blk_read_time + blk_write_time) DESC LIMIT 5; -- PostgreSQL 14及更高版本 SELECT userid::regrole, dbid, query FROM pg_stat_statements ORDER BY (shared_blk_read_time + local_blk_read_time + temp_blk_read_time + shared_blk_write_time + local_blk_write_time + temp_blk_write_time) DESC LIMIT 5;
- 找出单次执行最慢的SQL(长尾查询)
有些SQL虽然总耗时不高(total_exec_time 小),但平均每次执行都很慢,可能会导致前端接口超时。
-- PostgreSQL 13及更低版本 SELECT userid::regrole, dbid, query FROM pg_stat_statements ORDER BY mean_time DESC LIMIT 5; -- PostgreSQL 14及更高版本 SELECT userid::regrole, dbid, query FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 5;
- 找出执行频率最高的SQL(高频微操)
有些SQL单次执行仅需0.1ms,但每秒执行数千次,累积消耗大量CPU和资源。
SELECT userid::regrole, dbid, query FROM pg_stat_statements ORDER BY calls DESC LIMIT 5;
- 结合实时状态排查(pg_stat_activity)
当系统当前响应极慢时,pg_stat_statements可能数据滞后。此时应直接查看正在执行的SQL。
SELECT pid, usename, datname, state, wait_event_type, wait_event, query, age(clock_timestamp(), query_start) AS duration FROM pg_stat_activity WHERE state != 'idle' AND query NOT LIKE '%pg_stat_activity%' ORDER BY query_start ASC;
wait_event:若显示IO:DataFileRead,说明正在读磁盘(缺索引);若显示Lock:transactionid,说明有锁冲突。
重置统计信息
pg_stat_statements记录的数据具有累积性。您可以运行以下命令定期重置计数器,以便重新采集统计信息。
SELECT pg_stat_statements_reset();