二叉搜索树与Mysql索引的亲密关系

news2024/11/24 0:41:53

欢迎关注公众号:【离心计划】,一起逃离技术舒适圈

二叉搜索树

        二叉搜索树大家应该多多少少听过,它有一个很重要的特征,就是父节点左子树所有结点的值小于父节点的值,右子树所有结点的值大于父节点的值,这个特征引出来的重要信息就是,它的中序遍历是有序的!有序的特征在搜索查询里面可太重要了,为此我特地找了一道leetcode让大家感受一下:

        https://leetcode.cn/problems/kth-smallest-element-in-a-bst/

        大家可以动手做一下,由于其特性,我们寻找第k小只需要在中序遍历递归的位置记录一个索引表示第几大就行了,当这个索引值和题目给出的k相等时就是我们要的答案,我这边直接给出答案,读者可以自行理解一下,做完后可以思考下,如果题目是第k大又要怎么变动呢?

class Solution {
    int res;
    int k;
    public int kthSmallest(TreeNode root, int k) {
        this.k = k;
        reverse(root);
        return res;
    }
    int index = 0;
    private void reverse(TreeNode root){
        if(root==null){
            return;
        }
        reverse(root.left);
        this.index++;
        if(this.index==this.k){
            this.res = root.val;
            return;
        }
        reverse(root.right);
    }
}

        二叉搜索树提供了O(logn)的查询和写入效率,但是如果仅仅是内存查找,完全可以容忍,但是数据库往往将数据存入磁盘,如果是O(logN)的查询,那么意味着就需要logN次磁盘IO,这对数据库来说无疑是失败的查询模型,因此在二叉搜索树的基础上,引出了B树、B-树和B+树等多插搜索树,而关于这些不同树的解释不是这次的重点,接下来我们看一下,我们一直说的Mysql中InnoDB是以B+树的形式存储索引的,到底是怎么组织的?

Buffer Pool

        在此之前我们先了解一下InnoDB的内存模型,所谓内存模型就是内存的职责划分,目的是为了更高效的资源利用与回收。而Buffer Pool就是InnoDB的内存模型,其中Data区就是存放读取的行数据的,也是我们这次重点讨论的一块位置;ChangeBuffer是一块特殊的空间,主要用于如果update的行不在Data中,那么就先写到ChangeBuffer中去,避免了先读取数据到Data再修改的耗时耗资源操作;自适应索引则是InnoDB为了优化索引而存在的;Log Buffer则是针对redo log的io优化。

欢迎关注公众号:【离心计划】,一起逃离技术舒适圈

数据页和索引页

        在了解B+树是怎么在InnoDB发挥前,咱们先了解一下mysql表是怎么存储,这边就不卖关子了,mysql表由表数据索引组成。我们先看表数据,也就是我们存进去一行一行的数据,最终都要落到磁盘中,而这些一行行的数据,需要被InnoDB读取出来才能做crud,肯定不可能一行一行查,要记住,数据库的瓶颈是IO,所以InnoDB以为单位读取和存储这些行数据,默认16kb,当然行数据只是页的一部分,这些工业级产品当然会设计更多的“元数据”帮助更好的crud啦,因此InnoDB的页结构大概是这样的:

        InnoDB管存储数据的页叫做数据页,其中空闲空间就是用来存放数据行的,不断往里面塞直到空闲空间被用完。一个页肯定放不下所有数据,因此会有好多的数据页,这些数据页会以双向链表的形式串联起来,这个双向就需要上一页的地址和下一页的地址,对的,这个信息就是存在文件头中(可见啥东西的头都是用来存这些基本信息的,记住要考的),而每个页中的每一条行数据之间也以单链表的形式按照主键大小顺序关联着,因此这些许许多多的数据页就以这样的形式亲密着:

        现在为止其实已经可以查到我们想要的数据了,先找到第一个数据页,然后遍历其中的行数据,没找到往下一页找,但就是太慢了,所以需要优化,先从单数据页中进行优化,如果行数据小的话,一页也可以存下很多行,如果以O(N)的复杂度去遍历,是低效的,行数据是有序链表,有序的数据优化查询我们可熟悉啊,什么二分查找、跳表等,InnoDB也是差不多的想法,利用了上面页结构图中的数据页目录提供一个查询优化,做法就是按照一定规则将行数据分成多个组,以每个组最小的主键id作为槽值放到目录中,而目录其实就是一个key/value形式的数据,存储槽值和行偏移地址的关系,形成一个粗略索引,这个思想和调表就很像了,这样我们就可以借助目录,加速单页中的行数据查询。

