在同一台服务器上复制数据库而不会丢失数据

CSc*_*ulz 2 mysql innodb

我想在我的 mysql 服务器上复制一个 innodb 数据库以测试该软件的另一个版本。
使用 phpmyadmin 等工具将数据库减少了大约 20 MB,并且丢失了“很多”行。

只是复制/var/lib/mysql下的文件夹是行不通的,因为我没有为 innodb 引擎启用一些特殊的东西。

如何创建 innodb 数据库的副本?

Mic*_*bot 7

缺少“很多”行

如果您进行调查并解释为什么会发生这种情况,将最符合您的利益。工具或实用程序的神秘行为是不可接受的,因此该工具存在缺陷,或者不打算在您使用它时使用,或者您的数据库结构中存在与某些东西交互的怪癖您用来导致这些问题的实用程序。

作为一名 DBA,我喜欢尽可能地“在操作上接近”服务器,而不需要工具来做出决定并“提供帮助”。我只使用图形查询浏览器做三件事:在我想要滚动结果的地方运行查询、编辑存储的程序以及向大量未记录的表列添加注释。其他一切,我都是手工完成的,因为我喜欢准确地了解服务器被要求做什么,而且我也喜欢服务器了解我。所以,这就是我如何做我认为你所描述的。

我假设您正在谈论将单个服务器上的模式克隆到同一服务器上的不同模式。

从程序上说,“对于`prod_db`中的每个表(或其他对象),在`dev_db`中创建一个同名对象,包括所有索引、引用新模式中适当表的外键约束,以及可选的,复制所有数据。”

这是我如何做到的。

$ mysqldump [options*] --databases prod_db | perl -pe 's/`prod_db`/`dev_db`/g' > dump.sql
Run Code Online (Sandbox Code Playgroud)

这会生成一个人类可读的转储文件,将 `prod_db` 的每个实例(包括反引号)替换为 `dev_db`。Perl 在转储文件通过|管道时处理过滤。然后我检查文件的内容是否完整,并将其通过管道返回到 mysql:

$ mysql < dump.sql
Run Code Online (Sandbox Code Playgroud)

完毕。

现在了解详情。

如果我使用此命令生成的文件的前几行:

$ mysqldump [options] --databases sakila
Run Code Online (Sandbox Code Playgroud)

我在文件开头附近看到了这个:

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `sakila` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */;
USE `sakila`;
Run Code Online (Sandbox Code Playgroud)

现在这个:

$ mysqldump --databases sakila | perl -pe 's/`sakila`/`dolphin`/g' 

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `dolphin` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */;
USE `dolphin`;
Run Code Online (Sandbox Code Playgroud)

魔法。这个过程有一个主要的警告:你不能有一个与原始数据库同名的表,因为表名`sakila`会像数据库名称被更改一样更改为`dolphin`。

* 选项在mysqldump这里非常重要,因为如果你犯了一个错误,你就会冒着破坏你的实时数据库的风险。这个选项特别有用。

--skip-add-drop-table
Run Code Online (Sandbox Code Playgroud)

如果你做一个正常的mysqldump, 在CREATE TABLE结果文件中的each 之前,有一个DROP TABLE IF EXISTS声明。

DROP TABLE IF EXISTS `actor`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `actor` ( ...
Run Code Online (Sandbox Code Playgroud)

当您添加--skip-add-drop-tablemysqldump它时,会将DROP TABLE IF EXISTS语句写入转储文件,因此没有删除错误表的危险。最坏的情况是它会尝试创建一个已经存在的表,如果发生这种情况,脚本将停止。然后你可以找出问题所在。

您还应该添加该--verbose选项,mysqldump因为它会在转储进行时显示您的进度。

--events --triggers --routines
Run Code Online (Sandbox Code Playgroud)

如果您有 MySQL 事件调度程序事件、触发器或存储的函数/过程(“例程”),这些标志将确保 mysqldump 也复制这些。但是,您需要查看它们,以确保对架构的任何引用都是正确的,因为架构名称在这些中可能没有正确反引号。这应该不是主要问题,因为在定义这些时不需要引用模式——它们在定义它们的模式的上下文中运行。

--no-data
Run Code Online (Sandbox Code Playgroud)

如果您只想克隆结构,而不是表中的行,请使用此选项。您还可以使用此选项进行试运行,以检查生成的“dump.sql”文件的完整性。请记住,这些文件仅包含重新创建数据库所需的 SQL 语句,因此是人类可读的。

--single-transaction
Run Code Online (Sandbox Code Playgroud)

当您要转储的表是 InnoDB 时,您想使用它,因为它不会锁定表或阻止其他操作,但它会确保您获得的数据从表到表是一致的,因为它会START TRANSACTION WITH CONSISTENT SNAPSHOT针对原始服务器发出问题在提取转储文件之前。


Perl 在这里做什么?

perl -pe 's/`prod_db`/`dev_db`/g'
Run Code Online (Sandbox Code Playgroud)

我们本质上说的是 perl,-e执行以下小脚本(在引号中)并-p假装我已将此指令包装在一个循环中,上面写着“从标准中读取”、“对数据应用更改”、“打印结果”数据标准输出”。 s/替代,当您看到 `prod_db` 将/其替换为 `dev_db` 并/g全局范围内执行此操作(而不是仅替换任何给定行上的第一次出现,而是替换每个给定行上的每一次出现)。Perl 可以非常有效地进行这种替换,并且几乎适用于每个系统,并且可以免费用于未安装它的系统,包括 Windows。你可以用 做同样的事情sed,命令会类似,但不完全相同。


当我的开发人员需要将整个架构克隆到同一服务器但具有不同架构(数据库)名称时,上述步骤基本上是我执行此操作的方式。