首页 > 数据库 >MySQL借助ibd文件恢复数据技巧?

MySQL借助ibd文件恢复数据技巧?

时间:2023-08-29 09:58:36浏览次数:43  
标签:文件 技巧 数据库 ibd 备份 MySQL 空间 id

还记得我们之前写过的《只需一招,让失控的研发爱上你》吗?前文提到过我们日常使用的比较多的两种数据库恢复方法是:

MySQL借助ibd文件恢复数据技巧?MySQL借助ibd文件恢复数据技巧?

以上两种方法都可以实现实时性的回档,但是你会认为有了这两种技能就够了吗?

不….!

在线上这种错综复杂的架构中,其实还有很多未知的原因,我们是没法预知的。例如以下这种情况:

因辛勤劳动而折寿的磁盘产生成长坏道,导致数据库损坏。而又刚好损坏了ibdata文件和binlog文件。那么如果还想着以定时备份+binlog恢复的方案就不可能了,难道只能用定点备份回档吗?深思熟虑后,作为一名运维人员,我们是绝对不会在万不得已的情况下实行有损回档,因为这对业务产生太大的影响了,但是除此之外又能怎么办呢?下面我们将要放一门大招!!!

首先检查数据库环境,是否开启了独立表空间,如果已经开启的话,那恭喜你,有很大的机会可以恢复全部数据。我们可以依赖每个数据库目录下的frm和ibd文件来实现数据恢复,一般来说如果使用了InnoDB但没开启独立表空间的话,所有的数据库表信息和元数据都会写入ibdata文件里,这样长久运行的话,ibdata文件会变得越来越大,数据库性能下降。InnoDB提供了开启独立表空间参数,可以让数据独立存放起来,这样子ibdata文件只用于存放一些引擎相关的索引信息,实际的数据写入到独立的frm和ibd文件里。

好,有了frm和ibd文件,我们可以开始尝试数据恢复了,他的过程比binlog还原既惊险又有趣!首先我们来看一下关于ibd和frm的说明:

.frm文件:保存了每个表的元数据,包括表结构的定义等,该文件与数据库引擎无关。

.ibd文件:InnoDB引擎开启了独立表空间(my.ini中配置innodb_file_per_table = 1)产生的存放该表的数据和索引的文件。

我们都知道,对于InnoDB的数据库,如果不把整个数据目录拷贝,只拷贝指定数据库目录到新的实例下,数据库是认不出来的。那么如何根据这两个文件还恢复数据库呢?

恢复思路:

由于ibdata文件上存放了一些关于引擎的索引信息,ibdata文件损坏导致表名索引丢失而无法启动。那么我们可以先把原来旧的整个数据目录改名备份,然后重新初始化数据库生成新的ibdata文件,然后重新创建原有的数据库以及对应的表,最后把备份的表空间id号改为新建的表空间id号(ibdata文件里有每个表唯一的表空间索引id,该id由创建新表的数量依次递增),这样就可以恢复原来的数据库了。
举个例子:
库名:test_restore
表结构:db_struc.sql
表文件:G_RESTORE.ibd、G_RESTORE.frm

1. 创建新库,导入表结构

#mysql -uroot –p****  -e “create database test_restore”

#mysql -uroot –p****  test_restore < db_struc.sql

2. 查看并修改test_restore库中表在新实例中的id
#vim -b /data/database/mysql/test_restore/G_RESTORE.ibd

直接打开为乱码,转成16进制查看。Vi中执行  :%!xxd 转化为16进制。结果为 :

MySQL借助ibd文件恢复数据技巧?MySQL借助ibd文件恢复数据技巧?

如图所示。G_RESTORE表在mysql数据库中的id为00fe。

修改备份的G_RESTORE.ibd文件。操作同上,注意需先备份。

#cp G_RESTORE.ibd{,_back}

#vim -v G_RESTORE.ibd

MySQL借助ibd文件恢复数据技巧?MySQL借助ibd文件恢复数据技巧?

将011b修改为00fe 。注意。修改完成后需要在vim中先执行 :%!xxd  -r

再wq 保存退出文件。不然保存到的是16进制查看的结果。

保存结果如下:

MySQL借助ibd文件恢复数据技巧?MySQL借助ibd文件恢复数据技巧?

 

将修改好的G_RESTORE.ibd 替换掉新数据库中的G_RESTORE.ibd文件。

关于ibdata表id的解释:

MySQL借助ibd文件恢复数据技巧?MySQL借助ibd文件恢复数据技巧?

参考官方文档解释,每个表空间分配了4个字节存储了表空间id信息,最后偏移量地址为38。还有一组预留的表空间id,同样是4个字节,最后偏移量地址为42。

3. 验证并还原mysql数据

关闭mysql。修改my.conf。
innodb_force_recovery=6 innodb_purge_threads=0

启动数据库。如果不修改。数据库会认为G_RESTORE已被损坏。

