网站首页 > 技术文章 正文
一、快照读与当前读
快照读(SnapShot Read) 是一种一致性不加锁的读,是 InnoDB 并发如此之高的核心原因之一。
在 READ COMMITTED 事务隔离级别下,一致性不加锁的读是指,总是读取被锁定行的最新一份快照数据,因此其它事务修改了该行数据,该事务也能读取到,这也贴合了 RC 隔离级别下允许不可重复读的问题;
在 REPEATABLE READ 事务隔离级别下,一致性不加锁的读是指,事务读取到的数据,要么是事务开始前就已经存在的数据,要么是事务自身插入或者修改过的数据。(下面将以此隔离级别说明);
不加锁的简单的 SELECT 都属于快照读,例如:
SELECT * FROM t WHERE id=1;
与快照读相对应的则是当前读(Current Read),当前读就是读取最新数据,而不是历史版本的数据。加锁的 SELECT 就属于当前读,例如:
SELECT * FROM t WHERE id=1 LOCK IN SHARE MODE;
SELECT * FROM t WHERE id=1 FOR UPDATE;
SELECT…FOR UPDATE 对读取的行记录加一个 X 锁,其它事务不能对已锁定的行加上任何锁。
SELECT…LOCK IN SHARE MODE 对读取的行记录加一个 S 锁,其它事务可以向被锁定的行加 S 锁,但是如果加 X 锁,则会被阻塞。
二、基于快照读的多版本并发控制
多版本并发控制技术的英文全称是:Multiversion Concurrency Control,简称 MVCC,是通过保存数据的历史版本,通过对数据行的多个版本管理来实现数据库的并发控制。这样我们就可以通过比较版本号决定数据是否显示出来,读取数据的时候不需要加锁也可以保证事务的隔离效果(可以理解成乐观锁)。
多版本并发控制(MVCC)只在可重复读(REPEATABLE READ)和提交读(READ COMMITTED)两个隔离级别下工作,其他两个隔离级别都和 MVCC 不兼容,因为未提交读(READ UNCOMMITTED),总是读取最新的数据行,而不是符合当前事务版本的数据行;而可串行化(SERIALIZABLE) 则会对所有读取的行都加锁。
MySQL 的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。不仅是 MySQL,包括 Oracle、PostgreSQL 等其他数据库系统也都实现了 MVCC,但各自的实现机制不尽相同,因为 MVCC 没有一个统一的实现标准,典型的有乐观(optimistic)并发控制和悲观(pessimistic)并发控制。
MVCC 的流程过程非常类似于 SVN 等版本控制系统的流程,或者说 SVN 等版本控制系统就是使用的 MVCC 思想。
三、多版本并发控制解决了哪些问题?
1. 读写之间阻塞的问题
通过 MVCC 可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。
提高并发的演进思路:
1. 普通锁,只能串行执行;
2. 读写锁,可以实现读读并发;
3. 数据多版本并发控制,可以实现读写并发。
2. 降低了死锁的概率
因为 InnoDB 的 MVCC 采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。
3. 解决一致性读的问题
一致性非锁定读也被称为快照读,这也是 InnoDB 存储引擎的默认读取方式,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。
四、InnoDB 的 MVCC 是如何工作的?
1. InnoDB 是如何存储记录的多个版本的?
事务版本号: 每开启一个事务,我们都会从数据库中获得一个事务 ID(也就是事务版本号),这个事务 ID 是自增长的,通过 ID 大小,我们就可以判断事务的时间顺序。
行记录的隐藏列: InnoDB 的叶子段存储了数据页,数据页中保存了行记录,而在行记录中有一些重要的隐藏字段:
- DB_ROW_ID:6-byte,隐藏的行 ID,用来生成默认聚簇索引。如果我们创建数据表的时候没有指定聚簇索引,这时 InnoDB 就会用这个隐藏 ID 来创建聚集索引。采用聚簇索引的方式可以提升数据的查找效率。
- DB_TRX_ID:6-byte,操作这个数据的事务 ID,也就是最后一个对该数据进行插入或更新的事务 ID。(InnoDB 的插入、更新、删除都会更新该事务 ID,同时删除会将一个特殊位标记为已删除)
- DB_ROLL_PTR:7-byte,回滚指针,也就是指向这个记录的 Undo Log 信息。
Undo Log: InnoDB 将行记录快照保存在了 Undo Log 里,我们可以在回滚段中找到它们,如下图所示,回滚指针将数据行的所有快照记录都通过链表的结构串联了起来,每个快照的记录都保存了当时的 db_trx_id,也是那个时间点操作这个数据的事务 ID。这样如果我们想要找历史快照,就可以通过遍历回滚指针的方式进行查找。
InnoDB 存储引擎对于 DELETE 操作,仅仅是将记录的 delete flag 设置为 1 ,记录并没有被物理删除,即记录还是存在于 B+ 树中,这样设计是因为 InnoDB 存储引擎支持 MVCC,所以记录不能在事务提交时立即进行处理,这时其他事务可能在引用此行,那么该条记录什么时候被真正删除呢?这个是由 Purge Thread 线程来处理,Purge Thread 会判断该记录是否不被任何其他事务引用,那么就可以进行真正的 delete 操作。
猜你喜欢
- 2024-11-01 Oracle优化Hints功能并行parallel(二)
- 2024-11-01 PostgreSQL开发与实战(7.3)多版本并发控制3
- 2024-11-01 GitHub大神手打笔记:MySQL的多版本并发控制
- 2024-11-01 并发类的覆盖驱动测试代码生成 植被覆盖类型代码1112指的是
- 2024-11-01 多版本并发控制(MVCC)与一致性读(二)
- 2024-11-01 SQLite学习笔记(二) sql学习笔记
- 2024-11-01 Oracle数据库:揭秘大数据管理神器
- 2024-11-01 java并发编程-学习方法、进程和线程的区别
- 2024-11-01 Java高并发编程详解:深入理解并发核心库,文字可复制,高清PDF
- 2024-11-01 Spark jdbc 的并发的问题 spark jdbc server
你 发表评论:
欢迎- 632℃几个Oracle空值处理函数 oracle处理null值的函数
- 625℃Oracle分析函数之Lag和Lead()使用
- 614℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 608℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 606℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 598℃【数据统计分析】详解Oracle分组函数之CUBE
- 588℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 572℃Oracle有哪些常见的函数? oracle中常用的函数
- 最近发表
-
- oracle 19cOCM认证有哪些内容(oracle认证ocm月薪)
- Oracle新出AI课程认证,转型要持续学习
- oracle 表的查询join顺序,可能会影响查询效率
- Oracle DatabaseAmazon Web Services正式可用,Oracle数据库上云更容易了
- Oracle 19.28 RU 升级最佳实践指南
- 汉得信息:发布EBS系统安装启用JWS的高效解决方案
- 如何主导设计一个亿级高并发系统架构-数据存储架构(三)
- Java 后端开发必看!工厂设计模式轻松拿捏
- ORA-00600 「25027」 「x」报错(抱错孩子电视剧 爸爸是武术 另一个爸爸是画家)
- 新项目终于用上了jdk24(jdk新建项目)
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- 前端获取当前时间 (50)
- Oracle RAC (76)
- oracle恢复 (77)
- oracle 删除表 (52)
- oracle 用户名 (80)
- oracle 工具 (55)
- oracle 内存 (55)
- oracle 导出表 (62)
- oracle约束 (54)
- oracle 中文 (51)
- oracle链接 (54)
- oracle的函数 (58)
- 前端调试 (52)
本文暂时没有评论,来添加一个吧(●'◡'●)