MySQL索引及索引失效的分析(MySQL8.0.19)
目录
- 索引数据结构
- 主键索引
- 非主键索引
- 索引在什么时候是有效的?
- 字符串比较大小
- btween and
索引数据结构
主键索引
我们先来看看索引的数据结构,以及我们是如何利用索引来搜索数据的。MySQL的数据存储结构是B+树,在叶子节点存储了数据行,非叶子节点是主键索引。(MySQL的叶子节点是用双向链表链接的)
在MySQL中,表的数据行只存在于主键索引的叶子节点;因此查询任何数据都必须要搜索到叶子节点。B+树是一个多路平衡搜索树可以看出整个树结构是有序的(搜索过程与二叉搜索树的搜索过程相似);(PS:如果不了解B+树可以先了解下它的结构和特性)
如果要搜索id =7的数据行它的搜索过程是怎样的呢?select * from test_a where id = 7;(id是表主键)
因为搜索条件是id这是一个主键索引,因此在搜索数据时会直接利用B+树的结构做搜索。只用3次查找就可以找到id=7的数据行了。如果我们用年龄来做搜索条件呢?(select * from test_a where age = 78;)
只能全表挨个搜索了,因为年龄字段的存储是乱序的没有办法像搜索id那样利用id的有序性来做搜索。搜索7次才找到明显比上面的搜索次数多。并且有索引的行搜索所有的数据行都是3次(id=1~10),效率是很稳定的;实际在利用age做搜索条件时会搜索整个表,因为不确定后面是否有age=78的行。在数据量很大的时候,明显能感受到有索引和没有索引的差距。因为利用没有索引的字段做搜索条件会搜索整个表,而有索引的字段只需要根据B+树做搜索搜索次数是成指数减少的。
怎样让age作为搜索条件时,也可以减少搜索次数呢?给age建立一个B+树的结构—>建立索引。将表中所有行的age值用来建立一个B+树,那它的叶子节点也存储整个数据行吗? 显然不能这样做,这样做太浪费空间了。MySQL的做法是叶子节点存储主键id的值,这样就可以跟数据行关联起来了。(问题1:为什么不直接存储数据地址呢,岂不是更方便直接?这个问题文章末尾再讨论)
非主键索引
现在仍然用age做搜索条件:select * from test_a where age = 78;因为给age加了索引,因此搜索首先会搜索age的索引,也就是age值组成的B+树;
当搜索找到了age=7的时候只能够拿到主键id的值,而我们需要的是整个数据行的值,因此还需要用id的值去搜索主键的索引(B+树)也就是所谓的返表。从这里看出,如果只需要id字段就不要使用select *
来查询了。(问题2:在实际操作的时候,很少会使用select * 但是有时侯就是需要查询其他字段比如 :select id,name from test_a where age =78.这个时候该如何优化呢?有没有一种方法能够避免返表的操作呢?)
虽然使用索引可能会导致查找2个索引,但是在数据量特别大的时候相比较于没有索引的搜索也会快很多;使用索引搜索查找的次数与不使用索引相比是呈指数减少的。(问题3:这里有一个问题,age的值可能有重复不是唯一索引,因此当搜索到叶子节点age=7的时候搜索还没有完成,MySQL会如何处理普通索引呢?是所有字段都适合建立索引吗?)
索引在什么时候是有效的?
可以回想下,MySQL是如何利用索引进行搜索的?其实很简单,就是利用被搜索的字段值和B+树节点的值作比较,通过结果选择该搜索哪个分支。每搜索一层就会过滤掉其他分支减少搜索的次数,B+树就是通过这种方式来提高搜索效率的。(可以类比二叉搜索树的过程)简单来说,如果可以利用被搜索的字段值与B+树的节点值作比较,那就可以利用B+树来做搜索。如果被搜索字段不能与B+树的节点值比较,那索引就失效了。(理论上是这样的,但是MySQL还做了其他优化),要看是否走了索引可以用explain关键字来查看。
字符串比较大小
这涉及到在MySQL中如何比较2个值的大小问题了。在MySQL中比较字符串,是取出字符串的每一个字符来分别作比较。与String类的compareTo方法比较字符串大小大的规则是一样的。都是从第一个字符开始比较大小:如果第一个字符分出大小就返回;如果相同继续比较后面的字符;
CREATE TABLE test_a(
id INT PRIMARY KEY ,
NAME VARCHAR(20),
age INT ,
gender char(1)
);INSERT INTO test_a VALUES(1,'qwe',12,'m');
INSERT INTO test_a VALUES(2,'wer',122,'m');
INSERT INTO test_a VALUES(3,'qa',23,'f');
INSERT INTO test_a VALUES(4,'we',44,'m');
INSERT INTO test_a VALUES(5,'wsx',67,'m');
INSERT INTO test_a VALUES(6,'dc',89,'m');
INSERT INTO test_a VALUES(7,'rfv',78,'m');
INSERT INTO test_a VALUES(8,'yhn',54,'f');
INSERT INTO test_a VALUES(9,'ikm',43,'f');
INSERT INTO test_a VALUES(10,'pol',32,'f');SELECT * FROM test_a ;CREATE INDEX index_age ON test_a(age);
btween and
现在举几个例子判断一下索引是否失效:
# test_a有一个主键id索引,age索引explain select id from test_a where age between 10 AND 100;explain select * from test_a where age between 10 AND 100;explain select * from test_a where age between 10 AND 40;
-
第一个使用了索引;explain select id from test_a where age between 10 AND 100;
-
第二个没有使用索引;explain select * from test_a where age between 10 AND 100;
-
第三个使用了索引;explain select * from test_a where age between 10 AND 40;
前面2个SQL语句对比起来看:第一个sql为什么走了age的索引?第二个SQL不走索引?
分析一下这2个SQL有什么不同?第一个SQL直接查询id,不会返表。第二个SQL查询所有字段,拿到id会返回主键索引查询。从这2条SQL的结果对比来看会得出一个结论:在索引上使用(between and 或者 age > mm and age <nn)来查询,如果要进行回表查询的话就不会走索引了。如果不返表还是会走索引。
后面2个SQL语句对比起来看:第三个sql为什么走了age的索引?第二个SQL不走索引?
可以看到(10-100)占表90%的数据,基本上没怎么过滤数据,而(10-40)占表30%的数据,过滤了大部分的数据。后者拿到了一个较小了结果集,前者基本算是没有过滤了。因为还要拿着查询到的主键id到主键索引树再查询一次,如果没有筛选掉大部分的数据,拿着90%的id主键到主键的B+树上查询,相当于是来了2次全表查询,效率会相当低。这种情况下不走age的索引,直接全表查询效率会更高。
后续将范围扩至(10-78)包含70%数据也走了索引,情况有点诡异。后续往表里面添加100条数据(age:1-100)总数居113条,范围(10-78),没有走索引。当范围降至(10-41)时又会走索引。
再往表里添加100条数据(age:1-100),总共213条数据,与数据113条时相比:年龄(10-40)范围还要小,但是没有走索引。这就需要结果集数据占比减小,才可能走索引。
综合上面的情况,使用范围查询到底要不要走索引?如果需要返表查询会受到表的数据总量和查询到的结果集占总表数据量的占比这2个因素的影响。表的数据量越大,想要走索引那么查询的结果集就必须占比越小。表的数据量小,即使结果集占比较高也会走索引。
可以思考下面2个sql语句是否会走索引:
explain select * from test_A where age != 67;
explain select id from test_A where age != 67;
吃完饭再来跟新,未完待续。。。
相关文章:

