彻底搞懂MySql的B+Tree

news2024/11/24 9:32:59

1.什么是索引

官方定义:一种能为mysql提高查询效率的数据结构,索引是为了加速对表中数据行的检索而创建的一种分散存储的数据结构。好比如,一本书,你想找到自己想看的章节内容,直接查询目录就行。这里的目录就类似索引的意思。

1.1索引的工作原理

 

如上图中,如果现在有一条sql语句 select * from user where id = 40,如果没有索引的条件下,我们要找到这条记录,我们就需要在数据中进行全表扫描,匹配id = 40的数据。

如果有了索引,我们就可以通过索引进行快速查找,如上图中,可以先在索引中通过id = 40进行二分查找,再根据定位到的地址取出对应的行数据。

现在看来,索引是不是也不过如此。咋们接着往下看。

索引的优点:
1.大大加快数据的查询速度。
索引的缺点:
1.维护索引需要耗费数据库资源。
2.索引需要占用磁盘空间
3.当对表的数据增删改的时候,因为要维护索引,速度会受到影响。</pre>

那么有的同学可能会问,既然索引缺点这么多,那我为什么还要用索引啊?也就是提高了查询速度而已。

提高了查询速度呀,这个绝对是个大优势,在数据量庞大的情况下,我们通过命中索引,能大大的提高查询速度,增删改基本消耗忽略不计。摘抄阿里P3C开发规范。

 

2.索引的分类

1.主键索引
设定为主键后,数据库会自动为其创建主键索引,innodb为聚簇索引。
2.普通索引:用表中的普通列构建的索引,没有任何限制,用于加速查询。
3.组合索引:用多个列组合构建的索引,这多个列中的值不允许有空值。
4.全文索引(mysql5.7之前,由MyISAM提供):用大文本对象的列构建的索引,主要用来查找文件中的关键字。

3.B+Tree

我们先来看一个sql

image

执行完后:

 

奇怪?为什么数据和我插入的顺序不一致呢,竟然给我自动排序好了!!!我们接着看

其实mysql每条数据的存储是这样子的(图自己画的,—_—,将就下)

 

每次插入数据的时候,mysql会给我们自己排序好,因为这样可以快速的查询数据。并且会通过P的指针链接到下一条数据。这里看起来是不是像某种数据结构?链表的数据结构,对了,就是这样。
疑问点???
我们都知道链表查询数据的时间复杂度为On,那么当数据量一多的话,我要查的id特别大呢,这和全表扫描有什么区别呢?接着往下看。

mysql给我们提供了页的概念,并且有页目录,页目录数据为叶族节点每页的第一条数据id,页目录和每页大小均默认为16KB,如下图:

 

举个例子:

那么这个时候假如我想要查询id 为2的这条数据,在页目录中,2在1~4之间,直接去到第一页,查询第一页第一条数据为1,因为有指针P的存在,那么就可以顺着指针往下找即可。即找到了2。此时呢只进行了一次IO操作。现在想想看,是不是查询速度快很多。P指针的概念也很强大,是不是。

那么有的小伙伴可能会问,你这样也存不了多少数据呀,那假如我数据量非常多呢,这颗数怎么存呢。
以上表而言,一个id占用8个字节(long类型),name 20个字节,p指针也要占用字节的(大概4~8个字节),我们以最大8来算,那么一条数据大概就是:8+20+8=36,36个字节,那么一页换算一下是 16x1024 = 16384 个字节,那么叶子节点一页可以存储数据量为:16384/36 = 455 条数据。那么页目录又存着id,一个id8个字节,能存储16x1024/8 =2048,2048x455 = 931,840 …粗略的算了下3层数,能存储数据量为1,908,408,320个 很多了,可能表的字段很多的话,存储数据量稍微少点,但是也很多了。

3.对比B-Tree

 

可以看到b-Tree上的每个节点都存储了数据,那么,我们刚刚说了,mysql一页的大小为16KB,那么这样的话,一页能存储的数据就很少了,因为数据要占用每页的字节呀。这样树的深度可能就深了。我们知道mysql每次读取数据时会进行一次IO操作,那么深度越深,IO的次数不是会越多。说白了优化优化,大多数都是在IO层做优化的。那么对比B+Tree,数据只存在叶子节点上,树的深度就不是那么深了(一般企业级不会超过3层深度)

B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。

我们来总结下B+Tree和B-Tree的区别

1.B+Tree非叶子结点只存储键值信息。
2.B+Tree所有叶子节点都有一个指针(上面说到了指针的用途)。
3.B+Tree数据都存储在叶子节点上,B-Tree节点上都存储数据。
 innoDB存储引擎页大小为16KB,一般主键类型为INT(占用4个字节)或BIGINT(占用8个字节)。

