【Clickhouse】ReplaceingMergeTree引擎final实现合并去重探索 | 京东云技术团队

news2024/11/16 13:31:43

前言

在OLAP实践中,在有数据更新的场景中,比如存储订单数据,我们经常会用到ReplaceingMergeTree引擎来去重数据,以获取数据的最新状态。但是ReplaceingMergeTree引擎实现数据的去重合并的操作是异步的,这样在实际查询的时候,其实是仍然有一部分数据是未进行合并的。为了保证统计数据的准确性,比如订单金额,一个常用的方法是在查询时增加final关键字。那final关键字是如何合并数据的,以及合并的数据范围是怎样的,本文就对此做一个简单的探索。

知识准备

分片:分片就是clickhouse的实例节点,不同的分片就代表不同的节点或机器,分片之间是物理隔离的 分区:分区是一个表中通过指定的规则划分而成的逻辑数据集,比如日期分区,分区是一种逻辑上的,不同的分片上会有相同的分区

探索过程

探索过程比较长,请大家保持耐心,如果不想看过程,可以直接看结论哈,马上开始~

本文基于的clickhouse版本为version 23.3.1.2823

创建表

创建ReplacingMergeTree引擎的表,分布式表union_order_onl_all_test,本地表union_order_onl_local_test,以日期为分区,order_id作为排序键,mid是消息ID,用消息ID作为数据变更的版本号,同时order_id字段作为分片hash字段,不同的订单会被写入到不同的实例上。

CREATE TABLE gbn_onl_mix.union_order_onl_local_test on cluster lf6ckcnts05
(
    `order_id` UInt64 COMMENT '订单号',
    `after_prefr_amount_1` Float64 COMMENT '订单金额',
    `deal_flag` UInt8 COMMENT '成交标识',
    `mid` String COMMENT '消息ID',
    `update_time` String COMMENT '更新时间',
    `ver` UInt64 DEFAULT toUInt64OrZero(mid) COMMENT '版本号',
    `dt`Date DEFAULT toDate(update_time) COMMENT '分区'
)
ENGINE = ReplicatedReplacingMergeTree('/clickhouse/lf6ckcnts05/jdob_ha/gbn_onl_mix/lf6ckcnts05/{shard}', '{replica}', ver)
PARTITION BY toYYYYMMDD(dt)
ORDER BY (order_id)
TTL dt + toIntervalDay(7)
SETTINGS storage_policy = 'jdob_ha', index_granularity = 3


CREATE TABLE gbn_onl_mix.union_order_onl_all_test on cluster lf6ckcnts05 as gbn_onl_mix.union_order_onl_local_test
engine=Distributed(lf6ckcnts05, gbn_onl_mix, union_order_onl_local_test, cityHash64(order_id)) ;

数据初始化

初始数据包括2个订单,111和222,初始版本都是0,初始成交状态也都是0,日期是2023-05-28

INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,0, 0,'2023-05-28'),('222',2,0,0,'2023-05-28');

查询分区信息和数据如下:可以看到数据被写入到了1个分区的2个part中,分区都是20230528,part名都是20230528_0_0_0

知识点详见 https://clickhouse.com/docs/zh/engines/table-engines/mergetree-family/custom-partitioning-key 分区信息有重复是因为lf6ckcnts05集群的配置是有一个副本

验证同分片同分区数据合并

final合并

order_id=111有数据更新,mid变成了1,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,0, 1,'2023-05-28');

查询分区信息如下,可见增加了一个part,分区为20230528,part名为20230528_1_1_0

查询数据如下,可见order_id=111的订单,版本0和版本1的数据都是存在的

SELECT * FROM gbn_onl_mix.union_order_onl_all_test WHERE dt = '2023-05-28'

查询数据使用final结果如下,可见order_id=111的订单,只查询出最新版本1的数据

SELECT * FROM gbn_onl_mix.union_order_onl_all_test final WHERE dt = '2023-05-28'

再查询一下实际的数据如下,结果order_id=111的2个版本的数据还是都被查询出来了,可见final查询对实际物理数据的存储没有影响

