การโคลนฐานข้อมูล MySQL บนอินสแตนซ์ MySql เดียวกัน


154

ฉันต้องการเขียนสคริปต์ซึ่งคัดลอกฐานข้อมูลปัจจุบันของฉันsitedb1ไปยังsitedb2อินสแตนซ์ฐานข้อมูล mysql เดียวกัน ฉันรู้ว่าฉันสามารถถ่ายโอน sitedb1 ไปยังสคริปต์ sql:

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

sitedb2จากนั้นจึงนำไป มีวิธีที่ง่ายขึ้นโดยไม่ต้องทิ้งฐานข้อมูลแรกไปยังไฟล์ sql หรือไม่


ซ้ำซ้อนที่เป็นไปได้ของฐานข้อมูล Clone MySQL
bummi

คำตอบ:


303

ตามที่คู่มือบอกไว้ในการคัดลอกฐานข้อมูลคุณสามารถไพพ์ดัมพ์โดยตรงไปยังไคลเอนต์ mysql:

mysqldump db_name | mysql new_db_name

หากคุณใช้ MyISAM คุณสามารถคัดลอกไฟล์ได้ แต่ฉันจะไม่แนะนำ มันค่อนข้างจะหลบ

บูรณาการจากคำตอบที่ดีอื่น ๆ อีกมากมาย

ทั้งสองmysqldumpและmysqlคำสั่งยอมรับตัวเลือกสำหรับการตั้งค่ารายละเอียดการเชื่อมต่อ (และอีกมากมาย) เช่น:

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)


2
Kinda ... มันข้ามดิสก์ IO จำนวนมากถึงแม้ว่าคุณจะไม่ต้องอ่าน / เขียนข้อมูลสองครั้ง
34899 Greg

8
หากฐานข้อมูลของคุณมีขนาดกิกะไบต์นี่อาจไม่ได้ผลมากนัก ฉันคิดว่าสิ่งที่ OP กำลังดำเนินอยู่คือพวกเขาไม่ต้องการส่งออกสำเนา: สามารถทำได้ภายใน mysql หรือไม่
cletus

3
ผมว่าใหญ่ DB มากขึ้นก็รับคุณ ... ไม่มีทางที่จะทำเช่นนี้ภายใน MySQL ไม่มี AFAIK (ยกเว้นด้วยมือหนึ่งตาราง / มุมมองในเวลา)
เกร็ก

41
ก่อนอื่นฉันต้องสร้าง new_db โดยใช้คำสั่ง mysql มาตรฐาน: "CREATE DATABASE new_db;" จากนั้นใช้คำสั่งเหล่านี้: mysqldump -u root -p old_db | mysql -u root -p new_db
วาเลนไทน์

4
mysqldump -uroot -p database1 | mysql -uroot -p database2นี้ไม่ได้ทำงานสำหรับผมถ้าผมต้องใส่รหัสผ่านสำหรับการทุ่มตลาดและนำเข้าเช่นนี้ ฉันได้รับแจ้งสำหรับ pws ทั้งสอง แต่สามารถใส่ได้เพียงอันเดียว Enter password: Enter password: รูปลักษณ์ที่พรอมต์เช่นนี้ หลังจากให้ pw แรกกระบวนการจะรอตลอดไป
Torsten

66

ใช้โปรแกรมอรรถประโยชน์ของ MySQL

ยูทิลิตี้ MySQL มีเครื่องมือที่ดีmysqldbcopyซึ่งโดยปกติแล้วจะคัดลอกฐานข้อมูลรวมถึงวัตถุที่เกี่ยวข้องทั้งหมด (“ ตารางมุมมองทริกเกอร์เหตุการณ์ขั้นตอนฟังก์ชั่นและการมอบระดับฐานข้อมูล”) และข้อมูลจากเซิร์ฟเวอร์ฐานข้อมูลหนึ่งไปยังเซิร์ฟเวอร์เดียวกัน เซิร์ฟเวอร์ฐานข้อมูล มีตัวเลือกมากมายสำหรับปรับแต่งสิ่งที่คัดลอกจริง

ดังนั้นเพื่อตอบคำถามของ OP:

