Salin / duplikat basis data tanpa menggunakan mysqldump

427

Tanpa akses lokal ke server, apakah ada cara untuk menduplikasi / mengkloning MySQL db (dengan konten dan tanpa konten) ke yang lain tanpa menggunakan mysqldump?

Saat ini saya menggunakan MySQL 4.0.

jhornnes
sumber
12
Ada apa dengan ini mysqldump?
Michael Mior
48
Pastikan Anda tidak melakukan ini: CREATE TABLE t2 SELECT * FROM t1;karena Anda akan kehilangan informasi indeks Anda, hal-hal khusus seperti auto_increment dll. Banyak hal dari google untuk tabel copy semacam ini akan mengarahkan Anda untuk melakukan ini dan itu akan memiliki hasil yang tidak diinginkan .
John Hunt
59
Pertanyaan di luar topik mendapat 92 upvotes dan 37 favorit. Jempol untuk pertanyaan diluar topik seperti itu. Pedoman usang.
pal4life
25
100% setuju bahwa "topik yang ditutup sebagai salah" salah dan bahwa guildeline harus diperbarui - lebih banyak kelegaan diperlukan - SO sedang menuju ke arah yang salah. Jelas bahwa @will benar-benar melenceng, dan seharusnya hak moderatornya dihapus - pertanyaan tunggal ini cukup bukti.
stolsvik
10
Ditutup karena topik salah 100% salah. Ini adalah pertanyaan persis yang saya miliki, dan memiliki jawaban teknis yang didefinisikan dengan baik yang tidak berhubungan dengan pendapat belaka. Saya pikir moderator pasti telah melakukan pencarian kata-kata seperti "terbaik" untuk menemukan pertanyaan untuk ditutup.
Sam Goldberg

Jawaban:

686

Saya dapat melihat Anda mengatakan Anda tidak ingin menggunakan mysqldump, tetapi saya mencapai halaman ini sambil mencari solusi yang sama dan orang lain mungkin menemukannya juga. Dengan mengingat hal itu, berikut adalah cara sederhana untuk menduplikasi database dari baris perintah server windows:

  1. Buat database target menggunakan MySQLAdmin atau metode pilihan Anda. Dalam contoh ini, db2adalah database target, di mana database sumber db1akan disalin.
  2. Jalankan pernyataan berikut pada baris perintah:

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

Catatan: TIDAK ada ruang antara -pdan[password]

Rafe
sumber
108
Kasus terhadap mysqldump adalah bahwa harus ada cara yang lebih cepat kemudian mem-serialisasi data ke dalam kueri, mentransmisikan kueri di luar proses dan melalui tty kembali ke proses yang sama persis , reparasi kueri, dan menjalankannya sebagai pernyataan. Kedengarannya sangat tidak efisien dan tidak perlu . Kami tidak berbicara tentang persimpangan antara master MySQL atau mengubah mesin penyimpanan. Mengejutkan bahwa tidak ada transfer biner intraproses yang efisien.
Toddius Zho
42
Jika Anda tidak ingin menyimpan plaintext sandi dalam sejarah terminal Anda, Anda perlu untuk membagi perintah: mysqldump -h [server] -u [user] -p db1 > db1, mysql -h [server] -u [user] -p db2 < db1 Jika tidak password yang cepat messes itu, setidaknya bagi saya ketika menggunakan dempul.
kapex
5
menggunakan mysqldump dan mysql dari bash menjadi lebih mudah jika Anda mengatur file .my.cnf Anda untuk menyimpan file pengguna / host / kata sandi Anda
ErichBSchulz
4
mysqldump -u root -p -v db1 | mysql -u root -p db2dan dua kali masuk lulus
hlcs
6
Tuhan, bisakah seseorang menjelaskan mengapa pertanyaan saya yang menyatakan "tanpa mysqldump" memiliki jawaban pertama yang menggunakan mysqldump? dengan suka, 6x lebih banyak suara daripada yang benar ? ayolah, SO ...
igorsantos07
135

Anda bisa menduplikasi tabel tanpa data dengan menjalankan:

CREATE TABLE x LIKE y;

(Lihat Tabel CREATE MySQL Dokumen )

