Domanda

Vorrei scrivere uno script che copia il mio database corrente sitedb1 al sitedb2 sulla stessa istanza del database mysql. So che posso scaricare il sitedb1 a uno script SQL:

mysqldump -u root -p sitedb1 >~/db_name.sql

e quindi importarlo a <=>. C'è un modo più semplice, senza dumping il primo database in un file sql?

È stato utile?

Soluzione

Mentre il manuale dice in Copia di database si possibile reindirizzare il dump direttamente nel client mysql:

mysqldump db_name | mysql new_db_name

Se stai usando MyISAM potrebbero copiare i file, ma io non lo consiglio. E 'un po' dubbia.

integrato da varie buone altre risposte

Sia mysqldump e mysql comandi accettano opzioni per impostare i dettagli di collegamento (e molto altro), come:

mysqldump -u <user name> --password=<pwd> <original db> | mysql -u <user name> -p <new db>

Inoltre, se il nuovo database non è ancora esistente, è necessario creare in anticipo (per esempio con echo "create database new_db_name" | mysql -u <dbuser> -p).

Altri suggerimenti

Uso MySQL Utilità

I MySQL Utilità contengono la simpatica strumento mysqldbcopy che di default copie di un DB inclusi tutti gli oggetti correlati ( “tabelle, viste, trigger, eventi, procedure, funzioni, e borse di studio a livello di database”) e dati da un server DB allo stesso o ad un altro server DB. Ci sono un sacco di opzioni disponibili per personalizzare ciò che è effettivamente copiato.

Quindi, per rispondere alla domanda del PO:

mysqldbcopy \
    --source=root:your_password@localhost \
    --destination=root:your_password@localhost \
    sitedb1:sitedb2
$ mysqladmin create DB_name -u DB_user --password=DB_pass && \
    mysqldump -u DB_user --password=DB_pass DB_name | mysql -u DB_user --password=DB_pass -h DB_host DB_name

È necessario eseguire il comando dal prompt del terminale / comandi.

mysqldump -u <user name> -p <pwd> <original db> | mysql -u <user name> <pwd> <new db>

per esempio: mysqldump -u root test_db1 | mysql -u root test_db2

Questa copie test_db1 a test_db2 e concedere l'accesso alla 'root' @ 'localhost'

Il modo migliore e facile è inserire questi comandi in autorizzazioni ed impostare per l'utente root. Per me va bene..!

:~$> mysqldump -u root -p db1 > dump.sql
:~$> mysqladmin -u root -p create db2
:~$> mysql -u root -p db2 < dump.sql

Si potrebbe utilizzare (in pseudocodice):

FOREACH tbl IN db_a:
    CREATE TABLE db_b.tbl LIKE db_a.tbl;
    INSERT INTO db_b.tbl SELECT * FROM db_a.tbl;

Il motivo per cui non sto usando il CREATE TABLE ... SELECT ... la sintassi è quello di preservare gli indici. Naturalmente questo copia solo le tabelle. Vista e le procedure non vengono copiate, anche se può essere fatto nello stesso modo.

CREATE TABLE .

Per prima cosa creare il database duplicato:

CREATE DATABASE duplicateddb;

Assicurarsi che i permessi ecc sono tutti a posto e:

mysqldump -u admin -p originaldb | mysql -u backup -p password duplicateddb;

Si può fare qualcosa di simile al seguente:

mysqldump -u[username] -p[password] database_name_for_clone 
 | mysql -u[username] -p[password] new_database_name

Questa dichiarazione è stata aggiunta in MySQL 5.1.7, ma è risultato essere pericoloso ed è stato rimosso in MySQL 5.1.23. E 'stato destinato a consentire di riqualificazione pre-5.1 database per utilizzare la codifica implementata in 5.1 per i nomi dei database di mappatura ai nomi delle directory del database. Tuttavia, l'uso di questa affermazione potrebbe causare la perdita di contenuto del database, che è il motivo per cui è stato rimosso. Non utilizzare RENAME DATABASE nelle versioni precedenti, in cui è presente.

