MySQL 索引优化全景手册

️ MySQL 索引优化全景手册


一、核心思想与创建原则 (1-5)

1. 理解索引的本质

索引是数据的 有序副本(B+Tree 为主)。

-- 查看表索引情况
SHOW INDEX FROM users;

2. 为搜索、排序、分组而建

只为出目前 WHERE、ORDER BY、GROUP BY 的列建索引。

CREATE INDEX idx_user_email ON users(email);

3. 最左前缀原则

复合索引 (A, B, C) 相当于 (A)、(A,B)、(A,B,C)。

CREATE INDEX idx_abc ON orders(user_id, status, create_time);
-- 可用:WHERE user_id=1 AND status=1
-- 不可用:WHERE status=1 AND create_time>'2023-01-01'

4. 选择高选择性列

高选择性列优先建索引。

-- 好:几乎唯一
CREATE INDEX idx_phone ON users(phone);

-- 坏:只有男女两个值
CREATE INDEX idx_gender ON users(gender);

5. 避免过度索引

过多索引拖慢写入。

-- 删除冗余索引
DROP INDEX idx_email_duplicate ON users;

二、索引使用技巧与避坑 (6-15)

6. 避免函数操作

-- ❌ 索引失效
SELECT * FROM orders WHERE YEAR(create_time)=2023;

-- ✅ 改写
SELECT * FROM orders 
WHERE create_time >= '2023-01-01' 
  AND create_time < '2024-01-01';

7. 避免隐式类型转换

-- user_id 是 VARCHAR
-- ❌ 索引失效
SELECT * FROM users WHERE user_id = 10086;

-- ✅ 正确
SELECT * FROM users WHERE user_id = '10086';

8. 避免 <> 和 NOT IN

-- ❌ 索引利用差
SELECT * FROM orders WHERE status <> 1;

-- ✅ 改写
SELECT * FROM orders WHERE status IN (0,2,3);

9. LIKE 模糊查询

-- ✅ 走索引
SELECT * FROM products WHERE name LIKE 'abc%';

-- ❌ 不走索引
SELECT * FROM products WHERE name LIKE '%abc%';

10. IN / OR 使用

-- 一般可以用索引
SELECT * FROM users WHERE id IN (1,2,3);

-- 但如果 IN 集合很大,可能全表扫描

11. 覆盖索引

-- 有索引 (a,b)
CREATE INDEX idx_a_b ON t(a,b);

-- ✅ 覆盖索引查询(无需回表)
SELECT a,b FROM t WHERE a=1;

12. 利用索引排序

-- 有索引 (a,b)
-- ✅ ORDER BY a, b 可直接用索引
SELECT * FROM t WHERE a=1 ORDER BY b;

-- ❌ ORDER BY b 无法利用索引

13. IS NULL / IS NOT NULL

CREATE INDEX idx_email ON users(email);

-- ✅ 可用索引
SELECT * FROM users WHERE email IS NULL;

14. 短索引(前缀索引)

-- 只索引前 20 个字符
CREATE INDEX idx_title ON articles(title(20));

15. 慢查询分析

SET GLOBAL slow_query_log = ON;
EXPLAIN SELECT * FROM orders WHERE user_id=100;

三、高级与维护技巧 (16-20)

16. 减少索引碎片化

OPTIMIZE TABLE orders;

17. 复合索引 vs 单列索引

-- ✅ 更优
CREATE INDEX idx_user_status ON orders(user_id, status);

-- ❌ 冗余
CREATE INDEX idx_user ON orders(user_id);
CREATE INDEX idx_status ON orders(status);

18. 索引下推 ICP

-- MySQL 5.6+ 可在存储引擎层过滤
EXPLAIN SELECT * FROM orders WHERE user_id=1 AND status>2;

19. 唯一索引 vs 普通索引

-- 唯一索引(保证唯一性)
CREATE UNIQUE INDEX idx_email ON users(email);

-- 普通索引(允许重复,写入更快)
CREATE INDEX idx_status ON orders(status);

20. FORCE INDEX 谨慎使用

SELECT * FROM orders FORCE INDEX(idx_user_status) 
WHERE user_id=1 AND status=1;

四、进阶与场景优化技巧 (21-30)

21. 选择性 vs 条件顺序

-- 如果 status 选择性更高,应调整索引列顺序
CREATE INDEX idx_status_user ON orders(status, user_id);

22. 分页优化

-- ❌ 大偏移分页慢
SELECT * FROM orders WHERE status=1 ORDER BY id LIMIT 10000,20;

-- ✅ 子查询优化
SELECT o.* FROM orders o
JOIN (
    SELECT id FROM orders 
    WHERE status=1 ORDER BY id LIMIT 10000,20
) t ON o.id=t.id;

23. 索引合并

CREATE INDEX idx_a ON t(a);
CREATE INDEX idx_b ON t(b);

-- MySQL 可能使用 Index Merge
SELECT * FROM t WHERE a=1 OR b=2;

24. GROUP BY 隐式排序

-- 索引 (a,b) 可直接加速 GROUP BY
SELECT a,b,COUNT(*) FROM t GROUP BY a,b;

25. 统计信息

ANALYZE TABLE orders;

26. 虚拟列 + 索引

ALTER TABLE orders 
ADD COLUMN year_created INT 
  GENERATED ALWAYS AS (YEAR(create_time)) STORED,
ADD INDEX idx_year(year_created);

SELECT * FROM orders WHERE year_created=2023;

27. 分库分表场景

-- 分库分表路由字段必须建索引
CREATE INDEX idx_user_id ON orders(user_id);

28. JSON 索引 (MySQL 8.0+)

ALTER TABLE orders 
ADD COLUMN order_type VARCHAR(20) 
  GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(extra,'$.type'))) STORED,
ADD INDEX idx_order_type(order_type);

29. 监控索引使用

SELECT object_schema, object_name, index_name, count_star
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL;

30. 索引与锁

-- 如果 status 选择性差,更新可能锁大量行
UPDATE orders SET status=1 WHERE status=0;

-- 优化:增加高选择性条件
UPDATE orders SET status=1 WHERE status=0 AND user_id=123;

五、总结 & 优化闭环

索引优化四大维度

  1. 创建原则 → 最左前缀、高选择性、复合优于单列
  2. SQL 使用 → 避免函数/转换、LIKE 前模糊、少用 <>
  3. 性能提升 → 覆盖索引、索引排序、ICP、虚拟列
  4. 维护管理 → 碎片整理、冗余索引清理、慢查询分析

优化闭环

慢 SQL → EXPLAIN → 调整索引/SQL → 验证 → 持续监控


至此,一份带有 完整 SQL 示例MySQL 索引优化全景手册(30 条) 就整理完成了,能直接落地使用。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容