mysql误删除一个表,可以恢复吗

mysql误删除一个表,可以恢复吗,第1张

1、首先构建测试环境数据create table t1(a varchar(10),b varchar(10))insert into t1 values('1','1')insert into t1 values('2','2')commit。

2、模拟误修改,将t1表中的b字段更新为错误数据 "123456"update t1 set b='123456' where a='1'commitselect * from t1。

3、将恢复工具上传到服务器并进行解压。unzip binlog2sql-master.zip。

4、得到误修改时的binlog文件(show binary logs),实验环境是mysql-bin.000011。

5、通过 binlog2sql.py 脚本的到所有 对表 t1 的修改 *** 作。python binlog2sql.py -hlocalhost -P23307 -ubinlog2sql -p'binlog2sql' -dtest -tt1 --start-file='mysql-bin.000011'。

6、得到了误删除的sql的准确位置在1382-1615之间,使用 _**-B**_ 选项生成回滚sql。python binlog2sql.py -hlocalhost -P23307 -ubinlog2sql -p'binlog2sql' -dtest -tt1 --start-file='mysql-bin.000011' --start-position=1382 --stop-position=1615 -B。

7、执行得到的回滚语句进行误 *** 作恢复。就完成了。

误删数据的几种 *** 作

如何事前预防误删数据?

误删行数据恢复

误删行数据恢复可以使用 Flashback工具

Flashback恢复数据的原理是通过修改binlog内容,拿回原库进行回放,前提是 binlog_format=row和binlog_row_image=FULL

在使用Flashback进行恢复的时候, 不建议在主库上进行 *** 作 ,比较安全的做法是恢复出一个备份,或者找一个从库作为临时库,在这个临时库上执行 *** 作,然后再将确认过的临时库的数据恢复到主库。

误删库/表

drop table或者truncate table误删数据表 无法通过Flashback工具恢复 ,因为binlog_format的格式即使是ROW模式,在binlog中记录的也只是一条drop table或者truncate语句,因此无法进行恢复。

此时恢复的方式需要 全量备份加增量日志的方式进行恢复 ,因此要求数据有定期的全量备份,并且实时备份binlog。

假如某人在中午12点误删除了一个库里的某张表,恢复数据的流程如下:

mysqlbinlog恢复数据慢的原因?

如何更快的恢复误删的表?

在用备份恢复出临时实例以后,将这个临时实例设置成线上备库的从库:

假设此时备库的binlog已经被删除,那么需要去binlog备份系统找到删掉的日志文件拷贝到日志目录下,假设文件名是master.000001,打开日志目录下的binlog的index文件,在开头加入master.000001,让备库重新识别此日志文件

延迟复制备库

以上恢复都具有时间不可控性,如果采用上述步骤进行恢复,建议开发成工具(甚至可以做自己的DBA自动化平台),并大量测试后进行使用,避免手动误 *** 作带来更大的问题。

一般的主备复制存在的问题是,假设主库上的表被删除,这个命令很快会被发给所有从库,进而导致从库的数据表也被一起误删除。

延迟复制备库 是可以持续保持与主库有N秒延迟的备库

假设这里N=3600,那么表示只要在1个小时以内发现了误删除,就可以的到备库上执行stop slave,再通过之前讲到的方法,跳过误 *** 作的命令(比如将误删除的GTID加到实例集合中),就可以恢复出需要的数据。

rm误删

只要你的集群是高可用,如果rm删除了某个节点(只要不是恶意删除所有节点),HA系统会自动开始工作,选出一个新的主库,从而保证集群工作。

每个 DBA 是不是都有过删库的经历?删库了没有备份怎么办?备份恢复后无法启动服务什么情况?表定义损坏数据无法读取怎么办?

我曾遇到某初创互联网企业,因维护人员不规范的备份恢复 *** 作,导致系统表空间文件被初始化,上万张表无法读取,花了数小时才抢救回来。

当你发现数据无法读取时,也许并非数据丢失了,可能是 DBMS 找不到描述数据的信息

背景

先来了解下几张关键的 InnoDB 数据字典表,它们保存了部分表定义信息,在我们恢复表结构时需要用到。

