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

一、什么是慢查询?

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

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

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

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

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

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

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

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

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

  • 开启慢查询日志

  • 使用 mysqldumpslowpt-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
  • 分表是最后一步

相关推荐
颜酱2 小时前
07 | 把字段与指标同步到 Qdrant(生成阶段)
前端·人工智能·后端
Larcher3 小时前
从“加载模型”界面到端侧推理:拆解一个 React + WebGPU 大模型 Demo
javascript·后端
Larcher3 小时前
从状态快照到惰性初始化:读懂 React useState 的三个关键场景
javascript·人工智能·后端
lazy H3 小时前
Git clone 怎么用?克隆项目及常见问题完整教程
大数据·git·后端·学习·搜索引擎·github
wang09074 小时前
自己动手写一个spring之aop_1
java·后端·spring
神奇小汤圆4 小时前
IDEA 运行报 Command line is too long?别慌,两招搞定(附原理)
后端
SelectDB4 小时前
Apache Doris 4.1 全面增强 Iceberg:支持 UPDATE、MERGE INTO 与 Iceberg V3
后端
Conan在掘金4 小时前
ArkTS 进阶之道(13):ForEach 循环渲染边界——为啥 build 里不能写 for 循环
后端
妙码生花5 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(四十一):增加管理员账号管理接口
后端·go·gin
用户0678260743275 小时前
APP版本管理全链路(后端设计)
后端