InnoDB存储引擎的关键特性包括插入缓冲、两次写(double write)、自适应哈希索引(adaptive hash index)。这些特性为InnoDB存储引擎带来了更好的性能和更高的可靠性。

问题引入

比如说我们按下列SQL定义的表:

create table t(id int auto_increment,name varchar(30),primary key(id));

id列是自增长的,这意味着当执行插入操作时,id列会自动增长,页中的行记录按id执行顺序存放。一般情况下,不需要随机读取另一页执行记录的存放。因此,在这样的情况下,插入操作一般很快就能完成。

但是,不可能每张表上只有一个聚集索引,在更多的情况下,一张表上有多个非聚集的辅助索引(secondary index)。比如,我们还需要按照name这个字段进行查找,并且name这个字段不是唯一的。

表是按如下的SQL语句定义的:

create table t (id int auto_increment,name varchar(30),primary key(id),key(name));

这样的情况下产生了一个非聚集的并且不是唯一的索引。在进行插入操作时,数据页的存放还是按主键id的执行顺序存放,但是对于非聚集索引,叶子节点的插入不再是顺序的了。这时就需要离散地访问非聚集索引页,插入性能在这里变低了。然而这并不是这个name字段上索引的错误,因为B+树的特性决定了非聚集索引插入的离散性。

InnoDB存储引擎开创性地设计了插入缓冲,对于非聚集索引的插入或更新操作,不是每一次直接插入索引页中,而是先判断插入的非聚集索引页是否在缓冲池中。

插入缓冲

在进行数据插入时必然会引起索引的变化,聚集索引不必说,一般都是递增有序的。而非聚集索引就不一定是什么数据了,其离散性导致了在插入时结构的不断变化,从而导致插入性能降低。

所以为了解决非聚集索引插入性能的问题,InnoDB引擎 创造了Insert Buffer

插入缓冲,并不是缓存的一部分,而是物理页,对于非聚集索引的插入或更新操作,不是每一次直接插入索引页.而是先判断插入的非聚集索引页是否在缓冲池中。

如果在,则直接插入,如果不在,则先放入一个插入缓冲区中.然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作.

插入缓冲的使用需要满足以下两个条件:

1.索引是辅助索引。

2.索引不是唯一的。

先解释一下第一点,辅助索引指的是所有除了主键索引之外的其他索引。而主键索引的插入一般都是有序插入,如id、流水单号、交易单号等等,这种插入一般带来的都是顺序写,io写入性能高。而辅助索引下的写入是有可能是顺序写,但大部分情况下是随机写,若每次插入数据最坏情况下都执行一次随机写,那将耗费比较多的时间。

第二点该索引是非唯一的,因为根据insert buffer的概念,我们的数据会先自己在缓存池中先构造一个B+树插入索引,然后在一定的时间内由master thread进行插入。若该索引必须要唯一的,那么我们的数据在插入缓存池的B+树时候就会访问一次磁盘,查询当前索引是否满足唯一性,这样和不经过缓存池直接插入到磁盘中没有什么分别,无法节省磁盘IO,故该索引不是唯一的。

插入缓冲是InnoDB存储引擎关键特性中最令人激动的。不过,这个名字可能会让人认为插入缓冲是缓冲池中的一个部分。其实不然,InnoDB缓冲池中有Insert Buffer信息固然不错,但是Insert Buffer和数据页一样,也是物理页的一个组成部分。


主键是行唯一的标识符,在应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。因此,插入聚集索引一般是顺序的,不需要磁盘的随机读取。

当满足以上两个条件时,InnoDB存储引擎会使用插入缓冲,这样就能提高性能了。不过考虑一种情况,应用程序执行大量的插入和更新操作,这些操作都涉及了不唯一的非聚集索引,如果在这个过程中数据库发生了宕机,这时候会有大量的插入缓冲并没有合并到实际的非聚集索引中。如果是这样,恢复可能需要很长的时间,极端情况下甚至需要几个小时来执行合并恢复操作。

辅助索引不能是唯一的,因为在把它插入到插入缓冲时,我们并不去查找索引页的情况。如果去查找肯定又会出现离散读的情况,插入缓冲就失去了意义。

查看插入缓冲的信息:

