ClickHouse借助ReplacingMergeTree实现重复数据删除

MergeTree引擎的表,由于重复入库导致了表中数据重复,需要将重复的数据删除,只保留一条记录。

在使用Hive的时候,遇到这种情况通常是使用row_number取第一条插入到临时表中,然后将原表数据删除,再将临时表数据写回来就可以实现去重。

但是CK(clickhouse)中不支持row_number函数,需要使用别的方法去重。

翻阅文档后,发现可以使用ReplacingMergeTree + Optimize来手动实现去重。需要注意的是这种方式不太适合于超大数据量数据的去重

先介绍下ReplacingMergeTree和Optimize,具体的去重案例在最后。

ReplacingMergeTree简介

ReplacingMergeTree也是MergeTree派系的,与MergeTree的不用点在于它会删除排序键值相同的重复项。

数据的去重只会在数据分区合并期间进行,合并会在后台一个不确定的时间进行。

可以调用 OPTIMIZE 语句手动触发的合并,要注意的是OPTIMIZE语句会引发对数据的大量读写。

因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

建表语法

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = ReplacingMergeTree([ver])
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

ReplacingMergeTree的参数:

  • ver — 版本列。类型为 UInt*, DateDateTime。可选参数。

    在数据合并的时候,ReplacingMergeTree 从所有具有相同排序键的行中选择一行留下:

    • 如果 ver 列未指定,保留最后一条。
    • 如果 ver 列已指定,保留 ver 值最大的版本。

从上面我们可以看出,将要去重数据中的唯一标识字段设置为排序字段,然后可选的指定版本列,ReplacingMergeTree就可以完成数据的去重了。

另外要注意的是,要去重的重复数据必须位于同一个分区中。

Optimize子句

Optimize用于手动触发MergeTree引擎的分区合并。

语法:

OPTIMIZE TABLE [db.]name [ON CLUSTER cluster] [PARTITION partition | PARTITION ID 'partition_id'] [FINAL] [DEDUPLICATE]

Optimize有以下几点要注意的:

  • 默认是异步执行的。

  • 如果 OPTIMIZE出于任何原因不执行合并,它会报错。 要启用通知,需要使用 optimize_throw_if_noop 设置。

  • 可以指定分区,来触发对应分区的合并。如果指定了PARTITION,仅合并指定的分区。

  • 如果您指定 FINAL,即使所有数据已经在一个part中,也会执行优化。如果不加final,数据已经在同一个分区中,Optimize就不生效。

  • 如果您指定 DEDUPLICATE,则将对完全相同的行进行重复数据删除(所有列进行比较),这仅适用于MergeTree引擎。

重复数据删除案例

数据表表结构

CREATE TABLE raw_log
(
    `event_time` DateTime COMMENT '时间',
    `uuid` String COMMENT '唯一标识',
    `message` String COMMENT '日志内容'
)
ENGINE = MergeTree()
PARTITION BY toStartOfHour(event_time)
ORDER BY uuid;

需要对uuid重复的数据进行去重删除

创建表结构相同的ReplacingMergeTree表

CREATE TABLE replace_log
(
    `event_time` DateTime COMMENT '时间',
    `uuid` String COMMENT '唯一标识',
    `message` String COMMENT '日志内容'
)
ENGINE = ReplacingMergeTree()
PARTITION BY toStartOfHour(event_time)
ORDER BY uuid;

去重操作

-- 将数据导入到ReplacingMergeTree表
insert into replace_log select * from raw_log;

-- 触发合并,进行去重
OPTIMIZE TABLE replace_log final;

-- 删除原表的数据
alter table raw_log delete where 1=1;

-- 将ReplacingMergeTree表合并后的数据写回原表
insert into raw_log select * from replace_log;

以上就实现了重复数据只保留一条的效果。

参考

optimize文档:https://clickhouse.tech/docs/zh/sql-reference/statements/misc/#misc_operations-optimize

ReplacingMergeTree文档:https://clickhouse.tech/docs/zh/engines/table-engines/mergetree-family/replacingmergetree/

你可能感兴趣的:(ClickHouse,clickhouse数据去重)