[MySQL]浅谈InnoDB存储引擎(四)插入缓冲

回顾

上节我们了解Master Thread的主要工作,它包括:

  1. 刷新redo日志到磁盘中.
  2. 合并插入缓冲.
  3. 回收undo日志(新版本中被Purge Thread分担).
  4. 刷新脏页。(新版本中被Page Cleaner Thread分担).

那么这个插入缓冲到底是什么东西?

面试中常有提及的自适应哈希又是怎么一回事?
我们这节来探索这些InnoDB中的关键特性-插入缓冲(Insert Buffer).

InnoDB的关键特性

  • 插入缓冲(Insert Buffer).
  • 双写(Double Write).
  • 自适应哈希索引(Adaptive Hash Index).
  • 异步IO(Async IO).
  • 刷新邻接页(Flush Neighbor Page).
插入缓冲 Insert Buffer

首先,不要被插入缓冲这个名字所欺骗,它其实更多的是物理页的组成部分。
这个特性在往数据库插入数据时得到很好的体现,对Primary Key(通常我们称为主键)的插入时,如果该列有AUTO_INCREMENT的属性,在不声明主键列的值情况下,那么MySQL会帮你自动按照自增长的形式进行主键顺序递增,这种速度非常迅速。

Warning: 对UUID这种主键策略往往不能生效,因为UUID是随机的32位数值。是不遵循顺序增长这种规则的。

但是,对于非聚集索引,我们则需要引入插入缓冲来解决离散访问非聚集索引页导致性能低下的问题。这里举一个简单的例子:

id name age
1 张三 20
2 李华 53
3 刘备 12

这里我们假设id是主键,age作为二级索引,那么作为主键的id肯定是自增长的,但是age则不是按顺序排列的。如果此时插入数据,要同时更新二级索引,而更新二级索引这个操作是无法保证顺序插入的。

所以,这里我们能得到结论,插入缓冲是用来解决插入数据时对二级索引的离散插入而产生的IO问题。
这里有个博客举了一个非常生动的例子,我认为很好的诠释了离散插入的概念。有兴趣的朋友可以阅读一下。
innodb insert buffer 插入缓冲区的理解

InnoDB设计了Insert Buffer,对于非聚簇的非唯一索引的插入或者更新操作,不是每一次都同步到索引页中,而是先判断插入的非聚簇索引页是否在缓冲池中,如果在,则直接插入;如果不在,则先放入到Insert Buffer对象中,然后等待线程池在适当的时机进行Merge操作,如此一来,多次插入产生的非聚簇的非唯一索引则一次性合并到了一次Merge操作中了,大大提高了插入性能。但是凡事都有利弊,如果Insert Buffer中存在大量的未合并索引,那么如果数据库发生故障,这个恢复时间会比较漫长。

那么为什么这个非聚簇索引不能是唯一索引呢?这是因为在使用Insert Buffer的时候,数据库不会去查找索引页来判断插入的记录的唯一性。如果先进行读操作再进行写操作,那么Buffer的意义就不复存在了。

下面放一张MySQL的官方文档图加深理解:

innodb-change-buffer.png

可以通过命令 SHOW ENGINE INNODB STATUS来查看插入缓冲的信息,下面对Ibuf中各参数进行一个解释:

  • seg size : 当前Insert Buffer的大小,需要乘与16KB进行计算.
  • free list len : 空闲列表的长度.
  • size : 已经合并j记录页的数量.
  • inserts : 插入的记录数.
  • merged recs : 合并的插入记录数量.
  • merges : 合并的次数,也就是实际读取页的次数
  • merges : merges recs : 如果这个数为1/3,插入缓冲将对于非聚集的非唯一索引页的离散IO逻辑请求约降低了2/3
Change Buffer

InnoDB从1.0.x版本开始引入Change Buffer,可以对DML操作-INSERT、DELETE、UPDATE都进行缓冲。
Insert Buffer一样,Change Buffer是对非聚集的非唯一索引进行缓冲的。
Change Buffer可以细分为:Insert Buffer、Delete Buffer、Purge Buffer(缓冲在后台发生的物理删除操作)

一次UPDATE操作的过程
  1. 将旧记录标记为已删除.
  2. 真正将旧记录删除
  3. 插入新的记录

过程: 在Delete Buffer中将此记录标记为删除,然后真正删除后,在Purge Buffer中记录真正的删除标识,然后进行插入,是否需要Insert Buffer取决于索引的类型与是否能命中当前缓冲池中索引页。可见,要缓冲更新操作至少需要Insert Buffer、Delete Buffer。(An update operation is a combination of an insert and a delete)

innodb_change_buffering

InnoDB提供的Change Buffer配置参数。你可以通过这个参数配置你的MySQL缓冲行为。默认为all.

  • all

