ClickHouse数据一致性

查询CK手册发现,即便对数据一致性支持最好的Mergetree,也只是保证最终一致性 :

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

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

1 准备测试表和数据

(1)创建表

复制代码
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 代表删除数据。

(2)写入 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);`
`

(3)修改前 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);`
`

(4)统计总数

复制代码
SELECT` `COUNT() FROM test_a;`

`10500000`
`

还未触发分区合并,所以还未去重。

2 手动 OPTIMIZE

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

复制代码
OPTIMIZE TABLE test_a FINAL;`

`语法:OPTIMIZE TABLE` `[db.]name [ON CLUSTER cluster]` `[PARTITION partition | PARTITION ID 'partition_id']` `[FINAL]` `[DEDUPLICATE [BY expression]]`
`

3 通过 Group by 去重

(1)执行去重的查询

复制代码
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字段值。

(2)创建视图,方便测试

复制代码
CREATE VIEW view_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;`
`

( 3 )插入重复数据,再次查询

复制代码
#再次插入一条数据`
`INSERT INTO TABLE` `test_a(user_id,score,create_time)` `VALUES(0,'AAAA',now())`

`#再次查询`
`SELECT` `*`
`FROM view_test_a`
`WHERE user_id =` `0;`
`

( 4 )删除数据测试

复制代码
#再次插入一条标记为删除的数据`
`INSERT INTO TABLE` `test_a(user_id,score,deleted,create_time)` `VALUES(0,'AAAA',1,now());`

`#再次查询,刚才那条数据看不到了`
`SELECT` `*`
`FROM view_test_a`
`WHERE user_id =` `0;`
`

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

4 通过 FINAL 查询

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

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

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

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

参考链接:https://github.com/ClickHouse/ClickHouse/pull/10463

使用hits_v1表进行测试:

分别安装了20.4.5.36 和 21.7.3.14 两个版本的ClickHouse进行对比。

4.1 老版本测试

(1)普通查询语句

select * from visits_v1 WHERE StartDate = '2014-03-17' limit 100;

(2)FINAL查询

select * from visits_v1 FINAL WHERE StartDate = '2014-03-17' limit 100;

先前的并行查询变成了单线程。

4.2 新版本测试

( 1 )普通语句查询

select * from visits_v1 WHERE StartDate = '2014-03-17' limit 100 settings max_threads = 2;

查看执行计划:

explain pipeline select * from visits_v1 WHERE StartDate = '2014-03-17' limit 100 settings max_threads = 2;

(Expression)

ExpressionTransform × 2

(SettingQuotaAndLimits)

(Limit)

Limit 2 → 2

(ReadFromMergeTree)

MergeTreeThread × 2 0 → 1

明显将由2个线程并行读取 part 查询。

( 2 )FINAL 查询

select * from visits_v1 final WHERE StartDate = '2014-03-17' limit 100 settings max_final_threads = 2;

查询速度没有普通的查询快,但是相比之前已经有了一些提升,查看 FINAL 查询的执行计划:

explain pipeline select * from visits_v1 final WHERE StartDate = '2014-03-17' limit 100 settings max_final_threads = 2;

(Expression)

ExpressionTransform × 2

(SettingQuotaAndLimits)

(Limit)

Limit 2 → 2

(ReadFromMergeTree)

ExpressionTransform × 2

CollapsingSortedTransform × 2

Copy 1 → 2

AddingSelector

ExpressionTransform

MergeTree 0 → 1

从CollapsingSortedTransform这一步开始已经是多线程执行,但是读取 part 部分的动作还是串行。

相关推荐
隔窗听雨眠2 小时前
数据中台退潮之后的企业数据架构重构
大数据·数据中台·数据架构
QXWZ_IA3 小时前
北斗高精度定位在泛自然资源行业的技术演进与应用方向
大数据·人工智能
starzy19903 小时前
Scala 可变 Set 操作:从性能问题到最佳实践
大数据·scala
时文鲜读4 小时前
算力基建提速,数据中心安全建设与工业可靠性如何同步升级?
大数据·人工智能·安全
AllData公司负责人4 小时前
【产品便捷使用一】AIIData 数据中台:企业基础版核心能力支持,一站式全链路数据处理实操指南
大数据·前端·数据治理·数据可视化·数据开发·数据服务·数据接入
Decay__5 小时前
19_MySQL 告警与自动化运维 —— 告警分级收敛 / Webhook / 定时巡检 / 脚本库
运维·数据库·sql·mysql·架构
QY_Research_11 小时前
2026房地产NFT平台创业机遇与落地指南分析报告
大数据·人工智能·物联网·机器人·制造
全栈陈序员15 小时前
【Git】从入门到精通(五)—— git add:将文件加入暂存区
大数据·git·elasticsearch
KKKlucifer16 小时前
国内数据安全服务的产品智能化转型:大模型赋能下的技术能力重构分析
大数据·数据库·重构
故七月17 小时前
AI 答案里的竞品共现:怎么看出赛道格局
大数据·人工智能