一篇搞懂mysql中的索引(大白话版)

容易来说,索引的出现其实就是为了提升数据查询的效率,就像书的目录一样。一本 500 页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那我估计你可得找一会儿。同样,对于数据库的表而言,索引其实就是它的“目录”。

索引模型

索引的出现是为了提升查询效率,但是实现索引的方式却有很多种,所以这里也就引入了索引模型的概念,一下是常见的三种:

哈希表

哈希表是一种以键值对的方式进行存储的。只要输入key就可以查找到对应的value,哈希思路很容易,就是放在一个有序数组中,通过一个可以计算出hash值的函数算出key指定一个位置,然后再将value放到对应的位置上。
不可避免的还有哈希冲突,也就是算出了同一个哈希值作为key,发生哈希冲突时数据就会延升出一个链表,这个链表会存储value,value会有一个next属性指向下一个value。
在这里插入图片描述

图中User1和User4算出了两个相同的哈希值,不过没关系,后面跟了一个链表,假设,这时候你要查 ID_1对应的名字是什么,处理步骤就是:首先,将 ID_1 通过哈希函数算出 N;然后,按顺序遍历,找到 User1。

图中的ID不是自增的,这样做的好处是增加新的 User 时速度会很快,只需要往后追加。但缺点是,因为不是有序的,所以哈希索引做区间查询的速度是很慢的。

你可以设想下,如果你现在要找ID在[ID_X, ID_Y]这个区间的所有用户,就一定要全部扫描一遍了。所以,哈希表这种结构适用于只有等值查询的场景。

有序数组

但是有序数组在等值查询的时候就特别优秀,同样是上面的例子。
在这里插入图片描述
这个数组就是按照ID号递增的顺序保存的。这时候如果你要查 ID3 对应的名字,用二分法就可以快速得到,这个时间复杂度是 O(log(N))。

这个索引结构支持范围查询。你要查ID号在[ID_X, ID_Y]区间的 User,可以先用二分法找到 ID_X(如果不存在 ID_X,就找到大于 ID_X 的第一个 User),然后向右遍历,直到查到第一个大于 ID_Y 的ID号,退出循环。

如果仅仅看查询效率,有序数组就是最好的数据结构了,但是需要更新时就很麻烦了,如果要往中间插入数据的话就要挪动后面所有的数据。

一般可以使用在静态数据或者常年不怎么改变的数据进行存储。

搜索树

二叉搜索树的特点是:父节点左子树所有结点的值小于父节点的值,右子树所有结点的值大于父节点的值。
在这里插入图片描述
这样如果你要查 ID_4 的话,按照图中的搜索顺序就是按照 UserA -> UserC ->User2 这个路径得到。这个时间复杂度是 O(log(N))。

二叉树是搜索效率最高的,但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。

如果树节点很多,还很高的话,这个查询效率是非常底的。为了提升效率就一定要尽量的规避IO。

InnoDB 的索引模型

在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。每一个索引在 InnoDB 里面对应一棵 B+ 树。

假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有索引。

mysql> create table T(id int primary key, k int not null, name varchar(16),index (k))engine=InnoDB;

然后假设表中有五行数据:(id,k) 值分别为 (100,1)、(200,2)、(300,3)、(400,4) 和 (500,5)。
两棵树的图:
在这里插入图片描述
两棵树分为两个索引:主键索引和非主键索引。

  • 主键索引的叶子节点存储的是整行的数据。(聚簇索引)
  • 非主键索引的叶子节点内容是主键的值。(二级索引)
主键索引和非主键索引的区别
  • 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
  • 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

普通索引比主键索引多出了一次查询,所有我们要尽可能的使用自增主键。

维护索引

如果需要在id500后面新增id600,就直接在后面插入,如果说我要中间的位置插入数据的话成本又会显的很高。需要逻辑上挪动后面的数据,空出位置。

如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。

页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50%,也就是会挪动50%到新的数据页中。
比如我R3,R4,R5,R6挪动50%,到新的数据页里(新的数据页中包含R7因为插入时候不够了所以分页了呀),R3,R4,R5,R6、R7(这是挪过来的数据)。
当然有分裂就有合并。

