前言
单表恢复有两种情况:
1、主库单表恢复
2、从库单表恢复
下面就从这两种情况说一下解决思路和步骤
1、主库单库恢复
1.1 恢复思路
因为mysqlbinlog 对于单表过滤效果不好,可以通过对库的恢复然后跑binlog。看情况是否直接从备份机拉取整库备份。
如果单库数据量(相对全库较小),可从故意延迟从库mysqldump,如果单库数据量并不小,从远程备份机拉取全备
1.2 定位问题SQL
确定错误SQL类型:误操作 drop table,还是是dml 没有where条件
确定误操作大致时间
确定误操作大致时间
mysqlbinlog -vv -d test --start-datetime='xx' --stop-datetime='xx' mysqllogbin.000004 |egrep -B4 "INSERT|UPDATE|DELETE" |egrep -B4 "\`t3\`"
# at A
#131205 20:55:08 server id 18984603 end_log_pos 20393779 Query thread_id=16296016 exec_time=0 error_code=0 SET TIMESTAMP=1386248108/*!*/; BEGIN /*!*/; # at 20393779 #131205 20:55:08 server id 18984603 end_log_pos 20394211 Query thread_id=16296016 exec_time=0 error_code=0 SET TIMESTAMP=1386248108/*!*/; update table tablename set names='xxxx'; # at 20394211 #131205 20:55:08 server id 18984603 end_log_pos 20394238 Xid = 92465981 COMMIT/*!*/; # at B
1.3 单库备份恢复
# mysqldump -uroot -p123123 -S /mysqldata/mysql.sock --single-transaction --routines --events --master-data=2 test t1 >/tmp/t1.sql
# head -30 /tmp/t1.sql |egrep CHANGE , 得到位点C
# mysqlbinlog -vv -d test --start-position=C --stop-position=A mysqlbinlog--xxx >a.sql
# mysqlbinlog --vv -d test --start-positoon=B --stop-position=xx mysqlbinlog-xx >b.sql
1.4 全库备份恢复
全库恢复
恢复binlog,跳过错误SQL
2、从库单表快速恢复
2.1 情景描述

2.2 恢复过程
1. 从库发现复制异常,stop slave
2. 主库用mysqldump导出单表,注意,单表是导出开始时刻数据,master-data 记录位点A
3. 从库恢复单表
4. 修改my.cnf ,开启复制过滤、skip-slave-start 重启数据库
5. start slave until A, 直到追平到主库mysqldump时刻
6. 修改my.cnf ,去掉复制过滤,重启,start slave
2.3 实验模拟
主库建表插入数据
08:37:59 (none)> create database test ;
11:02:12 (none)> use test;
11:02:15 test> create table t1 (id int primary key ,age int );
11:03:14 test> create table t2 (id int primary key,name varchar(20));
11:02:48 test> insert into t1 values (1,1),(2,2);
11:03:39 test> insert into t2 values(1,'a'),(2,'b');
11:02:12 (none)> use test;
11:02:15 test> create table t1 (id int primary key ,age int );
11:03:14 test> create table t2 (id int primary key,name varchar(20));
11:02:48 test> insert into t1 values (1,1),(2,2);
11:03:39 test> insert into t2 values(1,'a'),(2,'b');
从库模拟误操作:
mysql> drop table t1;
主库正常继续操作
11:27:25 test> insert into t2 values (3,'c');
从库开始报错
mysql> show slave status G*************************** 1. row *************************** Last_Errno: 1146
Last_Error: Error executing row event: 'Table 'test.t1' doesn't exist' Last_SQL_Error: Error executing row event: 'Table 'test.t1' doesn't exist'
mysql> stop slave ;
主库继续操作,并单表导出,查看位点
[root@ser1 mysqldata]# >/tmp/t1.sql
[root@ser1 mysqldata]# mysqldump -uroot -p123123 -S /mysqldata/mysql.sock --single-transaction --routines --events --master-data=2 test t1 >/tmp/t1.sql[root@ser1 mysqldata]# head -30 /tmp/t1.sql |egrep CHANGE
-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.000054', MASTER_LOG_POS=10593;[root@ser1 ~]# scp /tmp/t1.sql root@192.168.234.130:/tmp/
11:32:27 test> insert into t1 values (4,4);11:27:35 test> insert into t2 values (4,'d');
从库恢复单表
[root@ser2 ~]# mysql -uroot -p123123 test </tmp/t1.sql mysql> select * from t1; //数据是备份时刻 t1的最新数据+----+------+| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+mysql> select * from test.t2; //数据是从库复制错误时刻的点,恢复后 t1 表新于 t2 表
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
4 rows in set (0.00 sec)
开启复制过滤,重启
[root@ser2 ~]# cat /etc/my.cnf |egrep -i "Repl*" -B1
skip-slave-start
replicate_wild_ignore_table=test.t1 //复制忽略test.t1这个表
[root@ser2 ~]# service mysqld restart
Shutting down MySQL.. [ OK ]
Starting MySQL. [ OK ]
# 开启复制过滤主从执行到备份点,让其他表执行到一致位点。
mysql> START SLAVE UNTIL MASTER_LOG_FILE = 'binlog.000054', MASTER_LOG_POS=10593;
mysql> show slave status G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Log_File: binlog.000054
Slave_IO_Running: Yes // IO线程连接正常
Slave_SQL_Running: No //执行到这个位点就不再执行了
Exec_Master_Log_Pos: 10593 //执行到了指定的点
mysql> select * from test.t2; //t2执行到备份开始点,t1/t2 时刻一致了
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+------+
6 rows in set (0.00 sec)
关闭复制过滤,正常启动slave
[root@ser2 ~]# vim /etc/my.cnf
#replicate_wild_ignore_table=test.t1 //关闭复制过滤表
[root@ser2 ~]# service mysqld restart
mysql> start slave;
mysql> select * from t1;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
+----+------+
mysql> select * from t2;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
+----+------+