数据库索引回表困难?揭秘PolarDB存储引擎优化技术

引言

数据库系统为了高效地存储、检索和维护数据,采用了多种不同的数据组织结构。不同的组织结构有其特定的用途和优化点,比如提高查询速度、优化写入性能、减少存储空间等。常见的数据库记录组织结构有:

  1. B-Tree

B-Tree是一种平衡的多路搜索树,特别适合存储在外部存储器(如硬盘)中。它通过减少访问磁盘的次数来优化读写操作。B-Tree广泛应用于数据库管理系统和文件系统中,用于存储索引和数据。典型的代表有MySQL。

  1. LSM Tree

LSM Tree是一种适合写入密集型场景的数据结构,通常用于NoSQL数据库中。它将数据更新操作写入内存中的结构,然后定期合并到磁盘上。这种设计充分利用了顺序写能力,大幅度优化了写入性能。使用LSM Tree的佼佼者有LevelDB、HBase等。

  1. Heap Table

Heap Table是一种简单的数据记录组织方式。Heap Table的记录以任意顺序插入到表中,数据的写入性能几乎能达到磁盘写入的上限。但是由于其无序性,数据查询效率不如索引表。为了改进查询性能,Heap Table通常还会搭配如B-Tree这样的索引结构使用。典型的数据库有PostgreSQL。

  1. Skip List跳表

跳表是一种概率性结构,它通过在多层链表上添加“快速通道”的方式来实现快速搜索,实现了平均复杂度为O(log n)的插入、删除和查找操作。同样用于某些版本的 NoSQL数据库中,被用作内存索引的一种有效结构。

每种数据组织结构都有其优势和应用场景。关系型数据库OLTP业务对并发读写、MVCC、空间利用率、高效查找和范围查询、优化磁盘I/O、平衡性等等都要有均衡的诉求,目前PolarDB分布式版采用了B-Tree的索引组织结构。

B-Tree索引中最常用到的是聚簇索引(即主键索引)。通过聚簇索引,查询能够直接找到对应数据行的所有数据。值得注意的是,阿里云瑶池旗下的云原生数据库PolarDB分布式版(PolarDB for Xscale,简称PolarDB-X)存储引擎在聚簇索引上还放入数据行的版本信息。当查询进行时,PolarDB分布式版需要通过比对查询的视图信息以及聚簇索引上行记录的版本信息,来确定查询需要查找的版本记录。当聚簇索引上的当前版本并不满足要求时,需要通过Undo日志把对应记录的历史版本构建出来。

聚簇索引对于主键查询非常有效,然而如果查询的条件并不由主键来决定时,查询需要回退到全量扫描。为了解决这个问题,非聚簇索引被引入。非聚簇索引与聚簇索引很相似,但非聚簇索引有一个重要的区别:

非聚簇索引没有版本信息,即通过非聚簇索引只能查找最新版本。当查找非聚簇索引时,需要首先确认该版本是否为本查询所需要的版本。但由于非聚簇索引上没有版本信息,所以进一步需要通过主键信息查找聚簇索引,以获得版本信息。

通过非聚簇索引查找对应的聚簇索引记录,这个过程通常被称为回表。

下面展示了一个典型的非聚簇索引的使用案例:

年级成绩表(聚簇索引):

640 (2).png

班级-学生号索引(非聚簇索引):

640 (3).png

当查询二班的所有学生号时,虽然只需要查找非聚簇索引即可,但是由于不能确定是否可见,还需要回查聚簇索引上对应的主键记录,确定其真实的版本号信息。

非聚簇索引回表代价

一条SQL语句回表代价取决于回表的频次以及回表本身的开销。

回表本身开销在于B-Tree查找,即一次非聚簇索引记录的查询,需要一次聚簇索引的查询。

回表的频次则取决于SQL语句的类型。特别是对于Range查询:

SELECT sec FROM t1 WHERE sec BETWEEN ? AND ?

