更新 MySQL 数据库

Saj*_*Saj 6 mysql database database-administration

我们有一个使用 MySQL 数据库的在线系统。我们需要将旧的备份数据库(完整表,而不是转储文件)与当前数据库合并。在没有经历任何服务器停机的情况下,你会怎么做?请注意,系统 24/7 全天候在线。可能会出现哪些问题?

谢谢你。

And*_*ndy 7

当弄乱 MySQL 的文件系统时,您必须停止 MySQL 服务器。为避免在您的实时机器上停机,请使用具有相同版本的 MySQL 服务器的备份/虚拟机。当BACKUP MySQL 服务器停止时,将表(我假设是 .FRM、.MYI 等?)复制到 /var/lib/mysql/BACKUP_DB(BACKUP_DB 的相应目录)中的文件系统中。

启动BACKUP MySQL 服务器并使用脚本或 CLI 确保数据已正确加载。验证后,mysqldump BACKUP_DB 数据库,以便它可以加载到实时服务器中:

mysqldump --extended-insert BACKUP_DB > /root/sql/BACKUP_DB.sql
Run Code Online (Sandbox Code Playgroud)

您现在已将原始备份数据转换为 SQL 语句,这些 SQL 语句可以在不停机的情况下加载到 MySQL 中(与原始数据不同)。移动BACKUP_DB.sql到现场机器。

作为不同的数据库导入BACKUP_DB.sql到您的LIVE MySQL 实例中:

mysql BACKUP_DB < /root/sql/BACKUP_DB.sql
Run Code Online (Sandbox Code Playgroud)

您现在应该将备份数据库作为 BACKUP_DB 加载到 MySQL 中。

现在,依赖于 INSERT IGNORE 或 REPLACE INTO 语句(您是覆盖旧数据还是在索引中“填充空白”?):

mysqldump --no-create-db
--no-create-info --extended-insert --insert-ignore MERGE_SOURCE | mysql BACKUP_DB
Run Code Online (Sandbox Code Playgroud)

或者,对于 REPLACE INTO 操作:

mysqldump --no-create-db --no-create-info --extended-insert MERGE_SOURCE | sed 's/INSERT INTO/REPLACE INTO/g' | mysql BACKUP_DB
Run Code Online (Sandbox Code Playgroud)

或者,不是将输出管道回 MySQL,而是发送到文件并查看 SQL 语句。

mysqldump --no-create-db --no-create-info --extended-insert --insert-ignore MERGE_SOURCE > /root/sql/merge.sql
mysqldump --no-create-db --no-create-info --extended-insert MERGE_SOURCE | sed 's/INSERT INTO/REPLACE INTO/g' > /root/sql/merge.sql
Run Code Online (Sandbox Code Playgroud)

最后,为了避免停机,将第一个数据库转储到第二个:

mysqldump BACKUP_DB | mysql CURRENT_DB
Run Code Online (Sandbox Code Playgroud)

您始终可以先锁定数据库,以防止将数据写入(例如)带有 a 表中的外键的 z 表(已被覆盖):

FLUSH TABLES WITH READ LOCK;
Run Code Online (Sandbox Code Playgroud)

(按照上一步执行转储)

UNLOCK TABLES;
Run Code Online (Sandbox Code Playgroud)

将 FLUSH 命令添加到转储 .sql 文件的开头,然后将 UNLOCK 添加到结尾。

在这种情况下,请务必四重检查您的数据库名称!询问您不确定的任何后续问题,因为这是高风险的数据混合内容。如果可能,在开发服务器上执行(并详细记录)所需的确切步骤,或虚拟化您的测试,或创建小规模测试。只是测试。而且,当然,进行足够的备份以涵盖所有数据丢失的可能性。


小智 5

对于此示例,假设您的数据库名为“zig”,而您备份的数据库名为“zig_backup”。我还将假设您的备份数据库和您的实时数据库具有相同的架构。

我还将假设您的实时数据库正在不断更新,并且您无法“离线”执行合并,然后翻转开关以使合并的副本“实时”。

需要注意的问题是:

  • 由于某种原因,旧/新中的索引或主键可能会发生冲突(通常是犯了错误,或者记录意外丢失)
  • 自备份以来发生的删除不应“合并”

更新过程将需要根据首先合并哪些表以及最后合并哪些表进行规划。我的一般倾向是先做繁重的工作(大桌子),然后在小桌子上工作。根据您的数据大小,这可能无关紧要。

合并的过程将是:

  1. 使用修改后的数据库名称(例如“zig_backup”)还原实时数据库旁边的备份数据库
  2. 对于实时数据库中的每个表,从备份数据库中合并
  3. 对于备份数据库中的每个表,检查该表是否存在于实时数据库中,如果不存在,则添加它。

最安全的方法是进行全表连接并插入不匹配的行:

for each table in the "live" database:
    INSERT INTO zig.$table
    SELECT BACKUP.* FROM zig_backup.$table AS BACKUP
    LEFT OUTER JOIN zig.$table AS LIVE ON LIVE.ID=BACKUP.ID
    WHERE LIVE.ID IS NULL;
Run Code Online (Sandbox Code Playgroud)

当然,这需要了解每个表的主键。直接的“REPLACE”可能不起作用,因为实时数据库中的行可能已更改,并且它们更改的数据将被

要合并丢失的表,请执行以下操作:

\u zig_backup
SHOW TABLES
Run Code Online (Sandbox Code Playgroud)

要获取所有表的列表,并确定该表是否存在于实时数据库中,您可以执行以下操作:

\u zig
SHOW TABLES LIKE 'tablename';
Run Code Online (Sandbox Code Playgroud)

或者,备份数据库中不存在于“实时”数据库中的表可以二进制复制到实时数据库目录中。

最后,处理从“实时”数据库中删除的内容充其量是困难的,尤其是因为您正在合并某些数据由于某种原因而丢失。