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 性能监控及调优
Apr 06 MySQL
MySQL 重写查询语句的三种策略
May 10 MySQL
MySQL 逻辑备份与恢复测试的相关总结
May 14 MySQL
探究Mysql模糊查询是否区分大小写
Jun 11 MySQL
MySQL里面的子查询的基本使用
Aug 02 MySQL
MySQL配置主从服务器(一主多从)
Aug 07 MySQL
MySQL的全局锁和表级锁的具体使用
Aug 23 MySQL
SQL基础查询和LINQ集成化查询
Jan 18 MySQL
MySQL的索引你了解吗
Mar 13 MySQL
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
Mar 23 MySQL
单机多实例部署 MySQL8.0.20
May 15 MySQL
Mysql中的触发器定义及语法介绍
Jun 25 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 文件上传源码分析(RFC1867)
2009/10/30 PHP
PHP+MYSQL会员系统的登陆即权限判断实现代码
2011/09/23 PHP
PHP移动文件指针ftell()、fseek()、rewind()函数总结
2014/11/18 PHP
php中ob函数缓冲机制深入理解
2015/08/03 PHP
php基于双向循环队列实现历史记录的前进后退等功能
2015/08/08 PHP
PHP使用Curl实现模拟登录及抓取数据功能示例
2018/04/27 PHP
PHP7使用ODBC连接SQL Server2008 R2数据库示例【基于thinkPHP5.1框架】
2019/05/06 PHP
php版本CKEditor 4和CKFinder安装及配置方法图文教程
2019/06/05 PHP
js一组验证函数
2008/12/20 Javascript
Javascript将string类型转换int类型
2010/12/09 Javascript
基于jquery打造的百分比动态色彩条插件
2012/09/19 Javascript
extjs两个tbar问题探讨
2013/08/08 Javascript
jquery 鼠标滑动显示详情应用示例
2014/01/24 Javascript
jQuery禁用快捷键例如禁用F5刷新 禁用右键菜单等的简单实现
2016/08/31 Javascript
JS实现图片预览的两种方式
2017/06/27 Javascript
基于Bootstrap表单验证功能
2017/11/17 Javascript
JavaScript实现单例模式实例分享
2017/12/22 Javascript
React Native 图片查看组件的方法
2018/03/01 Javascript
vue中v-for加载本地静态图片方法
2018/03/03 Javascript
WebGL three.js学习笔记之阴影与实现物体的动画效果
2019/04/25 Javascript
功能完善的小程序日历组件的实现
2020/03/31 Javascript
JavaScript实现猜数字游戏
2020/05/20 Javascript
用python统计代码行的示例(包括空行和注释)
2018/07/24 Python
使用Python实现租车计费系统的两种方法
2018/09/29 Python
使用python批量修改文件名的方法(视频合并时)
2020/03/24 Python
Kmeans均值聚类算法原理以及Python如何实现
2020/09/26 Python
纯HTML5+CSS3制作图片旋转
2016/01/12 HTML / CSS
Julep官网:美容产品和指甲油
2017/02/25 全球购物
美国在线和移动免费会员制批发零售商:Boxed(移动端的Costco)
2020/01/02 全球购物
"火柴棍式"程序员面试题
2014/03/16 面试题
五四青年节演讲稿
2014/05/26 职场文书
大学毕业生个人自荐书
2014/07/02 职场文书
繁星春水读书笔记
2015/06/30 职场文书
python爬取某网站原图作为壁纸
2021/06/02 Python
浅谈Python数学建模之线性规划
2021/06/23 Python
Golang 入门 之url 包
2022/05/04 Golang