mysql不总是使用索引,因优化器基于统计信息、数据分布和查询写法动态选择执行计划;常见失效原因包括隐式类型转换、函数包裹索引列及未满足最左前缀原则。

为什么 WHERE 条件用了字段却没走索引
不是加了索引就一定用得上,MySQL 会根据统计信息、数据分布和查询写法动态选择执行计划。最常见的是隐式类型转换或函数包裹导致索引失效。
-
WHERE user_id = '123'(user_id是INT)→ 触发隐式转换,索引可能失效 -
WHERE UPPER(name) = 'JOHN'→ 函数作用于索引列,无法使用name上的普通索引 -
WHERE status IN ('active', 'pending') AND created_at > '2023-01-01'→ 如果复合索引是(created_at, status),而查询条件没覆盖最左前缀,可能只用到部分
CREATE INDEX 时要不要加 UNIQUE
加不加取决于业务语义,不是性能优化手段。唯一索引在插入/更新时多一次重复校验,但能防止脏数据,且对 SELECT ... LIMIT 1 类查询有潜在优化(找到一条就停)。
- 主键和业务唯一约束(如
email、order_no)必须建UNIQUE索引 - 纯查询加速用的辅助索引(如
(user_id, type))一般不用UNIQUE,除非逻辑上天然不重复 - 误加
UNIQUE可能导致应用报错Duplicate entry 'xxx' for key 'xxx',排查时容易忽略索引定义本身
联合索引字段顺序怎么排
顺序决定索引能覆盖哪些查询,核心原则是:**区分度高 + 经常用于等值查询的字段放左边,范围查询(BETWEEN、>、LIKE 'abc%')字段放右边,排序/分组字段尽量靠右但不破坏最左前缀**。
- 查
WHERE category = ? AND price > ? ORDER BY create_time DESC→ 推荐索引:(category, price, create_time) - 如果写成
(create_time, category, price),WHERE中没带create_time,整个索引基本失效 - 区分度低的字段(如
gender只有 'M'/'F')放在左边,会导致索引树大部分分支无效,浪费空间和维护开销
EXPLAIN 看到 type=ALL 就一定没索引吗
不一定。type=ALL 表示全表扫描,但原因可能是:表太小(MySQL 认为扫磁盘比走索引还快)、索引被优化器判定为“不值得用”、或者查询返回大量行(比如 SELECT * 配合无过滤条件)。
- 先看
rows字段:如果只有几十行,type=ALL是正常行为 - 检查
key字段是否为NULL:是才说明真没走索引;非NULL却type=ALL,大概率是走了索引但最终回表成本高,优化器放弃 - 用
FORCE INDEX强制走某索引可验证判断,但别在线上乱试——可能让查询更慢
索引不是越多越好,每多一个索引都会拖慢 INSERT/UPDATE/DELETE,而且 MySQL 不会自动合并多个单列索引去模拟联合索引。真正难的不是建索引,是读懂 EXPLAIN 输出里那几行看似枯燥的字段含义。









