
好的,我们来对 Oracle 19C 数据库中的 V$PERSISTENT_SUBSCRIBERS 动态性能视图进行一次全面、深入的解析。这个视图是 Oracle Advanced Queuing (AQ) 持久化架构中的关键组成部分。
1. 作用与概述
V$PERSISTENT_SUBSCRIBERS 视图的主要作用是展示在系统全局区 (SGA) 中缓存的、与持久化队列相关联的订阅者(Subscriber)的实时状态信息。
核心概念:订阅者 (Subscriber)
在 Oracle Advanced Queuing 中,订阅者是一个对队列中的消息感兴趣的实体。它可以是:
- 消费者:从队列中出队并处理消息的应用程序或用户。
- 传播目标:另一个数据库或队列,消息将被传播(转发)到那里。
订阅信息可以持久化地存储在数据字典中。V$PERSISTENT_SUBSCRIBERS 显示了这些持久化订阅者在内存中的活动状态,这对于监控消息流的去向、诊断传播问题以及确保系统健康至关重要。
2. 使用场景
-
AQ 监控与故障诊断:
- 当消息没有被预期的消费者处理时,检查订阅者是否存在及其状态 (
STATE)。 - 诊断跨数据库的 AQ 传播 (Propagation) 问题。确认传播作业对应的订阅者是否活跃。
- 当消息没有被预期的消费者处理时,检查订阅者是否存在及其状态 (
-
系统健康检查:
- 验证在数据库实例重启后,所有关键的持久化订阅者状态是否已正确恢复。
- 监控是否有订阅者被意外禁用 (
ENABLED字段)。
-
性能分析:
- 通过
DEQUEUED_MESSAGE_NUMBER等字段,了解订阅者的消息处理量。 - 结合
V$PERSISTENT_QUEUES,分析特定队列的订阅者数量和负载分布。
- 通过
-
安全与权限审计:
- 查看哪些用户/程序 (
NAME) 订阅了哪些队列的消息。
- 查看哪些用户/程序 (
3. 字段含义详解
以下是 V$PERSISTENT_SUBSCRIBERS 视图中各个字段的详细说明,已按逻辑块整理以便于理解:
| 字段块 | 字段名 | 数据类型 | 含义说明 |
| :— | :— | :— | :— |
| 标识字段 | QUEUE_ID | NUMBER | 队列的内部对象标识符。可与 DBA_OBJECTS.OBJECT_ID 或 DBA_QUEUES.QUEUE_ID 关联。 |
| | QUEUE_NAME | VARCHAR2(128) | 订阅者所订阅的队列的名称。 |
| | SCHEMA_NAME | VARCHAR2(128) | 队列所属的 Schema 名称。 |
| | NAME | VARCHAR2(128) | 订阅者的名称。对于传播,这通常是传播作业的名称或接收队列的地址。 |
| | ADDRESS | VARCHAR2(128) | 订阅者的地址。通常用于传播,格式为 [schema.]queue@dblink。 |
| 状态与控制 | STATE | NUMBER | 订阅者的内部状态代码。表示订阅者在内存中的活动状态(如正常、等待、错误)。此为内部值,通常非零值可能表示异常。 |
| | ENABLED | VARCHAR2(5) | 指示订阅者是否被启用。值为 YES 或 NO。如果为 NO,则该订阅者不会收到消息。 |
| | SID | NUMBER | 当前正在为该订阅者处理消息的会话标识符 (Session ID)。如果为 NULL 或 0,表示没有活动会话。 |
| | TRANSACTION_ID | VARCHAR2(22) | 当前正在为该订阅者处理消息的事务ID。 |
| 统计信息 | DEQUEUED_MESSAGE_NUMBER | NUMBER | 该订阅者已从此队列中成功出队的消息总数。 |
| | DEQUEUE_ATTEMPTS | NUMBER | 该订阅者尝试出队消息的总次数(包括成功和失败的尝试)。 |
| | LAST_DEQUEUE_TIME | DATE | 该订阅者最后一次成功出队消息的时间戳。 |
| | DEQUEUE_MESSAGE_NUMBER | NUMBER | 该订阅者准备出队的下一条消息的消息编号。 |
| 配置与上下文 | QUEUE_TO_QUEUE | VARCHAR2(5) | 指示这是否是队列到队列的订阅(通常是传播)。值为 YES 或 NO。 |
| | RULESET_NAME | VARCHAR2(128) | 与此订阅关联的规则集名称。规则用于定义订阅者对哪些消息感兴趣。 |
| | SPARE1 | NUMBER | 保留字段,供 Oracle 内部使用。 |
| | SPARE2 | VARCHAR2(128) | 保留字段,供 Oracle 内部使用。 |
| 多租户 | CON_ID | NUMBER | 包含此订阅者的容器的 ID。在 CDB 环境中,指示该订阅者属于哪个 PDB。 |
4. 相关视图与基表
-
相关动态性能视图:
V$PERSISTENT_QUEUES:提供队列本身的运行时信息。这是最直接相关的视图,通常需要关联查询(QUEUE_ID)。DBA_QUEUE_SUBSCRIBERS:数据字典视图,提供静态的、持久化的订阅定义。V$PERSISTENT_SUBSCRIBERS是其内存中的运行时状态映射。V$BUFFERED_SUBSCRIBERS:类似于本视图,但用于缓冲队列的订阅者。V$PROPAGATION_SENDER/V$PROPAGATION_RECEIVER:专门用于监控 AQ 传播的发送和接收端,与传播类型的订阅者紧密相关。
-
底层基表:
V$PERSISTENT_SUBSCRIBERS是一个动态性能视图,其数据不直接来源于普通的用户基表。它的源头是 SGA 中的内存结构,该结构由QMNn(Queue Monitor) 进程管理。
持久化订阅者的定义信息存储在数据字典基表中(如SYS.SUB$和SYS.OBJ$等)。当数据库启动或订阅被创建/修改时,这些定义信息被加载到 SGA 中并转化为高效的内存对象,V$PERSISTENT_SUBSCRIBERS视图正是这些内存对象的投影。
5. 详细原理与知识点
1. 订阅者如何工作?
订阅者与队列是多对多的关系。一个队列可以有多个订阅者(发布-订阅模式),一个订阅者也可以订阅多个队列。当一条消息入队时,AQ 引擎会根据每个订阅者定义的规则(RULESET_NAME)来判断该消息是否适用于此订阅者。如果是,该消息对该订阅者变为可见并可被出队。
2. 持久化与内存缓存:
- 定义持久化:使用
DBMS_AQADM.ADD_SUBSCRIBER过程添加的订阅者,其元数据被保存在数据字典中,是持久的。 - 状态缓存:为了高性能,订阅者的活动状态(如出队指针
DEQUEUE_MESSAGE_NUMBER、统计信息、当前会话SID等)被维护在 SGA 中。V$PERSISTENT_SUBSCRIBERS查看的就是这个缓存。 - 恢复:实例崩溃后,SMON 进程在恢复期间会从事务日志和数据字典中重建这些内存中的订阅者状态信息,确保出队位置等关键状态得以恢复,避免消息丢失或重复处理。
3. 传播订阅者:
这是最重要的订阅者类型之一。当订阅者 ADDRESS 指向一个数据库链接时,它就定义了一个传播。QMNn 进程会自动处理传播:
- 它作为订阅者从源队列出队消息。
- 通过数据库链接将消息入队到目标队列。
QUEUE_TO_QUEUE和ADDRESS字段清晰地标识了这类订阅者。
4. 关键知识点:
QMNn进程的核心作用:该后台进程不仅管理队列,还负责处理传播订阅者的消息移动。- 状态一致性:
DEQUEUE_MESSAGE_NUMBER等字段保证了在事务上下文中,每个订阅者都能在其正确的顺序位置上继续处理消息,即使在系统故障后也是如此。 - 与缓冲订阅者的区别:
V$PERSISTENT_SUBSCRIBERS只关注受重做日志保护的持久化订阅。缓冲订阅由V$BUFFERED_SUBSCRIBERS管理,其生命周期和保证不同。
6. 常用查询SQL
1. 查看所有持久化订阅者的概况:
SELECT s.SCHEMA_NAME,
s.QUEUE_NAME,
s.NAME AS SUBSCRIBER_NAME,
s.ADDRESS,
s.ENABLED,
s.DEQUEUED_MESSAGE_NUMBER,
TO_CHAR(s.LAST_DEQUEUE_TIME, 'YYYY-MM-DD HH24:MI:SS') AS LAST_DEQUEUE_TIME,
s.CON_ID
FROM V$PERSISTENT_SUBSCRIBERS s
ORDER BY s.SCHEMA_NAME, s.QUEUE_NAME, s.NAME;
2. 检查被禁用的订阅者(可能是问题的根源):
SELECT SCHEMA_NAME, QUEUE_NAME, NAME, ADDRESS, STATE
FROM V$PERSISTENT_SUBSCRIBERS
WHERE ENABLED = 'NO';
3. 监控传播订阅者的状态(非常常用):
SELECT SCHEMA_NAME, QUEUE_NAME, NAME, ADDRESS, DEQUEUED_MESSAGE_NUMBER, STATE
FROM V$PERSISTENT_SUBSCRIBERS
WHERE QUEUE_TO_QUEUE = 'YES' AND ADDRESS IS NOT NULL;
4. 查找长时间没有活动的订阅者(结合队列消息数判断是否积压):
SELECT s.SCHEMA_NAME, s.QUEUE_NAME, s.NAME,
s.DEQUEUED_MESSAGE_NUMBER,
s.LAST_DEQUEUE_TIME,
q.NUM_READY_MSGS
FROM V$PERSISTENT_SUBSCRIBERS s
JOIN V$PERSISTENT_QUEUES q ON (s.QUEUE_ID = q.QUEUE_ID)
WHERE s.LAST_DEQUEUE_TIME < SYSDATE - INTERVAL '5' MINUTE
AND q.NUM_READY_MSGS > 0
ORDER BY s.LAST_DEQUEUE_TIME;
5. 在CDB中按PDB查询订阅者信息:
SELECT c.NAME AS PDB_NAME,
s.SCHEMA_NAME,
s.QUEUE_NAME,
s.NAME AS SUBSCRIBER_NAME
FROM V$PERSISTENT_SUBSCRIBERS s
JOIN V$CONTAINERS c ON s.CON_ID = c.CON_ID
ORDER BY c.NAME, s.SCHEMA_NAME, s.QUEUE_NAME;
总结
V$PERSISTENT_SUBSCRIBERS 视图是 Oracle Advanced Queuing 消息流系统的“路由表”。它提供了消息消费者和传播目标的实时、内存中的快照。通过它,可以:
- 可视化消息流向:清晰看到消息从队列被路由到何处(哪个应用程序或哪个目标数据库)。
- 确保系统健康:验证所有必要的订阅者是否活跃且已启用。
- 诊断复杂问题:当消息流中断时,快速定位是哪个订阅者出现了问题(禁用、挂起、错误)。
- 理解内部机制:洞察 AQ 如何通过持久化订阅者和内存状态管理来实现可靠的消息传递。
对于依赖 Oracle AQ 或 Oracle Streams / Goldengate 进行系统集成、异步处理和分布式工作流的环境,熟练掌握此视图是进行高级运维和保证业务连续性的关键。
欢迎关注我的公众号《IT小Chen》

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



