Copiar / duplicar la base de datos sin usar mysqldump
427
Sin acceso local al servidor, ¿hay alguna forma de duplicar / clonar una base de datos MySQL (con contenido y sin contenido) en otra sin usar mysqldump?
Asegúrese de no hacer esto: CREATE TABLE t2 SELECT * FROM t1;ya que perderá su información de índice, cualquier cosa especial como auto_increment, etc. muchos de los google para este tipo de tabla de copia lo llevarán a hacer esto y tendrá resultados no deseados .
John Hunt
59
Una pregunta fuera de tema obtiene 92 votos a favor y 37 favoritos. Pulgares arriba para tal pregunta fuera de tema. Pautas desactualizadas.
pal4life
25
El 100% está de acuerdo en que el "tema cerrado como incorrecto" está mal y que las líneas de culpabilidad deben actualizarse, se necesita más indulgencia, por lo que SO se dirige en la dirección equivocada. Es obvio que @will está completamente fuera de lugar, y debería tener sus privilegios de moderador eliminados; esta sola pregunta es prueba suficiente.
stolsvik
10
Cerrado como fuera de tema es 100% incorrecto. Esta es la pregunta exacta que tengo, y tiene una respuesta técnica bien definida que no se relaciona con la mera opinión. Creo que el moderador debe haber estado buscando palabras como "mejor" para encontrar preguntas para cerrar.
Sam Goldberg
Respuestas:
686
Puedo ver 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 eso en mente, aquí hay una manera simple de duplicar una base de datos desde la línea de comandos de un servidor de Windows:
Cree la base de datos de destino utilizando MySQLAdmin o su método preferido. En este ejemplo, db2es la base de datos de destino, donde db1se copiará la base de datos de origen .
Ejecute la siguiente instrucción en una línea de comando:
El caso en contra de mysqldump es que tiene que haber una forma más rápida de serializar los datos en consultas, transmitir las consultas fuera del proceso y a través del tty nuevamente en el mismo proceso , volver a analizar las consultas y ejecutarlas como declaraciones. Eso suena terriblemente ineficiente e innecesario . No estamos hablando de cruzar entre maestros MySQL o cambiar motores de almacenamiento. Es sorprendente que no haya una transferencia binaria eficiente dentro del proceso.
Toddius Zho el
42
Si no desea guardar el texto sin formato de la contraseña en el historial de sus terminales, debe dividir el comando: de lo contrario mysqldump -h [server] -u [user] -p db1 > db1, mysql -h [server] -u [user] -p db2 < db1el mensaje de contraseña lo estropea, al menos para mí cuando usa masilla.
kapex
55
usar mysqldump y mysql de bash se vuelve mucho más simple si configura su archivo .my.cnf para almacenar sus archivos de usuario / host / contraseña
ErichBSchulz
44
mysqldump -u root -p -v db1 | mysql -u root -p db2y dos veces entrará pase
hlcs
66
Dios, ¿podría alguien explicarme por qué una pregunta que dice "sin mysqldump" tiene como primera respuesta una que usa mysqldump? con como, 6 veces más votos que el correcto ? vamos, SO ...
Podría escribir una secuencia de comandos que tome la salida SHOW TABLESde una base de datos y copie el esquema en otra. Debería poder hacer referencia a nombres de esquema + tabla como:
CREATETABLE x LIKE other_db.y;
En lo que respecta a 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:
INSERTINTO x SELECT*FROM other_db.y;
Si está utilizando MyISAM, es mejor que copie los archivos de la tabla; Será mucho más rápido. Debería poder hacer lo mismo si está utilizando INNODB con espacios de tabla por tabla .
Si terminas haciendo un INSERT INTO SELECT, ¡asegúrate de desactivar temporalmente los índices con ALTER TABLE x DISABLE KEYS!
EDITAR Maatkit también tiene algunos scripts que pueden ser útiles para sincronizar datos. Puede que no sea más rápido, pero probablemente podría ejecutar sus scripts de sincronización en datos en vivo sin mucho bloqueo.
Intenté copiar los archivos de la tabla de una base de datos MyISAM una vez, pero eso solo dañó la nueva base de datos. Probablemente sea malo, pero definitivamente no es una operación tan trivial como algunos dicen que es.
Johan Fredrik Varen
2
Este es un buen truco y soy un fanático, pero una nota importante: esto no transfiere ninguna restricción de clave externa (incluso las que son externas al esquema que se está copiando) según los documentos de MySQL
abigperson
59
Si está utilizando Linux, puede usar este script bash: (tal vez necesite una limpieza adicional del código 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}forTABLEin`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
Si está utilizando el script anterior con tablas InnoDB y tiene claves foráneas, cambie la última línea a la siguiente:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
pegli
¿Esto también copia datos de restricción y otras propiedades de tablas?
Lucas Moeskops
1
Parece que sí, porque usa una instrucción "SHOW CREATE TABLE" que genera una CREATE TABLE con todas las propiedades del original.
Danita
1
Si tiene el problema que @zirael describió, probablemente se deba a que el script no puede copiar las vistas. Puede ignorar las vistas de la copia cambiando la SHOW TABLESlínea SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'y agregando | cut -f 1. La línea completa debería verse más o menos así, pero reemplace las líneas de retroceso dobles con líneas de fondo simples: 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
Limpié este script de @jozjan y apliqué algunos de los comentarios sobre claves externas y de otro tipo para crear esta versión en 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
Pero requiere la instalación de un paquete adicional:apt install mysql-utilities
Joel G Mathew
2
Pero no había ninguna restricción que dijera que eso no era posible ... y es algo que se instala comúnmente (pero opcional como usted dice) Si no está instalado, a muchos les resultaría más fácil instalar ese paquete que configurar y ejecutar un script Bash de 60 líneas , etc ....
furicle
Su publicación probablemente fue rechazada porque no incluyó ninguna otra información que no sea un enlace. Se supone que las respuestas son más completas.
Joel G Mathew
1
Realmente no sé qué quieres decir con "acceso local". Pero para esa solución, debe poder acceder a través del servidor ssh para copiar los archivos donde se almacena la base de datos .
No puedo usar mysqldump, porque mi base de datos es grande (7Go, mysqldump falla) Si la versión de la base de datos 2 mysql es demasiado diferente, puede que no funcione, puede verificar su versión de mysql usando mysql -V.
1) Copie los datos de su servidor remoto a su computadora local (vps es el alias de su servidor remoto, puede ser reemplazado por [email protected])
Esta es la forma más eficiente de hacerlo, pero creo que "sin acceso local al servidor" significa que no podemos acceder al sistema. Probablemente un alojamiento compartido? Entonces esta no es la respuesta.
Valerio Bozz
1
Todas las soluciones anteriores llegan al punto un poco, sin embargo, simplemente no copian todo. Creé una función PHP (aunque algo larga) que copia todo, incluyendo tablas, claves foráneas, datos, vistas, procedimientos, funciones, disparadores 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 schemaif 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 ifany 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 tabletoaddforeignkeyandinsert 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 allforeign keys for a particular tablein 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 ifanyforeign keys were returned and recreates them in the new schema// Note:ONUPDATEandONDELETE 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 ifany views were returned and recreates them in the new schemaif(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 ifany triggers were returned and recreates them in the new schemaif(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 ifany procedures were returned and recreates them in the new schemaif(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 ifany functions were returned and recreates them in the new schemaif(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 ifany events were returned and recreates them in the new schemaif(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]));}}}
Votado negativamente porque la pregunta no es "no use mysqldump" sino "use un enfoque mejor que mysqldump". Esto es aún peor mysqldumpen términos de eficiencia.
Valerio Bozz
1
En realidad, quería lograr exactamente eso en PHP, pero ninguna de las respuestas aquí fue muy útil, así que aquí está mi solución, bastante sencilla, usando 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 tableand 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;
No estoy seguro de que haga un clon 1: 1, pero parece que para bases de datos simples podría ser suficiente.
beppe9000
Lo estoy usando para crear instalaciones rápidas de WordPress en mi servidor de desarrollo. Esta parte combinada con algunas otras rutinas duplica y ajusta una instalación de origen en un nuevo proyecto. Para eso funciona bien ... pero una base de datos en blanco de WordPress no es muy compleja, así que no puedo hacer una declaración para casos de uso más extendido
GDY
0
La mejor manera de clonar tablas de bases de datos sin mysqldump:
Crea una nueva base de datos.
Crear consultas de clonación con 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';
¡Ejecuta esa salida!
Pero tenga en cuenta que la secuencia de comandos anterior solo clona tablas rápidas , no vistas, disparadores y funciones de usuario: puede obtener una estructura rápida mysqldump --no-data --triggers -uroot -ppasswordy luego usar para clonar solo insertar instrucciones.
¿Por qué es una pregunta real? Debido a que la carga de mysqldumps es muy lenta si la DB supera los 2 Gb. Y no puede clonar tablas de InnoDB simplemente copiando archivos DB (como la copia de seguridad de instantáneas).
un SQL que muestra comandos SQL, debe ejecutarse para duplicar una base de datos de una base de datos a otra. para cada tabla se crea una declaración de tabla y una declaración de inserción. se supone que ambas bases de datos están en el mismo servidor:
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';
mysqldump
?CREATE TABLE t2 SELECT * FROM t1;
ya que perderá su información de índice, cualquier cosa especial como auto_increment, etc. muchos de los google para este tipo de tabla de copia lo llevarán a hacer esto y tendrá resultados no deseados .Respuestas:
Puedo ver 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 eso en mente, aquí hay una manera simple de duplicar una base de datos desde la línea de comandos de un servidor de Windows:db2
es la base de datos de destino, dondedb1
se copiará la base de datos de origen .mysqldump -h [server] -u [user] -p[password] db1 | mysql -h [server] -u [user] -p[password] db2
Nota: NO hay espacio entre
-p
y[password]
fuente
mysqldump -h [server] -u [user] -p db1 > db1
,mysql -h [server] -u [user] -p db2 < db1
el mensaje de contraseña lo estropea, al menos para mí cuando usa masilla.mysqldump -u root -p -v db1 | mysql -u root -p db2
y dos veces entrará pasePuede duplicar una tabla sin datos ejecutando:
(Consulte los documentos de MySQL CREATE TABLE )
Podría escribir una secuencia de comandos que tome la salida
SHOW TABLES
de una base de datos y copie el esquema en otra. Debería poder hacer referencia a nombres de esquema + tabla como:En lo que respecta a 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:
Si está utilizando MyISAM, es mejor que copie los archivos de la tabla; Será mucho más rápido. Debería poder hacer lo mismo si está utilizando INNODB con espacios de tabla por tabla .
Si terminas haciendo un
INSERT INTO SELECT
, ¡asegúrate de desactivar temporalmente los índices conALTER TABLE x DISABLE KEYS
!EDITAR Maatkit también tiene algunos scripts que pueden ser útiles para sincronizar datos. Puede que no sea más rápido, pero probablemente podría ejecutar sus scripts de sincronización en datos en vivo sin mucho bloqueo.
fuente
CREATE TABLE ... SELECT
.Si está utilizando Linux, puede usar este script bash: (tal vez necesite una limpieza adicional del código pero funciona ... y es mucho más rápido que mysqldump | mysql)
fuente
echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
SHOW TABLES
líneaSHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'
y agregando| cut -f 1
. La línea completa debería verse más o menos así, pero reemplace las líneas de retroceso dobles con líneas de fondo simples:for TABLE in ``echo "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" | mysql $DBCONN $DBSNAME | tail -n +2 | cut -f 1``; do
En PHP:
fuente
Tenga en cuenta que hay un comando mysqldbcopy como parte del complemento de las utilidades mysql ... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html
fuente
apt install mysql-utilities
Realmente no sé qué quieres decir con "acceso local". Pero para esa solución, debe poder acceder a través del servidor ssh para copiar los archivos donde se almacena la base de datos .
No puedo usar mysqldump, porque mi base de datos es grande (7Go, mysqldump falla) Si la versión de la base de datos 2 mysql es demasiado diferente, puede que no funcione, puede verificar su versión de mysql usando mysql -V.
1) Copie los datos de su servidor remoto a su computadora local (vps es el alias de su servidor remoto, puede ser reemplazado por [email protected])
2) Importe los datos copiados en su computadora local
Si tiene una versión diferente, es posible que deba ejecutar
fuente
Todas las soluciones anteriores llegan al punto un poco, sin embargo, simplemente no copian todo. Creé una función PHP (aunque algo larga) que copia todo, incluyendo tablas, claves foráneas, datos, vistas, procedimientos, funciones, disparadores y eventos. Aquí está el código:
fuente
mysqldump
en términos de eficiencia.En realidad, quería lograr exactamente eso en PHP, pero ninguna de las respuestas aquí fue muy útil, así que aquí está mi solución, bastante sencilla, usando MySQLi:
fuente
La mejor manera de clonar tablas de bases de datos sin mysqldump:
Crear consultas de clonación con consulta:
¡Ejecuta esa salida!
Pero tenga en cuenta que la secuencia de comandos anterior solo clona tablas rápidas , no vistas, disparadores y funciones de usuario: puede obtener una estructura rápida
mysqldump --no-data --triggers -uroot -ppassword
y luego usar para clonar solo insertar instrucciones.¿Por qué es una pregunta real? Debido a que la carga de mysqldumps es muy lenta si la DB supera los 2 Gb. Y no puede clonar tablas de InnoDB simplemente copiando archivos DB (como la copia de seguridad de instantáneas).
fuente
un SQL que muestra comandos SQL, debe ejecutarse para duplicar una base de datos de una base de datos a otra. para cada tabla se crea una declaración de tabla y una declaración de inserción. se supone que ambas bases de datos están en el mismo servidor:
fuente
Mysqldump no es una mala solución. La forma más simple de duplicar la base de datos:
mysqldump -uusername -ppass dbname1 | mysql -uusername -ppass dbname2
Además, puede cambiar el motor de almacenamiento de esta manera:
mysqldump -uusername -ppass dbname1 | sed 's/InnoDB/RocksDB/' | mysql -uusername -ppass dbname2
fuente