MySQL学习笔记

事务

AICD

  • Atomicity:原子性
  • Isolation:隔离性
  • Consistency:一致性
  • Durability:持久性

脏读、不可重复读、幻读

  • 脏读:一个事务中读到其他未提交事务修改的数据
  • 不可重复读:在一个事务中,对同一份数据多次读取到的结果不一致
    • 更侧重数据的修改
  • 幻读:在一个事务内,相同的select语句前后执行,得到的数据结果不一致
    • 更侧重数据的insert和delete

事务隔离级别

  • Serializable(顺序读):可避免脏读、不可重复读、幻读
    • 所有语句都会上锁;select也会追加共享锁(lock in share mode)
    • 加上共享锁,允许其他读操作;保存读取数据一致性;如果发生写操作,尝试对数据加独占锁时,则会失败;必须等共享锁释放才可以。
  • Repeatable read(可重复读,默认隔离级别):可避免脏读、不可重复读
    • 消除脏读的原因:数据快照ReadView中记录了所有在途的事务集合,可以屏蔽不可见的事务结果
    • 消除不可重复读的原因:采用快照读;事务开启的时刻,会创建一份数据快照,事务内的所有读请求都基于该快照
      • 会对Select、update、insert、delete加锁
    • 为什么无法解决幻读:
  • Ready committed(读已提交):可避免脏读
    • 消除脏读的原因:数据快照ReadView中记录了所有在途的事务集合,可以屏蔽不可见的事务结果
    • 为什么无法解决不可重复读:采用当前读;事务中每次读请求都会创建一份数据快照,会导致不同阶段看到的在途事务不一致
      • 只会对update、insert、delete加锁;Select语句不加锁,这是产生重复读的根本原因
    • 为什么无法解决幻读:
      • 通过MVCC+行间锁可以解决大部分情况的幻读问题,但无法根除;
  • Ready uncommitted(读未提交):最低隔离级别,任何情况都无法保障
    • 什么锁都不加,没不使用MVCC,所有什么问题都可能发生

RR和RC为什么解决不了幻读、该如何解决:

RR基于临间锁只能解决部分幻读问题;解决不了的幻读场景

  • case1:在事务A的执行期间,事务B执行了insert/delete操作

    • 事务A先select(快照读)
    • 事务B执行insert(快照读不产生临间锁,写操作不受影响)
    • 事务A再执行update(update是当前读,则会刷新快照信息,导致可以看到事务B执行完成后的结果)
    • 事务A再执行select就发生幻读
  • case2:事务A中第一次查询采用快照读,第二次采用当前读

    • 事务A快照读
    • 事务B执行insert(A的快照读不产生临间锁,不阻塞B的写入)
    • 事务A当前读

隔离级别的实现原理

MVCC

基于MVCC产生的数据快照 ReadView,其内部结构如下(2个核心集合)

  • 创建ReadView时刻,当前DB所有在途事务ID集合(开启但未提交)
  • 在途事务集合中最小的事务ID(当事务ID小于这个值,代表事务已提交)
  • roll_pointer,回滚指针,指向undo log,记录在途事务的原始数据,串联回滚指针实现全量的快照数据恢复
  • 预分配给下一个事物的ID(当事务ID大于等于这个事,代表这个事物是后面创建的,即不可见)

如何判断一个事务是否可见:

  • 目标事务ID小于在途事务集合的最小事务ID,代表该事务已提交
  • 目标事务ID大于在途事务集合的最大事务ID,代表事务是后来创建的,即不可见
  • 目标事务ID介于最小值和最大值之间,则需要判断是否在在途事务集合列表
    • 在列表中,说明当前版本创建时,该事务还未提交,所以不可见
    • 不在列表中,说明当前版本创建时,该事务已提交,所以可见

MySQL日志

三个日志文件的区别

bin log

记录的是执行的sql语句;主要用于数据同步 & 恢复

redo log

重做日志,用于保障MySQL事务持久化能力。记录的是修改后的最新数据。

如何保障持久化:在事务提交前,先确保修改后的数据成功写入redolog,在执行事务的commit操作。这样当数据库异常,内存数据无法回刷磁盘时,可以通过redo log实现数据恢复,保证事务结果的一致性

sql修改数据的底层流程

  • 先通过select将数据检索并加载到内容
  • 在内存中更新数据,然后将内存结果回刷到磁盘
    因为InnoDB在磁盘的存储单位是页,如果页内的更新数据量较少,或者同时更新多个页,会产生随机IO问题,影响数据回刷的心梗。所以可以再内存数据修改之后,在同步记录一份redo log;作为一份备份保障。当内存数据正常回刷到磁盘,就用不着redo log,如果内存数据回刷不及时或者内存异常,则基于redo log 恢复

所以redo log文件一般是一个固定大小的文件,可以支持覆盖覆写的;并不是无限大。


undo log

回滚日志;记录数据修改前的日志。记录的是一个相反的命令

e.g. 执行一个insert 语句,则undo log里会对应记录一条delete语句;

执行一个update语句,则undo log里会记录一条update语句,只不过更新结果是SQL执行前的原始值。

undo log的写入在内存数据修改之前

使用场景:

  • 日志回滚
  • MVCC

数据库的索引结构

B树结构的特点

B树的节点包含三个维度的数据

  • 索引键
  • 对应的Value值
  • 子节点的地址索引
    优势
  • 基于索引的点对点查询比较优化;每个节点都包含数据信息
    劣势
  • 因为节点包含了索引+数据;当每行数据量过大时,因为节点大小是固定的,会导致整个B树的高度变高,增大了查询是的比较次数,影响查询性能
  • 不支持基于索引的范围查询

B+树结构的特点

  • 非叶子节点:只存储索引键和子节点的地址信息
  • 叶子节点:存储索引键和数据
  • 叶子节点有有指向下一个节点的索引;底层是一个双向有序链表
    优势
  • 树的高度稳定,磁盘IO次数更少
  • 支持范围查询

InnoDB引擎的索引结构

聚簇索引 即主键索引;InnoDB表的数据本身就是基于聚餐索引建立的一个B+树。其中叶子节点记录每一个行完整的数据。非叶子节点只记录了索引信息

辅助索引,除聚簇索引之外的其他索引。索引结构是基于特定的索引列创建B+树;叶子节点记录对应的主键隐私

所以基于辅助索引的查询,如果只查改列的值,则不需要回表,效果最好。这种方式被称为:覆盖索引

相关推荐
Code哈哈笑21 分钟前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
Python之栈26 分钟前
【无标题】
数据库·python·mysql
亦世凡华、1 小时前
MySQL--》如何在MySQL中打造高效优化索引
数据库·经验分享·mysql·索引·性能分析
QQ同步助手1 小时前
如何正确使用人工智能:开启智慧学习与创新之旅
人工智能·学习·百度
流浪的小新1 小时前
【AI】人工智能、LLM学习资源汇总
人工智能·学习
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
云边有个稻草人2 小时前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
南宫生10 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__10 小时前
Web APIs学习 (操作DOM BOM)
学习
冷眼看人间恩怨10 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget