searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Doris数据模型

2024-09-29 09:55:17
2
0

Doris数据模型

在 Doris 中,数据以表(Table)的形式进行逻辑上的描述。 一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。

Column 可以分为两大类:Key 和 Value。从业务角度看,Key 和 Value 可以分别对应维度列和指标列。Doris的key列是建表语句中指定的列,建表语句中的关键字'unique key'或'aggregate key'或'duplicate key'后面的列就是 Key 列,除了 Key 列剩下的就是 Value 列。

Doris的数据模型一共有Aggregate、Unique、Duplicate(默认)三类,分别对应建表语句指定'aggregate key'、'unique key'、'duplicate key'。

一、Aggregate数据模型

Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量。聚合模型的特点就是将表中的列分为了Key和Value两种。 Key 就是数据的维度列,比如时间,地区等等。 Value 则是数据的指标列,比如点击量,花费等。

支持的聚合类型如下:

    1. SUM:求和,多行的 Value 进行累加。
    2. REPLACE:替代,下一批数据中的 Value 会替换之前导入过的行中的 Value。
    3. MAX:保留最大值。
    4. MIN:保留最小值。
    5. REPLACE_IF_NOT_NULL:非空值替换。和 REPLACE 的区别在于对于null值,不做替换。
    6. HLL_UNION:HLL 类型的列的聚合方式,通过 HyperLogLog 算法聚合。
    7. BITMAP_UNION:BIMTAP 类型的列的聚合方式,进行位图的并集聚合。
1、示例:

现有数据表结构如下

ColumnName

Type

AggregationType

Comment

ser_month

varchar(6)

 

月份

latn_id

INT

 

本地网标识

latn_name

VARCHAR(30)

 

本地网名称

telecom_area_id

INT

 

区局标识

telecom_area_name

VARCHAR(50)

 

区局名称

user_count

INT

SUM

5G合约本月新增用户数

last_update_date

DATE

REPLACE

最后更新日期

  • 创建聚合表
CREATE TABLE IF NOT EXISTS ctyun_liucy.user_count_info
(
    `ser_month` varchar(6) COMMENT "月份",
    `latn_id` INT COMMENT "本地网标识",
    `latn_name` varchar(30) COMMENT "本地网名称",
    `telecom_area_id` INT COMMENT "区局标识",
    `telecom_area_name` varchar(50) COMMENT "区局名称",
    `user_count` INT SUM DEFAULT "0" COMMENT "5G合约本月新增用户数",
    `last_update_date` DATE REPLACE COMMENT "最后更新日期"
)
AGGREGATE KEY(`ser_month`, `latn_id`, `latn_name`,`telecom_area_id`,`telecom_area_name`)
DISTRIBUTED BY HASH(`ser_month`, `latn_id`) BUCKETS 3
PROPERTIES (
"replication_allocation" = "tag.location.default:3"
);

 

  • 插入数据
insert into ctyun_liucy.user_count_info (ser_month,latn_id,latn_name,telecom_area_id,telecom_area_name,user_count,last_update_date) values
('202401','1001','武汉','100101','洪山区','21','20240110'),
('202401','1005','宜昌','100511','西陵区','13','20240110'),
('202401','1009','十堰','100905','竹山县','8','20240110'),
('202401','1001','武汉','100101','洪山区','33','20240111'),
('202401','1001','武汉','100101','洪山区','10','20240112'),
('202401','1009','十堰','100908','茅箭区','6','20240112');
  • 查询数据

可以看到user_count字段根据AGGREGATE KEY做了SUM操作,last_update_date以最后一条记录进行了更新。

2、应用场景:

Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常

适合有固定模式的报表类查询场景。

3、实现原理:

Doris 采用了类似于 LSM-Tree 的数据写入模型,将数据以追加的方式顺序写入磁盘,实现了写优化。这样可以提高系统的写入性能,但是也带来了读取时的额外开销。为了处理多次写入造成的数据变化,Doris 引入后台compaction进行优化。

聚合模型可能发生合并(compaction)的阶段有两个,不同批次导入的数据会根据key发生一次聚合合并,另外一个阶段是当后台数据合并未完成,但是进行了查询,查询时时会将数据按key进行合并,保证查询的结果正确。

