#### 17.2.1.1基于报表和基于行的优点和缺点

复制

[](<>)[](<>)

每种二进制日志记录格式各有优缺点。对于大多数用户来说，混合复制格式应该提供数据完整性和性能的最佳组合。但是，如果您想在执行某些任务时利用基于语句或基于行的复制格式特有的功能，可以使用本节中的信息来确定哪种格式最适合您的需要，本节概述了它们的相对优缺点。

-   [基于语句的复制的优势](replication-sbr-rbr.html#replication-sbr-rbr-sbr-advantages)

-   [基于语句的复制的缺点](replication-sbr-rbr.html#replication-sbr-rbr-sbr-disadvantages)

-   [基于行的复制的优势](replication-sbr-rbr.html#replication-sbr-rbr-rbr-advantages)

-   [基于行的复制的缺点](replication-sbr-rbr.html#replication-sbr-rbr-rbr-disadvantages)

##### 基于语句的复制的优势

[](<>)

-   成熟的技术。

-   写入日志文件的数据更少。当更新或删除影响多行时，会导致*很*日志文件所需的存储空间更少。这也意味着可以更快地从备份中获取和恢复数据。

-   日志文件包含进行任何更改的所有语句，因此可以使用它们来审核数据库。

##### 基于语句的复制的缺点

[](<>)

-   **对SBR不安全的声明。** [](<>)[](<>)并非所有修改数据的语句（例如[`插入`](insert.html) [`删去`](delete.html),[`使现代化`](update.html)和[`代替`](replace.html)语句）可以使用基于语句的复制进行复制。在使用基于语句的复制时，任何不确定的行为都很难复制。此类数据修改语言（DML）语句的示例包括：

    -   一种依赖于可加载函数或存储程序的语句，它是不确定的，因为此类函数或存储程序返回的值或取决于提供给它的参数以外的因素。（然而，基于行的复制只是复制函数或存储程序返回的值，因此它对表行和数据的影响在源和副本上都是相同的。）看见[第17.5.1.16节，“调用功能的复制”](replication-features-invoked.html)，以获取更多信息。

    -   [`删去`](delete.html)和[`使现代化`](update.html)使用`限度`不带空格的子句`订购人`是不确定的。看见[第17.5.1.18节“复制和限制”](replication-features-limit.html).

    -   锁定读取语句([`选择更新`](select.html)和[`选择分享`](select.html))那个用途`诺瓦特`或`跳转锁定`选项。看见[使用NOWAIT和SKIP LOCKED锁定读取并发](innodb-locking-reads.html#innodb-locking-reads-nowait-skip-locked).

    -   必须在副本上应用确定性可加载函数。

    -   使用基于语句的复制无法正确复制使用以下任何函数的语句：

        -   [`加载_文件（）`](string-functions.html#function_load-file)

        -   [`UUID（）`](miscellaneous-functions.html#function_uuid), [`UUID_SHORT（）`](miscellaneous-functions.html#function_uuid-short)

        -   [`用户（）`](information-functions.html#function_user)

        -   [`找到_行（）`](information-functions.html#function_found-rows)

        -   [`SYSDATE（）`](date-and-time-functions.html#function_sysdate)（除非源和复制副本都以[`--sysdate现在是`](server-options.html#option_mysqld_sysdate-is-now)（可选）

        -   [`得到锁`](locking-functions.html#function_get-lock)

        -   [`是免费的吗`](locking-functions.html#function_is-free-lock)

        -   [`是否使用了锁`](locking-functions.html#function_is-used-lock)

        -   [`大师，等等`](miscellaneous-functions.html#function_master-pos-wait)

        -   [`兰德（）`](mathematical-functions.html#function_rand)

        -   [`释放锁（）`](locking-functions.html#function_release-lock)

        -   [`SOURCE_POS_WAIT（）`](miscellaneous-functions.html#function_source-pos-wait)

        -   [`睡眠（）`](miscellaneous-functions.html#function_sleep)

        -   [`版本（）`](information-functions.html#function_version)

            但是，使用基于语句的复制可以正确复制所有其他函数，包括[`现在（）`](date-and-time-functions.html#function_now)等等

            有关更多信息，请参阅[第17.5.1.14节，“复制和系统功能”](replication-features-functions.html).

        使用基于语句的复制无法正确复制的语句会被记录为警告，如下所示：

    ```
    [Warning] Statement is not safe to log in statement format.
    ```

    在这种情况下，也会向客户发出类似警告。客户端可以使用[`显示警告`](show-warnings.html).

-   [`插入选择`](insert.html)与基于行的复制相比，需要更多的行级锁。

-   [`使现代化`](update.html)需要表扫描的语句（因为在`哪里`子句）必须锁定比基于行的复制更多的行。

-   对于[`InnoDB`](innodb-storage-engine.html)：安[`插入`](insert.html)使用`自动增量`阻止其他非冲突[`插入`](insert.html)声明。

-   对于复杂语句，在更新或插入行之前，必须在副本上计算并执行该语句。对于基于行的复制，复制副本只需修改受影响的行，而不必执行完整语句。

-   如果在对复制副本进行求值时出现错误，尤其是在执行复杂语句时，则基于语句的复制可能会随着时间的推移慢慢增加受影响行的误差幅度。看见[第17.5.1.29节，“复制期间的副本错误”](replication-features-slaveerrors.html).

-   存储函数以相同的方式执行[`现在（）`](date-and-time-functions.html#function_now)值作为调用语句。然而，存储过程并非如此。

-   必须在副本上应用确定性可加载函数。

-   源和副本上的表定义必须（几乎）相同。看见[第17.5.1.9节，“源和副本上具有不同表定义的复制”](replication-features-differing-tables.html)，以获取更多信息。

-   从MySQL 8.0.22开始，从MySQL grant表（通过联接列表或子查询）读取数据但不修改数据的DML操作在MySQL grant表上作为非锁定读取执行，因此对于基于语句的复制不安全。有关更多信息，请参阅[授权表并发](grant-tables.html#grant-tables-concurrency).

##### 基于行的复制的优势

[](<>)

-   所有更改都可以复制。这是最安全的复制形式。

    笔记

    更新中信息的语句`mysql`系统架构，例如[`授予`](grant.html), [`撤销`](revoke.html)触发器、存储例程（包括存储过程）和视图的操作都使用基于语句的复制复制到副本中。

    例如[`创建表格。。。选择`](create-table.html)A.`创造`语句从表定义生成，并使用基于语句的格式复制，而行插入则使用基于行的格式复制。

-   对于以下类型的语句，源上需要更少的行锁，从而实现更高的并发性：

    -   [`插入选择`](insert-select.html)

    -   [`插入`](insert.html)声明与`自动增量`

    -   [`使现代化`](update.html)或[`删去`](delete.html)声明与`哪里`不使用键或不更改大多数检查行的子句。

-   对于任何类型的复制副本，都需要更少的行锁[`插入`](insert.html), [`使现代化`](update.html)或[`删去`](delete.html)陈述

##### 基于行的复制的缺点

[](<>)

-   RBR可以生成更多必须记录的数据。复制DML语句（例如[`使现代化`](update.html)或[`删去`](delete.html)语句），基于语句的复制只将语句写入二进制日志。相比之下，基于行的复制将每个更改的行写入二进制日志。如果语句更改了许多行，基于行的复制可能会向二进制日志写入更多数据；即使是回滚的语句也是如此。这也意味着备份和恢复可能需要更多时间。此外，二进制日志在写入数据时会被锁定更长的时间，这可能会导致并发问题。使用[`binlog_row_image=最小值`](replication-options-binary-log.html#sysvar_binlog_row_image)大大减少不利因素。

-   确定性可加载函数，生成大型[`斑点`](blob.html)使用基于行的复制比使用基于语句的复制需要更长的时间来复制值。这是因为[`斑点`](blob.html)记录列值，而不是生成数据的语句。

-   您无法在副本上看到从源接收并执行了哪些语句。但是，您可以看到使用[**mysqlbinlog**](mysqlbinlog.html)有选择吗[`--base64输出=解码行`](mysqlbinlog.html#option_mysqlbinlog_base64-output)和[`--冗长的`](mysqlbinlog.html#option_mysqlbinlog_verbose).

    或者，使用[`binlog\u行\u查询\u日志\u事件`](replication-options-binary-log.html#sysvar_binlog_rows_query_log_events)变量，如果启用该变量，将添加`行\u查询`事件，并声明[**mysqlbinlog**](mysqlbinlog.html)当`-vv`选项被使用。

-   对于使用[`米萨姆`](myisam-storage-engine.html)存储引擎，复制副本上需要更强大的锁[`插入`](insert.html)将它们作为基于行的事件应用于二进制日志时的语句，而不是将它们作为语句应用时的语句。这意味着[`米萨姆`](myisam-storage-engine.html)使用基于行的复制时不支持表。
