MySQL在Windows系统,OPTIMIZE或REPAIR损坏了大于4GB的MyISAM表

适用于:

MySQL服务器版本5.6及以上

本文信息适用于所有平台。

目标

 

Windows系统,OPTIMIZE TABLE损坏了大于4GB的表。

 

解决方案

Windows创建的bug引起损坏的发生:

http://bugs.mysql.com/bug.php?id=69683

BUG 17235179 OPTIMIZE AFTER A DELETE RETURNS ERROR 0 CAN’T GET STAT OF MYD FILE

解决方案是升级到5.6.19或更新版本。

参考

BUG:17235179 –OPTIMIZE AFTER A DELETE RETURNS ERROR 0 CAN’T GET STAT OF MYD FILE

http://dev.mysql.com/doc/relnotes/mysql/5.6/en/news5619.html

MySQL InnoDB:在文件操作中操作系统错误号1117

适用于:

MySQL 服务器版本4.0到5.7 [发行版4.0到5.7]

本文信息适用于所有平台。

 

目标

问题:

InnoDB将像这样的错误打印到错误日志后,mysqld.exe崩溃:

 

130820 13:37:44 InnoDB: Operating system error number 1117 in a file operation.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operatingsystemerrorcodes.html
InnoDB: File operation call: 'flush'.
InnoDB: Cannot continue operation.

 

解决方案

建议:

 

这不是InnoDB或MySQL问题。

该问题是由于硬盘,控制器,驱动或操作系统。

 

ERROR_IO_DEVICE
1117 (0x45D)
The request could not be performed because of an I/O device error.

 

建议对数据有完整的备份。然后执行硬件诊断来检测错误,使它能被修复或使错误组件被替代。

 

参考

http://msdn.microsoft.com/enus/library/windows/desktop/ms681383(v=vs.85).aspx

什么导致了MySQL InnoDB损坏且如何防护?

适用于:

MySQL服务器版本5.0及以上

本文信息适用于所有平台。

 

目标

学习引起InnoDB损坏最常见的原因以及你如何对其进行防护。

 

解决方案

InnoDB损坏的原因

InnoDB损坏四个主要的原因有:

  • 硬件错误(通常是磁盘或内存)
  • 崩溃 (例如由于断电或操作系统bug引起的)
  • Bugs
  • 不一致的备份

 

除了例如使用错误更正代码(ECC)内存外,防止硬件错误的措施很少。

 

对于由于断电引起的崩溃,UPS是最好的防护。对于有操作系统bug引起的崩溃 (幸好这些是很少发生的),电池备份的磁盘能帮助避免部分写。通常使用innodb_flush_log_at_trx_commit = 1来确保你在同步写入磁盘。

但注意操作系统或磁盘可能并没有实际刷掉写入。因为这个电池备份磁盘是防护。

 

除非按照更改日志并检查是否需要更新,否则bug很难防护。你能在以下找到更改日志:

  • MySQL 5.0
  • MySQL 5.1
  • MySQL 5.5
  • MySQL 5.6
  • MySQL 5.7

 

备份通常比预期的更常引起损坏 (包括不一致性,即在两个表中的数据不一致

)。这个情况的原因是即使有一个FLUSH TABLES WITH READ LOCK,InnoDB 将继续在底部写入数据文件。这表示即使备份方法对于比如MyISAM有作用,它可能对InnoDB不适用。

 

在所有情况中,建议经常备份并验证备份。

 

参考

https://dev.mysql.com/doc/relnotes/mysql/5.5/en/

https://dev.mysql.com/doc/relnotes/mysql/5.6/en/

NOTE:1023132.1 How to Create a Backup of MySQL Server

NOTE:1509073.1 How to Get Started with MySQL Enterprise Backup?

NOTE:1024113.1 InnoDB log buffer flushes to disk after each transaction

https://dev.mysql.com/doc/relnotes/mysql/5.0/en/

https://dev.mysql.com/doc/relnotes/mysql/5.1/en/

https://dev.mysql.com/doc/relnotes/mysql/5.7/en/

https://dev.mysql.com/doc/refman/en/innodbparameters.

html#sysvar_innodb_flush_log_at_trx_commit

https://dev.mysql.com/doc/refman/en/flush.html

NOTE:2017846.1 InnoDB Corruption Recover Guide

NOTE:1502290.1 How to Recover a Corrupted InnoDB Table Definition File

NOTE:1476982.1 What do I do with InnoDB message “Database page corruption on disk or a failed file read of page”

NOTE:2049861.1 Master Note for InnoDB

NOTE:1416063.1 InnoDB Error: “log sequence number is in the future”

 

 

MySQL使用REPAIR TABLE 在MyISAM 表中报告”Table ‘X’ is Read Only” 错误

适用于:

MySQL 服务器版本4.0及以上

本文信息适用于所有平台。

 

症状

在修复一个MyISAM表时,”Table ‘x’ is read only”错误是什么意思,如何修复它?

 

mysql> repair table t;
+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐ ‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
| Table | Op | Msg_type | Msg_text |
+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+
| test.t | repair | Error | Table 't' is read only |
| test.t | repair | status | Operation failed |
+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+

 

原因

这个错误有两个可能的起因:

  1. MyISAM文件MYD或MYI有错误权限且mysqld进程不能写它们
  2. MyISAM表被压缩

 

 

查看MyISAM表是否被压缩,运行

 

show table status like 't';

 

如果表被压缩,Row_format 显示 “Compressed”:

 

 

mysql> show table status like 't'\G


*************************** 1. row ***************************
Name: t
Engine: MyISAM
Version: 10
Row_format: Compressed <‐‐‐‐‐‐‐‐
Rows: 0
Avg_row_length: 0
Data_length: 41
Max_data_length: 281474976710655
Index_length: 1024
Data_free: 0
Auto_increment: NULL
Create_time: 2013‐0 6‐27 19:29:49
Update_time: 2013‐06‐27 19:29:49
Check_time: NULL
Collation: latin 1_swedish_ci
Checksum: 0
Create_options:
Comment:
1 row in s et (0.02 sec)

 

 

解决方案

对于每个可能的原因,(各个)解决方案有:

  1. MyISAM文件MYD或MYI有错误权限且mysqld进程不能写它们,要修复它,在shell上运行:

 

chgrp ‐R mysql <dataDir>
chown ‐R mysql <dataDir>
chmod ‐R 660 <dataDir>

 

  1. MyISAM表被压缩,要修复这个问题在shell运行:

 

myisamchk.exe ‐‐unpack <dataDir>\<db_name>\<table_name>

Then the table can be repaired:

mysql> flush tables;
Query OK, 0 rows affected (0.01 sec)

mysql> repair table t;

+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐ ‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+
| Table | Op | Msg_type | Msg_text |
+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐ ‐‐‐‐+
| test.t | repair | status | OK |
+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+
1 row in set (0.05 sec)

 

参考

https://dev.mysql.com/doc/en/repairtable.html

http://dev.mysql.com/doc/en/myisamchkrepairoptions.html#option_myisamchk_unpack

如何恢复MySQL中受损坏的InnoDB表定义文件

How to Recover a Corrupted InnoDB Table Definition File

 

适用于:

MySQL服务器版本5.0及以上

本文信息适用于所有平台。

你会想要完整的show create table的表输出来重建定义文件。

目标

如何在没有可用备份的情况下重建损坏的Innodb表定义文件。

 

修复

以下文档显示如何恢复InnoDB 中的损坏的表定义文件而无需通过创建一个相同的虚拟表并将它的定义复制到损坏的表中来从备份恢复。

 

 

mysql [localhost] {msandbox} ((none)) > drop database test;
Query OK, 5 rows affected (0.44 sec)

mysql [localhost] {msandbox} ((none)) > create database test;
Query OK, 1 row affected (1.38 sec)

mysql [localhost] {msandbox} ((none)) > create table test.a (b int);
Query OK, 0 rows affected (0.09 sec)

mysql [localhost] {msandbox} (test) > insert into test.a values (1),(2);
Query OK, 2 rows affected (0.53 sec)
Records: 2 Duplicates: 0 Warnings: 0


mysql [localhost] {msandbox} (test) > select * from a;

+‐‐‐‐‐‐+
| b |
+‐‐‐‐‐‐+
| 1 |
| 2 |
+‐‐‐‐‐‐+
2 rows i n set (0.00 sec)

mysql [localhost] {msandbox} ((none)) > \q
Bye

$ ls ‐l data/test/
total 16
‐rw‐rw‐‐ ‐‐ 1 ronan ronan 8554 Oct 30 13:44 a.frm
‐rw‐rw‐‐‐‐ 1 ronan ronan 65 Oct 30 13:44 db.op t

$ file data/test/a.frm
data/test/a.frm: MySQL table definition file Version 9

 

编辑frm文件来模拟损坏。

 

 

$ hexedit data/test/a.frm
00000000 FE 01 09 0C 03 00 00 10 01 00 00 30 00 00 10 00 05 00 00 00 00 00 00 00 00
00 00 02 08 00 08 00 00 05 00 00 00 00 08 00 00 00 00 00 00 00 00 10 00 00 00 5D
...........0.......................................]

 

然后重启数据库以清空文件缓存,现在我们发现文件被损坏且不可访问。

$ ./stop ; ./start

.... sandbox server started

$ ./use ‐Dtest

Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with ‐A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.25‐enterprise‐commercial‐advanced‐log MySQL Enterprise Server ‐
Advanced Edition (Commercial)
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql [localhost] {msandbox} (test) > select * from a;
ERROR 1033 (HY000): Incorrect information in file: './test/a.frm'
mysql [localhost] {msandbox} (test) > \q
Bye