Per eseguire il compito di aggiornare i nomi di database con la nuova codifica, utilizzare ALTER DATABASE db_name AGGIORNAMENTO DATI RUBRICA invece: http://dev.mysql.com/doc/refman/5.1/en/alter-database.html

Un modo semplice per farlo se si è installato phpMyAdmin :

Vai al database, selezionare la scheda "operazione", e si può vedere la "banca dati copia" blocco. Usalo ed è possibile copiare il database.

Oltre a di Greg risposta , questo è il modo più semplice e veloce se il new_db_name non esiste ancora:

echo "create database new_db_name" | mysql -u <user> -p <pwd> 
mysqldump -u <user> -p <pwd> db_name | mysql -u <user> -p <pwd> new_db_name

Se si dispone di trigger nel database originale, è possibile evitare il "trigger esiste già" l'errore convogliando una sostituzione prima dell'importazione:

mysqldump -u olddbuser -p -d olddbname | sed "s/`olddbname`./`newdbname`./" | mysql -u newdbuser -p -D newdbname

Come menzionato nel di Greg risposta , mysqldump db_name | mysql new_db_name è il libero, sicuro e facile modo per trasferire i dati tra i database. Tuttavia, è anche molto lento .

Se stai cercando di dati di backup, non può permettersi di perdere i dati (in questo o altri database), o stanno utilizzando le tabelle diverse innodb, quindi si dovrebbe utilizzare mysqldump.

Se siete alla ricerca di qualcosa per lo sviluppo, hanno tutti i database sottoposti a backup altrove, e sono confortevoli spurgo e la reinstallazione mysql (possibilmente manualmente) quando tutto va male, allora potrei avere la soluzione per voi.

non riuscivo a trovare una buona alternativa, così ho costruito uno script per farlo io stesso. Ho passato molto di tempo ottenere questo al lavoro la prima volta e terrorizza onestamente mi ha un po 'di apportare modifiche a ora. database InnoDB non erano destinate a copiati e incollati come questo. Piccoli cambiamenti causano questo a fallire in modo magnifico. Non ho avuto un problema quando ho finalizzato il codice, ma questo non significa che non lo farai.

Sistemi testato su (ma potrebbe comunque non riuscire su):

  • Ubuntu 16.04, mysql di default, InnoDB, file separati da tabella
  • Ubuntu 18.04, mysql di default, InnoDB, file separati da tabella

Cosa fa

  1. Ottiene sudo privilegio e verifica di avere abbastanza spazio di archiviazione per clonare il database
  2. Gets privilegi root di MySQL
  3. Crea un nuovo database denominato dopo che il ramo git attuale
  4. I cloni struttura alla nuova base di dati
  5. Passa in modalità di ripristino per InnoDB
  6. Elimina dati di default nel nuovo database
  7. Interrompe mysql
  8. Clones dati al nuovo database
  9. Avvia mysql
  10. Links dati importati in nuovo database
  11. Passa dalla modalità di recupero per InnoDB
  12. riavvia mysql
  13. Fornisce l'accesso degli utenti alla base di dati mysql
  14. Elimina i file temporanei

Come confronta con i master

In un database 3 GB, utilizzando <=> e <=> avrebbe preso 40-50 minuti sulla mia macchina. Utilizzando questo metodo, lo stesso processo sarebbe solo ~ 8 minuti.

Come usiamo

Noi abbiamo le nostre modifiche SQL salvate a fianco il nostro codice e il processo di aggiornamento è automatizzato sia su produzione e sviluppo, con ogni set di modifiche che fanno un backup del database da ripristinare se c'è errori. Un problema che abbiamo avuto era quando stavamo lavorando su un progetto a lungo termine con le modifiche del database, e ha dovuto cambiare i rami in mezzo di esso per correggere un bug o tre.

