如何删除 SQL 中的重复行(Clickhouse)?
How to delete duplicate rows in SQL ( Clickhouse)?
所以我使用 clickhouse 创建了一个 table,但它有重复项。
以下查询为我提供了 table
中的重复项
select *, count() AS cnt from my_table GROUP BY *
HAVING cnt > 1
在 clickhouse 中显然你需要通过改变 table 来做到这一点: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 );
但我收到以下错误:
Exception: The argument of function isZeroOrNull must have simple numeric type, possibly Nullable:
有人在使用 clickhouse 之前遇到过这个问题吗?
在此视频中,他们明确提到 clickhouse 不是此类操作的最佳选择:https://www.youtube.com/watch?v=FsVrFbcyb84&t=1865s
但我想知道是否有人想出解决方案
首先,答案取决于您使用的 table 引擎。
ClickHouse 上最常见的是 MergeTree 家族。
如果您使用任何 MergeTree 系列 tables、MaterializedView 或 Buffer 引擎,您可以使用 OPTIMIZE 查询:
OPTIMIZE TABLE table DEDUPLICATE BY name -- you can put any expression here
https://clickhouse.com/docs/en/sql-reference/statements/optimize/
在将上述查询视为答案之前,您必须了解为什么以及为什么这样做不是正确的方法。
在Clickhouse中,同一个主键有多行是正常的,un-like大多数数据库引擎,插入一行时根本没有检查。这允许在 tables 中非常快速地插入。
名称“MergeTree”并非无用,事实上,如果 Clickhouse 认为有必要 or/and 如果有时间,table 会自动“优化”。
ClickHouse 中的优化是什么意思?
此操作只是强制 table 合并它的数据。取决于您构建 table 的方式。 ClickHouse 将根据您的设置查找重复的行并应用您要求的功能。
两个例子 :
- ReplacingMergeTree,这里可选参数设置为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'
- 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
您选择的 table,您选择的功能,必须非常接近您最终想要对数据执行的操作。您是否替换了更新时的所有行?那么 ReplacingMergeTree 是最好的,你是否部分更新一行并在其上应用一些功能?那么 AggregatingMergeTree 是最好的...等等
这就是说,在某些情况下,您需要让数据“新鲜”而不是重复。
当你的table配置好了,一个简单的OPTIMIZE TABLE ...
就够了。 但是 这很昂贵,如果您不想破坏服务器性能,就必须聪明地完成。
您也可以即时合并数据,但同样,这很昂贵并且必须对一小部分数据进行合并,否则最好进行优化。
SELECT * FROM radio_data FINAL WHERE id = 1
例如,我们对“过去”的所有 un-merged 分区进行优化,例如前一天。目标是做尽可能少的OPTOIMIZE操作。
我最后要说的是 ALTER TABLE
语句的用法。它允许删除和更新。但它们是突变 (https://clickhouse.com/docs/en/sql-reference/statements/alter/#mutations) 并且不是同步的!如果您需要新数据,请不要依赖它们。
您可以在此处找到更多 material:
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/
所以我使用 clickhouse 创建了一个 table,但它有重复项。
以下查询为我提供了 table
中的重复项select *, count() AS cnt from my_table GROUP BY *
HAVING cnt > 1
在 clickhouse 中显然你需要通过改变 table 来做到这一点: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 );
但我收到以下错误:
Exception: The argument of function isZeroOrNull must have simple numeric type, possibly Nullable:
有人在使用 clickhouse 之前遇到过这个问题吗?
在此视频中,他们明确提到 clickhouse 不是此类操作的最佳选择:https://www.youtube.com/watch?v=FsVrFbcyb84&t=1865s
但我想知道是否有人想出解决方案
首先,答案取决于您使用的 table 引擎。 ClickHouse 上最常见的是 MergeTree 家族。
如果您使用任何 MergeTree 系列 tables、MaterializedView 或 Buffer 引擎,您可以使用 OPTIMIZE 查询:
OPTIMIZE TABLE table DEDUPLICATE BY name -- you can put any expression here
https://clickhouse.com/docs/en/sql-reference/statements/optimize/
在将上述查询视为答案之前,您必须了解为什么以及为什么这样做不是正确的方法。
在Clickhouse中,同一个主键有多行是正常的,un-like大多数数据库引擎,插入一行时根本没有检查。这允许在 tables 中非常快速地插入。
名称“MergeTree”并非无用,事实上,如果 Clickhouse 认为有必要 or/and 如果有时间,table 会自动“优化”。
ClickHouse 中的优化是什么意思? 此操作只是强制 table 合并它的数据。取决于您构建 table 的方式。 ClickHouse 将根据您的设置查找重复的行并应用您要求的功能。
两个例子 :
- ReplacingMergeTree,这里可选参数设置为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'
- 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
您选择的 table,您选择的功能,必须非常接近您最终想要对数据执行的操作。您是否替换了更新时的所有行?那么 ReplacingMergeTree 是最好的,你是否部分更新一行并在其上应用一些功能?那么 AggregatingMergeTree 是最好的...等等
这就是说,在某些情况下,您需要让数据“新鲜”而不是重复。
当你的table配置好了,一个简单的OPTIMIZE TABLE ...
就够了。 但是 这很昂贵,如果您不想破坏服务器性能,就必须聪明地完成。
您也可以即时合并数据,但同样,这很昂贵并且必须对一小部分数据进行合并,否则最好进行优化。
SELECT * FROM radio_data FINAL WHERE id = 1
例如,我们对“过去”的所有 un-merged 分区进行优化,例如前一天。目标是做尽可能少的OPTOIMIZE操作。
我最后要说的是 ALTER TABLE
语句的用法。它允许删除和更新。但它们是突变 (https://clickhouse.com/docs/en/sql-reference/statements/alter/#mutations) 并且不是同步的!如果您需要新数据,请不要依赖它们。
您可以在此处找到更多 material:
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/