源和目标表不需要是相同的。源表可以有更多或更少的列于副本表。此外,源和副本表的对应列可以使用不同的数据类型,subject to certain conditions。
不支持在不同的分区表之间进行复制。请参阅 第 19.5.1.24 节,“复制和分区”。
在所有情况下,源和目标表的定义不同,数据库和表名必须在源和副本上相同。附加条件将在以下两个部分中讨论,带有示例。
您可以从源复制表到副本,使源和副本表具有不同的列数,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
在副本上是允许的,因为共同的列c1
、c2
和c3
在表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);
理想情况下,源表和副本表中的对应列应该具有相同的数据类型。但是,这并不是严格执行的,只要满足一定的条件。
通常可以从一个给定的数据类型的列复制到同类型和同大小或更大的列。例如,可以从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
-
将提升的整数类型视为有符号值,如果可能,否则视为无符号值。
- [empty]
-
当
replica_type_conversions
未设置时,不允许任何属性提升或降级;这意味着源表和目标表中的所有列必须是相同的类型。这是默认模式。
当整数类型被提升时,其符号性不会被保留。默认情况下,副本将所有这些值视为有符号值。你可以使用 ALL_SIGNED
、ALL_UNSIGNED
或两者来控制这种行为。ALL_SIGNED
告诉副本将所有提升的整数类型视为有符号值:ALL_UNSIGNED
指示副本将这些值视为无符号值。指定两者将导致副本将值视为有符号值,如果可能,否则视为无符号值;列表顺序无关紧要。既不使用 ALL_SIGNED
也不使用 ALL_UNSIGNED
,除非至少有一个 ALL_LOSSY
或 ALL_NONLOSSY
也被使用。
更改类型转换模式需要重新启动副本以使用新的 replica_type_conversions
设置。
支持的转换。 支持的不同但相似数据类型之间的转换如下所示:
-
在任何整数类型
TINYINT
,SMALLINT
,MEDIUMINT
,INT
和BIGINT
之间。这包括 signed 和 unsigned 版本之间的转换。
损失转换是通过将源值截断到目标列允许的最大(或最小)值来实现的。当从无符号类型转换到有符号类型时,目标列必须足够大以容纳源列中的值范围。例如,可以将
TINYINT UNSIGNED
非损失地降级到SMALLINT
,但不能降级到TINYINT
。 -
在任何小数类型
DECIMAL
,FLOAT
,DOUBLE
和NUMERIC
之间。FLOAT
到DOUBLE
是非损失转换:DOUBLE
到FLOAT
只能进行损失转换。从DECIMAL(
到M
,D
)DECIMAL(
的转换,其中M'
,D'
)
和D'
>=D
(
是非损失转换;对于任何情况,其中M'
-D'
) >= (M
-D
,M'
<M
, 或两者,只能进行损失转换。D'
<D
对于任何十进制类型,如果要存储的值不能适合目标类型,根据服务器文档中定义的舍入规则将值舍入。请参阅第 14.24.4 节,“舍入行为”,了解 decimal 类型的舍入规则。
-
在所有字符串类型之间,包括
CHAR
、VARCHAR
和TEXT
,包括不同宽度之间的转换。将
CHAR
、VARCHAR
或TEXT
转换为同样大小或更大的CHAR
、VARCHAR
或TEXT
列时,从不损失。损失转换是通过在副本上插入字符串的前N
个字符来处理的,其中N
是目标列的宽度。Important不支持使用不同字符集之间的复制。
-
在所有二进制数据类型之间,包括
BINARY
、VARBINARY
和BLOB
,包括不同宽度之间的转换。将
BINARY
、VARBINARY
或BLOB
转换为同样大小或更大的BINARY
、VARBINARY
或BLOB
列时,从不损失。损失转换是通过在副本上插入字符串的前N
字节来处理的,其中N
是目标列的宽度。 -
在任何 2 个
BIT
列之间,大小无所谓。当从
BIT(
列插入值到M
)BIT(
列时,其中M'
)
,则清除M'
>M
BIT(
列的最重要位(设置为零),并将M'
)BIT(
值的M
)M
位设置为BIT(
列的最少重要位。M'
)当从源
BIT(
列插入值到目标M
)BIT(
列时,其中M'
)
,则将目标列分配最大可能值;换言之,将“所有设置”值分配给目标列。M'
<M
不允许在前面列表以外的类型之间进行转换。