关于postgresql:如何在一个单一操作中从生产中克隆测试数据库?

How to clone a test database from a production one in one single action?

我正在寻找一个基本的脚本/命令,它将创建一个实时数据库的副本(让它们命名为mydbmydb_test,都在同一个服务器上)。

要求

  • 即使mydb_test已经存在并有记录,它也必须运行。
  • 即使mydbmydb_test确实有连接,它也必须工作。
  • 如果需要,它必须清除可能存在的数据库

提示:

  • 如果您有现有连接,则不能使用drop database

创建现有(实时)数据库完整副本的最简单和最快速的方法是将CREATE DATABASETEMPLATE一起使用:

1
CREATE DATABASE mydb_test TEMPLATE mydb;

但是,有一个重要的限制违反了您的第二个要求:模板(源)数据库不能有额外的连接。我引用手册:

It is possible to create additional template databases, and indeed one
can copy any database in a cluster by specifying its name as the
template for CREATE DATABASE. It is important to understand, however,
that this is not (yet) intended as a general-purpose"COPY DATABASE"
facility. The principal limitation is that no other sessions can be
connected to the source database while it is being copied. CREATE DATABASE
will fail if any other connection exists when it starts; during
the copy operation, new connections to the source database are prevented.

如果您对pg_terminate_backend()具有必要的特权,则可以终止模板数据库的所有会话。要暂时不允许重新连接,请撤消CONNECT特权(稍后将撤消GRANT)。

1
2
3
4
5
6
7
8
9
10
11
REVOKE CONNECT ON DATABASE mydb FROM PUBLIC;

-- while connected to another DB - like the default maintenance DB"postgres"
SELECT pg_terminate_backend(pid)
FROM   pg_stat_activity
WHERE  datname = 'mydb'                    -- name of prospective template db
AND    pid <> pg_backend_pid();            -- don't kill your own session

CREATE DATABASE mydb_test TEMPLATE mydb;

GRANT CONNECT ON DATABASE mydb TO PUBLIC;  -- only if they had it before

在Postgres9.2之前的版本中,使用procpid而不是pid

  • 如果有活动连接,如何删除PostgreSQL数据库?

如果你负担不起终止并发会话的费用,那么就把pg_dump的输出通过管道输送到psql,就像其他答案已经建议的那样。


这就是我要找的,但我必须自己编译它:p

我只希望我知道一种方法来保持同一个用户,而不必把它放在脚本中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
DB_SRC=conf
DB_DST=conf_test
DB_OWNER=confuser

T="$(date +%s)"

psql -c"select pg_terminate_backend(procpid) from pg_stat_activity where datname='$DB_DST';" || { echo"disconnect users failed"; exit 1; }
psql -c"drop database if exists $DB_DST;" || { echo"drop failed"; exit 1; }
psql -c"create database $DB_DST owner confuser;" || { echo"create failed"; exit 1; }
pg_dump $DB_SRC|psql $DB_DST || { echo"dump/restore failed"; exit 1; }

T="$(($(date +%s)-T))"
echo"Time in seconds: ${T}"


由于您没有说在数据库中删除对象是一个问题,所以我认为使用--clean选项运行pg_dump可以满足您的需要。您可以将pg_dump的输出通过管道传输到psql中。


您是否正在研究流式复制的热备份?