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三值逻辑与NULL
May 19 MySQL
MySQL中in和exists区别详解
Jun 03 MySQL
解析MySQL binlog
Jun 11 MySQL
Mysql数据库值的添加、修改、删除及清空操作实例
Jun 20 MySQL
MySQL系列之九 mysql查询缓存及索引
Jul 02 MySQL
MySQL笔记 —SQL运算符
Jan 18 MySQL
一文弄懂MySQL索引创建原则
Feb 28 MySQL
MySQL多表查询机制
Mar 17 MySQL
MySQL 主从复制数据不一致的解决方法
Mar 18 MySQL
一文简单了解MySQL前缀索引
Apr 03 MySQL
MySQL数据库安装方法与图形化管理工具介绍
May 30 MySQL
Mysql中@和@@符号的详细使用指南
Jun 05 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 文章中的远程图片采集到本地的代码
2009/07/30 PHP
PHP chmod 函数与批量修改文件目录权限
2010/05/10 PHP
ThinkPHP中I(),U(),$this->post()等函数用法
2014/11/22 PHP
php中smarty模板条件判断用法实例
2015/06/11 PHP
js实现DIV的一些简单控制
2007/06/04 Javascript
Prototype1.6 JS 官方下载地址
2007/11/30 Javascript
jquery easyui的tabs使用时的问题
2010/03/23 Javascript
javascript nextSibling 与 getNextElement(node) 使用介绍
2011/10/13 Javascript
JavaScript—window对象使用示例
2013/12/09 Javascript
IE6/IE7中JavaScript json提示缺少标识符、字符串或数字问题处理
2014/12/16 Javascript
jQuery使用empty()方法删除元素及其所有子元素的方法
2015/03/26 Javascript
使用jQuery+EasyUI实现CheckBoxTree的级联选中特效
2015/12/06 Javascript
Node.js DES加密的简单实现
2016/07/07 Javascript
JavaScript实现跟随滚动缓冲运动广告框
2017/07/15 Javascript
JS按条件 serialize() 对应标签的使用方法
2017/07/24 Javascript
微信小程序 按钮滑动的实现方法
2017/09/27 Javascript
JavaScript设计模式之模板方法模式原理与用法示例
2018/08/07 Javascript
从零开始学习搭建React脚手架项目
2018/08/23 Javascript
JS大坑之19位数的Number型精度丢失问题详解
2019/04/22 Javascript
35个Python编程小技巧
2014/04/01 Python
对tensorflow 的模型保存和调用实例讲解
2018/07/28 Python
Python数据类型之Tuple元组实例详解
2019/05/08 Python
Python使用指定字符长度切分数据示例
2019/12/05 Python
Python单链表原理与实现方法详解
2020/02/22 Python
Python操作dict时避免出现KeyError的几种解决方法
2020/09/20 Python
Melissa鞋马来西亚官方网站:MDreams马来西亚
2018/04/05 全球购物
澳洲国民品牌乡村路折扣店:Country Road & Trenery Outlet
2018/04/19 全球购物
房地产销售计划书
2014/01/10 职场文书
挖掘机司机岗位职责
2014/02/12 职场文书
2014年干部作风建设总结
2014/10/23 职场文书
民主评议党员个人总结
2015/02/13 职场文书
军训个人总结
2015/03/03 职场文书
个人年终总结怎么写
2015/03/09 职场文书
2016消防宣传标语口号
2015/12/26 职场文书
解决hive中导入text文件遇到的坑
2021/04/07 Python
python三子棋游戏
2022/05/04 Python