注意:select count(*)在doris中非常耗时,可以直接某一个key列进行计数 。但是在聚合模型查出的结果不一定正确,因为此时可能并未聚合,所以聚合模型时尽量减少count操作,相关操作结果可能跟自己想要的结果存在偏差。

二、 Unique数据模型

在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性(如数据更新需求),即如何获得 Primary Key 唯一性约束。 因此,Doris引入了 Unique 数据模型。Unique模型能够保证Key的唯一性,当用户更新一条数据时,新写入的数据会覆盖具有相同key的旧数据。

Unique模型提供了两种实现方式:

  • 读时合并(merge-on-read)。在读时合并实现中,用户在进行数据写入时不会触发任何数据去重相关的操作,所有数据去重的操作都在查询或者compaction时进行。因此,读时合并的写入性能较好,查询性能较差,同时内存消耗也较高。
  • 写时合并(merge-on-write)。在1.2版本中,我们引入了写时合并实现,该实现会在数据写入阶段完成所有数据去重的工作,因此能够提供非常好的查询性能。
1、读时合并模型

读时合并的Unique数据模型是Aggregate数据模型的一个特例,它的底层实现原理与聚合模型一直,合并操作发生在compaction和查询时合并。

2、写时合并模型

Unique模型的写时合并实现,查询性能更接近于duplicate模型,在有主键约束需求的场景上相比聚合模型有较大的查询性能优势,尤其是在聚合查询以及需要用索引过滤大量数据的查询中。

在开启了写时合并选项的Unique表上,数据在导入阶段就会去将被覆盖和被更新的数据进行标记删除,同时将新的数据写入新的文件。在查询的时候, 所有被标记删除的数据都会在文件级别被过滤掉,读取出来的数据就都是最新的数据,消除掉了读时合并中的数据聚合过程,并且能够在很多情况下支持多种谓词的下推。因此在许多场景都能带来比较大的性能提升,尤其是在有聚合查询的情况下。

3、Unique写时合并模型数据更新

Unique Key模型目前仅支持在Merge-on-Write实现上进行列更新

用户通过正常的导入方式将一部分列的数据写入Doris的Memtable,此时Memtable中并没有整行数据,在Memtable下刷的时候,会查找历史数据,用历史数据补齐一整行,并写入数据文件中,同时将历史数据文件中相同key的数据行标记删除

当出现并发导入时,Doris会利用MVCC机制来保证数据的正确性。如果两批数据导入都更新了一个相同key的不同列,则其中系统版本较高的导入任务会在版本较低的导入任务成功后,使用版本较低的导入任务写入的相同key的数据行重新进行补齐

使用建议:

  1. 对写入性能要求较高,查询性能要求较低的用户,建议使用Aggregate Key模型
  2. 对查询性能要求较高,对写入性能要求不高(例如数据的写入和更新基本都在凌晨低峰期完成),或者写入频率不高的用户,建议使用Unique Key模型merge-on-write实现

由于Merge-on-Write实现需要在数据写入的时候,进行整行数据的补齐,以保证最优的查询性能,因此使用Merge-on-Write实现进行部分列更新会有较为明显的导入性能下降。

写入性能优化建议:

    1. 使用配备了NVMe的SSD,或者极速SSD云盘。因为补齐数据时会大量的读取历史数据,产生较高的读IOPS,以及读吞吐
    2. 开启行存将能够大大减少补齐数据时产生的IOPS,导入性能提升明显,用户可以在建表时通过如下property来开启行存:
"store_row_column" = "true"

读时合并的Unique模型在写入过程中不做任何额外处理,所以写入性能不受影响,与普通的数据导入相同。但是在查询时进行聚合的代价较大,典型的聚合查询性能相比Unique Key模型的Merge-on-Write实现会有5-10倍的下降。

三、 Duplicate数据模型

在某些多维分析场景下,数据既没有主键,也没有聚合需求。因此,我们引入 Duplicate 数据模型来满足这类需求。