In passato, abbiamo utilizzato un unico database per tutti i rami, e avrebbe dovuto ricostruire il database ogni volta che siamo passati a un ramo che non era compatibile con le nuove modifiche al database. E quando siamo passati di nuovo, avremmo dovuto eseguire nuovamente gli aggiornamenti.

Abbiamo cercato <=> per duplicare il database per diversi rami, ma il tempo di attesa era troppo lungo (40-50 minuti), e non abbiamo potuto fare altro nel frattempo.

Questa soluzione accorciato il tempo di database clone per 1/5 del tempo (si pensi caffè e bagno pausa, invece di un lungo pranzo).

Attività comuni e il loro tempo

Il passaggio tra i rami con le modifiche del database non compatibili assume 50+ minuti su un unico database, ma non c'è tempo a tutti dopo il tempo di setup iniziale con <=> o del presente codice. Questo codice avviene solo per essere ~ 5 volte più veloce di <=>.

Ecco alcuni compiti comuni e più o meno quanto tempo avrebbero preso con ogni metodo:

Crea ramo di caratteristica con le modifiche del database e immettersi immediatamente:

  • del database unico: ~ 5 minuti
  • Clone con <=>: 50-60 minuti
  • Clona con questo codice: ~ 18 minuti

Crea ramo di caratteristica con modifiche al database, passare a <=> per un bugfix, fare una modifica al ramo della funzione, e unire:

  • del database unico: ~ 60 minuti
  • Clone con <=>: 50-60 minuti
  • Clona con questo codice: ~ 18 minuti

Crea framo eature con modifiche al database, passare a <=> per un bugfix 5 volte rendendo le modifiche sul ramo funzione inbetween, e unire:

  • di database singolo: ~ 4 ore, 40 minuti
  • Clone con <=>: 50-60 minuti
  • Clona con questo codice: ~ 18 minuti

Il codice

Non utilizzare questo a meno che non avete letto e capito tutto sopra.

#!/bin/bash
set -e

# This script taken from: https://stackoverflow.com/a/57528198/526741

function now {
    date "+%H:%M:%S";
}

# Leading space sets messages off from step progress.
echosuccess () {
    printf "\e[0;32m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echowarn () {
    printf "\e[0;33m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echoerror () {
    printf "\e[0;31m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echonotice () {
    printf "\e[0;94m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echoinstructions () {
    printf "\e[0;104m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echostep () {
    printf "\e[0;90mStep %s of 13:\e[0m\n" "$1"
    sleep .1
}

MYSQL_CNF_PATH='/etc/mysql/mysql.conf.d/recovery.cnf'
OLD_DB='YOUR_DATABASE_NAME'
USER='YOUR_MYSQL_USER'

# You can change NEW_DB to whatever you like
# Right now, it will append the current git branch name to the existing database name
BRANCH=`git rev-parse --abbrev-ref HEAD`
NEW_DB="${OLD_DB}__$BRANCH"

THIS_DIR=./site/upgrades
DB_CREATED=false

tmp_file () {
    printf "$THIS_DIR/$NEW_DB.%s" "$1"
}
sql_on_new_db () {
    mysql $NEW_DB --unbuffered --skip-column-names -u root -p$PASS 2>> $(tmp_file 'errors.log')
}

general_cleanup () {
    echoinstructions 'Leave this running while things are cleaned up...'

    if [ -f $(tmp_file 'errors.log') ]; then
        echowarn 'Additional warnings and errors:'
        cat $(tmp_file 'errors.log')
    fi

    for f in $THIS_DIR/$NEW_DB.*; do
        echonotice 'Deleting temporary files created for transfer...'
        rm -f $THIS_DIR/$NEW_DB.*
        break
    done

    echonotice 'Done!'
    echoinstructions "You can close this now :)"
}

