Скопіюйте / копіюйте базу даних без використання mysqldump


427

Без локального доступу до сервера, чи є можливість копіювати / клонувати MySQL db (із вмістом та без вмісту) в інший без використання mysqldump?

Зараз я використовую MySQL 4.0.


12
Що не так mysqldump?
Майкл Міор

48
Переконайтеся, що ви цього не робите: CREATE TABLE t2 SELECT * FROM t1;оскільки ви втратите інформацію про свій індекс, будь-які спеціальні речі, такі як auto_increment тощо. Багато google для цієї таблиці копій подібні речі приведуть вас до цього, і це матиме небажані результати .
Джон Хант

59
Питання поза темою отримує 92 відгуки та 37 фаворитів. Великі пальці для такого поза тематичного питання. Застарілі вказівки.
pal4life

25
100% погоджуються з тим, що "закрита як поза темою" неправильна і що правила повинні бути оновлені - потрібно більше поблажливості - ТА спрямовується в неправильному напрямку. Очевидно, що @will повністю відзначений, і його права повинні бути усунені - це одне питання є достатньою доказою.
stolsvik

10
Закрито як поза темою на 100% помиляється. Це саме те питання, яке у мене є, і воно має чітко визначену технічну відповідь, яка не стосується простої думки. Я думаю, що модератор, мабуть, робив такі пошуки слів, як "найкраще", щоб знайти питання, які слід закрити.
Сем Голдберг

Відповіді:


686

Я бачу, ви сказали, що не хочете користуватися mysqldump, але я дійшов до цієї сторінки, шукаючи подібне рішення, і інші, можливо, знайдуть його. Зважаючи на це, ось простий спосіб дублювання бази даних з командного рядка сервера Windows:

  1. Створіть цільову базу даних за допомогою MySQLAdmin або бажаного методу. У цьому прикладі db2наведена цільова база даних, куди db1буде скопійована вихідна база даних .
  2. Виконайте таке команду в командному рядку:

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

Примітка. Між -pта між ними немає місця[password]


108
Справа проти mysqldump полягає в тому, що повинен існувати більш швидкий спосіб, а потім серіалізація даних у запити, передача запитів поза процесом і через tty назад в той самий процес , перезапис запитів і виконання їх як заяви. Це звучить жахливо неефективно і непотрібно . Ми не говоримо про перетин між майстрами MySQL або про зміну механізмів зберігання даних. Це шокує, що немає ефективної внутрішньопроцесорної бінарної передачі.
Тоддіус Жо

42
Якщо ви не хочете зберегти пароль відкритим текстом в історії терміналів, вам потрібно розділити команду: mysqldump -h [server] -u [user] -p db1 > db1, в mysql -h [server] -u [user] -p db2 < db1 іншому випадку буде запропоновано ввести пароль столових його, принаймні для мене , коли з допомогою шпаклівки.
kapex

5
використання mysqldump та mysql з bash стає набагато простішим, якщо ви налаштували файл .my.cnf для зберігання файлів користувача / хоста / пароля
ErichBSchulz

4
mysqldump -u root -p -v db1 | mysql -u root -p db2і два рази вводять пропуск
hlcs

6
Боже, міг би хтось пояснити моє питання, чому на запитання "без mysqldump" в якості першого відповіді є такий, який використовує mysqldump? з подібними, на 6 разів більше голосів, ніж за правильний ? давай, ТАК ...
igorsantos07

135

Ви можете скопіювати таблицю без даних, запустивши:

CREATE TABLE x LIKE y;

(Див. Документи MySQL CREATE TABLE )

Ви можете написати сценарій, який приймає вихід SHOW TABLESз однієї бази даних і копіює схему в іншу. Ви повинні мати можливість посилатися на схеми + назви таблиць, наприклад:

CREATE TABLE x LIKE other_db.y;

Що стосується даних, ви також можете це робити в MySQL, але це не обов'язково швидко. Після створення посилань ви можете виконати наступне, щоб скопіювати дані:

INSERT INTO x SELECT * FROM other_db.y;

Якщо ви використовуєте MyISAM, вам краще скопіювати файли таблиці; це буде набагато швидше. Ви можете зробити те ж саме, якщо ви використовуєте INNODB з пробілами таблиці .

Якщо ви все-таки зробите це INSERT INTO SELECT, не забудьте тимчасово відключити індекси за допомогою ALTER TABLE x DISABLE KEYS!

EDIT Maatkit також має кілька сценаріїв, які можуть бути корисними для синхронізації даних. Це може бути не швидше, але ви, ймовірно, можете запустити їхні сценарії синхронізації на живих даних без особливого блокування.


1
це робота для дублювання таблиці? оскільки я бачу, що команда CREATE TABLE
GusDeCooL

4
Можна зробити CREATE TABLE ... SELECT.
eggyal

3
Я спробував один раз скопіювати файли таблиць бази даних MyISAM, але це просто пошкодило нову базу даних. Напевно, це моє погано, але це точно не така тривіальна операція, як деякі кажуть.
Йохан Фредрік Варен

2
Це приємний трюк, і я шанувальник, але важлива примітка: це не переносить жодних обмежень щодо зовнішніх ключів (навіть тих, які є зовнішніми для копіювання схеми) для MySQL Docs
abigperson

59

