镇江网站建设多少钱/seo外链工具下载
1. 磁盘基础知识
-
分页:
现代操作系统都使用虚拟内存来印射到物理内存,内存大小有限且价格昂贵,所以数据的持久化是在磁盘上。虚拟内存、物理内存、磁盘都使用页作为内存读取的最小单位。一般一页为4KB(8个扇区,每个扇区512B,8*512B=4KB)。
-
局部性原理:
-
当一个数据被用到时,其附近的数据也通常会马上被使用。
-
程序运行期间所需要的数据通常比较集中。
-
磁盘预读原理:
磁盘读取依靠的是机械运动,分为寻道时间、旋转延迟、传输时间三个部分,这三个部分耗时相加就是一次磁盘IO的时间,大概 9ms 左右。这个成本是访问内存的十万倍左右;
磁盘读取的速度远小于内存,所以尽量减少 I/O 次数是提高效率的关键。
根据局部性原理,且由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),所以即使只需要读取一个字节,磁盘也会读取一页的数据。即磁盘预读时通常会读取页的整倍数。
2. 树基础知识回顾
排序二叉树:左 < 跟 < 右 B 树:有序数组 + 多叉平衡树,节点存储关键字、数据、指针; B+ 树:有序数组链表 + 多叉平衡树,非叶子节点存储指针、关键字,不存储数据; 红黑树:红黑树是一种不大严格的平衡树(平衡树要求太高)
平衡树是为了防止二叉查找树退化为链表,而红黑树在维持平衡以确保 O(log2(n)) 的同时,不需要频繁着调整树的结构;
二叉树的存储结构
-
顺序存储(适用于完全二叉树)
index 之间的对应关系:
注意:二叉树的顺序存储只适合存储完全二叉树,否则 index 无法和节点对应起来,会有点恶心:
-
链式存储
这里要好好理解一下,不然会影响后面的理解。
相关视频推荐
4种红黑树的使用场景,从linux内核到应用开发(epoll、sk_buff、虚拟内存管理、nginx流量监控)
90分钟搞定红黑树应用
后端开发必学4种层式结构:B+/B-树、时间轮、跳表、LSM-Tree
免费学习地址:c/c++ linux服务器开发/后台架构师
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
3. 为什么不能使用二叉树来存储数据库索引
先说结论:
-
平衡二叉树进行插入/删除时,大概率需要通过左旋/右旋来维持平衡;
-
旋转需要加载整个树,频繁旋转效率低;
-
二叉树的 I/O 次数近似为 O(log2(n));
-
范围查询时,二叉树的时间复杂度会退化成 O(n);
-
二叉树退化成链表时,时间复杂度也近似退化成了 O(n);
-
二叉树无法使用磁盘预读功能;
其实单论范围查询,在关系型数据库中就基本没有使用二叉树的可能了。但是为了加深对知识的了解,来看看其他的原因。
先剔除掉范围查询的情况,原因 1、2、6 可以通过红黑树来解决,那么其实就剩下 2 个原因:
-
I/O 次数对比;
-
磁盘预读功能的利用;
4. 二叉树的 I/O 次数分析
先说 I/O 次数:
其实相比于二叉树,B 树、B+树, CPU 的运算次数并没有变化,甚至增多。但是 CPU 运算次数相比于 I/O 的消耗而言,可以忽略不计,所以 I/O 次数是评价一个数据库索引的效率高低的关键指标。
对于红黑树而言,其 I/O 次数近似为 log2(n),为什么是近似呢?
首先,索引是存储在磁盘上的,磁盘上的数据大部分情况下是连续的,但是随着增删改查的发生,有可能产生很多碎片,也就是说:
-
索引在磁盘上的存储也不一定是连续的;
这里,严谨起见,我们来分两种情况:
-
索引节点,即树的节点在磁盘上存储是连续;
假设一个页能存储 5 个节点,假设二叉树如下:
注意,序号只代表在磁盘中存储的顺序,不代表对应节点的关键字的值;
二叉树可能是链式存储,也可能是顺序存储。但是这里假设节点在磁盘上的存储是连续的,所以这里可以近似理解成顺序存储。即使是链式存储,无非就是 pNext 指针指向下一个连续的内存地址而已。
现在假设搜索的结果是最左边的叶子节点 16,因为磁盘预读的特性,加上一个页能存储 5 个节点,第一次 I/O :
添加图片注释,不超过 140 字(可选)
如上,第一次 I/O 就读取了 5 个节点,不仅把根节点读取进内存了,还把节点 2 和 4 都读取进去了,看上去还节约了两次 I/O ?好厉害的样子……
此时,会根据二分法查找,对比 1 号节点然后去找节点 2,紧接着找节点 4,因为这两个节点都在内存中了,所以不需要进行 I/O
这里再说一次,序号不代表节点的关键字,而是单纯的表示节点在磁盘中的排列顺序;
紧接着,会需要 8 号节点,而 8 不再内存中,所以进行第二次 I/O 同样是读取一页,即 5 个节点:
这次虽然也是读取了 5 个节点,但是实际上只有 8 号节点有实际作用,其他节点并没什么卵用(这是二叉树无法使用预读功能的本质),但是现在还没体现出劣势,现在对比之后需要 16 号节点,继续第三次读取:
此时找到了 16,并将结果返回。
这是高度为 4 的情况,且只有 31 个数据。但是实际使用中,怎么可能就 31 个数据?假设要找的是 32 号节点,因为 16 号节点之后的 17-20 虽然被加载进内存了,但是完全没用。那么就需要再进行一次 I/O 来加载 32 号节点所在的页,同时也会将 33-36 加载进内存,但是这些节点并无卵用。
如果要找的是 1000 ,10000?
所以,随着层级的深入,会出现:
-
一个页中只有一个节点有用(二分法查找要的是子节点而不是兄弟节点);
-
I/O 次数近似等于log2(n);
即:
-
第一次 I/O 可能的优势在层级加深之后就没有了;
-
就算是红黑树,也只能将时间复杂度维持在 log2(n);
上述讨论的是索引树在磁盘上的存储是连续的,如果不是连续的,那么按页读取到的脏数据会更多,上述的情况中,前几次 I/O 读取到有用的数据的概率会变低,所以 I/O 的次数只会增多而不会减少,即仍然是近似于 log2(n)。
5. B/B+树
B 树即:多路平衡查找树;
B 树的巧妙之处在于:
-
将一个节点的大小设置为一页的大小;
-
一个节点可以存放多个关键字(多叉树);
-
自平衡;
这 3 点结合起来就可以做到:
-
一个节点大小为一页,被加载进内存时,这些关键字在进行对比,找出需要 leftChild 还是 rightChild 时,都是有用的(如最右侧时需要对比所有节点);
-
一个节点可以存储多个关键字,有效降低了树的高度;
B+ 树的巧妙之处在于:
-
非叶子节点不存储数据,进一步增大了一页中存储关键字的数量;
-
叶子节点中存储数据且存在指向下一页的链表指针,可以使用顺序查询(支持范围查询);
6. B/B+树的索引数量
B 树的节点中存储:指针、关键字(主键)、数据 B+ 树的非叶子节点:指针、关键字 B+树的叶子节点:指针(链表)、关键字、数据
注意,这里不是绝对的,比如有的 B+ 树中叶子节点存储的不是数据,而是指向数据的指针。查询到指针之后再去对应地址取出数据,但是这样应该会增加一次 I/O 吧,应该也是在数据量和 I/O 次数之间做了取舍,具体先不讨论。
以 Sqlite3.12 之后为例,page_size = 16k,假设指针为 8 byte,假设关键字类型占 8 byte,假设数据占 1 KB;
B 树的一个节点:
一页能存储的数据量为:16kb / (1KB+8byte+8byte) ≈ 16;
高度为 3 的 B 树能存储 16 x16 x16 = 4096 条数据
相比于二叉树的 1 个而言,确实有效降低了树的层级。而且上述是假设数据为 1KB,如果数据没那么大,高度为 3 的 B 树能存储更多的数据,但是如果用在大型数据库索引上还是不够。
B+ 树:
如上图,B+树的核心在于非叶子节点不存储数据。
这样做可以减少非叶子结点占用的空间,增大一页所能存储的数据量,最大程度减少树的层级。
仍然是以上假设,假如树的高度为 3 ,那么就有两层存储关键字+指针,一层叶子节点来存储实际数据。
一页能存储的关键字为:16 * 1024 / (8 + 8) = 1024 一页能存储的数据量为:16KB / (1KB + 8byte + 8byte) = 16 (这里计算不完全准确,实际情况应该是1页数据中只有一个链表指针指向下一页) 能存储的关键字为:1024 * 1024 = 1048576;
因为端节点又有 1024 个指针,这些指针可以指向一个页,页中存储数据,也就是叶子节点,一页能存储 16 个叶子节点,所以总共能索引的数据量为 1048576 * 16 ≈ 1600万;如果高度为 4 ,则再乘以 1024 约为 17亿…..
上述推理中,理解终端节点的指针指向一个页,页中存储着关键字 + 数据 + 链表指针是关键。page 标记如下,有助理解:
虽然叶子节点很多,一个 page 对应一个叶子节点甚至是多个 page 才能存下一个叶子节点,但是这些是存在磁盘上的,找到对应的 page 之后才去加载对应的 page。索引超大数据量的同时,不会对 I/O 次数产生影响,这就是这个设计的牛逼之处。
但是这样也是有缺点的:
无论查询结果如何,都必须走到叶子节点才结束,也就是 I/O 次数固定为 O(h) 或者说是 log(n)(底数为节点子分支个数),这个 h 一般为 2-3,排除掉根节点常驻内存,高度为 3 的 B+ 树进行两次 I/O 就可以索引千万级别的数据,高度为 4 的 B+ 树,进行 3 次 I/O 就能索引十亿级别的数据量,这个效果还是很好的。
所以,这个缺点也可以说成是优点:稳定(稳如一条老狗🐶)
7. 实际应用
-
红黑树优点
红黑树常用于存储内存中的有序数据,增删很快,内存存储不涉及 I/O 操作。
-
B/B+树的优点
更适合磁盘存储,减少了树的层级,进而减少 I/O 次数;
-
B 树和 B+ 树对比
都是 B 树,但是 B+树更适合范围查询,比如 Mysql,且查询次数很稳定,为 logn。而 B 树更适合键值对型的聚合数据库,比如 MongoDB,查询次数最优为 O(1);
红黑树更适合内存存储,B 树更适合键值对存储,B+ 树适合范围查询;
相关文章:

