mysql按索引最左前缀匹配where条件,等值查询从左到右连续使用,范围查询或函数导致后续列失效;多索引时选预估rows最小者,但依赖统计信息准确性。

MySQL 用哪个索引?看 WHERE 条件的最左前缀匹配
MySQL 不会“选最优”,而是按索引定义顺序,从左到右逐列匹配 WHERE 中的等值条件(= 或 IN),一旦遇到范围查询(>、、<code>BETWEEN、LIKE 前缀不固定)或函数/表达式,后续列就失效。比如索引是 (a, b, c):
-
WHERE a = 1 AND b = 2 AND c = 3→ 三列全用上 -
WHERE a = 1 AND b > 2 AND c = 3→ 只用到a和b,c被跳过(b是范围终点) -
WHERE b = 2 AND c = 3→ 索引完全不用(没给a) -
WHERE a = 1 AND c = 3→ 只用a,c无法跳过b
多个索引可选时,MySQL 怎么挑?看 rows 预估和索引区分度
当 WHERE 条件能命中多个索引(比如有 (a)、(a,b)、(a,c)),优化器会估算每个索引扫描的行数(rows 字段,来自 EXPLAIN),选预估成本最低的那个。但这个估算依赖统计信息,可能不准——尤其表数据大、长期未 ANALYZE TABLE 时,容易选错。
- 高区分度列(如
user_id)放索引左边,比低区分度列(如status)更利于剪枝 -
ORDER BY或GROUP BY字段如果能被同一索引覆盖,会优先考虑(避免额外排序) - 主键索引(聚簇索引)在回表代价高时可能被降级,即使它“理论上更优”
OR 条件会让索引失效?不一定,但很脆弱
单个 OR 条件(如 WHERE a = 1 OR b = 2)通常无法走索引,除非两边都独立有索引且满足某些版本限制(MySQL 5.7+ 对部分情况支持索引合并 index_merge)。但要注意:
-
index_merge是备选策略,性能常不如单个复合索引,且EXPLAIN显示为type: index_merge,不是常规ref或range - 写成
WHERE a = 1 UNION ALL SELECT ... WHERE b = 2有时反而更快,尤其当两边结果集小 - 含
NULL判断的OR(如a IS NULL OR a = 1)基本无法优化
哪些“看似合理”的写法会悄悄让索引下线
这些细节在开发中极易忽略,但一上线就拖慢查询:
- 对索引列用函数:
WHERE YEAR(create_time) = 2024→ 改成create_time BETWEEN '2024-01-01' AND '2024-12-31' - 隐式类型转换:
WHERE user_id = '123'(user_id是INT)→ 字符串转数字可能放弃索引,尤其字段有大量值时 -
LIKE开头带通配符:WHERE name LIKE '%abc'→ 全表扫;LIKE 'abc%'才能用索引 - 在索引列上做运算:
WHERE score * 10 > 100→ 改成score > 10
真正难的不是建索引,而是让 SQL 写法始终贴合索引结构——改一行 WHERE,可能让执行计划从毫秒变秒级。










