zoukankan      html  css  js  c++  java
  • mysql中的mvcc解读

    原文链接 : https://www.toutiao.com/i6674177996649136653

    对于MVCC想必大家也看到了不少源码层的解读,最大特点就是分析的是比较深入了,但是却不大好理解,最后有种不明觉厉的感觉,以至于在面试中经常翻船。

    我们换个角度来解读一下, 在表设计中,我们有一种策略,那就是尽可能保留数据变化的

    历史,比如在数据发生变化时我们不会直接删除数据,而是把它转换为两类操作。

    比如修改一个账户的余额,这是敏感信息,属于状态型数据,在更新时需要保留完整的数据

    变化历史,那么把余额从100变化为200的过程,会转化为1条 update 语句,1条 insert 语句。

    如下的操作是我们预期的结果:

    MySQL中的MVCC解读

     

    可以把这个过程改造为:

    MySQL中的MVCC解读

     

    有的同学说,这个和 MVCC 有什么关系呢,其实 MVCC 的实现原理也是类似的方式,我们就以

    这种方式作为例子来解释,在这种情况下,第1行 update 语句对应的数据可以理解为是之前

    的数据镜像,而第2行则是数据处理后的结果。

    如果存在大量的并发读写,我们可以把读的压力分担出来,即数据的查询可以指向镜像,而

    数据的修改指向当前的变化数据,这样两者是一个互补的关系。

    这种情况类似下面的方式,比如 T1,T2,T3三个顺序时间里发生了三次请求,分别是一次写

    请求和两次读请求.

    MySQL中的MVCC解读

     

    那么在 MySQL 中会先在 T1时间生成一个快照,比如数据标识是90,然后在这个基础上进行

    数据修改,数据标识为100,但是事务未提交。

    在 T1写数据的事务内,T2时间的读请求会读取 T1时间生成的快照数据,读取的数据标识

    依旧是 90,T3时间的读请求也是类似。所以MVCC本身还是比较接地气的,只是我们理解的方式有些高大上,消化不了了。我们小结一下:

    1.表设计中数据生命周期的管理是一种体系化的管理方式,原理和思路是通用的。2.数据生命周期管理有两个重要的标识,一个是标识数据变化的,一个是标识数据可用状态的。

    明白了这些,理解 InnoDB 的 MVCC 就很简单了,我们使用类似的思路来做下解读,假设在每

    行记录后面保存两个隐藏的列来实现的,这两个列,分别保存了这个行的创建时间,一个保

    存的是行的删除时间。这里存储的是系统版本号,会自动递增,我们按照 DML 的几个维度进

    行阐述。

    1)、首先是 Insert 操作, 事务 id 假设是1

    id name create version delete version

    1 test 1

    2)、Update 操作,会先把当前记录标识为已删除,然后新增一列数据,写入相应的版本号,

    在这里就是2,和上一条的 delete_version 是一致的,比如把字段 name 修改为 new_test

    id name create version delete version

    1 test 1 2

    1 new_test 2

    3)delete 操作,就是把当前记录标识为已删除

    id name create version delete version

    1 new_value 2 3

    此外需要考虑的是上面的实现方式中,如果事务发生回滚该如何处理,这个是我们需要重点

    考虑的,也是对数据周期管理流程的一个补充,这里我们就要引出 InnoDB 层的实现 undo.

    我们来设想一个问题,原有的镜像数据在表中存放显然是难以维护的,而且从存储上也是一

    笔不小的开销,所以从性价比考虑,这部分的内容应该是独立存放的,这个存放的地方就是

    undo 日志里面,一旦出现了事务回滚,我们可以把已有的数据状态通过逆向应用保证事务

    的 ACID 特性。

    要实现这个细粒度的操作,在 InnoDB 的设计中,实际上所有行数据会增加三个内部属性列:

    (1)DB_TRX_ID,6字节,记录每一行最近一次修改它的事务 ID;

    (2)DB_ROLL_PTR,7字节,记录指向回滚段 undo 日志的指针;

    (3)DELETE BIT,标识该记录是否被删除,不是真正的删除数据;

    把这三个列组合起来,就可以标记数据的周期性,并定位到相应的事务,在需要的时候进行

    回滚。

    比如一张表 test (id,name)主键为 id 列

     insert 的数据在 redo 中顺序记录 insert 操作,同时生成 undo 记录,为逆操作 delete

     delete 的数据在 redo 中顺序记录 delete 操作,同时生成 undo 记录,为逆操作 insert

     update 的数据在 redo 中顺序记录 update 操作,同时生成 undo 记录,为逆操作 update,

    原来是从 id=1 变成 id=3,则逆操作为 id =3,变成 id=1

    对于 InnoDB 来说,无论是更新,删除,都只是设置行记录上的 deleted version 标记位,

    而不是真正的删除记录,后续这些记录的清理,是通过 Purge 后台进程实现的。

    此外,需要说明的是只有在隔离级别 read-committed 和 repeatable-read 才能使用 MVCC,

    read-uncommited 由于是读到未提交的,所以不存在版本的问题,而 serializable 则会对

    所有读取的行加锁。

  • 相关阅读:
    【Android测试】Android截图的深水区
    【Android测试】UI自动化代码优化之路
    网页爬虫小试牛刀
    【Android测试】【第十九节】Espresso——API详解
    【iOS测试】【随笔】帧率FPS评测
    【iOS测试】【随笔】崩溃日志获取
    【后台测试】Linux下小试jmeter
    【后台测试】手把手教你jmeter压测
    【行业交流】2016 TiD质量竞争力大会——移动互联网测试到质量的转变之路
    【Android测试】【第十八节】Espresso——环境搭建
  • 原文地址:https://www.cnblogs.com/myd620/p/12871829.html
Copyright © 2011-2022 走看看