当前位置: 首页 > news >正文

B-tree(PostgreSQL 14 Internals翻译版)

概览

B树(作为B树访问方法实现)是一种数据结构,它使您能够通过从树的根向下查找树的叶节点中所需的元素。为了明确地标识搜索路径,必须对所有树元素进行排序。B树是为有序数据类型设计的,这些数据类型的值可以进行比较和排序。

下面的机场代码索引构建示意图将内部节点显示为水平矩形;叶节点垂直排列。

在这里插入图片描述
每个树节点包含几个元素,这些元素由一个索引键和一个指针组成。内部节点元素是下一层的引用节点;叶节点元素引用堆元组(图中没有显示这些引用)。

B树具有以下重要属性:

  • 它们是平衡的,这意味着树的所有叶节点都位于相同的深度。因此,它们保证所有值的搜索时间相等。
  • 它们有大量的分支,也就是说,每个节点包含许多元素,通常有数百个元素(为了清晰起见,该图仅显示了三个元素节点)。因此,B树深度总是很小,即使对于非常大的表也是如此。
  • 索引中的数据在每个节点内以及在同一级别的所有节点上按升序或降序排序。对等节点被绑定到一个双向列表中,因此可以通过简单地以一种或另一种方式扫描列表来获得有序的数据集,而不必每次都从根开始。

搜索与插入

等值搜索

让我们看一下如何根据条件“索引-列=表达式”在树中搜索值。我们将尽力找到KJA机场。

搜索从根节点开始,访问方法必须确定要下降到哪个子节点。它选择K i键,满足K i≤表达式< K i+1。

根节点包含键AER和OVB。条件AER < KJA<OVB成立,因此我们需要下降到具有AER键的元素所引用的子节点。

在这里插入图片描述

这个过程递归地重复,直到我们到达包含所需元组ID的叶节点。在这种特殊情况下,子节点满足条件DME≤KJA < KZN,因此我们必须下降到具有DME键的元素所引用的叶节点。

您可以注意到,树的内部节点中最左边的键是冗余的:要选择根的子节点,只要满足条件KJA < OVB就足够了。B树不存储这样的键,所以在下面的插图中,我将保留相应的元素为空。

叶节点中需要的元素可以通过二分查找快速找到。

然而,搜索过程并不像看起来那么简单。必须考虑到,索引中数据的排序顺序可以是升序(如上所示),也可以是降序。即使是唯一的索引也可以有几个匹配的值,并且必须返回所有这些值。此外,可能有太多的副本,以至于它们不适合单个节点,因此相邻的叶节点也必须处理。

最重要的是,当搜索正在进行时,其他进程可能会修改数据,页面可能被分成两个,树结构可能会发生变化。所有的算法都被设计为尽可能减少这些并发操作之间的争用,并避免过多的锁,但是我们在这里不打算讨论这些技术细节。

不等值搜索

如果搜索是通过条件“索引-列 ⩽expression”(或“索引-列⩾expression”)执行的,我们必须首先搜索满足相等条件的值的索引,然后在所需的方向遍历其叶节点,直到到达树的末端。

该图说明了搜索小于或等于DME的机场代码。

在这里插入图片描述
对于小于和大于操作符,过程相同,只是必须排除第一个找到的值。

范围搜索

当按照“表达式1≤索引列≤表达式2”的范围进行搜索时,我们必须先找到表达式1,然后沿着正确的方向遍历叶节点,直到找到表达式2。该图说明了在LED和ROV之间的范围内搜索机场代码的过程。

在这里插入图片描述

插入

新元素的插入位置由键的顺序明确定义。例如,如果将RTW机场代码插入到表中,则新元素将出现在ROV和SGC之间的最后一个叶节点中。

但是如果叶节点没有足够的空间容纳新元素怎么办?例如(假设一个节点最多可以容纳三个元素),如果我们插入TJM机场代码,最后一个叶节点将被过度填充。在这种情况下,节点被分成两个,旧节点的一些元素被移动到新节点中,指向新子节点的指针被添加到父节点中。显然,父节点也可能会被填满。然后它也被分成两个节点,以此类推。如果要拆分根,则在生成的节点之上再创建一个节点,以成为树的新根。在这种情况下,树的深度增加了一级。