SYS_TABLES 描述 InnoDB 表信息CREATE TABLE `SYS_TABLES` (`NAME` varchar(255) NOT NULL DEFAULT '',  表名`ID` bigint(20) unsigned NOT NULL DEFAULT '0',  表id`N_COLS` int(10) DEFAULT NULL,`TYPE` int(10) unsigned DEFAULT NULL,`MIX_ID` bigint(20) unsigned DEFAULT NULL,`MIX_LEN` int(10) unsigned DEFAULT NULL,`CLUSTER_NAME` varchar(255) DEFAULT NULL,`SPACE` int(10) unsigned DEFAULT NULL,   表空间idPRIMARY KEY (`NAME`)) ENGINE=InnoDB DEFAULT CHARSET=latin1SYS_INDEXES 描述 InnoDB 索引信息CREATE TABLE `SYS_INDEXES` (  `TABLE_ID` bigint(20) unsigned NOT NULL DEFAULT '0', 与sys_tables的id对应  `ID` bigint(20) unsigned NOT NULL DEFAULT '0',  索引id  `NAME` varchar(120) DEFAULT NULL,         索引名称  `N_FIELDS` int(10) unsigned DEFAULT NULL, 索引包含字段的个数  `TYPE` int(10) unsigned DEFAULT NULL,  `SPACE` int(10) unsigned DEFAULT NULL,  存储索引的表空间id  `PAGE_NO` int(10) unsigned DEFAULT NULL,  索引的root page id  PRIMARY KEY (`TABLE_ID`,`ID`)) ENGINE=InnoDB DEFAULT CHARSET=latin1SYS_COLUMNS 描述 InnoDB 表的字段信息CREATE TABLE `SYS_COLUMNS` (  `TABLE_ID` bigint(20) unsigned NOT NULL, 与sys_tables的id对应  `POS` int(10) unsigned NOT NULL,     字段相对位置  `NAME` varchar(255) DEFAULT NULL,    字段名称  `MTYPE` int(10) unsigned DEFAULT NULL,  字段编码  `PRTYPE` int(10) unsigned DEFAULT NULL, 字段校验类型  `LEN` int(10) unsigned DEFAULT NULL,  字段字节长度  `PREC` int(10) unsigned DEFAULT NULL, 字段精度  PRIMARY KEY (`TABLE_ID`,`POS`)) ENGINE=InnoDB DEFAULT CHARSET=latin1SYS_FIELDS 描述全部索引的字段列CREATE TABLE `SYS_FIELDS` (  `INDEX_ID` bigint(20) unsigned NOT NULL,  `POS` int(10) unsigned NOT NULL,  `COL_NAME` varchar(255) DEFAULT NULL,  PRIMARY KEY (`INDEX_ID`,`POS`)) ENGINE=InnoDB DEFAULT CHARSET=latin1./storage/innobase/include/dict0boot.h 文件定义了每个字典表的 index id,对应 id 的 page 中存储着字典表的数据。

这里我们需要借助 undrop-for-innodb 工具恢复数据,它能读取表空间信息得到 page,将数据从 page 中提取出来。

# wget https://github.com/chhabhaiya/undrop-for-innodb/archive/master.zip# yum install -y gcc flex bison# make# make sys_parser

# ./sys_parser 读取表结构信息

sys_parser [-h] [-u] [-p] [-d] databases/table

stream_parser 读取 InnoDB page 从 ibdata1 或 ibd 或分区表

# ./stream_parserYou must specify file with -f optionUsage: ./stream_parser -f <innodb_datafile>[-T N:M] [-s size] [-t size] [-V|-g]  Where:    -h         - Print this help    -V or -g   - Print debug information    -s size    - Amount of memory used for disk cache (allowed examples 1G 10M). Default 100M    -T         - retrieves only pages with index id = NM (N - high word, M - low word of id)    -t size    - Size of InnoDB tablespace to scan. Use it only if the parser can't determine it by himself.

c_parser 从 innodb page 中读取记录保存到文件

# ./c_parserError: Usage: ./c_parser -4|-5|-6 [-dDV] -f <InnoDB page or dir>-t table.sql [-T N:M] [-b <external pages directory>]  Where    -f <InnoDB page(s)>-- InnoDB page or directory with pages(all pages should have same index_id)    -t <table.sql>-- CREATE statement of a table    -o <file>-- Save dump in this file. Otherwise print to stdout    -l <file>-- Save SQL statements in this file. Otherwise print to stderr    -h  -- Print this help    -d  -- Process only those pages which potentially could have deleted records (default = NO)    -D  -- Recover deleted rows only (default = NO)    -U  -- Recover UNdeleted rows only (default = YES)    -V  -- Verbose mode (lots of debug information)    -4  -- innodb_datafile is in REDUNDANT format    -5  -- innodb_datafile is in COMPACT format    -6  -- innodb_datafile is in MySQL 5.6 format    -T  -- retrieves only pages with index id = NM (N - high word, M - low word of id)    -b <dir>-- Directory where external pages can be found. Usually it is pages-XXX/FIL_PAGE_TYPE_BLOB/    -i <file>-- Read external pages at their offsets from <file>.    -p prefix -- Use prefix for a directory name in LOAD DATA INFILE command

