【Java架构师体系课 | MySQL篇】④ 索引失效问题总结

简介: 本文详解MySQL索引使用规范,涵盖全值匹配、最左前缀法则、避免索引列操作、覆盖索引、不等条件与通配符对索引的影响等十二大要点,结合EXPLAIN分析SQL执行计划,提升查询性能。
示例表:
CREATE TABLE `employees` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
  `position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
  `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
  PRIMARY KEY (`id`),
  KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='员工记录表';

INSERT INTO employees(name,age,position,hire_time) VALUES('LiLei',22,'manager',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('HanMeimei', 23,'dev',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());


 一、全值匹配


EXPLAIN SELECT * FROM employees WHERE name= 'LiLei';

image.gif


image.gif

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22;


image.gif

image.gif

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';


image.gif

image.gif



二、最左前缀法则

如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。

EXPLAIN SELECT * FROM employees WHERE name = 'Bill' and age = 31;
EXPLAIN SELECT * FROM employees WHERE age = 30 AND position = 'dev';
EXPLAIN SELECT * FROM employees WHERE position = 'manager';

image.gif



三、不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描

EXPLAIN SELECT * FROM employees WHERE name = 'LiLei';
EXPLAIN SELECT * FROM employees WHERE left(name,3) = 'LiLei';

image.gif



 给hire_time增加一个普通索引:

ALTER TABLE `employees` ADD INDEX `idx_hire_time` (`hire_time`) USING BTREE ;

image.gif

EXPLAIN  select * from employees where date(hire_time) ='2018-09-30';

image.gif

image.gif


转化为日期范围查询,有可能会走索引:

EXPLAIN  select * from employees where hire_time >='2018-09-30 00:00:00'  and  hire_time <='2018-09-30 23:59:59';

image.gif

image.gif


还原最初索引状态:

ALTER TABLE `employees` DROP INDEX `idx_hire_time`;

image.gif


四、存储引擎不能使用索引中范围条件右边的列

也就是说,如果你在复合索引里使用了一个“范围条件”(>、<、BETWEEN、LIKE 'xx%' 以外的 LIKE),那么它右边的列(后面的列)就不能再用于索引查找。

EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age > 22 AND position ='manager';

image.gif



五、尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少 select * 语句

EXPLAIN SELECT name,age FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager';

image.gif


EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager';

image.gif



六、mysql在使用不等于(!=或者<>),not in ,not exists 的时候无法使用索引会导致全表扫描

< 小于、 > 大于、 = 这些,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引

EXPLAIN SELECT * FROM employees WHERE name != 'LiLei';

image.gif



七、is null、is not null 一般情况下也无法使用索引

EXPLAIN SELECT * FROM employees WHERE name is null

image.gif



八、like以通配符开头('$abc...')mysql索引失效会变成全表扫描操作

EXPLAIN SELECT * FROM employees WHERE name like '%Lei'

image.gif


EXPLAIN SELECT * FROM employees WHERE name like 'Lei%'

image.gif



问题:解决like'%字符串%'索引不被使用的方法?

a)使用覆盖索引,查询字段必须是建立覆盖索引字段

EXPLAIN SELECT name,age,position FROM employees WHERE name like '%Lei%';

image.gif


b)如果不能使用覆盖索引则可能需要借助搜索引擎



九、字符串不加单引号索引失效

EXPLAIN SELECT * FROM employees WHERE name = '1000';
EXPLAIN SELECT * FROM employees WHERE name = 1000;

image.gif



十、少用or或in,用它查询时,mysql不一定使用索引,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引,详见范围查询优化

EXPLAIN SELECT * FROM employees WHERE name = 'LiLei' or name = 'HanMeimei';

image.gif



十一、范围查询优化

给年龄添加单值索引。

ALTER TABLE `employees` ADD INDEX `idx_age` (`age`) USING BTREE ;
explain select * from employees where age >=1 and age <=2000;

image.gif


没走索引原因:mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引。比如这个例子,可能是由于单次数据量查询过大导致优化器最终选择不走索引

优化方法:可以将大的范围拆分成多个小范围

explain select * from employees where age >=1 and age <=1000;
explain select * from employees where age >=1001 and age <=2000;

image.gif


还原最初索引状态:

ALTER TABLE `employees` DROP INDEX `idx_age`;


十二、索引使用总结

image.gif

