最后一节, 第 7.5.1 节,“使用二进制日志进行时间点恢复”,解释了使用二进制日志执行时间点恢复的一般思路。本节通过示例详细说明操作。
举个例子,假设2020年3月11日20:06:00左右,执行了一条删除表的SQL语句。您可以执行时间点恢复以将服务器恢复到表删除之前的状态。这些是实现该目标的一些示例步骤:
恢复在感兴趣的时间点之前创建的最后一个完整备份( 在我们的示例中称之为 2020 年 3 月 11 日 20:06:00)。完成后,记下您已将服务器恢复到的二进制日志位置以备后用,然后重新启动服务器。
tp
笔记虽然在恢复和服务器重启后 InnoDB 也会显示恢复的最后一个二进制日志位置,但这不是获取恢复结束日志位置的可靠方法,因为可能发生了 DDL 事件和非 InnoDB 更改在显示位置反映的时间之后。您的备份和还原工具应该为您提供最后一个二进制日志位置以供您恢复:例如,如果您使用的是mysqlbinlog 对于任务,检查二进制日志重放的停止位置;如果您使用的是 MySQL Enterprise Backup,则最后一个二进制日志位置已保存在您的备份中。请参阅 时间点恢复。
找到与要将数据库还原到的时间点对应的精确二进制日志事件位置。在我们的示例中,假设我们知道表删除发生的大致时间 ( ),我们可以通过使用mysqlbinlog实用程序检查该时间附近的日志内容来找到日志位置。使用和 选项指定围绕 的短时间段 ,然后在输出中查找事件。例如:
tp
--start-datetime
--stop-datetime
tp
$> mysqlbinlog --start-datetime="2020-03-11 20:05:00" \ --stop-datetime="2020-03-11 20:08:00" --verbose \ /var/lib/mysql/bin.123456 | grep -C 15 "DROP TABLE" /*!80014 SET @@session.original_server_version=80019*//*!*/; /*!80014 SET @@session.immediate_server_version=80019*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 232 #200311 20:06:20 server id 1 end_log_pos 355 CRC32 0x2fc1e5ea Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1583971580/*!*/; SET @@session.pseudo_thread_id=16/*!*/; 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 utf8mb4 *//*!*/; SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; /*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/; DROP TABLE `pets`.`cats` /* generated by server */ /*!*/; # at 355 #200311 20:07:48 server id 1 end_log_pos 434 CRC32 0x123d65df Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=no original_committed_timestamp=1583971668462467 immediate_commit_timestamp=1583971668462467 transaction_length=473 # original_commit_timestamp=1583971668462467 (2020-03-11 20:07:48.462467 EDT) # immediate_commit_timestamp=1583971668462467 (2020-03-11 20:07:48.462467 EDT) /*!80001 SET @@session.original_commit_timestamp=1583971668462467*//*!*/; /*!80014 SET @@session.original_server_version=80019*//*!*/; /*!80014 SET @@session.immediate_server_version=80019*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 434 #200311 20:07:48 server id 1 end_log_pos 828 CRC32 0x57fac9ac Query thread_id=16 exec_time=0 error_code=0 Xid = 217 use `pets`/*!*/; SET TIMESTAMP=1583971668/*!*/; /*!80013 SET @@session.sql_require_primary_key=0*//*!*/; CREATE TABLE dogs
从mysqlbinlog的输出中,可以在 和 行之间的二进制日志段中找到该 语句
DROP TABLE `pets`.`cats`
, 这意味着该语句发生 在日志位置 232 之后,而日志位于该语句之后的位置 355 。# at 232
# at 355
DROP TABLE
笔记仅使用
--start-datetime
和--stop-datetime
选项来帮助您找到感兴趣的实际事件位置。不建议使用这两个选项来指定要应用的二进制日志段的范围:使用这些选项时丢失二进制日志事件的风险更高。使用--start-position
and--stop-position
代替。将二进制日志文件中的事件应用到服务器,从您在第 1 步中找到的日志位置(假设它是 155)开始,到您在第 2 步中找到的您感兴趣的时间点之前的位置结束(这是232):
$> mysqlbinlog --start-position=155 --stop-position=232 /var/lib/mysql/bin.123456 \ | mysql -u root -p
该命令恢复从起始位置到停止位置之前的所有事务。因为mysqlbinlog的输出包含
SET TIMESTAMP
了每条记录的SQL语句之前的语句,所以恢复的数据和相关的MySQL日志反映了事务执行的原始时间。您的数据库现在已恢复到感兴趣的时间点,就在表被删除之前。
tp
pets.cats
除了已经完成的时间点恢复之外,如果您还想重新执行 您感兴趣的时间点之后的所有语句,请再次使用mysqlbinlog将之后的所有事件应用到服务器。我们在第 2 步中注意到,在我们要跳过的语句之后,日志位于位置 355;我们可以将它用于 选项,以便包含位置之后的任何语句:
tp
--start-position
$> mysqlbinlog --start-position=355 /var/lib/mysql/bin.123456 \ | mysql -u root -p
您的数据库已恢复二进制日志文件中记录的最新语句,但已跳过所选事件。