乐趣区

关于数据库:StoneDB研发日志列式存储-delete方案调研

MySQL 删除数据的形式

以 MySQL 5.7 为例,数据库删除数据的形式一共有以下三种:

  1. delete
  2. truncate
  3. drop

以上三种形式都能够删除数据,然而应用场景是不同的。
对于整个表进行删除的执行速度来说:
drop > truncate >> delete

MySQL 删除数据的形式 -delete

delete 是属于数据库的 DML 操作语言,个别是依据条件逐行进行删除。
应用 delete 删除数据时,数据库只能删除数据不能删除表的构造,并且会触发数据库的事务机制。
delete 执行时,会先将所删除数据缓存到 rollback segment 中,事务 commit 之后失效;
在 InnoDB 中,应用 delete 其实并不会真正的把数据删除,是一种逻辑删,数据库底层实际上只是给删除的数据做了一个已删除的标记,因而,删除数据后的表占空间大小和删除前是一样的.

MySQL 删除数据的形式 -drop

drop 属于数据库 DDL 定义语言,同 truncate,执行后立刻失效,无奈找回。
drop table table_name 立即开释磁盘空间 ,drop 语句将删除表的构造、被依赖的束缚(constraint)、触发器(trigger)、索引(index); 依赖于该表的存储过程 / 函数将保留, 然而变为 invalid 状态。

删除数据的形式 -TianMu 引擎的反对状况

目前 StoneDB 的 TianMu 引擎是反对 truncate 语句 和 drop 语句的,然而 delete 语句目前还不反对。

TianMu 引擎须要不须要 delete?

TianMu 引擎设计的初衷

TianMu 是一个列式存储引擎,列式存储的呈现次要是为了方便快捷查问和高效存储大量同类型的数据而设计的, 次要应用场景就是 OLAP 场景。上面是 OLAP 场景的局部要害特色:
①绝大多数是读申请
②数据以相当大的批次(> 1000 行) 更新,而不是单行更新; 或者基本没有更新。
③已增加到数据库的数据不能批改。
④对于读取,从数据库中提取相当多的行,但只提取列的一小部分。
⑤列中的数据绝对较小:数字和短字符串(例如,每个 URL 60 个字节)
⑥解决单个查问时须要高吞吐量(每台服务器每秒可达数十亿行)
⑦事务不是必须的
⑧对数据一致性要求低

目前行业现状

反对列存储的数据库类型 是否反对 delete 备注
MariaDB ColumnStore 反对
SQL Server 反对
Oracle In-Memory Column Store 反对
DB2 BLU Acceleration 反对
MySQL HeatWave 不反对 次要作为辅助引擎,反对 DML 同步
TiFlash 不反对 次要作为辅助引擎,反对 DML 同步
PolarDBIn-Memory Column Index 反对
openGauss 反对
ClickHouse 反对 非标准的 DELETE 操作

OLAP 场景下 对于数据的 delete 的操作能够说没有或者频率很小,同时列式存储比照行式存储来说并不善于数据的增删改,如果是为了极致的查问性能,齐全能够舍弃 DML 操作。然而为了性能的完整性,晋升产品的竞争力,目前咱们也放开了 insert 和 单表的 update 的性能,delete 性能临时还不反对, 将来咱们将对改性能进行反对。

支流列式数据库的 delete 计划

本节次要讲以下三种列式存储数据库的 delete 计划:
openGauss
ClickHouse
PolarDB

openGauss 列存储引擎的计划

底层存储构造

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

CU 文件自身构造,则如下图所示。

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

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

删除策略

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

