web-dev-qa-db-ja.com

同じMySqlインスタンスでMySQLデータベースを複製する

同じmysqlデータベースインスタンスで現在のデータベースsitedb1sitedb2にコピーするスクリプトを作成したいと思います。私は、sitedb1をsqlスクリプトにダンプできることを知っています。

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

そしてそれをsitedb2にインポートします。最初のデータベースをSQLファイルにダンプせずに、簡単な方法はありますか?

114
uclajatt

マニュアルで データベースのコピー にあるように、mysqlクライアントに直接ダンプをパイプできます:

mysqldump db_name | mysql new_db_name

MyISAMを使用している場合は、ファイルをコピーできますが、お勧めしません。それは少し危険です。

さまざまな他の良い答えから統合された

mysqldumpmysqlの両方のコマンドは、次のような接続詳細(およびその他)を設定するためのオプションを受け入れます。

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

また、新しいデータベースがまだ存在しない場合は、事前に作成する必要があります(例:echo "create database new_db_name" | mysql -u <dbuser> -p)。

235
Greg

MySQLユーティリティの使用

MySQLユーティリティには、ニースツール mysqldbcopy が含まれています。これは、デフォルトで、関連するすべてのオブジェクト(「テーブル、ビュー、トリガー、イベント、プロシージャ、関数、データベースレベルの許可」)と1つのデータを含むDBをコピーします同じまたは別のDBサーバーへのDBサーバー。実際にコピーされるものをカスタマイズするために利用できる多くのオプションがあります。

したがって、OPの質問に答えるには:

mysqldbcopy \
    --source=root:your_password@localhost \
    --destination=root:your_password@localhost \
    sitedb1:sitedb2
59
Chriki
$ 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
18
Peru

端末/コマンドプロンプトからコマンドを実行する必要があります。

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

例:mysqldump -u root test_db1 | mysql -u root test_db2

これにより、test_db1がtest_db2にコピーされ、 'root' @ 'localhost'へのアクセスが許可されます。

12
Srikanth Gurram

最良かつ簡単な方法は、これらのコマンドを端末に入力し、rootユーザーにアクセス許可を設定することです。私のために働く..!

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

あなたは(擬似コードで)使用することができます:

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

CREATE TABLE ... SELECT ...構文を使用していない理由は、インデックスを保持するためです。もちろん、これはテーブルのみをコピーします。ビューと手順はコピーされませんが、同じ方法で実行できます。

CREATE TABLE を参照してください。

8
Emil H

最初に複製データベースを作成します。

CREATE DATABASE duplicateddb;

許可などがすべて整っていることを確認します。

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

次のようなことができます:

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

phpmyadminをインストールした場合の簡単な方法

データベースに移動し、「操作」タブを選択すると、「データベースのコピー先」ブロックが表示されます。それを使用すると、データベースをコピーできます。

1
fzyzcjy

このステートメントはMySQL 5.1.7で追加されましたが、危険であることが判明し、MySQL 5.1.23で削除されました。 5.1より前のデータベースをアップグレードして、データベース名をデータベースディレクトリ名にマッピングするために5.1で実装されたエンコーディングを使用できるようにすることを目的としました。ただし、このステートメントを使用すると、データベースの内容が失われる可能性があるため、削除されました。 RENAME DATABASEは、それが存在する以前のバージョンでは使用しないでください。

新しいエンコードでデータベース名をアップグレードするタスクを実行するには、代わりにALTER DATABASE db_name UPGRADE DATA DIRECTORY NAMEを使用します。 http://dev.mysql.com/doc/refman/5.1/en/alter-database.html

1
zacheusz

mysqldbcopyコマンドを使用して、データベースをあるサーバーから別のサーバーまたは同じサーバーにコピーすることをお勧めします。

mysqldbcopy --source=root:root@localhost --destination=root:root@localhost database-name:database-name-clone

[MySQL]

1
Rakesh C

Greg's answer で述べたように、mysqldump db_name | mysql new_db_name無料、安全、簡単データベース間でデータを転送する方法です。ただし、本当に遅いです。

データのバックアップを検討している場合、(このデータベースまたは他のデータベースで)データを失う余裕がない場合、またはinnodb以外のテーブルを使用している場合は、mysqldumpを使用する必要があります。

開発用のものを探している場合、すべてのデータベースを別の場所にバックアップし、すべてがうまくいかなくなったときにmysqlを(おそらく手動で)パージおよび再インストールしても問題ない場合は、解決策があるかもしれません。

