导读:本期聚焦于花满楼创作的《如何优化 MySQL 慢查询:10 分钟查询时间的系统化调优方法》,敬请观看详情。一条查询跑了 10 分钟还没出结果,问题究竟出在哪里?本文从慢查询日志定位、执行计划分析、索引设计与 SQL 改写四个层面入手,给出一套可落地的 MySQL 性能调优思路。内容涵盖 explain 关键字段的解读方法、联合索引的最左前缀原则、覆盖索引与回表的关系、深分页场景的优化技巧,以及服务器参数与硬件层面的补充手段,帮助你把分钟级的慢查询压缩到秒级甚至毫秒级。

当一个查询需要 10 分钟才能返回结果时,通常意味着它扫描的数据量过大、索引缺失或失效、SQL 写法不合理,也可能是服务器资源配置不当。优化这类查询不能靠猜,需要一套系统化的排查流程:先定位慢查询,再分析执行计划,然后从索引、SQL 写法、库表结构三个层面优化,最后必要时调整服务器参数。本文将按照这个顺序展开,配合具体示例说明每一步该怎么做。

如何优化 MySQL 慢查询:10 分钟查询时间的系统化调优方法

第一步:定位慢查询并打开慢查询日志

优化的起点是找到真正慢的那条 SQL。MySQL 提供了慢查询日志(slow query log),可以记录所有执行时间超过阈值的语句。可以通过下面的方式动态开启:

-- 查看慢查询日志配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 开启慢查询日志(动态方式,重启失效)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;  -- 超过1秒的查询都会被记录
SET GLOBAL log_queries_not_using_indexes = ON;  -- 记录未使用索引的查询

开启后,日志文件中会记录查询耗时、扫描行数、锁等待时间等关键信息。除了原生的慢日志,也可以使用 pt-query-digest 工具对日志做汇总分析,它会按照总耗时排序,快速找出最值得优化的几条 SQL。这一步非常关键:优化对象应该是那些执行频率高且单次耗时长的查询,而不是随便挑一条看起来复杂的语句。

拿到目标 SQL 后,还要确认几个基础事实:表的数据量多大?查询是偶发慢还是持续慢?是全表慢还是某些条件慢?这些信息决定了后续优化的方向。比如一张千万行的表没有走索引,10 分钟的耗时就很正常,补上索引可能立竿见影。

第二步:用 EXPLAIN 分析执行计划

EXPLAIN 是 MySQL 优化中最重要的工具,它在语句前加上 explain 关键字即可查看优化器选择的执行方案。重点看以下几个字段:

  • type:访问类型,从好到差依次是 system > const > eq_ref > ref > range > index > ALL。出现 ALL 表示全表扫描,通常是慢查询的元凶。
  • key:实际使用的索引。如果为 NULL,说明没有索引可用。
  • rows:预估扫描行数。10 分钟的查询往往扫描了几百万甚至上千万行。
  • Extra:附加信息。出现 Using filesort 说明排序没有用到索引,Using temporary 说明用了临时表,Using index 则是理想情况,表示覆盖索引生效。
EXPLAIN SELECT order_no, amount FROM t_order
WHERE user_id = 10086 AND status = 2
ORDER BY create_time DESC
LIMIT 20;

如果执行计划显示 type 为 ALL,rows 为上千万,那么问题就清楚了:过滤条件没有索引支持。如果 type 是 ref 或 range 但依然很慢,就要检查是否发生了大量回表,或者排序、分组操作消耗了过多资源。执行计划是后续所有优化决策的依据,务必先看懂它再动手。

另外注意 explain 结果里的 key_len 字段,它可以判断联合索引实际用了几列。如果建了三列的联合索引但 key_len 只覆盖了第一列,说明索引设计与查询条件不匹配,需要调整索引列的顺序。

第三步:索引优化,最直接有效的手段

大多数慢查询的根本原因是索引缺失或使用不当。设计索引时需要遵循几个核心原则。第一是最左前缀原则:联合索引 (a, b, c) 只对以 a 开头的条件有效,查询条件中只有 b 或 c 时无法使用该索引。第二是区分度原则:选择性高的列(如用户 ID)适合做索引前缀,而性别、状态这类只有几个取值的列单独建索引意义不大。