欢迎关注公众号:【离心计划】,一起逃离技术舒适圈

        单页的查询是优化了,但是数据页和数据页之间还是得遍历查找,能不能把数据页目录的思想继续放大呢,也就是我们有个大的全局数据页目录,记录了页号和这个页最小主键id的对应关系,像这样:

        这样我们就能在数据页上做一个目录,可以快速查找需要找的数据了。但是数据量一大的话,这个全局目录也会很大,查询效率会随着数据量增大下降,因此InnoDB将这个全局的大目录也以页为单位拆分了出来,这个页叫做索引页。索引页之间为了保持高效查询与IO,就会以B+树的形式存储,最下层的索引页节点存储的目录信息是数据页号,这样索引页和数据页就关联了起来,像下图这样,这也是我们为什么说InnoDB的非叶子节点只存储索引信息,叶子节点才存储具体数据信息。

        如上图所示,如果我们查找id为3的,那么顺序就是先找到跟索引页根据目录找到页号34,然后3在1和5之间,所以找到页号10,然后找到对应的数据。

        数据页和索引页都是在磁盘上都是文件,涉及到文件都是IO,页之间虽然有连接但是只是逻辑顺序的,而不能保证物理顺序,所以相邻的页有可能是在磁盘不同分区,这就会造成随机IO,因此InnoDB为了保证顺序IO,会在给表以区的方式存储,一个区是连续的页,这样就能保证大部分的页都是物理顺序的。

        而这是主键索引的组织方式,InnoDB中我们根据索引是否为主键,分为主键索引和非主键索引(也叫二级索引),而二级索引和主键索引的区别,就在于其数据页存储的是主键id信息,不会存储完成的行数据,如果根据二级索引查询的列信息只包含索引列,这个叫做索引覆盖,如果需要查询其他列数据,就需要查询到对应主键id后回到主键索引树中查询行数据,这个叫做回表

小结

        我们从二叉搜索树的特性引出了B+树等多叉树,然后从InnoDB的内存分布分析了索引和数据是如何组织成B+树的,所以我们现在不只是粗浅地知道了“mysql索引底层是B+树”的表面含义,也理解了其深层含义。

推荐阅读

【专栏】核心篇09| 怎么保证缓存与DB的数据一致性

【专栏】RPC系列(番外)-IO模型与线程模型

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

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

相关文章

详解vue中vuex的用法

前言 说到 vuex 相信大家都不陌生,vuex 是一个专为 vue.js 应用程序开发的状态管理模式。vuex 背后的基本思想,就是单向数据流。今天我们就来好好聊聊 vuex。 vuex? 用官方的话来说,vuex 是一个专为 vue.js 应用程序开发的状态管…

【Linux】进程间通信之共享内存与信号量初识

目录🌈前言🌸1、System V共享内存🍡1.1、概念🍢1.2、原理🌺2、共享内存相关函数和指令🍡2.1、shmget函数(创建)🍢2.2、shmctl函数(控制)&#x1f…

使用 DataAnnotations(数据注解)实现模型的通用数据校验

DataAnnotations 实现数据模型的通用校验参数校验的意义常用参数的校验.NET 中内置 DataAnnotations 提供的特性校验关于 DataAnnotations 中的特性介绍基于 DataAnnotations 的通用模型校验封装基于 DataAnnotations 的特性校验助手实现步骤如何使用 DataAnnotations 封装的特…

某农业学校 算法设计与分析-第五次实验-回溯算法

1. 罗密欧与朱丽叶的迷宫问题 问题描述 罗密欧与朱丽叶的迷宫。罗密欧与朱丽叶身处一个mn的迷宫中,如图所示。每一个方格表示迷宫中的一个房间。这mn个房间中有一些房间是封闭的,不允许任何人进入。在迷宫中任何位置均可沿8 个方向进入未封闭的房间。罗…

第二章:关系数据库

一、关系数据库结构及形式化定义 1、【单选题】 下图中,关系D1、D2、D3笛卡尔积的目和基数分别为 正确答案: B 2、【多选题】下图中能够作为候选码的属性组为 正确答案: ABD 3、【多选题】关于关系数据库,说法正确的是 正确答…

二、栈和队列

二、栈和队列 栈——后进先出 应用:数制转换、括号匹配、行编辑程序、迷宫求解、表达式求值、八皇后问题、函数调用、递归调用的实现 队列——先进先出 应用:脱机打印输出 多用户系统用户排队分时循环使用CPU和主存 按用户优先级排队,每…

编译gtest报错‘is_trivially_copy_constructible’ is not a member of ‘std’

