MySQL必知必会:用十一张图讲清楚,当你CRUD时BufferPool中发生了什么!以及BufferPool的优化!

一、收到了大佬们的建议

1、篇幅偏短,建议稍微加长一点。

这点说的确实挺对,有的篇幅确实比较短,针对这个提议我会考虑将相似的话题放在一篇文章中。但是这可能会导致我中断每天更新的步调,换成隔几天发一篇的步调(但是这个系列的文章一定会写完的!)

2、Buffer Pool、LRU List、Flush List、Free List相辅相成,建议放在一起串讲。

说的没错,是应该一起串讲。于是有了这篇加餐的文章:下面让我们就一起看下,当你执行CURD时,InnoDB的Buffer Pool中都发生了什么!以及Buffer Pool的优化!


二、Let‘s go

你知道的,MySQL对数据的增删改查都是内存中完成的,这块内存就是Buffer Pool。

你可以像下面这样查看下你的MySQL的Buffer的Buffer Pool的默认大小

上图中的0.125单位为GB,转换成MB就是 1024* 1/8 = 128MB

总结来说,就是MySQL启动后就会为我们初始化好这块Buffer Pool。如下图:

你可以看着上图,然后读下面这段话:

MySQL以数据页为单位,从磁盘中读取数据。数据页被读取到内存中,所谓的内存其实就是Buffer Pool。

Buffer Pool中维护的数据结构是缓存页,而且每个缓存页都有它对应的描述信息。

由于MySQL刚启动,还没有从磁盘中读取任何数据页到内存(Buffer Pool)中,那此时Buffer Pool中所有的缓存页其实都是空的。

除了缓存页之外,你还能看到Buffer Pool中存在三个双向链表。分别是FreeList、LRUList以及FlushList。这三个双向链表中维护着缓存页的描述信息。


三、好,假设你读取出来了1个数据页

当你通过select读取出一个数据页之后,是需要将这个数据页加载进Buffer Pool中的缓存页中的。

那问题来了,MySQL怎么知道该将你读取出来的数据页存放在那个缓存页中呢?相信你看了上图应该也能想到答案了。FreeList这个双向链表不是存放了空闲的缓存页的描述信息吗?那从FreeList中取出一个空间缓存页的描述信息不就好了?于是得到了下面这张图:

啰嗦一点:对这张图稍微做一下解读:

InnoDB会将你读取出来的数据页加载进Buffer Pool中的缓存页中,然后缓存页的描述信息也会被维护进LRU链表中。链表做了冷热数据分离优化,5/8的区域是热数据区域,3/8的区域算是冷数据区域。(本质上它们都是双向链表),而你新读取的数据页会被放在冷数据区的靠前的位置上。

如果你将该数据页读取出来加载进缓存页中后,间隔没到1s,就使用该缓存页。那么InnoDB是不会将这个描述信息移动到5/8的热数据区域的。

但是当超过1s后,你又去读这个数据页。那这个数据页的描述信息就会被放到热数据区域。如下图:


四、假设你一次性读取出来了好多数据页

白日梦在第 6 篇文章中跟大家分享过,MySQL是存在预读机制的,感兴趣可关注公众号阅读。

假设触发了MySQL的预读机制。一次性从磁盘中读取来N多个缓存页。会得到下面这张图:

因为发生了预读,所以你的一次磁盘IO读出了大量的数据页,但是这些数据页中很可能是有一些是你根本不需要的,仅仅是预读把它们级联查出来了。这时按老规矩,从FreeList中找到空闲的缓存页信息,然后将其从FreeList中移除。根据找到的空闲缓存页的描述信息,将从磁盘中读取出来的数据页加载进去。相应的该缓存页的描述信息也会被维护进LRU链表的冷数据区域。

