【问题标题】:Creating a copy of a database in PostgreSQL在 PostgreSQL 中创建数据库的副本
【发布时间】:2010-10-26 23:11:10
【问题描述】:

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

【问题讨论】:

  • 问PostgreSQL问题是切题,不属于“通用计算软硬件”的范畴。 PostgreSQL 不是您期望普通计算机用户使用的软件,而是程序员使用并且需要能够在其上运行查询的软件。

标签: postgresql


【解决方案1】:

pgAdmin 的新版本(肯定是 4.30)支持从模板创建新数据库。您只需要填充新的数据库名称和现有的模板数据库。

【讨论】:

    【解决方案2】:

    pgAdmin4:

    1.选择要复制的DB并断开连接

    右键单击 “断开数据库”

    2.在旧数据库旁边创建一个新数据库:

    • 给它一个名字。
    • 在“定义”选项卡中选择 第一个表作为模板(下拉菜单)

    点击创建,然后左键单击新数据库以重新连接。

    【讨论】:

      【解决方案3】:

      复制“负载不足”的数据库

      我将这种方法与上面的示例拼凑在一起。我正在使用“负载不足”的服务器,当我尝试来自@zbyszek 的方法时出现错误。我也在寻求“仅限命令行”的解决方案。

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

      这对我有用(nohup 开头的命令将输出移动到文件中并防止服务器断开连接):

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

        我的用户是“postgres”

      3. nohup psql exampledbclone_01 < example-01.sql

      【讨论】:

        【解决方案4】:

        这是仅使用 pgadmin4 GUI(通过备份和恢复)在数据库上创建副本的整个过程

        Postgres 带有 Pgadmin4。如果您使用 macOS,您可以按 CMD+SPACE 并输入 pgadmin4 来运行它。这将在 chrome 中打开一个浏览器选项卡。


        复制步骤

        1。创建备份

        通过右键单击数据库来执行此操作 -> “备份”

        2。为文件命名。

        喜欢test12345。点击备份。这会创建一个二进制文件转储,它不是.sql 格式

        3。查看下载位置

        屏幕右下角应该有一个弹出窗口。点击“更多详情”页面查看您的备份下载到哪里

        4。查找下载文件的位置

        在这种情况下,它是/users/vincenttang

        5。从 pgadmin 恢复备份

        假设您正确执行了步骤 1 到 4,您将拥有一个还原二进制文件。有时您的同事可能想在他们的本地计算机上使用您的还原文件。说人去pgadmin和恢复

        通过右键单击数据库来执行此操作 -> “恢复”

        6。选择文件查找器

        确保手动选择文件位置,不要将文件拖放到 pgadmin 中的上传器字段中。因为你会遇到错误权限。而是找到您刚刚创建的文件:

        7。找到所说的文件

        您可能需要将右下角的过滤器更改为“所有文件”。之后从第 4 步开始查找文件。现在点击右下角的“选择”按钮进行确认

        8。恢复所述文件

        您将再次看到此页面,并选择了文件的位置。继续并恢复它

        9。成功

        如果一切正常,右下角应该会弹出一个显示成功恢复的指示器。您可以导航到您的表以查看每个表上的数据是否已正确恢复。

        10.如果不成功:

        如果第 9 步失败,请尝试删除数据库上的旧公共架构。转到“查询工具”

        执行此代码块:

        DROP SCHEMA public CASCADE; CREATE SCHEMA public;
        

        现在再次尝试步骤 5 到 9,应该会成功

        EDIT - 一些附加说明。如果您在上传过程中遇到类似于“存档头 1.14 不支持的版本”的错误,请更新 PGADMIN4

        【讨论】:

          【解决方案5】:

          documentation 开始,不鼓励使用createdbCREATE DATABASE 和模板:

          虽然可以通过以下方式复制模板1以外的数据库 将其名称指定为模板,这不是(尚未)打算作为 通用“复制数据库”工具。主要限制是 没有其他会话可以连接到模板数据库,而 它正在被复制。如果有任何其他连接,CREATE DATABASE 将失败 启动时存在;否则,与模板的新连接 数据库在 CREATE DATABASE 完成之前被锁定。

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

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

          pg_dumpall > db.out
          

          恢复

          psql -f db.out postgres
          

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

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

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

          pg_restore -d newdb db.dump
          

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

          其他需要考虑的事情

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

          【讨论】:

            【解决方案6】:

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

            CREATE DATABASE newdb WITH TEMPLATE originaldb OWNER dbuser;
            

            不过,你可能会得到:

            ERROR:  source database "originaldb" is being accessed by other users
            

            要断开所有其他用户与数据库的连接,您可以使用以下查询:

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

            【讨论】:

            • 请注意,originaldb 需要处于空闲状态(无写入事务)才能正常工作。
            • 在pgAdmin3中,在对象浏览器(左)窗格中,我可以选择Servers -> (我的服务器) -> Databases,右键单击数据库,并选择“新建数据库”。选项之一是模板,用于创建数据库的 SQL 是等效的。它so比在同一台服务器上进行转储/恢复要快得多。
            • 我知道这是一个旧的问答,但我觉得需要澄清一下:当@synecdoche 说 originaldb 必须空闲时,这意味着根本没有写入的可能性。以这种方式“复制”数据库不会锁定 originaldb。 PostgreSQL 仅在有其他人访问 originaldb 时才阻止启动复制——不是在复制开始之后,因此在“复制”发生时另一个连接可能会修改数据库。恕我直言,这可能是最简单的答案,但“最好的”是使用转储/恢复。
            • 我刚看到这个。 @Josh:虽然 originaldb 是通过使用模板创建数据库来复制的,但 postgresql 不允许创建到它的新连接,因此无法进行任何更改。
            • 请注意,如果您使用 pgAdmin 并从 SQL 命令窗口执行 CREATE DATABASE ... TEMPLATE xxx,则必须在 pgAdmin 主窗口中断开与数据库的连接,否则您将收到关于连接到数据库的用户。
            【解决方案7】:

            创建数据库转储

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

            重新定位数据库转储

            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
            

            【讨论】:

              【解决方案8】:
              1. 在 pgAdmin 中打开主窗口,然后打开另一个查询工具窗口
              2. 在 pgAdmin 的主窗口中,

              断开要用作模板的“模板化”数据库。

              1. 转到查询工具窗口

              如下运行 2 个查询

              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 数据库,这样可以避免出现已经在使用的错误。)

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

              【讨论】:

                【解决方案9】:

                如果要复制整个架构,可以使用以下命令创建 pg_dump:

                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

                或者然后将其组合在一个衬垫中:

                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”
                

                【讨论】:

                  【解决方案10】:

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

                  pg_dump production-db | psql test-db
                  

                  【讨论】:

                  • 我发现这个方法的一个问题是 pg_dump 将保持打开它的事务直到恢复到新数据库完成,即使 pg_dump 实际上已经完成了它的转储。在某些情况下,这可能会导致锁定问题(例如,如果在源数据库上运行 DDL 语句)。
                  • 加一个不使用临时中间文件。
                  • 这也是我的解决方案。昨天它起作用了,现在违反了随机唯一约束。注意:我将所有表都放到接收方数据库中。
                  • 这假设 test-db 存在。否则,使用$ createdb newdb 创建新数据库
                  【解决方案11】:

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

                  1. 右键单击源数据库,备份...并转储到文件。
                  2. 右键单击,新建对象,新建数据库...并命名目标。
                  3. 右键单击新数据库,还原...并选择您的文件。

                  【讨论】:

                  • 我有通过外键关联的表,这工作得很好。
                  • 谢谢你,这是唯一的帮助。
                  【解决方案12】:

                  不了解 pgAdmin,但pgdump 为您提供了 SQL 数据库的转储。你只需要创建一个同名的数据库并做

                  psql mydatabase < my dump
                  

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

                  【讨论】:

                  • 谢谢,我需要从另一台服务器创建转储,这似乎有帮助:postgresql.org/docs/8.3/interactive/…
                  • 您甚至可以使用pg_dump -U postgres sourcedb | psql -U postgres newdb,尽管这种技术的效率可能值得怀疑(因为您最终可能会在读取和写入之间切换上下文)
                  • 您甚至可以通过 ssh 从远程机器获取您的转储:ssh dbserver pg_dump DBNAME | psql NEWDB ... 或 pg_dump DBNAME | ssh otherserver pgsql NEWDB ... 当然需要处理权限和身份验证,但您想处理它们。
                  【解决方案13】:

                  要使用 postgres 克隆现有数据库,您可以这样做

                  /* 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;
                  

                  IT 将终止与源数据库的所有连接以避免错误

                  ERROR:  source database "SOURCE_DB" is being accessed by other users
                  

                  【讨论】:

                  • +1 用于提及避免访问错误的脚本解决方案
                  • 在 Postgres 9.2 上,我必须将 procpid 替换为 pid 才能正常工作
                  【解决方案14】:

                  Bell's answer 的命令行版本:

                  createdb -O ownername -T originaldb newdb
                  

                  这应该在数据库master的权限下运行,通常是postgres。

                  【讨论】:

                  • 这是一个不错的命令,但是如果您尝试在生产数据库上执行此操作,您将得到 createdb: database creation failed: ERROR: source database "conf" is being accessed by other users,并且正如预期的那样,您不想将其关闭以创建副本。
                  • 是的,同样的警告也适用于这个命令,至于显式的 CREATE DATABASE 调用。就像上面贝尔回答的 cmets 所说,数据库应该是空闲的。
                  【解决方案15】:

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

                  sudo su postgres
                  

                  转到 PostgreSQL 命令行:

                  psql
                  

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

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

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

                  pg_dump old_database_name | psql new_database_name
                  

                  【讨论】:

                  • 即使发生了一些错误(网络问题),如何确保一切正常?迁移后如何检查两个数据库是否相同?
                  • 遇到错误时应在终端中显示。操作后两个数据库应该是一样的。但是,我不知道如何检查...
                  • 工作就像一个魅力,我在数据库生产时就这样做了。
                  • 这似乎运作良好;但是,两个数据库通过 \l+ 具有不同的磁盘大小。为什么大小不同?
                  • @kosgeinsky 这已经在这里得到了广泛的回答:dba.stackexchange.com/a/102089/39386
                  【解决方案16】:

                  试试这个:

                  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

                  【讨论】:

                    【解决方案17】:

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

                    【讨论】:

                      【解决方案18】:

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

                      答案:

                      CREATE DATABASE newdb WITH TEMPLATE originaldb;
                      

                      久经考验。

                      【讨论】:

                      • 这要求 originaldb 不被使用。 Isomorph 的方法没有。
                      • 同样的答案比你早了近三年提供了
                      • 赞成,因为与最佳答案不同,此答案至少指定该命令将复制结构和数据,这是我想确认的。
                      【解决方案19】:

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

                      #!/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"
                      

                      【讨论】:

                        【解决方案20】:

                        对于那些仍然感兴趣的人,我想出了一个 bash 脚本,它(或多或少)做了作者想要的。我必须在生产系统上制作日常业务数据库副本,这个脚本似乎可以解决问题。记得更改数据库名称/用户/密码值。

                        #!/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"
                        

                        【讨论】:

                          【解决方案21】:

                          PostgreSQL 9.1.2:

                          $ CREATEDB new_db_name -T orig_db_name -O db_user;
                          

                          【讨论】:

                          • 这可能实现为CREATE DATABASE newdb WITH TEMPLATE originaldb OWNER dbuser;,因此要求原始数据库必须处于空闲状态(没有具有写访问权限的连接),并且在复制过程中阻止与原始数据库的任何新连接.如果您对此感到满意,则此方法有效。
                          • 不错的细节。谢谢!
                          猜你喜欢
                          • 2010-10-22
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2014-04-25
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2012-07-10
                          相关资源
                          最近更新 更多