Posts mit dem Label Oracle werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Oracle werden angezeigt. Alle Posts anzeigen

Montag, 29. Februar 2016

SQLPlus Ausgabe in Variable Speichern

In Linux ist es sehr einfach, eine Variable mit der Ausgabe von einem SQLPlus-Befehl zu füllen. Unter Windows ist das eine halbe Doktorarbeit.

Vielen Dank an Damir Vadas für seinen sehr hilfreichen Post in seinem Blog (Thank you Damir Vadas for your helpful post on this subject):
"How to redirect sqlplus result in Windows batch script"

echo set timi off head off^&echo. select  MIN(sequence#) from v$log where thread#=1; | sqlplus -s "/ as sysdba" | findstr . > result.tmp
FOR /F %i IN (result.tmp) DO @set MIN1=%i
@echo %MIN1%
del result.tmp


Quelle: http://damir-vadas.blogspot.de/2010/11/how-to-redirect-sqlplus-result-in.html

That's IT

Dienstag, 9. Februar 2016

Katastrophe: Windows 64Bit, Oracle DB 64Bit und Oracle Client 32Bit

Von Zeit zu Zeit ist man als Oracle-DBA dazu gezwungen, Datenbanken unter Windows zu betreiben. Als wenn das nicht genug Ärger bedeutet, soll auch noch neben der 64Bit Datenbank ein 32Bit Client installiert werden.

Es gibt eine ganze Sammlung (Oracle Note 1157463.1) von Problemen die unter Windows auftreten wenn man versucht, ein zweites oder drittes Oracle-Produkt zu installieren. Mit Oracle-Produkt meine ich nicht Java oder ähnliches, sondern alles was mit dem Oracle Universal Installer installiert wird.

Neben verschiedenen Java-Problemen, Chaos im Inventory oder andere Kleinigkeiten gibt es noch dieses Problem:

Der OUI wurde mit "Als Administrator ausführen" ausgeführt und startet ganz normal. Am Ende des Assistenten klickt man auf "Install". Der Installationsdialog erscheint für 1-3 Sekunden und verschwindet wieder. Wer in den Installationslogs nach weiteren Informationen sucht, wird nicht fündig denn diese sind leer. Das Verhalten wurde in der Oracle-Community bereits diskutiert, leider ohne Erfolg: https://community.oracle.com/thread/2192825?tstart=0
Dieses Problem scheint auch nicht immer aufzutreten, denn sonst gäbe es im Internet sicher schon mehrere Komplettlösungen dazu.

Das Problem liegt an den Registry-Einträgen im Zusammenhang mit dem Oracle Inventory Pfad.

Nach der Installation von Oracle DB 64Bit gibt es den Registry-Key "inst_loc" unter [HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE]. Dieser verweist auf das Oracle-Inventory unter "C:\Program Files\Oracle\Inventory".

Der 32Bit-Installer sucht zusätzlich nach dem Registry-Key "inst_loc" in [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Oracle]. Diesen gibt es noch nicht und da dies ein 32Bit-Installer ist, müsste dementsprechend der Pfad "C:\Program Files (x86)\Oracle\Inventory" heißen. Den Konflikt zwischen den beiden Keys/Pfaden kann der Installer dann scheinbar nicht lösen und stürzt ab.

Wenn dieser Pfad vor der Installation des Oracle Client 32Bit manuell angelegt wird, funktioniert die Installation. Es kommt also darauf an, dass die beiden Registry-Keys [HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\inst_loc] und [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Oracle\inst_loc] auf den selben Pfad zeigen.

That's IT

Montag, 16. November 2015

"SET NEWNAME" per SQL generieren

Wer eine Datenbank clont und nicht die db_create_file_dest für alle DB-Files verwenden kann, muss unter umständen viele Datenbankfile manuell per "SET NEWNAME" anpassen.

Im Internet kursieren komischer Weise einige SQLs, die diesen Zweck nicht richtig erledigen. Vielleicht liegt es auch an inkompatiblen Befehlen. Dafür kenne ich mich mit den Änderungen im SQL-Bereich nicht gut genug aus.

In Oracle 11g muss das SQL jedenfalls so aussehen:

select 'set newname for datafile '||file_id||' to ''/PATH/TO/FILES/'||substr(file_name,instr(file_name,'/',-1)+1)||''';' 
  from dba_data_files
;
Oder mit v$-View:
select 'set newname for datafile '||file#||' to ''/PATH/TO/FILES/'||substr(name,instr(name,'/',-1)+1)||''';' 
  from v$datafile
;

That's IT

Mittwoch, 2. September 2015

Oracle Datenbanken mit RMAN verschieben

Es soll vorkommen, dass Datenbanken von einer Platte auf die andere verschoben werden sollen. Die folgende Beschreibung trifft ebenfalls zu, wenn die Datenbank vom Filesystem ins ASM oder andersherum verschoben wird.

Mit RMAN kann dies sehr gut vorbereitet werden um eine handliche Downtime von 10-20 Minuten zu erreichen. Mit etwas Einsatz kann auch eine 1-Minuten-Downtime erreicht werden.

Das folgende Beispiel entstand bei einem Umzug von ASM auf einem alten Storage ins Filesystem eines neuen Storage.

Schritt 1
Zunächst wird eine Image-Copy angelegt:
RMAN> backup incremental level 0 as copy database to destination '/opt/oracle/oradata' tag 'NEWSTORE';


Schritt 2
Die folgenden Pfade müssen im SPFILE angepasst werden. Dies kann online geschehen.
- db_create_file_dest
- FRA
- Archivelog-Dest
- Redologs

Schritt 3
Schritt 3 wird nun je nach Notwendigkeit zwischen der Vorbereitung und der Downtime 1-n Mal wiederholt. Dieser Vorgang aktualisiert die Image-Copy.
RMAN> backup incremental level 1 for recover of copy with tag 'NEWSTORE' database;
RMAN> recover copy of database with tag 'NEWSTORE';

Schritt 4 (switch)
Datenbank herunter fahren, Controlfiles verschieben und im SPFILE anpassen. Anschließend die Datenbank switchen:

Variante A (Alle Archivelogs seit dem letzten "Schritt 3" sind verfügbar):
RMAN> switch database to copy;
RMAN> recover database;

Variante B (Es sind nicht mehr alle Archivelogs verfügbar):
Zuerst "Schritt 3" ausführen, anschließend:
RMAN> switch database to copy;
RMAN> recover database;

Schritt 5
Datenbank wieder starten.

That's IT.

Montag, 6. Juli 2015

APEX 505 Fehler, I/O-Fehler: "Network Adapter could not establish the connection"

Problembeschreibung und Umgebung

Heute stieß ich auf den folgenden sonderbaren Fehler, den ich gerne teilen möchte. Eine APEX-Installation in einem Oracle Real Application Cluster (RAC) läuft auf einem Knoten plötzlich auf einen Fehler. Die Browser-Seite zeigte einen 505-Fehler.
Weitere Details zur Umgebung:
  • Oracle Version: 10g (2-Knoten RAC)
  • Oracle REST (APEX-Listener) 2.0.2
  • Applikations-Server: Tomcat

Symptome

Im catalina.out des Tomcat-Servers stand die folgende Fehlermeldung:
oracle.dbtools.common.jdbc.ConnectionPoolException: The pool named: apex is not correctly configured, error: I/O-Fehler: The Network Adapter could not establish the connection
         at oracle.dbtools.common.jdbc.ConnectionPoolException.badConfiguration(ConnectionPoolException.java:65)
         at oracle.dbtools.common.config.db.DatabaseConfig.badConfiguration(DatabaseConfig.java:166)
         at oracle.dbtools.common.config.db.DatabaseConfig.createPool(DatabaseConfig.java:187)
         at oracle.dbtools.common.config.db.DatabaseConfig.getConnection(DatabaseConfig.java:71)
         at oracle.dbtools.common.jdbc.ora.OraPrincipal.connection(OraPrincipal.java:69)
         at oracle.dbtools.apex.ModApexContext.getConnection(ModApexContext.java:372)
         at oracle.dbtools.apex.Procedure.getProcedure(Procedure.java:167)
         at oracle.dbtools.apex.OWA.validateProcedure(OWA.java:390)
         at oracle.dbtools.apex.security.Security.isValidRequest(Security.java:225)
 [...]
Wie gesagt, auf einem RAC-Knoten lief die Konfiguration, es gab keine Änderungen, die Konfigurationen waren auf beiden Knoten identisch.

Lösung

Die Apex-Dateien aus dem WEB-INF wurden gelöscht. Beim Neustart des Tomcats werden diese aus der .war-Datei automatisch neu deployed. Dieser erste Neustart wurde als tomcat-User manuell ausgeführt. Dabei durften die Umgebungsvariablen $LANG und $NLS_LANG nicht gesetzt sein!
$ su - tomcat
$ unset LANG
$ unset NLS_LANG
$ $CATALINA_HOME/bin/startup.sh
Anschließend war die APEX-Anwendung wieder über beide Knoten erreichbar.
Was genau das Problem war und wie es dazu kommen konnte, ließ sich anschließend natürlich kaum noch feststellen.
That's IT

Donnerstag, 8. Januar 2015

Oracle Upgrade: utlu112i.sql vergessen?

Wer kennt das nicht: Bei einem Upgrade möchte man das catupgrd.sql script laufen lassen, doch dieses läuft sofort auf den Fehler, dass irgend etwas mit der Tabelle registry$database nicht stimmt.
Das bedeutet man hat vor dem Upgrade das utlu112i.sql nicht ausgeführt. Entweder hat man es schlicht vergessen oder die Datenbank kommt aus einem Backup und man hatte überhaupt nicht die Möglichkeit das Script auszuführen.
In diesen Fällen muss man nicht unbedingt das utlu*i.sql Script vorher laufen lassen, es gibt auch eine einfache Korrektur.
Zunächst überprüft man die Tabelle registry$database:

SELECT TO_NUMBER('MUST_BE_SAME_TIMEZONE_FILE_VERSION')
FROM registry$database
WHERE tz_version != (SELECT version from v$timezone_file);

Wenn die Tabelle registry$database nicht existiert (für 11gR2):

CREATE TABLE registry$database (
 PLATFORM_ID    NUMBER,
 PLATFORM_NAME  VARCHAR2(101),
 EDITION        VARCHAR2(30),
 TZ_VERSION     NUMBER
);

Wenn die Tabelle registry$database existiert (für11gR2):

alter table registry$database add (tz_version number);
delete from registry$database;


Für beide Varianten muss noch folgendes ausgeführt werden:

INSERT into registry$database
       (platform_id, platform_name, edition, tz_version)
VALUES ((select platform_id from v$database),
        (select platform_name from v$database),
        NULL,
        (select version from v$timezone_file));
commit;


That's IT

Mittwoch, 7. August 2013

Authentifizierung bei APEX-Zugriff deaktivieren

Installiert man APEX mit PL/SQL Listener in einer Datenbank (außer XE), so muss man bei jedem Zugriff auf die APEX-Weboberfläche ein Username und Passwort eingeben. Es handelt sich hierbei um die Authentifizierung an der XML-Datenbank. Um dies abzustellen muss der folgende Code ausgeführt werden:

SET SERVEROUTPUT ON

DECLARE
  l_cfgxml XMLTYPE;
  l_value VARCHAR2(5) := 'true'; -- (true/false)
BEGIN
  l_cfgxml := DBMS_XDB.cfg_get();

  IF l_cfgxml.existsNode('/xdbconfig/sysconfig/protocolconfig/httpconfig/allow-repository-anonymous-access') = 0 THEN
    SELECT insertChildXML (
      l_cfgxml, '/xdbconfig/sysconfig/protocolconfig/httpconfig',
      'allow-repository-anonymous-access',
      XMLType('<allow-repository-anonymous-access xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd">' ||
      l_value || '</allow-repository-anonymous-access>'),
      'xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"'
    ) INTO l_cfgxml FROM dual;

    DBMS_OUTPUT.put_line('Element inserted.');
  ELSE
    SELECT updateXML (
      DBMS_XDB.cfg_get(),
      '/xdbconfig/sysconfig/protocolconfig/httpconfig/allow-repository-anonymous-access/text()',
      l_value, 'xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"'
    )
    INTO l_cfgxml FROM dual;

    DBMS_OUTPUT.put_line('Element updated.');
  END IF;

  DBMS_XDB.cfg_update(l_cfgxml);
  DBMS_XDB.cfg_refresh;
END;
/


(Quelle: My Oracle Support)
That's IT

Mittwoch, 31. Juli 2013

APEX mit PL/SQL Embedded Gateway

Diese Konstellation ist nur für Umgebungen mit einer geringen Anzahl von Usern geeignet. Es empfielt sich immer einen Web-Server vor APEX zu hängen; Ich habe gute Erfahrungen mit Tomcat gemacht.
Zurück zum PL/SQL Embedded Gateway. Um eine akzeptable performance zu erreichen, sollte der Shared Server konfiguriert werden. Hier ein Beispiel für eine solche Konfiguration:

alter system set shared_servers=5;
alter system set max_shared_servers=20;
alter system set dispatchers='(PROTOCOL=TCP) (SERVICE=XE) (DISPATCHERS=3)';


Der SERVICE muss natürlich auf die entsprechende Umgebung angepasst werden.
That's IT.

Donnerstag, 18. Juli 2013

log_file_sync

Thank you Riyaj Shamsudeen for your good post on resolving log_file_sync wait events.
Here is the article: http://orainternals.wordpress.com/2008/07/07/tuning-log-file-sync-wait-events/

Donnerstag, 27. Juni 2013

"Execute to Parse"-Wert ist negativ

Bei einer Datenbank-Analyse fiel mir kürzlich auf, dass bei der Instanz-Effektivität des Statspack-Berichts (gilt auch für AWR) ein negativer Wert für Execute to Parse angegeben wurde. Zunächst bin ich einfach darüber hinweggegangen mit der Annahme, dass dies ein Erfassungsfehler oder sonst ein Bug im Bericht sei.
Instance Efficiency Indicators
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Buffer Nowait %: 100.00       Redo NoWait %:  99.99
               Buffer Hit %:  99.99  Optimal W/A Exec %: 100.00
              Library Hit %:  93.59        Soft Parse %:  93.83
         Execute to Parse %: -43.82         Latch Hit %:  99.54
Parse CPU to Parse Elapsd %:  98.17     % Non-Parse CPU:  96.70
Was steckt jedoch wirklich hinter dieser negativen Zahl?
Die Anwendung, die diese Datenbank benutzt, hält nicht viel von Bind-Variablen. Deshalb war zu erwarten, dass dieser Wert gegen "0" geht. Ein negativer Wert bedeutet jedoch das Folgende:
Der Wert setzt sich zusammen aus [geparste SQLs]/[ausgeführte SQLs]*100. Normaler Weise sind die ausgeführten SQLs deutlich höher als die geparsten. Deshalb geht der Wert auch eher gegen 100% statt gegen 0%. In diesem Fall war aber die Anzahl der geparsten SQLs deutlich höher als die Anzahl der ausgeführten SQLs. Mit anderen Worten, die Anwendung lässt SQLs von der Datenbank parsen, die aber nie ausgeführt werden. Es werden hier also Datenbankressourcen verschwendet mit Operationen die niemand benötigt.
Was hier zu tun ist, liegt auf der Hand. Die Anwendung muss untersucht und bereinigt werden.

Update 2015-08-27:
Dieses Phänomen habe ich mittlerweile bei mehreren Datenbanken beobachtet. Wann immer die Entwickler der Anwendungen damit konfrontiert wurden, wurde dieses Verhalten der Anwendung vehement abgestritten. Meistens wird behauptet, dass SQLs nicht "prepared" werden und deshalb keine negative Zahl erscheinen kann. Es muss also mehr dahinter stecken als nur diese einfache Rechnung. Fakt ist, dass in der Datenbank etwas nicht ordnungsgemäß läuft.
Updates folgen...

Thrat's IT

Mittwoch, 26. Juni 2013

Mittwoch, 6. Februar 2013

Probleme beim Löschen einer Standby Datenbank

Diesen Blogeintrag liegt folgende Umgebung zu grunde:
Eine Oracle Datenbank vom Release 11.2.0.3 läuft auf einem Windows 2008 Server (das Betriebsystem spielt aber keine Rolle). Diese Datenbank hat 2 Standby-DBs die mit Oracle Dataguard Broker konfiguriert sind.
Eine der beiden Standby-Datenbanken sollte still gelegt werden was mit dem Befehl
DGMGRL> disable database "<DBUNIQUE_NAME>"
... normalerweise funktioniert.
Ein paar Tage später wurde die Standby-Datenbank dann komplett entfernt mit DGMGRL> remove database "<DBUNIQUE_NAME>". Zu dem Zeitpunkt war der Standby-Server nicht mehr verfügbar.
Kurze Zeit darauf fiel auf, dass im Enterprise Manager mehrere ARCH-Prozesse hohe Wartezeiten vom Typ "Unknown" haben. Im Alertlog konnten auch Timeouts beim Archivelog-Transport festgestellt werden. Ein Blick in das dazugeörige Tracefile machte dann deutlich, dass die stillgelegte Archivelog Destination Schuld an dem Problem trug. Anscheinend wird mit dem Broker-Befehl "disable database" bzw. "remove database" nur halbe Sache gemacht. Auch ein erneutes "enable configuration" half nichts. Oft ist das ja ein Heilmittel für solche Fälle.
Die Lösung war schlussendlich, die Archivelog-Destination von Hand mit
ALTER SYSTEM SET log_archive_dest_3='';
... zu löschen.
That's IT

Freitag, 10. August 2012

OracleNet für Clients in einer Data Guard Umgebung

Damit Clients immer auf die aktive Datenbank in einer Data Guard Umgebung kommen, muss die folgende Konfiguration vorgenommen werden.

Umgebung

Wir nehmen die folgende Konfiguration an:
Primary
Host: primhost
ORACLE_SID: mars
db_unique_name: mars
Standby
Host: primhost
ORACLE_SID: mars
db_unique_name: mars_dg
Konfiguration aus Sicht des Clients
Für die Clients soll der Oracle Service "marsdb" verfügbar gemacht werden. Dieser Dienst läuft immer auf der momentanen Primary-Database und wird bei einem Switchover oder Failover mit umgezogen. Dieses Verhalten kann mit einem Trigger erreicht werden, den wir auf der Primary Datenbank anlegen und per Redo-Apply auf die Standby Datenbank übertragen.

Trigger erstellen

Der Trigger startet den Oracle Service immer dann, wenn die Datenbank PRIMARY ist.
CREATE OR REPLACE TRIGGER MARS_SERVICE AFTER STARTUP ON DATABASE
DECLARE
  v_role VARCHAR(30);
BEGIN
  SELECT DATABASE_ROLE INTO v_role FROM V$DATABASE;
  IF v_role = ‘PRIMARY’ THEN
    DBMS_SERVICE.START_SERVICE(‘marsdb’);
  END IF;
END;
/
Wenn die Standby Datenbank von Zeit zu Zeit mal im READ_ONLY Modus laufen soll oder wenn das Feature Active Dataguard lizenziert wurde, kann der Trigger erweitert werden. Der Trigger startet immer dann der Oracle Service marsro (für "mars read only"), wenn es die momentane Standby Datenbank ist, die gerade gestartet wird. Die Erweiterung des Triggers sieht so aus:
CREATE OR REPLACE TRIGGER MARS_SERVICE AFTER STARTUP ON DATABASE
DECLARE
  v_role VARCHAR(30);
BEGIN
  SELECT DATABASE_ROLE INTO v_role FROM V$DATABASE;
  IF v_role = ‘PRIMARY’ THEN
    DBMS_SERVICE.START_SERVICE(‘marsdb’);
  ELSE
    DBMS_SERVICE.STOP_SERVICE(‘marsro’);
  END IF;
END;
/
Also, wie funktioniert der Trigger?
Immer beim ALTER DATABASE OPEN [READ ONLY]; prüft der Trigger ob die Datenbank PRIMARY ist oder nicht. Wenn sie PRIMARY ist, dann wird der Service marsdb gestartet. Andernfalls (READ_ONLY mit oder ohne Apply) wird der Service marsro gestartet. So ist die offene Datenbank immer unter dem Service Name marsdb erreichbar und die Datenbank im READ_ONLY Modus immer über den Service marsro. Also völlig transparent wird der Client immer auf die richtige Datenbank geschickt.

Client Konfiguration

Im Client ist jetzt eine Spezielle Konfiguration erforderlich damit er beide Datenbank-Server kennt.
In der TNSNAMES.ora muss der folgende Eintrag erstellt werden:
marsdb =
(DESCRIPTION =
  (ADDRESS_LIST =
  (ADDRESS = (PROTOCOL = TCP)(HOST = primhost)(PORT = 1521))
  (ADDRESS = (PROTOCOL = TCP)(HOST = stbyhost)(PORT = 1521))
  (LOAD_BALANCE = no)
  (FAILOVER = yes)
  )
  (CONNECT_DATA =
    (SERVER = DEDICATED)
    (SERVICE_NAME = marsdb)
    (failover_mode =
      (type = select)
      (method = preconnect)
      (retries = 50)
      (delay = 5)
    )
  )
)
Für unsere Freunde aus dem Java-Umfeld noch der JDBC Connectionstring:
jdbc:oracle:thin:@(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = primhost)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = stbyhost)(PORT = 1521))(LOAD_BALANCE = no)(FAILOVER = yes))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = marsdb)(failover_mode = (type = select)(method = preconnect)(retries = 50)(delay = 5))))
Was wird hier dem Client mitgeteilt?
  • Es existieren 2 Datenbanken die wo der Service marsdb gefunden werden kann.
  • LOAD_BALANCE ist aus weil ja immer nur eine Datenbank offen ist.
  • FAILOVER ist an und zwar mit der folgenden Konfiguration:
    • PRECONNECT
    • 50x soll versucht werden ein Reconnect durchzuführen.
    • 5 Sekunden Abstand zwischen den Reconnects.
