大家好!我是黄啊码,MySQL的入门篇已经讲到第16个课程了,今天我们继续讲讲大白篇系列——科技与狠活之恢复数据库

在没做数据库备份,没有开启使用 Binlog 的情况下,尽可能地找回数据。

今天的内容主要包括以下几个部分:

InnoDB 存储引擎的表空间 InnoDB

存储引擎的文件格式是.ibd 文件,数据会按照表空间(tablespace)进行存储, 分为共享表空间和独立表空间。如果想要查看表空间的存储方式,我们可以对 innodb_file_per_table变量进行查询,使用show variables like 'innodb_file_per_table';。ON 表示独立表空间,而 OFF 则表示共享表空间。

如果采用共享表空间的模式,InnoDB 存储的表数据都会放到共享表空间中,也就是多个数 据表共用一个表空间,同时表空间也会自动分成多个文件存放到磁盘上。这样做的好处在于 单个数据表的大小可以突破文件系统大小的限制,最大可以达到 64TB,也就是 InnoDB 存 储引擎表空间的上限。不足也很明显,多个数据表存放到一起,结构不清晰,不利于数据的 找回,同时将所有数据和索引都存放到一个文件中,也会使得共享表空间的文件很大。

采用独立表空间的方式可以让每个数据表都有自己的物理文件,也就是 table_name.ibd 的 文件,在这个文件中保存了数据表中的数据、索引、表的内部数据字典等信息。它的优势在 于每张表都相互独立,不会影响到其他数据表,存储结构清晰,利于数据恢复,同时数据表 还可以在不同的数据库之间进行迁移。

如果.ibd 文件损坏了,数据如何找回

如果我们之前没有做过全量备份,也没有开启 Binlog,那么我们还可以通过.ibd 文件进行 数据恢复,采用独立表空间的方式可以很方便地对数据库进行迁移和分析。如果我们误删除 (DELETE)某个数据表或者某些数据行,也可以采用第三方工具回数据。

我们这里可以使用 Percona Data Recovery Tool for InnoDB 工具,能使用工具进行修复 是因为我们在使用 DELETE 的时候是逻辑删除。我们之前学习过 InnoDB 的页结构,在保 存数据行的时候还有个删除标记位,对应的是页结构中的 delete_mask 属性,该属性为 1 的时候标记了记录已经被逻辑删除,实际上并不是真的删除。

不过当有新的记录插入的时 候,被删除的行记录可能会被覆盖掉。所以当我们发生了 DELETE 误删除的时候,一定要 第一时间停止对误删除的表进行更新和写入,及时将.ibd 文件拷贝出来并进行修复。 如果已经开启了 Binlog,就可以使用闪回工具,比如 mysqlbinlog 或者 binlog2sql,从 工具名称中也能看出来它们都是基于 Binlog 来做的闪回。

原理就是因为 Binlog 文件本身 保存了数据库更新的事件(Event),通过这些事件可以帮我们重现数据库的所有更新变 化,也就是 Binlog 回滚。

下面我们就来看下没有做过备份,也没有开启 Binlog 的情况下,如果.ibd 文件发生了损 坏,如何通过数据库自身的机制来进行数据恢复。

实际上,InnoDB 是有自动恢复机制的,如果发生了意外,InnoDB 可以在读取数据表时自 动修复错误。但有时候.ibd 文件损坏了,会导致数据库无法正常读取数据表,这时我们就 需要人工介入,调整一个参数,这个参数叫做innodb_force_recovery。

我们可以通过命令

show variables like 'innodb_force_recovery';

来查看当前 参数的状态,你能看到默认为 0,表示不进行强制恢复。如果遇到错误,比如 ibd 文件中 的数据页发生损坏,则无法读取数据,会发生 MySQL 宕机的情况,此时会将错误日志记 录下来。

innodb_force_recovery参数一共有 7 种状态,除了默认的 0 以外,还可以为 1-6 的 取值,分别代表不同的强制恢复措施。

