从 MyISAM 在线转换为 InnoDB 后行丢失

Yuv*_*uvi 16 mysql innodb myisam

我们有一个相当小的数据库,我们想将它从 MyISAM 转换为 InnoDB。作为数据库新手,我们只是转换(使用alter table),甚至没有关闭站点。

现在转换完成了,很多断断续续的行似乎丢失了。这可能是由于转换期间的操作造成的吗?还是其他地方的问题?

ran*_*omx 20

执行 ALTER 来更改存储引擎不会使行消失。但是,让我提供一些建议,因为您在问题中说您是“数据库菜鸟”。

在修改现有架构或执行任何可能影响数据的操作时,以下是一些基本建议:

  1. 先做好备份。
  2. 有一个改变计划。
  3. 在离线主机上测试您的计划。
  4. 有一个测试计划来比较之前和之后的数据。
  5. 安排并采取停机时间。
  6. 在停机时间生效并确认流量已停止后,立即进行备份和快照。
  7. 如果您正在运行 MYISAM,请在 ALTER 之前使用“CHECK TABLE”来评估您正在处理的内容。
  8. 除了备份之外,还可以在本地复制表,以防万一。
  9. 谨慎行事,启用“--show warnings”和其他输出,以便您在进行更改时获得全貌。
  10. 如果数据对您很重要,请聘请 DBA,即使只是在迁移期间进行咨询,以便您身边有经验丰富的老手。

我可能还有很多东西可以讨论,但是当出现问题时,上面的内容将为您提供选择。

就您丢失的数据/行而言,无法知道没有“之前/之后”快照进行比较。您可以与最新的备份进行比较,以至少验证这么多。


Rol*_*DBA 8

在没有大量停机的情况下将 MyISAM 转换为 InnoDB 的最佳方法之一只有一个先决条件:使用复制从站。

这是该计划的鸟瞰图

  1. 创建复制主/从设置
  2. 将 slave 上的每个 MyISAM 表转换为 InnoDB
  3. 将您的应用指向 Slave

听起来很简单?这背后有很多细节。

创建复制主/从设置

有一种巧妙的方法可以创建一个 Slave 而不会对 Master 造成太多干扰。我写了两个帖子:

请阅读这两篇文章,而不是详细说明如何使用 rsync。

将 slave 上的每个 MyISAM 表转换为 InnoDB

在 DB Slave 上,您可以执行以下 SQL 语句:

对于 MySQL 5.5:

SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' ENGINE=InnoDB;')
FROM information_schema.tables
WHERE engine = 'MyISAM' AND table_schema NOT IN
('information_schema','mysql','performance_schema');
Run Code Online (Sandbox Code Playgroud)

MySQL 5.5 之前的 MySQL 版本

SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' ENGINE=InnoDB;')
FROM information_schema.tables
WHERE engine = 'MyISAM' AND table_schema NOT IN
('information_schema','mysql');
Run Code Online (Sandbox Code Playgroud)

使用查询的输出,您就有了从站的转换脚本。

您必须将这两行放在脚本的顶部:

SET SQL_LOG_BIN = 0;
STOP SLAVE;
Run Code Online (Sandbox Code Playgroud)

该脚本将首先禁用二进制日志(如果您将从属配置为具有二进制日志),停止复制,并将每个 MyISAM 表转换为 InnoDB。

以下是创建该脚本并执行它的方法:

SQLSTMT="SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' ENGINE=InnoDB;') FROM information_schema.tables WHERE engine = 'MyISAM' AND table_schema NOT IN ('information_schema','mysql','performance_schema')"
INNODB_CONV_SCRIPT=MassConvertMyISAMTablesToInnoDB.sql
echo "SET SQL_LOG_BIN = 0;" > ${INNODB_CONV_SCRIPT}
echo "STOP SLAVE;" >> ${INNODB_CONV_SCRIPT}
mysql -h(IP of Master) -u... -p... --skip-column-names -A -e"${SQL}" >> ${INNODB_CONV_SCRIPT}
echo "START SLAVE;" >> ${INNODB_CONV_SCRIPT}
mysql -h(IP of Slave) -u... -p... --skip-column-names -A < ${INNODB_CONV_SCRIPT}
Run Code Online (Sandbox Code Playgroud)

将您的应用指向 Slave

从 Slave 执行 SELECT 查询。如果您对 Slave 上的数据内容感到满意,请随时将您的应用指向 Slave,如下所示:

  1. 在 Slave 上,运行SHOW SLAVE STATUS\G并确保 Seconds_Behind_Master 为 0
  2. 在 Slave 上, mysqldump -h(IP of Slave) -u... -p... --single-transaction --routines --triggers --all-databases > MySQLBackup.sql (嘿,备份会很好对大约现在)
  3. 在 Master 上,运行service mysql stop(停机时间开始)
  4. 重复步骤 1
  5. 将您的应用指向 Slave(停机时间在应用首次连接时结束)

如果你做到这一点毫发无损,恭喜!

附加奖励:如果你设置主/主复制(又名循环复制)而不是主/从,你可以这样做:

  1. 在 Slave 上,运行SHOW SLAVE STATUS\G并确保 Seconds_Behind_Master 为 0
  2. 在 Slave 上, mysqldump -h(IP of Slave) -u... -p... --single-transaction --routines --triggers --all-databases > MySQLBackup.sql (嘿,备份会很好对大约现在)
  3. 将您的应用指向 Slave(停机时间在应用的第一次连接时开始和结束)
  4. 在新的 Master 上,运行 STOP SLAVE;
  5. 在新的 Master 上,运行 CHANGE MASTER TO MASTER_HOST='';

您现在拥有的是反向的主/从。新的 Master 有 InnoDB 数据,旧的 Master 现在是一个拥有 MyISAM 数据的 slave。如果拆分读取和写入,则可以从 Slave 读取(从 MyISAM 读取比 InnoDB 快),写入到 Master(对 InnoDB 的事务支持)。就像汉娜·蒙塔娜 (Hannah Montana) 唱的那样,您可以两全其美(是的,我有两个喜欢这个节目的女儿)!!!

另一个额外的好处:因为 Master 现在是 InnoDB,你可以从 Master 执行 mysqldump,而不会停机,也不会干扰事务。唯一的缺点是增加了 CPU 和磁盘 I/O。因此,您可以仅在主服务器(InnoDB)上进行表结构的 mysqldump 和仅在从服务器上进行数据的 mysqldump(此类转储将没有对 InnoDB 或 MyISAM 的引用。它只是数据)加上从站的表结构具有 MyISAM 布局。

由于这个新设置,可能性可以继续......

更新 2011-08-27 19:50 EDT

我很抱歉。我没有完全阅读这个问题。您已经执行了转换

只有当你已经打开了二进制日志,并且你有一个之前的备份,你才可以

  • 将 /var/lib/mysql 恢复到另一个位置,例如 /var/lib/mysql2
  • service mysql stop
  • service mysql start --datadir=/var/lib/mysql2
  • mysqldump 数据库从该备份到 /root/olddata.sql
  • 对自上次备份到 /root/changes.sql 后的时间点 /var/lib/mysql(不是 /var/lib/mysql2)中的所有二进制日志运行 mysqlbinlog
  • 将changes.sql加载到mysql中(因为它仍然指向/var/lib/mysql2)

这应该捕获记录的所有内容并且应该开始转换。同样,这取决于您在上次备份之前已经打开了二进制日志记录。否则,我的哀悼。