热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL从InnoDB的内存结构、磁盘结构到update过程分析

Innodb内存结构Innodb的内存结构主要分为3个部分:BufferPool、ChangeBuffer、AdaptiveHashIndex,另外还有一个(redo)logbuf

Innodb 内存结构

Innodb的内存结构主要分为 3 个部分: Buffer Pool、Change Buffer、Adaptive HashIndex,另外还有一个(redo)log buffer。

缓冲池 Buffer Pool

首先,InnnoDB的数据都是放在磁盘上的,InnoDB操作数据有一个最小的逻辑单位,叫做页(索引页和数据页)。我们对于数据的操作,不是每次都直接操作磁盘,因为磁盘的速度太慢了。 InnoDB使用了一种缓冲池的技术,也就是把磁盘读到的页放到一块内存区域里面。这个内存区域就叫Buffer Pool。

 

 下一次读取相同的页,先判断是不是在缓冲池里面,如果是,就直接读取,不用再次访问磁盘。

修改数据的时候,先修改缓冲池里面的页。内存的数据页和磁盘数据不一致的时候,我们把它叫做脏页。InnoDB里面有专门的后台线程把Buffer Pool的数据写入到磁盘,每隔一段时间就一次性地把多个修改写入磁盘,这个动作就叫做刷脏。

Buffer Pool缓存的是页面信息,包括数据页、索引页。查看服务器状态,里面有很多跟Buffer Pool相关的信息:

SHOW STATUS LIKE '%innodb_buffer_pool%';

 

 这些状态都可以在官网查到详细的含义,用搜索功能。 Buffer Pool默认大小是128M(134217728字节),可以调整。另外,查看参数(系统变量)的命令是:

SHOW VARIABLES like '%innodb_buffer_pool%';

内存缓冲区对于提升读写性能有很大的作用。思考一个问题:当需要更新一个数据页时,如果数据页在BufferPool中存在,那么就直接更新好了。否则的话就需要从磁盘加载到内存,再对内存的数据页进行操作。也就是说,如果没有命中缓冲池,至少要产生一次磁盘IO,有没有优化的方式呢?


Change Buffer(写缓冲)

如果这个数据页不是唯一索引(注:唯一索引就是在同一字段下不能有相同值),也就不需要从磁盘加载索引页判断数据是不是重复(唯一性检查)。这种情况下可以先把修改记录在内存的缓冲池中,从而提升更新语句(Insert、Delete、Update)的执行速度。这一块区域就是 Change Buffer。5.5 之前叫Insert Buffer 插入缓冲,现在也能支持delete和update。最后把 Change Buffer 记录到数据页的操作叫做 merge

什么时候发生 merge?有几种情况:在访问这个数据页的时候,或者通过后台线程、或者数据库shut down、redo log写满时触发


(redo) Log Buffer

思考一个问题:如果BufferPool里面的脏页还没有刷入磁盘时,数据库宕机或者重启,这些数据丢失。如果写操作写到一半,甚至可能会破坏数据文件导致数据库不可用。为了避免这个问题, InnoDB把所有对页面的修改操作专门写入一个日志文件,并且在数据库启动时从这个文件进行恢复操作(实现crash-safe)——用它来实现事务的持久性。

 

 这个文件就是磁盘的redo log(叫做重做日志),对应于/var/lib/mysql/目录下的ib_logfile0和ib_logfile1,每个48M。

 

 这种日志和磁盘配合的整个过程,其实就是 MySQL 里的 WAL 技术(Write-Ahead Logging),它的关键点就是先写日志,再写磁盘

show variables like 'innodb_log%';



  • innodb_log_file_size:指定每个文件的大小,默认 48M

  • innodb_log_files_in_group:指定文件的数量,默认为 2

  • innodb_log_group_home_dir:指定文件所在路径,相对或绝对。如果不指定,则为 datadir 路径。

刷盘是随机I/O,而记录日志是顺序I/O,顺序I/O效率更高。因此先把修改写入日志,可以延迟刷盘时机,进而提升系统吞吐。

