Pergunta

Eu gostaria de escrever um script que copia o meu sitedb1 banco de dados atual para sitedb2 na mesma instância de banco de dados mysql. Eu sei que posso despejar o sitedb1 a um script sql:

mysqldump -u root -p sitedb1 >~/db_name.sql

e, em seguida, importá-lo para sitedb2. Existe uma maneira mais fácil, sem despejar o primeiro banco de dados para um arquivo sql?

Foi útil?

Solução

Como o manual diz em Copiando bancos de dados você tubo de lata o despejo diretamente no cliente mysql:

mysqldump db_name | mysql new_db_name

Se você estiver usando MyISAM você pode copiar os arquivos, mas eu não recomendo. É um pouco duvidosos.

Integrado de vários bons outras respostas

Ambos os comandos mysqldump e mysql aceitar opções para definir detalhes da ligação (e muito mais), como:

mysqldump -u <user name> --password=<pwd> <original db> | mysql -u <user name> -p <new db>

Além disso, se o novo banco de dados não está existindo, no entanto, você tem que criá-lo com antecedência (por exemplo, com echo "create database new_db_name" | mysql -u <dbuser> -p).

Outras dicas

Usando MySQL Utilities

Os Utilities MySQL conter a boa ferramenta mysqldbcopy que por cópias padrão de um DB incluindo todos os objetos relacionados ( “tabelas, views, triggers, eventos, procedimentos, funções e subsídios em nível de banco de dados”) e os dados de um servidor de banco de dados para o mesmo ou para outro servidor de DB. Há muitas opções disponíveis para personalizar o que realmente está copiado.

Assim, para responder à pergunta do OP:

mysqldbcopy \
    --source=root:your_password@localhost \
    --destination=root:your_password@localhost \
    sitedb1:sitedb2
$ mysqladmin create DB_name -u DB_user --password=DB_pass && \
    mysqldump -u DB_user --password=DB_pass DB_name | mysql -u DB_user --password=DB_pass -h DB_host DB_name

Você precisa executar o comando do terminal / prompt de comando.

mysqldump -u <user name> -p <pwd> <original db> | mysql -u <user name> <pwd> <new db>

por exemplo: mysqldump -u root test_db1 | mysql -u root test_db2

Esta cópias test_db1 para test_db2 e conceder o acesso ao 'root' @ 'localhost'

Best e fácil maneira é entrar nesses comandos em suas permissões de terminais e definido para o usuário root. Funciona para mim..!

:~$> mysqldump -u root -p db1 > dump.sql
:~$> mysqladmin -u root -p create db2
:~$> mysql -u root -p db2 < dump.sql

Você pode usar (em pseudocódigo):

FOREACH tbl IN db_a:
    CREATE TABLE db_b.tbl LIKE db_a.tbl;
    INSERT INTO db_b.tbl SELECT * FROM db_a.tbl;

A razão que eu não estou usando o CREATE TABLE ... SELECT ... sintaxe é preservar índices. Claro que isso só copia tabelas. Exibições e procedimentos não são copiadas, embora possa ser feito da mesma maneira.

CREATE TABLE .

Primeiro, crie o banco de dados duplicado:

CREATE DATABASE duplicateddb;

Certifique-se as permissões etc estão todos no lugar e:

mysqldump -u admin -p originaldb | mysql -u backup -p password duplicateddb;

Você pode fazer algo como o seguinte:

mysqldump -u[username] -p[password] database_name_for_clone 
 | mysql -u[username] -p[password] new_database_name

Esta declaração foi adicionada no MySQL 5.1.7, mas foi encontrado para ser perigoso e foi removido no MySQL 5.1.23. Foi destinado a permitir a modernização pré-5.1 bancos de dados para usar a codificação implementado em 5.1 para nomes de banco de dados de mapeamento para nomes de diretório de banco de dados. No entanto, o uso desta declaração pode resultar em perda de conteúdo banco de dados, razão pela qual ele foi removido. Não use RENAME DATABASE em versões anteriores em que está presente.

