执行此查询时,是否将所有记录加载到物理内存中?

时间:2012-10-17 17:15:03

标签: sql postgresql

我有一张桌子,里面有数百万条记录。该表的总大小仅为6-7千兆字节。该表是我的应用程序日志表。这个表增长得非常快,这很有意义。现在我想将记录从日志表移动到备份表中。这是场景,这是我的问题。

Table Log_A
Insert into Log_b select * from Log_A;
Delete from Log_A;

我正在使用postgres数据库。问题是

执行此查询时Log_A中的所有记录是否都会加载到物理内存中?注意:我的上述两个查询都在存储过程中运行。 如果否,那么它将如何运作?

我希望这个问题适用于所有数据库。

我希望有人能就此提出一些想法。

3 个答案:

答案 0 :(得分:1)

在PostgreSQL中,可能会执行顺序扫描,将一些记录加载到shared_buffers,插入它们,写出脏缓冲区,然后继续进行。

所有记录都将通过主内存,但它们不一定都必须在内存中。因为它们都是使用正常的缓冲读取(pread)从磁盘读取的,所以影响操作系统磁盘缓存,可能会将其他数据推出缓存。

其他数据库可能有所不同。有些人可以在处理SELECT之前执行整个INSERT(虽然如果有任何严重的话,我会感到惊讶)。一些使用O_DIRECT读取或原始磁盘I / O以避免OS缓存影响,因此缓冲区缓存效果可能不同。如果任何数据库依赖于将整个SELECT加载到内存中,我会感到惊讶。

如果您想了解PostgreSQL正在做什么以及如何做,EXPLAINEXPLAIN (BUFFERS, ANALYZE)命令非常有用。请参阅the manual

您可能会发现writable common table expressions对此有意义;它允许你在一个声明中完成所有这些。在这个简单的情况下,可能没什么好处,但它可以在更复杂的数据迁移中取得巨大成功。

BTW,请确保运行包含在BEGINCOMMIT中的那对查询。

答案 1 :(得分:0)

可能不是。

每条记录都是单独处理的;此特定查询不需要知道要成功执行的任何其他记录。因此,在任何特定时刻需要记忆的唯一记录是当前正在处理的记录。

但这实际上取决于数据库是否认为通过加载整个表可以更快地完成它。检查查询的执行计划。

答案 2 :(得分:0)

如果您的设置允许,只需重命名旧表并创建一个新的空表。显然要快得多,因为根本没有复制。

ALTER TABLE log_a RENAME TO log_b;
CREATE TABLE log_a (LIKE log_b INCLUDING ALL);

LIKE子句复制(现在重命名的)旧表的结构。 INCLUDING ALL包括默认值,约束,索引......

取决于表或其他不太常见的依赖项(但不是plpgsql函数中的查询)的外键约束或视图可能是此路由的障碍。您必须重新创建它们才能指向新表。但是你描述的日志表可能没有这种依赖。

这会在桌面上获取独占锁。我假设,典型的写访问权限仅在您的情况下为INSERT?处理并发访问的一种方法是在不同架构中创建新表,并为您的应用程序用户更改 search_path 。然后应用程序开始写入新表而没有并发问题。当然,您不会在INSERT语句中对表名进行模式限定,以使其生效。

CREATE SCHEMA log20121018;
CREATE TABLE log20121018.log_a (LIKE log20121011.log_a INCLUDING ALL);
ALTER ROLE myrole SET search_path = app, log20121018, public;

或者在适用于您的任何级别更改search_path设置: 全局,每个数据库,每个角色,每个会话,每个功能......