Kopieren / Duplizieren der Datenbank ohne Verwendung von mysqldump

427

Gibt es ohne lokalen Zugriff auf den Server eine Möglichkeit, eine MySQL-Datenbank (mit und ohne Inhalt) ohne Verwendung in eine andere zu duplizieren / klonen mysqldump?

Ich verwende derzeit MySQL 4.0.

jhornnes
quelle
12
Was ist los mit mysqldump?
Michael Mior
48
Stellen Sie sicher, dass Sie dies nicht tun: CREATE TABLE t2 SELECT * FROM t1;Wenn Sie Ihre Indexinformationen verlieren, führen Sie spezielle Dinge wie auto_increment usw. bei vielen Google-Inhalten für diese Kopiertabelle dazu, und dies führt zu unerwünschten Ergebnissen .
John Hunt
59
Eine Off-Topic-Frage erhält 92 Upvotes und 37 Favoriten. Daumen hoch für solche Off-Topic-Fragen. Veraltete Richtlinien.
Pal4life
25
100% stimmen zu, dass das Thema "Abgeschlossen als falsch" falsch ist und dass die Gildenlinien aktualisiert werden sollten - mehr Nachsicht ist erforderlich - SO geht in die falsche Richtung. Es ist offensichtlich, dass @will völlig daneben liegt und seine Moderatorrechte entfernt werden sollten - diese einzelne Frage ist Beweis genug.
Stolsvik
10
Geschlossen als Off-Topic ist 100% falsch. Dies ist genau die Frage, die ich habe, und sie hat eine genau definierte technische Antwort, die sich nicht auf bloße Meinung bezieht. Ich denke, der Moderator muss so nach Wörtern wie "am besten" gesucht haben, um Fragen zum Schließen zu finden.
Sam Goldberg

Antworten:

686

Ich kann sehen, dass Sie gesagt haben, Sie wollten nicht verwenden mysqldump, aber ich habe diese Seite erreicht, als ich nach einer ähnlichen Lösung gesucht habe, und andere könnten sie auch finden. In diesem Sinne gibt es eine einfache Möglichkeit, eine Datenbank über die Befehlszeile eines Windows-Servers zu duplizieren:

  1. Erstellen Sie die Zieldatenbank mit MySQLAdmin oder Ihrer bevorzugten Methode. In diesem Beispiel db2handelt es sich um die Zieldatenbank, in die die Quellendatenbank db1kopiert wird.
  2. Führen Sie die folgende Anweisung in einer Befehlszeile aus:

mysqldump -h [server] -u [user] -p[password] db1 | mysql -h [server] -u [user] -p[password] db2

Hinweis: Zwischen -pund befindet sich KEIN Leerzeichen[password]

Rafe
quelle
108
Der Fall gegen mysqldump ist, dass es einen schnelleren Weg geben muss, als die Daten in Abfragen zu serialisieren, die Abfragen außerhalb des Prozesses und über das tty zurück in genau denselben Prozess zu übertragen , die Abfragen erneut zu analysieren und als Anweisungen auszuführen. Das klingt schrecklich ineffizient und unnötig . Wir sprechen nicht über das Überqueren von MySQL-Mastern oder das Ändern von Speicher-Engines. Es ist schockierend, dass es keine effiziente binäre Übertragung innerhalb eines Prozesses gibt.
Toddius Zho
42
Wenn Sie den Klartext des Kennworts nicht in Ihrem Terminalverlauf speichern möchten, müssen Sie den Befehl aufteilen : mysqldump -h [server] -u [user] -p db1 > db1, mysql -h [server] -u [user] -p db2 < db1 Andernfalls wird er durch die Kennwortabfrage durcheinander gebracht, zumindest für mich, wenn Sie Kitt verwenden.
Kapex
5
Die Verwendung von mysqldump und mysql aus bash wird viel einfacher, wenn Sie Ihre .my.cnf-Datei zum Speichern Ihrer Benutzer- / Host- / Kennwortdateien
einrichten
4
mysqldump -u root -p -v db1 | mysql -u root -p db2und zweimal geben pass
hlcs
6
Gott, könnte bitte jemand erklären, warum eine Frage mit der Aufschrift "ohne mysqldump" als erste Antwort eine Frage hat, die mysqldump verwendet? mit wie, 6x mehr Stimmen als die richtige ? Komm schon, SO ...
igorsantos07
135