这个时候有个问题思考下?为什么mysql推荐ID自增呢?这个时候是不是心里有了答案呢?或许自己可以先想想再看。

在InnoDB的实践里面

其中一个建议是按主键的自增顺序插入记 录,就是为了避免Page Split问题。比如一个Page里依次装入了Key为(1,3,5,9)四条记录,并且假设这个Page满了。接下来如果插入一个 Key =4的记录,就不得不建一个新的Page,同时把(1,3,5,9)分成两半,前一半(1,3,4)还在旧的Page中,后一半(5,9)拷贝到新的Page 里,并且要调整Page前后的双向链表的指针关系,这显然会影响插入速 度。但如果插入的是Key = 10的记录,就不需要做Page Split,只需要建 一个新的Page,把Key = 10的记录放进去,然后让整个链表的最后一个 Page指向这个新的Page即可。
另外一个点,如果只是插入而不硬删除记录(只是软删除),也会 避免某个Page的记录数减少进而发生相邻的Page合并的问题。

3.聚簇索引和非聚簇索引

聚簇索引:将数据与索引放到了一块,索引的叶子节点保存了行数据。
非聚簇索引:将数据分开存储,索引结构的叶子节点指向了数据对应的位置。
总结:InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分;

 

我们日常工作中,根据实际情况自行添加的索引都是辅助索引,辅助索引就是一个为了需找主键索引的二级索引,现在找到主键索引再通过主键索引找数据;(这就是所谓的回表查询)

聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分,每张表只能拥有一个聚簇索引。

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。具体细节依赖于其实现方式。

聚簇索引的优缺点

优点:

1.数据访问更快,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快

2.聚簇索引对于主键的排序查找和范围查找速度非常快   缺点:

1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键     2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。    3.二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。

辅助索引(非聚簇索引)

聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。通过辅助索引首先找到的是主键值,再通过主键值找到数据行的数据页,再通过数据页中的Page Directory找到数据行。

总之,其实说白了也就是,我们平常定义的索引就是辅助索引,平常通过普通索引查询数据时,先通过辅助索引查询到主键索引,再通过主键索引查询到具体的数据。

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

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

相关文章

华为路由器升级系统文件

欢迎关注微信公众号【厦门微思网络】。http://www.xmws.cn 组网图形 组网需求 RouterA的管理网口与用户侧主机HostA相连。要求通过BootROM菜单下载系统文件至RouterA完成系统升级。 操作步骤 1.在PC端启动FTP Server服务。 2.用串口线连接并通过Console口登录设备。 3.重启设…

Java内存模型与线程(3)

文章目录4. Java与线程4.1 线程的实现4.2 Java线程调度4.3 状态转换4. Java与线程 并发不一定要依赖多线程&#xff08;如PHP中很常见的多进程并发&#xff09;&#xff0c;但是在Jva里面谈论并发&#xff0c;大多数都与线程脱不开关系。既然我们这本书探讨的话题是Java虚拟机…

一个系列涨粉47w,小红书内容创意卷出新高度

前有双11&#xff0c;后有世界杯&#xff0c;11月注定是热闹的。图源新红_流量分析_趋势查询在此情况下&#xff0c; 小红书内又涌现出哪些黑马博主&#xff1f;有多少品牌打造出了爆品&#xff1f;什么样的种草玩法才能成功出圈&#xff1f;我们将全面分析11月榜单&#xff0c…

java面向对象最全入门笔记

Java面向对象 什么是面向对象编程&#xff1f; 面向&#xff1a;找、拿。 对象&#xff1a;东西。 面向对象编程&#xff1a;找或者拿东西过来编程。 设计对象并使用 设计类&#xff0c;创建对象并使用 类是什么&#xff1f; 类&#xff08;设计图&#xff09;&#xff1…

Vue Cli安装和node-sass、less-loader、sass-loader安装

一、Vue Cli安装 CLI全程是Command-Line Interface&#xff0c;命令行界面&#xff0c;俗称脚手架&#xff0c;可以帮我们快速的创建vue项 Vue Cli的使用必须依赖node环境和webpack 管理员方式打开cmd进行安装&#xff0c;安装命令&#xff1a; npm i -g vue/cli 查看版本…

鸢尾花数据种类预测、分析与处理、scikit-learn数据集使用、seaborn作图及数据集的划分

一、鸢尾花种类预测 Iris数据集是常用的分类实验数据集&#xff0c;由Fisher, 1936收集整理&#xff0c;Iris也称鸢尾花卉数据集&#xff0c;是一类多重变量分析的数据集 鸢尾花数据集包含了 4个属性&#xff08;特征值&#xff09; Sepal.Length&#xff08;花萼长度&#…

Linux学习-69-Linux系统启动管理

16 Linux系统启动管理 Linux 系统的启动是不需要人为参与和控制的&#xff0c;只要选择开机&#xff0c;系统就会按照设定好的方式进行启动。不过&#xff0c;了解系统的启动有助于我们在系统出现问题时能够快速地修复 Linux 系统。在 CentOS 6.x 中&#xff0c;系统的启动过程…

NoSQLBooster for MongoDB 7.1.X

最智能的 MongoDB IDE NoSQLBooster 是 MongoDB v2.6-6.0 的跨平台 GUI 工具&#xff0c;它提供了内置的 MongoDB 脚本调试器MongoDB 脚本调试器、全面的服务器监控工具、链接流畅查询、SQL 查询、查询代码生成器、任务调度、ES2020 支持和高级智能感知体验。 嵌入式 MongoDB 外…

网络面试-0x17如何立即诶OSI模型和TCP/IP协议

OSI(Open System Interconnect) 开放式通信系统互连参考模型。 每一层实现各自的功能和协议&#xff0c;并完成与相邻层的接口通信。即每一层扮演固定的角色&#xff0c;互不打扰。 应用层 ⑦ 作用&#xff1a;通过应用程序间的交互来完成特定的网络应用。 定义了应用程序之间…

【ONE·R || R与C++混合编程简单介绍 】

总言 课堂演讲&#xff1a;R语言与CPP混合编程课后学习汇报。    文章目录总言1、汇报目的&#xff12;、RCPP2.1、简单介绍&#xff1a;2.2、简单使用演示&#xff1a;2.1.1、Rcpp包与RTools2.2.2、上手尝试1.0&#xff1a;一个hello world小程序。2.2.3、上手尝试2.0&#…

STC 51单片机57——矩阵键盘 基本原理演示

51单片机 矩阵键盘 基本原理演示 #include "reg51.h" sbit P11P1^1; sbit P14P1^4; sbit P20P2^0; sbit P21P2^1; void main(void) { P111;// Hight P140; //Low if(P111) P200; else P210; while(1); }

刷爆力扣之较大分组的位置

刷爆力扣之较大分组的位置 HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 工作原因拖更些时日&#xff0c;今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照…

Java项目:SSM农业信息管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 管理员角色包含以下功能&#xff1a; 管理员登陆,用户管理,新闻管理,留言列表查看等功能。 用户角色包含以下功能&#xff1a; 查看所有新闻,市…

免费分享20套微信小程序源码 源码免费下载【强烈推荐】

淘源码&#xff1a;国内知名的源码免费下载平台 微信小程序源码包括&#xff1a;商城系统、点餐外卖、垃圾分类、预约洗车、物业管理、校园跑腿、驾考学习、会议预约、图书管理、智能停车、在线答题等小程序源码。 源码分享&#xff0c;文末获取源码&#xff01; 1、JAVA微信…

微信API接口、微信二次开发API调用

微信API接口、微信二次开发API调用 微信协议接口调用-加微信好友及通过好友请求 加微信好友 /** * 微信自动添加好友 * author wechatno:tangjinjinwx * blog http://www.wlkankan.cn */ Async public void handleMsg(ChannelHandlerContext c…

代码随线录刷题|LeetCode 392.判断子序列 115.不同的子序列

目录 392.判断子序列 思路 1、确定dp数组 2、确定递推公式 3、初始化dp数组 4、遍历顺序 判断子序列 动态规划 双指针 115.不同的子序列 思路 1、确定dp数组 2、确定递推公式 3、初始化dp数组 4、遍历顺序 不同的子序列 392.判断子序列 题目链接&#xff1a;力扣 思路 比较简单…

【Exception】 Java Lambda List转换Map报错 触发异常 IllegalStateException: Duplicate key

【Exception】 Java Lambda List转换Map报错 触发异常 IllegalStateException: Duplicate key 一、问题描述 在使用Java8 lambda 将List转换为Map时&#xff0c;遇到报错&#xff1a;IllegalStateException- Duplicate key .... 具体报错信息如下&#xff1a; java.lang.Illega…

基于Dockerfile创建镜像

目录 一、Docker镜像的创建 1 基于现有镜像创建 2 基于本地模板创建 3 基于Dockerfile 创建 3.1 联合文件系统(UnionFS ) 3.2 镜像加载原理 二、Dockerfile 操作命令的指令 1 FROM 镜像 2 MAINTAINER 名字 3 RUN 命令 4 ENTRYPOINT 5 CMD ENTRYPOINT和CMD的区别&…

HTML网页设计【足球科普】学生DW静态网页设计

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

【openWrt】设置执行定时任务

遇到一个问题&#xff0c;使用openWrt软路由搭建服务器&#xff0c;在docker装了一个maccmsV10&#xff0c;需要每天执行cj信息定时任务&#xff0c;但是maccmsV10本身不支持执行定时任务的配置的。 看了下&#xff0c;openWrt是支持本身是linux系统&#xff0c;所以是可以设…