Anda bisa menulis skrip yang mengambil output SHOW TABLESdari satu database dan menyalin skema ke yang lain. Anda harus dapat merujuk skema + nama tabel seperti:

CREATE TABLE x LIKE other_db.y;

Sejauh data berjalan, Anda juga dapat melakukannya di MySQL, tetapi itu belum tentu cepat. Setelah membuat referensi, Anda dapat menjalankan yang berikut untuk menyalin data:

INSERT INTO x SELECT * FROM other_db.y;

Jika Anda menggunakan MyISAM, lebih baik Anda menyalin file tabel; itu akan jauh lebih cepat. Anda harus dapat melakukan hal yang sama jika Anda menggunakan INNODB dengan ruang tabel per .

Jika Anda akhirnya melakukan INSERT INTO SELECT, pastikan untuk sementara menonaktifkan indeks dengan ALTER TABLE x DISABLE KEYS!

EDIT Maatkit juga memiliki beberapa skrip yang mungkin berguna untuk menyinkronkan data. Mungkin tidak lebih cepat, tetapi Anda mungkin dapat menjalankan skrip sinkronisasi pada data langsung tanpa banyak mengunci.

Gary Richardson
sumber
1
Apakah ini berfungsi untuk tabel duplikat? karena saya melihat perintahnya CREATE TABLE
GusDeCooL
4
Anda bisa melakukannya CREATE TABLE ... SELECT.
eggyal
3
Saya mencoba menyalin file tabel database MyISAM sekali, tetapi itu baru saja merusak database baru. Mungkin saya buruk, tapi ini jelas bukan operasi sepele seperti yang dikatakan beberapa orang.
Johan Fredrik Varen
2
Ini adalah trik yang bagus dan saya penggemar, tetapi catatan penting: ini tidak membawa kendala kunci asing (bahkan yang eksternal untuk skema yang sedang disalin) per Dokumen MySQL
abigperson
59

