目前,StarRocks 支持的数据模型有:明细模型(Duplicate Key)、聚合模型(Aggregate Key)、更新模型(Unique Key)和主键模型(Primary Key)。其中,更新模型和主键模型是聚合模型的特殊情形。
下面将详细介绍这些模型的特点和使用场景。
明细模型
使用场景
StarRocks 建表的默认模型是明细模型(Duplicate Key)。
应用明细模型的场景有如下特点:
- 需要保留原始数据(比如用户行为日志)来进行分析
- 预聚合的方式不能满足查询的需求
- 数据主要以追加方式写入,并且更新不频繁
应用举例
下面是使用明细模型创建表的例子。
CREATE TABLE IF NOT EXISTS detail (
event_time DATETIME NOT NULL COMMENT "datetime of event",
event_type INT NOT NULL COMMENT "type of event",
user_id INT COMMENT "id of user",
device_code INT COMMENT "device of ",
channel INT COMMENT ""
)
DUPLICATE KEY(event_time, event_type)
DISTRIBUTED BY HASH(user_id) BUCKETS 8
关键词 DUPLICATE KEY
表明该表采用了明细模型,并且指定了排序键 event_time,event_type
。
注意事项
- 明细模型中, 可以指定部分的维度列为排序键;而聚合模型和更新模型中, 排序键只能是全体维度列。
- 排序键一定要出现在表定义里面其它列的前面。比如,我们希望指定
a,b
作为排序键,那么字段a
就必须是表定义中的第一位,而字段b
紧随其后。关于排序键的更加详细的介绍请看官方文档说明。
聚合模型
使用场景
应用聚合模型的场景有如下特点:
- 只执行聚合类查询,比如 sum、count、max 等类型的查询
- 不需要召回原始的明细数据
- 老数据不会被频繁更新,只会追加新数据
应用举例
在建表时,我们可以通过AGGREGATE KEY
显式地定义排序键,但实际上没有必要,因为只要给指标列的定义指明了聚合函数,就说明这该表采用了聚合模型,其它没有指明聚合函数的列都是维度列,而维度列都包含在排序键中。
CREATE TABLE IF NOT EXISTS example_db.aggregate_tbl (
site_id LARGEINT NOT NULL COMMENT "id of site",
date DATE NOT NULL COMMENT "time of event",
city_code VARCHAR(20) COMMENT "city_code of user",
pv BIGINT SUM DEFAULT "0" COMMENT "total page views"
)
DISTRIBUTED BY HASH(site_id) BUCKETS 8;
支持的聚合函数有:
- SUM、MAX、MIN、REPLACE
- HLL_UNION:仅用于HLL列,为HLL独有的聚合方式。
- BITMAP_UNION:仅用于 BITMAP 列,为 BITMAP 独有的聚合方式
- REPLACE_IF_NOT_NULL:这个聚合类型的含义是当且仅当新导入数据是非 NULL 值时会发生替换行为,如果新导入的数据是 NULL,那么 StarRocks 仍然会保留原值
关于聚合模型支持的聚合函数说明,具体可参考官方文档。
注意事项
- StarRocks 的聚合操作有可能在多个阶段触发,不过 StarRocks 会保证查询结果的最终一致性。因此,我们在查询聚合模型的表时不需要通过 SQL 语义(即在 SQL 中再做聚合操作)来保证。
- 如果指标列指定了 SUM 函数,当重复导入数据时,查询的结果就不符合预期。一种解决思路是使用更新模型或主键模型,在外部做好聚合后再导入到 StarRocks 的表。
更新模型
更新模型是聚合模型的特殊形式,它的实现原理和聚合模型的很相似:
在客户端执行数据导入操作时,后台会将数据分批次导入,每个批次会生成一个版本号。当用户发起查询请求,后台会将多版本的数据合并。
使用场景
应用更新模型的场景有如下特点:
- 已经写入的数据有大量的更新需求
- 需要进行实时数据分析
应用举例
下面是使用了更新模型创建表的示例。关键词 UNIQUE KEY
表明该表使用了更新模型,并且指定了排序键 create_time,order_id
。
CREATE TABLE IF NOT EXISTS detail (
create_time DATE NOT NULL COMMENT "create time of an order",
order_id BIGINT NOT NULL COMMENT "id of an order",
order_state INT COMMENT "state of an order",
total_price BIGINT COMMENT "price of an order"
)
UNIQUE KEY(create_time, order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 8
注意事项
- 导入数据时需要将所有字段补全才能够完成更新操作。在上面的例子中,create_time、order_id、order_state 和 total_price 四个字段都需必须存在。
- 控制数据导入的频率,导入数据的频率越高,后台生成的版本号就越多,对查询的性能影响就越大。建议在设计导入频率时以满足业务对实时性的要求为准,能设置到分钟级就不采用秒级。
- 将经常用在过滤条件且不会被修改的字段放在主键上, 能够在合并之前就将数据过滤掉,从而提升查询性能。
- 因为合并过程需要将所有主键字段进行比较,所以应该避免放置过多的主键字段,以免降低查询性能。
主键模型
相较更新模型,主键模型可以更好地支持实时和频繁更新等场景。主键模型的实现原理、相较更新模型的优势请看官方文档。
使用场景
应用主键模型的场景有如下特点:
- 数据有冷热特征,即最近几天的热数据才经常被修改,老的冷数据很少被修改。
- 大宽表(数百到数千列)。主键只占整个数据的很小一部分,其内存开销比较低。
应用举例
下面是使用了主键模型创建表的示例。关键词 PRIMARY KEY
表明该表使用了主键模型,并且指明了主键 user_id
。
CREATE TABLE IF NOT EXISTS users (
user_id BIGINT NOT NULL,
name STRING NOT NULL,
email STRING NULL,
address STRING NULL,
age TINYINT NULL,
sex TINYINT NULL,
last_active DATETIME,
property TINYINT NOT NULL
....
) PRIMARY KEY (user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 4
PROPERTIES("replication_num" = "3");
注意事项
- 目前primary主键存储在内存中,为防止滥用造成内存占满,限制主键字段长度全部加起来编码后不能超过127字节。
- 分区列(partition)、分桶列(bucket)必须在主键列中。
- 暂不支持使用ALTER TABLE修改列类型。
参考文档
[1] Doris 的数据模型
[2] StarRocks 的数据模型介绍