Doris数据模型

本文介绍Doris的三种模型及其使用场景

Doris 的数据模型主要分为3类:

模型 关键字 特点
明细模型 DUPLICATE KEY 默认模型
聚合模型 AGGREGATE KEY 按照AGGREGATE KEY指定的字段进行聚合
更新模型 UNIQUE KEY 按照UNIQUE KEY指定的字段为唯一键,如果重复则覆盖

Duplicate 明细模型

适用场景

1
2
3
4
1.需要保留原始的数据(例如,原始的日志,操作记录等)
2.分析方式不固定,因为查询方式很灵活,所以传统的预聚合方式难以命中
3.数据更新不频繁,产生后就不太会发生变化
4.唯一健需要很多个字段组合在一起

模型原理

Doris根据明细模型制定的key维护排序列,表中的数据会按照排序列进行排序存储

在查询中,如果有相关排序列的过滤条件时,Doris能够快速地过滤数据,降低整个查询的时间。 DUPLICATE KEY更贴切的名称应该为 “Sorted Column

使用案例

创建表的默认数据模型就是明细模型,当导入Doris明细模型表中完全相同的两行数据时,Doris会认为是两行数据。

在使用过程中,将关联或者过滤字段放在DUPLICATE KEY里,这里注意DUPLICATE KEY必须按照顺序依次排在建表语句前面,否则会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
DROP TABLE IF EXISTS demo_esc_commerce_config;
CREATE TABLE demo_esc_commerce_config (
id varchar(128) NOT NULL COMMENT '主键id',
commerce_model tinyint(4) NOT NULL COMMENT '贸易模式',
country_code varchar(128) NOT NULL COMMENT '所在地区',
entity_id varchar(128) NOT NULL COMMENT '关联贸易主体id',
currency_code varchar(128) NOT NULL COMMENT '结算币种',
status tinyint(4) NOT NULL COMMENT '状态',
INDEX idx_country_code (country_code)
)
DUPLICATE KEY (id,commerce_model,country_code)
COMMENT '贸易配置表'
DISTRIBUTED BY HASH(id,commerce_model) BUCKETS 1
PROPERTIES
(
"replication_num" = "3"
);

聚合模型

适用场景

在数据分析领域中,有很多场景需要对数据进行统计和汇总

1
2
3
1.业务看指标基本都是汇总数据,例如sumcount等类型查询
2.不需要查询明细数据
3.原始数据不会被频繁更新,只会追加新数据

模型原理

Doris会将指标按照相同的维度进行聚合。当多条数据具有相同的维度时,Doris会把指标根据sum,max,min等类型进行聚合。这个是建表时候指定的。

从而能够减少查询时所需要的处理的数据量,提升查询的效率。

数据举例:

date country Pv
2022-05-23 CHN 1
2022-05-23 CHN 2
2022-05-23 USA 3

在Doris的聚合模型的表中,存储内容会从三条数据变两条数据

date country Pv
2022-05-23 CHN 3
2022-05-23 USA 3

使用案例

1
2
3
4
5
6
7
8
9
10
11
12
13
DROP TABLE IF EXISTS demo_aggregate;
CREATE TABLE demo_esc_commerce_config (
date date NOT NULL COMMENT '日期',
country varchar(128) NOT NULL COMMENT '国家',
pv bitint sum NOT NULL COMMENT 'page views',
INDEX idx_country_code (country_code)
)
AGGREGATE KEY (date,country)
DISTRIBUTED BY HASH(country) BUCKETS 1
PROPERTIES
(
"replication_num" = "3"
);

聚合模型目前支持的聚合函数有SUM,MIN,MAX,REPLACE

Tips:

在 Doris 的聚合模型中,count(*) 这种查询的开销非常大

在 count() 查询中,Doris 必须扫描所有的 AGGREGATE KEY 列(这里就是 user_id date),并且聚合后,才能得到语意正确的结果。当聚合列非常多时,count(*) 查询需要扫描大量的数据。

