MySQL 索引优化实战:从 Explain 分析到查询性能翻倍

前言

数据库查询慢是 Web 开发中最常见的性能问题之一。而绝大多数慢查询都可以通过合理使用索引来解决。本文将从 Explain 执行计划入手,带你一步步掌握 MySQL 索引优化的实战技巧。

一、认识 Explain 执行计划

要优化查询,首先得知道 MySQL 是怎么执行你的 SQL 的。EXPLAIN 命令可以展示 MySQL 执行查询的详细步骤:

EXPLAIN SELECT * FROM orders WHERE user_id = 10086 AND status = 'paid';

重点关注以下几个字段:

  • type:访问类型,从好到差依次为 const > eq_ref > ref > range > index > ALL。出现 ALL 就是全表扫描,必须优化。
  • key:实际使用的索引。如果为 NULL,说明没有用到索引。
  • rows:预估需要扫描的行数。这个值越大越慢。
  • Extra:额外信息。Using filesort 和 Using temporary 都是危险信号。

二、最左前缀原则

联合索引 (a, b, c) 的匹配规则:

-- 用到索引 a,b,c
SELECT * FROM t WHERE a = 1 AND b = 2 AND c = 3;

-- 用到索引 a,b
SELECT * FROM t WHERE a = 1 AND b = 2;

-- 只用到索引 a(中间断了)
SELECT * FROM t WHERE a = 1 AND c = 3;

-- 完全用不到索引
SELECT * FROM t WHERE b = 2 AND c = 3;

实战要点:把等值查询的列放在前面,范围查询的列放在后面。

三、常见索引失效场景

1. 对索引列使用函数或运算

-- 失效:对索引列用了函数
SELECT * FROM users WHERE DATE(created_at) = '2026-01-01';

-- 有效:改成范围查询
SELECT * FROM users WHERE created_at >= '2026-01-01' AND created_at < '2026-01-02';

2. 隐式类型转换

-- 失效:phone 是 varchar,用数字查
SELECT * FROM users WHERE phone = 13800138000;

-- 有效:加引号
SELECT * FROM users WHERE phone = '13800138000';

3. LIKE 以通配符开头

-- 失效
SELECT * FROM users WHERE name LIKE '%张%';

-- 有效
SELECT * FROM users WHERE name LIKE '张%';

四、实战优化案例

问题 SQL(扫描 10 万行,耗时 1.2 秒):

SELECT id, title, created_at FROM articles
WHERE category_id = 5 AND status = 'published'
ORDER BY created_at DESC LIMIT 20;

Explain 结果:type=index,rows=120000,Using filesort。

优化方案:创建联合索引

ALTER TABLE articles ADD INDEX idx_cat_status_time (category_id, status, created_at DESC);

优化后:type=ref,rows=20,Extra 无 filesort。查询时间从 1.2 秒降到 0.005 秒。

五、索引不是越多越好

索引虽然能加速查询,但也有代价:

  1. 写入变慢:每次 INSERT/UPDATE 都要维护索引
  2. 占用空间:索引也是要存磁盘的
  3. 优化器选错:索引太多可能让优化器犯迷糊

建议:单表索引数量控制在 5 个以内,避免重复索引和冗余索引。

总结

MySQL 索引优化的核心思路:

  1. 用 EXPLAIN 看执行计划,找到慢的原因
  2. 遵循最左前缀原则设计联合索引
  3. 避免常见的索引失效写法
  4. 定期清理无用索引

掌握这些技巧,你就能解决 80% 以上的慢查询问题。


emer 发布于  2026-10-4 09:52