2

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

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

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

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

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

我希望有人能给我一些想法。

4

3 回答 3

1

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

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

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

当您想查看 PostgreSQL 在做什么以及如何做时,EXPLAINandEXPLAIN (BUFFERS, ANALYZE)命令非常有用。请参阅手册

为此,您可能会发现可写的公用表表达式很有趣;它使您可以在一个语句中完成所有这些。在这种简单的情况下,可能没有什么好处,但在更复杂的数据迁移中它可能是一个巨大的胜利。

顺便说一句,确保运行包裹在BEGINand中的那对查询COMMIT

于 2012-10-17T22:27:34.350 回答
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或者在对您有效的任何级别更改设置:全局、每个数据库、每个角色、每个会话、每个功能......

于 2012-10-18T03:24:05.837 回答
0

可能不是。

每条记录都单独处理;此特定查询不需要了解任何其他记录即可成功执行。因此,在任何给定时刻唯一需要在内存中的记录就是当前正在处理的记录。

但这真的取决于数据库是否认为它可以通过加载整个表来更快地做到这一点。检查查询的执行计划。

于 2012-10-17T17:18:35.150 回答