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?

Atualmente, estou usando o MySQL 4.0.

jhornnes
fonte
12
O que há de errado mysqldump?
Michael Mior 29/06
48
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:

  1. 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.
  2. Execute a seguinte instrução em uma linha de comandos:

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

Nota: NÃO há espaço entre -pe[password]

Rafe
fonte
108
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:

CREATE TABLE x LIKE y;

(Veja os documentos do MySQL CREATE TABLE )

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:

CREATE TABLE 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:

INSERT INTO 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.

Gary Richardson
fonte
1
é este trabalho para tabela duplicada? desde que eu vejo o comando é criar tabela
GusDeCooL
4
Você pode fazer CREATE TABLE ... SELECT.
eggyal 6/09/12
3
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}
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
fonte
7
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
mr_app
fonte
Se você estiver trabalhando na máquina Windows. Em seguida, use isso em vez de encontrar maneiras longas de executar o comando.
Parixit
este script não tomar pontos de vista em contagem
sd1sd1
4

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

furicle
fonte
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])

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) Importe os dados copiados no seu computador 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

Se você tem uma versão diferente, pode ser necessário executar

/etc/init.d/mysql stop
mysql_upgrade -u root -pPASSWORD --force #that step took almost 1hrs
/etc/init.d/mysql start
Remy Mellet
fonte
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 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
fonte
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 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
fonte
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:

  1. Crie um novo banco de dados.
  2. 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';
  3. 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).

Alexander Goncharov
fonte
0

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';
Shimon Doodkin
fonte
-1

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

Andy Al
fonte