Kill Blocking Job entfernt Blocking Sessions

Kill-Blocker-Job erkennt und entfernt Blocking-Sessions

Der Kill-Blocker-Job dient dazu, um Blocking-Sessions in der Oracle Datenbank zu erkennen und eventuell existierende „Blocker“ zu identifizieren und per E-Mail zu melden.

Dabei kann festgelegt werden, in welchen Intervallen die Blocking-Sessions gemeldet werden und ob sie automatisch gekillt werden oder nicht.

In diesem Beispiel wurde definiert, dass alle Blocking-Sessions die länger als 30 Sekunden blockieren, automatisch identifiziert werden und per E-Mail an mehrere eMail Adressen gemeldet werden.

Weiters versucht der Kill-Blocker-Job die Blocker-Sessions automatisch zu killen.

1) Tablespace BLOCKMON erstellen

Für den neuen User BLOCKMON kann optional ein Tablespace erstellt werden. In unserem Fall erstellen wir einen neuen Tablespace.

create tablespace BLOCKMON datafile size 100M autoextend on maxsize 5G;

2) User BLOCKMON erstellen

create user BLOCKMON identified by PASSWORDDEFINIEREN default tablespace BLOCKMON;

Dem User BLOCKMON müssen folgende, notwendige Rechte vergeben werden:

GRANT CREATE SESSION TO BLOCKMON;
GRANT SELECT ANY DICTIONARY TO BLOCKMON;
GRANT CREATE PROCEDURE,CREATE SEQUENCE,CREATE VIEW,CREATE TABLE TO BLOCKMON;
ALTER USER BLOCKMON QUOTA UNLIMITED ON USERS;
GRANT "RESOURCE" TO BLOCKMON ;
ALTER USER BLOCKMON DEFAULT ROLE "RESOURCE";
GRANT CREATE JOB TO BLOCKMON ;
GRANT ALTER SYSTEM TO BLOCKMON ;
GRANT UNLIMITED TABLESPACE TO BLOCKMON ;

3) Tabellen als User BLOCKMON erstellen

Als nächster Schritt müssen folgende Tabellen erstellt werden.
In diesen Tabellen werden die Details zu den Blockern gespeichert – wie zum Beispiel die Kill-Logdaten und Lock-Logdaten.

3-1- DDL für die Tabelle KILLLOG

CREATE TABLE "BLOCKMON"."KILLLOG" 
   (    "SNAP" NUMBER, 
    "TS" TIMESTAMP (6), 
    "INST_ID" NUMBER, 
    "SID" NUMBER, 
    "STMT" VARCHAR2(4000 BYTE)
   ) 
  TABLESPACE "BLOCKMON" ;

3-2- DDL für die Tabelle LOCKLOG

  CREATE TABLE "BLOCKMON"."LOCKLOG" 
   (    "INST_ID" NUMBER, 
    "ADDR" RAW(8), 
    "KADDR" RAW(8), 
    "SID" NUMBER, 
    "TYPE" VARCHAR2(2 BYTE), 
    "ID1" NUMBER, 
    "ID2" NUMBER, 
    "LMODE" NUMBER, 
    "REQUEST" NUMBER, 
    "CTIME" NUMBER, 
    "BLOCK" NUMBER, 
    "SNAP" NUMBER, 
    "TS" TIMESTAMP (6)
   ) 
  TABLESPACE "BLOCKMON" ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu Problem kommen, dass einige Spalten fehlen. Daher muss in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen werden und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table locklog;
create table locklog as (select s.*,1 snap,sysTIMESTAMP ts from gv$lock s where 1=0);

3-3- DDL für die Tabelle SESSIONLOG

  CREATE TABLE "BLOCKMON"."SESSIONLOG" 
   (    "INST_ID" NUMBER, 
    "SADDR" RAW(8), 
    "SID" NUMBER, 
    "SERIAL#" NUMBER, 
    "AUDSID" NUMBER, 
    "PADDR" RAW(8), 
    "USER#" NUMBER, 
    "USERNAME" VARCHAR2(30 BYTE), 
    "COMMAND" NUMBER, 
    "OWNERID" NUMBER, 
    "TADDR" VARCHAR2(16 BYTE), 
    "LOCKWAIT" VARCHAR2(16 BYTE), 
    "STATUS" VARCHAR2(8 BYTE), 
    "SERVER" VARCHAR2(9 BYTE), 
    "SCHEMA#" NUMBER, 
    "SCHEMANAME" VARCHAR2(30 BYTE), 
    "OSUSER" VARCHAR2(30 BYTE), 
    "PROCESS" VARCHAR2(24 BYTE), 
    "MACHINE" VARCHAR2(64 BYTE), 
    "PORT" NUMBER, 
    "TERMINAL" VARCHAR2(30 BYTE), 
    "PROGRAM" VARCHAR2(48 BYTE), 
    "TYPE" VARCHAR2(10 BYTE), 
    "SQL_ADDRESS" RAW(8), 
    "SQL_HASH_VALUE" NUMBER, 
    "SQL_ID" VARCHAR2(13 BYTE), 
    "SQL_CHILD_NUMBER" NUMBER, 
    "SQL_EXEC_START" DATE, 
    "SQL_EXEC_ID" NUMBER, 
    "PREV_SQL_ADDR" RAW(8), 
    "PREV_HASH_VALUE" NUMBER, 
    "PREV_SQL_ID" VARCHAR2(13 BYTE), 
    "PREV_CHILD_NUMBER" NUMBER, 
    "PREV_EXEC_START" DATE, 
    "PREV_EXEC_ID" NUMBER, 
    "PLSQL_ENTRY_OBJECT_ID" NUMBER, 
    "PLSQL_ENTRY_SUBPROGRAM_ID" NUMBER, 
    "PLSQL_OBJECT_ID" NUMBER, 
    "PLSQL_SUBPROGRAM_ID" NUMBER, 
    "MODULE" VARCHAR2(64 BYTE), 
    "MODULE_HASH" NUMBER, 
    "ACTION" VARCHAR2(64 BYTE), 
    "ACTION_HASH" NUMBER, 
    "CLIENT_INFO" VARCHAR2(64 BYTE), 
    "FIXED_TABLE_SEQUENCE" NUMBER, 
    "ROW_WAIT_OBJ#" NUMBER, 
    "ROW_WAIT_FILE#" NUMBER, 
    "ROW_WAIT_BLOCK#" NUMBER, 
    "ROW_WAIT_ROW#" NUMBER, 
    "TOP_LEVEL_CALL#" NUMBER, 
    "LOGON_TIME" DATE, 
    "LAST_CALL_ET" NUMBER, 
    "PDML_ENABLED" VARCHAR2(3 BYTE), 
    "FAILOVER_TYPE" VARCHAR2(13 BYTE), 
    "FAILOVER_METHOD" VARCHAR2(10 BYTE), 
    "FAILED_OVER" VARCHAR2(3 BYTE), 
    "RESOURCE_CONSUMER_GROUP" VARCHAR2(32 BYTE), 
    "PDML_STATUS" VARCHAR2(8 BYTE), 
    "PDDL_STATUS" VARCHAR2(8 BYTE), 
    "PQ_STATUS" VARCHAR2(8 BYTE), 
    "CURRENT_QUEUE_DURATION" NUMBER, 
    "CLIENT_IDENTIFIER" VARCHAR2(64 BYTE), 
    "BLOCKING_SESSION_STATUS" VARCHAR2(11 BYTE), 
    "BLOCKING_INSTANCE" NUMBER, 
    "BLOCKING_SESSION" NUMBER, 
    "FINAL_BLOCKING_SESSION_STATUS" VARCHAR2(11 BYTE), 
    "FINAL_BLOCKING_INSTANCE" NUMBER, 
    "FINAL_BLOCKING_SESSION" NUMBER, 
    "SEQ#" NUMBER, 
    "EVENT#" NUMBER, 
    "EVENT" VARCHAR2(64 BYTE), 
    "P1TEXT" VARCHAR2(64 BYTE), 
    "P1" NUMBER, 
    "P1RAW" RAW(8), 
    "P2TEXT" VARCHAR2(64 BYTE), 
    "P2" NUMBER, 
    "P2RAW" RAW(8), 
    "P3TEXT" VARCHAR2(64 BYTE), 
    "P3" NUMBER, 
    "P3RAW" RAW(8), 
    "WAIT_CLASS_ID" NUMBER, 
    "WAIT_CLASS#" NUMBER, 
    "WAIT_CLASS" VARCHAR2(64 BYTE), 
    "WAIT_TIME" NUMBER, 
    "SECONDS_IN_WAIT" NUMBER, 
    "STATE" VARCHAR2(19 BYTE), 
    "WAIT_TIME_MICRO" NUMBER, 
    "TIME_REMAINING_MICRO" NUMBER, 
    "TIME_SINCE_LAST_WAIT_MICRO" NUMBER, 
    "SERVICE_NAME" VARCHAR2(64 BYTE), 
    "SQL_TRACE" VARCHAR2(8 BYTE), 
    "SQL_TRACE_WAITS" VARCHAR2(5 BYTE), 
    "SQL_TRACE_BINDS" VARCHAR2(5 BYTE), 
    "SQL_TRACE_PLAN_STATS" VARCHAR2(10 BYTE), 
    "SESSION_EDITION_ID" NUMBER, 
    "CREATOR_ADDR" RAW(8), 
    "CREATOR_SERIAL#" NUMBER, 
    "ECID" VARCHAR2(64 BYTE), 
    "TS" TIMESTAMP (6), 
    "SNAP" NUMBER, 
    "INFO" VARCHAR2(100 BYTE)
   ) 
  TABLESPACE "BLOCKMON" ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu dem Problem kommen, dass einige Spalten fehlen. Daher muss hier in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table sessionlog;
