
好的,我们来深入探讨一个相对底层但非常重要的 Oracle 19C 动态性能视图:V$PERSISTENT_QMN_CACHE。这个视图揭示了 Advanced Queueing (AQ) 子系统内部为提升性能而采用的缓存机制。
1. 作用与概述
V$PERSISTENT_QMN_CACHE 视图用于显示和监控为队列监控进程(QMNn)缓存的消息句柄(Message Handles)的信息。这是一种针对缓冲消息(Buffered Messaging) 的性能优化机制。
- 核心目的: 减少频繁入队(ENQUEUE)和出队(DEQUEUE)缓冲消息时,为每个消息在共享池中分配和释放内存所带来的开销。
- 缓存对象: 缓存的是“消息句柄”,这是一个内存结构,包含了处理消息所需的核心信息(如消息ID、队列名称、状态等),而不是消息负载(payload)本身。
- 工作原理: 当应用程序使用缓冲消息时,AQ 会尝试从该缓存中获取一个空闲的消息句柄来使用,用完后并非立即释放,而是将其标记为空闲并放回缓存,供后续操作快速重用。这避免了频繁的内存分配与垃圾回收。
2. 使用场景
此视图主要用于高级性能诊断和调优,场景相对专业:
-
缓冲消息性能调优:
- 当处理大量、小尺寸的缓冲消息时,如果性能未达预期,检查此视图可以判断缓存机制是否在有效工作。高
GETS和低HIT_RATIO可能意味着缓存配置不足或工作负载模式不适合缓存。
- 当处理大量、小尺寸的缓冲消息时,如果性能未达预期,检查此视图可以判断缓存机制是否在有效工作。高
-
内存使用分析:
- 监控
CACHE_SIZE和CACHE_USED可以了解为 QMN 进程预留的缓存内存使用情况。
- 监控
-
诊断罕见的竞争问题:
- 在极端高并发的情况下,如果缓存本身成为瓶颈(虽然少见),可以通过此视图的统计信息辅助诊断。
3. 字段含义详解
该视图的字段主要描述了缓存的使用效率和状态。
| 字段名称 | 数据类型 | 含义说明 |
|---|---|---|
| CACHE_ID | NUMBER | 缓存的唯一标识符。通常与 QMN 进程或某种特定的缓存类型相关联。 |
| CACHE_SIZE | NUMBER | 该缓存所能容纳的消息句柄的最大数量。这是缓存的容量上限。 |
| CACHE_USED | NUMBER | 当前缓存中已被占用的消息句柄数量。 |
| CACHE_AVG_LEN | NUMBER | 缓存中链表(或类似结构)的平均长度。用于内部管理和诊断。 |
| GETS | NUMBER | 自实例启动以来,从此缓存中成功获取(即分配到)消息句柄的总次数。 |
| HITS | NUMBER | 在所有的 GETS 中,直接从缓存中获取到空闲句柄而无需分配新内存的次数。这是衡量缓存有效性的核心。 |
| HIT_RATIO | NUMBER | 缓存命中率,计算公式为 HITS / GETS。比值越接近 1,说明缓存效率越高。比值较低则意味着大多数请求都需要分配新内存,缓存作用有限。 |
| SCAN_COUNT | NUMBER | 缓存被扫描以寻找空闲句柄的总次数。 |
| SCAN_COMPLETE | NUMBER | 成功完成扫描的次数。 |
| TIME_REMOVED | NUMBER | 从缓存中移除句柄的总次数(或相关时间统计,具体含义较隐晦)。通常与缓存清理或LRU算法相关。 |
| TIME_REUSED | NUMBER | 缓存中的句柄被重用的总次数(或相关时间统计)。 |
4. 相关视图与基表
-
相关动态性能视图:
V$BUFFERED_QUEUES: 显示缓冲队列的实时状态信息(如当前消息数、等待数)。V$PERSISTENT_QMN_CACHE的缓存机制正是为了高效服务这些队列。V$BUFFERED_SUBSCRIBERS/V$BUFFERED_PUBLISHERS: 显示缓冲消息的订阅者和发布者信息。它们的活动会直接触发缓存的操作(GETS)。V$QMON_SERVER_STATS: 显示执行实际工作的 QMNn 进程的统计信息。这些进程是缓存的主要使用者。V$SHARED_POOL_RESERVED: 因为消息句柄的内存最终来自于共享池,如果缓存失效导致大量内存分配,可能会在共享池保留区中观察到压力。
-
基表(Underlying Base Table):
- XKXFPC∗∗:这是‘VKXFPC**: 这是 `VKXFPC∗∗:这是‘VPERSISTENT_QMN_CACHE
所依赖的底层内存结构(基表)。XKXFPC‘存储了关于持久化QMN缓存的实际内存结构和统计信息。如前所述,∗∗XKXFPC` 存储了关于持久化 QMN 缓存的实际内存结构和统计信息。如前所述,**XKXFPC‘存储了关于持久化QMN缓存的实际内存结构和统计信息。如前所述,∗∗X 表是内部表,其结构未公开,严禁直接查询。 - 视图定义查询:
SELECT view_definition FROM v$fixed_view_definition WHERE view_name = 'GV$PERSISTENT_QMN_CACHE';
- XKXFPC∗∗:这是‘VKXFPC**: 这是 `VKXFPC∗∗:这是‘VPERSISTENT_QMN_CACHE
5. 底层详细原理
-
为什么需要缓存?
- 每次处理一个缓冲消息,都需要在内存中构建一个“消息句柄”结构。如果每秒处理成千上万条消息,频繁的
malloc和free操作会成为显著的性能瓶颈,并可能导致共享池碎片化。 - 缓存通过对象池(Object Pool)模式来解决这个问题。预先分配一批对象(消息句柄),使用时从池中借出,使用后归还池中,而非直接销毁。
- 每次处理一个缓冲消息,都需要在内存中构建一个“消息句柄”结构。如果每秒处理成千上万条消息,频繁的
-
缓存的工作流程:
- 获取句柄 (Get): 当一个 QMNn 进程需要处理一条新的缓冲消息时,它首先向自己的缓存(由
CACHE_ID可能关联到特定进程)请求一个空闲的消息句柄。- 命中 (Hit): 缓存中有空闲句柄,直接返回给请求者。
HITS计数器增加。 - 未命中 (Miss): 缓存中无空闲句柄,需要从共享池中分配一个新的消息句柄。
GETS增加,但HITS不增加。
- 命中 (Hit): 缓存中有空闲句柄,直接返回给请求者。
- 释放句柄 (Release): 当消息处理完毕(如已成功传播或出队),其句柄不会被释放,而是被 QMNn 进程标记为空闲并归还到缓存中,供未来使用。
- 缓存管理: 缓存通常使用 LRU(最近最少使用)或类似算法进行管理。如果缓存已满(
CACHE_USED=CACHE_SIZE),当有新句柄需要缓存时,最老的、未被使用的句柄可能会被真正释放回系统,以腾出空间。
- 获取句柄 (Get): 当一个 QMNn 进程需要处理一条新的缓冲消息时,它首先向自己的缓存(由
-
性能影响:
- 高命中率: 意味着绝大多数操作都重用了现有的内存块,极大地减少了内存管理开销,提升了吞吐量,降低了延迟。
- 低命中率: 意味着缓存机制未能有效工作。可能原因包括:
- 缓存大小 (
CACHE_SIZE) 配置过小,无法容纳典型工作负载。 - 工作负载突发性极强,瞬间需要大量新句柄,超过了缓存的容量。
- 消息处理的生命周期过长,导致句柄被占用很久无法归还,缓存得不到有效循环。
- 缓存大小 (
6. 相关知识点介绍
- 缓冲消息 vs. 持久消息:
- 持久消息: 消息数据和安全存储在磁盘表(队列表)中,保证持久性。内存主要用于缓存。
- 缓冲消息: 为极致性能而设计,消息主要存储在内存中,仅在特定条件下(如内存压力、检查点)才写入磁盘。
V$PERSISTENT_QMN_CACHE的优化正是针对缓冲消息的内存操作。
AQ_TM_PROCESSES参数: 此参数定义了最大的 QMNn 进程数。每个 QMNn 进程可能有自己关联的缓存结构,因此此参数间接影响了缓存的总内存占用。- 共享池(Shared Pool): 消息句柄的内存来自于共享池。如果缓存效率低下,会导致共享池的分配活动增加,可能引发共享池竞争或碎片化问题。
7. 常用查询 SQL
1. 查看缓存总体效率和利用率
SELECT cache_id,
cache_size,
cache_used,
ROUND((cache_used / cache_size) * 100, 2) AS cache_used_pct,
gets,
hits,
ROUND((hits / gets) * 100, 2) AS hit_ratio
FROM v$persistent_qmn_cache
WHERE gets > 0 -- 避免除以零
ORDER BY cache_id;
2. 识别效率低下的缓存
SELECT cache_id,
gets,
hits,
hit_ratio,
cache_size,
cache_used
FROM v$persistent_qmn_cache
WHERE gets > 1000 -- 只看有显著活动的缓存
AND hit_ratio < 0.9 -- 命中率低于90%
ORDER BY hit_ratio ASC;
3. 监控缓存的使用情况随时间的变化(需要定期运行并对比结果)
-- 第一次运行,存入临时表或记录结果
SELECT SYSDATE AS snap_time, cache_id, gets, hits, hit_ratio
FROM v$persistent_qmn_cache;
-- 等待一段时间后,第二次运行并计算差值
SELECT current.cache_id,
current.gets - previous.gets AS gets_delta,
current.hits - previous.hits AS hits_delta,
ROUND( (current.hits - previous.hits) /
NULLIF((current.gets - previous.gets), 0), 4) AS hit_ratio_delta
FROM v$persistent_qmn_cache current, my_previous_snapshot previous
WHERE current.cache_id = previous.cache_id;
总结
V$PERSISTENT_QMN_CACHE 动态性能视图为我们打开了观察 Oracle Advanced Queueing 内部性能优化机制的一扇窗。它不关注消息内容或任务调度,而是专注于内存操作的效率。
通过此视图,您可以:
- 验证 缓冲消息的缓存机制是否按预期有效工作。
- 量化 缓存带来的性能收益(通过命中率)。
- 诊断 潜在的、由内存分配引起的性能瓶颈。
- 评估 当前缓存大小的配置是否与工作负载匹配。
理解这个视图,意味着您对 Oracle AQ 的理解从“它做了什么”深入到了“它如何高效地完成这些工作”的层面,是进行高端性能调优的必备知识。它与其他 V$QMON_* 和 V$BUFFERED_* 视图结合,构成了对 AQ 系统从业务逻辑到内存管理的全方位监控。
欢迎关注我的公众号《IT小Chen》
5246

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