Diese Konfiguration eignet sich besonders für Umgebungen die einen Observer haben. Ansonsten kann der Teil "failover_mode" weggelassen werden, denn es muss sowieso ein Manueller Eingriff erfolgen.
Für den Dienst marsro muss natürlich aus so ein Eintrag erstellt werden.
That's IT

Mittwoch, 18. Juli 2012

Automatic Memory Management in 11g

In Oracle 11g wurde das Automatic Memory Management (AMM) eingeführt, dass sowohl die SGA als auch die PGA dynamisch verwaltet. Mit der Einführung wurden die beiden neuen Parameter MEMORY_MAX_TARGET und MEMORY_TARGET geschaffen.
Immer wieder stelle ich fest, dass Datenbanken unvorteilhaft konfiguriert werden. Dies ist vor allem auf die Dokumente von Oracle zurückzuführen, die hier nicht alle Aspekte abdecken. Um Automatic Memory Management zu nutzen, müssen die folgenden Parameter gesetzt werden:
  • MEMORY_TARGET: Definiert die Obergrenze des Dynamisch verwalteten Speichers. SGA + PGA = MEMORY_TARGET.
  • MEMORY_MAX_TARGET: Dieser Parameter ist optional. Wenn er auf 0 steht, wird bei starten der Instanz der Parameter auf den selben Wert wie MEMORY_TARGET gesetzt.
  • SGA_TARGET: Laut Oracle Note 443746.1 soll dieser Parameter auf 0 gesetzt werden. In der Theorie stimme ich zu, in der Praxis nicht. Mehr dazu im nächsten Absatz.
  • PGA_AGGREGATE_TARGET: Das Selbe wie für Parameter SGA_TARGET.