error_cleanup () {
    exitcode=$?

    # Just in case script was exited while in a prompt
    echo

    if [ "$exitcode" == "0" ]; then
        echoerror "Script exited prematurely, but exit code was '0'."
    fi

    echoerror "The following command on line ${BASH_LINENO[0]} exited with code $exitcode:"
    echo "             $BASH_COMMAND"

    if [ "$DB_CREATED" = true ]; then
        echo
        echonotice "Dropping database \`$NEW_DB\` if created..."
        echo "DROP DATABASE \`$NEW_DB\`;" | sql_on_new_db || echoerror "Could not drop database \`$NEW_DB\` (see warnings)"
    fi

    general_cleanup

    exit $exitcode
}

trap error_cleanup EXIT

mysql_path () {
    printf "/var/lib/mysql/"
}
old_db_path () {
    printf "%s%s/" "$(mysql_path)" "$OLD_DB"
}
new_db_path () {
    printf "%s%s/" "$(mysql_path)" "$NEW_DB"
}
get_tables () {
    (sudo find /var/lib/mysql/$OLD_DB -name "*.frm" -printf "%f\n") | cut -d'.' -f1 | sort
}

STEP=0


authenticate () {
    printf "\e[0;104m"
    sudo ls &> /dev/null
    printf "\e[0m"
    echonotice 'Authenticated.'
}
echostep $((++STEP))
authenticate

TABLE_COUNT=`get_tables | wc -l`
SPACE_AVAIL=`df -k --output=avail $(mysql_path) | tail -n1`
SPACE_NEEDED=(`sudo du -s $(old_db_path)`)
SPACE_ERR=`echo "$SPACE_AVAIL-$SPACE_NEEDED" | bc`
SPACE_WARN=`echo "$SPACE_AVAIL-$SPACE_NEEDED*3" | bc`
if [ $SPACE_ERR -lt 0 ]; then
    echoerror 'There is not enough space to branch the database.'
    echoerror 'Please free up some space and run this command again.'
    SPACE_AVAIL_FORMATTED=`printf "%'d" $SPACE_AVAIL`
    SPACE_NEEDED_FORMATTED=`printf "%'${#SPACE_AVAIL_FORMATTED}d" $SPACE_NEEDED`
    echonotice "$SPACE_NEEDED_FORMATTED bytes needed to create database branch"
    echonotice "$SPACE_AVAIL_FORMATTED bytes currently free"
    exit 1
elif [ $SPACE_WARN -lt 0 ]; then
    echowarn 'This action will use more than 1/3 of your available space.'
    SPACE_AVAIL_FORMATTED=`printf "%'d" $SPACE_AVAIL`
    SPACE_NEEDED_FORMATTED=`printf "%'${#SPACE_AVAIL_FORMATTED}d" $SPACE_NEEDED`
    echonotice "$SPACE_NEEDED_FORMATTED bytes needed to create database branch"
    echonotice "$SPACE_AVAIL_FORMATTED bytes currently free"
    printf "\e[0;104m"
    read -p " $(now): Do you still want to branch the database? [y/n] " -n 1 -r CONFIRM
    printf "\e[0m"
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
        echonotice 'Database was NOT branched'
        exit 1
    fi
fi

