it-swarm.com.de

Klonen einer MySQL-Datenbank in derselben MySql-Instanz

Ich möchte ein Skript schreiben, das meine aktuelle Datenbank sitedb1 in sitedb2 auf derselben mysql-Datenbankinstanz kopiert. Ich weiß, dass ich die sitedb1 in ein SQL-Skript ausgeben kann:

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

und importieren Sie es dann in sitedb2. Gibt es einen einfacheren Weg, ohne die erste Datenbank in eine SQL-Datei zu sichern?

103
uclajatt

Wie im Handbuch unter Kopieren von Datenbanken angegeben, können Sie den Dump direkt in den mysql-Client leiten:

mysqldump db_name | mysql new_db_name

Wenn Sie MyISAM verwenden, können Sie die Dateien kopieren , aber ich würde es nicht empfehlen. Es ist ein bisschen zwielichtig.

Integriert aus verschiedenen guten anderen Antworten

Die beiden Befehle mysqldump und mysql akzeptieren Optionen zum Festlegen von Verbindungsdetails (und vielem mehr), wie z.

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

Wenn die neue Datenbank noch nicht vorhanden ist, müssen Sie sie zuvor erstellen (z. B. mit echo "create database new_db_name" | mysql -u <dbuser> -p).

235
Greg

MySQL-Dienstprogramme verwenden

Die MySQL-Dienstprogramme enthalten das Nice-Tool mysqldbcopy , das standardmäßig einen DB einschließlich aller zugehörigen Objekte ("Tabellen, Ansichten, Trigger, Ereignisse, Prozeduren, Funktionen und Zuweisungen auf Datenbankebene") und von einem DB-Server nach kopiert gleich oder zu einem anderen DB-Server. Es gibt viele Optionen, um das Kopierte anzupassen.

Um die Frage des OP zu beantworten:

mysqldbcopy \
    --source=root:[email protected] \
    --destination=root:[email protected] \
    sitedb1:sitedb2
51
Chriki
$ 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
16
Peru

Sie müssen den Befehl von Terminal/Command Prompt ausführen. 

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

beispiel: mysqldump -u root test_db1 | mysql -u root test_db2

Dies kopiert test_db1 nach test_db2 und gewährt den Zugriff auf 'root' @ 'localhost'.

12
Srikanth Gurram

Sie könnten (im Pseudocode) verwenden:

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

Der Grund, warum ich die CREATE TABLE ... SELECT ... -Syntax nicht verwende, ist das Beibehalten von Indizes. Natürlich kopiert dies nur Tabellen. Ansichten und Prozeduren werden nicht kopiert, obwohl sie auf dieselbe Weise ausgeführt werden können.

Siehe CREATE TABLE .

7
Emil H

Am besten und einfachsten können Sie diese Befehle in Ihr Terminal eingeben und Berechtigungen für den Root-Benutzer festlegen. Funktioniert bei mir..! 

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

Erstellen Sie zuerst die doppelte Datenbank:

CREATE DATABASE duplicateddb;

Stellen Sie sicher, dass alle Berechtigungen vorhanden sind und:

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

Sie können etwas wie das Folgende tun:

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

Diese Anweisung wurde in MySQL 5.1.7 hinzugefügt, wurde jedoch als gefährlich befunden und in MySQL 5.1.23 entfernt. Es sollte das Upgrade von Datenbanken vor 5.1 ermöglichen, um die in 5.1 implementierte Kodierung für die Zuordnung von Datenbanknamen zu Datenbankverzeichnisnamen zu verwenden. Die Verwendung dieser Anweisung kann jedoch zum Verlust von Datenbankinhalten führen, weshalb sie entfernt wurde. Verwenden Sie RENAME DATABASE nicht in früheren Versionen, in denen es vorhanden ist.

Um ein Upgrade der Datenbanknamen mit der neuen Codierung durchzuführen, verwenden Sie stattdessen ALTER DATABASE db_name UPGRADE DATA DIRECTORY NAME: http://dev.mysql.com/doc/refman/5.1/de/alter-database.html

