存档

2017年12月 的存档

Mysql INNODB存储引擎表损坏修复方法(转)

2017年12月10日 没有评论

设你正在运行使用InnoDB表格的MySQL,糟糕的硬件设备,驱动程序错误,内核错误,不幸的电源故障或某些罕见的MySQL错误使你的InnoDB表空间被损坏了。
在这种情况下,InnoDB的一般会出现这样的输出:

InnoDB: Database page corruption on disk ora failed
InnoDB: file read of page 7.
InnoDB: You may have to recover from a backup.
080703 23:46:16 InnoDB: Page dump in ascii and hex (16384bytes):
… 这里省略很多二进制和十六进制编码…
080703 23:46:16 InnoDB: Page checksum 587461377,prior-to-4.0.14-form checksum 772331632
InnoDB: stored checksum 2287785129, prior-to-4.0.14-form storedchecksum 772331632
InnoDB: Page lsn 24 1487506025, low 4 bytes of lsn at page end1487506025
InnoDB: Page number (if stored to page already) 7,
InnoDB: Database page corruption on disk or a failed

mysqldump导出库时报错如下:
“mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `; at row:6880″
或是操作对应表时,也会报错。这时数据库会重启。
当时想到的是在修复之前保证数据库正常,不是这么异常的无休止的重启。

使用innodb_force_recovery =1,正如你所看到的,即使日志文件中有校验失败的记录,但CHECK TABLE还是说表格是正确的。
这意味着你不能太依赖CHECKTABLE在InnoDB上执行的结果。
所以就修改了配置文件的一个参数:innodb_force_recovery
innodb_force_recovery影响整个InnoDB存储引擎的恢复状况。默认为0,表示当需要恢复时执行所有的,
innodb_force_recovery可以设置为1-6,大的数字包含前面所有数字的影响。
当设置参数值大于0后,可以对表进行select,create,drop操作,但insert,update或者delete这类操作是不允许的。
1(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。
2(SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash。
3(SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。
4(SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。
5(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。
6(SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。
因为错误日志里面提示出现了坏页,导致数据库崩溃,所以这里把innodb_force_recovery 设置为1,忽略检查到的坏页。
重启数据库之后,找到错误信息出现的表

因为后者可以通过使用OPTIMIZE TABLE命令来修复,但这和更难以恢复的表格目录(table dictionary)被破坏的情况来说要好一些。

操作步骤:

修改my.cnf 配置文件,添加innodb_force_recovery = 1运行InnoDB,然后重启mysql 。

1,建议一个备份表,T_MinuteStore_BAK,使用MYISAM存储引擎,建表语句如下:

CREATE TABLE `T_MinuteStore_BAK` (
`T_MinuteStore_ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘行标识’,
`siteID` int(11) DEFAULT NULL COMMENT ‘站点标识’,
`genTime` datetime DEFAULT NULL COMMENT ‘监测时间’,
`itemID` int(11) DEFAULT NULL COMMENT ‘监测项目’,
`value` varchar(255) DEFAULT NULL COMMENT ‘监测值’,
`flag` varchar(255) DEFAULT NULL COMMENT ‘异常标志’,
`filterFlag` bit(1) DEFAULT NULL COMMENT ‘过滤标志’,
PRIMARY KEY (`T_MinuteStore_ID`)
) ENGINE=MYISAM AUTO_INCREMENT=188995 DEFAULT CHARSET=utf8 COMMENT=’监测分钟数据–5分钟一组数据’;

2,把T_MinuteStore表中的数据导入到新表T_MinuteStore_BAK.

insert into T_MinuteStore_BAK select * from T_MinuteStore;

提示报错: 2013 (HY000): Lost connection TO MySQL server during query
你可能想对数据表进行扫描直到第一个被损坏的行,然后从MyISAM表中得到结果?
不幸的是,运行之后的T_MinuteStore_BAK表格是只有一部份数据。
这里查看T_MinuteStore_BAK表中,主键 T_MinuteStore_ID 从最小值到160861,可以看出是被顺序插入的数据。
那么现在就好办了,说明从16081之后,有损坏的数据行。
下面作下插入数据测试,看看大约有多少行数据损坏。
insert into T_MinuteStore_BAK select * from T_MinuteStore where T_MinuteStore_ID>161000;
执行命令后,还是报错。
最后测试;
161500160861
此主键之间的数据,有损坏,其它数据恢复正常。总计100万行数据,只丢了几百行数据,完全可以承受。
3, 删除掉原表: drop table T_MinuteStore;注释掉innodb_force_recovery 之后,重启Mysql。
4,重命名 T_MinuteStore_BAK:

rename table T_MinuteStore_BAK to T_MinuteStore;
5,最后将表T_MinuteStore修改回存储引擎:

alter table T_MinuteStore engine = innodb;

最后将数据库数据导出,测试导出成功,未发现问题。备份好数据,然后更换好硬盘,重装好Mysql ,将数据导入。
测试程序,一切正常。

分类: 解决方案 标签: , ,