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  /  ...  /  Stored Function Examples to Manipulate GTIDs

19.1.3.8 存储函数示例来操作GTIDs

本节提供了使用MySQL提供的一些内置函数来操作GTID-based复制的存储函数示例(见第27章,存储对象),这些函数列举如下:

  • GTID_SUBSET():显示一个GTID集是否是另一个GTID集的子集。

  • GTID_SUBTRACT():返回一个GTID集中不在另一个GTID集中的GTIDs。

  • WAIT_FOR_EXECUTED_GTID_SET():等待直到给定的GTID集中的所有事务都被执行。

请参阅第14.18.2节,“使用全局事务标识符(GTIDs)的函数”,以获取更多关于这些函数的信息。

注意,在这些存储函数中,delimiter命令已经被用来将MySQL语句分隔符更改为竖线,如下所示:

mysql> delimiter |

所有在本节中显示的存储函数都将字符串表示的GTID集作为参数,因此GTID集必须始终在使用它们时被引号括起来。

这个函数返回非零(true),如果两个GTID集是相同的集,即使它们不是以相同的方式格式化的:

CREATE FUNCTION GTID_IS_EQUAL(gs1 LONGTEXT, gs2 LONGTEXT)
  RETURNS INT
  RETURN GTID_SUBSET(gs1, gs2) AND GTID_SUBSET(gs2, gs1)
|

这个函数返回非零(true),如果两个GTID集是disjoint的:

CREATE FUNCTION GTID_IS_DISJOINT(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS INT
  RETURN GTID_SUBSET(gs1, GTID_SUBTRACT(gs1, gs2))
|

这个函数返回非零(true),如果两个GTID集是disjoint的,并且sum是它们的union:

CREATE FUNCTION GTID_IS_DISJOINT_UNION(gs1 LONGTEXT, gs2 LONGTEXT, sum LONGTEXT)
RETURNS INT
  RETURN GTID_IS_EQUAL(GTID_SUBTRACT(sum, gs1), gs2) AND
         GTID_IS_EQUAL(GTID_SUBTRACT(sum, gs2), gs1)
|

这个函数返回GTID集的标准形式,在所有大写字母中,没有空格,没有重复的,UUID按字母顺序排序,间隔按数字顺序排序:

CREATE FUNCTION GTID_NORMALIZE(gs LONGTEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(gs, '')
|

这个函数返回两个GTID集的union:

CREATE FUNCTION GTID_UNION(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
  RETURN GTID_NORMALIZE(CONCAT(gs1, ',', gs2))
|

这个函数返回两个GTID集的交集:

CREATE FUNCTION GTID_INTERSECTION(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(gs1, GTID_SUBTRACT(gs1, gs2))
|

这个函数返回两个GTID集之间的对称差,即存在于gs1但不存在于gs2的GTIDs,以及存在于gs2但不存在于gs1的GTIDs。

CREATE FUNCTION GTID_SYMMETRIC_DIFFERENCE(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(CONCAT(gs1, ',', gs2), GTID_INTERSECTION(gs1, gs2))
|

这个函数从GTID集中删除所有来自指定origin的GTIDs,并返回剩余的GTIDs,如果有的话。UUID是服务器的标识符,通常是server_uuid的值。

CREATE FUNCTION GTID_SUBTRACT_UUID(gs LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(gs, CONCAT(UUID, ':1-', (1 << 63) - 2))
|

这个函数是前一个函数的反向操作;它仅返回来自指定服务器标识符(UUID)的GTIDs。

CREATE FUNCTION GTID_INTERSECTION_WITH_UUID(gs LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(gs, GTID_SUBTRACT_UUID(gs, uuid))
|

示例 19.1 验证副本是否最新

内置函数GTID_SUBSET()GTID_SUBTRACT()可以用于检查副本是否应用了所有源服务器上的事务。

要使用GTID_SUBSET()执行此检查,请在副本上执行以下语句:

SELECT GTID_SUBSET(source_gtid_executed, replica_gtid_executed);

如果返回值为0(false),这意味着source_gtid_executed中的某些GTIDs不在replica_gtid_executed中,副本尚未应用源服务器上的所有事务,因此副本不是最新的。

要使用GTID_SUBTRACT()执行相同的检查,请在副本上执行以下语句:

SELECT GTID_SUBTRACT(source_gtid_executed, replica_gtid_executed);

该语句返回source_gtid_executed中的GTIDs,但不在replica_gtid_executed中。如果返回了任何GTIDs,源服务器已经应用了一些事务,而副本尚未应用,这意味着副本不是最新的。


示例 19.2 备份和恢复场景

存储函数GTID_IS_EQUAL()GTID_IS_DISJOINT()GTID_IS_DISJOINT_UNION()可以用于验证涉及多个数据库和服务器的备份和恢复操作。在这个示例场景中,server1包含数据库db1server2包含数据库db2。目标是将数据库db2复制到server1,并且server1上的结果将是两个数据库的union。使用的过程是使用mysqldump备份server2,然后在server1上恢复该备份。

假设mysqldump 使用 --set-gtid-purged 设置为 ONAUTO(默认值),输出将包含一个 SET @@GLOBAL.gtid_purged 语句,该语句将从 server2gtid_executed 集合添加到 server1gtid_purged 集合中。gtid_purged 集合包含了在给定服务器上提交的所有事务的 GTID,但这些事务不在服务器上的任何二进制日志文件中。当数据库 db2 被复制到 server1 时,server2 上提交的交易的 GTID 必须添加到 gtid_purged 集合中,以便使集合完整。

存储函数可以用于帮助以下步骤中的操作:

  • 使用 GTID_IS_EQUAL() 来验证备份操作是否正确地计算了 SET @@GLOBAL.gtid_purged 语句的 GTID 集合。在 server2 上,从 mysqldump 输出中提取该语句,并将 GTID 集合存储到本地变量中,例如 $gtid_purged_set。然后执行以下语句:

    server2> SELECT GTID_IS_EQUAL($gtid_purged_set, @@GLOBAL.gtid_executed);

    如果结果为 1,则两个 GTID 集合相等,且集合已经正确计算。

  • 使用 GTID_IS_DISJOINT() 来验证 mysqldump 输出中的 GTID 集合不与 server1 上的 gtid_executed 集合重叠。在 server1 上,提取并存储 gtid_purged 集合到本地变量中,如前所述,然后执行以下语句:

    server1> SELECT GTID_IS_DISJOINT($gtid_purged_set, @@GLOBAL.gtid_executed);

    如果结果为 1,则两个 GTID 集合不重叠,因此不存在重复的 GTID。

  • 使用 GTID_IS_DISJOINT_UNION() 来验证恢复操作是否在 server1 上正确地设置了 GTID 状态。在恢复备份之前,在 server1 上,通过执行以下语句来获取现有的 gtid_executed 集合:

    server1> SELECT @@GLOBAL.gtid_executed;

    将结果存储在本地变量 $original_gtid_executed 中,以及从 gtid_purged 集合中存储的集合在另一个本地变量中,如前所述。当从 server2 的备份被恢复到 server1 上时,执行以下语句以验证 GTID 状态:

    server1> SELECT 
          ->   GTID_IS_DISJOINT_UNION($original_gtid_executed,
          ->                          $gtid_purged_set,
          ->                          @@GLOBAL.gtid_executed);

    如果结果为 1,则存储函数已经验证了原始 gtid_executed 集合来自 server1 ($original_gtid_executed) 和从 server2 添加的 gtid_purged 集合 ($gtid_purged_set) 之间没有重叠,并且更新的 gtid_executed 集合现在由 server1 的原始 gtid_executed 集合和从 server2 添加的 gtid_purged 集合组成,这是所需的结果。确保在 server1 上执行任何进一步的事务之前执行此检查,否则新的交易将导致检查失败。


示例 19.3 选择最新的副本以进行手动故障转移

存储函数 GTID_UNION() 可以用来从一组副本中标识出最新的副本,以便在源服务器意外停止后执行手动故障转移操作。如果一些副本正在经历复制延迟,这个存储函数可以用来计算最新的副本,而不需要等待所有副本应用其现有的中继日志,从而最小化故障转移时间。该函数可以返回每个副本上的 gtid_executed 的联合,以及记录在性能模式 replication_connection_status 表中的交易集。您可以比较这些结果,以找到哪个副本的交易记录是最新的,即使还没有提交所有交易。

在每个副本上,通过发出以下语句来计算完整的交易记录:

SELECT GTID_UNION(RECEIVED_TRANSACTION_SET, @@GLOBAL.gtid_executed)
    FROM performance_schema.replication_connection_status
    WHERE channel_name = 'name';

然后,您可以比较每个副本的结果,以确定哪个副本的交易记录是最新的,并使用该副本作为新的源。


示例 19.4 检查副本上的额外交易

存储函数 GTID_SUBTRACT_UUID() 可以用来检查副本是否收到了不来自其指定源或源的交易。如果是这样,可能是您的复制设置或代理、路由器或负载均衡器出现问题。该函数通过从 GTID 集中删除指定来源服务器的所有 GTID,并返回剩余的 GTID(如果有)。

对于单个源的副本,发出以下语句,指定来源服务器的标识符,通常是 server_uuid

SELECT GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed, server_uuid_of_source);

如果结果不是空的,那么返回的交易是额外的交易,不来自指定的源。

对于多源拓扑结构的副本,包括每个源的服务器 UUID 在函数调用中,如下所示:

SELECT 
  GTID_SUBTRACT_UUID(GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed,
                                        server_uuid_of_source_1),
                                        server_uuid_of_source_2);

如果结果不是空的,那么返回的交易是额外的交易,不来自任何指定的源。


示例 19.5 验证服务器在复制拓扑结构中的只读状态

存储函数 GTID_INTERSECTION_WITH_UUID() 可以用来验证服务器没有生成任何 GTID 并且处于只读状态。该函数仅返回 GTID 集中的那些来自指定服务器标识符的 GTID。如果 gtid_executed 中的任何交易来自该服务器自身的标识符,那么该服务器本身生成了这些交易。您可以在服务器上发出以下语句来检查:

SELECT GTID_INTERSECTION_WITH_UUID(@@GLOBAL.gtid_executed, my_server_uuid);

示例 19.6 在多源复制中验证附加的副本

存储函数 GTID_INTERSECTION_WITH_UUID() 可以用来确定在多源复制设置中,副本是否应用了来自特定源的所有交易。在这种情况下,source1source2 都是源和副本,并且相互复制。source2 也有自己的副本。副本也从 source1 接收和应用交易,如果 source2 配置了 log_replica_updates=ON,否则不这样做。无论如何,我们当前只想知道副本是否与 source2 同步。在这种情况下,GTID_INTERSECTION_WITH_UUID() 可以用来确定 source2 生成的交易,忽略 source2source1 复制的交易。然后,可以使用内置函数 GTID_SUBSET() 将结果与副本上的 gtid_executed 集进行比较。如果副本与 source2 同步,那么副本上的 gtid_executed 集将包含交集集中的所有交易(来自 source2 的交易)。

要执行此检查,请将 gtid_executed 的值和 source2 的服务器 UUID 存储在用户变量中,如下所示:

source2> SELECT @@GLOBAL.gtid_executed INTO @source2_gtid_executed;

source2> SELECT @@GLOBAL.server_uuid INTO @source2_server_uuid;

replica> SELECT @@GLOBAL.gtid_executed INTO @replica_gtid_executed;

然后,使用 GTID_INTERSECTION_WITH_UUID()GTID_SUBSET() 函数,以这些变量作为输入,如下所示:

SELECT 
  GTID_SUBSET(
    GTID_INTERSECTION_WITH_UUID(@source2_gtid_executed,
                                @source2_server_uuid),
                                @replica_gtid_executed);

source2 (@source2_server_uuid) 的服务器标识符用于 GTID_INTERSECTION_WITH_UUID(),以标识和返回从 GTID 集合中来自 source2 的那些 GTID,省略来自 source1 的那些。然后,将结果 GTID 集合与副本上的所有执行 GTID 集合进行比较,使用 GTID_SUBSET()。如果该语句返回非零(true),则所有来自 source2 的已识别 GTID(第一个输入集)也出现在副本的 gtid_executed 中,这意味着副本已经收到并执行了来自 source2 的所有事务。