ClickHouse存儲引擎之ReplacingMergeTree引擎

一、ReplacingMergeTree作用

​ ClickHouse中最常用也是最基礎的表引擎爲MergeTree,在它的功能基礎上添加特定功能就構成了MergeTree系列引擎。MergeTree支持主鍵,但主鍵主要用來縮小查詢範圍,且不具備唯一性約束,可以正常寫入相同主鍵的數據。但在一些情況下,可能需要表中沒有主鍵重複的數據。ReplacingMergeTree就是在MergeTree的基礎上加入了去重的功能,但它僅會在合併分區時,去刪除重複的數據,寫入相同數據時並不會引發異常。

二、功能示例

創建一張ReplacingMergeTree的表和創建MergeTree類似,修改引擎即可。ReplacingMergeTree引擎創建規範爲:ENGINE = ReplacingMergeTree([ver]),其中ver爲選填參數,它需要指定一個UInt8/UInt16、Date或DateTime類型的字段,它決定了數據去重時所用的算法,如果沒有設置該參數,合併時保留分組內的最後一條數據;如果指定了該參數,則保留ver字段取值最大的那一行。

1、不指定ver參數

1
2
3
4
5
6
7
8
9
10
11
-- 創建未指定ver參數ReplacintMergeTree引擎的表
CREATE TABLE replac_merge_test
(
    `id` String, 
    `code` String, 
    `create_time` DateTime
)
ENGINE = ReplacingMergeTree()
PARTITION BY toYYYYMM(create_time)
PRIMARY KEY id
ORDER BY (id, code)
 

ReplacingMergeTree會根據ORDER BY所聲明的表達式去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 在上述表中插入數據
insert into replac_merge_test values ('A000', 'code1', now()),('A000', 'code1', '2020-07-28 21:30:00'), ('A001', 'code1', now()), ('A001', 'code2', '2020-07-28 21:30:00'), ('A0002', 'code2', now());
-- 查詢當前數據
select * from replac_merge_test;
┌─id────┬─code──┬─────────create_time─┐
│ A000  │ code1 │ 2020-07-28 21:23:48 │
│ A000  │ code1 │ 2020-07-28 21:30:00 │
│ A0002 │ code2 │ 2020-07-28 21:23:48 │
│ A001  │ code1 │ 2020-07-28 21:23:48 │
│ A001  │ code2 │ 2020-07-28 21:30:00 │
└───────┴───────┴─────────────────────┘

-- 強制進行分區合併
optimize table replac_merge_test FINAL;
-- 再次查詢數據
select * from replac_merge_test;
┌─id────┬─code──┬─────────create_time─┐
│ A000  │ code1 │ 2020-07-28 21:30:00 │
│ A0002 │ code2 │ 2020-07-28 21:23:48 │
│ A001  │ code1 │ 2020-07-28 21:23:48 │
│ A001  │ code2 │ 2020-07-28 21:30:00 │
└───────┴───────┴─────────────────────┘
 

通過上面示例可以看到,id、code相同的字段’A000’,’code1’被去重剩餘一條數據,由於創建表時沒有設置ver參數,故保留分組內的最後一條數據(create_time字段)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 再次使用insert插入一條數據
insert into replac_merge_test values ('A001', 'code1', '2020-07-28 21:30:00');

-- 查詢表中數據
select * from replac_merge_test;
┌─id────┬─code──┬─────────create_time─┐
│ A000  │ code1 │ 2020-07-28 21:30:00 │
│ A0002 │ code2 │ 2020-07-28 21:23:48 │
│ A001  │ code1 │ 2020-07-28 21:23:48 │
│ A001  │ code2 │ 2020-07-28 21:30:00 │
└───────┴───────┴─────────────────────┘
┌─id───┬─code──┬─────────create_time─┐
│ A001 │ code1 │ 2020-07-28 21:30:00 │
└──────┴───────┴─────────────────────┘
 

可以看到,再次插入重複數據時,查詢仍然會存在重複。在ClickHouse中,默認一條insert插入的數據爲同一個數據分區,不同insert插入的數據爲不同的分區,所以ReplacingMergeTree是以分區爲單位進行去重的,也就是說只有在相同的數據分區內,重複數據纔可以被刪除掉。只有數據合併完成後,纔可以使用引擎特性進行去重。

2、指定ver參數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
-- 創建指定ver參數ReplacingMergeTree引擎的表
CREATE TABLE replac_merge_ver_test
(
    `id` String, 
    `code` String, 
    `create_time` DateTime
)
ENGINE = ReplacingMergeTree(create_time)
PARTITION BY toYYYYMM(create_time)
PRIMARY KEY id
ORDER BY (id, code)

-- 插入測試數據
insert into replac_merge_ver_test values('A000', 'code1', '2020-07-10 21:35:30'),('A000', 'code1', '2020-07-15 21:35:30'),('A000', 'code1', '2020-07-05 21:35:30'),('A000', 'code1', '2020-06-05 21:35:30');

-- 查詢數據
select * from replac_merge_ver_test;
┌─id───┬─code──┬─────────create_time─┐
│ A000 │ code1 │ 2020-06-05 21:35:30 │
└──────┴───────┴─────────────────────┘
┌─id───┬─code──┬─────────create_time─┐
│ A000 │ code1 │ 2020-07-10 21:35:30 │
│ A000 │ code1 │ 2020-07-15 21:35:30 │
│ A000 │ code1 │ 2020-07-05 21:35:30 │
└──────┴───────┴─────────────────────┘

-- 強制進行分區合併
optimize table replac_merge_ver_test FINAL;

-- 查詢數據
select * from replac_merge_ver_test;
┌─id───┬─code──┬─────────create_time─┐
│ A000 │ code1 │ 2020-07-15 21:35:30 │
└──────┴───────┴─────────────────────┘
┌─id───┬─code──┬─────────create_time─┐
│ A000 │ code1 │ 2020-06-05 21:35:30 │
└──────┴───────┴─────────────────────┘
 

由於上述創建表是以create_time的年月來進行分區的,可以看出不同的數據分區,ReplacingMergeTree並不會進行去重,並且在相同數據分區內,指定ver參數後,會保留同一組數據內create_time時間最大的那一行數據。

三、ReplacingMergeTree引擎總結

  • 使用ORDER BY排序鍵,作爲判斷數據是否重複的唯一鍵
  • 只有在合併分區時,纔會觸發數據的去重邏輯
  • 刪除重複數據,是以數據分區爲單位。同一個數據分區的重複數據纔會被刪除,不同數據分區的重複數據仍會保留
  • 在進行數據去重時,由於已經基於ORDER BY排序,所以可以找到相鄰的重複數據
  • 數據去重策略爲:
    • 若指定了ver參數,則會保留重複數據中,ver字段最大的那一行
    • 若未指定ver參數,則會保留重複數據中最末的那一行數據
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章