如何从列式数据库中读取编码数据,例如Vertica 中的 RLE 编码数据?

How is encoded data read from a columnar database e.g. RLE encoded data in Vertica?

下面table在对Dept字段中的Data进行编码存储时,值为10的Dept如何知道其Age值为38。

ID部门年龄

1 10 60

2 10 38

3 10 49

对于行存储,我知道我检查 ID 2 并获取整行的数据。

但是当 ID 2 在列式存储中且部门信息采用编码形式时,我无法完全理解如何为 ID 2 检索数据。

如果我遗漏了一些明显的东西,你能帮我理解一下吗?

首先,让我们考虑未编码形式的柱状数据:

值为 2 的

ID 是列中的第二个元素,因此要获得 DeptAge,需要做的就是获取它们的第二个元素。

现在以编码(压缩)形式,您可以查看范围内的数据。例如 Dept 可以编码为 3*10,因此范围 1-3 的值为 10。要检索 Dept 中的第二个元素,数据库必须查找包含第二个元素的范围元素。那将是范围 1-3,其值为 10。

或者换一种方式看:要以顺序的方式在位置 4 处获取 Dept,系统会看到有一组 3 个元素被压缩成 1 个值,所以该组之后的项目 (这可能是一组新的相同值)将包含第四个元素的值。

为了加快速度,系统当然会保留一个索引,其中的位置能够(半)直接跳到某个范围的值(那些 ranges/groups 将存储在块中,例如,每个 1-8 kB - 在 B+ Tree 中,尤其是当需要稍后插入值时)。

另一种可能性是将这些组(范围值及其 rle 前缀)存储在块中,跟踪每个块的第一个和(或唯一)最后一个项目索引,并解压缩包含值的块我们正在寻找的索引。然后计算该解压块中项目的偏移量。这将取决于用于在该块中存储数据的压缩类型。


另一方面,在大多数情况下,我们不需要记录中的所有数据,这就是基于列的数据存储如此有趣的原因。

让我们考虑一个 table 有 10 亿条记录,每条 200 字节(字符串数据等)和一个有 10 GB 空闲 RAM 的系统(我把记录的数量足够大所以 table 不适合内存)。所以这是 200 GB 的数据。

现在假设我们想要某一列(4 字节整数列)的总和。要计算基于 table 的记录的总和,我们必须每 200 字节读取一次该值,并且由于数据是以 4kB 页面从磁盘读取的,我们必须读取完整的 200GB。在 100MB/秒的普通磁盘上需要 2000 秒。

如果我们将数据按列分隔,即使使用未压缩的数据,我们也只需要读取 4GB 的数据(可能已经在内存中)。如果列被压缩,比如 10:1,那将只有 400MB。如果数据稀疏(比如很多零值或空值),那会更少。此外,要对 100 个相同值的范围求和,所有需要做的就是 100*value 而不是从磁盘读取 100*200 字节,如果它们为零,甚至跳过该范围。

还有一个额外的速度增益,因为所有数据(所有值都靠近)将从 L1 CPU 缓存访问,这比访问主内存快得多。

首先:Vertica 使用了很多不同的encoding types。 RLE 只是可能的选项之一(适用于低基数,sorted 列)。请记住,某些编码可以减少存储大小(很多)但会增加 CPU 使用率。

第二个:如果你想看"RLE in action"请查看手册的this other section提供清晰简洁的解释(我认为图片有很大帮助).

第三个:在您的示例中table 选择正确的编码——就存储而言——非常容易。例如,如果前两列已排序,我会对第一列说 COMMONDELTA_COMP,对第二列说 RLE。但是 - 一般来说 - 当您有大量数据时,您可能希望使用 Vertica 的数据库设计器自动选择 "right" 编码...

这里没什么好理解的!数据表示与 Vertica 将数据写入文件系统的方式无关。

编码用于优化数据获取过程。

对于基于行的和基于列的,ROWKEY(内部数据库)的概念对两者都是一样的 ROWKEY 由您的数据库引擎和 "it works in mysterious ways" :)

维护

简写编码用于写入和读取,您不会看到编码的二进制代码,您将看到编码数据的表示。