Mysqldump kullanmadan veritabanını kopyala / çoğalt


427

Sunucuya yerel erişim olmadan, bir MySQL db'yi (içerikli ve içeriksiz) kullanmadan başka birine kopyalamanın / kopyalamanın herhangi bir yolu var mysqldumpmı?

Şu anda MySQL 4.0 kullanıyorum.


12
Sorun nedir mysqldump?
Michael Mior

48
Bunu yapmadığınızdan emin olun : CREATE TABLE t2 SELECT * FROM t1;endeks bilgilerinizi, auto_increment vb. Gibi özel şeyleri kaybedeceğinizden emin olun. .
John Hunt

59
Bir konu dışı soru 92 upvotes ve 37 favori alır. Bu konu dışı soru için başparmak yukarı. Eski kurallar.
pal4life

25
% 100, "konu dışı kapalı" nın yanlış olduğunu ve guildeline'ların güncellenmesi gerektiğine katılıyor - daha fazla hoşgörü gerekiyor - SO yanlış yönde gidiyor. @Will'in tamamen işaretsiz olduğu ve moderatör ayrıcalıklarının kaldırılması gerektiği açıktır - bu tek soru yeterince kanıttır.
stolsvik

10
Konu dışı olarak kapalı% 100 yanlış. Bu tam olarak sahip olduğum soru ve sadece görüşle ilgili olmayan iyi tanımlanmış bir teknik cevabı var. Ben moderatör kapatmak için soru bulmak için "en iyi" gibi bir kelime arıyor olması gerektiğini düşünüyorum.
Sam Goldberg

Yanıtlar:


686

Kullanmak istemediğinizi söylediğinizi görebiliyorum mysqldump, ancak benzer bir çözüm ararken bu sayfaya ulaştım ve diğerleri de bulabilir. Bunu göz önünde bulundurarak, bir veritabanını Windows sunucusunun komut satırından çoğaltmanın basit bir yolu:

  1. MySQLAdmin veya tercih ettiğiniz yöntemi kullanarak hedef veritabanını oluşturun. Bu örnekte, db2kaynak veritabanının db1kopyalanacağı hedef veritabanıdır .
  2. Komut satırında aşağıdaki ifadeyi yürütün:

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

Not: -pve arasında boşluk yoktur[password]


108
Mysqldump aleyhindeki durum , daha sonra verilerin sorgulara serileştirilmesi, sorguların işlemin dışında ve tty üzerinden tekrar aynı sürece aktarılması, sorguların tekrarlanması ve ifadeler olarak çalıştırılmasının daha hızlı bir yolu olması gerektiğidir . Kulağa korkunç derecede verimsiz ve gereksiz geliyor . MySQL yöneticileri arasında geçiş yapmak veya depolama motorlarını değiştirmek hakkında konuşmuyoruz. Verimli bir süreç içi ikili aktarım olmaması şaşırtıcıdır.
Toddius Zho

42
: Eğer terminalleri tarihinin şifre şifresiz kaydetmek istemiyorsanız, komut bölmek gerekir mysqldump -h [server] -u [user] -p db1 > db1, mysql -h [server] -u [user] -p db2 < db1 benim için en az macun kullanılırken, Aksi takdirde şifre istemi pisliklerimizi o kadar.
kapex

5
.ys.cnf dosyanızı kullanıcı / ana bilgisayar / parola dosyalarınızı saklamak için ayarladıysanız, bash'den mysqldump ve mysql kullanmak çok daha kolay hale gelir
ErichBSchulz

4
mysqldump -u root -p -v db1 | mysql -u root -p db2ve iki kez pas
giriyor

6
Tanrım, lütfen birisi neden neden "mysqldump olmadan" mysqldump kullanan ilk yanıt olduğunu açıklayan bir soru açıklayabilir misiniz? gibi, doğru olandan 6 kat daha fazla oy ? Hadi, SO ...
igorsantos07

135

Bir tabloyu veri olmadan kopyalayarak çalıştırabilirsiniz:

CREATE TABLE x LIKE y;

(Bkz. MySQL CREATE TABLE Belgeleri)

Çıkışı SHOW TABLESbir veritabanından alan ve şemayı başka bir veritabanına kopyalayan bir komut dosyası yazabilirsiniz . Şema + tablo adlarına aşağıdaki gibi başvurabilmeniz gerekir:

