为什么MySQL要用B+树?聊聊B+树与硬盘的前世今生

在上一节,我们聊到数据库为了让我们的查询加速,通过索引方式对数据进行冗余并排序,这样我们在使用时就可以在排好序的数据里进行快速的二分查找,使得查询效率指数提升。但是我在结尾同样提到一个问题,就是内存大小一般是很有限的,不可能把一个表所有的数据都加载到内存中,那么我们该如何解决这个问题呢?在解决这个问题之前,需要先简单了解一下硬盘知识

硬盘知识简介

由于机械硬盘的高耐久,低成本,现在仍然是数据存储的主流,所以这里着重讨论机械硬盘,下面是一个机械硬盘结构图

机械硬盘的数据都存放在盘片中,当我们从硬盘读取数据时,我们需要提供一个地址,然后硬盘通过前后移动磁头寻址,最后把地址对应数据返回。

这里有两个过程很重要,一个是寻址,一个是读取数据。以目前机械硬盘的速度,如果我们要从机械硬盘读取一条1KB的数据大概只需要0.01ms(100MB/s),而寻址却平均在10ms左右。通常我们把读取一段连续的数据,不需要多次寻址的操作叫做顺序读,而读取不连续的数据需要多次寻址的操作叫做随机读,用来区分它们之间的性能差距。

为了充分利用机械硬盘的性能,通常把相关数据连续保存,这样就可以一次加载更多的数据,减少磁头的的移动次数。操作系统有很多对此的优化,例如Linux ext3文件系统默认块大小就是4kb。还有linux预加载能力,即当你频繁访问一块数据时,系统会帮你把相邻的数据也加载进来。

MySQL InnoDB与硬盘

了解完机械硬盘的基本知识,现在回到MySQL,MySQL InnoDB引擎也会把数据进行分块存储,默认是16KB。所以我们上一节中的索引结构图在硬盘中的存储就是每16KB为一个块,当一个块快存放快满的时候开辟一个新的块来存放。

以books表为例

create table books(

id int not null primary key auto_increment,

name varchar(255) not null,

author varchar(255) not null,

created_at datetime not null default current_timestamp,

updated_at datetime not null default current_timestamp on update current_timestamp,

index idx_books_name(name)

)engine=InnoDB;

该表name字段的索引idx_books_name在硬盘中的存放就如下图

当块越来越多的时候,我们可能无法一次把所有的块都加载到内存,此时就要对每个块再进行索引,如下图:

每个块的上一级都存放着一条指向该块首记录的记录。这样只需要加载顶部的第一块,然后通过区间判断就可以找到下一块的地址。

例如我们查询一条name=name n+1的记录,过程如下:

1. 先从左边顶部块a开始查找,发现"name n+1"在"name 1"到"name m"记录之间

2. 加载"name 1"对应的下一级块b

3. 发现"name n+1"在块b第二条记录到第三条记录之间,所以需要加载第二条记录对应的下一级块d

4. 加载块d

5. 在块d中找到"name n+1"的那条记录。

如果把上图旋转一个,可以发现,整个图就是一个树,这其实就是B+树。B+树通过对数据块进行索引,使得当数据量很大,无法一次全部加载到内存时,可以先加载一个表的顶部数据块,然后根据数据所在区间再加载下一级的数据块。这样既保证了我们的快速搜索,又减少了内存使用。

MySQL InnoDB的聚簇索引和二级索引

了解了B+树,现在就可以很容易区分MySQL的聚簇索引和二级索引。

聚簇索引就是用主键生成B+树,在叶子节点存放这条记录的完整信息

二级索引就是用索引行生成B+树,在叶子节点只存放索引行和该行对应的主键信息

下面是聚簇索引和二级索引的区分图

了解上面的知识,对于一个查询,我们就可以大概想象出他的执行步骤

select * from books where name = "name400";

例如上面sql的执行步骤如下:

1. 在二级索引idx_books_name索引中查找name="name400"的字段所对应的主键id

2. 通过主键id在聚簇索引找到此id所对应的记录

3. 返回记录中的所有字段

当我们select的字段在二级索引上不存在时,都需要使用聚簇索引回表查询剩余字段。所以聚簇索引,也就是我们所说的id列,占用空间越小越好, 这样就可以在一个节点中存放更多的id值,减少树的层级,加速查询效率。一般推荐主键使用int或者bigint而不是字符串。同时最好保证插入的id值为递增的,这样就不会造成在一个已经满的节点中插入一条记录造成页分裂,降低查询效率。

小结

这节我们先了解了硬盘的基础知识,知道了机械硬盘的顺序读与随机读的巨大性能差距,以及操作系统为了优化磁盘性能而把数据进行按块存储。然后又学习了MySQL通过使用B+树,把存放索引的多个数据块进行索引,解决了我们上一节使用二分搜索需要先把所有数据都加载到内存的问题。最后,我们了解了聚簇索引和二级索引的区别,以及其中的使用建议。

下一节,我们会聊一聊如何创建一个好的索引,判断一个索引的好坏标准有哪些。

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[为什么MySQL要用B+树?聊聊B+树与硬盘的前世今生【宇哥带你玩转MySQL 索引篇(二)】]http://www.zyiz.net/tech/detail-126089.html

mysql为什么用b加树_为什么MySQL要用B+树?聊聊B+树与硬盘的前世今生【宇哥带你玩转MySQL 索引篇(二)】...相关推荐

  1. mysql 如何添加索引_MySQL如何创建一个好索引?创建索引的5条建议【宇哥带你玩转MySQL 索引篇(三)】...

    MySQL如何创建一个好索引?创建索引的5条建议 过滤效率高的放前面 对于一个多列索引,它的存储顺序是先按第一列进行比较,然后是第二列,第三列...这样.查询时,如果第一列能够排除的越多,那么后面列需 ...

  2. 六天带你玩转Mysql笔记--第五天

    六天带你玩转Mysql笔记--第五天 1.外键 1.1增加外键 1.2修改外键&删除外键 1.3外键作用 1.4外键条件 1.5外键约束 2联合查询 2.1基本语法 2.2意义 2.3 ord ...

  3. java 实现部门树_(java实现)哈夫曼(Huffman)树编码(自编压缩项目基础)

    哈夫曼树 给定 n 个权值作为 n 个叶子结点,构造一棵二叉树, 若该树的带权路径长度(wpl) 达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree), 也叫霍夫曼树. 哈 ...

  4. axure8 事件改变样式_【Petrel老师带你玩转Axure 8(二)】Axure部件样式与页面样式管理...

    原标题:[Petrel老师带你玩转Axure 8(二)]Axure部件样式与页面样式管理 作者:Petrel(UXRen社区Axure金牌讲师,资深交互设计师) 本文长度为1300字,建议阅读4分钟 ...

  5. mysql驱动为什么自动加载_为什么JDBC中加载驱动要使用反射?

    原文链接:https://www.cnblogs.com/homejim/p/8076481.html 在JDBC详解系列(一)之流程中,我将数据库的连接分解成了六个步骤. JDBC流程: 第一步:加 ...

  6. mysql 字段钳口可加引号_根据处理对象划分,计算机可以分为模拟计算机、(

    [判断题]( )3.保证数控机床各运动部件间的良好润滑就能提高机床寿命. [单选题]在储位编码中,把一些相关性货品经过集合以后,区分成几个品项群,再对其进行编码的方法是( ). [填空题]在数据库技术 ...

  7. 极客学院mysql教程_干货分享 速成必备视频 六天带你玩转MySQL视频教程 数据库......

    ├─mysql第一天 │  └─video4 p7 v* M+ D& s │          01数据库课程介绍.mp4 │          02数据库(基础知识).mp45 X# y2 ...

  8. 5天玩转mysql视频教程_六天带你玩转MySQL

    教程列表: 01数据库课程介绍 02数据库(基础知识) 03数据库(关系型数据库) 04数据库(关系型数据库关键字说明) 05数据库(SQL) 06数据库(mysql数据库) 07数据库(mysql服 ...

  9. 质量属性效用树_知识之森-数据化你的quot;知识树”

    "知识之森"原始体系 "知识之森",源于对于知识模型焦虑的我,某天在兰陵王的知乎号 @思维有了模型 ,看到的一篇关于"知识树"的文章--知识 ...

最新文章

  1. 计算机史最疯狂一幕:豪赌50亿美元,“蓝色巨人”奋身一跃
  2. ElasticSearch,Sphinx,Lucene,Solr,Xapian。哪种适合哪种用途? [关闭]
  3. SD-WAN为企业业务出海提供网络保障
  4. 北京交通大学2018计算机硕士录取公示,2017年北京交通大学研究生录取名单!!!...
  5. 学完Python后可以做哪些工作呢?
  6. android数据库给单选赋值,如何使用android studio将单选按钮的值保存到mysql数据库?...
  7. 浏览器执行机制探究,图解最直观
  8. java代码逆向工程生成uml
  9. java.nio异步线程安全的IO
  10. cad2008安装教程_品茗BIM、平面图软件安装教程
  11. lptwrite matlab,matlab读取地震数据sgy
  12. 83行代码通关攻略|据说看的人都过了
  13. php一元二次方程求根,JavaScript_在线一元二次方程计算器实例(方程计算器在线计算),复制代码 代码如下:htmll - phpStudy...
  14. JavaScript 生成弹性透明的图片放大代码
  15. 实战ssl-bump,实现squid的url过滤功能
  16. 既可加边也可删边的动态最小生成树
  17. 好用的音视频剪辑软件综述
  18. UI行业就业前景怎样 如何成为合格的UI设计师
  19. 解决:控制台使用nvm控制node版本时出现exit status 1与exit status 145
  20. 抖音链接被封杀?一行代码实现网页直接跳转抖音

热门文章

  1. WIN10开始菜单怎么点都没有反应
  2. ArcGIS Runtime SDK for iOS 开发之地图范围(map extent)
  3. 4.34、组播(多播)
  4. poj2947(高斯消元解同模方程组)
  5. listview嵌套listview,子listview只显示一个item问题
  6. Z-Score模型的进阶版:Zeta模型
  7. C++——素数(质数)专题训练2
  8. DC算法竞赛——北京PM2.5浓度回归分析
  9. 运维 03 Linux之文档与目录结构
  10. Vue中使用andt组件a-table列表数据根据点击的表头进行升/降排序-案例