SQL优化实战:慢查询分析与执行计划调优方案

SQL 查询优化是数据库运维里投入产出比最高的一类工作。一条慢 SQL 可能拖垮整个业务库,而一条索引就能让查询从秒级降到毫秒级。本文从慢查询定位开始,到 EXPLAIN 执行计划解读,再到索引设计和 SQL 改写,给出一套完整的 SQL 查询优化流程。

SQL优化第一步:定位慢查询日志

MySQL 开启慢查询日志,把执行时间超过阈值的 SQL 记录下来,用 pt-query-digest 汇总,找出真正高频高耗的 TOP SQL,而不是凭感觉优化。

-- 开启慢查询日志(持久化到 my.cnf)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;

# 分析慢查询日志 TOP 10
pt-query-digest /var/lib/mysql/slow.log | head -50

EXPLAIN 执行计划解读:type 与 key 是关键

拿到慢 SQL 后,用 EXPLAIN 查看执行计划。重点关注 type 列(访问类型)和 key 列(是否用到索引)。type 从好到差依次是 system > const > eq_ref > ref > range > index > ALL,出现 ALL 说明全表扫描,是优化重点。

EXPLAIN SELECT * FROM orders
WHERE user_id = 1024 AND status = 1
ORDER BY created_at DESC LIMIT 20;
-- type: ref, key: idx_user_id  可用但排序仍需 filesort

示例里 user_id 走了索引,但 ORDER BY created_at 仍可能触发 filesort。优化方式是建联合索引 (user_id, status, created_at),让索引同时覆盖过滤与排序,filesort 消失。

索引设计:覆盖索引与最左前缀

联合索引遵循最左前缀原则,设计时把等值条件列放前,排序列放后;查询列表要尽量被索引覆盖,这样查询完全从索引返回,免回表。

-- 覆盖索引:避免回表
ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, created_at);

-- 反例:下面的 SQL 用不到 idx_user_status_time(跳过 user_id)
-- WHERE status = 1

索引不是越多越好,每个索引都会拖慢写入。生产原则:单表索引数控制在 5 个以内,用慢查询数据驱动,而不是拍脑袋加。

常见慢 SQL 模式与改写

几类高频慢 SQL 可以按固定套路处理。%LIKE% 前缀通配符导致索引失效,改写为范围查询或全文索引;查询字段上套函数导致索引失效,改写为对列的范围判断;select * 改为只取需要的列;深分页 LIMIT 1000000,20 改成基于上次位置定位的滚动分页。

-- 反例:函数套在索引列上,索引失效
WHERE DATE(created_at) = '2026-09-15'
-- 改写:列上不加函数,走索引范围
WHERE created_at >= '2026-09-15 00:00:00'
  AND created_at < '2026-09-16 00:00:00'

优化后务必在真实流量下验证执行计划确实变化,避免”改了索引没生效”的情况。SQL 优化是个持续流程:慢查询监控、分析、优化、验证、回归监控,形成闭环后同类问题才不会再反复出现。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/sql-you-hua-shi-zhan-man-cha-xun-fen-xi-yu-zhi-xing-ji-hua/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