zoukankan      html  css  js  c++  java
  • 16.Mysql之MVCC浅谈03

    1.前言

         Mysql的MVCC机制是Mysql中的重要的一环,其中也是经常在Mysql DBA面试中被问到,并且也是Innodb存储引擎(带有MVCC机制)和Myism存储引擎的一个很大的区别。

    2. 什么是MVCC技术?

      MVCC(Multi-Version Concurrency Control)即多版本并发控制,在高性能Mysql一书中介绍,MVCC的大多数事务型存储引擎实现都不是简单的行级锁,它们一般都实现了多版本并发控制,可以认为MVCC是行锁的一个变种,在很多情况下避免的加锁的操作,因此开销更低,实现对读的不阻塞,读不加锁,读写不冲突。缺点是每行记录需要额外的记录空间,需要做更多的维护工作和检查

      MVCC的实现是通过保存数据在某个时间点的快照来实现的,也就是说不管执行多长时间,每个事务看到的数据都是一致的,根据事务开始的时间点不同,每个事务对同一张表,同一时刻看到的数据都是不一样的,

    3.MVCC具体实现原理?

      MVCC具体实现原理主要是依赖记录中3个隐藏的字段、undo日志、以及Read View来实现的

      3.1. 三个隐藏字段:在表中除了我们自定义的字段外,还包括DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段

    • DB_TRX_ID:6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID
    • DB_ROLL_PTR:7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)
    • DB_ROW_ID:6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引
    • 实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了 

    如下图所示: 

    前面的两列是用户自己定义的,后面的三列是Mysql数据库默认的隐藏列,其中,DB_ROW_ID是数据库默认为该行记录生成的唯一隐式主键,DB_TRX_ID是当前操作该记录的事务ID,而DB_ROLL_PTR是一个回滚指针,用于配合undo日志,指向上一个旧版本

      3.2 undo日志

      undo日志主要分为两种:

    • insert undo log : 代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃
    • update undo log:事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除

      对undo有帮助的主要是:update undo log日志,它实际存在于rollback segment中旧的记录链表中,

      执行流程如下(很重要):

      比如一个有个事务插入persion表插入了一条新记录,记录如下,name为LiuYiFei, age为20岁,隐式主键是1,事务ID和回滚指针,我们假设为NULL,

      

       现在来了一个事务1对该记录的name做出了修改,改为Tom (update person set name=Tom where  name='LiuYiFie')

    • 在事务1对数据行进行修改时,首先数据库会对该数据行加一个排他锁
    • 然后会把改行数据拷贝到undo log中,作为旧的记录,这样unlog 里面就会有了改行的副本
    • 拷贝完毕之后,修改字段name有LiuYiFei-->Tom,并修改隐藏字段事务ID为当前事务为1的ID,这里默认从1开始,之后递增,回滚指针指向拷贝拷贝到undo log的副本记录,即表示我的上一个副本就是它。
    • 事务提交,释放锁

    如下图所示:

      又来了个事务2修改person表的同一个记录,将age修改为30岁

    • 在事务2对数据行进行修改时,首先数据库也会对该数据行加一个排他锁
    • 然后把该行数据拷贝到undo log中,作为旧记录,发现该行记录已经有undo log了那么最新的旧数据作为链表的表头,插在该行记录的undo log最前面
    • 修改该行age为30岁,并且修改隐藏字段的事务ID为当前事务2的ID, 那就是2,回滚指针指向刚刚拷贝到undo log的副本记录
    • 事务提交,释放锁

    总结:

      从上面,我们就可以看出,不同事务或者相同事务的对同一记录的修改,会导致该记录的undo log成为一条记录版本线性表,既链表,undo log的链首就是最新的旧记录,链尾就是最早的旧记录(当然就像之前说的该undo log的节点可能是会purge线程清除掉,向图中的第一条insert undo log,其实在事务提交之后可能就被删除丢失了,不过这里为了演示,所以还放在这里)

      purge:

    • 从前面的分析可以看出,为了实现InnoDB的MVCC机制,更新或者删除操作都只是设置一下老记录的deleted_bit,并不真正将过时的记录删除
    • 为了节省磁盘空间,InnoDB有专门的purge线程来清理deleted_bit为true的记录。为了不影响MVCC的正常工作,purge线程自己也维护了一个read view(这个read view相当于系统中最老活跃事务的read view);如果某个记录的deleted_bit为true,并且DB_TRX_ID相对于purge线程的read view可见,那么这条记录一定是可以被安全清除的。

     3.3 Read View(读视图)

        什么是读视图?    

        说白了Read View就是事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)
        
        所以 Read View主要是用来做可见性判断的, 即当某个事务执行快照读的时候,对该记录创建一个Read View读视图,把它比作条件用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log里面的某个版本的数据
     
        InnoDB为每个事务构造了一个数组,用来保存这是事务启动的瞬间,当前正在活跃的所有的事务ID,活跃指的是,事务启动了但是还没有提交。
        这个数组里面的ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。
        这个视图数组和高水位,就组成了当前事务的一致性视图:
        而数据版本的可见性规则,就是基于数据的trix_id和这个一致性视图做对比的结果得到的。
        这个视图数组把所有的trx_id分成了三种情况:
     
        
        这样,对于当前事务的启动瞬间来说,一个数据版本的row trx_id,就会有三种情况:
    • 如果落在绿色的部分,表示这个版本是已提交的事务或者是当前事务自己生成的是可见的
    • 如果落在红色的部分,表明这个版本是由将来事务生成的,是肯定不可见的
    • 如果落在黄色的部分,那么就包括两种情况:
      • 若row_trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见
      • 若row_trx_id不在这个数组中,表示这个版本是已经提交的事务生成的,可见。  
     
     

        当前读:    

        像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

        快照读:

        像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

        总结:

        说白了MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现



      





        

      



  • 相关阅读:
    cass9.1打开程序错误——加载arx失败
    c#类型和变量
    AutoCAD启动缓慢
    XAML特殊字符
    静态GPS时间修改
    AutoCAD的IntersectWith方法
    Visual studio2010开发AutoCAD2008、2006 启动调试问题
    安装CAD2006装好了为什么不能用,显示系统错误无法启动此程序,因计算机丢失aclst.dll。尝试重新安装该程序以解
    安装AutoCAD2006时,提示已终止安装
    CASS 2008的野外操作码
  • 原文地址:https://www.cnblogs.com/zmc60/p/14958420.html
Copyright © 2011-2022 走看看