标记删除
标记删除功能是对 DELETE 语句删除功能的一种补充。使用 DELETE 语句对数据删除,无法支持高频操作场景。
另外,类似于CDC(Change Data Capture)场景中,INSERT 和 DELETE 一般是穿插出现的。
标记删除功能就是为了支持以上两种场景而做的功能。
实现原理
标记删除功能仅适用于 UNIQUE KEY 模型的表。其原理是在表中增加了一个隐藏列 __DELETE_SIGN__
。该列值为 true,则表示该行为一个删除操作,如果为 false,则表示该行是一个插入操作。该隐藏列的只需要用户在导入数据中添加。
假设表结构如下:
列名 | 主键 |
---|---|
order_id | Yes |
order_type | No |
order_status | No |
我们插入以下三行数据:
1000, TYPE#1, PENDING, false
1001, TYPE#2, PENDING, false
1002, TYPE#3, PENDING, false
其中第四列均为false,即表示这三行都是插入操作。执行后,查询结果为:
order_id | order_type | order_status |
---|---|---|
1000 | TYPE#1 | PENDING |
1001 | TYPE#2 | PENDING |
1002 | TYPE#3 | PENDING |
接下来我们再导入两行数据:
1001, TYPE#2, PENDING, true
1002, TYPE#3, PAID, false
第一行是一个删除操作,是将 1001 这个订单id对应的数据删除(TYPE#2, PENDING 两个值在这行数据中无意义,可以随意填写,但必须填写以保证列数匹配)。
第二行是一个插入操作,相当于将 1002 这个订单的状态更新为 PAID
。
执行后,查询结果为:
order_id | order_type | order_status |
---|---|---|
1000 | TYPE#1 | PENDING |
1002 | TYPE#3 | PAID |
由以上示例可以看出,配合 UNIQUE KEY 模型,可以实现按主键的更新或删除操作。当需要删除时,需要将对应的隐藏列设为 true。而当隐藏列是false时,则操作类似于 UPSERT 操作,即有则更新,无则插入。
启用标记删除功能
标记删除功能是 Doris 3.10 版本之后引入的新功能。
在新版本中创建的 UNIQUE KEY 表默认都包含隐藏列。而在之前版本中创建的 UNIQUE KEY 表并不具有隐藏列。对于老版本的表,可以使用以下方式增加隐藏列:
ALTER TABLE tablename ENABLE FEATURE "BATCH_DELETE";
这个操作本质上是一个 Schema Change 操作,执行后,需通过 SHOW ALTER TABLE COLUMN 查看作业执行进度。
如果想确定一个表是否已开启标记删除功能,可以通过 设置一个变量来显示隐藏列
SET show_hidden_columns=true`
之后使用 DESC tablename
,如果输出中有 __DELETE_SIGN__
列,则表示该表已开启标记删除功能。
在导入中使用标记删除功能
在不同的数据导入方式中使用标记删除的方式略有不同。标记删除目前支持以下数据导入方式:
在这些导入中使用标记删除功能,都需要添加以下两个属性:
-
Merge Type
Merge Type 分为3种,APPEND、DELETE 和 MERGE。默认为 APPEND。
APPEND 方式和正常导入无异。
DELETE 方式则表示这一批数据中的每一行都是删除操作。在这种方式下,无需再指定 Delete Label 列。
MERGE 方式表示这一批数据中混合了插入和删除操作。此时,需要通过指定 Delete Label 列来标识每一行的操作类型。
-
Delete Label
Delete Label 用于在 MERGE 方式下,指定数据中的某一列是删除标记列。用户可以指定当这一列为何值时,表示DELETE操作。
具体使用语法请参阅各自的文档,这里仅对不同导入方式进行简单的示例说明。假设原始导入数据如下:
1000,TYPE#1,PENDING,0
1001,TYPE#2,PENDING,0
1002,TYPE#3,PENDING,0
1003,TYPE#2,PENDING,1
1004,TYPE#3,PAID,1
Stream Load
Stream Load 请求如下:
curl --location-trusted -u root \
-H "columns: order_id, order_type, order_status, delete_label" \
-H "merge_type: MERGE" \
-H "delete: delete_label=1" \
-T data.txt http://host:port/api/testDb/testTbl/_stream_load
这个示例表示第四列为 Delete Label 列,并且当值为1时,表示对应行为删除操作。
Broker Load
LOAD LABEL example_db.my_label
(
MERGE DATA INFILE("hdfs://abc.com:8888/user/doris/test/ml/file1")
INTO TABLE example_tbl
COLUMNS TERMINATED BY ","
(order_id, order_type, order_status, delete_label)
DELETE ON delete_label=1
)
WITH BROKER 'bos'
(
...
);
这个示例表示第四列为 Delete Label 列,并且当值为1时,表示对应行为删除操作。
Routine Load
CREATE ROUTINE LOAD example_db.job1 ON example_tbl
WITH DELETE
COLUMNS(order_id, order_type, order_status, delete_label)
PROPERTIES
(
"desired_concurrent_number"="3",
"max_batch_interval" = "20",
"max_batch_rows" = "300000",
"max_batch_size" = "209715200",
"strict_mode" = "false"
)
FROM KAFKA
(
...
);
注意这里我们使用的 Merge Type 是 DELETE,因此无需指定 Delete Label,第四列的值不会被使用,所有数据均为删除操作。
注意事项
- 因为 Doris 无法保证一批次导入数据内部的顺序性,所以在诸如 CDC 等场景下,如需确保数据前后顺序,需配合 Sequence Column 功能一起使用。