CREATE TABLE
  `dsj_2024_kmh_fj_hz1` (
    `lx` varchar(200) NOT NULL,
    `cty_flg` varchar(20) NULL,
    `region_id` bigint(20) NULL,
    `region_name` text NULL,
    `group_region_id` bigint(20) NULL,
    `group_region_name` text NULL,
    `val_d` bigint(20) NULL,
    `val_d1` bigint(20) NULL,
    `val_l` bigint(20) NULL,
    `date_id` bigint(20) NULL
  ) ENGINE = OLAP DUPLICATE KEY(`lx`) COMMENT 'OLAP' DISTRIBUTED BY HASH(`date_id`) BUCKETS 30 PROPERTIES (
    "replication_allocation" = "tag.location.default: 3",
    "is_being_synced" = "false",
    "storage_format" = "V2",
    "light_schema_change" = "true",
    "disable_auto_compaction" = "false",
    "enable_single_replica_compaction" = "false"
  );

这种数据模型区别于 Aggregate 和 Unique 模型。数据完全按照导入文件中的数据进行存储,不会有任何聚合。即使两行数据完全相同,也都会保留。 而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序。(更贴切的名称应该为 “Sorted Column”, 这里取名 “DUPLICATE KEY” 只是用以明确表示所用的数据模型。)。在 DUPLICATE KEY 的选择上,我们建议适当的选择前 2-4 列就可以。

对于实际使用上,因为我们很多表是从Hive迁移过来,Hive中的表也没有聚合、去重相关概念,因此Hive导入的数据大部分表都可以选用该模型进行创建。

  • 无排序键Duplicate数据模型

当创建表的时候没有指定Unique、Aggregate或Duplicate时,会默认创建一个Duplicate模型的表,并自动指定排序列。

当用户并没有排序需求的时候,可以通过在表属性中配置:

"enable_duplicate_without_keys_by_default" = "true"

创建明细模型的时候,就会不再指定排序列,也不会给该表创建前缀索引,以此减少在导入和存储上额外的开销。

0条评论
0 / 1000
刘****阳
6文章数
0粉丝数
刘****阳
6 文章 | 0 粉丝
原创

Doris数据模型

2024-09-29 09:55:17
2
0

Doris数据模型

在 Doris 中,数据以表(Table)的形式进行逻辑上的描述。 一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。

Column 可以分为两大类:Key 和 Value。从业务角度看,Key 和 Value 可以分别对应维度列和指标列。Doris的key列是建表语句中指定的列,建表语句中的关键字'unique key'或'aggregate key'或'duplicate key'后面的列就是 Key 列,除了 Key 列剩下的就是 Value 列。

Doris的数据模型一共有Aggregate、Unique、Duplicate(默认)三类,分别对应建表语句指定'aggregate key'、'unique key'、'duplicate key'。

一、Aggregate数据模型

Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量。聚合模型的特点就是将表中的列分为了Key和Value两种。 Key 就是数据的维度列,比如时间,地区等等。 Value 则是数据的指标列,比如点击量,花费等。

支持的聚合类型如下:

    1. SUM:求和,多行的 Value 进行累加。
    2. REPLACE:替代,下一批数据中的 Value 会替换之前导入过的行中的 Value。
    3. MAX:保留最大值。
    4. MIN:保留最小值。
    5. REPLACE_IF_NOT_NULL:非空值替换。和 REPLACE 的区别在于对于null值,不做替换。
    6. HLL_UNION:HLL 类型的列的聚合方式,通过 HyperLogLog 算法聚合。
    7. BITMAP_UNION:BIMTAP 类型的列的聚合方式,进行位图的并集聚合。
1、示例:

现有数据表结构如下

ColumnName

Type

AggregationType

Comment

ser_month

varchar(6)

 

月份

latn_id

INT

 

本地网标识

latn_name

VARCHAR(30)

 

本地网名称

telecom_area_id

INT

 

区局标识

telecom_area_name

VARCHAR(50)

 

区局名称

user_count

INT

SUM

5G合约本月新增用户数

last_update_date

DATE

REPLACE

最后更新日期

  • 创建聚合表
