源码先锋

源码先锋

MySQL索引失效场景分析与优化

admin 112 61

MySQL索引失效是性能优化的关键问题,以下列举15+个典型场景,结合原理和示例分析,帮你全面避坑:

一、基础失效场景

对索引列进行计算或函数操作

sql

SELECT*FROMusersWHEREYEAR(create_time)=2023;--索引失效

分析:对create_time索引列使用YEAR()函数,需逐行计算后再比较。
优化:改用范围查询:

sql

SELECT*FROMusersWHEREcreate_timeBETWEEN'2023-01-01'AND'2023-12-31';

隐式类型转换

sql

SELECT*FROMusersWHEREphone=;--phone是varchar类型

分析:数字被转为字符串,相当于对索引列做CAST(phoneASsigned)操作。
优化:保持类型一致:

sql

SELECT*FROMusersWHEREphone='';

最左前缀原则缺失
索引:(name,age)

sql

SELECT*FROMusersWHEREage=30;--失效(未用name)SELECT*FROMusersWHEREnameLIKE'A%'ANDage=30;--有效

使用OR连接非索引列

sql

SELECT*FROMusersWHEREid=100ORemail='test@';--若email无索引,全表扫描

优化:拆分查询或用UNION:

sql

SELECT*FROMusersWHEREid=100UNIONSELECT*FROMusersWHEREemail='test@';

二、复杂查询失效场景

范围查询阻断后续索引
索引:(age,salary)

sql

SELECT*FROMusersWHEREage25ANDsalary=8000;--salary无法用索引

原理:age25返回大量无序数据,无法再用索引过滤salary。

!=或操作符

sql

SELECT*FROMusersWHEREstatus!=1;--全表扫描(需排除大部分数据)

例外:覆盖索引可能被使用(只需查索引)。

NOTIN/NOTEXISTS

sql

SELECT*FROMusersWHEREidNOTIN(1,2,3);--通常全表扫描

优化:小数据集用LEFTJOIN过滤:

sql

SELECTu.*FROMusersuLEFTJOIN(SELECT1ASidUNIONSELECT2)=;

LIKE以通配符开头

sql

SELECT*FROMusersWHEREnameLIKE'%abc';--索引失效

优化:

后缀匹配:LIKE'abc%'(有效)

全文索引:MATCH(name)AGAINST('abc')

三、优化器行为导致失效

索引区分度过低
例如ger列(值仅M/F),优化器可能弃用索引。
解决方案:复合索引(如(ger,age))。

表数据量过小
当行数全表扫描成本阈值时(如1000行),优化器直接全表扫描。

统计信息不准确
现象:EXPLAIN显示错误执行计划。
修复:ANALYZETABLEtable_name;更新统计信息。

强制索引合并成本高

sql

SELECT*FROMusersWHEREname='John'ORage=30;--可能全表扫描

优化器逻辑:当OR条件涉及不同索引,合并成本高时弃用索引。

四、隐式陷阱

字符集/排序规则不匹配

sql

SELECT*_col=_col;--隐式转换失效

解决方案:统一字符集或显式转换:

sql

ONCONVERT(_colUSINGlatin1)=_col

JOIN列类型不一致

sql

SELECT*_id=;--若_id为varchar,为int,失效

原理:类型不匹配触发隐式转换。

索引列使用子查询

sql

SELECT*FROMproductsWHEREcategory_idIN(SELECTidFROMcategoriesWHEREname='Electronics');--可能失效

优化:改用JOIN:

sql

SELECTp.*_id=='Electronics';

五、特殊场景

使用ORDERBY非索引列

sql

SELECT*FROMusersORDERBYcreate_timeDESC;--无索引时filesort

优化:为排序字段添加索引。

覆盖索引未命中

sql

SELECT*FROMtableWHEREindexed_col=1;--需回表

对比:若只查索引列则无需回表(Usingindex)。

索引损坏
现象:索引存在但查询极慢。
修复:REPAIRTABLEtable_name;或重建索引。

解决方案总结

场景

优化策略

函数操作

重写查询避免计算

类型不匹配

统一数据类型

最左前缀缺失

调整索引顺序或新增复合索引

OR条件失效

改UNION或确保所有列有索引

LIKE通配符开头

倒排索引/ES分词

优化器选错索引

FORCEINDEX(慎用)

统计信息过期

ANALYZETABLE

通过理解这些场景,结合EXPLAIN分析,能有效规避索引失效问题,提升查询性能!