In der Oracle-Dokumentation wird beschrieben, dass bei SGA_TARGET=0, Autotuning für DEFERRED Modus deaktiviert ist. Dies führt zu ORA-4031 ("Out of Memory") Fehlern. Ähnliches gilt für den Parameter PGA_AGGREGATE_TARGET. Hier kann es zu Fehler ORA-4030 kommen wenn der Parameter auf Wert 0 gesetzt wurde.
Mein Vorschlag ist deshalb die Parameter SGA_TARGET und PGA_AGGREAGATE_TARGET auf einen kleinen Wert zu setzen. Dieser Wert ist dann jeweils das Minimum an zugewiesenem Speicher und erlaubt Oracle trotzdem frei mit dem Speicher zu haushalten.
Als vollständiges Beispiel hier:
SQL> show parameter target
NAME                                 TYPE                              VALUE
------------------------------------ --------------------------------- ------------------------------
archive_lag_target                   integer                           0
db_flashback_retention_target        integer                           1440
fast_start_io_target                 integer                           0
fast_start_mttr_target               integer                           0
memory_max_target                    big integer                       12G
memory_target                        big integer                       12G
parallel_servers_target              integer                           64
pga_aggregate_target                 big integer                       500M
sga_target                           big integer                       2G

That's IT

Dienstag, 22. Mai 2012

