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 则会对

    所有读取的行加锁。

  • 相关阅读:
    POJ 1659 Frogs' Neighborhood
    zoj 2913 Bus Pass(BFS)
    ZOJ 1008 Gnome Tetravex(DFS)
    POJ 1562 Oil Deposits (DFS)
    zoj 2165 Red and Black (DFs)poj 1979
    hdu 3954 Level up
    sgu 249 Matrix
    hdu 4417 Super Mario
    SPOJ (BNUOJ) LCM Sum
    hdu 2665 Kth number 划分树
  • 原文地址:https://www.cnblogs.com/myd620/p/12871829.html
Copyright © 2011-2022 走看看