clickhouse的ReplacingMergeTree引擎实战

学习ReplacingMergeTree引擎,首先你得了解clickhouse的MergeTree引擎,因为MergeTree引擎是MergeTree引擎的一个扩展版引擎,他拥有和MergeTree一样的功能,同时新增了一个删除相同主键数据的功能。
我们知道,clickhouse的MergeTree引擎,是clickhouse众多引擎中,号称性能最好的一个引擎,但他只能按照分区删除数据,所以有些场景很难满足,或者说比较麻烦,不优雅,举个实际的例子:
比如有个系统,他的数据不是实时的,比如今天的数据,明天看会比今天多,后天看会比明天多,但你需要在你的系统中定时同步他的数据到clickhouse,
这种情况用MergeTree可以勉强实现,那就是把每天相同主键的数据都保存一条,查询的时候,只取最新的一条。但这个需要写sql解决,而且一旦查询复杂,设计到数据合并等,sql就会变的很复杂,查询效率也会降低,而且每天的数据都会重复保存,数据重复太多,量太大。
所以针对这种情况,我们可以考虑用clickhouse的ReplacingMergeTree引擎,这个引擎自动帮你筛选出来最新的一条数据,并删掉之前重复的数据。类似于mongo的updateOne,先增后删。

建表:

我们新建一个表replacing_test,用ReplacingMergeTree引擎,date作为分区键,id和name作为联合主键,point可以理解为版本号。
value就是你实际业务要的值,我们用数字类型举例。

create table replacing_test (date Date, id UInt8, name String, value UInt16, point DateTime) 
ENGINE= ReplacingMergeTree(date, (id, name), 8192,point);

这个表,相同id-name的数据,最终只会留下一条,具体留下哪一条,是由不同的point决定的。

插入测试数据

看下面的代码,我们循环插入9*9=81条数据,联合主键只有id在变,name暂时只是字符串b

    public static void main(String[] args) throws SQLException {
        for (int i = 1;i<10;i++){
            for (int j = 1;j<10;j++) {
                int v = j+i+100;
                String sql = "insert into replacing_test values ('2019-12-16', "+j+", 'b',"+v+", " + System.currentTimeMillis()/1000 + ");";
                System.out.println(sql+"_i="+i+"_j="+j);
                executeSql(sql);
            }
        }
    }
    private static void executeSql(String sql) throws SQLException {
        ClickHouseProperties properties = new ClickHouseProperties();
        ClickHouseDataSource dataSource = new ClickHouseDataSource("jdbc:clickhouse://clickhouse的ip:8123/default", properties);
        ClickHouseConnection connection = dataSource.getConnection();
        ClickHouseStatement statement = connection.createStatement();
        boolean execute = statement.execute(sql);
    }    

结果

我们看到,最终数据库只有11条数据,说明大部分相同主键的数据都被删除了,但还是有两条数据是重复的,分别是id为8和9的。
这个就是官网所说的,他的这个删除重复数据,并不是一插入就删的,而且在Merge的时候才会删,原话是:
数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,因此你无法预先作出计划。
所以说,这个引擎是一个类似于最终一致性的机制,估计是为了性能,把删除的逻辑做成了异步。
在这里插入图片描述

解决重复:

其实这种也是可以解决的,如果不是很在意性能的话,可以手动执行一个sql去触发他的Merge就好了,sql如下:

optimize table replacing_test;

执行完再看结果,这个就对了。每个id-name为主键的数据只有最后一条。
在这里插入图片描述

发布了203 篇原创文章 · 获赞 186 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/java_zhangshuai/article/details/103567816