Standby-Datenbank mit RMAN voll automatisch erstellen

Hier ein paar Notizen zum erstellen einer Standby-Datenbank mittels RMAN.
Immer wieder ärgere ich mich darüber, dass es im Internet keine vollständig beschriebene Anleitung gibt, wie man eine Standby-DB voll automatisch mit RMAN erstellt. Also habe ich mich dazu entschlossen eine weitere unvollständige Version hinzuzufügen. Vielleicht hilft es dem einen oder anderen... also, viel Erfolg!

Primary DB

  • Primary muss im Archivelog-Modus Laufen.
  • Force Loggin muss eingeschaltet sein.
  • Flashback muss an sein.
SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP MOUNT;
SQL> ALTER DATABASE ARCHIVELOG;
SQL> ALTER DATABASE FLASHBACK ON;
SQL> ALTER DATABASE FORCE LOGGING;
SQL> ALTER DATABASE OPEN;

Standby-Logfiles anlegen: Laut Oracle-Dokumentation sollen so viele Standby Log Gruppen angelegt werden wie Anzahl Redo Log Gruppen + 1. Im Fall eines RACs, sind es die Anzahl der Online Redo Logdateien + 1 multipliziert mit der Anzahl der RAC-Knoten.
Der Befehl zum Anlegen lautet wie folgt:
alter database add standby logfile group 4 size 50M;
alter database add standby logfile group 5 size 50M;
alter database add standby logfile group 6 size 50M;
alter database add standby logfile group 7 size 50M;

