看了还不懂b+tree的本质就来打我
看了还不懂b+tree的本质就来打我
大家好,我是蓝胖子。
今天我们来看看b+tree这种数据结构,我们知道数据库的索引就是由b+tree实现,那么这种结构究竟为什么适合磁盘呢,它又有哪些缺点呢?
我将不会对b+tree的一些定义做过多的讲解,因为这些东西网上一大推,关键还是要抓住本质,想想为什么b+tree这么设计 ?
b+tree,磁盘,文件系统之间的关系
要想理解b+tree的本质,一定要理解如何在磁盘上高效的存取数据。先看下磁盘是如何读取数据的。
来看下磁盘的结构图。
这是磁盘的一个柱面,读数据的时候,就是磁头来回左右的移动。柱面中一圈圈的叫做磁道,每个磁道都被切分为一个个扇区,磁盘读取的单位就是一个扇区一个扇区的读取。而如果要读取的数据在不同的磁道,就需要磁头前后移动到达指定磁道后再移动到特定扇区进行读取,而磁道的变换就是磁盘读取最耗时的过程。
所以对于磁盘怎样加速读取呢?
终极目的要尽量减少存取时不同磁道间的切换,如何减少切换开销?也很简单,往磁盘写入数据时尽可能在同一个磁道上写,从读取读取数据时,也保证尽可能在同一个磁道上读。
但平时我们并不直接操作磁盘,而是通过文件系统往磁盘上写入和读取数据,文件系统每次读取是按块为单位,一个块往往是多个连续的扇区构成。注意连续的扇区是为了减少磁道切换的开销。
从磁盘上找文件需要找到文件inode数据块,再从inode数据块中找到文件具体的数据块置,可以简单把一个文件理解为一个个文件块构成的,如图每个块都有自己的编号,这里的编号是连续的,实际上,分配的文件块编号也可以不连续。
那么文件系统和b+tree的关系是什么呢?
数据库也是通过文件系统去读取磁盘上的数据的,而数据库中读取数据的单位是一页,不过这个一页数据大小是文件块的整数倍(例如mysql数据页是16kb,而一般操作系统是4kb)。并且数据库实现索引时,会让b+tree中一个节点的大小刚好占用一页数据的大小。
这里其实又会产生一个疑问?如果大小是文件块的整数倍,那么一个btree节点的所占的空间也就是数据库一个数据页所占的空间 在磁盘上一定是连续的吗,答案为 近乎是连续的,因为文件系统在一次性分配文件块时,为了提升文件系统的性能,即减少磁道的变化,会倾向于连续分配。
比如我们告诉操作系统,往一个文件里写入16kb的数据,那么操作系统为文件分配的这16kb的数据会倾向于由4个连续的文件块构成。
这里还需要特别注意的是,比如文件块1,2,3,4 四个文件块 组成b+tree的根节点,那么b+tree的子节点一定是图中的文件块5,6,7,8组成的吗?
实际上也不是 ,因为随着b+tree节点的删除,分裂等操作,由1,2,3,4文件块组成的根节点 指向的子节点位置可能已经变成了其他连续的文件块组成的节点了,它们之间是逻辑上的相邻,在物理磁盘上并不相邻。
举个例子:
为了简单起见,我还是假设数据库在实现的时候,将一个b+tree的节点大小和文件块大小设计为相等。
比如文件块1的节点的左孩子指向了文件块2的节点,如果文件块2的节点中的数据被全部删除了,那么文件块2整个空间就会被标记为删除状态。而文件块1的节点的左孩子指针将会指向其他的文件块,空出来的文件块2的空间则会被新的节点拿来存放数据。可以看到,父子节点之间,只是通过指针联系在了一起,而父子节点可能处于相隔很远的文件块上。
理解了b+tree节点和文件块和磁盘扇区三者关系后,我们再来实际看看b+tree的写入过程,同时便能理解为什么b+tree的写入性能不高了。
b+tree的写入过程
真实数据库的b+tree一个节点能容纳上千个key,为了简单的演示下b+tree的写入过程,这里我会用一个最简单的b+tree来做演示。最简单的b+tree实际上是一颗2-3树。
它具有的特性是每个节点最多能容纳两个元素,孩子节点最多是3个。注意b+tree的插入都是往叶子节点插入。
拿最后一个插入元素4举例,首先得从整颗b+tree中找到4应该插入的节点位置,读取节点内容后,发现 最后一个叶子节点如果加上元素4,将会破坏2-3树的性质,所以又会产生节点的分裂,其父节点的内容也会发生变化。
由于b+tree各个节点之间在物理磁盘上可能已经跨越了不同的磁道了, 所以无论从插入时必须 首先得找到节点这个过程来看,还是分裂时会改变父节点这个过程来看,这样的过程都可以认为是随机读写磁盘的行为,都可能跨越多个磁道。而跨越多个磁道的操作,是磁盘最耗时的操作,这样的插入性能当然不高。
后续我也会介绍另一种构建索引的数据结构LSM(日志结构合并树),有别与b+tree,它具有很好的写入性能。
看了还不懂b+tree的本质就来打我的更多相关文章
- 深度分析:面试阿里,字节跳动,美团90%被问到的List集合,看完还不懂算我输
1 List集合 1.1 List概述 在Collection中,List集合是有序的,可对其中每个元素的插入位置进行精确地控制,可以通过索引来访问元素,遍历元素. 在List集合中,我们常用到Arr ...
- 详细!Mybatis-plus常用API全套教程,我就不信你看完还不懂!
前言 官网:Mybatis-plus官方文档 简化 MyBatis ! 创建数据库 数据库名为mybatis_plus 创建表 创建user表 DROP TABLE IF EXISTS user; C ...
- webpack代码分离 ensure 看了还不懂,你打我(转)
webpack异步加载的原理 webpack ensure相信大家都听过.有人称它为异步加载,也有人说做代码切割,那这 个家伙到底是用来干嘛的?其实说白了,它就是把js模块给独立导出一个.js文件的, ...
- 看完此文还不懂NB-IoT,你就过来掐死我吧...【转】
转自:https://www.cnblogs.com/pangguoming/p/9755916.html 看完此文还不懂NB-IoT,你就过来掐死我吧....... 1 1G-2G-3G-4G-5G ...
- 看完此文还不懂NB-IoT,你就过来掐死我吧...
看完此文还不懂NB-IoT,你就过来掐死我吧....... 1 1G-2G-3G-4G-5G 不解释,看图,看看NB-IoT在哪里? 2 NB-IoT标准化历程 3GPP NB-IoT的标准化始于20 ...
- Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!
本文原题“从实践角度重新理解BIO和NIO”,原文由Object分享,为了更好的内容表现力,收录时有改动. 1.引言 这段时间自己在看一些Java中BIO和NIO之类的东西,也看了很多博客,发现各种关 ...
- 盘点国内程序员不常用的热门iOS第三方库:看完,还敢自称”精通iOS开发”吗?【转载】
综合github上各个项目的关注度与具体使用情况,涵盖功能,UI,数据库,自动化测试,编程工具等类型,看完,还敢自称”精通iOS开发”吗? https://github.com/syedhali/EZ ...
- 我看谁还说程序员不会P图?拜托~4行python代码就够~
我们平时使用一些图像处理软件时,经常会看到其对图像的亮度.对比度.色度或者锐度进行调整.你是不是觉得这种技术的底层实现很高大上? 其实最基础的实现原理,用 Python 实现只需要几行代码,学会后你也 ...
- 一篇文章看懂JS闭包,都要2020年了,你怎么能还不懂闭包?
壹 ❀ 引 我觉得每一位JavaScript工作者都无法避免与闭包打交道,就算在实际开发中不使用但面试中被问及也是常态了.就我而言对于闭包的理解仅止步于一些概念,看到相关代码我知道这是个闭包,但闭包 ...
- 看完这篇还不懂Redis的RDB持久化,你们来打我!
一.为什么需要持久化 redis里有10gb数据,突然停电或者意外宕机了,再启动的时候10gb都没了?!所以需要持久化,宕机后再通过持久化文件将数据恢复. 二.优缺点 1.rdb文件 rdb文件都是二 ...
随机推荐
- How to Check and Repair EXT4 Filesystem in Linux
The fsck (stands for File System Consistency Check) is used to check and repair one or more Linux fi ...
- Spring学习记事本
原因:原因:Application的启动类不能放在默认的java目录,必须放在建有包的目录下.
- HTML复习(17.表格样式)
重点 掌握caption-side(表格标题位置) 掌握border-collapse(表格边框合并) 掌握border-spacing(表格边框间距) 表格标题位置在CSS中,我们可以使用capti ...
- 06 显示fps帧频
需要看fps就用下面这段代码即可 var FPS = {};FPS.time = 0;FPS.FPS = 0; FPS.startFPS = function (stage){ FPS.shape = ...
- javaweb链接到数据库(mysql)操作
准备:配置好数据库,下好mysql connect 第一步:将my connec文件和commons-dbutil(,jar)复制到webapp文件下WEB-INF的lib文件中,然后右键构建路径. ...
- opencv3 7.3 重映射 仿射变换
重映射的概念 将一幅图像某位置的像素放置到另外一幅图像的指定位置上,需要对非整数像素坐标重映射来表达每个像素的新位置. g(x,y)=f(h(x,y)); 实现重映射 remap()函数 dst(x, ...
- 用js获取当前路由信息的方法
1,设置或获取对象指定的文件名或路径.alert(window.location.pathname)2,设置或获取整个 URL 为字符串.alert(window.location.href);3,设 ...
- uniapp中使用echarts关系图
首先看一下页面效果: <template> <view class="page"> <!-- 导航栏 --> <b-nav-bar cla ...
- Java开发的事务
代码来自https://blog.csdn.net/weixin_42950079/article/details/99674292 可以看出jdbc的一个事务有这么几个步骤:1.关闭sql自动提交: ...
- Linux用户管理2
passwd给用户修改密码 用户自己给自己设置密码直接passwd root用户给普通用户设置密码passwd 用户名 --stdin从标准输入获取信息 echo "1" | pa ...