MySQL MVCC

简介

  • Multi Version Concurrency Control (MVCC), 即多版本并发控制, 是基于锁的并发控制。(Lock-Based Concurrency Control)
  • MVCC在Oracle, MySQL, PostgreSQL等主流RDBMS中都有应用, 在此仅解释MySQL中的MVCC。
  • 特征优势: 读不加锁, 读写不冲突, 有利于提升读多写少的OLTP应用中系统的并发性能。
  • 在理解MVCC前需要复习一下MySQL架构, 事务隔离级别 以及锁机制。

MySQL架构

  • 架构图

    “MYSQL 架构”的图片搜索结果

  • Connector

    • 连接器, 不同语言的客户端通过mysql的协议与mysql服务器进行连接通信。
  • Connection Pool

    • 连接池, 进行权限验证, 连接池管理, 线程管理等。
  • SQL Interface

    • SQL接口, 生成 Data Manipulation Language(DML), Data Defination Language(DDL), 存储过程, 视图, 触发器等。
  • Parser

    • 解析器
      • 内部将文本格式转换为二进制结构
      • 目的是为了让优化器更好的处理指令,以便以最优的路径,最少的耗时返回我们想要的结果。
  • Optimizer

    • 查询优化器

      • 对语法分析树的形态进行修改,把语法分析树变为查询树。

      • 逻辑优化

        • 逻辑优化阶段主要解决的问题是: 如何找出SQL语句等价的变换形式,使得SQL执行更高效。
      • 物理优化

        • 查询优化器在物理优化阶段,主要解决的问题:
          • 从可选的单表扫描方式中,挑选什么样的单表扫描方式是最优的?
          • 对于两个表连接时,如何选择是最优的?
          • 对多个表连接,连接顺序有多种组合,是否要对每种组合都探索?如果不全部探索,怎么找到最优的一种组合?
        • 目前数据库的查询优化器通常融合这两种方式。
  • Cache Buffer

    • 缓存区
      • 将sql 文本及缓存结果,用KV形式保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要在再去解析、优化、执行sql。
      • 具体的命中条件, 工作流程, 缓存失败, 缓存内存管理, 缓存的使用时机, 缓存参数, 减少内存碎片策略等暂不展开。
  • Pluggable Storage Engines

    • 可植入的存储引擎
      • 是MySql中具体的与文件打交道的子系统。
      • 随着MyISAM在mysql5.5后被废弃, 日常开发常用的也就是InnoDB了。
  • File System

    • 文件系统
      • NTFS(New Technology File System):
      • NFS(Network File System):
        • 网络文件系统, 允许网络中的计算机之间通过TCP/IP 网络共享资源。
      • SAN(Storage Area Network):
        • 存储区域网络, 建立专用于存储的区域网络,以达到存储和主机的物理分离。
        • 主要面向企业级存储。
      • NAS(Network Attached Storage):
        • 网络附加存储, 可以简单理解为便捷的局域网存储装置, 在linux系统中可以通过NFS协议挂载NAS存储。
        • NAS相对于SAN拥有自己的操作系统, 可以与各个系统更好的兼容, 且更加灵活。
  • Files & Logs

    • 文件及日志
      • InnoDB中与数据持久性, 一致性相关的日志:
        • Bin Log
          • 是mysql服务层产生的日志,常用来进行数据恢复、数据库复制,常见的mysql主从架构,就是采用slave同步master的binlog实现的
        • Redo Log
          • 记录了数据操作在物理层面的修改
          • mysql中使用了大量缓存,修改操作时会直接修改内存,而不是立刻修改磁盘
          • 事务进行中时会不断的产生redo log,在事务提交时进行一次flush操作,保存到磁盘中。
          • 当数据库或主机失效重启时,会根据redo log进行数据的恢复,如果redo log中有事务提交,则进行事务提交修改数据。
        • Undo Log
          • 进行数据修改时会记录undo log, 用于数据的撤回操作。
          • 比如,插入对应删除,修改对应修改为原来的数据,通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC。

