Creazione di una copia di un database in PostgreSQL


730

Qual è il modo corretto di copiare l'intero database (la sua struttura e i suoi dati) in uno nuovo in pgAdmin?

Risposte:


1121

Postgres consente l'uso di qualsiasi database esistente sul server come modello durante la creazione di un nuovo database. Non sono sicuro che pgAdmin ti offra l'opzione nella finestra di dialogo di creazione del database, ma in caso contrario dovresti essere in grado di eseguire quanto segue in una finestra di query:

CREATE DATABASE newdb WITH TEMPLATE originaldb OWNER dbuser;

Tuttavia, potresti ottenere:

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

Per disconnettere tutti gli altri utenti dal database, è possibile utilizzare questa query:

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

68
Si noti che originaldb deve essere inattivo (nessuna transazione di scrittura) affinché funzioni.
synecdoche,

62
in pgAdmin3, nel riquadro Browser degli oggetti (a sinistra), posso selezionare Servers-> (il mio server) -> Databases, fare clic con il tasto destro del mouse su Database e selezionare "Nuovo database". Una delle opzioni è il modello e l'SQL utilizzato per creare il database è equivalente. E ' così molto più veloce di una discarica / ripristino sullo stesso server.
jwhitlock,

22
So che questo è un vecchio Q / A, ma sento che ha bisogno di un chiarimento: quando @synecdoche dice che originaldb deve essere inattivo, ciò significa che non c'è alcuna possibilità di scrittura. "Copiare" un database in questo modo non blocca originaldb. PostgreSQL impedisce l'avvio della copia solo se ci sono altri che accedono a originaldb, non dopo l'avvio della copia, quindi è possibile che un'altra connessione possa modificare il database mentre si sta verificando la "copia". IMHO, questa potrebbe essere la risposta più semplice, ma il "migliore" sarebbe usare il dump / restore.
Josh

10
L'ho appena visto. @Josh: mentre originaldb viene copiato creando un database con template, postgresql non consente di creare una nuova connessione ad esso, quindi non sono possibili modifiche.
ceteras,

4
Nota che se stai usando pgAdmin ed esegui CREATE DATABASE ... TEMPLATE xxx da una finestra di comando SQL, devi disconnetterti dal database nella finestra principale di pgAdmin o visualizzerai l'errore relativo agli utenti connessi al database.
Jack RG,

296

Una versione da riga di comando della risposta di Bell :

createdb -O ownername -T originaldb newdb

Questo dovrebbe essere eseguito con i privilegi del master del database, generalmente postgres.


5
Questo è un bel comando MA otterrai createdb: database creation failed: ERROR: source database "conf" is being accessed by other usersse provi a farlo su un database di produzione e come previsto non vuoi chiuderlo per crearne una copia.
sorin,

7
Sì, gli stessi avvertimenti si applicano a questo comando, come per l'espulsione CREATE DATABASE esplicita. Come dicono i commenti per la risposta di Bell sopra, il database dovrebbe essere inattivo.
zbyszek,

108

Per clonare un database esistente con Postgres puoi farlo

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

L'IT ucciderà tutta la connessione al db di origine evitando l'errore

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

7
+1 per menzionare una soluzione di script per evitare l'errore di accesso
bullo

14
Su Postgres 9.2 devo sostituire procpidcon pidper questo al lavoro
marxjohnson

75

Nell'ambiente di produzione, dove il database originale è sotto traffico, sto semplicemente usando:

pg_dump production-db | psql test-db