Sie können eine Tabelle ohne Daten duplizieren, indem Sie Folgendes ausführen:

CREATE TABLE x LIKE y;

(Siehe die MySQL CREATE TABLE Docs)

Sie können ein Skript schreiben, das die Ausgabe SHOW TABLESaus einer Datenbank übernimmt und das Schema in eine andere kopiert. Sie sollten in der Lage sein, auf Schema- und Tabellennamen wie folgt zu verweisen:

CREATE TABLE x LIKE other_db.y;

Was die Daten betrifft, können Sie dies auch in MySQL tun, aber es ist nicht unbedingt schnell. Nachdem Sie die Referenzen erstellt haben, können Sie Folgendes ausführen, um die Daten zu kopieren:

INSERT INTO x SELECT * FROM other_db.y;

Wenn Sie MyISAM verwenden, ist es besser, die Tabellendateien zu kopieren. es wird viel schneller sein. Sie sollten in der Lage sein, dasselbe zu tun, wenn Sie INNODB mit Tabellenbereichen pro Tabelle verwenden .

Wenn Sie am Ende eine machen INSERT INTO SELECT, stellen Sie sicher, dass Sie die Indizes mit vorübergehend deaktivierenALTER TABLE x DISABLE KEYS !

EDIT Maatkit hat auch einige Skripte , die für die Synchronisierung Daten hilfreich sein kann. Es ist möglicherweise nicht schneller, aber Sie könnten wahrscheinlich ihre Synchronisierungsskripte für Live-Daten ausführen, ohne viel zu sperren.

Gary Richardson
quelle
1
ist das Arbeit für doppelte Tabelle? da ich sehe, ist der Befehl CREATE TABLE
GusDeCooL
4
Das kannst du machen CREATE TABLE ... SELECT.
Eggyal
3
Ich habe einmal versucht, die Tabellendateien einer MyISAM-Datenbank zu kopieren, aber dadurch wurde die neue Datenbank nur beschädigt. Wahrscheinlich meine schlechte, aber es ist definitiv keine so triviale Operation, wie manche sagen.
Johan Fredrik Varen
2
Dies ist ein netter Trick und ich bin ein Fan, aber ein wichtiger Hinweis: Dies
überträgt
59

Wenn Sie Linux verwenden, können Sie dieses Bash-Skript verwenden: (Es erfordert möglicherweise eine zusätzliche Code-Bereinigung, funktioniert aber ... und ist viel schneller als mysqldump | mysql)

#!/bin/bash

DBUSER=user
DBPASSWORD=pwd
DBSNAME=sourceDb
DBNAME=destinationDb
DBSERVER=db.example.com

fCreateTable=""
fInsertData=""
echo "Copying database ... (may take a while ...)"
DBCONN="-h ${DBSERVER} -u ${DBUSER} --password=${DBPASSWORD}"
echo "DROP DATABASE IF EXISTS ${DBNAME}" | mysql ${DBCONN}
echo "CREATE DATABASE ${DBNAME}" | mysql ${DBCONN}
for TABLE in `echo "SHOW TABLES" | mysql $DBCONN $DBSNAME | tail -n +2`; do
        createTable=`echo "SHOW CREATE TABLE ${TABLE}"|mysql -B -r $DBCONN $DBSNAME|tail -n +2|cut -f 2-`
        fCreateTable="${fCreateTable} ; ${createTable}"
        insertData="INSERT INTO ${DBNAME}.${TABLE} SELECT * FROM ${DBSNAME}.${TABLE}"
        fInsertData="${fInsertData} ; ${insertData}"
