MySQL InnoDB存储引擎体系架构 —— 内存管理

我们都知道,InnoDB引擎是基于磁盘存储的,但由于物理硬盘访问速度与内存访问速度存在着巨大的鸿沟,InnoDB常用缓冲池技术来提高数据库的性能。

与常用的缓存思想类似,在数据库中读取页的操作,首先将磁盘读到的页放在缓冲池当中,下一次再读相同页时,先检查该页是否在缓冲池当中。若在缓冲池中,则该页在缓冲池中被命中,直接读取该页,否则读取磁盘中的页。可见,缓冲池的大小非常影响MySQL的性能。缓冲池在MySQL用innodb_buffer_pool_size变量表示,可以在my.cnf文件中设置,查看方式如下图,可见,缓冲池的大小是134217728/1024/1024=128M(当然在生产环境下128M太小)。

show variables like 'innodb_buffer_pool_size'\G;

在数据库中修改页的操作,首先修改缓冲池中页的数据,然后以一定频率异步地将缓冲池页刷新到磁盘上,这种技术叫Checkpoint机制,这样的目的也是为了提高MySQL整体性能。

缓冲池是一块很大的内存区域,其中存放各种类型的页,默认每页的大小是16K,让我们来看一下缓冲池中数据页的类型:索引页,数据页,redo页,插入缓冲,自适应哈希索引,锁信息,数据字典等,那么InnoDB是如何管理内存的呢?

一、页的管理

1、LRU List

LRU,Latest Recent Used,最近最少使用算法。缓存池可以被认为一条长LRU链表,该链表又分为2个子链表,一个子链表存放old pages(里面存放的是长时间未被访问的数据页),另一个子链接存放new pages(里面存放的是最近被访问的数据页面)。

与传统的LRU算法不同,innoDB对LRU算法进行优化,插入的数据不在LRU List的首部,在innoDB中引入了一个midpoint的概念,将新的数据插入到LRU List的midpoint位置处。我们可以通过命令查看midpoint的值

show variables like 'innodb_old_blocks_pct'\G;

可以看到midpoint默认值是37,midpoint之前是newPage占37%,midpoint之后是oldPage,可以通过命令调整midpoint'的值

set global innodb_old_blocks_pct=38

思考:innodb为什么要设置midpoint而不用传统的LRU算法呢

答:这是因为若直接将读取的页放在LRU列表的首部,那么某些SQL操作可能会使缓冲池中的页被刷新出,从而影响缓冲的命中率。常见的操作如需要访问表中的很多页,也许这些页并不是热点数据,如果放在LRU列表首部,但这些页有可能会将热点数据刷出缓冲池。引入midpoint,将新查的数据存储在midpont位置中,midpoint之前的仍为最热数据。

2、Free List

当MySQL刚启动时,LRU List是空的,这时的页都存放在Free List中。当需要从缓冲池中分页时,首先从Free List中查找是否有空闲页,如果有则从FreeList中移除,放在LRU List中。我们可以根据以下命令查看LRU List和Free List的数据

show engine innodb status\G; 

其中有几个重要的参数,我已经标红,在下面一一解释:

  • Buffer pool size:缓冲池中页的个数,每页默认大小16k,则缓冲池的大小是8192*16/1024=128M。
  • Free buffers:Free List页的个数
  • Database pages:LRU List页的个数
  • Modified db pages:脏页的个数,由于在进行update操作时首先会修改缓冲池中的数据,在定时异步的将缓冲池的数据刷新到磁盘中(checkpoint技术),所以缓冲池的数据与磁盘的数据会产生不一致,称为脏页。
  • LRU len:LRU List的长度。

3、Flush List

在LRU中的页被修改后,该页称为脏页,即缓冲池中的页和磁盘上的页产生了不一致,而Flush List中的页即为脏页列表。注意:脏页既存在于LRU List中,也存在Flush List中,LRU List用来管理缓冲池中可用的页,Flush List用来管理将脏页刷新到磁盘上,二者互不影响。下面我用一个例子来给大家验证Flush List和Modified db pages;

有一张user表存有如下数据:

这时我们查看Modified db pages的值为0:

当我们update的时候,我执行如下命令,修改数据并查看脏页的值,之所以两条命令一起执行,是为了可以看到脏页的值的变化,如果分成两次执行,有可能checkpoint机制已将修改的数据刷新到磁盘中而观测不到脏页的值。

update user set id=5 where id=4;show engine innodb status\G;

