
好的,我们将对 Oracle 数据库缓冲区缓存(Buffer Cache)的替换算法进行一场深入而全面的剖析。这是 Oracle 内存管理的核心,直接决定了数据库的性能表现。
第一部分:官方技术详解
一、核心概念与作用
1. 什么是缓冲区缓存?
缓冲区缓存是系统全局区(SGA)中最大且最关键的部分之一。它充当数据库数据文件(磁盘)和服务器进程(内存)之间的中间缓存层。其核心目的是通过在内存中保留最近和最频繁访问的数据块副本,来最大限度地减少昂贵且缓慢的物理 I/O 操作。
2. 为什么需要替换算法?
缓冲区缓存的大小是有限的,远小于整个数据库。当缓存已满且服务器进程需要将新数据块读入内存时,必须决定淘汰哪个现有的数据块,以便为新块腾出空间。这个决策机制就是替换算法。一个高效的算法应能尽可能多地保留“有用”的数据块,避免将 soon-to-be-used-again(很快再次被使用)的块换出,从而最大化缓存命中率。
二、内部架构与核心算法:LRU 与 TCH
Oracle 的缓冲区缓存管理是一个复杂的、自适应的系统,其核心是 LRU(Least Recently Used)算法 的一个高度优化变体,并引入了触摸次数(Touch Count, TCH) 的概念。
1. 缓冲区的状态与结构
缓冲区缓存中的每个数据块(Buffer)都有一个相关的缓冲区头(Buffer Header),它存储了丰富的元数据,用于管理其状态。这些头信息存储在高速缓存缓冲区链(CBC, Cache Buffers Chains) 上,并通过哈希表进行快速查找。
关键元数据包括:
- 状态:
- Pinned:当前正被某个进程使用,不能被换出。
- Clean:内存中的内容与磁盘一致。
- Free/Unused:缓冲区为空,可供使用。
- Dirty:内存中的内容已被修改,与磁盘不一致,最终必须由 DBWn(Database Writer) 进程写入磁盘。
- 访问模式:
- 访问时间:最后一次被访问的时间戳。
- 触摸次数(TCH):一个计数器,记录该块被访问的频率。
- 队列指针:用于将缓冲区连接到各种管理链表(如 LRU 链表)。
2. 替换算法详解:多链表 LRU 与触摸次数(TCH)
Oracle 并不使用一个单一的 LRU 列表,而是使用两个主要链表来管理缓冲区:
-
LRU List(最近最少使用列表):
- 这是一个按最近访问时间排序的链表。最近被访问的块被移动到链表的 MRU(Most Recently Used)端,而最久未被访问的块则滑向链表的 LRU 端。
- 当服务器进程需要空闲缓冲区(Free Buffer) 来读取新块时,它从 LRU 端的尾部开始扫描。
-
Dirty List(脏列表) / Write List:
- 专门用于链接所有脏缓冲区。DBWn 进程会定期或根据特定条件(如检查点)将此列表中的缓冲区写入磁盘。写入后,这些缓冲区被标记为 Clean,并可以重新链接到 LRU 列表上。
核心算法流程(“冷热”分离模型):
-
新块进入缓存:
- 当一个服务器进程需要读取一个不在缓存中的数据块时,它必须找到一个空闲缓冲区。
- 它从 LRU 列表的尾部(LRU端) 开始扫描,寻找可用的候选者。
-
扫描与淘汰决策:
- 在扫描过程中,进程会检查每个遇到的缓冲区。
- 如果缓冲区是干净的(Clean)且触摸次数(TCH)为 0:这是一个理想的淘汰候选。进程立即使用它来存放新读入的数据块。新块被插入到 LRU 列表的 MRU 端,并且其 TCH 被设置为 1。
- 如果缓冲区是脏的(Dirty):进程不会立即处理它,而是跳过。脏缓冲区的写出由 DBWn 负责。
- 如果缓冲区是干净的但 TCH > 0:这表示该块最近被访问过,是“热”块。进程不会淘汰它,而是将其 TCH 值减 1,并将其向 MRU 端移动一些位置。然后继续扫描。
-
触摸次数(TCH)的作用:
- TCH 是一个热度指标。每次缓冲区被访问(读或写),TCH 都会增加(有一个上限,通常是 10 左右)。
- 这个机制确保了频繁访问的“热”块会保持较高的 TCH,从而在 LRU 扫描中很难被选中淘汰。而那些被访问一次后就再也没用过的“冷”块,其 TCH 会通过上述的减一操作逐渐降为 0,最终成为被淘汰的目标。
- 这解决了传统 LRU 的一个弱点:偶尔的全表扫描会污染缓存,将大量热块挤出。因为全表扫描的块通常只被访问一次,它们的 TCH 很低,会很快被淘汰,而真正的热块由于 TCH 高,得以保留。
-
辅助列表(Auxiliary Lists):
- 为了提升扫描效率,Oracle 还维护了其他辅助列表,如 LRUW(LRU Write,即脏列表) 和 检查点队列(Checkpoint Queue),后者按块第一次变脏的日志顺序(RBA)链接脏缓冲区,用于高效的恢复和写出。
三、管理机制与相关参数
- DB_CACHE_SIZE:定义标准块大小缓冲区缓存的大小。
- DB_nK_CACHE_SIZE:为非标准块大小的表空间(如 4k, 16k, 32k)定义独立的缓存区域。
- 多个缓冲池(Multiple Buffer Pools):允许对数据进行更精细的缓存策略管理。
- KEEP Pool:用于存放绝对不能被换出的“钉死”对象(如小型的、频繁访问的代码表)。
ALTER TABLE ... STORAGE (BUFFER_POOL KEEP); - RECYCLE Pool:用于存放一次性访问的大型对象(如临时作业的大表),防止它们污染主缓存。
ALTER TABLE ... STORAGE (BUFFER_POOL RECYCLE); - DEFAULT Pool:默认池,使用上述的主替换算法。
- KEEP Pool:用于存放绝对不能被换出的“钉死”对象(如小型的、频繁访问的代码表)。
- 自动内存管理(AMM/ASMM):
MEMORY_TARGET或SGA_TARGET参数允许 Oracle 自动调整缓冲区缓存的大小,根据工作负载在 SGA 各组件之间动态重新分配内存。
第二部分:场景、争用、排查与解决
四、性能争用与排查
缓冲区缓存的低效会直接导致物理 I/O 增加,从而引发一系列等待事件。
1. 场景:free buffer waits
- 原理:这是最典型、最直接的缓冲区缓存争用事件。当服务器进程需要将新块读入缓存,但在 LRU 列表上找不到可用的干净缓冲区时,就会发生此等待。
- 根本原因:
- 缓存太小:无法容纳工作集(Working Set)。
- DBWn 写出速度跟不上:脏缓冲区产生得太快,DBWn 来不及将它们清洗干净,导致 LRU 列表上充斥着待写出的脏块,没有足够的干净块可供重用。
- 低效的 SQL:大量的全表扫描或低效的索引使用,产生了远超缓存容量的逻辑读,剧烈地冲刷缓存。
- 排查:
- 检查 AWR 报告的 “Buffer Pool” 部分。关注
Buffer Hit Ratio,但更重要的是Free Buffer Waits和Free Buffer Inspected的统计信息。Free Buffer Inspected表示为了找一个空闲缓冲区而检查的块数,这个值过高意味着寻找空闲块非常困难。 - 检查
V$SYSSTAT:SELECT name, value FROM v$sysstat WHERE name IN ('free buffer requested', 'free buffer inspected', 'dirty buffers inspected'); - 检查 DBWn 是否繁忙(
V$BGPROCESS, AWR 报告的 “Background Wait Events”)。
- 检查 AWR 报告的 “Buffer Pool” 部分。关注
- 解决:
- 增加
DB_CACHE_SIZE:最直接的解决方案。 - 优化 DBWn:增加
DB_WRITER_PROCESSES(多个 DBWn 进程),调整DB_BLOCK_MAX_DIRTY_TARGET,或确保 I/O 子系统足够快。 - 优化 SQL:这是治本的方法。减少不必要的逻辑读,增加索引以避免全表扫描。
- 使用多缓冲池:将大型的、一次性的作业表分配到 RECYCLE 池,保护 DEFAULT 池中的热数据。
- 增加
2. 场景:write complete waits 和 buffer busy waits
write complete waits:当进程需要读取一个当前正被 DBWn 写出到磁盘的脏缓冲区时,它必须等待写出完成。这表明 I/O 或 DBWn 是瓶颈。buffer busy waits:当多个进程同时请求以不兼容的模式(如一个要读,一个要修改)访问同一个缓冲区时发生。这通常是应用程序并发争用的表现(如索引块的热块争用、或者小表的频繁更新)。- 排查与解决:
- 查询
V$WAITSTAT查看等待发生在什么类型的块上(如data block,index block,undo block)。SELECT * FROM v$waitstat ORDER BY count DESC; - 对于
buffer busy waitsondata blocks,考虑使用 自动段空间管理(ASSM) 或增加PCTFREE来分散数据。 - 对于
buffer busy waitsonindex blocks,考虑使用反向键索引(Reverse Key Indexes) 或哈希分区索引来打散热点。
- 查询
五、常用查询与管理 SQL
-
查看缓冲区缓存命中率(历史):应结合 AWR 报告看趋势,单点值意义不大。
SELECT (1 - (phy.value / (cur.value + con.value))) * 100 "Buffer Hit Ratio (%)" FROM v$sysstat cur, v$sysstat con, v$sysstat phy WHERE cur.name = 'db block gets' AND con.name = 'consistent gets' AND phy.name = 'physical reads'; -
查看缓冲池配置和统计信息:
SELECT name, block_size, current_size, buffers, target_size FROM v$buffer_pool_statistics; -
查看对象在缓存中的热度:
SELECT o.owner, o.object_name, o.object_type, COUNT(*) buffers, SUM(DECODE(bh.STATUS, 'free', 0, 1)) used_buffers FROM dba_objects o, v$bh bh WHERE o.data_object_id = bh.objd AND o.owner NOT IN ('SYS','SYSTEM') GROUP BY o.owner, o.object_name, o.object_type ORDER BY used_buffers DESC; -
检查等待事件:
SELECT event, total_waits, time_waited, average_wait FROM v$system_event WHERE event IN ('free buffer waits', 'write complete waits', 'buffer busy waits', 'db file sequential read', 'db file scattered read') ORDER BY time_waited DESC; -
强制清空缓存(仅用于开发和测试!):
ALTER SYSTEM FLUSH BUFFER_CACHE; -- 清空Buffer Cache ALTER SYSTEM FLUSH SHARED_POOL; -- 通常一并执行,清除执行计划
第三部分:通俗易懂的解释
想象一下缓冲区缓存是一个大学的图书馆阅览室,里面的座位(Buffers)是有限的。
- 数据块:就是一本本的书。
- 物理 I/O:就是去遥远的总书库调书,非常慢。
- 目标:让最受欢迎、最近最常被借阅的书尽量留在阅览室里,减少去总书库的次数。
替换算法(图书馆管理员的管理规则):
-
新书到来:当一个学生(服务器进程)想读一本新书(数据块),但阅览室没座位了,他必须请走一个人,腾出座位。
-
寻找可清退的人:
- 管理员(替换算法)不会随便赶人。他会从最久没翻过书的人(LRU 端) 开始询问。
- 他拍了拍第一个人:“同学,你的书(缓冲区)看完了吗(Clean)?而且我看你借阅记录(TCH)也很久没更新了(TCH=0)。” 如果是,太好了,就请他离开,让新同学坐下。新同学被安排到“刚来的人”区域(MRU 端),并得到一张积分卡(TCH=1)。
- 如果他看到一个人书没看完(Dirty),他不会打扰他(因为需要先还书,这是 DBWn 的工作),直接跳过。
- 如果他看到一个人正在认真看书,而且积分卡(TCH)分数很高,说明他是常客。管理员不会赶他走,反而会给他的积分卡扣一分(TCH-1),并把他往“刚来的人”区域挪一挪,然后继续往后找。
-
积分卡(TCH)的作用:
- 每次你续借或者打开书看,积分就加一分(上限10分)。这保证了真正的学霸(热块) 永远积分很高,很难被请走。
- 而那种偶尔来一次、借一本畅销小说看两眼就放下(全表扫描) 的人,积分很快就会被扣光,成为首先被清退的目标。这样就保护了学霸的座位不被临时访客挤占。
出现的问题(等待事件):
-
free buffer waits(找不到座位等待):管理员发现,从一头走到另一头,每个人都在看书(全是脏缓冲区或热块),找不到一个可以清退的人。新同学只能干等着(等待),直到有一个人看完书(DBWn 把脏块写出)或者管理员终于找到一个可清退的人。- 原因:要么阅览室太小(缓存太小),要么大家看书时间太长(DBWn 写出慢),要么突然来了太多新同学(高逻辑读)。
-
buffer busy waits(争抢同一本书):两个学生都想看同一本书的同一页(同一个缓冲区),而且一个人想写读书笔记(修改),另一个人只想读。他们必须互相协调,一个人用的时候另一个人就得等着。- 原因:热门资源(热点块)的并发访问冲突。
总结:
Oracle 的缓冲区缓存替换算法是一个精巧的、自适应的系统,它通过 LRU 链表 和 触摸次数(TCH) 机制,智能地区分了“热数据”和“冷数据”,高效地管理着有限的内存资源。DBA 的核心工作就是确保这个“阅览室”:
- 足够大(
DB_CACHE_SIZE)。 - 管理员(DBWn)效率高(配置合理的 DBWR 进程和 I/O)。
- 来的学生(SQL)都是好学生,不会毫无节制地一次借走几百本书(优化 SQL,减少逻辑读)。
通过监控相关的等待事件和使用性能视图,DBA 可以精准地诊断出缓存系统的瓶颈所在,并采取相应的优化措施,从而保证数据库的响应速度。
欢迎关注我的公众号《IT小Chen》
2065

被折叠的 条评论
为什么被折叠?