CREATE TABLE x LIKE other_db.y;

Verilere gelince, MySQL'de de yapabilirsiniz, ancak hızlı olması gerekmez. Referansları oluşturduktan sonra, verileri kopyalamak için aşağıdakileri çalıştırabilirsiniz:

INSERT INTO x SELECT * FROM other_db.y;

MyISAM kullanıyorsanız, tablo dosyalarını kopyalamak daha iyidir; çok daha hızlı olacak. Tablo başına tablo alanı ile INNODB kullanıyorsanız aynı şeyi yapabilmeniz gerekir .

Sonunda bir işlem yaparsanız INSERT INTO SELECT, dizinleri geçici olarakALTER TABLE x DISABLE KEYS !

EDIT Maatkit ayrıca veri senkronizasyonu için yararlı olabilecek bazı komut dosyalarına sahiptir. Daha hızlı olmayabilir, ancak senkronizasyon komut dosyalarını çok fazla kilitlemeden canlı verilerde çalıştırabilirsiniz.


1
yinelenen tablo için bu çalışma nedir? komut CREATE TABLE olduğunu
gördüğümden

4
Yapabilirsin CREATE TABLE ... SELECT.
eggyal

3
Bir kez MyISAM veritabanının tablo dosyalarını kopyalamayı denedim, ancak bu sadece yeni veritabanını bozdu. Muhtemelen benim kötüyüm, ama kesinlikle bazılarının söylediği kadar önemsiz bir işlem değil.
Johan Fredrik Varen

2
Bu güzel bir hile ve hayranıyım, ama önemli bir not: bu , MySQL Docs
abigperson

59

Linux kullanıyorsanız, bu bash betiğini kullanabilirsiniz: (belki de bazı ek kod temizlemeye ihtiyaç duyar, ancak çalışır ... ve mysqldump | mysql'den çok daha hızlıdır)

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

7
Yukarıdaki komut dosyasını InnoDB tablolarıyla kullanıyorsanız ve yabancı anahtarlarınız varsa, son satırı şu şekilde değiştirin:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
pegli

Bu ayrıca kısıtlama verilerini ve tabloların diğer özelliklerini de kopyalar mı?
Lucas Moeskops

1
Öyle görünüyor, çünkü orijinalin tüm özellikleriyle bir CREATE TABLE oluşturan bir "CREATE TABLE SHOW" ifadesi kullanıyor.
Danita

1
@Zirael açıkladı sorun alırsanız, muhtemelen komut dosyası görünümleri kopyalamak için başarısız olmasıdır. SHOW TABLESSatırı değiştirip SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'ekleyerek kopyadaki görünümleri yok sayabilirsiniz | cut -f 1. Komple çizgi böyle bir şey görünmeli ama çift backticks tek backticks ile değiştirin: for TABLE in ``echo "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" | mysql $DBCONN $DBSNAME | tail -n +2 | cut -f 1``; do
Kod Komutanı

1
Ben @jozjan tarafından bu komut dosyası yukarı temizlenmiş ve GIST bu sürümünü oluşturmak için yabancı ve diğer anahtarlar ile ilgili bazı yorumlar uyguladığınız gist.github.com/christopher-hopper/8431737
Christopher

11

PHP dilinde:

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

Windows makinesinde çalışıyorsanız. Ardından, komutu yürütmek için uzun yollar bulmak yerine bunu kullanın.
Parixit

Bu script sayıları ile ilgili bilgi
almaz

4

Mysql yardımcı programlarının eklentisinin bir parçası olarak bir mysqldbcopy komutu olduğunu unutmayın .... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html


Ancak ek bir paketin kurulmasını gerektirir:apt install mysql-utilities
Joel G Mathew

2
Ancak, bunun mümkün olmadığını söyleyen bir kısıtlama yoktu .... ve yaygın olarak yüklenmiş bir şey (ancak söylediğiniz gibi isteğe bağlı) Yüklü değilse, birçok kişi bu paketi yüklemeyi 60 satırlık bir Bash komut dosyası kurup çalıştırmaktan daha kolay bulabilirdi , vb ....
furicle

Bir bağlantıdan başka bilgi eklemediğiniz için yayınınız büyük olasılıkla oy kullanıldı. Cevapların daha kapsamlı olması gerekiyor.
Joel G Mathew

1

"Yerel erişim" ile ne demek istediğinizi gerçekten bilmiyorum. Ancak bu çözüm için veritabanının depolandığı dosyaları kopyalamak için ssh sunucusuna erişebilmeniz gerekir. .

Benim veritabanı büyük olduğu için mysqldump kullanamıyorum (7Go, mysqldump başarısız) 2 mysql veritabanının sürümü çok farklı olabilir, mysql -V kullanarak mysql sürümünü kontrol edebilirsiniz.

1) Verileri uzak sunucunuzdan yerel bilgisayarınıza kopyalayın (vps uzak sunucunuzun takma adıdır, root@1.2.3.4 ile değiştirilebilir)

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) Yerel bilgisayarınıza kopyalanan verileri içe aktarın

