1、什么是数据缓冲池:
- 1.InnoDB 存储引擎是
以页为单位
来管理存储空间的,我们进行的增删改查操作其实本质上都是在访问页面(包括读页面、写页面、创建新页面等操作)
,而磁盘 I/O 需要消耗的时间很多,而在内存中进行操作,效率则会高很多,为了能让数据表或者索引中的数据随时被我们所用,DBMS 会申请占用内存来作为数据缓冲池
,在真正访问页面之前,需要把在磁盘上的页缓存到内存中的 Buffer Pool 之后才可以访问
- 2.这样做好处是可以让磁盘活动最小化,从而
减少与磁盘直接进行 I/O 的时间
,这种策略对提升 SQL 语句的查询性能来说至关重要。如果索引的数据在缓冲池里,那么访问的成本就会降低很多
2、缓冲池 vs 查询缓存
缓冲池和查询缓存不是一个东西
2.1.缓冲池(Buffer Pool)
1.在
InnoDB 存储引擎
中,缓冲池都包括了哪些内容??
- 1.在 InnoDB 存储引擎中有一部分数据会放到内存中,缓冲池则占了这部分内存的大部分,它用来存储各种数据的缓存,如下图所示:
- 2.从图中,你能看到
InnoDB 缓冲池包括了数据页、索引页、插入缓冲、锁信息、自适应 Hash 和数据字典信息
等。每个数据页的大小默认是16kb,可以存储16kb的内容
2.缓冲池的重要性:
- 1.对于使用
InnoDB
作为存储引擎的表来说,不管是用于存储用户数据的索引(包括聚簇索引和二级索引),还是各种系统数据,都是以页
的形式存放在表空间中的,而所谓的表空间只不过是InnoDB对文件系统上一个或几个实际文件的抽象,也就是说我们的数据说到底还是存储在磁盘上的。 - 2.但是磁盘的速度慢的跟乌龟一样,怎么能配得上"快如风,疾如电"的CPU呢?这里,
缓冲池可以帮助我们消除CPU和磁盘之间的鸿沟
。所以InnoDB存储引擎在处理客户端的请求时,当需要访问某个页的数据时,就会把完整的页的数据全部加载到内存中
,也就是说即使我们只需要访问一个页的一条记录,那也需要先把整个页的数据加载到内存中。 - 3.将整个页加载到内存中后就可以进行读写访问了,在进行完读写访问之后并不着急把该页对应的内存空间释放掉,而是将其缓存起来,这样将来有请求再次访问该页面时,就可以
省去磁盘IO
的开销了
3.缓存原则:
- 1
.“ 位置 * 频次 ”
这个原则,可以帮我们对 I/O 访问效率进行优化。 - 2.首先,位置决定效率,提供缓冲池就是为了在内存中可以直接访问数据。
- 3.其次,频次决定优先级顺序。因为缓冲池的大小是有限的,比如磁盘有 200G,但是内存只有 16G,缓冲池大小只有 1G,就无法将所有数据都加载到缓冲池里,这时就涉及到优先级顺序,会
优先对使用频次高的热数据进行加载
4.缓冲池的预读特性:
- 1.了解了缓冲池的作用之后,我们还需要了解缓冲池的另一个特性:
预读
。 - 2.缓冲池的作用就是提升IO效率,而我们进行读取数据的时候存在一个"“局部性原理”,也就是说我们使用了一些数据,大概率还会使用它周周的一些数据,因此采用“预读”的机制提前加载,可以减少未来可能的磁盘I/O操作
2.2.查询缓存
- 1.查询缓存
是提前把查询结果缓存 起来
,这样下次不需要执行就可以直接拿到结果 - 2.需要说明的是,在MySQL 中的查询缓存,不是缓存查询计划,而是查询对应的结果。因为命中条件苛刻,而且只要数据表发生变化,查询缓存就会失效,因此命中率低
3、缓冲池如何读取数据
- 1.缓冲池管理器会尽量将经常使用的数据保存起来,在数据库进行页面读操作的时候,首先会判断该页面是否在缓冲池中,如果存在就直接读取,如果不存在,就会通过内存或磁盘将页面存放到缓冲池中再进行读取。
- 2.缓存在数据库中的结构和作用如下图所示:
- 3.如果我们执行 SQL 语句的时候更新了缓存池中的数据,那么这些数据会马上同步到磁盘上吗?
- 实际上,当我们对数据库中的记录进行修改的时候,
首先会修改缓冲池中页里面的记录信息
,然后数据库会以一定的频率
刷新到磁盘上。 - 注意并不是每次发生更新操作,都会立刻进行磁盘回写。
- 缓冲池会采用一种叫做
checkpoint
的机制将数据回写到磁盘上,这样做的好处就是提升了数据库的整体性能。 - 比如,当
缓冲池不够用时
,需要释放掉一些不常用的页,此时就可以强行采用checkpoint的方式,将不常用的脏页回写到磁盘上,然后两从缓冲池中将这些页释放掉。这里脏页(dirty page)指的是缓冲池中被修改过的页,与磁盘上的数据页不一致
- 实际上,当我们对数据库中的记录进行修改的时候,
3、查看/设置缓冲池的大小
- 1.如果你使用的是
MySQL MyISAM存储引擎,它只缓存索引,不缓存数据
,对应的键缓存参数为key_buffer_size
,你可以用它进行查看。 - 2.如果你使用的是 InnoDB 存储引擎,可以通过查看
innodb_buffer_pool_size 变量
来查看缓冲池的大小。命令如下:show variables like 'innodb_buffer_pool_size'; /*输出 +-------------------------+-----------+ | Variable_name | Value | +-------------------------+-----------+ | innodb_buffer_pool_size | 134217728 | +-------------------------+-----------+ */
- 3.你能看到此时 InnoDB 的缓冲池大小只有
134217728/1024/1024=128MB
。我们可以修改缓冲池大小,比如改为256MB,方法如下:set global innodb_buffer_pool_size = 268435456
或者在配置文件中修改:innodb_buffer_pool_size = 268435456
,然后再来看下修改后的缓冲池大小,此时已成功修改成了 256 MB
4、多个Buffer Pool实例
-
1.Buffer Pool本质是InnoDB向操作系统申请的一块
连续的内存空间
,在多线程环境下
,访问Buffer Pool中的数据都需要加锁
处理。在Buffer Pool特别大而且多线程并发访问特别高的情况下,单一的Buffer Pool可能会影响请求的处理速度。所以在Buffer Pool特别大的时候,我们可以把它们拆分成若干个小的Buffer Pool
,每个Buffer Pool都称为一个实例,它们都是独立的,独立的去中请内存空间,独立的管理各种链表。所以在多线程并发访问时并不会相互影响,从而提高并发处理能力
-
2.可以在服务器启动的时候通过设置
innodb_buffer_pool_instances
的值来修改Buffer Pool实例的个数,修改其配置文件,添加这行:innodb_buffer_pool_instances = 2
,这样就表明我们要创建2个 Buffer Pool 实例。 -
3.我们看下如何查看缓冲池的个数,使用命令:
show variables like 'innodb_buffer_pool_instances';
/*默认有一个Buffer Pool实例
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| innodb_buffer_pool_instances | 1 |
+------------------------------+-------+
*/
- 4.那每个 Buffer Pool 实例实际占多少内存空间呢?其实使用这个公式算出来的:
innodb_buffer_pool_size/innodb_buffer_pool_instances
,也就是:总共的大小除以实例的个数,结果就是每个 Buffer Pool 实例占用的大小
- 5.
也不是Buffer Pool实例创建的越多越好
,分别管理各个Buffer Pool也是需要性能开销的,InnoDB规定:当innodb_buffer_pool_size的值小于1G的时候设置多个实例是无效的,InnoDB会默认把innodb_buffer_pool_instances 的值修改为1
。而我们鼓励在Bufer Pool大于或等于1G的时候设置多个Buffer Pool实例
5、引申问题
Buffer Pool
是MySQL内存结构中十分核心的一个组成,你可以先把它想象成一个黑盒子。
a.黑盒下的更新数据流程:
- 1.当查询数据的时候,会先去Buffer Pool中查询。
- 2.如果Buffer Pool中不存在,存储引擎会先将数据从磁盘加载到Buffer Pool中,然后将数据返回给客户端;
- 3.同理,当更新某个数据的时候,如果这个数据不存在于BufferPool,同样会先将数据加载进来,然后修改内存的数据。被修改过的数据会在之后统一刷入磁盘
b.问题分析:
- 1.假设修改Buffer Pool中的数据成功,但是还没来得及将数据刷入磁盘MySQL就挂了怎么办?按照上图的逻辑,此时更新之后的数据只存在于Buffer Pool中,如果此时MySQL宕机了,这部分数据将会永久地丢失;
- 2.如果数据更新到一半突然发生错误了,想要回滚到更新之前的版本,该怎么办?连数据持久化的保证、事务回滚都做不到还谈什么崩溃恢复?答案:
Redo Log & Undo Log
- Redo Log :
解决刷盘时刷到一半宕机的问题
- Undo Log:
解决回滚的问题
- Redo Log :