删除重复项的最有效方法 - Postgres

问题描述 投票:0回答:2

我总是用这种查询删除重复项:

delete from test a
using test b 
where a.ctid < b.ctid
and a.col1=b.col1
and a.col2=b.col2
and a.col3=b.col3

另外,我看到这个查询被使用:

DELETE FROM test WHERE test.ctid NOT IN 
(SELECT ctid FROM (
    SELECT DISTINCT ON (col1, col2) *
  FROM test));

甚至这个(重复直到用完重复项):

delete from test ju where ju.ctid in 
(select ctid from (
select  distinct on (col1, col2) * from test ou
where (select count(*) from test inr
where inr.col1= ou.col1 and inr.col2=ou.col2) > 1

现在我遇到了一个包含 500 万行的表,该表在将在 where 子句中匹配的列中具有索引。现在我想知道:

在所有这些显然具有相同功能的方法中,哪种方法最有效?为什么? 我刚刚运行第二个,删除重复项需要超过 45 分钟。我只是好奇哪一个是最有效的,以防我必须从另一个大表中删除重复项。它一开始是否有主键并不重要,您始终可以创建或不创建它。

postgresql duplicates
2个回答
16
投票

演示:db<>fiddle

使用

row_number()
窗口函数:

可以轻松找到重复项
SELECT ctid 
FROM(
    SELECT 
        *, 
        ctid,
        row_number() OVER (PARTITION BY col1, col2, col3 ORDER BY ctid) 
    FROM test
)s
WHERE row_number >= 2

此命令对绑定行进行分组并添加行计数器。因此,带有

row_number > 1
的每一行都是重复的,可以删除:

DELETE 
FROM test
WHERE ctid IN 
(
    SELECT ctid 
    FROM(
        SELECT 
            *, 
            ctid,
            row_number() OVER (PARTITION BY col1, col2, col3 ORDER BY ctid) 
        FROM test
    )s
    WHERE row_number >= 2
)

我不知道这个解决方案是否比您的尝试更快,但您可以尝试一下。

此外 - 正如 @a_horse_with_no_name 已经说过的 - 我建议使用自己的标识符而不是

ctid
来解决性能问题。


编辑:

对于我的测试数据,您的第一个版本似乎比我的解决方案快一点。你的第二个版本似乎更慢,你的第三个版本对我不起作用(修复编译错误后,它没有显示结果)。

演示:db<>fiddle


0
投票

最好的解决方案!!!我花了更多的时间来解决重复的问题。感谢您的解决方案

© www.soinside.com 2019 - 2024. All rights reserved.