CollapsingMergeTree表引擎
CollapsingMergeTree
就是一種通過
以增代删
的思路,支援行級資料修改和删除的表引擎。它通過定義一個
sign
标記位字段,記錄資料行的狀态。如果
sign
标記為1,則表示這是一行有效的資料;如果
sign
标記為-1,則表示這行資料需要被删除。當
CollapsingMergeTree
分區合并時,同一資料分區内,sign标記為1和-1的一組資料會被抵消删除。
每次需要新增資料時,寫入一行sign标記為1的資料;需要删除資料時,則寫入一行sign标記為-1的資料。
建表文法
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = CollapsingMergeTree(sign)
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]
建表示例
上面的建表語句使用
CollapsingMergeTree(sign)
,其中字段
sign
是一個Int8類型的字段
CREATE TABLE emp_collapsingmergetree
(
emp_id UInt16 COMMENT '員工id',
name String COMMENT '員工姓名',
work_place String COMMENT '工作地點',
age UInt8 COMMENT '員工年齡',
depart String COMMENT '部門',
salary Decimal32(2) COMMENT '工資',
sign Int8
) ENGINE = CollapsingMergeTree(sign) ORDER BY (emp_id, name) PARTITION BY work_place;
使用方式
CollapsingMergeTree
同樣是以
ORDER BY
排序鍵作為判斷資料唯一性的依據。
-- 插入新增資料,sign=1表示正常資料
INSERT INTO emp_collapsingmergetree VALUES (1,'tom','上海',25,'技術部',20000,1);
-- 更新上述的資料
-- 首先插入一條與原來相同的資料(ORDER BY字段一緻),并将sign置為-1
INSERT INTO emp_collapsingmergetree VALUES (1,'tom','上海',25,'技術部',20000,-1);
-- 再插入更新之後的資料
INSERT INTO emp_collapsingmergetree VALUES (1,'tom','上海',25,'技術部',30000,1);
-- 檢視一下結果
select * from emp_collapsingmergetree ;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ -1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ 1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 30000.00 │ 1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┘
-- 執行分區合并操作
optimize table emp_collapsingmergetree;
-- 再次查詢,sign=1與sign=-1的資料互相抵消了,即被删除
select * from emp_collapsingmergetree ;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 30000.00 │ 1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┘
注意點
- 分區合并
分數資料折疊
不是實時
的,需要背景進行
Compaction
操作,使用者也可以使用手動合并指令,但是效率會很低,一般不推薦在生産環境中使用。
當進行彙總資料操作時,可以通過改變查詢方式,來過濾掉被删除的資料
SELECT emp_id,name,sum(salary * sign)FROM emp_collapsingmergetree GROUP BY emp_id, name HAVING sum(sign) > 0;
┌─emp_id─┬─name─┬─sum(multiply(salary, sign))─┐
│ 1 │ tom │ 30000.00 │
└────────┴──────┴─────────────────────────────┘
隻有
相同分區内
的資料才有可能被折疊。其實,當我們修改或删除資料時,這些被修改的資料通常是在一個分區内的,是以不會産生影響。
- 資料寫入順序
值得注意的是:
CollapsingMergeTree
對于寫入資料的順序有着嚴格要求,否則導緻無法正常折疊。
-- 建表
CREATE TABLE emp_collapsingmergetree_order
(
emp_id UInt16 COMMENT '員工id',
name String COMMENT '員工姓名',
work_place String COMMENT '工作地點',
age UInt8 COMMENT '員工年齡',
depart String COMMENT '部門',
salary Decimal32(2) COMMENT '工資',
sign Int8
) ENGINE = CollapsingMergeTree(sign) ORDER BY (emp_id, name) PARTITION BY work_place;
-- 先插入需要被删除的資料,即sign=-1的資料
INSERT INTO emp_collapsingmergetree_order VALUES (1,'tom','上海',25,'技術部',20000,-1);
-- 再插入sign=1的資料
INSERT INTO emp_collapsingmergetree_order VALUES (1,'tom','上海',25,'技術部',20000,1);
-- 查詢表
SELECT * FROM emp_collapsingmergetree_order;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ -1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ 1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┘
-- 執行合并操作
optimize table emp_collapsingmergetree_order;
-- 再次查詢表
-- 舊資料依然存在
SELECT * FROM emp_collapsingmergetree_order;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ -1 │
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ 1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┘
如果資料的寫入程式是
單線程執行
的,則能夠較好地控制
寫入順序
;如果需要處理的資料量很大,資料的寫入程式通常是多線程執行的,那麼此時就不能保障資料的寫入順序了。在這種情況下,
CollapsingMergeTree
的工作機制就會出現問題。但是可以通過
VersionedCollapsingMergeTree
的表引擎得到解決。
VersionedCollapsingMergeTree表引擎
上面提到
CollapsingMergeTree
表引擎對于資料寫入亂序的情況下,不能夠實作資料折疊的效果。
VersionedCollapsingMergeTree
表引擎的作用與
CollapsingMergeTree
完全相同,它們的不同之處在于,
VersionedCollapsingMergeTree
對資料的寫入順序沒有要求,在同一個分區内,任意順序的資料都能夠完成折疊操作。
VersionedCollapsingMergeTree
使用version列來實作亂序情況下的資料折疊。
建表文法
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = VersionedCollapsingMergeTree(sign, version)
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]
可以看出:該引擎除了需要指定一個sign辨別之外,還需要指定一個UInt8類型的version版本号。
建表示例
CREATE TABLE emp_versioned
(
emp_id UInt16 COMMENT '員工id',
name String COMMENT '員工姓名',
work_place String COMMENT '工作地點',
age UInt8 COMMENT '員工年齡',
depart String COMMENT '部門',
salary Decimal32(2) COMMENT '工資',
sign Int8,
version Int8
) ENGINE = VersionedCollapsingMergeTree(sign, version) ORDER BY (emp_id, name) PARTITION BY work_place;
-- 先插入需要被删除的資料,即sign=-1的資料
INSERT INTO emp_versioned VALUES (1,'tom','上海',25,'技術部',20000,-1,1);
-- 再插入sign=1的資料
INSERT INTO emp_versioned VALUES (1,'tom','上海',25,'技術部',20000,1,1);
-- 在插入一個新版本資料
INSERT INTO emp_versioned VALUES (1,'tom','上海',25,'技術部',30000,1,2);
-- 先不執行合并,檢視表資料
select * from emp_versioned;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┬─version─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ 1 │ 1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┴─────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┬─version─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 20000.00 │ -1 │ 1 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┴─────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┬─version─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 30000.00 │ 1 │ 2 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┴─────────┘
-- 擷取正确查詢結果
SELECT emp_id,name,sum(salary * sign) FROM emp_versioned GROUP BY emp_id,name HAVING sum(sign) > 0;
┌─emp_id─┬─name─┬─sum(multiply(salary, sign))─┐
│ 1 │ tom │ 30000.00 │
└────────┴──────┴─────────────────────────────┘
-- 手動合并
optimize table emp_versioned;
-- 再次查詢
select * from emp_versioned;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┬─sign─┬─version─┐
│ 1 │ tom │ 上海 │ 25 │ 技術部 │ 30000.00 │ 1 │ 2 │
└────────┴──────┴────────────┴─────┴────────┴──────────┴──────┴─────────┘
可見上面雖然在插入資料亂序的情況下,依然能夠實作折疊的效果。之是以能夠達到這種效果,是因為在定義
version
字段之後,
VersionedCollapsingMergeTree
會自動将
version
作為排序條件并增加到
ORDER BY
的末端,就上述的例子而言,最終的排序字段為
ORDER BY emp_id,name,version desc
。