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,可能让执行计划从毫秒变秒级。
