原理:binlog日志保存的是数据变化的DDL和DML SQL,并在每条SQL打上了时间缀和标记,所以可以指定时间和标记,找到指定SQL,恢复特定数据。
实战:从删库到恢复,不用再跑路。
1、建库建表准备数据再删库
mysql> flush binary logs;
Query OK, 0 rows affected (0.01 sec)
mysql> create database mydb;
Query OK, 1 row affected (0.00 sec)
mysql> use mydb;
Database changed
mysql> create table t(id int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t values(1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t values(2);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t values(3);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
mysql> drop database mydb;
Query OK, 1 row affected (0.05 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
8 rows in set (0.00 sec)
2、查看binlog日志记录
mysql> flush binary logs;
Query OK, 0 rows affected (0.01 sec)
mysql> show binary logs;
+---------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000001 | 3116922 | No |
| binlog.000002 | 139255766 | No |
| binlog.000003 | 157 | No |
| binlog.000004 | 201 | No |
| binlog.000005 | 1674 | No |
| binlog.000006 | 492 | No |
| binlog.000007 | 2196 | No |
| binlog.000008 | 489 | No |
| binlog.000009 | 2167 | No |
| binlog.000010 | 1570 | No |
| binlog.000011 | 157 | No |
+---------------+-----------+-----------+
11 rows in set (0.00 sec)
mysql> show binlog events in 'binlog.000010';
+---------------+------+----------------+-----------+-------------+--------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+---------------+------+----------------+-----------+-------------+--------------------------------------------------+
| binlog.000010 | 4 | Format_desc | 1 | 126 | Server ver: 8.0.28, Binlog ver: 4 |
| binlog.000010 | 126 | Previous_gtids | 1 | 157 | |
| binlog.000010 | 157 | Anonymous_Gtid | 1 | 234 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000010 | 234 | Query | 1 | 342 | create database mydb /* xid=799 */ |
| binlog.000010 | 342 | Anonymous_Gtid | 1 | 419 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000010 | 419 | Query | 1 | 529 | use `mydb`; create table t(id int) /* xid=804 */ |
| binlog.000010 | 529 | Anonymous_Gtid | 1 | 608 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000010 | 608 | Query | 1 | 683 | BEGIN |
| binlog.000010 | 683 | Table_map | 1 | 730 | table_id: 99 (mydb.t) |
| binlog.000010 | 730 | Write_rows | 1 | 770 | table_id: 99 flags: STMT_END_F |
| binlog.000010 | 770 | Xid | 1 | 801 | COMMIT /* xid=805 */ |
| binlog.000010 | 801 | Anonymous_Gtid | 1 | 880 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000010 | 880 | Query | 1 | 955 | BEGIN |
| binlog.000010 | 955 | Table_map | 1 | 1002 | table_id: 99 (mydb.t) |
| binlog.000010 | 1002 | Write_rows | 1 | 1042 | table_id: 99 flags: STMT_END_F |
| binlog.000010 | 1042 | Xid | 1 | 1073 | COMMIT /* xid=806 */ |
| binlog.000010 | 1073 | Anonymous_Gtid | 1 | 1152 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000010 | 1152 | Query | 1 | 1227 | BEGIN |
| binlog.000010 | 1227 | Table_map | 1 | 1274 | table_id: 99 (mydb.t) |
| binlog.000010 | 1274 | Write_rows | 1 | 1314 | table_id: 99 flags: STMT_END_F |
| binlog.000010 | 1314 | Xid | 1 | 1345 | COMMIT /* xid=807 */ |
| binlog.000010 | 1345 | Anonymous_Gtid | 1 | 1422 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000010 | 1422 | Query | 1 | 1526 | drop database mydb /* xid=809 */ |
| binlog.000010 | 1526 | Rotate | 1 | 1570 | binlog.000011;pos=4 |
+---------------+------+----------------+-----------+-------------+--------------------------------------------------+
24 rows in set (0.00 sec)
1、看info列,找create database,位于第4行,其上一行为SET...设置SQL执行的环境变量,Pos为157,把它当作start-position;
2、看info列,先找drop database,再找其上方COMMIT,找到该行的End_log_pos 为1345,把它当作end-position;
3、恢复数据,用上方找到start-position和end-position,筛选出所需binlog日志,再导入DB。
root@mysql:~# mysqlbinlog --start-position=157 --stop-position=1345 --database=mydb -v /var/lib/mysql/binlog.000010 > binlog_rec.txt
root@mysql:~# mysql -uroot -p123456 -v < binlog_rec.txt
4、检查恢复数据,数据库mydb恢复,表t恢复,数据恢复。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mydb |
| mysql |
| performance_schema |
| sys |
+--------------------+
9 rows in set (0.00 sec)
mysql> use mydb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+----------------+
| Tables_in_mydb |
+----------------+
| t |
+----------------+
1 row in set (0.00 sec)
mysql> select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
注意:如果binlog日志太大,mysql> show binary logs; 难以精确定位到Pos范围,使用mysqlbinlog联合grep一起查找,如下,Pos和End_log_pos为“# at”打头的行,同样能找到157和1345。
root@mysql:~# mysqlbinlog -v --base64-output='DECODE-ROWS' /var/lib/mysql/binlog.000010 | grep -C20 -i 'database'
#220325 6:19:27 server id 1 end_log_pos 157 CRC32 0x1ad148cc Previous-GTIDs
# [empty]
# at 157
#220325 6:20:07 server id 1 end_log_pos 234 CRC32 0xf6be5fed Anonymous_GTID last_committed=0 sequence_number=1 rbr_only=no original_committed_timestamp=1648189207588241 immediate_commit_timestamp=1648189207588241 transaction_length=185
# original_commit_timestamp=1648189207588241 (2022-03-25 06:20:07.588241 UTC)
# immediate_commit_timestamp=1648189207588241 (2022-03-25 06:20:07.588241 UTC)
/*!80001 SET @@session.original_commit_timestamp=1648189207588241*//*!*/;
/*!80014 SET @@session.original_server_version=80028*//*!*/;
/*!80014 SET @@session.immediate_server_version=80028*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 234
#220325 6:20:07 server id 1 end_log_pos 342 CRC32 0x4912f073 Query thread_id=8 exec_time=0 error_code=0 Xid = 799
SET TIMESTAMP=1648189207/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113696/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=255/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/;
/*!80016 SET @@session.default_table_encryption=0*//*!*/;
create database mydb
/*!*/;
# at 342
#220325 6:20:30 server id 1 end_log_pos 419 CRC32 0x7a998c77 Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=no original_committed_timestamp=1648189230558417 immediate_commit_timestamp=1648189230558417 transaction_length=187
# original_commit_timestamp=1648189230558417 (2022-03-25 06:20:30.558417 UTC)
# immediate_commit_timestamp=1648189230558417 (2022-03-25 06:20:30.558417 UTC)
/*!80001 SET @@session.original_commit_timestamp=1648189230558417*//*!*/;
/*!80014 SET @@session.original_server_version=80028*//*!*/;
/*!80014 SET @@session.immediate_server_version=80028*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 419
#220325 6:20:30 server id 1 end_log_pos 529 CRC32 0x55eda454 Query thread_id=8 exec_time=0 error_code=0 Xid = 804
use `mydb`/*!*/;
SET TIMESTAMP=1648189230/*!*/;
/*!80013 SET @@session.sql_require_primary_key=0*//*!*/;
create table t(id int)
/*!*/;
# at 529
#220325 6:20:51 server id 1 end_log_pos 608 CRC32 0x63127526 Anonymous_GTID last_committed=2 sequence_number=3 rbr_only=yes original_committed_timestamp=1648189251093346 immediate_commit_timestamp=1648189251093346 transaction_length=272
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
# original_commit_timestamp=1648189251093346 (2022-03-25 06:20:51.093346 UTC)
--
#220325 6:20:56 server id 1 end_log_pos 1274 CRC32 0x016cc72e Table_map: `mydb`.`t` mapped to number 99
# at 1274
#220325 6:20:56 server id 1 end_log_pos 1314 CRC32 0x4414727a Write_rows: table id 99 flags: STMT_END_F
### INSERT INTO `mydb`.`t`
### SET
### @1=3
# at 1314
#220325 6:20:56 server id 1 end_log_pos 1345 CRC32 0xcf486367 Xid = 807
COMMIT/*!*/;
# at 1345
#220325 6:21:25 server id 1 end_log_pos 1422 CRC32 0xc8959107 Anonymous_GTID last_committed=5 sequence_number=6 rbr_only=no original_committed_timestamp=1648189285121605 immediate_commit_timestamp=1648189285121605 transaction_length=181
# original_commit_timestamp=1648189285121605 (2022-03-25 06:21:25.121605 UTC)
# immediate_commit_timestamp=1648189285121605 (2022-03-25 06:21:25.121605 UTC)
/*!80001 SET @@session.original_commit_timestamp=1648189285121605*//*!*/;
/*!80014 SET @@session.original_server_version=80028*//*!*/;
/*!80014 SET @@session.immediate_server_version=80028*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 1422
#220325 6:21:25 server id 1 end_log_pos 1526 CRC32 0xae1a52a4 Query thread_id=8 exec_time=0 error_code=0 Xid = 809
SET TIMESTAMP=1648189285/*!*/;
drop database mydb
/*!*/;
# at 1526
#220325 6:22:11 server id 1 end_log_pos 1570 CRC32 0xc0539b89 Rotate to binlog.000011 pos: 4
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;