1
zacheusz

Es ist besser, den Befehl mysqldbcopy zu verwenden, um die Datenbank von einem Server auf einen anderen oder denselben Server zu kopieren.

mysqldbcopy --source=root:[email protected] --destination=root:[email protected] database-name:database-name-clone

[MySQL]

1
Rakesh C

Ein einfacher Weg, dies zu tun, wenn Sie phpmyadmin installiert haben:

Gehen Sie zu Ihrer Datenbank, wählen Sie die Registerkarte "Vorgang" aus, und Sie sehen den Block "Datenbank kopieren nach". Verwenden Sie es und Sie können die Datenbank kopieren.

0
fzyzcjy

Wie in Gregs Antwort erwähnt, ist mysqldump db_name | mysql new_db_name die freie, sichere und einfache Möglichkeit, Daten zwischen Datenbanken zu übertragen. Es ist jedoch auch sehr langsam .

Wenn Sie Daten sichern möchten, es sich nicht leisten können, Daten (in dieser oder anderen Datenbanken) zu verlieren, oder andere Tabellen als innodb verwenden, sollten Sie mysqldump verwenden.

Wenn Sie etwas für die Entwicklung suchen, alle Ihre Datenbanken an einem anderen Ort sichern möchten und mysql (möglicherweise manuell) problemlos löschen und neu installieren können, habe ich möglicherweise nur die Lösung für Sie.

Ich konnte keine gute Alternative finden und habe ein Skript dafür erstellt. Ich habe viel Zeit damit verbracht, dies zum ersten Mal zum Laufen zu bringen, und es macht mir ehrlich gesagt ein wenig Angst, jetzt Änderungen daran vorzunehmen. Innodb-Datenbanken sollten nicht so kopiert und eingefügt werden. Kleine Änderungen führen dazu, dass dies auf großartige Weise scheitert. Ich hatte kein Problem, seit ich den Code fertig gestellt habe, aber das heißt nicht, dass Sie es nicht tun werden.

Systeme, auf denen getestet wurde (aber möglicherweise weiterhin ein Fehler auftritt):

  • Ubuntu 16.04, Standard MySQL, Innodb, separate Dateien pro Tabelle
  • Ubuntu 18.04, Standard MySQL, Innodb, separate Dateien pro Tabelle

Was es macht

  1. Erhält die Berechtigung Sudo und überprüft, ob Sie über genügend Speicherplatz verfügen, um die Datenbank zu klonen
  2. Ruft Root-MySQL-Berechtigungen ab
  3. Erstellt eine neue Datenbank, die nach dem aktuellen Git-Zweig benannt ist
  4. Klont die Struktur in eine neue Datenbank
  5. Wechselt in den Wiederherstellungsmodus für innodb
  6. Löscht Standarddaten in neuer Datenbank
  7. Stoppt mysql
  8. Klont Daten in neue Datenbank
  9. Startet MySQL
  10. Verknüpft importierte Daten in einer neuen Datenbank
  11. Schaltet den Wiederherstellungsmodus für innodb aus
  12. Startet mysql neu
  13. Ermöglicht MySQL-Benutzern den Zugriff auf die Datenbank
  14. Bereinigt temporäre Dateien

Wie es mit mysqldump verglichen wird

In einer 3-GB-Datenbank würde die Verwendung von mysqldump und mysql auf meinem Computer 40-50 Minuten dauern. Mit dieser Methode würde derselbe Vorgang nur ~ 8 Minuten dauern.

Wie wir es benutzen

Wir haben unsere SQL-Änderungen zusammen mit unserem Code gespeichert und der Upgrade-Prozess wird sowohl in der Produktion als auch in der Entwicklung automatisiert. Bei jeder Änderung wird eine Sicherungskopie der Datenbank erstellt, um sie bei Fehlern wiederherzustellen. Ein Problem, auf das wir stießen, bestand darin, dass wir an einem langfristigen Projekt mit Datenbankänderungen arbeiteten und in der Mitte zwischen Zweigen wechseln mussten, um einen oder drei Fehler zu beheben.