接下来,我们演示场景的几种数据恢复场景。

场景1:drop table

是否启用了 innodb_file_per_table 其恢复方法有所差异,当发生误删表时,应尽快停止MySQL服务,不要启动。若 innodb_file_per_table=ON,最好只读方式重新挂载文件系统,防止其他进程写入数据覆盖之前块设备的数据。

如果评估记录是否被覆盖,可以表中某些记录的作为关键字看是否能从 ibdata1 中筛选出。

# grep WOODYHOFFMAN ibdata1

Binary file ibdata1 matches

也可以使用 bvi(适用于较小文件)或 hexdump -C(适用于较大文件)工具

以表 sakila.actor 为例CREATE TABLE `actor` (`actor_id` smallint(5) 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 AUTO_INCREMENT=201 DEFAULT CHARSET=utf8

首先恢复表结构信息1. 解析系统表空间获取 page 信息

./stream_parser -f /var/lib/mysql/ibdata1

2. 新建一个 schema,把系统字典表的 DDL 导入

cat dictionary/SYS_* | mysql recovered

3. 创建恢复目录

mkdir -p dumps/default

4. 解析系统表空间包含的字典表信息,

./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t dictionary/SYS_TABLES.sql >dumps/default/SYS_TABLES 2>dumps/default/SYS_TABLES.sql./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000002.page -t dictionary/SYS_COLUMNS.sql >dumps/default/SYS_COLUMNS 2>dumps/default/SYS_COLUMNS.sql./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t dictionary/SYS_INDEXES.sql >dumps/default/SYS_INDEXES 2>dumps/default/SYS_INDEXES.sql./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000004.page -t dictionary/SYS_FIELDS.sql >dumps/default/SYS_FIELDS 2>dumps/default/SYS_FIELDS.sql

5. 导入恢复的数据字典

cat dumps/default/*.sql | mysql recovered

6. 读取恢复后的表结构信息

./sys_parser -pmsandbox -d recovered sakila/actor

由于 5.x 版本 innodb 引擎并非完整记录表结构信息,会丢失 AUTO_INCREMENT 属性、二级索引和外键约束, DECIMAL 精度等信息。

若是 mysql 5.5 版本 frm 文件被从系统删除,在原目录下 touch 与原表名相同的 frm 文件,还能读取表结构信息和数据。若只有 frm 文件,想要获得表结构信息,可使用 mysqlfrm --diagnostic /path/to/xxx.frm,连接 mysql 会显示字符集信息。

innodb_file_per_table=OFF

因为是共享表空间模式,数据页都存储在 ibdata1,可以从 ibdata1 文件中提取数据。

1. 获取表的 table id,sys_table 存有表的 table id,sys_table 表 index id 是1,所以从0000000000000001.page 获取表 id./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t dictionary/SYS_TABLES.sql | grep sakila/actor000000000B28  2A000001430D4D  SYS_TABLES  "sakila/actor"  158  4  1 0   0   ""  0000000000B28  2A000001430D4D  SYS_TABLES  "sakila/actor"  158  4  1 0   0   ""  0

2. 利用 table id 获取表的主键 id,sys_indexes 存有表索引信息,innodb 索引组织表,找到主键 id 即找到数据,sys_indexes 的 index id 是3,所以从0000000000000003.page 获取主键 id

./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t dictionary/SYS_INDEXES.sql | grep 158000000000B28    2A000001430BCA  SYS_INDEXES     158     376     "PRIMARY"       1       3       0       4294967295000000000B28    2A000001430C3C  SYS_INDEXES     158     377     "idx_actor_last_name"        1       0       0       4294967295000000000B28    2A000001430BCA  SYS_INDEXES     158     376     "PRIMARY"       1       3       0       4294967295000000000B28    2A000001430C3C  SYS_INDEXES     158     377     "idx_actor_last_name"        1       0       0       4294967295

3. 知道了主键 id,就可以从对应 page 中提取表数据,并生成 sql 文件。

./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000376.page -t sakila/actor.sql >dumps/default/actor 2>dumps/default/actor_load.sql

4. 最后导入恢复的数据

cat dumps/default/*.sql | mysql sakila

更多详细情况点击网页链接

请点击输入图片描述


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/8658146.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-19
下一篇 2023-04-19

发表评论

登录后才能评论

评论列表(0条)

保存