现象:启动MySQL服务时报1067错误,服务无法启动。
查看xxx.err错误日志发现有数据页损坏信息:
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 200.
出现上述现象是由于突然断电、强制关机、强制杀死MySQL进程等操作所导致的。
首先修改my.ini中的innodb_force_recovery参数(4-6),使mysqld跳过恢复步骤,将mysqld启动,将数据导出来然后重建数据库。
innodb_force_recovery可以设置为1-6,大的数字包含前面所有数字的影响。
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):不执行前滚的操作。
注意
当设置参数值大于0后,可以对表进行select,create,drop操作,但insert,update或者delete这类操作是不允许的。
可以尝试使用MySQL的bin目录下的mysqlcheck.exe工具来尝试发现并修复MyISAM表的损坏数据页。
如果仅是MyISAM数据页损坏,修复后,删除my.ini中的innodb_force_recovery参数,尝试启动。
如果是InnoDB数据表发生了数据页损坏,需要导出数据,重新建库。
可以尝试运行
select concat('select 1 from ',table_name,';') from information_schema.tables where table_schema='xxx';查询到的结果定位哪些InnoDB出现了损坏,尝试使用冗余数据修复。
最后使用MySQL5\bin>mysqldump -uroot -pOSSDB123 databasename >e:\xxx.sql导出表结构和数据,使用load重建建库。也可以使用SELECT INTO OUTFILE从数据库转储你的表,通常以这种方法获取的数据是完好的。
下面是网上的一篇相关的文章:
1. 表损坏的原因分析
以下原因是导致mysql表毁坏的常见原因:
1、 服务器突然断电导致数据文件损坏。
2、 强制关机,没有先关闭mysql服务。
3、mysqld进程在写表时被杀掉。
4、 使用myisamchk的同时,mysqld也在操作表。
5、 磁盘故障。
6、 服务器死机。
7、mysql本身的bug。
2.表损坏的症状
一个损坏的表的典型症状如下:
1 、当在从表中选择数据之时,你得到如下错误:
Incorrect key file for table: '...'. Try to repair it
2 、查询不能在表中找到行或返回不完全的数据。
3 、Error: Table 'p' is marked as crashed and should be repaired。
4 、打开表失败:Can’t open file:‘×××.MYI’(errno: 145)。
3.预防MySQL表损坏
可以采用以下手段预防mysql表损坏:
1 、定期使用myisamchk检查MyISAM表(注意要关闭mysqld),推荐使用check table来检查表(不用关闭mysqld)。
2 、在做过大量的更新或删除操作后,推荐使用OPTIMIZE TABLE来优化表,这样既减少了文件碎片,又减少了表损坏的概率。
3 、关闭服务器前,先关闭mysqld(正常关闭服务,不要使用kill -9来杀进程)。
4 、使用ups电源,避免出现突然断电的情况。
5 、使用最新的稳定发布版mysql,减少mysql本身的bug导致表损坏。
6 、对于InnoDB引擎,你可以使用innodb_tablespace_monitor来检查表空间文件内文件空间管理的完整性。
7 、对磁盘做raid,减少磁盘出错并提高性能。
8 、数据库服务器最好只跑mysqld和必要的其他服务,不要跑其他业务服务,这样减少死机导致表损坏的可能。
9 、不怕万一,只怕意外,平时做好备份是预防表损坏的有效手段。
4. MySQL 表损坏的修复
MyISAM 表可以采用以下步骤进行修复 :
1、 使用reapair table或myisamchk来修复。
2、 如果上面的方法修复无效,采用备份恢复表。
具体可以参考如下做法:
阶段1:检查你的表
如果你有很多时间,运行myisamchk *.MYI或myisamchk -e *.MYI。使用-s(沉默)选项禁止不必要的信息。
如果mysqld服务器处于宕机状态,应使用--update-state选项来告诉myisamchk将表标记为'检查过的'。
你必须只修复那些myisamchk报告有错误的表。对这样的表,继续到阶段2。
如果在检查时,你得到奇怪的错误(例如out of memory错误),或如果myisamchk崩溃,到阶段3。
阶段2:简单安全的修复
注释:如果想更快地进行修复,当运行myisamchk时,你应将sort_buffer_size和Key_buffer_size变量的值设置为可用内存的大约25%。
首先,试试myisamchk -r -q tbl_name(-r -q意味着“ 快速恢复模式”)。这将试图不接触数据文件来修复索引文件。如果数据文件包含它应有的一切内容和指向数据文件内正确地点的删除连接,这应该管用并且表可被修复。开始修复下一张表。否则,执行下列过程:
在继续前对数据文件进行备份。
使用myisamchk -r tbl_name(-r意味着“ 恢复模式”)。这将从数据文件中删除不正确的记录和已被删除的记录并重建索引文件。
如果前面的步骤失败,使用myisamchk --safe-recover tbl_name。安全恢复模式使用一个老的恢复方法,处理常规恢复模式不行的少数情况(但是更慢)。
如果在修复时,你得到奇怪的错误(例如out of memory错误),或如果myisamchk崩溃,到阶段3。
阶段3:困难的修复
只有在索引文件的第一个16K块被破坏,或包含不正确的信息,或如果索引文件丢失,你才应该到这个阶段。在这种情况下,需要创建一个新的索引文件。按如下步骤操做:
把数据文件移到安全的地方。
使用表描述文件创建新的(空)数据文件和索引文件:
shell> mysql db_name
mysql> SET AUTOCOMMIT=1;
mysql> TRUNCATE TABLE tbl_name;
mysql> quit
如果你的MySQL版本没有TRUNCATE TABLE,则使用DELETE FROM tbl_name。
将老的数据文件拷贝到新创建的数据文件之中。(不要只是将老文件移回新文件之中;你要保留一个副本以防某些东西出错。)
回到阶段2。现在myisamchk -r -q应该工作了。(这不应该是一个无限循环)。
你还可以使用REPAIR TABLE tbl_name USE_FRM,将自动执行整个程序。
阶段4:非常困难的修复
只有.frm描述文件也破坏了,你才应该到达这个阶段。这应该从未发生过,因为在表被创建以后,描述文件就不再改变了。
从一个备份恢复描述文件然后回到阶段3。你也可以恢复索引文件然后回到阶段2。对后者,你应该用myisamchk -r启动。
如果你没有进行备份但是确切地知道表是怎样创建的,在另一个数据库中创建表的一个拷贝。删除新的数据文件,然后从其他数据库将描述文件和索引文件移到破坏的数据库中。这样提供了新的描述和索引文件,但是让.MYD数据文件独自留下来了。回到阶段2并且尝试重建索引文件。
InnoDB 表可以采用下面的方法修复:
如果数据库页被破坏,你可能想要用SELECT INTO OUTFILE从从数据库转储你的表,通常以这种方法获取的大多数数据是完好的。即使这样,损坏可能导致SELECT * FROM tbl_name或者InnoDB后台操作崩溃或断言,或者甚至使得InnoDB前滚恢复崩溃。 尽管如此,你可以用它来强制InnoDB存储引擎启动同时阻止后台操作运行,以便你能转储你的表。例如:你可以在重启服务器之前,在选项文件的[mysqld]节添加如下的行:
[mysqld]innodb_force_recovery = 4innodb_force_recovery 被允许的非零值如下。一个更大的数字包含所有更小数字的预防措施。如果你能够用一个多数是4的选项值来转储你的表,那么你是比较安全的,只有一些在损坏的单独页面上的数据会丢失。一个为6的值更夸张,因为数据库页被留在一个陈旧的状态,这个状态反过来可以引发对B树和其它数据库结构的更多破坏。
1 (SRV_FORCE_IGNORE_CORRUPT)
即使服务器检测到一个损坏的页,也让服务器运行着;试着让SELECT * FROM tbl_name跳过损坏的索引记录和页,这样有助于转储表。
2 (SRV_FORCE_NO_BACKGROUND)
阻止主线程运行,如果崩溃可能在净化操作过程中发生,这将阻止它。
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被设置为大于0的值时,InnoDB阻止用户执行INSERT, UPDATE或DELETE操作.
即使强制恢复被使用,你也可以DROP或CREATE表。如果你知道一个给定的表正在导致回滚崩溃,你可以移除它。你也可以用这个来停止由失败的大宗导入或失败的ALTER TABLE导致的失控回滚。你可以杀掉mysqld进程,然后设置innodb_force_recovery为3,使得数据库被挂起而不需要回滚,然后舍弃导致失控回滚的表。