文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  主节点和副本节点上具有不同表定义的复制

19.5.1.9 主节点和副本节点上具有不同表定义的复制

复制的源表和目标表不必完全相同。源表上的列可以比副本表上的列多或少。此外,源和副本上对应的表列可以使用不同的数据类型,但需满足某些条件。

注意

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

在源表和目标表的定义不完全相同的所有情况下,数据库和表名在源和副本上必须相同。以下两节将通过示例讨论其他条件。

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

您可以将表从源复制到副本,以便表的源副本和副本副本具有不同数量的列,但需满足以下条件:

  • 两个版本的表共有的列必须在源和副本上以相同的顺序定义。(即使两个表具有相同数量的列也是如此。)

  • 两个版本的表共有的列必须在任何其他列之前定义。

    这意味着如果在副本上执行 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 语句,因为两个版本的表 t 共有的列 c1c2c3 在两个版本的表中仍然保持在一起,位于任何不同的列之前。

    但是,以下 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) 列。在某些情况下,也可以从具有一种数据类型(在源表上)的列复制到具有不同数据类型(在副本表上)的列;当源表版本的列的数据类型提升为副本表上相同大小或更大的类型时,这称为 属性提升

属性提升可与基于语句的复制和基于行的复制一起使用,并且不依赖于源表或副本表使用的存储引擎。但是,日志记录格式的选择确实会影响允许的类型转换;本节稍后将讨论具体细节。

重要

无论使用基于语句的复制还是基于行的复制,如果您希望采用属性提升,则副本表的副本都不能包含比源表的副本更多的列。

基于语句的复制。 使用基于语句的复制时,要遵循的一个简单的经验法则是:如果在源表上运行的语句也可以在副本表上成功执行,那么它也应该可以成功复制。换句话说,如果语句使用的值与副本表上给定列的类型兼容,则可以复制该语句。例如,您可以将适合 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,则尝试进行会导致数据丢失的转换(例如,从 INT 转换为 TINYINT,或从 CHAR(25) 转换为 VARCHAR(20))会导致副本表停止并出现错误。

ALL_LOSSY,ALL_NON_LOSSY

设置此模式时,无论是否为有损转换,都允许所有受支持的类型转换。

ALL_SIGNED

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

ALL_UNSIGNED

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

ALL_SIGNED,ALL_UNSIGNED

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

[]

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

这是默认模式。

提升整数类型时,不会保留其符号。默认情况下,副本表将所有此类值视为有符号值。您可以使用 ALL_SIGNEDALL_UNSIGNED 或两者来控制此行为。ALL_SIGNED 告诉副本表将所有提升的整数类型都视为有符号;ALL_UNSIGNED 指示它将这些类型视为无符号。同时指定两者会导致副本表在可能的情况下将值视为有符号,否则将其视为无符号;它们列出的顺序无关紧要。如果 ALL_LOSSYALL_NONLOSSY 中至少有一个未使用,则 ALL_SIGNEDALL_UNSIGNED 均不起作用。

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

受支持的转换。 以下列表显示了不同但相似的数据类型之间受支持的转换

  • 在任何整数类型之间:TINYINTSMALLINTMEDIUMINTINTBIGINT

    这包括这些类型的有符号和无符号版本之间的转换。

    有损转换是通过将源值截断为目标列允许的最大值(或最小值)来进行的。为了确保从无符号类型转换为有符号类型时进行无损转换,目标列必须足够大以容纳源列中的值范围。例如,您可以将 TINYINT UNSIGNED 无损降级为 SMALLINT,但不能降级为 TINYINT

  • 在任何十进制类型之间:DECIMALFLOATDOUBLENUMERIC

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

    对于任何十进制类型,如果要存储的值不适合目标类型,则根据文档中其他地方为服务器定义的舍入规则将该值舍入。有关如何对十进制类型执行此操作的信息,请参见 第 14.24.4 节“舍入行为”

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

    CHARVARCHARTEXT 转换为相同大小或更大大小的 CHARVARCHARTEXT 列永远不会有损。有损转换是通过仅在副本表上插入字符串的前 N 个字符来处理的,其中 N 是目标列的宽度。

    重要

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

  • 在任何二进制数据类型 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),将分配 BIT(M') 列的最大可能值;换句话说,将为目标列分配一个“全设置”值。

不允许在上一个列表中不存在的类型之间进行转换。