CPU_PER_CALL和CPU_PER_SESSION是Oracle资源管理器中限制单次调用或会话累计CPU时间的硬配额,单位为十分之一秒(如200=20秒),仅在启用Resource Manager并为consumer group显式配置时生效。
Oracle 中 CPU_PER_CALL 和 CPU_PER_SESSION 是什么
这两个参数是 oracle resource manager(资源管理器)里用于限制单次调用或整个会话 cpu 使用量的硬性配额,单位是“十分之一秒”(centiseconds)。不是百分比,也不是毫秒,容易误读成“100 = 1 秒”,实际是 100 = 10 秒 —— 因为 100 × 0.1s = 10s。
它们只在启用 Resource Manager 并分配了对应 consumer group 的情况下才生效;单纯在 profile 里设没用,这点常被忽略。
-
CPU_PER_CALL:限制单条 SQL 或 PL/SQL 调用(比如一次SELECT、一次EXECUTE)最多能用多少 CPU 时间,超时直接报ORA-02392: exceeded session limit on CPU usage -
CPU_PER_SESSION:限制整个会话生命周期内累计可用的 CPU 时间,超限后会话被强制断开,错误通常是ORA-02393: exceeded call limit on CPU usage(注意错误码不同) - 两者不叠加生效:
CPU_PER_CALL先触发就先报错,不会等累计到CPU_PER_SESSION
怎么设置才真正生效
必须走 Resource Manager 流程,不能靠 ALTER PROFILE 或初始化参数。常见错误是改了 profile 却发现完全没限制效果——因为 profile 里的 CPU_PER_CALL 字段在 12c+ 已废弃,仅保留兼容性,实际不生效。
- 创建 resource plan:
BEGIN DBMS_RESOURCE_MANAGER.CREATE_PLAN(plan => 'LIMIT_CPU_PLAN'); END; - 定义 consumer group(比如叫
low_cpu_group),并把用户映射过去:DBMS_RESOURCE_MANAGER.SET_CONSUMER_GROUP_MAPPING - 在 plan directive 中显式指定:
CPU_P1(或CPU_P2等)配合CPU_PER_CALL和CPU_PER_SESSION值,例如:CPU_PER_CALL => 200表示最多 20 秒 - 启用 plan:
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'LIMIT_CPU_PLAN'
没执行最后一步 ALTER SYSTEM,前面全白配。
为什么设置了还是被绕过
几个高频漏点导致限制形同虚设:
- 用户属于
DEFAULT_CONSUMER_GROUP,而 plan directive 没给它配任何CPU_PER_*值(默认不限制) - 用了
DBMS_SCHEDULER或后台 job,job 默认运行在SYS_GROUP,不受你配的 plan 约束 - DBA 用户(如
SYS、SYSTEM)即使被映射到受限 group,Oracle 也会跳过资源限制(这是硬编码行为,无法关闭) - 并行查询(
PX)的 CPU 计算方式特殊:按 coordinator + 所有 slave 进程的总 CPU 累加,但CPU_PER_CALL只检查 coordinator 的单次调用耗时,容易误判“没超限”
性能和监控怎么看是否起作用
别只看会不会报错,要确认真实压制效果。关键视图是 V$RSRC_SESSION_INFO 和 V$RSRC_CONSUMER_GROUP:
-
V$RSRC_SESSION_INFO里CPU_WAIT_TIME突增,说明 session 在等 CPU 配额释放,限制已介入 -
V$RSRC_CONSUMER_GROUP的ACTIVE_SESSIONS和EXECUTION_WAITERS能看出 group 是否排队 - 查
V$SESSION的RESOURCE_CONSUMER_GROUP字段,确保当前 session 真的落在你配的 group 里(不是OTHER_GROUPS) - 测试时用
SELECT /*+ NO_PARALLEL */ COUNT(*) FROM big_table CONNECT BY LEVEL 这类纯 CPU 消耗语句,避免 I/O 干扰判断
真正难的是并行场景下的配额解释权在 Oracle 内部调度器手里,文档没写清怎么分摊,实测值常和理论值偏差较大。










