案例背景
线上反馈"系统变慢了",但慢在哪不清楚。传统性能调优流程:
- 看监控 → 延迟飙高,但不知道是 DB 还是接口
- 查慢查询日志 → 几百条,肉眼筛
- 翻代码 → 不知道哪段对应哪条慢 SQL
- 压测前端 → 不知道首屏卡在哪一帧
- 排查 3 天才出结论,优化靠经验拍脑袋
目标:用 AI 把"定位瓶颈 + 读代码 + 生成假设 + 给方案"自动化,人只做最终拍板。
工具链
- Claude:性能数据分析与瓶颈推演
- Postgres MCP:抓慢查询、看执行计划
- GitHub MCP:查对应代码
- Puppeteer MCP:测前端首屏与渲染
工作流程
Phase 1:抓慢查询(5 分钟)
Prompt:
用 Postgres MCP 查 pg_stat_statements
按 total_exec_time 倒序取前 10 条慢查询
对每条用 EXPLAIN ANALYZE 看执行计划
标记含 Seq Scan / 高 cost / 未命中索引的
AI 自动:
- 查出 Top 10 慢 SQL
- 逐条跑执行计划
- 标注可疑项:
SQL #1:SELECT * FROM orders WHERE user_id=?
执行计划:Seq Scan on orders (cost=0.00..8900 rows=1)
问题:全表扫描,无索引
平均耗时:1200ms
调用频次:8000 次/天
SQL #3:SELECT * FROM order_items WHERE order_id IN (...)
执行计划:Nested Loop + 多次单查
问题:疑似 N+1
平均耗时:800ms
Phase 2:代码定位(5 分钟)
Prompt:
基于慢 SQL,用 GitHub MCP 找到生成这些 SQL 的代码:
- orders WHERE user_id → 找 orderRepo.findByUser
- order_items IN → 找 orderItemRepo.findByOrderIds
看是否有循环内查库(N+1)
AI 调 GitHub MCP 读代码:
// orderService.js
async getUserOrders(userId) {
const orders = await orderRepo.findByUser(userId); // 1 次
const result = [];
for (const order of orders) {
const items = await orderItemRepo.findByOrderId(order.id); // ← N 次!
result.push({ ...order, items });
}
return result;
}
- 标注:典型 N+1,订单多 N 次查库。
Phase 3:前端瓶颈(5 分钟)
Prompt:
用 Puppeteer MCP 打开 /orders 页
采集 Performance trace
定位首屏最大阻塞任务(LCP / 长任务)
截图 + 给出关键指标
AI 自动:
- 导航 + 采集 trace
- 定位:
LCP:3.8s(目标 < 2.5s)
阻塞:/api/orders 接口 2.1s(后端慢,前端背锅)
长任务:一个大 bundle 的 JS 解析 600ms
Phase 4:根因推演(5 分钟)
Prompt:
基于 DB + 代码 + 前端数据,推演根因:
1. 首屏慢的直接原因
2. 慢在哪一层(DB/接口/前端)
3. 为什么之前没暴露
4. 给 3 个验证假设
AI 输出:
直接原因:
/orders 接口 2.1s → 首屏 LCP 3.8s
接口慢根因:N+1 查询(800ms)+ orders 全表扫描(1.2s)
慢在哪一层:
DB 层(2 条慢 SQL)→ 接口层(串行 N+1)→ 前端只是等接口
为什么没暴露:
1. 订单量小之前 N+1 不明显
2. orders 表行数少时 Seq Scan 不慢
3. 没有慢 SQL 告警阈值
验证假设:
H1:加索引后 orders 查询 < 10ms
→ 验证:建索引后 EXPLAIN ANALYZE
H2:N+1 改 JOIN 后接口 < 300ms
→ 验证:改写代码压测
H3:前端 bundle 拆分后长任务消失
→ 验证:拆包后重测 trace
Phase 5:分阶段优化方案(5 分钟)
Prompt:
给出修复方案,分紧急止血、短期、长期
AI 输出:
紧急止血(今天):
1. orders.user_id 加索引(DB 层,立竿见影)
2. N+1 改批量 IN 查询(一次查完所有 items)
短期(本周):
1. order_items.order_id 加索引
2. 接口加缓存(订单列表 Redis 5 分钟)
3. 慢 SQL 告警阈值接入监控
长期(本月):
1. 前端 bundle 拆分,按路由懒加载
2. 订单列表分页 + 字段裁剪(不 SELECT *)
3. 建立性能基线,每次发版回归
Phase 6:工单与跟踪(5 分钟)
配合 Linear/GitHub:
你:把优化任务建工单 + 跟踪
AI:
1. 建 3 个工单(止血/短期/长期)
2. 负责人 = 各层 owner
3. 每个工单附:根因 + 验证假设 + 预期指标
4. 接入监控,达标自动关单
关键 Prompt 复盘
Prompt 1:慢查询排序明确
按 total_exec_time 倒序取前 10
标记含 Seq Scan / 高 cost / 未命中索引的
为什么有效:限定排序维度和筛选条件,避免 AI 把几百条全列出。标记可疑项聚焦最值得优化的。
Prompt 2:N+1 探测
看是否有循环内查库(N+1)
为什么有效:明确点名 N+1 这个常见反模式,AI 会重点看 for 循环里的 await 查库。
Prompt 3:分层根因
慢在哪一层(DB/接口/前端)
为什么有效:强制分层定位,避免 AI 只说"慢"不说是哪层,后续优化才能对症。
Prompt 4:分阶段方案
紧急止血 / 短期 / 长期
为什么有效:区分立竿见影和长期改造,止血先上,根治排期,不混为一谈。
踩过的坑
坑 1:只看 DB 忽略前端
AI 只盯慢 SQL → 修完接口还是慢
→ 真因是前端 bundle 3MB
→ 漏了一层
解决:用 Puppeteer MCP 测前端,分层看,不止看 DB。
坑 2:EXPLAIN 读不懂
AI 给了执行计划但没解读
→ Seq Scan 是啥?cost 高代表啥?
解决:Prompt 要求"标记 Seq Scan / 高 cost / 未命中索引并解释含义",逼 AI 解读而非罗列。
坑 3:优化反而劣化
加索引后查询快了
→ 但写入变慢(索引维护成本)
→ 高写入表乱加索引适得其反
解决:方案要评估读写比,Postgres MCP 查表的读写比例再决定。
坑 4:N+1 修了又引入新的
批量查改完了 → 但又在新功能里写循环查库
→ 没有回归防护
解决:加 N+1 检测测试,配合 Prompt 回归测试 的思路——把"无 N+1"做成持续守住的基线。
坑 5:无基线无法判断好坏
"慢"是主观的 → 没基线 → 改完不知道有没有效
解决:建立性能基线(关键接口 P95/首屏 LCP),每次发版回归,达标才上线。
效率对比
| 环节 | 传统 | AI 辅助 | 提速 |
|---|---|---|---|
| 慢查询筛查 | 60 分钟 | 5 分钟 | 12x |
| 代码定位 | 40 分钟 | 5 分钟 | 8x |
| 前端分析 | 30 分钟 | 5 分钟 | 6x |
| 根因推演 | 50 分钟 | 5 分钟 | 10x |
| 方案输出 | 40 分钟 | 5 分钟 | 8x |
| 工单跟踪 | 20 分钟 | 5 分钟 | 4x |
| 合计 | 约 4 小时 | 30 分钟 | 8x |
准确率对比
| 维度 | 传统(人工) | AI 辅助 |
|---|---|---|
| 慢查询筛选 | 70%(累) | 90%(机器不累) |
| N+1 识别 | 60%(藏得深) | 85%(重点查循环查库) |
| 分层定位 | 中(容易盯一层) | 高(强制 DB/接口/前端) |
| 方案可行性 | 依赖经验 | 平衡(读写比+分阶段) |
AI 在 N+1 识别和分层定位上优势明显——人容易只盯自己熟的那层。
哪些环节 AI 真省时间
- ✅ 慢查询筛查:几百条秒级排序标记
- ✅ N+1 探测:重点查循环内查库
- ✅ 分层定位:强制 DB/接口/前端都看
哪些环节还得靠人
- ⚠️ 索引决策:读写比、表大小权衡靠人判断
- ⚠️ 架构级改造:分库分表、缓存策略靠人拍板
- ⚠️ 发版风险:改完要不要灰度、回滚靠人决策
- ⚠️ 业务优先级:先优化哪个接口,靠业务价值判断
质量保障
上线前必查:
- AI 读的是真实执行计划与代码(MCP 读的,非编造)
- 分层定位完整(DB + 接口 + 前端)
- 至少 2 个验证假设
- 方案分紧急/短期/长期
- 索引决策评估了读写比
- 建立性能基线,发版回归
小结
这个案例最大的启示:性能调优的瓶颈不是"懂优化技巧",而是"信息分散在哪一层都不清楚"。AI 把慢查询、代码、前端 trace 三处信息拉到一处分层定位,人只做索引决策和架构拍板。
下次遇到"系统变慢了"别凭感觉——用 Postgres MCP 抓慢 SQL、GitHub MCP 查 N+1、Puppeteer MCP 测首屏、Claude 分层推演根因,30 分钟出"DB/接口/前端各慢在哪、分阶段怎么修"的完整调优链,你会发现真正需要人脑的,可能就是那个"这表写入多到底加不加索引"的权衡。