如何删除SQL(Clickhouse)中的重复行?

Dud*_*ude 5 sql database delete-row clickhouse

所以我使用 clickhouse 创建了一个表,但其中有重复项。

以下查询给出了表中的重复项

select *, count() AS cnt from my_table   GROUP BY *
HAVING cnt > 1 
Run Code Online (Sandbox Code Playgroud)

在 clickhouse 中,显然你需要通过更改表来做到这一点:https ://clickhouse.com/docs/en/sql-reference/statements/alter/delete/

所以,我尝试了以下方法:

ALTER TABLE my_table DELETE WHERE (select *, count() AS cnt from my_table  GROUP BY *
HAVING cnt > 1 ); 
Run Code Online (Sandbox Code Playgroud)

但我收到以下错误:

Exception: The argument of function isZeroOrNull must have simple numeric type, possibly Nullable:

有人在使用 clickhouse 之前遇到过这个问题吗?

在此视频中,他们明确提到 clickhouse 并不是此类操作的最佳选择:https://www.youtube.com/watch?v= FsVrFbcyb84&t=1865s

但我想知道是否有人找到了解决方案

Erw*_*iel 13

首先,答案取决于您使用的表引擎。ClickHouse 上最常见的是 MergeTree 系列。

如果您使用任何 MergeTree 系列表、MaterializedView 或 Buffer 引擎,则可以使用 OPTIMIZE 查询:

OPTIMIZE TABLE table DEDUPLICATE BY name -- you can put any expression here
Run Code Online (Sandbox Code Playgroud)

https://clickhouse.com/docs/en/sql-reference/statements/optimize/

在将上述查询视为答案之前,您必须了解为什么以及为什么这不是正确的方法。

在 Clickhouse 中,同一个主键有多行是很正常的,与大多数数据库引擎不同,插入行时根本不进行检查。这允许非常快速地插入表中。

“MergeTree”这个名字并不是无缘无故的,事实上,当 Clickhouse 认为有必要或/和有时间时,表会自动“优化”。

ClickHouse 中的 OPTIMIZE 是什么意思? 此操作只是强制表合并其数据。取决于您如何构建表。ClickHouse 将根据您的设置查找重复的行并应用您要求的功能。

两个例子

  • 替换MergeTree,这里可选参数设置为datetime,并提示ClickHouse哪一行是最新的。然后,对于重复项,最新的保留在其他项之上。
create table radios
(
    id                UInt64,
    datetime          DateTime,
    name              Nullable(String) default NULL
)
    engine = ReplicatedReplacingMergeTree(datetime)
    ORDER BY id -- it's the primary key
-- example
INSERT INTO radios VALUES (1, now(), 'Some name'), (1, now(), 'New name')
-- after merging:
id,              datetime,       name
 1, '2022-04-04 15:15:00', 'New name'
Run Code Online (Sandbox Code Playgroud)
  • AggregatingMergeTree,这里应用一个函数来计算最后一行。这是您会发现最接近 UPDATE 语句的内容。
create table radio_data
(
    datetime                        DateTime,
    id                              UInt64,
    power                           SimpleAggregateFunction(anyLast, Nullable(Float64)) default NULL,
    access                          SimpleAggregateFunction(sum, Nullable(UInt64))    default NULL
)
    engine = ReplicatedAggregatingMergeTree()
        ORDER BY (id, datetime) -- the primary key

-- example
INSERT INTO radio_data VALUES ('2022-04-04 15:15:00', 1, NULL, 1), ('2022-04-04 15:15:00', 1, 12, 2)
-- will give after merging :
datetime           , id, power, access
2022-04-04 15:15:00,  1,    12,      3
Run Code Online (Sandbox Code Playgroud)

您选择的表、您选择的函数必须非常接近您最终想要对数据执行的操作。您是否替换了更新时的所有行?那么 ReplacingMergeTree 是最好的,您是否部分更新一行并在其上应用一些功能?那么 AggregatingMergeTree 是最好的......等等。

也就是说,在某些情况下,您需要使数据“新鲜”且不重复。当你的桌子配置良好时,一个简单的OPTIMIZE TABLE ...就足够了。但这是昂贵的,如果您不想破坏服务器性能,则必须明智地完成。您还可以动态合并数据,但同样,这很昂贵,并且必须在一小部分数据上完成,否则最好进行优化。

SELECT * FROM radio_data FINAL WHERE id = 1
Run Code Online (Sandbox Code Playgroud)

例如,我们对“过去”(例如前一天)的所有未合并分区进行优化。目标是尽可能少地进行 OPTIOMIZE 操作。

我的最后一句话将是关于语句的用法ALTER TABLE。它允许删除和更新。但它们是突变(https://clickhouse.com/docs/en/sql-reference/statements/alter/#mutations)并且不同步!如果您需要新数据,请不要依赖它们。

您可以在这里找到更多材料:

https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree/#mergetree https://clickhouse.com/docs/en/sql-reference/statements/optimize/ https:// clickhouse.com/docs/en/sql-reference/statements/alter/