怎么选择索引,使用自增还是普通的业务索引?

自增主键的插入数据模式,正符合了我们前面提到的递增插入的场景。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。

而有业务逻辑的字段做主键,则往往不容易保证有序插入,这样写数据成本相对较高。

还有一方面就是存储空间的考虑:我们上面也说了普通索引的叶子节点存的主键索引的ID。假设身份证这个唯一的字符串做主键索引的话,其他的普通索引的叶子节点就会存储主键索引的值,身份证一般18个子符,可以想象多占空间,如果用整型就是4字节。

主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小

什么场景适合用业务字段直接做主键的呢?
  • 只有一个索引;
  • 该索引一定要是唯一索引。

典型的 KV 场景。

索引覆盖

就是主键索引和非主键索引之间,非主键索引总是需要回表。这方面就可以采用索引覆盖去优化,覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
在这里插入图片描述

SELECT ID FROM SHADIAO WHERE K 1 BETWEEN 2;

这条语句需要执行几次树的搜索操作,会扫描多少行?

  1. 去K的索引字段取到k=1,id=100;
  2. 再到 id 索引树查到 id=100 对应的 R1;
  3. 再取k=2索引,叶子节点值是id=200;
  4. 再回表到主键索引id=200取到R2;
  5. 然后k再取下一个值3,继续循环判断条件成不成立,不成立循环结束。

可以看到这个过程非常的繁琐,来会进行回表的操作,因为根据k查询的结果都在主键中,所以不得不回表取数据。

如果这个语句只需要查询ID的值,而ID的值也已经在k索引上了,因此可以直接提供查询结果,不需要回表了,其实就是这个K已经覆盖了我们需要的查询结果,被称为覆盖索引。

联合索引