这时你就会发现这种冷热数据分离的机制多么妙!即使发生了预读又怎么样?根本没有机会将热数据区的描述信息1挤下去。当内存不够用了需要将部分缓存页刷新到磁盘中时,那就从冷数据区域开始刷新好了,反正他们本来就不经常被使用。

同样的,当你超过1s后又访问了冷数据区的缓存页,比如访问了缓存页66和数据页67,该缓存页对应的描述信息是会被提升到热数据区,于是有了下面这张图:

那,如果你访问上图中的数据页67,它会移动到描述信息66所在节点的前面去吗?

其实MySQL的LRU链表做了优化,数据67是不会往前跑的。


五、假设你修改了某数据页

假设你执行了update xxx set xxx where id in (xxx,xxx,xxx);

而符合条件的数据行恰巧就在描述信息1、描述信息66、描述信息67所指向的缓存页中,那BufferPool中会发生什么呢?

如下图:

你会看到,被你修改了的缓存页的描述信息,被添加到了FlushList这个双向链表中。

想必看到这里你已经知道了,原来FlushList中的节点存放就是被修改了脏数据页的描述信息块。

随着MySQL被使用的时间越来越长,BufferPool的大小就越来越小。等它不够用的时候,就会将部分LRU中的数据页描述信息移除出去,这时如果发现被移除出来的数据页在FLushList中,就会触发fsync的操作,触发随机写磁盘。如果该数据页是干净的,那移除出去就好了。其他也不用干啥。

举个例子:假设需要将描述信息66、描述信息67指向的缓存页落盘。会得到下面这张脑图:

描述信息66、67指向的缓存页被刷新进磁盘。 同时从FlushList中将其移除,然后存入FreeList中。完成一个循环

当然,将脏数据页刷新进磁盘的时机除了上图中说的还有好多种情况,白日梦在上一篇文章中有分享。可关注公众号查看哦


下面再看一下关于Buffer Pool的设置和相关的优化。

六、配置Buffer Pool的大小

buffer pool越大,MySQL的性能就越强悍。你可以像下面这样配置Buffer Pool的大小。

mysql> SET GLOBAL innodb_buffer_pool_size=402653184;

七、配置多个Buffer Pool的实例

你可以为MySQL实例配置多个Buffer Pool,每个Buffer Pool各自负责管理一部分缓存页,并且有自己独立的LRU、Free、Flush链表。

当有多线程并发请求过来时,线程可以在不同的Buffer Pool中执行自己的操作,MySQL性能就会得到很大的提升

在my.d中进行配置

[server]
innodb_buffer_pool_size = xxx
innodb_buffer_pool_instances = 4

意思是将总容量为xxx的buffer pool划分成4个实例。每个实例都有 xxx/4 的容量。

参数innodb_buffer_pool_instances的最大值为64,并且想让该参数生效,innodb_buffer_pool_size容量至少是1G。

可以像下面这样查看你的MySQL的Buffer Pool实例状态。


八、揭秘BufferPool的真实结构

现实中Buffer Pool动辄就占用好几G的内存,相对于直接申请几G的内存完成扩容,MySQL有更优雅的实现方式。

为了实现动态调整Buffer Pool的大小。MySQL设计了chunk 机制。

可以看上图脑补一下Buffer Pool 以及 Chunk长什么样。

总的来说:就是将每一个 Buffer Pool Instance 更加细力度化。将Buffer Pool拆分成更小的独立单元。

每个Buffer Pool划分成多个chunnk,每个chunk中维护一部分缓存页、缓存页的描述信息。同属于一个Buffer Pool的chunk共享该Buffer Pool的lru、free、flush链表。

块大小由参数innodb_buffer_pool_chunk_size控制,默认值为 128M

该参数可以像下面这样修改:

shell> mysqld --innodb-buffer-pool-chunk-size=134217728

或者通过配置文件自定义

[mysqld]
innodb_buffer_pool_chunk_size=134217728

九、看一看Buffer Pool相关的参数

执行命令

> mysql show engine innodb status

