我一直在使用 Laurenz Albe 的博客 https://www.cybertec-postgresql.com/en/postgresql-bulk-loading-huge-amounts-of-data/ 练习批量加载。当我稍微改变一下时,问题就开始了。表是一样的:
CREATE TABLE t_sample
(
a varchar(50),
b int,
c varchar(50),
d int
);
代替
BEGIN;
INSERT INTO t_sample VALUES ('abcd', 1, 'abcd', 1);
INSERT INTO t_sample VALUES ('abcd', 1, 'abcd', 1);
INSERT INTO t_sample VALUES ('abcd', 1, 'abcd', 1);
…
COMMIT;`
我用
BEGIN;
INSERT INTO t_sample VALUES
('abcd', 1, 'abcd', 1),
('abcd', 1, 'abcd', 1),
('abcd', 1, 'abcd', 1),
…
COMMIT;
对于那些不想看博客的人:我尝试比较
COPY
和插入方法之间的内存消耗。
此外,我使用了 2097152 条记录,而不是 1 m 条记录。我将此命令保存为文件 multipleinsert.sql 并像
psql -d load_test -f multipleinsert.sql
. 一样运行它
此外,如博客中所述,我使用了如下
COPY
方法(当然记录数相同,2097152)
COPY t_sample FROM stdin;
abcd 1 abcd 1
abcd 1 abcd 1
abcd 1 abcd 1
...
插入 14.543s 和
COPY
的执行时间为 1.237s。然而,这不是我要比较的重点。当我使用 COPY
时,服务器上的可用内存几乎没有减少,但在执行插入语句期间,可用内存减少了近 6.5 GB。包含插入语句的文件本身将近 49 MB,因此 PostgreSQL 尝试缓存它,但为什么它扩展到 ~6,5GB?有没有一种计算方法可以(粗略地)计算 PostgreSQL 为这种加载所消耗的内存?
注意:COPY 是如何工作的,为什么它比 INSERT 快得多?,很好地说明了为什么
COPY
比 insert 快,但是这个和互联网上的任何其他帖子都没有说明内存消耗。
多行
INSERT
与COPY
的处理方式不同。
使用
INSERT
,从客户端发送一个大语句,在服务器上解析和规划,然后执行。整个语句保存在客户端和服务器的内存中,整个大事情必须被解析和计划,所以如果使用大量内存我并不感到惊讶。
但是,我无法解释为什么 50MB 的语句会暂时需要 6.5 GB RAM。这似乎过分了。
COPY
语句本身很小,数据从客户端流式传输到服务器,并在到达时插入到表中。 COPY
可以批量插入多行以提高性能,但批量将小于您的 200 万行,因此它将使用更少的内存。
要调试为什么使用了这么多内存,请在机器上禁用内存过度使用,然后让
INSERT
运行直到内存不足。 PostgreSQL 会将内存上下文转储写入日志文件,它会告诉您内存分配在哪里。