InnoDB引擎三大特性
2023-01-19 15:33:37 0 举报
AI智能生成
InnoDB引擎三大特性:BufferPool\AdaptiveHashIndex\DoublewriteBuffer
作者其他创作
大纲/内容
AdaptiveHashIndex
自适应哈希索引
为了提高索引更好的查询数据的效率,而进行对二级索引的优化
查看自适应索引是否打开
show variables like '%ap%hash_index';
说明
经常访问的二级索引数据会自动被生成到hash索引里面去(最近连续被访问三次的数据),自适应哈希索引通过缓冲池的B+树构造而来
特点
无序,没有树高
降低对二级索引树的频繁访问
缺点
占用InnoDB Buffer Pool 的空间
自适应hash索引只适合搜索等值的查询
极端情况下,自适应hash索引才有比较大的意义,可以降低逻辑读
查询原理
Buffer Pool
缓冲区
为了提高MySQL的查询效率在内存中申请的一篇连续的空间
内存大小
how variables like 'innodb_buffer_pool_size';
默认大小
128M
最小空间大小
5M
通常的设置方法
如果没有专门的DBA做实时监测,设置为机器内存的60%就较为合适
如果有专门的检测人员,可以75%,根据业务和实时数据来进行大小的调整
通常根据缓存的命中率来进行调整
缓存命中的查看
show engine innodb status\G
具体规则
命中率没达到98%以上,都说明buffer不够,可以扩大
如果给命中都能达到98%~100%了,而且还有大量的free page那说明够用了
InnoDB 为缓冲区和控制结构保留了额外的内存
所以最终分配的空间比Buffer Pool分配的空间会大10%
Buffer Pool的组成
缓存页
数据的存放
和数据页的大小一致16KB
控制块
记录缓存页的相关信息
包括:页所属的表空间编号、页号、缓存页在Buffer Pool中的地址、链表节点信息、一些锁信息以及LSN信息
控制块和缓存页一一对应
结构
Buffer Pool的缓存页管理
free链表
空闲的缓存页对应的控制块作为一个节点组成的链表
处于free链表中控制块对应的缓存页就是空闲的可以进行数据缓存的缓存页
通过控制块上的缓存页地址就可以找到对应的缓存页,之后将使用的缓存页的控制块移出该链表就可表示控制块对应的缓存页已被使用
结构
缓存页hash表
用于快速判断某个数据页是否在Buffer Pool数据结构
使用Hash表存储
key
表空间号+页号
value
数据页对应的缓存页地址
过程
访问某个页的数据时,先从哈希表中根据表空间号 + 页号看看有没有对应的缓存页
有的话直接使用缓存页中的数据
没有的话在free链表中申请一个缓存页,将磁盘中对应的数据加载到缓存也中并维护到缓存页的hash表中
flush链表
有过数据更新操作的页(脏页)对应的控制块组成的链表
结构和free链表差不多
LRU链表
LRU算法
最近最少使用算法
长期不被使用的数据,在未来被用到的几率也不大,所以当新的数据进来时我们可以优先把这些数据替换掉
问题:
查询语句中可能导致进行数据表的全表扫描
这样就导致了表的所有页都会被加载到Buffer Poll<br>
而且数据的每条加载会导致页会频繁的被加载到,导致数据页成为热点页
这样存入缓存其实会导致使用Buffer Pool的查询效率不高
预读机制<br>
方案
线性预读
顺序访问了某个区(extent)的页面超过这个系统变量的值
就会触发一次异步读取下一个区中全部的页面到Buffer Pool的请求
随机预读
Buffer Pool中已经缓存了某个区的13个连续的页面
都会触发一次异步读取本区中所有其他的页面到Buffer Pool的请求
问题:
这样的预加载就会导致一些不用的页加载到缓存中
解决
将LRU链表进行分区,分为yong和old区
young区域
一部分存储使用频率非常高的缓存页
存放热数据
old区域
使用频率不是很高的缓存页
存放冷数据
yong和old的默认比利是old区域在LRU链表中所占的比例是37%
即yong:old=5:3
存放规则
初次加载到Buffer Pool中的某个缓存页时,该缓存页对应的控制块会被放到old区域的头部
解决预读的问题
某个处在old区域的缓存页进行第一次访问时就在它对应的控制块中记录下来这个访问时间,如果后续的访问时间与第一次访问的时间在某个时间间隔内,那么该页面就不会被从old区域移动到young区域的头部
SHOW VARIABLES LIKE 'innodb_old_blocks_time';
这样就解决了全表扫描导致数据页成为伪热点数据的情况
访问的缓存页位于young区域的1/4的后边,才会被移动到LRU链表头部
降低调整LRU链表的频率,从而提升性能
链表结构
刷新脏页到磁盘
MySQL会维护一个专门进行脏数据磁盘刷新的磁盘的线程
刷新方式
从LRU链表的冷数据中刷新一部分页面到磁盘
从flush链表中刷新一部分页面到磁盘
系统特别繁忙时,也可能出现用户线程批量的从flush链表中刷新脏页的情况
多个Buffer Pool实例<br>(Buffer Pool的隔离)
可以减少并发情况下的加锁导致的效率低的情况<br>
每个Buffer Pool都是独立的,在多线程并发访问时并不会相互影响,从而提高并发处理能力
innodb_buffer_pool_instances能设置的最大值是64
每个实例的innodb_buffer_pool_size(默认128M)的值小于1G的时候设置多个实例是无效的
Buffer Pool的扩容
MySQL 5.7.5之前,是需要继续申请一块新的连续的内存空间,然后进行Buffer Pool的转移
运行过程中不允许进行调整
MySQL在5.7.5以及之后的版本中支持了在服务器运行过程中调整Buffer Pool大小
每次回申请一个chunk
一个chunk的默认大小是128M
Buffer Pool的状态查看
SHOW ENGINE INNODB STATUS\G
重要参数
Total memory allocated:代表Buffer Pool向操作系统申请的连续内存空间大小
Dictionary memory allocated:为数据字典信息分配的内存空间大小
Buffer pool size:代表该Buffer Pool可以容纳多少缓存页,注意,单位是页!
Free buffers:代表当前Buffer Pool还有多少空闲缓存页
Database pages:代表LRU链表中的页的数量,包含young和old两个区域的节点数量
Old database pages:代表LRU链表old区域的节点数量。
Modified db pages:代表脏页数量,也就是flush链表中节点的数量。
BufferPool缓存淘汰机制是怎样的<br>
主要使用了LRU算法
1.3/8的list信息是作为old list,这些信息是被驱逐的对象。
2.list的中点就是我们所谓的old list头部和new list尾部的连接点,相当于一个界限
3.新数据的读入首先会插入到old list的头部,
4.如果是old list的数据被访问到了,这个页信息就会变成new list,变成young page,就会将数据页信息移动到new sublist的头部。但是要注意innodb_old_blocks_time参数
5.在数据库的buffer pool里面,不管是new sublist还是old sublist的数据如果不会被访问到,最后都会被移动到list的尾部作为牺牲者
Doublewrite Buffer
双写缓冲区
Doublewrite Buffer
系统表空间中的特定的两个区(128个页)
2M大小
这个双写缓冲区不仅在内存中,也存在于MySQL的系统表空间,属于磁盘文件的一部分
为什么要使用双写缓存
提高innodb把缓存的数据写到硬盘这个过程的安全性
为了解决部分页写入问题
在极端的情况下,由于操作系统分批进行磁盘记录的写入就可能出现"断页",导致数据混乱
innodb的事务日志不需要包含所有数据的前后映像,而是二进制变化量
节省大量的IO
涉及到双写缓冲区进行脏页刷盘的过程
使用mymcop将脏数据赋值到内存中一个2M的空间
通过两次将数据刷新到系统表空间中
马上调用fsync函数同步到磁盘上
fsync函数:将文件数据同步到硬盘
弊端
由于需要进行双写,既要写入Doublewrite buffer,又要对表的.bd文件写入,所以性能会比直接进行独立表空间写入降低5%~10%
但是在主从集群模式下,我们可以将从slave的双写缓存机制关掉,因为即使出现了部分写入的问题,也可以通过中继日志中恢复数据
redo日志和双鞋缓冲区的比较
redo日志
记录的是页的物理操作,即记录的是具体那条数据发生了什么变化
不是整页数据的记录
doublewrite buffer
进行的是整页数据的记录
部分写入问题问什么不用redo日志恢复?
redo日志只记录具体数据的变化,并没记录变化数据所在页的所有数据
redo日志需要配合磁盘中的原始语句一起才能进行异常页的恢复
但是使用doublewrite buffer 只需要将改变的页刷入磁盘即可
0 条评论
下一页