首页 文章

如何安全地安排Oracle dbms_scheduler作业时区和DST

提问于
浏览
5

我正在尝试设置一个DBMS_SCHEDULER作业,以便在每年1月1日凌晨1点在Oracle 11g上运行 . 如何设置其属性以确保它不会在错误的时间内执行,因为时区差异或夏令时 .

我花了很多时间浏览Oracle文档,但我还没有达到确定性水平 .

顺便说一句,以下是我发现并考虑与该主题相关的规则:

Job attributes

start_date 此属性指定计划启动此作业的第一个日期 . 如果start_date和repeat_interval保留为null,则作业将在计划启动后立即运行 . 对于重复使用日历表达式指定重复间隔的作业,start_date用作参考日期 . 第一次安排作业运行是当前日期或之后的日历表达式的第一个匹配 . 调度程序无法保证作业将在准确的时间执行,因为系统可能过载,因此资源不可用 .

repeat_interval 此属性指定作业重复的频率 . 您可以使用日历或PL / SQL表达式指定重复间隔 . 评估指定的表达式以确定下次运行作业的时间 . 如果未指定repeat_interval,则作业将仅在指定的开始日期运行一次 . 有关详细信息,请参阅"Calendaring Syntax" .

Rules in Calendaring syntax

  • 日历语法不允许您指定时区 . 而是调度程序从start_date参数中检索时区 . 如果作业必须遵循夏令时调整,则必须确保为start_date的时区指定区域名称 . 例如,在纽约将start_date时区指定为'US/Eastern'将确保自动应用夏令时调整 . 如果将start_date的时区设置为绝对偏移量(例如'-5:00'),则不会遵循夏令时调整,并且您的作业执行将在一年中的一半时间内关闭 .

  • 当start_date为NULL时,调度程序将确定重复间隔的时区,如下所示:

  • 将检查会话时区是否为区域名称 . 会话时区可以通过以下任一方式设置:发出ALTER SESSION语句,例如:SQL> ALTER SESSION SET time_zone = 'Asia/Shanghai';设置ORA_SDTZ环境变量 .

  • 如果会话时区是绝对偏移而不是区域名称,则调度程序将使用DEFAULT_TIMEZONE Scheduler属性的值 . 有关更多信息,请参阅SET_SCHEDULER_ATTRIBUTE过程 .

  • 如果DEFAULT_TIMEZONE属性为NULL,则调度程序将在启用作业或窗口时使用systimestamp的时区 .

3 回答

  • 1

    我不确定这个答案是否真的通过了这个网站上的答案规则,但是在花了很多时间用谷歌搜索后我想出了以下解决方案:

    start_date      => CAST(trunc(sysdate, 'YEAR')+2/24 AS TIMESTAMP) at time zone 'Europe/Berlin'
    

    我相信这是最接近最安全的解决方案,因为:

    • 它使用时间戳而不是日期 - 我相信它会强制在给定时区内给定时间内真正执行作业,同时忽略DMBS_SCHEDULER default_timezone . 我还发现了一些建议,说直接使用时间戳也是不安全的,只有这个演员是安全的

    • 我手动选择了我需要的时区,希望它不会与本地设置发生冲突 . 至于我不清楚它是否真的与SESSIONTIMEZONE或DBTIMEZONE无关,是否影响正常的运行时间 .

    • 我使用了一点点黑客,即使请求是工作应该在午夜之后开始,我已将其设置为凌晨2点,希望即使在时区不好和夏令时不好的情况下它也会被移动最大-2小时 .

    我对这个解决方案感到满意,如果我完全清楚当作业实际执行的时间与服务器的本地时间,SESSIONTIMEZONE,DBTIMEZONE,start_date时区和DBMS_SCHEDULER时区有关 .

    我也对时区规范感到不满,因为它有4个与之相关的缩写--LMT,CET,CEST,CEMT,其中CEST在我看来是完全错误的 . 我的目标是使用CET和夏令时(冬天!=夏天) .

  • 1

    您可以使用它来确保传递带时区的时间戳,并且开始日期将具有时区名称(美国/东部)而不是偏移量(例如:5:00) . 这样,正如oracle文档提到的上述片段一样,Scheduler将跟踪DST .

    • 创建一个SCHEDULE
    declare 
     v_start_date timestamp with time zone;
    BEGIN 
    
    select localtimestamp at time zone 'US/Eastern' into v_start_date from dual; --US/Eastern
    
    DBMS_SCHEDULER.CREATE_SCHEDULE(
          schedule_name => 'SAMPLE_SCHEDULE',
          start_date => v_start_date,
          repeat_interval => 'FREQ=DAILY; BYHOUR=10; BYMINUTE= 15',
          comments => 'Runs daily at the specified hour.'); 
    END;
    

    为了确保你已正确设置它,你可以运行:ALTER SESSION SET nls_timestamp_tz_format ='MM-DD-YYYY HH24:MI:SS tzr tzd';

    现在,创建两个调度,一个如上,一个使用sysdate作为start_date参数,并执行下面的查询 .

    • 检查TIMEZONE select * fromUSER_SCHEDULER_SCHEDULES;

    v1:27-MAR-14 11.44.24.929282 AM US/EASTERN

    V2:

    27-MAR-14 05.44.54.000000 PM +05:00

  • 0

    要为此添加更多信息,请在检查修改是否成功时添加 . 运行查询:从all_scheduler_jobs中选择*,其中owner ='schema_name' . 在那里你可以看到字段start_date,它有时区的类型时区,它包含如下数据:2017-12-05 01:55:00,000000000 EUROPE / YOUR_CITY最后有时区信息确认它已正确保存为了工作 . 然后,next_run_date也与start_date对齐,它还应显示时区详细信息 .

相关问题