#### 17.2.1.2 使用基于行的日志记录和复制

MySQL 使用基于语句的日志记录 (SBL)、基于行的日志记录 (RBL) 或混合格式日志记录。使用的二进制日志类型会影响日志记录的大小和效率。因此，基于行的复制 (RBR) 或基于语句的复制 (SBR) 之间的选择取决于您的应用程序和环境。本节介绍使用基于行的格式日志时的已知问题，并介绍在复制中使用它的一些最佳实践。

有关其他信息，请参阅[第 17.2.1 节，“复制格式”](replication-formats.html)， 和[第 17.2.1.1 节，“基于语句和基于行的复制的优缺点”](replication-sbr-rbr.html).

有关特定于 NDB Cluster 复制（取决于基于行的复制）的问题的信息，请参阅[第 23.7.3 节，“NDB 集群复制中的已知问题”](mysql-cluster-replication-issues.html).

-   [](<>)**临时表的基于行的日志记录。**如中所述[第 17.5.1.31 节，“复制和临时表”](replication-features-temptables.html)，当使用基于行的格式或（来自 MySQL 8.0.4）混合格式时，不会复制临时表。有关详细信息，请参阅[第 17.2.1.1 节，“基于语句和基于行的复制的优缺点”](replication-sbr-rbr.html).

    使用基于行或混合格式时不会复制临时表，因为没有必要。此外，由于临时表只能从创建它们的线程中读取，因此即使使用基于语句的格式，复制它们也几乎没有任何好处。

    即使已创建临时表，您也可以在运行时从基于语句的二进制日志格式切换到基于行的二进制日志格式。但是，在 MySQL 8.0 中，您不能在运行时从基于行或混合格式的二进制日志切换到基于语句的格式，因为任何`创建临时表`在以前的模式中，二进制日志中已经省略了语句。

    MySQL 服务器跟踪创建每个临时表时有效的日志记录模式。当给定的客户端会话结束时，服务器记录一个`如果存在则删除临时表`仍然存在并在使用基于语句的二进制日志记录时创建的每个临时表的语句。如果在创建表时正在使用基于行或混合格式的二进制日志记录，则`如果存在则删除临时表`语句未记录。在 MySQL 8.0.4 和 5.7.25 之前的版本中，`如果存在则删除临时表`无论有效的日志记录模式如何，都会记录语句。

    使用时允许涉及临时表的非事务性 DML 语句[`binlog_format=行`](replication-options-binary-log.html#sysvar_binlog_format)，只要受语句影响的任何非事务性表都是临时表（错误 #14272672）。

-   **RBL 和非事务表的同步。**当许多行受到影响时，更改集被拆分为几个事件；当语句提交时，所有这些事件都会写入二进制日志。在副本上执行时，对所有涉及的表进行表锁定，然后以批处理模式应用行。根据用于表副本的引擎，这可能有效，也可能无效。

-   **延迟和二进制日志大小。**RBL 将每一行的更改写入二进制日志，因此其大小可以迅速增加。这会显着增加在副本上进行更改以匹配源上的更改所需的时间。您应该意识到您的应用程序可能会出现这种延迟。

-   **读取二进制日志。**  [**mysqlbinlog**](mysqlbinlog.html)使用在二进制日志中显示基于行的事件`二进制日志`声明（见[第 13.7.8.1 节，“BINLOG 语句”](binlog.html)）。此语句将事件显示为 base 64 编码字符串，其含义不明显。当调用[`--base64-输出=解码-行`](mysqlbinlog.html#option_mysqlbinlog_base64-output)和[`--详细`](mysqlbinlog.html#option_mysqlbinlog_verbose)选项，[**mysqlbinlog**](mysqlbinlog.html)将二进制日志的内容格式化为人类可读的。当二进制日志事件以基于行的格式写入并且您想要读取或从复制或数据库故障中恢复时，您可以使用此命令来读取二进制日志的内容。有关详细信息，请参阅[第 4.6.9.2 节，“mysqlbinlog 行事件显示”](mysqlbinlog-row-events.html).

-   **二进制日志执行错误和副本执行模式。**使用[`slave_exec_mode=IDEMPOTENT`](replication-options-replica.html#sysvar_slave_exec_mode)通常只对 MySQL NDB Cluster 复制有用，对于`幂等`是默认值。（看[第 23.7.10 节，“NDB 集群复制：双向和循环复制”](mysql-cluster-replication-multi-source.html)）。当系统变量[`副本执行模式`](replication-options-replica.html#sysvar_replica_exec_mode)要么[`slave_exec_mode`](replication-options-replica.html#sysvar_slave_exec_mode)是`幂等`，由于无法找到原始行而无法从 RBL 应用更改不会触发错误或导致复制失败。这意味着有可能没有在副本上应用更新，因此源和副本不再同步。延迟问题和使用 RBR 时使用非事务性表[`副本执行模式`](replication-options-replica.html#sysvar_replica_exec_mode)要么[`slave_exec_mode`](replication-options-replica.html#sysvar_slave_exec_mode)是`幂等`可能导致源和副本进一步分歧。有关更多信息[`副本执行模式`](replication-options-replica.html#sysvar_replica_exec_mode)和[`slave_exec_mode`](replication-options-replica.html#sysvar_slave_exec_mode)， 看[第 5.1.8 节，“服务器系统变量”](server-system-variables.html).

    对于其他场景，设置[`副本执行模式`](replication-options-replica.html#sysvar_replica_exec_mode)要么[`slave_exec_mode`](replication-options-replica.html#sysvar_slave_exec_mode)到`严格的`通常就足够了；这是存储引擎的默认值，而不是[`新开发银行`](mysql-cluster.html).

-   **不支持基于服务器 ID 的过滤。**您可以使用基于服务器 ID 的过滤器`IGNORE_SERVER_IDS`选项[`将复制源更改为`](change-replication-source-to.html)语句（来自 MySQL 8.0.23）或[`将主更改为`](change-master-to.html)语句（在 MySQL 8.0.23 之前）。此选项适用于基于语句和基于行的日志记录格式，但在以下情况下不推荐使用[`GTID_MODE=ON`](replication-options-gtids.html#sysvar_gtid_mode)已设置。过滤掉某些副本上的更改的另一种方法是使用`在哪里`包含关系的子句`@@server_id <> *`id_value`*`子句[`更新`](update.html)和[`删除`](delete.html)陈述。例如，`在哪里@@server_id <> 1`.但是，这不适用于基于行的日志记录。要使用[`server_id`](replication-options.html#sysvar_server_id)用于语句过滤的系统变量，使用基于语句的日志记录。

-   **RBL、非事务性表和已停止的副本。**使用基于行的日志记录时，如果副本服务器在副本线程更新非事务表时停止，则副本数据库可能会达到不一致的状态。因此，建议您使用事务性存储引擎，例如[`InnoDB`](innodb-storage-engine.html)对于使用基于行的格式复制的所有表。用于[`停止复制`](stop-replica.html)要么[`停止复制 SQL_THREAD`](stop-replica.html)（或在 MySQL 8.0.22 之前，使用 SLAVE 而不是 REPLICA）在关闭副本 MySQL 服务器之前有助于防止问题发生，并且无论您使用何种日志记录格式或存储引擎，始终建议使用。