create table sessionlog as (select s.*,sysTIMESTAMP ts,1 snap,cast('x' as  VARCHAR2(100)) info  from gv$session s where 1=0);

3-4- DDL für die Tabelle SQLLOG

  CREATE TABLE "BLOCKMON"."SQLLOG" 
   (    "INST_ID" NUMBER, 
    "SQL_TEXT" VARCHAR2(1000 BYTE), 
    "SQL_FULLTEXT" CLOB, 
    "SQL_ID" VARCHAR2(13 BYTE), 
    "SHARABLE_MEM" NUMBER, 
    "PERSISTENT_MEM" NUMBER, 
    "RUNTIME_MEM" NUMBER, 
    "SORTS" NUMBER, 
    "LOADED_VERSIONS" NUMBER, 
    "OPEN_VERSIONS" NUMBER, 
    "USERS_OPENING" NUMBER, 
    "FETCHES" NUMBER, 
    "EXECUTIONS" NUMBER, 
    "PX_SERVERS_EXECUTIONS" NUMBER, 
    "END_OF_FETCH_COUNT" NUMBER, 
    "USERS_EXECUTING" NUMBER, 
    "LOADS" NUMBER, 
    "FIRST_LOAD_TIME" VARCHAR2(19 BYTE), 
    "INVALIDATIONS" NUMBER, 
    "PARSE_CALLS" NUMBER, 
    "DISK_READS" NUMBER, 
    "DIRECT_WRITES" NUMBER, 
    "BUFFER_GETS" NUMBER, 
    "APPLICATION_WAIT_TIME" NUMBER, 
    "CONCURRENCY_WAIT_TIME" NUMBER, 
    "CLUSTER_WAIT_TIME" NUMBER, 
    "USER_IO_WAIT_TIME" NUMBER, 
    "PLSQL_EXEC_TIME" NUMBER, 
    "JAVA_EXEC_TIME" NUMBER, 
    "ROWS_PROCESSED" NUMBER, 
    "COMMAND_TYPE" NUMBER, 
    "OPTIMIZER_MODE" VARCHAR2(10 BYTE), 
    "OPTIMIZER_COST" NUMBER, 
    "OPTIMIZER_ENV" RAW(2000), 
    "OPTIMIZER_ENV_HASH_VALUE" NUMBER, 
    "PARSING_USER_ID" NUMBER, 
    "PARSING_SCHEMA_ID" NUMBER, 
    "PARSING_SCHEMA_NAME" VARCHAR2(30 BYTE), 
    "KEPT_VERSIONS" NUMBER, 
    "ADDRESS" RAW(8), 
    "TYPE_CHK_HEAP" RAW(8), 
    "HASH_VALUE" NUMBER, 
    "OLD_HASH_VALUE" NUMBER, 
    "PLAN_HASH_VALUE" NUMBER, 
    "CHILD_NUMBER" NUMBER, 
    "SERVICE" VARCHAR2(64 BYTE), 
    "SERVICE_HASH" NUMBER, 
    "MODULE" VARCHAR2(64 BYTE), 
    "MODULE_HASH" NUMBER, 
    "ACTION" VARCHAR2(64 BYTE), 
    "ACTION_HASH" NUMBER, 
    "SERIALIZABLE_ABORTS" NUMBER, 
    "OUTLINE_CATEGORY" VARCHAR2(64 BYTE), 
    "CPU_TIME" NUMBER, 
    "ELAPSED_TIME" NUMBER, 
    "OUTLINE_SID" NUMBER, 
    "CHILD_ADDRESS" RAW(8), 
    "SQLTYPE" NUMBER, 
    "REMOTE" VARCHAR2(1 BYTE), 
    "OBJECT_STATUS" VARCHAR2(19 BYTE), 
    "LITERAL_HASH_VALUE" NUMBER, 
    "LAST_LOAD_TIME" VARCHAR2(19 BYTE), 
    "IS_OBSOLETE" VARCHAR2(1 BYTE), 
    "IS_BIND_SENSITIVE" VARCHAR2(1 BYTE), 
    "IS_BIND_AWARE" VARCHAR2(1 BYTE), 
    "IS_SHAREABLE" VARCHAR2(1 BYTE), 
    "CHILD_LATCH" NUMBER, 
    "SQL_PROFILE" VARCHAR2(64 BYTE), 
    "SQL_PATCH" VARCHAR2(30 BYTE), 
    "SQL_PLAN_BASELINE" VARCHAR2(30 BYTE), 
    "PROGRAM_ID" NUMBER, 
    "PROGRAM_LINE#" NUMBER, 
    "EXACT_MATCHING_SIGNATURE" NUMBER, 
    "FORCE_MATCHING_SIGNATURE" NUMBER, 
    "LAST_ACTIVE_TIME" DATE, 
    "BIND_DATA" RAW(2000), 
    "TYPECHECK_MEM" NUMBER, 
    "IO_CELL_OFFLOAD_ELIGIBLE_BYTES" NUMBER, 
    "IO_INTERCONNECT_BYTES" NUMBER, 
    "PHYSICAL_READ_REQUESTS" NUMBER, 
    "PHYSICAL_READ_BYTES" NUMBER, 
    "PHYSICAL_WRITE_REQUESTS" NUMBER, 
    "PHYSICAL_WRITE_BYTES" NUMBER, 
    "OPTIMIZED_PHY_READ_REQUESTS" NUMBER, 
    "LOCKED_TOTAL" NUMBER, 
    "PINNED_TOTAL" NUMBER, 
    "IO_CELL_UNCOMPRESSED_BYTES" NUMBER, 
    "IO_CELL_OFFLOAD_RETURNED_BYTES" NUMBER, 
    "SNAP" NUMBER, 
    "TS" TIMESTAMP (6)
   ) 
  TABLESPACE "BLOCKMON" 
 LOB ("SQL_FULLTEXT") STORE AS BASICFILE (
  TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION 
  NOCACHE LOGGING 
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)) ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu dem Problem kommen, dass einige Spalten fehlen. Daher muss hier in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table sqllog;
create table sqllog as (select s.*,1 snap,sysTIMESTAMP ts from gv$sql s where 1=0);

3-5- DDL für die Tabelle SQLTEXTLOG

  CREATE TABLE "BLOCKMON"."SQLTEXTLOG" 
   (    "INST_ID" NUMBER, 
    "ADDRESS" RAW(8), 
    "HASH_VALUE" NUMBER, 
    "SQL_ID" VARCHAR2(13 BYTE), 
    "COMMAND_TYPE" NUMBER, 
    "PIECE" NUMBER, 
    "SQL_TEXT" VARCHAR2(64 BYTE), 
    "SNAP" NUMBER
   ) 
  TABLESPACE "BLOCKMON" ;

Hinweis: Bei einigen Datenbank-Releases kann es beim Insert zu dem Problem kommen, dass einige Spalten fehlen. Daher muss hier in so einem Fall die Struktur von den jeweiligen gv$ Views übernommen und in den Tabellen die fehlenden Spalten ergänzt werden.

drop table sqltextlog;
create table sqltextlog as (select s.*,1 snap from gv$sqltext s where 1=0);

3-6- DDL für die Tabelle TEST

  CREATE TABLE "BLOCKMON"."TEST" 
   (    "N" NUMBER
   ) 
  TABLESPACE "BLOCKMON" ;

4) Mehrere VIEWS als User BLOCKMON erstellen

4-1- DDL for View V_BLOCKED_SESSIONS

CREATE OR REPLACE FORCE VIEW "BLOCKMON"."V_BLOCKED_SESSIONS" ("TIMESTAMP", "SNAP", "INFO", "INST_ID", "SID", "USERNAME", "WAIT_CLASS",

"EVENT", "SECONDS_IN_WAIT", "SQL_ID", "SQL_TEXT") AS 
  select se.ts timestamp,se.snap,se.info,se.inst_id,se.sid,se.username,se.wait_class,se.event,se.seconds_in_wait,sq.sql_id,sq.sql_text
