在 MySQL 的 InnoDB 的情况下,对某一建过索引的列进行 like 模糊查询时

  1. like “%XX” 是不会走索引的
  2. like “XX%” 还是会走索引的

但是还是存在一些特殊的情况,MySQL 的底层会帮我们优化,使上面的 2 条结论变成 不一定。

表结构 SQL

CREATE TABLE  `test_table`(`id` int unsigned auto_increment comment '主键',`name` varchar(10) not null comment  '姓名',`age` tinyint not null comment '年龄',primary key(`id`),unique `name_index`(`name`)
) ENGINE= INNODB DEFAULT CHARSET=utf8;

like “%XX” 走索引

执行 SQL

# 第一句
explain SELECT 'id', `name` from `test_table` WHERE `name` like '%123';# 第二句
explain SELECT `age`, `name` from `test_table` WHERE `name` like '%123';# 第三句
explain SELECT * from `test_table` WHERE `name` like '%123';

第一句的执行计划为:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE test_table index name_index 32 1 100 Using where; Using index

type = indexkey = name_index 可以知道走了索引。为什么呢? 一般情况下的确是不会走索引的,但是这里刚好满足了一个情况:“覆盖索引”。在后面的 Extra 说明了这条 SQL 走了覆盖索引。

在理解这个问题前,只要知道几个概念就能解决了。

1. 主键索引和二级索引

在基于 InnoDB 为引擎的 MySQL 的索引是基于 B+ Tree 实现的, 同时在基于 B+ Tree 的基础上有 2 种实现方式:

  1. 主键索引, 简单理解的话,就是通过 primary key 创建的索引, 在 test_table 里面就是我们的 id 了
  2. 二级索引:可以简单的理解为除了主键索引以外的索引类型,比如:普通索引,复合索引,唯一索引等, 在 test_table 里面就是唯一索引 name 了。

其中主键索引的实现是这样的是(注这是简略版):

在树的非叶子节点,存放的就是我们的主键的值,而叶子节点存放的是我们主键 和 我们主键对应的数据行。

【注】:想要真正了解 B+ Tree 所有的话,可以看一下这里

二级索引的实现是这样的(同样的,这也是简略版):

在树的非叶子节点,存放的就是我们的索引的值,而叶子节点存放的是 索引的值 + 对应的行的主键 Id。(所以平时在使用非主键索引查询数据时,都是在二级索引的 B+ Tree 里面找到了对应的行的主键 Id,在通过这个 Id 到主键索引的 B+ Tree 查找)

2. 覆盖索引

指一个查询语句的执行只需要从索引中就可以得到查询记录,而不用从数据表中读取。也可以称之为实现了索引覆盖。

举个例子:一张表

id first_name last_name birthday sex
1 can lee 2020-03-23 1
2 cn l 2020-02-23 2

在这种表中,我们建立了一个复合索引 index(‘first_name’, ‘last_name’, ‘birthday’);
然后查询的时候 select first_name, last_name from 表名 where first_name like "c%"; 这时观察我们的 SQL 发现了需要的几列刚好是我们复合索引里面有的。这时 MySQL 就会在我们的 B+ Tree 的非叶子节点找到了需要的数据了,直接返回,而不用到 叶子节点去取数据, 这就是 “覆盖索引”。
从中我们知道:覆盖索引不是一种索引,更类似于一种行为。

需要理解的 2 个概念都讲完了, 那么为什么 like “%XX” 走索引的情况,应该可以分析出来了。

  1. 查询的是列有 id, name, 查询的条件为 name like “%123”。
  2. 我们在 name 上面建了唯一索引, 也就是二级索引
  3. 在这里二级索引的叶子节点存放的是 name + id
  4. 需要的列数据在二级索引树的叶子节点就有了,那么 MySQL 直接去遍历索引也能找到数据了,而不用直接全表扫描。

所以这里走了索引。

第二句的执行计划

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE test_table ALL 1 100 Using where

就是我们平时常说的 like “%XX” 不走索引的情况了。

第三句的分析, 类似的情况

like “XXX%” 不走索引

依旧是上面的 test_table 表,我们先通过一个存储过程,给这张表填充一些数据

新建一个存储过程:给表里面填充 140 条数据,每条的 name 的前缀都是 ‘name’ + 数字

delimiter  //
CREATE PROCEDURE insertdata()
begindeclare tempName varchar(20);
DECLARE sourceStr VARCHAR(100);declare count int;
set count = 0;WHILE count <140 DOset tempName=CONCAT('name', count);set count = count + 1;insert into test_table(name, age) VALUES (tempName, 1);
END WHILE;end;
//

执行存储过程,填充数据

call insertdata();

准备完成,开始

explain SELECT * from test_table where name like 'name%';

他的执行计划是这样的

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE test_table ALL name_index 140 100 Using where;

可以看到 type 的类型是 all, 走的是全表扫描。之所以为这样是存的值的相似度高 + like 的条件刚好在他们相似的地方。

我们存的 name 的格式都是 name + 数字,同时查询条件为 like ‘name%’, MySQL 判断走全表扫描比索引快。