mysqldbcopy \
    --source=root:your_password@localhost \
    --destination=root:your_password@localhost \
    sitedb1:sitedb2

1
สิ่งนี้ใช้ได้ผลดีสำหรับฉันmysqldumpการแก้ปัญหาตามพื้นฐานล้มเหลว
saji89

1
ในกรณีของฉันฉันต้องระบุพอร์ตเช่นนี้: --source = root: your_password @ localhost: 3307 (มิฉะนั้นจะทำให้ฉันมีข้อผิดพลาดถูกปฏิเสธการเข้าถึง)
pbz

4
ต้องการsudo apt-get install mysql-utilitiesแต่นี่เป็นระเบียบมาก ฉันจะลืมรหัสผ่านและขอให้ป้อนรหัสผ่านได้หรือไม่
ADTC

2
@ADTC ฉันไม่ทราบว่ามีวิธีในตัวเพื่อmysqldbcopyขอรหัสผ่านจากคุณหรือไม่ อย่างน้อยฉันก็ไม่พบอะไรแบบนั้นในเอกสาร คุณสามารถสร้างฟังก์ชั่นนี้ได้ด้วยตัวเอง ใน Bash ที่อาจมีลักษณะเช่นนี้:mysqldbcopy --source=root:"$(read -sp 'Source password: ' && echo $REPLY)"@localhost --destination=root:"$(read -sp 'Destination password: ' && echo $REPLY)"@localhost sitedb1:sitedb2
Chriki

1
FYI: ดูเหมือนว่าคำสั่งของ Chriki จะทำงานได้อย่างไร้ที่ติ ฉันต้องเพิ่ม--forceไปยังmysqldbcopyคำสั่งเพราะฉันได้สร้างฐานข้อมูลปลายทางแล้ว ขอบคุณ!
Niavlys

19
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

2
มันจะเพิ่มอะไรในคำตอบที่ยอมรับ? คล้ายกัน แต่คุณเพิ่มความแตกต่างเพิ่มความคิดเห็นเพื่อความเข้าใจที่ดีขึ้น
Yaroslav

นี่ควรเป็นคำตอบที่ได้รับการยอมรับเพราะมันจะสร้างฐานข้อมูลที่ดีสำหรับการรับรองความถูกต้อง คำตอบที่ได้รับการยอมรับในปัจจุบันจะบอกให้คุณปฏิเสธการเข้าถึงจากนั้นไม่มีตาราง
Rami Dabain

14

คุณต้องรันคำสั่งจากหน้าจอพร้อมรับคำสั่ง

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'


ฉันชอบคำตอบนี้มันคมชัด อย่างไรก็ตามสำหรับฉัน mysql ต้องใช้ -p ก่อนรหัสผ่าน
lwitzel

1
เราจะคัดลอกฟังก์ชั่นกิจกรรมและอื่น ๆ ที่สร้างในฐานข้อมูลต้นฉบับได้อย่างไร ลักษณะนี้คัดลอกตารางเท่านั้น
Dogan Askan

12

วิธีที่ดีที่สุดและง่ายที่สุดคือการป้อนคำสั่งเหล่านี้ในเทอร์มินัลของคุณและกำหนดสิทธิ์ให้กับผู้ใช้รูท ใช้งานได้สำหรับฉัน .. !

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

1
คำถามระบุไว้อย่างชัดเจนว่าวิธีการส่งออก / นำเข้าเป็นที่รู้จักกันแล้ว
LAV

3
นี่เป็นวิธีที่ดีที่สุดในการทำมัน สามารถใช้งานกับฐานข้อมูลขนาดใหญ่ได้ในขณะที่เวอร์ชันไพพ์mysqldump -u <user> -p <pwd> db_name | mysql -u <user> -p <pwd> new_db_nameอาจมีปัญหากับฐานข้อมูลขนาดใหญ่
อเล็กซ์

10

คุณสามารถใช้ (ใน pseudocode):

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 ... คือการรักษาดัชนี ของหลักสูตรนี้คัดลอกตารางเท่านั้น มุมมองและขั้นตอนจะไม่ถูกคัดลอกถึงแม้ว่ามันจะสามารถทำได้ในลักษณะเดียวกัน

