《InnoDB引擎七》InnoDB关键特性-插入缓存

news2024/9/28 21:26:56

在这里插入图片描述

InnoDB 关键特性

  InnoDB存储引擎的关键特性包括:

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

  这些特性为InnoDB存储引擎带来了更好的性能以及更高的可靠性。

插入缓冲

1. Insert Buffer

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

  在InnoDB存储引擎中,主键是行唯一的标识符。通常应用程序中行记录的哈如顺序是按照主键递增的顺序进行插入的。因此,插入聚集索引(Primary Key)一般是顺序的,不需要磁盘的随机读取。比如按下列SQL定义表:

create table zxy (
	a int auto_increment,
	b varchar(30),
	primary key(a)
);

  其中a列是自增长的,若对a列插入null值,则由于其具有auto_increment属性,其值会自动增长。同时页中的行记录按a的值进行顺序存放。在一般情况下,不需要随机读取另一个页中的记录。因此对于这类情况下的插入操作,速度是非常快的。

  注意:并不是所有的主键插入都是有顺序的。若主键类是UUID这样的类,那么插入和辅助索引一样,同样是随机的。即使主键是自增类型,但是插入的是指定的指,而不是NULL指,那么同样可能导致插入并非连续的情况。

  但是不可能每张表上只有一个聚集索引,更多情况下,一张表上有多个非聚集的辅助索引(secondary index)。比如,用户需要按照b这个字段进行查找,并且b这个字段不是唯一的,即表是按如下的SQL语句定义的:

create table zxy (
	a int auto_increment,
	b varchar(30),
	primary key(a),
	key(b)
);

  在这样的情况下产生了一个非聚集的且不是唯一的索引。在进行插入操作时,数据页的存放还是按主键a进行顺序存放的,但是对于非聚集索引叶子节点的插入不再是顺序的了,这时就需要离散的访问非聚集索引页,由于随机读取的存在而导致了插入操作性能下降。当然这并不是b字段上索引的错误,而是因为B+树的特性决定了非聚集索引插入的离散型。

  需要注意的是,在某些情况下,辅助索引的插入依然是顺序的,或者说是比较顺序的,比如用户购买表中的事件字段。在通常情况下,用户购买时间是一个辅助索引,用来根据时间条件进行查询。但是在插入时却也是根据时间的递增而插入的,因此插入也是“较为”顺序的。

  InnoDB存储引擎开创性的设计了Insert Buffer,对于非聚集索引的插入或更新操作,不是每次直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入;若不在,则先放入到一个Insert Buffer对象中,好似欺骗。数据库这一个非聚集索引已经插入到叶子节点,而实际并没有,只是存放在另一个位置。然后再以一定的频率和情况进行Insert Buffer和辅助索引页子节点的merge(合并)操作,这时通常能将多个插入合并到一个操作中(因为在一个索引页中),这样就大大的提高了对于非聚集索引插入的性能。

  然而Insert Buffer的使用需要满足以下两个条件:

  • 索引是辅助索引 (secondary index)
  • 索引不是唯一的 (unique)

  当满足以上两个条件时,InnoDB存储引擎会使用Insert Buffer,这样就能提高插入操作的性能了。不过考虑到这样一种情况:应用程序进行大量的插入操作,这些都涉及了不唯一的非聚集索引,也就是使用Insert Buffer的情况。若此时MySQL数据库发生了宕机,这时势必有大量的Insert Buffer并没有合并到实际的非聚集索引中。因此这时恢复可能需要很长时间,在极端情况下,甚至需要几个销售。

  辅助索引不能是唯一的,因为在插入缓冲时,数据库并不去查找索引页来判断插入的记录的唯一性。如果去查找肯定会有离散读取的情况发生,从而导致Insert Buffer失去了意义。

  而Insert Buffer还存在的一个问题是:在写密集的情况下,插入缓冲会占用过多的缓冲池内存(innodb_buffer_pool),默认最大可以占用到1/2的缓冲池内存。但是可以通过ibuf_pool_size_per_max_size对插入缓冲大小进行控制。当ibuf_pool_size_per_max_size改为3时,则最大只能占用1/3的缓冲池内存。

