【问题标题】:Copy/duplicate database without using mysqldump不使用 mysqldump 复制/复制数据库
【发布时间】:2010-09-06 17:59:17
【问题描述】:

如果没有对服务器的本地访问,有没有办法在不使用 mysqldump 的情况下将 MySQL 数据库(有内容和无内容)复制/克隆到另一个数据库中?

我目前使用的是 MySQL 4.0。

【问题讨论】:

  • “无 mysqldump”要求是否有原因?如果我记得的话,它可以用来连接远程服务器。
  • mysqldump 有什么问题?
  • 确保你不要这样做:CREATE TABLE t2 SELECT * FROM t1; 因为你会丢失你的索引信息,像 auto_increment 等任何特殊的东西。很多谷歌的这个副本表某种事情会导致您这样做,并且会产生不希望的结果。
  • 我正在使用 MySQL Workbench。在 MySQL Utilities 中有一个 mysqldbcopy 命令对我有用。
  • @MichaelMior mysqldump 适用于小型数据库,但最近一次高度索引数据库的转储将花费我 40 多个小时才能从转储中恢复。这就是为什么 MySQL 企业有一个企业备份,价格为 5000 美元。 PS:我将通过让我们使用 InnoDB 并执行快速备份和恢复来提供保持参照完整性的答案。

标签: mysql


【解决方案1】:

我可以看到您说您不想使用 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] 之间没有空格

【讨论】:

  • 反对 mysqldump 的情况是,必须有一种更快的方法,然后将数据序列化为查询,将查询传输到进程之外并通过 tty 返回到 完全相同的过程,重新解析查询,并将它们作为语句执行。这听起来非常低效和不必要。我们不是在谈论 MySQL 主服务器之间的交叉或更改存储引擎。令人震惊的是没有有效的进程内二进制传输。
  • 如果您不想将密码明文保存在终端历史记录中,则需要拆分命令:mysqldump -h [server] -u [user] -p db1 > db1mysql -h [server] -u [user] -p db2 < db1 否则密码提示会搞砸,至少对我来说使用腻子时。
  • 如果您设置 .my.cnf 文件来存储您的用户/主机/密码文件,那么在 bash 中使用 mysqldump 和 mysql 会变得更加简单
  • mysqldump -u root -p -v db1 | mysql -u root -p db2 两次进入pass
  • 天哪,请有人解释一下为什么说“没有 mysqldump”的问题作为使用 mysqldump 的第一响应?喜欢,比 正确 多 6 倍的选票?来吧,所以...
【解决方案2】:

您可以通过运行复制没有数据的表:

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 与 per table table spaces 一起使用,您应该也可以这样做。

如果您最终执行了INSERT INTO SELECT,请务必暂时将turn off indexesALTER TABLE x DISABLE KEYS 联系起来!

EDIT Maatkit 也有一些可能有助于同步数据的脚本。它可能不会更快,但您可以在没有太多锁定的情况下在实时数据上运行他们的同步脚本。

【讨论】:

  • 这适用于重复表吗?因为我看到命令是 CREATE TABLE
  • 你可以做CREATE TABLE ... SELECT
  • 我尝试复制 MyISAM 数据库的表文件一次,但这只是损坏了新数据库。可能是我的错,但它绝对不像某些人说的那样微不足道。
  • 这是一个很好的技巧,我是一个粉丝,但重要的一点是:这不会继承任何外键约束(即使是外部的模式被复制)每个MySQL Docs
【解决方案3】:

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

【讨论】:

  • 如果您将上述脚本与 InnoDB 表一起使用并且有外键,请将最后一行更改为以下内容:echo "set foreign_key_checks = 0; $fCreateTable ; $fInsertData ; set foreign_key_checks = 1;" | mysql $DBCONN $DBNAME
  • 这是否也复制了表的约束数据和其他属性?
  • 看起来是这样,因为他使用“SHOW CREATE TABLE”语句生成具有原始所有属性的 CREATE TABLE。
  • 如果您遇到@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
  • 我已经清理了 @jozjan 的这个脚本,并应用了一些关于外键和其他键的 cmets 在 GIST gist.github.com/christopher-hopper/8431737上创建这个版本@
【解决方案4】:

在 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 机器上工作。然后请使用它而不是寻找冗长的方法来执行命令。
  • 此脚本不计入浏览次数
【解决方案5】:

注意有一个 mysqldbcopy 命令作为添加 mysql 实用程序的一部分.... https://dev.mysql.com/doc/mysql-utilities/1.5/en/utils-task-clone-db.html

【讨论】:

  • 但是需要安装额外的包:apt install mysql-utilities
  • 但是没有限制说这是不可能的......而且这是一个通常安装的东西(但正如你所说的那样是可选的)如果没有安装,许多人会发现安装该软件包比设置更容易启动并运行 60 行 Bash 脚本等......
  • 您的帖子可能被否决了,因为您除了链接之外没有包含任何其他信息。答案应该更全面。
【解决方案6】:

所有先前的解决方案都有一点点,但是,它们只是不会复制所有内容。我创建了一个 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 还要糟糕。
【解决方案7】:

实际上我想在 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;

【讨论】:

  • 我不确定 tihis 是否会进行 1:1 克隆,但看起来对于简单的数据库可能就足够了。
  • 我正在使用它在我的开发服务器上创建快速的 WordPress 安装。这部分与其他一些例程配对,将源​​安装复制并调整到新项目中。为此,它工作得很好……但是空白的 wordpress 数据库不是很复杂,所以我无法为更多扩展用例发表声明
【解决方案8】:

我真的不知道您所说的“本地访问”是什么意思。 但是对于该解决方案,您需要能够通过 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

【讨论】:

  • 这是最有效的方法,但我认为“没有本地访问服务器”意味着我们无法访问系统。可能是共享主机?所以这不是答案。
【解决方案9】:

不用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 快速获取结构,然后使用仅克隆插入语句。

为什么这是实际问题?因为如果 DB 超过 2Gb,mysqldumps 的上传速度很慢。而且您不能仅通过复制数据库文件(如快照备份)来克隆 InnoDB 表。

【讨论】:

    【解决方案10】:

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

    【讨论】:

      【解决方案11】:

      Mysqldump 是不错的解决方案。复制数据库的最简单方法:

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

      另外,您可以通过这种方式更改存储引擎:

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

      【讨论】:

        猜你喜欢
        • 2014-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-21
        • 1970-01-01
        相关资源
        最近更新 更多