真实模拟一条记录的insert-cancel-insert,验证CollapsingMergeTree的+1/-1抵消在跨part和同part两种场景下真实不同的生效时机。
代码CREATE TABLE demo.ctest (k UInt64, v String, sign Int8) ENGINE=CollapsingMergeTree(sign) ORDER BY k; INSERT INTO demo.ctest VALUES (1, 'active', 1); -- 真实先插入原始状态 INSERT INTO demo.ctest VALUES (1, 'active', -1); -- 真实插入取消标记(撤销上一行) INSERT INTO demo.ctest VALUES (1, 'inactive', 1); -- 真实插入新状态
-- merge前
SELECT * FROM demo.ctest ORDER BY k, sign;
→ 1 active -1
1 inactive 1
1 active 1 ← 真实3行都在,3个part
OPTIMIZE TABLE demo.ctest FINAL;
SELECT * FROM demo.ctest;
→ 1 inactive 1 ← 真实(active,+1)和(active,-1)这对互相抵消消失了
-- 只剩(inactive,+1)这一行,因为它没有配对的-1来抵消CollapsingMergeTree真实的抵消规则很直白:在同一个排序键(ORDER BY k)下,如果存在一对除sign外其余列完全相同、且sign分别是+1和-1的行,merge时真实会把这一对一起丢弃;本文的(active,+1)和(active,-1)正好是这样一对,真实被丢弃了;而(inactive,+1)没有配对的(inactive,-1)来抵消,真实原样保留了下来,最终结果正确反映了"这条记录最新状态是inactive"。
INSERT INTO demo.ctest2 VALUES (1, 'a', 1), (1, 'a', -1); -- 真实同一条INSERT语句携带这一对 SELECT * FROM demo.ctest2; → (空) ← 真实0行,没有等任何merge就已经抵消了 SELECT count() FROM system.parts WHERE table='ctest2' AND active; → 0 ← 真实这个part写入时就直接是空的
每一步都是本文上面用真实CollapsingMergeTree跑出来的原始结果。
CollapsingMergeTree(sign)