Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  Point-in-Time Recovery Using Event Positions

9.5.2 使用事件位置进行时间点恢复

上一节第9.5.1节,“使用二进制日志进行时间点恢复”解释了使用二进制日志来实现时间点恢复。该节详细解释了操作的过程,包括了一个示例。

例如,假设2020年3月11日20:06:00执行了一条SQL语句,该语句删除了一张表。你可以使用时间点恢复来恢复服务器到删除表之前的状态。以下是一些示例步骤来实现该目标:

  1. 恢复在感兴趣的时间点之前创建的最后一个完整备份(在我们的示例中是2020年3月11日20:06:00)。当完成后,注意服务器恢复到的最后一个二进制日志位置,以便在后续使用,并重新启动服务器。

    Note

    在恢复和服务器重新启动后,InnoDB将显示最后一个二进制日志位置,但是这不是恢复的可靠方法,因为可能存在DDL事件和非InnoDB更改事件。您的备份和恢复工具应该提供您恢复的最后一个二进制日志位置:例如,如果您使用mysqlbinlog工具来完成任务,请检查二进制日志回放的停止位置;如果您使用MySQL Enterprise Backup,最后一个二进制日志位置已经保存在备份中。请参阅时间点恢复

  2. 找到与您想要恢复到时间点对应的精确二进制日志事件位置。在我们的示例中,我们知道了表删除的时间点(tp),我们可以使用mysqlbinlog工具来找到该时间点附近的日志内容。使用--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`语句在二进制日志中的位置,该语句在日志段# at 232# at 355之间,这意味着该语句在日志位置232后执行,并且日志在位置355执行DROP TABLE语句。

    Note

    只使用--start-datetime--stop-datetime选项来帮助您找到实际事件的位置。使用这两个选项指定要应用的二进制日志段范围不是推荐的:使用这两个选项存在更高的风险,可能会错过二进制日志事件。相反,使用--start-position--stop-position

  3. 将二进制日志文件中的事件应用于服务器,自从步骤1中找到的日志位置(假设为155)开始,并到步骤2中找到的点在时间点之前(假设为232):

    $> mysqlbinlog --start-position=155 --stop-position=232 /var/lib/mysql/bin.123456 \
             | mysql -u root -p

    命令恢复了从开始位置到停止位置之间的所有事务。由于mysqlbinlog的输出包括了SET TIMESTAMP语句,恢复的数据和相关MySQL日志反映了事务执行的原始时间。

    您的数据库现在已经恢复到感兴趣的时间点tp,在pets.cats表之前被删除。

  4. 在恢复完成后,如果您还想重新执行所有在时间点tp之后的语句,请再次使用mysqlbinlog将所有在tp之后的事件应用于服务器。我们在步骤2中注意到,在语句后,我们想要跳过的语句的日志位置为355;我们可以使用它作为--start-position选项,以便包括在该位置之后的所有语句:

    $> mysqlbinlog --start-position=355 /var/lib/mysql/bin.123456 \
             | mysql -u root -p

    您的数据库现在已经恢复到二进制日志文件中的最新语句,但是跳过了选择的事件。