MySQL索引及索引失效的分析(MySQL8.0.19)
目录索引数据结构主键索引非主键索引索引在什么时候是有效的?字符串比较大小btween and索引数据结构 主键索引 我们先来看看索引的数据结构,以及我们是如何利用索引来搜索数据的。MySQL的数据存储结构是B树,在叶子节点存储了数据行ÿ…...

第一个 Django 应用
1. 创建项目 1.1 新建项目 首先新建一个项目,名为 mysite,命令如下: django-admin startproject mysite # 或用 django-admin.py运行成功,生成一些目录: mysite/manage.py # 管理 Django 项目的命令行工具mysit…...

001-ksum 求符合条件的 k 个数 1. Two Sum/15. 3Sum/18. 4Sum/
推荐阅读 000-从零开始的数据结构与算法 001-01-ksum 求符合条件的 k 个数 1. Two Sum/15. 3Sum/18. 4Sum/ 002-两数相加 add two numbers 003-无重复字符的最长子串 Longest Substring Without Repeating Characters 004-寻找两个正序数组的中位数 005-最长回文子串 Lon…...

Nginx学习笔记(三)Linux环境下Nginx的安装和部署
目录一、官网下载二、配置基本信息1.上传 Linux2.解压3.安装编译环境4.配置基本信息4.1 配置失败原因(1):没有安装C编译环境4.2 配置失败原因(2):没有安装 PCRE 依赖4.3 配置失败原因(3):没有安装 zlib 依赖5.查看文件列表三、编译安装四、配…...