举个栗子:就是如果我有一个id和身份证号加姓名这几个字段,这个时候我要根据身份证号去查询姓名的话,我需不需要把身份证号和姓名建立联合索引(多个索引合起来作为一个联合索引,如(card,name,size>1单值索引是联合索引size=1的特例)?

答案是肯定的,建立联合索引后,查询身份证号的时候就不用去回表去主键索引拿到整行数据再找到姓名这个字段了,而是直接将姓名这个字段结果返回了。(因为联合索引存的是联合字段+主键值)。

其实索引高多了成本也是很高的。

最左前缀

接上个栗子:给姓名和身份证号建立联合索引(name,card_id)可以看的我是顺序排列的,从左往右。
使用语句 like “name%” 这个索引就会生效:

  • 顾名思义:最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配(like “name%”会生效,like “%name”不会生效)。
  • 例如:b = 2 如果建立(a,b)顺序的索引,是匹配不到(a,b)索引的;但是如果查询条件是a = 1 and b = 2-或者a=1(又或者是a = 2 and b = 1)就可以,因为优化器会自动调整a,b的顺序。
  • 再比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,因为c字段是一个范围查询,它之后的字段会停止匹配。

索引下垂

还是用(name,card_id)这个例子,这两个是个联合索引,查询语句 like “name%” 就可以获取到数据了,但是如果我加了一个条件,语句变成了 like “name%” and card_id=2;
再遍历这两个索引的时候先对索引列进行判断,直接过滤掉不满足条件的记录,减少回表次数。

小结

如果有了(a,b)两个联合索引后就不需要去单独维护一个a的索引了。
如果有一个基于a、b给自的查询语句,比如条件里面只有b的话(a,b)索引就不会生效,这时候就不得不单独维护一个单独的索引了。
建立联合索引可以有效的避免回表次数。比如(a,b)两个索引,这和时候通过a去查询到b的值的时候就可以直接获取到b的数据而不用回表去查询了。(联合索引包含了字段值+主键id)
覆盖索引是一种优化索引,可以减少回表,就是当我这个索引包含了要查询的字段的值就可以不用回表查询而是直接返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556466.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sqlite插入时间字段_sqlite 获取最后插入id

(点击上方公众号&#xff0c;可快速关注)SQLite数据库中的表均有一个特殊的rowid字段&#xff0c;它是一个不重复的64位有符号整数&#xff0c;默认起始值为1。rowid别名为oid或_rowid_&#xff0c;但在创建表的SQL声明语句中只能使用rowid作为关键字。如果在创建表的时候设置了…

Dubbo与SpringCloud的架构与区别

Dubbo与SpringCloud的架构与区别 Dubbo架构图 SpringCloud 架构图 总结 框架DubboSpringCloud服务注册中心ZookeeperSpring Cloud Netfix Eureka(nacos)服务调用方式RPCREST API服务监控Dubbo-monitorSpring Boot Admin熔断器不完善Spring Cloud Netflix Hystrix服务网关无Sp…

matlab求微分数值,用MATLAB语言求微积分方程的数值解.(xd^2y)/dx^2-5dy/dx+y=0y(0)=0y'(0)=0...

function dymyfun03(x,y)dyzeros(3,1) %初始化变量dydy(1)y(2); %dy(1)表示y的一阶导数,其等于y的第二列值dy(2)5/x*y(3)-y(1); %dy(2)表示y的二阶导数%ex0808 用ode23 ode45 ode113解多阶微分方程clear,clc[x23,y23]ode23(myfun03,[1,10],[1 10 30]);[x45,y45]ode45(myfun03,[…

springboot 接口404_资深架构带你学习Springboot集成普罗米修斯

这篇文章主要介绍了springboot集成普罗米修斯(Prometheus)的方法&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧&#xff01;Prometheus 是一套开源的系统监控报警框…

http常见的状态码,400,401,403状态码分别代表什么?

2XX 成功 200 OK&#xff0c;表示从客户端发来的请求在服务器端被正确处理 204 No content&#xff0c;表示请求成功&#xff0c;但响应报文不含实体的主体部分 206 Partial Content&#xff0c;进行范围请求 3XX 重定向 301 moved permanently&#xff0c;永久性重定…

mysql left 数学原理,MySQL全面瓦解21(番外):一次深夜优化亿级数据分页的奇妙经历...

背景1月22号晚上10点半&#xff0c;下班后愉快的坐在在回家的地铁上&#xff0c;内心想着周末的生活怎么安排。sql忽然电话响了起来&#xff0c;一看是咱们的一个开发同窗&#xff0c;顿时紧张了起来&#xff0c;本周的版本已经发布过了&#xff0c;这时候打电话通常来讲是线上…

java8中的map与flatmap区别

map:只能返回一个值 flatmap:返回多个值 new ArrayList().stream().map(x -> x);//返回一个 new ArrayList().stream().flatMap(x -> Arrays.asList(x.split(" ")).stream());//返回一个流,也就是多个值 看API声明可以发现&#xff0c;flatmap接受的参数是流…

shell 文件路径有空格_Python学习第57课-shell入门之基本简单命令(一)

【每天几分钟&#xff0c;从零入门python编程的世界&#xff01;】我们现在学习shell操作&#xff0c;对于shell的命令&#xff0c;我们就把它看做新的语言&#xff0c;shell语言&#xff0c;它是不同于其他编程语言的。就像我们学习一门编程语言&#xff0c;都是从打出“hell …

比较Spring AOP和AspectJ

1. 介绍 当前有多个可用的AOP库&#xff0c;这些库必须能够回答许多问题&#xff1a; 它与我现有的或新的应用程序兼容吗&#xff1f;在哪里可以实施AOP&#xff1f;它与我的应用程序集成的速度有多快&#xff1f;性能开销是多少&#xff1f; 在本文中&#xff0c;我们将着眼…

hough变换直线检测_python+opencv实现霍夫变换检测直线

作者&#xff1a;Ruff_XY功能&#xff1a;创建一个滑动条来控制检测直线的长度阈值&#xff0c;即大于该阈值的检测出来&#xff0c;小于该阈值的忽略 注意&#xff1a;这里用的函数是HoughLinesP而不是HoughLines&#xff0c;因为HoughLinesP直接给出了直线的断点&#xff0c;…

php文件防删改,PHP实现增删改查以及防SQL注入

最近项目调研时&#xff0c;需要在集成板子上做个配置的网页&#xff0c;板子上装的是linux系统&#xff0c;配置信息在一个SQLite数据库中&#xff0c;经过讨论大家决定用PHP做这个网页。由于项目组没一个会PHP的&#xff0c;所以安排我调研下写个Demo&#xff0c;经过几天的研…

c# python 相互调用_【GhPython】Python如何使用“委托”和lambda表达式

【版权声明】| 作者&#xff1a;月之眼| 首发于大水牛参数化设计平台| 如需转载请联系作者| 如果觉得文章不错&#xff0c;欢迎分享 函数作为参数传入 在python中函数是能作为参数输入函数的。这个有点类似于C#中的委托&#xff0c;将一个函数封装到一个委托对象里&#xff0c;…

chimerge算法matlab实现,有监督的卡方分箱算法

实现代码import numpy as npimport pandas as pdfrom collections import Counterdef chimerge(data, attr, label, max_intervals):distinct_vals sorted(set(data[attr])) # Sort the distinct valueslabels sorted(set(data[label])) # Get all possible labelsempty_coun…

金士顿u盘真假软件_简洁轻巧 金士顿DT80 Type-C高速闪存盘评测

从都市的高端会议到普通的日常娱乐&#xff0c;USB高速闪存应用于我们生产生活的方方面面。它小巧便携&#xff0c;稳定可靠的特点吸引了无数人去使用&#xff0c;同时为我们提供了诸多便利。闪存盘也就是日常生活中经常提到的U盘。大多数人对于U盘的印象是老式的USB Micro接口…

php阴影效果,如何使用css3实现文字的单阴影效果和多重阴影效果(

使用css3实现文本阴影效果的原理实现阴影效果主要是用text-shadow属性&#xff0c;根据W3C标准&#xff0c;如果我们想要在IE下兼容CSS3的阴影属性可以使用ie.css3-htc&#xff0c;不过按照标准InternetExplorer9以及更早版本的浏览器暂时不支持text-shadow属性。最基本的语法为…

promise链式调用_这一次,彻底弄懂 Promise

Promise 必须为以下三种状态之一&#xff1a;等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。一旦Promise 被 resolve 或 reject&#xff0c;不能再迁移至其他任何状态(即状态 immutable)。基本过程&#xff1a;初始化 Promise 状态(pending)执行 then(..) 注册回调处…

visual studio 判断dropdownlist选的是什么_心理测试:五个小蓝人,你选哪个?测你是不是一个容易追求的人...

下面这张图片里&#xff0c;有五个小蓝人&#xff0c;你觉得自己会是里面的哪一个&#xff1f;A. 站在家里的窗户边B. 站在河边C. 坐在屋顶D. 站在树上E. 骑着鸟飞在空中测试结果选A的你容易追求指数20%。你是一个温柔细腻的人。在别人的眼里&#xff0c;你是一个很贴心的人。在…

java中为何输出框会无限输出,MyBatis启动时控制台无限输出日志的原因及解决办法...

你是否遇到过下面的情况&#xff0c;控制台无限的输出下面的日志&#xff1a;Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl adapter.Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl adapter.Logging initiali…

基于注解SpringAOP,AfterReturning,Before,Around__springboot工程 @Around 简单的使用__SpringBoot:AOP 自定义注解实现日志管理

基于注解SpringAOP&#xff0c;AfterReturning&#xff0c;Before&#xff0c;Around AOP&#xff08;Aspect Oriented Programming&#xff09;&#xff0c;即面向切面编程&#xff08;也叫面向方面编程&#xff0c;面向方法编程&#xff09;。其主要作用是&#xff0c;在不修…

流浪地球开机动画包zip_【文娱热点】流浪地球2定档2023大年初一;迪士尼计划裁员32000人...

剧集、综艺任嘉伦、白鹿《长安如故》开机11月26日&#xff0c;根据小说《一生一世美人骨》古代篇改编的剧集《长安如故》开机&#xff0c;两位主演任嘉伦和白鹿继现代篇《一生一世》之后再演古代篇&#xff0c;俩人穿着棉服、梳着古装发髻现身开机仪式&#xff0c;心情非常好。…