[ronan@hydra msb_5_5_25]$ tail data/msandbox.err
121030 13:52:27 InnoDB: Waiting for the background threads to start
121030 13:52:28 InnoDB: 1.1.8 started; log sequence number 1574983512
121030 13:52:28 [Note] Server hostname (bind‐address): '0.0.0.0'; port: 5525
121030 13:52:28 [Note] ‐ '0.0.0.0' resolves to '0.0.0.0';
121030 13:52:28 [Note] Server socket created on IP: '0.0.0.0'.
121030 13:52:28 [Note] Event Scheduler: Loaded 0 events
121030 13:52:28 [Note] /1/mysql/tgz/5.5.25/bin/mysqld: ready for connections.
Version: '5.5.25‐enterprise‐commercial‐advanced‐log' socket:
'/tmp/mysql_sandbox5525.sock' port: 5525 MySQL Enterprise Server ‐ Advanced Edition
(Commercial)
121030 13:52:31 [ERROR] /1/mysql/tgz/5.5.25/bin/mysqld: Incorrect information in file:
'./test/a.frm'
121030 13:52:32 [ERROR] /1/mysql/tgz/5.5.25/bin/mysqld: Incorrect information in file:
'./test/a.frm'

 

现在,使用相同的create语句,在另一数据库创建同一名称的相同表。现在我们能将该新的定义覆盖旧的损坏表定义( 当数据库下线时)。然后重启,发现我们现在能访问初始表定义和相关的数据了。

 

 

mysql [localhost] {msandbox} (test) > create database dummy;
Query OK, 1 row affected (0.15 sec)

mysql [localhost] {msandbox} (test) > create table dummy.a (b int);
Query OK, 0 rows affected (0.09 sec)

mysql [localhost] {msandbox} (test) > \q
Bye

$ ls ‐l data/dummy/
total 16

‐rw‐rw‐‐ ‐‐ 1 ronan ronan 8554 Oct 30 13:53 a.frm
‐rw‐rw‐‐‐‐ 1 ronan ronan 65 Oct 30 13:52 db.opt


$ ls ‐l data/test/
total 16
‐rw‐rw‐‐ ‐‐ 1 ronan ronan 8554 Oct 30 13:51 a.frm
‐rw‐rw‐‐‐‐ 1 ronan ronan 65 Oct 30 13:44 db.opt

$ ./stop

$ cp data/dummy/a.frm data/test/

$ ./start

... sandbox server started

$ ./use ‐Dtest

Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with ‐A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.25‐enterp rise‐commercial‐advanced‐log MySQL Enterprise Server ‐
Advanced Edition (Commercial)
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql [localhost] {msandbox} (test) > select * from a;
+‐‐‐‐‐‐+
| b |
+‐‐‐‐‐‐+
| 1 |
| 2 |
+‐‐‐‐‐‐+
2 rows i n set (0.00 sec)


mysql [localhost] {msandbox} (test) > \q


现在通过新的表定义能访问初始表数据了。

 

 

 

 

MySQL InnoDB 错误:”log sequence number is in the future”

适用于:

MySQL 服务器4.0及以上

本文信息适用于所有平台

 

症状

当尝试在恢复后使用InnoDB,会发生以下错误。

 

 

ERROR
‐‐‐‐‐ ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
120207 13:30:29 InnoDB: Error: page 573441 log sequence number 22 697197707
InnoDB: is in the future! Current system log sequence number 5 2916730276.
InnoDB: Your database may be corrupt or you may have copied the InnoDB
InnoDB: tablespace but not the InnoDB log files. See
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/forci ng‐recovery.html
InnoDB: for more information.

 

更改

这个问题通常发生在以下更改之后:

  • 如果InnoDB日志文件被删除且这些事件其中之一或更多发生在删除之前(没有任何一个事件是自己发生的—它由以下事件之一以及删除日志文件两个条件而引起):
    • 硬件服务器崩溃
    • Mysqld进程由于kill ‐9或其他原因终止。
    • 数据从一个热备份中恢复。
    • 在使用innodb_fast_shutdown = 2时,MySQL被关闭。
  • MySQL从一个InnoDB不存在或来自其他备份的备份被恢复。
  • MySQL从一个不一致的备份被恢复。
  • 在innodb_force_recovery = 6时,MySQL被启动。

 

原因

根本原因是InnoDB日志文件(重做日志)与数据文件不同步。

当InnoDB中发生更改,更改在被写入数据文件之前先被写入日志文件。在innodb_fast_shutdown = 0或1 (默认)的正常关闭期间,InnoDB会写一个比所有页中的位置更晚的检查点位置,因为它会将它们都刷掉,然后在服务器关闭之前写一个检查点。当innodb_fast_shutdown = 2时,它将它到达的位置写作检查点但不将任何页刷新到当前位置,所以会需要崩溃恢复。该崩溃恢复不会直接引起这个错误,但如果日志文件被删除就会引起,就像在崩溃后能删除它们一样。

 

当InnoDB从磁盘读取页并发出该错误信息时,它将页中位置与日志文件位置比较。

 

日志位置大于当前位置的页不会使用崩溃恢复,直到当前日志位置大于记录的位置。这表示崩溃恢复不能正确运行直到该问题被解决。

 

如果原因与以innodb_force_recovery = 6启动MySQL有关,这会清楚地显示在

MySQL错误日志中。更多信息参见Starting InnoDB on a Corrupted Database。

 

解决方案

选择以下方法之一:

  1. 如果你仍有它们,从备份或复制数据文件的位置恢复初始日志文件。在这个问题发生但没有任何更改的情况下,这会恢复所有数据。
  2. 使用mysqldump来备份数据,删除所有InnoDB表的ib_logfile*, ibdata*, *.ibd, 和*.frm;从转储中重建InnoDB表。一些数据丢失通常在这个情况下发生。
  3. 将所有InnoDB表转换为MyISAM,删除所有ib_logfile*, ibdata*,重启MySQL,并将表转回InnoDB。效果会与方案2相同,所以这个情况同样会发生数据丢失。
  4. 使用InnoDB存储引擎创建一个”work table” ,其大小与日志文件的总大小相同,将数据插入。然后删除这个工作表。通常在这个情况下会发生一些数据丢失。

 

方案2. 和 3. 可以合并。重要的是确保没有剩余的InnoDB表。合并方案2.和3.可以,例如使你将InnoDB表转换为MyISAM,其中没有具体InnoDB信息会丢失且使用mysqldump剩余的表能被备份并在重启后被恢复。

 

要在方案2., 3., 和4.中选择,你通常应该选择能在最短时间完成的方案,但是使用方案4会有较高的未检测问题的可能性,所以使用其他两个方案更好。

 

  1. 恢复初始日志文件

这也会从任何在使用的日志文件丢失的提交或未提交的事务中得到时间,所以这比之后会导致数据丢失的选项好多了。该选项应当被首先使用,除非错误发生后数据被更改了。那样的话,它对于接受旧工作的丢失并保留新工作造成的损失可能最低。

 

  1. 重载数据

在重新初始化所有InnoDB文件之后重载数据来确保一切回到一致状态。

 

步骤是:

  1. 转储所有InnoDB数据。你能用mysqldump 或 SELECT … INTO

OUTFILE完成。确保你也将schema信息如表定义和触发器包括在内。你不需要使用其他存储引擎来包括表。

  1. 停止MySQL。
  2. 删除所有InnoDB特定文件。文件的位置和名称将取决于你的MySQL 配置;默认是所有文件被datadir配置到MySQL数据目录下。你必须删除以下文件:
  • 共享的表空间文件(每个文件默认称为ibdata*)。
  • InnoDB日志文件(重做日志) ib_logfile*。
  • InnoDB表的表定义文件,*.frm。
  • InnoDB表的触发器文件 (*.TRN 和 *.TRG)。
  • InnoDB数据文件,*.ibd。
  1. 启动MySQL并等待InnoDB重新初始化。

当InnoDB完成创建新共享表空间和日志文件,你能在MySQL错误日志中看到。

  1. 重载InnoDB文件的数据和schema。

 

  1. 转换为MyISAM

将InnoDB表转换为MyISAM使你删除InnoDB共享表空间和日志文件,就像方案2,同时避免mysqldump 数据并恢复它。

特别是MySQL 5.1使用InnoDB 插件和MySQL 5.5及以上,你能利用快速索引创建来加速该过程。

 

步骤是:

  1. 对于每个InnoDB表,将表转换为MyISAM选项:

如果你在5.1或MySQL 5.5及以上使用InnoDB插件,还要从表中删除所有secondary索引。

 

删除secondary索引是性能优化,所以执行步骤的这个部分是可选的。对于很大的表,它们会获得最显著的性能提升。

 

例如:

 

ALTER TABLE t1
DROP INDEX va l1,
DROP INDEX val2,
ENGINE=MyISAM;

 

  1. 停止MySQL.
  2. 删除所有InnoDB特定文件。文件的位置和名称将取决于你的MySQL 配置;默认是所有文件被datadir配置到MySQL数据目录下。你必须删除以下文件:

 

共享的表空间文件(每个文件默认称为ibdata*).

 

InnoDB日志文件(重做日志) ib_logfile*.

 

  1. 启动MySQL并等待InnoDB重新初始化。

 

当InnoDB完成创建新共享表空间和日志文件,你能在MySQL错误日志中看到。

 

  1. 对于每个表:
  2. 将表重新转换为InnoDB并重新添加在步骤1被删除的唯一索引。你要在这个阶段操作,因为唯一索引不能利用快速索引创建,所以之后再添加它们会导致完整表的重建:

 

ALTER TABLE t1
ADD UNIQUE ( val1),
ENGINE=InnoDB;

 

  1. 将secondary索引重新添加到表中:

 

ALTER TABLE t1
ADD INDEX (v al2);

 

 

  1. 工作表

该方法会将当期日志序列带回未来报告的序列号之上。你能使用两个序列号之前的区别来估计你需要插入的数据量:

 

120207 13:30:29 InnoDB: Error: page 573441 log sequence number 22 697197707
InnoDB: is in the future! Current system log sequence number 5 2916730276.

 

号码与在SHOW ENGINE INNODB

