关于数据库:研发分享StoneDB如何给Tianmu引擎增加delete功能调研之旅

29次阅读

共计 3831 个字符,预计需要花费 10 分钟才能阅读完成。

StoneDB 作为开源我的项目,始终秉持开源凋谢的根本准则,咱们的社区版代码当初曾经齐全在 Github 上开源,并一直进步代码的可读敌对性,同时,为了让大家更好地了解咱们是如何打造一款一体化 HTAP 开源数据库的,咱们会定期把一些核心技术的研发实现思路分享给大家,也算是抛砖引玉,如果读者有更好的实现思路,也欢送与咱们沟通,甚至能够参加到咱们社区版的开发中~

Tianmu 引擎是 StoneDB 团队自研的一款列式存储引擎,在 6 月初刚开源时,并不反对 delete 性能,对此很多用户都提出了需要的意见,所以咱们过后也把 delete 性能列入到咱们的年度 Roadmap 里了,预计在 10 月 20 号的 StoneDB_5.7_v1.0.1 正式版本中,上线此性能。第一期,我将分享一下对 delete 性能的调研状况。

前置常识:数据库中删除数据的三种形式
以 Mysql 5.7 为例,数据库删除数据的形式一共有三种:

  1. delete
  2. truncate
  3. drop

以上三种形式都能够删除数据,然而应用场景是不同的。

对于整个表进行删除的执行速度来说:

drop > truncate >> delete

DELETE

delete 是属于数据库的 DML 操作语言,个别是依据条件逐行进行删除。

应用 delete 删除数据时,数据库只能删除数据不能删除表的构造,并且会触发数据库的事务机制。

delete 执行时,会先将所删除数据缓存到 rollback segment 中,事务 commit 之后失效。

在 InnoDB 中,应用 delete 其实并不会真正的把数据删除,是一种逻辑删,数据库底层实际上只是给删除的数据做了一个已删除的标记,因而,删除数据后的表占空间大小和删除前是一样的。

TRUNCATE

truncate 属于数据库 DDL 定义语言,不走事务,原数据不放到 rollback segment 中,操作不触发 trigger。执行后立刻失效,无奈找回(慎用 删除执行后,数据就没了,不可复原)。

truncate 删除表会立即开释磁盘空间。truncate table 其实有点相似于 drop table 而后 create, 只不过这个 create table 的过程做了优化,比方表构造文件之前曾经有了等等。所以速度上是靠近 drop table 的速度;

DROP

drop 属于数据库 DDL 定义语言,同 truncate,执行后立刻失效,无奈找回。

drop table table_name 立即开释磁盘空间,drop 语句将删除表的构造、被依赖的束缚(constraint)、触发器(trigger)、索引(index);依赖于该表的存储过程 / 函数将保留, 然而变为 invalid 状态。

Tianmu 引擎对 delete 性能的调研
Tianmu 是一个列式存储引擎,列式存储的呈现次要是为了方便快捷查问和高效存储大量同类型的数据而设计的,次要应用场景就是 OLAP。上面是 OLAP 场景的局部要害特色:

  • 绝大多数是读申请。
  • 数据以相当大的批次 (> 1000 行) 更新,而不是单行更新; 或者基本没有更新。
  • 已增加到数据库的数据不能批改。
  • 对于读取,从数据库中提取相当多的行,但只提取列的一小部分。
  • 列中的数据绝对较小:数字和短字符串(例如,每个 URL 60 个字节)。
  • 解决单个查问时须要高吞吐量(每台服务器每秒可达数十亿行)。
  • 事务不是必须的。
  • 对数据一致性要求低。

而 OLAP 场景下,对于数据的 delete 的操作能够说没有或者频率很小。列式存储比照行式存储来说并不善于数据的增删改,如果是为了极致的查问性能,齐全能够舍弃 DML 操作(比方初期的 ClickHouse 也不反对 delete)。然而为了性能的完整性,咱们初期就放开了 insert 和 update 的性能,不过没有对 delete 性能进行反对。

随着用户的呼声越来越多,咱们开始对各个有列式存储的数据库进行了一个调研,如下表所示:

目前行业现状

通过剖析目前行业内反对列式存储的支流数据库,大部分都是反对的,就算不反对间接 delete, 也是反对 DML 同步的,所以 Tianmu 引擎的 delete 性能的确有必要进行开发反对。

支流列式数据库的 delete 计划

openGauss

存储构造

openGauss 列存储引擎的底层存储构造与 Tianmu 引擎相似,存储根本单位是 CU(Compression Unit,压缩单元),即表中一列的一部分数据组成的压缩数据块。行存引擎中是以行作为单位来治理,而当应用列存储时,整个表整体被依照不同列划分为若干个 CU。

每个 CU 对应一个 CUDesc 的记录,在 CUDesc 里记录了整个 CU 的事务工夫戳信息、CU 的大小、存储地位、magic 校验码、min/max 等信息。

