'safe' 重载插入导致 PK 违规

'safe' insert on heavy load lead to PK violation

我正在 Postgresql 9.4 上处理大分区 table(大约 0.5 TB 和 5 x10^9 行...)。这个 table 每天增长 8 x10^6 行,并面临大量 read/write 使用。

我需要填补部分插入可能发生的缺失分钟数的空白。我使用以下查询执行此操作:

INSERT INTO huge_partitioned_table(id, date_gmt, date_local)
SELECT 
    to_do.id AS id,
    seq.seq AT TIME ZONE to_do.tz_lib AT TIME ZONE 'UTC' AS date_gmt,
    seq.seq AS date_local
FROM to_do
    CROSS JOIN LATERAL
        generate_series(
            to_do.date_needed::timestamp,
            to_do.date_needed::timestamp + INTERVAL '1439 minutes',
            INTERVAL '1 minute'
        ) seq
WHERE NOT EXISTS(
    SELECT 1
    FROM huge_partitioned_table hpt
    WHERE 
        to_do.id = hpt.id
        AND date_gmt = hpt.date_gmt
)
;

但这是我第二次在 PK(id, date_gmt) 上遇到 PK 违规,因为在 运行[] 此查询的同时完成了缺少分钟的插入=26=].

在这种情况下有没有办法避免PK违规? (pg 9.5 的 on duplicate key do nothing 非常适合,但我们不能仅为此更新)

具有忽略每个 duplicate key 规则的解决方案也不是很好,因为使用时区意味着我们犯了一些真正的错误并且想在那时击中 PK FAIL...

好的,经过一些测试后,我将在 table 上使用 explicit table write lock :

LOCK TABLE huge_partitioned_table IN SHARE ROW EXCLUSIVE MODE;

SHARE ROW EXCLUSIVE

Conflicts with the ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, and ACCESS EXCLUSIVE lock modes. This mode protects a table against concurrent data changes, and is self-exclusive so that only one session can hold it at a time.

This lock mode is not automatically acquired by any PostgreSQL command.

此解决方案允许在锁定时读取并将写入放在等待列表中。