Copiez / dupliquez la base de données sans utiliser mysqldump

427

Sans accès local au serveur, existe-t-il un moyen de dupliquer / cloner une base de données MySQL (avec contenu et sans contenu) dans une autre sans utiliser mysqldump?

J'utilise actuellement MySQL 4.0.

jhornnes
la source
12
Qu'est-ce qui ne va pas mysqldump?
Michael Mior
48
Assurez-vous que vous ne le faites pas : CREATE TABLE t2 SELECT * FROM t1;comme vous perdrez vos informations d'index, tout élément spécial comme auto_increment, etc. .
John Hunt du
59
Une question hors sujet obtient 92 votes positifs et 37 favoris. Bravo pour une telle question hors sujet. Lignes directrices obsolètes.
pal4life
25
100% sont d'accord pour dire que le "sujet fermé" est faux et que les lignes de guilde devraient être mises à jour - plus de clémence est nécessaire - SO se dirige dans la mauvaise direction. Il est évident que @will est complètement hors de propos et que ses privilèges de modérateur devraient être supprimés - cette seule question est une preuve suffisante.
stolsvik
10
Fermé car hors sujet est 100% faux. Telle est la question exacte que j'ai, et elle a une réponse technique bien définie qui ne se rapporte pas à une simple opinion. Je pense que le modérateur doit avoir fait une telle recherche de mots comme "meilleur" pour trouver des questions à fermer.
Sam Goldberg

Réponses:

686

Je peux voir que vous avez dit que vous ne vouliez pas l'utiliser mysqldump, mais j'ai atteint cette page en recherchant une solution similaire et d'autres pourraient également la trouver. Dans cet esprit, voici un moyen simple de dupliquer une base de données à partir de la ligne de commande d'un serveur Windows:

  1. Créez la base de données cible à l'aide de MySQLAdmin ou de votre méthode préférée. Dans cet exemple, db2c'est la base de données cible, où la base de données source db1sera copiée.
  2. Exécutez l'instruction suivante sur une ligne de commande:

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

Remarque: il n'y a PAS d'espace entre -pet[password]

Rafe
la source
108
L'argument contre mysqldump est qu'il doit y avoir un moyen plus rapide que de sérialiser les données en requêtes, de transmettre les requêtes en dehors du processus et à travers le tty de nouveau dans le même processus exact , de ré-analyser les requêtes et de les exécuter en tant qu'instructions. Cela semble horriblement inefficace et inutile . Nous ne parlons pas de passer entre les maîtres MySQL ou de changer les moteurs de stockage. C'est choquant qu'il n'y ait pas de transfert binaire intraprocessus efficace.
Toddius Zho
42
Si vous ne souhaitez pas enregistrer le texte en clair mot de passe dans l' historique de vos terminaux, vous devez diviser la commande suivante : mysqldump -h [server] -u [user] -p db1 > db1, mysql -h [server] -u [user] -p db2 < db1 Sinon le mot de passe mess rapides vers le haut, au moins pour moi lors de l' utilisation du mastic.
kapex
5
utiliser mysqldump et mysql de bash devient beaucoup plus simple si vous configurez votre fichier .my.cnf pour stocker vos fichiers utilisateur / hôte / mot de passe
ErichBSchulz
4
mysqldump -u root -p -v db1 | mysql -u root -p db2et deux fois entrer la passe
hlcs
6
dieu, quelqu'un pourrait-il expliquer pourquoi une question indiquant "sans mysqldump" a comme première réponse une question qui utilise mysqldump? avec comme, 6x plus de votes que le bon ? allez, SO ...
igorsantos07
135

Vous pouvez dupliquer une table sans données en exécutant:

CREATE TABLE x LIKE y;

(Voir les documents MySQL CREATE TABLE )

Vous pouvez écrire un script qui prend la sortie SHOW TABLESd'une base de données et copie le schéma dans une autre. Vous devriez pouvoir référencer les noms de schéma + table comme:

CREATE TABLE x LIKE other_db.y;

En ce qui concerne les données, vous pouvez également le faire dans MySQL, mais ce n'est pas nécessairement rapide. Après avoir créé les références, vous pouvez exécuter ce qui suit pour copier les données:

INSERT INTO x SELECT * FROM other_db.y;

Si vous utilisez MyISAM, vous feriez mieux de copier les fichiers de table; ce sera beaucoup plus rapide. Vous devriez pouvoir faire de même si vous utilisez INNODB avec des espaces table par table .

Si vous finissez par faire un INSERT INTO SELECT, assurez-vous de désactiver temporairement les index avec ALTER TABLE x DISABLE KEYS!

EDIT Maatkit possède également certains scripts qui peuvent être utiles pour la synchronisation des données. Ce n'est peut-être pas plus rapide, mais vous pourriez probablement exécuter leurs scripts de synchronisation sur des données en direct sans trop de verrouillage.

Gary Richardson
la source
1
est ce travail pour la table en double? puisque je vois que la commande est CREATE TABLE
GusDeCooL
4
Tu peux le faire CREATE TABLE ... SELECT.
eggyal
3
J'ai essayé de copier une fois les fichiers de table d'une base de données MyISAM, mais cela a juste corrompu la nouvelle base de données. Probablement ma mauvaise, mais ce n'est certainement pas une opération aussi triviale que certains le disent.
Johan Fredrik Varen
2
C'est une bonne astuce et je suis fan, mais une note importante: cela ne
recouvre
59

