目录
逻辑存储结构
Innodb引擎内存结构介绍
Innodb引擎磁盘结构介绍
内存和磁盘交互
MVCC(多版本并发控制)原理
预备知识
mvcc基本概念
mvcc的具体实现
总的来说mvcc原理:
逻辑存储结构
Innodb引擎内存结构介绍
Buffer Pool(缓冲池)
缓冲池是内存的一个区域,可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池的数据(若缓冲池内部没有数据,再从磁盘加载到内存),然后以一定频率刷新到磁盘,从而减少磁盘io,加快处理速度,缓冲池管理的单位是页,底层通过链表管理页,页可以分为:free page,clean page,dirty page(缓冲池数据改了,但磁盘还未刷新(磁盘中的数据没有改变)--脏页)。
Change Buffer (更改缓冲区)
mysql8.0之后将insert buffer更改为change buffer
针对的是非唯一二级索引页放在这个区管理,执行DML语句时,如果数据没有在缓冲池中,那么不会直接操作磁盘,而会将数据变更存放在 Change Buffer 中,当数据被用户读取了才将数据回复到缓冲池中,再刷新磁盘
Change Buffer 的意义是 如果我们先将 Change Buffer 的数据合并到缓冲池中,再将缓冲池中数据刷新到磁盘,这样的话如果用户多次执行DML,且每次插入的位置随机,把多个DML语句的执行结果先放在一个区域而不是执行一条刷新一次磁盘,能节省大量磁盘io。
Adaptive Hash Index (自适应哈希索引)
innodb默认支持的是B+树索引,默认不支持hash索引,hash索引一般匹配一次(缺点:不适应范围查询,只能等值查询),B+树索引一般匹配两三次,自适应hash系统默认开启的,不用手动
通过查询系统变量“%hash_index%”可以看到
Log Buffer(日志缓冲区)
日志缓冲区用来保存要写入到磁盘的数据的日志,日志缓冲区会定期刷新到磁盘中,如果需要操作失误,增加日志缓冲区大小可以节省磁盘i/o
Innodb引擎磁盘结构介绍
System Tablespace(系统表空间)
File-Per-Table tablespaces(单表的表文件空间)
每个表会对应一个.ibd,.ibd是表空间文件,存放表的数据和索引,,通用表空间general tablespaces,
General Tablespaces(总体的表文件空间)
创建表空间语句:create tablespaces 表空间名 add datafile ‘表名.ibd’ engine=innodb
建表时要关联指定的表空间:create table 表名(字段,字段类型)engine=innodb tablespaces 表空间名
Undo Tablespaces(撤销的表文件空间)
Mysql实例在初始化时自动创建两个默认的undo表空间,用于存储undo log日志,在MySQL5.6之前所有的undo log全部存储在系统表空间中(ibdata1);但是从5.6开始也可以使用独立表空间来存储undo log。
Temporary Tablespaces(临时的表文件空间):存储用户临时创建的临时表数据
Doublewrite Buffer Files(双写缓冲区),innodb引擎将数据也从缓冲池刷新到磁盘前,会先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据
Redo Log(重做日志):用来实现事务的持久性,这个区域由日志缓冲和重做日志文件组成,前者在内存中,后者在磁盘中,当事务提交之后把所有信息都会保存到这个日志中,用于如果在刷新脏页到磁盘中发生错误时,进行数据恢复,,每隔一段时间系统会清理redo log文件,
虽然也可以直接将内存中脏页的数据刷新到磁盘中,但存在严重的性能问题,因为是实时刷新的,而如果先保存日志,让redo log通过顺序磁盘刷新到磁盘,那么不会影响性能。
,查看innodb引擎状态:show engine innodb status
内存和磁盘交互
磁盘与内存间会通过多个线程交互
如何交互?原理?
后台线程:实现内存和磁盘间的交流,后台线程
Master Thread:核心后台线程,负责将内存中缓冲池的数据异步刷新到磁盘中,保证数据的一致性,还包括脏页的刷新,合并插入缓冲,undo页的回收
IO Thread:在Innodb存储引擎中使用了大量的AIO(Async IO异步io)来处理IO请求,这样就可以极大地提高数据库的性能,而IO线程主要是负责IO请求的回调
Purge Thread:事务提交后就持久化存储了,可能不需要undo log了,因此需要purge线程回收undo log
Page Cleaner Thread:协助Master Thread刷新脏页数据到磁盘的线程,可以减轻Master Thread的压力,减少阻塞,page cleanner thread 是唯一能够在 LRU List(块缓冲区高速缓存在内存的缓冲区中) 中进行脏页刷新并释放出新的 free page 的线程
MVCC(多版本并发控制)原理
预备知识
mvcc保证的是事务的隔离性,在前面的redo log和undo log保证事务的原子性,一致性,持久性undo log在前面内存的Undo Tablespaces中,它的作用是记录数据被修改前的信息,作用包含两个:提供回滚和MVCC,undo log的销毁:undo log在事务执行时产生,在事务提交后并不会马上销毁,因为这些undo log可能在不同客户端开启事务时需要用到;
mvcc基本概念
当前读的概念:
在innodb中,客户端我们默认的隔离级别是RR是可重复读,因此就算一个事务提交后另一个事务也查询不到前者事务更新的的数据,后者事务只有通过加共享锁查询才能读取到,
原因是RR隔离级别下,读取的是第一次执行查询语句生成快照的信息,下一次执行查询语句读取的是上一个快照,因此本质读的信息都是相同的。
演示:
快照读概念:
简单的不加锁的select是快照读,快照读记录的是可见数据版本,有可能是历史版本而不是最新的,不加锁不存在阻塞问题
mvcc的具体实现
需要用到数据库的3个隐式字段,undo log 和readview
3个隐式字段
分别是DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID
测试这三个东西是否存在于数据库?1.cd var/lib/mysql ;2. cd 数据库名; 可以看到很多表空间文件.ibd 3. ibd2sdi 表名.ibd ;这条语句是专门来查看ibd文件的
undo log版本链
展示的当前事务是事务3,执行事务时候当前DB_TRX_ID=3,DB_ROLL_PTR指向上一条记录的地址
readview:
一次快照读生成一次readview,包含4个核心字段:m_ids,min_trx_id,max_trx_id,
creator_trx_id
版本链访问规则:规范了事务查询时读取到的到底是哪个历史版本的数据,注意在不同隔离级别,生成快照图的时机也是不同的,RC级别commit一次事务生成一个快照,RR级别只在事务第一次执行时生成快照,后面的事务都会读取的时第一次事务生成的快照
RC级别下的事务读取原理:
举例:
事务5查询id=30的记录读取到的是id=2的事务;
之后的事务5查询id=30的记录读取到的是id=3的事务,因为此时,的creator_trx_id=5,而DB_TRX_ID=3<5,满足第二条规则。(很容易理解因为我们注意到事务5在查询时其实其他事务也在操作)
RR级别下事务读取原理:当前事务读取的都是第一次事务生成的快照,我理解的是无论除第一次事务外后面执行多少次事务读的都是最早的历史记录
总的来说mvcc原理:
三大组件各自负责的内容