Benutzer-Werkzeuge

Webseiten-Werkzeuge


prog:plsql_sleep_19c

PL/SQL - Eine DB Session "schlafen" legen - Wie und welche Sleep Funktion in welcher Oracle DB Version einsetzen?

Aufgabe: Eine Datenbank Session soll mit einer sleep Funktion eine gewisse Zeit pausiert werden.

Z.B. in einem Monitoring Job, der jede Minute prüfen ob ein andere Job noch aktiv ist und keine Fehler geworfen hat.

DBMS_LOCK.sleep - ab 18c bzw. in 19c / 23c auf keine Fall mehr verwenden! Gar nicht mehr offiziell in der Doku!

Möglichkeiten:

APEX Installiert:

  • APEX_UTIL.pause ( aber nur bis maximal 120 Sekunden! , Wait Event „PL/SQL lock timer“)

DB Version vor 18c:

  • Java über java.lang.Thread.sleep ( Waits Events in der Statistik sichtbar, nicht verwirren lassen!)
  • DBMS_LOCK.sleep (Sicherheitsproblem mit generellen Zugriff auf das Package DBMS_LOCK, Wait Event „PL/SQL lock timer“))

DB Version ab 18c

  • DBMS_SESSION.sleep ( so sollte es schon immer sein … )

APEX_UTIL.pause

Ist in der DB APEX installiert, kann auf APEX_UTIL zurückgegriffen werden.

10 Sekunden warten:

BEGIN
 APEX_UTIL.PAUSE(10);
END;
/

Jetzt ist nur die Frage, wie das intern umgesetzt wird. Das Synonym „APEX_UTIL“ zeigt jedenfalls auf das Package „htmldb_util“ und von da auf „WWV_FLOW_UTILITIES.PAUSE“, dort wird dann „SYS.DBMS_LOCK.SLEEP(L_SECONDS);“ gekapselt.

Und alle Werte über 120 Sekunden werden mit dem Default 120 Sekunden überschrieben!

D.h. die maximale Wartezeit beträgt 120 Sekunden.

Eigene Routine um auch länger als 120s warten zu können und dann ab der Version 18 gleich DBMS_SESSION.sleep verwenden zu können:

-- 
CREATE OR REPLACE 
PROCEDURE sleep_plsql(p_seconds IN NUMBER)
IS
  v_parts pls_integer;
  v_LastRound pls_integer;
  v_max_pos_seconds pls_integer:=120;