2. Change Buffer

  InnoDB从1.0.x版本开始引入了Change Buffer,可以将其视为Insert Buffer的升级。从这个版本开始,InnoDB存储引擎可以对DML操作-INSERT、DELETE、UPDATE都进行缓冲,他们分别是:Insert Buffer、Delete Buffer、Purge Buffer。

  当然和之前Insert Buffer一样,Change Buffer使用的对于依然是非唯一的辅助索引。

  对一条记录进行update操作分为两个步骤:

  • 将原记录标记为已删除
  • 真正将原记录删除

  因此Delete Buffer对应update操作的第一个过程,即将记录标记为删除。Purge Buffer对应update操作的第二个过程,即将记录真正的删除。同时,InnoDB存储引擎提供了参数innodb_change_buffering,用来开启各种buffer的选项。该参数可选的值为:inserts、deletes、purges、changes、all、none。inserts、deletes、purges就是前面讨论的三种情况。changes表示启用inserts和deletes,all表示启用所有,none表示都不启用。参数默认值为all。

  从InnoDB 1.2.x版本开始,可以通过innodb_change_buffer_max_size来控制Change Buffer最大使用内存的数量。

mysql> show variables like 'innodb_change_buffer_max_size'\G;
*************************** 1. row ***************************
Variable_name: innodb_change_buffer_max_size
        Value: 25
1 row in set (0.00 sec)

  innodb_change_buffer_max_size值默认为25,表示最多使用1/4的缓冲池内存空间。需要注意的是,该参数最大有效值是50,也就是最多使用1/2的缓冲池内存空间。

  通过show engine innodb status;可以看到merged operations和discard operation,并且下面显示Change Buffer中每个操作的次数。insert表示insert buffer;delete mark表示delete buffer;delete表示purge buffer;discard operations表示当change buffer发生了merge时,表已经被删除了,此时无需再将记录合并(merge)到辅助索引中。

mysql> show engine innodb status\G;
......
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
......

3. Insert Buffer的内部实现

  通过前面的介绍可以知道Insert Buffer的使用场景是非唯一辅助索引的插入操作。但是对于Insert Buffer具体是什么,以及内部怎么实现还处于模糊阶段。

  其实Insert Buffer的数据结构是一颗B+树。在MySQL 4.1之前的版本中每张表有一颗Insert Buffer B+树。而在现在的版本中,全局只有一颗Insert Buffer B+树,负责对所有表的辅助索引进行Insert Buffer。而这颗B+树存放在共享表空间中,默认也就是idbatal中。因此,视图沟通独立表空间idb文件恢复表中数据时,往往会导致CHECK TABLE失败。这时因为表的辅助索引中数据肯恶搞还在Insert Buffer中,也就是共享表空间中,所以通过idb文件进行恢复后,还需要进行REPLACE TABLE操作来重建表上所有的辅助索引。

  Insert Buffer是一颗B+树,因此其也由叶子节点和非叶子节点组成。非叶子节点存放的是查询的search key(键值),其构造如下所示:

space | marker | offset

  search key 一共占用9个字节,其中space表示待插入记录所在表空间id,在InnoDB存储引擎中,每个表有一个唯一的space id,可以通过sapce id查询得知是哪张表。space占用4字节。marker占用1字节,它是用来兼容老版本的Insert Buffer。offset表示页所在的偏移量,占用4字节。

  当一个辅助索引要插入到页(space,offset)时,如果这个页不在缓冲池中,那么InnoDB存储引擎首先根据上述规则构造一个search key,接下来查询insert buffer这颗B+树,然后再将这条记录插入到Insert Buffer B+树的叶子节点中。

  对于插入到Insert Buffer B+树叶子节点的记录,并不是直接将待插入的记录插入,而是需要根据如下的规则进行构造:

