针对oracle、mysql、pgsq进行慢sql的排查
排查慢 SQL 的核心流程是"发现->定位->分析->优化"。三大数据库实现方式不同: MySQL 依赖慢查询日志,通过 mysqldumpslow 工具分析,配合 EXPLAIN 查看执行计划 PostgreSQL 使用 pg_stat_statements 扩展模块记录SQL性能数据,结合 EXPLAIN ANALYZE 深入分析 Oracle 通过内存视
排查慢 SQL 是数据库运维和开发的核心技能。Oracle、MySQL 和 PostgreSQL 虽然内核不同,但排查逻辑相通:“发现 -> 定位 -> 分析 -> 优化”。
🐬 一、MySQL:日志驱动型 (Log-Driven)
MySQL 的排查主要依赖慢查询日志 (Slow Query Log)。它像一个“保安”,只记录超过设定时间的“可疑人员”。
1. 如何开启与配置
MySQL 默认可能未开启慢查询日志,需手动配置。
临时生效(重启失效):
-- 1. 开启日志
SET GLOBAL slow_query_log = 'ON';
-- 2. 设置阈值(单位:秒),例如记录超过 1 秒的 SQL
SET GLOBAL long_query_time = 1;
-- 3. 查看日志文件路径
SHOW VARIABLES LIKE 'slow_query_log_file';
永久生效:
修改 my.cnf (Linux) 或 my.ini (Windows):
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1 -- 【重要】记录没走索引的 SQL,即使很快
2. 如何分析
直接看日志文件很痛苦,推荐使用官方工具 mysqldumpslow 或第三方神器 pt-query-digest (Percona Toolkit)。
使用 mysqldumpslow 排序查看 top 10 最耗时的 SQL:
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# -s t: 按时间排序 (time)
# -t 10: 取前10条
核心分析工具:EXPLAIN
找到慢 SQL 后,必须在前面加 EXPLAIN 运行,查看执行计划:
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'PAID';
重点关注字段:
- type: 访问类型。
ALL(全表扫描,最差) >index>range>ref>eq_ref>const(最好)。 - key: 实际使用的索引。如果是
NULL,说明没走索引。 - rows: 预估扫描行数。越大越慢。
- Extra: 如果出现
Using filesort(文件排序) 或Using temporary(临时表),通常需要优化。
💡 生动比喻
MySQL 的慢查询日志就像小区的**“迟到登记本”**。
long_query_time是门卫设定的迟到阈值(比如 8:05 算迟到)。- 一旦有人超过这个时间进门,门卫就记下来。
EXPLAIN就像是调取监控录像,分析这个人为什么迟到:是路堵了(全表扫描)?还是他绕远路了(没走索引)?
🐘 二、PostgreSQL:模块监控型 (Module-Monitoring)
PostgreSQL 不推荐频繁使用日志文件(因为日志量巨大且难分析),而是推崇使用内置的强大扩展模块 pg_stat_statements。它像飞机的“黑匣子”,记录所有飞行的详细数据。
1. 开启 pg_stat_statements (黄金标准)
这是 PG 排查慢 SQL 的绝对核心。
步骤 A:配置文件 (postgresql.conf)
shared_preload_libraries = 'pg_stat_statements' # 必须重启生效
pg_stat_statements.track = all # 跟踪所有语句
pg_stat_statements.max = 10000 # 记录的最大语句数
修改后需重启数据库服务。
步骤 B:创建扩展
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
2. 如何分析
直接查询系统视图,找出“总耗时最长”或“调用次数最多”的 SQL。
查询 Top 10 最耗时的 SQL:
SELECT
query,
calls,
total_exec_time,
mean_exec_time,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
total_exec_time: 总耗时(可能是调用次数多导致的)。mean_exec_time: 平均每次耗时(真正的慢 SQL)。
核心分析工具:EXPLAIN (ANALYZE, BUFFERS)
PG 的 EXPLAIN 比 MySQL 更强大,建议加上 ANALYZE (真正执行一次) 和 BUFFERS (查看 IO 命中)。
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM users WHERE email LIKE '%@gmail.com';
重点关注:
- Execution Time: 真实执行时间。
- Plan Nodes:
Seq Scan: 全表扫描(坏)。Index Scan/Index Only Scan: 索引扫描(好)。Hash Join/Nested Loop: 连接算法是否合理。
- Buffers:
hit(内存命中) 多还是read(磁盘读取) 多?磁盘读多是性能杀手。
💡 生动比喻
PostgreSQL 的
pg_stat_statements就像医院的**“电子病历系统”**。
- 它不只记录“病危”病人(慢 SQL),而是记录所有病人的就诊数据。
- 医生(DBA)可以随时拉报表:哪种病(SQL 类型)发作最频繁?哪种药(执行计划)效果最差?
EXPLAIN (ANALYZE)就像是**“模拟手术”**,在真正动刀前,先演练一遍,看看哪里会出血(IO 瓶颈),哪里会堵塞(锁等待)。
🏛️ 三、Oracle:视图诊断型 (View-Diagnostic)
Oracle 是企业级数据库,它的核心理念是**“一切皆视图”**。不需要改配置文件,只要数据库在跑,数据就在内存视图里等着你去查。
1. 实时排查 (当前正在跑的慢 SQL)
如果系统现在正卡,查 v$session 和 v$sql。
-- 查找当前正在执行且耗时较长的会话
SELECT s.sid, s.serial#, s.username, q.sql_text, s.last_call_et
FROM v$session s, v$sql q
WHERE s.sql_id = q.sql_id
AND s.status = 'ACTIVE'
AND s.username IS NOT NULL
ORDER BY s.last_call_et DESC;
2. 历史排查 (过去跑过的慢 SQL)
Oracle 有强大的 AWR (Automatic Workload Repository) 报告和历史视图 v$sqlarea 或 dba_hist_sqlstat。
方法 A:直接查视图 (简单快捷)
-- 按“总_elapsed_time”找出 Top 10 SQL
SELECT sql_id, executions, elapsed_time/1000000 as total_sec, sql_text
FROM (
SELECT sql_id, executions, elapsed_time, sql_text
FROM v$sqlarea
ORDER BY elapsed_time DESC
)
WHERE ROWNUM <= 10;
方法 B:生成 AWR 报告 (专业深度)
这是 Oracle DBA 的终极武器。
-- 1. 查看可用的快照 ID
SELECT snap_id, begin_interval_time, end_interval_time FROM dba_hist_snapshot ORDER BY snap_id DESC FETCH FIRST 5 ROWS ONLY;
-- 2. 生成报告 (在 SQL*Plus 中运行)
@$ORACLE_HOME/rdbms/admin/awrrpt.sql
-- 输入开始快照 ID 和 结束快照 ID,它会生成一个详细的 HTML/TXT 报告,包含:
-- * Load Profile (负载概况)
-- * SQL ordered by Elapsed Time (按耗时排序的 SQL)
-- * Wait Events (等待事件,判断是 CPU 不够还是 IO 太慢)
核心分析工具:EXPLAIN PLAN & DBMS_XPLAN
-- 1. 解释计划
EXPLAIN PLAN FOR SELECT * FROM emp WHERE deptno = 10;
-- 2. 查看格式化输出
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
重点关注:
- Cost: 优化器预估的成本,越低越好。
- Operation:
TABLE ACCESS FULL(全表扫描) 通常是优化目标。 - Wait Events (在 AWR 报告中):
db file scattered read(多块读,通常全表扫描),db file sequential read(单块读,通常索引),enq: TX - row lock contention(行锁争用)。
💡 生动比喻
Oracle 就像一架波音 747 的驾驶舱。
- 仪表盘上(
v$视图)密密麻麻全是实时数据:油压、速度、引擎温度。- 你不需要去翻黑匣子(日志),直接看仪表盘就知道哪个引擎(SQL)过热了。
- AWR 报告 就像是**“飞行数据记录仪分析报告”**,航班结束后,工程师可以复盘整个飞行过程,精确到每一秒的油耗和风速,找出为什么这次飞行比上次慢了 10 分钟。
⚔️ 四、横向对比总结
| 特性 | MySQL | PostgreSQL | Oracle |
|---|---|---|---|
| 核心机制 | 日志文件 (Slow Log) | 内存模块 (pg_stat_statements) | 动态视图 (v$sql, AWR) |
| 开启难度 | 低 (配置参数即可) | 中 (需修改 config 并重启,建扩展) | 无 (默认开启,企业版 AWR 需 License) |
| 性能影响 | 高并发下写日志可能有轻微 IO 开销 | 极低 (内存统计) | 极低 (内存统计),AWR 采集有微小开销 |
| 分析工具 | mysqldumpslow, pt-query-digest |
直接 SQL 查询 pg_stat_statements |
awrrpt.sql, ASH Report |
| 执行计划 | EXPLAIN (静态为主) |
EXPLAIN (ANALYZE, BUFFERS) (动态+IO) |
DBMS_XPLAN + Wait Events (等待事件) |
| 最大痛点 | 日志轮转管理,格式解析麻烦 | 忘记开启 pg_stat_statements |
AWR 功能需要付费 License (19c 后部分受限) |
| 一句话口诀 | 查日志,看 Explain | 开插件,查视图,跑 Analyze | 查 V$视图,跑 AWR 报告 |
🚀 五、通用优化思路 (不管用什么库)
- 索引是王道:80% 的慢 SQL 是因为没走索引或索引失效(如对字段做计算、
LIKE '%...')。 - 拒绝
SELECT *:只查需要的列,利用覆盖索引减少回表。 - 小表驱动大表:在 JOIN 操作中,确保数据量小的表驱动数据量大的表。
- 分页优化:深分页 (
LIMIT 100000, 10) 是性能杀手,改用WHERE id > last_id方式。 - 硬件与配置:
- MySQL: 调整
innodb_buffer_pool_size。 - PG: 调整
shared_buffers,work_mem,effective_cache_size。 - Oracle: 调整
SGA,PGA大小。
- MySQL: 调整
建议:
- MySQL 用户:务必开启
log_queries_not_using_indexes,它能帮你抓到那些“跑得快但没走索引”的隐患 SQL。 - PostgreSQL 用户:生产环境必须开启
pg_stat_statements,这是 PG 的灵魂。 - Oracle 用户:学会看 AWR 报告中的 “Top 5 Timed Foreground Events”,它能直接告诉你系统是卡在 CPU、IO 还是锁上。
更多推荐

所有评论(0)