STATUS (参见Document 1326051.1如何在计算中使用日志序列号的示例)中LOG部分的格式相同,所以两者之间的区别就是:

 

data required = ((22 ‐ 5) * 4 * 1024 * 1024 * 1024) + (697197707 ‐ 2916730276)

= 70794911463 bytes

 

即为66GB左右。

 

注:当使用带有InnoDB插件的MySQL 5.1或MySQL 5.5及以上,日志序列号会包括一个64-位号码而不是两个32-位号码。

 

要执行此方法,创建一个表并持续插入数据直到系统日志序列号赶上日志序列号。完成后,你能再次删除表。

 

这是linux的示例脚本,这会领先日志序列号大约20M:

 

#!/bin/sh
mysql ‐uroot test <<EOF
DROP TABLE IF EXISTS te mp_advance_lsn;
CREATE TABLE temp_advance_lsn (col1 TE XT) ENGINE=InnoDB;
INSERT INTO temp_advance_lsn VALUES (REPEAT('0123456789' , 1000));
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
INSERT INTO temp_advance_lsn SELECT * FROM temp_advance_lsn;
DROP TABLE temp_advance_lsn;
EOF
mysql ‐uroot ‐e 'SHOW ENGINE INNODB STATUS;' \
| sed 's/\n/\n/g' \
| grep '^Log sequenc e'

 

 

 

如果你需要领先日志序列号(LSN)大于20M,那就不能删除表而是TRUNCATE它。然后重复添加数据和清空的进程知道你达到了LSN目标只。每次可以进行大于或小于20M,这只是如何通过较少的数据快速创建较大数据量的一个例子。创建然后破坏任何对你的情况最有效的数据块大小。

 

参考

https://dev.mysql.com/doc/refman/5.6/en/innodbparameters.

html#sysvar_innodb_fast_shutdown

https://dev.mysql.com/doc/refman/5.6/en/innodbmonitors.html

https://dev.mysql.com/doc/refman/5.6/en/selectinto.html

https://dev.mysql.com/doc/refman/5.6/en/innodbbackup.html

https://dev.mysql.com/doc/refman/5.6/en/forcinginnodbrecovery.html

https://dev.mysql.com/doc/refman/5.6/en/innodbparameters.html#sysvar_innodb_force_recovery

NOTE:1380282.1 MySQL Enterprise Backup (MEB) Fails; ERROR: Log scan was only able to reach to; InnoDB: log sequence number is in the future

NOTE:1326051.1 How to Check Whether innodb_log_file_size is Big Enough, InnoDB Redo Log

https://dev.mysql.com/doc/refman/5.6/en/innodbdatalogreconfiguration.html

MySQL: 如何使用myisam-recover-options选项?myisamrecover

适用于:

MySQL 服务器-版本4.0及以上

本文信息适用于所有平台。

 

目标

学习MySQL的myisamrecoveroptions选项并如何将它用于启动服务器时崩溃的MyISAM表的自动修复。

myisam‐recover‐options 在MySQL 5.1及更早版本中叫做mysqlrecover。

 

修复

myisam‐recover‐options选项是用于创建启动MySQL时MyISAM 的自动恢复。myisam‐recover‐options选项能使用以下值:

  • DEFAULT: 不用备份,强制,或快速检查进行恢复。
  • BACKUP: 如果数据文件在恢复时被更改,将MYD 文件的备份保存为 tbl_name‐datetime.BAK。
  • FORCE: 即使会从.MYD 文件丢失多于一行仍运行恢复。
  • QUICK: 如果没有任何delete块就不检查行。

 

myisam‐recover‐options 也允许值的组合,例如果数据文件在恢复时被更改,即使创建备份时丢失了多于一行,FORCE,BACKUP 结合恢复的使用。

 

myisam‐recover‐options的QUICK和DEFAULT值是两个最安全的选项,因为它们不删除任何数据。这也使得它们对于自动恢复是很适合的值。DEFAULT和FORCE的差异是即使FORCE不能从之前完成的语句中找到所有行,它仍被允许继续恢复。因此,建议将FORCE与BACKUP结合,使得在对MyISAM数据文件作更改之前创建一个备份。

 

所以在myisam‐recover‐options 选项使用DEFAULT 是个好方法,但如果失败的话,如果错误经常出现且可以接受潜在丢失数据的风险,建议手动修复并仅使用myisamrecover=FORCE,BACKUP。

 

你应该在执行手动修复之前创建表的备份。

 

如果你需要自动修复表而不重启MySQL ,你需要使用调度服务启 myisamchk, CHECK TABLE,且/或REPAIR TABLE 来定期检查并修复表的错误。MySQL 5.1及以上你能使用EVENTs;在MySQL

5.0及以下,你需要使用操作系统提供的scheduler。

 

如果你选择使用myisamchk,你必须确保在运行myisamchk时没有其他程序在使用表。

参见:

MyISAM Startup Options

Setting Up a MyISAM Table Maintenance Schedule

How to Repair MyISAM Tables

What is a MySQL Event and How is it Created?

 

参考

NOTE:1023216.1 How can I speed up bulk loading or repairing of MyISAM tables?

NOTE:1023264.1 What can Cause Corrupted MyISAM Tables in MySQL Server?

NOTE:1023408.1 Error: 1034 Incorrect key file for table ‘%s’; try to repair it Or ERROR 126

(HY000): Incorrect key file for table ‘%s’; try to repair it From MySQL Server

NOTE:1023752.1 Error: 1195 Table ‘%s’ is marked as crashed and last (automatic?) repair failed.

NOTE:1023780.1 Error: 1035 Old key file for table ‘%s’; repair it!

NOTE:1024132.1 What is a MySQL Event and How is it Created?

Didn’t find what you are looking for?

MySQL InnoDB表的Table is Full错误

症状

4.x, 5.0.84 及以下, 5.1.37 及以下, 带 InnoDB 插件的5.1.40及以下

使用 InnoDB 表空间且不使用 innodb_file_per_table 的所有版本

 

重现问题:

使用自动扩展 InnoDB 表空间包括使用 innodb_file_per_table 的所有版本

 

原因

4.x, 5.0.84 及以下, 5.1.37 及以下, 及带 InnoDB 插件的5.1.40 及以下

使用 fixed size InnoDB 表空间和不使用 innodb_file_per_table的所有版本

使用自动扩展InnoDB 表空间包括使用 innodb_file_per_table的所有版本

 

解决方案

Versions 4.x, 5.0.84 及以下, 5.1.37 及以下, 带 InnoDB 插件的5.1.40 及以下

使用固定大小InnoDB 表空间和不使用 innodb_file_per_table 的所有版本

使用自动扩展 InnoDB 表空间包括使用 innodb_file_per_table 的所有版本

 

 

应用于:

MySQL服务器版本4.0 及以上

本文信息适用于所有平台。

 

症状

这个错误的方式有两种可能:

4.x, 5.0.84 及以下, 5.1.37 及以下,以及带InnoDB插件的5.1.40及以下版本

当运行以下MySQL 服务器版本之一:

  • MySQL 4.0 和1的所有版本
  • 0.84 及以下
  • 不带InnoDB插件的MySQL 5.1:1.37 及以下
  • 带InnoDB插件的MySQL 5.1:1.40 及以下

 

当有多于1023个动态事务且错误信息”Table is Full”被返回到客户端。有时会发生插入错误。错误日志会包含一个更描述性的错误信息:

 

110912 14:52:14 InnoDB: Warning: cannot find a free slot for an undo log. Do you have too
InnoDB: many active transactions running concurrently?

 

所有版本 使用固定大小的 InnoDB 表空间且不使用 innodb_file_per_table

当 InnoDB 表空间设为固定大小且不使用 innodb_file_per_table 选项时,尝试将数据插入InnoDB 表时,会发生以下错误:

 

The table ‘<tablename>’ is full

 

其中<tablename> 是表名。相应的 MySQL 错误代码和SQL 状态是:

 

MySQL Error Code: 1114

SQLState: HY000

 

显示在MySQL错误日志中的错误取决于在使用的InnoDB存储引擎版本:

  • 对于带InnoDB插件的MySQL 5.1 和MySQL 5.5 及以上,错误日志包含如下错误:

 

InnoDB: Error: Data file(s) ran out of space.

Please add another data file or use ‘autoextend’ for the last data file.

110908 12:18:13 [ERROR] /usr/sbin/mysqld: The table ‘<tablename>’ is full

 

 

  • 对于MySQL/InnoDB 更早的版本(包括有InnoDB的buildin版本的MySQL 5.1 ),错误信息是:

110908 13:25:37 [ERROR] /usr/sbin/mysqld: The table ‘t1’ is full

 

即使 SHOW TABLE STATUS 或 SELECT * FROM information_schema.TABLES 显示InnoDB 表有大于0的Data_free 。

重现问题:

该问题能通过以下步骤重现:

  1. 以重新安装的MySQL启动
  2. 在首次启动MySQL之前,在你的my.cnf中有这样的设置

innodb_data_file_path = ibdata1:100M

且确保没有启动 innodb_file_per_table

  1. 启动MySQL并让InnoDB 创建数据文件
  2. 登录到MySQL并运行:

CREATE DATABASE innodbtest;

use innodbtest

CREATE TABLE t1 (id mediumint unsigned NOT NULL auto_increment PRIMARY KEY) ENGINE=InnoDB;

 

 

  1. 不断将行插入到表中,直到查询返回 The table ‘t1’ is full。
  2. 当空间即将耗尽,错误信息类似于:

 

SQLSTATE[HY000]: General error: 1114 The table ‘t1’ is full

 

 

  1. 运行SHOW TABLE STATUS:

 

mysql> SHOW TABLE STATUS LIKE 't1'\G

*************************** 1. row ***************************
Name: t1
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 3918789
Avg_row_length: 23
Data_length: 90800128
Max_data_length: 0
Index_length: 0
Data_free: 4194304
Auto_increment: 3920001
Create_time: 2011-09-08 12:14:35
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)

 

 

