mysql 索引失效分析

一、索引失效的核心原理

MySQL 索引通常采用 B+ 树结构,其高效查询依赖于有序性索引键的可比较性。当查询条件破坏了这些特性时,数据库无法有效利用索引,只能进行全表扫描。

1. 索引列上使用函数或表达式

对索引列进行函数运算或表达式计算会导致索引失效,因为数据库需要先计算所有行的结果才能比较,无法直接使用索引的有序性。

sql 复制代码
-- 失效:索引列 age 上使用了函数
SELECT * FROM users WHERE YEAR(birthday) = 1990;

-- 优化:改为索引列可直接比较
SELECT * FROM users WHERE birthday >= '1990-01-01' AND birthday < '1991-01-01';
2. 隐式类型转换

当索引列类型与查询条件类型不匹配时,MySQL 会进行隐式转换,相当于在索引列上执行了函数操作。

sql 复制代码
-- 失效:phone 是字符串类型,查询用数字,触发隐式转换
SELECT * FROM users WHERE phone = 13800138000;

-- 优化:类型匹配
SELECT * FROM users WHERE phone = '13800138000';
3. 使用 NOT IN、NOT EXISTS、!=、<> 等操作符

这些操作符可能导致索引失效,因为它们通常需要扫描大部分数据才能确定结果。

sql 复制代码
-- 可能失效
SELECT * FROM users WHERE status != 1;

-- 优化:根据业务场景改用范围查询(如果适用)
SELECT * FROM users WHERE status < 1 OR status > 1;
4. 模糊查询以 % 开头

LIKE '%xxx'LIKE '%xxx%' 会导致索引失效,因为前缀不确定,无法利用索引的有序性定位。

sql 复制代码
-- 失效:% 开头的模糊查询
SELECT * FROM users WHERE name LIKE '%张';

-- 有效:仅后缀模糊,可利用索引
SELECT * FROM users WHERE name LIKE '张%';
5. 联合索引不满足最左前缀原则

联合索引 (a, b, c) 的有效查询条件必须从左到右匹配,跳过左侧列会导致后续索引失效。

sql 复制代码
-- 有效:匹配最左前缀 a
SELECT * FROM users WHERE a = 1;

-- 有效:匹配 a + b
SELECT * FROM users WHERE a = 1 AND b = 2;

-- 失效:跳过 a 直接查询 b
SELECT * FROM users WHERE b = 2;

-- 部分有效:a 有效,c 失效
SELECT * FROM users WHERE a = 1 AND c = 3;
6. OR 连接的条件中有列未建立索引

OR 两边的列如果有一个没有索引,会导致整个查询无法使用索引(因为需要同时扫描索引和全表)。

sql 复制代码
-- 失效:age 有索引但 email 无索引
SELECT * FROM users WHERE age = 30 OR email = 'test@example.com';

-- 优化:给 email 建立索引,或拆分查询
7. 索引列参与计算

与函数操作类似,索引列参与算术运算会导致索引失效。

sql 复制代码
-- 失效:索引列 price 参与计算
SELECT * FROM products WHERE price * 0.8 < 100;

-- 优化:改写为索引列直接比较
SELECT * FROM products WHERE price < 100 / 0.8;
8. MySQL 优化器认为全表扫描更快

当表数据量很小,或查询结果集占表数据比例很大(通常超过 30%)时,优化器可能选择全表扫描,此时索引会被忽略。

9. 使用 IS NOT NULL

IS NOT NULL 可能导致索引失效,因为索引通常不存储 NULL 值的位置信息(聚簇索引除外)。

sql 复制代码
-- 可能失效
SELECT * FROM users WHERE email IS NOT NULL;

二、如何避免索引失效

  1. 避免在索引列上使用函数、表达式或计算
  2. 保证查询条件与索引列类型一致
  3. 遵循联合索引的最左前缀原则
  4. 优化模糊查询,避免以 % 开头
  5. 对 OR 连接的所有列建立索引
  6. 使用 EXPLAIN 分析查询计划,检查 type 列是否为 ALL(全表扫描)

通过理解上述原理和场景,可以有效避免索引失效,提升 MySQL 查询性能。实际开发中,应结合业务场景合理设计索引,并通过执行计划验证索引使用情况。

相关推荐
阿里小阿希20 分钟前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神25 分钟前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员35 分钟前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java44 分钟前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿1 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴1 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存
YOU OU1 小时前
三大范式和E-R图
数据库
MaCa .BaKa1 小时前
47-心里健康咨询平台/心理咨询系统
java·spring boot·mysql·tomcat·maven·intellij-idea·个人开发
一江寒逸1 小时前
零基础从入门到精通MySQL(上篇):筑基篇——吃透核心概念与基础操作,打通SQL入门第一关
数据库·sql·mysql
@土豆1 小时前
Ubuntu 22.04 运行 Filebeat 7.11.2 崩溃问题分析及解决文档
linux·数据库·ubuntu