PSQL COPY 表到 CSV - 生产数据库上的数据一致性

PSQL COPY tables to CSV - Data consistency on production database

我正在转储数据库以分离 CSV 文件,使用下面的 shell 脚本:

PGENGINE=$PGHOME/bin
PGPASSWORD= $PGENGINE/psql -p  -h  -U  -Atc "select tablename from pg_tables where schemaname='public'"  |\
while read TBL; do
    echo "Exporting table "$TBL
    PGPASSWORD= $PGENGINE/psql -p  -h  -U  -c "COPY public.$TBL TO STDOUT WITH CSV HEADER DELIMITER '"$SEPARATEUR_CSV"'"  > /$ROOT_PATH//$TBL.csv
    echo -e $TBL ": Export done\n"
done

这在我的测试数据库上运行良好,但我担心 运行 它在生产数据库上会发生什么。

我看到很多话题都说 pg_dump 获取数据锁,但我不知道 psql COPY,包括我正在对所有表进行循环。我需要确保如果用户更新了我的一个表,COPY 命令仍将获得正确的数据和正确的 FK。

我的问题:

  1. 你觉得这样做合适吗?存储过程对于数据一致性是否更安全?

  2. 实现此目标的最有效方法是什么? (因为这个生产数据库非常大 - 有些表超过 3000 万行)。

在实时数据库中跨 tables 的一致读取是通过在可重复读取隔离模式下启动事务并在读取所有内容时结束它来实现的。您的脚本必须进行转换,以便只有一个 psql 调用,如下所示:

psql [connection arguments] << EOF
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
\copy table1 TO file1.csv
\copy table2 TO file2.csv
\copy table3 TO file3.csv
COMMIT;

EOF

注意 \copy 而不是 COPY,因为所有这些都分组在同一个 psql 调用中。 psql 本身将每个 \copy 的数据路由到每个客户端输出文件。

这也是一个两步工作流程:首先生成上述脚本(例如通过在 bash 中循环 psql -c 'select tablename....' 或任何其他方法的结果),然后执行脚本。

为什么不能简化为一步?

循环不能在 psql 脚本中实现,因为 psql 没有循环,除了 \gexec,但它在这里不适用,因为 \copy 是一个元命令,并且 \gexec 仅处理 SQL 命令。

循环也不能在 plpgsql 中实现,除非更改问题的上下文,因为 COPY TO STDOUT 的每个输出都不会路由到相应的每个 table 客户端文件。当所有内容连接成一个流时,它会返回给客户端。如果使用 SQL 命令 COPY TO file 它会工作,但你需要是超级用户并且文件最终在服务器上,而不是在客户端上。

我终于找到了这个解决方案:

PGENGINE=$PGHOME/bin
    CHEMIN_SCRIPT_TRANSACTION=/$ROOT_PATH/plc/proc/tmp/dump_transaction.sql
    DOSSIER_DUMP_FICHIERS=/$ROOT_PATH/dump/dump_/dump_fichiers

    echo "BEGIN; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;" > $CHEMIN_SCRIPT_TRANSACTION

    PGPASSWORD= $PGENGINE/psql -p  -h  -U  -Atc "select tablename from pg_tables where schemaname='public'"  |\
    while read TBL; do
        echo "\copy $TBL TO $DOSSIER_DUMP_FICHIERS/$TBL.csv WITH CSV HEADER DELIMITER ';';" >> $CHEMIN_SCRIPT_TRANSACTION
        echo "\echo " >> $CHEMIN_SCRIPT_TRANSACTION
    done
    echo "COMMIT;" >> $CHEMIN_SCRIPT_TRANSACTION

    PGPASSWORD= $PGENGINE/psql -p  -h  -U  -d  -f $CHEMIN_SCRIPT_TRANSACTION

我在另一个文件中创建一个脚本,然后我使用 psql -f 来播放这个脚本。