要避免mysql索引失效,需遵循七项关键原则:1. 索引列避免使用函数或表达式,如用范围查询替代YEAR()函数;2. 联合索引遵守最左前缀原则,条件需从左连续使用;3. 避免在索引列使用!=、<>、NOT IN等否定操作,改用正向条件;4. LIKE查询禁用前导通配符%,优先使用前缀匹配或全文索引;5. 防止隐式类型转换,字符串字段查询时加引号;6. ORDER BY和GROUP BY字段应建索引并保持顺序一致;7. 少用OR,建议拆分为union或UNION ALL。始终结合EXPLaiN分析执行计划,确保索引有效利用。

在mysql中,索引是提升查询性能的关键手段,但不合理的SQL写法或表结构设计会导致索引无法被使用,从而大幅降低查询效率。要避免索引失效,核心在于理解索引的使用规则,并遵循最佳实践。
1. 避免在索引列上使用函数或表达式
如果对索引列进行计算、函数处理或类型转换,MySQL将无法直接使用索引。
错误示例:
select * FROM users WHERE YEAR(create_time) = 2023;
即使 create_time 上有索引,YEAR() 函数会让索引失效。
正确做法:
SELECT * FROM users WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01';
这样可以利用 create_time 的范围扫描,走索引。
2. 遵循最左前缀原则(针对联合索引)
联合索引 (a, b, c) 要求查询条件从最左边开始连续使用,否则可能无法命中索引。
能用索引的情况:
- WHERE a = 1
- WHERE a = 1 AND b = 2
- WHERE a = 1 AND b = 2 AND c = 3
可能失效的情况:
- WHERE b = 2(跳过 a)
- WHERE c = 3(只用 c)
- WHERE a = 1 AND c = 3(缺少 b,c 无法生效)
注意:如果查询只选择索引中的字段,即使顺序不全,也可能走覆盖索引。
3. 避免在 WHERE 条件中对索引列使用 !=、<>、NOT IN、NOT EXISTS
这些否定操作通常会导致全表扫描,因为索引更擅长查找“等于”或“范围”值。
建议替代方式:
- 用 IN 替代 NOT IN,配合允许为空的判断
- 拆分查询逻辑,用正向条件代替否定
例如:WHERE status != 1 可能不走索引,可考虑是否能重构为 status IN (2,3) 等明确集合。
4. 尽量避免在索引列上使用 LIKE 以 % 开头
前导通配符会破坏索引的有序性。
索引失效:
WHERE name LIKE '%John%' 或 LIKE '%John'
可走索引:
WHERE name LIKE 'John%'
如果必须支持模糊搜索,可考虑全文索引(FULLTEXT)或引入搜索引擎如 elasticsearch。
5. 注意隐式类型转换导致索引失效
当索引列是字符串类型,而查询时传入数字,MySQL会做隐式转换,导致索引失效。
示例:
SELECT * FROM users WHERE phone = 13812345678;(phone 是 VARCHAR)
应改为:
SELECT * FROM users WHERE phone = '13812345678';
6. 合理使用 ORDER BY 和 GROUP BY
ORDER BY 和 GROUP BY 字段如果没有索引,或顺序与联合索引不一致,可能导致 filesort 或临时表。
建议:
- 为排序和分组字段建立合适索引
- 保持 ORDER BY 字段顺序与联合索引一致
- 避免混合 ASC 和 DESC(某些版本不支持索引优化)
7. 少用 OR 条件,尽量用 UNION
WHERE 中使用 OR 连接非同一索引字段时,可能无法走索引。
替代方案:
将 OR 查询拆分为 UNION ALL(如果无重复数据)或 UNION。
例如:
SELECT * FROM users WHERE a = 1 OR b = 2; → 改为:
SELECT * FROM users WHERE a = 1 UNION SELECT * FROM users WHERE b = 2;
基本上就这些常见场景。关键是在写SQL时时刻想着索引结构,结合 EXPLAIN 分析执行计划,及时发现潜在问题。索引有效与否,往往就在细节之间。


