介绍

课程官网:6.5830/6.5831: Lecture Notes and Assignments (mit.edu)
项目仓库:MIT-DB-Class/simple-db-hw-2021 (github.com)

理论

Lecture5

Buffer Pool Optimizations

Lecture7

Basic Join Summary

上面的图列举了将两个表进行join操作时,CPU和I/O的开销。{R}指表R中行数,|R|指表R在磁盘上存储的页面数,如果每页存B条记录,则|R|={R}/B

External Join Summary

Lecture8

Query Optimization Objective

谓词下推(Predicate Pushdown):将尽可能多的判断更贴近数据源,以使查询时能跳过无关的数据。用在SQL优化上来说,就是先过滤再做聚合**等操作。

Lecture10

Transaction:

  • Begin:在开始修改数据库的SQL语句之后
  • Commit:使事务生效,即持久化到磁盘中,对其他事务可见。即使数据库崩溃了也同样有效。
  • Abort:撤销事务的所有操作。

View Serializability(视图可串行化)
一个在调度S中特定的指令顺序被认为是等价于串行顺序S’当仅当:

  • 在 S 中读取的每个值都与在 S’ 中读取的相同。
  • 每个对象的最终写入都由 S 和 S’ 中的同一个事务 T 完成。

以较为简略的表达方式,所有在S中的事务“观察”到的数值与在S’中的相同,并且事务运行后的最终状态是相同的。


左边的调度次序S,和右边的串行化先T1后T2的等价。

  1. 先T1后T2,那么最后写入的B是由T2执行的,不符合”每个对象的最终写入都由 S 和 S’ 中的同一个事务 T 完成。“
  2. 先T2后T1,那么T1读取到的A是被T2更新之后的,不符合”在 S 中读取的每个值都与在 S’ 中读取的相同。“

Conflict Serializability(冲突可串行化)
如果可以通过交换不冲突的操作得出串行调度,那么该调度就是可冲突串行化的。
换言之:
对于所有冲突操作对,(o1 in T1,o2 in T2)要么o1恒先于o2,要么o2恒先于o1。

判断方法:优先图无环

是冲突可串行化的一定是视图可串行化的,反之不一定。

实现冲突可串行化
两段锁

  • 共享锁S 排他锁X
  • 实现了冲突可串行化
  • 访问对象需要获得共享锁,写入对象需要获得排他锁(或将共享锁升级为排他锁)
  • 一个事务不可以释放任何锁,直到它获取了所有锁。
  • 只有在最后一个锁被获取且对该对象的操作完成后,才释放锁。先获取后释放。(也就是只能在扩张阶段获取锁,不可释放锁;在收缩阶段只能释放锁,不可以获取锁)如下图

二段锁问题:
Deadlocks
相互等待获取锁,而导致谁都无法释放锁。

Cascading Aborts(级联终止)

Strict Two-Phase Locking (Strict 2PL):

  • 可以避免级联终止通过持有排他锁直到事务结束
  • 保证事务永远不会读取其他事务为提交的数据
  • 可以解决”脏读“问题
    不同:
  • 在对于某个对象操作结束和已经获取最新的锁后,仅释放共享锁
  • 只有当事务提交后,才释放排他锁

Rigorous Two-Phase Locking Protocol:

  • 仅当事务提交后,才释放所有的锁。
  • 提交顺序与串行顺序一致

隔离等级


再探幻读!什么是幻读?为什么会产生幻读,MySQL中是怎么解决幻读的?-CSDN博客

OCC(Optimistic concurrency control)
假定事务在访问数据时,不发生冲突。只在验证阶段,检测冲突,冲突则abort。
三个阶段:Read Validation Wrte
Forward Validation(前馈验证)。如果事务Ti的验证时刻<事务Tj的验证时刻

  • 事务Ti在事务Tj开始前就已经完成。意味着无相互影响
  • 事务Ti在事务Tj开始Write阶段前完成,并且WriteSet(Ti) ∩ ReadSet(Tj) = Ø。也就是Ti没有写入任何被Tj读取的对象。
  • 事务Ti完成了Read阶段在事务Tj完成其Read阶段之前,并且WriteSet(Ti) ∩ ReadSet(Tj) = ØWriteSet(Ti) ∩ WriteSet(Tj) = Ø。也就是事务Ti没有写入任何被Tj读取或写入的对象。

