数据库性能系列之索引(中)

GOOD NIGHT

前言

上一篇中,我们已经了解到了索引的基本概念和一些用法。那索引为什么会提升查询的速度,以及索引究竟是怎么工作的呢?也许大家心里还是有一些迷茫,这一切,还要从索引背后的算法说起。

GOOD NIGHT

概述

大家知道数据库的索引和数据,一般都是存储在硬盘中的,这样利于数据的持久化和永久保存。因此在我们查找数据的时候,就会产生硬盘的I/O操作。而硬盘相较于内存而言,速度是比较慢的,所以如何减少硬盘的I/O操作,就是索引背后的算法存在的意义。

GOOD NIGHT

二分法

二分法是一种常用的查找算法,相较于逐个遍历查找而言,二分法的时间复杂度为O(log2n)。为了帮助大家理解和回忆二分查找,我画了一张二分查找的流程图:

4348dadf73dd83418df1f5a6cd8ca8d1.png

从上述流程来看,我们要事先对要查找的数组或集合进行排序,而且每次会寻找中间节点进行范围的划分和对数字的比较。那么我们能不能把这个过程进行简化呢?二叉搜索树(Binary Search Tree)会给你答案。

GOOD NIGHT

二叉搜索树

如上文所述,二叉搜索树的特征是有序,且预先把数据进行分段存储,并且将中间节点作为树的根节点,那么我们会得到如下的二叉树结构,这里以数组[7,25,36,50,64,78,87]为例,创建出来的二叉树如下所示:

fe10da540d43b57d9918fd47496de697.png

我们可以看出一些特征:对于每个节点而言,它的左孩子都小于它的父节点,而右孩子,都大于它的父节点。所以我们把这样的二叉树,叫做二叉搜索树(Binary Search Tree)。

二叉搜索树,重复利用了二分法的思想来查找数据,但有时由于构造树时产生问题,导致同样的数据插入顺序不一样,二叉搜索树就会变成如下结构:

e4b625f70f1a117bd549c4a2e99077ae.png

从两张图的比较中我们不难看出,图一的树高度为3,也就是最多只需要3次比较,就能找出节点,而图二的树的结构会变成线性,需要7次比较,查找时的复杂度也会瞬间提升为O(n)。

所以为了解决二叉树不平衡的问题,人们又提出了新的数据结构,叫做平衡二叉搜索树(AVL树)

GOOD NIGHT

平衡二叉搜索树

刚才我们提出了,要解决二叉树的不平衡问题,就需要一个可以在每次插入或者删除节点时,都可以做到自动平衡的二叉树结构,也叫平衡二叉搜索树。

平衡二叉搜索树的核心思想就是计算每个节点的平衡因子(balance factor),平衡因子的定义是一个节点的左孩子的高度减去其右孩子的高度,这里的高度(height)就是指从一个节点出发到达最远叶子节点所经过的最长路径。如我们上述的图一中,从根节点50,到达子节点36的高度即为2。

通过上面的概念,我们可以发现,当一个节点的平衡因子绝对值大于等于1时,树就不再平衡,所以这里平衡二叉树还包含了一个旋转的机制,在此不表,感兴趣的同学可以自行查找进行理解。

那么我们在讲了这么多之后,平衡二叉搜索树是不是就可以作为索引背后的数据结构来进行存储了呢?这里再使用一张图来直观说明一下:

6f616a343ce6fb9641687539ed763a39.png

我们前文提到了查找数据是走了硬盘的I/O操作,那么对于这棵二叉树来说,树的高度为5,最坏的情况下,需要查找5次。这就意味着,如果树的高度越高,那么硬盘的I/O次数也会越多。

所以我们有没有办法去降低树的高度呢?可以遵循这样的思路去思考,如果一个节点下不止2个子节点,而是多个,那么整体的高度就可以降低。比如我们将二叉树,改为三叉树:

c748407dabf96980caf2a64496c35d52.png

这个时候,同样的节点数量,我们的树高度则降为了4,也就是说,最多需要4次I/O即可找到需要查找的内容。

所以我们可以将二叉树改为M叉树(M>2),即一个节点下有M个子节点,这样当数据量大小为N时,M叉树的高度将会远远小于二叉树的高度,这样就引申出了B树的概念。

GOOD NIGHT

什么是B树?

B树的英文全名为Banlance Tree,翻译过来为平衡多路搜索树,我们从上文中已知,当一个节点有多个子节点时,高度会下降,因此B树很适合用于查询,在文件系统和数据库系统中的索引,常常会使用B树来实现。在这里有一个概念纠正下,有些书中或博客会提到B-树,而实际上B-树和B树是同一种结构,只是翻译名称上存在一些误解。

B树的结构如图所示:

6dd3b154f109253060323cccb36871e4.png

B 树作为平衡的多路搜索树,它的每一个节点最多可以包括 M 个子节点,M 称为 B 树的阶。每个节点中,都存储了关键字和子节点的指针。对于一个 100 阶的 B 树来说,如果有 3 层的话最多可以存储约 100*100* 100=100 万的索引数据。

B树的特性有以下几点:

1、所有节点关键字是按递增次序排列,并遵循左小右大原则。

2、树中的每个节点至多有M个子节点,即至多有M-1个关键字(二叉树有2个子节点和1个关键字)。

3、除根节点外,其他节点至少有M/2个子节点。

4、若根节点不是叶子节点,则根节点至少有2个子节点。

5、所有叶子节点均在同一层,所以B树是一个所有平衡因子均为0的多路查找树。

以上图为例,根节点中有2个关键字:17和35,以及3个子节点指针:P1、P2和P3。而且在第二层最左侧的子节点中,有2个关键字8和12,包含了3个子节点。子节点1中的关键字为3和5,都小于8,而子节点2中的关键字为9和10,大于8小于12,子节点3中的关键字为13和15,均大于12,都符合我们上述提到的特性。

如果我们使用B树进行查找关键字9,那么可以分为以下几步:

1、先与根节点进行比较,9小于17,那么我们可以得到指针P1,继续从子节点中进行查找;

2、在子节点中,9大于8而小于12,此时可以得到指针P2,继续往下查找;

3、在最后一层的子节点中,找出关键字9,结束查找。

可以看出,相较于平衡二叉树而言,B树查找时的磁盘I/O要少,整体查询效率也要高出很多。看到这里相信大家已经大致明白了索引背后的工作原理,B树已经很适合作为索引的算法。但实际上,在MySQL中,还会使用B+树索引,这又是为什么呢?

GOOD NIGHT

B+树的改进

相较于B树而言,B+树在两个方面又做出了改进和提升,一方面是查询的稳定性,另一方面是查询的效率更高。

B+树的结构如下图所示:

b41f0ebeaca20f4cad8b3e13e17c437f.png

与B树相比,B+树的非叶子节点不保存具体的数据,而只保存关键字的索引,所有的数据都会保存至叶子节点。因为所有数据必须要到叶子节点才能获取到,所以每次数据查询的次数都一样,这样一来B+树的查询速度也就会比较稳定。

在B+树中,非叶子节点的子节点数=关键字数,如上图所示,根节点有2个关键字,对于的也有2个子节点。这样的好处是一个节点可以存储更多的关键字,阶数会更大,高度会更低,查询效率也就更高。

B+树查找关键字的方式与B树类似,先从关键字中找出范围和指针,然后找到对应的子节点,一级一级往下查询,直到最终的叶子节点查出所需要的数据。

由于B+树的数据都存储在叶子节点,所以更有利于数据库做全表扫描,不需要像B树一样逐层扫描,而是直接遍历所有的叶子节点即可。

GOOD NIGHT

总结

今天我们从最基本的二分查找开始,逐步分析了各种查找树的工作原理和优缺点,不断改进,从而挖掘出最终的B树和B+树算法,深刻理解了索引背后的工作原理。虽然传统的二叉树查询的效率也很高,但是很容易增加磁盘I/O的次数,影响索引使用的效率,所以我们最终会采用降低树高度的方式来构造索引。