注意即使没有更多可用的数据,Data_free 仍是4194304 。

 

 

使用自动扩展的 InnoDB 表空间包括使用 innodb_file_per_table 的所有版本

当出现Table is full error ,在MySQL错误日志的常见症状为:

 

2014-09-15 08:33:38 7f28aeb8a700 InnoDB: Error: Write to file /mysql/data/ibdata1 failed at offset 20971520.
InnoDB: 1048576 bytes should have been written, only -1 were written.
InnoDB: Operating system error number 28.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 28 means 'No space left on device'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.6/en/operating-system-error-codes.html
2014-09-15 08:33:38 7101 [ERROR] /usr/sbin/mysqld: The table 't1' is full
2014-09-15 08:33:39 7101 [ERROR] /usr/sbin/mysqld: The table 't1' is full

 

 

在Windows中,错误可能像这样:

 

 

2014-09-15 10:04:06 12AB InnoDB: Encountered a problem with file C:\ProgramData\MySQL\ibdata1
2014-09-15 10:04:06 12AB InnoDB: Disk is full. Try to clean the disk to free space.
2014-09-15 10:04:06 13D7 [ERROR] C:\Program Files\MySQL\bin\mysqld.exe: The table 't1' is full

 

 

以上是共享的表空间的错误。相似错误能在各个表空间发生。

 

原因

4.x, 5.0.84 及以下, 5.1.37 及以下, InnoDB插件的5.1.40 及以下版本

 

这是由于bug If InnoDB Runs Out of Undo Slots, It Returns Misleading ‘Table is Full’。在MySQL 5.1 及以下 InnoDB 支持最多1023个动态事务。要启动更多将会导致错误或在受该bug影响的版本中可能产生声明assertion。

 

使用固定大小的InnoDB 表空间和不使用 innodb_file_per_table 的所有版本

 

该问题是由于InnoDB 耗尽了在共享表空间中的可用空间。在每个参考手册中,Table is full 错误表示磁盘用尽或表达到最大。对于InnoDB,当InnoDB被设为有共享的表空间,InnoDB 表空间的大小 (数据文件) 决定了表的最大空间。

 

InnoDB 表空间包含默认大小为16KB的数据页。有可能一些页没有被完全使用,但是实际上不太可能对新的数据进行提示。因此,SHOW TABLE STATUS报告仍有空间而实际上无法再插入任何数据是有可能的。

 

参见MySQL参考手册中以下页:

  • The table is full
  • Limits on Table Size
  • Configuring InnoDB
  • InnoDB File Space Management

 

使用自动扩展的InnoDB 表空间包括使用 innodb_file_per_table 的所有版本

在这个情况下,起因可能是:

储存表空间的磁盘已满。

已达到设置的磁盘配额。

表空间文件达到文件系统支持的最大尺寸。

 

解决方案

4.x, 5.0.84 及以下, 5.1.37 及以下,和带InnoDB插件的5.1.40及以下版本

解决方案是升级到MySQL的补丁版本。以下版本被打过补丁:

  • MySQL 5.0: 5.0.85及以上
  • 不带InnoDB插件的MySQL 5.1:1.38及以上
  • 带InnoDB插件的MySQL 5.1:1.41及以上
  • MySQL 5.5 及以上:所有版本

 

建议升级到可用的最新GA版本。

 

在升级之前总是创建数据库部分!这包括schema,数据和数据库需要执行的程序(函数,触发器等)。安全总是最好的策略,所以如果在升级过程中有一些问题,很容易恢复到之前的版本。

 

升级教程参见:

  • Downloading MySQL Server
  • 升级或下载MySQL。检查表或索引是否必须重建的部分尤其重要。对下载的版本使用页: 5, 5.1, 5.0。参见 How to Upgrade your Existing MySQL Server to MySQL 5.6 Version 获得更多升级MySQL的帮助。

 

总是在对生产服务器执行升级之前开发或阶段系统中进行测试。

 

使用固定大小的InnoDB表空间和不使用 innodb_file_per_table的所有版本

解决方案使让InnoDB表空间增长,通过执行以下步骤完成:

 

总是在更改应用于生产之前,在开发或阶段系统中尝试步骤。

 

  1. 停止MySQL
  2. 在你喜欢的编辑器中打开MySQL配置文件。
  3. 找到配置innodb_data_file_path 选项的行
  4. 添加一个新表空间或让最近的表空间自动扩展:
  5. 将 innodb_data_file_path 设为

innodb_data_file_path = ibdata1:100M;ibdata2:100M

或类似的

  1. 将 innodb_data_file_path 设为

innodb_data_file_path = ibdata1:100M:autoextend

  1. 保存MySQL配置文件
  2. 再次启动MySQL
  3. 确认现在能够再次将数据插入InnoDB表
  4. 将解决方法迁移到合适的其他环境。

 

参见MySQL参考手册中以下页:

Configuring InnoDB

Adding, Removing, or Resizing InnoDB Data and Log Files

 

使用自动扩展的InnoDB 表空间包括使用 innodb_file_per_table 的所有版本

由于原因是无法进一步增加表空间文件的大小,解决方法包括:

  • 确保表空间文件储存的路径有多余的磁盘空间(参见以下建议,如何释放磁盘空间)。

不要为了释放空间而删除任何InnoDB文件,包括共享的表空间。没有它的这些文件,InnoDB将无法启动。

如何取回空间的教程,参见以下。

  • 确保没有预设的定量会阻止表空间文件的增长。
  • 确保文件系统支持的最大文件尺寸还未达到。如果这是Table is full错误的原因,一些解决方案如下:
    1. 通过你将所有表储存在共享的表空间 (innodb_file_per_table = 0):
      1. 另外创建一个共享的表空间文件。
      2. 或者,你能另外创建一个额外共享的表空间文件启用 innodb_file_per_table ,从而能将表移出共享的表空间。注意到这不会降低共享的表空间大小。参见MySQL Server Variable: innodb_file_per_table获得关于innodb_file_per_table的更多信息。
    2. 对于每个表的表空间的文件,对表进行分区。对已分区的表,每个分区在 自己的表空间中且innodb_file_per_table = 1,所以这是你能将总大小分割到多个文件。

 

释放磁盘空间的可能操作有:

 

  • 使用OPTIMIZE TABLE <table_name>取回每个表空间的空闲空间

这需要重建在表空间文件位置的表。所以只有当你已经释放了空间或将表迁移到另外的位置才有作用。(参见以下)

  • 要取回在共享表空间文件中的文件,参见:How to Reclaim Unused Space and Decrease InnoDB ibdata1 Data File Size.
  • 如果错误日志,慢查询日志,一般查询日志,审计日志等储存在与表空间相同的磁盘。考虑重定向停止并压缩旧日志或将旧日志移动到其他磁盘。参见:
    1. 服务器日志维护
    2. audit_log_rotate_on_size
  • 如果二进制日志位于与数据相同的磁盘上,考虑清楚旧的二进制日志。

确保被清楚二进制日志是不再需要的,例,用于复制或时间点恢复。如果二进制不再需要用于复制但仍要用于恢复,你能在清楚日志之前创建备份。

确保你使用PURGE BINARY LOGS 命令来删除旧的二进制日志。

  • 在MySQL 5.6 中,你能使用 InnoDB native links将在自己tablespace的表空间移到另一个磁盘。
  • 将日志移到另一个磁盘。参见:
    1. What is the General Query Log and How to Control Where the Log is Stored?
    2. What is the Slow Query Log and How to Control Where the Log is Stored and What is Logged?
    3. –log_ error
    4. –audit_ log_file

 

什么导致了MySQL服务器中的MyISAM 表损坏?

 

应用于:

MySQL 服务器-版本:4.0 到 5.5 –发行版:到5.5

MySQL 服务器-版本:4.0 以上–发行版:4.0 以上

MySQL 服务器-版本:4.0 到 5.5 –发行版:4.0 到 5.5

 

所有平台

 

目标

说明MyISAM 表损坏的具体原因

 

解决方案

 

MyISAM 存储引擎非常可靠。但如果时常遇到MyISAM 表损坏,你最好思考导致这个问题的原因。在查询数据时,以下错误信息通常意味着表损坏:

 

Error 1034 Incorrect key file for table: ‘…’. Try to repair it

 

或包含以下错误号码之一的信息:

 

Error 126 = Index file is crashed

Error 127 = Record-file is crashed

Error 134 = Record was already deleted (or record file crashed)

Error 144 / Error 1195 = Table is crashed and last repair failed

Error 145 / Error 1194 = Table was marked as crashed and should be repaired

 

当查询本该查找到在表中的行但没有找到,或当一个查询返回不完整的数据,也可以假定发生了损坏。你可以使用CHECK TABLE 语句来验证MyISAM 表是否损坏。

 

MyISAM的损坏可能由多种因素导致。以可能性从大到小排序,它们依次为:

  1. 由于服务器崩溃,意外关闭,或硬件错误引起的损坏
  • 如果在写的过程中,mysqld进程被杀掉或崩溃可能会导致损坏。
  • 由于电源故障导致运行MySQL的服务器关闭可能会导致损坏。
  • 还可能由于硬件错误导致,如服务器的硬盘问题,这比之前的问题引起损坏的可能性低。
  • RAM中的损坏;重启硬件可能解决这个罕见的问题;如果在操作系统缓存中有损坏的数据,有时只需重启,不需要通断电就能解决这个问题。这个情况比较罕见,但如果你的硬件故障,发生频率就会很高。

服务器重启时的自动修复通常会解决这个问题,但有时需要使用REPAIR TABLE SQL 语句以及更深入的检查选项。当你的表很大,而服务器离线并有强制更快修复的选项时,可以使用myisamchk 。如果你有许多CPU 内核且表中有许多索引,你应该尝试myisamchk 选项先来使用多个线程,因为这通常会更快;这个选项失败时而会有报告,所以不太可能尝试后发现只需要单个线程。

 

  1. 由于其他程序导致的损坏
  • 如果你在使用外部程序,如myisamchk,这会在服务器运行时对表进行更改,你就很可能遇到损坏。
  • 部分或反病毒软件也经常导致损坏,有时由于恢复表的旧版,或由于检验需要的文件。

