没有本地访问服务器,有没有办法复制/克隆一个MySQL数据库(有内容和没有内容)到另一个不使用mysqldump?

我目前使用的是MySQL 4.0。


当前回答

没有mysqldump克隆数据库表的最好方法:

创建一个新数据库。 使用query创建clone-queries: SET @NewSchema = 'your_new_db'; SET @OldSchema = 'your_exists_db'; SELECT CONCAT('CREATE TABLE ',@NewSchema,')。',table_name,' LIKE ', TABLE_SCHEMA,'.',table_name,';插入',@NewSchema,'。”,table_name“SELECT * FROM”,TABLE_SCHEMA。“table_name,”,”) 从information_schema。TABLE_SCHEMA = @OldSchema AND TABLE_TYPE != 'VIEW'; 运行输出!

但是请注意,上面的脚本只是快速克隆表-而不是视图,触发器和用户函数:你可以通过mysqldump——no-data——triggers -uroot -ppassword快速获得结构,然后使用仅克隆插入语句。

为什么这是实际问题?因为如果DB超过2Gb, mysqldump的上传速度非常慢。你不能仅仅通过复制DB文件来克隆InnoDB表(比如快照备份)。

其他回答

所有先前的解都在这一点上,但是,它们并没有完全复制。我创建了一个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]));
        }
    }
}

我真的不知道你说的“本地访问”是什么意思。 但是对于这个解决方案,你需要能够通过ssh访问服务器来复制数据库存储的文件。

我不能使用mysqldump,因为我的数据库很大(7Go, mysqldump失败) 如果2个mysql数据库的版本差异太大,可能无法工作,您可以使用mysql -V检查您的mysql版本。

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

运行以下命令可以复制一个没有数据的表:

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也有一些脚本,可能有助于同步数据。它可能不会更快,但您可能可以在没有太多锁定的情况下对实时数据运行他们的同步脚本。

如果你使用的是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

没有mysqldump克隆数据库表的最好方法:

创建一个新数据库。 使用query创建clone-queries: SET @NewSchema = 'your_new_db'; SET @OldSchema = 'your_exists_db'; SELECT CONCAT('CREATE TABLE ',@NewSchema,')。',table_name,' LIKE ', TABLE_SCHEMA,'.',table_name,';插入',@NewSchema,'。”,table_name“SELECT * FROM”,TABLE_SCHEMA。“table_name,”,”) 从information_schema。TABLE_SCHEMA = @OldSchema AND TABLE_TYPE != 'VIEW'; 运行输出!

但是请注意,上面的脚本只是快速克隆表-而不是视图,触发器和用户函数:你可以通过mysqldump——no-data——triggers -uroot -ppassword快速获得结构,然后使用仅克隆插入语句。

为什么这是实际问题?因为如果DB超过2Gb, mysqldump的上传速度非常慢。你不能仅仅通过复制DB文件来克隆InnoDB表(比如快照备份)。