done;
echo "$fCreateTable ; $fInsertData" | mysql $DBCONN $DBNAME
jozjan
quelle
7
Wenn Sie das obige Skript mit InnoDB-Tabellen verwenden und Fremdschlüssel haben, ändern Sie die letzte Zeile in die folgende:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
Pegli
Kopiert dies auch Einschränkungsdaten und andere Eigenschaften von Tabellen?
Lucas Moeskops
1
Es scheint so, weil er eine "SHOW CREATE TABLE" -Anweisung verwendet, die eine CREATE TABLE mit allen Eigenschaften des Originals generiert.
Danita
1
Wenn Sie das von @zirael beschriebene Problem erhalten, liegt dies wahrscheinlich daran, dass das Skript keine Ansichten kopieren kann. Sie können Ansichten aus der Kopie ignorieren, indem Sie die SHOW TABLESZeile ändern SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'und hinzufügen | cut -f 1. Die komplette Zeile sollte ungefähr so ​​aussehen, aber die doppelten Backticks durch einzelne Backticks ersetzen: for TABLE in ``echo "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" | mysql $DBCONN $DBSNAME | tail -n +2 | cut -f 1``; do
Code Commander
1
Ich habe dieses Skript von @jozjan bereinigt und einige Kommentare zu Fremd- und anderen Schlüsseln angewendet, um diese Version auf GIST zu erstellen. Gist.github.com/christopher-hopper/8431737
Christopher
11

In PHP:

function cloneDatabase($dbName, $newDbName){
    global $admin;
    $db_check = @mysql_select_db ( $dbName );
    $getTables  =   $admin->query("SHOW TABLES");   
    $tables =   array();
    while($row = mysql_fetch_row($getTables)){
        $tables[]   =   $row[0];
    }
    $createTable    =   mysql_query("CREATE DATABASE `$newDbName` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;") or die(mysql_error());
    foreach($tables as $cTable){
        $db_check   =   @mysql_select_db ( $newDbName );
        $create     =   $admin->query("CREATE TABLE $cTable LIKE ".$dbName.".".$cTable);
        if(!$create) {
            $error  =   true;
        }
        $insert     =   $admin->query("INSERT INTO $cTable SELECT * FROM ".$dbName.".".$cTable);
    }
    return !isset($error);
}


// usage
$clone  = cloneDatabase('dbname','newdbname');  // first: toCopy, second: new database
mr_app
quelle
Wenn Sie an einem Windows-Computer arbeiten. Verwenden Sie dies dann bitte, anstatt lange Wege zu finden, um den Befehl auszuführen.
Parixit
Dieses Skript nimmt keine Ansichten in count
sd1sd1
4

Beachten Sie, dass es einen mysqldbcopy-Befehl als Teil der Add-on-mysql-Dienstprogramme gibt .... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html

Furikel
quelle
Aber es erfordert die Installation eines zusätzlichen Pakets:apt install mysql-utilities
Joel G Mathew
2
Aber es gab keine Einschränkung, die besagte, dass dies nicht möglich war ... und es ist eine häufig installierte Sache (aber optional, wie Sie sagen). Wenn es nicht installiert ist, wäre es für viele einfacher, dieses Paket zu installieren, als ein 60-Zeilen-Bash-Skript einzurichten und auszuführen , etc ....
Furicle
Ihr Beitrag wurde wahrscheinlich abgelehnt, weil Sie keine anderen Informationen als einen Link angegeben haben. Die Antworten sollen umfassender sein.
Joel G Mathew
1

Ich weiß nicht genau, was Sie unter "lokalem Zugang" verstehen. Für diese Lösung müssen Sie jedoch über ssh auf den Server zugreifen können, um die Dateien zu kopieren, in denen die Datenbank gespeichert ist .

Ich kann mysqldump nicht verwenden, da meine Datenbank groß ist (7Go, mysqldump fehlgeschlagen). Wenn die Version der 2 mysql-Datenbank zu unterschiedlich ist, funktioniert sie möglicherweise nicht. Sie können Ihre mysql-Version mit mysql -V überprüfen.

1) Kopieren Sie die Daten von Ihrem Remote-Server auf Ihren lokalen Computer (vps ist der Alias ​​für Ihren Remote-Server und kann durch [email protected] ersetzt werden.)

ssh vps:/etc/init.d/mysql stop
scp -rC vps:/var/lib/mysql/ /tmp/var_lib_mysql
ssh vps:/etc/init.d/apache2 start

