【问题标题】:Automated way of deleting millions of rows from Postgres tables从 Postgres 表中删除数百万行的自动化方法
【发布时间】:2022-02-13 12:58:38
【问题描述】:

Postgres 版本:PostgreSQL 10.9 (Ubuntu 10.9-1.pgdg16.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609, 64-bit

在我提出问题之前,我想解释一下我为什么要研究这个问题。我们有一个历史记录表,其中包含超过 500 万行并且每小时都在增长。

随着表长度的增长,选择查询变得越来越慢,即使我们有一个合适的索引。所以我们最理想的选择是删除未使用的旧记录。

方法#1

我们尝试使用简单的delete from table_name where created_date > certain_date where is_active = false从表中删除记录

  • 这花了很长时间。

方法 #2

创建一个脚本,该脚本将使用基于光标的方法删除行。

  • 这也需要很长时间。

方法#3

  • 创建了一个新的未记录表。

  • 在 new_table 上创建索引。

  • 将旧表中的内容复制到新表中

  • 然后记录设置表。

  • 将主表重命名为备份。

  • 这种方法存在问题,需要一些停机时间。

在实时制作实例上,这会导致数据丢失/导致失败

方法#4

在进一步调查中,删除未使用行的高效方法是,如果我们创建一个分区为 https://www.postgresql.org/docs/10/ddl-partitioning.html 的表 - 我们可以立即删除整个分区。

上述方法的问题是

  1. 如何在现有表上创建分区?
  2. 这需要停机吗?
  3. 如何配置 Postgres 自动创建分区,我们真的不能每天手动创建分区吗?

也欢迎任何其他方法,问题是我真的希望这是自动化而不是手动,因为我会将其扩展到多个表。

请告诉我你的想法,这将非常有帮助

【问题讨论】:

  • @a_horse_with_no_name 我们正在使用PostgreSQL 10.9 (Ubuntu 10.9-1.pgdg16.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609, 64-bit
  • @a_horse_with_no_name 抱歉将链接更改为 10 链接。但是问题还是一样的。
  • 如果按日期进行分区,您必须定义适合您的用例的时间粒度级别,无论是一年、季度还是一个月。您的分区功能/索引会将您的数据推送到正确的分区中。然后,您可以通过脚本或手动将最旧的分区切换为新分区。我会说 500 万条记录并不是一个巨大的数字。也许您缺少正在使用的查询之一的覆盖索引。

标签: sql postgresql automation


【解决方案1】:

我会选择方法 4,表分区。

  1. 创建分区
  2. 新数据直接进入正确的分区
  3. 将旧数据(手动/脚本)移动到正确的分区
  4. 设置一个 cron 作业来为接下来的 X 天创建分区(如果它们尚不存在)

无需停机

【讨论】:

  • 感谢弗兰克·海肯斯的建议。所以只是为了确认我可以在不停机的情况下创建表分区,所以我可以每个月创建一次分区,并让 cron worker 删除完全未使用的旧分区。对吗?
  • 是的,我们就是这样做的。未来几个月我们总是至少有 3 个分区,以防 cron 作业失败而我们未能发现这个问题。现在是 1 月,这意味着我们已经有 2021 年 3 月和 2021 年 4 月的 2 月和 4 月可用。 1 月 28 日,下一个分区将被创建,2021 年 5 月。2020 年 9 月 28 日将被删除,我们不再需要那个分区了。
  • 再次感谢您。那么这个 cron 是如何工作的呢?这是 Postgres 的一部分,还是您使用微服务运行单独的脚本?您是否在某处维护已经创建的分区?或者使用存在查询会解决这个问题?更好奇。 :)
  • 这是一个使用 psql-client 执行 SQL 脚本的单个 Linux cron 作业。该 SQL 脚本做了很多事情并且工作正常。它还会生成输出,因此我们可以在早上检查异常情况。
  • 这是 5 年前的问题,我认为即使在那时你也不需要停机。可能会锁定半毫秒,但我不认为那是“停机时间”。
【解决方案2】:

我们尝试使用简单的delete from table_name where created_date > certain_date where is_active = false 从表中删除记录,这花了很长时间。

你的意思是<,而不是>?那么,如果需要很长时间呢?你需要多快?有没有引起问题?您打算一次删除多少数据?

500 万行非常小。我可能一开始不会在这么大的东西上使用分区。

如果您还没有分区数据,则没有简单且透明的方法可以迁移到分区数据。最简单的方法是在填充新表时有一点停机时间。

如果您确实要分区,您的分区方案必须包括 is_active,而不仅仅是 created_date。白天看起来太棒了,你可以按月做,并预先创造几年的价值。

【讨论】:

    【解决方案3】:

    具体回答如下:

    我们如何配置 Postgres 自动创建分区,我们真的不能每天手动创建分区吗?

    当您使用 Postgres 10 时,您可以使用 https://github.com/pgpartman/pg_partman 来自动管理分区。

    【讨论】:

      猜你喜欢
      • 2019-02-15
      • 2012-01-07
      • 2010-11-22
      • 2016-09-05
      • 2019-07-12
      • 2023-03-22
      • 2013-01-12
      • 2021-08-03
      • 1970-01-01
      相关资源
      最近更新 更多