SELECT * FROM gbn_onl_mix.union_order_onl_all_test WHERE dt = '2023-05-28'

小结:final可以合并同分片同分区的数据,并且final合并数据只是针对当次查询,不会对数据进行物理合并

引擎合并

order_id=111有数据更新,mid变成了2,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,0, 2,'2023-05-28');

查询分区和数据如下,分区20230528,增加一个part,名为20230528_2_2_0

order_id=111有数据更新,mid变成了3,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,0, 3,'2023-05-28');

分区20230528,增加名为20230528_2_2_0的part

此时数据还没有被引擎合并,先去吃个饭吧~

Later For a Moment ~~~

吃饭回来,查询分区,发现数据已经被引擎合并了,合并后的分区为20230528_0_3_1,但是同分区不同分片的数据没有被合并

小结:ReplaceingMergeTree引擎合并数据,合并的是同分片同分区的数据

验证同分片不同分区数据合并

final合并

order_id=111数据继续更新,mid变成了4,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,1, 4,'2023-05-29');

查询分区和数据如下,可见增加了一个part,分区是20230529,part名为20230529_0_0_0,order_id=111订单数据版本3和版本4同时存储,数据还未合并

使用final查询数据,结果如下,我们会发现,order_id=111的订单在2个分区2023-05-28和2023-05-29中的数据被合并了

SELECT * FROM gbn_onl_mix.union_order_onl_all_test final

小结:final可以跨分区进行合并

引擎合并

order_id=111数据继续更新,mid变成5、6、7,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,1, 5,'2023-05-29','111',1,1, 6,'2023-05-29','111',1,1, 7,'2023-05-29');

查询分区和数据如下,可见增加part 20230529_1_1_0,只插入了一条最新消息为7的数据,即插入数据时,数据就已经合并了

order_id=111数据继续更新,mid变成8、9,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,1, 8,'2023-05-29');
INSERT into gbn_onl_mix.union_order_onl_all_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('111',1,1, 9,'2023-05-29');

查询分区和数据如下,新增part 20230529_2_2_0和20230529_3_3_0

使用final同时查询2个分区数据,以及单独查询单个分区的数据,结果如下,可以看到卡不同的分区,最后合并的结果也不同,(这不是废话嘛~~)

SELECT * FROM gbn_onl_mix.union_order_onl_all_test final

SELECT * FROM gbn_onl_mix.union_order_onl_all_test final WHERE dt = '2023-05-29'

SELECT * FROM gbn_onl_mix.union_order_onl_all_test final WHERE dt = '2023-05-28'

Later For a Moment ~~~

数据合并完成,结果如下,part 20230529_0_0_0、20230529_1_1_0、20230529_2_2_0、20230529_3_3_0变成active=0,合并后part为20230529_0_3_1,但是分区20230508的part 20230528_0_3_1并没有被合并

查询分区数据,结果如下

SELECT * FROM gbn_onl_mix.union_order_onl_all_test WHERE dt = '2023-05-28'
SELECT * FROM gbn_onl_mix.union_order_onl_all_test WHERE dt = '2023-05-29'

小结:无论是从分区信息还是从数据结果来看,ReplaceingMergeTree引擎是不会合并同分片不同分区的数据的

验证不同分片数据合并

final合并

考虑order_id=222的订单数据,金额修改成22以做区分,在不同的分片上插入变更数据,本次插入改用向本地表中插入数据,可达到跨分片实例的效果,如下

order_id=222的订单,mid变成1,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_local_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('222',22,0,1,'2023-05-28');

查询数据,发现居然和版本0插入到同一个分片上了

SELECT * FROM gbn_onl_mix.union_order_onl_local_test WHERE dt = '2023-05-28'

再来一次,order_id=222的订单,mid变成2,即插入如下数据

INSERT into gbn_onl_mix.union_order_onl_local_test (order_id,after_prefr_amount_1,deal_flag,mid,update_time) values ('222',22,0,2,'2023-05-28');

查询数据,可见这次数据是插入到了不同的分片实例上

