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查询语句的执行过程
May 07 MySQL
Mysql数据库命令大全
May 26 MySQL
正确使用MySQL INSERT INTO语句
May 26 MySQL
MySQL连接查询你真的学会了吗?
Jun 02 MySQL
MYSQL 无法识别中文的永久解决方法
Jun 03 MySQL
MySQL中的布尔值,怎么存储false或true
Jun 04 MySQL
MySQL开启事务的方式
Jun 26 MySQL
MySQL系列之十三 MySQL的复制
Jul 02 MySQL
mysql备份策略的实现(全量备份+增量备份)
Jul 07 MySQL
MySQL数据库超时设置配置的方法实例
Oct 15 MySQL
深入理解mysql事务隔离级别和存储引擎
Apr 12 MySQL
MySql数据库触发器使用教程
Jun 01 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
str_replace只替换一次字符串的方法
2013/04/09 PHP
二进制交叉权限微型php类分享
2014/02/07 PHP
10款非常有用的 Ajax 插件分享
2012/03/14 Javascript
Flex通过JS获取客户端IP和计算机名的实例代码
2013/11/21 Javascript
JS获取地址栏参数的几种方法小结
2014/02/28 Javascript
js的参数有长度限制吗?发现不能超过2083个字符
2014/04/20 Javascript
js Object2String方便查看js对象内容
2014/11/24 Javascript
JS自定义混合Mixin函数示例
2016/11/26 Javascript
JQuery.dataTables表格插件添加跳转到指定页
2017/06/09 jQuery
微信小程序之圆形进度条实现思路
2018/02/22 Javascript
JavaScript创建对象的常用方式总结
2018/08/10 Javascript
JS实现换肤功能的方法实例详解
2019/01/30 Javascript
深入理解es6块级作用域的使用
2019/03/28 Javascript
vue router 跳转时打开新页面的示例方法
2019/07/28 Javascript
package.json配置文件构成详解
2019/08/27 Javascript
Vue中watch、computed、updated三者的区别及用法
2020/07/27 Javascript
Linux 发邮件磁盘空间监控(python)
2016/04/23 Python
python3实现全角和半角字符转换的方法示例
2017/09/21 Python
python 字符串和整数的转换方法
2018/06/25 Python
将python图片转为二进制文本的实例
2019/01/24 Python
python求加权平均值的实例(附纯python写法)
2019/08/22 Python
解决Tensorflow2.0 tf.keras.Model.load_weights() 报错处理问题
2020/06/12 Python
手把手教你如何用Pycharm2020.1.1配置远程连接的详细步骤
2020/08/07 Python
python中time、datetime模块的使用
2020/12/14 Python
CSS3 边框效果
2019/11/04 HTML / CSS
SHEIN台湾:购买最新流行女装服饰
2019/05/18 全球购物
科颜氏法国官网:Kiehl’s法国
2019/08/20 全球购物
五一手机促销方案
2014/03/08 职场文书
乡镇纠风工作实施方案
2014/03/22 职场文书
欢迎领导标语
2014/06/27 职场文书
Keras在mnist上的CNN实践,并且自定义loss函数曲线图操作
2021/05/25 Python
浅谈如何提高PHP代码质量之单元测试
2021/05/28 PHP
Redis基本数据类型List常用操作命令
2022/06/01 Redis
SQL Server2019安装的详细步骤实战记录(亲测可用)
2022/06/10 SQL Server
MySQL数据库之内置函数和自定义函数 function
2022/06/16 MySQL
Nginx开源可视化配置工具NginxConfig使用教程
2022/06/21 Servers