一、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參數,則會保留重複數據中最末的那一行數據