BEGIN
 
 
  $IF DBMS_DB_VERSION.VER_LE_12 $THEN
 	v_max_pos_seconds:=120;
  $ELSE
   	v_max_pos_seconds:=3600;
  $END
 
   IF p_seconds/v_max_pos_seconds > 1 THEN
      --- floor largest integer equal to or less than
      v_parts:=FLOOR(p_seconds/v_max_pos_seconds);
      -- return the remainder 
      v_LastRound:=MOD( p_seconds, v_max_pos_seconds );
   ELSE
      v_parts:=0;
      v_LastRound:=p_seconds;
   END IF;
 
 
   -- if we are on 18 use the DBMS_SESSION sleep methode!
   $IF DBMS_DB_VERSION.VER_LE_12 $THEN
 
          -- we need an oracle apex security context .-(
          -- put in your workspace
          apex_util.set_security_group_id (p_security_group_id => apex_util.find_security_group_id (p_workspace => 'GPI'));
 
          --  APEX_UTIL.PAUS cann only sleep may 120s!
          -- 
          IF v_parts > 0 THEN
              FOR i IN 1..v_parts
               loop
                 APEX_UTIL.PAUSE(120);
               END loop;
           END IF;
           ---
           IF v_LastRound > 0 THEN
              APEX_UTIL.PAUSE(v_LastRound);
           END IF; 
    $ELSE	 
          --  DBMS_SESSION can only sleep may 3600s!
          -- 
          IF v_parts > 0 THEN
              FOR i IN 1..v_parts
               loop
                 DBMS_SESSION.sleep(3600);
               END loop;
          END IF;
          ---
          IF v_LastRound > 0 THEN
              DBMS_SESSION.sleep(v_LastRound);
          END IF;          
    $END
END;
/
 
--- testen
 
SET serveroutput ON
BEGIN
dbms_output.put_line('-- Info start at '||to_char(systimestamp,'hh24:mi:SSxFF'));
sleep_plsql(11);
dbms_output.put_line('-- Info start at '||to_char(systimestamp,'hh24:mi:SSxFF'));
sleep_plsql(119);
dbms_output.put_line('-- Info start at '||to_char(systimestamp,'hh24:mi:SSxFF'));
sleep_plsql(123);
dbms_output.put_line('-- Info start at '||to_char(systimestamp,'hh24:mi:SSxFF'));
sleep_plsql(245);
dbms_output.put_line('-- Info start at '||to_char(systimestamp,'hh24:mi:SSxFF'));
sleep_plsql(545);
dbms_output.put_line('-- Info start at '||to_char(systimestamp,'hh24:mi:SSxFF'));
END;
/

Problem ORA-20987: APEX - Package variable g_security_group_id must be set

Fehler:

ORA-20987: APEX - Package variable g_security_group_id must be SET. - Contact your application administrator.

Lösung, Security ID setzen!

  -- we need an oracle apex security context .-(
  -- put in your workspace
 
  apex_util.set_security_group_id (p_security_group_id => apex_util.find_security_group_id (p_workspace => 'GPI'));
 

Das ist dann leider nicht so schön, damit wird der Code doch sehr von der Umgebung abhängig.

Wait Event - PL/SQL lock timer

In der DB ist „PL/SQL lock timer“ der Wait Event hinter diesem Aufruf in den Wait Statistiken.


Java

Verwendung der Java Klasse „java.lang.Thread“

CREATE OR REPLACE PROCEDURE sleep_java(p_milli_seconds IN NUMBER) 
  AS 
  LANGUAGE JAVA NAME 'java.lang.Thread.sleep(long)';

Nachteil: In den AWR / Statspack Berichten wird dann OVJM gerne als häufigster Wait aufgezeigt, sind noch andere Java Komponenten im Einsatz verfälscht das stark das Ergebniss.

Wie:  OVJM Waits mit java.lang.Thread.sleep in der Datenbank


DBMS_LOCK.sleep

Nachteil:

  • Sicherheitsprobleme mit DBMS_LOCK habe dazu geführt das her keine Public Synonym in der DB für dieses Package vorliegt und damit ein direkter Grant benötigt wird!
Ab 18c auf keine Fall mehr verwenden! Gar nicht mehr offiziell in der Doku!

DBMS_SESSION.sleep

Ab der Version 18c!

Session „schläft“ für n Sekunden, der Maximal Wert beträgt 3600 Sekunden (ansonsten gibt es ein ORA-38148: invalid time limit specified!).

Aus der Doku „The smallest increment can be entered in hundredths of a second; for example, 1.95 is a legal time value.“

Beispiel

BEGIN
 dbms_session.sleep(10.45);
END;

Problem! nur bis 3600s möglich!

SYS@GPI-?>BEGIN
  2   dbms_session.sleep(3601);
  3  END;
  4  /
BEGIN
*
ERROR at line 1:
ORA-38148: invalid TIME LIMIT specified
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 79
ORA-06512: at "SYS.DBMS_SESSION", line 432
ORA-06512: at line 2

Siehe dazu den Code oben mit APEX, hier nochmal die wichigen Teile für eine Umgebung die noch 12c und 19c für die Software verwendt:

PROCEDURE sleep_plsql(p_seconds IN NUMBER)
IS
 
  v_parts pls_integer:=0;
  v_LastRound pls_integer:=0;
  v_max_pos_seconds pls_integer:=120;
  v_use_java BOOLEAN:=FALSE;
 
BEGIN
 
  $IF DBMS_DB_VERSION.VER_LE_12 $THEN
        v_max_pos_seconds:=120;
  $ELSE
        v_max_pos_seconds:=3600;
  $END
 
   IF p_seconds/v_max_pos_seconds > 1 THEN
      --- floor largest integer equal to or less than
      v_parts:=FLOOR(p_seconds/v_max_pos_seconds);
      -- return the remainder
      v_LastRound:=MOD( p_seconds, v_max_pos_seconds );
   ELSE
      v_parts:=0;
      v_LastRound:=p_seconds;
   END IF;
 
    -- if we are on 18 use the DBMS_SESSION sleep methode!
    $IF DBMS_DB_VERSION.VER_LE_12 $THEN
 
    ... USE apex sleep see code above 
 
 
    $ELSE 
       --  DBMS_SESSION can only sleep may 3600s!     
       -- 
          IF v_parts > 0 THEN
              FOR i IN 1..v_parts
               loop
                 DBMS_SESSION.sleep(3600);
               END loop;
          END IF;
          ---
          IF v_LastRound > 0 THEN
              DBMS_SESSION.sleep(v_LastRound);
          END IF;          
   $END      
 
END;

Quellen

Diese Website verwendet Cookies. Durch die Nutzung der Website stimmen Sie dem Speichern von Cookies auf Ihrem Computer zu. Außerdem bestätigen Sie, dass Sie unsere Datenschutzbestimmungen gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information
prog/plsql_sleep_19c.txt · Zuletzt geändert: 2023/02/01 12:12 von gpipperr