Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

插入缓冲 #87

Closed
zhangyachen opened this issue Oct 22, 2016 · 0 comments
Closed

插入缓冲 #87

zhangyachen opened this issue Oct 22, 2016 · 0 comments

Comments

@zhangyachen
Copy link
Owner

zhangyachen commented Oct 22, 2016

当插入辅助索引时,会出现随机插入的情况,此时mysql会离散的访问索引页,然后插入索引数据。因为存在随机的IO,如果存在大量的并发插入,会导致性能下降,所以出现了插入缓冲机制。对于辅助索引的插入或者更新,不是直接插入到索引页中,而是先判断插入的辅助索引页是否在缓冲池中,如果在,直接插入,否则先放入到一个insert buffer对象中。之后再以一定的频率进行insert buffer和辅助索引页子节点的merge操作。

这里说的是先判断插入的索引页是否在缓冲池中,但是mysql如何判断插入的是哪一个索引页呢?个人认为还是读磁盘上的该索引对应的B+树,找到该数据应该插入的地方,也就是对应的索引页。但是既然找到了插入的地方,为什么不直接插入?因为插入可能会造成索引节点的分裂,会有随机IO。而且对于同一索引节点的写入,可以利用insert buffer在后期直接一次写入merge,节省IO。

使用insert buffer的两个条件:

  • 索引是辅助索引
  • 索引不是唯一的

为什么索引不能是唯一的?因为若索引是唯一的,mysql为了检查一致性,还是要进行随机读取索引页,违背了设计插入缓存的初衷——为了防止随机IO读取索引页。

insert buffer的数据结构是B+树,全局只有一颗B+树,存放在共享表空间中,也就是ibdata1。
B+树的非叶子节点是Search key,构造结构为(space,marker,offset)。

  • space:待插入记录所在表的表空间id。每个表都有唯一的表空间id,通过表空间id可以查出是哪张表。
  • marker:兼容之前的版本。
  • offset:在表空间中页的偏移量。

当一个辅助索引要插入到(space,offset)中时,如果该页不在缓冲池中,则按上述规则构造一个search key,将该记录插入到insert buffer中。

但是如果该页一直在insert buffer中,不断有记录插入到同一个索引页中,那么该索引页的空间就会逐渐缩小,要出现B+树节点的分裂情况,这时就不能进行insert buffer了。所以,我们需要一个机制来管理每个页面的剩余空闲空间,这就是Insert buffer bitmap。每隔page_size个页面,就是一个Insert buffer bitmap page。例如:若page_size = 16384(16k),那么page_no为0,16384,32768,…的page,就是Insert buffer bitmap page,Bitmap page的功能,就是管理其后连续的page_size – 1个page的空间使用率。
每个辅助索引页在Insert buffer bitmap中占用4bit。

名称 大小(bit) 说明
IBUF_BITMAP_FREE 2 表示该辅助索引页的可用空间(无,剩余大于1/32,剩余大于1/16,剩余大于1/8)
IBUF_BITMAP_BUFFERED 1 1表示该辅助索引页有记录被缓存在insert buffer中
IBUF_BITMAP_IBUF 1 1表示该页为insert buffer的索引页

insert buffer什么时候真正合并到真正的辅助索引中?

  • 辅助索引页被读取到缓冲池中。
  • Insert buffer bitmap page追踪到该索引页无可用空间时。
  • Master Thread。

针对第一点:

针对第三点:
若过去1s之内发生的I/O,小于系统I/O能力的5%,则主动进行一次Insert buffer的merge操作。Merge的页面数为系统I/O能力的5%,读取page采用async io模式。
每10s,必定触发一次insert buffer merge动作。Merge的页面数仍旧为系统I/O能力的5%。
如何选择insert buffer页?随机选择一个insert buffer页,读取该页中的space及之后所需要数量的页。

参考资料:《MySQL技术内幕-InnoDB存储引擎》
何登成的技术博客 InnoDB Insert Buffer实现详解

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant