【Mysql技术内幕InnoDB存储引擎】读书笔记
一、存储引擎
1、InnoDB引擎
设计目标是面向在线事务(OLTP)处理的应用。
支持事务、行级锁、通过多版本并发控制(MVCC)支持高并发、提供一致性非锁定读、next-key locking避免幻读、主键聚集索引
2、MyISAM引擎
设计目标是面向OLAP应用。
不支持事务、不支持行锁、表锁设计、支持全文索引
3、其他存储引擎
略
二、InnoDB体系结构
1、线程模型
InnoDB存储引擎是多线程模型,后台有多个不同的线程,用于处理不同的任务。
- Master Thread:核心线程,将缓冲池中的数据异步刷新到磁盘
- IO Thread:负责io请求的回调处理
- Purge Thread:负责undo页的回收
- Page Cleaner Thread:负责脏页的刷新
1.1、Master Thread
内部由多个循环组成。包括主循环(loop),后台循环(background loop)
主循环每隔一秒的操作
- 把日志缓冲刷新到磁盘,即使这个事务还没有提交。很好的解释了再大的事务提交时间也很短
- 合并插入缓冲
- 至多刷新n(可配置,自动调整,1.2版本之后)个脏页到磁盘
- 没有用户活动,切换到background loop
主循环每隔10秒的操作
- 合并最多5个插入缓冲
- 缓冲日志刷新到磁盘
- 删除无用的undo页
- 刷新脏页到磁盘(超过70%,刷新100页,没超过70%,刷新10页)
2、内存模型
2.1、缓冲池
InnoDB是基于磁盘的存储系统,为了弥补cpu和磁盘性能的差距,将从磁盘读出的数据保存在内存中,下次读取先从缓冲池中读取。有数据更新也先更新缓冲池的数据,通过checkpoint机制写回磁盘。缓冲池中包括索引页、数据页、undo页、插入缓存、锁信息等
2.2、缓冲池管理(LRU List)
最近做少使用算法,最频繁使用的页在List前端,最少使用的页在List末尾。当缓冲池容量不足容纳新数据时,先从尾部释放数据页。新数据插入在List的midpoint(List的5/8,对朴素LRU的优化,朴素LRU插入List头部。避免大量一次性查询把频繁使用的页刷出缓冲池)
2.3、脏页管理(Flush List)
当数据被更新,缓冲池中的数据首先被更新,修改之后的页称为脏页。脏页会保存到Flush List中,通过checkpoint机制把脏页数据写回磁盘
2.4、重做日志(redo log)缓冲
首先把重做日志信息存入缓冲区,然后按照一定频率同步到重做日志文件中。以下三种情况都会触发重做日志缓存同步到重做日志文件:
- Master Thread 每隔一秒刷新
- 每个事务提交时
- 重做日志缓冲池容量达到阈值,一般是1/2
2.5、check point技术
为了防止宕机导致事务未提交信息丢失,在事务提交时,先把数据保存到重做日志(redo log)中,再修改页。保证了持久性(D)
发生宕机,重启之后自动从重做日志中恢复数据。
但是这里有以下问题:
- 重做日志过大,宕机重启恢复数据太慢
- 重做日志不能无限扩容,需要循环利用
- 重做日志不可用怎么办
check point就是为了解决这些问题:
- 缩短数据库恢复时间
- 重做日志不可用,刷新脏页
- 缓冲池不够用,将脏页刷新到磁盘
check point触发时机:
- Master Thread check point。每隔一秒触发一次
- LRU List check point。保证LRU List中有100个空闲页,如果清理的页中有脏页,触发check point 强制刷新脏页数据到磁盘
- Dirty Page too mush check point。脏页太多,超过阈值,触发check point 强制刷新脏页数据到磁盘
3、关键特性
3.1、插入缓存
(1)为什么需要插入缓存?
我们知道索引分为聚集索引和非聚集索引。
聚集索引一般是自增的唯一id,页中的数据记录按顺序存放,写入的时候不需要随机读取其他页中的数据,写入速度很快(如果用UUID作为主键,写入速度会很慢,每次写入都需要随机读)
实际应用中,一张表往往还有非聚集索引的存在。非聚集索引叶子节点的插入不是顺序的,需要离散的访问非聚集索引页,随机读取导致了插入数据的性能下降。插入缓存就是为了优化这种场景下的插入速度
(2)什么场景会触发插入缓存?
- 索引是辅助索引
- 索引不是唯一索引
对于非聚集索引的插入,会先判断非聚集索引页是否在缓冲池中,如果在缓冲池中,直接插入索引页,如果没在,先放入到insert buffer对象中,然后再以一定的频率把insert buffer中的数据和非聚集索引的叶子节点进行数据合并
(3)实现原理
insert buffer 的数据结构也是B+树,有记录要插入的时候,会对记录进行封装,按照记录的插入顺序进行编号,是顺序写入
3.2、两次写
(1)为什么需要插入两次写?
如果InnoDB正在写入某个页的数据到磁盘,正好写了一部分的时候宕机了。这种情况称为部分写失效,会导致数据丢失
(2)实现原理
double write由两部分组成。一部分是double write缓冲,一部分是物理磁盘连续共享空间。在刷新脏页数据的时候,先复制一份脏页数据到两次写缓存中,在顺序写入共享磁盘中(因为是顺序写性能影响不大)。最后写入数据存储磁盘中(离散写)
3.3、自适应hash索引优化
hash是非常快的查询方式,时间负责度为O(1)。而B+树的查找次数取决于树的高度。
如果一个页被频繁的访问,而且访问模式也相同(联合索引使用最左原则)。会自动针对这页数据根据缓冲池中的索引建立Hash索引提高查询速度
3.4、异步IO
可以在发出一个IO请求后,在发出另外的IO请求,没必要等待上一次的IO请求处理完成。把全部IO请求都发出,等待所有IO操作的完成,这就是AIO(Aysnc IO)
三、文件
MySQL据库和InnoDB存储引擎有很多类型的文件,每种文件用处不同。主要有参数文件、sokcet文件、pid文件、日志文件、表结构文件、存储引擎文件
1、日志文件
- 错误日志:记录启动运行以及关闭遇到的错误信息
- 查询日志:记录所有的查询记录
- 二进制文件(binlog):记录所有的数据更改记录。用于数据恢复和数据复制。事务中未提交的二进制日志会存放到缓冲中,等事务提交时直接将缓冲中的日志同步到二进制文件中。通过配置可以指定写缓冲多少次之后同步到磁盘,如果值设置大于1,当发生宕机时可能会丢失数据
- 慢查询日志:查询时间超过指定阈值的记录
2、InnoDB存储引擎文件
- 表空间文件:存储数据
- 重做日志文件:存储事务日志
四、表
1、索引组织表
InnoDB中,表数据都是按照主键顺序组织存放的。每张表都有主键,如果没有显示的定义主键,会把唯一索引作为主键。如果唯一索引也没有,会自动创建6字节大小的指针作为主键
2、存储结构
所有数据都存放在表空间中,表空间又由段、区、页组成
- 段:表空间由各个段组成。段的管理由引擎自身完成
- 区:每个区大小为1M,由连续页组成
- 页:磁盘管理的最小单位,默认每个页大小16k
- 行:数据是按行进行存放的,一个页最多存放16k/2-200=7992行
五、索引
数据库的索引结构是B+树,高度一般在2-4层,一次查找只需要2-4次的io。索引分为聚集索引和非聚集索引
1、聚集索引
按照每张表的主键构建的B+树,叶子节点中存储着整张表的行记录数据,每个叶子节点通过双向链表进行连接。因为实际的数据页只能按照一个聚集索引进行排列,每张表只能拥有一个聚集索引
聚集索引对于主键的范围查找和排序查找速度非常快。
2、非聚集索引(辅助索引)
叶子节点不包含行记录的全部数据,叶子节点只存储了键值和指向聚集索引的书签
3、索引创建和删除
3.1、Online Scheme Change(OSC)
在线架构改变,通过php脚本实现,在索引的创建或删除过程中,可以有读写事务对表进行操作。过程如下:
- 创建和原表结构一样的新表
- 对新表进行alter table操作
- 创建临时表
- 对原表添加触发器,把新产生的数据变化同步到临时表
- 把原表的数据同步到新表
- 将临时表的数据同步到新表
- 对新表创建辅助索引
- 再次回放临时表的数据到新表
- 新表和旧表交换名字rename
3.2、mysql5.6开始支持online DDL
通过新的alter语法,可以选择索引的创建方式
4、什么样的数据适合创建辅助索引?
Cardinality表示索引中唯一值的数据的估计值(不是实时更新,使用采样法延迟更新),应尽可能接近表中数据总行数。
5、联合索引
联合索引也是一棵B+树,不同的是索引键值的数量大于等于2。联合索引的第二个好处是已经对第二个键值做了排序处理,减少了一次额外的排序操作
六、锁
1、MyISAM引擎
MyISAM引擎的锁是表锁设计,并发情况下读没有问题,但是写的性能会比较低
2、InnoDB引擎
2.1、锁的类型
- 共享锁(S Lock)
- 排它锁(X Lock)
2.2、一致性非锁定读
实现原理是通过MVCC机制实现,如果读取的行正处于update或delete中,读操作不会去等待行上X锁的释放,而是去读取行的快照数据。
一致性非锁定读可以极大的提高并发性能
不同的事务隔离级别,读取的快照版本是有差别的
- 读已提交隔离级别,总是读取最新的快照版本。可能会产生幻读
- 可重复读隔离级别,总是读取事务开始后第一次读取的快照版本。可以避免幻读的产生
2.3、一致性锁定读
默认配置下,采用可重复读的隔离级别,读取数据采取的是一致性非锁定读。
但是某些场景下需要对读取操作加锁来保证严格的数据一致性,这时候可以显式的对读取的记录进行加锁:
- select *** for update(对读取记录加X锁)
- select *** lock in share model(对读取记录加S锁)
2.4、锁的算法
- record lock:单个记录的锁。
- gap lock:间隙锁,锁定一个范围,不包括记录本身
- next-key lock:gap lock+record lock
默认隔离级别(可重复读)下,默认加的是next-key lock(为了解决幻读问题),当索引中含有唯一属性时,会降级为record lock。
在读已提交隔离级别下,加的是record lock
举个例子:
现在表z,有a,b两列,a是主键索引,b建立辅助索引。现在记录如下:(1,1)(3,1)(5,3)(7,6)(10,8)
select * from z where b=3 for update
因为锁是通过对索引加锁实现的。所以这里需要对主键索引和辅助索引加锁,主键索引加的锁是record lock,辅助索引加的锁是next-key lock,锁定范围是(1,3)、3、(3,6)
【Mysql技术内幕InnoDB存储引擎】读书笔记的更多相关文章
- mysql技术内幕InnoDB存储引擎-阅读笔记
mysql技术内幕InnoDB存储引擎这本书断断续续看了近10天左右,应该说作者有比较丰富的开发水平,在源码级别上分析的比较透彻.如果结合高可用mysql和高性能mysql来看或许效果会更好,可惜书太 ...
- 《mysql技术内幕 InnoDB存储引擎(第二版)》阅读笔记
一.mysql架构 mysql是一个单进程多线程架构的数据库. 二.存储引擎 InnoDB: 支持事务 行锁 读操作无锁 4种隔离级别,默认为repeatable 自适应hash索引 每张表的存储都是 ...
- Mysql技术内幕——InnoDB存储引擎
Mysql技术内幕——InnoDB存储引擎 http://jingyan.baidu.com/article/fedf07377c493f35ac89770c.html 一.mysql体系结构和存储引 ...
- MySQL技术内幕InnoDB存储引擎(三)——文件相关
构成MySQL数据库和InnoDB存储引擎表的文件类型有: 参数文件:MySQL实例运行时需要的参数就是存储在这里. 日志文件:用来记录MySQL实例对某种条件做出响应时写入的文件. socket文件 ...
- 《MySQL技术内幕 InnoDB存储引擎 》学习笔记
第1章 MySQL体系结构和存储引擎 1.3 MySQL存储引擎 数据库和文件系统最大的区别在于:数据库是支持事务的 InnoDB存储引擎: MySQL5.5.8之后默认的存储引擎,主要面向OLTP ...
- (转)Mysql技术内幕InnoDB存储引擎-表&索引算法和锁
表 原文:http://yingminxing.com/mysql%E6%8A%80%E6%9C%AF%E5%86%85%E5%B9%95innodb%E5%AD%98%E5%82%A8%E5%BC% ...
- MySQL技术内幕InnoDB存储引擎(表&索引算法和锁)
表 4.1.innodb存储引擎表类型 innodb表类似oracle的IOT表(索引聚集表-indexorganized table),在innodb表中每张表都会有一个主键,如果在创建表时没有显示 ...
- MySQL技术内幕InnoDB存储引擎(七)——事务
什么是数据库的事务? 事务是访问并更新数据库中各种数据的一个程序执行单元.事务也是数据库区别于文件系统的一个重要特性. 事务需要满足的特性 1.原子性 原子性就是指数据库中的一个完整的事务是不可分割的 ...
- MySQL技术内幕InnoDB存储引擎(二)——InnoDB存储引擎
1.概述 是一个高性能.高可用.高扩展的存储引擎. 2.InnoDB体系架构 InnoDB存储引擎主要由内存池和后台线程构成. 其中,内存池由许多个内存块组成,作用如下: 维护所有进程和线程需要访问的 ...
随机推荐
- 201871010117-石欣钰《面向对象程序设计(Java)》第四周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- PDB files out of the debugger
我想我不需要强调在调试时拥有有效的PDB文件有多重要.通常,PDB文件是由调试器静默加载的,并且您很高兴在modules窗口中看到解析的所有符号.不幸的是,您还可能遇到调试器找不到匹配符号的情况.其原 ...
- 调用 redis 原子命令,保证多线程安全 的incr命令问题
redis本身就是事件驱动模型,你incr递增好了,然后get获取判断一下是否超过次数 参考:如何用java实现redis incr的高并发计数器
- ValueError: Graph disconnected: cannot obtain value for tensor Tensor
一般是Input和下面的变量重名了,导致model里面的input变成了第二次出现的Input变量,而不是最开始模型中作为输入的Input变量 改正方法:给第二个变量赋一个新名字即可
- Airtest-UI 自动化集大成者
前言 Airtest是由网易研发的一款基于Python的.跨平台的UI自动化测试框架,基于图像识别原理,适用于游戏和App.该项目目前已在Github上面开源: https://github.com/ ...
- 蚂蚁金服2019实习生面经总结(已拿口头offer)
一面 (37 分钟左右) 一面是上海的小哥打来的,3.12 号中午确认的内推,下午就打来约时间了,也是唯一一个约时间的面试官.约的晚上八点.紧张的一比,人生第一次面试就献给了阿里. 幸运的是一面的小哥 ...
- laravel如何引用外部文件
(1).首先在app\Http\routes.php中定义路由: 1 2 3 Route::get('view','ViewController@view'); Route::get('article ...
- MySQL常见的应用异常记录
>>Error Code: 1045. Access denied for user 'test'@'%' (using password: YES) 使用MySQL的select * i ...
- vue.js与element-ui实现菜单树形结构
由于业务需要,要求实现树形菜单,且菜单数据由后台返回,在网上找了几篇文章,看下来总算有了解决办法.借鉴文章链接在最底部. 场景:根据业务要求,需要实现活动的树形菜单,菜单数据由后台返回,最后的效果图如 ...
- 建造(Builder)模式
建造模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象. 摘自EffectiveJava:当构造方法参数过多时使用建造者模式. 产品的内部表象 ...