MySQL索引优化是数据库性能调优中最常见也最见效的手段。慢查询日志定位语句、EXPLAIN 分析执行计划、索引设计消除回表,三个环节构成完整的调优流程。本文用真实场景的 SQL 示例,讲解从发现问题到验证效果的完整操作。
慢查询日志如何开启与查看
MySQL 默认不开启慢查询日志。修改参数后重启或动态开启,设置阈值时间,低于阈值即记录。
# 动态开启(无需重启)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
# 查看配置
SHOW VARIABLES LIKE 'slow_query%';
线上建议阈值设为 1 秒,定期分析 slow.log。配合 mysqldumpslow 汇总高频慢语句,优先处理出现频率高的。
EXPLAIN 执行计划怎么看
EXPLAIN 是分析 SQL 执行计划的核心工具。重点关注 type、key、rows 三列:type 从 system 到 ALL 依次变差,ALL 表示全表扫描;key 是否命中索引;rows 是预估扫描行数,数字越大开销越大。
EXPLAIN SELECT id, title, created_at
FROM orders
WHERE user_id = 12345
AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;
type=ref 且 key 命中联合索引,说明索引有效。若看到 type=ALL 且 rows 达百万,基本可以判定这条语句在生产环境会很慢。
联合索引设计与最左前缀
联合索引遵循最左前缀原则:索引顺序 (user_id, status, created_at) 能支持 user_id 开头条件查询。查询条件要尽量让索引覆盖更多列,减少回表。
-- 推荐:联合索引覆盖等值+排序
CREATE INDEX idx_user_status_time ON orders (user_id, status, created_at);
-- 覆盖索引避免回表
CREATE INDEX idx_user_cover ON orders (user_id, status, created_at)
INCLUDE (title, order_no);
等值条件列放前面,范围与排序列放后面。查询包含排序时,让排序列作为联合索引的最后一列,避免 filesort。
常见的索引失效场景
索引并非命中条件就一定生效,以下写法会造成索引失效:
- 对索引列使用函数:WHERE DATE(created_at) = ‘2026-09-01’ 会全表扫描,改成范围条件
- 隐式类型转换:字符串列与数字比较时不加引号
- 前导模糊查询:LIKE ‘%keyword’ 无法使用索引,考虑反向存储或全文索引
- OR 连接不同索引列:需要拆成 UNION ALL 或建联合索引
-- 正确写法:时间范围条件走索引
SELECT * FROM orders
WHERE created_at >= '2026-09-01'
AND created_at < '2026-09-02';
分页查询性能优化
深分页 LIMIT 100000, 20 会扫描大量行,优化用游标法(传入上一页最后一条记录的主键):
-- 游标分页:翻页快
SELECT * FROM orders
WHERE id > 100000
ORDER BY id ASC
LIMIT 20;
业务允许时优先用 id 游标分页代替 offset 分页,数据量大时性能差异非常明显。
调优效果如何验证
每次改完索引跑一次 EXPLAIN 对比 type 与 rows,再用相同数据集压测对比响应时间。监控端到端延迟、慢查询数量与 QPS,观察优化是否真实落地。索引不是越多越好,冗余索引会增加写放大,定期用 pt-duplicate-key-checker 清理重复索引。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql-suo-yin-you-hua-shi-zhan-man-cha-xun-ding-wei-yu-zhi/