MySQL索引失效的典型案例


Posted in MySQL onJune 05, 2021

典型案例

有两张表,表结构如下:

CREATE TABLE `student_info` (
  `id` int(11) NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

CREATE TABLE `student_score` (
  `id` int(11) NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  `score` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

其中一张是info表,一张是score表,其中score表比info表多了一列score字段。

插入数据:

mysql> insert into student_info values (1,'zhangsan'),(2,'lisi'),(3,'wangwu'),(4,'zhaoliu');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> insert into student_score values (1,'zhangsan',60),(2,'lisi',70),(3,'wangwu',80),(4,'zhaoliu',90);
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from student_info;
+----+----------+
| id | name     |
+----+----------+
|  2 | lisi     |
|  3 | wangwu   |
|  1 | zhangsan |
|  4 | zhaoliu  |
+----+----------+
4 rows in set (0.00 sec)

mysql> select * from student_score ;
+----+----------+-------+
| id | name     | score |
+----+----------+-------+
|  1 | zhangsan |    60 |
|  2 | lisi     |    70 |
|  3 | wangwu   |    80 |
|  4 | zhaoliu  |    90 |
+----+----------+-------+
4 rows in set (0.00 sec)

当我们进行下面的语句时:

mysql> explain select B.* 
       from 
       student_info A,student_score B 
       where A.name=B.name and A.id=1;
+----+-------------+-------+------------+-------+------------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys    | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+------------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | A     | NULL       | const | PRIMARY,idx_name | PRIMARY | 4       | const |    1 |   100.00 | NULL        |
|  1 | SIMPLE      | B     | NULL       | ALL   | NULL             | NULL    | NULL    | NULL  |    4 |   100.00 | Using where |
+----+-------------+-------+------------+-------+------------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

为什么B.name上有索引,但是执行计划里面第二个select表B的时候,没有使用索引,而用的全表扫描???

解析:

该SQL会执行三个步骤:

1、先过滤A.id=1的记录,使用主键索引,只扫描1行LA

2、从LA这一行中找到name的值“zhangsan”,

3、根据LA.name的值在表B中进行查找,找到相同的值zhangsan,并返回。

其中,第三步可以简化为:

select * from student_score  where name=$LA.name

这里,因为LA是A表info中的内容,而info表的字符集是utf8mb4,而B表score表的字符集是utf8。

所以

在执行的时候相当于用一个utf8类型的左值和一个utf8mb4的右值进行比较,因为utf8mb4完全包含utf8类型(长字节包含短字节),MySQL会将utf8转换成utf8mb4(不反向转换,主要是为了防止数据截断).

因此,相当于执行了:

select * from student_score  where CONVERT(name USING utf8mb4)=$LA.name

而我们知道,当索引字段一旦使用了隐式类型转换,那么索引就失效了,MySQL优化器将会使用全表扫描的方式来执行这个SQL。

要解决这个问题,可以有以下两种方法:

a、修改字符集。

b、修改SQL语句。

给出修改字符集的方法:

mysql> alter table student_score modify name varchar(10)  character set utf8mb4 ;
Query OK, 4 rows affected (0.03 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> explain select B.* from student_info A,student_score B where A.name=B.name and A.id=1;
+----+-------------+-------+------------+-------+------------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys    | key      | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+------------------+----------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | A     | NULL       | const | PRIMARY,idx_name | PRIMARY  | 4       | const |    1 |   100.00 | NULL  |
|  1 | SIMPLE      | B     | NULL       | ref   | idx_name         | idx_name | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+------------------+----------+---------+-------+------+----------+-------+
2 rows in set, 1 warning (0.01 sec)

修改SQL的方法,大家可以自己尝试。

附:常见索引失效的情况

一、对列使用函数,该列的索引将不起作用。

二、对列进行运算(+,-,*,/,! 等),该列的索引将不起作用。

三、某些情况下的LIKE操作,该列的索引将不起作用。

四、某些情况使用反向操作,该列的索引将不起作用。

五、在WHERE中使用OR时,有一个列没有索引,那么其它列的索引将不起作用。

六、隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误。

七、使用not in ,not exist等语句时。

八、当变量采用的是times变量,而表的字段采用的是date变量时.或相反情况。

九、当B-tree索引 is null不会失效,使用is not null时,会失效,位图索引 is null,is not null 都会失效。

十、联合索引 is not null 只要在建立的索引列(不分先后)都会失效。

以上就是MySQL索引失效的典型案例的详细内容,更多关于MySQL索引失效的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
多属性、多分类MySQL模式设计
Apr 05 MySQL
Windows10下安装MySQL8
Apr 06 MySQL
Mysql MVCC机制原理详解
Apr 20 MySQL
MySQL时间设置注意事项的深入总结
May 06 MySQL
MySQL 表空间碎片的概念及相关问题解决
May 07 MySQL
mysql 带多个条件的查询方式
Jun 05 MySQL
MySQL分库分表详情
Sep 25 MySQL
mysql5.6主从搭建以及不同步问题详解
Dec 04 MySQL
一文搞懂MySQL索引页结构
Feb 28 MySQL
Arthas排查Kubernetes中应用频繁挂掉重启异常
Feb 28 MySQL
MySQL时区造成时差问题
Apr 13 MySQL
MySQL库表名大小写的选择
Jun 05 #MySQL
mysql 带多个条件的查询方式
Mysql 如何实现多张无关联表查询数据并分页
Jun 05 #MySQL
Mysql中存储引擎的区别及比较
浅谈mysql返回Boolean类型的几种情况
Jun 04 #MySQL
Mysql 设置boolean类型的操作
Jun 04 #MySQL
MySQL中的布尔值,怎么存储false或true
You might like
php中json_encode中文编码问题分析
2011/09/13 PHP
php的mail函数发送UTF-8编码中文邮件时标题乱码的解决办法
2015/10/20 PHP
symfony2.4的twig中date用法分析
2016/03/18 PHP
PHP getNamespaces()函数讲解
2019/02/03 PHP
JQUERY THICKBOX弹出层插件
2008/08/30 Javascript
JQuery Study Notes 学习笔记(一)
2010/08/04 Javascript
node.js中的fs.statSync方法使用说明
2014/12/16 Javascript
理解Javascript的动态语言特性
2015/06/17 Javascript
Jquery UI实现一次拖拽多个选中的元素操作
2020/12/01 Javascript
微信小程序 欢迎界面开发的实例详解
2016/11/30 Javascript
Bootstrap缩略图与警告框学习使用
2017/02/08 Javascript
layui分页效果实现代码
2017/05/19 Javascript
vue项目base64字符串转图片的实现代码
2018/07/13 Javascript
JQuery扩展对象方法操作示例
2018/08/21 jQuery
Layui数据表格跳转到指定页的实现方法
2019/09/05 Javascript
layui问题之模拟table表格中的选中按钮选中事件的方法
2019/09/20 Javascript
js实现简单的秒表
2020/01/16 Javascript
Python交换变量
2008/09/06 Python
python django 访问静态文件出现404或500错误
2017/01/20 Python
Django与JS交互的示例代码
2017/08/23 Python
python 常用的基础函数
2018/07/10 Python
Python使用win32com模块实现数据库表结构自动生成word表格的方法
2018/07/17 Python
python将txt文件读入为np.array的方法
2018/10/30 Python
python调用虹软2.0第三版的具体使用
2019/02/22 Python
python BlockingScheduler定时任务及其他方式的实现
2019/09/19 Python
Python3 Tensorlfow:增加或者减小矩阵维度的实现
2020/05/22 Python
python 三种方法提取pdf中的图片
2021/02/07 Python
一款利用css3的鼠标经过动画显示详情特效的实例教程
2014/12/29 HTML / CSS
html5 video标签屏蔽右键视频另存为的js代码
2013/11/12 HTML / CSS
巴西儿童时尚购物网站:Dinda
2019/08/14 全球购物
动态密码技术
2012/10/18 面试题
缴纳养老保险的证明
2014/01/10 职场文书
大学毕业感言100字
2014/02/03 职场文书
带刀到教室的检讨书
2014/10/04 职场文书
党的群众路线教育实践活动心得体会(乡镇)
2014/11/03 职场文书
图文详解matlab原始处理图像几何变换
2021/07/09 Python