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 20 MySQL
为什么代码规范要求SQL语句不要过多的join
Jun 23 MySQL
MySQL系列之八 MySQL服务器变量
Jul 02 MySQL
为什么MySQL选择Repeatable Read作为默认隔离级别
Jul 26 MySQL
MySQL配置主从服务器(一主多从)
Aug 07 MySQL
MySQL数据库超时设置配置的方法实例
Oct 15 MySQL
mysql事务隔离级别详情
Oct 24 MySQL
Mysql分析设计表主键为何不用uuid
Mar 31 MySQL
MySQL分区路径子分区再分区
Apr 13 MySQL
Mysql 文件配置解析介绍
May 06 MySQL
MySQL如何修改字段类型和字段长度
Jun 10 MySQL
MySQL数据库实验实现简单数据库应用系统设计
Jun 21 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
用Zend Encode编写开发PHP程序
2006/10/09 PHP
PHP 开发环境配置(Zend Server安装)
2010/04/28 PHP
关于二级目录拖拽排序的实现(源码示例下载)
2013/04/26 PHP
php实现的太平洋时间和北京时间互转的自定义函数分享
2014/08/19 PHP
PHP中创建图像并绘制文字的例子
2014/11/19 PHP
Ubuntu 16.04下安装PHP 7过程详解
2017/03/28 PHP
php实现用户登陆简单实例
2017/04/04 PHP
SCP远程VPS快速搬家和WDCP升级php5.3安装memcached和eaccelerator教程
2017/07/27 PHP
PHP使用递归按层级查找数据的方法
2019/11/10 PHP
JavaScript 题型问答有答案参考
2010/02/17 Javascript
js 父窗口控制子窗口的行为-打开,关闭,重定位,回复
2010/04/20 Javascript
IE中图片的onload事件无效问题和解决方法
2014/06/06 Javascript
javascript实现简单的全选和反选功能
2016/01/05 Javascript
基于Jquery和html5实现炫酷的3D焦点图动画
2016/03/02 Javascript
javascript事件冒泡简单示例
2016/06/20 Javascript
深入分析javascript中的错误处理机制
2016/07/17 Javascript
基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解
2016/07/18 Javascript
将鼠标焦点定位到文本框最后(代码分享)
2017/01/11 Javascript
jQuery实现鼠标响应式透明度渐变动画效果示例
2018/02/13 jQuery
JS将网址url转化为JSON格式的方法
2018/07/02 Javascript
axios异步提交表单数据的几种方法
2019/08/11 Javascript
vue如何实现动态加载脚本
2020/02/05 Javascript
JavaScript实现鼠标移入随机变换颜色
2020/11/24 Javascript
Python的Tornado框架的异步任务与AsyncHTTPClient
2016/06/27 Python
python分析作业提交情况
2017/11/22 Python
Python微信操控itchat的方法
2019/05/31 Python
python多线程分块读取文件
2019/08/29 Python
3种python调用其他脚本的方法
2020/01/06 Python
PyCharm中如何直接使用Anaconda已安装的库
2020/05/28 Python
python如何求圆的面积
2020/07/01 Python
班会关于环保演讲稿
2013/12/29 职场文书
社区科普工作方案
2014/06/03 职场文书
教师党员批评与自我批评发言稿
2014/10/15 职场文书
介绍信样本
2015/01/31 职场文书
安全教育日主题班会
2015/08/13 职场文书
Python+OpenCV实现在图像上绘制矩形
2022/03/21 Python