前言系统突然变慢老板在身后盯着用户疯狂投诉——别慌90% 的性能问题都源于那几条“罪魁祸首”SQL。今天这份指南从定位、分析、优化到预防手把手教你根治慢 SQL。一、什么是慢 SQL为什么要关注它慢 SQL 指执行时间超过阈值的 SQL 语句通常设置 long_query_time 1 秒。为什么必须优化慢 SQL 占用数据库连接资源拖垮整体性能导致接口响应超时、系统雪崩掩盖更深层的架构问题索引缺失、数据倾斜黄金法则一个系统 80% 的慢查询来自 20% 的糟糕 SQL。二、第一步定位——怎么抓出慢 SQL2.1 开启慢查询日志sql– 查看当前配置SHOW VARIABLES LIKE ‘slow_query_log%’;SHOW VARIABLES LIKE ‘long_query_time’;– 开启慢查询日志MySQL 8.0SET GLOBAL slow_query_log ON;SET GLOBAL long_query_time 1; – 阈值 1 秒SET GLOBAL log_queries_not_using_indexes ON; – 记录未用索引的查询– 慢查询日志位置SHOW VARIABLES LIKE ‘slow_query_log_file’;生产建议阈值不要设太低0.5-1 秒合适避免日志过多配合 pt-query-digest 或 mysqldumpslow 分析日志2.2 实时抓取慢 SQLsql– 查看当前正在执行的线程SHOW FULL PROCESSLIST;– 找出执行时间长的线程SELECT * FROM information_schema.PROCESSLISTWHERE COMMAND ! ‘Sleep’ AND TIME 5ORDER BY TIME DESC;2.3 性能监控表sql– 查看最近慢 SQL 统计SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10;三、第二步分析——用 EXPLAIN 看执行计划抓出慢 SQL 后用 EXPLAIN 分析它是怎么执行的。3.1 EXPLAIN 基本用法sqlEXPLAIN SELECT * FROM user WHERE name ‘张三’\G3.2 重点关注字段字段 含义 危险信号type 访问类型 ALL全表扫描⚠️key 实际使用的索引 NULL没走索引⚠️rows 预估扫描行数 越大越慢Extra 额外信息 Using filesort / Using temporary ⚠️type 性能排序好→坏const eq_ref ref range index ALL3.3 危险 Extra 详解Using filesort文件排序无法利用索引排序需优化 ORDER BYUsing temporary使用临时表GROUP BY 或 DISTINCT 需优化Using where用 WHERE 过滤正常Using index覆盖索引好四、第三步优化——对症下药4.1 索引优化解决 80% 的问题① 没走索引 → 检查索引失效场景sql– 索引失效常见原因WHERE name LIKE ‘%张’ – 模糊查询 % 开头WHERE YEAR(create_time)2026 – 对索引列用函数WHERE phone 13800138000 – 隐式转换phone 是 varcharWHERE a 1 AND b 2 – 联合索引 (a,b)范围查询右边列失效② 索引选择性差 → 重建索引或调整字段顺序sql– 查看索引选择性SELECT COUNT(DISTINCT name)/COUNT(*) FROM user; – 越接近 1 越好③ 联合索引顺序错误 → 遵循最左前缀原则sql– 联合索引 (a,b,c)WHERE a1 AND b2 AND c3 – ✅ 全匹配WHERE a1 AND b2 – ✅ 部分匹配WHERE a1 AND c3 – ⚠️ a 用索引c 失效WHERE b2 AND c3 – ❌ 索引失效4.2 SQL 重写优化**① 避免 SELECT ***sql– 坏可能回表 传输大量数据SELECT * FROM user WHERE name ‘张三’;– 好覆盖索引减少回表SELECT id, name FROM user WHERE name ‘张三’;② 优化 OR 条件sql– 坏OR 两边不是都有索引SELECT * FROM user WHERE name‘张三’ OR status1;– 好改 UNIONSELECT * FROM user WHERE name‘张三’UNIONSELECT * FROM user WHERE status1;③ 优化大分页sql– 坏LIMIT 1000000,10 扫描 100 万行后丢弃SELECT * FROM user ORDER BY id LIMIT 1000000, 10;– 好基于 ID 的延迟关联SELECT * FROM userWHERE id (SELECT id FROM user ORDER BY id LIMIT 1000000, 1)LIMIT 10;– 或记录上次最大 IDSELECT * FROM user WHERE id 1000000 ORDER BY id LIMIT 10;④ 优化 COUNT 查询sql– 坏COUNT() 扫描全表SELECT COUNT() FROM user;– 好用近似值或缓存SHOW TABLE STATUS LIKE ‘user’; – 估算行数– 或维护计数器表4.3 表结构优化① 分表单表数据超千万考虑水平拆分② 合理数据类型能用 INT 不用 BIGINT能用 DATETIME 不用 VARCHAR③ 冗余字段适当反范式减少 JOIN五、第四步预防——建立优化机制5.1 慢 SQL 监控告警接入 Prometheus Grafana 监控慢查询数量设置阈值告警如 1 分钟内慢 SQL 10 条5.2 自动化巡检sql– 定期扫描慢查询日志分析 TOP Npt-query-digest /var/log/mysql/slow.log report.txt5.3 SQL 审核流程上线前用 EXPLAIN 审核禁止 SELECT *、禁止大事务控制 JOIN 表数量不超过 3 张六、实战案例从 5 秒到 0.01 秒6.1 原始 SQLsqlSELECT * FROM ordersWHERE customer_name LIKE ‘%张%’AND create_time BETWEEN ‘2026-01-01’ AND ‘2026-03-01’ORDER BY amount DESCLIMIT 1000, 20;执行时间5.2 秒6.2 EXPLAIN 分析type: ALL全表扫描Extra: Using where; Using filesortrows: 500 万6.3 优化过程第一步解决索引失效sql– 原LIKE ‘%张%’ 导致索引失效– 改如果能确定前缀用 ‘张%’或用全文索引ALTER TABLE orders ADD FULLTEXT INDEX idx_name(customer_name);SELECT * FROM ordersWHERE MATCH(customer_name) AGAINST(‘张’) – 全文索引AND create_time BETWEEN ‘2026-01-01’ AND ‘2026-03-01’;第二步建立联合索引sql– 创建联合索引 (create_time, amount)覆盖查询和排序ALTER TABLE orders ADD INDEX idx_time_amount(create_time, amount);第三步优化分页sql– 记录上一页最大 amount 值SELECT * FROM ordersWHERE create_time BETWEEN ‘2026-01-01’ AND ‘2026-03-01’AND amount 上一页最大金额ORDER BY amount DESCLIMIT 20;6.4 最终效果执行时间0.03 秒提升 170 倍。总结慢 SQL 优化六步法步骤 动作 工具/方法1 定位问题SQL 慢查询日志、SHOW PROCESSLIST2 分析执行计划 EXPLAIN3 检查索引 索引是否存在、是否失效4 优化SQL 重写、改分页、避免函数5 优化表结构 分表、数据类型、冗余字段6 建立预防机制 监控、审核、巡检最后一句真理慢 SQL 优化不是“救火”而是“防火”。建立完善的监控和审核机制让慢 SQL 无处遁形。觉得有用点个「收藏」下次系统卡顿翻出这篇照着做你就是团队救星你在工作中遇到过哪些“奇葩”慢 SQL评论区分享一起避坑
1. 项目概述:当AR眼镜遇见你的双手 几年前,当我第一次戴上Project North Star原型机,看到虚拟的立方体悬浮在真实桌面上时,那种震撼感至今难忘。但更让我着迷的,是当我伸出手,无需任何控制器,仅…
PLIP完全指南:蛋白质-配体相互作用分析的7个实战技巧 【免费下载链接】plip Protein-Ligand Interaction Profiler - Analyze and visualize non-covalent protein-ligand interactions in PDB files according to 📝 Schake, Bolz, et al. (2025), http…