【问题标题】:How to avoid data duplicates in ClickHouse如何避免 ClickHouse 中的数据重复
【发布时间】:2019-11-13 23:45:14
【问题描述】:

我已经阅读了this,但我仍有疑问。我只有一个具有 16 GB RAM、4 个内核和 100 GB 磁盘的 VM,只有 ClickHouse 和一个轻量级 Web api 在上面工作。

我将泄露的凭据存储在数据库中:

CREATE TABLE credential (
    user String,
    domain String,
    password String,
    first_seen Date,
    leaks Array(UInt64)
) ENGINE ReplacingMergeTree
PARTITION BY first_seen
ORDER BY user, domain, password, first_seen

某些凭据出现多次(在一个文件内或多个文件之间)会发生这种情况。

我的长期目标是(曾经)如下: - 当插入一个已经在数据库中的凭证时,我想保留较小的first_seen并将新的泄漏ID添加到字段leaks

我尝试了 ReplacingMergeTree 引擎,插入两次相同的数据 ($ cat "data.csv" | clickhouse-client --query 'INSERT INTO credential FORMAT CSV'),然后执行 OPTIMIZE TABLE credential 以强制替换引擎执行其异步工作,根据 the documentation。什么都没有发生,数据在数据库中出现了两次。

所以我想知道:
- 我错过了什么 ReplacingMergeTree 引擎? - OPTIMIZE 是如何工作的,为什么它没有达到我的预期?
- 有没有真正的解决方案可以避免在 ClickHouse 的单个实例上复制数据?

我已经尝试过手动操作。我的问题是我的数据库中有 45 亿条记录,并且使用以下查询识别 100k 条目样本中的重复项几乎需要 5 分钟:SELECT DISTINCT user, domain, password, count() as c FROM credential WHERE has(leaks, 0) GROUP BY user, domain, password HAVING c > 1 这个查询显然不适用于 4.5b 条目,因为我没有足够的内存。

任何想法都会尝试。

【问题讨论】:

    标签: clickhouse


    【解决方案1】:

    这里有多处出错:

    • 您的分区非常精细...您应该按一个月的数据进行分区,无论如何。现在 clickhous 必须扫描大量文件。
    • 您没有为表引擎提供版本。这里的问题是,clickhouse 无法找出应该替换另一行的那一行。 我建议您使用 ReplacingMergeTree 的“版本”参数,因为它允许您提供增量版本作为数字,或者如果这对您更有效,则使用当前日期时间(最后一个日期时间总是获胜)

    • 您永远不应设计解决方案来要求调用 OPTIMIZE 以使您的数据在结果集中保持一致,它不是为此而设计的。

    Clickhouse 始终允许您编写一个查询,您可以在其中提供(最终)一致性,而无需事先使用OPTIMIZE

    避免 OPTIMIZE 的原因,除了在您的数据库上非常缓慢和沉重之外,您最终可能会陷入竞争条件,其中数据库的其他客户端(或复制 clickhouse 节点)可能会使您的数据在 OPTIMIZE 完成和 SELECT 之间无效完成。

    底线,作为解决方案: 所以你应该在这里做的是,添加一个版本列。然后在插入行时,将当前时间戳作为版本插入。 然后为每一行只选择结果中版本最高的那一行,这样您就不会依赖 OPTIMIZE 来获得除 garbage collection 之外的任何内容。

    【讨论】:

    • 如果我将分区键定义为几个月,它会产生一个巨大的结果(我有一个将近 1 TB 的凭据集合要插入),而其他每个分区都将是荒谬的。我选择按first_seen 进行分区,因为我认为即使我有更多的分区,它们也会更加平衡。由于我的响应时间很棒,我没有考虑改变它。我没有提供版本,因为在这种情况下,两个条目实际上是相同的。我没有很多磁盘空间,所以我试图尽可能减少信息量。
    • 根据文档,“合并时,ReplacingMergeTree 从具有相同主键的所有行中只留下一个: - 最后在选择中,如果未设置。”所以我想 ver 不是强制性的,它应该删除一些东西。最后,我没有将其设计为与 OPTIMIZE 一起使用,我只是在阅读文档时发现它 lol
    • 我只是试图解释我的选择,以帮助您了解我的想法并帮助您纠正我的错误!
    • 好了,够清楚了;你应该瞄准 10 到 100 的分区。如果您最终得到超过数千个,那将是低效的。有关于那个的文档。您应该等待 clickhouse 完成重复数据删除,但是对于 1TB 的数据(数十亿行?),这将需要一段时间。只需给它时间合并所有行。至少使用版本列,您将只能获取每行的最后一个版本(通过选择 HAVING version=max(version),您可以从连接中获取最大值)
    • 另外,理想情况下,您必须在 1 个查询的结果集中包含尽可能少的分区,并始终在 WHERE 条件中将分区键作为过滤器。这将防止完整的分区扫描,并使查询更快。
    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 2019-03-09
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多