设置二进制日志格式
你可以通过在启动MySQL服务器时使用–binlog-format=type来明确选择二进制日志记录格式。type的支持值包括:
- STATEMENT表示基于语句的日志记录。
- ROW表示基于行的日志记录。这是默认设置。
- MIXED表示使用混合格式进行日志记录。
设置二进制日志记录格式不会激活服务器的二进制日志记录。只有在服务器上启用了二进制日志记录时,该设置才会生效,这是在log_bin系统变量设置为ON时的情况。从MySQL 8.0开始,默认情况下启用了二进制日志记录,只有在启动时指定–skip-log-bin或–disable-log-bin选项时才会禁用。
日志记录格式也可以在运行时切换,但请注意,在本节后面的讨论中有一些情况下无法这样做。通过设置binlog_format系统变量的全局值,可以为连接到更改后的客户端指定格式:
mysql> SET GLOBAL binlog_format = 'STATEMENT'; mysql> SET GLOBAL binlog_format = 'ROW'; mysql> SET GLOBAL binlog_format = 'MIXED';
单独的客户端可以通过设置binlog_format的会话值来控制其自己语句的日志记录格式:
mysql> SET SESSION binlog_format = 'STATEMENT'; mysql> SET SESSION binlog_format = 'ROW'; mysql> SET SESSION binlog_format = 'MIXED';
更改全局binlog_format值需要具有足够权限来设置全局系统变量。更改会话binlog_format值需要具有足够权限来设置受限会话系统变量。
客户端可能希望根据每个会话设置二进制日志记录的原因有几个:
- 对数据库进行许多小更改的会话可能希望使用基于行的日志记录。
- 执行的更新在WHERE子句中匹配多行的会话可能希望使用基于语句的日志记录,因为记录少量语句比记录多行更有效率。
- 某些语句在源上需要很长的执行时间,但只会修改很少的行。因此,使用基于行的日志记录来复制它们可能更有益。
有些情况下,您无法在运行时切换复制格式:
- 无法在存储函数或触发器内更改复制格式。
- 如果启用了NDB存储引擎。
- 如果会话中有打开的临时表,则无法为该会话更改复制格式(SET @@SESSION.binlog_format)。
- 如果任何复制通道有打开的临时表,则无法全局更改复制格式(SET @@GLOBAL.binlog_format或SET @@PERSIST.binlog_format)。
- 如果任何复制通道的应用程序线程正在运行,则无法全局更改复制格式(SET @@GLOBAL.binlog_format或SET @@PERSIST.binlog_format)。
在任何这些情况下尝试切换复制格式(或尝试设置当前复制格式)将导致错误。但是,您可以随时使用PERSIST_ONLY(SET @@PERSIST_ONLY.binlog_format)来更改复制格式,因为此操作不会修改运行时全局系统变量的值,并且仅在服务器重新启动后生效。
当存在临时表时,不建议在运行时切换复制格式,因为只有在使用基于语句的复制时才会记录临时表,而使用基于行的复制和混合复制时不会记录。
在复制正在进行时切换复制格式也可能导致问题。每个MySQL服务器可以设置自己的二进制日志记录格式(无论binlog_format是使用全局还是会话范围设置)。这意味着在复制源服务器上更改日志格式不会导致副本更改其日志格式以进行匹配。在使用STATEMENT模式时,binlog_format系统变量不会被复制。在使用MIXED或ROW日志记录模式时,它会被复制,但副本会忽略它。
副本无法将以ROW日志记录格式接收的二进制日志条目转换为STATEMENT格式,以供其自己的二进制日志使用。因此,如果源使用ROW或MIXED格式,则副本必须使用ROW或MIXED格式。在复制正在进行时,将源上的二进制日志记录格式从STATEMENT更改为ROW或MIXED,以适应具有STATEMENT格式的副本,可能会导致复制失败,并出现错误,如“执行行事件时出错:无法执行语句:由于语句处于行格式且BINLOG_FORMAT = STATEMENT,无法写入二进制日志。” 当源仍在使用MIXED或ROW格式时,将副本的二进制日志记录格式更改为STATEMENT格式也会导致相同类型的复制失败。要安全地更改格式,您必须停止复制,并确保在源和副本上进行相同的更改。
如果您使用的是InnoDB表,并且事务隔离级别为READ COMMITTED或READ UNCOMMITTED,则只能使用基于行的日志记录。可以将日志记录格式更改为STATEMENT,但在运行时这样做会非常快速地导致错误,因为InnoDB无法再执行插入操作。
将二进制日志格式设置为ROW时,许多更改都使用基于行的格式编写到二进制日志中。但是,仍然有一些更改使用基于语句的格式。例如,包括所有DDL(数据定义语言)语句,如CREATE TABLE、ALTER TABLE或DROP TABLE。
当使用基于行的二进制日志记录时,binlog_row_event_max_size系统变量及其对应的启动选项–binlog-row-event-max-size对行事件的最大大小设置了软限制。默认值为8192字节,该值只能在服务器启动时更改。在可能的情况下,存储在二进制日志中的行被分组为不超过此设置值的事件。如果无法分割事件,则最大大小可能会超过此值。
–binlog-row-event-max-size选项适用于能够进行基于行复制的服务器。行按块存储到二进制日志中,每个块的大小(以字节为单位)不超过此选项的值。该值必须是256的倍数。默认值为8192。
警告
在使用基于语句的日志记录进行复制时,如果某个语句设计得使数据修改是不确定的(即由查询优化器决定),则源和副本上的数据可能会变得不同。通常情况下,即使在复制之外,这也不是一个好的做法。