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 08 MySQL
mysql的MVCC多版本并发控制的实现
Apr 14 MySQL
MySQL数据迁移相关总结
Apr 29 MySQL
MySQL EXPLAIN输出列的详细解释
May 12 MySQL
MySql开发之自动同步表结构
May 28 MySQL
如何使用分区处理MySQL的亿级数据优化
Jun 18 MySQL
MySQL连接控制插件介绍
Sep 25 MySQL
MySQL中datetime时间字段的四舍五入操作
Oct 05 MySQL
MySQL中IO问题的深入分析与优化
Apr 02 MySQL
mysql拆分字符串作为查询条件的示例代码
Jul 07 MySQL
MySQL中正则表达式(REGEXP)使用详解
Jul 07 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
PHPShop存在多个安全漏洞
2006/10/09 PHP
100多行PHP代码实现socks5代理服务器[2]
2016/05/05 PHP
给大家分享几个常用的PHP函数
2017/01/15 PHP
详解php几行代码实现CSV格式文件输出
2017/07/01 PHP
javascript 播放器 控制
2007/01/22 Javascript
jQuery 常见学习网站与参考书
2009/11/09 Javascript
jquery中防刷IP流量软件影响统计的一点对策
2011/07/10 Javascript
获取元素距离浏览器周边的位置的方法getBoundingClientRect
2013/04/17 Javascript
jquery的live使用注意事项
2014/02/18 Javascript
jQuery结合CSS制作动态的下拉菜单
2015/10/27 Javascript
jQuery页面刷新(局部、全部)问题分析
2016/01/09 Javascript
JS简单设置下拉选择框默认值的方法
2016/08/20 Javascript
BootStrap轮播HTML代码(推荐)
2016/12/10 Javascript
三种方式实现瀑布流布局
2017/02/10 Javascript
jQuery树插件zTree使用方法详解
2017/05/02 jQuery
浅谈使用mpvue开发小程序需要注意和了解的知识点
2018/05/23 Javascript
vue 的点击事件获取当前点击的元素方法
2018/09/15 Javascript
浅谈vue 锚点指令v-anchor的使用
2019/11/13 Javascript
python命令行参数sys.argv使用示例
2014/01/28 Python
Python常用的文件及文件路径、目录操作方法汇总介绍
2015/05/21 Python
python获取一组汉字拼音首字母的方法
2015/07/01 Python
python通过文件头判断文件类型
2015/10/30 Python
django文档学习之applications使用详解
2018/01/29 Python
python实现创建新列表和新字典,并使元素及键值对全部变成小写
2019/01/15 Python
linux环境下Django的安装配置详解
2019/07/22 Python
Python3 hashlib密码散列算法原理详解
2020/03/30 Python
使用html2canvas实现将html内容写入到canvas中生成图片
2020/01/03 HTML / CSS
Origins悦木之源香港官网:雅诗兰黛集团高端植物护肤品牌
2018/03/21 全球购物
夏威夷灵感服装及配饰:Reyn Spooner
2018/09/18 全球购物
什么是Connection-oriented Protocol/Connectionless Protocol面向连接的协议/无连接协议
2012/09/06 面试题
95%的面试官都会问到的50道Java线程题,附答案
2012/08/03 面试题
销售总经理岗位职责
2014/03/15 职场文书
生物工程专业求职信
2014/09/03 职场文书
运动会主持词大全
2015/07/02 职场文书
nginx配置ssl实现https的方法示例
2021/03/31 Servers
Python爬虫实战之爬取京东商品数据并实实现数据可视化
2021/06/07 Python