-- 针对上面的查询建立联合索引,等值列在前,排序列在后
ALTER TABLE t_order ADD INDEX idx_user_status_time (user_id, status, create_time);

这个索引设计包含了三层意图:user_idstatus 作为等值条件放在前面可以精确过滤,create_time 放在最后可以让排序直接利用索引顺序,消除 filesort。建立索引后,原本需要全表扫描加排序的查询会变成一次索引范围定位,性能通常能提升几个数量级。

覆盖索引是另一个重要技巧。如果查询的列全部包含在索引中,MySQL 无需回表读取整行数据,Extra 会显示 Using index。对于高频的列表查询,可以考虑把 select 的字段扩充进索引,用一点写入开销换取查询速度的大幅提升。但要避免无节制地加索引:每个索引都会拖慢写入并占用磁盘空间,一张表保留三到五个高频索引即可。

还要警惕索引失效的常见场景:对索引列使用函数或运算(如 WHERE YEAR(create_time) = 2024)、隐式类型转换(字符串列传了数字)、前导模糊匹配 LIKE '%abc'、以及 OR 连接了无索引的列。这些写法都会让优化器放弃索引,改写 SQL 时要格外注意。

第四步:改写 SQL 与优化深分页

有些慢查询即使加了索引也不够快,问题出在 SQL 写法本身。典型的例子是深分页:LIMIT 1000000, 20 需要扫描并丢弃前一百万行数据,页码越深越慢。常见的优化方案有两种:

-- 方案一:延迟关联,先在索引上定位主键,再回表取数据
SELECT t.order_no, t.amount
FROM t_order t
INNER JOIN (
    SELECT id FROM t_order
    WHERE user_id = 10086
    ORDER BY create_time DESC
    LIMIT 1000000, 20
) tmp ON t.id = tmp.id;

-- 方案二:游标分页,记住上一页最后一条的排序值,避免扫描前页
SELECT order_no, amount FROM t_order
WHERE user_id = 10086 AND create_time < 1690000000
ORDER BY create_time DESC
LIMIT 20;

延迟关联方案利用了覆盖索引,子查询只在索引上完成偏移定位,回表只发生 20 次;游标分页则彻底消除了偏移量,适合下拉加载场景。除此之外,还有一些通用的改写技巧:避免 select 星号只取需要的列、用 union all 代替 or、大事务拆小、join 表的数量控制在三张以内、子查询尽量改写为 join。

对于统计类慢查询,可以考虑把实时聚合改为预聚合:用定时任务把结果写入汇总表,查询时直接读汇总数据,避免每次都扫描明细。这是以空间换时间的经典架构手段,在报表场景中效果显著。

第五步:服务器参数与架构层面的补充优化

SQL 和索引之外,服务器配置也会影响查询速度。重点关注这几个参数:innodb_buffer_pool_size 建议设为物理内存的 50% 到 70%,保证热数据尽量驻留内存;innodb_buffer_pool_instances 在高并发下可设为 4 到 8 以减少锁竞争;sort_buffer_sizejoin_buffer_size 影响排序和连接性能,但不宜设置过大以免内存耗尽。

-- 查看缓冲池命中率,理想值应接近 99%
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';

如果缓冲池命中率偏低,说明大量读请求落到了磁盘,加大缓冲池或升级内存往往能直接缩短查询时间。此外还可以借助 performance_schema 和 sys 库观察锁等待、临时表使用情况,找出被阻塞的会话。

当单表数据量达到数亿级别,单机优化会触及天花板,此时需要架构层面的手段:按照业务维度做垂直拆分、按照时间或用户 ID 做水平分表、引入读写分离把分析类查询分流到从库,或者把复杂的实时统计迁移到 Elasticsearch、ClickHouse 等专用引擎。这些方案改造成本更高,建议在索引和 SQL 优化穷尽之后再考虑。

总结

把 10 分钟的查询优化到秒级,路径通常是:慢日志定位目标,explain 分析瓶颈,索引修复访问路径,SQL 改写消除不合理操作,最后辅以参数调整和架构升级。实践中超过八成的慢查询问题靠正确建索引就能解决,因此优先把前四步做扎实。同时要建立长效机制,持续监控慢查询日志,在数据量增长前预判性能风险,而不是等用户投诉后再补救。

MySQL慢查询优化索引优化SQL执行计划修改时间:2026-09-01 13:56:46

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。