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

时间:2017-12-11 09:45:08

标签: postgresql psql postgresql-9.4 consistency pg-dump

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

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

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

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

我的问题:

  1. 您认为这是一种正确的方法吗?存储过程对数据的一致性是否更安全?

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

2 个答案:

答案 0 :(得分:1)

通过在REPEATABLE READ隔离模式下启动事务并在读取所有事务时结束事务,可以实现对实时数据库中表的一致读取。必须转换您的脚本,以便只有一个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的数据路由到每个客户端输出文件。

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

为什么不能简化为一步?

循环无法在psql脚本中实现,因为psql没有循环,除了某些\gexec,但它在这里不适用,因为\copy是一个元命令,{{1只处理SQL命令。

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

答案 1 :(得分:0)

我最终得到了这个解决方案:

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

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

    PGPASSWORD=$1 $PGENGINE/psql -p $2 -h $3 -U $4 -Atc "select tablename from pg_tables where schemaname='public'" $5 |\
    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=$1 $PGENGINE/psql -p $2 -h $3 -U $4 -d $5 -f $CHEMIN_SCRIPT_TRANSACTION

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