2008-08-25 24 views
403

Sin acceso local al servidor, ¿hay alguna manera de duplicar/clonar un MySQL db (con contenido y sin contenido) en otro sin usar mysqldump?Copiar/duplicar base de datos sin usar mysqldump

Actualmente estoy usando MySQL 4.0.

+12

¿Qué pasa con 'mysqldump'? –

+2

La mayoría de las respuestas a continuación recrean mysqldump, que seguramente se romperá en algunos casos ... –

+4

@MichaelMior mysqldump está bien para bases de datos pequeñas pero un volcado reciente de una base de datos altamente indexada me llevará más de 40 horas recuperarme de un volcado. Es por eso que la empresa MySQL tiene una copia de seguridad empresarial, con un precio de $ 5k. PD: Proporcionaré una respuesta que mantenga la integridad referencial al permitirnos usar InnoDB y realizar copias de seguridad y recuperación rápidas. – Quaternion

Respuesta

129

Puede duplicar una tabla sin datos ejecutando:

CREATE TABLE x LIKE y; 

(Ver las MySQL CREATE TABLE Docs)

Se puede escribir un script que toma la salida de SHOW TABLES de una base de datos y copia el esquema de otro. Usted debe ser capaz de hacer referencia a nombres de esquema + mesa como:

CREATE TABLE x LIKE other_db.y; 

Por lo que van los datos, también puede hacerlo en MySQL, pero no es necesariamente rápido. Después de crear las referencias, puede ejecutar lo siguiente para copiar los datos:

INSERT INTO x SELECT * FROM other_db.y; 

Si está usando MyISAM, que es mejor para copiar los archivos de la tabla; será mucho más rápido. Debería poder hacer lo mismo si está utilizando INNODB con per table table spaces.

Si terminas haciendo un INSERT INTO SELECT, asegúrate de temporalmente turn off indexes con ALTER TABLE x DISABLE KEYS!

EDITMaatkit también tiene algunos scripts que pueden ser útiles para sincronizar datos. Puede que no sea más rápido, pero probablemente puedas ejecutar sus scripts de sincronización en datos en vivo sin demasiado bloqueo.

+1

es este trabajo para la tabla duplicada? dado que veo el comando es CREATE TABLE – GusDeCooL

+4

Puede hacer ['CREATE TABLE ... SELECT'] (http://dev.mysql.com/doc/refman/4.1/en/create-table-select.html). – eggyal

+3

Intenté copiar los archivos de tabla de una base de datos MyISAM una vez, pero eso corrompió la nueva base de datos. Probablemente sea malo, pero definitivamente no es una operación tan trivial como algunos dicen que es. –

57

Si está utilizando Linux, puede utilizar este script bash: (quizás necesita un poco de código adicional limpieza pero funciona ... y es mucho más rápido 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 
+0

¿Esto también copia los datos de restricción y otras propiedades de las tablas? –

+1

Parece que sí, porque usa una instrucción "SHOW CREATE TABLE" que genera una CREATE TABLE con todas las propiedades del original. – Danita

+0

¿Soy yo o no funciona? Creó solo unas pocas tablas y arrojó esto: Copiando la base de datos (...) ERROR 1064 (42000) en la línea 1: Tiene un error en su sintaxis SQL; revise el manual que corresponde a su versión del servidor MySQL para la sintaxis correcta para usar cerca de '-modelowanie-copy' en la línea 1 ERROR 1064 (42000) en la línea 1: tiene un error en su sintaxis SQL; revise el manual que corresponde a su versión del servidor MySQL para la sintaxis correcta para usar cerca de '-modelowanie-copy' en la línea 1 – zirael

676

que pueda veo que dijiste que no querías usar mysqldump, pero llegué a esta página mientras buscaba una solución similar y otros podrían encontrarla también. Con esto en mente, aquí hay una manera simple de duplicar una base de datos desde la línea de comando de un servidor de Windows:

  1. Cree la base de datos de destino utilizando MySQLAdmin o su método preferido. En este ejemplo, db2 es la base de datos de destino, donde se copiará la base de datos de origen db1.
  2. ejecute la siguiente instrucción en una línea de comandos:

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

Nota: No hay espacio entre -p y [password]

+0

mysqldump: Tengo error: 1449: El usuario especificado como definidor ('root'@'127.0.0.1') no existe cuando se usa LOCK TABLES – Tjorriemorrie

+3

/¿cuál sería en realidad una buena razón para NO usar mysqldump? –

+88

El caso en contra de ** mysqldump ** es que tiene que haber una manera más rápida que serializar los datos en las consultas, transmitir las consultas fuera del proceso y volver a la cola en ** el mismo proceso **, reparsing the questions y ejecutarlos como declaraciones. Eso suena terriblemente ineficiente e innecesario. No estamos hablando de cruzar entre maestros MySQL o cambiar los motores de almacenamiento. Es impactante que no haya una transferencia binaria intraprocesal eficiente. –

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

Si está trabajando en la máquina de Windows. Entonces amablemente use esto en lugar de encontrar formas largas de ejecutar el comando. – Parixit

+0

este script no toma vistas en el conteo – sd1sd1

0

Realmente no sé a qué te refieres con "acceso local". Pero para esa solución necesita poder acceder a través del servidor ssh al copiar los archivos donde está almacenada la base de datos.

No puedo usar mysqldump, debido a mi base de datos es grande (7Go, Mysqldump fallar) Si la versión de la base de datos MySQL 2 es demasiado diferente podría no funcionar, se puede comprobar la versión de MySQL usando -V MySQL.

1) Copiar los datos desde el servidor remoto en el equipo local (VPS es el alias a su servidor remoto, puede ser reemplazado por [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) Importación de los datos copiados en su computadora 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 usted tiene una versión diferente, es posible que tenga que ejecutar

/etc/init.d/mysql stop 
mysql_upgrade -u root -pPASSWORD --force #that step took almost 1hrs 
/etc/init.d/mysql start 
0

La mejor forma de clonar tablas de bases de datos sin mysqldump:

  1. Cree una nueva base de datos.
  2. Crear clon de consultas con la consulta:

    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. Run que la producción!

Pero tenga en cuenta, por encima de la escritura sólo tablas clon rápido - no vistas, triggers y la facilidad de funciones: se puede obtener rápidamente la estructura de mysqldump --no-data --triggers -uroot -ppassword, y luego se utiliza para clonar sólo se inserte comunicado.

¿Por qué es una pregunta real? Porque la carga de mysqldumps es fea lenta si DB es más de 2 Gb. Y no puede clonar tablas InnoDB simplemente copiando archivos DB (como copia de seguridad de instantáneas).

0

Todas las soluciones anteriores llegan un poco al punto, sin embargo, simplemente no copian todo. Creé una función PHP (aunque algo larga) que copia todo, incluidas tablas, claves externas, datos, vistas, procedimientos, funciones, activadores y eventos. Aquí está el código:

/* 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])); 
     } 
    } 
} 
Cuestiones relacionadas