Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Replication with Differing Table Definitions on Source and Replica

19.5.1.9 源和副本表定义不同的复制

源和目标表不需要是相同的。源表可以有更多或更少的列于副本表。此外,源和副本表的对应列可以使用不同的数据类型,subject to certain conditions。

Note

不支持在不同的分区表之间进行复制。请参阅 第 19.5.1.24 节,“复制和分区”

在所有情况下,源和目标表的定义不同,数据库和表名必须在源和副本上相同。附加条件将在以下两个部分中讨论,带有示例。

19.5.1.9.1 源或副本上具有更多列的复制

您可以从源复制表到副本,使源和副本表具有不同的列数,subject to the following conditions:

  • 共同的列必须在源和副本上以相同的顺序定义。(这甚至适用于两表具有相同的列数。)

  • 共同的列必须在任何附加列之前定义。

    这意味着,在副本上执行 ALTER TABLE 语句,其中新列被插入到表中的共同列范围内,会导致复制失败,如下面的示例所示:

    假设表 t 在源和副本上存在,定义如下 CREATE TABLE 语句:

    CREATE TABLE t (
        c1 INT,
        c2 INT,
        c3 INT
    );

    假设在副本上执行以下 ALTER TABLE 语句:

    ALTER TABLE t ADD COLUMN cnew1 INT AFTER c3;

    前面的 ALTER TABLE 在副本上是允许的,因为共同的列 c1c2c3 在表 t 的两个版本中保持在一起,在任何不同的列之前。

    然而,以下 ALTER TABLE 语句不能在副本上执行,而不会导致复制中断:

    ALTER TABLE t ADD COLUMN cnew2 INT AFTER c2;

    在副本上执行 ALTER TABLE 语句后,复制将失败,因为新列 cnew2 在表 t 的两个版本中的共同列之间。

  • 每个“额外”的列在具有更多列的表版本中必须具有默认值。

    列的默认值是由多个因素确定的,包括其类型、是否定义了 DEFAULT 选项、是否声明为 NULL,以及服务器 SQL 模式在创建时的效果;更多信息,请参阅 第 13.6 节,“数据类型默认值”

此外,当副本的表具有更多列时,每个共同的列必须在两个表中使用相同的数据类型。

示例  以下示例说明了一些有效和无效的表定义:

源上具有更多列  以下表定义是有效的并正确复制:

source> CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT);

以下表定义将引发错误,因为共同的列在副本上的定义顺序不同于源上:

source> CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
replica>  CREATE TABLE t1 (c2 INT, c1 INT);

以下表定义也将引发错误,因为源上的额外列定义出现在共同的列之前:

source> CREATE TABLE t1 (c3 INT, c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT);

副本上具有更多列  以下表定义是有效的并正确复制:

source> CREATE TABLE t1 (c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);

以下定义将引发错误,因为共同的列在源和副本上没有以相同的顺序定义:

source> CREATE TABLE t1 (c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c2 INT, c1 INT, c3 INT);

以下表定义也会引发错误,因为副本表中的额外列定义出现在公共列定义之前:

source> CREATE TABLE t1 (c1 INT, c2 INT);
replica>  CREATE TABLE t1 (c3 INT, c1 INT, c2 INT);

以下表定义失败,因为副本表中的额外列与源表中的公共列使用不同的数据类型,例如c2列:

source> CREATE TABLE t1 (c1 INT, c2 BIGINT);
replica>  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT);
19.5.1.9.2 具有不同数据类型的列的复制

理想情况下,源表和副本表中的对应列应该具有相同的数据类型。但是,这并不是严格执行的,只要满足一定的条件。

通常可以从一个给定的数据类型的列复制到同类型和同大小或更大的列。例如,可以从CHAR(10)列复制到另一个CHAR(10)列,或者从CHAR(10)列复制到CHAR(25)列。 在某些情况下,也可以从源表中的一个数据类型的列复制到副本表中的不同数据类型的列;当源表中的列类型被提升到副本表中的同类型或更大类型时,这称为属性提升

属性提升可以与基于语句的复制和基于行的复制一起使用,并且不依赖于源表或副本表使用的存储引擎。然而,日志格式的选择会影响允许的类型转换;这些细节将在本节后面讨论。

Important

无论您使用基于语句的复制还是基于行的复制,如果您想使用属性提升,副本表中的列数不能多于源表中的列数。

基于语句的复制  使用基于语句的复制时,一个简单的规则是,如果在源表上执行的语句也可以在副本表上成功执行,那么它也应该能够成功复制。换言之,如果语句使用的值与副本表中的某个列的类型兼容,那么语句可以被复制。例如,可以将任何适合TINYINT列的值插入到BIGINT列中;因此,即使您将副本表中的TINYINT列类型更改为BIGINT,源表上的任何插入语句也应该能够成功复制到副本表上,因为它不可能有一个合法的TINYINT值太大以至于超过BIGINT列。

基于行的复制:属性提升和降级  基于行的复制支持小型数据类型到大型数据类型的属性提升和降级。还可以指定是否允许损失(截断)或非损失的降级列值转换,如本节后面所述。

