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 相关文章推荐
数据库的高级查询六:表连接查询:外连接(左外连接,右外连接,UNION关键字,连接中ON与WHERE的不同)
Apr 05 MySQL
mysql中between的边界,范围说明
Jun 08 MySQL
MySQL连表查询分组去重的实现示例
Jul 01 MySQL
MySQL系列之一 MariaDB-server安装
Jul 02 MySQL
MySQL子查询中order by不生效问题的解决方法
Aug 02 MySQL
JMeter对MySQL数据库进行压力测试的实现步骤
Jan 22 MySQL
将MySQL的表数据全量导入clichhouse库中
Mar 21 MySQL
Windows下载并安装MySQL8.0.x 版本的完整教程
Apr 10 MySQL
MySQL创建管理LIST分区
Apr 13 MySQL
MySQL创建管理RANGE分区
Apr 13 MySQL
Mysql排查分析慢sql之explain实战案例
Apr 19 MySQL
MySQL如何修改字段类型和字段长度
Jun 10 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 file_exists无效的解决办法
2013/06/26 PHP
索趣科技的答案
2007/02/07 Javascript
jQuery jqgrid 对含特殊字符json 数据的 Java 处理方法
2011/01/01 Javascript
Jquery实现弹性滑块滑动选择数值插件
2015/08/08 Javascript
JavaScript类型系统之正则表达式
2016/01/05 Javascript
Node.js重新刷新session过期时间的方法
2016/02/04 Javascript
AngularJS 路由和模板实例及路由地址简化方法(必看)
2016/06/24 Javascript
javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】
2016/12/15 Javascript
原生js轮播(仿慕课网)
2017/02/15 Javascript
Vue中使用vue-i18插件实现多语言切换功能
2018/04/25 Javascript
vue项目在安卓低版本机显示空白的原因分析(两种)
2018/09/04 Javascript
electron实现qq快捷登录的方法示例
2018/10/22 Javascript
package.json配置文件构成详解
2019/08/27 Javascript
在vue中利用全局路由钩子给url统一添加公共参数的例子
2019/11/01 Javascript
基于JavaScript实现控制下拉列表
2020/05/08 Javascript
Vue使用预渲染代替SSR的方法
2020/07/02 Javascript
在SAE上部署Python的Django框架的一些问题汇总
2015/05/30 Python
Python冒泡排序注意要点实例详解
2016/09/09 Python
解决python2.7用pip安装包时出现错误的问题
2017/01/23 Python
Python 高级专用类方法的实例详解
2017/09/11 Python
Python3.遍历某文件夹提取特定文件名的实例
2018/04/26 Python
python 日期操作类代码
2018/05/05 Python
Pandas 按索引合并数据集的方法
2018/11/15 Python
python re库的正则表达式入门学习教程
2019/03/08 Python
python列表推导和生成器表达式知识点总结
2020/01/10 Python
Yahoo-PHP面试题3
2012/01/14 面试题
C/C++程序员常见面试题一
2012/12/08 面试题
淘宝好评语大全
2014/05/05 职场文书
预备党员综合考察材料
2014/05/31 职场文书
爱护公共设施标语
2014/06/24 职场文书
教师演讲稿开场白
2014/08/25 职场文书
专职安全员岗位职责
2015/04/11 职场文书
常住证明范本
2015/06/23 职场文书
90行Python代码开发个人云盘应用
2021/04/20 Python
mysql 8.0.24 安装配置方法图文教程
2021/05/12 MySQL
pytorch 实现多个Dataloader同时训练
2021/05/29 Python