当我们需要强制恢复的时候,可以将innodb_force_recovery设置为 1,表示即使发现 了损坏页也可以继续让服务运行,这样我们就可以读取数据表,并且对当前损坏的数据表进 行分析和备份。 通常innodb_force_recovery参数设置为 1,只要能正常读取数据表即可。

但如果参数 设置为 1 之后还无法读取数据表,我们可以将参数逐一增加,比如 2、3 等。一般来说不需 要将参数设置到 4 或以上,因为这有可能对数据文件造成永久破坏。另外当 innodb_force_recovery设置为大于 0 时,相当于对 InnoDB 进行了写保护,只能进行 SELECT 读取操作,还是有限制的读取,对于 WHERE 条件以及 ORDER BY 都无法进行操 作。

当我们开启了强制恢复之后,数据库的功能会受到很多限制,我们需要尽快把有问题的数据 表备份出来,完成数据恢复操作。整体的恢复步骤可以按照下面的思路进行:

1. 使用innodb_force_recovery

启动服务器 将innodb_force_recovery参数设置为 1,启动数据库。如果数据表不能正常读取,需 要调大参数直到能读取数据为止。通常设置为 1 即可。

2. 备份数据表

在备份数据之前,需要准备一个新的数据表,这里需要使用 MyISAM 存储引擎。原因很简 单,InnoDB 存储引擎已经写保护了,无法将数据备份出来。然后将损坏的 InnoDB 数据表 备份到新的 MyISAM 数据表中。

3. 删除旧表

改名新表 数据备份完成之后,我们可以删除掉原有损坏的 InnoDB 数据表,然后将新表进行改名。

4. 关闭innodb_force_recovery

并重启数据库 innodb_force_recovery大于 1 的时候会有很多限制,我们需要将该功能关闭,然后重 启数据库,并且将数据表的 MyISAM 存储引擎更新为 InnoDB 存储引擎。

InnoDB 文件的损坏与恢复实例

我们刚才说了 InnoDB 文件损坏时的人工操作过程,下面我们用一个例子来模拟下。

生成 InnoDB 数据表

为了简便,我们创建一个数据表 t1,只有 id 一个字段,类型为 int。使用命令create table t1(id int);即可。

然后创建一个存储过程帮我们生成一些数据

BEGIN
-- 当前数据行
DECLARE i INT DEFAULT 0;
-- 最大数据行数
DECLARE max_num INT DEFAULT 100;
-- 关闭自动提交
SET autocommit=0;
REPEAT
SET i=i+1;
-- 向 t1 表中插入数据
INSERT INTO t1(id) VALUES(i);
UNTIL i = max_num
END REPEAT;
-- 提交事务
COMMIT;
END

然后我们运行call insert_t1(),这个存储过程帮我们插入了 100 条数据,这样我们就 有了 t1.ibd 这个文件。

模拟损坏.ibd 文件

实际工作中我们可能会遇到各种各样的情况,比如.ibd 文件损坏等,如果遇到了数据文件 的损坏,MySQL 是无法正常读取的。在模拟损坏.ibd 文件之前,我们需要先关闭掉 MySQL 服务,然后用编辑器打开 t1.ibd,类似下图所示:

文件是有二进制编码的,看不懂没有关系,我们只需要破坏其中的一些内容即可,比如我在 t1.ibd 文件中删除了 2 行内容(文件大部分内容为 0,我们在文件中间部分找到一些非 0 的取值,然后删除其中的两行:4284 行与 4285 行,原 ibd 文件和损坏后的 ibd 文件见 GitHub地址。其中 t1.ibd 为创建的原始数据文件,t1- 损坏.ibd 为损坏后的数据文件, 你需要自己创建 t1 数据表,然后将 t1- 损坏.ibd 拷贝到本地,并改名为 t1.ibd)。

然后我们保存文件,这时.ibd 文件发生了损坏,如果我们没有打开 innodb_force_recovery,那么数据文件无法正常读取。为了能读取到数据表中的数 据,我们需要修改 MySQL 的配置文件,找到[mysqld]的位置,然后再下面增加一行 innodb_force_recovery=1。