当PolarDB分布式版DN存储引擎执行一条SQL时,需要经历开表、B-Tree查找等等阶段,Range查询会显著地增大回表开销的占比,如果每一行记录都需要回表,则会造成严重的性能问题。

在我们的测试数据中发现,全回表相比于不回表,性能有10倍以上的差距

索引回表操作还会对Buffer Pool造成冲击,特别是当Buffer Pool资源紧张时,大量的回表操作会占用了Buffer Pool的空闲页,导致数据库雪崩。

考虑极端情况,如果一张表上几乎没有修改,则因为要判断可见性而带来的回表操作几乎是没有意义的。

通过上面分析可以发现,因为判断可见性而带来的回表,代价是昂贵,且大多数情况下是无必要的。目前单机数据库如MySQL通过引入最小活跃事务号,辅助非聚簇索引的可见性判断,大幅度降低了因为可见性判断而带来的回表问题。

但是,对于PolarDB-X这样的分布式数据库,情况会变得更复杂,这个方案将不再适用。为了解决这个问题,PolarDB分布式版DN存储引擎提出了CSM(Commit Snapshot Manager)方案

下面会介绍单机数据库MySQL的解决方案,并引申到PolarDB分布式版针对分布式场景设计的CSM方案。

单机MySQL非聚簇索引回表优化

为了解决这个问题,MySQL通过引入最小活跃事务号,辅助非聚簇索引的可见性判断,大幅度避免了回表查询的次数,大大降低了查找代价。

事务ID号唯一标识了一个事务。MySQL会维护一个事务ID号生成器。该事务ID号生成器会生成全局唯一单调递增的事务ID号。当事务启动时,都需要从该事务ID号生成器里获取一个事务ID号作为自己的事务标识。

同时,MySQL还维护了一个全局的状态变量:min_active_trx_id。

min_active_trx_id表示所有活跃事务里最小的事务ID号。这意味着,所有事务ID号比min_active_trx_id小的事务都已提交。

除此之外,还会在非聚簇索引的每一个数据页上维护一个特殊的持久化信息:max_trx_id。max_trx_id表示本数据页内所有修改过该数据页的事务里最大的事务ID号。

当查询发起时,会构建一个视图,该视图需要获取当前系统的min_active_trx_id作为视图的up_limit_id。当查找非聚簇索引时,可以通过up_limit_id与数据页的 max_trx_id做比较来确定可见性。相关流程图如下所示:

640.jpg

分布式数据库的索引回表困境

对于分布式数据库,回表问题会被进一步放大。PolarDB分布式版,分布式查询采用基于全局时间戳TSO的MVCC多版本查询。即分布式查询视图的版本号GCN是由外部的全局授时服务生成的TSO来指定,而并非从数据库管理系统里的本地事务系统最新状态获取。

由于网络、系统调度等原因,当分布式查询真正发起时,节点内的事务系统状态可能已经发生过多次变化,事务系统状态最新的min_active_trx_id信息已经不再适用于本次分布式查询GCN视图的构建。

以下面例子为例:

640.png

对于上述发起的分布式查询,实际上由于(snapshot_GCN = 99)<(rec_GCN = 100),所以该记录对于该视图应该是不可见的。

之所以出现上述问题,其核心原因在于,所有的分布式事务的提交顺序并非由本地生成,而是由外部全局协调器统一生成。即多个分布式事务的分支事务在各个节点上的实际提交顺序可能是不同的。

这导致分布式查询的可见性要远比本地单机查询复杂,目前业界内基于单机查询设计的非聚簇索引优化理论,在分布式查询上不再有效。

如何在分布式数据库管理系统里,降低非聚簇索引因为查找版本信息而带来的额外回表代价,是分布式数据库管理系统设计里最关键的问题之一。

Commit Snapshot Manager方案