SQL-Net vorbereiten

In die SID-List des Primary und Standby Listeners die jeweilige Datenbank eintragen (+ _DGMGRL Eintrag). Anschließend die TNS-Names Einträge erstellen. Das Format des GLOBAL_NAME muss wie folgt sein: <db_unique_name>_DGMGRL[.db_domain]

listener.ora auf Primary

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = primhost)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = mars_DGMGRL)
      (ORACLE_HOME = c:\oracle\product\db112)
      (SID_NAME = mars)
    )
  )

listener.ora auf Standby

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = stbyhost)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = mars_dg_DGMGRL)
      (ORACLE_HOME = c:\oracle\product\db112)
      (SID_NAME = mars)
    )
  )

tnsnames.ora auf beiden Servern

DG_mars =
  (DESCRIPTION =
   (ADDRESS = (PROTOCOL=TCP)(HOST=primhost)(PORT=1521))
    (CONNECT_DATA =
      (SERVICE_NAME = mars_DGMGRL)
    )
  )
DG_mars_dg =
  (DESCRIPTION =
   (ADDRESS = (PROTOCOL=TCP)(HOST=stbyhost)(PORT=1521))
    (CONNECT_DATA =
      (SERVICE_NAME = mars_dg_DGMGRL)
    )
  )

Passwordfile

Das Passwordfile muss von der Primary Datenbank auf die Standby Datenbank kopiert werden. Neu erzeugen hilft nichts.

SPFILE erstellen

*.audit_file_dest='/opt/oracle/admin/dummy/adump'
*.db_create_file_dest='/opt/oracle/oradata'
*.db_name='mars'
*.db_recovery_file_dest='/opt/oracle/fast_recovery_area'
*.db_recovery_file_dest_size=17179869184
*.db_unique_name='mars_dg'
*.diagnostic_dest='/opt/oracle'
*.memory_target=536870912
*.undo_tablespace='UNDOTBS1'
!!!Es dürfen keine Dataguard-Spezifischen Parameter gesetzt sein. Wenn OMF verwendet wird, ist auch der Parameter "controlfiles" überflüssig. Alle nötigen Parameter werden von RMAN und später vom Broker gesetzt. Also am besten copy-paste übernehmen und namen anpassen.

Datenbank Clonen