我们可以看到Modified db pages的值确实变化了,表明又脏页产生。

二、插入缓冲(Insert Buffer)

听到这个名字,可能会让人认为insert? buffer是缓冲池中的一部分,其实不是,insert buffer和数据页一样,也是物理页中的一个组成部分。

在InnoDB中,主键是行的唯一标识,如果我们的主键是auto_increment的话,插入顺序是有序的,一般情况下不需要读取另一页的数据,所以插入速度非常快,如下表:

但不可能每张表都只有一个聚集索引,大多情况下,每张表会有非聚集索引。比如用户按照b字段查询,而且b字段不是唯一的,在insert时,主键a还是按照有序存放,但非聚集索引b的叶子节点插入的不一定是有序了。如下表:

InnoDB设计的Insert Buffer,对非聚集索引的插入和更新操作,不是每次一都直接插入索引页(index page)中,而是先判断插入的非聚集索引页是否在缓冲池中存在,若在则直接插入,若不在,则先放入到一个Insert Buffer对象中。然后再以一定频率执行Insert Buffer和index page的合并操作,这时候能将多个insert合并到一个操作中,大大提高了非聚集索引插入的性能。我理解的Insert Buffer的操作如下图所示:对于insert操作,首先进入insert buffer中,然后以一定频率将索引merge到index page中,checkpoint定时将数据刷新到磁盘中。

然而,InnoDB使用Insert Buffer需要同时满足一下两个条件:

  • 索引是非聚集索引
  • 索引不是唯一的

如果索引是唯一的,在每次插入的时候先会判断索引值是否已经存在,这样会随机读取index page,从而导致Insert Buffer失去了意义。

通过命令可以查看到insert buffer的信息:

show engine innodb status\G;
  • size:已经和index page合并并记录页的数量;
  • free list:空闲列表的长度;
  • seg size:当前insert buffer的大小,2*16k=32k。

对insert buffer的形象理解(摘自网络)

我们去图书馆还书,对应图书馆来说,他是做了insert(增加)操作,管理员在1小时内接受了100本书,这时候他有2种做法把还回来的书归位到书架上

1)每还回来一本书,根据这本书的编码(书柜区-排-号)把书送回架上

2)暂时不做归位操作,先放到柜面上,等不忙的时候,再把这些书按照书柜区-排-号先排好,然后一次性归位

用方法1,管理员需要进出(IO)藏书区100次,不停的登高爬低完成图书归位操作,累死累活,效率很差。

用方法2,管理员只需要进出(IO)藏书区1次,对同一个位置的书,不管多少,都只要爬一次楼梯,大大减轻了管理员的工作量。

为什么对于非聚集索引(非唯一)的插入和更新有效?

还是用还书的例子来说,还一本书A到图书馆,管理员要判断一下这本书是不是唯一的,他在柜台上是看不到的,必须爬到指定位置去确认,这个过程其实已经产生了一次IO操作,相当于没有节省任何操作。

所以这个buffer只能处理非唯一的插入,不要求判断是否唯一。

三、自适应哈希索引(Adaptive Hash Index)

此索引非彼索引。Innodb存储引擎会监控对表上普通索引的查找,如果发现某索引被频繁访问,则该索引成为热数据,建立哈希索引可以带来速度的提升。看下图,AHI的位置在普通索引之前,查询时先查AHI,后查普通索引。

产生AHI的条件

通过主键查询,或者通过联合索引(a,b)查询,比如select * from t where a=xxx或select * from t where a=xxx and b=yyy;

以该模式查询至少100次。

页通过该模式访问至少N次,N=页中的记录数*1/16;

AHI只对等值查询有效,对范围查询无效。

另外,我们要知道,AHI是InnoDB控制的,因此我们不能对AHI进行干预。我们可以查看AHI的是否开启,默认是开启ON状态。

show variables like 'innodb_adaptive_hash_index'\G;

通过命令我们可以查到AHI的使用状况。

show engine innodb status\G; 

hash表示系统使用AHI查询的速度,non-hash是没有使用AHI的查询速度。如果读者想要看到数值,可以连续查询某数据100次以上,则可以看到hash的值。

select * from t where id=1;show engine innodb status\G;

select * from t where id>1;show engine innodb status\G;

Java_苏先生:专注于Java开发技术的研究与知识分享!
————END————

  • 点赞(感谢)
  • ...
  • 转发(感谢)
  • ...
  • 关注(感谢)
  • ...
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容