Якщо ви використовуєте Linux, ви можете використовувати цей скрипт bash: (можливо, потрібна додаткова чистка коду, але вона працює ... і це набагато швидше, ніж 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
Якщо ви використовуєте сценарій вище з таблицями InnoDB і маєте зовнішні ключі, змініть останній рядок на такий:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
pegli

Чи це також копіює дані обмежень та інші властивості таблиць?
Лукас Moeskops

1
Це здається, тому що він використовує оператор "SHOW CREATE TABLE", який генерує CREATE TABLE з усіма властивостями оригіналу.
Даніта

1
Якщо у вас виникла проблема @zirael описана, це, мабуть, через те, що сценарій не копіює представлення даних. Ви можете ігнорувати перегляди з копії, змінивши SHOW TABLESрядок на SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'та додавши | cut -f 1. Повний рядок повинен виглядати приблизно так, але замініть подвійні заднім числом на одну задню: for TABLE in ``echo "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" | mysql $DBCONN $DBSNAME | tail -n +2 | cut -f 1``; do
Командир коду

1
Я очистив цей сценарій від @jozjan і застосував деякі коментарі щодо іноземних та інших ключів, щоб створити цю версію на GIST gist.github.com/christopher-hopper/8431737
Крістофер

11

На 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

Якщо ви працюєте на машині Windows. Потім люб’язно використовуйте це замість того, щоб знайти тривалі способи виконання команди.
Parixit

цей сценарій не сприймає переглядів
sd1sd1

4

Зауважте, що команда mysqldbcopy є частиною доповнення утиліти mysql .... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html


Але для цього потрібно встановити додатковий пакет:apt install mysql-utilities
Joel G Mathew

2
Але не було обмежень, сказати, що це неможливо .... і це звичайно встановлена ​​річ (але необов'язково, як ви говорите) Якщо вона не встановлена, багатьом буде встановити цей пакет простіше, ніж налаштувати та запустити 60-рядовий сценарій Bash тощо ....
furicle

Можливо, ваше повідомлення було відхилено, оскільки ви не містили жодної іншої інформації, крім посилання. Відповіді повинні бути більш вичерпними.
Джоель Г Метью

1

Я не знаю, що ви розумієте під "місцевим доступом". Але для цього рішення вам потрібно мати доступ через сервер ssh для копіювання файлів, де зберігається база даних .

Я не можу використовувати mysqldump, тому що моя база даних велика (7Go, помилка mysqldump) Якщо версія 2 mysql бази даних занадто інша, вона може не працювати, ви можете перевірити свою версію mysql за допомогою mysql -V.

1) Скопіюйте дані з віддаленого сервера на локальний комп'ютер (vps - псевдонім на віддалений сервер, його можна замінити на 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) Імпортуйте дані, скопійовані на локальний комп'ютер

/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

Якщо у вас інша версія, можливо, вам доведеться запустити

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

Це найефективніший спосіб зробити це, але я думаю, що "без локального доступу до сервера" означає, що ми не можемо отримати доступ до системи. Можливо, спільний хостинг? Тож це не відповідь.
Валеріо Бозз

1

Усі попередні рішення отримують точку з точки зору, однак вони просто не копіюють усе. Я створив функцію PHP (хоч і дещо тривалу), яка копіює все, включаючи таблиці, зовнішні ключі, дані, представлення даних, процедури, функції, тригери та події. Ось код:

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

Незважаючи на те, що питання не в тому, щоб "не використовувати mysqldump", а "використовувати кращий підхід, ніж mysqldump". Це ще гірше з mysqldumpточки зору ефективності.
Валеріо Бозз

1

Насправді я хотів досягти саме цього в PHP, але жодна з відповідей тут не була дуже корисною, тому ось моє - досить просте - рішення за допомогою 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;

Я не впевнений, що тихіс робить клон 1: 1, але схоже, що для простих баз даних може бути достатньо.
beppe9000

Я використовую це для створення швидких установок WordPress на своєму сервері розробки. Ця частина в поєднанні з деякими іншими процедурами дублюється і налаштовує встановлення джерела в новий проект. Для цього це працює чудово… але пуста база даних Wordpress не дуже складна, тому я не можу зробити заяву для більш розширених випадків використання
GDY

0

Найкращий спосіб клонування таблиць баз даних без mysqldump:

  1. Створіть нову базу даних.
  2. Створіть запити клонів із запитом:

    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. Запустити цей вихід!

Але зауважте, сценарій вище просто таблиць швидкого клонування - не перегляди, тригери та функції користувача: ви можете швидко отримати структуру mysqldump --no-data --triggers -uroot -ppassword, а потім використовувати для клонування лише вставити оператор.

Чому це актуальне питання? Оскільки завантаження mysqldumps некрасиво повільне, якщо БД перевищує 2 Гб. І ви не можете клонувати таблиці InnoDB, просто скопіювавши файли БД (наприклад, резервне копіювання знімків).


0

SQL, який показує команди SQL, потрібно запустити, щоб дублювати базу даних з однієї бази даних в іншу. для кожної таблиці створено оператор таблиці та оператор вставки. передбачається, що обидві бази даних є на одному сервері:

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 не є поганим рішенням. Найпростіший спосіб копіювання бази даних:

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

Також ви можете змінити двигун зберігання таким чином:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.