防止复制 csv postgresql 上重复数据的最佳方法

Best way to prevent duplicate data on copy csv postgresql

这更像是一个概念性问题,因为我正在计划如何最好地实现我们的目标。

我有一个包含 5 列的 postgresql/postgis table。我将每 10 分钟左右通过复制命令将 inserting/appending 数据从 csv 文件导入数据库。可能会有一些重复的数据行,所以我想将数据从 csv 文件复制到 postgresql table,但要防止任何重复的条目从 csv 文件进入 table。共有三列,如果它们都相等,则意味着该条目是重复的。它们是 "latitude"、"longitude" 和 "time"。我应该从所有三列中制作一个复合键吗?如果我这样做,它会在尝试将 csv 文件复制到数据库时抛出错误吗?我将自动复制 csv 文件,所以我希望它继续复制文件的其余部分,而不是重复文件,而不是复制重复文件。有办法吗?

此外,我当然希望它以最有效的方式查找重复项。我不需要通过行上的时间戳查看整个 table(这将非常大)以查找重复项......只需过去 20 分钟左右。我已经用时间列索引了数据库。

感谢您的帮助!

我想我会采取以下方法。

首先,在您关心的三个列上创建索引:

create unique index idx_bigtable_col1_col2_col3 on bigtable(col1, col2, col3);

然后,使用 copy 将数据加载到分段 table 中。最后,你可以这样做:

insert into bigtable(col1, . . . )
    select col1, . . .
    from stagingtable st
    where (col1, col2, col3) not in (select col1, col2, col3 from bigtable);

假设没有其他数据修改正在进行,这应该可以完成您想要的。从性能的角度来看,使用索引检查重复项应该没问题。

另一种方法是模仿 MySQL 的 "on duplicate key update" 来忽略此类记录。 Bill Karwin 建议在对此 question. The documentation for rules is here 的回答中实施规则。类似的事情也可以用触发器完成。

更新

is correct but can simplified a bit by Postgres 9.5 new ”UPSERT“ feature (a.k.a. MERGE). That new feature is implemented in Postgres as INSERT ON CONFLICT 语法。

我们可以让 ON CONFLICT 子句检测违规,而不是显式检查是否违反唯一索引。然后我们 DO NOTHING,这意味着我们放弃 INSERT 的努力,而不必费心去尝试 UPDATE。所以如果我们不能插入,我们就继续下一行。

我们得到了与 Linoff 代码相同的结果,但丢失了 WHERE 子句。

INSERT INTO bigtable(col1, … )
    SELECT col1, …
    FROM stagingtable st
ON CONFLICT idx_bigtable_col1_col2_col
DO NOTHING
;

贴出的方法很好,但是有一点语法错误

the documentation的基础上,我修改为如下,有效:

INSERT INTO bigtable(col1, … )
    SELECT col1, …
    FROM stagingtable st
ON CONFLICT (col1)
DO NOTHING
;