MySQL使用LIKE索引是否失效的验证

1、简单的示例展示

在MySQL中,LIKE查询可以通过一些方法来使得LIKE查询能够使用索引。以下是一些可以使用的方法:

  • 使用前导通配符(%),但确保它紧跟着一个固定的字符。

  • 避免使用后置通配符(%),只在查询的末尾使用。

  • 使用COLLATE来控制字符串比较的行为,使得查询能够使用索引。

下面是一个简单的例子,演示如何使用LIKE查询并且使索引有效

-- 假设我们有一个表 users,有一个索引在 name 字段上
CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(255)
);-- 创建索引
CREATE INDEX idx_name ON users(name);-- 使用 LIKE 查询,并且利用索引进行查询的例子
-- 使用前导通配符,确保它紧跟着一个固定的字符
SELECT * FROM users WHERE name LIKE 'A%'; -- 使用索引-- 避免使用后置通配符
SELECT * FROM users WHERE name LIKE '%A'; -- 不使用索引-- 使用 COLLATE 来确保比较符合特定的语言或字符集规则
SELECT * FROM users WHERE name COLLATE utf8mb4_unicode_ci LIKE '%A%'; -- 使用索引

在实际应用中,你需要根据你的数据库表结构、查询模式和数据分布来决定是否可以使用LIKE查询并且使索引有效。如果LIKE查询不能使用索引,可以考虑使用全文搜索功能或者其他查询优化技巧。

2、实验演示是否能正确使用索引

2.1、表及数据准备

准备两张表 t_departments 和 t_deptlist

(root@192.168.80.85)[superdb]> desc t_departments;
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| DEPARTMENT_ID   | int         | NO   | PRI | NULL    |       |
| DEPARTMENT_NAME | varchar(30) | YES  |     | NULL    |       |
| MANAGER_ID      | int         | YES  |     | NULL    |       |
| LOCATION_ID     | int         | YES  | MUL | NULL    |       |
+-----------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)(root@192.168.80.85)[superdb]> create table t_deptlist as select DEPARTMENT_ID,DEPARTMENT_NAME from t_departments;
Query OK, 29 rows affected (0.09 sec)
Records: 29  Duplicates: 0  Warnings: 0(root@192.168.80.85)[superdb]> desc t_deptlist;
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| DEPARTMENT_ID   | int         | NO   |     | NULL    |       |
| DEPARTMENT_NAME | varchar(30) | YES  |     | NULL    |       |
+-----------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)(root@192.168.80.85)[superdb]> alter table t_deptlist add constraint pk_t_deptlist_id primary key(DEPARTMENT_ID);
Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0(root@192.168.80.85)[superdb]> create index idx_t_deptlist_department_name on t_deptlist(department_name);
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0(root@192.168.80.85)[superdb]> show index from t_departments;
+---------------+------------+-----------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table         | Non_unique | Key_name              | Seq_in_index | Column_name     | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+---------------+------------+-----------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| t_departments |          0 | PRIMARY               |            1 | DEPARTMENT_ID   | A         |          29 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| t_departments |          1 | idx_t_department_name |            1 | DEPARTMENT_NAME | A         |          29 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+---------------+------------+-----------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.00 sec)(root@192.168.80.85)[superdb]> show index from t_deptlist;
+------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table      | Non_unique | Key_name                       | Seq_in_index | Column_name     | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| t_deptlist |          0 | PRIMARY                        |            1 | DEPARTMENT_ID   | A         |          29 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| t_deptlist |          1 | idx_t_deptlist_department_name |            1 | DEPARTMENT_NAME | A         |          29 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.00 sec)

表t_departments有多个字段列,其中DEPARTMENT_ID是主键,DEPARTMENT_NAME是索引字段,其它是非索引字段列

表t_deptlist有两个字段,其中DEPARTMENT_ID是主键,DEPARTMENT_NAME是索引字段

2.2、 执行 where DEPARTMENT_NAME LIKE ‘Sales’