2) Importieren Sie die auf Ihren lokalen Computer kopierten Daten

/etc/init.d/mysql stop
sudo chown -R mysql:mysql /tmp/var_lib_mysql
sudo nano /etc/mysql/my.cnf
-> [mysqld]
-> datadir=/tmp/var_lib_mysql
/etc/init.d/mysql start

Wenn Sie eine andere Version haben, müssen Sie diese möglicherweise ausführen

/etc/init.d/mysql stop
mysql_upgrade -u root -pPASSWORD --force #that step took almost 1hrs
/etc/init.d/mysql start
Remy Mellet
quelle
Dies ist der effizienteste Weg, aber ich denke, dass "ohne lokalen Zugriff auf den Server" bedeutet, dass wir nicht auf das System zugreifen können. Wahrscheinlich ein Shared Hosting? Das ist also nicht die Antwort.
Valerio Bozz
1

Alle früheren Lösungen kommen ein wenig auf den Punkt, aber sie kopieren einfach nicht alles über. Ich habe eine PHP-Funktion erstellt (wenn auch etwas langwierig), die alles kopiert, einschließlich Tabellen, Fremdschlüssel, Daten, Ansichten, Prozeduren, Funktionen, Trigger und Ereignisse. Hier ist der Code:

/* This function takes the database connection, an existing database, and the new database and duplicates everything in the new database. */
function copyDatabase($c, $oldDB, $newDB) {

    // creates the schema if it does not exist
    $schema = "CREATE SCHEMA IF NOT EXISTS {$newDB};";
    mysqli_query($c, $schema);

    // selects the new schema
    mysqli_select_db($c, $newDB);

    // gets all tables in the old schema
    $tables = "SELECT table_name
               FROM information_schema.tables
               WHERE table_schema = '{$oldDB}'
               AND table_type = 'BASE TABLE'";
    $results = mysqli_query($c, $tables);

    // checks if any tables were returned and recreates them in the new schema, adds the foreign keys, and inserts the associated data
    if (mysqli_num_rows($results) > 0) {

        // recreates all tables first
        while ($row = mysqli_fetch_array($results)) {
            $table = "CREATE TABLE {$newDB}.{$row[0]} LIKE {$oldDB}.{$row[0]}";
            mysqli_query($c, $table);
        }

        // resets the results to loop through again
        mysqli_data_seek($results, 0);

        // loops through each table to add foreign key and insert data
        while ($row = mysqli_fetch_array($results)) {

            // inserts the data into each table
            $data = "INSERT IGNORE INTO {$newDB}.{$row[0]} SELECT * FROM {$oldDB}.{$row[0]}";
            mysqli_query($c, $data);

            // gets all foreign keys for a particular table in the old schema
            $fks = "SELECT constraint_name, column_name, table_name, referenced_table_name, referenced_column_name
                    FROM information_schema.key_column_usage
                    WHERE referenced_table_name IS NOT NULL
                    AND table_schema = '{$oldDB}'
                    AND table_name = '{$row[0]}'";
            $fkResults = mysqli_query($c, $fks);

            // checks if any foreign keys were returned and recreates them in the new schema
            // Note: ON UPDATE and ON DELETE are not pulled from the original so you would have to change this to your liking
            if (mysqli_num_rows($fkResults) > 0) {
                while ($fkRow = mysqli_fetch_array($fkResults)) {
                    $fkQuery = "ALTER TABLE {$newDB}.{$row[0]}                              
                                ADD CONSTRAINT {$fkRow[0]}
                                FOREIGN KEY ({$fkRow[1]}) REFERENCES {$newDB}.{$fkRow[3]}({$fkRow[1]})
                                ON UPDATE CASCADE
                                ON DELETE CASCADE;";
                    mysqli_query($c, $fkQuery);
                }
            }
        }   
    }

    // gets all views in the old schema
    $views = "SHOW FULL TABLES IN {$oldDB} WHERE table_type LIKE 'VIEW'";                
    $results = mysqli_query($c, $views);

    // checks if any views were returned and recreates them in the new schema
    if (mysqli_num_rows($results) > 0) {
        while ($row = mysqli_fetch_array($results)) {
            $view = "SHOW CREATE VIEW {$oldDB}.{$row[0]}";
            $viewResults = mysqli_query($c, $view);
            $viewRow = mysqli_fetch_array($viewResults);
            mysqli_query($c, preg_replace("/CREATE(.*?)VIEW/", "CREATE VIEW", str_replace($oldDB, $newDB, $viewRow[1])));
        }
    }

    // gets all triggers in the old schema
    $triggers = "SELECT trigger_name, action_timing, event_manipulation, event_object_table, created
                 FROM information_schema.triggers
                 WHERE trigger_schema = '{$oldDB}'";                 
    $results = mysqli_query($c, $triggers);

    // checks if any triggers were returned and recreates them in the new schema
    if (mysqli_num_rows($results) > 0) {
        while ($row = mysqli_fetch_array($results)) {
            $trigger = "SHOW CREATE TRIGGER {$oldDB}.{$row[0]}";
            $triggerResults = mysqli_query($c, $trigger);
            $triggerRow = mysqli_fetch_array($triggerResults);
            mysqli_query($c, str_replace($oldDB, $newDB, $triggerRow[2]));
        }
    }

    // gets all procedures in the old schema
    $procedures = "SHOW PROCEDURE STATUS WHERE db = '{$oldDB}'";
    $results = mysqli_query($c, $procedures);

    // checks if any procedures were returned and recreates them in the new schema
    if (mysqli_num_rows($results) > 0) {
        while ($row = mysqli_fetch_array($results)) {
            $procedure = "SHOW CREATE PROCEDURE {$oldDB}.{$row[1]}";
            $procedureResults = mysqli_query($c, $procedure);
            $procedureRow = mysqli_fetch_array($procedureResults);
            mysqli_query($c, str_replace($oldDB, $newDB, $procedureRow[2]));
        }
    }

    // gets all functions in the old schema
    $functions = "SHOW FUNCTION STATUS WHERE db = '{$oldDB}'";
    $results = mysqli_query($c, $functions);

    // checks if any functions were returned and recreates them in the new schema
    if (mysqli_num_rows($results) > 0) {
        while ($row = mysqli_fetch_array($results)) {
            $function = "SHOW CREATE FUNCTION {$oldDB}.{$row[1]}";
            $functionResults = mysqli_query($c, $function);
            $functionRow = mysqli_fetch_array($functionResults);
            mysqli_query($c, str_replace($oldDB, $newDB, $functionRow[2]));
        }
    }

    // selects the old schema (a must for copying events)
    mysqli_select_db($c, $oldDB);

    // gets all events in the old schema
    $query = "SHOW EVENTS
              WHERE db = '{$oldDB}';";
    $results = mysqli_query($c, $query);

    // selects the new schema again
    mysqli_select_db($c, $newDB);

    // checks if any events were returned and recreates them in the new schema
    if (mysqli_num_rows($results) > 0) {
        while ($row = mysqli_fetch_array($results)) {
            $event = "SHOW CREATE EVENT {$oldDB}.{$row[1]}";
            $eventResults = mysqli_query($c, $event);
            $eventRow = mysqli_fetch_array($eventResults);
            mysqli_query($c, str_replace($oldDB, $newDB, $eventRow[3]));
        }
    }
}
Dustin
quelle
Abgestimmt, weil die Frage nicht "benutze nicht mysqldump", sondern "benutze einen besseren Ansatz als mysqldump" lautet. Dies ist noch schlimmer mysqldumpin Bezug auf die Effizienz.
Valerio Bozz
1