C:\Users\Administrator.DC_MARS>set ORACLE_SID=mars
(der folgende Befehl nur unter Windows)
C:\Users\Administrator.DC_MARS>oradim -new -sid mars
Instanz erstellt.
C:\Users\Administrator.DC_MARS>sqlplus / as sysdba
SQL*Plus: Release 11.2.0.2.0 Production on Fr Mai 4 12:28:51 2012
Copyright (c) 1982, 2010, Oracle. All rights reserved.
Bei einer nicht hochgefahrenen Instanz angemeldet.
SQL> create spfile from pfile;
Datei erstellt.
SQL> startup nomount
ORACLE-Instanz hochgefahren.
Total System Global Area 4,8103E+10 bytes
Fixed Size 2264200 bytes
Variable Size 2,2414E+10 bytes
Database Buffers 2,5636E+10 bytes
Redo Buffers 50454528 bytes
SQL>
Und jetzt das eigentlich Clonen...
C:\Users\Administrator.DC_MARS>rman
Recovery Manager: Release 11.2.0.2.0 - Production on Fr Mai 4 12:32:39 2012
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
RMAN> connect target sys/<pw>@DG_mars
Mit Ziel-Datenbank verbunden: MARS (DBID=3147292014)
RMAN> connect auxiliary sys/<pw>@DG_mars_dg
Bei Hilfsdatenbank angemeldet: MARS (nicht mit MOUNT angeschlossen)
RMAN>
RMAN>
RMAN> run {
allocate channel d1 device type disk;
allocate channel d2 device type disk;
allocate channel d3 device type disk;
allocate auxiliary channel aux1 device type disk;
allocate auxiliary channel aux2 device type disk;
allocate auxiliary channel aux3 device type disk;
duplicate target database for standby from active database;
}
Kontrolldatei der Zieldatenbank wird anstelle des Recovery-Katalogs verwendet
Zugewiesener Kanal: d1
Kanal d1: SID=1267 Device-Typ=DISK
Zugewiesener Kanal: d2
Kanal d2: SID=1373 Device-Typ=DISK
Zugewiesener Kanal: d3
Kanal d3: SID=1468 Device-Typ=DISK
Zugewiesener Kanal: aux1
Kanal aux1: SID=673 Device-Typ=DISK
Zugewiesener Kanal: aux2
Kanal aux2: SID=770 Device-Typ=DISK
Zugewiesener Kanal: aux3
Kanal aux3: SID=866 Device-Typ=DISK
Starten Duplicate Db um 04.05.12
Inhalt von Speicher-Skript:
{
backup as copy reuse
targetfile 'c:\oracle\product\db112\DATABASE\PWDmars.ORA' auxiliary format
'c:\Oracle\product\db112\DATABASE\PWDmars.ORA' ;
}
Speicher-Skript wird ausgef³hrt
Starten backup um 04.05.12
Beendet backup um 04.05.12
Inhalt von Speicher-Skript:
{
sql clone "alter system set control_files = ''L:\ORADATA\MARS\CONTROLFILE\O1_MF_7T7FK57Q_.CTL'', ''F:\ORAFLASH\MARS\CONTROLFILE\O1_MF_7T7FK57Q_.CTL'' comment=''Set by RMAN'' scope=spfile";
backup as copy current controlfile for standby auxiliary format 'L:\ORADATA\MARS\CONTROLFILE\O1_MF_7T7FK586_.CTL';
restore clone controlfile to 'F:\ORAFLASH\MARS\CONTROLFILE\O1_MF_7T7FK586_.CTL' from 'L:\ORADATA\MARS\CONTROLFILE\O1_MF_7T7FK586_.CTL';
sql clone "alter system set control_files = ''L:\ORADATA\MARS\CONTROLFILE\O1_MF_7T7FK586_.CTL'', ''F:\ORAFLASH\MARS\CONTROLFILE\O1_MF_7T7FK586_.CTL'' comment=''Set by RMAN'' scope=spfile";
shutdown clone immediate;
startup clone nomount;
}
Speicher-Skript wird ausgef³hrt
SQL-Anweisung: alter system set control_files = ''L:\ORADATA\MARS\CONTROLFILE\O1_MF_7T7FK57Q_.CTL'', ''F:\ORAFLASH\MARS\CONTROLFILE\O1_MF_7T7FK57Q_.CTL'' comment= ''Set by RMAN'' scope=spfile
Starten backup um 04.05.12
Kanal d1: Datendatei-Kopie wird gestartet
Standby-Kontrolldatei wird kopiert
Ausgabedateiname=C:\ORACLE\PRODUCT\DB112\DATABASE\SNCFMARS.ORA Tag=TAG20120504T125741 RECID=111 STAMP=782398662
Kanal d1: Datendatei-Kopie abgeschlossen, abgelaufene Zeit: 00:00:02
Beendet backup um 04.05.12
Starten restore um 04.05.12
Kanal aux2: ³bersprungen, AUTOBACKUP schon gefunden
Kanal aux3: ³bersprungen, AUTOBACKUP schon gefunden
Kanal aux1: Kontrolldateikopie wurde kopiert
Beendet restore um 04.05.12
SQL-Anweisung: alter system set control_files = ''L:\ORADATA\MARS\CONTROLFILE\O1_MF_7T7FK586_.CTL'', ''F:\ORAFLASH\MARS\CONTROLFILE\O1_MF_7T7FK586_.CTL'' comment= ''Set by RMAN'' scope=spfile
Oracle-Instanz heruntergefahren
Mit Hilfsdatenbank verbunden (nicht gestartet)
Oracle-Instanz gestartet
Gesamte System Global Area 48102666240 Byte
Fixed Size 2264200 Byte
Variable Size 22414361464 Byte
Database Buffers 25635586048 Byte
Redo Buffers 50454528 Byte
Zugewiesener Kanal: aux1
Kanal aux1: SID=578 Device-Typ=DISK
Zugewiesener Kanal: aux2
Kanal aux2: SID=673 Device-Typ=DISK
Zugewiesener Kanal: aux3
Kanal aux3: SID=770 Device-Typ=DISK
Inhalt von Speicher-Skript:
{
sql clone 'alter database mount standby database';
}
Speicher-Skript wird ausgef³hrt
SQL-Anweisung: alter database mount standby database
Inhalt von Speicher-Skript:
{
set newname for clone tempfile 2 to new;
switch clone tempfile all;
set newname for clone datafile 1 to new;
set newname for clone datafile 2 to new;
set newname for clone datafile 3 to new;
set newname for clone datafile 4 to new;
set newname for clone datafile 5 to new;
set newname for clone datafile 6 to new;
backup as copy reuse
datafile 1 auxiliary format new
datafile 2 auxiliary format new
datafile 3 auxiliary format new
datafile 4 auxiliary format new
datafile 5 auxiliary format new
datafile 6 auxiliary format new
;
sql 'alter system archive log current';
}
Speicher-Skript wird ausgef³hrt
Befehl wird ausgef³hrt: SET NEWNAME
Temporõre Datei 2 in Kontrolldatei in L:\ORADATA\MARS\DATAFILE\O1_MF_TEMP_%U_.TMP umbenannt
Befehl wird ausgef³hrt: SET NEWNAME
Befehl wird ausgef³hrt: SET NEWNAME
Befehl wird ausgef³hrt: SET NEWNAME
Befehl wird ausgef³hrt: SET NEWNAME
Befehl wird ausgef³hrt: SET NEWNAME
Befehl wird ausgef³hrt: SET NEWNAME
Starten backup um 04.05.12
Kanal d1: Datendatei-Kopie wird gestartet
Dateinummer der Eingabedatendatei=00004 Name=E:\ORADATA\MARS_DG\DATAFILE\O1_MF_DATA1_DATA_D-MARS_I-3147292014_TS-DATA1_FNO-4_1EMOBHPS_.DBF
Kanal d2: Datendatei-Kopie wird gestartet
Dateinummer der Eingabedatendatei=00006 Name=E:\ORADATA\MARS_DG\DATAFILE\O1_MF_DATA1_77P38MKR_.DBF
Kanal d3: Datendatei-Kopie wird gestartet
Dateinummer der Eingabedatendatei=00001 Name=E:\ORADATA\MARS_DG\DATAFILE\O1_MF_SYSTEM_DATA_D-MARS_I-3147292014_TS-SYSTEM_FNO-1_1GMOBHPT_.DBF
Ausgabedateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_SYSTEM_DATA_D-MARS_I-3147292014_TS-SYSTEM_FNO-1_D7NA4T7J_.DBF Tag=TAG20120504T125827
Kanal d3: Datendatei-Kopie abgeschlossen, abgelaufene Zeit: 00:02:36
Kanal d3: Datendatei-Kopie wird gestartet
Dateinummer der Eingabedatendatei=00003 Name=E:\ORADATA\MARS_DG\DATAFILE\O1_MF_UNDOTBS1_DATA_D-MARS_I-3147292014_TS-UNDOTBS1_FNO-3_1HMOBHPT_.DBF
Ausgabedateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_UNDOTBS1_DATA_D-MARS_I-3147292014_TS-UNDOTBS1_FNO-3_D8NA4TCF_.DBF Tag=TAG20120504T125827
Kanal d3: Datendatei-Kopie abgeschlossen, abgelaufene Zeit: 00:00:36
Kanal d3: Datendatei-Kopie wird gestartet
Dateinummer der Eingabedatendatei=00002 Name=E:\ORADATA\MARS_DG\DATAFILE\O1_MF_SYSAUX_DATA_D-MARS_I-3147292014_TS-SYSAUX_FNO-2_1IMOBHPT_.DBF
Ausgabedateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_SYSAUX_DATA_D-MARS_I-3147292014_TS-SYSAUX_FNO-2_D9NA4TDJ_.DBF Tag=TAG20120504T125827
Kanal d3: Datendatei-Kopie abgeschlossen, abgelaufene Zeit: 00:00:25
Kanal d3: Datendatei-Kopie wird gestartet
Dateinummer der Eingabedatendatei=00005 Name=E:\ORADATA\MARS_DG\DATAFILE\O1_MF_INDEX1_DATA_D-MARS_I-3147292014_TS-INDEX1_FNO-5_1JMOBHPT_.DBF
Ausgabedateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_INDEX1_DATA_D-MARS_I-3147292014_TS-INDEX1_FNO-5_DANA4TEC_.DBF Tag=TAG20120504T125827
Kanal d3: Datendatei-Kopie abgeschlossen, abgelaufene Zeit: 00:00:07
Ausgabedateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_DATA1_DATA_D-MARS_I-3147292014_TS-DATA1_FNO-6_D6NA4T7J_.DBF Tag=TAG20120504T125827
Kanal d2: Datendatei-Kopie abgeschlossen, abgelaufene Zeit: 00:09:13
Ausgabedateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_DATA1_DATA_D-MARS_I-3147292014_TS-DATA1_FNO-4_D5NA4T7J_.DBF Tag=TAG20120504T125827
Kanal d1: Datendatei-Kopie abgeschlossen, abgelaufene Zeit: 00:10:33
Beendet backup um 04.05.12
SQL-Anweisung: alter system archive log current
Inhalt von Speicher-Skript:
{
switch clone datafile all;
}
Speicher-Skript wird ausgef³hrt
Datendatei 1 gegen Datendateikopie ausgetauscht
Eingabe-Datendateikopie RECID=111 STAMP=782399342 Dateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_SYSTEM_DATA_D-MARS_I-3147292014_TS-SYSTEM_FNO-1_D7NA4T7J_.DBF
Datendatei 2 gegen Datendateikopie ausgetauscht
Eingabe-Datendateikopie RECID=112 STAMP=782399342 Dateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_SYSAUX_DATA_D-MARS_I-3147292014_TS-SYSAUX_FNO-2_D9NA4TDJ_.DBF
Datendatei 3 gegen Datendateikopie ausgetauscht
Eingabe-Datendateikopie RECID=113 STAMP=782399342 Dateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_UNDOTBS1_DATA_D-MARS_I-3147292014_TS-UNDOTBS1_FNO-3_D8NA4TCF_.DBF
Datendatei 4 gegen Datendateikopie ausgetauscht
Eingabe-Datendateikopie RECID=114 STAMP=782399342 Dateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_DATA1_DATA_D-MARS_I-3147292014_TS-DATA1_FNO-4_D5NA4T7J_.DBF
Datendatei 5 gegen Datendateikopie ausgetauscht
Eingabe-Datendateikopie RECID=115 STAMP=782399342 Dateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_INDEX1_DATA_D-MARS_I-3147292014_TS-INDEX1_FNO-5_DANA4TEC_.DBF
Datendatei 6 gegen Datendateikopie ausgetauscht
Eingabe-Datendateikopie RECID=116 STAMP=782399343 Dateiname=L:\ORADATA\MARS\DATAFILE\O1_MF_DATA1_DATA_D-MARS_I-3147292014_TS-DATA1_FNO-6_D6NA4T7J_.DBF
Beendet Duplicate Db um 04.05.12
Freigegebener Kanal: d1
Freigegebener Kanal: d2
Freigegebener Kanal: d3
Freigegebener Kanal: aux1
Freigegebener Kanal: aux2
Freigegebener Kanal: aux3
RMAN>

