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

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

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

select *, count() AS cnt from my_table   GROUP BY *
HAVING cnt > 1 

显然,在 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 ); 

但是我收到以下错误:

异常:函数 isZeroOrNull 的参数必须是简单数值类型,可能为 Nullable:

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

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

但我想知道是否有人想出解决方案

最佳答案

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

如果您使用任何 MergeTree 系列表、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 中,同一个主键有多行是正常的,与大多数数据库引擎不同,插入一行时根本没有检查。这允许在表中非常快速地插入。

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

在 ClickHouse 中优化是什么意思? 此操作只是强制表合并它的数据。取决于您构建表格的方式。 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

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

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

SELECT * FROM radio_data FINAL WHERE id = 1

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

我最后要说的是 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/

https://stackoverflow.com/questions/71686567/

相关文章:

ethereum - 扁平化智能联系人是否会降低部署成本?

python - 等于运算符与元组 : 'a' , 'b' == ('a' , 'b' )

r - 如果列的值与另一列的值匹配,如何返回列的名称?

javascript - 根据条件在嵌套的 JS 数组中插入新的 JSON 对象

reactjs - 在函数或类中使用 `useDispatch` 可以吗?

c# - c#中的整数提升(以sbyte的范围为例)

google-forms - 您可以向 google forms api 提交 Restful 请求

aws-lambda - SQS 到 ECS (Fargate) 或 SQS 到 Lambda 到

python - 连接到与登录到 google colab 的不同的 google 驱动器

r - 创建一个虚拟变量,指示事件是否在过去 2 年发生