因此,当业务上有频繁的 count(*) 查询时,我们建议用户通过增加一个**值恒为 1 的,聚合类型为 SUM 的列来模拟 count(*)**。如刚才的例子中的表结构,我们修改如下:

增加一个 count 列,并且导入数据中,该列值恒为 1。则 select count() from table; 的结果等价于 select sum(count) from table;。而后者的查询效率将远高于前者。不过这种方式也有使用限制,就是用户需要自行保证,不会重复导入 AGGREGATE KEY 列都相同的行。否则,select sum(count) from table; 只能表述原始导入的行数,而不是 select count() from table; 的语义。

另一种方式,就是 将如上的 count 列的聚合类型改为 REPLACE,且依然值恒为 1。那么 select sum(count) from table; 和 select count(*) from table; 的结果将是一致的。并且这种方式,没有导入重复行的限制。


更新模型

适用场景

在有些分析场景中,分析的数据经常会发生变化。对于这些分析场景的需求,可以使用Doris的更新模型UNIQUE KEY来实现。

以下是一些适用更新模型的场景:

1
2
3
1.已经写入的数据有大量的更新需求
2.需要进行实时数据分析
3.需要保证端到端的一致性(即保证不会重复插入)

模型原理

Doris存储内部会给每一个批次导入数据分配一个版本号,在查询的时候对于主键相同的两条数据,会根据版本的大小进行返回,版本大的被返回,版本小的不会被返回。

ID value _version
1 100 1
1 101 2
2 100 3
2 103 4

那么用户能够看到的数据如下:

ID value
1 100
2 102

通过这种机制,Doris可以支持对于频繁更新数据的分析

使用案例

例如订单分析场景中,经常会有根据订单状态进行的统计分析需求。

因为订单状态经常改表,而create_time和order_id不会改变,并且经常会在查询中作为过滤条件。所以可以将create_time和order_id两个列作为这个表的主键(UNIQUE KEY定义)

以下是建表例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DROP TABLE IF EXISTS ods.ods_esc_usr_company_business_country;
CREATE TABLE ods.ods_esc_usr_company_business_country (
id varchar(128) NOT NULL COMMENT 'id',
company_id varchar(128) NOT NULL COMMENT '公司id',
country_code varchar(255) NOT NULL COMMENT '国家编码',
country_name varchar(255) NOT NULL COMMENT '国家名称',
creator varchar(128) NOT NULL COMMENT '创建人',
modifier varchar(128) NOT NULL COMMENT '修改人',
create_time datetime NULL DEFAULT NULL COMMENT '创建时间',
update_time datetime NULL DEFAULT NULL COMMENT '更新时间'
)
UNIQUE KEY (id,company_id)
COMMENT '已开通代销资质国家'
DISTRIBUTED BY HASH(id,company_id) BUCKETS 1
PROPERTIES
(
"replication_num" = "3"
);

Tips:

如果业务对实时性的要求是分钟级别,那么每分钟导入一次更新数据即可,不需要秒级的导入。

数据模型的选择建议

因为数据模型在建表时就已经确定,且无法修改。所以,选择一个合适的数据模型非常重要

  1. Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常适合有固定模式的报表类查询场景。但是该模型对 count(*) 查询很不友好,同时因为固定了 Value 列上的聚合方式,在进行其他类型的聚合查询时,需要考虑语意正确性。

  2. Unique 模型针对需要唯一主键约束的场景,可以保证主键唯一性约束。但是无法利用 ROLLUP 等预聚合带来的查询优势(因为本质是 REPLACE,没有 SUM 这种聚合方式)。

  3. Duplicate 适合任意维度的 Ad-hoc 查询。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有 Key 列)。


觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭



wechat pay



alipay

Doris数据模型
http://yuting0907.github.io/2022/05/23/Doris数据模型/
作者
Echo Yu
发布于
2022年5月23日
许可协议