oracle 在上一条数据的基础上递增插入_分布式数据库之MVCC

目录

MVCC如何实现

旧版本数据延迟清除地原因

快照读(一致性读)的用途

MVCC总结

Mysql MVCC实现

Innodb的事务的相关概念

Innodb多版本的实现

Innodb的事务的提交与回滚

Oracle的多版本实现

ITL解释

ITL内容

Oracle数据块的结构

Oracle的多版本实现

旧版本的数据在回滚段中的结构

PostgreSQL MVCC实现

PostgreSQL事务ID

PostgreSQL MVCC实现

比较事务新旧的方法

可见性判断


以下内容来自于唐成老师的公开课内容,感谢老师不吝分享,仅限于学习交流。如有侵权,及时删除。

借助wiki上的解释:

Multiversion concurrency control (MCC or MVCC), is a concurrency control method commonly used by database management systems to provide concurrent access to the database and in programming languages to implement transactional memory.

1a160056dd22a80130e839e85f453b48.png

MVCC如何实现

• 简单说,就是更新数据时,保留原先版本的数据, 即一行数据存在多个版本。

• 实现方法: – 回滚段的实现方法(Oracle、MySQL Innodb的实现方 法) – 在原先的数据文件中的旧版本数据不删除,生成新版 本的数据(PostgreSQL的实现方法)

• 通常与事务的功能集成在一起:

• 但MVCC时事物回滚或提交之后,旧版本的数据 仍然需要保留一段时间,是延迟清除的。

旧版本数据延迟清除的原因

• 就是为了提供快照读(一致性读)的功能

• 对于Read Commited隔离级别:需要保证当开始 执行一个SQL之后,这个SQL是读一个不变的快 照的数据,即使在这个SQL执行过程中有其它的事务提交了,这些提交的数据对于这个SQL也是 看不到了,这样保证了数据的一致性。

• 对于Read Repeatable隔离级别:从这个事务开 始之后,看到的数据就是一个不变的数据,执行 相同的SQL总是可以看到相同的数据。所以叫"可重复读"

快照读(一致性读)的用途

如果没有MVCC的解决方案

c77bacfe56ffb7d0667bb912012a0cef.png

管理者在事务中持有对A的锁,等待获取B的锁,而用户B在事务中持有对B的锁,等待获取A的锁,于是便发生了死锁。

6e0535c9cb12e54378d8c3700c812162.png

MVCC总结

  • 查询和更新、删除、插入操作互相不阻塞

• 当开始一个查询后,读到的数据总是查询 开始时那个时间点的快照

  1. 在查询开始后,发生的变更(即使已提交), 这次查询也是看不到的。
  2. 一个事务无论运行多长时间,看到数据都是相 同的
  3. 不同开始时间的事务中相同的查询,返回的数 据也可能不同

Mysql MVCC实现

Innodb的事务的相关概念

• redo log – 在变更数据之前,把变更先记录到一个文件中, 称为redo log

• undo log – 与redo log相反,undo log是为回滚而用

• rollback segment – 在Innodb中,undo log被划分为多个段,具体 某行的undo log就保存在某个段中,称为回滚 段。

Innodb多版本的实现

事务1:insert t(id, col1,col2,col3,col4) values(23,'a1','b1','c1','d1');

ce995327fbb91d259ccf6f076c090fb3.png

行上有三个隐含字段:分别对应该行的rowid、事务号和回滚指针, id、Col1~Col4是表格列的名字,23、'a1'~'d1'是其对应的数据。

60512b4268d38bbeb383b72b6f7bb7ca.png
d4608e58a48aea07334a62202ee9cd2b.png
  • 多次更新后,回滚指针会把不同版本的记录 串在一起。
  • 在Innodb中存在purge线程,它会查询哪些 比现在最老的活动事务还早的undo log,并 删除它们,从而保证undo log文件不至于无 限增长。

Innodb的事务的提交与回滚

提交与回滚

– 当事务正常提交时,Innodb只需要更改事务状 态为COMMIT即可,不需做其他额外的工作

– Rollback需要根据当前回滚指针从undo log中 找出事务修改前的版本,并恢复

• 如果事务影响的行非常多,回滚则可能会很慢,根 据经验值没提交的事务行数在1000~10000之间, Innodb效率还是非常高的,大量的回滚效能会影响。

• 回滚时,也会产生redo日志 – Innodb的COMMIT效率高,Rollback代价大

Innodb的可见性判断

• InnoDB表会有三个隐藏字段

– 6字节的DB_ROW_ID

– 6字节的DB_TX_ID

• InnoDB内部维护了一个递增的tx id counter,其当 前值可以通过show engine innodb status获得

– 7字节的DB_ROLL_PTR(指向回滚段的地址)

可见性比较的方法:

– 并不是用当前事务ID与表中各个数据行上的事 无ID去比较的

– 在每个事务开始的时候,会将当前系统中的所 有的活跃事务拷贝到一个列表中 (read view), 根据read view最早一个事务ID和最晚的一个事 务ID来做比较的,这样就能确保在当前事务之 前没有提交的所有事务的变更以及后续新启动 的事务的变更,在当前事务中都是看不到的。