Broker Konfigurieren

Broker Starten

SQL> alter system set dg_broker_start=true;

Konfiguration erstellen

Primary Datenbank hinzufügen

DGMGRL> CONNECT sys/<pw>@DG_mars
DGMGRL> create configuration mars_dataguard as primary database is mars connect identifier is DG_mars;

Standby Datenbank hinzufügen

DGMGRL> add database mars_dg as connect identifier is DG_mars_dg maintained as physical;

Konfiguration anschalten

DGMGRL> enable configuration;

Standby File Management auf AUTO setzen

DGMGRL> edit database mars set property 'StandbyFileManagement'='AUTO';
DGMGRL> edit database mars_dg set property 'StandbyFileManagement'='AUTO';

Protection Mode anpassen

Konfigurationen vornehmen:
DGMGRL> edit database mars_dg set property 'logxptmode'='sync';
DGMGRL> edit database mars set property 'logxptmode'='sync';
Protection Mode wechseln:
DGMGRL> edit configuration set protection mode as maxavailability;
That's IT -- beim nächsten Mal mehr...

Freitag, 18. Mai 2012

Stabilität für Oracle Datenbanken


Warum Standardisierung zur Stabilitätsgewinnung?

"Ordnung ist das halbe Leben." Ein total abgedroschenes Sprichwort - finde ich - unwahr ist es deshalb aber bei Weitem nicht. Ganz im Gegenteil. Meine Erfahrungen als Oracle-DBA haben mich immer wieder zu dem Schluss geführt, dass viele Fehler vermeiden lassen wenn Ordnung herrscht.
Oracle Datenbanken zu betreiben, bedeutet weit mehr als Software Installation, Tablespaces erweitern und Backup. Datenbanken brauchen sehr viel Pflege und Zuwendung, sie sind sehr unbeständig und können ihre Ansprüche daher auch schnell verändern. Kümmert sich ein (DBA) nicht ständig um das Wohlergehen der Datenbanken, so wird bald ein Durcheinander und Wirrwarr entstehen. Dies hat zur wiederum Folge, dass die Performance und Stabilität der Systeme untergraben werden. Es gibt viele Oracle Datenbank Landschaften, die nach genau diesem Prinzip betrieben werden, aber sie sind alles andere als stabil, schnell und zuverlässig.
Meiner Meinung nach ist es also unabdingbar ein klares Konzept zu haben, ein "Handbuch" das eine Verbindliche Vorgehensweise beschreibt, wie Datenbanken unter welchen Umständen zu konfigurieren sind. Damit meine ich nicht nur die Konfigurations-Parameter der Datenbank selbst, sonder insbesondere die Infrastruktur in der diese Datenbank eingefügt ist.