CREATE TABLE IF NOT EXISTS ctyun_liucy.user_count_info
(
    `ser_month` varchar(6) COMMENT "月份",
    `latn_id` INT COMMENT "本地网标识",
    `latn_name` varchar(30) COMMENT "本地网名称",
    `telecom_area_id` INT COMMENT "区局标识",
    `telecom_area_name` varchar(50) COMMENT "区局名称",
    `user_count` INT SUM DEFAULT "0" COMMENT "5G合约本月新增用户数",
    `last_update_date` DATE REPLACE COMMENT "最后更新日期"
)
AGGREGATE KEY(`ser_month`, `latn_id`, `latn_name`,`telecom_area_id`,`telecom_area_name`)
DISTRIBUTED BY HASH(`ser_month`, `latn_id`) BUCKETS 3
PROPERTIES (
"replication_allocation" = "tag.location.default:3"
);

 

  • 插入数据
insert into ctyun_liucy.user_count_info (ser_month,latn_id,latn_name,telecom_area_id,telecom_area_name,user_count,last_update_date) values
('202401','1001','武汉','100101','洪山区','21','20240110'),
('202401','1005','宜昌','100511','西陵区','13','20240110'),
('202401','1009','十堰','100905','竹山县','8','20240110'),
('202401','1001','武汉','100101','洪山区','33','20240111'),
('202401','1001','武汉','100101','洪山区','10','20240112'),
('202401','1009','十堰','100908','茅箭区','6','20240112');
  • 查询数据

可以看到user_count字段根据AGGREGATE KEY做了SUM操作,last_update_date以最后一条记录进行了更新。

2、应用场景:

Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常

适合有固定模式的报表类查询场景。

3、实现原理:

Doris 采用了类似于 LSM-Tree 的数据写入模型,将数据以追加的方式顺序写入磁盘,实现了写优化。这样可以提高系统的写入性能,但是也带来了读取时的额外开销。为了处理多次写入造成的数据变化,Doris 引入后台compaction进行优化。

聚合模型可能发生合并(compaction)的阶段有两个,不同批次导入的数据会根据key发生一次聚合合并,另外一个阶段是当后台数据合并未完成,但是进行了查询,查询时时会将数据按key进行合并,保证查询的结果正确。

注意:select count(*)在doris中非常耗时,可以直接某一个key列进行计数 。但是在聚合模型查出的结果不一定正确,因为此时可能并未聚合,所以聚合模型时尽量减少count操作,相关操作结果可能跟自己想要的结果存在偏差。

二、 Unique数据模型

在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性(如数据更新需求),即如何获得 Primary Key 唯一性约束。 因此,Doris引入了 Unique 数据模型。Unique模型能够保证Key的唯一性,当用户更新一条数据时,新写入的数据会覆盖具有相同key的旧数据。

Unique模型提供了两种实现方式:

  • 读时合并(merge-on-read)。在读时合并实现中,用户在进行数据写入时不会触发任何数据去重相关的操作,所有数据去重的操作都在查询或者compaction时进行。因此,读时合并的写入性能较好,查询性能较差,同时内存消耗也较高。
  • 写时合并(merge-on-write)。在1.2版本中,我们引入了写时合并实现,该实现会在数据写入阶段完成所有数据去重的工作,因此能够提供非常好的查询性能。
1、读时合并模型

读时合并的Unique数据模型是Aggregate数据模型的一个特例,它的底层实现原理与聚合模型一直,合并操作发生在compaction和查询时合并。

2、写时合并模型

Unique模型的写时合并实现,查询性能更接近于duplicate模型,在有主键约束需求的场景上相比聚合模型有较大的查询性能优势,尤其是在聚合查询以及需要用索引过滤大量数据的查询中。

在开启了写时合并选项的Unique表上,数据在导入阶段就会去将被覆盖和被更新的数据进行标记删除,同时将新的数据写入新的文件。在查询的时候, 所有被标记删除的数据都会在文件级别被过滤掉,读取出来的数据就都是最新的数据,消除掉了读时合并中的数据聚合过程,并且能够在很多情况下支持多种谓词的下推。因此在许多场景都能带来比较大的性能提升,尤其是在有聚合查询的情况下。