from sessionlog se,sqllog sq
where info='blocked'
and se.snap=sq.snap(+)
and se.sql_id=sq.sql_id(+);

4-2- DDL for View V_BLOCKING_DATA

CREATE OR REPLACE FORCE VIEW "BLOCKMON"."V_BLOCKING_DATA" ("SNAP", "INST_ID", "SID", "SQL_ID", "INFO", "WAIT_CLASS", "EVENT",

"SECONDS_IN_WAIT", "TIMESTAMP") AS 
  select se.snap,se.inst_id,se.sid,se.sql_id,se.info,se.wait_class,se.event,se.seconds_in_wait,se.ts timestamp from sessionlog se, killlog

ki,sqllog sq
where se.snap=ki.snap
and se.snap=sq.snap(+)
and se.inst_id=ki.inst_id
and se.sid=ki.sid
and se.sql_id=sq.sql_id(+);

4-3- DDL for View V_KILLED_SESSIONS

  CREATE OR REPLACE FORCE VIEW "BLOCKMON"."V_KILLED_SESSIONS" ("TIMESTAMP", "SNAP", "INFO", "INST_ID", "SID", "USERNAME", "WAIT_CLASS",

"EVENT", "SECONDS_IN_WAIT", "SQL_ID", "SQL_TEXT") AS 
  select ki.ts timestamp,ki.snap,se.info,ki.inst_id,ki.sid,se.username,se.wait_class,se.event,se.seconds_in_wait,sq.sql_id,sq.sql_text
from killlog ki,sessionlog se,sqllog sq
where ki.snap=se.snap
and ki.inst_id=se.inst_id
and ki.sid=se.sid
and se.info='blocker'
and se.snap=sq.snap(+)
and se.sql_id=sq.sql_id(+);

5) SEQUENCES als User BLOCKMON erstellen

DDL for Sequence SEQ

CREATE SEQUENCE  "BLOCKMON"."SEQ"  MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 607041 CACHE 20 NOORDER NOCYCLE ;

6) PROZEDUR WATCHDOG als User BLOCKMON erstellen

DDL for Procedure WATCHDOG

set define off;  
 
create or replace procedure BLOCKMON.watchdog as
snapid number;
rsid number;
sqlid varchar2(100);
stm varchar2(4000);
msg varchar2(32000);
blkdmsg varchar2(32000);
blkdsql varchar2(32000);
crlf varchar2(100):=chr(13)||chr(10);
flag number;
begin
select seq.nextval into snapid from dual;
for s in (select * from gv$session where blocking_session is not null) loop
--session
  insert into sessionlog (select s1.*,systimestamp,snapid,'blocked' from gv$session s1 where inst_id=s.inst_id and sid=s.sid);


 insert into sessionlog  (select s1.*,systimestamp,snapid,'blocker' from gv$session s1 where inst_id=s.blocking_instance and sid=s.blocking_session);


 insert into sessionlog  (select s1.*,systimestamp,snapid,'finalblocker' from gv$session s1 where inst_id=s.final_blocking_instance and sid=s.final_blocking_session);


--sql
  insert into sqllog (select s1.*,snapid,systimestamp from gv$sql s1 where sql_id=(select sql_id from gv$session s1 where inst_id=s.inst_id and sid=s.sid));


  insert into sqllog (select s1.*,snapid,systimestamp from gv$sql s1 where sql_id=(select sql_id from gv$session s1 where inst_id=s.blocking_instance and sid=s.blocking_session));


  insert into sqllog (select s1.*,snapid,systimestamp from gv$sql s1 where sql_id=(select sql_id from gv$session s1 whereinst_id=s.final_blocking_instance and sid=s.final_blocking_session));


--lock  
insert into locklog (select s1.*,snapid,systimestamp from gv$lock s1 where inst_id=s.inst_id and sid=s.sid);
insert into locklog (select s1.*,snapid,systimestamp from gv$lock s1 where inst_id=s.blocking_instance and sid=s.blocking_session);
insert into locklog (select s1.*,snapid,systimestamp from gv$lock s1 where inst_id=s.final_blocking_instance and sid=s.final_blocking_session);
--sqltext
insert into sqltextlog (select s1.*,snapid from gv$sqltext s1 where inst_id=s.inst_id and sql_id=s.sql_id);

blkdmsg:='instance:'||s.inst_id||crlf;
blkdmsg:=blkdmsg||'sid:'||s.sid||crlf;
blkdmsg:=blkdmsg||'username:'||s.username||crlf;
blkdmsg:=blkdmsg||'program:'||s.program||crlf;
blkdmsg:=blkdmsg||'module:'||s.module||crlf;
blkdmsg:=blkdmsg||'wait_class:'||s.wait_class||crlf;
blkdmsg:=blkdmsg||'evnt:'||s.event||crlf;
blkdmsg:=blkdmsg||'seconds_in_wait:'||s.seconds_in_wait||crlf;
blkdmsg:=blkdmsg||crlf;
  
flag:=0;
blkdsql:='';
for r in (select distinct piece,sql_text from sqltextlog where sql_id=s.sql_id order by piece) loop
  blkdsql:=blkdsql||r.sql_text||crlf;
  flag:=1;
end loop;
if flag=0 then 
  blkdsql:='--NONE--'||crlf;  
end if;
  
--kill nur final blocker
  if s.seconds_in_wait>=30 then
    for b in (select * from gv$session where inst_id=s.final_blocking_instance and sid=s.final_blocking_session) loop
--sqltext
    insert into sqltextlog (select s1.*,snapid from gv$sqltext s1 where inst_id=b.inst_id and sql_id=b.sql_id);
      
      
      stm:='alter system kill session '''||b.sid||','||b.serial#||',@'||b.inst_id||'''';
      insert into killlog values (snapid,systimestamp,b.inst_id,b.sid,stm);
msg:='will try to kill('||stm||')'||chr(10)||chr(13)||'(if this mail is not sent again, the kill has been successful)'||crlf;    
msg:=msg||crlf;
msg:=msg||'(there will be one mail per blocked session, if there is a cascading block situation, the blocks will be handled sequencially)'||

crlf;    
msg:=msg||crlf;
msg:=msg||'DETAILED INFORMATION:'||crlf;
msg:=msg||'---------------------'||crlf;
msg:=msg||crlf;
msg:=msg||'BLOCKER SESSION:'||crlf;
msg:=msg||'----------------'||crlf;
msg:=msg||'instance:'||b.inst_id||crlf;
msg:=msg||'sid:'||b.sid||crlf;
msg:=msg||'username:'||b.username||crlf;
msg:=msg||'program:'||b.program||crlf;
msg:=msg||'module:'||b.module||crlf;
msg:=msg||'wait_class:'||b.wait_class||crlf;
msg:=msg||'event:'||b.event||crlf;
msg:=msg||'seconds_in_wait:'||b.seconds_in_wait||crlf;
msg:=msg||crlf;
msg:=msg||'BLOCKED SESSION:'||crlf;
msg:=msg||'-------------------'||crlf;
msg:=msg||blkdmsg;
msg:=msg||crlf;
msg:=msg||'Current Statements:'||crlf;
msg:=msg||'-------------------'||crlf;
msg:=msg||'BLOCKER(normaly NONE):'||crlf;
flag:=0;
for r in (select distinct piece,sql_text from sqltextlog where sql_id=b.sql_id order by piece) loop
  msg:=msg||r.sql_text||crlf;
  flag:=1;
end loop;
if flag=0 then 
  msg:=msg||'--NONE--'||crlf;
end if;
msg:=msg||crlf;
msg:=msg||'BLOCKED:'||crlf;
msg:=msg||blkdsql||crlf;
msg:=msg||crlf;
msg:=msg||'historical data in schema BLOCKMON:'||crlf;
msg:=msg||'select * from blockmon.v_blocked_sessions where snap=<snap>'||crlf;
msg:=msg||'select * from blockmon.v_killed_sessions where snap=<snap>'||crlf;
msg:=msg||'Base Tables:'||crlf;
msg:=msg||'KILLLOG'||crlf;
msg:=msg||'LOCKLOG'||crlf;
msg:=msg||'SESSIONLOG'||crlf;
msg:=msg||'SQLLOG'||crlf;
msg:=msg||'SQLTEXTLOG'||crlf;

msg:=msg||crlf;

          utl_mail.send(
    sender      =>    'NAME@xyxyxy.com',
    recipients  =>  'EMPFÄNGER@xyxyxy.com, EMPFÄNGER@xyxyxy.com ',  
    cc          =>    'EMPFÄNGER@xyxyxy.com ',
    bcc         =>    '',
    subject     =>    'BLOCKER DETECTED (snap '||snapid||')',
    message     =>    msg,
    mime_type   =>    'text/plain; charset=us-ascii',
    priority    =>    NULL);
      begin
