在PostgreSQL中创建数据库副本

Creating a copy of a database in PostgreSQL

在pgadmin中,将整个数据库(其结构和数据)复制到新数据库的正确方法是什么?


Postgres允许在创建新数据库时使用服务器上的任何现有数据库作为模板。我不确定pgadmin是否为您提供了"创建数据库"对话框上的选项,但如果没有,您应该能够在查询窗口中执行以下操作:

1
CREATE DATABASE newdb WITH TEMPLATE originaldb OWNER dbuser;

不过,你可能会得到:

1
ERROR:  SOURCE DATABASE"originaldb" IS being accessed BY other users

要修复它,可以使用此查询

1
2
SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'originaldb' AND pid <> pg_backend_pid();


贝尔答案的命令行版本:

1
createdb -O ownername -T originaldb newdb

这应该在数据库主服务器(通常是Postgres)的权限下运行。


要用Postgres克隆现有数据库,可以这样做

1
2
3
4
5
6
/* KILL ALL EXISTING CONNECTION FROM ORIGINAL DB (sourcedb)*/
SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'SOURCE_DB' AND pid <> pg_backend_pid();

/* CLONE DATABASE TO NEW ONE(TARGET_DB) */
CREATE DATABASE TARGET_DB WITH TEMPLATE SOURCE_DB OWNER USER_DB;

它将终止与源数据库的所有连接,从而避免出现错误。

1
ERROR:  SOURCE DATABASE"SOURCE_DB" IS being accessed BY other users


在生产环境中,原始数据库处于流量下,我只是使用:

1
pg_dump production-db | psql test-db


不知道pgadmin,但是pgdump提供了一个SQL中数据库的转储。只需要用相同的名称创建数据库,然后

1
psql mydatabase < my dump

恢复所有表及其数据和所有访问权限。


首先,sudo作为数据库用户:

1
sudo su postgres

转到postgresql命令行:

1
psql

创建新数据库,授予权限并退出:

1
2
3
CREATE DATABASE new_database_name;
GRANT ALL PRIVILEGES ON DATABASE new_database_name TO my_user;
\d

将结构和数据从旧数据库复制到新数据库:

1
pg_dump old_database_name | psql new_database_name


我将这种方法与上面的例子结合起来。我正在一个"欠载"的服务器上工作,当我尝试从@zbyszek进行访问时出错。我也在寻求"仅限命令行"的解决方案。

createdb: database creation failed: ERROR: source database"exampledb" is being accessed by other users

