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.

jhornnes
źródło
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]

Rafe
źródło
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.

Gary Richardson
źródło
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
jozjan
źródło
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
mr_app
źródło
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

ząb
źródło
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ć [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) 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
Remy Mellet
źródło
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]));
        }
    }
}
Dustin
źródło
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;
GDY
źródło
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).

Alexander Goncharov
źródło
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';
Shimon Doodkin
źródło
-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

Andy Al
źródło