Innodb核心原理之内存结构

2024-06-27  本文已影响0人  这货不是王马勺

innodb架构图

5.5以上默认innodb,最大特性是支持事务。
innodb架构主要由两部分组成:in-memory & on-disk,即内存结构和磁盘结构。这里单独介绍一下内存结构。

架构图:


innodb内存结构

1.innodb内存结构由哪几部分组成?各自作用是什么?

由buffer pool(含buffer pool主要部分、change buffer、adaptive hash index)、log buffer。

参考架构图左半部分。

2.什么是buffer pool?

缓冲池,缓存表和索引的数据,目的是减少磁盘io。

由两部分组成:

buffer pool默认大小128M,
page默认16K,
控制块一般为页的5%,约800字节。

当我们查询一条数据的时候,会将这条数据所在页从磁盘加载到buffer pool


innodb是如何判断一个页已经在buffer pool中缓存的?
在MySQL中有一个hash表的数据结构,是一个k-v形式,它使用表空间号+当前数据页编号作为一个key,value是缓存页对应的控制块。当我们需要访问某个页的数据时,先从hash表中根据表空间号+数据页编号判断是否有对应的缓存页。如果有,则直接使用;如果没有,则从free链表中选出一个空闲的缓存页,然后把磁盘中对应的页加载到该空闲缓存页的位置,即一次磁盘io。

3.buffer pool中如何管理page页?

buffer pool底层采用链表的方式管理page页。
参考:

https://blog.csdn.net/wangdamingll/article/details/107348038

page根据状态可分为3种类型:

对于上述三种页,innodb使用3中链表结构进行管理:

磁盘加载页的流程:
1.从free list链表中取一个空闲的控制块,即得到对应的空闲缓存页;
2.把此缓存页对应的控制块信息补充完整(比如页所在的表空间,页号之类的信息);
3.将此控制块从free list链表中移除掉,表示该缓存页已被使用,不再空闲;

参考图例:


参考文章:

https://blog.csdn.net/fvdfsdafdsafs/article/details/137889775

4.MySQL为什么没有采用传统LRU算法?

普通的LRU算法
LRU(最近最少使用),新数据从链表头部加入,本来在内存中的page如果使用了则移动到头部;释放空间时从就从末尾淘汰。

普通的LRU链表的缺点

5.MySQL对LRU算法进行了哪些优化?

改进型LRU算法
链表分为new和old两个区域,new区占63%,old区占37%,查看如下参数:

mysql> SHOW VARIABLES LIKE 'innodb_old_blocks_pct';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+

加入元素时并不是从表头插入,而是从midpoint位置插入。


先将页加载到冷数据区头部,当使用时才会再放到热数据区头部,不使用则被淘汰。这就避免了预读失效导致的性能下降,以及buffer pool污染。

冷数据区数据什么时候被转到热数据区?

mysql> SHOW VARIABLES LIKE 'innodb_old_blocks_time';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_old_blocks_time | 1000  |
+------------------------+-------+

参考:

https://blog.csdn.net/zhanglong_4444/article/details/138469956

6.change buffer

change buffer (写缓冲区),针对于二级索引页更新的优化措施。作用是在进行DML操作时,如果请求的是辅助索引,并且没有在缓冲池中缓存,这时并不会立刻将磁盘页加载到缓冲池,而是在change buffer中记录变更,等待未来数据被读取的时候,再将数据合并恢复到buffer pool中。

什么情况会进行merge?

change buffer默认占整个buffer pool的25%,最大允许占用50%。可以根据读写的业务量进行适当调整:

change buffer更新流程:

为什么change buffer写缓冲区仅适用于辅助索引页?
为什么仅用于非唯一二级索引?因为如果设置了唯一性,则修改时innodb必须进行唯一性校验。因此,如果不在缓冲区,则必须查询磁盘,进行一次io操作,会直接将记录加载到buffer pool,在缓冲池中修改,就不会在change buffer操作了。

7.Log buffer

Log buffer的作用?
log buffer:日志缓冲区,用来保存将要写入磁盘log文件(redo和undo)的数据,默认大小16MB。日志缓冲区的内容会定期刷新到磁盘文件当中。
log buffer作用:用来优化每次更新操作后都要写入redo log而产生的磁盘io过多的问题。日志缓冲区满时,会自动将数据刷新到磁盘;或者当遇到blob或大量更新的大事务时,增加日志缓冲区可节省磁盘io。

关键参数:

判断是否需要增加innodb_log_buffer_size,需要依据如下状态:

show status like 'innodb_log_waits';

如果该参数不为0,则应该适当增加大小。

8.adaptive hash index

innodb是否支持哈希索引?
实验:

alter table t1 add index ix_1(col1)  using hash;
show index from t1\G

如果我们用语句加hash索引,会发现实际上建的还是B+树。
因为innodb不支持用户手动创建哈希索引,使用存储引擎默认的值进行替代。
innodb会自调优,判断如果建立AHI(adaptive hash index)能提高查询效率,则在内存中建立,不需要人工干预。

为什么要有adaptive hash index?
AHI用于实现对热数据页的一次查询。使用聚簇索引进行数据页定位的时候,需要根据索引树的高度
,从根节点走到叶子节点,通常需要3~4次io才能定位数据。innodb会根据索引字段情况和索引使用情况进行分析,通过自调优的方式,为索引页建立hash索引。不需要的时候会删掉hash索引。

自适应哈希索引是如何提高查询效率?
AHI作用的目标是频繁查询的数据页和索引页,由于数据页是聚簇索引的一部分,因此AHI是建立在索引之上的索引。
对于二级索引,如果命中AHI,则直接从AHI中获取二级索引页的记录指针,再根据主键沿着聚簇索引查询。
对于聚簇索引,如果聚簇索引查询命中AHI,则直接返回目标数据页的记录指针,即可通过此记录指针直接定位数据页。

通过二级索引访问记录过程如图:


不管是聚簇索引还是普通索引,记录定位的寻路路径都是比较长的。MySQL的运行过程中,如果发现有很多寻路很长(B+树层数多,回表次数多)SQL,或有很多SQL命中相同的页,innodb就会在内存中开辟一块区域建立自适应哈希索引,加速查询。

hash数据结构都是包含k-v(键值)的。
在AHI中,key就是经常访问的索引键值,value就是该索引键值匹配的完整记录所在page位置。
通过adaptive hash index访问记录的过程和聚簇索引对比如图:


如果是二级索引想获取整行数据还是要回一次表。

上一篇 下一篇

猜你喜欢

热点阅读