Si vous utilisez Linux, vous pouvez utiliser ce script bash: (il a peut-être besoin d'un nettoyage de code supplémentaire mais cela fonctionne ... et c'est beaucoup plus rapide que 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
la source
7
Si vous utilisez le script ci-dessus avec des tables InnoDB et avez des clés étrangères, changez la dernière ligne comme suit:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
pegli
Est-ce que cela copie également les données de contrainte et d'autres propriétés des tables?
Lucas Moeskops
1
Il semble que oui, car il utilise une instruction "SHOW CREATE TABLE" qui génère une CREATE TABLE avec toutes les propriétés de l'original.
Danita
1
Si vous rencontrez le problème décrit par @zirael, c'est probablement parce que le script ne parvient pas à copier les vues. Vous pouvez ignorer les vues de la copie en modifiant la SHOW TABLESligne SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'et en ajoutant | cut -f 1. La ligne complète devrait ressembler à ceci mais remplacer les doubles backticks par des simples backticks: 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
J'ai nettoyé ce script par @jozjan et appliqué certains des commentaires concernant les clés étrangères et autres pour créer cette version sur GIST gist.github.com/christopher-hopper/8431737
Christopher
11

En 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
la source
Si vous travaillez sur une machine Windows. Ensuite, veuillez utiliser ceci au lieu de trouver de longues façons d'exécuter la commande.
Parixit le
ce script ne prend pas en compte les vues
sd1sd1
4

Notez qu'il existe une commande mysqldbcopy dans le cadre de l'utilitaire add on mysql .... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html

furicule
la source
Mais cela nécessite l'installation d'un package supplémentaire:apt install mysql-utilities
Joel G Mathew
2
Mais il n'y avait aucune restriction disant que ce n'était pas possible .... et c'est une chose couramment installée (mais facultative comme vous le dites) Si elle n'est pas installée, beaucoup trouveraient l'installation de ce paquet plus facile que la configuration et l'exécution d'un script Bash de 60 lignes , etc ....
furicule
Votre message a probablement été rejeté parce que vous n'avez inclus aucune autre information qu'un lien. Les réponses sont censées être plus complètes.
Joel G Mathew
1

Je ne sais pas vraiment ce que vous entendez par "accès local". Mais pour cette solution, vous devez pouvoir accéder via ssh au serveur pour copier les fichiers où se trouve la base de données .

Je ne peux pas utiliser mysqldump, car ma base de données est grande (7Go, mysqldump échoue) Si la version de la base de données 2 mysql est trop différente, cela pourrait ne pas fonctionner, vous pouvez vérifier votre version mysql en utilisant mysql -V.

1) Copiez les données de votre serveur distant sur votre ordinateur local (vps est l'alias de votre serveur distant, peut être remplacé par [email protected])

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) Importez les données copiées sur votre ordinateur local

/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

Si vous avez une version différente, vous devrez peut-être exécuter

/etc/init.d/mysql stop
mysql_upgrade -u root -pPASSWORD --force #that step took almost 1hrs
/etc/init.d/mysql start
Remy Mellet
la source
C'est le moyen le plus efficace de le faire mais je pense que "sans accès local au serveur" signifie que nous ne pouvons pas accéder au système. Probablement un hébergement mutualisé? Ce n'est donc pas la réponse.
Valerio Bozz du
1

Toutes les solutions antérieures arrivent un peu au point, cependant, elles ne copient pas tout. J'ai créé une fonction PHP (quoique quelque peu longue) qui copie tout, y compris les tables, les clés étrangères, les données, les vues, les procédures, les fonctions, les déclencheurs et les événements. Voici le 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
la source
Voté parce que la question n'est pas "ne pas utiliser mysqldump" mais "utiliser une meilleure approche que mysqldump". C'est encore pire mysqldumpen termes d'efficacité.
Valerio Bozz
1

En fait, je voulais atteindre exactement cela en PHP, mais aucune des réponses ici n'était très utile, alors voici ma - assez simple - solution utilisant 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
la source
Je ne suis pas sûr que cela fasse un clone 1: 1 mais il semble que des bases de données simples pourraient être suffisantes.
beppe9000
Je l'utilise pour créer des installations WordPress rapides sur mon serveur de développement. Cette partie associée à d'autres routines dupliquent et ajustent une installation source dans un nouveau projet. Pour cela, cela fonctionne très bien… mais une base de données wordpress vierge n'est pas très complexe, donc je ne peux pas faire de déclaration pour des cas d'utilisation plus étendus
GDY
0

La meilleure façon de cloner des tables de base de données sans mysqldump:

  1. Créez une nouvelle base de données.
  2. Créez des requêtes de clonage avec une requête:

    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. Exécutez cette sortie!

Mais notez, le script au-dessus des tables de clonage rapide seulement - pas les vues, les déclencheurs et les fonctions utilisateur: vous pouvez rapidement obtenir la structure par mysqldump --no-data --triggers -uroot -ppassword, puis utiliser pour cloner uniquement l'insertion d'une instruction.

Pourquoi c'est une question réelle? Parce que le téléchargement de mysqldumps est très lent si DB dépasse 2 Go. Et vous ne pouvez pas cloner des tables InnoDB simplement en copiant des fichiers DB (comme la sauvegarde d'instantanés).

Alexander Goncharov
la source
0

un SQL qui affiche des commandes SQL, doit être exécuté pour dupliquer une base de données d'une base de données à une autre. pour chaque table, il existe une instruction de table et une instruction d'insertion. il suppose que les deux bases de données sont sur le même serveur:

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
la source
-1

Mysqldump n'est pas une mauvaise solution. Manière la plus simple de dupliquer la base de données:

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

Vous pouvez également modifier le moteur de stockage de cette façon:

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

Andy Al
la source