--      null;
      execute immediate stm;                                    
      exception when others then null;
      end;
      dbms_output.put_Line(stm);
    end loop;
  end if;
end loop;
end;
/

Falls man vorher testen möchte ob die Blocking Sessions richtig gekillt werden, muss man den Eintrag „execute immediate stm;“ auskommentieren.

Dadurch werden die Blocker nicht gekillt, sondern nur E-Mails verschickt mit der Info welche Session gekillt werden sollten.

begin
    null;
--      execute immediate stm;                                    
      exception when others then null;
      end;
     dbms_output.put_Line(stm);

Wie schon oben bei den einzelnen Tabellen beschrieben, kann es bei einigen Datenbank-Releases beim Insert in den folgenden Tabellen zum Problem kommen, dass einige Spalten fehlen, die aber auf den entsprechenden Datenbank-Releases in den jeweiligen gv$ Views vorhanden sind:

sqllog, sessionlog, locklog, sqltextlog

Daher muss hier in solchen Fällen die Struktur von den jeweiligen gv$ Views übernommen- und in den Tabellen die fehlenden Spalten ergänzt werden.

Als BLOCKMON:

drop table locklog;
create table locklog as (select s.*,1 snap,sysTIMESTAMP ts from gv$lock s where 1=0);

drop table sqllog;
create table sqllog as (select s.*,1 snap,sysTIMESTAMP ts from gv$sql s where 1=0);

drop table sessionlog;
create table sessionlog as (select s.*,sysTIMESTAMP ts,1 snap,cast('x' as  VARCHAR2(100)) info  from gv$session s where 1=0);

drop table sqltextlog;
create table sqltextlog as (select s.*,1 snap from gv$sqltext s where 1=0);

7) ACL EINRICHTEN

BEGIN
  DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('netacl.xml',
      'Allow usage to the UTL network packages', 'BLOCKMON', TRUE,
'connect');

  DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE('netacl.xml' ,'BLOCKMON', TRUE,
'resolve');

  DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('netacl.xml','*');
END;
/

8) Falls kein UTL_MAIL installiert -> UTL_MAIL installieren

select * from dba_objects where object_name='UTL_MAIL';        => kein UTL_MAIL installiert

installieren des UTL_MAILS:
@utlmail.sql
@prvtmail.plb


 Rechte fehlen (BLOCKMON):
 grant execute on utl_mail to BLOCKMON;

9) SMTP EINRICHTEN

SQL> alter system set smtp_out_server='mail.xyxyxy.com';
System altered.

SQL> show parameter smtp

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
smtp_out_server                      string      mail.xyxyxy.com

10)  TESTEN

Zum Testen kann eine Blocking-Session erstellt werden und getestet werden, ob der Kill-Blocker richtig eingerichtet wurde.

1- Blockingsessions erzeugen:

BLOCKMON User:
insert into TEST values(1);
commit;
update TEST set n=2;

Nun nochmal mit einem anderen User.

update BLOCKMON.TEST set n=3;

=> Blockingsessions erzeugt!!!
3- Prozedur ausführen als BLOCKMON USER (am besten ohne kill):

=> nach 30 Sekunden:
begin
watchdog;
end;
/

Falls der Test erfolgreich verläuft, kann das Killen wieder aktiviert- und der Job dafür eingerichtet werden.

11) JOB FÜR BLOCKMON USER EINRICHTEN

Nun muss noch folgender Job zum Ausführen des WATCHDOGs eingerichtet werden:

begin
dbms_scheduler.create_job(
job_name=>'BLOCKMON.WATCHDOG_JOB',
job_type=>'PLSQL_BLOCK',
job_action=>'begin watchdog;end;',
repeat_interval=>'freq=minutely',
enabled=>true);
end;
/

12) Abschließend

Durch das Einrichten des WATCHDOG_JOB wird die Oracle Datenbank laufend aktiv auf blockierende Sessions überprüft und ein aufgespührter Blocker automatisch beendet.

In der WATCHDOG Procedure (Punkt 6)  werden alle Einstellungen vorgenommen, um die Kill-Voraussetzungen für Blocking Sessions anzupassen.

Intel Cascade Lake und Oracle Database SE2 ein künftiges Risiko?

Wie schon bei vielen AMD Nutzern bekannt und beliebt setzt nun auch Intel auf die technischen Vorteile, welche ein Multichip Layout bietet.

Mit den seit Q2/2019 verfügbaren und nun langsam in den Markt auftauchenden Intel-Cascade-Lake-Mikroarchitektur Familie von 64-Bit-Mikroprozessoren für Server, stellt sich in Zukunft das Problem des lizenzkonformen Betriebs von Standard Edition 2 Datenbanken.

Diese Mehrkernprozessoren mit 4 bis 28 (SP) Kernen stellen die Nachfolger der Intel-Skylake-Mikroarchitektur-basierten Intel-Xeon-Prozessoren dar.

Sie werden jedoch im Gegensatz zu Ihren Vorgängern (obwohl in einem Gehäuse vergossen) Aufgrund ihres Layouts mit mehreren Prozessor Chips auf einer Platine nicht als Multichip Prozessoren gewertet.

Das neue Prozessor Layout ist derzeit bei der „Advanced Performance“ Serie verfügbar Xeon® Platinum 9282, 9242, 9222 und 9221.

Wir gehen davon aus, dass Intel diese Technogie noch weiter verbreiten wird.

Lizenzregeln

Es gibt zu Multichip Prozessoren eine seit 2007 bestehende Definition in den Oracle Lizenzverträgen, die in diesen Fällen nun nach vielen Jahren wieder zu Tragen kommt  ( nachzulesen unter der allgemeinen Prozessordefinition):

 

Bei der Lizenzierung von Oracle Programmen mit Standard Edition 2, Standard Edition One oder Standard Edition im Produktnamen (hiervon ausgenommen sind WebCenter Enterprise Capture Standard Edition, Java SE Abonnement, Java SE Support, Java SE Advanced and Java SE Suite) wird ein Prozessor mit einem belegten Socket gleichgesetzt; bei Modulen mit mehreren Chips hingegen wird jeder Chip mit einem belegten Socket gleichgesetzt.“

 

Somit haben wir die Situation, dass bei einer Nutzung von Intel-Cascade-Lake Prozessoren aus der Advanced Perfomance Linie für EINEN belegten Sockel ZWEI Prozessorlizenzen schlagend werden.

Weiters wären bei Maschinen, welche mit zwei solcher Prozessoren bestückt sind, das erlaubte Lizenzmaxima nicht mehr gegeben und eine Lizenz der Oracle Database Enterprise Edition notwendig!

Tipp: Es ist vor jedem Hardware-Upgrade zu prüfen, ob der Prozessor zum gewählten Lizenzmodell passt.

Auch bei einem Upgrade der Infrastruktur mit den besten Absichten kann der Lizenz- und Kosteneinsatz sich um das 20-fache erhöhen, sofern man wie oben beschrieben durch das Multi-Chip Layout gezwungen ist, von Standard Edition Database Lizenzierung auf Enterprise Edition Database Lizenzierung zu migrieren.

Die Liste der betroffenen Prozessoren finden Sie hier:

https://de.wikipedia.org/wiki/Intel_Xeon_(Cascade_Lake)

oder hier:

https://www.intel.de/content/www/de/de/design/products-and-solutions/processors-and-chipsets/cascade-lake/2nd-gen-intel-xeon-scalable-processors.html

Autor: Berhard Halbetel

Webservices direkt aus der DB (XMLDB)

Übersicht

Web Services werden heutzutage immer öfter benutzt um Daten unabhängig vom Standort, zwischen zwei Applikationen auszutauschen und Funktionen aufzurufen.

Oracle stellt mit den Native Oracle XML DB Web Services eine Möglichkeit zur Verfügung, die es erlauben SQL und XQuery Abfragen an einen Host zu senden.

Außerdem kann auf PL/SQL Stored Procedures und Functions zugegriffen werden.

Dabei unterstützt Oracle XML DB das Netzwerkprotokoll SOAP 1.1. Durch die HTTP POST Methode werden die SOAP Requests an die Oracle XML DB Web Services übermittelt.

Der Standort der Web Services und WSDL Dokumente können in der Oracle XML DB Datei xdbconfig.xml konfiguriert werden.

Konfiguration

Um die Web Services zu aktivieren, ist es zuallererst notwendig dem Datenbankbenutzer als SYS User die XDB_WEBSERVICES Rolle zuzuweisen.

Durch die Zuweisung der Rolle können die Web Services benutzt werden. Standardmäßig ist die Benutzung via HTTPS freigeschalten.

Dazu können noch weitere Rollen vergeben werden:

XDB_WEBSERVICES_OVER_HTTP – Benutzung via http

XDB_WEBSERVICES_WITH_PUBLIC – Zugriff auf PUBLIC Datenbank-Objekte

Hat ein User die Zugangsberechtigung auf eine Datenbank mittels Web Services so kann er nur auf die ihm zugewiesenen Datenbank-Objekte zugreifen.

Mit XDB_WEBSERVICES_WITH_PUBLIC kann er nun auch auf PUBLIC Objekte zugreifen.

Zugriff

Das Web Service für Datenbank-Abfragen befindet sich auf http://host:port/orawsv.

Bei host:port handelt es sich um den Datenbank-Host und HTTP(S)-Port. Der Pfad enthält eine WSDL-File, die eingehende und ausgehende Dokumente in XML spezifiziert.

Um auf Stored Procedures und Functions zugreifen zu können, muss http://host:port/orawsv/dbschema/package/fn_or_proc angewählt werden. Host:port enthält wieder den Datenbank-Host und  HTTP(S)-Port. Fn_or_proc gibt dabei die Procedure bzw. Function an.

Mit dbschema wird das Datenbank-Schema angegeben.

Sollte eine Procedure oder Function außerhalb eines Packages sein, so kann package ausgelassen werden.

Oracle 19c SE2 ohne RAC Funktionalität

Das (faule) Oracle19c SE2 Osterei – Standard Edition 2 ohne RAC

Die neue Oracle19c Datenbank ist gleichzeitig die Long Term Support Release bzw. das Terminal Patch Set für die Oracle Datenbank Version 12.2.

Anders als bei der Annual Release Oracle18c (2 Jahre ab Release von Oracle19c) wird es für diese Version Support bis zum 31. März 2026 geben.

Oracle 19c SE2 ohne RAC

Ein Blick in den aktuellen Oracle Lizenz Guide der Long Term Version 19c bringt Ernüchterung – der Einsatz von Oracle Real Application Clusters (RAC) ist ab Oracle19c in der Standard Edition 2 (SE2) nicht mehr erlaubt.

Oracle SE2 RAC Kunden, die ein Software Upgrade auf Oracle19c durchführen, dürfen dann die RAC Funktionalität nicht mehr einsetzen.

SE2 RAC Kunden, die bereits auf der wesentlich kürzeren Annual Release 18c sind, stehen damit auf einem bereits sehr kurzen Abstellgleis für Standard Edition 2 RAC.

Unklare Strategie

Welche Oracle Strategie hinter dieser Entscheidung steckt ist unklar.

Eventuell will man die Oracle Kunden mit sanftem Druck in die Oracle Autonomous Database Cloud bewegen indem man die On-Premise Lösungen für die Kunden nicht unmöglich, aber zunehmend unbequem macht.

Ob solch eine Strategie aufgehen würde ist fraglich, weil Oracle damit den Kunden wieder ein klares Zeichen der Unberechenbarkeit gäbe.

Die Kunden verlieren zunehmend das Vertrauen in die Kontinuität der Lizenzgewährung des Herstellers und der eine oder andere wird sich wohl oder übel dadurch nach Alternativen zu Oracle umsehen.

Offene Fragen aus lizenzrechtlicher Sicht

Aus lizenzrechtlicher Sicht ist diese Entwicklung ebenfalls fragwürdig.

Aus unserer Sicht stellen sich folgende Fragen bzw. Überlegungen:
Oracle SE2 Bestandskunden haben mit Oracle in der Vergangenheit vertraglich (Oracle TOMA und LDR – Lizenz Definitionen und Regeln) vereinbart, dass die Verwendung von Oracle RAC in der SE2 Lizenz unter definierten Regeln erlaubt ist!

Die Version 19c ist aber kein neues Produkt mit neuem Oracle LDR Vertrag, somit müsste der damals akzeptierte LDR gelten und die Verwendung von SE2 RAC für alle Bestandskunden weiterhin möglich sein.
Auch dann, wenn der aktuelle 19c Lizenz-Guide es für Neukunden nicht mehr vorsieht.

Fazit

Die obigen Schlussfolgerungen und Überlegungen basieren auf dem aktuellen Stand der uns zugänglichen Informationen.
Ausgelöst durch ein simples „N“ wo im Lizenz-Guide der Datenbank früher ein „Y“ stand.

Derzeit ist noch vieles unklar und es gilt abzuwarten, wie Oracle diese doch sehr eingreifende Änderung letztendlich präsentieren wird.

Migrieren ohne Downtime - ein Oracle 12.2 Feature

Migration OHNE Downtime – ein cooles Oracle 12.2 New Feature

Mit der Release 2 der Oracle Datenbank 12c bekommt der DBA eine Vielfalt neuer Funktionalitäten, die dem Datenbankadministrator die Arbeit in Zukunft um einiges erleichtern werden. Eines dieser neuen Features ist das Hot Cloning und Relocate von Pluggable Databases, das in diesem Artikel kurz näher vorgestellt wird.

Die Oracle Datenbank 12c Release 2 bringt mit der Multitenant-Architektur viele tolle Features, die man vorher nicht benutzen konnte. Zuallererst sollten wir aber die Aussage des Artikeltitels ein wenig einschränken und erläutern, welcher Themenkreis in diesem Artikel beleuchtet wird.
Eine Migration ohne Downtime ist mehr ein Wunsch als Wirklichkeit, aber mit der Version 12.2 kommen wir dem Ziel näher. Im gegenständlichen Artikel werden wir über die Möglichkeit Pluggable Databases online zu kopieren/migrieren beschreiben.

Ein Blick in die Vergangenheit

In der Version 11.2 hatte der Datenbankadministrator folgende Möglichkeiten, um eine Datenbank von einem System auf ein anderes System zu migrieren:

  • Duplicate
  • Datapump
  • Restore/Recover via RMAN
  • GoldenGate

Welchen Weg man letztendlich wählen wird, hängt ganz von der Situation und den Voraussetzungen ab. Es geht hier nicht um Cross-Platform-Migrationen oder um Migrationen zwischen Systemen mit unterschiedlicher Endianness. Jede Option verlangt gewisse Vorbereitungen und birgt auch mögliche, verborgene Gefahren mit sich, die dann erst im Zuge der Migration sichtbar werden.

Variante „Duplicate“

Bei einem Duplicate hat der Benutzer die Möglichkeit entweder direkt über SQL*Net, oder aus einem vorhandenen Backup, eine Kopie der Datenbank zu erstellen. Die Duplicate Methode ist eigentlich die einfachste, weil man hier entweder nur Firewall Freischaltungen zwischen den Servern benötigt oder man alternativ auf ein Backup, meistens von einem NFS Share oder einer Bandsicherung, zugreift. Wenn zwischen den Servern ein leistungsstarkes Netzwerk zur Verfügung steht, dann führt man am besten den Befehl DUPLICATE TARGET DATABASE TO … FROM ACTIVE DATABASE aus oder benutzt Backups die entweder in einer BACKUP LOCATION gespeichert oder aus Bandsicherungen gezogen werden.  Oracle automatisiert dabei einige Tätigkeiten die man bei Restores sonst manuell machen muss. Grundsätzlich ist es ein automatischer Restore/Recover der Quelldatenbank mit Veränderungen der Datafile Pfade und der DBID.

Variate „Datapump“

Die Variante Datapump ermöglicht dem Datenbankadministrator logische Datenbankbackups zu erstellen, auf ein neues Ziel zu übertragen und dort wieder zu importieren. Datapump bietet auch Features wie Transportable Tablespace oder Full Transportable Export. Dabei werden nur Metadaten exportiert und diese dann mit allen Datafiles kopiert und am Ziel importiert.

Variante „klassische Migration“

Bei der klassischen Migration einer Datenbank mittels RMAN Restore/Recover wird eine Datenbank auf Basis eines Backups neu aufgebaut.

Variante „GoldenGate“

Als letzte Option bleibt GoldenGate. Bei GoldenGate handelt es sich um eine kostenpflichtige Replikationssoftware, die es erlaubt nahezu Zero Downtime Migrationen durchzuführen. GoldenGate unterstützt zudem auch noch andere Datenbankanbieter wie MySQL, MS SQL und Hadoop.

Multitenant Architektur

Mit der Version 12.1 hat Oracle eine neue Datenbankarchitektur eingeführt – die Multitenant Architektur (CDB Architektur). Die Multitenant Architektur wird in Zukunft die derzeitige Non-CDB Architektur ersetzen. In der 12.1 Dokumentation findet man bereits den entsprechenden Hinweis auf die „Deprecation of Non-CDB Architecture“ für kommende Oracle Releases nach 12.2. Oracle empfiehlt hier auf die CDB Architektur zu schwenken. Multitenant ist prinzipiell eine kostenpflichtige Option zur Enterprise Edition, jedoch als Single tenant in allen Oracle Editionen enthalten.