在实际工作中,我们使用索引也许不会直接去编写B树和B+树的算法。但是学习这些算法,会有助于我们增强逻辑思考的能力,还可以提升一些设计方面的能力,对于“修炼内功”会很有帮助,希望大家可以在这条路上持之以恒。

下一期将是索引系列的最终篇章,我们会结合实际工作中的复杂SQL场景,合理使用索引和改写原有语句以避免全表扫描来对数据库进行优化,敬请期待!

47002dcda9476a3d3e64ce019ef5ed69.png

您的点赞和在看是我创作的最大动力,感谢支持

b19aeaa59133bbf240d9f6bc99eb2316.jpeg

7d37dac3b57346cfbf66e81f2e984ec7.png

8dd831b914580f994e6a3cd82075d9f9.png

公众号:wacky的碎碎念

知乎:wacky

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

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

相关文章

微服务架构的设计原则和核心话题

目录 一、前言 二、微服务架构的设计原则 1.拆分足够微 2.轻量级通信 3.单一职责原则 4.领域驱动原则 三、微服务架构的核心话题 1.服务拆分 2.服务注册与发现 3.负载均衡 4.API网关 5.服务部署与发布 四、总结 一、前言 毫无疑问,微服务架构的设计原…

Golang GOPATH 包

2019独角兽企业重金招聘Python工程师标准>>> Golang GOPATH & 包的定义 & 包的导入 GOPATH 设置 go 命令依赖一个重要的环境变量:$GOPATH 可以在 .zshrc 配置文件中加上一行这样的配置, export GOPATH/Users/flyme/mygo Go从1.1版本到…

PPK大疆无人机应用教程

文章目录 一、新建项目二、导入数据三、解算过程四、结果导出一、新建项目 新建工程,设置项目名称,保存位置,控制等级,坐标系统(坐标系统选择高斯克吕格,中央子午线根据实际数据所在位置进行选择) 二、导入数据 选择大疆数据,找到对应的文件夹 数据有:图片,EVENT.b…

Eclipse Add generated serial version ID报错解决方案

为什么80%的码农都做不了架构师?>>> 问题: The following problem occurred:Could not find class file.Make sure the file is compilable 解决方案: 1、右键项目 -> Java Build Path -> Source 在Sourcd folders on bui…

C# WPF设备监控软件(经典)-上篇

01—前言应老东家也是老同学的需求,开发了此设备监控软件。主要是为了应对测试设备长时间不上传测试数据未能及时发现的问题,测试数据一般在每台设备都有个固定的临时存放目录,测试数据不更新时,此文件夹便不再更新。需求相对比较…

[转]微服务的4个设计原则和19个解决方案

目录 一、微服务架构演进过程 二、微服务架构的好处 三、微服务应用4个设计原则 1.AKF拆分原则 2.前后端分离 3.无状态服务 4.Restful通信风格 四、微服务架构带来的问题 五、微服务平台的19个落地实践 1.企业IT建设的三大基础环境 2.微服务应用平台总体架构 3.微服…

【GlobalMapper精品教程】033:影像地图羽化方式详解

在Globalmapper中,可以很方便的对影响进行多种羽化值设置。 文章目录 1. 不要羽化此图层2. 沿一个或多个边缘羽化3. 羽化到有效数据的多边形覆盖4. 在当前选定的多边形内羽化5. 裁剪到选定的边界,而不是羽化6. 在多边形外部羽化,而不是内部加载配套案例数据包中的data033.ra…

基于WPF重复造轮子,写一款数据库文档管理工具(一)

项目背景公司业务历史悠久且复杂,数据库的表更是多而繁杂,每次基于老业务做功能开发都需要去翻以前的表和业务代码。需要理解旧的表的用途以及包含的字段的含义,表少还好说,但是表一多这就很浪费时间,而且留下来的文档…

[转]GitBook使用教程收藏

GitBook使用教程 最简单的方式就是使用GitBook编辑器,没有什么难度,后面的教程主要针对命令行的方式 PS:GitBook的book页面默认没有download按钮的 需要到设置中打开,打开后再次publish生效 同步GitHub 更新失败,无法…

二 面向对象三大特性

