✏️
blog
  • README
  • 2023 11
    • expect使用
  • 2023 10
    • 通过Appium给iOS应用自动化执行脚本
  • 2023 06
    • 三种ThreadLocal详解
    • 常见限流算法总结
    • 分布式ID生成算法
  • 2023 05
    • 线上机器CLOSE_WAIT连接数异常排查
    • 多数据源引发transactional事务回滚失效
  • 2023 04
    • MySQL中BufferPool
  • 2022 12
    • Linux IO
    • Netty总结
  • 2022 04
    • Thrift
  • 2022 03
    • JVM命令总结
    • 频繁FullGC定位思路
    • Redis总结
    • Spring常见问题总结
    • Kafka总结
  • 2022 02
    • Dubbo柔性服务天池大赛总结
  • 2021 12
    • 泛型中的extends和super
    • 手写一个Spring Boot Starter
  • 2021 11
    • 常用消息队列总结
  • 2021 10
    • swagger2快速使用
    • SpringBoot接口cors跨域访问
  • 2021 08
    • 常用shell命令总结
  • 2021 05
    • 线程cpu飙升排查
    • zookeeper install
  • 2021 04
    • Java虚拟机
    • [Spring Boot](2021-04/2021-04-04-Spring Boot.md)
    • [Spring MVC](2021-04/2021-04-04-Spring MVC.md)
    • 分布式ID
    • 消息队列
    • [Spring AOP](2021-04/2021-04-05-Spring AOP.md)
    • 布隆过滤器
    • Scala内核Spark阻塞排查
  • 2020 12
    • 使用Python优雅实现tail命令
  • 2020 11
    • Spark基础架构
    • 一文搞定Git
    • Spark线上问题引发的思考
  • 2020 04
    • 使用GitBook
  • 2019 05
    • SELinux、Netfilter、iptables、firewall和ufw五者关系
    • 安装npm和nodejs
    • 访问不到云服务器中的项目
  • 2019 04
    • 二叉树中节点与度数
    • 实现会话跟踪的技术有哪些
    • 计算机操作系统-死锁
    • Semaphore Count Down Latch Cyclic Barrier
    • Java内存模型
    • 双重检查锁定
    • synchronized实现底层
    • Lock接口
    • HTTP与HTTPS的区别
    • Java中线程池
    • Java中的阻塞队列
    • 排序算法
  • 2019 03
    • MySQL中索引
    • MySQL存储引擎
    • MySQL锁机制
    • n的阶乘结果后面0的个数
由 GitBook 提供支持
在本页
  • MySQL InnoDB
  • 前置文章
  • Buffer Pool
  • 锁
  • 日志
  • 索引
  • 整理过程中问题

这有帮助吗?

  1. 2023 04

MySQL中BufferPool

上一页2023 04下一页2022 12

最后更新于1年前

这有帮助吗?

Table of Contents generated with

MySQL InnoDB

前置文章

Buffer Pool

  • 索引页、数据页、锁、undo页、自适应哈希索引和插入缓冲页

  • Free List

  • Flush List

  • LRU List(预读失效、Buffer Pool污染)

  • master thread loop

  • write ahead log

主要线程和职能

  • master thread:核心的后台线程,负责将缓冲区中的数据异步刷新到磁盘, 刷新脏页、merge insert buffer和回收undo页等

  • io thread:InnoDB中存在大量AIO,io thread用于处理这些异步请求的回调逻辑

  • purge thread:事务被提交后,undo log不再需要,purge thread用于回收已经被分配并使用的undo log页

  • page cleaner thread:刷新脏页

关键特性

  • 插入缓冲区:即insert buffer/change buffer,InnoDB针对非唯一的辅助索引写入专门的优化,会将写入操作先写入到buffer中

    • https://blog.csdn.net/it_lihongmin/article/details/115315120

    • insert buffer底层是一颗B+树,所有表共用一颗

    • Merge Insert Buffer的时机:1、当辅助索引页被读取到缓冲区时 2、Insert Buffer BitMap检测到该页已无可用空间时 3、master thread定时merge

  • 两次写:double write,在将数据页写到表时,这时发生宕机,16KB的页可能只写了部分,这时就发生了部分写失效,此时页发生损坏,即使有重做日志,也没有意义 InnoDB通过两次写来解决这种部分写失效的问题,将需要写入的页copy到double write buffer和共享表磁盘空间,由于都是顺序写,开销并不大,后再将buffer中的页写入表空间文件中

  • 自适应哈希索引:InnoDB自动根据访问的频率和模式来为某些热点页建立哈希索引

    • where a = xx / where a = xx and b = xxx 若交替以上述模式(where条件)执行,不会建立索引

    • 以该模式访问了100次

    • 页通过该模式访问了N次,其中N=页中记录条数/16

  • 异步IO:即AIO,AIO的好处就是可以非常方便的合并多个IO操作,如分别读取多个相邻页时可以合并为一次IO,读取一次。

  • 刷新邻接页:刷新脏页时,检查是否有相邻的脏页,如果存在就合并刷新到磁盘

Buffer Pool简单小结

Innodb 存储引擎设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能。

Buffer Pool 以页为单位缓冲数据,可以通过 innodb_buffer_pool_size 参数调整缓冲池的大小,默认是 128 M。

Innodb 通过三种链表来管理缓页:

