MySQL索引命中与失效

2023-11-11

讨论MySQL索引命中与失效,我们得先来创建表

创建表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(5) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户密码',
  `create_essay` int(5) NOT NULL COMMENT '原创文章',
  `user_visited` int(10) NOT NULL COMMENT '被访问量',
  `user_rank` int(5) NOT NULL COMMENT '用户排名',
  `perms` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `nickname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户昵称',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 116856 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

// 创建组合索引
ALTER TABLE `user` ADD INDEX idx_username_password_user_rank (`username`,`password`,`user_rank`)

这里有一个组合索引的最左匹配原则,具体看我另一篇博客:MySQL最左匹配原则

 
 

查看MySQL中索引是否命中可以使用explainh执行优化器来查看

MySQL执行优化器

执行优化器,顾名思义,优化语句的,准确来说是优化查询语句。其实就是在我们写的select语句前加一个Explain关键字。
 
 

索引的命中与失效情况

第一种情况:针对联合索引,是否遵循最左匹配原则;

建立一个组合索引

idx_username_password_user_rank(`username`,`password`,`user_rank`)
// 命中索引跟顺序无关
explain SELECT * from `user` where username =  "liuxiangcheng" and password = "515239" and user_rank = 1
explain SELECT * from `user` where user_rank = 1 and username =  "liuxiangcheng" and password = "515239"  
explain SELECT * from `user` where user_rank = 1 and password = "515239" and username =  "liuxiangcheng"

结果:

在这里插入图片描述

 

第二种情况:去掉大哥,看看索引是否命中;

// 去掉大哥
explain SELECT * from `user` where   password = "515239" and user_rank = 1

去掉大哥之后,索引失效,全表扫描。

在这里插入图片描述

 

第三种情况:在索引列上做了函数操作,会导致索引失效而导致全表扫描

我们先把那个联合索引删除掉,然后在username这一列上建立一个唯一索引:

删除组合索引

drop index idx_username_password_user_rank on `user`

创建唯一索引

alter table `user` ADD UNIQUE key (`username`)

查看索引

在这里插入图片描述

 

explain SELECT * from `user` where  username= 'user110819'

在这里插入图片描述

 

explain SELECT * from `user` where  concat(username,'')= 'user110819'

在这里插入图片描述

 

第四种情况:模糊查询前缀是以%开头的,索引失效

explain SELECT * from `user` where   username like '%user11081'

在这里插入图片描述

 

第五种情况:模糊查询中后缀是以%,可以命中索引

explain SELECT * from `user` where   username like 'user11081%'

在这里插入图片描述

 

第六种情况:使用is not null 会导致索引失效

explain SELECT * from `user` where   username is not null

在这里插入图片描述
 

第六种情况:使用and时,其中有一个条件查询带有索引而另一个不带索引,不会导致索引失效。而使用or时,如果条件查询中其中一个不带索引,导致索引失效,必须全部带有索引。

and情况:

explain SELECT * from `user` where   username = "liuxiangcheng" and password = "515239"

在这里插入图片描述
 

or情况:

explain SELECT * from `user` where   username = "liuxiangcheng" or user_rank = 1

在这里插入图片描述

我们给user_rank加上索引

alter table `user` ADD  index (`user_rank`)

在这里插入图片描述
再次查询:

explain SELECT * from `user` where   username = "liuxiangcheng" or user_rank = 1

在这里插入图片描述

 

第七种情况:使用不等于(!= 或者<>)的时候,会导致索引失效

explain SELECT * from `user` where   user_rank != 1

or 

explain SELECT * from `user` where   user_rank <> 1

在这里插入图片描述

 
第八种情况:使用范围查询之后索引失效

explain SELECT * from `user` where   user_rank >(<,>=,<=) 1

在这里插入图片描述

 
第八种情况:隐式转换可能会导致我们的索引失效

varchar类型,如果用int类型来查询,索引失效
数据库user表中我们的password是varchar类型
如果我们在条件查询中使用整形来替代,那么这个时候索引就会失效,where varchar = int 索引失效

// password is varchar type

explain SELECT * from `user` where password = 515239

explain SELECT * from `user` where password = '515239'

explain SELECT * from `user` where password = "515239"

在这里插入图片描述

 

如果是int类型,我们使用varchar来替代,索引命中

// user_rank is int type

explain SELECT * from `user` where user_rank = "1"

explain SELECT * from `user` where user_rank = '1'

explain SELECT * from `user` where user_rank = 1

在这里插入图片描述

总结隐式转换

  1. 当操作符左右两边的数据类型不一致时,会发生隐式转换
  2. 当 where 查询操作符左边为数值类型时发生了隐式转换,但是索引会命中,对查询效率影响不大,但还是不推荐这么做
  3. 当 where 查询操作符左边为字符类型时发生了隐式转换,这样会导致索引失效,造成全表扫描。
  4. 字符串转换为数值类型时,非数字开头的字符串会转化为0,以数字开头的字符串会截取从第一个字符到第一个非数字内容为止的值为转化结果。

 
 

总结

(1)MySQL中索引失效的情况

1、组合索引中不遵循最左匹配原则,带头大哥不在,导致索引失效,全表扫描。
2、在索引列上做了函数操作,导致索引失效,全表扫描。
3、模糊查询前缀是以%开头的,导致索引失效,全表扫描。
4、使用is not null 会导致索引失效。
5、使用or时,如果条件查询中其中一个不带索引,导致索引失效,全表扫描。
6、使用不等于(!= 或者<>)的时候,会导致索引失效。
7、使用范围查询(>、<、>=、<=)之后索引失效。
8、隐式转换可能会导致我们的索引失效。

(2)查看MySQL中索引是否命中可以使用explainh执行优化器来查看。

 
 

拓展

为什么我们要尽量避免使用

select * 

这得从我们的主键索引和非主键索引说,比如我们使用name来作为唯一索引,而唯一索引又是非聚簇索引,非聚簇索引中叶子节点数据区挂载的是主键id,那么我们使用select * from table where name = liu。这个时候,我们就会先从name索引树中查找,找到之后再到主键索引树中查找主键值对应的记录(这个过程称为回表),再进行返回。而如果我们使用select id ,name from table where name = liu。在name索引树的数据区中找到name = liu的数据时,一同把 id、name 返回,不用遍历主键索引树,效率高。

理清楚思路之后再次总结:其实这个的话,其实是命中了覆盖索引,而在了解覆盖索引之前,我们还是先需要知道聚簇索引和非聚簇索引的区别。覆盖索引,我们在通过聚簇索引/稀疏索引在B+Tree的叶子节点数据区中找到我们想找到的内容并返回(如聚簇索引/稀疏索引username,主键索引id),而不用产生回表操作,拿到主键值id之后再去遍历一遍主键索引树,这就是覆盖索引。覆盖索引查询一颗树,总比查询两颗树快,这也是为什么覆盖索引能够加快我们查询效率的原因,而这也是为什么我们在写SQL语句的时候需要写什么就写什么,而不要使用select *,我们举给例子:
我们select id , username from talbe where username = “xxx”,这个时候通过非聚簇索引在B+Tree叶子节点数据区获取到辅助我们找到行记录的主键值id之后就返回了,速度快。

 
具体B+Tree原理见我博客:MySQL索引和B+Tree底层原理

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL索引命中与失效 的相关文章

随机推荐

  • vlc activex调用

    首先是在html页面调用 第一种方式 下面直接给出的是调用函数 function doGo targetURL port var options new Array vlc input repeat 1 aspect ratio 704 4
  • 代码的认爹之路: 面向对象继承

    面向对象 继承 前言 Hello 各位同学朋友大家好啊 今天给大家分享的技术呢 是面向对象三大特征之一的继承 我们今天主要按照以下几个点 展开继承的讲解 目录 继承的介绍 继承的好处和弊端 继承中成员访问特点 成员变量 继承中成员访问特点
  • 苏宁!你还挺得过去吗?(苏宁大幅裁员)

    前两天才写了一篇 作为一个江苏人 我眼中的苏宁 说实话 我内心是有点不太相信 偌大的苏宁会走到今天这步田地 可一件件传闻都慢慢变成了实锤 一 苏宁大裁员 一位多年老友刚跳槽去了苏宁 入职一个月 就面临整个部门裁员 据说要直接裁掉4成研发人员
  • 解决报错: `defaultValue` is invalid for `getFieldDecorator` will set `value`, please use `option...

    报错原因 当我的input 绑定了v decorator的时候 又设置了default value默认值 如下
  • 小波去噪及其matlab实现方法

    小波去噪是小波分析的一个应用 小波分析是一种数学工具 用于将信号分解成不同的频率分量 小波去噪的目的是利用小波变换将噪声从信号中去除 MATLAB Matrix Laboratory 是一种基于数值计算的高级工具 广泛用于工程 科学和金融等
  • C语言-字符串(单个字符)

    一 字符串 单个字符 的定义 1 单个字符的定义 char i x 单个字符的定义 字符串创建后为常量无法修改 2 一维字符串数组的定义 char i xxxx 此方式定义的一维字符串数组必须立刻赋值 char i 4 此方式相当于在存储器
  • 多线程批量执行任务简单实例(CompletableFuture)

    创建线程的四种方式 1 extendds Thred类 start 2 implements Runnable接口 new Thread new MyRun start 3 ListenableFuture CompletableFutur
  • C++11 并发指南五(std condition_variable 条件变量 详解)

    C 11 并发指南五 std condition variable 详解 前面三讲 C 11 并发指南二 std thread 详解 C 11 并发指南三 std mutex 详解 分别介绍了 std thread std mutex st
  • 计算机毕业设计Node.js+Vue基于Web的网络教学系统(程序+源码+LW+部署)

    该项目含有源码 文档 程序 数据库 配套开发软件 软件安装教程 欢迎交流 项目运行 环境配置 Node js Vscode Mysql5 7 HBuilderX Navicat11 Vue Express 项目技术 Express框架 No
  • k8s学习-DaemonSet(模板、创建、更新、回滚、删除等)

    目录 概念 模板 实战 创建 更新 回滚 回滚到上一版本 回滚到指定版本 删除 参考 概念 DaemonSet 守护进程集 在kubectl中缩写为ds 在所有节点或者是匹配的节点上都部署一个Pod 当有节点加入集群时 也会为他们新增一个
  • Unity Cinemachine之第三人称摄像机CinemachineFreeLook属性详解

    演示 CinemachineFreeLook是一个第三人称视角相机插件 功能非常强大 内置了很多属性可以供开发者根据需求进行调整 创建 首先是Cinemachine插件的导入 如果是2018以后的Unity版本 应该 可以直接从Unity顶
  • C++之:struct和class的区别

    一 数据封装和成员访问权限 1 结构体 struct 在struct中 默认的成员访问权限是public 这意味着 在结构体外部 我们可以直接访问其成员变量和成员函数 下面是一个简单的例子 struct Point int x y Poin
  • ggplot2入门

    ggplot2入门 二 3 5 几何对象 geom 和统计变换 stat 几何对象执行着图层的实际渲染 控制着生成的图像类型 各种类型图如下 示例代码如下 head mtcars library ggplot2 p lt ggplot mt
  • 自学Java做的第一个入门项目:ATM银行系统

    import java util ArrayList import java util Random import java util Scanner public class ATMSystem public static void ma
  • Unity中协程和线程区别

    协程和线程的效果类似 都可以实现与主线程异步的效果 但是本质不一样 协程在主线程内 通过软件手段实现函数与主线程的异步效果 Startcoroutine IEnumerator Func IEnumerator是迭代器关键字 修饰一个函数
  • 标准单元库---NLDM/CCS library model

    Timing Model 数字芯片设计 除了全定制设计外 绝大部分都是基于std cell的半定制设计 那么std cell的模型就极为重要 尤其半定制 需要把一个std cell看成block box 只考虑其input output p
  • python发送邮件的乱码问题解决方案

    公司项目中需要通过后台发送邮件 邮件内容包括图片附件 如果通过PHPmailer发送 由于邮件服务器可能存在延迟现象 通过PHPmailer发送邮件 需要等待邮件发送成功后才能返回结果 这在实践中证明 有时发送邮件无法即时返回结果 影响用户
  • Python内容聚合

    Python3 教程 Python 标准库概览 pip 设置代理 设置代理 PyCharm支持的4种Python Interpreter和配置方法 Python中import的as语法 Python安装自己的代码到site packages
  • python 停止线程

    import threading import time import inspect import ctypes def async raise tid exctype raises the exception performs clea
  • MySQL索引命中与失效

    目录 创建表 MySQL执行优化器 索引的命中与失效情况 总结 拓展 讨论MySQL索引命中与失效 我们得先来创建表 创建表 SET NAMES utf8mb4 SET FOREIGN KEY CHECKS 0 Table structur