05-数据库学习笔记(缓冲池优化和存储模型)

一.缓冲池四大优化方案

1.多缓冲池

(1)为什么需要多缓冲池

单一大缓冲池:整个缓冲池共用一套闩锁、LRU 链表。

大量线程同时读写缓存页面时,会争抢同一个全局闩锁,频繁阻塞,并发性能暴跌。

把一个大缓冲池,切分成多个大小相等、互相独立的小缓冲池,
每个分片有专属的 LRU 链表、哈希页表、独立闩锁。线程访问页面,只会争抢某一个分片的锁,不会锁住整个缓存,并发大幅提升。

(通俗理解:单缓冲池:一间超大公共阅览室,所有人共用一把大门锁,进门都要排队;多缓冲池:拆成十几个小阅览室,各自带门锁。大家分开进入,几乎不用排队。)

(2)两种核心映射方式

ID范围映射: 把所有磁盘页号从头到尾划分为连续均等区间,每一段固定绑定一个缓冲池分片。通过对象ID维护"对象-缓冲池"的映射关系,能实现更精细的缓冲池分配,但会增加一定的存储开销。

哈希映射: 对页面唯一页号做哈希运算,再对分片总数取模,算出归属分片。这种方式更通用、均匀,无需额外维护映射关系,是工业界更常用的方式。

常用公式:分片下标 = hash (页号) % 缓冲池分片数

2.预取

(1)为什么需要预取

磁盘机械硬盘随机读取很慢,但连续读取速度很快。利用磁盘连续读写高性能,提前加载后续将要访问的数据页,减少磁盘寻址次数、降低查询 IO 等待耗时,数据库预判你接下来大概率要访问后面相邻的数据页,不等你发起查询请求,提前把后续一连串页面从磁盘加载进缓冲池,这个行为就叫预取

(通俗理解:你看书正翻第 10 页,系统预判你马上要看 11、12、13 页,一次性把后面几页全部提前放到手边,不用看一页翻一次书柜。)

(2)两种预取方式

  • 顺序读取: 连续访问若干页之后,一次性往后多读数个页面存入缓存。
    优点:批量连续 IO,大幅降低寻道耗时;
    缺点:如果只读一半就不再访问,提前加载的页面白白占用缓存空间,挤占热点数据。
  • 随机预取: 针对零散随机访问的页面,预判周边页面可能被用到,轻微预加载。收益很低,数据库很少开启。

(3)预取的优缺点

优点

把多次随机小 IO,合并成一次连续大 IO,磁盘效率暴涨;

后续查询直接命中缓冲池,无磁盘等待,查询速度提升。

缺点

预判失误会造成缓存污染:提前加载一堆用不着的冷页面,挤走缓冲池里的热点常用页;

无谓占用内存、消耗 IO 带宽。

3.扫描共享

(1)为什么需要扫描共享(优点)

  • 杜绝重复磁盘 IO,减轻磁盘压力
  • 提升整体系统吞吐
  • 节约缓冲池内存

(2)核心逻辑

第一个人开始顺序扫描,一页一页加载数据;后续紧跟着发起相同范围扫描的事务,不用重复去磁盘读取页面,直接复用已经正在被加载、或者已经载入缓存的页面,大家共用这一轮扫描加载出来的数据。

(通俗理解:一群同学依次要通读同一本书。第一个同学一页一页慢慢从书架取书翻看;后面排队的同学不用自己再去书架反复拿书,直接等着、共用已经拿出来的书页一起看,不用重复跑腿。)

(3)缺点

  • 只对顺序扫描生效,随机查询、单点查找无法共享;
  • 会轻微拖慢第一个发起查询的用户速度(要负责全部 IO),换来全体并发扫描整体提速;
  • 若中途某个查询终止,共享队列也要一并处理,逻辑更复杂。

4.缓冲池绕过

(1)为什么需要缓冲池绕过

当执行全表扫描、后台统计报表这类一次性查询时,会读取海量冷门页面,这些数据只会使用一次,后续不会再访问。若数据全都存入缓冲池:大量冷页会依照淘汰算法挤走常驻热点页面,后续正常业务大量走磁盘 IO,系统性能急剧下降。

(2)核心逻辑

对于确定的某些只使用一次、不会被再次访问的页面(如大型表的顺序扫描),数据库直接从磁盘读取该页面,不放入缓冲池,避免这些"一次性页面"占用缓冲池空间,污染热点页面(频繁访问的页面)。

(3)优点

  • 保护热点数据,提升缓存命中率:一次性页面不进入缓冲池,避免挤占热点索引页、核心业务数据页的空间,大幅降低热点数据被淘汰的概率,减少后续查询的磁盘 I/O 次数。
  • 避免无效的缓存开销:一次性页面读取后无需缓存,省去了缓冲池的维护成本(如 LRU 队列更新、页面状态标记、后续淘汰管理等),减少无意义的资源消耗。
  • 降低系统整体 I/O 压力:一次性页面直接读写磁盘,无需经过缓冲池中转,减少了内存与磁盘之间的额外数据拷贝,降低了系统整体 I/O 开销。