意向锁
IS:意向共享锁:表明事务在其子节点(表/页/记录)设置共享锁
IX:意向排他锁:表明事务在其子节点(表/页/记录)设置互斥锁

获取和释放锁的顺序:

  • 自上而下获取锁,先获取祖先节点的意向锁,再获取共享/排他锁
  • 自下而上释放锁。

MVCC(Multi-Version Concurrency Control)
【MySQL笔记】正确的理解MySQL的MVCC及实现原理_mysqlmvcc实现原理-CSDN博客

Snapshot Isolation

  • 当事务启动时,它会记录一个时间戳T。
  • 所有读取均从DB版本为T执行。
  • 所有的写都在各自的缓冲区进行
  • 当事务提交时,DBMS检查冲突
    废弃时间戳为T1的TA1,如果存在TA2
    • TA2在T1之后,但在TA1之前提交
    • TA1和TA2更新了相同的对象

      因为T2在操作W(X:=v3)之前,T3已经提交了对X的修改,并且该修改位于T2开始之后,T2提交之前。
      快照隔离不能防止写-读冲突,因为它不检查是否读取从另一个事务写入的内容

Lecture13

数据库故障类型

  • 事务故障:由于某些内部错误(如违反完整性约束条件)导致事务无法完成;内部状态错误(死锁)
  • 系统故障:软件故障(OS或DBMS,除零错误等);主机异常奔溃
  • 存储介质故障:磁盘损坏。这个类型是无法恢复的,没有DBMS可以从该类异常中恢复。

易失性内存主要充当缓冲区,用户与数据库的交互全都是在内存中完成,然后写回磁盘的

  • 首先将目标记录复制到内存中
  • 在内存中执行写入操作
  • 将脏数据写回磁盘

数据库崩溃后

  • 内存会被重置
  • 磁盘是持久化的

在崩溃后,Recovery机制需要保证:

  • 原子性:部分完成的事务需要回滚
  • 持久性:已提交的事务需要在稳定的存储中,如磁盘

使数据库进入事务一致状态,已提交的事务得到完全反映,未提交的事务被完全撤销。


UNDO:消除不完整或终止的事务对数据库的影响。某些事务可能已将其未提交状态写入表中–需要撤销
REDO:重新执行已提交的事务对数据库的影响。某些事务在提交之前可能还没有刷新所有的状态到他们的表中–需要重做

Steal Policy:DBMS是否允许未提交的事务覆盖磁盘上最新已提交的数据。
STEAL:允许,意味着磁盘上可能有uncommitted的数据,需要通过undo日志支持回滚。(原子性)
NO-STEAL:不允许

Force Policy:DBMS是否要求事务提交时,必须将所有更新刷盘。
FORCE:需要
NO-FORCE:不需要。这种情况磁盘上可能还是前镜像状态,需要redo日志来恢复后镜像状态。(持久性)

当代数据库存储引擎大部分都有 undo log 和 redo log,那么它们就是 steal/no-force 策略的数据库

提前写入日志(WAL)原则:在执行实际操作时,先写日志后操作。避免操作失败后,无法通过日志恢复。

Checkpoint
数据库的日志会无限增长,导致crash后,重新执行日志来恢复数据的时间越来越长。checkpoint的机制就是用来解决这个问题的。它类似于快照,创建一个checkpoint之后,之前已提交的事务的日志则不必重新执行。

  • 暂停所有查询
  • 写日志记录到磁盘中
  • 写缓冲池中的脏页到磁盘中
  • 添加Checkpoint的日志条目到磁盘中
  • 重新开始查询

ARIES

  • Write-Ahead Logging:写前日志+(STEAL+NO-FORCE policies)
  • 使用Redo重复历史
  • 记录Undo过程中的更改

Fuzzy Checkpoint
图解数据库Aries事务Recovery算法 - 黑客画家的个人空间 - OSCHINA - 中文开源技术交流社区

实验

Lab1

MIT6.830 Lab1

Lab2

MIT6.830 Lab2

Lab3

MIT6.830 Lab3

Lab4

MIT6.830 Lab4

Lab5

MIT6.830 Lab5

Lab6

MIT6.830 Lab6