redo log,它又分成内存和磁盘两部分。redo log有什么特点?

 

 



  1. redo log是InnoDB存储引擎实现的,并不是所有存储引擎都有。

  2. 不是记录数据页更新之后的状态,而是记录这个页做了什么改动,属于物理日志。

  3. redo log的大小是固定的,前面的内容会被覆盖

这里再强调一次,redolog的内容主要是用于崩溃恢复。磁盘的数据文件,数据来自bufferpool。redo log 写入磁盘,不是写入数据文件。

当然redo log也不是每一次都直接写入磁盘,在Buffer Pool里面有一块内存区域(Log Buffer)专门用来保存即将要写入日志文件的数据,默认16M,它一样可以节省磁盘IO。


update过程

有了这些日志之后,我们来总结一下一个更新操作的流程,这是一个简化的过程(name原值是zhangsan)。

update user set name='penyuyan' where id=1;


  1. 事务开始,从内存或磁盘取到这条数据,返回给Server 的执行器;

  2. 执行器修改这一行数据的值为penyuyan;

  3. 记录 name=zhangsan 到 undo log

  4. 记录 name=zhangsan 到redo log

  5. 调用存储引擎接口,在内存(Buffer Pool)中修改 name=zhangsan;

  6. 事务提交

另外,内存和磁盘之间,工作着很多后台线程。后台线程的主要作用是负责刷新内存池中的数据和把修改的数据页刷新到磁盘。后台线程分为:master thread,IO thread,purge thread,page cleaner thread。



  • master thread:负责刷新缓存数据到磁盘并协调调度其它后台进程

  • IO thread:分为 insert buffer、 log、 read、 write进程。分别用来处理 insert buffer、重做日志、读写请求的IO回调

  • purge thread:用来回收undo 页

  • page cleaner thread:用来刷新脏页

除了 InnoDB 架构中的日志文件,MySQL 的 Server 层也有一个日志文件,叫做binlog,它可以被所有的存储引擎使用。

binlog 以事件的形式记录了所有的DDL和DML语句(因为它记录的是操作而不是数据值,属于逻辑日志),可以用来做主从复制和数据恢复。跟redo log不一样,它的文件内容是可以追加的,没有固定大小限制。

在开启了binlog功能的情况下,我们可以把binlog导出成SQL语句,把所有的操作重放一遍,来实现数据的恢复。binlog的另一个功能就是用来实现主从复制,它的原理就是从服务器读取主服务器的binlog,然后执行一遍。

有了这两个日志之后,我们来看一下一条更新语句是怎么执行的:

 



推荐阅读
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • 本文介绍了在PostgreSQL中批量导入数据时的优化方法。包括使用unlogged表、删除重建索引、删除重建外键、禁用触发器、使用COPY方法、批量插入等。同时还提到了一些参数优化的注意事项,如设置effective_cache_size、shared_buffer等,并强调了在导入大量数据后使用analyze命令重新收集统计信息的重要性。 ... [详细]
  • Nginx Buffer 机制引发的下载故障
    Nginx ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文介绍了使用数据库管理员用户执行onstat -l命令来监控GBase8s数据库的物理日志和逻辑日志的使用情况,并强调了对已使用的逻辑日志是否及时备份的重要性。同时提供了监控方法和注意事项。 ... [详细]
  • 本文总结和分析了JDK核心源码(2)中lang包下的基础知识,包括常用的对象类型包和异常类型包。在对象类型包中,介绍了Object类、String类、StringBuilder类、StringBuffer类和基本元素的包装类。在异常类型包中,介绍了Throwable类、Error类型和Exception类型。这些基础知识对于理解和使用JDK核心源码具有重要意义。 ... [详细]
  • 设备模型三(潜谈sysfs)
    前言引出一个问题:假设sysaxx,xx是kobja的属性文件,当对xx进行写操作时,即echo‘1’sysaxx实际上,调用了kobja的ktype中定义的接口函 ... [详细]
  • oracle 数据库正常关闭情况下当前日志损坏的恢复(转) ... [详细]
author-avatar
冬日暖光816
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有