Free List (空闲页链表),管理空闲页; Flush List (脏页链表),管理脏页; LRU List,管理脏页+干净页,将最近且经常查询的数据缓存在其中,而不常查询的数据就淘汰出去。; InnoDB 对 LRU 做了一些优化,我们熟悉的 LRU 算法通常是将最近查询的数据放到 LRU 链表的头部,而 InnoDB 做 2 点优化:

将 LRU 链表 分为young 和 old 两个区域,加入缓冲池的页,优先插入 old 区域;页被访问时,才进入 young 区域,目的是为了解决预读失效的问题。 当**「页被访问」且「 old 区域停留时间超过 innodb_old_blocks_time 阈值(默认为1秒)」**时,才会将页插入到 young 区域,否则还是插入到 old 区域,目的是为了解决批量数据访问,大量热数据淘汰的问题。 可以通过调整 innodb_old_blocks_pct 参数,设置 young 区域和 old 区域比例。

在开启了慢 SQL 监控后,如果你发现「偶尔」会出现一些用时稍长的 SQL,这可因为脏页在刷新到磁盘时导致数据库性能抖动。如果在很短的时间出现这种现象,就需要调大 Buffer Pool 空间或 redo log 日志的大小。

参考博客:https://xiaolincoding.com/mysql/buffer_pool/buffer_pool.html#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%9C%89-buffer-pool

锁

  • S锁:读锁

  • X锁:写锁

  • IS锁:意向读锁

  • IX锁:意向写锁

  • Record Lock

  • Gap Lock

  • Next Key Lock

日志

  • redo log:是Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复。顺序写

    • 刷新:master thread每秒刷新、事务提交时、redo缓冲区可用空间小于一半时

  • undo log:是Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC。随机读写

    • 当事务提交时:1、会将undo log页放入列表中,以供之后的purge操作 2、判断undo页是否可重用(可用空间是否大于1/4),若可以则分配给下一个事务使用

  • binlog:是 Server 层生成的日志,主要用于数据备份和主从复制。

索引

索引类型

  • 聚簇索引:每个表都会有一个聚簇索引,如果表存在主键就是用主键顺序,如果不存在主键会生成隐式主键。叶子节点中包含行数据。

  • 非聚簇索引(辅助索引/二级索引): 需要通过非聚簇索引的B+树找到对应节点,节点中包含主键信息,根据主键信息再通过聚簇索引找到对应的行记录,这个过程叫做回表。当查询信息只包含主键或索引列时,这时不会回表,这叫做索引覆盖。

  • 联合索引

  • 覆盖索引

  • 自适应哈希索引:由InnoDB优化自行创建,无法手动创建

创建索引的原则

  • 列区分度较大

  • 经常会被使用到的列

  • 更新特别频繁的列不建议创建索引

  • 尽量控制索引个数,索引不是越多越好

  • 尽量使用短索引

索引失效的场景

Hash索引:

  • 只用于使用=或<=>操作符的等式比较,只适用于key-value查询

  • Hash索引不适用于范围查询,例如<、>、<=、>=这类操作

B-Tree索引:

  • 以%开头的LIKE查询不能利用B-Tree索引

  • 数据类型出现隐式转换的时候也不会使用索引,特别是当列类型是字符串,要将字符串用引号引起来索引才生效

  • 复合索引的情况下,假如查询条件不包含索引列最左边部分,即不满足最左原则,是不会使用复合索引的,右边可以没有,左边和中间不能缺

  • 如果MySQL估计使用索引比全表扫描更慢,则不使用索引

  • 用or分割开的条件,每一列都要有索引才能使用索引

整理过程中问题

当行记录数据大小大于页大小(16KB)时,如何存储?

行记录在数据页中的存储结构

https://mp.weixin.qq.com/s/A5gNVXMNE-iIlY3oofXtLw

一个页中至少需要两行数据,溢出的数据存储在新的一个页里面,留出部分字节存储溢出页信息

select如何找到mvcc中具体版本的数据

通过read view和undo log,readview中记录了当前行记录已提交和未提交的事务,根据事务隔离级别,选择对应版本的undo log,生成具体版本的行记录 http://imodou.com.cn/article/MySQL%20MVCC%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3.html#_3-%E7%89%88%E6%9C%AC%E9%93%BE

undo log存储在哪

存储在共享表空间, rollback segment,一个rollback segment对应1024个undo log segment,在每个undo log segment中进行undo页的申请

SSD和机械磁盘差异

select是否会触发隐式事务

insert/update/delete会触发隐式事务,select不会

direct io是mmap吗?和其他常规io差异是零拷贝吗?

mmap是把page cache地址空间映射到用户空间,像操作应用层内存一样写文件,省去了系统调用的开销

direct io是避开了page cache,数据直接写磁盘数据块

https://www.cnblogs.com/bandaoyu/p/16752377.html

mysql写时如果数据页没在缓冲区,会先将数据页加载到缓冲区再写,还是直接写?

Double Write

MySQL索引总结
MySQL存储引擎
MySQL锁机制
InnoDB数据插入流程
ChangeBuffer
DocToc
MySQL InnoDB
前置文章
Buffer Pool
主要线程和职能
关键特性
Buffer Pool简单小结
锁
日志
索引
索引类型
创建索引的原则
索引失效的场景
整理过程中问题
当行记录数据大小大于页大小(16KB)时,如何存储?
select如何找到mvcc中具体版本的数据
undo log存储在哪
SSD和机械磁盘差异
select是否会触发隐式事务
direct io是mmap吗?和其他常规io差异是零拷贝吗?
mysql写时如果数据页没在缓冲区,会先将数据页加载到缓冲区再写,还是直接写?