8
Un problema che ho riscontrato con questo metodo è che pg_dump terrà aperta la sua transazione fino al completamento del ripristino nel nuovo database, anche se pg_dump ha effettivamente terminato il suo dump. Ciò può causare problemi di blocco in alcuni casi (ad esempio, se un'istruzione DDL viene eseguita sul DB di origine).
Chris Butler,

3
Più uno per non usare file intermedi temporanei.
Ardee Aram,

Era anche la mia soluzione. Ieri ha funzionato, ora vengono violati vincoli univoci casuali. Nota: lascio cadere tutta la tabella nel ricevitore db.
gunzapper


1
Ciò presuppone l'esistenza di test-db. Altrimenti, crea il nuovo db con$ createdb newdb
SamGoody il

50

Non so di pgAdmin, ma pgdumpti dà un dump del database in SQL. Hai solo bisogno di creare un database con lo stesso nome e fare

psql mydatabase < my dump

per ripristinare tutte le tabelle, i loro dati e tutti i privilegi di accesso.


Grazie, dovevo creare un dump da un altro server e sembra che questo aiuti: postgresql.org/docs/8.3/interactive/…
egaga,

19
Puoi anche fare anche pg_dump -U postgres sourcedb | psql -U postgres newdbse l'efficienza di questa tecnica può essere discutibile (dal momento che probabilmente finisci per passare dal contesto tra lettura e scrittura)
Frank Farmer,

1
Puoi persino ottenere il tuo dump da una macchina remota tramite ssh: ssh dbserver pg_dump DBNAME | psql NEWDB... o pg_dump DBNAME | ssh otherserver pgsql NEWDB ... Le autorizzazioni e l'autenticazione ovviamente devono essere gestite comunque tu voglia gestirle.
ghoti,

23

Innanzitutto, sudocome utente del database:

sudo su postgres

Vai alla riga di comando PostgreSQL:

psql

Crea il nuovo database, dai i diritti ed esci:

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

Copia struttura e dati dal vecchio database al nuovo:

pg_dump old_database_name | psql new_database_name

come assicurarsi che tutto sia a posto anche in presenza di errori (problemi di rete)? Come verificare se i due database sono uguali dopo la migrazione?
BAE

Gli errori devono essere visualizzati nel terminale ogni volta che si verificano. I due database dovrebbero essere gli stessi dopo l'operazione. Tuttavia, non so come controllare questo ...
Mathieu Rodic,

2
Funziona come un incantesimo, l'ho fatto mentre il database era in produzione.
BioRod,

Questo sembra funzionare bene; tuttavia, i due database hanno dimensioni del disco diverse tramite \l+. Perché la differenza di dimensioni?
kosgeinsky,

@kosgeinsky è stata ampiamente risposta qui: dba.stackexchange.com/a/102089/39386
Mathieu Rodic

18

Ho inserito questo approccio insieme agli esempi dall'alto. Sto lavorando su un server "sotto carico" e ho ricevuto l'errore quando ho tentato l'approccio da @zbyszek. Ero anche alla ricerca di una soluzione "solo a riga di comando".

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

Ecco cosa ha funzionato per me (i comandi preposti nohupper spostare l'output in un file e proteggere da una disconnessione del server ):

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

    il mio utente è "postgres"

  3. nohup psql exampledbclone_01 < example-01.sql


15

In pgAdmin è possibile eseguire un backup dal database originale, quindi creare un nuovo database e ripristinare dal backup appena creato:

  1. Fare clic con il tasto destro del mouse sul database di origine, Backup ... e scaricare in un file.
  2. Fare clic con il tasto destro, Nuovo oggetto, Nuovo database ... e denominare la destinazione.
  3. Fare clic con il tasto destro del mouse sul nuovo database, Ripristina ... e selezionare il file.

Ho tabelle correlate tramite chiavi esterne e questo ha funzionato bene.
Randall Blake,

12

Qual è il modo corretto di copiare l'intero database (la sua struttura e i suoi dati) in uno nuovo in pgAdmin?

Risposta:

CREATE DATABASE newdb WITH TEMPLATE originaldb;

Provato e testato.


3
Ciò richiede che originaldb non sia in uso. Il metodo di Isomorfo no.
Bradley,

2
La stessa risposta fu fornita quasi tre anni prima della tua
Jason S

8

Dalla documentazione , l'uso createdbo CREATE DATABASEcon i modelli non è incoraggiato:

Sebbene sia possibile copiare un database diverso da template1 specificando il suo nome come modello, questo non è (ancora) inteso come una funzione "COPIA DATABASE" per scopi generici. Il limite principale è che nessun'altra sessione può essere connessa al database dei modelli mentre viene copiato. CREATE DATABASE avrà esito negativo se esiste un'altra connessione all'avvio; in caso contrario, le nuove connessioni al database dei modelli vengono bloccate fino al completamento di CREATE DATABASE.

pg_dump o pg_dumpall è un buon metodo per copiare il database E TUTTI I DATI. Se si utilizza una GUI come pgAdmin, questi comandi vengono chiamati dietro le quinte quando si esegue un comando di backup. La copia in un nuovo database viene eseguita in due fasi: backup e ripristino

pg_dumpallsalva tutti i database sul cluster PostgreSQL. Lo svantaggio di questo approccio è che si finisce con un file di testo potenzialmente molto grande pieno di SQL necessario per creare il database e popolare i dati. Il vantaggio di questo approccio è quello di ottenere gratuitamente tutti i ruoli (autorizzazioni) per il cluster. Per eseguire il dump di tutti i database, eseguire questa operazione dall'account superutente

pg_dumpall > db.out

e per ripristinare

psql -f db.out postgres

pg_dumpha alcune opzioni di compressione che ti danno file molto più piccoli. Ho un database di produzione di cui eseguo il backup due volte al giorno con un cron job utilizzando

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

dove si compresstrova il livello di compressione (da 0 a 9) e createdice pg_dumpdi aggiungere comandi per creare il database. Ripristina (o passa al nuovo cluster) utilizzando

pg_restore -d newdb db.dump

dove newdb è il nome del database che si desidera utilizzare.

Altre cose a cui pensare

PostgreSQL utilizza ROLES per la gestione delle autorizzazioni. Questi non vengono copiati da pg_dump. Inoltre, non abbiamo trattato le impostazioni in postgresql.conf e pg_hba.conf (se si sta spostando il database su un altro server). Dovrai capire le impostazioni di configurazione da solo. Ma c'è un trucco che ho appena scoperto per il backup dei ruoli. I ruoli sono gestiti a livello di cluster e puoi chiedere di pg_dumpalleseguire il backup solo dei ruoli con l' --roles-onlyopzione della riga di comando.


7

PostgreSQL 9.1.2:

$ CREATEDB new_db_name -T orig_db_name -O db_user;

3
Ciò è probabilmente implementato poiché CREATE DATABASE newdb WITH TEMPLATE originaldb OWNER dbuser;e di conseguenza è necessario che il database originale sia inattivo (nessuna connessione con accesso in scrittura) e che qualsiasi nuova connessione al database originale sia impedita mentre è in corso la copia. Se sei soddisfatto, funziona.
Mikko Rantalainen,

Bel dettaglio. Grazie!
Arta,

6

Per quelli ancora interessati, ho ideato uno script bash che fa (più o meno) ciò che l'autore voleva. Ho dovuto fare una copia giornaliera del database aziendale su un sistema di produzione, questo script sembra fare il trucco. Ricordarsi di modificare il nome del database / i valori utente / pw.

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

5

Per creare il dump del database

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

Per ridimensionare il dump del database

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

5

Ecco l'intero processo di creazione di una copia su un database utilizzando solo la GUI di pgadmin4 (tramite backup e ripristino)

Postgres viene fornito con Pgadmin4. Se usi macOS puoi premere CMD+ SPACEe digitare pgadmin4per eseguirlo. Questo aprirà una scheda del browser in Chrome.


Passaggi per la copia

1. Creare il backup

Per fare ciò, fai clic con il pulsante destro del mouse sul database -> "backup"

inserisci qui la descrizione dell'immagine

2. Assegna un nome al file.

Come test12345. Fai clic su backup. Questo crea un dump di file binario, non è in un .sqlformato

inserisci qui la descrizione dell'immagine

3. Guarda dove è stato scaricato

Dovrebbe esserci un popup nella parte inferiore destra dello schermo. Fai clic sulla pagina "Ulteriori dettagli" per vedere dove è stato scaricato il backup

inserisci qui la descrizione dell'immagine

4. Trova la posizione del file scaricato

In questo caso, lo è /users/vincenttang

inserisci qui la descrizione dell'immagine

5. Ripristinare il backup da pgadmin

Supponendo di aver eseguito correttamente i passaggi da 1 a 4, avrai un file binario di ripristino. Potrebbe venire un momento in cui il collega desidera utilizzare il file di ripristino sul proprio computer locale. Ho detto che la persona va su pgadmin e ripristina

Fatelo facendo clic con il tasto destro sul database -> "ripristina"

inserisci qui la descrizione dell'immagine

6. Seleziona il file finder

Assicurati di selezionare manualmente il percorso del file, NON trascinare e rilasciare un file sui campi del programma di caricamento in pgadmin. Perché ti imbatterai in permessi di errore. Trova invece il file che hai appena creato:

inserisci qui la descrizione dell'immagine

7. Trova detto file

Potrebbe essere necessario modificare il filtro in basso a "Tutti i file". Trova il file in seguito, dal passaggio 4. Ora premi il pulsante "Seleziona" in basso per confermare

inserisci qui la descrizione dell'immagine

8. Ripristina detto file

Vedrai di nuovo questa pagina, con la posizione del file selezionata. Vai avanti e ripristinalo

inserisci qui la descrizione dell'immagine

9. Successo

Se tutto va bene, in basso a destra dovrebbe apparire un indicatore che mostra un ripristino riuscito. Puoi passare alle tue tabelle per vedere se i dati sono stati ripristinati correttamente su ciascuna tabella.

10. Se non ha avuto successo:

Se il passaggio 9 fallisce, prova a eliminare il tuo vecchio schema pubblico sul tuo database. Vai a "Strumento di query"

inserisci qui la descrizione dell'immagine

Eseguire questo blocco di codice:

DROP SCHEMA public CASCADE; CREATE SCHEMA public;

inserisci qui la descrizione dell'immagine

Ora prova di nuovo i passaggi da 5 a 9, dovrebbe funzionare

MODIFICA - Alcune note aggiuntive. Aggiorna PGADMIN4 se ricevi un errore durante il caricamento con qualcosa del tipo "versione non supportata dell'header 1.14 dell'archiviatore" durante il ripristino


3

Se il database ha connessioni aperte, questo script può essere d'aiuto. Lo uso per creare un database di test da un backup del database di produzione live ogni notte. Questo presuppone che tu abbia un file di backup .SQL dal db di produzione (lo faccio all'interno di 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"

1

Utilizzando pgAdmin, scollegare il database che si desidera utilizzare come modello. Quindi lo si seleziona come modello per creare il nuovo database, in questo modo si evita l'errore già in uso.


0

Se vuoi copiare l'intero schema puoi creare un pg_dump con il seguente comando:

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

E quando vuoi importare quel dump, puoi usare:

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

Ulteriori informazioni sulle stringhe di connessione: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING

O poi semplicemente combinandolo in una fodera:

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”

0
  1. Aprire la finestra principale in pgAdmin e quindi aprire un'altra finestra Strumenti query
  2. Nelle finestre principali di pgAdmin,

Disconnettere il database "basato su modelli" che si desidera utilizzare come modello.

  1. Vai alla finestra Strumenti query

Esegui 2 query come di seguito

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

(La precedente istruzione SQL terminerà tutte le sessioni attive con TemplateDB e quindi ora è possibile selezionarlo come modello per creare il nuovo database TargetDB, questo evita di ottenere l'errore già in uso.)

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

-4

Prova questo:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.