【MySQL高阶】19.变更缓冲区,自适应哈希索引,日志缓冲区

文章目录

  • [5. InnoDB 内存结构](#5. InnoDB 内存结构)
    • [5.4 变更缓冲区 - Change Buffer](#5.4 变更缓冲区 - Change Buffer)
      • [5.4.1 变更缓冲区的作用?](#5.4.1 变更缓冲区的作用?)
        • [5.4.1.1 为什么是二级索引?](#5.4.1.1 为什么是二级索引?)
        • [5.4.1.2 Merge(合并操作)的触发时机有哪些?](#5.4.1.2 Merge(合并操作)的触发时机有哪些?)
      • [5.4.2 变更缓冲区的主要配置项都有哪些?](#5.4.2 变更缓冲区的主要配置项都有哪些?)
      • [5.4.3 怎么查看当前变更缓冲区的信息?](#5.4.3 怎么查看当前变更缓冲区的信息?)
    • [5.5 自适应哈希索引](#5.5 自适应哈希索引)
      • [5.5.1 自适应哈希索引的作用?](#5.5.1 自适应哈希索引的作用?)
        • [5.5.1.1 为什么要创建自适应哈希索引?](#5.5.1.1 为什么要创建自适应哈希索引?)
        • [5.5.1.2 自适应哈希索引的Key - Value如何设置?](#5.5.1.2 自适应哈希索引的Key - Value如何设置?)
        • [5.5.1.3 自适应哈希索引在保存在哪里?](#5.5.1.3 自适应哈希索引在保存在哪里?)
      • [5.5.2 关于自适应哈希索引有哪些配置项?](#5.5.2 关于自适应哈希索引有哪些配置项?)
      • [5.5.3 怎么查看自适应哈希索引的信息?](#5.5.3 怎么查看自适应哈希索引的信息?)
    • [5.6 日志缓冲区](#5.6 日志缓冲区)
      • [5.6.1 日志缓冲区的作用?](#5.6.1 日志缓冲区的作用?)
      • [5.6.2 日志不通过Log Buffer直接写入磁盘不行吗?](#5.6.2 日志不通过Log Buffer直接写入磁盘不行吗?)
      • [5.6.3 Log Buffer与日志文件是如何配合工作的?](#5.6.3 Log Buffer与日志文件是如何配合工作的?)
      • [5.6.4 小结](#5.6.4 小结)

5. InnoDB 内存结构

5.4 变更缓冲区 - Change Buffer

5.4.1 变更缓冲区的作用?

  • 变更缓冲区占用Buffer Pool(缓冲池)的一部分空间,具体如图所示:
  • 变更缓冲区用来缓存对二级索引数据的修改,是一个特殊的数据结构。

    当使用 INSERT 、UPDATEDELETE 语句修改二级索引对应的数据时:

    ​ 如果对应的数据页在缓冲池中则直接更新。

    ​ 如果不在缓冲池中,那么就把修改操作缓存到变更缓冲区,这样就不用立即从磁盘读取对应的数据页了。

    当之后的读操作将对应的数据页从磁盘加载到缓冲池中时,变更缓冲区中缓存的修改操作再批量合并到缓冲池,从而达到减少磁盘I/O的目的。

    执行流程如图所示:

而正常情况,我们修改一条数据,内存和磁盘的交互过程是:

  1. 在磁盘中找到对应的数据行

  2. 数据行所在的数据页加载到内存中

  3. 在内存中完成对数据行的修改

  4. 把修改过后的数据页再写回到磁盘中

读的过程一次I/O,写的过程一次I/O

相比之下,我们节省了一次I/O的机会。
总结:

变更缓冲区用来缓存对二级索引数据的修改,当数据页没有被回载到内存中时先把修改缓存起来,等到其他查询操作发生时数据页被加载到内存后,再直接修改内存中的数据页,从而达到减少磁盘I/O的目的。


5.4.1.1 为什么是二级索引?
  • 关于索引在数据库初阶已经做了介绍,我们知道索引分为聚集索引(主键)和二级索引(自定义)

  • 由于聚集索引具有唯一性,我们分析一下聚集索引为什么不能被放入变更缓存,假设表中有一个主键( ID ),现在有两条 INSER 语句,都在插入数据时ID的值相同 (id=1) ,那么在变更缓冲区中就存在两个修改操作,如果以后要合并到缓冲池中,这时就会出现重复的主键值,所以聚集索引的修改不能被加入到变更缓冲区;

  • 与聚集索引不同,二级索引通常是不唯一的,并且向二级索引中插入数据时由于数据列不同,所以位置相对随机,同样对于删除和更新操作可能会影响不相邻的二级索引页。

    如果每次都从磁盘读取数据就会发生大量的随机I/O,以变更缓冲区的方式先将修改缓存起来,当真正的读取数据时再把修改合并到缓冲池中可以提升效率。


5.4.1.2 Merge(合并操作)的触发时机有哪些?
  1. 读取对应的数据页时;
  2. 当系统空闲或者 Slow Shutdown(慢速关闭)时,主线程发起 merge
  3. Change buffer (写缓冲)的内存空间即将耗尽时;
  4. Redo Log(重做日志) 写满时。

5.4.2 变更缓冲区的主要配置项都有哪些?

主要的配置项有缓冲类型和更改缓冲区的最大小

缓冲类型

  1. 在修改二级索引数据时变更缓冲区可以减少磁盘I/O从而提高效率,但是变更缓冲区占用了缓冲池的一部分空间,从而减少了可用于缓存数据页的内存,如果业务场景读多写少,或者表中的二级索引相对较少,那么可以考虑禁用变更缓冲区从而提高缓冲池空间。可以通过选项文件或 SET GLOBAL 语句对系统变量 innodb_change_buffering 进行设置,来控制变更缓冲区对于插入、删除操作(索引记录被标记为删除)和清除操作(当索引记录被物理删除时)的开启或禁用:

    • 删除操作:索引记录被标记为删除

    • 清除操作:索引记录被物理删除时

    • 更新操作:是插入和删除操作的组合

  • all : 默认值,缓存插入、删除标记操作和清除
  • none :不缓存任何操作
  • inserts :只缓存插入操作
  • deletes :只缓存删除标记操作
  • changes :缓存插入和删除标记操作
  • purges :缓存发生在后台的物理删除操作
  1. 更改缓冲区的最大小
  • 通过 innodb_change_buffer_max_size 系统变量可以设置更改缓冲区的最大小,默认为25,最大为50,表示更改缓冲区占缓冲池内存总大小的百分比。
  • 在有大量插入、更新和删除的业务场景中,可以考虑增加innodb_change_buffer_max_size 的值,在大部分是读多写少,比如用于报表的静态数据场景中考虑减小 innodb_change_buffer_max_size 的值
  • 需要注意的是,如果更改缓冲区占了缓冲池太多的内存空间,会导致缓冲池中的数据页更快地淘汰。
    总结:

主要的配置项有缓冲类型和更改缓冲区的最大大小


5.4.3 怎么查看当前变更缓冲区的信息?

通过使用 SHOW ENGINE InnoDB STATUS 访问 InnoDB 标准监视器输出中 INSERT BUFFER AND ADAPTIVE HASH INDEX 部分查看有关更改缓冲区状态的信息。

mysql 复制代码
mysql> SHOW ENGINE INNODB STATUS\G
*************************** 1. row ***************************
 Type: InnoDB
 Name:
Status:
=====================================
... # 省略
-------------------------------------
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
Hash table size 4425293, used cells 32, node heap has 1 buffer(s)
13577.57 hash searches/s, 202.47 non-hash searches/s
... # 省略

5.5 自适应哈希索引

  • 自适应哈希索引在内存中的位置

5.5.1 自适应哈希索引的作用?

  • 自适应哈希索引可以使InnoDB存储引擎在不牺牲事务特性和可靠性以及缓冲池空间足够的前提下提升效率,使用起来更像是一个内存数据库,哈希索引根据经常访问的索引页自动构建;

  • 根据InnoDB内部的监控机制,如果监控到某些查询通过建立哈希索引可以提高性能,则自动对这个页创建哈希索引,这个过程称为自适应,所以叫自适应哈希索引;

    例如:某个查询条件经常用到,超过一定次数后就建立这个查询条件位置和查询条件的哈希索引,节省了寻路的时间。

  • 如果表完全放在内存中,则哈希索引可以通过直接查找任何元素来加快查询速度

总结:

  • 自适应哈希索引的主要作用就是提升查询效率

5.5.1.1 为什么要创建自适应哈希索引?
  • InnoDB存储引擎的数据存储于B+树中,B+树通常只有35层,但从根节点到叶节点的寻路涉及到多层页面内记录的比较,即使所有路径上的页面都在内存中,也非常消耗CPU的资源
  • InnoDB对寻路的开销进行了优化,比如寻路结束后将cursor缓存起来方便下次查询复用;尽可能的避免单词寻路开销,Adaptive hash index(AHI)便是为此而设计,可以理解为B+树的索引
  • 本质上是通过缩短寻路路径(Search Path)从而提升MySQL查询性能的一种方式

5.5.1.2 自适应哈希索引的Key - Value如何设置?

以查询条件为key,B+树页的地址为valueHash Index


5.5.1.3 自适应哈希索引在保存在哪里?

自适应哈希索引会占用缓冲池一部分内存区域,在缓冲池初始化后被初始化,为了避免AHI的锁竞争压力,AHI支持分区,可以使用innodb_adaptive_hash_index_parts 参数配置分区个数,默认为 8

注意:自适应哈希索引是InnoDB内部的优化方式,外部不能干预


5.5.2 关于自适应哈希索引有哪些配置项?

  • 通过设置系统变量 innodb_adaptive_hash_index 开启或关闭自适应哈希索引
    • 在选项文件中设置系统变量 innodb_adaptive_hash_index=[1|0] 实现开启与关闭
    • 通过命令行选项 --skip-innodb-adaptive-hash-index 也可以关闭自适应哈希索引
  • 每个自适应散列索引被绑定到不同的分区中,每个分区有不同的锁保护,分区数量由系统变量innodb_adaptive_hash_index_parts 控制,默认置为 8 ,最大值为 512

5.5.3 怎么查看自适应哈希索引的信息?

通过使用 SHOW ENGINE InnoDB STATUS 访问 InnoDB 标准监视器输出中 INSERT BUFFER AND ADAPTIVE HASH INDEX 部分查看自适应哈希索引使用信息,如果锁争抢过多,可以考虑增加自适应哈希索引分区数量或禁用自适应哈希索引。

mysql 复制代码
mysql> SHOW ENGINE INNODB STATUS\G
*************************** 1. row ***************************
 Type: InnoDB
 Name:
Status:
=====================================
... # 省略
-------------------------------------
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
 # 字节为单位,占用内存空间总量
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 4 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 1 buffer(s) 
# 计算自适应hash索引带来的收益以及付出,确定是否开启自适应hash索引
0.00 hash searches/s, 0.00 non-hash searches/s

5.6 日志缓冲区

  • 日志缓冲区在内存中的位置

5.6.1 日志缓冲区的作用?

  • 日志缓冲区是服务器启动时向操作系统申请的一片连续的内存区域,存储即将要写入磁盘日志文件的数据(也就是生成的日志)。
  • 在对数据库进行DML操作时,InnoDB会记录对应操作的日志,比如为保证数据完整性实现数据库崩溃恢复的Redo Log,这些日志会首先写入Log Buffer中,从而解决同步写磁盘导致的性能问题,然后根据不同落盘策略最终写入磁盘

5.6.2 日志不通过Log Buffer直接写入磁盘不行吗?

如果日志不通过Log Buffer直接写入磁盘,那么每次进行DML操作都会进行一次磁盘I/O,这样会严重影响效率,所以把日志统一写入内存中的Log Buffer,根据刷盘策略统一进行落盘操作,可以实现一次磁盘I/O写入多条日志,从而提升效率


5.6.3 Log Buffer与日志文件是如何配合工作的?

关于Log Buffer与日志文件之间的交互过程、RedoLog的结构和RedoLog的写入时机,本专题最后在介绍磁盘上的Redo Log时会详细讲解它他的工作原理


5.6.4 小结

  • InnoDB内存结构主要分为:

    1. Buffer Pool 缓冲池、
    2. Change Buffer 变更缓冲区
    3. adaptive_hash_index 自适应哈希索引
    4. Log Buffer 日志缓冲区
  • 缓冲池

    • 内存中的主要工作区域

    • 缓冲池中包含至少一个 Instances ,每个 Instances 中包含至少一个ChunkChunk 管理着多个数据页

    • 缓冲池中使用控制块与数据页建立对应关系,通过双向链表连接每个控制块,从而管理数据页

    • 缓冲池中有三个链表分别是 Free List 、 LRU ListFlush List :

      • Free List :只管理Free

      • LRU List :管理 Clean页和Dirty

      • Flush List :只管理Dirty

    • 缓冲池淘汰策略采用变形的最近最少使用算法LRU

  • 变更缓冲区

    • 用来缓存对二级索引数据的修改,从而减少磁盘的IO次数以提升效率
  • 自适应哈希索引

    • 为频繁使用的查询条件和对应的数据页建立映射关系,从而提升内存级别的查询效率
  • 日志缓冲区

    • 把日志统一写入内存中的Log Buffer,根据刷盘策略统一进行落盘操作,从而减少磁盘的IO次数以提升效率
相关推荐
晴天¥2 小时前
Oracle中的监听配置与管理(动态、静态监听配置对比以及listener.ora和tnsnames.ora)
数据库·oracle
ylscode2 小时前
Comodo防火墙曝致命零日漏洞:单个IPv6数据包即可触发Windows蓝屏死机
运维·网络·windows·安全·安全威胁分析
瀚高PG实验室3 小时前
python连接HGDB超时
数据库·瀚高数据库·highgo
x***r1513 小时前
nvm-windows 安装教程:Node.js 多版本管理(避坑版)
windows·node.js
一个假的前端男3 小时前
windows flutter 适配鸿蒙
windows·flutter·harmonyos
闪电悠米3 小时前
黑马点评-Redisson-01_why_redisson
java·服务器·网络·数据库·缓存·wpf
Counter-Strike大牛4 小时前
SpringBoot2.7.10+MyBatisPlus实现MySQL+DM双数据库切换
数据库·mysql
dllxhcjla4 小时前
Redis
数据库·redis·缓存
睡不醒男孩0308234 小时前
数据库高可用运维实操指南:基于CLup的PostgreSQL生产环境自动化管理
运维·数据库·postgresql