试图解决“outside tablespace bounds” MySQL 错误,但使用 mysqldump 恢复表失败

Erj*_*jen 6 mysql recovery

我在 Windows 2008 服务器上运行 MySQL。其中一个表(> 100 万条记录)似乎已损坏。mysql 错误日志显示:

InnoDB: Error: trying to access page number 197105 in space 89,
InnoDB: space name dbname/tablename,
InnoDB: which is outside the tablespace bounds.
InnoDB: Byte offset 0, len 16384, i/o type 10.
InnoDB: If you get this error at mysqld startup, please check that
InnoDB: your my.cnf matches the ibdata files that you have in the
InnoDB: MySQL server.
Run Code Online (Sandbox Code Playgroud)

根据此错误消息,我检查了my.cnf中的相关行:

innodb_data_home_dir = "C:/xampp/mysql/data"
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = "C:/xampp/mysql/data"
Run Code Online (Sandbox Code Playgroud)

这正是数据所在的位置。ibdata1大小约为 208 MB,tablename.ibd大小约为 4 GB。我已经成功使用这台服务器好几个月了。

在本网站和其他地方搜索后,我尝试按如下方式执行恢复:

  • 设置innodb_force_recovery=1然后到6
  • 接下来,使用 mysqldump 转储特定表。我正在使用此命令:mysqldump dbname tablename --user=root --password=blahblah. 在此转储期间,对于恢复级别 1 到 3,mysql 崩溃(“消失”)。在 4 时,它设法转储了前 23992 条记录,但随后它说

    tablename在行中转储表时,在查询期间失去与 MySQL 服务器的连接:23992。

    日志在我上面显示的内容之前有一些额外的行:

    InnoDB: Failed to find tablespace for table "dbname"."tablename" in the cache. Attempting to load the tablespace with space id 89. InnoDB: Error: trying to access page number 0 in space 89, InnoDB: space name dbname/tablename, InnoDB: which is outside the tablespace bounds.

  • 似乎只要我通过 php、python 或 phpMyAdmin 触摸或(选择)查询此表,mysql 就会崩溃。

是否有人有任何其他建议,可能基于上面的表空间边界错误?

提前致谢!

aku*_*sky 1

我们来详细说明一下错误消息

InnoDB:错误:试图访问空间89中的页码197105,

在该错误消息中,InnoDB 将 .ibd 文件称为“表空间”或仅称为“空间”。因此,有一个空格 89,它的其中一页引用了一个不存在的页码 197105。错误消息没有说明哪个表对应于空格 89。我认为某些 MySQL 版本告诉了这一点,但有可能找到来自 InnoDB 字典。

mysql> select NAME from information_schema.INNODB_SYS_TABLESPACES WHERE SPACE=4304;
+----------------------+
| NAME                 |
+----------------------+
| sakila/film_category |
+----------------------+
1 row in set (0.01 sec)
Run Code Online (Sandbox Code Playgroud)

现在,我们知道哪个表损坏了,问题是如何修复它。InnoDB 不会修复表空间(就像 MyISAM 那样REPAIR TABLE),唯一的方法是删除表空间(=表)并重新创建它。

在这种特殊情况下,没有必要以innodb_force_recovery模式启动 MySQL。只需正常启动并删除表即可。但首先,您可能需要保存该表中的数据。

有两种方法。首先,您可以选择未损坏主键值的范围并将它们转储到另一个表或文本转储中。我遇到过像这样的恢复案例,并编写了一个脚本来做到这一点。该脚本迭代 PK 范围并将尽可能多的记录转储到另一个 (MyISAM) 表中。

第二种方法需要更多的时间和技能。您将需要Undrop for InnoDB和包含步骤的博客文章

然后删除损坏的表,创建一个空表并加载恢复的转储。