show engine innodb status\G
Ibuf: Size 7545,free list len 3790,seg size 11336,  8075308 inserts,7540969 merged recs,2246303 merges  

seg size显示了当前插入缓冲的大小为11336*16KB,大约为177MB。free list len代表了空闲列表的长度,size代表了已经合并记录页的数量。

inserts代表了插入的记录数字,merges recs代表合并的插入数,merges代表合并的次数,也就是实际读取页的次数。由该数据可以表明,merges:merged recs=1:3,插入缓存对于非聚集索引的离散IO请求降低了2/3.

潜在问题

目前插入缓冲存在一个问题是,在写密集的情况下,插入缓冲会占用过多的缓冲池内存,默认情况下最大可以占用1/2的缓冲池内存。

聚簇索引的插入

首先我们知道在InnoDB存储引擎中,主键是行唯一的标识符。我们平时插入数据一般都是按照主键递增插入,因此聚集索引都是顺序的,不需要磁盘的随机读取。

CREATE TABLE test( id INT AUTO_INCREMENT, name VARCHAR(30), PRIMARY KEY(id));

如上我创建了一个主键 id,它有以下的特性:

  • Id列是自增长的
  • Id列插入NULL值时,由于AUTO_INCREMENT的原因,其值会递增,同时数据页中的行记录按id的值进行顺序存放
  • 一般情况下由于聚集索引的有序性,不需要随机读取页中的数据,因为此类的顺序插入速度是非常快的。

聚簇索引的插入一定是顺序的吗?
不一定,如果你把列 Id 插入UUID这种数据,那你插入就是和非聚集索引一样都是随机的了。这会导致你的B+ tree结构不停地变化,那性能必然会受到影响。

非聚簇索引的插入

很多时候我们的表还会有很多非聚集索引,比如我按照b字段查询,且b字段不是唯一的。如下表:

CREATE TABLE test( id INT AUTO_INCREMENT, name VARCHAR(30), PRIMARY KEY(id), KEY(name));

这里我创建了一个test表,它有以下特点:

  • 有一个聚集索引 id
  • 有一个不唯一的非聚集索引 name
  • 在插入数据时数据页是按照主键id进行顺序存放,辅助索引 name的数据插入不是顺序的
  • 非聚集索引也是一颗B+树,只是叶子节点存的是聚集索引的主键和name 的值。

因为不能保证name列的数据是顺序的,所以非聚集索引这棵树的插入必然也不是顺序的了,会带来离散IO的发生。

当然如果name列插入的是时间类型数据,那其非聚集索引的插入也是顺序的。

频繁的随机IO插入会造成性能下降

首先对于非聚集索引的插入或更新操作,不是每一次直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中。

若在,则直接插入;若不在,则先放入到一个Insert Buffer对象中。

给外部的感觉好像是树已经插入非聚集的索引的叶子节点,而其实是存放在其他位置了

以一定的频率和情况进行Insert Buffer和辅助索引页子节点的merge(合并)操作,通常会将多个插入操作一起进行merge,这就大大的提升了非聚集索引的插入性能。

总结

其实Insert Buffer的数据结构就是一棵B+树。

在MySQL 4.1之前的版本中每张表有一棵Insert Buffer B+树

目前版本是全局只有一棵Insert Buffer B+树,负责对所有的表的辅助索引进行Insert Buffer

如果在,则直接插入;如果不在,则先放入一个插入缓冲区中,好似欺骗数据库这个非聚集的索引已经插到叶子节点了,然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作,这时通常能将多个插入合并到一个操作中(因为在一个索引页中),这就大大提高了对非聚集索引执行插入和修改操作的性能。

实验表明,引入插入缓存之后,整个插入效率:原始插入效率为1:3,减少了2/3的IO次数。

和Jerry哥聊技术,聊生活