/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

Farklı bir sürümünüz varsa, çalıştırmanız gerekebilir

/etc/init.d/mysql stop
mysql_upgrade -u root -pPASSWORD --force #that step took almost 1hrs
/etc/init.d/mysql start

Bu bunu yapmanın en etkili yoludur, ancak "sunucuya yerel erişim olmadan" sisteme erişemeyeceğimizi düşünüyorum. Muhtemelen paylaşılan bir barındırma? Yani cevap bu değil.
Valerio Bozz

1

Önceki tüm çözümler bu noktada biraz olsun, ancak her şeyi kopyalamıyorlar. Tablolar, yabancı anahtarlar, veriler, görünümler, prosedürler, fonksiyonlar, tetikleyiciler ve olaylar dahil her şeyi kopyalayan bir PHP işlevi (biraz da olsa) oluşturdum. İşte kod:

/* 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]));
        }
    }
}

Soru "mysqldump kullanma" değil "mysqldump daha iyi bir yaklaşım kullanın" olduğu için indirildi. Bu, mysqldumpverimlilik açısından daha da kötüdür .
Valerio Bozz

1

Aslında ben tam olarak PHP elde etmek istedim ama burada cevapların hiçbiri çok yararlı değildi bu yüzden burada MySQLi kullanarak benim - oldukça basit - çözüm:

// 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;

Tihis'in 1: 1 klon yaptığını bilmiyorum ama basit veritabanları için yeterli gibi görünüyor.
beppe9000

Geliştirme sunucumda hızlı WordPress kurulumları oluşturmak için kullanıyorum. Bu bölüm diğer bazı rutinlerle eşleştirilir ve kaynak kurulumunu yeni bir projeye ayarlar. Bunun için gayet iyi çalışıyor… ama boş bir wordpress veritabanı çok karmaşık değil, bu yüzden daha geniş kullanım durumları için bir açıklama yapamam
GDY

0

MySQLdump olmadan veritabanı tablolarını klonlamak için en iyi yolu:

  1. Yeni bir veritabanı oluşturun.
  2. Sorgu ile klon sorguları oluşturun:

    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. Bu çıktıyı çalıştırın!

Ancak, komut dosyası görünümlerin, tetikleyicilerin ve kullanıcı işlevlerinin değil, sadece hızlı klon tablolarının üstünde yazılır: Yapıyı hızlı bir şekilde alabilir mysqldump --no-data --triggers -uroot -ppasswordve daha sonra yalnızca deyimi eklemek için kullanabilirsiniz.

Neden asıl soru bu? Çünkü DB 2 Gb üzerinde ise mysqldumps yükleme çirkin yavaş . Ve sadece DB dosyalarını kopyalayarak (anlık görüntü yedekleme gibi) InnoDB tablolarını klonlayamazsınız.


0

SQL komutlarını gösteren bir SQL, bir veritabanını bir veritabanından diğerine çoğaltmak için çalıştırılmalıdır. her tablo için bir tablo ifadesi ve bir insert ifadesi vardır. her iki veritabanının da aynı sunucuda olduğunu varsayar:

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';

-1

Mysqldump kötü bir çözüm değil. Veritabanını kopyalamanın en kolay yolu:

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

Ayrıca, depolama motorunu şu şekilde değiştirebilirsiniz:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.