Inhalt der Database Guideline

Was sollte alles in der Database Guideline beschrieben werden? Meine Antwort darauf lautet „ALLES – (fast) alles!“. Alles was nicht individuell für diese eine Datenbank so eingestellt wird muss in diesem Handbuch stehen. Für ein 1-Mann DBA-Büro mag das unsinnig erscheinen - ist es aber nicht. Wer kennt das nicht: "Wie war das gerade nochmal? Ach, wird schon stimmen...". Die Schwierigkeit besteht also darin, zwischen sinniger und unsinniger Dokumentation zu bleiben. Dabei ist aber die unsinnige Dokumentation immer noch besser als keine Dokumentation.
Als Starthilfe will ich hier ein mögliches Inhaltsverzeichnis vorgeben:
  1. Host System
    1. Unterstützte Betriebsysteme (je weniger, desto besser)
    2. Benutzer und Benutzer-Gruppen
      1. Oracle Environment (UNIX/Linux)
      2. User und Group-IDs (sehr wichtig z.B. zentralen Script-Shares)
  2. Massenspeicher-Medien
  3. Datenbank Konfiguration
    1. Pfade für Software
      1. Oracle Datenbank
      2. ASM
      3. Application Server
    2. Pfade für Konfiguration
      1. Oracle HOME und BASE
      2. Parameter Dateien, Scripte, Kleine Helferlein
    3. Pfade für Daten
      1. Oradata
      2. Oraredo
      3. Oraarchive
      4. Oramirror (sofern verwendet)
      5. Flashrecovery Area (sofern verwendet)
    4. Namensauflösung
      1. TNSNAME / LDAP / OID
      2. Ein Standard, wie die Namensauflösung verteilt wird wenn TNANAMES verwendet wird
  4. Datenbank Backup
    1. Erläuterungen zum Backup-Konzept
    2. Scheduler
    3. Protokolle, Fehlermeldungen, Fehlerbehandlung
    4. Überwachung
    5. Anbindung an Backup-System
    6. RMAN-Scripte und Usage
  5. Hochverfügbarkeit
    1. RAC
      1. […]
    2. DataGuard
      1. […]
    3. Grid Infrastructure
    4. Oracle Restart / init-Scripte
  6. Antragsformulare
    1. Klingt bürokratisch, ist aber eine große Hilfe beim Managen von User-Anfragen
Fast alle dieser Punkte sind ein absolutes Muss. Je nach Datenbank Landschaft kommen noch einige Punkte hinzu, ganz besonders im Hochverfügbarkeits-Bereich. Wenn alle diese Punkte Dokumentiert und auf jeder Datenbank umgesetzt sind, so kann ich mit Sicherheit voraussagen, dass eine Grund-Stabilität geschaffen ist.
An dieser Stelle passt das folgende Beispiel aus einem Kundenprojekt: Fast täglich hatte irgend eine Datenbank (von ca. 70-80 Datenbanken) die unterschiedlichsten Probleme, meistens war eine Downtime nicht zu vermeiden. Zunächst wurde das zweiköpfige Datenbank-Team neu aufgestellt, anschließend arbeitete man an einem Konzept zur Standardisierung der Datenbank-Landschaft. Schon während der Umsetzung verringerten sich die Ausfälle immer mehr. Innerhalb von einem halben Jahr wurde das DBA-Team zum Aushängeschild der IT-Abteilung was Zuverlässigkeit der Systeme und Dokumentation anging.
That's IT :-)