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 MVCC机制原理详解
Apr 20 MySQL
MySQL表字段时间设置默认值
May 13 MySQL
my.ini优化mysql数据库性能的十个参数(推荐)
May 26 MySQL
MySQL Router实现MySQL的读写分离的方法
May 27 MySQL
MySQL快速插入一亿测试数据
Jun 23 MySQL
QT连接MYSQL数据库的详细步骤
Jul 07 MySQL
JMeter对MySQL数据库进行压力测试的实现步骤
Jan 22 MySQL
MySQL的索引你了解吗
Mar 13 MySQL
MySQL数据库 安全管理
May 06 MySQL
MySQL选择合适的备份策略和备份工具
Jun 01 MySQL
mysql数据库实现设置字段长度
Jun 10 MySQL
MySQL count(*)统计总数问题汇总
Sep 23 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去除HTML标签实例
2013/11/06 PHP
PHP实现常用排序算法的方法
2020/02/05 PHP
Javascript之旅 对象的原型链之由来
2010/08/25 Javascript
JavaScript 注册事件代码
2011/01/27 Javascript
jQuery+PHP+MySQL实现无限级联下拉框效果
2016/02/19 Javascript
AngularJS入门教程之AngularJS模型
2016/04/18 Javascript
关于JS 预解释的相关理解
2016/06/28 Javascript
jQuery简单注册和禁用全局事件的方法
2016/07/25 Javascript
jquery插件bootstrapValidator数据验证详解
2016/11/09 Javascript
JavaScript实现审核流程状态的动态显示进度条
2017/03/15 Javascript
vue Element-ui input 远程搜索与修改建议显示模版的示例代码
2017/10/19 Javascript
详解Angular路由之路由守卫
2018/05/10 Javascript
JS实现的冒泡排序,快速排序,插入排序算法示例
2019/03/02 Javascript
react写一个select组件的实现代码
2019/04/03 Javascript
vue下使用nginx刷新页面404的问题解决
2019/08/02 Javascript
浅析vue-cli3配置webpack-bundle-analyzer插件【推荐】
2019/10/23 Javascript
vue-resource:jsonp请求百度搜索的接口示例
2019/11/09 Javascript
使用JS实现动态时钟
2020/03/12 Javascript
python中的代码编码格式转换问题
2015/06/10 Python
python装饰器与递归算法详解
2016/02/18 Python
python文件与目录操作实例详解
2016/02/22 Python
web.py 十分钟创建简易博客实现代码
2016/04/22 Python
Python利用Beautiful Soup模块搜索内容详解
2017/03/29 Python
Python从文件中读取指定的行以及在文件指定位置写入
2019/09/06 Python
基于Python爬取爱奇艺资源过程解析
2020/03/02 Python
详解如何修改python中字典的键和值
2020/09/29 Python
奥地利体育网上商店:Gigasport
2019/10/09 全球购物
我看到了用指针调用函数的不同语法形式
2014/07/16 面试题
生物技术专业研究生自荐信
2013/09/22 职场文书
五年级学生评语
2014/04/22 职场文书
干部个人考察材料
2014/12/24 职场文书
烈士陵园观后感
2015/06/08 职场文书
中秋节祝酒词
2015/08/12 职场文书
解除合同协议书范本
2016/03/21 职场文书
辞职申请书范本
2019/05/20 职场文书
Nginx域名转发使用场景代码实例
2021/03/31 Servers