Skopiuj / zduplikuj bazę danych bez użycia mysqldump


427

Czy bez lokalnego dostępu do serwera istnieje sposób na zduplikowanie / sklonowanie bazy danych MySQL (z zawartością i bez zawartości) na inną bez użycia mysqldump?

Obecnie używam MySQL 4.0.


12
Co jest nie tak z mysqldump?
— Michael Mior

48
Upewnij się, że tego nie robisz: CREATE TABLE t2 SELECT * FROM t1;ponieważ stracisz informacje o indeksie, wszelkie specjalne rzeczy, takie jak auto_increment itp. Wiele google'ów dla tego rodzaju tabeli kopii prowadzi do tego i będzie to miało niepożądane efekty .
— John Hunt,

59
Pytanie poza tematem zyskuje 92 głosy poparcia i 37 ulubionych. Kciuki za takie pytanie poza tematem. Nieaktualne wytyczne.
— pal4life

25
100% zgadza się, że „zamknięte jak poza tematem” jest błędne i że linie gildii powinny zostać zaktualizowane - potrzebna jest większa wyrozumiałość - SO zmierza w złym kierunku. Oczywiste jest, że @will jest całkowicie poza zasięgiem i powinien usunąć swoje uprawnienia moderatora - to pojedyncze pytanie jest wystarczającym dowodem.
— Stolsvik,

10
Zamknięty jako wyłączony temat jest w 100% błędny. To jest dokładnie takie pytanie, jakie mam, i ma ono jasno określoną odpowiedź techniczną, która nie dotyczy samej opinii. Myślę, że moderator musiał szukać słów takich jak „najlepszy”, aby znaleźć pytania do zamknięcia.
— Sam Goldberg,

Odpowiedzi:


686

Widzę, że powiedziałeś, że nie chcesz używać mysqldump, ale doszedłem do tej strony, szukając podobnego rozwiązania i inni też mogą go znaleźć. Mając to na uwadze, oto prosty sposób na skopiowanie bazy danych z wiersza poleceń serwera Windows:

  1. Utwórz docelową bazę danych za pomocą MySQLAdmin lub preferowanej metody. W tym przykładzie db2jest docelowa baza danych, do której db1zostanie skopiowana źródłowa baza danych .
  2. Wykonaj następującą instrukcję w wierszu polecenia:

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

Uwaga: Nie ma spacji między -pi[password]


108
Sprawa przeciwko mysqldump polega na tym, że musi istnieć szybszy sposób niż serializowanie danych do kwerend, przesyłanie zapytań poza proces i poprzez tty z powrotem do dokładnie tego samego procesu , ponownej analizy zapytań i wykonywania ich jako instrukcji. To brzmi okropnie nieefektywnie i niepotrzebnie . Nie mówimy o przechodzeniu między wzorcami MySQL lub zmianie silników pamięci masowej. To szokujące, że nie ma wydajnego transferu binarnego w trakcie procesu.
— Toddius Zho

42
Jeśli nie chcesz zapisywać hasła zwykłego tekstu w historii zaciskami, trzeba podzielić polecenie: mysqldump -h [server] -u [user] -p db1 > db1, mysql -h [server] -u [user] -p db2 < db1 w przeciwnym razie hasło szybkich mes go, przynajmniej dla mnie, gdy za pomocą szpachli.
— kapex

5
używanie mysqldump i mysql z bash staje się znacznie prostsze, jeśli skonfigurujesz plik .my.cnf do przechowywania plików użytkownika / hosta / hasła
— ErichBSchulz 11.11

4
mysqldump -u root -p -v db1 | mysql -u root -p db2i dwa razy wejdź w karnet
— hlcs

6
Boże, czy ktoś mógłby mi wyjaśnić, dlaczego pytanie brzmi „bez mysqldump” ma pierwszą odpowiedź, która używa mysqldump? z jak, 6 razy więcej głosów niż prawidłowy ? no dalej, SO ...
— igorsantos07,

135

Możesz powielić tabelę bez danych, uruchamiając:

CREATE TABLE x LIKE y;