SELECT * FROM gbn_onl_mix.union_order_onl_local_test WHERE dt = '2023-05-28'

查看目前分区20230528的数据,如下

SELECT * FROM gbn_onl_mix.union_order_onl_all_test WHERE dt = '2023-05-28'

使用final查询结果如下,可见final查询不能合并跨分片的数据,(order_id=222,ver=1和ver=2是存储在不同分片上的数据)

SELECT * FROM gbn_onl_mix.union_order_onl_all_test final WHERE dt = '2023-05-28'

引擎合并

手动触发引擎合并,如下

optimize table union_order_onl_local_test on cluster lf6ckcnts05 FINAL;

查询数据结果,如下,结果同final查询

小结:无论是final查询还是引擎合并,不同分片上的数据都不会被合并,即使是同分区的也不会被合并

结论

啰哩啰嗦这么多,总结一下吧~~

1.对于不同分片上的数据来说,ReplaceingMergeTree引擎合并和查询时加final的合并,都不会合并不同分片上的数据

2.对于相同分片上的数据来说,ReplaceingMergeTree引擎合并,只合并同分区的数据,不同分区的数据不会合并;查询时加final的合并,会对不同分区的数据进行合并,合并是按照排序键进行合并的,如果想避免不同分区间的合并可以在排序键中增加分区字段

如有问题请指正,欢迎大家沟通交流,感谢~~

作者:京东零售 曹建奇

来源:京东云开发者社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/623526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人事项目开发记录2

项目构建 前端项目构建 Vue项目使用webpack来构建。首先确保本地已经安装了NodeJS,然后在CMD中执行如下命令,可以创建并启动一个名为vuehr的前端项目: 在执行“vue init webpack vuehr”命令时,会要求依次输入项目的基本信息&…

核心领域的数字基建梳理

数字基建:新基建的核心 数字基建是数字经济发展的重要底座,《“十四五”数字经济发展规划》的首要重要任务就是“优化升级数字基础设施”,并提出要建设高速泛在、天地一体、云网融合、智能敏捷、绿色低碳、安全可控的智能化综合性数字信息基…

如何有效避免项目需求蔓延?

