如何避免 Aurora Postgres 因大型插入 (select ...) 查询而耗尽内存?

I w*_*ood 5 postgresql amazon-rds jooq sql-insert

我正在尝试做的事情:

我正在尝试将大约 200 万条记录从一个表移动到另一个表中。为此,我正在执行一个insert由查询提供的语句select

insert into my_table (
   select a, b, c
   from my_other_table 
   where (condition)  
)
Run Code Online (Sandbox Code Playgroud)

然而,在运行这个程序时,我总是出现内存不足的情况。

我的期望(以及为什么我感到困惑):

如果工作集大于内存所能容纳的大小,我完全认为 Postgres 会将页面缓冲到磁盘上并在幕后迭代地进行写入。

然而,所发生的情况是,它显然尝试将所有edselect内容读入内存,然后再将其填充到另一个表中。

即使在我们的大块 r5.2xl 实例上,它也会消耗所有内存,直到最终 OOM Killer 触发并且 Aurora 重新启动实例。

在此输入图像描述

该图显示每次运行查询时,可用内存都会下降到零。内存备份是由于实例因 OOM 而被自动杀死并重新启动。

我的主要问题:

  1. 为什么 Postgresql 不变得更聪明并在幕后进行自己的分页?
  2. 我需要启用一些设置才能让它了解其内存限制吗?

我尝试过的:

调整shared_bufferswork_mem参数。

Aurora 的默认shared_buffer值为我们的实例分配 20GB。我尝试将其调低至 10gb,然后调至 6.5gb(每次都重新启动),但无济于事。唯一的影响是使查询花费很长时间,并且在运行大约 30 分钟后最终仍然消耗所有可用内存。

我同样尝试将work_mem所有方式设置为允许的最小值,但这似乎对最终结果没有影响。

我可以做些什么来解决这个问题:

当然,我可以从客户端进行分页/批处理:

computeBatchOffsets(context).forEach(batchOffset ->
    context.insertInto(BLAH)
      .select(DSL.asterisk())
      .from(FOO)
      .limit(batchOffset)
      .offset(batchOffset)
      .execute()
Run Code Online (Sandbox Code Playgroud)

但是,除了比仅仅让数据库执行它要慢之外,它“感觉”像是数据库肯定能够内部执行的操作。所以,我很困惑为什么我需要在客户端级别处理它。