Select 一下,即可查看到还原结果,但此时插入数据会报错,应尽快将数据dump出来 ,导回原来的实例中。

导出数据,再导入数据,恢复完毕!

#mysqldump -uroot –p****** test_restore > test_restore.sql

#mysql -uroot –p****** test_restore < test_restore.sql

说明:变更了新的space id后的.ibd表文件,启动数据库后只能认出数据,但不能写入,这是因为原ibdata文件不仅保存了space id索引,还同时保存了一些其它的元数据。为了使元数据补全,所以采取导出、再导入的操作。

以上举例为单个库表的恢复过程,看到这里大家一定会产生另一个疑问吧?线上的场景不可能是只有一个表的,数据库表很多的情况下,这样一个个表的修改,速度无疑是太慢了。那么存在大量表的情况下如何恢复呢?思路是,取得备份的ibd文件的id值,按id值顺序来建表,中间跨度随便建表语句来凑够数(每个表空间索引id由创建新表的数量依次递增)。实现方式如下:

1. 获取备份数据库ibd文件的space id号,并排序。

for ibd in `find test_restore/ -name “*.ibd”` ; do  echo -e “${ibd///// }   /c” ;hexdump -C ${ibd} |head -n 3 |tail -n 1|awk ‘{print  strtonum(“0x”$6$7)}’ ;done | sort -n  -k 3 | column -t > /tmp/

生成的ibd.txt文件,格式如下:(库名–表名–SpaceId)

MySQL借助ibd文件恢复数据技巧?MySQL借助ibd文件恢复数据技巧?
2. 新建表,查看当前表空间id(假设space id为10)

#mysql -uroot –p****** -e”create table test.tt(a bool)”

#hexdump -C mysql/test/tt.ibd |head -n 3 |tail -n 1|awk ‘{print  strtonum(“0x”$6$7)}’

3. 先创建所有库,准备所有表结构,写脚本,依据space id号自动创建新表

准备好数据库表结构,可以从备份文件里取出来(我们备份方式是把结构和数据分开备份的),或者从其他有相同表结构的服务器上备份再拷贝过来。

参考备份语句:

mysqldump -uroot –p****** -d ${db} –T /data/backup/${db}/

创建原有的数据库:

mysql -uroot –p****** -e “create database ${db}”

恢复表id创建表脚本

#!/bin/bash
#因为前面假设为10,所以从11开始创建
oid=11

#打开前面生成的ibd.txt文件,按行读取”库名–表名–SpaceId”
cat /tmp/ibd.txt | while read db tb id ;do

#假如我们需要恢复catetory表,他的id为415,基于id是创表自增的原则,即415-11=404,
#我们还需要循环创建404个表后,才真正导入catetory表结构。
for ((oid;oid<id;oid++)); do
mysql -uroot –p****** -e “create table test.t(a bool);drop table test.t;” && echo “${oid} ok”
done

#循环创建404次表后,id为415,与原来备份的.ibd文件编号一致,导入表结构
mysql -uroot –p****** ${db} < /data/backup/${db}/${tb%%.ibd}.sql && echo “${oid} ${db}/${tb%%.ibd}.sql ok”
let oid=oid+1
done

4. 检查表空间id 和备份的是否一致

for ibd in `find test_restore/ -name “*.ibd”` ; do  echo -e “${ibd///// }   /c” ;hexdump -C ${ibd} |head -n 3 |tail -n 1|awk ‘{print  strtonum(“0x”$6$7)}’ ;done | sort -n  -k 3 | column -t > /tmp/ibd2.txt

确认一致后,拷贝备份的.ibd文件到新数据库实例目录下,修改my.cnf

innodb_force_recovery=6

innodb_purge_threads=0

启动数据库。后续步骤如同单表恢复,直接导出恢复到原来实例中即可。

当然,这种方式是在数据库出现极端情况下,不得不采取的一种方式,线上最重要的还是做好主从同步和定时备份,从而规避此类风险。

关于InnoDB引擎独立表空间说明:

使用过MySQL的同学,刚开始接触最多的莫过于MyISAM表引擎了,这种引擎的数据库会分别创建三个文件:表结构、表索引、表数据空间。我们可以将某个数据库目录直接迁移到其他数据库也可以正常工作。然而当你使用InnoDB的时候,一切都变了。

InnoDB默认会将所有的数据库InnoDB引擎的表数据存储在一个共享空间中:ibdata1,这样就感觉不爽,增删数据库的时候,ibdata1文件不会自动收缩,单个数据库的备份也将成为问题。通常只能将数据使用mysqldump导出,然后再导入解决这个问题。

但是可以通过修改MySQL配置文件[mysqld]部分中innodb_file_per_table的参数来开启独立表空间模式,每个数据库的每个表都会生成一个数据空间。

优点:

1.每个表都有自已独立的表空间。

2.每个表的数据和索引都会存在自已的表空间中。

3.可以实现单表在不同的数据库中移动。

4.空间可以回收(除drop table操作处,表空不能自已回收)

a) Drop table操作自动回收表空间,如果对于统计分析或是日值表,删除大量数据后可以通过:alter table TableName engine=innodb;回缩不用的空间。

b) 对于使innodb-plugin的Innodb使用turncate table也会使空间收缩。