单机数据库管理系统上非聚簇索引的优化方案,在分布式场景下不再适用的原因是:分布式查询需要的是“彼时彼刻”的min_active_trx_id,但数据库现有的设计只能提供“此时此刻”的min_active_trx_id。

上述说的“时刻”并不是物理时间上的时刻,而是GCN这样的逻辑“时刻”。即:

对于snapshot_GCN = 99的分布式查询,它需要的是DN节点处于GCN = 99时事务系统对应的min_active_trx_id。

一个直观的设想是,如果事务系统维护了过去所有时间点的事务系统状态信息,并且提供能力回查当时时刻的min_active_trx_id状态,则可以解决分布式场景下非聚簇索引因为无法判断可见性而需要回表的问题。

当然这个代价是巨大的,以10万TPS为例,每分钟需要产生至少90 MB的数据。

PolarDB分布式版存储引擎采用了CSM方案来均衡了资源开销与可用性,以极低的代价维护过去时间点的近似min_active_trx_id状态,彻底解决了分布式场景下非聚簇索引频繁回表的问题。CSM是一个环形队列,每间隔一定时间(如 1 秒)则会产生一个Commit Snapshot。更具体地说:

  1. CSM收集开始;
  2. 获取系统当下的min_active_trx_id作为up_limit_id;
  3. 获取系统当下的sys_GCN, sys_SCN为csm_GCN以及csm_SCN;
  4. 将 (up_limit_id, csm_GCN, csm_SCN) 作为一个Commit Snapshot,插入到CSM。

其中,sys_GCN是PolarDB分布式版存储引擎维护的本节点上的最大GCN号。其更新时机为:

  1. 分布式查询由外部协调者指定了snapshot_GCN作为分布式查询视图的GCN,sys_GCN = max { sys_GCN, snapshot_GCN }。
  2. 分布式事务提交由外部协调者指定了commit_GCN作为分布式事务的提交号 GCN,sys_GCN = max { sys_GCN, commit_GCN }。

显然,sys_GCN,min_active_trx_id均满足单调递增永不回退。这意味着:在CSM 环形队列上,csm_GCN、up_limit_id总是有序的。

当分布式查询发起时,根据视图的snapshot_GCN,从CSM尾部开始查找,直到找到 csm_GCN刚好不大于snapshot_GCN的CSM元素,取该元素的up_limit_id作为视图的up_limit_id——我们就得到了我们想要的“彼时彼刻”的up_limit_id。值得注意的是,由于有序性的保证,上述查找可通过二分查找完成。

显然,这个up_limit_id只是“彼时彼刻”真正的up_limit_id的近似值。但通过上述步骤,我们总是能够拿到一个比真实值要小的近似值。幸运的是,当我们拿一个更小的up_limit_id去做可见性判断时,并不会导致误判。

可以看见,上述CSM中的Commit Snapshot还包括了csm_SCN。这是因为PolarDB分布式版标准版还支持了闪回查询AS OF语法。通过闪回查询,可以轻松完成游戏回档、业务回滚、数据误删恢复等特性。有关PolarDB分布式版DN存储引擎的事务系统的设计,可参考过往文章《PolarDB分布式版存储引擎核心技术|Lizard分布式事务系统》。

SELECT sec FROM t1 AS OF SCN $SCN WHERE sec BETWEEN ? AND ?
SELECT sec FROM t1 AS OF TIMESTAMP $time WHERE sec BETWEEN ? AND ?

测试结果显示,对于分布式事务的一致性查询,开启CSM(32KB内存资源 + 少量计算开销)具有显著的性能提升:

# 压测SQL,模拟命中sec列的索引
SELECT sec FROM t1 WHERE sec BETWEEN ? AND ?

640 (1).png

🎉 云原生数据库PolarDB分布式版(PolarDB for Xscale,简称PolarDB-X)价格下调40%,最低至0.75元/小时,点击👉「产品」即可了解详情

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL 数据宝典】【索引原理】- 007 索引优化示例