(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE 'Sales';
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
| id | select_type | table         | partitions | type  | possible_keys         | key                   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t_departments | NULL       | range | idx_t_department_name | idx_t_department_name | 123     | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE 'Sales';
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys                  | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | range | idx_t_deptlist_department_name | idx_t_deptlist_department_name | 123     | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.01 sec)

执行计划查看,发现选择扫描二级索引index_name,表t_departments有多个字段列的行计划中的 Extra=Using index condition 使用了索引下推功能。MySQL5.6 之后,增加一个索引下推功能,可以在索引遍历过程中,对索引中包含的字段先做判断,在存储引擎层直接过滤掉不满足条件的记录后再返回给 MySQL Server 层,减少回表次数,从而提升了性能。

2.3、 执行 where DEPARTMENT_NAME LIKE ‘Sa%’

(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE 'Sa%';
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+-------------+------+------+----------+-----------------------+
| id | select_type | table         | partitions | type  | possible_keys         | key                   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+-------------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t_departments | NULL       | range | idx_t_department_name | idx_t_department_name | 123     | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE 'Sa%';
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys                  | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | range | idx_t_deptlist_department_name | idx_t_deptlist_department_name | 123     | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+------------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

执行计划查看,发现选择扫描二级索引index_name

2.4、 执行 where DEPARTMENT_NAME LIKE ‘%ale%’

(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE '%ale%';
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table         | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_departments | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   29 |    11.11 | Using where |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE '%ale%';
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | index | NULL          | idx_t_deptlist_department_name | 123     | NULL |   29 |    11.11 | Using where; Using index |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

表t_departments有多个字段列的执行计划的结果 type= ALL,代表了全表扫描。
表t_deptlist 有两个字段列的执行计划的结果中,可以看到 key=idx_t_deptlist_department_name ,也就是说用上了二级索引,而且从 Extra 里的 Using index 说明用上了覆盖索引。

2.5、 执行 where DEPARTMENT_NAME LIKE ‘%ale’

(root@192.168.80.85)[superdb]> explain select * from t_departments where DEPARTMENT_NAME LIKE '%ale';
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table         | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_departments | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   29 |    11.11 | Using where |
+----+-------------+---------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)(root@192.168.80.85)[superdb]> explain select * from t_deptlist where DEPARTMENT_NAME LIKE '%ale';
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key                            | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t_deptlist | NULL       | index | NULL          | idx_t_deptlist_department_name | 123     | NULL |   29 |    11.11 | Using where; Using index |
+----+-------------+------------+------------+-------+---------------+--------------------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

表t_departments有多个字段列的执行计划的结果 type= ALL,代表了全表扫描。
表t_deptlist 有两个字段列的执行计划的结果中,可以看到 key=idx_t_deptlist_department_name ,也就是说用上了二级索引,而且从 Extra 里的 Using index 说明用上了覆盖索引。
和上一个LIKE ‘%ale%’ 一样的结果。

3、为什么表t_deptlist where department_name LIKE ‘%ale’ 和 LIKE '%ale%'用上了二级索引

首先,这张表的字段没有「非索引」字段,所以 SELECT * 相当于 SELECT DEPARTMENT_ID,DEPARTMENT_NAME,这个查询的数据都在二级索引的 B+ 树,因为二级索引idx_t_deptlist_department_name 的 B+ 树的叶子节点包含「索引值+主键值」,所以查二级索引的 B+ 树就能查到全部结果了,这个就是覆盖索引。

从执行计划里的 type 是 index,这代表着是通过全扫描二级索引的 B+ 树的方式查询到数据的,也就是遍历了整颗索引树。

而 LIKE 'Sales’和LIKE 'Sa%'查询语句的执行计划中 type 是 range,表示对索引列DEPARTMENT_NAME进行范围查询,也就是利用了索引树的有序性的特点,通过查询比较的方式,快速定位到了数据行。

所以,type=range 的查询效率会比 type=index 的高一些。

4、为什么选择全扫描二级索引树,而不扫描聚簇索引树呢?

因为表t_deptlist 二级索引idx_t_deptlist_department_name 的记录是「索引列+主键值」,而聚簇索引记录的东西会更多,比如聚簇索引中的叶子节点则记录了主键值、事务 id、用于事务和 MVCC 的回滚指针以及所有的非索引列。

再加上表t_deptlist 只有两个字段列,DEPARTMENT_ID是主键,DEPARTMENT_NAME是索引字段,因此 SELECT * 相当于 SELECT DEPARTMENT_ID,DEPARTMENT_NAME 不用执行回表操作。

所以, MySQL 优化器认为直接遍历二级索引树要比遍历聚簇索引树的成本要小的多,因此 MySQL 优化器选择了「全扫描二级索引树」的方式查询数据。

5、数据表t_departments 多了非索引字段,执行同样的查询语句,为什么是全表扫描呢?

多了其他非索引字段后,select * from t_departments where DEPARTMENT_NAME LIKE ‘%ale’ OR DEPARTMENT_NAME LIKE ‘%ale%’ ; 要查询的数据就不能只在二级索引树里找了,得需要回表操作找到主键值才能完成查询的工作,再加上是左模糊匹配,无法利用索引树的有序性来快速定位数据,所以得在二级索引树逐一遍历,获取主键值后,再到聚簇索引树检索到对应的数据行,这样执行成本就会高了。

所以,优化器认为上面这样的查询过程的成本实在太高了,所以直接选择全表扫描的方式来查询数据。

如果数据库表中的字段只有主键+二级索引,那么即使使用了左模糊匹配或左右模糊匹配,也不会走全表扫描(type=all),而是走全扫描二级索引树(type=index)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/41981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【致知功夫 各随分限】成长需要时间,助人须考虑对方的承受程度

帮助他人需考虑各人的分限所能及的,初学圣学需时间沉淀,存养心性 任何人都应该受到教育,不应受到贫富、贵贱的差异而排除在教育之外,对于不同材质的学生,需要因材施教; 每天都有新的认知,大我…

STL—容器—string类【对其结构和使用的了解】【对oj相关练习的训练】

STL—容器—string类 其实string类准确来说并不是容器,因为他出现的时间比STL要早,但是也可以说是容器吧。 1.为什么要学习string类? 1.1C语言当中的字符串 C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作…

CTFShow的RE题(三)

数学不及格 strtol 函数 long strtol(char str, char **endptr, int base); 将字符串转换为长整型 就是解这个方程组了 主要就是 v4, v9的关系, 3v9-(v10v11v12)62d10d4673 v4 v12 v11 v10 0x13A31412F8C 得到 3*v9v419D024E75FF(1773860189695) 重点&…

Windows ipconfig命令详解,Windows查看IP地址信息

「作者简介」:冬奥会网络安全中国代表队,CSDN Top100,就职奇安信多年,以实战工作为基础著作 《网络安全自学教程》,适合基础薄弱的同学系统化的学习网络安全,用最短的时间掌握最核心的技术。 ipconfig 1、基…

Android Studio Run窗口中文乱码解决办法

Android Studio Run窗口中文乱码解决办法 问题描述: AndroidStudio 编译项目时Run窗口中文乱码,如图: 解决方法: 依次打开菜单:Help--Edit Custom VM Options,打开studio64.exe.vmoptions编辑框&#xf…

计算机专业怎么选择电脑

现在高考录取结果基本已经全部出来了,很多同学都如愿以偿的进入到了计算机类专业,现在大部分同学都在为自己的大学生活做准备了,其中第一件事就是买电脑,那计算机类专业该怎么选择电脑呢? 计算机专业是个一类学科&…

网络中的网络 NiN

一、全连接层问题 1、卷积层的参数:输入的通道数乘以输出的通道数再乘以窗口的高宽 2、全连接层的参数就是输入的元素个数乘以输出的元素个数,也就是输入的通道数乘以输入的高宽,再乘以输出的通道数乘以输出的高宽,贼大的量级 …

NLP简介

自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门融语言学、计算机科学、数学于一体的科学。因此,这一领域的研究将涉及自…

【算法】(C语言):冒泡排序、选择排序、插入排序

冒泡排序 从第一个数据开始到第n-1个数据,依次和后面一个数据两两比较,数值小的在前。最终,最后一个数据(第n个数据)为最大值。从第一个数据开始到第n-2个数据,依次和后面一个数据两两比较,数值…

关于用户咨询华为擎云L410笔记本安装Windows系统的说明

同样也是单位购买的华为擎云L410 KLVU-WDU0笔记本电脑,国产UOS系统某些软件用着不是很方便,用户咨询是否能够安装Windows10或者Windows7? 带着种种疑问也做了一些查询,之前也给一些国产设备更改过操作系统,之前的国产设…

计算机网络浅谈—什么是 OSI 模型?

开放系统通信(OSI)模型是一个代表网络通信工作方式的概念模型。 思维导图 什么是 OSI 模型? 开放系统互连 (OSI) 模型是由国际标准化组织创建的概念模型,支持各种通信系统使用标准协议进行通信。简单而言,OSI 为保证…

智能交通(3)——Learning Phase Competition for Traffic Signal Control

论文分享 https://dl.acm.org/doi/pdf/10.1145/3357384.3357900https://dl.acm.org/doi/pdf/10.1145/3357384.3357900 论文代码 https://github.com/gjzheng93/frap-pubhttps://github.com/gjzheng93/frap-pub 摘要 越来越多可用的城市数据和先进的学习技术使人们能够提…

Laravel框架详解及使用方法

Laravel是一款开源的PHP Web应用程序框架,它基于MVC(模型-视图-控制器)架构,以其简单易学、灵活性强、安全性高和强大的社区支持而广受开发者喜爱。以下是对Laravel框架的详细解析及使用方法: 一、Laravel框架简介 1…

刷题——在二叉树中找到最近公共祖先

在二叉树中找到两个节点的最近公共祖先_牛客题霸_牛客网 int lowestCommonAncestor(TreeNode* root, int o1, int o2) {if(root NULL) return -1;if((root->val o1) || (root->val o2)) return root->val;int left lowestCommonAncestor(root->left, o1, o2);i…

【pytorch19】交叉熵

分类问题的loss MSECross Entropy LossHinge Loss (SVN用的比较多) ∑ i m a x ( 0 , 1 − y i ∗ h θ ( x i ) ) \sum_imax(0,1-y_i*h_\theta(x_i)) ∑i​max(0,1−yi​∗hθ​(xi​)) Entropy(熵) Uncertainty(…

ESP32——物联网小项目汇总

商品级ESP32智能手表 [文章链接] 用ESP32,做了个siri?!开源了! [文章链接]

IPsec连接 和 SSL连接

Psec和SSL连接是两种用于保障网络通信安全的技术 IPsec 通常用于连通两个局域网,主要是网对网的连接,如分支机构与总部之间,或者本地IDC与云端VPC的子网连接。适合站点间的稳定通讯需求以及对网络层安全有严格要求的场合。要求两端有固定的网…

UDP协议:独特之处及其在网络通信中的应用

在网络通信领域,UDP(用户数据报协议,User Datagram Protocol)是一种广泛使用的传输层协议。与TCP(传输控制协议,Transmission Control Protocol)相比,UDP具有其独特的特点和适用场景…

对数据采集、数据存储和数据处理流程

对数据采集、数据存储和数据处理流程 数据采集是指从各种来源收集原始数据的过程,这通常包括传感器、网站、社交媒体、API等。它涉及设置抓取工具、爬虫技术或直接从数据库获取数据。数据存储则涉及到将采集到的数据安全、高效地保存起来,常见的有关系型…

EDEM-FLUENT耦合报错几大原因总结(持续更新)

写在前面,本篇内容主要是来源于自己做仿真时的个人总结,以及付费请教专业老师。每个人由于工况不一样,所以报错原因千奇百怪,不能一概而论,本篇内容主要是为本专栏读者在报错时提供大致的纠错方向,从而达到少走弯路的效果,debug的过程需要大家一点点试算。问题解答在文 …