Container Datenbank

Während es vor 12.1 nur eine 1:1-Beziehung zwischen Instanz und Datenbank gab (beim RAC ist es eine n:1-Beziehung), verändert sich das jetzt mit der Multitenant Architektur. In der Multitenant Architektur werden alle gemeinsamen Systemobjekte in eine neue, zentrale, Datenbank – die Container Datenbank (CDB) – gepackt, die alle notwendigen Funktionalitäten bereits vorinstalliert hat. Die eigentlichen Benutzerdaten befinden sich in sogenannten Pluggable Databases (PDB), die in die Containerdatenbank eingehängt werden.

In der Version 12.1 konnte man Datenbanken, die bereits als Pluggable Database definiert waren wesentlich einfacher kopieren, als noch in älteren Versionen ohne Multitenant Architektur. Man musste die Quelldatenbank lediglich in den Read Only Modus setzen und anschließend ein CREATE PLUGGABLE DATABASE Statement ausführen. Im einfachsten Fall bekommt man mit dem Kommando CREATE PLUGGABLE DATABASE ORCL2 FROM ORCL1 bereits eine lokale Kopie der Datenbank.

Mit der Multitenant Architektur bringt Oracle dem Benutzer eine Vielfalt von Features die das Provisionieren von Datenbanken leichter machen. Man bekommt eine Konsolidierungsplattform für Datenbanken in der man mit dem Ressource Manager Systemressourcen optimal zuteilen kann um wichtigeren Datenbanken mehr Performance zuzusichern. Weiters eine Automationsplattform in der man Datenbank Templates vordefinieren kann um im Anlassfall schnell PDBs zu erstellen oder klonen zu können. Das Kopieren von PDBs geht in 12.1 nicht ganz ohne Downtime ab. Im Internet findet man Artikel die ohne den Read Only Modus eine Kopie der PDBs ermöglichen, in 12.1 ist es jedoch nicht möglich PDBs online zu kopieren. Die Quelldatenbank geht hier in den Quiesce Modus, was mit einer Downtime vergleichbar ist.

Die Gegenwart – Hot Cloning und Relocate

Mit der Version 12.2 wird der Traum des DBAs jedoch endlich wahr: Die von vielen erwartete Lösung für das online kopieren von PDBs. Dieses Feature kommt in Begleitung mit einem anderen neuen Feature, den Local Undo Tablespaces. Um Datenbanken wirklich online kopieren zu können, braucht man die Container Datenbank im Local Undo Mode (und natürlich im Archivelog Mode).
Das Aktivieren des Local Undo Modes in der CDB erstellt automatisch in jeder PDB einen eigenen Undo Tablespace, welcher wiederum Voraussetzung für Flashback, PDBPITR und Hot Cloning in der PDB ist.

Um den Leser nicht weiter auf die Folter zu spannen, schauen wir uns das RELOCATE-Feature in Aktion an. Hier wird die Datenbank automatisch auf eine andere Instanz transferiert und alle DMLs und DDLs bis zum Öffnen der Pluggable Datenbank werden automatisch im Hintergrund verarbeitet, um die Datenbank konsistent zu halten.

In unserem Szenario haben wir 2 virtuelle Maschinen, ora01 und ora02 mit  Version 12.2.0.1 Enterprise Edition installiert, die ora01 verwaltet die cdb1 und ora02 die cdb2.

Beide Datenbanken sind im gleichen Netz, als Storage benutzen wir ASM, das erleichtert auch die Namenskonvention für die Datafiles. Diese Funktionalität (mit und ohne RELOCATE) funktioniert auch in der 12.2 SE2.

Um keine Lizenzverletzung zu begehen, denken Sie daran, dass in einer CDB nur eine Benutzer PDB existieren darf. Mehrere Benutzer PDBs verlangen die Multitenant Option und damit Enterprise Edition.

 

sys@cdb1 SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 ORCL                           MOUNTED

sys@cdb1 SQL> alter pluggable database orcl open ;
Pluggable database altered.

sys@cdb2 SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO

Um die Datenbank auf die neue Maschine zu transferieren, sind ein paar Vorbereitungen nötig. Zuerst ist ein Common User anzulegen, der die notwendigen Privilegien bekommt. Ein in der Dokumentation offensichtlich entdeckter Fehler wird am Ende des Beispiels beschrieben.

sys@cdb1 SQL> create user c##dba identified by oracle container=all ;
User created.

sys@cdb1 SQL> grant create session, create pluggable database to c##dba container=all ;
Grant succeeded.

sys@cdb1 SQL> grant sysoper to c##dba container=all ;
Grant succeeded.

Um die PDB zu erreichen, brauchen wir einen Connect-Descriptor, der die Datenbank identifiziert. In unserem Beispiel werden wir den Alias CDB1 in der tnsnames.ora der CDB2 anlegen.

CDB1 =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = ora01)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = cdb1)
    )
  )

Als vorletzte Voraussetzung brauchen wir einen Public Database Link von der CDB2 in die CDB1.

 

sys@cdb2 SQL> create public database link cdb1 
connect to c##dba identified by oracle using 'cdb1' ;
Database link created.

Nachdem wir alle Voraussetzungen erfüllt haben, können wir die Datenbank auf die CDB2 migrieren. Diese Tätigkeit erledigt man mit einem Kommando auf der CDB2:

sys@cdb2 SQL> create pluggable database orcl from orcl@cdb1 relocate ;
Pluggable database created.

Nach dem Erstellen der PDB bleibt die neue PDB in der CDB2 im Zustand MOUNTED. Ohne den Zusatz RELOCATE würden wir einen Hot Clone der PDB „orcl“ erstellen. Um die Near Zero Downtime Migration zu zeigen, erstellen wir in der PDB „orcl“ auf CDB1, die immer noch im Read Write Modus ist, einen neuen Benutzer und eine Tabelle.

sys@cdb1 SQL> alter session set container=orcl ;
Session altered.

sys@cdb1 SQL> create tablespace data ;
Tablespace created.

sys@cdb1 SQL> create user psorger identified by oracle default tablespace data quota unlimited on data;
User created.

sys@cdb1 SQL> grant connect, resource to psorger ;
Grant succeeded.

sys@cdb1 SQL> create table PSORGER.EMP as select level id from dual connect by level<=10 ;
Table created.

Nachdem wir die Tabelle erstellt haben, können wir die neue PDB in der CDB2 öffnen.
Mit dem folgenden Kommando wird die PDB auf CDB1 gelöscht und die PDB auf CDB2 im Read Write Modus geöffnet.

sys@cdb2 SQL> alter pluggable database orcl open ;
 Pluggable database altered.

sys@cdb2 SQL> alter session set container=orcl ;
 Session altered.

sys@cdb2 SQL> select count(*) from psorger.emp ;

COUNT(*)
 ----------
 10

Nach dem Öffnen der neuen PDB sehen wir, dass alle DML/DDL Statements erfolgreich übertragen wurden.

Um den Fehler in der Dokumentation zu beschreiben werden wir dem C##DBA die Rolle SYSOPER entziehen und SYSDBA vergeben. Mit dieser Rolle vergibt man eigentlich Superprivilegien und logischerweise erwarten wir, dass das funktioniert.

sys@cdb1 SQL> revoke sysoper from C##DBA container=all ;
Revoke succeeded.

sys@cdb1 SQL> grant sysdba to C##DBA container=all ;
Grant succeeded.

sys@cdb2 SQL> select sysdate from dual@cdb1 ;

SYSDATE
---------
09-MAY-17

sys@cdb2 SQL> create pluggable database orcl from orcl@cdb1 ;
Pluggable database created.

sys@cdb2 SQL> create pluggable database orcl1 from orcl@cdb1 relocate ;
create pluggable database orcl1 from orcl@cdb1 relocate
*
ERROR at line 1:
ORA-17628: Oracle error 1031 returned by remote Oracle server
ORA-01031: insufficient privileges

Wie wir hier sehen ist ein Online Clone der Datenbank möglich, aber beim Relocate bekommt der C##DBA mit SYSDBA Privilegien dennoch einen insufficient Privileges Fehler.
Es scheint, dass man dieses Verhalten als einen Bug entweder in der Dokumentation oder in der Software bezeichnen kann.
In der Zukunft werden wir es bestimmt erfahren. 🙂

Um diesen Artikel abzurunden, möchte ich noch die neuen Features der Oracle Public Cloud erwähnen.

Ein neues Feature, der direkte SQL*Net Zugang in die Cloud, erleichtert ab 12.2 die Migration von On-Premise Datenbanken in die Cloud und zurück. Mit diesen zwei neuen Features bekommt der Benutzer die Möglichkeit sehr einfach in die Cloud zu wechseln, dort etwa Performance-Tests durchzuführen und dann die Datenbank wieder zurück ins eigene Rechenzentrum zu verschieben.