– 当然,当前事务自身的变更还是需要看到的。

3ddeeaeaf8298f458191223b200b4249.png

Oracle的多版本实现

• Oracle也是通过回滚段来实现多版本的 – 但Oracle的实现更复杂,更精细一些。

• Oracle中也有事务ID,但不是递增的

– Undo Segment Number + Transaction Table Slot Number + Wrap

• 与innodb不一样的地方:

– 事务信息并不是记录在每个数据行上的,而是 在块头中的ITL槽上,所以相对来说更省空间

ITL解释

• ITL(Interested Transaction List)在Oracle 数据块的头部

– ITL记录在一个数据块中有多条,每一条itl可 以看作是一个记录,每条记录常被称为槽位 (itl slot)

– 一个itl slot只可以记录一个事务的信息,如果 这个事务已经提交或回滚了,那么这个itl的 位置就可以被反复使用。

• 每个数据块上itl槽的多少可以动态创建, 建表时可以指定: – initrans:每个数据块默认ITL槽数目,默认 为2 maxtrans:每个数据块最多的ITL槽数,最 大255

3cc7100552841066193b399adee9c76c.png

ITL内容

119ad6191d919645b2509275577490e8.png

Oracle数据块的结构

3e9683a5e5b1f437bf254fe6cd50955d.png

Oracle的多版本实现

• 由于Oracle中的事务ID不是递增的,为了判 断事务之间的先后关系,需要一个递增序 号,这个序号在Oracle中就叫SCN(当然 SCN还有其它用处)

• SCN(System Change Number)

– 是顺序递增的一个数字,在Oracle 中用来标识 数据库的每一次改动,及其先后顺序。

– SCN是由6字节组成,最大值是0xffff.ffffffff

– 单节点的instance中,SCN值存在SGA区,由 system commit number latch保护。任何进程 要得到当前的SCN值,都要先得到这个latch。

– RAC中是通过排队机制(Enqueue)实现SCN在 各并行节点之间的顺序增长,这里不再赘述。

旧版本的数据在回滚段中的结构

512dc6c141f271770febfe20a5bb25e7.png

PostgreSQL MVCC实现

什么?PostgreSQL没有回滚段!!!

– 是的,没有回滚段。旧数据是放在原有数据文 件中的

– 如果放在原有的数据文件中,旧数据越来越多 怎么办?

• 垃圾回收操作vacuum来做这个事。

• 有自动垃圾回收autovacuum

• 更新操作中新行的物理位置发生了变化, 非更新列的索引是不是也要更新?

– 通常不会,HOT技术。如果原有的数据块之间 有空间,旧行与新行之间会建一个链接,索引 上仍然指向旧的数据行。

• 垃圾回收的代价会不会影响性能?

• 有很多参数控制这个影响:vacuum_cost_delay, vacuum_cost_limit

• 实现方法

– 每行上有xmin和xmax两个系统字段

– 当插入一行数据时,将这行上的xmin设置为当 前的事务id,而xmax设置为0

– 当更新一行时,实际上是插入新行,把旧行上 的xmax设置为当前事务id,新插入行的xmin设 置为当前事务id,新行的xmax设置为0

– 当删除一行时,把当前行的xmax设置为当前事 务id

– 当读到一行时,到commitlog中查询xmin和 xmax对应的事务状态是否是已提交还是回滚了, 就能判断出此行对当前行是否是可见。

– autovacuum进程会把一些不要的旧行清理掉

PostgreSQL事务ID

• 与innodb类似,是一个递增的数字,常常 被称为xid

– 但是一个无符号的32bit的数字表示

• 如何知道事务是提交了还是回滚了?

– 事务的状态记录一个叫commitlog的位图文件 中,即pg_clog目录下的文件中

– 每个事务的状态用两个bit来表示:

– #define TRANSACTION_STATUS_IN_PROGRESS 0x00

– #define TRANSACTION_STATUS_COMMITTED 0x01

– #define TRANSACTION_STATUS_ABORTED 0x02

– #define TRANSACTION_STATUS_SUB_COMMITTED 0x03

PostgreSQL MVCC实现

• 事务ID到达最大的一个数字后,怎么办?

– 到达最大后,又重新开始,

– 此问题被称之为事务ID回卷问题(Transaction ID Wraparound) • 记录事务的commitlog文件会不会不断的增 大?

比较事务新旧的方法

– 普通事务的比较方法:(int32) (id1 - id2) < 0

– 表达式算出来值为真,则id1比id2更旧一些, 为假则id1比id2新 • 例子:id1=4294967294,经过4个事务,id2=5, id1-id2=4294967289,而4294967289因大于2^31, 转成int32后会变成一个负数,表过式为真,所以id1 比id2更旧

– BootstrapXID比所有其它事务都旧,包括 FrozenXID

– FrozenXID比普通事务旧

可见性判断

• 与innodb一样,事务开始时,会把当前活 月的事务ID记录到一个列表中,这称之为 快照

• 系统先通过判断t_xmin是否在全局活跃事务 列表中、是否在事务快照活跃事务列表中、 根据事务提交日志判断事务是提交还是回 滚了等来判断t_xmin事务是否在事务开始时 已经提交

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值