【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

目录
相关文章
|
28天前
|
架构师 关系型数据库 MySQL
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
Explain用于分析SQL执行计划,通过模拟优化器行为揭示查询性能瓶颈。它展示索引使用、扫描行数等信息,帮助优化查询语句,提升数据库效率。
149 6
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
|
27天前
|
SQL 架构师 关系型数据库
【Java架构师体系课 | MySQL篇】⑤ 索引优化实战一
本文深入解析MySQL索引优化原理,涵盖联合索引使用、覆盖索引、索引下推、filesort排序机制及trace工具分析执行计划选择等内容,并结合实际案例提供索引设计原则与SQL优化策略。
104 5
|
26天前
|
SQL 存储 关系型数据库
MySQL中到底什么是覆盖索引、索引下推?
覆盖索引指查询只需通过索引即可获取数据,无需回表,提升查询效率。索引下推则在索引遍历时提前过滤条件,减少回表次数,尤其适用于联合索引中部分字段无法使用的情况,二者均能显著降低I/O开销,提高查询性能。(238字)
179 1
|
24天前
|
消息中间件 存储 负载均衡
【高可用】什么是异地多活、同城容灾?
异地多活与同城容灾均为提升系统高可用的分布式架构。前者实现跨地域数据中心实时同步与故障切换,保障全球服务连续性;后者聚焦同城内快速容灾,通过高速网络实现低延迟、高可靠的数据同步与负载均衡,适用于对延迟敏感的业务场景。
83 11
|
24天前
|
Java Spring
IDEA调出services窗口
本教程分两步指导:首先点击指定选项,然后在Templates中添加Spring Boot并应用,即可调出services窗口,快速完成配置。
84 11
|
24天前
|
存储 领域建模
【DDD】如何理解领域驱动设计?
领域驱动设计(DDD)是一种以业务为核心的软件开发方法,强调通过领域建模、分层架构与团队协作,实现业务与技术的深度融合,提升系统可维护性与业务匹配度,但其复杂性要求更高的学习成本与投入。
156 11
|
24天前
|
架构师 微服务
【架构师】微服务的拆分有哪些原则?
微服务拆分需遵循七大原则:职责单一、围绕业务、中台化公共模块、按系统保障级别分离、技术栈解耦、避免循环依赖,并遵循康威定律使架构与组织匹配,提升可维护性与协作效率。
120 4
|
25天前
|
机器学习/深度学习 SQL 关系型数据库
TRUNCATE、DELETE、DROP 的区别?
MySQL中DELETE、TRUNCATE和DROP均用于删除数据,但作用不同:DELETE删除行记录,支持WHERE条件和事务回滚,速度慢;TRUNCATE快速清空表并重置自增ID,不可回滚;DROP则彻底删除表结构与数据,操作不可逆。三者在日志记录、速度及功能上有显著差异。
262 0
|
13天前
|
网络协议 安全 Ubuntu
Linux中的ARP包过滤利器(手把手教你使用arptables命令)
本文介绍Linux下的ARP防火墙工具arptables,涵盖其安装、基本语法、实战应用及规则持久化方法。通过arptables可有效防范ARP欺骗攻击,提升局域网安全性,适合网络初学者快速上手,助力构建更安全的内网环境。