这些情况的第一步是找出是什么更改了文件。修复表只是暂时的方法。

  1. 由于bug导致的损坏
  • 使用在2007年夏季之前版本的服务器建设。从2006年开始到2007年,MySQL执行了系统的测试来找出罕见且难以复制的MyISAM损坏bug。大约在2007年夏季,我们看到几乎所有bug相关的损坏问题来自旧版本,有广泛修复的较新版本很少受到影响。你能通过将版本升级到接近于2007夏季的版本,最好是最接近的,来消除遇到损坏的可能性,越接近的版本越好。
  • 如果bug仍导致损坏,你应该首先查看最近引入的服务器功能和情况,其中并发级别很高的区域是最可能有问题的。现今,新的损坏bug通常涉及具体客户的语句结合和高并发性,或新功能和高并发性。

你能查找在错误认知中最近重启的mysqld 来验证表是否由于服务器崩溃而损坏。如果没有错误信息表明问题是由于服务器故障,且损坏看上去发生在正常操作期间,这可能是bug。因此,你应该尝试创建一个可复制的测试以反映出问题并通过在My Oracle Support中开启一个Support Request 来报告问题。

再说一次,你能用REPAIR TABLE SQL 语句来修改损坏的MyISAM表。此外,当 mysqld不在运行时,你能用myisamchk 命令来检查或修复表。

 

 

MySQL InnoDB存储引擎表损坏恢复指南

目的

故障排除步骤

适用于:

MySQL服务器版本
5.0至5.7[5.0版到5.7]

 

A 第一反应

A.1 停止,备份,重启

  1. 停止MySQL 服务器。如果它已经下线或崩溃,跳到步骤 2。

代码:

 

/etc/init.d/mysqld stop

 

这里的目的是要冻结数据和表文件的当前状态,这样就没有新的写入发生,并且我们能创建文件副本,而无需注意文件更改会导致数据不一致,或存储信息的丢失。

 

2.如果不是整个MySQL数据目录,备份您的数据和日志文件。

代码:

 

mkdir /root/innodb.bak (or backup path of your choice)
cd /var/lib/mysql (or alternate data directory, if con figured)
dd if=ibdata1 of=ibdata1.bak conv=noerror
cp -p ./ibdata* /root/innodb.bak/
cp -p ./ib_log* /root/innodb.bak/

首先,你创建了存放任何文件副本的目录,然后你在/var/lib/mysql(或你的数据目录)中创建了ibdata1 文件的本地备份,还有ibdata和ib_logfiles的备份到你的备份目录。我喜欢同时使用dd和cp创建(多个)ibdata文件的副本,因为两个工具的性质不同。 Dd工具复制原始文件,而CP复制文件内容到一个新的文件。我没有遇到过任何情况中这是恢复成功的关键,但这仍是我的习惯,我认为这绝不是一个坏习惯。

 

理想情况下,特别当你还没有备份时,如果可能的话,你最好立即尝试创建你的数据目录的完整副本。

命令:

 

cp -Rp /var/lib/mysql{,.orig}

 

我知道这可能过于费时或对一些的紧急情况不太实际,因此,如果这不可行,至少数据文件和InnoDB数据库目录应该提供一些能回退的数据。

 

3.备份你的InnoDB数据库文件夹

 

假设你没有备份完整的MySQL数据目录,你最好还是确保包含InnoDB表的任何数据库都有各自的备份的文件夹。如果你不知道哪个数据库包含InnoDB表,可以使用像这样的命令检查包含的.ibd文件,并将它们复制到备份文件夹(在这个例子中/root/innodb.bak是额外的目录,如果你的DATADIR不是默认的,则需要在一开始更新变量):

代码:

 

DATADIR=/var/lib/mysql; find $DATADIR -type f -name *.ibd | awk -F/ '{print $(NF-1)}' | sort | uniq |
xargs -I {} cp -Rp $DATADIR/{} /root/innodb.bak

 

4.启动MySQL服务器(如果可以的话)
此时将MySQL重新联网是安全的,如果你能这样做而不导致崩溃。如果你能使其联网,接下来就启动MySQL服务,然后执行mysqldump,我建议如下(你可以将这些转储至/root以外的其他路径,如果你愿意记得你的选择):

 

 

Code:

/etc/init.d/mysql start
mysqldump --single-tran saction -AER > /root/dump_wtrans.sql
mysqldump -AER > /root/dump.sql

 

Dumping it with singletransaction flag creates the dump in, go figure, a single transaction, which prevents locking on the database, and may help if you’re running a 100% InnoDB environment so to be safe, particularly if you’re not sure, I recommend running both.

 

以singletransaction标识转储它在单个事务转储数据,go figure,这能防止在数据库上的锁,如果你在运行100% InnoDB环境也会安全,特别是你不能确定的情况下,我推荐两个都运行。

 

