面试宝典:介绍下Oracle数据库动态性能视图 V$BH

在这里插入图片描述
好的,我们将对 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. 使用场景

  1. 识别热点块(Hot Blocks)
    当系统出现 buffer busy waitscache buffers chains latch 等待事件时,通过此视图可以精确定位到被频繁访问和争用的具体数据块(FILE#, BLOCK#),进而找到对应的数据库对象(OBJD)。

  2. 分析 SQL 性能
    对于一条运行缓慢的 SQL,可以查看其访问的数据段有多少比例缓存在内存中。如果大部分不在内存中,则说明全表扫描或索引快速全扫可能因物理 I/O 而变慢。

  3. 评估内存大小是否充足
    通过统计不同对象在缓存中的块数,可以判断当前 Buffer Cache 大小是否足以容纳经常访问的"工作集"(Working Set),或者是否需要考虑使用 Buffer Pool 优化(KEEP/RECYCLE)。

  4. 调查缓存一致性
    在并发度高的环境中,可以查看一个数据块有多少个 CR(一致性读)版本,这有助于理解读一致性的开销。

  5. 实例恢复后分析
    实例崩溃后,可以查看哪些脏块(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。
STATUSVARCHAR2(1)缓冲区的状态
free : 缓冲区为空闲,可重用
xcur : 独占当前模式。缓冲区已被当前实例以排他模式缓存,且是当前版本。
scur : 共享当前模式。缓冲区已被以共享模式缓存,是当前版本。
cr : 一致性读模式。这是一个为读一致性而构建的过去版本的块。
read : 缓冲区正在从磁盘被读取。
mrec : 处于介质恢复模式。
irec : 处于实例恢复模式。
DIRTYVARCHAR2(1)指示缓冲区是否为"脏"块
Y : 缓冲区已被修改,其内容与磁盘上的块不一致,需要被 DBWn 进程写入数据文件。
N : 缓冲区内容与磁盘一致。
TEMPVARCHAR2(1)指示是否为临时段中的块(用于排序、哈希连接等)。
PINGVARCHAR2(1)指示该块是否在 RAC 环境中被"ping"了(即一个实例需要强制从另一个实例的缓存中写入该块)。
STALEVARCHAR2(1)指示缓冲区内容是否为"陈旧的"(在 RAC 中,远程实例已使其失效)。
OBJDNUMBER数据块所属的数据对象ID。这是最关键的字段之一,可以与 DBA_OBJECTS.DATA_OBJECT_ID 关联,从而确定是哪个表或索引的块。
HLADDRRAW(48)
NXT_HASH
PRV_HASH
RAW(48)
NXT_REPL
PRV_REPL
RAW(48)
BARAW(48)
LRU_FLAGNUMBER指示缓冲区在 LRU 列表中的位置状态。用于管理缓冲区的老化(aging)和替换。
SET_DSCRAW(48)
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 chains latch 子级。
    • 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`**。 `XBHXBH包含了比VBH‘∗∗更详细、更底层的字段∗∗,但这些字段绝大多数是供Oracle内部开发人员使用的,其含义晦涩且不受支持。∗∗重要警告∗∗:∗∗严禁∗∗直接查询‘XBH` **更详细、更底层的字段**,但这些字段绝大多数是供 Oracle 内部开发人员使用的,其含义晦涩且不受支持。 **重要警告**:**严禁**直接查询 `XBH更详细、更底层的字段,但这些字段绝大多数是供Oracle内部开发人员使用的,其含义晦涩且不受支持。重要警告严禁直接查询XBH。所有诊断信息都应通过公开的、安全的 V$BH` 视图获取。


5. 相关底层详细原理

  1. Buffer Cache 管理
    Oracle 使用哈希算法来管理 Buffer Cache。数据块地址(DBA = FILE# + BLOCK#)通过一个哈希函数,被映射到一个哈希桶(Hash Bucket) 中。
  2. 缓存缓冲区链(CBC)Latch
    每个哈希桶由一个 cache buffers chains latch 保护。要访问或修改一个桶内的缓冲区链表,进程必须先获取相关的 CBC latch。这就是 HLADDR 字段的意义,也是 cache buffers chains latch 争用的根源。
  3. 缓冲区状态
    • xcur:只有一个实例可以持有该块的当前版本(排他模式)。
    • scur:多个实例可以同时持有该块的当前版本(共享模式),常见于 RAC。
    • cr:为了实现读一致性,如果一个查询开始时,某个块已经被修改,Oracle 会利用 Undo 数据在 Buffer Cache 中构建一个该块在查询开始那个时间点的版本,这个版本就是 CR 块。一个当前块可能有多个 CR 版本。
  4. LRU 算法与写入
    脏块(DIRTY='Y')会被 DBWn 进程根据检查点事件或LRU算法写入磁盘。NXT_REPLPRV_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;

然后可以用 HLADDRV$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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值