生效空间的清理

  • 因为 CU 以及 CUDesc 的元数据管理模式,原有零碎中的 Vacuum 机制实际上并不会十分无效的革除 CU 中曾经生效的存储空间,因为 Lazy Vacuum(清理数据时,只是标识无用行的状态能够录入新数据,不会影响对表数据的操作)仅能在 CUDesc 级别进行操作,在少数场景下无奈对 CU 文件自身进行清理。列存储外部如果要对列存数据表进行清理,须要执行 Vacuum Full(除了清理无用行,还会合并数据块,整个过程会锁定表)操作。

    ClickHouse delete 计划

    特点:短少高频率,低提早的批改或删除已存在数据的能力。仅能用于批量删除或批改数据。
    数据有序存储
    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,但其实是一个虚构的索引,用于捕捉对该索引笼罩列的增删改操作。

    如上图所示,在 PolarDB 中所有 Primary Index 和 Secondary Index 都实现为一个 B +Tree。而列索引在定义上是一个 Index,但其实是一个虚构的索引,用于捕捉对该索引笼罩列的增删改操作。
    对于下面的表其主表 (Primary Index)蕴含(C1,C2,C3,C4,C5) 5 列数据, Seconary Index 索引蕴含(C2,C1) 两列数据, 在一般二级索引中,C2 与 C1 编码成一行保留在 B +tree 中。而其中的列存索引蕴含(C2,C3,C4) 三列数据. 在理论物理存储时,会对三列进行拆分独立存储,每一列都会按写入程序转成列存格局。
    列存实现为二级索引的另一个益处是执行器的工程实现非常简单,在 MySQL 中曾经存在笼罩索引的概念,即一个查问所须要的列都在一个二级索引中存储,则能够间接利用这个二级索引中的数据满足查问需要,应用二级索引绝对于应用 Primary Index 能够极大缩小读取的数据量进而晋升查问性能。当一个查问所须要的列都被列索引笼罩时,借助列存的减速作用,能够数十倍甚至数百倍的晋升查问性能。

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

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

    列存数据组织

    对 ColumnIndex 中每一列,其存储都应用了无序且追加写的格局,联合标记删除及后盾异步 compaction 实现空间回收。其具体实现上有如下几个关键点:
    列索引中记录按 RowGroup 进行组织,每个 RowGroup 中不同的列会各自打包造成 DataPack。
    每个 RowGroup 都采纳追加写,分属每个列的 DataPack 也是采纳追加写模式。对于一个列索引,只有个 Active RowGroup 负责承受新的写入。当该 RowGroup 写满之后即解冻,其蕴含的所有 Datapack 会转为压缩格保留到磁盘上,同时记录每个数据块的统计信息便于过滤。
    列存 RowGroup 中每新写入一行都会调配一个 RowID 用作定位,属于一行的所有列都能够用该 RowID 计算定位,同时系统维护 PK 到 RowID 的映射索引,以反对后续的删除和批改操作。
    删除操作只须要设置一个删除标记位。
    更新操作采纳标记删除的形式来反对,对于更新操作,首先依据 RowID 计算出其原始地位并设置删除标记,而后在 ActiveRowGroup 中写入新的数据版本。
    当一个 RowGroup 中的有效记录超过肯定阈值,则会触发后盾异步 compaction 操作,其作用一方面是回收空间,另一方面能够让无效数据存储更加紧凑,晋升剖析型查问单的效率。

    delete 策略

    删除操作只须要设置一个删除标记位。
    更新操作采纳标记删除的形式来反对,对于更新操作,首先依据 RowID 计算出其原始地位并设置删除标记,而后在 ActiveRowGroup 中写入新的数据版本。
    当一个 RowGroup 中的有效记录超过肯定阈值,则会触发后盾异步 compaction 操作,其作用一方面是回收空间,另一方面能够让无效数据存储更加紧凑,晋升剖析型查问的效率。

    各列式存储的 delete 计划汇总

    反对列存储的数据库类型 存储构造 Delete 策略
    MariaDB ColumnStore 固定大小的数据块 + 元数据 标记删除
    SQL Server 列存储索引 + 行组 + 列段 标记删除
    PolarDB In-Memory Column Index 列存储索引 +RowGroup+DataPack+ 元数据 标记删除
    openGauss 元数据 + 数据包 标记删除
    ClickHouse 有序存储 + 分区数据包 新建分区替换

TianMu 引擎 delete 性能布局

GitHub issue 链接:
https://github.com/stoneatom/stonedb/issues/343

TianMu 引擎 delete 性能实现流程图

退出移动版