从 Postgres 表中删除数百万行的自动化方法
Automated way of deleting millions of rows from Postgres tables
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
在我提出问题之前,我想解释一下我为什么要调查这个问题。我们有一个历史 table,它有超过 500 万行并且每小时都在增长。
随着 table 长度的增长,select 查询变得越来越慢,即使我们有一个合适的索引。所以理想情况下我们的首选是删除未使用的旧记录。
方法 #1
我们尝试使用简单的 delete from table_name where created_date > certain_date where is_active = false
从 table 中删除记录
- 这花了很长时间。
方法 #2
创建一个脚本,使用基于游标的方法删除行。
- 这也需要很长时间。
方法 #3
创建了一个新的未记录的 table。
在 new_table 上创建索引。
将旧 table 中的内容复制到新 table
然后设置table被记录。
重命名主 table 作为备份。
此方法存在问题,需要一些停机时间。
在现场制作实例中,这会导致数据丢失/导致故障
方法 #4
经进一步调查,删除未使用行的高效方法是创建一个 table 分区 https://www.postgresql.org/docs/10/ddl-partitioning.html - 我们可以立即删除整个分区。
上述方法的问题是
- 如何在现有 table 上创建分区?
- 这需要停机吗?
- 我们如何配置 Postgres 自动创建分区,我们不能每天手动创建分区吧?
也欢迎任何其他方法,问题是我真的希望这是自动化的而不是手动的,因为我会将其扩展到多个 tables。
请告诉我你的想法,这将非常有帮助
我会选择方法 4,table 分区。
- 创建分区
- 新数据直接进入正确的分区
- 将旧数据(手动/脚本)移动到正确的分区
- 设置一个 cron 作业来为接下来的 X 天创建分区,如果它们不存在的话
无需停机
We tried deleting the records from the table using simple delete from table_name where created_date > certain_date where is_active = false
This took a very long time.
你肯定是指 <
,而不是 >
?那么,如果需要很长时间呢?你需要多快?它造成问题了吗?您尝试一次删除多少数据?
500 万行很小。我可能一开始就不会在这么大的东西上使用分区。
如果您还没有分区数据,则没有简单透明的方法可以迁移到分区数据。最简单的方法是在填充新 table.
时稍作休息
如果您确实想要分区,您的分区方案必须包括 is_active,而不仅仅是 created_date。白天似乎太好了,你可以按月做,然后预先创造几年的价值。
具体回答以下内容:
How can we configure Postgres to create partition automatically, we can't really create partitions manually everyday right?
由于您使用的是 Postgres 10,您可以使用 https://github.com/pgpartman/pg_partman 自动管理分区。
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
在我提出问题之前,我想解释一下我为什么要调查这个问题。我们有一个历史 table,它有超过 500 万行并且每小时都在增长。
随着 table 长度的增长,select 查询变得越来越慢,即使我们有一个合适的索引。所以理想情况下我们的首选是删除未使用的旧记录。
方法 #1
我们尝试使用简单的 delete from table_name where created_date > certain_date where is_active = false
- 这花了很长时间。
方法 #2
创建一个脚本,使用基于游标的方法删除行。
- 这也需要很长时间。
方法 #3
创建了一个新的未记录的 table。
在 new_table 上创建索引。
将旧 table 中的内容复制到新 table
然后设置table被记录。
重命名主 table 作为备份。
此方法存在问题,需要一些停机时间。
在现场制作实例中,这会导致数据丢失/导致故障
方法 #4
经进一步调查,删除未使用行的高效方法是创建一个 table 分区 https://www.postgresql.org/docs/10/ddl-partitioning.html - 我们可以立即删除整个分区。
上述方法的问题是
- 如何在现有 table 上创建分区?
- 这需要停机吗?
- 我们如何配置 Postgres 自动创建分区,我们不能每天手动创建分区吧?
也欢迎任何其他方法,问题是我真的希望这是自动化的而不是手动的,因为我会将其扩展到多个 tables。
请告诉我你的想法,这将非常有帮助
我会选择方法 4,table 分区。
- 创建分区
- 新数据直接进入正确的分区
- 将旧数据(手动/脚本)移动到正确的分区
- 设置一个 cron 作业来为接下来的 X 天创建分区,如果它们不存在的话
无需停机
We tried deleting the records from the table using simple
delete from table_name where created_date > certain_date where is_active = false
This took a very long time.
你肯定是指 <
,而不是 >
?那么,如果需要很长时间呢?你需要多快?它造成问题了吗?您尝试一次删除多少数据?
500 万行很小。我可能一开始就不会在这么大的东西上使用分区。
如果您还没有分区数据,则没有简单透明的方法可以迁移到分区数据。最简单的方法是在填充新 table.
时稍作休息如果您确实想要分区,您的分区方案必须包括 is_active,而不仅仅是 created_date。白天似乎太好了,你可以按月做,然后预先创造几年的价值。
具体回答以下内容:
How can we configure Postgres to create partition automatically, we can't really create partitions manually everyday right?
由于您使用的是 Postgres 10,您可以使用 https://github.com/pgpartman/pg_partman 自动管理分区。