In der Vergangenheit haben wir eine einzige Datenbank für alle Zweige verwendet und mussten die Datenbank jedes Mal neu erstellen, wenn wir zu einem Zweig gewechselt haben, der mit den neuen Datenbankänderungen nicht kompatibel war. Und wenn wir zurückwechseln, müssen wir die Upgrades erneut ausführen.

Wir haben versucht, mysqldump die Datenbank für verschiedene Zweige zu duplizieren, aber die Wartezeit war zu lang (40-50 Minuten), und wir konnten in der Zwischenzeit nichts anderes tun.

Diese Lösung verkürzte die Zeit für das Klonen der Datenbank auf 1/5 der Zeit (denken Sie an Kaffee- und Toilettenpausen anstelle eines langen Mittagessens).

Gemeinsame Aufgaben und ihre Zeit

Das Wechseln zwischen Zweigen mit inkompatiblen Datenbankänderungen dauert mehr als 50 Minuten für eine einzelne Datenbank, jedoch nach der anfänglichen Setup-Zeit mit mysqldump oder diesem Code überhaupt nicht. Dieser Code ist ungefähr fünfmal schneller als mysqldump.

Hier sind einige häufige Aufgaben und ungefähr wie lange sie mit jeder Methode dauern würden:

Erstellen Sie einen Feature-Zweig mit Datenbankänderungen und führen Sie ihn sofort zusammen:

  • Einzelne Datenbank: ~ 5 Minuten
  • Klonen Sie mit mysqldump: 50-60 Minuten
  • Klonen Sie mit diesem Code: ~ 18 Minuten

Erstellen Sie einen Feature-Zweig mit Datenbankänderungen, wechseln Sie zu master, um einen Bugfix zu erhalten, bearbeiten Sie den Feature-Zweig und führen Sie Folgendes zusammen:

  • Einzelne Datenbank: ~ 60 Minuten
  • Klonen Sie mit mysqldump: 50-60 Minuten
  • Klonen Sie mit diesem Code: ~ 18 Minuten

Erstellen Sie einen Feature-Zweig mit Datenbankänderungen, wechseln Sie fünfmal zu master für einen Bugfix, während Sie dazwischen Änderungen am Feature-Zweig vornehmen, und führen Sie Folgendes zusammen:

  • Einzelne Datenbank: ~ 4 Stunden, 40 Minuten
  • Klonen Sie mit mysqldump: 50-60 Minuten
  • Klonen Sie mit diesem Code: ~ 18 Minuten

Der Code

Verwenden Sie dies nur, wenn Sie alles oben gelesen und verstanden haben.

#!/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 [email protected]" | 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

Wenn alles reibungslos verläuft, sollten Sie Folgendes sehen:

Screenshot of script output for example database

0
0b10011

Neben Gregs Answer.
der einfachste und schnellste Weg, wenn der new_db_name noch nicht existiert. 

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
0
rayphi

Wenn Sie Trigger in Ihrer ursprünglichen Datenbank haben, können Sie den Fehler "Trigger existiert bereits" vermeiden, indem Sie vor dem Import einen Ersatz weiterleiten:

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

Ich glaube nicht, dass es dafür eine Methode gibt. Wenn PHPMyAdmin dies ausführt, wird die Datenbank abgelegt und unter dem neuen Namen wieder eingefügt.

0
UnkwnTech

Verwenden Sie 'mysqldbcopy' für das Terminal. Dieser Fall wird schön hier ..__ erwähnt. Beispiel: Starten Sie die cmd-Eingabeaufforderung. Navigieren Sie zum Ordner bin von mySql Server. Feuern Sie die folgende Abfrage ab:

C:\Program Files\MySQL\MySQL Server 5.7\bin>mysqldbcopy --source=root:[email protected] --destination=root:[email protected] master:master_clone

hier versuche ich, meine 'master' -Db in 'master_clone' auf localhost zu kopieren.

0
Rajneesh