Jika Anda menggunakan Linux, Anda dapat menggunakan skrip bash ini: (mungkin membutuhkan pembersihan kode tambahan tetapi berfungsi ... dan jauh lebih cepat daripada 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
sumber
7
Jika Anda menggunakan skrip di atas dengan tabel InnoDB dan memiliki kunci asing, ubah baris terakhir ke yang berikut:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
pegli
Apakah ini juga menyalin data kendala dan properti tabel lainnya?
Lucas Moeskops
1
Sepertinya begitu, karena dia menggunakan pernyataan "SHOW CREATE TABLE" yang menghasilkan CREATE TABLE dengan semua properti aslinya.
Danita
1
Jika Anda mendapatkan masalah yang dijelaskan @ zirael mungkin karena skrip gagal menyalin tampilan. Anda dapat mengabaikan tampilan dari salinan dengan mengubah SHOW TABLESbaris ke SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'dan menambahkan | cut -f 1. Baris lengkap akan terlihat seperti ini tetapi ganti backticks ganda dengan backticks tunggal: for TABLE in ``echo "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" | mysql $DBCONN $DBSNAME | tail -n +2 | cut -f 1``; do
Code Commander
1
Saya telah membersihkan skrip ini oleh @jozjan dan menerapkan beberapa komentar mengenai kunci asing dan lainnya untuk membuat versi ini di GIST gist.github.com/christopher-hopper/8431737
Christopher
11

Dalam 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
sumber
Jika Anda bekerja pada mesin windows. Maka silakan gunakan ini alih-alih menemukan cara panjang untuk menjalankan perintah.
Parixit
skrip ini jangan dilihat dalam hitungan
sd1sd1
4

Perhatikan ada perintah mysqldbcopy sebagai bagian dari add on mysql utilities .... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html

furicle
sumber
Tetapi itu membutuhkan instalasi paket tambahan:apt install mysql-utilities
Joel G Mathew
2
Tetapi tidak ada batasan yang mengatakan bahwa itu tidak mungkin .... dan itu adalah hal yang umum diinstal (tetapi opsional seperti yang Anda katakan) Jika tidak diinstal, banyak yang akan menemukan menginstal paket itu lebih mudah daripada mengatur dan menjalankan skrip Bash 60 baris , dll ....
furicle
Posting Anda mungkin ditolak karena Anda tidak memasukkan informasi selain tautan. Jawaban seharusnya lebih komprehensif.
Joel G Mathew
1

Saya tidak benar-benar tahu apa yang Anda maksud dengan "akses lokal". Tetapi untuk solusi itu Anda harus dapat mengakses ssh server untuk menyalin file di mana basis data disimpan .

Saya tidak dapat menggunakan mysqldump, karena database saya besar (7Go, mysqldump gagal) Jika versi dari database mysql 2 terlalu berbeda mungkin tidak berfungsi, Anda dapat memeriksa versi mysql Anda menggunakan mysql -V.

1) Salin data dari server jarak jauh Anda ke komputer lokal Anda (vps adalah alias untuk server jarak jauh Anda, dapat diganti dengan [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) Impor data yang disalin di komputer lokal Anda

/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

Jika Anda memiliki versi yang berbeda, Anda mungkin perlu menjalankannya

/etc/init.d/mysql stop
mysql_upgrade -u root -pPASSWORD --force #that step took almost 1hrs
/etc/init.d/mysql start
Remy Mellet
sumber
Ini adalah cara paling efisien untuk melakukannya tetapi saya pikir "tanpa akses lokal ke server" berarti bahwa kita tidak dapat mengakses sistem. Mungkin hosting bersama? Jadi ini bukan jawabannya.
Valerio Bozz
1

Semua solusi sebelumnya mendapatkan sedikit intinya, namun, mereka tidak menyalin semuanya. Saya membuat fungsi PHP (meskipun agak panjang) yang menyalin segala sesuatu termasuk tabel, kunci asing, data, tampilan, prosedur, fungsi, pemicu, dan acara. Ini kodenya:

/* 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
sumber
Diturunkan karena pertanyaannya bukan "jangan gunakan mysqldump" tetapi "gunakan pendekatan yang lebih baik daripada mysqldump". Ini bahkan lebih buruk mysqldumpdalam hal efisiensi.
Valerio Bozz
1

Sebenarnya saya ingin mencapai hal itu dalam PHP tetapi tidak ada jawaban di sini yang sangat membantu jadi inilah solusi saya - cukup mudah - menggunakan 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
sumber
Saya tidak yakin ini membuat klon 1: 1 tetapi sepertinya untuk database sederhana mungkin cukup.
beppe9000
Saya menggunakannya untuk membuat instalasi WordPress cepat di server pengembangan saya. Bagian ini dipasangkan dengan beberapa rutinitas lain, duplikat dan sesuaikan instalasi sumber ke proyek baru. Untuk itu berfungsi dengan baik ... tetapi database kosong wordpress tidak terlalu rumit sehingga saya tidak dapat membuat pernyataan untuk kasus penggunaan yang lebih luas
GDY
0

Cara terbaik untuk mengkloning tabel database tanpa mysqldump:

  1. Buat database baru.
  2. Buat klon-kueri dengan kueri:

    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. Jalankan output itu!

Tetapi perhatikan, skrip di atas hanya tabel klon cepat - bukan tampilan, pemicu, dan fungsi pengguna: Anda dapat dengan cepat mendapatkan struktur dengan mysqldump --no-data --triggers -uroot -ppassword, dan kemudian gunakan untuk mengkloning hanya memasukkan pernyataan.

Mengapa itu adalah pertanyaan aktual? Karena mengunggah mysqldumps lambat sekali jika DB lebih dari 2Gb. Dan Anda tidak dapat mengkloning tabel InnoDB hanya dengan menyalin file DB (seperti pencadangan snapshot).

Alexander Goncharov
sumber
0

SQL yang menunjukkan perintah SQL, perlu dijalankan untuk menduplikasi database dari satu database ke yang lain. untuk setiap tabel ada buat pernyataan tabel dan pernyataan insert. itu mengasumsikan kedua database berada di server yang sama:

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
sumber
-1

Mysqldump bukan solusi buruk. Cara termudah untuk menggandakan basis data:

mysqldump -uusername -ppass dbname1 | mysql -uusername -ppass dbname2

Anda juga dapat mengubah mesin penyimpanan dengan cara ini:

mysqldump -uusername -ppass dbname1 | sed 's/InnoDB/RocksDB/' | mysql -uusername -ppass dbname2

Andy Al
sumber