代码之家  ›  专栏  ›  技术社区  ›  Eva

从ibd文件恢复*partitiond*mysql InnoDB表

  •  4
  • Eva  · 技术社区  · 12 年前

    如何从TableName#P#pname.ibd格式的.ibd文件中恢复分区的mysql InnoDB表?Chris Calendar的文章在这里 http://www.chriscalender.com/?p=28 适用于具有单个.ibd文件的非分区表,但“丢弃”和“导入”步骤会导致分区表出现“存储引擎没有此选项”错误。

    Wes Smith在上面链接的一条评论中建议使用手动过程一次导入一个分区,但这对我来说并不奏效。如果我试图遵循他的方法,创建一个未分区的表,移动重命名为TableName.ibd的第一个.ibd文件,然后进行导入,导入成功,但表中没有任何行。随后建议的“在分区中添加回”步骤,我尝试 "alter table TableName partition by range ... (partition pname1 values less than (...) ENGINE=InnoDB)" 令人震惊的是,将TableName.ibd文件(对应于第一个分区)替换为大小微不足道的新TableName#P#pname1.ibd。尝试此操作时,我丢失了相当于一个分区的数据。我有大约150个分区要恢复。

    关于如何从.ibd文件中恢复数据,有什么建议吗?谢谢

    1 回复  |  直到 12 年前
        1
  •  1
  •   Eva    12 年前

    因此,事实证明,在原帖子链接的评论中建议的方法确实有效。我在上面的“alter table…”步骤中提到的分区的删除是合法的,因为它是在ibdata和日志文件丢失之前在原始表中故意删除的(但mysql无论如何都没有删除.ibd文件)。恢复过程非常缓慢,但我已经设法编写了脚本,并希望在接下来的几天内完成。

    如果您发现自己处于类似的情况,需要恢复许多分区,这里有一些提示。假设您有一个具有100个分区的表TableName。通常,如果100个分区是通过“create table”语句创建的,那么它们将具有连续的innodb ID,但通常情况下可能不是这样,因为分区可能是在创建后添加的。因此,以下是步骤:

    1) 在上面的博客中使用Calendar的方法找到每个分区对应的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的表TableName_i。例如,如果100个分区对应于ID 321、322、,。。。,370415416,。。。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)),那将是非常好和快速的,但我不确定是否有。