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 使用事件(Events)完成计划任务
May 24 MySQL
MySQL 查询速度慢的原因
May 25 MySQL
MySQL 亿级数据导入导出及迁移笔记
Jun 18 MySQL
MySQL8.0.18配置多主一从
Jun 21 MySQL
记一次Mysql不走日期字段索引的原因小结
Oct 24 MySQL
防止web项目中的SQL注入
Dec 06 MySQL
一文搞懂MySQL索引页结构
Feb 28 MySQL
MySQL中B树索引和B+树索引的区别详解
Mar 03 MySQL
一次Mysql update sql不当引起的生产故障记录
Apr 01 MySQL
详细聊一聊mysql的树形结构存储以及查询
Apr 05 MySQL
mysql函数之截取字符串的实现
Aug 14 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 常见郁闷问题答解
2006/11/25 PHP
php数组函数序列之array_key_exists() - 查找数组键名是否存在
2011/10/29 PHP
PHP通过内置函数memory_get_usage()获取内存使用情况
2014/11/20 PHP
php简单备份与还原MySql的方法
2016/05/09 PHP
ExtJs扩展之GroupPropertyGrid代码
2010/03/05 Javascript
jQuery总体架构的理解分析
2011/03/07 Javascript
基于jquery实现的表格分页实现代码
2011/06/21 Javascript
HTML复选框和单选框 checkbox和radio事件介绍
2012/12/12 Javascript
js实现幻灯片播放图片示例代码
2013/11/07 Javascript
javascript 数字格式化输出的实现代码
2013/12/10 Javascript
一个非常全面的javascript URL解析函数和分段URL解析方法
2014/04/12 Javascript
js删除数组元素、清空数组的简单方法(必看)
2016/07/27 Javascript
JS简单生成两个数字之间随机数的方法
2016/08/03 Javascript
Angular2入门教程之模块和组件详解
2017/05/28 Javascript
Vue2.0 slot分发内容与props验证的方法
2017/12/12 Javascript
如何制作一个Node命令行图像识别工具
2018/12/12 Javascript
vue+eslint+vscode配置教程
2019/08/09 Javascript
vue中的mescroll搜索运用及各种填坑处理
2019/10/30 Javascript
微信小程序自定义navigationBar顶部导航栏适配所有机型(附完整案例)
2020/04/26 Javascript
js+canvas实现图片格式webp/png/jpeg在线转换
2020/08/22 Javascript
pandas 使用apply同时处理两列数据的方法
2018/04/20 Python
python 将列表中的字符串连接成一个长路径的方法
2018/10/23 Python
pytorch标签转onehot形式实例
2020/01/02 Python
python实现简单井字棋小游戏
2020/03/05 Python
Python切割图片成九宫格的示例代码
2020/03/10 Python
一款基于css3和jquery实现的动画显示弹出层按钮教程
2015/01/04 HTML / CSS
西班牙美妆电商:Perfume’s Club(有中文站)
2018/08/08 全球购物
我们的节日春节活动方案
2014/08/22 职场文书
离婚协议书怎么写
2014/09/12 职场文书
单位租房协议书范本
2014/12/04 职场文书
2015新学期开学寄语
2015/02/26 职场文书
婚育证明样本
2015/06/16 职场文书
应届生个人的求职(自荐信范文2篇)
2019/08/23 职场文书
Vue过滤器(filter)实现及应用场景详解
2021/06/15 Vue.js
Python 详解通过Scrapy框架实现爬取CSDN全站热榜标题热词流程
2021/11/11 Python
python pygame 开发五子棋双人对弈
2022/05/02 Python