image-20201103070730462

十、如何规划你的Buffer Pool大小

推荐将Buffer Pool的总大小设置为服务器内存的 50%~60%左右

BufferPool总大小 = (chunkSize * bufferPoolInstanceNum)*2


十一、Buffer Pool的预热机制

这种机制实际上是想让重启后的MySQL快速适应大规模的流量请求。

InnoDB 在服务器关闭时为每个缓冲池保存一部分最近高频使用的页面,并在服务器启动时恢复这些页面。保存多大比例的缓存页由参数innodb_buffer_pool_dump_pct控制。

在启动时还原缓冲池,实际上会缩短预热的时间。

你可以通过下面的方式配置该参数

# 通过命令
SET GLOBAL innodb_buffer_pool_dump_pct=40;

# 通过文件
[mysqld]
innodb_buffer_pool_dump_pct=40

参数innodb_buffer_pool_dump_at_shutdown控制 MySQL关闭时保存缓冲池的状态,默认为on的状态。

启动参数--innodb-buffer-pool-load-at-startup 表示启动MySQL的时候恢复缓冲池中的状态,默认也是开启的。


关注送书!《Netty实战》

文章公号 首发!连载中!关注微信公号回复:“抽奖” 还可参加抽

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


navicat查看某个表的所有字段的详细信息 navicat设计表只能一次查看一个字段的备注信息,那怎么才能做到一次性查询表的信息呢?SELECT COLUMN_NAME,COLUMN_COMMENT,COLUMN_TYPE,COLUMN_KEY FROM information_schema.CO
文章浏览阅读4.3k次。转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52768613前言:数据库每天的数据不断增多,自动删除机制总体风险太大,想保留更多历史性的数据供查询,于是从小的hbase换到大的hbase上,势在必行。今天记录下这次数据仓库迁移。看下Agenda:彻底卸载MySQL安装MySQL_linux服务器进行数据迁移
文章浏览阅读488次。恢复步骤概要备份frm、ibd文件如果mysql版本发生变化,安装回原本的mysql版本创建和原本库名一致新库,字符集都要保持一样通过frm获取到原先的表结构,通过的得到的表结构创建一个和原先结构一样的空表。使用“ALTER TABLE DISCARD TABLESPACE;”命令卸载掉表空间将原先的ibd拷贝到mysql的仓库下添加用户权限 “chown . .ibd”,如果是操作和mysql的使用权限一致可以跳过通过“ALTER TABLE IMPORT TABLESPACE;”命令恢_alter table discard tablespace
文章浏览阅读225次。当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化:单表优化除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑、部署、运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的。而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量:字段尽量使用TINYINT、SMALLINT、MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNEDVARCHAR的长度只分配_开发项目 浏览记录表 过大怎么办
文章浏览阅读1.5k次。Mysql创建、删除用户MySql中添加用户,新建数据库,用户授权,删除用户,修改密码(注意每行后边都跟个;表示一个命令语句结束):1.新建用户登录MYSQL:@>mysql -u root -p@>密码创建用户:mysql> insert into mysql.user(Host,User,Password) values("localhost_删除mysql用户组
MySQL是一种开源的关系型数据库管理系统,被广泛应用于各类应用程序的开发中。对于MySQL中的字段,我们需要进行数据类型以及默认值的设置,这对于数据的存储和使用至关重要。其中,有一个非常重要的概念就是MySQL字段默认字符串。 CREATE TABLE `my_...
MySQL是一个流行的开源关系型数据库管理系统,广泛应用于Web应用程序开发、数据存储和管理。在使用MySQL时,正确设置字符集非常重要,以确保数据的正确性和可靠性。 在MySQL中,字符集表示为一系列字符和字母的集合。MySQL支持多种字符集,包括ASCII、UTF...
MySQL存储函数 n以内偶数 MySQL存储函数能够帮助用户简化操作,提高效率,常常被用于计算和处理数据。下面我们就来了解一下如何使用MySQL存储函数计算n以内的偶数。 定义存储函数 首先,我们需要定义一个MySQL存储函数,以计算n以内的偶数。下...
MySQL是一个流行的关系型数据库管理系统,基于客户机-服务器模式,可在各种操作系统上运行。 MySQL支持多种字符集,不同的字符集包括不同的字符,如字母、数字、符号等,并提供不同的排序规则,以满足不同语言环境的需求。 //查看MySQL支持的字符集与校对规...
在MySQL数据库中,我们有时需要对特定的字符串进行截取并进行分组统计。这种操作对于数据分析和报表制作有着重要的应用。下面我们将讲解一些基本的字符串截取和分组统计的方法。 首先,我们可以使用substring函数对字段中的字符串进行截取。假设我们有一张表stude...
MySQL提供了多种字符串的查找函数。下面我们就一一介绍。 1. LIKE函数 SELECT * FROM mytable WHERE mycolumn LIKE 'apple%'; 其中"apple%"表示以apple开头的字符串,%表示任意多个字符...
MySQL 是一种关系型数据库管理系统,广泛应用于各种不同规模和类型的应用程序中。在 MySQL 中,处理字符串数据是很常见的任务。有时候,我们需要在字符串的开头添加一定数量的 0 ,以达到一定的位数。比如,我们可能需要将一个数字转换为 4 位或 5 位的字符串,不足的...
MySQL是一种流行的关系型数据库管理系统,支持多种数据类型。以下是MySQL所支持的数据类型: 1. 数值型数据类型: - TINYINT 保存-128到127范围内的整数 - SMALLINT 保存-32768到32767范围内的整数 - MEDIU...
MySQL中存储Emoji表情字段类型 在现代互联网生态中,表情符号已经成为人们展示情感和思想的重要方式之一,因此将表情符号存储到数据库中是一个经常出现的问题。MySQL作为最流行的开源关系型数据库管理系统之一,也需要能够存储和管理这些表情符号的字段类型。 UT...
MySQL是一种关系型数据库管理系统。在MySQL数据库中,有多种不同的数据类型。而其中,最常见的数据类型之一就是字符串类型。在MySQL中,字符串类型的数据通常会被存储为TEXT或VARCHAR类型。 首先,让我们来看一下VARCHAR类型。VARCHAR是My...
MySQL字符串取整知识详解 MySQL是一种开源的关系型数据库管理系统,广泛应用于各个领域。在使用MySQL过程当中,我们经常需要对数据进行取整操作。本文将介绍如何使用MySQL字符串取整来处理数据取整问题。 什么是MySQL字符串取整? MySQL...
使用MySQL进行数据存储是现代应用程序开发中一个非常重要的组成部分。在MySQL中,数据存储的一个重要特点就是字符长度无限制。在下文中,我们将会详细探讨MySQL字符长度无限制的特征和优势。 什么是MySQL字符长度无限制? MySQL字符长度无限制是指在...
在MySQL中,常常会涉及到字符串和数字之间的比较。然而它们有着不同的排序规则,因此需要注意对它们进行正确的比较。 首先我们来看一下数字比较。 SELECT 1 < 2; -- 返回 1 SELECT 2 > 1; -- 返回 1 SELEC...
MySQL是一种流行的关系型数据库管理系统,可以处理各种不同类型的数据。其中字符串是MySQL中最重要的数据类型之一,因为它可以存储各种不同的数据,例如邮件地址、文本信息、数字等等。在MySQL中,有时候我们需要将字符串按照某个符合进行分隔,例如将一条包含多个数字的字符...
在MySQL中,我们经常需要将字符串与变量拼接起来,以便满足数据操作的需求。可以使用CONCAT函数来进行字符串与变量的拼接,下面是一个使用CONCAT函数的例子: SELECT CONCAT('Hello', ' ', 'world'); 这个例子...