在本例中,TJM机场的插入导致两个节点分裂;生成的新节点在下面的图中突出显示。为了确保可以拆分任何节点,双向列表绑定了所有级别的节点,而不仅仅是最低级别的节点。

在这里插入图片描述

所描述的插入和分割过程保证树保持平衡,并且由于节点可以容纳的元素数量通常相当大,因此树的深度很少增加。

问题是,一旦分裂,节点就永远无法合并在一起,即使它们在垃圾回收后包含的元素非常少。这个限制并不适用于B树数据结构本身,而是适用于它的PostgreSQL实现。因此,如果在尝试插入时发现节点已满,则访问方法首先尝试删除冗余数据,以便清除一些空间并避免额外的分割

页面布局

B树的每个节点占用一个页面。页的大小定义了节点的容量。

由于页面分割,树的根可以由不同时间的不同页面表示。但是搜索算法必须总是从根开始扫描。它在**零索引页(称为元页)**中查找当前根页的ID。元页面还包含一些其他元数据。

在这里插入图片描述

索引页中的数据布局与我们目前看到的略有不同。除了每个级别最右边的页面外,所有页面都包含一个额外的 “高键”,该键保证不小于该页中的任何键 。在上面的图表中,高音键被突出显示。

让我们使用pageinspect扩展来查看基于六位数预订引用的真实索引的页面。元页面列出根页面ID和树的深度(级别编号从叶节点开始,从零开始):

在这里插入图片描述
存储在索引项中的键被显示为字节序列,这不是很方便:

在这里插入图片描述
为了破译这些值,我们必须编写一个专门的函数。它不会支持所有平台,也可能不适用于某些特定场景,但它可以用于本章的示例:

在这里插入图片描述

现在我们可以看一下根页面的内容:

在这里插入图片描述

正如我所说的,第一个条目不包含键。ctid列提供到子页面的链接。

假设我们正在寻找预订E2D725。在这种情况下,我们必须选择条目19(因为E2CB14≥E2D725 < EF6FEA)并向下到第5135页。

在这里插入图片描述

本页中的第一个条目包含高键,这可能看起来有点出乎意料。从逻辑上讲,它应该放在页面的末尾,但从实现的角度来看,将它放在页面的开头更方便,以避免每次页面内容更改时都移动它。

在这里,我们选择条目3(因为E2D71D ⩽ E2D725 < E2E2F4),并向下到第11919页。

在这里插入图片描述
它是索引的叶子页。第一个入口是高键;所有其他条目都指向堆元组。

这是我们的预订单:

在这里插入图片描述
当我们按代码搜索预订时,低级别的情况大致就是这样:
在这里插入图片描述

重复数据删除

非唯一索引可以包含许多指向不同堆元组的重复键。由于非唯一键出现不止一次,因此占用大量空间,因此重复项被折叠成单个索引项,其中包含键和相应的元组ID列表。在某些情况下,这个过程(称为重复数据删除)可以显著减小索引大小。

但是,由于MVCC,唯一索引也可以包含重复项:索引保留对表行所有版本的引用。HOT更新机制可以帮助您避免由于引用过时的、通常寿命较短的行版本而导致的索引膨胀,但有时它可能不适用。在这种情况下,重复数据删除可以为清理冗余堆元组和避免额外的页面分割赢得一些时间。

为了避免在没有直接好处的情况下在重复数据删除上浪费资源,只有在叶子页没有足够的空间容纳另一个元组时才执行折叠。然后,页面修剪和重复数据删除可以释放一些空间,并防止不希望的页面分割。但是,如果副本很少,则可以通过关闭deduplicate_items storage参数来禁用重复数据删除特性。

部分索引不支持重复数据删除功能。主要的限制是键的相等性必须通过对其内部表示的简单二进制比较来检查。到目前为止,并不是所有的数据类型都可以用这种方式进行比较。例如,浮点数(浮点数和双精度数)对零有两种不同的表示。任意精度的数字(数字)可以用不同的尺度表示同一个数字,而jsonb类型可以使用这样的数字。如果使用非确定性排序,则不可能对文本类型进行重复数据删除,非确定性排序允许用不同的字节序列表示相同的符号(标准排序是确定性的)。

此外,复合类型、范围和数组以及用INCLUDE子句声明的索引目前不支持重复数据删除。