损失和非损失转换  如果目标类型无法表示要插入的值,必须决定如何处理转换。如果我们允许转换但截断(或以其他方式修改)源值以适应目标列,我们执行了一个损失转换。不需要截断或修改源值以适应目标列的转换是一个非损失转换。

类型转换模式  系统变量replica_type_conversions的全局值控制了副本上的类型转换模式。该变量采用以下列表中的值,描述了每种模式对副本类型转换行为的影响:

ALL_LOSSY

在这种模式下,允许损失信息的类型转换。

这并不意味着非损失转换是允许的,只是说只有需要损失转换或不需要转换的情况下才被允许;例如,在这种模式下,允许将INT列转换为TINYINT列(损失转换),但不允许将TINYINT列转换为INT列(非损失转换)。尝试在这种情况下进行后一种转换将导致副本上的复制停止并出现错误。

ALL_NON_LOSSY

这种模式允许不需要截断或特殊处理源值的转换;也就是说,它允许目标类型范围比源类型更广的转换。

设置此模式不会影响损失转换是否被允许;这由 ALL_LOSSY 模式控制。如果只设置了 ALL_NON_LOSSY,但没有设置 ALL_LOSSY,那么尝试进行可能导致数据丢失的转换(例如 INTTINYINT,或 CHAR(25)VARCHAR(20))将导致副本停止并出现错误。

ALL_LOSSY,ALL_NON_LOSSY

当设置了此模式时,所有支持的类型转换都是允许的,无论它们是否是损失转换。

ALL_SIGNED

将提升的整数类型视为有符号值(默认行为)。

ALL_UNSIGNED

将提升的整数类型视为无符号值。

ALL_SIGNED,ALL_UNSIGNED

将提升的整数类型视为有符号值,如果可能,否则视为无符号值。

[empty]

replica_type_conversions 未设置时,不允许任何属性提升或降级;这意味着源表和目标表中的所有列必须是相同的类型。

这是默认模式。

当整数类型被提升时,其符号性不会被保留。默认情况下,副本将所有这些值视为有符号值。你可以使用 ALL_SIGNEDALL_UNSIGNED 或两者来控制这种行为。ALL_SIGNED 告诉副本将所有提升的整数类型视为有符号值:ALL_UNSIGNED 指示副本将这些值视为无符号值。指定两者将导致副本将值视为有符号值,如果可能,否则视为无符号值;列表顺序无关紧要。既不使用 ALL_SIGNED 也不使用 ALL_UNSIGNED,除非至少有一个 ALL_LOSSYALL_NONLOSSY 也被使用。

更改类型转换模式需要重新启动副本以使用新的 replica_type_conversions 设置。

支持的转换。 支持的不同但相似数据类型之间的转换如下所示:

  • 在任何整数类型 TINYINT, SMALLINT, MEDIUMINT, INTBIGINT 之间。

    这包括 signed 和 unsigned 版本之间的转换。

    损失转换是通过将源值截断到目标列允许的最大(或最小)值来实现的。当从无符号类型转换到有符号类型时,目标列必须足够大以容纳源列中的值范围。例如,可以将 TINYINT UNSIGNED 非损失地降级到 SMALLINT,但不能降级到 TINYINT

  • 在任何小数类型 DECIMAL, FLOAT, DOUBLENUMERIC 之间。

    FLOATDOUBLE 是非损失转换:DOUBLEFLOAT 只能进行损失转换。从 DECIMAL(M,D)DECIMAL(M',D') 的转换,其中 D' >= D(M'-D') >= (M-D 是非损失转换;对于任何情况,其中 M' < M, D' < D, 或两者,只能进行损失转换。

    对于任何十进制类型,如果要存储的值不能适合目标类型,根据服务器文档中定义的舍入规则将值舍入。请参阅第 14.24.4 节,“舍入行为”,了解 decimal 类型的舍入规则。

  • 在所有字符串类型之间,包括CHARVARCHARTEXT,包括不同宽度之间的转换。

    CHARVARCHARTEXT 转换为同样大小或更大的 CHARVARCHARTEXT 列时,从不损失。损失转换是通过在副本上插入字符串的前 N 个字符来处理的,其中 N 是目标列的宽度。

    Important

    不支持使用不同字符集之间的复制。

  • 在所有二进制数据类型之间,包括BINARYVARBINARYBLOB,包括不同宽度之间的转换。

    BINARYVARBINARYBLOB 转换为同样大小或更大的 BINARYVARBINARYBLOB 列时,从不损失。损失转换是通过在副本上插入字符串的前 N 字节来处理的,其中 N 是目标列的宽度。

  • 在任何 2 个 BIT 列之间,大小无所谓。

    当从 BIT(M) 列插入值到 BIT(M') 列时,其中 M' > M,则清除 BIT(M') 列的最重要位(设置为零),并将 BIT(M) 值的 M 位设置为 BIT(M') 列的最少重要位。

    当从源 BIT(M) 列插入值到目标 BIT(M') 列时,其中 M' < M,则将目标列分配最大可能值;换言之,将“所有设置”值分配给目标列。

不允许在前面列表以外的类型之间进行转换。