PostgreSQL 大对象导出报错问题分析

1、前言

在处理用户问题过程遇到一个问题。用户通过pg_dump导出 bytea 对象时,当行的大小超过 1G时,会报错:

[v8r6c5b41@dbhost01 ~]$ sys_dump -t t1_bytea -f 1.dmp -U system test
sys_dump: error: Dumping the contents of table "t1_bytea" failed: PQgetResult() failed.
sys_dump: error: Error message from server: ERROR: invalid memory alloc request size 1298083843
sys_dump: error: The command was: COPY public.t1_bytea (id1, id2) TO stdout;

我们知道,bytea 类型最大存储是 1G ,因此,实际的存储不可能超过1G。 那怎么会有这个问题了?

2、问题复现

构造两个二进制的数据文件:

[root@dbhost01 dbdata]# ls -l *tar
-rw-r--r-- 1 root root  649041920 May 19 17:15 1.tar
-rw-r--r-- 1 root root 1734932480 May 19 19:12 2.tar

创建测试表:

create table t1_bytea(id1 bytea,id2 bytea) ;

插入数据:

复制代码
--单个字段长度超 1G , 报错
test=# insert into t1_bytea(id1) values(sys_read_binary_file('/dbdata/2.tar')); ERROR: requested length too large
--单个字段不超过 1G, 但两个字段总大小超过 1G , 报错。 test=# insert into t1_bytea values(sys_read_binary_file('/dbdata/1.tar'),sys_read_binary_file('/dbdata/1.tar')); ERROR: invalid memory alloc request size 1298083896
--先insert 单个字段,再 update 另一个字段,使得总大小超过 1G , 这种情况下不报错。 test=# insert into t1_bytea(id1) values(sys_read_binary_file('/dbdata/1.tar')); INSERT 0 1 test=# update t1_bytea set id2=sys_read_binary_file('/dbdata/1.tar'); UPDATE 1
--insert select 方式不影响 test=# insert into t1_bytea select * from t1_bytea; INSERT 0 1
复制代码

验证导出数据:

[v8r6c5b41@dbhost01 ~]$ sys_dump -t t1_bytea -f 1.dmp -U system test
sys_dump: error: Dumping the contents of table "t1_bytea" failed: PQgetResult() failed.
sys_dump: error: Error message from server: ERROR:  invalid memory alloc request size 1298083843
sys_dump: error: The command was: COPY public.t1_bytea (id1, id2) TO stdout;

3、结论分析

1、不仅列的大小有 1G 的限制,行的大小也有 1G 的限制;

2、插入数据时,如果一行的数据超过 1G , 则不允许插入;

3、通过 insert 小于 1G 的数据,后续再通过update,可以使得整行数据超过 1G。这也是上述 pg_dump 报错的根本原因。

posted @ 2022-05-25 16:06  数据库集中营  阅读(217)  评论(0编辑  收藏  举报