如何有效避免项目需求蔓延?6种措施: 1、确定项目范围 (1)确定范围基线 在项目目标明确的基础上,所有干系人在完全了解项目需求后,建立需求范围基线(项目范围说明书、工作分解结构WBS、WBS字典&a…

关于矿井地面电力综合自动化系统的研究与产品选型

摘要:煤矿供电系统是煤矿生产的重要动力保障 , 一旦电力中断 , 生产将被迫停止 , 同时停电后容易发生瓦斯积聚爆炸、淹井等恶性事故,现有配电室采用不同厂商的保护装 置产品,没有形成有效的监控配电系统,不便于管理和实现无人值守…

CSS中scope和scoped区别

前言 在css的发展中,涌现了大量的新的特性和专有名词。 scope scope 是 CSS 中的一个伪类选择器,表示当前规则所在元素,它可以用于限定元素选择器的范围。在常规的 CSS 中,所有的选择器都是全局的,即它们适用于文档…

Mybatis的parameterType造成线程阻塞问题分析 | 京东云技术团队

一、前言 最近在新发布某个项目上线时,每次重启都会收到机器的 CPU 使用率告警,查看对应监控,持续时长达 5 分钟,对于服务重启有很大风险。而该项目有非常多 Consumer 消费,服务启动后会有大量线程去拉取消息处理逻辑…

【网络安全】学习路线和资料分享

一.自己对网络安全的理解 安全其实有很多个方向,从大的方面来说,也就是测试和开发。测试,细分下来,又有渗透(也就是所谓的web),逆向(也就是所谓的二进制,主要是代码审计方…

uniapp(四) 之还原网络请求以及接口封装

通过uniapp官网,不难发现简单的接口请求格式 uni.request({url: https://www.example.com/request, //仅为示例,并非真实接口地址。data: {text: uni.request},header: {custom-header: hello //自定义请求头信息},success: (res) > {console.log(re…

零基础想学黑客?推荐你了解一下Kali Linux!(建议收藏)

最近好多朋友问我:不会编程,英语也不好,dos命令也记不住,能学习黑客技术么? 我可以明确告诉大家,可以的! 相信每一个少年心中,曾经都有过一个黑客梦! 有人觉得黑客霸气…

5.1 合并数据

5.1 合并数据 5.1.1 堆叠合并数据1、横向堆叠 concat()2、纵向堆叠 concat()和append() 5.1.2 主键合并数据 merge()和join()5.1.3 重叠合并数据 combine_first() 5.1.1 堆叠合并数据 堆叠就是简单地把两个表拼在一起,也被称作轴向连接、绑定或连接。依照连接轴的方…

U盘 PE系统制作教程(附pe启动教程+获取方式)

目录 软件介绍: 软件安装步骤: 01 02 03 04 05 06 07 08 09 附:u盘pe系统启动教程 01 02 03 软件介绍: 微 PE 工具箱 v2.2 是一款免费纯净、无捆绑软件、体积小巧、功能齐全的PE 系统,微PE工具箱 v2.2 …

正大国际期货与国内期货的区别

一:定义 国际期货:是指交易所建立在中国大陆以外的期货交易,以美国,英国,新加坡等交易所内的产品为常见交易期货合约。有些期货合约品种会对国内期货价格变动产生影响,所以国内投资者可以参考国际期货行情…

科普:python怎么添加命令行参数

目录 1. 安装click2. 官方例子,快速入门3. 使用Group实现命令选择4. 使用click.option对指定命令的入参进行详细配置4.1 指定 type4.1.1 指定type是某种数据类型4.1.2 指定type限定可选值4.1.3 指定type限定参数的范围 4.2 指定命令行参数接收的值的个数4.3 输入密码…

导出下拉列表的两种小技巧【EasyPoi实战系列】- 第473篇

历史文章(文章累计460) 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 用…

【SVN】windows下的SVN客户端访问ubuntu下的SVN服务器

目录 第一部分 windows创建本地版本库、连接ubuntu的SVN服务器 步骤0: 步骤一:创建windows本地版本库 步骤二:checkout检测 步骤三:输入之前配置的用户名和密码 第二部分 windows上传文件至SVN服务器 步骤一:添加…

python基础学习2【numpy生成数组+random随机数生成+索引+拼接+切割【jupyter学习】】

接上一期jupyter结尾的一小部分: 这四个用好了,排版得好你的代码看起来就像一篇文章一样~ 导出功能: NumPy数值计算基础 NumPy数组对象ndarray(存储单一数据类型的多维数组): 属性 说明ndim返回int,表示数…

记录一次 bin/rails db:migrate 报错

theme: condensed-night-purple bin/rails db:migrate 最近在倒腾后端,用的是 Ruby on Rails,数据库是 Postgres,在执行数据库迁移命令(bin/rails db:migrate)时,模型更新出错了 :( bin/rails db:migrate:status 提示说&#xff0…

毕业生高频常用材料线上签,高校毕业季契约锁电子签章一站式助力

据人社部消息,2023年全国高校毕业生总规模将达1158万人!毕业季开启,全国各地高校普遍面临三方协议、成绩单、证书、证明等毕业生高频常用材料签署量激增的现状。学生、教职工、学校常常疲于应对机械化的材料盖章工作。 #毕业季高频常用材料清…

剑走偏锋,正经程序员都在用的无头浏览器到底有多神奇?

浏览器是再熟悉不过的东西了,几乎每个人用过,比如 Chrome、FireFox、Safari,尤其是我们程序员,可谓开发最强辅助,摸鱼最好的伴侣。 浏览器能干的事儿,无头浏览器都能干,而且很多时候比标准浏览…

主动发现系统稳定性缺陷:混沌工程 | 京东云技术团队

这是一篇较为详细的混沌工程调研报告,包含了背景,现状,京东混沌工程实践,希望帮助大家更好的了解到混沌工程技术,通过混沌工程实验,更好的为系统保驾护航。 一、概述 1.1 研究背景 Netflix公司最早系统化…