SQL 查询很慢,如何排查是否是硬件的问题?
内容:判断路径 -> 具体手段 -> 可操作指标 -> 结论方法
SQL 慢 ≠ 一定是硬件问题
但如果出现以下特征,高度怀疑是硬件瓶颈:
- 同一 SQL,EXPLAIN 计划合理
- 执行时间不稳定(抖动)
- CPU / IO / 内存 某一项持续打满
- 数据量没变,但 突然变慢
SQL 慢
↓
EXPLAIN ANALYZE 是否正常?
↓
数据库等待事件?
↓
CPU / 内存 / IO 指标
↓
文件系统 / 磁盘
↓
虚拟化 / 云宿主机
EXPLAIN (ANALYZE, BUFFERS)
SELECT ...;
关键判断点
| 现象 | 说明 |
|---|---|
| Seq Scan 扫描百万行 | 索引问题 |
| Rows 预估 vs 实际差异巨大 | 统计信息问题 |
| Execution Time 高 | 可能硬件 |
| Planning Time 很低 | 正常 |
看 BUFFERS(关键)
Buffers: shared hit=120000 read=50000
- hit 高 -> 内存命中
- read 高 -> 磁盘 IO 压力
👉 read 高 = 怀疑磁盘
查看当前慢查询在等什么
SELECT
pid,
wait_event_type,
wait_event,
state,
query
FROM pg_stat_activity
WHERE state != 'idle';
重点看:
| wait_event_type | 含义 |
|---|---|
| IO | 磁盘瓶颈 |
| CPU | 计算瓶颈 |
| Lock | 锁等待 |
| LWLock | 内部资源争用 |
| Client | 客户端慢 |
👉 大量 IO = 硬件或参数问题
top -Hp $(pidof postgres)
判断:
| 现象 | 结论 |
|---|---|
| 单核 100% | SQL 单线程 |
| 所有核 100% | CPU 不够 |
| load 高,CPU 低 | IO wait |
vmstat 1
重点列:
| 列 | 含义 |
|---|---|
| us | 用户态 CPU |
| sy | 内核态 |
| wa | IO wait |
👉 wa > 20% = IO 瓶颈
SELECT
sum(blks_read) AS disk_read,
sum(blks_hit) AS cache_hit
FROM pg_stat_database;
命中率计算
hit_ratio = hit / (hit + read)
👉 < 99%,说明内存不足或参数不合理
free -h
关注:
- 是否频繁 swap
- cache 是否被回收
vmstat 1
si / so > 0 -> 灾难
iostat -x 1
重点看:
| 指标 | 说明 |
|---|---|
| %util | >80% 饱和 |
| await | >20ms 慢 |
| svctm | 服务时间 |
| r/s w/s | 读写量 |
👉 %util 100% = 磁盘打满
SELECT * FROM pg_stat_bgwriter;
- checkpoints 频繁
- buffers_backend 高
👉 IO 压力
常见坑
| 问题 | 后果 |
|---|---|
| ext4 未调优 | fsync 慢 |
| NFS | WAL 极慢 |
| 云盘 IOPS 限制 | 抖动 |
| RAID5 | 写入慢 |
WAL 单独盘?
df -h
👉 WAL 和 data 在一起 = 风险
云主机典型问题
- 邻居 IO 干扰
- 突发型实例用完 credit
- 存储限速
判断方法
- 同一 SQL 执行时间不稳定
- 夜间更快,白天更慢
满足 ≥3 条,几乎可以定性:
- ✅ SQL 计划合理
- ✅ 索引齐全
- ✅ BUFFERS read 高
- ✅ wait_event_type = IO
- ✅ iostat %util ≈ 100%
- ✅ vmstat wa 高
- ✅ CPU 未满但慢
👉 结论:硬件瓶颈(磁盘 / 内存 / 云盘)
| 现象 | 更可能 |
|---|---|
| IO 等待高 | 磁盘 |
| cache 命中低 | 内存 |
| checkpoint 频繁 | 参数 |
| load 高 CPU 低 | IO |
| 查询抖动 | 存储 |
先 SQL -> 再等待 -> 看 IO -> 查 CPU -> 核内存 -> 盘性能