PostgreSQL pg_dump/复制

Posted

技术标签:

【中文标题】PostgreSQL pg_dump/复制【英文标题】:PostgreSQL pg_dump/COPY 【发布时间】:2020-12-04 09:02:14 【问题描述】:

我需要将可定义的表选择的内容转储为 CSV,以用于初始加载由于各种原因无法与 PostgreSQL 连接的系统。

我已经编写了一个脚本来执行此操作,它使用带有 -c 标志的 psql 运行表列表来运行 psql 的 \COPY 命令将相应的表转储到这样的文件中:

COPY table_name TO table_name.csv WITH (FORMAT 'csv', HEADER, QUOTE '\"', DELIMITER '|');

它工作正常。但我相信您已经发现了问题所在:由于处理约 60 张奇数表需要约 57 分钟,因此一致性的可能性非常接近绝对零。

我考虑了一下,并怀疑我可以对 pg_dump 进行一些轻量级的更改来做我想做的事,即从 pg_dump 创建多个 csv,同时希望表之间的完整性 - 并且能够指定并行转储也是。

我添加了一些标志以允许我应用文件后缀(日期)、设置格式选项并传入相关输出文件的路径。

但是,我修改后的 pg_dump 在写入文件时失败,例如:

COPY table_name (pkey_id, field1, field2 ... fieldn) TO table_name.csv WITH (FORMAT 'csv', HEADER, QUOTE '"', DELIMITER '|')

注意:在pg_dump中,列列表是展开的

所以我四处寻找更多信息并找到了这些COPY Tips。

看起来写入文件是网络上的禁忌;但是我在同一台机器上(现在)。我觉得写到 /tmp 就可以了,因为任何人都可以写。

所以我尝试作弊:

seingramp@seluonkeydb01:~$ ./tp_dump -a -t table_name -D /tmp/ -k "FORMAT 'csv', HEADER, QUOTE '\"', DELIMITER '|'" -K "_$DATE_POSTFIX"
tp_dump: warning: there are circular foreign-key constraints on this table:
tp_dump:   table_name
tp_dump: You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.
tp_dump: Consider using a full dump instead of a --data-only dump to avoid this problem.
--
-- PostgreSQL database dump
--

-- Dumped from database version 12.3
-- Dumped by pg_dump version 14devel

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- Data for Name: material_master; Type: TABLE DATA; Schema: mm; Owner: postgres
--

COPY table_name (pkey_id, field1, field2 ... fieldn) FROM stdin;
tp_dump: error: query failed:
tp_dump: error: query was: COPY table_name (pkey_id, field1, field2 ... fieldn) TO PROGRAM 'gzip > /tmp/table_name_20200814.csv.gz' WITH (FORMAT 'csv', HEADER, QUOTE '"', DELIMITER '|')

我已经对数据进行了绝育,因为它是客户特定的。

我没有发现 pg_dump 的错误信息很有帮助,你对我做错了什么有什么想法吗? 从 ~line 1900 开始,更改确实很小(请原谅代码!),忽略在 getopt() 周围添加的标志。

        /*
         * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
         * a filter condition was specified.  For other cases a simple COPY
         * suffices.
         */
        if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
        
                /* Note: this syntax is only supported in 8.2 and up */
                appendPQExpBufferStr(q, "COPY (SELECT ");
                /* klugery to get rid of parens in column list */
                if (strlen(column_list) > 2)
                
                        appendPQExpBufferStr(q, column_list + 1);
                        q->data[q->len - 1] = ' ';
                
                else
                        appendPQExpBufferStr(q, "* ");

                if ( copy_from_spec )
                
                        if ( copy_from_postfix )
                        
                                appendPQExpBuffer(q, "FROM %s %s) TO PROGRAM 'gzip > %s%s%s.csv.gz' WITH (%s)",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  tdinfo->filtercond ? tdinfo->filtercond : "",
                                                  copy_from_dest ? copy_from_dest : "",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  copy_from_postfix,
                                                  copy_from_spec);
                        
                        else
                        
                                appendPQExpBuffer(q, "FROM %s %s) TO PROGRAM 'gzip > %s%s.csv.gz' WITH (%s)",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  tdinfo->filtercond ? tdinfo->filtercond : "",
                                                  copy_from_dest ? copy_from_dest : "",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  copy_from_spec);
                        
                
                else
                
                        appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  tdinfo->filtercond ? tdinfo->filtercond : "");
                
        
        else
        
                if ( copy_from_spec )
                
                        if ( copy_from_postfix )
                        
                                appendPQExpBuffer(q, "COPY %s %s TO PROGRAM 'gzip > %s%s%s.csv.gz' WITH (%s)",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  column_list,
                                                  copy_from_dest ? copy_from_dest : "",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  copy_from_postfix,
                                                  copy_from_spec);
                        
                        else
                        
                                appendPQExpBuffer(q, "COPY %s %s TO PROGRAM 'gzip > %s%s.csv.gz' WITH (%s)",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  column_list,
                                                  copy_from_dest ? copy_from_dest : "",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  copy_from_spec);
                        
                
                else
                
                        appendPQExpBuffer(q, "COPY %s %s TO stdout;",
                                                  fmtQualifiedDumpable(tbinfo),
                                                  column_list);
                

我也尝试了其他一些作弊方法,例如指定 postgres 拥有的目录。我知道这是一个快速的 hack,但我希望你能提供帮助,感谢您的关注。

【问题讨论】:

IMO,要求不合理。我会从您现有的解决方案中提供 CSV 文件。如果您的客户必须具有数据一致性,那么我会将最近的一致备份还原到另一个数据库并从那里创建 CSV 文件。 在一个设置为 REPEATABLE READ 的事务中运行所有 COPY 语句怎么样? @Mike,现有的解决方案是 MS 技术——遗憾的是,在这个方向上没有希望。 @a_horse_with_no_name 有趣的想法!如果可以从 psql 中的 \COPY 运行,那很可能是一个执行者。 【参考方案1】:

这是pg_restore -f 的用例。 所以:

-- Create custom format dump file
pg_dump -d some_db -U some_user -Fc -f dump.out
-- Move that file to where you need it
-- Dump data only from named table to a file from the dump file.
pg_restore -a -t table_1 -f table_1_data.sql dump.out

pg_dump 将创建表的一致快照,因此您在 dump.out 中使数据库处于“冻结”状态。然后,您可以使用pg_restore 来“解冻”您日程安排中需要的那些部分。通过使用-a,您将获得所需的COPY

【讨论】:

对不起,我没有早点回来,我分心了。感谢您不厌其烦地查看我的问题并提出可行的解决方案 - 我很感激。

以上是关于PostgreSQL pg_dump/复制的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql 9.2执行pg_dump命令问题[重复]

PostgreSQL逻辑备份恢复--pg_dump导出及psql导入案例

Postgresql:如何应用 pg_dump --exclude-table-data 补丁?

PostgreSQL 备份与还原命令 pg_dump

pg_dump:如何在 Amazon Linux 上安装 PostgreSQL 9.5.2?

PostgreSQL pg_dump&psql 数据的备份与恢复