按顺序插入图片_MysqlInnodb特性之插入缓存相关推荐

  1. java通过itext方法往pdf中插入图片(交互式pdf插入图片无法显示)

    本文参考自: 原文地址 一.:首先明确pdf的类型,在自己的开发过程中发现pdf也分几种类型. 我目前这里就指出常用两种: 一种是交互式pdf,他的组件可以读取,可以被编辑,比如liveCycle(A ...

  2. php mysql 插入图片_mysql中怎样插入图片

    mysql中插入图片的方法:首先要在数据库中建表:然后装载JDBC驱动,建立连接:最后创建Statement接口类,来执行SQL语句即可. mysql中插入图片的方法: 1.首先,先要在数据库中建表. ...

  3. word插入图片的同时自动插入图片名称

    文章目录 1.打开一个需要插入的word 2.打开Word VBA 3.点击ThisDocument 4.粘贴代码进去,然后关闭(复制代码,别手敲!!!) 5.点击运行宏 6.选择要插入的图片目录 7 ...

  4. 写java的时候怎么插入图片_java swing怎么插入图片

    我的文件的位置 代码如下 JLabel jl3=new JLabel(new ImageIcon("WebRoot/img/sight1.png")); jf.add(jl3); ...

  5. beamer插入图片_beamer中暗背景插入图片

    You need the standard package graphicx to include the image. Loaded xcolor would also be a good idea ...

  6. Github的README中插入图片,Github仓库项目主页显示图片

    Github仓库主页的 README.md 支持 MarkDown 文本,也支持图片显示.显示图片需要提供<img>标签,这个链接可以位于其他服务器上,也可以是GitHub自身的仓库文件. ...

  7. Magento2创建自定义Widget 并通过添加图片选择器插入图片

    为什么80%的码农都做不了架构师?>>>    创建自定义Widget 并通过添加图片选择器插入图片 自定义widget 先在模块的etc 配置文件中创建widget.xml配置文件 ...

  8. pdf插入图片到指定坐标位置 亲测可用

    pdf插入图片到指定位置,常见图片格式都支持 坐标位置可自定义 根据文字.关键字识别坐标位置,可见另一个帖子:pdf识别关键字坐标 依赖引用:itextpdf-5.5.13.jar 常见itextpd ...

  9. markdown笔记(二)—— 插入图片及调整大小

    更快地插入图片 最传统的插入图片方式当然是使用代码方式: ![Alt](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hdmF0YXIuY3Nkbi5uZXQvNy ...

最新文章

  1. php微信jssdk下载图片,微信JSSDK上传多张图片回调方法以及服务器端处理下载媒体...
  2. 测绘技术的发展与分类简述
  3. 阿里云服务器怎么安装docker
  4. 关于Mybatis,我总结了 10 种通用的写法
  5. 重磅!一文读懂线性方程组的求解方法
  6. hibernate教程笔记5
  7. 独家:XIV能否助IBM改变传统存储规则?
  8. 极客大学架构师训练营--食堂就餐系统架构设计⽂档 -- 第一次作业
  9. 人世轮回,无人相怜--观《艺妓回忆录》有感
  10. 插画师如何确定自己的风格?教你如何一步步找到自己绘画风格!
  11. ksps什么单位_采样频率Hz 采样率KSPS或MSPS,两种单位的换算关系
  12. 了解爬虫的风险与以及如何规避风险-Java网络爬虫系统性学习与实战系列(3)
  13. 计算机从bios到操作系统,高手进!!计算机开机后在进入操作系统前BIOS在进行什么检测工作?...
  14. 【DFS】先简单说说DFS分布式存储系统和fastDFS
  15. online python compiler_在线控制台编译器:Online Console Compiler
  16. 举个栗子!Tableau 技巧(16):如何插入自定义形状
  17. Cocos Creator 的组件式编程 以及分工策略 一分钟上手流程
  18. 小白学流程引擎-FLowable(五) — BPMN2.0模型规范
  19. 17 追悔:回到过去,你也不能改变命运
  20. 【Mac】anaconda创建虚拟环境+jupyter虚拟环境配置

热门文章

  1. 幕后产品_使用Bitwarden密码管理器在幕后
  2. 前端:JS/33/实例:表单验证
  3. 太强大了 | 一键生成,太强大了……
  4. JSON语法之JSON字符串
  5. HTML5 canvas中使用路径
  6. es6 调用 Iterator 接口的场合
  7. html显示docx,网页中显示PDF的HTML代码.docx
  8. php7 mcrypt模块_如何在php7.2/php7.3中安装mcrypt扩展?
  9. 怎么把ps转化成html,【论文】浅谈Photoshop转化成Html的方法.pdf
  10. 白盒测试方法_软件测试的种类:白盒测试和黑盒测试