大纲
一.InnoDB的内存结构
二.InnoDB的存储结构
三.索引优化
四.事务原理
五.锁机制原理和索引原理
一.InnoDB的内存结构
1.Buffer Pool的概念
2.Buffer Pool的Page管理机制
3.Change Buffer的概念和作用
4.Log Buffer的概念和作用
1.Buffer Pool的概念
(1)Buffer Pool基本概念
Buffer Pool是缓冲池的意思。Buffer Pool的作用是缓存表数据与索引数据,减少磁盘IO,提升效率。Buffer Pool由缓存数据页(Page)和对缓存数据页进行描述的控制块(描述数据块)组成。控制块(描述数据块)存储着缓存页的表空间、数据页号、在Buffer Pool中的地址等。Buffer Pool默认大小是128M,以Page页为单位,Page页默认大小16K。而控制块的大小约为数据页的5%,大概是800字节。
(2)如何判断数据页是否缓存在Buffer Pool
MySQl中有一个哈希表数据结构:key是表空间号 + 数据页号,然后value就是缓存页对应的控制块。当需要访问某个页的数据时:会先从哈希表中根据表空间号 + 数据页号看看是否存在对应的缓存页。如果有,则直接使用。如果没有,则从Free链表中选出一个空闲的缓存页,然后把磁盘中对应的页加载到该缓存页的位置。
2.Buffer Pool的Page管理机制
(1)Page根据状态可以分为三种类型
一.Free Page:空闲Page,未被使用
二.Clean Page:被使用Page,没被修改
三.Dirty Page:被使用Page,已被修改
(2)Free List表示空闲缓冲区(管理Free Page)
Buffer Pool初始化时会先向操作系统申请连续的内存空间,然后把它划分成若干个控制块&缓存页,接着把所有空闲的缓存页对应的控制块作为节点放到一个链表中,这个链表就是Free链表。
从磁盘加载数据页的流程:
首先从Free链表中取出一个空闲的控制块(对应缓存页)。然后把该缓存页对应的控制块信息填上,如缓存页所在的表空间、数据页号之类的信息。接着把该缓存页对应的Free链表节点(即控制块)从链表中移除,表示该缓存页已经被使用了。
(3)Flush List表示需要刷新到磁盘的缓冲区(管理Dirty Page)
Flush List管理的Dirty Page会按修改时间排序。InnoDB引擎为了提高处理效率,在每次修改缓存页后,并非立刻把修改刷新到磁盘上,而是在未来某个时间点进行刷新操作。凡是被修改过的缓存页对应的控制块都会作为节点加入到Flush链表,Flush链表的结构与Free链表的结构相似。
脏页既存在于Flush链表中,也存在于LRU链表中,但它们互不影响。LRU链表负责管理Page的可用性和释放,Flush链表负责管理脏页的刷盘操作。
(4)LRU List表示正在使用的缓冲区(管理Clean Page和Dirty Page)
缓冲区以midpoint为基点:链表的前部分称为热数据列表,存放经常访问的数据,占63%。链表的后部分称为冷数据列表,存放使用较少数据,占37%。
3.Change Buffer的概念和作用
(1)Change Buffer基本概念
Change Buffer是写缓冲区,用于优化对二级索引(辅助索引)页的更新。对于DML操作,如果请求的是辅助索引(非唯一键索引)且还没有在Buffer Pool中,那么不会立刻将数据页加载到Buffer Pool中,而是会先在Change Buffer中记录数据的变更,等未来数据被读取时再将数据合并恢复放到Buffer Pool,以减少磁盘IO。
(2)Change Buffer的数据更新流程
情况1:对于唯一索引,需要将数据页读入内存。然后判断没有冲突才插入更新值,语句执行结束。
情况2:对于普通索引,更新一条记录的步骤如下:
步骤一:如果该记录在Buffer Pool中存在,那么就直接在Buffer Pool中修改,进行一次内存操作。
步骤二:如果该记录在Buffer Pool中不存在(没有命中),那么在不影响数据一致性的前提下,InnoDB会将该记录的更新操作缓存在Change Buffer中,先不用去磁盘查询数据,从而避免一次磁盘IO。
步骤三:当下次查询该记录时,InnoDB才会将数据页读入内存,然后执行Change Buffer中与该记录有关的操作。
(3)为什么写缓冲区仅适用于二级索引页
如果新增或修改发生在唯一索引中,那么InnoDB必须要做唯一性校验。此时就必须查询磁盘,进行一次IO操作。也就是会直接将记录查询到Buffer Pool中,然后在Buffer Pool修改,不需要在Change Buffer操作了。如果新增或修改发生在非索引中,那么InnoDB还是要做唯一性校验。此时也必须查询磁盘,进行一次IO操作。
(4)Change Buffer的使用场景
Change Buffer的主要目的是将记录的变更操作缓存下来,所以在merge发生前应当尽可能多的缓存变更信息,这样Change Buffer的优势发挥得就越明显。应用场景是写多读少的业务,此时页面在写完后马上被访问的概率较小,Change Buffer使用效果最好,这种业务模型常见的就是账单类、日志类的系统。
4.Log Buffer的概念和作用
(1)Log Buffer的概念和作用
Log Buffer是用来保存要写入磁盘log文件的log数据。Log Buffer可以优化每次更新操作后要写文件而产生的磁盘IO问题,因为每次更新操作都是需要写log到redo log和undo log磁盘文件的。
Log Buffer日志缓冲区的内容会定期刷新到磁盘log文件中,Log Buffer日志缓冲区满时会自动将其刷新到磁盘。当遇到BLOB或多行更新的大事务时,增加日志缓冲区可节省磁盘IO。
Log Buffer主要是用于记录InnoDB引擎日志,InnoDB在DML操作时会产生redo和undo日志。Log Buffer空间满了,会自动写入磁盘,默认16M。可以通过将innodb_log_buffer_size参数调大,减少磁盘IO频率。
(2)Adaptive Hash Index介绍
自适应哈希索引,用于优化对Buffer Pool数据的查询,InnoDB存储引擎会监控对表索引的查找。
自适应哈希索引指的是:如果观察到建立哈希索引可以带来速度的提升,则建立哈希索引。InnoDB存储引擎会自动根据访问的频率和模式来为某些页建立哈希索引。
二.InnoDB的存储结构
1.InnoDB磁盘结构
2.表空间(Tablespaces)
3.数据字典(Data Dictionary)
4.双写缓冲区(Double Write Buffer Files)
5.重做日志(redo log)
6.撤销日志(undo log)
7.二进制日志(binlog)
8.表空间文件结构
1.InnoDB磁盘结构
(1)Tablespaces
表空间分为:系统表空间、临时表空间、常规表空间、Undo表空间及独立表空间。系统表空间又包括:Change Buffer(写缓冲区)、Double Write Buffer(双写缓冲区)等。
(2)Double Write Buffer
InnoDB将数据页写到文件前存放的位置。
(3)redo log
存储的是Log Buffer刷到磁盘的数据。
(4)undo log
存在于全局临时表空间中,用于事务的回滚。
2.表空间(Tablespaces)
表空间(Tablespaces)是用于存储表结构和数据的,InnoDB表空间类型包括系统表空间、独立表空间、常规表空间、Undo表空间、临时表空间等。
系统表空间(又叫共享表空间)包含:InnoDB数据字典、Double Write Buffer、Change Buffer、undo log的存储区域。
独立表空间是一个单表表空间,创建一个表就给这个表一个独立表空间。表的数据文件创建和保存于独立表空间中,而不是创建于系统表空间中。
通用表空间和系统表空间类似,也是共享的表空间,一个通用表空间文件能够存储多个表的数据。
撤销表空间用来保存回滚日志,即undo log。撤销表空间由一个或多个Undo日志文件组成,它会在对应表空间目录下生成undo_001和undo_002两个文件。撤销表空间的文件必须以".ibu"作为扩展后缀名,撤销表空间也叫回滚表空间。
临时表空间用来保存用户创建的临时表和磁盘内部的临时表。
3.数据字典(Data Dictionary)
数据字典由内部系统表组成。这些表存储了用于查找表、索引和表字段等对象的元数据,即数据字典存储了表结构、数据库名、表名、字段类型等元数据信息,元数据信息存储在InnoDB系统表空间中。
4.双写缓冲区(Double Write Buffer Files)
(1)什么是写失效(部分页失效)
InnoDB的页和操作系统的页大小不一致。InnoDB页大小一般为16K,操作系统页大小为4K。InnoDB的页写入到磁盘时,一个页需要分4次写。
如果存储引擎正在把页的数据写入到磁盘时发生了宕机,那么就可能出现页的数据只写了一部分的情况,比如只写了4K就宕机了。这种情况叫做部分写失效(Partial Page Write),可能会导致数据丢失。
有人可能会想到,如果发生写失效,MySQL可以根据redo log进行恢复。但是redo log中记录的只是对页的物理修改,如偏移量800写'abc'记录。如果这个脏页本身已经损坏,再对其进行重做redo log是没有用的。可以理解为脏页写一半时机器宕机,会破坏其对应的数据页的完整性。当然其他还没写的脏页,自然不会被破坏,它们可以通过重做日志恢复。注意:数据页有checksum机制检查是否完整。
(2)双写缓冲区Double Write Buffer
为了解决部分写失效问题,