2024年7月23日
今天天气不错,在公司给同事们介绍了数据库的sql、数据模型、sql优化的一点点内容。
这次分享理论上应该是上周二开始准备的,周二到周四在听课,周末和周一把要讲的内容大概过了一遍。
周二下午开始讲解,感觉很吃力,总的原因有一下:

一是因为ppt没有自己做,沿用的官方的英文资料。很多内容一眼看不明白,没办法快速的说下去,讲解的过程中是不够时间去慢慢思考的。

二是对算法和原理的部分,缺乏足够的理解,没有办法用自己的语言进行阐述。

三是要在说明的过程中,带入自己的对问题的认知,拿身边的事情举例。和听众做好更深的互动,才是一个合格的分享。

四是实验过程没有完整的操作,导致无法流程和快速的完成预期的动作。

后续应该做的事情,用输出倒逼输入,才能对问题有更深入的认知
将重要的内容用自己的语言加以表达
重视实践和操作,充满好奇心的完成事情,价钱记录和分享

概念:
说事务的隔离级别之前,应该先说清楚事务

事务是一组具有统一逻辑功能的语句的组合。
事务具有4个特点:
原子性、隔离性、永久性、一致性
原子性 变更的执行结果具有统一性、全部执行ok、or not。
隔离性 事务执行完毕之前,对其他事物是不可见的
永久性 执行成功后永久生效
一致性 执行全部ok或者全部回退

文章目录
一、前言
二、操作流程

  1. 获取最后一个 GTID 操作
  2. 跳过一个事务
    三、案例
  3. 问题描述
  4. 原因分析
  5. 处理过程
    一、前言
    很多场景下我们需要跳过一个事务来修复主从关系,例如主从事务不一致,或者对无主键表更新,导致较大延迟,操作过程在此记录。

二、操作流程

  1. 获取最后一个 GTID 操作
    在 GTID 模式下,如果需要跳过一个事务,就需要先获得从库执行的最后一个 GTID 操作,可以通过下方几种方法获得:

    show slave status:

    Executed_Gtid_Set: 2102e47a-a63b-11eb-b2a1-fa85c353c300:1-68835,
    741e7d25-a5a2-11eb-a8d2-facd1b9d5200:1-1691060:1691062-1696109,
    aeccf6dc-c76d-11eb-a563-fab7dbe5cd00:1-38,
    eab37148-e44b-11eb-a993-fa85c353c300:1-2

这里主要看 Executed_Gtid_Set 变量。

show master status:

*************************** 1. row ***************************
File: mysql-bin.000014
Position: 234
Binlog_Do_DB: 
Binlog_Ignore_DB: 
Executed_Gtid_Set: 2102e47a-a63b-11eb-b2a1-fa85c353c300:1-68835,
741e7d25-a5a2-11eb-a8d2-facd1b9d5200:1-1691060:1691062-1696109,
aeccf6dc-c76d-11eb-a563-fab7dbe5cd00:1-38,
eab37148-e44b-11eb-a993-fa85c353c300:1-2
1 row in set (0.01 sec)

这里主要看 Executed_Gtid_Set 变量。

如果数据库有多次切换,Executed_Gtid_Set 中的 GTID SET 比较多,我们只看当前主库的 server_uuid 的 GTID SET 即可。
主库的 UUID 可以通过 select @@server_uuid; 查到。

  1. 跳过一个事务

    stop slave;
    set session gtid_next='72170331-ae27-11eb-b3a1-000c29169a83:96174';
    begin;commit;
    set session gtid_next='AUTOMATIC';
    start slave;

在 GTID 模式下,传统复制参数 sql_slave_skip_counter 不能使用。

三、案例

  1. 问题描述

    CREATE TABLE order_temp (
    order_code varchar(10) DEFAULT NULL,
    order_status varchar(255) DEFAULT NULL,
    order_time varchar(255) DEFAULT NULL,
    account_status varchar(255) DEFAULT NULL,
    receivable decimal(10,2) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

一张无主键表,开发想将 receivable 值全部修改为 3 因为测试环境,直接全表更新,在主库不到一分钟就执行成功了,没想到备库跑了两天都没有结束。

update order_temp set receivable = 3;
1

  1. 原因分析
    使用 row 模式复制 binlog 按行存储,回放的时候也是一行一行去改,因为该表没有主键索引,每一次修改都是一次全表扫描,一次全表扫描需要两秒,表中有 4998000 行数据:

4998000 * 2 / 3600 / 24 = 155 天

如果不处理的话,估计得跑上小半年,这个备库也算是废了。

  1. 处理过程
    确认主库 uuid 在主库查:

    root@mysql 14:43: [rep_test]>select @@server_uuid;
    +--------------------------------------+
    | @@server_uuid |
    +--------------------------------------+
    | 741e7d25-a5a2-11eb-a8d2-facd1b9d5200 |
    +--------------------------------------+
    1 row in set (0.00 sec)

确认从库最后一个事务:

*************************** 1. row ***************************
File: mysql-bin.000014
Position: 234
Binlog_Do_DB: 
Binlog_Ignore_DB: 
Executed_Gtid_Set: 
2102e47a-a63b-11eb-b2a1-fa85c353c300:1-68835,
741e7d25-a5a2-11eb-a8d2-facd1b9d5200:1-1691060:1691062-1696109,
aeccf6dc-c76d-11eb-a563-fab7dbe5cd00:1-38,
eab37148-e44b-11eb-a993-fa85c353c300:1-2
1 row in set (0.00 sec)

第二行就是该实例主库的 uuid 最后一个事务是 1696109

停止复制:
该步骤可能持续时间较长,这个和修改的数据量和延迟的时长有关系,此刻需要回滚已经应用的 event。

stop slave;

跳过复制:
刚才最后一个事务是 1696109 正在执行的事务就是 1696109 + 1 = 1696110

set session gtid_next='741e7d25-a5a2-11eb-a8d2-facd1b9d5200:1696110';
begin;commit;
set session gtid_next='AUTOMATIC';

修复数据
跳过事务,则主库的更新操作没有在从库应用,已经被回滚,此时可以手动在从库跑一下该 SQL。不同的场景有不用的修复方法,此时就跑原 SQL 即可。
修复数据时,要注意如果有级联复制,这种特殊操作前,临时会话级别关闭 binlog

set session sql_log_bin = 0;

重新启动复制

start slave;

启动后观察主从延迟情况。
————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                    

原文链接:https://blog.csdn.net/qq_42768234/article/details/121355272