DBMS_SCHEDULER und die Sommerzeit, DB-Job richtig timen
Bei der Weiterentwicklung eines Projektes ist aufgefallen, dass ein DB-Job 1 Stunde zu früh ausgeführt wird.
Geplant für 06:20Uhr wird er bereits um 05:20Uhr ausgeführt:
          , to_char(r.req_start_date,'dd.mm.yyyy hh24:mi:ss.ff TZR') "Required Start Date TZ"
          , to_char(r.actual_start_date,'dd.mm.yyyy hh24:mi:ss.ff TZR') "Actual Start Date TZ"
    from ALL_SCHEDULER_JOB_LOG L, ALL_SCHEDULER_JOB_RUN_DETAILS R
  where l.Owner = 'my'
      and l.job_name = 'myJob'
      and l.log_id = r.log_id (+)
  order by 1 desc;
Log Date TZ | Required Start Date TZ | Actual Start Date TZ |
---|---|---|
31.12.2022 05:21:06.062526 +01:00 | 31.12.2022 06:20:00.366020 +02:00 | 31.12.2022 06:20:00.445268 +02:00 |
30.12.2022 05:22:15.510405 +01:00 | 30.12.2022 06:20:00.160237 +02:00 | 30.12.2022 06:20:00.354385 +02:00 |
29.12.2022 05:21:29.299165 +01:00 | 29.12.2022 06:20:00.019715 +02:00 | 29.12.2022 06:20:00.135502 +02:00 |
Ein für 06:20Uhr in Zeitzone +02:00 geplanter Start startet in Zeitzone +01:00 eben um 05:20Uhr.
Nur war das anders gedacht!
Erstellt wurde der Job per Script im Sept 2022:
  (
    job_name => 'myJob'
    ,start_date => TO_TIMESTAMP_TZ('20220928','yyyymmdd')
    ,repeat_interval => 'FREQ=DAILY; BYHOUR=6; BYMINUTE=20; BYSECOND=0'
    ,end_date => NULL
    ,job_class => 'DEFAULT_JOB_CLASS'
    ,job_type => 'STORED_PROCEDURE'
    ,job_action => 'myProc'
    ,comments => 'myProc-Kommentar'
    ,enabled => false
  );
Dabei scheint dem START_DATE eine größere Rolle zuzukommen, als vermutet.
Die Prüfung per
          , REPEAT_INTERVAL
          , LAST_START_DATE
          , NEXT_RUN_DATE
    from SYS.ALL_SCHEDULER_JOBS
  where JOB_NAME = 'myJob';
Und eben dieses +02:00 ist das Problem. Da NEXT_RUN_DATE basierend auf START_DATE berechnet wird, gibt es eine Verschiebung bei der Zeitumstellung. Im September befindet sich die Datenbank in Zeitzone UTC+02:00, weil Sommerzeit. Im Winter liegt sie in UTC+01:00. Da +02:00 hart vorgegeben ist, startet der Job im Winter früher.
Was kann man tun?
Grundsätzlich gibt es für SYS.DBMS_SCHEDULER.CREATE_JOB folgende Optionen:
- ,start_date => TO_TIMESTAMP_TZ('20230101','yyyymmdd') --> wie oben, nicht gut!
- ,start_date => TO_TIMESTAMP_TZ('20230101 EUROPE/BERLIN','yyyymmdd TZR') --> Zeitzonenregion (TZR) mit angeben -> beste Lösung, da eindeutig!
- Parameter start_date weglassen --> dann bestimmt die Datenbank über verschiebende Ebenen den Wert. (Siehe dazu den Blogeintrag von Martin Preiss.)
Im Beispiel ergeben sich für die drei Varianten folgende START_DATE:
Option | NEXT_RUN_DATE | START_DATE |
---|---|---|
1 | 04.01.2023 06:20:00,628493 +01:00 | 2023/01/01 00:00:00.000000 +01:00 |
2 | 04.01.2023 06:20:00,946355 +01:00 | 2023/01/01 00:00:00.000000 Europe/Berlin |
3 | 04.01.2023 06:20:00,588781 +01:00 | 2023/01/03 10:59:59.588781 Europe/Vienna |
Fazit: Mit der Umstellung auf DBMS_SCHEDULER ist die Job-Steuerung der Datenbank sehr viel leistungsfähiger geworden. Gleichzeitig gibt es aber auch mehr Punkte zu beachten.
  (
    job_name => 'myJob'
    ,start_date => TO_TIMESTAMP_TZ('20230101 EUROPE/BERLIN','yyyymmdd TZR')
    ,repeat_interval => 'FREQ=DAILY; BYHOUR=6; BYMINUTE=20; BYSECOND=0'
    ,end_date => NULL
    ,job_class => 'DEFAULT_JOB_CLASS'
    ,job_type => 'STORED_PROCEDURE'
    ,job_action => 'myProc'
    ,comments => 'myProc-Kommentar'
    ,enabled => false
  );
Den bestehende Job umzustellen schaut dann so aus:
  (
    name => 'myJob'
    , attribute => 'start_date'
    , value => TO_TIMESTAMP_TZ('20220928 EUROPE/BERLIN','yyyymmdd TZR')
  );
Eine gute Erläuterung zu diesem Thema findet sich im Blog von Martin Preiss:
https://martinpreiss.blogspot.com/2012/03/dbmsscheduler-und-die-sommerzeit.html
Kommentare
Kommentar veröffentlichen