一定要检查你的SQL转储内容,以确保数据实际存在。有一些情况中,如果数据由于任何原因无法访问,那只有表结构会存在。尤其当在使用singletransaction,你操作的数据库经常运行ALTER TABLE命令的时候。如果在一个表中mysqldump与ALTER TABLE一致,可能只有结构。 (详细讨论在MySQL的错误报告#71017(BUG17862905))

 

注意:如果你在处理文件系统损坏,尝试并将这些文件备份到另一个可用的磁盘驱动(如果可以,甚至备份到一个安全的远程主机上)

 

A.2 如果MySQL崩溃

 

如果MySQL崩溃并拒绝重启,那这很可能是你此时最关心的问题。当然你在想让它在线用于生产,但最重要的是,MySQL在线可以让你得到真正的MySQL数据转储,这样可以最大限度地减少永久丢失数据的机会,并有助于修复可能损坏的表。

 

由于InnoDB的ACID合规性(MySQL的:: MySQL 5.6参考手册:: 14.2.1 MySQL和ACID模型),它坚持严格的数据一致性标准。这实际上意味着,如果它遇到数据的任何问题,它遵循严格的数据一致性标准。这实质上意味着,如果遇到数据的任何问题,它几乎总是使MySQL崩溃以防止进一步的一致性问题。从理论上讲,这是一件好事,但实际上,非计划的停机时间从来都不是一件好事。

不过使用innodb_force_recovery选项通常可以帮助至少让MySQL回到可访问状态。也就是说,了解它的运行原因,以及如何小心使用它是个好主意。

 

使用 innodb_force_recovery

 

当 InnoDB遇到问题时,它已经尝试默认下的基本恢复步骤,但更多的时候,你需要在你的/etc/my.cnf文件这添加innodb_force_recovery设置来帮助它。这指示InnoDB在恢复模式下启动,告诉它跳过InnoDB启动过程中,通常是崩溃发生的各种部分。你最好在一开始设置最低值,1,并且只有在需要时增加,最高值是6。此设置在你的my.cnf文件的[mysqld]部分输入,在示例中显示:

代码:

[mysqld]

innodb_force_recovery = 1

 

你还可以运行以下单行命令来将其自动添加到你的/etc/my.cnf文件的正确部分(在一开始时,将“mode=”变量更改为任何你想用的模式):

代码:

 

mode=1; sed -i "/^\[mysqld\]/{N;s/$/\ninnodb_force_recovery=$mode/}" /etc/my.cnf

 

然后,一旦你准备把你的服务器返回到默认模式,你可以通过以下命令删除innodb_force_recovery行:

代码:

 

sed -i '/innodb_force_recovery/d' /etc/my.cnf

 

此配置选项不应被用作使你的服​​务器联网的长期,或甚至中期的解决方案。如果你的服务器只能在innodb_force_recovery启用时联网,那在你的服务器上还是有需要处理的重要问题。如果innodb_force_recovery被闲置的活动时间过长,在服务器上可能会造成更多的问题,特别当选项设置为高值(将innodb_force_recovery长时间设为6没什么很好的理由)。这种模式完全是暂时的,仅用于恢复的目的。

 

以下是对每种模式的简短概要(每一种模式还复合自身,这意味着更高的值包括所有的低值的功能):

 

  • Mode 1当遇到损坏页时,不使 MySQL 崩溃
  • Mode 2不运行后台操作
  • Mode 3不会尝试回滚事务
  • Mode 4不计算统计数据或应用存储/缓冲的变化
  • Mode 5在启动过程中不查看撤消日志
  • Mode 6在启动时不从重做日志(ib_logfiles)前滚

 

因此,如果你的MySQL服务器以模式3而不是模式2启动,崩溃与事务回滚过程有关是安全的假设。另外,要注意在MySQL5.6.15中,模式4和6将会把MySQL设为只读模式。

 

如果您已经试过所有innodb_force_recovery模式,但仍然由于InnoDB错误崩溃,下一步最好就是尝试并收集有关导致崩溃的原因的其他信息。

 

B 识别问题

InnoDB的问题多种原因,虽然通常用于概括大部分问题的“corruption”术语了常不准确,但试图找出你所面对的具体问题总是一个好主意。

 

B.1 检查日志

如果你怀疑InnoDB表或数据库被损坏,很可能是因为你发现受到损坏的数据,不存在数据,或者MySQL的服务拒绝启动。对于任何一种情况,你要首先查看的是MySQL错误日志。在通常的设置中,这是在/ var/ lib/mysql/中,而文件是你的主机名与.err后缀。

 

这里是拉出日志最后200行的快速命令,如果你不知道主机名,或不想完整输出(如果不是默认的,将数据目录替换为你自己的):

代码:

 

tail -200 /var/lib/mysql/`hostname`.err

 

这执行hostname命令,并使用返回的字符串代替`hostname`,这是在命令行中的反引号的功能。
在这里你可能还会看到几件事情,可以帮助你pin下你遇到的损坏类型,如果有的话。在本指南中,我会涵盖在页损坏,日志序列号问题和数据字典的问题中最常见的三种损坏问题的类型。下面是几个例子,以及它们可能表示什么的说明:

 

B.1.1 页损坏

错误代码:

 

InnoDB: Database page corruption on disk or a failed
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 515891.

 

通常在这之前还有一些信息,你应该注意,因为它可能包含这种损坏发生在哪里的有用信息,但最终这会告诉你,InnoDB看上去认为在引用的页ID上存在页损坏,或者可能只是无法读取文件。

 

这并不一定表示实际损坏,事实上,在某些情况下,这可能只是操作系统损坏它自己的文件缓存的结果。正因为如此,建议创建备份后,在无任何进一步操作之前,重启你的计算机。也就是说,如果重新启动解决了你的问题,你最好确保你的RAM没有问题或者在它的出门途中没问题,因为这是操作系统损坏它自己的文件高速缓存的常见原因之一。这可能是要在尝试任何恢复之前解决的问题,以避免陷入相同问题。

 

如果你不确定,或重启后,你仍怀疑存在损坏,可以运行下面的脚本在所有的.ibd文件执行innochecksum以找出损坏。这对MySQL仍不能成功启动特别有用,因为它在文件上直接运行,而无需MySQL(事实上,如果表空间的检查在服务器上启动,它无法工作):

 

代码:

 

#!/bin/bash
for i in $( ls /var/lib/mysql/*/*.ibd)
do
innochecksum $i
done

 

innochecksum工具查看在表空间文件中的页,并且计算每页的校验。然后,将这些与存储的校验相比,如果有错配就告诉你。如果有,那通常表明页已被损坏。如果没有发现错配,它不会显示任何输出(除非包含v,即详细输出)。

i

如果MySQL是在线且可访问的,你可以使用CHECK TABLE语句,如下所述:

MySQL :: MySQL 5.5 Reference Manual :: 13.7.2.2 CHECK TABLE Syntax

 

B.1.2 InnoDB 的TimeTraveling 和日志序列号错误

代码:

 

mysql: 120901 9:43:55 InnoDB: Error: page 70944 log sequence number 8 1483471899
mysql: InnoDB: is in the future! Current system log sequence number 5 612394935.
mysql: InnoDB: Your database may be corrupt or you may have copied the InnoDB
mysql: InnoDB: tablespace but not the InnoDB log files. See
mysql: InnoDB: [url=http://dev.mysql.com/doc/refman/5.5/en/ forcing-innodb-recovery.html]MySQL ::
MySQL 5.5 Reference Manual :: 14.21.2 Starting InnoDB on a Corrupted Database[/url]

 

 

 

首先,解释一下日志序列号(LSN)是什么。在InnoDB引擎上每发生一个行为,记录被写入“redo”日志文件,通常默认为MySQL数据目录中的ib_logfile0和ib_logfile1。这两个文件有一组大小,(MySQL中5.6.8+中,默认每个48M),记录按顺序被写入这些文件,从第一个日志文件直到结束,然后继续在第二日志文件中进行。一旦它到达第二日志文件(假定只有2默认日志文件被配置在innodb_log_files_in_group可见)的尾部,它重新开始,再次在第一日志文件的开头写入。所有这些记录都有一个相关的LSN。

 

此外,当一个数据库被修改,在该数据库中的特定页面也得到一个相关LSN。两者之间,这些LSN被一起检查,确保操作以正确的顺序执行。LSN本身基本上是一个到日志文件的偏移,且存储在数据库页头中的LSN告诉InnoDB有多少日志需要被刷。

 

在过程中,无论是意外重启,内存问题,文件系统损坏,复制问题,手动更改为InnoDB的文件或其他,这些LSN不再“同步”。无论是否使你的服务器崩溃,这应该被当作合理损坏,通常你需要解决它。

 

B.1.3 数据字典错误

错误代码:

 

 

[ERROR] Table ./database/table has no primary key in InnoDB data dictionary, but has one in MySQL!
InnoDB: Error: table 'database/table'
InnoDB: in InnoDB data dictionary has tablespace id 423,
InnoDB: but tablespace with that id or name does not exi st. Have
InnoDB: you deleted or moved .ibd files?
[ERROR] Cannot find or open table database/table from
the internal data dictionary of InnoDB though the .fr m file for the
table exists. Maybe you have deleted and recreated InnoDB data
files but have forgotten to delete the corresponding .frm file s
of InnoDB tables, or you have moved .frm files to another datab ase?
or, the table contains indexes that this version of the engine
doesn't support.

 

 

稍微解释一下InnoDB数据字典,它存在于系统表空间,本身作为页的特殊集存储在ibdata1文件中(系统表空间总是被引用为“space 0”),它储存InnoDB显式处理的任何表,列,或索引的元信息。这不是结构元件的主要位置,那些是每个InnoDB表的.frm文件中的,然而,它确实含有许多相同信息。

 

在这里,你通常能看到导致这些错误的差异。如果由于某种原因,ibdata1文件被修改,移动,手动更改或替换,你会突然得到一个数据字典,它并不能反映你的文件或数据库结构中有什么。

如果你看过之前的错误描述,你应该知道在ibdata1中(或以其他方式命名)文件中的数据与在单个表空间/.ibd / .frm文件的数据之间有明显的关联。当该关联丢失或损坏,可能会发生不好的情况。所以这像这样的数据字典的错误出现,最常见的原因是有些文件被手动移动或修改。它通常归结为:“数据字典预计这一文件或表空间在这里,但它不在!”,或“.ibd / .frm文件预计此项目在数据字典中,但它不在! “。再次记住,数据字典存储在ibdata文件中,在大多数环境中,就是MySQL数据目录中的ibdata1。

 

B.2 检查错误的表

当问题发生时,日志通常会立即显示,但它们有时会有点模糊。你通常只会被告知有损坏,但不知道哪个表,页或数据库具体受到影响。两个InnoDBrelevant检查表的方法是CHECK TABLE SQL语句,以及innochecksum工具。你要使用的方法取决于一个因素:你的MySQL服务器是在线还是离线。
MySQL正在运行并且能访问?

 

使用 CHECK TABLE。 innochecksum 不检查当前由服务器启动的表空间。

 

MySQL 崩溃或离线?

 

innochecksum 是你的选择。它查看在表空间文件的页,计算每个的校验,并将之与储存的校验值相比。如果不匹配,显然MySQL 会崩溃,损坏或数据更改,所以这是确认表空间中有问题的可靠方法。

 

B.2.1 使用 CHECK TABLE / mysqlcheck

CHECK TABLE 命令,也由mysqlcheck的运用(特别是c标志,然而mysqlcheck默认为这种行为),在许多不同的确认和比较检查中执行,以尝试识别损坏的迹象。CHECK TABLE和mysqlcheck都在MyISAM和InnoDB表执行,但在本文中,我将着重于在InnoDB表的执行。

 

注意mysqlcheck r的REPAIR功能和“REPAIR TABLE”MySQL命令不会在InnoDB表执行;在这里,mysqlcheck主要只用于找出问题而不是解决问题。

 

这是它在内部具体查找的详细内容:

  1. 相应的.ibd表空间文件的存在
  2. Primary索引的一致性
  3. 正确顺序(键的升序)
  4. 唯一约束的完整
  5. 索引条目的计数
  6. 对表中的其他索引重复步骤1-5。
  7. 最终,所有表经过一个Adaptive Hash Index 检查。

 

如果其中任何一个返回不正确或不一致的值,该表可以被标记为损坏。一旦表被标记为损坏,表不能再被使用,直到问题得到解决,或者直到后续表检查确认该问题已不存在。

 

在某些情况下,如果在MySQL遇到问题之前,CHECK TABLE 在 InnoDB 表中发现了这个问题,这可能导致MySQL服务器被关闭,以避免引起其他错误。尽管这可能是件好事,因为它可以帮助你停止任何进一步的损害的发生,但当你决定在InnoDB表运行CHECK TABLE或mysqlcheck时最好要注意到这一点。

 

这不是发现问题是简单损坏或错误的情况。被发现的损坏/错误只会导致索引/表中相应地被标记。

 

运行CHECK TABLE

CHECK TABLE命令必须早MySQL shell中运行,或通过MySQL的其它地方执行。例如,这里是我创建的一个情况,我将现有的dictionary.ibd文件用来自同一个数据库另一个表的.idb文件替换,你可以看到一个普通表,与一个被损坏或有遇到错误表进行CHEACK TABLE的对比:
代码:

 

 

mysql> CHECK TABLE roundcube.users;

+-----------------+-------+-------- --+----------+

| Table | Op | Msg_type | Msg_text |
+-----------------+-------+----------+----------+
| roundcube.users | check | status | OK |
+-----------------+-------+----------+----------+
1 row in set (0.13 sec)



mysql> CHECK TABLE roundcube.dictionary;
+----------------------+-------+-------- --+------------------------------------------------------------
----+
| Tab le | Op | Msg_type |
Msg_text |
+----------------------+-------+----------+--------------------- ---------------------------------------
----+
| roundcube.dictionary | check | Warning | InnoDB: Tablespace is missing for table
'roundcube/dictionary' |
| roundcube.dictionary | check | Error | Table 'roundcube.dictionary' doesn't
| roundcube.dictionary | check | Error | Table 'roundcube.dictionary' doesn't
exist |
| roundcube.dictionary | ch eck | status | Operation
failed |
+----------------------+-------+----------+----------- -------------------------------------------------
----+
3 row s in set (0.00 sec)

 

 

In this situation, the error experienced actually warrants the server being automatically shut down. The instant I ran the CHECK TABLE on roundcube.dictionary the first time, the server crashed. This is because I “introduced” the active MySQL instance to the problem’s existence. 在这种情况下,经历的错误实际保证了服务器被自动关闭。我第一次在roundcube.dictionary上运行CHECK TABLE,服务器崩溃了。这是因为我将主动MySQL实例“带入”到这个问题的存在。

 

InnoDB的数据一致性坚持一旦这样的问题出现,它应尽快被停止。根据引发崩溃的源头,需要不同级别的innodb_force_recovery使MySQL服务器恢复。在缺少表空间的情况下,最低值为1就行了。

 

请记住MySQL服务器被强制崩溃是有原因的。不要通过快速启用innodb_force_recovery立即回到MySQL!这有时会造成比它解决的问题更多的问题。

 

运行 mysqlcheck

 

通常,你要一次检查许多表或数据库。CHECK TABLE对通配符没有任何支持,因此当要检查所有数据库中的表,或检查服务器上的所有数据库时,它就不实用了。 mysqlcheck默认在命令行中执行CHECK TABLE以弥补这点,允许你轻松地检查整个数据库或所有数据库。对数据库执行CHECK TABLE的默认语法是(用你的数据库名替换db_name):

代码:

mysqlcheck db_name

 

 

然后它将输出对数据库中每个表执行CHECK TABLE的结果。如果你只想在一些选出的表上执行命令,你也能在数据库名后指定表 (mysqlcheck db_name tbl1_name tbl2_name…)。

 

下面是我在之前的情况中对roundcube数据库执行命令的例子:

代码:


-bash-4.1# mysqlcheck roundcube

roundcube.cache OK
roundcube.cache_index OK
roundcube.cache_messages OK
roundcube.cache_thread OK
roundcube.contactgroupmembers OK
roundcube.contactgroups OK
roundcube.contacts OK
roundcube.cp_schema_version OK
roundcube.dictionary
Warning : InnoDB: T ablespace is missing for table 'roundcube/dictionary'
Error : Table 'roundcube.dictionary' doesn't exist
status : Operation failed
roundcube.identities
Warning : InnoDB: T ablespace is missing for table 'roundcube/identities'
Error : Table 'roundcube.identities' doesn't exist
status : Operation failed
roundcube.searches OK
roundcube.session OK
roundcube.system OK
roundcube.users OK

 

Additionally, you can use the A flag (or alldatabases) to perform a CHECK TABLE on all tables in all databases on your server. 此外,还可以使用一个标志(或alldatabases)在服务器上的所有数据库中的所有表上 执行CHECK TABLE。

 

B.2.2 使用innochecksum

 

像在之前提到的 ,InnoDB需要有一致的数据,当它遇到对本身校验的不匹配,将立即停止活动的服务器。考虑到这一点,innochecksum不仅可以帮助识别损坏,而且能监控校验状态。这里唯一的缺点,在预防方面,即它不能在任何启动的 表空间文件运行。因此,要得到表的校验状态的描述,服务器需要下线。

 

不过,又有我们处理的是在崩溃的MySQL服务器的损坏,这可能你是最不用担心的,innochecksum在追踪不匹配的校验方面很强大,特别是它不需要服务器在线。

 

从innochecksum得到的输出将由发生的情况变化而变化,一般除非使用-v 指定详细的输出,你不会看到任何输出,除非确实有发现的问题。下面是发现在数据文件中的校验失败的例子:

代码:

 

page 8 invalid (fails old style checksum)
page 8: old style: calculated = 0x 819564 6B; recorded = 0x DA79A2EE

 

innochecksum工具目前只能在专门引用的表空间文件(.ibd)运行,但你可以简单使用find命令如下,在所有.ibd文件(调整合适的DATADIR)执行innochecksum:

代码:

 

DATADIR=/var/lib/mysql; find $DATADIR -type f -name *.ibd -o -name ibdata* | xargs -I{} innochecksum {}

 

C 恢复数据
一旦你确定了问题并准备好你的服务器,下一步将是获得以运作排序的数据。MySQL此时应在线且至少部分响应,无论是通过innodb_force_recovery或其他方式。

 

C.1 MySQL工具/从.frm文件中提取CREATE TABLE语句
MySQL提供可下载的实用工具,包括对特定的恢复过程有帮助的一些工具,其中有个工具叫做“mysqlfrm”。该工具可以简单地从.frm文件中提取表的CREATE TABLE语句。该语句非常有用,因为几乎所有有用的恢复方法能重建你试图修复原始表的结构,而且往往不能有任何MySQL直接访问原始表本身成。

 

C.1.1 下载并安装 MySQL 工具:

此处下载包。

在服务某处提取它。

代码:

 

tar xvzf mysql-utilities*

 

更改到解压目录,将执行权限给setup.py,然后运行它的编译和安装操作

代码:

 

cd mysql-utilities-1.4.3
chmod +x setup.py
./setup.py build
./setup.py insta ll

 

C.1.2 要从.frm文件提取CREATE TABLE语句:

mysqlfrm将根据您现有的安装创建其临时的MySQL守护进程,这意味着如果你现有的MySQL安装已在运行,你需要指定一个备用端口。这里我运行的示例是从我的“staff.frm”文件中提取CREATE TABLE:

代码:

 

mysqlfrm --basedir=/usr --user=mysql --port=3308 /var/lib/mysql/testdb/staff.frm

 

这是之后的输出:

 

代码:


# Spawning server with --user=mysql.
# Starting the spawned server on por t 3308 ... done.
# Reading .frm files
#
# Reading the staff.frm file.
#
# CREATE statement for staff.frm:
#
CREATE TABLE `staff` (
`staff_id` tinyint(3 ) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
`address_id` smallint(5) unsigned NOT NULL,
`picture` blob,
`email` varchar (50) DEFAULT NULL,
`store_id` tinyint(3) unsigned NO T NULL,
`active` tinyint(1) NOT NULL DEFAULT '1' ,
`username` varchar(16) NOT NULL,
`password` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CUR RENT_TIMESTAMP,
PRIMARY KEY (`staff_id`),
KEY `idx_fk_store_id` (`s tore_id`),
KEY `idx_fk_address_id` (`address_i d`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
#...done.


以上输出从“CREATE TABLE”部分到“CHARSET= UTF8”都是完整的,需要可执行的CREATE TABLE语句来重建“staff”表和正确的结构。要在MySQL shell中执行,我可以简单地粘贴该完整语句,并用分号(;)结尾。在某些情况下,你也可能需要禁用外键检查使之成功:

 

代码:

 

SET FOREIGN_KEY_CHECKS=0;

 

C.2 损坏的表
如果您已经确定了当前在服务器的损坏的表,根据情节严重程度,你可以有几种方法处理。在几乎所有表损坏的情况下,你至少需要以innodb_force_recovery为1运行的InnoDB,使MySQL在你操作时保持在线。

 

C.2.1 以CREATE..LIKE恢复表
这种方法的目标是尝试使用表的现有结构和数据,由于它们是可访问的,能用来简单地创建一个具有相同的结构和数据的新表来替代原始表。基本步骤如下:

 

1.访问MySQL shell通过运行:

代码:

mysql -u root -p

 

成功的话,你会得到这样的提示符:

mysql>

 

2. 运行以下 MySQL 语句,以你的表和数据库名称分别替换 tablename 和 dbname :

代码:

 

USE dbname;
CREATE TABL E tablename_recovered LIKE tablename;
INSERT INTO tablename_recovered SELECT * FROM ta blename;

 

3. 如果在这里没有遇到任何问题,那你真走运了。此时,你就能删除原始表,并将”_recovered” 表名改回原来的:

 

 

DROP dbname.tablename;
RENAME TABLE dbname.ta blename_recovered TO dbname.tablename;

 

 

当遇到页损坏的情况,这种方法是最简单的,但可能成功率最低,因为它取决于你能否从表中选出所有的数据,并创建一个基于它结构的恢复表。如果没有可访问或可读的,这种方法可能会失败。

 

但是,如果它在“SELECT *”部分失败了,你还有另一个选择,涉及增量插入。因此,选择不执行以上的“INSERT INTO… SELECT*……”,你要执行以下操作:

 

insert ignore into tablename_recovered select * from tablename limit 10;
insert ignore into tablename_recovered select * from tablename limit 50;
insert ignore into tablename_recovered select * from tablename limit 100 ;
insert ignore into tablename_recovered select * from tablename limit 200;

...

 

With this method, you can piece through the data that’s accessible until you reach the point of failure, at which point you’ll likely lose connection from the MySQL server.

使用这种方法,你可以拼凑可访问的数据,直到到达故障点,此时你可能会失去MySQL服务器的连接。

 

 

C.2.2 恢复多个/所有的InnoDB数据库并重建ibdata / ib_log文件

这种方法的成功又取决于mysqldump从每个问题表中生成功能数据的能力,但它也是更全面的方法,因为它涉及到初始化新ibdata和ib_log文件。正因为如此,如不谨慎处理,这种方法也很有可能失败。所以确保你已经运行了第一反应的步骤,且在进一步操作之前有另外的备份。

 

如果你已有备份转储想要恢复从步骤2开始的现有损坏的数据库,也可以使用此方法。

 

1.对所有数据库执行mysqldump

 

mysqldump  -AER > /root/recovery_dump.sql

 

如果你在此处遇到任何错误,停下来仔细看一下错误。如果它们表明任何重要数据都被损坏到无法正确转储的地步,最好就不要继续使用该方法了。此外,一定要查看生成的转储文件,以确保它包含预期的数据。

 

2. 删除所有受影响的 InnoDB 数据库。

 

mysql> SET FOREIGN_KEY_CHECKS=0;
mysql> DROP DATABASE db1;
mysql> DROP DATABASE db2;
...


3. 在禁用 innodb_fast_shutdown 以确保干净,完整的关闭执行后,停止 mysqld。

 

mysql -e "SET GLOBAL innodb_fast_shutdown=0"
/etc/init.d/mysql stop

 

 

4.重新定位 InnoDB 数据并重做日志文件

 

mv /var/lib/mysql/ibdata* /tmp/
mv /var/lib/mysql/ib_log* /tmp/

 

 

5. 注释或删除在当前 /etc/my.cnf 中的 innodb_force_recovery 条目:

 

sed -i '/innodb_force_recovery/d' /etc/my.cnf

 

6. 启动 mysqld 并监控日志,以确保其联网,初始化数据及正确重做日志文件

 

nohup /etc/init.d/mysql start & tail -f /var/lib/mysql/`hostname`.err

 

7.  一旦你确定MySQL仍在线上,并准备将数据导入就恢复转储。

 

mysql  < /root/recovery_dump.sql

 

 

C.3 日志序列号不匹配/在未来(In Future)

 

为了确保你的数据保持一致,并且具有“撤销/重做”的功能,InnoDB在日志文件和表空间文件中保存了日志序列号。每当在InnoDB表中的数据有所变化,它会导致日志序列号更新。这相当于一个偏移,指示InnoDB在文件中要向前或向后查看多少以找到引用该数据的具体状态。

 

在任何时间内,如果发生了什么事导致一个序列号被更新,而其他没有,最终你会在MySQL日志中看到有关“不匹配的日志序列号”或“日志序列号是在未来”的错误。为了你的数据库服务器再次正常工作,使这些序号回到正轨是很重要的。

 

C.3.1 删除并重建数据

这是最有效和唯一的 “实际”的解决方案,但遗憾的是,对许多人来说,这是不适用的,因为在实际情况中,不是每个人得到的数据可用(不过,如果你正在经历,你是该考虑建立一个有效的备份解决方案)。但是,如果你的MySQL实例没有崩溃,而你能创建mysqldump,那它值得一试,并将它重新导入回。你可以按照在损坏的表章节中“还原多个/所有的InnoDB数据库并重建ibdata/ ib_log文件” 方法中的详细步骤,尝试恢复现有数据库的转储。

 

再次声明,在进行任何更改之前,要确保你已经创建了所有重要ibdata,ib_logfile,.ibd,和.frm文件的副本。

 

C.3.2重建ib_logfiles

 

如果你只是处理单个MySQL实例,而不是一个主- >从或其他集群的情况,这可能是一种有效的方法。这里的目的是把现有的ib_logfiles从等式中取出,让MySQL来重新初始化它们来重启。说实话这种方法的成功率有限,但它的使用历史很长,值得一提:

 

mysql -e "SET GLOBAL innodb_fast_shutdown=0"
/etc/init.d/mysql stop
cd /var/lib/mysql
mv ib_logfile0 ib _logfile0.bak
mv ib_logfile1 ib_logfile1.bak
/etc/init.d/mysql start

 

第一个命令确保InnoDB执行干净的关闭,这偶尔会对情况有帮助,值得写在这里。

 

C.3.3 执行引擎交换

 

这又是一个较激进的方法,虽然操作难度大,但根据我个人的经验,它似乎有一个非常稳定的成功率,但它肯定也取决于你的操作环境。这种方法还需要MySQL能被成功启动。

 

1. 将所有数据库中的表从InnoDB转换为MyISAM,在MySQL运行以下命令,将有管数据库名替换db_name:

 

mysql -e "SELECT concat('ALTER TABLE ', TABLE_NAME,' ENGINE=MYISAM;') FROM Information_schema.TABLES WHERE TABLE_SCHEMA = 'db_name' AND ENGINE = 'InnoDB' AND TABLE_TYPE = 'BASE TABLE'"

 

2.停止 MySQL之后,将 ibdata* 和 ib_logfiles 取出:

 

/etc/init.d/mysql stop
mkdir -p /root/innodb.bak
mv ib* /root/innodb.bak/
/etc/init.d/mysql start

 

3.现在,你的 MySQL 启动且其中的表使用 MyISAM,是时候将它们转换回 InnoDB了,祈祷把(再次用你的数据库名替换db_name ):

 

mysql -e "SELECT concat('ALTER TABLE ', TABLE_NAME,' ENGINE=InnoDB;') FROM  Information_schema.TABLES WHERE TABLE_SCHEMA = 'db_name' AND ENGINE = 'MyISAM'"

 

C.4 数据字典问题

 

在这些错误中,最常见的数据字典问题是有关表或表格文件不在InnoDB期望它们的状态,很多时候是由于不当删除InnoDB的.ibd或.frm文件,或者由于删除/移动ibdata文件。了解这些之后,要注意以下几点:

 

C.4.1 如何正确删除.ibd文件

数据库各子目录中的“.ibd文件代表在这些数据库中表的表空间。
删除文件本身会导致许多与InnoDB保持数据一致性的记录相关的问题。如果你由于一些原因(如尝试导入新的表空间/ idb文件)只要删除表空间,正确的方法是使用ALTER TABLE … DISCARD TABLESPACE语句,如:

 

mysql -e "ALTER TABLE roundcube.staff DISCARD TABLESPACE"

 

在上面的例子中,’roundcube’是数据库,’staff’是表。如果你这样做后检查数据库目录,你会发现虽然.frm文件仍然存在,但.ibd文件没了。记住,数据本身仍然显示于服务器上。

 

注:通常在这样操作之前,你需要先停用foreign_key_checks,通过以下操作执行:

 

SET FOREIGN_KEY_CHECKS=0;

 

C.4.2 ibd文件丢失后表的重建

 

如果你已删除或更改表空间(.ibd)文件,你很有可能遇到像这样一个错误:

 

[ERROR] MySQL is trying to open a table handle but the .ibd file for table dbname/tblname does not exist.

 

这个情况是它仍然认为表存在,这表示在该问题被解决之前,你将无法正常重建表。幸运的是,尽管执行失败,InnoDB能聪明地意识到发生了什么,并进行一些实用进程,如果运行以下命令(在适当处替换dbname和tblname):

第一步是尝试删除任何在表空间遗留的一切:

 

ALTER TABLE dbname.tblname DISCARD TABLESPACE;

 

它可能会或不会在MySQL shell报错,但如果你查看错误日志,它仍然继续清除缓冲:

 

InnoDB: Warning: cannot delete tablespace 251 in DISCARD TABLESPACE.
InnoDB: But let us remove the insert buffer entries for this tablesp ace.

 

然后,尝试删除实际表记录(如果你需要保存.frm文件来再次获得CREATE TABLE语句,确保在执行此步骤之前进行复制):

 

DROP TABLE dbname.tblname;

 

你更可能遇到类似的错误,但以下会在日志中再次出现

 

InnoDB: We removed now the InnoDB internal data dictionary entry
InnoDB: of table `dbname/tblname`.

 

之后你就能使用备份或.frm文件副本来重建表(使用之前描述的mysqlfrm方法)。

 

C.4.3 .frm文件存在,但表不存在

 

这是与之前问题的相同的行,但情况更简单,也更容易解决:

代码:

 

InnoDB: Cannot find table test/child2 from the internal data dictionary
InnoDB: of InnoDB though the .frm file for the table exists.

 

这里最常见的问题是,部分运行的删除或修改语句没有导致所有表中的文件被正确删除。在这些情况下,.frm文件可以简单地被安全删除,且InnoDB应该相应调整。我的建议是不要删除它,而是将其复制到备份文件夹,至少是暂时的,这样你就有CREATE TABLE语句,你可以以任何原因访问它。

 

If you did not intend to drop this table, or if the .ibd file was deleted by some other means, then aside from attempting some deep data recovery by digging through the ibdata file your only option in regards to restoring this table would be to restore from a backup, because InnoDB is essentially indicating in the error that this .frm file is absolutely the only thing left of the table in question. Definitely do not delete the .frm file if this is the case simply relocate it so that you can perhaps have a chance of recreating the table and rebuilding your data.

如果你不打算删除该表,或者如果.ibd文件通过其他方式被删除,那么除了通过挖掘ibdata文件尝试一些深层次的数据恢复,你唯一恢复表的方法就是从备份进行恢复,因为InnoDB基本上指明了错误,.frm文件是所剩表中唯一有问题的。如果是这样的话,绝对不要删除.frm文件,而是对它重新定位,这样或许有机会重建表,并重建你数据。

 

C.4.4 孤表或丢失的.frm文件

如果.frm文件因为某些原因丢失,你可能会看到如下所示的错误:

 

InnoDB: Error: table dbname/tblname already exists in InnoDB internal
InnoDB: data dictionary. Have you deleted the .frm file
InnoDB: and not used DROP TABLE? ...

 

在这种情况下,这个错误的说明通常描述了处理该问题最有效的方法:

 

 

InnoDB: You can drop the orphaned table inside InnoDB by
InnoDB: creating an InnoDB table with the same name in a nother
InnoDB: database and moving the .frm file to the current datab ase.
InnoDB: Then MySQL thinks the table exists, and DROP TABLE will
InnoDB: succeed.

 

 

这表示,如果你有孤表的CREATE TABLE语句,不论通过备份或其他方式,你可以创建一个测试数据库,并在其中创建表的副本(仅结构)。这将创建一个.frm文件,它可以用来复制到原始数据库,并替换丢失的.frm,使你能删除表。这里是一个简单的例子,假设原来的数据库和表名都是“test”:

 

代码:

 

# mysql

mysql> CREATE DATABASE test2;
mysql> CREATE TABLE ... CHARS ET=utf8;
mysql> quit
# cp /var/lib/mysql/test2/test.frm /var/lib/mysql/test/
# mysql
mysql> SET FOREIGN_KEY_CHECKS=0;
mysql> DROP TABLE test.test;

 

 

总结

InnoDB的数据一致性标准是一把双刃剑。当小心运作并充分理解它是如何操作时,它就是梦幻般的引擎,但很遗憾,当涉及对它的环境改变时,它就不是最宽容的了。它有一些很好的方法来处理自己的情况,还有一些出色的错误日志记录,但当要确保一个稳定的环境时,它也绝对是需要谨慎操作的。

 

沪ICP备14014813号-2

沪公网安备 31010802001379号