16.2.1.3 确定二进制日志中的安全和不安全语句

MySQL 复制中语句的“安全性”是指是否可以使用基于语句的格式正确复制该语句及其影响。如果该声明是正确的,则我们将该声明称为“安全”。否则,我们将其称为不安全。

通常,如果语句是确定性的,则它是安全的;否则,则是不安全的。但是,某些不确定的函数不被认为是不安全的(请参阅非确定性功能不被认为是不安全的,本节后面的内容)。此外,使用浮点 math 函数的结果(取决于硬件)的语句始终被认为是不安全的(请参阅第 16.4.1.12 节,“复制和浮点值”)。

处理安全和不安全的语句. 根据语句是否被认为安全以及相对于二进制日志记录格式(即binlog_format的当前值)的不同,对语句的处理方式不同。

  • 使用基于行的日志记录时,对安全和不安全语句的处理没有区别。

  • 使用混合格式日志记录时,标记为不安全的语句将使用基于行的格式记录;使用基于语句的格式记录被视为安全的语句。

  • 使用基于语句的日志记录时,标记为不安全的语句会产生警告。安全语句正常记录。

每个标记为不安全的语句都会生成警告。以前,如果在源上执行了大量此类语句,则可能导致错误日志文件过大。为了防止这种情况,MySQL 5.7 提供了一种警告抑制机制,其行为如下:每当在任何 50 秒钟的时间内生成 50 次最近的ER_BINLOG_UNSAFE_STATEMENT警告超过 50 次时,就会启用警告抑制。激活后,这将导致这样的警告不被写入错误日志;而是,对于这种类型的每 50 条警告,都会在错误日志中写入 CommentsThe last warning was repeated N times in last S seconds。只要在 50 秒或更短的时间内发出了最近的 50 条警告,这种情况就会持续下去;一旦速率降低到此阈值以下,警告将再次正常记录。警告抑制不影响如何确定基于语句的日志记录的语句安全性,也不影响如何将警告发送给 Client 端。 MySQLClient 端仍然为每个这样的语句收到一个警告。

有关更多信息,请参见第 16.2.1 节“复制格式”

Statements 被认为是不安全的. 具有以下 Feature 的 Statements 被认为是不安全的:

确定性功能不被认为是不安全的. 尽管这些功能不是确定性的,但出于记录和复制的目的,它们被视为安全的:CONNECTION_ID()CURDATE()CURRENT_DATE()CURRENT_TIME()CURRENT_TIMESTAMP()CURTIME()LAST_INSERT_ID()LOCALTIME()LOCALTIMESTAMP()NOW()UNIX_TIMESTAMP()UTC_DATE()UTC_TIME()UTC_TIMESTAMP()

有关更多信息,请参见第 16.4.1.15 节,“复制和系统功能”

  • 参考系统变量. 大多数系统变量未使用基于语句的格式正确复制。参见第 16.4.1.37 节,“复制和变量”。有关 exceptions,请参见第 5.4.4.3 节“混合二进制日志记录格式”

  • UDF. 由于我们无法控制 UDF 的工作,因此我们必须假定它正在执行不安全的语句。

  • 全文插件. 此插件在不同的 MySQL 服务器上的行为可能有所不同;因此,取决于它的语句可能会有不同的结果。因此,所有依赖全文插件的语句都被视为不安全(错误#11756280,错误#48183)。

  • 触发器或存储的程序会更新具有 AUTO_INCREMENT 列的 table. 这是不安全的,因为行的更新 Sequences 在源和副本上可能会有所不同。

此外,table 中的INSERT具有一个复合主键,该主键包含一个AUTO_INCREMENT列,该列不是此复合键的第一列,这是不安全的。

有关更多信息,请参见第 16.4.1.1 节“复制和 AUTO_INCREMENT”

  • 在具有多个主键或唯一键的 table 上执行 INSERT ... ON DUPLICATE KEY UPDATE 语句. 对包含多个主键或唯一键的 table 执行时,此语句被认为是不安全的,对 Sequences 的敏感度很高存储引擎检查密钥(不确定),以及由 MySQL Server 更新的行的选择取决于密钥。

对于具有多个唯一或主键的 table 的插入...在重复的密钥更新上语句对于基于语句的复制被标记为不安全。 (缺陷#11765650,错误#58637)

  • 使用 LIMIT 更新. 未指定行的检索 Sequences,因此被认为是不安全的。参见第 16.4.1.17 节,“复制和限制”

  • 访问或引用日志 table. 源和副本之间系统日志 table 的内容可能有所不同。

  • 事务性操作之后的非事务性操作. 在事务内,允许任何非事务性读取或写入在任何事务性读取或写入之后执行是不安全的。

有关更多信息,请参见第 16.4.1.33 节,“复制和事务”

  • 访问或引用自记录 table. 对自记录 table 的所有读取和写入均被视为不安全。在事务中,对自记录 table 进行读取或写入之后的任何语句也被认为是不安全的。

  • LOAD DATA 语句. LOAD DATA被视为不安全,并且当binlog_format=mixed时,该语句以基于行的格式记录。 binlog_format=statement LOAD DATA不生成警告时,不同于其他不安全的语句。

  • XA 事务. 如果正在反向上在副本上准备在源上并行提交的两个 XA 事务,则无法安全解决的基于语句的复制可能会发生锁定依赖关系,并且有可能复制到由于副本上的死锁而失败。设置binlog_format=STATEMENT时,XA 事务中的 DML 语句被标记为不安全并生成警告。设置binlog_format=MIXEDbinlog_format=ROW时,将使用基于行的复制来记录 XA 事务中的 DML 语句,并且不存在潜在的问题。

有关更多信息,请参见第 16.4.1 节“复制功能和问题”