Eigentlich wollte ich genau das in PHP erreichen, aber keine der Antworten hier war sehr hilfreich. Hier ist meine - ziemlich einfache - Lösung mit MySQLi:

// Database variables

$DB_HOST = 'localhost';
$DB_USER = 'root';
$DB_PASS = '1234';

$DB_SRC = 'existing_db';
$DB_DST = 'newly_created_db';



// MYSQL Connect

$mysqli = new mysqli( $DB_HOST, $DB_USER, $DB_PASS ) or die( $mysqli->error );



// Create destination database

$mysqli->query( "CREATE DATABASE $DB_DST" ) or die( $mysqli->error );



// Iterate through tables of source database

$tables = $mysqli->query( "SHOW TABLES FROM $DB_SRC" ) or die( $mysqli->error );

while( $table = $tables->fetch_array() ): $TABLE = $table[0];


    // Copy table and contents in destination database

    $mysqli->query( "CREATE TABLE $DB_DST.$TABLE LIKE $DB_SRC.$TABLE" ) or die( $mysqli->error );
    $mysqli->query( "INSERT INTO $DB_DST.$TABLE SELECT * FROM $DB_SRC.$TABLE" ) or die( $mysqli->error );


endwhile;
GDY
quelle
Ich bin mir nicht sicher, ob dies ein 1: 1-Klon ist, aber es sieht so aus, als ob einfache Datenbanken ausreichen könnten.
beppe9000
Ich verwende das, um schnelle WordPress-Installationen auf meinem Entwicklungsserver zu erstellen. Dieser Teil wird zusammen mit einigen anderen Routinen dupliziert und eine Quellinstallation in ein neues Projekt angepasst. Dafür funktioniert es
einwandfrei
0