ดูสร้างตาราง


3
สิ่งนี้อาจล้มเหลวในการอ้างอิงที่สมบูรณ์เนื่องจากยังไม่สามารถคัดลอกตารางที่อ้างอิงได้ บางทีมันอาจทำงานได้ในการทำธุรกรรมครั้งใหญ่
Ondrej Galbavý

4

สร้างฐานข้อมูลซ้ำกันก่อน:

CREATE DATABASE duplicateddb;

ตรวจสอบให้แน่ใจว่ามีการอนุญาตอื่น ๆ ทั้งหมดและ:

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

2

คุณสามารถทำสิ่งต่อไปนี้:

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

1

คำสั่งนี้ถูกเพิ่มใน 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/th/alter-database.html


1

วิธีง่ายๆในการทำเช่นนั้นหากคุณติดตั้งphpmyadmin :

ไปที่ฐานข้อมูลของคุณเลือกแท็บ "การดำเนินการ" และคุณจะเห็นบล็อก "คัดลอกฐานข้อมูลไปยัง" ใช้มันและคุณสามารถคัดลอกฐานข้อมูล


1

ตามที่ระบุไว้ในคำตอบของเกร็ก , mysqldump db_name | mysql new_db_nameเป็นฟรีปลอดภัยและใช้งานง่ายด้วยวิธีการถ่ายโอนข้อมูลระหว่างฐานข้อมูล แต่ก็ยังช้าจริงๆ

หากคุณกำลังมองหาในการสำรองข้อมูลไม่สามารถจะสูญเสียข้อมูล (ในนี้หรือฐานข้อมูลอื่น ๆ ) หรือใช้ตารางอื่น ๆ กว่าแล้วคุณควรใช้innodbmysqldump

หากคุณกำลังมองหาบางอย่างเพื่อการพัฒนาให้สำรองฐานข้อมูลทั้งหมดของคุณไว้ที่อื่นและลบทิ้งและติดตั้งใหม่mysql(อาจเป็นด้วยตนเอง) เมื่อทุกอย่างผิดพลาดฉันก็อาจมีทางออกให้คุณ

ฉันหาทางเลือกที่ดีไม่ได้ดังนั้นฉันจึงสร้างสคริปต์ขึ้นมาเพื่อทำด้วยตัวเอง ฉันใช้เวลามากในการทำให้สิ่งนี้ทำงานเป็นครั้งแรกและมันทำให้ฉันตกใจเล็กน้อยที่จะทำการเปลี่ยนแปลงในตอนนี้ ฐานข้อมูล Innodb ไม่ได้หมายถึงการคัดลอกและวางแบบนี้ การเปลี่ยนแปลงเล็กน้อยทำให้สิ่งนี้ล้มเหลวในรูปแบบที่งดงาม ฉันไม่ได้มีปัญหาเนื่องจากฉันทำการสรุปรหัส แต่นั่นไม่ได้หมายความว่าคุณจะไม่ทำ

ระบบทดสอบใน (แต่อาจยังล้มเหลว):

  • Ubuntu 16.04, mysql เริ่มต้น, innodb, แยกไฟล์ต่อตาราง
  • Ubuntu 18.04, mysql เริ่มต้น, innodb, แยกไฟล์ต่อตาราง

มันทำอะไร

  1. รับsudoสิทธิ์และตรวจสอบว่าคุณมีพื้นที่เก็บข้อมูลเพียงพอในการโคลนฐานข้อมูล
  2. รับสิทธิ์ root mysql
  3. สร้างฐานข้อมูลใหม่ตั้งชื่อตามสาขา git ปัจจุบัน
  4. โครงสร้างโคลนกับฐานข้อมูลใหม่
  5. เปลี่ยนเป็นโหมดการกู้คืนสำหรับ innodb
  6. ลบข้อมูลเริ่มต้นในฐานข้อมูลใหม่
  7. หยุด mysql
  8. โคลนข้อมูลไปยังฐานข้อมูลใหม่
  9. เริ่ม mysql
  10. ลิงก์ข้อมูลที่นำเข้าในฐานข้อมูลใหม่
  11. สลับออกจากโหมดการกู้คืนสำหรับ innodb
  12. รีสตาร์ท mysql
  13. ให้ผู้ใช้ mysql เข้าถึงฐานข้อมูล
  14. ล้างข้อมูลไฟล์ชั่วคราว

