Copiar / duplicar banco de dados sem usar o mysqldump
427
Sem acesso local ao servidor, existe alguma maneira de duplicar / clonar um banco de dados MySQL (com conteúdo e sem conteúdo) em outro sem usar mysqldump?
Certifique-se de não fazer isso: CREATE TABLE t2 SELECT * FROM t1;como você perderá suas informações de índice, qualquer material especial, como auto_increment etc. .
John Hunt
59
Uma pergunta fora do tópico recebe 92 votos positivos e 37 favoritos. Polegares para cima para essa pergunta fora de tópico. Diretrizes desatualizadas.
pal4life
25
100% concordam que o tópico "fechado como desligado" está errado e que as linhas da guilda devem ser atualizadas - é necessária mais clareza - O SO está indo na direção errada. É óbvio que @will está completamente errado e deve ter seus privilégios de moderador removidos - essa pergunta única é prova suficiente.
Stolsvik 09/04
10
Fechado como fora do tópico está 100% errado. Esta é a pergunta exata que tenho e tem uma resposta técnica bem definida que não se relaciona com mera opinião. Eu acho que o moderador deve ter procurado palavras como "melhor" para encontrar perguntas para fechar.
Sam Goldberg
Respostas:
686
Percebo que você disse que não queria usá-lo mysqldump, mas cheguei a esta página enquanto procurava uma solução semelhante e outras pessoas também a poderiam encontrar. Com isso em mente, aqui está uma maneira simples de duplicar um banco de dados da linha de comando de um servidor Windows:
Crie o banco de dados de destino usando o MySQLAdmin ou seu método preferido. Neste exemplo, db2é o banco de dados de destino, onde o banco de dados de origem db1será copiado.
Execute a seguinte instrução em uma linha de comandos:
O caso contra o mysqldump é que deve haver uma maneira mais rápida de serializar os dados em consultas, transmitindo as consultas fora do processo e através do tty de volta ao mesmo processo , reparando as consultas e executando-as como instruções. Isso soa terrivelmente ineficiente e desnecessário . Não estamos falando sobre o cruzamento entre mestres do MySQL ou a alteração de mecanismos de armazenamento. É chocante que não haja transferência binária intraprocesso eficiente.
Toddius Zho
42
Se você não quiser salvar o texto sem formatação da senha no histórico de seus terminais, precisará dividir o comando :, Caso contrário mysqldump -h [server] -u [user] -p db1 > db1, mysql -h [server] -u [user] -p db2 < db1o prompt de senha estragará tudo, pelo menos para mim ao usar o putty.
Kapex
5
usando mysqldump e mysql do bash torna-se muito mais simples se você configurar você .my.cnf arquivo para armazenar os arquivos de usuário / host / senha
ErichBSchulz
4
mysqldump -u root -p -v db1 | mysql -u root -p db2e duas vezes digite pass
hlcs
6
Deus, alguém poderia me explicar por que uma pergunta afirmando "sem mysqldump" tem como primeira resposta uma que usa mysqldump? com sim, 6x mais votos do que o correto ?
Vamos lá
135
Você pode duplicar uma tabela sem dados executando:
Você pode escrever um script que retire a saída SHOW TABLESde um banco de dados e copie o esquema para outro. Você deve poder referenciar nomes de esquema + tabela como:
CREATETABLE x LIKE other_db.y;
Quanto aos dados, você também pode fazê-lo no MySQL, mas não é necessariamente rápido. Depois de criar as referências, você pode executar o seguinte para copiar os dados:
INSERTINTO x SELECT*FROM other_db.y;
Se você estiver usando o MyISAM, é melhor copiar os arquivos da tabela; será muito mais rápido. Você poderá fazer o mesmo se estiver usando o INNODB com espaços de tabela por tabela .
Se você acabar fazendo um INSERT INTO SELECT, certifique- se de desativar temporariamente os índices com ALTER TABLE x DISABLE KEYS!
O EDIT Maatkit também possui alguns scripts que podem ser úteis para sincronizar dados. Pode não ser mais rápido, mas você provavelmente pode executar os scripts de sincronização em dados ativos sem muito bloqueio.
Tentei copiar os arquivos da tabela de um banco de dados MyISAM uma vez, mas isso apenas corrompeu o novo banco de dados. Provavelmente é ruim, mas definitivamente não é uma operação tão trivial quanto alguns dizem que é.
Johan Fredrik Varen
2
Este é um truque legal e sou um fã, mas uma observação importante: isso não carrega nenhuma restrição de chave estrangeira (mesmo as externas ao esquema que está sendo copiado) de acordo com o MySQL Docs
abigperson
59
Se você estiver usando Linux, poderá usar este script bash: (talvez precise de alguma limpeza adicional de código, mas funciona ... e é muito mais rápido que o 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
Se você estiver usando o script acima com tabelas do InnoDB e tiver chaves estrangeiras, altere a última linha para o seguinte:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
pegli
Isso também copia dados de restrição e outras propriedades de tabelas?
Lucas Moeskops
1
Parece que sim, porque ele usa uma instrução "SHOW CREATE TABLE" que gera uma CREATE TABLE com todas as propriedades do original.
Danita
1
Se você encontrar o problema, o @zirael descreveu provavelmente porque o script não conseguiu copiar as visualizações. Você pode ignorar as vistas da cópia alterando a SHOW TABLESlinha SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'e adicionando | cut -f 1. A linha completa deve ser algo como isto, mas substituir os acentos graves duplos com acentos graves individuais: for TABLE in ``echo "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" | mysql $DBCONN $DBSNAME | tail -n +2 | cut -f 1``; do
Código Commander
1
Eu limpo-up esse script @jozjan e aplicados alguns dos comentários sobre as chaves estrangeiras e outros para criar esta versão no GIST gist.github.com/christopher-hopper/8431737
Christopher
11
Em 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
Mas isso requer a instalação de um pacote adicional:apt install mysql-utilities
Joel G Mathew
2
Mas não havia nenhuma restrição dizendo que isso não era possível ... e é uma coisa comumente instalada (mas opcional como você diz) Se não estiver instalado, muitos acharão mais fácil instalar esse pacote do que configurar e executar um script Bash de 60 linhas , etc ...
furicle 18/09/18
Sua postagem provavelmente foi rejeitada porque você não incluiu outras informações além de um link. As respostas devem ser mais abrangentes.
Joel G Mathew
1
Eu realmente não sei o que você quer dizer com "acesso local". Porém, para essa solução, você precisa acessar o servidor ssh para copiar os arquivos em que o banco de dados está armazenado .
Não consigo usar o mysqldump, porque meu banco de dados é grande (7Go, falha do mysqldump) Se a versão do banco de dados 2 mysql for muito diferente, pode não funcionar, você pode verificar sua versão do mysql usando o mysql -V.
1) Copie os dados do servidor remoto para o computador local (vps é o alias do servidor remoto, pode ser substituído por [email protected])
Essa é a maneira mais eficiente de fazer isso, mas acho que "sem acesso local ao servidor" significa que não podemos acessar o sistema. Provavelmente uma hospedagem compartilhada? Portanto, essa não é a resposta.
Valerio Bozz 12/09
1
Todas as soluções anteriores chegam um pouco ao ponto, no entanto, simplesmente não copiam tudo. Eu criei uma função PHP (ainda que um pouco demorada) que copia tudo, incluindo tabelas, chaves estrangeiras, dados, visualizações, procedimentos, funções, gatilhos e eventos. Aqui está o 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]));}}}
Voto negativo porque a pergunta não é "não use o mysqldump", mas "use uma abordagem melhor que o mysqldump". Isso é ainda pior mysqldumpem termos de eficiência.
Valerio Bozz 12/09
1
Na verdade, eu queria conseguir exatamente isso no PHP, mas nenhuma das respostas aqui foi muito útil, então aqui está minha - bastante direta - solução usando o 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;
Não tenho certeza se isso cria um clone 1: 1, mas parece que bancos de dados simples podem ser suficientes.
beppe9000 18/03
Estou usando isso para criar instalações rápidas do WordPress no meu servidor de desenvolvimento. Esta parte emparelhada com outras rotinas duplicam e ajustam uma instalação de origem em um novo projeto. Por isso, funciona muito bem ... mas um banco de dados wordpress em branco não é muito complexo, então não posso fazer uma declaração para casos de uso mais estendidos
GDY
0
A melhor maneira de clonar tabelas de banco de dados sem o mysqldump:
Crie um novo banco de dados.
Crie consultas de clone com a 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';
Execute essa saída!
Mas observe, o script acima apenas clona tabelas rapidamente - não exibições, gatilhos e funções do usuário: você pode obter rapidamente a estrutura mysqldump --no-data --triggers -uroot -ppassworde, em seguida, usar para clonar apenas a instrução insert.
Por que é uma pergunta real? Porque o upload do mysqldumps é muito lento se o DB tiver mais de 2 GB. E você não pode clonar tabelas do InnoDB apenas copiando arquivos de banco de dados (como backup de instantâneo).
um SQL que mostra comandos SQL, precisa executar para duplicar um banco de dados de um banco de dados para outro. para cada tabela, é criada uma instrução de tabela e uma instrução de inserção. assume que os dois bancos de dados estão no mesmo 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;
como você perderá suas informações de índice, qualquer material especial, como auto_increment etc. .Respostas:
Percebo que você disse que não queria usá-lo
mysqldump
, mas cheguei a esta página enquanto procurava uma solução semelhante e outras pessoas também a poderiam encontrar. Com isso em mente, aqui está uma maneira simples de duplicar um banco de dados da linha de comando de um servidor Windows:db2
é o banco de dados de destino, onde o banco de dados de origemdb1
será copiado.mysqldump -h [server] -u [user] -p[password] db1 | mysql -h [server] -u [user] -p[password] db2
Nota: NÃO há espaço entre
-p
e[password]
fonte
mysqldump -h [server] -u [user] -p db1 > db1
,mysql -h [server] -u [user] -p db2 < db1
o prompt de senha estragará tudo, pelo menos para mim ao usar o putty.mysqldump -u root -p -v db1 | mysql -u root -p db2
e duas vezes digite passVocê pode duplicar uma tabela sem dados executando:
(Veja os documentos do MySQL CREATE TABLE )
Você pode escrever um script que retire a saída
SHOW TABLES
de um banco de dados e copie o esquema para outro. Você deve poder referenciar nomes de esquema + tabela como:Quanto aos dados, você também pode fazê-lo no MySQL, mas não é necessariamente rápido. Depois de criar as referências, você pode executar o seguinte para copiar os dados:
Se você estiver usando o MyISAM, é melhor copiar os arquivos da tabela; será muito mais rápido. Você poderá fazer o mesmo se estiver usando o INNODB com espaços de tabela por tabela .
Se você acabar fazendo um
INSERT INTO SELECT
, certifique- se de desativar temporariamente os índices comALTER TABLE x DISABLE KEYS
!O EDIT Maatkit também possui alguns scripts que podem ser úteis para sincronizar dados. Pode não ser mais rápido, mas você provavelmente pode executar os scripts de sincronização em dados ativos sem muito bloqueio.
fonte
CREATE TABLE ... SELECT
.Se você estiver usando Linux, poderá usar este script bash: (talvez precise de alguma limpeza adicional de código, mas funciona ... e é muito mais rápido que o mysqldump | mysql)
fonte
echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
SHOW TABLES
linhaSHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'
e adicionando| cut -f 1
. A linha completa deve ser algo como isto, mas substituir os acentos graves duplos com acentos graves individuais:for TABLE in ``echo "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" | mysql $DBCONN $DBSNAME | tail -n +2 | cut -f 1``; do
Em PHP:
fonte
Observe que há um comando mysqldbcopy como parte do utilitário add on mysql .... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html
fonte
apt install mysql-utilities
Eu realmente não sei o que você quer dizer com "acesso local". Porém, para essa solução, você precisa acessar o servidor ssh para copiar os arquivos em que o banco de dados está armazenado .
Não consigo usar o mysqldump, porque meu banco de dados é grande (7Go, falha do mysqldump) Se a versão do banco de dados 2 mysql for muito diferente, pode não funcionar, você pode verificar sua versão do mysql usando o mysql -V.
1) Copie os dados do servidor remoto para o computador local (vps é o alias do servidor remoto, pode ser substituído por [email protected])
2) Importe os dados copiados no seu computador local
Se você tem uma versão diferente, pode ser necessário executar
fonte
Todas as soluções anteriores chegam um pouco ao ponto, no entanto, simplesmente não copiam tudo. Eu criei uma função PHP (ainda que um pouco demorada) que copia tudo, incluindo tabelas, chaves estrangeiras, dados, visualizações, procedimentos, funções, gatilhos e eventos. Aqui está o código:
fonte
mysqldump
em termos de eficiência.Na verdade, eu queria conseguir exatamente isso no PHP, mas nenhuma das respostas aqui foi muito útil, então aqui está minha - bastante direta - solução usando o MySQLi:
fonte
A melhor maneira de clonar tabelas de banco de dados sem o mysqldump:
Crie consultas de clone com a consulta:
Execute essa saída!
Mas observe, o script acima apenas clona tabelas rapidamente - não exibições, gatilhos e funções do usuário: você pode obter rapidamente a estrutura
mysqldump --no-data --triggers -uroot -ppassword
e, em seguida, usar para clonar apenas a instrução insert.Por que é uma pergunta real? Porque o upload do mysqldumps é muito lento se o DB tiver mais de 2 GB. E você não pode clonar tabelas do InnoDB apenas copiando arquivos de banco de dados (como backup de instantâneo).
fonte
um SQL que mostra comandos SQL, precisa executar para duplicar um banco de dados de um banco de dados para outro. para cada tabela, é criada uma instrução de tabela e uma instrução de inserção. assume que os dois bancos de dados estão no mesmo servidor:
fonte
Mysqldump não é uma solução ruim. Maneira mais simples de duplicar o banco de dados:
mysqldump -uusername -ppass dbname1 | mysql -uusername -ppass dbname2
Além disso, você pode alterar o mecanismo de armazenamento desta maneira:
mysqldump -uusername -ppass dbname1 | sed 's/InnoDB/RocksDB/' | mysql -uusername -ppass dbname2
fonte