c) 对于使用独立表空间的表,不管怎么删除,表空间的碎片不会太严重的影响性能,而且还有机会处理。

缺点:

单表增加过大,如超过100个G。

结论:

共享表空间在Insert操作上少有优势。其它都没独立表空间表现好。当启用独立表空间时,请合理调整一下:innodb_open_files。

配置方式:
1.innodb_file_per_table设置.开启方法:

在my.cnf中[mysqld]下设置

innodb_file_per_table=1
2.查看是否开启:
mysql> show variables like ‘%per_table%’;

3.关闭独享表空间
innodb_file_per_table=0关闭独立的表空间

mysql> show variables like ‘%per_table%’;

标签:文件,技巧,数据库,ibd,备份,MySQL,空间,id
From: https://www.cnblogs.com/roccn/p/17663950.html

相关文章

  • 初识MySql
    初始MySqljavaEE:企业级java开发web前端(页面:展示,数据!)后台(连接点,链接数据库JDBC,链接前端(控制,控制试图跳转,给前端传数据))数据库(存数据,Txt,Excel,Word)1.只写代码,数据库。基本操作2.操作系统,数据结构与算法!3.离散数学,数学电路,体系结构1.学习数据库原因?岗位需求。大数据时代。......
  • MYSQL基础语法-cnblog
    MYSQL基础语法基础语法:1.创建数据库:creatdatabase***;(数据库名称自定义)2.使用数据库:use***;(已经创建好的数据库名称)3.描述表的结构:desc**(表字段成员)4.显示表格:showtables;5.查询当前数据库:selectdatabase();6.重命名文件:select--as(as可省略)--(中文......
  • 再遇 MySQL “一招必杀” Bug
    TL;DR该Bug与DerivedConditionPushdownOptimization相关,从MySQL8.0.26引入,8.0.27和8.0.28仍受影响,直到MySQL8.0.29被修复。但是,MySQL8.0.29有其他致命缺陷,官网已经移除下载链接,建议升级到新版本MySQL8.0.33或MySQL8.0.34。问题现象该问题是vx群里的好......
  • QT连接MySql关于驱动问题
    今天分享一下在qt中连接数据库遇到的一些问题,主要是mysql驱动以及mysql动态库加载1.环境变量配置一下mysql和QT的环境变量,这个比较简单,各位自行百度。2.编译mysql驱动用QT打开mysql.pro文件,在第六行首加上#,然后在末尾加入:win32:LIBS+=-LD:/MySql/mysql-8.1.0-winx64/lib-l......
  • 数据库MySQL
     Concat(a,b)连接a,b两个字段                                    MySQL函数       分组之后再插入查询条件不能用Where关键字,而要用HA......
  • MySQL 分析查询与来源机器
    当前分析针对版本:MariaDB10.5线上出现报错:can'tcreatemorethanmax_prepared_stmt_countstatements。造成这个错误的直接原因就是同时开启了prepare句柄太多导致的,所以比较直接的方式是调大参数,首先查看设置的值:showglobalvariableslike'max_prepared_stmt_count';......
  • Arch中使用Qt6的QtSql出现mysql driver not loaded的解决记录
    查阅了网上的说法,出现这个错误的原因大致可能有以下几种:Qt和mysql的位数不一样,一个是32位的,一个是64位的Qt中自带的驱动库与所使用的版本不匹配代码写错了,比如"QMYSQL"写成了"MYSQL"我出现个问题的原因是第二种。参考了一位老哥的博客QTMacM1解决mysqldrivernotloade......
  • MySQL的连接和导出数据分析和lift曲线
    MySQL的连接和使用https://www.cnblogs.com/zdstudy/p/16567399.htmlmysql使用网址https://blog.csdn.net/LikiLyn/article/details/120385981多个文件mergeimportpandasaspdimportnumpyasnpimportpymysql#%%打开数据库连接conn=pymysql.connect(host='地址',user......
  • mysql日志追踪 / 数据恢复
    1.查看日志开启状态showvariableslike'log_%';2.查看日志文件列表showbinarylogs;或者showmasterlogs;3.查看当前日志index位置showmasterstatus;4.查看binlog关键事件showbinlogevents[IN'log_name'][FROMpos][LIMIT[offset,]row_c......
  • MySQL online DDl原理
    onlineDDL从5.6开始,不阻塞DML但是会阻塞所有的DDL,online有三种模式:INSTANT(8.0.12),INPLACE(rebuild),INPLACE(no-rebuild),具体操作如下:1、只修改表的元数据信息删除二级索引修改索引名(5.7)修改字段名设置(删除)字段的默认值增加varchar长度,如果表示字符串长度的字节数变化则会使用c......