3.5.3 主键模型¶
当用户有数据更新需求时,可以选择使用主键数据模型( Unique
)。主键模型能够保证 Key
(主键)的唯一性,当用户更新一条数据时,新写入的数据会覆盖具有相同 key
(主键)的旧数据。
主键模型提供了两种实现方式:
-
写时合并(
merge-on-write
)。在1.2
版本中,我们引入了写时合并实现,该实现会在数据写入阶段完成所有数据去重的工作,因此能够提供非常好的查询性能。自2.1
版本起,写时合并经过两个大版本的打磨,已经非常成熟稳定,由于其优秀的查询性能,写时合并成为Unique
模型的默认实现。 -
读时合并(
merge-on-read
)。在读时合并实现中,用户在进行数据写入时不会触发任何数据去重相关的操作,所有数据去重的操作都在查询或者compaction
时进行。因此,读时合并的写入性能较好,查询性能较差,同时内存消耗也较高。
数据更新的语义
-
Unique
模型默认的更新语义为整行UPSERT
,即UPDATE OR INSERT
,该行数据的key
如果存在,则进行更新,如果不存在,则进行新数据插入。在整行UPSERT
语义下,即使用户使用insert into
指定部分列进行写入,Doris
也会在Planner
中将未提供的列使用NULL
值或者默认值进行填充。 -
部分列更新。如果用户希望更新部分字段,需要使用写时合并实现,并通过特定的参数来开启部分列更新的支持。请查阅文档部分列更新。
下面以一个典型的用户基础信息表,来看看如何建立读时合并和写时合并的主键模型表。这个表数据没有聚合需求,只需保证主键唯一性。(这里的主键为 user_id + username
)。
ColumnName | Type | IsKey | Comment |
---|---|---|---|
user_id | BIGINT | Yes | 用户 id |
username | VARCHAR(50) | Yes | 用户昵称 |
city | VARCHAR(20) | No | 用户所在城市 |
age | SMALLINT | No | 用户年龄 |
sex | TINYINT | No | 用户性别 |
phone | LARGEINT | No | 用户电话 |
address | VARCHAR(500) | No | 用户住址 |
register_time | DATETIME | No | 用户注册时间 |
1 写时合并¶
写时合并建表语句为:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
2 读时合并¶
读时合并的建表语句如下:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
用户需要在建表时添加下面的 property
来开启读时合并。
SQL | |
---|---|
1 |
|
Warning
在 2.1
版本中,写时合并将会是主键模型的默认方式。
对于新用户,强烈推荐使用 2.0
及其以上版本。在 2.0
版本中,写时合并的性能和稳定性都有大幅的提升和优化。
对于 1.2
的用户
-
建议使用
1.2.4
及以上版本,该版本修复了一些bug
和稳定性问题。 -
在
be.conf
中添加配置项:disable_storage_page_cache=false
。不添加该配置项可能会对数据导入性能产生较大影响
3 使用注意¶
-
Unique
表的实现方式只能在建表时确定,无法通过schema change
进行修改。 -
旧的
Merge-on-Read
的实现无法无缝升级到Merge-on-Write
的实现(数据组织方式完全不同),如果需要改为使用写时合并的实现版本,需要手动执行insert into unique-mow-table select * from source table
来重新导入。 -
整行更新:
Unique
模型默认的更新语义为整行UPSERT
,即UPDATE OR INSERT
,该行数据的key
如果存在,则进行更新,如果不存在,则进行新数据插入。在整行UPSERT
语义下,即使用户使用insert into
指定部分列进行写入,Doris
也会在Planner
中将未提供的列使用NULL
值或者默认值进行填充 -
部分列更新。如果用户希望更新部分字段,需要使用写时合并实现,并通过特定的参数来开启部分列更新的支持。请查阅文档部分列更新获取相关使用建议。