
好的,我们将对 Oracle 19C 数据库中一个极为核心的动态性能视图——V$BH——进行最全面、最深入的解析。这个视图是窥探 Oracle 核心内存结构 Buffer Cache(数据库缓冲区缓存) 的窗口,是性能调优和故障诊断的利器。
1. 视图概述与核心作用
V$BH (Buffer Headers) 动态性能视图的作用是展示当前实例的 Buffer Cache 中每一个数据块(Block)的详细信息。Oracle 不会直接操作数据块,而是通过管理这些块的缓冲区头(Buffer Header) 来进行。V$BH 就是这些缓冲区头信息的集合。
核心作用可以概括为:
- 缓存内容分析:查看哪些表、索引的哪些块当前正缓存在内存中。
- 性能问题诊断:识别"热块"(经常被访问和争用的块),分析缓存命中率低的根源。
- 竞争与等待分析:理解与
buffer busy waits,cache buffers chains latch等待事件相关的根本原因。 - 内部机制理解:洞察 Oracle 如何管理 Buffer Cache,包括并发控制、缓存一致性(CR块)和缓存算法。
2. 使用场景
-
识别热点块(Hot Blocks):
当系统出现buffer busy waits或cache buffers chains latch等待事件时,通过此视图可以精确定位到被频繁访问和争用的具体数据块(FILE#,BLOCK#),进而找到对应的数据库对象(OBJD)。 -
分析 SQL 性能:
对于一条运行缓慢的 SQL,可以查看其访问的数据段有多少比例缓存在内存中。如果大部分不在内存中,则说明全表扫描或索引快速全扫可能因物理 I/O 而变慢。 -
评估内存大小是否充足:
通过统计不同对象在缓存中的块数,可以判断当前 Buffer Cache 大小是否足以容纳经常访问的"工作集"(Working Set),或者是否需要考虑使用 Buffer Pool 优化(KEEP/RECYCLE)。 -
调查缓存一致性:
在并发度高的环境中,可以查看一个数据块有多少个 CR(一致性读)版本,这有助于理解读一致性的开销。 -
实例恢复后分析:
实例崩溃后,可以查看哪些脏块(DIRTY='Y')需要被写回数据文件,这有助于理解恢复过程。
3. 字段详细含义
V$BH 视图字段非常多,以下是对最关键字段的详细解释:
| 字段名 | 数据类型 | 含义说明 |
|---|---|---|
| FILE# | NUMBER | 块所在的数据文件号。与 DBA_DATA_FILES.FILE_ID 对应。 |
| BLOCK# | NUMBER | 块在数据文件内的块号。与 FILE# 共同唯一标识一个数据块。 |
| CLASS# | NUMBER | 块的类型。例如:1=data, 2=sort, 3=save undo, 4=segment header, 5=save undo header, 6=free list, 7=extent map, 8=1st level bmb, 9=2nd level bmb, 10=3rd level bmb, 11=bitmap block, 12=bitmap index block, 13=file header block, 14=unused, 15=system undo header, 16=system undo, 17=undo header, 18=undo block。 |
| STATUS | VARCHAR2(1) | 缓冲区的状态: • free : 缓冲区为空闲,可重用• xcur : 独占当前模式。缓冲区已被当前实例以排他模式缓存,且是当前版本。• scur : 共享当前模式。缓冲区已被以共享模式缓存,是当前版本。• cr : 一致性读模式。这是一个为读一致性而构建的过去版本的块。• read : 缓冲区正在从磁盘被读取。• mrec : 处于介质恢复模式。• irec : 处于实例恢复模式。 |
| DIRTY | VARCHAR2(1) | 指示缓冲区是否为"脏"块: • Y : 缓冲区已被修改,其内容与磁盘上的块不一致,需要被 DBWn 进程写入数据文件。• N : 缓冲区内容与磁盘一致。 |
| TEMP | VARCHAR2(1) | 指示是否为临时段中的块(用于排序、哈希连接等)。 |
| PING | VARCHAR2(1) | 指示该块是否在 RAC 环境中被"ping"了(即一个实例需要强制从另一个实例的缓存中写入该块)。 |
| STALE | VARCHAR2(1) | 指示缓冲区内容是否为"陈旧的"(在 RAC 中,远程实例已使其失效)。 |
| OBJD | NUMBER | 数据块所属的数据对象ID。这是最关键的字段之一,可以与 DBA_OBJECTS.DATA_OBJECT_ID 关联,从而确定是哪个表或索引的块。 |
| HLADDR | RAW(4 | 8) |
| NXT_HASH PRV_HASH | RAW(4 | 8) |
| NXT_REPL PRV_REPL | RAW(4 | 8) |
| BA | RAW(4 | 8) |
| LRU_FLAG | NUMBER | 指示缓冲区在 LRU 列表中的位置状态。用于管理缓冲区的老化(aging)和替换。 |
| SET_DSC | RAW(4 | 8) |
| TS# | NUMBER | 块所属的表空间ID。 |
| FORCED_READS FORCED_WRITES | NUMBER | 强制读取/写入的次数(通常与直接路径加载或高级特性相关)。 |
| CR_SCN_BAS CR_SCN_WRP CR_XID_USN CR_XID_SLT CR_XID_SQN | NUMBER | 这些字段记录了创建这个 CR(一致性读)块 的事务信息(SCN 和 Undo 信息),用于保证读一致性。 |
4. 相关视图与基表
-
核心关联视图:
DBA_OBJECTS:通过OBJD=DATA_OBJECT_ID关联,这是将缓冲区块映射到具体表、索引等数据库对象的关键。V$LATCH_CHILDREN:通过HLADDR=ADDR关联,可以找到保护该缓冲区的具体cache buffers chainslatch 子级。DBA_DATA_FILES:通过FILE#=FILE_ID关联,可以找到块所属的数据文件。V$BUFFER_POOL:提供所有缓冲池(DEFAULT, KEEP, RECYCLE)的统计信息。X$KCBBF(RAC):在 RAC 中,用于查看所有实例的缓冲区信息。
-
**底层基表(X表)∗∗:‘V表)**: `V表)∗∗:‘VBH
的数据直接来源于 SGA 中管理 Buffer Headers 的**内存结构**。其底层关联的 **X$表** 是 **XBH‘∗∗。‘XBH`**。 `XBH‘∗∗。‘XBH包含了比VBH‘∗∗更详细、更底层的字段∗∗,但这些字段绝大多数是供Oracle内部开发人员使用的,其含义晦涩且不受支持。∗∗重要警告∗∗:∗∗严禁∗∗直接查询‘XBH` **更详细、更底层的字段**,但这些字段绝大多数是供 Oracle 内部开发人员使用的,其含义晦涩且不受支持。 **重要警告**:**严禁**直接查询 `XBH‘∗∗更详细、更底层的字段∗∗,但这些字段绝大多数是供Oracle内部开发人员使用的,其含义晦涩且不受支持。∗∗重要警告∗∗:∗∗严禁∗∗直接查询‘XBH。所有诊断信息都应通过公开的、安全的V$BH` 视图获取。
5. 相关底层详细原理
- Buffer Cache 管理:
Oracle 使用哈希算法来管理 Buffer Cache。数据块地址(DBA =FILE#+BLOCK#)通过一个哈希函数,被映射到一个哈希桶(Hash Bucket) 中。 - 缓存缓冲区链(CBC)Latch:
每个哈希桶由一个cache buffers chainslatch 保护。要访问或修改一个桶内的缓冲区链表,进程必须先获取相关的 CBC latch。这就是HLADDR字段的意义,也是cache buffers chains latch争用的根源。 - 缓冲区状态:
xcur:只有一个实例可以持有该块的当前版本(排他模式)。scur:多个实例可以同时持有该块的当前版本(共享模式),常见于 RAC。cr:为了实现读一致性,如果一个查询开始时,某个块已经被修改,Oracle 会利用 Undo 数据在 Buffer Cache 中构建一个该块在查询开始那个时间点的版本,这个版本就是 CR 块。一个当前块可能有多个 CR 版本。
- LRU 算法与写入:
脏块(DIRTY='Y')会被 DBWn 进程根据检查点事件或LRU算法写入磁盘。NXT_REPL和PRV_REPL指针用于维护这些列表。
6. 相关知识点介绍
- 逻辑读与物理读:当请求一个块时,Oracle 先在 Buffer Cache 中查找(逻辑读)。如果找到(缓存命中),就直接读取;如果找不到(缓存缺失),则发生物理读,从磁盘将块读入缓存。
- 工作集(Working Set):数据库经常访问的数据块集合。Buffer Cache 的理想大小是能够容纳整个工作集。
- 多缓冲池:
- DEFAULT:默认池,所有对象默认在此缓存。
- KEEP:用于缓存小而常用的表,使其常驻内存,避免被淘汰。
- RECYCLE:用于缓存大而不常访问的表,使其尽快被淘汰,避免污染默认池。
- 直读(Direct Read):像并行查询、直接路径加载等操作会绕过 Buffer Cache,直接读写磁盘,适用于大量数据操作。
7. 常用查询 SQL
1. 查找Buffer Cache中的热点块(按块访问次数排名):
SELECT obj.owner, obj.object_name, obj.object_type,
bh.file#, bh.block#, bh.status, bh.temp, bh.dirty,
COUNT(*) OVER (PARTITION BY bh.file#, bh.block#) AS touch_count
FROM v$bh bh
JOIN dba_objects obj ON (bh.objd = obj.data_object_id)
WHERE obj.owner NOT IN ('SYS','SYSTEM') -- 排除系统对象
ORDER BY touch_count DESC;
2. 查看特定表(如’EMPLOYEES’)在缓存中有多少个块:
SELECT COUNT(*) cached_blocks,
SUM(CASE WHEN dirty = 'Y' THEN 1 ELSE 0 END) dirty_blocks
FROM v$bh
WHERE objd = (SELECT data_object_id
FROM dba_objects
WHERE owner = 'HR'
AND object_name = 'EMPLOYEES'
AND object_type = 'TABLE');
3. 诊断 cache buffers chains latch争用,找到被争用的具体对象:
SELECT hladdr, objd, file#, block#,
COUNT(*) num_buffers,
COUNT(CASE WHEN dirty = 'Y' THEN 1 END) dirty_buffers
FROM v$bh
GROUP BY hladdr, objd, file#, block#
HAVING COUNT(*) > 10 -- 一个链上有很多缓冲区,可能意味着热点链
ORDER BY num_buffers DESC;
然后可以用 HLADDR 去 V$LATCH_CHILDREN 中找到具体的latch。
4. 查看缓存中CR块的数量(高并发读写的指标):
SELECT status, COUNT(*) buffers, ROUND(COUNT(*) * 8 / 1024, 2) size_mb
FROM v$bh
GROUP BY status
ORDER BY buffers DESC;
5. 查看整个Buffer Cache的按对象分类的使用情况:
SELECT o.owner, o.object_name, o.object_type,
COUNT(*) num_blocks,
ROUND(COUNT(*) * 8 / 1024, 2) size_mb -- 假设块大小是8K
FROM v$bh b
JOIN dba_objects o ON b.objd = o.data_object_id
WHERE o.owner NOT IN ('SYS','SYSTEM')
GROUP BY o.owner, o.object_name, o.object_type
ORDER BY num_blocks DESC;
通过深入掌握 V$BH 视图,您就拥有了从微观层面洞察和理解 Oracle 数据库核心内存运作机制的能力,从而能够进行精准的性能优化和高效的问题诊断。
欢迎关注我的公众号《IT小Chen》

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