事务隔离级别

  • ACID就不说了, 老生常谈。

  • Read Uncommitted

    • 读未提交, 可以读取尚未提交的数据。
    • 缺点: 会产生脏读, 幻读, 不可重复读。
  • Read Committed

    • 读已提交(大多数数据库默认事务隔离级别, MySQL不是)
    • 优点: 避免了脏读
    • 缺点: 可能会造成不可重复读
  • Repeatable Read

    • 可重复读(MySQL 默认事务隔离级别)
    • 优点: 避免了不可重复读
    • 缺点: 可能出现幻读
  • Serializable

    • 序列化, 最高的事务隔离级别

    • 优点: 避免了脏读, 幻读, 不可重复读

    • 缺点: 代价高, 性能很低

    • 很少使用

锁机制

  • 读锁
    • 也称共享锁, 若事务I对数据对象A加上读锁, 则事务T可以读A但不能修改A。
    • 其他事务只能再对A加读锁, 而不能加写锁, 直到I释放A上的读锁。
    • 它保证了其他事务可以读A, 但是在I释放A上的S锁之前不能对A做任何修改。
  • 写锁
    • 又称排他锁, 若事务I对数据对象加上写锁, 事务I可以读A也可以修改A。
    • 其他事务不能再对A加任何锁, 直到I释放A上的锁。
    • 这保证了其他事务在I释放A上的锁之前不能再读取和修改A
  • 表锁
    • 操作对象是数据表。
    • MySQL大多数锁策略都支持表锁,是系统开销最低但并发性最低的一个锁策略。
  • 行级锁
    • 操作对象是数据表中的一行。
    • MVCC较多使用该锁。
    • 对系统开销较大, 但处理高并发较好。

重要字段

  • data_trx_id
    • 用来标识最近一次对本行记录做修改(insert|update)的事务的标识符, 即最后一次修改(insert|update)本行记录的事务id。
    • DB_TRX_ID记录了行的创建的时间,删除的时间在每个事件发生的时候,每行存储版本号,而不是存储事件实际发生的时间
    • 每次事务的开始此版本号都会增加。
    • 自记录时间开始,每个事物都会保存记录的系统版本号。
    • 依照事物的版本来检查每行的版本号。
  • data_poll_ptr
    • 指写入回滚段(rollback segment)的 undo log record (撤销日志记录记录)。如果一行记录被更新, 则 undo log record 包含 '重建该行记录被更新之前内容' 所必须的信息。

“DB_TRX_ID”的图片搜索结果

MVCC实现

  • 基本原理
    • MVCC通过在每行纪录后面保存两个隐藏的列来实现的。
      • 一个保存了行的创建时间[实际存储的是版本号]
      • 一个报存了行的过期时间(或删除时间)[实际存储的是版本号]
    • 每开始一个新的事务, 系统版本号都会自动递增
    • 事务开始时刻的系统版本号会作为事务的版本号, 用来与查询到的每行记录的版本号进行比较。
  • 在RR(Repeatable Read) 隔离级别下, MVCC具体操作如下:
    • select
      • InnoDB会根据以下两个条件检查每行记录:
        • InnoDB只查找版本早于当前事务版本的数据行。这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
        • 行的删除版本,要么未定义,要么大于当前事务版本号。这样可以确保事务读取到的行,在事务开始之前未被删除
    • insert
      • InnoDB为插入的每一行保存当前系统版本号作为行版本号。
    • delete
      • InnoDB为删除的每一行保存当前系统版本号作为行删除标识。
    • update
      • InnoDB为插入一行新纪录,保存当前系统版本号作为行版本号。
      • 同时,保存当前系统版本号到原来的行作为行删除标识。
  • 优点
    • 保存这两个额外系统版本号,使大多数读操作都可以不用加锁
    • 这样设计使得读数据操作很简单,性能很好
  • 缺点
    • 每行纪录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作
原文地址:https://www.cnblogs.com/ronnieyuan/p/12203052.html