目录
相关文章
|
21天前
|
架构师 关系型数据库 MySQL
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
Explain用于分析SQL执行计划,通过模拟优化器行为揭示查询性能瓶颈。它展示索引使用、扫描行数等信息,帮助优化查询语句,提升数据库效率。
140 6
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
|
21天前
|
存储 关系型数据库 MySQL
Mysql如何往表中插入10万条测试数据
创建存储过程批量插入10万条测试数据。示例中先建员工表,再通过循环调用存储过程高效生成大量记录,适用于性能测试或数据初始化场景。
102 3
|
7天前
|
存储 SQL 运维
数据湖 vs 数据仓库 vs 数据湖仓一体:何时选哪种架构?——写给正在做数据平台的你
数据湖 vs 数据仓库 vs 数据湖仓一体:何时选哪种架构?——写给正在做数据平台的你
87 12
|
18天前
|
机器学习/深度学习 SQL 关系型数据库
TRUNCATE、DELETE、DROP 的区别?
MySQL中DELETE、TRUNCATE和DROP均用于删除数据,但作用不同:DELETE删除行记录,支持WHERE条件和事务回滚,速度慢;TRUNCATE快速清空表并重置自增ID,不可回滚;DROP则彻底删除表结构与数据,操作不可逆。三者在日志记录、速度及功能上有显著差异。
213 0
|
9天前
|
人工智能 Java API
Java 正式进入 Agentic AI 时代:Spring AI Alibaba 1.1 发布背后的技术演进
Spring AI Alibaba 1.1 正式发布,提供极简方式构建企业级AI智能体。基于ReactAgent核心,支持多智能体协作、上下文工程与生产级管控,助力开发者快速打造可靠、可扩展的智能应用。
835 24
|
8天前
|
弹性计算 应用服务中间件
租用阿里云服务器一个月多少钱?看完吓一跳,这么便宜了吗?
阿里云服务器月租低至3元!轻量应用服务器2核2G,200M带宽,仅需38元/年,新用户专享;ECS经济型实例99元/年,2核2G,3M带宽,新老同享。时长越长折扣越大,最高可享3.4折。详情见官方活动页。
186 15
|
10天前
|
自然语言处理 JavaScript 前端开发
全面解析 i18n:从概念到实践,再到底层原理
本文系统讲解国际化(i18n)的核心概念与实现原理,涵盖多语言文本、日期、数字、复数等处理方式,结合 i18next 与 Vue I18n 实战案例,深入剖析资源分离、环境识别与动态替换三大机制,并分享插值、格式化、CI/CD 集成等最佳实践,助力构建可扩展的全球化应用。
196 14
|
6天前
|
Python Windows
Miniconda 安装与环境配置全流程图解(2025 最新版)
Miniconda 可以看作是 Anaconda 的“轻装版”,只自带 conda 包管理器与基础的 Python 运行时。它体积小、部署速度快,特别适合按需创建与管理虚拟环境的用户。与 Anaconda 相比,Miniconda 不会预先安装一大堆科学计算库,你可以根据项目需求再单独选择、安装需要的包,因此整体更轻巧、更灵活。 本文将手把手演示在 Windows 下安装 Miniconda 的全过程:从下载安装器、完成向导配置、设置环境变量,到最后的基础验证与简单示例,帮助你迅速把 Miniconda 用起来。
|
10天前
|
人工智能 前端开发 安全
AI 最先替代的开发工作:从重复劳动到人机协同的新范式
AI正加速替代基础开发工作:CRUD页面、样板代码、简单Bug修复、文档生成与基础测试等重复性任务已可通过低代码平台与AI工具高效完成,显著提升生产力。据Gartner报告,70%企业内部系统已采用AI辅助开发,人力投入减少60%-80%。GitHub Copilot等工具更让开发者节省45%编码时间。然而,产品需求分析、系统架构设计、复杂交互体验及创新研发等需深度判断与创造力的工作,仍依赖人类智慧。未来开发者将转型为“AI指挥官”,聚焦问题定义、提示工程与人机协同,核心竞争力转向系统思维、业务理解与技术创新。
158 15
|
10天前
|
JavaScript 数据可视化 测试技术
Node.js 性能诊断利器 Clinic.js:原理剖析与实战指南
Clinic.js 是由 NearForm 开发的 Node.js 性能诊断工具集,通过可视化、低开销的方式帮助开发者快速定位 CPU 高占用、事件循环延迟、内存泄漏等性能瓶颈。它包含三大核心工具:`doctor` 初筛异常,`flame` 分析 CPU 热点,`bubbleprof` 追踪异步 I/O 延迟。基于 `perf_hooks`、`async_hooks` 等技术,实现多维度数据关联与智能建议,适用于预发环境压测与性能优化,显著提升调试效率。
116 14