【问题标题】:How to delete lots of rows from PostgreSQL?如何从 PostgreSQL 中删除大量行?
【发布时间】:2021-01-13 16:48:42
【问题描述】:

我们在 AWS RDS 中托管了一个包含许多行 (100m) 的表。

  1. 如果表有不断的读、写和更新查询,我们如何才能有效地删除 50% 的行?
  2. 如何每天删除 1% 的数据?

表结构:

  • created_at
  • user_id
  • 其他数据

我们每天都在尝试删除,但随后自动清理开始并且队列深度增加了。

【问题讨论】:

  • Partition the table 并在需要时删除“最旧”分区。
  • @PanagiotisKanavos 我在问题中添加了表格结构。我需要一直查询用户的所有数据。我可以通过分区来实现这一点吗?另外,我现在有这张表,我无法为当前数据添加分区,但只能为新数据添加分区。
  • 如果您的系统无法处理自动清空,则说明它配置错误或配置不足。不管是什么触发了 autovacuum。
  • @jjanes 或者它有大量数据和大量流量。 100M 行是很多数据。如果您点击分区文档的链接,您会发现主要好处之一是它避免了清理。如果您分离分区而不是删除它,则几乎没有停机时间或阻塞,因为这本质上是元数据操作。
  • Postgres RDS 分区上的AWS announcement for Postgres 11 是一个关于分区及其一般好处的简短教程。 announcement for Postgres 12 解释了最新版本中如何改进分区修剪(在运行查询时避免不相关的分区)。

标签: postgresql amazon-web-services query-optimization amazon-rds


【解决方案1】:

我猜你想根据created_at 的值删除很多行。而且,我猜你的表有一个 id 列,它是唯一的主键。

您所做的是一次删除一个具有有限行数的批次,就像这样。

DELETE FROM yourtable
 WHERE id IN (
     SELECT id
       FROM yourtable
      WHERE created_at < '2020-11-01'
      LIMIT 1000
    )

(在我的示例中,我们将删除 2020 年 10 月结束之前任何时间创建的表中的所有行。)

这会删除一批 1000 行。您继续运行此查询,直到它不删除任何行。

之所以有效,是因为删除每批不需要很长时间,而且每批不会过多干扰您的生产工作量或真空维护。如果您在 created_at 列上有一个索引,这将特别有效。

在批次之间延迟几百毫秒也是明智的,因为您不太可能干扰您的生产工作流程。

一次一千次删除 25 亿行将需要 25 万个批次。但这没关系,这就是发明编程的原因。这种批处理方法在我工作过的地方非常有效,适用于最初设计不便于清理的表格。

一旦您删除了大量积压的旧行,那么每天跟上它就容易多了。

但是,如果您必须每天删除大量行,那么分区是可行的方法(如 cmets 中所述)。但我怀疑您需要停机时间来转换您的表格布局以使用它们。这不是一项小工作。

【讨论】:

  • 这取决于在created_at 上有一个索引以避免全表扫描。不过,有几种类似的技术可以处理这个问题——例如,将要删除的 PK 复制到临时表中并将其与 USING 一起使用。但这仍然很昂贵,尤其是在 RDS 上
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
  • 1970-01-01
  • 2022-07-18
  • 1970-01-01
相关资源
最近更新 更多