以下是我的工作原理(使用nohup预先准备的命令将输出移动到文件中并防止服务器断开连接):

  • nohup pg_dump exampledb > example-01.sql
  • createdb -O postgres exampledbclone_01


    my user is"postgres"

  • nohup psql exampledbclone_01 < example-01.sql

  • 在pgadmin中,您可以从原始数据库进行备份,然后只需创建一个新数据库并从刚刚创建的备份中还原:

  • 右键单击源数据库,备份…并转储到一个文件。
  • 右键单击,新建对象,新建数据库…并命名目的地。
  • 右键单击新数据库,还原…并选择您的文件。

  • 在pgadmin中,将整个数据库(其结构和数据)复制到新数据库的正确方法是什么?

    答:

    1
    CREATE DATABASE newdb WITH TEMPLATE originaldb;

    经过测试。


    《PostgreSQL》9.1.2:

    1
    $ CREATEDB new_db_name -T orig_db_name -O db_user;


    创建数据库转储

    1
    2
    cd /var/lib/pgsql/
    pg_dump database_name> database_name.out

    重新分配数据库转储

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    psql -d template1
    CREATE DATABASE database_name WITH  ENCODING 'UTF8' LC_CTYPE 'en_US.UTF-8' LC_COLLATE 'en_US.UTF-   8' TEMPLATE template0;
    CREATE USER  role_name WITH PASSWORD 'password';
    ALTER DATABASE database_name OWNER TO role_name;
    ALTER USER role_name CREATEDB;
    GRANT ALL PRIVILEGES ON DATABASE database_name TO role_name;


    CTR+D(logout FROM pgsql console)
    cd /var/lib/pgsql/

    psql -d database_name -f database_name.out


    对于那些仍然感兴趣的人,我已经想出了一个bash脚本,它执行(或多或少)作者想要的操作。我不得不每天在生产系统上复制一份商业数据库,这个脚本似乎能做到这一点。请记住更改数据库名称/user/pw值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    #!/bin/bash

    IF [ 1 -ne $# ]
    THEN
      echo"Usage `basename $0` {tar.gz database file}"
      exit 65;
    fi

    IF [ -f"$1" ]
    THEN
      EXTRACTED=`tar -xzvf $1`
      echo"using database archive: $EXTRACTED";
    ELSE
      echo"file $1 does not exist"
      exit 1
    fi


    PGUSER=dbuser
    PGPASSWORD=dbpw
    export PGUSER PGPASSWORD

    datestr=`date +%Y%m%d`


    dbname="dbcpy_$datestr"
    createdbcmd="CREATE DATABASE $dbname WITH OWNER = postgres ENCODING = 'UTF8' TABLESPACE = pg_default LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8' CONNECTION LIMIT = -1;"
    dropdbcmp="DROP DATABASE $dbname"

    echo"creating database $dbname"
    psql -c"$createdbcmd"

    rc=$?
    IF [[ $rc != 0 ]] ; THEN
      rm -rf"$EXTRACTED"
      echo"error occured while creating database $dbname ($rc)"
      exit $rc
    fi


    echo"loading data into database"
    psql $dbname < $EXTRACTED > /dev/NULL

    rc=$?

    rm -rf"$EXTRACTED"

    IF [[ $rc != 0 ]] ; THEN
      psql -c"$dropdbcmd"
      echo"error occured while loading data to database $dbname ($rc)"
      exit $rc
    fi


    echo"finished OK"

    如果数据库有打开的连接,此脚本可能会有所帮助。我每天晚上都用它从实时生产数据库的备份中创建一个测试数据库。这假定您有来自生产数据库的.sql备份文件(我在Webmin中这样做)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #!/bin/sh

    dbname="desired_db_name_of_test_enviroment"
    username="user_name"
    fname="/path to /ExistingBackupFileOfLive.sql"

    dropdbcmp="DROP DATABASE $dbname"
    createdbcmd="CREATE DATABASE $dbname WITH OWNER = $username"

    export PGPASSWORD=MyPassword



    echo"**********"
    echo"** Dropping $dbname"
    psql -d postgres -h localhost -U"$username" -c"$dropdbcmp"

    echo"**********"
    echo"** Creating database $dbname"
    psql -d postgres -h localhost -U"$username" -c"$createdbcmd"

    echo"**********"
    echo"** Loading data into database"
    psql -d postgres -h localhost -U"$username" -d"$dbname" -a -f"$fname"

    在文档中,不鼓励将createdbCREATE DATABASE与模板一起使用:

    Although it is possible to copy a database other than template1 by
    specifying its name as the template, 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 template database while
    it is being copied. CREATE DATABASE will fail if any other connection
    exists when it starts; otherwise, new connections to the template
    database are locked out until CREATE DATABASE completes.

    pg_dumppg_dumpall是复制数据库和所有数据的好方法。如果您使用的是类似于gui的pgadmin,那么在执行备份命令时,这些命令会在后台调用。复制到新数据库分两个阶段完成:备份和恢复

    pg_dumpall保存了PostgreSQL集群上的所有数据库。这种方法的缺点是,您最终会得到一个可能非常大的文本文件,其中包含创建数据库和填充数据所需的SQL。这种方法的优点是您可以免费获得集群的所有角色(权限)。要从超级用户帐户转储所有数据库,请执行此操作

    1
    pg_dumpall > db.out

    并恢复

    1
    psql -f db.out postgres

    pg_dump有一些压缩选项,可以为您提供更小的文件。我有一个生产数据库,每天备份两次,使用cron作业

    1
    pg_dump --create --format=custom --compress=5 ==file=db.dump mydatabase

    其中compress是压缩级别(0到9),create告诉pg_dump添加命令以创建数据库。使用还原(或移动到新群集)

    1
    pg_restore -d newdb db.dump

    其中newdb是要使用的数据库的名称。

    其他需要考虑的事情

    PostgreSQL使用角色来管理权限。这些不是由pg_dump复制的。另外,我们还没有处理postgresql.conf和pg_hba.conf中的设置(如果您要将数据库移动到另一个服务器)。您必须自己解决conf设置。但有一个技巧我刚刚发现备份角色。角色是在集群级别管理的,您可以要求pg_dumpall使用--roles-only命令行开关仅备份角色。


    使用pgadmin,断开要用作模板的数据库。然后选择它作为创建新数据库的模板,这样可以避免出现已在使用中的错误。


  • 在pgadmin中打开主窗口,然后打开另一个查询工具窗口
  • 在pgadmin的主窗口中,
  • 断开要用作模板的"模板化"数据库。

  • 转到"查询工具"窗口
  • 运行2个查询,如下所示

    1
    2
    3
    SELECT pg_terminate_backend(pg_stat_activity.pid)
        FROM pg_stat_activity
        WHERE pg_stat_activity.datname = 'TemplateDB' AND pid <> pg_backend_pid();

    (上面的SQL语句将终止所有使用templatedb的活动会话,然后您现在可以选择它作为模板来创建新的targetdb数据库,这避免了获得已在使用的错误。)

    1
    2
    3
    CREATE DATABASE 'TargetDB'
      WITH TEMPLATE='TemplateDB'
           CONNECTION LIMIT=-1;


    如果要复制整个架构,可以使用以下命令进行pg_转储:

    pg_dump -h database.host.com -d database_name -n schema_name -U database_user --password

    当您要导入该转储文件时,可以使用:

    psql"host=database.host.com user=database_user password=database_password dbname=database_name options=--search_path=schema_name" -f sql_dump_to_import.sql

    有关连接字符串的详细信息:https://www.postgresql.org/docs/current/libpq connect.html libpq-connstring

    或者只是将其组合在一个行中:

    1
    pg_dump -h DATABASE.host.com -d postgres -n schema_name -U database_user --password | psql"host=database.host.com user=database_user password=database_password dbname=database_name options=--search_path=schema_name"

    试试这个:

    1
    CREATE DATABASE newdb WITH ENCODING='UTF8' OWNER=owner TEMPLATE=templatedb LC_COLLATE='en_US.UTF-8' LC_CTYPE='en_US.UTF-8' CONNECTION LIMIT=-1;

    GL XD