因此,事实证明,原始帖子链接的评论中建议的方法确实有效。我在上面的“更改表...”步骤中提到的分区的删除是合法的,因为在丢失 ibdata 和日志文件之前,它已在原始表中被故意删除(但 mysql 无论如何都不会删除 .ibd 文件) . 恢复过程非常缓慢,但我设法编写了脚本并希望让它在接下来的几天内运行完成。
如果您发现自己处于类似情况,需要恢复许多分区,这里有一些提示。假设您有一个包含 100 个分区的表 TableName。通常,如果通过“create table”语句创建 100 个分区,它们将具有连续的 innodb ID,但通常情况可能并非如此,因为分区可能是在创建后添加的。所以,这里是步骤:
1)使用上面博客中Calendar的方法找出每个partition对应的innodb ID如下。注意这一步不需要重启mysql服务器。只需创建一个像 TableName 这样没有任何分区的表并丢弃它的表空间。然后将第一个分区的 .ibd 文件(命名为 TableName#P#pname1.ibd)作为 TableName.ibd 移动到数据库目录并尝试导入它。查看 mysql error.log(通常是 /var/log/mysql/error.log)以查看该分区的 innodb ID 是什么。对每个分区(或根据需要)重复此步骤,直到文件中的所有分区都有 2 元组(innodb_ID_i,partition_boundary_i)。
2)从一个空的innodb状态开始(停止服务器,删除ibdata和ib_logfile*,重新启动服务器)。对于上面步骤 1 中文件中的每个 innodb_ID 条目,创建一个表 TableName_i,如 TableName。例如,如果这 100 个分区对应的 ID 为 321、322、...、370、415、416、...464(两个块,每个块有 50 个连续 ID),那么编写一个脚本来创建 320 个虚拟表,50 个表像 TableName、45 个虚拟表和 50 个像 TableName 的表。
3) 对于上面创建的每个 TableName_i 表,
--do
(i) rename table TableName_i to TableName
(ii) alter table TableName discard tablespace // important to do this step before the next one
(iii) mv TableName#P#pname_i.ibd TableName.ibd // with the appropriate directory prefixes
(iv) alter table TableName import tablespace
(v) alter table partition by range (partition_field) (partition pname_i values less than (partition_boundary_i)) // This is the most and only time consuming step
(vi) rename table TableName to TableName_i // or some other name or just dump it to a file
--repeat
请注意,上述所有步骤都是可编写脚本的,并且不需要在任何时候重新启动服务器,除非在第 2 步开始时以空的 innodb 状态开始。在进行下一步之前,请注意在步骤 3 中引入对每个子步骤是否成功的检查,否则后续步骤可能会失败和/或 .ibd 文件可能会被覆盖。如果可行,请在步骤 3(iii) 中使用副本而不是 mv。
最后一点:使用 percona 的恢复工具包使用十六进制编辑可能会稍微简单一些,但这不适用于我的分区表情况。我遇到了同样的,看似未解决的问题,分区表如http://www.mysqlperformanceblog.com/2011/05/13/connecting-orphaned-ibd-files/的评论之一所述。不过,您的里程可能会有所不同。如果有一种方法可以避免重新创建分区(如上面的步骤 3(v)),那将是非常好的和快速的,但我不确定是否有一个。