3、Unique写时合并模型数据更新

Unique Key模型目前仅支持在Merge-on-Write实现上进行列更新

用户通过正常的导入方式将一部分列的数据写入Doris的Memtable,此时Memtable中并没有整行数据,在Memtable下刷的时候,会查找历史数据,用历史数据补齐一整行,并写入数据文件中,同时将历史数据文件中相同key的数据行标记删除

当出现并发导入时,Doris会利用MVCC机制来保证数据的正确性。如果两批数据导入都更新了一个相同key的不同列,则其中系统版本较高的导入任务会在版本较低的导入任务成功后,使用版本较低的导入任务写入的相同key的数据行重新进行补齐

使用建议:

  1. 对写入性能要求较高,查询性能要求较低的用户,建议使用Aggregate Key模型
  2. 对查询性能要求较高,对写入性能要求不高(例如数据的写入和更新基本都在凌晨低峰期完成),或者写入频率不高的用户,建议使用Unique Key模型merge-on-write实现

由于Merge-on-Write实现需要在数据写入的时候,进行整行数据的补齐,以保证最优的查询性能,因此使用Merge-on-Write实现进行部分列更新会有较为明显的导入性能下降。

写入性能优化建议:

    1. 使用配备了NVMe的SSD,或者极速SSD云盘。因为补齐数据时会大量的读取历史数据,产生较高的读IOPS,以及读吞吐
    2. 开启行存将能够大大减少补齐数据时产生的IOPS,导入性能提升明显,用户可以在建表时通过如下property来开启行存:
"store_row_column" = "true"

读时合并的Unique模型在写入过程中不做任何额外处理,所以写入性能不受影响,与普通的数据导入相同。但是在查询时进行聚合的代价较大,典型的聚合查询性能相比Unique Key模型的Merge-on-Write实现会有5-10倍的下降。

三、 Duplicate数据模型

在某些多维分析场景下,数据既没有主键,也没有聚合需求。因此,我们引入 Duplicate 数据模型来满足这类需求。

CREATE TABLE
  `dsj_2024_kmh_fj_hz1` (
    `lx` varchar(200) NOT NULL,
    `cty_flg` varchar(20) NULL,
    `region_id` bigint(20) NULL,
    `region_name` text NULL,
    `group_region_id` bigint(20) NULL,
    `group_region_name` text NULL,
    `val_d` bigint(20) NULL,
    `val_d1` bigint(20) NULL,
    `val_l` bigint(20) NULL,
    `date_id` bigint(20) NULL
  ) ENGINE = OLAP DUPLICATE KEY(`lx`) COMMENT 'OLAP' DISTRIBUTED BY HASH(`date_id`) BUCKETS 30 PROPERTIES (
    "replication_allocation" = "tag.location.default: 3",
    "is_being_synced" = "false",
    "storage_format" = "V2",
    "light_schema_change" = "true",
    "disable_auto_compaction" = "false",
    "enable_single_replica_compaction" = "false"
  );

这种数据模型区别于 Aggregate 和 Unique 模型。数据完全按照导入文件中的数据进行存储,不会有任何聚合。即使两行数据完全相同,也都会保留。 而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序。(更贴切的名称应该为 “Sorted Column”, 这里取名 “DUPLICATE KEY” 只是用以明确表示所用的数据模型。)。在 DUPLICATE KEY 的选择上,我们建议适当的选择前 2-4 列就可以。

对于实际使用上,因为我们很多表是从Hive迁移过来,Hive中的表也没有聚合、去重相关概念,因此Hive导入的数据大部分表都可以选用该模型进行创建。

  • 无排序键Duplicate数据模型

当创建表的时候没有指定Unique、Aggregate或Duplicate时,会默认创建一个Duplicate模型的表,并自动指定排序列。

当用户并没有排序需求的时候,可以通过在表属性中配置:

"enable_duplicate_without_keys_by_default" = "true"

创建明细模型的时候,就会不再指定排序列,也不会给该表创建前缀索引,以此减少在导入和存储上额外的开销。

文章来自个人专栏
MPP-Doris应用
4 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0