Resource Manager 不能直接限制某用户在某个时间段执行查询,它仅管理CPU、I/O等资源消耗,不支持基于日历时间的访问控制;可行方案是使用登录触发器(Logon Trigger)在连接时校验时间并拒绝非授权时段登录,或结合DBMS_SCHEDULER动态切换Resource Plan实现时段资源降级。
Resource Manager 能不能直接限制“某用户在某个时间段执行查询”
不能。oracle resource manager 本身不提供基于日历时间(比如“只允许周一到周五 9:00–17:00”)的 sql 执行拦截能力。它管理的是资源消耗(cpu、i/o、并发会话数等),不是时间窗口访问控制。想靠 dbms_resource_manager 的 plan directive 或 consumer group 机制硬拦住非工作时间的 select,会失败。
真正可行的替代方案:用 Logon Trigger + SYSDATE 判断
最直接、可控的方式是创建登录触发器,在用户连接时检查当前时间,不符合策略就抛错断连。虽然不阻止已建立连接后的查询,但能有效防止非授权时段的新会话建立——这对多数运维管控场景已足够。
示例逻辑:
CREATE OR REPLACE TRIGGER block_offhours_login
AFTER LOGON ON DATABASE
DECLARE
v_day PLS_INTEGER := TO_NUMBER(TO_CHAR(SYSDATE, 'D')); -- 1=Sunday, 2=Monday...
v_hour PLS_INTEGER := TO_NUMBER(TO_CHAR(SYSDATE, 'HH24'));
BEGIN
IF (v_day IN (1, 7) OR (v_hour NOT BETWEEN 9 AND 17)) THEN
IF USER = 'REPORT_USER' THEN
RAISE_APPLICATION_ERROR(-20001, 'Login denied: REPORT_USER only allowed Mon-Fri 09:00-17:00');
END IF;
END IF;
END;- 注意
TO_CHAR(SYSDATE, 'D')的周起始依赖数据库NLS_TERRITORY,生产环境务必先验证(如美国默认周日=1,中国可能不同) - 触发器对所有用户生效,必须用
USER = 'xxx'显式限定目标账户,否则可能误锁 DBA - 该触发器不影响已存在的会话,仅作用于新连接;若需实时中断运行中查询,得配合
DBMS_SCHEDULER定时查V$SESSION并ALTER SYSTEM KILL SESSION
Resource Manager 配合时间感知计划:间接实现“时段资源降级”
如果你的目标不是完全禁止查询,而是让非工作时间的查询变慢(比如限制 CPU 占用、强制串行执行),Resource Manager 可以做到——通过动态切换 resource plan。
操作要点:
- 用
DBMS_SCHEDULER.CREATE_JOB创建两个定时任务:一个在工作时间开始前启用高配 plan(如DAY_PLAN),另一个在结束时切回低配 plan(如NIGHT_PLAN) -
NIGHT_PLAN中给目标 consumer group(如REPORT_GROUP)设置CPU_P1 = 0、PARALLEL_DEGREE_LIMIT_P1 = 1,并开启ACTIVE_SESSION_POOL_P1限并发 - 必须确保数据库已启用 Resource Manager:
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'DAY_PLAN';,且初始 plan 不为''
这种做法不会报错或断连,但会让非工作时间的查询响应明显变长——适合“柔性管控”场景,比如避免报表拖垮白天 OLTP 性能。
为什么别用 Profile 的 FAILED_LOGIN_ATTEMPTS 或 IDLE_TIME 来凑合
有人试图用 profile 限制登录频次或空闲时长来模拟时间管控,这是典型误用:
-
FAILED_LOGIN_ATTEMPTS针对密码错误次数,和时间无关 -
IDLE_TIME控制会话空闲超时,无法区分“现在是不是工作时间” - profile 没有时间条件表达能力,所有限制都是静态、全局生效的
强行套用只会导致策略失效或误伤,不如直接上 logon trigger 或 scheduler + resource plan 组合。
真要按时间控查询,核心就两条路:登录时掐断(trigger),或运行时压资源(scheduler + RM)。前者简单粗暴,后者需要更精细的 plan 设计和测试——特别是 CPU_P1 和 PARALLEL_DEGREE_LIMIT_P1 的数值,不同版本 Oracle 行为略有差异,上线前务必在测试库跑真实负载验证。


















