POSTGRES - 删除使用不起作用

时间:2018-03-14 14:07:16

标签: sql postgresql

我正在尝试从表中删除重复的行,但似乎无效。

查询

DELETE FROM notifications N1
USING notifications N2
WHERE N1.id < N2.id
      AND N1.user_id = N2.user_id
      AND N1.notification_type = N2.notification_type;

有些SGDB表示与通知表无关。如果我在另一个应用程序中运行它需要1小时才能删除它们,但看起来它最终永远不会提交并返回到之前的状态。 该数据库是一个AWS RDS实例,该表包含超过4000万行,我预计最终不到1英里。

假设:

  • 有大量删除查询的Postgres锁。
  • 由于表的大小,它会丢弃连接并且永远不会提交。
  • 由于尺寸和表格的可用性,我必须为查询添加锁定。
  • 也许我必须复制表,进行删除,然后用新表替换旧表。

我不确定我必须遵循什么方法。

1 个答案:

答案 0 :(得分:1)

如果没有要测试的完整数据,很难给出明确的答案,但您可能会发现将查询分为两部分会有所帮助:确定要删除的行并删除它们。

CREATE TEMPORARY TABLE temp_notifications_to_delete (
    id Int
)

INSERT INTO temp_notifications_to_delete ( id )
SELECT N1.id
FROM notifications N1
JOIN notifications N2
ON N1.id < N2.id
      AND N1.user_id = N2.user_id
      AND N1.notification_type = N2.notification_type;

DELETE FROM notifications N
USING temp_notifications_to_delete D
WHERE N.id = D.id

以这种方式分隔可以防止在计算要删除的行时锁定表。它还可以更轻松地测试SELECT部分​​的其他改进,例如添加相关索引,以及使用替代形式的查询。

如a_horse_with_no_name所述,您可以使用EXISTS:

INSERT INTO temp_notifications_to_delete ( id )
SELECT N1.id
FROM notifications N1
WHERE EXISTS (
   SELECT * 
   FROM notifications N2
      WHERE N1.id < N2.id
      AND N1.user_id = N2.user_id
      AND N1.notification_type = N2.notification_type
);

如果您确定为每个user_id,notification_type对一次删除一个副本,则可以使用GROUP BY

INSERT INTO temp_notifications_to_delete ( id )
SELECT MIN(id)
FROM notifications
GROUP BY user_id, notification_type
HAVING COUNT(*) > 1;

Panagiotis Kanavos使用窗口函数的建议听起来也很有希望,虽然我不知道他们想到的确切查询。