面试常考数据结构:红黑树、B树、B+树各自适用的场景
1. 磁盘基础知识 分页: 现代操作系统都使用虚拟内存来印射到物理内存,内存大小有限且价格昂贵,所以数据的持久化是在磁盘上。虚拟内存、物理内存、磁盘都使用页作为内存读取的最小单位。一般一页为4KB(8个扇区,每个扇…...

Paddle GPU版本需要安装CUDA、CUDNN
完整的教程 深度学习环境配置:linuxwindows系统下的显卡驱动、Anaconda、Pytorch&Paddle、cuda&cudnn的安装与说明 - 知乎这篇文档的内容是尽量将深度学习环境配置(使用GPU)所需要的内容做一些说明,由于笔者只在windows和linux下操作过…...

MYSQL length函数
mysql length函数计算结果的单位是啥,和varchar字段类型的单位是相同的吗? 做了一下实验,结果如下: 1.mysql length 函数计算的是有多少个字符,比如字段值是 permission 则length函数计算结果为10。 2.如果字段类型是…...

uniapp 在android手机上运行tab栏页面跳转问题
【问题描述】: 使用uniapp写的项目,在tab页面,无论使用哪种方式的跳转,只要是在url后面拼接参数,在打包成apk文件后,在手机上面安装使用,都是获取不到susIndex参数的,而在浏览器上面…...

css3 hover效果
CSS3中的:hover伪类用于创建鼠标悬停时的样式效果。当用户将鼠标悬停在页面元素上时,你可以为这些元素定义不同的样式规则,以实现交互效果 /* 一般样式规则 */ element {/* 正常状态下的样式 */ }/* 悬停样式规则 */ element:hover {/* 鼠标悬停时的样式…...

C语言char与short取反以及符号判断问题
这个问题主要是在从对一个变量进行符号判断引出,有一种判断方法是#define ISUNSIGNED(Value) (Value >0 && ~Value >0) 主要是通过将符号位取反然后将变量与0进行比较。传入int与unsigned int结果正确,但是当传入unsigned char 与unsign…...

Gpt-4多模态功能强势上线,景联文科技多模态数据采集标注服务等您来体验!
就在上个月,OpenAI 宣布对ChatGPT 进行重大更新,该模型不仅能够通过文字输入进行识别和分析,还能够通过语音、图像甚至视频等多种模态的输入来获取、识别、分析和输出信息。这一重要技术突破,将促进多模态自然语言处理的发展&…...

【idea】 java: 找不到符号
idea 启动时提示 java: 找不到符号 java: 找不到符号 符号: 方法 getCompanyDisputeCount() 位置: 类型为com.yang.entity.AreaAnalyse的变量 areaAnalyse 在setting ——> Compiler ——>Shared build process VM options: 添加: -Djps.track.ap.dep…...

Flink测试利器之DataGen初探 | 京东云技术团队
什么是 Flinksql Flink SQL 是基于 Apache Calcite 的 SQL 解析器和优化器构建的,支持ANSI SQL 标准,允许使用标准的 SQL 语句来处理流式和批处理数据。通过 Flink SQL,可以以声明式的方式描述数据处理逻辑,而无需编写显式的代码…...

linux更换常用软件的默认缓存路径(.conda, .huggingface等)
在使用linux的过程中,我们往往会使用软件安装很多packages,其中的大多数软件(例如conda)会把当前安装的packages缓存起来,以加速之后的相同package的安装。 而很多软件的默认缓存路径是user自己的home路径。下面罗列几…...

Kafka消费者使用案例
本文代码链接:https://download.csdn.net/download/shangjg03/88422633 1.消费者和消费者群组 在 Kafka 中,消费者通常是消费者群组的一部分,多个消费者群组共同读取同一个主题时,彼此之间互不影响。Kafka 之所以要引入消费者群组…...

SpringMVC全注解开发
在学习过程中,框架给我们最大的作用,就是想让开发人员尽可能地只将精力放在具体业务功能的实现之上,而对于各种映射关系的配置,统统由框架来进行完成,由此,注解就很好的将映射功能进行实现,并且…...

解决 android Cannot access ‘<init>‘: it is private in
最近要在2个非直接依赖module使用单例,有一种注入依赖的方式可以,但是报了如下错误: Cannot access <init>: it is private in 经过查阅资料,原来是依赖的单例类的构造函数不能使用private,这里做个记录&#…...

不容易解的题10.15
395.至少有K个重复字符的最长字串 395. 至少有 K 个重复字符的最长子串 - 力扣(LeetCode)https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/description/?envTypelist&envIdZCa7r67M自认为是不好做的题。尤其…...

Megatron-LM GPT 源码分析(二) Sequence Parallel分析
引用 本文基于开源代码 https://github.com/NVIDIA/Megatron-LM ,延续上一篇Megatron-LM GPT 源码分析(一) Tensor Parallel分析 通过对GPT的模型运行示例,从三个维度 - 模型结构、代码运行、代码逻辑说明 对其源码做深入的分析。…...

DNA序列(DNA Consensus String, ACM/ICPC Seoul 2006, UVa1368) rust解法
输入m个长度均为n的DNA序列,求一个DNA序列,到所有序列的总Hamming距离尽量小。两个等长字符串的Hamming距离等于字符不同的位置个数,例如,ACGT和GCGA的Hamming距离为2(左数第1, 4个字符不同)。 输入整数m和…...

如何使用Jmeter进行http接口测试?
前言: 本文主要针对http接口进行测试,使用Jmeter工具实现。 Jmter工具设计之初是用于做性能测试的,它在实现对各种接口的调用方面已经做的比较成熟,因此,本次直接使用Jmeter工具来完成对Http接口的测试。 一、开发接…...

bash一行输入,多行回显demo脚本
效果图: 脚本: #!/bin/bash # 定义一个变量,用来存储输入的内容 input"" # 定义一个变量,用来存储输入的字符 char""# 为了让read能读到空格键 IFS_store$IFS IFS# 提示内容,在while循环中也有&a…...

IDEA spring-boot项目启动,无法加载或找到启动类问题解决
问题描述:找不到或无法加载主类 xxx.xxx.xxx.Classname 解决方案: 1.检查启动设置: 启动类所在包运行环境(一般选择默认即可)设置完成即可进行运行测试 2.如果第一步没有解决问题,试着第二步:…...

【LeetCode刷题(数据结构与算法)】:完全二叉树的节点个数
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点 输入:r…...

【代码随想录】算法训练营 第一天 第一章 数组 Part 1
目录 数组基础知识补充 704. 二分查找 题目 左闭右闭方法 思路 代码 左闭右开方法 思路 代码 27. 移除元素 题目 暴力解法 思路 代码 双指针法 思路 代码 数组基础知识补充 1. 在leecode中,数组一般是以vector容器的形式出现的,虽然ve…...

286_C++_定时器的其中一个操作,定时重载接口—startTimer循环执行回调(未完全)
1、启动一个定时器,允许在一定时间间隔内执行回调函数startTimer 1、接口函数参数详解 /*** @brief startTimer 定时重载接口* @param interval 定时器触发间隔,单位毫秒 (ms)* @param notify 定时时间到后需要触发的回调* @param type 回调驱动方…...

自动驾驶学习笔记(四)——变道绕行仿真
#Apollo开发者# 学习课程的传送门如下,当您也准备学习自动驾驶时,可以和我一同前往: 《自动驾驶新人之旅》免费课程—> 传送门 《2023星火培训【感知专项营】》免费课程—>传送门 文章目录 前言 仿真内容 启动Dreamview 开启Sim…...

C++位图,布隆过滤器
本期我们来学习位图,布隆过滤器等相关知识,以及模拟实现,需求前置知识 C-哈希Hash-CSDN博客 C-封装unordered_KLZUQ的博客-CSDN博客 目录 位图 布隆过滤器 海量数据面试题 全部代码 位图 我们先来看一道面试题 给 40 亿个不重复的无符号…...

Python多种方法实现九九乘法表
你好,我是悦创。 九九乘法表是一种常见的算术学习工具,通常用于帮助学生记住乘法的基本运算。以下是使用Python实现九九乘法表的几种方法: 1. 使用两个嵌套循环 for i in range(1, 10):for j in range(1, i 1):print(f"{j}x{i}{i * …...

【力扣1876】长度为三且各字符不同的子字符串
👑专栏内容:力扣刷题⛪个人主页:子夜的星的主页💕座右铭:前路未远,步履不停 目录 一、题目描述二、题目分析 一、题目描述 题目链接:长度为三且各字符不同的子字符串 如果一个字符串不含有任何…...

HSN:微调预训练ViT用于目标检测和语义分割,华南理工和阿里巴巴联合提出
今天跟大家分享华南理工大学和阿里巴巴联合提出的将ViT模型用于下游任务的高效微调方法HSN,该方法在迁移学习、目标检测、实例分割、语义分割等多个下游任务中表现优秀,性能接近甚至在某些任务上超越全参数微调。 论文标题:Hierarchical Side…...

机器学习的原理是什么?
训过小狗没? 没训过的话总见过吧? 你要能理解怎么训狗,就能非常轻易的理解机器学习的原理. 比如你想教小狗学习动作“坐下”一开始小狗根本不知道你在说什么。但是如果你每次都说坐下”然后帮助它坐下,并给它一块小零食作为奖励,经过多次…...

Java集合框架之ArrayList源码分析
文章目录 简介ArrayList底层数据结构初始化集合操作追加元素插入数据删除数据修改数据查找 扩容操作总结 简介 ArrayList是Java提供的线性集合,本篇笔记将从源码(java SE 17)的角度学习ArrayList: 什么是ArrayList?ArrayList底层数据结构是…...

TensorFlow入门(二十、损失函数)
损失函数 损失函数用真实值与预测值的距离指导模型的收敛方向,是网络学习质量的关键。不管是什么样的网络结构,如果使用的损失函数不正确,最终训练出的模型一定是不正确的。常见的两类损失函数为:①均值平方差②交叉熵 均值平方差 均值平方差(Mean Squared Error,MSE),也称&qu…...