MySQL中对索引字段使用函数、违反最左前缀原则或发生隐式类型转换均会导致索引失效,应保持索引列裸露、遵循左前缀匹配并确保类型严格一致。

WHERE 条件里对索引字段用函数就失效
MySQL(以及大多数主流数据库)在执行 WHERE 时,如果对索引列施加了函数或表达式运算,优化器通常无法使用该索引——不是“可能不走”,而是基本确定跳过索引,转为全表扫描。
常见错误现象:SELECT * FROM users WHERE YEAR(create_time) = 2023,哪怕 create_time 有 B+ 树索引,这条也大概率走全表;同理 UPPER(name) = 'JOHN'、id + 1 = 100 都会失效。
- 正确做法:把函数移到等号右边,让左边保持裸字段。比如改写为
create_time >= '2023-01-01' AND create_time - 如果必须模糊匹配前缀且字段是字符串,优先用
LIKE 'abc%',别用LEFT(name, 3) = 'abc' - MySQL 8.0+ 支持函数索引,但需显式创建:
CREATE INDEX idx_name_upper ON users ((UPPER(name))),不是默认行为,别指望它自动生效
联合索引的左前缀原则不是“从左开始连续用”,而是“最左列必须出现在查询条件中”
很多人误以为只要用了联合索引的第一列就一定走索引,其实关键在于:**最左列是否以“等于”或“范围”方式参与了过滤**,且不能被跳过。
假设索引是 INDEX idx_a_b_c (a, b, c):
-
WHERE a = 1 AND b > 10✅ 走索引,用到 a 和 b -
WHERE b = 2 AND c = 3❌ 不走索引(a 没出现),即使 b、c 都有值 -
WHERE a = 1 AND c = 3✅ 走索引,但只用到 a;b 缺失导致 c 无法下推,相当于WHERE a = 1后再内存过滤 c -
WHERE a IN (1,2) AND b = 5✅ 可用,IN 算等值类操作,不影响左前缀连续性
隐式类型转换会让索引彻底失效
当 WHERE 中的字段和值类型不一致,MySQL 会悄悄做类型转换——而一旦转换发生在索引列上,索引就废了。
典型场景:user_id 是 INT 类型,但写成 WHERE user_id = '123'(字符串)。MySQL 实际执行的是 CAST(user_id AS CHAR) = '123',左边字段被函数包裹,索引失效。
- 检查方法:用
EXPLAIN看type是否为ALL或index,再看Extra有没有Using where; Using index—— 如果只有Using where,大概率出问题 - 修复很简单:确保传参类型和字段定义完全一致。ORM 框架里注意
Integer别传成String,SQL 拼接时别漏掉类型转换 - 时间字段也常踩坑:
created_at = '2023-10-01'(没带时分秒)可能触发隐式转换,不如明确写成created_at >= '2023-10-01' AND created_at
ORDER BY 和 GROUP BY 用错字段顺序也会绕过索引
联合索引不仅能加速查找,还能避免排序和临时表。但前提是 ORDER BY 或 GROUP BY 的字段顺序和索引定义严格一致,且没有混用 ASC/DESC(MySQL 8.0 前不支持混合方向)。
还是以 INDEX idx_a_b_c (a, b, c) 为例:
-
ORDER BY a, b✅ 复用索引,无需 filesort -
ORDER BY b, c❌ 不行,缺少 a,无法利用索引有序性 -
ORDER BY a DESC, b ASC❌ MySQL 5.7 默认不支持混合方向;8.0+ 需索引明确定义为(a DESC, b ASC) -
GROUP BY a, b ORDER BY a✅ 可复用;但GROUP BY a, b ORDER BY b❌ 会强制排序
真正容易被忽略的是:即使 WHERE 走了索引,只要 ORDER BY 不匹配,仍可能触发 Using filesort,查 10 万行时延迟直接翻倍。