备份数据表

当我们设置innodb_force_recovery参数为 1 的时候,可以读取到数据表 t1 中的数 据,但是数据不全。我们使用SELECT * FROM t1 LIMIT 10;读取当前前 10 条数据。

但是如果我们想要完整的数据,使用SELECT * FROM t1 LIMIT 100;就会发生如下错 误。

这是因为读取的部分包含了已损坏的数据页,我们可以采用二分查找判断数据页损坏的位 置。这里我们通过实验,可以得出只有最后一个记录行收到了损坏,而前 99 条记录都可以 正确读出(具体实验过程省略)。

这样我们就能判断出来有效的数据行的位置,从而将它们备份出来。首先我们创建一个相同 的表结构 t2,存储引擎设置为 MyISAM。我刚才讲过这里使用 MyISAM 存储引擎是因为 在innodb_force_recovery=1的情况下,无法对 innodb 数据表进行写数据。使用命令 CREATE TABLE t2(id int) ENGINE=MyISAM;。

然后我们将数据表 t1 中的前 99 行数据复制给 t2 数据表,使用:

INSERT INTO t2 SELECT * FROM t1 LIMIT 99;

我们刚才讲过在分析 t1 数据表的时候无法使用 WHERE 以及 ORDER BY 等子句,这里我 们可以实验一下,如果想要查询 id<10 的数据行都有哪些,那么会发生如下错误。原因是 损坏的数据页无法进行条件判断。

删除旧表,改名新表

刚才我们已经恢复了大部分的数据。虽然还有一行记录没有恢复,但是能找到绝大部分的数 据也是好的。然后我们就需要把之前旧的数据表删除掉,使用DROP TABLE t1;。

更新表名,将数据表名称由 t2 改成 t1,使用RENAME TABLE t2 to t1;。

将新的数据表 t1 存储引擎改成 InnoDB,不过直接修改的话,会报如下错误:

关闭innodb_force_recovery,并重启数据库 因为上面报错,所以我们需要将 MySQL 配置文件中的innodb_force_recovery=1删除 掉,然后重启数据库。最后将 t1 的存储引擎改成 InnoDB 即可,使用ALTER TABLE t1 engine = InnoDB;。

总结:用这种方式恢复丢失的数据不可能100%完全找回来,只能尽可能找到,我们平常最主要的就是应该及时备份,并且开启二进制日志,这样当有误 操作的时候就可以通过数据库备份以及 Binlog 日志来完成数据恢复。同时采用延迟备份的 策略也可以尽量抵御误操作。

好了,今天的课程学到这里,有问题的留个言,别忘了一键三连,下次我们还会再见!

我是黄啊码,码字的码,退。。。退。。。退。。。朝!