编译gtest报错‘is_trivially_copy_constructible’ is not a member of ‘std’一、问题描述二、原因分析三、升级gcc版本四、验证一、问题描述 在一个新的Redhat7.6 linux虚拟机上,将gtest clone下来之后编译,一堆报错: /opt/googletest/…

多线程问题(二)(安全问题)

目录 一、多线程不安全引例 二、线程不安全的原因 1、线程是抢占式执行 2、多线程共享同一变量 3、对变量的操作不是原子性 4、内存可见性 5、指令重排序 三、线程不安全问题的解决方案 1、使用synchronized关键字进行加锁 a、 synchronized修饰普通方法 b、sy…

Maleimide-PEG-Biotin,Biotin-PEG-MAL,生物素PEG马来酰亚胺用于生物分子检测

化学试剂生物素聚乙二醇马来酰亚胺,其英文名为Maleimide-PEG-Biotin,Biotin-PEG-MAL,它所属分类为Biotin PEG Multi-arm PEGs。 该试剂质量控制为95%,试剂的储存条件为: -20℃长期保存,避光,干…

数据结构---图

(一) 相关知识点 图(graph):图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中的顶点的集合,E是图G…

SpringBoot系列之自动装配原理详解

文章目录前言一、SpringBoot自动配置-Condition-11、观察spring自动创建bean过程2、创建自定义bean对象3、根据条件创建自定义bean二、 SpringBoot自动配置-Condition-2三、SpringBoot自动配置-切换内置web服务器1、查看继承关系图2、shiftdelete 排除Tomcat四、SpringBoot自动…

Win10启动Pycharm报错

Win10启动Pycharm报错报错信息解决方法报错信息 Internal error. Please report to http://jb.gg/ide/critical-startup-errors java.net.BindException: Address already in use: bind at java.base/sun.nio.ch.Net.bind0(Native Method) at java.base/sun.nio.ch.Net.bind(U…

如何在3个月内写出博士论文

在阅读本文之前,请注意:我花了三年半的时间进行全职研究,为我的博士论文收集数据;这三个月只涉及写作,我在最后很快就完成了。我并不是说每个人都能写得那么快,如果你没有做过研究,那是不可能的…

全国各省368个地级市河流密度数据(工具变量)

数据来源:国家基础地理信息中心 时间跨度:-- 区域范围:全国各省市 指标说明: 根据河流矢量和中国城市行政边界矢量地理信息,计算每个城市河流的总长度;根据各城市的行政区划面积,计算中国各城…

第三章:关系数据库标准语言SQL

一、sql概述和数据定义 1、【单选题】 create user A identified by B default tablespace C temporary tablespace D; 上述oracle数据库查询语句中A、B、C、D分别代表: 正确答案: A 2、【单选题】下表为患者缴费记录,现需…

2023跨年烟花3D最炫烟花,html最酷炫动态烟花源码分享,点击即可直接运行

📋 前言 🖱 博客主页:在下马农的碎碎念✍ 本文由在下马农原创,首发于CSDN📆 首发时间:2022/12/25📅 最近更新时间:2022/12/25🤵 此马非凡马,房星本是星。向前…

lambda表达式,函数式接口,链式编程,Stream流式计算

新时代的程序员:lambda表达式,函数式接口,链式编程,Stream流式计算 函数式接口 函数式接口:只有一个方法的接口(简化编程模型,在新版本框架底层中大量应用!) 只要是 函数型接口 就可以使用lambd…

iOS 16.2 在 SwiftUI 子视图中无法关闭弹出的(sheet)导航视图(NavigationView)之解决

问题现象 iOS 16.2 中,若在 SwiftUI 4.0 里弹出(sheet)一个导航视图 A,则不能在 A 的子视图中将 A 关闭(dismiss): 如上图所示:上面的按钮直接放在导航视图 A 中,点击它可以直接关闭 A;而下面的按钮放在一个子视图中,点击它想要关闭 A 却没有任何反应。 那么,该如…

可转债网格交易策略回测

什么是网格交易策略:基于股票波动高抛低吸策略,自动化反复买卖赚取差价。投资者借助条件单,把资金分成多份,从基准价开始,每跌x%就自动买入一份,每涨y%就自动卖掉一份。股价越波动高抛低吸的机会越多 什么…

Java项目:springboot基于java+mysql+springboot的社区养老医疗综合服务平台

作者主页:源码空间站2022 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目分为管理员、医生、病人三种角色, 管理员的功能包含如下: 个人信息:个人资料、修改密码 系统管理&…