Clickhouse学习笔记(11)—— 数据一致性

使用合并树引擎时,无论是ReplacingMergeTree还是SummingMergeTree,都只能保证数据的最终一致性,因为数据的去重、聚合等操作会在数据合并的期间进行,而合并会在后台以一个不确定的时间进行,因此无法预先计划;

数据准备

建表:

sql 复制代码
CREATE TABLE test_consistence(
 user_id UInt64,
 score String,
 deleted UInt8 DEFAULT 0,
 create_time DateTime DEFAULT toDateTime(0)
)ENGINE= ReplacingMergeTree(create_time)
ORDER BY user_id;

其中deleted作为是否删除的标识;create_time 是版本号字段,每组数据中 create_time 最大的一行表示最新的数据

导入数据:

sql 复制代码
INSERT INTO TABLE test_consistence(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);

数据结构如下:

通过修改create_time的值,可以更新数据:

sql 复制代码
INSERT INTO TABLE test_consistence(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);

now()函数可以获取当前时间

查询发现,此时表中共有10500000条数据,说明还未进行去重;

去重方案

手动 OPTIMIZE

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

optimize table test_consistence;

耗费时间:

可以看到,optimize是一个相对比较耗时的操作(与select、insert相比),因为需要进行大量的数据读写

通过 Group by 去重

执行去重的查询

sql 复制代码
SELECT
 user_id ,
 argMax(score, create_time) AS score, 
 argMax(deleted, create_time) AS deleted,
 max(create_time) AS ctime 
FROM test_consistence 
GROUP BY user_id
HAVING deleted = 0;

函数argMaxargMax(field1,field2):按照 field2 的最大值取 field1 的值

因此argMax(score, create_time)的含义就是,按照create_time的最大值取score的值,因为create_time代表当前数据的更新时间,因此总能取到最新的数据;

同理argMax(deleted, create_time)是取最新的deleted标识,来判断数据是否被删除

创建视图

通过上面的操作我们可以实现数据的去重等操作,从而保证一致性,因此创建视图来保存数据查询的逻辑

sql 复制代码
CREATE VIEW view_test_consistence AS
SELECT
 user_id ,
 argMax(score, create_time) AS score, 
 argMax(deleted, create_time) AS deleted,
 max(create_time) AS ctime 
FROM test_consistence 
GROUP BY user_id
HAVING deleted = 0;

视图创建的格式:create view view_name as select......

注意:这里创建的视图仅仅保存了数据查询的逻辑,并不保存具体的数据;

测试去重效果

插入数据:

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

然后查询数据:

sql 复制代码
select * from test_consistence where user_id = '0';

发现并未去重;

而从视图中查询:

sql 复制代码
select * from view_test_consistence where user_id = '0';

则仅有最新的数据:

通过 FINAL 查询

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

测试

① 不使用final查询:

sql 复制代码
select * from visits_v1 WHERE StartDate = '2014-03-17' limit 100;

②使用final查询:

sql 复制代码
select * from visits_v1 final WHERE StartDate = '2014-03-17' limit 100;

可以看到,查询速度并没有普通的查询快,因此使用final确保数据一致性也是以效率为代价的;

版本说明

早期版本增加 FINAL 之后,查询会变成单线程;但从v20.5.2.7-stable版本之后转为多线程执行,并可以通过max_final_threads 参数控制单个查询的线程数:

sql 复制代码
explain pipeline select * from visits_v1 final WHERE StartDate = '2014-03-17' limit 100;

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

相关推荐
不掰手腕14 分钟前
在UnionTech OS Server 20 (统信UOS服务器版) 上离线安装PostgreSQL (pgsql) 数据库
linux·数据库·postgresql
MAGICIAN...15 分钟前
【Redis五种数据类型】
数据库·redis·缓存
yddddddy36 分钟前
SQLite的基本操作
数据库·sqlite
华科云商xiao徐39 分钟前
Java并发编程常见“坑”与填坑指南
javascript·数据库·爬虫
知其然亦知其所以然42 分钟前
面试官微笑发问:第100万页怎么查?我差点当场沉默…
后端·mysql·面试
广州腾科助你拿下华为认证1 小时前
PostgreSQL认证_PGCM考试难度有多大?
数据库·postgresql
代码的余温1 小时前
Oracle RAC认证矩阵:规避风险的关键指南
数据库·oracle·矩阵
白鲸开源1 小时前
一行代码引发 12G 内存 5 分钟爆仓!SeaTunnel Kafka 连接器"内存溢出"元凶抓到了
数据库·kafka·开源
cellurw2 小时前
Day39 SQLite数据库操作与HTML核心API及页面构建
数据库·sqlite·html