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 相关文章推荐
仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案
May 06 MySQL
mysql中between的边界,范围说明
Jun 08 MySQL
MySQL 十大常用字符串函数详解
Jun 30 MySQL
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
Jul 01 MySQL
Mysql实现简易版搜索引擎的示例代码
Aug 30 MySQL
面试被问select......for update会锁表还是锁行
Nov 11 MySQL
一条慢SQL语句引发的改造之路
Mar 16 MySQL
MySQL多表查询机制
Mar 17 MySQL
如何创建一个创建MySQL数据库中的datetime类型
Mar 21 MySQL
MySQL如何使备份得数据保持一致
May 02 MySQL
MYSQL常用函数介绍
May 05 MySQL
MySQL数据库实验实现简单数据库应用系统设计
Jun 21 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
再说下636单管机
2021/03/02 无线电
Netbeans 8.2将支持PHP7 更精彩
2016/06/13 PHP
深入理解PHP 数组之count 函数
2016/06/13 PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
2017/04/18 PHP
Ruffy javascript 学习笔记
2009/11/30 Javascript
IE6下js通过css隐藏select的一个bug
2010/08/16 Javascript
javascript Array.prototype.slice使用说明
2010/10/11 Javascript
JavaScript 5 新增 Array 方法实现介绍
2012/02/06 Javascript
jquery按回车提交数据的代码示例
2013/11/05 Javascript
基于jQuery实现的文字按钮表单特效整理
2014/12/07 Javascript
js中匿名函数的创建与调用方法分析
2014/12/19 Javascript
javascript单例模式的简单实现方法
2015/07/25 Javascript
angular+ionic 的app上拉加载更新数据实现方法
2017/01/16 Javascript
详解vue中computed 和 watch的异同
2017/06/30 Javascript
理解 JavaScript EventEmitter
2018/03/29 Javascript
AngularJS与后端php的数据交互方法
2018/08/13 Javascript
vuex2中使用mapGetters/mapActions报错的解决方法
2018/10/20 Javascript
js实现简单模态框实例
2018/11/16 Javascript
VsCode与Node.js知识点详解
2019/09/05 Javascript
原生JavaScript之es6中Class的用法分析
2020/02/23 Javascript
[05:28]刀塔密之一:团结则存
2014/07/03 DOTA
Django中模型Model添加JSON类型字段的方法
2015/06/17 Python
Python的爬虫框架scrapy用21行代码写一个爬虫
2017/04/24 Python
python实现求解列表中元素的排列和组合问题
2018/03/15 Python
Python QQBot库的QQ聊天机器人
2019/06/19 Python
python多维数组分位数的求取方式
2020/03/03 Python
Django实现whoosh搜索引擎使用jieba分词
2020/04/08 Python
css3的focus-within选择器的使用
2020/05/11 HTML / CSS
使用spring mvc+localResizeIMG实现HTML5端图片压缩上传的功能
2016/12/16 HTML / CSS
意大利在线高尔夫商店:Online Golf
2021/03/09 全球购物
预备党员思想汇报范文
2013/12/29 职场文书
竞选体育委员演讲稿
2014/04/26 职场文书
有关环保的标语
2014/06/13 职场文书
法学专业毕业实习自我鉴定2014
2014/09/27 职场文书
2016年端午节校园广播稿
2015/12/18 职场文书
使用 MybatisPlus 连接 SqlServer 数据库解决 OFFSET 分页问题
2022/04/22 SQL Server