一 继承与派生 一、继承定义 二、继承与抽象的关系 三、继承与重用性 四、派生 五、组合与重用性 六、接口与归一化设计 七、抽象类 八、继承实现的原理 九、子类中调用父类的方法 二 多态与多态性 一、多态 二、多态性 三 封装 一、封装定义 二、特性(property) 三、封装与扩展…

CSS3新属性

边框: border-radius 用于创建圆角 div { border:2px solid; border-radius:25px; -moz-border-radius:25px; /* Old Firefox */ } box-shadow 用于向方框添加阴影 div { box-shadow: 10px 10px 5px #888888; } border-image 使用图片来创建边框 div { border-image…

Android实用笔记——使用Spinner实现下拉列表

2019独角兽企业重金招聘Python工程师标准>>> 1、编辑activity_main.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"mat…

基于.NET 6 的开源访客管理系统

简单介绍一下系统功能系统用于简化访客登记、查询、保存。传统的登记方式&#xff0c;不仅浪费纸张&#xff0c;而且还面临保存的问题&#xff0c;查阅不方便。该系统为了在疫情期间能很好管理访客登记做好风险管控,同时可以整合智能设备做到自动确认并跟踪访客的行动轨迹,该项…

完整的产品管理工作流程

产品经理的工作具体会落实到工作流程中&#xff0c;所以工作流程很大程度上会体现工作层次。很多白领产品经理&#xff0c;多年来在一个低层次的流程中转圈——理需求、画原型、写文档、管项目、验收上线&#xff0c;一个版本上线之后立刻对下一个版本理需求、画原型、写文档、…

java爬虫-简单爬取网页图片

刚刚接触到“爬虫”这个词的时候是在大一&#xff0c;那时候什么都不明白&#xff0c;但知道了百度、谷歌他们的搜索引擎就是个爬虫。 现在大二。再次燃起对爬虫的热爱&#xff0c;查阅资料&#xff0c;知道常用java、python语言编程&#xff0c;这次我选择了java。在网上查找的…

Windows Server 2016-图形化迁移FSMO角色

上章节我们简单介绍了三种不同方式查看FSMO主机角色信息&#xff0c;在开篇之前我们简单回顾一下FSMO五种操作主机角色&#xff1a;林范围操作主机角色有两种&#xff0c;分别是 架构主机角色&#xff08;Schema Master&#xff09;和 域命名主机角色&#xff08;Domain Naming…

[转]互联网最大谣言:程序员35岁必淘汰?今天我就来击碎他

朋友&#xff0c;只要你是程序员&#xff0c;你一定知道996和“程序员35岁必死”的言论。 这两个话题在互联网上的讨论一次比一次激烈。 996工作制&#xff0c;众所周知&#xff0c;每天早上9点到岗&#xff0c;一直待到晚上9点&#xff0c;每周工作6天&#xff0c;很多互联网公…

【ArcGIS微课1000例】0057:将多波段栅格(影像.tif)背景设置为无数据nodata的方法

本文讲解将多波段栅格(影像.tif)背景设置为无数据nodata的方法。 文章目录 一、背景值识别二、背景值去除【推荐阅读】: 【ArcGIS微课1000例】0056:将单波段栅格背景设置为无数据NoData的方法 一、背景值识别 可以用【识别】工具来获取影像数据的背景值。 在背景上单击,…

华为HCIA认证H12-811题库新增

801、[单选题]178/832、在系统视图下键入什么命令可以切换到用户视图? A quit B souter C system-view D user-view 试题答案&#xff1a;A 试题解析&#xff1a;在系统视图下键入quit命令退出到用户视图。因此答案选A。 802、[单选题]“网络管理员在三层交换机上创建了V…

经典Java微服务架构教程 微服务从开发到部署

图书目录脑图&#xff1a; 本书根据开源项目整理&#xff0c;由于原在线文档无法正常使用&#xff0c;本人重新在Github上重新布署了一套在线文档。 书中讲解非常详细&#xff0c;并且有在线的视频教程&#xff0c;另有在线文档和在线的源码。 书中的代码由于PDF排版问题可能显…