Para executar a tarefa de nomes de banco de dados atualização com a nova codificação, utilize ALTER DATABASE db_name UPGRADE dados do diretório NOME vez: http://dev.mysql.com/doc/refman/5.1/en/alter-database.html

Uma maneira simples de fazê-lo se você tiver instalado phpMyAdmin :

Vá para o seu banco de dados, selecione a guia "operação", e você pode ver o "banco de dados de cópia para" bloco. Use-o e você pode copiar o banco de dados.

Além de Greg resposta , esta é a maneira mais fácil e mais rápido se o new_db_name ainda não existe:

echo "create database new_db_name" | mysql -u <user> -p <pwd> 
mysqldump -u <user> -p <pwd> db_name | mysql -u <user> -p <pwd> new_db_name

Se você tem gatilhos em seu banco de dados original, você pode evitar o "Trigger já existe" erro canalizando um substituto antes da importação:

mysqldump -u olddbuser -p -d olddbname | sed "s/`olddbname`./`newdbname`./" | mysql -u newdbuser -p -D newdbname

Conforme mencionado na de Greg resposta , mysqldump db_name | mysql new_db_name é a livre seguro e fácil maneira, para transferir dados entre os bancos de dados. No entanto, também é muito lento .

Se você estiver olhando para os dados de backup, não pode dar ao luxo de perder dados (neste ou outros bancos de dados), ou se estiver usando diferentes innodb tabelas, então você deve usar mysqldump.

Se você está procurando algo para o desenvolvimento, tem todos os seus bancos de dados de backup em outro lugar, e são purga confortável e mysql reinstalar (possivelmente manualmente) quando tudo der errado, então eu só poderia ter a solução para você.

Eu não poderia encontrar uma boa alternativa, assim que eu construí um script para fazer isso sozinho. Passei muito de tempo começar este trabalho pela primeira vez e honestamente me assusta um pouco para fazer alterações agora. bancos de dados InnoDB não foram feitos para copiado e colado assim. Pequenas mudanças causar esta a falhar de forma magnífica. Eu não tive um problema desde que eu finalizado o código, mas isso não significa que você não vai.

Sistemas testado em (mas ainda pode falhar em):

  • Ubuntu 16.04, mysql padrão, InnoDB, arquivos separados por tabela
  • Ubuntu 18.04, mysql padrão, InnoDB, arquivos separados por tabela

O que ele faz

  1. Obtém privilégio sudo e verifica que você tem espaço de armazenamento suficiente para clonar o banco de dados
  2. Obtém privilégios mysql root
  3. Cria um novo banco de dados nomeado após o git branch atual
  4. estrutura Clones a nova base de dados
  5. muda para o modo de recuperação para innodb
  6. dados padrão Exclui em novo banco de dados
  7. Pára mysql
  8. Dados clones para novo banco de dados
  9. Inicia mysql
  10. Data Links importados no novo banco de dados
  11. Muda do modo de recuperação para innodb
  12. Reinicia mysql
  13. Dá acesso do usuário mysql para banco de dados
  14. Limpa arquivos temporários

Como ele se compara com mysqldump

Em um banco de dados de 3GB, usando mysqldump e mysql levaria 40-50 minutos na minha máquina. Usando este método, o mesmo processo levaria apenas ~ 8 minutos.

Como podemos usá-lo

Nós temos nossa SQL alterações salvas junto com o nosso código e o processo de atualização é automatizado na produção e desenvolvimento, com cada conjunto de mudanças que fazem um backup do banco de dados para restaurar se há erros. Um problema que tive foi quando estávamos trabalhando em um projeto de longo prazo com mudanças de banco de dados, e teve que ramos interruptor no meio dela para corrigir um bug ou três.