每张列存表还配有张 Delta 表,Delta 表本身为行存储表。当有大量的数据插入到一张列存表时,数据会被临时放入 Delta 表,等达到阈值或满足肯定条件或操作时再行整合为 CU 文件。Delta 表能够防止单点数据操作带来的很重的 CU 操作与开销。

delete 策略

CU 中数据的删除,实际上是标记删除。删除操作,相当于是更新了 CUDesc 表中 CU 对应 CUDesc 记录的 delete bitmap(删除位图)构造,标记列中某行对应数据已被删除,而 CU 文件数据不会被更改。这样能够防止删除操作带来的 IO 放大以及解压、压缩的高额 CPU 开销。这样的设计,也能够使得对于同一个 CU 的 select(查问)和 delete(删除)互不阻塞,晋升并发能力。列存储 CU 中数据更新,则是遵循 append-only(仅容许追加)准则的,即 CU 文件仅会向后进行延展裁减,亦或是启用新的 CU 文件,而不是在对应行在 CU 中的地位就地更新。

ClickHouse

存储构造

ClickHouse 反对在建表时,指定将数据依照某些列进行 sort by。排序后,保障了雷同 sort key 的数据在磁盘上间断存储,且有序摆放。在进行等值、范畴查问时,where 条件命中的数据都严密存储在一个或若干个间断的 Block 中,而不是扩散的存储在任意多个 Block,大幅缩小须要 IO 的 block 数量。另外,间断 IO 也可能充分利用操作系统 page cache 的预取能力,缩小 page fault。

delete 策略

特点:短少高频率,低提早的批改或删除已存在数据的能力。仅能用于批量删除或批改数据。

ClickHouse 是个剖析型数据库。OLAP 场景下,数据个别是不变的,因而 ClickHouse 对 update、delete 的反对是比拟弱的,实际上并不反对规范的 update、delete 操作。

ClickHouse 通过 alter 形式实现更新、删除,它把 update、delete 操作叫做 mutation(渐变)。

规范 SQL 的更新、删除操作是同步的,即客户端要等服务端返回执行后果(通常是 int 值),而 ClickHouse 的 update、delete 是通过异步形式实现的,当执行 update 语句时,服务端立刻返回,然而实际上此时数据还没变,而是排队等着。

Mutation 具体过程

首先,应用 where 条件找到须要批改的分区;而后,重建每个分区,用新的分区替换旧的,分区一旦被替换,就不可回退;对于独自一个分区,是原子性的;但对于整个 mutation,如果波及多个分区,则不是原子性的。

PolarDB In-Memory Column Index

存储构造

特点:PolarDB 将列存实现为 InnoDB 的二级索引。
在 PolarDB 中所有 Primary Index 和 Secondary Index 都实现为一个 B+Tree。列索引在定义上是一个 Index,但其实是一个虚构的索引,用于捕捉对该索引笼罩列的增删改操作。

实现为 InnoDB 二级索引计划的长处:

  • 查问执行器的工程实现非常简单
  • 能够复用 InnoDB 的事务处理框架
  • 能够复用 InnoDB 的数据编码格局
  • DDL 语句操作非常灵活
  • 能够复用 InnoDB 的 Redo 事务日志模块
  • 二级索引与主表有一样的生命周期,方便管理

PolarDB In-Memory Column Index 的存储应用了无序且追加写的格局。

列索引中记录按 RowGroup 进行组织,每个 RowGroup 中不同的列会各自打包造成 DataPack。

每个 RowGroup 都采纳追加写,分属每个列的 DataPack 也是采纳追加写模式。

对于一个列索引,只有个 Active RowGroup 负责承受新的写入。

当该 RowGroup 写满之后即解冻,其蕴含的所有 DataPack 会转为压缩格保留到磁盘上,同时记录每个数据块的统计信息便于过滤。

列存 RowGroup 中每新写入一行都会调配一个 RowID 用作定位,属于一行的所有列都能够用该 RowID 计算定位,同时系统维护 PK 到 RowID 的映射索引,以反对后续的删除和批改操作。

delete 策略

在 PolarDB In-Memory Column Index 中,删除操作只须要设置一个删除标记位。更新操作采纳标记删除的形式来反对,对于更新操作,首先依据 RowID 计算出其原始地位并设置删除标记,而后在 ActiveRowGroup 中写入新的数据版本。

当一个 RowGroup 中的有效记录超过肯定阈值,则会触发后盾异步 compaction 操作,其作用一方面是回收空间,另一方面能够让无效数据存储更加紧凑,晋升剖析型查问的效率。

各列式存储的 delete 计划汇总

好了,以上就是我对 delete 性能的一个调研状况,下一期我将分享一下,Tinamu 引擎实现 delete 的具体思路。

作者:李红建(空海)

编辑:宇亭

正文完
 0