【十二天学java】day05--数组和循环高级
**# 1.数组 概念: 指的是一种容器,可以同来存储同种数据类型的多个值。 但是数组容器在存储数据的时候,需要结合隐式转换考虑。 比如: 定义了一个int类型的数组。那么boolean。double类型的数据是不能存到这个数组中的&#…...

用队列实现栈和用栈实现队列(C 语言)
目录 一、用队列实现栈 二、 用栈实现队列 一、用队列实现栈 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 实现 MyStack 类: void push(int…...

albedo开源框架配置多数据源
前言:公司框架项目一直都没认真阅读过,最近项目需要连接oracle数据,所以尝试使用框架连接多数据库。添加多数据源插件:我们在项目的插件模块内添加多数据源插件:albedo-dynamic-datasource<?xml version"1.0&…...

22张图带你了解IP地址有什么作用
了解IP地址 1、IP地址的格式 在IP协议的报文中,可以得知IP地址是有32个比特,IP地址在计算机中是以二进制的方式处理的,如果全部以二进制的形式来表示,使用跟表达都非常的困难,所以为了人类方便记忆,采用了…...

121.Android 简单的人工智能聊天项目,chatAi,AI聊天项目,GPTAi
//首页xml布局代码: <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"mat…...

C++ this指针详解
this 是 C 中的一个关键字,也是一个 const 指针,它指向当前对象,通过它可以访问当前对象的所有成员。所谓当前对象,是指正在使用的对象。例如对于stu.show();,stu 就是当前对象,this 就指向 stu。下面是使用…...

CSS 实现六边形柱状图
前言 👏CSS 实现六边形柱状图 速速来Get吧~ 🥇文末分享源代码。记得点赞关注收藏! 1.实现效果 2.实现步骤 定义全局css变量,柱状宽度为–w,最大高度为–h,柱形整体为渐变色,定义上部分颜色为…...

什么是推挽输出,开漏输出?
这篇文章是看B站“工科男孙老师”这个视频的笔记推挽 开漏 高阻 这都是谁想出来的词?? 我觉得讲的很好,做一下笔记 1.什么是IO输出三态 一共有:高电平, 低电平,浮空/高阻态 三种IO态 2.推挽输出 推挽输出能够表示高、…...

【图像分割】Unet系列深度讲解(FCN、UNET、UNET++)
【图像分割】Unet 深度讲解 文章目录【图像分割】Unet 深度讲解1. 介绍1.1 背景介绍:1.2 医学图像特点1.3 图像分割是什么2. Unet发展历程(FCN、Unet、Unet)2.1 全卷积网络-FCN2.1.1 FCN介绍:2.1.2 FCN框架2.1.3 反卷积层2.1.4 输…...

list底层的简单实现(万字长文详解!)
list底层的简单实现 文章目录list底层的简单实现list_node的实现!list_node的构造函数list的迭代器!——重点!list迭代器的成员变量迭代器的构造函数* 重载前置 重载后置 重载前置-- 重载后置-- 重载! 重载 重载-- 重载list的const迭代器——…...

学习Linux只要学会这个命令就够了!
大家好,我是良许。 这段时间又是搬家,又是找新办公室,现在终于安顿下来了,有时间给大家分享干货了。 今天给大家介绍一个 Linux 超级实用命令,有了这个命令,你就可以愉快使用 Linux 上几乎所有常用命令了…...

javascript基础
javascript基础 1概述: JavaScript是目前web开发中不可缺少的脚本语言,js不需要编译即可运行,运行在客户端,需要通过浏览器来解析执行JavaScript代码。 诞生于1995年,当时的主要目的是验证表单的数据是否合法。 JavaS…...

【游戏逆向】某游戏技能库分析
技能库的分析大多是从技能名字入手的,然后再通过传入职业或者ID等信息去到库中去取当前角色的可用技能。下面我们来对《**明月刀》中的技能库进行分析。 首先通过CE对技能名字进行搜索,得到较少的结果,分别对结果进行修改,并再次…...

Pytorch深度学习常用预训练网络模型的下载地址
Resnet:model_urls {‘resnet18’: ‘https://download.pytorch.org/models/resnet18-5c106cde.pth‘,‘resnet34’: ‘https://download.pytorch.org/models/resnet34-333f7ec4.pth‘,‘resnet50’: ‘https://download.pytorch.org/models/resnet50-19c8e357.pth‘,‘resnet…...

毕业设计 基于51单片机自动智能浇花系统设计
基于51单片机自动智能浇花系统设计1、毕业设计选题原则说明(重点)2、项目资料2.1 系统框架2.2 系统功能3、部分电路设计3.1 STC89C52单片机最小系统电路设计3.2 按键电路设计3.3 水泵控制电路设计4、部分代码展示4.1 数码管位选程序4.2 ad0832数据读取程…...

熟悉常用的 Linux 操作和 Hadoop 操作
文章目录前言一、常用命令集合1、cd命令:切换目录1、切换到目录/usr/local2、切换回上级目录3、切换到当前登录Linux系统的用户的自己的文件夹2、ls命令:查看文件与目录3、mkdir命令:创建目录4、rmdir命令:删除空的目录5、cp 命令…...

Vue2项目总结-电商后台管理系统
Vue2项目总结-电商后台管理系统 去年做的项目,拖了很久,总算是打起精力去做这个项目的总结,并对Vue2的相关知识进行回顾与复习 各个功能模块如果有过多重复冗杂的部分,将会抽取部分值得记录复习的地方进行记录 一:项目…...

【二】一起算法---队列:STL queue、手写循环队列、双端队列和单调队列、优先队列
纸上得来终觉浅,绝知此事要躬行。大家好!我是霜淮子,欢迎订阅我的专栏《算法系列》。 学习经典算法和经典代码,建立算法思维;大量编码让代码成为我们大脑的一部分。 ⭐️已更系列 1、基础数据结构 1.1、链表➡传送门 1…...

<Linux>环境变量
环境变量 文章目录环境变量一、基本概念二、常见环境变量三、查看环境变量的方法四、测试PATH五、测试HOME六、测试SHELL七、环境变量相关的命令八、环境变量的组织方式九、命令行参数十、通过代码获得环境变量十一、通过系统调用获取环境变量十二、环境变量通常是具有全局属性…...

【MySQL】下载(超详细教程)
目录 First-下载 Second-安装 Third-检测是否安装 Last-总结 First-下载 首先 ,我们一步一步跟着我的操作来,不能越步骤,很容易报错,就芭比Q了。 第一步直接进入这个网址:MySQL :: MySQL 社…...

再探pytorch的Dataset和DataLoader
本文从分类、检测、分割三大任务的角度来剖析pytorch得dataset和dataloader源码,可以让初学者深刻理解每个参数的由来和使用,并轻松自定义dataset。思考:在探究Dataset和DataLoader之前,需要明白一个事情,就是当我们不…...

【2023.3.18 美团校招】
文章目录1. 小美剪彩带2. 最多修改两个字符,生成字典序最小的回文串1. 小美剪彩带 题意:找出区间内不超过k种数字子数组的最大长度 使用双指针的方式,用哈希表来统计每个数出现次数。在双指针移动的过程中,动态的维护区间内不同数…...

程序员必须知道的HTML常用代码有哪些?
HTML 即超文本标记语言,是目前应用最为广泛的语言之一,是组成一个网页的主要语言。在现今这个 HTML5 华丽丽地占领了整个互联网的时候,如果想要通过网页抓住浏览者的眼球光靠因循守旧是不行的,程序猿们需要掌握一些必须知道的 HTM…...

多目标家庭行为检测--人脸识别模块构建
文章目录前言原理项目结构编码配置主控函数人脸采集模块特征提取识别测试前言 2023-3-18 天小雨,午觉舒适程度5颗星。任务完成指数2颗星。续接上文:《MidiaPipe stgcn(时空图卷积网络)实现人体姿态判断(单目标&#x…...

RocketMQ重复消费问题的原因
文章目录 概览消息发送异常时重复发送消费消息抛出异常消费者提交offset失败服务端持久化offset失败主从同步offset失败重平衡清理长时间消费的消息总结概览 消息发送异常时重复发送 首先,我们来瞅瞅RocketMQ发送消息和消费消息的基本原理。 如图,简单说一下上图中的概念: …...

proxy详细介绍与使用
proxy详细介绍与使用 proxy 对象用于创建一个对象的代理,是在目标对象之前架设一个拦截,外界对该对象的访问,都必须先通过这个拦截。通过这种机制,就可以对外界的访问进行过滤和改写。 ES6 原生提供 Proxy 构造函数,…...