No passado, foi utilizado um único banco de dados para todos os ramos, e teria de reconstruir o banco de dados sempre que nós mudamos para um ramo que não era compatível com as novas alterações de banco de dados. E quando voltou, teríamos de executar as atualizações novamente.

Nós tentamos mysqldump para duplicar a base de dados para diferentes ramos, mas o tempo de espera foi muito tempo (40-50 minutos), e nós não poderíamos fazer qualquer outra coisa nesse meio tempo.

Esta solução reduziu o tempo clone banco de dados para 1/5 o tempo (pense café e casa de banho pausa em vez de um longo almoço).

Tarefas comuns e seu tempo

A comutação entre filiais com alterações de dados incompatíveis leva 50+ minutos em um único banco de dados, mas pouco tempo depois do tempo de configuração inicial com mysqldump ou este código. Este código só acontece de ser ~ 5 vezes mais rápido que mysqldump.

Aqui estão algumas tarefas comuns e cerca de quanto tempo eles levariam com cada método:

Criar ramo de funcionalidade com alterações de dados e mesclar imediatamente:

  • banco de dados único: ~ 5 minutos
  • Clone com mysqldump: 50-60 minutos
  • Clone com este código: ~ 18 minutos

Criar ramo de funcionalidade com alterações de dados, mude para master parauma correção de bug fazer uma edição no ramo de funcionalidade, e merge:

  • banco de dados único: ~ 60 minutos
  • Clone com mysqldump: 50-60 minutos
  • Clone com este código: ~ 18 minutos

Criar ramo de funcionalidade com alterações de dados, mude para master para um bugfix 5 vezes ao fazer edições no inbetween recurso ramo, e merge:

  • banco de dados único: ~ 4 horas, 40 minutos
  • Clone com mysqldump: 50-60 minutos
  • Clone com este código: ~ 18 minutos

O código

Não use este a menos que você leu e entendeu tudo acima.

#!/bin/bash
set -e

# This script taken from: https://stackoverflow.com/a/57528198/526741

function now {
    date "+%H:%M:%S";
}

# Leading space sets messages off from step progress.
echosuccess () {
    printf "\e[0;32m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echowarn () {
    printf "\e[0;33m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echoerror () {
    printf "\e[0;31m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echonotice () {
    printf "\e[0;94m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echoinstructions () {
    printf "\e[0;104m %s: %s\e[0m\n" "$(now)" "$1"
    sleep .1
}
echostep () {
    printf "\e[0;90mStep %s of 13:\e[0m\n" "$1"
    sleep .1
}

MYSQL_CNF_PATH='/etc/mysql/mysql.conf.d/recovery.cnf'
OLD_DB='YOUR_DATABASE_NAME'
USER='YOUR_MYSQL_USER'

# You can change NEW_DB to whatever you like
# Right now, it will append the current git branch name to the existing database name
BRANCH=`git rev-parse --abbrev-ref HEAD`
NEW_DB="${OLD_DB}__$BRANCH"

THIS_DIR=./site/upgrades
DB_CREATED=false

tmp_file () {
    printf "$THIS_DIR/$NEW_DB.%s" "$1"
}
sql_on_new_db () {
    mysql $NEW_DB --unbuffered --skip-column-names -u root -p$PASS 2>> $(tmp_file 'errors.log')
}

general_cleanup () {
    echoinstructions 'Leave this running while things are cleaned up...'

    if [ -f $(tmp_file 'errors.log') ]; then
        echowarn 'Additional warnings and errors:'
        cat $(tmp_file 'errors.log')
    fi

    for f in $THIS_DIR/$NEW_DB.*; do
        echonotice 'Deleting temporary files created for transfer...'
        rm -f $THIS_DIR/$NEW_DB.*
        break
    done

    echonotice 'Done!'
    echoinstructions "You can close this now :)"
}