在这里插入图片描述

  space、marker、page_no字段和之前非叶子节点中含义相同,一共占用9字节。第4个字段metadata占用4字节,其存储的内容如下:

  IBUF_REC_OFFSET_COUNT是保存两个字节的帧数,用来排序每个记录进入Insert Buffer的顺序。因为从InnoDB 1.0.x开始支持Change Buffer,所以这个值同样记录进入Insert Buffer的顺序。通过这个顺序回放(replay)才能得到记录的正确值。

名称字节
IBUF_REC_OFFSET_COUNT2
IBUF_REC_OFFSET_TYPE1
IBUF_REC_OFFSET_FLAGES1

  从叶子节点的第5列开始,就是实际插入记录的各个字段。因此相较于之前的插入记录,Insert Buffer B+树的叶子节点记录需要额外13字节的开销。

  因为启用Insert Buffer索引后,辅助索引页(space,page_no)中的记录可能被插入到Insert Buffer B+树中,所以为了保证每次Merge Insert Buffer页必须成功,还需要有一个特殊的页来标记每个辅助索引页(space,page_no)的可用空间。这个页的类型为Insert Buffer Bitmap。

  每个Insert Buffer Bitmap页用来追踪16384个辅助索引页,也就是256个区(Extent)。每个Insert Buffer Bitmap页都在16384个页的第二个页中。

  每个辅助索引页在Insert Buffer Bitmap页中占用4位(bit),由如下三个部分组成:

名称大小(bit)说明
IBUF_BITMAP_FREE2表示该辅助索引的可用空间数量
0 表示无可用剩余空间
1 表示剩余空间大于1/32页(512字节)
2 表示剩余空间大于1/16页
3 表示剩余空间大于1/8页
IBUF_BITMAP_BUFFERED11 表示该辅助索引页有记录被缓存在Insert Buffer B+树中
IBUF_BITMAP_IBUF11 表示该页为Insert Buffer B+树的索引页

4. Merge Insert Buffer

  通过前面的介绍可知,Insert/Change Buffer是一颗B+树。若需要实现插入记录的辅助索引不在缓冲池中,那么需要将辅助索引记录首先插入到这颗B+树中。但是Insert Buffer中的记录何时合并(merge)到真正的辅助索引中呢?

  概况的说,Merge Insert Buffer的操作可能发生以下几种情况:

  • 辅助索引页被读取到缓冲池时
  • Insert Buffer Bitmap页追踪到该辅助索引页时已经无可用空间
  • Master Thread

  第一种情况为当辅助索引页被读取到缓冲池中时,例如在这个执行正常的select查询操作,这时需要检查Insert Buffer Bitmap页,然后u企鹅人该辅助索引页是否有记录存放到Insert Buffer B+树种。若有,则将Insert Buffer B+树中该页的记录插入到该辅助索引页中。可以看到对该页多次的记录操作通过一次操作合并到原有的辅助索引页中,因此性能会大幅提高。

  Insert Buffer Bitmap页用来追踪每个辅助索引页的可用空间,并且至少有1/32页的空间。若插入辅助索引记录时检测到插入记录后可用空间会小于1/32页,则会强制进行一个合并操作,即强制读取辅助索引页,将Insert Buffer B+树种该页的记录及待插入的记录插入到辅助索引中。

  最后一种情况,之前在分析Master Thread时曾讲到,在Master Thread线程中每秒或10秒会进行一次Merge Insert Buffer的操作,不同之处在于每次进行merge操作页数量不同。

  在Master Thread中,执行merge操作的不止是一个页,而是根据srv_innodb_io_capacity的百分比来决定真正要合并多少个辅助索引页。但InnoDB存储引擎又是根据怎样的算法来得知需要合并的辅助索引页呢?

  在Insert Buffer B+树种,辅助索引页根据(space,offset)都已排序好,所以可以根据(sapce,offset)的排序顺序进行页的选择。然而,对于Insert Buffer页的选择,InnoDB存储引擎并非采用这个方式,它随机的选择Insert Buffer B+树的一个页,读取该页种sapce及之后所需要数量的页。该算法在复杂的情况下应有更好的公平性。同时,若进行merge时,要进行merge的表已经被删除,此时可以直接丢弃已经被Insert Change Buffer的数据记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年湖北监理工程师考试时间、报名时间、报考条件是什么?

