
--演示说明CREATE TABLE try(`username` String,`lables.name` Array(String),`lables.value` Array(String),`day` Date)ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/try', '{replica}')PARTITION BY toYYYYMMDD(day)ORDER BY username;insert into try values ('张三',['os_type','version','database_name','owner'],['linux','redhat_7.6','postgres','postgres'],toDate(now()));insert into try values ('李四',['os_type','version','database_name','owner'],['linux','redhat_7.7','flyingdb','flyingdb'],toDate(now()));insert into try values ('王五',['os_type','version','database_name','owner'],['linux','Mint_17.3','test','test'],today());insert into try values ('赵六',['os_type','version','database_name','owner'],['linux','Mint_17.4','data','data'],today());select * from try;┌─username─┬─lables.name───────────────────────────────────┬─lables.value────────────────────────┬────────day─┐│ 赵六 │ ['os_type','version','database_name','owner'] │ ['linux','Mint_17.4','data','data'] │ 2022-09-14 │└──────────┴───────────────────────────────────────────────┴─────────────────────────────────────┴────────────┘┌─username─┬─lables.name───────────────────────────────────┬─lables.value─────────────────────────────────┬────────day─┐│ 李四 │ ['os_type','version','database_name','owner'] │ ['linux','redhat_7.7','flyingdb','flyingdb'] │ 2022-09-14 │└──────────┴───────────────────────────────────────────────┴──────────────────────────────────────────────┴────────────┘┌─username─┬─lables.name───────────────────────────────────┬─lables.value────────────────────────┬────────day─┐│ 王五 │ ['os_type','version','database_name','owner'] │ ['linux','Mint_17.3','test','test'] │ 2022-09-14 │└──────────┴───────────────────────────────────────────────┴─────────────────────────────────────┴────────────┘┌─username─┬─lables.name───────────────────────────────────┬─lables.value─────────────────────────────────┬────────day─┐│ 张三 │ ['os_type','version','database_name','owner'] │ ['linux','redhat_7.6','postgres','postgres'] │ 2022-09-14 │└──────────┴───────────────────────────────────────────────┴──────────────────────────────────────────────┴────────────┘
2022.09.14 17:01:20.725741 [ 163 ] {67719eb7-2f61-41b7-8abb-bcf2e67d6ae8} <Error> executeQuery: Code: 57, e.displayText() = DB::Exception: Table icat.try already exists. (version 20.2.1.2120 (official build)) (from 127.0.0.1:36636) (in query: CREATE TABLE icat.try (`username` String, `lables.name` Array(String), `lables.value` Array(String), `day` Date) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/try', '{replica}') PARTITION BY toYYYYMMDD(day) ORDER BY username), Stack trace (when copying this message, always include the lines below):
可以发现,新插入的数据被clickhouse过滤掉了。那么,来看下ClickHouse的处理逻辑。
# 数据插入入口
InterpreterInsertQuery::execute
StorageReplicatedMergeTree::write // 构造数据流 ReplicatedMergeTreeBlockOutputStream
deduplicate = replicated_deduplication_window != 0 && insert_deduplicate // 是否去重,跟去重窗口和去重标志有关,默认窗口为100,标志为true
ReplicatedMergeTreeBlockOutputStream::write // 数据写入
block转为part
if deduplicate == true
hash // part的哈希值
block_id = partition_id + "_" + hash.words[0] + "_" + hash.words[1] // 构造block_id的字符串名称
end
commitPart // 向zk提交part
if block_id not empty
zkutil::makeCreateRequest // 如果zk上有相同的节点,则返回空block_number,否则创建该节点
end
if getActiveContainingPart
return // 该part已经被包含,则忽略它
# 复制表清理线程
ReplicatedMergeTreeCleanupThread::run
sleep_ms // 周期间隔时间,默认30s~40s随机
ReplicatedMergeTreeCleanupThread::iterate
clearOldBlocks // 清理过期block
replicated_deduplication_window_seconds
replicated_deduplication_window // 两者综合考虑,超过replicated_deduplication_window或者之间间隔超过replicated_deduplication_window_seconds
在默认情况下,如果一次插入的数据与一周内最近的100次左右(如果一次性插入的block可以分为多个part,则不到100次)成功插入的数据具有相同的block_id,则会被过滤掉。
针对这个问题官方有个参数:insert_deduplicate
对于 Replicated* 表,启用或禁用INSERT删除重复数据。
可能的值:
0 -禁用。
1 -启用(默认值)。
默认情况下,通过INSERT语句插入到复制表中的块会被重复数据删除(请参阅数据复制)
https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication
insert_deduplicate参数配置三种方式:
1.在 users.xml 中的用户配置文件中
2.SET 命令的会话
3.在SELECT语句的 SETTINGS 子句中。
通过设置可以让clickhouse不做此项检查,保证数据每次都能插入成功。有点需要注意的是,真正生效的窗口大小可能不止100,可能更多。因为清理线程的周期是30-40s,如果老的block_id没有及时清理掉,会导致实际的去重窗口值大于replicated_deduplication_window。
文章转载自ClickHouse周边,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




