14.22.3 对 InnoDB 数据字典操作进行故障排除
有关 table 定义的信息既存储在.frm
文件中,又存储在 InnoDB data dictionary中。如果四处移动.frm
个文件,或者服务器在数据字典操作过程中崩溃,则这些信息源可能会变得不一致。
如果数据字典损坏或一致性问题使您无法启动InnoDB
,请参阅第 14.22.2 节“强制 InnoDB 恢复”以获取有关手动恢复的信息。
CREATE TABLE 由于孤立 table 而失败
数据字典不同步的症状是CREATE TABLE语句失败。如果发生这种情况,请查看服务器的错误日志。如果日志 table 明该 table 已经存在于InnoDB
内部数据字典中,则说明InnoDB
table 空间文件中有一个孤立 table,该 table 没有相应的.frm
文件。错误消息如下所示:
InnoDB: Error: table test/parent already exists in InnoDB internal
InnoDB: data dictionary. Have you deleted the .frm file
InnoDB: and not used DROP TABLE? Have you used DROP DATABASE
InnoDB: for InnoDB tables in MySQL version <= 3.23.43?
InnoDB: See the Restrictions section of the InnoDB manual.
InnoDB: You can drop the orphaned table inside InnoDB by
InnoDB: creating an InnoDB table with the same name in another
InnoDB: database and moving the .frm file to the current database.
InnoDB: Then MySQL thinks the table exists, and DROP TABLE will
InnoDB: succeed.
您可以按照错误消息中给出的说明删除孤立 table。如果仍然无法成功使用DROP TABLE,则问题可能是由于mysqlClient 端中的名称完成。要变通解决此问题,请使用--skip-auto-rehash选项启动mysqlClient 端,然后再次尝试DROP TABLE。 (启用名称补全后,mysql尝试构造 table 名称列 table,如果存在上述问题,该列 table 将失败。)
无法打开数据文件
启用innodb_file_per_table(默认)后,如果缺少file-per-tabletable 空间文件(.ibd
文件),则可能在启动时显示以下消息:
[ERROR] InnoDB: Operating system error number 2 in a file operation.
[ERROR] InnoDB: The error means the system cannot find the path specified.
[ERROR] InnoDB: Cannot open datafile for read-only: './test/t1.ibd' OS error: 71
[Warning] InnoDB: Ignoring tablespace `test/t1` because it could not be opened.
要解决这些消息,请发出DROP TABLE语句以从数据字典中删除有关丢失的 table 的数据。
无法打开文件错误
数据字典不同步的另一个症状是 MySQL 显示错误,无法打开InnoDB
文件:
ERROR 1016: Can't open file: 'child2.ibd'. (errno: 1)
在错误日志中,您可以找到以下消息:
InnoDB: Cannot find table test/child2 from the internal data dictionary
InnoDB: of InnoDB though the .frm file for the table exists. Maybe you
InnoDB: have deleted and recreated InnoDB data files but have forgotten
InnoDB: to delete the corresponding .frm files of InnoDB tables?
这意味着存在一个孤立的.frm
文件,而InnoDB
内没有相应的 table。您可以通过手动删除.frm
孤立文件来删除它。
孤立中级 table 格
如果 MySQL 在原位ALTER TABLE操作(ALGORITHM=INPLACE
)中间退出,则可能会留下一个孤立的中间 table,该 table 占用了系统空间。此外,否则为空的general tablespace中的孤立中间 table 可防止您删除常规 table 空间。本节介绍如何识别和删除孤立的中间 table。
中间 table 名称以#sql-ib
前缀(例如#sql-ib87-856498050
)开头。随附的.frm
文件具有#sql-*
前缀,并具有不同的名称(例如#sql-36ab_2.frm
)。
要标识系统上的孤立中间 table,您可以查询INFORMATION_SCHEMA.INNODB_SYS_TABLES。查找以#sql
开头的 table 名。如果原始 table 位于file-per-tabletable 空间中,那么孤立的中间 table 的 table 空间文件(#sql-*.ibd
文件)应该在数据库目录中可见。
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE '%#sql%';
要删除孤立的中间 table,请执行以下步骤:
- 在数据库目录中,重命名
#sql-*.frm
文件以匹配孤立中间 table 的基本名称:
shell> mv #sql-36ab_2.frm #sql-ib87-856498050.frm
Note
如果没有.frm
文件,则可以重新创建它。 .frm
文件必须具有与孤立中间 table 相同的 table 架构(它必须具有相同的列和索引),并且必须放置在孤立中间 table 的数据库目录中。
- 通过发出DROP TABLE语句,在 table 名前面加上
#mysql50#
并将 table 名括在反引号中来删除孤立的中间 table。例如:
mysql> DROP TABLE `#mysql50##sql-ib87-856498050`;
#mysql50#
前缀告诉 MySQL 忽略 MySQL 5.1 中引入的file name safe encoding
。要对具有特殊字符(例如“#”)的 table 名执行 SQL 语句,需要将 table 名括在反引号中。
Note
如果在将 table 移动到其他 table 空间的就地ALTER TABLE操作期间发生崩溃,则恢复过程会将 table 还原到其原始位置,但将孤立的中间 table 保留在目标 table 空间中。
Note
如果 MySQL 在分区 table 上执行ALTER TABLE操作的中间退出,则可能会留下多个孤立的中间 table,每个分区一个。在这种情况下,请使用以下过程删除孤立的中间 table:
-
在相同 MySQL 版本的单独实例中,创建一个具有与分区 table 相同的架构名称和列的未分区 table。
-
将非分区 table 的
.frm
文件复制到带有孤立中间 table 的数据库目录中。 -
为每个 table 制作一个
.frm
文件的副本,并重命名.frm
文件以匹配孤立中间 table 的名称(如上所述)。 -
对每个 table 执行DROP TABLE操作(如上所述)。
孤立的临时 table 格
如果 MySQL 在执行 table 复制ALTER TABLE操作(ALGORITHM=COPY
)的中间退出,则可能会留下一个孤立的临时 table,该 table 会占用系统空间。另外,否则为空的general tablespace中的孤立临时 table 可防止您删除常规 table 空间。本节介绍如何识别和删除孤立的临时 table。
孤立的临时 table 名称以#sql-
前缀(例如#sql-540_3
)开头。随附的.frm
文件具有与孤立临时 table 相同的基本名称。
Note
如果没有.frm
文件,则可以重新创建它。 .frm
文件必须具有与孤立临时 table 相同的 table 架构(必须具有相同的列和索引),并且必须放置在孤立临时 table 的数据库目录中。
要标识系统上的孤立临时 table,您可以查询INFORMATION_SCHEMA.INNODB_SYS_TABLES。查找以#sql
开头的 table 名。如果原始 table 位于file-per-tabletable 空间中,则孤立临时 table 的 table 空间文件(#sql-*.ibd
文件)应该在数据库目录中可见。
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE '%#sql%';
要删除孤立的临时 table,请通过发出DROP TABLE语句来删除该 table,并在 table 名前加上#mysql50#
并将 table 名括在反引号中。例如:
mysql> DROP TABLE `#mysql50##sql-540_3`;
#mysql50#
前缀告诉 MySQL 忽略 MySQL 5.1 中引入的file name safe encoding
。要对具有特殊字符(例如“#”)的 table 名执行 SQL 语句,需要将 table 名括在反引号中。
Note
如果 MySQL 在分区 table 的 table 复制ALTER TABLE操作中间退出,则可能会留下多个孤立的临时 table,每个分区一个。在这种情况下,请使用以下过程删除孤立的临时 table:
-
在相同 MySQL 版本的单独实例中,创建一个具有与分区 table 相同的架构名称和列的未分区 table。
-
将非分区 table 的
.frm
文件复制到带有孤立临时 table 的数据库目录中。 -
为每个 table 制作
.frm
文件的副本,并重命名.frm
文件以匹配孤立临时 table 的名称(如上所述)。 -
对每个 table 执行DROP TABLE操作(如上所述)。
table 空间不存在
启用innodb_file_per_table时,如果缺少.frm
或.ibd
文件(或两者),则可能会出现以下消息:
InnoDB: in InnoDB data dictionary has tablespace id N,
InnoDB: but tablespace with that id or name does not exist. Have
InnoDB: you deleted or moved .ibd files?
InnoDB: This may also be a table created with CREATE TEMPORARY TABLE
InnoDB: whose .ibd and .frm files MySQL automatically removed, but the
InnoDB: table still exists in the InnoDB internal data dictionary.
如果发生这种情况,请尝试以下过程解决问题:
-
在其他一些数据库目录中创建匹配的
.frm
文件,并将其复制到孤立 table 所在的数据库目录中。 -
原始 table 的发布DROP TABLE。那应该成功删除该 table,并且
InnoDB
应该在错误日志中显示一条警告,指出.ibd
文件丢失。
恢复每 table 孤儿文件 ibd 文件
此过程描述了如何将孤立的file-per-table .ibd
文件还原到另一个 MySQL 实例。如果系统 table 空间丢失或不可恢复,并且您想在新的 MySQL 实例上还原.ibd
文件备份,则可以使用此过程。
general tablespace .ibd
文件不支持该过程。
该过程假定您只有.ibd
个文件备份,并且要恢复到最初创建孤立.ibd
文件的 MySQL 版本,并且.ibd
文件备份是干净的。有关创建干净备份的信息,请参见第 14.6.1.4 节“移动或复制 InnoDBtable”。
第 14.6.1.3 节“导入 InnoDBtable”中概述的 table 导入限制适用于此过程。
- 在新的 MySQL 实例上,在同名数据库中重新创建 table。
mysql> CREATE DATABASE sakila;
mysql> USE sakila;
mysql> CREATE TABLE actor (
actor_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
first_name VARCHAR(45) NOT NULL,
last_name VARCHAR(45) NOT NULL,
last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (actor_id),
KEY idx_actor_last_name (last_name)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 丢弃新创建的 table 的 table 空间。
mysql> ALTER TABLE sakila.actor DISCARD TABLESPACE;
- 将孤立的
.ibd
文件从备份目录复制到新的数据库目录。
shell> cp /backup_directory/actor.ibd path/to/mysql-5.7/data/sakila/
-
确保
.ibd
文件具有必要的文件权限。 -
导入孤立的
.ibd
文件。发出警告,指示InnoDB
将尝试在不进行模式验证的情况下导入文件。
mysql> ALTER TABLE sakila.actor IMPORT TABLESPACE; SHOW WARNINGS;
Query OK, 0 rows affected, 1 warning (0.15 sec)
Warning | 1810 | InnoDB: IO Read error: (2, No such file or directory)
Error opening './sakila/actor.cfg', will attempt to import
without schema verification
- 查询 table 以验证
.ibd
文件已成功还原。
mysql> SELECT COUNT(*) FROM sakila.actor;
+----------+
| count(*) |
+----------+
| 200 |
+----------+