良い選択肢が見つからなかったので、自分でスクリプトを作成しました。私はa lotを費やしてこれを初めて動作させましたが、今では変更を加えるのが少し怖いです。 Innodbデータベースは、このようにコピーして貼り付けることを意図していませんでした。小さな変更は、これをすばらしい方法で失敗させます。コードを完成させて以来、問題はありませんでしたが、それはあなたがそうしないという意味ではありません。

テストされたシステム(ただし、まだ失敗する可能性があります):

  • Ubuntu 16.04、デフォルトmysql、innodb、テーブルごとに個別のファイル
  • Ubuntu 18.04、デフォルトmysql、innodb、テーブルごとに個別のファイル

何をする

  1. Sudo特権を取得し、データベースを複製するのに十分なストレージスペースがあることを確認します
  2. ルートmysql特権を取得します
  3. 現在のgitブランチにちなんで命名された新しいデータベースを作成します
  4. 新しいデータベースへのクローン構造
  5. Innodbの回復モードに切り替えます
  6. 新しいデータベースのデフォルトデータを削除します
  7. Mysqlを停止します
  8. データを新しいデータベースに複製します
  9. Mysqlを開始します
  10. インポートされたデータを新しいデータベースにリンクします
  11. Innodbの復旧モードを切り替えます
  12. Mysqlを再起動します
  13. Mysqlユーザーにデータベースへのアクセスを許可します
  14. 一時ファイルをクリーンアップします

mysqldumpとの比較方法

3GBのデータベースでは、mysqldumpmysqlの使用には、マシンで40〜50分かかります。この方法を使用すると、同じプロセスに約8分しかかかりません。

使い方

SQLの変更はコードと一緒に保存され、アップグレードプロセスは本番と開発の両方で自動化されます。各変更セットは、エラーが発生した場合に復元するデータベースのバックアップを作成します。私たちが遭遇した問題の1つは、データベースの変更を伴う長期プロジェクトに取り組んでいて、バグを修正するために途中でブランチを切り替える必要があったときでした。

以前は、すべてのブランチに単一のデータベースを使用していたため、新しいデータベースの変更と互換性のないブランチに切り替えるたびにデータベースを再構築する必要がありました。そして、切り替えたときに、アップグレードを再度実行する必要がありました。

mysqldumpを使用して異なるブランチのデータベースを複製しようとしましたが、待機時間が長すぎ(40〜50分)、その間は何もできませんでした。

このソリューションにより、データベースのクローン作成時間が1/5に短縮されました(長い昼食の代わりにコーヒーとトイレの休憩を考えてください)。

一般的なタスクとその時間

互換性のないデータベースの変更があるブランチ間の切り替えには、単一のデータベースで50分以上かかりますが、mysqldumpまたはこのコードを使用した初期セットアップ後はまったく時間がかかりません。このコードは、たまたまmysqldumpよりも5倍高速です。

いくつかの一般的なタスクと、それぞれの方法で大体どれくらいの時間がかかるかを示します。

データベースを変更して機能ブランチを作成し、すぐにマージします。

  • 単一データベース:〜5分
  • mysqldumpで複製:50-60分
  • このコードでクローンを作成:〜18分

データベースを変更して機能ブランチを作成し、バグ修正のためにmasterに切り替えて、機能ブランチを編集し、マージします。

  • 単一データベース:〜60分
  • mysqldumpで複製:50-60分
  • このコードでクローンを作成:〜18分

データベースに変更を加えて機能ブランチを作成し、その間の機能ブランチを編集しながら、バグ修正のためにmasterに5回切り替えて、マージします。

  • 単一データベース:〜4時間40分
  • mysqldumpで複製:50-60分
  • このコードでクローンを作成:〜18分

コード

上記のすべてを読んで理解していない限り、これを使用しないでください。

#!/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

すべてがスムーズに進むと、次のように表示されます。

Screenshot of script output for example database

0
0b10011

Gregの答え に加えて、new_db_nameがまだ存在しない場合、これが最も簡単で最速の方法です。

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

元のデータベースにトリガーがある場合、インポートの前に置換をパイピングすることにより、「トリガーが既に存在する」エラーを回避できます。

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

これを行う方法はないと思います。 PHPMyAdminがこれを行うと、DBをダンプし、新しい名前で再挿入します。

0
UnkwnTech

ターミナルで「mysqldbcopy」を使用します。この場合は here といいます。例:cmdプロンプトを開始します。 mySql Serverのbinフォルダーに移動します。以下のクエリを実行します。

C:\Program Files\MySQL\MySQL Server 5.7\bin>mysqldbcopy --source=root:root@localhost --destination=root:root@localhost master:master_clone

ここで、localhostの「master」dbを「master_clone」にコピーしようとしています。

0
Rajneesh