(Zobacz dokumenty MySQL CREATE TABLE )

Możesz napisać skrypt, który pobiera dane wyjściowe SHOW TABLESz jednej bazy danych i kopiuje schemat do innej. Powinieneś być w stanie odwoływać się do schematu + nazw tabel, takich jak:

CREATE TABLE x LIKE other_db.y;

Jeśli chodzi o dane, możesz to zrobić również w MySQL, ale niekoniecznie jest to szybkie. Po utworzeniu odniesień możesz uruchomić następujące polecenie, aby skopiować dane:

INSERT INTO x SELECT * FROM other_db.y;

Jeśli używasz MyISAM, lepiej skopiować pliki tabeli; będzie znacznie szybciej. Powinieneś być w stanie zrobić to samo, jeśli używasz INNODB z obszarami tabel .

Jeśli to zrobisz INSERT INTO SELECT, tymczasowo wyłącz indeksy za pomocą ALTER TABLE x DISABLE KEYS!

EDIT Maatkit ma również kilka skryptów, które mogą być pomocne w synchronizacji danych. To może nie być szybsze, ale prawdopodobnie możesz uruchomić ich skrypty synchronizujące na danych na żywo bez większego blokowania.


1
czy to działa dla zduplikowanej tabeli? ponieważ widzę, że polecenie brzmi: UTWÓRZ TABELĘ
— GusDeCooL

4
Można to zrobić CREATE TABLE ... SELECT.
— eggyal

3
Próbowałem raz skopiować pliki tabeli bazy danych MyISAM, ale to tylko uszkodziło nową bazę danych. Prawdopodobnie moje złe, ale zdecydowanie nie jest to tak trywialna operacja, jak niektórzy twierdzą.
— Johan Fredrik Varen

2
To fajna sztuczka i jestem fanem, ale ważna uwaga: nie przenosi żadnych ograniczeń klucza obcego (nawet tych, które są zewnętrzne w stosunku do kopiowanego schematu) na MySQL Docs
— abigperson

59

Jeśli używasz Linuksa, możesz użyć tego skryptu bash: (być może wymaga dodatkowego czyszczenia kodu, ale działa ... i jest znacznie szybszy niż 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

7
Jeśli używasz powyższego skryptu z tabelami InnoDB i posiadasz klucze obce, zmień ostatni wiersz na następujący:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
— pegli

Czy to również kopiuje dane ograniczeń i inne właściwości tabel?
— Lucas Moeskops,

1
Wydaje się, że tak, ponieważ używa instrukcji „POKAŻ KREATYWNĄ TABELĘ”, która generuje KREATYWNĄ TABELĘ ze wszystkimi właściwościami oryginału.
— Danita

1
Jeśli napotkasz problem opisany przez @zirael, to prawdopodobnie dlatego, że skrypt nie kopiuje widoków. Możesz zignorować widoki z kopii, zmieniając SHOW TABLESwiersz na SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'i dodając | cut -f 1. Pełna linia powinna wyglądać mniej więcej tak, ale należy zastąpić podwójne backticks pojedynczymi backticks: 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
Wyczyściłem ten skrypt przez @jozjan i zastosowałem niektóre komentarze dotyczące kluczy obcych i innych, aby utworzyć tę wersję na GIST gist.github.com/christopher-hopper/8431737
— Christopher

11

W 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

Jeśli pracujesz na komputerze z systemem Windows. Następnie skorzystaj z tego, zamiast znajdować długie sposoby wykonywania polecenia.
— Parixit 11.04.17

ten skrypt nie uwzględnia wyświetleń
— sd1sd1

4

Zauważ, że istnieje komenda mysqldbcopy jako część narzędzia add on mysql .... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html


Wymaga to jednak instalacji dodatkowego pakietu:apt install mysql-utilities
— Joel G Mathew

2
Ale nie było żadnych ograniczeń mówiących, że to niemożliwe ... i jest to rzecz powszechnie instalowana (ale opcjonalna, jak mówisz) Jeśli nie zostanie zainstalowana, wielu uważa, że ​​instalowanie tego pakietu jest łatwiejsze niż konfigurowanie i uruchamianie 60-liniowego skryptu Bash , etc ....
— furicle

Twój post został prawdopodobnie odrzucony, ponieważ nie podałeś żadnych innych informacji niż link. Odpowiedzi powinny być bardziej wyczerpujące.
— Joel G Mathew

1

Naprawdę nie wiem, co rozumiesz przez „dostęp lokalny”. Ale w przypadku tego rozwiązania musisz mieć dostęp przez serwer ssh do kopiowania plików, w których przechowywana jest baza danych .

Nie mogę użyć mysqldump, ponieważ moja baza danych jest duża (7Go, mysqldump fail) Jeśli wersja 2 mysql bazy danych jest zbyt inna, może nie działać, możesz sprawdzić swoją wersję mysql za pomocą mysql -V.

1) Skopiuj dane ze zdalnego serwera na komputer lokalny (vps to alias do zdalnego serwera, można go zastąpić root@1.2.3.4)

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) Zaimportuj dane skopiowane na komputer lokalny

