Oracle AQ(Advanced Queuing)是Oracle数据库内置的消息队列功能,它把消息的发送、接收、路由全部放到数据库内部完成,凭借与事务的一致性获得很多企业的青睐。要使用AQ,第一步不是创建队列,而是先创建队列表(Queue Table)。队列表本质上是存放队列和消息数据的特殊表,队列必须依附于某个队列表才能存在。理解队列表的原理和管理方法,是用好Oracle AQ的基础,也是排查消息堆积、空间膨胀等问题的必修课。

队列表的基本概念与创建方法
队列表是一个特殊的堆表,除了用户数据外,还包含消息ID、入队时间、相关性标识、重试次数等系统管理的列。Oracle会自动为每个队列表生成若干辅助对象,包括索引、IOT格式的从属表(用于多消费者队列)、时间管理表以及相关的触发器和视图。正因为它不是普通表,运维时不建议直接用DDL去修改它的结构,所有管理操作都应通过DBMS_AQADM包完成。
创建队列表的核心是DBMS_AQADM.CREATE_QUEUE_TABLE过程,最常用的参数包括队列表名、队列负载类型、是否支持多消费者以及存储表空间。下面是一个典型示例:
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE(
queue_table => 'ORDERS_QTAB',
queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE',
multiple_consumers => TRUE,
message_grouping => DBMS_AQADM.NONE,
comment => '订单消息队列表',
tablespace => 'USERS',
storage_clause => NULL
);
END;
/
queue_payload_type决定了消息的格式,既可以选系统自带的SYS.AQ$_JMS_TEXT_MESSAGE等类型,也可以使用自定义的对象类型或RAW。multiple_consumers设为TRUE后,一条消息可以被多个订阅者同时消费,适合发布订阅场景;设为FALSE则是点对点模型。需要注意的是,队列表一旦创建,负载类型和多消费者属性都无法通过ALTER修改,只能删除重建,所以设计阶段要想清楚消息模型。
队列与队列表的关系及日常管理
队列必须建立在队列表之上,一个队列表可以承载多个队列。创建队列使用CREATE_QUEUE,指定队列名和所属队列表,然后执行START_QUEUE启用入队出队。这三个步骤是标准流程:
BEGIN
-- 在已有队列表上创建队列
DBMS_AQADM.CREATE_QUEUE(
queue_name => 'ORDERS_QUEUE',
queue_table => 'ORDERS_QTAB',
max_retries => 5,
retry_delay => 60
);
-- 启用队列的入队和出队
DBMS_AQADM.START_QUEUE(queue_name => 'ORDERS_QUEUE');
END;
/
修改队列表使用DBMS_AQADM.ALTER_QUEUE_TABLE,它支持调整的主要是primary_instance、secondary_instance这类RAC环境下的实例亲和属性,以及修改注释。停止队列、启动队列分别对应STOP_QUEUE和START_QUEUE,停止时可通过enqueue和dequeue参数控制只禁用其中一个方向。
删除的顺序必须反过来:先删队列,再删队列表。如果队列表上还存在未删除的队列,直接执行DROP_QUEUE_TABLE会报ORA-24057错误。正确的清理方式如下:
BEGIN DBMS_AQADM.STOP_QUEUE(queue_name => 'ORDERS_QUEUE'); DBMS_AQADM.DROP_QUEUE(queue_name => 'ORDERS_QUEUE'); DBMS_AQADM.DROP_QUEUE_TABLE(queue_table => 'ORDERS_QTAB'); END; /
另外要注意force参数。带上force => TRUE时,Oracle会自动删除队列表上的所有队列再删表,虽然方便,但如果队列里还有未处理的消息,会连带丢弃,生产环境务必确认业务允许后再使用。
队列表的监控与常见问题排查
队列表的消息堆积和空间膨胀是最常见的运维问题。查看队列信息可以用USER_QUEUES和USER_QUEUE_TABLES数据字典视图,统计队列中的消息数量则查询与队列表同名且带AQ$前缀的视图。例如队列表为ORDERS_QTAB,对应的消息视图就是AQ$ORDERS_QTAB。常用排查SQL如下:
-- 查看当前用户下的队列及所属队列表 SELECT queue_name, queue_table, queue_type, max_retries FROM user_queues; -- 统计队列表中等待消费的消息数量 SELECT COUNT(*) AS pending_msgs FROM aq$orders_qtab WHERE msg_state = 'READY'; -- 查看消息保留情况与队列表存储属性 SELECT queue_table, recipients, message_grouping, compatible FROM user_queue_tables;
出队后的消息默认不会立即删除,而是进入PROCESSED状态保留一段时间,这个行为由retention_time参数控制。如果消息量大又没有设置合理的保留时间,队列表会持续增长。可以在创建队列时指定retention_time,也可以出队后定期执行清理。对于已经膨胀的队列表,可以在停用相关队列后执行DBMS_AQADM.PURGE_QUEUE_TABLE按条件批量清除消息,比逐条删除高效得多:
DECLARE
po dbms_aqadm.aq$_purge_options_t;
BEGIN
po.block := TRUE;
po.delivery_mode := dbms_aqadm.persistent;
DBMS_AQADM.PURGE_QUEUE_TABLE(
queue_table => 'ORDERS_QTAB',
purge_condition => NULL, -- NULL表示清空全部消息
purge_options => po
);
END;
/
还有一个容易踩坑的场景:直接用DROP TABLE删除队列表会留下元数据残留,之后在数据字典中还能看到队列信息,但操作报错。遇到这种情况,应改用DBMS_AQADM.DROP_QUEUE_TABLE配合force参数清理,必要时再借助迁移过程修正异常状态。日常管理中坚持所有操作都走DBMS_AQADM接口,就能从根本上避免这类残留问题,保持消息体系的长期稳定。
Oracle AQ队列表高级队列DBMS_AQADM修改时间:2026-09-08 18:11:18