Gerade das ist ein Feature, das bei anderen Cloud-Anbietern aktuell kaum zu finden ist!

Oracle Scheduler Jobs Kurzfassung

Oracle Scheduler Jobs – eine Kurzfassung

Wer regelmäßig automatische Vorgänge in seiner Datenbank laufen lässt, wie zum Beispiel das Aufrufen von Services, Datenübernahmen oder regelmäßige Berechnungen, der wird sehr bald auf Oracle Scheduler Jobs treffen. Diese können auf verschiedene Arten regelmäßig Prozeduren und ähnliches in regelmäßigen Abständen ausführen.

Die grundlegende Definition benötigt zumindest folgende Parameter:

  • job_name: der Name des Scheduler Jobs
  • job_type: der Typ des Scheduler Jobs, ist es ein PL/SQL Block oder ein direkter Prozeduraufruf, …
  • job_action: der tatsächlich auszuführende Ausdruck (abhängig von job_type)

und würde dann so aussehen:

Weiterlesen

Düsseldorf Oracle Lizenzierung Seminar Kostenbremse

Erstmals in Düsseldorf – das Oracle Lizenzierungs Seminar

Aufgrund mehrer Anfragen haben wir uns entschieden, am 21. Mai 2016 zum ersten Mal in Düsseldorf unser bekanntes Seminar zum Thema Oracle Software Lizenzierung abzuhalten.

Bisher war es den deutschen Kollegen/innen nur möglich, das Seminar in Österreich zu besuchen.

Obwohl der Seminarort Salzburg immer gerne gebucht wurde, ist die Entscheidung für Düsseldorf natürlich für alle Lizenzmanager und Oracle Datenbank Administratoren aus NRW und den angrenzenden Bundesländern aufgrund der kurzen Anreise eine attraktive Option.

Wir sind überzeugt, dass es mit den zahlreichen Tipps und Praxis Beispielen wahrscheinlich kein anderes Seminar  in dieser Form gibt.

Wie das Feedback der Seminar Teilnehmer zeigt, ist das vermittelte Know-how sofort anwendbar und der Nutzen in kürzester Zeit umzusetzen.

Alle weiteren Details zu den Inhalten, zum Termin und Veranstaltungsort sowie die Anmeldung zum Seminar finden Sie auf der Webseite zum Oracle Software Lizenzierung Seminar – Düsseldorf.

 

Oracle streicht 450 Support Stellen

Oracle streicht in Europa 450 Stellen im Support

Wie zahlreiche Medien berichten, baut Oracle in Europa 450 Stellen im Support ab, alleine 150 davon in Deutschland. Ziel der Maßnahme ist die Verlegung des Supports nach Rumänien.

Alle europäischen Oracle Support Standorte sollen bis Ende März 2016 geschlossen werden – das betrifft sämtliche Support-Zentren mit den Ausnahmen von England, Holland und Rumänien.

Zukünftig werden die Support Anfragen aus Deutschland, Österreich und der Schweiz von rumänischen Oracle Support Mitarbeiter/innen beantwortet.

Wie sehr diese Entwicklung Auswirkungen auf die Qualität der deutschsprachigen Unterstützung und auf die dahinter stehenen Prozesse haben wird, kann nur die Praxis zeigen.

DBConcepts – wir sprechen Ihre Sprache

Bei wichtigen und dringenden Support Aufgaben ist es oft von Vorteil, wenn alle Gesprächspartner die gleiche Sprache sprechen und sich auch in der selben Zeitzone befinden.

Alle unsere Remote DBA Mitarbeiter/innen sprechen selbstverständlich Deutsch, um Sie ohne Verständigungsprobleme optimal bei Ihren Anforderungen unterstützen zu können.

Wir befinden uns in Ihrer Zeitzone und sind nur einen Anruf entfernt.

Link: Weiter Infos zu Datenbank Fernwartung durch Remote DBA >>

 

Medien Quellen:

http://www.it-zoom.de/dv-dialog/e/oracle-support-rumaenien-12621/

http://www.heise.de/ix/meldung/Deutscher-Oracle-Kundendienst-schliesst-Ende-Maerz-3117680.html

DOAG Artikel

 

Oracle Datenbank Upgrade 12c

Upgrade auf Oracle 12c

Vieles scheint sich zu verändern: Ganze Datacenter wandern in die Cloud, neue Lösungsangebote wie Database as a Service betreten den Markt, der Trend zur Virtualisierung scheint ungebrochen, Solid State Drives werden herkömmliche Festplatten wohl bald gänzlich ersetzen, Big Data und Datamining sind in aller Munde.

Doch manches verändert sich nicht so schnell: Genauso wichtig wie unternehmerische Innovationen und technologische Paradigmenwechsel ist die Fortführung von bewährten Technologien. Entgegen mancher kurzzeitiger Moden bildet das relationale Datenmodell immer noch das stabile Fundament für viele Anwendungen.

Die IT-Landschaft verändert sich in rasendem Tempo, und Oracle bildet hier keine Ausnahme.
Im Gegenteil: Mit dem Release der Datenbankversion 12c ebnet Oracle diesen Ent-wicklungen den Weg und eröffnet neue und vielversprechende Perspektiven für den Betrieb von Datenbanken, ohne dabei die Stärken einer relationalen Datenbank aufzugeben.

Mit 12c ist es Oracle gelungen, beide Anforderungen zu erfüllen:
Mit der Entwicklung von Features wie Pluggable Database und InMemory wird ein zukunftsweisender Weg aufgezeigt, mit der kontinuierlichen Weiterentwicklung der Stärken der Release 11gR2 eine Erfolgsgeschichte weitergeschrieben.

Wie sich auch entscheiden, wir möchten Sie mit unserem Know-How auf ihrem Weg unterstützen. Doch bevor die Reise beginnt, werfen wir noch einen Blick auf die Gegenwart.

Roadmap 11gR2

Wie bereits über verschiedene Kanäle angekündigt, neigt sich die Unterstützung von Release 11gR2 dem Ende zu. Die Version 11gR2 wurde im Jahr 2009 erstmals veröffentlicht, seitdem erschienen mehrere Subreleases. Momentan ist die Version 11.2.0.4 aktuell, wobei diese Version auch die letzte sein wird (Oracle spricht hier vom terminal patchset).

Das Release 11gR2 wird zwar in Form von PSUs (Patch Set Updates) noch weiter gepflegt, aktuelle Entwicklung findet aber keine mehr statt.

Release  Patching End Date

11.2.0.1  13.09.2011
11.2.0.2  31.10.2013
11.2.0.3  27.08.2015
11.2.0.4  31.01.2018

Wie aus der Tabelle ersichtlich wird, endet das Patching für die Version 11.2.0.3 noch dieses Jahr, bei 11.2.0.4 bleibt noch ein wenig mehr Zeit. Dies betrifft jedoch nur die Bereitstellung von Patches und PSUs, nicht den Support. Hier sieht es anders aus.

 

Premier Support Ends

Achtung: Der Premier Support für 11gR2 ist mit Ende Jänner 2015 ausgelaufen!

Oracle bietet die Möglichkeit, für ein zusätzliches Jahr den sog. „Free Extended Support“ in Anspruch zu nehmen.

Dies ist für alle Kunden mit einem aufrechten Support-Vertrag möglich.

Um in den Genuss von „Free Extended Support“ zu kommen, ist es erforderlich, dass sie bei Oracle einen Vertrag anfordern. Sie bekommen dann eine Rechnung über den Betrag von 0 Euro ausgestellt, der die Aktivierung des „Free Extended Supports“ ausweist. Nach Ablauf des kostenlosen „Free Extended Support“erfolgt keine automatische Verlängerung des Supportvertrags. Ab dem zweiten Jahr (also nach 31.01.2016) würden die vollen Sup-portgebühren anfallen. Sofern sie den „Free Extended Support“ beantragen, ist nach Ablauf des Vertrags nichts mehr zu machen. Sie brauchen den Vertrag weder kündigen, noch wird dieser zu den regulären Supportpreisen verlängert.

Wie aus der Tabelle (siehe unten) ersichtlich wird, ist der „Free Extended Support“ nur für die Version 11.2.0.4 von Relevanz.

Für die Version 11.2.0.3 endet der Support bereits in wenigen Monaten.

Oracle Support Roadmap

 

Release  Free Extended Support Ends

11.2.0.1 No Extended Support available
11.2.0.2 No Extended Support available
11.2.0.3 27.08.2015
11.2.0.4 31.01.2016

Der „Free Extended Support“ für 11.2.0.4 endet mit Ende Jänner 2016. Ab diesem Zeitpunkt gibt es nur mehr den kostspieligen „Extended Support“, der maximal bis Ende Jänner 2018 verlängert werden kann.

 