/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

Jeśli masz inną wersję, może być konieczne uruchomienie

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

Jest to najbardziej efektywny sposób, aby to zrobić, ale myślę, że „bez lokalnego dostępu do serwera” oznacza, że ​​nie możemy uzyskać dostępu do systemu. Prawdopodobnie hosting współdzielony? To nie jest odpowiedź.
— Valerio Bozz,

1

Wszystkie poprzednie rozwiązania są trochę w punkcie, jednak po prostu nie kopiują wszystkiego. Stworzyłem funkcję PHP (choć nieco dłuższą), która kopiuje wszystko, w tym tabele, klucze obce, dane, widoki, procedury, funkcje, wyzwalacze i zdarzenia. Oto 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]));
        }
    }
}

Odebrano, ponieważ pytanie nie brzmi „nie używaj mysqldump”, ale „użyj lepszego podejścia niż mysqldump”. Jest to jeszcze gorsze pod mysqldumpwzględem wydajności.
— Valerio Bozz,

1

Właściwie chciałem osiągnąć dokładnie to w PHP, ale żadna z odpowiedzi tutaj nie była bardzo pomocna, więc oto moje - dość proste - rozwiązanie z 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;

Nie jestem pewien, czy tihis tworzy klon 1: 1, ale wygląda na to, że proste bazy danych mogą być wystarczające.
— beppe9000

Używam tego do tworzenia szybkich instalacji WordPress na moim serwerze programistycznym. Ta część w połączeniu z innymi procedurami powiela się i dostosowuje instalację źródłową do nowego projektu. Do tego działa dobrze… ale pusta baza danych wordpress nie jest bardzo skomplikowana, więc nie mogę wydać oświadczenia w przypadku bardziej rozszerzonych przypadków użycia
— GDY

0

Najlepszy sposób klonowania tabel bazy danych bez mysqldump:

  1. Utwórz nową bazę danych.
  2. Twórz zapytania do klonowania za pomocą zapytania:

    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. Uruchom to wyjście!

Ale zauważ, skrypt powyżej szybkich tabel klonowania - nie widoków, wyzwalaczy i funkcji użytkownika: możesz szybko uzyskać strukturę mysqldump --no-data --triggers -uroot -ppassword, a następnie użyć do klonowania tylko instrukcji wstawiania.

Dlaczego to prawdziwe pytanie? Ponieważ przesyłanie mysqldumps jest brzydko wolne, jeśli DB przekracza 2 Gb. Nie można klonować tabel InnoDB po prostu poprzez kopiowanie plików DB (takich jak tworzenie kopii zapasowych migawek).


0

SQL, który pokazuje polecenia SQL, należy uruchomić, aby zduplikować bazę danych z jednej bazy danych do drugiej. dla każdej tabeli jest tworzona instrukcja tabeli i instrukcja wstawiania. zakłada, że ​​obie bazy danych znajdują się na tym samym serwerze:

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 nie jest złym rozwiązaniem. Najprostszy sposób na zduplikowanie bazy danych:

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

Możesz także zmienić silnik pamięci masowej w ten sposób:

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.