error_cleanup () {
    exitcode=$?

    # Just in case script was exited while in a prompt
    echo

    if [ "$exitcode" == "0" ]; then
        echoerror "Script exited prematurely, but exit code was '0'."
    fi

    echoerror "The following command on line ${BASH_LINENO[0]} exited with code $exitcode:"
    echo "             $BASH_COMMAND"

    if [ "$DB_CREATED" = true ]; then
        echo
        echonotice "Dropping database \`$NEW_DB\` if created..."
        echo "DROP DATABASE \`$NEW_DB\`;" | sql_on_new_db || echoerror "Could not drop database \`$NEW_DB\` (see warnings)"
    fi

    general_cleanup

    exit $exitcode
}

trap error_cleanup EXIT

mysql_path () {
    printf "/var/lib/mysql/"
}
old_db_path () {
    printf "%s%s/" "$(mysql_path)" "$OLD_DB"
}
new_db_path () {
    printf "%s%s/" "$(mysql_path)" "$NEW_DB"
}
get_tables () {
    (sudo find /var/lib/mysql/$OLD_DB -name "*.frm" -printf "%f\n") | cut -d'.' -f1 | sort
}

STEP=0


authenticate () {
    printf "\e[0;104m"
    sudo ls &> /dev/null
    printf "\e[0m"
    echonotice 'Authenticated.'
}
echostep $((++STEP))
authenticate

TABLE_COUNT=`get_tables | wc -l`
SPACE_AVAIL=`df -k --output=avail $(mysql_path) | tail -n1`
SPACE_NEEDED=(`sudo du -s $(old_db_path)`)
SPACE_ERR=`echo "$SPACE_AVAIL-$SPACE_NEEDED" | bc`
SPACE_WARN=`echo "$SPACE_AVAIL-$SPACE_NEEDED*3" | bc`
if [ $SPACE_ERR -lt 0 ]; then
    echoerror 'There is not enough space to branch the database.'
    echoerror 'Please free up some space and run this command again.'
    SPACE_AVAIL_FORMATTED=`printf "%'d" $SPACE_AVAIL`
    SPACE_NEEDED_FORMATTED=`printf "%'${#SPACE_AVAIL_FORMATTED}d" $SPACE_NEEDED`
    echonotice "$SPACE_NEEDED_FORMATTED bytes needed to create database branch"
    echonotice "$SPACE_AVAIL_FORMATTED bytes currently free"
    exit 1
elif [ $SPACE_WARN -lt 0 ]; then
    echowarn 'This action will use more than 1/3 of your available space.'
    SPACE_AVAIL_FORMATTED=`printf "%'d" $SPACE_AVAIL`
    SPACE_NEEDED_FORMATTED=`printf "%'${#SPACE_AVAIL_FORMATTED}d" $SPACE_NEEDED`
    echonotice "$SPACE_NEEDED_FORMATTED bytes needed to create database branch"
    echonotice "$SPACE_AVAIL_FORMATTED bytes currently free"
    printf "\e[0;104m"
    read -p " $(now): Do you still want to branch the database? [y/n] " -n 1 -r CONFIRM
    printf "\e[0m"
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
        echonotice 'Database was NOT branched'
        exit 1
    fi
fi