Release 12c

Das Datenbank-Release 12c wurde am 22.06.2013 zum ersten Mal veröffentlicht. Mittlerweile (Stand: Februar 2015) steht die Release 12.1.0.2 zur Verfügung. Allerdings betrifft dies nur die Enterprise Edition der Datenbank, für die Standard Edition ist das letzte verfügbare Patchlevel 12.1.0.1.6.

 

Edition      Release and PSU-Level

Enterprise   12.1.0.2.2 (includes PSU Jan2015)

Standard      12.1.0.1.6 (includes PSU Jan2015)

 

Ein „Direct Upgrade“ auf 12c ist nur von folgenden Versionen aus möglich:

•             ≥ 10.2.0.5
•             ≥ 11.1.0.7
•             ≥ 11.2.0.2

Sollten sie eine ältere Version im Einsatz haben, ist ein Zwischenschritt notwendig. Doch auch hier gibt es wie immer mehrere Möglichkeiten.

Wir beraten sie gerne hinsichtlich der möglichen Upgrade-Szenarien und stimmen dieses gerne auf ihre Anforderungen hinsichtlich Downtime und Applikationstests ab.

 

Neben der in Verwendung befindlichen Version des RDBMS spielt das Client-Umfeld eine entscheidende Rolle für ein erfolgreiches Upgrade auf 12c.

  • Welche JDBC-Versionen sind im Einsatz?
  • Welche Client-Versionen verbinden sich zur Datenbank?
  • Wurde am Applikationsserver ein Connection Pool konfiguriert?
  • Und wie authentifizieren sich die Clients gegenüber der Datenbank?

Das sind nur einige der Fragen, die es im Vorfeld zu erheben gilt.

Wir unterstützen sie bei der Erfassung dieser Informationen und der möglicherweise notwendigen Konfigurationsänderungen.

 

Are you ready for Oracle 12c?

Um ihnen den Umstieg auf 12c so einfach wie möglich zu machen, bieten wir ihnen umfassende Prüfung ihrer Datenbanken und ihrer Clients im Vorfeld des Upgrades an.

 

Basierend auf unserer Erfahrung, die wir bei diversen Upgrades auf 12c sammeln konnten, haben wir einen Upgrade-Check erarbeitet, der in nicht-invasiver Weise die vorhandene Datenbank-Landschaft prüft und auf mögliche Stolpersteine beim Upgrade hinweist.

 

Am Ende des Prüfvorgangs erhalten Sie von uns einen detaillierten Bericht, wie sich ein Upgrade-Szenario darstellen würde, was hinsichtlich Datenbank und Client-Umfeld zu tun wäre und mit welchen Serviceeinschränk-ungen während des Upgrades zu rechnen wäre.

Dieser Check bildet die Grundlage für ein erfolgreiches Upgrade auf 12c.

Also: Sind sie dabei? Oder anders gefragt: Are you ready for 12c?

 

 

 

JavaScript Object Notation Support in Oracle 12c

JavaScript Object Notation Support in Oracle 12.1.0.2

Mit der Oracle 12c Release 12.1.0.2 hat die Oracle Datenbank JSON Unterstützung erhalten. JSON kann nun direkt gespeichert, abgefragt und auch indiziert werden. Im Folgenden soll dazu ein kurzer Überblick gegeben werden.

JSON steht für JavaScript Object Notation und beschreibt wie der Name schon ausdrückt eine Möglichkeit komplexe Objekte zu notieren und zu verarbeiten. Die Datenbank verwendet intern grundsätzlich immer UTF-8, entsprechend notwendige Konvertierungen bei der Ein- und Ausgabe werden automatisch durchgeführt.

Folgendes Beispiel eines Studenten soll dies verdeutlichen:

{    „Matrikelnummer“    : 123564869,
    „Name“    : „Otto Mayer“,
    „Studiengang“    : „Informationstechnik“,
    „aktuelles Semester“    : „WS2014/15“,
    „Fächer“    : [    „Business Englisch“,
            „Objektorientiertes Programmieren“,
            „Mathematik 3“]
}

Um nun ein JSON speichern zu können wird eine simple VARCHAR2 oder bei größeren Objekten eine CLOB Spalte verwendet. Neu dazukommen ist der Check-Constraint IS JSON um sicherzustellen, dass die Spalte auch wirklich immer valide JSON-Syntax enthält.

Eine Tabelle mit einer JSON Spalte sieht dann z.B. folgendermaßen aus:

CREATE TABLE students
    (id            RAW(16) NOT NULL,
    date_loaded   DATE,
    student_info  CLOB
    CONSTRAINT ensure_json CHECK (student_info IS JSON));

In diese Tabelle kann nun in die Spalte STUDENT_INFO ein Text im JSON-Format eingefügt ([…] wurde hier als Platzhalter verwendet) werden.

INSERT INTO students
VALUES ( sys_guid(),
        sysdate,
        ‘{      „Matrikelnummer“    : 123564869,
           „Name“            : „Otto Mayer“,
           [...] }’);

Die Daten können nun über eine ganz einfache Punkt-getrennte-Notation wie man sie von JavaScript kennt ausgelesen werden. Folgende SQL-Query ergibt z.B. das Ergebnis 123564869.

select st.student_info.Matrikelnummer
from students st

Es muss folgendes beachtet werden:

Die Schlüsselwerte sind case-sensitive – das gleiche muss in SQL berücksichtigt werden – das Statement oben würde kein Ergebnis liefern wenn statt „Matrikelnummer“ „matrikelnummer“ oder „MATRIKELNUMMER“ geschrieben wird. Sollten Leerzeichen oder Sonderzeichen wir Umlaute im Key sein – was grundsätzlich zu vermeiden ist – dann muss die entsprechende Angabe unter Anführungszeichen gesetzt werden also z.B.:

select st.student_info.”aktuelles Semester”
from students st

Sollte es sich um ein verschachteltes Objekt handeln so wird die Punkt-getrennte-Notation einfach auf allen Ebenen angewandt bis man bei dem gewünschten Wert angelangt ist.

Oracle bietet noch drei Funktionen die in SQL oder PL/SQL verwendet werden können die ich hier noch kurz beschreiben will: JSON_VALUE, JSON_QUERY, JSON_TABLE und JSON_EXISTS.

Allgemein nutzen alle JSON-Pfad-Notationen. Diese entspricht der Punkt-getrennten Notation die bereits besprochen wurde, und kann auch Elemente aus Arrays nutzen.

JSON_VALUE

Selektiert einen Wert wie zum Beispiel mit dem Ergebnis „Business English“ bei folgendem Query:

select json_value(st.student_info, '$.Faecher[0]')
from students st

JSON_EXISTS

Prüft ob ein bestimmer Schlüssel im JSON existiert. Das erste Query gibt ein Datum zurück bei allen Zeilen, denn das Array hat ein zweites Element (0 ist der Start-Index). Das zweite Query gibt nichts zurück da das Array nur 3 Elemente hat (und [3] das vierte Element abfragt).

select date_loaded
from students st
where json_exists(student_info, '$.Faecher[1]')


select date_loaded
from students st
where json_exists(student_info, '$.Faecher[3]')

JSON_QUERY

Im Gegensatz zu JSON_VALUE wird hier ein Teilstück des JSON selektiert und nicht nur ein Wert, folgendes Query gibt die Liste der Fächer zurück:

select json_query(student_info, '$[*].Faecher')
from students

JSON_TABLE

Diese Funktion dient dazu JSON-Daten in eine virtuelle Tabellenform zu überführen. Sie bietet damit die Möglichkeit im FROM-Teil der Query eingesetzt zu werden und dadurch mehrere Werte auf einmal ohne mehrmaliges Aufrufen von JSON_VALUE oder JSON_QUERY zu selektieren. Das bringt einen Geschwindigkeitsvorteil da die Daten so nur einmal geparst werden und nicht für jeden Funktionsaufruf immer wieder.

select jt.matrikelnummer, jt.fach1, jt.fach2, jt.fach3
from students st,
       json_table(st.student_info,
                 '$' COLUMNS(matrikelnummer NUMBER PATH '$.Matrikelnummer',
                         fach1 VARCHAR2(240) PATH '$.Faecher[0]',
                         fach2 VARCHAR2(240) PATH '$.Faecher[1]',
                         fach3 VARCHAR2(240) PATH '$.Faecher[2]')) jt

Die neuen JSON Funktionen bieten nützliche Werkzeuge, gerade im Zusammenhang mit APEX, dass durch seine Web-Browser Basis JavaScript massiv nutzt können sich dadurch hilfreiche Vereinfachungen implementieren lassen.

Weitere Infos zu JSON in der Oracle Datenbank finden sie hier:

http://docs.oracle.com/database/121/ADXDB/json.htm