二.存储架构

1.元组导向存储(原地增删改查)

是关系数据库最经典、默认的物理存储范式,核心规则:把逻辑上一行完整元组(一条记录)的所有字段值,在磁盘页面中物理连续存放。

(1)槽式页面

绝大多数行式数据库磁盘页内部统一采用 槽式页面结构,是元组导向存储最核心的底层页面布局规范。

作用:在固定大小磁盘页中灵活存放长短不一的元组、支持删除更新、快速定位任意一条记录、管理页面空闲空间。

槽式页面就是为了解决:不定长元组存放、删除无需挪动数据、快速寻址、碎片管理。

(2)页面空间分为三大区域

页头: 相当于文件夹的封面,记录当前页面的已用槽数量、最后一个槽的起始偏移量,方便快速定位槽数组的位置。

槽位数组 : 相当于文件夹的目录,每个槽对应一个元组,记录该元组在页面中的起始偏移量------就像目录记录每篇文章在文件夹中的页码,通过槽数组能快速找到元组的位置。

元组数据区: 相当于文件夹的正文区域,存储固定长度和可变长度的元组数据,元组的存储顺序与槽数组的顺序可以不一致。

(3)缺点

  • 碎片化: 磁盘 / 页面里的空闲空间被切分成无数细小、不连续的空隙,无法高效利用
  • 无效磁盘I/O: 磁盘存储是按块(页面)划分的,即使只更新元组中的一个字段,也需要将整个页面从磁盘读入缓冲池,修改后再写回磁盘
  • 随机磁盘I/O: 如果要更新多个元组,而这些元组分布在不同的页面,磁盘需要频繁跳转不同的物理位置读取页面,速度极慢

2.日志结构存储(纯顺序写入)

(1)核心逻辑

日志结构存储是针对元组导向存储的缺点设计的,核心思想是"不原地更新元组,而是记录元组的修改日志"。

后台会定时做合并(Compaction):把一大堆零散的日志打包整理,删掉作废的旧数据,压缩成规整的大文件。

(2)特点:

写入速度天花板

只有顺序追加写,没有磁盘随机修改,机械硬盘写数据飞快,海量并发写入首选;

读取会变慢

一条数据可能有多条历史日志,查询需要遍历多个文件对比版本;后台合并整理还要消耗 CPU、磁盘资源;

几乎不会产生传统页内碎片

适用:海量日志写入、时序数据、大数据写入场景

3.索引组织存储

(1)核心逻辑

本质: 属于元组导向存储的升级版,没有单独的数据区,数据本身就是索引叶子节点

普通行存储:

有两份东西:① 原始数据账本 ② 单独一本索引小册子(记着名字对应的页码)

查数据:先翻索引找位置,再跳去数据页读取记录。

索引组织存储:

把完整账单行,直接按照主键顺序整齐排好,本身就是索引。

比如以顾客 ID 排序,所有记录从小到大紧紧连续排布:

ID1 账单 → ID2 账单 → ID3 账单 → ID4 账单......

(2)优点:

  • 根据主键查个人账单速度拉满,连续翻阅一批 ID 的记录是顺畅顺序读取;
  • 少了一套独立数据文件,存储开销更小。

(3)缺点:

  • 主键乱序插入会打乱排布,产生大量空隙和碎片;
  • 不用主键查找时,需要二级索引跳转,会多一次 IO。

4.三种存储模型精简对比表

对比维度 元组导向存储(堆行存) 索引组织存储(InnoDB) 日志结构存储(LSM)
核心原理 整行数据存放,数据与索引分离 行数据按主键有序构成B+树,数据即索引 只追加写入,禁止原地修改数据
碎片情况 极易产生页内、页间碎片 有序写入碎片少,乱序插入易产生碎片 几乎无存储碎片
IO特征 点查随机IO多 主键扫描顺序IO快 写入全顺序IO,读取随机IO较多
单行查询效率 最优 主键查询极快 最慢
写入性能 中等 良好 极高
后台开销 碎片整理开销大 开销小 持续合并压缩,CPU/磁盘开销高
相关推荐
仙宇觉尘1 天前
记一次 .NET 某中医药附属医院门诊系统 崩溃分析
数据库·oracle·.net
minglie11 天前
蚂蚁S9矿板PS 将驱动编译到内核
学习
小码农 - 初1 天前
MySQL的表操作
数据库·mysql
华如锦1 天前
【AGENT开发】python学习 Python Level 5
python·学习·elasticsearch
灵机一物1 天前
2026智能清洁设备推荐榜:无人值守与效率提升解析
数据库
xuankuxiaoyao1 天前
WQ 算子尝试1
数据库·mysql
筑梦之路1 天前
harbor使用国产数据库PolarDB PG版本部署——筑梦之路
数据库·信创适配·国产化改造
自不量力的A同学1 天前
LibreOffice 26.2.5 发布
笔记
大鹏说大话1 天前
移动应用打包常见报错汇总
数据库
MartinYeung51 天前
[论文学习]Learning to Inject:基于强化学习的自动化提示注入攻击
网络·学习·自动化