[MySQL] like “%XX“ 和 like “XX%“ 的特殊情况相关推荐

  1. 关于mysql:Can‘t connect to MySQL server on ‘localhost:3306‘ (XX) + 关于navicat:client does not supp...

    bug:Can't connect to MySQL server on 'localhost:3306' (XX)   # XX=1003?/6? 问题描述:mysql的服务无法启动,不给任何解释; ...

  2. Navicat for Mysql数据导入时报错1366 - Incorrect string value: ‘\xE7\x90\xAD‘ for column ‘xx‘ at row xx

    在 Navicat for Mysql 进行数据导入时 报错1366 - Incorrect string value: '\xE7\x90\xAD' for column 'xx' at row x ...

  3. ERROR 2003 (HY000): Can't connect to MySQL server on 'xxx.xxx.xx.xxx' (111)

    一.问题描述 远程连接mysql数据库的时候报如下错误 ERROR 2003 (HY000): Can't connect to MySQL server on 'xxx.xxx.xx.xxx' (1 ...

  4. Can‘t connect to MySQL server on ‘xxx.xxx.xx.xx‘ (111)

    问题 我在Linux的一台机器中,想要使用MySQL远程连接其它主机时,发现无法连接.错误显示如下:. Can't connect to MySQL server on 'xxx.xxx.xx.xx' ...

  5. mysql error parsing_Go 解析日期格式-解决 parsing time xx as xx: cannot parse xx as xx 错误

    最近在解析 Go 的日期数据格式时(mysql 的 datetime 类型)时遇到个问题,在网上搜了很多方案都试了以后发现不可行,于是自己尝试解决后将解决方案发布出来.[结尾有彩蛋] Go 自身的 t ...

  6. Go 自定义日期时间格式解析解决方案 - 解决 parsing time xx as xx: cannot parse xx as xx 错误

    最近在解析 Go 的日期数据格式时(mysql 的 datetime 类型)时遇到个问题,在网上搜了很多方案都试了以后发现不可行,于是自己尝试解决后将解决方案发布出来. Go 自身的 time.Tim ...

  7. Go 自定义日期时间格式解析解决方案 - 解决 `parsing time xx as xx: cannot parse xx as xx` 错误

    最近在解析 Go 的日期数据格式时(mysql 的 datetime 类型)时遇到个问题,在网上搜了很多方案都试了以后发现不可行,于是自己尝试解决后将解决方案发布出来. Go 自身的 time.Tim ...

  8. java newsize_JVM中的-Xms -Xmx -XX:newSize -XX:MaxnewSize -Xmn -XX:PermSize -XX:MaxPermSize区别介绍...

    一.配置参数使用条件 在不断重构代码的情况下,仍然不能解决内存溢出的问题(OutOfMemoryError等),这种情况下就需要使用JVM的配置参数对JVM运行时各个区域的内存情况进行相应的分配. 二 ...

  9. -XX:+UseParallelGC与 -XX:+UseParNewGC相关介绍

    首先看一个图(所有的垃圾回收器,以及工作的堆空间) 对于我们默认(jdk1.7)使用parallel 垃圾回收器,old区就是使用的是parallel old, yong区使用的是parallel S ...

  10. http://www.od85c.com.cn/html/,OllyDbg script for unpacking Enigma 4.xx and 5.xx

    [Asm] 纯文本查看 复制代码// Enigma Protector 4.xx and 5.XX unpacker by GIV (some parts are from LCF-AT Altern ...

最新文章

  1. AI算法在FPGA芯片上还有这种操作?| 技术头条
  2. 八皇后问题(递归+非递归)
  3. 【Linux】13.linux内核切换
  4. 触发器before和after的区别
  5. boost的chrono模块等待按键的测试程序
  6. 数学--数论-- HDU 2601 An easy problem(约束和)
  7. 1.2鼠标移入移出改变背景色和其他大小样式
  8. QT学习笔记(十一):QString类
  9. mysql sqlserver firstrow=2_将CSV文件导入SQLServer
  10. auto_cmdb--01之models.py建表
  11. Android系统(187)---最易懂的Activity启动模式详解
  12. Linux内核将用Nftables替代iptables
  13. c语言坐标打印佛祖,C语言输入平面上两个点的坐标(double类型),计算两个点之间的距离。看”详细“里哪里写错了谢谢...
  14. 2014第7周1Web安全概念学习
  15. Thinkphp 使用原生类
  16. 用科学数据求真:地月之间不可能电视直播
  17. 联想7x04服务器装系统,联想硬盘保护EDU7X的安装方法.doc
  18. cad转pdf怎么变成黑白?
  19. windows10安装masscan
  20. Photoshop CC 2019魔棒工具的抠图

热门文章

  1. 代理模式--江南皮鞋厂
  2. 计算机网络A习题(2)
  3. Team Leader 的职责与范围
  4. 安利:华为鲲鹏920云主机部署Nginx服务器一键拉起自动化脚本
  5. 前端map循环遍历使用
  6. 手机批发业务—产品选购
  7. 如何使用文件便签管理工具 用标签管理你的文件
  8. video.min.js php,用Video.js实现H5直播界面
  9. 安卓APP源码和设计报告——Android小程序超级小猫
  10. 软考-软件项目活动图详解