clickhouse21.7.11.3 ReplacingMergeTree、SummingMergeTree数据一致性

需要掌握:

  1. clickhourse21.7.11.3 表引擎-ReplacingMergeTree

  2. clickhourse21.7.11.3 表引擎-SummingMergeTree

说明

在使用ReplacingMergeTree、SummingMergeTree这类表引擎的时候,会出现 短暂数据不一致 的情况

在某些对一致性非常敏感的场景,通常有以下几种解决方案:

  1. 手动OPTIMIZE(不推荐)
  2. 通过group by去重
  3. 通过final查询

准备

准备表

CREATE TABLE test_a(
  user_id UInt64,
  score String,
  deleted UInt8 DEFAULT 0,
  create_time DateTime DEFAULT toDateTime(0)
)ENGINE= ReplacingMergeTree(create_time)
ORDER BY user_id;

解释:

  • user_id 是数据去重更新的标识

  • create_time 是版本号字段,每组数据中create_time最大的一行表示最新的数据

  • deleted 是自定的一个标记位,比如0代表未删除,1代表删除数据

写入1000万测试数据

INSERT INTO TABLE test_a(user_id,score)
WITH(
SELECT ['A','B','C','D','E','F','G']
)AS dict
SELECT number AS user_id, dict[number%7+1] FROM numbers(10000000);

修改前50万行数据

修改内容包括name字段和 create_time 版本号字段

INSERT INTO TABLE test_a(user_id,score,create_time)
WITH(
SELECT ['AA','BB','CC','DD','EE','FF','GG']
)AS dict
SELECT number AS user_id, dict[number%7+1], now() AS create_time FROM
numbers(500000);

统计总数

select count() from test_a;

手动OPTIMIZE(不推荐)

在写入数据后,立刻执行OPTIMIZE强制触发新写入分区的合并动作

OPTIMIZE TABLE 表名 FINAL;

通过group by去重

select
user_id ,
argMax(score, create_time) as score, 
argMax(deleted, create_time) as deleted,
max(create_time) as ctime 
from test_a 
group by user_id
having deleted = 0;

解释:

  • argMax(field1,field2) :按照field2的最大值取field1的值。见 英文解释、中文解释

  • 当更新数据时,会写入一行新的数据,例如上面语句中,通过查询最大的 create_time 得到修改后的 score 字段值

创建视图,方便测试

CREATE VIEW v_test_a AS
SELECT
user_id ,
argMax(score, create_time) AS score, 
argMax(deleted, create_time) AS deleted,
max(create_time) AS ctime 
FROM test_a 
GROUP BY user_id
HAVING deleted = 0;

插入重复数据,再次查询

再次插入一条数据

insert into table test_a(user_id,score,create_time)
values(0,'AAAA',now());

再次查询

select *
from v_test_a
where user_id = 0;

删除数据测试

再次插入一条标记为删除的数据

insert into table test_a(user_id,score,deleted,create_time) 
values(0,'AAAA',1,now());

再次查询,刚才那条数据看不到了

select *
from v_test_a
where user_id = 0;

这行数据并没有被真正的删除,而是被过滤掉了。在一些合适的场景下,可以结合表级别的TTL最终将物理数据删除

通过final查询

在查询语句后增加 FINAL 修饰符,这样在查询的过程中将会执行 Merge 的特殊逻辑(例如数据去重、预聚合等)

早期版本

但是这种方法在早期版本基本没有人使用,因为在增加FINAL之后,我们的查询将会变成一个单线程的执行过程,查询速度非常慢

v20.5.2.7 版本

在 v20.5.2.7-stable 版本中,FINAL 查询支持多线程执行,并且可以通过 max_final_threads 参数控制单个查询的线程数。但是目前读取 part 部分的动作依然是串行的

FINAL 查询最终的性能和很多因素相关,列字段的大小、分区的数量等等都会影响到最终的查询时间,所以还要结合实际场景取舍

explain pipeline select * from datasets.visits_v1 final where StartDate = '2014-03-17' settings max_final_threads = 2;

参考:
https://mp.weixin.qq.com/s/a8OfsBn9VFnj7oxp0IIVGg
https://blog.csdn.net/qq_40378034/article/details/120473116


原文出处:/show_1IX3RLRIJVfY.html