先测量再改配置
慢查询排查统一按四步走:找到慢操作、看清执行代价、定位原因、验证修复。各库都提供了分析器与执行计划工具,先把真实执行的扫描量与返回量测出来,再决定加索引还是改写法;直接调大超时与缓存只是把压力往后推。
单次耗时与累计开销分开看
判断一条语句是不是真的慢,要把单次耗时与累计资源占用分开:一次扫描上千万行的报表查询只占用户几秒,却可能把节点内存与磁盘读带宽吃掉大半;反过来,毫秒级的查询在高频调用下累计开销同样可观。前者优化执行计划,后者通常要靠缓存或预聚合解决。
四步排查法
- 找到慢操作:打开慢日志或分析器,按耗时排序取前几条
- 看清代价:执行计划里的扫描行数、返回行数与耗时占比
- 定位原因:缺索引、写法导致索引失效、数据倾斜或返回体积过大
- 验证修复:在同样数据与同样冷热条件下对比修改前后的指标
各库的定位入口
各库的定位入口
# MongoDB:开启慢查询分析器(100ms 以上记录)
mongosh --eval "db.setProfilingLevel(1, { slowms: 100 })"
mongosh --eval "db.system.profile.find().sort({ millis: -1 }).limit(5).pretty()"
# Elasticsearch:索引级慢查询日志阈值
curl -X PUT "localhost:9200/my-index/_settings" -H 'Content-Type: application/json' \
-d '{"index.search.slowlog.threshold.query.warn": "5s", "index.search.slowlog.threshold.fetch.warn": "2s"}'
# ClickHouse:查询日志里找耗时最长的查询
clickhouse-client -q "SELECT query_duration_ms, read_rows, query FROM system.query_log WHERE type = 'QueryFinish' ORDER BY query_duration_ms DESC LIMIT 5"
# Redis:慢命令与延迟诊断
redis-cli SLOWLOG GET 10
redis-cli --latency-history执行计划示例
执行计划示例
// MongoDB:看扫描文档数与返回数之比
db.orders.find({ status: "open", city: "hz" }).explain("executionStats")
// 关键字段:totalDocsExamined 与 nReturned
// Elasticsearch:用 profile 看查询各阶段耗时
// GET /my-index/_search { "profile": true, "query": { ... } }
// ClickHouse:看读取行数与索引命中情况
// EXPLAIN indexes = 1 SELECT ... FROM events WHERE ts >= now() - INTERVAL 1 DAY;现象与常见原因
| 现象 | 常见原因 | 下一步 |
|---|---|---|
| 扫描远大于返回 | 缺索引或索引选择不佳 | 补复合索引并复核字段顺序 |
| 扫描正常但耗时长 | 排序、聚合或返回体积过大 | 收窄投影与返回条数 |
| 部分查询慢得不均匀 | 数据倾斜或热点分片 | 看分片级耗时分布 |
| 忽快忽慢 | 缓存冷热、锁等待或合并争用 | 对比冷热一致条件下的耗时 |
判断标准是扫描放大倍数:扫描量远大于返回量通常缺索引或索引选择不佳;扫描量正常但耗时长,则要看排序、聚合与网络返回体积。