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

Sql 执行此查询时,是否将所有记录加载到物理内存中?,sql,postgresql,Sql,Postgresql,我有一张有数百万条记录的桌子。该表的总大小仅为6-7G。此表是我的应用程序日志表。这张桌子长得真快,这是有道理的。现在我想将记录从日志表移动到备份表中。这里是场景,这里是我的问题 Table Log_A Insert into Log_b select * from Log_A; Delete from Log_A; 我正在使用postgres数据库。问题是 执行此查询时,是否会在物理内存中加载来自Log_A的所有记录?注意:我的上述两个查询都在存储过程中运行。 如果没有,那么它将如何工作 我

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

Table Log_A
Insert into Log_b select * from Log_A;
Delete from Log_A;
我正在使用postgres数据库。问题是

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

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

我希望有人能给我一些建议。

可能没有

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


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

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

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

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

当您想了解PostgreSQL正在做什么以及如何做时,
EXPLAIN
EXPLAIN(BUFFERS,ANALYZE)
命令非常有用。看

为此,你可能会觉得有趣;它可以让您在一个语句中完成所有这一切。在这种简单的情况下,可能没有什么好处,但在更复杂的数据迁移中,这可能是一个巨大的胜利


顺便说一句,确保运行包装在
BEGIN
COMMIT
中的那对查询,如果您的设置允许,只需重命名旧表并创建一个新的空表即可。显然,速度要快得多,因为根本不需要复制

ALTER TABLE log_a RENAME TO log_b;
CREATE TABLE log_a (LIKE log_b INCLUDING ALL);
该子句复制(现已重命名)旧表的结构。包括默认值、约束、索引等

根据表或其他不太常见的依赖项(但不是plpgsql函数中的查询)的外键约束或视图可能是此路由的障碍。您必须重新创建它们,使它们指向新表。但是像您描述的日志记录表可能没有这种依赖关系

这将获得表上的独占锁。我假设,只有在您的情况下,典型的写访问才会是
INSERT
?处理并发访问的一种方法是在不同的模式中创建新表,并为应用程序用户更改搜索路径。然后,应用程序开始写入新表,而不会出现并发问题。当然,您不会在
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\u path
设置:
在全球范围内,每个数据库、每个角色、每个会话、每个功能……

听起来不错。谢谢你的解释。顺便说一句,我在postgres函数中运行这些查询。我是否仍然需要处理BEGIN和COMMIT。不应该将整个函数视为一个事务,并用Begin和Commit包装。@PRP好吧,您没有说它封装在函数中。任何不包含周围事务的语句都会被服务器自动包装在一个语句中,因此在函数中不需要(也不能使用)显式事务管理。请参阅您可能希望使用可写CTE(请参阅添加到post的链接)。