Oracle 19c调用DBMS_JOB.SUBMIT创建作业调度时间偏移7小时问题
问题背景
客户将数据库迁移至AWS平台运行的Oracle 19c后,所有通过DBMS_JOB.SUBMIT接口创建的Oracle作业,调度运行时间均比数据库服务器时间晚7小时。
测试场景如下:客户端机器本地时间为7:00时执行测试代码,此时AWS数据库服务器时间为14:00,但实际创建出的作业计划运行时间为21:00。
测试代码:
DECLARE I NUMBER; BEGIN DBMS_JOB.SUBMIT(I, 'DECLARE I NUMBER; BEGIN SELECT COUNT(1) INTO I FROM DUAL; END;'); COMMIT; END;
复现验证
测试人员连接客户数据库做对照测试,结果如下:
- 客户端操作系统时区设置为
(UTC+00:00) London时,执行上述测试代码后作业会被立即调度执行 - 客户端操作系统时区修改为
(UTC-08:00) Pacific Time(测试时为太平洋夏令时,实际偏移UTC-7)模拟客户侧环境时,执行代码后作业会被调度为7小时后运行
问题成因
该问题是Oracle遗留调度接口DBMS_JOB的时区处理逻辑导致的:
DBMS_JOB是Oracle早期版本提供的调度接口,作业的执行时间字段next_date为不带时区信息的DATE类型,本身不具备时区感知能力- 调用
DBMS_JOB.SUBMIT时如果不显式指定next_date参数,接口会默认取客户端会话当前时间作为首次执行时间写入数据字典 - Oracle作业后台协调进程判断作业是否到期时,使用的是数据库服务器操作系统的本地时间解读
next_date字段值 - 本次场景中AWS Oracle数据库默认使用UTC时区,客户侧客户端使用太平洋夏令时(UTC-7),二者存在7小时时差:写入
next_date的是客户端本地时间,调度进程按服务器时区解读该时间值,最终导致作业执行时间比预期晚7小时。当时区设置为UTC的伦敦环境连接时,会话时区和数据库时区一致,因此作业可以立即执行,和测试结果吻合。
解决方案
按落地优先级从高到低排列:
- 显式传参指定
next_date:调用DBMS_JOB.SUBMIT时不要依赖默认值,显式将next_date参数指定为数据库端的SYSDATE,保证写入的执行时间是基于数据库时区计算的,修改后示例代码如下:
DECLARE I NUMBER; BEGIN DBMS_JOB.SUBMIT( JOB => I, WHAT => 'DECLARE I NUMBER; BEGIN SELECT COUNT(1) INTO I FROM DUAL; END;', NEXT_DATE => SYSDATE, INTERVAL => NULL ); COMMIT; END;
- 统一会话与数据库时区:客户端连接数据库后,先执行
ALTER SESSION SET TIME_ZONE = DBTIMEZONE;,将会话时区修改为和数据库时区一致,从会话层面消除时区差。 - 替换为官方推荐调度接口:将
DBMS_JOB替换为DBMS_SCHEDULER创建作业,该接口是Oracle 10g之后推出的时区感知调度组件,原生支持作业时区配置,不会出现这类隐式时间偏移问题。 - 修改数据库时区对齐客户端:将AWS上Oracle数据库的时区修改为客户侧使用的太平洋时区,该方案需要重启数据库,会影响所有依赖数据库系统时间的业务逻辑,非必要不推荐。
内容的提问来源于stack exchange,提问作者PDM
相关产品推荐
相关产品推荐