要检查特定索引是否可以使用重复数据删除,您可以查看其元页面中的allequalimage字段:

在这里插入图片描述

此时支持重复数据删除功能。事实上,我们可以看到,其中一个叶页包含具有单个元组ID (htid)和具有ID列表(tids)的索引条目:

在这里插入图片描述

内部索引项的紧凑存储

重复数据删除可以在索引的叶页中容纳更多条目。但是,即使叶页构成了索引的大部分,在内部页中执行数据压缩以防止额外的分割也同样重要,因为搜索效率直接依赖于树的深度。

内部索引项包含索引键,但它们的值仅用于在搜索期间确定要下降到的子树。在多列索引中,通常使用第一个键属性(或几个第一个键属性)就足够了。可以截断其他属性以节省页面中的空间。

这样的后缀截断发生在叶页被分割并且内页必须容纳一个新指针的时候。

例如,下面是在包含订票参考和乘客姓名的列上建立的票务表索引的根页的几个条目:

在这里插入图片描述

我们可以看到一些索引条目没有第二个属性。

当然,叶页必须保留所有键属性和INCLUDE列值(如果有的话)。否则,将无法执行仅索引扫描。唯一的例外是高键;它们可以部分保存。

相关文章:

B-tree(PostgreSQL 14 Internals翻译版)

概览 B树(作为B树访问方法实现)是一种数据结构&#xff0c;它使您能够通过从树的根向下查找树的叶节点中所需的元素。为了明确地标识搜索路径&#xff0c;必须对所有树元素进行排序。B树是为有序数据类型设计的&#xff0c;这些数据类型的值可以进行比较和排序。 下面的机场代…...

React环境初始化

环境初始化 学习目标&#xff1a; 能够独立使用React脚手架创建一个React项目 1.使用脚手架创建项目 官方文档&#xff1a;(https://create-react-app.bootcss.com/)    - 打开命令行窗口    - 执行命令      npx create-react-app projectName    说明&#xff1a…...

Hadoop3教程(二十八):(生产调优篇)NN、DN的多目录配置及磁盘间数据均衡

文章目录 &#xff08;148&#xff09;NN多目录配置&#xff08;149&#xff09;DataNode多目录配置及磁盘间数据平衡磁盘间数据均衡 参考文献 &#xff08;148&#xff09;NN多目录配置 NN多目录的意思是&#xff0c;本地目录可以配置成多个&#xff0c;且每个目录存放内容相…...

博客续更(五)

十一、后台模块-菜单列表 菜单指的是权限菜单&#xff0c;也就是一堆权限字符串 1. 查询菜单 1.1 接口分析 需要展示菜单列表&#xff0c;不需要分页。可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询。菜单要按照父菜单id和orderNum进行排序 请求方式 请求路径…...

看微功耗遥测终端机如何轻松应对野外环境挑战?

在野外&#xff0c;数据的实时监测和传输是至关重要的。无论是环境温度、湿度&#xff0c;还是水位、流量&#xff0c;都需要精准把控。然而&#xff0c;传统的监测方法往往受限于电源供应问题&#xff0c;而无法充分发挥其功能。这时候&#xff0c;一款微功耗遥测终端机&#…...

vue后台开发第一步

1、创建vue3.2的项目 2、安装前期组件 安装 安装 vue-router npm install vue-router4安装 vuex npm install vuexnext --save安装 element-plus npm install element-plus --save安装 element-plus图标 npm install element-plus/icons-vue 使用 创建router目录、目录下创…...

Vue3踩坑指南

vue.config.ts不起作用 关于项目 项目使用的还是vue-cli搭建的&#xff0c;底层还是webpack&#xff0c;没有使用新的vite搭建。 踩坑1&#xff1a;vue.config.ts不起作用 我本着既然是vue3 ts的项目&#xff0c;那么为了规范&#xff0c;项目中所有的js文件都得替换成ts文…...

第十七章 Java连接数据库

1.打卡“命令提示符”&#xff0c;用管理员身份运行 2.登录MySQL 3.创建库和表 4.使用Java命令查询数据库操作 5.右击——点击“Build Path”——选择第四个——找到包的位置——导入成功 一、创建java项目 二、连接数据库 1.注册驱动 2.获取链接 3.获取statment对象 4.…...