PASS='badpass'
connect_to_db () {
    printf "\e[0;104m %s: MySQL root password: \e[0m" "$(now)"
    read -s PASS
    PASS=${PASS:-badpass}
    echo
    echonotice "Connecting to MySQL..."
}
create_db () {
    echonotice 'Creating empty database...'
    echo "CREATE DATABASE \`$NEW_DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" | mysql -u root -p$PASS 2>> $(tmp_file 'errors.log')
    DB_CREATED=true
}
build_tables () {
    echonotice 'Retrieving and building database structure...'
    mysqldump $OLD_DB --skip-comments -d -u root -p$PASS 2>> $(tmp_file 'errors.log') | pv --width 80  --name " $(now)" > $(tmp_file 'dump.sql')
    pv --width 80  --name " $(now)" $(tmp_file 'dump.sql') | sql_on_new_db
}
set_debug_1 () {
    echonotice 'Switching into recovery mode for innodb...'
    printf '[mysqld]\ninnodb_file_per_table = 1\ninnodb_force_recovery = 1\n' | sudo tee $MYSQL_CNF_PATH > /dev/null
}
set_debug_0 () {
    echonotice 'Switching out of recovery mode for innodb...'
    sudo rm -f $MYSQL_CNF_PATH
}
discard_tablespace () {
    echonotice 'Unlinking default data...'
    (
        echo "USE \`$NEW_DB\`;"
        echo "SET foreign_key_checks = 0;"
        get_tables | while read -r line;
            do echo "ALTER TABLE \`$line\` DISCARD TABLESPACE; SELECT 'Table \`$line\` imported.';";
        done
        echo "SET foreign_key_checks = 1;"
    ) > $(tmp_file 'discard_tablespace.sql')
    cat $(tmp_file 'discard_tablespace.sql') | sql_on_new_db | pv --width 80 --line-mode --size $TABLE_COUNT --name " $(now)" > /dev/null
}
import_tablespace () {
    echonotice 'Linking imported data...'
    (
        echo "USE \`$NEW_DB\`;"
        echo "SET foreign_key_checks = 0;"
        get_tables | while read -r line;
            do echo "ALTER TABLE \`$line\` IMPORT TABLESPACE; SELECT 'Table \`$line\` imported.';";
        done
        echo "SET foreign_key_checks = 1;"
    ) > $(tmp_file 'import_tablespace.sql')
    cat $(tmp_file 'import_tablespace.sql') | sql_on_new_db | pv --width 80 --line-mode --size $TABLE_COUNT --name " $(now)" > /dev/null
}
stop_mysql () {
    echonotice 'Stopping MySQL...'
    sudo /etc/init.d/mysql stop >> $(tmp_file 'log')
}
start_mysql () {
    echonotice 'Starting MySQL...'
    sudo /etc/init.d/mysql start >> $(tmp_file 'log')
}
restart_mysql () {
    echonotice 'Restarting MySQL...'
    sudo /etc/init.d/mysql restart >> $(tmp_file 'log')
}
copy_data () {
    echonotice 'Copying data...'
    sudo rm -f $(new_db_path)*.ibd
    sudo rsync -ah --info=progress2 $(old_db_path) --include '*.ibd' --exclude '*' $(new_db_path)
}
give_access () {
    echonotice "Giving MySQL user \`$USER\` access to database \`$NEW_DB\`"
    echo "GRANT ALL PRIVILEGES ON \`$NEW_DB\`.* to $USER@localhost" | sql_on_new_db
}

echostep $((++STEP))
connect_to_db

EXISTING_TABLE=`echo "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$NEW_DB'" | mysql --skip-column-names -u root -p$PASS 2>> $(tmp_file 'errors.log')`
if [ "$EXISTING_TABLE" == "$NEW_DB" ]
    then
        echoerror "Database \`$NEW_DB\` already exists"
        exit 1
fi

echoinstructions "The hamsters are working. Check back in 5-10 minutes."
sleep 5

echostep $((++STEP))
create_db
echostep $((++STEP))
build_tables
echostep $((++STEP))
set_debug_1
echostep $((++STEP))
discard_tablespace
echostep $((++STEP))
stop_mysql
echostep $((++STEP))
copy_data
echostep $((++STEP))
start_mysql
echostep $((++STEP))
import_tablespace
echostep $((++STEP))
set_debug_0
echostep $((++STEP))
restart_mysql
echostep $((++STEP))
give_access

echo
echosuccess "Database \`$NEW_DB\` is ready to use."
echo

trap general_cleanup EXIT

Se tudo correr bem, você deve ver algo como:

Captura de tela de saída do script, por exemplo, banco de dados

Eu não acho que há um método para fazer isso. Quando PHPMyAdmin faz isso, ele despeja a DB, em seguida, re-inserções lo sob o novo nome.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top