SQL优化系列(二):索引优化原则与失效场景
前言
上一篇文章介绍了如何发现SQL问题以及EXPLAIN命令的使用。本文将深入讲解索引优化的原则以及常见的索引失效场景,帮助大家写出高效的SQL语句。
索引基础回顾
什么是索引
索引是帮助MySQL高效获取数据的数据结构。可以简单理解为”排好序的快速查找数据结构”。
MySQL索引类型
- B+Tree索引: 最常用的索引类型,适用于全键值、键值范围和键前缀查找
- Hash索引: 只支持等值查询,不支持范围查询
- 全文索引: 用于全文搜索
- R-Tree索引: 用于地理空间数据
索引优化原则
1. 最左前缀原则
对于复合索引,MySQL会从最左边的列开始匹配。
1 | -- 假设有复合索引 INDEX idx_abc (a, b, c) |
2. 覆盖索引
如果查询的列都在索引中,MySQL可以直接从索引获取数据,无需回表查询。
1 | -- 假设有索引 INDEX idx_name_age (name, age) |
优化建议: 尽量使用覆盖索引,减少SELECT *的使用。
3. 索引选择性
索引选择性 = 不重复的索引值数量 / 表的总记录数
选择性越高,索引效率越高。例如:
- 主键的选择性为1,是最高的
- 性别字段只有男/女两个值,选择性很低,不适合建索引
4. 前缀索引
对于长字符串,可以只索引前面部分字符,节省索引空间。
1 | -- 对email字段的前10个字符建立索引 |
注意: 前缀索引无法用于ORDER BY和GROUP BY,也无法使用覆盖索引。
索引失效的常见场景
1. 对索引列进行运算或函数操作
1 | -- 索引失效 |
2. 使用不等于(!= 或 <>)
1 | -- 索引可能失效 |
3. IS NULL 和 IS NOT NULL
1 | -- 可能导致索引失效 |
建议: 设计表时尽量避免NULL值,使用默认值代替。
4. LIKE以通配符开头
1 | -- 索引失效 |
5. 字符串不加引号
1 | -- 假设phone字段是VARCHAR类型 |
6. OR条件连接
1 | -- 如果or两边的列不都有索引,则索引失效 |
7. 范围查询后的列无法使用索引
1 | -- 假设有复合索引 INDEX idx_abc (a, b, c) |
索引设计建议
1. 适合建索引的场景
- WHERE子句中经常使用的列
- ORDER BY子句中的列
- GROUP BY子句中的列
- 多表JOIN的关联列
- 选择性高的列
2. 不适合建索引的场景
- 数据量很小的表
- 频繁更新的列
- 选择性很低的列(如性别、状态)
- 很少用于查询的列
3. 复合索引设计原则
- 将选择性高的列放在前面
- 将等值查询的列放在范围查询的列前面
- 考虑覆盖索引,将常用查询列加入索引
实战案例
假设有订单表:
1 | CREATE TABLE orders ( |
常见查询场景:
1 | -- 查询某用户的订单 |
推荐索引设计:
1 | -- 复合索引,满足多种查询场景 |
总结
本文介绍了索引优化的核心原则和常见的索引失效场景:
- 最左前缀原则: 复合索引从左到右匹配
- 覆盖索引: 减少回表查询
- 索引失效场景: 函数操作、隐式转换、LIKE通配符开头等
- 索引设计: 根据查询场景合理设计复合索引
下一篇文章将通过实际案例,演示SQL优化的完整过程,敬请期待。
参考资料
- MySQL官方文档
- 《高性能MySQL》