存储引擎

存储引擎是数据库系统的存储基座,数据库基于存储引擎进行数据的创建、查询、更新和删除等操作。根据你的需要,不同的存储引擎将提供不同的存储机制,在物理布局,索引类型,锁的粒度等不同维度进行设计。
目前MatrixDB数据库系统支持两种存储引擎的使用:基于PostgreSQL的HEAP,MatrixDB自研发的MARS2。HEAP表为传统PostgreSQL数据库提供的存储引擎,又称堆表。 该类型的表支持大量并发读写、事务、索引等特性。MARS2表为在MARS1基础上开发的存储引擎,凭借其物理有序的合并方式,减少IO寻址的次数,从而提高对表内数据的查询性能。 同时,MARS2支持压缩、列存、自动归档、预聚集等功能,在时序场景中表现优越。 当前暂不支持更新和删除。

不同存储引擎下创建表

依据两种存储引擎的不同特性,你可以在不同的场景需求下灵活创建不同的表。我们给出以下示例。

1 创建HEAP表

HEAP表为MatrixDB默认存储引擎,因此如果你建表时没有特殊指定存储引擎,创建的则均为HEAP表。

CREATE TABLE disk(
    time timestamp with time zone,
    tag_id int,
    read float,
    write float
)
DISTRIBUTED BY (tag_id);

2 创建MARS2表

MARS2表依赖matrixts扩展,在建表前,首先需要你在使用该存储引擎的数据库中创建扩展。

注意!
matrixts扩展为数据库级别,一个数据库里面创建一次即可,无需重复创建。

CREATE EXTENSION matrixts;

建表时使用USING mars2来指定存储引擎:

CREATE TABLE vehicle_basic_data_mars2(
  daq_time timestamp  encoding (minmax),
  vin varchar(32)  COLLATE "C" encoding (minmax),
  lng float encoding (minmax),
  lat float encoding (minmax),
  speed float ,
  license_template varchar(16) ,
  flag integer
)
USING mars2
WITH (compresstype=zstd, compresslevel=3)
DISTRIBUTED BY (vin)
PARTITION BY RANGE (daq_time)
( START ('2022-07-01 00:00:00') INCLUSIVE
  END ('2022-08-01 00:00:00') EXCLUSIVE
  EVERY (INTERVAL '1 day')
,default partition others);

我们将对 vehicle_basic_data_mars2 表中的具体参数和语句做一些说明:

  1. encoding (minmax)
    这个选项的使用是为了提升计算能力,如果你想要根据此字段进行 min、max、avg、sum、count 等聚集查询,或者进行 WHERE 条件过滤时需要加上这个选项。这个选项的添加需要根据业务场景来确定,不要不加思考地添加至全部的字段,否则这种操作会带来很多数据写入的CPU以及磁盘IO的消耗。
  2. COLLATE "C"
    此选项只在设备编码字段添加,其他字段无需添加。利用此操作,可以提高文本类型的排序速度和查询速度。
  3. USING mars2
    是使用 MARS2 表的固定写法,不能改变内容及大小写方式。
  4. WITH (compresstype=zstd, compresslevel=3)
    指定压缩算法为zstd,还有rle_type,zlib,lz4 压缩算法,此表中推荐使用 zstd,压缩级别使用3级。压缩性能相关参数具体见下文表格。
  5. DISTRIBUTED BY (vin):
    使用此语句选择分布键。我们推荐使用设备编码字段作为分布键,从而可以查询同一个设备的的数据,并进行相关计算。避免了节点之间的数据重分布带来的性能损耗。
  6. PARTITION BY RANGE (daq_time)
    指定分区表的分区键。我们推荐使用设备采集数据的时间作为分区键。通常大量查询都是筛选数据采集的时间。例如,当你想要查询一天内的数据并进行相关的计算,你就需要加上过滤条件 WHERE daq_time >= CURRENT_DATE - INTERVAL '1 day' ,这样数据库就会快速的判断出数据在哪个分区子表上,从而快速的将数据定位并查询表出来。
  7. ( START ('2022-07-01 00:00:00') INCLUSIVE END ('2022-08-01 00:00:00') EXCLUSIVE EVERY (INTERVAL '1 days') ,default partition others);
    此条SQL语句表明,你将使用START...END 语句以及INCLUSIVEEXCLUSIVE关键字创建从2022-07-01零点开始到2022-08-01零点前截止的子分区表。
  8. EVERY (INTERVAL '1 day')
    子分区表的时间跨度为1天,除了以 day 为单位,你也完全可以使用 hour、month、year 等,根据数据量的规模来确定即可。例如,在一天的时间里,你的服务器接收到了高达100万~1000万条数据,那天以“1 day”作为时间间隔就是最佳选择;如果一天的数据量只有十几万或几十万,那么选择“1 month”就很合适;如果每天的数据量不过万级,那么“1 year”子分区表生成一次就可以了。
  9. default partition others
    表示默认分区。数据的时间如果在其他分区里面找不到对应的子表存储,就会存储到这个分区里面。

注意!
我们希冀你会根据我们的建议设计建表思路,但我们不希望你盲目套用。具体的时序场景千变万化,具体情况具体分析仍是非常必要的。

上文提到的MARS2表压缩性能相关参数:

参数名 默认值 最小值 最大值 描述
compress_threshold 1200 1 8000 同一个组压缩的tuple数上限
compresstype lz4 -- -- 压缩算法,支持:
1. zstd
2. zlib
3. lz4
compresslevel 1 1 -- 压缩级别。通常值越小压缩率越小,但压缩越快;值越大压缩率越高,但压缩越慢。不同的算法有效值范围都不同:
zstd:1-19
zlib:1-9
lz4:1-20

注意!
一般而言,zstd 符合压缩级别越高,压缩率越高,同时速度越低。但这并不绝对。

创建MARS2表成功后,你必须额外创建一个 mars2_btree 类型的索引,这样才能进行正常的数据读写。使用索引排序的目的是使得同一维度或相似特性的数据尽可能的在物理上靠近,以减少IO寻址的次数,提高查询效率。因此排序键的选择需要符合主要的业务查询特征。例如需求是单设备点查询,那么排序键就是时序场景中的设备号(vin),如果需求是单设备在某时间段内明细查询、聚集查询或多设备查询,那么排序键就是设备号以及时间戳(vin,daq_time)。

CREATE INDEX idx_mars2 ON vehicle_basic_data_mars2 
USING mars2_btree(vin, daq_time);

注意!
当设备相同时间点数据分批上报时,MARS2可以对相同时间(此表中为 daq_time 值)相同设备(此表中为 vin 值)的数据进行合并。合并特性需要在创建索引时手动指定uniquemode=true,因为此选项的默认值是false。例如,当你指定 uniquemode=true ,设备'A01'在'2022-01-01 00:00:00'这个时间传回来 3 条数据,最后会根据最后一条数据将原来的两条数据覆盖,只保留一条数据;但如果你默认了 uniquemode=false ,那么设备'A01'在'2022-01-01 00:00:00'这个时间传回来的 3 条数据,最后会全部保留,不做任何处理。