Der beste Weg, um Datenbanktabellen ohne mysqldump zu klonen:

  1. Erstellen Sie eine neue Datenbank.
  2. Erstellen Sie Klonabfragen mit Abfrage:

    SET @NewSchema = 'your_new_db';
    SET @OldSchema = 'your_exists_db';
    SELECT CONCAT('CREATE TABLE ',@NewSchema,'.',table_name, ' LIKE ', TABLE_SCHEMA ,'.',table_name,';INSERT INTO ',@NewSchema,'.',table_name,' SELECT * FROM ', TABLE_SCHEMA ,'.',table_name,';') 
    FROM information_schema.TABLES where TABLE_SCHEMA = @OldSchema AND TABLE_TYPE != 'VIEW';
  3. Führen Sie diese Ausgabe aus!

Beachten Sie jedoch, dass das Skript oben nur schnelle Klontabellen enthält - keine Ansichten, Trigger und Benutzerfunktionen: Sie können schnell Strukturen abrufen mysqldump --no-data --triggers -uroot -ppasswordund dann nur Insert-Anweisungen klonen.

Warum ist es eigentlich eine Frage? Weil das Hochladen von mysqldumps hässlich langsam ist, wenn DB über 2 GB ist. Und Sie können InnoDB-Tabellen nicht einfach durch Kopieren von DB-Dateien (wie Snapshot-Backup) klonen.

Alexander Goncharov
quelle
0

Ein SQL, das SQL-Befehle anzeigt, muss ausgeführt werden, um eine Datenbank von einer Datenbank in eine andere zu duplizieren. Für jede Tabelle gibt es eine Tabellenanweisung und eine Einfügeanweisung. Es wird davon ausgegangen, dass sich beide Datenbanken auf demselben Server befinden:

select @fromdb:="crm";
select @todb:="crmen";

SET group_concat_max_len=100000000;


SELECT  GROUP_CONCAT( concat("CREATE TABLE `",@todb,"`.`",table_name,"` LIKE `",@fromdb,"`.`",table_name,"`;\n",
"INSERT INTO `",@todb,"`.`",table_name,"` SELECT * FROM `",@fromdb,"`.`",table_name,"`;") 

SEPARATOR '\n\n')

as sqlstatement
 FROM information_schema.tables where table_schema=@fromdb and TABLE_TYPE='BASE TABLE';
Shimon Doodkin
quelle
-1

Mysqldump ist keine schlechte Lösung. Einfachste Möglichkeit, eine Datenbank zu duplizieren:

mysqldump -uusername -ppass dbname1 | mysql -uusername -ppass dbname2

Sie können die Speicher-Engine auch folgendermaßen ändern:

mysqldump -uusername -ppass dbname1 | sed 's/InnoDB/RocksDB/' | mysql -uusername -ppass dbname2

Andy Al
quelle