2023年湖北监理工程师考试时间、报名时间、报考条件是什么? 一、2023年湖北监理工程师考试时间: 参考往年的监理工程师考试时间,预计考试时间为5月份。 二、2023年湖北监理工程师报名时间: 2023年湖北监理工程师报名时间预计3月份…

单例模式【JavaEE初阶】

一、单例模式的概念 单例模式是一种常见的设计模式 。单例模式希望:有些对象,在一个程序中应该只有唯一一个实例,就可以使用单例模式 。换句话说,在单例模式下,对象的实例化被限制了,只能创建一个&#xff…

Mybatis源码解析(七):Mapper代理原理

Mybatis源码系列文章 手写源码(了解源码整体流程及重要组件) Mybatis源码解析(一):环境搭建 Mybatis源码解析(二):全局配置文件的解析 Mybatis源码解析(三):映射配置文件的解析 Mybatis源码解析(四):s…

使用R语言对S&P500股票指数进行ARIMA + GARCH交易策略

在本文中,我想向您展示如何应用S&P500股票市场指数的交易策略。最近我们被客户要求撰写关于交易策略的研究报告,包括一些图形和统计输出。 通过组合ARIMA GARCH模型,从长期来看,我们可以超过“买入并持有”方法。 相…

【MySQL基础】常用指令详解

如果看不清未来,就走好当下的路,做你此刻该去做的事。——《冰雪奇缘2》 目录 1、进入和退出mysql 1.1进入mysql 1.2退出mysql 2、查看mysql中有哪些数据库 2.2.创建数据库 3、使用数据库 3.1开始使用数据库 3.2展示数据库中的表 4、查看表中的…

跨境电商面临“寒冬”考验,如何转型升级入局新赛道(Starday)

近几年随着互联网和高新技术的飞速发展,加之疫情下各国海外贸易政策的管理,跨境贸易模式不断地创新升级,现今的跨境贸易模式已经从线下交易上升为线上交易,各种基于互联网商务网站的电子商务业务和网络公司开始不断地涌现&#xf…

WebDAV之葫芦儿•派盘+FolderSync

FolderSync 支持WebDAV方式连接葫芦儿派盘。 随着业务发展,文件数据增长,如文档更新、资料下载、拍照录像等。如何更好的管理这些资料,不出现丢失的问题就成为了一个很大的问题。也正是有了类似的需求,现在网络上出现了很多的文件同步备份软件。那么,文件同步备份软件哪…

Thread类的start()方法创建线程的底层分析

