如何从 Postgres 9.4 中转储大对象数据,然后将其导入 Postgres8.x?
Posted
技术标签:
【中文标题】如何从 Postgres 9.4 中转储大对象数据,然后将其导入 Postgres8.x?【英文标题】:How to dump the large object data from Postgres 9.4, and then import it to Postgres8.x? 【发布时间】:2016-12-06 10:30:45 【问题描述】:我使用pg_dump
从 Postgres 9.4 中导出包括大对象 (LO) 的数据,如下所示:
$ pg_dump fhir -O -b > fhir.sql
我生成的fhir.sql
中的 LO 语句是这样的:
SET standard_conforming_strings = on;
SELECT pg_catalog.lowrite(0, '\x1f8b0800000000000000a5903b6ec3300c86efa2d9b1dad5a728daa2');
当我在我的 Postgres8.2 中执行 \i fhir.sql
时,我得到了这个错误:
ERROR: invalid input syntax for type bytea
当我SET standard_conforming_strings = off
时,数据被插入了,但是我得到了一个警告,而我pg_largeobject
表中的数据是:
14 | 0 | \0378b0800000000000000a5903b6ec3300c86efa2d9b1dad5a728daa2
原来的\x1f
改成\037
了,我测试了一下,已经不是我原来的zip文件了……
我该如何解决这个问题?
更新:
我用Hibernate程序将同样的原始数据插入Greenplum(基于Postgresql8.2),然后用pg_dump
导出,格式如下:
SELECT pg_catalog.lowrite(0, '\\037\\213\\010\\000\\000\\000\\000\\000\\000\\000\\245\\220;n\\3030\\014')
【问题讨论】:
【参考方案1】:问题在于转储使用函数pg_catalog.lowrite(integer, bytea)
来创建大对象,并且bytea
字面量在PostgreSQL 中的默认语法在9.0 版本中发生了变化。
有一个参数bytea_output
可以设置为escape
,以旧格式输出bytea
更高版本的PostgreSQL。唉,pg_dump
在创建转储时不尊重该参数,它始终使用“新”hex
格式。
结果是包含来自 PostgreSQL 9.0 或更高版本的大型对象的转储无法恢复到 9.0 之前的数据库中。
您必须以其他方式传输这些大型对象,可能是通过编写迁移程序。
您可以(在 pgsql-hackers 邮件列表中)向pg_dump
提出一个选项,该选项允许为转储设置bytea_escape
,但您可能会遇到阻力,因为将转储从较新的 PostgreSQL 版本恢复到较旧的版本一个不支持。
【讨论】:
很遗憾听到这个消息,我也试过bytea_output
,将其设置为escape
不起作用。感谢您的回答。如果还有其他答案对我有帮助,请允许我抱一线希望。
我会尝试使用 pg_dump 的 Greenplum 版本。但是我没有弄乱过大的物体,所以我不知道它是否会起作用。
@JonRoberts 也许 Greenplum 不一样,但是 PostgreSQL 的 pg_dump
拒绝连接到版本比它自己更高的服务器。
[gpadmin@localhost export]$ pg_dump fhir -h 192.168.2.108 -p 5432 -U postgres -O -t hfj_resource -f fhir.dmp Password: pg_dump: server version: 9.4.6; pg_dump version: 8.2.15 pg_dump: aborting because of server version mismatch
@YinAqu 是的,这正是我所期望的。【参考方案2】:
UPDATA
我发现了一种更简单的工作方式:只需使用pg_dump -b -Fc
将包括LO 的数据导出到自定义文件中,稍后使用与您用于导出数据的pg_dump
相同版本的pg_restore
导入自定义文件文件数据到greenplum。
脚本:
$ pg_dump fhir -O -a -Fc -f fhir.dump
$ pg_restore -h mdw -d fhir -U gpadmin -a fhir.dump > errors.log 2>&1
我错过的一点是lo_export
导出的二进制数据可以完美地导入greenplum。
我的解决方案(针对我的情况):
-
分别从 Postgres9.4 导出纯数据(使用
pg_dump
,排除LO)和LO数据(使用lo_export
)。
将纯数据转储导入 Greenplum
用lo_import
导入LO数据,这会生成一些新的oid
(lo_import
和oid
从Postgres8.4开始),同时用这些新的@更新引用表对应的oid
987654333@。
示例脚本:
从 Postgres9.4 导出纯数据
$ pg_dump fhir -O -a -n public -f fhir.dmp
从包含 LO 数据的某个表中导出 LO,用原始 oid 命名导出的文件
SELECT lo_export(res_text, '/usr/local/pgsql/export/res_lo/'||res_text) FROM hfj_resource;
将纯数据导入Greenplum
\i fhir.dmp
在 Greenplum 中创建一个函数来导入 LO 并更新引用的 oid
CREATE FUNCTION import_lo(tab_name text, lo_path text) RETURNS void AS $$
DECLARE
res record;
new_oid oid;
BEGIN
FOR res in EXECUTE 'select res_text from '||$1 LOOP
new_oid := lo_import($2||'/'||res.res_text);
RAISE NOTICE 'res_text from % to %', res.res_text, new_oid;
EXECUTE 'update '||$1||' set res_text='||new_oid||'where res_text='||res.res_text;
END LOOP;
RAISE NOTICE 'import large object into % finished .....', $1;
END;
$$ LANGUAGE plpgsql;
导入 LO
SELECT import_lo('hfj_resource', '/home/gpadmin/export/res_lo');
【讨论】:
以上是关于如何从 Postgres 9.4 中转储大对象数据,然后将其导入 Postgres8.x?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Postgres 9.4 中对 JSONB 类型的列执行更新操作
RDS postgres 从 9.4 升级到 9.5,CPU 卡在 100% 几个小时
如何从 Postgres Heroku 上的先前备份中恢复特定数据? (例如,意外删除的行)