MySQL WHERE条件未走索引会导致全表扫描,性能骤降;原因包括对索引列使用函数、联合索引未从最左列开始匹配、范围查询后列失效,以及优化器基于成本估算放弃索引。

WHERE 条件没走索引,MySQL 就只能全表扫描 —— 这是性能骤降最直接的原因。B+ 树索引能把查找从 O(N) 降到 O(log N),但一旦失效,优化器就放弃索引,老老实实一行行读数据页,I/O 次数暴增,CPU 也得反复比对。
WHERE 中对索引列用了函数或表达式
比如 create_time 有索引,但写成 WHERE DATE(create_time) = '2023-10-01',MySQL 必须对每一行计算 DATE() 才能判断,索引的有序性完全作废。
- 实际表现:执行计划中
type变成ALL,rows显示扫描全部记录 - 正确写法是把函数挪到右边:
WHERE create_time >= '2023-10-01' AND create_time - MySQL 8.0+ 可建函数索引:
CREATE INDEX idx_order_date ON orders ((DATE(order_time))),但要注意它只对显式匹配生效
LIKE 查询以 % 开头
name LIKE '%手机' 或 name LIKE '%手机%' 都无法利用 B+ 树前缀结构 —— 索引是按字典序排的,开头不确定,就无法定位起始位置。
- 右模糊
name LIKE '手机%'是有效的,能快速跳到“手机”开头的索引块 - 真要支持左模糊,别硬扛:
FULLTEXT索引 +MATCH ... AGAINST更靠谱 - 用
EXPLAIN看key字段是否为空,就能确认是否命中索引
隐式类型转换让索引“看不见”
字段是 VARCHAR,查询却传整数:WHERE user_id = 12345,MySQL 会把每行 user_id 转成数字再比 —— 相当于在索引列上做了隐式函数调用。
- 典型错误:ORM 自动生成参数时未指定类型,或前端传参没加引号
- 查
EXPLAIN FORMAT=JSON,看attached_condition里是不是出现类型转换表达式 - 修复很简单:统一为字符串,
WHERE user_id = '12345'
联合索引没按最左前缀用
有 INDEX idx_status_created (status, created_at),但只查 WHERE created_at > '2023-01-01',左边的 status 没出现,整个索引就废了。
- 不是“部分生效”,而是“完全不走”——B+ 树必须从最左列开始构建搜索路径
- 如果经常单独查
created_at,就得另建单列索引,或者调整联合索引顺序 - 注意:范围查询(如
>)后面的列,即使出现在索引定义里,也无法用于索引查找(只能用于过滤)
EXPLAIN 里没出现 key,那它就是没用。



















