MARS3 存储引擎在 MARS2 基础上进行多项优化,采用行列结合的存储方式,同时实现数据的高速写入与极限压缩。
MARS3 支持通过 UPDATE
与 DELETE
子句实现数据更新与删除(Unique Mode 模式除外)。
MARS3 支持增删列,支持 COPY
、pg_dump
操作。
对于每个 MARS3 单表而言,其内部均采用 LSM Tree 结构存储。LSM Tree(Log Structured Merge Tree)是一种分层的,有序的,面向磁盘的数据结构。其核心思想是充分利用磁盘性能进行批量的顺序写操作,性能远高于随机写。
MARS3 内部原理图如下:
我们将以概念逐层剖析的形式来解读上图。
prefer_load_mode
参数设置加载模式,详见下文配置项。rowstore_size
参数配置)的大小可以灵活的进行调节,以适应不同场景达到最优性能。CREATE INDEX brin_idx ON t1 USING mars3_brin(time,tag_id);
Dead
的数据,当然你也可以有计划地定期使用 VACUUM
清理已 Dead
的数据。INSERT
写入到内存中,再写入 L0 的 Run 中。DELETE
进行删除,删除会在对应 Run 的 Delta 文件中进行记录,在进行 Run 合并的时候真正把数据删除。UPDATE
进行更新,更新会先删除原本数据,再重新插入一条新数据。UPDATE
子句,直接执行 INSERT
子句即可自动完成操作。如果想要更新某个 Unique Key(即建表时指定的排序键所对应的具体键值)对应的某条数据,直接插入一条相同 Unique Key 的新数据即可。例如 CREATE TABLE mars3_t(c1 int NOT NULL, c2 int) USING MARS3 WITH (uniquemode=true) ORDER BY (c1, c2);
,其中 Unique Key 即为 (c1, c2)
。注意!
如开启 Unique Mode,则ORDER BY
子句的第一个字段在定义时需要添加NOT NULL
约束。
在已创建 matrixts
扩展的前提下,最简洁的建表方式,只需要在 CREATE TABLE
语句加上 USING
子句,并附加 ORDER BY
子句。延伸示例请见表设计最佳实践。
=# CREATE TABLE metrics (
ts timestamp,
dev_id bigint,
power float,
speed float,
message text
) USING MARS3
ORDER BY (dev_id,ts);
注意!
MARS3 表支持创建 Brin 索引,但非必须创建;MARS3 表建表时必须使用ORDER BY
子句制定排序键。
注意!
此部分配置项为表级配置项,只能在创建数据表时使用WITH(mars3options='a=1,b=2,...')
子句配置(MARS2 同样支持的参数compress_threshold
除外,直接使用WITH
子句配置即可),适用于单表,且一旦配置便无法修改。更多信息请见 数据表配置参数。
以下参数用于调节 L0 层 Run 的大小,也可间接控制 L1 层之上的 Run 大小。
参数 | 单位 | 默认值 | 取值范围 | 描述 |
---|---|---|---|---|
rowstore_size | MB | 64 | 8 ~ 1024 | 用于控制 L0 Run 何时切换。当数据大小超过该值,将会切换下一个 Run |
以下参数用于设置压缩阈值,可用于调节压缩效果和改善读取效率,如果配置过低压缩效果不明显,配置过高消耗内存较多。
参数 | 单位 | 默认值 | 取值范围 | 描述 |
---|---|---|---|---|
compress_threshold | 元组 | 1200 | 1 ~ 100000 | 压缩阈值。用于控制单表每一列的多少元组(Tuple)进行一次压缩,是同一个单元中压缩的 Tuple 数上限 |
以下参数用于指定数据在 MARS3 中的加载模式。
参数 | 单位 | 默认值 | 取值范围 | 描述 |
---|---|---|---|---|
prefer_load_mode | normal | normal / bluk | 数据加载模式。normal 表示正常模式,新写入数据先写到 L0 层的行存 Run 中,积累到 rowstore_size 之后,落至 L1 层的列存 Run,相对于 bulk 模式会多一次 I/O,列存转换由同步变成了异步,但适用于 I/O 能力充足且对延迟敏感的高频次小批量写入场景;bluk 表示批量加载模式,适用于低频大批量写入场景,直接写至 L1 层的列存 Run,相对于 normal 模式,减少了一次 I/O,列存转换由异步变成了同步,适用于 I/O 能力不足且对延迟不敏感的低频大批量的数据写入 |
以下参数用于指定 Level 尺寸的放大系数。
参数 | 单位 | 默认值 | 取值范围 | 描述 |
---|---|---|---|---|
level_size_amplifier | 8 | 1 ~ 1000 | Level 尺寸的放大系数。Level 触发合并操作的阈值,计算方式为:rowstore_size * (level_size_amplifier ^ level) 。其值越大,读速越慢,写速越快。可以根据具体场景信息(写多读少/读多写少、压缩率等)来决定具体值。注意:确保每个 Level 的 run 数量不要过多,否则会影响查询性能,甚至阻止新数据插入 |
配置示例:
=# CREATE TABLE metrics (
ts timestamp,
dev_id bigint,
power float,
speed float
) USING MARS3
WITH (compress_threshold=1200,mars3options='rowstore_size=64',compresstype=zstd, compresslevel=1)
DISTRIBUTED BY (dev_id)
ORDER BY (dev_id,ts)
PARTITION BY RANGE (ts)
( START ('2023-07-01 00:00:00') INCLUSIVE
END ('2023-08-01 00:00:00') EXCLUSIVE
EVERY (INTERVAL '1 day')
,DEFAULT PARTITION OTHERS);
matrixts_internal.mars3_level_stats
:查看 MARS3 表每一个 Level 层级的状态,据此可以判断 MARS3 表的健康度,例如 Run 有没有按预期的进行合并,其个数是否符合预期等;matrixts_internal.mars3_files
:查看 MARS3 表文件状态,可以用来查看 MARS3 表的扩展文件和增量文件(Data 文件、Delta 文件、Index 文件等)是不是符合预期;matrixts_internal.mars3_info_brin
:查看 MARS3 表某个 Brin 索引的状态。MARS2 存储引擎主要是面向数据高速加载和查询而设计的,其内部采用有序存储省却搜索。
MARS2 表与 MARS3 相同,也采用 LSM Tree 结构存储。
MARS2 内部原理图如下:
我们将以概念逐层剖析的形式来解读上图。
COLLATE C
能够加速排序。mars2_automerge_threshold
),触发 L0 合并,将 L0 所有的 Runs 合并为一个 Run。level0_upgrade_size
),则将其升级到 L1。level1_upgrade_size
),则触发合并,L1 的所有 Runs 合并为一个 Run。level1_upgrade_size
),则将其升级到 L2。首先创建 matrixts
扩展:
=# CREATE EXTENSION matrixts ;
显式声明记录最小最大值。
=# CREATE TABLE metrics (
ts timestamp ENCODING(minmax),
dev_id bigint ENCODING(minmax),
power float,
speed float,
message text
) USING MARS2;
创建 mars2_btree
索引。
=# CREATE INDEX ON metrics
USING mars2_btree (ts, dev_id);
同 MARS3。
INSERT
写入到内存中,之后经历这些过程,生成一个 Run。TRUNCATE
分区表完成。在已创建 matrixts 扩展的前提下,最简洁的建表方式,只需要在 CREATE TABLE 语句加上 USING
子句,并创建索引即可。延伸示例请见表设计最佳实践。
=# CREATE TABLE metrics (
ts timestamp,
dev_id bigint,
power float,
speed float,
message text
) USING MARS2;
=# CREATE INDEX ON metrics
USING mars2_btree (ts, dev_id);
注意!
下述内容中表级配置项,指的是只能在创建数据表时使用WITH
子句配置,适用于单表,且一旦配置便无法修改的配置项。全局配置项指的是可在会话或系统级别配置,系统级别的修改需要执行mxstop -u
才能生效的配置项。更多信息请见 数据表配置参数。
以下几个参数用于控制合并(Merge),其影响合并的方式见上文 Level 部分。
合并控制参数 | 单位 | 默认值 | 取值范围 | 描述 |
---|---|---|---|---|
mars2_automerge_threshold | run | 32 | 10 - 2048 | 用于控制 所有 的 MARS2 表,L0 达到多少个 Run 触发合并,为全局配置项。如果要为表单独指定可以使用表选项 level0_merge_threshold |
level0_merge_threshold | run | 32 | 1 - 2048 | 用于控制单表 L0 达到多少个 Run 触发合并,为表级配置项 |
level0_upgrade_size | MB | 25 | 1 - 10000 | 控制单表 L0 -> L1 升级的大小,当 L0 发生合并后结果 Run 超过这个大小将升级到 L1,为表级配置项 |
level1_upgrade_size | MB | 1000 | 1 - 10000 | 控制单表 L1 -> L2 升级的大小,当 L1 发生合并后结果 Run 超过这个大小将升级到 L2,为表级配置项 |
以下参数用于压缩控制,调节压缩效果,如果配置过低压缩效果不明显,配置过高消耗内存较多。
压缩控制参数 | 单位 | 默认值 | 取值范围 | 描述 |
---|---|---|---|---|
compress_threshold | 元组 | 1200 | 1 - 100000 | 压缩阈值。用于控制单表多少元组(Tuple)进行一次压缩,是同一个单元中压缩的 Tuple 数上限,为表级配置项 |
以下参数用于内存控制。这部分参数控制插入数据时,使用的排序内存的大小,当有多张分区表被插入时,每个分区表会分配 mars2_sort_mem_core
配置的内存;如果不够用则扩大,但总量不会超过 mars2_sort_mem
。
排序内存参数 | 单位 | 默认值 | 取值范围 | 描述 |
---|---|---|---|---|
mars2_sort_mem | KB | 2097152KB(2GB) | 128KB - 2147483647KB (~ 2048GB) | 控制每一个单个插入的排序内存大小,如果插入目标表是分区表,它们将共享这个大小,为全局配置项 |
mars2_sort_mem_core | KB | 16384KB(16MB) | 128KB - 2147483647KB (~ 2048GB) | 控制每一个单个分区表至少分配多少排序内存,为全局配置项 |
表配置项示例:
=# CREATE TABLE metrics (
ts timestamp,
dev_id bigint,
power float,
speed float,
message text
)
USING MARS2
WITH (compress_threshold=1200,level0_merge_threshold=32);
=# CREATE INDEX ON metrics
USING mars2_btree (ts, dev_id);
全局配置项在会话级别修改值示例:
=# SET mars2_sort_mem TO 2097152;
全局配置项在系统级别修改值示例:
=# gpconfig -c mars2_sort_mem -v 2097152
=# \q
$ mxstop -u
HEAP 是 YMatrix 的默认存储引擎,又称作堆存储,从 PostgreSQL 继承而来,只支持行存储,不支持列存储及压缩。它基于 MVCC 机制实现,适用于有大量更新、删除需求的场景。
在 MVCC 机制影响下,HEAP 表在处理更新和删除操作时,并没有真正删除数据,而只是依靠数据版本信息屏蔽了老的数据(控制了数据的可见性)。因此,HEAP 表大量进行更新或删除操作,占用的物理空间会不断增大,需要你有计划地定期使用 VACUUM
清理老数据。
你可以运用以下 SQL 语句在 YMatrix 中创建一个 HEAP 表。
=# CREATE TABLE disk_heap(
time timestamp with time zone,
tag_id int,
read float,
write float
)
DISTRIBUTED BY (tag_id);
以 AOCO、AORO 为存储引擎的表统称为 AO(Append-Optimized)表,又称作追加优化表,可以支持插入、更新与删除操作,支持压缩。
AORO 支持行存储,AOCO 支持列存储。
AO 表无论是在表的逻辑结构还是物理结构上,都与 HEAP 表存在很大的不同。如上节所述 HEAP 表使用 MVCC 机制控制更新及删除操作后数据的可见性,而 AO 表则使用一个附加的 bitmap 表来实现,这个表的的内容就是表示 AO 表中哪些数据是可见的。
对于有大量更新及删除操作的 AO 表,同样需要计划地定期清理老数据,不过在 AO 表中,清理数据工具 vacuum
需要对 bitmap 进行重置并压缩物理文件,因此通常比 HEAP 进度慢。
注意!
存储引擎详细信息、使用及最佳实践请见表设计最佳实践。