慢查询优化诊断器
将以下提示词粘贴到你的 AI 对话框中:
请根据 https://skillhub.cn/install/skillhub.md,安装 @user_3c6cb52e/query-optimization-1991513ccie-png 到当前 AI 助手,使助手能够解析 EXPLAIN 执行计划、诊断慢查询并修复 ORM N+1 问题。
技能介绍
当查询从 4 秒变成 88 毫秒
在拥有 50 万订单的报表系统里,一个连接三张表的查询能吃掉 4.2 秒的响应时间。更糟的是,Django 列表页每次渲染发出 201 条 SQL,其中 200 条只是重复加载关联对象。这类问题不会在代码评审中暴露,只有当生产环境的实际执行计划摆到面前,你才会看到顺序扫描扫过整张表、索引缺失导致的嵌套循环爆炸、以及 ORM 懒加载在循环里堆出的 N+1 查询。
这个技能解决什么
这个技能的核心是把慢查询诊断变成一套可重复的流程,而不是靠经验猜测。
能力覆盖:
- 解读
EXPLAIN ANALYZE与EXPLAIN FORMAT=JSON的实际执行计划 - 定位顺序扫描、低效 JOIN、排序操作和估算与实际行数的巨大偏差
- 给出具体的索引策略:复合索引、覆盖索引,以及避免不必要的表回查
- 重写子查询为 JOIN,消除
SELECT *带来的 I/O 浪费 - 识别 ORM 层面的 N+1 模式,并建议改用
select_related、joinedload或include等预加载方式 - 在修改后重新运行计划对比,提供可测量的改进证据
工作流程:
- 收集慢查询来源:从慢查询日志、APM 工具或用户反馈中提取问题查询,记录当前执行时间、涉及表规模和调用频率,优先处理高频慢查询。
- 分析执行计划:对 PostgreSQL 运行
EXPLAIN ANALYZE,对 MySQL 运行EXPLAIN FORMAT=JSON,寻找全表扫描、高行数估计的嵌套循环、未索引列排序,以及估算行数与实际行数之间的巨大差距。 - 确定优化方案:基于计划给出可执行的修改——为
WHERE、JOIN、ORDER BY涉及的列创建索引,把子查询改写成 JOIN,用具体列替换SELECT *,添加LIMIT,利用覆盖索引避免回表,清理冗余条件。 - 逐一应用并测量:每次只改一处,分别创建索引、重写查询或调整 ORM 用法,这样可以独立量化每个改动带来的收益。
- 验证结果:重新运行
EXPLAIN ANALYZE,对比执行时间、扫描行数和计划结构,确认查询返回结果不变,并检查新索引是否让写入性能下降到不可接受。 - 搭建持续监控:配置
log_min_duration_statement(如 PostgreSQL 100ms 阈值),集成pg_stat_statements、Datadog 或 Grafana 跟踪查询性能趋势,尽早发现回归。
适用边界与注意点
这套方法依赖数据库自身的执行计划信息,要求数据库账号具备运行 EXPLAIN ANALYZE 和查询系统统计视图的权限。对于已经做过极致优化的系统,索引数量本身可能成为写入负担,因此每次新增索引后都需要在写密集场景下做基准测试。
容易踩的坑:
- 统计信息漂移:大量数据导入后,查询规划器仍使用过期统计,需要手动
ANALYZE或ANALYZE TABLE。 - 索引膨胀:高变更表上频繁 UPDATE/DELETE 会让索引体积膨胀,需定期
REINDEX或OPTIMIZE TABLE。 - 视图里藏着关联子查询:看起来简单的查询可能引用包含逐行执行的视图,分析时务必展开视图查看完整计划。
- 计划缓存与参数嗅探:某个参数值的缓存计划对另一个参数值可能很差,PostgreSQL 中可用
PREPARE/EXECUTE或调整plan_cache_mode来缓解。 - ORM 生成多余 JOIN:有些 ORM 会把 INNER JOIN 生成为 LEFT JOIN,或添加不必要的子查询,需要用
QuerySet.query或.toSQL()检查实际 SQL 并在必要时改用原生查询。
最终,这个技能给出的不是万能调优配方,而是一套以执行计划为依据、以前后对比为验证手段的工程化诊断流程。它适合那些已经出现明确性能瓶颈、愿意用数据而不是直觉来驱动优化决策的团队。
使用场景
- 后端拿到 PostgreSQL 报表查询耗时 4 秒的反馈,需要按 `EXPLAIN ANALYZE` 定位顺序扫描并补复合索引。
- MySQL 慢查询日志里出现高频订单筛选,需要用 `EXPLAIN FORMAT=JSON` 判断缺失索引并改写查询。
- Django 列表页一次渲染发出 201 条 SQL,需要识别 N+1 模式并改成 `select_related` / `prefetch_related`。
- 优化 JOIN 查询后,需要重新跑 `EXPLAIN ANALYZE` 对比扫描行数与执行时间,确认结果不变且写入未明显变慢。
适合人员
- 负责 PostgreSQL / MySQL 生产库的后端工程师,需要按执行计划修复报表、订单筛选等高频慢查询。
- 维护 Django / SQLAlchemy 项目的开发者,正在排查列表页、详情页里由懒加载引发的 N+1 查询。
- 使用 Prisma / Sequelize / TypeORM 的全栈开发者,需要识别 ORM 生成的多余 JOIN 并改写为更高效的原生查询。
- 负责 APM 与数据库监控的工程师,希望配置慢查询阈值并用 pganalyze、Datadog 或 Grafana 跟踪回归。