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

时间:2018-12-11 10:30:18

标签: postgresql duplicates

我一直使用这种查询删除重复项:

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分钟以上的时间才能删除重复项。我只是好奇哪个会是最高效的,以防万一我不得不从另一个巨大的表中删除重复项。首先它具有主键并不重要,您始终可以创建它。

1 个答案:

答案 0 :(得分:2)

demo:db<>fiddle

使用row_number() window function可以很容易地找到重复项:

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


修改:

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

demo:db<>fiddle