MySQL索引可能因查询写法、数据分布或索引结构不匹配而不生效;常见原因包括索引列使用函数、隐式类型转换、违反最左前缀原则、LIKE通配符前置、OR条件含非索引列等,需通过EXPLAIN分析执行计划并针对性优化。

MySQL 索引不是建了就一定起作用。优化器是否走索引,取决于查询写法、数据分布和索引结构是否匹配。真正“失效”的本质,是执行计划没选你期望的索引——用 EXPLAIN 查看 key 为 NULL 且 type = ALL,基本就能确认。
索引列上用了函数或表达式
比如对日期字段用 DATE(create_time)、对数字字段做 price * 1.1 > 100,或者写 UPPER(username) = 'TOM'。B+ 树索引存的是原始值,无法直接匹配计算后的结果,只能逐行取值再算,等于放弃索引。
- 把运算移到常量侧:把
YEAR(create_time) = 2023改成create_time >= '2023-01-01' AND create_time < '2024-01-01' - 避免在 WHERE 中对索引列调用函数;如需大小写不敏感查询,可建函数索引(MySQL 8.0+)或统一存储小写
隐式类型转换
字段是 VARCHAR,却传入无引号的数字(WHERE phone = 13800138000);或字段是 INT,却传入带引号的字符串(WHERE id = '123')。MySQL 会悄悄转换字段类型,导致无法使用索引。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 确保查询值类型与字段定义完全一致:字符串加单引号,数字不加引号
- 用
EXPLAIN观察Extra列是否出现Using where; Using index,若只有Using where且type = ALL,大概率是类型不匹配
违反联合索引最左前缀原则
有联合索引 idx_name_age_city(name, age, city),但只查 WHERE age = 25 或 WHERE name = 'Tom' AND city = 'BJ'(跳过 age),都无法完整利用该索引。
- 查询条件必须从索引最左侧连续列开始,中间不能断档
- 高频查询模式变了,就调整索引顺序;比如常按
city和age查,就考虑新建(city, age)索引
LIKE 通配符开头或 OR 条件混用
name LIKE '%张' 或 name LIKE '%张%' 无法利用 B+ 树前缀有序性,必然全表扫描。WHERE a = 1 OR b = 2 中若 b 没索引,整个条件通常不走索引。
- 后缀模糊可用
LIKE '张%',仍能走索引 - 前缀模糊需求强,改用全文索引(
FULLTEXT)或引入 Elasticsearch - OR 涉及非索引列时,拆成
UNION查询,或给缺失列补上索引
其他易忽略的情况
比如 !=、NOT IN、IS NOT NULL 在数据量大或选择率高时,优化器可能主动放弃索引;又比如某字段 95% 值都是 'active',查 status != 'active' 就不如全表扫描快。
- 用
EXPLAIN FORMAT=JSON查看filtered字段,数值越低说明匹配行越少,越可能走索引 - 对高频
IS NULL查询,可显式建单列索引;IS NOT NULL效果有限,优先考虑业务逻辑过滤 - 定期用
ANALYZE TABLE更新统计信息,避免优化器因数据分布误判

