มันเปรียบเทียบกับอย่างไร mysqldump

บนฐานข้อมูล 3gb ให้ใช้mysqldumpและmysqlจะใช้เวลา 40-50 นาทีในเครื่องของฉัน ใช้วิธีนี้กระบวนการเดียวกันจะใช้เวลาประมาณ 8 นาที

เราใช้มันอย่างไร

เราได้บันทึกการเปลี่ยนแปลง SQL ไว้ข้างๆโค้ดของเราและกระบวนการอัปเกรดนั้นเป็นแบบอัตโนมัติทั้งในการผลิตและการพัฒนาโดยแต่ละชุดของการเปลี่ยนแปลงจะทำการสำรองข้อมูลของฐานข้อมูลเพื่อเรียกคืนหากมีข้อผิดพลาด ปัญหาหนึ่งที่เราพบคือเมื่อเราทำงานในโครงการระยะยาวที่มีการเปลี่ยนแปลงฐานข้อมูลและต้องสลับสาขาที่อยู่ตรงกลางเพื่อแก้ไขข้อผิดพลาดหรือสามข้อ

ในอดีตเราใช้ฐานข้อมูลเดียวสำหรับทุกสาขาและจะต้องสร้างฐานข้อมูลใหม่ทุกครั้งที่เราเปลี่ยนเป็นสาขาที่ไม่เข้ากันกับการเปลี่ยนแปลงฐานข้อมูลใหม่ และเมื่อเราเปลี่ยนกลับไปเราต้องทำการอัพเกรดอีกครั้ง

เราพยายามmysqldumpทำซ้ำฐานข้อมูลสำหรับสาขาที่แตกต่างกัน แต่เวลารอนานเกินไป (40-50 นาที) และเราไม่สามารถทำอะไรได้อีกในเวลาเดียวกัน

วิธีนี้ทำให้เวลาในการโคลนฐานข้อมูลสั้นลงเป็น 1/5 ของเวลา (คิดว่าช่วงพักดื่มกาแฟและห้องน้ำแทนที่จะเป็นมื้อกลางวันยาว)

งานทั่วไปและเวลาของพวกเขา

การสลับระหว่างสาขาที่มีการเปลี่ยนแปลงฐานข้อมูลที่ใช้ร่วมกันไม่ได้นั้นใช้เวลา 50+ นาทีในฐานข้อมูลเดียว แต่ไม่มีเวลาเลยหลังจากตั้งค่าเริ่มต้นด้วยmysqldumpหรือรหัสนี้ รหัสนี้เพิ่งเกิดขึ้นเป็น ~ 5 mysqldumpครั้งเร็วกว่า

ต่อไปนี้เป็นงานทั่วไปและประมาณระยะเวลาที่จะใช้กับแต่ละวิธี:

สร้างสาขาฟีเจอร์ที่มีการเปลี่ยนแปลงฐานข้อมูลและผสานทันที:

  • ฐานข้อมูลเดียว: ~ 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

หากทุกอย่างราบรื่นคุณควรเห็นสิ่งต่อไปนี้:

สกรีนช็อตของเอาต์พุตสคริปต์สำหรับฐานข้อมูลตัวอย่าง


0

นอกจากคำตอบของ 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

หากคุณมีทริกเกอร์ในฐานข้อมูลดั้งเดิมของคุณคุณสามารถหลีกเลี่ยงข้อผิดพลาด "ทริกเกอร์มีอยู่แล้ว" โดยการเปลี่ยนท่อก่อนที่จะนำเข้า:

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

-4

ฉันไม่คิดว่าจะมีวิธีการทำเช่นนี้ เมื่อ PHPMyAdmin ทำสิ่งนี้มันจะทิ้ง DB จากนั้นแทรกใหม่ภายใต้ชื่อใหม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.