【MySQL篇|第一篇】索引失效的情况

1. 引言

在 MySQL 中,索引是提升查询性能的关键手段,但索引并非总能生效。很多情况下,即使表上建立了合适的索引,SQL 语句依然会走全表扫描,导致查询变慢。理解索引失效的常见场景,有助于写出更高效的 SQL,也能帮助排查线上慢查询问题。下面是一些常见的索引失效的情况。

2. 索引失效的常见情况

下面列举 MySQL 索引失效的典型场景,并给出对应的示例和规避建议。

2.1 对索引列使用函数或表达式

当查询条件中对索引列使用了函数、运算或类型转换时,MySQL 通常无法使用索引,因为索引中存储的是原始值,而不是函数处理后的结果。

sql 复制代码
-- 失效:对索引列使用函数
SELECT * FROM user WHERE DATE(create_time) = '2024-01-01';

-- 失效:对索引列进行运算
SELECT * FROM user WHERE age + 1 = 30;

-- 建议改写为:
SELECT * FROM user WHERE create_time >= '2024-01-01' AND create_time < '2024-01-02';
SELECT * FROM user WHERE age = 29;

2.2 隐式类型转换

当索引列是字符串类型,而查询条件传入的是数值类型(或反之),MySQL 会进行隐式类型转换,导致索引失效。这是一个很隐蔽的点,在实际的开发中需要格外的注意。

sql 复制代码
-- 假设 phone 字段是 varchar 类型且有索引
-- 失效:传入数值,发生隐式转换
SELECT * FROM user WHERE phone = 13800138000;

-- 建议改写为:
SELECT * FROM user WHERE phone = '13800138000';

2.3 模糊查询以通配符开头

当 LIKE 查询以 % 或 _ 开头时,索引无法用于前缀匹配,只能全表扫描。

sql 复制代码
-- 失效:以通配符开头
SELECT * FROM user WHERE name LIKE '%张';

-- 有效:以固定前缀开头
SELECT * FROM user WHERE name LIKE '张%';

2.4 联合索引未遵循最左前缀原则

联合索引 (a, b, c) 遵循最左前缀原则。如果查询条件没有包含最左列 a,索引通常无法使用。

sql 复制代码
-- 假设联合索引 idx(a, b, c)
-- 失效:未使用最左列 a
SELECT * FROM t WHERE b = 1 AND c = 2;

-- 有效:包含最左列 a
SELECT * FROM t WHERE a = 1 AND b = 1;

2.5 使用 OR 连接非索引列

当 OR 连接的多个条件中,只要有一个列没有索引,整个查询就可能放弃使用索引。

sql 复制代码
-- 假设 name 有索引,age 无索引
-- 失效:age 无索引导致整体无法走索引
SELECT * FROM user WHERE name = '张三' OR age = 30;

-- 建议改写为 UNION 或为 age 也建立索引
SELECT * FROM user WHERE name = '张三'
UNION
SELECT * FROM user WHERE age = 30;

2.6 对索引列进行排序或分组时使用不当

当 ORDER BY 或 GROUP BY 的字段顺序与索引顺序不一致,或排序方向不一致时,索引可能无法用于排序优化。

sql 复制代码
-- 假设联合索引 idx(a, b)
-- 失效:排序顺序与索引不一致
SELECT * FROM t WHERE a = 1 ORDER BY b DESC;

-- 有效:与索引顺序一致
SELECT * FROM t WHERE a = 1 ORDER BY b ASC;

2.7 使用不等于、NOT IN、IS NOT NULL

对于范围查询和否定条件,MySQL 优化器往往认为走索引的代价高于全表扫描,从而放弃索引。

sql 复制代码
-- 失效:不等于条件
SELECT * FROM user WHERE status != 1;

-- 失效:NOT IN
SELECT * FROM user WHERE id NOT IN (1, 2, 3);

-- 失效:IS NOT NULL
SELECT * FROM user WHERE email IS NOT NULL;

2.8 数据量过小或优化器选择全表扫描

当表中数据量很小,或者索引选择性很低(如性别字段只有两个值)时,MySQL 优化器可能认为全表扫描比走索引更快,从而主动放弃索引。

sql 复制代码
-- 即使有索引,优化器也可能选择全表扫描
SELECT * FROM user WHERE gender = '男';

3. 如何确认索引是否生效

使用 EXPLAIN 关键字可以查看 SQL 的执行计划,重点关注 type 和 key 字段。

sql 复制代码
EXPLAIN SELECT * FROM user WHERE name = '张三';
  • type:如果为 ALL,说明走了全表扫描;如果为 ref、range、index 等,说明使用了索引。
  • key:显示实际使用的索引名称;如果为 NULL,说明没有使用索引。

4. 总结

索引失效的原因多种多样,核心在于理解 MySQL 优化器的工作方式以及索引的数据结构。日常开发中,建议遵循以下原则:避免对索引列使用函数和运算、保持字段类型一致、遵循最左前缀原则、谨慎使用 OR 和否定条件,并善用 EXPLAIN 验证执行计划。只有让索引真正生效,才能充分发挥数据库的性能优势。对一些少量数据我们也不要胡用索引,我们要优先选择查询更快的方案。

相关推荐
paopaokaka_luck1 小时前
宠物门店经营管理系统(销售与库存联动、进货自动记账、 退换与退款关联、员工个人业绩、ECharts 经营分析、滞销识别与客户分层、宠物档案年龄计算)
前端·javascript·spring boot·mysql·echarts·mybatis·1024程序员节
北京青蓝智慧马老师1 小时前
比外部黑客更难防的,是那个有权限的自己人(3 个脱敏复盘)
大数据·数据库·人工智能
笃行3502 小时前
拆一台数据集成产品:KFS 的骨架、肌肉和神经
数据库
4SAPI2 小时前
搭建 AI 数据分析工具大模型 API 选型指南
数据库·人工智能·架构·php·1024程序员节
paopaokaka_luck3 小时前
心理咨询管理系统(WebSocket实时沟通、基于用户的协同过滤、 ECharts多维分析、 预约业务流程、预约校验与定时处理)
java·vue.js·spring boot·mysql·spring·echarts·1024程序员节
码士集团小青4 小时前
面霸篇:高频 Java 基础问题(核心卷一)
linux·服务器·数据库·redis·缓存·1024程序员节
2301_32241428044 小时前
springboot农产品交易平台的设计与实现08055-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·spring boot·redis·mysql·tomcat·maven·mybatis
LMT流氓兔5 小时前
第五单元——第十二课:把脚本整理成项目
java·数据库·python·langchain·1024程序员节
cuijiecheng20185 小时前
WeFlow 无法使用怎么办?一次数据库组件到期问题的排查与修复
数据库·oracle