Benutzer-Werkzeuge

Webseiten-Werkzeuge


prog:plsql_sleep_19c

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
prog:plsql_sleep_19c [2019/05/22 09:38] – [PL/SQL - Eine DB Session "schlafen" legen - Wie und welche Sleep Funktion einsetzen?] gpipperrprog:plsql_sleep_19c [2023/02/01 12:12] (aktuell) – [DBMS_SESSION.sleep] gpipperr
Zeile 1: Zeile 1:
-=====PL/SQL - Eine DB Session "schlafen" legen - Wie und welche Sleep Funktion einsetzen? =====+=====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.
  
-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
  
 +<note warning>DBMS_LOCK.sleep - ab 18c bzw. in 19c / 23c auf keine Fall mehr verwenden! Gar nicht mehr offiziell in der Doku!</note>
  
-Möglichkeiten:+ 
 + 
 +**Möglichkeiten:**
  
 **APEX Installiert:** **APEX Installiert:**
-  * APEX_UTIL.pause+  * APEX_UTIL.pause ( aber <fc #800000>nur bis maximal 120 Sekunden!</fc> , Wait Event "PL/SQL lock timer"
  
 **DB Version vor 18c:** **DB Version vor 18c:**
-  * Java  +  * Java über java.lang.Thread.sleep  ( <fc #800000>Waits Events in der Statistik</fc> sichtbar, nicht verwirren lassen!) 
-  * DBMS_LOCK.sleep+  * DBMS_LOCK.sleep (<fc #800000>Sicherheitsproblem</fc> mit generellen Zugriff auf das Package DBMS_LOCK, Wait Event "PL/SQL lock timer"))
  
  
 **DB Version ab 18c** **DB Version ab 18c**
-  * DBMS_SESSION.sleep+  * <fc #008080>**DBMS_SESSION.sleep**</fc>  ( <fc #008000>so sollte es schon immer sein ...</fc> )  
  
  
Zeile 37: Zeile 42:
 </code> </code>
  
 +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:
 +<code sql>
 +-- 
 +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;
 +/
 +
 +
 +</code>
 +
 +
 +===Problem ORA-20987: APEX - Package variable g_security_group_id must be set ====
 +
 +Fehler:
 +<code sql>
 +ORA-20987: APEX - Package variable g_security_group_id must be set. - Contact your application administrator.
 +</code>
 +
 +Lösung, Security ID setzen!
 +<code sql>
 +  -- 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'));
 +  
 +</code>
 +
 +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 <fc #800000>** "PL/SQL lock timer"**</fc> der Wait Event hinter diesem Aufruf in den Wait Statistiken. 
  
 ---- ----
Zeile 42: Zeile 163:
 ==== Java ==== ==== Java ====
  
 +Verwendung der Java Klasse "java.lang.Thread"
  
  
 +<code sql>
 +create or replace PROCEDURE sleep_java(p_milli_seconds in number) 
 +  AS 
 +  LANGUAGE JAVA NAME 'java.lang.Thread.sleep(long)';
 +</code>
 +
 +
 +<fc #800000>**Nachteil:**</fc> 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:
 +{{ :prog:oracle_ovjm_waits_with_java_sleep.png | OVJM Waits mit java.lang.Thread.sleep in der Datenbank }}
  
 ---- ----
Zeile 53: Zeile 186:
 Nachteil: Nachteil:
  
-  * Sicherheitsprobleme mit DBMS_LOCK habe dazugeführt das her keine Public Synonym in der DB für dieses Package vorliegt und damit ein direkter Grant benötigt wird! +  * 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! + 
 +<note warning>Ab 18c auf keine Fall mehr verwenden! Gar nicht mehr offiziell in der Doku!</note>
  
 ---- ----
Zeile 62: Zeile 195:
 ====DBMS_SESSION.sleep==== ====DBMS_SESSION.sleep====
  
-Ab der Version 18!+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
 +<code sql>
 +
 +begin
 + dbms_session.sleep(10.45);
 +end;
 +
 +</code>
 +
 +
 +=== Problem! nur bis 3600s möglich! ===
 +
 +<code sql>
 +
 +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
 +</code>
 +
 +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:
 +<code sql>
 +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;
 +</code>
  
 ---- ----
prog/plsql_sleep_19c.1558510700.txt.gz · Zuletzt geändert: 2019/05/22 09:38 von gpipperr