默认值:缓冲inserts, delete-marking operations, and purges

  • none

不需要任何缓冲

  • inserts

缓冲Insert行为

  • deletes

缓冲 delete-marking operations.

  • changes

缓冲 inserts and delete-marking operations.

  • purges

缓冲在物理表中真正执行的删除操作:purges

innodb_change_buffer_max_size

此参数用于控制Change Buffer最大使用内存的数量.默认值为25,它表示Change Buffer最多占用缓冲池的25%,最多可以设置到50%.

你可以用SHOW ENGINE INNODB STATUS来查看当前Change Buffer的行为

  • merge operations

显示Change Buffer中每个操作的次数,insert表示Insert Buffer;delte mark 表示Delete Buffer;delete 表示Purge Buffer.

  • discarded operations

当Change Buffer准备发生merge时,表已经被删除。此时可以将这部分合并抛弃。

InnoDB实现Insert Buffer的原理

Insert Buffer是一颗B+树。它是全局唯一的(4.1版本后),负责对所有的表的辅助索引进行Insert Buffer。它存在共享表空间中,默认在ibdata1中。因此,试图通过独立表空间ibd文件恢复表中数据时,往往会导致CHECK TABLE失败。这是因为表的辅助索引中的数据可能还在Insert Buffer中,也就是共享表空间中,所以通过ibd文件进行恢复后,还需要进行REPAIR TABLE操作来重建表上所有的辅助索引。

非叶子节点结构

非叶子节点存放的是search key(键值),9个字节


image.png
  • space
    待插入记录所在表的表空间id,4个字节。(在InnoDB中,每个表都有属于自己的唯一space id,通过space id可以查询得知是哪张表)

  • marker
    用来兼容老版本的Insert Buffer,1个字节

  • offset
    页所在的偏移量,4个字节

插入缓冲的细节

当一个非聚簇的非唯一索引要插入到页(space,offset)时,如果这个页不在缓冲池中,那么InnoDB会构造一个search key,然后查询Insert Buffer这棵B+树,然后将这条缓冲记录插入到Insert Buffer中。

Insert Buffer的叶子节点
image.png

space、marker、offset的规则都跟search key一样,占用9个字节。接下来我们来介绍一下metadata.

  • metadata
    占用4个字节。它存储的内容如下
名称 字 节
IBUF_REC_OFFSET_COUNT 2
IBUF_REC_OFFSET_TYPE 1
IBUF_REC_OFFSET_FLAGS 1

IBUF_REC_OFFSET_COUNT:
整数,用来排序每个记录进入Insert Buffer的顺序,通过这个顺序回放(replay)得到记录的正确值。

剩下的则是需要合并的索引记录了。由此可见,叶子节点有13个额外的字节+需要合并的索引记录组成。

Insert Buffer Bitmap

启用Insert Buffer后,原本要插入到非聚簇索引页(space,page_no)的数据可能被插入到Insert Buffer B+树中了,那么为了保证每次Merge Insert Buffer页必须成功,还需要有一个特殊的页来标记每个非聚簇索引页(space,page_no)的可用空间,这个页的类型为Insert Buffer Bitmap.

每个Insert Buffer Bitmap页用来追踪16384个非聚簇索引页,也就是256个区。关于非聚簇索引页的信息如下:

名称 大小(bit) 说明
IBUF_BITMAP_FREE 2 表示该辅助索引页中的可用空间数量:
0: 表示无可用剩余空间
1: 表示剩余空间大于1/32页(512字节)
2: 表示剩余空间大于1/16页
3: 表示剩余空间大于1/8页
IBUF_BITMAP_BUFFERED 1 1表示该非聚簇索引页有记录被缓存在Insert Buffer B+树中
IBUF_BITMAP_IBUF 1 1表示该页为Insert Buffer B+树的索引页
合并插入缓存的时机
  • 当非聚簇索引页被读取到缓冲池中时

插入缓冲中的数据还没有持久化到非聚簇索引中,但是此时的查询请求需要用到这部分信息,此时先检查Insert Buffer Bitmap,如果发现IBUF_BITMAP_BUFFERED为1,则执行插入缓冲合并,保持索引页数据的一致性。

  • Insert Buffer Bitmap页追踪到该非聚簇索引页无可用空间时

如果当前索引页的可用空间小于1/32页,强制执行插入缓冲合并,把非聚簇索引页读到缓冲,然后合并后插入。

  • Master Thread

Master Thread每10秒或者每秒进行的操作。
Insert Buffer采用随机选择页的方式,让插入缓冲更具备公平性。值得注意的是,如果合并插入缓冲时发现该该表已经被删除,那么丢弃这次合并的操作。

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