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

相关推荐
__zRainy__12 小时前
Node系列 · Node基础:net 模块
后端·node.js
Diligently_12 小时前
Anolis 系统更新与密码设置&磁盘扩容
java·后端·spring
kyson_12 小时前
大文件切片上传:从“能传”到“可靠”的 Vue 3 + Java 全栈实现
后端
张龙68712 小时前
uv 全面指南:比 pip 快 100 倍的 Python 包管理器,从安装到团队落地
后端·python
用户409666013175113 小时前
Guava 不止有 Lists 和 Maps:Cache、EventBus、Multimap 实战
java·后端
一只叫煤球的猫14 小时前
从 Java 21 到 Java 25:ThreadLocal 以外的选择—— ScopedValue
java·后端·架构
用户31693538118314 小时前
SpringBoot + Vue 项目生产环境部署完整指南
前端·后端
霸道流氓气质14 小时前
Spring 事务同步机制 —— AfterTransactionActionCollector 的异步解耦原理
java·后端·spring