PASS='badpass'
connect_to_db () {
    printf "\e[0;104m %s: MySQL root password: \e[0m" "$(now)"
    read -s PASS
    PASS=${PASS:-badpass}
    echo
    echonotice "Connecting to MySQL..."
}
create_db () {
    echonotice 'Creating empty database...'
    echo "CREATE DATABASE \`$NEW_DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" | mysql -u root -p$PASS 2>> $(tmp_file 'errors.log')
    DB_CREATED=true
}
build_tables () {
    echonotice 'Retrieving and building database structure...'
    mysqldump $OLD_DB --skip-comments -d -u root -p$PASS 2>> $(tmp_file 'errors.log') | pv --width 80  --name " $(now)" > $(tmp_file 'dump.sql')
    pv --width 80  --name " $(now)" $(tmp_file 'dump.sql') | sql_on_new_db
}
set_debug_1 () {
    echonotice 'Switching into recovery mode for innodb...'
    printf '[mysqld]\ninnodb_file_per_table = 1\ninnodb_force_recovery = 1\n' | sudo tee $MYSQL_CNF_PATH > /dev/null
}
set_debug_0 () {
    echonotice 'Switching out of recovery mode for innodb...'
    sudo rm -f $MYSQL_CNF_PATH
}
discard_tablespace () {
    echonotice 'Unlinking default data...'
    (
        echo "USE \`$NEW_DB\`;"
        echo "SET foreign_key_checks = 0;"
        get_tables | while read -r line;
            do echo "ALTER TABLE \`$line\` DISCARD TABLESPACE; SELECT 'Table \`$line\` imported.';";
        done
        echo "SET foreign_key_checks = 1;"
    ) > $(tmp_file 'discard_tablespace.sql')
    cat $(tmp_file 'discard_tablespace.sql') | sql_on_new_db | pv --width 80 --line-mode --size $TABLE_COUNT --name " $(now)" > /dev/null
}
import_tablespace () {
    echonotice 'Linking imported data...'
    (
        echo "USE \`$NEW_DB\`;"
        echo "SET foreign_key_checks = 0;"
        get_tables | while read -r line;
            do echo "ALTER TABLE \`$line\` IMPORT TABLESPACE; SELECT 'Table \`$line\` imported.';";
        done
        echo "SET foreign_key_checks = 1;"
    ) > $(tmp_file 'import_tablespace.sql')
    cat $(tmp_file 'import_tablespace.sql') | sql_on_new_db | pv --width 80 --line-mode --size $TABLE_COUNT --name " $(now)" > /dev/null
}
stop_mysql () {
    echonotice 'Stopping MySQL...'
    sudo /etc/init.d/mysql stop >> $(tmp_file 'log')
}
start_mysql () {
    echonotice 'Starting MySQL...'
    sudo /etc/init.d/mysql start >> $(tmp_file 'log')
}
restart_mysql () {
    echonotice 'Restarting MySQL...'
    sudo /etc/init.d/mysql restart >> $(tmp_file 'log')
}
copy_data () {
    echonotice 'Copying data...'
    sudo rm -f $(new_db_path)*.ibd
    sudo rsync -ah --info=progress2 $(old_db_path) --include '*.ibd' --exclude '*' $(new_db_path)
}
give_access () {
    echonotice "Giving MySQL user \`$USER\` access to database \`$NEW_DB\`"
    echo "GRANT ALL PRIVILEGES ON \`$NEW_DB\`.* to $USER@localhost" | sql_on_new_db
}

echostep $((++STEP))
connect_to_db

EXISTING_TABLE=`echo "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$NEW_DB'" | mysql --skip-column-names -u root -p$PASS 2>> $(tmp_file 'errors.log')`
if [ "$EXISTING_TABLE" == "$NEW_DB" ]
    then
        echoerror "Database \`$NEW_DB\` already exists"
        exit 1
fi

echoinstructions "The hamsters are working. Check back in 5-10 minutes."
sleep 5

echostep $((++STEP))
create_db
echostep $((++STEP))
build_tables
echostep $((++STEP))
set_debug_1
echostep $((++STEP))
discard_tablespace
echostep $((++STEP))
stop_mysql
echostep $((++STEP))
copy_data
echostep $((++STEP))
start_mysql
echostep $((++STEP))
import_tablespace
echostep $((++STEP))
set_debug_0
echostep $((++STEP))
restart_mysql
echostep $((++STEP))
give_access

echo
echosuccess "Database \`$NEW_DB\` is ready to use."
echo

trap general_cleanup EXIT

Se tutto va liscio, si dovrebbe vedere qualcosa di simile:

Schermata di output dello script, ad esempio database

Non credo che ci sia un metodo per fare questo. Quando PHPMyAdmin fa questo, fa uscire il DB poi re-inserisce sotto il nuovo nome.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top