221 - Urban Elevations (UVA)

题目链接如下&#xff1a; Online Judge 首先&#xff0c;我的代码虽然AC了&#xff0c;但是是有问题的&#xff0c;uva的测试数据太水了所以侥幸通过而已。因为题目要求的数据是实数而非整数&#xff0c;我的代码是按所有数据都是整数来暴力做的……但因为刘汝佳的代码写得太…...

驱蚊“卷到”母婴,润本市值73亿

作者 | 若楠 禄存 排版 | Cathy 监制 | Yoda 出品 | 不二研究 从 " 驱蚊第二股 " 到 " 婴童护理第一股 " 润本终于敲钟了。 尽管宣称 " 婴童护理第一股 "&#xff0c;但实际上&#xff0c;润本最初是以驱蚊产品起家的。 10 月 17 日&#…...

Swingbench 压力测试(超详细)

目录 前提需要有配置好的oracle哦 1、环境准备 2、安装Swingbench 3、造数据 4、压测 前提需要有配置好的oracle哦 1、环境准备 启动监听 lsnrctl start 启动数据库 sqlplus / as sysdba startup 创建表 CREATE TABLESPACE soe DATAFILE /u01/app/oracle/oradata/or…...

【python】--python环境安装及配置

目录 一、python开发环境部署1、下载安装Miniconda2、python环境3、进入或退出python环境4、对应python环境安装工具/库5、进入pyhton环境&#xff0c;查看已安装的工具/库6、安装pycharm专业版7、pycharm创建项目并关联python版本环境 一、python开发环境部署 要安装一个pyth…...

Android前台服务和通知

前台服务 Android 13及以上系统需要动态获取通知权限。 //android 13及以上系统动态获取通知权限 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {checkPostNotificationPermission(); } private void checkPostNotificationPermission() {if (ActivityCompat.chec…...

算法进修Day-36

算法进修Day-36 71. 简化路径 难度&#xff1a;中等 题目要求&#xff1a; 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 / 开头&#xff09;&#xff0c;请你将其转化为更加简洁的规范路径。 在 Unix 风格的文件系统中&am…...

postman自动化运行接口测试用例

做过接口测试的人&#xff0c;应该都知道postman &#xff0c;我们在日常的时候都可以利用postman做接口测试&#xff0c;我们可以把接口的case保存下来在collection里面&#xff0c;那么可能会有这样的需求&#xff0c;我们怎么把collection的用例放到jenkins中定时执行呢&…...

【Linux】Linux环境搭建

Linux环境搭建 前言Linux 环境的搭建方式一、Linux环境搭载购买云服务器 二、 使用 XShell 远程登陆到 Linux关于 Linux 桌面下载安装 XShell查看 Linux 主机 ip使用 XShell 登陆主机XShell 下的复制粘贴 前言 Linux 环境的搭建方式 主要有三种 直接安装在 物理机 上. 但是由…...

k8s day07

昨日内容回顾: - 污点: 影响Pod调度&#xff0c;污点是作用在worker节点上。语法格式: KEY[VALUE]:EFFECT 有三种污点。 EFFECT: - NoSchedule&#xff1a; 已经调度到当前节点的Pod不驱逐&#xff0c;并且不在接…...

压力大,休息日都没有,更别说年休假了

我一周要工作六天&#xff0c;每天至少十小时&#xff0c;连个休息日都没有。哪来的年休假&#xff1f;...

人手一个助理,三句话让AI替我们上班

目录 前言 从大模型上长出来的 AI 原生应用&#xff0c;才是关键 而这看起来只是一个小小的办公沟通场景&#xff0c;却是大模型重构的一个非常典型的场景。背后考验的也是大模型的综合能力应用 这种从AI原生角度进行的重构&#xff0c;离不开大模型的理解、生成、逻辑、记…...

【Eclipse Maven Tycho】如何通过maven执行eclipse application

通过maven执行eclipse application 前言命令行下运行通过maven tycho运行 前言 eclipse其实不只是一个桌面&#xff08;GUI&#xff09;程序&#xff0c;他还可以是一个命令行程序。如果你的产品或软件是基于eclipse开发的&#xff0c;并且他没有UI相关的功能&#xff0c;那么…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...