在Java中通过如下简单代码就可以创建一个新线程 Thread thread new Thread(new Runnable() {Overridepublic void run() {//do something} }); thread.start(); 在start()中又调用了start0(),它才是真正创建线程的方法。 public synchronized void start() {gro…

安全机制(security) - 加解密算法 - 对称加密 - 加解密模式

说明 大部分对称加密算法支持多种加密模式,每种模式的运算结果也不相同。加解密模式是分组加密算法通用的机制,不同算法可能支持相同的加密模式,不同算法支持的加密模式也可能不同。加密和解密需要使用相同的模式才能得到正确的结果。不同的…

CANOE功能介绍

1.CANoe主界面 当计算机安装完CANoe后,用户只需选择“开始”→“所有程序 ”→Vector CANoe 11.0→CANoe 11.0 系 统 菜 单 命 令 即 可 启 动CANoe。 为了快速熟悉CANoe的常用功能,我们可以打开Vector官方的自带例程,一边学习一边实践相关功…

超算/先进计算如何改变现如今对的生活

算力作为新一代的“石油”,与超算/先进计算有着不可分割的紧密联系。 通俗而言,算力泛指计算能力,即数据处理能力。算力大小代表数据处理能力的强弱。从远古的结绳计算到近代的机械式计算,再到现代的数字电子计算,特别…

Ajax学习:设置CROS响应头实现跨域(跨域资源共享)

CROS:跨域资源共享、是官方的跨域解决方案&#xff0c;特点不需要在客户端做任何特殊的操作&#xff0c;完全在服务器中处理&#xff08;支持get post 等&#xff09; 客户端做ajax请求&#xff0c;服务端做相应头设置就可以实现跨域&#xff1a; <!DOCTYPE html> <h…

如何快速构建研发效能度量的指标体系?

本月初&#xff0c;没毛病软件公司的研发总监 Kevin 在参加完公司管理层月度例会后&#xff0c;心情非常糟糕...... 刚才会议中&#xff0c;老板很严肃地问研发总监 Kevin&#xff1a;“我在会议前接到了客户的投诉电话&#xff0c;说产品出现了 Bug&#xff0c;这已经不是第一…

.net-----Windows 窗体应用程序包括控件,对话框,多重窗体,绘制图形,菜单和工具栏

目录前言Windows窗体应用程序概述&#xff1b;窗体和大部分控件常用的事件创建Windows窗体应用程序使用Visual Studio集成开发环境实现Hello World程序使用常用Windows窗体控件&#xff1b;Label、TextBox、RichTextBox、Button应用示例单选按钮、复选框和分组【例】RadioButto…

(附源码)springboot物流配货管理系统 毕业设计 250858

基于springboot物流配货管理系统的设计与实现 摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题.针对物流配货等问题,对物流配货进行研究分析,然后…

电力系统机组组合优化调度(IEEE14节点、IEEE30节点、IEEE118节点)(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f4dd;目前更新&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;电力系统相关知识&#xff0c;期刊论文&…

数云融合丨知识图谱在烟草零售数字化转型中的应用

一、知识图谱的趋势 随着互联网、云计算、大数据、人工智能等信息数据技术的快速发展&#xff0c;计算机的智能化程度也越来越高&#xff0c;知识图谱作为人工智能的核心技术&#xff0c;其在数据集成、语义表示和逻辑推理等方面存在着得天独厚的优势。 2021年&#xf…

Java并发-交替打印的四种方法。

1 前言 如下图所示&#xff0c;现在有两个线程A,B&#xff1b;A打印12345&#xff0c;B打印abcde&#xff0c;结果为1a2b3c4d5e交替输出。 1.1 采用wait和notify 【分析】我们要求线程A始终先打印&#xff0c;因此在线程B先获得CPU使用时间时也应该阻塞。 细节 线程A应该打印…

【人工智能/算法】搜索求解(Solving Problemsby Searching)

文章目录一、求解与搜索二、盲目式搜索1. 深度优先搜索&#xff08;Depth First Search, DFS&#xff09;回溯搜索&#xff08;Backtracking Search&#xff09;2. 广度优先搜索&#xff08;Breadth First Search, BFS&#xff09;一致代价搜索&#xff08;Uniform-cost Search…

TLog轻量级分布式日志标记追踪神器

文章目录TLog简介项目特性安装TLogspringboot依赖spring native依赖日志框架适配方式(举例Log4j框架适配器)任务框架支持(举例XXL-JOB框架)TLog架构图TLog简介 TLog通过对日志打标签完成企业级微服务的日志追踪。它不收集日志&#xff0c;使用简单&#xff0c; 产生全局唯一的…