MySQL 慢查询优化:从定位到根治的完整思路

一、什么是慢查询?

慢查询通常指执行时间超过预期阈值的 SQL,比如:

  • 单次执行超过 1s
  • 在高并发场景下平均超过 100ms
  • 导致 CPU / IO 飙高、接口超时

在 MySQL 中,可以通过 慢查询日志​ 来捕获这些 SQL。

sql 复制代码
-- 查看是否开启
SHOW VARIABLES LIKE 'slow_query_log';

-- 设置阈值(单位:秒)
SET GLOBAL long_query_time = 1;

二、慢查询优化的标准流程(核心)

先定位 → 再分析 → 后优化 → 最后验证

1️⃣ 开启慢查询日志,找到"真凶"

不要凭感觉优化,要用数据说话:

  • 开启慢查询日志

  • 使用 mysqldumpslow或 pt-query-digest分析

  • 重点关注:

    • 执行次数多
    • 平均耗时高
    • 扫描行数大

2️⃣ 使用 EXPLAIN 分析执行计划

对可疑 SQL 执行:

ini 复制代码
EXPLAIN SELECT * FROM orders WHERE user_id = 123;

重点关注字段:

字段 关注点
type ALL(全表扫描)是大忌
key 实际使用的索引
rows 扫描行数,越小越好
Extra Using filesort / Using temporary 需警惕

✅ 目标:

  • type 至少达到 range
  • key 不为 NULL
  • 避免 filesort 和临时表

3️⃣ 索引优化(最常见的手段)

✅ 建索引的原则

  • 高区分度字段(user_id、order_no)
  • WHERE / JOIN / ORDER BY 常用字段
  • 联合索引遵循最左前缀
  • 控制索引数量(写多读少表尤其注意)

❌ 常见索引失效写法

  • 对索引字段使用函数:DATE(create_time)
  • 隐式类型转换:phone = 13800000000
  • 左模糊:LIKE '%abc'
  • OR 条件中混合无索引字段
  • 不符合最左前缀

✅ 覆盖索引(进阶)

sql 复制代码
-- 索引 (user_id, status)
SELECT user_id, status FROM orders WHERE user_id = 123;

避免回表,显著提升性能。


4️⃣ SQL 改写优化

  • 避免 SELECT *
  • 大分页优化:
sql 复制代码
-- 避免
SELECT * FROM orders LIMIT 100000, 20;

-- 推荐
SELECT * FROM orders WHERE id > 100000 LIMIT 20;
  • 减少不必要的排序和分组
  • 拆分复杂 JOIN 和子查询

5️⃣ 表结构与业务层优化

  • 冷热数据分离(历史数据归档)
  • 读写分离(主写从读)
  • 适当冗余字段,减少 JOIN
  • 写多读少场景控制索引数量

三、加索引不是银弹(重要认知)

很多初学者容易陷入一个误区:

"查询慢?加索引!"

但现实情况是:

  • 索引会降低 INSERT / UPDATE / DELETE 性能
  • 索引占用磁盘空间
  • 索引过多会增加死锁概率
  • 返回大量数据时,索引效果有限

✅ 正确姿势:

索引解决的是"扫描行数过多"的问题,不是所有慢查询的解药。


四、什么时候考虑分库分表?

当以下情况出现时,索引优化已接近极限:

  • 单表数据量超过千万级
  • 写入成为明显瓶颈
  • 硬件扩容成本过高

此时可以考虑:

  • 分库分表(ShardingSphere / MyCat)
  • 引入 ES / ClickHouse 处理复杂查询

⚠️ 注意:

  • 分库分表会增加系统复杂度
  • 非分片键查询会退化为全表扫描
  • 应作为最后手段,而非首选方案

五、总结

慢查询优化不是一蹴而就的过程,而是一套组合拳:

慢查询日志定位 → EXPLAIN 分析 → 索引 + SQL 优化 → 表结构 / 架构调整

记住一句话:

索引是加速器,不是救命稻草;架构是解决扩展性问题的终极手段。


附:面试速记口诀

  • 慢查先看日志
  • EXPLAIN 看 type / key / rows
  • 索引失效避函数、避左模、避隐转
  • 覆盖索引少回表
  • 分页不用大 offset
  • 分表是最后一步

相关推荐
余槐i20 分钟前
rollbackFor 不设置,Checked 异常不回滚:Spring 默认规则与两行修复的取舍
java·spring boot·后端·spring·事务管理
孙启超22 分钟前
【AI开发之Rust】第 17 课:项目总览与核心架构 —— AI 助手 Rust 核心从 0 到 1
开发语言·后端·rust
EatFan1 小时前
JunoYi 框架实践:Spring Boot 项目为什么拆成 framework、module、server 三层?
java·spring boot·后端·framework·module·模块化·junoyi
汉堡大王95271 小时前
一张图三句需求,我用 Trae Work 做了一块能看日出日落和月相的天文机械表
前端·后端·github
mudtools1 小时前
在.NET现有系统中快速集成飞书任务分配能力
后端·c#·.net
知守观1 小时前
ThreadLocal + 异步线程导致用户数据串号:一次跨请求数据泄漏的完整复盘
后端
前端冒菜师1 小时前
我为什么做了 Iris,又为什么停下了它
后端·ai编程
子一!!1 小时前
集成Spring家族的Spring论坛实战==一阶段
java·后端·spring
Ticnix1 小时前
你的 Agent 聊到第 20 轮就"失忆"?你管理的是历史,高手管理的是上下文
后端·python·agent
不合格的程序员1 小时前
Agent Memory架构设计与实现
后端·ai编程