首页 > 系统相关 >openGauss内存引擎中的索引

openGauss内存引擎中的索引

时间:2024-04-08 15:14:28浏览次数:24  
标签:索引 引擎 内存 key openGauss 节点

一、索引
索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有: B 树, B+树和 Hash。

索引的作用就相当于目录的作用。打个比方: 我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。

二、内存引擎
在 OpenGauss 中内存引擎全称为内存优化表(MOT)存储引擎。

内存引擎作为在 openGauss 中与传统基于磁盘的行存储、列存储并存的一种高性能存储引擎,基于全内存态数据存储,为 openGauss 提高了高吞吐的实时数据处理分析能力及极低的事务处理时延,在不同业务负载场景下可以达到其他引擎事务处理能力的 3~10 倍。内存引擎之所以有较强的事务处理能力,更多因为其全面利用内存中可以实现的无锁化的数据及其索引结构、高效的数据管控,基于 NUMA 架构的内存管控,优化的数据处理算法及事务管理机制。

MOT 与基于磁盘的普通表并排创建。MOT 的有效设计实现了几乎完全的 SQL 覆盖,并且支持完整的数据库功能集,如存储过程和自定义函数。通过完全存储在内存中的数据和索引、非统一内存访问感知(NUMA-aware)设计、消除锁和锁存争用的算法以及查询原生编译,MOT 可提供更快的数据访问和更高效的事务执行。MOT 有效的几乎无锁的设计和高度调优的实现,使其在多核服务器上实现了卓越的近线性吞吐量扩展。

图 1 OpenGauss 内存引擎架构图

三、Masstree
1.概要
Trie 树和 B+ 树结合而成的并发算法——MassTree。

1.1 因此首先介绍一下字典树(Trie 树)。
Trie 树,又叫字典树、前缀树(Prefix Tree)、单词查找树 或 键树,是一种多叉树结构。

图 2 一棵 Trie 树,表示了关键字集合{“a”, “to”, “tea”, “ted”, “ten”, “i”, “in”, “inn”}。

Trie 树的基本性质:

1.根节点不包含字符,除根节点外的每一个子节点都包含一个字符。

2.从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。

3.每个节点的所有子节点包含的字符互不相同。

一般会在节点结构中设置一个标志,用来标记该结点处是否构成一个单词(关键字)。

1.2 然后再介绍一下 B+树。
图 3 B+树样例

B+树是 B 树的一种变种,有着比 B-树更高的查询性能

一个 m 阶的 B+树具有如下几个特征:

1.有 k 个子树的中间节点包含有 k 个元素(B 树中是 k-1 个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。

2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。

从结构上来说,Mass Tree 是由一层或多层 B+ 树组成的 Trie 树。

图 4

图 4 中,圆形代表内部节点(interior node,也就是 B+ 树的 branch node),矩形代表边缘节点(border node,也就是 B+ 树的 leaf node),五角星代表 value。border node 的 value 域可能存放的是数据,也可能存放的是下一层子树的根节点。

Masstree 以键(key)的前缀作为索引,每 k 个字节形成一层 B+ 树结构,在每层中处理键中这 k 个 字 节 对 应 所 需 的 INSERT/LOOKUP/ UPDATE/DELETE 流程。图 4 为 k=8 的情况。

2.Masstree 静态数据结构
图 5

四、OpenGauss 中基于 Masstree 的索引
下面所有提到的大部分文件位于

openGauss-server-master\openGauss-server-master\src\gausskernel\storage\mot\core\src\storage\index 中

1.数据结构
对应文件位置:

openGauss-server-master\openGauss-server-master\src\gausskernel\storage\mot\core\src\storage\index\Masstree

OpenGauss 中对应 Masstree 的索引类名为 MasstreePrimaryIndex,

继承 Index 超类。

类 MasstreePrimaryIndex 拥有图 6 中的成员属性。

图 6

其超类 Index 拥有图 7 中的成员属性。

图 7

2.并发控制
为了防止读线程读到中间状态,叶节点被设计成最多存放 15 个 key,引入了一个 8 字节 64 位的 permutation(uint64_t),这个 permutation 被划分成 16 份,每份 4 位,其中 1 份代表当前节点的 key 数量,另外 15 份用于存放每个 key 在节点中实际位置的索引,key 的插入是顺序插入,之后只需要修改 permutation 来更新节点内 key 的索引信息,然后施加一个 release 语义,当读线程对这个节点的 permutation 施加 acquire 语义时,可以获取到完整的节点信息。

并发情况一般有两种竞争,OpenGauss 采用一个 32bit 的 version 参数应对并发控制。

图 8

write-write 竞争:同一时刻只有一个线程可以对当前节点进行写操作

read-write 竞争:开始前和读结束后都需要获取当前节点的最新 version,来判断在读过程中当前节点是否发生了写操作(插入或分裂),同时对节点的写操作都需要先修改 version,在插入 key 之前需要设置 inserting 标记,插入完成之后将 insert 的 vinsert + 1;在分裂之前需要设置 splitting 标记,分裂完成之后将 split 的 vsplit + 1。

3.查找操作
图 9

首先,在开始读取节点之前,必须获得节点的 stable version,即 version 中的 inserting 和 splitting 位都为 0。

其次,在下降之前,需要获取最新的 root,因为在开始下降前,根节点可能分裂了,导致其发生了改变。

最后,如果当前节点已经是叶节点,那么可以返回,否则需要进行下降,读取内部结点根据 key[x, x+8)(8 字节) 获得下降节点之后,分为 3 种情况处理:

1.节点在我们读取期间没有发生任何变化,我们可以安全地进行下降;

2.节点发生了变化,而且是分裂,那么我们需要从根节点重新进行下降;

3.节点发生了变化,但只是插入,只需要重新对当前节点进行下降。

  1. 插入操作
    图 10

查找 key,如果找到 key 则 tree 不做改变;如果没找到,

1.先锁住应该持有待插入 key 的节点

2.将相应节点 version 修改为 inserting

3.将相应节点 state 修改为 insert

4.更新树结构,以满足约束

5.更新在叶节点中的 key slice ,keylen, key suffix ,key vaule

6.Add the key's location in permutation's back.在解锁节点并将密钥输入到排列中之后将在 finish_insert(从 lp.finish 调用)中完成。

图 11 OpenGauss 内存引擎索引上插入操作代码部分

图 12

在 lp.finish 传入第一个参数为 1 时,调用 finish_insert,finish_insert 函数中实现通过在 permutation 插入新增节点的 index 使得节点对外可见。

5.删除操作
这里只讨论逻辑删除。

逻辑删除和 B+树的类似,但是并不对 key 少的节点进行合并,当节点 key 减少到 0 时,需要标记这个节点为 deleted,然后将其从父节点删除,同时如果是叶节点的话,还需要维护叶节点的双向连接。如果某棵子树为空的话也可以删除整棵子树。当其他线程发现节点处于 deleted 状态时,需要进行重试,因为这个节点逻辑上是不存在的。

图 13

删除操作可能会遇到图 13 的情况,左边的线程根据 k1 定位到了位置 i,在读取 v1 之前这个节点发生了删除位于位置 i 的 k1,同时在位置 j 处插入 k2,如果 i 等于 j,可能导致左边的线程读取到 v2,为了解决这个问题,需要在索引 i 被删除后重新利用时增加节点的 vinsert 域。

图 14 OpenGauss 内存引擎索引上删除操作代码部分

图 15 lp.finish 传入参数为-1 时,调用 finish_remove 函数,通过在 permutation 中删除节点索引已达到逻辑删除作用

标签:索引,引擎,内存,key,openGauss,节点
From: https://www.cnblogs.com/helloopenGauss/p/18121190

相关文章

  • volatility内存取证问题,命令总结,解题思路汇总
    volatility内存取证的简单用法**可以使用kali,windows管理员权限运行.exe程序**一、常用命令格式命令格式:volatility-f文件名--profile=dump的系统版本命令volatility-fwin7.rawimageinfo##检测目标系统信息volatility-fwin7.raw--profile=Win7SPIx64pslist##......
  • 国产开源数据库OpenGauss的安装运行
    步骤一:OpenGauss的安装环境OS:openEuler20.0364bitwithARM架构:arm64部署:单机安装过程1、环境配置安装依赖包:yuminstalllibaio-develflexbisonncurses-develglibc-develpatchreadline-devel2、创建xml配置文件创建cluster_config.xml配置文件并进行配置......
  • vue快速入门(十二)v-key索引标志
    注释很详细,直接上代码新增内容v-key的使用场景数组筛选器的使用源码<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0">&......
  • py脚本实现监控(内存、磁盘、CPU负载)发送邮件
    #!usr/local/python3/bin/python3importsubprocess#引用模块importyagmail#引用模块defsendmail(user,passwd,text,subject,touser):yag=yagmail.SMTP(user=user,password=passwd,host="smtp.163.com"......
  • C语言——动态内存分配
    在学习动态开辟内存之前,我们已经掌握了两种内存分配的方法:inta=10;intarr[10]={0};这两种开辟空间方法的特点:1.开辟空间的大小是固定的2.数组在申明时,必须指定数组的长度,它所需要的内存在编译时分配但有时,我们需要的内存大小在程序运行时才能知道,上述的两种方法......
  • 【C语言】内存分区
    【C语言】内存分区文章目录【C语言】内存分区一、数据类型数据类型概念typedefvoid数据类型sizeof操作符总结二、变量变量的概念变量的修改方式三、程序内存分区模型内存分区栈区堆区全局/静态区常量区四、函数调用模型宏函数函数调用流程调用惯例函数变量传递分析......
  • Redis的前世今生(内存管理、持久化、高可用、集群 详解)一看就懂
    Redis的诞生:    redis的诞生和mysql脱不了关系,在redis还未出现时,用户的每次请求都是直接访问mysql,渐渐的人们发现,请求大部分都是读操作,而且很多都是重复的数据,磁盘的i/o是很慢的,所以人们就想,能不能学学cpu建立的缓存机制,mysql也搞一个缓存,就这样一个基于内存的数据库......
  • Spring内存马分析
    环境搭建踩了很多坑....,不过还好最后还是成功了IDEA直接新建javaEE项目,然后记得把index.jsp删了,不然DispatcherServlet会失效导入依赖:<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId&g......
  • openGauss学习笔记-257 openGauss性能调优-使用Plan Hint进行调优-Custom Plan和Gener
    文章目录openGauss学习笔记-257openGauss性能调优-使用PlanHint进行调优-CustomPlan和GenericPlan选择的Hint257.1功能描述257.2语法格式257.3示例openGauss学习笔记-257openGauss性能调优-使用PlanHint进行调优-CustomPlan和GenericPlan选择的Hint257.......
  • c++内存管理(new、delete)
    目录前言c/c++中程序内存区域划分c++函数之new的使用方法第一个场景:对任意类型动态开辟一个类型大小的空间第二个场景:对任意类型动态开辟多个类型大小的空间第三个场景:在第一、二场景下还需要对数据初始化c++函数之delete的使用方法第一个场景:对任意开辟一个类型大小......