一、单表优化 1.1 数据准备 下面是一张用户通讯表的表结构信息,这张表来源于真实企业的实际项目中,有接近500万条数据. CREATE TABLE user_contacts (id INT(11) NOT NULL AUTO_INCREMENT,user_id INT(11) DEFAULT NULL COMMENT 用户标识,mobile VARCHAR(50) DEFAULT NULL C…

QT-小项目:连接MY SQL数据库实现登录(下一章实现登录注册账号和忘记密码功能)

一、环境准备 1、下载MYSQL 64位&#xff0c;安装完成&#xff0c;制作简易数据库教程如下&#xff1a; MY SQL安装 2、QT 编译器使用 二、实现工程目录&#xff08;基于上一章基础上&#xff09; 三、源程序增加内容如下&#xff1a; login.cpp 增加头文件&#xff1a; #in…

python代码自动生成器原理 python 生成器原理

python生成器原理剖析 函数的调用满足“后进先出”的原则&#xff0c;也就是说&#xff0c;最后被调用的函数应该第一个返回&#xff0c;函数的递归调用就是一个经典的例子。显然&#xff0c;内存中以“后进先出”"方式处理数据的栈段是最适合用于实现函数调用的载体&…

架空光缆用什么型号

架空光缆是什么意思 , 架空光缆用什么型号的 GYTC8A , 架空光缆型号是啥 8字形光缆 产品描述 Description GYTC8A光缆的结构是将250m光纤套入高模量材料制成的松套管中&#xff0c;松套管内填充防水化合物。缆芯的中心是一根金属加强芯&#xff0c;松套管(和填充绳 )围绕中心…

Davinci工程WrapNv模块讲解

配置讲解 WrapNv模块里面有两个东西&#xff0c;WrapNvGeneral和WrapNvMemoryLayout。 WrapNvGeneral里面配置的就是这个E方的基地址 WrapNvMemoryLayout里面就是分几个块来存储&#xff0c;每个块有自己的数据。 再里面一层&#xff0c;有各自的长度和默认值。我们可以在后面…

常见C语言基础说明二:位运算问题

一. 简介 前面一篇文章学习了 常见的 C语言基础题&#xff0c;文章如下&#xff1a; 常见C语言基础题说明一-CSDN博客 本文继续上一篇C语言基础题的学习。 二. C语言中 -> 位运算问题 1. 数据在计算机中的存储方式 当前的计算机系统使用的基本上是二进制系统&#…

Linux环境Redis部署

Redis部署 Redis是一个高性能的开源键值存储系统&#xff0c;它主要基于内存操作&#xff0c;但也支持数据的持久化。与其他数据库相比&#xff0c;Redis的主要优势在于它的高性能、丰富的数据结构和原生的持久化能力。Redis不仅提供了类似的功能&#xff0c;还增加了持久化和…

命令行方式将mysql数据库迁移到达梦数据库(全步骤)

因项目需求&#xff0c;需要将mysql数据库转换为国产达梦数据库&#xff0c;但由于安全问题&#xff0c;正式环境只能用命令行方式连接&#xff0c;下列是操作全步骤 目录 一、操作逻辑二、操作步骤1、本地安装达梦相关工具2、将服务器mysql导出到本地a) 服务器命令行导出mysql…

改进灰狼算法优化随机森林回归预测

灰狼算法&#xff08;Grey Wolf Optimization&#xff0c;GWO&#xff09;是一种基于自然界灰狼行为的启发式优化算法&#xff0c;在2014年被提出。该算法模仿了灰狼群体中不同等级的灰狼间的优势竞争和合作行为&#xff0c;通过不断搜索最优解来解决复杂的优化问题。 灰狼算法…

图:广度优先遍历(BFS)和深度优先遍历(DFS)

1.工具类&#xff1a;队列和字典 export class DictionNary {// 字典的封装constructor() {this.items {}}set(key, value) {// 添加键this.items[key] value}has(key){// 判断键是否存在return this.items.hasOwnProperty(key)}get(key){// 获取键的valuereturn this.has(k…

利用github pages建立Serverless个人博客

利用github pages建立Serverless个人博客 概述 使用github pages&#xff0c;可以在github上部署静态网站。利用这个功能&#xff0c;可以很方便地实现个人博客的发布托管。 比如我的个人博客&#xff1a;Buttering’s Blog 对应代码仓库&#xff1a;buttering/EasyBlog: 自…

MT3516W-ASEMI工业电源专用MT3516W

编辑&#xff1a;ll MT3516W-ASEMI工业电源专用MT3516W 型号&#xff1a;MT3516W 品牌&#xff1a;ASEMI 封装&#xff1a;MTW-5 最大重复峰值反向电压&#xff1a;1600V 最大正向平均整流电流(Vdss)&#xff1a;35A 功率(Pd)&#xff1a;大功率 芯片个数&#xff1a;5…

程序员不会告诉老板的那些神器

目录 1. 持续集成工具&#xff1a;CruiseControl&#xff08;简称CC&#xff09; 2. 代码风格、质量检查工具&#xff1a;StyleCop 3.AI工具 3.1 AI助力编写开发日报 3.2 AI助力编写普适性代码 3.3 AI助力生成代码注释 3.4 AI助力重构代码去掉“坏味道” 3.5 AI助力…

汽车品牌区域营销方案

领克汽车粤海区域营销方案-36P 活动策划信息&#xff1a; 方案页码&#xff1a;36页 文件格式&#xff1a;PPT 方案简介&#xff1a; 车市反弹形势明显&#xff0c;领克销量呈现稳健上涨趋势 品牌 未来市场可观&#xff0c;应 持续扩大品牌声量&#xff0c;保持市场占有优…

【C++】C++11--- lambda表达式

目录 Lambda表达式概述 Lambda表达式语法定义 Lambda表达式参数详解 Lambda捕获列表 捕获列表总结 Lambda参数列表 可变规则mutable lambda表达式原理 Lambda表达式概述 当对自定义类型的数据集合进行排序时&#xff0c;需要根据自定义类型的不同属性去实现不同的排序方…

ESD静电问题 | 手持摄像头整改

【转自微信公众号&#xff1a;柯普伦科技】

用webui.sh安装报错No module named ‘importlib.metadata‘

安装sdweb报错&#xff0c;出现No module named importlib.metadata&#xff1a; glibc version is 2.35 Cannot locate TCMalloc. Do you have tcmalloc or google-perftool installed on your system? (improves CPU memory usage) Traceback (most recent call last):File…

访问网络附加存储:nfs

文章目录 访问网络附加存储一、网络附加存储1.1、存储类型1.3、通过NFS挂载NAS1.4、NFS挂载过程服务端客户端 二、实验&#xff1a;搭建NFS服务端及挂载到nfs客户端服务端客户端测试命令合集服务端客户端 访问网络附加存储 一、网络附加存储 1.1、存储类型 DAS&#xff1a;Di…

TCP四次挥手中为什么 TIME_WAIT 等待的时间是 2MSL?

TCP 连接断开 1、TCP 四次挥手过程是怎样的&#xff1f;如下图 2、为什么 TIME_WAIT 等待的时间是 2MSL&#xff1f; MSL 是 Maximum Segment Lifetime&#xff0c;报文最大生存时间&#xff0c;它是任何报文在网络上存在的最长时间&#xff0c;超过这个时间报文将被丢弃。因…

激光雷达技术:科技之眼,照亮前行

在科技与人文关怀的交响乐章中&#xff0c;一项名为“蝙蝠避障”使用了激光雷达技术原理及应用的创新成果&#xff0c;正悄然改变着视障朋友们的生活方式&#xff0c;为他们的日常出行铺设了一条充满希望的光明之路。今天&#xff0c;让我们一起深入探讨这项技术如何成为盲人出…