【黄啊码】MySQL入门—17、在没有备份的情况下,如何恢复数据库数据?相关推荐

  1. centos下mysql常用的三种备份方法_centos下mysql自动备份(全量)

    1.新建mysql的备份目录mkdir -p path/mysql/backup/ 2.新建备份脚本vi path/mysql/backup/backup.sh #!/bin/bash backupd ...

  2. mysql 二进制日志在哪_如何通过Mysql的二进制日志恢复数据库数据

    经常有网站管理员因为各种原因和操作,导致网站数据误删,而且又没有做网站备份,结果不知所措,甚至给网站运营和盈利带来负面影响.所以本文我们将和大家一起分享学习下如何通过Mysql的二机制日志(binlo ...

  3. MySQL将表中的yes改成no_mysql在不需要改程序的情况下通过操作数据库对单表数据量大的表进行分表...

    1.为什么要分表? 数据库数据越来越大,随之而来的是单个表中数据太多.以至于查询速度变慢,而且由于表的锁机制导致应用操作也搜到严重影响,出现了数据库性能瓶颈. mysql中有一种机制是表锁定和行锁定, ...

  4. MySql通过Data恢复数据库数据

    Windows下将MySQL5.5升级为MySQL5.7 本机电脑之前是MySQL5.5直接升级到MySQL5.7之后,data中的数据不能解锁. MySQL5.5升级MySQL5.7,慌乱之中忘了用 ...

  5. php mysql 库存变负数_解决并发情况下库存减为负数问题

    场景: 一个商品有库存,下单时先检查库存,如果>0,把库存-1然后下单,如果<=0,则不能下单,事务包含两条sql语句: select quantity from products WHE ...

  6. mysql中backup_mysql中的备份(backup)和恢复(recovery)

    (一)备份类型(backup type) 物理和逻辑备份(Physical Versus Logical Backup) 物理备份是指直接复制存储数据库内容的目录和文件,这种类型的备份适用于出现问题时 ...

  7. 产品经理如何入门,没人带的情况下如何学习?

    自己也是一个自学的产品经理,简单的说下自己的学习历程和感悟吧,希望能给题主带来帮助: 一.产品经理的要求是什么? 如果说题主想要成为一个产品经理,不管自己的目的如何,是为了产品经理这个名头?逼格?收入 ...

  8. mysql 5.6 缓存_为什么默认情况下从MySQL 5.6开始禁用query_cache_type?

    您需要InnoDB的历史才能理解原因.它来了: 战争故事 InnoDB和查询缓存处于不断的战争状态.在检查InnoDB缓冲池中的更改然后交叉检查查询缓存以进行相同更改时,InnoDB往往非常苛刻. 和 ...

  9. mysql增删改查 工具类_JDBC工具类实现对数据库数据的增删改查

    1.先将连接的地址和账号密码放在属性文件中,本地连接直接///代替,java1.6以后自动加载驱动 url = jdbc:mysql:///testdata user =root password= ...

最新文章

  1. python标准库的基本使用
  2. laravel翻看php日志,关于Laravel的日志用法
  3. 粗略。。类设计的基本经验3之笔记
  4. SAP ABAP和C4C,Hybris Commerce里一些性能分析工具
  5. Gradle技巧–显示buildscript依赖项
  6. liunx立即关机命令是什么?
  7. ATM-object面向对象版本
  8. nacos默认用户名密码_Docker下,两分钟极速体验Nacos配置中心
  9. 【BZOJ】3289: Mato的文件管理(莫队算法+树状数组)
  10. 【网络通信 -- SIP 电话】项目实战记录 -- FreeSwitch 服务器搭建与典型 SIP 电话应用
  11. 单元刚度矩阵与刚度方程
  12. 如何重装win10应用商店?
  13. 兼容移动端的 Web 档案馆可视化管理系统
  14. 【Linux】ssh支持的加密算法有哪些?
  15. 剑~~~~~~~~~~
  16. Excel无法打开文件xxx.xlsx,因为文件格式或文件扩展名无效。请确定文件未损坏,并且文件扩展名与文件的格式匹配
  17. 【C语言】scanf函数报错
  18. C#像素鸟(独自一鸟闯天下)
  19. 藏在今日头条、喜马拉雅背后的神秘天使:龚挺 | 捕捉隐秘猎手
  20. 来自飞机座椅的实测数据

热门文章

  1. 《3ds Max疯狂设计学院》——1.4节学习3ds Max我还能用到哪些软件或插件?
  2. 练习2-4:调整名字的大小写 用变量表示一个人的名字,再以小写、大写和首字母大写的方式显示这个人名
  3. 《智能时代》读书笔记
  4. Linux-更改终端字体大小
  5. 使用JavaScript写一个三级下拉框联动
  6. python数组操作
  7. 验证键盘录入的用户名跟user.txt中已注册的用户名是否重复:是:控制台提示:用户名已存在否:将键盘录入的用户名及密码写入user.txt文件,并在控制台提示:注册成功;
  8. 【VBA编程】自定义函数,Function过程
  9. 解决重新启动电脑打印机自动打印上一次打印作业的方法
  10. php study 配合伪静态,phpStudy V8 Apache伪静态的配置教程图文说明,快米云