Sandini Bib
Oracle9i für den DBA
Sandini Bib
EDITION Oracle Oracle 8 effizient einsetzen – Verteilung und Betrieb leistungsfähiger Oracle 8-Anwendungen Andreas Christiansen / Michael Höding / Gunter Saake / Claus Rautenstrauch ISBN 3-8273-1347-3 Oracle-Programmierung – Datenbankprogrammierung und -administration Heinz-Gerd Raymans ISBN 3-8273-1733-9 Oracle Designer R 6i und Developer 6i – Professionelle Modulentwicklung Werner Hasselberg ISBN 3-8273-1728-2 Oracle 8i Tuning und Administration – Mit praktischer Referenz Heidi Thorpe ISBN 3-8273-1778-5 Oracle9i für den DBA – Effizient konfigurieren, optimieren und verwalten Uwe Herrmann/Dierk Lenz/Günter Unbescheid/Johannes Ahrends ISBN 3-8273-1559
Sandini Bib
Uwe Herrmann, Dierk Lenz, Günter Unbescheid, Johannes Ahrends
Oracle9i für den DBA Effizient konfigurieren, optimieren und verwalten
An imprint of Pearson Education München • Boston • San Francisco • Harlow, England Don Mills, Ontario • Sydney • Mexico City Madrid • Amsterdam
Sandini Bib
Bibliografische Information Der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar.
Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt. 10 9 8 7 6 5 4 3 2 04 03 ISBN 3-8273-1559-X © 2002 by Addison-Wesley Verlag, ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D-81829 München/Germany Alle Rechte vorbehalten Einbandgestaltung: Lektorat: Korrektorat: Satz: Druck und Verarbeitung: Printed in Germany
Hommer Design, Haar bei München Barbara Lauer, Bonn Anne Spranger, München mediaService, Siegen Bercker, Kevelaer
Sandini Bib
Inhaltsverzeichnis Vorwort .............................................................................................................15 Einleitung ..........................................................................................................17 1
Die Basis-Architektur der Oracle-Datenbank ...................................................19 1.1 Allgemeines über Oracle8i und Oracle9i...................................................19 1.1.1 Kleine Versionshistorie ..............................................................20 1.2 Speicher und Prozesse ..............................................................................21 1.2.1 Hauptspeicherkomponenten.....................................................21 1.2.2 Prozesse....................................................................................22 1.2.3 Instanz und Datenbank.............................................................28 1.3 Physische und logische Strukturen............................................................28 1.3.1 Datendateien und Datenbankblöcke.........................................28 1.3.2 Inhalte der Datendateien: Datenbanksegmente ........................30 1.3.3 Weitere Dateien........................................................................31 1.4 Kommunikation .......................................................................................33 1.5 National Language Support .....................................................................33 1.5.1 Sprache und Gebiet..................................................................34 1.5.2 Zahlen- und Datumsformate.....................................................34 1.5.3 Zeichensätze.............................................................................35 1.6 Sicherheitsstrukturen ................................................................................37 1.7 Transaktionen, Sperren und Lesekonsistenz ..............................................39 1.7.1 Transaktionen ...........................................................................39 1.7.2 Sperren.....................................................................................40 1.7.3 Lesekonsistenz ..........................................................................42 1.8 Einige interne Algorithmen.......................................................................44 1.8.1 Der Least Recently Used-Algorithmus........................................44 1.8.2 Management von abhängigen Objekten ..................................45 1.9 Zusammenspiel der Komponenten...........................................................45 1.9.1 Szenario 1: SELECT ...................................................................46 1.9.2 Szenario 2: UPDATE..................................................................47 1.9.3 Szenario 3: Gleichzeitige Befehle SELECT und UPDATE .............51 1.9.4 Szenario 4: SELECT/UPDATE über Shared Server .......................52 1.9.5 Szenario 5: Wechsel der aktuellen Redolog-Gruppe ..................53 1.9.6 Szenario 6: Instanzabbruch und -wiederherstellung ..................54 1.10 DBA-Werkzeuge .......................................................................................56 1.10.1 Kommandozeilen-Werkzeuge ...................................................56 1.10.2 Oracle Enterprise Manager .......................................................56 1.11 Die Oracle9i-Familie .................................................................................57
Sandini Bib
6
Inhaltsverzeichnis
2
Installation und Basiskonfiguration..................................................................59 2.1 Basis für die Oracle-Installation: Hardware und Betriebssystem .................59 2.1.1 Hardware..................................................................................60 2.1.2 Betriebssysteme ........................................................................61 2.2 Installationsplanung .................................................................................67 2.2.1 Versionstechnische Planung ......................................................67 2.2.2 Betriebssystemspezifische Planung ............................................68 2.2.3 Die Planung von Instanzen und Datenbanken...........................68 2.3 Universal Installer: Konzepte und Installationsprozedere ...........................75 2.3.1 Interaktive Softwareinstallation .................................................75 2.3.2 Silent-Installation mit Konfigurationsdateien .............................80 2.3.3 Konfiguration der Oracle-Umgebung........................................80 2.3.4 Software Packager ....................................................................89 2.4 Basiskonfiguration ....................................................................................89 2.4.1 Oracle Flexible Architecture (OFA) ............................................89 2.4.2 Initialisierungsparameter...........................................................91 2.4.3 Betriebssystemspezifika .............................................................93 2.4.4 Datenbank erstellen ..................................................................94 2.4.5 Database Configuration Assistent............................................104 2.5 Instanzverwaltung ..................................................................................109 2.5.1 Werkzeuge und Voraussetzungen ...........................................109 2.5.2 Startup ...................................................................................110 2.5.3 Shutdown...............................................................................112 2.5.4 ALTER DATABASE....................................................................114 2.5.5 ALTER SYSTEM........................................................................114 2.5.6 Parametrierung.......................................................................116 2.5.7 Checkpoints ...........................................................................117 2.6 Oracle Real Application Cluster...............................................................119 2.6.1 Architektur..............................................................................119 2.6.2 Installation..............................................................................120 2.6.3 Konfiguration der RAC-Datenbank ..........................................121 2.6.4 Starten und Stoppen von RAC ................................................123 2.7 Oracle Enterprise Manager .....................................................................124 2.7.1 Konsole ..................................................................................125 2.7.2 Management Server ...............................................................126 2.7.3 Agent .....................................................................................127
Sandini Bib
Inhaltsverzeichnis
3
7
Datenbankdesign............................................................................................129 3.1 Namenskonventionen ............................................................................129 3.1.1 Datenbanken..........................................................................130 3.1.2 Objektnamen .........................................................................132 3.1.3 Systemobjekte ........................................................................133 3.2 Physische Implementierung von Entitäten ..............................................134 3.2.1 Überblick ................................................................................134 3.2.2 Heap-organisierte Tabellen .....................................................135 3.2.3 Cluster....................................................................................136 3.2.4 Index-organisierte Tabellen (IOT)............................................138 3.2.5 Partitionierte Tabellen.............................................................139 3.2.6 Externe Tabellen .....................................................................140 3.2.7 Temporäre Tabellen................................................................142 3.2.8 Objekttypen und Kollektionen ................................................143 3.3 Indexstrukturen ......................................................................................148 3.3.1 Allgemeine Regeln ..................................................................149 3.3.2 B*Indizes ................................................................................151 3.3.3 Bitmap-Indizes........................................................................152 3.3.4 Bitmap Join-Indizes .................................................................154 3.3.5 Reverse Key-Indizes.................................................................157 3.3.6 Funktionale Indizes .................................................................157 3.3.7 Komprimierung ......................................................................158 3.3.8 Aspekte der Indexverwaltung..................................................159 3.4 Partitionierung .......................................................................................162 3.4.1 Einführung .............................................................................162 3.4.2 Typen der Partitionierung .......................................................164 3.4.3 Partitionierte Tabellen.............................................................166 3.4.4 Partitionierte Indizes ...............................................................171 3.4.5 Partitionen und der Optimizer ................................................176 3.4.6 Partitionen verwalten..............................................................182 3.4.7 Alternativen zur Partionierung ................................................188 3.5 Constraints.............................................................................................189 3.5.1 Constraint-Definitionen ..........................................................189 3.5.2 Aus- und Einschalten von Constraints .....................................195 3.5.3 Verzögerte Constraint-Prüfung ...............................................197 3.5.4 Views......................................................................................199
Sandini Bib
8
Inhaltsverzeichnis
3.6
3.7
3.8
3.9 4
Systemobjekte........................................................................................200 3.6.1 Data Dictionary ......................................................................200 3.6.2 Rollback-Segmente .................................................................201 3.6.3 Temporär-Segmente...............................................................213 Tablespaces und Datendateien ...............................................................215 3.7.1 Erstellen eines Tablespaces......................................................217 3.7.2 Dictionary Managed Tablespaces............................................222 3.7.3 Locally Managed Tablespaces .................................................222 3.7.4 Temporary Tablespace............................................................223 3.7.5 Read-Only-Tablespace ............................................................223 3.7.6 Offline-Tablespace ..................................................................224 3.7.7 Transportable Tablespace .......................................................225 Redolog-Dateien ....................................................................................226 3.8.1 Arbeitsweise des LGWR-Prozesses ...........................................226 3.8.2 Konfiguration .........................................................................227 3.8.3 Administrationskommandos ...................................................229 3.8.4 Überwachung von Redolog-Dateien .......................................231 3.8.5 Überlegungen zur Spiegelung von Redolog-Dateien ...............232 3.8.6 Redolog-Dateien als Oracle Managed Files..............................232 3.8.7 Archivierte Redolog-Dateien ...................................................232 Control-Dateien .....................................................................................235 3.9.1 Administration der Control-Dateien ........................................236
Sicherheit ........................................................................................................241 4.1 Einführung .............................................................................................241 4.2 Benutzerplanung....................................................................................243 4.3 Interne Benutzerverwaltung ...................................................................244 4.3.1 Möglichkeiten der Authentifizierung .......................................245 4.3.2 Interne Authentifizierung ........................................................245 4.3.3 Externe Authentifizierung .......................................................247 4.3.4 Globale Authentifizierung .......................................................249 4.3.5 Proxy-Authentifizierung ..........................................................249 4.3.6 Authentifizierung von Datenbankadministratoren ...................251 4.3.7 Benutzerverwaltung................................................................252 4.4 Internet Directory, LDAP und SSL ...........................................................256 4.4.1 Die Möglichkeiten im Überblick ..............................................257 4.4.2 Grundlegende Standards und Begriffe ....................................260 4.4.3 Modell 1: Auflösung von Dienstbenennungen ........................266 4.4.4 Modell 2: Authentifizierung globaler Benutzer ........................271 4.4.5 Modell 3: Enterprise-Benutzer und Enterprise-Rollen ...............276 4.4.6 Verwaltung von Oracle Internet Directory...............................281
Sandini Bib
Inhaltsverzeichnis
9
4.5
Privilegien und Rollen.............................................................................282 4.5.1 Systemprivilegien ...................................................................282 4.5.2 Objektprivilegien ....................................................................288 4.5.3 Rollen .....................................................................................289 4.6 Virtual Private Database..........................................................................295 4.6.1 Einführung .............................................................................295 4.6.2 Aufbau einer VPD-Umgebung.................................................296 4.7 Labels.....................................................................................................304 4.7.1 Überblick ................................................................................304 4.7.2 Die Grundlagen ......................................................................305 4.7.3 Konfiguration eines Label-Systems ..........................................309 4.8 Profile ....................................................................................................316 4.8.1 Management von Ressourcen ................................................316 4.8.2 Password Management ..........................................................318 4.9 Management von Ressourcen mit dem Resource Manager .....................320 4.9.1 Überblick ................................................................................320 4.9.2 Der Aufbau einer Beispielumgebung.......................................321 4.9.3 Monitoring .............................................................................329 4.10 Auditing .................................................................................................329 4.10.1 Aktivieren von Auditing ..........................................................330 4.10.2 Kommando-Auditing ..............................................................331 4.10.3 Privilegien-Auditing ................................................................332 4.10.4 Objekt-Auditing......................................................................332 4.10.5 Fine-Grain-Auditing ................................................................333 4.10.6 Audit-Trigger ..........................................................................334 4.10.7 Empfehlungen ........................................................................334 5
Oracle Net .......................................................................................................337 5.1 Oracle Net-Architektur ...........................................................................337 5.1.1 Begriffe...................................................................................337 5.1.2 Funktionsweise von Client-Server-Verbindungen.....................338 5.1.3 Allgemeines zur Konfiguration ................................................340 5.1.4 Spezielle Konfigurationen .......................................................349 5.1.5 Fehlersuche ............................................................................354 5.2 Konfigurationswerkzeuge .......................................................................360 5.2.1 Net-Konfigurationsassistent ....................................................361 5.2.2 Net Manager ..........................................................................367 5.3 Shared Server .........................................................................................372 5.4 Connection Manager .............................................................................375 5.5 Zentrale Auflösung von Dienstnamen.....................................................378 5.5.1 Oracle Names.........................................................................379 5.5.2 LDAP-Verzeichnis ....................................................................383
Sandini Bib
10
Inhaltsverzeichnis
5.6
5.7
5.8
6
Allgemeine Tipps....................................................................................384 5.6.1 Verwaltung der Netzwerkkonfiguration ..................................384 5.6.2 Ein Listener für verschiedene Versionen...................................385 5.6.3 Oracle Net und Firewalls.........................................................386 HTTP-Server ...........................................................................................386 5.7.1 Installation..............................................................................387 5.7.2 Konfiguration .........................................................................388 IIOP-Verbindungen ................................................................................393 5.8.1 Java in der Datenbank.............................................................393 5.8.2 IIOP-Konfiguration..................................................................394
Backup/Recovery ............................................................................................397 6.1 Übersicht/Strategie.................................................................................397 6.2 Sicherung und Wiederherstellung interner Strukturen ............................398 6.2.1 Export ....................................................................................398 6.2.2 Import ....................................................................................404 6.2.3 Export/Import – National Language Support und Kompatibilität ....................................................406 6.2.4 Flat File Unload.......................................................................407 6.2.5 SQL*Loader ............................................................................408 6.3 Sicherung und Wiederherstellung externer Strukturen............................409 6.3.1 Archivierungsmodus ...............................................................409 6.3.2 Physikalische Verteilung der Datenbankkomponenten ............413 6.3.3 Offline-Sicherung....................................................................414 6.3.4 Online-Sicherung....................................................................415 6.3.5 Wiederherstellung ..................................................................419 6.4 Recovery Manager .................................................................................429 6.4.1 Architektur..............................................................................430 6.4.2 Backup ...................................................................................438 6.4.3 Restore und Recovery .............................................................440 6.4.4 Reporting und Überprüfung ...................................................443 6.4.5 Aufräumen .............................................................................444 6.4.6 Oracle Enterprise Manager Backup-Verwaltung ......................445 6.5 LogMiner ...............................................................................................447 6.5.1 Beispiel ...................................................................................449 6.5.2 LogMiner Viewer (Oracle9i) ....................................................449 6.5.3 PL/SQL-Packages ....................................................................454 6.5.4 Weitere Anwendungsfälle .......................................................456 6.5.5 Restriktionen...........................................................................456 6.5.6 Fazit .......................................................................................457 6.6 Failover-Systeme / Optionen ..................................................................458 6.6.1 Oracle Standby-Datenbank.....................................................458 6.6.2 Replikation..............................................................................465
Sandini Bib
Inhaltsverzeichnis
11
7
Optimierung ...................................................................................................467 7.1 Überblick und Strategie..........................................................................467 7.1.1 Die Ausführung von SQL-Code ...............................................468 7.2 Monitoring und Engpassanalyse .............................................................471 7.2.1 utlbstat/utlestat ......................................................................472 7.2.2 Statspack ................................................................................475 7.2.3 SQL-Area ................................................................................478 7.2.4 Anwendungs-Tracing und TKPROF .........................................479 7.2.5 Oracle Trace ...........................................................................485 7.2.6 Oracle SQL Analyze ................................................................486 7.3 Zugriffsoptimierung ...............................................................................490 7.3.1 Optimizer ...............................................................................491 7.3.2 Ausführungspläne...................................................................499 7.3.3 Indizes ....................................................................................502 7.3.4 Hints.......................................................................................508 7.3.5 Cluster....................................................................................518 7.3.6 Partitionierung........................................................................519 7.3.7 Gespeicherte Statistiken..........................................................520 7.3.8 Plan Stability...........................................................................521 7.4 Instanzoptimierung ................................................................................527 7.5 Datenbankoptimierung ..........................................................................532 7.5.1 Redundante Datenhaltung......................................................532 7.5.2 I/O-Verteilung ........................................................................533 7.5.3 Rollback-Segmente .................................................................534 7.5.4 Automatic Segment Space Management ................................534 7.5.5 Checkpoints ...........................................................................535 7.5.6 Hardware und Betriebssysteme ...............................................537 7.6 Real Application Cluster..........................................................................538
8
Verteilte Datenbanktechniken........................................................................541 8.1 Grundkonzepte ......................................................................................541 8.1.1 Datenbank-Link ......................................................................542 8.1.2 Verteilte Transaktionen ...........................................................545 8.2 Replikation .............................................................................................549 8.2.1 Einführung .............................................................................549 8.2.2 Konzepte und Architektur .......................................................550 8.2.3 Die Planung einer replizierten Datenbank ...............................558 8.2.4 Installation und Konfiguration.................................................567 8.2.5 Administration ........................................................................595 8.3 Advanced Queueing...............................................................................604 8.3.1 Was ist eine Queue? ...............................................................604 8.3.2 Die Praxis ...............................................................................606 8.3.3 Advanced Queueing vs. Replikation ........................................621
Sandini Bib
12
9
Inhaltsverzeichnis
Monitoring/Reorganisation............................................................................623 9.1 Was wird beobachtet .............................................................................623 9.1.1 Platzbedarf .............................................................................623 9.1.2 Grenzen .................................................................................624 9.1.3 Tuningparameter....................................................................624 9.2 Wie wird beobachtet ..............................................................................624 9.2.1 Alert-Datei ..............................................................................625 9.2.2 Tablespace und Datendatei ....................................................626 9.2.3 Extents ...................................................................................627 9.2.4 Filesystem ...............................................................................628 9.2.5 Oracle Enterprise Manager Advanced Events ..........................629 9.2.6 Online-Monitoring..................................................................631 9.3 Reparieren/Reorganisieren......................................................................635 9.3.1 Export/Import.........................................................................637 9.3.2 CREATE TABLE ... AS SELECT ... (CTAS) ...................................638 9.3.3 SQL*Plus-Befehl COPY ............................................................640 9.3.4 REBUILD INDEX ......................................................................640 9.3.5 MOVE TABLESPACE ................................................................640 9.3.6 Online-Table-Reorganisation...................................................641 9.3.7 Oracle Enterprise Manager-Reorganisationen..........................642
10 Neue Technologien.........................................................................................645 10.1 Objektrelationale Datenstrukturen ..........................................................645 10.1.1 Objekttypen ..........................................................................645 10.1.2 Vererbung .............................................................................649 10.1.3 REFs.......................................................................................651 10.1.4 Methoden .............................................................................652 10.1.5 Typerweiterungen .................................................................656 10.1.6 Objekt-Views .........................................................................657 10.1.7 Privilegien für Objekttypen ....................................................660 10.1.8 Programmierumgebungen ....................................................660 10.1.9 Verteilte Datenbanken ...........................................................661 10.2 XML-Unterstützung in der Datenbank ....................................................662 10.3 Java in der Datenbank ............................................................................663 10.3.1 Java-Grundlagen....................................................................664 10.3.2 Java-APIs in der Datenbank ....................................................665 10.3.3 Installation.............................................................................666
Sandini Bib
Inhaltsverzeichnis
13
11 Data Warehousing ..........................................................................................669 11.1 Extraktion, Transformation, Laden ..........................................................670 11.1.1 Transportable Tablespaces ......................................................670 11.1.2 Parallelisierung........................................................................673 11.1.3 Komplexe Laderoutinen..........................................................676 11.1.4 Überwachung der Ladeoperation............................................682 11.2 Datenbankdesign für Data Warehouses ..................................................685 11.2.1 Hardware-Architekturen..........................................................686 11.2.2 Tablespace-Layout ..................................................................690 11.2.3 Partitionierung........................................................................692 11.2.4 Indizierung .............................................................................697 11.2.5 Konsolidierung und Verdichtung ............................................700 11.2.6 Aggregationsfunktionen .........................................................710 11.3 Darstellung ............................................................................................713 11.3.1 Dimensionen ..........................................................................714 11.3.2 Parallele Abfragen...................................................................717 11.3.3 Analysefunktionen ..................................................................718 Stichwortverzeichnis.......................................................................................723
Sandini Bib
Sandini Bib
Vorwort Warum überhaupt ein Buch veröffentlichen, an dem die Autoren – mit Unterbrechungen – mehr als ein Jahr geschrieben haben und das sich auf ein Thema – die Datenbank Oracle9i – bezieht, das in atemberaubendem Tempo Änderungen und Ergänzungen ausgesetzt ist? Ist hierfür nicht das Internet ein viel geeigneteres Medium? Wenn es nur um die Beschreibung hochdynamischer technischer Details alleine ginge, wäre die Antwort mit Sicherheit ein ganz klares „Ja“. Wir, die Autoren, glauben jedoch, das es eine Welt jenseits nervöser Verkaufsstrategien gibt, in der es immer wichtiger wird, konzeptionelle Zusammenhänge, neue Lösungsansätze und Technologien grundlegend zu verstehen, kritisch zu bewerten und strategisch einzuschätzen, um sie dann über den Tag hinaus gewinnbringend einsetzen zu können. Hierzu sind auch, aber nicht nur, technische Details notwendig. Beiden Aspekten wollen wir in dieser Publikation Rechnung tragen. In diesem Sinne hoffen wir, allen interessierten DBAs die Orientierung im Dickicht der Datenbanktechnik etwas zu erleichtern. Es versteht sich, dass zum Gelingen eines Buches, gleich welcher Art, neben den Autoren eine ganze Reihe weiterer Personen und Institutionen beitragen müssen. Die vollständige Liste aller Namen wäre lang. Unser Dank gilt natürlich allen Beteiligten, auch wenn wir an dieser Stelle namentlich nur unsere Lektorin, Frau Barbara Lauer, erwähnen wollen, die unser Projekt mit unendlicher Geduld durch alle terminlichen „Herausforderungen“ begleitet hat. Jachenau und Burscheid, im August 2002 Die Autoren
Sandini Bib
Sandini Bib
Einleitung Auf die in vielen Fachbüchern an dieser Stelle übliche Kapitelübersicht verzichten wir bewusst, weil wir der Meinung sind, dass
: :
sich der grobe Themenbereich eines Kapitels über dessen Titel erschließt, die Details des jeweiligen Themas durch das Lesen des betreffenden Kapitels vermittelt werden.
Die Lektüre einzelner, isolierter Kapitel oder Kapitelabschnitte ist natürlich möglich, gleichwohl haben wir darauf geachtet, übergreifendes Basiswissen nicht in allen Kapiteln wiederzukäuen, um die Lesbarkeit des gesamten Buches zu verbessern. In der Abfolge der Kapitel gehen wir vom Allgemeinen zum Besonderen. Der Publikation liegt eine CD bei, welche die Originaldokumentation für die Version 9i im PDF-Format enthält, auf die an verschiedenen Stellen des Buches verwiesen wird. Schreibweisen Namen von Tabellen, Spalten, Prozeduren und Systemparametern erscheinen in Courierschrift und werden grundsätzlich klein geschrieben. Die gilt sowohl für die Namen von Beispielobjekten – Tabelle kunden –, als für die feststehenden Namen von Data Dictionary-Views oder mitgelieferten Paketen (View dba_tables, Paket dbms_repcat). In Syntaxbeispielen werden Schlüsselwörter groß, der Rest klein geschrieben: CREATE TABLE test ....
Menüpunkte erscheinen in KAPITÄLCHEN. Hervorhebungen im Text sind kursiv gesetzt.
Sandini Bib
Sandini Bib
1
Die Basis-Architektur der Oracle-Datenbank
Warum brauche ich ein Datenbankmanagementsystem? Und wenn ich schon eins brauche, warum dann dazu noch eines, das ich teuer bezahlen und über das ich zusätzlich zur mitgelieferten Dokumentation ein weiteres Buch lesen muss? Im Zeitalter von frei erhältlicher Software wie MySQL ist zumindest die zweite Frage sicherlich eine gute Frage. Die erste Frage ist nicht wirklich ernst gemeint; wer dieses Buch aufschlägt, hat sicher bereits eine Vorstellung davon, warum ein strukturiertes Management von Daten eine gute Idee ist. Kommen wir also zur zweiten Frage. Das Oracle-Datenbankmanagementsystem ist mit Sicherheit das komplexeste unter seinen direkten Mitbewerbern, da es im Laufe der Zeit eine riesige Menge an Möglichkeiten und Funktionen angesammelt hat. Immer wieder hört man die Frage: Brauche ich wirklich all die Funktionen, die eine Oracle-Datenbank mitbringt? Hierzu die klare Antwort: Nein! Aber in den meisten Fällen erweisen sich einige der mitgelieferten Funktionen als äußerst sinnvoll. Und diese „einigen Funktionen“ sind praktisch bei jeder Umgebung andere, so dass sich unter dem Strich wieder ergibt, dass es sich um ein riesiges, aber rundes Paket handelt. Wenn also ein riesiges Paket wie Oracle8i oder Oracle9i eine gute Idee ist, dann ist ein praxisbezogener Leitfaden zur Administration sinnvoll. Genau das versucht dieses Buch zu sein. Es ist von Leuten geschrieben worden, die sich über viele Jahre hinweg in den verschiedensten Situationen mit der Administration von OracleSystemen beschäftigt haben. Deshalb haben wir versucht, den richtigen Mix aus Hintergrundwissen und Anleitungen aus der Praxis zu finden. Voraussetzung für das Verständnis dieses Buches sind Grundkenntnisse über die Datenbanksprache SQL und über Datenbanken allgemein. Dieses Buch enthält im Übrigen keine Einführung in die Programmierung, sei es mit SQL, PL/SQL oder Java.
1.1
Allgemeines über Oracle8i und Oracle9i
Die Oracle-Datenbank ist als relationales Datenbankmanagementsystem ein kommerzielles Produkt, das auf Basis von theoretischen Grundlagen implementiert wurde. Als Standardprodukt basiert es auf der Datenbanksprache SQL (steht für Structured Query Language, obwohl viel mehr Möglichkeiten als nur die Abfrage von Daten bestehen; wird „SEQUEL“ gesprochen). Es erfüllt in weiten Teilen die Bedingungen an Core SQL:99, den mandatorischen Teil des SQL:99-Standards, der 1999 sowohl von der ANSI- als auch von den ISO/IEC-Organisiationen verabschiedet wurde. Neben den Standardelementen enthält Oracle SQL eine Reihe von Erweiterungen.
Sandini Bib
20
Die Basis-Architektur der Oracle-Datenbank
SQL selbst besteht sowohl aus dem SELECT-Befehl für die Abfrage als auch aus verschiedenen Befehlsgruppen wie DML-Befehlen (Data Manipulation Language, umfasst INSERT, UPDATE, DELETE) und DDL-Befehlen (Data Definition Language, zur Definition von Tabellen, Indizes usw.). Als Literaturhinweise für den interessierten Leser seien die theoretische Grundlage für relationale Systeme genannt, E.F. Codd: A Relational Model of Data for Large Data Banks, Communiactions of the ACM, Volume 13, 1970, Number 6, und das Standardwerk über Datenbanksysteme, C.J. Date, Introduction to Database Systems, Volume 1, 6th Edition, Addison-Wesley, 1995. Als Referenz der Oracle-Produkte sei natürlich auch auf die umfangreichen Handbücher zum Oracle Server verwiesen, die bei der Software-Auslieferung als zusätzliche CD sowohl im HTMLals auch im PDF-Format ausgeliefert werden.
1.1.1
Kleine Versionshistorie
Bevor die Komponenten der Oracle-Datenbank einzeln näher betrachtet werden, folgen zunächst einige Anmerkungen zum Begriff „Oracle-Datenbank“. Nachdem die Datenbanksoftware der Firma Oracle bis einschließlich Version 6 ausschließlich unter der Bezeichnung RDBMS (Relationales Datenbankmanagementsystem) verkauft wurde, wurde ab Version 7 der Begriff „Oracle Server“, zur Verdeutlichung der aktuellen Version auch „Oracle7 Server“ verwendet. Dieser Begriff betont die ab Version 7 stark ausgeprägten Serverfähigkeiten der Datenbanksoftware im Netzwerk. Im Hause Oracle wurde zwar bereits Mitte der 80er Jahre mit Release 5.1 und dem Produkt SQL*Net die Client-Server- und Server-Server-Kommunikation eingeführt, mit Version 7 wurden diese Fähigkeiten dann aber stärker ausgeprägt und wesentlich verfeinert. Das Produkt SQL*Net wurde mit dem Erscheinen des Oracle8 Servers in Net8 umbenannt. Um die Ausrichtung auf Internettechnologien zu betonen, wurde das erste Folgerelease von Oracle mit Oracle8i bezeichnet; die Releasenummer hierzu war 8.1. Beim Übergang auf Oracle9i (Release 9.0) wurde die offizielle Produktbezeichnung von „Oracle Server“ auf „Oracle Database“ geändert, so dass die deutsche Bezeichnung Oracle-Datenbank sich mehr denn je anbietet. SQL*Net heißt ab Oracle9i schlicht Oracle Net. Die ersten beiden Stellen der insgesamt fünfstelligen Oracle-Versionsnummer – Version und Release – sind „marketingrelevant“, d.h., mit einem neuen Release werden neben Fehlerkorrekturen zum Vorgänger auch neue Funktionen ausgeliefert. Sie tauchen damit u.a. in Buchtiteln auf. Die Versionsnummer kann z.B. nach erfolgreicher Anmeldung in SQL*Plus gelesen werden: Connected to: Oracle9i Enterprise Edition Release 9.0.1.3.1 - Production
Für Oracle8i wurde zur allgemeinen Verwirrung die Marketing-Zählweise von der Versionsnummerierung entkoppelt, was dazu führte, dass Oracle8i für Version 8.1.5, Oracle8i Release 2 für 8.1.6 und Oracle8i Release 3 für 8.1.7 steht. Normalerweise bezeichnet die dritte Stelle der Versionsnummer das Maintenance-Release, das nicht mit neuen Funktionen aufwartet, höchstens mit kleineren Schnittstellenänderungen im Rahmen von Fehlerkorrekturen oder Performance-Verbesserungen. Für
Sandini Bib
Speicher und Prozesse
21
Oracle9i benutzt man nun wieder die alte Logik, d.h., Oracle9i steht für Version 9.0; das als Nächstes erscheinende Oracle9i Release 2 für Version 9.2 – man hat also lediglich Version 9.1 ausgelassen, damit Marketing-Zählweise und Versionsnummer wieder stimmen. Zur vollständigen Beschreibung der Versionsnummer fehlen nun noch die vierte und fünfte Stelle, die für Patchsets und plattformspezifische Patches benutzt werden. Patchsets (z.B. 8.1.7.4) sind plattformunabhängig, d.h., für die verschiedenen Portierungen des Oracle-Systems steht ein identisches Basiscode-Release zur Verfügung. Erst bei der letzten Stelle können plattformspezifische Patches nachgeschoben werden, z.B. als 8.1.7.4.1 für MS-Windows. Damit Oracle-DBA und Entwickler sich nicht Dutzende von Versionsnummern merken müssen, wurden die Versionsnummern praktisch aller Produkte im Umfeld der Datenbank sinnvollerweise synchronisiert, d.h., zur Datenbank Version 9.0.1 gibt es SQL*Plus Version 9.0.1, Oracle Net Version 9.0.1 usw.
1.2
Speicher und Prozesse
Um dem Anspruch der Oracle-Datenbank als aktives System gerecht zu werden, widmet sich dieser Abschnitt zunächst den aktiven Komponenten im Hauptspeicher und auf dem Prozessor.
1.2.1
Hauptspeicherkomponenten
Stark vereinfacht gesagt, ist es die Hauptaufgabe einer Datenbank, Daten aus Anwendungen in Datenbankblöcke zu bringen bzw. umgekehrt. Diese Aktionen werden von den SQL-Befehlen aus den Anwendungen veranlasst. Dabei muss sichergestellt werden, dass die gleichzeitig laufenden Aktionen verschiedener Anwender sich möglichst wenig gegenseitig behindern. Diese Eigenschaft ist nicht einfach zu implementieren – bedenkt man, dass gleichzeitig Daten einer Tabelle gelesen und von anderen Anwendungen geschrieben werden können. Ein Schlüssel zur effizienten Abarbeitung gleichzeitiger Aktionen ist die „Datenverteilungszentrale“ des Oracle Servers im Hauptspeicher, die so genannte System Global Area (SGA). Die SGA muss von allen Prozessen, die zur Datenbank gehören, zugreifbar sein, da alle Daten, die in irgendeiner Weise für mehrere verschiedene Aufgaben benötigen werden könnten, hier zwischengespeichert werden. Diese Eigenschaft bildet die Basis für die Leistungsfähigkeit des Oracle Servers. Die Implementierung erfolgt plattformspezifisch, z.B. als Shared Memory Segment bei Unix-Systemen. Die SGA besteht aus sechs Hauptkomponenten: dem Blockpuffer (buffer cache), dem Logpuffer (log buffer), dem Shared Pool, dem Java Pool, dem Large Pool sowie einem fest allokierten Bereich. Der Blockpuffer bietet Platz für eine beim Systemstart festgelegte Anzahl von Datenbankblöcken. Hier werden Datenbankblöcke, die aus Datendateien gelesen worden sind, so gespeichert, dass sie bei Bedarf wiederbenutzt werden können, ohne sie erneut aus der Datendatei zu lesen. Der Blockpuffer kann optional in verschiedene Bereiche aufgeteilt werden, in denen sich die Algorithmen zum Wiederauffinden von Blöcken unterscheiden. Im Logpuffer werden
Sandini Bib
22
Die Basis-Architektur der Oracle-Datenbank
für die Wiederherstellbarkeit Veränderungen an den Datenbankblöcken protokolliert, bevor sie in die Redolog-Dateien geschrieben werden. Der Shared Pool nimmt hauptsächlich SQL- und PL/SQL-Befehle sowie den Dictionary Cache auf, um die Verarbeitung der Befehle zu beschleunigen. Die Befehle können ähnlich wie die Datenbankblöcke des Blockpuffers wiederverwendet werden; der Dictionary Cache enthält Informationen über Datenbankobjekte, die aus dem Data Dictionary stammen und bei der Übersetzung der Befehle benötigt werden. Im Java Pool werden Java-Objekte zwischengespeichert, wenn mit dem JServer gearbeitet wird. Im Large Pool wird sowohl für den Shared Server-Betrieb Platz für einzelne Sitzungen als auch für den Parallel Query-Betrieb und beim Backup mit dem Recovery Manager Platz allokiert.
Abbildung 1.1: Die System Global Area (SGA)
Eine wesentliche Neuerung von Oracle9i gegenüber Oracle8i ist die Einführung von dynamischen SGA-Parametern in Oracle9i. Solange eine statische Maximalgröße der SGA nicht überschritten wird, kann die Größe der oben beschriebenen SGA-Komponenten dynamisch verändert werden.
1.2.2
Prozesse
Ein wesentlicher Unterschied eines DBMS zur einfachen Datenhaltung auf einem Dateiserver ist der, dass das DBMS erheblich mehr Funktionen als solch elementare wie DATEI ÖFFNEN, DATEI SCHLIESSEN und NÄCHSTEN DATENSATZ LESEN anbietet: Über die Datenbanksprache SQL sind auch sehr komplexe Funktionen durchführbar. Weiterhin sind Transaktionssicherung, Sperrverhalten und viele andere Funktionen transparenter Bestandteil der Serverfunktionen, d.h., diese Funktionen müssen nicht von außen programmiert werden („Datensatz sperren“), sondern werden automatisch bei den entsprechenden SQL-Befehlen (z.B. UPDATE) ausgeführt.
Sandini Bib
Speicher und Prozesse
23
Weil auf dem Server eine solch komplexe Funktionalität implementiert ist, ist das Prozesskonzept von erheblicher Bedeutung. Der Datenbankserver wird verständlicherweise nicht nur das I/O-System beschäftigen, sondern auch in umfangreichem Maße Prozessorleistung beanspruchen. Dabei muss immer beachtet werden, dass es sich bei einem Datenbankserver um eine Mehrbenutzeranwendung handelt. Im Praxisbetrieb werden mehrere Benutzer gleichzeitig verschiedene oder ähnliche Aufgaben ausführen und dabei eventuell auch identische Daten benutzen. Das heißt wiederum, dass Sperr- und Transaktionskonzepte die Konsistenz der Daten garantieren müssen. Andererseits sollen sich die Benutzer so wenig wie möglich gegenseitig behindern, soweit ihre Aufgaben das zulassen. Der Ansatz der Oracle-Datenbank hierzu ist, die anfallenden Aufgaben auf verschiedene Prozesse aufzuteilen, so dass sich diese selbständig um die ihnen zugeordneten Aufgaben kümmern können. Vorausgesetzt, dass Hardware und Betriebssystem die Aufteilung der Ressourcen wie Prozessor, Hauptspeicher und I/O auf verschiedene Prozesse gut beherrschen, kann der Oracle Server die verfügbaren Ressourcen optimal nutzen. Die Alternative, alle Aufgaben des DBMS mit nur einem Prozess zu erledigen, brächte z.B. die Beschränkung, dass ein zweiter Prozessor nicht genutzt werden könnte. Bei einem Oracle-System unterscheidet man Prozesse, die spezielle Aufgaben ohne feste Zuordnung zu einzelnen Sitzungen ausführen (Hintergrundprozesse) und Prozesse, die den Sitzungen eins zu eins zugeordnet sind (Schatten- oder Dedicated Server-Prozesse). Als Sitzung wird eine logische Verbindung zur Datenbank bezeichnet, die im allgemeinen nach der Eingabe von Benutzername und Passwort aufgebaut wird. Alle genannten Prozesse sind Prozesse des Oracle Servers oder des Backends. Um das Backend mit Aufgaben zu versorgen, muss mindestens ein Frontend- oder Client-Prozess vorhanden sein. Dieser stellt Aufgaben, z.B. in Form von SQL-Befehlen, an das Backend, den Oracle Server. Frontend-Prozesse sind meist die Anwendungen, die die Anwender auf ihrem Bildschirm sehen (manchmal ohne zu wissen, dass sich eine Oracle-Datenbank um ihre Daten kümmert). Sie müssen nicht auf dem Rechner laufen, auf dem sich die Oracle-Datenbank befindet. Das Prinzip der Kombination von Hintergrund- und Dedicated Server-Prozessen ist ein entscheidender Punkt in der Oracle-Architektur. An dieser Stelle wird der Grundstein für die hohe Skalierbarkeit des Oracle Server mit der Hardwareleistung gelegt. Die einzelnen Prozesse sind unabhängig voneinander und gleichzeitig ausführbar.1 Falls die Möglichkeit des Oracle Servers genutzt werden soll, selbstgeschriebene 3GL-Prozeduren aus PL/SQL heraus aufzurufen, werden weitere Prozesse sitzungsbezogen gestartet.
1.
„Gleichzeitige Ausführung“ bezieht sich bei Einprozessorsystemen auf die quasi gleichzeitige Ausführung mehrerer Prozesse durch den Scheduler des Betriebssystems. Zu jedem Zeitpunkt wird lediglich genau ein Prozess ausgeführt, der Scheduler verteilt die CPU in Form von Zeitscheiben an die einzelnen Prozesse. Bei Mehrprozessorsystemen können tatsächlich mehrere Prozesse gleichzeitig ausgeführt werden.
Sandini Bib
24
Die Basis-Architektur der Oracle-Datenbank
Client-Prozesse Der Datenbankserver muss in irgendeiner Form mit Aufgaben in Form von SQLBefehlen versorgt werden. Dies übernimmt ein Client-Prozess, der entweder auf dem gleichen Rechner wie die Oracle-Datenbank läuft oder auf einem anderen Rechner im Netzwerk. Im ersten Fall spricht man von einer „lokalen Anwendung“, im zweiten von einer „Client-Server-Anwendung“. Die Anbindung von Anwendungen mit Oracle Net an eine Oracle-Datenbank über ein Netzwerk wird in Kapitel 5 behandelt. Die Anwendung selber kann unterschiedliche Ausprägungen haben: Es kann z.B. eine mit Oracle-Entwicklungswerkzeugen (z.B. Oracle9i Developer Suite) erstellte Anwendung, eine 3GL-Anwendung (z.B. in C, COBOL oder FORTRAN) mit Embedded SQL- oder OCI-Befehlen, eine Java-Anwendung oder eine ODBC-Anwendung sein. Diese Unterschiede sind aus Sicht der Oracle-Datenbank nicht relevant, da letztendlich alle Anwendungen die gleiche Aufrufschnittstelle zur Oracle-Datenbank benutzen, das User Program Interface (UPI). Somit verhalten sich alle Clients für die Oracle-Datenbank im Prinzip identisch. Hintergrundprozesse Die Hintergrundprozesse sind je nachdem, welche Optionen installiert sind, und je nach Konfiguration, in unterschiedlicher Zahl vorhanden. Als Minimum für einen funktionsfähigen Oracle Server sind fünf Hintergrundprozesse vorhanden, von denen drei Schreib- und zwei Monitoraufgaben übernehmen. Zusammen mit den Hauptspeicherstrukturen werden die Hintergrundprozesse auch als Instanz bezeichnet. Die folgende Tabelle enthält eine Übersicht der wichtigsten Oracle-Hintergrundprozesse. Ihre Funktion ist jeweils kurz beschrieben; auch hier werden spätere Kapitel noch genaueren Aufschluss bringen. Prozess
Optional?
Beschreibung
DBWn (Database Writer), n=0..9
Nein
Schreibt veränderte Datenbankblöcke, die in der SGA liegen, zurück in die Datenbank.
LGWR (Log Writer)
Nein
Schreibt das Transaktionsprotokoll vom Logpuffer in die Redolog-Dateien. Arbeitet beim Umschalten auf eine andere Redolog-Gruppe mit den DBWn zusammen.
CKPT (Checkpoint Process)
Nein
Beschleunigt Checkpoints bei Datenbanken mit vielen Datendateien.
SMON (System Monitor)
Nein
Beobachtet die interne Datenbankaktivität: Achtet z.B. auf Deadlocks und löscht nicht mehr benutzte Temporärsegmente.
PMON (Process Monitor)
Nein
Beobachtet die Datenbankaktivität aus Betriebssystemsicht: Sind noch alle notwendigen Prozesse vorhanden?
Sandini Bib
Speicher und Prozesse
25
Prozess
Optional?
Beschreibung
ARCn (Archiver), n=0..9
Ja
Erstellt Kopien der vom LGWR generierten Redolog-Dateien. Diese Kopien bilden die Offline- oder archivierten Redolog-Dateien.
RECO (Distribted Recovery)
Ja
Koordiniert die verteilte Wiederherstellung bei abgebrochenen verteilten Transaktionen.
LCKn (Lock Process)
Ja
PCM-Locking bei Parallel Server Option
SNPn (Snapshot Refresh Process), n=0..9A..Z
Ja
Job Queue-Abarbeitung bis einschließlich Oracle8i
CJQ0 (Job Queue Coordinator)
Ja
Job Queue-Koordinator ab Oracle9i
Jnnn (Job Queue Process), nnn=000..999
Ja
Dynamisch von CJQ0 gestartete Prozesse zur Job Queue-Abarbeitung (Oracle9i)
Pnnn (Parallel Query Server)
Ja
Übernimmt Teilaufgaben bei der parallelen Abarbeitung von SQL-Befehlen.
Dnnn (Dispatcher)
Ja
Kommunikationsprozess für die Shared ServerProzesse
Snnn (Shared Server)
Ja
Shared Server-Prozesse
AQTM (Advanced Queueing Time Manager)
Ja
Zeitgesteuerte Aktionen beim Advanced Queueing
QMNn (Advanced Queue Manager), n=0..9
Ja
Advanced Queueing
Tabelle 1.1: Die wichtigsten Oracle-Hintergrundprozesse
Bei Systemen, die im Netzwerk zur Verfügung stehen müssen, ist zusätzlich zu den o.a. Hintergrundprozessen ein Listener vorhanden. Dieser hat die Aufgabe, auf Verbindungsanforderungen aus dem Netzwerk zu „lauschen“ und die Verbindung zur passenden Instanz herzustellen. Der Listener gehört allerdings nicht direkt zur Instanz, im Allgemeinen ist ein Listener auf einem System für alle vorhandenen Instanzen zuständig. Benutzerspezifische Server-Prozesse Für die einzelnen Benutzer gibt es je nach Art der Verbindung und Konfiguration entweder einen Dedicated Server-Prozess, oder der Benutzer arbeitet mit Shared Server-Prozessen. Beide Architekturvarianten haben Vor- und Nachteile, können aber pro Sitzung wahlweise benutzt werden. Die Auswahl des Dedicated oder Shared Server-Modells erfolgt beim Sitzungsaufbau. Somit kann es sowohl Dedicated als auch Shared Server-Prozesse an ein und demselben Oracle-System geben. Die Wahl der Prozessarchitektur ohne Änderung am Client-Programm ist möglich, weil alle Varianten über ihre Aufrufschnittstelle UPI das Oracle Program Interface (OPI) auf der Serverseite bedienen. Das OPI ist sowohl in den Dedicated Server-Prozessen als auch in den Dispatchern implementiert, so dass die Servervarianten vor dem Client-Programm verborgen bleiben. Bei einem Aufruf an das OPI werden
Sandini Bib
26
Die Basis-Architektur der Oracle-Datenbank
dann hauptsächlich Aktionen in den (Dedicated oder Shared) Server-Prozessen ausgelöst, je nach Typ der Aktivität werden jedoch auch die Hintergrundprozesse beschäftigt. Wichtig ist, dass es eine Initialisierung der Verbindung von Client zu Server gibt, also den Verbindungsaufbau oder CONNECT. Die dann bestehende logische Verbindung wird auch als (Benutzer-)Sitzung oder Session bezeichnet und kann mit Hilfe einer Sitzungsnummer identifiziert werden. Beim Verbindungsaufbau wird unter anderem festgelegt, ob die Sitzung einen eigenen Dedicated Server-Prozess oder einen Dispatcher zugewiesen bekommt. Bei Dedicated Server-Prozessen gibt es eine Eins-zu-eins-Zuordnung von Sitzungen zu Prozessen, d.h., sobald eine Sitzung aufgebaut wird, entsteht ein dieser Sitzung exklusiv zugeordneter Prozess. Die Sitzung ist mit dem Dedicated Server-Prozess fest verbunden. Alle Aufrufe zur Datenbankschnittstelle aus dieser Sitzung werden von diesem speziellen Prozess bearbeitet; der Prozess arbeitet andererseits ausschließlich für diese eine Sitzung. Diese Art der Zuordnung – zusammen mit der sehr guten Implementierung der Prozesssynchronisation über die SGA – führt zu einer hohen Skalierbarkeit des Oracle Server mit Prozessorleistung, d.h., durch zusätzliche Prozessorleistung ist eine fast linear ansteigende Leistung des Gesamtsystems erreichbar. Es ergibt sich jedoch ein Nachteil bei einer extrem hohen Zahl von gleichzeitigen Verbindungen: Wird die Anzahl der Prozesse zu hoch, so wird das Betriebssystem mit der Verwaltung von Prozessinformationen überlastet. Dies wirkt sich insbesondere dann aus, wenn ein großer Teil der Server-Prozesse von online-artigen Anwendungen benutzt werden. In diesem Fall ist ein Server-Prozess nur zu einem geringen Teil ausgelastet, da er den größten Teil seiner Zeit damit verbringt, auf den nächsten Aufruf zu warten. Die Steuerung der Aufrufe erfolgt dabei direkt oder indirekt von Anwendern, die naturgemäß durch Analyse der Ergebnisse, Nachdenken und andere Tätigkeiten Zeit verbringen, ohne sofort weitere Oracle-Aktivitäten auszulösen. Hier kann die Alternative zu Dedicated Server-Prozessen genutzt werden: der Shared Server. Ziel des Shared Servers ist es, die Prozesszahl auf dem Datenbankserver zu reduzieren, ohne künstliche Beschränkungen, z.B. in der Skalierbarkeit, zu schaffen. Bei diesem Prozessmodell wird eine Sitzung nicht einem Server-Prozess, sondern zunächst einem Kommunikationsserver, dem Dispatcher (Dnnn), zugeordnet. Dispatcher werden in einer konfigurierbaren Zahl gestartet; es können bei laufendem System weitere Dispatcher gestartet oder beendet werden. Die Zuordnung zu einem Dispatcher ist nach dem Verbindungsaufbau für eine Sitzung fest, wobei ein Dispatcher mehrere Verbindungen übernehmen kann. Wenn ein Client nun einen Aufruf an seinen Dispatcher schickt, so wird dieser Aufruf nicht vom Dispatcher selbst bearbeitet, sondern von diesem zunächst in einer Request Queue abgelegt. Die eigentliche Bearbeitung übernimmt dann ein beliebiger Shared Server-Prozess (Snnn). Dieser nimmt den Aufruf aus der Request Queue, bearbeitet ihn und legt das Ergebnis in einer dem Dispatcher zugeordneten Response Queue ab.
Sandini Bib
Speicher und Prozesse
27
Der Shared Server-Prozess ist der Sitzung bis auf die Abarbeitung des aktuellen Aufrufs in keiner Weise zugeordnet. Aus einer konfigurierbaren Anzahl von Shared Servern nimmt sich jeweils der nächste freie Server einen Aufruf aus der Request Queue und bearbeitet ihn. Hierdurch wird eine gleichmäßige Auslastung der Shared Server sichergestellt. Die Anzahl der Shared Server ist konfigurierbar und kann sogar online per Befehl oder durch selbständige Anpassung des Oracle Server verändert werden. Die richtige Anzahl von Shared Server-Prozessen ist von vielen Faktoren abhängig, jedoch gerade bei Systemen mit großen Benutzerzahlen in den meisten Fällen erheblich niedriger als die Anzahl der Verbindungen. Abschließend noch eine Bemerkung zum Prozessbegriff: In diesem Buch wird der Begriff Prozess im abstrakten Sinne verwendet. Er steht für eine logische Programmeinheit, die eine klar abgegrenzte Funktionalität umsetzt. Für das Betriebssystem wird vorausgesetzt, dass ein solcher Prozess unabhängig von anderen Prozessen zur Ausführung gebracht werden kann, zumindest bei Mehrprozessorsystemen auch gleichzeitig mit anderen Prozessen. Auf den verschiedenen Betriebssystemen ergibt sich manchmal eine unterschiedliche Bedeutung des Begriffs Prozess, wobei dann der abstrakte Oracle-Prozess sinnvoll auf eine Einheit des Betriebssystems abgebildet wird. Dies muss nicht immer genau ein Betriebssystemprozess sein: Zum Beispiel ist unter MS-Windows jeder abstrakte Oracle-Prozess als MS-Windows-Thread eines Dienstprozesses oder Services implementiert.
Abbildung 1.2: Prozesse
Sandini Bib
28
1.2.3
Die Basis-Architektur der Oracle-Datenbank
Instanz und Datenbank
Nun sind genug Komponenten erklärt, um einen wichtigen Begriff im Oracle Server-Umfeld einzuführen: die Oracle Instanz. Die Instanz ist ein Oberbegriff für alle Komponenten eines Oracle Server, die den aktiven Betrieb des Systems repräsentieren, d.h. für die Hintergrund- und Server-Prozesse sowie ihre Speicherstrukturen, insbesondere die SGA. Dieser Teil des Oracle Server wird bewusst vom passiven Teil des Systems, der Datenbank, unterschieden. Die Datenbank umfasst alle Dateien (Daten-, Log- und Kontrolldateien), die zum ordnungsgemäßen Funktionieren der Instanz benötigt werden. Beide Teile des Oracle Server, Datenbank und Instanz, werden eigenständig benannt, d.h., unterschiedliche Namen für Datenbank und Instanz sind möglich. Im Normalfall stehen Datenbank und Instanz in einer Eins-zu-eins-Beziehung. Der Fall der gleichzeitigen Nutzung einer einzigen Datenbank von mehreren Maschinen wird mit der Einführung des Multi-Instanz-Betriebs gelöst; dies erfordert die Parallel Server-Option. So erklärt sich, dass nicht die Datenbank hoch- oder heruntergefahren wird (da diese sich passiv verhält), sondern zunächst die Instanz, der aktive Teil! (Obwohl der Ausdruck „Datenbank hochfahren“ für praktisch alle Oracle-Kenner nach wie vor gängig, aber nicht korrekt ist). Die gestartete Instanz öffnet dann im weiteren Verlauf des Systemstarts die Datenbank. Beim Starten der Instanz können selbstverständlich für diverse Einstellungen Parameter angegeben werden, wie z.B. die SGAGröße, Anzahl und Art der Hintergrundprozesse usw. In diesem Buch werden einige, aber nicht alle Initialisierungsparameter beschrieben. Man sollte von den Initialisierungsparametern keine Wunderdinge erwarten: Sie ermöglichen in vielen Fällen die Anpassung des Systems an die Gegebenheiten des Betriebssystems und der Hardware sowie an die Anforderungen der Anwendungen. Oft wird durch die Einstellung eines Initialisierungsparameters auf einen bestimmten Wert das Verhalten des Oracle Server für eine bestimmte Aktion optimiert, für eine andere Aktion aber gerade das Gegenteil erreicht. Somit läuft die Einstellung der Initialisierungsparameter auf eine Einstellung des bestmöglichen Kompromisses für alle Anwendungsteile eines Systems hinaus.
1.3
Physische und logische Strukturen
1.3.1
Datendateien und Datenbankblöcke
Die in einem DBMS gehaltenen Daten müssen aus Gründen der Wiederherstellbarkeit permanent gespeichert werden, so dass Dateien naturgemäß eine zentrale Rolle für DBMS spielen. Die Dateien eines RDBMS dürfen aber nicht als „flache Dateien“, d.h. Dateien mit einer simplen Satzstruktur aufgebaut sein, da Änderungen, wie z.B. das Hinzufügen von Spalten an bestehende Tabellen, in der Datenstruktur im laufenden Betrieb möglich sein müssen.
Sandini Bib
Physische und logische Strukturen
29
Informationen über die Struktur der Daten (so genannte Metadaten) dürfen weiterhin nicht ausschließlich in den verarbeitenden Programmen, sondern müssen bei den Daten gespeichert werden: Dies garantiert die Offenheit der Schnittstellen und die Verwendbarkeit der Daten in unterschiedlichsten Programmen und Entwicklungsumgebungen. Auch um diese Flexibilität zu erreichen, verwendet der Oracle Server eine Blockstruktur als Grundlage für seine Dateistrukturen. Die kleinste Bearbeitungseinheit für fast alle Komponenten des Oracle Servers ist demnach ein Datenbankblock – dementsprechend wichtig ist seine Erwähnung bereits zu Anfang. Ob es sich um I/O-Problematiken, physikalische Zugriffskonflikte oder die Entscheidungsstrategien des Optimizers handelt, der Block spielt eine zentrale Rolle. Weiterhin ist zu erwähnen, dass alle Datenbankinhalte, also auch das Data Dictionary, das die Metadaten enthält, in Blockstruktur gespeichert sind. Die Größe eines Datenbankblocks ist keinesfalls a priori festgelegt; sie kann vielmehr beim Anlegen der Datenbank den Gegebenheiten (Anforderungen, Anwendung, Hardware und Betriebssystem) angepasst werden. Sie ist auf jeden Fall ein Vielfaches von 1 Kbyte, gängige Werte sind 2, 4, 8 oder 16 Kbyte. Wenn die Datenbank einmal angelegt ist, ist die Datenbankblockgröße nicht mehr änderbar und gilt – zumindest bis einschließlich Oracle8i – für die gesamte Datenbank. Ab Oracle9i können innerhalb einer Datenbank mehrere Blockgrößen verwendet werden, jedoch nicht innerhalb einer Datei. Für die Dateien des Datenbanksystems, die Daten enthalten, gilt, dass ihre Größe einem Vielfachen ihrer Blockgröße entspricht. Diese Dateien werden im folgenden als Datendateien bezeichnet. Ein Datenbankblock besteht immer aus zwei logischen Teilen: dem Kopf und dem Inhalt. Beide Teile sind variabel in der Größe, so dass möglichst keine vorgefertigten Beschränkungen wie z.B. Satzzahl pro Block vorhanden sind. Damit sich die beiden Teile beim Wachstum nicht behindern, befindet sich der Kopf am Anfang des Blocks und wächst zum Ende hin; der eigentliche Inhalt beginnt dagegen am Blockende und wächst zum Anfang hin.
.RSI 'DWHQ
'DWHQGDWHL Abbildung 1.3: Datendatei und Datenbankblock
'DWHQEDQNEORFN
Sandini Bib
30
1.3.2
Die Basis-Architektur der Oracle-Datenbank
Inhalte der Datendateien: Datenbanksegmente
Datendateien sind aus der Sicht eines Betriebssystems nicht weiter strukturiert. An dieser Stelle ist für das weitere Verständnis der Architektur lediglich von Bedeutung, dass die logischen Strukturen der Datenbank (dies sind u.a. Tabellen und Indizes) in den Datendateien als (Datenbank-)Segmente abgebildet werden. Dies bedeutet einerseits einen Wechsel der Begrifflichkeit beim Übergang der Diskussion von logischen Strukturen auf die Diskussion der physikalischen Strukturen, andererseits technisch die Möglichkeit, alle logischen Strukturen mit all ihren Unterschieden auf der Ebene der Speicherung gleich zu behandeln – eben als Segment. Zur Unterscheidung der Segmente in verschiedenen Fällen kennt der Oracle Server verschiedene Segmenttypen: TABLE, INDEX, CLUSTER usw. Zusätzlich zu diesen Benutzer- oder Datensegmenttypen sind für den Betrieb des Oracle Servers zwei weitere Segmenttypen notwendig, die im Folgenden kurz vorgestellt werden. Rollback- und Undo-Segmente Um ein Transaktionskonzept zu implementieren, benötigt man einen Speicher für Dateninhalte vor der Änderung, so genannte Before Image-Informationen. Das Transaktionskonzept erlaubt, eine Reihe von Änderungen als Transaktionseinheit entweder zu bestätigen (COMMIT) oder, etwa im Fehlerfall, wieder zurückzunehmen (ROLLBACK). In der Oracle-Architektur werden die Before Image-Informationen nicht in separaten Dateistrukturen verwaltet, sondern als eigenständiger Segmenttyp innerhalb der Datendateien untergebracht. Diese speziellen Segmente heißen Rollback-Segmente bzw. – in einer optional konfigurierbaren Variante ab Oracle9i – Undo-Segmente. Im weiteren Verlauf dieses Kapitels wird der Begriff Rollback-Segment stellvertretend für beide Varianten verwendet. Durch die Verwaltung der Before Image-Informationen innerhalb der Datendateien stehen auch für die Rollback- und Undo-Segmente die gleichen Zugriffsalgorithmen wie für Datensegmente zur Verfügung, so dass die Strukturen sehr effizient auch für andere Funktionen eingesetzt werden können, beispielsweise zur Realisierung der Lesekonsistenz. Dies wird im Verlauf dieses Kapitels noch detailliert behandelt. Temporärsegmente In einem DBMS fallen immer wieder Sortieroperationen oder damit verwandte Operationen wie Gruppierungen an. Diese Operationen benötigen Speicherplatz für Zwischenergebnisse und das Endergebnis. Man bezeichnet diesen Speicher als Temporärspeicher. Falls nur eine kleine Menge an Temporärspeicherplatz benötigt wird, wird im Oracle Server eine Sort Area benutzt. Diese befindet sich im Hauptspeicher des Datenbanksystems. Werden allerdings größere Mengen Speicherplatz angefordert, so wird automatisch auf Temporärsegmente ausgewichen, d.h., es wird ein spezielles Segment in der Datenbank allokiert, das Zwischenergebnisse und das Endergebnis aufnimmt.
Sandini Bib
Physische und logische Strukturen
31
Im Unterschied zu allen anderen Segmenttypen werden Temporärsegmente immer implizit angelegt und können nicht explizit angesprochen oder ausgelesen werden. Nach erfolgreicher Durchführung der Sortierung oder Gruppierung werden Temporärsegmente wieder freigegeben.
1.3.3
Weitere Dateien
Neben den Datendateien existieren in einer Oracle-Datenbank noch weitere Dateien, denen spezielle Aufgaben zugeordnet sind. Die folgenden Unterabschnitte beschreiben diese Dateitypen. Redolog-Dateien und Redolog-Gruppen Die Redolog-Dateien enthalten ein physikalisches Transaktionsprotokoll. (Dies ist nicht zu verwechseln mit einem logischen Transaktionsprotokoll, das eine Sequenz von SQL-Kommandos enthalten würde.) Alle Änderungen an Datenbankblöcken werden hier protokolliert. Die Protokollierung hat den einfachen Sinn, dass in einem Fehlerfall die logischen Änderungen an der Datenbank durch das nochmalige Durchführen der Blockänderungen wiederhergestellt werden können. Die Eigenschaft der Wiederherstellbarkeit ist eine rudimentäre Anforderung an ein DBMS – ohne sie wäre ein produktiver Einsatz nicht möglich. Eine Oracle-Datenbank kennt zwei Typen von Redolog-Dateien: die vom RDBMS ständig zyklisch beschriebenen Online-Redolog-Dateien sowie die Offline- oder archivierten Redolog-Dateien, die optional (im so genannten Archivelog-Modus) nach dem Schließen von Online-Redolog-Dateien als eine chronologische Folge von durchnummerierten Redolog-Kopien entstehen. Der Oracle Server bietet die Möglichkeit, Redolog-Dateien zu spiegeln. Hierzu werden die Begriffe Redolog-Gruppe und Redolog-Member benötigt. Eine RedologGruppe besteht aus einer oder mehreren Redolog-Dateien, die die gleiche Größe und den gleichen Inhalt haben. Eine einzelne Datei einer Redolog-Gruppe wird als Redolog-Member der Redolog-Gruppe bezeichnet. An einer Oracle-Datenbank befinden sich immer mindestens zwei Redolog-Gruppen mit mindestens einem Redolog-Member (d.h. zwei ungespiegelte Redolog-Gruppen). Die Anzahl der Redolog-Gruppen kann mehr als zwei betragen, die maximale Anzahl ist nicht durch Oracle begrenzt. Kontrolldateien Eine zentrale Aufgabe haben die Kontrolldateien: Sie enthalten neben einigen Zeitstempeln und Konsistenzinformationen die physikalische Struktur der OracleDatenbank, d.h. die Namen und Größen aller Daten- und Online-Redolog-Dateien. Für eine Datenbank gibt es zu jedem Zeitpunkt genau eine gültige Version der Kontrolldatei; diese kann gespiegelt betrieben werden. Die Kontrolldatei übernimmt eine zentrale Rolle bei der Wiederherstellung der Datenbank im Fehlerfall.
Sandini Bib
32
Die Basis-Architektur der Oracle-Datenbank
5HGRORJ 0HPEHU PLW JOHLFKHP ,QKDOW XQG JOHLFKHU *U|H DEHU XQWHU VFKLHGOLFKHP ,QKDOW XQG HYWO XQWHUVFKLHGOLFKHU *U|H ]X GHQ 5HGRORJ0HPEHUQ YRQ 5HGO/RJ *UXSSH
5HGRORJ 0HPEHU PLW JOHLFKHP ,QKDOW XQG JOHLFKHU *U|H
5HGRORJ*UXSSH
5HGRORJ*UXSSH
Abbildung 1.4: Redolog-Gruppen und Redolog-Member
Initialisierungsparameter- oder init.ora-Dateien In den meisten Fällen gibt es zusätzlich zu den bisher erwähnten Dateien eine spezielle Datei, die Initialisierungsparameter für das Oracle-System enthält: die so genannte init.ora-Datei. Hier wird beim Systemstart die Konfiguration und das Verhalten der Instanz bestimmt. Unter anderem enthält die init.ora-Datei den oder die Namen der Kontrolldateien. Zum Begriff init.ora-Datei sind zwei Anmerkungen zu machen: 1. Der tatsächliche Name der Parameterdatei ist in den meisten Fällen anders als init.ora. Meist ist der Name der Oracle-Instanz (zum Begriff der Instanz siehe weiter oben) enthalten, wie in initORCL.ora; er kann aber auch frei gewählt werden. 2. Die Start- oder Initialisierungsparameter einer Oracle-Instanz heißen in der OracleAnwendergemeinde „init.ora-Parameter“, da sie traditionell in der „init.oraDatei“ gespeichert werden. Da die Speicherung der Parameter in der init.oraDatei nur noch eine von vielen Möglichkeiten ist, wird in diesem Buch die Bezeichnung Initialisierungsparameter vorgezogen. Serverparameterdateien (SPFILEs) Die Konfiguration einer Instanz über Initialisierungsparameterdateien ist problematisch, wenn Start- und Stoppvorgänge in einer verteilten Rechnerumgebung vorgenommen werden. Das liegt daran, dass das Werkzeug, das den STARTUP-Befehl ausführt, die Initialisierungsparameterdatei liest. Da die Datei jedoch normalerweise auf dem Server gespeichert ist, muss diese vom Client entweder über das Netzwerk gelesen werden oder eine Kopie auf dem Client existieren. Beide Möglichkeiten sind fehleranfällig.
Sandini Bib
Kommunikation
33
Mit Oracle9i besteht die Möglichkeit, alternativ zur Initialisierungsparameterdatei eine Serverparameterdatei zu nutzen. Diese wird in einem Binärformat auf dem Server gespeichert und kann aus einer bestehenden Initialisierungsparameterdatei erzeugt werden. Falls eine Serverparameterdatei existiert, wird diese anstelle der Initialisierungsparameterdatei zur Konfiguration beim Instanzstart benutzt. Der Inhalt der Serverparameterdatei wird mit Hilfe von ALTER SYSTEM-Befehlen modifiziert.
1.4
Kommunikation
Alle Programme und Module, die sich mit Kommunikation (Client-Server-Kommunikation, Server-Server-Kommunikation, ...) beschäftigen, sind unter dem Begriff Oracle Net zusammengefasst. Hierbei ist es wichtig, festzuhalten, dass jedes für den Zugriff auf eine OracleDatenbank geschriebene Programm bei Bedarf ein Client-Server-Programm sein kann. Diese Eigenschaft wird lediglich konfiguriert und nicht etwa programmiert! Die Kommunikationskomponente des Oracle-Systems heißt ab Oracle9i Oracle Net, bis Oracle7 war das SQL*Net, ab Oracle8 dann Oracle Net8. Die bestehende Kommunikationsarchitektur wurde mit Oracle7 bzw. SQL*Net Version 2 eingeführt. Hierbei wurde eine komplette Mehrschichtarchitektur nach ISO/OSI-Vorgaben als Oracle-eigener Stack implementiert, der nach oben mit den Oracle-Programmierschnittstellen und nach unten mit vorhandenen Netzwerkprotokollen, etwa TCP/ IP oder LU6.2, kommunizieren kann. Der damals notwendige Bruch mit der SQL*Net Version 1-Architektur löst bei den Anwendern immer wieder Bedenken bezüglich der Interoperabilität verschiedener Client- und Serverversionen aus – mittlerweile jedoch eher unbegründet. Oracle7Clients werden bis zu Oracle9i unterstützt, Oracle8-Clients bis mindestens Oracle9i Release 2. Das bedeutet u.a. einen Investitionsschutz für eingekaufte Software, die mit einer bestimmten Clientversion zusammenarbeitet. Neben dem reinen Basisdienst für Client-Server-Anwendungen stellt Oracle Net u.a. Firewall-Funktionen, Bündelung von mehreren logischen Sitzungen in eine Netzwerkverbindung u.v.m. zur Verfügung. Zur Darstellung der Funktionen sowie der Funktionsweise von Oracle Net siehe Kapitel 5.
1.5
National Language Support
Diverse Funktionen, die sich mit den Eigenheiten unterschiedlicher Länder und Kontinente beschäftigen, sind in der Oracle-Architektur als National Language Support (NLS) zusammengefasst. Die Funktionen reichen von der Darstellung von Ausgabetext und Fehlermeldungen in verschiedenen Sprachen über Formatvarianten bei Zahlen und Datumsdarstellung bis hin zur Verwendung unterschiedlicher Zeichensätze und deren automatischer Konvertierung.
Sandini Bib
34
Die Basis-Architektur der Oracle-Datenbank
Die Beachtung des NLS ist deshalb wichtig, da einerseits bei der Anwendungsentwicklung darauf geachtet werden muss, dass Module, die sich mit Datums- oder Zeitberechnungen befassen, immer im gleichen Kontext arbeiten, d.h., für solche Module müssen interne NLS-Einstellungen vorgegeben werden. Extrem wichtig für den Einsatz des Oracle Server ist das Verständnis der Behandlung von Zeichensätzen, da bei fehlerhaften Einstellungen Sonderzeichen und Umlaute verloren gehen können.
1.5.1
Sprache und Gebiet
Jeder Oracle-Client kann angeben, in welcher Sprache er Informationen vom Server bekommen möchte. Gerade bei Fehlermeldungen ist diese Einstellung wichtig, um die Verständlichkeit der Meldungen zu garantieren. Neben dem Server reagieren auch einige Oracle-Client-Programme auf die gewählte Sprache: Zum Beispiel sind die Ausgabetexte von SQL*Plus auch in anderen Sprachen als Englisch verfügbar, wie folgendes Beispiel zeigt: SQL> SELECT * FROM x; select * from x * ERROR at line 1: ORA-00942: table or view does not exist
SQL> ALTER SESSION SET NLS_LANGUAGE = Dutch; Sessie is gewijzigd. SQL> SELECT * FROM x; SELECT * FROM x * FOUT in regel 1: ORA-00942: Tabel of view bestaat niet.
Außer der Sprache ist auch das Gebiet eine wichtige Einstellung: In Amerika ist der erste Tag der Woche der Sonntag, in Deutschland ist es der Montag. Somit ist die Ausgabe von Datumskonvertierfunktionen abhängig von der Gebietseinstellung.
1.5.2
Zahlen- und Datumsformate
Werden Sprache und Gebiet eingestellt, so werden diverse Standardformate für Zahlen und Daten automatisch miteingestellt. Wichtige Unterschiede zum amerikanischen Standardformat sind die Verwendung von Komma und Punkt in der Zahlendarstellung (die Zahl „eintausend und drei Zehntel“ wird in Amerika „1,000.3“, in Deutschland „1.000,3“ geschrieben) und die Standarddatumsformate (Amerika: 01-JAN-02, Deutschland: 01.01.02).
Sandini Bib
National Language Support
35
Die Standarddatumsformate führen die Jahreszahl immer zweistellig. Das Format kann jedoch leicht auf eine vierstellige Jahreszahl geändert werden. Ebenso wichtig ist die Information, dass die Speicherung von Daten intern immer mit einer vierstelligen Jahreszahl erfolgt.
1.5.3
Zeichensätze
In heterogenen Rechnerumgebungen wird mit einer Vielzahl von Zeichensätzen gearbeitet. Ein Zeichensatz ist eine Tabelle, in der z.B. für einen 8-Bit-Zeichensatz den 256 möglichen Werten Buchstaben, Ziffern, Sonderzeichen und Umlaute zugeordnet sind. Problematisch hieran ist, dass die meisten Zeichensätze sich zwar im Bereich von 0...127 an die Vorgabe des ASCII-Zeichensatzes halten, Umlaute aber verschieden behandeln. Zum Beispiel hat der Umlaut „Ä“ im ISO-Latin-l-Zeichensatz den Wert 142, im 8-Bit-DOS-Zeichensatz den Wert 196. Um die Kommunikation zwischen verschiedenen Endgeräten transparent zu ermöglichen, kann die Oracle-Software mit verschiedenen Zeichensätzen umgehen. Um eine definierte Basis zu haben, werden für jede Datenbank zwei Zeichensätze, ein Basiszeichensatz sowie ein weiterer so genannter nationaler Zeichensatz, festgelegt. Alle Zeichen des Basistyps CHAR werden im Datenbankzeichensatz, die des Basistyps NCHAR im nationalen Zeichensatz gespeichert. Zum Basistyp CHAR gehören Zeichenketten fester Länge (CHAR), variabel lange Zeichenketten (VARCHAR2), lange Zeichenketten (LONG) sowie Character LOBs (CLOB). Diese Datentypen gibt es – außer LONG – nochmals zum Basistyp NCHAR (NCHAR, NVARCHAR2, NCLOB) sowie als reine Binärtypen RAW, VARRAW, LONG RAW und BLOB. Jeder Client gibt nun beim Verbindungsaufbau seinen Zeichensatz bekannt, so dass im Bedarfsfall zwischen den Zeichensätzen konvertiert werden kann. Falls also die Datenbank im ISO8859-Latin-1-Zeichensatz arbeitet und ein DOS-Client eine Abfrage ausführt, so wird ein „Ä“, das in der Datenbank mit dem Wert 142 gefunden wird, an den Client als 196 weitergegeben, so dass dieser eine richtige Ausgabe produzieren kann. Besonders wichtig ist, dass für die Datenbank ein Basiszeichensatz gewählt wird, in dem alle oft benötigten Zeichen vorkommen. Der Standardzeichensatz US7ASCII (7-Bit-ASCII) enthält z.B. keine Umlaute und kann somit in deutschsprachigen Umgebungen nur eingeschränkt genutzt werden.
Sandini Bib
36
Die Basis-Architektur der Oracle-Datenbank
1/6B/$1*
1/6B&+$5$&7(56(7
$PHULFDQB*HUPDQ\:(,623
:(3&
&OLHQW3UR]HVV
6HUYHU3UR]HVV
Abbildung 1.5: Zeichensatzkonvertierung
Unicode Für internationale Anwendungen wird die Unterstützung von Unicode-Zeichensätzen immer wichtiger. Unicode ist ein standardisierter Multibyte-Zeichensatz, der u.a. europäische, asiatische und fernöstliche Zeichen enthält. Somit ist es möglich, Daten aus verschiedensten Regionen der Welt zusammen zu verarbeiten. Auch hier arbeiten die Normierungsgremien immer weiter, so dass mit Oracle8i (Release 8.1.7) der Unicode Version 1.1-Zeichensatz AL24UTFFSS sowie die Unicode Version 2.1-Zeichensätze UTF8 und UTFE, letzterer als EBCDIC-Zeichensatz für Mainframes, unterstützt werden; bei Oracle9i ausschließlich die Unicode Version 3.0-Zeichensätze AL16UTF16 (feste Länge), AL32UTF8, UTF8 und UTFE, wobei die letzen beiden offensichtlich unverändert sind. Die meisten Unicode-Zeichensätze sind variabel lang, d.h., häufig benutzte Zeichen, wie jene aus dem ASCII-Bereich, haben eine kurze Darstellung, selten benutzte Zeichen eine längere. Unicode-Zeichensätz können sowohl als Basiszeichensatz einer Datenbank als auch als nationaler Zeichensatz eingestellt werden; ab Oracle9i sind jedoch für den nationalen Zeichensatz ausschließlich Unicode-Zeichensätze erlaubt.2 Ein aktuelles Thema bei Zeichensätzen ist das Euro-Symbol (€) für die im Januar 2002 eingeführte neue Währung in den Euro-Nationen. Alle Unicode-Zeichensätze von Oracle9i enthalten das Euro-Symbol. Der ISO8859-Latin-1-Zeichensatz (OracleBezeichnung WE8ISO8859P1) enthält das Euro-Symbol jedoch z.B. nicht; hierfür gibt es eigens einen neuen ISO8859-Latin-15-Zeichensatz (WE8ISO8859P15). Dies 2.
Da der einzige sowohl für Oracle8i als auch für Oracle9i unterstützte Unicode-Zeichensatz für Nicht-Mainframe-Systeme UTF8 ist, empfiehlt sich dieser als nationaler Zeichensatz für Oracle8i-Systeme. Dies ist die einzige Möglichkeit, transportable Tablespaces zwischen Oracle8i und Oracle9i zu nutzen!
Sandini Bib
Sicherheitsstrukturen
37
ist oft nicht von Bedeutung, wenn z.B. Währungssymbole nicht in der Datenbank gespeichert werden; in einigen Umgebungen muss es jedoch bedacht werden. Zu erwähnen ist noch der Zeichensatz WE8MSWIN1252, der von MS-Windows benutzt wird (und u.a. das Euro-Symbol beinhaltet). Dieser wird bei Installationen unter MS-Windows ab Oracle9i standardmäßig in der Registrierung eingestellt, vorher war das WE8ISO8859P1. Byte- und Character-Semantik Bei Ein-Byte-Zeichensätzen ist von vorneherein klar, was in eine Spalte des Typs VARCHAR2(10) hineinpasst: zehn Zeichen. Das stimmt nicht mehr für MultibyteZeichensätze wie Unicode: Es passen nämlich Zeichenketten mit einer Maximallänge von 10 Bytes hinein – und das sind nur noch fünf Zeichen oder sogar weniger! Da Datenbankdesigns jedoch eher mit der Länge von Zeichenketten in Zeichen und nicht mit der Länge von deren Repräsentierung in Bytes erstellt werden, ist es u.U. ratsam, beim Datentyp genau zu spezifizieren: VARCHAR2(10 BYTE) bedeutet Maximallänge 10 Bytes, VARCHAR2(10 CHAR) 10 Zeichen. Die NCHAR-Datentypen unterliegen grundsätzlich der Character-Semantik, CHARDatentypen der Byte-Semantik.
1.6
Sicherheitsstrukturen
Die Oracle-Datenbank wird oft als strukturierter unkontrollierter Datenspeicher genutzt. Hiermit ist gemeint, dass die Strukturen und Zugriffe im Rahmen des Datenbank- und Anwendungsdesigns entworfen und programmiert worden sind; über Sicherheit in jeglicher Form macht sich jedoch niemand Gedanken. Das hat oft zur Folge, dass es einen Datenbankbenutzer gibt, dem sämtliche Datenbankobjekte zu einer bestimmten Anwendung gehören. Der Einfachheit halber nennt man diesen Benutzer XYZ, wenn die Anwendung ebenfalls XYZ heißt. Damit ist das Passwort für den Benutzer XYZ auch schon ausgedacht: XYZ. Da dies so schön einfach in Login-Makros zu implementieren ist, melden sich auch alle Benutzer der Anwendung mit diesem Benutzer an der Datenbank an. Dieses Szenario funktioniert so lange, bis der erste Benutzer mit Basis-Programmierkenntnissen aus Versehen den kompletten Auftragsbestand mit Hilfe einer selbstgeschriebenen MS-Access-Routine löscht. Und plötzlich ist es interessant, dass die Oracle-Datenbank selber kontrollieren kann, wer welche Aktionen auf den Daten ausführen darf, wer überhaupt was sehen darf und dass bestimmte Aktionen sogar protokolliert werden können. Alle Sicherheitsfunktionen basieren zunächst auf der Identifikation eines Benutzers, in den meisten Fällen authentifiziert durch die Überprüfung eines Passworts durch die Datenbank selbst. Dies impliziert, dass das Passwort im Data Dictionary der Datenbank – natürlich verschlüsselt – gespeichert ist.
Sandini Bib
38
Die Basis-Architektur der Oracle-Datenbank
In größeren Umgebungen ist es durchaus sinnvoll, Benutzernamen und Passworte nicht in jedem System einzeln zu pflegen, sondern zentral zu verwalten. Diese Funktion wird neben anderen Funktionen durch so genannte Verzeichnisdienste abgedeckt, die sich am Markt für diesen Zweck langsam durchzusetzen scheinen. Verzeichnisdienste werden oft auch als LDAP-Dienste bezeichnet, wobei LDAP für Lightweight Directory Access Protocol steht. LDAP ist jedoch lediglich das Zugriffsprotokoll für einen Verzeichnisdienst. Oracle bietet mit dem Oracle Internet Directory einen eigenen Verzeichnisdienst an, der z.B. für die Verwaltung von Oracle-Benutzern genutzt werden kann. Da LDAP-basierte Verzeichnisdienste standardisiert sind, stehen auch andere Verzeichnisdienste hierfür zur Auswahl, etwa Active Directory von Microsoft. Datenbankbenutzer, ob innerhalb der Datenbank oder extern authentifiziert, können Rechte oder Privilegien innerhalb der Datenbank erhalten, die zunächst in System- und Objektprivilegien unterteilt werden. Systemprivilegien erlauben bestimmte Aktionen, wie z.B. CREATE TABLE, das Anlegen einer Tabelle, oder CREATE SESSION, das Anmelden an die Datenbank. Bei den Objektprivilegien können Aktionen für bestimmte Objekte erlaubt werden, z.B. SELECT für eine Tabelle oder UPDATE für bestimmte Spalten einer Tabelle. Auch bei wenig komplexen Anwendungen zeigt sich schnell, dass sowohl Entwickler als auch Anwender über eine große Menge von Privilegien verfügen müssen, um z.B. mit einem bestimmten Modul einer Anwendung arbeiten zu können. Entwickler haben dabei eher eine große Menge von Systemprivilegien wie CREATE TABLE, CREATE PROCEDURE, CREATE TRIGGER usw., bei Anwendern genügt oft das Systemprivileg CREATE SESSION. Dafür besitzen Anwender eine große Menge von Objektprivilegien. Um die Arbeit mit umfangreichen Privilegien zu erleichtern, gibt es in der Oracle-Datenbank das Rollenkonzept. In einer Rolle können sowohl System- und Objektprivilegien als auch weitere Rollen enthalten sein. Hiermit ist es dem DBA möglich, für einzelne Anwendungen bzw. Module Rollen zu erstellen, die einem Anwender als Einheit zugeteilt oder auch weggenommen werden können. Um nur Teile einer Tabelle für andere Benutzer sichtbar zu machen bieten sich Views an. Hiermit können Teile der Tabelle vertikal (nicht alle Spalten der Tabelle werden in der SELECT-Liste der View angegeben) oder horizontal (Filtern eines Teils der Datensätze durch eine WHERE-Klausel) ausgeblendet werden. Eine solche View kann nun mittels Objektprivilegien wie SELECT, INSERT, UPDATE, DELETE anderen Benutzern zur Verfügung gestellt werden. Diese können mit der View arbeiten, ohne dafür die entsprechenden Privilegien für die Basistabelle zu benötigen. Dieses Konzept hat Oracle mit der Virtual Private Database (VPD) noch weiterentwickelt und in den Datenbankkern integriert, so dass auch Hierarchien abgebildet werden können. Z.B. können alle Verkäufer in einer Umsatztabelle ausschließlich die Umsätze sehen, die sie mit ihren Kunden getätigt haben; Gruppenleiter sehen jedoch zusätzlich alle Umsätze der Gruppe.
Sandini Bib
Transaktionen, Sperren und Lesekonsistenz
39
Ein weiterer Bereich im Sicherheitsumfeld ist das Auditing. Hiermit können Aktionen, die Gebrauch von bestimmten Privilegien machen, protokolliert werden. Diese Funktion ist vergleichbar mit der Ereignisanzeige von MS-Windows. Auditing kann z.B. dazu genutzt werden, wiederholte Versuche zum Erraten von Passwörtern zu erkennen, indem das Ereignis CREATE SESSION protokolliert wird, wenn es nicht erfolgreich ist. Andere Möglichkeiten ergeben sich dadurch, dass man Zugriffe auf bestimmte Tabellen pro Sitzung protokolliert, so dass man das eingeführte Sicherheits- und Rollenkonzept überprüfen kann. Zusätzlich zu dieser kurzen Darstellung einiger Sicherheitsfunktionen in der OracleDatenbank ist dem umfangreichen Thema Sicherheit ein eigenes Kapitel, Kapitel 4, gewidmet.
1.7
Transaktionen, Sperren und Lesekonsistenz
Transaktionen, Sperren und Lesekonsistenz sind Mechanismen, die im Hintergrund der Oracle-Datenbank stattfinden. Sie sind so implementiert, dass ein möglichst reibungsloser Datenbankbetrieb für viele gleichzeitig arbeitende Benutzer sichergestellt wird. Bei der Entwicklung von Datenbankanwendungen ist es ratsam, sich mit diesen Dingen vertraut zu machen, da andernfalls beim Übergang von der EinbenutzerEntwicklungsumgebung zum Mehrbenutzerbetrieb im produktiven Einsatz manche böse Überraschung lauern kann.
1.7.1
Transaktionen
Einer der ganz großen Unterschiede zwischen einem Datenbankmanagementsystem wie Oracle und flachen Dateisystemen oder einfachen Datenbanken wie MS-Access ist die Möglichkeit der Transaktionsverarbeitung, und zwar transparent und automatisch. Eine Transaktion ist dabei wie folgt zu charakterisieren:
: :
Eine Transaktion besteht aus einer Folge von Kommandos, die den Inhalt der Datenbank manipulieren. Das Datenbankmanagementsystem garantiert, dass bei erfolgreichem Transaktionsabschluss (COMMIT) alle Änderungen wiederherstellbar in die Datenbank integriert sind, oder bei einem Fehler bzw. nicht erfolgreichem Abschluss (ROLLBACK) keine der Änderungen in die Datenbank gelangt. Hierzu kann als einfaches Beispiel eine Überweisung in einer konten-Tabelle dienen: Ein UPDATE-Befehl zieht einen Betrag x vom Kontostand des Kontos A ab, ein weiterer UPDATE-Befehl addiert den Betrag auf den Kontostand des Kontos B. Hierbei sollte der Alles-oder-Nichts-Ansatz der Transaktionsverarbeitung schnell klar werden.
Sandini Bib
40
:
Die Basis-Architektur der Oracle-Datenbank
Die Transaktions-Lesekonsistenz garantiert zusätzlich, dass andere Sitzungen die Auswirkungen einer Transaktion erst nach deren Bestätigung mit COMMIT sehen können. In der Zwischenzeit verhalten sich alle Operationen so, als habe die Transaktion nicht stattgefunden.
Alle DML- und DDL-Befehle finden in der Oracle-Datenbank im Rahmen von Transaktionen statt; es gibt keine Möglichkeit, das Transaktionsverhalten „auszuschalten“. Autonome Transaktionen Innerhalb der Programmiersprache PL/SQL gibt es die Möglichkeit, einzelne Programmblöcke oder Module als autonome Transaktion zu kennzeichnen. Damit verhalten diese sich als geschachtelte Transaktion, d.h., die autonome Transaktion kann mit COMMIT bestätigt werden, während die übergeordnete zurückgerollt wird. Dies ermöglicht Funktionen wie eine Fehlerprotokollierung als INSERT-Befehle in eine Fehlertabelle, die robust funktioniert. Ohne die autonome Transaktion würde im Fall eines ROLLBACK der übergeordneten Transaktion auch der Eintrag in die Fehlertabelle wieder entfernt.
1.7.2
Sperren
Sperren (engl. locks) werden zur Transaktionssicherung eingesetzt, und zwar ebenso automatisch wie die Transaktionen. Es gibt grundsätzlich zwei verschiedene Arten von Sperren, DML- und DDL-Sperren. DML-Sperren beschützen die Daten selbst, DDL-Sperren Objektdefinitionen (Tabellen, Indizes usw.) im Data Dictionary. Sperren können wiederum verschiedene Typen haben, z.B. kann eine DML-Sperre auf einer Tabelle Row-Exclusive- oder Share-Modus haben. Sperren verschiedener Modi können wiederum kompatibel oder inkompatibel sein; z.B. ist eine Share-Modus DDL-Sperre auf einer Tabelle inkompatibel mit einer Row-Exclusive-Modus DMLSperre auf der gleichen Tabelle. Kompatible Sperren können gleichzeitig von verschiedenen Sitzungen gehalten werden; inkompatible Sperren führen zu Wartezuständen. Übersetzt in Operationen heißt das z.B., dass ein CREATE INDEX-Befehl, der eine Share-Modus DDL-Sperre auf der zugrunde liegenden Tabelle benötigt, nicht gleichzeitig mit einem UPDATE auf der gleichen Tabelle laufen kann, das eine DML-Sperre im Row-Exclusive-Modus erzeugt. Bis auf wenige Ausnahmen sind DML- und DDL-Sperren nicht kompatibel. Mit anderen Worten heißt das, dass Änderungen im physischen Datenmodell nur dann durchgeführt werden können, wenn keine Anwendungen die Tabelle gleichzeitig modifizieren, und umgekehrt. In neueren Versionen versucht Oracle, nach und nach DDL-Befehle so umzubauen oder zu ergänzen, dass sie keine Share-Modus DDL-Sperren mehr benötigen. Z.B. hat der Befehl ALTER INDEX
REBUILD ...
Sandini Bib
Transaktionen, Sperren und Lesekonsistenz
41
ab Oracle8i die Option ONLINE, mit deren Hilfe man einen Index auch bei laufenden Anwendungen defragmentieren kann. Da es hier jedoch noch viel für die Oracle-Entwickler zu tun gibt, können wir zunächst davon ausgehen, dass auf einer Tabelle entweder nur DDL- oder nur DML-Befehle laufen. In beiden Fällen können mehrere gleichartige Operationen gleichzeitig laufen, z.B. können mehrere Indizes für eine Tabelle aus mehreren Sitzungen gleichzeitig erstellt werden. DDL-Sperren DDL-Sperren befinden sich entweder im Share-Modus (z.B. bei CREATE INDEXoder AUDIT-Befehlen), im Exclusive-Modus (z.B. bei DROP TABLE) oder sind Breakable Parse Locks. Im Share- oder Exclusive-Modus lassen sie keine gleichzeitigen DML-Sperren zu; als Breakable Parse Locks tauchen sie im Shared Pool gerade bei DML-Befehlen auf. Sie erlauben die Rückverfolgung von SQL-Befehlen im Shared Pool, um diese bei Änderungen der Struktur, z.B. durch ALTER TABLE, als INVALID zu markieren und bei wiederholter Ausführung eine Neuübersetzung zu erzwingen. Sperren im Share-Modus verhalten sich kompatibel zu weiteren Sperren im ShareModus; der Exclusive-Modus ist nur für eine einzige Sperre erlaubt. DML-Sperren Eine Besonderheit der Oracle-Datenbank ist sicherlich die Behandlung von Datensatzsperren. Hierfür ist, wie bereits weiter oben erwähnt, der Row-Exclusive-Modus der DML-Sperre zuständig. Dieser Modus ist grundsätzlich automatisch von der Oracle-Datenbank eingestellt, sobald DML-Befehle benutzt werden. Hierbei wird eine Sperre pro Datensatz erstellt, sobald dieser vom DML-Befehl bearbeitet wird. Da die eigentliche Datensatzsperre an einer dafür vorgesehenen Stelle im Row Directory des Datenbankblocks geführt wird, gibt es keinerlei Einschränkung der erlaubten Datensatzsperren pro Transaktion, pro Sitzung oder pro Datenbank. Daher sind Verfahren wie Lock Escalation, bei denen Datensatzsperren in Blocksperren umgewandelt werden, sobald eine bestimmte Anzahl von Datensätzen gesperrt werden soll, in der Oracle-Datenbank nicht notwendig – und daher auch nicht implementiert. Die Datensatzsperre ist grundsätzlich eine sehr gut geeignete Einheit für Sperrverfahren, da für viele Anwendungen hiermit sinnvolles Arbeiten mit mehreren Benutzern möglich ist. Dies bedeutet im Übrigen nicht, dass die Verwaltung der Datensatzsperren keinen Aufwand für die Datenbank bedeutet. Falls man z.B. große Mengen von DML-Befehlen als Batch zu verarbeiten hat und gleichzeitig keine weiteren Operationen laufen, lohnt sich die Anforderung einer ExclusiveModus DML-Sperre mit dem Befehl LOCK TABLE IN EXCLUSIVE MODE;
Oft lassen sich Laufzeiten hiermit um etwa die Hälfte (!) reduzieren.
Sandini Bib
42
Die Basis-Architektur der Oracle-Datenbank
Weiterhin existieren für DML-Sperren die Modi Row Share (für SELECT ... FOR UPDATE), Share und Share Row Exclusive. Letztere sind aus Kompatibilitätsgründen zu früheren Oracle Versionen (es handelt sich hier um Version 5!) vorhanden und sollten i.A. nicht eingesetzt werden. Alle Modi können mit LOCK TABLEBefehlen explizit angefordert werden. Deadlocks Mit einem Deadlock ist eine Situation gemeint, in der mehrere Sitzungen zyklisch aufeinander warten. Hierzu ein Beispiel mit zwei Sitzungen, die Datensätze einer Tabelle test bearbeiten, deren Datensätze durch die Primärschlüsselspalte x eindeutig bestimmt sind. Sitzung 1
Sitzung 2
UPDATE test SET c='AAA' WHERE x=1; o.k. UPDATE test SET c='AAA' WHERE x=2; o.k. UPDATE test SET c='AAA' WHERE x=2; Wartet UPDATE test SET c='AAA' WHERE x=1; wartet ORA-00060: deadlock detected while waiting for resource
o.k.
Tabelle 1.2: Deadlock
In der Praxis kommen Deadlocks eher dann vor, wenn sich Entwickler verschiedener Module einer Anwendung nicht darüber einig sind, in welcher Reihenfolge Datensätze grundsätzlich zu sperren sind, wenn sie aus verschiedenen Tabellen kommen. Z.B. sollte bei Tabellen, die über einen Fremdschlüssel verknüpft sind, immer zuerst die Master-Tabelle, dann die Detail-Tabelle gesperrt werden.
1.7.3
Lesekonsistenz
Als äußerst wichtige Eigenschaft der SQL-Verarbeitung in der Oracle-Datenbank gilt, dass lesende Befehle (SELECT) keinerlei DML-Sperren verursachen. Damit ist die Lauffähigkeit von Berichten parallel zur Transaktionsverarbeitung grundsätzlich sichergestellt. Neben dem Lesekonsistenz-Grundsatz bei der Transaktionsverarbeitung, der besagt, dass keine Änderungen einer Transaktion von anderen Sitzungen gesehen werden, wenn die Transaktion noch nicht beendet ist, gibt es in diesem Zusammenhang jedoch eine weitere Lesekonsistenz-Eigenschaft. Diese besagt, dass keine
Sandini Bib
Transaktionen, Sperren und Lesekonsistenz
43
Änderungen bei der Abarbeitung eines SQL-Befehls gesehen werden, die beim Start der Verarbeitung noch nicht durch COMMIT bestätigt sind. Hierdurch wird sichergestellt, dass das Ergebnis einer Abfrage immer korrekt ist, auch wenn es sich auf einen Zeitpunkt in der Vergangenheit bezieht. Würde die Lesekonsistenz in dieser Form nicht eingehalten werden, so würden dadurch falsche Ergebnisse möglich, eben weil beim SELECT keine Sperren ausgelöst werden. Isolation Level Das Setzen des Lesekonsistenzzeitpunkts auf den Anfang einer Abfrage hat zur Folge, dass eine Abfrage, die mehr als einmal innerhalb einer Transaktion ausgeführt wird, unter Umständen bei jeder Ausführung ein anderes Ergebnis liefert. Für die Transaktionsverarbeitung von Datenbanken sind von den Standardisierungsgremien Isolation Level definiert worden. Der eben beschriebene wird dabei als Read Committed bezeichnet. Es besteht die Möglichkeit, dass eine Anwendung hiermit nicht ausreichend geschützt ist. Hierfür ist der Isolation Level Serializable vorgesehen. Dieser erlaubt einer Transaktion, immer nur die Änderungen zu sehen, die bereits bei Transaktionsanfang bestätigt waren (und natürlich die eigenen Änderungen). Mehrfach ausgeführte Abfragen innerhalb der Transaktion garantieren hiermit stets das gleiche Ergebnis, es sei denn, die eigene Transaktion hat die Daten modifiziert. Sobald die Transaktion versucht, Datensätze zu bearbeiten, die von anderen Transaktionen seit dem Transaktionsanfang bereits bearbeitet worden sind, wird dies mit folgender Fehlermeldung abgelehnt: ORA-08177: can't serialize access for this transaction
In diesem Fall sollte die Transaktion zurückgerollt und neu gestartet werden, da die Startbedingungen sich geändert haben. Auch wenn der Isolation Level Serializable ein noch konsistenteres Arbeiten ermöglicht als Read Commited, empfiehlt Oracle aus Performancegründen letzteren. Weiterhin kann der Anwendungsentwickler durch explizites Sperren (mittels SELECT ... FOR UPDATE) für konsistentes Verhalten sorgen und so trotzdem die Performancevorteile nutzen. Der Vollständigkeit halber sei noch der Isolation Level Read-Only erwähnt. Dieser setzt wie Serializable den Lesekonsistenzzeitpunkt auf den Beginn der Transaktion, erlaubt jedoch keine eigenen DML-Kommandos, sondern ausschließlich SELECTBefehle. Hiermit können z.B. in sich konsistente Berichte bei gleichzeitig laufenden Transaktionen erzeugt werden.
Sandini Bib
44
Die Basis-Architektur der Oracle-Datenbank
1.8
Einige interne Algorithmen
1.8.1
Der Least Recently Used-Algorithmus
In den vorangegangenen Abschnitten wurde bereits auf die beiden wesentlichen Zugriffspuffer der SGA, den Shared Pool und den Blockpuffer, eingegangen. Beide Puffer enthalten wesentliche, zur Ausführung von SQL-Befehlen benötigte Informationen. Für das Verhalten des Gesamtsystems ist ausschlaggebend, dass einerseits Informationen in den Puffern schnell auffindbar sind, andererseits für neue Informationen permanent Platz zur Verfügung steht oder schnell zur Verfügung gestellt werden kann. Es ist zudem einfach vorstellbar, dass jeder noch so große Puffer nach einer gewissen Zeit bzw. Anzahl von Operationen gefüllt ist. Dies bedeutet wiederum, dass ein Mechanismus zur Verfügung gestellt werden muss, der entscheidet, welche Informationen in den Puffern – zumindest mit großer Wahrscheinlichkeit – nicht mehr benötigt werden. In beiden oben genannten Puffern werden bei der OracleDatenbank dazu Varianten des Least Recently Used-AIgorithmus (LRU) eingesetzt. Least recently used kann man grob mit „am längsten nicht mehr benutzt“ übersetzen. Der Algorithmus konzentriert sich also darauf, jederzeit zu wissen, welche Objekte am längsten nicht mehr benutzt worden sind. Dies wird durch eine doppelt verkettete Liste mit Zeigern auf Kopf (auch most recently used oder MRU-Ende) und Ende (auch least recently used oder LRU-Ende) der Liste realisiert. Werden neue Objekte in den Puffer gestellt, so werden sie am Kopf der Liste eingefügt. Falls Objekte, die bereits im Puffer sind, erneut benutzt werden, werden sie an der Stelle der Liste, an der sie sich befinden, ausgekettet und am Kopf wieder eingefügt. Daraus geht hervor, dass Objekte vom Kopf zum Ende der Liste wandern, wenn sie einige Zeit nicht benutzt werden. Das Objekt am Ende der Liste ist am längsten nicht mehr benutzt worden. Benötigt also z.B. ein SQL-Befehl freie Blöcke im bereits gefüllten Blockpuffer, so wird am Ende der LRU-Liste nach einer geeigneten Menge von Blöcken gesucht. Falls der Inhalt der Blöcke durch SQL-Befehle manipuliert ist, können diese natürlich nicht einfach überschrieben werden, sondern sie müssen zunächst in die Datendateien zurückgeschrieben werden. Die Arbeit am Ende der LRU-Liste des Blockpuffers übernimmt somit der Database Writer DBW0, der als einziger Prozess Blöcke in die Datendateien schreibt. Von den Server-Prozessen können Aufträge an den DBW0 gestellt werden, Platz für neue Blöcke zu beschaffen. Der DBW0 wartet jedoch nicht ausschließlich auf solche Aufträge, sondern arbeitet vor-ausschauend: Spätestens alle drei Sekunden bearbeitet er eine gewisse Menge der LRU-Liste, damit permanent Platz zur Verfügung steht. Bei ausreichend großem Blockpuffer kommt es daher eher selten vor, dass der DBW0 von einem Server-Prozess beauftragt werden muss.
Sandini Bib
Zusammenspiel der Komponenten
45
.RSI
%ORFNSXIIHU
/58/LVWH
(QGH Abbildung 1.6: LRU-Liste
1.8.2
Management von abhängigen Objekten
Im Oracle Server gibt es durch die Vielzahl von möglichen Objekttypen (Tabelle, View, Prozedur, Paket usw.) eine große Menge von Abhängigkeiten unter den Objekten; z.B. wird durch das Löschen eines Indexes eine auf der zugehörigen Tabelle definierte View ungültig, weil Ausführungspläne zur View den Index nun nicht mehr nutzen können. Im Verlauf dieses Kapitels wird noch darauf eingegangen, dass der Oracle Server SQL-Befehle ausschließlich dynamisch ausführt. Für den der Viewdefinition zugrunde liegenden SQL-Befehl heißt das, dass dieser neu übersetzt werden muss, bevor die View wieder genutzt werden kann. Eine Möglichkeit hierzu wäre, abhängige Objekte bei Änderungen von zugrunde liegenden Objekten sofort neu zu übersetzen. Allerdings wären dann komplexe Systeme allzu sehr mit andauernder Neuübersetzung beschäftigt. Im Oracle Server wird daher das Prinzip verfolgt, einerseits Abhängigkeiten der Objekte im Data Dictionary zu pflegen (Dependency Tracking) und andererseits zu jedem Objekt einen Status (VALID oder INVALID) zu führen. Im o.a. Beispiel wird bei Änderung der Tabellendefinition der Status der abhängigen View von VALID auf INVALID geändert. Die View kann nun über ein entsprechendes Kommando manuell neu übersetzt werden; bei einem nächsten Zugriff auf die View erfolgt aber auch eine automatische Neuübersetzung.
1.9
Zusammenspiel der Komponenten
Die Funktionsweise der Architekturkomponenten soll nun im Zusammenhang beleuchtet werden. Hierzu werden einige Szenarios betrachtet, die typische Befehle und Situationen des Oracle Server betreffen.
Sandini Bib
46
Die Basis-Architektur der Oracle-Datenbank
1.9.1
Szenario 1: SELECT
Der SELECT-Befehl ist zentraler Bestandteil der Datenbanksprache SQL. Mit diesem Befehl können Daten aus der Datenbank gelesen werden, wobei sehr komplexe Verknüpfungen der Daten möglich sind. Die Betrachtungen zum Zusammenspiel der Komponenten des Oracle Server beginnen mit dem SELECT-Befehl einerseits aufgrund seiner zentralen Bedeutung, andererseits ist seine Funktionsweise recht einfach. Dies bezieht sich natürlich nicht auf die tatsächliche interne Abwicklung des SELECT-Befehls; diese ist eher als äußerst komplex zu bezeichnen. Was passiert also, wenn ein SELECT-Befehl an die Aufrufschnittstelle eines ServerPro-zesses abgegeben wird? Der Einfachheit halber wird zunächst ein Dedicated Server angenommen. Dieser ist immer dann gemeint, wenn vom „Server-Prozess“ die Rede ist. Dieser ServerProzess durchläuft nun folgende Schritte: Zunächst wird ein Cursor, eine Speicherstruktur zur Behandlung von SQL-Befehlen, im Server-Prozess bereitgestellt. Der SQL-Befehl wird mit der PARSE-Anforderung an den Server-Prozess übertragen. Der Server-Prozess durchsucht den Shared Pool der SGA nach dem SQL-Befehl. Hierbei muss eine vollständige Übereinstimmung des gesamten Befehl inklusive aller Leerzeichen, Groß-/Kleinschreibung usw. gegeben sein. Falls der Befehl bereits vorhanden ist, wird überprüft, ob 1. die im SQL-Befehl angesprochenen Objekte die gleichen wie die im gefundenen SQL-Befehl sind und, falls ja, ob 2. entsprechende Zugriffsrechte vorhanden sind. Falls beide Prüfungen positiv ausfallen, kann die PARSE-Phase abgeschlossen werden. In allen anderen Fällen wird der Befehl neu übersetzt, die Zugriffsrechte geprüft sowie vom Optimizer ein Ausführungsplan bestimmt. Die hierzu benötigten Informationen werden aus dem Dictionary Cache des Shared Pools gelesen bzw. bei Bedarf mit Hilfe von SQL-Befehlen aus dem Data Dictionary abgefragt. (Diese vom Server-Prozess generierten SQL-Befehle werden auch als rekursives SQL bezeichnet.) Der SQL-Befehl und der Ausführungsplan werden abschließend im Shared Pool abgelegt. In der EXECUTE-Phase wird zunächst die aktuelle System Change Number3 (SCN) in den Cursor geschrieben. Falls für die Ausführung des SELECT-Befehls im Ausführungsplan keine Sortierungen oder Gruppierungen vorgesehen sind, ist die EXECUTE-Phase hiermit abgeschlossen.
3.
Die System Change Number ist eine fortlaufend bei jedem Transaktionsende heraufgezählte Zahl, die zentral im System geführt wird und somit die Zeitachse der Datenbank bestimmt.
Sandini Bib
Zusammenspiel der Komponenten
47
Im anderen Fall werden alle benötigten Datensätze gelesen und die Ergebnismenge bestimmt. Hierbei wird Speicherplatz für die Aufnahme von Zwischenergebnissen und der Ergebnismenge benötigt. Dieser Speicherplatz wird zunächst als Sort Area im Hauptspeicher des Server-Prozesses allokiert. Falls die Sort Area zu klein wird, wird auf ein Temporärsegment ausgewichen. Der Zugriff auf die Daten erfolgt, indem der Blockpuffer der SGA benutzt wird. Auch hier wird für den logischen Zugriff auf einen bestimmten Block zunächst überprüft, ob der Block im Blockpuffer bereits vorhanden ist. Falls ja, kann er von dort benutzt werden, falls nein, wird er vom Server-Prozess aus der entsprechenden Datendatei gelesen und im Blockpuffer abgelegt. An jedem Datensatz wird geprüft, ob dieser durch eine Transaktion seit dem Beginn der EXECUTE-Phase verändert worden ist, d.h., ob seine aktuelle SCN größer als die im Cursor vermerkte SCN ist. Falls der Datensatz „zu neu“ ist, wird mit Hilfe eines Rollback-Segments der Zustand zum Zeitpunkt der vermerkten SCN wiederhergestellt. (Beachte: Es können mehrere Änderungen hintereinander stattgefunden haben. In diesem FalI wird dieser Vorgang entsprechend oft wiederholt.) Nun kann, je nach Anzahl der Datensätze in der Ergebnismenge, entsprechend oft die FETCH-Funktion ausgeführt werden. Hierbei wird jeweils die benötigte Menge an Informationen gelesen. Als Quelle dient, je nach Art des Befehls, der in der EXECUTE-Phase gefüllte Temporärbereich oder die zu den abgefragten Daten gehörigen Daten- und Indexblöcke. Der Zugriff auf Segmente erfolgt immer über den Blockpuffer. Wenn alle gewünschten Datensätze gelesen sind, kann der Cursor geschlossen werden. Es besteht keine grundsätzliche Notwendigkeit, alle Daten zu lesen. Zusätzlich besteht die Möglichkeit, den Cursor mit neu gefüllten Bindevariablen erneut auszuführen, d.h., wenn der gleiche SQL-Befehl mehrfach mit verschiedenen Parametern benutzt werden soll, so kann nach dem ersten Durchlauf die PARSE-Phase jeweils übersprungen und sofort die EXECUTE-Phase durchlaufen werden.
1.9.2
Szenario 2: UPDATE
Der UPDATE-Befehl wird exemplarisch als einer der Data Manipulation Language(DML)Befehle von SQL behandelt, da beim UPDATE sowohl „alte“ als auch „neue“ Daten beachtet werden müssen. Dadurch lässt sich das Verhalten der OracleDatenbank bei DML-Befehlen umfassend erklären. INSERT- und DELETE-Befehle werden sehr ähnlich wie der UPDATE-Befehl behandelt. Ein UPDATE-Befehl unterscheidet sich von einem SELECT-Befehl u.a. dadurch, dass i.A. keine Datensätze an die Anwendung zurückgegeben werden4. Das bedeutet, dass die FETCH-Phase entfällt. Alle entscheidenden Aktionen spielen sich also in der EXECUTE-Phase ab. Die PARSE-Phase als vorbereitende Phase zur EXECUTEPhase ist im Wesentlichen identisch zur PARSE-Phase im SELECT-Fall. Im Folgenden wird somit nur die EXECUTE-Phase beschrieben. 4.
DML-Befehle können optional eine RETURNING-Klausel enthalten, mit der z.B. beim INSERT generierte Schlüsselfelder an die Anwendung zurückgegeben werden können. Diese müssen wie beim SELECT per FETCH abgeholt werden. Diese Möglichkeit wird hier nicht betrachtet.
Sandini Bib
48
Die Basis-Architektur der Oracle-Datenbank
Abbildung 1.7: Szenario 1
Ein weiterer Unterschied zum SELECT-Befehl ist, dass mit dem UPDATE-Befehl Daten verändert werden. Der Befehl muss also als Bestandteil einer Transaktion behandelt werden, und es muss eine Transaktion eröffnet werden, falls der UPDATE-Befehl der erste DML-Befehl der Transaktion ist. Hierzu wird eine Transaktionsnummer vergeben, die u.a. zur Parametrierung einer logischen Transaktionssperre dient. Die Transaktionssperre entsteht gleichzeitig mit der Transaktion und wird benutzt, um Sitzungen, die die gleichen Ressourcen sperren wollen, aufeinander warten zu lassen. Weiterhin wird der Transaktion ein Rollback-Segment zugewiesen, so dass die folgenden Aktionen Before Image-Informationen ablegen können. Das Rollback-Segment enthält eine Transaktionstabelle, in der die aktiven Transaktionen mit einigen zusätzlichen Parametern eingetragen sind. Die neue Transaktion wird in die Transaktionstabelle des zugewiesenen Rollback-Segments aufgenommen.
Sandini Bib
Zusammenspiel der Komponenten
49
Ein UPDATE-Befehl enthält immer eine SET-KIausel, mit der neue Attributwerte bzw. Spalteninhalte gesetzt werden, und optional eine WHERE-Klausel, mit der die zu verändernden Datensätze ausgewählt werden. Fehlt die WHERE-KIausel, so betrifft der UPDATE-Befehl alle Datensätze einer Tabelle. Bei der Ausführung der EXECUTE-Phase werden die vom UPDATE betroffenen Datensätze nacheinander in den Blockpuffer gelesen. Für jeden Datensatz wird nun eine Sperre gesetzt. Zur Verwaltung von Satzsperren enthält jeder Datenblock eine Tabelle mit Transaktionseinträgen. Eine Transaktion belegt in jedem Block, den sie verändert, einen Transaktionseintrag. Im Transaktionseintrag werden u.a. die Transaktionsnummer und das zugewiesene Rollback-Segment eingetragen. Der Transaktionseintrag selbst entsteht also für den jeweils ersten Datensatz, der von der Transaktion im Block modifiziert wird. Die Sperre entsteht nun dadurch, dass an einer vorgesehenen Stelle im Kopf des Datensatzes auf den passenden Transaktionseintrag verwiesen wird. Sowohl der Transaktionseintrag als auch der Verweis auf den Transaktionseintrag werden in das Rollback-Segment geschrieben, bevor die Einträge gemacht werden. Danach wird für den Datensatz die SET-Klausel angewandt, d.h., die Attribute werden entsprechend verändert. Bevor die Werte jedoch in den Datenblock geschrieben werden, wird eine Kopie der betroffenen Attributwerte in das zugewiesene Rollback-Segment geschrieben. Somit besteht die Möglichkeit, auf eventuell noch folgende Fehler zu reagieren und den UPDATE-Befehl wieder zurückzurollen (ROLLBACK), d.h. die alten Werte wieder an die ursprüngliche Stelle zu kopieren. Falls beim UPDATE Werte verändert werden, die in Indizes vorkommen, müssen die entsprechenden Indizes noch angepasst werden, d.h., in jedem Index muss der betreffende Eintrag entfernt und mit dem neuen Indexwert wieder eingefügt werden. Auch für die Indexeinträge gilt, dass alle Before Image-Informationen in das Rollback-Segment geschrieben werden. Für alle Rollback-Segmenteinträge gilt, dass so wenig Information wie möglich bewegt wird, es werden aslo nur die zu ändernden Attribute tatsächlich in das Rollback-Segment kopiert. Für jede der bis jetzt angesprochenen Blockänderungen gilt nun zusätzlich, dass sie mit dem Redolog-Mechanismus protokolliert werden, damit sie bei Fehlerfällen, wie z.B. dem Verlust einer Datendatei, wiederherstellbar sind. Blockänderungen sind dabei sowohl Änderungen von Daten- und Indexblöcken als auch Änderungen von Rollback-Segmentblöcken. Auch der Redolog-Mechanismus arbeitet mit einem Puffer, dem Logpuffer. Dieser Puffer enthält für jede Änderung die Data Block Address (DBA), die physische Adresse des betroffenen Datenbankblocks, und die eigentliche Änderung, wobei im Normalfall nicht Blöcke, sondern nur die betroffenen Bereiche protokolliert werden. Der Logpuffer wird als Ringpuffer geführt, d.h., er wird zyklisch beschrieben, vorausgesetzt, dass die überschriebenen Informationen zuvor vom Log Writer (LGWR) in eine Redolog-Gruppe geschrieben wurden. Falls der Logpuffer zu einem Drittel oder mehr gefüllt ist, wird der LGWR beauftragt, die Informationen in die aktuelle Redolog-Gruppe zu schreiben. Dabei schreibt er parallel in die RedologMember dieser Redolog-Gruppe. Eine der Redolog-Gruppen wird als die aktuelle
Sandini Bib
50
Die Basis-Architektur der Oracle-Datenbank
(bzw. current) Gruppe bezeichnet, in die momentan alle Loginformationen sequentiell geschrieben werden. Die zweite Situation, die den LGWR veranlasst, den noch nicht geschriebenen Inhalt des Logpuffers in die aktuelle Redolog-Gruppe zu schreiben, ist das Beenden einer Transaktion mit COMMIT. Dieser Befehl gilt erst dann als abgeschlossen, wenn die zugehörige Information garantiert in eine Redolog-Datei geschrieben worden ist. Hierzu wird zunächst eine neue SCN generiert und in die Transaktionstabelle des Rollback-Segments eingetragen, so dass für andere Sitzungen später das COMMIT der Transaktion nachvollziehbar ist. Gleichzeitig wird hiermit der Zeitstempel der Änderung festgelegt, der für die Lesekonsistenz eine entscheidende Rolle spielt. Schließlich wird ein COMMIT-Satz generiert, der mit den Rollback-Segmentänderungen in den Logpuffer geschrieben wird. Für ein COMMIT müssen keine Datenbankblöcke geschrieben werden.
Abbildung 1.8: Szenario 2
Sandini Bib
Zusammenspiel der Komponenten
51
Abschließend wird dann der LGWR gezwungen, die nun im Logpuffer vorhandenen Informationen in die aktuelle Redolog-Gruppe zu schreiben. Dies hat den Zweck, dass die Transaktionssteuerungsbefehle z.B. auch nach einem Stromausfall wiederhergestellt werden können. Die zur Wiederherstellung benötigte Information muss demnach permanent auf Festplatte gespeichert sein. Erst wenn der LGWR vom Betriebssystem die Bestätigung bekommt, dass der Schreibvorgang durchgeführt ist, wird dem Client-Prozess die Ausführung der Aktion bestätigt. An dieser Stelle soll ebenfalls darauf hingewiesen werden, dass die Writer-Prozesse DBW0 und LGWR auf allen Betriebssystemen die Benutzung eventuell vorhandener Caches für schreibende Dateizugriffe ausschalten, was allgemein als Write Through Cache oder ähnlich bezeichnet wird. Der Grund dafür ist, dass z.B. im Szenario des LGWR, der für ein COMMIT den COMMIT-Satz herausschreiben muss, die Gefahr besteht, dass der COMMIT-Satz noch eine ganze Weile im Cache des jeweiligen Dateisystems steht, bevor er tatsächlich geschrieben wird. Wenn es in dieser Situation einen Stromausfall gibt, könnte die betroffene Transaktion nicht wiederhergestellt werden.
1.9.3
Szenario 3: Gleichzeitige Befehle SELECT und UPDATE
Für dieses Szenario wird angenommen, dass in einer Sitzung A ein SELECT-Befehl und in einer Sitzung B kurz nach dem Start des SELECT-Befehls ein UPDATE-Befehl abgesetzt wird . Sitzung A
SELECT SUM(col1) FROM tab1
Sitzung B
UPDATE tab1 SET col1 = col1 + 1 WHERE col2 = 4711
Tabelle 1.3: SQL-Befehle aus Sitzung A und B
Dabei hat der SELECT-Befehl eine längere Laufzeit als der UPDATE-Befehl (unter der Annahme, dass der UPDATE-Befehl über die WHERE-KIausel indiziert auf eine relativ kleine Datenmenge zugreift). Da die Datensätze in einer Tabelle nicht sortiert gespeichert werden, können die Datensätze, die der WHERE-Klausel des UPDATE-Befehls entsprechen, beliebig über die Blöcke der Tabelle tab1 verteilt sein. Damit ergibt sich folgender Ablauf: Der SELECT-Befehl aus Sitzung A startet. Die Berechnung erfolgt in der EXECUTEPhase, da es sich um eine Gruppenfunktion handelt. Es werden die ersten Datensätze gelesen, u.a. auch einige mit col2 = 4711. Der UPDATE-Befehl aus Sitzung B startet. Da der Zugriff indiziert erfolgt, sind alle Änderungen durchgeführt, bevor der SELECT-Befehl zum Ende kommt. Für den UPDATE-Befehl treffen alle Darstellungen aus Szenario 2 zu, insbesondere werden die Attributwerte für col1 sofort geändert. Ein gleichzeitiger oder quasi gleichzeitiger Zugriff auf einen Block von den Server-Prozessen der beiden Sitzungen ist dabei nicht möglich: Jeder Block besitzt einen Schutzmechanismus vor gleichzeitigen Zugriffen (gleichzeitige lesende Zugriffe sind natürlich erlaubt). Der Mechanismus ist als atomare (oder auch unteilbare) Operation implementiert und wird in der Oracle-Architektur als Latch bezeichnet. Hiermit wird sichergestellt, dass nicht
Sandini Bib
52
Die Basis-Architektur der Oracle-Datenbank
gelesen werden kann, während die Änderung den Block in einen eventuell inkonsistenten Zwischenzustand gebracht hat. Latches sind im übrigen nicht mit Sperren (Locks) zu verwechseln: Latches werden im Allgemeinen nur sehr kurz gehalten, Sperren bestehen immer bis zum Transaktionsende. Die Verwendung von Latches führt dazu, dass für den SELECT-Befehl entweder der unveränderte Zustand von Schritt 1 oder aber – während oder nach Schritt 2 – ein veränderter Block vorgefunden wird. Für die Berechnung der Summe über col1 kann nicht einfach der vorgefundene Wert benutzt werden: Es stehen bereits von Sitzung B veränderte Werte in den Blöcken. Richtigerweise muss über den Transaktionseintrag des Datensatzes der vor dem UPDATE bestehende Wert für col1 rekonstruiert werden. Dies gilt auch, wenn Sitzung B in der Zwischenzeit bereits ein COMMIT ausgeführt hat: Es muss nicht die aktuelle, sondern die konsistente Version jedes Datensatzes gelesen werden! Falls bei der Auswertung des SELECTBefehls also seit dem Beginn der EXECUTE-Phase veränderte Werte angetroffen werden, muss über den „Umweg“ des Rollback-Segments gelesen werden. Diese Vorgehensweise des Oracle Server bei gleichzeitig laufenden Aktionen bringt im Mehrbenutzerbetrieb zwei immense Vorteile: 1. Gleichzeitige DML- und SELECT-Befehle müssen nicht bis zum Transaktionsende aufeinander warten, und 2. das Ergebnis von SELECT-Befehlen ist immer konsistent. Bei vielen anderen Systemen müssen konsistente Ergebnisse mit Sperren „erkauft“ werden, so dass Wartezustände unvermeidlich sind. Beim Oracle Server ist die Lesekonsistenz automatisch und transparent immer verfügbar!
1.9.4
Szenario 4: SELECT/UPDATE über Shared Server
In den ersten beiden Szenarios wurde der Server-Prozess als Dedicated Server angenommen. Der Grund hierfür ist, dass zwischen den einzelnen Aufrufen an den Server-Prozess (Cursor bereitstellen, PARSE, EXECUTE, FETCH) Informationen in der Context Area „gemerkt“ werden müssen. Dies ist im Dedicated Server dadurch möglich, dass die Context Area als dynamischer Speicherbereich allokiert wird (z.B. in C durch einen malloc()-Befehl) und bei den Folgeaktionen direkt adressierbar zur Verfügung steht. Vom Shared Server ist bereits bekannt, dass jeder Aufruf an den Oracles Server über den Dispatcher in die Request Queue gestellt wird und ein beliebiger Shared Server den Aufruf bearbeitet. Das bedeutet, dass z.B. der Aufruf PARSE durch den Server 5003, EXECUTE durch 5001, der erste FETCH durch 5015, der nächste FETCH durch 5001 bearbeitet wird usw. Damit wird klar, dass die Context Area nicht an einem speziellen Prozess allokiert werden kann, sondern sie muss zentral gespeichert werden. Das Problem wird dadurch gelöst, dass Context Areas für Shared Server-Sitzungen im Large Pool der SGA gespeichert werden. Somit kann jeder Shared Server auf die von anderen Shared Servern gespeicherte Information zugreifen.
Sandini Bib
Zusammenspiel der Komponenten
53
Die zentrale Speicherung im Large Pool bezieht sich nicht nur auf die Context Areas, sondern auch auf die gesamte so genannte Program Global Area (PGA) der einzelnen Sitzungen. Hierzu gehören nicht nur die Context Areas, sondern auch die Sort Area und die Hash Area. Letztere wird für den Hash Join genutzt. Die Ergebnisse der einzelnen Aufrufe werden von den Shared Servern in die Response Queue des Dispatchers eingetragen. Sobald der Dispatcher das Ergebnis findet, schickt er es an die Anwendung zurück.
1.9.5
Szenario 5: Wechsel der aktuellen Redolog-Gruppe
Bei den Ausführungen zu Szenario 2 wurde erwähnt, dass alle Schreibaktivitäten des LGWR in der aktuellen Redolog-Gruppe stattfinden. Eine Eigenschaft jeder Redolog-Gruppe ist die Größe ihrer Redolog-Member in Bytes, so dass beim sequentiellen Beschreiben die Redolog-Gruppe irgendwann gefüllt ist. Die aktuelle Redolog-Gruppe wird dann geschlossen, und die nächste RedologGruppe wird zur aktuellen Redolog-Gruppe. Da immer mindestens zwei RedologGruppen existieren, kann grundsätzlich in eine andere Redolog-Gruppe gewechselt werden. Dies ist recht einfach durchführbar, jedoch muss etwas beachtet werden: Die Online-Redologs sind u.a. dazu da, nach einem Absturz der Instanz die Konsistenz der Datenbank wiederherzustellen. Diese Anforderung und der LRU-Algorithmus führen dazu, dass der DBW0 beim Wechsel der aktuellen Redolog-Gruppe, der auch als Log Switch bezeichnet wird, beschäftigt wird. Angenommen, die Datenbank besteht aus zwei Redolog-Gruppen mit beliebig vielen Redolog-Membern. Nach dem Systemstart wird in Gruppe 1 geschrieben, dann folgt ein Log Switch auf Gruppe 2, danach wieder ein Log Switch auf Gruppe 1. In der ganzen Zeit wird ein bestimmter Datenblock in kurzen Abständen immer wieder geändert, z.B. mit einem UPDATE auf eine Statusinformation. Der LRU-Algorithmus sorgt dafür, dass dieser Block nicht an das Ende der LRU-Liste rutscht, so dass dieser Block nicht zurück in die Datendatei geschrieben wird. Wenn in dieser Situation nach dem zweiten Log Switch die Instanz abstürzt, z.B. durch Stromausfall, kann der Block nicht wiederhergestellt werden, da die Änderungen aus dem ersten Inhalt von Redolog-Gruppe 1 fehlen. Es muss also Folgendes sichergestellt werden: Bevor der Inhalt einer RedologGruppe überschrieben wird, müssen die Blockänderungen, die in dieser RedologGruppe protokolliert sind, in die entsprechenden Datendateien zurückgeschrieben werden. Dieser Vorgang, der als Checkpoint bezeichnet wird, ist wie folgt implementiert: Neben der allgemeinen LRU-Liste wird in der SGA eine Liste aller noch nicht zurück-geschriebenen modifizierten Blöcke (dirty blocks) geführt, die so genannte Checkpoint Queue. Aus der Checkpoint Queue können alle Dirty Blocks in der Reihenfolge ihrer Änderungen ausgelesen werden (bei mehreren Änderungen zählt die erste). Der Zeitstrahl der Änderungen wird über die Redo Byte Address (RBA) geführt. Somit kann bei einem Checkpoint die Checkpoint Queue in der Reihenfolge der Blockänderungen vom DBW0 abgearbeitet werden, d.h., alle modifizierten Blöcke werden in die Datendateien zurückgeschrieben. Der Checkpoint
Sandini Bib
54
Die Basis-Architektur der Oracle-Datenbank
bekommt bei seiner Auslösung eine eigene RBA, die nach dessen Fertigstellung vom Checkpoint Process CKPT zusammen mit der letzten SCN in alle Datendateien eingetragen wird, so dass im Kopf einer Datei festgestellt werden kann, welcher Checkpoint als Letzter enthalten ist. Ein Checkpoint kann in den verschiedenen Situationen entweder automatisch oder vom DBA manuell ausgelöst werden. Beim Wechsel der aktuellen RedologGruppe löst der LGWR einen Checkpoint aus, übergibt dem DBW0 die Liste der modifizierten Blöcke und wechselt dann zur nächsten Gruppe, die zur aktuellen Gruppe wird. Die vorhergehende Gruppe wird so lange als aktiv markiert, bis der Checkpoint durchgeführt ist. Für den LGWR wird nun noch eine zusätzliche Regel eingeführt: Beim Wechsel der aktuellen Redolog-Gruppe darf nicht in eine aktive Redolog-Gruppe gewechselt werden. Damit ist sichergestellt, dass alle Transaktionen mit den vorhandenen Datendateien und den Online-Logs wiederherstellbar sind! Der Status, welche Redolog-Gruppe die aktuelle Redolog-Gruppe ist, wird in der Kontrolldatei vermerkt. Weiterhin wird in der Kontrolldatei für jede RedologGruppe die erste, bei geschlossenen Redolog-Gruppen auch die letzte enthaltene SCN verwaltet. Für alle Datendateien wird anhand der SCN vermerkt, welcher Checkpoint der letzte in der Datei enthaltene ist.
1.9.6
Szenario 6: Instanzabbruch und -wiederherstellung
Nachdem erklärt ist, in welcher Art und Weise Transaktionen protokolliert werden und wann Informationen in die Datendateien geschrieben werden, kann nunmehr ein erster Fehlerfall diskutiert werden: der Instanzabbruch. Alle Situationen, bei denen Teile der Instanz oder die gesamte Instanz nicht mehr zur Verfügung stehen und kein ordnungsgemäßer Systemstopp durchgeführt worden ist, werden als Instanzabbruch bezeichnet. Weiterhin wird beim Instanzabbruch angenommen, dass keine Dateien beschädigt sind. Andernfalls zählt dieser Fehler zu den Medienfehlern. Da bei einem Instanzabbruch keine Information verloren gegangen ist (auch die letzte Transaktion steht in den Redolog-Dateien!), kann die Konsistenz der Datenbank automatisch wiederhergestellt werden. Es muss allerdings ein Wiederherstellungsverfahren angewandt werden, da in den Datendateien eventuell inkonsistente Informationen enthalten sind. Es können zwei verschiedene Situationen vorkommen: 1. Informationen aus mit COMMIT abgeschlossenen Transaktionen sind noch nicht in die Datendateien zurückgeschrieben worden. Die Blöcke haben also einen „zu alten“ Zustand. 2. Informationen, die aus DML-Befehlen entstanden sind, wurden bereits in die Datendateien zurückgeschrieben, die Transaktion wurde jedoch nicht mit COMMIT abgeschlossen. Die Blockinhalte sind also falsch, da der vorangegangene Zustand wiederhergestellt werden muss.
Sandini Bib
Zusammenspiel der Komponenten
55
Wie kann nun dieser offensichtlich inkonsistente Zustand wieder bereinigt werden? Beim Systemstart wird festgestellt, dass der Systemstop nicht „sauber“ durchgeführt worden ist, da diese Information in der Kontrolldatei vermerkt wäre. Mit der Kontrolldatei kann jedoch überprüft werden, dass alle Daten- und Redolog-Dateien vorhanden sind und den richtigen, d.h. zuletzt vermerkten Zustand haben. Für die nun folgende Wiederherstellung muss weiterhin festgestellt werden, welche Checkpoints bereits in den Datendateien enthalten sind. Hier gibt es zwei Extremfälle: 1. Keiner der zuletzt angeforderten Checkpoints ist in den Datendateien enthalten, d.h., alle Redolog-Gruppen außer der aktuellen sind noch als aktiv markiert. 2. Alle Checkpoints sind durchgeführt. Der Datenbank fehlen lediglich die Blockänderungen, die in der aktuellen Redolog-Gruppe enthalten und noch nicht durch einen Checkpoint gesichert sind. Im ersten Fall müssen alle Redolog-Gruppen zur Wiederherstellung herangezogen werden, im zweiten Fall nur die aktuelle Redolog-Gruppe. Falls eine Datenbank aus mehr als zwei Redolog-Gruppen besteht, können natürlich auch Situationen entstehen, die z.B. zwei von vier Redolog-Gruppen betreffen. Die Wiederherstellung erfolgt in zwei Phasen: Roll-Forward und Roll-Back. In der ersten Phase werden alle Blockänderungen aus den Redolog-Dateien nochmals auf die betroffenen Blöcke angewandt, indem die Blöcke in den Blockpuffer gelesen und entsprechend modifiziert werden. Damit nur die wirklich notwendigen Änderungen durchgeführt werden, wird für jede Änderung geprüft, ob die Änderungsnummer des Blocks mit der Information im Log übereinstimmt. Die Änderungsnummer wird im Block als Incarnation Number geführt und bei jeder Blockänderung hochgezählt. Eine Änderung wird bei der Wiederherstellung nur dann durchgeführt, wenn die Änderung die Änderungsnummer von X auf X + 1 verändert und der Block die Änderungsnummer X hat. Hat der Block eine größere Änderungsnummer, so enthält er den aktuellen Logeintrag bereits. Hat er eine kleinere Änderungsnummer, so wird die Wiederherstellung abgebrochen; die Loginformationen sind inkonsistent. Dieser Fall ist eher von theoretischer Bedeutung, da er nach den bisher aufgeführten Regeln nicht vorkommen kann. Die Roll-Forward-Phase kann demnach als das rein physikalische Wiederherstellen aller Datenbankblöcke betrachtet werden. Nach Beendigung der Wiederherstellung haben alle Blöcke in der Datenbank den Status wieder erhalten, den sie beim Instanzabbruch hatten. Nun muss noch sichergestellt werden, dass nur Änderungen, die mit COMMIT bestätigt worden sind, in der Datenbank erhalten bleiben. Dies wird in der RollBack-Phase dadurch erreicht, dass die Transaktionstabellen der Rollback-Segmente, die mit dem Roll-Forward ebenfalls wieder auf dem aktuellen Stand sind, nach offenen Transaktionen durchsucht werden. Diese werden daran erkannt, dass ihnen noch keine SCN zugeordnet ist. Alle offenen Transaktionen werden nun mit Hilfe der Informationen in den Rollback-Segmenten zurückgerollt, d.h., die Blöcke erhalten wieder die Informationen, die dem Zeitpunkt vor der Transaktion entsprechen. Sobald die Roll-Back-Phase abgeschlossen ist, können alle Informationen in der Datenbank wieder benutzt werden und sind garantiert konsistent.
Sandini Bib
56
Die Basis-Architektur der Oracle-Datenbank
1.10 DBA-Werkzeuge 1.10.1 Kommandozeilen-Werkzeuge Zu jeder Installation der Oracle-Datenbank gehören einige Werkzeuge, die ausschließlich über die Kommandozeile bedient werden. Sie erfüllen vielleicht nicht alle Ansprüche an Administrationswerkzeuge für diejenigen, die Administration über graphische Oberflächen à la MS-Windows gewohnt sind, erlauben jedoch nach einer gewissen Einarbeitungszeit äußerst effektives Arbeiten. Zu diesen Werkzeugen zählen u.a. SQL*Plus, das neben der seit Jahren bekannten Funktionalität als Werkzeug für SQL interaktiv und per Script einige Administrationskommandos „gelernt“ hat und den Server Manager ersetzt, Export/Import zum Entladen und Einladen von Daten in ein Oracle-spezifisches Binärformat, SQL*Loader zum Laden von Daten in beliebigen Formaten sowie TKPROF zur Auswertung von SQL-Tracedateien. Fast alle Beispiele in diesem Buch sind mit Hilfe von SQL*Plus durchgeführt worden. Neben der reinen Kommandozeilenversion gibt es dieses Werkzeug unter MS-Windows auch als GUI-Version, mit der zumindest Aktionen wie Kopieren & Einfügen einfacher durchführbar sind. Die GUI-Version kann man gerne zum interaktiven Arbeiten benutzen, für die Abarbeitung von Scripts ist die Kommandozeilenversion wesentlich besser geeignet. Bei der Beliebtheit von SQL*Plus unter Oracle-Anwendern sind ähnliche Effekte zu beobachten wie beim Unix-Editor VI unter Unix-Benutzern: Anfänger hassen die Werkzeuge wegen ihrer wenig komfortablen Bedienung; hat man sich einmal an die Bedienung gewöhnt, weiß man ihre speziellen Funktionen zu schätzen und kann nicht mehr recht die Finger davon lassen ...
1.10.2 Oracle Enterprise Manager Seit der Version 7.3 wird mit jeder Oracle Server Version der Oracle Enterprise Manager ausgeliefert. Dabei basierte das Produkt zunächst auf einer so genannten Konsole, die in C geschrieben und nur auf MS-Windows Systemen lauffähig war. Mit der Einführung von Oracle8i als Internet-Plattform wurde auch der Enterprise Manager in der Version 2 generalüberholt und steht jetzt als Java-Komponente auf allen grafischen Oberflächen zur Verfügung. Im Laufe der Jahre hat Oracle einige weitere Komponenten entwickelt bzw. zugekauft, so dass heute ein umfangreiches Framework für die Administration der Datenbank und Anwendungen, wie z.B. dem Internet Application Server oder Oracle OLAP Services, um eine zentrale Konsole angeordnet sind. Neben der Standardadministration der Datenbank kann der Enterprise Manager um zusätzliche Pakete erweitert werden. Dies sind im Folgenden:
Sandini Bib
Die Oracle9i-Familie
: :
:
: :
57
Oracle Change Management Pack Vergleicht unterschiedliche Objekte, Schemas oder ganze Datenbanken. Zusätzlich ist es möglich, Scripts zu erstellen, die erkannte Unterschiede beheben. Oracle Diagnostics Pack Grafische Werkzeuge, um ein Online-Monitoring oder einen „Gesundheitscheck“ durchzuführen. Die wichtigste Komponente ist jedoch das Paket Advanced Events, mit denen ein Alarmsystem für die wichtigsten Datenbankparameter bzw. Engpässe aufgebaut werden kann. Oracle Tuning Pack Diese Werkzeuge können für das Tuning von Anwendungen oder die Reorganisation von Tabellen benutzt werden. Am hilfreichsten ist dabei das Werkzeug SQL Analyze, das eine gute grafische Oberfläche für die Analyse von SQL-Befehlen bietet. Oracle Management Pack for Oracle Applications Hier sind die drei bereits beschriebenen Pakete unter spezieller Berücksichtigung von Oracle Applications zusammengefasst. Oracle Management Pack for SAP/R3 Hier sind die drei beschriebenen Pakete für das Anwendungsmanagement von SAP/R3 zusammengefasst worden.
Wichtig: Diese Erweiterungen können nur für die Enterprise Edition lizenziert werden. Für die Standard-Edition liefert Oracle kostenlos das Oracle Standard Management Pack aus, dass einige Basisfunktionen aus den Paketen Change Management, Diagnostics und Tuning Pack enthält; wichtige Elemente wie SQL Analyze fehlen dabei allerdings.
1.11 Die Oracle9i-Familie Den Abschluss dieses Kapitels bilden einige Informationen rund um die Vermarktung von Oracle9i. Neben der Datenbankproduktreihe (Oracle9i Database) gibt es eine Produktreihe im Umfeld des Anwendungs- bzw. Webservers (Oracle9iAS) sowie die Entwicklungsumgebungen (Oracle9i Developer Suite oder Oracle9iDS). In der Oracle9i Developer Suite finden sich sowohl alte Bekannte wie Oracle Forms und Oracle Reports als auch der Oracle JDeveloper zur Entwicklung von Java-Anwendungen. Eine interessante Neuigkeit bezüglich Oracle Forms und Oracle Reports ist, dass die Runtime-Umgebungen der aktuellen Versionen nicht mehr im Client-Server-Modus lauffähig sind, sondern ausschließlich innerhalb des Oracle9iAS laufen. Für diejenigen, die diese Umstellung nicht sofort durchführen wollen, gibt es das etwas ältere Paket Oracle Developer6i noch für einige Jahre.
Sandini Bib
58
Die Basis-Architektur der Oracle-Datenbank
Die Oracle9i-Datenbank gibt es in verschiedenen Editionen: Personal, Standard und Enterprise. Die Standard Edition enthält die komplette Basisfunktionalität wie SQL, PL/SQL, die Datenbankwerkzeuge usw. Sie ist lizenztechnisch auf die Installation für Systeme mit maximal vier Prozessoren beschränkt. Seit Oracle9i enthält auch die Standard Edition die komplette Advanced Replication-Funktionalität. Die Enterprise Edition enthält zunächst dafür, dass sie erheblich teurer als die Standard Edition ist, lediglich einige erweiterte Funktionen, z.B. funktionsbasierte Indizes. Zusätzlich kann sie, gegen weitere Lizenzgebühren, um Optionen erweitert werden. Hierzu zählen:
: : : : : : :
RAC (Real Application Clusters, löst Parallel Server ab) zum Betreiben der Datenbank in einem Cluster Partitioning, ermöglicht die Unterteilung von Tabellen und Indizes in Partitionen, denen die Datensätze wertebasiert zugeordnet werden, um große und riesige Datenmengen besser in den Griff zu bekommen OLAP (OnLine Analytical Processing), dies ist die in den Oracle-Datenbankkern integrierte frühere Oracle Express-Funktionalität Data Mining, spezielle Analysefunktionen für große Datenmengen Spatial, zur Darstellung und Auswertung von mehrdimensionalen Modellen in der Datenbank Advanced Security, spezielle Sicherheitsfunktionen, die z.B. die Verschlüsselung von Datenpaketen ermöglichen, die über Oracle Net verschickt werden Label Security, eine Option, die früher als eigenes Trusted Oracle-Produkt erworben werden konnte, zur Erfüllung spezieller Sicherheitsanforderungen
Auf die Optionen wird teilweise innerhalb des Buches eingegangen, z.B. auf RAC und Partitioning. Da die Optionen eine erhebliche Komplexität aufweisen, ist auf die detaillierte Betrachtung aller Optionen verzichtet worden. Die Personal Edition ist eine Einzelplatzversion, die der Enterprise Edition inklusive allen Optionen außer RAC entspricht. Damit ist sie z.B. für Entwickler-Arbeitsplätze hervorragend geeignet. Das ebenfalls erhältliche Oracle Lite ist ein eigenes Produkt und beinhaltet nicht die in diesem Buch dargestellte Datenbank-Architektur. Oracle Lite ist als „schmales“ Produkt ausgelegt, u.a. als Mitbewerber zu PC-Datenbankprodukten, die erheblich weniger Ressourcenbedarf als eine komplette Oracle-Datenbank haben, sowie als Produkt für Handheld- und Palmtop-Computer.
Sandini Bib
2 2.1
Installation und Basiskonfiguration Basis für die Oracle-Installation: Hardware und Betriebssystem
Die Basis für eine Oracle-Installation ist ein Rechner bzw. Server inklusive eines dazu passenden Betriebssystems. Neben persönlichen Vorlieben sind hier zwei Fragen zu klären: 1. Welche Kombination von Hardware und Betriebssystem ist die richtige? 2. Wie soll die Hardware ausgestattet und das Betriebssystem konfiguriert werden? Es ist nicht unsere Absicht, die verschiedenen Plattformen zu bewerten. Die Auswahl bleibt weiterhin Ihnen überlassen. Im Folgenden wird aber versucht, die Eigenheiten der Plattformen sowie die der Oracle-Implementierungen möglichst objektiv darzustellen. Vor der Installation der Oracle Database-Software sollten Sie ausführlich die plattform-spezifischen Installationsvoraussetzungen überprüfen. Bei Oracle9i ist – noch mehr als in allen früheren Oracle-Versionen – ein ausgiebiger Festplatten- und Hauptspeicherbedarf festzustellen. Das liegt einerseits an der immer weiter wachsenden Funktionsvielfalt des Oracle-Datenbanksystems, andererseits im Speziellen an der Integration von Java-Komponenten im Datenbankkern, die bekanntermaßen gerne Speicher – welcher Art auch immer – belegen. In diesem Kapitel werden die Standardanforderungen für eine saubere OracleInstallation dargestellt. Aus Aktualitäts- und Übersichtsgründen können wir hier lediglich über Größenordnungen schreiben, nicht über detaillierte Angaben. Diese sind plattform-spezifisch in der Dokumentation zu den einzelnen Oracle-Versionen nachzulesen. Neben einer gelungenen Initialkonfiguration sollte eine Datenbankmaschine jedoch immer so ausgestattet sein, dass eine Erweiterung in den wichtigsten Bereichen möglich ist. Hierzu gehören Rechenkapazität, Hauptspeicherkapazität und EA-Bandbreite. Für die folgenden Abschnitte gilt generell die Annahme, dass ausschließlich die Oracle Database-Software installiert werden soll. Falls zusätzlich weitere OracleProdukte, wie z.B. der Internet Application Server Oracle9iAS oder das Internet Filesystem iFS installiert werden sollen, sind die Anforderungen dieser Produkte getrennt zu analysieren und entsprechend als Hardwarekapazität bereitzustellen.
Sandini Bib
60
Installation und Basiskonfiguration
Auch die Tatsache, dass hier Minimalanforderungen diskutiert werden, die im Einzelfall weit unter den tatsächlichen Anforderungen liegen, soll an dieser Stelle ausdrücklich betont werden. Im weiteren Verlauf dieses Buches wird immer wieder der Ressourcenbedarf diverser Features diskutiert, so dass der Bedarf eines speziellen Systems zumindest abgeschätzt werden kann.
2.1.1
Hardware
Eine Eigenschaft des Oracle-Datenbanksystems, die immer wieder beobachtet werden kann, ist die bedingungslose Ausnutzung bereitgestellter Ressourcen. Diese Tatsache kann man aus mehreren Blickwinkeln betrachten und sowohl positive – „Das System besitzt einen hohen Durchsatz.“ – als auch negative – „Das System beschränkt Ressourcen für andere Dienste auf der gleichen Hardware.“ – Schlussfolgerungen ziehen. Man kann jedoch genauso gut aus den Fakten lernen und einige Tipps für eine gut funktionierende Gesamtkonfiguration ableiten. Die erste Grundregel für Oracle-Installationen lautet, dass, soweit möglich, andere Softwaresysteme auf getrennten Rechnern installiert werden sollen. Diese Vorgehensweise verhindert, dass Datei- und Druckserver, Domänen-Kontrollsysteme sowie das Oracle-Datenbanksystem die meiste Zeit damit verbringen, sich gegenseitig Ressourcen streitig zu machen. Jedes Software-System kann bei getrennter Hardware exakt die per Installation zugeteilten Ressourcen nutzen. Umgekehrt heißt das, dass ein überlastetes System die anderen Systeme nicht in Mitleidenschaft ziehen kann. Die Auslegung von Prozessorstärke, Hauptspeichergröße und I/O-System ist naturgemäß stark abhängig von den Aufgaben des Datenbankservers: Von der Kundenverwaltung für einige Mitarbeiter bis zu zentraler Verwaltung von riesigen Datenmengen mit mehreren tausend Verbindungen ist alles mit einem Oracle-System machbar. Als Minimalkonfiguration sollte folgende Konstellation angenommen werden: Der Prozessor sollte einer recht neuen Generation angehören (wobei man durchaus einen Pentium III Prozessor noch nicht zum alten Eisen zählen muss). Falls große Leistungsreserven bereitgestellt werden müssen, sollten zunächst die einzelnen Prozessoren so leistungsfähig wie möglich eingesetzt und erst dann eine Mehrprozessorkonfiguration in Betracht gezogen werden. Gründe hierfür sind, dass eine solche Konfiguration immer eine gewisse zusätzliche Belastung gegenüber einem Einprozessorsystem bedeutet und dass für jedes System eine absolute Grenze der Skalierbarkeit bezüglich der Anzahl der Prozessoren gegeben ist, die man mit kleinen Prozessoren natürlich schneller erreicht. Die Grenzen der Skalierbarkeit sind im Allgemeinen weniger vom Oracle-System gegeben als vom darunter liegenden Betriebssystem oder der verwendeten Anwendungssoftware. Der Hauptspeicherausbau für ein Oracle9i-System sollte auf keinen Fall weniger als 512 Mbyte betragen. Je nach Konfiguration nimmt die Oracle-Instanz im Minimalfall 50 Mbyte bis 100 Mbyte in Anspruch, dazu kommen Ressourcen für das Betriebssystem und zusätzliche Oracle-Prozesse, wie z.B. der Intelligent Agent. Je nach Anwendung und Zahl der Verbindungen beträgt die Größe des Hauptspeichers eines Oracle Servers durchaus einige Gbyte bis einige zehn Gbyte.
Sandini Bib
Basis für die Oracle-Installation: Hardware und Betriebssystem
61
Beim I/O-System sind neben den reinen Kapazitätsüberlegungen auch Lastverteilungs- und Redundanzfragen zu klären. Die Details hierzu werden in Kapitel 7 diskutiert. Grundsätzlich ist eine Verteilung anzustreben, in der
: : : : :
Betriebssystem- und Oracle-Software-Installation, eventuelle Auslagerungsbereiche, Datendateien, Redolog-Dateien sowie die archivierten Redolog-Dateien
jeweils auf unterschiedlichen Festplatten oder Festplatten-Gruppen liegen. Diese Verteilung ist mit modernen Festplatten-Systemen nicht leicht einsehbar, da für viele Installationen die Summe des Platzbedarfs für alle genannten Bereiche nicht größer als die Kapazität einer handelsüblichen Festplatte ist. In solchen Fällen hilft nur die wiederholte Überlegung, in welcher Art und Weise eine Datenbanksoftware auf I/ORessourcen zugreift und wie wichtig die gespeicherten Daten schließlich sind. Die wichtigste Empfehlung von allen ist: Halten Sie Ihr System erweiterbar! Nur dadurch verhindern Sie, dass Sie auf eine komplett andere Hardware umstellen müssen, sobald Sie in einer zukünftigen Optimierungsbetrachtung auf RessourcenEngpässe stoßen. Die Erweiterung von Rechen-, Speicher- oder I/O-Kapazität ist eine durchaus häufig vorkommende – und durch die am Kapitelanfang diskutierte Eigenschaft des Oracle-Datenbanksystems meist erfolgreiche – Maßnahme.
2.1.2
Betriebssysteme
Die Wahl eines geeigneten Betriebssystems für eine Oracle-Softwareinstallation ist wohl eine der meistdiskutierten Fragen in der Gemeinschaft der Oracle-Administratoren. Wo vor einigen Jahren noch eine klare Grenze zwischen MS-Windows1 (für kleinere Installationen) und Unix (für größere Installationen und bei Bedarf für große Reserven) zu ziehen war, ist mittlerweile eine Diskussion an diversen Fronten entbrannt. Einerseits wird MS-Windows immer erwachsener, d.h., Eigenschaften wie Verfügbarkeit, Skalierbarkeit und Administrierbarkeit werden immer mehr in die Oracle-für-Windows-Welt projiziert; andererseits bekommt MS-Windows als Basis für Oracle-Installationen auf dem angestammten PC-Server-Sektor ernst zu nehmende Konkurrenz durch Linux. Dieses Buch wird gar nicht erst versuchen, eine abschließende Antwort auf die Frage nach dem besten Betriebssystem zu geben, da, abgesehen von persönlichen Präferenzen, jedes System sicherlich neben seinen Nachteilen auch Vorteile gegenüber den anderen Systemen zu bieten hat. In diesem Abschnitt soll lediglich versucht werden, einige Fakten über die diversen Systeme objektiv darzustellen, um Ihre persönliche Entscheidung ein wenig zu erleichtern. Am Anfang steht jedoch die Diskussion der betriebssystemunabhängigen Eigenschaften, die auf jeden Fall zur Verfügung stehen. 1.
Um ein ständiges Aufzählen der beiden möglichen Varianten für Oracle Serverinstallationen, nämlich MSWindows NT und MS-Windows 2000, zu vermeiden, wird ab sofort Windows als Synonym für beide Varianten verwendet. Nur bei der expliziten Betrachtung werden die Varianten jeweils benannt.
Sandini Bib
62
Installation und Basiskonfiguration
Betriebssystemunabhängige Eigenschaften des Oracle ORDBMS Zunächst einmal ist es wichtig klarzustellen, dass eine Entscheidung für das Betriebssystem unter einer Oracle-Datenbank keine endgültige ist. Es ist zwar jeweils mit Aufwand verbunden, aber eine Oracle-Datenbank kann immer von einer Plattform auf eine andere migriert werden. Programme, die mit einer OracleDatenbank auf einer Plattform laufen, tun dies mit Sicherheit auch auf jeder anderen Oracle-Datenbankplattform. Zur Migration muss – neben lizenztechnischen Dingen – jeweils das Problem der Auszeit zwischen der letzten Verfügbarkeit des Quellsystems und der ersten Verfügbarkeit des Zielsystems gelöst werden. Diese Auszeit kann relativ lang sein, da die Daten aus der Quelldatenbank entladen und in die Zieldatenbank geladen werden müssen, was z.B. einen Neuaufbau aller Indizes erfordert. Das simple Kopieren der Datenbankdateien ist definitiv nicht möglich. Es lohnt sich also, einen solchen Übergang gut zu planen und eventuell mit einer Datenbankreorganisation zusammenzuführen. Die wichtigsten betriebssystemunabhängigen Werkzeuge, mit denen eine Migration von einer Plattform zur anderen möglich ist, sind Export und Import. Ihre Unabhängigkeit erlangen diese mit dem Exportdateiformat, das eine betriebssystemunabhängige Binär-Struktur hat und somit von einer Plattform zur anderen transferiert werden kann. Durch die Abwärtskompatibilität des Importwerkzeugs ist zusätzlich auch eine Versionsmigration möglich. Mit einigen Tricks2 – und dem Verzicht auf Beibehaltung neuester Merkmale – kann man sogar Daten in einen Export mit kleinerem Versionsstand entladen, so dass das Heruntermigrieren auf eine kleinere Versionsnummer im Bedarfsfall (z.B. wenn auf der Zielplattform die neueste Version noch nicht verfügbar ist) ebenfalls machbar ist. Die Oracle-Systemarchitektur ist – wie aus dem ersten Kapitel bekannt – als Mehrprozessarchitektur inklusive der Nutzung gemeinsamer Hauptspeicherbereiche bei allen Plattformen vorhanden; allein die Implementierung ist teilweise stark unterschiedlich. Damit sind auf allen Plattformen die Voraussetzungen für gute Skalierbarkeit mit den Hardwareressourcen gegeben. Vor der eigentlichen Installation sind – unabhängig vom gewählten Betriebssystem – die plattformspezifischen Installationsanweisungen zu beachten: Oft finden sich hier Hinweise auf erforderliche Betriebssystemversionen oder Patchlevel sowie im Betriebssystem zu konfigurierende Parameter. Eine Aufstellung der aktuellen Richtwerte an dieser Stelle macht leider keinen Sinn, da diese sich für neue Releases zu schnell ändern. Aktuelle Installationsanweisungen sind für die wichtigsten Plattformen im Oracle Technet (http://technet.oracle.com) frei verfügbar; außerdem sind entsprechende Anweisungen als HTML- und/oder PDF-Dokumente bei jeder Softwareauslieferung enthalten. Oracle unter Unix Durch die große Anzahl an Unix-Plattformen, die in den Unternehmen als Serverplattformen betrieben werden, ist der Einsatz von Oracle auf Unix-Systemen wohl immer noch die am meisten eingesetzte Variante. Aus diesem Grund ist das Unix2.
Hierbei handelt es sich um das Einspielen eines älteren Exportkatalogs sowie den Zugriff mit einem der Versionsnummer entsprechenden Exportwerkzeugs auf die Datenbanksoftware mit neuerer Versionsnummer.
Sandini Bib
Basis für die Oracle-Installation: Hardware und Betriebssystem
63
Derivat (Sun) Solaris auch die Entwicklungsplattform für die Oracle Database-Software; andere Derivate wie HP-UX, (IBM) AIX und (Compaq) Tru64 werden sehr schnell nach Verfügbarkeit der Solaris-Version freigegeben. Aufgrund der langjährigen Erfahrung der Oracle-Entwickler mit Unix-Systemen können den entsprechenden Oracle-Versionen sowohl große Stabilität als auch sehr gute PerformanceEigenschaften bescheinigt werden. Die Prozessarchitektur für die Oracle Database-Software ist de facto der Standard, der nur bei wenigen Ausnahmen modifiziert wird (siehe die Implementierung unter MS-Windows). PMON
SMON
DBW0
ARC0
LGWR
SNP0
CKPT
RECO
SGA
Server
Server
Server
Server
Abbildung 2.1: Oracle-Prozesse unter Unix mit Speicherstruktur SGA
Diese Struktur lässt sich sofort an der Ausgabe eines ps-Kommandos (in diesem Beispiel unter Solaris) nachvollziehen: UID oracle oracle oracle oracle oracle oracle oracle oracle oracle
PID PPID C STIME TTY 577 1 0 10:52:09 ? 569 1 0 10:52:09 ? 571 1 0 10:52:09 ? 581 1 0 10:52:09 ? 579 1 0 10:52:09 ? 573 1 0 10:52:09 ? 575 1 0 10:52:09 ? 583 1 0 10:52:09 ? 585 1 0 10:52:09 ?
TIME 0:00 0:00 0:00 0:00 0:00 0:00 0:00 0:00 0:00
CMD ora_smon_SUN901 ora_pmon_SUN901 ora_dbw0_SUN901 ora_snp0_SUN901 ora_reco_SUN901 ora_lgwr_SUN901 ora_ckpt_SUN901 ora_snp1_SUN901 ora_arc0_SUN901
Listing 2.1: Oracle-Prozesse
Die Interprozesskommunikation wird unter Unix grundsätzlich mit Semaphoren realisiert; der Zugriff auf den gemeinsamen Speicherbereich, die SGA, mit Shared Memory. Bei der Installationsvorbereitung ist darauf zu achten, dass beide Komponenten installiert und mit ausreichenden Parametern konfiguriert sind. Hierzu sind vor einer Installation unbedingt die plattformspezifischen Installationsanweisungen (Oracle9i Installation Guide) zu konsultieren. Je nach Plattform sind zusätzliche Schritte vor der eigentlichen Installation durchzuführen. Unter IBMs Unix-Derivat AIX wird z.B. ein spezieller, von Oracle mitgelieferter Post-Wait-Treiber für die Oracle-Interprozesskommunikation verwendet.
Sandini Bib
64
Installation und Basiskonfiguration
Dieser wird als AIX-Kernel-Erweiterung installiert und muss während der OracleInstallation bereits vorhanden sein. Typischerweise muss hierzu vom Oracle-Installationsmedium die Datei rootpre.sh als Benutzer root ausgeführt werden. Neben der Installation des Post-Wait-Treibers wird in diesem Script dafür gesorgt, dass im AIX Kernel der asynchrone I/O eingeschaltet ist, der ebenfalls von der Oracle-Software vorausgesetzt wird. Bei der Installation einer neueren Oracle-Version ist darauf zu achten, dass der Post-Wait-Treiber eventuell ebenfalls in der neuen Version benötigt wird (Kompatibilität der Versionen untereinander im Readme nachlesen!). Das bedeutet wiederum, dass eine eventuell vorhandene Instanz, die eine ältere Oracle-Version benutzt, für den Tausch des Post-Wait-Treibers heruntergefahren werden muss. Viele Unix-Anbieter liefern ihre Betriebssysteme in 64-Bit-Versionen aus oder bieten eine entsprechende Variante an. Der hierdurch mögliche riesige virtuelle Adressraum (264 Bytes = 16.777.216 Tbyte) ermöglicht – im Gegensatz zum virtuellen Adressraum von 4 GB bei 32-Bit-Versionen – ohne Probleme Prozessgrößen und Shared Memory-Konfigurationen von mehreren zehn Gbyte. Für diese UnixDerivate bietet Oracle 64-Bit-Versionen an, so dass entsprechend große SGA-Konfigurationen möglich sind. Da heute mit reellen Speichergrößen von einigen zehn Gbyte entsprechende Hardware-Ausbaumöglichkeiten vorhanden sind, kann der Einsatz einer solchen 64 Bit-Version erhebliche Vorteile bringen. Oracle unter MS-Windows Oracle-Installationen unter MS-Windows erfreuen sich sowohl in Entwicklungsund Test- als auch in produktiven Umgebungen sehr großer Beliebtheit. Generell wird bei Oracle-Installationen unter MS-Windows zwischen einer Clientund einer Server-Variante unterschieden. In diesem Buch ist grundsätzlich die Server-Variante gemeint, da nur hiermit die Installation der Oracle Database Standard und Enterprise Edition möglich ist. Die Client-Version erlaubt lediglich die Installation der Oracle Net-Produkte, diverse APIs sowie Entwicklungskomponenten und lässt sich auch unter MS-Windows 95/98/ME durchführen. Die Oracle ServerInstallation setzt im übrigen nicht voraus, dass eine MS-Windows Server-Version installiert ist; auch auf den MS-Windows NT/2000 Workstation-Varianten läuft die Oracle Database-Software problemlos. Dies ist insbesondere für Entwicklungs- und Übungsumgebungen auf Desktop PCs oder Laptops interessant. Viele spezielle Merkmale der Oracle-Software unter MS-Windows sorgen mittlerweile für eine sehr gute Integration in die Windows-Welt. Hierunter zählen u.a. die Integration der Alert-Informationen in die Windows-Ereignisanzeige, diverse Möglichkeiten zur Nutzung von Windows-Anmeldungen bei der Oracle-Autorisierung, die Verfügbarkeit zahlreicher Werkzeuge und Programmierschnittstellen sowie die schnelle Verfügbarkeit der kompletten Oracle-Software-Palette unter MS-Windows. Der letzte Punkt ist ausschlaggebend dafür, dass mit MS-Windows wohl die vollständigste Entwicklungsumgebung in-a-box für Oracle-basierte Systeme gegeben ist.
Sandini Bib
Basis für die Oracle-Installation: Hardware und Betriebssystem
65
Ein grundlegender Unterschied zwischen der Oracle-Implementierung unter MSWindows und praktisch allen anderen Implementierungen ist die Prozessarchitektur: Anstelle der sonst üblichen Multi-Prozess-Variante wurde der Oracle Server unter MS-Windows mit Hilfe der Multi-Threaded-Architektur des Betriebssystems implementiert. RECO CKPT SNP0 ARC0
SGA
LGWR DBW0 SMON PMON Server Server Server Server
Abbildung 2.2: Einzelprozess-Architektur unter MS-Windows mit Threads-Abbildung
Mit dieser Architektur ist eine Betriebssystem-Ressource wie Shared Memory für die SGA nicht notwendig, da Speicheranforderungen am Prozess durchgeführt werden und somit automatisch allen Oracle-Threads zur Verfügung stehen. Diese Architektur kann man mit dem MS-Windows Task-Manager nachvollziehen. Die Spalte THREADS in Abbildung 2.3 ist standardmäßig nicht eingestellt, sie muss erst über den Punkt SPALTEN AUSWÄHLEN im Menü ANSICHT aktiviert werden. Neben drei Threads, die grundsätzlich für den Oracle-Prozess gestartet sind, gibt es für jeden Oracle-Hintergrund-„Prozess“3 sowie für jeden Dedicated Server genau einen Thread, im Beispiel sind es insgesamt 13. Der Oracle-Prozess wird nicht als Anwendung auf der Oberfläche, sondern als Dienst gestartet. Nur so ist die Lauffähigkeit des Oracle-Systems ohne Abhängigkeit von einer Benutzeranmeldung am System möglich. Die Konfiguration von Diensten für Oracle-Instanzen wird in Kapitel 2.4 beschrieben.
3.
An dieser Stelle ist der „Prozess“ in seiner Oracle-Bedeutung gemeint!
Sandini Bib
66
Installation und Basiskonfiguration
Abbildung 2.3: Oracle-Prozess mit Threads unter MS-Windows
Oracle unter Linux Die Portierung der Oracle Database unter Linux hat sowohl im Lager der OracleAnhänger als auch im Lager der Linux-Anhänger, und natürlich erst recht in der nicht eben kleinen Schnittmenge, für große Begeisterung gesorgt: Oracle-Anhänger konnten nun auf der erschwinglichen PC-Plattform das Look-and-feel einer OracleInstallation auf einer „großen“ Unix-Plattform nachvollziehen und z.B. lauffähige Scripts und Programme unter Linux entwickeln. Und die immer größer werdende Schar der Linux-Anhänger hat mit der Oracle Database ein weiteres Produkt in der Liste der unter Linux lauffähigen Anwendungen, die immerhin als EntwicklerLizenz auch kostenlos vom Oracle Technet zu beziehen ist.4 Der Stand der Portierung von Oracle-Software unter Linux kann sich mittlerweile sehen lassen: Der Umfang der Oracle Database-Portierung bedient sowohl den Managementbereich mit dem Management Server und Enterprise Manager als auch spezielle Anforderungen z.B. mit dem Parallel Server bzw. Real Application Clusters. Weiterhin gibt es den Internet Application Server Oracle9iAS inklusive aller wichtigen Optionen sowie den Oracle Developer. Es fehlen – zum Zeitpunkt der Drucklegung – lediglich noch Produkte wie der JDeveloper und der Designer. Zumindest bei der Oracle Database kann dem Portierungsteam sehr gute Arbeit bescheinigt werden: Sowohl Installation als auch Betrieb der Oracle Database funktionieren auf praktisch allen Linux-Derivaten, die gewisse, gut dokumentierte Voraussetzungen, wie z.B. einen bestimmten Versionsstand der glibc, erfüllen, 4.
Natürlich gilt dies bei Oracle auch für andere Plattformen. Oracle-Lizenzkosten für produktive Systeme sind übrigens für alle Plattformen gleich. Aus Oracle-Sicht ist Linux also keineswegs eine „freie“ Plattform.
Sandini Bib
Installationsplanung
67
äußerst robust. Für wichtige Linux-Distributionen, wie z.B. Red Hat und SuSE, werden Kombinationen von Distributionen und Oracle Database mit Hilfe beider Hersteller getestet und zertifiziert. Es empfiehlt sich grundsätzlich, eine zertifizierte Kombination einzusetzen. Ansonsten gilt für die Oracle-Implementierung unter Linux alles, was bereits für Oracle unter Unix beschrieben wurde. Andere Betriebssysteme Nach wie vor gibt es Oracle-Portierungen auf weiteren Betriebssystemen, z.B. auf Compaq OpenVMS oder IBM MVS. Auch hier gibt es Eigenheiten und spezielle Eigenschaften, allerdings ist die Verbreitung der Oracle Database auf diesen Plattformen nicht sonderlich groß. Wir verweisen daher auf die jeweiligen Installationsanweisungen.
2.2
Installationsplanung
Die Einrichtung eines Oracle-Datenbanksystems wird nicht nur von dem technischen Verfahren bestimmt, in dessen Verlauf Software und Datenbank auf einem Rechner korrekt und fehlerfrei installiert werden. Sie wird vielmehr vorbereitet und begleitet von einer Vielzahl von Fragestellungen und Entscheidungen, die sich in die folgenden Planungsbereiche gliedern lassen:
: : :
Die versionstechnische Planung untersucht die Funktionalität von Merkmalen, die Stabilität und den vertraglich zugesicherten Support der betreffenden OracleVersion. Die betriebssystemspezifische Planung kümmert sich um die Verfügbarkeit, die Rahmenbedingungen und den Ressourcenverbrauch der geplanten Oracle-Version auf dem eingesetzten Betriebssystem. Die Instanz- und Datenbankplanung entscheidet, wie viele und welche Datenbanken auf welchen Rechnern aufgebaut und wie die einzelnen Systeme initialisiert und parametrisiert werden sollen.
Es versteht sich, dass die genannten Planungsbereiche nicht strikt voneinander getrennt sind, sondern sich gegenseitig beeinflussen. Am Ende einer solchermaßen umfassenden Installationsplanung steht ein Installationskonzept, welches klare Vorgaben im Rahmen der oben genannten Themenbereiche bietet. Dies im Einzelnen zu erörtern, ist das Ziel des folgenden Kapitels.
2.2.1
Versionstechnische Planung
Die versionstechnische Planung durchzuführen bedeutet festzulegen, ob und wann eine bestimmte Oracle-Version auf einem bestimmten Betriebssystem zum Einsatz kommt. Diese Frage entscheidet sich keinesfalls nur vor dem Hintergrund der produktiven Verfügbarkeit der betreffenden Version, sondern wird von einer Vielzahl zusätzlicher Faktoren bestimmt.
Sandini Bib
68
Installation und Basiskonfiguration
Ein „äußerer“ Faktor kann sich aus der begrenzten Unterstützungsdauer seitens des Herstellers ergeben. Für offiziell nicht mehr unterstützte Versionen werden keine neuen Patches erstellt, wohl aber bestehende ausgeliefert und telefonische Auskünfte gewährt. Im Fehlerfall kann dies unter Umständen zu unangenehmen Ausfällen führen, die eine Versionsaktualisierung notwendig machen. „Innere“ Faktoren ergeben sich aus der Verfügbarkeit oder Qualität von Softwaremerkmalen, die für geplante oder bestehende Anwendungen benötigt werden. Die Möglichkeit, Tabellen und Indizes zu partitionieren, kann beispielsweise eine Migration von Oracle7 nach Oracle8i oder Oracle9i rechtfertigen. Die geringere Fehlerrate oder größere Stabilität einer Version kann einen weiteren Auslöser für eine Aktualisierung darstellen. In manchen Fällen können sich jedoch unangenehme Abhängigkeiten zu bestehenden Anwendungen ergeben. Wenn diese für den neuen Release-Stand noch nicht freigegeben sind, kann es notwendig werden, vorhandene Instanzen aufzuteilen und die für die Migration nicht geeigneten Anwendungen unter der alten Version zu belassen. In den meisten Fällen empfiehlt es sich, eine dem eigenen Umfeld angepasste „Oracle-Versionspolitik“ auszuarbeiten und Versionen für das eigene Unternehmen gesondert freizugeben. Nach Verfügbarkeit einer Beta- oder produktiven Version wird eine entsprechende Testumgebung aufgebaut, in der die neue Software im Zusammenspiel mit allen für das Unternehmen kritischen Anwendungen getestet wird. Nach erfolgreichem Abschluss der Tests kann dann eine entsprechende Richtlinie für das Unternehmen herausgegeben werden. Abteilungen, die den uneingeschränkten Support des betreffenden Rechenzentrums – z.B. im Rahmen von Backup und Recovery – wünschen, können dann zur Einhaltung dieser Richtlinien verpflichtet werden. Diese Richtlinien beschränken sich in der Regel nicht nur auf die Version der Datenbank, sondern können ebenso Namenskonventionen und Installationsregeln umfassen.
2.2.2
Betriebssystemspezifische Planung
Die Oracle-Software hat sich naturgemäß in eine vorhandene Rechnerlandschaft einzugliedern. Oracle-Versionen sind auf Betriebssystemen zu unterschiedlichen Zeitpunkten und – in manchen Fällen – in unterschiedlicher Stabilität verfügbar. Mit jedem neuen Software-Release wächst bekanntlich auch der Verbrauch an Systemressourcen – Hauptspeicher sowie Plattenplatz. Darüber hinaus gilt es, die für eine Version minimal notwendige Betriebsystemversion zu beachten und bei Bedarf auch hier eine Aktualisierung vorzubereiten und rechtzeitig einzuleiten.
2.2.3
Die Planung von Instanzen und Datenbanken
Neben den Versions- und Betriebssystemfragen ist die Planung von Instanzen und ihnen zugeordneten Datenbanken von großer Bedeutung. Diese Planung wird vor allem dort wichtig sein, wo der Administrator die Aufgabe der Versionsanpassung mit der Reorganisation der Datenbanklandschaft verbinden möchte oder muss.
Sandini Bib
Installationsplanung
69
Bei der hier angesprochenen Planung von Datenbanken sollten vor allem folgende Aspekte Beachtung finden: Zum einen ist zu entscheiden, welche Anwendungen und Schemas zusammen in welcher Datenbank installiert und betrieben werden. Diesen Aspekt wollen wir hier als Datenbankmodell bezeichnen. Ähnlich einem Datenmodell sind hierbei auch die Beziehungen der einzelnen Datenbanken untereinander wichtig, etwa im Zusammenhang mit dem Einsatz der Replikation. Der einfache, zu Zeiten der Versionen 6 und 7 nahe liegende Leitsatz „jedes Projekt bekommt eine eigene Instanz und Datenbank“ kann sehr schnell eine Inflation von Instanzen nach sich ziehen, die den Administrator mit entsprechend komplexen Anforderungen in Sachen Backup, Recovery, Optimierung und Verfügbarkeit konfrontiert. Auf der anderen Seite kann eine ganzheitliche Lösung, bei der alle Daten eines Unternehmens in nur einer Datenbank gespeichert sind, den DBA oft vor unlösbare Tuning-Aufgaben stellen und – im Falle eines Systemabsturzes – das operationale Geschäft sämtlicher Abteilungen gefährden. Der zweite Aspekt, der bei der Installationsplanung Beachtung finden muss, ist die Festlegung all jener Datenbank-Parameter, die nicht oder nur mit großem Aufwand im laufenden Betrieb anpassbar sind – mit anderen Worten die Datenbankparametrierung, die bereits mit der Initialisierung der Datenbank festzulegen ist. Die Instanzplanung verfolgt im Wesentlichen zwei Ziele: 1. Eine für den DBA verwaltbare und überschaubare Datenbanklandschaft zu schaffen und 2. den einzelnen Anwendungen und Schemas eine in Sachen Verfügbarkeit und Laufzeitverhalten optimierte Umgebung zu bieten. Beide Aspekte werden im Folgenden näher erläutert. Das „Datenbankmodell“ Die Frage, welche Daten und Schemas und welche Anwendungen mit ihnen in welcher Datenbank installiert und betrieben werden sollen, lässt sich am besten vor dem Hintergrund der wesentlichen, zentralen Attribute einer Oracle-Datenbank und -Instanz erörtern. Die Festlegung der folgenden Datenbankattribute ist in diesem Zusammenhang wichtig:
:
Bestimmung der Blockgröße
Bis zur Version Oracle8i hat jede Datenbank eine globale Blockgröße, die über den Initialisierungsparameter db_block_size festgelegt wird und Größen zwischen 2Kbyte und 64Kbyte annehmen kann. Die Blockgröße stellt die kleinste Dateneinheit und I/O-Einheit dar, mit der das System arbeiten kann. Je größer der einzelne Block ist, desto mehr Daten(sätze) kann er enthalten. Dies führt u.a. zu „flacheren“ und damit effizienteren Indexbaumstrukturen sowie zu potenziell größeren Datenmengen pro Blockzugriff. Die internen Strukturen für die Verwaltung von Zeilensperren – so genannte Transaction Entries – werden innerhalb jedes Datenblockes angelegt. Je mehr Datensätze ein Block enthalten kann, desto mehr Ressourcen sollten daher für Zeilensperren auf-
Sandini Bib
70
Installation und Basiskonfiguration
gebaut werden5, um nicht mit einem erhöhten Risiko für Zugriffskonflikte konfrontiert zu werden. Da der minimale Platzbedarf für Tabellen 2 Oracle-Blöcke beträgt – ein Header- und ein Datenblock – steigt auf der anderen Seite bei großen Blöcken der minimale Speicherplatz, was für kleine Tabellen sehr schnell zu einem zusätzlichen Bedarf von Speicherplatz führen kann. Da die Blockgröße auch die Puffergröße im Cache bestimmt, sinkt – bei gleich bleibenden Cache-Größen – die Anzahl der Puffer und damit die Trefferquote. Auf Grund dieser Sachverhalte sind Datenbanken mit großen durchschnittlichen Satzlängen und einem großen Datenvolumen pro Objekt prädestiniert für Blockgrößen von 16Kbyte und mehr. Die erhöhten Blockgrößen reduzieren in diesem Fall das Aufteilen von Datensätzen über mehrere Blöcke (Row Splitting) und die Höhe der Indexbäume. Beides kann zu einem optimierten Zugriffsverhalten der Anwendungen beitragen. Für alle Datenbanken, die in diesem Sinne keine besonderen Anforderungen stellen, eignen sich Blockgrößen von 4Kbyte oder 8Kbyte. Beginnend mit der Version 9i ist es möglich, unterschiedliche Blockgrößen innerhalb einer Oracle-Datenbank zu definieren und dementsprechend separate Pufferbereiche für die unterschiedlichen Blockgrößen in der SGA anzulegen. Aus diesem Grunde können nun auch Anwendungen, die bisher auf Grund ihrer Speicheranforderungen separat installiert werden mussten, gemeinsam in einer Datenbank betrieben werden. Der oben erwähnte Initialisierungsparameter db_block_size bestimmt nun die Blockgröße für den SYSTEM-Tablespace und dient als Standardwert für die Blockgrößen der übrigen Tablespaces. Darüber hinaus lassen sich maximal vier weitere Blockgrößen zwischen 2Kbyte und 32Kbyte nutzen. Die gewünschte Blockgröße wird beim Anlegen eines Tablespace über die Blocksize-Klausel eingestellt. Für jede genutzte Blockgröße müssen zusätzliche Pufferbereiche in der SGA angelegt werden. Hierzu steht der Initialisierungsparameter db_Nk_cache_size zur Verfügung, wobei N durch die gewünschte Blockgröße zu ersetzen ist. Die Größe des Puffers für die Standardblöcke wird dagegen über den Parameter db_cache_size festgelegt. Alle Parameter geben die Größe des Puffers – z.B. 120Mbyte – und nicht die Anzahl der Puffer an. Die Parameter lassen sich darüber hinaus dynamisch mit Hilfe des Befehls ALTER SYSTEM bei laufender Datenbank ändern, sofern die für die SGA vorgegebenen Maximalgröße6 dabei nicht überschritten wird.
:
Festlegung des Zeichensatzes
Jede Datenbank hat einen normalen und einen länderspezifischen Zeichensatz für die Speicherung von Zeichenketten. Der normale Zeichensatz wird in den skalaren Datentypen CHAR, VARCHAR2, CLOB und LONG und darüber hinaus für Bezeichner von Tabellen, Spalten, Variablen und Programmeinheiten verwendet. Der länderspezifische Zeichensatz findet entsprechend in den Datentypen NCHAR, NVARCHAR2 und NCLOB seine Anwendung. Unterschiedliche Zeichensätze auf Seiten der Datenbank und der Clients werden durch Konvertierungen angepasst, sofern der Zieldatensatz alle Zeichen des Quellzeichensatzes enthält. Zeichen, die im Zielda5. 6.
Die Anzahl der transaction entries pro Datenblock lässt sich sehr einfach über den Storage-Parameter initrans festlegen. Bestimmt über den Initialisierungsparameter sga_max_size.
Sandini Bib
Installationsplanung
71
tensatz nicht dargestellt werden können, werden durch Ersatzzeichen – in den meisten Fällen ? – repräsentiert. Bei der Initialisierung der Datenbank sind entsprechend den Anforderungen der Anwendungen die geeigneten Zeichensätze auszuwählen. Sowohl der normale als auch der länderspezifische Zeichensatz können über einen einfachen Befehl7 angepasst werden. Diese Anpassung kann aber nur dann erfolgen, wenn der neue Zeichensatz eine strikte Obermenge des aktuellen Zeichensatzes darstellt. In allen anderen Fällen muss die Anpassung stets – sehr aufwändig – durch einen vollständigen Neuaufbau der Datenbank erfolgen! Eine gültige Neudefinition ist beispielsweise die Umstellung von US7ASCII nach WE8SO8859P1.
:
Festlegung des Datenbanknamens
Jede Datenbank hat einen globalen Namen, der – in verteilten Umgebungen – die Namensgebung von Datenbankverbindungen (database links) bestimmt.8 Der globale Name einer Oracle-Datenbank wird bei der Initialisierung aus den Initialisierungsparametern db_name und db_domain gebildet, also z.B. lager.database_consult.de für db_name = lager und db_domain = database_consult.de. Obwohl der Name nachträglich über den ALTER DATABASE-Befehl9 geändert werden kann, empfiehlt es sich, bereits bei der Initialisierung der Datenbank eine sinnvolle Entscheidung zu treffen. Bei Verwendung des globalen Namensmodells ist es zwingend notwendig, dass die Namen der Datenbankverbindungen mit den globalen Namen der Zieldatenbanken übereinstimmen.
:
Version des Datenbankkerns
Jede Datenbank ist an eine Version gebunden und damit an die in dieser Version verfügbaren softwaretechnischen Merkmale. Die Verfügbarkeit von Merkmalen kann darüber hinaus mit Hilfe des Initialisierungsparameters compatible kontrolliert werden. Auf diese Weise kann eine installierte Datenbankversion nach unten „korrigiert“ werden. Der Parameter compatible muss allerdings für alle Instanzen einer Datenbank identisch gesetzt werden.
:
Festlegung des Transaktionsmanagements
Bis zur Version Oracle8i hat jede Datenbank einen Satz von Rollback-Segmenten, die das Rollback-Volumen aller Transaktionen bewältigen müssen. Die in einer Datenbank definierten Rollback-Segmente müssen in Anzahl und Größe so ausgelegt sein, dass sie das Datenvolumen aller Transaktionen bewältigen können, die zu einem Zeitpunkt in die Datenbank schreiben. Jede Transaktion schreibt dabei während ihrer gesamten Dauer nur in ein Rollback-Segment; dieses muss entsprechend dem Umfang der betreffenden Transaktion und dem Umfang aller weiteren ihm zugewiesenen Transaktionen gewachsen sein. Gleichzeitig sollten für alle lesenden Transaktionen genügend Daten für die Rekonstruktion lesekonsistenter Sichten vorliegen. Die Befehle lauten: alter database character set ; bzw. alter database national character set ; 8. Dies gilt für Instanzen, bei denen das globale Namensmodell eingeschaltet ist (Initialisierungsparameter global_names = true). 9. alter database rename global_name to ;
7.
Sandini Bib
72
Installation und Basiskonfiguration
Standardmäßig verteilt Oracle die Transaktionen gleichmäßig nach ihrer Anzahl – nicht nach ihrer Größe – auf alle aktiven Rollback-Segmente der betreffenden Instanz. Die Zuweisung einer Transaktion an ein bestimmtes Rollback-Segment ist nur explizit über den SET TRANSACTION-Befehl10 möglich und erfordert demnach einen entsprechenden Eingriff in den Programmcode. Diese explizite Zuweisung ist für alle Transaktionen empfehlenswert, deren Volumen die „normalen“ RollbackSegmente überfordern würde. Da in der Regel auf eine Datenbank Transaktionen mit stark voneinander abweichenden Umfängen zukommen, ist es Aufgabe des Administrators, Rollback-Segmente unterschiedlicher Größen im System anzulegen, um so den gestellten Anforderungen gerecht zu werden. Je größer das System ist, desto diffiziler ist diese Aufgabe. Ab der Version Oracle9i können Rollback-Segmente durch einen Undo-Tablespace ersetzt werden, der ein gemeinsames Reservoir für alle Rollback-Daten eines Systems bietet und dadurch die oben beschriebene Aufgabe ganz wesentlich vereinfacht. Über den Initialisierungsparameter undo_management wird für jede Instanz die Art des Transaktionsmanagements festgelegt, der Wert auto schaltet auf die hier besprochene Methode des automatischen Rollbackmanagements. Der Undo-Tablespace ist zuvor über den Befehl CREATE UNDO-TABLESPACE anzulegen und mit dem Initialisierungsparameter undo_tablespace für die betreffende Instanz zu reservieren. In Oracle9i wird alternativ auch noch die herkömmliche Nutzung von Rollback-Segmenten unterstützt.11 Die oben beschriebene automatisierte Methode bietet jedoch flexiblere Möglichkeiten der Transaktionsverwaltung.
:
Die Festlegung des Datenbankmodus
Jede Datenbank hat einen Datenbankmodus, der ihr Verhalten im Falle von Backupund Recovery-Operationen bestimmt. Oracle-Datenbanken können im Archivelogoder Noarchivelog-Modus betrieben werden. Der Datenbankmodus legt fest12, ob alle Datenmodifikationen – in Form von so genannten Offline-Redolog-Dateien – fortlaufend archiviert werden oder nicht. Für Datenbanken im Archivelog-Modus können Online-Sicherungen sowie vollständige und unvollständige Recovery-Aktionen durchgeführt werden, bei denen auch Transaktionen, die nach der Sicherung durchgeführt wurden, rekonstruiert werden können. Datenbanken im Noarchivelog-Modus dagegen können nur offline gesichert werden. Ihr Recovery beschränkt sich auf das Einspielen der Offline-Sicherung; nach der Sicherung durchgeführte Transaktionen gehen damit verloren. Anwendungen, die auf Grund der oben dargestellten Merkmale zusammenpassen, d.h.
: :
gleiche Anforderungen an die Oracle-Blockgröße haben, gleiche Anforderungen an den normalen und länderspezifischen Zeichensatz haben,
10. set transaction use rollback segment ; 11. Über den Initialisierungsparameter undo_management = manual 12. Die Einstellung erfolgt in der Mount-Phase über den Befehl alter database archivelog;
Sandini Bib
Installationsplanung
: : :
73
mit gleichen Datenbankversionen arbeiten können, über ein gemeinsames Transaktionsmanagement betrieben werden können, gleiche Voraussetzungen für Backup und Recovery erfordern,
und darüber hinaus die Ressourcen – Plattenplatz und Memory – einer gegebenen Hardware-Plattform nicht überfordern, können prinzipiell gemeinsam in einer Datenbank konfiguriert und über eine oder mehrere Instanzen13 bedient werden. Die in den Oracle-Versionen Oracle8i und Oracle9i realisierte Datenbanktechnik ist mittlerweile wesentlich effizienter als früher in der Lage, sehr große Mengen an Daten, Benutzern und Datenbanksitzungen zu verwalten und kann ebenso sehr große Speicherbereiche – für die System Global Area – effizient nutzen. Durch die damit mögliche Reduzierung der Anzahl der Datenbanken lassen sich die Aufgaben der Administratoren weitaus besser und effizienter umsetzen, und einer „Inflation von Instanzen“ mit allen ihren administrativen Alpträumen kann wirkungsvoll begegnet werden. Die Datenbank-Parametrierung Sind im Rahmen des Datenbankmodells die Entscheidungen gefallen, welche Anwendungen in welchen Datenbanken und Instanzen installiert werden, können die einzelnen Systeme parametrisiert werden. Einige der Parameter – wie z.B. die Blockgröße, die Zeichensätze, der globale Name und der Datenbankmodus – können direkt aus den Anforderungen des Datenbankmodells abgeleitet werden. Darüber hinaus sollten jedoch weitere Parameter, wie zum Beispiel die Puffergrößen, geplant werden. Eine wesentliche Neuerung unter Oracle9i sind die dynamisch änderbaren Speicherparameter. Durch die Möglichkeit, während der Laufzeit die Werte für die verschiedenen Pufferbereiche der SGA anzupassen, lassen sich die Systeme – auch ohne Neustart – an veränderte oder unbekannte Anforderungen anpassen. Unter Oracle8i dagegen erfordern die Änderungen dieser Initialisierungsparameter immer einen Neustart der Instanz. Im Einzelnen sind die folgenden Entscheidungen zu treffen:
:
Die Größe der Blockpuffer (database buffer cache) festlegen.
Der Blockpuffer speichert Kopien von Oracle-Blöcken aus den Datendateien der Datenbank. Er ist Teil der System Global Area. Seine Größe wird bis zur Version Oracle8i über den Initialisierungsparameter db_block_buffers festgelegt, der die Anzahl der Puffer bestimmt. Unter Oracle9i sind hierfür die im Abschnitt Das „Datenbankmodell“ beschriebenen Parameter db_cache_size und db_Nk_cache_size zuständig, welche die Größe des Pufferbereiches und nicht die Anzahl der Puffer festschreiben. Neben diesen Standardbereichen lassen sich unter Oracle noch Blockpuffer mit alternativen Ein- und Ausgabealgorithmen definieren: der Keep-Pool – für Objekte, die konstant im Puffer gehalten werden sollten – und der Recycle-Pool – für Objekte, die nur kurzzeitig im Speicher verbleiben sollen. Beide letztgenannten Berei-
13. Die Oracle-Parallel-Server-Konfiguration erlaubt den Zugriff über mehrere Instanzen auf eine Datenbank. Die Instanzen können in einer Cluster- oder Massiv-Parallel-Umgebung konfiguriert sein.
Sandini Bib
74
Installation und Basiskonfiguration
che sind sowohl unter Oracle8i14 als auch unter Oracle9i15 verfügbar und operieren in beiden Versionen nur mit der Standardblockgröße (db_block_size). Bei einer neu zu initialisierenden Datenbank ist es praktisch unmöglich, die optimale Größe der Blockpuffer festzulegen. Hier wird zunächst ein Schätzwert eingestellt und dann – nach vollständiger Installation und einer „Warmlaufperiode“ – durch entsprechende Tuning-Maßnahmen der optimierte Wert ermittelt und übernommen. Die während der Installation bereitgestellte Parameterdatei enthält bereits einige Vorgaben für „kleine“, „mittlere“ und „große“ Systeme. Die Vorgaben können über entsprechende Kommentarzeichen aktiviert und deaktiviert werden.
:
Die Größe des gemeinsamen Pools (Shared Pool) festlegen.
Der gemeinsame Pool speichert u.a. Informationen aus dem Data Dictionary (dictionary cache), ausführbaren PL/SQL-Programmcode und Zugriffspfade für ausgeführte SQL-Befehle (shared SQL areas). Die Größe des gemeinsamen Pools wird über den Initialisierungsparameter shared_pool_size festgelegt. Ähnlich dem Buffer Cache, ist auch der gemeinsame Pool erst durch genaues Messen optimierbar. Auch er kann ab der Version 9 dynamisch bei laufendem System angepasst werden.
:
Verzeichnisstrukturen und Dateinamen festlegen.
Jede Oracle-Datenbank besteht aus 3 Gruppen von Dateien: Kontrolldateien (control files) enthalten u.a. Listen aller Dateien einer Datenbank sowie interne Systeminformationen, die u.a. für Backup- und Recovery-Aktionen sowie für die Konsistenzsicherung (checkpoints) notwendig sind. Entsprechend sind Zugriffe auf Steuerdateien – im Vergleich zu denen der anderen Gruppen – eher gering an der Zahl. Datendateien enthalten alle Benutzer- und Metadaten der betreffenden Datenbank. Die Häufigkeit und die Art der Zugriffe hängt vom Zugriffsverhalten der abhängigen Anwendungen und darüber hinaus auch von der Größe des BufferCache ab – je größer der Buffer-Cache, desto geringer die Anzahl der physischen Zugriffe. Der Zugriff auf Datendateien erfolgt stets wahlfrei. Redolog-Dateien enthalten Änderungsprotokolle, die durch Datenmanipulationen generiert werden und über den Logpuffer der System Global Area in die Redolog-Dateien geschrieben werden. Redolog-Dateien werden im laufenden Datenbankbetrieb nur geschrieben, während eines Recovery dagegen auch gelesen. Zugriffe auf Redolog-Dateien erfolgen stets sequenziell. Die Schreibhäufigkeit hängt ganz von der DML-Charakteristik des betreffenden Systems ab. In vielen Fällen gehören die Redolog-Dateien jedoch zu den im Hinblick auf die Ein- und Ausgabe am intensivsten genutzten Dateien eines Oracle-Systems.
14. Initialisierungsparameter buffer_pool_keep und buffer_pool_recycle 15. Initialisierungsparameter db_keep_cache_size und db_recycle_cache_size. Die Werte können dynamisch geändert werden.
Sandini Bib
Universal Installer: Konzepte und Installationsprozedere
75
Die Installationsplanung hat auf der einen Seite die Aufgabe, ein Regelwerk zum Aufbau von Verzeichnisstrukturen166und Namenskonventionen zu schaffen, welches den Administratoren eine schnelle Orientierung auf unterschiedlichen Rechnern des Unternehmens erlaubt und auch Scripts besser portierbar macht. Ab der Version Oracle9i ist es möglich, Dateien der drei oben beschriebenen Dateigruppen vollständig über die Datenbank zu verwalten (Oracle Managed Files). Die Datenbank übernimmt in diesem Fall nicht nur das Anlegen, sondern auch das Löschen der Dateien, z.B. dann, wenn der betreffende Tablespace gelöscht wird. Das automatisierte Dateimanagement wird über unterschiedliche Initialisierungsparameter aktiviert: db_create_file_dest bezeichnet das – bereits vorhandene – Verzeichnis, welches die Datendateien aufnehmen soll. Die Verzeichnisse für die Redolog-Dateien und die Steuerdateien werden durch db_create_online_log_dest_N vorgegeben. _N wird dabei durch eine positive Ganzzahl ersetzt, die den Grad der Spiegelung bestimmt. Für die einfache Spiegelung ist der Parameter zweifach – mit N = 1 und 2 – zu setzen. Daten- und Redolog-Dateien werden mit einer anfänglichen Größe von 100Mbyte erzeugt. Alle genannten Parameter sind sowohl auf der Ebene der gesamten Datenbank als auch auf der Ebene einer einzelnen Datenbanksitzung änderbar. Auf diese Weise lassen sich Dateien eines Typs auch über unterschiedliche Verzeichnisse verteilen, was bei großen Installation zur Verteilung der Ein- und Ausgabeoperationen sinnvoll ist. Auf der anderen Seite sind die Dateien jeder Oracle-Datenbank den I/O-Anforderungen entsprechend sinnvoll zu verteilen. Als Minimalforderung für produktive Systeme gilt hier die strikte Trennung von Steuer-, Daten- und Redolog-Dateien auf den Platten des Systems.
2.3
Universal Installer: Konzepte und Installationsprozedere
2.3.1
Interaktive Softwareinstallation
Viele Werkzeuge wurden seit der Entwicklung von Oracle8i in Java neu geschrieben. Dies betrifft auch das Installationswerkzeug Oracle Universal Installer, das nunmehr in der Version 2 vorliegt. Der Grund für die Entwicklung eines neuen Installationswerkzeugs lag in dem Bestreben, ein identisches Werkzeug für alle Oracle-Plattformen anbieten zu können. Die Auswahl von Java als Programmiersprache hierfür erfolgte im Rahmen der derzeitigen Strategie im Hause Oracle, für Eigenentwicklungen verstärkt Java einzusetzen. Diese Strategie hat den Vorteil, dass der Universal Installer auf allen Plattformen identisch aussieht und fast identisch zu bedienen ist. Ein Nachteil gegenüber allen bisher bekannten Versionen ist der sofort nachvollziehbare Speicherhunger von 16. Oracle bietet hierzu die so genannte OFA-Struktur an (Oracle Flexible Architecture).
Sandini Bib
76
Installation und Basiskonfiguration
Java-Anwendungen schon beim ersten Start. Allein das weiter unten abgebildete Einstiegsbild bringt es auf gut 10 Mbyte Hauptspeicherbedarf für die Java RuntimeUmgebung; im Verlauf einer Installation kann sich dieser Bedarf vervielfachen. Das Konzept des Universal Installers sieht vor, alle Oracle-Installationen auf einer Maschine zentral zu verwalten. Weiterhin gibt es die Möglichkeit, die Installationsroutine anzupassen und z.B. eigene Software mit der Oracle-Software auszuliefern. Der Universal Installer läuft interaktiv ausschließlich im Grafik-Modus. Vollbildschirm-Alternativen, wie z.B. die Versionen des „alten“ Oracle Installers unter Unix, gibt es grundsätzlich nicht mehr. Auf den meisten Plattformen wird davon ausgegangen, dass ein X-Server vorhanden ist, über den die grafischen Ein- und Ausgaben gemacht werden können; bei MS-Windows wird natürlich die eigene Oberfläche genutzt.
Abbildung 2.4: Einstiegsbild des Universal Installers
Als Erstes fällt dem erfahrenen Oracle-Administrator auf, dass der Universal Installer in Deutsch erscheint, obwohl keine Variable aus dem Oracle NLS-Umfeld das verlangen würde. Dieses Verhalten haben alle getesteten Java-Werkzeuge aus dem Hause Oracle gemeinsam: Sie schauen nicht auf die im Oracle-Umfeld üblichen NLS-Variablen, sondern auf die Spracheinstellungen im Betriebssystem, also die Systemsteuerung unter Windows bzw. die Variable LANG unter Unix. Tipp: Viele häufig vorkommende Probleme bei der Installation unter Unix können vermieden werden, wenn durch den Befehl unset LANG
die Variable auf den Standard (Englisch!) zurückgesetzt wird.
Sandini Bib
Universal Installer: Konzepte und Installationsprozedere
77
Weiterhin fällt auf, dass es einen Punkt INSTALLIERTE PRODUKTE... gibt. Folgendes Fenster erscheint, sobald man diesen Schalter betätigt.
Abbildung 2.5: Anzeige der installierten Produkte
Man kann mit dem Universal Installer alle Oracle-Installationen eines Systems anschauen, alle Installationen ab Release 8.1.5 auch bearbeiten, z.B. patchen oder löschen. Für die Deinstallation von Oracle-Produkten kann man in diesem Fenster die entsprechenden Kontrollkästchen markieren und die Aktion mit dem Schalter ENTFERNEN... durchführen. Wählt man im Einstiegsbild den Schalter WEITER aus, so gelangt man zur Auswahl der Quell- und Zielverzeichnisse. Falls von CD installiert wird, ist das passende Verzeichnis als Quelle voreingestellt; im Falle einer Installation von einer Festplatte muss man über den DURCHSUCHEN...- bzw. BROWSE...-Schalter das Verzeichnis suchen, in dem die Datei products.jar zu finden ist. Die Oracle-Software wird in das angegebene Zielverzeichnis installiert. Das OracleSoftware-Installationsverzeichnis wird mit der Umgebungsvariablen ORACLE_HOME bezeichnet. Unter MS-Windows muss zusätzlich zu den Quell- und Zielpfaden ein Name für die Oracle-Installation eingegeben werden (im o.a. Beispiel 0901), d.h., das ORACLE_HOME erhält einen Bezeichner. Dieser Oracle Home Name wird zur Identifikation in der Registrierung und in einigen MS-Windows-spezifischen Werkzeugen benutzt. Um das praktisch identische Aussehen des Universal Installers auf den verschiedenen Plattformen zu belegen, folgt ein Bild der entsprechenden Stelle der Installation unter Solaris.
Sandini Bib
78
Installation und Basiskonfiguration
Abbildung 2.6: Auswahl für Installationsquelle und -ziel unter Windows
Abbildung 2.7: Auswahl für Installationsquelle und -ziel unter Solaris
Sandini Bib
Universal Installer: Konzepte und Installationsprozedere
79
Auswahl der Softwarekomponenten Grundsätzlich hat man bei der Installation von Oracle-Software die Auswahl zwischen einem oder mehreren vordefinierten Paketen und der flexiblen benutzerdefinierten Variante (Custom). Die sicherste Methode, das zu installieren, was man haben will, ist die letztgenannte Methode. Bei den Paketen wird eine mehr oder weniger sinnvolle Vorauswahl seitens der Oracle-Softwareingenieure getroffen. Weiterhin wird bei allen Nicht-Custom-Installationen eine Datenbank zwangsweise mitinstalliert. Der Autor bevorzugt die Trennung der Vorgänge SoftwareInstallation und Aufsetzen einer Datenbank. Unbedingt empfehlenswert ist die Vorgehensweise, nur die Softwarekomponenten zu installieren, die tatsächlich bzw. mit großer Wahrscheinlichkeit gebraucht werden – zu viel „Software-Müll“ auf der Festplatte tut grundsätzlich nicht gut. Weiterhin ist es notwendig, bei der Installation den Lizenzvertrag zur Hand zu haben, da viele der installierbaren Komponenten auf der CD zusätzlich zur Oracle DatabaseSoftware erworben werden müssen bzw. ohne Lizenz auch nicht installiert werden dürfen. Grundsätzlich sollten je nach Lizenzvertrag folgende Komponenten ausgewählt werden:
: : : : : : :
Oracle Database Standard bzw. Enterprise Edition17 Optionen Net Server und Net Client SQL*Plus (für Administrationszwecke) Universal Installer Plattformspezifische Dokumentation Intelligent Agent
Weitere Enterprise Manager-Komponenten wie die Console oder der Management Server sollten ausschließlich auf die dafür vorgesehenen Rechner installiert werden, z.B. die Console auf dem Arbeitsplatzrechner des Administrators. Verzeichnis des Universal Installers Wählt man den Universal Installer bei der Installation selbst als zu installierende Softwarekomponente aus (was unbedingt zu empfehlen ist), so wird ein eigenes Zielverzeichnis hierfür bestimmt, das nicht innerhalb des ORACLE_HOME-Verzeichnisses liegt. Unter MS-Windows ist das standardmäßig <Systemlaufwerk>:\Programme\Oracle\oui, unter Unix bei gesetzter ORACLE_BASE-Variable $ORACLE_BASE/ oui. Der Grund hierfür ist, dass eine Version des Universal Installers – nämlich immer die neueste – für alle Oracle-Installationen auf einem Rechner zuständig ist. Die 17. Die verschiedenen Editionen werden bei Oracle8i auf verschiedenen CDs, bei Oracle9i als Auswahloptionen auf einer CD ausgeliefert.
Sandini Bib
80
Installation und Basiskonfiguration
Scripts für den Universal Installer sind aufwärtskompatibel, d.h., ein neuerer Universal Installer kann ältere Installationen bearbeiten sowie löschen. Das ermöglicht beim Abfragen der installierten Produkte eine Gesamtübersicht wie in Abbildung 2.5. Ähnlich wie der Universal Installer werden auch das von Oracle mitgelieferte Java Runtime Environment sowie das Oracle-Software-Inventarverzeichnis [Ora]Inventory an zentraler Stelle abgelegt.
2.3.2
Silent-Installation mit Konfigurationsdateien
Neben der beschriebenen interaktiven Installation gibt es die Möglichkeit, die Installationsparameter in einer Konfigurationsdatei zu beschreiben. Der Universal Installer kann dann im Silent-Modus unter Angabe der Konfigurationsdatei gestartet werden, so dass die Installation ohne weitere Interaktion laufen kann. Diese Art der Installation empfiehlt sich z.B.,
: : : :
wenn mehrere Installationen gleicher Art vorgesehen sind, wenn bereits die Anforderung besteht, Installationen per Script durchführen zu können, (oft bei Client-Installationen in größeren Umgebungen), wenn die Installation aus anderen Gründen nachvollziehbar gemacht werden soll, oder wenn keine grafische Ausgabe des Universal Installer gewünscht ist.18
Die Konfigurationsdatei wird in der Oracle-Dokumentation als Response File (Antwortdatei) bezeichnet. Templates für verschiedene Installationstypen (z.B. CustomInstallation) werden mit der Oracle-Software im Verzeichnis response ausgeliefert. Es empfiehlt sich, eine Konfigurationsdatei zu kopieren und entsprechend den eigenen Wünschen zu bearbeiten. Die Installation wird durchgeführt mit dem Aufruf -silent –responseFile
Bitte beachten Sie unbedingt die Schreibweise der Option -responseFile!
2.3.3
Konfiguration der Oracle-Umgebung
Zusätzlich zur Installation der Oracle-Software muss eine Konfiguration mit den Mitteln des jeweiligen Betriebssystems erfolgen. Grundsätzlich werden hierzu Umgebungsvariablen benutzt. Die Art und Weise, wie Umgebungsvariablen für eine Oracle Konfiguration verwaltet werden, unterscheidet sich für die verschiedenen Betriebssysteme erheblich.
18. Grundsätzlich muss jedoch eine solche grafische Ausgabemöglichkeit existieren, da sonst der Installer nicht gestartet werden kann.
Sandini Bib
Universal Installer: Konzepte und Installationsprozedere
81
Bei der detaillierten Betrachtung ist es zunächst wichtig, wie entsprechende Variablen abgelegt werden und wie sie modifiziert bzw. für spezielle Aufgaben übersteuert werden können. Weiterhin ist die Behandlung von mehreren Oracle-Installationen auf einem System interessant. Oracle-Umgebung unter Unix Unter Unix werden grundsätzlich Shell-Variablen verwendet, d.h., bei der Benutzung von Oracle-Programmen ist dafür Sorge zu tragen, dass im Vorfeld die passenden Variablen gesetzt werden. Bei Benutzern, die interaktiv mit Oracle-Programmen arbeiten, empfiehlt es sich, entsprechende Kommandos für den Sitzungsstart (z.B. in die Datei .profile) einzutragen. Eine grundsätzliche Empfehlung ist, ein Script zum Setzen der Oracle-Umgebung zentral abzulegen und von den benutzerspezifischen Scripts aufzurufen. Spätestens bei einer Migration der Oracle-Software stellt es sich als immenser Vorteil heraus, nicht für 300 Benutzer alle Scripts ändern zu müssen... Ein Script zur Einstellung der wichtigsten Variablen wird bei der Oracle-Installation weder mitgeliefert noch erzeugt, so dass man hier selbst tätig werden muss. Die wichtigsten Umgebungsvariablen zum Auffinden einer Instanz sind deren Name ORACLE_SID, das zugehörige Installationsverzeichnis ORACLE_HOME sowie der Eintrag ORACLE_HOME/bin in die PATH-Variable. Damit diese Einträge weitestgehend automatisiert gesetzt werden können, wird zunächst die Verbindung zwischen Instanzname und Installationsverzeichnis in der Datei oratab abgelegt. Bei den meisten Unix-Derivaten wird diese Datei im Verzeichnis /etc abgelegt, bei System V Release 4-Derivaten (wie z.B. Solaris) im Verzeichnis /var/opt/oracle. Die Datei sieht für eine Beispielkonfiguration wie folgt aus: # # --- Hier fehlen einige Zeilen Originalkommentare von Oracle. --# SUNREP:/app/oracle/product/8.1.7:N SUN806:/app/oracle/product/8.0.6:N SUN817:/app/oracle/product/8.1.7:N SUN734:/app/oracle/product/7.3.4:N SUNDB:/app/oracle/product/9.0.1:N Listing 2.2: oratab
Die Syntax ist recht einfach zu interpretieren: Kommentarzeilen fangen mit „#“ an; gültige Zeilen haben die Form ::
Hierbei steht für die Frage, ob die Scripts dbstart und dbstop, die Oracle für den automatischen Systemstart mitliefert, die Instanz berücksichtigen sollen. Die ebenfalls mitgelieferten Scripts oraenv (für Bourne- und Korn-Shells) und coraenv (für die C-Shell) setzen nach Eingabe des Instanznamens alle oben genannten Variablen, wobei in der PATH-Variablen ein eventuell bereits vorhande-
Sandini Bib
82
Installation und Basiskonfiguration
nes ORACLE_HOME/bin-Verzeichnis ersetzt wird. Der folgende Ausschnitt einer Sitzung unter Solaris zeigt das Umschalten von der Instanz SUN806 auf die Instanz SUN817. hlsun1:oracle% echo $PATH /usr/bin:<...>:/app/oracle/product/8.0.6/bin hlsun1:oracle% echo $ORACLE_SID $ORACLE_HOME SUN806 /app/oracle/product/8.0.6 hlsun1:oracle% . oraenv ORACLE_SID = [SUN806] ? SUN817 hlsun1:oracle% echo $PATH /usr/bin:<...>:/app/oracle/product/8.1.7/bin hlsun1:oracle% echo $ORACLE_SID $ORACLE_HOME SUN817 /app/oracle/product/8.1.7 Listing 2.3: oraenv
Bei der Ausführung ist unbedingt darauf zu achten, dass dem Aufruf von oraenv ein Punkt und ein Leerzeichen vorausgehen. Andernfalls wird zur Ausführung des Scripts eine Subshell eröffnet, die nach dem Ändern der Parameter sofort wieder beendet wird, d.h., es erfolgt keine Änderung der Variablen! Die nicht interaktive Ausführung von oraenv und coraenv (z.B. für die Ausführung innerhalb von Scripts) kann man durch Setzen der Variablen ORAENV_ASK erreichen. Dann kann man im Script den Instanznamen setzen und oraenv aufrufen: ORAENV_ASK=NO export ORAENV_ASK ORACLE_SID=SUN817 export ORACLE_SID . oraenv unset ORAENV_ASK Listing 2.4: ORAENV_ASK
Die Scripts oraenv und coraenv werden mit dem Script root.sh in ein auswählbares Verzeichnis, typischerweise wird hier /usr/local/bin oder /usr/lbin gewählt, installiert. Es ist natürlich darauf zu achten, dass dieses Verzeichnis in der PATHVariablen vorkommt. Bei der Einrichtung der Oracle-Umgebung ist außerdem sicherzustellen, dass die folgenden Variablen ebenfalls gesetzt werden: ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data NLS_LANG=American_Germany.WE8ISO8859P1
Dabei bezeichnet ORA_NLS33 den Pfad zu den Dateien, die von Oracle zur Benutzung diverser Zeichensätze benötigt werden. NLS_LANG setzt die Werte Sprache, Gebiet und Zeichensatz der National Language Support-Umgebung, wobei es im deutschen Sprachraum insbesondere auf das Setzen eines Zeichensatzes ankommt. Beachtet man dies nicht, so wird der Standardzeichensatz US7ASCII angenommen,
Sandini Bib
Universal Installer: Konzepte und Installationsprozedere
83
der keinerlei Umlaute enthält. NLS_LANG sollte daher grundsätzlich gesetzt sein und einen Zeichensatz enthalten, der alle wichtigen Zeichen der Datenbank enthält, damit z.B. unbeabsichtigtes Eliminieren von Umlauten während eines Exports vermieden wird. Eine geeignete Stelle zum Setzen der zusätzlichen Variablen ist das Ende der Datei oraenv bzw. coraenv, bei der die entsprechenden Zeilen hinter den folgenden
Kommentarzeilen eingefügt werden können: # # Install any "custom" code here # Mehrere Instanzen auf einem System Es ist problemlos möglich, auf einem System mehrere Datenbanken aufzusetzen. Diese werden von jeweils einer Instanz betrieben, so dass auf einem System mehrere Instanzen gleichzeitig laufen. Bitte beachten Sie unbedingt, dass die laufenden Instanzen sich die zur Verfügung stehenden Ressourcen auf der Maschine teilen müssen!
Der einfachste Fall für diese Konstellation ist, dass man alle Instanzen mit der gleichen Software betreibt, d.h., die oratab enthält für alle Instanzen den gleichen ORACLE_HOME-Eintrag. Das Ergebnis eines Aufrufs von oraenv würde ausschließlich die Variable ORACLE_SID ändern. Daher reicht es – nur für diesen einfachen Fall – aus, die ORACLE_SID als einzige Variable zu ändern. Mehrere Installationen auf einem System Durch die Installationen mehrerer Oracle-Versionen in verschiedenen Verzeichnissen ist es ebenfalls möglich, verschiedene Instanzen mit unterschiedlichen Versionen zu betreiben. Hier ist zunächst zu beachten, dass sich der Hauptspeicherbedarf im Unterschied zur Variante mit einer Softwareinstallation für mehrere Instanzen nochmals erhöht, da die Instanzen unterschiedliche Executables verwenden.
Ein Grund für das Vorhandensein mehrerer Versionen auf einem System ist z.B., dass die vorhandenen Datenbanken i.A. nicht gleichzeitig auf ein neueres Release migriert werden. Mit dieser Vorgehensweise kann zunächst ein Testsystem mit einem neuen Release ausprobiert werden, bevor das produktive System umgestellt wird. Beim Wechsel der Umgebung zu einer anderen Instanz muss in diesem Fall oraenv oder coraenv aufgerufen werden, da mehrere Variablen (ORACLE_HOME, PATH, ...) geändert werden müssen. Automatisierter Ablauf über die crontab Regelmäßig auszuführende Aktionen werden auf Unix-System meist über den crontab-Mechanismus gesteuert. Hierbei ist zu beachten, dass Scripts, die aus der crontab eines bestimmten Benutzers gestartet werden, nicht die gleiche Umgebung besitzen wie die Shell dieses Benutzers nach einem Login, da Start-Scripts wie .profile nicht automatisch ausgeführt werden.
Da die Ausführung bestimmter Scripts im Oracle-Umfeld durchaus sinnvoll ist, wie z.B. regelmäßige Exports bestimmter Tabellen oder auch Sicherungs-Scripts, muss hierbei unbedingt auf den Aufruf der Scripts für die Umgebungsvariablen geachtet werden.
Sandini Bib
84
Installation und Basiskonfiguration
Um dies sicherzustellen hat man zwei Möglichkeiten: 1. Das Script für die Umgebung wird explizit am Anfang des in die crontab eingetragenen Scripts aufgerufen. Hierbei kann die crontab eines beliebigen Benutzers, z.B. des oracle-Benutzers genutzt werden. 2. Aus der crontab des Benutzers root wird das Script über ein su-Kommando aufgerufen. Hierbei geht man davon aus, dass die Oracle-Umgebung per LoginScript richtig initialisiert wird. Der Befehlsteil des crontab-Eintrags sieht dann etwa wie folgt aus: su – oracle –c <Scriptpfad> Integrierter Start/Stopp Man spricht von integriertem Start/Stopp, wenn der Start
des Oracle-Systems in den Start des Unix-Systems eingegliedert ist. Hierzu kann es leicht unterschiedliche Vorgehensweisen geben; grundsätzlich ist dies jedoch mit dem Oracle-System möglich. Lokale Administrator-Authentifizerung Die lokale Authentifizierung eines DBAs
kann unter Unix ohne Passwort erfolgen. Das Oracle-System verlässt sich dabei auf eine erfolgreiche Authentifizierung auf Betriebssystemebene. Beim Installieren bzw. Linken des Datenbankkerns wird die Unix-Gruppennummer einer Oracle DBA-Gruppe, standardmäßig dba, festgehalten. Sowohl im Server Manager als auch in SQL*Plus ist dann die folgende Anmeldung möglich: CONNECT / AS SYSDBA19
In der Datei sqlnet.ora muss hierfür der Parameter sqlnet.authentication_ services entweder nicht vorhanden (auskommentiert) sein, oder die angegebene Liste muss den Wert BEQ enthalten: sqlnet.authentication_services = (BEQ)
Die passwortlose Administrator-Authentifizierung erweist sich sowohl beim interaktiven Betrieb als auch für Scripts als sehr nützlich: Passwörter müssen nicht hinterlegt oder gar im Script eingetragen werden. Allerdings sollte die Mitgliedschaft in der Gruppe dba auch nicht sehr breit gestreut werden. Betriebssystem-Upgrades und -Patches Unter Unix wird die Oracle-Software in
Form von Bibliotheken ausgeliefert, die bei der Installation auf dem Zielsystem mit den Betriebssystembibliotheken zusammengebunden werden. Das ist der Grund dafür, dass bei den Installationsvoraussetzungen je nach Unix-Derivat ein bestimmter Compiler angegeben ist. Falls für das Betriebssystem Upgrades oder Patches eingespielt werden, sind davon oft auch die Betriebssystembibliotheken betroffen. Daher empfiehlt es sich in solchen Situationen grundsätzlich, die Oracle Database-Software neu zu binden. Dies geschieht durch Eingabe des Befehls relink oracle 19. Die bei vielen Administratoren bekannte Alternative CONNECT INTERNAL wird bei Oracle8i noch unterstützt, bei Oracle9i nicht mehr.
Sandini Bib
Universal Installer: Konzepte und Installationsprozedere
85
Hierfür muss man als Installationseigentümer am System angemeldet sein. Der Befehl relink all
bindet alle installierten Oracle Komponenten neu. Oracle-Umgebung unter Windows Unter Windows werden die Umgebungsvariablen für die Oracle-Installation in der Windows-Registrierung abgelegt. Das hat den Vorteil, dass die Variablen zumindest in einer Standardausprägung nach der Oracle-Installation vorhanden sind; optional können noch Anpassungen vorgenommen werden. Die Variablen werden in einer festgelegten Struktur in der Registrierung abgelegt. Generell liegen alle Oracle-Variablen unter dem Schlüssel HKEY_LOCAL_MACHINE\ SOFTWARE\ORACLE. Unter dem Schlüssel ALL_HOMES gibt es einen Schlüssel für jedes auf dem System angelegte ORACLE_HOME; diese sind mit ID0, ID1, ID2 usw. bezeichnet. In diesen Schlüsseln sind folgende Werte vom Typ REG_EXPAND_SZ (Zeichenketten) abgelegt: 1. NAME Dies ist der Name des ORACLE_HOME-Verzeichnisses, der in der Universal InstallerSitzung zugewiesen wurde. 2. PATH Dies ist der zugehörige Pfad. Die Registrierungseinträge für das ORACLE_HOME-Verzeichnis, das in ID beschrieben wird, sind wiederum in HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOME zu finden. Die Werte auf dieser Ebene entsprechen den teilweise schon besprochenen Oracle-Umgebungsvariablen wie NLS_LANG, ORACLE_HOME, ORACLE_SID usw. Die Verknüpfung von Umgebungsvariablen aus der Registrierung mit einem Programm erfolgt zunächst automatisch: Wird per Windows-Startmenü oder per expliziter Pfadangabe ein Programm aus einem der installierten ORACLE_HOME-Verzeichnisse gestartet, so gelten für dieses Programm automatisch die Werte aus dem passenden Schlüssel. Falls z.B. eine gemeinsame Konfiguration der Net8-Umgebung für alle Installationen gelten soll, kann der Wert TNS_ADMIN für alle HOME-Schlüssel mit dem gleichen Konfigurationsverzeichnis abgelegt werden. Andererseits können unterschiedliche Werte für ORACLE_SID (lokale Instanz aus dem gleichen ORACLE_HOME) bzw. LOCAL (Net8-Name für eine andere Instanz) gewählt werden. Die Standardwerte können entweder durch Modifikation in der Registrierung selbst oder durch das Setzen von Umgebungsvariablen in der Eingabeaufforderung bzw. in einem Script übersteuert werden. Die Modifikation von Registrierungseinträgen sollte immer nur unter größter Vorsicht erfolgen, da fehlerhafte Einträge das ganze Betriebssystem instabil machen können. Für Kommandozeilen-Scripts eignet sich die Möglichkeit, Umgebungsvariablen manuell zu setzen, wie z.B. in der folgenden Zeile: set ORACLE_SID=WIN817
Sandini Bib
86
Installation und Basiskonfiguration
Hiermit hat man (wie bei Shell-Scriptsn unter Unix) die Möglichkeit, individuell parametrierte Scripts zu erstellen. Oracle Home Selector Der Oracle Home Selector hat eine ähnliche Wirkung auf die MS-Windows-Umgebung wie ein Aufruf von oraenv auf eine Unix-Shell: Alle folgenden Oracle Befehle, die ohne explizite Pfadangabe aufgerufen werden, werden aus dem ausgewählten ORACLE_HOME-Verzeichnis gestartet.
Die Bedienung ist recht einfach. Nach dem Aufruf des Oracle Home Selectors aus dem Programmordner Oracle-Installation Products erscheint folgendes Fenster:
Abbildung 2.8: Oracle Home Selector
Aus der Liste neben dem Feld NAME kann ein Oracle_Home-Name ausgewählt werden; das zugehörige ORACLE_HOME-Verzeichnis wird als Speicherort angezeigt. Durch Bestätigung mit OK werden die Umgebungsvariablen in der MS-Windows-Sitzung entsprechend geändert. Die Einstellungen bleiben erhalten. Tipp: Dadurch, dass jedes laufende Programm einen eigenen Satz Umgebungsvariablen besitzt, hat der Aufruf des Oracle Home Selectors keine Auswirkungen auf bereits laufende Programme. Auch eine bereits gestartete Eingabeaufforderung reagiert nicht auf die Umstellung der Umgebung. Also: Zuerst Eingabeaufforderung schließen, dann Oracle Home Selector aufrufen und schließlich neue Eingabeaufforderung starten. Integrierter Start/Stopp Die Einbindung des Oracle-Starts bzw. -Stopps in den MS-
Windows Start/Stopp ist recht einfach, da die betroffenen Dienste in der Systemsteuerung lediglich auf „Automatisch Starten“ eingestellt werden müssen. Falls beim Einrichten des Dienstes mit dem Instance Manager die Option -startmode automatic angegeben wurde, wird beim Start ein STARTUP-Kommando sowie beim Stopp standardmäßig ein SHUTDOWN IMMEDIATE-Kommando für die betreffende Instanz ausgeführt. Dieses Verhalten kann über die folgenden Registrierungseinträge modifiziert werden: ORA_<SID>_AUTOSTART = TRUE | FALSE
Sandini Bib
Universal Installer: Konzepte und Installationsprozedere
87
ORA_<SID>_PFILE = ORA_<SID>_SHUTDOWN = TRUE | FALSE ORA_<SID>_SHUTDOWN_TIMEOUT = <Sekunden> ORA_<SID>_SHUTDOWNTYPE = i | n | a
Über ORA_<SID>_AUTOSTART wird festgelegt, ob beim Start des Dienstes die Instanz automatisch gestartet werden soll. Dabei verweist ORA_<SID>_PFILE auf die passende Datei mit den Initialisierungsparametern. ORA_<SID>_SHUTDOWN legt fest, ob beim Stopp des Dienstes die Instanz ebenfalls gestoppt werden soll. Dabei legt ORA_<SID>_SHUTDOWNTYPE fest, ob das SHUTDOWN-Kommando mit der Option Immediate, Normal oder Abort abgesetzt wird. ORA_<SID>_SHUTDOWN_TIMEOUT legt die Zeit in Sekunden fest, die maximal auf den SHUTDOWN gewartet wird, bevor der Dienst letztendlich auch hart beendet wird. Falls man den ORA_<SID>_SHUTDOWN auf TRUE einstellt, sollte man den Wert für ORA_<SID>_SHUTDOWN_TIMEOUT erhöhen, da die voreingestellten 30 Sekunden oft nicht ausreichen. Als Alternative zur direkten Einstellung in der Registrierung können diese Einstellungen auch im Oracle Administration Assistant for Windows NT vorgenommen werden. Hierzu ist Voraussetzung, dass die MS-Management Console installiert ist.
Abbildung 2.9: Oracle Administration Assistant for Windows NT
Wenn man mit der rechten Maustaste auf eine der Datenbanken klickt, kommt man über den Menüpunkt OPTIONEN FÜR HOCH-/HERUNTERFAHREN in folgendes Auswahlfenster (eigenartigerweise kann der Timeout hier nicht eingestellt werden):
Sandini Bib
88
Installation und Basiskonfiguration
Abbildung 2.10: Start/Stopp-Optionen
Tipp
für
produktive
Systeme:
Probieren
Sie
in
diversen
Situationen
SHUTDOWN IMMEDIATE Kommandos aus (nicht nur für eine frisch gestartete Instanz)
und stoppen Sie die Zeit. Addieren Sie 50 - 100 % Sicherheitsreserve und tragen Sie diesen Wert (manuell) als ORA_<SID>_SHUTDOWN_TIMEOUT ein. Achtung: Wenn Sie Dienste mit oradim löschen und neu kreieren gehen die Start/ Stopp-Einstellungen verloren! Lokale Administrator-Authentifizerung Analog zur Anmeldung ohne Passwort für
den DBA gibt es eine entsprechende Lösung unter MS-Windows. Bei der Installation wird eine lokale Gruppe ORA_DBA angelegt, in der der installierende MS-Windows-Benutzer automatisch Mitglied ist. Diese Gruppe erhält das SYSDBA-Privileg, so dass ein Mitglied der Gruppe sich ohne Passwort wie folgt an die Datenbank anmelden kann: CONNECT / AS SYSDBA
Der Gruppenname ist nicht flexibel wählbar. Allerdings ist es möglich, manuell zusätzliche Gruppen mit dem Namen ORA__DBA anzulegen. Gruppenmitglieder besitzen Instanz-spezifisch das SYSDBA-Privileg. Die ebenfalls manuell anzulegenden Gruppen ORA_OPER bzw. ORA__OPER beinhalten entsprechend das SYSOPER-Privileg. Voraussetzung für das korrekte Funktionieren dieser Methode ist der Eintrag NTS (für NT Security) beim Parameter sqlnet.authentication_services in der Datei sqlnet.ora wie in der folgenden Zeile: sqlnet.authentication_services = (NTS)
Auch unter MS-Windows wird für Scripts dringend empfohlen, die passwortlose Administrator-Authentifizierung auszunutzen, um das Hinterlegen von Passwörtern in Dateien zu vermeiden.
Sandini Bib
Basiskonfiguration
2.3.4
89
Software Packager
Mit dem Software Packager können eigene Softwarepakete definiert werden, die mit dem Universal Installer installiert werden können. Hiermit wird z.B. Softwarehäusern eine Möglichkeit zur Verfügung gestellt, die eigene Anwendung eventuell zusammen mit der benötigten Oracle-Basissoftware als Softwarepaket auszuliefern und „unter einem Dach“ zu installieren. Der Software Packager selbst ist eine objektorientierte Java-Anwendung, in der die Definition der zu installierenden Komponenten in einer grafischen Oberfläche vorgenommen wird. Es können sowohl komprimierte (.jar-Dateien) als auch nicht komprimierte Dateien eingepackt werden. Die selbsterstellte Softwareinstallation kann ebenfalls von allen Vorteilen profitieren, die der Universal Installer nutzt:
: : : :
NLS-Unterstützung Webbasierte Installation Vordefinierte Bibliothek von Abfragen, Aktionen usw. Erweiterbarkeit mit eigenen Java-Bibliotheken
Auf eine detaillierte Einführung in den Software Packager wird an dieser Stelle verzichtet – auf Grund des Umfangs der Beschreibung. Weiterführende Dokumentation sowie die Software selbst sind im Oracle Technet zu beziehen.
2.4
Basiskonfiguration
Im folgenden Kapitel wird die Konfiguration einer Beispieldatenbank Oracle9i (Version 9.0.1) unter SUN-Solaris 8 (Name: SUNDB) beschrieben. Alle Beispiele beziehen sich, soweit nicht explizit genannt, auf das Betriebssystem Unix, im Wesentlichen sind unter MS-Windows jedoch wenig Unterschiede zu erwarten. Die Unterschiede zwischen der Version 8.1.7 und 9.0.1 werden separat angesprochen.
2.4.1
Oracle Flexible Architecture (OFA)
Als Grundlage für eine Installation sollte die Oracle Flexible Architecture (OFA)Methode verwendet werden, da sie gewährleistet, dass Datenbankdateien, Konfigurationsdateien, Log-Dateien und die Oracle-Software voneinander getrennt werden. Dies ist unter anderem deshalb zu empfehlen, weil dann ein Update der Software ohne Auswirkungen auf die Datenbank bleibt. Folgendes Beispiel zeigt eine OFA-konforme Installation unter Solaris. Die Installation unter MS-Windows ist bis auf die obligatorischen \ und den vorangestellten Laufwerksbuchstaben identisch. /opt/oracle/ORACLE_BASE .../product/9.0.1ORACLE_HOME
Sandini Bib
90
Installation und Basiskonfiguration .../oradata/SUNDB Verzeichnis der Datenbankdateien .../admin/SUNDB Verzeichnis der Konfigurationsdateien .../admin/SUNDB/arch Verzeichnis mit archivierten Redolog-Dateien .../admin/SUNDB/bdump Background-Dump-Destination .../admin/SUNDB/create Scripts, mit denen die Datenbank erstellt wurde .../admin/SUNDB/cdump Coredump Verzeichnis .../admin/SUNDB/pfile Initialisierungsdateien .../admin/SUNDB/udump User-Dump-Destination
Listing 2.5: OFA-Struktur
Die Variable ORACLE_BASE gibt vor, dass es sich um eine OFA-Installation handelt, d.h., das ORACLE_HOME-Verzeichnis wird dementsprechend als Unterverzeichnis mit der Versionsnummer angegeben. Die hier verwendeten Unterverzeichnisse oradata und arch sind nur exemplarisch zu sehen, denn für die Sicherheit und Performance einer Oracle-Datenbank ist es erforderlich, die Datenbankdateien, die Redolog-Dateien und die Kontrolldateien auf unterschiedliche Festplatten zu legen. Die Dump-Einträge in bdump, cdump und udump sind nur für die Gruppe der Datenbankadministratoren lesbar (unter Unix standardmäßig Gruppe dba, unter MSWindows Gruppe ORA_DBA). Einzige Ausnahme ist die Datei alert_<SID>.ora, die alle kritischen Meldungen der Instanz protokolliert, sie ist für alle lesbar. Problematisch ist diese Einschränkung für das Verzeichnis udump, da Datenbankbenutzer die Möglichkeit haben, Prozesse zu protokollieren, diese Trace-Dateien dann aber nicht lesen können (siehe Kapitel Tuning). Im Verzeichnis create sollte man die Scripts, mit denen die Datenbank erstellt wurde, sowie die während der Installation erstellten Protokolldateien ablegen. Das Verzeichnis pfile enthält die Initialisierungdateien der Datenbank (init.ora). Da dies nicht das Standardverzeichnis für Initialisierungsdateien ist (MS-Windows: %ORACLE_HOME%/database, Unix: $ORACLE_HOME/dbs), kann die Datenbank nur mit dem Parameter pfile=... gestartet werden. Unter MS-Windows ist es möglich, den Namen der Datei in die Registrierung einzutragen (Schlüssel: ORA_<SID>_PFILE), unter Unix kann mit einem symbolischen Link ein entsprechender Eintrag erzeugt werden. MS-Windows: oradim -edit -SID SUNDB -pfile D:\oracle\admin\SUNDB\pfile\initSUNDB.ora
Unix: ln -s /app/oracle/admin/SUNDB/pfile/initSUNDB.ora /app/oracle/product/9.0.1/dbs
Alternativ gibt es für alle Betriebssysteme die Möglichkeit, eine Standardinitialisierungsdatei mit folgendem Inhalt anzulegen:
Sandini Bib
Basiskonfiguration
91
ifile='D:\oracle\admin\SUNDB\pfile\initSUNDB.ora'
Dadurch kann eine einheitliche Struktur über Betriebssystemgrenzen hinweg aufgebaut werden. Bevor mit der Installation begonnen werden kann, müssen die entsprechenden Verzeichnisse angelegt und die Initialisierungsdateien erstellt worden sein.
2.4.2
Initialisierungsparameter
Mit den Initialisierungsparametern wird zunächst einmal die Datenbank im Grundgerüst angelegt, und der Instanz werden entsprechende Ressourcen zugeordnet. SPFILE Mit der Version 9i ist es möglich, die Initialisierungsparameter im Binärformat im Standardverzeichnis (UNIX: $ORACLE_HOME/dbs) als sog. SPFILE anzulegen. Dies ermöglicht es, im laufenden Betrieb Änderungen der Parametrisierung festzuschreiben, die dann auch nach einem Neustart der Instanz zur Verfügung stehen. Außerdem ist es durch diese Konfiguration möglich, die Instanz remote hochzufahren, ohne eine explizite Parameterdatei zu haben. Mit dem Befehl CREATE spfile FROM pfile
kann jederzeit aus einer vorhandenen Initialisierungsdatei ein SPFILE erstellt werden. Dieses wird dann automatisch gepflegt und beim Hochfahren des Systems als Standardkonfigurationsdatei verwendet. Der umgekehrte Weg, also die Erstellung einer Initialisierungsdatei in lesbarer Form (init.ora) ist ebenfalls möglich, allerdings fehlen dabei alle Kommentare. CREATE PFILE FROM SPFILE
erstellt die Datei $ORACLE_HOME/dbs/init.ora. Sie wird jedoch nur dann genutzt, wenn das entsprechende SPFILE gelöscht wurde oder über den Startup-Parameter pfile=$ORACLE_HOME/dbs/init.ora diese explizit angegeben wurde. Unterschiede zwischen Version 8 und 9 Am wichtigsten ist wohl die neue Struktur für den Aufbau der SGA. Statt wie bisher die SGA über die Parameter db_block_buffer, shared_pool_size und log_buffer zu verwalten, gibt es jetzt die Möglichkeit, über den Parameter sga_max_size eine maximale Größe der SGA vorzugeben, die dann wahlweise auf den Shared Pool oder die unterschiedlichen Block-Caches verteilt werden kann. Durch die Möglichkeit, unterschiedliche Blockgrößen für die einzelnen Tablespaces vorzugeben, entfällt außerdem der Parameter db_block_buffer. Er wird durch db_cache_size für die Standard-Blockgröße sowie db_nk_cache_size für die Tablespaces mit speziellen Blockgrößen ersetzt.
Sandini Bib
92
Installation und Basiskonfiguration
Erstellen der Initialisierungdatei Um eine Initialisierungsdatei zu erstellen, empfiehlt es sich, eine der mitgelieferten Beispieldateien zu kopieren und dann die entsprechenden Parameter anzupassen (für MS-Windows: %ORACLE_HOME%\sample\pfile\initsmpl.ora, für Unix: $ORACLE_HOME/dbs/init.ora und initdw.ora). Diese Möglichkeit kann jedoch nur eingeschränkt für die Version 9.0.1 genutzt werden, da die mitgelieferte Datei identisch mit der von Version 8.1.7 ist, also keine 9i-spezifisichen Änderungen enthält. Die von Oracle vorgegebenen Größenbeispiele (small, medium und large) sind allerdings wenig hilfreich, da ein Bezug zu Datenbankgrößen schwer herzustellen ist. So bezieht sich zum Beispiel der Parameter db_block_buffer auf die Größe der SGA, der Parameter db_file_multiblock_read_count auf das Leseprofil der Anwendung und der Parameter db_files auf die Anzahl möglicher Datenbankdateien. Dabei ist dann für die Konfiguration large die Größe der SGA mit 21 Mbyte viel zu klein aber die Anzahl der Datenbankdateien mit 1.500 wesentlich zu groß! Die Verwendung einer bereits produktiv genutzten Initialisierungsdatei als Basis für eine neue Installation ist nur unter größter Vorsicht möglich, da hierbei fälschlicherweise zu einer anderen Datenbank gehörige Dateien (z.B. Kontrolldateien) überschrieben werden könnten. Die folgende Liste zeigt die notwendigen Anpassungen einer kopierten Initialisierungsdatei: db_name instance_name service_names control_files background_dump_dest core_dump_dest user_dump_dest db_block_size
= = = = = = = =
SUNDB SUNDB SUNDB ("/oradata1/SUNDB/control01.ctl") /app/oracle/admin/SUNDB/bdump /app/oracle/admin/SUNDB/cdump /app/oracle/admin/SUNDB/udump 4096
Listing 2.6: Standard-Initialisierungsparameter
:
db_name gibt den Namen der Datenbank an, der in den entsprechenden Kon-
:
instance_name gibt den Namen der zugehörigen Instanz an. Dieser Name kann
:
service_names sind ein oder mehrere Namen, unter denen sich die Instanz bei
:
control_files gibt die Namen der zur Datenbank gehörenden Kontrolldateien
trolldateien eingetragen ist und später die Verbindung zu einer Instanz herstellt. Dieser Name kann nur durch ein neues Erstellen der Kontrolldateien geändert werden. jederzeit geändert werden, um die Instanz unter einem neuen Namen hochzufahren. einem Listener anmeldet. Hierdurch kann auf eine separate Listener-Konfiguration verzichtet werden. an. In der Regel sind dies drei auf unterschiedlichen Festplatten.
Sandini Bib
Basiskonfiguration
: : : :
93
background_dump_dest gibt das Verzeichnis an, in den die Hintergrundprozesse
eventuelle Traces schreiben. In diesem Verzeichnis befindet sich die Alert-Datei der Instanz, in der alle Fehlermeldungen, das Hoch- und Herunterfahren der Datenbank sowie die Logswitches eingetragen werden. core_dump_dest ist ein Basisverzeichnis für Core-Dumps. user_dump_dest ist das Verzeichnis für Benutzer-Traces. Sie entstehen entweder
durch Prozessabbrüche oder durch ein explizites Tracing eines Prozesses – auch der Kontrolldateien. db_block_size gibt die Größe der Oracle-Blöcke an, mit der die Datenbank erstellt werden soll. Sie ist nach dem CREATE DATABASE nicht mehr änderbar!
Der Parameter rollback_segments kann an dieser Stelle schon eingetragen werden, da der Wert für ein CREATE DATABASE-Kommando nicht ausgewertet wird. Erst beim nächsten Starten der Datenbank muss dieser Eintrag mit den tatsächlich vorhandenen Rollback-Segmenten übereinstimmen. Des Weiteren empfiehlt es sich, einige Parameter schon vor der Installation hochzusetzen, da die angegebenen Standardwerte wesentlich zu klein sind und sich dadurch das Anlegen der Datenbank verzögert. db_block_buffers db_cache_size shared_pool_size log_checkpoint_interval log_buffer
= = = = =
5000 50000000 20000000 1000000 163840
-- Nur Oracle8 -- Nur Oracle9
Listing 2.7: Tuning-Parameter
Diese Parameter beziehen sich auf eine Datenbank mit 4 Kbyte Blockgröße. Sollten Sie eine Datenbank für Data Warehouse Anwendungen erstellen, empfiehlt es sich, die Blockgröße auf 8 Kbyte oder 16 Kbyte einzustellen (Näheres im Kapitel Data Warehouse).
2.4.3
Betriebssystemspezifika
Bevor mit der eigentlichen Installation begonnen werden kann, müssen weitere Betriebssystemparameter eingestellt werden. Unter Unix sind dies die Kernel-Parameter für Shared-Memory und Semaphore. Als Beispiel sei hier die Datei /etc/system für SUN Solaris genannt. Andere Konfigurationen und Beschreibungen entnehmen Sie bitte der entsprechenden Installationsdokumentation. set set set set set set set
shmsys:shminfo_shmmax=4294967295 shmsys:shminfo_shmmin=1 shmsys:shminfo_shmmni=200 shmsys:shminfo_shmseg=10 semsys:seminfo_semmni=500 semsys:seminfo_semmsl=500 semsys:seminfo_semmns=1000
Sandini Bib
94
Installation und Basiskonfiguration
set semsys:seminfo_semvmx=32767 set semsys:seminfo_semmnu=500 set semsys:seminfo_semume=500 Listing 2.8: /etc/system
Der Befehl . oraenv
setzt alle Umgebungsvariablen unter Unix, dafür wird für die Datenbank ein Eintrag in der Datei oratab erwartet. Dieser Eintrag besteht aus der ORACLE_SID, dem ORACLE_HOME und einem Flag, mit dem ein automatisches Starten der Instanz über den Befehl dbstart ermöglicht wird. Mit dem Befehl orapwd kann sowohl unter Unix als auch unter MS-Windows die Passwortdatei erstellt und geändert werden. orapwd file=$ORACLE_HOME/dbs/orapwSUNDB password=manager entries=5
Dieser Befehl erstellt die Passwortdatei mit dem Kennwort manager für den Benutzer internal und der Möglichkeit weitere 4 Benutzer einzutragen. Die Datei muss den Namen orapw (MS-Windows Endung .ora) haben und im Verzeichnis ORACLE_HOME/dbs (Unix) bzw. ORACLE_HOME/database (MS-Windows) liegen. Dies gilt dann, wenn als Initialisierungsparameter remote_login_passwordfile = exclusive gewählt wurde. Bei der Option remote_login_passwordfile = shared kann ein anderer Name gewählt werden. Unter MS-Windows müssen mit dem Befehl oradim die datenbankspezifischen Parameter in der Registrierung eingetragen werden. Hierzu gehört neben den Umgebungsvariablen auch der Dienst. oradim -new -sid WINDB -intpwd oracle -startmode manual -pfile "D:\oracle\admin\WINDB\pfile\initWINDB.ora"
Dieser Befehl erzeugt einen neuen Eintrag für eine Instanz mit dem Namen WINDB. Der Dienst OracleServiceWINDB wird eingetragen mit dem Autostarttyp manuell. Außerdem wird eine Passwortdatei mit dem Namen %ORACLE_HOME%\database\PWDWINDB.ORA angelegt und als Passwort oracle gewählt. Unter diesem Kennwort können sich Benutzer als SYSDBA an die Datenbank anmelden.
2.4.4
Datenbank erstellen
Um eine Oracle-Datenbank zu erstellen, braucht man das Programm SQL*Plus, da nur dieses in der Lage ist, alle Befehle (inkl. Starten und Stoppen der Instanz) durchzuführen und in geeigneter Form zu dokumentieren. Aus diesem Grund erlaubt die Oracle-Lizensierung den Einsatz von genau einer SQL*Plus-Lizenz pro Server. Zu beachten ist, dass es auf einem System durchaus unterschiedliche SQL*Plus-Versionen geben kann, eine Erstellung der Datenbank bzw. das Starten und Stoppen der Instanz kann aber nur mit der Version 8.1 und neueren durchgeführt werden. Der
Sandini Bib
Basiskonfiguration
95
in der Vergangenheit genutzte Oracle Server Manager existiert nur noch aus Kompatibilitätsgründen bei Version 8.1 und sollte deshalb nicht mehr genutzt werden. CREATE DATABASE Im Folgenden wird die Erstellung der Datenbank anhand eines Unix-Systems beschrieben. Hierfür muss als erstes eine Kennwortdatei unter dem Standardverzeichnis angelegt werden, ansonsten wird das Anmelden als SYSDBA fehlschlagen. orapwd file=$ORACLE_HOME/dbs/orwpwSUNDB password=manager entries=5
In der Initialisierungsdatei müssen alle oben beschriebenen Einträge, speziell die der Kontrolldateien und des Datenbanknamens vorgenommen worden sein. SPOOL /app/oracle/admin/SUNDB/create/crdb1.log CONNECT / as sysdba STARTUP NOMOUNT PFILE = "/app/oracle/admin/SUNDB/pfile/initSUNDB.ora" CREATE DATABASE "SUNDB" MAXDATAFILES 254 MAXINSTANCES 1 MAXLOGFILES 10 CHARACTER SET WE8ISO8859P15t NATIONAL CHARACTER SET UTF8 DATAFILE '/oradata1/SUNDB/system01.dbf' SIZE 200M AUTOEXTEND ON NEXT 10M MAXSIZE 500M LOGFILE '/oradata1/SUNDB/redo01.log' SIZE 10M, '/oradata1/SUNDB/redo02.log' SIZE 10M, '/oradata1/SUNDB/redo03.log' SIZE 10M; SPOOL OFF; Listing 2.9: CREATE DATABASE
Gestartet wird dieses Script mit dem Befehl sqlplus /nolog @crdb.sql. Die Angabe der Initialisierungsdatei durch pfile = "/app/oracle/admin/SUNDB/pfile/initSUNDB.ora"
ist optional, wenn wie oben angesprochen der Link zur entsprechenden Datei im ORACLE_HOME/dbs-Verzeichnis schon existiert. Die Parameter maxdatafiles, maxinstances und maxlogfiles bestimmen die Anzahl der Datenbankdateien, der Instanzen (nur für Oracle Parallel Server sinnvoll) und der Redolog-Gruppen. Die Größe der Werte richtet sich im Wesentlichen nach der Größe der zu installierenden Datenbank, daher können hier nur Richtwerte angegeben werden, die sich allerdings in der Praxis in den meisten Fällen als ausreichend erwiesen haben. Durch diese Parameter wird die Struktur und Größe der Kontrolldateien mitbestimmt, d.h., sollten diese Werte nicht ausreichend sein, muss eine neue Kontrolldatei erzeugt werden.
Sandini Bib
96
Installation und Basiskonfiguration
Der Character-Set gibt den Zeichensatz für die Verwendung der Datentypen CHAR, VARCHAR2 und CLOB an, zusätzlich kann über den National-Character-Set für die Datentypen NCHAR, NVARCHAR2 und NCLOB ein zweiter Zeichensatz (in diesem Fall der Unicode-Zeichensatz UTF8) angegeben werden. Bei nicht expliziter Angabe sind beide Zeichensätze identisch. Die Lage des Tablespaces SYSTEM, der das Data Dictionary enthält, wird durch das Schlüsselwort DATAFILE angegeben. Hier können bei Bedarf auch mehrere Dateien durch Kommata getrennt angegeben werden. Jede Datei bekommt eine Initialgröße in Byte, Kbyte (K) oder Mbyte (M) zugewiesen. Das optionale Schlüsselwort AUTOEXTEND ON ermöglicht eine automatische Erweiterung der zugehörigen Datendatei um den Wert NEXT integer [K|M]. Hier sollten nicht zu kleine Erweiterungen gewählt werden, da eine solche Erweiterung während des Betriebs zu PerformanceEinbußen führt. Es ist dringend anzuraten, eine maximale Größe der Datendatei mit MAXSIZE integer [K|M] anzugeben, um ein unkontrolliertes Wachstum der Dateien zu vermeiden. Die Redolog-Dateien werden mit mindestens zwei Gruppen (im Beispiel drei) angegeben. Die Größe sollte bei allen gleich sein und nicht weniger als 10 Mbyte betragen. Optional können pro Gruppe noch mehrere logische Spiegel (sog. Member) aufgesetzt werden. Standardmäßig wird beim Versuch, eine existierende Datei zu überschreiben, eine Fehlermeldung ausgegeben; dies kann durch das Schlüsselwort REUSE übersteuert werden. Dabei sollte beachtet werden, dass ein Fehler im Script oder in der Initialisierungsdatei dazu führen kann, dass eine zu einer anderen Datenbank gehörige Datei überschrieben wird. Besser ist es, man löscht auf Betriebssystemebene alle neu zu erstellenden Dateien und verzichtet auf die Benutzung die Option REUSE! Mit dem Befehl CREATE DATABASE wird das interne Data Dictionary aufgebaut, über das sich die Datenbank verwaltet. Die dem Benutzer SYS gehörenden Tabellen liegen im Tablespace SYSTEM und werden durch die Endung $ gekennzeichnet. Es ist nicht erlaubt, DML-Befehle (INSERT, UPDATE, DELETE) auf Data Dictionary-Tabellen auszuführen, einzige Ausnahme bildet die Audit-Tabelle, da sie vom Administrator in regelmäßigen Abständen bereinigt werden muss. Für große, performancekritische Datenbanken kann man, nach Rücksprache mit der Oracle-Hotline, Änderungen an den Storage-Klauseln der Tabellen (z.B. Freelists) vornehmen. In diesen speziellen Fällen wird die Datei sql.bsq (Verzeichnis: ORACLE_HOME/rdbms/ admin), die die Definition des Data Dictionarys enthält, angepasst. Das interne Data Dictionary wird den Adminstratoren und Benutzern durch eine Reihe von Sichten (Externes Data Dictionary) zur Verfügung gestellt. Oracle Managed Files In der Version 9i kann man die Erstellung einer Datenbank bzw. die Erstellung von Tablespaces, Kontrolldateien und Redolog-Dateien über Oracle Managed Files wesentlich vereinfachen. Durch zwei Initialisierungsparameter DB_CREATE_FILE_DEST und DB_CREATE_ONLINE_LOG_DEST_1 kann die Lage der Dateien vorgegeben werden. Die Größe der Dateien wird dabei auf 100 Mbyte gesetzt, kann aber übersteuert werden.
Sandini Bib
Basiskonfiguration
97
Dadurch kann das oben beschriebene Beispiel zur Erstellung einer Datenbank wie folgt vereinfacht werden. SPOOL /app/oracle/admin/SUNDB/create/crdb1.log CONNECT / as sysdba CREATE SPFILE FROM PFILE = '/app/oracle/admin/SUNDB/pfile/initSUNDB.ora' STARTUP NOMOUNT CREATE DATABASE "SUNDB" MAXDATAFILES 254 MAXINSTANCES 1 MAXLOGFILES 10 CHARACTER SET WE8ISO8859P15 NATIONAL CHARACTER SET UTF8 DATAFILE AUTOEXTEND ON NEXT 10M MAXSIZE 500M
LOGFILE GROUP 1 SIZE 10M, GROUP 2 SIZE 10M, GROUP 3 SIZE 10M; SPOOL OFF; Listing 2.10: CREATE DATABASE mit Oracle Managed Files
Interessant ist hierbei, dass es möglich ist, schon vor dem Starten einer Instanz einen CREATE SPFILE-Befehl auszuführen. Danach werden alle weiteren Parameter direkt in diese Initialisierungsdatei eingetragen. Voraussetzung hierfür sind nur die beiden oben erwähnten Parameter in der Initialisierungsdatei. Durch das direkte Anlegen einer persistenten Initialisierungsdatei kann auf die Angabe des Parameters CONTROL_FILES verzichtet werden, die Lage ergibt sich aus den Oracle Managed Files. Wenn zusätzlich der Parameter UNDO_MANAGEMENT=AUTO gesetzt ist, dann wird automatisch ein sog. Undo-Tablespace mit dem Namen UNDOTBS und der Standardgröße angelegt. Die hierdurch erstellten Dateien erhalten den Namen des entsprechenden Tablespaces und zusätzlich einen sechsstelligen Schlüssel, der eine eindeutige Identifizierung möglich macht. Externes Data Dictionary Mit dem Script catalog.sql (Verzeichnis: $ORACLE_HOME/rdbms/admin) wird die Benutzersicht auf das interne Data Dictionary aufgebaut. sqlplus sys/manager @?/rdbms/admin/catalog.sql
Sandini Bib
98
Installation und Basiskonfiguration
Das ? steht hierbei für das ORACLE_HOME-Verzeichnis und kann sowohl unter Unix als auch MS-Windows verwendet werden. Dieses Script baut verschiedene Sichten auf. 1. Virtuelle Sichten (v$, gv$) Dies sind Informationen der Kontrolldateien sowie Zähler und Strukturen der Prozesse und des Shared-Memories. Das Beispiel v$process gibt die aktuelle Liste aller Prozesse an. SQL> SELECT username, program FROM v$process; USERNAME PROGRAM --------------- -----------------------------------------------PSEUDO oracle oracle@hlsun1 (PMON) oracle oracle@hlsun1 (DBW0) oracle oracle@hlsun1 (LGWR) oracle oracle@hlsun1 (CKPT) oracle oracle@hlsun1 (SMON) oracle oracle@hlsun1 (RECO) oracle oracle@hlsun1 (SNP0) oracle oracle@hlsun1 (SNP1) oracle oracle@hlsun1 (TNS V1-V3) Listing 2.11: v$process
Das Beispiel v$datafile gibt die Liste der Datenbankdateien aus Sicht der Kontrolldatei an. SQL> SELECT name, ts#, bytes FROM v$datafile; NAME TS# BYTES ---------------------------------------- ---------- ---------/oradata1/SUNDB/demo01.dbf 7 178257920 /oradata1/SUNDB/oem_repository.dbf 5 31461376 /oradata1/SUNDB/quest01.dbf 6 41943040 /oradata1/SUNDB/rbs01.dbf 2 1059061760 /oradata1/SUNDB/system01.dbf 0 262144000 /oradata1/SUNDB/tools01.dbf 1 73400320 /oradata1/SUNDB/users01.dbf 4 10485760 /oradata2/SUNDB/prod_data01.dbf 8 1073741824 /oradata2/SUNDB/prod_idx01.dbf 9 209715200 Listing 2.12: v$datafile
Sandini Bib
Basiskonfiguration
99
Globale virtuelle Sichten sind noch eine Erweiterung für den Oracle Parallel Server-Betrieb. Sie zeigen Parameter als Zusammenfassung mehrerer Instanzen an und beginnen mit gv$ anstelle von v$. 2. DBA-Sichten (dba_) Dies ist die komplette Repräsentation des internen Data Dictionarys, d.h., über diese Sichten können alle relevanten Informationen über die Datenbank abgefragt werden. Die Informationen können nur von Benutzern gesehen werden, die zur Gruppe der Administratoren gehören, bzw. die Rolle select_catalog_role zugeteilt bekommen haben. Als Beispiel die Abfrage der Datenbankdateien (dba_data_files) aus Sicht des Data Dictionarys: SQL> SELECT file_name, tablespace_name, bytes FROM dba_data_files; FILE_NAME ------------------------------------/oradata1/SUNDB/demo01.dbf /oradata1/SUNDB/oem_repository.dbf /oradata1/SUNDB/rbs01.dbf /oradata1/SUNDB/system01.dbf /oradata1/SUNDB/tools01.dbf /oradata1/SUNDB/users01.dbf /oradata2/SUNDB/prod_data01.dbf /oradata2/SUNDB/prod_idx01.dbf
TABLESPACE_NAME -----------------DEMO OEM_REPOSITORY RBS SYSTEM TOOLS USERS PROD_DATA PROD_IDX
BYTES ---------178257920 31461376 1059061760 262144000 73400320 10485760 1073741824 209715200
Listing 2.13: dba_data_files
Beim Vergleich mit v$datafile fällt auf, dass hier der Name des Tablespaces angegeben wird, während im ersten Beispiel nur die Nummer des Tablespaces (ts#) aufgelistet wird. 3. Sichten für alle Benutzer (all_) Diese Sichten erlauben es den Benutzern, auf Objekte zuzugreifen, auf die ihnen Rechte gegeben wurden. Dazu gehören natürlich auch die eigenen Objekte. Als Beispiel wird hier mit der Sicht all_tables eine Liste aller lesbaren Tabellen für den momentan angemeldeten Benutzer (in diesem Fall scott) erstellt. SQL> SELECT owner, table_name FROM all_tables; OWNER -----------------------------SCOTT SCOTT SCOTT SCOTT
TABLE_NAME -----------------------------BONUS CUSTOMER DEPARTMENT DEPT
Sandini Bib
100
Installation und Basiskonfiguration
SCOTT SCOTT STAMMDATEN STAMMDATEN STAMMDATEN STAMMDATEN SYS SYS
DUMMY EMP NACHNAMEN ORTE STRASSEN VORNAMEN AUDIT_ACTIONS DUAL
Listing 2.14: all_tables
Für den Datenbankadministrator besteht oftmals kein Unterschied zwischen den DBA- und den All-Sichten. 4. Sichten nur für den lokalen Benutzer (user_) Hier werden nur noch die Informationen zu Objekten des momentan angemeldeten Benutzers angezeigt. Als Beispiel hier die Sicht user_tables, die im Gegensatz zu all_tables keine Information über den Besitzer (owner) anzeigt. SQL> SELECT table_name FROM user_tables; TABLE_NAME -----------------------------BONUS CUSTOMER DEPARTMENT DEPT DUMMY EMP Listing 2.15: user_tables
Zusätzlich werden aus dem Script catalog.sql weitere Scripts aufgerufen, mit denen z.B. die Sichten für das Export-/Importk-Kommando (catexp.sql) oder den Oracle Loader (catldr.sql) aufgebaut werden. Nachdem das Script durchgelaufen ist, wird als Nächstes die Grundinstallation von PL/SQL durch catproc.sql (ebenfalls im ORACLE_HOME/rdbms/admin-Verzeichnis) durchgeführt. Der Befehl hierfür ist: sqlplus sys/manager @?/rdbms/admin/catproc.sql
Je nach installierten Optionen kann es notwendig sein, dafür weitere Scripts im Verzeichnis ORACLE_HOME/rdbms/admin aufzurufen.
: : :
catparr.sql
Performance-Messungen für Oracle Parallel Server
catqueue.sql
Advanced Queuing Informationen
catrep.sql
Replikations-Informationen
Sandini Bib
Basiskonfiguration
101
Diese Liste ändert sich von Version zu Version und sollte deshalb bei Bedarf aus der entsprechenden Installationsdokumentation entnommen werden. Erweiterte Datenbank Für die weiteren Beispiele wird auf die Verwendung von Oracle Managed Files verzichtet, da dies lediglich eine Vereinfachung der Beispiele bedeutet. Zum Betrieb einer Oracle-Datenbank ist es notwendig, weitere Tablespaces und Objekte zu erstellen. Dazu gehören die folgenden Elemente:
: : : : :
Undo- bzw. Rollback-Tablespace Temporary-Tablespace Mindestens je einen Tablespace für die Daten und Indizes Einen Tablespace für Tools wie z.B. Oracle Enterprise Manager Rollback-Segmente (Oracle8i)
Die folgenden Beispiele erstellen alle notwendigen Objekte für die bereits vorhandene Datenbank SUNDB. REM ********** TABLESPACE FOR ROLLBACK ********** CREATE Undo-Tablespace rbs DATAFILE '/oradata1/SUNDB/rbs01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M MINIMUM EXTENT 512K DEFAULT STORAGE (INITIAL 512K NEXT 512K MINEXTENTS 10 MAXEXTENTS UNLIMITED); Listing 2.16: Anlegen eines Rollback-Tablespace
Bei der Version 9 empfiehlt es sich, einen Undo-Tablespace anzulegen und in der Initialisierungsdatei den Parameter UNDO_MANAGEMENT=AUTO zu setzen. Damit werden die Rollback-Segmente vom System verwaltet und das explizite Anlegen von Rollback-Segmenten entfällt. Als Undo-Tablespace wird der erste in der Datenbank gefundene Tablespace vom Typ UNDO genutzt. Optional kann durch den Parameter UNDO_tablespace = rbs ein bestimmter Undo-Tablespace gesetzt werden. Dies empfieht sich beim Einsatz von Oracle Real Application Cluster (früher Oracle Parallel Server), da hier jede Instanz eigene Rollback-Segmente zugewiesen bekommen muss. Die folgenden Rollback-Segmente sind also nur für die Version 8i bzw. für ein manuelles Undo-Management notwendig (Initialisierungparameter: undo_management= manual). REM **** Creating five rollback segments **************** CREATE PUBLIC ROLLBACK SEGMENT rbs0 TABLESPACE rbs STORAGE ( OPTIMAL 10M ); CREATE PUBLIC ROLLBACK SEGMENT RBS1 TABLESPACE rbs
Sandini Bib
102
Installation und Basiskonfiguration
STORAGE ( OPTIMAL 10M ); CREATE PUBLIC ROLLBACK SEGMENT rbs2 TABLESPACE rbs STORAGE ( OPTIMAL 10M ); CREATE PUBLIC ROLLBACK SEGMENT rbs3 TABLESPACE rbs STORAGE ( OPTIMAL 10M ); CREATE PUBLIC ROLLBACK SEGMENT rbs4 TABLESPACE rbs STORAGE ( OPTIMAL 10M ); ALTER ALTER ALTER ALTER ALTER
ROLLBACK ROLLBACK ROLLBACK ROLLBACK ROLLBACK
SEGMENT SEGMENT SEGMENT SEGMENT SEGMENT
rbs0 rbs1 rbs2 rbs3 RBS4
ONLINE; ONLINE; ONLINE; ONLINE; ONLINE;
Listing 2.17: Anlegen von Rollback-Segmenten unter Oracle8i
Die im Beispiel angelegten Rollback-Segmente (RBS0 bis RBS4) sollten, falls noch nicht geschehen, in der zugehörigen Initialisierungsdatei eingetragen werden: rollback_segments = ( rbs0, rbs1, rbs2, rbs3, rbs4)
Für die von den Benutzern vorgenommenen komplexen Sortierungen (z.B. für sortierte Abfragen oder den Aufbau von Indizes) muss ein weiterer Tablespace als sog. Temporary Tablespace angelegt werden. Dabei unterscheiden sich die Versionen 8 und 9 hinsichtlich der Zuweisung eines Tablespaces für Sortierungen. Während in der Version 8 jedem Benutzer dediziert ein Tablespace zugewiesen werden muss, kann in der Version 9 durch die explizite Angabe DEFAULT TEMPORARY TABLESPACE ein Tablespace angelegt werden, der für alle angelegten und noch anzulegenden Benutzer gilt. Dieser Tablespace kann dann nur noch gelöscht werden, wenn vorher ein neuer DEFAULT TEMPORARY TABLESPACE angelegt worden ist. Dadurch wird erreicht, dass die Benutzer immer einen expliziten Tablespace für Sortierungen zugewiesen haben und es nicht zu der Situation kommt, dass im SYSTEM-Tablespace sortiert wird. REM ********** TABLESPACE FOR TEMPORARY ********** CREATE DEFAULT TEMPORARY TABLESPACE temp TEMPFILE '/oradata1/SUNDB/temp01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M MINIMUM EXTENT 1M; Listing 2.18: Anlegen des Temporary-Tablespace unter Oracle9i
Sandini Bib
Basiskonfiguration
103
Bei der Version 8 gibt es die Option DEFAULT nicht, somit müssen in einem zweiten Schritt alle Benutzer den Tablespace explizit zugewiesen bekommen. REM **** SYS and SYSTEM users **************** ALTER USER sys TEMPORARY TABLESPACE temp; ALTER USER system TEMPORARY TABLESPACE temp; Listing 2.19: Zuordnung des Sortier-Tablespaces
Mit diesem Schritt ist die Basisdatenbank installiert, und es folgen noch zusätzliche Tablespaces für die Benutzerdaten mit zugehörigen Indizes und ein Tablespace für den Oracle Enterprise Manager. Dieser Tablespace muss nicht explizit angelegt werden, da es die Möglichkeit gibt, beim Erstellen des Enterprise Manager Repositorys den Tablespace mit zu erzeugen. REM ********** TABLESPACE FOR user ********** CREATE TABLESPACE users DATAFILE '/oradata1/SUNDB/users01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M MINIMUM EXTENT 128K DEFAULT STORAGE (INITIAL 128K NEXT 128K MAXEXTENTS UNLIMITED PCTINCREASE 1); REM ********** TABLESPACE FOR index ********** CREATE TABLESPACE indx DATAFILE '/oradata2/SUNDB/indx01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M MINIMUM EXTENT 128K DEFAULT STORAGE (INITIAL 128K NEXT 128K MAXEXTENTS UNLIMITED PCTINCREASE 1); REM ********** TABLESPACE FOR oem_repository ********** CREATE TABLESPACE oem_repository DATAFILE '/oradata2/SUNDB/oem_repository01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M MINIMUM EXTENT 128K DEFAULT STORAGE (INITIAL 128K NEXT 128K MAXEXTENTS UNLIMITED PCTINCREASE 1); Listing 2.20: Zusätzliche Tablespaces
Die hier verwendete Benennung und Lage der Datenbankdateien entspricht der OFA- bzw. OFM-Konvention. Alle Datenbankdateien liegen in einem entsprechenden Unterverzeichnis mit dem Namen der Datenbank. Die Datendateien enthalten den Namen des zugehörigen Tablespaces mit einer pro Tablespace fortlaufenden zweistelligen Nummerierung. Die Endung entspricht dem Typ der Datenbankdatei:
Sandini Bib
104
: : : : :
Installation und Basiskonfiguration
.dbf für Datendateien .tmp für Temporary-Tablespaces .log für Online Redolog-Dateien .ctl für Kontrolldateien .arc für archivierte Redolog-Dateien
Es ist natürlich jedem freigestellt, diese Endung anzupassen. So findet man zum Beispiel oft die Endung .dbf für alle Dateitypen (was syntaktisch auch richtiger ist, da dbf für Databasefiles also die Gesamtheit der Datenbank steht). Man sollte sich auf ein einheitliches Namenskonzept – gerade in größeren Umgebungen – einigen. Die hier verwendeten Größen und Storage-Klauseln der Tablespaces sind für eine kleine Oracle-Datenbank gedacht. Gerade die Definition des Rollback-Tablespaces und des Temporary-Tablespaces muss optimal an die entsprechende Anforderung, d. h. das Transaktionsprofil, angepasst werden. Damit steht Ihnen jetzt eine voll einsatzfähige Datenbank zur Verfügung. Sollten Sie mit SQL*Plus arbeiten wollen, müssen Sie unter dem Benutzer SYSTEM folgendes Kommando ausführen. sqlplus system/manager SQL> @?/sqlplus/admin/pupbld
Damit wird eine sog. PRODUCT_PROFILE-Tabelle für SQL*Plus aufgebaut. Wenn Sie Hilfetexte zu SQL-Befehlen haben möchten, können Sie diese mit folgendem Befehl installieren: sqlplus system/manager SQL> @?/sqlplus/admin/help/helpbld.sql helpd.sql
Damit erhalten Sie deutsche Hilfetexte (sofern Sie eine deutsche Installation durchgeführt haben). Mit helpus.sql erhalten Sie die englischen Texte.
2.4.5
Database Configuration Assistent
Als Alternative zur manuellen Erstellung der Datenbank kann mit dem grafischen Werkzeug Database Configuration Assistent eine Datenbank erstellt, geändert oder gelöscht werden. Mit diesem in Java geschriebene Werkzeug kann eine Datenbank direkt erstellt oder ein Script für die weitere Bearbeitung aufgebaut werden. Die Vorgehensweise unterscheidet sich hier bezüglich Version 8 und 9, so dass im Folgenden beide Werkzeuge separat beschrieben werden. Database Configuration Assistant (9i) Bei der Version 9i wird ein Template als Vorlage für die Erstellung einer Datenbank verwendet. Unterschiedliche Konfiguration sind möglich, z.B. die Erstellung eines
Sandini Bib
Basiskonfiguration
105
Templates aus einer bestehenden Datenbank heraus oder aus einer existierenden Vorlage. Zu beachten ist, dass mit der Option INCLUDING DATAFILES eine komplette Datenbank als Template erstellt wird (Größe bis zu 400 Mbyte). Auf die neuen Möglichkeiten der Oracle Managed Datafiles wird allerdings nicht eingegangen. Die Standard-Tablespaces werden alle in konventioneller Weise angelegt, allerdings als Locally Managed. Es ist jedoch möglich, die Datendateien der entsprechenden Tablespaces zu löschen und damit Oracle Managed Files zu erzwingen. Es sind dann aber keine Größenangaben oder Autoextend-Klauseln mehr möglich. Für die Redolog-Dateien funktioniert dieser Weg nicht, sie müssen mit dem gesamten Pfad angegeben werden. Der Einsatz von Templates ermöglicht es, unhabhängige Datenbanken mit der gleichen Struktur zu erstellen, da der Name der Datenbank als Variable übergeben werden kann und alle Dateien diese Variable als Verzeichnis zugeordnet bekommen. Leider hat sich in der Version 9.0.1 ein kleiner, aber entscheidender Fehler eingeschlichen. Wenn man eine Datenbank aus einem Template heraus erstellen will und von der Möglichkeit Gebrauch macht, zusätzliche Änderungen (z.B. andere Tablespaces, Initialisierungsparameter, etc.) vorzunehmen, werden diese in das Template gesichert, auch wenn man dies nicht explizit angegeben hat.
Abbildung 2.11: Oracle9i-Templates
Sandini Bib
106
Installation und Basiskonfiguration
Daher sollte man, wenn man ein optimales Template erstellt hat, dieses nochmals kopieren und daraus dann die Datenbanken erstellen. Bei der Erstellung der Templates bzw. des Datenbank-Scripts wird keine SyntaxÜberprüfung vorgenommen, so dass eventuelle Fehler erst beim Erzeugen der Datenbank gemeldet werden. Eine Modifikation von Templates ist nur insofern möglich, dass man ein neues Template aus einem bestehenden generiert und dieses dann wieder unter dem alten abspeichert. Manuelle Änderungen an den konfigurierten Dateien sind nicht möglich! Database Configuration Assistant (8i) In der Version 8i dient der Database Configuration Assistant (MS-Windows: Programmordner Database-Administration; Unix: $ORACLE_HOME/bin/dbassist) als grafische Oberfläche für die Installation, das Ändern und Löschen von Datenbanken. Bei einer Neuinstallation kann unter zwei Arten gewählt werden: 1. Standardinstallation 2. Benutzerdefinierte Installation Bei der Standardinstallation gibt es die Möglichkeit, eine Kopie einer StandardDatenbank zu erstellen. Diese Datenbank befindet sich als gepackte Dateien im Verzeichnis ORACLE_HOME/starterdb und muss nur noch entpackt und an die richtige Stelle (ORACLE_BASE/oradata/) kopiert werden. Es dauert also nur wenige Minuten, bis die Datenbank einsatzbereit ist; allerdings werden hierbei alle Optionen mitinstalliert. Daneben gibt es noch die Möglichkeit, die Datenbankdateien neu zu erstellen und somit einen gewissen Einfluss auf die Installation auszuüben. Neben der Art der Nutzung (OLTP, DataWarehouse oder Hybrid) können hierbei die Datenbankoptionen einzeln ausgewählt werden. Die Datenbank kann dann wahlweise direkt installiert oder als Scripts gespeichert werden (Shell Kommandos unter UNIX, Batch Kommando und SQL-Scripts unter MS-Windows). Falls Sie über eine dieser Methoden eine Datenbank erstellen, sollten Sie anschließend einige Änderungen vornehmen. So werden zum Beispiel die Redolog-Dateien mit einer Größe von 512 Kbyte (UNIX) bzw. 1 Mbyte (MS-Windows) angelegt, was für einen effektiven Gebrauch wesentlich zu klein ist. Vorsicht ist geboten mit den Umgebungsvariablen, da zum Beispiel die NLS_LANG-Variable während der Installation ausschlaggebend für den Zeichensatz der Datenbank ist. Außerdem erfolgt die Installation nach der OFA-Methode, daher ist die Variable ORACLE_BASE entscheidend für die Lage der Datenbank- und Konfigurationsdateien. Alle Kontrolldateien liegen in einem Verzeichnis, so dass aus Sicherheitsgründen diese noch verteilt werden müssen. Für den fortgeschrittenen Benutzer bietet sich die benutzerdefinierte Installation an, da hierbei alle wichtigen Parameter (Größe und Lage der Datendateien, Initialisierungsparameter, Character-Set etc.) frei gewählt werden können (siehe Abbildung 2.12). Es ist zu empfehlen, die Datenbank dann nicht über den Assistenten zu installieren, sondern die entsprechenden Scripts zu erstellen. Der Vorteil liegt einerseits in der besseren Dokumentation und der Möglichkeit, bestimmte Parame-
Sandini Bib
Basiskonfiguration
107
ter noch zu ändern (z.B. Anzahl der Kontrolldateien oder Redolog-Dateien), andererseits ist ein Wiederaufsetzen bei Fehlern möglich.
Abbildung 2.12: Database Configuration Assistant
Alle grafischen Hilfsmittel sind natürlich nur dann hilfreich, wenn es sich um eine Standardinstallation handelt. So müssen z.B. anschließend noch die Initialisierungsparameter angepasst, die Kontrolldateien über mehrere Laufwerke verteilt und eine Trennung der Daten- und Index-Tablespaces vorgenommen werden. Weitere Hindernisse sind Fehler in der Java-Oberfläche (Felder werden nicht richtig angezeigt) oder der Umfang der Installation (es müssen mehrere Datenbanken erstellt werden). In diesen Fällen empfiehlt es sich, eine Grundkonfiguration zu erstellen und diese dann als Standard-Script zur Verfügung zu haben. Aufgrund der Unterschiede in den einzelnen Oracle-Releases ist es anzuraten, diese Konfiguration hin und wieder zu überprüfen, da gerade bei den Optionen je nach Release mehrere Scripts ausgeführt werden müssen. Am einfachsten ist die Erstellung der Konfigurationsdateien durch den Database Configuration Assistant mittels einer Standardinstallation (egal auf welcher Plattform). Dabei lässt man sich die Scripts erstellen und vergleicht diese mit den eigenen Konfigurationsdateien (siehe Abbildung 2.13).
Sandini Bib
108
Installation und Basiskonfiguration
Abbildung 2.13: Scripterstellung
Die
hierdurch
erstellten
Scripts
werden
standardmäßig
im
Verzeichnis
$ORACLE_HOME/assistants/dbca/jlib abgespeichrt, können aber auch in einem
beliebigen anderen Verzeichnis abgelegt werden. Nach der OFA-Konvention sollten die Scripts besser im Verzeichnis $ORACLE_BASE/admin//create gespeichert werden. Die Scripts haben folgende Struktur: Unix (Beispieldatenbank SUNDB):
:
: : : : :
sqlSUNDB.sh
Ruft die folgende Scripts auf: SUNDBrun.sh
Erstellt die Datenbank mit dem Befehl CREATE DATABASE. SUNDBrun1.sh
Erstellt alle weiteren Tablespaces und die Rollback-Segmente und führt das Script catalog.sql aus. SUNDBrun2.sh
Führt das Script catproc.sql und alle für die gewählten Optionen notwendigen Scripts aus. Außerdem wird das sog. Product-Profile für SQL*Plus installiert. SUNDBsqlplus.sh
Installiert die Hilfe-Tabellen. SUNDBalterTablespace.sh
Ändert den Default-Tablespace und den Sortier-Tablespace für den Benutzer SYSTEM.
MS-Windows (Beispieldatenbank WINDB):
Sandini Bib
Instanzverwaltung
109
Da es unter MS-Windows keine Möglichkeit gibt, umfangreiche Scripts als Befehlsparameter mitzugeben, werden hier alle Scripts als SQL-Befehle abgelegt und von dem Kommando WINDB.bat gestartet. Dabei wird auch das Kommando oradim ausgeführt. Ansonsten ist der Aufbau identisch zu denen unter Unix.
2.5
Instanzverwaltung
Die zentralen Befehle für die Instanzverwaltung sollen in diesem Abschnitt vorgestellt werden. Hierzu zählen sicherlich STARTUP und SHUTDOWN mit den entsprechenden Parametern, um ein Oracle-System zu starten und zu stoppen. Dazu müssen aber die passenden Werkzeuge unter bestimmten Voraussetzungen verwendet werden, die hier auch kurz dargestellt werden. Die Instanz-Verwaltung wird sich zudem auch immer auf die Datenbank beziehen, die mit einer Instanz gemountet oder geöffnet ist. Daher ist in diesem Abschnitt auch das ALTER-DATABASE-Kommando mit zwei Optionen zu finden. Um Parametrierungen der Instanz zu ändern, an die Instanz angemeldete Prozesse zu verwalten, Zugriffe zu sperren oder freizugeben und Redolog-Wechsel zu initiieren, steht das ALTER-SYSTEM-Kommando zur Verfügung. Abschließend werden noch Checkpoints behandelt.
2.5.1
Werkzeuge und Voraussetzungen
Das bekannteste Werkzeug zur Administration eines Oracle-Systems wird nach wie vor der Server Manager sein. Dieses seit Oracle-Version 7 verwendete Werkzeug wurde aber mit Oracle8i letztmalig unterstützt, ist also mit Oracle9i nicht mehr verfügbar. Voraussetzung für eine Reihe von Administrationskommandos wie STARTUP, SHUTDOWN, ARCHIVE usw. ist die privilegierte Anmeldung mit CONNECT / (username/password) AS SYSDBA (SYSOPER). In vielen Scripts wird auch noch CONNECT INTERNAL zu finden sein, was nur noch aus Kompatibilitätsgründen unterstützt wird, mit Oracle9i aber nicht mehr verwendet werden kann. Um ein CONNECT / AS SYSDBA ausführen zu können, muss der Betriebssystembenutzer über das Betriebssystem privilegiert sein. Unter Unix wird das durch die Zugehörigkeit zur Gruppe dba, unter MS-Windows durch die Zugehörigkeit zur Gruppe ora_dba realisiert. Meldet man sich mit username/password an, ist ein entsprechender Eintrag in der
Passwortdatei von Oracle Voraussetzung. Auf die Passwortdatei wird in Kapitel 4, Sicherheit, eingegangen. Seit SQL*Plus 8.1 wird das CONNECT / AS SYSDBA unterstützt, so dass SQL*Plus den Server Manager als Administrationswerkzeug auf Server-Ebene abgelöst hat. Es müssen also unter Oracle8i existierende Scripts, die den Server Manager aufrufen, auf die Benutzung von SQL*Plus umgestellt werden. Daneben gibt es für die Remote-Administration von Instanzen und Datenbanken den Enterprise Manager, der in einem eigenen Kapitel behandelt wird, und Werk-
Sandini Bib
110
Installation und Basiskonfiguration
zeuge von Fremdherstellern, die die Administration über grafische Oberflächen und Menüführungen erleichtern. Im Folgenden werden die Befehle für SQL*Plus vorgestellt, die zur Administration von Instanz und Datenbank notwendig sind.
2.5.2
Startup
Im Folgenden wird das STARTUP-Kommando vorgestellt, das ein Oracle-System in drei Phasen startet. Die Phasen werden als NOMOUNT, MOUNT und OPEN bezeichnet. Wie bereits erwähnt, ist eine Anmeldung an das Oracle-System mit CONNECT / AS SYSDBA Voraussetzung. Syntax: STARTUP
[FORCE][RESTRICT][PFILE=filename] [OPEN][RECOVER][database] [MOUNT] [NOMOUNT]
NOMOUNT Die Instanz wird in der ersten Phase, der NOMOUNT-Phase gestartet. Das bedeutet, dass in dieser Phase die SGA als Hauptspeicherstruktur angelegt wird und die Hintergrundprozesse gestartet werden. Wie groß die SGA ist und welche Hintergrundprozesse gestartet werden, ist von der Parametrierung der Instanz abhängig, die über Einträge in der Datei init<sid>.ora oder in einem SPFile vorgenommen wird. In der NOMOUNT-Phase wird die init<sid>.ora oder spfile<sid>.ora gelesen und die Parameter werden interpretiert. In Abschnitt 2.5.6 wird näher darauf eingegangen. Oracle versucht permanent, so viele Parameter wie möglich dynamisch änderbar zu implementieren. Unter Oracle8i ist für die Veränderung der Größe der SGA noch ein Stoppen und Starten der Instanz notwendig, ab Oracle9i können die Bereiche der SGA dynamisch verändert werden, wobei die Vergrößerung eines Bereichs zu Lasten eines anderen fällt. In dieser Phase läuft die Instanz ohne eine Verbindung zur Datenbank. Zu diesem Zeitpunkt können die Kommandos CREATE DATABASE und CREATE CONTROLFILE abgesetzt werden. Auch kann bereits auf einige V$-Tabellen zugegriffen werden. V$-Tabellen sind „virtuelle“ Tabellen, die SGA-Strukturen abbilden und auf Inhalte der Kontrolldateien zugreifen. Durch den Initialisierungsparameter control_files in der Parameterdatei ist die Anzahl und die Lage der Kontrolldateien bekannt. MOUNT MOUNT ist die zweite Phase, in der die Kontrolldateien geöffnet werden. Damit wird die Verbindung der Instanz zur Datenbank hergestellt. Die Kontrolldatei wird üblicherweise über Oracle-Mechanismen gespiegelt. In der MOUNT-Phase werden die gespiegelten Dateien geöffnet und miteinander verglichen. Nur wenn alle Spiegel identisch sind, wird die MOUNT-Phase erfolgreich beendet und die Kontroll-
Sandini Bib
Instanzverwaltung
111
dateien sind geöffnet. Damit sind sämtliche Verweise auf die Redolog-Dateien und die Datendateien mit den dazugehörigen Konsistenz-Informationen bekannt. In der MOUNT-Phase können Dateien umbenannt werden. Bei der Umbenennung werden die neuen Namen in die geöffneten Kontrolldateien eingetragen und ersetzen die alten Einträge. Ebenso muss die Instanz in den MOUNT-Status gebracht werden, wenn eine Wiederherstellung der Datenbank durchgeführt werden muss. Die Konsistenzinformationen aus den Kontrolldateien werden dann für die Bestimmung der Dateien und des Zielpunkts des Recovery benötigt. OPEN Wird beim Kommando STARTUP keine Phase spezifiziert, so ist OPEN die Voreinstellung. Es werden also automatisch alle drei Phasen durchlaufen. In der OPEN-Phase werden die Redolog-Dateien und die Datendateien, die in den Kontrolldateien verzeichnet sind, geöffnet, die Konsistenz-Informationen werden mit den Informationen in den Dateiköpfen verglichen. Stimmen die Informationen überein, sind die geöffneten Dateien für den Betrieb verfügbar. In dieser Phase wird die Notwendigkeit eines Crash-Recovery, z.B. nach einem Stromausfall, erkannt und automatisch durchgeführt. Werden neben den Informationen aus den Redolog-Dateien (Online Redolog Files) auch noch Daten aus den archivierten Redolog-Dateien benötigt, so wird die OPEN-Phase mit einer entsprechenden Fehlermeldung abbrechen. In diesem Fall muss in der MOUNT-Phase die Wiederherstellung der Datenbank durchgeführt werden, oder sie muss ohne die beschädigten Dateien geöffnet werden. Diese Punkte werden in Kapitel 6, Backup/Recovery, eingehend behandelt. OPEN RECOVER Der Parameter OPEN mit dem Zusatz RECOVER zeigt an, dass bei Erkennen einer Beschädigung einer Datendatei automatisch ein Recovery der Datenbank gestartet werden soll. Es werden so die Befehle STARTUP MOUNT und RECOVER DATABASE zusammengefasst. RESTRICTED Der Zusatz RESTRICTED beim Öffnen der Datenbank bewirkt, dass zwar alle Datendateien geöffnet werden und das Oracle-System damit voll verfügbar ist, der Zugriff jedoch nur Administratoren oder Benutzern erlaubt ist, die das Oracle-Systemprivileg RESTRICTED SESSION besitzen. Dieser Zustand der Datenbank ist dann interessant, wenn Aktivitäten durchgeführt werden müssen, die eine geöffnete Datenbank voraussetzen, bei denen aber Zugriffe von Anwendern unerwünscht sind. Ein Beispiel dafür ist die Reorganisation von Tabellen. FORCE Das Kommando STARTUP FORCE fasst die Einzelbefehle SHUTDOWN ABORT (s. nächster Abschnitt) und STARTUP zusammen. Dieser Befehl findet typischerweise seine Anwendung, wenn ein Oracle-System nach einem Systemabsturz, aus welchen
Sandini Bib
112
Installation und Basiskonfiguration
Gründen auch immer, wieder gestartet werden soll, aber noch Fragmente der abgestürzten Instanz vorhanden sind und das Starten verhindern. MOUNT Oracle Parallel Server Bis zu Oracle8 Version 8.0 gab es für die MOUNT-Phase eine Option, in der ausgewählt werden konnte, ob die Datenbank exklusiv oder parallel (shared) geöffnet wurde. Diese Mount Option entfällt seit Oracle8i. Es wird nun über den Initialisierungsparameter parallel_server eingestellt, ob die Datenbank im Modus EXCLUSIVE oder PARALLEL läuft. parallel_server = false | true
Syntaktisch werden die Mount-Optionen noch unterstützt, sie haben jedoch keine Auswirkung auf die MOUNT-Phase mehr.
2.5.3
Shutdown
Genau wie das Starten des Oracle-Systems läuft das Stoppen in drei Phasen ab. Die Phasen des Shutdown heißen CLOSE und DISMOUNT, danach wird die Instanz terminiert, d.h., die Hintergrundprozesse werden gestoppt und das Memory der SGA wird freigegeben. Hierbei ist ebenfalls ein CONNECT / AS SYSDBA (SYSOPER) Voraussetzung. Syntax: SHUTDOWN
[NORMAL] [IMMEDIATE] [TRANSACTIONAL] [ABORT]
NORMAL NORMAL ist die Voreinstellung beim Shutdown. In diesem Fall wird mit dem Stoppen
des Oracle-Systems so lange gewartet, bis sich alle Benutzer abgemeldet haben, neue Anmeldungen an die Instanz werden jedoch nicht mehr erlaubt. Als Erstes wird ein Checkpoint im fast mode (s. 2.5.7, Checkpoints) initialisiert, damit alle modifizierten Datenbankblöcke durch den Database Writer in die Datendateien geschrieben werden. Danach wird die Datenbank (Datendateien und RedologDateien) geschlossen (CLOSE), anschließend werden die Kontrolldateien aktualisiert und geschlossen (DISMOUNT). Abschließend werden alle Hintergrundprozesse beendet und die SGA wird freigegeben. Die Datenbank befindet sich dann in einem konsistenten Zustand und kann beispielsweise gesichert werden. Das SHUTDOWN NORMAL wird jedoch in der Praxis selten eingesetzt, da man sich nicht darauf verlassen kann, dass sich alle Anwender abmelden. Wenn Agents des Enterprise Managers gestartet sind, so sind diese permanent angemeldet und verhindern damit ein Stoppen des Oracle-Systems. Entweder müssen die Anwender per Script abgemeldet und die Agenten gestoppt werden, oder man verwendet eine der beiden Optionen IMMEDIATE oder TRANSACTIONAL.
Sandini Bib
Instanzverwaltung
113
IMMEDIATE Ein SHUTDOWN IMMEDIATE funktioniert genauso wie das SHUTDOWN NORMAL, mit dem Unterschied, dass nicht auf das Abmelden der Benutzer gewartet wird. Der Hintergrundprozess PMON terminiert alle angemeldeten Datenbankprozesse und rollt eventuell offene Transaktionen zurück. Hierbei wird auf die Beendigung der aktuell laufenden Anweisungen gewartet, neue Befehle werden nicht mehr ausgeführt. So kann auf die Beendigung eines UPDATE-Befehls gewartet werden, der anschließende COMMIT-Befehl wird aber nicht mehr akzeptiert. Dann folgen Checkpoint, Close, Dismount und Beendigung der Instanz. Da der Hintergrundprozess PMON alle offenen Transaktionen zurückgerollt hat, ist auch in diesem Fall die Datenbank in einem konsistenten Zustand und kann gesichert werden. TRANSACTIONAL Seit Oracle8 existiert ein neuer Parameter des SHUTDOWN-Befehls, der die Beendigung der laufenden Transaktionen erlaubt, das SHUTDOWN TRANSACTIONAL. Im Gegensatz zum SHUTDOWN IMMEDIATE wird auf die Beendigung von Transaktionen, nicht von Befehlen, gewartet. Neue Transaktionen können aber nicht mehr gestartet werden. In der Praxis ist jedoch die Gefahr gegeben, dass bei einer Online-Anwendung eine Transaktion noch aktiv ist, ein COMMIT jedoch nicht mehr abgesetzt wird. In diesem Fall würde durch eine automatisierte Sicherungsprozedur das Oracle-System nicht gestoppt werden können. In früheren Oracle-Versionen existierte für das SHUTDOWN TRANSACTIONAL eine Zeitangabe in Sekunden, nach der trotz laufender Transaktionen ein Shutdown durchgeführt wurde. Diese Angabe ist zwar syntaktisch noch möglich, wird aber nicht mehr ausgewertet. ABORT Mit SHUTDOWN ABORT wird ein absoluter Nothalt des Oracle-Systems durchgeführt. SHUTDOWN ABORT beendet sofort die Hintergrundprozesse und gibt die SGA frei. Es wird kein Checkpoint mehr ausgeführt, offene Transaktionen werden nicht zurückgerollt, Datendateien Redolog-Dateien und Kontrolldateien werden nicht geschlossen. Der daraus resultierende Zustand der Datenbank ist inkonsistent. Das bedeutet, dass beim STARTUP ein Instance Recovery durchgeführt werden muss. Eine solche Datenbank sollte nicht als Grundlage einer Offline-Sicherung verwendet werden. Dieses Kommando ist dafür vorgesehen, die „Reste“ einer abgestürzten Instanz zu beseitigen. Beendet sich ein Oracle-Hintergrundprozess durch einen Fehler, so werden auch alle anderen Hintergrundprozesse beendet. Auf Unix-Systemen wird jedoch unter dem Verzeichnis $ORACLE_HOME/dbs noch eine Datei lk<sid> zu finden sein. Bei einem Versuch eines STARTUP wird die Fehlermeldung ausgegeben, dass die Instanz bereits gestartet ist, ein SHUTDOWN bringt die Meldung, dass die Instanz nicht gestartet ist. Ein solcher Zustand wird mit SHUTDOWN ABORT besei-
Sandini Bib
114
Installation und Basiskonfiguration
tigt. SHUTDOWN ABORT wird implizit auch durch das Kommando STARTUP FORCE ausgeführt.
2.5.4
ALTER DATABASE
Einige Einstellungen von Instanz und Datenbank lassen sich nicht im STARTUPKommando spezifizieren, sondern nur über das ALTER DATABASE-Kommando. Befehle, die sich mit der Handhabung von Standby-Datenbanken beschäftigen, also mit deren Aufbau und dem Zugriff im Lesemodus, werden hier nicht behandelt, sondern sind in Kapitel 6, Backup/Recovery, zu finden. RENAME GLOBAL_NAME Globale Namen von Datenbanken sind Voraussetzung für verteilte Datenbanksysteme. In einer verteilten Umgebung, also bei Server-Server-Konfigurationen muss jeder Datenbank ein im System eindeutiger Name zugeordnet sein. Dieser globale Datenbankname kann über ALTER DATABASE RENAME GLOBAL_NAME TO domain.dbname geändert werden. In verteilten Datenbankumgebungen wird üblicherweise der globale Name einer Datenbank im entsprechenden Datenbank-Link verwendet. Wird der globale Name umbenannt, so müssen die Administratoren der Datenbanken informiert werden, in denen Verweise in Datenbank-Links auf die umbenannte Datenbank existieren, damit diese entsprechend angepasst werden können. CHARACTER SET / NATIONAL CHARACTER SET Der Character Set und der National Character Set einer Datenbank werden beim Anlegen der Datenbank angegeben und sind danach fest. Alle Zeichen, die in die Datenbank geschrieben werden, werden im Datenbankzeichensatz abgelegt. Über das Kommando ALTER DATABASE CHARACTER SET charset kann der Datenbankzeichensatz geändert werden, aber nur unter der Voraussetzung, dass der neue Zeichensatz eine Übermenge des alten Zeichensatzes ist. So kann eine Datenbank, die mit dem Zeichensatz US7ASCII angelegt worden ist, über den Befehl ALTER DATABASE CHARACTER SET we8iso8859p1 auf den Zeichensatz WE8ISO8859P1 umgestellt werden. Auch eine Umstellung auf zum Beispiel den Zeichensatz UTF8 wird unterstützt, eine Konvertierung der bereits abgelegten Zeichen wird automatisch durchgeführt.
2.5.5
ALTER SYSTEM
Eine weitere Gruppe von Instanz-Verwaltungsbefehlen wird über das Kommando ALTER SYSTEM angestoßen. Es werden hier nicht alle Optionen aufgeführt, sondern nur die, die für die Instanz-Verwaltung interessant wird. Für die komplette Syntax des Befehls sei auf die Dokumentation Oracle9i SQL Reference verwiesen.
Sandini Bib
Instanzverwaltung
115
ENABLE / DISABLE RESTRICTED SESSION Mit dem Befehl ALTER SYSTEM ENABLE RESTRICTED SESSION kann der Administrator den Zugang zur Datenbank für den „normalen Benutzer” sperren. Das ist immer dann sinnvoll, wenn Aktivitäten durchgeführt werden müssen, die zwar eine geöffnete Datenbank voraussetzen, aber keine Benutzeraktivitäten zulassen. Ein Beispiel hierfür ist die Reorganisation einer Tabelle. KILL SESSION Mit ALTER SYSTEM KILL SESSION 'sid,serial#' können Benutzerprozesse des Datenbanksystems gestoppt werden. Dieser Befehl bewirkt, dass noch laufende wichtige Aktivitäten, wie das Warten auf Antwort bei einer verteilten Transaktion oder ein Rollback, noch bearbeitet werden, dann der PMON-Prozess die Verbindung beendet und die Session als killed markiert. Ist die Verbindung nach einem Wartezustand tatsächlich beendet, geht der Status in dead über. Mit dem Zusatz IMMEDIATE wird sofort ein Rollback offener Transaktionen durchgeführt und alle Sperren werden aufgehoben. Die SID und SERIAL#, die als Parameter angegeben werden müssen, können aus der virtuellen Tabelle v$session abgelesen werden. Beispiel: SQL> SELECT username,sid,serial# FROM v$session WHERE username='SCOTT';
USERNAME SID SERIAL# ------------------------------ ---------- ---------SCOTT 13 4 SQL> ALTER SYSTEM KILL SESSION '13,4'; System altered. SQL> SELECT username,sid,status FROM v$session WHERE username='SCOTT'; USERNAME SID STATUS ------------------------------ ---------- -------SCOTT 13 KILLED Listing 2.21: Kill Session
DISCONNECT SESSION Der Befehl ALTER SYSTEM DISCONNECT SESSION ´sid,serial#´ arbeitet grundsätzlich so wie der KILL SESSION-Befehl. In diesem Fall wird der Server-Prozess terminiert. Der Zusatz POST_TRANSACTION bewirkt, dass auf die Beendigung offener Transaktionen gewartet wird. Der Status des Prozesses ist in dieser Zeit inactive. Mit
Sandini Bib
116
Installation und Basiskonfiguration
dem Zusatz IMMEDIATE wird der gleiche Effekt wie beim Kommando ALTER SYSTEM KILL SESSION 'SID,SERIAL#' IMMEDIATE erreicht. FLUSH SHARED POOL ALTER SYSTEM FLUSH SHARED POOL räumt in der SGA den Shared Pool auf, den
Bereich, in dem Data Dictionary-Informationen und Shared SQL und PL/SQL liegen. Durch das Aufräumen dieses Bereichs wird Speicherplatz von nicht mehr verwendeten Befehlen freigegeben und damit der Zugriff im Shared SQL-Bereich verbessert. SWITCH LOGFILE Im normalen Betrieb wird der Wechsel der Redolog-Dateien dann ausgeführt, wenn die gerade benutzte Datei gefüllt ist. Soll explizit ein Wechsel ausgeführt werden, wird dazu der Befehl ALTER SYSTEM SWITCH LOGFILE benutzt. Dieser Befehl wird dann gebraucht, wenn an einer Redolog-Gruppe gearbeitet werden muss, die gerade den Status current hat und dadurch Aktivitäten nicht erlaubt. Auch bei konventionellen Online-Backup-Prozeduren findet dieses Kommando seine Anwendung. SUSPEND / RESUME Mit dem Befehl ALTER SYSTEM SUSPEND werden alle I/O-Aktivitäten des Oracle-Systems auf Datendateien, Redolog-Dateien und Kontrolldateien angehalten. Mit ALTER SYSTEM RESUME werden sie wieder eingeschaltet. Diese Kommandos bieten eine Erweiterung zu Backup-Verfahren, bei denen Plattenspiegelungen aufgelöst werden. Für Details sei auf die Dokumentation Oracle9i SQL Reference, Kapitel 9, verwiesen.
2.5.6
Parametrierung
Eine Oracle-Instanz lässt sich in der Version 9i mit über 200 Parametern einstellen. Die Datei, in der diese Parameter pro Instanz spezifiziert sind, heißt init<sid>.ora und befindet sich auf UNIX-Systemen unter $ORACLE_HOME/dbs, auf MS-Windows unter %ORACLE_HOME%\database. Wie in Abschnitt 2.4 beschrieben, kann bei Oracle9i anstelle einer Datei init.ora auch mit einem SPFile (System Parameter File) gearbeitet werden. Dieses SPFile befindet sich in den gleichen Verzeichnissen wie die init.ora-Datei. Die wichtigsten Parameter, die nachträglich nicht oder nur schwer änderbar sind, wurden ja bereits in Abschnitt 2.4 vorgestellt. Die eingestellten Parameter einer Instanz lassen sich über die virtuelle Tabelle v$parameter abfragen. Feld
Beschreibung
num
Nummer des Parameters
name
Name des Parameters
type
Parametertyp (String, Number, Boolean)
Sandini Bib
Instanzverwaltung
117
Feld
Beschreibung
value
Aktueller Wert des Parameters
isdefault
TRUE oder FALSE, zeigt an, ob es der Standardwert ist.
isses_modifiable
TRUE oder FALSE, zeigt an, ob über ALTER SESSION veränderbar.
issys_modifiable
IMMEDIATE kann über ALTER SYSTEM verändert werden. DEFERRED ist nur für neue Anmeldungen gültig. FALSE kann nicht über ALTER SYSTEM verändert werden.
ismodified
MODIFIED zeigt Änderung über ALTER SESSION an. SYS_MODIFIED zeigt Änderung über ALTER SYSTEM an.
isadjusted
TRUE oder FALSE, zeigt an, ob der Parameter automatisch vom Datenbanksystem auf einen gültigen Wert korrigiert wurde.
description
Beschreibung des Parameters
Tabelle 2.1: Die virtuelle Tabelle V$PARAMETER
Die Initialisierungsdatei wird, wie vorher schon beschrieben, immer beim STARTUP in der MOUNT-Phase ausgelesen. Mit neueren Oracle-Versionen werden immer mehr Parameter zur Laufzeit der Instanz änderbar. Da eine Besprechung aller Parameter den Rahmen an dieser Stelle sprengen würde, sei hier auf die Oracle-Dokumentation verwiesen. Die komplette Beschreibung aller Parameter ist in der Dokumentation Reference zu finden. Zu jedem Parameter ist dort zu finden, ob der Parameter generell änderbar ist, ob er für einen bestimmten Prozess oder für das gesamte System zu Laufzeit geändert werden kann, welche Bereiche gültig sind und wie seine Standardeinstellung ist. Für Parameteränderungen, die auf Systemebene möglich sind, wir der Befehl ALTER SYSTEM SET parametername=wert;
verwendet.
2.5.7
Checkpoints
Ein Checkpoint ist ein notwendiger Mechanismus, um die Konsistenz der Datenbank zu garantieren. Bedingt wird dieses durch die asynchrone Arbeitsweise des Database Writers, der in der SGA modifizierte Blöcke nicht sofort wieder auf die Platte zurückschreibt. Zwar wird dieses Problem durch den Log Writer und die Redolog-Dateien gelöst, jedoch werden die im Falle eines Absturzes der OracleInstanz benötigten Informationen in den Redolog-Dateien zyklisch wieder überschrieben. In diesem Fall ist es unverzichtbar, diejenigen Blöcke aus der SGA auf die Platte zurückzuschreiben, die auf Grund der überschriebenen Informationen nicht wiederhergestellt werden könnten. Genau dieses wird durch einen Checkpoint gewährleistet. Ein anderes Ereignis für das Auslösen eines Checkpoints ist ein Schließen von Dateien wie zum Beispiel beim SHUTDOWN eines Oracle-Systems. Auch in diesem Fall sollen vor einem Schließen der Dateien alle modifizierten Daten auf die Festplatten zurückgeschrieben werden.
Sandini Bib
118
Installation und Basiskonfiguration
Außerdem kann ein Checkpoint zur Bildung eines Synchronisationszeitpunktes verwendet werden, wie es bei einem konventionellen Online-Backup notwendig ist. Folgende Ereignisse und Befehle lösen Checkpoints aus:
: : : : : : : :
Wechsel der Redolog-Dateien SHUTDOWN NORMAL / IMMEDIATE / TRANSACTIONAL LOG_CHECKPOINT_INTERVAL LOG_CHECKPOINT_TIMEOUT ALTER SYSTEM CHECKPOINT ALTER SYSTEM SWITCH LOGFILE ALTER TABLESPACE BEGIN BACKUP ALTER TABLESPACE OFFLINE NORMAL / TEMPORARY
Ist ein Checkpoint durch die genannten Ereignisse oder Befehle initiiert worden, so ist es Aufgabe des Database Writers, modifizierte Blöcke aus dem Database Buffer Cache der SGA auf die Festplatten zurückzuschreiben. Die Dauer eines Checkpoints ist also von der Größe des Database Buffer Cache in Verbindung mit der Transaktionsaktivität abhängig. Ein Checkpoint, der durch den Wechsel einer Redolog-Datei ausgelöst wird, soll den normalen Betrieb des Datenbanksystems möglichst wenig beeinträchtigen, kann dafür aber etwas länger dauern. Man spricht hier von einem Checkpoint im normal mode. Wird ein Oracle-System heruntergefahren, so soll dies möglichst schnell geschehen. Zudem muss sich der Database Writer nicht mehr um „normale Transaktionen“ kümmern, sondern kann sich nur um das Schreiben der modifizierten Blöcke kümmern, schreibt also den Checkpoint im fast mode. Die Beendigung eines Checkpoints wird im Kopf jeder einzelnen Datenbankdatei und in den Kontrolldateien mit der zum Zeitpunkt des Checkpoints aktuellen System Change Number (SCN) protokolliert. Diese Aufgabe wird durch den Checkpoint-Prozess CKPT wahrgenommen. Die Dauer für die Ausführung eines Checkpoints kann bei transaktionsorientierten Systemen mit größeren SGAs durchaus in den Minutenbereich gehen. Obwohl seit Oracle8 der Checkpoint-Algorithmus wesentlich verbessert worden ist, indem durch Speicherung von Zeitstempeln Checkpoints parallelisiert werden können, kann es dennoch zu Wartezuständen auf die Beendigung von Checkpoints durch eine zu hohe Frequenz von Redolog-Datei-Wechseln kommen. Man findet eine Protokollierung dieser Wartezustände in der Alert-Datei der Instanz mit der Meldung checkpoint not complete. Der früher bekannte Initialisierungsparameter db_block_checkpoint_batch für das Tuning des Checkpoints ist seit Oracle8i obsolet. Zur Vermeidung der Wartezustände müssen also die Redolog-Dateien vergrößert werden, oder es müssen zusätz-
Sandini Bib
Oracle Real Application Cluster
119
liche Redolog-Gruppen angelegt werden. Im ersten Fall wird die Anzahl der Checkpoints reduziert, im zweiten Fall können mehr Checkpoints parallel laufen. Bei einer Vergrößerung der Redolog-Dateien sollte daran gedacht werden, den Initialisierungsparameter log_checkpoint_interval auf einen entsprechend großen Wert zu setzen. Der Parameter gibt an, nach welcher Anzahl in die Redolog-Datei geschriebener Betriebssystemblöcke ein Checkpoint initiiert werden soll.
2.6
Oracle Real Application Cluster
Bei dem Produkt Real Application Cluster (oder kurz RAC) handelt es sich um die Weiterentwicklung der Oracle Parallel Servers. Dieses Produkt wurde unter Oracle Version 6 zunächst für DEC VMS-Cluster entwickelt (Version 6.2) und später auch auf andere Plattformen portiert. Heute ist dieses Produkt auf allen gängigen Betriebssystemen (Open-VMS, Unix, Linux, MS-Windows 2000) verfügbar und wird in unterschiedlicher Ausprägung eingesetzt.
2.6.1
Architektur
Während in einer „normalen“ Konfiguration eine Instanz auf eine Datenbank zugreift (und daher viele Anwender diese Begriffe synonym verwenden), ist Oracle Real Application Cluster so aufgebaut, dass mindestens zwei Instanzen auf unterschiedlichen Systemen auf eine gemeinsame Datenbank zugreifen.
Abbildung 2.14: Oracle Real Application Cluster
Die obige Abbildung veranschaulicht die Konfiguration. Beide Knoten (K01 und K02) greifen dabei gleichberechtigt auf die Datenbank DB1 zu. Folgende Voraussetzungen müssen dafür geschaffen werden: 1. Die Einbindung des Festplattensubsystems muss so erfolgen, dass keiner der beteiligten Systeme eine „Hoheit“ über die Daten bzw. das Subsystem hat. In der
Sandini Bib
120
Installation und Basiskonfiguration
Regel wird dies durch Multi Ported SCSI, SAN oder Fiberchannel Adapter erreicht. 2. Das Betriebssystem braucht eine so genannte Cluster-Software, die die Kommunikation zwischen den beteiligten Knoten übernimmt und dabei auch Fehleranalyse bzw. das Abschalten eines fehlerhaften Knotens veranlasst. Wie schon gesagt, gibt es diese Software für alle gängigen Betriebssysteme. 3. Die Festplatten müssen als Raw Devices konfiguriert werden, das bedeutet unter dem Betriebssystem Unix, dass keine Filesysteme genutzt werden können. Zur Zeit gilt nur für Open-VMS die Ausnahme, dass die Datenbank in einem Filesystem installiert werden darf. In näherer Zukunft ist allerdings damit zu rechnen, dass auch unter Unix so genannte Globale Filesysteme eingesetzt werden dürfen. 4. Konfiguration eines Distributed Lock Managers (DLM), der die Instanzen überwacht. Diese Software wird von Oracle für das entsprechende Betriebssystem mitgeliefert.
2.6.2
Installation
Das folgende Beispiel bezieht sich auf die Installation von Oracle Real Application Cluster auf zwei Rechnern unter SUN Solaris 2.8. Installationen unter anderen Unix-Derivaten oder MS-Windows verhalten sich ähnlich. Vorbereitungen Neben der Parametrierung des Betriebssystems für Veritas oder SUN-Cluster müssen wie bei einer Standardinstallation die Kernel-Parameter in der Datei /etc/systems gesetzt werden. Als nächstes wird ein Knoten (K01) für die Installation der Software genutzt. Dieser Knoten muss später auch für die Installation von Patches genutzt werden, da der Universal Installer zwar die Oracle-Software auf die beteiligten Knoten installieren kann, nicht jedoch das Inventory. Somit wird der Versuch, ein Patch auf einem anderen Knoten zu installieren, fehlschlagen, da das Inventory fehlt. Auf dem zweite Knoten (K02) wird der Benutzer oracle, das ORACLE_BASE-Verzeichnis und das Verzeichnis /var/opt/oracle erstellt. Außerdem wird im Home-Verzeichnis des Benutzers oracle eine Datei .rhosts angelegt, in dem der Knoten K01 als privilegierter Knoten eingetragen wird. Damit kann der Universal Installer die Software über rcp auf den zweiten Knoten übertragen. Installation DLM Vor der Installation der Oracle Software muss noch der Distributed-Lock-Manager (DLM bzw. UDLM unter Unix) auf den beteiligten Systemen installiert werden. Er befindet sich in einem Unterverzeichnis auf der ersten Installations-CD (meist opspatch oder racpatch-Verzeichnis). % cd /cdrom/disk1/racpatch % cp ORCLudlm.tar.Z /tmp
Sandini Bib
Oracle Real Application Cluster
121
% cd /tmp % uncompress ORCLudlm.tar.Z % tar xvf ORCLudlm.tar % cd /tmp % pkgadd -d . ORCLudlm Listing 2.22: Installation Unix Distributed Lock Manager
Nach der Installation des DLM muss das System neu gestartet werden. Damit ist diese Komponente automatisch aktiviert und der Oracle Universal Installer erkennt, dass es sich um eine Real Application Cluster-Installation handelt. Die weitere Software-Installation weicht nur unerheblich von einer Standardinstallation ab, einzig das Menü für die Auswahl der Knoten wird automatisch während des Installationsvorgangs angezeigt. Außerdem ist bei der Liste der zu installierenden Software zusätzlich die Real Application Cluster Software aufgeführt. Nach der erfolgreichen Installation sollte auf beiden Systemen die komplette Software im entsprechenden ORACLE_HOME installiert worden sein. Oracle empfiehlt, die Konfiguration und Administration des Real Application Clusters über das Kommando srvctl durchzuführen. Dagegen ist zwar prinzipiell nichts einzuwenden, in der von uns durchgeführten Installation hatte das Tool aber derartige Probleme, dass wir auf die weitere Benutzung verzichtet haben. Bevor der GSD (Global Service Daemon) gestartet werden kann, muss eine Konfigurationsdatei (srvconfig) angelegt werden. Die Datei /var/opt/oracle/srvConfig.loc enthält hierfür einen Zeiger, der auf ein Raw Device (Größe ca. 100Mbyte) zeigt, in dem die Konfiguration abgespeichert wird. srvconfig_loc=/dev/vx/rdsk/ora-dg/data01-100m
Auf dem ersten Knoten K01 wird jetzt diese Datei mit dem Befehl srvconfig –init erstmalig initialisiert. Danach kann auf beiden Knoten der GSD mit dem Befehl gsd gestartet werden.
2.6.3
Konfiguration der RAC-Datenbank
Es bietet sich auch beim Real Application Cluster an, den Oracle Database Configuration Assistant für die Installation zu verwenden. Da jetzt nicht mehr mit Oracle Managed Files gearbeitet werden kann, muss eine Lösung gefunden werden, wie die Raw Devices angegeben werden können. Hierfür gibt es eine zusätzliche Konfigurationsdatei, in der die Tablespaces und die entsprechenden Raw Devices eingetragen werden können und die dann über die Umgebungsvariable DBCA_RAW_CONFIG=dateiname genutzt werden kann. Um die Administration von Raw Devices zu vereinfachen, empfiehlt es sich, einige wenige unterschiedliche Größen zu konfigurieren. In unserem Fall haben wir die
Sandini Bib
122
Installation und Basiskonfiguration
Dateigrößen 100 Mbyte, 500 Mbyte und 2 Gbyte gewählt und die Devices dementsprechend benannt und durchnummeriert. system=/dev/vx/rdsk/ora-dg/data01-500m spfile=/dev/vx/rdsk/ora-dg/data02-100m users=/dev/vx/rdsk/ora-dg/data02-500m temp=/dev/vx/rdsk/ora-dg/data03-2g undotbs1=/dev/vx/rdsk/ora-dg/data01-2g undotbs2=/dev/vx/rdsk/ora-dg/data02-2g tools=/dev/vx/rdsk/ora-dg/data03-500m Control1=/dev/vx/rdsk/ora-dg/data03-100m Control2=/dev/vx/rdsk/ora-dg/data04-100m redo1_1=/dev/vx/rdsk/ora-dg/data05-100m redo1_2=/dev/vx/rdsk/ora-dg/data06-100m redo2_1=/dev/vx/rdsk/ora-dg/data07-100m redo2_2=/dev/vx/rdsk/ora-dg/data08-100m Listing 2.23: DBCA_RAW_CONFIG-Datei
Mit diesen Informationen kann jetzt der Database Configuration Assistant aufgerufen werden. Dieser trägt dann die entsprechenden Dateien für die Tablespaces ein. Das Oracle-Dokument Step-By-Step Installation of RAC on Sun Cluster v3 ist an dieser Stelle leider fehlerhaft, da es für alle Tablespaces die Endung 1 enthält. Wichtig ist, dass der Database Configuration Assistant schon während der Konfiguration überprüft, ob die Dateien vorhanden und vom Oracle-Benutzer schreibbar sind. Ist hier irgendwo ein Fehler, kann die Konfiguration nicht fortgesetzt werden. Nachdem die Konfiguration erfolgreich abgeschlossen wurde, steht der Erstellung der Datenbank nichts mehr im Wege. Die Initialisierungsdatei wird direkt so angelegt, dass sie alle erforderlichen Parameter für beide Instanzen enthält. Das folgende Beispiel zeigt die wichtigsten Parameter für die Datenbank mit dem Namen RAC und den Instanznamen RAC1 und RAC2. db_block_size=8192 db_cache_size=25165824 cluster_database_instances=2 db_name=RAC control_files=("/dev/vx/rdsk/ora-dg/data03-100m", "/dev/vx/rdsk/ora-dg/data04-100m") shared_pool_size=115343360 undo_management=AUTO undo_retention=10800 cluster_database=true RAC2.instance_name=RAC2 RAC1.instance_name=RAC1 RAC2.instance_number=2 RAC1.instance_number=1
Sandini Bib
Oracle Real Application Cluster
123
RAC1.thread=1 RAC2.thread=2 RAC1.undo_tablespace=UNDOTBS1 RAC2.undo_tablespace=UNDOTBS2 Listing 2.24: Initialisierungsdatei RAC
Gegenüber einer Oracle8i-Installation, bei der jede Instanz seine eigene Parameterdatei haben musste, gibt es jetzt eine gemeinsame Datei. Jede Instanz kann aber dennoch über ihren Instanznamen eigene Parameter in dieser Datei ablegen. Wichtig ist dies vor allen Dingen für die Konfiguration der Rollback-Segmente bzw. Undo-Tablespaces, da jede Instanz ihre eigenen Rollback-Segmente haben muss. Eine weitere Unterscheidung zur Version 8i ist der Parameter cluster_database=true, der angibt, dass es sich um eine Real Application Cluster-Instanz handelt. Beim Starten der Instanz kann jetzt nicht mehr angegeben werden, dass eine Instanz im Exclusive-Modus genutzt werden soll. Es bietet sich an, die Initialisierungsparameter in einem SPFile abzulegen. Leider hat Oracle hierfür noch keine geeignete Lösung gefunden, da der Kernel das SPFile im Verzeichnis $ORACLE_HOME/dbs erwartet, es für die gemeinsame Nutzung im Real Application Cluster-Betrieb aber auf ein Raw Device gelegt werden muss. Die Umgehungslösung ist hier, eine normale Initialisierungsdatei (initRAC1.ora bzw. initRAC2.ora) mit folgendem Eintrag im Verzeichnis $ORACLE_HOME/dbs anzulegen: spfile=’/dev/vx/rdsk/ora-dg/data02-100m
Anschließend können die Parameter über den ALTER SYSTEM-Befehl geändert werden. Soll die Änderung nur eine Instanz betreffen, so wird die Option SID = 1 oder SID = 2 verwendet. Der folgende Befehl würde z.B. einen größeren Cache für die Instanz 2 definieren: SQL> ALTER SYSTEM SET db_cache_size = 100000000 SCOPE=SPFILE SID=2
2.6.4
Starten und Stoppen von RAC
Nachdem die Datenbank erfolgreich installiert worden ist und die Initialisierungsparameter auf den einzelnen Instanzen angepasst wurden, können die Instanzen wie gewöhnlich hochgefahren werden. Da für das Starten der Instanz zunächst der GSD hochgefahren werden muss, empfiehlt es sich, ein Script zu schreiben, das alle Komponenten in der richtigen Reihenfolge startet. # # 1. Starten des Global Service Daemon # gsdctl start >> /opt/oracle/admin/RAC/startup.log 2>&1 if [ $? != 0 ] then echo "GSD kann nicht gestartet werden" >>
Sandini Bib
124
Installation und Basiskonfiguration
/opt/oracle/admin/RAC/bdump/gsd.log 2>&1 exit fi # # 2. Starten der Instanz # sqlplus /nolog <<EOF >> /opt/oracle/admin/RAC/startup.log 2>&1 connect / as sysdba startup EOF # # 3. Starten des Listeners # lsnrctl start >> /opt/oracle/admin/RAC/startup.log 2>&1 Listing 2.25: Starten einer RAC-Instanz
Das Stoppen der Instanz sollte dann in umgekehrter Reihenfolge erfolgen. Wenn Ihr Betriebssystem ein Global-Filesystem unterstützt, können und sollten Sie dieses für die archivierten Redolog-Dateien verwenden. Im Oracle Technology Network oder im Oracle Metalink gibt es eine Liste, welche Betriebssysteme mit Global-Filesystem unterstützt werden. Einbindung in den Oracle Enterprise Manager Um den Real Application Cluster aus dem Oracle Enterprise Manager heraus administrieren und überwachen zu können, müssen die Agenten auf den Knoten entsprechend informiert werden. Hierbei gibt es eine kleine Unwägbarkeit des Systems: Normalerweise wird in die Datei /var/opt/oracle/oratab der Instanzname und das entsprechende ORACLE_HOME-Verzeichnis eingetragen. In diesem speziellen Fall muss hier aber der Datenbankname eingetragen werden (also RAC anstelle von RAC1 bzw. RAC2). Wenn Sie dies beachten, wird der Agent nach dem Start die Real Application Cluster-Konfiguration erkennen. Auch im Oracle Enterprise Manager ist die Datenbank als Clusterdatenbank zu sehen.
2.7
Oracle Enterprise Manager
Der Oracle Enterprise Manager tritt mit den Zusatzpaketen als universelles Werkzeug für alle Datenbankaufgaben an. Im Folgenden wird daher die Funktion dieses sog. Frameworks näher beschrieben und auf die Verwendung der einzelnen Komponenten eingegangen. Sie sollten aber beim Einsatz des Enterprise Managers vorsichtig sein, da die Lizenzierung der einzelnen Module recht kompliziert ist: Einige Teile (z.B. die Konsole mit dem integrierten DBA-Studio) sind nicht kostenpflichtig, andere Teile (z.B. der Reorganisations-Assistent) gehören zum Umfang des Tuning Packs und können nur für die Oracle Enterprise Edition lizenziert werden.
Sandini Bib
Oracle Enterprise Manager
125
Wieder andere (z.B. die Advanced Events) gehören bei der Enterprise Edition zum Diagnostic Pack und bei der Standard Edition zum Standard Management Pack und sind damit unterschiedlich zu lizenzieren. Die Architektur des Enterprise Managers beruht auf drei Schichten: zum einen die Client-Komponente mit den entsprechenden Modulen für Monitoring, Tuning, Change Management und Tools für die täglich anfallenden Arbeiten eines Administrators. In der mittleren Schicht gibt es den Management Server, der als Repository für die Abspeicherung von gesammelten Daten, aber auch als Schnittstelle für E-Mail und Paging-Funktionen dient. Auf der Seite der Datenbanken vervollständigt dann ein Agent die Struktur. Dieser übernimmt alle Aufgaben des EreignisManagements und mit Einführung der Version 9i auch das Monitoring für den Performance Monitor oder Capacity Planer (der mit dem Enterprise Manager 1.5.5 eingeführte Data-Gatherer entfällt).
2.7.1
Konsole
Die Enterprise Manager-Konsole vereint in der Version 9i die alte Konsole und das Werkzeug DBA-Studio. Mit diesem Werkzeug können zunächst über Oracle Net die Datenbanken verwaltet werden, d.h., alle administrativen Aufgaben können mit der grafischen Oberfläche durchgeführt werden.
Abbildung 2.15: OEM-Architektur
Wenn man sich über den Management Server an die Konsole anmeldet, kann zusätzlich ein Repository genutzt werden, in dem neben den Kennworten auch die Ereignisse und Jobs definiert sind.
Sandini Bib
126
Installation und Basiskonfiguration
Die Datenbanken, Knoten, Webserver etc. werden entweder manuell oder über einen automatischen Dienst in der Konsole eingetragen. Bei der manuellen Einrichtung muss entweder eine Oracle Net-Konfigurationsdatei (tnsnames.ora) existieren, die dann als Ganzes oder in Teilen geladen wird, oder es werden direkt Adressen von Rechnern (z.B. bei der Verwendung von Hostnaming für Oracle Net) eingegeben. Bei der automatischen Erkennung wird ein Knotenname angegeben, und ein sog. Discoverer versucht, über den entsprechenden Agenten die Informationen über die dort befindlichen Datenbanken zu ermitteln und trägt diese im Repository ein. Aus der Konsole heraus können dann andere Werkzeuge aufgerufen werden.
2.7.2
Management Server
Der Management Server ist ein Prozess, der die gesamte Administrationsumgebung verwaltet. Zu diesem Prozess gehört ein Repository, das in einer beliebigen Datenbank liegen kann. Die Aufgaben des Management Servers gliedern sich in folgende Bereiche: 1. Verwaltung der Administratoren 2. Verwaltung der bevorzugten Benutzernamen und Kennworte der zu administrierenden Datenbanken, 3. Steuerung der Ereignisse und Jobs
Abbildung 2.16: Knoten erkennen
Sandini Bib
Oracle Enterprise Manager
127
4. Speicherung von Konfigurationsinformationen (z. B: Diagramme), 5. Speicherung von Ergebnissen von bestimmten Werkzeugen (SQL Analyze, Change Management Pack etc.). Es ist möglich, den Enterprise Manager auch ohne Management Server zu nutzen, nur sind dann die o.g. Punkte nicht vorhanden. Die Konfiguration des Management Servers geschieht über den Enterprise Manager Configuration Assistant, womit ein Repository in einer beliebigen Datenbank aufgebaut wird. Die Standardkonfiguration sollte dabei nicht genutzt werden, da dieses Werkzeug die Oracle9i Funktionen wie Oracle Managed Files oder Locally Managed Tablespaces nicht unterstützt. Sinnvoller ist es, wenn Sie vorher ein Tablespace mit Ihren Konfigurationsparametern anlegen und dieses dann angeben. Der bei dem Aufbau angegebene Benutzer ist der Besitzer des Repositorys in der Oracle-Datenbank, es ist nicht der Administrator des Management Servers. Der Management Server wird nach der Konfiguration automatisch gestartet. Unter MS-Windows wird dafür ein Dienst erstellt (z.B. OracleO901ManagementServer), unter Unix kann er mit dem Kommando oemctl start oms gestartet werden. An den Management Server kann man sich dann mit dem Administratorbenutzer SYSMAN anmelden. Das Standardkennwort ist hierbei oem_temp, es muss jedoch
sofort nach der ersten Anmeldung geändert werden. Sollten Sie das Kennwort vergessen haben, können Sie mit dem Script $ORACLE_HOME/sysman/admin/vduResetSysman.sql
das Kennwort wieder zurücksetzen.
2.7.3
Agent
Der Intelligent Agent ist ein Prozess, der auf dem zu administrierenden Knoten läuft und mit dem Management Server kommuniziert. Zu den Aufgaben des Agenten gehört die Ausführung von Jobs und Events sowie die Ermittlung von Monitoring-Informationen für den Performance-Monitor und Capacity-Planer. Für diese Aufgaben meldet sich der Agent unter einem bestimmten Benutzer an die entsprechende Datenbank an. Der Agent wird mit dem Befehl agtctl start oder als MS-Windows-Dienst gestartet und erhält seine Informationen vom Oracle Net-Listener des entsprechenden Knotens. Aus diesen Informationen werden dann zwei Dateien snmp_ro.ora und snmp_rw.ora im Verzeichnis $ORACLE_HOME/network/admin bzw. in dem entsprechenden Oracle Net-Verzeichnis erstellt. Während die Datei snmp_ro.ora bei jedem Start überschrieben wird und daher nicht geändert werden sollte (ro steht für Read-Only), können zusätzliche Parameter in der Datei dbsnmp_rw.ora eingetragen werden. Mit der Installation der Datenbank wird für den Agenten ein Schema dbsnmp mit dem Kennwort dbsnmp in der Datenbank angelegt. Dieses Schema hat Leserechte
Sandini Bib
128
Installation und Basiskonfiguration
auf fast alle Oracle-Objekte und kann deshalb im produktiven Umfeld ein Sicherheitsrisiko sein. Das Kennwort kann wie folgt geändert werden: 1. In der Datenbank: SQL> ALTER USER dbsnmp IDENTIFIED BY prodpwd;
2. In der Datei dbsnmp_rw.ora snmp.connect.<service_name>.name = prodpwd snmp.connect.<service_name>.password = prodpwd
Danach wird der Agent mit den neuen Parametern gestartet. Da der Agent permanent in der Datenbank angemeldet ist, ist es nicht möglich, eine solche Datenbank mit dem Befehl SHUTDOWN NORMAL herunterzufahren, es sei denn, der Agent wird vorher angehalten (agtctl stop).
Sandini Bib
3
Datenbankdesign
Beim Aufbau jeder Datenbank und jedes Datenbankschemas sind eine Fülle von Designentscheidungen zu treffen. Diese Entscheidungen stehen auf der einen Seite im Zusammenhang mit konkreten Anforderungen an die Funktionalität und Performance der betreffenden Installation und sind auf der anderen Seite abhängig von den gegebenen technischen Möglichkeiten des eingesetzten Datenbanksystems – in diesem Falle Oracle9i. Oftmals stehen mehrere Alternativen für eine Implementierung zur Verfügung. Das nachfolgende Kapitel möchte an dieser Stelle behilflich sein, um im „Wald“ der technischen Merkmale optimale Entscheidungen für die Implementierung von Schema- und Datenbankobjekten treffen zu können.
3.1
Namenskonventionen
Beim Umgang mit einer Datenbank werden auf den verschiedensten Ebenen Dinge benannt: Datenbanken, Instanzen, Dateien, Tablespaces, Tabellen, Views, Indizes usw. Neben den allgemeingültigen Regeln für die Benennung von Datenbankobjekten, die z.B. die maximale Länge und die erlaubten Zeichen festlegen und vom Datenbanksystem vorgegeben werden, ist es empfehlenswert, eigene Richtlinien für die Namensbildung zu schaffen. Warum denken wir an dieser Stelle über diese Namenskonventionen nach? Einige der in Frage kommenden Beweggründe sind: 1. Wenn wir darüber nachdenken, nachdem die Datenbank konfiguriert und die Daten geladen sind, ist es zu spät. 2. Eine Oracle-Datenbank wird auf verschiedenen Ebenen mit diversen Namen identifiziert (u.a. Datenbankname, Instanzname, Netzwerkdienstname sowie Dienstname). Sie können alle verschieden sein, müssen aber nicht. 3. Es gibt immer mehr Situationen, bei denen die im Unternehmen vorhandenen Datenbanken global betrachtet werden – der Enterprise Manager oder ein Storage-Subsystem bzw. SAN sind nur zwei Beispiele. Wenn dann fünf von acht Datenbanken ORACLE heißen, ist die Übersichtlichkeit dahin. 4. Konventionen können die Erschliessung des Kontextes der betreffenden Objekte erleichtern: pk$tabellenname kann dem Betrachter signalisieren, dass es sich um den Primaärschlüssel der Tabelle tabellenname handelt. Im Folgenden wird zunächst über Datenbanken und deren Namensgebung diskutiert; im Anschluss dann über die Namensgebung bei Datenbankobjekten.
Sandini Bib
130
3.1.1
Datenbankdesign
Datenbanken
Bei der Bennung von Datenbanken ist zu unterscheiden zwischen dem per Parameter vergebenen Datenbanknamen (db_name), dem Domänennamen der Datenbank (db_domain) und dem globalen Datenbanknamen, der aus den beiden genannten Parameter zusammengesetzt wird, jedoch auch – unabhängig davon – explizit gesetzt werden kann. Die folgenden Abschnitte erläutern die Zusammenhänge. Domänen Bei der Vergabe von Namen für eine Oracle-Datenbank gibt es zwei Stellen, an denen eine Domäne auftauchen kann:
:
:
Die db_domain wird zusammen mit db_name (beides Initialisierungsparameter) interner Bestandteil des Datenbanknamens; zusammen ergeben diese Namen auch den Standardwert für den Initialisierungsparameter service_names, der ab Oracle8i zur Adressauflösung bei den Netzwerkdiensten genutzt werden kann.1 Netzwerkdienstnamen, früher auch mit SQL*Net Alias oder Net8-Name bezeichnet, können ebenfalls mit einer Domäne versehen werden. Einen hohen Bekanntheitsgrad unter langjährigen Oracle-DBAs dürfte die Standarddomäne früherer Releases, world, haben.
Die beiden genannten Domänen haben eigentlich nichts miteinander zu tun. Sobald man allerdings mit dem Enterprise Manager arbeitet, entsteht plötzlich doch eine Verknüpfung: Bei der automatischen Erkennung von Netzwerkdiensten liefert der Oracle Agent dem Management-Server alle vorhandenen Instanzen und trägt sie sowohl in den Navigationsbaum als auch optional in die tnsnames.oraDatei ein – natürlich in der Form db_name.db_domain. Die Empfehlung an dieser Stelle lautet also, die Domänen in beiden Fällen gezielt zu nutzen und identisch zu halten. Mittels eines weiteren Initialisierungsparameters können die Domänen zusammen mit Datenbanknamen auf Datenbank-Links übertragen werden: Sobald global_names = true
steht, dürfen Datenbank-Links nur so benannt werden wie die Zieldatenbank. Diese Forderung ist gerade in gewachsenen Datenbanken schwer einzuhalten, da der funktionale Verlust, der durch das Deaktivieren eines Datenbank-Links entsteht, oft schwer zu überblicken ist. Fängt man jedoch mit einem neuen System bei Null an, so ist diese Einstellung unbedingt zu empfehlen. Einfache Empfehlungen für Standarddomänen sind firma.de, firma.com oder einfach firma. Da die im Oracle-Namensmodell verwendeten Domänen nicht identisch zu den (meist jedoch ähnlichen) Netzwerkdomänen sein müssen, können mit
1.
In der CONNECT_DATA-Klausel wird hierzu statt dem Parameter (SID=XXX) der Parameter (SERVICE_NAME=XXX[.DOM]) angegeben. Eine Verbindung wird hergestellt, wenn der angegebene SERVICE_NAME einem der in service_names angegebenen Namen entspricht.
Sandini Bib
Namenskonventionen
131
Hilfe der Domänen zusätzliche Informationen hinterlegt werden; z.B. können alle produktiven Datenbanken in die Domäne prod.firma.de gelegt werden. Datenbanknamen Ausgehend davon, dass Domänen verwendet werden, kann sich der Datenbankname auf die Funktion der Datenbank fokussieren. Datenbanknamen wie oradb sind wenig sinvoll. Es sollten eher Namen wie dwh für Data Warehouse, pps für die Datenbank eines PPS oder xyz für die Datenbank unter der Anwendung XYZ ausgewählt werden. Der Datenbankname kann insgesamt acht Zeichen lang sein. Im Hinblick auf die nächste Migration kann es sinnvoll sein, dem Datenbanknamen eine Nummer hinzuzufügen, also z.B. pps01. Der Datenbankname wird als Initialisierungsparameter db_name hinterlegt. Er kann beim CREATE DATABASE-Kommando angegeben werden. Es wird grundsätzlich empfohlen, dies zu tun – damit hat man die Sicherheit, mit den richtigen Initialisierungsparametern zu arbeiten. Arbeitet man z.B. mit der falschen Initialisierungsparameterdatei, so geht das CREATE DATABASE-Kommando schief, und das ist gut so. Der Datenbankname, zusammengesetzt aus db_name und db_domain, wird beim Anlegen der Datenbank u.a. dazu verwendet, den globalen Datenbanknamen abzuleiten. Dieser kann über die View global_name abgefragt werden. Der globale Datenbankname wird dazu verwendet, die Namen von Datenbank-Links zu erzwingen. Mit gesetztem Initialisierungsparameter globale_names = true
muss – wie bereits erwähnt – ein Datenbank-Link immer genauso heißen wie der globale Datenbankname der Zieldatenbank. Unabhängig vom eigentlichen Datenbanknamen kann der globale Datenbankname mit dem Kommando ALTER DATABASE RENAME GLOBAL_NAME TO globdb.firma.de;
geändert werden. Der Datenbankname selbst – Parameter db_name – kann ausschließlich über ein CREATE CONTROLFILE-Kommando geändert werden. Instanznamen In der Oracle-Architektur sind Datenbank und Instanz getrennt, und somit können auch verschiedene Namen vergeben werden. Der Instanzname verfügt nicht über eine Domäne; er muss allerdings auf jedem Knoten eindeutig sein. Auch wenn es nicht zwingend erforderlich ist – der Instanzname sollte gleich oder zumindest ähnlich dem Datenbanknamen sein. Auf Grund der fehlenden Domänen kann er aus Übersichtlichkeitsgründen leicht abgewandelt werden, z.B. kann die Instanz zur Datenbank dwh05.prod.firma.de den Namen pdwh05 tragen, um die Eigenschaft Produktivsystem auch im Instanznamen zu verdeutlichen.
Sandini Bib
132
Datenbankdesign
Die maximale Länge des Instanznamens, hinterlegt im Umgebungsparameter oracle_sid, ist plattformspezifisch. Acht Stellen werden bei den getesteten Plattformen problemlos akzeptiert; mehr als acht Stellen werden generell nicht empfohlen. Datenbanken im Netzwerk Sobald man auf eine Datenbank im Netzwerk zugreifen will, kommt zusätzlich zu den bereits diskutierten Namen ein Netzwerkdienstname ins Spiel. Hiermit wird die Datenbank im Netzwerk identifiziert. Netzwerkdienstnamen können mit Domänen versehen werden. Sie sehen daher den globalen Datenbanknamen sehr ähnlich und werden oft mit diesen verwechselt. Hat man sich bei den Datenbanknamen Gedanken gemacht, so kann man natürlich die Netzwerkdienstnamen identisch zu den Datenbanknamen inklusive Domäne wählen. Diese Wahl trifft z.B. auch der Enterprise Manager, wenn er eine über den Agenten entdeckte Datenbank in sein Repository einträgt. Oft gibt es für eine Datenbank mehrere Netzwerkdienstnamen. Oft wird für eine Anwendung ein spezieller Netzwerkdienstname verwendet, so dass die Anwendungsdaten bei Bedarf zwischen verschiedenen Datenbanken verschoben werden können. Dieses Konzept findet sich auch bei den Dienstnamen als Instanzparameter wieder: Hiermit kann jeder Instanz eine Liste von Diensten (service_names) mitgegeben werden. Der Parameter wird standardmäßig auf den Wert db_name.db_domain gesetzt. Beim Verbindungsaufbau über die Oracle Net-Schnittstelle wird ein service_name mitgegeben, der mindestens einem Wert aus der Liste der service_names der Instanz entsprechen muss.
3.1.2
Objektnamen
Grundregeln Folgende Regeln existieren für die Namensgebung von Objekten in der Datenbank: 1. Namen sind bis zu 30 Byte lang (Ausnahme: Datenbankname bis zu 8 Byte; Datenbank-Links bis zu 128 Byte). 2. Namen dürfen keine Anführungsstriche enthalten. 3. Groß-/Kleinschreibung wird bei Namen nicht unterschieden. 4. Namen müssen mit einem alphabetischen Zeichen des Datenbankzeichensatzes anfangen. 5. Namen können ausschließlich alphanumerische Zeichen, _, $ und # enthalten; Namen von Datenbank-Links zusätzlich . und @ . 6. Reservierte Worte dürfen nicht verwendet werden. 7. dual darf nicht verwendet werden. 8.
Auch nicht reservierte Worte, die aber eine Bedeutung im Oracle-Umfeld haben (z.B. DIMENSION oder SEGMENT), dürfen nicht verwendet werden.
Sandini Bib
Namenskonventionen
9.
133
Zwei Objekte im gleichen Namensraum (d.h. Schema) dürfen nicht den gleichen Namen haben.
10. Die Spalten einer Tabelle bzw. einer View müssen alle unterschiedliche Namen haben. Spalten unterschiedlicher Tabellen oder Views können gleich lautende Namen haben. 11. Prozeduren oder Funktionen innerhalb eines Packages können gleich lautende Namen haben, falls sie eine unterschiedliche Anzahl von Argumenten oder Argumente verschiedenen Typs haben. 12. Namen können in doppelten Anführungszeichen geschrieben werden. In diesem Fall treffen die Regeln 3 bis 7 nicht zu. Allgemeine Empfehlungen Neben den eigentlichen Regeln sind aber folgende Überlegungen wichtig, um Namen für Datenbankobjekte zu finden:
: : :
Namen sollten lesbar und ausführlich sein. Die 30 Zeichen können ruhigen Gewissens ausgenutzt werden. Aussagekräftige Namen erhöhen die Lesbarkeit von SQL-Befehlen und Programmen erheblich. Passend zu den Voreinstellungen vieler Design Werkzeuge sollten Tabellennamen im Plural definiert werden. (Entitäten werden meist im Singular definiert.) Spaltennamen für Spalten mit identischer Bedeutung sollten im gesamten Schema konsistent benannt werden. Somit können sowohl Beziehungen zwischen Tabellen als auch Sachverhalte klar umschrieben werden.
Eine Spalte, die den Preis eines Produktes in Euro angibt, sollte ruhig preis_in_euro genannt werden. Eine solche Spalte lediglich preis zu nennen, kann verwirrend sein (man denke nur an die Euro-Umstellung). Sollte die Währung in einer eigenen Spalte waehrung_id gekennzeichnet sein (wobei dies natürlich einen Fremdschlüssel in einer Tabelle waehrungen repräsentiert), so kann der Spaltenname z.B. preis_in_waehrung sein. An dieser Stelle empfehlen wir, für deutsche Namen mit Umlauten ae, oe und ue einzusetzen, obwohl auch Namen wie währungen möglich sind (dies auch ohne doppelte Anführungszeichen). Solche Namen können aber Probleme bereiten, z.B. wenn Sie bei der Programmierung in Oracle-fremden Produkten verwendet werden.
3.1.3
Systemobjekte
Auch für Systemobjekte wie Tablespaces, Datendateien, Rollback-Segmente usw. müssen Namen gefunden werden. Hierbei ist auf jeden Fall Kreativität gefragt, denn Systemobjekte sind für die Anwendung nicht unmittelbar erforderlich und spielen somit auch keine Rolle im System, die a priori benannt werden kann. Daher ist es wichtig, sich einige Grundregeln zu überlegen, um den Überblick im Datenbankdschungel nicht zu verlieren. Tablespaces für Systemobjekte wie Rollback- und Temporärsegmente sollten immer gleich genannt werden, z.B. rbs und temp. Bei Tablespaces für Anwendungsdaten
Sandini Bib
134
Datenbankdesign
bringt die Anwendung oft einen Vorschlag mit. Ansonsten nimmt man für eine Anwendung X gerne x_data für Tabellen, x_index für Indizes usw. Bei den Datendateien sollte gewährleistet sein, dass man am vollqualifizierten Dateinamen folgende Eigenschaften erkennen kann:
: : : :
Diese Datei gehört zu einer Oracle-Datenbank. Den Datenbanknamen (ohne Domäne) Den Tablespace-Namen Eine laufende Nummer für die n-te Datei des Tablespaces
Bei Rollback-Segmenten ist die Standardstrategie eine Nummerierung, z.B. rbs01, rbs02 usw. Lediglich Rollback-Segmente für spezielle Aufgaben sollten auch entsprechend genannt werden, z.B. rbs_batch.
3.2
Physische Implementierung von Entitäten
Die Analyse der Anforderungen und die daran anschließende Entwicklung eines konzeptionellen Datenmodells ist bekanntlich systemneutral, d.h. unabhängig von dem eingesetzten Datenbanksystem. Anders verhält es sich dagegen bei der Umsetzung des konzeptionellen Modells in das physische Datenmodell. Hierbei sind die technischen Möglichkeiten des Zielsystems – in unserem Fall des Datenbanksystems Oracle8i oder Oracle9i – mit den funktionalen und operationalen Anforderungen der betreffenden Anwendung in Einklang zu bringen. Die folgenden Abschnitte behandeln vor diesem Hintergrund die verschiedenen technischen Möglichkeiten, Entitäten in einer Oracle-Datenbank zu implementieren, und die mit diesen Möglichkeiten verbundenen Auswirkungen im Hinblick auf die Zugriffe und die Verwaltbarkeit der betreffenden Objekte. Ziel ist es dabei, die zur Verfügung stehenden Organisationsformen von Tabellen geschickt für die Optimierung von Zugriffen und Verwaltungsoperationen zu nutzen.
3.2.1
Überblick
Die Zeiten, in denen Entitäten einzig in Form von Heap-Tabellen oder Clustern implementiert werden konnten, sind lange vorbei. Mittlerweile existieren weitergehende Möglichkeiten der physischen Organisation, die – bei sinnvoller Nutzung – wesentlich zur Optimierung von Anwendungen und zur Vereinfachung der Administration beitragen können. Diese Organisationsformen sind im Einzelnen:
: : :
die „klassischen“ in Heap-Form organisierten Tabellen, die Daten unsortiert speichern, im Cluster abgelegte Tabellen, deren Daten in Abhängigkeit von Cluster-Schlüsseln physisch gespeichert werden, Index-organisierte Tabellen, deren Daten über B*Baumstrukturen organisiert sind,
Sandini Bib
Physische Implementierung von Entitäten
: : : :
135
partitionierte Tabellen, die physisch unabhängige Partitionen zu einer „logischen“ Tabelle zusammenfassen, externe Tabellen, die auf externe, in Dateiform abgelegte Daten zugreifen, temporäre Tabellen, die Daten für die Dauer einer Transaktion oder Session speichern, Objekttabellen, deren Datensätze über Objektbezeichner referenzierbar sind, und die die Einbettung von geschachtelten Tabellen (nested tables) erlauben.
Diese Organisationsformen werden mit ihren Besonderheiten in den folgenden Abschnitten im Detail besprochen.
3.2.2
Heap-organisierte Tabellen
Heap-organisierte Tabellen sind die „klassischen“ Datenbanktabellen von OracleSystemen. Sie speichern ihnen zugewiesene Datensätze unsortiert in einem beliebigen, für Insert-Operationen zur Verfügung stehenden Oracle-Block. Bei einer neu angelegten, leeren Tabelle bedeutet dies, dass die Daten in der Reihenfolge der Insert-Operationen nacheinander – im Anschluss an den Header-Block – in die Blöcke des betreffenden Datensegmentes geschrieben werden. Im fortgeschrittenen Zustand der Tabelle, nachdem auch DELETE- und UPDATE-Operationen die Tabelle verändert haben, werden Datenblöcke, die für INSERT-Operationen zur Verfügung stehen, über so genannte Freilisten verwaltet. Aufeinander folgende INSERT-Operationen werden dadurch nicht zwangsläufig in physisch aufeinander folgende Blöcke geschrieben, sondern können beliebig verstreut werden. Der jeweilige „Höchststand“ der Füllung wird durch die so genannte Hochwassermarke (high water mark) gekennzeichnet. Blöcke, die sich jenseits der Hochwassermarke befinden, haben demnach noch nie Datensätze für die betreffende Tabelle enthalten. Der Zugriff auf Heap-organisierte Tabellen erfolgt entweder durch das vollständige Lesen der Tabelle (full table scan) oder über eine vorgegebene Satzadresse. Beim vollständigen Lesen werden alle Blöcke vom Beginn des Segmentes bis zur Hochwassermarke gelesen. Bei dynamischen Tabellen mit einem hohen Anteil an DELETEOperationen kann dies bedeuten, dass entsprechend viele Leerblöcke gelesen werden müssen – ein typischer Fall für eine Reorganisation der betreffenden Tabelle. Der Zugriff über Satzadressen (rowids) erfolgt dagegen gezielt auf bestimmte Blöcke in bestimmten, über Dateinummern identifizierten Dateien. Die Hochwassermarke und die „Datenlöcher“ spielen in diesen Fällen keine Rolle. Die Satzadressen selbst werden in der Regel über entsprechende Indexzugriffe vom System ermittelt. Die Indizes werden in separaten Segmenten aufgebaut. Für aufwändig indizierte Tabellen kann der für Indizes benötigte Speicherplatz dem der Tabelle nahe kommen oder ihn gar überschreiten. Heap-organisierte Tabellen sind gut geeignet für Entitäten, die keine besonderen Anforderungen an die Menge der Daten, deren physische Speichersequenz oder deren Indizierung stellen. Heap-Tabellen sind darüber hinaus eine gute Standardlösung für den Fall, dass die genauen Anforderungen an die Speicherung nicht bekannt sind.
Sandini Bib
136
Datenbankdesign
Im folgenden Beispiel wird die Heap-Tabelle kunde mit den Attributen kdnr (Schlüssel), kname und kadresse erstellt. Die organization-Klausel ist dabei optional: CREATE TABLE kunde (kdnr NUMBER CONSTRAINT kunde_pk PRIMARY KEY, kname VARCHAR2(100), kadresse VARCHAR2(500)) ORGANIZATION HEAP;
3.2.3
Cluster
In Clustern abgelegte Tabellen speichern Daten in Abhängigkeit von ClusterSchlüsseln in für diese Cluster-Schlüssel ausgewiesenen Datenblöcken. Teilen mehrere Tabellen einen Cluster-Schlüssel, können sie gemeinsam in einem Cluster angelegt werden. Entsprechend werden Datensätze mit gleichen Cluster-Schlüsseln gemeinschaftlich gespeichert. Die Zuordnung von Cluster-Schlüsseln zu Datenblöcken und entsprechend der Zugriff auf diese Sätze wird über zwei unterschiedliche Verfahren – durch Indizierung und Hash-Algorithmen – geregelt. Dementsprechend sprechen wir von Index-Clustern oder Hash-Clustern. Index-Cluster Bei Index-Clustern übernimmt ein B*-Index, der so genannte Cluster-Index, die Reservierung einzelner Blöcke für bestimmte Cluster-Schlüssel. Da der Index im Kontext der Insert-Operationen gefüllt wird, erfolgt die Reservierung der Blöcke in der Reihenfolge, wie die Insert-Operationen der Cluster-Schlüssel von den Programmen durchgeführt werden. Die Hochwassermarke wird bei leeren Index-Clustern – wie auch bei Heap-Tabellen – synchron zu den Insert-Operationen verschoben. Im folgenden Beispiel wird der Index-Cluster testcl mit den Tabellen kunde und auftrag angelegt: CREATE CLUSTER testcl (kdnr NUMBER) INDEX; CREATE INDEX i$testcl ON CLUSTER testcl; CREATE TABLE kunde (kdnr NUMBER, kname VARCHAR2(100), kadresse VARCHAR2(500))CLUSTER testcl(kdnr); CREATE TABLE auftrag (aufnr NUMBER, kdnr NUMBER, aufdat DATE) CLUSTER testcl(kdnr); Listing 3.1: Anlegen Index-Cluster
Hash-Cluster Beim Hash-Cluster ist die Reihenfolge der Insert-Operationen nicht relevant für die Zuordnung der Datenblöcke zu den Cluster-Schlüsseln. Hier bestimmt eine HashFunktion den Block, in welchem ein Cluster-Schlüssel zu speichern ist. Die HashFunktion gibt in der Regel den Blockversatz relativ zum Beginn des betreffenden
Sandini Bib
Physische Implementierung von Entitäten
137
Segmentes an. Damit nicht mehrere Cluster-Schlüssel einen Datenblock teilen, muss beim Anlegen eines Hash-Clusters die erwartete maximale Anzahl von Cluster-Schlüsseln möglichst präzise angegeben werden. Diese Schlüsselanzahl bestimmt direkt die Anzahl der Blöcke, die unterhalb der Hochwassermarke bereitgehalten werden müssen – unabhängig davon, ob Daten eingefügt wurden oder nicht. Insert-Operationen bewegen daher nur dann die Hochwassermarke, wenn ein Blocküberlauf stattfindet. Im folgenden Beispiel wird der Hash-Cluster testclh mit den Tabellen kundeh und auftragh angelegt. Es werden 1.000 Cluster-Schlüssel erwartet. Entsprechend werden 1.000 Blöcke initialisiert. Die Hash-Funktion arbeitet – spezifiziert durch die hash is-Klausel – auf Basis der numerischen Spalte kdnr: CREATE CLUSTER testclh (kdnr NUMBER(10,0)) HASHKEYS 1000 HASH IS kdnr; CREATE TABLE kundeh (kdnr NUMBER(10,0), kname VARCHAR2(100), kadresse VARCHAR2(500)) CLUSTER testclh(kdnr); CREATE TABLE auftragh (aufnr NUMBER, kdnr NUMBER(10,0), aufdat DATE) CLUSTER testclh(kdnr); Listing 3.2: Anlegen Hash-Cluster
Cluster-Implementierungen sind keine Standardlösungen, sie sollten sorgfältig geplant werden. Generell können sie die folgenden Vorteile bieten:
: : :
„physische Joins“ durch die Speicherung mehrerer Tabellen in einem Cluster, sofern der Cluster-Schlüssel identisch mit dem Join-Schlüssel ist Adressierung der Datensätze im Hash-Cluster ohne Vorhandensein eines Indexes „sortierte“ Speicherung der Datensätze
Diesen Vorteilen stehen jedoch eine Reihe von Nachteilen gegenüber:
: : : : : :
Für den Fall, dass nur eine der im Cluster abgelegten Tabellen gelesen wird, kommt es zu erhöhten Blockzugriffen. bei nur partiell gefüllten Hash-Clustern erhöhte Anzahl von Blockzugriffen Ungenügende Füllung von Cluster-Blöcken bei „geringem“ Datenvolumen pro Cluster-Schlüssel; umgekehrt Verkettung von Cluster-Blöcken (Überlauf) bei „großem“ Datenvolumen pro Cluster-Schlüssel; nicht einschätzbare Wirkungen bei „schwankendem“ Datenvolumen pro Cluster-Schlüssel Eindeutigkeit kann nur über zusätzliche Indizes sichergestellt werden, die zusätzlichen Speicherplatz kosten. ineffiziente Segmentgrößen bei Hash-Clustern, wenn die Anzahl der ClusterSchlüssel nicht bekannt ist oder falsch eingeschätzt wurde Die Hash-Funktion kann nur für Gleichheitsoperatoren genutzt werden.
Sandini Bib
138
:
Datenbankdesign
Cluster können nicht repliziert und partitioniert werden.
Die vorangehenden Abschnitte machen deutlich, dass Cluster-Implementierungen nur selten zum Einsatz kommen dürften.
3.2.4
Index-organisierte Tabellen (IOT)
Index-organisierte Tabellen speichern ihre Daten – sortiert nach dem Primärschlüssel – in Form eines B*-Index-Baumes. Im Gegensatz zu normalen B*-Index-Bäumen enthalten die B*-Bäume von IOT-Tabellen jedoch auch Spalten, die nicht zu dem Tabellenschlüssel gehören. Es ist darüber hinaus möglich, bestimmte Spalten, die nicht zum Schlüssel gehören, „auszulagern“, d.h. außerhalb des B*-Baumes in einem separaten Segment – dem Überlaufbereich – zu speichern. Auf diese Weise können die Datensätze in den Blättern des Baumes kurz gehalten und dadurch der Baum kompakter aufgebaut werden. Beginnend mit Oracle8i lassen sich zusätzliche Sekundärindizes für IOT-Tabellen definieren, um Zugriffe, die nicht über die Primärschlüsselspalten erfolgen, zu optimieren. Diese Sekundärindizes enthalten logische Satzadressen für den Zugriff auf den Index-Baum. Da Einträge in IndexBäumen durch INSERT- und UPDATE-Operationen und damit verbundenen SplitOperationen auf den Index-Blättern möglicherweise verschoben werden, können Zugriffe über logische Satzadressen fehlschlagen. In diesen Fällen ist dann eine zusätzliche Scan-Operation über den Primärschlüssel notwendig, um den betreffenden Datensatz zu lesen. Im folgenden Beispiel wird die Index-organisierte Tabelle artikelpreis mit den Schlüsselspalten artnr, von_datum und bis_datum angelegt. Die Spalten kommentar und rabattliste werden dabei – sofern der Schwellenwert von 10 % pro Block und Datensatz überschritten wird – in einen Überlaufbereich ausgelagert, der sich in der Tablespace ts_over befindet: CREATE TABLE artikelpreis (artnr VARCHAR2(20), von_datum DATE, bis_datum DATE, preis_euro number(6,2), kommentar VARCHAR2(2000), rabattliste number(4), CONSTRAINT pk_artikelpreis PRIMARY KEY(artnr, von_datum, bis_datum) ) ORGANIZATION INDEX TABLESPACE ts_data PCTTHRESHOLD 10 INCLUDING preis_euro OVERFLOW TABLESPACE ts_over; Listing 3.3: Index-organisierte Tabelle
Im nächsten Beispiel wird der Sekundärindex i$artpreis_rab für die Spalte rabattliste angelegt: CREATE INDEX i$artpreis_rab ON artikelpreis(rabattliste);
Wie normale Indizes, so lassen sich auch Index-organisierte Tabellen zusätzlich komprimieren. Bei der Komprimierung werden die Spalten des Primärschlüssels in Präfix- und Suffixbereiche aufgeteilt und die wiederholt auftretenden Werte der Präfixe innerhalb eines Blockes unterdrückt. Durch die Komprimierung wird eine
Sandini Bib
Physische Implementierung von Entitäten
139
Verkürzung der Datensätze in den Blättern des Index-Baumes erreicht, die den Index kompakter und damit für I/O-Operationen effizienter machen. Im folgenden Beispiel wird die oben beschriebene Tabelle artikelpreis mit einer Komprimierung auf der ersten Schlüsselspalte – artnr – angelegt. Dementsprechend werden redundante Artikelnummern innerhalb eines Index-Blattes unterdrückt: CREATE TABLE artikelpreis (artnr VARCHAR2(20), von_datum DATE, bis_datum DATE, preis_euro NUMBER(6,2), kommentar VARCHAR2(2000), rabattliste NUMBER(4), CONSTRAINT pk_artikelpreis PRIMARY KEY(artnr, von_datum, bis_datum) ) ORGANIZATION INDEX COMPRESS 1 TABLESPACE ts_data PCTTHRESHOLD 10 INCLUDING preis_euro OVERFLOW TABLESPACE ts_over; Listing 3.4: Index-organisierte Tabelle (komprimiert)
Index-organisierte Tabellen sind sehr gut geeignet für die Umsetzung aller Entitäten, die einen großen Teil ihres Informationsgehaltes aus den Schlüsselspalten beziehen. Hierbei schlägt vor allem die Einsparung von Speicherplatz zu Buche, da keine separaten Segmente für Tabellen und Indizes angelegt werden müssen. Mögliche Kandidaten sind z.B.
: :
so genannte Intersection-Tabellen, die n:m-Relationen 2 des Datenmodells auflösen und große Referenztabellen, die nur wenige Spalten enthalten, die nicht zum Schlüssel gehören.
3.2.5
Partitionierte Tabellen
Partitionierte Tabellen bieten die Möglichkeit, Datensätze nach vorgegebenen Verteilungskriterien physikalisch unabhängig, d.h. in separaten Tablespaces mit unterschiedlich großen Extents, zu speichern und diese Partitionen separat zu verwalten. Aus Sicht der Anwendung sind alle Daten über den Namen der partitionierten Tabellen les- und schreibbar, der Optimizer dagegen kennt die physikalische Aufteilung der Tabelle und ist in der Lage, entsprechende Zugriffspfade zu generieren. Die zu einer partitionierten Tabelle gehörenden Indizes lassen sich ebenso partitionieren – nach eigenständigen oder identischen Kriterien wie die Tabelle selbst. Für die Festlegung der Verteilungskriterien stehen drei unterschiedliche Strategien zur Verfügung:
: : 2.
Die Range-Partitionierung verteilt die Daten nach festen, in der Syntax vorgegebenen Wertebereichen. Die Hash-Partitionierung regelt die Verteilung über eine Hash-Funktion. Jedes A bezieht sich auf ein oder mehrere B und umgekehrt kann sich jedes B auf ein oder mehrere A beziehen.
Sandini Bib
140
: :
Datenbankdesign
Die Composite-Partitionierung kombiniert die beiden oben erwähnten Methoden, indem für jede Range-Partition mehrere Hash-Subpartitionen angelegt werden. Ab Oracle9i steht mit der List-Partitionierung ein weiteres Verteilungskriterium zur Verfügung, wodurch die Zuteilungen zu Partitionen über beliebige, disjunkte Wertelisten erfolgen.
Durch die Aufteilung der Daten in „kleinere“ Partitions-Segmente kann grundsätzlich eine bessere Verwaltbarkeit und ein effizienterer Aufbau der Indizes erreicht werden. Für wirklich große Tabellen, d.h. Tabellen im Gigabyte-Bereich, sollte die Partitionierung auf jeden Fall in Erwägung gezogen werden. In Kapitel 3.4 werden die Details dieses Themas ausführlich behandelt.
3.2.6
Externe Tabellen
Ab der Version 9i ist es möglich, externe, im Dateisystem abgelegte Daten mit Hilfe von „externen“ Tabellen so in die Datenbank zu integrieren, dass ihr lesender Zugriff über normale SQL-Befehle durchgeführt werden kann. UPDATE-, INSERTund DELETE-Operationen sowie das Anlegen von Indizes sind dagegen in diesem Kontext nicht möglich. Die externen Daten können jedoch mit Hilfe von Funktionen und Ausdrücken beliebig abgefragt, in Views integriert, über Synonyme referenziert oder nach Spalten sortiert werden. Externe Tabellen werden im Data Dictionary hinsichtlich ihrer Spaltenstruktur, der Lokation ihrer externen Daten sowie der für das Lesen der Daten notwendigen Formatmaske definiert. Der Zugriff auf die externen Daten erfolgt schließlich über einen in die Datenbank integrierten Treiber. Um mit externen Tabellen arbeiten zu können, muss zunächst einmal ein Datenbankverzeichnis angelegt werden. Dem im Data Dictionary definierten Aliasnamen wird dabei ein externes Verzeichnis auf dem Datenbankserver zugeordnet. Im folgenden Beispiel wird dem Datenbankverzeichnis dat_dir das externe Verzeichnis /home/oracle zugeordnet: CREATE OR REPLACE DIRECTORY dat_dir AS '/home/oracle';
Der Benutzer, der die externe Tabelle anlegen will, muss als Nächstes in der Datenbank Leserechte für dieses neue Datenbankverzeichnis erhalten: GRANT READ ON DIRECTORY dat_dir TO scott;
Sollen die Zugriffe auf die externen Daten in einer Log-Tabelle protokolliert oder Formatverletzungen in eine Bad-Datei geschrieben werden, sind darüber hinaus Schreibrechte für das Verzeichnis zu vergeben: GRANT WRITE ON DIRECTORY dat_dir TO scott;
Im nächsten Schritt kann dann die externe Tabelle – in diesem Fall exttab – definiert werden:
Sandini Bib
Physische Implementierung von Entitäten
141
CREATE TABLE scott.exttab (empno NUMBER(4), ename VARCHAR2(10) ) ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY dat_dir ACCESS PARAMETERS (records delimited by newline badfile dat_dir:'exttab%p.bad' logfile dat_dir:'exttab%p.log' fields terminated by ',' missing field values are null (empno,ename) ) LOCATION ('exttab.txt') ) PARALLEL REJECT LIMIT UNLIMITED; Listing 3.5: Externe Tabelle
In diesem Beispiel wird die externe Tabelle exttab mit den Spalten empno und ename angelegt. Die zugrunde liegende Datei wird in der LOCATION-Klausel angegeben. Die Zeilen der Tabelle sollen sich aus den Zeilen dieser Datei ergeben (NEWLINE-Klausel); die Felder sind entsprechend durch Kommata getrennt gespeichert. Auf die Datei wird über den Treiber Oracle_Loader – siehe die TYPE-Klausel – zugegriffen. Die Datei Exttab.txt kann durchaus mehr als die hier angegebenen „Spalten“ enthalten, entsprechende, weiterführende Einträge werden ignoriert. Für den Fall, dass die „Spaltenwerte“ der Datei sich nicht im Rahmen der definierten Datentypen und längen – hier NUMBER(4) und VARCHAR2(10) – darstellen lassen, wird eine Fehlerdatei geschrieben – siehe die BADFILE-Klausel. In diesem Beispiel wird der Name der Datei aus den Elementen exttab, der Prozessnummer des betreffenden Serverprozesses und der Dateierweiterung txt gebildet. Jeder Zugriff wird darüber hinaus in einer Log-Datei – LOGFILE-Klausel – protokolliert. Zugriffe werden über die gewohnte SQLSyntax generiert, die Selektion von Rowids ist jedoch – aus nahe liegenden Gründen – nicht möglich. Die PARALLEL-Klausel sorgt für eine Parallelisierung der Zugriffe, was jedoch nur für große Datenmengen Laufzeitvorteile mit sich bringt. Externe Tabellen sind vor allem dort interessant, wo externe Daten konsolidiert und geladen werden müssen. Die Dateien können auf diese Weise direkt aus der Datenbank heraus – z.B. im Kontext von PL/SQL-Prozeduren – selektiert, die Daten über SQL-Funktionen entsprechend verdichtet und in interne Tabellen übernommen werden. Der aufwändige Aufruf von separaten Werkzeugen, wie z.B. SQL*Loader, ist damit in vielen Fällen nicht mehr notwendig. Ebenso ist es möglich, die der externen Tabelle zugeordneten Datendateien durch gleichnamige zu ersetzen. Dadurch kann der Datenbestand komplett ausgetauscht werden, ohne die Definition der externen Tabelle in der Datenbank ändern zu müssen.
Sandini Bib
142
3.2.7
Datenbankdesign
Temporäre Tabellen
Der Terminus „temporäre Tabellen“ (temporary tables) ist etwas irreführend: Was an temporären Tabellen „flüchtig“ ist, sind ihre Daten, keineswegs jedoch ihre im Data Dictionary definierte Struktur. Einmal angelegt sind sie – entsprechende Privilegien vorausgesetzt – für alle Benutzer sichtbar und benutzbar. Die Daten, die sie speichern, werden jedoch am Ende jeder Transaktion oder am Ende der betreffenden Session automatisch gelöscht. Sie sind grundsätzlich – auch nach einer COMMITOperation – nur für den einfügenden Benutzer sichtbar. Physisch speichern temporäre Tabellen ihre Daten in der temporären Tablespace des anlegenden Benutzers, und dies auch erst zum Zeitpunkt der betreffenden Insert-Operation. Aus diesem Grunde führt die Verwendung der TABLESPACE-Klausel bei temporären Tabellen zu Fehlern. Sie können beliebig indiziert, über Views – auch zusammen mit regulären Tabellen – referenziert und mit Triggern belegt werden. DML-Operationen auf ihren Daten erzeugen nur für die Rollback-Informationen Redo Log-Einträge, nicht jedoch für die geänderten Datenblöcke. Im folgenden Beispiel wird die temporäre Tabelle load erzeugt, deren Daten bis zum Ende jeder Session erhalten bleiben sollen. CREATE GLOBAL TEMPORARY TABLE load (startdate DATE, enddate DATE, class CHAR(20)) ON COMMIT PRESERVE ROWS; Listing 3.6: Temporäre Tabelle
Zum Einfügen und Selektieren von Daten werden herkömmliche SELECT- und INSERT-Befehle benutzt. Indizes werden über den CREATE INDEX-Befehl – ohne TABLESPACE- und STORAGE-Klausel – erzeugt, setzen allerdings voraus, das die betreffende Tabelle vollständig leer ist. CREATE INDEX t$load ON load(class) * FEHLER in Zeile 1: ORA-14452: Versuch, einen Index auf einer schon verwendeten temporären Tabelle zu erstellen, zu ändern oder zu löschen
Temporäre Tabellen sind sehr gut für die Zwischenspeicherung und spätere Konsolidierung von Daten geeignet. Beliebig viele Anwendungen mit gleichen Anforderungen an temporäre Speicherstrukturen können sich jeweils eine temporäre Tabelle teilen, ohne Bezeichner für die Identifizierung der eigenen Daten mitzuführen. Die Daten können dabei intern entstehen und intern weiterverarbeitet werden oder in einem ersten Schritt von externen Ressourcen geladen und dann intern konsolidiert werden. Durch das reduzierte Redo Log-Volumen können temporäre Tabellen im Kontext großer Datenmengen verwendet werden. Ein weiterer Vorteil ist dadurch gegeben, dass sie ihren Speicherplatz nicht permanent in Form eines
Sandini Bib
Physische Implementierung von Entitäten
143
eigenen Segmentes anlegen, sondern diesen – beim Vorhandensein von Daten – aus dem Speichervolumen des temporären Tablespaces beanspruchen. Temporäre Tabellen haben unter Oracle9i durch das Aufkommen von externen Tabellen für das Laden externer Daten an Bedeutung verloren, sind hier aber immer noch interessant für die interne Zwischenspeicherung. Leider ist es nicht möglich, parallele Abfragen oder parallele DML-Operationen auf Temporär-Tabellen auszuführen, außerdem können sie nicht partitioniert werden.
3.2.8
Objekttypen und Kollektionen
Seit der Version 8.0 des Oracle-Datenbanksystems stehen eine Reihe objektrelationaler Merkmale zur Verfügung. Die Liste dieser Merkmale wurde unter Oracle8i und – vor allem – unter Oracle9i erweitert, so dass nun eine beachtliche Bandbreite objektorientierter Techniken – inklusive der Vererbung und Polymorphie – für Designimplementierungen zur Verfügung stehen. Eine ausführliche Besprechung dieser Merkmale liegt außerhalb der Ziele dieser Publikation. Auf den folgenden Seiten soll jedoch ein kurzer Überblick über die Möglichkeiten gegeben werden, konzeptionelle Vorgaben in Oracle8i und Oracle9i umzusetzen. Weitergehende Informationen zu diesem Thema finden sich in Kapitel 10. Objekttypen Objekttypen sind die Grundbausteine der objektorientierten Welt. Sie werden im Kontext von Oracle auch als „benutzerdefinierte Datentypen“ (user-defined datatypes) bezeichnet. Objekttypen bestehen ihrerseits aus Attributen und Methoden. Attribute sind entweder skalare Datentypen, wie z.B. NUMBER und VARCHAR2, Referenzen oder andere benutzerdefinierte Datentypen. Methoden (member functions) sind Prozeduren oder Funktionen, die relevante Abläufe für die Objekte des betreffenden Typs abbilden. Methoden können in PL/SQL oder Java codiert und als solche in der Datenbank gespeichert werden. Methoden, die in anderen Sprachen – z.B. C – realisiert wurden, werden dagegen extern gehalten, sind aber über gespeicherte Prozeduren ansprechbar. Neben den vom Benutzer frei definierbaren Methoden gibt es vordefinierte Methoden: Konstruktoren (constructor methods) dienen dem Anlegen und Ändern von Objekten eines Typs und heißen so wie der Objekttyp selbst. Objekttypen sind sehr gut geeignet, wiederverwendbare Attributgruppen mit für sie relevanten Prozedurabläufen zu definieren und in unterschiedlichen – relationalen wie objektrelationalen – Schemakontexten einzusetzen. Im folgenden Beispiel wird der Objekttyp adresse angelegt, der aus den Attributen strasse, postfach, plz , ort und land besteht.
Sandini Bib
144
Datenbankdesign
CREATE OR REPLACE TYPE adresse AS OBJECT( strasse VARCHAR2(50), postfach VARCHAR2(20), plz VARCHAR2(20), ort VARCHAR2(50), land VARCHAR2(50)) / Listing 3.7: Anlegen Objekttyp adresse
Einmal definiert, lassen sich Objekttypen als Spaltenobjekte (column object) oder Zeilenobjekte (row object) verwenden. Spaltenobjekte Objekttypen, die als Attribute in anderen Objekttypen oder in relationalen TupelTabellen verwendet werden, bezeichnet man als Spaltenobjekte. Auf diese Weise lassen sich Objekttypen als „Attributgruppen“ beliebig oft einsetzen. Im folgenden Beispiel wird die relationale Tabelle firma angelegt, die – neben zwei skalaren Attributen – den Objekttyp adresse verwendet: CREATE TABLE id name anschrift /
firma( INTEGER CONSTRAINT pk_firma PRIMARY KEY, VARCHAR2(100), adresse)
Listing 3.8: Anlegen Tabelle
INSERT-Operationen für diese Tabelle müssen den – mit dem Objekttyp automatisch vordefinierten – Konstruktor adresse verwenden: INSERT INTO firma VALUES (1,'DATABASE Consult', adresse(NULL,NULL,'83676','Jachenau',NULL) );
Für den Zugriff auf einzelne skalare Attribute des Objekttyps adresse ist der Attributname der implementierenden Tabelle und der des Objekttyps anzugeben. Im folgenden Beispiel werden entsprechend nur der Firmenname und Ort selektiert: SELECT f.name, f.anschrift.ort FROM firma f;
Die – für relationale Begriffe – ungewohnte Syntax lässt sich nötigenfalls durch eine View kaschieren: CREATE VIEW firma_view AS SELECT f.name name , f.anschrift.ort ort FROM firma f; SELECT name, ort FROM firma_view; Listing 3.9: Benutzung von Views
Sandini Bib
Physische Implementierung von Entitäten
145
Spaltenobjekte liegen auch dann vor, wenn Objekttypen in anderen Objekttypen verwendet werden. Der Objekttyp person verfährt so: CREATE OR REPLACE TYPE person AS OBJECT( vorname VARCHAR2(30), nachname VARCHAR2(30), anschrift adresse) / Listing 3.10: Anlegen von Objekttyp person
Objekttabellen und Zeilenobjekte Objekttypen, die vollständige Zeilen in Objekttabellen definieren, werden als Zeilenobjekte bezeichnet. Zeilenobjekte lassen sich aus Objekttypen heraus referenzieren. Im folgenden Beispiel wird die Objekttabelle personen auf der Basis des Objekttyps person angelegt: CREATE TABLE personen OF PERSON OBJECT IDENTIFIER IS SYSTEM GENERATED;
Die in Objekttabellen gespeicherten Objekte werden über Objektbezeichner (object identifier) referenziert. Standardmäßig legt Oracle – wie in diesem Beispiel ( ...IDENTIFIER IS SYSTEM GENERATED...) – eine interne OID-Spalte in der Länge von 16 Byte für die interne Referenzierung der Objekte an. Alternativ lässt sich auch der Primärschlüssel einer Tabelle hierzu einsetzen (…IDENTIFIER IS PRIMARY KEY...), der jedoch nicht – wie der generierte Bezeichner – eine globale Eindeutigkeit garantiert und ggf. auch mehr Speicherplatz benötigt. Auch im Falle der Objekttabellen werden die Attributwerte über Konstruktoren eingefügt: INSERT INTO personen VALUES ('Otto','Müller', adresse(NULL,NULL,'PLZ','Ort',NULL) );
Zeilenobjekte lassen sich über ihre Objektbezeichner referenzieren. Im nächsten Beispiel wird zunächst der Objekttyp auftrag angelegt, dessen Attribut auftraggeber den Objekttyp person referenziert: CREATE OR REPLACE TYPE auftrag AS OBJECT ( aufnr INTEGER, datum DATE, auftraggeber REF person , kommentar VARCHAR2(500) ) / Listing 3.11: Anlegen von Objekttyp auftrag
Sandini Bib
146
Datenbankdesign
Im zweiten Schritt wird nun die Objekttabelle auftraege auf der Basis des Typs auftrag angelegt: CREATE TABLE auftraege OF auftrag;
Damit das Attribut auftraggeber der Objekttabelle auftraege nicht alle möglichen Tabellenimplementierungen des Objekttyps person referenziert, wird der Gültigkeitsbereich dieses Attributes in der Tabelle auftraege im folgenden Beispiel auf die Objekte der Objekttabelle personen beschränkt. Mit anderen Worten: Das Attribut auftraggeber der Tabelle auftraege referenziert nur Datensätze aus der Tabelle personen: ALTER TABLE auftraege ADD(SCOPE FOR (auftraggeber) IS personen);
Durch die Einschränkung des Gültigkeitsbereiches über die SCOPE-Klausel wird auch die interne Speicherung des betreffenden Attributes optimiert! Einschränkungen sollten daher nach Möglichkeit durchgeführt werden. Für das Einfügen von Personenreferenz in die neue Tabelle ist der REF-Operator zuständig, der, wie das Beispiel zeigt, über einen eindeutigen (!) Zugriff auf die Tabelle personen den Objektbezeichner zuordnet: INSERT INTO auftraege SELECT 12345, SYSDATE, REF(p), 'Kommentar' FROM personen p WHERE p.nachname = 'Müller' AND p.vorname = 'Otto'; Listing 3.12: Einfügen mit REF
Beim Selektieren der Auftragsdaten ist die Syntax – dank der Möglichkeit der impliziten Dereferenzierung – einfacher. Für diese Dereferenzierung muss auf jeden Fall ein Aliasname angegeben werden: SELECT a.aufnr, a.auftraggeber.nachname, a.auftraggeber.vorname FROM auftraege a /
Kollektionen Kollektionen lassen sich als Behältnis für mehrere gleichartige Objekte begreifen. Es stehen zwei unterschiedliche Typen von Kollektionen bereit:
:
:
Varrays – sind geordnete Kollektionen von Elementen gleichen Datentyps, deren maximale Anzahl bei der Definition festgelegt wird und nicht überschritten werden kann. Einzelne Elemente von Varray-Kollektionen können darüber hinaus nicht beliebig gelöscht und eingefügt werden. Varrays können als Datentypen für Attribute relationaler Tabellen oder für Attribute von Objekttypen verwendet werden. Nested Tables – sind ungeordnete Kollektionen von Elementen gleichen Datentyps, die nicht in ihrer Maximalzahl festgelegt werden und aus nur einem Attri-
Sandini Bib
Physische Implementierung von Entitäten
147
but bestehen. Das Attribut einer geschachtelten Tabelle ist entweder ein skalarer Datentyp oder ein Objekttyp. Geschachtelte Tabellen werden – wie auch Varrays – als Datentypen für Attribute relationaler Tabellen oder für Attribute von Objekttypen verwendet. Im folgenden Beispiel wird das Varray telnummern angelegt, das die Speicherung von maximal zehn Telefonnummern pro Objektinstanz gestattet: CREATE OR REPLACE TYPE telnummern AS VARRAY(10) OF VARCHAR2(20) /
Dieses Varray kann nun in dem Objekttyp pers_tel verwendet werden: CREATE OR REPLACE TYPE pers_tel AS OBJECT ( personenangabe person, telefon telnummern) / Listing 3.13: Objekttyp mit VARRAY pers_tel kann dann – wie oben beschrieben – weiterverwendet werden. Zum Ein-
fügen von Varray-Attributen stehen ebenfalls vordefinierte Konstruktoren bereit: in diesem Fall z.B. telnummern('nr1', 'nr2'). Im nächsten Beispiel wird der Objekttyp auftragsposition angelegt, der dann im Folgenden für die geschachtelte Tabelle auftragspositionen benutzt wird. CREATE OR REPLACE TYPE auftragsposition AS OBJECT (posnr INTEGER, anzahl INTEGER, prodid VARCHAR2(20)); CREATE OR REPLACE TYPE auftragspositionen AS TABLE OF auftragsposition / Listing 3.14: Objekttyp mit geschachtelter Tabelle
Der tabellarische Objekttyp auftragspositionen kann nun in einen weiteren Objekttyp auftraege_pos integriert werden: CREATE OR REPLACE TYPE auftraege_pos AS OBJECT (auftragkopf auftrag, pos_tab auftragspositionen);
Schließlich wird dieser Objekttyp dazu benutzt, die endgültige Objekttabelle auftraege_positionen mit der geschachtelten Tabelle pos_tab_table anzulegen: CREATE TABLE auftraege_positionen OF auftraege_pos NESTED TABLE pos_tab STORE AS pos_tab_table ( (PRIMARY KEY(NESTED_TABLE_ID,posnr)) ORGANIZATION INDEX COMPRESS) RETURN AS LOCATOR; Listing 3.15: Anlegen einer geschachtelten Tabelle
Sandini Bib
148
Datenbankdesign
Die Koppelung der Haupttabelle mit der geschachtelten Tabelle wird über die interne Spalte nested_table_id gewährleistet. Für den Fall, dass die geschachtelte Tabelle – wie in diesem Fall – einen Primärschlüssel enthält, kann sie als IOTTabelle angelegt und der Index-Baum zusätzlich komprimiert werden. Die Speicherung als Index hat die Sortierung der Daten (clustering) mit der nested_table_id als Präfix zur Folge. Durch die Komprimierung wird die Wiederholung gleicher Werte von nested_table_id unterdrückt und die Tabelle dadurch kompakter. Statt der gesamten Daten wird ferner nur ein Locator für den Zugriff zurückgegeben, was besonders bei geschachtelten Tabellen mit vielen Elementen empfehlenswert ist. Das Füllen der Objekttabelle auftraege_positionen geschieht in zwei Phasen: Zunächst wird ein Auftragskopfsatz über Konstruktoren mit einer leeren Referenz in die geschachtelte Tabelle eingefügt: INSERT INTO auftraege_positionen VALUES(auftrag(123,SYSDATE,NULL,NULL),auftragspositionen());
In der zweiten Phase wird mit Hilfe des TABLE-Ausdrucks die geschachtelte Tabelle für den Auftrag 123 mit einem Element gefüllt: INSERT INTO TABLE(SELECT a.pos_tab FROM auftraege_positionen a WHERE a.auftragkopf.aufnr = 123) VALUES(1,3,222) / Listing 3.16: Einfügen von Sätzen in eine geschachtelte Tabelle
3.3
Indexstrukturen
Indizes sind für relationale Datenbanksysteme aus verschiedenen Gründen unerlässlich: Auf der einen Seite helfen sie – richtig aufgebaut – bei der Optimierung von Zugriffen, auf der anderen Seite können sie – als eindeutige Indizes – eindeutige Wertemengen garantieren. Für den Datenbankverwalter wie auch den Applikationsentwickler gruppieren sich unterschiedliche Aufgabenbereiche um die Welt der Indizes: 1. Im Zuge der Datenmodellierung gilt es, geeignete Attribute für die Indizierung auszusuchen. 2. Wird das physikalische Modell aufgesetzt, müssen den Indexkandidaten konkrete Indizes bzw. Indextypen zugewiesen werden. 3. Die Indizes des physikalischen Modells werden dann mit geeigneten StorageKlauseln angelegt. 4. Im laufenden Betrieb schließlich müssen die Indizes überwacht und bei Bedarf reorganisiert werden. Gleichfalls kann es notwendig sein, konkrete Zugriffspläne einzelner SQL-Befehle zu generieren, hinsichtlich ihrer Indexnutzung zu analysieren und – falls notwendig – die Indexstrukturen zu optimieren.
Sandini Bib
Indexstrukturen
149
Das vorliegende Kapitel beschäftigt sich vornehmlich mit Punkt 2 der oben angeführten Aufgabenliste, nämlich der Umsetzung einer Indexanforderung in einen konkreten Index eines bestimmten Indextyps. In Oracle9i stehen uns eine Reihe unterschiedlicher Indextypen zur Verfügung. Neben den „klassischen“ B*Bäumen können wir u.a. Bitmap-Indizes, Reverse Key-Indizes oder funktionale Indizes anlegen. Die genaue Kenntnis dieser einzelnen Indextypen und ihrer Charakteristika ist für eine optimale Indeximplementierung mindestens genauso wichtig, wie die Entscheidung darüber, welche Attribute welcher Tabellen in welcher Gruppierung indiziert werden sollen.
3.3.1
Allgemeine Regeln
Indizes lassen sich im Kontext von Tabellen und Clustern anlegen. Vorhandene Indizes werden durch Update-, Insert- oder Delete-Befehle automatisch verändert, was bei einer großen Zahl von Indizes und entsprechendem DML-Aufkommen messbare Folgen haben kann. Über die Nutzung von Indizes für konkrete SQLZugriffe entscheidet der Optimizer, beeinflusst durch die Syntax des betreffenden SQL-Befehls, vorhandene Statistiken oder konkrete Anweisungen (hints). Indizes lassen sich eindeutig (unique) oder nicht eindeutig (non-unique) anlegen. Es können sowohl einzelne Spalten als auch Spaltengruppen indiziert werden. Im letzteren Fall handelt es sich um zusammengesetzte Indizes (concatenated index, composite index). Die maximale Anzahl von Spalten, die in zusammengesetzten Indizes gruppiert werden können, liegt – abhängig vom Indextyp – zwischen 30 und 32. Wichtig ist beim Aufbau von zusammengesetzten Indizes vor allem die Reihenfolge der Spalten, entscheidet sie doch über die Nutzung seitens des Optimizers3. Indizes lassen sich technisch in beliebiger Anzahl für jede Tabelle erzeugen, solange sich die Kombination der Spalten für jeden Index unterscheidet. Demnach sind mehrere Indizes auf einer Spalte oder einer Spaltengruppe mit gleichen Spalten in gleicher Reihenfolge nicht möglich. Indizes sind logisch wie physisch von den Tabellen, auf die sie sich beziehen, in dem Sinne unabhängig, als sie angelegt, gelöscht oder reorganisiert werden können, ohne das Programme ihre Funktionsfähigkeit verlieren. Die einzige Auswirkung kann die Beeinflussung der Laufzeit von Zugriffen sein. Indizes verwalten ihre Daten in sortierten Listen. Die sortierten Listen der Schlüssel werden dabei auf einzelne Oracle-Blöcke, die so genannten Index-Blätter (leaf node) verteilt. Zeiger auf die Endpunkte dieser Index-Blätter werden in einem IndexBaum in so genannten Index-Zweigen (branch node) zusammengefasst, die den schnellen Zugriff auf konkrete Schlüsselwerte garantieren.
3.
Zusammengesetzte Indizes können nur genutzt werden, wenn alle oder die führenden Spalten spezifiziert werden.
Sandini Bib
150
Datenbankdesign
5RRW +
/
,
%UDQFKHV
/HDYHV Abbildung 3.1: Struktur eines Index-Baumes
Die oben abgebildete Grundstruktur wird im Rahmen eines Segments für jeden Index, unabhängig von seinem Typ, aufgebaut. Die Art, in welchem Format und in welcher Sortierung die Daten in den Index-Blättern gespeichert werden, ist dagegen unterschiedlich und hängt von dem verwendeten Indextyp ab. Suchvorgänge in Indizes beginnen bei dem so genannten Wurzelblock (root block) und gelangen über die „Zweige“ des Index-Baumes zu den „Blättern“, über die schließlich die Satzadresse (rowid) des gesuchten Schlüsselwertes ermittelt wird. Der Zugriff auf den gewünschten Datensatz erfolgt dann über die ermittelte Adresse. Da die Blätter von Index-Bäumen auch untereinander durch Pointer verbunden sind, lassen sich Bereichszugriffe (range scans) ohne erneuten Einstieg über die Wurzel realisieren. Prinzipiell können Indizes nur dann vom Optimizer genutzt werden, wenn die betreffende SQL-Anweisung Prädikate enthält, welche die indizierten Spalten referenzieren. Bei zusammengesetzten Indizes müssen dies alle oder zumindest die führenden Spalten sein. Die Indexnutzung ist darüber hinaus abhängig vom verwendeten Operator: Mit Ausnahme von Ungleich-Operatoren und Like-Operatoren, die führende Platzhalter haben, sind alle Operatoren für Indexzugriffe geeignet. Enthält die SQL-Anweisung mehrere indizierte Prädikate, kann der Optimizer die betreffenden Indizes für den Zugriff mischen (merge). Indizes werden als Segmente in Oracle-Datenbanken verwaltet und gespeichert. Als solche lassen sie sich – unabhängig von der ihnen zugeordneten Tabelle – mit eigenen Storage-Klauseln und in separaten Tablespaces organisieren.
Sandini Bib
Indexstrukturen
151
In den folgenden Abschnitten werden die Besonderheiten der einzelnen Indextypen vorgestellt.
3.3.2
B*Indizes
B*Indizes sind die „klassischen“ Indizes in Oracle-Datenbanken. Im folgenden Beispiel wird ein nicht eindeutiger B*Index mit Namen i$ang_name für die Spalte name der Tabelle angestellte aufgebaut. CREATE INDEX i$ang_name ON angestellte (name);
Für den Aufbau dieses Indexes werden die Spaltenwerte von name sortiert. Jeder Name wird zusammen mit der ihm zugehörigen Satzadresse (rowid) in den IndexBlättern gespeichert. Über den Blättern wird dann der restliche Index-Baum erzeugt. Da die Syntax keine Storage-Klausel enthält, wird das Indexsegment in diesem Fall in der Default-Tablespace des betreffenden Schema-Benutzers und dort mit den standardmäßigen Extent-Größen angelegt. B*Indizes enthalten keine NULL-Werte, d.h., Abfragen mit IS NULL-Klauseln können diesen Index prinzipiell nicht benutzen. Im zweiten Beispiel wird ein zusammengesetzter Index mit expliziter STORAGEKlausel erzeugt, der an erster Stelle die Abteilungsnummer und an zweiter den Namen setzt. CREATE INDEX i$ang_abtname ON angestellte (abtnr, name) STORAGE (INITIAL 500K NEXT 500K);
B*Indizes lassen sich wie folgt charakterisieren:
:
: :
Sie zeigen – im Gegensatz zu den weiter unten beschriebenen Bitmap-Indizes – ein gutes, weil die Gleichzeitigkeit von Transaktionen förderndes Sperrverhalten. Sperren werden hier auf der Basis einzelner Einträge durchgeführt und verursachen dadurch keine unnötigen Wartezustände bei gleichzeitig operierenden Transaktionen. Ihr Speicherbedarf ist auf der anderen Seite größer als der von Bitmap-Indizes. Dies führt zu höheren „Kosten“ beim Zugriff, da mehr Indexblöcke gelesen werden müssen. Durch den höheren Speicherbedarf sind Mischoperationen (merge) mit B*Indizes aufwändiger als bei Bitmap-Indizes. Zur Vermeidung unnötiger Mischoperationen kann statt einzelner Indizes ein zusammengesetzter Index angelegt werden.
Auf Grund der oben beschriebenen Charakteristika sind B*Indizes überall dort einsetzbar, wo die folgenden Kriterien zutreffend sind:
: :
Die betreffenden Spalten werden in Prädikaten referenziert und vom Optimizer als Zugriffspfad akzeptiert. Die Spalten werden prinzipiell über DML-Befehle verändert (Sperrverhalten).
Sandini Bib
152
:
Datenbankdesign
Die Referenzierung der Spalten in den Prädikaten erfolgt in direkter Form, d.h., die Spalten werden dort nicht über Funktionen und Ausdrücke verändert.
Zu Recht sind aus diesen Gründen B*Indizes die Oracle-Indizes, die in den meisten Fällen zum Einsatz kommen können.
3.3.3
Bitmap-Indizes
Im Gegensatz zu B*Indizes speichern Bitmap-Indizes ihre Schlüssel nicht mit den zugehörigen Satzadressen, sondern in Form von Bitmaps. Jeder distinktive Spaltenwert eines Bitmap-Indexes erhält eine logische Bitmap. Jede Bitmap enthält in ihrem Kopf eine Start- und Schlussadresse, gefolgt von der eigentlichen Bitmap, bei der jede Bitposition einem Satz der zugeordneten Tabelle entspricht. Enthält der betreffende Datensatz den der Bitmap zugeordneten Spaltenwert, steht das Bit auf 1, ansonsten auf 0. Die Umrechnung einer Bitposition in eine Satzadresse erfolgt mit Hilfe der Kopfdaten und eines – gedachten – Rasters. Das Raster jeder Bitmap einer Tabelle ergibt sich aus der maximalen Anzahl von Datensätzen pro Block. Diese Anzahl wiederum wird beim Aufbau des Bitmap-Indexes aus der minimalen Satzlänge errechnet. Logische Bitmaps werden bei der Speicherung in physische Bitmaps aufgeteilt, wobei maximal zwei physische Bitmaps in einem Oracle-Block Platz finden. Um den Speicherbedarf weiter zu optimieren, werden aufeinander folgende Nullen in den Bitmaps komprimiert. Die folgenden Abbildung zeigt den Aufbau einer Bitmap.
&ROXPQ9DOXHJHOE 6WDUW5RZLG
(QG5RZLG
Abbildung 3.2: Struktur einer Bitmap
Auf die physischen Bitmaps eines Bitmap-Indexes wird über eine Baumstruktur – vergleichbar einem B*Index – zugegriffen. Im folgenden Beispiel wird der nicht eindeutige Bitmap-Index bi$ang_dat für die Spalte einstelldatum der Tabelle angestellte aufgebaut: CREATE BITMAP INDEX bi$ang_dat ON angestellte(einstelldatum);
Sandini Bib
Indexstrukturen
153
Auch dieser Index wird – wegen der fehlenden Storage-Klausel – in der DefaultTablespace des betreffenden Schemas angelegt. Der Speicherplatz, der für die Sortierung der Daten und den Aufbau der Bitmaps notwendig ist, kann über den Initialisierungsparameter create_bitmap_area_size eingestellt werden, dessen Standardwert 8 Mbyte beträgt. Alternativ kann dieser Speicherbereich auch im Rahmen der dynamischen PGA-Verwaltung optimiert werden.4 Eine weitere Optimierung der Bitmap-Indizes lässt sich über die Festlegung der maximalen Anzahl von Datensätzen pro Oracle-Block erreichen: ALTER TABLE angestellte MINIMIZE RECORDS_PER_BLOCK;
Dieser Befehl sorgt dafür, dass die maximale Anzahl von Datensätzen pro Block für die betreffende Tabelle festgeschrieben wird5 und zukünftige INSERT-Operationen diese vorgegebene Marke nicht überschreiten. Auf diese Weise müssen die Bitmaps nicht auf der Basis der theoretisch maximal möglichen Blockfüllung, sondern können auf Basis der konkret vorgefundenen Anzahl von Datensätzen pro Block kalkuliert werden. Der Befehl kann nur dann abgesetzt werden, wenn die Tabelle bereits Datensätze, aber noch keinen Bitmap-Index enthält. Im Gegensatz zu B*Indizes werden in Bitmap-Indizes auch Null-Werte erfasst, d.h., ein Prädikat mit einer IS NULL-Klausel kann über den Index aufgelöst werden. Bitmap-Indizes können – wie B*Indizes – auch als zusammengesetzte Indizes angelegt werden. Eindeutige Bitmap-Indizes dagegen sind nicht erlaubt. Bitmap-Indizes werden grundsätzlich nur über den statistischen Optimizer genutzt; sie existieren nicht für den regelbasierten Optimizer. Der folgende Zugriffsplan6 verdeutlicht die Nutzung eines Bitmap-Indexes für den Zugriff auf Null-Werte: SELECT * FROM angestellte WHERE einstelldatum IS NULL; Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=82) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'ANGESTELLTE' (Cost=2 Card=2 Byes=82) 2 1 BITMAP CONVERSION (TO ROWIDS) 3 2 BITMAP-INDEX (SINGLE VALUE) OF 'BI$ANG_DAT' Listing 3.17: Ausführungsplan mit Bitmap-Index
Die Operation Bitmap-Index (Single Value) sucht gezielt die Bitmap für den Wert null. Mit Hilfe von Bitmap Conversion wird die Umrechnung in eine Satzadresse vorgenommen, die dann den Zugriff steuert. Bitmap-Indizes lassen sich zusammenfassend wie folgt charakterisieren:
: 4. 5. 6.
Bitmap-Indizes werden extrem kompakt gespeichert. Auf Grund dessen sind die Kosten für Zugriffe auf diese Indizes sehr gering. Siehe den Systemparameter pga_aggregate_target . Die Spalte spare1 der Dictionary-Tabelle tab$ wird entsprechend angepasst. Der Plan wurde in SQL*Plus über den Befehl Set Autotrace On generiert.
Sandini Bib
154
:
:
:
Datenbankdesign
Die Bitmaps einer Tabelle lassen sich – unabhängig davon ob, sie unterschiedliche Werte einer Spalte oder unterschiedliche Spalten repräsentieren – sehr effizient mischen. Auf diese Weise können Prädikate, die über AND oder OR miteinander verknüpft sind oder die über IN- oder BETWEEN-Operatoren verfügen, effizient abgearbeitet werden. Der „Ausweg“ über verknüpfte Bitmap-Indizes, obwohl möglich, ist nur selten notwendig. Da sich maximal nur zwei physische Bitmaps einen Block teilen, können – abhängig von der Blockgröße und der Komprimierung – Hunderte bis Tausende von Datensätzen in einer Bitmap referenziert werden. Bei relativ kleinen Tabellen mit hoher Kardinalität, die pro distinktivem Spaltenwert nur wenige Datensätze aufweisen, werden daher die physischen Bitmaps sehr schlecht genutzt. Der Speichervorteil gegenüber B*Indizes ist in diesem Fall nicht sehr signifikant. Bei Änderungen von Spalten, die über Bitmap-Indizes indiziert wurden, wird die gesamte physische Bitmap gesperrt. Davon können wiederum Tausende von Datensätzen betroffen sein.
Die oben beschriebenen Merkmale verdeutlichen, dass die Nutzung von BitmapIndizes sehr große Vorteile, aber auch erhebliche Probleme nach sich ziehen kann! Der Einsatz von Bitmap-Indizes sollte aus diesem Grunde wohl überlegt werden. Optimale Bedingungen für Bitmap-Indizes sind gegeben, wenn
: : : :
die betreffenden Spalten nicht oder nur äußerst selten und dann von streng seriell ablaufenden Transaktionen geändert werden, die Kardinalität der Spalten eher gering ist, die Tabellen „viele“ Datensätze enthalten und Zugriffe existieren, deren Prädikate diese Spalten verwenden.
Bitmap-Indizes dürfen in keinem Fall – wegen des oben beschriebenen Sperrverhaltens – für Spalten angelegt werden, die gleichzeitig von mehreren Transaktionen verändert werden! Vor massenhaften INSERT- oder UPDATE-Operationen kann es in einigen Fällen vorkommen, dass Bitmap-Indizes überproportional schnell wachsen. In solchen Fällen ist entweder eine regelmäßige Neuorganisation7 oder das Löschen vor und Neuanlegen nach den betreffenden Operationen sinnvoll.
3.3.4
Bitmap Join-Indizes
Bitmap Join-Indizes sind Bitmap-Indizes, die eine Tabelle in Bezug auf Spaltenwerte anderer Tabellen indizieren. Diese anderen Tabellen sind Tabellen, die über Fremdschlüssel mit der indizierten Tabelle verbunden sind. Auf diese Weise lassen sich Join-Operationen im Index vorbereiten. Für die Join-Operationen sind dementsprechend keine Zugriffe auf die Fremdschlüsseltabellen mehr notwendig; alle WHERE-Klauseln können vielmehr über den betreffenden Bitmap Join-Index aufgelöst werden.
7.
ALTER INDEX ... REBUILD;
Sandini Bib
Indexstrukturen
155
'
)
'
%LWPDS-RLQ,QGH[
Abbildung 3.3: Speicherstrukturen von Bitmap Join-Indizes
Ein Beispiel soll dies verdeutlichen: Eine zentrale, partitionierte Faktentabelle namens sales8 enthält Verkaufszahlen zu Produkten. Die Tabelle sales ist neben den Produkten (products) mit weiteren Dimensionen wie z.B. Datumsangaben (times) verbunden. Eine Abfrage soll die Umsatzzahlen des Produktes „Linen Big Shirt“ für das Kalenderjahr 1998 wie folgt ermitteln: SELECT FROM WHERE AND AND AND
SUM(amount_sold) sales s , times t, t.time_id p.prod_id t.calendar_year p.prod_name
products p = s.time_id = s.prod_id = 1998 = 'Linen Big Shirt';
Listing 3.18: Abfrage
Ohne Aufbau eines Bitmap Join-Indexes könnte diese Abfrage wie folgt optimiert werden9, für den Fall, dass außer den Primärschlüsseln der Dimensionen keine weiteren Indizes angelegt wurden:
8. 9.
Die Beispieltabellen dieses Abschnitts sind dem Oracle Demo-Schema Sales History entlehnt, das jeder Installation beigefügt ist. Die Ausgabe wurde überden Befehl SET AUTOTRACE ON in SQL*Plus erzeugt.
Sandini Bib
156
Datenbankdesign
Execution Plan -------------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1160 Card=1 Bytes=84 ) 1 0 SORT (AGGREGATE) 2 1 HASH JOIN (Cost=1160 Card=102 Bytes=8568) 3 2 TABLE ACCESS (FULL) OF 'PRODUCTS' (Cost=65 Card=100 Bytes=3100) 4 2 HASH JOIN (Cost=1095 Card=10163 Bytes=538639) 5 4 TABLE ACCESS (FULL) OF 'TIMES' (Cost=6 Card=15 Bytes=300) 6 4 PARTITION RANGE (ITERATOR) 7 6 TABLE ACCESS (FULL) OF 'SALES' (Cost=1089 Card=1016271 Bytes=33536943) Listing 3.19: Ausführungsplan ohne Bitmap Join-Index
Der Zugriffsplan zeigt klar, dass neben sales auch die Tabellen times und products zur Auflösung der Join-Operation gelesen werden müssen. Zur Optimierung dieser Abfrage wird nun ein Bitmap Join-Index für die Tabelle sales angelegt, der die Spalten prod_name der Tabelle products und calendar_year von times enthält: CREATE BITMAP INDEX bj_index ON sales (products.prod_name, times.calendar_year) FROM sales,times,products WHERE products.prod_id = sales.prod_id AND times.time_id = sales.time_id LOCAL COMPUTE STATISTICS; Listing 3.20: Erstellen eines Bitmap Join-Indexes
Da die Tabelle sales partitioniert wurde, muss auch der Bitmap Join-Index lokal partitioniert angelegt werden. Das Syntaxbeispiel zeigt die minimale Syntax ohne explizite Benennung der einzelnen Partitionsnamen. Im Anschluss an den Aufbau des Indexes werden sofort Statistiken generiert. Durch diesen Index wird der Zugriffsplan der oben angegebenen Abfrage wie folgt geändert: Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=37 Card=1 Bytes=33) 1 0 SORT (AGGREGATE) 2 1 PARTITION RANGE (ALL) 3 2 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'SALES' (Cost=37 Card=1016271 Bytes=33536943) 4 3 BITMAP CONVERSION (TO ROWIDS) 5 4 BITMAP-INDEX (SINGLE VALUE) OF 'BJ_INDEX' Listing 3.21: Ausführungsplan mit Bitmap Join-Index
Sandini Bib
Indexstrukturen
157
Der Plan zeigt, dass die Umsatzzahlen für das genannte Produkt nun nur durch Zugriff auf die Tabelle sales über den neuen Index generiert werden können. Die Zugriffe auf products und sales sind nicht mehr notwendig, da der Bitmap JoinIndex alle referenzierten Spaltenwerte enthält. Derzeit10 ist es noch nicht möglich, funktionale Bitmap Join-Indizes oder Bitmap Join-Indizes für Index-organisierte Tabellen zu erstellen. Informationen zu Bitmap Join-Indizes enthalten die Views user_indexes – Index_type = 'BITMAP' AND Join_Index = 'YES' – sowie user_ind_columns. Das vorangehende Beispiel hat gezeigt, dass Bitmap Join-Indizes ideal geeignet sind, um Star-Abfragen – wie sie z.B. im Umfeld von Data Warehouses auftreten – zu optimieren. Für sie gelten darüber hinaus die gleichen Merkmale, die bereits in Abschnitt 3.3.3 für Bitmap-Indizes erwähnt wurden. Hier ist vor allem die Tatsache zu erwähnen, dass bei Änderungen auf Dimensionsschlüsseln – in unserem Beispiel time_id und product_id – Sperren im Kontext von Bitmap-Bereichen aufgebaut werden.11
3.3.5
Reverse Key-Indizes
B*Indizes lassen sich auch als Reverse Key-Indizes aufbauen. In diesem Fall werden die Schlüsselwerte in den Index-Blättern in umgekehrter Zeichenfolge abgespeichert; aus der Zeichenkette „Adam“ wird demnach „madA“. Im folgenden Beispiel wird der Index ir$ang_abt als Reverse Key-Index für die Spalte abt_nr der Tabelle angestellte angelegt: CREATE INDEX Ir$Ang_Abt ON angestellte (abt_nr) REVERSE;
Durch die umgekehrte Speicherung der Zeichenketten werden Schlüssel, die normalerweise in einem Index-Blatt zusammengefasst würden, auf unterschiedliche Blätter verteilt. Das Gleiche gilt auch für DML-Operationen, die diese Schlüsselwerte verändern. Reverse Key-Indizes können also helfen, I/O-Operationen besser auf die Index-Blätter zu verteilen. Auf der anderen Seite werden auf Grund der umgekehrten Speicherung Wertebereiche, die normalerweise über Range-Zugriffe im Index gelesen werden können, einzeln abgearbeitet. Informationen zu Reverse Key-Indizes enthält die View user_indexes unter dem Indextyp NORMAL/REV. Die indizierten Spalten werden über user_ind_columns ausgewiesen.
3.3.6
Funktionale Indizes
Funktionale Indizes (function-based Index) werden im Kontext von Funktionen oder Ausdrücken angelegt, die sich auf Spalten der betreffenden Tabelle beziehen. Hierbei werden die von der betreffenden Funktion oder dem Ausdruck zurückgegebe10. Oracle 9i Version 9.0.1.3 11. Bei Bitmap Join-Indizes werden – im Gegensatz zu Bitmap-Indizes – mehr als zwei physische Bitmaps in einem Oracle-Block gespeichert.
Sandini Bib
158
Datenbankdesign
nen Werte indiziert. Die indizierten Funktionen können sowohl vordefinierte SQLFunktionen als auch vom Benutzer selbst definierte Funktionen sein. Das folgende Beispiel erzeugt den funktionalen Index fi$ang_name der Tabelle angestellte für die SQL-Funktion UPPER der Spalte name: CREATE INDEX fi$ang_name ON angestellte (UPPER(name));
Für den Aufbau eines funktionalen Indexes ist das Systemprivileg QUERY REWRITE erforderlich! Damit der neu angelegte Index genutzt werden kann, sind zum einen der statistische Optimizer einzuschalten und entsprechende Statistiken zu generieren, zum anderen muss in die betreffende Sitzung explizit auf QUERY REWRITE umgeschaltet werden, wie das folgende Beispiel zeigt: ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE;
Der Parameter kann auch als Systemparameter pauschal gesetzt werden. Abfragen, welche die SQL-Funktion UPPER nutzen, werden danach über den funktionalen Index ausgeführt: SELECT * FROM angestellte WHERE UPPER(name) = 'ADAM'; Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=82) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'ANGESTELLTE' (Cost=2 Card=2 Bytes=82) 2 1 INDEX (RANGE SCAN) OF 'FI$ANG_NAME' (NON-UNIQUE) (Cost=1 Card=2) Listing 3.22: Function-based Index
Funktionale Indizes können als B*Index oder Bitmap-Index angelegt werden, als B*Index sind sie auch reverse definierbar. Informationen können über die View user_indexes abgerufen werden. Die Spalte index_type enthält entsprechende Angaben: FUNCTION-BASED NORMAL oder FUNCTION-BASED NORMAL/REV sowie FUNCTION-BASED BITMAP. Die dem Index zugeordneten Funktionen enthält die View user_ind_expressions. Die View user_ind_columns weisst für funktionale Indizes nur eine Pseudospalte – z.B. SYS_NC000010$ – auf. Funktionale Indizes bieten überall dort Vorteile, wo Funktionen oder Ausdrücke in Where-Klauseln Verwendung finden und diese Prädikate genügend Selektivität für Indexzugriffe bieten. Normale Indizes sind für diese Prädikate nicht einsetzbar.
3.3.7
Komprimierung
Bei der komprimierten Speicherung von Indizes wird jeder Schlüsselwert in ein Präfix und ein Suffix aufgeteilt. Präfixe, die in der Regel redundant vorkommen, werden pro Index-Blatt nur einmal gespeichert; Suffixe verweisen auf die Präfixe ihres
Sandini Bib
Indexstrukturen
159
Blattes und sind pro Blatt mehrfach vorhanden. Auf diese Weise lässt sich die Speichergröße von Indizes reduzieren und damit lassen sich die Zugriffe optimieren. Standardmäßig wird das Präfix bei einem n-fach zusammengesetzten nicht eindeutigen Index aus n Spalten gebildet, für eindeutige Indizes aus n-1 Spalten. Das folgende Beispiel zeigt den Aufbau eines zusammengesetzten nicht eindeutigen Indexes für die Spalten gehalt und kommission der Tabelle angestellte: CREATE INDEX i$ang_com ON angestellte (gehalt, kommission) COMPRESS;
Die folgende Abfrage gibt die Eigenschaften des neuen Indexes aus: SELECT index_name, index_type, compression, prefix_length FROM user_indexes WHERE index_name = 'I$ANG_COM'; INDEX_NAME INDEX_TYPE COMPRESS PREFIX_LENGTH --------------- ----------------------- -------- ------------I$ANG_COM NORMAL ENABLED 2 Listing 3.23: user_indexes
Das Präfix wird hier von beiden Spalten – gehalt und kommission – gebildet, im Suffix werden in diesem Fall die Satzadressen (rowid) gespeichert. Der Speicherbedarf dieses Indexes gegenüber einem identischen ohne Komprimierung betrug etwa 30%.12 Die Länge von Präfixen kann aber auch explizit definiert werden. Im folgenden Beispiel wird die Anzahl der Spalten des Präfixes – hier nur die führende Spalte gehalt – in der Compress-Klausel angegeben: CREATE INDEX i$ang_com ON angestellte (gehalt, kommission) COMPRESS 1;
Es versteht sich, dass der Speicherbedarf bei sinkender Komprimierungsrate steigt. Komprimierte Indizes empfehlen sich überall dort, wo großer Wert auf kompakte Speicherung gelegt wird, Bitmap-Indizes jedoch auf Grund konkurrierender DMLAktivitäten nicht angebracht sind. Für die Rekonstruktion der Schlüsselwerte aus Präfixen und Suffixen ist ein geringfügiger Anstieg der CPU-Zeiten in Kauf zu nehmen.
3.3.8
Aspekte der Indexverwaltung
Parallelisierung Der Aufbau von Indizes kann parallelisiert und dadurch beschleunigt werden. In diesem Fall arbeiten mehrere Prozesse daran, die Basistabelle zu lesen und die 12. Die Tabelle angestellte bestand aus 29.000 Einträgen; die Indexgrößen betrugen 550 Kbyte (nicht komprimiert) und 300 Kbyte (komprimiert).
Sandini Bib
160
Datenbankdesign
Schlüsselwerte zu sortieren. Im folgenden Beispiel wird der Index i$sales_amount mit zweifacher Parallelisierung angelegt: CREATE INDEX i$sales_amount ON sales (quantity_sold) PARALLEL 2;
Entsprechende Hintergrundprozesse müssen in diesem Fall vorher vom Datenund bankverwalter über die Systemparameter parallel_min_servers parallel_max_servers konfiguriert worden sein. Die Parallelisierung kann hier sowohl intra- als auch interoperational erfolgen. Dies bedeutet, dass sowohl das Lesen der Tabelle als auch das Sortieren gleichzeitig parallelisiert wird. In unserem Beispiel führt das zur Aktivierung von insgesamt vier Serverprozessen. Die Parallelisierung hat auch Auswirkungen auf die Größe der Segmente, da jeder Serverprozess ein eigenes Extent aufbaut. Online-Aufbau Um die Konsistenz der Index- und Tabellendaten im Mehrbenutzerbetrieb sicherzustellen, wird der Aufbau von Indizes stets von entsprechenden Tabellensperren begleitet. Die Beispiele der vorangehenden Abschnitte fordern aus diesem Grunde stets eine Tabellensperre vom Typ Share Mode für die zu indizierende Tabelle an. Dies kann zu unterschiedlichen Reaktionen führen, abhängig davon, welche Transaktionen gleichzeitig auf der betreffenden Tabelle aktiv sind. Bei offenen UPDATE-, DELETE- oder INSERT-Operationen, die bereits aktive Row Exclusive-Sperren auf Tabellenebene aufgebaut haben, führt dies zu einem Fehler13, da beide Sperrmodi nicht miteinander kompatibel sind. Der gleiche Fehler wird generiert, wenn in umgekehrter Reihenfolge zuerst der Indexaufbau durchgeführt wird und in dieser Zeit UPDATE-, DELETE- oder INSERT-Befehle auf die Tabelle treffen. Um im Mehrbenutzerbetrieb parallel ablaufende Transaktionen weniger zu stören ist für den Indexaufbau eine Online-Klausel verfügbar: CREATE INDEX i$ang_abt ON angestellte (abtnr) ONLINE;
Hierbei wird die Basistabelle – in unserem Beispiel angestellte – nur im Row ShareModus gesperrt. Dieser Modus ist mit den meisten anderen Sperrmodi – Row Exclusive, Row Share und Share Row Exclusive – kompatibel. Dies bedeutet das der Indexaufbau keine INSERT-, UPDATE und DELETE-Operationen, die Row Exclusive-Sperren aufbauen, behindert. Auch SELECT FOR UPDATE-Befehle sind möglich, da sie Row Share-Sperren erzeugen. Der einzig inkompatible Sperrmodus ist Exclusive. Um die Änderungen, die während des Indexaufbaus anfallen, zu protokollieren, erzeugt der Befehl automatisch eine Journaltabelle im Schema des Tabelleneigentümers mit Namen sys_journal_nnnnn, wobei nnnnn ein 5-stelliger, intern generierter, eindeutiger numerischer Bezeichner ist. Die Journaltabelle enthält im Wesentlichen einen numerischen Operationscode und die Adresse des veränderten Datensatzes. Bei partitionierten Tabellen kommt noch eine Partitionsnummer hinzu. Diese Tabelle wird im Share Modus gesperrt, mit den DML-Daten zwischenzeitlicher Transaktionen gefüllt und nach dem fertigen Aufbau des Indexes
13. ORA-00054: resource busy and acquire with NOWAIT specified
Sandini Bib
Indexstrukturen
161
genutzt, um die angefallenen Änderungen diesem anzufügen. Die ONLINE-Klausel ist für Bitmap- und Cluster-Indizes nicht nutzbar. Indexreorganisation Durch häufiges Einfügen und Löschen14 von Indexschlüsseln kann es notwendig werden, Index-Bäume zu reorganisieren, um ihre Effizienz wiederherzustellen. Nach der reinen Lehre sind B*Bäume zwar ausgewogen und haben überall die gleiche Höhe, da Oracle Schlüsselwerte in Indizes jedoch nur logisch und nicht physisch löscht, kann der äußerlich ausgewogene Index eine „innere“ Schieflage erhalten. Um dies zu erkennen ist eine Indexanalyse durchzuführen. Die Analyse eines Index-Baumes lässt sich am besten über den ANALYZE-Befehl bewerkstelligen: ANALYZE INDEX i$brev VALIDATE STRUCTURE;
Die Klausel VALIDATE STRUCTURE prüft die Baumstruktur und füllt die Hilfstabelle index_stats mit statistischen Werten. Das folgende Beispiel zeigt den Platzverbrauch sowie die Anzahl und den Umfang von gelöschten Einträgen. Beim Platzverbrauch wird differenziert zwischen der Größe des Segmentes – blocks –, dem in diesem Segment für den Aufbau des B*Baumes benötigten Platz – btree_space – sowie dem innerhalb des Baumes für Einträge verbrauchten Bereich – used_space. NAME HEIGHT BLOCKS BR_BLKS LF_BLKS DEL_LF_ROWS BTREE_SPACE USED_SPACE ----------- ------- ------- ------- ------- ----------- ----------- ---------I$BREV 2 64 1 56 307 455804 377892 DEL_LF_ROWS DEL_LF_ROWS_LEN ----------- --------------307 4298
Indizes mit einem hohen Anteil an gelöschten Schlüsselwerten können durch eine Reorganisation wesentlich kompakter gespeichert werden. Für die Reorganisation von Indizes stehen unterschiedliche Methoden bereit. Im folgenden Beispiel wird der Index i$brev über die REBUILD-Klausel reorganisiert: ALTER INDEX i$brev REBUILD; REBUILD baut den Index vollständig neu auf, indem der alte Index als Datenquelle
benutzt wird, auf dieser Basis der neue Index erstellt wird und dieser schließlich an die Stelle des alten rückt. Über die REBUILD-Klausel ist es ebenfalls möglich, den Index in eine neue Tablespace zu stellen und seine STORAGE-Klausel anzupassen. Die Online-Option kann hier ebenfalls verwendet werden und verändert das Sperrverhalten wie im Abschnitt Online-Aufbau beschrieben. Für die Fälle, in denen der – kurzzeitig – erhöhte Speicherbedarf und die CPU-Belastung der Rebuild-Methode Probleme bereitet, steht die COALESCE-Klausel bereit:
14. Da Schlüsselwerte in Indizes sortiert gespeichert werden, werden UPDATE-Operationen als Löschen des alten und Einfügen des neuen Wertes ausgeführt. Es gibt in den Blättern eines Indexes also keine Updates. (Die Ausnahme sind Bitmaps.)
Sandini Bib
162
Datenbankdesign
ALTER INDEX i$brev COALESCE; COALESCE zieht benachbarte Blätter eines Index-Zweiges zusammen. Auf diese
Weise lassen sich gelöschte Schlüsselwerte kostengünstig ausmustern. Da der Index jedoch nicht vollständig neu aufgebaut wird, kann COALESCE keine STORAGE-Klauseln und Tablespaces ändern. Kommt es lediglich darauf an, den ungenutzten Speicherplatz eines Indexsegmentes zu reduzieren, kann die DEALLOCATE-Klausel helfen: ALTER INDEX i$brev DEALLOCATE UNUSED;
Die DEALLOCATE-Klausel bietet keine Reorganisation! Sie lässt lediglich das betreffende Segment bis auf die Hochwassermarke oder einen oberhalb von ihr befindlichen Wert15 schrumpfen. Monitoring Indizes sind nur sinnvoll, wenn sie vom Optimizer genutzt werden können. Um dies festzustellen lassen sich einerseits die Zugriffspläne einzelner SQL-Befehle generieren, andererseits können Indizes gezielt beobachtet werden. Im folgenden Beispiel wird der Index i$ang_geh für das Monitoring aktiviert: ALTER INDEX i$ang_geh MONITORING USAGE;
Einmal eingeschaltet kann die Nutzung der betreffenden Indizes über die View v$object_usage angezeigt werden. Man sollte sich hier beim Testen nicht verwirren lassen, es kann einige Stunden dauern, bis die ersten Protokolle in dieser View auftauchen. Das Monitoring wird über die NOMONITORING-Klausel wieder ausgeschaltet.
3.4
Partitionierung
3.4.1
Einführung
Unter Partitionierung versteht man die physische Aufteilung logischer Datenbankobjekte. Die physische Aufteilung der Objekte dient dem Ziel, eine „große“ Entität in kleinere, effizienter zugreifbare und einfacher zu verwaltende Einheiten aufzuspalten. Es können sowohl Tabellen als auch Indizes partitioniert werden. Eine Tabelle zu partitionieren bedeutet demnach, ihre Daten in unabhängigen Segmenten mit jeweils eigenen Speicherparametern, d.h., wenn gewünscht in separaten Tablespaces, nach definierten Partitionierungskriterien in der Datenbank zu speichern. Alle Partitionen einer Tabelle müssen jedoch die gleichen logischen Attribute besitzen, d.h. die gleichen Spalten- und Constraint-Definitionen aufweisen. Analog können die Partitionen eines partitionierten Indexes unterschiedliche physische Attribute haben, müssen aber identische logische Attribute, d.h. Indexspal15. Über den Zusatz Keep n, wobei n die Anzahl Bytes oberhalb der Hochwassermarke angibt.
Sandini Bib
Partitionierung
163
ten, besitzen. Die Kombinationsmöglichkeiten zwischen partitionierten Tabellen und Indizes sind beliebig: Eine partitionierte Tabelle kann sowohl über partitionierte wie auch nicht partitionierte Indizes verfügen. Ein partitionierter Index kann sich auf eine nicht partitionierte Tabelle beziehen. Auch Index-organisierte Tabellen und in ihrem Kontext definierte Sekundärindizes lassen sich prinzipiell partitionieren. Man spricht von einer „transparenten“ Partitionierung, wenn die zugreifenden Programmodule die partitionierten Objekte ebenso wie nicht partitionierte verarbeiten können, d.h. SELECT-, INSERT-, UPDATE- und DELETE-Operationen für das betreffende logische Objekt, nicht aber für die Partition, programmiert werden können. Gleichermaßen muss der Optimizer in der Lage sein, „intelligent“ mit der vorhandenen Partitionierung umzugehen, d.h. bei den Zugriffen – in Abhängigkeit von dem jeweiligen Prädikat (WHERE-Klausel) – bestimmte Partitionen auszuklammern. Die Partitionierung von Tabellen – und nur für diese – war bereits in der Version 7 mit einer Reihe von Einschränkungen über so genannte „partitionierte Views“ möglich. Eine syntaktisch und operational transparente Partitionierung wurde jedoch erst mit der Version 8 sowohl für Tabellen als auch für Indizes eingeführt und in den Versionen 8i und 9i funktional erweitert. Wie oben bereits angedeutet werden bei der Partitionierung im Wesentlichen zwei Ziele verfolgt: Zum einen geht es um die Optimierung der Zugriffe, zum anderen um vereinfachte und zeitlich verkürzte Verwaltungsroutinen. Die Optimierung von Zugriffen ist prinzipiell durch folgende Merkmale gegeben:
: : :
Partitionen stellen eine im Vergleich zum übergeordneten logischen Objekt kleinere Einheit dar. Table Scan-Operationen können – in Abhängigkeit von der betreffenden Where-Klausel – davon profitieren, indem sie bestimmte Partitionen operational ausklammern. Index-Bäume können – da sie partitionsspezifisch aufgebaut werden – flacher ausfallen, d.h. weniger Ebenen benötigen. Hierdurch können die I/O-Operationen bei den Zugriffen minimiert werden. Bestimmte Tabellenoperationen, wie z.B. Joins, lassen sich parallel zwischen einzelnen Partitionen ausführen.
Vereinfachte und verkürzte Verwaltungsroutinen sind prinzipiell möglich, weil:
: :
Partitionen einzeln hinzugefügt, gelöscht und aufgeteilt werden können. Der Austausch der Daten zwischen Tabellen und Partitionen über sehr effiziente switch-Operationen durchgeführt werden kann.
Diese Vorteile sind prinzipiell möglich, ob sie jedoch konkret genutzt werden können, ist im Einzelfall durch eine sorgfältige Analyse zu ermitteln, bevor mit der Implementierung dieses Merkmals begonnen wird! Diese Analyse sollte die folgenden Kriterien berücksichtigen:
Sandini Bib
164
Datenbankdesign
1. Die Priorisierung der Optimierungsziele. Wird mehr Wert auf eine effizientere Verwaltung oder auf die Optimierung der Zugriffe gelegt? 2. Die Größe der Objekte. Eine Tabelle mit wenigen Tausend Zeilen ist mit Sicherheit nicht für die Partitionierung geeignet, eine mit viele Millionen schon eher. 3. Die Art der Zugriffe. Indexzugriffe auf die betreffenden Objekte, die über die entsprechenden Satzadressen (rowids) nur wenige Zeilen selektieren, wie sie im so genannten OLTP-Betrieb16 typisch sind, profitieren in der Regel wenig oder gar nicht von einer Partitionierung. Batch-Zugriffe, die Scans auf große Bereiche der Tabellen durchführen, profitieren dagegen von den kompakteren Partitionsbereichen und eventuell auch von flacheren Indexstrukturen. 4. Die Art der Verwaltung bzw. die DML-Charakteristik: Rolling window-Anwendungen17, die Daten periodisch löschen und hinzufügen, sind vor allem dann geeignete Kandidaten, wenn die Partitionierungskriterien der Tabellen sich mit den Löschzyklen direkt oder indirekt18 synchronisieren lassen. Modifikationen der Partitionsstrukturen, wie z.B. das Löschen einer Parition, können dagegen die Reorganisation bestimmter Indizes notwendig machen und wirken aus diesem Grunde dem Ziel der Verwaltungsoptimierung entgegen. Eine Partitionierung kann erst dann empfohlen werden, wenn alle zu einer Priorisierung passenden Kriterien erfüllt werden.
3.4.2
Typen der Partitionierung
Für die transparente Partitionierung im Sinne der Versionen 8 und 9 stehen vier unterschiedliche Partitionierungsmethoden zur Verfügung:
:
Range-Partitionierung Die Kriterien für die Partitionierung werden bei diesem Modell durch fest definierte Wertebereiche einer oder mehrerer Spalten vergeben. Für jede Partition wird über eine entsprechende Values-Klausel der begrenzende Spaltenwert vorgegeben, z.B. VALUES LESS THAN (2000). Auf diese Weise lässt sich auch von außen unmittelbar nachvollziehen, welche Daten in welcher Partition gespeichert sind: Wurde beispielsweise eine Partitionierung nach Jahren und Monaten durchgeführt, d.h. für jeden Monat jeden Jahres eine Partition aufgebaut, lassen sich Löschungen eines bestimmten Monats in einem bestimmten Jahr sehr einfach über das Löschen der betreffenden Partition realisieren. Gleichermaßen kann der Optimizer bei lesenden Bereichszugriffen bestimmte Partitionen „ausklammern“ und die Zugriffen auf einzelne Partitionen beschränken. Die Range-Partitionierung ist aus diesem Grunde überall dort angebracht, wo auf Grund der Tabellenstruktur und der Spaltenwerte „natürliche“ Partitionie-
16. OLTP steht für OnLine Transaction Processing und wird – im Gegensatz zum Batch-Betrieb – durch kleine Online-Transaktionen charakterisiert. 17. Rolling window = ein „Fenster“ aktiv vorgehaltener Daten, z.B. Aufträge, die vom Tagesdatum aus 2 zurückliegende Jahre vorgehalten werden. 18. Direkte Synchronisierung: Das Partitionierungskriterium fällt mit der Einheit Zyklus zusammen, z.B. Monat, Vierteljahr. Indirekte Synchronisierung: Die Einheiten fallen nicht zusammen, können aber zur Übereinstimmung gebracht werden, z.B. Tage gegenüber Monaten.
Sandini Bib
Partitionierung
:
165
rungskriterien vorliegen, die darüber hinaus auch annäherungsweise eine Gleichverteilung der Daten garantieren können. Hash-Partitionierung Bei der Hash-Partitionierung dagegen übernimmt eine interne Hash-Funktion die Zuordnung einer Tabellenzeile zu einer Partition. Dies geschieht – wie auch bei der Range-Partitionierung – in Abhängigkeit von einer oder mehreren Partitionierungsspalten. Auf Grund der internen Hash-Funktion ist es jedoch für das Programm nicht absehbar, in welcher Partition ein vorgegebener Spaltenwert gespeichert wird. Daher wird hier während der Definition nur die Anzahl der gewünschten Partitionen vorgegeben. Das Löschen von Monatsdaten analog dem obigen Beispiel könnte in diesem Falle daher nicht über das Löschen der Partition realisiert werden, wie auch Bereichszugriffe nicht profitieren, weil sie Partitionsgrenzen überschreiten. Auf der anderen Seite bietet die Hash-Partitionierung aber dort Vorteile, wo keine „natürlichen“ Partitionierungskriterien vorliegen oder diese nur eine sehr ungleiche Verteilung der Daten aufweisen könnten.
:
Um eine möglichst homogene Verteilung der Datensätze auf die einzelnen Partitionen zu gewährleisten, ist es darüber hinaus empfehlenswert, nur Spalten mit möglichst hoher Selektivität – eindeutige oder nahezu eindeutige Werte – als Kriterium auszuwählen. Composite-Partitionierung Die Composite-Partitionierung stellt eine Kombination der beiden oben genannten Methoden dar. Hierbei wird in erster Instanz eine Range-Partitionierung durchgeführt, innerhalb jeder Range-Partition werden dann in zweiter Instanz Subpartitionen nach der Hash-Methode angelegt. Jede Subpartition ist hierbei speichertechnisch unabhängig, d.h., sie kann Gegenstand einer eigenen Storage-Klausel sein.
:
Die Composite-Partitionierung ist vor allem für die Parallelisierung von DMLund Join-Operationen auf der Ebene der Subpartitionen interessant. Folgendes Beispiel soll dies kurz erläutern: Eine gedachte Tabelle auftrag sei auf Jahresund Monatsbasis Range-partitioniert; die zugeordnete Tabelle kunden – wegen des fehlenden „natürlichen“ Versionierungskriteriums – auf Basis der Kundennummer Hash-partitioniert. Beide Tabellen sind also – was die Kriterien ihrer Partitionierung betrifft – inkompatibel. Werden nun für die Tabelle auftrag Subpartitionen auf Basis der auch in ihr enthaltenen Kundennummer angelegt, entstehen „kompatible“ Partitionen, für die sich parallele Join-Operationen für die einzelnen Partitionen durchführen lassen. List-Partitionierung Im Gegensatz zur Range-Partitionierung werden bei der List-Partitionierung keine festen Wertebereiche, sondern explizite, möglicherweise diskontinuierliche Werte als Kriterium vorgegeben. Aus diesem Grunde ist diese Methode überall dort empfehlenswert, wo keine natürlichen Wertebereiche vorliegen, trotzdem aber die Kontrolle über die Zuordnung von Spaltenwert und Partition erhalten bleiben soll, um beispielsweise das Löschen von Daten zu erleichtern.
Sandini Bib
166
Datenbankdesign
Derzeit lässt sich bei der List-Partitionierung – im Gegensatz zu den vorangehenden Methoden – nur eine Spalte als Partitionierungskriterium definieren. Die Abgrenzung der einzelnen Partitionen wird – wie auch bei der Range-Partitionierung – über eine VALUES-Klausel erreicht.
3.4.3
Partitionierte Tabellen
Im folgenden Abschnitt wird die syntaktische Seite partitionierter Tabellen beschrieben. Range-Partitionierung Im folgenden Beispiel wird die Heap-Tabelle verkauf mit den Partitionierungsspalten verkjahr, verkmonat und verktag angelegt. Sie besteht aus vier Partitionen, für welche die Namen verkaufq1 bis verkaufq4 vergeben werden. Jede Partition liegt in einer separaten Tablespace. Für alle Partitionen wurde jedoch eine identische Extent-Größe von jeweils 900 Megabyte festgelegt, was in der gemeinsamen STORAGE-Klausel vor der Partitionierungsklausel zum Ausdruck kommt. CREATE TABLE verkauf ( rechnungsnr NUMBER, betrag NUMBER, verkjahr INT NOT NULL, verkmonat INT NOT NULL, verktag INT NOT NULL ) STORAGE (INITIAL 900M NEXT 900M ) PCTFREE 0 PARTITION BY RANGE (verkjahr, verkmonat, verktag) ( PARTITION verkaufq1 VALUES LESS THAN (2000, 04, PARTITION verkaufq2 VALUES LESS THAN (2000, 07, PARTITION verkaufq3 VALUES LESS THAN (2000, 10, PARTITION verkaufq4 VALUES LESS THAN (2001, 01,
01) 01) 01) 01)
TABLESPACE TABLESPACE TABLESPACE TABLESPACE
tsa, tsb, tsc, tsd );
Listing 3.24: Range Partition
Die STORAGE-Klausel kann auch explizit für jede Partition angegeben werden, für den Fall, dass jede Partition eigene Einstellungen benötigt. Sie ist dann syntaktisch vor jeder TABLESPACE-Klausel anzugeben. In diesem Beispiel werden drei numerische Partitionierungsspalten definiert, es lassen sich jedoch bis zu 16 Spalten als Partitionierungskriterium angeben – ähnlich den Restriktionen bei zusammengesetzten Indizes. Bis auf wenige Ausnahmen19 können sämtliche Datentypen für Partitionierungsspalten verwendet werden. Im Falle des Datentyps DATE ist darauf zu achten, dass über die Funktion TO_DATE die vierstellige Jahreszahl mit in die Partitionierungsklausel wandert, damit die Zuordnung der Sätze unabhängig von den jeweiligen NLS-Einstellungen garantiert werden kann. Die Klausel lautet beispielsweise:
19. Nicht zulässig sind die Pseudospalten level und rowid, der Datentyp Rowid, LOB-Spalten sowie Objekttypen, REF-Spalten, Nested Tables und Varrays.
Sandini Bib
Partitionierung
167
..PARTITION test1 VALUES LESS THAN (TO_DATE(‘1999-01-01‘,‘YYYY-MM-DD‘))
Neben den Heap-Tabellen lassen sich auch IOT-Tabellen20 partitionieren. Im Folgenden Beispiel wird die IOT-Tabelle verkauf$iot angelegt. Jede IOT-Tabelle benötigt einen Primärschlüssel, der über ein entsprechendes Constraint definiert wird. Da die Partitionierungsspalten einer IOT-Tabelle eine Teilmenge des Primärschlüssels sein müssen, enthält der Primärschlüssel hier neben der Spalte rechnungsnr auch noch die drei Partitionierungsspalten. Die Tabellenstruktur wurde – gegenüber dem vorangehenden Beispiel – um die Spalte kommentar ergänzt. Um die Baumstruktur der Index-organisierten Tabelle kompakt zu halten, wird die Spalte kommentar aus der Baumstruktur ausgegliedert und einem Überlaufbereich zugewiesen. INCLUDING verktag gibt in diesem Zusammenhang an, dass alle Spalten bis einschließlich der Spalte verktag in den Blättern des Index-Baumes gespeichert werden. Jede Partition erhält auf diese Weise ihren eigenen, ebenfalls partitionierten Überlaufbereich, der nur die Spalte kommentar aufnimmt. Im Gegensatz zu den Partitionen des Index-Baumes werden die Partitionen des Überlaufbereiches jedoch nicht in unterschiedlichen, sondern in einer gemeinsamen Tablespace tso1 abgelegt. CREATE TABLE verkauf$iot ( rechnungsnr NUMBER, verkjahr INT NOT NULL, verkmonat INT NOT NULL, verktag INT NOT NULL, betrag NUMBER, kommentar VARCHAR2(1000), CONSTRAINT pkverkauf$iot PRIMARY KEY (rechnungsnr, verkjahr, verkmonat, verktag)) ORGANIZATION INDEX INCLUDING verktag OVERFLOW STORAGE (INITIAL 500M NEXT 500M) PCTFREE 0 PARTITION BY RANGE (verkjahr, verkmonat, verktag) ( PARTITION verkaufq1 VALUES LESS THAN (2000, 04, 01) TABLESPACE ts1 OVERFLOW TABLESPACE tso1, PARTITION verkaufq2 VALUES LESS THAN (2000, 07, 01) TABLESPACE ts2 OVERFLOW TABLESPACE tso1, PARTITION verkaufq3 VALUES LESS THAN (2000, 10, 01) TABLESPACE ts3 OVERFLOW TABLESPACE tso1, PARTITION verkaufq4 VALUES LESS THAN (2001, 01, 01) TABLESPACE ts4 OVERFLOW TABLESPACE tso1); Listing 3.25: Partitionierung Index Organized Table
20. IOT = Index-organisierte Tabellen
Sandini Bib
168
Datenbankdesign
Hash-Partitionierung Das nächste Beispiel zeigt die Definition der Tabelle produkt. Auch sie besteht aus vier Partitionen mit den Namen prod1 bis prod4. Da es sich um eine Hash-partitionierte Tabelle handelt, fehlen in den Partitionierungsklauseln die VALUES LESSAngaben. Die der Partitionierungsklausel vorangestellte Storage-Klausel bewirkt auch hier, dass alle Partitionen identische Extent-Größen erhalten. CREATE TABLE produkt (nr NUMBER(10) NOT NULL, bez VARCHAR2(100) NOT NULL, gruppe NUMBER(10) NOT NULL, CONSTRAINT pkprodukte PRIMARY KEY (nr)) STORAGE (INITIAL 900M NEXT 900M) PARTITION BY HASH(nr) (PARTITION prod1 TABLESPACE ts1, PARTITION prod2 TABLESPACE ts2, PARTITION prod3 TABLESPACE ts3, PARTITION prod4 TABLESPACE ts4); Listing 3.26: Hash-Partition
Hash-partitionierte Tabellen lassen sich nicht Index-organisiert anlegen. Composite-Partitionierung Als Nächstes wird die Tabelle auftrag angelegt. Sie wird zunächst nach dem Auftragsdatum in Quartalsabschnitten Range-partitioniert. Um unabhängig von NLSEinstellungen zu sein, werden die Kriterien explizit über TO_DATE konvertiert und Monate numerisch und nicht namentlich21 referenziert! Bei der Partition Q4 wird ein offener Grenzwert angegeben (MAXVALUE). Dadurch können auch Werte des folgenden Jahres 2001 aufgenommen werden. Bei einem etwaigen Jahresabschluss oder Jahreswechsel ist dann durch ein Splitten dieser Partition für eine definierte Trennung der Daten zu sorgen (s.u.). Für jede RANGE-Partition werden des Weiteren acht Subpartitionen definiert, die in den Tablespaces ts1 bis ts8 angelegt werden. Die Namen der Subpartitionen werden in diesem Beispiel nicht vorgegeben, d.h., Oracle generiert hier selbsttätig eindeutige, fortlaufend nummerierte Bezeichner22. Die Tabelle auftrag erhält auf diese Weise 32 (Sub-)Partitionen. Die STORAGE-Klausel darf sich hier nur auf die Subpartitionen beziehen und gilt in diesem Beispiel pauschal für alle Subpartitionen. CREATE TABLE auftrag ( anr NUMBER, adatum DATE, prodnr NUMBER, menge NUMBER) STORAGE(INITAL 900M NEXT 900M) 21. z.B. DEZ statt DEC! 22. Subpartitionen werden nach dem Muster SYS_SUBPnn benannt – nn steht hier für eine laufende Nummer.
Sandini Bib
Partitionierung
169
PARTITION BY RANGE(adatum) SUBPARTITION BY HASH(prodnr) SUBPARTITIONS 8 STORE IN(ts1,ts2,ts3,ts4,ts5,ts6,ts7,ts8) ( PARTITION q1 VALUES LESS THAN(TO_DATE('01-04-2000','DD-MM-YYYY')), PARTITION q2 VALUES LESS THAN(TO_DATE('01-07-2000','DD-MM-YYYY')), PARTITION q3 VALUES LESS THAN(TO_DATE('01-10-2000','DD-MM-YYYY')), PARTITION q4 VALUES LESS THAN(MAXVALUE)); Listing 3.27: Composite-Partition
Namen für Subpartitionen können auch – wie das folgende Beispiel zeigt – explizit vergeben werden. Auf entsprechend eindeutige Namengebung – hier werden jeweils nur zwei Subpartitionen aufgebaut – ist zu achten: CREATE TABLE auftrag2 ( anr NUMBER, adatum DATE, prodnr NUMBER, menge NUMBER) STORAGE(INITAL 900M NEXT 900M) PARTITION BY RANGE(adatum) SUBPARTITION BY HASH(prodnr) SUBPARTITIONS 2 ( PARTITION q1 VALUES LESS THAN(TO_DATE('01-04-2000','DD-MM-YYYY')) (SUBPARTITION q1s1 TABLESPACE ts1, SUBPARTITION q1s2 TABLESPACE ts2) , PARTITION q2 VALUES LESS THAN(TO_DATE('01-07-2000','DD-MM-YYYY')) (subpartition q1s3 tablespace ts3, subpartition q1s4 tablespace ts4) ); Listing 3.28: Composite-Partition mit expliziter Zuweisung
List-Partitionierung Die Faktentabelle verkauf_nach_prodgruppe des folgenden Beispiels partitioniert die Verkäufe nach Produktgruppen. CREATE TABLE verkauf_nach_prodgruppe ( verkjahr INT NOT NULL, verkmonat INT NOT NULL, verktag INT NOT NULL, betrag NUMBER, prodgrp VARCHAR2(30) -- Produktgruppe ) PARTITION BY LIST (prodgrp) (PARTITION lebensmittel VALUES ('KÄ', 'WU', ’FR’), PARTITION literatur VALUES ('BE', 'BI', 'SA'), PARTITION werkzeuge VALUES ('HO', 'ME', 'GA'), PARTITION kosmetik VALUES ('SK', 'HC'),
Sandini Bib
170
Datenbankdesign
PARTITION kleidung VALUES ('HE', 'DA'), PARTITION spielwaren VALUES ('PC', 'KK', 'HS')); Listing 3.29: List-Partition
Die Partitionen werden auch hier explizit benannt. Da die STORAGE-Klauseln fehlen, werden die Partitionen in der Standard-Tablespace des betreffenden Benutzers angelegt. Partitionierungskriterium ist die Spalte prodgrp. Metadaten Auskunft über angelegte partitionierte Tabellen liefern die folgenden Data Dictionary-Views:
: : :
: : :
user_tables – enthält allgemeine Informationen und globale Statistiken (Filterung der partitionierten Tabellen über die Where-Klausel partitioned = ‘YES‘ user_part_tables – enthält Informationen zum Typ der Partitionierung, über die für alle Partitionen gültigen Storage-Parameter und die Anzahl der Partitionen. user_tab_partitions – enthält Informationen zu den einzelnen Partitionen,
d.h. zu den Namen, Partitionierungskriterien, Speicherparametern und Statistiken. user_tab_subpartitions – enthält die Namen, Speicherparameter und Statisti-
ken für Subpartitionen. user_part_key_columns – enthält die Namen und Reihenfolge der Partitionie-
rungsspalten. user_subpart_key_columns – enthält analog die Namen und Reihenfolge der
Partitionierungsspalten von Subpartitionen.
Es versteht sich, dass die oben genannten Views auch in den dba- und all-„Familien“ definiert sind. Abfragen und Manipulieren partitionierter Tabellen Einmal angelegt, werden partitionierte Tabellen mit der gewohnten INSERT-, UPDATE-, DELETE- und natürlich auch SELECT-Syntax bearbeitet: INSERT VALUES -DELETE -UPDATE
INTO verkauf (rechnungsnr, verkjahr, verkmonat, verktag) (103, 2000, 08,25); FROM verkauf WHERE verkjahr = 2000 AND verkmonat = 08; verkauf SET rechnungsnr = 110 WHERE rechnungsnr = 102;
UPDATE-Operationen auf Partitionierungsspalten, die einen Wechsel der Partition nach sich ziehen, führen jedoch standardmäßig zu Fehlern. Wenn diese Operationen gewünscht sind, muss die entsprechende Tabellendefinition angepasst werden, wie das folgende Beispiel verdeutlicht:
Sandini Bib
Partitionierung
171
UPDATE verkauf SET verkmonat = 5 WHERE verkmonat = 8; ORA-14402: Aktualisieren der Partitionsschlüsselspalte verursacht Partitionswechsel –ALTER TABLE verkauf enable row movement; Tabelle wurde geändert. -UPDATE verkauf SET verkmonat = 5 WHERE verkmonat = 8; 1 Zeile wurde aktualisiert. Listing 3.30: Row Movement
Ob eine partitionierte Tabelle für Änderungen von Partitionierungsspalten vorbereitet ist, lässt sich über die View user_tables, dort die Spalte row_movement, abfragen (Wert: Enabled bzw. Disabled). Ist bei SQL-Operationen von vorn herein bekannt, dass nur Daten einer bestimmten Partition betroffen sind, lässt sich die Syntax durch eine Partitionsklausel erweitern. Dies kann sich in einigen Fällen sehr positiv auf das Laufzeitverhalten auswirken: SELECT * FROM verkauf PARTITION(verkaufq2); -INSERT INTO verkauf PARTITION(verkaufq3) (rechnungsnr, verkjahr, verkmonat, verktag) VALUES (120, 2000, 07,25); Listing 3.31: SQL auf Partitionsebene
Stimmt die angegebene Partition nicht mit den Partitionierungskriterien überein, d.h., die Daten gehören in eine andere Partition, wird eine entsprechende Fehlermeldung ausgegeben.
3.4.4
Partitionierte Indizes
Ebenso wie Tabellen können auch Indizes partitioniert werden. Es ist grundsätzlich möglich, partitionierte Indizes für partitionierte wie auch nicht partitionierte Tabellen anzulegen. Ebenso ist es möglich, partitionierte Tabellen mit nicht partitionierten Indizes zu versehen. Mit bestimmten Einschränkungen23 können sowohl B*- als auch Bitmap-Indizes für die Partitionierung verwendet werden. Die Auswahl geeigneter Spalten aber auch geeigneter Indextypen erfordert bei partitionierten Tabellen mindestens die gleiche Aufmerksamkeit wie bei nicht partitionierten.
23. Nicht partitionierte Tabellen können nicht mit partitionierten Bitmap-Indizes versehen werden; Bitmap-Indizes auf partitionierten Tabellen müssen nach gleichen Kriterien wie die zugeordnete Tabelle partitioniert sein (Equiparitionierung).
Sandini Bib
172
Datenbankdesign
Indextypen Bei partitionierten Indizes werden zwei Eigenschaftspaare unterschieden, deren Elemente in unterschiedlichen Kombinationen miteinander auftreten und entsprechende Indextypen definieren können. Die Elemente des ersten Paares beziehen sich auf die Kriterien der Partitionierung. Es sind:
:
Lokale Indizes Partitionierte Indizes sind immer dann lokal, wenn sie die gleichen Partitionierungskriterien – Partitionen und Subpartitionen – wie die ihnen zugeordnete Tabelle aufweisen (Equipartitioniert). Operationen auf den Partitionen der Tabelle – wie z.B. aufteilen, löschen, lesen – können 1:1 auf den entsprechenden Index übertragen werden, unabhängig davon, ob die Tabelle Range- oder Hash-partitioniert wurde. Aus diesem Grunde wird ein lokaler Index transparent zu allen Operationen auf der partitionierten Tabelle mitgeführt.
:
Lokale Indizes können auch eindeutig sein, sofern die Partitionierungsspalten eine Untermenge der Indexspalten darstellen. Auf diese Weise ist es möglich, die Eindeutigkeit im Rahmen einer Partition und damit über die gesamte Tabelle sicherzustellen. Globale Indizes Man spricht von einem globalen Index, wenn der Index eigene, von der zugeordneten Tabelle unabhängige Partitionierungskriterien aufweist. Diese Kriterien werden stets auf Basis der Range-Partitionierung definiert. Operationen auf den Partitionen der zugeordneten Tabelle können hier nicht direkt auf den Index übertragen werden. Das Löschen einer einzigen Tabellenpartition beispielsweise kann den gesamten globalen Index betreffen, Zugriffe auf eine Tabellenpartition können mehrere Indexpartitionen umfassen und umgekehrt. Aus diesem Grunde werden globale Indizes nach bestimmten administrativen Eingriffen – z.B. dem Löschen oder Splitten von Partitionen – ungültig und müssen reorganisiert werden.
Die Elemente des zweiten Attributpaares beziehen sich auf die Rollen der Indexspalten. Es sind:
: :
Prefixed Indizes sind prefixed, wenn die für die Partitionierung des Indexes verantwortlichen Spalten selbst auch indiziert sind: Ein Index X ist prefixed, wenn die indizierte Spalte C1 auch die Grundlage für die Partitionierung bildet. Nonprefixed Indizes sind nonprefixed, wenn die für die Partitionierung verantwortlichen Spalten selbst nicht indiziert werden: Ein Index Y ist nonprefixed, wenn er die Spalte C1 indiziert, jedoch nach den Werten der Spalte C2 partitioniert wird.
Die oben genannten Eigenschaftspaare können nun in den folgenden drei Kombinationen auftreten und entsprechende Indizes definieren. Die Eigenschaften ergeben sich entsprechend durch die Zusammenstellung der oben genannten Elemente:
Sandini Bib
Partitionierung
:
173
Local Prefixed-Index Ein Index wird als local prefixed bezeichnet, wenn er in Bezug auf die zugeordnete Tabelle equipartitioniert ist und die Partitionierungsspalte oder -spalten an führender Position enthält. Es spielt dabei keine Rolle, ob die Tabelle Range-, Hash- oder Composite-partitioniert wurde. Ein Beispiel soll dies verdeutlichen: Gegeben sei die Tabelle x mit den Spalten c1, c2 und c3. Sie wird auf Basis der Spalte c2 Range-partitioniert. Der Index i1 ist local prefixed, wenn er für die Spalte c2 definiert und in der gleichen Weise wie x partitioniert wird. Der Index i2, der zwar wie x partitioniert wird, aber aus den Spalten c3 und c2 besteht, ist nicht local prefixed, weil er die Partitionierungsspalte der Tabelle – c2 – nicht an führender Position enthält. Local Prefixed-Indizes haben eine Reihe von erwähnenswerten Vorteilen:
:
–
Sie unterstützen die Unabhängigkeit von Partitionen, weil sie beim Hinzufügen, Löschen und Aufteilen von Partitionen transparent zu der betreffenden Tabelle angepasst werden und keinen Neuaufbau (rebuild) erfordern.
–
Sie können als eindeutige Indizes angelegt werden.
–
Der Optimizer kann die Zugriffe auf identische Index- und Tabellen-Partitionen abstimmen.
–
Recovery-Aktionen – vollständig oder unvollständig – sind ohne zusätzlichen Verwaltungsaufwand für die Indizes durchführbar.
Local Prefixed-Indizes zählen daher zu den am häufigsten eingesetzten Typen. Local Nonprefixed-Index Ein Index, der in gleicher Weise wie die zugrunde liegende Tabelle partitioniert ist, jedoch die für die Partitionierung verantwortliche Spalte selbst nicht oder nicht an führender Position indiziert, wird als local nonprefixed bezeichnet. Der oben beschriebene Index i2 auf den Spalten c3 und c2 ist ein Local Nonprefixed-Index. Ebenso ist ein Index i3, der nur die Spalte c3 indiziert, aber wie die Tabelle x nach c2 partitioniert ist, ebenfalls local nonprefixed. Local Nonprefixed-Indizes haben auf Grund des Attributes local und der damit verbundenen Equipartitionierung die bereits besprochenen Vorteile bei der Verwaltung der zugeordneten Tabelle. Sie sind aus diesem Grunde überall dort sinnvoll, wo Zugriffe ohne die jeweiligen Partitionierungsspalten durchgeführt werden sollen, ohne die oben erwähnten Vorteile bei der Verwaltung der Tabellen und Indizes zu verlieren – beispielsweise beim Zugriff auf eine partitionierte Tabelle auftrag über Kundennummern unabhängig von dem Auftragsdatum. Diesen Vorteilen stehen jedoch einige Nachteile gegenüber: –
Local Nonprefixed-Indizes können nur dann als unique definiert werden, wenn die Partitionierungsspalten eine Untermenge der Indexspalten bilden.
Sandini Bib
174
–
:
Datenbankdesign
Zugriffe sind – wegen der fehlenden Equipartitionierung – aufwändiger als über Prefixed-Indizes, denn Schlüsselwerte können in mehreren Partitionen vorkommen.
Global Prefixed-Index Ein Index wird als global prefixed bezeichnet, wenn er nach anderen Kriterien als die zugrunde liegende Tabelle partitioniert ist, die für die Partitionierung verantwortliche Spalte jedoch mit indiziert ist. Die Partitionierung bei Global Prefixed-Indizes darf jedoch nur vom Type Range sein, die Tabelle, auf die er sich bezieht, kann dagegen jede Art von Partitionierung enthalten. Auch hierzu ein kurzes Beispiel: Gegeben sei wieder die Tabelle x, die – immer noch – aus den Spalten c1, c2 und c3 besteht und auf Basis von c2 partitioniert ist. Der Index i4, der die Spalten c3 und c1 von x indiziert und nach c3 partitioniert ist, wird als global prefixed bezeichnet. Global Prefixed-Indizes haben wenige Vorteile – z.B. die mögliche Eindeutigkeit –, dagegen eine Reihe von gravierenden Nachteilen: –
Administrative Eingriffe, wie z.B. das Löschen, Hinzufügen und Splitten von Partitionen haben – wegen der unterschiedlichen Partitionierung – in der Regel Auswirkungen auf sämtliche Indexpartitionen und erfordern daher die anschließende explizite Reorganisation der globalen Indizes!
–
Unvollständige Recovery-Aktionen der Tabelle erfordern den kompletten Neuaufbau aller globalen Indizes.
–
Satzadressen einer Indexpartition können auf mehrere oder alle Partitionen der zugeordneten Tabelle verweisen.
Syntaxbeispiele Im Folgenden finden sich einige syntaktische Beispiele für den Aufbau der oben besprochenen Indexvarianten. Im ersten Beispiel wird der lokale Index i$verkauf1 angelegt, der, genau wie seine Basistabelle verkauf, Range-partitioniert ist. Er enthält alle Partitionierungsspalten dieser Tabelle. Die übergeordnete STORAGE-Klausel bezieht sich auch hier auf alle Partitionen des Indexes. Partitionsnamen werden in diesem Beispiel explizit vergeben, wie auch die betreffenden Tablespaces. Eine VALUES-Klausel ist wegen der Equipartitionierung nicht zulässig. CREATE INDEX i$verkauf1 ON verkauf(verkjahr, verkmonat,verktag) STORAGE (INITIAL 300M NEXT 300M) PCTFREE 0 LOCAL (PARTITION vi1 TABLESPACE tsi1, PARTITION vi2 TABLESPACE tsi2, PARTITION vi3 TABLESPACE tsi3, PARTITION vi4 TABLESPACE tsi4); Listing 3.32: Index-Partition
Sandini Bib
Partitionierung
175
Im zweiten Beispiel wird für die Index-organisierte Tabelle verkauf$iot, die nach den Spalten verkjahr, verkmonat und verktag partitioniert ist, der lokale Sekundärindex i$verkiot1 angelegt. Da er nur die Spalten verkmonat und verktag enthält und nicht alle Partitionierungsspalten an führender Position, handelt es sich um einen Local Nonprefixed-Index. Wegen der fehlenden STORAGE-Klausel gelten für die Partitionen die Default-Parameter der betreffenden Tablespaces. CREATE INDEX i$verkiot1 ON VERKAUF$IOT(VERKMONAT, VERKTAG) LOCAL (PARTITION vi1 TABLESPACE tsi1, PARTITION vi2 TABLESPACE tsi2, PARTITION vi3 TABLESPACE tsi3, PARTITION vi4 TABLESPACE tsi4); Listing 3.33: Index-Organized Table Partition
Die kürzeste mögliche Form der Syntax zeigt das folgende Beispiel. Für die Tabelle auftrag, die nach dem Auftragsdatum und – als Subpartition – nach der Produktnummer partitioniert ist, wird der lokale Nonprefixed-Index i$auftrag3 angelegt. Dieser Index ist wie auch die Tabelle in vier Hauptpartitionen mit jeweils acht Subpartitionen aufgeteilt. Da jegliche Speicherparameter zu Partitionen fehlen, werden die Indexpartitionen so benannt wie die der Tabelle und in der Default-Tablespace des betreffenden Schemas mit dort geltenden Default-Speicherparametern gespeichert. CREATE INDEX i$auftrag3 ON auftrag(prodnr) LOCAL;
Bei der Composite-partitionierten Tabelle auftrag soll die Vergabe eindeutiger Auftragsnummern sichergestellt werden. Aus diesem Grunde wird ein eindeutiger, partitionierter Index für die Spalte anr geplant. Ein lokaler eindeutiger Index müsste – neben der Spalte anr – aus den Partitionierungsspalten adatum (Hauptpartitionen) und prodnr (Subpartitionen) bestehen und könnte daher keine eindeutigen Auftragsnummern garantieren. Deshalb wird im folgenden Beispiel ein eindeutiger, Range-partitionierter Global Prefixed-Index angelegt24, der nach anr partitioniert werden muss. CREATE UNIQUE INDEX ui$auftrag ON auftrag(anr) GLOBAL PARTITION BY RANGE (anr) (PARTITION p1 VALUES LESS THAN(1000), PARTITION p2 VALUES LESS THAN(2000), PARTITION p3 VALUES LESS THAN (MAXVALUE) ); Listing 3.34: Global Prefixed-Index
24. Als Alternative käme hier auch ein nicht partitionierter, eindeutiger Index in Frage.
Sandini Bib
176
Datenbankdesign
Metadaten Informationen zu partitionierten Indizes sind über die folgenden Views abrufbar:
: : :
: :
user_indexes – enthält allgemeine Informationen und globale Statistiken (Filterung der partitionierten Indizes über die WHERE-Klausel partitioned = ‘YES‘). user_part_indexes – enthält Informationen zum Typ der Partitionierung und des Indexes, die für alle Partitionen gültigen Speicherparameter und die Anzahl der Partitionen. user_ind_partitions – enthält Informationen zu den einzelnen Hauptpartitio-
nen, d.h. Namen, Partitionierungskriterien, Speicherparametern und Statistiken. user_ind_subpartitions – enthält entsprechend die Namen, Speicherparameter und Statistiken für Subpartitionen. user_ind_columns – enthält die Namen und Reihenfolge der Indexspalten für partitionierte wie auch nicht partitionierte Indizes.
Es versteht sich, dass die oben genannten Views auch in den dba- und all-„Familien“ definiert sind.
3.4.5
Partitionen und der Optimizer
Der performante Zugriff auf partitionierte Tabellen – dies gilt gleichermaßen für Heap- als auch für Index-organisierte Tabellen – ist eine Aufgabe für den kostenbasierten Optimizer. Der folgenden Abschnitt behandelt sowohl die Generierung von Statistiken als auch die Zugriffsalgorithmen des kostenbasierten Optimizers für partitionierte Objekte. Generierung von Statistiken Der kostenbasierte Optimizer generiert seine Zugriffspläne – wie der Name vermuten lässt – auf der Basis der kostengünstigsten Operationen. Hierfür benötigt er Statistiken, die explizit oder über geeignete Jobs erstellt werden müssen. Die Generierung von Statistiken im Zusammenhang mit partitionierten Objekten ist naturgemäß komplexer als bei nicht partitionierten:
:
:
Neben den individuellen Statistiken für die „elementaren“ Speichereinheiten – Partitionen oder Subpartitionen – werden ebenso globale Statistiken für die gesamte Tabelle oder die jeweils übergeordnete Partition benötigt, damit Zugriffe, die über mehr als eine Partition oder Subpartition laufen, optimal berechnet werden können. Globale Statistiken können nicht immer direkt von den individuellen abgeleitet werden: Die Anzahl der distinktiven Schlüssel kann keinesfalls – wegen möglicher Überlappungen – aus den Partitionen addiert werden. Anders verhält es sich mit der Anzahl der Datensätze oder dem kleinsten oder größten Wert
Sandini Bib
Partitionierung
:
177
Auf Grund der – in der Regel – großen Datenmengen ist eine Optimierung bei der Generierung von Statistiken wünschenswert.
Aus den oben genannten Gründen ist es nicht sinnvoll, Statistiken für partitionierte Objekte einzig über den ANALYZE-Befehl zu erzeugen, weil
:
ANALYZE globale Statistiken nicht direkt berechnet, sondern aus den Basiseinhei-
:
ANALYZE nicht parallelisierbar ist.
ten – Subpartitionen oder Partitionen – ableitet und
Als Alternative zum ANALYZE-Befehl steht für diese Zwecke das dbms_stats-Paket zur Verfügung. Dbms_stats sammelt Statistiken für Tabellen, Spalten und Indizes, kann sowohl exakt (COMPUTE) als auch exemplarisch (ESTIMATE) arbeiten, ist parallelisierbar und geeignet, globale Statistiken zu generieren. Im Gegensatz zu ANALYZE werden über dbms_stats jedoch die folgenden Statistiken nicht erfasst: die Anzahl der migrierten Datensätze (chain_cnt), der durchschnittliche Freiplatz pro Block (avg_space) und die Anzahl ungenutzter Datenblöcke jenseits der Hochwassermarke (empty_blocks). Dies liegt daran, dass dbms_stats die Statistiken über entsprechende SELECT-Befehle, Gruppenfunktionen und Hints – für die Parallelisierung – generiert25. Lediglich die Indexdaten werden – mangels eines geeigneten SELECT-Befehls – über den ANALYZE-Befehl erzeugt. Im Folgenden Beispiel wird die Prozedur gather_table_stats des dbms_statsPakets aufgerufen, um für die partitionierte Tabelle verkauf im Schema scott Statistiken zu generieren. Über granularity => all wird sichergestellt, dass Statistiken auf allen Ebenen – Subpartition, Partition und global – generiert werden. Cascade => TRUE sorgt für Statistiken auf den zugehörigen Indizes. Alle übrigen Argumente werden über Standardwerte bedient: Keine Angabe für partname bewirkt, dass alle Partitionen behandelt werden. Das Fehlen von estimate und block_sample führt zur exakten Berechnung der Werte (compute). Method_opt ist mit for all columns size 1 vorbelegt und die fehlende Angabe bei degree sorgt für eine Parallelisierung des Tabellenzugriffs, wie sie in der Definition der Tabelle festgelegt wurde. Statistiken für die Indizes werden in jedem Fall seriell generiert, da sie über den ANALYZE-Befehl gesammelt werden. BEGIN dbms_stats.gather_table_stats (ownname => 'SCOTT', tabname => 'VERKAUF' , -- Defaults für: partname, estimate, block_sample, method_opt, degree , granularity => 'ALL', CASCADE => TRUE ); END; / Listing 3.35: gather_table_stats
25. Die genaue Syntax der Befehle kann leicht über SQL-Trace und TKPROF ermittelt werden.
Sandini Bib
178
Datenbankdesign
Die Sammlung solchermaßen komplexer Statistiken kann trotz einer durchgeführten Parallelisierung zu einem längeren Laufzeitverhalten führen. Aus diesem Grunde ist es sinnvoll, Statistiken auf globaler Ebene nicht in der gleichen Frequenz wie solche auf Partitions- und Subpartitionsebene zu generieren. Eine ausgewogene Mischung aus ANALYZE- und dbms_stats-Aufrufen ist hier ratsam. Innerhalb des dbms_stats-Pakets sind drei weitere Prozeduren von Interesse: gather_index_stats, gather_schema_stats und gather_database_stats, die – wie die Namen erwarten lassen – Statistiken auf Index-, Schema- und Datenbankebene generieren. Im folgenden Beispiel werden über ANALYZE für die – neu angelegte – Partition q5 der Tabelle auftrag Tabellen- und Spaltenstatistiken für indizierte Spalten generiert. ANALYZE TABLE auftrag PARTITION (q5) ESTIMATE STATISTICS FOR TABLE FOR ALL INDEXED COLUMNS SAMPLE 30 PERCENT;
Gleichermaßen kann eine neue Indexpartition explizit analysiert werden: ANALYZE INDEX i$auftrag1 PARTITION (q5) COMPUTE STATISTICS;
Die Statistiken selbst können dann über die in Abschnitt 3.4.3 und 3.4.4 beschriebenen Views selektiert werden. Zusätzlich stehen die Views user_part_col_statistics und user_subpart_col_statistics für Spaltenstatistiken zur Verfügung. Die Spalte last_analyzed zeigt dabei das Datum der letzten Analyse. Über die Spalte global_stats lässt sich feststellen, ob globale Statistiken – mit Hilfe von dbms_stats – generiert wurden (=YES). Werden – aus Gründen der Performance – ANALYZE und dbms_stats gemischt verwendet, weisen die genannten Views eine gewöhnungsbedürftige Mischung von Statistikdaten auf:
:
:
Läuft ANALYZE nach dbms_stats, werden Partitionsstatistiken generiert und entsprechend über die View user_tab_partitions ausgewiesen. Das Attribut global_stats wird hier korrekt auf No gesetzt. Allerdings werden die globalen Statistiken der View user_tables nicht überschrieben! Das Attribut global_stats bleibt hier nach wie vor auf Yes geschaltet. Läuft dbms_stats nach analyze, werden Statistiken in allen Views überschrieben und global_stats wird korrekt gesetzt.
Bei der Entscheidung, in welchen Abständen Statistiken für ein bestimmtes Objekt erzeugt werden sollten, kann das Tabellen-Monitoring helfen. Über den Befehl ALTER TABLE verkauf MONITORING;
wird beispielsweise das interne Monitoring für die Tabelle verkauf eingeschaltet. Mit Hilfe der View user_tab_modifications kann die Anzahl der Update-, Deleteund Insert-Befehle für alle Tabellen, deren Monitoring eingeschaltet ist, abgerufen werden. Da die Daten über die Tabellenmodifikationen über den Hintergrundprozess SMON gespeichert werden, kann zwischen der Operation und ihrem Auftauchen in der View einige Zeit vergehen26. Die Prozedur gather_schema_stats des 26. Der SMON-Hintergrundprozess ist alle zwei Stunden aktiv.
Sandini Bib
Partitionierung
179
Pakets dbms_stats kann über den Parameter options => ’GATHER STALE’ gezielt Tabellen mit veralteten Statistiken analysieren. Zugriffe auf einzelne Tabellen Im folgenden Beispiel wurde für die Tabelle verkauf der lokale Prefix-Index i$verkauf_kk definiert, der neben den Partitionierungsspalten verkjahr, verkmonat und verktag die Kundennummer der Spalte kunde enthält. Gefragt ist in diesem Beispiel der Umsatz des Kunden 25 zwischen dem 2. und 10. März 2000. Der Zugriff erfolgt über den oben genannten Index. Für den Index wie auch die Tabelle wird – wegen der Equipartitionierung – nur die erste Partition ausgewertet, wie sich an den Spalten partition_start und partition_stop der Tabelle plan_table erkennen lässt. SELECT WHERE AND AND AND
sum(preis) FROM verkauf verkjahr = 2000 verkmonat = 03 verktag BETWEEN 02 AND 10 kunde = 25;
Plan Table ------------------------------------------------------------------| Operation | Name | Rows|Pstart|Pstop| ------------------------------------------------------------------| SELECT STATEMENT | | 1 | | | | SORT AGGREGATE | | 1 | | | | TABLE ACCESS BY LOCAL INDEX |VERKAUF | 3 | 1 | 1| | INDEX RANGE SCAN |I$VERKAUF_KK | 3 | 1 | 1| ------------------------------------------------------------------Listing 3.36: Einfacher Index-Zugriff
In welcher Form profitiert nun dieser Zugriff von der erfolgten Partitionierung? Der Tabellenzugriff über die per Index-Scan ermittelte Satzadresse ist mit Sicherheit in seinem Laufzeitverhalten dem einer nicht partitionierten Tabelle ebenbürtig. Der Index-Scan selbst könnte von der Tatsache profitieren, dass der lokal partitionierte Index – wegen der reduzierten Datenmenge – eine geringere Höhe als sein nicht partitioniertes Ebenbild aufweist. Hierdurch würden ein oder zwei Blockzugriffe gespart, welche die Zugriffszeit mit Sicherheit nicht nachhaltig beeinflussen. Fazit: Der in diesem Beispiel dargestellte Zugriff profitiert nicht von der Partitionierung der Tabelle verkauf. Durch einen Buchungsfehler wurden während der ersten vier Monate des Jahres 2000 für den Kunden mit der Nummer 25 zu niedrige Preise eingetragen. Der UPDATE-Befehl des zweiten Beispiels sorgt für eine entsprechende Anpassung der Tabelle verkauf. UPDATE verkauf SET preis = preis * to_number(‘1,1‘) WHERE verkjahr = 2000 AND verkmonat < 05 AND kunde = 25;
Sandini Bib
180
Datenbankdesign
Plan Table ------------------------------------------------------------------| Operation | Name | Rows|Pstart| stop| ------------------------------------------------------------------| UPDATE STATEMENT | | 44 | | | | UPDATE |VERKAUF | | | | | PARTITION RANGE ITERATOR | | | 1 | 2| | TABLE ACCESS FULL |VERKAUF | 44 | 1 | 2| ------------------------------------------------------------------Listing 3.37: Zugriff für UPDATE
Der Zugriffsplan zeigt hier einen nicht indizierten Tabellenzugriff für die Partitionen 1 – bis einschließlich März – und 2 – für den Monat April. Die Operation Partition Range Iterator verdeutlicht zusätzlich den partiellen Zugriff auf mehrere Partitionen. Der im ersten Beispiel beschriebene Index wurde hier nicht herangezogen, offensichtlich weil die nutzbaren führenden Spalten verkjahr und verkmonat zu wenig selektiv waren. Da nicht benötigte Partitionen für das dritte und vierte Quartal vom Zugriff ausgeschlossen werden (partition elemiation), reduziert sich die Anzahl der zu lesenden Blöcke erheblich, so dass in diesem Beispiel durch die Partitionierung eine deutliche Verbesserung des Laufzeitverhaltens zu erwarten ist. Joins Im folgenden Beispiel soll eine Liste mit Kundennamen und Umsätzen für alle Einkäufe vom Mai des Jahres 2000 ausgegeben werden. Hierzu wird die Range-partitionierte Tabelle verkauf mit der nach dem Attribut Kundennummer (kdnr) Hashpartitionierten Tabelle kunde, die aus drei Partitionen besteht, verknüpft und die Spalte preis pro Kunde summiert. Für die Tabelle kunde existiert darüber hinaus ein eindeutiger Local Prefixed-Index auf der Spalte kdnr. SELECT FROM WHERE AND GROUP
sum(v.preis) umsatz, k.name verkauf v, kunde k k.kdnr = v.kunde v.verkjahr = 2000 AND v.verkmonat = 05 BY k.name;
Plan Table ------------------------------------------------------------------| Operation | Name | Rows|Pstart|Pstop | ------------------------------------------------------------------| SELECT STATEMENT | | 1 | | | | SORT GROUP BY | | 1 | | | | HASH JOIN | | 5K| | | | TABLE ACCESS FULL |VERKAUF | 5K| 2 | 2 | | PARTITION HASH ALL | | | 1 | 3 | | TABLE ACCESS FULL |KUNDE | 50K| 1 | 3 | ------------------------------------------------------------------Listing 3.38: Zugriffsplan für Hash-Join
Sandini Bib
Partitionierung
181
Der Zugriffsplan zeigt einen Hash-Join, bei dem zunächst ohne Index auf die zweite Partition der Tabelle verkauf zugegriffen wird, da der Verkaufsmonat 05 in dieser Partition liegt. Mit der Tabelle verkauf wird dann im zweiten Schritt die Tabelle kunde verbunden. Da diese nicht mit verkauf equipartitioniert ist, sondern per Hash auf der Basis der Kundennummern partitioniert wurde, muss für die JoinOperation auf alle Partitionen von kunde zugegriffen werden (Operation Partition Hash All). Die Vorteile der Partitionierung werden bei diesem Beispiel nur auf Seiten der Tabelle verkauf deutlich, weil hier die Anzahl der Blockzugriffe der Table Access Full-Operation gegenüber einer nicht partitionierten Lösung minimiert wird. Parallele Operationen Für das nächste Beispiel wird eine neue Tabelle verkauf$cp angelegt, die die gleichen Attribute wie verkauf hat, jedoch Composite-partitioniert ist. Für jede RangePartition sind hier drei Hash-Partitionen vorhanden. Verkauf$cP und kunde sind dadurch auf unterster Ebene equipartitioniert, nämlich durch jeweils drei HashPartitionen auf der Basis der Kundennummer. Diese Equi-Partitionierung kann nun – wie das folgende Beispiel zeigt – zu einer Parallelisierung der Join-Operationen genutzt werden. Die Abfrage ist bis auf den Hint mit der des vorangehenden Beispiels identisch. SELECT /*+ parallel(v,4) parallel(k,4) */ sum(v.preis) Umsatz, k.name FROM verkauf$cp v, kunde k WHERE k.kdnr = v.kunde AND v.verkjahr = 2000 AND v.verkmonat = 05 GROUP BY k.name; Part 1 ------------------------------------------------------------------| Operation | Name | Rows|Pstart|Pstop| ------------------------------------------------------------------| 0 SELECT STATEMENT | | 1 | | | | 1 SORT GROUP BY | | 1 | | | | 2 SORT GROUP BY | | 1 | | | | 3 PARTITION HASH ALL | | | 1 | 3| | 4 HASH JOIN | | 5K| | | | 5 PARTITION RANGE SINGLE | | | 2 | 2| | 6 TABLE ACCESS FULL |VERKAUF$CP | 5K| 4 | 6| | 7 TABLE ACCESS FULL |KUNDE | 50K| 1 | 3| ------------------------------------------------------------------Listing 3.39: Zugriffsplan für partitionierte Tabelle
Der erste Teil des Zugriffsplans zeigt den vertrauten Hash-Join zwischen verkauf$cp und kunde. Für verkauf$cp werden die Partitionen 4 bis 6 – dies sind die drei Subpartitionen einer, nämlich der zweiten Range-Partition, die den Verkaufsmonat 05 enthält – ohne Index gelesen. Für kunde werden alle drei vorhandenen Hash-Partitionen eingelesen und per Hash mit verkauf$cp verknüpft.
Sandini Bib
182
Datenbankdesign
Part 2 -------------------------------------------------------| ID | Rows |IN-OUT| PQ Distrib | Pstart| Pstop | -------------------------------------------------------| 0 | 1 | | | | | | 1 | 1 | P->S | QC (RANDOM)| | | | 2 | 1 | P->P | HASH | | | | 3 | | PCWP | | 1 | 3 | | 4 | 5K| PCWP | | | | | 5 | | PCWP | | 2 | 2 | | 6 | 5K| PCWP | | 4 | 6 | | 7 | 50K| PCWP | | 1 | 3 | -------------------------------------------------------Listing 3.40: Zugriffsplan für Parallelisierung
Der zweite Teil des Zugriffsplanes stellt die Parallelisierung der Operationen, die über den eingebetteten Hint erzwungen wurden, dar. Der Hint sorgt hier für die vierfache Parallelisierung27 beim Zugriff auf beide Tabellen. Die Zuordnung der Operationen erfolgt über die in beiden Darstellungen vorhandene Identifizierungsnummer (id). Der Plan zeigt, dass die Operationen 2 bis 7 mit Hilfe eines Sets von Serverprozessen parallel auf der Basis der Hash-Partitionen durchgeführt werden. PCWP steht dabei für parallel combined with parent28. Die Operation 2, die auf Basis der Partition den Gruppensort parallel durchführt, übergibt ihre Daten in neuer „Partitionierung“ an die Operation 1, die nun ihrerseits einen Gruppensort parallel – allerdings nun für die gesamte Ergebnismenge – erledigt. Diese „Neupartitionierung“ der Ergebnisdaten wird durch das Attribut P -> P – parallel to parallel – zum Ausdruck gebracht. Die Zuordnung einzelner Datensätze zu den Prozessen erfolgt dabei durch eine Hash-Funktion (Spalte PQ distribution). Operation 1 übergibt ihre Daten schließlich seriell an den Koordinatorprozess (parallel to serial), der sie ohne weitere Sortierung ausgibt (QC29 random). Da bei der oben dargestellten Abfrage für alle beteiligten Tabellen eine vergleichbare Partitionierung vorliegt, nämlich drei Hash-Partitionen auf der Basis der Kundennummern, kann der Join „paarweise“ parallelisiert werden. Dies führt bei großen Ergebnismengen zu erheblichen Laufzeitverbesserungen.
3.4.6
Partitionen verwalten
Eingangs wurde bereits erwähnt, dass dem Administrator eine Vielzahl von Operationen für das Verwalten und Umorganisieren von Partitionen zur Verfügung steht: wie z.B. das Hinzufügen, Löschen, Laden und Aufteilen von Partitionen u.v.m. Für die Beurteilung der einzelnen Operationen sind – neben ihrer grundlegenden Funktionalität – im Wesentlichen zwei weitere Faktoren wichtig: 27. Durch die interoperationale Parallelisierung können so maximal acht Serverprozesse genutzt werden. 28. D.h., die Operation wird parallel ausgeführt, die Folgeoperation wird vom gleichen Serverprozess übernommen. 29. QC steht für Query Coordinator.
Sandini Bib
Partitionierung
: :
183
Die Auswirkungen in Bezug auf gleichzeitig mögliche Zugriffe (concurrency), die über das Sperrverhalten der Operation bestimmt werden. Die Auswirkungen auf abhängige Objekte, vor allem Indizes.
Diese Auswirkungen beeinflussen einerseits den Designer – z.B. bei der Auswahl bestimmter Indextypen –, andererseits den Administrator, der den Zeitpunkt der Durchführung und die begleitenden Aktionen bestimmter Operationen genau festlegen muss. Der folgende Abschnitt gibt hierzu einen Überblick. Historische Daten: „Rolling Window“-Operationen Die Verwaltung zeitgesteuerter Daten über entsprechende Batch-Programme gehört zu den Paradebeispielen partitionierter Tabellen. Diese Daten zu verwalten bedeutet im Einzelnen:
: :
Altdaten periodisch zu löschen Neudaten (periodisch) zu übernehmen
Durch die periodische Löschung und Übernahme von Daten entsteht ein – stets gleich bleibendes – Zeitfenster aktiver Nutzdaten (rolling window). Wurden die Partitionierungskriterien sorgfältig mit den geschäftlichen Anforderungen abgestimmt, kann die Löschung und Übernahme der Daten sehr effizient über das Löschen und Hinzufügen ganzer Partitionen statt durch aufwändige Delete- und Insert-Operationen erreicht werden. Gibt es keine exakte Deckung zwischen den Partitionierungs- und Verwaltungsfenstern, müssen ggf. Partitionen aufgeteilt werden. Partitionen löschen Das Löschen von Partitionen ist für Range- und Composite-
partitionierte Tabellen möglich. Partitionen Hash-partitionierter Tabellen können dagegen nicht gelöscht werden. Im Folgenden Beispiel wird die Partition verkaufq4 der Tabelle verkauf gelöscht. Hierzu wird eine exklusive Sperre für die betreffende Partition angefordert. Aus diesem Grunde ist das Löschen einer Partition nur dann möglich und erfolgreich, wenn keine weiteren Satz- oder Tabellensperren für die betreffende Partition vorliegen. Sperren im Kontext anderer Partitionen wirken sich dagegen auf diese Operation nicht aus. Lesende Zugriffen werden in keinem Fall beeinträchtigt. ALTER TABLE verkauf DROP PARTITION verkaufq4;
Beim Löschen der Partition werden lokale Indizes automatisch mitangepasst, d.h., sie verlieren ebenfalls ihre der Tabellenpartition verkaufq4 zugeordnete Partition. Globale Indizes dagegen verlieren ihre Gültigkeit: Das Attribut status der Views user_ind_partitions oder user_ind_subpartitions – bei Composite-partitionierten Indizes – zeigt den Wert unusable. Dies führt dazu, dass alle Zugriffe, bei denen der Optimizer sich für eine Nutzung der betreffenden Indizes entscheidet, mit einer entsprechenden Fehlermeldung abgebrochen werden30. Globale Indizes müssen daher nach dem Löschen von Partitionen reorganisiert werden. Die Reorganisation von globalen, partitionierten Indizes erfolgt entweder durch das Löschen und Neuanlegen des Indexes oder über die Rebuild-Klausel des ALTER 30. ORA-01502: Index ‘xxx‘ oder Partition dieses Indexes in nicht brauchbarem Zustand
Sandini Bib
184
Datenbankdesign
INDEX-Befehls. Die Reorganisation muss in diesem Fall allerdings explizit für jede Partition bzw. Subpartition durchgeführt werden:
ALTER INDEX i$verk_glob REBUILD PARTITION p1;
Da globale Indizes anderen Partitionierungskriterien wie ihnen zugeordnete Tabellen folgen, muss für die Reorganisation jeder Partition die komplette Basistabelle gelesen werden. Dies kann u.U. aufwändiger als das Löschen und der Neuaufbau sein. Aus den oben angeführten Gründen ist es wichtig, globale Indizes nur dann einzusetzen, wenn sie unbedingt benötigt werden. Hinzufügen von Partitionen Bei Anwendungen, die ihre historischen Daten nicht
nur periodisch löschen, sondern auch periodisch laden, gehört das Anlegen neuer Partitionen mit zum Bestandteil eines Rolling Window-Moduls. Das Anlegen neuer Partitionen kann nur am „oberen“ Ende der Partitionierungsskala erfolgen und ist bei Range-, Hash- und Composite-partitionierten Tabellen möglich. Es können sowohl Partitionen als auch Subpartitionen ergänzt werden. Im Folgenden Beispiel wird die Partition verk01q1 für die Range-partitionierte Tabelle verkauf im Tablespace ts1 mit einer Extent-Größe von 500 Mbyte angelegt: ALTER TABLE verkauf ADD PARTITION verk01q1 VALUES less than (2001,04,01) TABLESPACE ts1 STORAGE (INITIAL 500M NEXT 500M);
Diese Aktion hat keine Auswirkungen auf die Indizes der betreffenden Tabelle, d.h., lokale wie globale Indizes bleiben ohne Reorganisation nutzbar. Für alle lokalen Indizes werden automatisch gleichnamige Indexpartitionen angelegt. Sperren auf den „alten“ Partitionen der Tabelle beeinträchtigen diese Operation nicht, d.h., sie kann ohne Einschränkungen online durchgeführt werden. Partitionstausch Die neu erstellte Partition kann nun Daten aufnehmen. Eine elegante und sehr performante Möglichkeit, Daten en bloc einer Partition zuzuteilen, ist der „Tausch“ der Datensegmente von Partitionen und Tabellen. Dabei wird eine vorhandene Tabelle, die vorher mit Daten gefüllt wurde, zu einer Partition einer partitionierten Tabelle gemacht, ohne dass dabei die Daten Segmentgrenzen überschreiten. Aus diesem Grunde ist die Operation konkurrenzlos schnell!
Im Folgenden Beispiel werden die Segmente der Tabelle verk_lade und der Partition verkaufq3 der Tabelle verkauf getauscht. Die aus der Tabelle stammenden Daten sollen dabei hinsichtlich der Partitionierungskriterien geprüft werden (WITH VALIDATION). Die angegebene Partition muss vorher angelegt worden sein. ALTER TABLE verkauf EXCHANGE PARTITION verkaufq3 WITH TABLE verk_lade WITH VALIDATION;
Die Tabelle verk_lade enthält nach dem Tausch die Daten der angegebenen Partition. Da in unserem Beispiel die Partition leer war, bleibt nach dem Tausch eine leere Tabelle verk_lade zurück.
Sandini Bib
Partitionierung
185
Durch die Tauschaktion werden alle globalen Indizes sowie die der Tauschpartition zugeordneten Partitionen der lokalen Indizes unbrauchbar und müssen – wie oben beschrieben – reorganisiert werden. Der Befehl kann auch dann ausgeführt werden, wenn Transaktionen Sperren auf anderen Partitionen der Tabelle halten. Aufteilen von Partitionen Werden Daten nicht periodisch eingefügt, sondern durch Insert-Operationen im laufenden Betrieb, ist es oft notwendig, die letzte Range-Partition einer Tabelle mit Hilfe von MAXVALUE offenzuhalten. Kommt es dann zu einem Wechsel der jeweiligen Verwaltungsperiode – beispielsweise Ende eines Quartals – muss die letzte Partition so aufgeteilt werden, dass die Daten des zurückliegenden Quartals eine eigene Partition erhalten. Gleichermaßen kann es bei der Änderung von Verwaltungsperioden – monatsweise statt quartalsweise – notwendig werden, vorhandene Partition aufzuteilen. Dies wird über die SPLIT PARTITION-Klausel des Befehls ALTER TABLE erreicht.
Im folgenden Beispiel wird die Partition verkaufq3 der Tabelle verkauf in die Partitionen q3a und q3b aufgeteilt. Als Grenzwert wird der 1. August 2000 festgelegt. ALTER TABLE verkauf SPLIT PARTITION verkaufq3 AT (2000,08,01) INTO (PARTITION q3a TABLESPACE ts1, PARTITION q3b TABLESPACE ts2);
Lokale Indizes werden auch hier automatisch in ihrer Partitionierung angepasst. Da durch die Split-Operation die Daten der angegebenen Partition jedoch neu aufgeteilt werden müssen, werden die betroffenen Partitionen der lokalen Indizes ebenso unbenutzbar wie alle Partitionen aller globalen Indizes der betreffenden Tabelle. Auch in diesem Beispiel ist daher eine Reorganisation angesagt. Der folgende Befehl übernimmt dies für alle lokalen Indizes. Globale Indizes dagegen müssen explizit über den ALTER INDEX-Befehl reorganisiert werden. ALTER table verkauf MODIFY PARTITION q3b REBUILD UNUSABLE LOCAL INDEXES;
Ebenso sollten die Partitionsstatistiken neu generiert werden; die globalen Statistiken dürften sich durch die Aufteilung dagegen kaum ändern. Weitere Verwaltungsoperationen Neben den oben besprochenen Operationen im Kontext versionierter Daten stehen dem Administrator eine Reihe weiterer Möglichkeiten offen, Partitionen zu modifizieren:
:
Partitionen umorganisieren Mit Hilfe der MOVE PARTITION- oder MOVE SUBPARTITION-Klauseln des ALTER TABLE-Befehls lassen sich Partitionen in anderen Tablespaces unterbringen. Diese Operation baut eine vorhandene Partition neu auf und löscht die alte und ist aus diesem Grunde entsprechend aufwändig. Globale Indizes und zugeordnete Partitionen lokaler Indizes sind hier ebenfalls zu reorganisieren. Wenn es nur darum geht, Standardattribute, wie z.B. die Extent-Größen oder die Anzahl maximaler Extents, anzupassen, wird stattdessen die MODIFY PARTITION-Klausel des ALTER TABLE- oder ALTER INDEX-Befehls verwendet.
Sandini Bib
186
: : :
:
Datenbankdesign
Partitionen umbenennen Sowohl für Partitionen als auch Subpartitionen können die Namen über entsprechende RENAME PARTITION oder RENAME SUBPARTITION-Klauseln des ALTER TABLE oder ALTER INDEX-Befehls verändert werden. Partitionen leeren Sollen Partitionen erhalten, jedoch ihre Daten komplett gelöscht werden, empfiehlt sich die TRUNCATE PARTITION-Klausel des ALTER TABLE-Befehls. Auch hier gilt es, unbrauchbare Indizes anschließend zu reorganisieren. Hash-Partitionen reduzieren Hash-Partitionen können nicht wie Range-Partitionen explizit gelöscht werden. Stattdessen lassen sie sich über die COALESCE-Klausel des ALTER TABLE-Befehls „verschmelzen“, d.h. um jeweils eine Partition reduzieren. Die Reduzierung ist auch in Composite-partitionierten Tabellen zulässig und erfordert eine Reorganisation lokaler und globaler Indizes. Im Gegensatz zur DROP-Klausel werden die Daten der „gelöschten“ Partition hierbei unter den verbleibenden Paritionen neu aufgeteilt. Partitionen zusammenlegen Dort, wo Partitionierungskriterien erweitert werden müssen, lassen sich jeweils zwei aneinander grenzende Range-Partitionen – von Range- oder Compositepartitionierten Tabellen – zusammenlegen. Die Operation wird mit Hilfe der MERGE PARTITIONS-Klausel des ALTER TABLE-Befehls durchgeführt.
Laden von Daten Es existieren verschiedene Strategien, um Daten in eine partitionierte Umgebung zu übertragen. Export und Import Über die Werkzeuge Export und Import können sowohl ganze
– partitionierte und nicht partitionierte – Tabellen als auch einzelne Partitionen oder Subpartitionen gesichert oder geladen werden. Auf diese Weise ist es möglich, Daten zwischen
: :
zwei partitionierten Tabellen sowie von einer nicht partitionierten zu einer partitionierten Tabelle und umgekehrt
zu übertragen. Das folgende Syntaxbeispiel zeigt den Export der Partition verkaufq1 der Tabelle verkauf. Die Angabe einer Partition oder Subpartition
erfolgt nach dem Doppelpunkt: EXP scott/tiger@ORA817 TABLES=verkauf:verkaufq1 FILE=verkauf.dmp
Schemagrenzen spielen bei diesen Werkzeugen keine Rolle. Eventuelle Namensdifferenzen können mit Hilfe von Synonymen oder Views überwunden werden31:
31. Mit dieser Technik ist es natürlich nicht möglich, Statistiken und Indizes durch den Import aufbauen zu lassen.
Sandini Bib
Partitionierung
187
1. Tabelle aa wird exportiert und soll in Partition p1 der partitionierten Zieltabelle bb des Schemas xx importiert werden. 2. Im Schema xx wird die View aa erzeugt mit der Spezifikation AS SELECT * FROM bb PARTITION (p1);
3. Der Import wird durchgeführt und füllt bb über die View aa. SQL*Loader Über das Werkzeug SQL*Loader können sowohl ganze partitionierte
Tabellen als auch einzelne Partitionen geladen werden. Die Kontrolldatei des Loaders unterstützt hierzu über die into table-Klausel und das Schlüsselwort PARTITION die explizite Angabe einer Partition. Das Laden partitionierter Tabellen kann in allen drei verfügbaren Modi durchgeführt werden:
: : :
Über den konventionellen „Pfad“ – d.h. Array-Insert-Operationen über den Buffer-Cache der SGA Über den (sehr effizienten) direkten „Pfad“ – d.h. durch den externen Aufbau der Oracle-Blöcke, die dann „direkt“ in die Datendateien geschrieben werden Über den parallelen direkten „Pfad“, der die Operationen des direkten „Pfades“ parallelisiert.
Direct-Load-Insert Nur in Ausnahmefällen sollte daran gedacht werden, Massendaten über einfache Insert-Befehle in partitionierte Tabellen zu laden. Eine weitaus bessere Methode ist der Direct-Load-Insert. Hierbei werden die Daten außerhalb des Buffer-Caches formatiert und – jenseits der Hochwassermarke des betreffenden Segments – direkt in die Datendateien geschrieben. Direct-Load Inserts können sowohl für partitionierte wie für nicht partitionierte Tabellen eingesetzt werden und sind seriell sowie parallel ausführbar. Die Operationen können zusätzlich dadurch beschleunigt werden, dass für sie keine Redolog-Einträge geschrieben werden. Werden partitionierte Tabellen parallel geladen, bearbeitet jeder Query-Slave-Prozess eine oder mehrere Partitionen; beim Commit schließlich wird durch den Koordinator-Prozess die Hochwassermarke angepasst und die Daten werden damit für andere Benutzer sichtbar. Das parallele Laden innerhalb einer Partition ist demnach mit dem Direct-Load-Insert nicht möglich.
Das serielle Direct-Load-Insert wird über einen einfachen Hint, wie im folgenden Beispiel dargestellt, erreicht: INSERT /*+ APPEND */ INTO verkauf2 SELECT * FROM verkauf;
Diese Transaktion ist mit COMMIT oder ROLLBACK zu beenden, bevor ein weiterer lesender Zugriff auf dieses Objekt erfolgt32. Das parallele Laden wird über die folgenden Kommandos realisiert: ALTER SESSION ENABLE PARALLEL DML; INSERT /*+ PARALLEL(verkauf2, 4) */ INTO verkauf2 SELECT /*+ PARALLEL(verkauf, 4) */ * FROM verkauf; 32. Ansonsten zeigt sich der eindeutige ORA-12838.
Sandini Bib
188
Datenbankdesign
Durch das Umschalten der Session ist der Append-Hint überflüssig. Die Parallelisierung wird über den Parallel-Hint beigesteuert. Alternativ kann der parallelisierte Zugriff auf die Tabelle auch über das entsprechende Attribut erreicht werden. In diesem Fall sind die Hints überflüssig: ALTER TABLE verkauf PARALLEL(4);
Auch in diesem Beispiel kann das Objekt erst nach dem Beenden der Transaktion gelesen werden.
3.4.7
Alternativen zur Partionierung
Die in den vorangehenden Abschnitten besprochene Partitionierung basiert auf der Partitioning Option, die ab der Version 8.0 verfügbar ist und eine transparente Partitionierung von Tabellen und Indizes ermöglicht. Für Anwender, die entweder keine Version 8.x zur Verfügung oder die Partitioning Option nicht lizensiert haben, besteht die Möglichkeit, die Partitionierung über Views nachzustellen. Die Partitionierung über Views funktioniert nach dem folgenden Prinzip:
: : :
:
Entsprechende Basistabellen gleicher Struktur werden erzeugt. Über CHECK-Constraints werden die Partitionierungskriterien auf den relevanten Spalten definiert. Eine union-all-View wird angelegt, welche die Einzeltabellen logisch zusammenfasst und den globalen Zugriff ermöglicht. Über den Systemparameter partition_view_enabled33 (= true) wird der Optimizer angewiesen, beim Zugriff über partitionierte Views nicht benötigte Basistabellen nicht zu lesen (partition pruning).
Dabei sind jedoch die folgenden Einschränkungen gegenüber der transparenten Partitionierung zu beachten:
: : : :
Die Partitionierung kann nur nach dem Range-Prinzip durchgeführt werden. Die Hash- oder Composite-Partitionierung ist nicht möglich. Die Indizes werden stets im Kontext der Basistabelle definiert und simulieren so eine Equipartitionierung. Global partitionierte Indizes sind überhaupt nicht möglich. Schreibende Zugriffe müssen stets direkt auf den entsprechenden Basistabellen durchgeführt werden. Falls mit der Version 8 oder höher gearbeitet wird, besteht jedoch die Möglichkeit, mit Hilfe von – umfangreichen – Instead-of-Triggern DML-Befehle entsprechend umzuformen. Administrative Eingriffe, wie das Zusammenlegen, Löschen oder Aufsplitten von Partitionen, erfordern größtenteils eine umfangreiche Programmlogik und sind nicht oder nur in Ausnahmefällen über einfache DDL-Befehle möglich. In jedem Fall muss die partitionierte View gelöscht und neu aufgebaut werden.
33. Der Parameter ist dynamisch, d.h., er kann in der init.ora-Datei oder über den ALTER SESSION-Befehl gesetzt werden.
Sandini Bib
Constraints
:
189
Globale Statistiken sind nicht verfügbar und müssen vom Optimizer „simuliert“ werden.
Aus den oben genannten Gründen ist eine Partitionierung über Views in der Regel nicht empfehlenswert.
3.5
Constraints
Constraints sind eine – sehr nützliche – grundlegende Eigenschaft des relationalen Datenbankmodells. Sie dienen dazu, gewisse Basiseigenschaften von Datenbankobjekten zu garantieren, z.B. deren Eindeutigkeit. Besonders hervorzuheben ist dabei die Tatsache, dass Constraints nicht programmiert werden müssen. Sie sind deklarativ, d.h., sie werden lediglich im Kontext einer Tabelle definiert. Die Verknüpfung von Daten mit Hilfe von Primärschlüssel-Fremdschlüssel-Relationen ist die Basis für ein gut funktionierendes relationales Datenmodell. Dieses basiert auf der grundlegenden Eigenschaft, zusammenhängende Daten nicht durch feste Zeiger (Pointer) darzustellen, sondern durch die Übereinstimmung von Schlüsselfeldern. Dies wiederum ermöglicht die immense Flexibilität bei der Ablage, Indizierung und Abfrage von Daten in relationalen Strukturen. Rein technisch ist es zwar möglich, ein relationales Datenmodell ohne Constraints zu implementieren; allerdings müssen dann sämtliche Prüfungen von den Anwendungen durchgeführt werden. Andererseits führen gute Constraint-Definitionen i.A. dazu, dass Anwendungen einen robusten und datentechnisch sauberen Eindruck machen – weil sie den Ballast der Constraint-Prüfungen zumindest teilweise ablegen und sich auf eine funktionierende Datenbasis verlassen können. Einige grundlegende Constraint-Definitionen sollten daher mit der Entwicklung des Datenmodells einhergehen.
3.5.1
Constraint-Definitionen
Allgemeines Im Folgenden werden die unterschiedlichen Constraints vorgestellt. Jeder definierte Constraint hat einen Namen. Dieser wird entweder vom Benutzer vorgegeben oder beim Anlegen des Constraints vom Datenbanksystem automatisch vergeben. Die automatisch vergebenen Namen lauten i.A. sys_cnnnnn. Es wird unbedingt empfohlen, eigene Namen für Constraints zu vergeben, da andernfalls Administrationsprozeduren schwer lesbar sind. Die Definition eines Constraints erfolgt entweder bei der Deklaration der Spalte (Spalten-Constraint) oder als Zusatz zu den Spaltendefinitionen (Tabellen-Constraint). Constraints, die sich lediglich auf eine einzige Spalte beziehen, kann man mit beiden Varianten deklarieren; die Definition als Spalten-Constraint ist oft übersichtlicher. Bezieht sich ein Constraint auf mehrere Spalten, so ist er ausschließlich als Tabellen-Constraint definierbar.
Sandini Bib
190
Datenbankdesign
Bei der Implementierung eines Datenmodells empfiehlt es sich, Tabellen- und Constraint-Definitionen in verschiedenen Scripts zu trennen. Bei einer späteren Migration hat man dann alle Werkzeuge zur Verfügung, um die erforderlichen Schritte (in etwa: Tabellen aufsetzen, Daten laden, Constraints anlegen) gezielt und kontrolliert auszuführen. NOT NULL Der einfachste Constraint-Typ ist der NOT NULL-Constraint. Hiermit wird für eine Spalte definiert, dass sie auf jeden Fall mit einem Wert besetzt sein muss bzw. sie keine NULL-Werte enthalten darf. Hiermit können bereits sehr wirkungsvolle Regeln im Datenbankschema implementiert werden, z.B. dass ein Auftrag immer eine Kundennummer enthalten muss. CREATE TABLE auftraege (... kundennr NUMBER(10,0) CONSTRAINT auft_kdnr_nn NOT NULL, ...)
Mit den Spalten einer Tabelle, die als NOT NULL deklariert sind, wird ein minimaler Rumpfdatensatz beschrieben, der als sinnvoll angesehen wird. UNIQUE Mit dem UNIQUE-Constraint wird definiert, dass die Werte einer Spalte bzw. einer Kombination von Spalten eindeutig sein müssen. Man spricht auch von einem eindeutigen Schlüssel oder UNIQUE KEY. Eine Tabelle kann beliebig viele eindeutige Schlüssel haben. Zur Abgrenzung von den weiter unten definierten Primärschlüsseln spricht man bei eindeutigen Schlüsseln auch von Sekundärschlüsseln. ALTER TABLE produkte ( CONSTRAINT produkte_prodid_uq UNIQUE (prodid) );
Die Überprüfung der Eindeutigkeit erfolgt mit Hilfe eines Indexes. Falls die Spalte bzw. die Spaltenkombination noch nicht indiziert ist, wird beim Anlegen des Constraints automatisch ein eindeutiger Index angelegt, dessen Name identisch zum Namen des Constraints ist. Mit Hilfe der USING INDEX-Klausel können für den Index Speicheroptionen angegeben werden: ALTER TABLE produkte ( CONSTRAINT produkte_prodid_uq UNIQUE (prodid) USING INDEX TABLESPACE appl_idx STORAGE (INITIAL 5M NEXT 5M PCTINCREASE 0) ); Listing 3.41: UNIQUE-Constraint
Sandini Bib
Constraints
191
Falls die Spaltenkombination bereits indiziert ist, benutzt Oracle den bestehenden Index zur Constraint-Prüfung. Der bestehende Index muss nicht unbedingt eindeutig sein! Auch mit einem nicht eindeutigen Index kann die Prüfung auf Eindeutigkeit performant erfolgen. Primary Key Jede Tabelle kann maximal einen Primärschlüssel oder PRIMARY KEY enthalten. Der Primärschlüssel bezeichnet wie ein eindeutiger Schlüssel eine Spalte oder eine Spaltenkombination, die – einzeln oder in Kombination – für die Tabelle eindeutig sein muss. Beim Primärschlüssel ist – im Gegensatz zum eindeutigen Schlüssel – implizit eine NOT NULL-Definition für alle Schlüsselspalten eingeschlossen. CREATE INDEX auftragspositionen_pk_nonunique ON auftragspositionen (auftr_id, pos_id) TABLESPACE appl_idx STORAGE (INITIAL 10M next 10M PCTINCREASE 0); ALTER TABLE auftragspositionen ( CONSTRAINT auftragspositionen_pk PRIMARY KEY (auftr_id, pos_id) ); Listing 3.42: Primary Key-Constraint
Zur Primärschlüsselprüfung werden wie bei den eindeutigen Schlüsseln Indizes verwendet. Foreign Key Mit Fremdschlüsseln oder Foreign Key-Constraints werden relationale Tabellen miteinander verknüpft. Foreign Key-Constraints können eine oder mehrere Spalten enthalten. Sie müssen sich stets auf den Primaärschlüssel oder ein beliebiges Unique-Constraint einer übergeordneten „Master“-Tabelle beziehen. Es versteht sich, das die Anzahl und die Datentypen der referenzierten wie referenzierenden Spalten zusammenpassen müssen. Im nachfolgenden Beispiel wird der Primärschlüssel der Tabelle auftraege über ein Foreign Key-Constraint der Tabelle auftragspositionen referenziert: ALTER TABLE auftragspositionen ( CONSTRAINT auftragspositionen_ref_auftraege FOREIGN KEY (auftr_id) REFERENCES auftraege ); Listing 3.43: Foreign Key-Constraint
Soll statt des Primärschlüssels ein Unique-Constraint referenziert werden, so ist dies explizit in Form der betreffenden Spalten anzugeben: ALTER TABLE auftragspositionen ( ... REFERENCES auftraege (
Sandini Bib
192
Datenbankdesign
Bei DML-Operationen auf der Fremdschlüsseltabelle wird nun immer überprüft, ob der als Fremdschlüssel vorhandene Wert bzw. die Wertekombination als Primärschlüssel vorhanden ist. Im Beispiel heißt das, dass nur dann auftragspositionen angelegt werden können, wenn ein passender auftrag (mit gleicher auftr_id) vorhanden ist. Nicht ganz konform zu den allgemeinen Erwartungen ist die Prüfung mehrspaltiger Fremdschlüssel in Verbindung mit NULL-Werten. Sobald eine Spalte eines mehrspaltigen Fremdschlüssels einen NULL-Wert enthält, werden die restlichen Spalten nicht mehr geprüft. Hierzu ein Beispiel: Tabelle a hat zwei Primärschlüsselspalten a1 und a2, die die folgenden Werte besitzen: SQL> SELECT * FROM a; a1 a2 ---------- ---------1 2 3 4
Tabelle b besitzt ebenfalls die Spalten a1 und a2, die als Fremdschlüssel zu A definiert werden; dabei sind NULL-Werte erlaubt: SQL> INSERT INTO b VALUES (1, 2) 1 row created. SQL> INSERT INTO b VALUES (3, 4) 1 row created. SQL> INSERT INTO b VALUES (1, 4) * ERROR at line 1: ORA-02291: integrity constraint (SYSTEM.SYS_C001782) violated - parent key not found SQL> INSERT INTO b VALUES (NULL, NULL) 1 row created. SQL> INSERT INTO b VALUES (NULL, 4) 1 row created. SQL> INSERT INTO b VALUES (77, NULL) 1 row created. SQL> COMMIT; Commit complete. Listing 3.44: Constraint-Verletzung
Sandini Bib
Constraints
193
Beim Durchlesen der o.a. Zeilen sind die Reaktionen des Datenbanksystems größtenteils o.k.; lediglich die Wertekombination (77, NULL) findet oft nicht auf Anhieb das Einverständnis des Betrachters. Allerdings verdeutlicht die angegebene Regel folgendes: Sobald ein Wert eines mehrspaltigen Fremdschlüssels NULL ist, wird der Rest – hier die 77 – nicht mehr geprüft. Um ein solches Verhalten zu vermeiden, genügt es oft, alle Fremdschlüsselspalten mit einem NOT NULL-Constraint zu belegen. Sollen aber auch NULL-Werte erlaubt sein, hilft zumindest manchmal ein CHECK-Constraint, der nur Wertekombinationen zulässt, bei denen alle Spalten entweder NULL oder NOT NULL sind (s.a. Beispiel weiter unten). Ein definierter Fremdschlüssel schränkt die DML-Möglichkeiten sowohl auf der Primär- als auch auf der Fremdschlüsselseite ein. Es können nur solche Befehle verarbeitet werden, deren Ergebnis im Sinne der Fremdschlüsselbedingung korrekt ist. D.h., dass nach einem Update auf auftr_id in der Fremdschlüsseltabelle die neue auftr_id auch als Primärschlüssel vorkommen muss. Das Gleiche gilt für UPDATEund DELETE-Befehle auf der Primärschlüsseltabelle. Optional zum Standardverhalten kann für Delete-Befehle auf der Primärschlüsseltabelle eingestellt werden, dass die zugehörigen Fremdschlüsseldatensätze gelöscht werden sollen (ON DELETE CASCADE) bzw. dass die Fremdschlüssel auf NULL gesetzt werden sollen (ON DELETE SET NULL). Sollen z.B. beim Löschen eines Auftrags alle Auftragspositionen mitgelöscht werden, so lautet obige Fremdschlüsseldefinition wie folgt: ALTER TABLE auftragspositionen ( CONSTRAINT auftragspositionen_ref_auftraege FOREIGN KEY (auftr_id) REFERENCES auftraege ON DELETE CASCADE ); Listing 3.45: ON DELETE CASCADE
Gibt man keine ON DELETE-Klausel an, so werden Löschbefehle für Primärschlüsseldatensätze, die noch referenziert werden, nicht zugelassen. Eine manuelle Löschroutine muss also immer bei den Fremdschlüsseldatensätzen anfangen und sich zu den Primärschlüsseln „hocharbeiten“. Ein spezieller Diskussionspunkt beim DML-Verhalten ist das Sperrkonzept für Fremdschlüssel. Die wichtigste Information ist, dass praktisch keine Probleme mit Sperren auftreten, wenn Fremdschlüssel indiziert werden. Das passiert hier – im Gegensatz zu den eindeutigen und Primärschlüsseln – nicht automatisch. Falls kein solcher Index existiert, wird bei einem UPDATE oder DELETE auf der Primärschlüsselseite ein Share Lock auf Tabellenebene bei der Fremdschlüsselseite benötigt. Oracle9i agiert hier ein wenig besser als Oracle8i, da der Share Lock nur für eine kurze Zeit pro betroffenem Datensatz gehalten wird; Oracle8i hält den Share Lock bis zum Transaktionsende. Allerdings ist auch das Oracle9i-Verhalten problematisch, da der Share Lock auf Tabellenebene inkompatibel zum Exclusive Lock auf Datensatzebene ist. Falls eine große Transaktionslast auf der Fremdschlüsseltabelle existiert, kann es zu längeren Wartezeiten wegen inkompatibler Sperren kommen.
Sandini Bib
194
Datenbankdesign
Tipp 1. Grundsätzlich sollten Fremdschlüssel indiziert werden. Hiermit werden Probleme mit Sperren verhindert. 2. Ein weiterer empfohlener Grundsatz, der in der Anwendung berücksichtigt werden muss, ist, keine UPDATE-Befehle auf eindeutige und Primärschlüsselspalten zuzulassen. Auch bei DDL-Operationen gibt es Einschränkungen für Tabellen mit Fremdschlüsselverknüpfungen: Tabellen, deren eindeutige bzw. Primärschlüssel von anderen Tabellen referenziert werden, können mit dem gängigen DROP TABLE-Befehl nicht gelöscht werden. Mit der Option CASCADE CONSTRAINTS kann der Befehl durchgeführt werden, die referenzierenden Constraints werden dabei entfernt. Die Option ist auch beim DROP TABLESPACE-Befehl vorhanden. DROP TABLE auftraege CASCADE CONSTRAINTS; -- oder: DROP TABLESPACE appl_data -- Lösche den ganzen Tablespace INCLUDING CONTENTS -- sowie alles, was drin ist CASCADE CONSTRAINTS; -- und alle Fremdschlüssel-Constraints Listing 3.46: Löschen von Tabellen mit CASCADE-Constraints
CHECK Mit dem CHECK-Constraint ist es möglich, frei formulierbare Bedingungen an einen Datensatz zu knüpfen. Die CHECK-Klausel ähnelt der WHERE-Klausel eines SELECTBefehls, ist aber einigen Einschränkungen unterworfen. Der Gebrauch von Unterabfragen, Sequenzen und einigen SQL-Funktionen ist untersagt. Die CHECK-Klausel bezieht sich also immer auf genau einen Datensatz. Ein gutes Beispiel ist ein CHECK-Constraint, der dafür sorgt, dass zwei Spalten entweder beide NULL oder beide NOT NULL sind (s.a. die Diskussion mehrspaltiger Fremdschlüssel weiter oben): ALTER TABLE b ADD CONSTRAINT b_chk_fk CHECK (((a1 IS NULL) AND (a2 IS NULL)) OR ((a1 IS NOT NULL) AND (a2 IS NOT NULL))); Listing 3.47: CHECK-Constraint
Mit den genannten Bedingungen können CHECK-Constraints immer sofort „am Datensatz“ überprüft werden. Sie können daher nicht zu Laufzeitproblemen durch weitere Scans in der Datenbank o.Ä. führen.
Sandini Bib
Constraints
3.5.2
195
Aus- und Einschalten von Constraints
Für administrative Operationen, Migrationen und andere Aktivitäten ist es oft notwendig, Constraints temporär zu deaktivieren. Wenn z.B. bei einer Reorganisation die Tabellen neu geladen werden, sind die Fremdschlüssel meist ungültig. Beim Beladen fehlen oft auch die zur Prüfung benötigten Indizes. Das Ausschalten eines Constraints wird mit dem Befehl ALTER TABLE x DISABLE CONSTRAINT x_constraint;
erreicht; das Einschalten entsprechend mit dem Schlüsselwort ENABLE. Zusätzlich kann die Option VALIDATE bzw. NOVALIDATE angegeben werden, wobei VALIDATE beim ENABLE und NOVALIDATE beim DISABLE als Standard genommen wird. ENABLE VALIDATE bedeutet, dass beim Einschalten des Constraints auch vorhandene Datensätze geprüft werden; ENABLE NOVALIDATE prüft den Constraint lediglich für nachfolgende DML-Operationen. Für die Prüfung von eindeutigen bzw. Primärschlüsseln werden Indizes verwendet. Ist die Spaltenkombination beim Einschalten nicht indiziert, so wird ein neuer eindeutiger Index erzeugt; ein vorher angelegter Index kann aber auch zur Überprüfung der Eindeutigkeit herangezogen werden. Der Vorteil eines nicht eindeutigen Indexes ist, dass dieser beim DISABLE des Constraints nicht entfernt wird. Falls beim Einschalten eines Constraints ein Index angelegt werden muss, können mit der USING INDEX-Klausel hierfür Speicheroptionen (STORAGE-Klausel, TABLESPACE, FREELISTS usw.) angegeben werden. Noch flexibler ist die USING INDEXKlausel bei Oracle9i, da hier auch ein bestehender Index mit USING INDEX <schema>.
oder ein komplettes CREATE INDEX-Kommando mit USING INDEX (CREATE INDEX ...)
angegeben werden kann. In Oracle9i ist außerdem der Übergang von ENABLE NOVALIDATE zu ENABLE VALIDATE als nicht blockierende Operation implementiert, die auch parallel ausgeführt werden kann. Zum Einschalten von umfangreichen eindeutigen Schlüsseln oder Primärschlüsseln kann idealerweise folgende Kommandofolge verwendet werden: CREATE INDEX <schema>. ... / ALTER TABLE <schema>. ENABLE NOVALIDATE CONSTRAINT / ALTER TABLE <schema>. ENABLE VALIDATE
Sandini Bib
196
Datenbankdesign
CONSTRAINT USING INDEX <schema>. / Listing 3.48: NOVALIDATE-Constraint
Ein Spezialfall ist das DISABLE VALIDATE-Kommando. Dies wird benötigt, wenn Daten mittels EXCHANGE PARTITION in eine Range-partitionierte Tabelle eingefügt werden sollen. Ein vorhandener eindeutiger oder Primärschlüssel wird dann ausgeschaltet, ein eindeutiger Index entfernt, aber die Eigenschaft VALID wird behalten. Beim DISABLE eines eindeutigen oder Primärschlüssel-Constraints kann bei Oracle9i mit der KEEP INDEX- bzw. DROP INDEX-Option über das Verbleiben des Indexes, der zur Prüfung des Constraints genutzt wurde, entschieden werden. Eine elementare Eigenschaft des VALIDATE-Prozesses ist die Möglichkeit, Constraint-Verletzungen in einer Ausnahmetabelle zu speichern. Der Hintergrund hierzu ist, dass man beim Fehlschlagen des VALIDATE nicht nur auf eine Fehlermeldung wie ORA-02437: cannot validate (<schema>.) - primary key violated
angewiesen sein sollte – man weiß dann immer noch nicht, welche Datensätze die Bedingung verletzt haben. Die Speicherung in der Ausnahmetabelle erfolgt mit der EXCEPTIONS INTO-Option: ALTER TABLE <schema>. ENABLE VALIDATE CONSTRAINT EXCEPTIONS INTO <exceptions> /
Hierbei bezeichnet <exceptions> eine Tabelle, für die ein Beispiel im Script $ORACLE_HOME/rdbms/admin/utlexcpt.sql
angegeben ist: CREATE TABLE exceptions(row_id ROWID, owner VARCHAR2(30), table_name VARCHAR2 (30), constraint VARCHAR2 (30)); Listing 3.49: Exceptions-Tabelle
Alternativ kann eine beliebige eigene Tabelle verwendet werden; lediglich Spaltennamen und Datentypen müssen identisch zu o.a. Tabelle sein. Nach dem VALIDATE werden alle Datensätze, deren Constraint-Prüfung fehlschlägt, in der Ausnahmetabelle über ihre ROWID identifiziert. Da bei doppelten Schlüsseln für eindeutige oder Primärschlüssel nicht entschieden werden kann, welcher der „falsche“ ist, werden in solchen Fällen alle (mindestens zwei!) betroffenen Datensätze eingetragen.
Sandini Bib
Constraints
197
RELY-/NORELY-Status Mit Hilfe des RELY-Status kann beim ALTER TABLE MODIFY CONSTRAINT bestimmt werden, dass ein Constraint im NOVALIDATE-Modus für eine Query-Rewrite-Aktion herangezogen wird, obwohl das standardmäßig nicht passiert. Diese Eigenschaft ist nicht beim Anlegen des Constraints verfügbar, da sie dann noch keinen Sinn macht. RELY wird bei Materialized Views im Zusammenhang mit ausgeschalteten Constraints benötigt.
3.5.3
Verzögerte Constraint-Prüfung
Die Prüfung der Constraints bei DML-Befehlen erfolgt grundsätzlich auf Befehlsebene. Bei INSERT, UPDATE oder DELETE mehrerer Datensätze wird also geduldet, dass es einen nicht Constraint-konformen Zwischenstatus geben kann. Solange am Ende eines einzelnen Befehls alle Constraints erfüllt werden, läuft der Befehl ohne Fehlermeldung durch. Diese Eigenschaft kann zwar in Ausnahmefällen nützlich sein – oft wird eine Modifikation der Schlüsselfelder bei einer selbstreferenzierenden Tabelle genannt –, praxisnahe Beispiele hierfür sind aber eher selten. Weitaus wichtiger ist die optionale Möglichkeit, die Constraint-Prüfung auf das Ende der Transaktion zu verschieben. Hierzu gibt es weitaus mehr Beispiele, u.a. viele Fälle von Anwendungen, bei denen im Verlauf einer Transaktion zwischenzeitlich ein nicht Constraint-konformer Zustand besteht, am Ende einer Transaktion jedoch alles in Ordnung ist. Diese Situation trifft man oft bei der nachträglichen Einführung von Constraints bei bestehenden Anwendungssystemen. Hierzu gibt es die Möglichkeit, eine verzögerte Constraint-Prüfung am Ende einer Transaktion zu aktivieren. Bei der Definition der Constraints hat man zunächst die Möglichkeit, die verzögerte Prüfung zuzulassen oder nicht (DEFERRABLE/ NOT DEFERRABLE). Weiterhin kann man bestimmen, ob standardmäßig verzögert geprüft wird oder nicht (INITIALLY DEFERRED/INITIALLY IMMEDIATE). Die Umschaltung auf verzögerte bzw. nicht verzögerte Constraint-Prüfung erfolgt mit einem ALTER SESSION-Befehl: ALTER SESSION SET CONSTRAINTS = [ IMMEDIATE | DEFERRED | DEFAULT ]
Hier ein Beispiel, bei dem ein Primärschlüssel-Constraint verzögert geprüft werden kann: SQL> ALTER TABLE t1 ADD CONSTRAINT t1_pk PRIMARY KEY (i) DEFERRABLE INITIALLY IMMEDIATE; Table altered. SQL> INSERT INTO t1 VALUES (1,'a'); ERROR at line 1:
Sandini Bib
198
Datenbankdesign
ORA-00001: unique constraint (DIERK.T1_PK) violated
SQL> ALTER SESSION SET CONSTRAINTS = DEFERRED; Session altered. SQL> INSERT INTO t1 VALUES (1,'a'); 1 row created. SQL> SELECT * FROM t1; I ---------1 2 3 1
C --------------x y z a
SQL> COMMIT; commit * ERROR at line 1: ORA-02091: transaction rolled back ORA-00001: unique constraint (DIERK.T1_PK) violated Listing 3.50: Deferred Constraint Checking
Mit einem ALTER TABLE-Befehl kann später zwischen INITIALLY IMMEDIATE und INITIALLY DEFERRED gewechselt werden; die prinzipielle Eigenschaft DEFERRABLE oder NOT DEFERRABLE kann ausschließlich beim Anlegen des Constraints angegeben werden. Mit der verzögerten Constraint-Prüfung hat man nunmehr für viele Situationen ein wirkungsvolles Werkzeug zur Hand, u.a. auch für die Einführung von Constraints in replizierten Umgebungen. Interessant ist nun die Frage, warum man nicht automatisch dazu übergeht, Constraints verzögert zu prüfen. Dabei sind, wie immer, verschiedene Aspekte abzuwägen:
:
:
Die verzögerte Constraint-Prüfung erfolgt sicher nicht ohne zusätzlichen CPUund Hauptspeicheraufwand. Es sind zwar keine allgemein gültigen Vergleichsfaktoren bekannt; die Alternative der direkten Prüfung in Verbindung mit einer Anwendung, die damit umgehen kann, stellt jedoch sicherlich die schnellere Variante dar. Falls verzögerte Constraint-Prüfungen oft negativ ausgehen, ist auch der Zusatzaufwand für den Datenbankserver nicht zu unterschätzen. Es entstehen
Sandini Bib
Constraints
:
199
Aufwände im Bereich der Rollback- bzw. Undosegmente sowie des Redolog sowohl durch die Transaktion als auch durch das Zurückrollen derselben. Generell ist auch die Aufwärtskompatibilität zu älteren Releases wie Oracle7 erwähnenswert: Ohne verzögerte Constraint-Prüfung verhält sich der Datenbankserver identisch zum alten Release.
3.5.4
Views
Die Views dba_constraints und dba_cons_columns sind zum Monitoring von Constraints vorgesehen. Spaltenname
Bedeutung
owner
Eigentümer des Constraints
constraint_name
Name des Constraints
constraint_type
Constraint-Typ, siehe Tabelle 3.2
table_name
Tabellenname
search_condition
Bedingung für Check-Constraints
r_owner
Eigentümer der referenzierten Tabelle bei Fremdschlüsseln
r_constraint_name
Name des referenzierten Constraints bei Fremdschlüsseln
delete_rule
CASCADE bei ON DELETE CASCADE-Fremdschlüsseln, sonst NO ACTION
status
ENABLED oder DISABLED
defarrable
DEFERRABLE oder NOT DEFERRABLE
deferred
DEFERRED oder IMMEDIATE
validated
VALIDATED oder NOT VALIDATED
generated
GENERATED NAME oder USER NAME
bad
YES bedeutet, dass ein Datum mit einem zweistelligen Jahresformat verwendet wird (und somit zu falschen Ergebnissen führen kann).
rely
RELY oder NORELY
last_change
Datum des letzten ENABLE oder DISABLE
index_owner
Eigentümer des genutzten Indexes
index_name
Name des genutzten Indexes
Tabelle 3.1: Erläuterung der View dba_constraints CONSTRAINT_TYPE
Bedeutung
P
Primärschlüssel
U
Eindeutiger Schlüssel
R
Fremdschlüssel
C
Check-Constraint
Sandini Bib
200
Datenbankdesign
CONSTRAINT_TYPE
Bedeutung
V
View mit Check-Option
O
Read-Only-View
Tabelle 3.2: CONSTRAINT_TYPE Erläuterung Spaltenname
Bedeutung
owner
Eigentümer des Constraints
constraint_name
Name des Constraints
table_name
Tabellenname
column_name
Spaltenname
position
Spaltenposition (wichtig für mehrspaltige Schlüssel)
Tabelle 3.3: Erläuterung der View dba_cons_columns
3.6
Systemobjekte
Als Systemobjekte werden alle nicht benutzerspezifischen Segmente bezeichnet. Hierzu gehören neben dem Data Dictionary die Rollback-Segmente zur Speicherung von Undo-Informationen sowie die Segmente, die für Sortierungen (Temporärsegmente) und Zwischenspeicherungen (Temporäre Tabellen) verwendet werden. Dabei kommt den Temporärtabellen eine Zwitterstellung zu, da sie vom Benutzer erstellt, aber über den Oracle-Kernel verwaltet werden.
3.6.1
Data Dictionary
Wie schon in Kapitel 2 besprochen, verwaltet sich die Datenbank über das Data Dictionary. Genau wie jede Anwendung aus einer Reihe von Objekten besteht, die über Schlüsselwerte in Bezug zueinander stehen, ist auch das Data Dictionary eine Anwendung, die über Schlüssel verwaltet wird. Im Gegensatz zu einer „normalen“ Anwendung wird hierauf jedoch nicht mit DML-Befehlen (DML = Data Manipulation Language, INSERT, UPDATE, DELETE), sondern mit DDL-Befehlen (DDL = Data Definition Language) zugegriffen. Warum dies notwendig ist, zeigt folgendes Beispiel: CREATE TABLE personen ( persnr NUMBER anrede VARCHAR2 vorname VARCHAR2 nachname VARCHAR2 geburtstag DATE ) TABLESPACE demo STORAGE (INITIAL 1M NEXT 1M
NOT NULL, (5), (20), (20),
MAXEXTENTS unlimited PCTINCREASE 0);
Listing 3.51: Erstellen einer Tabelle
Sandini Bib
Systemobjekte
201
Mit diesem Befehl wird eine Tabelle mit dem Namen personen und fünf Spalten im Tablespace demo angelegt. Was als DDL-Befehl CREATE TABLE nur wenige Zeilen benötigt, wird durch den Kernel in 29 (!) Statements aufgeteilt. Was geschieht mit diesem Befehl? Zunächst einmal muss überprüft werden, ob der Anwender, der den Befehl ausführt, die entsprechenden Rechte hat, d.h.: „Darf er ein CREATE-Statement absetzen?“, „Hat er das Recht, im Tablespace demo eine Tabelle anzulegen?“ Dann muss überprüft werden, ob in dem Tablespace ausreichend Platz für ein Extent mit 1 Mbyte Größe vorhanden ist. Außerdem müssen die nicht angegebenen Parameter (z.B. FREELIST, PCTFREE, PCTUSED) aus den Standardvorgaben des Tablespaces gewonnen werden. Wenn diese Abfragen erfolgreich waren, können die entsprechenden Einträge im Data Dictionary vorgenommen werden. Dies sind unter anderem Einträge in tab$ für den Namen der Tabelle und col$ für die Spalten der Tabelle. Die folgende Liste zeigt alle Tabellen des Data Dictionary, in die in diesem Fall Einträge vorgenommen wurden: ccol$, cdef$, col$, con$, fet$, obj$, seg$, tab$, tsq$, uet$
Auffallend ist die Endung $, die anzeigt, dass es sich hierbei um die Tabellen des Data Dictionary handelt, die dem Benutzer sys gehören. Ähnlich wie die Erstellung einer neuen Tabelle über DDL-Befehle versteckt wird, wird auch die Abfrage von Informationen über das externe Data Dictionary erleichtert. Das Beispiel, um die Struktur einer Tabelle anzuzeigen, verdeutlicht dies: SELECT * FROM user_tab_columns; Dieser Befehl greift auf folgende Data Dictionary-Tabellen zu: col$, coltype$, hist_head$, obj$, tab$, user$, yobj$
Es ist also leicht nachzuvollziehen, warum es nicht erlaubt ist, mit DML-Befehlen auf das Data Dictionary zuzugreifen. Die Gefahr einer Inkonsistenz und damit der Korruption der Datenbank ist zu groß! Ebenso sollten die Views, die auf das Data Dictionary zugreifen, nicht manipuliert werden, allerdings ist hier die Gefahr nicht ganz so groß, da diese über das bereits in Kapitel 2 besprochene SQL-Script catalog.sql jederzeit wiederhergestellt werden können.
3.6.2
Rollback-Segmente
Primäre Aufgabe der Rollback-Segmente ist es, den alten Zustand von Datensätzen (Before Images) so lange zu speichern, bis der neue Zustand in der Datenbank festgeschrieben wurde. Dadurch kann sichergestellt werden, dass Befehle entweder vom System (PMON-Prozesss) oder vom Anwender wieder zurückgenommen werden können. Solche Situationen können entstehen, wenn interne Ressourcen aufgebraucht sind, z.B. nicht genug Platz in einem Tablespace vorhanden ist, oder wenn ein Anwender mit dem expliziten Befehl ROLLBACK eine Transaktion rückgängig macht. Für Zugriffe auf das Data Dictionary gibt es hierfür ein spezielles
Sandini Bib
202
Datenbankdesign
Rollback-Segment system im gleichnamigen Tablespace system. Da dieses ausschließlich für Transaktionen im Tablespace system – und damit in der Regel für DDL-Befehle – reserviert ist, benötigt man für eine produktive Datenbank weitere Rollback-Segmente, die dann zyklisch beschrieben werden. Wenn die Instanz mit automatischem Undo-Management arbeitet (Initialisierungsparameter: undo_management = AUTO), werden die notwendigen Segmente vom System in einem speziellen Undo-Tablespace angelegt, ansonsten ist es Aufgabe des Administrators, für eine ausreichende Anzahl und Größe der Rollback-Segmente zu sorgen. Die Verwaltung der Rollback-Segmente erfolgt in jedem Fall in Form von Ringpuffern. Bei der „manuellen“ Verwaltung von Rollback-Segmenten muss jedes Segment aus mindesten zwei Extents bestehen, in der Regel werden aber fünf bis zehn Extents je Rollback-Segment angelegt. Jedes Rollback-Segment kann in diesem Modus ein oder mehrere Transaktionen beherbergen, umgekehrt schreibt jede Transaktion während ihrer Laufzeit jedoch nur in ein Rollback-Segment. Jedes Extent eines Rollback-Segmentes kann ebenfalls ein oder mehrere Transaktionen speichern. Es versteht sich, dass eine Transaktion um so mehr Speicherplatz belegt, je umfangreicher ihre Änderungen ausfallen. Rollback-Segmente sind – wie bereits erwähnt – als logische „Ringe“ aufgebaut sind. Ist ein Extent gefüllt, wird entweder
: :
das nächstfolgende, bereits existierende Extent wiederverwendet, aber nur dann, wenn es keine aktiven Transaktionen mehr enthält oder eine neues Extent angelegt und logisch in den Ring eingefügt.
Es ist keinesfalls möglich, aktive Extents des Rings zu überspringen – etwa wenn das übernächste frei wäre! Auf diese Weise kann es vorkommen, das lang andauerden Transaktionen – unabhängig von ihrer Grösse – Rollback-Segmente „blockieren“ und zu einer stetigen Erweiterung des Ringbuffers führen, solange bis die entsprechende Transaktion per COMMIT abgeschlossen wird! Die automatische Undo-Verwaltung übernimmt auf der anderen Seite nicht nur die Verwaltung von Anzahl und Größe der Rollback-Segmente, sondern kann mit weiteren Raffinessen aufwarten:
: :
: :
Nach Möglichkeit wird nur eine schreibende Transaktion pro Rollback-Segment zugelassen, um Wahrscheinlichkeit von Zugriffkonflikten auf den Transaktionstabellen im Header des Segments zu minimieren. Das Überschreiben von Extents ist nicht nur davon abhängig, ob alle schreibenden Transaktionen abgeschlossen wurden, sondern hängt auch von einer „Freigabezeit“ ab, die über den Systemparameter undo_retention gesteuert wird und festlegt, wie lange „commitete“ Daten für potentielle Leser zur Verfügung gehalten werden sollen. Diese „Freigabezeit“ kann jedoch unterschritten werden, wenn der Platz in der Undo-Tablespace knapp zu werden droht (space pressure). Die Segment-Verwaltung ist darüber hinaus so flexibel, Extents bei Bedarf zwischen den Segmenten auszutauschen. Auf diese Weise kann ein Segment in der Not und um entsprechenden Speicherplatz in der betreffenden Tabelspace zu
Sandini Bib
Systemobjekte
203
sparen, ein Extent eines fremden Rollback-Segmentes „stehlen“, d.h. für sich nutzen. Die Oracle-Datenbank arbeitet nach einem optimistischen Ansatz, der besagt, dass jede Änderung permanent ist. Daher wird mit der Änderung eines oder mehrerer Datensätze eine Kopie des alten Zustandes in ein Rollback-Segment geschrieben und die neue Information wird als permanenter Datensatz gespeichert, obwohl der Anwender noch keinen COMMIT-Befehl ausgeführt hat. Wenn der Anwender mit ROLLBACK die Transaktion rückgängig machen möchte, muss also der neue Zustand wieder mit dem alten (before-image) überschrieben werden. Neben dieser Möglichkeit des Zurückrollens von Transaktionen erlauben die Rollback-Segmente eine Lesekonsistenz von Abfragen. Da für einen gewissen Zeitraum alte und neue Datensätze zur Verfügung stehen können, kann eine Abfrage zeitlich ältere Daten sehen, obwohl diese von einer anderen Transaktion zwischenzeitlich geändert und bereits festgeschrieben wurden. Im Folgenden Beispiel wird durch den Benutzer u1 eine Transaktion ausgeführt, die den Mitarbeitern der Abteilung 50 fünf Prozent mehr Gehalt zuweist. Es handelt sich um ein Unternehmen mit mehr als 100.000 Mitarbeitern, so dass die Änderung ca. 5 Minuten dauert. Eine Minute nach dem Start der Änderung wird aus der Personalabteilung eine Abfrage gestartet, um die Summe aller Gehälter pro Abteilung zu berechnen. Wenn jetzt auf bereits geänderte und nicht geänderte Daten zugegriffen werden würde, würde dies zu einem falschen Ergebnis führen. Durch das Read-Consistency-Modell von Oracle greift die Abfrage automatisch auf das Before-Image der bereits geänderten Datensätze (z.B. MITNR 1) zu, um so zu gewährleisten, dass die Information gelesen wird, wie sie zum Start der Abfrage existierte. U1: UPDATE mitarbeiter SET gehalt = gehalt * 1,05 WHERE abtnr = 50; U2: SELECT abtnr, SUM(gehalt) FROM mitarbeiter GROUP BY abtnr ORDER BY abtnr; Listing 3.52: Read-Consistency-Modell
Sandini Bib
204
Tabelle Mitarbeiter Mitnr Abtnr Gehalt 1 50 5250 … … … 154 50 4200 … … … 7804 50 6300 … … … … … … 19765 50 3150 … … …
Datenbankdesign
Roll back Segment 1
5250
154
4200
7804
6300
19765
3150
Abbildung 3.4: Consistent Read
Im Rahmen der manuellen Administration müssen Rollback-Segmente so dimensioniert werden, dass sie zunächst ihre Hauptaufgabe, die Speicherung der BeforeImages einer Transaktion, aufnehmen können. Werden die Rollback-Segmente zu klein dimensioniert, werden große Transaktionen mit dem Fehler ORA-01650 unable to extend rollback segment ... abgebrochen. Ebenso müssen die Rollback-Segmente für das Read-Consistency-Modell angepasst werden. Es kommt hierbei aber erschwerend hinzu, dass die lesenden Zugriffe für die Rollback-Segmente nicht messbar sind und daher vom System aus ein Before-Image sofort überschrieben werden darf, wenn die Transaktion abgeschlossen ist. Mit der Version 9i steht hierfür eine zusätzliche Option, die undo_retention (im Standardfall 15 Minuten), zur Verfügung. Das ist eine Zeitdauer, bis zu der auf Before-Images für Lesekonsistenz oder sog. Flashback-Queries zugegriffen werden kann. Allerdings gilt auch hier, dass bei unzureichend dimensionierten Undo-Tablespaces das Before-Image überschrieben wird, wenn eine DML-Operation den Platz beansprucht, d.h., eine DML-Operation hat Vorrang vor einer eventuellen Leseoperation auf ältere Datensätze. Das folgende Bild veranschaulicht das Transaktionsmanagement anhand eines Rollback-Segments mit zwei Transaktionen. Die Information der ersten Transaktion T1 kann nach deren Beendigung sofort durch die Transaktion T2 überschrieben werden. Benötigt die Transaktion T2 dann noch weiteren Platz, wird ein zusätzliches Extent in den Ring eingebaut.
Sandini Bib
Systemobjekte
205
E4
E4
E3
E1
E3
Transaktion 1
E2
Transaktion 2
E1
Transaktion 1 Beendet
E2
Transaktion 2
E4 E4 E1
E3 E3
E1
E2 E2
E2N
Transaktion 2 Transaktion 2
Abbildung 3.5: Rollback-Segmente
Fallbeispiel Das im folgenden besprochene Beispiel bezieht sich auf manuelles Undo-Management. Zunächst wird ein normales Tablespace angelegt: CREATE TABLESPACE rbs DATAFILE '/oradata1/SUNDB/rbs01.dbf' SIZE 100M AUTOEXTEND OFF MINIMUM EXTENT 512K DEFAULT STORAGE (INITIAL 512K NEXT 512K MINEXTENTS 10 MAXEXTENTS UNLIMITED); Listing 3.53: Rollback Tablespace-Management für manuelles Rollback
Dann werden fünf Rollback-Segmente RBS0 bis RBS4 angelegt mit je zehn Extents und einer Größe von 512 Kbyte pro Extent. CREATE CREATE CREATE CREATE CREATE
PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC
ROLLBACK ROLLBACK ROLLBACK ROLLBACK ROLLBACK
SEGMENT SEGMENT SEGMENT SEGMENT SEGMENT
rbs0 rbs1 rbs2 rbs3 rbs4
TABLESPACE TABLESPACE TABLESPACE TABLESPACE TABLESPACE
rbs; rbs; rbs; rbs; rbs;
Sandini Bib
206
ALTER ALTER ALTER ALTER ALTER
Datenbankdesign
ROLLBACK ROLLBACK ROLLBACK ROLLBACK ROLLBACK
SEGMENT SEGMENT SEGMENT SEGMENT SEGMENT
rbs0 rbs1 rbs2 rbs3 rbs4
ONLINE; ONLINE; ONLINE; ONLINE; ONLINE;
Listing 3.54: Anlegen von Rollback-Segmenten
Diese fünf Rollback-Segmente werden jetzt zyklisch beschrieben, wobei jeweils die angelegten fünf Mbyte (zehn Extents à 512 Kbyte) ausgenutzt werden. Jetzt wird eine umfangreiche Transaktion gestartet, die wesentlich mehr als die fünf Mbyte an Rollback-Information beansprucht, z.B. ein Ladevorgang. Dafür werden für das entsprechende Segment, in diesem Fall rbs3, zusätzliche Extents angelegt und der Ring wird vergrößert. Im Beispiel ist das Rollback-Tablespace auf 100 Mbyte beschränkt, so dass die größtmögliche Transaktion 80 Mbyte groß werden kann (fünf Rollback-Segmente à 5 Mbyte = 25 Mbyte, d. h., ein Segment kann um 75 Mbyte wachsen). Die Beispieltransaktion belegt also z.B. im Rollback-Segment rbs3 140 Extents à 512 Kbyte = 70 Mbyte. Damit stehen den restlichen Rollback-Segmenten nur noch 5 Mbyte zusätzlich zur Verfügung. D.h., sollte die nächste Transaktion mehr als 10 Mbyte beanspruchen, wird sie fehlschlagen, egal ob die Transaktion in rbs3 schon beendet wurde oder nicht. Um dies zu vermeiden, sollte man für umfangreiche Batch-Operationen ein dediziertes Rollback-Segment verwenden. Mit dem Befehl SET TRANACTION USE ROLLBACK SEGMENT rbs3;
wird einer Transaktion ein Rollback-Segment zugewiesen. Danach kann mit dem Befehl ALTER ROLLBACK SEGMENT rbs3 SHRINK TO 5M;
das entsprechende Rollback-Segment wieder auf die Ursprungsgröße zurückgesetzt werden. Über den Parameter OPTIMAL kann dieser Vorgang, d.h. das Schrumpfen eines Rollback-Segments (shrink), automatisiert werden. Jedem Rollback-Segment sollte also als zusätzliche STORAGE-Klausel der Optimal-Parameter mitgegeben werden. Für das obige Beispiel gilt also: ALTER ALTER ALTER ALTER ALTER
ROLLBACK ROLLBACK ROLLBACK ROLLBACK ROLLBACK
SEGMENT SEGMENT SEGMENT SEGMENT SEGMENT
rbs0 rbs1 rbs2 rbs3 rbs4
STORAGE STORAGE STORAGE STORAGE STORAGE
(OPTIMAL (OPTIMAL (OPTIMAL (OPTIMAL (OPTIMAL
5M); 5M); 5M); 5M); 5M);
Sandini Bib
Systemobjekte
207
Beim Umschalten auf das nächste Extent wird jetzt überprüft, ob die aktuelle Größe des Rollback-Segments größer als die „optimale“ Größe ist und ob die folgenden Extents inaktiv sind, d. h. von keiner Transaktion genutzt werden. Ist dies der Fall, werden die ältesten Extents freigegeben, um somit Platz zu schaffen, aber noch laufende Abfragen wenig zu behindern. Das Rollback-Segment wird so lange verkleinert, bis die durch den Parameter OPTIMAL vorgegebene Größe erreicht ist. Da diese Operation die Performance von Transaktionen beeinträchtigt, sollte in Produktionssystemen darauf geachtet werden, dass das Wachsen und Schrumpfen von Rollback-Segmenten möglichst selten vorkommt. Mit der View v$rollstat kann die maximale Größe des Segments über die hwmsize und die Anzahl von Schrumpfungen über den Wert shrinks beobachtet werden. Anzahl und Größe von Rollback-Segmenten Alle Transaktionen einer Instanz werden automatisch gleichmäßig über die verfügbaren Rollback-Segmente verteilt. Dabei können mehrere Transaktionen auf den gleichen Rollback-Segmenten arbeiten; Daten verschiedener Transaktionen können sogar im gleichen Extent des Rollback-Segments liegen. Eine Transaktion arbeitet aber immer genau mit einem Rollback-Segment. Auf Grund dieser Tatsache muss auch ein Rollback-Segment wachsen können. Jede Transaktion, die RollbackInformationen erzeugt, muss sich in den Kopfbereich eines Rollback-Segments eintragen. Bei einer großen Anzahl parallel laufender Transaktionen können also die Kopfbereiche der Rollback-Segmente zum Engpass werden. OLTP34-Anwendungen haben zumeist die Charakteristik, dass es sich um viele kleine Transaktionen handelt; Batch-Anwendungen erzeugen zumeist große, lang laufende Transaktionen. Die Anzahl der Rollback-Segmente, die in einer Datenbank konfiguriert werden sollten, ist abhängig von der Art und Anzahl von parallel laufenden Transaktionen. Nicht zu vergessen sind aber auch die Anforderungen, die an Rollback-Segmente auf Grund der Lesekonsistenz gestellt werden. Die Einträge in einem Rollback-Segment werden zunächst einmal überflüssig, wenn eine Transaktion mit einem COMMIT-Befehl abgeschlossen worden ist, werden aber eventuell von sehr lange laufenden Abfragen für die Gewährleistung der Lesekonsistenz noch gebraucht. Für OLTP-Anwendungen sollte für je fünf parallel laufende Transaktionen je ein Rollback-Segment zur Verfügung gestellt werden, wobei es sich wegen der Administration nicht empfiehlt, über 60 Rollback-Segmente zu konfigurieren. Diese Rollback-Segmente werden relativ klein dimensioniert sein, da OLTP-Anwendungen sich zumeist auf geringe Datenmengen beziehen. Für Batch-orientierte Anwendungen wird ein Rollback-Segment für ca. 10 bis 15 Transaktionen ausreichend sein, es sollte aber eher groß konfiguriert sein, um Massendaten-Änderungen aufnehmen zu können. Als Einstellung für MINEXTENTS wird fünf bis zehn empfohlen, MAXEXTENTS sollte so groß gewählt werden, dass sich die Rollback-Segmente im Extremfall über den gan34. OLTP = Online Transaktion Processing. Hiermit wird charakterisiert, dass es sich um eine große Anzahl gleichzeitiger Transaktionen handelt, wobei die einzelne Transaktion eher klein ist.
Sandini Bib
208
Datenbankdesign
zen Tablespace ausdehnen können; hier bietet sich UNLIMITED an. INITIAL und NEXT sind gleich groß. Beide Parameter werden so groß eingestellt, dass die größte Transaktion ihre Daten ohne Überschreitung der maximalen Anzahl von Extents unterbringen kann. OPTIMAL muss mindestens auf die Initialgröße des RollbackSegments gesetzt werden und sollte bezugnehmend auf die durchschnittliche Größe der Rollback-Segmente entsprechend angepasst werden. Aktivierung von Rollback-Segmenten Es gibt zwei Arten von Rollback-Segmenten, public und private. Public besagt, dass sich die Instanzen aus einem Pool von Rollback-Segmenten bedienen können. Dabei wird dann Anhand der Initialisierungsparameter transactions und transactions_per_rollback_segment die Anzahl von Rollback-Segmenten je Instanz berechnet. Interessant ist dies im Oracle Parallel Server- bzw. Real Application Cluster-Betrieb, bei der mehr als eine Instanz auf eine Datenbank zugreift. Im Gegensatz dazu werden private Rollback-Segmente über den Initialisierungsparameter rollback_segments aktiviert. Die Namen der zu aktivierenden RollbackSegmente werden hierzu in Klammern und durch Kommata getrennt angegeben. Rollback_Segments = (RBS0, RBS1, RBS2, RBS3, RBS4)
Beim Single-Instance-Betrieb kann auf private Rollback-Segmente verzichtet werden, da hier alle existierenden public Rollback-Segmente der einen Instanz zugewiesen werden. Trotzdem ist es üblich, die Rollback-Segmente – auch im Falle von public – in der Initialisierungsdatei einzutragen. Im Parallel Server-Betrieb wird man in der Regel jedoch private Rollback-Segmente einsetzen, da hier die Kontrolle etwas besser ist als über die oben genannten Initialisierungsparameter. Automatisches Undo-Management In der Version 9i wurde das Undo-Management grundlegend überarbeitet. Es war das erklärte Ziel beim Design dieser Version, das Datenbanksystem automatisch auf die Undo-Anforderungen reagieren zu lassen und auf diese Weise die Arbeit des DBA zu vereinfachen. Das Undo-Management der Version 9i arbeitet nach wie vor mit Rollback-Segmenten. Allerdings besteht die Möglichkeit, die Konfiguration der Rollback-Segmente durch die folgenden „Bausteine“ zu automatisieren:
: : : :
Ein spezieller Undo-Tablespace enthält Rollback-Segmente, die in Anzahl und Größe vom System verwaltet werden; der DBA gibt auf diese Weise nur die Gesamtgröße des Undo-Speicherplatzes vor. Über den Systemparameter undo_management wird die Methode für das UndoManagement eingestellt - auto oder manual Weitere Systemparameter definieren die Regeln des Undo-Managements. Neue bzw. erweiterte v$-Views ermöglichen die Analyse der Undo-Daten.
Diese Bausteine werden im Folgenden detaillierter dargestellt.
Sandini Bib
Systemobjekte
209
Undo-Tablespace Das automatische, d.h. systemgesteuertes Undo-Management erfordert Undo-Tablespaces. Ein Undo-Tablespace kann direkt beim Erstellen der Datenbank angelegt oder nachträglich aufgebaut werden. Um Fehler zu vermeiden, ist es zu empfehlen, den zweiten Weg zu wählen, d.h. den Undo-Tablespace nachträglich anzulegen. Im folgenden Beispiel wird der Undo-Tablespace undotbs mit einer Größe von 100 Mbyte und einer automatischen Erweiterung auf maximal 900 Mbyte aufgebaut: CREATE Undo-Tablespace undotbs DATAFILE '/opt/oracle/oradata/undotbs01.dbf' SIZE 100m AUTOEXTENT ON NEXT 50M MAXSIZE 900M
Undo-Tablespaces sind lokal verwaltete Tablespaces, deren Extent-Größen vom System bestimmt werden (allocation_type = system). Zusätzliche Klauseln, wie die Default STORAGE- oder SEGMENTMANAGEMENT-Klausel sind hierbei nicht zulässig und werden mit einer Fehlermeldung quittiert. CREATE Undo-Tablespace legt nicht nur ein Tablespace vom Typ UNDO (Attribut contents der View dba_tablespaces mit Wert UNDO) an, sondern erzeugt in die-
ser Tablespace auch sofort zehn Rollback-Segmente. Die Namen der Rollback-Segmente lauten _syssmuxx$, wobei xx eine pro Datenbank fortlaufende Nummer darstellt. Undo-Tablespaces können darüber hinaus wie andere Tablespaces auch verwaltet werden: über den Befehl ALTER TABLESPACE lassen sich zusätzliche Dateien anfügen oder die AUTOEXTENT-Klausel anpassen. Das Offline-Schalten gelingt allerdings nur, wenn der betreffende Tablespace sowohl nicht mehr aktiv ist als auch keine offenen Transaktionen mehr enthält. Grundsätzlich können mehrere Undo-Tablespaces pro Datenbank angelegt werden, Oracle arbeitet aber pro Instanz immer nur mit einem aktiven Undo-Tablespace. Das Umschalten zwischen vorhandenen Undo-Tablespaces ist grundsätzlich - auch im laufenden Betrieb – möglich, sofern die avisierte Tablespace nicht bereits von einer anderen Instanz aktiviert wurde. In unserem Beispiel wird der Tablespace mit Namen undotbs02 aktiviert, gleichzeitig sperrt Oracle den alten Undo-Tablespace für neue Transaktionen: ALTER SYSTEM SET UNDO_TABLESPACE = undotbs02
Das Umschalten gelingt auch dann, wenn offene Transaktionen existieren. Alte Transaktionen behalten nach wie vor ihren Undo-Kontext, neue Transaktionen werden einem Rollbacksegment der neu aktivierten Tablespace zugeordnet. Undo-Management konfigurieren Die automatische Konfiguration von RollbackSegmenten wird pauschal über den Systemparameter undo_management geregelt: undo_management = auto
Dieser Parameter ist statisch, d.h., er kann nicht im laufenden Betrieb geändert werden und er muss für alle Instanzen, die eine Datenbank geöffnet haben, identisch gesetzt sein.
Sandini Bib
210
Datenbankdesign
Es versteht sich, dass vor dem Umschalten auf die automatische Undo-Verwaltung ein entsprechender Tablespace angelegt worden sein muss. Der Wert manual schaltet auf die manuelle Konfiguration von Rollback-Segmenten um, die bereits aus älteren Versionen von Oracle bekannt sein dürfte. Weitere Parameter Das automatische Undo-Management bringt einen weiteren
Vorteil mit sich: Der Verbleib von Rollback-Informationen bereits abgeschlossener Transaktionen, muss nun nicht mehr mühsam durch Try-and-error-Methoden ermittelt, sondern kann direkt per Systemparameter eingestellt werden. Im folgenden Beispiel wird festgelegt, dass Rollback-Informationen pro Transaktion nach dem COMMIT für weitere 3600 Sekunden - also eine Stunde - für lesende Transaktionen verfügbar sind: undo_retention = 3600
Der Parameter ist dynamisch, kann also über den Befehl ALTER SYSTEM angepasst werden. Er muss allerdings für alle Instanzen einer Datenbank identisch eingestellt werden. Ein kleiner Wehrmutstropfen: der DBA wird hier nicht von allen konfiguratorischen Überlegungen entlastet. Sollte der aktive Undo-Tablespace nicht genügend Platz für neu startende Transaktionen bereithalten und auch nicht dynamisch erweiterbar sein, werden „commitete“ Rollback-Einträge auch vor dem Ablauf dieser Zeitspanne entfernt! Ein weiterer, dynamischer Systemparameter regelt die Ausgabe von Fehlermeldungen. undo_suppress_errors = true
unterdrückt Fehlermeldungen, wie die unten abgebildete. Er ist vor allem dort sinnvoll, wo Programmteile sich noch des alten Codes aus Zeiten des manuellen Undo-Managements bedienen. set transaction use rollback Segment "_SYSSMU13$" * ERROR at line 1: ORA-30019: Illegal rollback Segment operation in Automatic Undo mode
Des Weiteren besteht die Möglichkeit, Benutzergruppen im Zusammenhang mit Ressourcenplänen maximale Undo-Volumen zuzuteilen. Hierzu ist wie folgt vorzugehen: 1. Entsprechende Benutzergruppen (consumer groups) anlegen oder bereits vorhandene auswählen. 2. Den einzelnen Gruppen Benutzer zuteilen. 3. Ressourcenpläne erstellen oder bereits vorhandene auswählen. 4. Benutzergruppen den Ressourcenplänen zuordnen und im Zuge dieser Zuordnung sogenannte Direktiven festlegen. Die in diesem Zusammenhang wichtige Direktive ist UNDO_POOL. Der Wert wird in Kilobyte festgelegt. 5. Den betreffenden Ressourcenplan aktivieren.
Sandini Bib
Systemobjekte
211
Das Vorgehen ist recht komplex. Das folgende Beispiel zeigt die notwendigen Prozeduraufrufe. Zwar ist der Ressourcenmanager auch über den Oracle Enterprise Manager bedienbar – und dadurch verhältnismäßig komfortabel – doch unterstützt er dort leider noch nicht die Zuweisung von Undo-Quoten (und einige weitere Einstellungen)! BEGIN dbms_resource_manager.clear_pending_area(); dbms_resource_manager.create_pending_area(); dbms_resource_manager.create_consumer_group(consumer_group => 'POOL_GROUP', comment => 'zum Testen'); dbms_resource_manager.submit_pending_area(); dbms_resource_manager.grant_switch_consumer_group('BENUTZER','POOL_GROUP',false); END; BEGIN dbms_resource_manager.clear_pending_area(); dbms_resource_manager.create_pending_area(); dbms_resource_manager.create_plan('POOL_PLAN', ' '); dbms_resource_manager.create_plan_directive( plan => 'POOL_PLAN', group_or_subplan => 'OTHER_GROUPS', comment => ' ', cpu_p1 => 10, cpu_p2 => 0, cpu_p3 => 0, cpu_p4 => 0, cpu_p5 => 0, cpu_p6 => 0, cpu_p7 => 0, cpu_p8 => 0, parallel_degree_limit_p1 => 1000000, undo_pool => 700 ); dbms_resource_manager.create_plan_directive( plan => 'POOL_PLAN', group_or_subplan => 'POOL_GROUP', comment => ' ', cpu_p1 => 70, cpu_p2 => 0, cpu_p3 => 0, cpu_p4 => 0, cpu_p5 => 0, cpu_p6 => 0, cpu_p7 => 0, cpu_p8 => 0, parallel_degree_limit_p1 => 1000000, undo_pool => 300 ); dbms_resource_manager.create_plan_directive( plan => 'POOL_PLAN', group_or_subplan => 'SYS_GROUP', comment => ' ', cpu_p1 => 20, cpu_p2 => 0, cpu_p3 => 0, cpu_p4 => 0, cpu_p5 => 0, cpu_p6 => 0, cpu_p7 => 0, cpu_p8 => 0, parallel_degree_limit_p1 => 1000000, undo_pool => 500 ); dbms_resource_manager.submit_pending_area(); END;
Sandini Bib
212
Datenbankdesign
-- Aktivieren des Planes ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'POOL_PLAN'; Listing 3.55: Resource Manager
Ist der Plan mit den eingestellten Direktiven aktiviert worden, erhält der erste Benutzer der Gruppe, die den Maximalwert überschreitet eine Fehlermeldung. Der Befehl wird entsprechend zurückgerollt. INSERT INTO bigemp SELECT * FROM bigemp * ERROR at line 1: ORA-30027: Undo quota violation - failed to get 340 (bytes)
Über die View v$rsrc_plan werden die gerade aktiven Ressourcenpläne ausgegeben. Die View v$rsrc_consumer_group und dort das Attribut current_undo_consumption zeigt das aktuelle Undo-Volumen in KB pro Gruppe. Die eingestellten Quoten werden in der View dba_rsrc_plan_directives gelistet. Data Dictionary Views Die aus den Versionen 7 und 8 bekannten Views sind auch im Kontext des automatischen Undo-Managements noch relevant:
: : :
: : : :
dba_tablespaces listet die Undo-Tablespaces unter CONTENTS=UNDO dba_rollback_segs listet die Rollback-Segmente, ob manuell erstellt oder vom System generiert. Alle generierten Segmente von nicht aktiven Undo-Tablespaces haben konsequenterweise den Status Offline. dba_segments führt die systemgenerierten Rollback-Segmente unter dem Segmenttyp TYPE2 UNDO. v$rollstat und v$rollname geben in der gewohnten Weise Auskunft über aktive Rollback-Segmente und ihre Statistiken. v$transaction erlaubt die Zuordnung von Transaktionen zu Rollback-Segmen-
ten Die View dba_undo_extents ist neu hinzugekommen. Sie gibt die letzte Commit-Zeit für jedes Extent des Undo-Tablespace aus. Neu hinzugekommen ist auch die View v$undostat, über die Statistiken im Zusammenhang mit Undo-Tablespaces ausgegeben werden können. Die View gruppiert die Undo-Nutzung in Intervallen von jeweils 10 Minuten. Für die Optimierung sind vor allem die folgenden Attribute interessant: undoblks
die Anzahl benutzter Undo-Blöcke
txncount
die Anzahl der Transaktionen
maxconcurrency
die maximale Zahl gleichzeitig operierender Transaktionen
unxpblkrelcny
Freisetzen von Extents, deren RETENTION-Periode noch nicht abgelaufen war, für andere Transaktionen
Sandini Bib
Systemobjekte ssolderrcnt
213
weißt auf Fehler in Zusammenhang mit einer zu hohen UNDO_RETENTION-Periode hin.
Die folgende Abfrage gibt beispielsweise die Anzahl benutzter Undo-Blöcke für den 3. Oktober 2001 aus: SELECT TO_CHAR(begin_time,'dd.mm hh24:mi:ss') begin_time, TO_CHAR(end_time,'dd.mm hh24:mi:ss') end_time,undoblks FROM v$undostat WHERE begin_time >= TO_DATE('03.11.01', 'dd.mm.yy') AND end_time <= TO_DATE('03.11.01', 'dd.mm.yy') / Listing 3.56: v$undostat
3.6.3
Temporär-Segmente
Temporär-Segmente werden automatisch durch einen Oracle Serverprozess aufgebaut, wenn einer der folgenden Befehle durchgeführt wird und der dadurch notwendige Sortiervorgang mehr Speicher benötigt, als dem Benutzer durch den Initialisierungs-Parameter sort_area_size zugewiesen wurde. CREATE INDEX SELECT ... ORDER BY SELECT DISTINCT ... SELECT … GROUP BY SELECT … UNION SELECT … INTERSECT SELECT … MINUS Listing 3.57: Sortierbefehle
Sobald der Befehl beendet wurde, werden die Temporär-Segmente durch den SMON-Prozess wieder freigegeben. Sollte dies nicht erwünscht sein, z.B. für die Speicherung von Zwischenergebnissen, können so genannte Temporärtabellen aufgebaut werden, die dann die Information für die Dauer einer Transaktion oder einer Session zwischenspeichern. Jedem Benutzer wird ein Tablespace für die Generierung von Temporärsegmenten zugewiesen. Bis zur Version 8i wird einem Benutzer durch den Befehl ALTER USER DEMO TEMPORARY TABLESPACE TEMP;
ein Tablespace für Sortierungen zugewiesen. Wird dieser Befehl vergessen – was in der Praxis nicht selten vorkommt –, werden die Temporär-Segmente des Benutzers
Sandini Bib
214
Datenbankdesign
im System-Tablespace (!) angelegt. Dabei ist es unerheblich, ob der Benutzer entsprechende Quoten auf dem Tablespace hat oder nicht, da die Segmente vom System aufgebaut werden. Ab der Version 9i kann allen Benutzern gemeinsam ein Default Temporary Tablespace zugewiesen werden. Dadurch entfällt die explizite Angabe eines Tablespaces. Es muss nur beachtet werden, dass dieser Tablespace nicht mehr gelöscht werden darf, es sei denn, es wurde vorher ein neuer „Default Temporary Tablespace“ angelegt. CREATE DEFAULT TEMPORARY TABLESPACE temp TEMPFILE '/oradata1/SUNDB/temp01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M MINIMUM EXTENT 1M; Listing 3.58: Temporary Tablespace
Die Größe und maximal mögliche Anzahl von Extents kann dabei durch die Default-Storages des entsprechenden Tablespaces vorgegeben werden. Besser ist es jedoch, wenn man direkt ein „Temporary Tablespace“ als Locally-Managed-Tablespace erstellt. Dadurch entfällt die Notwendigkeit, Extents vorzudefinieren. Bei Locally-Managed-Tablespaces empfiehlt sich dann die Verwendung der UNIFORMKlausel, die automatisch alle Extents gleich verwaltet. Folgendes sollte bei der Auswahl der Storage-Klauseln des Temporär-Tablespaces beachtet werden:
: : : :
Das Tablespace sollte mindestens 1,5 mal so groß wie der größte Index sein. Die Größe eines Extents sollte ein Vielfaches der sort_area_size sein. Alle Extents sollten die gleiche Größe oder ein Vielfaches haben. MAXEXTENTS sollte auf UNLIMITED gesetzt werden.
Es sollte also darauf geachtet werden, dass bei Änderungen der sort_area_size als Initialisierungsparameter u.U. auch die Storage-Klauseln der Temporär-Tablespaces angepasst werden müssen. Da es sich hierbei um Default-Storages handelt, kann eine Änderung im laufenden Betrieb ohne Probleme durchgeführt werden und gilt ab dann für alle neuen Sortierungen. ALTER TABLESPACE Temp DEFAULT STORAGE (INITIAL 1M NEXT 1M PCTINCREASE 0 MAXEXTENTS UNLIMITED);
Sandini Bib
Tablespaces und Datendateien
3.7
215
Tablespaces und Datendateien
Alle Daten werden in der Oracle-Datenbank in Tablespaces verwaltet, die auf der physikalischen Ebene durch Datendateien (datafiles) repräsentiert werden. Durch diese Unterscheidung zwischen logischer Architektur und physikalischer Speicherung ist es möglich, auf unterschiedlichen Plattformen (MS-Windows, Unix, OpenVMS, MVS, etc.) den gleichen Aufbau der Datenbank zu gewährleisten. Das folgende Bild macht den Zusammenhang zwischen physikalischen Platten, Datendateien und Tablespaces deutlich.
Abbildung 3.6: Tablespaces und Datafiles
Planung Für die Planung einer Oracle-Datenbank stellt sich zunächst die Frage, wie man die Daten auf einzelne Tablespaces bzw. Datendateien verteilt. Dabei spielen unterschiedliche Gesichtspunkte eine Rolle:
: : : :
Performance Wie kann der Zugriff über mehrere I/O-Kanäle optimiert werden, wie kann man Fragmentierungen vermeiden? Verfügbarkeit Wie kann im Fall eines Media-Fehlers möglichst ohne Transaktionsverlust wieder aufgesetzt werden? Backup-Recovery Wie kann die Granularität eines notwendigen Backups oder Recoverys möglichst klein gehalten werden? Administration Welche Möglichkeiten gibt es, die Administration von umfangreichen Anwendungen transparent zu machen und notwendige Reorganisationen zu vereinfachen?
Sandini Bib
216
:
Datenbankdesign
Anwendungsgruppierung Wie kann man Anwendungen gruppieren, um sie einfacher verwalten oder um den Anwendern Ressourcen in Rechnung stellen zu können.
Sicher gibt es je nach Unternehmen noch weitere Fragestellungen, die in ein Layout der Tablespaces einfließen müssen. Aber man kann schon erkennen, dass die unterschiedlichen Anforderungen sich teilweise ausschließen bzw. aus Sicht der heute üblichen Hardware schwer zu implementieren sind. Geht man z.B. von heute üblichen Festplattenkonfigurationen aus (Festplattenkapazitäten von mehr als 100 Gbyte sind keine Seltenheit), so muss man sich fragen, wie man zum Beispiel die Verfügbarkeitsanforderung bei einer Datenbankgröße von weniger als 10 Gbyte erfüllen kann. Für viele Unternehmen sind deshalb Raid-5- oder Raid-S-Systeme (HP/UX auch Autoraid) das Maß aller Dinge bezüglich ihrer Verfügbarkeit. Bei großen Datenbanken mit mehreren 100 Gbyte Datenvolumen verwendet man logische Devices, bei denen die physikalischen Platten mittels Raid 0 und 1 zunächst einmal gespiegelt (Raid 1) und dann über mehrere Controller in Stücken à 64 Kbyte oder 128 Kbyte „gestriped“ (Raid 0) werden. Dadurch ist ein Optimum an Verfügbarkeit und IOVerteilung (je nach Anzahl der Controller und Platten) möglich. Die Frage, die sich dabei stellt, ist: Braucht man in solchen Fällen dann überhaupt noch mehrere Tablespaces? Die Antwort ist: „Ja“! Zum einen muss das Data Dictionary geschützt werden, um ein unkontrolliertes Wachstum und damit einen eventuellen Absturz der Datenbank zu vermeiden. Daher gehören keine, wie auch immer gearteten Benutzerdaten, in diesen Tablespace! Des Weiteren stellt auch ein Raid-5- oder Raid-1-System keine Garantie für hohe Verfügbarkeit dar Der Fehler in einem Controller kann z.B. dazu führen, dass Teile des Systems korrumpiert werden. Die Punkte 3 und 4 in der obigen Aufzählung sind auch bei solchen Systemen nicht zu vernachlässigen; der DBA wird es ihnen danken! Folgende Tablespaces sollten deshalb bei jeder Datenbank zusätzlich zur Tablespace system angelegt werden: 1. Temporär-Tablespace 2. Rollback-Tablespace 3. Tablespace für Werkzeuge wie den Oracle Enterprise Manager 4. Mindestens je ein Tablespace für die Daten einer Anwendung 5. Mindestens je ein Tablespace für die Indizes einer Anwendung 6. Eventuell ein Tablespace für Tests und Benutzerdaten 7. Eventuell ein- oder mehrere Tablespaces für ungewöhnlich große Objekte Je nach Datenbank können zusätzlichen Tablespaces notwendig sein, z.B. beim Einsatz von Partitionen.
Sandini Bib
Tablespaces und Datendateien
3.7.1
217
Erstellen eines Tablespaces
Mit dem folgenden Befehl wird ein Tablespace für die Anwendung Kundenverwaltung angelegt. Die Werte beziehen sich auf eine Unix-Installation, d.h., die Angabe der Klausel DATAFILE muss je nach Betriebssystem angepasst werden. CREATE TABLESPACE kunden_daten DATAFILE ’/oradata2/O817/kunden_daten01.dbf’ SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M MINIMUM EXTENT 64k BLOCKSIZE 8K LOGGING DEFAULT STORAGE (INITIAL 64k NEXT 64k PCTINCREASE 1 MAXEXTENTS UNLIMITED FREELISTS 5) PERMANENT EXTENT MANAGEMENT DICTIONARY; Listing 3.59: CREATE TABLESPACE-Kommando
Die Klauseln im Einzelnen: TABLESPACE
Um ein Tablespace anzulegen, sollte man sich zunächst überlegen, welche Aufgabe es zu erfüllen hat, d.h., ob es der Speicherung von Tabellen und Indizes, der Verwaltung von Temporär-Segmenten oder dem Undo-Management dient. Es bietet sich an, dem Tablespace einen Namen zu geben, mit dem er eindeutig seiner Bestimmung zugeordnet werden kann, also z.B. lager_daten, um zu zeigen, dass es sich hierbei um die Daten der Anwendung LAGERVERWALTUNG handelt. Dazu würde noch ein Tablespace lager_index mit den zugehörigen Indizes gehören. Die Länge des Namens ist auf 30 Zeichen begrenzt. Wie bei allen Oracle Data Dictionary-Einträgen wird standardmäßig nicht zwischen Groß- und Kleinschreibung unterschieden. Soll der Tablespace-Name explizit aus Kleinbuchstaben bestehen, muss der Name mit doppelten Hochkommata angegeben werden. Es ist allerdings davon abzuraten, dies zu tun, genauso wie die Verwendung von Umlauten oder Sonderzeichen vermieden werden sollte, da dies bei einigen Werkzeugen zu Problemen führen kann. DATAFILE
Der Name der zugehörigen Datendatei sollte den Namen des Tablespaces beinhalten. Zusätzlich können die Datendateien eines Tablespaces durchnummeriert werden, und sie erhalten eine Endung, die sie auf der Ebene des Betriebssystems als zur Datenbank gehörende Datei kennzeichnet. Dies ist in den meisten Fällen die Endung .dbf, allerdings ist auch die Endung .ora gebräuchlich. Da Oracle mit den Oracle Managed Files entsprechende Vorschläge macht, werden diese im Folgenden verwendet. D.h., die Endung .dbf steht für eine Datendatei, die Endung .tmp für eine Datei eines Temporary-Tablespaces.
Sandini Bib
218
Datenbankdesign
Oracle Managed Files Mit den Initialisierungsparametern db_create_file_dest und db_create_online_ log_dest_ ist es ab der Version 9i möglich, Standardverzeichnisse für die Erstellung von Datendateien und Redolog-Dateien vorzugeben, als Größe wird dabei Standardmäßig 100 Mbyte sowohl für Datendateien als auch Redolog-Dateien gewählt. Zusammen mit der in Oracle9 standardmäßigen Nutzung von Locally Managed Files ergibt sich damit eine erhebliche Vereinfachung bei der Erstellung von Tablespaces bzw. Redolog-Dateien. Im folgenden Beispiel wird veranschaulicht, wie ein Tablespace ohne Angabe von Lage und Größe der Datendateien angelegt werden kann. Der erste Befehl kann natürlich entfallen, wenn db_create_file_dest als Initialisierungsparameter gesetzt ist. ALTER SYSTEM SET DB_CREATE_FILE_DEST = ’/oradata2/SUNDB’; CREATE TABLESPACE demo_daten DATAFILE AUTOEXTEND ON NEXT 10M MAXSIZE 500M; Listing 3.60: Oracle Managed Files
Auf die Angabe DATAFILE AUTOEXTEND sollte, wie oben erwähnt, nicht verzichtet werden. Dieser Befehl legt in diesem Beispiel ein Tablespace demo_daten mit der Datendatei /oradata2/SUNDB/ora_demo_dat_xpbryn4v.dbf an. Zu beachten ist, dass der Name des Tablespaces in der Datendatei auf acht Zeichen beschränkt wird, um ausreichend Platz für Pre- und Postfix zu behalten. Der Name der Datei besteht dabei aus drei Teilen, die durch _ getrennt werden sowie einem durch . getrennten Postfix. 1. Prefix o1_mf 2. bei Tablespaces max. acht Stellen als Name des entsprechenden Tablespaces (hier: demo) bei Redolog-Dateien die Nummer der entsprechenden Gruppe bei Kontrolldateien fehlt dieser Teil acht Stellen als eindeutige Identifizierung 3. Postfix zur Kennzeichnung der Art der Datei: dbf = Datendatei log = Redolog-Datei ctl = Kontrolldatei tmp = Temporär-Datei SIZE
Sandini Bib
Tablespaces und Datendateien
219
Mit einer initialen Größe (SIZE) wird Platz auf der Festplatte bzw. dem Filesystem allokiert. Da Oracle den Bereich sofort in Oracle-Blöcke einteilt, kann das Erstellen eines Tablespaces durchaus mehrere Minuten betragen. Bei der Verwendung von Oracle Managed Files wird eine Standardgröße von 100 Mbyte angenommen, die jedoch jederzeit geändert werden kann. Es gibt je nach Betriebssystem maximale Größen von Dateien, allerdings liegt diese bei den neueren 64-Bit- und auch einigen 32-Bit-Betriebssystemen bei mehr als 2 Gbyte bis hin zu 256 Gbyte. AUTOEXTEND
Mit der Option AUTOEXTEND ON kann zusätzlich eine Erweiterung der Datendatei erfolgen. In diesem Falle wird, wenn der Platz in der Datendatei nicht mehr ausreicht, diese Datei um den Faktor NEXT vergrößert wird bis zu einer maximalen Größe von MAXSIZE. Wird der Parameter NEXT nicht angegeben, wird die Datei jeweils um einem Datenbankblock vergrößert! Dies kann zu erheblichen Performance-Einbußen führen, so dass anzuraten ist, den Parameter NEXT nicht zu klein zu wählen (10 Mbyte oder größer) und die Initialgröße von vornherein ausreichend zu dimensionieren. Sollten Sie mehrere Datendateien in einem Filesystem anlegen, müssen Sie darauf achten, dass jede mit AUTOEXTEND angelegte Datei unter Umständen Platz allokiert, den sie eigentlich für eine andere Datei vorgesehen hatten. Daher empfiehlt es sich, die maximale Größe der Datei mit dem Parameter MAXSIZE zu beschränken. Standardmäßig wird dieser Wert auf unlimited gesetzt, so dass jede Datei beliebig viel Platz allokieren kann. Auch an diesen Parametern sieht man, wie wichtig die Aufteilung von Anwendungen auf unterschiedliche Tablespaces ist, da es nur so möglich ist, bestimmte Anwendungen auf ihren Plattenplatz hin zu limitieren. BLOCKSIZE
Mit dieser Klausel ist es möglich, einen Tablespace mit einer anderen Blockgröße als der Standardgröße anzulegen. Damit kann zum Beispiel für die Abspeicherung von Binärdaten in BLOB-Feldern ein spezieller Tablespace erstellt werden, der den Anforderungen dieser Felder entgegenkommt und somit eine Verkettung von Blöcken vermeidet oder zumindest minimiert. Außerdem können hierdurch die transportablen Tablespaces besser unterstützt werden, da jetzt in jeder Zieldatenbank ein Tablespace mit identischer Blockgröße aufgebaut werden kann. Um eine derartige Blockgröße nutzen zu können, müssen der zugehörige Initialisierungsparameter db_nk_cache_size und der Parameter db_cache_size gesetzt sein, damit im Buffer-Cache entsprechende Ressourcen zur Verfügung stehen. Es versteht sich daher von selbst, dass nur die Größen als BLOCKSIZE erlaubt sind, für die es einen entsprechenden Initialisierungsparameter gibt. Dies sind: 2 Kbyte, 4 Kbyte, 8 Kbyte, 16 Kbyte und 32 Kbyte. LOGGING
Die Klausel LOGGING steht an dieser Stelle für das Standardverhalten der Objekte. Logging besagt, dass wie üblich alle DML-Operationen mitprotokolliert werden. Alternativ kann durch ein NOLOGGING erreicht werden, dass umfangreiche DML-
Sandini Bib
220
Datenbankdesign
Operationen z.B. durch ein INSERT AS SELECT oder den Oracle Loader nicht mitprotokolliert werden. Das bedeutet, falls ein Media-Fehler auftritt, können die geladenen Daten nicht wiederhergestellt werden und die zugehörige Data Dictionary Information (z.B. Extent-Verwaltung) wird als logisch korrupt gekennzeichnet. Oftmals wird diese Klausel mit der Option PERMANENT bzw. TEMPORARY verwechselt. Dabei handelt es sich jedoch um die Möglichkeit, Daten in einem Tablespace zu speichern, so dass diese Option außer bei Temporary-Tablespaces immer auf PERMANENT eingestellt wird. MINIMUM EXTENT
Die Option MINIMUM EXTENT erlaubt es, die Größe der Extents eines Objektes in Vielfachen dieses Parameters festzulegen. Dadurch wird eine Fragmentierung im Wesentlichen verhindert und die Notwendigkeit von Reorganisationen ganzer Tablespaces minimiert. DEFAULT STORAGE
Die DEFAULT STORAGE-Angabe schließlich erlaubt es, das Standardverhalten beim Erstellen von Objekten vorzudefinieren. Im Gegensatz zu MINIMUM EXTENT sind dies jedoch nur Beispielwerte, die jederzeit übersteuert werden können. Für die Definition von neuen Objekten können diese Werte zwar hilfreich sein, sie verleiten aber zu einer gewissen Sorglosigkeit, was dazu führen kann, das Objekte ohne STORAGEKlausel angelegt werden, und man sich später wundert, warum eine Tabelle plötzlich mehrere hundert Extents hat. Besser ist es sicherlich, den Objekten bei der Definition eigene STORAGE-Parameter mitzugeben. Einen Spezialfall stellt der Parameter PCTINCREASE dar. Da hierdurch ein unkontrolliertes Wachstum von Objekten erfolgen kann – die Standardgröße in einer Oracle-Datenbank ist 50, d.h., jedes Extent wird um 50 Prozent größer als das vorherige –, sollte dieser Parameter eigentlich auf 0 gesetzt werden. Für einen Tablespace bedeutet dies aber, dass der System-Monitor (SMON) kein COALESCE EXTENTS ausführt, d.h. keine Zusammenführung von freien Extents vornimmt. Daher ist es sinnvoll, den Parameter für das Tablespace auf 1 zu setzen, für die Objekte sollte er jedoch immer auf 0 gesetzt sein. Segment-Space-Management Die Verwaltung der freien Blöcke für ein Segment geschah bislang ausschließlich durch sog. Freilisten, d.h. verkettete Listen, die alle freien Blöcke diesseits der High Water Mark enthalten. Diese Listen werden schubweise beim Allokieren eines Extents gefüllt und die INSERT-Operationen holen sich dann den nächsten freien Block aus dieser Liste. Wird eine bestimmte Marke (PCTFREE) in einem Block überschritten, dann wird dieser von der FREELISTS gelöscht. Wird durch Änderungsoder Löschoperationen eine zweite Marke (PCTUSED) in einem Block unterschritten, dann wird der entsprechende Block wieder in die FREELISTS eingetragen. Bei großer Transaktionslast, speziell mit INSERT- und DELETE-Operationen, kann eine solche Freiliste zu einem Engpass führen. Dadurch kommt es zu Wartezuständen bei der Verarbeitung, die in der Vergangenheit nur durch mehrere Freilisten ausgeglichen werden konnten. Die Änderung des Parameters FREELIST GROUPS kann jedoch nur durch eine Reorganisation der gesamten Tabelle erfolgen wohin-
Sandini Bib
Tablespaces und Datendateien
221
gegen FREELISTS seit Neuestem auch durch einen ALTER TABLE-Befehl angepasst werden kann. Mit Version 9i und der Verwendung von Locally Managed Tablespaces kann durch die Klausel SEGMENT SPACE MANAGEMENT AUTO auf eine Verwaltung über FREELISTS verzichtet werden. Bei dieser Methode (ASSM = AUTOMATIC SEGMENT SPACE MANAGEMENT genannt) wird über eine Bitstruktur der freie Platz in den Blöcken verwaltet. Die Bitstruktur ist je nach Segmenttyp (Daten, Index, LOB) unterschiedlich, hat aber generell folgende Struktur:
:
: : : : : : : :
Das erste Bit zeigt an, ob der Block als voll markiert wurde; dies geschieht, wenn der Wert PCTFREE überschritten wurde. 1 = voll
Das zweite und drittes Bit zeigen den Füllgrad des Blockes an (nur Datensegmente). 00 = freier Platz größer 75 Prozent 01 = freier Platz größer 50 Prozent 10 = freier Platz größer 25 Prozent 11 = freier Platz kleiner 25 Prozent
Das letzte Bit zeigt an, ob der Block formatiert wurde. 1 = formatiert
Das zweite und dritte Bit ersetzen zusätzlich den Parameter PCTUSED, d.h., ein Block wird wieder mit Sätzen gefüllt, wenn der Platz unter die PCTFREE-Marke gesunken ist. Bei Indizes entfällt der Füllgrad der Blöcke, da es hier nur entscheidend ist, ob ein Block formatiert oder voll ist. Die Verwaltung des freien Platzes für ein Segment erfolgt jetzt in bis zu drei Stufen. Die erste Stufe bilden Bitmapped-Blöcke, die an den Segment-Header gebunden sind, eine Zwischenstufe von Bitmapped-Blöcken wird für große Tabellen verwendet. Die eigentliche Verwaltung in den Blöcken erfolgt dann in der dritten Stufe. Hier werden je Bitmapped-Block mehrere freie Blöcke verwaltet. Bei INSERT-Operationen wird jetzt vom Segment-Header aus geprüft, ob in einem Block noch genügend Platz vorhanden ist. Ist dies der Fall, wird der Datensatz eingefügt, und wenn ein Schwellenwert (25 %, 50 %, 75 %) überschritten wurde, wird die entsprechende Bitstruktur angepasst. Wenn kein freier Block mehr zur Verfügung steht, werden neue Blöcke formatiert (je nach Verfahren mindestens 16 Blöcke) bzw. ein neues Extent wird allokiert. Wenn viele INSERT-Operationen (z.B. Parallel INSERT) ausgeführt werden, wird die Formatierung der Blöcke auf mehrere Prozesse über einen Hash-Algorithmus verteilt. Dadurch kann es vorkommen, dass bestimmte Blöcke, obwohl sie unterhalb der High Water Mark liegen, nicht formatiert werden. Dies ist ein Nachteil dieser Freiplatzverwaltung, da u.U. Platz verschwendet wird (natürlich werden die Blöcke bei einer nächsten Formatierung mitbenutzt). Der Vorteil des Verfahrens ist aber die geringe Latch-Contention (Sperren auf der Freelist eines Segmentes) und schnellere Vergabe von freiem Platz.
Sandini Bib
222
Datenbankdesign
Die Verwendung von Automatic Segment Space Management ist also in solchen Systemen interessant, in denen eine große Anzahl von Benutzern oder Batch-Prozessen viele INSERT-Operationen gleichzeitig durchführen.
3.7.2
Dictionary Managed Tablespaces
Im Standardfall werden im Data Dictionary alle Informationen zu Datenbankobjekten gespeichert, dazu zählt auch die Verwaltung der Tablespaces. Das bedeutet, dass eine Erweiterung von Tabellen oder Indizes um neue Extents oder die Freigabe von Extents mit dem Befehl TRUNCATE zusätzliche rekursive Operationen im Kontext des Data Dictionary durchführen. Die entsprechenden Änderungen in der Extent-Verwaltung erzeugt damit zusätzliche Rollback- und Redolog-Information. Aus diesem Grund kann die Data Dictionary-Verwaltung bei umfangreichen Operationen wie zum Beispiel dem Laden großer Tabellen oder der Erstellung von Indizes zu einem Performance-Engpass führen. Mit Oracle Version 7.3 konnte das Temporär-Tablespace aus dieser Verwaltung herausgetrennt werden, wodurch sich Sortierungen und auch die generelle Verwaltung beschleunigen ließen. Mit der Version 8.1 wird dieser Schritt durch die Einführung von Locally Managed Tablespaces konsequent weitergeführt, um mit der Version 9 dann die Möglichkeit zu schaffen, Tablespaces auf unterschiedliche Anforderungen (freie Definition der Oracle-Blockgröße pro Tablespace) anzupassen.
3.7.3
Locally Managed Tablespaces
Bei dieser Methode verwaltet der Tablespace seine Extents über eine lokale Bitmapstruktur in jeder zugehörigen Datendatei. Dadurch wird die Extent-Allokierung beschleunigt und die hierfür üblichen rekursiven Operationen entfallen. Durch den Bitstatus muss keine Rollback-Information erzeugt werden. Darüber hinaus wird die Verwaltung der Extents vereinfacht, so dass ein Coalesce von freien Extents entfallen kann. Bei der Angabe der Größe von Extents für Objekte gibt es jetzt nur noch zwei Alternativen: UNIFORM legt eine einheitliche Größe für alle Extents fest, AUTOALLOCATE (Standard) kalkuliert die Größe der Extents. Dabei werden die Extents wie folgt angelegt.
: : : : :
64 Kbyte für die ersten 16 Extents 1 Mbyte ab dem 17. Extent 8 Mbyte ab dem 80. Extent 64 Mbyte ab dem 200. Extent Dabei werden, wenn das Objekt direkt mit einer Größe von mehr als einem Mbyte angelegt wird, sofort Extents mit 256 Blöcken angelegt, die Extents mit 1.024 Blöcken werden aber in jedem Fall erst nach dem 50. Extent genutzt. Das nachfolgende Beispiel zeigt die Erstellung eines Locally Managed Tablespace mit einheitlicher Extent-Grösse:
Sandini Bib
Tablespaces und Datendateien
223
CREATE TABLESPACE local_user DATAFILE ‘/oradata2/O817/local_user01.dbf’ size 100M AUTOEXTEND ON NEXT 10M MAXSIZE 300M EXTENT MANAGEMENT LOCAL UNIFORM SIZE 2M; Listing 3.61: Locally Managed Tablespace
3.7.4
Temporary Tablespace
Seit der Version 7 ist es möglich, ein Tablespace ausschließlich für die Zwischenspeicherung von Sortierungen aufzubauen. Dadurch kann während der Laufzeit für jede Instanz ein allgemeiner Sortierbereich aufgebaut werden. Das aufwendige Anlegen und Löschen individueller Sort-Segmente und die mit diesen Operationen einhergehenden Verwaltungsinformationen des Data Dictionary können auf diese Weise eingespart werden. Dennoch werden hierbei Redolog-Informationen geschrieben und der Tablespace ist aus diesem Grund beim Backup zu sichern. Durch den mit Version 8.1 eingeführten Befehl CREATE TEMPORARY TABLESPACE ist es jetzt möglich, die gesamte Verwaltung dieser Tablespaces aus dem Data Dictionary herauszunehmen. Da Dateien dieser Art in einem separaten Bereich in der Kontrolldatei gespeichert werden, „sieht“ ein Checkpoint oder ein Backup über den Recovery-Manager diese Tablespaces nicht. Somit ist auch ein Restore nach einem Fehler nicht notwendig – man erstellt den Tablespace einfach neu. CREATE TEMPORARY TABLESPACE temp TEMPFILE ‘/oradata2/O817/temp01.dbf’ size 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M EXTENT MANAGEMENT LOCAL UNIFORM 10M; Listing 3.62: Temporary Tablespace
Mit diesem Befehl wird ein Tablespace mit Namen temp erstellt und durch die Angabe EXTENT MANAGEMENT LOCAL als Locally Managed Tablespace verwaltet. Die Angabe von DEFAULT STORAGE-Klauseln kann bei einem Temporary Tablespace nicht angegeben werden. Es werden immer Extents mit gleicher Größe (Standard 1Mbyte) angelegt. Die Angabe EXTENT MANAGEMENT LOCAL kann entfallen, da es zurzeit keine andere Möglichkeit gibt.
3.7.5
Read-Only-Tablespace
Für spezielle Operationen kann es sinnvoll sein, ein Tablespace als Read-Only zu spezifizieren, so dass nur lesend auf die Daten zugegriffen werden kann, DML-Operationen aber nicht mehr möglich sind. Ab der Version 8.1 kann ein Tablespace auch dann in den Read-Only-Modus gebracht werden, wenn noch offene Transaktionen vorliegen. Diese offenen Transaktionen werden normal beendet, neue schreibende Transaktionen jedoch nicht mehr zugelassen. Wichtig: Es ist trotz des Read-Only-Modus möglich, in dem Tablespace Objekte zu löschen!
Sandini Bib
224
Datenbankdesign
Eingesetzt werden Read-Only-Tablespaces bei der Benutzung von CD-ROM-Laufwerken z.B. für Bilddateien und bei der Historisierung von Daten, die nicht mehr geändert werden dürfen. Der wesentliche Unterschied zu Read-Write-Tablespaces besteht darin, dass der Header der zugehörigen Datendateien eingefroren wird, wodurch die Notwendigkeit eines Backups entfällt. Das Schreiben eines Checkpoints wird in diesem Fall ignoriert und dadurch kann ein Recovery auf einen älteren Stand wieder aufsetzen. Die Verwendung von Read-Only-Tablespaces ist nicht ganz ungefährlich, da es bei Migrationen zu Einschränkungen kommen kann. So ist z.B. eine Migration von Version 7 nach Version 8 nur möglich, wenn alle Tablespaces Read-Write gesetzt sind, was bei einigen Unternehmen zu großen Schwierigkeiten führte, da die Datendateien auf CD-Rom gespeichert waren. Beim Übergang von Oracle Version 8 nach Version 9 sind solche Probleme zwar nicht bekannt, es ist aber für die Zukunft zu empfehlen, Read-Only-Tablespaces als Locally Managed Tablespaces zu spezifizieren, um die Notwendigkeit von Data Dictionary-Migrationen zu vermeiden.
3.7.6
Offline-Tablespace
Ein bereits angesprochener Aspekt für die Aufteilung von Objekten auf mehrere Tablespaces ist die Verfügbarkeit. In diesem Punkt ist die Verwendung von OfflineTablespaces sinnvoll, da hierdurch erreicht wird, dass mit der Datenbank gearbeitet werden kann, obwohl eine Datendatei defekt ist und dadurch recovered werden muss. Weitere Anwendungen sind administrative Aufgaben, wie das Sichern im konsistenten Modus oder das Verschieben des Tablespaces auf ein anderes Laufwerk. Folgende Optionen können verwendet werden, um ein Tablespace offline zu setzen: ALTER TABLESPACE demo OFFLINE NORMAL
Es wird ein Checkpoint geschrieben, um die Konsistenz des Tablespaces zu gewährleisten, anschließend werden alle Datendateien offline gesetzt. ALTER TABLESPACE demo OFFLINE TEMPORARY
Für die Datendateien die noch geöffnet sind, wird ein Checkpoint geschrieben. Sollten alle zugehörigen Datendateien geöffnet sein, so ist dies mit einem NORMAL gleichgesetzt. Der Befehl wird normalerweise verwendet, wenn ein oder mehrere Datendateien defekt sind und deshalb ein OFFLINE NORMAL nicht mehr funktioniert. ALTER TABLESPACE demo OFFLINE IMMEDIATE
Es wird kein Checkpoint geschrieben, d.h., die Datendateien des Tablespaces sind inkonsistent. Diese Option wird verwendet, wenn es zu einem Fehler in einer Datei kommt, der nur durch ein Media-Recovery behoben werden kann. ALTER TABLESPACE demo OFFLINE FOR RECOVER
Sandini Bib
Tablespaces und Datendateien
225
Der Tablespace eines Recovery-Sets wird für Point-In-Time-Recovery offline gesetzt. Ein Recovery-Set bezieht sich hierbei auf eine Anzahl Tablespaces, die die Konsistenz einer Anwendung gewährleisten können und damit für ein Point-In-TimeRecovery als Einheit betrachtet werden sollen.
3.7.7
Transportable Tablespace
Mit den transportable Tablespaces ist es endlich möglich, einen Tablespace zu klonen, um ihn von einer Datenbank in eine andere zu kopieren. Dadurch entfällt der mühsame Weg, einen Export, Import oder Ähnliches durchzuführen, um z.B. für eine verteilte Datenhaltung eine Initialbefüllung vorzunehmen. Voraussetzung:
: : : : : :
Gleiche db_block_size (Version 8i) Kompatible Hardware des gleichen Herstellers Gleiches Character-Set und National-Character-Set Ein entsprechender Tablespace existiert noch nicht auf dem Zielsystem. Self-Contained, d.h., es dürfen keine Referenzen auf Daten außerhalb des Tablespaces existieren (Ausnahme: Data Dictionary). Dies ist bei Indizes wichtig, da zugehörige Tabellen in anderen Tablespaces liegen könnten. Alle oder keine Partitionen
Um die Voraussetzungen bez. Self-Contained zu überprüfen, kann man die Prozedur transport_set_check des Pakets dbms_tts ausführen und das Ergebnis in der View transport_set_violations ansehen. EXECUTE dbms_tts.transport_set_check(’demo’,TRUE); SELECT * FROM transport_set_violations;
Erstellen eines Transportable Tablespace Sets Im folgenden Beispiel wird der Tablespace demo aus einer Datenbank kopiert und in eine andere eingehängt. Dafür muss das Tablespace in den Read-Only-Modus gesetzt werden, um eine konsistente Sicherung zu ermöglichen. ALTER TABLESPACE demo READ ONLY;
Als Nächstes wird ein Export, der nur die entsprechenden Data Dictionary-Informationen enthält, durchgeführt. EXP TRANSPORT_TABLESPACE=y TABLESPACES=demo TRIGGERS=n CONSTRAINTS=n GRANTS=n FILE=expdat.dmp
Danach können alle notwendigen Tablespaces und die Export-Datei auf das andere System übertragen werden und der lokale Tablespace wird wieder online gesetzt.
Sandini Bib
226
Datenbankdesign
ALTER TABLESPACE demo READ WRITE;
Einfügen eines Transportable Tablespaces auf dem Zielsystem Nach dem Kopieren der Datendateien auf das Zielsystem müssen die neuen Verwaltungsinformationen in das Data Dictionary eingetragen, d.h. der oben durchgeführte Export importiert werden. IMP TRANSPORT_TABLESPACE=y DATAFILES=(’/oradata1/O817/demo01.dbf’)
Dies ist die Minimalkonfiguration, die davon ausgeht, dass ein entsprechender Tablespace bzw. die entsprechende Datendatei auf dem Zielsystem noch nicht existiert. Außerdem muss gewährleistet werden, dass bei Oracle8i-Datenbanken die db_block_size auf Quell- und Zielsystem identisch sind. Bei der Oracle9i entfällt diese Einschränkung, da sie unterschiedliche Blockgrößen für die Tablespaces erlaubt, allerdings muss die entsprechende Blockgröße in der Initialisierungsdatei bzw. über den Befehl ALTER SYSTEM SET DB__CACHE_SIZE = ...
gesetzt werden, wenn es sich nicht um die Standardgröße der Datenbank handelt. Die Verwendung von Oracle Managed Files ist hier ebenfalls hilfreich, da auf diese Weise eine eindeutige Identifikation der Datendateien vorgenommen wird, und es daher zu keinen Kollisionen mit existierenden Dateinamen kommen kann.
3.8
Redolog-Dateien
Redolog-Dateien speichern Redo-Informationen des Oracle-Systems, d.h. Informationen die zum Wiederherstellen (redo) von Blockzuständen notwendig sind – im Gegensatz zu den Rollback-Segmenten, die Informationen zum Zurücksetzen (undo) von Blockzuständen speichern. Sie beinhalten ein Transaktionsprotokoll der Datenbankaktivitäten, das im Fehlerfall für die Wiederherstellung der Datenbankkonsistenz nach einem Absturz der Instanz benötigt wird. Als solches enthalten sie Daten zu allen möglichen Blöcken, Daten-, Index- und auch Rollback-SegmentBlöcken. Notwendig wird das Transaktionsprotokoll durch die asynchrone Arbeitsweise des Database- Writer-Prozesses, der ja nur in Intervallen oder bei Platzmangel Blöcke aus dem Datenbank-Puffer auf die Platte schreibt. Damit wäre also z.B. bei einem Stromausfall ein Transaktionsverlust vorprogrammiert. Tritt bei einer Oracle-Instanz durch einen Stromausfall, einen Hardware- oder Softwarefehler ein Abbruch auf, so werden bei einem Wiederanlauf automatisch, durch den System Monitor-Prozess angestoßen, die Transaktionen aus den benötigten Redolog-Dateien nachgefahren.
3.8.1
Arbeitsweise des LGWR-Prozesses
Der Logwriter-Prozess (LGUR) überwacht in der SGA den Logpuffer. Die Größe dieses Bereichs wird über den Initialisierungsparameter log_buffer konfiguriert. In
Sandini Bib
Redolog-Dateien
227
diesen Puffer werden Informationen zur Transaktion und die Daten nach der Änderung eines Blocks (nicht der komplette Block, sondern nur die geänderten Informationen) geschrieben. Einträge werden durch Änderungen von Datenblöcken, aber auch von Rollback-Segment-Blöcken oder Index-Blöcken erzeugt. Die interne Organisation des Log-Puffers ist eine Ringstruktur. Ziel ist es, Wartezustände auf Grund eines zu 100 Prozent gefüllten Puffers zu vermeiden. Aus diesem Grunde schreibt der Logwriter-Prozess die Inhalte im Puffer in die RedologDateien, wenn entweder ein COMMIT-Befehl eine beliebige Transaktion beendet oder der Ringpuffer zu über einem Drittel gefüllt ist. Werden trotzdem noch Wartezustände beobachtet, die z.B. über v$sysstat unter redo buffer allocation retries messbar sind, so ist der Puffer zu klein konfiguriert und sollte vergrößert werden. Für OLTP-System sind Größen zwischen 128 Kbyte und 256 Kbyte gebräuchlich. Zu einer Oracle-Datenbank gehören mindestens zwei Redolog-Gruppen, mit einer festen Größe eingerichtet sind. Zu einer Gruppe kann es ein oder mehrere Mitglieder in Form von Dateien geben, die dann vom Logwriter-Prozess synchron beschrieben werden, also eine Spiegelung darstellen und daher auf unterschiedlichen Platten liegen sollten. Der LGWR-Prozess schreibt sequenziell in die Datei(en) der ersten Gruppe und wechselt auf die Datei(en) der zweiten Gruppe, wenn die erste Gruppe zu 100 % gefüllt ist. Bei einem Switch der Redolog-Gruppe wird implizit ein Checkpoint ausgelöst. Bei jedem Switch wird die Log-Sequence-Nummer (siehe den Abschnitt 3.8.4) hochgezählt. Ist die zweite Gruppe ihrerseits gefüllt, schaltet der Logwriter-Prozess wieder auf die erste Gruppe zurück und überschreibt deren Inhalt. Sind die Dateien einer Gruppe für den LGWR-Prozess nicht verfügbar, wird die OracleInstanz mit einer Fehlermeldung in der Alert-Datei terminiert. Geht eine aktive Redolog-Gruppe verloren, so bedeutet das Datenverlust.
3.8.2
Konfiguration
Bei der Konfiguration von Redolog-Dateien werden die Bereiche Sicherheit und Performance des Oracle-Systems tangiert. Diese Ziele stehen zunächst im Widerspruch, können aber durch Spiegelung der Redolog-Dateien gut in Einklang gebracht werden. Lage der Redolog-Dateien Für transaktionsorientierte Oracle-Systeme spielt der Durchsatz des Logwriter-Prozesses eine entscheidende Rolle. Bei einem COMMIT-Befehl gilt die Transaktion so lange als nicht beendet, bis alle notwendigen Protokollinformationen in die Redolog-Dateien geschrieben worden sind. Aus Gründen der Performance sollten also die Redolog-Dateien auf schnelle Platten gelegt werden, auf denen ansonsten wenig Aktivitäten stattfinden. Bei extrem hohen Anforderungen sollte auch über Plattenstriping für die Redolog-Dateien nachgedacht werden.
Sandini Bib
228
Datenbankdesign
Die Trennung der Redolog-Dateien von den Datendateien empfiehlt sich ohnehin aus Sicherheitsaspekten, da ja die Redolog-Dateien im Fehlerfall, bei einem PlattenCrash, zur Wiederherstellung der Datendateien benötigt werden. Anzahl der Redolog-Dateien Eine Oracle-Datenbank benötigt mindestens zwei Gruppen von Redolog-Dateien, zwischen denen der Logwriter-Prozess umschalten kann. Mehr als zwei RedologGruppen zu konfigurieren, kann folgende Gründe haben: 1. Wartezustände auf Checkpoints Eine Redolog-Datei kann erst dann überschrieben werden, wenn sämtliche ARCn-Blöcke aus dem Database Buffer Cache in der SGA vom Database Writer in die Datendateien geschrieben worden sind, für deren Wiederherstellung bei Ausfall der Instanz die Informationen aus der jeweiligen Redolog-Datei gebraucht werden. Dieser Konsistenzabgleich ist schon als Checkpoint beschrieben worden. Dauert jetzt bei einem sehr großen Database Buffer Cache und einer hohen Transaktionslast der Checkpoint länger als das Vollschreiben der zweiten Gruppe, ist ein Wartezustand die Folge. In der Alert-Datei der Instanz wird die Meldung Checkpoint not complete protokolliert. Da seit Oracle8 der Checkpoint-Algorithmus die Parallelisierung von Checkpoints erlaubt, kann dieser Wartezustand durch eine höhere Anzahl von Redolog-Gruppen beseitigt werden. 2. Performance des Archivierungsprozesses Der Archivierungsprozess ARCn sichert voll geschriebene Redolog-Dateien auf eine dafür vorgesehene Platte. Ist der ARCn-Prozess damit noch nicht fertig, wenn die Datei wieder überschrieben werden soll, so erzeugt das einen Wartezustand. Das kann gerade bei Transaktions-Spitzen auftreten. Diese Spitzen können über eine größere Anzahl von Redolog-Gruppen abgefangen werden, da es dann entsprechend länger dauert, bis die betreffende Datei wieder überschrieben werden soll und der ARCn-Prozess damit mehr Zeit zur Verfügung hat, diese zu sichern. Auf die Archivierung von Redologdateien wird im nächsten Abschnitt ausführlicher eingegangen. Größe der Redolog-Dateien Die Größe der Redolog-Dateien wird aus Performance-Gründen verändert. Immer, wenn auf die nächste Redolog-Gruppe umgeschaltet wird, weil die Datei der aktuellen Gruppe zu 100 Prozent gefüllt ist, wird ein Checkpoint initiiert. Während des Checkpoints müssen alle modifizierten Blöcke aus der SGA durch den DBWn-Prozess in die Datendateien geschrieben werden, was bei einer großen SGA bei hoher Transaktionslast zu einer hohen Systemlast führen kann. Eine Reduzierung der Checkpoints führt also zu einer Reduzierung der Systemlast. Werden also die Redolog-Dateien vergrößert, verlängert sich die Zeit zwischen zwei Checkpoints und die Systemlast sinkt.
Sandini Bib
Redolog-Dateien
229
Allerdings verlängert sich die Zeit beim Wiederanlauf des Oracle-Systems, da z.B. nach einem Stromausfall mehr Transaktionen seit dem letzten Konsistenzzeitpunkt nachgefahren werden müssen. Jedoch ist diese Zeit in der Praxis zu vernachlässigen. Zu dem Wiederanlauf des Rechners kommen dann pro 50 Mbyte RedologInformation ca. 2-4 Minuten Instance-Recovery-Zeit, was in einem solchen Ausnahmefall in den meisten Fällen nicht kritisch sein sollte. Bei einem Verlust einer Redolog-Gruppe wäre allerdings die Menge der verlorenen Transaktionen größer. Also stellen größere Redolog-Dateien ein höheres Risiko dar. Das Risiko kann aber dadurch minimiert werden, dass man die Redolog-Dateien spiegelt, also Gruppen mit zwei oder drei Mitgliedern (members) konfiguriert, oder die Redolog-Dateien auf gespiegelte Platten legt. Für Systeme mit hoher Transaktionslast sind dann Redolog-Dateien mit einer Größe von 50 Mbyte bis 100 Mbyte anzuraten, bei großen Systemen werden durchaus auch 500 Mbyte RedologDateien konfiguriert. Anhängige Initialisierungsparameter Wenn aus Performance-Gründen die Redolog-Dateien vergrößert werden, muss an die Anpassung folgender Initialisierungsparameter gedacht werden: log_checkpoint_interval
Dieser Parameter bestimmt, nach wie vielen geschriebenen Betriebssystem-Blöcken in der Redolog-Datei ein Checkpoint initiiert werden soll. Vergrößert man die Redolog-Dateien, um die Anzahl der Checkpoints zu reduzieren, muss auch dieser Parameter auf einen hohen Wert gesetzt werden. Auf den meisten Systemen ist die Standardeinstellung 10.000, was dann lediglich für eine Redolog-Größe von 5 Mbyte ausreicht. Der Wert muss nicht mit der Größe der Dateien korrespondieren. log_checkpoint_timeout
Über diesen Parameter wird ein Zeitintervall in Sekunden definiert, nach dem ein Checkpoint initiiert werden soll. Standardeinstellung für die Oracle9i Standard Edition ist 900 Sekunden, für die Enterprise Edition 1.800 Sekunden. Sollen die Checkpoints nur über die Redolog-Switches initiiert werden, muss dieser Wert auf 0 gesetzt werden.
3.8.3
Administrationskommandos
Im Folgenden werden die wichtigen Kommandos für die Administration der Redolog-Dateien beispielhaft vorgestellt. Für die komplette Syntax sei auf das Handbuch Oracle9i SQL Reference verwiesen. Die hier vorgestellten Kommandos gelten genauso für Oracle8i, mit Ausnahme des Ein- und Ausschaltens von Zusatzinformationen für den LogMiner. Anlegen einer neuen Gruppe SQL> ALTER DATABASE ADD LOGFILE GROUP 3 '/disk1/verzeichnis/redo_3_1.rdo' SIZE 5M;
Sandini Bib
230
Datenbankdesign
Die Nomenklatur der Redolog-Dateien sollte die Gruppennummer (hier 3) und die Nummer des Mitglieds einer Gruppe beinhalten (hier 1). Hinzufügen eines Mitglieds zu einer Gruppe SQL> ALTER DATABASE ADD LOGFILE MEMBER '/disk1/verzeichnis/redo_3_2.rdo' to group 3;
Ein- und Ausschalten von Zusatzinformationen für den LogMiner Um mit dem LogMiner Auswertungen oder Scripts für die Wiederherstellung von Transaktionen mit mehr Informationen zu erhalten, kann die Protokollierung von Zusatzinformationen ein- und ausgeschaltet werden. SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA PRIMARY KEY COLUMNS;
Bei Tabellen mit einem Primärschlüssel werden bei einem UPDATE-Befehl die Primary Key-Spalten mitprotokolliert. SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG UNIQUE INDEX COLUMNS;
Wird ein Feld als Bestandteil eines eindeutigen Schlüssels modifiziert, so werden alle Felder des Schlüssels mit protokolliert. SQL> ALTER DATABASE DROP SUPPLEMENTAL LOG DATA PRIMARY KEY COLUMNS; SQL> ALTER DATABASE DROP SUPPLEMENTAL LOG UNIQUE INDEX COLUMNS;
Die Zusatzinformationen in den Redolog-Dateien werden wieder ausgeschaltet. Umbenennen von Redolog-Dateien SQL> ALTER DATABASE RENAME FILE '/disk1/verzeichnis/redo_1_1.rdo' TO '/disk2/verzeichnis_neu/redo_1_1.rdo’;
Voraussetzungen für dieses Kommando sind, dass die Gruppe nicht gerade im Zugriff des Logwriter-Prozesses ist, die Quelldatei identisch mit den Informationen aus v$logfile ist und die Zieldatei existiert, also vorher auf Betriebssystemebene kopiert worden ist. Zum Letzteren bieten die Oracle Managed Files eine Ausnahme. Löschen eines Mitglieds einer Gruppe SQL> ALTER DATABASE DROP LOGFILE MEMBER '/disk1/verzeichnis/redo_3_2.rdo';
Dieser Befehl löscht den Eintrag aus der Control-Datei. Auf Betriebssystemebene muss die Datei zusätzlich gelöscht werden. Bei Oracle Managed Files werden die Dateien automatisch von der Platte gelöscht.
Sandini Bib
Redolog-Dateien
231
Löschen einer Gruppe SQL> ALTER DATABASE DROP LOGFILE GROUP 3;
Voraussetzungen sind, dass die jeweilige Gruppe nicht im Zugriff des LogwriterProzesses ist und mindestens zwei Gruppen verbleiben. Auf Betriebssystem-Ebene muss die Datei zusätzlich gelöscht werden. Bei Oracle Managed Files werden die Dateien automatisch von der Platte gelöscht. Initialisieren einer Gruppe SQL> ALTER DATABASE CLEAR UNARCHIVED LOGFILE GROUP 1 UNRECOVERABLE;
Mit diesem Befehl kann eine Logfile-Gruppe oder auch eine einzelne Redolog-Datei initialisiert werde. Die Wirkung entspricht dem Löschen und Neuanlegen der Gruppe, jedoch funktioniert dieser Befehl auch dann, wenn nur zwei RedologGruppen angelegt wurden. Der Status der Gruppe ist anschließend UNUSED, die Log Sequence Number wird auf 0 zurückgesetzt. Der Zusatz UNARCHIVED erlaubt sogar die Initialisierung, auch wenn die Datenbank im Archivierungsmodus läuft und die Redolog-Datei noch nicht archiviert ist. Die Option UNRECOVERABLE bewirkt, das eine Initialisierung stattfindet, obwohl Inhalte der Redolog-Datei noch für eine Wiederherstellung der Datenbank benötigt werden. Diese Optionen sollten jedoch nur im äußersten Notfall verwendet werden.
3.8.4
Überwachung von Redolog-Dateien
Zur Überwachung der Redolog-Dateien stehen folgende v$-Tabellen zur Verfügung: v$log GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM ------ ------- --------- ---------- ------- --- ------- ---------------- ----------1 1 2 10485760 1 YES INACTIVE 471741 30-JUL-01 2 1 1 10485760 1 YES INACTIVE 471528 15-JUN-01 3 1 3 10485760 1 NO CURRENT 471742 30-JUL-01 Listing 3.63: v$log
v$logfile Neben der Gruppenzugehörigkeit werden in dieser Tabelle auch der Status und die Namen der Redolog-Dateien angezeigt, unter ihnen auch Oracle Managed Files. v$loghist und v$loghistory In diesen v$-Tabellen werden Informationen über archivierte Redolog-Dateien, wie Namen, Zeitstempel und SCN-Nummer verwaltet. Diese Auszüge kommen aus der Redolog-Historie in den Control-Dateien. Zusätzlich werden sämtliche Redolog-Switches mit Zeitstempel in der Alert-Datei einer Instanz protokolliert. Hier sind auch die Wartezustände vermerkt, die durch Checkpoints oder die Archivierung bedingt sind, meist mit Zeitangaben.
Sandini Bib
232
3.8.5
Datenbankdesign
Überlegungen zur Spiegelung von Redolog-Dateien
Die Redolog-Dateien sind die kritischen Dateien einer Oracle-Datenbank im Fehlerfall. Datendateien und Control-Dateien können wiederhergestellt werden, vorausgesetzt, es existiert eine Sicherung. Die Redolog-Dateien beinhalten Transaktionsinformationen, die insbesondere nach einer Beschädigung an einer Festplatte zur Wiederherstellung der Datendateien benötigt werden. Der Verlust einer kompletten Redolog-Gruppe bedeutet Datenverlust! Aus diesem Grunde ist es für Produktionsdatenbanken erforderlich, die RedologDateien zu spiegeln, also mindesten zwei Mitglieder in einer Gruppe auf unterschiedlichen Platten zu haben. Dabei steht zur Auswahl, entweder eine Oracle-seitige Spiegelung einzuschalten oder die Dateien der Redolog-Gruppen auf gespiegelte Platten zu legen. Dabei sind sowohl betriebssystemseitige oder Controller-Spiegelungen üblich. Von einer logischen Spiegelung über RAID5 sollte abgesehen werden, da die gerade benötigte Performanz beim Schreiben fehlt. Fällt ein Spiegel aus, wird die Oracle-Instanz weiterlaufen, der Logwriter-Prozess schreibt in die verbleibende Datei der Gruppe. Bei der Oracle-seitigen Spiegelung hat man den Vorteil, dass der Schreibfehler auf das fehlende Mitglied in der AlertDatei protokolliert wird. Betriebssystemseitige oder Controller-Spiegelungen sind für den Logwriter-Prozess transparent.
3.8.6
Redolog-Dateien als Oracle Managed Files
Auch die Redolog-Dateien einer Oracle-Datenbank können als Oracle Managed Files angelegt werden. Die Lage der Dateien, deren Name vom Oracle-System automatisch eindeutig generiert wird, wird über den Initialisierungsparameter db_create_online_log_dest_n = /platte/verzeichnis bestimmt. Werden mehrere Destinationen definiert, so sind diese jeweils Spiegelungen der Redolog-Dateien einer Gruppe. Die Standardgröße für Oracle Managed Redolog Files ist 100 Mbyte. Es kann innerhalb einer Datenbank sowohl mit Oracle Managed Files als auch mit benutzerdefinierten Dateien gearbeitet werden.
3.8.7
Archivierte Redolog-Dateien
In diesem Abschnitt wird noch kurz das Thema der archivierten Redolog-Dateien, oder Oflline-Redolog-Dateien, behandelt, da auch diese Dateien als Bestandteil der Datenbank und der Datensicherung anzusehen sind. Archivierte Redolog-Dateien werden dann angelegt, wenn die Datenbank im Archivierungsmodus betrieben wird. In Verbindung damit steht das automatische Archivieren der Dateien durch einen dedizierten Prozess der betreffenden Oracle-Instanz, den ARCn-Prozess.
Sandini Bib
Redolog-Dateien
233
Arbeitsweise des ARCn-Prozesses Immer dann, wenn eine Redolog-Datei vollgeschrieben ist und ein Redolog-Switch ausgeführt wird, kopiert ein Prozess, der ARCn, diese Datei auf eine Platte. Die Redolog-Datei wird erst dann zum überschreiben freigegeben, wenn der Archivierungsprozess das vollständige Kopieren der Datei quittiert hat. Sollte das Überschreiben anstehen, bevor die Inhalte der Datei in eine archivierte Redolog-Datei geschrieben worden sind, tritt ein Wartezustand auf, was bedeutet, dass Transaktionen nicht weiterlaufen oder gestartet werden können. Bei einem Switch wird der ARCn-Prozess angestoßen, der dann die Inhalte der Redolog-Datei in eine archivierte Redolog-Datei schreibt, nicht etwa nur die Datei kopiert. So kann es sein, dass nach manuell angestoßenen Switches die archivierten Redolog-Dateien unterschiedliche Größen haben. Bei gespiegelten RedologDateien wird abwechselnd aus den Mitgliedern der Gruppe gelesen, um die I/Os zu verteilen und damit eine bessere Performanz des ARCn-Prozesses zu erreichen. Initialisierungsparameter für die Archivierung log_archive_dest
Dieser Parameter beschreibt das Verzeichnis und den Anfang des Dateinamens für die Archivierung. log_archive_dest ist nicht kompatibel mit dem Parameter log_archive_dest_n, kann also nicht in Kombination mit diesem verwendet werden. log_archive_dest_n log_archive_dest_n beschreibt verschiedene Ziele für die Archivierung und ist für
Standby-Datenbanken konzipiert. Die Archivierung kann hier über IPC oder TCP erfolgen, wobei für TCP ein tnsnames_service benötigt wird. Für die komplette Dokumentation des Parameters wird auf die Dokumentation Oracle9i Database Reference, Kapitel 1, verwiesen. log_archive_dest_state_n
Über diesen Parameter können die zuvor beschriebenen Standby-Destinationen ein- oder ausgeschaltet werden. log_archive_duplex_dest
Der Parameter gibt das Verzeichnis für die Spiegelung der archivierten RedologDateien an. log_archive_format
Der Wert dieses Parameters ergänzt den Dateinamen, der in log_archive_dest seinen Präfix erhalten hat. Der gesamte Dateiname ergibt sich nur aus der Kombination beider Parameter. Es stehen Variablen zur Verfügung, die die Log Sequence Number oder die Thread Number (einer Oracle Parallel Server-Instanz) in den Dateinamen generieren. %s %S
Log Seuqence Number Log Sequence Number, mit Nullen aufgefüllt
Sandini Bib
234
%t %T
Datenbankdesign
Thread Number Thread Number, mit Nullen aufgefüllt
Beispiel: log_archive_dest = "/disk1/oraarch/arch" log_archive_format = "_%s.arc"
Daraus
ergibt
sich
im
Verzeichnis
/disk1/oraarch
z.B.
der
Dateiname
arch_121.arc log_archive_max_processes
Dieser Parameter spezifiziert die Anzahl von Archivierungsprozessen ARC0 bis ARC9 (maximal 10), die mit der Oracle-Instanz gestartet werden. Wie viele Prozesse dann aktiv sind, ist von der aktuellen Last abhängig. log_archive_min_succeed_dest log_archive_min_succeed_dest gibt an, auf wie vielen Destinationen das Archivieren erfolgreich sein muss. Wird zum Beispiel mit log_archive_dest und log_archive_duplex_dest gearbeitet, so besagt der Wert 1, dass die Archivierung auf die Duplex-Destination nicht erfolgreich sein muss, die Instanz aber trotzdem weiterläuft. 2 würde bedeuten, dass die Instanz gestoppt wird, wenn die Archivierung nicht auf beiden Destinationen erfolgreich war. log_archive_start
Dieser Parameter kann die Werte true oder false annehmen, wobei false die Standardeinstellung ist. Sobald der Parameter auf true gesetzt wird, wird beim Start der Instanz die automatische Archivierung durch den ARCn-Prozess gestartet. log_archive_trace
Über das Trace Level kann eingestellt werden, wie umfangreich die Informationen über die Archivierung sind, die in die Alert-Datei und die Trace-Datei der Achivierungsprozesse geschrieben werden. Auch hier sei der Verweis auf die Dokumentation Oracle9i Database Reference, Kapitel 1, erlaubt. Überwachung der Archivierung Über folgenden Befehl kann die Archivierung überwacht werden: SQL> CONNECT / AS SYSDBA SQL> ARCHIVE LOG LIST Database log mode Automatic archival Archive destination Oldest online log sequence Next log sequence to archive Current log sequence Listing 3.64: ARCHIVE LOG LIST
Archive Mode Enabled /oraarch/o9i/arch 2 4 4
Sandini Bib
Control-Dateien
235
Der Archivierungsprozess kann über die Befehle SQL> ARCHIVE LOG STOP SQL> ARCHIVE LOG START
gestoppt und gestartet werden. Die
Parameter sind, mit Ausnahme von log_archive_format und log_archive_start dynamisch und können mit ALTER SYSTEM geändert werden.
3.9
Control-Dateien
Die Control-Dateien sind die kleinsten Komponenten (zwischen 800 Kbyte und 5 Mbyte) einer Oracle-Datenbank, haben aber sowohl für die Verfügbarkeit als auch für die Konsistenz der Datenbank eine zentrale Bedeutung, besonders im Wiederherstellungsfall. In einer Control-Datei sind Informationen über die Datenbank und alle Dateien abgelegt, die zur Datenbank gehören. Dabei besteht eine Eins-zu-eins-Zuordnung der Control-Datei zu einer Datenbank. Wichtige Informationen, die in einer Control-Datei gespeichert sind, sind unter anderem:
: : :
: : : : : : :
Datenbankname Zeitpunkt der Erstellung der Datenbank Name der zur Datenbank gehörenden Datendateien, und Redolog-Dateien mit kompletter Pfadangabe Informationen über die Tablespaces (seit Oracle8 über v$tablespace abgreifbar) Offline-Informationen von Datendateien Informationen über den Archiv-Status Redolog-Historie Informationen für den Recovery Manager aktuelle Log Sequence Nummer Checkpoint-Informationen
Die Control-Dateien sind sowohl beim Startup des Oracle-Systems im Zugriff als auch während des normalen Datenbankbetriebs. Die Aktualisierung der Control-Dateien erfolgt über die Instanz bei Auftreten eines Checkpoints oder Strukturveränderungen an der Datenbank. Strukturveränderungen der Datenbank sind beispielsweise das Hinzufügen, Umbenennen und Löschen von Datendateien oder Tablespaces, Redolog-Dateien oder Redolog-Membern.
Sandini Bib
236
Datenbankdesign
Konsistenzinformationen bezüglich der Datendateien werden redundant in der Control-Datei und in den File-Header der betreffenden Dateien gespeichert und bei Bedarf – z.B. beim Starten der Datenbank – verglichen. Ein Abgleich der Information findet darüber hinaus bei einem Checkpoint statt. Zudem speichert der Checkpoint-Prozess in Intervallen von drei Sekunden den Status der RedologDateien in der Control-Datei, um parametrierte Grenzen wie z.B. log_checkpoint_interval oder log_checkpoint_timeout abgleichen zu können. Diese Konsistenzinformationen bestimmen bei einem Instanz-Recovery oder bei einem Media-Recovery, welche Informationen aus Redolog-Dateien oder archivierten Redolog-Dateien nachgefahren werden müssen, um die Datenbank wieder auf einen konsistenten Zustand zu bringen. Sind diese Informationen nicht vollständig vorhanden, muss ein unvollständiges Media-Recovery durchgeführt werden, was einen Datenverlust nach sich zieht. Die Control-Dateien sind somit auch ein wichtiger Bestandteil der Sicherung einer Oracle-Datenbank. Wenn Strukturänderungen wie das Hinzufügen eines neuen Tablespaces oder einer neuen Daten- oder Redolog-Datei ducrhgeführt werden, sollte anschließend sofort eine Sicherung der Control-Datei vorgenommen werden.
3.9.1
Administration der Control-Dateien
Anlegen der Control-Dateien Die Control-Datei wird automatisch beim Anlegen der Datenbank erzeugt. Die Lage der Control-Datei wird dabei über den Initialisierungsparameter control_files bestimmt. Die Größe wird abhängig vom CREATE DATABASE-Kommando spezifizierten Obergrenzen errechnet. Die dafür relevanten Parameter sind MAXINSTANCES, MAXLOGFILES, MAXLOGMEMBERS, MAXLOGHISTORY und MAXDATAFILES. Hier ist anzuraten, die Parameter mit Reserven zu versehen. Ist die hier definierte Obergrenze überschritten, so können keine weiteren Dateien des entsprechenden Typs an die Datenbank angehängt werden. Dieses Problem ist dann nur über das Anlegen einer neuen Control-Datei zu lösen, was man in der Praxis jedoch vermeiden sollte. Spiegelung der Control-Dateien Die Wichtigkeit der Control-Dateien, sowohl für den laufenden Betrieb als auch für den Wiederanlauf des Oracle-Systems, insbesondere bei der Wiederherstellung der Datenbank, ist im vorangehenden Abschnitt beschrieben worden. Aus diesem Grunde ist es unbedingt anzuraten, die Control-Dateien zu spiegeln. Dabei steht zur Auswahl, die Spiegelung auf unterschiedliche Platten über das Betriebssystem, einen Platten-Controller oder Oracle-seitig ausführen zu lassen. Im Folgenden wird das Verfahren zur Einrichtung einer Oracle-seitigen Spiegelung beschrieben (Pfadangaben für UNIX): 1. Aktueller Eintrag in der init<sid>.ora oder im SP-File
Sandini Bib
Control-Dateien
237
control_files = '/disk1/verzeichnis/control_1.ctl'
zu kontrollieren über 2. Änderung des Eintrags in der init<sid>.ora auf control_files = '/disk1/verzeichnis/control_1.ctl', '/disk2/verzeichnis/control_2.ctl'
oder im SP-File über ALTER SYSTEM SET control_files = '/disk1/verzeichnis/control_1.ctl', '/disk2/verzeichnis/control_2.ctl' scope = spfile;
3. Shutdown des Oracle-Systems, z.B. SQL> SHUTDOWN IMMEDIATE
4. Kopieren der Control-Datei auf Betriebssystemebene $ cp /disk1/verzeichnis/control_1.ctl /disk2/verzeichnis/control_2.ctl
5. Startup des Oracle-Systems SQL> STARTUP
Es ist unbedingt zu beachten, dass die Control-Dateien nur bei gestoppter Instanz kopiert werden dürfen, da ansonsten die Versionsstände der Dateien differieren und zu einem Fehler beim Starten des Oracle-Systems führen. Weiterhin sei darauf hingewiesen, dass die Definition über ein SP-File erst mit Oracle9i verfügbar ist. Umbenennen oder Verlagern der Control-Dateien Für das Umbenennen oder Verlagern der Control-Dateien gilt das gleiche Verfahren wie bei der Erstellung einer Spiegelung. Auch hier ist unbedingt die Reihenfolge des Stoppens, der Umbenennung und des Startens einzuhalten. Sichern und Erzeugen von Control-Dateien Eine Control-Datei kann während des laufenden Betriebes durch folgendes Kommando gesichert werden: SQL> ALTER DATABASE BACKUP CONTROLFILE TO '/backupdisk/verzeichnis/control_bck.ctl';
Bei Verlust der Control-Datei einer Datenbank kann diese durch ein CREATE CONTROLFILE-Kommando wieder aufgebaut werden. Im Kommando müssen alle Dateien angegeben werden, die zur Datenbank gehören, sowohl alle Redolog- als auch alle Datendateien. Da bei der Erstellung eines solchen Scripts Fehler vorprogrammiert sind, existiert die Möglichkeit des automatischen Generierens. SQL> ALTER DATABASE BACKUP CONTROLFILE TO TRACE;
Die daraus resultierende Trace-Datei wird in das Verzeichnis geschrieben, das als user_dump_dest definiert ist. Die Trace-Datei enthält das Startup-Kommando und
Sandini Bib
238
Datenbankdesign
das CREATE CONTROLFILE-Kommando, inklusive Kommentierung der einzelnen Schritte. Dieses Script kann auch dann genutzt werden, wenn durch zu klein gewählte Einstellungen beim Anlegen der Datenbank – die Klauseln MAXDATAFILES und MAXLOGFILES – strukturelle Erweiterungen nicht mehr möglich sind. Das Script kann editiert werden, wobei man dann höhere MAX-Werte einträgt. Das Erzeugen einer Control-Datei ist jedoch immer ein Vorgang, der große Sorgfalt erfordert und für den das Oracle-System gestoppt werden muss. In der OracleDokumentation wird angeraten, sowohl vor als auch nach der Ausführung des CREATE CONTROLFILE-Kommandos eine Sicherung zu machen. Beispiel eines CREATE CONTROLFILE-Kommandos: STARTUP NOMOUNT CREATE CONTROLFILE REUSE DATABASE "O9I" NORESETLOGS ARCHIVELOG MAXLOGFILES 32 MAXLOGMEMBERS 3 MAXDATAFILES 254 MAXINSTANCES 1 MAXLOGHISTORY 113 LOGFILE GROUP 1 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\REDO01.LOG' SIZE 10M, GROUP 2 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\REDO02.LOG' SIZE 10M, GROUP 3 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\REDO03.LOG' SIZE 10M DATAFILE 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\SYSTEM01.DBF', 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\RBS01.DBF', 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\USERS01.DBF', 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\TEMP01.DBF', 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\TOOLS01.DBF', 'C:\ORABASE\PRODUCTS\ORA901\ORADATA\O9I\INDX01.DBF' CHARACTER SET WE8ISO8859P1 ; Listing 3.65: CREATE CONTROLFILE
Control-Dateien und Oracle Managed Files Die Control-Dateien können auch als Oracle Managed Files angelegt werden. Das bedeutet, dass nicht durch den Initialisierungsparameter control_files die Namen bestimmt werden, sondern dass das Oracle-System beim Anlegen der Datenbank eigene eindeutige Dateinamen generiert. Die Lage der Control-Dateien wird dann über den Initialisierungsparameter db_create_online_log_dest_n = /platte/verzeichnis
Sandini Bib
Control-Dateien
239
bestimmt. Dieser Parameter bestimmt darüber hinaus die Lage der Online-RedologDateien. Für die Spiegelung müssen dann entsprechend zwei oder mehr Destinationen angegeben werden. Bei Verwendung einer Parameterdatei alten Stils – init.ora-Datei – müssen die generierten Dateinamen über die View v$controlfile ermittelt und anschliessend über den Parameter control_files eingetragen werden. Bei Verwendung einer SPDatei entfällt diese Maßnahme.
Sandini Bib
Sandini Bib
4
Sicherheit
4.1
Einführung
Das funktionale Umfeld, in dem Datenbanksysteme zum Einsatz kommen, ist in den letzten Jahren dramatisch erweitert worden. Vorbei sind die Zeiten, in denen Client-Anwendungen durch direkte Connect-Operationen auf relationale Daten zugriffen. Drei- und mehrschichtige Architekturen erfordern heute auch dann sichere Authentifizierungen und Autorisierungen der Anwender, wenn diese nicht als Benutzer in der Datenbank registriert wurden. Gleichermaßen fordern Anwender, die mit einer Vielzahl von Systemen arbeiten müssen, eine zentrale, sichere Identifizierung für den Zugriff auf alle Systeme. Einhergehend mit dieser Entwicklung wurden neue, erweiterte Anforderungen an die Sicherheitsmerkmale von Datenbanksystemen gestellt. Vor diesem Hintergrund wurden auch die Sicherheitsmerkmale von Oracle8i und Oracle9i durch neue Funktionalitäten ergänzt, so dass dem Datenbankverwalter nun eine breite Palette erprobter Techniken für die sichere Konfiguration seiner Systeme zur Verfügung steht. Das Thema Sicherheit im Kontext von Datenbanken wird jedoch nicht durch den Einsatz einzelner Features erledigt, sondern lebt erst durch die konzertierte Planung, Konfiguration und kontinuierliche Überwachung der relevanten Systeme. In vielen Fällen wird dem Thema Sicherheit immer noch zu wenig Aufmerksamkeit geschenkt. Sicherheit kostet: Zeit und Geld für die Planung, Geld für Hard- und Software, Zeit und Geld für die Ausbildung der Beteiligten. Wir sollten uns hüten, Sicherheit nur als Synonym für Datenverschlüsselung zu handeln, um das unerlaubte Abhören, Lesen und Modifizieren von Daten während der Übertragung über ein Netzwerk zu verhindern. Sicherheit hat viele wichtige Seiten! Eine angemessene Benutzerplanung und Authentifizierung, Strategien bei der Wahl und Verwaltung von Schlüsselworten, die bewusste und maßvolle Zuteilung von Privilegien sowie die Beobachtung des Systems sind mindestens ebenso wichtig für eine sichere Datenbankumgebung wie die oben genannte Verschlüsselung. Es sollte daher in jedem Projekt von Anfang an auch für diese Aspekte genügend Zeit eingeplant werden. Der große Nachteil einer ungenügenden Sicherheitsplanung ist leider der, dass die Sicherheitslücken oftmals über Jahre nicht bemerkt werden, ganz im Gegensatz zu einer unvollständigen Planung von Funktionen, die jedem Anwender sofort ins Auge springt, weil er bestimmte Aktionen nicht ausführen kann. Die Literatur ist voll von Definitionen zum Begriff „Datenbanksicherheit“. Eine dieser Definitionen soll dieses Kapitel einleiten:
Sandini Bib
242
Sicherheit
„Datenbanksicherheit besteht aus einem Korpus von Maßnahmen, Verfahrensweisen (policy) und Mechanismen, welche die Geheimhaltung, Integrität und Verfügbarkeit von Daten sicherstellen und mögliche interne und externe Angriffe, ob bösartiger oder zufälliger Art, abwehren sollen.“1 Diese Definition macht bereits deutlich, dass Sicherheit im Allgemeinen und Datenbanksicherheit im Besonderen nicht nur aus einem Katalog von technischen „Features“ besteht, sondern in ein breites organisatorisches Umfeld eingebettet ist. Sicherheit beginnt mit der Bereitschaft der Unternehmensleitung und der betreffenden Abteilungen, in die notwendigen Maßnahmen zu investieren, geht dann über rein „physikalische“ Maßnahmen, die regeln, wer wann Zugang zur Hardware der betreffenden Datenbank haben darf, bis hin zur „logischen“ Lösung der Problemstellungen über die zur Verfügung stehende Software. Sicherheit im Bereich der Datenbank geht dabei in vielen Aspekten über die Anforderungen der zugrunde liegenden Betriebssysteme hinaus. Ist die Datei für das Betriebssystem die kleinste Einheit, für die Zugriffe definiert werden können, muss die Datenbanksoftware die Zugriffe auf wesentliche feinere Art regeln. Jede Datenbankdatei enthält bekanntlich eine beliebige Anzahl von Objekten, deren Zugriff einzeln zu legitimieren ist. Innerhalb der Objekte muss es ferner möglich sein, den Zugriff für einzelne Tupel oder Attribute zu bestimmen. Schließlich werden dynamisch Ergebnistabellen generiert, die ebenfalls Sicherheitsanforderungen genügen können. Die Risiken, die entstehen, wenn das Thema Sicherheit nicht in der notwendigen Form Berücksichtigung findet, sind vielfältig:
: : : : :
1.
Verletzung der Geheimhaltungspflicht (privacy) durch unberechtigten Zugriff auf Daten, Verletzung der Integrität durch unerlaubtes Modifizieren von Daten, Verletzung der Geheimhaltung durch unerlaubte Schlussfolgerungen (Die Fehlermeldung „ORA-00001: Verstoß gegen Eindeutigkeit .....“ lässt beispielsweise den Schluss zu, dass ein Datensatz mit dem angegebenen Schlüssel bereits existiert, auch wenn er vom Benutzer nicht gelesen werden kann.), Verletzung der Geheimhaltung durch das Aggregieren von Daten (Das Lesen einzelner Sätze einer Tabelle mag beispielsweise erlaubt sein, aber die Bildung von maximalen Werten oder Durchschnittswerten über der gesamten Tabelle kann eine Verletzung der Geheimhaltung bedeuten.) und Daten können auch über verdeckte Kanäle (covert disclosure) an Unbefugte gelangen. (Einem Benutzer a wird das Recht gegeben, Tabelle t1 zu lesen, Benutzer B dagegen nicht. Benutzer A darf darüber hinaus eigene Tabellen erzeugen. Er kann nun die Daten der Tabelle t1 in eine eigene Tabelle einfügen und Benutzer b ein Leserecht an dieser Tabelle einräumen.)
Castano et al. Database Security, Seite IX.
Sandini Bib
Benutzerplanung
243
Das folgende Kapitel soll daher eine Anleitung zur Planung und Konfiguration einer sicheren Datenbankumgebung liefern. Die folgenden Meilensteine können dieses Vorhaben markieren:
: : :
Benutzerplanung und Authentifizierung Privilegisierung der Benutzer Systemüberwachung
4.2
Benutzerplanung
Der erste Schritt beim Aufbau eines Sicherheitskonzeptes ist die Planung und Konfiguration von Datenbankbenutzern. Es sind im Einzelnen die folgenden Kriterien zu beachten: 1. Wer greift aus welchem Kontext auf die Systeme zu? 2. Welche (internen) Datenbankbenutzer sollen unter welchem Namen angelegt werden? 3. Wie soll die Authentifizierung der Benutzer durchgeführt werden? 4. Sind externe Benutzer – z.B. in Verzeichnisdiensten – zu berücksichtigen bzw. zu konfigurieren? 5. Welche Benutzer erhalten welche Privilegien und wie werden die Privilegien vergeben? 6. Über welche Benutzer wird die Verwaltung der Datenbank realisiert und wie werden die Administratoren authentifiziert? Folgende Zusammenhänge sind hierbei zu beachten:
:
: :
Privilegien, die den Zugriff auf Objekte regeln, können nur im Kontext von Datenbankbenutzern vergeben werden. Einen Sonderfall stellen sog. Shared Schemas dar, bei denen die Zuteilung der Privilegien über Verzeichnisdienste gesteuert wird2. Benutzer, die mit eigenen Objekten arbeiten, haben alle möglichen Rechte in Bezug auf diese Objekte und können diese Rechte nach eigenem Gutdünken an Dritte weitergeben3. Zugriffskontrollen (auditing) können ebenfalls nur im Kontext von Datenbankbenutzern durchgeführt werden.
Je mehr physische Benutzer sich also einen Datenbankbenutzer „teilen“, sprich sich unter diesem Benutzer bei der Datenbank anmelden, desto undurchsichtiger wird für den Administrator die Vermeidung von destruktiven Operationen und die Zuordnung dieser Operationen zu bestimmten Personen oder Personenkreisen – Ausnahme sind hier die oben erwähnten Shared Schemas. Arbeiten gar alle Benutzer 2. 3.
Siehe hierzu Abschnitt Variante 3: Enterprise-Benutzer und Enterprise-Rollen Dies wird als discretionary access control bezeichnet. Ein alternatives Modell, das über Labels arbeitet, steht mit der so genannten mandatory access control zur Verfügung. Zu Labels siehe Abschnitt 4.7.
Sandini Bib
244
Sicherheit
in dem Schema des Eigentümers der Objekte, wird jede Zugriffsverwaltung ad absurdum geführt, weil im Prinzip alle Aktionen für alle erlaubt sind. Zugriffsbeschränkungen, die nur in der jeweiligen Anwendung realisiert werden, lassen sich bekanntlich sehr leicht unterlaufen, denn das Werkzeug SQL*Plus ist in wenigen Minuten auf jedem PC installiert und damit ist dem direkten Zugriff auf die Daten Tür und Tor geöffnet. Aus diesen Gründen sollte auf jeden Fall für jede bekannte, physische Person, die mit der Datenbank arbeitet, ein eigener Datenbankbenutzer erzeugt werden. Gibt es Benutzerkreise, d.h. Gruppen von Personen, welche die gleichen Zugriffsrechte an der Datenbank benötigen, so lässt sich die Administration der notwendigen Privilegien über geeignete Rollen sehr leicht realisieren. Diese einfache Regel wird leider immer dort verletzt, wo eine Anwendung für unterschiedliche Datenbanksysteme tauglich sein soll. Was die Authentifizierung der Benutzer betrifft, stehen dem Datenbankadministrator unterschiedliche Wege offen:
: :
Er kann jedem Datenbankbenutzer ein eigenes, in der Datenbank verwaltetes Schlüsselwort zuteilen, das der Benutzer bei der Anmeldung an der Datenbank zusätzlich zu seinem Schlüsselwort auf der Ebene des Betriebssystems einzugeben hat. Alternativ kann auf die Verwaltung und Eingabe eines Datenbankschlüsselwortes verzichtet werden. In diesem Fall „vertraut“ die Datenbank einem externen System, wie z.B. dem Betriebssystem oder einem Verzeichnisdienst.
Die zweite Lösung, nämlich der Verzicht auf ein eigenes Datenbankschlüsselwort, ist in der Regel für die Benutzer vorteilhafter, weil einfacher, setzt aber ein absolut sicheres System zur Authentifizierung außerhalb der Datenbank voraus. Was die Verwaltung der Datenbank betrifft, so kann ein Datenbankadministrator die gesamte Palette der Verwaltungsarbeit übernehmen. Eine für große Datenbanken in der Regel sinnvollere Lösung ist die Aufteilung der Arbeit unter verschiedenen Benutzern, die ganz gezielte Verwaltungsrechte zur Erfüllung ihrer Aufgaben erhalten und ihren Aufgaben entsprechend authentifiziert werden.
4.3
Interne Benutzerverwaltung
Der Zugriff auf Oracle-Datenbanken erfolgt stets in Form von Sitzungen (sessions). Sitzungen wiederum laufen im Kontext von Benutzern (user), die vorher in der Datenbank angelegt werden müssen. Über Authentifizierungsmechanismen, die letztendlich einer Sitzung einen Benutzer zuordnen, ist das Datenbanksystem in der Lage, die Autorisierung, d.h. die Zuordnung definierter Privilegien, durchzuführen4. Je differenzierter die Benutzerstrukturen in der Datenbank aufgebaut werden, desto differenzierter lassen sich Identitäten feststellen und über diese notwendige Privilegienmuster ableiten und initialisieren. Der Zugriff über Pauschal- oder 4.
Beim Einsatz von Verzeichnisdiensten kann die Autorisierung auch extern erfolgen. Siehe hierzu Abschnitt 4.4
Sandini Bib
Interne Benutzerverwaltung
245
Gruppenbenutzer erfordert – sofern eine exakte Privilegierung überhaupt gewünscht wird – die Identifizierung der Benutzer über jede der zugreifenden Anwendungen und ist aus diesem Grunde entsprechend aufwendig in der Programmierung und im Testen. In diesem Zusammenhang kümmert sich die interne Benutzerverwaltung um die Planung und Verwaltung von Benutzern innerhalb der Datenbank. Für das Anlegen von Benutzern ist das Privileg CREATE USER erforderlich, das standardmäßig über die DBA-Rolle vergeben wird.
4.3.1
Möglichkeiten der Authentifizierung
Beim Anlegen eines Benutzers in der Datenbank wird bereits eine geeignete Authentifizierungsmethode festgelegt. Es stehen unterschiedliche Methoden der Authentifizierung für die Identifikation von Kommunikationspartnern zur Verfügung:
: : : :
Bei der internen Authentifizierung wird der betreffende Benutzer mit einem Passwort angelegt, das in der Datenbank gespeichert wird und aus diesem Grunde auch über die Datenbank verifiziert werden kann. Die externe Authentifizierung verzichtet auf die Speicherung eines Passwortes in der Datenbank. Zur Verifizierung der Identität müssen aus diesem Grunde externe Quellen, z.B. das Betriebssystem, herangezogen werden. Die globale Authentifizierung speichert ebenfalls kein Passwort in der Datenbank. Die Identifikation erfolgt in diesem Falle über externe, in der Regel zentrale oder zentral autorisierte Quellen wie digitale Zertifikate und Verzeichnisdienste. Bei der Proxy-Authentifizierung übernimmt eine Mittelschicht (middle-tier) die Authentifizierung des Clients oder leitet zumindest dessen Identitätsdaten an die Datenbank weiter.
Die einzelnen Verfahren werden in den folgenden Abschnitten detailliert besprochen.
4.3.2
Interne Authentifizierung
Die interne Authentifizierung stellt die „klassische“ und am einfachsten zum implementierende Authentifizierungsmethode dar: Benutzer werden hierbei mit ihnen zugeordneten Passwörtern in der Datenbank angelegt. Bei der Anmeldung an die Datenbank wird der Benutzername zusammen mit dem verschlüsselten Passwort an den Datenbankserver übermittelt und dort mit den Einträgen des Data Dictionary verglichen. Da Passwörter in verschlüsselter Form im Data Dictionary gespeichert werden und auf Grund der verwendeten Algorithmen nicht entschlüsselbar sind, erfolgt ihr Vergleich entsprechend in verschlüsselter Form.
Sandini Bib
246
Sicherheit
Jeder Kommunikationspartner, der einen Benutzernamen mit dem ihm zugeordneten Passwort reproduzieren kann, hat aus diesen Gründen Zugang zur Datenbank mit den Privilegien, die dem entsprechenden Benutzer zugeordnet wurden. Die interne Authentifizierung ist zweifelsfrei die einfachste Methode, hat jedoch auch eine Reihe gravierender Nachteile:
: :
:
„schwache“ oder schriftlich fixierte Passwörter können leicht erraten oder reproduziert werden. Benutzername und Passwort müssen explizit – entweder interaktiv oder, schlimmer noch, hart kodiert – angegeben werden. Dies führt – vor allem, wenn mit einer Vielzahl von Datenbank gearbeitet wird – zur Auswahl von primitiven Passwörtern, die der Einfachheit halber auf allen Systemen identisch sind. Benutzer müssen auf jeder Datenbank separat angelegt und verwaltet werden.
Im folgenden Beispiel wird der Benutzer guenter mit dem Passwort unbescheid definiert: SQL> CREATE USER guenter IDENTIFIED BY unbescheid PASSWORD EXPIRE;
Die PASSWORD-Klausel bewirkt, dass der betreffende Benutzer bei seiner ersten Anmeldung zur Eingabe eines neuen Passwortes aufgefordert wird. Auf diese Weise lassen sich vom Datenbankverwalter einfach zu erinnernde Erstlingspasswörter vergeben, die der Endbenutzer entsprechend differenzieren muss5. Die Auswahl von Passwörtern ist sorgfältig zu überlegen. Ein leicht zu erratendes Schlüsselwort ist bekanntlich wertlos. Aus diesem Grunde ist es durchaus sinnvoll, entsprechende Standards für die Wahl von Schlüsselworten festzulegen und den Benutzern zu empfehlen. Die grundlegende Anforderung an Schlüsselworte ist so einfach wie schwierig: sie sollten schwer zu erraten, aber für den betreffenden Benutzer leicht zu behalten sein. Eine Empfehlung für die Erzeugung eines solchen Schlüsselwortes könnte z.B. lauten:
: : : :
Es sind zwei Worte auszuwählen und nach bestimmten Regeln zu kombinieren, z.B. durch „Mischen“ der Worte auf Buchstabenebene: Erstes Wort: „Haus“ Zweites Wort „1234“ Daraus resultierendes Schlüsselwort: „h1a2u3s4“
Schlüsselworte sollten darüber hinaus in regelmäßigen Abständen geändert und nicht niedergeschrieben werden. Der oben abgebildete Befehl legt lediglich den Benutzer an, er vergibt noch keine Privilegien! Die Anmeldung an die Datenbank ist aus diesem Grunde zu diesem Zeitpunkt noch gar nicht möglich. 5.
Siehe hierzu und zu den Regeln der Passwortvergabe auch Abschnitt 4.8.2.
Sandini Bib
Interne Benutzerverwaltung
247
Informationen über Benutzer können mit Hilfe der Views dba_users, all_users oder user_users abgefragt werden: SQL> SELECT username, user_id, password FROM dba_users WHERE username = 'GUENTER'; USERNAME USER_ID PASSWORD --------------------- ---------- -----------------------------GUENTER 31 86F7130824E83895 Listing 4.1: dba_users
Die Änderung des vergebenen Passwortes ist jederzeit, sowohl für den DBA als auch den betreffenden Benutzer, über den Befehl ALTER USER möglich: SQL> ALTER USER guenter IDENTIFIED BY neues_passwort;
Im Gegensatz zum DBA darf ein normaler Benutzer diesen Befehl nur zur Änderung seines eigenen Passworts nutzen.
4.3.3
Externe Authentifizierung
Extern authentifizierte Benutzer werden ohne Passwort in der Datenbank angelegt. Dementsprechend können sie nicht mit Mitteln der Datenbank identifiziert werden. Die Authentifizierung der Benutzer und die Verwaltung von Schlüsselworten erfolgt vielmehr mit datenbankfremden Mitteln, eben extern. Die Datenbank startet lediglich auf Anforderung eine Session mit dem Benutzer, der ihr von der externen Quelle „übergeben“ wird. Dadurch ist es möglich, den Connect an die Datenbank ohne Angabe eines Benutzernamens und eines Passwortes wie im folgenden Beispiel durchzuführen: sqlplus /
Die Vorteile einer solchen Methode liegen auf der Hand:
: :
Die Benutzer müssen sich keine zusätzlichen Passwörter für ihre Datenbankverbindungen merken. Batch-Programme kommen ohne hart kodierte Passwortanweisungen aus.
Das Verfahren hat jedoch auch Nachteile:
:
:
Beim Einwählen von entfernten Clients (remote login) können – je nach der verwendeten Methode – unsichere Authentifizierungen die Folge sein. Jeder externe Benutzer kann immer nur mit einem speziellen internen Benutzer verbunden werden.
Im folgenden Beispiel wird der Benutzer johannes mit externer Authentifizierung in der Datenbank angelegt:
Sandini Bib
248
Sicherheit
SQL> CREATE USER ops$johannes IDENTIFIED EXTERNALLY;
Wie der Benutzer ops$johannes im Einzelnen extern authentifiziert wird, hängt von dem gewählten Kontext ab. Die folgenden Abschnitte beschreiben die zur Verfügung stehenden Möglichkeiten. Nutzung des Betriebssystems Die erste Möglichkeit besteht in der Nutzung des Betriebssystems. Hierbei wird ein vom Betriebssystem authentifizierter Benutzer mit einem bestimmten Benutzer der ausgewählten Datenbank verbunden. Die Regeln dieser Zuordnung werden über den statischen Systemparameter os_authent_prefix festgeschrieben, der mit dem Wert OPS$ vorbelegt ist. In diesem Fall würde der Betriebssystembenutzer johannes ohne Angabe eines Passwortes mit dem Benutzer ops$johannes der Datenbank verbunden. os_authent_prefix kann genauso gut mit einer „leeren“ Zeichenkette (““) vorbelegt werden, wodurch eine Zuordnung identischer Benutzernamen möglich wird. Die externe Authentifizierung über das Betriebssystem ist standardmäßig nur für lokale Verbindungen zulässig. Sollen auf diese Weise auch entfernte Verbindungen zur Datenbank aufgebaut werden, ist zusätzlich der Systemparameter remote_os_authent auf true zu setzen. Die Datenbank vertraut in diesem Fall den von den Clients übermittelten Benutzernamen ohne weiteres und führt die Verbindung an die Datenbank durch. Es versteht sich, das diese Einstellungen extrem gefährlich und daher nur in Ausnahmefällen zu empfehlen sind. Für die entfernte Einwahl ohne Angabe von Passwörtern stehen andere, wesentlich sicherere Verfahren zu Verfügung, wie z.B. die Nutzung von Verzeichnisdiensten6 und Authentifizierungsservern. Unter den Betriebssystemen Windows NT und Windows2000 werden Authentifizierungen – transparent für den Benutzer – über eigene Authentifizierungsprotokolle durchgeführt7. Die Nutzung dieser Protokolle muss in der Datei sqlnet.ora entsprechend vorbereitet werden: sqlnet.authentication_services = (NTS)
Das Fehlen dieses Parameters beschert dem Benutzer den folgenden Fehler: ORA-01004: default username feature not supported; logon denied
Für einen fehlerfreien Verbindungsaufbau unter Windows ist es gleichermaßen notwendig, dass der Benutzername in der Datenbank aus dem Domänennamen, einem umgekehrten Schrägstrich und dem eigentlichen Benutzernamen zusammengesetzt wird: Aus dem Benutzer johannes des Betriessystems wird daher auf dem Computer bzw. unter der NT-Domäne RECHNER1 der Benutzer rechner1\johannes für den Fall, dass der Parameter os_authent_prefix mit ““ belegt wurde. Für das Anlegen von extern authentifizierten Oracle-Benutzern empfiehlt sich das Werkzeug Oracle Administration Assistant for Windows NT, das auf jeder Oracle-CD für Windows enthalten ist und separat installiert werden muss. 6. 7.
Siehe hierzu die ausführliche Besprechung in Abschnitt 4.4 Dies sind standardmäßig Kerberos für Windows2000 und NT Lan Manager für Windows NT.
Sandini Bib
Interne Benutzerverwaltung
249
Es ist natürlich auch möglich, einen Benutzer mit intern gespeichertem Passwort zu definieren, und sich trotzdem ohne Passwort über die oben beschriebenen Mechanismen bei der Datenbank anzumelden. Im Unterschied zu externen Benutzern kann ein solcher Benutzer auch – falls das Passwort bekannt ist – von beliebigen Betriebssystembenutzern angewählt werden. Nutzung von externen Authentifizierungsservern Für sichere, zentralisierte Authentifizierungen im Client-Server-Umfeld können darüber hinaus eine Reihe weiterer, etablierter Produkte und Verfahren für die Authentifizierung von Datenbankbenutzern eingesetzt werden. Dies können auf der einen Seite Authentifizierungsdienste wie Kerberos, DCE und RADIUS sein, die durch so genannte Smart-Cards ergänzt werden können, auf der anderen Seite ebenso biometrische Verfahren, bei denen Fingerabdrücke oder Netzhautmuster interpretiert werden. Die Nutzung dieser Dienste ist vor allem dort interessant, wo sie bereits in Oracle-fremden Kontexten eingesetzt werden und entsprechende administrative Erfahrungen vorliegen. Sie ermöglichen die Authentifizierung nach Single Sign On-Prinzip, bei dem sich Benutzer einmal anmelden und dann verschiedene Dienste, unter ihnen auch Datenbanken, ohne erneute Authentifizierung nutzen können. Zusätzlich kann bei diesen Verfahren auch die Verschlüsselung der Daten erfolgen. Die konfiguratorische Einbindung dieser externen Umgebungen in die Oracle-Welt wird über Oracle Net und dort vor allem über die Datei sqlnet.ora8 realisiert. Eine detaillierte Besprechung der einzelnen Methoden würde den Rahmen dieses Buches sprengen. Sie findet sich vielmehr in der Oracle-Dokumentation, dort vor allem unter dem Thema Advanced Security.
4.3.4
Globale Authentifizierung
Bei der globalen Authentifizierung werden Benutzer über digitale Zertifikate identifiziert. Zentrale Verzeichnisdienste regeln auf dieser Basis die Anmeldung an autorisierte Datenbanken und können darüber hinaus auch entsprechende Privilegien in Form von Enterprise-Rollen an den Benutzer übertragen. Die Verschlüsselung der Daten wird hierbei ebenfalls durchgeführt. Auf diese Weise lässt sich auch das oben beschriebene Single Sign On-Prinzip implementieren. Verzeichnisdienste und die mir ihrer Hilfe mögliche globale Authentifizierung werden ausführlich im Abschnitt 4.4 auf Seite Internet Directory, LDAP und SSL besprochen.
4.3.5
Proxy-Authentifizierung
Der Einsatz einer so genannten Mittelschicht (middle-tier), z.B. beim Einsatz von Applikationsservern, stellt besondere Anforderungen an die Authentifizierung von Benutzern in der Datenbank, sofern diese überhaupt gewünscht wird. In diesen Umgebungen authentifiziert sich ein Client zunächst bei einer Anwendung der Mittelschicht, z.B. mit Hilfe eines Zertifikats oder durch Angabe eines Benutzerna8.
Hier vor allem über den Parameter SQLNET.AUTHENTICATION_SERVICES
Sandini Bib
250
Sicherheit
mens und Passwortes. Die Mittelschicht realisiert dann für ihn den Zugriff auf die Datenbanken im Hintergrund. In manchen Fällen kann es hierbei notwendig sein, die Identität des Clients bei dieser „Umleitung“ nicht zu verlieren. Anwendungen, die über OCI9 oder JDBC aus der Mittelschicht heraus auf die Datenbank zugreifen, haben die Möglichkeit, über nur eine Verbindung mehrere so genannte leichtgewichtige Sitzungen (lightweight session) zu eröffnen, die jeweils eine Benutzeridentität bedienen. Die Anwendung kann diese Sitzungen nach Bedarf wechselweise benutzen. Die Authentifizierung gegenüber der Datenbank erfolgt in diesem Falle dreistufig: 1. Der Client authentifiziert sich gegenüber der Anwendung der Mittelschicht (Client-Identität). 2. Die Anwendung der Mittelschicht authentifiziert sich in der Datenbank zunächst unter einem ihr zugeordneten Datenbankbenutzer (Applikationsidentität). 3. Sie eröffnet dann eine Sitzung im Namen des Clients mit einer Client-Zielidentität in der gewünschten Datenbank. 4. Die Datenbank prüft, ob die Anwendung, d.h. der Benutzer, der die Anwendung benutzt (Applikationsidentität), berechtigt ist, die Client-Zielidentität zu benutzen. 5. Wenn die Prüfung erfolgreich verläuft, wird eine Sitzung im Namen der ClientZielidentität eröffnet und die zugesprochenen Rollen werden aktiviert. Die Applikationsidentität muss in diesem Falle ein Datenbankbenutzer sein. Die Client-Zielidentität kann ein Datenbankbenutzer oder ein Enterprise-Benutzer sein. Um die Konzepte der Proxy-Authentifizierung in der Datenbank umzusetzen, sind folgende SQL-Befehle notwendig. Die Applikationsidentität wird zunächst wie gewohnt erzeugt und autorisiert. Beispielsweise: CREATE USER applikation1 IDENTIFIED BY ......; GRANT .... TO applikation1;
Ebenso wird die Client-Zielidentität in der Datenbank angelegt. In unserem Beispiel werden dem Benutzer client1 die Rollen rolle1 und rolle2 zugeteilt: CREATE USER client1 IDENTIFIED .....; GRANT rolle1,rolle2 TO client1;
Im nächsten Schritt erhält der Anwendungsbenutzer das Recht, client1 für den Sitzungsaufbau zu einzusetzen: ALTER USER client1 GRANT CONNECT THROUGH applikation1 WITH ROLE rolle2;
Zusätzlich wird in diesem Beispiel für client1, wenn er über die Anwendung applikation1 mit der Datenbank verbunden wird, nur die Rolle rolle2 aktiviert. Proxy-Einstellungen dieser Art lassen sich über die View dba_proxies10 abfragen. 9. OCI = Oracle Call Interface 10. Unter Oracle 8i ist die View proxy_users zu benutzen.
Sandini Bib
Interne Benutzerverwaltung
4.3.6
251
Authentifizierung von Datenbankadministratoren
Für die Authentifizierung von Administratoren, welche die Datenbank starten oder herunterfahren, Backup- und Recovery-Operationen durchführen, Parameterdateien erzeugen oder den Datenbankmodus ändern müssen, stehen zwei alternative Verfahren zur Verfügung: die Authentifizierung über das Betriebssystem oder über eine Passwortdatei. Die Autorisierung erfolgt in diesem Fall über die Systemprivilegien SYSDBA und SYSOPER. Die folgende Tabelle zeigt, welche Operationen die beiden Privilegien im Einzelnen zulassen: Systemprivileg
Erlaube Operationen/Befehle
Datenbankbenutzer
SYSDBA
STARTUP, SHUTDOWN
SYS
CREATE/ ALTER DATABASE Zeichensatz anpassen CREATE SPFILE archivelog Recovery Restricted session Privileg SYSOPER
STARTUP, SHUTDOWN
SYS (eingeschränkt)
CREATE SPFILE ALTER DATABASE OPEN/MOUNT/BACKUP archivelog Recovery Restricted session Privileg Tabelle 4.1: Systemprivilegien SYSDBA und SYSOPER
Datenbankverwalter, die nicht mit den oben beschriebenen Kernaufgaben betraut sind, sondern sich beispielsweise um die Benutzerverwaltung oder das Anlegen von Rollen kümmern, können wie normale Benutzer über die Datenbank oder externe Verfahren authentifiziert werden und benötigen nicht die in den vorangehenden Abschnitten beschriebenen Verfahren. Die Authentifizierung über das Betriebssystem Bei der Authentifizierung über das Betriebssystem wird die Zugehörigkeit des Betriebssystembenutzers zu entsprechend vordefinierten Betriebssystemgruppen – OSDBA und OSOPER – herangezogen. Zusätzlich muss der Systemparameter remote_login_passwordfile für die betreffende Datenbank mit dem Wert none belegt worden sein: Die Zugehörigkeit zu der Gruppe OSDBA erlaubt dem Betreffenden den Connect mit dem Privileg SYSDBA, die Zugehörigkeit zu der Gruppe OSOPER erlaubt den Connect als SYSOPER, wie das folgende Beispiel zeigt.
Sandini Bib
252
Sicherheit
sqlplus /nolog SQL> CONNECT / AS SYSDBA
Die Authentifizierung von Administratoren über Gruppenzugehörigkeiten ist nur für lokale Zugriffe empfehlenswert. In allen anderen Fällen sollte von einer entsprechend konfigurierten Passwortdatei – wie im folgenden Abschnitt beschrieben – Gebrauch gemacht werden. Die Authentifizierung über eine Passwortdatei Bei der Authentifizierung über eine Passwortdatei spielt die Gruppenzugehörigkeit des betreffenden Betriebssystembenutzers keine Rolle. Die Identität wird vielmehr über eine separate, mit dem Werkzeug orapwd erstellte Datei verifiziert. Im folgenden Beispiel wird diese Datei für die Instanz T1 erzeugt. Das Passwort für den Datenbankbenutzer SYS wird auf den Wert geheim gesetzt, der Dateiname orapwT1 und der Pfad sind unter Unix für diesen Instanznamen obligatorisch. Die Datei wird für 20 Einträge, d.h. Benutzer, vorbereitet: orapwd file=$ORACLE_HOME/dbs/orapwT1 password=geheim entries=20
Unter Windows muss die Datei pwd<sid>.ora heißen und unter dem Verzeichnis %ORACLE_HOME%\database liegen. Für die Nutzung von Passwortdateien sind – über den Systemparameter remote_login_passwordfile – zwei unterschiedliche Verfahren konfigurierbar: 1. Der Wert exclusive reserviert die Passwortdatei für jeweils eine Instanz. Beliebigen Benutzern können in diesem Fall die Privilegien SYSOPER und SYSDBA zugeteilt werden. In unserem Beispiel erhält der Benutzer scott das SYSOPER-Privileg. Über die AS-Klausel kann er anschließend beim Verbindungsaufbau diese zusätzlichen Privilegien aktivieren. Die Datenbank identifiziert ihn in diesem Fall als public und nicht als scott. Entsprechend würde er – für den Fall, dass er das SYSDBA-Privileg erhalten hätte – als SYS authentifiziert. GRANT SYSOPER TO scott; ... CONNECT scott/tiger AS SYSOPER
2. Der Wert shared öffnet die Passwortdatei für mehrere Datenbanken. Die Datei speichert in diesem Fall jedoch nur Passwörter für die Benutzer SYS. Privilegien, die über Oracle-Passwortdateien verwaltet werden, lassen sich über die View v$pwfile_users auflisten.
4.3.7
Benutzerverwaltung
Zur Benutzerverwaltung gehört mehr als das Festlegen des Benutzernamens und der geplanten Authentifizierungsmethode. Die wichtigsten Aufgaben werden in den folgenden Abschnitten besprochen.
Sandini Bib
Interne Benutzerverwaltung
253
Tablespaces und Quoten Jedem Benutzer lassen sich die folgenden Standardwerte zuteilen:
:
:
:
DEFAULT TABLESPACE gibt den Tablespace an, der für die Speicherung der Objekte des betreffenden Benutzers standardmäßig genutzt wird, sofern diese nicht über eine explizite TABLESPACE-Klausel angelegt werden. Für Default-Tablespaces sind auf jeden Fall Quoten notwendig!
Die Quota-Klausel erteilt Benutzern Speicherquoten in bestimmten Tablespaces. Speicherquoten benötigt ein Benutzer zum Aufbau eigener Tabellen, Cluster oder Indizes. Es ist auf alle Fälle darauf zu achten, das Benutzer in ihrem DefaultTablespace entsprechende Quoten haben, sofern sie überhaupt zum Speichern von Objekten autorisiert werden sollen. TEMPORARY TABLESPACE teilt dem Benutzer einen Tablespace für die Speicherung
temporärer Daten zu. Temporäre Daten sind zum einen zwischengespeicherte Sortierungen, wie sie beispielsweise für ORDER BY- oder DISTINCT-Klauseln benötigt werden, wenn der Sortierbereich im Speicher zu klein ist, zum anderen aber auch temporäre Tabellen und temporäre CLOBs.
In der Version 9i kann ein so genannter Default Temporary Tablespace definiert werden, der automatisch jedem Benutzer als Temporary Tablespace zugewiesen wird. Im folgenden Beispiel wird dem Benutzer guenter der Standard-Tablespace users mit einer Quote von 100 Mbyte zugeteilt. Zusätzlich erhält er für den Tablespace indexes eine unbegrenzte Quote. Seine temporären Daten landen in tempts: SQL> ALTER USER guenter DEFAULT TABLESPACE users TEMPORARY TABLESPACE tempts QUOTA 100M ON users QUOTA UNLIMITED ON indexes; Listing 4.2: Vergabe von Quoten auf Tablespaces
Die Klauseln können auch schon bei dem Befehl CREATE USER angegeben werden. Für die Speicherung temporärer Daten sind grundsätzlich keine Quoten erforderlich. Benutzer und ihnen erteilte Quoten werden über die View dba_ts_quotas aufgelistet. Die View gibt darüber hinaus auch Auskunft über die Speicherbelegung der Benutzer in den einzelnen Tablespaces. Sperren und Löschen von Benutzern Benutzer können vom Administrator gesperrt werden. Die Sperre verwehrt dem Benutzer die Verbindung zur Datenbank, ohne seine Objekte und erteilten Privilegien zu zerstören. Andere Benutzer können weiterhin auf die Objekte des Gesperrten zugreifen, sofern sie die notwendigen Privilegien dazu haben. ALTER USER scott ACCOUNT LOCK;
Die Sperre kann vom Administrator jederzeit durch die UNLOCK-Klausel aufgehoben werden.
Sandini Bib
254
Sicherheit
Das Löschen von Benutzern erfolgt über den Befehl DROP USER. Hat der Benutzer eigene Objekte angelegt, ist zusätzlich die CASCADE-Klausel anzugeben. Die Löschung erfolgt ohne Rückfrage und kann nicht zurückgerollt werden! DROP USER guenter CASCADE;
Lizenzen verwalten Für die Lizenzierung von Oracle-Datenbanken stehen unterschiedliche Modelle zur Verfügung, die darüber hinaus in ihren Details von Zeit zu Zeit angepasst werden. Im Wesentlichen unterscheiden diese Modelle zwischen
: :
namentlich registrierten Benutzern (named user) und gleichzeitig aktiven Benutzern oder Datenbanksitzungen (concurrent usage).
Zur Überwachung der im Einzelfall vereinbarten Maximalwerte stehen die folgenden, dynamischen Systemparameter zur Verfügung:
: :
:
license_max_sessions gibt die maximal zulässigen Datenbanksitzungen an. Wird der Grenzwert erreicht, können nur noch Benutzer, die das Privileg restricted session haben, Verbindung zur Datenbank aufnehmen. Alle anderen
erhalten eine Fehlermeldung. Der vorbelegte Wert 0 hebt die Begrenzung auf. license_sessions_warning setzt den Schwellenwert für Warnungen im Zu-
sammenhang mit Datenbanksitzungen. Beim Erreichen des Schwellenwertes wird einerseits eine Meldung in die Alert-Datei geschrieben, andererseits erhalten Benutzer, die das Privileg restricted session haben, beim Anmelden einen Hinweis. license_max_users gibt die maximale Anzahl von Benutzern an, die in der Datenbank angelegt werden können. Der Parameter ist alternativ zu den beiden vorgenannten zu benutzen.
Über die View v$license können sowohl die vorgenommenen Einstellungen als auch die Hochwassermarke für Sitzungen aufgelistet werden. Standardbenutzer Bei der Installation von Oracle werden – abhängig von den angekreuzten Optionen – einige Standardbenutzer mit Standardpasswörtern angelegt. Es ist dringend zu empfehlen, für diese Benutzer entweder die Passwörter abzuändern, die Benutzer zu sperren oder ganz zu löschen, falls sie nicht benötigt werden. Bei der Installation über den CONFIGURATIONSASSISTENT, werden bereits einige Änderungen generiert, d.h. manche Benutzer gesperrt. Im Zweifelsfalle hilft die folgende Abfrage weiter: SQL> SELECT username, account_status, lock_date, expiry_date FROM dba_users;
Sandini Bib
Interne Benutzerverwaltung
255
Die folgende Tabelle gibt einen Überblick über die wichtigsten Standardbenutzer. Benutzer
Standardpasswort
Kontext
Privilegien
Bemerkungen
SYS
CHANGE_ON_ INSTALL
Schema des Data Dictionary
Volle DBARechte
Passwort unbedingt nach der Installation ändern!
SYSTEM
MANAGER
Schema für Objekte von „Werkzeugen“, z.B. Metatabellen für die Replikation
Volle DBARechte
Passwort unbedingt nach der Installation ändern!
MDSYS
MDSYS
InterMedia Spatial
AURORA$ JIS$UTILITY$
Zufallsgenerierung
JServer
RESOURCE, UNLIMITED TABLESPACE
AURORA$ ORB$UNAUTHENITCATED$
Zufallsgenerierung
JServer
CREATE SESSION; RESTRICTED SESSION
OSE$HTTP$ ADMIN$
Zufallsgenerierung
JServer
RESOURCE; JAVAUSERPRIV; CREATE SESSION; UNLIMITED TABLESPACE
DBSNMP
DBSNMP
Intelligent Agent
CONNECT, RESOURCE, SNMPAGENT, UNLIMITED TABLESPACE
OUTLN
OUTLN
Schema für stored outlines
CONNECT, RESOURCE, EXECUTE ANY PROCEDURE, UNLIMITED TABLESPACE
CTXSYS
CTXSYS
Oracle Text
ORDPLUGINS
ORDPLUGINS
InterMedia Audio
ORDSYS
ORDSYS
InterMedia Audio
Tabelle 4.2: Vordefinierte Datenbankbenutzer
Nach Änderung Datei snmp_rw.or a anpassen
Sandini Bib
256
4.4
Sicherheit
Internet Directory, LDAP und SSL
Das Volumen der Daten, die in relationalen Datenbanken gespeichert werden, ist in den letzten Jahren drastisch angestiegen. Mit dem größeren Datenvolumen sind auch die Anforderungen an die Datensicherheit und den Zugriffsschutz gewachsen. Immer mehr Benutzer benötigen heute für die Durchführung ihrer täglichen Arbeit Zugriff auf ein oder – in den meisten Fällen – mehrere relationale Systeme. Die herkömmliche Authentifizierung durch die Eingabe von Benutzernamen und ihnen zugeordneten Kennworten führt bei der Menge der Systeme zu schwachen, leicht zu erratenden Kennworten, die eine sichere Datenhaltung ad absurdum führen. Darüber hinaus müssen die Benutzer einzeln in den betreffenden Datenbanken eingerichtet werden. Noch schlechter steht es um das Thema Sicherheit, wenn „Gruppenbenutzer“ angelegt werden, die eine Maximalmenge der erforderlichen Privilegien erhalten. Über diese Gruppenbenutzer werden dann sämtliche Verbindungen einzelner Anwendungen abgewickelt. Individuelle Privilegien müssen in diesen Fällen mühsam in den Modulen der betreffenden Anwendungen programmiert werden. Sie können auf diese Weise leicht durch eine direkte Verbindung zur Datenbank umgangen werden. Zusätzlich besteht die Gefahr, dass die Daten während der Übertragung über Netzleitungen von Dritten abgehört und verändert werden. Um in Szenarien, wie sie oben beschrieben wurden, eine starke Authentifizierung und individuelle Privilegisierung der Benutzer sowie eine sichere Übertragung der Daten zu gewährleisten, ohne dabei die Abläufe an der Oberfläche der Anwendung zu komplizieren, ist Folgendes notwendig:
: : : : :
Eine zentrale, datenbankübergreifende Verwaltung von Benutzern (enterprise user) und ihnen zugeteilten Privilegien (enterprise roles) in Bezug auf definierte Zielsysteme Die Authentifizierung jedes Benutzers über diese zentrale Instanz (single sign on) Nach der Authentifizierung: die privilegierte Nutzung der Zielsysteme ohne erneute Eingabe eines Kennwortes Die freie Verknüpfung von zentral authentifizierten Benutzern mit bestimmten Datenbankschemas der betreffenden Zielsysteme Bei der Übertragung: die Sicherung der Daten durch geeignete Verschlüsselungsalgorithmen (encryption)
Das vorliegende Kapitel zeigt Lösungsmöglichkeiten für die Erfüllung dieser Forderungen.
Sandini Bib
Internet Directory, LDAP und SSL
4.4.1
257
Die Möglichkeiten im Überblick
Die oben genannten Forderungen sind mittlerweile auch im Kontext von OracleDatenbanken realisierbar. Für ihre Umsetzung stehen die folgenden „Bausteine“ zur Verfügung:
: :
:
: : : : :
Verzeichnisdienste (directories) stellen standardisierte Speicherstrukturen für die zentrale Erfassung von Benutzern, Rollen und Datenbanken u.v.a. zur Verfügung. Standardisierte Zugriffsprotokolle – wie z.B. LDAP11 – regeln den Zugriff auf diese Verzeichnisdienste. Am Markt sind unterschiedliche LDAP-Server verfügbar. Einer von ihnen ist der Server des Oracle Internet Directory (OID), der die Verzeichnisdaten gemäss den standardisierten Verzeichnisstrukturen in einer OracleDatenbank speichert. Digitale Zertifikate speichern Identitäten und ihnen zugeordnete Schlüssel. Identitäten in digitalen Zertifikaten werden über so genannte Distinguished Names – z.B. cn=guenter, o=databaseconsult, c=de – eindeutig bezeichnet. Sie lassen sich über Kennwörter öffnen und authentifizieren dann deren Benutzer für den Zugriff auf Datenbanken und andere Ressourcen. Protokolle für die Verschlüsselung, Authentifizierung und Integritätsprüfung – wie z.B. SSL12 – regeln den sicheren Verbindungsaufbau und die Verschlüsselung der Daten bei der Übertragung über das Netz. Globale Benutzer können in jeder Oracle-Datenbank angelegt werden und beziehen sich auf jeweils eine per Zertifikat ausgewiesene Identität. „Offene“ Benutzer (shared schemas) lassen sich in jeder Oracle-Datenbank anlegen und müssen über Verzeichnisdienste einer oder mehreren zertifizierten Identitäten, d.h. Benutzern (enterprise user), zugeordnet werden. Enterprise-Rollen werden in Verzeichnisdiensten definiert und dort ebenfalls Identitäten (enterprise user) zugeordnet. Sie werden darüber hinaus mit globalen Rollen, die in der Zieldatenbank angelegt werden müssen, verknüpft. Dienstbenennungen (net service names) können – statt in der lokalen Datei tnsnames.ora – über Verzeichnisdienste verwaltet und beim Aufbau einer Datenbanksitzung von dort abgerufen werden.
Die oben aufgezählten „Bausteine“ lassen sich technisch in unterschiedlichen Nutzungsvarianten kombinieren.
11. LDAP steht für Lightweight Directory Access Protocol. 12. SSL steht für Secure Sockets Layer. Das Protokoll sorgt für die Authentifizierung, Verschlüsselung und Integritätsprüfung einer TCP/IP-Verbindung.
Sandini Bib
258
Sicherheit
Variante 1: Auflösung von Dienstbenennungen Bei dieser Variante werden lediglich die Servicenamen für den Verbindungsaufbau zu den Zieldatenbanken über einen Verzeichnisdienst – z.B. Oracle Internet Directory – bereitgestellt. Die Authentifizierung und Autorisierung der Benutzer erfolgt auf herkömmliche Art direkt in der Datenbank. Auf die Verschlüsselung der Daten während der Übertragung wird verzichtet. Für diese Konfiguration werden die folgenden Bausteine benötigt:
: :
LDAP-Server Verzeichnisdienst (OID) mit entsprechenden Einträgen zur Namensauflösung
Variante 2: Authentifizierung globaler Benutzer In diesem Modell erfolgt die Authentifizierung der Benutzer über standardisierte digitale Zertifikate. Ein über das betreffende Zertifikat identifizierter Benutzer wird genau einem globalen Benutzer in einer Zieldatenbank zugeordnet. Die Zuordnung erfolgt über die Identität der Namen (distinguished name). Da die Verbindung zur Datenbank über SSL aufgebaut wird, ist auf diesem Wege auch die Verschlüsselung der Daten möglich. Der Benutzer kann sich – bei geöffnetem Zertifikat – ohne Kennwort bei dem Zielsystem anmelden.
Diese Konfiguration setzt die folgenden Bausteine voraus:
: :
:
Gültige digitale Zertifikate für den betreffenden Benutzer und die Zieldatenbank Globale Datenbankbenutzer, deren distinguished names mit denen der geöffneten Zertifikate der Clients identisch sind Konfiguration des Clients und des Datenbank-Listeners, um den Verbindungsaufbau über SSL zu ermöglichen
Variante 3: Enterprise-Benutzer und Enterprise-Rollen Im Unterschied zur Vari-
ante 2 wird in diesem Modell die Zuordnung der Benutzer zu bestimmten Datenbankschemas über einen Verzeichnisdienst geregelt. Im Kontext des Verzeichnisdienstes werden Enterprise-Benutzer und – ihnen zugeordnet – Enterprise-Rollen definiert. Den Enterprise-Rollen werden – ebenfalls über den Verzeichnisdienst – globale Rollen der Zieldatenbanken zugeordnet. Enterprise-Rollen erhalten ihre Privilegien ausschließlich über diese globalen Rollen, die in den Zieldatenbanken mit den notwendigen Privilegien definiert werden. Hier werden ebenfalls globale Benutzer ohne explizite Distinguished Names angelegt. Auch die Zuordnung der globalen Rollen zu den Benutzern erfolgt nicht in den Zieldatenbanken, sondern nur über den Verzeichnisdienst. Auf Grund dieser „Offenheit“ der globalen Benutzer ist es möglich, ihnen mehr als einen Enterprise-Benutzer zuzuordnen, daher der Begriff Shared Schema. Da auch die Zuordnung der Privilegien über den Verzeichnisdienst geregelt wird, können unterschiedliche Enterprise-Benutzer mit jeweils unterschiedlichen Privilegien ein Datenbankschema nutzen. Die Authentifizierung der Benutzer erfolgt auch in diesem Modell über Zertifikate. Die Eingabe eines Kennwortes ist nur für das Öffnen des Zertifikates, nicht aber für die Anmeldung an die Datenbank erforderlich. Der Verbindungsaufbau zur Datenbank erfolgt über SSL, wodurch die Verschlüsselung der Daten ebenfalls durchgeführt wird.
Sandini Bib
Internet Directory, LDAP und SSL
259
Enterprise User - Global User
Enterprise User Enterprise Role Global Role Global User Privilegien
Directory Service
Datenbank
Abbildung 4.1: Enterprise User zu Global User
Im Einzelnen werden für die dritte Variante die folgenden Bausteine benötigt:
: : : : :
Verzeichnisdienst mit entsprechenden Einträgen für Enterprise-Benutzer und Enterprise-Rollen Gültige digitale Zertifikate für den betreffenden Benutzer und die Zieldatenbank Globale Datenbankbenutzer ohne Angabe eines Distinguished Name sowie globale Rollen Konfiguration des Clients und des Datenbank-Listeners, um den Verbindungsaufbau über SSL zu ermöglichen Konfiguration des Servers zur Kommunikation mit dem LDAP-Server und dem Verzeichnisdienst, um die Zuordnung der Benutzer zu den Schemas vornehmen zu können
Variante 4: Kombination der vorangehenden Modelle Natürlich lassen sich die
vorangehenden Modelle auch mischen: Auf diese Weise können nicht nur Enterprise-Benutzer sondern auch Dienstbenennungen über Verzeichnisdienste interpretiert werden. Die zur technischen Umsetzung dieser Modelle notwendigen Konfigurationsmaßnahmen werden in den Abschnitten 4.4.3 bis 4.4.5 im Einzelnen erläutert.
Sandini Bib
260
4.4.2
Sicherheit
Grundlegende Standards und Begriffe
Bei der Beschreibung der oben dargestellten Variante wurden Standards erwähnt, die in dem vorliegenden Abschnitt eingehender erläutert werden sollen. Verzeichnisdienste Verzeichnisdienste (directories) sind spezialisierte Datenbanken, die Informationen über Personen, Rechner, Privilegien und vieles mehr enthalten können. Wir sprechen deshalb von spezialisierten Datenbanken, weil Zugriffe auf ihre Daten – im Gegensatz zu denen auf „herkömmliche“ Datenbanken – durch besondere Merkmale charakterisiert werden:
: :
:
Die Informationen werden im Wesentlichen gelesen, nur selten geändert. Es gibt eine hohe Anzahl paralleler Client-Zugriffe, jeder Client ist nur schwach aktiv. Jeder Client fordert nur geringe Datenmengen – z.B. eine E-Mail-Adresse – an.
Verzeichnisdienste können beliebig im Netzwerk repliziert oder verteilt werden. Die Replikation und Verteilung der Daten ist transparent für die zugreifenden Clients. Der Aufbau von Verzeichnisdiensten wird über den X.500-Standard geregelt. Informationen werden nach diesem Standard hierarchisch in Form von Einträgen (entries) im Kontext eines Verzeichnisinformationsbaumes (directory information tree) abgelegt. Jeder Eintrag wird dabei über ein oder mehrere Attribute näher beschrieben. Einträge mit identischen Attributtypen werden in Objektklassen zusammengefasst. Objektklassen selbst sind in Super- und Subklassen gegliedert. Subklassen erben – wie üblich – die Attribute ihrer Superklassen. Attribute können obligatorisch oder optional sein. Die Objektklasse organisationalPerson beispielsweise wird aus der Klasse person abgeleitet. Sie hat die obligatorischen Attribute sn (surname) und cn (common name) sowie eine Reihe weiterer optionaler Attribute wie z.B. userpassword, telephonenumber und title. Es ließe sich für diese Objektklasse ein entsprechender Eintrag mit den Attributwerten cn=unbescheid und sn=guenter definieren. Da die Person unbescheid in der deutschen Firma databaseconsult arbeitet, wird ihr Eintrag hierarchisch unter dem Objekt der Klasse organization mit dem Attributwert o=databaseconsult angelegt. Das Objekt o=databaseconsult liegt seinerseits unter dem Objekt c=de vom Type country. Die Identifizierung jedes Verzeichniseintrages ist dementsprechend auf unterschiedliche Weise möglich: 1. Innerhalb einer Ebene eines Unterbaumes über den relativen eindeutigen Namen (relative distinguished name - RDN). Der RDN enthält dabei alle Attributtypen und ihnen zugeordnete Werte, die im Rahmen der betreffenden Objektklasse intern als markant (distinguished) definiert wurden. Im oben genannten Beispiel lautet der RDN cn=unbescheid, obwohl die Objektklasse zwei obligatorische Attributtypen – cn und sn – enthält.
Sandini Bib
Internet Directory, LDAP und SSL
261
2. Innerhalb des gesamten Verzeichnisbaumes über einen global eindeutigen Namen (distinguished name – DN), der die RDNs aller übergeordneten Einträge zur Identifizierung mitführt. Im oben genannten Beispiel lautet der DN dementsprechend cn=unbescheid, o=databaseconsult, c=de. Neben den hier dargestellten Benutzerattributen enthalten Objektklassen eine Reihe von weiteren, operationalen Attributen, wie z.B. Zeitstempel, die für administrative Operationen des Verzeichnisses benötigt werden. Neue Objektklassen und Attributtypen lassen sich im Rahmen des oben dargestellten Modells beliebig anlegen, wodurch Verzeichnisdienste einen großen Teil ihrer Flexibilität und Dynamik erhalten. Der X.500-Standard definiert allerdings einen allgemein gültigen Satz aus Attributtypen und Objektklassen, um die internationale Nutzung der Dienste sicherzustellen. Die Erweiterung der Attributtypen ist auf der anderen Seite überall dort sinnvoll, wo Hersteller spezifische Informationen für die Funktionalität ihrer Produkte in dem betreffenden Verzeichnis speichern wollen. Das Verzeichnisschema (directory schema) enthält dementsprechend alle Metainformationen zu Objektklassen, Attributtypen, Datenformaten (Syntax) und Vergleichsregeln (matching rules) eines Verzeichnisses. Auch Oracle hat im Rahmen von Oracle Internet Directory zusätzliche Objektklassen und Attributtypen definiert, so z.B. die Objektklasse orclDBServer zur Verwaltung von Oracle-Datenbanken. Oracle Internet Directory Architektur Oracle Internet Directory
implementiert die im vorangehenden Abschnitt beschriebenen Verzeichnisdienste. Es besteht im Einzelnen aus einer Reihe unterschiedlicher Komponenten, die gemeinsam auf einem Rechner oder verteilt installiert und verwaltet werden können.
:
:
LDAP-Server Der LDAP-Server nimmt Anfragen an den Verzeichnisdienst entgegen und leitet sie an die betreffende Datenbank weiter. LDAP-Server werden als Instanz gestartet. Jede LDAP-Instanz besteht aus einem Dispatcher- bzw. Listener-Prozess, der auf eine konfigurierbare Portnummer – z.B. 386 oder 639 – „horcht“, und einem oder mehreren Serverprozessen, welche die Verbindung zur Verzeichnisdatenbank über Threads aufbauen. Die Anzahl der Serverprozesse sowie der Threads sind ebenfalls konfigurierbar. Es lassen sich ein oder mehrere LDAP-Instanzen auf einem Server starten. Die Datenbank mit den Verzeichnisdaten kann sowohl lokal als auch entfernt konfiguriert werden. Directory Replication Server Der Directory Replication Server sorgt für die Replikation der Verzeichnisdaten.
Sandini Bib
262
Sicherheit
/'$36HUYHU ,QVWDQ]HQ
/'$36HUYHU /'$3 $QIRUGHUXQJHQ
2,' /LVWHQHU
/'$36HUYHU
1HW /LVWHQHU
/'$36HUYHU
2UDFOH 1HW
Abbildung 4.2: LDAP-Diagramm
:
: :
Verzeichnisdatenbank Die Verzeichnisdatenbank speichert die Verzeichnisdaten. Aus Gründen der Konformität mit dem LDAP-Standard der Version 3 muss diese Datenbank mit dem UTF8-Zeichensatz angelegt werden. Die Kommunikation zwischen den LDAP-Instanzen und der Verzeichnisdatenbank erfolgt über Oracle-Netzdienste (Oracle Net Services13). Die Datenbank muss darüber hinaus die für die Verwaltung der Verzeichnisdaten notwendigen Schemaobjekte enthalten, die im Zuge der Installation angelegt werden. OID-Monitor Der Monitorprozess wird zum Starten und Stoppen sowie zur Beobachtung (monitoring) der LDAP-Instanzen benötigt. Er wird über Befehle angesprochen, welche die OID Control Utility generiert. OID Control Utility OID Control Utility ist ein Werkzeug zum Starten, Stoppen und Konfigurieren von LDAP-Servern. Die für die Konfiguration notwendigen Parameter – z.B. die Anzahl der LDAP-Serverprozesse – werden innerhalb der Verzeichnisdatenbank in so genannten Configuration Set Entries oder Configsets gespeichert. Beim Start einer LDAP-Instanz über die Control Utility wird der gewünschte Configset referenziert.
Installation und Konfiguration Oracle Internet Directory wird über den Oracle Universal Installer und dort über die Produktauswahl MANAGEMENT AND INTEGRATION installiert. Im Zuge der Installation kann auch direkt eine neue Datenbank mit dem UTF8-Zeichensatz und den entsprechenden Schemaobjekten angelegt oder eine 13. Oracle Net Services ist der neue Name für SQL*Net und Net8. Er wurde mit Oracle9i eingeführt.
Sandini Bib
Internet Directory, LDAP und SSL
263
bestehende Instanz für die Verzeichnisdaten verwendet werden. Es ist auf jeden Fall empfehlenswert, die Verzeichnisdaten in einer eigenen Instanz und Datenbank zu speichern. Der Universal Installer installiert ebenfalls das Werkzeug Oracle Directory Manager, über dessen Eingabemasken Verzeichnisdaten verwaltet werden können. Nach der Installation sind eine oder mehrere LDAP-Instanzen zu konfigurieren und zu starten, um mit dem Verzeichnisdienst arbeiten zu können. Die Konfiguration wird – wie bereits erwähnt – über so genannte Configsets vorbereitet, die über den Oracle Directory Manager und dort über den Verzeichnispunkt SERVER-VERWALTUNG, dann DIRECTORY-SERVER erstellt und verwaltet werden können. Das Anlegen neuer Sets erfolgt am besten durch das Kopieren bereits bestehender14. Im nächsten Schritt ist dann der OID-Monitorprozess auf dem Rechner des LDAPServers zu starten: oidmon connect=oid3 sleep=15 start
Im vorangehenden Beispiel kommuniziert der Monitorprozess mit einer Datenbank, die über den Dienstnamen oid3 erreicht wird. Der Dienstname muss dementsprechend im Rahmen der Oracle Net Services – dort z.B. in der Datei tnsnames.ora – definiert worden sein. Im Abstand von 15 Sekunden (sleep = 15) prüft in diesem Beispiel der Monitorprozess, ob neue Anfragen der OID Control Utility vorliegen. Log-Einträge, die das Starten und Stoppen des Monitor-Prozesses dokumentieren, finden sich in der Datei oidmon.log15. Nach dem erfolgreichen Start des Monitor-Prozesses können nun LDAP-Instanzen gestartet werden: oidctl connect=oid3 server=oidldapd instance=3 configset=5 start
Das vorangehende Beispiel startet die LDAP-Instanz (server = oidldapd) mit der Instanznummer 3. Die Anzahl der Serverprozesse und Threads pro Server wurde vorher in dem Configset 5 im Verzeichnisdienst definiert. Dieser Configset wird hier referenziert. Für den ersten Start des LDAP-Servers und als Standardwert steht der Configset mit der Identifizierungsnummer 0 zur Verfügung. Die Serverprozesse der Instanz verbinden sich mit der Verzeichnisdatenbank über den Dienstnamen oid3 (connect-Klausel). Log-Einträge zu den LDAP-Instanzen finden sich in der Datei oidldapdxx.log16 – xx steht dabei für die Instanznummer, in unserem Beispiel also 03. Nach dem erfolgreichen Start der LDAP-Instanz kann nun auf den Verzeichnisdienst – z.B. über das Werkzeug Oracle Directory Manager – zugegriffen werden. Für den Verbindungsaufbau müssen drei Angaben gemacht werden:
: :
Name des Rechners, auf dem die LDAP-Instanz gestartet wurde Portnummer des LDAP-Servers: Standardwerte sind 389 für die normale Verbindung und 683 für die Verbindung über SSL. Für die SSL-Verbindung sind jedoch zusätzlich konfiguratorische Schritte notwendig, so dass diese Portnummer direkt nach einer Installation praktisch nicht genutzt werden kann.
14. Rechte Maustaste Funktion ÄHNLICHE ERSTELLEN. 15. Die Datei befindet sich im Verzeichnis $ORACLE_HOME/ldap/log. 16. Auch diese Datei liegt im Verzeichnis $ORACLE_HOME/ldap/log.
Sandini Bib
264
:
Sicherheit
Benutzername und Passwort eines LDAP-Benutzers. LDAP-Benutzer sind nicht mit Datenbankbenutzern zu verwechseln. Sie werden innerhalb des Verzeichnisdienstes selbst definiert und für die Verwaltung der Verzeichnisdaten genutzt. Der Benutzer orcladmin ist für diese Zwecke mit dem Passwort welcome vordefiniert. Die Änderung dieses Passwortes sowie die Definition weiterer Verzeichnisbenutzer ist über das Werkzeug Oracle Directory Manager jederzeit möglich.
Verzeichnisdaten werden – wie bereits erwähnt – in Baumstrukturen in Form von Entries angelegt. Um Oracle-spezifische Daten, wie z.B. Benutzer- und Datenbanknamen, in Verzeichnissen zu speichern, sind spezifische Objektklassen, Attribute und Regeln notwendig, die als Metadaten in der betreffenden Datenbank gespeichert und zusammenfassend als das Oracle-Schema bezeichnet werden. Während der standardmäßigen Installationsprozedur über den Universal Installer wird dieses Oracle-Schema in der Zieldatenbank bereits aufgebaut. Für manuelle Neu- oder Nachinstallationen dieses Schemas steht das Werkzeug Net Configuration Assistant zur Verfügung. Mit Hilfe der im Oracle-Schema enthaltenen Objektklassen und Attribute können dann über Oracle Contexts individuelle Verzeichnisdaten zu Benutzern, Datenbank- und Dienstnamen eingetragen werden. Ein Oracle-Kontext ist demnach ein administrativer Kontext, der an einem Punkt innerhalb des Verzeichnisbaumes die Speicherung von Oracle-spezifischen Einträgen erlaubt und über den Client-Anwendungen Verzeichnisdaten suchen und abrufen können. Es sind durchaus mehrere Oracle-Kontexte pro Verzeichnisdatenbank möglich. Oracle-Kontexte werden – wie auch Oracle-Schemas – über das Werkzeug Net Configuration Assistant initiiert und können je nach Inhalt über unterschiedliche Werkzeuge verwaltet werden. Einzelheiten hierzu finden sich in den Abschnitten 4.4.3 bis 4.4.5. Jede Oracle-Datenbank, die Verzeichnisdaten enthält, wird demnach durch die folgenden Merkmale charakterisiert:
: : : :
Sie speichert ihre Daten im UTF8-Zeichensatz. Sie enthält im Datenbankschema ods Tabellen, Pakete und Sequenzen zur Speicherung von Metadaten und Benutzerdaten. Das Datenbankschema odscommon verweist über Synonyme auf die Tabellen von ods. Beide Schemas werden im Zuge der Installation zusammen mit einer Reihe von Tablespaces angelegt. Sie enthält Oracle-spezifische Objektklassen und Attribute (Metadaten) in Form eines Oracle-Schemas, das in den Tabellen des Datenbankschemas ods gespeichert wird. Sie enthält einen oder mehrere Oracle-Kontexte, in denen benutzerspezifische Daten – ebenfalls in den Tabellen von ods – gespeichert und von Client-Anwendungen abgerufen werden.
Digitale Zertifikate und SSL Digitale Zertifikate identifizieren Entitäten. Entitäten im Kontext von Oracle können z. B. globale Benutzer, Datenbanken oder Verzeichnisadministratoren sein. Digitale Zertifikate funktionieren vor dem Hintergrund der Public Key-Kryptografie.
Sandini Bib
Internet Directory, LDAP und SSL
265
Bei diesem Paradigma werden zwei verschiedene Schlüssel – ein öffentlicher (public) und ein privater – verwendet. Die Schlüssel werden so generiert, dass die Ableitung des öffentlichen Schlüssels aus dem privaten und umgekehrt mit vertretbarem Rechenaufwand nur schwer möglich ist und es keine Schlüssel gibt, die auf mehr als ein Schlüsselpaar verweisen. Beide Schlüssel können zur Verschlüsselung verwendet werden, die Entschlüsselung kann jedoch nur mit dem jeweils anderen Schlüssel des Paares erfolgen. Eine mit einem öffentlichen Schlüssel verschlüsselte Botschaft kann daher nur mit dem entsprechenden privaten Schlüssel entschlüsselt werden und umgekehrt. Wie die Namen bereits nahe legen, verbleibt der private Schlüssel in den „Händen“ des Benutzers, der öffentliche kann entsprechend verteilt werden. Diese enge Koppelung der beiden Schlüssel eines Schlüsselpaares hat weitreichende Konsequenzen – nicht nur für die Verschlüsselung von Botschaften, sondern auch für die Authentifizierung ihrer Besitzer: Gelingt die Entschlüsselung einer Botschaft – z.B. mit Hilfe eines öffentlichen Schlüssels – kann sich der Empfänger sicher sein, den für den privaten Schlüssel passenden Gegenschlüssel verwendet und damit auch die Authentizität der Botschaft nachgewiesen zu haben. Die Authentizität der Botschaft ist immer dann gegeben, wenn sich der Empfänger über die Zuordnung eines öffentlichen Schlüssels zu einer Entität absolut sicher sein kann. Diese Zuordnung eines öffentlichen Schlüssels zu einer Entität wird in Form eines digitalen Zertifikates beglaubigt, welches von einer Zertifizierungsstelle (certificate authority, CA) „unterschrieben“ ist. Die Unterschrift erfolgt in elektronischer Form durch den privaten Schlüssel der CA. Das Anwendungsprogramm kann dieses beglaubigte Zertifikat mit Hilfe des öffentlichen Schlüssels der unterzeichneten CA „auspacken“. Die öffentlichen Schlüssel von vertrauenswürdigen CAs sind in Form von so genannten Trust Points der betreffenden Anwendung bekannt zu machen, d.h., diese müssen entsprechen installiert werden. Der Standard X.509 legt den genauen Aufbau von digitalen Zertifikaten fest. Zertifikate enthalten neben dem Distinguished Name der betreffenden Entität und dem öffentlichen Schlüssel auch noch eine Seriennummer, ein Verfallsdatum sowie Informationen über die ausstellende CA. Alle identifizierenden Daten einer Entität – das Schlüsselpaar, das Zertifikat sowie vertrauenswürdige Trust Points – werden in Form eines so genannten Wallet gespeichert. Nach dem Öffnen eines Wallets, das über ein Passwort geschützt ist, stehen diese identifizierenden Daten zur Verfügung und können von Anwendungen im Zusammenspiel mit einem Verzeichnisdienst für die Authentifizierung und Autorisierung genutzt werden. Oracle stellt mit dem Oracle Wallet Manager ein Werkzeug zum Generieren von Zertifikatanforderungen und Verwalten von Wallets zur Verfügung. Zertifikatsanforderungen können hier exportiert und – nach der Bearbeitung durch eine vertrauenswürdige Zertifizierungsstelle – wieder importiert werden. Für das Öffnen von Wallets steht neben dem erwähnten Wallet Manager auch noch der Oracle Enterprise Login Assistant zur Verfügung. Benutzern, die – vornehmlich zu Testzwecken oder für den produktiven Einsatz – eine eigene Zertifizierungsstelle betreiben möchten, stehen neben kommerziellen Produkten die Kryptografie-Bibliotheken und Werkzeuge des OpenSSL-Projektes17 kostenfrei zur Verfügung.
Sandini Bib
266
Sicherheit
Für die sichere Kommunikation über Netzverbindungen ist neben der oben beschriebenen Identifizierung des Kommunikationspartners auch die Verschlüsselung und Integritätssicherung der übermittelten Daten wichtig. Secure Sockets Layer (SSL) ist ein Protokoll zur sicheren Kommunikation über Netzverbindungen. SSL sorgt beim Verbindungsaufbau dafür, dass
: : :
Zertifikate ausgetauscht, Verschlüsselungsalgorithmen ausgehandelt, und Integritätsprüfungen durchgeführt werden.
Für die Verschlüsselung benutzt SSL herkömmliche symmetrische Algorithmen, wie z.B. DES oder RC4, die Integritätsprüfung wird mit Hilfe von Hash-Algorithmen, wie z.B. MD5 oder SHA durchgeführt.
4.4.3
Modell 1: Auflösung von Dienstbenennungen
Die Nutzung von Verzeichnisdiensten im Kontext von Oracle-Datenbanken ist in vielfältiger Hinsicht möglich. In unserem ersten Nutzungsmodell werden die Dienstbenennungen von Oracle Net statt über die lokale Datei tnsnames.ora oder – wie in älteren Versionen – über Oracle Names nun über den Verzeichnisdienst aufgelöst. Hierzu sind neben den im Abschnitt Installation und Konfiguration beschriebenen Schritten die folgenden Arbeiten notwendig:
: :
Planung und Definition von Dienstbenennungen im Kontext des Verzeichnisdienstes Konfiguration des Clients
Planung und Definition von Dienstbenennungen Einträge in Verzeichnisdiensten erfolgen – wie bereits in Abschnitt Verzeichnisdienste auf Seite Verzeichnisdienste dargelegt wurde – auf der Basis von Objektklassen im Kontext von Verzeichnisbäumen. Um die in unserem Beispiel geforderten Dienstbenennungen für Oracle Net in Oracle Internet Directory zu platzieren, benötigen wir daher
: : :
Objektklassen, die in der Lage sind, die spezifischen Informationen von OracleDienstbenennungen zu repräsentieren, Einen Wurzelpunkt im Kontext einer Verzeichnishierarchie, unter dem ein OracleKontext aufgebaut werden kann, Konkrete Einträge unter diesem Wurzelpunkt auf der Basis der oben erwähnten Objektklassen, welche die von uns benötigten Dienstbenennungen speichern.
17. Informationen und Downloads finden sich unter der Internetadresse www.openssl.org.
Sandini Bib
Internet Directory, LDAP und SSL
267
In diesem Beispiel gehen wir davon aus, dass die spezifischen Objektklassen (Oracle-Schema) bereits im Rahmen der Installationsprozedur oder nachträglich über den Oracle Net Configuration Assistant aufgebaut wurden. Die nötigen Objektklassen sind also bereits vorhanden. Unser Ziel ist es nun, die vier Testdatenbanken der Firma Database Consult – t1 und t2 in Jachenau sowie t3 und t4 in München – gemäß ihrer physischen Lokation auf zwei unterschiedliche Domänen – jachenau.databaseconsult.de und muenchen.databaseconsult.de – zu verteilen. In diesen beiden Domänen stehen de für das Land, databaseconsult für die Organisation sowie jachenau und muenchen für die Organisationseinheiten. Diesen Domänen werden die Namen der Datenbanken vorangestellt, woraus sich dann die folgenden Dienstbenennungen ergeben:
:
:
t1.jachenau.databaseconsult.de und t2.jachenau.databaseconsult.de t3.muenchen.databaseconsult.de und t4.muenche.databaseconsult.de
Übersetzt in die hierarchische Baumstruktur des Verzeichnisdienstes ergeben sich daraus folgende Einträge:
:
: : :
An der Wurzel der Eintrag auf der Basis der Objektklasse country mit den identifizierenden Attributwerten c=de und dem gleich lautenden relativen eindeutigen Namen Darunter das Objekt der Objektklasse organization mit den Attributwerten o=databaseconsult
Unter der Organisation die Objekte ou=jachenau und ou=muenchen, die beide der Klasse organizationalUnit angehören Die Datenbanken t1 bis t4 werden über Objekte der Objektklasse orclDBServer mit den Attributwerten cn=t1 etc. erfasst. Die Syntaxregeln von Oracle Net erfordern es jedoch, dass unmittelbar oberhalb dieses Objektes der bereits erwähnte Oracle-Kontext in Form eines Objektes der Klasse orclContext mit dem Attributwert cn=OracleContext angelegt wird. Für die in diesem Beispiel gegebene Verzeichnisstruktur sind aus diesem Grunde zwei getrennte Oracle-Kontexte aufzubauen.
Der global eindeutige Name für die Datenbank t1 würde in diesem Modell daher im Verzeichnis wie folgt definiert sein: DN: cn=t1,cn=OracleContext,ou=jachenau,o=databaseconsult,c=de
Zur praktischen Umsetzung des oben beschriebenen Konzeptes sind die folgenden Schritte notwendig: 1. Das Objekte c=de ist explizit über das Werkzeug Oracle Directory Manager anzulegen. Hierzu wird – wie die Abbildung zeigt – unter dem Verzeichnispunkt EINTRAGSVERWALTUNG ein entsprechendes Objekt der Klasse country erzeugt.
Sandini Bib
268
Sicherheit
URRW
F GH R GDWDEDVHFRQVXOW RX MDFKHQDX FQ RUDFOH&RQWH[W &Q W
Abbildung 4.3: Directory Information Tree für einen Oracle-Servicenamen
Abbildung 4.4: Anlegen eines neuen Country-Objektes im Oracle Directory Manager
Sandini Bib
Internet Directory, LDAP und SSL
269
2. Gleichermaßen werden die Objekte o=databaseconsult unterhalb von c=de und ou=jachenau bzw. ou=muenchen unterhalb von o=databaseconsult angelegt. 3. Der Oracle-Kontext wird mit Hilfe des Werkzeuges Oracle Net Configuration Assistant und dort über die Auswahl KONFIGURATION VON DIRECTORY SERVICE ACCESS sowie nachfolgend NEUEN ORACLE CONTEXT ERSTELLEN angelegt. Das Werkzeug generiert nach erfolgreicher Anmeldung an den Verzeichnisdienst unter dem anzugebenden administrativen Kontext die notwendigen Objekte. In unserem Beispiel sind die administrativen Kontexte ou=jachenau,o=databaseconsult,c=de bzw. ou=jachenau, o=databaseconsult, c=de. Dementsprechend werden unterhalb der genannten Verzeichnispunkte jeweils die Objekte cn=OracleContext mit einigen Untereinträgen aufgebaut. 4. Im nächsten Schritt können nun die Dienstbenennungen angelegt werden. Hierbei sind unterschiedliche Vorgehensweisen möglich: Dienstnamen können explizit über das Werkzeug Oracle Net Manager18 und dort über die Baumauswahl VERZEICHNIS angelegt werden. Vorhandene Dienstnamen können – ebenfalls über Oracle Net Manager – aus einer lokalen Datei tnsnames.ora importiert werden. Der Import erfolgt stets im Kontext einer Domäne der Datei. Diese Domäne wird jeweils einem administrativen Kontext des Verzeichnisdienstes zugeordnet. Es ist auf diese Weise also auch möglich, Domänen zu „migrieren“. Die betreffenden Datenbanken können bei dem Verzeichnisdienst über das Werkzeug Database Configuration Assistant registriert werden. Diese Vorgehensweise ist überall dort empfehlenswert, wo auch an eine Authentifizierung und Autorisierung über Verzeichnisdienste gedacht wird. Dienstnamen können ebenfalls aus dem – in Zukunft nicht mehr unterstützten – Werkzeug Oracle Names übernommen werden. Hierzu bietet das Werkzeug namesctl den Befehl dump_ldap, der eine Ldif-Datei erzeugt, die zum Import in den Verzeichnisdienst genutzt werden kann. Auch hier ist die Migration von Domänen möglich. Damit sowohl der Oracle Net Manager als auch der Datenbank-Konfigurationsassistent die Generierung der Objekte fehlerfrei durchführen können, ist vorher der Client, wie im folgenden Abschnitt beschrieben, zu konfigurieren! Konfiguration des Clients Die Konfiguration von Clients ist – im Gegensatz zu der des Verzeichnisdienstes – recht einfach durchzuführen. Hierzu sind die folgenden Aktionen durchzuführen: 1. Konfiguration der Methode für die Auflösung von Dienstnamen 2. Konfiguration des vorbereiteten Verzeichnisdienstes in Form der Portnummern, des Servernamens und des Diensttyps
18. Unter der Version 8i hieß dieses Tool Net8 Assistant.
Sandini Bib
270
Sicherheit
3. Auswahl eines administrativen Kontextes, d.h. des für den betreffenden Client relevanten Wurzelpunktes in dem Verzeichnisbaum Alle genannten Aktionen lassen sich über Werkzeuge erledigen. Punkt 1, die Methode der Namensauflösung, wird im Netzprofil des Clients mit Hilfe des Werkzeugs Oracle Net Manager19 definiert und in der Datei sqlnet.ora gespeichert. Das folgende Beispiel zeigt den relevanten Ausschnitt aus dieser Datei. LDAP, das heißt der Verzeichnisdienst, wird hier als erste Wahl der Namensauflösung festgeschrieben. Für den Fall, dass eine Auflösung über LDAP nicht erfolgreich sein sollte, kann die lokale Datei tnsnames.ora herangezogen werden: names.directory_path = (LDAP, TNSNAMES)
Für die Konfiguration der Punkte 2 und 3 ist leider ein anderes Werkzeug, der Oracle Net Configuration Assistant20, zuständig. Dort führen die Auswahlpunkte KONFIGURATION VON DIRECTORY SERVICE ACCESS und danach KONFIGURIEREN SIE DIESES ORACLE-STANDARDVERZEICHNIS ... zu einem Dialog, der die relevanten Informationen abfragt. Die Ergebnisse werden in der Datei ldap.ora gespeichert: # LDAP.ORA Network Configuration File: # c:\oracle\ora9\network\admin\ldap.ora # Generated by Oracle configuration tools. default_admin_context = "ou=jachenau,o=databaseconsult,c=de" directory_servers = (oid_server:389:636) directory_server_type = OID Listing 4.3: Datei ldap.ora
In diesem Beispiel wird dem Client der Verzeichnisdienst vom Typ Oracle Internet Directory auf dem Server oid_server bekannt gegeben. Die Portnummer für unverschlüsselte, normale Verbindungen ist 389, SSL-Verbindungen werden über den Port 636 aufgebaut. Nicht voll spezifizierte Dienstnamen werden in dem Oracle Kontext, der sich unter dem Wurzelpunkt ou=jachenau,o=databaseconsult,c=de befindet, gesucht. Für Namen aus anderen Domänen, ist die volle Namensspezifikation anzugeben. Dem entsprechend lässt sich die Datenbank t1.jachenau.databaseconsult.de über t1 erreichen: sqlplus scott/tiger@t1
Der Dienstname t1 wird für den Zugriff auf den Verzeichnisdienst umgewandelt in cn=t1,cn=OracleContext,ou=jachenau,o=databaseconsult,c=de
Für den Zugriff auf die Datenbank t3 in der Domäne muenchen.databaseconsult.de ist dagegen die volle Spezifikation des Namens notwendig: sqlplus scott/[email protected]
19. Unter Oracle 8i heißt dieses Werkzeug Oracle Net8 Assistant. 20. Der alte Name lautet Oracle Net8 Configuration Assistant.
Sandini Bib
Internet Directory, LDAP und SSL
271
Die Namensauflösung über Verzeichnisdienste ist – wegen des erforderlichen Zugriffs auf den Verzeichnisdienst – geringfügig aufwändiger als die über die lokale Datei tnsnames.ora. Dem stehen jedoch die Vorteile der zentralen Namensverwaltung gegenüber.
4.4.4
Modell 2: Authentifizierung globaler Benutzer
Die Authentifizierung globaler Benutzer bietet Anwendern die Möglichkeit, Verbindungen zu entfernten Datenbanken ohne Angabe von Passwörtern aufzubauen. Der Anwender wird dabei mit dem globalen Datenbankbenutzer der Zieldatenbank verbunden, dessen global eindeutiger Name (distinguished name) identisch ist mit dem des geöffneten Wallets auf der Seite des betreffenden Clients. Verzeichnisdienste werden in diesem Modell nicht benötigt, wohl aber der Verbindungsaufbau über das SSL-Protokoll. Im Einzelnen sind für die Umsetzung dieses Modells die folgenden Konfigurationsschritte notwendig: 1. Generieren, Anfordern und Beglaubigen von digitalen Zertifikaten für Clients und Datenbanken 2. Anlegen der erforderlichen globalen Benutzer in den betreffenden Zieldatenbanken 3. Konfiguration des Listener-Prozesses der Datenbank für den Verbindungsaufbau über das SSL-Protokoll 4. Bereitstellen von Dienstnamen für die Herstellung der SSL-Verbindungen 5. Konfiguration des Clients für den Verbindungsaufbau über SSL Diese Konfigurationsschritte werden im Folgenden detailliert erläutert. Anlegen von Zertifikaten Die Grundlagen von Zertifikaten wurden bereits im Abschnitt Digitale Zertifikate und SSL besprochen. In unserem Beispiel wird zunächst mit Hilfe des Werkzeugs Oracle Wallet Manager über die Menüpunkte WALLET und NEU eine voll spezifizierte Zertifikatsanforderung für folgende Identität erstellt: DN: cn=guenter, ou=jachenau, o=databaseconsult, l=laich, st=bayern, c=de. Die Attribute Organization Unit, Organization, Locality (L) und State (ST) sind dabei optional. Bei der Generierung ist ferner ein entsprechendes Passwort anzugeben und eine Schlüssellänge – am besten, weil sichersten 1.024 Bit – auszuwählen. Die Anforderung wird im vorgeschlagenen Standardverzeichnis21 gespeichert und dann über die Menüpunkte VORGÄNGE und ZERTIFIKATSANFORDERUNG EXPORTIEREN in eine Datei geschrieben. Diese Exportdatei muss nun an eine vertrauenswürdige Zertifizierungsstelle übermittelt werden. Von dort erhält der Anwender das beglaubigte Zertifikat in Form einer Datei zurück. Nach dem Öffnen der Zertifikatsanforderung im Oracle Wallet Manager ist diese Datei dann über die Menüpunkte VORGÄNGE und BENUTZERZERTIFIKAT IMPORTIEREN einzulesen. Die Zertifikatsanforderung erhält dadurch den Status bereit und mutiert zu einem beglaubigten Zertifikat, sofern die 21. Unter Windows2000: c:\Dokumente und Einstellungen\Administrator\ORACLE\WALLETS
Sandini Bib
272
Sicherheit
ausstellende Zertifizierungsstelle mit ihrem Zertifikat als „vertrauenswürdig“ im Oracle Wallet Manager aufgenommen wurde. Die Zertifikate vertrauenswürdiger Zertifizierungsstellen erscheinen dort unter dem Verzeichnispunkt GESCHÜTZTE ZERTIFIKATE. Zusätzliche Trust Points lassen sich über die Menüpunkte VORGÄNGE und GESCHÜTZTES ZERTIFIKAT IMPORTIEREN anfügen. Zertifikate und ihnen anhängende Informationen werden in Form eines Wallets in der Datei ewallet.der in dem angegebenen Verzeichnis gespeichert, unabhängig davon, wie der Distinguished Name angegeben wurde. Zertifikate für unterschiedliche Identitäten auf einem Client sind daher in unterschiedlichen Verzeichnissen abzulegen. Für erfolgreich geöffnete Wallets existiert zusätzlich in demselben Verzeichnis die Datei cwallet.sso.
Abbildung 4.5: Oracle Wallet Manager mit Benutzerzertifikat
In gleicher Weise werden Zertifikate für die erforderlichen Datenbanken generiert. Definition globaler Benutzer Im nächsten Schritt sind entsprechend den Zertifikaten globale Benutzer in den betreffenden Datenbanken zu definieren. Beim Anlegen der Benutzer ist darauf zu achten, dass die global eindeutigen Namen beider Identitäten einschließlich der Groß- und Kleinschreibung genau übereinstimmen. In unserem Beispiel wird der Datenbankbenutzer GUENTER mit einem dem Zertifikat entsprechenden Distinguished Name in der Datenbank erzeugt:
Sandini Bib
Internet Directory, LDAP und SSL
273
SQL> CREATE USER guenter PROFILE default IDENTIFIED GLOBALLY AS 'cn=guenter, ou=jachenau, o=databaseconsult, l=laich, st=bayern, c=de' DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp ACCOUNT UNLOCK; Listing 4.4: Erstellen eines globalen Users
Da der Benutzer ohne Passwort angelegt wird, ist ein normaler Connect von vornherein nicht möglich. Verbindungen mit diesem Benutzer können nur über eine SSL-Verbindung aufgebaut werden. Es versteht sich, dass der Benutzer ebenso über das Werkzeug Oracle Security Manager angelegt werden kann. Den Anforderungen entsprechende Privilegien sind danach über geeignete GRANT-Befehle zu erteilen. Datenbank-Listener konfigurieren Bevor eine SSL-Verbindung zur Datenbank hergestellt werden kann, ist der Listener-Prozess entsprechend zu konfigurieren oder ein separater Listener-Prozess zu starten. Diese Aufgabe ist mit Hilfe des Werkzeugs Oracle Net Manager zu erledigen. Im Kontext des Listeners sind die folgenden Einstellungen durchzuführen:
: :
:
Anlegen einer neuen Listener-Adresse für das TCPS-Protokoll (TCP/IP mit SSL), das für die SSL-Verbindung erforderlich ist. In diesem Zusammenhang ist auch die Angabe einer Portnummer notwendig – die Nummer 2484 wurde für diese Zwecke von Oracle offiziell reserviert und wird aus diesem Grunde hier empfohlen. Konfiguration des Verzeichnisses, in dem das Datenbankzertifikat gespeichert wurde: Diese Einstellungen werden über den Verzeichnispunkt PROFIL des Net Managers und dort über die Kontextauswahl ORACLE ADVANCED SECURITY und die Karteikarte SSL vorgenommen. Nach Auswahl der Option SERVER ist das entsprechende Verzeichnis anzugeben. Es ist darauf zu achten, dass an diesem Ort nicht nur das Wallet installiert wurde, sondern dass für dieses nach dem Öffnen im Oracle Wallet Manager die Option AUTOMATISCHE ANMELDUNG22 aktiviert wurde, damit das Zertifikat für andere Anwendungen – hier den Listener – nutzbar ist. Am gleichen Ort sind auch die vom Server unterstützten kryptografischen Algorithmen (cipher suite) und die SSL-Version auszuwählen.
Die Konfiguration wird vom Oracle Net Manager in den Dateien listener.ora und sqlnet.ora gespeichert. Die nachfolgenden Listings zeigen die relevanten Ausschnitte.
22. Dort unter dem Menüpunkt WALLET
Sandini Bib
274
Abbildung 4.6: Oracle Net Manager mit SSL-Konfiguration
OSS.SOURCE.MY_WALLET = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = c:\winnt\profiles\administrator\oracle\wallets) ) ) .... LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCPS)(HOST = t1_host)(PORT = 2484)) ) ... SSL_CLIENT_AUTHENTICATION = FALSE Listing 4.5: Ausschnitte aus der Datei listener.ora auf dem Server
SSL_CIPHER_SUITES= (SSL_RSA_WITH_RC4_128_MD5) ... SSL_VERSION = 3.0 Listing 4.6: Ausschnitte aus der Datei sqlnet.ora auf dem Server
Sicherheit
Sandini Bib
Internet Directory, LDAP und SSL
275
Dienstnamen für SSL definieren Es versteht sich, dass für den Verbindungsaufbau über SSL wegen der speziellen Portnummer ein vorhandener Dienstname modifiziert oder ein eigener aufgebaut werden muss. Je nachdem, wie Dienstnamen auf den jeweiligen Clients aufgelöst werden, kann dieser Name lokal in der Datei tnsnames.ora oder zentral im Kontext eines Verzeichnisdienstes definiert werden. Das folgende Beispiel zeigt einen Ausschnitt der Datei tnsnames.ora für den Dienstnamen t1_ssl.jachenau.databaseconsult.de: t1_ssl.jachenau.databaseconsult.de = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCPS)(HOST = t1_server)(PORT = 2484)) ) (CONNECT_DATA = (SERVICE_NAME = t1.jachenau.databaseconsult.de) ) ) Listing 4.7: Ausschnitt aus der Datei tnsnames.ora auf dem Client
Wallet für Client konfigurieren Neben dem Dienstnamen müssen für den Verbindungsaufbau des Clients das Verzeichnis des Wallets, die unterstützten kryptografischen Algorithmen und die SSLVersion angegeben werden. Die Einstellungen erfolgen wiederum über den Oracle Net Manager analog den Angaben, die in Abbildung 4.6 gemacht wurden, mit dem Unterschied, dass hier als Kontext die Option CLIENT aktiviert wird. Alle Angaben werden im Netzprofil in der Datei sqlnet.ora gespeichert, die hier in Auszügen abgedruckt ist: SSL_CIPHER_SUITES= (SSL_RSA_WITH_RC4_128_MD5) ... OSS.SOURCE.MY_WALLET = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = c:\Dokumente und Einstellugen\Administrator\ORACLE\WALLETS) ) ) ... SSL_VERSION = 3.0 Listing 4.8: Ausschnitt aus der Datei sqlnet.ora auf dem Client
Sandini Bib
276
Sicherheit
Bevor nun der erste Verbindungstest durchgeführt wird, sollte noch einmal überprüft werden, ob die Zertifikate auf dem Client und dem Server für die automatische Anmeldung konfiguriert und entsprechend geöffnet wurden. Zeigt das Werkzeug Enterprise Login Assistant eine grüne Ampel, sind die Zertifikate operationsbereit. Ein weiterer Blick sollte auf die SSL-Versionen (Parameter SSL_VERSION) und den kryptografischen Algorithmus (Parameter SSL_CIPHER_ SUITES) geworfen werden. Hier müssen auf beiden Seiten der Verbindung identische Einstellungen vorliegen. Bei der Komplexität der Konfiguration und der Vielzahl der zu verwendenden Werkzeuge können sich hier sehr leicht Fehler einschleichen. Die Fehlermeldungen, die beim Connect ausgeworfen werden, sind leider nicht immer so prägnant, dass die Ursache des Problems sofort ersichtlich wird. Schließlich kann der Verbindungstest erfolgen: sqlplus /@t1.jachenau.databaseconsult.de
Die Verbindung sollte nun zu dem globalen Benutzer guenter der Zieldatenbank hergestellt werden, dessen global eindeutiger Name mit dem Distinguished Name des geöffneten Zertifikats übereinstimmt.
4.4.5
Modell 3: Enterprise-Benutzer und Enterprise-Rollen
In diesem dritten Nutzungsmodell wird die feste Bindung eines globalen Datenbankbenutzers an ein Zertifikat, die im Abschnitt 4.4.4 beschrieben wurde, aufgebrochen. Enterprise-Benutzer sind globale Benutzer, die ohne Zuordnung eines Distinguished Name in der Datenbank definiert werden. Die Zuordnung von Zertifikaten und ihren Identitäten zu den Benutzern vorgegebener Datenbanken erfolgt ausschließlich über einen Verzeichnisdienst. Auf diese Weise lassen sich mehrere Zertifikate an einen Datenbankbenutzer binden, daher der Begriff Shared Schema. Da möglicherweise nicht alle Identitäten, die ein Shared Schema benutzen, die gleichen Privilegien erhalten dürfen, lassen sich Rollen ebenso über Verzeichnisdienste zuteilen: In der Datenbank definierte globale Rollen mit ihren Privilegien werden Enterprise-Rollen zugeordnet, die im Kontext des Verzeichnisdienstes ohne Angabe von Privilegien angelegt wurden. Über den Verzeichnisdienst werden dann die Enterprise-Rollen den Enterprise-Benutzern im Kontext bestimmter Zieldatenbanken zugeordnet. Für dieses Modell sind die folgenden Komponenten notwendig:
: : : :
Verzeichnisdienst/ LDAP-Dienst mit entsprechenden Einträgen Zertifikate für Benutzer und Datenbanken Datenbanken mit globalen Benutzern und globalen Rollen SSL-Verbindungen zu den betreffenden Datenbanken
Zur Implementierung dieses Modells sind dementsprechend die folgenden Arbeiten durchzuführen:
Sandini Bib
Internet Directory, LDAP und SSL
277
1. Grundinstallation des Verzeichnisdienstes mit dem Aufbau des Oracle-Schemas und des Oracle-Kontextes 2. Registrierung der betreffenden Datenbanken bei dem Verzeichnisdienst 3. Anlegen von globalen Benutzern und Rollen in den Datenbanken 4. Anlegen von Enterprise-Benutzern und –Rollen in dem Verzeichnisdienst 5. Konfiguration der Datenbankserver 6. Konfiguration der Clients Diese Aufgaben sollen nun – sofern dies nicht schon in vorangehenden Abschnitten geschehen ist – im Detail besprochen werden: Registrierung der Datenbanken Die Registrierung der Datenbanken erfolgt über das Werkzeug Oracle Database Configuration Assistant. Über die Option ÄNDERN EINER DATENBANK wird im vierten Schritt die Registrierungsmaske erreicht, in der die Authentifizierung an den Verzeichnisdienst und im Anschluss daran die Registrierung selbst erfolgt. Damit die Verbindung zum Verzeichnisdienst erfolgreich aufgebaut werden kann, muss vorher der Client für den Zugriff auf den Dienst konfiguriert worden sein, d.h., die Datei ldap.ora muss – auf der Seite des Servers – den Server, den administrativen Kontext sowie die Portnummer für die Verbindung entsprechend dem Syntaxbeispiel auf Seite 270 ausweisen. Entsprechend werden unter dem administrativen Kontext Einträge der Objektklassen generiert. Gleichzeitig wird die betreffende Parameterdatei der Datenbank durch den Parameter rdbms_server_dn ergänzt. Dieser Parameter wird mit dem im Verzeichnis registrierten Distinguished Name der Datenbank belegt und ermöglicht später die Zuordnung der Datenbank zu einem Verzeichniseintrag und über diesen die Zuordnung globaler Benutzer und Rollen zu entsprechenden Enterprise-Einträgen. Für die in unserem Beispiel verwendete Datenbank t1.jachenau.databaseconsult.de wird der folgende Parameterwert generiert: rdbms_server_dn = "cn=t1,cn=OracleContext,ou=jachenau,o=databaseconsult,c=DE"
Beachtung verdient cn=OracleContext. Der relativ eindeutige Name (relative distinguished name) cn=OracleContext wird beim Zugriff von den Oracle-Werkzeugen entsprechend ausgefiltert. Eine Änderung dieses Parameters ohne Anpassung des entsprechenden Verzeichniseintrags führt zu Fehlfunktionen! Es versteht sich, dass der statische Parameter durch einen Neustart der Datenbank aktiviert werden muss. Globale Benutzer und globale Rollen Globale Benutzer, die von unterschiedlichen digitalen Identitäten benutzt werden sollen (shared schema), dürfen selbst keine Distinguished Names enthalten. Dementsprechend wird beispielsweise der „offene“ globale Benutzer jedermann mit leerer AS-Klausel wie folgt aufgebaut:
Sandini Bib
278
Sicherheit
CREATE USER jedermann PROFILE DEFAULT IDENTIFIED GLOBALLY AS '' DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp; Listing 4.9: Globaler Benutzer
Da jedermann von unterschiedlichen Identitäten mit möglicherweise unterschiedlichen Anforderungen an die erforderlichen Privilegien genutzt werden kann, wird ihm lediglich das Privileg CREATE SESSION zugewiesen: GRANT CREATE SESSION TO jedermann;
Im nächsten Schritt sind für jedes erforderliche Privilegienbündel, das für die Nutzung der globalen Benutzer notwendig ist, entsprechende globale Rollen anzulegen. Das Beispiel zeigt die Syntax für die globale Rolle r_global1: CREATE ROLE r_global1 IDENTIFIED GLOBALLY;
Es versteht sich, dass diesen Rollen über GRANT-Befehle die notwendigen Privilegien zuzuweisen sind. Im Gegensatz zu „normalen“ Rollen werden sie jedoch nicht mit Datenbankbenutzern verbunden. Enterprise-Benutzer und Enterprise-Rollen Die Grundlagen, die beim Anlegen eines Oracle-Kontextes zu beachten sind, wurden bereits eingehend erläutert. In diesem Modell müssen nun zusätzlich unter einem administrativen Kontext Benutzereinträge angelegt werden, die den Datenbankbenutzern zuzuordnen sind. Alle Aufgaben in diesem Zusammenhang werden am besten über das Werkzeug Oracle Enterprise Security Manager23 erledigt, das alle notwendigen Verzeichniseinträge generiert. Über die Menüpunkte OBJEKT und ERSTELLEN ... wird dort eine Eingabemaske erreicht, über die nach Auswahl des Typs VERZEICHNISBENUTZER ein Enterprise Benutzer im Verzeichnisdienst angelegt werden kann. Das unten stehende Beispiel zeigt die Anlage des Benutzers DN: cn=guenter, ou=jachenau, o=databaseconsult, c=DE. Dem Verzeichnisbenutzer ist im nächsten Schritt ein Datenbankschema zuzuordnen. Die Zuordnung geschieht entweder im Kontext einer konkreten Zieldatenbank oder im Kontext einer Enterprise-Domäne, in der eine oder mehrere Datenbanken zusammengefasst sein können. Das folgende Beispiel ordnet dem Benutzer cn=guenter den Datenbankbenutzer JEDERMANN im Rahmen der EnterpriseDomäne oracledefaultdomain zu, der standardmäßig alle im Verzeichnisdienst registrierten Datenbanken angehören.
23. Dieses Werkzeug darf nicht mit dem Oracle Security Manager verwechselt werden, das für die Verwaltung von Datenbankbenutzern und Rollen Verwendung findet.
Sandini Bib
Internet Directory, LDAP und SSL
279
Abbildung 4.7: Anlegen eines Enterprise-Benutzers über den Oracle Enterprise Security Manager
Abbildung 4.8: Datenbankschemazuordnung im Oracle Enterprise Security Manager
Die Abbildung 4.8 zeigt, dass Enterprise-Rollen im Kontext von Enterprise-Domänen definiert werden. Als Nächstes wird dementsprechend über den Menüpunkt OBJEKT, dann ERSTELLEN... unter dem Typ Enterprise-Rolle die Rolle r_enterprise1 angelegt. Diese neue Rollen kann dann – wie die folgende Abbildung zeigt – angewählt und über die Karteikarte GLOBALE ROLLEN die Zuordnung vorgenommen werden. Die verfügbaren globalen Rollen werden nach Auswahl der Datenbank direkt von dort eingelesen. Entsprechend ist über ein eingeblendetes Fenster der Connect an die betreffende Datenbank durchzuführen.
Sandini Bib
280
Sicherheit
Abbildung 4.9: Zuordnung von Enterprise-Rollen und globalen Rollen
In einem letzten Schritt sind nun noch die Enterprise-Benutzer und die EnterpriseRollen miteinander zu verknüpfen. Dies kann entweder über die in Abbildung 4.9 sichtbare Karteikarte BERECHTIGTE BENUTZER/GRUPPEN oder über die Anwahl der entsprechenden berechtigten Benutzer in der Baumauswahl erfolgen. Client- und Server-Konfiguration Die Arbeit mit Enterprise-Benutzern erfordert den Verbindungsaufbau über das SSL-Protokoll. Aus diesem Grunde benötigen wir sowohl für die Datenbank als auch für den Client-Rechner beglaubigte Zertifikate. Entsprechend sind auf der Seite jeder beteiligten Datenbank die folgenden Einstellungen vorzunehmen, deren Details bereits in Abschnitt 4.4.4 beschrieben wurden:
:
: : :
Installation eines Wallets mit den Schlüsseln und dem Zertifikat für die Datenbank bzw. den Client. Für das Wallet muss die Option AUTOMATISCHE ANMELDUNG aktiviert sein. Verweise auf das installierte Wallet aus den Dateien sqlnet.ora und listener.ora heraus mit Hilfe des Parameters oss.source.my_wallet Auswahl geeigneter Verschlüsselungsalgorithmen in der Datei sqlnet.ora über den Parameter ssl_cipher_suites Konfigurieren des Datenbank-Listeners für Verbindungen über das TCPS-Protokoll (SSL) über die Datei listener.ora
Sandini Bib
Internet Directory, LDAP und SSL
:
281
Definieren des zuständigen Verzeichnisdienstes über die Datei ldap.ora, damit die Datenbank die Schemazuordnungen abfragen kann
Die Vorbereitung jedes Clients entspricht mit Ausnahme des nicht vorhandenen Listener-Prozesses der auf der Seite der Datenbank. Zusätzlich ist hier auch noch ein entsprechender Dienstname für die Verbindung über den vorgesehenen SSLPort – in der Regel 2484 – bereitzustellen. Schlussbetrachtung Dieses dritte Kommunikationsmodell ist mit Abstand das komplexeste von allen hier besprochenen. Eine große Zahl von Komponenten – Client, Verzeichnisdienst und Datenbank – muss aufeinander abgestimmt werden. Schon bei kleinen Fehlern, etwa in der Einstellung der SSL-Version oder der kryptografischen Algorithmen, kann es zu Fehlfunktionen kommen, die einen Verbindungsaufbau unmöglich machen. Leider sind die zurückgegebenen Fehlermeldungen nicht immer aufschlussreich genug für eine schnelle Fehlerbehebung. Die Komplexität wird noch erhöht durch die Palette an einzusetzenden Werkzeuge: Directory Manager, Net8 Configuration Assistant, Net8 Assistant, Database Configuration Assistant, Enterprise Security Manager, Security Manager, Wallet Manager und nicht zuletzt Enterprise Login Assistant müssen im richtigen Kontext und in der richtigen Reihenfolge zum Einsatz kommen! Eine integrierte Oberfläche tut hier Not. Trotz alledem bieten Verzeichnisdienste für Oracle-Datenbanken sehr elegante Möglichkeiten der zentralisierten Benutzer- und Privilegienverwaltung.
4.4.6
Verwaltung von Oracle Internet Directory
In den vorangehenden Abschnitten haben wir uns auf die Grundlagen von Verzeichnisdiensten sowie die Möglichkeiten der Authentifizierung und Autorisierung von Clients konzentriert. In der Praxis kommen zu den hier dargestellten Aufgabenbereichen jedoch eine Reihe weiterer, nicht minder bedeutsamer, hinzu, die hier aus Platzgründen jedoch nur stichwortartig erwähnt werden können:
: : : : : : : :
Konfiguration gesicherter Zugriffe auf das Verzeichnis über SSL-Verbindungen und Installation eines Wallets für den Dienst Anlegen von Benutzern für die Verwaltung bestimmter Bereiche des Verzeichnisses, z.B. zum Registrieren von Datenbanken oder Dienstnamen Vergabe von Lese- und Schreibrechten auf Bereichen des Verzeichnisbaumes Replikation von Verzeichnisdiensten, um die Ausfallsicherheit zu erhöhen Aufbau von Namensbereichen (naming context) und Aufteilung der Verzeichnisdaten über mehrere LDAP-Server Synchronisation mit Metadirectories Konfiguration einer Audit-Log-Verwaltung Tuning des LDAP-Servers durch den Start mehrerer LDAP-Instanzen und -Prozesse
Sandini Bib
282
4.5
Sicherheit
Privilegien und Rollen
Unabhängig davon, wie wir Benutzer authentifizieren, ob intern in der Datenbank oder extern über Verzeichnisdienste, letztlich werden die Privilegien für den Zugriff in der betreffenden Datenbank selbst definiert. Hierzu stehen uns Systemprivilegien, Objektprivilegien und Rollen zur Verfügung. Die Privilegien können dabei entweder einem Benutzer – einzeln oder in Form von Rollen – direkt zugeordnet oder ohne jede Zuordnung in Form von Rollen zusammengefasst werden. Im letzteren Fall muss die Kopplung von Benutzern und Rollen über externe Mechanismen, wie z.B. Verzeichnisdienste, erfolgen.
4.5.1
Systemprivilegien
Durch Systemprivilegien wird festgelegt, welche Aktionen ein Benutzer innerhalb einer Oracle-Datenbank durchführen darf. Daher stimmt der Name der Systemprivilegien in den meisten Fällen mit SQL-Befehlen überein. Die Liste der Systemprivilegien ist sehr umfangreich. Das hat zur Folge, dass die Datenbankrechte jedes einzelnen Benutzers exakt an seine Aufgaben angepasst werden können. In Abschnitt 4.5.3 wird erläutert, wie Rollen dazu benutzt werden können, die Administration der Systemprivilegien zu vereinfachen, indem diese gruppiert und als Ganzes an Benutzer vergeben werden. Die folgende Tabelle enthält alle verfügbaren Systemprivilegien, gruppiert nach Bereichen oder Objekttypen, die sie betreffen. Bereich
Privileg
Berechtigung zu ...
Analysieren
ANALYZE ANY
Analysieren sämtlicher Tabellen, Indizes und Cluster in der Datenbank
Auditing
AUDIT ANY
Audit auf allen Datenbankobjekten
AUDIT SYSTEM
Privilegien- und Kommando-Audit
CREATE USER
Erstellen von Benutzern
BECOME ANY USER
Ein anderer Benutzer werden (für FULLImports benötigt)
ALTER USER
Verändern von Benutzerparametern anderer Benutzer (für eigenes Passwort nicht notwendig)
DROP USER
Benutzer entfernen
CREATE CLUSTER
Cluster im eigenen Schema anlegen
CREATE ANY CLUSTER
Cluster in beliebigem Schema anlegen
ALTER ANY CLUSTER
beliebige Cluster verändern
Benutzer
Cluster
DROP ANY CLUSTER
beliebige Cluster entfernen
Datenbank
ALTER DATABASE
Datenbank ändern (Status, Log-Gruppen usw.)
SYSTEM
ALTER SYSTEM
ALTER SYSTEM-Befehle ausführen
AUDIT SYSTEM
AUDIT-Befehl für SQL-Befehle ausführen
Sandini Bib
Privilegien und Rollen
283
Bereich
Privileg
Berechtigung zu ...
Context
CREATE ANY CONTEXT
Namensbereich für Kontexte anlegen
DROP ANY CONTEXT
Namensbereich für Kontexte löschen
CREATE DATABASE LINK
Datenbank-Links im eigenen Schema anlegen
CREATE PUBLIC DATABASE LINK
Public Datenbank-Links anlegen
DROP PUBLIC DATABASE LINK
Public Datenbank-Links entfernen
CREATE DIMENSION
Eigene Dimension anlegen
CREATE ANY DIMENSION
Dimension in beliebigem Schema anlegen
ALTER ANY DIMENSION
Dimension in beliebigem Schema ändern
DROP ANY DIMENSION
Dimension in beliebigem Schema löschen
CREATE ANY DIRECTORY
Aliasname für Verzeichnis anlegen
DROP ANY DIRECTORY
Aliasname für Verzeichnis löschen
CREATE INDEXTYPE
Eigenen Indextyp anlegen
CREATE ANY INDEXTYPE
Indextyp in beliebigem Schema anlegen
ALTER ANY INDEXTYPE
Indextyp in beliebigem Schema ändern
DROP ANY INDEXTYPE
Indextyp in beliebigem Schema löschen
EXECUTE ANY INDEXTYPE
Indextyp in beliebigem Schema referenzieren
CREATE ANY INDEX
Indizes in beliebigem Schema auf beliebiger Tabelle anlegen
ALTER ANY INDEX
beliebigen Index ändern
DROP ANY INDEX
beliebigen Index entfernen
QUERY REWRITE
Query Rewrite für materialisierte Views, die Tabellen im eigenen Schema betreffen, oder Aufbau von entsprechenden Funktionsindizes (function-based index)
GLOBAL QUERY REWRITE
Query Rewrite für materialisierte Views, die Tabellen in beliebigen Schemas betreffen, oder Aufbau von entsprechenden Funktionsindizes (function-based index)
RESUMABLE
Ermöglicht wieder aufnehmbare Speicherplatzzuweisungen (z.B. beim Fehlschlagen von Insert-Operationen)
CREATE LIBRARY
Bibliothek externer Prozeduren im eigenen Schema anlegen
CREATE ANY LIBRARY
Bibliothek externer Prozeduren in beliebigem Schema anlegen
DROP LIBRARY
Bibliothek im eigenem Schema löschen
DROP ANY LIBRARY
Bibliothek in beliebigem Schema löschen
Datenbank-Links
Dimensionen
Directories
Indextypen
Indizes
Anwendung
Libraries
Sandini Bib
284
Sicherheit
Bereich
Privileg
Berechtigung zu ...
Materialisierte Views
CREATE MATERIALIZED VIEW
Materialisierte View im eigenen Schema anlegen
CREATE ANY MATERIALIZED VIEW
Materialisierte View in beliebigem Schema anlegen
ALTER ANY MATERILIAZED VIEW
Materialisierte View in beliebigem Schema ändern
DROP ANY MATERIALIZED VIEW
Materialisierte View in beliebigem Schema löschen
ON COMMIT REFRESH
Einrichten von on commit refresh für materialisierte Views in beliebigem Schema
CREATE OPERATOR
Operator im eigenen Schema anlegen
CREATE ANY OPERATOR
Operator in beliebigem Schema anlegen
DROP ANY OPERATOR
Operator in beliebigem Schema löschen
EXECUTE ANY OPERATOR
Operator in beliebigem Schema referenzieren
CREATE ANY OUTLINE
Public Outlines erzeugen
ALTER ANY OUTLINE
Public Outlines ändern
DROP ANY OUTLINE
Public Outlines löschen
SELECT ANY OUTLINE
Eigene Outline mit Referenz auf Public Outline erstellen
GRANT ANY PRIVILEGE
Systemprivilegien erteilen
EXEMPT ACCESS POLICY
Umgehen von Zugriffskontrollen (fine grain access control)
CREATE PROCEDURE
Prozeduren, Funktionen und Pakete im eigenen Schema erstellen
CREATE ANY PROCEDURE
Prozeduren, Funktionen und Pakete in beliebigem Schema erstellen
ALTER ANY PROCEDURE
Prozeduren, Funktionen und Pakete in beliebigem Schema ändern (z.B. Übersetzen)
DROP ANY PROCEDURE
Prozeduren, Funktionen und Pakete in beliebigem Schema entfernen
EXECUTE ANY PROCEDURE
Prozeduren und Funktionen (auch in Paketen) in beliebigem Schema ausführen
CREATE PROFILE
Profile anlegen
ALTER PROFILE
Profile ändern
DROP PROFILE
Profile entfernen
CREATE ROLE
Rollen anlegen
ALTER ANY ROLE
beliebige Rollen ändern
DROP ANY ROLE
beliebige Rollen entfernen
Operatoren
Outlines
Privilegien
Prozeduren
Profile
Rollen
Sandini Bib
Privilegien und Rollen
Bereich
Rollback-Segmente
Sessions
Sequenzen
Synonyme
Tabellen
285
Privileg
Berechtigung zu ...
GRANT ANY ROLE
beliebige Rollen zuweisen
CREATE ROLLBACK SEGMENT
Rollback-Segmente anlegen
ALTER ROLLBACK SEGMENT
Rollback-Segmente ändern
DROP ROLLBACK SEGMENT
Rollback-Segmente entfernen
CREATE SESSION
Verbindungsaufbau zur Datenbank
ALTER SESSION
Sitzungsparameter ändern (Tracing, NLS-Parameter usw.)
RESTRICTED SESSION
Verbindungsaufbau, auch wenn RESTRICTED SESSION aktiv ist
ALTER RESOURCE COST
Kosten für Ressourcen (Basis für Profile) ändern
CREATE SEQUENCE
Sequenzen im eigenen Schema anlegen
CREATE ANY SEQUENCE
Sequenzen in beliebigem Schema anlegen
ALTER ANY SEQUENCE
Sequenzen in beliebigem Schema ändern
DROP ANY SEQUENCE
Sequenzen in beliebigem Schema entfernen
SELECT ANY SEQUENCE
auf Sequenzen in beliebigem Schema zugreifen
CREATE SYNONYM
Synonyme im eigenen Schema anlegen
CREATE ANY SYNONYM
Synonyme in beliebigem Schema anlegen
DROP ANY SYNONYM
Synonyme in beliebigem Schema entfernen
CREATE PUBLIC SYNONYM
Public-Synonyme anlegen
DROP PUBLIC SYNONYM
Public-Synonyme entfernen
CREATE TABLE
Tabellen (und für eigene Tabellen Indizes) im eigenen Schema anlegen
CREATE ANY TABLE
Tabellen in beliebigem Schema anlegen
ALTER ANY TABLE
Tabellen in beliebigem Schema anlegen
BACKUP ANY TABLE
Inkrementellen Export für Tabellen in beliebigem Schema ausführen
DROP ANY TABLE
Tabellen in beliebigem Schema anlegen
LOCK ANY TABLE
Sperren auf Tabellen in beliebigem Schema setzen
COMMENT ANY TABLE
Kommentare auf Tabellen in beliebigem Schema anlegen
SELECT ANY TABLE
Abfragen auf Tabellen in beliebigem Schema ausführen
Sandini Bib
286
Bereich
Tablespaces
Transaktionen
Trigger
Objekttypen
Views
Sicherheit
Privileg
Berechtigung zu ...
INSERT ANY TABLE
INSERT-Befehle auf Tabellen in beliebigem Schema ausführen
UPDATE ANY TABLE
UPDATE-Befehle auf Tabellen in beliebigem Schema ausführen
DELETE ANY TABLE
DELETE-Befehle auf Tabellen in beliebigem Schema ausführen
CREATE TABLESPACE
Tablespaces anlegen
ALTER TABLESPACE
Tablespaces ändern
MANAGE TABLESPACE
Tablespaces online und offline setzen sowie Online Backup-Modus ein- und ausschalten
DROP TABLESPACE
Tablespaces entfernen
UNLIMITED TABLESPACE
unbeschränkt Platz in beliebigem Tablespace belegen
FORCE TRANSACTION
COMMIT oder ROLLBACK für eigene verteilte Transaktionen mit Zustand in doubt forcieren
FORCE ANY TRANSACTION
COMMIT oder ROLLBACK für beliebige verteilte Transaktionen mit Zustand in doubt forcieren
CREATE TRIGGER
Trigger für Tabellen im eigenen Schema anlegen
CREATE ANY TRIGGER
Trigger für Tabellen in beliebigem Schema anlegen
ALTER ANY TRIGGER
Trigger für Tabellen in beliebigem Schema ändern
DROP ANY TRIGGER
Trigger für Tabellen in beliebigem Schema entfernen
ADMINISTER DATABASE TRIGGER
Datenbank-Trigger anlegen (entsprechendes CREATE-Privileg erforderlich)
CREATE TYPE
Objekttypen im eigenen Schema anlegen
CREATE ANY TYPE
Objekttypen in beliebigem Schema anlegen
ALTER ANY TYPE
Objekttypen in beliebigem Schema ändern
DROP ANY TYPE
Objekttypen in beliebigem Schema löschen
EXECUTE ANY TYPE
Benutzen von Objekttypen aus beliebigen Schemas
UNDER ANY TYPE
Subtypen anlegen
CREATE VIEW
View im eigenen Schema anlegen
CREATE ANY VIEW
View in beliebigem Schema anlegen
DROP ANY VIEW
View in beliebigem Schema entfernen
Sandini Bib
Privilegien und Rollen
Bereich
Administration
287
Privileg
Berechtigung zu ...
UNDER ANY VIEW
Für Objektviews: Sub-Views anlegen
SYSOPER
Ausführen der Kommandos STARTUP, SHUTDOWN, ALTER DATABASE MOUNT/ OPEN, ALTER DATABASE BACKUP, ARCHIVE LOG und RECOVER (vollständiges Wiederherstellen) sowie RESTRICTED SESSION, CREATE SPFILE
SYSDBA
alle SYSOPER-/ OSOPER- Privilegen, alle Systemprivilegien WITH ADMIN OPTION, CREATE DATABASE-Kommando, unvollständiges Wiederherstellen, CREATE SPFILE
SELECT ANY DICTIONARY
Abfragen von SYS-Tabellen und Views, überschreibt den Systemparameter O7_DICTIONARY_ACCESSIBILITY
Tabelle 4.3: Übersicht Systemprivilegien
Jeder Benutzer, der sich an das System anmeldet, muss das Privileg CREATE SESSION besitzen. Das Privileg CREATE SESSION kann andererseits dazu genutzt werden, bestimmten Benutzern die Anmeldung nicht zu ermöglichen. Ein eleganterer Weg ist hierzu freilich das Sperren des Benutzers. Benutzer, in deren Schema lediglich Objekte gespeichert werden, die über separate Benutzer abgefragt und verändert werden, erhalten konsequenterweise kein CREATE SESSION. Für alle Objekttypen, die zu Schemas gehören können, gibt es jeweils ein CREATEPrivileg, das dem Benutzer die Erstellung von Objekten dieses Typs im eigenen Schema ermöglicht. Soll ein Benutzer Objekte in beliebigen Schemas erstellen können, so muss das entsprechende CREATE ANY-Privileg zugewiesen werden. Da die Verwaltung von Objekten standardmäßig nur dem Besitzer gestattet ist, gibt es zusätzlich zum CREATE ANY-Privileg noch weitere Privilegien, wie z.B. ALTER ANY oder DROP ANY, die eine datenbankweite Administration der Objekte eines bestimmten Typs ermöglichen. Falls z.B. ein regelmäßig laufender Prozess alle Datenbankobjekte analysieren soll, um Statistiken für den kostenbasierten Optimizer aktuell zu halten, so kann einem Benutzer das ANALYZE ANY-Privileg zugewiesen werden. Der Benutzer benötigt ansonsten keine Privilegien, so dass er z.B. keine Tabellen abfragen kann. Mit diesem Benutzer kann somit ein Script aufgesetzt werden, das für alle Datenbankbenutzer außer SYS die von Oracle mitgelieferte Prozedur dbms_utility.analyze_schema(’&BENUTZER’, ’ESTIMATE’);
aufruft. Die Zuweisung von Systemprivilegien an Benutzer erfolgt mit dem GRANT-Befehl. Eine Zuweisung kann WITH ADMIN OPTION erfolgen, so dass der Empfänger der Systemprivilegien diese an andere Benutzer weitergeben kann. Der Pseudobenutzer PUBLIC steht für alle Benutzer in der gesamten Datenbank. Sowohl die Systemprivilegien als auch die Benutzernamen können als Liste angegeben werden.
Sandini Bib
288
Sicherheit
GRANT CREATE SESSION TO guenter, johannes, dierk; GRANT CREATE TABLE, CREATE VIEW TO uwe WITH ADMIN OPTION; GRANT ALTER SESSION TO PUBLIC;
Zugewiesene Systemprivilegien können mit dem REVOKE-Befehl wieder rückgängig gemacht werden. Mit dem folgenden REVOKE-Befehl wird dem Benutzer dierk das Privileg CREATE SESSION entzogen : REVOKE CREATE SESSION FROM dierk;
Systemprivilegien, die Benutzern oder Rollen zugewiesen wurden, können über die View dba_sys_privs abgefragt werden.
4.5.2
Objektprivilegien
Während die Systemprivilegien die erlaubten Kommandos und Aktionen eines Benutzers einschränken, regeln Objektprivilegien den Zugriff auf die Objekte innerhalb der Datenbank, also auf Tabellen, Views, Prozeduren usw. Viele Benutzer von Oracle-Datenbanken, zumeist Anwender von Oracle-basierten Softwarelösungen, besitzen vergleichsweise wenige Systemprivilegien, eventuell sogar nur das Privileg CREATE SESSION, dafür aber umso mehr Objektprivilegien. Über Objektprivilegien werden den Benutzern die Teile der Datenbank zur Verfügung gestellt, die sie nicht selbst besitzen, aber für ihre Anwendung benötigen. Dabei regeln Objektprivilegien nicht nur ob, sondern auch in welcher Art und Weise auf die Datenbankobjekte zugegriffen werden kann. Das meistverwendete Privileg ist das SELECT-Privileg, das für Tabellen, Cluster, Views, Sequenzen und Snapshots vergeben werden kann. Für Objekte, die auch mit DML-Operationen bearbeitet werden können, also Tabellen, Cluster und – zumindest teilweise – Views und Snapshots, gibt es zusätzlich die Objektprivilegien INSERT, UPDATE und DELETE. Bei Tabellen gibt es zusätzlich zu den genannten die Privilegien INDEX und REFERENCES, die es erlauben, für die Tabelle Indizes bzw. Fremdschlüsseldefinitionen anzulegen. Für praktisch alle Objekte kann das ALTER-Privileg zugewiesen werden, das die Veränderung des Objekts (z.B. Spalte hinzufügen für eine Tabelle oder Übersetzen einer Prozedur) erlaubt. Die Objektprivilegien INSERT, UPDATE und REFERENCES können auch auf Spaltenebene vergeben werden. Ein spezielles Privileg ist für aufrufbare PL/SQL-Objekte, also Prozeduren, Funktionen und Pakete, verfügbar: Mit dem EXECUTE-Privileg kann der Aufruf der Objekte gestattet werden. Bei Paketen gilt dies immer für das gesamte Objekt; einzelne Prozeduren oder Funktionen aus dem Paket können nicht zugewiesen werden. Der Zugriff auf Trigger muss nicht explizit gestattet werden, da Trigger implizit mit einem DML-Zugriff auf ein Objekt ausgeführt werden. Die Ausführungsberechtigung für den Trigger ist somit im entsprechenden DML-Recht enthalten.
Sandini Bib
Privilegien und Rollen
289
Wenn die zugewiesenen Rechte vom Empfänger an andere Benutzer weitergegeben werden sollen, muss der GRANT-Befehl die Klausel WITH GRANT OPTION enthalten. Einige Beispiele verdeutlichen den GRANT-Befehl: GRANT GRANT GRANT GRANT GRANT
SELECT ON emp TO uwe WITH GRANT OPTION; INSERT (empno, ename, deptno, mgr, hiredate) ON emp TO uwe; ALL ON dept TO PUBLIC; EXECUTE ON hire_employee TO dierk, uwe, guenter; SELECT, UPDATE (comm) ON emp TO guenter;
Man beachte, dass sowohl die Objektprivilegien als auch die Benutzer im GRANTBefehl als Liste angegeben werden können, die Objekte selbst jedoch nicht. Einmal zugewiesene Objektprivilegien können mit einem REVOKE-Befehl wieder entzogen werden: REVOKE ALL ON dept FROM PUBLIC; REVOKE UPDATE (comm) ON emp FROM guenter;
Ein Sonderfall bei Objektprivilegien ist das kaskadierende REVOKE. Nach den folgenden Befehlen USER1: GRANT SELECT ON user1.emp TO user2 WITH GRANT OPTION; USER2: GRANT SELECT ON user1.emp TO user3; USER1: REVOKE SELECT ON user1.emp FROM user2;
kann user3 nicht auf die Tabelle user1.emp zugreifen. Das Kommando USER3: SELECT * FROM user1.emp;
führt zu einer Fehlermeldung. Das bedeutet, dass bei Objektprivilegien im Data Dictionary mitgeführt wird, von wem diese zugewiesen worden sind. Falls diesem Benutzer die Grundlage für seinen Befehl entzogen wird, so werden alle abhängigen Zuweisungen aufgehoben. Das kaskadierende REVOKE gilt im Übrigen nicht für Systemprivilegien. Objektprivilegien, die einer Rolle oder einem Benutzer zugewiesen wurden, können über die View dba_tab_privs abgefragt werden.
4.5.3
Rollen
Mit den in den vorhergehenden Abschnitten genannten Möglichkeiten der Systemprivilegien und des Zugriffsschutzes lassen sich viele Aspekte der Sicherheit lösen. Allerdings kann der erforderliche Administrationsaufwand für den DBA bereits bei kleinen und mittleren Datenbanken problematisch werden. Sobald einige Dutzend Tabellen und Benutzer zu verwalten sind, sind bei einer gründlichen Sicherheitsverwaltung Hunderte oder Tausende von GRANT-Befehlen abzusetzen. Das Hinzufügen einer Tabelle oder eines Benutzers bedeutet ebenfalls umfangreiche Aktionen, die meist durch Scripts realisiert werden. Diese wiederum
Sandini Bib
290
Sicherheit
sind selbst bei guter Dokumentation nach relativ kurzer Zeit nicht mehr lesbar; bei Änderungen am Datenmodell entsteht somit ein immens hoher Pflegeaufwand. Das von Oracle bereits mit dem Release 7.0 des RDBMS eingeführte Rollenkonzept ermöglicht eine drastische Reduzierung des Wartungsaufwands für die Privilegienvergabe in produktiven Umgebungen. Zusätzlich sind durch die dynamischen Eigenschaften von Rollen viele spezielle Probleme lösbar, die sich z.B. durch unterschiedliche Vergabe von Möglichkeiten zur Selektion oder Manipulation von Daten in unterschiedlichen Anwendungsumgebungen ergeben. In einer Rolle können verschiedene Privilegien zusammengefasst und später als Einheit vergeben werden. Eine Rolle kann System- und Objektprivilegien sowie weitere Rollen enthalten, sie wird ansonsten (z.B. bezüglich der Zuweisung an Benutzer) wie ein Systemprivileg behandelt. Vordefinierte Rollen In einer Oracle-Datenbank gibt es bestimmte vordefinierte Rollen, welche die Zuweisung standardisierter Privilegiengruppen vereinfachen sollen. Die folgende Tabelle enthält eine Übersicht dieser Rollen und ihrer Privilegien: CONNECT
ALTER SESSION, CREATE CLUSTER, CREATE DATABASE LINK, CREATE SEQUENCE, CREATE SESSION, CREATE SYNONYM, CREATE TABLE, CREATE VIEW
RESOURCE
CREATE CLUSTER, CREATE PROCEDURE, CREATE SEQUENCE, CREATE TABLE, CREATE TRIGGER
DBA
alle Systemprivilegien WITH ADMIN OPTION
DELETE_CATALOG_ROLE
Löschen von Audit-Informationen
SELECT_CATALOG_ROLE
SELECT-Privilegien für die Objekte des Data Dictionary
EXCUTE_CATALOG_ROLE
EXECUTE-Privilegien für die DBMS-Pakete von SYS
AQ_USER_ROLE AQ_ADMINISTRATOR_ROLE
Benutzer- bzw. Administratorprivilegien für Advanced Queuing
SNMPAGENT
Privilegien für den Intelligent Agent des Enterprise Manager
RECOVERY_CATALOG_OWNER
Privilegien für den Eigentümer des Recovery-Katalogs (Recovery Manager)
HS_ADMIN_ROLE
Privilegien für Heterogeneous Services
EXP_FULL_DATABASE
SELECT ANY TABLE, BACKUP ANY TABLE, INSERT, DELETE, UPDATE ON SYS.INCVID, UPDATE ON SYS.INCFIL, UPDATE ON AND SYS.INCEXP
IMP_FULL_DATABASE
BECOME USER, WRITEDOWN
Tabelle 4.4: Vordefinierte Rollen
Beim GRANT der Rollen RESOURCE und DBA wird gleichzeitig das Systemprivileg UNLIMITED TABLESPACE bei der Rolle DBA WITH ADMIN OPTION zugewiesen. Diese Zuweisung erfolgt nicht als Bestandteil der Rolle, sondern als direktes Systemprivileg. In
Sandini Bib
Privilegien und Rollen
291
den meisten Fällen empfiehlt es sich, dies nicht bestehen zu lassen, sondern mit expliziten Quoten für einzelne Tablespaces zu arbeiten.24 Beim Aufsetzen eines Datenbanksystems erweisen sich die Rollen CONNECT, RESOURCE und DBA als praktisch, da man „sofort loslegen“ kann. Dabei passt die Rolle CONNECT für Anwendungsbenutzer und Entwickler, RESOURCE für fortgeschrittene Entwickler und DBA für Administratoren. In den meisten Fällen ist es jedoch empfehlenswert, eigene Rollen für spezielle Benutzerprofile zu erstellen. Für Entwickler gibt es z.B. oft die Anforderung, zusätzlich zu den CONNECT- und RESOURCEPrivilegien Public-Synonyme verwalten zu können, um Datenbankobjekte transparent zur Verfügung zu stellen. Hier empfiehlt es sich, eine eigene Rolle zu erstellen. Es wird entschieden davon abgeraten, die vordefinierten Rollen zu verändern, da die Änderungen bei einem eventuellen Neuaufsetzen des Systems, z.B. durch eine Export/Import-Migration auf ein anderes Betriebssystem, verloren gehen oder Werkzeuge nicht mehr erwartungsgemäß arbeiten können (smnpagent). Rollen anlegen und zuweisen Eine Rolle wird erstellt durch den Befehl CREATE ROLE: CREATE ROLE entwickler;
Der Ersteller der Rolle benötigt das Privileg CREATE ROLE. Nach der Erstellung besitzt der Benutzer die Rolle WITH ADMIN OPTION, d.h., er kann sie weiteren Benutzern zuweisen. Die Rolle verhält sich bezüglich GRANT und REVOKE wie ein Systemprivileg, d.h., sie kann wie folgt anderen Benutzern zugewiesen werden: GRANT entwickler TO dierk, guenter, johannes;
Weiterhin können Rollen wiederum Rollen enthalten: GRANT CONNECT TO entwickler;
Mit diesem Befehl wird die Rolle CONNECT Bestandteil der Rolle entwickler. Diese Rolle kann aber auch um Systemprivilegien erweitert werden: GRANT create public synonym, drop public synonym, create public database link, drop public database link TO entwickler;
Benutzer, die im Besitz der Rolle entwickler sind, können ab dem nächsten Verbindungsaufbau die neuen Systemprivilegien nutzen. Ebenso ist eine Erweiterung um Objektprivilegien möglich: GRANT select ON sys.dba_usrs TO entwickler;
Rollen können über die View dba_roles selektiert werden, den Rollen zugewiesene Privilegien entsprechend über dba_tab_privs und dba_sys_privs.
24. Das UNLIMITED TABLESPACE-Privileg wird aus Kompatibilitätsgründen zu Oracle Version 6 zugewiesen.
Sandini Bib
292
Sicherheit
Dynamisches Aktivieren von Rollen Wird die Rolle einem anderen Benutzer zugewiesen, so heißt das nicht, dass die enthaltenen Privilegien für diesen Benutzer grundsätzlich aktiv sind. Eine Eigenschaft von Rollen ist, dass sie dynamisch aktiviert und deaktiviert werden können. Hierzu gibt es den Befehl SET ROLE: SET SET SET SET SET
ROLE ROLE ROLE ROLE ROLE
entwickler; CONNECT, entwickler; ALL; ALL EXCEPT CONNECT; NONE;
Der Befehl SET ROLE hat den Effekt, dass die explizit angegebenen Rollen aktiviert werden. Vorher aktivierte Rollen bleiben nicht aktiv, es sei denn, dass sie ebenfalls explizit genannt sind. Sollen zugeteilte Rollen bereits beim Anmelden eines Benutzers aktiviert werden, so müssen diese als dessen Standardrollen – wie im folgenden Beispiel dargestellt – definiert werden. ALTER USER uwe DEFAULT ROLE ALL; /* Standardeinstellung */ ALTER USER dierk DEFAULT ROLE CONNECT; ALTER USER guenter DEFAULT ROLE NONE;
Falls das Systemprivileg CREATE SESSION dem Benutzer mittels einer Rolle zugewiesen wurde, so muss diese Rolle für den Benutzer als Standardrolle definiert sein. Andernfalls kann der Benutzer sich nicht an das System anmelden. Der einzelne Benutzer sieht über die View user_role_privs die ihm zugeteilten Rollen und über session_roles seine aktiven Rollen. session_privs zeigt alle aktiven Privilegien eines Benutzers. Passwörter für Rollen Zusätzlich zu den genannten Eigenschaften kann das Aktivieren einer Rolle mit einem Passwort geschützt werden. Damit kann verhindert werden, dass ein Benutzer mit jeder beliebigen Anwendung auf die in der Rolle enthaltenen Privilegien zugreift, wenn z.B. nur eine Anwendung selbst das Passwort zum Aktivieren der Rolle kennt. CREATE ROLE spezial IDENTIFIED BY keinerweiss; ALTER ROLE entwickler IDENTIFIED BY keinerkennt; ALTER ROLE rolle51 NOT IDENTIFIED;
Sobald ein Passwort für eine Rolle definiert ist, muss dies beim SET ROLE-Kommando angegeben werden: SET ROLE CONNECT, spezial IDENTIFIED BY keinerweiss, entwickler IDENTIFIED BY keinerkennt;
Sandini Bib
Privilegien und Rollen
293
Für den Erfolg des SET ROLE-Kommandos muss sowohl die Rolle zugewiesen als auch das Passwort korrekt angegeben sein. Sind solche SET ROLE-Kommandos z.B. versteckt in Anwendungen kodiert, so können an bestimmten Stellen in der Anwendung Privilegien aktiviert werden, die ansonsten dem jeweiligen Benutzer verborgen bleiben. Werden Rollen, die über Passwörter geschützt sind, als Standardrollen vergeben, entfällt selbstverständlich die Angabe des Passwortes bei der Anmeldung des Benutzers. Rollenverwaltung über das Betriebssystem Die Zuweisung von Rollen an einzelne Benutzer, die im Normalfall über datenbankinterne Mechanismen behandelt wird, kann alternativ dem Betriebssystem überlassen werden. Dabei geht die Kontrolle über Rollenprivilegien komplett für alle Benutzer auf das Betriebssystem über, die Zuweisungen innerhalb der Datenbank haben keinerlei Bedeutung mehr.25 Eine Alternative stellt die in Abschnitt 4.4.5 beschriebene Zuweisung von Rollen über Verzeichnisdienste dar. Die Verwaltung von Rollen wird im Falle der Verwaltung über das Betriebssystem auf Gruppen oder ähnliche Mechanismen abgebildet (Unix und Windows NT: Gruppen, VMS: Process Rights Identifier). Ein Datenbankbenutzer besitzt die Rolle rolle in der Instanz prod, falls er Mitglied der Gruppe ora_prod_rolle ist. Der Name der Gruppe kann zusätzlich das Postfix _d enthalten, um anzuzeigen, dass die Rolle als Default-Rolle zu betrachten ist. Wenn das Postfix _a enthalten ist, steht die Rolle WITH ADMIN OPTION. Das Postfix _da kombiniert diese beiden Eigenschaften. Die Eigenschaft WITH ADMIN OPTION hat die Auswirkung, dass der jeweilige Benutzer die Rolle anderen Benutzern zuweisen darf. Die Zuweisungen, die der Benutzer vornimmt, beziehen sich allerdings auf die Oracle-interne Verwaltung von Rollen, d.h., die Zuweisungen sind erst dann gültig, wenn die Rollenverwaltung nicht mehr über das Betriebssystem vorgenommen wird. Über den Initialisierungsparameter OS_ROLES = TRUE
wird die Rollenverwaltung über das Betriebssystem eingeschaltet. Zur Administration der Datenbank stehen die Rollen OSOPER und OSDBA zur Verfügung, die mit den gleichen Privilegien ausgestattet sind wie die Rechte SYSOPER und SYSDBA. Empfehlungen für den Aufbau von Rollen Rollenhierarchie Beim Design einer Rollenstruktur für eine Datenbank kann die Eigenschaft von Rollen, selbst wieder Rollen enthalten zu können, ausgenutzt werden. Dabei ist anzuraten, dass die Rollenhierarchie nicht mehr als zwei oder drei Ebenen umfassen sollte. Dies wird einerseits dadurch begründet, dass der Sicherheitscheck in der Parse-Phase von SQL-Befehlen länger dauert, je mehr Rollen aktiviert sind, andererseits eine systemweite Grenze aktiv ist, welche die Anzahl der gleichzeitig aktiven Rollen pro Sitzung einschränkt, wobei die Unterrollen in einer 25. Das unterscheidet die Rollenverwaltung über das Betriebssystem von der Authentifizierung von Benutzern über das Betriebssystem: Bei Benutzern kann im Einzelfall entschieden werden, ob ein Benutzer ein datenbankinternes Passwort benutzt oder ob er extern authentifiziert wird.
Sandini Bib
294
Sicherheit
Hierarchie mitzählen. Die Grenze wird vom Initialisierungsparameter max_ enabled_roles vorgeschrieben, dessen Maximalwert 148 betragen kann. Der Standardwert für diesen Initialisierungsparameter ist 20. Für die Gestaltung der Rollen wird empfohlen, System- und Objektprivilegien in unterschiedlichen Rollen zusammenzufassen. Die Rollen, die Systemprivilegien enthalten, beschreiben dann jeweils den Benutzertyp (z.B. anwender, entwickler, administrator), Rollen mit Objektprivilegien die bereitgestellten Anwendungen (z.B. buchhaltung, personal, lager). Bei einer komplexen Anwendungsstruktur kann es sinnvoll sein, die Anwendungsrollen in zwei Ebenen zu definieren. In der unteren Ebene sind dann jeweils Rollen definiert, die alle notwendigen Objektprivilegien zur Nutzung einer Anwendung enthalten. In der Ebene darüber können dann Anwendungsprofile für verschiedene Benutzertypen erstellt werden, die aus den Rollen für einzelne Anwendungen zusammengesetzt sind. Anzahl gleichzeitig aktiver Rollen Falls die Privilegienstruktur sehr komplex ist,
empfiehlt es sich, vom Befehl SET ROLE Gebrauch zu machen, damit nicht alle Privilegien gleichzeitig aktiv sind. Bei zu vielen gleichzeitig aktiven Rollen besteht die Gefahr, das Maximum der gleichzeitig aktivierten Rollen, das über den Initialisierungsparameter max_enabled_roles bestimmt wird, zu überschreiten. max_enabled_roles steht standardmäßig auf 20, der Maximalwert ist 148. Bei vielen gleichzeitig aktiven Rollen kann die Sicherheitsprüfung in der Parse-Phase vergleichsweise lange dauern. Der Befehl set role kann nicht nur als SQL-Kommando, sondern auch über die mitgelieferte PL/SQL-Prozedur dbms_session.set_role('LAGER');
ausgeführt werden. Rollen für Administratoren In der Standardrolle DBA sind alle Systemprivilegien WITH ADMIN OPTION enthalten. Falls ein Benutzer über diese Rolle verfügt, kann er die gesamte Datenbank in sämtlichen Aspekten administrieren. Gerade in größeren Teams ist dies jedoch nicht immer wünschenswert: Häufig ergibt sich eine Aufteilung der Administrationsaufgaben unter verschiedenen Personen, die dann Teilbereiche der Datenbank, etwa das Sicherheitssystem oder den physikalischen Datenbankaufbau, administrieren sollen. Eine Rolle für den physikalischen Datenbankaufbau kann etwa wie folgt definiert werden: CREATE ROLE ts_dba_role; GRANT CREATE TABLESPACE, ALTER TABLESPACE, MANAGE TABLESPACE TO ts_dba_role;
Sandini Bib
Virtual Private Database
295
Diese Rolle kann nun z.B. einem Datenbankbenutzer zugeteilt werden, der sich in Absprache mit der Betriebssystemadministration um die Verwaltung des Festplattenspeicherplatzes für die Datenbank kümmert. Da das Privileg DROP TABLESPACE fehlt, kann dieser Administrator nicht destruktiv arbeiten.
4.6
Virtual Private Database
4.6.1
Einführung
Das Konzept Virtual Private Database – kurz VPD – ist auch unter dem Namen Fine Grain Access Control bekannt geworden. Es wurde bereits unter der Version 8 eingeführt und nun unter Oracle9i funktional erweitert. VPD steht im Rahmen der Enterprise Edition von Oracle9i zur Verfügung und ermöglicht die automatische Generierung von WHERE-Klauseln für ausgesuchte Tabellen. Auf diese Weise lassen sich komplexe Konzepte des Zugriffsschutzes transparent und unabhängig von der jeweiligen Anwendung realisieren. Der Grundgedanke dieses Konzeptes ist – immer noch – recht einfach und bestechend: Für jeden Benutzer wird ein spezifischer Anwendungskontext (application context) aufgebaut, der aus Attributen und ihnen zugeordneten Werten besteht. Der Name dieses Kontextes wie auch der in seinem Kontext definierten Attribute ist frei wählbar. Die Belegung der Attributwerte kann auf verschiedene Arten erfolgen, im einfachsten Falle über geeignete Logon-Trigger, die bereits beim Verbindungsaufbau an die Datenbank zur Ausführung kommen. Die zu schützenden Schemaobjekte, z.B. Tabellen, werden jeweils mit einer oder mehreren Sicherheitsrichtlinien (policy) verknüpft. Im Rahmen der Richtlinien definierte Funktionen generieren beim Zugriff auf das betreffende Objekt WHERE-Klauseln, die sich der Attribute des erwähnten Anwendungskontextes bedienen, um auf diese Weise den originalen SQL-Befehl zu erweitern und den Zugriff entsprechend zu filtern. Diese Richtlinien lassen sich darüber hinaus explizit mit bestimmten DML-Operationen – z.B. SELECT – verknüpfen. VPD kann in diesem Sinne salopp als "Default Where-KlauselGenerierung" beschrieben werden. Die Möglichkeiten von VPD gehen dabei nicht nur funktional über die von Views hinaus: Hervorzuheben ist hier vor allem, dass die entsprechenden Attributwerte nur einmal – zum Zeitpunkt des Verbindungsaufbaus – ermittelt und nicht bei jedem Zugriff selektiert werden müssen, wie dies bei funktional ähnlichen Konstrukten in Views, die beispielsweise über Unterabfragen gesteuert werden, der Fall ist. Der Vorteil in Sachen Performance kann hierbei erheblich sein. Damit Dritte einen Anwendungskontext und seine Attribute nicht beliebig fälschen und sich damit Zugang zu „unerlaubten“ Daten verschaffen können, wird in jedem Kontext ein Paket definiert, das für die Generierung der Attributwerte „freigegeben“ ist. Die betreffenden Benutzer müssen dann nur mit dem EXECUTE-Privileg auf dieses Paket ausgestattet werden, um den erforderlichen Kontext zu setzen.
Sandini Bib
296
Sicherheit
Da unter Oracle 8i an jede Basistabelle pro DML-Operation nur eine Richtlinie gekoppelt werden konnte, war es schwierig, für unterschiedliche Anwendungen, die identische Basisobjekte mit gleichen Operationen bearbeiteten, spezifische, sich gegenseitig ausschließende Richtlinien zu implementieren. Oracle9i hat dieses Konzept dahingehend erweitert, dass Richtlinien nun gruppiert und diese Gruppen über Anwendungskontexte gezielt aktiviert werden können. Auf diese Weise lassen sich über Funktionen, die den Gruppen zugeordnet wurden, unterschiedliche Kontextattribute für unterschiedliche Anwendungen erzeugen und auswerten.
4.6.2
Aufbau einer VPD-Umgebung
Das folgende umfangreiche Beispiel soll das im vorangehenden Abschnitt dargestellte Konzept erläutern. Ermittlung der Anforderungen Wie überall anders, so sind auch beim Aufbau einer VPD-Umgebung eine genaue Ermittlung der Anforderungen und ein aus diesen Anforderungen abgeleitetes Feinkonzept unerlässlich. Für unser Beispiel sollen die folgenden Anforderungen gelten: Es gilt, die Zugriffe auf die Tabelle auftraege aus zwei unterschiedlichen Anwendungen heraus zu steuern. Die Anwendungen sind auf der einen Seite das Auftragswesen (aw) und auf der anderen Seite die Kundenbetreuung (kb). Für das Auftragswesen gilt: Manager sollen alle Aufträge bearbeiten dürfen, die von ihnen selbst oder von Mitarbeitern ihrer Abteilung aufgenommen wurden. Die Mitarbeiter dagegen haben nur Zugriff auf ihre eigenen Aufträge. Für die Kundenbetreuung gilt: Kunden sehen nach Angabe ihrer Kundennummer nur die von ihnen initiierten Aufträge. Die Tabelle auftraege ist wie folgt angelegt worden: CREATE TABLE auftraege ( a_nr VARCHAR2(10) NOT NULL, -- Auftragsnummer a_datum DATE NOT NULL, -- Auftragsdatum a_kunde VARCHAR2(10) NOT NULL, -- Kundennummer a_mitarb VARCHAR2(10) NOT NULL, --Personalnummer des Mitarbeiters a_abt VARCHAR2(10) NOT NULL, -- Abteilung des Mitarbeiters CONSTRAINT auf_pk PRIMARY KEY(a_nr)); Listing 4.10: Tabelle auftraege
Beim Anlegen eines Auftrages sorgen Trigger für das Befüllen der Personal- und Abteilungsnummer des bearbeitenden Mitarbeiters. Mitarbeiter melden sich an der Datenbank mit ihrem eindeutigen Kurznamen an: z.B. msorglos im Falle des Mitarbeiters Manfred Sorglos. Die Tabelle mitarbeiter speichert sämtliche Mitarbeiterdaten, so auch die Abteilungs- und Personalnummern sowie die Position, z.B. Manager:
Sandini Bib
Virtual Private Database
297
CREATE TABLE mitarbeiter( m_mitarb VARCHAR2(10) NOT NULL, m_kurzname VARCHAR2(30) NOT NULL, m_abt VARCHAR2(10) NOT NULL, m_vorname VARCHAR2(50), m_nachname VARCHAR2(100), m_position VARCHAR2(100), CONSTRAINT mit_pk PRIMARY KEY(m_mitarb), CONSTRAINT mit_knam UNIQUE (m_kurzname)); Listing 4.11: Tabelle mitarbeiter
Beim Anmelden an die Datenbank sind dementsprechend über den Kurznamen die abhängigen Daten zu ermitteln. Anlegen des Kontextes Das oben geschilderte Zugriffsmodell soll im Schema vpd_test aufgebaut werden. Für die Arbeit stehen uns grundsätzlich eine Reihe von SQL-Befehlen und Prozedur aufrufen sowie alternativ das Werkzeug Oracle Policy Manager zur Verfügung. Im ersten Schritt wird zunächst ein Kontext mit eindeutigem Namen in der Datenbank angelegt, in unserem Fall der Kontext auftrag_con: CREATE CONTEXT auftrag_con USING vpd_test.sec_init;
Für die Ausführung ist das Systemprivileg CREATE ANY CONTEXT notwendig. Beim Definieren wird gleichzeitig das – in unserem Beispiel noch zu erstellende – Paket sec_init im Schema vpd_user dazu autorisiert, die erforderlichen Attribute dieses Anwendungskontextes aufzubauen. Im nächsten Schritt gilt es nun, das genannte Paket anzulegen. In diesem Paket sind alle für den Kontext relevanten Prozeduren und Funktionen beheimatet. CREATE OR REPLACE PACKAGE vpd_user.sec_init AS PROCEDURE init(applikation VARCHAR2, kunde VARCHAR2); END; / CREATE OR REPLACE PACKAGE BODY vpd_user.sec_init IS PROCEDURE init (applikation VARCHAR2, kunde VARCHAR2) IS lv_mitarb mitarbeiter.m_mitarb%TYPE; lv_position mitarbeiter.m_position%TYPE; lv_abt mitarbeiter.m_abt%TYPE; invalid_application EXCEPTION;
Sandini Bib
298
Sicherheit
BEGIN IF applikation = 'AW' THEN -- Auftragsverwaltung -- Userdaten ermitteln SELECT m_mitarb, m_position, m_abt INTO lv_mitarb, lv_position, lv_abt FROM mitarbeiter WHERE m_kurzname = user; -- Attributewerte setzen dbms_session.set_context('AUFTRAG_CON','MIT',lv_mitarb); dbms_session.set_context('AUFTRAG_CON','POS',lv_position); dbms_session.set_context('AUFTRAG_CON','ABT',lv_abt); ELSIF applikation = 'KB' THEN -- Kundenbetreuung dbms_session.set_context('AUFTRAG_CON','KUN',kunde); ELSE -- keine andere Applikation zulassen RAISE invalid_application; END IF; -dbms_session.set_context('AUFTRAG_CON','APP', applikation); --- hier noch entsprechendes Exception-Handling hinzufügen END; END; / Listing 4.12: Anlegen des Kontext-Pakets
In diesem Paket wird zunächst die Prozedur init angelegt, die für den Aufbau der erforderlichen Kontextattribute verantwortlich ist. init wird über den Eingabeparameter applikation die Kurzbezeichnung der Anwendung übergeben. Abhängig davon werden weitere Kontextattribute gesetzt, die später von den Funktionen, welche die WHERE-Klauseln generieren, gelesen werden. Das Kürzel der Anwendung selbst wird an das Kontextattribut app übergeben. Im dritten Schritt muss dieses Kontextattribut app nun zur Aktivierung unterschiedlicher Richtlinien für Schemaobjekte explizit autorisiert werden. Im folgenden Beispiel geschieht dies im Rahmen des Kontextes auftrag_con für die Tabelle auftraege des Schemas vpd_user.
Sandini Bib
Virtual Private Database
299
BEGIN dbms_rls.add_policy_context( object_schema => 'VPD_USER', object_name => 'AUFTRAEGE', namespace => 'AUFTRAG_CON', attribute => 'APP'); END; / Listing 4.13: Erstellen der Kontext-Policy
Abbildung 4.10: Anwendungskontext im Oracle Policy Manager
Richtliniengruppen und Richtlinien Schließlich sind Richtliniengruppen und diesen zugeordnete Funktionen anzulegen, die entsprechende WHERE-Klauseln generieren. In unserem Beispiel sollen die Gruppen aw und kb mit den ihnen zugeordneten Funktionen aw_policy_function und kb_policy_function aufgebaut werden. Beide Funktionen werden hier in das Package sec_init von vpd_user integriert. Die nachfolgende Syntax zeigt nur die relevanten Erweiterungen des Codes:
Sandini Bib
300
Sicherheit
-- Package Spezifikation FUNCTION aw_policy_function (owner VARCHAR2, objname VARCHAR2) RETURN VARCHAR2; -- Package Body FUNCTION aw_policy_function(owner VARCHAR2, objname VARCHAR2) RETURN VARCHAR2 IS BEGIN -- Mitarbeiter oder Manager? IF SYS_CONTEXT('AUFTRAG_CON','POS') = 'Manager' THEN RETURN ' a_abt = SYS_CONTEXT(''AUFTRAG_CON'',''ABT'')'; ELSIF SYS_CONTEXT('AUFTRAG_CON','POS') = 'Mitarbeiter' THEN RETURN ' a_mitarb = SYS_CONTEXT(''AUFTRAG_CON'',''MIT'')'; END IF; END; Listing 4.14: Funktion aw_policy_function
Die Funktion aw_policy_function erzeugt – abhängig von der Position des betreffenden Mitarbeiters, die aus den Kontextattributen abgeleitet wird – eine WHEREKlausel, die entweder alle Aufträge einer Abteilung oder eines Mitarbeiters filtert. Es ist unbedingt zu beachten, dass die beiden Eingabeparameter owner und objname, obwohl im Code nicht gebraucht, spezifiziert werden! Es kommt sonst bei späteren Zugriffen zu Fehlern (ORA-28112). Analog ist für kb_policy_function zu verfahren. Auch hier werden im nachfolgenden Beispiel nur die Erweiterungen des Codes angegeben: -- Package Spezifikation FUNCTION kb_policy_function (owner VARCHAR2, objname VARCHAR2) RETURN VARCHAR2; -- Package Body FUNCTION kb_policy_function(owner VARCHAR2, objname VARCHAR2) RETURN VARCHAR2 IS BEGIN RETURN ' a_mitarb = sys_context(''AUFTRAG_CON'',''KUN'')'; END; Listing 4.15: Funktion kb_policy_function kb_policy_function filtert die einer Kundennummer zugeordneten Aufträge so, wie es im Abschnitt Ermittlung der Anforderungen formuliert wurde.
Nachdem die Funktionen angelegt wurden, können nun die Richtliniengruppen im Kontext der Tabelle auftraege des Schemas vpd_user erstellt werden. Die
Sandini Bib
Virtual Private Database
301
Namen der Gruppen entsprechen dabei den gewählten Anwendungskürzeln aw und kb, um der Datenbank die Zuordnung von Anwendungen und Richtliniengruppen zu ermöglichen: BEGIN dbms_rls.create_policy_group( object_schema => 'VPD_USER', object_name => 'AUFTRAEGE', policy_group => 'AW'); END; / BEGIN dbms_rls.create_policy_group( object_schema => 'VPD_USER', object_name => 'AUFTRAEGE', policy_group => 'KB'); END; / Listing 4.16: Richtliniengruppe erstellen
Im letzten Schritt müssen nun die Funktionen und Gruppen über Richtlinien (policies) verknüpft und für bestimmte DML-Operationen aktiviert werden. Im folgenden Beispiel geschieht dies im Rahmen der Richtlinie aw_policy für die Gruppe AW im Kontext der Tabelle auftraege für SELECT-Operationen: BEGIN dbms_rls.add_grouped_policy( object_schema => 'VPD_USER', object_name => 'AUFTRAEGE', policy_group => 'AW', policy_name => 'AW_POLICY', function_schema => 'VPD_USER', policy_function => 'SEC_INIT.AW_POLICY_FUNCTION', statement_types => 'SELECT', enable => TRUE); END; / Listing 4.17: Verknüpfung der Funktionen und Gruppen
Es versteht sich, dass auch hier ein entsprechender Aufruf für die Gruppe kb zu realisieren ist. Aktivieren der Kontextattribute Um die Richtlinien im Kontext der Gruppe aw für alle Mitarbeiter, die als eigene Datenbankbenutzer geführt werden, transparent zu machen, wird abschließend
Sandini Bib
302
Sicherheit
der folgende Logon-Trigger für alle relevanten Benutzer angelegt. Das Beispiel zeigt den Trigger set_vpd für den Benutzer gunbesch. Der Benutzer wird in der Tabelle mitarbeiter als Manager geführt. Nicht vergessen werden darf, dass alle beteiligten Benutzern das EXECUTE-Privileg auf dem Packet sec_init von vpd_user erteilt wird, damit der Kontext korrekt gesetzt werden kann. Geschieht dies nicht, schlägt keinesfalls die Connect-Operation fehl, sondern – wegen des nicht gesetzten Kontextes – die nachfolgenden Zugriffe auf die Tabelle auftraege. CREATE OR REPLACE TRIGGER gunbesch.set_vpd AFTER LOGON ON gunbesch.SCHEMA BEGIN vpd_user.sec_init.init(applikation => 'AW', kunde => null); END; Listing 4.18: Logon-Trigger
Damit sind nun alle Objekte angelegt worden und die Umgebung ist voll funktionstüchtig. Wenn sich in unserem Beispiel der Benutzer gunbesch anmeldet, erhält er als Manager über die Funktion aw_policy_function Zugriff auf alle Aufträge seiner Abteilung. Natürlich muss gunbesch für einen erfolgreichen Zugriff auch das SELECT-Privileg für auftraege erteilt worden sein! Für Kunden wird der Zugriff in unserem Beispiel über eine spezielle Anwendung geregelt. Im Kontext dieser Anwendung – beispielsweise einer Web-Anwendung – wird die Kundennummer plausibel ermittelt und sodann der Anwendungskontext kb über den folgenden Aufruf aktiviert: BEGIN vpd_user.sec_init.init('KB','K123'); END;
Dementsprechend gelten nun die Regeln für den Anwendungskontext kb und der Kunde k123 sieht nur die eigenen Aufträge. Die Sicherheit ist in diesem Fall ganz entscheidend von der Authentifizierung des Kunden in der betreffenden Anwendung abhängig. Die folgende Grafik fasst noch einmal die komplexen Beziehungen aller beschriebenen VPD-Objekte zusammen.
Sandini Bib
Virtual Private Database
303
$SSO&RQWH[W 3ROLF\&RQWH[W
3DNHW $WWULEXW
3ROLF\)XQFWLRQ 7DEHOOH
'0/7\SH
3 3ROLF\*URXS
!
3ROLF\
Abbildung 4.11: Beziehungsgeflecht der VPD-Objekte
Views und Privilegien Das oben dargestellte VPD-Konzept wird wegen der umschaltbaren Kontexte auch Partitioned Fine Grain Access Control genannt. Für Informationen zu den oben angelegten Objekten stehen verschiedene DD-Views zur Verfügung: dba_context, dba_policies, dba_policy_contexts und dba_policy_groups, v$vpd_policy, dba_global_context, v$context, v$globalcontext. Über das Systemprivileg EXEMP ACCESS POLICY lässt sich VPD pauschal für einen Benutzer deaktivieren, so dass für den Betreffenden keine WHERE-Klauseln generiert werden! Die oben geschilderten Beispiele funktionieren nur auf der Basis individueller Sessions. Beim Einsatz von Applikationsservern, in deren Kontext unterschiedliche Anwendungsbenutzer über einen Datenbankbenutzer eine Session aufbauen, werden verfeinerte Konzepte benötigt. Diese „globalen“ Anwendungskontexte existieren. Die Darstellung dieser Möglichkeiten sprengt jedoch den Rahmen dieser Abhandlung.
Sandini Bib
304
Sicherheit
4.7
Labels
4.7.1
Überblick
In den vorangehenden Abschnitten wurde gezeigt, wie mit Hilfe von Privilegien Zugriffe auf Tabellen und Views für bestimmte Benutzer freigeschaltet werden können. Diese Objektprivilegien können entweder direkt vom Besitzer des betreffenden Objektes oder durch einen von diesem Besitzer explizit privilegierten Dritten26 vergeben werden. Kein DBA hat von sich aus das Recht, Objektprivilegien für fremde Objekte zu erteilen oder zurückzunehmen, obwohl er auf der anderen Seite Daten aller Tabellen lesen und verändern darf. Bei Zugriffen über Labels dagegen entscheiden nicht die vergebenen Objektprivilegien alleine darüber, ob ein Benutzer eine bestimmte Tabelle und deren Daten abfragen und verändern darf. LabelSysteme erfordern darüber hinaus die Übereinstimmung des jeweiligen Benutzeroder Session-Labels mit den Daten-Labeln, die jedem Datensatz zugeordnet sind. Anders ausgedrückt: Jeder Benutzer kann nur die Daten sehen, deren Label mit dem ihm zugeordneten Label kompatibel sind. Labels werden von Administratoren zentral im Rahmen von Richtlinien (policies) für jede Datenbank konfiguriert. Einmal angelegt, können sie auf der einen Seite Sessions (session label) und auf der anderen Seite Tabellenzeilen (row label) zugeordnet werden. Nur wenn der Label eines Benutzers oder einer Session mit dem Label einer Tabellenzeile vereinbar ist und entsprechende Objektprivilegien vorliegen, kann der Zugriff erfolgen. Label-Systeme werden auf Grund dieses „übergreifenden“ Kriteriums auch MAC-Systeme (mandatory access control) genannt, weil der Eigentümer alleine nicht über den Zugriff entscheiden kann. Im Gegensatz zu MAC-Systemen steht bei DAC-Systemen (discretionary access control) der jeweilige Besitzer im Mittelpunkt, indem er eigenmächtig die Zugriffe per Grant-Befehl vergeben kann. Für die meisten Tabellenobjekte genügen DAC-Zugriffskriterien. DACPrivilegien können dort wo es die Sicherheit der Daten erfordert durch MAC-Label ergänzt werden. Typische MAC-Objekte sind in der Regel solche, bei denen die Entscheidung darüber, wer zugreifen darf, nicht dem Besitzer des betreffenden Objektes alleine anvertraut werden darf. Objekte, bei denen die Privilegierung auf Zeilenebene nicht über bestimmte vorgegebene Spaltenwerte – Benutzer X sieht alle Daten von Abteilung 10 – oder feststehende Unterabfragen geregelt werden kann, sondern über komplexe nicht standardisierbare Mechanismen entschieden wird, sind ebenfalls für den Einsatz von Labels prädestiniert. Ein großer Vorteil des LabelSystems ist darüber hinaus, dass es nicht pauschal konfiguriert werden muss, sondern individuell für einzelne Tabellenobjekte im Rahmen von Richtlinien zuschaltbar ist. Neben SELECT-Operationen können auch INSERT-, UPDATE- und DELETEBefehle das Label-System nutzen. Bisher erforderte der Einsatz des Label-Systems im Kontext von Oracle-Datenbanken auf der einen Seite ein speziell zertifiziertes Betriebssystem (B-Level) und auf der anderen Seite eine für dieses System zertifizierte Version von Trusted Oracle. Labels sind unter Oracle9i nun auch ohne B-Betriebssystem und ohne entspre26. Die WITH GRANT OPTION-Klausel des GRANT-Befehls
Sandini Bib
Labels
305
chende Trusted-Version der Datenbank zu realisieren. Oracle Label Security (OLS) baut intern auf dem VPD27-Konzept auf, das in Abschnitt 4.6 beschrieben wurde. Für den Aufbau und die Verwaltung von Label-Systemen stehen einige Pakete mit entsprechenden Prozeduren und Funktionen zur Verfügung. Darüber hinaus lassen sich die wichtigsten Aufgaben auch über die grafische Oberfläche des Oracle Policy Manager28 realisieren.
4.7.2
Die Grundlagen
Ein Label-System im Rahmen einer Oracle-Datenbank aufzubauen bedeutet im Einzelnen: 1. Richtlinien (policies) anzulegen, die vorgeben, in welchem operativen Kontext Label-Operationen prinzipiell zur Anwendung kommen sollen. Der Kontext von Richtlinien wird über Optionen festgelegt. Mögliche Optionen sind auszugsweise in der folgenden Tabelle dargestellt: Option
Bedeutung
READ_CONTROL
Aktiviert die Richtlinien für alle Abfragen, auch für implizite Abfragen im Kontext von UPDATE-, INSERT- und DELETE-Befehlen.
WRITE_CONTROL
Aktiviert die Richtlinien für INSERT-, UPDATE- und DELETE-Operationen
ALL_CONTROL
Aktiviert die Richtlinien in jedem möglichen Kontext.
Tabelle 4.5: Auszüge aus den Policy-Optionen
Neben den Optionen spezifiziert jede Richtlinie auch den Namen der LabelSpalte. Label-Spalten enthalten die Daten-Labels und werden für alle Tabellen angelegt, die im Rahmen des Label-Systems verwaltet werden. 2. Sind Richtlinien spezifiziert, müssen im Kontext dieser Richtlinien die Komponenten geplant und definiert werden, aus denen letztendlich die Labels zusammengesetzt werden können. Die Planung der Label-Komponenten wie auch der Labels selbst erfordert große Sorgfalt und orientiert sich an den spezifischen Sicherheitsbedürfnissen der betreffenden Datenbank. Jeder Label kann sich prinzipiell aus ein bis drei unterschiedlichen Komponenten zusammensetzen: –
Level: Jeder Label muss aus einer Level-Komponente bestehen. Levels sind hierarchisch organisiert und ermöglichen dadurch eine Klassifizierung der zugeordneten Daten hinsichtlich ihrer Sensibilität. Beispielsweise lassen sich die Level u (unbedenklich), g (geheim) und sg (streng geheim) definieren. Die hierarchische Ordnung wird über numerische Angaben erreicht. Je höher der numerische Wert, desto sensibler der Level.
–
Compartment: Compartments erlauben zusätzlich die Unterteilung der Daten in operationale Bereiche. Beispielsweise lassen sich die Compartments vk
27. VPD = Virtual Private Database 28. Aufruf im Unix-Umfeld über oemapp opm
Sandini Bib
306
Sicherheit
(Verkauf) oder mk (Marketing) anlegen. Jeder Label kann ein oder mehrere Compartments enthalten. –
Group: Auch Gruppen sind für Labels optional. Sie lassen sich wie Level hierarchisch definieren, können aber, im Gegensatz zu diesen, jedem Label mehrfach zugewiesen werden. Über Gruppen können beispielsweise Organisationsbereiche implemtiert werden: rw (westliche Region) oder rs (Region Süd). Die hierarchische Staffelung kann durch eine jeder Gruppe zuzuweisende parent group zum Ausdruck gebracht werden.
3. Aus den einzeln definierten Label-Komponenten können schließlich gültige Daten-Labels zusammengesetzt werden: g:vk,mk:rs steht beispielsweise für den Level geheim mit den Compartments Verkauf und Marketing sowie der Gruppe Region Süd, wobei die Komponenten über Doppelpunkt voneinander getrennt werden. Ein weiterer gültiger Label könnte sein: sg für streng geheim, Compartments und Gruppen sind hier – als optionale Komponenten – nicht zugewiesen worden. Jedem Label wird bei seiner Erstellung entweder explizit oder implizit ein numerischer Bezeichner (tag) zugewiesen. Dieser Bezeichner ist es, der intern in der Label-Spalte der einzelnen Benutzertabellen gespeichert wird. 4. Die Richtlinien, in deren Kontext die Labels definiert wurden, müssen im nächsten Schritt einzelnen Tabellen, Prozeduren oder ganzen Schemas zugewiesen werden. Die Optionen der Richtlinien, die den operativen Kontext festlegen – z.B. WRITE_CONTROL –, werden entweder implizit auf die Objekte übertragen oder können dort nochmals alternativ spezifiziert werden. Darüber hinaus lassen sich bei der Zuweisung auch Label-Funktionen angeben, die individuell kodiert für die automatisierte Generierung von Labels bei INSERT-Operationen zuständig sein können. Es lassen sich hier ebenfalls Prädikate spezifizieren, die zusätzlich zu den Labels die Zugriffe steuern können. 5. Damit Benutzer auf die im Rahmen des Label-Systems verwalteten Tabellen Zugriff erhalten können, müssen jedem Benutzer entweder so genannte BenutzerLabels (user label, session label) oder einzelne Levels, Compartments oder Groups zugewiesen werden. Im letzteren Fall werden für jeden Benutzer folgende Autorisierungen festgelegt: –
Der maximale Level, den der Betreffende lesen und schreiben darf. Wird ein Benutzer beispielsweise für den Level g (geheim) freigegeben, darf er alle hierarchisch tieferen Level lesen, allerdings nur bis zu seinem minimalen Level schreiben.
–
Sein Default-Level schließlich gibt den Level an, unter dem er standardmäßig operiert.
–
Der Default Row Level schließlich ist der Level, der beim Einfügen von Datensätzen übertragen wird, sofern für die Tabelle keine Label-Funktion angegeben wurde.
–
Gleichermaßen werden dem Benutzer Compartments und Gruppen zugeordnet, für die er Berechtigungen erhalten soll. Für jede der beiden letztgenannten Komponenten kann separat angegeben werden, ob der Benutzer
Sandini Bib
Labels
307
Schreibrechte erhält und ob die genannte Komponente Bestandteil seines standardmäßigen Session-Labels (default) sowie Daten-Labels (row) wird.
Abbildung 4.12: Zuordnung von Label-Komponenten zu Benutzern (1)
Ein Beispiel soll den vorangehenden Abschnitt verdeutlichen. Dem Benutzer scott wird der minimale Level g und der maximale Level sg zugewiesen. Er erhält darüber hinaus den Default-Level g und auch den Row-Level g. Ihm wird das Compartment mk (Marketing) zugeteilt und die Gruppe rs (Region Süd). Auf beiden Komponenten erhält er Schreibrechte und beide werden auch Bestandteil seiner Sessionund Row-Labels. Meldet sich scott im Folgenden an der Datenbank an, arbeitet er unter dem Level g, dem Compartment mk und der Gruppe rs als Session-Label (g:mk:rs). Er kann mit diesen Einstellungen alle Datensätze lesen, die maximal den Level g in ihrem Row-Label haben, mindestens die Gruppe rs oder keine Gruppe sowie ausschließlich das Compartment mk oder kein Compartment haben.
Sandini Bib
308
Sicherheit
Abbildung 4.13: Zuordnung von Label-Komponenten zu Benutzern (2)
Daten, die andere oder zusätzliche Compartments enthalten, stehen scott nicht zum Lesen zur Verfügung! Da er maximal für den Level sg autorisiert wurde, kann Scott im laufenden Betrieb seinen Session-Label ändern, z.B. in sg:mk:rs. Damit hat er Zugriff auf weitere Daten. Wenn er Daten einfügt, gibt er diesen – sofern er die Einstellungen seiner Session nicht ändert – seinen Default-Row-Label g:mk:rs mit. Zusätzlich darf er alle die Datensätze ändern, die mindestens seinem minimalen Level g entsprechen, die mindestens die Gruppe rs sowie maximal das Compartment mk enthalten.
Abbildung 4.14: Kompatibilität zwischen Session-Label und Row-Label
Sandini Bib
Labels
309
6. Neben den Label-Komponenten können den Benutzern zusätzlich noch spezielle Systemprivilegien zugeteilt werden, die den Betreffenden erlauben, sich über bestimmte Label-Autorisierungen hinwegzusetzen. Die folgende Tabelle enthält einige Beispiele: Systemprivilegien
Berechtigungen
WRITEUP
Gestattet die Veränderung der Level-Komponente von RowLabeln bis zum maximalen Level des ausführenden Benutzers
WRITEDOWN
Gestattet die Veränderung der Level-Komponente von RowLabeln bis zum minimalen Level des ausführenden Benutzers
READ
Gibt dem Betreffenden volles Leserecht auf alle Daten der betreffenden Richtlinie
Tabelle 4.6: Systemprivilegien im Label-Kontext (Auszug)
Die wenigen Beispiele zeigen bereits, wie mächtig diese Systemprivilegien ausfallen. Es ist daher dringend anzuraten, sie nur in Ausnahmefällen zu vergeben, beispielsweise an Administratoren, die einen vollständigen Export von LabelDaten durchführen müssen (READ).
4.7.3
Konfiguration eines Label-Systems
Im Folgenden wird der Aufbau eines Label-Systems unter Verwendung der Beispiele des vorangehenden Abschnittes im Einzelnen durchgeführt. Alle Arbeitsschritte sind über den Oracle Policy Manager grafisch und interaktiv durchführbar, gleichwohl werden in unserem Beispiel entsprechende Prozeduraufrufe benutzt, die für den Aufbau umfangreicher Label-Umgebungen unverzichtbar sind. Im ersten Schritt ist bekanntlich eine Richtlinie zu definieren. Die Richtlinie soll in unserem Beispiel den Namen test_policy erhalten. Der Name der – für RowLabels notwendigen – verdeckten Spalte soll labtest_col sein. Dieser Spaltenname muss unter allen angelegten Richtlinien eindeutig sein. Die Richtlinie soll darüber hinaus sämtliche Label-Optionen aktivieren (all_control). BEGIN sa_sysdba.create_policy( policy_name => 'TEST_POLICY', column_name => 'LABTEST_COL', default_options => 'ALL_CONTROL'); END; / Listing 4.19: Erstellung einer Richtlinie
Erstellte Richtlinien können über die View dba_sa_policies selektiert werden: POLICY_NAME COLUMN_NAME STATUS --------------------- -------------------- -------TEST_POLICY LABTEST_COL ENABLED
Sandini Bib
310
Sicherheit
POLICY_OPTIONS -------------------------------------------------------------READ_CONTROL, INSERT_CONTROL, UPDATE_CONTROL, DELETE_CONTROL, LABEL_DEFAULT, LABEL_UPDATE, CHECK_CONTROL Listing 4.20: dba_sa_policies
Die Spalte Status ENABLED verdeutlicht bereits, dass Richtlinien im Kontext von Tabellen auch „ausgeschaltet“ werden können. Es versteht sich, dass Zugriffe in diesem Fall ohne die Kontrollen des Label-Systems erfolgen. Im Rahmen dieser Richtlinien werden nun die Label-Komponenten einzeln definiert. BEGIN sa_components.create_level( policy_name => 'TEST_POLICY', level_num => 5, short_name => 'G', long_name => 'geheim'); sa_components.create_level( policy_name => 'TEST_POLICY', level_num => 10, short_name => 'SG', long_name => 'streng geheim'); END; / Listing 4.21: Erstellen der Level
Das vorangehende Beispiel zeigt den Aufbau der Levels g und sg. Die numerischen Angaben (Parameter level_num) werden für die hierarchische Gruppierung benötigt. Der Kurzname dient der Anzeige über entsprechende Funktionen oder über den Policy Manager, die Langform hat rein dokumentarischen Charakter. Die View dba_sa_levels gibt alle vorhandenen Levels mit den ihnen zugeordneten Richtlinien aus. Compartments und Gruppen werden analog angelegt: BEGIN sa_components.create_compartment( policy_name => 'TEST_POLICY', comp_num => 10, short_name => 'MK', long_name => 'Marketing'); sa_components.create_compartment( policy_name => 'TEST_POLICY', comp_num => 20,
Sandini Bib
Labels
311
short_name long_name
=> 'VK', => 'Verkauf');
END; / Listing 4.22: Erstellen der Compartments
Für Gruppen steht eine entsprechende Prozedur create_group zur Verfügung, bei der über den zusätzlichen Parameter parent_name eine Master-Gruppe angegeben werden kann. Die Parameter policy_name bzw. group_name haben in beiden Fällen keine hierarchisierende Funktion. Die Views dba_sa_groups und dba_sa_compartments geben die vorhandenen Komponenten aus. Sind alle Komponenten angelegt, lassen sich die Daten-Label definieren: BEGIN sa_label_admin.create_label( policy_name => 'TEST_POLICY', label_tag => 101010, label_value => 'G:MK:RS'); sa_label_admin.create_label( policy_name => 'TEST_POLICY', label_tag => 201010, label_value => 'SG:MK:RS'); END; / Listing 4.23: Erstellen der Label
Die numerischen Bezeichner der Labels (label_tag) werden in der Label-Spalte der Tabellen gespeichert und nicht etwa die entsprechenden Kurznamen sg:mk_rs usw. Sie können explizit vergeben werden oder werden – wenn dies nicht geschieht – implizit generiert. Es ist in jedem Fall empfehlenswert, Label-Bezeichner nach einem bestimmten Konzept explizit vorzuschreiben. In unserem Beispiel wurden jeweils zwei Ziffern für jede Komponente vergeben: 10 für den Level g, 20 für sg usw. Nur bei einem solchen Vorgehen ist es möglich, die Daten nach dem Sensibilisierungsgrad zu gruppieren oder gar zu partitionieren. Angelegte Labels können über die View dba_sa_labels selektiert werden. Im nächsten Schritt ist nun die Richtlinie test_policy mit Tabellen oder Schemas zu verknüpfen. Das folgende Beispiel zeigt die Verknüpfung mit der Tabelle emp von scott: BEGIN sa_policy_admin.apply_table_policy ( policy_name => 'TEST_POLICY',
Sandini Bib
312
Sicherheit
schema_name => 'SCOTT', table_name => 'EMP'); END; / Listing 4.24: Verknüpfung von Richtlinien mit Tabellen
Im Zuge dieser Verknüpfung wird die in der Richtlinie angegebene Spalte labtest_col für die Tabelle emp angelegt. Zusätzlich kann die Hide-Option gesetzt werden, die bewirkt, dass die Labelspalte labtest_col nicht sichtbar29 ist. Allerdings enthält die Label-Spalte in unserem Beispiel für vorhandene Datensätze noch keine Label-Angaben. Entsprechend sind abschließend die Altdaten von emp explizit mit einem Label zu versehen. Hierzu steht die Funktion char_to_label zur Verfügung, die den alphanumerischen Wert eines Labels in die numerische Entsprechung umsetzt. In unserem Beispiel werden die Angestellten der Abteilung 20 mit dem Label g:mk:rs versehen. UPDATE scott.emp SET labtest_col = char_to_label('TEST_POLICY', 'G:MK:RS') WHERE deptno = 20;
Wie bereits erwähnt speichert die Label-Spalte nur numerische Daten: SELECT empno, labtest_cal FROM scott.emp WHERE deptno = 20; EMPNO LABTEST_COL ---------- ----------7369 101010 7566 101010 7788 101010 7876 101010 7902 101010 Listing 4.25: Label-Spalte
Nicht vergessen werden darf die Autorisierung der einzelnen Benutzer. Die Prozeduren erlauben dabei sowohl die Angabe einzelner Komponenten als auch die Spezifikation über fertige Labels. In den folgenden Beispielen wird der Benutzer Scott über die einzelnen Label-Komponenten autorisiert. BEGIN sa_user_admin.set_levels ( policy_name => 'TEST_POLICY', user_name => 'SCOTT', max_level => 'SG', 29. Nicht sichtbar für DESCRIBE- und SELECT *- Befehle. Die Spalte kann allerdings explizit selektiert werden.
Sandini Bib
Labels
313
min_level def_level row_level
=> 'G', => 'G', => 'G');
END; / Listing 4.26: Autorisierung Benutzer
Zunächst werden für Scott die Hierarchiestufen (level) bestimmt, in deren Kontext er Operationen ausführen darf. min_level gibt dabei die unterste Hierarchiestufe für Schreiboperationen an, max_level analog die höchste Stufe für Schreib- und Leseoperationen. def_level gibt die Stufe an, auf der sich der Benutzer nach dem Connect bewegt. row_level setzt den Standard für INSERT-Operationen. Auf ähnliche Weise werden im Folgenden die Compartments und die Gruppen für scott vorgegeben: BEGIN sa_user_admin.set_compartments ( policy_name => 'TEST_POLICY', user_name => 'SCOTT', read_comps => 'MK', write_comps => 'MK', def_comps => 'MK', row_comps => 'MK'); END; / BEGIN sa_user_admin.set_groups ( policy_name => 'TEST_POLICY', user_name => 'SCOTT', read_groups => 'RS', write_groups => null, def_groups => 'RS', row_groups => 'RS'); END; / Listing 4.27: Compartment und Gruppe zuweisen
Über die in den vorangehenden Beispielen gemachten Angaben werden entsprechende Labels generiert, die für die Zugriffe von scott relevant sind. Die folgende Abbildung zeigt diese generierten Labels. In wenigen, wohl begründeten Fällen kann es notwendig sein, einem Benutzer spezielle Privilegien im Rahmen des Label-Systems zu erteilen. Im folgenden Beispiel erhält scott das WRITEUP-Privileg, mit dem ihm erlaubt wird, die Level-Komponente eines Daten-Labels bis zu seinem eigenen, maximalen Level – in unserem Beispiel sg – zu erhöhen.
Sandini Bib
314
Sicherheit
BEGIN sa_user_admin.set_user_privs ( policy_name => 'TEST_POLICY', user_name => 'SCOTT', privileges => 'WRITEUP'); END; / Listing 4.28: Spezielle Privilegien
Abbildung 4.15: Generierte Benutzer-Labels
Die erteilten Label-Komponenten und Privilegien lassen sich auch für den Endbenutzer über die Views all_sa_users und all_sa_user_labels abfragen. Ist die Label-Spalte der betreffenden Tabelle offen gelegt, können darüber hinaus die Daten-Labels direkt abgefragt werden: SELECT empno, deptno, label_to_char(labtest_col) label FROM emp; EMPNO DEPTNO LABEL ---------- ---------- ---------7369 20 G:MK:RS 7876 20 G:MK:RS Listing 4.29: Abfrage-Label
Sandini Bib
Labels
315
Im vorangehenden Beispiel sieht der Benutzer scott nur die Daten mit dem Label g:mk:rs, weil sein Standard-Session-Label auf g:mk:rs eingestellt wurde. Der Benutzer kann dieses Session-Label allerdings im Rahmen der ihm zugeteilten Privilegien über die Prozedur sa_session.set_label abändern und erhält – je nachdem wie die Daten-Labels vergeben sind – andere Treffermengen. SET SERVEROUTPUT ON DECLARE dum VARCHAR2(100); BEGIN -- entweder über den alphanumerischen Label sa_session.set_label('TEST_POLICY', 'SG:MK:RS'); -- oder alternativ numerisch -- sa_utl.set_label('TEST_POLICY', 201010); -- zur Kontrolle den aktuellen Session-Label noch einmal ausgeben dum := sa_session.label('TEST_POLICY'); dbms_output.put_line(dum); END; / Listing 4.30: Label-Abfrage über Prozedur
Neben Tabellen und Benutzern können auch Programmeinheiten mit Label-Privilegien versehen werden. Auf diese Weise lassen sich außergewöhnliche Zugriffe über geprüfte Programmeinheiten realisieren. Im folgenden Beispiel wird der Funktion zaehl_test, welche die Anzahl der Datensätze in einer Tabelle mit Namen Test ausgibt, das READ-Privileg zugeteilt. Dieses Privileg erlaubt der Funktion das vollständige Lesen der Tabelle Test, unabhängig von den eingestellten Label-Privilegien des aufrufenden Benutzers. Die Label-Privilegien von Programmeinheiten werden aus verständlichen Gründen mit jeder Kompilierung zurückgenommen und müssen entsprechend neu zugeteilt werden. BEGIN sa_user_admin.set_prog_privs ( policy_name => 'TEST_POLICY', schema_name => 'BLA', program_unit_name => 'ZAEHL_TEST', privileges => 'READ'); END; / Listing 4.31: Vergabe von Label an Programmeinheiten
Sandini Bib
316
4.8
Sicherheit
Profile
Die Benutzerprofile haben zwei Aufgaben. Erstens die Einschränkung von Ressourcen und des Weiteren die Möglichkeit des Managements von Passwörtern. Jedem Benutzer wird durch den Befehl CREATE USER automatisch ein Standardprofil zugewiesen. Dieses Profil mit dem Namen DEFAULT setzt zunächst alle Begrenzungen auf UNLIMITED, bzw. schaltet alle Parameter für das Passwortmanagement aus. Es kann aber jederzeit durch einen Administrator mit Grenzen versehen werden. In der Regel wird das Standardprofil jedoch nicht angepasst, sondern es werden für bestimmte Benutzergruppen eigene Profile angelegt, die diesen dann zugeordnet werden. Dabei ist zu beachten, dass dem Benutzer automatisch das Standardprofil zugewiesen wird, wenn ein Profil gelöscht wird.
4.8.1
Management von Ressourcen
Mit den Ressourcenparametern sind grobe Grenzen für die CPU-Benutzung oder das EA-Verhalten einstellbar, des Weiteren können Beschränkungen hinsichtlich Anzahl gleichzeitiger Sessions und die maximale IDLE-Zeit eingestellt werden. In der Praxis haben sich einige dieser Parameter als nützlich erwiesen, während andere, wie zum Beispiel PRIVATE_SGA, so gut wie nie eingesetzt werden. ALTER SYSTEM SET RESOURCE_LIMIT = TRUE;
In diesem Beispiel wird zunächst die Ressourcen-Limitierung aktiviert. Dies kann entweder über den o.g. Befehl ALTER SYSTEM geschehen oder über den Initialisierungsparameter resource_limit = true. Damit werden mit dem Anmelden einer Session die Parameter überwacht. Im Folgenden werden die einzelnen Parameter beschrieben:
:
session_per_user
:
cpu_per_session
:
Anzahl gleichzeitiger Verbindungen zur Instanz. Dieser Parameter ermöglicht es, die Anzahl gleichzeitiger Verbindungen zu einer Instanz sinnvoll zu limitieren. Leider scheitert die Benutzung oftmals daran, dass alle Benutzer über den gleichen Schemanamen mit der Datenbank arbeiten. Dieser Parameter soll den CPU-Verbrauch einer Session einschränken (in 1/100Sekunden) und somit den Benutzer davon abhalten, sehr umfangreiche Abfragen zu starten. Wird während der Ausführung eines Befehls diese Limitierung überschritten, wird er mit einer Fehlermeldung abgebrochen. Da kaum jemand erfassen kann, wie viel CPU-Verbrauch eine Session hat, wird dieser Wert selten gesetzt. cpu_per_call
Mit diesem Wert kann eine CPU-Begrenzung noch genauer festgelegt werden, da hier die einzelnen Phasen einer Abfrage (PARSE, EXECUTE, FETCH) gemessen werden. Das macht oft dann Sinn, wenn auf einem sehr ausgelasteten OLTPSystem gelegentliche Abfragen durchgeführt werden, da diese bei Erreichen des
Sandini Bib
Profile
: :
:
:
:
:
317
Limits abgebrochen werden. Somit kann mit dem Befehl ALTER USER einem Benutzer für den Tagesbetrieb ein Profil mit einem niedrigen Wert und bei Nachtbetrieb mit großem oder unlimitiertem Wert zugewiesen werden. logical_reads_per_session
Für diesen Parameter gilt das Gleiche wie bei cpu_per_session. Da die Menge der Datenbankblöcke, die für die Dauer einer Verbindung gelesen werden, nur schwer fassbar ist, wird dieser Wert selten gesetzt. logical_reads_per_call
Hiermit wird die maximale Anzahl von Lesezugriffen auf Datenbankblöcke je Aufruf (PARSE, EXECUTE, FETCH) festgelegt. Ebenso wie der Parameter cpu_per_call kann dieser Wert sinnvoll in Hochlastsystemen sein, um bestimmte Abfragen abzublocken. Leider wird die Abfrage zunächst aber gestartet und erst mit der Erreichung der Grenze abgebrochen. idle_time
Eine sehr sinnvolle Methode, um zu vermeiden, dass sich Benutzer zwar an der Datenbank anmelden und somit Ressourcen blockieren, aber nicht mit der Datenbank arbeiten. Wenn der Benutzer eine Zeit lang (im Beispiel 30 Minuten) keine Eingabe vornimmt, wird die Session als beendet gekennzeichnet. Ein Abmelden des Prozesses erfolgt jedoch erst mit der nächsten Eingabe des Benutzers, so dass hier der erzieherische Effekt im Vordergrund steht. connect_time
Es ist schwierig für diesen Parameter, der die Dauer einer Verbindung beschränkt, eine geeignete Anwendung zu finden. Sicherlich kann es als erzieherische Maßnahme sinnvoll sein, dass jeder beim Nachhausegehen seine offenen Verbindungen zur Datenbank beendet, aber der gleiche Effekt kann auch mit der idle_time erzielt werden und dort, durch die Einschränkung des „Nichtstuns“ wesentlich effektiver. private_sga
Dieser Parameter bezieht sich ausschließlich auf die Verwendung des Shared Server, da hierbei der private SQL- und PL/SQL-Anteil einer Verbindung Teil der SGA wird. Auch dieser Wert ist schwer einzuschätzen, daher wird er sehr selten genutzt. composite_limit
Mit diesem Parameter werden die Gesamtressourcen einer Verbindung auf der Basis von Service Units beschränkt. Damit werden sowohl CPU-Zeit als auch lesende Zugriffe gemessen und entsprechend gewichtet. Mit dem Befehl ALTER RESOURCE COST kann die Gewichtung eingestellt werden.
Im folgenden Beispiel wird ein Profil mit dem Namen p_verwaltung erstellt. Dann wird für das composite_limit die Gewichtung eingestellt. Danach können die Benutzer das Profil über den Befehl ALTER USER zugewiesen bekommen oder neue Benutzer können wie im Beispiel direkt das neue Profil erhalten.
Sandini Bib
318
Sicherheit
CREATE PROFILE p_verwaltung LIMIT SESSIONS_PER_USER 2 CPU_PER_SESSION unlimited CPU_PER_CALL 6000 LOGICAL_READS_PER_SESSION unlimited LOGICAL_READS_PER_CALL 100 IDLE_TIME 30 CONNECT_TIME 480 COMPOSITE_LIMIT 20000; ALTER RESOURCE COST CPU_PERS_SESSION 1 LOGICAL_READS_PER_SESSION 50; CREATE USER heyo IDENTIFIED BY heyo DEFAULT TABLESPACE USERS PROFILE p_verwaltung; GRANT CONNECT, RESOURCE TO heyo; Listing 4.32: Erstellen und Zuweisen eines Profils
4.8.2
Password Management
Neben der Limitierung von Ressourcen ist ein weiteres Thema der Profile die Überwachung von Kennworten. Damit existiert die Möglichkeit, ähnlich wie auf Betriebssystemebene Vorgaben bezüglich der Passworte zu machen. Im Gegensatz zu den Ressourcen müssen diese Parameter nicht erst über den ALTER SYSTEMBefehl oder einen Initialisierungsparameter aktiviert werden, sondern sind immer aktiv.
:
:
: :
failed_login_attempts
Maximale Anzahl fehlerhafter Kennworteingaben. Danach wird das Schema gesperrt und erst nach Ablauf von password_lock_time-Tagen oder durch den Administrator wieder freigegeben. password_lifetime
Gültigkeitsdauer des Kennwortes in Tagen. Nach Ablauf der Frist wird das Kennwort ungültig und kann nur noch für die Änderung z.B. mit dem SQL*PlusBefehl PASSWORD eingegeben werden. Vorher wird der Benutzer eine Zeit lang (password_grace_time) aufgefordert, ein neues Kennwort einzugeben. password_reuse_time
Hier wird die Mindestzeit in Tagen angegeben, nach der ein Kennwort wieder verwendet werden kann. password_reuse_max Ähnlich wie bei password_reuse_time wird hiermit die Wiederverwendbarkeit
eines Kennwortes geregelt. In diesem Fall wird allerdings die Anzahl der Kennwortwechsel festgelegt. Beide Parameter können nur alternativ genutzt werden.
Sandini Bib
Profile
:
password_lock_time
:
password_grace_time
:
319
Anzahl von Tagen, nach denen ein durch fehlerhafte Eingaben gesperrtes Kennwort wieder freigegeben wird. Übergangsperiode in Tagen, während der der Benutzer zum Ändern des Kennwortes aufgerufen wird. Dieser Parameter ist nur in Verbindung mit password_life_time sinnvoll. password_verify_function
Falls die oben beschriebenen Mechanismen nicht ausreichen, können über PL/ SQL-Funktionen eigene Routinen für das Password-Management erstellt werden. Mit dem Script utlpwdmg.sql im Verzeichnis $ORACLE_HOME/rdbms/admin wird eine Routine für die Überprüfung der Komplexität eines Kennwortes mitgeliefert. Mit der Funktion verify_function wird überprüft, ob eine Mindestlänge von vier Zeichen mit mindestens einem Sonderzeichen eingegeben wurde, ob bestimmte einfache Passwörter wie z.B: „manager“ eingegeben wurden und ob das Passwort sich in mindestens drei Zeichen vom vorherigen unterscheidet.
@?/rdbms/admin/utlpwdmg.sql ALTER PROFILE p_verwaltung LIMIT PASSWORD_LIFE_TIME 60 PASSWORD_GRACE_TIME 5 PASSWORD_REUSE_TIME 180 PASSWORD_REUSE_MAX UNLIMITED FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 7 PASSWORD_VERIFY_FUNCTION verify_function; Listing 4.33: Password Management
Mit diesem Beispiel wird zunächst die Funktion verify_function erstellt und anschließend dem Profil p_verwaltung zusammen mit anderen Password-Mechanismen zugewiesen. Für alle Profile gilt, dass sie nur zu Beginn einer Session ausgewertet werden und somit anschließende Änderungen keine Auswirkungen auf bestehende Verbindungen haben. Eine Übersicht über die vorhandenen Profile und Einstellungen gibt die View dba_profiles. In der View dba_users kann überprüft werden, welche Benutzer welches Profil verwenden.
Sandini Bib
320
Sicherheit
4.9
Management von Ressourcen mit dem Resource Manager
4.9.1
Überblick
Seit der Version 8i der Oracle-Datenbank gibt es den Database Resource Manager, mit dessen Hilfe es möglich ist, bestimmte System- und Datenbankressourcen einzelnen Benutzern sinnvoll zuzuteilen. Dadurch, dass die Zuteilung der Ressourcen über interne Mechanismen der Datenbank und nicht allein über das Betriebssystem durchgeführt werden kann, ergeben sich zusätzliche und verfeinerte Möglichkeiten für den Datenbankverwalter. Im Einzelnen lassen sich die folgenden Ressourcen hinsichtlich ihrer maximalen Nutzung vorgeben:
: : : :
Zuteilung von maximalen CPU-Zeiten Begrenzung des Parallelisierungsgrades für Datenbankoperationen Begrenzung der Anzahl gleichzeitig aktiver Datenbanksitzungen Vorgaben für die Nutzung von Speicherplatz in Rollback-Segmenten (undo pool)
Der Database Resource Manager ergänzt derzeit noch die im vorangehenden Abschnitt besprochenen Profile und geht im Funktionsumfang weit über diese hinaus. Die bewusste Aufteilung von Ressourcen ist überall dort sinnvoll, wo eine Vielzahl von Benutzern und Anwendungen mit unterschiedlichen Anforderungen untereinander um die Nutzung von CPU-Zyklen, Rollback-Segmenten und Parallel ServerProzessen konkurrieren. Der Database Resource Manager operiert im Kontext von Konsumentengruppen (consumer groups) und Ressourcenplänen. Für die Einstellung der Vorgaben können entweder die API-Prozeduren der PL/SQL-Pakete dbms_resource_manager und dbms_resource_manager_privs oder die grafische Oberfläche des Enterprise Managers30 genutzt werden. Zum Aufbau komplexer Umgebungen ist auf jeden Fall die Nutzung des PL/SQL-API zu empfehlen. Kleinere Verwaltungsarbeiten können dagegen komfortabel über die Oberfläche des Enterprise Managers erledigt werden. Die folgenden Arbeitsschritte sind zum Aufbau eines Ressourcenmanagements notwendig: Zunächst müssen analog zu den gegebenen Prioritäten Konsumentengruppen angelegt werden. Diesen Konsumentengruppen sind dann einzelne Benutzer oder Rollen zuzuweisen. Gleichzeitig werden Ressourcenpläne angelegt. Die Konsumentengruppen und die Ressourcenpläne werden anschließend über so genannte Direktiven miteinander verknüpft. Die Direktiven bestimmen hierbei die konkreten Vorgaben für die Nutzung der oben aufgelisteten Ressourcentypen. Es können unterschiedliche Pläne mit unterschiedlichen Anforderungen erstellt werden. Jeder Plan kann hierarchisch aufgebaut sein, d.h., er kann aus einem oder 30. In der Version 9.0.1 des Enterprise Manager sind nicht alle Einstellungen über die grafische Oberfläche möglich.
Sandini Bib
Management von Ressourcen mit dem Resource Manager
321
mehreren Unterplänen bestehen. Die Vorgaben der Ressourcenpläne werden allerdings erst dann wirksam, wenn der betreffende Plan aktiviert wurde. Zu einem bestimten Zeitpunkt lässt sich immer nur ein Plan aktivieren, die Umschaltung auf einen alternativen Plan kann allerdings dynamisch, möglicherweise über eine Zeitsteuerung, erfolgen. Einmal aktiviert, regelt der Plan die maximale Nutzung von Ressourcen auf der Basis der Konsumentengruppen. Benutzer, welche die Vorgaben ihrer Gruppe über Gebühr beanspruchen, können dabei dynamisch im laufenden Betrieb einer alternativen Konsumentengruppe mit möglicherweise geringeren Prioritäten zugewiesen werden. Im folgenden Abschnitt wird dieses Konzept anhand eines konkretes Beispiels erläutert.
4.9.2
Der Aufbau einer Beispielumgebung
Vorgaben Wir administrieren die fiktive Datenbank mit dem globalen Namen versand.ganzbillig.de. Diese Datenbank wird sowohl von OLTP-Transaktionen als auch von Batch-Programmen genutzt. Gleichzeitig testen zwei Entwicklungsteams ihre Anwendungen in separaten Schemas. In der Vergangenheit gab es immer wieder Beschwerden darüber, dass OLTP-Transaktionen, die Kundenbestellungen verwalten, auf Grund von Batch-Programmen oder Testläufen des Entwicklungsteams nicht genügend CPU-Ressourcen für die effiziente Auftragsbearbeitung zur Verfügung standen. Dies wollen wir mit Hilfe des Resource Managers optimieren. Die folgenden Regeln sollen aus diesem Grund auf Wunsch der Geschäftsleitung implementiert werden: Allen OLTP-Transaktionen sollen während der Geschäftszeiten zwischen 8 und 19 Uhr mindestens 80 % der CPU-Zeiten gesichert zur Verfügung stehen. Die restlichen 20 % sollen im Verhältnis 60 : 40 an die Entwicklungsteams team_a und team_b aufgeteilt werden. Batch-Programmen sollen während dieser Zeit nur die ungenutzten CPU-Ressourcen zufallen. Während der Nacht dagegen erhalten Batch-Programme 90 % der CPU für die Entwicklungsteams stehen die restlichen 10 %, wieder im Verhältnis 60 : 40 zur Verfügung. OLTP-Transaktionen dagegen werden in dieser Zeit nur mit ungenutzten CPUZyklen abgespeist. Diese Anforderungen lassen sich wie folgt tabellarisch darstellen, wobei die „Schichtung“ der oben beschriebenen Vorgaben über unterschiedliche Planungsebenen erreicht wird. Gruppe
CPU-Level 1
CPU-Level 2
CPU-Level 3
OLTP-Transaktionen
80
0
0
team_a
0
60
0
team_b
0
40
0
Batch-Programme
0
0
100
Tabelle 4.7: Tagesplan
Sandini Bib
322
Sicherheit
Gruppe
CPU-Level 1
CPU-Level 2
CPU-Level 3
OLTP-Transaktionen
0
0
100
team_a
0
60
0
team_b
0
40
0
Batch-Programme
90
0
0
Tabelle 4.8: Nachtplan
Zusätzlich zu diesen CPU-Anforderungen sollen auch weitere Vorgaben hinsichtlich des Parallelisierungsgrades und der Nutzung der Rollback-Segmente implementiert werden. Für die Entwickler soll darüber hinaus sichergestellt werden, dass nicht mehr als zehn aktive Sitzungen pro Team während des Tages existieren. Für den Fall, dass Sitzungen von Entwicklern mehr als 300 Sekunden aktiv sind, sollen sie in die Gruppe der Batch-Programme zurückgestuft werden. Privilegien erteilen Benutzer, welche die oben beschriebene Umgebung aufbauen und verwalten wollen, benötigen das Systemprivileg ADMINISTER RESOURCE MANAGER. Dieses Privileg ist bereits in der vordefinierten Rolle DBA enthalten, kann aber auch explizit mit dem folgenden Prozeduraufruf vergeben werden: BEGIN dbms_resource_manager_privs.grant_system_privilege( grantee_name => 'Guenter', privilege_name => 'ADMINISTER_RESOURCE_MANAGER', admin_option => FALSE); END; / Listing 4.34: Privilegienvergabe
Im Gegensatz zu den meisten anderen Systemprivilegien kann ADMINISTER RESOURCE MANAGER nur in dieser Form und nicht über einen GRANT-Befehl zugeteilt werden. Es ist keinesfalls notwendig und auch nicht wirksam, den betreffenden Benutzern die Execute-Rechte für das Paket dbms_resource_manager zuzuteilen. Im vorangehenden Beispiel erhält der Benutzer guenter die Privilegien zur Arbeit mit dem Resource Manager. Er darf diese Privilegien allerdings nicht an Dritte weitergeben (admin_option => false). Erteilte Privilegien können über die View dba_rsrc_manager_system_privs abgefragt werden. Pending Area anlegen Einfache Ressourcenpläne, die sich nur auf die Zuteilung von CPU-Zeiten auf bis zu acht Ebenen beschränken, lassen sich vollständig über die Prozedur create_simple_plan des Paketes dbms_resource_manager zusammen mit ihren Konsumentengruppen und Direktiven anlegen. Für komplexere Umgebungen, so
Sandini Bib
Management von Ressourcen mit dem Resource Manager
323
wie in unserem Beispiel vorgesehen, sind unterschiedliche Prozeduraufrufe notwendig, die alle im Kontext eines Arbeitsbereiches (Pending Area) ablaufen müssen. Dieser Arbeitsbereich kann separat validiert werden und muss schließlich – nachdem alle Aufrufe abgesetzt werden konnten – explizit übermittelt werden, um die Änderungen festzuschreiben. Der folgende Aufruf initiiert diesen Arbeitsbereich: BEGIN dbms_resource_manager.create_pending_area; END; /
Eine Validierung kann über die Prozedur validate_pendig_area, das Löschen über clear_pending_area erreicht werden, was einem Rollback gleichkommt. Sind alle Aufrufe durchgeführt worden, wird der Arbeitsbereich mit submit_pending_area aktiviert. Konsumentengruppen und Ressourcenpläne anlegen Nachdem der Arbeitsbereich initialisiert wurde, können als Nächstes die notwendigen Konsumentengruppen angelegt werden. Im folgenden Beispiel geschieht dies für die in Abschnitt Vorgaben geplanten Gruppen. Jeder Gruppe wird eine entsprechende Kommentarzeile beigefügt: BEGIN dbms_resource_manager.create_consumer_group ( consumer_group => 'OLTP', comment => 'Gruppe für OLTP-Anwendungen'); dbms_resource_manager.create_consumer_group ( consumer_group => 'Batch', comment => 'Gruppe für Batch-Anwendungen'); dbms_resource_manager.create_consumer_group ( consumer_group => 'Team_A', comment => 'Gruppe für Entwicklungsteam A'); dbms_resource_manager.create_consumer_group ( consumer_group => 'Team_B', comment => 'Gruppe für Entwicklungsteam B'); END; / Listing 4.35: Anlegen von Consumer-Groups create_consumer_group bietet noch den Parameter cpu_mth (CPU-Methode), welcher die Strategie bei der Verteilung der CPU-Zeiten innerhalb einer Gruppe regelt. Der einzige mögliche Wert (round-robin) ist gleichzeitig auch der Standardwert und daher hier nicht explizit aufgeführt.
Ähnlich lassen sich die geplanten Ressourcenpläne anlegen:
Sandini Bib
324
Sicherheit
BEGIN dbms_resource_manager.create_plan ( plan => 'Tagesplan', comment => 'Plan für die Tageszeit von 8 bis 19 Uhr'); dbms_resource_manager.create_plan( plan => 'Nachtplan', comment => 'Plan für die Nacht von 19 bis 8 Uhr'); END; / Listing 4.36: Anlegen von Ressourcenplänen
Auch hier lassen sich über zusätzliche Parameter die Methoden für die Zuteilung der verschiedenen Ressourcenbereiche (CPU, Anzahl der aktiven Sessions, Parallelisierung und Nutzung der Warteschlange) regeln. Die eingestellten Standardwerte sind jedoch auch in diesem Fall die einzig möglichen Werte. Ressourcenpläne
und
Konsumentengruppen
können
über
die
Views
dba_rsrc_consumer_groups und dba_rsrc_plans ausgegeben werden.
Grenzwerte vorgeben Nachdem nun die Konsumentengruppen und die Ressourcenpläne angelegt wurden, können die erforderlichen Grenzwerte definiert werden, die für bestimmte Gruppen in bestimmten Plänen gelten sollen. BEGIN dbms_resource_manager.create_plan_directive ( plan => 'Tagesplan', group_or_subplan => 'OLTP', comment => 'OLTP-Ressourcen während des Tages', cpu_p1 => 80, parallel_degree_limit_p1 => 4, undo_pool => 500000); END; / Listing 4.37: Anlegen von Grenzen für Ressourcenpläne
Im vorangehenden Beispiel wird festgeschrieben, dass alle aktiven Sitzungen der Gruppe oltp im Rahmen des Planes Tagesplan zusammen maximal 80 % der CPUZeit und für jede parallelisiert ausgeführte Operation maximal vier Serverprozesse verbrauchen darf. Der Speicherplatz aller in dieser Gruppe aktiven Sitzungen darf in den Rollback-Segmenten (undo pool) 500.000 Kbyte nicht überschreiten. Die Gruppe oltp ist die einzige Gruppe der ersten Schicht. Die verbleibenden oder nicht genutzten Ressourcen, für den Fall, dass oltp keine aktiven Sitzungen vorzuweisen hat, werden der nächstfolgenden Schicht, in diesem Falle der Schicht 2,
Sandini Bib
Management von Ressourcen mit dem Resource Manager
325
zugeführt. Auf diese Weise erhält die zweite Schicht in unserem Beispiel mindestens 20 %. Im folgenden Beispiel werden dementsprechend die Ressourcen für die Gruppe team_a zugeteilt. Gemäß der in Abschnitt Vorgaben vorgegebenen Planung darf diese Gruppe von den mindestens verbleibenden 20 % CPU-Zeit der ersten „Schicht“ maximal 60 % nutzen. Nicht genutzte CPU-Zeit geht auch hier an die nächstfolgende und nicht etwa an andere Gruppen derselben Schicht. Zusätzlich wird festgelegt, dass jede Sitzung dieser Gruppe maximal 300 Sekunden CPU-Zeit verbrauchen darf, bevor sie auf die Gruppe batch heruntergestuft wird. Die Herunterstufung kann auch schon dann erfolgen, wenn die Statistiken eine entsprechend lange Laufzeit erwarten (switch_estimate => true). BEGIN dbms_resource_manager.create_plan_directive ( plan => 'Tagesplan' group_or_subplan => 'Team_A', comment => 'Ressourcen für Entwicklungsteam A während des Tages', cpu_p1 => 0, cpu_p2 => 60, active_sess_pool_p1 => 10, switch_time => 300, switch_group => 'Batch', switch_estimate => TRUE, parallel_degree_limit_p1 => 4, undo_pool => 500000); END; / Listing 4.38: Vergabe eines Ressourcenplans
Dementsprechend werden alle geplanten Direktiven angelegt. Es ist darauf zu achten, dass jeder Plan auch Direktiven für die vordefinierte Gruppe other_groups enthält, damit Benutzern, deren Gruppen nicht explizit in den betreffenden Plan miteingeschlossen wurden, restliche CPU-Zeiten zugeteilt werden können. In unserem Beispiel erhält diese Gruppe in der vierten Schicht alle verbleibenden CPU-Ressourcen. BEGIN dbms_resource_manager.create_plan_directive ( plan => 'Tagesplan', group_or_subplan => 'Team_B', comment => 'Ressourcen für Entwicklungsteam B während des Tages', cpu_p1 => 0, cpu_p2 => 40,
Sandini Bib
326
Sicherheit
active_sess_pool_p1 switch_time switch_group switch_estimate parallel_degree_limit_p1 undo_pool
=> => => => => =>
10, 300, 'Batch', TRUE, 4, 500000);
dbms_resource_manager.create_plan_directive ( plan => 'Tagesplan', group_or_subplan => 'Batch', comment => 'Ressourcen für Batch-Verarbeitung während des Tages', cpu_p1 => 0, cpu_p2 => 0, cpu_p3 => 100); dbms_resource_manager.create_plan_directive ( plan => 'Tagesplan', group_or_subplan => 'OTHER_GROUPS', comment => 'Diese Gruppe muss aufgeführt werden', cpu_p1 => 0, cpu_p2 => 0, cpu_p3 => 0, cpu_p4 => 100); -- Nachtzeit dbms_resource_manager.create_plan_directive ( plan => 'Nachtplan', group_or_subplan => 'OLTP', comment => 'Ressourcen für OLTP-Verarbeitung während der Nacht' cpu_p1 => 0, cpu_p2 => 0, cpu_p3 => 100); dbms_resource_manager.create_plan_directive ( plan => 'Nachtplan', group_or_subplan => 'Team_A', comment => 'Ressourcen für Entwicklungsteam A während der Nacht', cpu_p1 => 0, cpu_p2 => 60, active_sess_pool_p1 => 10); dbms_resource_manager.create_plan_directive ( plan => 'Nachtplan', group_or_subplan => 'Team_B', comment => 'Ressourcen für Entwicklungsteam B während der Nacht',
Sandini Bib
Management von Ressourcen mit dem Resource Manager
327
cpu_p1 => 0, cpu_p2 => 40, active_sess_pool_p1 => 10); dbms_resource_manager.create_plan_directive ( plan => 'Nachtplan', group_or_subplan => 'Batch', comment => 'Ressourcen für Batchprogramme während der Nacht', cpu_p1 => 90); dbms_resource_manager.create_plan_directive ( plan => 'Nachtplan', group_or_subplan => 'OTHER_GROUPS', comment => 'Diese Gruppe muss aufgeführt werden', cpu_p1 => 0, cpu_p2 => 0, cpu_p3 => 0, cpu_p4 => 100); END; / Listing 4.39: Vergabe der Ressource
Pläne und Direktiven stellt die View dba_rsrc_plan_directives dar. Zum Schluss darf nicht vergessen werden, die durchgeführten Aktionen aus dem Arbeitsbereich heraus zu übertragen: BEGIN dbms_resource_manager.submit_pending_area; END; /
Konsumentengruppen und Benutzer Nachdem nun die Pläne mit Leben gefüllt wurden, müssen die Konsumentengruppen auf die Benutzer verteilt und für jeden Benutzer eine Standardgruppe definiert werden, in deren Kontext er nach dem Connect operiert. Im Einzelnen ist hierzu jedem Benutzer das Privileg zum Umschalten auf eine oder mehrere Gruppen zu erteilen, dann kann eine dieser Gruppen zur Standardgruppe gemacht werden. Die Grant-Option – falls gesetzt – ermöglich es dem Betreffenden, dieses Recht weiterzugeben: BEGIN dbms_resource_manager_privs.grant_switch_consumer_group ( grantee_name => 'SCOTT', consumer_group => 'OLTP', grant_option => FALSE); dbms_resource_manager.set_initial_consumer_group(
Sandini Bib
328
Sicherheit
user => 'SCOTT', consumer_group => 'OLTP'); END; /
BEGIN dbms_resource_manager_privs.grant_switch_consumer_group ( grantee_name => 'DEV_A', consumer_group => 'Team_A', grant_option => FALSE); dbms_resource_manager_privs.grant_switch_consumer_group ( grantee_name => 'DEV_A', consumer_group => 'BATCH', grant_option => FALSE); dbms_resource_manager.set_initial_consumer_group( user => 'DEV_A' consumer_group => 'Team_A'); END; / Listing 4.40: Zuweisung der Konsumentengruppe
Im vorangehenden Beispiel wird der Benutzer dev_a den Konsumentengruppen team_a und batch zugeteilt. Seine Standardgruppe wird team_a, auf batch wird er umgesetzt falls – wie oben beschrieben – seine CPU-Zeiten zu hoch liegen. Die Prozeduraufrufe dieses Abschnittes lassen sich im Übrigen direkt, ohne Initialisierung eines Arbeitsbereiches durchführen. Die View dba_rsrc_consumer_ group_privs gibt Auskunft über die erteilten Privilegien. Pläne aktivieren Nun sind alle Pläne und Gruppen wie geplant angelegt worden. Die Überprüfung der angegebenen Grenzwerte erfolgt jedoch erst dann, wenn ein Plan aktiviert wird. Diese Aktivierung kann entweder über den Systemparameter resource_manager_plan oder dynamisch über den Befehl ALTER SYSTEM erfolgen. Im folgenden Beispiel wird der Plan Tagesplan aktiviert: ALTER SYSTEM SET resource_manager_plan = 'TAGESPLAN';
Die in unserem Beispiel geforderte Umschaltung um 19 Uhr lässt sich leicht mit Hilfe eines Datenbankjobs und der Prozedur dbms_resource_manager. switch_plan erreichen. v$rsrc_plan gibt den jeweils aktiven Plan und seine Unterpläne aus.
Sandini Bib
Auditing
4.9.3
329
Monitoring
Im laufenden Betrieb lassen sich Statistiken über die tatsächliche Verteilung der CPU-Zeiten über die View v$rsrc_consumer_group abrufen: SELECT name, active_sessions, consumed_cpu_time FROM v$rsrc_consumer_group; NAME ACTIVE_SESSIONS CONSUMED_CPU_TIME -------------------------------- --------------- ----------------TEAM_A 1 11091 TEAM_B 0 0 BATCH 1 106606 OTHER_GROUPS 0 1002 OLTP 2 283984 Listing 4.41: v$rsrc_consumer_group
Der hohe CPU-Anteil der Gruppe batch in diesem Beispiel wurde dadurch verursacht, dass die Sitzung der Gruppe team_a erst später startete.
4.10 Auditing Die beste Sicherheitstechnik ist nutzlos, wenn nicht überprüft werden kann, ob sie auch funktioniert. Somit muss es (auch nach den Bestimmungen des NCSC C2Standards) eine Möglichkeit geben, die Nutzung von Privilegien zu protokollieren und auszuwerten. Mit dem Auditing können die drei Bereiche Objekte, Kommandos und Privilegien überwacht werden, und somit ist es möglich, von fehlerhaften Anmeldungen bis zu Abfragen auf bestimmte Tabellen oder sogar nur bestimmte Spalten alle Informationen zu protokollieren. Diese Protokollierung kann natürlich bei übermäßigem Gebrauch zu einer Performance-Verschlechterung führen. Außerdem muss darauf geachtet werden, dass die gesammelte Information von Zeit zu Zeit gelöscht wird, da das Auditing ein zwingender Vorgang ist. Kann zum Beispiel das „Session Login“ nicht mehr überwacht werden, weil die Audit-Tabelle in der Datenbank voll ist (maximale Anzahl Extents erreicht oder Ähnliches), dann ist es für einen Standardbenutzer nicht mehr möglich, sich anzumelden. Gleiches gilt auch für die Überwachung von DML-Befehlen, d.h. unter Umständen steht eine Anwendung, weil kein Protokoll mehr geschrieben werden kann. Generell sollte Auditing nur verwendet werden, wenn ein Grund zur Annahme besteht, dass Missbrauch betrieben wird, oder es nur sehr wenige Operationen, z.B. den Zugriff auf bestimmte Tabelleninformtionen, betrifft. Es ist über das BefehlsAuditing möglich, die zu protokollierenden Aktionen auf ganz bestimmte Zeilen oder Spalten einer Tabelle zu beschränken.
Sandini Bib
330
Sicherheit
4.10.1 Aktivieren von Auditing Sie sollten sich frühzeitig überlegen, ob ein Auditing für eine bestimmte Datenbank sinnvoll ist, da nur über den Initialisierungsparameter audit_trail das generelle Auditing aktiviert wird. Im laufenden Betrieb ist es nur möglich, das Auditing für bestimmte Aktionen zu aktivieren bzw. deaktivieren. Auch ein Umschalten zwischen der Speicherung von Protokollen auf Betriebssystemebene (audit_trail=os) oder in der Datenbank (audit_trail=db) ist nur bei heruntergefahrener Datenbank möglich. Das eigentliche Überwachen erfolgt dann mit dem Befehl: AUDIT
Als Optionen gelten:
: :
BY SESSION / BY ACCESS WHENEVER SUCCESSFUL / WHENEVER NOT SUCCESSFUL
Ausgeschaltet werden kann das Auditing, wenn es nicht über die Änderung des Initialisierungsparameters audit_trail erfolgt, über den Befehl: NOAUDIT
Beim Auditing auf Betriebssystemebene (audit_trail=os) gibt es Unterschiede zwischen MS Windows und anderen (z. B: UNIX oder VMS). Bei Unix gibt es den Initialisierungsparameter audit_file_dest, der angibt, in welches Verzeichnis die Audit-Dateien geschrieben werden sollen (standardmäßig ist dies das Verzeichnis $ORACLE_HOME/rdbms/audit). Das Verzeichnis sollte also überwacht werden, da es stark anwachsen kann. Bei MS-Windows gibt es diesen Parameter nicht, sondern alle Audit-Informationen werden an die Ereignisanzeige übergeben und sind über das Anwendungsprotokoll einsehbar. Das Auditing in der Datenbank legt alle Informationen im Schema SYS in der Tabelle aud$ ab. Diese Tabelle wird bei der Erstellung der Datenbank angelegt und gehört zum internen Data Dictionary. Diese Tabelle ist die einzige des Data Dictionarys, die mit DML-Befehlen geändert werden darf, da nur hierüber die alten Einträge gelöscht werden können. Bei einem umfangreichen Gebrauch dieser Tabelle ist es zu empfehlen – was ebenfalls nur für diese Tabelle erlaubt ist –, die StorageKlauseln zu ändern31. Zwar ist als Standardeinstellung PCTINCREASE 50 und MAXEXTENTS 256 gesetzt, so dass nicht davon auszugehen ist, dass es zu einem Fehler aufgrund fehlender Extents kommt, der SYSTEM-Tablespace kann aber durch diese Einstellung stark anwachsen. Es empfiehlt sich also zum Beispiel folgende Änderung: ALTER TABLE aud$ STORAGE (NEXT 1M PCTINCREASE 0 MAXEXTENTS 100)
31. Der Tablespace darf nicht geändert werden, da dies bei Upgrades zu Problemen führen könnte.
Sandini Bib
Auditing
331
Unabhängig davon, ob das Auditing ein- oder ausgeschaltet ist, gibt es jeweils Protokolle für das Hoch- und Herunterfahren der Datenbank sowie das Login als SYSDBA oder SYSOPER. Diese Information wird immer auf Betriebssystemebene abgelegt, da beim Hochfahren der Datenbank ja noch keine Tabellen zur Verfügung stehen. Unter MS-Windows wird dabei jeder Prozess in der Ereignisanzeige eingetragen, was dazu führt, dass bei häufigem Hoch- und Herunterfahren der Datenbank dieses Protokoll stark anwächst.
4.10.2 Kommando-Auditing Das Kommando-Auditing befasst sich mit der Überwachung einzelner Kommandos oder Kommandogruppen, die zu einem bestimmten Bereich der Datenbank gehören. Hiermit kann z.B. überprüft werden, ob eine Einschränkung von Benutzern auf eine PL/SQL-Schnittstelle eingehalten wird. Die Protokollierung von Kommandooperationen im Administrationsbereich (ALTER SYSTEM) kann für die Rekonstruktion von Problemsituationen interessant sein. Der einfachste Fall für ein Kommando-Auditing ist der Befehl: AUDIT SESSION;
Damit wird jeder Login und jeder Logout an der Datenbank mitprotokolliert. Da dies für eine große Datenbank bzw. eine umfangreiche Anzahl von Benutzern unübersichtlich wird, wird in vielen Fällen ein Schemaname mitgegeben. AUDIT SESSION BY gerd, anna;
Dieser Befehl schränkt die Protokollierung auf die Benutzer gerd und anna ein. Das folgende Beispiel zeigt die Ausgabe der View dba_audit_trail. SQL> SELECT os_username, username, terminal, timestamp, action_name, returncode FROM dba_audit_trail; OS_USERNAM ---------jahrends jahrends jahrends
USERNAME ---------GERD ANNA GERD
TERMINAL ---------HLLAP33 HLLAP33 HLLAP33
TIMESTAM -------10.09.01 10.09.01 10.09.01
ACTION_NAME RETURNCODE ------------ ---------LOGON 1017 LOGOFF 0 LOGON 0
Listing 4.42: Kommando-Auditing
Der RETURNCODE 1017 gibt die Oracle-Fehlermeldung an, sie kann über oerr ora 1017 oder in der Dokumentation nachgelesen werden. In diesem Fall handelt es sich um den Fehler „invalid username/password; logon denied“. Neben den hier dargestellten Spalten ist noch die Spalte comment_text interessant, da hier die Netzwerkkonfiguration abgespeichert wird. Insgesamt gibt es 144 mögliche Kommando-Auditing-Befehle, angefangen beim UNKNOWN bis zum ALTER OPERATOR, so dass hiermit alle möglichen DDL-Befehle
Sandini Bib
332
Sicherheit
überwacht werden können. Eine komplette Liste kann in der View audit_actions nachgesehen werden. Die
Abfrage
der
eingestellten
Audit-Funktionen
erfolgt
über
die
View
dba_stmt_audit_opts.
4.10.3 Privilegien-Auditing Mit dem Kommando-Auditing steht die Objektart im Vordergrund, z.B. werden mit dem Befehl AUDIT TABLE alle DDL-Befehle bezüglich der Erstellung, Änderung oder Löschung einer Tabelle überwacht. Beim Privilegien-Auditing kann hingegen eine einzelne Operation, für die z. B: das Privileg CREATE ANY TABLE notwendig ist, gezielt überwacht werden. In einem uns bekannten Beispiel existierte das Problem, dass bestimmte Views immer wieder gelöscht wurden. Durch ein gezieltes Auditing (AUDIT DROP VIEW) konnte das Problem gefunden und beseitigt werden. Da eine Überschneidung zwischen dem Kommando-Auditing und dem PrivilegienAuditing besteht, existieren zwar zwei Views, dba_priv_audit_opts und dba_stmt_audit_opts, der Inhalt ist jedoch identisch. Mit der Tabelle system_privilege_map können die möglichen Audit-Optionen abgefragt werden.
4.10.4 Objekt-Auditing Während Kommando- und Privilegien-Auditing die generelle Nutzung von Befehlen und Rechten ohne Objektbezug überwachen, ist mit dem Objekt-Auditing die gezielte Überwachung bestimmter Objekte möglich. Damit können Zugriffe auf bestimmte Objekte oder DML-Operationen überwacht werden. Über die weitere Einschränkung BY <user> und BY ACCESS ist es möglich, die anfallende Menge an Informationen einzuschränken. Mit dem Befehl AUDIT INSERT, UPDATE, DELETE ON demo.kunden ist es möglich, die Verwendung von DML-Operationen zu überwachen, z.B. weil sichergestellt werden soll, dass nur über eine PL/SQL-Funktion auf diese Tabelle zugegriffen wird. SQL> SELECT terminal, username, timestamp#, owner, action_name, returncode FROM dba_audit_trail; TERMINAL -------HLLAP33 HLLAP33
USERNAME -------ANNA GERD
TIMESTAM -------11.09.01 11.09.01
Listing 4.43: Objekt-Auditing
OWNER -----DEMO DEMO
ACTION_NAME RETURNCODE ----------- ---------INSERT 2004 UPDATE 0
Sandini Bib
Auditing
333
Die Fehlermeldung ORA-02004 security violation in dem Fall des Inserts des Users anna ist ein spezieller Eintrag in die Audit-Trail-Tabelle, der Benutzer bekommt eine ORA-00942: Table or view does not exist zurückgeliefert. Die
eingestellten
Objektüberwachungen
können
mit
der
View
dba_obj_audit_opts überprüft werden.
4.10.5 Fine-Grain-Auditing Das generelle Auditing von Objekten kann unter Umständen zu aufwändig bzw. zu unübersichtlich sein. Als Beispiel sei eine Kundentabelle genannt, die natürlich alle relevanten Informationen des Kunden enthält, vielleicht aber auch seine Liquidität. Diese darf – und so ist es in der Anwendung auch implementiert – nur von bestimmten Personen eingesehen und geändert werden. Genutzt wird die Tabelle natürlich von sehr vielen Anwendungen. Hier ist es also nur interessant zu protokollieren, welche Zugriffe auf die Spalte liquiditaet erfolgten. Für diesen Zugriff gibt es ein Datenbankpaket dbms_fga, mit dem es möglich ist, eine Spalte oder eine Bedingung mitanzugeben. BEGIN dbms_fga.add_policy( object_schema => object_name => policy_name => audit_condition => audit_column => END; /
'DEMO', 'KUNDEN2', 'CHECK_LIQ', 'LIQUIDITAET > 400000', 'LIQUIDITAET');
SQL> SELECT timestamp#, dbuid, osuid, obj$schema, obj$name, policyname, sqltext FROM sys.fga_log$; TIMESTAM DBUID OBJ$SCHEMA OBJ$NAME POLICYNAME SQLTEXT -------- ------ ---------- -------- ---------- -------------11.09.01 DEMO DEMO KUNDEN2 CHECK_LIQ select * from kunden2 11.09.01 DEMO
DEMO
KUNDEN2 CHECK_LIQ select nachname, vorname from kunden2 where liquiditaet = 100000
Listing 4.44: Fine-Grain-Auditing
Die Information kann dann über die Tabelle sys.fga_log$ abgefragt werden. Diese mit der Version 9i eingeführte Variante des Auditing ermöglicht ein viel gezielteres Überwachen von Statements inklusive Abfragen. Warum die Information nicht über die Standard Auditing-Views abgefragt werden können, ist allerdings ein Rätsel.
Sandini Bib
334
Sicherheit
Mit weiteren Prozeduren des Packages dbms_fga kann das Auditing an- oder ausgeschaltet bzw. gelöscht werden.
4.10.6 Audit-Trigger Neben den beschriebenen Verfahren des Auditing darf die Verwendung von Triggern zur Überwachung nicht vergessen werden. Durch den Einbau eines Triggers auf eine Tabelle kann zum Beispiel jede DML-Operation in einer anderen Tabelle mit Datum, Uhrzeit, Benutzer und anderen Informationen festgehalten werden. Im Folgenden werden alle alten Werte der Tabelle kunden mit dem Benutzer und dem Systemdatum festgehalten. CREATE TABLE audit_kunden ( kdnr NUMBER (10) NOT NULL, anrede_alt VARCHAR2 (5), vorname_alt VARCHAR2 (50), nachname_alt VARCHAR2 (50), adresse_alt VARCHAR2 (50), ort_alt VARCHAR2 (50), plz_alt NUMBER (6), telefon_alt VARCHAR2 (20), benutzer VARCHAR2(10), systemdatum DATE); CREATE OR REPLACE TRIGGER audit_kunden AFTER INSERT OR DELETE OR UPDATE ON kunden FOR EACH ROW BEGIN INSERT INTO audit_kunden VALUES ( :new.kdnr, :old.anrede, :old.vorname, :old.nachname, :old.adresse, :old.ort, :old.plz, :old.telefon, user, sysdate ); END; Listing 4.45: Trigger-Auditing
Dies ist sicher ein einfaches Beispiel, erlaubt es aber, alle relevanten Informationen in einer eigenen separaten Tabelle abzulegen. Es ist jedoch nicht möglich, in dieser Form auf SELECT-Anweisungen zu reagieren.
4.10.7 Empfehlungen Die beim Auditing zur Verfügung stehenden Optionen erlauben die Beobachtung der Datenbankaktivität in verschiedenen Stufen. Die Granularität der Beobachtungen sollte sich dabei an den Anforderungen ausrichten: Generell sollten sie mit sehr allgemeinen Optionen beginnen, so dass der Einfluss auf die Performance
Sandini Bib
Auditing
335
gering bleibt und wenig Platz verwendet wird. Erst wenn konkrete Verdachtsmomente für einen unbefugten Zugang zum System vorliegen, sollten aufwändigere Optionen eingeschaltet werden. Im Datenbankkonzept sollte zunächst eine Strategie zum Auditing festgelegt werden, die dann konkret in eine Auditing-Konfiguration umgesetzt wird. Die Strategie sollte auch Maßnahmen festlegen, wie bei der Entdeckung von nicht zulässigen Zugriffen verfahren werden soll. In vielen Unternehmen wird es außerdem notwendig sein, Auditing-Konzepte mit Unternehmensgremien wie z.B. dem Betriebsrat abzustimmen. Besonders dann, wenn nicht nur versuchte Eingriffe ins System oder nicht gestattete Operationen, sondern auch die tägliche Arbeit eines Anwenders nachvollzogen werden können, kann es zu Konflikten mit den Betriebsvereinbarungen kommen.
Sandini Bib
Sandini Bib
5
Oracle Net
5.1
Oracle Net-Architektur
Die Oracle-Datenbanksoftware ist schon seit geraumer Zeit für Client-ServerKommunikation konzipiert. Die Anfänge der verteilten Verarbeitung mit SQL*Net Version 1.x haben jedoch praktisch nichts mehr gemeinsam mit der aktuellen Oracle Net-Produktlinie. Im Zeitalter der Netzwerke wird für Serverkomponenten wie Datenbanken eine flexible Architektur benötigt. Hiermit müssen komplexe Netzwerkstrukturen effizient umzusetzen und in der Datenbankwelt zu implementieren sein. Weiterhin besteht die Anforderung, Industriestandards umfangreich zu unterstützen. Dies hat vor einigen Jahren mit der Unterstützung des Protokolls TCP/IP begonnen – heute immerhin das Standardprotokoll schlechthin – und bedeutet heute z.B. die Einbindung von LDAP an verschiedenen Stellen. Neben der traditionellen Rolle relationaler Datenbanken im Client-Server-Umfeld spielen diese auch eine zentrale Rolle in Internet- und Intranet-Architekturen. Hier wird auch eine ganz neue Dimension von Anforderungen eröffnet: Benutzerzahlen sind nach oben nicht mehr beschränkt, die Antwortzeiten sollen aber weit unter einer Sekunde liegen – immer nach dem Motto „Webbenutzer sind geduldig: Sie klicken erst nach 2 Sekunden Wartezeit weiter“. Zusätzlich entsteht eine ganz neue Art von Herausforderung an die Verbindung zur Datenbank: Im Gegensatz zum reinen Client-Server-Umfeld, wo eine Verbindung zur Datenbank im Zweifelsfalle morgens aufgebaut und zum Feierabend wieder abgebaut wird, sind Verbindungen vom Client zum Webserver von äußerst kurzer Dauer – dies gilt dann eben auch für die Datenbankverbindung. Während also das Client-Server-Geschäft eher mit einigen Dutzend bis Hundert Verbindungen über den Tag zu tun hat, erfordert das Webgeschäft Hunderte bis Tausende Verbindungen innerhalb kürzester Zeit. Eine Vorbemerkung zum Thema Protokolle: Historisch betrachtet sind von Oracle immer alle wichtigen Netzwerkprotokolle unterstützt worden. Es werden zwar weiterhin spezielle Protokolle auf entsprechenden Spezialplattformen unterstützt; grundsätzlich ist aber lediglich ein wichtiges Protokoll übrig geblieben: TCP/IP. Hierauf beziehen sich deshalb auch praktisch alle Beispiele in diesem Buch.
5.1.1
Begriffe
Nach einer erneuten Umstellung der Namensgebung widmen wir den Begriffen in diesem Umfeld einen eigenen Abschnitt. Der Sammelbegriff für die Software ist nunmehr Oracle Net (nach Net8 im Oracle8/Oracle8i-Zeitalter und SQL*Net davor); die Dienste wie Listener, Connection Manager usw. werden mit Oracle Net Services
Sandini Bib
338
Oracle Net
bezeichnet. Zur Konfiguration dienen in einfachen Fällen der Oracle Net Configuration Assistant (früher Net8 Configuration Assistant) sowie der Oracle Net Manager (früher Net8 Assistant). Die Konfiguration besteht im Wesentlichen aus der Abbildung von Dienstnamen (Net Service Names) auf Oracle Net-Adressen. Oracle Net steht weiterhin in einem engen Zusammenhang mit der DatenbankProzessarchitektur. Grundsätzlich werden zwei Modelle unterschieden: Bei der Dedicated Server-Architektur steht für jede Datenbankverbindung ein eigener Prozess (unter MS-Windows: Thread) zur Verfügung. Falls die Zahl der gleichzeitigen Verbindungen oder die Häufigkeit des Verbindungsaufbaus sehr hoch sind, steht das Shared Server-Modell zur Verfügung. Hierbei teilen sich alle Verbindungen eine dynamisch konfigurierbare Anzahl von Serverprozessen. Der hierfür bis einschließlich Oracle8i verwendete Begriff Multi-Threaded Server wird für Oracle9i nicht mehr benutzt. Protokolle Die Unterstützung für verschiedene Netzwerkprotokolle – früher eines der Alleinstellungsmerkmale von SQL*Net – hat sich bei Oracle Net im Wesentlichen auf die Unterstützung von TCP/IP über alle Plattformen hinweg reduziert. Hier schließt sich Oracle sinnvollerweise dem Marktstandard an. In Spezialfällen werden plattformspezifische Protokolle weiterhin unterstützt, so etwa Named Pipes unter MSWindows und LU6.2 auf IBM-Plattformen. Bis einschließlich Oracle8i wird auf PCPlattformen SPX/IPX aus dem Hause Novell unterstützt; mit Oracle9i nicht mehr. Im TCP/IP-Umfeld werden noch die Varianten TCP/IP mit SSL (Secure Socket Layer) und VI (Virtual Interface) unterstützt. SSL spielt immer dann eine Rolle, wenn es um Sicherheit und sichere Netzwerkverbindungen geht – z.B. als Basis für den Austausch von Schlüsselinformationen bei verschlüsselter Übertragung von Oracle Net-Inhalten. Das VI-Protokoll bietet (neu mit Oracle9i) eine performante Speziallösung für die Anbindung von Webservern an Datenbankserver an. In diesem Buch werden ausschließlich Beispiele aus der TCP/IP-Umgebung verwendet, da in der Praxis nur äußerst selten andere Protokolle zum Einsatz kommen.
5.1.2
Funktionsweise von Client-Server-Verbindungen
Client-Server-Verbindungen werden mit der Absicht eingesetzt, einer beliebigen Anwendung Datenbankdienste zur Verfügung zu stellen. Dabei ist es wichtig, dies transparent zu tun, d.h., die Anwendung selbst hat keinerlei Information darüber, ob sich eine Instanz lokal auf dem gleichen Rechner oder auf einem speziellen Rechner im Netzwerk befindet. Damit Anwendung und Anwender transparent auf Datenbanken zugreifen können, muss das Konzept erlauben, komplexe Netzwerkeigenschaften und -konfigurationen in einer für den Anwender zugänglichen Umgebung zu verwalten. Daher beschäftigt sich dieser Abschnitt zunächst mit der rein technischen Funktionsweise von Oracle Net-Client-Server-Verbindungen; später wird dann auf die Konfiguration und spezielle Oracle Net-Features eingegangen.
Sandini Bib
Oracle Net-Architektur
339
Die Oracle Net Services stellen einerseits an sich kein Protokoll dar – sie basieren vielmehr auf einem bereits installierten und funktionierenden Protokoll (das, wie bereits erwähnt, meist TCP/IP heißt). Andererseits stellen sie einen Kommunikationsmechanismus dar, der nach dem ISO/OSI-7-Schichten-Modell aufgebaut ist. Hierbei „verschwindet“ TCP/IP in einer der unteren Schichten. Eine wichtige Komponente der Oracle Net Services ist der Listener: Hierbei handelt es sich um einen eigenständigen Prozess auf dem Datenbankserver, der für den Aufbau der Verbindungen zwischen Client und Server zuständig ist. Dem Listener wird eine (oder auch mehrere) Adresse zugewiesen, an der er auf Anforderungen zum Verbindungsaufbau wartet. Diese Adresse ist im TCP/IP-Umfeld ein spezifischer Port auf einem Netzwerk-Interface, genauer gesagt eine IP-Adresse und ein freier Port. Als Standardport für den Oracle Net Listener hat sich 1521 durchgesetzt. Es ist auf jeden Fall wichtig, festzuhalten, dass der Listener unabhängig von der Instanz bzw. den Instanzen auf dem Server ist. Auf einem System mit mehreren Instanzen wird in der Regel nur ein Listener benötigt, selbst wenn die Instanzen mit unterschiedlichen Oracle Releases betrieben werden. In der Praxis hat sich gezeigt, dass man mit dem Listener des jeweils neuesten Releases für einen solchen Knoten meist eine gute Wahl trifft: Hiermit kann man sowohl die neuen als auch die alten Releases bedienen und ist zusätzlich in der Lage, eventuell vorhandene neue Features zu nutzen. Ebenfalls erwähnenswert ist die Tatsache, dass der Listener ausschließlich für den Verbindungsaufbau zuständig ist und nicht etwa für die Client-Server-Kommunikation. Die Listener-Adresse wird also vom Client nur bei einem einzigen – nämlich dem ersten – Kommunikationszyklus genutzt. Mit anderen Worten: Wenn alle Clients angemeldet sind (und keine zusätzliche Client-Server-Kommunikation mehr benötigt wird), kann der Listener heruntergefahren werden, ohne die bestehenden Verbindungen zu beeinträchtigen.1 Im Standardfall, dem Dedicated Server-Betrieb, reagiert der Listener auf eine Anfrage zum Verbindungsaufbau durch das Starten eines entsprechenden Serverprozesses. Unter Unix geschieht das durch ein fork() des Executables oracle, das im bin-Unterverzeichnis des für die Instanz angegebenen ORACLE_HOME-Verzeichnisses liegt. Unter Windows wird im Prozess, der der Instanz zugeordnet ist, ein weiterer Thread gestartet. Dies setzt voraus, dass der entsprechende Prozess bereits (als Dienst unter MS-Windows) gestartet ist. Ist dies nicht der Fall, antwortet der Listener mit der Fehlermeldung: ORA-12500: TNS:listener failed to start a dedicated server process
Sobald das Starten des Serverprozesses gelungen ist, ermittelt dieser einen freien Port, den er als exklusiven Kommunikationskanal für den Client nutzen kann. Je nach Betriebssystem und Implementierung gibt es nun zwei Möglichkeiten:
1.
Dies ist zumindest für die meist genutzten Plattformen MS-Windows und Unix der Fall. Auf IBM Host-Systemen unterscheidet sich die Implementierung an dieser Stelle; hier darf der Listener nicht heruntergefahren werden.
Sandini Bib
340
Oracle Net
1. Der Serverprozess teilt dem Listener seine Kommunikationsdaten mit und dieser antwortet dem Client mit den Serverdaten; ab jetzt kommunizieren nur noch Client und Server. Diese Variante wird als redirect bezeichnet. 2. Der Serverprozess erbt alle Informationen vom Listener und antwortet dem Client sofort. Dies wird auch als bequeath bezeichnet. Von nun an unterhalten sich nur noch der Client- und der Serverprozess. Die Inhalte dieser Unterhaltung sind praktisch nicht zu beeinflussen; Auswirkungen auf das Verhalten des Clients gibt es so gut wie keine – außer der Geschwindigkeit. Auch wenn es eigentlich klar sein sollte: Selbst mit den schnellsten verfügbaren Netzwerken ist der Datentransfer von einem Prozess zum anderen um Faktoren langsamer als ein vergleichbarer Transfer mittels Interprozesskommunikation.
5.1.3
Allgemeines zur Konfiguration
In diesem Abschnitt wird eine Standardkonfiguration mit dem TCP-Adapter erstellt, die auf allen gängigen Plattformen lauffähig ist. Alle Oracle Net-Komponenten werden mit Dateien konfiguriert. Die Einträge können sowohl mit Hilfe eines einfachen Texteditors als auch mit Hilfe von Werkzeugen erstellt werden. In diesem Abschnitt werden zunächst die Parameter in Rohform erläutert; weiter unten werden die Konfigurationswerkzeuge und ihre Möglichkeiten diskutiert. Abschied vom Konfigurations-Repository Mit SQL*Net Version 2 und dem Werkzeug Network Manager hatte Oracle den Anspruch, die Netzwerkkonfiguration auf einem zentralen Repository aufzusetzen. Die Idee war exzellent, die Umsetzung problematisch: Gerade bei Konfigurationen für große, heterogene Umgebungen, für die das Ganze ja gedacht war, hatte man mit Programmfehlern, Abstürzen und in einzelnen Fällen mit dem Verlust ganzer Repositories zu tun. So konsequent Oracle seinerzeit auf der Umsetzung der Netzwerkkonfiguration über das hauseigene Werkzeug bestand – es war beispielsweise unter Androhung von Support-Verlust nicht gestattet, Konfigurationsdateien mit einem Editor zu bearbeiten – so umfassend verzichtet man heute auf ein Repository. Das hat sicherlich einerseits mit dem Kundenverhalten zu tun (letztendlich wurde der Network Manager nicht benutzt), andererseits fehlt ein Repository gerade bei großen Umgebungen. So ist z.B. mit keinem der von Oracle ausgelieferten Werkzeuge ein einfacher Syntaxcheck der Konfigurationsdateien möglich; ebenfalls gibt es keinen Abgleich zwischen Konfigurationsdateien. Die Schlussfolgerung für einen Betrieb der Oracle Net-Produkte in produktiven Umgebungen ist demnach, dass ein Repository in Eigenregie abgebildet werden muss! Da es sich bei den zu sichernden Dateien um einfache Textdateien handelt, kann die Ablage der Oracle Net-Konfiguration beispielsweise in einem SourcecodeVerwaltungsmodul erfolgen.
Sandini Bib
Oracle Net-Architektur
341
Gerade in Anbetracht des hohen Aufwands für die Verwaltung der Oracle Net-Konfiguration ist es ratsam, diesen so weit wie möglich zu reduzieren und die Auflösung von Dienstnamen nicht lokal beim Client, sondern über einen der angebotenen zentralen Mechanismen wie Oracle Names und LDAP durchzuführen. Regeln für Konfigurationsdateien Zunächst ist der Speicherort für Oracle Net-Konfigurationsdateien wichtig. Standardmäßig ist dies das network/admin-Unterverzeichnis von $ORACLE_HOME. Falls ein anderes Verzeichnis gewünscht ist, kann der Pfad mit der Umgebungsvariablen $TNS_ADMIN eingestellt werden.2 Hierfür bietet sich ein Verzeichnis wie $ORACLE_BASE/network/admin an, da dieses Verzeichnis unabhängig von einzelnen installierten Versionen der Oracle-Software existieren kann. Verschiedene Softwareversionen können somit die gleiche Oracle Net-Konfiguration nutzen. Dies ist insbesondere dann sinnvoll, wenn – wie oben beschrieben – mehrere Versionen von einem Listener bedient werden. Die Datei sqlnet.ora kann auch im aktuellen Arbeitsverzeichnis gespeichert werden, so dass unterschiedliche Konfigurationen für verschiedene Anwendungen einfach möglich sind. Neben dem Administrationsverzeichnis kann z.B. $ORACLE_BASE/network/log für Log-Dateien eingerichtet werden (Achtung! Dies muss für die verschiedenen Funktionen wie Client, Server, Listener usw. an unterschiedlichen Stellen parametriert werden). Die Struktur der Konfigurationsdateien folgt dem Konzept, dass alle Parameter in der Form Parameter = (Schlüssel = Wert)
Angegeben werden. Bei mehreren Attributen können auch verschachtelte Strukturen wie (Schlüssel = (Schlüssel = Wert) (Schlüssel = Wert))
verwendet werden. Fortsetzungszeilen müssen mindestens mit einem Leerzeichen eingerückt werden, d.h., die Form (Schlüssel = (Schlüssel = Wert) (Schlüssel = Wert))
wird nicht korrekt interpretiert. Empfohlen ist eine Einrückung, so dass die Zuordnung von über- und untergeordneten Schlüsseln erkennbar wird. Neue Parameter müssen in einer eigenen Zeile ohne Einrückung beginnen.
2.
Unter MS-Windows muss TNS_ADMIN für jede Installation im Registrierungsschlüssel \\HKEY_LOCAL_MACINE\SOFTWARE\ORACLE\HOMEn gesetzt werden.
Sandini Bib
342
Oracle Net
Bei Schlüsselworten wird Groß-/Kleinschreibung nicht beachtet; bei den Werten ist dies abhängig von der aktuellen Umgebung (z.B. wird bei Pfadangaben auf einem Unix-System Groß-/Kleinschreibung sehr wohl unterschieden; auf einem MS-Windows-System nicht). Leerzeichen um das =-Zeichen herum sind optional. Innerhalb von Schlüsselworten dürfen keine Leerzeichen vorkommen; wohl aber innerhalb von Werten, insofern die Werte in einfache oder doppelte Anführungszeichen eingeschlossen sind. Kommentare beginnen mit # und enden mit dem Ende der Zeile. Es ist empfehlenswert, sich einige von Oracle-Werkzeugen generierte Beispiele anzuschauen, bevor man Oracle Net-Konfigurationsdateien komplett selbst erzeugt. Standardkonfiguration Die Konfiguration des Listeners erfolgt auf dem Datenbankserver in der Datei listener.ora im o.a. Konfigurationsverzeichnis. Die Basiskonfiguration sieht für einen Listener wie folgt aus: LOG_DIRECTORY_LISTENER = C:\OraBase\Network\Log LOG_FILE_LISTENER = listener LISTENER = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521)) ) SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = O817DL1.test.hl.de) (ORACLE_HOME = C:\OraBase\Product\O817) (SID_NAME = tO817DL1) ) (SID_DESC = (GLOBAL_DBNAME = DLTST.test.hl.de) (ORACLE_HOME = C:\OraBase\Product\O901) (SID_NAME = DLTST) ) ) Listing 5.1: listener.ora
Es werden vier Variablen definiert: LOG_DIRECTORY_LISTENER (Verzeichnis für LogDateien), LOG_FILE_LISTENER (der Name der Log-Datei, wird mit .log ergänzt), LISTENER (Adressparameter) sowie SID_LIST_LISTENER (Instanzparameter). Diese definieren das Verhalten eines Listeners, der den Namen LISTENER trägt.
Sandini Bib
Oracle Net-Architektur
343
Der Adressparameter enthält eine Liste von Adressen, auf denen der Listener Verbindungsanfragen entgegennimmt. Je nach Protokoll werden zusätzliche Parameter eingestellt, z.B. für TCP/IP ein Hostname und ein Port. Anstelle des Hostnamens wird auch eine numerische IP-Adresse akzeptiert. Der Port 1521 hat sich als Standard-Port für Oracle Net-Listener etabliert. Eine manchmal verwirrende Eigenschaft des Listeners ist, dass er auch ohne Konfigurationsdatei startet. Er hat dann folgendes Verhalten: Die Log-Datei ist listener.log im Verzeichnis $ORACLE_HOME/network/log, die Adresse für den Listener ist vom Typ TCP/IP und belegt Port 1521. Die Liste der Instanzen ist zunächst leer. Sobald Instanzen starten, melden diese sich beim Listener an und werden in einer flüchtigen SID-Liste verwaltet. Die Nichtkonfiguration des Listeners ist zwar recht eindrucksvoll bei der Ersteinrichtung von Systemen, ratsam ist sie jedoch in vielen Fällen nicht. Will man z.B. mit dem Enterprise Manager arbeiten, so bekommt man den vollen Funktionsumfang nur dann, wenn die zu verwaltende Instanz in der Listener-Konfigurationsdatei definiert ist. Die nächste Konfigurationsdatei heißt sqlnet.ora und enthält allgemeine Kommunikationsparameter: NAMES.DEFAULT_DOMAIN = hl.de NAMES.DIRECTORY_PATH= (TNSNAMES) SQLNET.EXPIRE_TIME = 10 SQLNET.AUTHENTICATION_SERVICES= (NTS) Listing 5.2: sqlnet.ora
Da allgemeine Parameter sowohl für Clients als auch für Server interessant sind, wird eine sqlnet.ora-Datei i.A. sowohl auf Client- als auch auf Serverseite angelegt. Mit dem Parameter NAMES.DEFAULT_DOMAIN wird eine Domäne angegeben, die als Standard für die Namensauflösung gilt, d.h., alle Dienstnamen, die ohne einen Punkt angegeben werden, werden um diese Domäne erweitert. Das Domänenkonzept von Oracle Net erlaubt die Aufteilung der Oracle Net Services in logische Einheiten. Dabei sind Oracle Net-Domänen nicht zwangsweise identisch mit eventuell vorhandenen Netzwerkdomänen (z.B. auf TCP/IP- oder MS-Windows-Ebene). Mit NAMES.DIRECTORY_PATH wird bestimmt, welche Dienste zur Namensauflösung benutzt werden sollen. Mit TNSNAMES bezieht man sich auf die Namensauflösung über eine entsprechende Datei tnsnames.ora, die in diesem Abschnitt weiter unten behandelt wird. Über den Parameter SQLNET.EXPIRE_TIME aktiviert man die sog. Dead Connection Detection. Hierbei wird nach der angegebenen Zahl von Sekunden vom Server aus versucht, ein Kontrollpaket zum Client zu schicken, falls keine sonstige Client-Server-Kommunikation stattgefunden hat. Antwortet der Client nicht, so wird eine eventuell laufende Transaktion zurückgerollt, eventuell vorhandene Sperren werden aufgehoben und die Verbindung wird serverseitig terminiert. Mit Hilfe der Dead Connection Detection können hängende Verbindungen auf Grund von Abstürzen oder frühzeitig ausgeschalteten PCs vermieden werden. Dieser Parameter wird ausschließlich auf dem Server gesetzt.
Sandini Bib
344
Oracle Net
Wichtig für die Net Services-Konfiguration auf der Serverseite ist der Parameter SQLNET.AUTHENTICATION_SERVICES. Hierdurch werden u.a. Dienste ausgewählt, die eine passwortlose Anmeldung von Administratoren erlauben. Unter Windows ist dies erlaubt, wenn SQLNET.AUTHENTICATION_SERVICES den Eintrag NTS (für NT Security) enthält und der aktive Benutzer Mitglied der Windows-Gruppe ORA_DBA ist. Für Unix gilt Ähnliches: Der Eintrag BEQ (für bequeath) erlaubt einem Benutzer, der Mitglied der Oracle-Administrationsgruppe (Standard: dba) ist, die passwortlose Anmeldung. Die beiden genannten Mechanismen gelten insbesondere für lokale Anmeldungen, d.h., die Oracle Net Services sind eigentlich nicht im Spiel! Die dritte und letzte Datei für die Standardkonfiguration ist für die lokale Namensauflösung (die in der Datei sqlnet.ora ausgewählt wurde) zuständig und heißt tnsnames.ora. Sie enthält Dienstnamen und die dazugehörige Adressinformation: DLTST.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = DLTST.test.hl.de) ) ) REP1.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = REP1.prod.hl.de) ) ) Listing 5.3: tnsnames.ora
Eine tnsnames.ora-Datei wird überall dort gespeichert, wo potenziell Client-Server-Verbindungen initiiert werden; i.A. heißt das sowohl auf dem Client als auch auf dem Server. In diesem Beispiel sind zwei Dienstnamen für Oracle-Instanzen auf dem gleichen Rechner angegeben. Für jeden Dienstnamen ist eine DESCRIPTION angegeben, die sich in zwei Teile gliedert. Der ADDRESS-Teil referenziert den Listener des Zielsystems (d.h., die Angaben müssen mit denen in der listener.ora des Zielsystems übereinstimmen); der CONNECT_DATA-Teil identifiziert die Instanz, zu der eine Verbindung aufgebaut werden soll. Normalerweise besteht der hier angegebene SERVICE_NAME aus den Initialisierungsparametern db_name.db_domain der Zieldatenbank. Es ist zu beachten, dass die hier angegebenen Dienstnamen mit der Domäne hl.de versehen sind; diese ist in der Datei sqlnet.ora als Default-Domäne angegeben.
Sandini Bib
Oracle Net-Architektur
345
Für den Verbindungsaufbau können somit sowohl der vollständige Dienstname DLTST.hl.de als auch die Kurzform DLTST angegeben werden. Administration des Listeners Zur Administration des Listener-Prozesses gibt es das Listener Control Utility lsnrctl, das sowohl mit einzelnen Kommandos auf der Kommandozeile als auch interaktiv genutzt werden kann. Kommandos sind z.B. START und STOP. Hier folgt ein Beispiel für einen Listener-Start unter MS-Windows: C:\>lsnrctl start LSNRCTL for 32-bit Windows: Version 9.0.1.2.1 - Production on 28-NOV-2001 22:49:57 Copyright (c) 1991, 2001, Oracle Corporation. All rights reserved. Starting tnslsnr: please wait... TNSLSNR for 32-bit Windows: Version 9.0.1.2.1 – Production System parameter file is C:\OraBase\Network\Admin\listener.ora Log messages written to C:\OraBase\Network\Log\listener.log Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP10)(PORT=1521))) Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hllap10)(PORT=1521))) STATUS of the LISTENER -----------------------Alias LISTENER Version TNSLSNR for 32-bit Windows: Version 9.0.1.2.1 – Production Start Date 28-NOV-2001 22:49:59 Uptime 0 days 0 hr. 0 min. 2 sec Trace Level off Security OFF SNMP OFF Listener Parameter File C:\OraBase\Network\Admin\listener.ora Listener Log File C:\OraBase\Network\Log\listener.log Listening Endpoints Summary... (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP10)(PORT=1521))) Services Summary... Service "DLTST.test.hl.de" has 1 instance(s). Instance "DLTST", status UNKNOWN, has 1 handler(s) for this service... Service "REP.hl.de" has 1 instance(s). Instance "REP", status UNKNOWN, has 1 handler(s) for this service... The command completed successfully Listing 5.4: Starten des Listeners
Sandini Bib
346
Oracle Net
Das Gleiche passiert, wenn man zunächst das Listener Control Utility ohne Parameter aufruft (dies wird als interaktiver Modus bezeichnet) und dann ein oder mehrere Kommandos eingibt: C:\>lsnrctl LSNRCTL for 32-bit Windows: Version 9.0.1.2.1 - Production on 29-NOV-2001 22:02:44 Copyright (c) 1991, 2001, Oracle Corporation. All rights reserved. Welcome to LSNRCTL, type "help" for information. LSNRCTL> start ... LSNRCTL> exit C:\ Listing 5.5: lsnrctl
Wichtig in obiger Ausgabe für das START-Kommando ist, dass der Listener den Ort der Konfigurations- und Log-Dateien bekannt gibt – damit ist man sicher, dass die richtige Konfiguration ausgewählt ist. (O.a. Pfad für die Konfigurationsdatei ist durch Setzen der Variablen TNS_ADMIN in der Registrierung eingestellt worden; in der Datei ist das Log-Verzeichnis entsprechend angegeben.) Es wird ebenfalls die Adresse (bzw. Adressen) ausgegeben, auf der der Listener horcht. Zu beachten ist, dass zwei Versionsnummern ausgegeben werden: die des Listener Control Utilitys (LSNRCTL) sowie die des Listeners selbst (TNSLSNR). Die Ausgabe ab der Zeile Connecting to entspricht der Ausgabe des Kommandos lsnrctl status. Hiermit kann man auch ohne Neustart des Listeners überprüfen, ob z.B. weitere Instanzen am Listener angemeldet sind: C:\>lsnrctl status LSNRCTL for 32-bit Windows: Version 9.0.1.2.1 - Production on 28-NOV-2001 23:00:53 Copyright (c) 1991, 2001, Oracle Corporation. All rights reserved. Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hllap10)(PORT=1521))) STATUS of the LISTENER -----------------------Alias LISTENER Version TNSLSNR for 32-bit Windows: Version 9.0.1.2.1 – Production Start Date 28-NOV-2001 22:49:59 Uptime 0 days 0 hr. 10 min. 55 sec Trace Level off Security OFF SNMP OFF Listener Parameter File C:\OraBase\Network\Admin\listener.ora Listener Log File C:\OraBase\Network\Log\listener.log
Sandini Bib
Oracle Net-Architektur
347
Listening Endpoints Summary... (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP10)(PORT=1521))) Services Summary... Service "DLTST.test.hl.de" has 1 instance(s). Instance "DLTST", status UNKNOWN, has 1 handler(s) for this service... Service "O901DL1.test.hl.de" has 1 instance(s). Instance "to901dl1", status READY, has 1 handler(s) for this service... Service "REP.hl.de" has 1 instance(s). Instance "REP", status UNKNOWN, has 1 handler(s) for this service... The command completed successfully Listing 5.6: Listener-status
Hier hat sich eine weitere Instanz to901dl1 dem Listener bekannt gemacht. Dies ist durch einfaches Starten der Instanz erfolgt. Aus der Log-Datei des Listeners lassen sich nach erfolgreichem Start ähnliche Informationen entnehmen: TNSLSNR for 32-bit Windows: Version 9.0.1.2.1 - Production on 01-DEC-2001 15:59:16 Copyright (c) 1991, 2001, Oracle Corporation. All rights reserved. System parameter file is C:\OraBase\Network\Admin\listener.ora Log messages written to C:\OraBase\Network\Log\listener.log Trace information written to C:\OraBase\Product\O901\network\trace\listener.trc Trace level is currently 0 Started with pid=712 Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP10)(PORT=1521))) Listing 5.7: listener.log
Eine weitere Zeile beschreibt das Format der Folgeeinträge: TIMESTAMP * CONNECT DATA [* PROTOCOL INFO] * EVENT [* SID] * RETURN CODE 30-NOV-2001 12:18:45 * (CONNECT_DATA=(SERVICE_NAME=rep.hl.de) (CID=(PROGRAM=C:\OraBase\jre\1.1.8\bin\jre.exe)(HOST=HLLAP10)(USER=SYSTEM))) * (ADDRESS=(PROTOCOL=tcp)(HOST=131.220.110.198)(PORT=1096)) * establish * rep.hl.de * 0
Obige Beispielzeile beschreibt einen erfolgreichen Verbindungsaufbau. Die folgenden Zeilen beschreiben die Kommunikation der Instanz REP mit dem Listener. 30-NOV-2001 30-NOV-2001 30-NOV-2001 30-NOV-2001
12:15:18 12:15:19 12:15:26 12:15:32
* * * *
service_register * REP * 0 service_died * REP * 12537 service_register * REP * 0 service_update * REP * 0
Sandini Bib
348
Oracle Net
Die Log-Datei des Listeners kann also sehr gut zur Analyse von Problemsituationen herangezogen werden. Allerdings wächst sie – insbesondere bei einer großen Anzahl von Verbindungen – schnell an, so dass sie von Zeit zu Zeit gelöscht oder archiviert werden muss. Problematisch ist dabei, dass der Listener die Log-Datei permanent offen hält (im Gegensatz zu den Alertlog- und Trace-Dateien der Datenbankserverprozesse, die für jeden Eintrag göffnet und wieder geschlossen werden.) Daher ist es im Rahmen einer Log-Dateibereinigung unter MS-Windows nicht möglich, die Listener-Log-Datei im laufenden Betrieb zu löschen oder umzubenennen. Unter Unix funktionieren zwar die entsprechenden Befehle, der Listener schreibt jedoch weiter in die gleiche Datei, d.h., es können Log-Informationen verloren gehen. Trotzdem ist es durchaus wünschenswert, die Log-Datei regelmäßig zu sichern und mit einer neuen Datei zu beginnen. Hier hilft ein einfacher Trick weiter, mit dem ein Neustart des Listeners umgangen werden kann: Falls die Log-Datei ursprünglich listener.log heißt, benennt man sie aus dem Listener Control Utility im interaktiven Modus mit dem Kommando set log_file l.log
temporär in l.log um; das Verzeichnis bleibt hierbei gleich. Dann kann man die Datei listener.log entsprechend behandeln (archivieren, löschen, ...) und schließlich mit set log_file listener.log
wieder auf eine leere Datei listener.log umschalten. Dies sollte regelmäßig – am besten automatisiert – geschehen, da die Listener-LogDatei je nach Anzahl der Verbindungen recht groß werden kann. Im Extremfall handelt man sich mit einer zu großen Listener-Log-Datei Performance-Einbußen ein. Die bereits erwähnten Kommandos START und STATUS sowie weitere Kommandos wie STOP (Listener beenden), SERVICES (ausführliche Liste der Net Services inklusive Verbindungsstatistik) oder RELOAD (Parameter neu einlesen; funktioniert, wenn mindestens ein Adressparameter der alten und neuen Konfiguration übereinstimmt) können nun eingegeben werden. Beim Eingeben der Kommandos ist zu beachten, dass der Name des Listeners hinter dem Kommando angegeben werden muss, wenn dieser nicht LISTENER ist. (Daher empfiehlt es sich, bei einfachen Installationen alle Listener LISTENER zu nennen.) Unter MS-Windows ist der Listener als Dienst implementiert. Dieser wird beim ersten Start des Listeners automatisch mit dem Namen OracleTNSListener angelegt. Danach ist das Starten und Stoppen des Listeners sowohl über das Listener Control Utility als auch über das Starten und Stoppen des jeweiligen Dienstes durchführbar. Da der Listener mit einigen Mbyte Hauptspeicher nur wenig Ressourcenbedarf hat, empfiehlt sich für dessen Dienst auf jeden Fall die Einstellung Automatisch Starten.
Sandini Bib
Oracle Net-Architektur
349
Verbindungsaufbau Mit der im vorangegangenen Abschnitt dargestellten Standardkonfiguration kann nunmehr eine Oracle Net-Verbindung aufgebaut werden – die Speicherung der Konfigurationsdateien im Verzeichnis $ORACLE_HOME/network/admin vorausgesetzt. Eine Verbindung vom Client zur Datenbank, die sich hinter dem Dienstnamen DLTST.hl.de verbirgt, mit dem Benutzer SYSTEM (und Standardpasswort) über das Werkzeug SQL*Plus sieht wie folgt aus: sqlplus system/[email protected]
Solche Aufrufe sind natürlich mit Vorsicht zu genießen, da das Passwort unverkennbar auf der Kommandozeile prangt ; auf einem Unix-System sogar im ProzessListing für alle Benutzer einsehbar. Daher kann auch die Alternative sqlplus [email protected]
gewählt werden, wobei man direkt im Anschluss zur verdeckten Passworteingabe aufgefordert wird. Damit der Dienstname nicht jedes Mal eingetippt werden muss, kann er in der Variablen TWO_TASK (unter Unix) bzw. LOCAL (unter MS-Windows; hier auch in der Registrierung) vorbelegt werden, so dass sqlplus system
zum gleichen Ergebnis wie oben führt.
5.1.4
Spezielle Konfigurationen
Client-Konfiguration SID und SERVICE_NAME Mit Oracle8i wurde zusätzlich zur bis dahin bekannten
Möglichkeit, die Zielinstanz für den Verbindungsaufbau direkt über ihre SID zu benennen, die Benennung eines Services (SERVICE_NAME) eingeführt. Zum Vergleich zunächst einmal ein Eintrag in der alten Form: DLTST.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521)) ) (CONNECT_DATA = (SID = DLTST) ) )
Hier die neue Form: DLTST.HL.DE = (DESCRIPTION = (ADDRESS_LIST =
Sandini Bib
350
Oracle Net
(ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = DLTST.test.hl.de) ) ) Listing 5.8: tnsnames.ora mit SID oder SERVICE_NAME
Die Identifikation der Zielinstanz erfolgt in diesem Modell indirekt: Jede vom Listener verwaltete Instanz meldet die verfügbaren Servicenamen an. Diese werden über den Initialisierungsparameter service_names gesetzt. Der Listener baut die Verbindung zu einer Instanz auf, die sich mit dem passenden Servicenamen registriert hat. Dieses Verfahren bietet mehr Flexibilität:
:
:
:
Falls mit dem Parallel Server eine automatische Lastverteilung konfiguriert werden soll, müssen bei der Adressierung mit der SID-Methode alle Instanzen gleich heißen, da die Lastverteilung über eine ADDRESS_LIST gehandhabt wird, die keine unterschiedlichen SID-Einträge für verschiedene Adressen erlaubt. Dies kann wiederum zu Verwirrung bei der Administration führen. Bei der SERVICE_NAME-Adressierung fällt das Problem weg; es muss lediglich sichergestellt werden, dass jede Instanz den passenden Service anbietet. Gerade im Parallel Server-Umfeld besteht die Möglichkeit, Benutzer noch gezielter auf die Instanzen zu verteilen. Falls es z.B. die Benutzergruppen A, B und C gibt, wobei Gruppe A auf beliebigen Instanzen arbeiten kann, die Gruppen B und C aber getrennt werden sollen, so können die Gruppen als SERVICE_NAME definiert werden – eventuell zusätzlich zu anderen bereits vorhandenen –, wobei eine Instanz A und B, die andere A und C erhält. Auch bei Standardinstallationen kann die Funktionalität der Servicenamen genutzt werden, indem man z.B. für jede Anwendung einen Servicenamen definiert. Über den Servicenamen kann der Listener nun zuordnen, welche Instanz für die Anwendung zuständig ist. Der DBA hat nun die Freiheit, Anwendungen auf verschiedene Instanzen zu verteilen – z.B. Testschemas auf Testdatenbanken, die in regelmäßigen Abständen neu angelegt und umverteilt werden.
Etwas problematisch ist lediglich das Verhalten des Listeners, wenn die Instanz den Servicenamen nicht angemeldet hat. Er beantwortet dann einen versuchten Verbindungsaufbau mit der Fehlermeldung ORA-12514: TNS:listener could not resolve SERVICE_NAME given in connect descriptor
Diese Meldung wird leicht missverstanden und als Konfigurationsproblem gewertet. Meist ist das Problem aber tatsächlich entweder eine nicht gestartete Instanz oder ein noch nicht abgeglichener Listener (z.B. nach einem Listener-Restart). Clients, die älter als Oracle8i sind, also Versionen 8.0 und älter, können nicht mit der SERVICE_NAME-Methode konfiguriert werden.
Sandini Bib
Oracle Net-Architektur
351
SDU anpassen Wenn Daten über Oracle Net verschickt werden, werden sie eventuell in kleinere Einheiten aufgeteilt. Diese Einheiten entsprechen maximal dem der Session Data Unit Size (SDU). Die SDU hat einen systemspezifischen Standardwert. Oracle Net entscheidet beim Verbindungsaufbau, welche SDU für die Verbindung genommen wird. Dies ist der kleinere der beiden von Client und Server vorgegebenen Werte. Möchte man die SDU ändern, so muss dies sowohl auf Client- als auch auf Serverseite eingetragen werden. Ein Eintrag in der Datei tnsnames.ora sieht dann z.B. wie folgt aus: TO901DL1.HL.DE = (DESCRIPTION = (SDU = 8192) (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = O901DL1.test.hl.de) ) ) Listing 5.9: tnsnames.ora mit SDU
In der Datei listener.ora auf dem Server wird die SID-Liste wie folgt modifiziert: SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SDU = 8192) (GLOBAL_DBNAME = O901DL1.test.hl.de) (ORACLE_HOME = C:\OraBase\Product\O901) (SID_NAME = TO901DL1) ) … ) Listing 5.10: listener.ora mit SDU
Eine Änderung der SDU ist nur in seltenen Fällen notwendig, da Netzwerkpakete der Oracle Net-Umgebung typischerweise eher klein sind. Falls jedoch regelmäßig größere Datenmengen für einzelne Kommandos übertragen werden, kann mit der SDU experimentiert werden. Listener-Konfiguration Mehrere Listener Soll ein weiterer Listener, z.B. mit dem Namen HORCH2, definiert werden, müssen entsprechend die Variablen LOG_DIRECTORY_HORCH2, LOG_FILE_HORCH2, HORCH2 sowie SID_LIST_HORCH2 definiert werden. Falls auf einem System mehrere Listener definiert werden sollen, muss darauf geachtet werden,
Sandini Bib
352
Oracle Net
dass diese keinen identischen Adressparameter bekommen – für den Fall, dass sie gleichzeitig gestartet sein sollen. Nach jedem Kommando kann der Name des Listeners genannt werden, für den das Kommando gelten soll; Standard hierfür ist LISTENER. Hier einige Beispiele: lsnrctl start lsnrctl stop HORCH2 Service für externe Prozeduren Die Programmiersprache PL/SQL unterstützt Aufrufe selbst geschriebener C-Funktionen. Dies ist nützlich, wenn aus Oracle-Funktionalität heraus Abläufe außerhalb des Oracle-Systems angestoßen werden sollen, zu denen keine Schnittstellen existieren, z.B. das Starten von Jobs auf dem Datenbankserver oder der Aufruf von Systemfunktionen. Ein weiterer Anwendungsfall ist die Einbindung bestehender Module, z.B. komplexer Berechnungsverfahren, in eine Oracle-Anwendung.
Die C-Funktionen müssen in Form von Shared Libraries zur Verfügung gestellt werden, d.h., sie werden zur Laufzeit angebunden. Da Betriebssysteme wie Unix und MSWindows keine abgesicherten Hauptspeicherbereiche unterstützen, werden die Shared Libraries nicht direkt an den Oracle-Kern gebunden, sondern an einen weiteren Hintergrundprozess EXTPROC (für external procedure). Die Kommunikation zwischen Oracle Serverprozess und dem EXTPROC-Programm wird über den Listener initiiert (auch wenn in diesem Spezialfall keine Netzwerkkommunikation erforderlich ist). Auch hier bedeutet „initiiert“, dass der Listener lediglich bei Bedarf EXTPROC-Prozesse startet und die Verbindung zwischen diesem und dem Oracle Server herstellt; die Kommunikation selbst erfolgt direkt zwischen Oracle Server und EXTPROC-Prozess. Der Zugriff auf das EXTPROC-Programm wird über einen SID_DESC-Eintrag (als Bestandteil einer SID_LIST) der folgenden Form in der listener.ora konfiguriert: (SID_DESC = (SID_NAME = PLSExtProc) (ORACLE_HOME = C:\OraBase\Product\O901) (PROGRAM = extproc) )
Da die Kommunikation zwischen Serverprozess und EXTPROC-Prozess lokal stattfindet, muss eine Adresse für Interprozesskommunikation in der Adressliste des Listeners eingetragen sein, d.h., er muss einen Adresseintrag der Form (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
haben. Somit ist der Listener in der Lage, beim Eingang einer EXTPROC-Anforderung das Programm extproc zu starten und die entsprechenden Shared Libraries anzubinden. Schließlich muss der Dienstname EXTPROC_CONNECTION_DATA für den Datenbankkern auflösbar sein und auf die beim Listener angegebene IPC-Adresse mit der SID PLSExtProc verweisen. Hierbei ist zu beachten, dass eine eventuell in der Datei SQLNET.ORA angegebene NAMES.DEFAULT_DOMAIN (Standarddomäne für die Auflösung von Dienstnamen) auf jeden Fall verwendet wird.
Sandini Bib
Oracle Net-Architektur
353
EXTPROC_CONNECTION_DATA[.default-domain] = (DESCRIPTION = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0)) (CONNECT_DATA = (SID = PLSExtProc)))
Die Verknüpfung der Shared Library mit den PL/SQL-Strukturen erfolgt in zwei Schritten. Zunächst wird die Shared Library mit dem Kommando CREATE LIBRARY ExtLib AS ’/userlibs/oralib.so’;
bekannt gemacht. Der Aufruf einer Funktion innerhalb der Shared Library wird über die Erstellung einer PL/SQL-Wrapper-Funktion ermöglicht: CREATE FUNCTION WRAP_CALL (X VARCHAR2, Y VARCHAR2) RETURN VARCHAR2 AS LANGUAGE C NAME “FuncCallC” LIBRARY ExtLib;
Ein Aufruf der Form declare ret_val VARCHAR2(100); begin ret_val := wrap_call(’aaa’, ’bbb’); end; /
führt nun dazu, dass 1. über den Listener ein EXTPROC-Prozess aufgebaut wird, falls dieser für die aktuelle Sitzung noch nicht vorhanden ist, 2. die Shared Library /userlibs/oralib.so an den EXTPROC-Prozess gebunden wird, falls dies noch nicht geschehen ist, sowie 3. die Funktion FuncCallC mit den entsprechenden Parametern aufgerufen wird. Der Rückgabewert der Funktion wird an die PL/SQL-Variable ret_val zurückgegeben. Die Details der EXTPROC-Funktionalität sind plattformspezifisch, so dass an dieser Stelle erfahrungsgemäß ein recht hoher Zeitaufwand für die Inbetriebnahme zu kalkulieren ist. Es ist insbesondere anzumerken, dass die mit Hilfe der EXTPROC-Funktionalität programmierten Lösungen nicht portabel sind, d.h. für die Migration auf eine andere Betriebssystemplattform muss der Anpassungsaufwand beachtet werden.
Sandini Bib
354
5.1.5
Oracle Net
Fehlersuche
ORA-12560: TNS:protocol adapter error
Diese Fehlermeldung – aussagekräftig wie syntax error für Programmierer, der Albtraum jedes Administrators – soll den Auftakt zu diesem Abschnitt darstellen. Gerade im Netzwerkumfeld gestaltet sich die Fehlersuche oft kompliziert. Im Falle der Oracle Net Services hat man einige Werkzeuge an der Hand, die zumindest in den meisten Fällen auf unkomplizierte Art und Weise die Analyse des Fehlers ermöglichen. Um einem Fehler auf den Grund zu gehen, ist es zunächst wichtig, die Ebene herauszufinden, auf der das Problem auftritt. Falls keine konkrete Fehlermeldung vorhanden ist, sollte i.A. versucht werden, sich von den unteren Schichten aus nach oben vorzuarbeiten. Die erste Hürde ist die Namensauflösung. Hierbei leistet das Werkzeug tnsping gute Dienste, indem es für einen eingegebenen Dienstnamen die aufgelöste Adresse darstellt. Ein erfolgreicher tnsping-Versuch sieht wie folgt aus: C:\>tnsping dltst.hl.de TNS Ping Utility for 32-bit Windows: Version 9.0.1.1.1 - Production on 26-NOV-2001 21:43:38 Copyright (c) 1997 Oracle Corporation. All rights reserved. Used parameter files: C:\OraBase\Network\Admin\sqlnet.ora C:\OraBase\Network\Admin\tnsnames.ora Used TNSNAMES adapter to resolve the alias Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = hllap10)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = DLTST.test.hl.de))) OK (50 msec) Listing 5.11: tnsping
Leider sind die Angaben zu den benutzten Parameterdateien und Methoden zur Namensauflösung erst ab Oracle9i vorhanden. Man kann jedoch sofort erkennen, welche TCP/IP-Parameter verwendet werden; in diesem Fall wird ebenfalls das Ergebnis „OK“ sowie die Zeitangabe für den Listener-Kontakt zurückgegeben. Fehlt eine Adressangabe oder tnsping antwortet etwa mit TNS-03505: Failed to resolve name,
so ist mit den vorhandenen Konfigurationsdateien keine Namensauflösung möglich. Leider ist man mit Oracle8i darauf angewiesen, die verwendeten Dateien selbst aufzuspüren.
Sandini Bib
Oracle Net-Architektur
355
Falls eine Oracle Net-Verbindung nicht klappt, sollte zunächst einmal mit TCP/IPWerkzeugen wie ping und telnet die Erreichbarkeit des Servers untersucht werden – und zwar mit dem Servernamen bzw. der IP-Adresse, die für den Oracle Net-Verbindungsaufbau benötigt wird. Die beiden Fehlermeldungen TNS-12545: Connect failed because target host or object does not exist ORA-12545: Connect failed because target host or object does not exist
unterscheiden sich lediglich in der Fehlerkategorie (ORA bzw. TNS), meinen aber das Gleiche: Ein TCP/IP-Name kann nicht aufgelöst werden (TCP/IP-Mechanismen HOST-Datei bzw. DNS). Hingegen bedeutet ORA-12154: TNS:could not resolve service name,
dass ein Dienstname nicht aufgelöst werden kann (TNSNAMES.ORA, Oracle Names etc.). Nach erfolgreicher Namensauflösung geht tnsping noch einen Schritt weiter: Mit den nunmehr vorhandenen Adressdaten wird versucht, einen Listener zu kontaktieren. Wenn also eine Erfolgsmeldung wie OK (50 msec)
erscheint, bedeutet dies, dass der Name erfolgreich aufgelöst wurde und danach mit den angegebenen Adressierungsdaten ein Listener kontaktiert wurde, auf dessen Antwort 50 ms gewartet wurde. Dies ist allerdings noch nicht die Bestätigung dafür, dass für die angegebene Instanz eine Verbindung aufgebaut werden kann, wie folgender Versuch mit einem falschen SERVICE_NAME zeigt: C:\>tnsping falsch TNS Ping Utility for 32-bit Windows: Version 9.0.1.2.1 - Production on 09-JAN-2002 15:11:20 Copyright (c) 1997 Oracle Corporation. All rights reserved. Used parameter files: C:\OraBase\Network\Admin\sqlnet.ora C:\OraBase\Network\Admin\tnsnames.ora Used TNSNAMES adapter to resolve the alias Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = hllap10)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = isnichda.hl.de))) OK (50 msec)
Erst ein Verbindungsversuch zeigt den tatsächlichen Fehler: C:\>sqlplus x/y@falsch SQL*Plus: Release 9.0.1.0.1 - Production on Wed Jan 9 15:11:35 2002
Sandini Bib
356
Oracle Net
(c) Copyright 2001 Oracle Corporation. All rights reserved. ERROR: ORA-12514: TNS:listener could not resolve SERVICE_NAME given in connect descriptor Listing 5.12: tnsping mit Fehler
Dies zeigt, dass Versuche mit tnsping nicht die komplette Oracle Net-Funktionsfähigkeit beweisen können, das Werkzeug jedoch wertvolle Hilfe im Bereich Namensauflösung und Adressierung geben kann. Die in SQL*Plus angezeigte Fehlermeldung ORA-12514 bedeutet, dass der Listener den verlangten SERVICE_NAME nicht in seiner Liste hat, d.h., es liegt entweder ein Konfigurationsfehler vor oder die Instanz, die den Namen als einen von mehreren Namen im Initialisierungsparameter SERVICE_NAMES zugewiesen hat, ist nicht gestartet. Sobald auch dies berichtigt ist, kann ein Verbindungsversuch wie folgt aussehen: C:\>sqlplus x/x@to901dl1 SQL*Plus: Release 9.0.1.0.1 - Production on Wed Jan 9 15:27:20 2002 (c) Copyright 2001 Oracle Corporation. All rights reserved. ERROR: ORA-01017: invalid username/password; logon denied
Dies bestätigt nun schließlich den korrekten Verbindungsaufbau – die Fehlermeldung kommt immerhin aus dem Oracle Serverprozess, der offensichtlich korrekt vom Listener aufgebaut worden ist. Mit einem korrekten Benutzername/PasswortPaar funktioniert dies natürlich ebenfalls; es kommt jedoch vor, dass man die NetAnbindung verifizieren muss, ohne ein korrektes Login zu kennen. Trace-Dateien Sollten die beschriebenen einfachen Verfahren nicht weiterhelfen, so muss Tracing aktivert werden. Für Oracle Net lassen sich an verschiedenen Stellen Traces anschalten, deren Ergebnis in Form von Dateien gespeichert wird. Grundsätzlich muss überlegt werden, welche Komponente Traces erzeugen soll, damit die passenden Informationen erzeugt werden. Weiterhin muss nach der Trace-Sitzung unbedingt darauf geachtet werden, die Traces wieder auszuschalten, da diese Funktion sowohl die Performance beeinflusst als auch sehr speicherplatzintensiv ist. Um Oracle Net auf der Client-Seite zu tracen, muss folgender Parameter in der Datei SQLNET.ORA angegeben werden: TRACE_LEVEL_CLIENT = OFF | USER | ADMIN | SUPPORT
Sandini Bib
Oracle Net-Architektur
357
Diese dokumentierten Trace-Level reichen in vielen Fällen aus. Weitere Trace-Level sind direkt über Ziffern erreichbar, wobei der größte Trace-Level 16 ist (dabei entspricht SUPPORT dem Trace-Level 15). Einige weitere Parameter sind bei der Einrichtung der Traces ebenfalls hilfreich: TRACE_DIRECTORY_CLIENT = TRACE_FILE_CLIENT = TRACE_FILELEN_CLIENT = <max. Größe in Kbyte> TRACE_FILENO_CLIENT = <max. Anzahl> TRACE_UNIQUE_CLIENT = ON | OFF TRACE_TIMESTAMP_CLIENT = ON | OFF
Wichtig ist, mit TRACE_DIRECTORY_CLIENT ein Verzeichnis anzugeben, in dem alle Traces gespeichert werden sollen. Den Namen mit TRACE_FILE_CLIENT anzugeben ist weniger wichtig; interessanter ist sicherlich, mit TRACE_UNIQUE_CLIENT = ON dafür zu sorgen, dass Traces von unterschiedlichen Sitzungen verschiedene Namen bekommen. Optional ist es möglich, die Größe der Trace-Dateien in Kbyte mit TRACE_FILELEN_CLIENT zu beschränken. Dabei sollte auch eine Anzahl TraceDateien mit TRACE_FILENO_CLIENT angegeben werden, die zyklisch benutzt und überschrieben werden. Mit TRACE_TIMESTAMP_CLIENT wird jedem Eintrag ein Zeitstempel beigefügt. Um eine schnelle Reaktion zu ermöglichen, empfiehlt es sich, die gewünschten Parameter mit dem Wert OFF für TRACE_LEVEL_CLIENT in der SQLNET.ORA vorbereitet zu haben, so dass das Tracing mit einem Handgriff eingeschaltet werden kann. Alle o.a. Parameter gibt es für den Datenbankserver auch als TRACE_LEVEL_SERVER usw. Hier zählen natürlich die Einträge der SQLNET.ORA auf der Serverseite. Das Einschalten des Tracings ist nicht so einfach wie auf der Client-Seite, da der Datenbankserver die Parameter beim Start der Instanz auswertet. Zum Server-Tracing ist also ein Neustart der Instanz notwendig (und natürlich auch wieder beim Abschalten). Weiterhin gibt es TRACE_LEVEL_LISTENER usw. für den Listener (in der Datei LISTENER.ORA). Den Listener kann man im laufenden Betrieb durch einen RELOAD in den Trace-Modus versetzen. Trace Assistant Zur Auswertung von Trace-Dateien auch unter Performance-Gesichtspunkten sei der Vollständigkeit halber der Trace Assistant erwähnt. Dieses Werkzeugt benötigt eine Net Trace-Datei, die mit Trace-Level 16 erstellt wurde. (Der größte dokumentierte Trace-Level SUPPORT entspricht 15.) Der Trace Assistant ist bei Oracle8i als kompiliertes ausführbares Programm generell Bestandteil der normalen Installation. In der Oracle9i-Installation fehlt dieses Programm auf einigen Plattformen, u.a. auf MS-Windows. Allerdings gibt es einen neuen Ansatz, dieses Werkzeug Javabasiert zu verteilen. Für kurze Zeit gab es einen entsprechenden Beta-Download im Oracle Technet (http://otn.oracle.com), mit dem die Beispiele in diesem Kapitel erstellt worden sind. Eine gute Übersicht über die Oracle Net-Parameter liefert die Darstellung des Connect-Pakets:
Sandini Bib
358
Oracle Net
---> Send 247 bytes - Connect packet sequence number=000001 Current NS version number is: 311. Lowest NS version number can accommodate is: 300. Maximum SDU size:2048 Maximum TDU size:32767 NT protocol characteristics: Asynchronous mode Callback mode Test for more data Full duplex I/O Urgent data support Grant connection to another Line turnaround value :0 Connect data length :189 Connect data offset :58 Connect data maximum size :512 Native Services wanted Authentication is linked and specify NAU doing O3LOGON - DH key foldedin Native Services wanted Authentication is linked and specify NAU doing O3LOGON - DH key foldedin Cross facility item 1: 0 Cross facility item 2: 0 Connection id : Ox000002E4000001B8 (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host= ... Listing 5.13: Trace Assistent
Aus den eher kryptischen einzelnen Zeilen der Trace-Datei werden dann Informationen mit Aufrufen gegen die Datenbank generiert, die z.B. wie folgt aussehen: ---> Send 93 bytes - Data packet sequence number=000001 Start of user function (TTIFUN) new v8 bundled call (OALL8) <--- Received 172 bytes - Data packet sequence number=000001 Describe information (TTIDCB)
Für jedes Paket werden also die aufgerufenen Funktionen sowie die Anzahl der gesendeten bzw. empfangenen Bytes dokumentiert. Eine solch detaillierte Aufstellung ist nur in seltenen Fällen notwendig; es kann jedoch auch (entweder zusätzlich oder alleine) Statistikinformation in der folgenden Form aufgerufen werden: ====================================================================== Trace File Statistics: ---------------------------------------------------------------------DATABASE Operation Counts: 2 opens, 2 parses, 2 executes, 1 fetches.
Sandini Bib
Oracle Net-Architektur
359
Parse Counts: 0 pl/sql, 1 select, 0 insert, 0 update, 0 lock, 1 transact, 0 define, 0 secure, Execute Counts for those executes with SQL data: 0 pl/sql, 0 select, 0 insert, 0 update, 0 lock, 0 transact, 0 define, 0 secure,
0 delete, 0 other 0 delete 0 other
Operation Ratios: 1.0 parses per open, 1.0 executes per parse Packet Ratio: 89.0 SQL*Net: Total Calls: 178 sent, Total Bytes: 10565 sent, Average Bytes: 59 sent, Maximum Bytes: 1023 sent, GRAND TOTAL PACKETS sent: 178
178 received, 92454 received 519 received 905 received received: 178
172 upi
Listing 5.14: Trace File-Statistik
Man bekommt hier einen guten Überblick über die Art und Anzahl der Aufrufe an die Datenbank sowie die dazugehörenden Netzwerkpakete. An dieser Stelle kann z.B. überprüft werden, ob eine Veränderung der SDU den gewünschten Effekt hat. Für ein Beispiel, in dem 1.000 kleine Datensätze in SQL*Plus mit einer ARRAYSIZE von 15 selektiert wurden, sehen die entsprechenden Zeilen in der Trace AssistantStatistik wie folgt aus: SQL*Net: Total Calls: 44 sent, 232 received, Total Bytes: 5685 sent, 407380 received Average Bytes: 129 sent, 1755 received Maximum Bytes: 791 sent, 2019 received GRAND TOTAL PACKETS sent: 44 received: 232
29 upi
Wird die SDU auf 8.192 geändert, so ändert sich die Statistik: SQL*Net: Total Calls: 44 sent, 82 received, Total Bytes: 5687 sent, 405881 received Average Bytes: 129 sent, 4949 received Maximum Bytes: 792 sent, 8163 received GRAND TOTAL PACKETS sent: 44 received: 82
29 upi
Listing 5.15: Trace File-Statistik mit geänderter SDU
Die maximale Paketgröße für empfangene Pakete hat sich von 2.019 Byte auf 8.163 Byte erhöht, wodurch sich die Anzahl der empfangenen Pakete von 232 auf 82 reduziert (ca. 65 % weniger Pakete). Zusätzlich reduziert sich die Anzahl der empfangenen Bytes von 407.380 auf 405.881 um immerhin 1.499, d.h., insgesamt reduziert sich der Netzwerk-Overhead.
Sandini Bib
360
5.2
Oracle Net
Konfigurationswerkzeuge
Die Geschichte der Konfigurationswerkzeuge für Oracle Net hat mittlerweile zahlreiche Kapitel. Leider gibt es kein Werkzeug, das in der Lage ist, alle Konfigurationsanforderungen im Oracle Net-Umfeld abzudecken. In diesem Abschnitt sollen daher die Werkzeuge mit ihren Spezialaufgaben dargestellt werden. Historisch hat die Geschichte der Oracle Net-Konfigurationswerkzeuge mit dem Network Manager der SQL*Net-Version 2 angefangen. Mit Version 1 von SQL*Net war eine Konfiguration nicht vorgesehen – mit Connect-Strings wie T:host:1525 wurde angegeben, dass eine Verbindung über TCP/IP auf den Host host zu Port 1525 aufgebaut werden sollte. Zusätzliche Parameter gab es nicht. Das Konzept des Network Managers war dann eher monolithisch: Das ganze Netzwerk musste zunächst einmal nachmodelliert werden, um später Services wie Listener, Datenbanken usw. auf Knoten zu platzieren. Danach wurden Konfigurationsdateien generiert und auf die Knoten verteilt. Schließlich konnte man die Konfiguration benutzen. Obwohl alle Konfigurationsdateien ein reines ASCII-Format hatten, war es nicht erlaubt, sie mit einem Texteditor zu verändern. Das hat zu zwei Effekten geführt: 1. An die Vorgabe, die Konfigurationsdateien nicht manuell ändern zu dürfen, hat sich niemand gehalten. 2. Neue Features wurden oft erst in späteren Releases bzw. fehlerhaft im Network Manager implementiert, so dass SQL*Net selbst nach Oracle-Vorgaben gar nicht benutzbar war. Somit wurde mit Oracle8 die Strategie komplett geändert: Selbst erstellte bzw. modifizierte Konfigurationsdateien waren erlaubt, teilweise sogar vorausgesetzt. Wer unbedingt wollte, konnte einige Konfigurationen mit dem Net8 Assistant durchführen. Der Repository-basierte Ansatz zur zentralen Verwaltung der Konfiguration wurde ersatzlos gestrichen – bei dem Anspruch, alle möglichen manuell erstellten Dateien zu unterstützen, wäre diese sicherlich auch nicht mehr möglich gewesen. Mit Oracle Net in der Version 9i sind die Nachfolger von Net8 Assistant usw. in recht stabilen (aber auch nicht unproblematischen) Versionen verfügbar. Mit allen vorgestellten Werkzeugen hat man aus einer grafischen Oberfläche Zugriff auf die Konfigurationsdateien, d.h., alle Werkzeuge arbeiten so, dass sie beim Start die jeweils benötigten – lokalen! – Konfigurationsdateien einlesen und beim Beenden bzw. beim Aufruf des entsprechenden Menüpunkts die geänderte Konfiguration in die Dateien zurückschreiben. Es gibt demnach kein Repository o.Ä., das mit den Dateien abgeglichen werden müsste. Weiterhin sind alle Werkzeuge in Java geschrieben. Das ermöglicht u.a. ein nahezu identisches Aussehen und Verhalten auf den verschiedenen Plattformen. Nachteilig ist der recht hohe Ressourcenbedarf, z.B. an Hauptspeicher. Bei knapp ausgestatteten Maschinen kann es z.B. während der Installation Probleme geben, wenn der Universal Installer, der ja ebenfalls in Java geschrieben ist, weitere Java-basierte Konfigurationswerkzeuge startet. Über die letzten Releases hinweg kann man Oracle
Sandini Bib
Konfigurationswerkzeuge
361
jedoch in der Java-Produktlinie ein durchaus großes Engagement in Bezug auf Laufzeitstabilität und Ressourcenoptimierung bescheinigen. In diesem Kapitel sollen der Net-Konfigurationsassistent sowie der Net Manager vorgestellt werden. Weitere Hilfswerkzeuge und Assistenten streifen Oracle Net zwar thematisch, gehören jedoch eher zu Spezialgebieten wie dem Internet Directory.
5.2.1
Net-Konfigurationsassistent
Der Net-Konfigurationsassistent wird am Ende einer erfolgreichen Oracle-Installation automatisch gestartet und ist somit das erste Oracle Net-Werkzeug, mit dem man Bekanntschaft macht. Dabei kann eine Basiskonfiguration eingerichtet werden. Diese ähnelt der weiter oben beschriebenen Standardkonfiguration; der Listener enthält jedoch z.B. keine Einträge für eine Instanz in der SID_LIST. Unverständlich ist, dass der Net-Konfigurationsassistent nicht auf die $TNS_ADMINVariable zur Festlegung des Konfigurationsverzeichnisses reagiert. Er liest und speichert Konfigurationen grundsätzlich in $ORACLE_HOME/network/admin. Falls man $TNS_ADMIN benutzt, muss man vor Konfigurationsänderungen alle betroffenen Dateien ins Standardverzeichnis kopieren und später wieder zurück. Nach dem Aufruf des Net-Konfigurationsassistenten stehen vier Konfigurationsbereiche zur Auswahl:
Abbildung 5.1: Einstieg Net-Konfigurationsassistent
Listener-Konfiguration Beim Listener werden lediglich Name und Listener-Adresse (Protokoll sowie im Falle von TCP/IP Hostname und Port) abgefragt. Weitere Parameter wie Pfade für Logging und Tracing, Timeouts usw. können nicht konfiguriert werden.
Sandini Bib
362
Oracle Net
Angenehm ist, dass der Listener nach erfolgter Konfiguration sofort gestartet wird – somit steht die Oracle Net-Serverfunktionalität direkt zur Verfügung.
Abbildung 5.2: Listener hinzufügen
Eine Listener-Konfiguration durchläuft im Net-Konfigurationsassistenten folgende Schritte: Zunächst muss ausgewählt werden, ob ein Listener hinzugefügt, neu konfiguriert, gelöscht oder umbenannt werden soll. An dieser Stelle treffen wir die Auswahl HINZUFÜGEN. Als Nächstes kann der Listener-Name vergeben werden, der mit LISTENER voreingestellt ist:
Abbildung 5.3: Listener-Namen vergeben
Sandini Bib
Konfigurationswerkzeuge
363
Aus der Liste der Protokolle wird in der Regel TCP ausgewählt.
Abbildung 5.4: Protokoll(e) auswählen
Anschließend werden die Details für die ausgewählten Protokolle – hier TCP/IP – konfiguriert. Der Port ist standardmäßig mit 1521 vorbelegt. Wenn keine speziellen Anforderungen dagegen sprechen, sollte dieser Port übernommen werden. Falls der zu konfigurierende Server über mehrere Netzwerk-Interfaces verfügt, wird hier ausschließlich das Standard-Interface konfiguriert.
Abbildung 5.5: Port auswählen
Nach dem Bestätigen der folgenden Meldung wird der Listener gestartet; unter MSWindows wird gegebenenfalls ein passender Dienst angelegt.
Sandini Bib
364
Oracle Net
Abbildung 5.6: Abschluss der Konfiguration
Konfiguration von Benennungsmethoden Mit dieser Konfiguration wird festgelegt, welche Benennungsmethoden verwendet werden sollen (Oracle Names, TNSNAMES.ORA-Datei usw.) sowie in welcher Reihenfolge diese genutzt werden. Hierbei ist lediglich folgender Auswahlbildschirm von Bedeutung:
Abbildung 5.7: Benennungsmethoden
Aus VERFÜGBARE BENENNUNGSMETHODEN können verschiedene ausgewählt werden; diese werden mit den Pfeilen auf der rechten Seite von AUSGEWÄHLTE BENENNUNGSMETHODEN in der Priorität verändert. ORACLE-NAMEN steht für Namensauflösung in
Sandini Bib
Konfigurationswerkzeuge
365
Oracle Names, LOKAL für TNSNAMES.ORA sowie VERZEICHNIS (taucht erst nach der Konfiguration eines Verzeichnisdienstes auf) für Verzeichnisdienst bzw. LDAP-Server. Konfiguration von Directory-Verwendung Diese Konfigurationsoption kann ausschließlich mit dem Net-Konfigurationsassistenten eingerichtet werden – der Net Manager ermöglicht dies nicht. Der Net-Konfigurationsassistent stellt nun einige Optionen zur Verfügung, mit denen
: : : :
ein Directory Server lediglich ausgewählt werden kann, ein Directory Server zur Verwendung mit Oracle (Namensauflösung) konfiguriert werden kann, ein zusätzlicher Oracle Context eingerichtet werden kann und ein Oracle-Schema konfiguriert werden kann.
Abbildung 5.8: Directory-Verwendung konfigurieren
Details hierzu werden in Kapitel 4.4 besprochen. Danach wählt man zunächst die Art des Verzeichnisses (ORACLE INTERNET DIRECTORY oder MICROSOFT ACTIVE DIRECTORY) aus:
Sandini Bib
366
Oracle Net
Abbildung 5.9: Auswahl der Verzeichnisart
Danach muss nur noch die Adresse eingegeben werden, unter der der Verzeichnisdienst erreichbar ist:
Abbildung 5.10: Adresse des Verzeichnisdienstes
Sobald man diesen Bildschirm mit WEITER bestätigt, versucht der Net-Konfigurationsassistent den Verzeichnisdienst zu erreichen. Unabhängig vom Erfolg erstellt er eine Datei LDAP.ORA mit folgendem Inhalt: # LDAP.ORA Network Configuration File: C:\OraBase\Product\O901\network\admin\ldap.ora # Generated by Oracle configuration tools.
Sandini Bib
Konfigurationswerkzeuge
367
DIRECTORY_SERVERS= (hlsun1:389:636) DIRECTORY_SERVER_TYPE = OID
Nur bei erfolgreichem Test trägt er allerdings die Benennungsmethode LDAP in der Datei SQLNET.ORA ein.
5.2.2
Net Manager
Das vielfältigste Konfigurationswerkzeug für Oracle Net ist der Net Manager. Wir empfehlen generell, den Net Manager anstelle des Net-Konfigurationsassistenten zu benutzen, da hier zumindest mehr Optionen auf der Oberfläche zur Verfügung stehen und daher eine größere Flexibilität gegeben ist. Es gibt jedoch ein Feature, das ausschließlich mit dem Net-Konfigurationsassistenten eingeschaltet werden kann: die Benutzung eines LDAP-Servers zur Auflösung von Dienstnamen. Falls ein Verzeichnisdienst verwendet werden soll, sollte lediglich die Basiskonfiguration mit dem Net-Konfigurationsassistenten erstellt werden; die weitere Konfiguration sollte mit dem Net Manager erfolgen. Der Net Manager zeigt sich mit folgender Oberfläche:
Abbildung 5.11: Net Manager
Sandini Bib
368
Oracle Net
Die grundsätzliche Arbeitsweise des Net Managers besteht aus dem Auslesen der Oracle Net-Konfigurationsdateien aus einem Arbeitsverzeichnis, dem Bearbeiten der Konfiguration über die grafische Oberfläche sowie dem abschließenden Speichern im Arbeitsverzeichnis. Einträge, die der Net Manager nicht „versteht“, bleiben, so wie sie sind, erhalten. Das aktuell bearbeitete Konfigurationsverzeichnis wird in der Titelleiste des Net Managers angegeben. Falls man ein anderes Verzeichnis bearbeiten möchte, kann dies unter DATEI – NETZWERKKONFIGURATION ÖFFNEN ... ausgewählt werden. Mit DATEI – NETZWERKKONFIGURATION SPEICHERN ... werden die Dateien im aktuellen Arbeitsverzeichnis gespeichert; mit DATEI – SPEICHERN UNTER ... kann ein anderer Speicherort gewählt werden. Die Bedienoberfläche des Net Managers ist dreigeteilt. Ganz links befinden sich einige Schalter, z.B. zum Einfügen oder Löschen von Elementen. Rechts daneben befindet sich ein Navigationsbaum, in dem der zu konfigurierende Bereich ausgewählt wird. Auf der rechten Seite werden schließlich die zu konfigurierenden Details gezeigt. Bei komplexeren Konfigurationen, wie z.B. für Listener, werden durch ein Pulldown-Menü (LISTENING-ADRESSEN) verschiedene Unterbereiche angewählt; hier sind neben LISTENING-ADRESSEN noch ALLGEMEINE PARAMETER, DATENBANKDIENSTE und ANDERE DIENSTE vorhanden. Bei den allgemeinen Parametern sind z.B. die Einstellungen für Logs und Traces vorzunehmen:
Abbildung 5.12: Listener Logs und Traces
Sandini Bib
Konfigurationswerkzeuge
369
Der Bereich DIENSTEBENENNUNG bestimmt den Inhalt der Datei TNSNAMES.ORA. Klickt man einen Eintrag im Navigationsbaum an, so erscheinen auf der rechten Seite die Details zu dem Eintrag:
Abbildung 5.13: Dienstebenennung
Der abgebildete Eintrag ist durch folgende Schritte mit dem Net Service NameAssistenten erstellt worden:
Abbildung 5.14: Dienstnamen eingeben
Sandini Bib
370
Oracle Net
Zunächst muss der komplette Dienstname angegeben werden. Hier wird nicht etwa eine Standarddomäne angehängt; wenn man eine Domäne haben möchte, muss sie angegeben werden.
Abbildung 5.15: Protokoll auswählen
Je nach Plattform werden verschiedene Protokolladapter angeboten. TCP/IP ist der gebräuchlichste.
Abbildung 5.16: Verbindungsdaten eingeben
Diese Seite ist bereits abhängig vom gewählten Protokolladapter. Für TCP/IP müssen ein Hostname und eine Port-Nummer angegeben werden. Anstelle des Hostnamens wird auch die Angabe einer IP-Adresse akzeptiert.
Sandini Bib
Konfigurationswerkzeuge
371
Abbildung 5.17: Zieldatenbank (Dienst oder Instanz)
Zur Identifikation der gewünschten Instanz auf dem Zielrechner muss entweder ein Dienstname oder eine SID angegeben werden. Die SID funktioniert mit allen Oracle-Versionen, der Dienstname erst ab Oracle8i (Client- und Serverversion!).
Abbildung 5.18: Abschluss
Der Assistent muss zwar für die Ersteingabe des Dienstnamens benutzt werden, danach kann aber der Net Manager zur Modifikation des Eintrags genutzt werden. Fügt man z.B. eine weitere Adresse in der Adresskonfiguration ein, so erreicht man über den Schalter ERWEITERT ... das folgende Fenster:
Sandini Bib
372
Oracle Net
Abbildung 5.19: Optionen für Adresslisten
Mit der hier gezeigten Option sieht der Eintrag in der Datei TNSNAMES.ORA wie folgt aus: NEUER-NAME.DOMAIN = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hostname)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = hostname)(PORT = 1522)) (LOAD_BALANCE = yes) ) (CONNECT_DATA = (SERVICE_NAME = dienst.domain) ) )
Die Auswahl NEHMEN SIE DEN VERSUCH BELIEBIG MIT JEDER ADRESSE VOR, BIS EIN VERSUCH ERFOLGREICH IST schaltet also den LOAD_BALANCE-Parameter ein. Die anderen Parameter schalten weitere Varianten mit den Parametern FAILOVER bzw. SOURCE_ROUTE ein.
5.3
Shared Server
Der Standardmodus für Serverprozesse einer Oracle-Instanz ist nach wie vor das Dedicated Server-Modell. Hierbei wird für jede Verbindung an die Instanz ein eigener Prozess (unter MS-Windows: Thread) gestartet, der ausschließlich für deren Aufrufe an den Datenbankserver zuständig ist. Für die meisten Installationen ist dieser Modus nach wie vor optimal, da das Betriebssystem die verfügbaren Ressourcen wie CPU und Speicher so flexibel zuteilen kann. In folgenden Situationen kann das Dedicated Server-Modell jedoch nachteilig sein:
:
Wenn sehr viele Verbindungen bestehen (etwa mehrere Tausend oder Zehntausend), die eher selten genutzt werden. Dies ist bei OLTP3-Systemen der Fall.
Sandini Bib
Shared Server
:
373
Wenn Verbindungen extrem häufig auf- und abgebaut werden. Dies ist bei Webanwendungen der Fall.
Für diese Fälle bietet Oracle den Shared Server-Modus an, bei dem die Datenbanklast von einer konfigurierbaren, dynamischen Anzahl von Shared Server-Prozessen abgearbeitet wird, die keine feste Verbindung mehr zu den Verbindungen bzw. Sitzungen haben. In diesem Modell stellen die Dispatcher-Prozesse die festen Ansprechpartner für die Client-Verbindungen dar. Diese werden durch Initialisierungsparameter wie dispatchers = "(PROTOCOL=TCP)(DISPATCHERS=2)" max_dispatchers = 7
konfiguriert.4 Die Shared Server werden mit shared_servers = 3 max_shared_servers = 10
angegeben. Die beiden max_-Parameter sind im Gegensatz zu den anderen beiden nicht dynamisch veränderbar. Die Anzahl der Shared Server wird je nach Lastsituation selbständig vom System innerhalb der vorgegebenen Grenzen verändert. Beim Hochfahren der Instanz melden sich die Dispatcher beim Listener an. Das Listener Control Utility listet bei einem SERVICES-Kommando alle angemeldeten Services für eine Instanz: Service "O901DL1.test.hl.de" has 1 instance(s). Instance "to901dl1", status READY, has 3 handler(s) for this service... Handler(s): "DEDICATED" established:0 refused:0 state:ready LOCAL SERVER "D001" established:0 refused:0 current:0 max:1002 state:ready DISPATCHER <machine: HLLAP10, pid: 1192> (ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP10)(PORT=1219)) "D000" established:1 refused:0 current:1 max:1002 state:ready DISPATCHER <machine: HLLAP10, pid: 1372> (ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP10)(PORT=1218)) Listing 5.16: Anmelden des Dispatchers
Das Beispiel zeigt eine Instanz mit zwei Dispatchern (D000 und D001) zusätzlich zum Standard-Handler für Dedicated Server-Verbindungen. Es werden neben den Ports für die TCP/IP-Kommunikation auch Verbindungsstatistiken angezeigt. Hiermit wird z.B. herausgefunden, ob mit einer bestimmten Konfiguration der gewünschte Verbindungstyp – shared oder dedicated – auch genommen wird. 3. 4.
Online Transaction Processing: Diese Beschreibung gilt für viele Client-Server-Systeme. Hier werden typischerweise viele kleine Transaktionen gegen eine große Datenbank gefahren. In Oracle8i und früheren Releases ist allen Parametern aus dem Bereich Shared Server das Präfix mts_ vorangestellt. Diese Varianten werden zwar in Oracle9i noch unterstützt, es wird jedoch empfohlen, auf die neuen Namen umzustellen. Dies ist mit der Umbenennung der Multi-Threaded Server in Shared Server begründet.
Sandini Bib
374
Oracle Net
Für den Initialisierungsparameter DISPATCHERS gilt, dass er mehrmals angegeben werden kann. Es können also verschiedene Dispatcher bzw. Gruppen von Dispatchern in mehreren Zeilen konfiguriert werden, z.B. eine Gruppe von TCP-Dispatchern und eine Gruppe von IPC-Dispatchern: dispatchers = "(PROTOCOL=TCP)(DISPATCHERS=2)" dispatchers = "(PROTOCOL=IPC)(DISPATCHERS=2)"
Dies führt dazu, dass für jedes der Protokolle TCP und IPC zwei Dispatcher gestartet werden. Mit ALTER SYSTEM-Befehlen kann auf die einzelnen Gruppen Einfluss genommen werden: alter system set dispatchers='(protocol=ipc)(dispatchers=1)';
Neben der Angabe von PROTOCOL als erstem Parameter für DISPATCHERS ist eine ADDRESS- oder DESCRIPTION-Klausel erlaubt, wie z.B.: dispatchers = "(ADDRESS=(PROTOCOL=TCP)(HOST=hllap10)(PORT=1527))"
Hiermit wurde ein Dispatcher gezielt auf einem bestimmten Port gestartet. Weiterhin können diverse Optionen für die Dispatcher angegeben werden:
: : : : : :
: :
SESSIONS (SES, SESS) gibt die maximale Anzahl von Verbindungen pro Dispat-
cher an, CONNECTIONS (CON, CONN) die maximale Anzahl von Netzwerkverbindungen, TICKS (TIC, TICK) die Länge eines Netzwerk-Ticks in Sekunden, POOL (POO) schaltet Connection Pooling ein, MULTIPLEX (MUL, MULT) schaltet Multiplexing ein, LISTENER (LIS, LIST) gibt den Namen des Listeners an, bei dem sich die Dispat-
cher registrieren sollen, SERVICE (SER, SERV) gibt den Service-Namen an, mit dem sich die Dispatcher
beim Listener registrieren sollen, INDEX gilt für ALTER SYSTEM-Befehle und gibt die Nummer der Dispatcher-Konfigurationszeile an, die modifiziert werden soll (es wird bei 0 beginnend nummeriert).
Diese Optionen werden meist für Connection Manager-Konfigurationen (MULTIPLEX) bzw. in speziellen Situationen benötigt. Einfache Shared Server-Konfigurationen kommen in den meisten Fällen ohne diese Optionen aus. Als Besonderheit kann noch das Connection Pooling erwähnt werden: Hierbei wird die Anzahl möglicher Verbindungen (SESSIONS) zur Instanz dadurch erhöht, dass eine beschränkte Anzahl von Netzwerkverbindungen (CONNECTIONS) je nach Bedarf zwischen den logischen Verbindungen verteilt wird. Hierzu ein Konfigurationsbeispiel: dispatchers = "(PROTOCOL=TCP)(DISPATCHERS=1)(POOL=ON)(SES=2000)\ (CONN=200)(TICK=10)"
Sandini Bib
Connection Manager
375
Hierdurch werden Konfigurationen mit Tausenden von Verbindungen, wie sie im Webumfeld vorkommen können, ermöglicht. Zur Performance-Optimierung von Shared Server-Konfigurationen ist zu sagen, dass die Hauptaufgabe darin besteht, die richtige Anzahl an Dispatchern und Shared Servern zu finden. Die Dispatcher können zwar asynchron arbeiten, d.h. bei quasi gleichzeitigen Zugriffen mehrerer Sitzungen die ein- und ausgehenden Daten fehlerfrei behandeln, allerdings ergeben sich Wartezustände, wenn zu viele Sitzungen mit vielen Calls oder mit großen Datenmengen vorhanden sind. Die Shared Server funktionieren prinzipiell sehr gut auf CPU-Basis, d.h., pro CPU sollte zunächst ein Shared Server konfiguriert werden. Falls jedoch Calls mit längeren Laufzeiten (z.B. lange laufende Abfragen) vorhanden sind, muss man sich der Tatsache bewusst sein, dass ein Shared Server für die Laufzeit eines Calls an eben diesen Call gebunden ist, d.h., es kann zu blockierenden Zuständen kommen. (Man kann es auch so formulieren, dass die Shared Server-Architektur für OLTP-typische Anwendungen optimiert ist.) Die Wartezustände kann man entweder dadurch umgehen, dass mehrere Shared Server definiert werden, oder man richtet für Anwendungen, die bekanntermaßen lange laufende Calls haben, Dedicated Server ein.
5.4
Connection Manager
Der Connection Manager ist ein Dienst der Oracle Net Services, der verschiedene Rollen im Netzwerkumfeld spielen kann. Man kann sich den Connection Manager zunächst als Zwischenstation zwischen Client und Server vorstellen:
Abbildung 5.20: Connection Manager
Bei der Einführung mit Net8 hat der Connection Manager zuallererst das MultiProtocol Interchange der SQL*Net Version 2 abgelöst, mit dem Clients und Server sich transparent über unterschiedliche Protokolle unterhalten können. Zu diesem Zeitpunkt waren Installationen mit Novell-Netzwerken und SPX/IPX als Protokoll auf den Clients noch recht häufig anzutreffen. Mit dem Connection Manager können diese Clients z.B. auf einen Oracle Server unter Unix zugreifen, der ausschließlich TCP/IP beherrscht, ohne die Clients mit eben diesem Protokoll ausstatten zu müssen. Nur der Rechner, auf dem der Connection Manager läuft, muss beide Protokolle installiert haben. Aus heutiger Sicht fällt dieser Einsatzbereich praktisch weg, da TCP/IP als Kommunikationsbasis überall zur Verfügung steht.
Sandini Bib
376
Oracle Net
Der häufigste Einsatzbereich bezieht sich auf das Connection Multiplexing. Hierbei laufen mehrere Client-Verbindungen über einen Connection Manager zu einem Dispatcher, wobei alle logischen Verbindungen für die Strecke vom Connection Manager zum Dispatcher nur eine physikalische Verbindung nutzen. Dies soll den zusätzlichen Verwaltungsaufwand für die Connection Manager-Verbindungen reduzieren. In einigen WAN-Modellen, deren Kosten etwa über die Anzahl von TCP/IP-Verbindungen abgerechnet werden, kann Connection Multiplexing zur Kostenreduzierung eingesetzt werden. Die Installation des Connection Managers kann auf einem Rechner erfolgen, der keine andere Oracle-Software installiert hat. Alternativ dazu kann ein Server die Connection Manager-Aufgaben zusätzlich übernehmen; die Anforderungen an Hauptspeicher und CPU halten sich dabei meist in Grenzen. Grundsätzlich müssen für den Connection Manager lediglich zwei Adressen in der Datei cman.ora konfiguriert werden: CMAN = (ADDRESS = (PROTOCOL = TCP)(HOST = cmserver)(PORT = 1630)) CMAN_ADMIN = (ADDRESS = (PROTOCOL = TCP)(HOST = cmserver)(PORT = 1830)) Listing 5.17: cman.ora
Aus der Konfiguration wird ersichtlich, dass der Connection Manager mit zwei Prozessen implementiert wird, die jeweils eine oder mehrere Adressen zugewiesen bekommen. Die eigentliche Funktion wird vom Gateway-Prozess CMAN ausgeführt, der Admin-Prozess CMAN_ADMIN übernimmt im Wesentlichen Kontrollfunktionen. Unter MS-Windows ist der Gateway-Prozess als CMGW.EXE; der Admin-Prozess als CMADMIN.EXE zu beobachten. Die hier angegebenen Port-Nummern 1630 für den Gateway-Prozess und 1830 für den Admin-Prozess werden von Oracle empfohlen; es können aber auch beliebige andere freie Ports verwendet werden. Eine Client-Verbindung über einen Connection Manager wird nun in der Datei tnsnames.ora wie folgt konfiguriert: GEHEIM.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = cmserver)(PORT = 1630)) (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521)) ) (SOURCE_ROUTE = yes) (CONNECT_DATA = (SERVICE_NAME = GEHEIM.HL.DE) ) ) Listing 5.18: tnsnames.ora für Connection Manager
Sandini Bib
Connection Manager
377
Es werden also beim Client beide Adressen (Connection Manager und Listener) konfiguriert; durch die Angabe der Option (SOURCE_ROUTE = yes) wird Oracle Net mitgeteilt, dass es sich hierbei nicht um Failover-Adressen, sondern um eine Kette von nacheinander zu kontaktierenden Diensten handelt. Sobald nun in einem Shared Server-Umfeld Dispatcher mit dem Parameter (MULT=ON) konfiguriert werden, ist Connection Multiplexing aktiviert. Die Funktionsweise kann mit Kommandos wie NETSTAT auf TCP/IP-Ebene kontrolliert werden. Eine weitere Funktionalität des Connection Managers implementiert ein Regelwerk ähnlich einer Firewall. Mit Hilfe von Zugriffskontrollregeln können für Clients, Netzwerke und Hosts Verbindungen erlaubt bzw. verboten werden. Die Regeln werden ebenfalls in der Datei cman.ora abgelegt: CMAN_RULES = (RULE_LIST = (RULE= (src=hllap10)(dst=dbserver)(srv=O901DL1.test.hl.de)(act=reject) ) ) Listing 5.19: cman.ora mit Regeln
Unter src bzw. dst (Quell- und Zielrechner) können Netzwerknamen oder IPAdressen angegeben werden. Als Wildcard kann ein Stern (*) verwendet werden; bei IP-Adressen auch für Teile der Adresse (192.168.149.*). Der Service srv ist bei Oracle8 die ORACLE_SID; bei Oracle8i und Oracle9i die Kombination aus db_name und db_domain bzw. der Servicename. Als Aktion act kann ACCEPT, REJECT oder DROP gewählt werden. Es gelten folgende Regeln bei der Auswertung von CMAN_RULES: 1. Falls es keine Regeln gibt, werden alle Aktionen erlaubt. 2. Die erste Regel, die auf die gewünschte Verbindung zutrifft, zieht. 3. Falls keine Regel zutrifft, wird die gewünschte Aktion abgewiesen. Eine abgewiesene Verbindung (sowohl REJECT als auch DROP) bekommt die Fehlermeldung ORA-12564: TNS:connection refused
Wie beim Shared Server-Konzept kann man keine allgemein gültigen Aussagen über die Performance-Einflüsse des Connection Managers machen. Grundsätzlich ist damit zu rechnen, dass der Aufwand im Oracle Net-Bereich durch den Connection Manager größer wird; somit werden auch die Antwortzeiten eher größer werden. Das Ausmaß der Differenz wird wiederum durch verschiedenste Faktoren wie Netzwerk-Hardware, CPU-Auslastung, Hauptspeicherauslastung usw. bestimmt, so dass das Spektrum von „kein messbarer Unterschied“ bis „Veränderung um einige 10 %“ reichen kann. Das Connection Multiplexing kann andererseits in speziellen Situationen zur Entlastung von WAN-Verbindungen führen. Hier sollten die Auswirkungen im Einzelfall erprobt werden.
Sandini Bib
378
Oracle Net
Ansonsten ist der Connection Manager eher als Spezialist für kreative Lösungen zu sehen. Wenn z.B. eine transparente Oracle Net-Verbindung nicht möglich ist, weil zwei Netze über einen Knoten miteinander verbunden werden, der NAT (Network Address Translation; auch IP-Masquerading) implementiert, was bedeutet, dass ein Netz vom anderen lediglich eine IP-Adresse sieht, kann der Connection Manager auf dem NAT-Knoten (der z.B. unter Linux läuft) die einzig funktionierende Lösung sein!
5.5
Zentrale Auflösung von Dienstnamen
Die Standardmethode zur Auflösung von Dienstnamen ist die Verwendung von TNSNAMES.ORA-Dateien. Die Vorteile liegen auf der Hand:
: : :
Die Struktur der Datei ist recht einfach, so dass z.B. neue Einträge ohne Konfigurationswerkzeuge durch Modifikation eines durch Kopieren und Einfügen entstandenen Eintrags erstellt werden können. Oracle Net kann – abgesehen vom Listener – ohne Installation von weiteren Softwarekomponenten und Konfiguration von Diensten zum Laufen gebracht werden. Das Fehlen zusätzlicher Dienste hat den weiteren großen Vorteil, dass hierdurch keine weiteren Fehlersituationen entstehen können (z.B. durch den Absturz einer zentralen Namensauflösungskomponente).
Gegenüber diesen Vorteilen steht jedoch ein gravierender Nachteil: Sobald die Information der TNSNAMES.ORA-Datei geändert werden muss, weil z.B. eine Datenbank hinzugekommen oder auf einen anderen Knoten umgezogen ist, müssen die Dateien für alle Client-Rechner neu verteilt werden! Nur wenige große Installationen verfügen über eine automatische Verteilfunktion für Softwarekomponenten und Konfigurationsdateien, so dass an dieser Stelle oft ein großer Aufwand für den oder die Administratoren entsteht. Oft wird über die Alternative nachgedacht, die TNSNAMES.ORA-Datei in einem zentralen Verzeichnis zu speichern, das für alle Clients unter dem gleichen Pfadnamen zur Verfügung steht, so dass über die passende Einstellung der TNS_ADMIN-Variablen der Zugriff zentral erfolgen kann. Dies hat wiederum den Nachteil, dass die zentrale Komponente ausfallen kann. Weiterhin ergibt sich ab einer bestimmten Größe der TNSNAMES.ORA-Datei (umgebungsabhängig etwa ab einigen Dutzend Einträgen) eine hohe Netzwerkbelastung sowie eine lange Wartezeit für die Namensauflösung selbst, da die Art und Weise der Dateizugriffe des Net Clients nicht für den Netzwerkbetrieb optimiert ist. Momentan gibt es zwei etablierte Lösungen zur zentralen Namensauflösung: Oracle Names und die Verwendung eines LDAP-fähigen Verzeichnisdienstes (d.h. momentan entweder Oracle Internet Directory oder MS-Active Directory). Oracle Names wurde mit SQL*Net Version 2 eingeführt und stellt einen proprietären Dienst dar. Die Möglichkeiten reichen hier von einer einfachen, größtenteils
Sandini Bib
Zentrale Auflösung von Dienstnamen
379
selbstkonfigurierenden Lösung bis hin zur Unterstützung von großen Netzwerken mit mehreren voneinander abgeschirmten administrativen Regionen, deren Konfigurationen in Datenbanken abgelegt sind. Da Oracle grundsätzlich versucht, Marktstandards in seine Produkte zu integrieren, ist es seit dem Oracle8i Release 2 (8.1.6) möglich, die Namensauflösung einem LDAP-fähigen Verzeichnisdienst zu überlassen. Oracle unterstützt hierbei das hauseigene Internet Directory sowie MS-Active Directory. Eigenschaften wie Speicherung der Daten, Skalierbarkeit und Ausfallsicherheit sind in diesem Fall auf der Ebene des Verzeichnisdienstes zu lösen; mit dem Oracle Internet Directory, das seine Daten – natürlich! – in einer Oracle-Datenbank ablegt, können Skalierbarkeit und Ausfallsicherheit z.B. mit Hilfe des LDAP-Replikationsverfahrens gelöst werden. Oracle betont in den Handbüchern, dass mittelfristig Oracle Names durch das LDAP-Verfahren komplett abgelöst werden soll. Wer also noch keinen zentralen Dienst zur Auflösung von Dienstnamen hat, sollte tunlichst mit LDAP anfangen. In den folgenden beiden Abschnitten werden Oracle Names und LDAP als Namensauflösungsverfahren jeweils näher beleuchtet.
5.5.1
Oracle Names
Um eine zentrale Verwaltung der Dienstnamen zu ermöglichen, gibt es seit SQL*Net Version 2 die Möglichkeit, ein Repository in einer Oracle-Datenbank zu pflegen und die Namen über einen zentralen Dienst abzufragen. Hierbei stehen diverse Strategien zur Verwaltung größerer Netzwerke zur Verfügung. Zunächst unterstützt Oracle Names ein Domänenkonzept. Hierbei handelt es sich um die Domänen, die bereits aus der Benennung von Dienstnamen in der Datei TNSNAMES.ORA bekannt sind. Domänen innerhalb Oracle Net sehen TCP/IP-Domänen sehr ähnlich und werden oft genauso verwendet, d.h., eine Datenbank, die auf dem Rechner host.domain betrieben wird, bekommt den Dienstnamen db.domain. Der Dienstname entspricht wiederum häufig dem globalen Datenbanknamen, der aus den Parametern db_name und db_domain zusammengesetzt wird. Die Namen sind aber nicht zwingend identisch. Das Konzept von Oracle Names sieht nun weiterhin vor, dass Domänen bzw. Gruppen von Domänen zu „administrativen Regionen“ zusammengefasst werden. Diese können wiederum getrennt administriert werden. Eine Region muss die leere sog. Root-Domäne enthalten; diese wird als Root-Region bezeichnet. Eine Option für Oracle Names ist die Speicherung der Daten in einer Regionsdatenbank. Hierzu wird ein Schema in einer Oracle-Datenbank gespeichert, das mit Hilfe eines SQL-Scripts ($ORACLE_HOME/network/names/namesini.sql) initialisiert wird. Die Regionsdatenbank kann nun mit verschiedenen Verfahren gefüllt werden, z.B. mit manuellen Einträgen im Net Manager oder über das Laden von tnsmanes.oraDateien.
Sandini Bib
380
Oracle Net
Oracle Names-Server werden mit names.ora-Dateien konfiguriert. In einer Minimalkonfiguration werden lediglich der Name des Servers und eine Adresse (im Falle von TCP/IP Netzwerk-Interface und Port) angegeben, wie im folgenden Beispiel: # NAMES.ORA Network Configuration File: C:\OraBase\Network\Admin\names.ora # Generated by Oracle configuration tools. NAMES.SERVER_NAME = NS1 NAMES.ADDRESSES = (ADDRESS = (PROTOCOL = TCP)(HOST = HLLAP10)(PORT = 1575)) Listing 5.20: names.ora
Diese Konfiguration bedeutet, dass ohne Regionsdatenbank gearbeitet wird und dass es sich um die Root-Region handelt. Zur Administration des Oracle Names-Servers gibt es das Names Control Utility NAMESCTL. Wie beim Listener Control Utility kann es entweder ohne Parameter aufgerufen und auf einer eigenen Kommandozeile bedient werden oder beim Aufruf mit einem Kommando versehen werden. C:\>namesctl start Oracle Names Control for 32-bit Windows: Version 9.0.1.1.1 - Production on 17-JAN-2002 17:34:12 Copyright (c) 2001 Oracle Corporation. All rights reserved. NNL-00018: warning: could not contact default name server Starting "names.exe"...server successfully started Currently managing name server "NS1" Version banner is "Oracle Names for 32-bit Windows: Version 9.0.1.2.0 - Production" Server name: NS1 Server has been running for: 2.03 seconds Request processing enabled: yes Request forwarding enabled: yes Requests received: 0 Requests forwarded: 0 Foreign data items cached: 0 Region data next checked for reload in: not set Region data reload check failures: 0 Cache next checkpointed in: not set Cache checkpoint interval: not set Cache checkpoint file name: C:\OraBase\Product\O901\network\ names\ckpcch.ora Statistic counters next reset in: not set Statistic counter reset interval: not set Statistic counters next logged in: not set
Sandini Bib
Zentrale Auflösung von Dienstnamen
Statistic counter logging interval: Trace level: Trace file name: Log file name: System parameter file name: Command-line parameter file name: Administrative region name: Administrative region description: ApplTable Index: Contact Operational Status Save Config on Stop
381
not set 0 C:\OraBase\Product\O901\network\trace\ names_1752.trc C:\OraBase\Product\O901\network\ log\names.log C:\OraBase\Network\Admin\names.ora "" "" "" 0 "" 0 no
Listing 5.21: namesctl
Alternativ zur Nutzung des Names Control Utilitys können diverse Funktionen direkt aus dem Net Manager ausgeführt werden. Beim ersten Starten des Servers wird unter MS-Windows ein Dienst OracleNames angelegt. Unter dem Verzeichnis $ORACLE_HOME/network/names werden einige Dateien angelegt, die die Konfiguration und Inhalte des Servers speichern. Falls man auf einem System einen Oracle Names-Server neu aufsetzt, sollten diese Dateien unbedingt gelöscht werden, um eine saubere Ausgangskonfiguration zu erhalten. Die Client-Konfiguration in der Datei sqlnet.ora muss nun noch für Oracle Names konfiguriert werden, z.B. mit folgenden (zusätzlichen bzw. modifizierten) Einträgen: NAMES.PREFERRED_SERVERS = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1575)) ) NAMES.DEFAULT_DOMAIN = hl.de NAMES.DIRECTORY_PATH= (ONAMES) Listing 5.22: sqlnet.ora für Oracle Names
Der Parameter NAMES.PREFERRED_SERVERS gibt eine Liste der erreichbaren Oracle Names-Server an. Mit dem Wert ONAMES als einem von mehreren Werten von NAMES.DIRECTORY_PATH wird Oracle Names als Namensauflösungsverfahren parametriert. Die Benutzung von Oracle Names kann abschließend über TNSPING verifiziert werden: C:\>tnsping to901dl1 TNS Ping Utility for 32-bit Windows: Version 9.0.1.2.1 - Production on 18-JAN-2002 11:14:53 Copyright (c) 1997 Oracle Corporation. All rights reserved.
Sandini Bib
382
Oracle Net
Used parameter files: C:\OraBase\Network\Admin\sqlnet.ora Used ONAMES adapter to resolve the alias Attempting to contact (DESCRIPTION = (SDU = 8192) (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = O901DL1.test.hl.de))) OK (30 msec) Listing 5.23: tnsping für Oracle Names
Falls man eine Regionsdatenbank benutzen möchte, kann diese wiederum im Net Manager oder manuell angegeben werden. Die Datei names.ora sieht dann wie folgt aus: # NAMES.ORA Network Configuration File: C:\OraBase\Network\Admin\names.ora # Generated by Oracle configuration tools. NAMES.SERVER_NAME = NS1 NAMES.ADDRESSES = (ADDRESS = (PROTOCOL = TCP)(HOST = HLLAP10)(PORT = 1575))
NAMES.ADMIN_REGION = (REGION = (DESCRIPTION = (SOURCE_ROUTE = OFF) (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap10)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = O901DL1.test.hl.de) (SERVER = DEDICATED) ) ) (USERID = names) (PASSWORD = names) (NAME = LOCAL_REGION) (REFRESH = 86400) (RETRY = 60) (EXPIRE = 600) (VERSION = 134230016) ) Listing 5.24: names.ora mit Regionen
Sandini Bib
Zentrale Auflösung von Dienstnamen
383
Auffällig ist, dass die Verbindungsdaten zur Regionsdatenbank nicht über einen Dienstnamen referenziert werden, sondern direkt angegeben sind. Das ist auch gut so, da diese Daten zum Starten des Name-Servers benötigt werden, dieser aber nicht starten könnte, wenn die Namensauflösung über Oracle Names konfiguriert ist. Weiterhin sind Benutzername und Passwort unverschlüsselt in der Parameterdatei enthalten, was diese Datei zu einem beträchtlichen Sicherheitsrisiko macht. Glücklicherweise muss die Datei nicht auf Clients verteilt werden.
5.5.2
LDAP-Verzeichnis
In Kapitel 4 wurde bereits auf das Oracle Internet Directory (OID) und die Möglichkeit der Namensauflösung eingegangen. Oracle selbst bevorzugt diese Methode und empfiehlt, bestehende Oracle Names-Installationen sobald wie möglich abzulösen. Bezüglich der Betreibbarkeit einer OID-Lösung gibt es keine Nachteile gegenüber einer Oracle Names-Lösung, da Skalierbarkeit und Ausfallsicherheit über die Replikationsmöglichkeit des OID sichergestellt werden können. Der Ressourcenbedarf ist sicherlich deutlich höher als bei einer reinen Oracle Names-Lösung; allerdings bietet das OID auch einige Möglichkeiten mehr als die reine Namensauflösung. Bei der Abbildung von bestehenden Oracle Names-Installationen sind allerdings verschiedene Punkte zu beachten:
: : :
Globale Datenbank-Links können nicht vollständig abgebildet werden. Aliasnamen für Dienstnamen können nicht vergeben werden. Oracle-Clients können erst ab Release 8.1.6 auf ein LDAP-Verzeichnis zugreifen.
Die globalen Datenbank-Links müssen über interne (public oder private) Datenbank-Links nachgebildet werden. Aliasnamen können durch die Einführung eines weiteren Dienstnamens ersetzt werden. Durch beide Maßnahmen erhöht sich der Pflegeaufwand. Falls nicht alle Clients auf mindestens Release 8.1.6 umgestellt werden können, kann ein Oracle Names-Server als LDAP-Proxy konfiguriert werden, d.h., der Oracle Names-Server lädt seine Daten aus einem LDAP-Server statt aus einer Regionsdatenbank. Ein oder mehrere solcher Oracle Names-Server können für ältere Clients die Namensauflösung durchführen, alle anderen können direkt mit den LDAP-Servern arbeiten. Zur Konfiguration eines Oracle Names LDAP-Proxys wird der Parameter NAMES.ADMIN_REGION wie folgt modifiziert: NAMES.ADMIN_REGION = (REGION = (TYPE = LDAP) [(USERID=user_dn)] [(PASSWORD=password)] [(HOST=host)] [(PORT=port)] [(SUBTREE_LIST=
Sandini Bib
384
Oracle Net
[(SUBTREE=(BASE=base_DN)[(SCOPE=sub|one))] [(SUBTREE=(BASE=base_DN)[(SCOPE=sub|one))] ... )] ) Listing 5.25: names.ora für LDAP-Proxy
Wichtig ist hierbei lediglich die Zeile (TYPE = LDAP); alle weiteren Parameter zum Zugriff auf den LDAP-Server werden normalerweise aus der LDAP.ORA-Datei entnommen, d.h., der Zugriff auf den LDAP-Server muss vorher korrekt konfiguriert sein. In speziellen Fällen können die Parameter hier aber auch explizit angegeben werden.
5.6
Allgemeine Tipps
5.6.1
Verwaltung der Netzwerkkonfiguration
Neben der Ablage von Dienstnamen in Dateien, Oracle Names oder einem LDAPVerzeichnis gibt es keine Möglichkeit der zentralen Ablage von Oracle Net-Konfigurationsinformationen. Erst recht gibt es kein Werkzeug mehr mit dem Ansatz eines Network Managers (aus Oracle7): Hier wurde das Netzwerk in einem Repository abgebildet, um die Konfigurationsdateien in einem zweiten Schritt zu generieren. Nun ist es zwar einerseits so, dass für Standardkonfigurationen kaum noch Konfigurationsdateien benötigt werden; gerade für größere Umgebungen (mit Dutzenden bis Hunderten von Dienstnamen) stellt sich jedoch nach wie vor die Frage nach einer geeigneten Konfigurationsumgebung, insbesondere weil hier auch wieder alle Konfigurationsdateien benötigt werden, wenn z.B. der Enterprise Manager eingesetzt wird. Hier kann man nur mit einer Strategie erfolgreich sein, die so weit wie möglich die Konfigurationsdateien standardisiert. Zunächst sollte man versuchen, die Konfigurationsverzeichnisse zu standardisieren, so dass z.B. grundsätzlich unter /orabase/ network/admin die Oracle Net-Konfiguration zu finden ist, Log-Dateien unter /orabase/network/log usw. Somit können Inhalte auch weitgehend standardisiert werden, z.B.: LOG_DIRECTORY_LISTENER = /orabase/network/log
An zentraler Stelle (DB-Tabelle, MS-Excel o.ä.) sollte der DBA dann Übersichten über Listener-Adressen, Instanzen und ORACLE_HOME-Verzeichnisse usw. haben. Allgemein gültige Dateien wie SQLNET.ORA sollte es je nach Anforderungen nur einige wenige geben, die entsprechend verteilt werden. Falls es z.B. verschiedene SQLNET.ORA-Dateien für unterschiedliche Anwendergruppen gibt, sollte ebenfalls darüber Buch geführt werden, wer welche Version einsetzt. Zentrales Repository für alle benötigten Dateien ist entweder ein strukturiert aufgebauter Dateibaum oder auch ein Versionskontrollwerkzeug, mit dem Änderungen auch später noch nachvollzogen werden können.
Sandini Bib
Allgemeine Tipps
5.6.2
385
Ein Listener für verschiedene Versionen
Sobald sich mehrere Versionen bzw. Installationen der Oracle-Software auf einer Maschine befinden und diese auch jeweils für eine oder mehrere Instanzen zuständig sind, stellt sich die Frage, ob man für jede Instanz einen Listener braucht – oder etwa für jede Installation – oder etwa doch nur einen einzigen ... Jede der angegebenen Möglichkeiten kann implementiert werden, und es gibt sogar Argumente für jede Strategie. Sollen z.B. Rechnerressourcen strikt getrennt werden (etwa im Hosting-Umfeld), so wird zumindest ein Listener pro Installation Sinn machen. Weiterhin können z.B. Netzwerkressourcen einen Engpass darstellen, so dass eine Instanz einen eigenen Listener auf einem eigenen Interface, also einer eigenen Netzwerkkarte, bekommen könnte. Auch spezielle Listener-Parameter für einzelne Instanzen können der Grund für eine Separierung sein. Bei der Implementierung von mehreren Listenern stellt sich die zusätzliche Frage, welcher Speicherort für die Konfiguration gewählt wird. Standardmäßig würde das jeweilige $ORACLE_HOME/network/admin-Verzeichnis durchsucht werden. Das hat den Vorteil, dass die Konfigurationen in verschiedenen Dateien stehen, zumindest soweit sie unterschiedliche Installationen betreffen. Setzt man allgemein gültig die Variable $TNS_ADMIN, so müssen alle Listener in einer Datei konfiguriert werden. Der große Vorteil dieser Methode ist, dass man alle Adressinformationen – welche Ports auf welchen Netzwerk-Interfaces sind belegt? – zentral in einer Datei hat. Die Konfiguration mehrerer Listener hat jedoch noch einen gravierenden Nachteil: Es kann nur ein Listener pro Netzwerk-Interface auf Port 1521 (bzw. einem beliebigen anderen unternehmensweiten Standardport) liegen. Das heißt wiederum, dass für jede Client-Konfiguration nachgeschaut werden muss, welcher Port verwendet wird. Gerade dies bedeutet in vielen Unternehmen einen großen Zusatzaufwand: Da normalerweise bekannt ist, welches Netzwerk-Interface zu einer Instanz gehört, kann auf Verdacht – und mit großer Erfolgsquote – mit Port 1521 auf diesem Interface konfiguriert werden. Aus diesem Grund wird im Standardfall – d.h., es bestehen keine besonderen Zusatzanforderungen – empfohlen, einen Listener pro Maschine auf Port 1521 des oder der Netzwerk-Interfaces zu installieren. Dieser kennt über seine SID_LIST alle Instanzen. Damit keine Inkompatibilitäten entstehen, sollte der Listener mit der neuesten verfügbaren Oracle-Version gestartet werden.
Sandini Bib
386
5.6.3
Oracle Net
Oracle Net und Firewalls
Viele Client-Server-Konfigurationen laufen nicht ohne weiteres, wenn sich eine Firewall zwischen Client und Server befindet. Das liegt daran, dass viele Firewalls darauf aufbauen, dass nur bestimmte wohl definierte Ports auf Servermaschinen für die Kommunikation freigeschaltet werden. Hier liegt Port 1521 für den Listener nahe; allerdings reicht dies im Normalfall nicht: Der Listener ist lediglich für den Verbindungsaufbau zuständig; der von ihm erzeugte Serverprozess bekommt einen eigenen Port und kommuniziert mit dem Client ausschließlich über seinen eigenen Port. Da dieser i.A. für die Firewall nicht freigeschaltet ist, funktioniert der Verbindungsaufbau nicht. Es bieten sich zwei Lösungsmöglichkeiten an: 1. Einige Firewalls kennen das beschriebene Verhalten und schalten dynamisch die von Oracle benötigten Ports frei; teilweise können sie zusätzlich kontrollieren, dass es sich bei den versendeten Paketen um gültige Oracle Net-Pakete handelt. 2. Sowohl beim Connection Manager als auch beim Dispatcher kann der Port für die Kommunikation spezifiziert werden. Hierdurch ergibt sich die Möglichkeit, genau diese Ports in der Firewall zu konfigurieren und damit Client-Server-Kommunikation durch die Firewall zu ermöglichen.
5.7
HTTP-Server
Seit der Version 8.1.7.0.0 bietet Oracle die Möglichkeit, zusammen mit der Datenbank auch einen Apache-HTTP-Server der Version 1.3 zu installieren. Neben den im Kontext von Apache üblichen Modulen, wie z.B. dem Perl-Modul zur Interpretation von Perl-Scripts, liefert Oracle zusätzliche Funktionalitäten in Form der Module mod_ose – der Oracle Servlet Engine – und mod_plsql – dem PL/SQL-Gateway. Mit Hilfe des PL/SQL-Gateways kann der Apache-Prozess PL/SQL-Code in der Datenbank aufrufen und über diesen Code generierte HTML-Seiten ausgeben. mod_ose dagegen kanalisiert die HTTP-Anforderungen an Java Servlets und Java Server Pages, die in der Datenbank gespeichert wurden und dort im Kontext der virtuellen Java-Maschine ausgeführt werden. Die Kommunikation zwischen dem HTTP-Serverprozess und der Datenbank wird über Oracle Net realisiert. Im Falle einer mod_ose -Kommunikation werden die HTTP-Anforderungen über Oracle Net getunnelt, so dass die virtuelle Java-Maschine der Datenbank nur die HTTP-Aufrufe sieht.
Sandini Bib
HTTP-Server
387
+7736HUYHU
&OLHQW
'$'6FRWW
+773
2UDFOH 1 HW
3/64/
2UDFOH 1HW7XQQHO
6HUYOHW
Abbildung 5.21: Connects über den Oracle HTTP-Server
Die Installation dieses HTTP-Servers ist überall dort interessant und stellt eine preiswerte Alternative dar, wo die Installation eines kommerziellen Anwendungsoder Webservers aus Gründen der Skalierbarkeit und Performance nicht notwendig ist. Die folgenden Abschnitte geben eine kurze Einführung in die Installation und Konfiguration des Apache-Servers, sie werden dieses Thema jedoch in keiner Weise erschöpfend behandeln können.
5.7.1
Installation
Der Oracle HTTP-Server kann zusammen mit der Datenbank über den Universal Installer und dort über den Auswahlpunkt ORACLE HTTP-SERVER installiert werden. Im betreffenden Untermenü lassen sie die Zusatzmodule mod_ose und mod_plsql über die Punkte APACHE MODULE FOR ORACLE SERVLET ENGINE und ORACLE MOD PL/ SQL-GATEWAY getrennt auswählen. Der Installer erzeugt in diesen Fällen unter dem Oracle_Home-Verzeichnis das Verzeichnis Apache mit weiteren Unterverzeichnissen und den entsprechenden Dateien. Die Installationsprozedur lädt auch diverse HTML-Dateien zur weiterführenden Konfiguration der Oracle-Zusatzmodule sowie die SQL-Scripts zum Aufbau des Web-Toolkit in den betreffenden Zieldatenbanken. Im Anschluss an die Installation lässt sich der HTTP-Server wie folgt starten: apachectl start
Die Programmdatei apachectl liegt im Verzeichnis $ORACLE_HOME/Apache/Apache/ bin. Entsprechend stehen die Optionen stop, restart, status und fullstatus zur Verfügung. In der Windows-Welt werden darüber hinaus entsprechende Programmpunkte generiert.
Sandini Bib
388
5.7.2
Oracle Net
Konfiguration
Die Konfiguration des HTTP-Servers und seiner Zusatzmodule erfolgt – wie bei Apache üblich – über hierarchisch organisierte Konfigurationsdateien. An der Spitze dieser Hierarchie steht die Datei httpd.conf im Verzeichnis $ORACLE_HOME/Apache/Apache/conf. Das folgende Listing zeigt einige kleine Ausschnitte aus dieser Datei direkt nach einer erfolgreichen Installation: Listen 80 ServerName DATTATREYA # # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. # DocumentRoot "c:\oracle\ora901\Apache\Apache\htdocs" # # DirectoryIndex: Name of the file or files to use as a pre-written HTML # directory index. Separate multiple entries with spaces. # DirectoryIndex index.html # Include the Oracle configuration file for custom settings include "c:\oracle\ora901\Apache\Apache\conf\oracle_apache.conf" Listing 5.26: httpd.conf
Die Port-Nummer 80 ist die Standard-Pornummer für HTTP-Listener-Prozesse; der Name des Servers wird hier auf Dattatreya und das Stammverzeichnis auf das Verzeichnis c:\oracle\ora901\Apache\Apache\htdocs gesetzt; die Klausel include verweist auf die eingebettete Konfigurationsdatei mit den Erweiterungen von Oracle. Nach dem Start des HTTP-Prozesses lässt sich ein erster Funktionstest mit der folgenden, minimalen URL5 durchführen: http://dattatreya Auf Grund der oben beschriebenen Einstellungen wird über diese URL die Datei index.html im Verzeichnis c:\oracle\ora901\Apache\Apache\htdocs aufgerufen, die sich wie folgt im Browser darstellt:
5.
URL = Uniform Resource Locator; Internetadresse
Sandini Bib
HTTP-Server
389
Abbildung 5.22: Konfigurationsmenü des Oracle HTTP-Servers
Die in Abbildung 5.22 dargestellten Menüpunkte verzweigen auf die Dokumentation (APACHE), auf Demos oder entsprechende Konfigurationsmasken wie im Falle von MOD_PLSQL. Genaue Anleitungen zur Konfiguration des Moduls mod_ose lassen sich über die URL http://<servername>/mod_ose.html oder den Link MOD_OSE abrufen, wobei <servername> durch den Namen des HTTP-Servers zu ersetzen ist. PL/SQL-Gateway Im Folgenden wird kurz die Konfiguration des PL/SQL-Gateways über den Link mod_plsql beschrieben, der die unten dargestellte HTML-Seite aufruft:
Sandini Bib
390
Oracle Net
Abbildung 5.23: Konfiguration des PL/SQL-Gateways
Um PL/SQL-Code ausführen zu können, benötigt der HTTP-Server einen so genannten Database Access Descriptor – kurz DAD –, über den der Benutzername, das Passwort, der Dienstname der Zieldatenbank sowie die Authentifizierungsmethode festgelegt werden. Die entsprechende HTML-Seite wird über die Auswahl GATEWAY-EINSTELLUNGEN FÜR DEN DATABASE ACCESS DESCRIPTOR erreicht. Auf dieser Seite können sowohl neue DADs angelegt als auch bestehende angepasst werden. Für unser Beispiel wählen wir den Link STANDARD HINZUFÜGEN (KEINE KONFIGURATION) aus. Unter dem Namen SCOTT konfigurieren wir den DAD für den Benutzer scott mit dem Passwort tiger auf der Datenbank mit dem Dienstnamen dc1.world.
Sandini Bib
HTTP-Server
391
Abbildung 5.24: Konfiguration eines Database Access Descriptors.
Die in diesem Beispiel vorgenommenen Einstellungen finden Eingang in eine Oracle-spezifische Konfigurationsdatei mit Namen wdbsrv.app, die im Verzeichnis $ORACLE_HOME/Apache/modplsql/cfg liegt. Das folgende Listing zeigt einen Ausschnitt aus dieser Datei für den DAD mit Namen scott. [DAD_scott] connect_string = dc1.world password = tiger username = scott
Unglücklicherweise wird das Passwort hier, wie gezeigt, unverschlüsselt gespeichert! Dementsprechend ist diese Datei auf Ebene des Betriebssystems zu schützen. Nachdem nun der HTTP-Server konfiguriert wurde, erstellen wir ein kleine Beispielprozedur im Schema scott der Datenbank dc1.world: CREATE OR REPLACE PROCEDURE HelloWorld AS BEGIN htp.htitle('Scotts erste Webseite'); htp.print('Hello world'); htp.line; END HelloWorld; / Listing 5.27: Beispielprozedur für HTTP
Sandini Bib
392
Oracle Net
Die Ausgabe der HTML-Tags wird hier über den Aufruf entsprechender Prozeduren des Pakets htp erreicht. Dieses Paket ist Bestandteil des so genannten Web-Toolkits, das bei einer standardmässigen Installation der Datenbank im Schema Sys angelegt wird6. Entsprechende Synonyme sowie Grants an Public öffnen das Toolkit für die Allgemeinheit und sorgen in diesem Beispiel für die fehlerfreie Kompilation des PL/ SQL-Codes. Die dargestellte Prozedur HelloWord gibt den gleichnamigen Slogan mit der Titelzeile „Scotts erste Webseite“ an den Browser zurück, wenn dort die folgende URL aufgerufen wird: http://<servername>/pls/scott/helloworld Das virtuelle Verzeichnis /pls aktiviert das PL/SQL-Gateway, /scott verweist auf den DAD gleichen Namens, /helloworld schließlich ruft die Prozedur Helloworld in dem betreffenden Schema auf. Oracle Servlet Engine HTML-Seiten lassen sich auch mit Hilfe von Java-Servlets generieren. Servlets, die in der Datenbank gespeichert wurden, können über das Modul mod_ose des Oracle HTTP-Servers aufgerufen werden. Dieses Modul sorgt – im Gegensatz zum dem Apache-Modul mod_jserv, das ebenfalls Servlets einbinden kann – für den Erhalt von Session-Kontexten in der Datenbank. Die Verbindung des HTTP-Servers zu einer Datenbank ist in der Konfigurationsdatei mod_ose.conf im Verzeichnis $ORACLE_HOME/Apache/Apache/conf über den folgenden Eintrag verankert: AuroraService inst1_http mod_ose.conf ist über die Datei oracle_apache.conf in die Hauptdatei httpd.conf eingebunden. Der Name inst1_http verweist – bei lokaler Namensauflösung – auf einen gleich lautenden Eintrag in der Oracle Net-Datei tnsnames.ora, der die
Details dieser Datenbankverbindung regelt. Der Name ist selbstverständlich frei wählbar, muss aber bei Bedarf in beiden Dateien angepasst werden! inst1_http = (DESCRIPTION= (ADDRESS= (PROTOCOL=tcp)(HOST=dbconsult-server)(PORT=1521) ) (CONNECT_DATA= (SERVICE_NAME=dc1.world) (SERVER=shared) (PRESENTATION=http://dbconsult) ) ) Listing 5.28: tnsnames.ora mit HTTP-Konfiguration
6.
Der explizite Aufbau dieses Toolkits wird über das Script owacomm.sql im Verzeichnis $ORACLE_HOME/Apache/moplsql/owa gesteuert.
Sandini Bib
IIOP-Verbindungen
393
Mod_ose-Verbindungen sind nur im Kontext von Shared Servern möglich (SERVER=shared). Zur Generierung der Konfigurationsdateien stehen alternativ die Werkzeuge exportwebdomain und gencfg.pl7 zur Verfügung, die in dem Oracle-
Handbuch Oracle9i – Java Tools Reference – detailliert beschrieben werden.
5.8
IIOP-Verbindungen
5.8.1
Java in der Datenbank
Die Programmiersprache Java hat bereits seit der Version 8.1 Eingang in die OracleDatenbank gefunden. Momentan stehen unterschiedliche Kontexte oder APIs zur Verfügung, um mit Java-Objekten in der Datenbank umzugehen:
:
:
:
Java Stored Procedures und Functions können über PL/SQL-Code aufgerufen werden oder können ihrerseits PL/SQL-Code aufrufen. Die Nutzung dieser Prozeduren und Funktionen ist vollkommenen transparent für den betreffenden Benutzer, d.h., er kann den Code innerhalb einer normalen Datenbanksitzung explizit aufrufen oder – im Falle einer Funktion – im Kontext von SQL-Befehlen benutzen. Java Servlets und Java Server Pages spielen im Rahmen von HTML-Anwendungen eine Rolle und werden über entsprechende HTTP-Aufrufe ausgeführt. Wenn die Servlets und Java Server Pages nicht auf dem middle Tier, sondern, wie hier besprochen, in der Datenbank gespeichert werden, müssen die HTTPAufrufe über HTTP-Server direkt an die Datenbank weitergeleitet werden, wie im vorangehenden Abschnitt 5.7 beschrieben wurde. Durch die Unterstützung der CORBA8- und EJB9-Standards ist es möglich, JavaKomponenten in der Datenbank zu speichern und mit anderen CORBA- oder EJB-Komponenten kommunizieren zu lassen. Im Gegensatz zu Servlets und Java Server Pages kommunizieren CORBA- und EJB-Komponenten über das von der Object Management Group spezifizierte Internet Inter-ORB Protocoll, kurz IIOP. IIOP ist eine Implementierung des General Inter-ORB Protocol (GIOP) über TCP/ IP-Verbindungen. Die mögliche Speicherung dieser Komponenten in der Datenbank bringt es mit sich, dass direkte IIOP-Verbindungen im Kontext von Oracle-Datenbanken möglich sein müssen, um mit diesen Komponenten zu arbeiten.
Der folgende Abschnitt beschreibt kurz die notwendigen Schritte zur Konfiguration von IIOP-Verbindungen.
7. 8. 9.
Gencfg ist ein Perl-Script. CORBA = Common Object Request Broker Architecture, Architektur für verteilte Anwendungen mit Komponenten in unterschiedlichen Programmiersprachen EJB = Enterprise Java Beans, Architektur für verteilte Anwendungen mit Java-Komponenten
Sandini Bib
394
5.8.2
Oracle Net
IIOP-Konfiguration
Die Datenbank für IIOP-Verbindungen zu konfigurieren bedeutet im Einzelnen:
: :
Dispatcher-Prozesse zu konfigurieren sowie Für den Listener-Prozess eine separate Port-Nummer einzurichten.
Dispatcher konfigurieren IIOP-Verbindungen setzen eine Shared Server-Konfiguration der betreffenden Datenbank voraus. Sie können sowohl unverschlüsselt über das TCP-Protokoll als auch verschlüsselt – in Verbindung mit SSL – über TCPS konfiguriert werden. Während einer standardmäßigen Installation der Datenbank werden sowohl der Listener- als auch die Dispatcher-Prozesse für IIOP-Verbindungen vorbereitet. Der folgende Abschnitt zeigt einen Ausschnitt aus der Initialisierungsparameterdatei, der die Konfiguration der Dispatcher durchführt: dispatchers="(protocol=tcp)(presentation=oracle.aurora.server.SGiopServer)“
Nach dem Start der Datenbank melden sich die Dispatcher bei dem Listener-Prozess an. Listener konfigurieren Listener-Prozesse können entweder dynamisch oder statisch – durch Editieren der Konfigurationsdatei listener.ora – für den IIOP-Betrieb vorbereitet werden. Jeder Listener hat – neben der für den TCP/IP-Betrieb vorgesehenen Port-Nummer – eine separate Port-Nummer für IIOP-Anforderungen. Die dynamische Konfiguration der IIOP-Port-Nummer hat den Vorteil, dass die Datenbank nicht neu gestartet werden muss, sondern die gewünschte Nummer sofort aktiv ist. Im folgenden Beispiel wird über den Befehl regep10 die Port-Nummer 2241 auf dem Server namens Dc1 für den dortigen Listener und über ihn eintreffende IIOP-Verbindungen aktiviert: regep -pres oracle.aurora.server.SGiopServer -host dc1 -port 2241
Alternativ kann eine statische Konfiguration über die Datei listener.ora durchgeführt werden, wie der folgende Ausschnitt aus dieser Datei zeigt: listener= (description_list= (description= (address=(protocol=tcp)(host=dc1)(port=2481)) (protocol_stack= (presentation=giop)
10. Der Befehl wird auf der Ebene des Betriebssystems abgesetzt. Einzelheiten finden sich in dem Handbuch Oracle9i – Java Tools Reference.
Sandini Bib
IIOP-Verbindungen
395
(session=raw)) ) ) Listing 5.29: listener.ora für IIOP-Betrieb
Bevor nun die ersten Verbindungstests mit EJB- oder CORBA-Komponenten durchgeführt werden können, sind die Datenbankbenutzer AURORA$JIS$UTILITY$ und AURORA$ORB$UNAUTHENTICATED zu aktivieren. Diese Benutzer werden bei der Installation der Datenbank automatisch gesperrt. Die Aktivierung erfolgt beispielsweise über den folgenden Befehl: ALTER USER aurora$orb$unauthenticated ACCOUNT UNLOCK;
Potenzielle Clients können dann die Verbindung zu den Komponenten auf dem Server Dc1 und der Instanz Orcl mit der Port-Nummer über die folgende URL aufnehmen: sess_iiop://dc1/:2481/:orcl
Trifft die IIOP-Anforderung eines Clients beim Listener-Prozess ein, schickt dieser die Adresse eines geeigneten Dispatcher-Prozesses an den Object Request Broker (ORB) des Clients. Der ORB kommuniziert nun in der Folge direkt mit dem betreffenden Dispatcher der Datenbank, über den der Aufruf abgearbeitet wird.
Sandini Bib
Sandini Bib
6
Backup/Recovery
Oracle-Datenbanken sind heutzutage zunehmend die zentrale Stelle für die Speicherung unternehmensrelevanter Daten. Dabei ist nicht nur die Größe der Datenbank entscheidend, sondern auch die Wichtigkeit der abgelegten Informationen. So ist es eine der vorrangigen Aufgaben eines Datenbankadministrators, die Sicherung und die Wiederherstellbarkeit der Datenbank in einem Fehlerfall zu gewährleisten. Zwar ist es heutzutage auf Grund der stark gesunkenen Hardware-Kosten möglich, sowohl die Plattensysteme als auch die Rechner redundant auszulegen, jedoch ist dies keine Sicherung gegen logische Fehler oder den Zufall, dass mehr als eine Komponente gleichzeitig einen Defekt aufweist. In Konsequenz bedeutet das, dass der Datenbankadministrator ein Sicherungskonzept entwickeln muss, das auf die Größe der Datenbank und die maximal zulässige Ausfallzeit der Datenbank zugeschnitten ist. Zudem muss der Erfolg der Sicherung regelmäßig geprüft werden. Die Größen der Oracle-Datenbanken in der heutigen Zeit, die oft von mehreren hundert Gigabyte bis in den Tbyte-Bereich gehen, und die hohen Transaktionsraten, die Einfluss auf die Dauer der Wiederherstellung im Fehlerfall haben, stellen dabei erhöhte Anforderungen an die Konzepte der Datensicherung und die Hardware, auf die die Daten gesichert werden. In diesem Kapitel werden nun die möglichen Konzepte der Datensicherung vorgestellt.
6.1
Übersicht/Strategie
Bei der Sicherung einer Oracle-Datenbank kann zwischen der Sicherung interner Strukturen und der Sicherung externer Strukturen unterschieden werden. In Abschnitt 6.2 werden Verfahren zur Sicherung der internen Strukturen beschrieben, die aber nicht unbedingt dazu verwendet werden können, Transaktionsprotokolle nachzufahren, und daher eher als Ergänzung zu einer physikalischen Sicherung anzusehen sind. Die physikalische Sicherung von externen Strukturen, wie in Abschnitt 6.3 beschrieben, dient als Basis, um Transaktionsprotokolle in die Datenbank einzuspielen, die eine konsistente Datenbank mit allen abgeschlossenen Transaktionen bis zum Zeitpunkt der Beschädigung wiederherstellen. Das seit Oracle8 verfügbare Werkzeug Recovery Manager, Abschnitt 6.4, bietet eine Alternative zur herkömmlichen physikalischen Sicherung auf Betriebssystemebene. Ab Oracle8i bietet ein zusätzliches Werkzeug, den LogMiner, an. Dieser kann verwendet werden, um aus archivierten und Online-Redolog-Dateien Transaktionen extrahieren zu können, die dann zu Wiederherstellungen in bestimmten Fehlerfällen verwendet werden können. Diese Möglichkeiten werden in Abschnitt 6.5 vorgestellt.
Sandini Bib
398
Backup/Recovery
Abschnitt 6.6 beschäftigt sich mehr mit den Möglichkeiten, die Oracle zum Einrichten und zum Betrieb von Katastrophenfalldatenbanken anbietet. Hier sind die herkömmlichen Sicherungskonzepte nicht mehr tauglich, da für eine Wiederherstellung eine unakzeptabel lange Zeit benötigt würde. Um eine sinnvolle Strategie für die Sicherung einer Datenbank festzulegen, sind folgende Fragen zu stellen: 1. Welche Ausfallzeit des Datenbanksystems kann Ihr Unternehmen maximal akzeptieren? 2. Welche Medien stehen für die Sicherung zur Verfügung? 3. Wird das Oracle-System im 24-Stunden-Betrieb gefahren, und wenn nicht, wie viel Zeit bleibt für eine Offline-Sicherung? Die erste Frage wird oft damit beantwortet werden, dass der Ausfall nur möglichst kurz sein darf, z.B. höchstens eine Stunde. Zu berücksichtigen ist, dass in dieser Zeit die Fehleranalyse, das Festlegen eines geeigneten Wiederherstellungsverfahrens, das Zurückspielen vom Sicherungsmedium und die Wiederherstellung der Datenbank durchgeführt werden müssen. Abhängig von der Größe der Datenbank und der Transaktionslast hat diese Forderung dann Einfluss auf das Sicherungsmedium, das die geforderte Zeit für das Zurückspielen der beschädigten Komponenten gewährleisten muss. So kann es eventuell notwendig sein, auf ein schnelleres Sicherungsmedium umzusteigen, das aber entsprechend teurer ist. Hier müssen nun die Kosten, die durch einen Systemausfall entstehen, den Kosten für die Sicherungs-Hardware gegenübergestellt werden. Oftmals wird in der Praxis die Ausfallzeit, die verkraftet werden kann, dann nach oben korrigiert.
6.2
Sicherung und Wiederherstellung interner Strukturen
Die in diesem Abschnitt beschriebenen Verfahren zur Sicherung und Wiederherstellung interner Strukturen sollten nur als Ergänzung zu einem physikalischen Sicherungskonzept verstanden werden. Eine Ausnahme können hier Entwicklungsdatenbanken sein, an die keine hohen Ansprüche bezüglich der Wiederherstellungszeiten gestellt werden und deren Sicherung einen dedizierten Zeitpunkt wiederspiegeln soll.
6.2.1
Export
Export ist ein Werkzeug, das zur Datenbanksoftware gehört. Mit dem Export-Utility können logische Sicherungen der Datenbank erstellt werden, es unterstützt aber auch Migrationen zwischen Oracle-Versionen und Plattformen sowie Reorganisationen. Dabei werden neben den Daten auch die Befehle zur Erstellung der Datenbank-Objekte, wie Tablespaces, Tabellen, Indizes, Benutzer usw. in einem Oracleinternen Binär-Format in einer Exportdatei, auch Dump-Datei genannt, abgelegt. Dieses Format kann nur über das Werkzeug Import, das Gegenstück zum Export,
Sandini Bib
Sicherung und Wiederherstellung interner Strukturen
399
gelesen und verarbeitet werden, um die Strukturen und Daten wieder in eine vorhandene Datenbank einzuspielen. Export kennt vier verschiedene Granularitäten:
: : : :
FULL USER (OWNER) TABLE TABLESPACE
Die folgende Liste zeigt die Objekte, die in den verschiedenen Granularitäten exportiert werden. Die Einheit TABLESPACE ist erst mit Oracle9i eingeführt worden. Objekt
Table
Analyze Cluster
User
Full
Tablespace
X
X
X
X
X
Auditing-Informationen
X
X
X
Indizes (B*-Tree, Bitmap, domain, functional Indexes)
X
X
X
X
X
X
X
X
X
X
X
X
Analyze Table/Statistics Application Context
X
Cluster-Definitionen Spalten- und Tabellenkommentare
X
Datenbank-Links Vorgefertigte Rollen
X
Dimensionen
X
Directory-Aliasnamen Externe Tabellen (ohne Daten)
X X
X
X X
X
X
X
X
Indextypen
X
X
Java-Ressourcen und -Klassen
X
X
Foreign Function Libraries Indizes, die nicht dem Eigentümer der indizierten Tabelle gehören
X
Job Queues
X X
X
X
Daten aus geschachtelten Tabellen
X
X
X
X
Objektberechtigungen
X
X
X
X
Object-Type Definitions von Tabellen
X
X
X
X
Object-Types
X
X
Operatoren
X
X
Passworthistorie
X
Post-Instance-Aktionen und -Objekte
X
Sandini Bib
400
Objekt
Backup/Recovery
Table
Post- und Pre-Schema-prozedurale Aktionen und Objekte Post- und Pre-Table-Aktionen
X
User
Full
X
X
X
X
Private Synonyme
X
X
Prozedurale Objekte
X
X
Profile
X
Public Synonyms
X
Bedingungen der referentiellen Integrität
X
Refresh-Gruppen
X
X
X
X
Resource-Costs
X
Rollback-Segmentdefinitionen
X X
Sequenzen mit Nummern
X X
X X
Systemprivilegberechtigungen
X X
X
X
X
Snapshots, Snapshot Logs und Materialized Views Tabellen-Constraints
X
X
Rollen und Rollenberechtigungen Security Policies für Tabellen
Tablespace
X
X
Tabelleninhalte
X
X
X
X
Tabellendefinitionen
X
X
X
X
Trigger
X
X
X
Trigger anderer Benutzer
X
Benutzersichten
X
X
Stored Procedures, Funktionen und Packages von Benutzern
X
X
Tablespace-Definitionen und -Quoten
X
Benutzerdefinitionen und Proxies
X
X
Tabelle 6.1: Liste mit exportierten Objekten in den verschiedenen Modi
Welche Granularität benutzt wird und welche Objekte in der gewählten Einheit berücksichtigt werden, wird über die Parametrierung des Export-Befehls ausgewählt, ebenso, wie der Name der Exportdatei, Puffergrößen, Konsistenzanforderungen und einiges mehr. Jeder Anwender kann seine eigenen Daten, also sein Schema, exportieren. Soll ein Export eines anderen Benutzers, ein Tablespace-Export oder ein Export der gesamten Datenbank ausgeführt werden, so muss der Anwender, unter dessen Namen der Export ausgeführt wird, entsprechende Privilegien besitzen, um die fremden Objekte lesen zu können. Dazu existiert eine vorgefertigte Rolle exp_full_database.
Sandini Bib
Sicherung und Wiederherstellung interner Strukturen
401
Die Liste aller Parameter, von denen einige Standardeinstellungen haben, bekommt man durch den Aufruf: $ exp help=y
Export kann in drei verschiedenen Modi ausgeführt werden:
: : :
Interaktiv, Zeilenmodus, Verwendung einer Parameterdatei
Im interaktiven Modus werden vom Anwender Eingaben für die wichtigsten Parameter verlangt. Jedoch können hier nicht alle möglichen Parameter spezifiziert werden. Im Zeilenmodus werden die Parameter positionell oder, was üblicher ist, über die Parameternamen direkt beim Aufruf eingegeben. $ exp system file=export_full_04112001.dmp full=y consistent=y
Besonders für wiederkehrende Exports empfiehlt sich die Verwendung einer Parameterdatei. Dazu werden die Parameter in eine Datei geschrieben, die dann beim Exportaufruf als parfile spezifiziert wird. $ exp parfile=parameterdatei.par
Die Exportparameter im einzelnen (Defaulteinstellungen in Klammern): USERID
Benutzername/Kennwort
BUFFER
Größe des Datenpuffers
FILE
Ausgabedateien (expdat.dmp)
COMPRESS
Import in einen Extent (Y)
GRANTS
Berechtigungen exportieren (Y)
INDEXES
Indizes exportieren (Y)
DIRECT
direkter Pfad (N)
LOG
Log-Datei der Bildschirmausgabe
ROWS
Datenzeilen exportieren (Y)
CONSISTENT
Kreuztabellenkonsistenz
FULL
Export der gesamten Datei (N)
OWNER
Liste der Eigentümerbenutzernamen
TABLES
Liste mit Tabellennamen
RECORDLENGTH
Länge des I/O-Datensatzes
INCTYPE
Inkrementeller Exporttyp
RECORD
Inkr. Export überwachen (Y)
TRIGGERS
Trigger exportieren (Y)
Sandini Bib
402
Backup/Recovery
STATISTICS
Objekte analysieren (ESTIMATE)
PARFILE
Parameterdateiname
CONSTRAINTS
Constraints exportieren (Y)
FEEDBACK
Fortschritt alle x Zeilen (0) anzeigen
FILESIZE
Max. Größe jeder Dump-Datei
FLASHBACK_SCN
Export mit Flashback-Query auf eine best. SCN
FLASHBACK_TIME
Zeit, bis SCN am nächsten bei der angegebenen Zeit liegt, über Flashback-Query
QUERY
Select-Klausel für das Exportieren einer Teilmenge einer Tabelle
RESUMABLE
Unterbrechen, wenn ein platzbezogener Fehler auftritt (N)
RESUMABLE_NAME
Textfolge zur Identifizierung einer wiederaufnehmbaren Anweisung
RESUMABLE_TIMEOUT
Wartezeit für RESUMABLE
TTS_FULL_CHECK
Vollständige oder teilweise Abhängigkeitsprüfung für TTS durchführen
TABLESPACES
Liste mit zu exportierenden Tablespaces
TRANSPORT_TABLESPACE
portable Tablespace-Metadaten exportieren (N)
TEMPLATE
Vorlagenname, der Export im iAS-Modus aufruft
Tabelle 6.2: Exportparameter
Einige wichtige Parameter sollen an dieser Stelle noch erklärt werden: COMPRESS
Dieser Parameter (Standardeinstellung YES) bewirkt, dass der Initial Extent der zu exportierenden Tabelle abhängig vom Füllgrad der jetzigen Tabelle neu berechnet wird. Der ungefähre Wert ergibt sich aus der Summe der zur Zeit allokierten Extents. Das bedeutet, dass beim Import ein einzelnes Extent mit der Gesamtgröße der jetzigen Tabelle angelegt wird. Dies kann bei großen Tabellen zu Problemen führen, weil z.B. eine einzelne Datendatei nicht ausreichend Platz bietet. Es ist anzuraten, den Platzbedarf unter zur Hilfenahme der Tabellenstatistiken zu ermitteln, die Tabelle dann von Hand mit den geeigneten Storage-Parametern anzulegen und in diese die Daten zu importieren. CONSISTENT
Bei einem Export, der bei laufendem Oracle-System ausgeführt wird, werden einzelne Tabellen lesekonsistent exportiert. Sobald Tabellen in logischer Beziehung stehen, können diese durch Angabe des Parameters consistent=y innerhalb einer Lesetransaktion konsistent exportiert werden. Die Anforderungen an die RollbackSegmente können bei lange laufenden Exports und gleichzeitig hoher Transaktionslast auf dem System entsprechend groß sein. Es besteht die Gefahr eines ORA-01555: Snapshot too old.
Sandini Bib
Sicherung und Wiederherstellung interner Strukturen
403
TABLES
Mit diesem Parameter können einzelne Tabellen für den Export spezifiziert werden, aber auch einzelne Tabellenpartitionen. Beispiel: tables=(herrmann.auftraege:part_2) QUERY
Ab Oracle8i ist es möglich, für den Export einer oder mehrerer Tabellen eine WHERE-Klausel zu spezifizieren, um nur eine eingeschränkte Menge der Daten zu exportieren. $ exp scott/tiger file=exp_121101.dmp tables=(emp,dept) query=”where deptno=20”
Die WHERE-Klausel wird in doppelte Hochkommata eingeschlossen, da Leerzeichen innerhalb der Klausel auftreten. Folgende Einschränkungen existieren für den Parameter QUERY: 1. QUERY kann nur für die Granularität von Tabellen angegeben werden, 2. Die Einschränkung muss auf alle spezifizierten Tabellen anwendbar sein, 3. QUERY kann nicht für den direkten Pfad angegeben werden, 4. Tabellen mit geschachtelten Tabellen können nicht eingeschränkt werden, 5. Aus der Exportdatei ist nicht ersichtlich, ob der Export mit Einschränkungen über QUERY ausgeführt wurde. Direkter Pfad Beim Direct Path-Export wird aus dem Buffer-Cache direkt in die Exportdatei geschrieben. Der Puffer für die Auswertung der Blöcke wird umgangen, wodurch der direkte Pfad des Exports signifikante Verbesserungen der Performance bringt. Die unter Oracle-Version 7.3 existierenden Einschränkungen, dass keine Objekte und LOBs über den direkten Pfad exportiert werden konnten, existieren seit Oracle8i Release2 (8.1.6) nicht mehr. Wie groß die Performance-Vorteile sind, ist von der Datenbankblockgröße und der IO-Bandbreite abhängig. Zum Tuning kann nicht, wie beim normalen Pfad des Exports, der Parameter BUFFER verwendet werden, sondern es muss mit dem Parameter RECORDLENGTH gearbeitet werden. Dieser sollte ein Vielfaches der Datenbankblockgröße und ein Vielfaches der Betriebssystem-I/O-Größe sein. Das Ergebnis eines Exports ist also eine logische Sicherung der internen Strukturen der gesamten Datenbank oder von Objekten aus ausgesuchten Bereichen. Diese logische Sicherung kann gesamt oder partiell mit dem Importwerkzeug in eine Oracle-Datenbank zurückgespielt werden, eine Wiederherstellung aller nach dem Export erfolgter Transaktionen über die Redolog-Dateien kann jedoch nicht angeschlossen werden.
Sandini Bib
404
Backup/Recovery
Komprimieren von Exportdateien Als problematisch erweist sich oftmals die Größe der Exportdatei. Bei manchen Betriebssystemen ist die Maximalgröße auf 2 Gbyte beschränkt, wodurch sich große Tabellen nicht mehr exportieren lassen. Aber selbst wenn diese Beschränkung nicht gilt, stellt sich oftmals die Frage, ob es möglich ist, die Exportdatei während des Exportierens zu komprimieren, um Zeit und Platz zu sparen. Unter dem Betriebssytem Unix kann dies über sog. Named Pipes realisiert werden. Mit dieser Methode ist es möglich, vom Export aus in die Pipe zu schreiben und mit einem Compress-Befehl aus dieser zu lesen. $ /sbin/mknod /tmp/exp_pipe p $ exp demo/demo compress=n tables=kunden file=/log/exp_pipe > export.log 2>&1 & $ cat /log/exp_pipe | gzip -c > /log/exp_user.ora & Listing 6.1: Komprimieren von Exportdateien
6.2.2
Import
Import kann Exportdateien lesen und logisch gesicherte Datenbankstrukturen und -objekte wiederherstellen. Genau wie Export kann Import im interaktiven Modus, im Zeilenmodus oder mit einer Parameterdatei betrieben werden. Auch hier werden im interaktiven Modus nur die wichtigsten Parameter angeboten. Wollen Sie spezielle Parameter spezifizieren, so müssen Sie den Zeilenmodus oder die Parameterdatei nutzen. USERID
Benutzername/Kennwort
BUFFER
Größe des Datenpuffers
FILE
Eingabedateien (expdat.dmp)
SHOW
Nur Dateiinhalt auflisten (N)
IGNORE
Erstellen-Fehler ignorieren (N)
GRANTS
Berechtigungen importieren (Y)
INDEXES
Indizes importieren (Y)
ROWS
Datenzeilen importieren (Y)
LOG
Log-Datei mit Bildschirmausgabe
FULL
Import der gesamten Export-Datei (N)
FROMUSER
Liste der Schemanamen der exportierten Objekte
TOUSER
Liste der Schemanamen, in die importiert werden soll
TABLES
Liste der Tabellennamen
RECORDLENGTH
Länge des I/ODatensatzes
INCTYPE
Inkrementeller Importtyp
Sandini Bib
Sicherung und Wiederherstellung interner Strukturen
405
COMMIT
Array-Einfügen bestätigen (N)
PARFILE
Parameterdateiname
CONSTRAINTS
Import-Constraints (Y)
DESTROY
Tablespace-Datendatei überschreiben (N)
INDEXFILE
Tabellen-/Indexinfo in angegebene Datei schreiben
SKIP_UNUSABLE_INDEXES
Verwaltung von nicht benutzbaren Indizes überspringen (N)
FEEDBACK
Fortschritt alle x Zeilen (0) anzeigen
TOID_NOVALIDATE
Validierung von angegebenen Typ-IDs überspringen
FILESIZE
Max. Größe von jeder Dump-Datei
STATISTICS
Im Voraus berechnete Statistiken importieren (immer)
RESUMABLE
Unterbrechen, wenn ein platzbezogener Fehler auftritt (N)
RESUMABLE_NAME
Textfolge zur Identifizierung von wiederaufnehmbarer Anweisung
RESUMABLE_TIMEOUT
Wartezeit für RESUMABLE
COMPILE
Prozeduren, Packages und Funktionen kompilieren (Y)
Parameter für portable Tablespaces TRANSPORT_TABLESPACE
portable Tablespace-Metadaten importieren (N)
TABLESPACES
In Datenbank portable Tablespaces
DATAFILES
In Datenbank portable Datendateien
TTS_OWNERS
Benutzer mit Daten in der portablen Tablespace-Gruppe
Auch hier seien wieder einige wichtige Parameter gesondert erläutert. IGNORE
Import erwartet, dass die zu importierenden Objekte, insbesondere Tabellen, nicht in der Zieldatenbank existieren. Folgt man jedoch dem Ratschlag, bei einer Reorganisation Tabellen vorher mit passenden Speicherplatzparametern anzulegen, so muss dem Importprozess mitgeteilt werden, dass die existierenden Objekte benutzt und Fehlermeldungen, die sich auf das Vorhandensein des Objekts beziehen, ignoriert werden sollen. FULL
Im Kontext des Imports bedeutet FULL, dass alle Objekte aus der angegebenen Exportdatei importiert werden sollen. FROMUSER/TOUSER
Über FROMUSER/TOUSER können Datenbankobjekte zwischen Schemas bewegt werden. Mit FROMUSER wird angegeben, unter welchem Schema die Objekte in der Exportdatei liegen, mit TOUSER, in welches Schema sie in die Zieldatenbank geschrieben werden sollen. Dazu sind entsprechende Privilegien des Prozesses nötig, der den Import ausführt. Anzuraten ist, solche Aktivitäten als DBA-Benutzer zu starten. Exports, die von einem DBA durchgeführt wurden, können auch nur
Sandini Bib
406
Backup/Recovery
von einem DBA wieder importiert werden. FROMUSER kann auch dazu verwendet werden, aus einem FULL-Export nur Objekte eines Schemas selektiv zu importieren. TABLES
Mit TABLES=(t1,t2,t3…) kann eine einzelne Tabelle, eine Liste von Tabellen oder Partitionen von Tabellen angegeben werden, die dann selektiv aus der Exportdatei gelesen werden. COMMIT
Import führt einen COMMIT-Befehl nach erfolgtem Import aller Daten einer Tabelle aus, was bei großen Tabellen zu extremen Anforderungen an die Rollback-Segmente der Zieldatenbank führen kann. Über die Einstellung commit=y wird ein Commit-Befehl nach jedem Puffer, dessen Größe über buffer=nnnnn eingestellt werden kann, ausgeführt. INDEXFILE
Mit dem Befehl: imp un/pw file=expdat.dmp indexfile=create_index.sql
können Sie aus einer bestehenden Exportdatei ein SQL-Script generieren lassen, das Befehle zum Anlegen der Indizes beinhaltet, die durch den Import erzeugt würden. Auch sämtliche Befehle zum Anlegen der Tabellen werden in die angegebene Datei geschrieben, sind jedoch als Kommentar gekennzeichnet. Sinn dieser Scripts ist es, den Import ohne Indizes durchführen zu können und diese dann später mit einer speziell definierten sort_area_size, eventuell auch parallelisiert, anlegen zu können. Indizes, die über einen Primary Key Constraint definiert worden sind, werden hier allerdings nicht berücksichtigt, da diese in der Exportdatei als Constraint-Definitionen, nicht aber als Index-Definitionen abgelegt sind. Es ist so aber auch eine elegante Möglichkeit geboten, Scripts für den Neuaufbau einer Datenbank zu generieren und diese mit eventuell vorhandenen Scripts abzugleichen.
6.2.3
Export/Import – National Language Support und Kompatibilität
Export und Import werten die Umgebungsvariable NLS_LANG aus und unterstützen so Zeichensatzkonvertierungen zwischen verschiedenen Datenbanken. Das bedeutet aber auch, dass unbedingt darauf geachtet werden muss, dass die Einstellungen vor Start des Exports korrekt sind. Ist zum Beispiel ein 7-Bit Zeichensatz (bei nicht gesetztem NLS_LANG ist US7ASCII voreingestellt) spezifiziert, werden beim Export sämtlich Umlaute, die in den zu exportierenden Objekten gespeichert sind, konvertiert und verschwinden. Der Zeichensatz, der beim Export verwendet wird, ist in der Exportdatei abgelegt. Import interpretiert dann den Zeichensatz aus der Exportdatei und führt entsprechende Konvertierungen durch.
Sandini Bib
Sicherung und Wiederherstellung interner Strukturen
407
CHARSET
Export/Import unterstützt die Migration zwischen Oracle-Versionen. So kann Import von Oracle8i oder Oracle9i Exports von Oracle-Version 5 und Oracle-Version 6 lesen. Da bei diesen Versionen noch keine Zeichensatzkonvertierung implementiert war, fehlen die Informationen über die Zeichensätze in den Exportdateien. Aus Kompatibilitätsgründen kann der Zeichensatz der Exportdatei über den Parameter charset (z.B. charset=WE8DEC) bekannt gemacht werden. In Abschnitt 6.3.5 ist der Fall des Benutzerfehlers beschrieben, der über die Wiederherstellung von z.B. gelöschten Tabellen durch einen Import behoben werden kann. Hier soll aber nochmals deutlich darauf hingewiesen werden, dass ein Export immer nur eine Ergänzung zur physischen Sicherung sein kann. Der Datenbankadministrator übernimmt beim Import einer einzelnen Tabelle die Gewähr für die logische Konsistenz der Datenbank. Auch wenn mit einer Tabelle Constraints verbunden sind, lassen sich diese beim Import ausschalten. Export/Import über Unix-Pipes Gerade bei der Migration von Datenbanken oder der Umstellung der Hardware auf einen neuen Anbieter stellt sich die Frage, wie die gesamte Anwendung übertragen werden kann. Ein Export in eine Datei scheidet oftmals wegen der Größe der Datenbank aus, so dass nur eine direkte Übertragung der Daten in Betracht gezogen werden kann. Hier kann man unter Unix auf die sog. Named Pipes zurückgreifen, die sich vom Betriebssystem wie normale Dateien ansprechen lassen und somit zwei unterschiedlichen Prozessen ermöglichen, in die Pipe zu schreiben bzw. aus ihr zu lesen. Ein Export/Import kann über dieses Hilfsmittel wie folgt realisiert werden. $ /sbin/mknod /tmp/exp_pipe p $ rsh hlsun1 -l oracle "/usr/sbin/mknod /tmp/exp_pipe p" $ cat /tmp/exp_pipe | rsh hlsun1 -l oracle "cat > /tmp/exp_pipe" & $ exp system/manager file=/tmp/exp_pipe parfile=exp.par & $ rsh hlsun1 -l oracle "imp system/manager file=/tmp/exp_pipe parfile=/tmp/imp.par log=/tmp/imp.log" Listing 6.2: Export/Import über Unix-Pipes
6.2.4
Flat File Unload
Eine weitere Möglichkeit zur Sicherung von Daten, die in einer Oracle-Datenbank gespeichert sind, ist das Entladen dieser Daten in eine Textdatei. Es existiert kein gesondertes Werkzeug für das Entladen von Daten, sondern es wird vielmehr SQL*Plus mit einem entsprechenden SPOOL-Kommando verwendet.
Sandini Bib
408
Backup/Recovery
Diese Daten können dann mit dem nachfolgend vorgestellten SQL*Loader wieder in eine Tabelle in der Datenbank geladen werden, wobei hier ein besonders schneller Weg über den direkten Pfad des SQL*Loader zur Verfügung steht.
6.2.5
SQL*Loader
Der SQL*Loader ist ein komplexes Werkzeug, das es ermöglicht, Inhalte aus externen Textdateien in eine Oracle-Tabelle zu laden. Dabei werden fixe und variable Satzlängen in der Textdatei genauso unterstützt wie physikalische oder logische Sätze. Um die Textdatei zu spezifizieren und Daten in der Textdatei auf Felder von Datenbanktabellen abzubilden, müssen so genannte Kontrolldateien erstellt werden. Die Syntax der Kontrolldateien erlaubt weiterhin den Ausschluss von Datensätzen und die Angabe von Fehlerdateien, in die nicht geladene Sätze geschrieben werden. Auf Grund der Informationen in den Kontrolldateien werden SQL-Insert-Befehle generiert, die an das Oracle-System geschickt werden. Das INSERT wird genauso behandelt, als wenn es aus einer Anwendung käme, hier ist eben der SQL*Loader die Anwendung. Das heißt, dass die Daten über den Database Buffer Cache, mit Transaktionssicherung über Rollback-Segmente und Redolog-Dateien, mit der Möglichkeit der Nutzung von SQL-Funktionen und definierbaren Commit-Intervallen in Tabellen geschrieben werden. Zusätzlich wird ein direkter Pfad angeboten, der sich über die Oracle-Instanz nur Informationen über freie Blöcke holt und dann die Daten direkt in diese freien Blöcke schreibt, ohne über die SGA zu gehen. In diesem Fall sind keine SQL-Funktionen nutzbar. Trigger auf Tabellen, in die Daten geladen werden, werden nicht mehr unterstützt, bis auf wenige Ausnahmen. Die komplette Beschreibung des SQL*Loader-Werkzeuges ist in der Dokumentation Oracle9i Database Utilities, Part II zu finden. In der Dokumentation werden Fallstudien erläutert. Zu diesen Fallstudien sind im Verzeichnis $ORACLE_HOME/rdbms/ demo die beschriebenen Kontrolldateien und die Textdateien zu finden (ulcase1 bis ulcase9). Diese Beispiele decken die meisten Anforderungen aus der Praxis ab und können so hervorragend als Vorlage genutzt werden. So sind dann nur noch Namen und Felddefinitionen anzupassen. Beispiel: ulcase2.dat 7782 7839 7934 7566 7499 7654 7658
CLARK KING MILLER JONES ALLEN MARTIN CHAN
MANAGER PRESIDENT CLERK MANAGER SALESMAN SALESMAN ANALYST
7839 2572.50 10 5500.00 10 7782 920.00 10 7839 3123.75 20 7698 1600.00 300.00 30 7698 1312.50 1400.00 30 7566 3450.00 20
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
409
ulcase2.ctl LOAD DATA INFILE 'ulcase2.dat' INTO TABLE EMP ( EMPNO POSITION(01:04) ENAME POSITION(06:15) JOB POSITION(17:25) MGR POSITION(27:30) SAL POSITION(32:39) COMM POSITION(41:48) DEPTNO POSITION(50:51)
INTEGER CHAR, CHAR, INTEGER DECIMAL DECIMAL INTEGER
EXTERNAL,
EXTERNAL, EXTERNAL, EXTERNAL, EXTERNAL)
Der Aufruf erfolgt mit dem Kommando $ sqlldr scott/tiger control=ulcase2.ctl
6.3
Sicherung und Wiederherstellung externer Strukturen
Die Möglichkeiten der Wiederherstellung einer Datenbank im Fehlerfall richten sich nach den Vorbereitungen, die auf Instanz- und Datenbankebene getroffen wurden. Ziel ist es normalerweise, eine komplette Wiederherstellung der Datenbank zu gewährleisten. Nur in Ausnahmefällen ist ein Point-In-Time-Recovery gewünscht. Das Zurücksetzen auf den Stand der letzten Sicherung ist gerade bei Produktionsdatenbanken oft nicht ausreichend. Die folgenden zwei Unterpunkte 6.3.1 und 6.3.2 beleuchten die vorbereitenden Maßnahmen auf Datenbankebene, die eine vollständige oder teilweise Wiederherstellung der Datenbank ermöglichen. Unter 6.3.3 und 6.3.4 werden Offline- und Online-Sicherungen behandelt. Darunter sind die Verfahren zur physikalischen Sicherung der externen Strukturen mit Betriebssystemmitteln zu verstehen. Seit Oracle8 liefert Oracle den Recovery Manager aus, ein eigenes Werkzeug zur Sicherung von Datenbanken, das in Abschnitt 6.4 auf Grund seiner Komplexität gesondert behandelt wird.
6.3.1
Archivierungsmodus
Datenbankbetrieb ohne Archivierung Redolog-Dateien beinhalten Protokollinformationen der Transaktionen, die benötigt werden, um z.B. nach einem durch einen Stromausfall bedingten Systemausfall ein Instance-Recovery durchzuführen. Sind alle verfügbaren Gruppen von Redolog-Dateien gefüllt, so wird auf die erste Gruppe zurückgeschaltet, und die dort abgelegten Transaktionsprotokolle werden überschrieben. So entsteht dann eine Lücke zwischen der letzten Sicherung der Datenbank und den aktuellen Transaktionsprotokollen.
Sandini Bib
410
Backup/Recovery
Abbildung 6.1: Archivierungslücke
Eine Datenbank, die nicht im Archivierungsmodus betrieben wird, kann also nur den Fehlerfall des „Instance-Crash“ abdecken. Tritt ein Platten-Crash auf, kann die Datenbank nur auf den Stand der letzten Sicherung zurückgesetzt werden, eine Wiederherstellung der Transaktionen nach dieser Sicherung ist nicht möglich. Das bedeutet, dass die Arbeit eines Tages – abhängig von der Frequenz der Sicherungen vielleicht sogar mehr – verloren ist. Datenbankbetrieb mit Archivierung Für Produktionsdatenbanken, insbesondere wenn sie im 24-Stunden-Betrieb gefahren werden, ist der Archivierungsmodus zwingend. Durch den Archivierungsmodus der Datenbank wird sichergestellt, dass eine Redolog-Datei erst dann wieder überschrieben werden kann, wenn ein Prozess die Inhalte dieser Protokolldatei vollständig auf ein Ziel für eine Archivierung geschrieben hat. Diese Aufgabe wird in der Praxis automatisiert, indem die Oracle-Instanz mit einem Archivierungsprozess gestartet wird. In Kapitel 3.8 wurden bereits die Parameter, die für eine automatische Archivierung genutzt werden (automatischer Start, Zielverzeichnis, Format der Dateinamen), beschrieben. Da der Archivierungsmodus eine Eigenschaft der Datenbank ist, wird dieser in die Kontrolldatei(en) eingetragen. Um einen Konsistenzzeitpunkt zu haben, an dem die Archivierung startet, ist es zum Einschalten des Archivierungsmodus notwendig, das Oracle-System erst konsistent zu stoppen und dann in den MOUNT-Status hochzufahren, in dem die Kontrolldateien, in die der Eintrag gemacht wird, ja geöffnet sind. SQL> shutdown [normal | immediate | transactional] SQL> startup mount SQL> alter database archivelog; SQL> alter database open; Listing 6.3: Einschalten archiving
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
411
Die Datenbank kann dann wieder geöffnet werden. Es empfiehlt sich, sofort eine Sicherung der Datenbank durchzuführen. Nach dieser Sicherung kann dann der aktuelle Stand der Datenbank nach einem Plattendefekt wiederhergestellt werden. Eine Datenbank, die mit shutdown abort gestoppt wurde, kann nicht in den Archivierungsmodus gesetzt werden, da der Konsistenzzeitpunkt fehlt. Der Versuch wird mit einer Fehlermeldung abgelehnt. SQL> shutdown abort ORACLE-Instanz heruntergefahren. SQL> startup mount ORACLE-Instanz hochgefahren. Total System Global Area 118255568 bytes Fixed Size 282576 bytes Variable Size 83886080 bytes Database Buffers 33554432 bytes Redo Buffers 532480 bytes Datenbank mit MOUNT angeschlossen. SQL> alter database archivelog; alter database archivelog * FEHLER in Zeile 1: ORA-00265: Instance-Wiederherstellung erforderlich. ARCHIVELOG-Modus nicht aktivierbar
Überwachung des Archivierungsmodus Um die Einstellung des Archivierungsmodus zu überwachen, haben Sie zwei Möglichkeiten. 1. Für den folgenden Befehl müssen Sie als SYSDBA angemeldet sein: SQL> archive log list Datenbank-Log-Modus Automatische Archivierung Archivierungsziel Älteste Online-Log-Sequenz Nächste zu archivierende Log-Sequenz Aktuelle Log-Sequenz
Archive-Modus Aktiviert g:\o9iarch 12 14 14
2. Für die Abfrage aus der Tabelle v$database reicht eine Anmeldung mit einem privilegierten Benutzer. SQL> select log_mode from v$database; LOG_MODE -----------ARCHIVELOG
Sandini Bib
412
Backup/Recovery
Es sei hier nochmals darauf hingewiesen, dass die automatische Archivierung durch den ARCn-Prozess eine Eigenschaft der Oracle-Instanz ist und demnach über den Initialisierungsparameter log_archive_start = true parametriert werden muss. Vergessen Sie diese Parametrierung bei eingeschaltetem Archivierungsmodus (ALTER DATABASE ARCHIVELOG) der Datenbank und starten den ARCn-Prozess nicht manuell, wird das Oracle-System stehen bleiben, wenn auf die erste noch nicht archivierte Redolog-Datei zurückgeschaltet werden soll. Zudem ist es Aufgabe des Datenbankadministrators, den Füllgrad der Platte zu überwachen, auf der die archivierten Redolog-Dateien liegen. Kann der ARCn-Prozess auf Grund fehlenden Platzes nicht mehr archivieren, können keine Transaktionen mehr ausgeführt werden, da die Online-Redolog-Dateien nicht mehr zum Überschreiben freigegeben werden. Informationen über die archivierten Redolog-Dateien sind in folgenden v$-Views zu finden: v$log
Aus dieser Liste ist ersichtlich, ob eine Redolog-Datei bereits archiviert wurde (arc = archived). SQL> SELECT group#,archived,status FROM v$log; GROUP# ---------1 2 3
ARC --NO YES NO
STATUS ---------------CURRENT INACTIVE ACTIVE
v$loghist / v$log_history Listing 6.4: v$log
Diese Views geben Auskunft darüber, welche Transaktionsnummern in welcher archivierten Redolog-Datei zu finden sind und wann diese das erste Mal beschrieben wurde. Hier wird nicht auf Namen, sondern auf Log Sequence Numbers (in Verbindung mit einer Thread Number, wichtig bei Real Application Cluster bzw. Oracle Parallel Server Konfigurationen) referenziert. SQL> SELECT sequence#, first_change#, first_time FROM v$log_history; SEQUENCE# FIRST_CHANGE# FIRST_TIME ---------- ------------- ------------------1 1 28.09.2001 10:46:43 2 37255 28.09.2001 10:55:46 3 57272 28.09.2001 11:04:35 4 108153 28.09.2001 11:09:18 5 128105 28.09.2001 11:14:49 6 168144 28.09.2001 11:25:11
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
7 8 9 10 11 12 13 14 15
177952 211727 231987 252285 272467 292842 313492 313885 314114
28.09.2001 01.10.2001 02.10.2001 04.10.2001 05.10.2001 06.10.2001 08.10.2001 08.10.2001 09.10.2001
413
11:32:01 11:04:53 13:19:28 08:23:04 09:14:09 13:10:51 17:01:49 17:41:23 10:30:13
Listing 6.5: v$log_history
Vorsicht! Diese Liste wird auch gepflegt, wenn keine Archivierung eingeschaltet ist. Hier wird nur eine Historie der Redolog-Wechsel mit entsprechenden Informationen angezeigt. v$archived_log
Hier sind die ausführlichsten Informationen über tatsächlich archivierte RedologDateien zu finden. Neben den vorher erwähnten Nummern sind hier auch die Namen und die Größen in Blöcken abzulesen. SQL> COLUMN name FORMAT a22 SQL> SELECT sequence#, name, blocks, block_size FROM v$archived_log; SEQUENCE# ---------13 14
NAME BLOCKS BLOCK_SIZE ---------------------- ---------- ---------G:\O9IARCH\ARCH13.ARCH 251 512 G:\O9IARCH\ARCH14.ARCH 227 512
Listing 6.6: v$archived_log
6.3.2
Physikalische Verteilung der Datenbankkomponenten
Zweiter Schritt der Vorbereitung für eine erfolgreiche Wiederherstellung einer Datenbank nach einem Plattendefekt ist eine Verteilung der Datenbankkomponenten auf unterschiedliche Platten. Geht eine Datendatei verloren, so werden neben der lesbaren Sicherung der betroffenen Dateien folgende Komponenten für eine vollständige Wiederherstellung benötigt: 1. eine zum Zeitpunkt des Plattenfehlers aktuelle Kontrolldatei, 2. die lückenlose Kette aller archivierter Redolog-Dateien seit der verwendeten Sicherung der betroffenen Dateien, 3. die zum Zeitpunkt des Plattenfehlers aktiven Online-Redolog-Dateien, die noch nicht archiviert wurden. Aus diesen Forderungen ergibt sich folgende Verteilung der Komponenten auf unterschiedliche Platten:
Sandini Bib
414
Backup/Recovery
1. Kontrolldateien sollten gespiegelt auf anderen Platten als die Datendateien liegen, 2. Die Redolog-Dateien sollten gespiegelt sein und ebenfalls auf anderen Platten als die Datendateien liegen, 3. Für die archivierten Redolog-Dateien sollte eine separate Platte vorgesehen werden. Daraus ergibt sich ohne jegliche Betrachtung der Performance in Hinblick auf IOVerteilung eine Minimalforderung an Platten für eine Oracle-Datenbank:
:
: : :
Festplatte 1: SYSTEM-Tablespace ROLLBACK-Tablespace TEMP-Tablespace DATEN-Tablespace INDEX-Tablespace Festplatte 2: Controlfile1 Redolog Group 1 Member 1 Redolog Group 2 member 1 Festplatte 3: Controlfile2 Redolog Group 1 Member 1 Redolog Group 2 member 1 Festplatte 4 Archivierte Redolog-Dateien
6.3.3
Offline-Sicherung
Die Offline-Sicherung einer Oracle-Datenbank wird auch als konsistente Sicherung bezeichnet. Wie der Name schon sagt, muss die Datenbank zum Zeitpunkt der Sicherung geschlossen sein, was bedeutet, dass zu dieser Zeit kein Zugriff möglich ist. Zur Offline-Sicherung gehören alle Dateien der Datenbank, also Kontrolldateien, Redolog-Dateien und sämtliche Datendateien. Eine Liste dieser Dateien kann aus Informationen im Data Dictionary abgerufen werden. SQL> SELECT name FROM v$controlfile; SQL> SELECT member FROM v$logfile; SQL> SELECT name FROM v$datafile;
Diese Liste sollte im Rahmen der Sicherungsprozedur jeweils vor dem Stoppen des Oracle-Systems als Input für den Sicherungsbefehl generiert werden, um sicherzustellen, dass, wenn eine physikalische Komponente zur Datenbank hinzugefügt wurde, diese auch berücksichtigt wird, ohne sie in das Script zur Sicherung explizit eintragen zu müssen. Das gilt natürlich auch für Namensänderungen oder eine veränderte Pfadangabe.
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
415
Die Datenbank muss also zu Beginn der Sicherung konsistent geschlossen werden. Dazu verwenden Sie das Kommando shutdown mit den Parametern normal, immediate oder transactional. Von der Verwendung des Parameters abort wird abgeraten, da im Falle der Verwendung der Sicherung ein Instance-Recovery notwendig wäre. Das wiederum kann bei einem Verlust der Redolog-Dateien auf dem Sicherungsmedium zu weiteren Problemen führen. Danach werden auf Betriebssystemebene alle Dateien, die zur Datenbank gehören, physikalisch gesichert. Dazu können diverse Möglichkeiten der unterschiedlichen Betriebssysteme genutzt werden. Unter Unix kann ein einfaches cp genauso wie ein cpio oder tar verwendet werden, für Raw Devices muss dd benutzt werden. Bei Microsoft Windows NT/ MS-Windows 2000 können copy, backup oder andere Werkzeuge wie Arcserve, Arkaia oder andere verwendet werden. Unix: $ cp /disk1/oracle/test/daten/system01.dbf /backupdisk/oracle/test/system01.dbf
MS-Windows: C:\> copy d:\oracle\test\daten\system01.dbf e:\oracle\test\backup\system01.dbf
Nachdem alle Dateien kopiert sind, wird das Oracle-System wieder gestartet. Diese Sicherung kann als definierter Stand z.B. nach einem Platten-Crash zurückgespielt werden. Unter der Voraussetzung, dass die Datenbank im Archivierungsmodus betrieben wird, kann eine Wiederherstellung auf dieser Basis gestartet werden. Die Wiederherstellung der Datenbank wird aber ausführlich im Abschnitt 6.3.5 behandelt.
6.3.4
Online-Sicherung
Die Variante der Offline-Sicherung scheidet den Fällen aus, in denen entweder ein 24-Stunden-Betrieb des Oracle-Systems gefordert wird, oder aber die Größe der Datenbank eine Offline-Sicherung im zur Verfügung stehenden Zeitfenster nicht erlaubt. Eine Oracle-Datenbank kann jedoch auch im laufenden Betrieb ohne Einschränkungen für die Anwender gesichert werden. Da in diesem Fall geöffnete Dateien gesichert werden, die weiterhin im Zugriff der Database Writer-Prozesse stehen und beschrieben werden, wird auch von einem „inkonsistenten Backup“ gesprochen. Die Skepsis, die diesem Verfahren immer noch entgegengebracht wird, ist unbegründet. Die Online-Sicherung ist ein Verfahren, das schon seit Oracle-Version 6 problemlos funktioniert und mit dem sämtliche Wiederherstellungsverfahren möglich sind, die mit einer Offline-Sicherung gewährleistet sind.
Sandini Bib
416
Backup/Recovery
Technisches Konzept Eine Online-Sicherung kann bei laufender Oracle-Instanz mit geöffneter Datenbank durchgeführt werden. Dabei bleiben alle Aktivitäten der Hintergrundprozesse (DBW0, LGWR, SMON, PMON, CKPT ...) unverändert aktiv. Auch für Dedicated Server-Prozesse oder Multi-Threaded Server-Prozesse bestehen keine Einschränkungen. Für die physikalische Sicherung muss nun ein Werkzeug verwendet werden, dass geöffnete Dateien sichern kann. Die unter UNIX verwendeten Werkzeuge wie cpio, tar oder dd bieten diese Möglichkeit, unter MS-Windows können Werkzeuge von Fremdanbietern benutzt werden, z.B. Arcserve oder Arkaia. Außerdem gibt es im Verzeichnis %ORACLE_HOME%\bin das Programm ocopy.exe, mit dem es möglich ist, auch unter MS-Windows, geöffnete Dateien zu kopieren. Während die physikalischen Dateien der Datenbanken gesichert werden, findet nach wie vor uneingeschränkter Schreibbetrieb statt. Aus diesem Grund ist der Stand, der gesichert wird, inkonsistent und kann nur mit Hilfe der Transaktionsprotokolle im Wiederherstellungsfall in einen konsistenten Zustand gebracht werden. Daher ist eine Online-Sicherung mit der Voraussetzung verbunden, dass die Datenbank im Archivierungsmodus betrieben wird, damit alle während der Sicherung angefallenen Transaktionsprotokolle verfügbar sind. Das hier beschriebene Verfahren gilt für die Verwendung eines Standardbefehls für die Sicherung. Eine Online-Sicherung mit dem Recovery Manager wird in Kapitel 6.4 beschrieben. Die einzelnen Tablespaces einer Datenbank müssen jeweils in einen Modus für die Online-Sicherung gesetzt werden. SQL> ALTER TABLESPACE users BEGIN BACKUP;
Das Kommando bewirkt drei Dinge: 1. Für die Dateien des Tablespaces wird ein Checkpoint ausgelöst. 2. Die Header-Informationen werden eingefroren. 3. Für Blöcke des Tablespaces wird auf Full-Block-Logging umgeschaltet. Der Checkpoint stellt einen konsistenten Stand der Dateien des Tablespaces her. Da zum gleichen Zeitpunkt die Header-Informationen der Dateien eingefroren werden, existiert also ein definierter Synchronisationszeitpunkt, der als Startpunkt einer Wiederherstellung dient. Die Umschaltung auf Full-Block-Logging muss deshalb durchgeführt werden, da unter Umständen das Betriebssystem und die Oracle Datenbank mit unterschiedlicher Blockgröße arbeiten. Dadurch könnte es passieren, dass vom Sicherungswerkzeug nicht ein kompletter Oracle-Block in einer Operation gesichert wird und sich vor dem Kopieren des restlichen Teils der Block ändert, so dass er dann in der gesicherten Version inkonsistent ist. Kompensiert wird das dadurch, dass komplette Inhalte von Oracle-Blöcken in die RedologDateien geschrieben werden. Als Folge kann die Menge der Redolog-Dateien, die zur Archivierung anstehen, drastisch ansteigen.
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
417
Sie sollten also daher eine Online-Sicherung nicht in Zeitfenster legen, in denen sehr hohe Transaktionslasten liegen. Leseoperationen sind nicht problematisch. Zudem sollten Tablespaces nur nacheinander, so lange die physikalische Sicherung läuft, in den Backup-Status gesetzt werden. Beendet wird der Status für die Sicherung durch das Kommando SQL> ALTER TABLESPACE users END BACKUP;
Durch diesen Befehl werden die Header-Informationen wieder freigegeben und das Block-Logging wird ausgeschaltet. Geprüft werden kann der Status der Datendateien über folgenden Befehl: SQL> select * from v$backup; FILE# ---------1 2 3 4 5
STATUS CHANGE# TIME ------------------ ---------- ------------------NOT ACTIVE 375471 14.10.2001 19:30:34 NOT ACTIVE 375475 14.10.2001 19:30:53 NOT ACTIVE 375478 14.10.2001 19:31:16 NOT ACTIVE 375481 14.10.2001 19:31:56 ACTIVE 375467 14.10.2001 19:32:23
Listing 6.7: v$backup
Durchführung Die Online-Sicherung wird auf Ebene der Tablespaces durchgeführt. Bei der OnlineSicherung sind die Redolog-Dateien nicht Bestandteil der Sicherung, da diese während des Sicherungsvorganges weiterhin beschrieben werden und auch Wechsel der Redolog-Gruppen auftreten können. Daher ist auch der Archivierungsmodus der Datenbank Voraussetzung für die Online-Sicherung. Die folgenden Schritte sind ein Vorschlag für eine Vorgehensweise, die eine Kontrolle und die Nachvollziehbarkeit der Sicherung ermöglicht. SQL> SPOOL protokoll.lis SQL> CONNECT / as sysdba
Als Erstes sollte ein Protokoll erstellt werden, das den aktuellen Stand der RedologDateien und der Archivierung anzeigt. Zudem werden alle Tablespaces und Datendateien aufgelistet. Aus diesen Abfragen sind auch die anschließend benötigten Schleifen zu füllen. SQL> archive log list SQL> SELECT name FROM v$controlfile; SQL> SELECT * FROM v$log; SQL> SELECT name FROM v$datafile; Listing 6.8: Auflisten aller Datenbank-Dateien
Sandini Bib
418
Backup/Recovery
Nun sollte eine Schleife über alle Tablespaces laufen, die diese auf den Status BACKUP setzt, und eine weitere, in der alle Dateien des Tablespaces gesichert werden. Anschließend muss das Ende des Backups für den Tablespace bekannt gegeben werden. SQL> ALTER TABLESPACE users BEGIN BACKUP; SQL> host cp /disk3/oracle/test/users_01.dbf /backup/oracle/test/users_01.dbf SQL> host cp /disk3/oracle/test/users_02.dbf /backup/oracle/test/users_02.dbf SQL> ALTER TABLESPACE users END BACKUP; Listing 6.9: Online-Backup
Ein komplettes Beispiel finden Sie in Kapitel 6.6.1 für den Aufbau einer StandbyDatenbank. Um im Fehlerfall eine Online-Sicherung für die Wiederherstellung verwenden zu können, müssen mindestens alle Redolog-Dateien vom Start der Sicherung bis zu deren Ende vorhanden sein. Gesichert werden typischerweise die archivierten Redolog-Dateien, da diese nicht mehr geöffnet sind. Um am Ende der OnlineSicherung einen definierten Stand zu haben, der auch auf ein Band abgezogen werden kann, empfiehlt sich am Ende der Sicherung noch ein manuell initiierter Wechsel der Redolog-Gruppen, der eine Archivierung auslöst. Zusätzlich kann in diesem Zuge eine Online-Sicherung der Kontrolldatei erstellt werden. Ratsam ist es, sich mit dem passenden CREATE CONTROLFILE- Befehl auch eine Trace-Datei generieren zu lassen. SQL> ALTER SYSTEM SWITCH LOGFILE; SQL> ALTER DATABASE BACKUP CONTROLFILE TO '/backup/oracle/test/control.bck'; SQL> ALTER DATABASE BACKUP CONTROLFILE TO TRACE; Listing 6.10: Controlfile Backup
Als Letztes wird der aktuelle Status der Redolog-Dateien als Ende des Protokolls ausgegeben. SQL> ARCHIVE LOG LIST SQL> SPOOL OFF SQL> EXIT
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
6.3.5
419
Wiederherstellung
In diesem Abschnitt sollen die Schritte dargestellt werden, die im Fehlerfall vom Datenbankadministrator durchzuführen sind. Das Oracle-System bietet vielfältige Möglichkeiten der Wiederherstellung, die in den meisten Fällen alternativ angewendet werden können. Wichtig ist es, die Variante zu wählen, die die kürzeste Ausfallzeit der Datenbank bei größter Fehlertoleranz mit sich bringt. Dazu ist, trotz der sicherlich herrschenden Eile im Fehlerfall, eine genaue Fehleranalyse notwendig, um die geeignete Strategie zur Wiederherstellung festlegen zu können, die mit minimalem Aufwand eine vollständige Wiederherstellung der Datenbank ermöglicht. Verschiedene Fehlerfälle, die in der Praxis sicherlich auch in Kombination auftreten, werden anschließend mit entsprechenden Lösungen erläutert. Fehleranalyse Ziel ist es, die Datenbank mit möglichst wenig Aufwand, d.h. auch in geringst möglicher Zeit, wiederherzustellen. Um dieses Ziel zu erreichen, dürfen nur die Komponenten der Datenbank zurückgespielt werden, die auch tatsächlich durch einen Plattenfehler oder einen Anwenderfehler beschädigt worden sind. Dazu bedarf es einer eingehenden Fehleranalyse. Der Datenbankadministrator wird einen Fehler sehr wahrscheinlich vom Anwender gemeldet bekommen. Die Qualität der Fehlermeldung kann dabei sehr unterschiedlich sein, von „die Datenbank läuft nicht mehr“ bis zu einer konkreten OracleFehlermeldung. Aufgabe des DBAs ist es nun, zu überprüfen, ob die Datenbank noch läuft, ob eventuell „nur“ Probleme mit dem Archivieren aufgetreten sind oder aber tatsächlich eine Beschädigung einer Platte vorliegt. Sollte eine Oracle-Instanz abgestürzt sein, muss als Erstes die Datei alert<sid>.log (Standardverzeichnis ist betriebssystemabhängig oder über den Initialisierungsparameter background_dump_dest festgelegt) auf Fehlermeldungen hin untersucht werden. Danach sollte der DBA versuchen, ein Startup auszuführen. Bei physikalischen Beschädigungen werden bei diesem Versuch Fehlermeldungen auftauchen, die weitere Hinweise auf die Ursache geben. Ist eine Platte definitiv ausgefallen, so muss herausgefunden werden, welche Komponenten auf dieser Platte lagen. Sobald die Instanz in den Status MOUNT gestartet werden kann, ist eine Abfragemöglichkeit auf die Views v$datafile und v$tablespace gegeben. Sollte die Instanz auf Grund des Fehlers nicht abgestürzt sein, können Tablespaces über die View v$recover_file geprüft werden. Ein weiterer Anlass für die Wiederherstellung einer Datenbank kann ein Anwenderfehler oder ein Programmfehler sein. So könnte zum Beispiel versehentlich eine Tabelle gelöscht worden sein.
Sandini Bib
420
Backup/Recovery
Wiederherstellungsstrategie Ist der Fehler eingekreist, kann eine Wiederherstellungsstrategie festgelegt werden. Dafür sind folgende Punkte zu berücksichtigen: 1. Welche Teile der Datenbank müssen von Band zurückgespeichert werden? 2. Ist von diesen Komponenten der Tablespace SYSTEM oder ein Tablespace mit aktiven Rollback-Segmenten betroffen? 3. Sind alle Voraussetzungen für eine vollständige Wiederherstellung gegeben? 4. Soll eine vollständige Wiederherstellung durchgeführt werden oder soll die Datenbank auf einen früheren Zeitpunkt zurückgesetzt werden? Nach der Beantwortung dieser Fragen kann die Wiederherstellung gestartet werden. Verschiedene Fehlerfälle werden im Folgenden behandelt, wobei immer nur der Verlust einzelner Komponenten besprochen wird. Da es in der Praxis häufig zu Kombinationen dieser Fehler kommt, muss die Wiederherstellung auf die Komponente der Datenbank ausgerichtet werden, die die meisten Einschränkungen mit sich bringt. Um die Datenbank möglichst schnell wieder verfügbar zu machen, auch wenn eventuell ein einzelner Tablespace dann noch nicht zugreifbar ist, kann sich auch eine Wiederherstellung in mehreren Schritten anbieten. Instance-Recovery, Prozess- und Netzwerkfehler Das Oracle-System besitzt interne Mechanismen, die die Wiederherstellung einer Datenbank nach Fehlersituationen wie Stromausfall, Netzwerkfehler oder Absturz eines einzelnen Prozesses automatisch bereinigen. Der Hintergrundprozess SMON ist für die Konsistenz der Datenbank insgesamt verantwortlich. Nach einem Systemabsturz, egal ob durch Stromausfall, Fehlbedienung oder Hardware-Fehler bedingt, ist es beim Neustart des Oracle-Systems Aufgabe des SMON, Inkonsistenzen festzustellen und automatisch ein InstanceRecovery durchzuführen. Dazu ist es notwendig, erstens in der Roll Forward Phase alle Transaktionen aus den aktiven Redolog-Dateien nachzufahren, zweitens alle zum Zeitpunkt des Absturzes offenen Transaktionen in der Rollback Phase zurückzurollen. Dieser Vorgang ist in der Datei alert<sid>.log als Crash Recovery protokolliert. Die Datenbank ist also nach einem Neustart nach einem solchen Fehler in einem konsistenten Zustand. Der Hintergrundprozess PMON übernimmt diese Aufgabe für einzelne Serverprozesse. Sollte der Vordergrundprozess eines Anwenders abbrechen, z.B. durch eine allgemeine Schutzverletzung ..., wird dieser Fehler durch den Prozess PMON entdeckt. PMON terminiert den Serverprozess, offene Transaktionen werden zurückgerollt und Sperren auf Datensätzen werden aufgehoben. Das gleiche Verfahren deckt in Verbindung mit der Dead Connection Detection von Oracle Net auch die Problematik abgebrochener Netzwerkverbindungen ab. Bei den hier beschriebenen Fehlertypen ist also keine weitere Aktivität des Datenbankadministrators nötig, sondern die Wiederherstellung wird automatisch durchgeführt.
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
421
Media-Recovery Der Begriff Media-Recovery beschreibt die Wiederherstellung von Datenbanken oder einzelnen Dateien nach Beschädigung einer Platte. Im Folgenden werden verschiedene Fälle in Abhängigkeit der betroffenen Dateitypen behandelt. Basis einer solchen Wiederherstellung ist immer der Stand einer Sicherung, der nach Instandsetzung der betroffenen Platte auf diese zurückgespielt wird. Alternativ kann eine verfügbare andere Platte benutzt werden. Es ist unerheblich, ob es sich bei der verwendeten Sicherung um eine Offline- oder Online-Sicherung handelt. Die Kommandos, die eine Wiederherstellung anstoßen, sind: SQL> RECOVER DATABASE … SQL> RECOVER TABLESPACE … SQL> RECOVER DATAFILE …
Voraussetzung für die Ausführung ist die privilegierte Anmeldung als Datenbankadministrator mit z.B. CONNECT / AS sysdba; Sobald für die Wiederherstellung einer Komponente archivierte Redolog-Dateien benötigt werden, wird eine Interaktion des DBAs verlangt. Der Prozess meldet, welche Transaktionen aus welcher archivierten Redolog-Datei benötigt werden und wo diese gesucht werden. Beispiel für die Interaktion bei der Wiederherstellung: SQL> ALTER TABLESPACE users OFFLINE IMMEDIATE; Tablespace wurde geändert. SQL> RECOVER TABLESPACE users ORA-00279: Änderung 495389, erstellt von 10/21/2001 17:50:48. Erforderlich für Thread 1 ORA-00289: Vorschlag: G:\O9IARCH\ARCH25.ARCH ORA-00280: Änderung 495389 für Thread 1 in Sequenz #25 Log angeben: {=suggested | filename | AUTO | CANCEL} ORA-00279: ORA-00289: ORA-00280: ORA-00278: forderlich
Änderung 495482, erstellt von 10/21/2001 18:10:11. Erforderlich für Thread 1 Vorschlag: G:\O9IARCH\ARCH26.ARCH Änderung 495482 für Thread 1 in Sequenz #26 Log-Datei 'G:\O9IARCH\ARCH25.ARCH' für diese Wiederherstellung nicht mehr er-
Log angeben: {=suggested | filename | AUTO | CANCEL} AUTO ORA-00279: ORA-00289: ORA-00280: ORA-00278: forderlich
Änderung 495489, erstellt von 10/21/2001 18:10:33. Erforderlich für Thread 1 Vorschlag: G:\O9IARCH\ARCH27.ARCH Änderung 495489 für Thread 1 in Sequenz #27 Log-Datei 'G:\O9IARCH\ARCH26.ARCH' für diese Wiederherstellung nicht mehr er-
Sandini Bib
422
Backup/Recovery
Log angewendet. Wiederherstellung des Datenträgers abgeschlossen. SQL> ALTER TABLESPACE users ONLINE; Tablespace wurde geändert. Listing 6.11: Tablespace Recovery
Bei der Interaktion werden bei der Angabe der archivierten Redolog-Datei vier Möglichkeiten angeboten:
:
: :
:
=suggested
Der Recovery-Prozess schlägt eine Datei im Verzeichnis log_archive_dest bzw. log_archive_dest_n für die Wiederherstellung vor. Durch Bestätigung durch wir der Vorschlag vom Datenbankadministrator akzeptiert. filename
Alternativ zum Vorschlag des Recovery-Prozesses kann ein Dateiname mit Pfadangabe spezifiziert werden. AUTO
Normalerweise werden die archivierten Redolog-Dateien auf der Destination für die Archivierung zu finden sein. Die Eingabe von AUTO weist das System an, alle Dateien, die in der log_archive_dest bzw. log_archive_dest_n zu finden sind, für die Wiederherstellung zu verwenden. Wird eine Datei nicht gefunden, so wird die Interaktion mit dem DBA wieder aufgenommen. Es kann dann ein neuer Satz von archivierten Redolog-Dateien vom Band zurückgespielt werden, der über eine weitere Angabe von AUTO eingespielt werden kann. CANCEL
Mit der Angabe CANCEL wird die Wiederherstellung abgebrochen. Diese Option wird dann gebraucht, wenn eine unvollständige Wiederherstellung der Datenbank durchgeführt werden muss. Verlust der Dateien von Daten-Tablespaces Der Verlust der Dateien eines Daten-Tablespaces führt nicht zum Absturz der Instanz, jedoch wird ein Anwender, der auf Daten aus diesem Tablespace zugreift, eine Fehlermeldung bekommen, die einen Schreib-/Lesefehler für die Datei anzeigt. Die Wiederherstellung des Tablespace kann im laufenden Betrieb des Oracle-Systems durchgeführt werden. Anwendungen, die auf andere Bereiche der Datenbank zugreifen, können dabei ohne Einschränkung weiterarbeiten. Als Erstes muss der betroffene Tablespace in den Status offline versetzt werden. Das Offline-Setzen eines Tablespaces initiiert einen Checkpoint für den Tablespace, was aber auf Grund der Zerstörung der Dateien nicht mehr möglich ist. Aus diesem Grund wird bei dem folgenden Kommando der Zusatz immediate verwendet, der
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
423
bewirkt, das kein Checkpointing gestartet wird. Dieses ist jedoch nur möglich, wenn die Datenbank im Archivierungsmodus betrieben wird. SQL> ALTER TABLESPACE users OFFLINE IMMEDIATE;
Danach kann die Datei mit einem entsprechenden Kommando vom Sicherungsmedium auf die wiederhergestellte Platte zurückgespielt werden. Wird die Datei ersatzweise auf eine andere Platte gelegt, muss der Eintrag in der Kontrolldatei noch geändert werden mit dem Befehl: SQL> ALTER DATABASE RENAME FILE '/disk1/oracle/test/daten/users01.dbf' TO '/disk9/oracle/test/daten/users01.dbf';
Als Nächstes kann das Online-Recovery des Tablespaces gestartet werden. SQL> RECOVER [AUTOMATIC] TABLESPACE users;
Nun wird, wie bereits einleitend beschrieben, die Interaktion mit dem DBA gestartet. Ist die Wiederherstellung abgeschlossen, kann der Tablespace wieder aktiviert werden. SQL> ALTER TABLESPACE users ONLINE; Sonderfall: Um einen Tablespace in den Status OFFLINE zu setzen, muss die Datenbank geöffnet sein. Sollte der Datenbankadministrator als Reaktion auf den auftretenden Fehler das Oracle-System stoppen und starten, so wird beim Öffnen der Datenbank ein Fehler auftreten, da eine oder mehrere Dateien nicht lesbar sind. Um das Oracle-System nun schnellstmöglich wieder starten und den oder die Tablespaces während des laufenden Betriebs wiederherstellen zu können, müssen zunächst die Datendateien, die nicht mehr zugreifbar sind, in den Status OFFLINE gesetzt werden,. SQL> STARTUP MOUNT SQL> ALTER DATABASE DATAFILE '/disk1/oracle/test/daten/users01.dbf' OFFLINE; SQL> ALTER DATABASE OPEN;
Mit den offline geschalteten Dateien lässt sich die Datenbank also öffnen, so dass dann wie zuvor beschrieben verfahren werden kann. Der Status OFFLINE der Datei(en) hat keinen Einfluss auf den Status des Tablespaces. Verlust einer einzelnen Datei eines Daten-Tablespaces Eine Granularität bei der Wiederherstellung einer Datenbank, die noch unter der des Tablespaces liegt, ist die auf Ebene der Datendateien. Sollte ein Tablespace aus mehr als einer Datei bestehen und diese Dateien auf unterschiedlichen Platten liegen, von denen eine einen Defekt erleidet, so ist es möglich, nur genau diese eine Datei im laufenden Betrieb wiederherzustellen.
Sandini Bib
424
Backup/Recovery
Das Verfahren ähnelt dem Sonderfall für die Wiederherstellung eines Tablespaces. SQL> ALTER DATABASE DATAFILE '/disk1/oracle/test/daten/users01.dbf' OFFLINE;
Wiederherstellung der betroffenen Datei auf der ersetzten Platte oder einer Ersatzplatte mit eventuellem rename. SQL> RECOVER DATAFILE '/disk1/oracle/test/daten/users01.dbf';
Es folgt die Interaktion für die Wiederherstellung. Nach erfolgreicher Beendigung der Wiederherstellung kann die Datei wieder aktiviert werden. SQL> ALTER DATAFILE '/disk1/oracle/test/daten/users01.dbf' ONLINE;
Verlust des Tablespaces SYSTEM oder eines Tablespaces mit aktiven RollbackSegmenten Der Tablespace SYSTEM beinhaltet das Data Dictionary und damit zentrale Informationen, ohne die ein Oracle-System nicht lauffähig ist. Das Oracle-System wird also abstürzen, wenn die Platte, auf der eine Datei des Tablespaces SYSTEM liegt, einen Defekt aufweist. Ein Tablespace Recovery oder ein Datafile Recovery ist ebenfalls nicht möglich, da der Tablespace nicht offline gesetzt werden kann. In diesem Fall muss die Wiederherstellung über ein Database Recovery durchgeführt werden. Für die vollständige Wiederherstellung müssen immer die Kontrolldatei-Informationen bekannt sein, um das Ziel der Wiederherstellung festzulegen. Der Status des Oracle-Systems für das Database Recovery ist daher der MOUNT-Status. Daraus ergeben sich folgende Schritte: Zurückspielen der beschädigten Datei(en) auf die ersetzte Platte oder eine Ersatzplatte. Die Kontrolldateien der Sicherung sollten nicht zurückgespielt werden. Eventuell : SQL> ALTER DATABASE RENAME FILE … SQL> STARTUP MOUNT SQL> RECOVER [AUTOMATIC] DATABASE
Nun folgt die Interaktion bei der Wiederherstellung. Auch in diesem Fall werden nur Transaktionen wiederhergestellt, die Objekte im Tablespace SYSTEM betreffen. Nachdem die Wiederherstellung beendet ist, kann die Datenbank wieder geöffnet werden. SQL> ALTER DATABASE OPEN;
Das gleiche Verfahren muss auch beim Verlust der aktiven Rollback-Segmente eingesetzt werden, da diese die Konsistenz der Datenbank gewährleisten müssen und daher nicht offline gesetzt werden können.
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
425
Verlust der Online-Redolog-Dateien Der Verlust der Online-Redolog-Dateien ist einer der schlimmsten Fälle. Die Instanz wird abstürzen, da der LGWR-Prozess Informationen aus dem Logpuffer nicht mehr auf Platte schreiben kann. Alle Transaktionen, die in einer aktiven Redolog-Datei protokolliert sind, gehen verloren. Es ist einer der Fälle, die zu einer unvollständigen Wiederherstellung der Datenbank führen. Zur Vermeidung dieses Falles ist es, wie bei der Vorbereitung der Datenbank beschrieben, unbedingt anzuraten, die Redolog-Dateien entweder mit Oracle Mitteln (mehrere Member) oder über das Betriebssystem bzw. Controller zu spiegeln. Für eine unvollständige Wiederherstellung muss die gesamte Datenbank auf einen konsistenten Stand gebracht werden. Das funktioniert nicht auf Basis einzelner Komponenten wie Tablespaces oder Datendateien. Das Vorgehen: Zurückspielen aller Datendateien inklusiver der des Tablespaces SYSTEM und der Rollback-Segment-Tablespaces. Kontrolldateien sollten auch in die-
sem Fall nicht zurückgespielt werden. Die Redolog-Dateien, die auf der beschädigten Platte lagen, müssen auf der ausgetauschten Platte oder auf einer Ersatzplatte wieder eingerichtet werden. Zudem sollten vor den nächsten Schritten unbedingt die zum Zeitpunkt der Beschädigung aktuellen Kontrolldateien gesichert werden. Die Inhalte werden zum Schluss zurückgesetzt und können daher nicht für einen erneuten Versuch zur Wiederherstellung verwendet werden. $ cp /disk1/oracle/test/control/control01.ctl /disk99/oracle/test/backup/control01.ctl SQL> STARTUP MOUNT
Eventuelles Umbenennen von Dateien SQL> RECOVER [AUTOMATIC] DATABASE UNTIL CANCEL
Es folgt die Interaktion bei der Wiederherstellung. Sobald die letzte archivierte Redolog-Datei eingespielt worden ist, wird nach der nächsten Log-Sequence-Nummer gefragt. An diesem Punkt endet die Wiederherstellung. Eingabe in diesem Fall ist bei der Interaktion cancel
Nach dem Abbruch des Recovery ist die Datenbank noch nicht in dem Zustand, den die Kontrolldateien vorgeben. Daher muss jetzt ein Reset der entsprechenden Header-Informationen durchgeführt werden. Das Kommando dazu lautet: SQL> ALTER DATABASE OPEN RESETLOGS;
Dieser Befehl setzt beim Öffnen der Datenbank die Log-Sequence-Number und die SCN auf 1 zurück. Bevor die Datenbank nun wieder betrieben wird, sollte eine Sicherung durchgeführt werden, da alle archivierten Redolog-Dateien auf Grund
Sandini Bib
426
Backup/Recovery
der darin enthaltenen höheren SCNs für ein Recovery nicht mehr angewendet werden können. Verlust der archivierten Redolog-Dateien Der Verlust der archivierten Redolog-Dateien ist zunächst nicht kritisch. Diese werden ja nur für den Fall gebraucht, dass die Datenbank durch Beschädigung einer Komponente wiederhergestellt werden muss. Kritisch würde die Situation, wenn zudem Teile der Datenbank beschädigt würden. Bemerkt wird diese Beschädigung wahrscheinlich durch einen Stillstand der Datenbank, da der Archivierungsprozess ARCn nicht mehr auf seine Destination schreiben kann. Die Platte sollte so schnell wie möglich instand gesetzt werden. In der Zwischenzeit kann die Archivierung auf eine andere Platte umgeleitet werden. SQL> alter system set log_archive_log_dest = '/disk9/test/arch';
Kein Stillstand tritt auf, wenn die Archivierung gespiegelt wird und die minimale Anzahl der erfolgreichen Destinationen nicht unterschritten wird oder nicht mandatorische Destinationen ausfallen. Sollte zu dem Verlust der archivierten Redolog-Dateien noch eine Beschädigung der Datenbank hinzukommen, kann nur eine unvollständige Wiederherstellung ausgeführt werden, da dann keine ununterbrochene Kette seit der letzten Sicherung mehr verfügbar ist. Aus diesem Grunde muss sofort eine Sicherung der Datenbank angestoßen werden, sobald die Archivierung umgeleitet ist oder die Archivierungsplatte ersetzt wurde. Unvollständige Wiederherstellung Eine unvollständige Wiederherstellung, auch Cancel-based Recovery genannt, muss immer dann durchgeführt werden, wenn zwar eine Sicherung der Datenbank vorhanden ist, aber keine aktuelle Kontrolldatei, wenn die Online-Redolog-Dateien beschädigt sind, oder eine archivierte Redolog-Datei seit der verwendeten Sicherung fehlt. Ein weiterer Grund für eine unvollständige Wiederherstellung kann sein, dass die Datenbank auf einen bestimmten Stand wiederhergestellt werden soll. Die unvollständige Wiederherstellung bei Verlust der Online-Redolog-Dateien ist bereits unter Punkt 4 beschrieben worden. Das Vorgehen bei einer fehlenden archivierten Redolog-Datei ist identisch, nur endet die Wiederherstellung entsprechend früher: genau dann, wenn nach der fehlenden Datei bei der Interaktion gefragt wird, muss mit cancel abgebrochen werden. Danach erfolgt das Öffnen der Datenbank mit dem Zusatz resetlogs, dessen Konsequenzen ja bereits erörtert worden sind. Muss eine Wiederherstellung durchgeführt werden, wenn keine Kontrolldatei mehr vorhanden ist, die zum Zeitpunkt des Absturzes eines Oracle-Systems aktuell war, so kann eine Sicherung der Kontrolldatei verwendet werden.
Sandini Bib
Sicherung und Wiederherstellung externer Strukturen
427
Vorgehen: SQL> CONNECT / AS SYSDBA SQL> STARTUP MOUNT SQL> RECOVER DATABASE UNTIL CANCEL USING BACKUP CONTROLFILE Listing 6.12: Recovery mit Backup Controlfile
Der Zusatz USING BACKUP CONTROLFILE zeigt an, dass es sich um eine Sicherung der Kontrolldatei und nicht um den aktuellen Stand handelt. Die weitere Vorgehensweise ist die bekannte. Sollte nach der verwendeten Sicherung der Kontrolldatei eine Datendatei angelegt worden sein, die also nicht in der Kontrolldatei bekannt ist, lässt sich diese über das Kommando SQL> ALTER DATABASE CREATE DATAFILE '/disk5/oracle/test/datei_neu.dbf';
hinzufügen. Die unvollständige Wiederherstellung kommt auch zum Einsatz, wenn die Datenbank auf Grund eines logischen Fehlers oder eines Anwenderfehlers auf einen Stand zurückgesetzt werden soll, der entweder über eine Uhrzeit oder eine Transaktionsnummer bekannt ist. Letzteres ergibt sich bei Wiederherstellungen verteilter Datenbanken. Man spricht auch von einem Time-based oder Change-based Recovery, da zusätzlich als Parameter eine Datum-Uhrzeit-Angabe oder eine SCN-Angabe gemacht werden kann. SQL> SQL> SQL> SQL>
CONNECT / AS SYSDBA STARTUP MOUNT ALTER SESSION SET nls_date_format='dd.mm.yyyy hh24:mi:ss'; RECOVER DATABASE UNTIL TIME '01.11.2001 13:30:00'
Listing 6.13: Time-based Recovery
oder SQL> RECOVER DATABASE UNTIL CHANGE 629117
Es folgt die bekannte Interaktion. Ist der angegebene Punkt erreicht, stoppt die Wiederherstellung. Das Öffnen der Datenbank muss wiederum mit RESETLOGS erfolgen, daher sollte sich auch hier sofort eine Sicherung anschließen. Anwenderfehler Anwenderfehler sind aus Sicht der Wiederherstellung sehr problematisch. Bezeichnet wird damit das unbeabsichtigte Löschen von Tabellen oder Datensätzen. Es ist schnell einzusehen, dass ein solcher Fehler nicht mit einer vollständigen Wiederherstellung gelöst werden kann, sondern höchstens eine unvollständige Wieder-
Sandini Bib
428
Backup/Recovery
herstellung mit einem Time-based Recovery oder einem Change-based Recovery in Frage kommt. Das bedeutet dann aber, dass die gesamte Datenbank auf einen älteren Stand zurückgesetzt werden muss, was im produktiven Betrieb nicht wünschenswert ist. Es können an dieser Stelle nur Hinweise für Lösungsmöglichkeiten dieser Probleme gegeben werden. Für Details muss auf die Oracle-Dokumentation verwiesen werden.
:
:
Verwendung eines Exports Wird von der Datenbank regelmäßig eine logische Sicherung (z.B. ein Export) erstellt, so kann eine versehentlich gelöschte Tabelle aus diesem Export wieder in die Datenbank zurückgespielt werden. Ein solches Vorgehen ist nur nach eingehender Prüfung der logischen Abhängigkeiten empfehlenswert. Der Datenbankadministrator trägt dabei die Verantwortung für die Konsistenz der Datenbank. Aber hier ist es oft das kleinere Übel, gewisse Inkonsistenzen in Kauf zu nehmen oder anschließend manuell zu beseitigen. Time-based Recovery Sollte kein Export vorhanden sein, kann ein Time Based Recovery bis zu einem Zeitpunkt kurz vor Löschung der Tabelle durchgeführt werden. Dieser Stand der Datenbank kann dann genutzt werden, um von der gelöschten Tabelle einen Export durchzuführen. Das bedeutet natürlich, dass auf dem Produktionssystem der aktuelle Stand der Datenbank gesichert werden muss, dann das Time Based Recovery ausgeführt wird und ein Export gefahren wird. Danach muss die Produktionsdatenbank zurückgespielt werden, um die Tabelle anschließend zu importieren. Die logische Konsistenz ist natürlich auch in diesem Fall nicht gewährleistet und muss unbedingt geprüft werden.
:
Um die Produktionsdatenbank nicht zu beeinträchtigen, kann die Sicherung auch auf ein wesentlich kleineres Testsystem zurückgespielt werden, um den Export durchzuführen. Es müssen nämlich nur der Tablespace SYSTEM, Tablespaces mit aktiven Rollback-Segmenten und der Tablespace mit der betroffenen Tabelle zurückgespielt werden. Alle anderen Datendateien können in den Status OFFLINE gesetzt werden. Dieses Verfahren wurde ja schon zuvor beschrieben. Tablespace Point in Time Recovery Seit Oracle8 existiert die Möglichkeit, ein Tablespace Point in Time Recovery auf einer Clone-Datenbank durchzuführen. Hier soll aber wegen der Komplexität auf die Oracle-Dokumentation verwiesen werden: Oracle8i Backup and Recovery Guide, Kapitel 7, oder Oracle9i User-Managed Backup and Recovery Guide.
Das Recovery-Kommando bietet noch eine ganze Anzahl von weiteren Parametern und Optionen, die sich auf verteilte Datenbanken und Standby-Datenbanken beziehen (siehe Kapitel 6.6).
Sandini Bib
Recovery Manager
6.4
429
Recovery Manager
Nachdem Oracle viele Jahre überhaupt kein Werkzeug für die Sicherung der Datenbank mitgeliefert hat, gibt es seit der Version 8.0 den Oracle Recovery Manager. Mit ihm ist es erstmals möglich, alle relevanten Datendateien aus der Sicht der Datenbank heraus zu sichern und wiederherzustellen. Dabei unterstützt er alle möglichen Konfigurationen, z.B. Online- oder Offline-Backup, inkrementelles Backup, vollständiges (bis zur letzten Transaktion) oder teilweises Recovery. Bedient wird der Recovery Manager über eine grafische Erweiterung des Enterprise Managers oder als einfaches Kommando rman, das sich auch für die Batch-Verarbeitung über Unix cron oder den MS-Windows at-Befehl eignet. Die Sicherung erfolgt entweder auf die Festplatte oder über eine Media Management Library (MML1) auf ein Bandgerät. Es wird von Oracle hierfür der Legato Networker in einer Application Specific License (ASL2) mitgeliefert. Der entscheidende Vorteil des Recovery Managers gegenüber selbstgeschriebenen Sicherungsmethoden (Shell-Scripts, etc.) ist zum einen die Integration in die OracleDatenbank, d.h., es werden alle datenbankrelevanten Informationen direkt aus den Kontrolldateien gelesen, und zum anderen die Schnittstelle zur Sicherungssoftware. Dadurch kann zum Beispiel nach der erfolgreichen Sicherung der archivierten Redolog-Dateien ein Löschen dieser Dateien über den Recovery Manager veranlasst werden. Während der Installation einer Oracle-Datenbank wird daher im SQL-Script catproc.sql ein Package (dbms_backup_restore) angelegt, das die Kommunikation mit einem Recovery Manager-Client ermöglicht. Außerdem ermöglicht der Recovery Manager die Online-Sicherung einer Datenbank, ohne die einzelnen Tablespaces in den BEGIN BACKUP-Modus setzen zu müssen. Erreicht wird dies durch eine Checksumme für die einzelnen Datenbankblöcke, so dass eine Konsistenz jederzeit gewährleistet ist. Das aufwändige Full-BlockLogging, das gerade in großen Datenbanken für erheblich mehr Redolog-Informationen sorgt, entfällt somit.
1. 2.
MML = Media Management Library, eine Anzahl von DLLs bzw. Libraries zur Ansteuerung von Media Management-Werkzeugen, wie IBM ADSM, Legato Networker o. Ä. ASL = Application Specific License ist die Lizensierung eines Produktes nur für einen ganz bestimmten Einsatz.
Sandini Bib
430
Backup/Recovery
Abbildung 6.2: RMAN-Architektur
6.4.1
Architektur
Die Sicherung und das Wiedereinspielen einer Datenbank oder von Teilen davon geschieht mit dem Befehl rman und zusätzlichen Parametern. Als Kommandozeile kann dieser Befehl von jedem Client aus gestartet werden, in der Regel wird er jedoch auf dem gleichen System gestartet, auf dem die zu sichernde Datenbank liegt. Alternativ kann über den Oracle Enterprise Manager das Werkzeug BackupManagement aufgerufen werden, und über die mitgelieferten Wizards können dann unterschiedliche Konfigurationen durchgeführt werden. Für eine einfache Sicherung einer Oracle-Datenbank, die sich im ArchivelogModus befindet, ist der Enterprise Manager allerdings zu aufwändig. Hier genügt die Eingabe: rman target=system/manager@<SID> RMAN> backup database plus archivelog; Listing 6.14: RMAN-Sicherung einer einfachen Datenbank
Damit wird die gesamte Datenbank inklusive der angefallenen archivierten Redolog-Dateien in zwei Backup-Sets (eines für die archivierten Redolog-Dateien und eines für die Datenbankdateien) gesichert, und es können beliebige Teile wieder hergestellt werden. Als Target (Ziel) wird dabei die Datenbank bezeichnet, von der ein Backup durchgeführt werden soll. Die Anmeldung an die entsprechende Datenbank erfolgt automatisch mit dem Systemprivileg SYSDBA. Da während des Backups der Datenbank an dieser auch Strukturänderungen durchgeführt werden können, muss vom Recovery Manager aus sichergestellt werden, dass es einen definierten Zustand zum Sicherungszeitpunkt gibt. Dies erfolgt durch eine Kopie der Kontrolldatei als sog. Snapshot-Controlfile. Standardmäßig ist dies %ORACLE_HOME%\DATABASE\SNCF<SID>.ora unter MS-Windows und $ORACLE_HOME/
Sandini Bib
Recovery Manager
431
dbs\snapcf_.f unter Unix, sie kann aber über den Befehl CONFIGURE SNAPSHOT CONTROLFILE NAME TO ... umgenannt werden.
Damit ist für die Dauer der Sicherung bekannt, welche Datenbankdateien, Kontrolldateien, Online- und archivierte Redolog-Dateien zur Datenbank gehören. Außerdem enthält die Kontrolldatei Informationen über die Historie des Recovery Managers, um zum Beispiel eine inkrementelle Sicherung durchzuführen. Voraussetzungen Um eine Datenbank mit dem Recovery Manager sichern zu können, muss es möglich sein, sich als SYSDBA an die Datenbank anzumelden. Das bedeutet, der Initialisierungsparameter remote_login_passwordfile = exclusive muss gesetzt sein, und es muss eine entsprechende Passwortdatei existieren. In der zu sichernden Datenbank wird dann einem Benutzer (z.B. SYSTEM) mit dem Befehl GRANT SYSDBA TO SYSTEM das SYSDBA-Recht zugewiesen. Damit kann man sich jetzt mit dem Recovery Manager an die entsprechende Datenbank anmelden, zum Beispiel mit dem Befehl: rman TARGET=system/manager@SUNDB
Der Recovery Manager ist hinsichtlich der Kompatibilität sehr eingeschränkt. Zwar ist es möglich, das Repository in einer Oracle8i-Datenbank zu speichern, die eigentliche Funktionalität erstreckt sich jedoch immer auf die Datenbankversion, zu der der Recovery Manager gehört. D.h., man kann eine Datenbankversion 9.0.1 nur mit einer RMAN-Version 9.0.1 sichern. Bei der Version 8.1 gibt es die Möglichkeit, diese mit einem Recovery Manager 8.0.6 zu sichern. Was wird gesichert Mit dem Recovery Manager können verschiedene Objekte einer Datenbank entweder als einzelnes Objekt oder in einem Backup-Set gesichert werden. Je nach Verfahren (Online oder Offline, Full oder Incremental, Datafile-Copy oder Backup-Set) werden damit mehr oder weniger Dateien erstellt, die entweder auf eine andere Platte oder auf ein Bandlaufwerk gesichert werden. In den meisten uns bekannten Unternehmen wird die Datenbank insgesamt gesichert, und zusätzlich werden von Zeit zu Zeit die archivierten Redolog-Dateien und die Kontrolldateien gesichert. Es kann aber auch Szenarien geben, in denen es Sinn macht, Teile der Datenbank zu unterschiedlichen Zeiten zu sichern, also zum Beispiel einen sehr kritischen Tablespace einmal täglich, aber den Rest der Datenbank wöchentlich. Folgende Befehle stehen für das Backup zur Verfügung: RMAN> RMAN> RMAN> RMAN> RMAN> RMAN>
BACKUP BACKUP BACKUP BACKUP BACKUP BACKUP
DATABASE; DATABASE PLUS ARCHIVELOG; TABLESPACE ; DATAFILE ; CURRENT CONTROLFILE FOR STANDBY; ARCHIVELOG ALL;
Listing 6.15: Backup-Beispiele
Sandini Bib
432
Backup/Recovery
Dies sind nur einige Beispiele, die wiederum miteinander kombinierbar und erweiterbar sind. Sicherungstypen Der Recovery Manager kennt zwei unterschiedliche Sicherungsverfahren. Zum einen die einfache Kopie der Datendateien, z.B. für den Aufbau einer StandbyDatenbank, und zum anderen den Aufbau von sog. Backup-Sets. Die Sicherung erfolgt entweder als Full Backup oder in verschiedenen Stufen als inkrementelles Backup. Full Backup Mit einem Full-Backup ist in diesem Fall kein Backup der gesamten Datenbank gemeint, sondern die Sicherung aller genutzten Blöcke einer Datenbank-Datei. Inkrementelles Backup Beim inkrementellen Backup werden nur die Datenbankblöcke gesichert, die sich seit einem bestimmten Zeitpunkt (z.B. letzte inkrementelle oder letzte volle Sicherung) geändert haben. Damit kann die Dauer des Backups sowie die notwendigen Kapazitäten (Bandbreite des Netzwerkes oder Anzahl Bänder) minimiert werden. Die inkrementelle Sicherung bezieht sich jedoch nur auf Datendateien, nicht jedoch auf Kontroll- oder Redolog-Dateien. Beim inkrementellen Backup können verschiedene Backup-Level aufgebaut werden, um damit den notwendigen Speicherplatz zu minimieren, aber auch, um zum Beispiel bei der Sicherung über ein Netzwerk die Netzwerk-Ressourcen nicht zu sehr zu belasten. Diese inkrementellen Backups können entweder als differenzielle oder als kumulative Backups aufgebaut werden. Differenz bedeutet, dass alle Änderungen seit dem letzten Backup der gleichen Ebene oder einer tieferen Ebene gesichert werden. Kumulative Backups sichern alle geänderten Blöcke seit der letzten Sicherung der nächsthöheren Ebene. Inkrementelle Backups haben den Vorteil, dass sie am wenigsten Platz beanspruchen, allerdings kann unter Umständen ein Wiedereinspielen der Sicherung recht lange dauern, da alle vorher angefallenen Sicherungen der gleichen Stufe eingespielt werden müssen. Das folgende Beispiel zeigt den Aufbau eines inkrementellen Backups, das für die meisten größeren Datenbanken ausreichend sein sollte. Kleine Datenbanken wird man in der Regel ausschließlich über ein Full-Backup sichern. Am Wochenende wird ein Full-Backup (INCREMENT LEVEL 0) und jeden Tag ein kumulatives Backup (INCREMENT LEVEL 1 CUMULATIVE) durchgeführt. Mit den zugehörigen archivierten Redolog-Dateien sollte so ein guter Kompromiss zwischen dem verwendeten Platz für das Backup und der Zeitdauer für das Recovery gefunden sein. Sonntag: BACKUP INCREMENATL LEVEL = 0 DATABASE PLUS ARCHIVELOG;
Sandini Bib
Recovery Manager
433
Montag bis Samstag: BACKUP INCREMENATL LEVEL = 1 CUMULATIVE DATABASE PLUS ARCHIVELOG;
Bei einem Totalverlust der Datenbank oder beim Verlust einer Datendatei benötigt man dann drei unterschiedliche Sicherungen: 1. Full Backup des letzten Sonntags, 2. Inkrementelles Backup des letzten Wochentags vor dem Crash, 3. Archivierte Redolog-Dateien seit dem letzten Backup. Bei der Sicherung auf Disk sollten Sie beachten, dass zunächst eine Kopie der Datenbankdateien entsteht und erst zum Schluss das Backup-Set aufgebaut wird. Backup-Sets Backup-Sets sind ein Oracle-internes Sicherungsformat, das die Sicherung von einer oder mehreren Datenbankdateien enthält, wobei leere Blöcke nicht mitgesichert werden. Damit wird der benötigte Platz für die Sicherung klein gehalten, ohne dass auf Komprimierungstools wie Winzip o. Ä. zurückgegriffen werden muss. Außerdem kann Oracle eine Verifikation der gesicherten Daten durchführen, was bei einem externen Werkzeug nicht möglich wäre. Backup-Sets können aus einer oder mehreren Dateien (sog. Backup Pieces) bestehen, je nachdem, wie groß die Datenbank ist. Es werden jedoch immer die Datenbankdateien und die archivierten Redolog-Dateien in unterschiedlichen Backup-Sets gespeichert. Bei der Verwendung des Recovery Managers in der Version 8.0 oder 8.1 hat das Backup-Set keine Informationen über die Struktur der Datenbank. Das bedeutet, dass für ein Recovery entweder ein Recovery-Katalog oder aber eine Kontrolldatei der Datenbank zur Verfügung stehen muss. Dies schränkt die Verwendbarkeit des Recovery Managers sehr ein, so dass in der Vergangenheit nur in großen Umgebungen damit gearbeitet wurde. Mit der Version 9 kann das Backup-Set die notwendigen Informationen enthalten, um ein Recovery durchzuführen, auch wenn kein Katalog und keine Kontrolldatei zur Verfügung steht. Dadurch steht jetzt dem Einsatz nichts mehr entgegen. Im Gegenteil, die einfache Handhabbarkeit gerade in kleineren Umgebungen macht den Recovery Manager sicherlich zur ersten Wahl bei der Sicherung einer Oracle9iDatenbank. Der Befehl BACKUP DATABASE PLUS ARCHIVELOG sichert die Datenbank standardmäßig in einem Backup-Set und die archivierten Redolog-Dateien in einem zweiten. Über den Parameter PARALLELISM oder über explizite Allokation von Channels kann das Backup auch auf mehrere Backup-Sets erfolgen. Über den Befehl: BACKUP NOT BACKED UP SINCE TIME ’SYSDATE – 7’ DATABASE
Sandini Bib
434
Backup/Recovery
ist es außerdem möglich, automatisch die Datenbankdateien zu sichern, die seit einer Woche nicht mehr gesichert wurden. Ohne die Angabe SINCE werden die Datendateien gesichert, die noch nie gesichert wurden. Channels Die Kommunikation mit einem externen Sicherungswerkzeug, aber auch die Speicherung auf einer anderen Platte erfolgt über sog. Channels. Mit dem Channel wird festgelegt, welches Sicherungsmedium (DISK oder TAPE/SBT) angesprochen wird, welches Format die Sicherung haben soll (z.B. das Verzeichnis und der Name des Backup-Sets) und ob eine Parallelisierung über mehrere Kanäle erfolgen soll. Mit der Version 9 ist es erstmals möglich, die Geräte und Channels einmalig zu konfigurieren, um dann ohne zusätzliche Angabe von Parametern eine Sicherung durchzuführen. Diese automatische Konfiguration wird einmal im Recovery Manager durchgeführt und gilt dann für alle Sicherungen der entsprechenden Zieldatenbank. 1. Automatische Konfiguration eines Standardgerätes Wenn Sie das erste Mal mit dem Recovery Manager arbeiten, sollten Sie einfach den Befehl: BACKUP DATABASE eingeben. Sie werden feststellen, dass Sie keinen Channel angeben müssen, sondern es wird als Standard des Channels Disk gesetzt und die Sicherung erfolgt z.B. bei MS-Windows in das Verzeichnis %ORACLE_HOME\database. Mit dem Befehl: CONFIGURE DEFAULT DEVICE TYPE TO sbt ändern Sie das Gerät auf den Type sbt, so dass in Zukunft beim gleichen Befehl eine Sicherung auf das Bandgerät erfolgt. 2. Automatische Konfiguration der Geräte Der Befehl: CONFIGURE DEVICE TYPE DISK PARALLELISM 3 stellt bei der Verwendung des Gerätes Disk drei Kanäle für die Sicherung zur Verfügung. Damit erfolgt jede Sicherung fortan in drei statt in ein Backup-Set. Genau so kann natürlich auch eine Konfiguration für den Typ sbt erfolgen. Der Parameter PARALLEL bedeutet allerdings, dass jedem Kanal etwa die gleiche Anzahl Datendateien zugewiesen wird, was aufgrund der unterschiedlichen Dateigrößen dazu führen kann, dass die Backup-Sets ebenfalls unterschiedlich groß werden 3. Automatische Konfiguration der Channels Um noch zusätzliche Möglichkeiten bei der Namensgebung der Backup-Sets oder der Verwendung der Bandgeräte zu haben, kann man die einzelnen Kanäle separat konfigurieren. Mit dem Befehl: CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT=“E:\TEMP\%d_%s_%T“ wird ein neues Format für die Speicherung auf Disk angegeben, dabei können folgende Variablen genutzt werden: –
%c Nummer eines Backup-Pieces bei Verwendung von Duplex Backups
–
%d Name der Datenbank
–
%D Tag des Monats
–
%F Datenbank-ID (DBID) plus Tag, Monat, Jahr und fortlaufender Nummer
–
%M Monat
Sandini Bib
Recovery Manager
–
%n Name der Datenbank (mit x aufgefüllt auf acht Zeichen)
–
%p Nummer des Backup-Pieces
–
%s Nummer des Backup-Sets
–
%t Zeitstempel des Backup-Sets (4 Byte)
–
%T Datum (Jahr, Monat, Tag im Format YYYYMMDD)
–
%u 8-Zeichen langer Name aus Backup-Set und Zeit
–
%U Zusammengesetztes eindeutiges Format (%u_%p_%c)
–
%Y Jahr
–
%% %
435
Wie auch schon in der Version 8 und 8i kann allerdings mit dem Befehl ALLOCATE CHANNEL im RUN-Block die automatische Konfiguration übersteuert werden. Sie hat die gleichen Konfigurationsparameter wie die automatische Konfiguration, eine Parallelisierung erfolgt hier jedoch nicht über den Parameter PARALLEL, sondern es müssen alle Devices getrennt angegeben werden. RUN { ALLOCATE CHANNEL disk1 DEVICE TYPE DISK; ALLOCATE CHANNEL disk2 DEVICE TYPE DISK; ALLOCATE CHANNEL disk3 DEVICE TYPE DISK; BACKUP DATABASE; ) Listing 6.16: Beispiel: Manuelle Channel-Allokation
Die hier aufgeführten Beispiele können um zusätzliche Kontrollfunktionen erweitert werden. So kann zum Beispiel die maximale Größe eines Backup-Pieces (MAXPIECESIZE) oder die maximale I/O-Bandbreite (RATE) angegeben werden. Weitere Parameter finden Sie in der Dokumentation (Oracle9i Recovery Manager Reference). Hier werden auch die möglichen Formate beschrieben (Kapitel: RMAN Commands; Backup). Recovery-Katalog In komplexeren Umgebungen ist es sinnvoll einen Recovery-Katalog anzulegen, da dieser eine einfachere Verwaltung der Backups und eines eventuellen Recovery sowie die Speicherung der Scripts ermöglicht. Dabei werden alle relevanten Informationen (Lage und Name der Datendateien, Informationen über die archivierten Redolog-Dateien etc.) in einem Repository abgelegt und regelmäßig mit der zu sichernden Datenbank abgeglichen. Für diesen Katalog sollte eine eigene Datenbank aufgebaut werden, die dann natürlich ebenfalls gesichert werden muss. Der Benutzer kann beliebig gewählt werden, es sollte jedoch nicht SYS oder SYSTEM sein, um den Bezug zum Recovery Manager zu bewahren. Oftmals findet man in Beispielen als Repository-Schema den Namen RMAN. Da es hierbei aber leicht zu Ver-
Sandini Bib
436
Backup/Recovery
wirrungen zwischen dem Befehl und dem Benutzer kommt, werden wir im Weiteren den Benutzer RMC (RMAN-Catalog) als Benutzer wählen.
Abbildung 6.3: RMAN-Sicherungen
Das folgende Beispiel legt diesen Benutzer mit den erforderlichen Rechten an und erstellt dann den Katalog. SHELL% sqlplus system/manager@ja901 SQL>
CREATE USER rmc IDENTIFIED BY rmc DEFAULT TABLESPACE TOOLS TEMPORARY TABLESPACE TEMP;
SQL>
ALTER USER rmc QUOTA UNLIMITED ON TOOLS;
SQL>
GRANT RECOVERY_CATALOG_OWNER TO rmc;
SHELL% rman CATALOG rmc/rmc@ja901 RMAN> CREATE CATALOG; Listing 6.17: Erstellen eines Recovery-Katalogs
Mit dem Befehl: RMAN> REGISTER DATABASE
wird die zu sichernde Datenbank in den Katalog eingetragen. Dabei muss die Datenbank-ID (DBID) eindeutig sein. Da diese ID beim Erstellen der Datenbank automatisch generiert wird, ist davon auszugehen, dass sie in der Regel auch eindeutig ist. Einzige Ausnahme: Wenn Sie eine Datenbank kopieren (z.B. um eine zweite mit identischem Inhalt aufzubauen, oder bei der Verwendung von EMC2Systemen und sog. BCV). Eine solche Datenbank kann nur mit dem Befehl DUPLICATE in das Repository eingetragen werden. Wenn ein Backup über den Recovery-Katalog durchgeführt wird, werden die Inhalte bez. der Datendateien und Kontrolldateien abgeglichen. Wenn Änderun-
Sandini Bib
Recovery Manager
437
gen an der Struktur der Datenbank durchgeführt werden (hinzufügen von Tablespaces oder Datendateien), kann der Katalog mit dem Befehl RESYNC CATALOG manuell mit der Kontrolldatei synchronisiert werden. Bei der Verwendung des Recovery Managers in einer Oracle8- oder Oracle8i-Umgebung sollte immer ein Katalog aufgebaut werden, da Informationen über das erzeugte Backup-Set sonst nur in der Kontrolldatei existieren und somit kein Recovery durchgeführt werden kann, wenn die Kontrolldatei nicht existiert. Wenn jetzt ein Backup über den Recovery-Katalog durchgeführt werden soll, muss zunächst eine Anmeldung an das Repository erfolgen. Wichtig ist, dass die Anmeldung nur zu Beginn einer RMAN-Sitzung erfolgen kann, d.h. vor dem ersten BACKUPoder RUN-Befehl. Am sinnvollsten ist es, sich direkt beim Aufruf des Recovery Managers an das Repository anzumelden, zum Beispiel mit dem Befehl: rman CATALOG rmc/rmc@ja901 TARGET system/manager@SUNDB.
Damit wird sichergestellt, dass alle folgenden Kommandos über den RecoveryKatalog protokolliert werden, um dann mit den entsprechenden Befehlen überprüft zu werden. Controlfile Autobackup Diese Funktionalität beim Recovery Manager 9.0 erstellt automatisch ein Backup der Kontrolldatei nach jeder Sicherung mit dem Befehl BACKUP oder COPY. Standardmäßig ist die Funktion ausgeschaltet, sie kann aber jederzeit mit folgendem Befehl aktiviert werden: RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON;
Mit dieser Option ist es möglich, eine Datenbank wieder zurückzusichern, wenn weder eine Kontrolldatei noch ein Recovery-Katalog existieren. Die Information des notwendigen Restores wird dann aus dem Autobackup-Controlfile gewonnen. Daher ist in jedem Fall anzuraten, diesen Parameter auf ON zu setzen. Die Kontrolldatei wird standardmäßig in das Verzeichnis $ORACLE_HOME/dbs (UNIX) bzw. %ORACLE_HOME%\database (MS-Windows) gesichert. Als Name wird dann einzig das Format %F verwendet, das sich aus diversen Parametern zusammensetzt. Um diese Datei in eine Sicherung miteinzubauen, ist es daher sinnvoll, die Lage und den Namen der Kontrolldateisicherung mitzukonfigurieren. RMAN> CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO ’e:\temp\control%F.ctl’;
Die Variable %F ist beim Namen der Kontrolldatei zwingend erforderlich. Überprüft werden kann die Konfiguration mit dem Befehl: RMAN> SHOW CONTROLFILE AUTOBACKUP FORMAT;
Sandini Bib
438
6.4.2
Backup/Recovery
Backup
Um das geeignete Backup-Verfahren zu wählen, müssen zunächst die Randbedingungen geklärt werden. Diese sind im Folgenden:
: : : : :
Größe der Datenbank Zeitraum des Backups Größe des Backups Online- oder Offline-Backup Recovery-Katalog
Durch diese Parameter wird das Verfahren bestimmt, mit dem die Sicherung durchgeführt werden soll. Im Folgenden werden exemplarisch einige Beispiele beschrieben, wobei nicht darauf eingegangen wird, ob ein Recovery-Katalog benutzt wird, da dies für die eigentliche Sicherung ohne Belang ist. Lediglich der Aufruf des Befehls rman erthält dann als Zusatz den Parameter CATALOG ... . Full Online Backup der Datenbank Wenn eine Sicherung mit dem Befehl: RMAN> BACKUP DATABASE PLUS ARCHIVELOG
durchgeführt wird, wird automatisch ein ALTER SYSTEM ARCHIVE LOG CURRENT vor und nach der Sicherung durchgeführt. Die während des Backups angefallenen archivierten Redolog-Dateien werden zum Schluss ebenfalls gesichert. Mit dem Befehl: RMAN> BACKUP ARCHIVELOG ALL DELETE INPUT
kann ein Backup aller archivierten Redolog-Dateien erfolgen, diese werden dann anschließend von der ursprünglichen Lokation gelöscht. Alternativ kann über den Maintance-Befehl: DELETE ARCHIVELOG UNTIL TIME 'sysdate – 5' ein Löschen der archivierten Redolog-Dateien erfolgen. Dieser Befehl ist dem oben angegebenen vorzuziehen, da es oftmals sinnvoll ist, die archivierten Redolog-Dateien der letzten Tage auf der Platte zur Verfügung zu stellen und nur ab einem bestimmten Zeitraum diese zu löschen. Dadurch kann man zum einen sicherstellen, dass die archivierten Redolog-Dateien mehrfach gesichert werden (im obigen Fall fünf Tage), und zum anderen wird dadurch ein Restore erleichtert, da weniger Daten vom Band zurückgespielt werden müssen. Das folgende Beispiel konfiguriert den Recovery Manager für eine Sicherung auf Disk und führt anschließend das eigentliche Backup durch. Die Konfiguration wird nur einmal durchgeführt, da die entsprechenden Informationen in den Kontrolldateien und im Recovery Manager-Katalog abgelegt werden. rman target=system/manager@SUNDB RMAN> CONFIGURE DEFAULT DEVICE TYPE TO DISK; RMAN> CONFIGURE DEVICE TYPE DISK PARALLELISM 3;
Sandini Bib
Recovery Manager
439
RMAN> CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT = "/oradata2/backup/%d_%s_%T"; RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON; RMAN> CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/oradata2/backup/%F.ctl'; RMAN> BACKUP DATABASE PLUS ARCHIVELOG; Listing 6.18: Konfiguration Recovery Manager
Anschließend wird für die Sicherungen auf diese Art nur noch der letzte Befehl verwendet. Offline-Backup Bisher war die Rede davon, dass ein spezieller Befehl (z.B. BACKUP) ausgeführt wird und dieser eine Datenbank inklusive der archivierten Redolog-Dateien sichert. Um eine Offline-Sicherung bzw. die Sicherung einer Datenbank ohne archivierte Redolog-Dateien durchzuführen, muss zunächst einmal die Datenbank heruntergefahren werden. Anschließend wird sie in den MOUNT-Zustand hochgefahren, um die Kontrolldatei zu lesen, und dann können die bereits erwähnten Befehle für das Backup genutzt werden. SHELL% rman system/manager@JA901 RMAN> RMAN> RMAN> RMAN>
SHUTDOWN IMMEDIATE; STARTUP MOUNT; BACKUP DATABASE; ALTER DATABASE OPEN;
Listing 6.19: Offline-Sicherung
Wie in dem Beispiel ersichtlich, ist es nicht notwendig, die SQL-Befehle als solche zu definieren; der Recovery Manager kennt die Standardbefehle STARTUP, SHUTDOWN und ALTER DATABASE. Zusätzlich steht allerdings auch noch der Befehl SQL zur Verfügung, der die Ausführung von DDL-Befehlen oder PL/SQL-Prozeduren erlaubt, einzig SELECT-Befehle sind nicht möglich. Datenbank-Kopie Für kleine Datenbanken oder für den Aufbau einer zweiten identischen Datenbank kann es sinnvoll sein, statt der Backup-Sets direkte Kopien der Datenbankdateien zu erstellen. Der Vorteil bei der Verwendung des Recovery Managers anstelle eines normalen Kopierbefehls ist der, dass die Datendateien direkt validiert werden und damit auch ein Full-Block-Logging entfallen kann. Da es leider nicht möglich ist, einen Befehl wie COPY DATABASE aufzurufen, muss man den Umweg über die Erstellung eines RMAN-Scripts über SQL gehen. Das folgende Beispiel generiert zunächst über SQL*Plus ein Script mit dem Namen copyfiles.rman und den COPY-Befehlen für den RMAN. Danach wird das Script vom Recovery Manager aus aufgerufen.
Sandini Bib
440
Backup/Recovery
CONNECT system/manager@ja901 SET pages 100 SET lines 200 SET trimspool on SET heading off SET feedback off SPOOL d:\temp\copyfiles.rman SELECT 'copy datafile '||file#||' to ''e:\temp\'||substr(name,instr(name,'\',-1)+1)||''';' FROM v$datafile WHERE STATUS = 'ONLINE' OR STATUS = 'SYSTEM'; SPOOL off rman target=system/manager@ja901 cmdfile=copyfiles.rman Listing 6.20: Erzeugen eines RMAN-Copy-Scripts
Damit werden die Standardkonfigurationsparameter der zu sichernden Datenbank genutzt, d.h., es wird u.U. auch ein AUTOBACKUP der Kontrolldatei durchgeführt.
6.4.3
Restore und Recovery
Solange es keine Probleme mit dem MML gibt, ist eine Wiederherstellung der Datenbank oder Teile davon sehr einfach. Mit dem Befehl RESTORE kann jeder beliebige Teil der Datenbank wiederhergestellt werden. Im Folgenden werden exemplarisch einige Szenarien beschrieben. 1. Verlust eines Tablespaces Solange es sich nicht um den SYSTEM-Tablespace oder einen Tablespace mit aktiven Rollback-Segmenten handelt, kann die Wiederherstellung im laufenden Betrieb geschehen. SQL> ALTER TABLESPACE tools OFFLINE IMMEDIATE; RMAN> RESTORE TABLESPACE tools; RMAN> RECOVER TABLESPACE tools; RMAN> SQL "ALTER TABLESPACE tools ONLINE"; Listing 6.21: Wiederherstellung eines Tablespaces
2. Verlust einer Datendatei Auch hier gilt, dass die Wiederherstellung im laufenden Betrieb erfolgen kann, solange es sich nicht um den SYSTEM-Tablespace oder einen Tablespace mit aktiven Rollback-Segmenten handelt. SQL> ALTER DATABASE DATAFILE 'e:/oradata/JA901/tools01.dbf' OFFLINE IMMEDIATE; RMAN> RESTORE DATAFILE 'e:/oradata/JA901/tools01.dbf';
Sandini Bib
Recovery Manager
441
RMAN> RECOVER DATAFILE 'e:/oradata/JA901/tools01.dbf'; SQL> ALTER DATABASE DATAFILE 'e:/oradata/JA901/tools01.dbf' ONLINE; Listing 6.22: Wiederherstellung einer Datendatei
3. Verlust einer Kontrolldatei Sollte die Datenbank nicht gestartet werden können und der Fehler ORA-00205: Fehler beim Identifizieren der Kontrolldatei auftreten, kann über die Alert-Datei ermittelt werden, welche Kontrolldatei fehlerhaft ist. Danach kann das entsprechende Restore durchgeführt werden. RMAN> RMAN> RMAN> RMAN>
RESTORE CONTROLFILE FROM AUTOBACKUP; ALTER DATABASE MOUNT; RECOVER DATABASE; ALTER DATABASE OPEN RESETLOGS;
Listing 6.23: Wiederherstellung der Datenbank nach Verlust der Kontrolldateien
Sollten Sie jedoch nur eine Kontrolldatei von mehreren verloren haben, empfiehlt es sich, die beschädigte durch eine noch intakte zu überschreiben oder zunächst in der Initialisierungsdatei die fehlende oder defekte Datei auszutragen. Damit entfällt dann das Recovery der Datenbank. 4. Verlust der gesamten Datenbank Es wird jetzt angenommen, dass die gesamte Datenbank inklusive der Kontrolldateien und archivierten Redolog-Dateien nicht mehr zur Verfügung steht. Allerdings muss ein Autoback der Kontrolldatei existieren. Die Wiederherstellung sieht dann wie folgt aus: sqlplus "system/manager@SUNDB as sysdba" SQL> STARTUP NOMOUNT rman RMAN> SET DBID=2749674549 RMAN> CONNECT TARGET SYSTEM/MANAGER@SUNDB RMAN> SET CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/oradata2/backup/%F.ctl'; RMAN> RESTORE CONTROLFILE FROM AUTOBACKUP; RMAN> ALTER DATABASE MOUNT; RMAN> RESTORE DATABASE; RMAN> RECOVER DATABASE; RMAN> ALTER DATABASE OPEN RESETLOGS; Listing 6.24: Wiederherstellung der Datenbank mit RMAN
An dem Beispiel sieht man, dass es notwendig ist, sich die DBID zu merken (also am besten als Teil des Backup-Formates eintragen), da ohne diese ID die Kontrolldateien nicht aufgebaut werden können.
Sandini Bib
442
Backup/Recovery
5. Block Media Recovery Neben der Möglichkeit, die gesamte Datenbank oder bestimmte Objekte (Tablespace oder Datafile) wiederherzustellen, erlaubt es die Version 9 erstmals, auch einen einzelnen Block wiederherzustellen, wobei nur dieser Block während des Recovery-Vorgangs gesperrt wird und die übrige Datenbank unangetastet bleibt. Dieser Vorgang ist dann sinnvoll, wenn durch einen Hardware- oder Betriebssystemfehler einige Blöcke korrupt sind. Bei einem Backup mit dem Recovery Manager wird automatisch geprüft, ob die Blöcke korrupt sind. Sollte ein solcher Fehler vorliegen, kann es zum Beispiel zu folgender Fehlermeldung kommen: RMAN-00571: ========================================== RMAN-00569: ====== ERROR MESSAGE STACK FOLLOWS ======= RMAN-10035: exception raised in RPC: ORA-19566: exceeded limit of 0 currupt block for file /oradata1/SUNDB/users01.dbf Listing 6.25: Block-Korruption
Natürlich macht es keinen Sinn, jetzt die Sicherung weiterlaufen zu lassen. Zunächst wird man sich um die Beseitigung des Fehlers kümmern und froh sein, dass noch keine Anwendung davon betroffen ist. Es gilt also, den schnellstmöglichen Weg zu finden, die fehlerhaften Blöcke wiederherzustellen. Dafür muss erst einmal ermittelt werden, welche Blöcke tatsächlich fehlerhaft sind. Normalerweise führen Zugriffe auf fehlerhafte Blöcke zu Trace-Dateien, die im Verzeichnis user_dump_dest erstellt werden. Eine solche Trace-Datei kann dann folgenden Eintrag haben: ORA-01578: ORACLE data block corrupted (file # 7, block # 3) ORA-01110: data file 7: ’/oradata1/SUNDB/users01.dbf’ Listing 6.26: Fehlermeldung Block-Korruption
Damit steht fest, der Block Nummer 3 in der Datenbank-Datei Nummer 7 ist korrupt und muss repariert werden. Dies geschieht dann mit dem Befehl: RMAN> BLOCKRECOVER DATAFILE 7 BLOCK 3;
Alternativ kann man auch den Recovery Manager benutzen, um den korrupten Block zu ermitteln. Dafür lässt man das Backup durchlaufen, und der Recovery Manager protokolliert alle korrupten Blöcke im Data Dictionary. Voraussetzung ist, dass der Parameter maxcorrupt gesetzt wird. Im obigen Fall könnte also ein Backup wie folgt aussehen: RMAN> run { set maxcorrupt for datafile 7 to 999; backup datafile '/oradata1/SUNDB/users01.dbf'; } Listing 6.27: Backup fehlerhafter Blöcke
Sandini Bib
Recovery Manager
443
Über die View v$backup_corruption kann jetzt die Information über die fehlerhaften Blöcke gefunden werden. Der Befehl BLOCKRECOVER gestaltet sich jetzt einfacher, weil eine Liste der korrupten Blöcke im Data Dictionary existiert. RMAN> BLOCKRECOVER CORRUPT LIST;
Dieser Befehl stellt alle fehlerhaften Blöcke wieder her. Für die Wiederherstellung der Blöcke muss eine Komplettsicherung existieren, eine inkrementelle Sicherung reicht nicht aus. Außerdem kann der Header-Block einer Datei über diesen Mechanismus nicht wieder hergestellt werden. Wiederherstellung ohne Kontrolldateien Sollte die gesamte Datenbank nicht mehr zur Verfügung stehen und kein Autobackup der Kontrolldatei erfolgt sein, besteht dennoch die Möglichkeit, eine Kontrolldatei aus einem Backup-Set wieder herzustellen. Hierzu gibt es von der OracleHotline ein einsprechendes Verfahren, das uns allerdings nicht zur Verfügung steht.
6.4.4
Reporting und Überprüfung
Reporting Es gibt zwei wesentliche Befehle für das Reporting des Recovery Managers. 1. REPORT Mit diesem Befehl kann überprüft werden, welche Datendateien noch nicht gesichert wurden oder in welchen Dateien UNRECOVERABLE Operationen durchgeführt wurden und die deshalb gesichert werden sollten. Der Standardbefehl REPORT SCHEMA listet die Datenbankdateien mit der entsprechenden Größe auf. 2. LIST Mit diesem Befehl können Informationen über die bereits durchgeführten Backups, archivierte Redolog-Dateien etc. ausgegeben werden. Der Befehl LIST BACKUP gibt dabei eine vollständige Liste aller Backups aus. Natürlich kann auch direkt auf die entsprechenden Views zugegriffen werden. Folgender Befehl eignet sich zum Einbau in Überwachungs-Scripts: COLUMN COLUMN COLUMN COLUMN
set_stamp FORMAT 999G999G999 HEADING 'Id' backup_type FORMAT a20 HEADING 'Backup Art' start_time HEADING 'Startzeit' completion_time HEADING 'Beendet'
SELECT set_stamp, decode(backup_type, 'D','Full', 'I','Incremental Level ' || incremental_level, 'L','Redologs',
Sandini Bib
444
Backup/Recovery
null) backup_type, start_time, completion_time FROM v$backup_set WHERE start_time >= trunc(sysdate) - 7 ORDER BY start_time; Listing 6.28: RMAN-Überwachungs-Script
Überprüfung Es gibt beim Recovery Manager drei Arten der Überprüfung: 1. Datendateien und archivierte Redolog-Dateien können auf Fehler untersucht werden (z.B. korrupte Blöcke oder fehlende archivierte Redolog-Dateien) mit den Befehl: RMAN> BACKUP VALIDATE DATABASE ARCHIVELOG ALL;
2. Die Sicherungen können mit dem Restore-Test überprüft werden: RMAN> RESTORE DATABASE VALIDATE; RMAN> RESTORE TABLESPACE VALIDATE; RMAN> RESTORE ARCHIVELOG ALL VALIDATE; RMAN> RESTORE CONTROLFILE VALIDATE;
3. Die Backup-Sets können überprüft werden: RMAN> VALIDATE BACKUPSET ;
6.4.5
Aufräumen
Unter dem Namen Retention Policies versteht man die Angaben bezüglich des Aufbewahrens oder Löschens von Datensicherungen. Dabei muss unterschieden werden, ob die Steuerung über den Recovery Manager oder eine Media ManagementSoftware durchgeführt wird. Die heute gebräuchlichen Media Manager sind im Normalfall in der Lage, entsprechende Strategien aufzubauen und auszuführen. Das Problem in der Vergangenheit war nun, dass der Recovery Manager bzw. der Recovery Manager-Katalog von solchen „Aufräumaktionen“ nichts mitbekam. Durch die in Oracle9i eingeführte Retention Policy kann diese Strategie zum einen komplett an den Recovery Manager übergeben werden, zum anderen kann mit den Befehlen CROSSCHECK BACKUP und DELETE EXPIRED BACKUPS eine Überprüfung und Synchronisierung der Backups zwischen Recovery Manager und Media Manager erfolgen. Beim Recovery Manager gibt es hierfür zwei Kategorien:
Sandini Bib
Recovery Manager
445
1. Anzahl Tage, die ein Backup aufbewahrt werden soll RMAN> CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 60 DAYS;
2. Anzahl Kopien, die aufbewahrt werden sollen RMAN> CONFIGURE RETENTION POLICY TO REDUNDANCY 7;
Bei einer Sicherung kann von dieser Policy abgewichen werden, zum Beispiel um bestimmte Sicherungen für einen längeren Zeitraum – oder sogar für immer – aufzubewahren. Die optionale Angabe KEEP UNTIL oder KEEP FOREVER nach dem Backup-Befehl ermöglicht dies. Das KEEP FOREVER ist allerdings nur möglich, wenn ein Recovery-Katalog verwendet wird, da die Informationen in den Kontrolldateien über den Initialisierungsparameter controlfile_record_keep_time gesteuert werden.
6.4.6
Oracle Enterprise Manager Backup-Verwaltung
Natürlich ist es auch möglich, den Recovery Manager über den Oracle Enterprise Manager zu nutzen. Zunächst einmal ist dafür erforderlich, dass man sich als SYSDBA an die zu sichernde Datenbank anmeldet. Über den Datenbank-Assistenten im Verzeichnis WERKZEUGE gelangt man dann zum Menüpunkt BACKUP-VERWALTUNG.
Abbildung 6.4: Oracle Enterprise Manager, Backup-Konfiguration
Sandini Bib
446
Backup/Recovery
Leider ist der Enterprise Manager nicht in der Lage, eine vordefinierte Konfiguration zu übernehmen, so dass man zunächst einmal eine neue Backup-Konfiguration erstellen muss. Die Verwendung der Standardnamen ist hier möglich, allerdings gibt es keine Abfrage, ob ein Controlfile Autobackup erfolgen soll. Es wird jetzt eine einfache Konfiguration erstellt, die dann vom Backup-Assistenten genutzt werden kann. Dieser kann dann eine eigene Backup-Strategie aufbauen oder auf vordefinierte Templates zurückgreifen. Als Strategie wird dabei die Art (Full oder Incremental) und der Zeitpunkt eines Backups verstanden. Es ist zwar möglich, an dieser Stelle nochmals die Backup-Konfiguration aufzurufen, Änderungen kann man jedoch nicht mehr durchführen. Da die hierbei produzierten RMAN-Scripts vom Enterprise Manager als TCL-Jobs ausgeführt werden, kann jetzt noch angegeben werden, zu welchen Zeitpunkten das Script starten soll. Mit dem Button FERTIG wird nochmals eine Zusammenfassung angezeigt, und diese kann dann direkt an das Job-System des Enterprise Managers übergeben werden.
Abbildung 6.5: Backup-Assistent
Sandini Bib
LogMiner
447
Abbildung 6.6: Zusammenfassung Enterprise Manager
6.5
LogMiner
Wie schon in Kapitel 3 beschrieben, enthalten die Redolog-Dateien alle Informationen der ausgeführten Transaktionen. Es wäre also für verschiedene Bereiche sehr hilfreich, wenn man diese Informationen analysieren könnte, z.B. um festzustellen, wann eine Transaktion ausgeführt worden ist, oder noch besser, um eine Transaktion wieder rückgängig zu machen. Verschiedene Unternehmen wie BMC und Quest verwenden die Redolog-Informationen seit Jahren in Produkten für Backup/Recovery (BMC SQL-Backtrack) und Replication (Quest SharePlex). Oracle hielt es aber nie für nötig, eine derartige Unterstützung selbst anzubieten. Mit der Version 8i hat Oracle den LogMiner eingeführt, mit dem die Informationen der Online- und Offline-Redolog-Dateien ausgelesen werden können. Das Werkzeug ist zunächst über eine Reihe von PL/SQL-Prozeduren realisiert und in der Version 9i durch eine grafische Oberfläche im Enterprise Manager ergänzt worden. Damit besteht jetzt die Möglichkeit, ein Undo oder Redo einer Transaktion durchzuführen.
Sandini Bib
448
Backup/Recovery
Interessanterweise kann man mit dem LogMiner auch Redologs einer Oracle8-Version 8.0.x analysieren, es ist nur notwendig, ein Dictionary in einer 8.1 Version zu installieren. Der Aufbau des LogMiners basiert auf einem Daten-Repository, das die Struktur der zu analysierenden Datenbank enthält. Notwendig ist dies, um eine Beziehung zwischen den Objekt-Ids und den Objektnamen herzustellen. Dieses Repository muss in einer Oracle-Datenbank-Version 8.1 oder höher installiert werden. Es ist zwar theoretisch möglich, auch ohne ein Repository zu arbeiten; da aber dann die Objektnamen fehlen, ist es schwierig, die ermittelte Information auszuwerten. Während dieses Repository in der Version 8.1 nur als einfache Datei zur Verfügung stand, gibt es in der Version 9 auch die Möglichkeit, das Data Dictionary zu nutzen oder die Dictionary-Information in einer Redolog-Datei mit abzuspeichern. Folgende Vor- und Nachteile ergeben sich bei der jeweiligen Verwendung eines Dictionarys. Dictionary als Datei Es ist notwendig, mit einem Befehl (PL/SQL-Prozedur oder Enterprise Manager LOGMINER VIEWER) eine solche Datei im File-System zu erstellen. Diese Datei ist jedoch nur eine Momentaufnahme der Datenbank, so dass jede spätere Änderung an den Datenstrukturen zu einer Inkonsistenz zwischen Dictionary-Datei und tatsächlichem Data Dictionary führt. Als Vorteil muss jedoch gesehen werden, dass der Einfluss auf die Datenbank in diesem Falle am geringsten ist. Voraussetzung für die Verwendung einer externen Datei ist, dass der Initialisierungsparameter utl_file_dir gesetzt ist. Redolog Dictionary Hierbei wird die Information des Data Dictionarys in die Redolog-Dateien geschrieben und ist somit über den LogMiner wie auch die DML-Operationen verfügbar. Diese Operation kann je nach Anzahl zu sichernder Objekte die Performance der Datenbank stören und kann außerdem zu zusätzlichen archivierten RedologDateien führen. Der Vorteil liegt jedoch bei der besseren Performance des LogMiner Viewers bzw. der entsprechenden PL/SQL-Prozeduren gegenüber einer externen Datei. Online Dictionary Die Data Dictionary-Information ist dann zu bevorzugen, wenn keine Zeit ist, um eine externe Datei anzulegen. Es erleichtert die Arbeit mit dem LogMiner, führt aber zu einer größeren Last in der Datenbank. Allen drei Konfigurationen ist aber gemeinsam, dass sie nur eine Momentaufnahme des Data Dictionarys ermöglichen, das bedeutet speziell beim Zugriff auf archivierte Redolog-Dateien kann es vorkommen, dass es das entsprechende Objekt gar nicht mehr in der Datenbank gibt.
Sandini Bib
LogMiner
449
Der sicherlich interessanteste Anwendungsfall ist das Undo einer bereits durchgeführten Transaktion. Im Folgenden werden deshalb die wesentlichen Merkmale anhand eines solchen Beispiels beschrieben.
6.5.1
Beispiel
Ein Benutzer demo hat einen neuen Datensatz in die Tabelle orte eingefügt. SQL> INSERT INTO demo.orte (ORTENR, PLZ, ORT, VORWAHL) VALUES (18, ’51299’, ’Burscheid’, ’02174’); SQL> COMMIT;
Danach stellt er fest, dass er sich mit der Postleitzahl vertan hat, und möchte schnell ein Update auf den Datensatz durchführen: SQL> UPDATE orte SET plz = ’51399’; SQL> COMMIT;
Probleme? Leider hat er, wie es sicherlich jedem schon passiert ist, der per SQL*Plus schnell eine Änderung durchführen wollte, die WHERE-Klausel vergessen und somit für alle Datensätze der Tabelle ORTE die Postleitzahl auf 51399 gesetzt. Die Frage lautet: „Ist es möglich, mit dem LogMiner den alten Zustand der Tabelle wiederherzustellen?“
6.5.2
LogMiner Viewer (Oracle9i)
Der LogMiner Viewer ist eine grafische Oberfläche, die mit dem Enterprise Manager mitgeliefert wird. Darüber lässt sich die Abfrage von Redolog-Informationen sowie der Aufbau des Dictionarys grafisch verwalten, so dass neben der direkten Abfrage von Redolog-Informationen auch auf gespeicherte Abfragen zurückgegriffen werden kann. Die grafische Unterstützung liefert eine erhebliche Verbesserung gegenüber den vielen PL/SQL-Prozeduren, die ansonsten für die Abfrage verwendet werden müssen. Am o.g. Beispiel kann dargestellt werden, dass es zwar durchaus möglich ist, den alten Zustand der Tabelle wieder herzustellen, dies ist allerdings bei größeren Tabellen sehr aufwändig. Auswahl des Dictionarys Wie schon erwähnt, muss zunächst entschieden werden, welches Dictionary verwendet werden soll. Da es sich in diesem Fall um eine recht kleine Datenbank handelt, kann auf das Online-Dictionary zurückgegriffen werden.
Sandini Bib
450
Backup/Recovery
Abbildung 6.7: LogMiner-Dictionary
Wie in dieser Abbildung deutlich wird, kann bei der Verwendung einer Oracle9Datenbank zwischen Redolog, Dictionary-Datei und Data Dictionary gewählt werden. Beim Zugriff auf eine Oracle8i oder Oracle8-Datenbank kann nur eine Dictionary-Datei ausgewählt werden. Das heißt, die entsprechende Eingabemaske sieht wie folgt aus:
Sandini Bib
LogMiner
451
Abbildung 6.8: LogMiner-Dictionary Version 8i
Der vorgegebene Dateiname LogMinerDictionary.ora kann zu einer PL/SQL-Fehlermeldung führen, wenn man, wie in diesem Fall den Parameter utl_file_dir = * gesetzt hat. Dann muss die Datei mit vollem Pfadnamen angegeben werden. Auswahl der Redolog-Dateien Über den Reiter REDO-LOG-DATEIEN kann ausgewählt werden, ob ausschließlich Online-Redolog-Dateien oder auch archivierte Redolog-Dateien verwendet werden. Beim Zugriff auf die lokale Datenbank3 werden die entsprechenden Initialisierungsparameter für die archivierten Redolog-Dateien verwendet, beim Zugriff auf eine andere Datenbank müssen diese Parameter explizit angegeben werden. Das Format entspricht im Wesentlichen denen der Initialisierungsparameter log_archive_dest und log_archive_format. Leider wird die Variable %T (für Thread) nicht ausgewertet, so dass der Thread explizit angegeben werden muss.
3.
Als lokale Datenbank wird die Datenbank bezeichnet, in der der LogMiner Viewer oder die PL/SQL-Prozeduren gestartet wurden.
Sandini Bib
452
Backup/Recovery
Abbildung 6.9: LogMiner Redolog-Auswahl
Abfragekriterien festlegen Mit der Angabe der Redolog-Dateien sind die Voraussetzungen für die Auswahl eines bestimmten Zeitraumes gegeben, der sich automatisch an die minimale und maximale Zeit in den ausgewählten Redolog-Dateien richtet. Bei der Verwendung der Online-Redolog-Dateien muss darauf geachtet werden, dass Transaktionen, die nach dem Aufruf des Abfrage-Werkzeugs gestartet wurden, nicht mehr berücksichtigt werden. Das gilt speziell auch für die abgespeicherten Abfragen. Es ist also nicht möglich, eine Abfrage zu einem späteren Zeitpunkt auf neuere RedologInformationen zu wiederholen. Hierfür muss die Abfrage über den Menüpunkt ÄHNLICHE ABFRAGE neu erstellt werden. Über eine grafische oder textuelle Eingabe können jetzt weitere Einschränkungen bezüglich der zu ermittelnden Informationen gemacht werden. Für das obige Beispiel wird der Zeitpunkt auf zwei Stunden eingeschränkt und als Benutzername demo gewählt.
Sandini Bib
LogMiner
453
Abbildung 6.10: LogMiner-Abfrage
Leider gibt es bei der deutschen Einstellung des LogMiners ein Problem mit der Konvertierung der Zeiten, so dass in dem obigen Beispiel die Eingabe einer Zeit von 15 Uhr kein Ergebnis brachte, obwohl der Zeitstempel mit 03:47 PM also 15:47 Uhr angegeben ist. Undo und Redo In Abbildung 6.10 kann man die beiden Felder SQL-REDO und SQL-UNDO erkennen. Somit hat man einen schnellen Überblick und kann sich bei umfangreichen Operationen schnell zurechtfinden. Neben der oben dargestellten Version mit Balloon-Help gibt es den Button REDO/UNDO ANZEIGEN, mit dessen Hilfe der Befehl kopiert werden kann. Dies eignet sich vor allen Dingen bei einzelnen Operationen. Bei umfangreichem Undo, wenn wie im Beispiel eine ganze Tabelle betroffen ist, ist es sinnvoller, die entsprechenden Befehle über den Button LISTE SPEICHERN als Textdatei zu sichern und diese dann mit einem geeigneten Editor (Blockmodus) zu modifizieren. Die Ausgabe kann dann etwa so aussehen: update "DEMO"."ORTE" set where "PLZ" = '51399' update "DEMO"."ORTE" set where "PLZ" = '51399' …
"PLZ" = '10000' and ROWID = 'AAABSCAAGAAAAASAAA'; "PLZ" = '20000' and ROWID = 'AAABSCAAGAAAAASAAB';
Sandini Bib
454
Backup/Recovery
Damit ist es tatsächlich möglich, in relativ kurzer Zeit solche Benutzerfehler zu revidieren. Voraussetzung ist allerdings, dass die Fehler keine Millionen von Datensätzen betreffen.
6.5.3
PL/SQL-Packages
Die grafische Suche ist sehr hilfreich in kleineren Umgebungen und wenn der Enterprise Manager zur Verfügung steht. So einfach gestaltet sich das Umfeld in vielen Unternehmen aber nicht, weshalb man immer die Möglichkeiten der direkten Eingabe der erforderlichen SQL-Befehle berücksichtigen sollte. Mit dem Package dbms_logmnr_d wird das Dictionary verwaltet. Die zugehörige Prozedur build baut das Dictionary entweder als Datendatei oder als RedologInformation auf. Mit dem Package dbms_logmnr stehen dann die Prozeduren zur Verfügung, um die notwendigen Redologs zu spezifizieren, d.h., mit der Prozedur add_logfile werden Redolog-Dateien gelesen, und mit der Prozedur start_logmnr wird die Analyse gestartet. Anschließend kann über die View v$logmnr_contents die Abfrage der benötigten Informationen gestartet werden. Das folgende Beispiel entstand unter Oracle8i (Version 8.1.7), so dass als Dictionary nur eine Datei in Frage kommt. BEGIN sys.dbms_logmnr_d.build( DICTIONARY_FILENAME =>'dictionary.ora', DICTIONARY_LOCATION => 'D:/oracle/admin/JA817/udump'); sys.dbms_logmnr.add_logfile( LOGFILENAME => 'E:/oracle/oradata/JA817/redo01.log', OPTIONS => sys.dbms_logmnr.NEW); sys.dbms_logmnr.add_logfile( LOGFILENAME => 'E:/oracle/oradata/JA817/redo02.log', OPTIONS => sys.dbms_logmnr.ADDFILE); sys.dbms_logmnr.add_logfile( LOGFILENAME => 'E:/oracle/oradata/JA817/redo03.log', OPTIONS => sys.dbms_logmnr.ADDFILE); sys.dbms_logmnr.start_logmnr( DICTFILENAME =>'D:/oracle/admin/JA817/udump/dictionary.ora'); END; / SELECT sql_undo FROM v$logmnr_contents WHERE username = 'DEMO';
Sandini Bib
LogMiner
455
SQL_UNDO -----------------------------------------------------------------------------------update "DEMO"."ORTE" set "PLZ" = 10000 where ROWID = 'AAABt2AAIAAABgYAAA'; update "DEMO"."ORTE" set "PLZ" = 20000 where ROWID = 'AAABt2AAIAAABgYAAB';
… Listing 6.29: LogMiner-Prozeduren
Diese Vorgehensweise empfiehlt sich, wenn die zu ändernde Anzahl an Datensätzen sehr groß ist. Die Ausgabe kann entsprechend formatiert werden und dann als SQL-Befehl für das Undo dienen. Wichtig bei dieser Vorgehensweise ist, dass das Package dbms_logmnr Session-bezogen ist, d.h., die entsprechende Auswertung muss von der gleichen Session aus erfolgen. Die Prozedur dbms_logmnr.add_logfile mit der Option NEW legt dabei eine neue Redolog-Liste an, die dann um weitere Redolog-Dateien erweitert werden kann mit der Option addfile. In der Version 8.1.7 gibt es einen Bug, so dass es beim Aufbau der Dictionary-Datei u.U. zu folgender Fehlermeldung kommen kann: ERROR at line 1: ORA-01330: problem loading a required build table ORA-06512: at "SYS.DBMS_LOGMNR_D", line 1755 ORA-06512: at line 1 Listing 6.30: Fehlermeldung Oracle8i Version 8.1.7
Dieser Fehler ist darauf zurückzuführen, dass das Array für die Speicherung der Spaltenbeschreibung zu klein ist. Sollte der Fehler auftreten, ändern Sie bitte die Zeile TYPE col_desc_array IS VARRAY(513) OF col_description;
auf TYPE col_desc_array IS VARRAY(2000) OF col_description; Listing 6.31: Fehlerbehebung Oracle8i Version 8.1.7
Sandini Bib
456
6.5.4
Backup/Recovery
Weitere Anwendungsfälle
Alternativ kann der LogMiner allerdings, da die Ausgabe der entsprechenden View mehr als 50 Spalten hat, weitere hilfreiche Informationen sammeln. Zum Beispiel kann ermittelt werden, welche Aktionen ein bestimmter Benutzer zu einer festgelegten Zeit durchgeführt hat. SELECT
FROM WHERE AND
username, to_char(timestamp,’DD.MM.YYYY HH24:MI:SS’) TIME, sql_redo v$logmnr_contents username = 'HEYO' timestamp BETWEEN (sysdate – 10 AND sysdate);
Listing 6.32: LogMiner-Informationen über Benutzer
Außerdem ist es möglich, mit Hilfe des LogMiners Statistiken bezüglich der Zugriffe auf bestimmte Segmente zu erstellen, um damit zu ermitteln, welche Tabellen oder Indizes am stärksten bei DML-Operationen betroffen sind. SELECT FROM WHERE GROUP BY
seg_name, count(*) Hits v$logmnr_contents seg_owner = 'DEMO' seg_name;
Listing 6.33: LogMiner-Informationen über Segmente
Des Weiteren ist es in der Version 9i möglich, DDL-Operationen nachzuvollziehen und damit auch die Zeit, zu der eine solche Operation durchgeführt worden ist. Dies ist vor allen Dingen dann sinnvoll, wenn ein Point-In-Time-Recovery durchgeführt werden muss, weil jemand Objekte gelöscht hat und die Wiederherstellung über den LogMiner zu kompliziert wäre.
6.5.5
Restriktionen
Die Informationen des LogMiners werden in einer Session-spezifischen v$-View geschrieben, d.h., sie existieren nur, solange dies Session existiert, und es kann von anderen Benutzern nicht auf die Information zugegriffen werden. Gerade bei sehr umfangreichen Operationen sollte man daher zunächst einmal eine Tabelle mit den Informationen erstellen und diese dann weiteranalysieren. Daher empfiehlt es sich, nach dem Aufbau der View folgendes Statement zu benutzen, um dann auf die Tabelle logmnr_info zuzugreifen. CREATE TABLE logmnr_info AS SELECT * FROM v$logmnr_contents;
Dies hat dann auch den Vorteil, dass Indizes auf spezifische Spalten aufgebaut werden können, um die Analysen zu beschleunigen.
Sandini Bib
LogMiner
457
Der LogMiner kann nicht in einer Oracle Parallel Server- bzw Oracle Real Application Cluster-Umgebung eingesetzt werden. Es ist aber dennoch möglich, aus einer anderen Instanz heraus die Redolog-Dateien einer solchen Datenbank zu analysieren. Außerdem existieren folgende Einschränkungen: Oracle9i
: : : :
Keine Index-Only Tables Keine Tabellen mit Objektdatentypen Direct-Path-Operationen nur im Archivelog-Modus Keine LONG oder LONGRAW Datentypen
Oracle8i Speziell bei der Verwendung einer Oracle8i-Datenbank gibt es einige Restriktionen. Zwar ist es möglich, aus einer Oracle8i-Instanz heraus eine Oracle8-Datenbank bzw. die Redolog-Dateien zu analysieren. Hierfür sind jedoch folgende Voraussetzungen nötig: 1. Der Aufruf muss aus einer Oracle8i-Datenbank heraus erfolgen, 2. Der Datenbank-Zeichensatz muss auf beiden Datenbanken identisch sein, 3. Die Blockgröße (db_block_size) muss identisch sein, 4. Die Hardware-Plattform muss identisch sein. Außerdem gibt es folgende Einschränkungen bezüglich der Analyse von DML-Operationen:
: : : : :
Keine Index-Only Tables Keine Cluster-Tables oder Cluster-Indexes Keine Tabellen mit Objektdatentypen Keine Chained Rows bzw. Migrated Rows Keine Direct-Path-Loader-Operationen
6.5.6
Fazit
Beim Einsatz des LogMiners ist Vorsicht geboten. Zum einen gibt es beim Auslesen der Redolog-Dateien keine Information über die Datenkonsistenz, d.h., ein Undo könnte zu einer logischen Inkonsistenz führen. Zum anderen kann der Einsatz natürlich auch zu einem Sicherheitsproblem werden, da alle Transaktionsinformationen – auch die Benutzerdaten - gelesen werden können. Das Werkzeug ist also im Wesentlichen als Informationsquelle bei logischen Fehlern zu verstehen, und man sollte sich überlegen, ob bei einem Fehler besser ein Backup genutzt wird. Trotzdem kann es bei gravierenden und durch ein Backup schwer zu behebenden Fehlern eine Hilfestellung sein, um ein System wiederherzustellen.
Sandini Bib
458
Backup/Recovery
Wenn Sie einen Schutz vor logischen Fehlern brauchen, sollten Sie besser überlegen, ob sich für Sie der Aufbau einer Standby-Datenbank (siehe Kapitel 6.6.1) lohnt.
6.6
Failover-Systeme / Optionen
In diesem Abschnitt werden die Konzepte von Failover-Systemen beleuchtet, ohne auf technische Details einzugehen, da ansonsten der Rahmen dieses Buches gesprengt würde. Es muss an dieser Stelle deutlich darauf hingewiesen werden, dass auch Failover-Systeme kein Ersatz für eine Datensicherung sind, sondern nur helfen, den Verlust einer Hardware-Komponente ohne oder mit möglichst wenig Ausfallzeit zu überstehen.
6.6.1
Oracle Standby-Datenbank
Das Produkt Oracle Data Guard ist die Weiterentwicklung der Oracle Standby Database-Funktionalität. Bereits unter Oracle-Version 6 gab es – durch eigene Scripts und durch das Produkt DBShadow der Firma Libelle Informatik – die Möglichkeit, eine Standby-Datenbank aufzubauen. Mit der Version 7.3 übernahm Oracle dann offiziell den Support für die Standby-Datenbank. Seit dieser Zeit wird die Funktionalität des Produktes in jedem Release erweitert, was dazu geführt hat, dass Oracle kurz vor der Einführung von Oracle9i eine komplette grafische Oberfläche mit entsprechenden Wizards und der Einbindung in den Oracle Enterprise Manager unter dem Namen Data Guard zur Verfügung stellte. Da sich der Name im Wesentlichen auf die grafische Oberfläche bezieht, die darunter liegende Funktion eher einer Schattendatenbank entspricht, werden wir im Folgenden den Namen Standby-Datenbank verwenden. Architektur Im Prinzip ist die Standby-Datenbank eine physikalische Kopie einer Produktionsdatenbank, die sich im permanenten Recovery-Modus befindet. Die Abbildung 6.11 zeigt, dass sich das Produktionssystem (PROD) im Archivierungsmodus befindet. Die archivierten Redolog-Dateien werden über Betriebssystemmechanismen (rcp, ftp etc.) oder über Oracle Net auf das Standby-System übertragen und dort über ein Recovery in die Standby-Datenbank (STBY) eingefügt. Voraussetzungen Die wesentliche Voraussetzung und gleichzeitig die größte Limi-
tierung einer Standby-Datenbank ist, dass die beteiligten Systeme das gleiche Betriebssystem und die gleiche (bis auf Patchlevel genau) Oracle-Version haben müssen. Somit ist ein so genanntes Rolling Upgrade, d.h. ein Upgrade von Betriebssystem oder Oracle-Software im laufenden Betrieb, mit einer Standby-Datenbank nicht möglich. Eine Standby-Datenbank kann ohne nennenswerte Probleme auch für eine Oracle Parallel Sever bzw. Oracle Real Application Cluster-Datenbank ausgesetzt werden. Dabei ist es nicht erforderlich, dass die Standby-Datenbank ebenfalls eine derartige Server-Datenbank ist.
Sandini Bib
Failover-Systeme / Optionen
459
Abbildung 6.11: Standby-Datenbank
Datenverfügbarkeit Da die Standby-Datenbank in der Regel die archivierten Redolog-Dateien des Produktionssystems erhält, gehen unter Umständen im Fehlerfall Transaktionen (die der letzten Online-Redolog-Datei) verloren. Mit der Version 9i ist es allerdings erstmals möglich, eine so genannte No Data Loss-Konfiguration aufzubauen. Bei dieser Konfiguration werden alle Transaktionen, die auf dem Produktionssystem ausgeführt werden, nicht nur in die lokale Redolog-Datei sondern auch in eine zweite Redolog-Datei auf dem Standby-System eingetragen. Damit steht im Fehlerfall die gesamte Redolog-Information zur Verfügung und kann dem entsprechend eingespielt werden.
Beim Aufbau einer derartigen Konfiguration sollten Sie allerdings bedenken, dass, wenn das Standby-System oder das dazwischen liegende Netzwerk nicht zur Verfügung steht, keine Transaktion durchgeführt werden kann. In sofern ist die No Data Loss-Konfiguration nur dann ratsam, wenn es unter gar keinen Umständen zu einem Datenverlust kommen darf. Auf der anderen Seite ist es möglich, das Recovery der Standby-Datenbank bewusst zu verzögern. Damit können logische Fehler auf der Produktionsseite wie z.B. Fehler in Anwendungen, die zu fehlerhaften Datensätzen führen oder Bedienerfehler (TRUNCATE TABLE etc.) behoben werden, ohne dass ein komplettes Backup eingespielt werden muss. Dabei wird dann das Recovery bis zum Zeitpunkt kurz vor dem Fehler auf der Standby-Datenbank durchgeführt und dann die betroffenen Objekte aus der Standby-Datenbank exportiert und in die Produktionsdatenbank eingefügt. Insofern ist die Standby-Datenbank als zusätzliche Absicherung von Anwenderbzw. Anwendungsfehlern sicher die erste Wahl.
Sandini Bib
460
Backup/Recovery
Nutzbarkeit der Standby-Datenbank Die Standby-Datenbank kann für lesende Zugriffe geöffnet werden. Dieser Vorgang unterbricht das Recovery und öffnet die Standby-Datenbank im Read Only-Modus. In diesem Zustand kann z.B. ein Export erfolgen oder auch ein Reporting. Allerdings sollte diese Möglichkeit nicht zu stark beachtet werden, da Sie in der Standby-Datenbank keine Objekte anlegen können, nicht einmal ein Sortieren im Temporary Tablepace ist möglich. Da das Öffnen der Standby-Datenbank das Recovery ausschaltet, müssen Sie außerdem damit rechnen, dass im Fehlerfall eine entsprechend längere Zeit vergeht, bis das System einsatzfähig ist. Failover Der eigentliche Sinn der Standby-Datenbank ist natürlich der, dass im
Fehlerfall die Produktion auf das Standby-System umgeschaltet werden kann. Aber auch hier gibt es einiges zu beachten:
: : :
In dem Moment, wo das Recovery beendet und die Standby-Datenbank im Read-Write-Modus geöffnet wird, schreibt sie ihre eigenen Redolog-Informationen und ist somit eine andere Datenbank als das ursprüngliche Produktionssystem. Das bedeutet, dass diese Datenbank dann in ein Sicherungskonzept mit eingebaut werden muss. Da die Datenbank als Kopie entstanden ist und damit die gleiche DBID wie die Produktion hat, muss der Recovery Manager entsprechend angepasst werden. Ein Zurückschwenken auf das alte Produktionssystem ist außerdem nicht so einfach möglich. Es müssen folgende Schritte durchgeführt werden: –
Die Produktionsdatenbank wird als Kopie der Standby-Datenbank aufgesetzt.
–
Das Produktionssystem wird in den Standby-Modus hochgefahren und die archvierten Redolog-Dateien werden vom Standby-System übertragen. Damit ist die ursprüngliche Produktionsumgebung jetzt Standby-System.
–
Die Produktion wird im Read-Write-Modus geöffnet und die Anwendungen werden auf das ursprüngliche Produktionssystem zurück geschwenkt.
–
Die Standby-Datenbank muss jetzt wieder neu aufgesetzt werden.
Diese Punkte sollte man wohl überlegen, wenn man ein Standby-System aufsetzt. Daher ist es in den meisten Fällen ratsam, ein Zeitfenster zu definieren, das für einen Ausfall des Produktionsrechners toleriert werden kann, bevor auf das Standby-System umgeschaltet wird. Sollte diese Umschalt-Zeit bei Ihnen im Bereich von weniger als einer Stunde liegen, dann sollten Sie lieber eine alternative Konfiguration wie z.B. Oracle Real Application Cluster oder Quest Shareplex in Betracht ziehen, da diese eine kürzere Umschaltzeit, allerdings zu Lasten der Lizenzkosten, haben. Außerdem bietet ein Oracle Real Application Cluster keinen Schutz gegen Anwendungsfehlern. Konfiguration Für die Konfiguration einer Standby-Datenbank gibt es jetzt mehrere Ansätze:
Sandini Bib
Failover-Systeme / Optionen
461
1. Manuelle Konfiguration 2. Oracle Managed Standby 3. Oracle Data Guard Es würde den Rahmen des Buches sprengen, wenn wir hier alle Konfigurationsarten durchsprechen würden, daher beschränken wir uns auf die wesentlichen Merkmale. Außerdem arbeitet Oracle an weiteren Konfigurationen (z.B. Logical Standby), so dass wir gespannt sind, welche Arten der Konfiguration in Zukunft noch möglich sein werden. Alle Konfigurationsarten gehen dabei im Wesentlichen wie folgt vor: 1. Es wird eine Kopie der Produktionsdatenbank erstellt. In der Regel geschieht dies dadurch, dass zunächst alle Tablespaces der Datenbank in den BEGIN BACKUP-Modus gesetzt werden; die entsprechenden Datendateien werden auf die Standby-Seite übertragen, und anschließend werden die Tablespaces mit END BACKUP wieder in den ursprünglichen Zustand zurück gesetzt. 2. Es wird eine Kopie der Kontrolldatei erstellt, um diese als Standby-Kontrolldatei benutzten zu können. Der Befehl hierfür ist: SQL> ALTER DATABASE CREATE STANDBY CONTROLFILE AS ;
Diese Datei wird dann ebenfalls auf die Standby-Seite übertragen. 3. Jetzt wird die Initialisierungsdatei der Standby-Datenbank für den StandbyModus angepasst (z.B. Name der Instanz, Lokation der archivierten RedologDateien etc.) 4. Das Recovery auf der Standby-Seite wird angestoßen. Da in der Regel Strukturänderungen der Datenbank (neue Tablespaces, neue Datendateien) nicht mit übertragen werden, muss hierfür eine separate Lösung gefunden werden. Oracle Data Guard und Libelle DBShadow bieten hierfür zusätzliche Lösungen an, die die Änderungen der Datenbankstruktur überwachen und dann die entsprechenden Scripts generieren, um diese Änderungen auf der Standby-Seite nachzupflegen. Manuelle Konfiguration Die manuelle Konfiguration ist die älteste Art, eine Standby-Datenbank aufzubauen. Außer der mit Oracle8 eingeführten Standby-Kontrolldatei gibt es keine Unterschiede in der Handhabung unterschiedlicher Oracle Releases. Der Vorteil der manuellen Konfiguration ist, dass dieses System das flexibelste ist. So können z.B. alle Programme bzw. Befehle von der Standby-Seite aus initiiert werden und belasten somit das Produktionssystem nicht. Der Nachteil besteht natürlich in der Fehleranfälligkeit. Kopieren der Produktionsdatenbank Wir empfehlen, alle Schritte für das Kopieren einer Standby-Datenbank als Informationen aus der Produktionsdatenbank herauszulesen. Nichts ist gefährlicher als die Lösung, einfach ein Filesystem zu nehmen und auf das andere System zu übertragen. Das funktioniert sicher bei einer
Sandini Bib
462
Backup/Recovery
neuen Datenbank, nicht aber, wenn zusätzliche Tablespaces oder Datendateien angelegt wurden, die sich nicht an die Konventionen halten. Das folgende Script erstellt unter dem Unix-Betriebssystem eine Reihe von ShellScripts, die die Tablespaces in den BEGIN BACKUP-Modus setzten, das Backup ausführen und anschießend mit END BACKUP die Tablespaces wieder zurücksetzen. sqlplus /nolog << ESQL CONNECT system/$SYSPWD SET ECHO ON ALTER TABLESPACE $1 BEGIN BACKUP; EXIT; ESQL Listing 6.34: Script begin_backup.sh
sqlplus /nolog << ESQL CONNECT system/$SYSPWD SET ECHO ON ALTER TABLESPACE $1 END BACKUP; EXIT; ESQL Listing 6.35: Script end_backup.sh
echo "cp $1 $CDIR" cp $1 $CDIR/ Listing 6.36: Script do_backup.sh
sqlplus -s /nolog <<EOF >> $LOGFILE CONNECT system/manager SET SERVEROUTPUT ON SET ECHO OFF FEEDBACK OFF TERMOUT OFF HEADING OFF VERIFY OFF SPOOL backupdatei.sh DECLARE CURSOR c_ts is SELECT tablespace_name FROM dba_tablespaces; CURSOR c_df (v_tablespace_name IN VARCHAR2) is SELECT file_name FROM dba_data_files WHERE tablespace_name = v_tablespace_name; BEGIN dbms_output.put_line('./switch_log.sh '); FOR r_ts IN c_ts LOOP
Sandini Bib
Failover-Systeme / Optionen
463
dbms_output.put_line('./begin_backup.sh ' || r_ts.tablespace_name); FOR r_df IN c_df(r_ts.tablespace_name) LOOP dbms_output.put_line('./do_backup.sh ' || r_df.file_name); END LOOP; dbms_output.put_line('./end_backup.sh ' || r_ts.tablespace_name); END LOOP; END; / Listing 6.37: Erstellen eines Online-Backups
In dem Shell-Script begin_backup.sh und end_backup.sh wird jeweils ein Tablespace in den BEGIN BACKUP- bzw. END BACKUP-Modus gesetzt. Mit dem Shell-Script do_backup.sh wird dann die eigentliche Kopie der zu dem Tablespace gehörenden Datendateien durchgeführt. Diese Scripts kopieren jederzeit jede Datenbank, dabei muss nur das Script do_backup.sh so angepasst werden, dass es den entsprechenden Kopierbefehl ent-
hält. Vor und nach dem Backup der Datenbank sollte noch ein ALTER SYSTEM SWITCH LOGFILE durchgeführt werden, um neue archivierte Redolog-Dateien zu erstellen. Erstellen der Standby-Kontrolldatei Die Standby-Kontrolldatei wird, wie bereits erklärt, mit dem Befehl SQL> ALTER DATABASE CREATE STANDBY CONTROLFILE AS ;
erstellt. Starten der Standby-Datenbank Auf dem Standby-System wird die Instanz jetzt im Standby-Modus hochgefahren: sqlplus "/ as sysdba" SQL> STARTUP NOMOUNT PFILE = initSTBY.ora; SQL> ALTER DATABASE MOUNT STANDBY DATABASE; Listing 6.38: Starten einer Standby-Datenbank
Jetzt ist die Standby-Datenbank für das Recovery vorbereitet. Recovery von archivierten Redolog-Dateien Im ersten Schritt müssen die archi-
vierten Redolog-Dateien bei der manuellen Konfiguration mit selbst geschriebenen Scripts auf das Standby-System übertragen werden. Wenn das Produktionssystem
Sandini Bib
464
Backup/Recovery
damit nicht belastet werden soll, bedeutet dies, dass von dem Standby-System aus regelmäßig (ca. alle 5 Minuten) nachgesehen werden muss, ob auf dem Produktionssystem eine neue archivierte Redolog-Datei erstellt worden ist. Wenn ja, wird diese auf das Standby-System in das Verzeichnis kopiert, das über den Initialisierungsparameter log_archive_dest bzw. log_archive_dest_n (n zwischen 0 und 9) vorgegeben wurde. Im zweiten Schritt, der eventuell verzögert durchgeführt werden kann, um logische Fehler beheben zu können, wird dann das Recovery durchgeführt: SQL> RECOVER AUTOMATIC STANDBY DATABASE; Aktivieren der Standby-Datenbank Für die Umschaltung der Produktion auf das Standby-System muss die Datenbank aus dem STANDBY-Modus herausgenommen und als „normale“ Datenbank gestartet werden. Dies geschieht durch die Befehle: SQL> ALTER DATABASE ACTIVATE STANDBY DATABASE; SQL> SHUTDOWN IMMEDIATE; SQL> STARTUP; Listing 6.39: Aktivieren der Standby-Datenbank
Vorsicht! Nach dem Befehl ALTER DATABASE ACTIVATE STANDBY DATABASE gibt es keine Möglichkeit mehr, in den Standby-Modus zurück zu kommen. Oracle Managed Standby Mit der Konfiguration über den Oracle Listener und einem speziellen Archive-Verzeichnis ist es möglich, das Übertragen der Redolog-Dateien und das Recovery der Standby-Datenbank vom Produktionsrechner zu initiieren. Dabei wird auf dem Standby-System ein Oracle Net Listener konfiguriert, der die Informationen zur Standby-Datenbank wie bei einer „normalen“ Datenbank enthält. Auf dem Produktionssystem wird als Achivierungsverzeichnis jetzt statt eines echten Verzeichnisses der Servicename der Standby-Instanz angegeben. Dabei muss archive_log_dest_n (n = 0 bis 9) als Initialisierungsparameter gewählt werden, da nur dieser die entsprechenden Optionen (SERVICE oder LOCATION) versteht. Der Eintrag kann dann z.B. wie folgt aussehen: archive_log_dest_0 = 'LOCATION = /oraarch/SUNDB' archive_log_dest_1 = 'SERVICE = STBY' Listing 6.40: Oracle Managed Standby
Sandini Bib
Failover-Systeme / Optionen
465
Weitere Optionen dieser Parameter können hier zusätzlich angegeben werden. Beispiele sind:
: :
MANDANTORY: Die Archivierung in dieses Verzeichnis bzw. diese Lokation muss erfolgreich gewesen sein, bevor die entsprechende Redolog-Datei überschrieben werden darf. Das Gegenstück hierzu ist OPTIONAL. DELAY = n (in Minuten): Hiermit wird die Verzögerung des Recoverys einge-
stellt.
Dem Vorteil der automatischen Übertragung der archivierten Redolog-Dateien und des automatischen Recoverys auf der Standby-Datenbank steht der Nachteil gegenüber, dass dies alles vom Produktionsrechner aus initiiert werden muss. In diesen Kontext fällt auch die No Data Loss-Konfiguration. Dabei wird neben dem Parameter MANDANTORY auch noch der Parameter LGWR gesetzt, wodurch sichergestellt wird, dass jede Transaktion nicht nur in eine lokale Redolog-Datei, sondern auch in eine Redolog-Datei auf der Standby-Seite geschrieben wird. Leider fehlen uns an dieser Stelle noch Erfahrungswerte, wie stark eine derartige Konfiguration ein Produktionssystem belasten. Es bleibt jedoch Fakt, dass die Gesamtverfügbarkeit der Anwendung durch den Parameter MANDANTORY und noch mehr durch den Parameter LGWR abnimmt, daher sollten sie nur mit größter Vorsicht eingesetzt werden. Eine interessante Alternative zu den hier vorgestellten Konfigurationen ist das Produkt DBShadow der Firma Libelle Informatik. Dieses Produkt kann für alle gängigen Oracle-Datenbanken eine Standby-Funktionalität aufbauen. Neben der automatischen Aktivierung und Überwachung der Datenbanken ist gerade das Aufsetzen einer Standby-Umgebung und das Kopieren der Datendateien eine der wesentlichen Merkmale dieses Tools.
6.6.2
Replikation
Die technischen Details der Replikation, wie das Konzept, das Aufsetzen, die Administration und die Überwachung, werden in Kapitel 8 behandelt. An dieser Stelle soll auf Möglichkeiten hingewiesen werden, die eine redundante Datenhaltung für die Wiederherstellung von Daten bieten. Bei physikalischen Beschädigungen an Platten können redundant gehaltene Daten auf anderen Systemen dazu genutzt werden, um eine Wiederherstellung durchzuführen. Dazu stehen Export/Import oder Insert-Befehle mit Select-Befehlen über Datenbank-Links zur Verfügung. Die Aktualität der redundanten Daten ist abhängig davon, ob die Replikation synchron oder asynchron betrieben wird. Außerdem muss berücksichtigt werden, ob sämtliche Daten redundant gehalten werden. Eventuell werden nämlich nicht alle Tabellen des beschädigten Systems repliziert, oder es werden nur vertikale und/oder horizontale Ausschnitte von Tabellen abgebildet. In solchen Fällen müssten entweder mehrere Systeme als Quelle für die Wiederherstellung der Daten genutzt werden oder es kann nur ein Teil der Daten reproduziert werden, zu dem dann fehlende Daten nacherfasst werden müssen.
Sandini Bib
466
Backup/Recovery
Bei asynchronen Replikationen, die einen „veralteten“ Stand der Daten darstellen, kann, wie auch bei einem Export einer Datenbank, keine Wiederherstellung der Transaktionen über Redolog-Dateien angestoßen werden. Hier könnten Sie nur versuchen, durch den Einsatz des LogMiners die Befehle der Transaktionen aus den Redolog-Dateien zu extrahieren, um diese dann nachzufahren. Keinen Schutz bietet die redundante Datenhaltung über die Replikation gegen logische Fehler oder Benutzerfehler. Bei synchroner Replikation werden diese Fehler nämlich sofort, bei asynchroner Replikation mit einem zeitlichen Versatz auf dem Zielsystem nachgezogen. Es sollte auch deutlich sein, dass Wiederherstellungen auf diese Weise enorm zeitaufwändig und fehleranfällig sind, insbesondere in Bezug auf die logische Konsistenz der Daten. Daher sind redundante Daten auch höchstens als Ergänzung zur physikalischen Sicherung einer Datenbank zu sehen, aber auf keinen Fall als Ersatz.
Sandini Bib
7
Optimierung
Die Optimierung von Anwendungen, Instanzen, Datenbanken und Netzwerken wird den Datenbankadministrator und den Anwendungsentwickler immer wieder vor neue Herausforderungen stellen. Mit der steigenden Komplexität der Anwendungen und der stetig wachsenden Menge der in der Datenbank abgelegten Informationen, aber auch durch die zunehmende Anzahl von Anwendern, die konkurrierend auf die Datenbank zugreifen, werden sich auch die Anforderungen an die Performance stetig steigern. Zwar wird die Hardware immer leistungsfähiger, jedoch sind auch hier Grenzen gesetzt, so dass der Ressourcenbedarf bei komplexen Zugriffen mit schlechten Zugriffspfaden nicht mehr abgedeckt werden kann. Durch die Optimierung eines Oracle-Systems kann oft eine teuere Hardware-Investition vermieden werden. In diesem Kapitel werden die verschiedenen Möglichkeiten der Optimierung eines Oracle-Systems aufgezeigt.
7.1
Überblick und Strategie
Die Optimierungsmöglichkeiten eines Oracle-Systems lassen sich in vier Bereiche aufteilen:
: : : :
Zugriffsoptimierung Datenbankoptimierung Instanzoptimierung Netzwerkoptimierung
Die hier aufgezeigte Reihenfolge ist nicht zufällig gewählt. Der erste Ansatz der Optimierung sollte immer die Anwendung sein, da hier die größten Gewinne zu erzielen sind. Die Datenbankoptimierung aus Sicht des Datenmodells (7.5.1) ist für die Zugriffe natürlich Voraussetzung und soll der Zugriffsoptimierung zugerechnet werden. Die im Unterpunkt 7.5.3 und folgenden beschriebenen Punkte betreffen interne Ressourcen der Datenbank, die Sie, genau wie die Instanzparameter, nur dann optimal einstellen können, wenn Sie davon ausgehen können, dass die Anwendung nicht unnötig Ressourcen verschwendet. Die Optimierung des Netzwerkes ist nur in speziellen Fällen angezeigt. Wie werden Engpässe erkannt? Wünschenswert ist natürlich, eine neue Anwendung vor ihrer Einführung auf Performance getestet und optimiert zu haben. Gerade aber beim Einsatz des kostenbasierten Optimizers stehen oftmals für die Testdatenbank keine der späteren Produktion entsprechenden Datenmengen zur Verfügung, so dass die Zugriffspfade in der Testumgebung nicht mit denen in der Produktion übereinstimmen.
Sandini Bib
468
Optimierung
Die Praxis sieht jedoch anders aus. In der Entwicklungsphase eines Projekts wird das Datenmodell zwar zuerst definiert, jedoch ergeben sich häufig durch Anforderungen der Anwendung nachträglich Veränderungen. Sehr häufig kommt ein hoher Termindruck hinzu, der dazu führt, die Anwendung erst einmal lauffähig zu machen, ohne sich jedoch um Optimierungsaspekte zu kümmern. Beim Einsatz von Standardsoftware ist generell ein Datenmodell vorgegeben, das an spezifische Anforderungen angepasst wird. Hier sind bei unterschiedlichen Unternehmen oft unterschiedliche Datenmengen und unterschiedliche Datenverteilungen anzutreffen, auf die der kostenbasierte Optimizer dann reagiert. Performance-Engpässe werden dann entweder von den Anwendern direkt gemeldet, die sich auf bestimmte Masken oder Berichte beziehen, oder es wird generell über eine schlechte Performance des Gesamtsystems geklagt. Hier gilt es dann, mit geeigneten Werkzeugen und Verfahren die Engpässe zu lokalisieren und zu beseitigen. Zum besseren Verständnis wird zunächst einmal besprochen, wie in einer Oracle-Datenbank die SQL-Befehle übersetzt (Parsing) und ausgeführt werden (FETCH und EXECUTE).
7.1.1
Die Ausführung von SQL-Code
Die Abarbeitung eines SQL-Befehls erfolgt nicht an einem Stück, sondern in mehreren Phasen. Die einzelnen Phasen werden im Folgenden kurz erklärt. Sie gelten im Wesentlichen für alle Arten von SQL-Befehlen. Eine Ausnahme ist lediglich die FETCH-Phase, die nur beim SELECT-Befehl existiert und dafür sorgt, dass die Ergebnisdatensätze vom Server zum Client übertragen werden. Der Cursor Um in den nachfolgend diskutierten Phasen Informationen zwischenzuspeichern wird eine spezielle Datenstruktur benötigt. Diese wird, in Anlehnung an die Vorstellung eines Zeigers, der bei der Ausgabe der Datensätze die aktuelle Position angibt, als Cursor bezeichnet. Bezieht man sich auf die dort enthaltenen Informationen, so wird diese Struktur auch Context Area genannt. Der Cursor ist die Schaltzentrale für die Ausführung eines SQL-Befehls. Er enthält den betreffenden SQLBefehl als Zeichenkette sowie den Ausführungsplan des SQL-Befehls als Zeiger auf den Shared Pool sowie Zeitstempel- und Zustandsinformationen. Ein Anwendungsprogramm kann – bis auf die Beschränkungen des virtuellen Adressraums und des Initialisierungsparameters open_cursors – beliebig viele Cursors öffnen. Weiterhin werden in einer Anwendung Variablen benutzt, um einerseits Parameter an SQL-Befehle zu übergeben (z.B. in WHERE-Klauseln), und um andererseits das Ergebnis eines SELECT-Befehls aufzunehmen. Diese Variablen werden als Bindevariablen bezeichnet und ebenfalls Cursor-spezifisch behandelt. Das Vorgehen zum Binden von Variablen unterscheidet sich nach Art des Clients (Embedded SQL, Forms, OCI usw.).
Sandini Bib
Überblick und Strategie
469
Um die Arbeitsweise des Oracle Servers zu verdeutlichen, muss noch auf eine spezielle Eigenschaft hingewiesen werden: Der Oracle Server arbeitet ausschließlich nach einer Methode, die allgemein als dynamisches SQL bezeichnet wird. Dies bedeutet, dass die SQL-Befehle der Anwendungen dem Oracle Server vor der Ausführung nicht bekannt sein müssen. Im Gegensatz dazu müssen bei Datenbankservern, die mit statischem SQL arbeiten, die Anwendungen vorher übersetzt werden, so dass beim Ablauf der Anwendungen alle SQL-Befehle bekannt sind und ein beim Übersetzen festgelegter Ausführungsplan benutzt wird. Das dynamische SQL des Oracle Server hat den Vorteil, dass die Anwendungen dadurch flexibler werden: Moderne SQL-Werkzeuge generieren SQL-Befehle aus den Eingaben des Benutzers in eine grafische Oberfläche, so dass permanent neue SQL-Befehle entstehen. Das Datenbank-Tuning wird dadurch vereinfacht, dass z.B. ein neu kreierter Index sofort von allen Anwendungen benutzt werden kann, wenn die Benutzung aus der Sicht des Optimizers Sinn macht. Um die Performance des dynamischen SQLs zu optimieren, wird beim Oracle Server der einmal bestimmte Ausführungsplan in einem dafür vorgesehenen Teil der SGA, dem Shared Pool, abgelegt. Somit kann generell in der PARSE-Phase Zeit eingespart werden, indem zunächst überprüft wird, ob der Befehl bereits im Shared Pool abgelegt ist und vom aktuellen Benutzer ohne Verletzung der Zugriffsrechte benutzt werden kann. Die Suche des SQL-Befehls im Shared Pool erfolgt mit Hilfe eines Hash-Algorithmus recht schnell, so dass bei einem Nichtvorhandensein kein allzu großer Nachteil entsteht. Die größten Vorteile des Shared Pools entstehen aus der Verwendung des Oracle Server mit fest programmierten SQL-Befehlen in den Anwendungen im Mehrbenutzerbetrieb: Diese werden nur einmal übersetzt und dann immer wieder verwendet. Da aber auch die vom Oracle Server intern generierten SQL-Befehle, so genannte rekursive SQL-Befehle, über den Shared Pool abgewickelt werden, können bei praktisch allen Anwendungen die Vorteile des Shared Pools genutzt werden. Der Effekt eines gut gefüllten Shared Pools vereint die Vorteile von dynamischem und statischem SQL: Die Flexibilität des dynamischen SQL erreicht fast die Performance von statischem SQL. Die OPEN-Phase In der OPEN-Phase wird lediglich die Datenstruktur des Cursors bereitgestellt und initialisiert. In einigen Programmierumgebungen wird die nachfolgende PARSEPhase automatisch beim OPEN ausgeführt. Die PARSE-Phase Die PARSE-Phase dient zur Vorbereitung der Ausführung eines SQL-Befehls. In der PARSE-Phase wird der zu bearbeitende SQL-Befehl als Zeichenkette an den Oracle Server geschickt und dort zunächst einmal analysiert. Wird der Befehl im Shared Pool gefunden und kann er verwendet werden, wird die PARSE-Phase sofort erfolgreich beendet. Ansonsten erfolgt eine Syntaxprüfung (Ist der Befehl korrekt formuliert?), die Auswertung der betroffenen Datenbankobjekte (Tabellen, Views, Sequenzen usw.) inklusive einer Zugriffsprüfung (Darf der Benutzer auf die Objekte
Sandini Bib
470
Optimierung
zugreifen?) sowie die Bestimmung eines Ausführungsplans durch den Optimizer (Welches Objekt wird zuerst gelesen, welche Indizes werden benutzt?). Der Ausführungsplan und der SQL-Befehl werden im Shared Pool abgelegt. Nun ist der Befehl fertig zur Ausführung. Binden der Eingabevariablen Bevor der SQL-Befehl endgültig ausgeführt werden kann, müssen eventuell vorhandene Eingabevariablen an Werte gebunden werden, d.h., die Werte werden als Parameter an den Oracle Server übertragen. Ein SQL-Befehl mit einer Bindevariablen kann z.B. wie folgt aussehen: SELECT name FROM kunde WHERE kdnr = :b1;
Vor der Ausführung des Befehls muss die Variable b1 mit einem Wert gefüllt werden. Die EXECUTE-Phase Die EXECUTE-Phase kann nur nach einer erfolgreichen PARSE-Phase durchgeführt werden. In allen SQL-Befehlen außer dem SELECT-Befehl verbirgt sich hier die komplette Befehlsausführung. Zunächst wird auf jeden Fall der Lesekonsistenzzeitpunkt gesetzt. Hierzu wird ein interner Zeitstempel, die System Change Number (SCN), im Cursor vermerkt, so dass die Möglichkeit besteht, die SCN mit derjenigen von eventuellen Änderungen an Datensätzen zu vergleichen. Sobald im späteren Verlauf der EXECUTE-Phase oder in der FETCH-Phase Datensätze gelesen werden, die nach der vermerkten SCN verändert worden sind, werden automatisch die Daten so rekonstruiert, wie sie zum Zeitpunkt der vermerkten SCN waren. Damit wird sichergestellt, dass ein SQLBefehl immer lesekonsistent arbeitet, d.h., aus Sicht des Befehls haben sich die Daten seit Befehlsstart nicht verändert. Dies ist notwendig, um nachvollziehbare, richtige Ergebnisse zu erhalten. Beim SELECT-Befehl hängt der Umfang der Arbeit, die zusätzlich in der EXECUTEPhase zu tun ist, von der Art des Befehls ab. Sind etwa Sortierungen oder Gruppierungen vorzunehmen, so erfolgen diese Operationen in der EXECUTE-Phase. Die aufbereitete Ergebnismenge wird dann in einem Temporärbereich so zur Verfügung gestellt, dass in der nächsten Phase sofort die ersten Datensätze übertragen werden können. Alle anderen Befehle werden nach dem Setzen des Lesekonsistenzzeitpunkts vollständig abgearbeitet. Die FETCH-Phase Diese Phase wird ausschließlich für SELECT-Befehle durchgeführt, da alle anderen Befehle mit der EXECUTE-Phase abgeschlossen sind. Bei SELECT-Befehlen werden in der FETCH-Phase die Ergebnisdatensätze an die Anwendung übertragen. Dabei wird entweder aus den Daten- und Indexblöcken oder aus dem in der EXECUTE-Phase vorbereiteten Temporärbereich gelesen.
Sandini Bib
Monitoring und Engpassanalyse
471
Eine Spezialität der Client-Server-Funktionalität des Oracle Server ist der Array Fetch, bei dem ein Array von Ergebnisdatensätzen anstatt eines einzigen Datensatzes übertragen wird. Hierzu ist anzumerken, dass der ANSI-Standard die Übertragung eines Datensatzes pro FETCH vorsieht. In Netzwerkumgebungen ist jedoch die Optimierung des Übertragungsverhaltens von entscheidender Bedeutung – nicht nur in Bezug auf die Performance einer einzelnen Anwendung, sondern auch im Sinne aller Netzwerkbenutzer auf die gesamte Netzwerkauslastung. Somit ist die Verwendung des Array Fetch-Mechanismus uneingeschränkt zu empfehlen. Die CLOSE-Phase Wenn der Cursor nicht mehr gebraucht wird, kann er durch ein CLOSE beendet und entfernt werden. Das Schließen eines Cursors sollte allerdings nur dann durchgeführt werden, wenn der Cursor mit Sicherheit nicht mehr benutzt wird. Ansonsten kann z.B. mit dem Binden anderer Werte an die Variablen neu eingestiegen werden, wenn der SQL-Befehl mit anderen Variablen nochmals ausgeführt werden soll. Damit kann die recht aufwändige PARSE-Phase eingespart werden.
7.2
Monitoring und Engpassanalyse
Zur Unterstützung des Datenbankadministrators für das Monitoring von OracleSystemen bieten mehrere Hersteller Werkzeuge an, die Grafiken und Listen, zumeist unter MS-Windows-Oberflächen, erstellen. Zu diesen Werkzeugen zählen z.B. das Tuning-Pack des Oracle Enterprise Managers, Quest Spotlight on Oracle und SQLab Vision, BMC Patrol, Keeptool HORA oder Precise. Hinweise dazu sind in Kapitel 9 beschrieben, das sich generell mit Monitoring auseinander setzt. Diese Werkzeuge fahren unterschiedliche Ansätze. Einige greifen auf die virtuellen Performance-Tabellen (V$-Tabellen) zu, die Strukturen der Oracle-SGA abbilden. Diese Zugriffe erzeugen Last im Oracle-System und können bei nicht angepasster Parametrierung bezüglich der Überwachungsintervalle selbst eine Quelle erhöhten Ressourcenbedarfs sein. Andere greifen direkt SGA-Strukturen ab, so dass keine Last für die Oracle-Instanz erzeugt wird. Alle Werkzeuge haben gemeinsam, dass sie lizenziert werden müssen. Die Lizenzgebühren leiten sich zumeist aus den Oracle-Lizenzstufen ab, so dass gerade für große Systeme mit erheblichen Kosten gerechnet werden muss. Die Informationen können aber auch durch SQL-Scripts über die v$-Tabellen abgegriffen werden. Im Laufe der Zeit wird ein Datenbankadministrator sich eine Sammlung solcher Scripts erstellen, die auch oft in der Literatur zum Thema OracleTuning zu finden sind bzw. von Internetseiten der Autoren geladen werden können. Die Ausgabe solcher Scripts muss natürlich so formatiert werden, dass der Administrator schnell die wichtigen Informationen erkennen kann. Hier ist sicher ein Nachteil zu den farbigen Grafiken der Werkzeuge zu sehen, jedoch sind die Ausgaben der Scripts auch nicht überfrachtet und liefern direkt die gewünschten Informationen.
Sandini Bib
472
Optimierung
In diesem Kapitel wird ausschließlich die Nutzung von SQL-Befehlen und Scripts beschrieben, da wir nicht davon ausgehen können, dass jedem Leser ein solches Werkzeug zur Verfügung steht und wir auch keine Gebrauchsanweisung eines dieser Werkzeuge liefern, sondern einen generellen Überblick über die Tuning-Möglichkeiten geben möchten.
7.2.1
utlbstat/utlestat
utlbstat und utlestat sind SQL-Scripts, die seit Oracle Version 6 mitgeliefert werden und im Verzeichnis $ORACLE_HOME/rdbms/admin (Unix), bzw. %ORACLE_HOME%\rdbms\admin (MS-Windows) zu finden sind. bstat und estat stehen für
begin statistics und end statistics. Sie dienen hauptsächlich dazu, die Parametrierung der Instanz zu überwachen, d.h. die Auslastung der einzelnen Ressourcen der Instanz darzustellen. Jedoch sind auch Hinweise auf Probleme der Anwendung in der Ausgabe zu finden. Sie werden aus SQL*Plus heraus gestartet. SQL> @$ORACLE_HOME/rdbms/admin/utlbstat
Erster Schritt ist eine Anmeldung mit connect / as sysdba, um sicherzustellen, dass auf sämtliche Data Dictionary-Information zugegriffen werden kann. Das Script erstellt nun eine Reihe von Tabellen mit dem Präfix STATS$, in die Informationen aus verschiedenen v$-Tabellen abgelegt werden. Die Beobachtungsintervalle sollten sich zwischen 30 und 60 Minuten bewegen. Nach dieser Zeit wird die Beendigung der Beobachtung gestartet. SQL> @$ORACLE_HOME/rdbms/admin/utlestat
Dieses Script erstellt einen erneuten Abzug aus den v$-Tabellen und legt einen Satz von Auswertungstabellen an, auch mit dem Präfix STATS$. Die Veränderungen zwischen dem Start und dem Ende der Beobachtung werden nun durch SELECTBefehle ausgewertet und über SPOOL in eine Datei report.txt geschrieben (aktuelles Verzeichnis bei UNIX-Plattformen oder Arbeitsverzeichnis bei MS-Windows). Anschließend werden alle STATS$-Tabellen wieder gelöscht. Ausgabe Auf die Formatierung des Reports ist nicht viel Wert gelegt worden. So sind Überschriften nicht gut angepasst worden, die SQL-Befehle und Formatierungsanweisungen werden nicht unterdrückt. In den Kommentaren vor jedem SQL-Befehl sind jedoch Informationen über die Inhalte der Listen und Hinweise gegeben, die bei der Interpretation des Reports helfen. Folgende Listen und Ausgaben sind im Report enthalten:
:
Library Cache-Statistiken Hier ist die Trefferrate im Dictionary Cache (SGA-Bereich im Shared Pool) für die einzelnen Komponenten zu sehen. Wünschenswert sind Trefferraten nahe 1 (100 %). Eine Verbesserung ist über die Vergrößerung der Shared Pools (shared_pool_size) zu erreichen.
Sandini Bib
Monitoring und Engpassanalyse
: :
473
Anzahl angemeldeter Anwender Diese Liste ist recht kurz und zeigt die Anzahl der angemeldeten Benutzer zum Zeitpunkt der Abzüge der v$-Tabellen. Daraus wird das arithmetische Mittel errechnet, das aber vom Informationsgehalt irrelevant ist. Informationen aus v$sysstat In dieser Liste sind die umfangreichsten und interessantesten Informationen zu finden, die aber größtenteils noch in Formeln gesteckt werden müssen, um interpretierbare Ergebnisse zu erhalten. Hier können nur die wichtigsten Punkte erläutert werden. Die Trefferrate im Database Buffer Cache kann berechnet werden aus 100 – ((physical reads / (consistent gets + db block gets)) * 100)
Des Weiteren ist parse count und parse time cpu zu beachten. Hier können Rückschlüsse auf die Effektivität der Anwendung gezogen werden, wenn die Zahlen im Verhältnis zum execute count gesetzt werden. Execute count im Verhältnis zu den consistent gets liefert erste Anhalts-
punkte über die Effektivität der Statements. Weitere Informationen über die Zugriffspfade der Anwendungen erhalten Sie aus den Statistikinformationen table fetch by rowid und table scan rows gotten. Werden sehr viele Zeilen über Full-Table-Scans gelesen, sollte aus v$sysstat ausgelesen werden, ob es sehr viele Full-Table-Scans auf große Tabellen gibt, und wenn ja, sollten die Anwendungen weiter untersucht werden. SQL> SELECT name,value FROM v$sysstat WHERE name LIKE 'table scan%'; Listing 7.1: v$sysstat
:
Die Statistiken redo size und redo sync time geben Aufschluss über die Transaktionslast und die Durchsätze auf die Redolog-Dateien. Stellt man die redo size der Zeit des Messintervalls gegenüber, kann man kalkulieren, wie lange in eine Redolog-Datei bis zum nächsten Wechsel geschrieben werden kann. Wait-Events für Anwenderprozesse Bei den Wait-Events sind nur die Wartezustände von Interesse, die die Performance verschlechtern. Warten auf SQL*Net message from client ist natürlich kein problematischer Wartezustand, da ja nicht auf Ressourcen gewartet wird, sondern auf eine Aktivität. Hingegen sind Wartezustände wie db file sequential read oder db file scattered read Indikatoren auf Probleme im I/O-Bereich, die näher untersucht werden müssen.
Sandini Bib
474
:
:
Optimierung
Wait-Events für Datenbank-Hintergrundprozesse Auch bei den Hintergrundprozessen sind hauptsächlich die Wartezustände für reads und writes von Interesse. Sollten hier Probleme erkennbar sein, werden dann wahrscheinlich auch für die Anwenderprozesse dementsprechende Probleme protokolliert. Latch Statistiken/No-Wait-Latches Latches sind sehr kurzlebige Sperren für Oracle-Blöcke in der SGA. Die Liste zeigt, wie oft ein Latch zum Sperren angefordert wurde und wie oft er dabei nicht allokiert werden konnte. Besonders bremsend machen sich sleeps bemerkbar. Kann ein Prozess einen angeforderten Latch nicht bekommen, so wird dieser Prozess in einen Schlafzustand versetzt und zu einem späteren Zeitpunkt wieder geweckt. Diese Vorgänge sind für die Systeme sehr belastend. Bei Multiprozessorsystemen versucht man sleeps zu vermeiden, indem man, gesteuert durch den Initialisierungsparameter spin_count (Standard ist 2000), den Prozess in einer Schleife versuchen lässt, den Latch zu bekommen, bevor man ihn dann schlafen schickt. Besonders zu beachten sind Latch-Events wie cache buffer chain, cache buffer lru, redo allocation, library cache oder shared pool. Für die Beseiti-
:
:
:
gung der Latch-Waits kann bei den Cache-Events die Parametrierung der Instanz geändert werden, bei Events wie library cache oder shared pool sollte die Anwendung auf die Verwendung von Bindevariablen und unnötiges Parsing der SQL-Befehle hin untersucht werden. Buffer-Busy-Wait-Statistik In der Buffer-Busy-Wait-Statistik werden die verschiedenen Block-Klassen aufgelistet. Gibt es z.B. Wartezustände auf undo header, bedeutet dies, dass es zu wenige Rollback-Segmente gibt. Werden segment header angezeigt, kann dies auf zu wenige Freelists hinweisen. Rollback-Segment-Statistiken Hier ist die einzig interessante Information trans_tbl_waits, die aber nichts anderes aussagt als vorher der Wartezustand auf undo header. Leider wird hier nicht die Information über die durchschnittliche Größe der Rollback-Segmente dem Wert OPTIMAL gegenübergestellt, um diesen passend zu parametrieren. Diese sollten Sie über die View v$rollstat abfragen und dabei die Felder avgactive und optsize in Beziehung setzen. Liste der geänderten Initialisierungsparameter Diese Liste zeigt alle Initialisierungsparameter an, die von der Standardeinstellung abweichen. Es ist dabei nicht zwingend, dass es nur die Parameter sind, die Sie in der Datei init<sid>.ora oder im SPFILE modifiziert haben. Auch ohne Modifikationen weichen einige Parameter vom Standard ab, da sie zum Beispiel für die Oracle-Version auf dem jeweiligen Betriebssystem angepasst worden sind.
Sandini Bib
Monitoring und Engpassanalyse
:
475
Tablespace- und Datei-I/O-Statistik Abschließen sind noch die Statistiken über Aktivitäten auf den einzelnen Tablespaces und Datendateien interessant. Aus den Werten ist abzulesen, ob sich Aktivitäten auf einzelnen Teilen den Datenbank zu sehr bündeln. In diesem Fall sollte die Möglichkeit einer besseren Verteilung untersucht werden. Sind es nur die I/O-Zeiten, die zu Bedenken Anlass geben, so muss das I/O-System näher untersucht werden.
Vor- und Nachteile Der Report ist nicht ohne weitere Kalkulationen nutzbar und setzt ein hohes Grundverständnis voraus, um sinnvolle Maßnahmen zu definieren. Sie können sich aber auch eine Kopie des utlestat.sql-Scripts anfertigen, in der Sie die interessantesten Berechnungen ergänzen und den Report so an Ihre Anforderungen anpassen. Es kann auch lediglich ein Intervall betrachtet werden, da utlestat.sql ja die Tabellen löscht, die die Informationen temporär gespeichert haben. Der Vorteil der Nutzung dieser Scripts ist, dass sie ad hoc, ohne die Installation und Einrichtung von Scripts, Tabellen und spezieller Schemas, auf jeder Datenbank durchgeführt werden kann und die wichtigen Informationen, wenn auch nicht perfekt formatiert, auf jeden Fall liefert.
7.2.2
Statspack
Statspack ist die Weiterführung von utlbstat/utlestat, die die eben geschilderten Nachteile dieser Scripts aufhebt. Vielleicht sind einigen Lesern Scripts mit den Namen NST7... oder NST8... in Erinnerung, die von Oracle-Mitarbeitern zur Zeit der Versionen 7 und 8 erstellt wurden und von Oracle oder über die DOAG herausgegeben wurden. Oracle liefert nun Scripts und Prozeduren aus, die in einem speziellen Schema Tabellen installieren, in die, genau wie bei utlbstat/utlestat, Abzüge aus den v$Tabellen abgelegt werden, die aber in diesem Fall mit einer Snapshot ID versehen werden. Das bedeutet, dass zu bestimmten Zeitpunkten solche Snapshots gezogen werden können, die man dann zu einem späteren Zeitpunkt in verschiedenen Intervallen auswerten kann. Installation Zur Installation von Statspack startet man, als SYSDBA angemeldet, ein Script, das einen Benutzer PERFSTAT mit identischem Kennwort anlegt. Das Script verlangt nach der Angabe eines Default Tablespace und eines Temporary Tablespace, wofür sich TOOLS und TEMP anbieten. Außerdem werden Packages installiert und Tabellen für die Abzüge aus den v$-Tabellen angelegt. SQL> connect / as sysdba
Sandini Bib
476
Optimierung
Unter Oracle 8.1.6 SQL> @?/rdbms/admin/statscre
Unter Oracle 8.1.7 und Oracle 9i SQL> @?/rdbms/admin/spcreate
Benutzung Nach der Installation der Packages können nun nach Anmeldung als Benutzer PERFSTAT Snapshots ausgeführt werden, mit denen jeweils ein Abzug der v$-Tabellen durchgeführt wird. SQL> connect perfstat/perfstat SQL> execute statspack.snap
Es bietet sich an, diese Snapshots in regelmäßigen Intervalle von 30 oder 60 Minuten zu erstellen, die natürlich wahlweise auch als Job eingestellt werden können, um auch für den nächtlichen Betrieb mit Batch-Jobs Statistiken zu sammeln. Oracle bietet dafür das Script spauto an, das über Oracle-Jobs Snapshots zu jeder vollen Stunde erstellt. SQL> connect perfstat/perfstat SQL> @?/rdbms/admin/spauto
Wenn Snapshots zu Verfügung stehen, können diese über verschiedene Intervalle ausgewertet werden. Für die Erstellung eines Reports wird ein SQL-Script aufgerufen, das die Eingabe eines Start- und eines Endpunktes verlangt und einen Namen für den Report vorschlägt, der aber auch verändert werden kann. Sie können nur Reports über Start- und Endpunkte bilden, zwischen denen die Instanz nicht gestoppt worden ist, da ja bei einem Start einer Instanz die v$-Tabellen neu initialisiert werden und daher eine Auswertung über ein solches Intervall unsinnig wäre. Unter Oracle 8.1.6 SQL> @?/rdbms/admin/statsrep
Unter Oracle 8.1.7 und Oracle 9i SQL> @?/rdbms/admin/spreport
Einstellungen und Pflege der Tabellen Wie viele Informationen gesammelt werden, hängt von einer Einstellung ab. Ein „Snap“ kennt verschiedene Levels, Standardeinstellung ist 5. Diese Einstellung ist durchaus sinnvoll, da schon umfangreiche Informationen über die Instanz und auch aufwändige SQL-Befehle geliefert werden.
Sandini Bib
Monitoring und Engpassanalyse
477
Möchte man dennoch weitergehende Informationen über SQL-Befehle mit Ausführungsplänen haben, kann die Einstellung des Levels über eine Prozedur verändert werden. Für eine einmalige Ausführung: SQL> execute statspack.snap(I_snap_level=>6);
Permanent: SQL> execute statspack.snap(I_snap_level=>6, i_modify_parameter=>'true');
Es existieren weitergehende Einstellungen, die Schwellenwerte für die Beobachtung der kritischen SQL-Befehle beinhalten und aus der Tabelle STATS$STATSPACK_PARAMETER abgelesen werden können. Auch diese können über eine Prozedur modifiziert werden. Beispiel: SQL> execute statspack.modify_statspack_parameter (i_snap_level=>10, i_buffer_gets_th=>10000, i_disk_reads_th=>1000);
Je mehr Informationen gesammelt werden, desto mehr Platz wird natürlich in den Tabellen zur Zwischenspeicherung benötigt. Daher sollten Sie den verfügbaren Platz im Default-Tablespace des Benutzers PERFSTAT überwachen und nach erfolgten Auswertungen nicht mehr benötigte Snapshots löschen. Dazu stehen wiederum SQL-Scripts zur Verfügung. SQL> @?/rdbms/admin/sptrunc
löscht die gesamten Inhalte der STATS$-Tabellen oder SQL> @?/rdbms/admin/sppurge
löscht einen anzugebenden Bereich von Snapshots. Diese Scripts standen vor Oracle 8.1.7 nicht zur Verfügung. Bis zu dieser Version setzen Sie einen DELETE-Befehl auf die Tabelle STATS$SNAPSHOT mit Angabe von SNAP_IDs ab, die dann über kaskadierende Löschungen auch die anderen Tabellen bereinigen. Interpretation der Ausgabe Die Interpretation der Ergebnisse ist wesentlich einfacher als bei bstat/estat. Es werden im Wesentlichen die gleichen Informationen ausgegeben, jedoch sind sämtliche Trefferraten oder sonstigen Werte, die sonst errechnet werden mussten, aufbereitet und mit guten Überschriften und Kommentaren versehen.
Sandini Bib
478
Optimierung
Auch werden WAIT-Events schon nach ihrer Relevanz geordnet als Top-5-Liste ausgegeben, ebenso wie I/O-Statistiken oder Rollback-Segment-Statistiken. Da der Report gut lesbar ist, soll er hier nicht Zeile für Zeile besprochen werden. Zusätzlich werden in diesem Report SQL-Befehle aufgelistet, die als nicht effizient beurteilt werden. Die Beurteilung erfolgt in vier Bereichen: Anzahl der verarbeiteten Blöcke, Anzahl der von der Festplatte gelesenen Blöcke, Anzahl Ausführungen und Anzahl Parse Calls. Die Schwellenwerte dafür sind einstellbar. Damit liefert Statspack neben den wichtigen Kennzahlen für das Instanz-Tuning auch wertvolle Hinweise auf verbesserungswürdige SQL-Befehle, die einer Zugriffsoptimierung unterzogen werden sollten. Wichtiger Bestandteil der Ausgabe ist auch die Beschreibung des Snap-Intervalls. Bei der Interpretation des Reports sollten Sie immer berücksichtigen, dass es sich bei den kalkulierten Werten um ein Mittel über das Snap-Intervall handelt. So kann zum Beispiel die Trefferrate im Buffer-Cache der SGA über den Tag gesehen sehr gut sein, jedoch knickt diese in einem kleineren Zeitintervall im Laufe des Tages dramatisch ein und führt zu schlechter Performance. Gerade hierin liegt unter anderem die Stärke von Statspack, da Snapshots in regelmäßigen Intervallen abgesetzt werden können, Auswertungen sich aber über beliebige verfügbare Intervalle erstrecken können.
7.2.3
SQL-Area
In der SQL-Area als Bestandteil des Shared Pools, einem Bereich in der SGA, sind SQL-Befehle in kompilierter Form abgelegt. Zusätzlich zu den SQL-Texten werden Informationen über den Hauptspeicherbedarf der einzelnen Befehle gepflegt, aber auch Statistiken über die Ausführungen. Diese Informationen können vom Datenbankadministrator direkt aus der View v$sqlarea gewonnen werden. Von Interesse sind die Informationen, wann der Befehl das erste Mal ausgeführt worden ist, wie oft er seitdem ausgeführt wurde, wie viele Oracle-Blöcke im Hauptspeicher dafür gelesen werden mussten und wie viele Oracle-Blöcke dafür über einen Plattenzugriff gelesen werden mussten. Der folgende SQL-Befehl, dessen Ausgabe Sie natürlich noch formatieren können, listet Ihnen die SQL-Befehle aus der SQL-Area auf, die einen hohen Ressourcenverbrauch erzeugen. Die Anzahl der gelesenen Blöcke pro Ausführung sollte natürlich immer so gering wie möglich sein. Mit dieser Zahl korreliert die Ausführungsgeschwindigkeit eines SQL-Befehls. Plattenzugriffe werden die Ausführungszeit zusätzlich in die Höhe treiben, auch wenn nur geringfügig mehr CPU-Zeit verbraucht wird. SQL> SELECT address, first_load_time, executions, disk_reads, buffer_gets, buffer_gets / executions FROM v$sqlarea WHERE executions > 0 AND buffer_gets/executions > 100000 ORDER BY buffer_gets / executions; Listing 7.2: v$sqlarea
Sandini Bib
Monitoring und Engpassanalyse
479
Sie werden also am Ende dieser Liste die Adressen der kritischen Befehle finden, wobei die Grenze der gelesenen Blöcke pro Ausführung natürlich variabel eingetragen werden soll. Die SQL-Befehle selbst können aus einer weiteren View v$sqltext abgelesen werden, die 80 Byte-Stücke der Befehle beinhaltet. SQL> SELECT FROM WHERE ORDER
address, piece, sql_text v$sqltext address = &addr BY piece;
Listing 7.3: v$sqltext
Die Adresse wird aus der Ausgabe des ersten Befehls übernommen. Zu berücksichtigen ist jedoch, dass die SQL-Area nur eine beschränkte Anzahl von SQL-Befehlen abhängig von ihrer Größe beherbergt. Die Zuordnung der Befehle zu Anwendungen erweist sich in der Praxis nicht immer als leicht und wird oftmals nur mit der Unterstützung von Entwicklern möglich sein. Diese Methode ermöglicht es aber dem Administrator auf einfache Art und Weise, aufwändige SQL-Befehle zu ermitteln, ohne eine gesamte Anwendung oder einen Prozess mit Tracing zu belegen.
7.2.4
Anwendungs-Tracing und TKPROF
Anwendungs-Tracing, auch SQL-Tracing genannt, beschreibt die Aufzeichnung von SQL-Befehlen von Prozessen und deren Ausführungsstatistiken. AnwendungsTracing ist immer dann angezeigt, wenn Anwender sich über Antwortzeiten einer Anwendung beschweren und die Quelle der schlechten Performance lokalisiert werden muss, aber auch, wenn ein Anwendungsentwickler oder ein Datenbankadministrator Ausführungspläne und Statistiken für SQL-Befehle ermitteln möchten. Anwendungs-Tracing kann auf Prozessebene oder auf Datenbankebene eingeschaltet werden. Prozess-Tracing Für jede Oracle-Sitzung kann das Tracing der SQL-Befehle über ein alter sessionKommando eingeschaltet werden. SQL> alter session set sql_trace = true;
Das Kommando kann auch aus beliebigen Anwendungen heraus abgesetzt werden, jedoch bietet sich in der Praxis das Problem, dass Anwendungen keinen Schalter besitzen, mit dem ein SQL-Tracing aktiviert werden kann und eine nachträgliche Implementierung gerade in Standardprodukte oder auch Individualsoftware nicht oder nur schwer möglich ist. Dieser Befehl wird aber vom Entwickler oder Datenbankadministrator genutzt werden, der SQL-Befehle, die er näher untersuchen möchte, in einem Script separiert hat.
Sandini Bib
480
Optimierung
Für Anwendungen bietet sich eher die Möglichkeit an, das SQL-Tracing von außen für eine Oracle-Sitzung an- und auszuschalten. Dafür steht das Package DBMS_SYSTEM mit der Prozedur SET_SQL_TRACE_IN_SESSION zur Verfügung, die allerdings seit Oracle 8.1.6 nicht mehr dokumentiert ist, die aber nach wie vor funktioniert und auch in Oracle9i-Foren erwähnt wird. Für die Parametrierung der Prozedur müssen sid und serial# der Sitzung bekannt sein. Sollte eine Sitzung über username aus v$session nicht eindeutig identifiziert werden können, bietet es sich an, die Spalten terminal, program und module mit ausgeben zu lassen. SQL> select username, sid, serial# from v$session; USERNAME SID SERIAL# ------------------------------ ---------- ---------1 1 2 1 3 1 4 1 5 1 6 1 7 1 DEMO 8 30 Listing 7.4: v$session
Für den Benutzer DEMO wird das SQL-Tracing aktiviert mit: SQL> execute dbms_system.set_sql_trace_in_session(8,30,TRUE);
Nach einer gewünschten Beobachtungszeit wird deaktiviert über: SQL> execute dbms_system.set_sql_trace_in_session(8,30,FALSE);
Sollte die Sitzung beendet werden, ist das Tracing automatisch beendet. Das Protokoll des Tracings wird in das Verzeichnis geschrieben, das über den Initialisierungsparameter user_dump_dest eingestellt ist. Die Namen der erzeugten Trace-Dateien variieren je nach Betriebssystem. Bestandteil des Namens ist die Betriebssystem-Prozessnummer des Oracle Serverprozesses. In der Praxis sucht man im Filesystem nach einer Datei mit der Endung .trc, die einen Zeitstempel zum Ende des Tracings trägt. Unter UNIX kann dazu der Befehl ls –ltr verwendet werden. Datenbank-Tracing Anwendungs-Tracing kann auch für die gesamte Oracle-Instanz aktiviert werden. Die Aktivierung erfolgt über den Initialisierungsparameter sql_trace = true. Der Parameter ist statisch, kann also nur zum Start einer Instanz gesetzt werden. Ist der Parameter gesetzt, wird jeder Prozess protokolliert. Dadurch kann es zu nicht unerheblichen Belastungen des System kommen, sowohl in Bezug auf die CPU als
Sandini Bib
Monitoring und Engpassanalyse
481
auch auf den I/O, besonders auf der Platte, auf die der Parameter user_dump_dest verweist. Zudem wird unter Umständen enorm viel Platz auf dieser Platte benötigt. Die Größe der Trace-Dateien lässt sich über den Initialisierungsparameter max_dump_file_size begrenzen. Die Auswertung einer solchen Menge von Trace-Dateien ist natürlich auch problematisch, da auch im Nachhinein eine Zuordnung zu Anwendungen und Anwendern schwierig ist. Diese Möglichkeit bietet sich also nur für Testsysteme an, auf denen festgelegte Anwendungen auf die Performance untersucht werden sollen. TKPROF Der Inhalt einer Trace-Datei ist kryptisch, kann also nicht einfach interpretiert werden. Für die Aufbereitung der Trace-Dateien wird ein Werkzeug mitgeliefert, TKPROF. Das ausführbare Programm ist unter $ORACLE_HOME/bin zu finden und kann über die Shell eines UNIX-Systems oder über die MS-Windows-Kommandoebene aufgerufen werden. Wird das Werkzeug ohne Parameter aufgerufen, wird eine Hilfe mit der möglichen Parametrierung geboten. Aufruf: $ tkprof ora00391.trc out.tkp explain=username/passwd sort=fchqry ora00391.trc
Name der Trace-Datei, die ausgewertet werden soll.
out.tkp
Ausgabedatei der Auswertung, hier muss auf die Schreibberechtigung geachtet werden.
explain
Gibt an, dass die Ausführungspläne der SQL-Befehle in der TraceDatei ermittelt werden sollen. Es muss ein Benutzername und dessen Passwort angegeben werden. Hier sollten Sie darauf achten, dass es der Benutzer ist, unter dem auch die Anwendung während des Tracings ausgeführt worden ist, damit sichergestellt ist, dass es sich um die gleichen Schema-Objekte handelt. Der Ausführungsplan ist nicht in der Trace-Datei abgelegt, sondern wird zum Zeitpunkt des TKPROF-Aufrufs ermittelt. Vorsicht: Nach dem Tracing angelegte oder gelöschte Indizes verfälschen den Ausführungsplan.
sort
Die Befehle können in der Ausgabedatei nach verschiedenen Kriterien sortiert werden. Wird nichts angegeben, werden sie in der Reihenfolge der Ausführung dargestellt. Sortiert werden kann nach Zeitverbrauch oder der Anzahl von gelesenen Blöcken in den drei Phasen der SQL-Befehle: PARSE, EXECUTE oder FETCH.
Beispiele: prscpu
CPU-Zeitverbrauch für SQL-Parsing
exeela
Verweilzeit für Ausführung (meist bei DML)
fchqry
Anzahl gelesener Oracle-Blöcke (Select)
Sandini Bib
482
Optimierung
Durch die optionale Angabe SYS=NO können rekursive Befehle des Benutzers SYS aus der Ausgabe herausgefiltert werden. Zusätzlich zu den Statistiken eines SQL-Befehls wird, falls durch explain=username/passwd angefordert, der Ausführungsplan dargestellt. Die Interpretation von Ausführungsplänen wird unter 7.3.2 näher erläutert. Beispiel: tkprof ora00031.trc out1.tkp explain=demo/demo sys=no Optimizer goal: CHOOSE Parsing user id: 26 (DEMO) *************************************************************** SELECT k.kd_ort, SUM(p.pos_menge * p.pos_einzelpreis) AS umsatz FROM kunden k, auftraege a, positionen p WHERE k.kd_nr = a.auf_kdnr AND a.auf_nr = p.pos_aufnr AND UPPER(k.kd_nachname) = 'AHRENDS' AND UPPER(k.kd_vorname) = 'MARLIES' GROUP BY k.kd_ort call count cpu elapsed disk query current rows ------- ------ ----- -------- ------- ------- -------- -----Parse 1 0.04 0.02 0 15 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 1.85 8.77 27771 28142 0 1 ------- ------ ----- -------- ------- ------- -------- -----total 4 1.90 8.79 27771 28157 0 1 Misses in library cache during parse: 1 Optimizer goal: CHOOSE Parsing user id: 26 (DEMO) Rows Row Source Operation ------- --------------------------------------------------1 SORT GROUP BY 27 HASH JOIN 9 HASH JOIN 1 TABLE ACCESS FULL KUNDEN 1000000 TABLE ACCESS FULL AUFTRAEGE 2502684 TABLE ACCESS FULL POSITIONEN
Sandini Bib
Monitoring und Engpassanalyse
Rows Execution Plan ------- --------------------------------------------------0 SELECT STATEMENT GOAL: CHOOSE 1 SORT (GROUP BY) 27 HASH JOIN 9 HASH JOIN 1 TABLE ACCESS GOAL: ANALYZED (FULL) OF 'KUNDEN' 1000000 TABLE ACCESS GOAL: ANALYZED (FULL) OF 'AUFTRAEGE' 2502684 TABLE ACCESS GOAL: ANALYZED (FULL) OF 'POSITIONEN' **************************************************************** ... *************************************************************** OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ ----- -------- ------- ------- -------- -----Parse 6 0.04 0.02 0 15 0 0 Execute 7 0.00 0.00 0 6 9 7 Fetch 5 1.85 8.77 27771 28164 0 8 ------- ------ ----- -------- ------- ------- -------- -----total 18 1.90 8.80 27771 28185 9 15 Misses in library cache during parse: 5 Misses in library cache during execute: 1 OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ------ ----- -------- ------- ------- -------- -----Parse 18 0.03 0.01 0 0 0 0 Execute 45 0.00 0.01 0 2 8 7 Fetch 66 0.00 0.00 0 104 0 37 ------- ------ ----- -------- ------- ------- -------- -----total 129 0.03 0.02 0 106 8 44 Misses in library cache during parse: 14 Misses in library cache during execute: 1 8 17 25 5
user SQL statements in session. internal SQL statements in session. SQL statements in session. statements EXPLAINed in this session.
*************************************************************** Trace file: ora00031.trc Trace file compatibility: 9.00.01 Sort options: default
483
Sandini Bib
484
Optimierung
3 11 32 25 20 5
sessions in tracefile. user SQL statements in trace file. internal SQL statements in trace file. SQL statements in trace file. unique SQL statements in trace file. SQL statements EXPLAINed using schema: DEMO.prof$plan_table Default table was used. Table was created. Table was dropped. 363 lines in trace file. Trace file: ora00031.trc Trace file compatibility: 9.00.01 Sort options: default 3 11 32 25 20 5
sessions in tracefile. user SQL statements in trace file. internal SQL statements in trace file. SQL statements in trace file. unique SQL statements in trace file. SQL statements EXPLAINed using schema: DEMO.prof$plan_table Default table was used. Table was created. Table was dropped. 363 lines in trace file. Listing 7.5: TKPROF-Ausgabe
Interpretationsproblematiken:
:
:
Falsche Ausführungspläne durch implizite Datentypkonvertierungen TKPROF kennt nicht die Inhalte von Bindevariablen und daher auch nicht die verwendeten Datentypen. Es ist daher möglich, dass in der TKPROF-Ausgabe ein Ausführungsplan angezeigt wird, der aber nicht den tatsächlichen Ausführungsplan abbildet, weil sich durch implizite Datentypkonvertierungen, die immer auf Seite der Tabellenfelder ausgeführt werden, dieser Zugriff nicht realisieren lässt. Diese Diskrepanz ist nur anhand der Statistiken festzustellen, wenn z.B. trotz angezeigter Indexbenutzung die Anzahl der gelesenen Blöcke zu hoch erscheint. Anzahl gelesener Blöcke bei Lesekonsistenz Zu beachten ist, dass die Anzahl der gelesenen Blöcke im Konsistenzmodus in der Spalte query auch die gelesenen Rollback-Segment-Blöcke beinhaltet, die für die Wahrung der Lesekonsistenz herangezogen werden mussten. So kann diese Zahl differieren, abhängig davon, ob gerade DML-Operationen von anderen Prozessen auf den beteiligten Tabellen der Abfrage durchgeführt werden.
Sandini Bib
Monitoring und Engpassanalyse
:
:
:
485
Falsche Ausführungspläne durch Änderungen am Schema Hier sei nochmals auf die Tatsache hingewiesen, dass die Ausführungspläne nicht in der Trace-Datei mit abgelegt sind, sondern bei Ausführung von TKPROF mit einem erneuten Anmelden an die Instanz unter dem Benutzer, der bei explain=u/p angegeben wird, ermittelt wird. In der Zwischenzeit angelegte oder gelöschte Indizes erzeugen daher einen Unterschied des angezeigten Ausführungsplans zur tatsächlichen Ausführung. Interpretation der elapsed time Die elapsed time wird von der CPU time häufig abweichen, gerade dann, wenn Wartezustände auf Plattenzugriffe auftreten oder der Prozess nicht permanent CPU-Zeit zugeteilt bekommen kann. Aber auch künstlich erzeugte Wartezustände auf Tabellen, wie z.B. eine exklusive Sperre auf einer Tabelle, können die Zeitinformationen ungewollt verfälschen. Höherer Ressourcenverbrauch durch Trigger In den Statistiken werden sämtliche Ressourcenverbräuche eines Befehls kumuliert, so z.B. auch Aktivitäten, die durch Trigger auf den Tabellen erzeugt werden, auf die zugegriffen wird. Daraus können auf den ersten Blick nicht erklärbare Werte in den Statistikinformationen entstehen.
7.2.5
Oracle Trace
Oracle Trace ist ein Werkzeug, um Datenbank- oder Anwendungsinformationen in Form von sog. Events zu sammeln und entsprechend aufzubereiten. Entstanden ist das Werkzeug im Umfeld des Oracle Enterprise Managers der Version 7. Das ursprünglich durch die Übernahme der DEC-RDB-Produktreihe eingekaufte Werkzeug RDB-Trace findet hier seine Wiederverwendung. Allerdings war schon in der Version 7 und auch in späteren Versionen des Enterprise Managers die Verwendung von Oracle Trace sehr schwierig, wenn nicht unmöglich. Das hat sich bis zum heutigen Tag nicht geändert, und zu Recht gibt es in der aktuellen Oracle-Dokumentation den Hinweis, Oracle Trace nicht mehr zu verwenden, sondern TKPROF oder SQL Trace einzusetzen. Zitat Oracle9i-Dokumentation, Database Performance Tuning Guide and Referencer Kapitel 12: Note: Oracle Trace will be deprecated in a future release. Oracle Corporation strongly advises the use of SQL Trace and TKPROF instead. Einige Tests, die wir auf Basis der Dokumentation durchgeführt haben, bestätigen die mangelnde Funktionalität, daher werden wir nicht weiter auf das Produkt eingehen.
Sandini Bib
486
7.2.6
Optimierung
Oracle SQL Analyze
Wenn Sie die Oracle Enterprise Edition lizenziert haben, können Sie zusätzlich das Oracle Enterprise Manager Tuning Pack erwerben. In diesem Paket gibt es ein sehr interessantes Werkzeug, mit dem sich SQL-Statements effektiv analysieren und tunen lassen. Das Produkt – das interessanterweise nicht in Java geschrieben ist – kann über die Konsole des Enterprise Managers aufgerufen werden, hat dann aber keinen weiteren Bezug zu diesem. Die ermittelten Daten können in einen Repository abgespeichert werden, um zu einem späteren Zeitpunkt auf die Ergebnisse zurückzugreifen. Der Einstieg in das Werkzeug erfolgt – wie bei den meisten Analysewerkzeugen – in der Regel über das Auslesen des Shared Pool-Bereichs. Über den Menüpunkt TOPSQL können die kritischen Befehle auf Grund unterschiedlicher Kriterien (z.B. Plattenzugriffe pro Ausführung, Ausführungen, Sortierungen) ausgewählt werden. Dabei werden standardmäßig die Top-25-Befehle ausgegeben; alternativ kann jedoch auch jede beliebige andere Anzahl von Befehlen ausgegeben werden.
Abbildung 7.1: TopSQL
Man sollte allerdings bei der Verwendung des Werkzeuges bedenken, dass der Shared Pool über SQL-Befehle (z.B. auf v$sqlarea und v$sqltext) ausgelesen wird. Das kann bei großem Shared Pool zu langen Laufzeiten der Abfrage führen. Andere Werkzeuge, wie die Produkte SQLab Vision von Quest Software oder Precise/SQL bzw. Precise/Indepth von Precise Software, haben Agenten, die den SharedMemory-Bereich direkt auslesen und somit bei größeren Datenbanken wesentlich schneller Ergebnisse bringen. Wenn Sie dann einen Befehl gefunden haben, den zu analysieren sich lohnt, können Sie diesen mit Drag&Drop als neuen Analysebefehl ablegen. In diesem Beispiel ist es ganz offensichtlich, da ein Befehl 72.027 Datenbankblöcke von der Festplatte liest.
Sandini Bib
Monitoring und Engpassanalyse
487
Abbildung 7.2: SQL-Ausführungsplan
Das Beispiel zeigt einen SQL-Befehl, der auf nicht analysierte Tabellen zugreift. Daher wählt SQL Analyze richtigerweise zunächst den regelbasierten Optimizer und zeigt den Ausführungsplan (Explain) entsprechend an. Diese Darstellung beherrschen auch viele andere Werkzeuge von Oracle und anderen Anbietern (z.B. Oracle Topsessions oder Keeptool Hora). Die Menüleiste WERKZEUGE zeigt den eigentlichen Vorteil dieses Werkzeuges: Neben der Darstellung des Ausführungsplans können virtuelle Indizes getestet werden, Optimizer-Hints können eingepflegt und der gesamte Befehl kann umgestellt werden. Unter dem Menüpunkt SQL gibt es außerdem die Möglichkeit, Indexempfehlungen zu erhalten. Für das Beispiel wurde das Schema zunächst analysiert: SQL> execute dbms_stats.gather_schema_stats(’’); Listing 7.6: Analysieren des eigenen Schemas
Sandini Bib
488
Optimierung
Danach wurde eine Indexempfehlung generiert.
Abbildung 7.3: Indexempfehlung
Diese Empfehlung sollte aber hinsichtlich ihrer Effektivität überprüft werden. Das obige Beispiel zeigt auch warum: „Es war mindestens eine Referenz durch SELECT-, ORDER-BY- oder GROUP-BY-Klauseln vorhanden.“ Der daraus resultierende Index ist wenig hilfreich, da er Spalten aus der WHEREKlausel (KD_NR) und aus dem GROUP-BY-Zweig miteinander mischt. Das Einfügen der ermittelten Indizes liefert danach folgendes Ergebnis:
Sandini Bib
Monitoring und Engpassanalyse
489
Abbildung 7.4: Neuer Index
Man erkennt, dass der auf der Tabelle kunden eingeführte Index überhaupt nicht genutzt wird. Zwar ist die Gesamtlaufzeit des Befehls durch die Indizes auf die Tabellen auftraege und positionen erheblich besser geworden, allerdings werden immer noch 2.230 Datenbankblöcke von der Festplatte gelesen (Tab-Reiter: STATISTIKEN). In diesem Fall wäre ein Function-based Index auf die Spalten kd_nachname und kd_vorname sinnvoller. Bitte beachten Sie, dass hierfür der Initialisierungsparameter query_rewrite_enabled = true gesetzt sein muss und der Benutzer das Recht bekommen muss, diese Indizes zu nutzen: SQL> GRANT QUERY REWRITE TO ;
Danach kann der Index aufgebaut werden: CREATE INDEX demo.kunden_func_idx_001 ON demo.kunden (UPPER(kd_nachname), UPPER(kd_vorname)) TABLESPACE ts_demO; Listing 7.7: Function-based Index
Sandini Bib
490
Optimierung
Danach sieht der Ausführungsplan so aus:
Abbildung 7.5: Ausführungsplan mit Function-based Index
Schon an den Kosten (15 zu 462) ist zu erkennen, dass dieser Ausführungsplan effektiver ist. Die Statistik beweist es: Es werden insgesamt noch 27 Blöcke gelesen. Anmerkung: Function-based Indizes können nur mit der Oracle Enterprise Edition genutzt werden!
7.3
Zugriffsoptimierung
Wie einleitend beschrieben, sollte die Zugriffsoptimierung der Anwendung die erste Phase des Tunings sein. Nur hier sind Faktoren in der Verarbeitungsgeschwindigkeit zu erreichen. Die Verteilung der Ressourcen, hauptsächlich des Hauptspeichers, über die Parametrierung der Oracle-Instanz kann nur dann sinnvoll durchgeführt werden, wenn sichergestellt ist, dass es keine extremen „Ressourcenfresser“ in der Anwendung mehr gibt. Dieses Ziel ist jedoch nicht leicht zu erreichen. Grundlage für ein erfolgreiches Tuning ist ein Basisverständnis der Arbeitsweise des Optimizers und der Möglichkeiten der Einflussnahme auf die Zugriffspfade. Werkzeuge, die den Anspruch haben, Vorschläge für optimierte SQL-Befehle zu erstellen, erfüllen diesen nur bei relativ einfachen Zugriffen. Für komplexe Joins werden Sie zumeist den Hinweis bekommen, dass kein Vorschlag erstellt werden kann. Oracle verbessert zwar von Version zu Version den kostenbasierten Optimizer, jedoch stößt auch dieser gerade bei komplexen Zugriffen an seine Grenzen und macht eine „manuelle Optimierung“ der Zugriffe nötig.
Sandini Bib
Zugriffsoptimierung
7.3.1
491
Optimizer
Die Aufgabe des Optimizers ist die Ermittlung des optimalen Zugriffspfades für einen SQL-Befehl. Die Optimierung ist Teil des Parsings, der Übersetzung des SQLBefehls in eine ausführbare Form. Der Optimizer soll bei einem Zugriff auf eine Tabelle z.B. feststellen, ob ein Zugriff über einen Index auf Grund der WHERE-Klausel ausgeführt werden kann, bei mehreren vorhandenen Indizes auch, über welchen. Bei Joins, also dem Zugriff auf zwei oder mehr Tabellen in einem SELECT-Befehl, muss ermittelt werden, welche Tabelle zuerst gelesen wird, also zur treibenden Tabelle wird, und in welcher Reihenfolge die weiteren Tabellen hinzugenommen werden. Zudem ist die Methode der Zusammenführung der Teilmengen der Tabellen entscheidend (Merge Join, Nested Loop, Hash Join). Regelbasierter Optimizer Bis einschließlich Oracle Version 6 setzte Oracle einen regelbasierten Optimizer ein. Dieser Optimizer arbeitet nach einer einfachen Bewertung der Zugriffe mit 15 Stufen. Rang
Zugriffspfad
1
Einzelne Zeile über ROWID
2
Einzelne Zeile bei Cluster-Join
3
Einzelne Zeile über eindeutigen Hash-Cluster-Schlüssel
4
Einzelne Zeile über eindeutigen Schlüssel
5
Cluster-Join für Tabellen im selben Cluster
6
Hash-Cluster-Schlüssel mit Gleichheitsoperator
7
Indizierter Cluster-Schlüssel
8
Zusammengesetzter Index über AND-Verknüpfung bei Gleichheitsoperator
9
Einfacher Index bei Gleichheitsoperator
10
Gebundener Wertebereich (between) bei indizierter Spalte
11
Ungebundener Wertebereich bei indizierter Spalte
12
Sort-Merge-Join
13
MAX- oder MIN-Funktion für indizierte Spalte
14
ORDER-BY für indizierte Spalten
15
Durchsuchen der gesamten Tabelle (full table scan)
Tabelle 7.1: Rangordnung des regelbasierten Optimizers
Beispiel: SQL> SELECT FROM WHERE AND
* kunde plz = 58553 kredit > 100000;
Sandini Bib
492
Optimierung
Beide referenzierten Spalten in der WHERE-Klausel seien über einen nicht eindeutigen Index belegt. So wird die Bedingung auf die Postleitzahl mit einem Rang 9 belegt, die Einschränkung auf die Höhe des Kredits mit Rang 11. Der Zugriff wird in diesem Fall über den Index auf der Postleitzahl erfolgen. Ob dieser Zugriff tatsächlich besser ist, hängt von der Werteverteilung in den einzelnen Feldern ab. Diese Informationen kann der regelbasierte Optimizer jedoch nicht beurteilen. Zwar kann über das einfache „Ranking“ sehr schnell ein Zugriffspfad bestimmt werden, jedoch kann der Optimizer auch in vielen Fällen, insbesondere bei komplizierten Befehlen, einen wenig effizienten Weg wählen. Die Verteilungen der Schlüsselwerte können ebenso wenig beurteilt werden wie die Größen der Tabellen. Im Beispiel kann auf Grund des hohen Kreditrahmens, den eventuell nur sehr wenige Kunden haben, der Zugriff effizienter sein als der über die Postleitzahl. Ist eine Tabelle indiziert, die nur einen Oracle-Block belegt, so wird der indizierte Zugriff, der das Lesen von zwei Oracle-Blöcken erzeugt, einen Block für den Index und einen Block für die Daten, dem Full-Table-Scan, der nur einen Oracle-Block liest und damit effizienter ist, vorgezogen. Die Einflussnahme auf den Optimizer ist nur über die Syntax des SQL-Befehls möglich. So kann die Benutzung eines Indexes nur durch eine Dummy-Operation auf das entsprechende Feld in der WHERE-Klausel verhindert werden, da eine Funktion auf einem Feld die Benutzung eines Indexes verbietet. Bezogen auf das Beispiel kann die Indexbenutzung auf der Postleitzahl wie folgt ausgeschaltet werden: SQL> SELECT FROM WHERE AND
* kunde plz + 0 = 58553 kredit > 100000;
Entsprechend ist die Dummy-Operation auf ein alphanumerisches Feld die Verkettung mit einem „Null-String“, z.B. name || '' = 'Berthold'. Ist bei Tabellen-Joins der Zugriff auf jede der Tabellen über den gleich bewerteten Rang möglich, so wird die Tabelle als treibende Tabelle genommen, die in der FROM-Klausel hinten steht. Hier kann ein Tuning dadurch erfolgen, dass die Tabelle mit der kleinsten Ergebnismenge in der FROM-Klausel als letzte aufgeführt wird. Diese Nachteile sollen über den kostenbasierten Optimizer kompensiert werden. Die Entwicklung des kostenbasierten Optimizers wird ständig vorangetrieben, wohingegen der regelbasierte Optimizer seit Oracle Version 6 nicht mehr weiterentwickelt wird und irgendwann gänzlich verschwindet. Er ist jedoch in unveränderter Form noch in Oracle9i implementiert. Sämtliche neuen Zugriffspfade wie Hash-Joins, neue Indextypen, Partitionierung usw. werden nur über den neuen kostenbasierten Optimizer unterstützt, der mit Oracle Version 7 eingeführt wurde und seit Oracle Version 7.3 auch produktiv eingesetzt werden kann.
Sandini Bib
Zugriffsoptimierung
493
Kostenbasierter Optimizer Der kostenbasierte Optimizer ist ein Expertensystem, das die optimalen Zugriffspfade auf Oracle-Tabellen auf Grund statistischer Informationen, die für Tabellen, Indizes und Cluster erzeugt werden können, ermittelt. Neben den Statistiken der Objekte sind für die Pfade auch Ressourcen und Parameter der Instanz relevant, die im Folgenden noch erläutert werden. Statistiken Die Statistikinformationen werden durch einen ANALYZE-Befehl erzeugt und im Data Dictionary abgelegt. Sie sind über die folgenden Views abzurufen (hier dba_, aber auch all_ und user_):
: : : : : :
dba_tables, dba_tab_partitions, dba_tab_subpartitions dba_indexes, dba_ind_partitions, dba_ind_subpartitions dba_tab_columns dba_ind_columns dba_tab_histograms, dba_subpart_histograms dba_clusters
Zur Ermittlung des optimalen Pfades werden zunächst alle möglichen Permutationen von möglichen Zugriffen gebildet. Zu jedem Pfad werden dann die entsprechenden Kosten errechnet, die die Statistiken als Grundlage haben und die Nutzung von Ressourcen beziffern, wie z.B. die Anzahl der I/O-Operationen, die Hauptspeichernutzung und die CPU-Zeit. Der Zugriffspfad mit den geringsten Kosten ist der optimale, insofern eine Parallelisierung außer Acht gelassen wird. Die Nachteile, die beim regelbasierten Optimizer festgestellt wurden, sollen durch den kostenbasierten Optimizer eliminiert werden, da dieser die Größen der Tabellen ebenso wie die Selektivität der Indizes beurteilen kann. Die Güte der Zugriffspfade wird durch den Detaillierungsgrad und die Aktualität der Statistiken bestimmt, aber auch durch die implementierten Algorithmen des Optimizers, die von Version zu Version verbessert werden. Erstellung und Pflege von Statistiken über das ANALYZE-Kommando Statistiken werden über das ANALYZE-Kommando erzeugt, aktualisiert oder gelöscht. Neben der Aktualität der Statistiken ist die Genauigkeit von Interesse. Die Genauigkeit korreliert aber auch mit dem Aufwand der Statistikerstellung und ist daher abzuwägen. Über das ANALYZE-Kommando lassen sich folgende Operationen für Tabellen, Indizes und Cluster ausführen:
:
Genaues Berechnen von Statistikinformationen SQL> ANALYZE TABLE kunden COMPUTE STATISTICS;
Sandini Bib
494
:
Optimierung
Das Berechnen der genauen Statistiken kann bei großen Tabellen extrem zeitaufwändig sein und einen hohen Ressourcenverbrauch erzeugen. Schätzen von Statistikinformationen SQL> ANALYZE TABLE kunden ESTIMATE STATISTICS;
Ohne weitere Angabe werden 1.064 Zeilen zufällig zur Schätzung ausgewählt SQL> ANALYZE TABLE kunden ESTIMATE STATISTICS SAMPLE 20 PERCENT; SQL> ANALYZE TABLE kunden ESTIMATE STATISTICS SAMPLE 10000 ROWS;
:
Löschen von Statistiken SQL> ANALYZE TABLE kunden DELETE STATISTICS;
:
FOR-Klausel SQL> ANALYZE TABLE kunden ESTIMATE STATISTICS FOR ALL INDEXED COLUMNS;
:
Über die FOR-Klausel des ANALYZE-Kommandos kann die Erstellung von Statistiken eingeschränkt werden, wie zum Beispiel auf die Tabelle, deren Indizes oder bestimmte Spalten. FOR ALL erweitert die Einschränkungen auf z.B. alle Spalten oder Indizes. Validieren von Tabellen und Indizes SQL> ANALYZE TABLE kunden VALIDATE STRUCTURE [INTO INVALID_ROWS] CASCADE;
Die Tabelle invalid_rows kann über ein Script im Verzeichnis $ORACLE_HOME/ rdbms/admin mit dem Namen utlvalid.sql erstellt werden. SQL> ANALYZE TABLE kunden VALIDATE REF UPDATE;
Mit diesem Befehl können Referenzen in Tabellen validiert werden. Die in den Referenzen vermerkten Teile der ROWID werden mit der tatsächlichen ROWID verglichen und gegebenenfalls korrigiert. SQL> ANALYZE TABLE kunden VALIDATE REF UPDATE SET DANGLING TO NULL;
Sollte in den Referenzen auf nicht existierende oder ungültige Objekte verwiesen werden, so werden diese auf NULL gesetzt.
Sandini Bib
Zugriffsoptimierung
:
495
Erstellen einer Liste mit verketteten Sätzen SQL> ANALYZE TABLE kunden LIST CHAINED_ROWS INTO CHAINED_ROWS;
Die Tabelle chained_rows kann über ein Script im Verzeichnis $ORACLE_HOME/ rdbms/admin mit dem Namen utlchain.sql erstellt werden. In der Tabelle chained_rows werden dann die ROWIDs des ursprünglichen Satzes aufgelistet. Statistiken müssen regelmäßig aktualisiert werden. Hierzu können Scripts für dedizierte Tabellen oder Indizes erstellt werden, in denen die Analyze-Kommandos aufgeführt werden. Existieren Indizes zu einer Tabelle, so werden diese automatisch mit der Tabelle analysiert. Sie können aber auch die Prozeduren aus dem Package dbms_utility nutzen, was den Vorteil bietet, dass diese sehr einfach in die Datenbank-Jobqueue gestellt werden können, um eine regelmäßige Aktualisierung zu garantieren. Die Prozeduren sind analyze_database, analyze_schema oder analyze_part_object. Beispiel für das Analysieren eines Schemas: SQL> execute dbms_utility.analyze_schema ('HLADMIN','ESTIMATE',NULL,20,'FOR ALL INDEXED COLUMNS');
In diesem Beispiel werden alle Tabellen, Indizes und Cluster im Schema HLADMIN analysiert, wobei die Statistiken geschätzt werden, und zwar mit 20 Prozent der Datenmenge des jeweiligen Segments als Grundlage. Zusätzlich werden Histogramme für alle indizierten Spalten erstellt. Die komplette Beschreibung der Packages ist in der Dokumentation, Oracle9i Supplied PL/SQL Packages and Types Reference, nachzulesen. Die Aktualität kann aus dem Feld last_analyzed abgelesen werden, das in allen zuvor aufgelisteten Views vorhanden ist. Statistikerstellung über dbms_stats Seit Oracle8i gibt es ein weiteres Package, das die Erstellung und die Pflege der Statistiken unterstützt, dbms_stats. Dieses Package bietet die Prozeduren und gather_table_stats, gather_index_stats, gather_schema_stats gather_database_stats an. Die Parametrierung der Prozeduren ist ähnlich der des DBMS_UTILITY-Packages, bietet jedoch einige Erweiterungen für Histogramme und Partitionen an. Die Vorteile des neuen Packages dbms_stats sind die Möglichkeit der Parallelisierung und ein verminderter Overhead, da nicht alle statistischen Spalten im Data Dictionary gefüllt werden. Nachteile sind die fehlenden Möglichkeiten des Analysierens von Clustern und verketteten Sätzen. Für die ausführliche Beschreibung sei auch hier wieder auf die oben genannte Dokumentation verwiesen. Validierungen können über dieses Package generell nicht durchgeführt werden.
Sandini Bib
496
Optimierung
Systemstatistiken Mit Version 9i ist es zusätzlich möglich, über das dbms_stats-Package Systemstatistiken zu erstellen und zu verwalten (gather_system_stats). Damit ist es möglich, neben den Informationen über Tabellengrößen, Indizes oder Histogramme auch Systeminformationen oder den Workload des Systems zu betrachten. Der Optimizer erhält dadurch Informationen über das I/O-System und den CPU-Verbrauch. Da sich der Workload eines Systems aber permanent ändert, ist es sinnvoll, ein Intervall für die Messung anzugeben und die Messung zu unterschiedlichen Zeiten (Tagesbetrieb, Nachtbetrieb, eventuelle Spitzenzeiten) zu wiederholen. Die Ergebnisse der Messung werden standardmäßig direkt in das Data Dictionary eingetragen und damit vom Optimizer für alle folgenden Befehle genutzt. Alternativ kann die Auswertung in einer separaten Tabelle erfolgen, die dann zu Testzwecken genutzt bzw. auch manipuliert und exportiert werden kann. Somit ist es auch möglich, Systemstatistiken auf ein Testsystem zu übertragen, obwohl dieses eigentlich anders aufgebaut ist. Das folgende Beispiel generiert Systemstatistiken in einer Benutzertabelle stattest. Dabei wird die Tabelle zunächst mit der Prozedur drop_stat_table gelöscht und anschließend mit create_stat_table wieder angelegt. Mit der Prozedur gather_system_stats wird dann für 60 Minuten ein Workload ermittelt und mit der ID TAG in der Tabelle stattest abgelegt. BEGIN DBMS_STATS.DROP_STAT_TABLE ( ownname => 'DEMO', stattab => 'STATTEST'); DBMS_STATS.CREATE_STAT_TABLE ( ownname => 'DEMO', stattab => 'STATTEST', tblspace => 'TS_DEMO'); DBMS_STATS.GATHER_SYSTEM_STATS( gathering_mode => 'interval', interval => 60, stattab => 'STATTEST', statid => 'TAG'); END; / Listing 7.8: Ermitteln von Systemstatistiken
Mit der Prozedur set_system_stats kann dann eine einmal ermittelte Statistik als Systemstatistik gesetzt werden. Da es sich hier um eine sehr neue Funktion mit u.U. gravierendem Einfluss auf bereits existierende Anwendungen handelt, empfehlen wir, mit diesen Statistiken vorsichtig umzugehen. Gerade der unbedarfte Aufruf von gather_system_stats ohne Tabellenangabe kann dazu führen, dass alle folgenden Befehle mit einem fal-
Sandini Bib
Zugriffsoptimierung
497
schen Ausführungsplan geparsed werden. Sie sollten daher, wie im obigen Beispiel gezeigt, Systemstatistiken unter einem bestimmten Benutzer anlegen und dann vorhandene Befehle mit diesen Statistiken testen. Automatische Pflege von Statistiken Mit Oracle8i wurde auch die Möglichkeit eingeführt, INSERT-, UPDATE- und DELETE-Aktivitäten für Tabellen zu beobachten und protokollieren zu lassen. Die Informationen können aus der View dba_tab_modifications abgelesen werden. Eingeschaltet wird die Protokollierung der Aktivitäten über SQL> CREATE / ALTER TABLE tabname MONITORING;
Wird nun die Erstellung der Statistiken mit den Prozeduren gather_schema_stats oder gather_database_stats unter Angabe der Option gather_auto oder gather_stale angestoßen, so werden die Objekt analysiert, die einen Eintrag in dba_tab_modifications haben. Dadurch kann insbesondere bei Datenbanken mit vielen Tabellen der Aufwand für die Statistikerstellung deutlich reduziert werden, da nur einige Tabellen gravierende Änderungen der Datenmengen und Schlüsselverteilungen aufweisen, viele hingegen statisch sind. Instanzparameter mit Relevanz für den kostenbasierten Optimizer
:
:
sort_area_size / hash_area_size
Der Parameter sort_area_size bestimmt die maximale Größe des Hauptspeichers, die jeder einzelne Serverprozess für Sortierungen bekommt. Aus diesem Parameter abgeleitet wird die hash_area_size festgelegt, die, wenn nichts anderes spezifiziert wurde, doppelt so groß ist wie die sort_area_size. Dieser Hauptspeicherbereich steht jedem Serverprozess für den Hash-Algorithmus des HashJoin zur Verfügung. Je größer diese Werte sind, desto seltener müssen Sortierzwischenschritte in den Temporär-Tablespace ausgelagert werden. Der Optimizer wird aber in diesen Fällen zu häufig Merge-Joins oder Hash-Joins verwenden, die für die Ressourcen belastender als Nested Loops sind. Die Join-Methoden werden im Anschluss noch behandelt. db_file_multiblock_read_count
Wie viele Oracle-Blöcke werden mit einem Betriebssystem-I/O in die SGA geholt? Diese Festlegung erfolgt über diesen Parameter. Standardeinstellung ist 8, was aus unserer Erfahrung heraus auch nicht ohne besonderen Grund verändert werden sollte, da der Optimizer bei höheren Einstellungen Full-Table-Scans stärker favorisiert, da ja ein I/O für eine große Menge von Daten ausreicht. Bei einem Striping der Platten mit 64Kbyte-Chunks harmoniert die Standardeinstellung 8 bei einer Datenbankblockgröße von 8Kbyte hervorragend mit der I/O-Größe.
Sandini Bib
498
:
Optimierung
optimizer_max_permutations
Dieser Parameter bestimmt, wie viele Permutationen der Zugriffspfade maximal gebildet werden, um den optimalen Zugriffspfad zu ermitteln. Die Standardeinstellung für diesen Parameter ist 80.000, der im Normalfall nicht erreicht wird. Jedoch berechnet sich die Anzahl der möglichen Permutationen als Fakultät aus der Anzahl der Tabellen und deren Indizes. Bei Joins mit mehr als 6 Tabellen kann diese maximale Anzahl schon erreicht werden. Als Folge steigt die Zeit für das Parsing des Befehls stark an. In einem konkreten Beispiel mit einem Join über 14 Tabellen betrug die Parse-Time ca. 3 Minuten, die Ausführungszeit selbst für den Befehl dann weniger als eine Sekunde. Durch Reduzierung der maximalen Permutationen auf 1.000 ließ sich die ParseTime ebenfalls auf unter eine Sekunde reduzieren, ohne dass die Ausführungszeit schlechter wurde. Zwar ist die Gefahr gegeben, dass nicht der optimale Pfad ermittelt wird, jedoch bewegen sich die Zeiten für das Parsing in vertretbaren Größenordnungen. Sollte die Ausführungszeit sich dramatisch verschlechtern, sollten diese sicherlich extremen Fälle über Optimizer Hints optimiert werden. Da dieser Parameter aus Sitzungsebene eingestellt werden kann, können Sie an dieser Stelle auch gut experimentieren. Welcher Optimizer wird benutzt Zwei Bedingungen steuern, welcher Optimizer genutzt wird. Zum einen der Initialisierungsparameter optimizer_mode, der die Einstellungen choose (Standardeinstellung), rule, first_rows, first_rows_n oder all_rows anbietet. Die zweite Bedingung ist das Vorhandensein von Statistiken. choose
Sind keine Statistiken vorhanden, wird der regelbasierte Optimizer genutzt, existieren Statistiken auf mindestens einer Tabelle, die im SQL-Befehl angesprochen wird, wird der kostenbasierte Optimizer genutzt. Fehlende Statistiken werden in diesem Fall geschätzt. Hier gilt die Regel, dass entweder alle Tabellen eines Schemas analysiert werden sollten oder gar keine.
rule
Es wird ausschließlich der regelbasierte Optimizer genutzt, auch wenn Statistiken existieren.
first_rows
Bei dieser Einstellung wird eine Mischung aus Statistikinformationen und Annahmen benutzt, um einen Zugriffspfad auszuwählen, der die schnellstmögliche Lieferung der ersten Zeilen ermöglicht.
first_rows_n
n kann die Werte 1, 10, 100 oder 1.000 haben. Dabei wird, auch ohne Statistiken, der kostenbasierte Ansatz gewählt, um möglichst schnell die spezifizierte Anzahl von Zeilen liefern zu können.
all_rows
Es wird der statistikbasierte Ansatz gewählt, auch wenn keine Statistiken vorhanden sind (Annahmen werden getroffen). Die gesamte zu liefernde Datenmenge wird mit den geringsten Kosten ermittelt.
Es ist dringend davon abzuraten, nur einige Tabellen eines Schemas zu analysieren und andere nicht. Die dann getroffenen Annahmen sind häufig zu ungenau, so dass unbe-
Sandini Bib
Zugriffsoptimierung
499
friedigende Zugriffspfade ermittelt werden. Auch die Erzwingung des kostenbasierten Ansatzes durch Optimizer Hints bei fehlenden Statistiken sollte vermieden werden.
7.3.2
Ausführungspläne
Der Ausführungsplan eines Befehls zeigt sowohl die Reihenfolge, in der auf die beteiligten Tabellen zugegriffen wird, als auch die Zugriffmethode, also z.B. indiziertes Lesen, Lesen von Indexbereichen oder Full-Table-Scans. Ausführungspläne (auch Explain-Plans) genannt, können auf unterschiedliche Arten erstellt werden.
: : : :
Ermitteln von Ausführungsplänen für aktuelle Befehle über Werkzeuge wie Oracle TopSessions, Oracle SQL Analyze, Quest TOAD und viele weitere grafische Tools. Tracing von Anwendungen und Erstellung der Ausführungspläne aus der entsprechenden Trace-Datei (z.B: TKPROF). Darstellung eines Ausführungsplans für einen konkreten Befehl aus SQL*Plus (AUTOTRACE) nach der Ausführung des Befehls. Alleinige Ermittlung eines Ausführungsplans mit dem SQL*Plus-Befehl EXPLAIN PLAN.
Jede der genannten Arten hat ihre Vor- und Nachteile. Die grafischen Werkzeuge bieten oft die Möglichkeit, neben dem Ausführungsplan auch Informationen über die zugrunde liegenden Tabellen und deren Indizes anzuzeigen. Das Tracing von Anwendungen hat hingegen den Vorteil, dass die gesamte Anwendung bzw. der relevante Teil betrachtet werden kann. Außerdem werden dabei zusätzliche Statistikinformationen wie z.B. der CPU-Bedarf der einzelnen Phasen ermittelt. Die Generierung eines Ausführungsplans aus SQL*Plus ist hingegen dann interessant, wenn keine grafische Oberfläche zur Verfügung steht und die SQL-Befehle mehrfach geändert und dann wieder überprüft werden sollen. Das folgende Beispiel generiert für einen SQL-Befehl den Ausführungsplan aus SQL*Plus heraus. Voraussetzung ist, dass die Rolle PLUSTRACE existiert und dem Benutzer zugewiesen wurde: SQL> connect / as sysdba SQL> @?/sqlplus/admin/plustrce SQL> grant plustrace to demo;
Als Nächstes muss für den entsprechenden Benutzer die Tabelle plan_table angelegt werden: SQL> connect demo/demo SQL> @?/rdbms/admin/utlxplan
Sandini Bib
500
Jetzt steht der Benutzung von AUTOTRACE nichts mehr im Wege: SQL> set autotrace on -- Einschalten von Autotrace SQL> set autotrace traceonly -- Nur Tracing-Informationen ausgeben SQL> SELECT k.kd_ort, SUM(p.pos_menge * p.pos_einzelpreis) AS umsatz FROM kunden k, auftraege a, positionen p WHERE k.kd_nr = a.auf_kdnr AND a.auf_nr = p.pos_aufnr AND UPPER(k.kd_nachname) = 'AHRENDS' AND UPPER(k.kd_vorname) = 'GERD' GROUP BY k.kd_ort; Ausführungsplan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=582 Card=8 Bytes=432) 1 0 SORT (GROUP BY) (Cost=582 Card=8 Bytes=432) 2 1 TABLE ACCESS (BY INDEX ROWID) OF 'POSITIONEN' (Cost=2 Card=3 Bytes=39) 3 2 NESTED LOOPS (Cost=578 Card=287 Bytes=15498) 4 3 NESTED LOOPS (Cost=348 Card=115 Bytes=4715) 5 4 TABLE ACCESS (FULL) OF 'KUNDEN' (Cost=337 Card=11 Bytes=341) 6 4 INDEX (RANGE SCAN) OF 'AUFTRAEGE_IDX_002' (NON-UNIQUE) (Cost=1 Card=10 Bytes=100) 7 3 INDEX (RANGE SCAN) OF 'POSITIONEN_IDX_003' (NON-UNIQUE) (Cost=1 Card=3) Statistiken ---------------------------------------------------------157 recursive calls 0 db block gets 2282 consistent gets 2210 physical reads 0 redo size 451 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 5 sorts (memory) 0 sorts (disk) 1 rows processed Listing 7.9: Ausführungsplan mit SQL*Plus
Optimierung
Sandini Bib
Zugriffsoptimierung
501
Der Ausführungsplan muss jetzt wie folgt interpretiert werden:
: : : :
Die erste Spalte ist eine Nummerierung aller Befehlsteile. Die zweite Spalte gibt an, auf welche Befehlszeile dieser Befehl aufbaut. Die dritte Spalte gibt dann den Zugriffspfad bzw. den ausgeführten Befehl an. Die Ausführung beginnt mit dem Befehl, der am weitesten eingerückt wurde (in dem Beispiel Zeile 5 und 6).
Das gesamte Beispiel liest sich also wie folgt: 1. Zeile 5: TABLE ACCESS (FULL) OF 'KUNDEN': Es wird ein Full-Table-Scan auf die Kundentabelle ausgeführt. 2. Zeile 6: INDEX (RANGE SCAN) OF 'AUFTRAEGE_IDX_002': Es wird auf einen Index über einen Bereich zugegriffen. 3. Zeile 4: NESTED LOOPS: Ein Nested-Loop-Join wird zwischen dem in Zeile 5 ermittelten Indexbereich und dem Full-Table-Scan durchgeführt. 4. Zeile 7: INDEX (RANGE SCAN) OF 'POSITIONEN_IDX_003': Es wird auf einen zweiten Index über einen Bereich zugegriffen. 5. Zeile 3: NESTED LOOPS: Ein Nested-Loop-Join wird zwischen dem in Zeile 7 ermittelten Indexbereich und dem Ergebnis des Nested-Loop-Joins aus Zeile 4 durchgeführt. 6. Zeile 2: TABLE ACCESS (BY INDEX ROWID) OF 'POSITIONEN': Es wird auf die Datensätze der Tabelle positionen über ihre Rowid (aus dem Index Zeile 7 ermittelt) zugegriffen. 7. Zeile 1: SORT (GROUP BY): Das ermittelte Ergebnis wird sortiert. 8. Zeile 0: SELECT STATEMENT: Das Ergebnis wird dargestellt. In dem obigen Beispiel fällt auf, dass auf die Tabelle auftraege gar nicht zugegriffen wird. Der Grund ist, dass alle für die Abfrage relevanten Daten aus dem zugehörigen Index (AUFTRAEGE_IDX_002) ermittelt werden können. Statt AUTOTRACE könnte auch ein EXPLAIN PLAN verwendet werden. In diesem Fall wird der Ausführungsplan in der Tabelle plan_table eingetragen, aber nicht ausgeführt. Daher eignet sich dieses Vorgehen vor allen Dingen bei komplexen und lang laufenden SQL-Befehlen bzw. bei Befehlen, bei denen Bindevariablen verwendet werden, die nicht bekannt sind. Das obige Beispiel mit Bindevariablen könnte so aussehen: EXPLAIN PLAN SET STATEMENT_ID = 'demo_explain' FOR SELECT k.kd_ort, SUM(p.pos_menge * p.pos_einzelpreis) AS umsatz FROM kunden k, auftraege a, positionen p WHERE k.kd_nr = a.auf_kdnr
Sandini Bib
502
AND AND AND GROUP
Optimierung
a.auf_nr = p.pos_aufnr UPPER(k.kd_nachname) = :nachname UPPER(k.kd_vorname) = :vorname BY k.kd_ort;
@?/rdbms/admin/utlxpls Plan Table ------------------------------------------------------------------| Operation | Name |Rows |Bytes|Cost | ------------------------------------------------------------------| SELECT STATEMENT | | 8 | 432 | 582 | | SORT GROUP BY | | 8 | 432 | 582 | | TABLE ACCESS BY INDEX RO|POSITIONEN | 3 | 39 | 2 | | NESTED LOOPS | | 287 | 15K| 578 | | NESTED LOOPS | | 115 | 4K| 348 | | TABLE ACCESS FULL |KUNDEN | 11 | 341 | 337 | | INDEX RANGE SCAN |AUFTRAEGE_IDX_002 | 10 | 100 | 1 | | INDEX RANGE SCAN |POSITIONEN_IDX_003| 3 | | 1 | -----------------------------------------------------------------Listing 7.10: Explain Plan
Das SQL-Script utlxpls.sql gibt dann den Inhalt der Tabelle plan_table etwas besser lesbar aus (die Spalten PSTART und PSTOP wurden hier weggelassen). Neben dem Script utlxpls.sql gibt es noch das Script utlxplp.sql, das dann verwendet wird, wenn der Ausführungsplan des Befehls parallelisiert wurde.
7.3.3
Indizes
An dieser Stelle sollen spezielle Indextypen besprochen werden, die sicherlich nicht als Standard eingesetzt werden, sondern nur in dedizierten Fällen sinnvoll sind. Hier sollen anhand von Beispielen Einsatzmöglichkeiten, aber auch Randbedingungen und Nachteile aufgezeigt werden. Index-Histogramme Histogramme sind zwar kein eigener Indextyp, jedoch sind sie eine Erweiterung der Indizes. Wie bereits beschrieben, nutzt der kostenbasierte Optimizer Statistiken, um einen Zugriff optimal zu gestalten. Dazu werden auch Informationen über Indizes betrachtet, wie z.B. die Anzahl der unterschiedlichen Schlüsselwerte. Ein indizierter Zugriff auf Daten einer Tabelle ist nur dann sinnvoll, wenn weniger als 15 % des Tabelleninhaltes als Ergebnismenge geliefert werden. Ansonsten ist ein Full-Table-Scan sinnvoller, da die Anzahl der gelesenen Indexblöcke im anderen Fall zu groß ist. Der Eintrag in der Statistik zu einem Index sagt aber nichts über die Verteilung der Satzanzahl zu einem Schlüsselwert aus. Hierzu sei ein Beispiel gegeben:
Sandini Bib
Zugriffsoptimierung
503
In einer Tabelle auftrag sind die Aufträge eines Unternehmens der letzten zwei Jahre gespeichert. Die Tabelle speichert ca. 100.000 Sätze. Ein Feld der Tabelle ist der Auftragsstatus, der die Werte 0 für „Offen“ und 1 für „Abgeschlossen“ hat, außerdem gibt es noch weitere seltene Stati (2 bis 4). Über eine Anwendung können sich Sachbearbeiter die offenen Aufträge anzeigen lassen. In der Statistik des Indexes findet der Optimizer die Information distinct_keys = 5; Ein solcher Index würde vom kostenbasierten Optimizer nicht benutzt werden, da 20 Prozent der Sätze als Ergebnismenge zu erwarten sind, obwohl ev. nur 250 Sätze der 100.000 den Status offen haben. Dieses Problem lässt sich über ein Histogramm für diesen Index lösen, in dem die Verteilung der Sätze auf die Schlüsselwerte abgebildet wird. Wenn man sich die Werteverteilung als Bereiche mit je einem Endwert (bucket) vorstellt, dann ginge Oracle bei einem gleich verteilten Index davon aus, dass jeder Wert ein Endwert ist. Das würde für den Auftragsstatus so aussehen:
Abbildung 7.6: Gleich verteilter Index
In der Theorie gibt es zwei Arten von Histogrammen.
:
:
Breitenbalancierte Histogramme, bei denen die Schlüsselwerte so auf verschiedene Partitionen (buckets) aufgeteilt werden, dass jede Partition die gleiche Anzahl von Schlüsselwerten enthält. Als Konsequenz ergibt sich eine ungleiche Verteilung der Schlüsselwerte in den Partitionen, wenn die Schlüsselverteilung in der Tabelle ungleichmäßig ist. Höhenbalancierte Histogramme besitzen Partitionen mit gleicher Anzahl von Elementen, die die Sätze der Tabelle abbilden. Bei ungleichmäßiger Schlüsselverteilung ergibt sich eine unterschiedliche Anzahl von Schlüsseln in einem bucket. Pro Bucket werden Endpunkte (endpoints) verwaltet, die die Schlüsselwerte am Anfang und am Ende eines buckets beinhalten.
Oracle hat ausschließlich höhenbalancierte Histogramme implementiert, da diese sich besser zur Berechnung der Selektivität bei ungleichmäßiger Schlüsselverteilung eignen. Der Optimizer betrachtet häufig vorkommende Werte (popular values) und selten vorkommende Werte (nonpopular values). Popular values sind solche, die in mehr als einem Endpunkt erscheinen. Das folgende Beispiel zeigt die Berechnung der Selektivität des Schlüssels mit dem Wert 1. S(column=1) = ¾ = 0,75
Sandini Bib
504
Optimierung
Abbildung 7.7: Höhenbalanciertes Histogramm
Der Schlüsselwert 1 erschein in drei von vier Endpunkten. Die Selektivität berechnet sich also aus der Anzahl der Endpunkte mit diesem Schlüsselwert dividiert durch die Anzahl der buckets insgesamt. Für nonpopular values wird ein Density-Faktor errechnet, wobei hier eine Gleichverteilung der Schlüsselwerte angenommen wird. Histogramme können mit dem folgenden Befehl erstellt werden, wobei hier für die Tabelle kunde ein Histogramm mit 3 buckets definiert wird. SQL> ANALYZE TABLE kunde COMPUTE STATISTICS FOR COLUMNS kredit SIZE 3;
Wie viele buckets tatsächliche angelegt werden, ist aus der Spalte num_buckets der View dba_tab_columns abzulesen. Diese kann jedoch nie höher als die Anzahl der unterschiedlichen Schlüsselwerte sein. Die Anzahl der Endpunkte ist die Anzahl der buckets + 1 und ist aus dba_histograms abzulesen. Die Anzahl der buckets sollte immer höher als die angenommene Anzahl der häufig vorkommenden Schlüsselwerte sein, damit für die Berechnung der Selektivität genügen viele popular values entstehen. Bitmap-Indizes Über Bitmap-Indizes lässt sich die Optimierung von Abfragen gestalten, die durch verschiedene Kombinationen unterschiedlicher nicht selektiver Kriterien eine hohe Selektivität erzeugt. Mit herkömmlichen Indizes kann in diesem Fall nicht gearbeitet werden, da ansonsten für sämtliche Permutationen der in der WHEREKlausel kombinierten Einschränkungen dementsprechend konkatenierte Indizes erstellt werden müssten. Einsatzgebiete sind typischerweise Data Warehouse-Datenbanken, bei denen Auswertungen von Daten unter Auswahl verschiedener Kriterien durchgeführt werden. Die Einschränkung der Einsatzgebiete ergibt sich auch durch die Restriktionen, die auf Grund der physikalischen Speicherung der Bitmap-Indizes auftreten und im folgenden noch behandelt werden. Für eine indizierte Spalte einer Tabelle wird im Bitmap-Index für jeden Schlüsselwert eine Bit-Leiste erstellt, in der über die Werte 0 und 1 abgelegt ist, ob der Wert in einem Satz vorkommt oder nicht. Als einfaches Beispiel soll die Indizierung der Spalte Auftragsstatus in der Tabelle auftraege genommen werden. Auftragsstatus O bedeutet offen, also noch in Bearbeitung, A bedeutet abgeschlossen.
Sandini Bib
Zugriffsoptimierung
505
O | 00010000010001000001 ... Anzahl Sätze ____________________________ A | 11101111101110111110 ... Anzahl Sätze Abbildung 7.8: Bit-Leiste eines Bitmap-Indexes
Physikalisch werden diese Bit-Leisten in Teilbereichen gespeichert, die die Größe eines halben Oracle-Blocks haben und selbst in einer B*Baum-Struktur abgelegt werden. Zusätzlich sind die Anfangs- und Endadressen in einem Bereich über die rowids gespeichert. Unter Annahme der minimalen Satzlänge wird über einen Algorithmus aus den Bit-Positionen eine Satzadresse berechnet, so dass ein bestimmter Oracle-Block der Tabelle beim Zugriff gelesen werden kann. Daraus ergibt sich aber auch die Tatsache, dass bei Änderung der minimalen Satzlänge durch einen ALTER TABLE-Befehl der Bitmap-Index ungültig werden kann und reorganisiert werden muss. Die einzelnen Bereiche werden komprimiert, um den Platzbedarf zu verringern und die Zugriffe dahingehend effektiver zu machen, dass mit einem Block mehr Informationen abgreifbar sind. So benötigen Bitmap-Indizes häufig nur wenige Prozent des Platzes, den B*Baum-Indizes benötigen würden. Das ist natürlich sehr abhängig von der Anzahl der unterschiedlichen Schlüsselwerte und der Anzahl der Sätze, aber nur sinnvoll bei einer geringen Kardinalität. Daraus ergeben sich folgende Vorteile:
: : :
Geringerer Platzbedarf, besonders bei geringer Kardinalität, also wenig unterschiedlichen Schlüsselwerten und einer hohen Anzahl von Tabellenzeilen Sehr effiziente AND- und OR- Verknüpfungen. Die Bit-Leisten unterschiedlicher Bitmap-Indizes einer Tabelle können über boolesche Operationen verknüpft werden. Erst mit dem Ergebnis der Verknüpfung wird über die Konvertierung in Satzadressen auf die Tabelle zugegriffen. Sehr schnelle Zähloperationen (count-Funktion)
Nachteil:
:
Werden durch DML-Operationen indizierte Spalten verändert, muss der gesamte physische Bitmap-Bereich gesperrt werden. Diese Sperren sind zwar kurzzeitig, können aber bei OLTP-Transaktionen zu erheblichen Sperrkonflikten führen und sind daher in solchen Umgebungen nicht einsetzbar. In der Praxis ergibt sich daher die Konsequenz, dass Bitmap-Indizes nur für Tabellen sinnvoll sind, die entweder statisch sind oder nur durch einen dedizierten Prozess befüllt und verändert werden.
Relevante Initialisierungsparameter:
:
create_bitmap_area_size
Bestimmt die Größe des Hauptspeicherbereich für einen Prozess, der für die Erstellung eines Bitmap-Indexes zur Verfügung steht. Dieser Parameter wird nur
Sandini Bib
506
:
:
Optimierung
aus Kompatibilitätsgründen und für Shared Server-Konfigurationen weiter unterstützt. Ansonsten wird auf den Parameter pga_aggregate_target verwiesen. bitmap_merge_area_size
Hier kann die Größe des Hauptspeicherbereichs pro Prozess definiert werden, in dem Bit-Leisten verknüpft werden können. Auch dieser Parameter wird nur für Shared Server-Konfigurationen angeraten, ansonsten wird auf pga_aggregate_target verwiesen. pga_aggregate_target
Über diesen Parameter wird eine Zielgröße für Prozess-Hauptspeicherbereiche definiert. Der Bereich wird für speicherintensive Operationen wie Sortierungen, GROUP-BY-Oprationen, Indexerstellungen oder Ähnliches benutzt. Der Parameter wird in Abschnitt 7.4, Instanzoptimierung, noch ausführlicher behandelt. Das Anlegen eines Bitmap-Indexes erfolgt über den Befehl: SQL> CREATE BITMAP INDEX auftrag_bmi_status ON auftrag(status);
Informationen sind der View dba_indexes zu entnehmen. Bitmap-Indizes sind am Wert BITMAP in der Spalte uniqueness zu erkennen. Index-Organized Tables Streng genommen sind Index-Organized Tables keine Spezialform eines Index, sondern Tabellen, deren Daten in einer B*Baum-Struktur abgelegt sind. Über diese Sonderform lassen sich invertierte Listen, also Inhaltsverzeichnisse, besonders effektiv ablegen. Anstatt die jeweils 10 Byte lange ROWID zu einem Schlüsselwert zu speichern, werden die Daten eines Satzes, die außerhalb der indizierten Felder liegen, direkt mit in der B*Baum-Struktur gespeichert. Das bedeutet, dass neben der ROWID auch noch die ansonsten redundant im Index und in der Tabelle gespeicherten Schlüsselfelder nur einfach gehalten werden. Es versteht sich, dass die zusätzlich zu den Indexwerten gespeicherten Daten nicht zu umfangreich sein dürfen, da ansonsten die Struktur des B*Baumes zerstört wird. Aus diesem Grunde kann ein Überlaufbereich definiert werden, in den Daten ausgelagert werden, die einen definierbaren Schwellenwert bezüglich des prozentualen Anteils der Satzlänge überschreiten. SQL> CREATE TABLE inhaltsverzeichnis (begriff VARCHAR2(50), dokument_nr NUMBER, fundstelle NUMBER) CONSTRAINT cons_iot PRIMARY KEY (begriff) ORGANIZATI/ON INDEX TABLESPACE ts1 PCTTHRESHOLD 20 OVERFLOW TABLESPACE ts2; Listing 7.11: Index-Organized Table
Sandini Bib
Zugriffsoptimierung
507
Zu beachten ist, dass keine Zugriffe über eine explizite Angabe der ROWID mehr möglich ist. Ansonsten bleiben DML-Anweisungen für diese Art von Tabellen unverändert. Nachteilig können Zugriffe über Sekundärschlüssel sein, die, wie auf normale Tabellen, auch auf Index-Organized Tables gelegt werden können. Die Sekundärschlüssel können nicht über ROWIDs auf die Sätze im B*Baum verweisen, sondern es werden Lokationen in Blöcken in Form einer logischen ROWID geschätzt. Bei einem Zugriff wird eine Probe durchgeführt, die die Schätzung verifizieren soll. Trifft die Annahme nicht zu, muss über den Primärschlüssel gesucht werden. Problematisch ist dieses Verhalten bei Sätzen, die nicht in ihren ursprünglichen Blöcken verbleiben. Besondere Berücksichtigung sollte der Parameter COMPRESS finden. Es kann eine Zahl definiert werden, die bestimmt, wie viele Felder des Primärschlüssels nur einmal gehalten werden sollen, die restlichen Informationen werden dann unter diesen Eintrag gehängt. Über diesen Parameter können erhebliche Platzersparnisse für Index-organisierte Tabellen erreicht werden. Reverse Key-Indizes Der Einsatz dieses Indextyps ist nur in wenigen Fällen angezeigt, und zwar dann, wenn bei parallelem Einfügen von Sätzen Zugriffskonflikte auf Indexblöcken auftreten. Das kann zum Beispiel dadurch verursacht werden, dass Werte für einen Primärschlüssel aus einer Sequenz gefüllt werden und damit Sätze eingefügt werden, deren Schlüssel im selben Block gespeichert werden. Dieser Block bildet dann einen Engpass. Die Schlüsselwerte werden in ihrem binären Wert umgekehrt. In einem einfachen Beispiel sieht die Umkehrung wie folgt aus: 1 2 5
00110001 00110010 00110101
-> -> ->
10001100 01001100 10101100
Auf diese Art und Weise wird eine höhere Verteilung der Werte auf verschiedenen Leaf-Blöcken eines Indexes erreicht, wodurch die Engpässe beim parallelen Zugriff eliminiert werden. Angelegt werden Reverse Key-Indizes genauso wie herkömmliche Indizes, jedoch mit dem Zusatz REVERSE. SQL> CREATE INDEX r_ind1 ON tab1 (feld1, feld2) REVERSE;
Die Umkehrung kann bei einem Neuaufbau des betreffenden Indexes aufgehoben werden. SQL> ALTER INDEX r_ind1 REBUILD NOREVERSE;
Sandini Bib
508
Optimierung
Function-based Indizes Die Einsatzmöglichkeiten der Function-based Indizes sollen auch hier an einem Beispiel verdeutlicht werden. In einer Tabelle KUNDEN wird der Kundenname in Groß-Kleinschreibung abgelegt. Bei der Suche nach einem Kunden mit dem Namen als Suchkriterium ist meistens die verwendete Schreibweise nicht bekannt, "Oracle" oder "ORACLE". Umgangen werden kann das Problem durch die Abfrage SQL> SELECT * FROM kunden WHERE UPPER(kundenname) = UPPER(:variable);
Für die Optimierung des Zugriffs kann aber ein herkömmlicher Index auf dem Feld kundenname nicht verwendet werden, da auf dieses Feld in der Abfrage eine Funktion angewendet wird. Der Zugriff erfolgt in diesem Fall über einen Full-Table-Scan. Seit Oracle8i kann ein Function-based-Index angelegt werden, wobei aber zu beachten ist, dass diese Funktionalität nur in der Enterprise Edition zur Verfügung steht. SQL> CREATE INDEX kunden_kundenname_caps ON kunden (UPPER(kundenname)) ...;
Hier können numerische, alphanumerische und Datumsfunktionen verwendet werden, die für die Unterstützung eines Zugriffs sinnvoll sind.
7.3.4
Hints
Trotz diverser Möglichkeiten der Indizierung und der Histogramme wird der kostenbasierte Optimizer nicht immer die beste Möglichkeit des Zugriffs wählen, da viele Annahmen getroffen werden müssen und Grenzwerte vordefiniert sind, die nicht immer stimmen. Weiterhin kann es vorkommen, dass durch die Einschränkung der Permutationen ein nicht performanter Weg gewählt wird, oder dass für einige wenige Befehle die Parametrierung der Instanz, die andere Anwendungen optimal unterstützt, zu schlechten Ausführungsplänen führt. In diesen Fällen können Sie dem Optimizer Hinweise geben, wie der Zugriff am besten zu realisieren ist. Ein Hint ist auch wirklich als Hinweis zu verstehen, d.h., der angegebene Zugriff muss nicht zwingend vom Optimizer verwendet werden, wenn aus bestimmten Gründen der Zugriff so nicht realisiert werden kann. Syntax SQL> SELECT /*+ hint */ * FROM ...;
oder SQL> SELECT --+ hint FROM ...;
Der Hinweis für den Optimizer wird in der Form eines Kommentars sofort nach dem Schlüsselwort SELECT angegeben. Entscheidend für die Interpretation als Hint
Sandini Bib
Zugriffsoptimierung
509
ist das Plus-Zeichen nach Einleitung des Kommentars. Sie sollten ausschließlich die erste Form benutzen, da bei der zweiten Möglichkeit Probleme bei kombinierten Hints auftreten, weil das Ende des Hints nicht eindeutig gekennzeichnet ist. Auch ist es unbedingt wichtig, nach dem Plus-Zeichen genau ein Leerzeichen anzugeben und vor Beendigung des Kommentars ebenfalls ein Leerzeichen zu verwenden. SQL*Plus interpretiert die Hints auch ohne die Leerzeichen richtig, PL/SQL hingegen benötigt die Leerzeichen unbedingt, um die Hints erkennen zu können. Eine zweite Besonderheit ist bei der Verwendung von Tabellennamen-Aliases zu beachten. Werden in der FROM-Klausel Aliasnamen für die Tabellen verwendet, müssen diese ebenfalls im Hint verwendet werden. Wird stattdessen der Tabellenname im Hint angegeben, so kann dieser nicht interpretiert werden. Beispiel: SQL> SELECT /*+ full(auftrag) */ sum(auftragswert) FROM auftrag;
Verwendung eines Tabellennamen-Alias: SQL> SELECT /*+ full(a) */ sum(auftragswert) FROM auftrag a;
funktioniert! SQL> SELECT /*+ full(auftrag) */ sum(auftragswert) FROM auftrag a;
funktioniert nicht! Hints zur Auswahl des Optimizers Mit diesen Hints kann pro SQL-Befehl die Benutzung eines bestimmten Optimizers mit unterschiedlichen Optimierungsansätzen gewählt werden. ALL_ROWS
Optimierung auf Gewinnung der gesamten Ergebnismenge (Standardeinstellung bei CHOOSE). FIRST_ROWS
Optimierung auf schnellstmögliche Gewinnung der ersten Sätze, sinnvoll für Online-Anwendungen. CHOOSE
Oracle wählt den kostenbasierten Optimizer aus, wenn Statistiken vorhanden sind, ansonsten wird der regelbasierte Optimizer gewählt. RULE
Es wird explizit der regelbasierte Optimizer gewählt.
Sandini Bib
510
Optimierung
Hints für Zugriffsmethoden Mit dieser Kategorie von Hinweisen können sie auf die Zugriffsmethode Einfluss nehmen, also ob die Tabelle über einen Full-Table-Scan oder einen bestimmten Index gelesen werden soll. So würde man z.B. dann verfahren, wenn der Optimizer einen Index auf Grund der Statistiken als nicht selektiv betrachtet, für eine bestimmte Abfrage mit einem fest definierten Wertebereich der indizierte Zugriff aber sinnvoll ist. FULL(tabname)
Für den Zugriff auf die im FULL-Hint angegebene Tabelle wird ein Full-Table-Scan angefordert. Das kann dann sinnvoll sein, wenn man weiß, dass auf einen Wertebereich zugegriffen werden soll, der einen Großteil der Tabelle ausmacht und so keinen selektiven Zugriff über einen Index bietet. INDEX(tabname indname)
In diesem Fall wird ein indizierter Zugriff erzwungen. Hier sollte bekannt sein, dass man in der WHERE-Klausel der Abfrage auf einen selektiven Wert einschränkt, wohingegen der benutzte Index selbst nur wenige unterschiedliche Schlüsselwerte aufweist und normalerweise deshalb nicht vom Optimizer benutzt würde. ROWID(tabname)
Der Zugriff auf die angegebene Tabelle wird über einen Table Scan by ROWID durchgeführt. In der entsprechenden Abfrage wird in der WHERE-Klausel eine Einschränkung wie ROWID > 'AAAG5kAAFAAABQiAAB’ in Kombination mit anderen Bedingungen verwendet, wobei durch den Hint der Einschränkung durch die ROWID der Vorzug gegeben werden sollte. INDEX_COMBINE(tabname bitmap_indname1 bitmap_indname2)
Dieser Hint erzwingt den Zugriff auf die angegebene Tabelle über eine boolesche Kombination von Bitmap-Indizes. Um Indizes für den Zugriff kombinieren zu können, gilt als Voraussetzung, dass es sich um Bitmap-Indizes handelt. Sollten die angegebenen Indizes B*Baum-Indizes sein, ist es möglich, dass eine interne Konvertierung vorgeschaltet wird. Ob dann noch ein Vorteil beim Zugriff messbar ist, muss ermittelt werden. CLUSTER(tabname), HASH(tabname)
Die Hints CLUSTER und HASH können nur auf Tabellen angewendet werden, die in einem Oracle-Tabellen-Cluster abgelegt sind, und fordern für diese einen ClusterScan oder einen Hash-Scan an. INDEX_ASC(tabname, indname), INDEX_DESC(tabname indname)
Diese beiden Hints fordern Index-Range-Scans auf die angegebene Tabelle über den angegebenen Index an. Da Oracle standardmäßig eine aufsteigende Reihenfolge verwendet, ist die Funktion von INDEX_ASC identisch mit der des Hints INDEX. Bei INDEX_DESC wird der Index-Scan in absteigender Reihenfolge durchgeführt.
Sandini Bib
Zugriffsoptimierung
511
INDEX_FFS(tabname indname)
Es wird ein Index-Fast-Full-Scan angefordert. Hierbei wird der gesamte Index durchgelesen. Kann über die Felder des angegebenen Index die Abfrage beschickt werden, so kann dadurch ein Full-Table-Scan auf die Tabelle ersetzt werden. NO_INDEX(tabname [indname [,indname]])
Mit dem NO_INDEX-Hint kann die Benutzung einzelner Indizes oder aller Indizes für den Optimizer ausgeschaltet werden, die auf der spezifizierten Tabelle liegen. AND_EQUAL(tabname indname, indname [,indname …])
Es wird ein MERGE der Ergebnisse von Index-Scans erzwungen. Voraussetzung ist, dass es sich bei den angegebenen Indizes um Indizes auf jeweils nur ein Feld handelt. Es müssen mindestens zwei Indizes angegeben werden. Die maximale Zahl der Indizes im Hint beträgt fünf. Hints für Join-Reihenfolgen und Join-Operationen ORDERED
Der ORDERED-Hint kennt keine weiteren Parameter. Er bestimmt, dass die Zugriffe auf die Tabellen in der Reihenfolge ausgeführt werden, wie sie in der FROM-Klausel angegeben ist. Stellen Sie bei der Verwendung dieses Hints aber sicher, dass auch entsprechende Join-Kriterien zur Verfügung stehen, um von einer Tabelle zur nächsten zu kommen. Ansonsten könnten Sie mit diesem Hint kartesische Produkte als Zwischenschritte erzeugen. STAR
An einer STAR-Query sind mindestens drei Tabellen beteiligt, wobei mindestens zwei Tabellen „klein“ und nur eine Tabelle „groß“ ist. Die „große Tabelle“ hat dazu einen konkatenierten Index auf mindestens drei Felder. Bei einem „Star-Plan“ werden zuerst die kleinen Tabellen gelesen, wobei der Optimizer die Zugriffe auf diese selbst optimiert. Die große Tabelle wird dann als Letzte über eine Nested-Loop mit einem Zugriff über den konkatenierten Index hinzugefügt. Der Hint STAR ist nur dann wirksam, wenn die beschriebenen Randbedingungen gegeben sind und kein anderer Hint die Nutzung der Star-Query verbietet. USE_NL(tabname [tabname...])
Es wird die Benutzung von Nested-Loops, also von verschachtelten Schleifen, erzwungen. Dabei beschreibt die im Hint angegebene Tabelle diejenige, die über eine verschachtelte Schleife an eine bereits existierende Ergebnismenge angehängt werden soll. Beispiel: SQL> SELECT /*+ USE_NL(p) */ aufnr, aufpos, wert FROM auftraege a, positionen p
Sandini Bib
512
Optimierung
WHERE a.aufnr = p.aufnr;
In diesem Beispiel wird also zuerst die Tabelle auftraege gelesen. Auf die Tabelle positionen wird dann innerhalb einer Nested-Loop zugegriffen, wobei die Tabelle auftraege die treibende Tabelle darstellt. USE_MERGE(tabname [tabname...])
Mit diesem Hint wird ein Merge-Join erzwungen. Bei einem Merge-Join werden die beteiligten Tabellen nach dem Join-Kriterium sortiert und die Ergebnismengen gemischt, also übereinander gelegt. Diese Join-Methode ist bei kleinen Tabellen sehr effektiv. Sobald aber der Hauptspeicherbereich pro Prozess, der mit dem Parameter sort_area_size eingestellt ist, überschritten ist und die Sortierzwischenschritte auf den Temporary-Tablespace ausgelagert werden müssen, geht die Effektivität verloren. Dann ist eine Nested Loop vorzuziehen. Die Parametrierung ist hier die gleiche wie beim USE_NL. USE_HASH(tabname [tabname...])
Dieser Hint hat die gleiche Parametrierung wie die beiden vorhergehenden. Hier werden die spezifizierten Tabellen über einen Hash-Join verbunden, wobei für den Zugriff von der treibenden Tabelle aus über eine Satzadresse geschieht, die über einen Hash-Algorithmus berechnet wird. Auch für die Verwendung des Hash-Algorithmus muss ein Sortierproblem gelöst werden. Der dafür zur Verfügung stehende Hauptspeicherbereich pro Prozess wird über den Parameter hash_area_size eingestellt, der als Standardwert das Doppelte der sort_area_size hat. DRIVING_SITE(tabname)
Dieser Hint ist nur interessant für Abfragen, die Tabellen aus unterschiedlichen Datenbanken in Relation setzen. Über diesen Hint wird die Datenbank bzw. die damit verbundene Instanz festgelegt, auf deren Seite die Aktivität des Joins ausgeführt wird. Beispiel: SQL> SELECT FROM WHERE AND
kdnr, kdname, aufnr, aufwert kunden k, auftraege@aufdb k.kdnr = :var_kdnr k.kdnr = a.kdnr;
Normalerweise werden die benötigten Datensätze auf die lokale Seite transportiert. In diesem Fall werden also die Sätze aus der Tabelle auftraege von der Instanz aufdb auf die lokale Seite geholt, wo der Join dann ausgeführt wird. Es wäre jedoch viel effektiver, nur den einen Satz für den entsprechenden Kunden auf die entfernte Seite zu transportieren und dann dort die Ergebnismenge zu ermitteln. Dieses kann mit dem folgenden Hint erreicht werden: SQL> SELECT /*+ DRIVING_SITE(auftraege) */ kdnr, kdname, aufnr,aufwert FROM kunden k, auftraege@aufdb WHERE k.kdnr = :var_kdnr
Sandini Bib
Zugriffsoptimierung
AND
513
k.kdnr = a.kdnr;
LEADING(tabname)
Mit dem Hint LEADING kann genau eine Tabelle angegeben werden, die als treibende Tabelle benutzt wird. Die Join-Reihenfolge der weiteren Tabellen aus der FROM-Klausel wird durch den Optimizer ermittelt. Wird mehr als eine Tabelle angegeben, so wird der Hint ignoriert. Ein ORDERED-Hint überschreibt den LEADINGHint. HASH_AJ, MERGE_AJ, NL_AJ
Diese Hints können in einer NOT-IN-Unterabfrage dazu benutzt werden, um die Join-Methode zu bestimmen, die für die Unterabfrage verewndet wird. AJ steht dabei für Anti-Join, also die Auflösung des NOT-IN. HASH_SJ, MERGE_SJ, NL_SJ SJ steht für SEMI-Join. Diese Hints können für die Optimierung des SELECT-
Befehls in einer EXITS-Unterabfrage benutzt werden. Dabei müssen folgende Voraussetzungen zutreffen:
: : : :
Die Unterabfrage darf nur auf eine Tabelle gehen. Die aufrufende Abfrage selbst darf keine Unterabfrage sein. Es muss sich um eine mit einem Gleichheitsoperator korrelierte Unterabfrage handeln. In der Unterabfrage dürfen keine GROUP BY- und CONNECT BY-Klauseln verwendet werden, ebenso dürfen keine Einschränkungen auf ROWNUM vorhanden sein.
Globale Hints Eine Problematik bei der Verwendung von Hints stellt sich, wenn in der FROMKlausel einer Abfrage Views verwendet werden. Die Zugriffspfade können dann nicht direkt mit den üblichen Hints beeinflusst werden. Es ist jedoch auch nicht anzuraten, Hints innerhalb der SELECT-Anweisung in einer View zu spezifizieren, da man dadurch Abfragen negativ beeinflussen könnte, die diese View ebenfalls verwenden, aber andere WHERE-Klauseln haben. Die Lösung dieses Problems sind globale Hints, die aus dem aufrufenden SELECT-Befehl den Ausführungsplan innerhalb der View bestimmen. Beispiel: SQL> CREATE VIEW auftrag_positionen AS SELECT a.aufnr, a.kdnr, a.kdname, a.aufstatus, p.posnr, p.artnr, p.poswert FROM auftraege a, positionen p WHERE a.aufnr = p.aufnr SQL> SELECT * FROM auftrag_positionen ap where ap.aufstatus = 'O';
Sandini Bib
514
Optimierung
Da nur eine kleine Anzahl der Aufträge im System den Status offen hat, wäre ein Zugriff über einen Index auf dem Feld aufstatus sehr attraktiv, obwohl laut Statistik der Index eine geringe Selektivität aufweist. Es würde sich hier absolut verbieten, einen Hint zur Erzwingung des indizierten Zugriffs in die View selbst zu schreiben, da dies für einen Zugriff auf die Daten mit aufstatus „geliefert“ hochgradig kontraproduktiv wäre. Hier sollten Sie also einen globalen Hint in folgender Form nutzen: SQL> SELECT /*+ INDEX(ap.a ind_aufstatatus) */ * FROM auftrag_positionen ap WHERE ap.aufstatus = 'O';
Der globale Hint verweist also mit der Nomenklatur ap.a auf die Tabelle mit dem Alias a in der View mit dem Alias ap. Hints zur Parallelisierung PARALLEL(tabname, n | DEFAULT [,n | DEFAULT])
Der Hint zur Parallelisierung kann sowohl für SELECT-Anweisungen als auch für DML-Anweisungen genutzt werden und bestimmt die Anzahl der Serverprozesse, die für die Abarbeitung des Befehls genutzt werden. Dabei gibt der erste Wert die Anzahl der Serverprozesse an, der zweite Wert, wie diese Serverprozesse auf Instanzen in einem Oracle Real Application Cluster (RAC, in früheren Versionen Oracle Parallel Server, OPS, genannt) verteilt werden. Wird der Wert DEFAULT spezifiziert, so werden die Werte der entsprechenden Initialisierungsparameter verwendet. Die Anzahl der wirklichen benutzten Serverprozesse kann doppelt so hoch sein wie angegeben, wenn nämlich in der Abfrage mit einer ORDER BY- oder GROUP BY-Operation gearbeitet wird. Die angegebene Anzahl von Serverprozessen wird dann für die Abarbeitung der Abfrage genutzt, für die Sortieroperation wird noch einmal die gleiche Anzahl von Prozessen gestartet. Der Hint wird ignoriert, sobald eine Voraussetzung für die Möglichkeit des Parallelisierens nicht gegeben ist. NOPARALLEL(tabname)
Mit dem Hint NOPARALLEL kann eine auf Tabellenebene eingestellte Parallelisierung ausgeschaltet werden. PQ_DISTRIBUTE(tabname_innere_Tabelle, Lieferung äußerer Tabelle, Lieferung innerer Tabelle)
Dieser sehr komplizierte Hint hilft bei der Optimierung eines Joins. Hier werden die Wege beschrieben, wie die Daten der äußeren treibenden Tabelle von parallelen Prozessen an die parallelen Prozesse der inneren Tabelle geliefert werden. Im Folgenden werden die möglichen Kombinationen beschrieben und die Fälle, in denen sie angewendet werden sollten:
Sandini Bib
Zugriffsoptimierung
515
HASH, HASH
Beide Tabellen ähnlich groß, Join-Operation ist Merge-Join oder Hash-Join. BROADCAST, NONE
Die äußere Tabelle ist wesentlich kleiner als die innere Tabelle (Größe äußere Tabelle * Anzahl Serverprozesse < innere Tabelle). NONE, BROADCAST
Der umgekehrte Fall wie vorher. PARTITION, NONE
Ordnet die Sätze der äußeren Tabelle Partitionen der inneren Tabelle zu. Die innere Tabelle muss partitioniert sein, und zwar über die Schlüssel, über die auch der Join durchgeführt wird. Die Anzahl der Partitionen der äußeren Tabelle sollte dabei etwa einem Vielfachen der Anzahl der „Query Server“ entsprechen. NONE, PARTITION
Der umgekehrte Fall wie vorher. NONE, NONE
Jeder Query Server beschäftigt sich mit den übereinstimmenden Partitionen zweier „equi-partitionierter“ Tabellen, die über das Partitionierungskriterium verbunden werden. PARALLEL_INDEX(tabname indname, n | DEFAULT [,n | DEFAULT])
Über diesen Hint wird der Parallelisierungsgrad für einen Index-Scan auf einen partitionierten Index ausgewählt. Wie beim PARALLEL-Hint beschreibt der erste Wert nach dem Namen des Indexes den Grad der Parallelisierung, der zweite Wert die Anzahl der zu nutzenden RAC-Instanzen. So bedeutet (tabname indname, 4, 2), dass auf zwei RAC-Instanzen jeweils vier Query-Prozesse benutzt werden. DEFAULT bewirkt die Standardeinstellungen der Initialisierungsparameter. NOPARALLEL_INDEX(tabname indname)
Schaltet den auf Index-Ebene eingestellten Grad der Parallelisierung aus. Hints für Abfragetransformationen USE_CONCAT
Hierdurch wird die Transformation von kombinierten OR-Bedingungen in einer WHERE-Klausel in eine UNION ALL-Operation erzwungen. NO_EXPAND
OR-Expansionen werden vermieden. Es werden, in Umkehrung zum USE_CONCATHint, OR-Operatoren oder IN-List-Operationen bevorzugt. REWRITE
Bei der Verwendung von Materialized Views können Abfragen auf Tabellen durch Oracle auf die Verwendung dieser Materialized Views umgeschrieben werden. Dazu muss der Initialisierungsparameter query_rewrite_enabled = true gesetzt sein.
Sandini Bib
516
Optimierung
Der Hint erzwingt dieses Verfahren ohne Berücksichtigung der kalkulierten Kosten. NOREWRITE
Verbietet das Umschreiben einer Abfrage, auch wenn der Initialisierungsparameter query_rewrite_enabled = true gesetzt ist. MERGE(tabname)
Der Hint beschreibt das Verfahren, wie eine SQL-Abfrage in einer View mit der SQL-Abfrage verbunden wird, die diese View verwendet. Der Hint MERGE erzwingt die Verschmelzung der Abfragen. NO_MERGE(tabname)
Die Verschmelzung der Abfrage in einer View mit der aufrufenden Abfrage wird verhindert, auch wenn dieses möglich wäre. Sie erhalten dadurch mehr Kontrolle über den Zeitpunkt der Abarbeitung der View. STAR_TRANSFORMATION
Wird dieser Hint angegeben, so wird der Optimizer angewiesen, nach dem besten Zugriffsplan unter Einschluss der Transformation der Abfrage zu ermitteln. Ansonsten könnte er nach dem besten kostenbasierten Ansatz ohne Umschreiben der Join-Operationen in Subqueries abbrechen. Auch wenn Sie diesen Hint angeben, ist nicht sichergestellt, dass eine Transformation genutzt wird. Lassen sich Subqueries nicht aufbauen oder ist der damit errechnete Zugriffsplan schlechter, so wird die nicht transformierte Abfrage benutzt. FACT(tabname)
Sie können über diesen Hint in Verbindung mit der Star-Transformation eine Tabelle bestimmen, die als Faktentabelle benutzt wird. NO_FACT(tabname)
Die hier angegebene Tabelle wird als Faktentabelle bei der Star-Transformation ausgeschlossen. Diverse Hints APPEND
Der APPEND-Hint aktiviert den Direct Path-Modus für einen INSERT-Befehl. Dabei wird, vergleichbar mit dem direkten Pfad des Oracle-Loaders, das normale SQLHandling umgangen. Die Daten werden nicht über den Database Buffer Cache geschickt, und Integritätsbedingungen werden ignoriert. APPEND gibt an, dass die Datensätze in nicht benutzte Blöcke ans Ende der Tabelle geschrieben werden. Die im seriellen Modus durchgeführte Platzverwaltung über Free Block Lists wird nicht benutzt. Im Append-Modus können wesentlich bessere Zeiten für Inserts erreicht werden.
Sandini Bib
Zugriffsoptimierung
517
NOAPPEND
Der Append-Modus ist die Standardeinstellung bei paralleler Verarbeitung. Über den Hint NOAPPEND kann dieser Modus in der Parallelverarbeitung deaktiviert werden. CACHE(tabname)
Blöcke einer Tabelle, die durch einen Full-Table-Scan gelesen werden, werden nicht über den Least Recently Used(LRU)-Algorithmus im Database Buffer Cache verwaltet, sondern direkt zum Überschreiben freigegeben. Bei kleinen Tabellen, die als Referenztabellen dienen und immer wiederkehrend gelesen werden, empfiehlt es sich, diese Blöcke über den LRU-Algorithmus verwalten zu lassen. Das kann über den Hint CACHE für eine Tabelle erreicht werden (alternativ lässt sich der Parameter CACHE auf Tabellen-Ebene setzen). NOCACHE(tabname)
Mit NOCACHE kann die LRU-Verwaltung, die auf Tabellenebene parametriert ist, für einen Befehl deaktiviert werden. UNNEST
Dieser Hint kann nur verwendet werden, wenn auf Prozessebene der Parameter unnnest_subquery auf true gesetzt ist. Eine Subquery kann dann intern in einen Join umgeschrieben werden, um dem Optimizer andere Zugriffspfade zu ermöglichen. Der UNNEST-Hint bewirkt lediglich die Prüfung der Unterabfrage auf Gültigkeit. NO_UNNEST
Der NO_UNNEST-Hint deaktiviert die Möglichkeit der Auflösung der Subqueries in Joins für einen Block, obwohl der unnest_subquery-Parameter auf Sitzungsebene gesetzt ist. PUSH_PRED(viewname)
Wird in einem SELECT-Befehl ein Join zwischen einer Tabelle und einer View ausgeführt, so kann mit diesem Hint das Join-Prädikat in die View geschoben werden. NO_PUSH_PRED(viewname)
Das Verschieben des Join-Prädikats in die View wird verhindert. PUSH_SUBQ
Dieser Hint bewirkt, dass eine nicht korrelierte Subquery, die normalerweise zuletzt ausgeführt würde, im Ausführungsplan an erster Stelle steht. Das ist dann sinnvoll, wenn die Subquery nur wenig aufwändig ist, dadurch aber die Treffermenge beim Zugriff auf die weiteren Tabellen signifikant reduziert werden kann. ORDERED_PREDICATES
Alle bisher beschriebenen Hints folgen sofort auf die Einleitung des Befehls. ORDERED_PREDICATES hingegen wird in der WHERE-Klausel eines SQL-Befehls angegeben und erzwingt die Beibehaltung der Reihenfolge für die Auswertung der Prädikate, wobei indizierte Spalten ausgenommen sind. Es geht also hier um die
Sandini Bib
518
Optimierung
Reihenfolge der Ausführung von benutzerdefinierten Funktionen, Typmethoden und Subqueries. CURSOR_SHARING_EXACT
Der Initialisierungsparameter cursor_sharing = exact | force bestimmt, ob in der Parsing-Phase eines SQL-Befehls versucht wird, Literale in einem Befehl durch Bindevariablen zu ersetzen. Der hier genannte Hint verhindert die Ersetzung von Literalen für den Befehl, in dem er spezifiziert wurde.
7.3.5
Cluster
Mit der Speichermethode des Clustering kann Einfluss auf die physikalische Lage von Datensätzen genommen werden. Index-Cluster können seit Oracle Version 6 definiert werden, Hash-Cluster sind seit Oracle7 möglich. Nähere Informationen zur Verwendung von Index- und Hash-Clustern finden Sie in Kapitel 3. Hier sollen nur kurz Möglichkeiten der Nutzung unter Performance-Aspekten erörtert werden. Index-Cluster Bei Index-Clustern übernimmt ein B*-Index, der so genannte Cluster-Index, die Reservierung einzelner Blöcke für bestimmte Clusterschlüssel. Ein Anwendungsbereich bietet sich, wenn Datensätze aus zwei Tabellen generell nur in Verbindung verwendet werden. In diesem Fall ist es natürlich sehr sinnvoll, diese Datensätze auch physikalisch zusammen abzulegen. Jedoch entstehen gravierende Nachteile, wenn nur auf Sätze einer Tabelle zugegriffen werden muss. Es kann sich auch anbieten, eine einzelne Tabelle als Index-Cluster zu organisieren. Durch die Cluster-Organisation sind ja die Datensätze sortiert gespeichert. Das bedeutet, dass DML-Operationen aufwändiger sind, da ein entsprechender Block für einen Schlüssel erst ermittelt werden muss und auch das Platz-Management innerhalb eines Blocks aufwändiger ist. Bei Abfragen, die Gruppen von Sätzen zu einem Cluster-Schlüssel ermitteln müssen, kann natürlich dann auf einen zusammenhängenden Datenbestand zugegriffen werden, was die Anzahl der zu lesenden Blöcke drastisch reduzieren kann. Hash-Cluster Hash-Cluster sind nur dann anzuraten, wenn extrem schnelle Zugriffe auf eine von der Datenmenge her sehr statische Tabelle vorgenommen werden. Die Hash-Operation berechnet ja auf Grund eines Schlüsselwertes eine Satzadresse. Dieses Verfahren funktioniert nur dann, wenn von vorneherein die Anzahl der Sätze bekannt ist. Entsprechender Platz muss auch in der Datenbank allokiert werden. Aus diesen Gründen wird es nur sehr wenige Fälle geben, die den Einsatz von HashClustern ermöglichen.
Sandini Bib
Zugriffsoptimierung
7.3.6
519
Partitionierung
Hier sollen nur die Bereiche der Partitioning Option besprochen werden, die die Optimierung von SQL-Befehlen unterstützen. Besonders interessant werden diese Möglichkeiten in Data Warehouse-Umgebungen, wenn zusätzlich auch die Parallel Query Option eingesetzt wird. Hier bieten sich dann diverse Möglichkeiten der Unterstützung der parallelen Verarbeitung, die aber auch Berücksichtigung bei der Konfiguration des I/O-Systems finden muss, damit an dieser Stelle keine Engpässe entstehen. Partition Pruning Die Informationen über die Wertebereiche in den Partitionen sind im Data Dictionary der Datenbank abgelegt und können vom kostenbasierten Optimizer ausgewertet werden. So können bei WHERE-Bedingungen mit Bereichen oder Abfragen auf Gleichheit sofort Partitionen für den Zugriff eliminiert werden. Über diese Möglichkeit lassen sich bei großen Tabellen Zugriffe auf große Teile der Datenmenge vermeiden. Hier ist auch ein Vorteil des „Equi-Partitioning“ zu erkennen. Wenn für den Index die gleichen Partitionen ausgeblendet werden können, werden die zu durchsuchenden Bereiche der B*Bäume natürlich auch kleiner und damit performanter. Partition Level Optimization Der kostenbasierte Optimizer kann pro Partition unterschiedliche Zugriffsmethoden, also z.B. Full-Table-Scan oder Indexnutzung, bestimmen und ausführen. So können Abfragen, die über mehr als eine Partition gehen, Teilergebnismengen aus den verschiedenen Partitionen über unterschiedliche Zugriffspfade erhalten. Wird aus einer der Partitionen nur eine geringe Datenmenge benötigt, so kann diese indiziert gelesen werden, wohingegen für andere Partitionen, aus denen Großteile der Sätze gelesen werden, ein Full-Table-Scan verwendet wird. Partition-Wise-Joins Wird bei einem Join auf zwei äquipartitionierte Tabellen zugegriffen, die nach dem Join-Kriterium partitioniert sind, so wird dieser Join in mehrere kleinere Joins aufgebrochen, die jeweils die entsprechenden Partitionen der Tabellen miteinander verbinden. Diese Teile werden dann sequenziell nacheinander bearbeitet, können aber unter der Voraussetzung, dass die Parallel Query Option eingesetzt wird, auch parallel bearbeitet werden. Die Parallelverarbeitung bringt zusätzlich den Vorteil mit sich, dass die Datenmenge, die zwischen den Parallel Query-Prozessen ausgetauscht werden muss, wesentlich reduziert ist. Der Parallelisierungsgrad ist dabei auf die Anzahl der Partitionen beschränkt. Diese Optimierung ist bei Range-partitionierten Tabellen, aber auch bei Hash-Partitioning oder Composite-Partitioning möglich, was natürlich eine extreme Möglichkeit der Parallelisierung bietet, aber auch sehr hohe Anforderungen an die I/O-Bandbreite stellt.
Sandini Bib
520
7.3.7
Optimierung
Gespeicherte Statistiken
Es ist wünschenswert, dass SQL-Befehle auf ihre Performance hin getestet werden, bevor sie in den Produktionsbetrieb gehen. Insbesondere dann, wenn der kostenbasierte Optimizer genutzt wird, stellt sich diese Untersuchung auf dem Entwicklungs- oder Testrechner als sehr problematisch dar, da diese Rechner immer kleiner ausgelegt sind als das Produktionssystem und keinen kompletten Abzug der Produktionsdaten bieten. Ein solcher Aufwand ist meist aus Kostengründen nicht möglich und auch unter Datenschutzgesichtspunkten problematisch. Hier bieten die gespeicherten Statistiken einen Lösungsweg. Über Prozeduren des mitgelieferten Packages dbms_stats können Statistiken von Tabellen, Indizes und Feldern aus dem Data Dictionary in eine Statistiktabelle exportiert werden. Diese Statistiktabelle kann auf ein Testsystem übertragen werden, aus dem dann die Statistiken der Produktionsdatenbank in das Data Dictionary der Testdatenbank importiert werden können. Über diesen Weg kann ohne physikalischen Platzbedarf eine große Datenbank für den kostenbasierten Optimizer simuliert werden. Eine weitergehende Möglichkeit der Simulation ist auch das manuelle Verändern der Statistiken. So kann der Einfluss einer Veränderung in der Statistik auf Ausführungspläne im Vorfeld bestimmt werden. Das Arbeiten mit gespeicherten Statistiken soll für Tabellenstatistiken an einem einfachen Beispiel erläutert werden. Das Schema bzw. der Datenbankbenutzer mit dem in diesem Beispiel gearbeitet wird, sei hladmin. Unter diesem Schema muss als Erstes auf der Produktionsdatenbank eine Statistiktabelle aufgebaut werden. SQL> execute dbms_stats.create_stat_table('HLADMIN','STAT_TAB');
Nun können die Statistikinformationen für eine Tabelle, z.B. kunden, in die Statistiktabelle exportiert werden. SQL> execute dbms_stats.export_table_stats ('HLADMIN','KUNDEN',NULL,'STAT_TAB',1,TRUE,'HLADMIN');
Parameter: HLADMIN
Eigentümer der Tabelle, deren Statistiken exportiert werden.
KUNDEN
Tabellenname
NULL
Partition; NULL, wenn die Tabelle nicht partitioniert ist.
STAT_TAB
Name der Statistiktabelle.
1
Nummerierung der Statistik für diese Tabelle.
TRUE
CASCADE=TRUE, d.h., Statistiken für Indizes und Spalten werden
mit exportiert.
Sandini Bib
Zugriffsoptimierung HLADMIN
521
Eigentümer der Statistiktabelle, braucht nur angegeben zu werden, wenn sie vom aktuellen Schema abweicht.
Die so gefüllte Statistiktabelle stat_tab kann nun über einen Datenbank-Link oder mit den Werkzeugen exp/imp auf das Testsystem übertragen werden. Hier können optional noch Statistikinformationen verändert werden, um andere Datenmengen oder Schlüsselverteilungen zu simulieren. SQL> execute dbms_stats.set_table_stats ('HLADMIN','KUNDEN',NULL,'STAT_TAB', 1,10000,1000,NULL,NULL,NULL,NULL,NULL,NULL,'HLADMIN');
Hier würde eingestellt, dass die Tabelle kunden 10.000 Sätze hat, die auf 1.000 Blöcke verteilt sind. Die restlichen Statistikwerte werden nicht modifiziert. Nun können die Statistiken aus der Statistiktabelle in das Data Dictionary der Testdatenbank importiert werden. SQL> execute dbms_stats.import_table_stats ('HLADMIN','KUNDEN',NULL,'STAT_TAB',1,TRUE,'HLADMIN');
Am Beispiel ist zu erkennen, dass die Handhabung relativ kompliziert ist. Die Prozeduren für Indexstatistiken und Feldstatistiken haben wiederum abweichende Parameterleisten. Es sei hier auf die Documentation Oracle9i Supplied PL/SQL Packages and Types Reference verwiesen. Für dbms_stats sind sämtliche Prozeduren mit ihren Parametern ausführlich beschrieben. Speicherung von historischen Statistiken Die Möglichkeit der Speicherung von Statistiken kann auch dazu genutzt werden, um eine Historie der Statistiken zu verwalten. Im Beispiel ist gezeigt worden, dass gespeicherte Statistiken mit einer stat_id gekennzeichnet werden können. So können mehrere Stände der Statistiken aufbewahrt werden. So können Sie auch beim Analysieren von Objekten über dbms_stats. oder dbms_stats. dbms_stats.gather_schema_stats gather_table_stats, gather_database_stats einstellen, dass die vorher existierenden Statistiken unter einer bestimmten stat_id in einer Statistiktabelle gespeichert werden sollen. Sie haben dann sogar die Möglichkeit, die alten Statistiken zurückzuholen, wenn aus den neuen Statistiken Ausführungspläne mit schlechterer Performance resultieren.
7.3.8
Plan Stability
Trotz gespeicherter Statistiken kann ein Entwickler nicht garantieren, dass ein für ein Produktionssystem ausgelieferter SQL-Befehl den gleichen Ausführungsplan wie auf seinem Testsystem hat. Bei kostenbasierten Optimizer kann eine Änderung des Ausführungsplans durch die Aktualisierung der Statistiken stattfinden, aber auch durch Instanzparameter, die sich von denen des Testsystems unterscheiden. Besonders geht es hier um Para-
Sandini Bib
522
Optimierung
meter wie db_cache_size und sort_area_size. Die Lösung dieses Problems heißt Plan Stability. Gespeicherte Ausführungspläne werden als Stored Outlines bezeichnet. Ein Ausführungsplan für einen SQL-Befehl kann während der Ausführung aufgezeichnet werden. Sobald ein identischer SQL-Befehl ausgeführt wird, wird dieser gespeicherte Ausführungsplan verwendet. Die Erkennung von identischen Befehlen ist dabei äquivalent zu der im Shared Pool. Das bedeutet, dass die Verwendung von Literalen oder zusätzliche Leerzeichen die Verwendung verhindert. Hier ist aber auch die automatische Ersetzung von Literalen durch Bindevariablen möglich, die über den Initialisierungsparameter cursor_sharing = force | similar erreicht werden kann. Die Zugriffspfade werden in den Data Dictionary-Tabellen OL$, OL$HINTS und OL$NODES abgelegt, deren Eigentümer der automatisch bei der Erstellung der Datenbank angelegte Benutzer OUTLN ist. Stored Outlines können in unterschiedlichen Kategorien abgelegt werden. Es existiert eine feste Kategorie mit dem Namen DEFAULT. Weitere Kategorien können angelegt und individuell benannt werden. Voraussetzungen Um mit Stored Outlines arbeiten zu können, muss eine Reihe von Voraussetzungen zutreffen:
: : :
Der Initialisierungsparameter query_rewrite_enabled muss auf true gesetzt sein. Der Initialisierungsparameter star_transformation_enabled muss auf true gesetzt sein. Der Initialisierungsparameter optimizer_features_enable muss auf allen Systemen, die dieselben Stored Outlines verwenden, auf identischen Werten stehen.
Anlegen von Stored Outlines Zum Anlegen von Stored Outlines gibt es zwei Möglichkeiten: 1. Aktivierung der Aufzeichnung von Ausführungsplänen auf der Sitzungsebene: SQL> ALTER SESSION SET CREATE_STORED_OUTLINES = TRUE;
Für alle SQL-Befehle, die nach der Aktivierung ausgeführt werden, werden die Zugriffspläne gespeichert, und zwar in der Standardkategorie DEFAULT. Möchten Sie in eine selbst benannte Kategorie, z.B. rule_cat, speichern, so sieht die Aktivierung wie folgt aus: SQL> ALTER SESSION SET CREATE_STORED_OUTLINES = rule_cat;
Sandini Bib
Zugriffsoptimierung
523
Möchten Sie die Aufzeichnung von Ausführungsplänen beenden, so geben Sie ein: SQL> ALTER SESSION SET CREATE_STORED_OUTLINES = FALSE;
2. Benutzung des SQL-Kommandos CREATE OUTLINE Sie können auch gezielt für einen SQL-Befehl eine Stored Outline erstellen. Es ist jedoch darauf zu achten, dass es bei dieser Art der Erstellung nicht möglich ist, den Parameter cursor_sharing zu berücksichtigen, so dass bei Befehlen mit Literalen keine Übereinstimmung erkannt wird. SQL> CREATE OUTLINE zugriff_1 FOR CATEGORY rule_cat ON SELECT ...;
Public Outlines und Private Outlines Neben unterschiedlichen Kategorien können Sie auch Private Outlines definieren. Dazu müssen Sie sich zuerst eigene Outline-Tabellen definieren. SQL> execute dbms_outln_edit.create_edit_tables;
Nun kann mit dem Befehl SQL> CREATE PRIVATE OUTLINE priv_zugriff_1 ON SELECT ...;
eine neue Private Outline erzeugt werden. Sie können sich aber auch eine Stored (Public) Outline in eine Private Outline kopieren; SQL> CREATE PRIVATE OUTLINE priv_zugriff_1 FROM zugriff_1;
Private Outlines werden dann verwendet, wenn über den Enterprise Manager, Tuning Pack, Outline Management oder die Prozedur dbms_outln_edit. change_join_pos die Join-Reihenfolge vertauscht werden soll. Damit Fehler, die hier entstehen können, nicht nach außen getragen werden, kann also in einer lokalen Kopie gestestet werden. Wird manuell editiert, so muss anschließend eine Synchronisierung ausgeführt werden. SQL> CREATE PRIVATE OUTLINE priv_zugriff_1 FROM PRIVATE priv_zugriff_1;
Nach einem Test kann die Private Outline wieder in die Public Outline überstellt werden. SQL> CREATE OR REPLACE OUTLINE zugriff_1 FROM PRIVATE priv_zugriff_1;
Sandini Bib
524
Optimierung
Verwendung der Stored Outlines Bisher ist beschrieben worden, wie Stored Outlines erstellt werden. Damit identische SQL-Befehle diese gespeicherten Zugriffspfade auch nutzen, muss entweder auf Sitzungs- oder auf Systemebene der entsprechende Parameter aktiviert werden. SQL> ALTER SESSION | SYSTEM SET USE_STORED_OUTLINES = TRUE | category;
Die Nutzung von Private Outlines ist ausschließlich auf Sitzungsebene möglich und kann daher auch nicht generell über einen Systemparameter oder von außen gesetzt werden. SQL> ALTER SESSION SET USE_PRIVATE_OUTLINES = TRUE | category;
Nach Aktivierung eines dieser Parameter wird also die Erkennung identischer Befehle ausgeführt und der entsprechende gespeicherte Ausführungsplan benutzt. Administration von Stored Outlines Die in der Datenbank abgelegten Stored Outlines können nun vom Administrator abgefragt werden, müssen aber auch überwacht und verwaltet werden. Abfragemöglichkeiten Zwei Views, dba_outlines und dba_outline_hints, liefern die Daten aus den Dictionary-Tabellen OL$, OL$HINTS und OL$NODES.
In dba_outlines wird die Zuordnung von Stored Outlines mit Namen zu Kategorien und SQL-Befehlen dargestellt. dba_outline_hints zeigt zu den einzelnen Stored Outlines die Zugriffspfade.
Verwaltung von Kategorien Einzelne Stored Outlines können von einer Kategorie
in eine andere verlegt werden. Das ist z.B. dann sinnvoll, wenn erkannt wird, dass ein gespeicherter Zugriffspfad nicht performant ist. In diesem Fall kann eine Kategorie für Problemfälle definiert werden, in die diese Stored Outlines dann ausgelagert werden. Dort können sie dann weiter untersucht werden, stören aber nicht mehr bei der Benutzung der allgemeinen Kategorie. SQL> ALTER OUTLINE zugriff_1 CHANGE_CATEGORY TO problem_cat;
Weiterhin steht ein Package zur Verfügung, das für die Administration verwendet werden sollte. Die wichtigen Prozeduren aus dem Package dbms_outln sind: drop_by_cat
Löscht alle Stored Outlines einer bestimmten Kategorie.
drop_unused
Löscht alle Stored Outlines aller Kategorien, die noch nie verwendet worden sind.
drop_unrefd_hints
Löscht alle Stored Outline Hints, die keine Beziehung zu Stored Outlines haben.
update_by_cat
Ordnet alle Stored Outlines einer Kategorie einer anderen zu.
Sandini Bib
Zugriffsoptimierung
525
Export und Import von Stored Outlines Mit Hilfe der Stored Outlines ist es nun
möglich, feste Zugriffspfade für SQL-Zugriffe einer Anwendung mitauszuliefern. Dazu können diese aus den Data Dictionary-Tabellen exportiert werden. Mit Hilfe des QUERY-Parameters des Exports ist es so auch möglich, nur bestimmte Kategorien zu extrahieren. $ exp system/pwd file=ol.dmp tables=(outln.ol$, outln.ol$hints, outln.ol$nodes) query='WHERE CATEGORY=''DEFAULT'''
In diesem Beispiel wird nur die Kategorie DEFAULT exportiert. Da der QUERY-Parameter nur bei tabellenbezogenem Export möglich ist, müssen hier die drei beteiligten Tabellen explizit aufgeführt werden. Wird die Exportdatei nun in die Zieldatenbank importiert, sind die gespeicherten Ausführungspläne dort vorhanden und können aktiviert werden. Oracle Enterprise Manager Wenn Sie das Tuning-Pack des Oracle Enterprise Mana-
gers verwenden, können Sie Stored Outlines über den Menüpunkt OUTLINE MANAGEMENT verwalten. Die Verwendung ist recht einfach, die einzelnen Menüpunkte erlauben es, sich zunächst einen Ausführungsplan in grafischer Form anzeigen zu lassen und diesen dann entsprechend den eigenen Anforderungen zu verändern. Änderungen können zum Beispiel die Reihenfolge der Befehlsteile oder aber der Zugriffsweg (Index, Table-Scan, etc.) sein. Im Untermenü OUTLINE - BINDEVARIABLEN können eventuell verwendete Variablen für einen Test des SQL-Befehls ersetzt werden. Die Ausführung des Befehls zeigt dann alle relevanten Statistikinformationen an. Als Letztes wird diese Stored Outline dann in der Datenbank abgespeichert.
Sandini Bib
526
Optimierung
Abbildung 7.9: Stored Outlines
Anwendungsmöglichkeiten Eine Anwendungsmöglichkeit ist natürlich die Auslieferung von stabilen Ausführungsplänen mit einer Software. Stored Outlines sind aber auch sehr hilfreich, wenn Sie z.B. vom regelbasierten Optimizer auf den kostenbasierten Optimizer umstellen. Sie können in diesem Fall zunächst die Ausführungspläne des regelbasierten Optimizers aufzeichnen. Dann aktivieren Sie deren Nutzung. Nach der Erstellung der Tabellen- und Indexstatistiken und Veränderung des Initialisierungsparameters optimizer_mode werden trotzdem die Ausführungspläne stabil bleiben. Zum Test der Performance mit dem regelbasierten Ansatz können dann sukzessive die gespeicherten Ausführungspläne deaktiviert werden, indem Sie diese einer nicht verwendeten Kategorie zuweisen.
Sandini Bib
Instanzoptimierung
7.4
527
Instanzoptimierung
Die Instanzoptimierung ist immer nur dann sinnvoll, wenn davon auszugehen ist, dass die SQL-Befehle zum größten Teil optimiert sind. Bei der Instanzoptimierung werden im Wesentlichen Ressourcen des Rechners verteilt, zum Beispiel durch die Benutzung des physikalischen Hauptspeichers durch die SGA. Dieser Schritt wird sinnvollerweise als zweiter durchgeführt, wenn im ersten Schritt sichergestellt ist, dass nicht unnötig Ressourcen durch SQL-Befehle mit unbefriedigenden Zugriffspfaden verbraucht werden. Trefferrate im Database Buffer Cache Einer der zentralen Bereiche einer Oracle-Instanz ist der Database Buffer Cache, der Bereich in der SGA, in dem die Datenbank-Blöcke für alle Anwender zugreifbar verwaltet werden. Vergrößerung des Buffer Cache Die Performance eines Oracle-Systems hängt
maßgeblich von der erzielten Trefferrate im Buffer Cache ab. Diese kann aus dem Verhältnis der insgesamt gelesenen Blöcke zu den physikalisch gelesenen Blöcken bestimmt werden. Diese Informationen können aus der Performance-View v$sysstat gewonnen werden (db block gets, consistent gets und physical reads). Durch Vergrößerung des Buffer Cache kann eine zu geringe Trefferrate verbessert werden. Sie sollten eine solche Vergrößerung aber nur dann vornehmen, wenn die SQL-Befehle zum Großteil optimiert sind und durch die Vergrößerung der physikalische Hauptspeicher nicht so stark belastet wird, dass das System Swapping durchführen muss. Der Parameter, der die Buffer Cache-Größe bestimmt, ist bei Oracle8i db_block_buffers (Anzahl der Oracle-Blöcke), bei Oracle9i db_cache_size (Angabe in Byte, Megabyte oder Gigabyte). Bei Oracle9i ist dieser Parameter dynamisch, kann also während des laufenden Betriebs verändert werden, jedoch nur bis zur eingestellten Größe des statischen Parameters sga_max_size. So müsste für die Vergrößerung des Buffer Cache ein anderer Bereich verkleinert werden, oder die maximale Größe wird von vorneherein größer gewählt, was aber den Hauptspeicher sofort belasten würde. Daher ist der Sinn der dynamischen Vergrößerung fraglich. Unterschiedliche Caches Hier soll auf die Möglichkeit hingewiesen werden, unterschiedliche Buffer Caches zu definieren. Der Default Buffer Cache wird über einen Least Recently Used-Algorithmus verwaltet. Das bedeutet, dass versucht wird, die Blöcke bevorzugt im Hauptspeicher zu behalten, auf die am häufigsten zugegriffen wird.
Abweichend davon können aber bei Oracle8i zwei weitere Buffer Caches eingerichtet werden; einer, der die eingelagerten Blöcke sofort wieder zum Überschreiben freigibt, der Buffer Pool Recycle (buffer_pool_recycle), und ein zweiter, der die Blöcke längstmöglich hält, der Buffer Pool Keep (buffer_pool_keep), für den auch noch zusätzlich Latches parametriert werden können. Die Größen dieser zwei Buffer Pools werden von der Gesamtgröße des Buffer Cache abgezogen, der Rest entfällt auf den Default Buffer Pool.
Sandini Bib
528
Optimierung
Mit Oracle9i sind zwei neue Parameter eingeführt worden, die bevorzugt verwendet werden sollen. Diese sind db_recycle_cache_size und db_keep_cache_size, die von der Funktionalität identisch sind, aber den Vorteil haben, dass sie dynamisch änderbar sind. Datenbankblockgröße Bei den Oracle-Versionen bis einschließlich Oracle8i ist die
Datenbankblockgröße (db_block_size) statisch, das bedeutet, dass sie nur beim initialen Anlegen der Datenbank bestimmt werden kann. Bei Oracle9i kann diese Einstellung zwar auch nicht geändert werden, jedoch lassen sich Tablespaces mit abweichenden Blockgrößen definieren, was im anschließenden Abschnitt näher erläutert wird. Jeder Oracle-Block enthält Header-Informationen, die sich in einen statischen Bereich und zwei variable Bereiche, ein Zeilenverzeichnis und einen Bereich für Transaktionseinträge, unterteilen. Der prozentuale Overhead dieser Bereiche ist bei kleinen Blöcken demzufolge höher. Da ein Oracle-Block die kleinste Einheit ist, die aus den Datendateien in den Buffer Cache transportiert wird, ist die Wahrscheinlichkeit bei größeren Blöcken höher, dass andere Prozesse ihre Daten in diesen Blöcken finden, die Trefferrate also erhöht wird. Voraussetzung ist natürlich ein ausreichend großer Buffer Cache. Zudem muss jeder Block, der in die SGA eingelagert wird, verwaltet werden. Sind die Blöcke klein, müssen also dementsprechend mehr Blöcke verwaltet werden, was sich nachteilig auf die Performance auswirken kann. Die Standardeinstellung für die Blockgröße ist 2.048 Byte, was aber für die meisten Systeme als zu klein zu bewerten ist. In der Praxis haben sich Blockgrößen von 4.096 oder 8.192 Byte bewährt. Extreme Größen von 32Kbyte oder 64Kbyte sind nur in speziellen Fällen anzuraten, wenn etwa LOB-Felder verwendet werden, oder bei Data Warehouse-Datenbanken. Tablespaces mit unterschiedlichen Blockgrößen Ziel bei der Auswahl der Daten-
bankblockgröße ist es, die benötigten Daten für einen SQL-Befehl mit einem Lesevorgang auf einen Block zu erhalten. Zudem soll, abgestimmt auf die Größe des Database Buffer Cache, eine möglichst hohe Trefferrate erreicht werden. So soll laut Dokumentation für kurze Sätze mit indiziertem Zugriff eine kleinere Blockgröße gewählt werden, für kurze Sätze mit sequenziellem Zugriff eine größere und für Datenbanken mit LOBs eine eventuell noch größere Einstellung. In der Praxis werden aber immer Mischformen bestehen, für die bis einschließlich Oracle8i ein sinnvoller Kompromiss gewählt werden musste. Bei Oracle9i können Tablespaces mit unterschiedlichen Blockgrößen definiert werden. Da die Blöcke eines solchen Tablespaces aber nicht im Database Buffer Cache mit der Standardeinstellung für diese Datenbank verwaltet werden können, müssen dafür spezielle Buffer Caches eingerichtet werden.
Sandini Bib
Instanzoptimierung
529
Der Parameter dafür heißt db_nk_cache_size. Für die genaue Beschreibung mit Restriktionen sei hier auf die Dokumentation verwiesen (Oracle9i Database Reference). Log Buffer Der Log Buffer nimmt die Transaktionsprotokolle auf, die für die Konsistenzwahrung der Datenbank notwendig sind. Hier werden Änderungen an Blöcken im Database Buffer Cache gespeichert, die vom Logwriter-Prozess in die RedologDateien geschrieben werden müssen. Der Log Buffer ist als Ringpuffer organisiert. Es muss also vermieden werden, dass Wartezustände dadurch auftreten, dass der Ringpuffer nicht früh genug durch den Logwriter-Prozess geleert worden ist. Das kann durch eine Vergrößerung erreicht werden, wodurch dem Logwriter mehr Zeit für den Schreibvorgang zur Verfügung steht. Der Parameter dafür heißt log_buffer und wird in Byte angegeben. Wartezustände können aus v$sysstat unter redo buffer allocation retries abgelesen werden. Sinnvolle Größen für transaktionsorientierte Instanzen bewegen sich zwischen 128 Kbyte und 1Mbyte. Trefferrate im Shared Pool Äquivalent zur Trefferrate im Database Buffer Cache ist die Trefferrate im Shared Pool zu betrachten. Der Shared Pool besteht aus zwei Bereichen, dem Library Cache und dem Dictionary Cache. Der Library Cache nimmt die ausführbaren Versionen der SQL-Befehle auf, der Dictionary Cache die benötigten Daten aus den referenzierten Dictionary-Tabellen. Diese Bereiche werden im Shared Pool von Oracle dynamisch verwaltet und den beiden Bereichen zugeordnet. Vergrößerung des Shared Pools Der Sinn des Shared Pools ist es, einerseits die Wiederverwendbarkeit von SQL-Befehlen ohne erneutes Parsing sicherzustellen, andererseits die Dictionary-Informationen über die verwendeten Objekte im Hauptspeicher zu halten. Wünschenswert ist eine hohe Trefferrate, die, genau wie beim Database Buffer Cache, durch eine Vergrößerung des zugeordneten Hauptspeicherbereichs erreicht werden kann. Hier kann allerdings nicht der Dictionary Cache gegen den Library Cache abgeschottet werden.
Sie sollten sich jedoch davor hüten, ohne genaue Prüfung bei einer schlechten Trefferrate diesen Bereich sofort zu vergrößern. Sie müssen vorher unbedingt prüfen, ob die geringe Trefferrate auf Grund einer zu geringen Größe des Shared Pools erreicht wird oder wegen der nicht gegebenen Wiederverwendbarkeit von SQLBefehlen, bedingt durch Verwendung von Literalen, z.B. in WHERE-Bedingungen der SQL-Befehle. In zweitem Fall hätte die Vergrößerung des Shared Pools fatale Folgen. Durch immer wieder unterschiedliche SQL-Befehle könnte sowieso keine Trefferrate erreicht werden, durch die Vergrößerung des Shared Pools könnten nur immer mehr SQL-Befehle in kompilierter Form abgelegt werden, so dass der Vergleich, ob bereits identische Befehle existieren, immer aufwändiger würde, was sich in immer längeren Zeiten für das Parsing eines Befehls niederschlägt.
Sandini Bib
530
Optimierung
Pinning Besonders aufwändig ist das Ein- und Auslagern großer Packages, z.B.
Packages wie STANDARD und DIUTIL. Solche großen PL/SQL-Packages können im Shared Pool „festgeheftet“ werden, um eine Auslagerung dieser Packages zu verhindern. Dazu verwenden Sie eine Prozedur aus einem DBMS-Package, dbms_shared_pool.keep. Der benötigte Platzbedarf für Pinned Packages muss natürlich bei der Konfiguration des Shared Pools berücksichtigt werden. Cursor Handling Sie können auf die Trefferrate im Shared Pool durch die Behandlung der SQL-Cursor wesentlich Einfluss nehmen. cursor_space_for_time
Wird dieser Initialisierungsparameter auf true gesetzt, werden Cursor so lange nicht freigegeben, solange sie mit Anwendungs-Cursors assoziiert sind. Damit entfällt die Prüfung, ob der entsprechende SQL-Befehl noch im Library Cache ist. Verbunden damit ist ein höherer Platzbedarf in der PGA. session_cached_cursors
Die Idee der Session Cached Cursor ist es, Cursor für Befehle, die immer wiederkehrend aus einer Anwendung geöffnet werden, im Cache des einzelnen Prozesses zu halten. Der Initialisierungsparameter session_cached_cursors legt dabei die Anzahl der Cursor fest, die auf Prozessebene zur Verfügung stehen. Oracle nutzt diesen Parameter für Cursor, wenn mehr als drei Parse-Aufrufe für einen Befehl stattgefunden haben. cursor_sharing
Standardeinstellung für diesen Parameter ist exact. Das bedeutet, dass zwei Befehle nur als identisch erkannt werden, wenn sie Byte für Byte übereinstimmen. Wird dieser Parameter auf force gesetzt, wird die Wiederverwendbarkeit eines Befehl dadurch erzwungen, dass die Literale intern beim Parsing durch Bindevariablen ersetzt werden. Large Pool Der Large Pool sollte besondere Berücksichtigung beim Einsatz der
Parallel Query Option und Multithreaded Server-Konfigurationen finden. In beiden Fällen muss für mehrere Serverprozesse Information zentral zugänglich gehalten werden, die sonst prozessspezifisch in der PGA (Process Global Area) gehalten wird. Unter Oracle7 konnten diese Informationen nur im Shared Pool gehalten werden, wodurch aber eine Verdrängung des Library Cache und des Dictionary Cache stattfand. Dadurch konnten die Trefferraten dieser Bereiche signifikant beeinträchtigt werden. Ab Oracle8 kann ein Large Pool als Hauptspeicherbereich neben dem Shared Pool definiert werden, der speziell diese Bereiche aufnimmt. Durch diese Trennung ist also eine sinnvolle Konfiguration des Shared Pools möglich, auch wenn diese Optionen eingesetzt werden.
Sandini Bib
Instanzoptimierung
531
Latching Bei der Optimierung des Shared Pools ist nur die Optimierung der Trefferrate betrachtet worden, die zweifelsohne eine wichtige Rolle spielt. Ein weiterer Aspekt sind jedoch die Latches, über die Zugriffe auf diesen Hauptspeicherbereich verwaltet werden. Latches sind kurzzeitige Sperren für SGA-Bereiche, vergleichbar mit Semaphoren unter UNIX. Der Library Cache wird zum Beispiel über einen einzelnen Latch verwaltet. Ein Latch sollte nur maximal innerhalb einer Zeitscheibe eines Prozesses aktiv sein und vor der Beendigung freigegeben werden. Kann ein Serverprozess einen angeforderten Latch nicht bekommen, so wird er in den Status SLEEP versetzt und nach einem bestimmten Intervall wieder aktiviert. Da dieser Vorgang Zeit kostet, ist es auf Multiprozessorsystemen vorteilhafter, den Prozess in einer Schleife versuchen zu lassen, den angeforderten Latch zu bekommen. Die Anzahl der Versuche konnte bis Oracle8i mit dem Initialisierungsparameter spin_count festgelegt werden. Für Oracle9i kann dieser Parameter nicht mehr gesetzt werden, sondern wird intern über die Anzahl der Prozessoren berechnet. Es sollte jedoch auf alle Fälle vermieden werden, konkurrierende Zugriffe auf Latches zu erzeugen. Sie sollten also die Verwendung von Literalen in SQL-Befehlen wo immer möglich vermeiden. Neben einer schlechteren Trefferrate im Shared Pool muss nämlich für jeden einzulagernden Befehl ein Latch angefordert werden. Bei parallel arbeitenden Prozessen können also hier schnell Zugriffskonflikte entstehen. Für Anwendungen ist es zu bevorzugen, Objektnamen transparent zu halten, was über Synonyme zu erreichen ist. Hier sollte jedoch vor dem Einsatz von privaten Synonymen für eine höhere Anzahl von Anwendern gewarnt werden. Da in diesem Fall jedes Synonym einen anderen Eigentümer hat und damit ein anderes Datenbankobjekt darstellt, müssen darauf referenzierende Befehle in mehreren Versionen gehalten werden. Die SQL-Befehle sind zwar syntaktisch gleich, über das Dependency Tracking werden aber unterschiedliche Objekte festgestellt, die zu einer Belastung des Library Cache führen, aber auch den Dictionary Cache belasten, da Informationen über unterschiedliche Objekte gehalten werden müssen. Sortiervorgänge Sortiervorgänge werden immer dann aufwändig, wenn der pro Prozess über den Initialisierungsparameter sort_area_size zugeordnete Hauptspeicherbereich nicht ausreichend ist und Zwischensortierungen auf temporäre Segmente ausgelagert werden müssen. Dem kann entgegengewirkt werden, indem der Parameter erhöht wird. Es sollte natürlich bei vielen parallel ablaufenden Sortierungen keine Einstellung gewählt werden, die den physikalischen Hauptspeicher überbelastet, also Paging erzeugt. Sortiervorgänge können auch dadurch reduziert werden, dass Indizes genutzt werden. So braucht für ein ... ORDER BY name nicht sortiert zu werden, wenn ein Index auf name liegt, der ja die Werte in sortierter Reihenfolge gespeichert hat.
Sandini Bib
532
Optimierung
Sie sollten hier unbedingt auf die Einstellung des NLS-Parameters NLS_SORT achten. Ist dieser auf einen anderen Wert als binary gesetzt, so kann ein Index eine Sortierung nicht unterstützen. Ausnahmen bilden hier Function-based Indizes, die mit einer spezifischen NLS-Sortierung angelegt wurden. Diese Möglichkeit ist aber nur für die Oracle Enterprise Edition gegeben.
7.5
Datenbankoptimierung
In diesem Abschnitt werden Maßnahmen erläutert, die durch Veränderungen im physikalischen Layout der Datenbank performancesteigernd wirken. Diese Änderungen sind immer dann notwendig, wenn die SQL-Befehle optimiert sind, aber trotzdem keine zufrieden stellenden Antwortzeiten erreicht werden, weil es zu Wartezuständen auf Datenbankobjekte kommt.
7.5.1
Redundante Datenhaltung
Die Vermeidung von Redundanzen der Daten ist eine Forderung des relationalen Datenmodells. Aus Performance-Gründen wird in der Praxis aber von der Normalisierung und der Redundanzfreiheit in Netzwerken abgewichen. Denormalisierung Bei einem normalisierten Datenmodell (dritte Normalform) liegen keine Redundanzen mehr vor, abgesehen von Schlüsselwerten. Damit geht aber auch einher, dass häufig Tabellen verknüpft werden müssen, um die benötigten Daten zu erhalten. Als Folge einer Verknüpfung zweier Tabellen müssen also mindestens zwei Datenblöcke aus den Tabellen gelesen werden. Wenn also für zeitkritische Abfragen nur ein zusätzliches Feld aus der zweiten Tabelle benötigt wird, kann es unter Performance-Gesichtspunkten notwendig sein, diese Information denormalisiert in die erste Tabelle zu übernehmen. Damit handelt man sich zwar Probleme bei der Pflege der Daten ein, weil Tabellen-Trigger eingesetzt werden müssen, um die Daten konsistent zu halten, man spart jedoch bei den kritischen Zugriffen das Lesen eines zusätzlichen Blocks ein. Die Zugriffe auf die Indexblöcke sind hier gar nicht mitgerechnet worden, so dass sich durch die Denormalisierung in bestimmten Fällen starke Verbesserungen erreichen lassen. Verteilte Datenhaltung Bei Abfragen von einer lokalen Instanz aus auf eine entfernte Datenbank über einen Datenbank-Link kann das Netzwerk zum limitierenden Faktor werden. Bei Ausfall des Netzwerks ist ein Zugriff sogar unmöglich. Sowohl zu Wahrung der lokalen Autonomie als auch zur Steigerung der Performance bietet es sich dann an, in der lokalen Datenbank die benötigten Daten als Kopie lokal vorzuhalten. Oracle bietet dazu verschiedene Möglichkeiten an. So können neben synchronen Replikationen auch Materialized Views (Snapshots) eingerichtet werden, die in definierten Intervallen aktualisiert werden. Hier muss festgelegt werden, welche Aktualität die Daten bieten müssen.
Sandini Bib
Datenbankoptimierung
7.5.2
533
I/O-Verteilung
Bei komplexen Abfragen auf mehrere Tabellen oder bei Abfragen auf große Datenmengen, die das Lesen einer oder mehrerer kompletter Tabellen notwendig machen, kann die Performance durch die I/O-Leistung begrenzt werden. In einem solchen Fall muss die I/O-Bandbreite durch Maßnahmen vergrößert werden. Manuelle Verteilung Sind Zugriffe auf Datenbanksegmente bekannt, die auf derselben Platte liegen, kann eine Verteilung der I/O-Anforderungen erreicht werden, indem die Objekte auf Tablespaces verteilt werden, die auf unterschiedlichen Platten liegen. So können z.B. bei Joins mehrere Platten parallel angesprochen werden, wodurch die Bandbreite erhöht wird. Hier ist darauf zu achten, dass nicht etwa der entsprechende Platten-Controller zum Engpass wird, wenn die Verteilung der Objekte auf Platten geschieht, die an demselben Controller hängen. In der Praxis gestaltet sich eine manuelle Verteilung sehr schwierig, da alle kritischen Zugriffe bekannt sein müssen, um sicherzustellen, dass das Verteilungskonzept, das für eine bestimmte Abfrage von Vorteil ist, nicht zum Nachteil für andere Zugriffe wird. Partitionierung Zugriffe auf sämtliche Daten einer sehr großen Tabelle können dadurch verbessert werden, dass die Daten der Tabelle in Partitionen abgelegt werden, die in unterschiedlichen, auf unterschiedliche Platten verteilten Tablespaces liegen. In Verbindung mit einer Parallelisierung einer Abfrage (Parallel Query Option) kann dies eine wesentliche Verbesserung der I/O-Leistung bringen. Neben der Partitionierung nach Wertebereichen (Range-Partitioning) steht seit Oracle8i auch Hash-Partitioning zur Verfügung, was eine Art Striping auf Tabellenebene ermöglicht. Striping Bei I/O-intensiven Abfragen kann die Performance durch die I/O-Leistung einer Platte begrenzt werden. In diesem Fall kann Striping über mehrere Platten die I/OBandbreite vergrößern und damit den Durchsatz wesentlich verbessern. Beim Striping werden mehrere physikalische Platten zu einer logischen Einheit zusammengefasst, über die die Schreib-/Lesevorgänge verteilt werden, so dass die I/O-Leistung den nahezu gleichen Faktor hat wie die Anzahl der eingesetzten Platten. Limitierend wirkt dann die Leistung des Platten-Controllers. Striping (RAID0) kann Controller-basiert oder betriebssystembasiert eingerichtet werden. Dabei bietet das betriebssystembasierte Striping den Vorteil, dass mehrere System-Controller genutzt werden können, was eine noch höhere I/O-Leistung bietet.
Sandini Bib
534
7.5.3
Optimierung
Rollback-Segmente
Die Rollback-Segmente, die in einem eigenen Tablespace oder auch in verschiedenen Tablespaces liegen, nehmen die Rollback-Informationen sämtlicher Transaktionen auf. Sie müssen bedenken, dass die Rollback-Informationen nicht nur für die Daten der Tabellen, sondern auch für Indexblöcke geschrieben werden. Neben den weiteren Punkten in diesem Abschnitt ist dabei auch zu berücksichtigen, dass es auch zu I/O-Engpässen auf den Datendateien des Rollback-Tablespaces kommen und eine Verbesserung auch durch eine höhere I/O-Bandbreite erreicht werden kann, wenn Wartezustände beim I/O auf die Dateien beobachtet werden. Dafür bieten sich unterschiedliche Tablespaces auf verschiedenen Platten oder PlattenStriping an. Anzahl der Rollback-Segmente Typischerweise kann es zu Wartezuständen auf die Header der Rollback-Segmente kommen, in die sich Prozesse zum Start einer Transaktion eintragen müssen. Analysiert werden kann ein solcher Engpass über eine Abfrage auf die v$-Tabelle v$rollstat. SQL> SELECT usn, waits FROM v$rollstat;
Sind hier verstärkt Wartezustände zu sehen, ist dies ein Indiz dafür, dass zu wenige Rollback-Segmente konfiguriert sind. Erweitern und Schrumpfen Aus derselben Performance-View kann abgelesen werden, ob es häufig zu Erweiterungen der Rollback-Segmente und anschließendem Schrumpfen kommt. SQL> SELECT extends, shrinks, aveshrink, aveactive, optsize FROM v$rollstat;
Angezeigt wird die Anzahl der Erweiterungen und der Schrumpfungen, die durchschnittliche Belastung der einzelnen Rollback-Segmente, wie viele Bytes geschrumpft werden und wie die optimale Größe justiert ist. Wichtig ist, dass die durchschnittliche Größe unter der optimalen Größe liegt. Das ist ein Indikator dafür, dass Schrumpfungen nur als Ausnahmen auftreten. Sollte die durchschnittliche Größe die optimale Größe übersteigen, sollte OPTIMAL heraufgesetzt werden. SQL> ALTER ROLLBACK SEGMENT rbs1 STORAGE (OPTIMAL 10M);
7.5.4
Automatic Segment Space Management
Wie schon in Kapitel 3 beschrieben, bietet das Automatic Segment Space Management eine effektivere Nutzung der Oracle-Blöcke, als dies über die Freelist-Verwaltung möglich war. Zum einen ist es dadurch möglich, bei konkurrierenden Insert-Operationen Latch-Contention (also den gleichzeitigen Zugriff auf die Freelist) zu ver-
Sandini Bib
Datenbankoptimierung
535
meiden, zum anderen werden Blöcke, in denen Datensätze gelöscht wurden, früher mit neuen Sätzen gefüllt, als dies mit dem Parameter PCT_USED der Fall war. Man darf allerdings von dieser Verwaltung keine Wunder erwarten. Zum einen wird dadurch eine Satz-Migration (Row-Chaining als Migrated-Rows) nicht vermieden, da der Parameter PCT_FREE immer noch entsprechend gesetzt sein muss. Zum anderen nimmt der Füllgrad in den einzelnen Blöcken bei hoher Insert-Last ab. Trotz dieser Einschränkungen sollten Sie alle neu angelegten Tablespaces mit Automatic Segment Space Management anlegen. Vergessen Sie aber nicht, für die wichtigen Tabellen den Parameter PCT_FREE anzupassen, damit es nicht zu Row-Chaining kommt. SQL> CREATE TABLESPACE ts_daten DATAFILE SIZE 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 5000M SEGMENT SPACE MANAGEMENT AUTO; Listing 7.12: Automatic Segment Space Management
7.5.5
Checkpoints
Checkpoints sind, wie bereits beschrieben, notwendig für die Wahrung der Konsistenz der Datenbank. Jeder Checkpoint erzeugt aber eine Last auf einer Instanz und der verbundenen Datenbank, da alle modifizierten Blöcke aus dem Database Buffer Cache, die über die Modified Block List verwaltet werden, vom Database Writer-Prozess in die Datendateien geschrieben werden müssen. Können Checkpoints nicht schnell beendet werden, kann es zu Wartezuständen kommen, da RedologDateien, die Informationen von Blöcken beinhalten, die für einen Checkpoint geschrieben werden müssen, vor der Beendigung nicht überschrieben werden können. Diese Wartezustände werden in der Alert-Datei der Instanz protokolliert: Checkpoint not complete. In diesem Fall muss entweder die Anzahl der Checkpoints reduziert werden, oder die Geschwindigkeit der einzelnen Checkpoints muss verbessert werden. Auch wenn es nicht zu Wartezuständen auf die Beendigung der Checkpoints kommt, wird immer eine Last auf dem I/O-System und auf dem Prozessor erzeugt. Kosten für einen Checkpoint Die Kosten für einen Checkpoint werden durch die Größe des gesamten Database Buffer Cache und die Transaktionslast bestimmt. Es müssen die modifizierten Blöcke aus dem Cache auf die Festplatten geschrieben werden, um die Konsistenz der Datenbank zu gewährleisten. Wird also zum Beispiel eine Instanz mit einer extrem großen SGA betrieben, die eine hohe Transaktionslast durch Messdatenerfassungen erfährt, müssen bei einem Checkpoint auch extrem viele Blöcke geschrieben werden. Dadurch werden die Kosten für einen Checkpoint in die Höhe getrieben. In einem solchen Fall wäre ein großer Database Buffer Cache unangebracht, da bei INSERT-Befehlen zwar freie Blöcke in der SGA zur Verfügung stehen müssen, eine Trefferrate aber nicht erreicht werden kann. Für dieses Beispiel würde sich als Lösung des Problems also eine Verkleinerung des Database Buffer Cache anbieten.
Sandini Bib
536
Optimierung
Redolog-Dateianzahl und -größe In der Praxis sind es die Wechsel der Redolog-Dateien, die die Frequenz der Checkpoints einer Oracle-Instanz bestimmen. Ist diese zu hoch, bietet sich also als Lösung an, die Redolog-Dateien zu vergrößern. Zusätzliche Redolog-Gruppen können zwar helfen, Wartezustände zu reduzieren, da seit Oracle8 Checkpoints parallelisiert werden; die Last durch Checkpoints wird jedoch nicht verringert. Bei Systemen mit sehr hoher Transaktionslast sind Redolog-Dateigrößen von 100 bis 500 Mbyte und auch darüber nicht ungewöhnlich. Hier soll jedoch nochmals deutlich darauf hingewiesen werden, dass die Datensicherheit nicht der Performance geopfert werden darf. Große Redolog-Dateien sind nur unter der Voraussetzung anzuraten, dass diese gespiegelt sind. Bei einem Verlust der Online-Redolog-Dateien sind alle Transaktionen verloren, also umso mehr, je größer die Dateien sind. Die Vergrößerung der Redolog-Dateien führt aber nur zum Ziel, wenn auch zugehörige Initialisierungsparameter angepasst werden. Initialisierungsparameter log_checkpoint_interval
Der Parameter gibt an, nach wie vielen geschriebenen Betriebssystemblöcken ein Checkpoint initialisiert wird. Die Standardeinstellung ist betriebssystemabhängig, in den meisten Fällen 10.000. Bei einer Betriebssystemblockgröße von 512 Byte bedeutet das also, dass nach 5 Megabyte ein Checkpoint gestartet wird, auch wenn kein Redolog-Dateiwechsel durchgeführt wird. Also muss für die Nutzung größerer Redolog-Dateien dieser Parameter angepasst werden, wobei der eingestellte Wert aber nicht mit der Dateigröße korrespondieren muss. Der Parameter ist dynamisch und kann über ALTER SYSTEM geändert werden. log_checkpoint_timeout
Eine weitere Möglichkeit ist die zeitliche Steuerung von Checkpoints. Dieser Parameter gibt ein Zeitintervall in Sekunden an, nach dem ein Checkpoint gestartet wird. Voreinstellung ist für die Oracle Standard Edition 900 Sekunden, für die Enterprise Edition 1.800 Sekunden. Es wird also alle 15 Minuten bzw. alle 30 Minuten ein Checkpoint gestartet; Zeitintervalle, die durch große Redolog-Dateien in den meisten Fällen überschritten werden sollten. Wird der Parameter auf den Wert 0 gesetzt, wird die zeitliche Steuerung der Checkpoints ausgeschaltet. In der Oracle-Dokumentation wird davon abgeraten, durch die Parameter die Checkpoint-Intervalle zu verlängern, da dadurch auch die Instance-Recovery-Zeiten nach einem Abbruch einer Instanz, wie z.B. durch einen Stromausfall, ansteigen. Für 100 Mbyte große Redolog-Dateien ist mit einer Instance-Recovery-Zeit von 5 bis 10 Minuten im Maximalfall zu rechnen. Hier ist also abzuwägen, ob für die Minimierung einer Störungszeit eine Einschränkung der Performance im Normalbetrieb in Kauf genommen werden soll. fast_start_io_target
Sandini Bib
Datenbankoptimierung
537
Um auch bei reduzierten Checkpoint-Intervallen relativ kleine Instance-RecoveryZeiten gewährleisten zu können, kann der Parameter fast_start_io_target verwendet werden. Voreinstellung ist die Anzahl der Blöcke im Database Buffer Cache. Das heißt, dass nach einem Instance-Abbruch alle Blöcke durch das Instance-Recovery wiederhergestellt werden müssen. Wird ein kleinerer Wert eingestellt, wird der Database Writer-Prozess dazu gezwungen, vermehrt Blöcke auf die Platten zu schreiben, um weniger modifizierte Blöcke auf der Liste zu haben. Demzufolge müssen dann auch weniger Blöcke wiederhergestellt werden. Außerdem werden die Kosten für einen Checkpoint dadurch auch reduziert. Der Database Writer-Prozess wird aber permanent stärker belastet, da es auch durch das vermehrte Schreiben von Blöcken dazu kommen kann, dass ein Block, in dem in kurzer Zeit mehrere Modifikationen durchgeführt werden, mehrfach geschrieben werden muss. optimizer_index_cost_adj
Der kostenbasierte Optimizer betrachtet ja bekanntlich zum einen die Statistiken der Tabellen und Indizes, auf die in dem zu optimierenden Befehl zugegriffen wird, zum anderen aber auch die Größe des Database Buffer Cache, die Anzahl der OracleBlöcke, die mit einem physikalischen I/O gelesen werden, und die Größe der Sort Area, parametriert über sort_area_size. Ein abhängiger Parameter dieser Einstellung ist die hash_area_size, die das Doppelte der sort_area_size ist, wenn sie nicht gezielt anders parametriert wird. Sind diese Parameter über den Standard hinaus gesetzt, so werden Sie beim Betrachten der Ausführungspläne vieler SQL-Befehle feststellen, dass der kostenbasierte Optimizer extrem Hash Join-lastig ist, obwohl die Nested Loop die bessere Zugriffsstrategie wäre. Das kommt dadurch zustande, dass die Kosten für einen Hash-Join niedriger eingeschätzt werden als die für einen Indexzugriff. Diese Gewichtung kann man ändern, d.h., die Kosten für einen indizierten Zugriff können über den Parameter optimizer_index_cost_adj eingestellt werden. Der Bereich geht dabei von 1 bis 10.000 und ist auf Sitzungsebene einstellbar. Die Standardeinstellung ist 100 (Prozent). Wird dieser Wert also auf 50 gesetzt, so wird ein indizierter Zugriff nur noch als halb so teuer gewichtet, es wird also eher ein Zugriff über einen Index gewählt.
7.5.6
Hardware und Betriebssysteme
Oracle kann alle Ressourcen eines Rechners auf Grund seiner Architektur ausnutzen, da die Portierung der Software speziell die angebotenen Besonderheiten und Architekturmerkmale ausnutzt. Dadurch ist auch die Hardware, respektive das Betriebssystem, als Möglichkeit des Tunings anzusehen. Der Schritt zu neuer Hardware, also Prozessoren, physikalischem Hauptspeicher oder I/O-Systemen sollte nur dann beschritten werden, wenn die Optimierung der Zugriffe weitestgehend abgeschlossen ist. Durch die Architektur des Oracle-Systems ist die Ausnutzung jedes weiteren Prozessors mit einem sehr hohen Skalierungsfaktor möglich. Hier soll aber bemerkt werden, dass durch damit zusätzlich mögliche parallele Zugriffe auf Datenbankobjekte neue Engpässe entstehen können, die analysiert und beseitigt werden müssen. Als
Sandini Bib
538
Optimierung
Beispiel seien parallele Inserts auf eine Tabelle genannt, die zu Konflikten bei Zugriffen auf die Freelists der entsprechenden Tabelle oder deren Indizes führen können. Eine Erweiterung des Hauptspeichers eines Rechners kann direkt durch eine Vergrößerung der SGA einer Oracle-Instanz genutzt werden. Dadurch kann die Trefferrate im Database Buffer Cache verbessert werden, was durch die Vermeidung von Plattenzugriffen signifikante Verbesserungen der Zugriffszeiten bewirken kann. Aber auch hier können Nachteile dadurch entstehen, dass bei stark transaktionsorientierten Systemen der Aufwand für einen Checkpoint ansteigt, so dass es zu Wartezuständen auf die Beendigung von Checkpoints kommen kann. In einem solchen Fall müsste entweder die I/O-Leistung des Database Writer-Prozesses verbessert werden oder die Anzahl der Checkpoints durch Vergrößerung der RedologDateien reduziert werden. Plattensysteme An dieser Stelle soll der Einsatz von Plattensystemen besonders erwähnt werden. Es werden diverse Systeme angeboten, die herstellerspezifische RAID-Implementierungen haben. Diese Implementierungen gehen über den bekannten Standard hinaus und erhöhen die I/O-Leistungen, aber nur unter der Voraussetzung, dass die Konfiguration auf die Anforderungen der Datenbank angepasst ist. Weitere große Vorteile können durch die Nutzung eines dem Plattensystem eigenen Caches gezogen werden. Dieser ermöglicht eine Trefferrate, die ähnlich der im Database Buffer Cache der Oracle-SGA ist.
7.6
Real Application Cluster
Die Leistung eines Rechners ist durch die Anzahl seiner Prozessoren und durch die maximale Ausstattung des Hauptspeichers begrenzt. Die Idee des Clusters ist es, weitere Rechner dazuzukoppeln, die so die Leistungsfähigkeit erhöhen, wobei auf dieselben Datenbestände, also dieselben Plattensysteme, zugegriffen wird. Die Architektur der Cluster ist von der Digital Equipment Corporation eingeführt worden, die seit 1986 unter dem Betriebssystem VMS diese Technologie anbot. Oracle hat 1990 mit Oracle 6.2 speziell für VMS-Systeme die erste Version angeboten, die diese Rechnerarchitektur unterstützt. In den darauf folgenden Jahren haben weitere Hersteller unter dem Betriebsystem UNIX ebenfalls Cluster-Rechner auf den Markt gebracht. Heutzutage ist die Technologie auch für Windows NT und Windows 2000 verfügbar. Neben Compaq, die ja bekanntlich Digital Equipment Corporation übernommen haben, sind SUN, IBM und HP führend. Auf ähnlichen Konzepten beruhen auch MPP-Systeme (Massiv Parallel Processing) und NUMAArchitekturen. Für all diese Plattformen hat Oracle spezielle Portierungen, die bis Oracle8i unter dem Namen Oracle Parallel Server bekannt sind.
Sandini Bib
Real Application Cluster
539
Abbildung 7.10: Oracle Real Application Cluster
Bis einschließlich Oracle8 (8.0.6) ist die Skalierfähigkeit, also die Fähigkeit, die zusätzliche Rechenleistung in Performance der Datenbank umzusetzen, dadurch beschränkt, dass der Abgleich der Oracle-Blöcke in den SGAs auf den Rechnern im Cluster über Plattenzugriffe erfolgen muss, um die Konsistenz der Datenbank zu sichern. So kann es bei konkurrierenden Zugriffen auf dieselben Blöcke zur Verschlechterung des Durchsatzes kommen. Mit Oracle8i hat Oracle das Projekt Cache Fusion gestartet. Mit dieser Technologie sollen also die Hauptspeicherinhalte „verschmolzen“ werden. Dahinter steht der direkte Austausch von Blöcken über eine schnelle Verbindung zwischen den beteiligten Rechnern, auch Inter-Connect genannt. Oracle8i unterstützt mit der ersten Phase den Transport von lesekonsistenten Versionen modifizierter Blöcke in die SGA der Instanz, die lesend zugreift. Es muss also auch in dieser Phase noch berücksichtigt werden, dass nicht von beiden Rechnern aus modifizierend auf die gleichen Datenbestände zugegriffen wird. Oracle9i bringt die Cache Fusion zum Abschluss. Es wird also der direkte Austausch von Datenblöcken und Rollback-Segmentblöcken direkt zwischen den SGAs unterstützt, auch unter der Voraussetzung, dass beide Instanzen schreibend auf ein und denselben Block zugreifen. Die Satzsperren werden dabei mittransportiert, so dass keine Unterschiede zu einer Single Instance-Konfiguration festzustellen sind. Tests haben ergeben, dass auch bei transaktionsorientierten Systemen wie z.B. SAP ein Skalierungsfaktor von 0,9 zu erreichen ist. Durch einen zweiten äquivalenten Rechner kann also das 1,8-fache an Performance erreicht werden. Dadurch ist es nun möglich, Prozesse über die Oracle Net-Konfiguration auf Rechner im Cluster zu verteilen, ohne logische Trennungen der Daten vornehmen zu müssen. Es kann also ein uneingeschränktes Load Balancing eingerichtet werden. Nähere Informationen zum Tuning von Oracle Net finden Sie in Kapitel 5.
Sandini Bib
Sandini Bib
8 8.1
Verteilte Datenbanktechniken Grundkonzepte
Im Folgenden Abschnitt sollen kurz die Motive, die zum Aufbau einer verteilten Datenbank und zur Planung von Replikationen führen, zusammengefasst werden. Eine verteilte Datenbank ist ein Verbund aus mehreren physikalischen Datenbanken, die zu einer übergeordneten logischen Datenbank zusammengefasst werden. Sie ist durch Anwendungen gekennzeichnet, in deren Kontext entweder verteilte Abfragen oder sogar verteilte Transaktionen stattfinden. Während eine verteilte Abfrage keine großen Anforderungen an die Anwendung stellt, d.h., sie kann für den Anwender ohne große Probleme transparent dargestellt werden, werden in einer verteilten Transaktion Tabellen oder Tabellenfragmente auf verschiedenen Datenbankknoten in einer übergeordneten globalen Transaktion konsistent geändert. Dabei ist zu unterscheiden, ob es sich um eine Transaktion auf nur einer entfernten Datenbank handelt, oder ob die Transaktion echt verteilt wird. Einen ganz besonderen Stellenwert bei der verteilten Datenhaltung nimmt die Replikation ein, d.h. die bewusste redundante Speicherung von Daten für eine höhere Verfügbarkeit oder Reduzierung der Last eines Systems. Dieses sehr komplexe Thema wird daher gesondert in Kapitel 8.2 beschrieben. Einige Beispiele sollen die unterschiedlichen Konzepte transparenter machen: 1. Für den Verkauf wird eine neue Datenbank aufgebaut, in der alle verkaufsrelevanten Daten, wie z.B. Artikel, Preise, Kundeninformationen etc., gespeichert werden sollen. Um jetzt aber Informationen über den Lagerbestand zu erhalten, wird im ersten Schritt über einen lesenden Zugriff auf die Lagerdatenbank zugegriffen. In diesem Fall sind keine verteilten Transaktionen notwendig, sondern lediglich ein Lesezugriff über einen Datenbank-Link. 2. Die Lageranwendung soll im zweiten Schritt dem Verkauf Informationen über neu gelieferte Artikel zukommen lassen. Dabei wird die Tabelle Artikel in der Verkaufsdatenbank einmal täglich mit den neuen Artikeldaten gefüllt. Hier wird jetzt auf eine entfernte Datenbank (remote) zugegriffen und es wird eine Tabelle als einzelne Transaktion gepflegt.
Sandini Bib
542
Verteilte Datenbanktechniken
3. Nachdem diese Anwendung einige Zeit erfolgreich eingesetzt wird, häufen sich die Probleme, dass Waren verkauft werden, die im Lager nicht mehr vorrätig sind. Daher entschließt man sich, den Lagerbestand mit jedem Verkauf sofort zu aktualisieren, d.h., es wird eine verteilte Transaktion durchgeführt, die am Ende eines Verkaufszyklus den Bestand im Lager aktualisiert. 4. Da es einige Vertriebsmitarbeiter gibt, die per Laptop Kundentermine durchführen, wird als letzter Schritt ein Außendienstsystem aufgebaut, so dass jeder Mitarbeiter seinen Datenbestand in Form einer eigenen lokalen Datenbank auf seinem Laptop mit zum Kunden nehmen kann. Dieser Bestand muss natürlich nach jedem Termin neu abgeglichen werden. Hier ist jetzt die komplexeste Art der verteilten Datenhaltung entstanden. Die unterschiedlichen Systeme dürfen alle auf die gleichen Daten zugreifen, und jede Anwendung glaubt, sie habe die aktuellen Informationen. Dabei kann es zu Fehlinformationen kommen, wenn zwei unterschiedliche Datenbanken die gleichen Informationen ändern. Die Motive, die zum Aufbau eines verteilten Datenbanksystems und damit ggf. zur Replikation von Daten führen, können sowohl technischer als auch organisatorischer und wirtschaftlicher Natur sein. Die Dezentralisierung von Geschäftsprozessen und die damit einhergehende Forderung, an unterschiedlichen Standorten schnell und effizient auf Daten zuzugreifen, sind in vielen Fällen entscheidend für den Aufbau von verteilten Datenbanken. Daneben bietet sich in verteilten Datenhaltungen die Möglichkeit, bereits existierende, zunächst als Insellösungen konzipierte Datenbanken zu einer gemeinsamen übergeordneten logischen Datenbank zusammenzuführen. Hierbei spielen natürlich neben den Oracle-Datenbanken auch Fremdsysteme wie Informix, DB2 etc. eine Rolle. Vom wirtschaftlichen Standpunkt aus betrachtet bieten verteilte Datenbanken eine effektivere und schnellere Anpassung auf Organisationsänderungen und die Hardware kann besser genutzt werden. In jedem Fall ist eine verteilte Datenhaltung dann anzuraten, wenn über Leitungen mit geringer Kapazität gearbeitet werden soll, wie es oft bei Wählverbindungen (ISDN o.Ä.) der Fall ist.
8.1.1
Datenbank-Link
Ein Datenbank-Link ist die Beschreibung des Zugriffsweges von einer lokalen Datenbank auf eine Ferndatenbank. Jeder Datenbank-Link besteht aus folgenden Komponenten: 1. Einem eindeutigen Namen, der entweder beliebig gewählt werden kann oder aber dem globalen Namen der referenzierten Datenbank entsprechen muss. Der Initialisierungsparameter global_names = true schaltet hierbei die freie Namensgebung aus, d.h., der Name des Datenbank-Links muss dem globalen Datenbanknamen entsprechen. Der globale Datenbankname setzt sich standardmäßig aus der Datenbankdomäne und dem Datenbanknamen zusammen, kann aber jederzeit mit dem Befehl
Sandini Bib
Grundkonzepte
543
ALTER DATABASE RENAME GLOBAL_NAMES TO SUNDB.HL.DE
geändert werden. 2. Einem Benutzernamen und Kennwort, die für die Anmeldung auf der Gegenseite verwendet werden sollen. Wird kein Name angegeben, werden der lokale Benutzername und das lokale Kennwort für die Anmeldung verwendet. 3. Einer Datenbankadresse (connect string) für die Oracle-Net-Verbindung zur Ferndatenbank. Auch dieser Parameter ist optional, d.h., wenn keine Adresse angegeben wird, wird eine Adressauflösung über den Namen des Links versucht. Datenbank-Links können auf verschiedenen Ebenen definiert werden: 1. Private Links: Sie werden im Kontext eines Schemas und dort in einem separaten Namensbereich definiert und müssen in Bezug auf andere Links des gleichen Schemas eindeutig sein. Sie können darüber hinaus nur vom Schemabenutzer selbst referenziert werden. 2. Public Links: Sie werden für alle Benutzer angelegt und müssen in Bezug auf andere Public Links eindeutig sein. Der Vorteil von Public Links ist, dass bei globaler Namensgebung (global_names = true) fehlende Adressangaben in privaten Links durch die gleichnamigen Public Links ergänzt werden können. Damit lässt sich eine Modularisierung der Speicherung von Datenbankadressen erreichen, die in der Praxis sehr vorteilhaft ist. 3. Global Links: Sie verbinden die lokale Datenbank mit allen anderen in einem Netzwerk definierten Datenbanken. Globale Links werden nicht wie andere Links im Data Dictionary der erstellenden Datenbank, sondern in den Konfigurationsdateien von Oracle Names gespeichert. Sie enthalten keine expliziten Benutzernamen, sondern benutzen den Namen des aufrufenden Benutzers mit seinem aktuellen Kennwort für die Anmeldung. Globale Links werden bei der Definition des Netzwerkes automatisch erstellt und sind nur dann von Bedeutung, wenn Oracle Names zur Namensauflösung im Netz eingesetzt wird. Dieses Verfahren ist aber zur Zeit unsicher, da Oracle Names in der Zukunft nicht mehr unterstützt werden wird, es aber zurzeit noch Einschränkungen bei der Benutzung von Directory Services gibt. Außerdem existiert im Umfeld der Replikation der Name Scheduled Link. Hierbei handelt es sich jedoch nicht um einen Datenbank-Link, sondern eine Kombination aus einem Datenbankjob, der Deferred Transaction Queue und den privaten Datenbank-Links des betreffenden Replication Propagators, d.h. des Benutzers, über dessen Schema die verzögerten Transaktionen im Falle einer Replikation an die anderen Datenbanken des verteilten Systems übertragen werden. Scheduled Links ermöglichen damit die zeitgesteuerte Übertragung von verzögerten Transaktionen.
Sandini Bib
544
Verteilte Datenbanktechniken
Beispiel für Datenbank-Links SQL> CREATE PUBLIC DATABASE LINK JA901 USING 'JA901'; SQL> SELECT table_name FROM user_tables@ja901; Listing 8.1: Erstellen eines Public Datenbank-Links
In diesem Beispiel wird ein Public Link auf die Datenbank mit der Adresse JA901 erstellt. Die anschließende Abfrage gibt alle Tabellennamen des äquivalenten Benutzers auf der anderen Datenbank aus. SQL> CREATE PUBLIC DATABASE LINK JA901_DEMO CONNECT TO demo IDENTIFIED BY demo USING 'JA901'; SQL> SELECT table_name FROM user_tables@ja901_demo; Listing 8.2: Public Datenbank-Link auf ein spezifisches Schema
In diesem Fall wird ein Public Link erstellt, der sich in der Zieldatenbank immer mit dem gleichen Benutzer anmeldet. Das bedeutet, egal welcher Benutzer auf der Quelldatenbank die Abfrage aufruft, das Ergebnis ist immer gleich, da er die Tabellennamen des Benutzers demo abfragt. SQL> CREATE DATABASE LINK JA901 CONNECT TO demo IDENTIFIED BY demo USING 'JA817'; SQL> SELECT table_name FROM user_tables@ja901; Listing 8.3: Private Link auf ein spezifisches Schema
Obwohl es bereits einen Public Link ja901 auf die Datenbank mit der Adresse ja901 gibt, kann der Benutzer einen Private Link mit gleichem Namen auf die Datenbank mit der Adresse ja817 erstellen. In diesem Fall greift dieser Benutzer immer auf die Datenbank ja817 und den Benutzer demo zu, während alle anderen auf die Datenbank ja901 und ihren äquivalenten Benutzer zugreifen. An diesem Beispiel erkennt man, dass eine derartige Konstellation schwer zu durchschauen ist. Empfehlung: Setzen Sie für die Instanzen global_names = true, damit kann zwar jeder Benutzer seine eigenen Links erstellen (sofern er die Berechtigung dafür hat), gleiche Link-Namen für unterschiedliche Datenbanken werden so aber verhindert. Nachdem ein entsprechender Datenbank-Link auf die Ferndatenbank angelegt worden ist, können die entsprechenden Tabellen wie lokale Tabellen angesprochen werden. Durch den Einsatz von Synonymen können diese Tabellen dann in jede Anwendung eingebaut werden, ohne dass Rücksicht auf die Verteilung genommen werden muss.
Sandini Bib
Grundkonzepte
545
SQL> CREATE SYNONYM KUNDEN FOR KUNDEN@ja901; SQL> SELECT nachname FROM KUNDEN; Listing 8.4: Einsatz von Synonymen
Gerade dieses Beispiel ist interessant für die Migration von Anwendungen, da das Synonym jederzeit geändert werden kann und somit die Tabelle kunden von einer auf die andere Datenbank verschoben werden kann, ohne dass die Anwendung dies merkt.
8.1.2
Verteilte Transaktionen
Bei verteilten Transaktionen garantiert ein im Oracle-Kern verankerter Mechanismus, das Two-Phase-Commit-Protokoll, die Datenkonsistenz. Entscheidendes Merkmal für das Vorhandensein einer verteilten Transaktion sind DML-Operationen in mehr als einer Datenbank im Kontext einer globalen Transaktion. INSERT INTO KUNDEN (kdnr, anrede, vorname, nachname) VALUES (100001, 'Frau', 'Carina','Ahrends'); INSERT INTO KUNDEN@ja901 (kdnr, anrede, vorname, nachname) VALUES (100001, 'Frau', 'Carina','Ahrends'); COMMIT; Listing 8.5: Two-Phase-Commit
In diesem Beispiel wird zunächst in der lokalen Datenbank und dann in der Ferndatenbank ein Datensatz eingetragen und anschließend durch den Befehl COMMIT festgeschrieben. Es muss gewährleistet werden, dass mit dem COMMIT der Eintrag in beiden Datenbanken vorgenommen wird oder, falls das aus irgendeinem Grunde nicht möglich ist, auf beiden Datenbanken zurückgesetzt wird. Es ist wichtig zu wissen, dass verteilte Transaktionen nicht nur für synchrone Replikate wie in diesem Fall gebraucht werden, sondern genauso im Umfeld von asynchronen Kopien. Denn auch dort müssen die Aktionen abgeglichen werden, d.h., auf der Quellseite darf und muss ein Datensatz erst gelöscht werden, wenn er auf der Zielseite erfolgreich eingetragen wurde. Die zwei Phasen des Two-Phase-Commit-Protokolls werden wie folgt umgesetzt: 1. Prepare-Phase: Der globale Koordinator veranlasst alle beteiligten Knoten, bis auf die Commit Point Site, in den Vorbereitungszustand (prepare) zu gehen. Die betreffenden Transaktionsteile schreiben daraufhin wie bei einem normalen Commit ihre Transaktionsdaten in die Redolog-Dateien und garantieren ferner, die Transaktionskontrolle nur im Einklang mit dem globalen Koordinator durchzuführen. Die erfolgreiche Ausführung der Aktion wird dem Koordinator mit dem Flag
Sandini Bib
546
Verteilte Datenbanktechniken
prepared zurückgemeldet. Wenn auf einem der beteiligten Knoten nur Daten gelesen wurden, meldet dieser ein read-only an den Koordinator. Dieser Knoten nimmt dann nicht mehr an der zweiten Phase teil. Der Knoten, auf dem sich der Anwender angemeldet hat, wird als Primärtransaktionsknoten oder als Koordinator bezeichnet. Die
Commit
Point
Site
ermittelt
über
den
Initialisierungsparameter
commit_point_strength. Der an der Transaktion beteiligte Knoten mit der
höchsten Nummer wird zur Commit Point Site. Der Standardwert ist 1 und sollte so angepasst werden, dass der Knoten mit der größten Transaktionslast die höchste Nummer erhält. In der Regel ist dies der Koordinator. Wenn aber eine Datenbank an der Transaktion teilnimmt, die kein Two-Phase-Commit-Protokoll unterstützt, wird diese Datenbank automatisch zur Commit Point Site. 2. Commit-Phase: Der globale Koordinator wertet die Antworten der beteiligten Knoten aus. Wenn er von allen das prepared oder read-only zurückerhalten hat, wird die Commit Point Site angewiesen, die Transaktion zu beenden (commit). Nachdem diese die Meldung transaction completed zurückgegeben hat, werden alle anderen Knoten ebenfalls angewiesen, die Transaktion zu beenden. Waren alle Transaktionsteile erfolgreich, wird die Gesamttransaktion beendet und aus den entsprechenden virtuellen Tabellen gelöscht. wird der Initialisierungsparameter der commit_point_strength distributed_transactions gesetzt. Mit ihm wird die maximale Anzahl parallel
Neben
laufender verteilter Transaktionen, die eine Instanz verwalten kann, eingestellt. Der Standardwert ist 10.
Abbildung 8.1: Two-Phase-Commit
Sandini Bib
Grundkonzepte
547
Fehler bei verteilten Transaktionen Der oben beschriebene Fall stellt die in den meisten Fällen vorkommende Ausführung eines Commits dar. Natürlich kann es in solchen Umgebungen, gerade wenn die Latenzzeit im Netzwerk sehr hoch ist, zu Fehlern während der Ausführung des Two-Phase-Commit kommen. Im Folgenden werden die einzelnen Aktionen beschrieben, die das System oder der Administrator durchführen müssen, wenn es zu einem solchen Fehler kommt.
: :
Fehler in der Prepare-Phase Schließt eine Subtransaktion die Prepare-Phase nicht erfolgreich ab (z.B. weil die Redolog-Datei nicht geschrieben werden kann), gibt der globale Koordinator die Anweisung zum Rollback der globalen Transaktion. Fehler in der Commit-Phase Schlägt der Commit auf dem ersten Knoten (Commit Point Site) fehl, kann der Koordinator für alle Knoten ein Rollback veranlassen. Schlägt der Commit auf einem anderen Knoten fehl (z.B. durch einen Netzwerkausfall), bleiben die Transaktionen in einem zweifelhaften Zustand, in-doubt, bis sich dieser Knoten wieder meldet und der Recover-Prozess (RECO) die Subtransaktion beendet. Während dieser Zeit sind die Daten auf dem betroffenen Knoten weder les- noch schreibbar. Sollte der Knoten durch einen Fehler keine Informationen vom Koordinator erhalten, muss der Administrator die Beendigung der Transaktion manuell beheben. Dafür wird zunächst die Transaktionsnummer aus der Tabelle dba_2pc_pending gelesen und anschliessend mit dem Befehl COMMIT FORCE ’transaction_id’ oder ROLLBACK FORCE ’transaction_id’ beendet. Danach muss die Transaktion ebenfalls manuell aus der Tabelle dba_2pc_pending gelöscht werden. Dies geschieht mit der PL/SQL-Prozedur: dbms_transaction. purge_lost_db_entry('trans_id'). Leider funktioniert diese Prozedur nicht in der Version 9i sondern nur in Version 8i.
Das folgende Beispiel zeigt, wie ein solcher Fehler simuliert und behoben werden kann. Beispiel: SQL> ALTER SYSTEM DISABLE DISTRIBUTED RECOVERY; System wurde geändert. SQL> INSERT INTO KUNDEN@ja901 (kdnr, anrede, vorname, nachname) VALUES (100002, 'Frau', 'Mareike','Ahrends'); 1 Zeile wurde erstellt.
Sandini Bib
548
Verteilte Datenbanktechniken
SQL> INSERT INTO KUNDEN (kdnr, anrede, vorname, nachname) VALUES (100002, 'Frau', 'Mareike','Ahrends'); 1 Zeile wurde erstellt. SQL> COMMIT COMMENT 'ORA-2PC-CRASH-TEST-7'; commit comment 'ORA-2PC-CRASH-TEST-7' * FEHLER in Zeile 1: ORA-02054: Transaktion 7.13.2228 unterbrochen, Transaktionsausgang ungewiss. ORA-02059: ORA-2PC-CRASH-TEST-7 in Commit-Kommentar SQL> SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID, STATE FROM DBA_2PC_PENDING; LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE ---------------------- -------------------------- --------7.13.2228 SUNDB.534b4e3a.7.13.2228 prepared SQL> COMMIT FORCE '7.13.2228'; Transaktion mit COMMIT abgeschlossen. Listing 8.6: Simulation einer fehlerhaften Transaktion
Alternativ kann ein solcher Fehler natürlich auch über den Oracle Enterprise Manager behoben werden. Die folgende Abbildung zeigt eine offene Transaktion und die Möglichkeit eines Commits oder Rollbacks dieser.
Abbildung 8.2: Erzwungener Commit
Sandini Bib
Replikation
549
Ein solcher Eingriff in ein operatives System sollte aber die Ausnahme bleiben. In den meisten Fällen wird der Reco-Prozess die entsprechende Transaktion nach einer gewissen Zeit auflösen können. Daher sollten Sie den Einsatz vermeiden und nur dann einsetzen, wenn zum Beispiel eine Datenbank zurückgesichert werden muss und aus diesem Grunde keine Transaktionsinformation mehr zur Verfügung steht.
8.2
Replikation
8.2.1
Einführung
Replikation wird im Kontext von Datenbanken eingesetzt, um Objekte und ihre Inhalte redundant zu speichern. Ein betreffendes Objekt, wie z.B. eine Tabelle, ist aus diesem Grunde auf mehreren Systemen ganz oder teilweise verfügbar. Die Replikationsmechanismen der Datenbank sorgen dafür, dass Änderungen an den Daten oder den Strukturen auf alle beteiligten Systeme verteilt und auf diesen Systemen auch genutzt werden. Datenbanken, in deren Kontext replizierte Objekte im Verbund konfiguriert wurden, sind aus diesem Grunde Bestandteil einer gemeinsamen verteilten Datenbankumgebung mit entsprechenden Auswirkungen auf die Komplexität der Konfiguration und Administration. Verteilte Datenbankumgebungen lassen sich – im Gegensatz zur Replikation – auch dispersiv konfigurieren. Hierbei werden Objekte einer Anwendung jeweils einmalig gespeichert, in ihrer Gesamtheit aber auf unterschiedliche Datenbanken verteilt und über entsprechende verteilte Transaktionen manipuliert. Das vorliegende Kapitel konzentriert sich ausschließlich auf die Techniken der Replikation. Es gibt unterschiedliche Motive, über den Aufbau von replizierten Umgebungen nachzudenken:
: : :
Verfügbarkeit: Beim zeitweiligen Ausfall eines Systems stehen die Daten in replizierten Systemen weiterhin zur Verfügung. Performance: Zugriffe auf die betreffenden Objekte können möglicherweise lokal und damit performanter erfolgen. Sicherheit: Durch „selektive“ Replikation werden nur die Daten lokal gespeichert, die auch lokal benötigt werden.
Eine verteilte Datenbankumgebung stellt jedoch eine Reihe von zusätzlichen Anforderungen, die den Grad der Komplexität bei der Entwicklung von Anwendungen zweifelsohne heraufsetzen:
: :
Datenmodellierung: Vorhandene Tabellenmodelle müssen um die Dimensionen Verteilung und Replikation erweitert werden. Attributerweiterungen können die Folge sein. Programmlogik: Prozeduren müssen „replikaktionstauglich“ sein, z.B. bei der Vergabe von eindeutigen Schlüsseln in verteilten Umgebungen.
Sandini Bib
550
: :
Verteilte Datenbanktechniken
Performance: Da im Zuge der Replikation Daten zwischen verschiedenen Systemen über interne Trigger und Prozeduren synchronisiert werden, erhöht sich die „Last“ auf den betreffenden Datenbanken vor allem dort, wo häufige und umfangreiche DML-Operationen die Regel sind. Konfiguration und Administration: Replizierte Umgebungen sind in jedem Fall komplexer in der Konfiguration sowie der laufenden Administration, wie z.B. bei der Fehlerbehandlung oder bei Recovery-Aktionen.
Im Einzelfall gilt es daher, Aufwand und Nutzen bei der Einführung einer replizierten Umgebung sorgfältig zu prüfen. Die folgenden Seiten geben in diesem Zusammenhang Unterstützung.
8.2.2
Konzepte und Architektur
Um eine replizierte Umgebung optimal planen und implementieren zu können, ist es notwendig, die zugrunde liegenden Konzepte und Begriffe genau zu verstehen. Dies soll der vorliegende Abschnitt leisten. Im Wesentlichen existieren zwei grundlegend verschiedene Kommunikationsmodelle, nach denen sich die Replikation im Umfeld von Oracle-Datenbanken konfigurieren lässt:
: :
Die Multimaster-Replikation arbeitet mit identischen und gleichwertigen Kommunikationspartnern (peer-to-peer) Die Materialized View-Replikation setzt auf vollständige oder teilweise Kopien ihrer Master-Objekte in sternförmig angelegten Kommunikationsumgebungen.
Beide Modelle, sowie ihre Kombination in hybriden Konfigurationen, werden Im Folgenden detailliert beschrieben. Multimaster-Replikation Das Grundprinzip der Multimaster-Replikation ist die Synchronisation von Daten zwischen identischen Replikationsobjekten, wobei jeder Partner, auch Master (master site) genannt, mit allen weiteren Partnern auf gleicher Ebene kommuniziert (peer-to-peer). Die Replikationsobjekte müssen dabei sowohl in ihrer Struktur als auch in ihrem Inhalt auf allen Mastern identisch sein. Für Tabellen bedeutet dies, dass sie mit allen Attributen und allen Tupeln auf jedem Master vertreten sind. Änderungen auf einem Master werden dem entsprechend auf allen anderen Mastern – zeitversetzt oder synchron – repliziert. Replikationsobjekte werden in so genannten Replikationsgruppen (replication group) zusammengefasst. Jede Replikationsgruppe kann Objekte aus einem oder mehreren Schemas enthalten und umgekehrt können Objekte eines Schemas in unterschiedlichen Replikationsgruppen konfiguriert sein. Jedes Replikationsobjekt darf jedoch nur in einer Gruppe enthalten sein.
Sandini Bib
Replikation
551
% %
% %
% %
Abbildung 8.3: Multimaster-Replikation
Replikationsgruppen dienen der Zusammenfassung von logisch miteinander verbundenen Objekten. Für jede Replikationsgruppe lassen sich ein oder mehrere Master Sites definieren. Alle Replikationsobjekte einer Gruppe werden stets vollständig auf allen der Gruppe zugewiesenen Mastern repliziert.
Abbildung 8.4: Replikationsgruppen
Sandini Bib
552
Verteilte Datenbanktechniken
Für jede Replikationsgruppe lässt sich darüber hinaus die gewünschte Übertragungsmethode in Bezug auf einen Master festlegen. Es stehen zwei Methoden zur Verfügung:
:
:
Die asynchrone Replikation überträgt angefallene Änderungen zeitlich versetzt. Die Zeitspanne des Versatzes oder die Häufigkeit der Synchronisation lässt sich entsprechend konfigurieren. Asynchrone Verfahren können zu Datenkonflikten führen, wenn innerhalb einer Aktualisierungsperiode mehrere Master identische Datensätze widersprüchlich ändern. Je kürzer die Aktualisierungsperioden konfiguriert werden und je geringer das Änderungsaufkommen ist, desto geringer ist die Wahrscheinlichkeit von Konflikten. Oracle stellt vorkonfigurierte Konfliktlösungsmethoden zur Verfügung, die im Falle einer asynchronen Replikation unbedingt aktiviert werden sollten. Darüber hinaus erlauben asynchrone Verfahren lokale Transaktionen auch dann, wenn die entfernten Master kurzzeitig nicht zur Verfügung stehen. Die synchrone Replikation übertragt Änderungen unmittelbar im Kontext von verteilten Transaktionen. Für eine erfolgreiche Synchronisation müssen hierzu alle Master der Gruppe verfügbar sein. Ist dies nicht der Fall, sorgt der 2PC-Algorithmus der verteilten Transaktion für das Zurückrollen der lokalen Transaktion. Datenänderungen werden bei dieser Methode unmittelbar auf allen Mastern sichtbar. Auf Grund der synchronen Übertragung sind Datenkonflikte per se ausgeschlossen.
Innerhalb jeder Replikationsgruppe hat einer der vorhandenen Master die Rolle der Master Definition Site inne. Über die Master Definition Site werden alle administrativen Änderungen im Rahmen der Gruppe durchgeführt, wie z.B. das Hinzufügen neuer Objekte oder weiterer Master. Die Master Definition Site verteilt diese Änderungen zentralistisch an alle Master der betreffenden Gruppe. Replikationsgruppen können unterschiedliche Objekttypen enthalten. Die Art, wie Objekte im Einzelnen repliziert werden, hängt dabei von dem jeweiligen Objekttyp ab:
:
1.
Tabellen werden mit ihrer Struktur und ihren Daten repliziert. Zur Struktur zählen hier nicht nur die Attribute, sondern auch die Constraints, nicht aber im Kontext der Tabelle definierte Trigger oder Indizes. Letztere müssen explizit (s.u.) als replizierte Objekte definiert werden. Änderungen an den Daten werden über so genannte verzögerte Transaktionen (deferred transactions) den anderen Mastern zugespielt. Interne Trigger erzeugen dabei Prozeduraufrufe an entfernte Prozeduren (remote procedure call). Im Falle der asynchronen Replikation werden diese Prozeduraufrufe in Tabellen des Schemas System zwischengespeichert (deferred transaction queue) und von dort aus über Datenbankjobs an die übrigen Master Sites übertragen (Push-Prinzip). Die Prozeduraufrufe enthalten neben den geänderten Spaltenwerten auch die alten Spaltenwerte1, um Konflikte zu erkennen.
In der Version 7 wurden sämtliche alten und neuen Spaltenwerte übertragen, was zu aufgeblähten Tranaction Queues führte. Ab Oracle8 gibt es verschiedene Methoden, das Datenvolumen der Queues zu reduzieren (siehe Minimierung der Transaktionsdaten in Abschnitt 8.2.5)
Sandini Bib
Replikation
553
7
7 = =
&RQVWUDLQWV
&RQVWUDLQWV
,QWHUQHU 7ULJJHU
,QWHUQHU 7ULJJHU
,QWHUQH 3DNHW SUR]HGXU
,QWHUQH 3DNHW SUR]HGXU
=
0DVWHU$
0DVWHU%
Abbildung 8.5: Interne Trigger und Paketprozeduren
: : :
Prozeduren, Funktionen und Pakete werden als Programmeinheit repliziert. Generierte Stellvertreterprozeduren (wrapper) sorgen dafür, dass der Programmcode nicht nur lokal, sondern auf allen Mastern der betreffenden Gruppe zur Ausführung kommt. Trigger werden ebenfalls als Programmeinheit repliziert. Synonyme, Views, Indizes und Indextypen werden als „sekundäre“ Objekte nur mit ihrer Struktur repliziert, d.h., der betreffende DDL-Befehl wird auf allen Mastern der betreffenden Gruppe zur Ausführung gebracht.
Multimaster-Umgebungen erlauben grundsätzlich Datenänderungen auf allen beteiligten Mastern (Update Anywhere-Modell). Dort, wo die Logik der Anwendung dies nicht zulässt, sind andere Änderungsmodelle denkbar:
: :
Primary Site-Prinzip: Änderungen sind nur auf einem und stets demselben Master zulässig. Konflikte sind auf Grund dieser Logik ausgeschlossen. Workflow-Modell: Auch hier sind Änderungen nur auf einem Master zulässig, die Rolle des ändernden Masters kann jedoch – abhängig von einem festen oder freibleibenden Workflow – wechseln. Auch bei diesem Modell sind Konflikte ausgeschlossen.
Beide oben beschriebenen Modelle müssen im Rahmen der jeweiligen Anwendung mit herkömmlichen Methoden – über entsprechende Privilegien, Trigger und Prozeduren – explizit konfiguriert werden.
Sandini Bib
554
Verteilte Datenbanktechniken
Materialized View-Replikation Die Materialized View-Replikation2 erlaubt die vollständige oder teilweise Replikation von Master-Objekten. Auf diese Weise lassen sich sowohl ausgesuchte Spalten (column subsetting) als auch Zeilen (row subsetting) von Master-Tabellen replizieren. Darüber hinaus können auch mehrere Tabellen über Join- oder Set-Operationen in einer Materialized View zusammengefasst werden. Hierin liegt einer der wesentlichen konzeptionellen Unterschiede gegenüber der Multimaster-Welt.
0DVWHU$ 7
7
7
7 6QDSVKRW6LWH
6QDSVKRW6LWH
Abbildung 8.6: Materialized View-Replikation
Die Aktualisierung der Daten erfolgt bei Materialized Views über so genannte Refresh-Operationen (Pull-Prinzip). Refresh-Operationen können entweder manuell oder über einen Datenbankjob auf Seiten der Materialized View initialisiert werden. Die Aktualisierung erfolgt dabei entweder vollständig, d.h., bei jeder Operation werden alle Daten des Masters übertragen (complete refresh), oder „schnell“ (fast refresh), d.h., nur die seit der letzten Aktualisierung erfassten Änderungen werden eingespielt. Für die „schnelle“ Aktualisierung ist auf Seiten des Master-Objektes ein Materialized View Log notwendig. Dieses Log besteht aus einer Hilfstabelle und einem internen Trigger, der bei DML-Operationen die Hilfstabelle mit dem Typ der Operation und dem Primärschlüssel oder der Rowid füllt. Dieses Log enthält damit keine geänderten oder alten Daten, wie die im vorangehenden Abschnitt erwähnten Deferred Transaction Queues. Die Daten werden bei der Aktualisierung direkt aus dem Master-Objekt geladen. Ob eine Materialized View „schnell“ aktualisiert werden kann, hängt von der Materialized View zugrunde liegenden SQL-Abfrage ab.
2.
Unter Oracle8 als Snapshot-Replikation bezeichnet
Sandini Bib
Replikation
555
Jede Materialized View bezieht sich stets auf nur ein Master-Objekt und tauscht mit diesem die Daten aus. Dieses Master-Objekt kann eine einzelne Master-Tabelle, ein Verbund (Join-Operation) aus Master-Tabellen oder seinerseits eine so genannte Master Materialized View sein, wodurch sich ein Mehrschichtenmodell konfigurieren lässt. Umgekehrt kann jede Master-Tabelle mehrere Materialized Views bedienen, so dass eine sternförmige Kommunikationsstruktur entsteht. Materialized Views können die ihnen übertragenen Daten in unterschiedlicher Weise verwalten:
: : :
Lesbare (read-only) Materialized Views gestatten nur lesende Zugriffe. Schreibbare (writeable) Materialized Views können über DML-Operationen lokal verändert werden, die durchgeführten Änderungen werden aber nicht an den zugeordneten Master übertragen, sondern bei der nächsten Aktualisierung überschrieben oder gelöscht. Änderbare (updateable) Materialized Views hingegen übertragen die in ihrem Kontext durchgeführten Änderungen an ihren Master. Die Rückübertragung kann synchron oder asynchron erfolgen und nutzt hierfür – wie die Multimaster-Replikation – Deferred Transaction Queues. Bei asynchroner Übertragung können hier ebenfalls Konflikte entstehen, die auf der Seite des Masters – sofern Konfliktlösungsmethoden konfiguriert wurden – aufgelöst werden.
8SGDWHDEOH 0DWHULDOL]HG9LHZ
0DVWHU7DEHOOH $
,QWHUQHU
,QWHUQH
,QWHUQHU
3DNHW
7ULJJHU ,QWHUQHU
SUR]HGXU
/RJ7ULJJHU
/RJ7ULJJHU
µ
09/RJ 7DEHOOH Abbildung 8.7: Materialized Views – Refresh-Operation
8SGDWHDEOH 09/RJ
Sandini Bib
556
Verteilte Datenbanktechniken
0DVWHU7DEHOOH $
8SGDWHDEOH 0DWHULDOL]HG9LHZ $ &
,QWHUQH ,QWHUQHU
3DNHW ,QWHUQHU
7ULJJHU
SUR]HGXU
,QWHUQHU /RJ7ULJJHU
/RJ7ULJJHU
09/RJ 7DEHOOH
8SGDWHDEOH 09/RJ
Abbildung 8.8: Materialized Views – Update-Operation
Materialized Views, die auf Grund ihrer logischen Zusammengehörigkeit gemeinsam und konsistent aktualisiert werden müssen, lassen sich in Aktualisierungsgruppen (refresh groups) zusammenfassen. Im Kontext einer Materialized View-Umgebung lassen sich neben den besprochenen Materialized Views, die sich auf Master-Tabellen beziehen, auch weitere Objekttypen replizieren: Prozeduren, Funktionen, Pakete, Indizes, Synonyme, Trigger, Views, Indextypen, Operatoren und Type-Definitionen. Für diese Objekte wird jedoch nur der entsprechende DDL-Befehl über den Master generiert und das entsprechende Objekt auf diese Weise auf der Materialized View Site repliziert. Hybride Modelle Die Welt der Multimaster-Replikation und die der Materialized Views lassen sich zum einem hybriden Modell mischen. In diesem Falle werden bestimmte Master Sites über Deferred Transaction Queues miteinander verbunden. Jede Master Site kann darüber hinaus Master für eine oder mehrere Materialized Views sein. Die Materialized Views kommunizieren auch hier ausschließlich mit dem ihnen zugeordneten Master-Objekt. Nur über dieses Objekt gelangen die in ihrem Kontext durchgeführten Änderungen an weitere Materialized Views dieses Masters oder an andere Master der Multimaster-Welt. Die Aktualisierungsgruppen der Materialized View Sites werden in Bezug auf Master-Gruppen der Master Sites angelegt, können aber – im Gegensatz zu einer reinen Multimaster-Umgebung – auch Teilmengen einer zugeordneten Mastergruppe replizieren. Konfliktlösungen lassen sich auch in
Sandini Bib
Replikation
557
diesem Modell nur im Kontext der Master-Gruppen konfigurieren. Die MasterGruppen lösen damit auch die Konflikte der ihnen angeschlossenen Materialized View.
0DVWHU$ 7
0DVWHU%
7
7
7 6QDSVKRW6LWH
7 6QDSVKRW6LWH
7
7
7
6QDSVKRW6LWH
Abbildung 8.9: Replikation – Hybride Modelle
Schnittstellen und Werkzeuge Zur Konfiguration und Verwaltung von replizierten Umgebungen stehen unterschiedliche Möglichkeiten zur Verfügung:
: :
:
Das so genannte Replication Management API bietet unter dem Schema von SYS eine Reihe von Paketprozeduren zur Verwaltung aller Funktionalitäten, welche die Replikation unter Oracle9i zu bieten hat. Über spezielle Views des Data Dictionary, die auf Tabellen des Schemas System zugreifen, und einige v$-Views lassen sich alle Informationen abfragen. Im Kontext der Konsole des Enterprise Managers erscheint für jede registrierte Datenbank ein Verzeichnispunkt „Replication“, über den viele Funktionalitäten verwaltet und Informationen angezeigt werden können. Der Enterprise Manager bietet in diesem Zusammenhang auch Setup-Routinen zum Konfigurieren von Multimaster- und Materialized View-Umgebungen, welche die Arbeit erleichtern können. Darüber hinaus bietet dieses Werkzeug die Möglichkeit, SQL-Befehle und Prozeduraufrufe in SQL-Dateien zu protokollieren. Diese Dateien können dann entsprechend angepasst und erweitert werden. Die Nutzung des Enterprise Managers ist vor allem dort empfehlenswert, wo – wie unten im Detail erläutert – mit einem globalen Replikationsadministrator gearbeitet wird. Wird die Replikation über einen Schemaadministrator verwaltet, bereitet der Enterprise Manager weniger Freude.
Sandini Bib
558
8.2.3
Verteilte Datenbanktechniken
Die Planung einer replizierten Datenbank
Im vorangehenden Abschnitt wurden die grundlegenden technischen Möglichkeiten zum Aufbau replizierter Umgebungen dargestellt. In der Praxis ist es jedoch notwendig, aus diesen technischen Möglichkeiten diejenigen auszusuchen und entsprechend zu konfigurieren, welche den konkreten Anforderungen eines Projektes genügen und den produktiven Betrieb in der erwarteten Form unterstützen. Nur so lässt sich sicherstellen, dass die Erwartungen an die Replikation der Daten erfüllt werden können. Auswahl des Replikationsmodells An erster Stelle steht in diesem Zusammenhang die Auswahl eines geeigneten Replikations- und Kommunikationsmodells, das die Strukturen des betreffenden Geschäftsmodells adäquat abbildet. Filialen, die auch organisatorisch an eine bestimmte Geschäftsstelle gebunden sind, nur eine Untermenge an Daten benötigen und nicht direkt miteinander kommunizieren, lassen sich in der Regel besser im Rahmen einer Materialized View-Replikation konfigurieren. Ebenbürtige Geschäftsstellen, die ihre Daten alle direkt austauschen müssen, verlangen häufig nach einer Multimaster-Replikation. Die Vor- und Nachteile der einzelnen Modelle werden in den folgenden Abschnitten noch einmal zusammengefasst. Multimaster-Replikation Die Multimaster-Replikation repliziert Objekte – wie bereits dargelegt – ohne Ausnahme vollständig inklusive vorhandener Constraints. Alle Master Sites dieses Modells kommunizieren darüber hinaus ebenbürtig miteinander. Dies kann – bei einer großen Anzahl von Mastern und entsprechendem Änderungsvolumen – das Kommunikationsaufkommen erheblich steigern. Für Umgebungen, die mehr als drei konkurrierende Master Sites3 betreiben, sind darüber hinaus automatisierte Konfliktlösungen nicht oder nur eingeschränkt möglich4.
Darüber hinaus werden Änderungen in Multimaster-Umgebungen über verzögerte Transaktionen übertragen. Verzögerte Transaktionen reproduzieren alle durchgeführten Änderungen mit ihren neuen und alten Daten in der Reihenfolge der originalen Transaktionen. Häufige und umfangreiche Änderungen an identischen Daten verursachen in dieser Umgebung eine linear wachsende Deferred Transaction Queue. Im Gegensatz dazu erfassen Materialized View-Umgebungen die Änderungen ihrer Master mit Hilfe von Materialized View Logs, die im wesentlichen nur die Satzadressen oder Primärschlüssel ihrer Quelldaten repräsentieren. Multimaster-Umgebungen unterstützen synchrone Übertragungsverfahren und garantieren damit größtmögliche Aktualität. Ein großer Vorteil ist hierbei die Konfliktvermeidung, die allerdings durch eine erhöhte Abhängigkeit von den übrigen Master Sites erkauft wird. In vielen Fällen ist daher die asynchrone Übertragung vorteilhaft. Um hohen Ansprüchen an die Aktualität zu genügen, können die Übertragungsintervalle entsprechend kurz konfiguriert werden, wodurch auch die Wahrscheinlichkeit von Konflikten minimiert und eine Quasi-Synchronität erreicht wird. 3. 4.
Dies sind Master Sites, die Änderungstransaktionen durchführen. Siehe hierzu Tabelle 8.1
Sandini Bib
Replikation
559
Materialized Views Ein markantes Merkmal von Materialized View-Umgebungen ist die Möglichkeit, Untermengen von Master-Tabellen oder Master-Gruppen zu replizieren. Dadurch lassen sich gezielt die Ausschnitte von Tabellen abbilden, die auf der Materialized View Site tatsächlich benötigt werden. Diese Tatsache dient zum einen der Datensicherheit, zum anderen lässt sich dadurch auch das Übertragungsvolumen reduzieren. Da Konflikte, die durch Änderungen über Materialized Views entstehen, auf dem zugeordneten Master erkannt und dort nach entsprechender Konfiguration zentral gelöst werden, gibt es hier keine Einschränkungen hinsichtlich der maximal möglichen, konkurrierenden Materialized View Sites.
Aktualisierungen von Materialized Views sind allerdings nur asynchron über Refresh-Operationen möglich, allerdings können Änderungen, die über Materialized Views eingegeben werden, bei Bedarf synchron an den Master übertragen werden. Auch hier können bei hohen Anforderungen an die Aktualität die Aktualisierungsintervalle der asynchronen Übertragung entsprechend klein gewählt werden. Materialized Views reproduzieren nicht die Constraints ihres Master-Objektes. Sind Constraints auf Seiten der Materialized View gefordert, und dies macht nur Sinn für veränderbare Materialized Views, können diese nachträglich aufgebaut werden. Wegen der Batch-orientierten Aktualisierung sollten die Constraints jedoch erst am Ende einer Transaktion verifiziert werden5, da eine transaktionsinterne Verletzung der Konsistenzregeln nicht ausgeschlossen werden kann. Wichtig: Die Verwendung von kaskadierendem Löschen (ON DELETE CASCADE-Constraint) ist auf der Materialized View Site nicht erlaubt, da es dabei zu einer fehlerhaften Interpretation des Löschvorganges kommt; zum einen kommt der Löschbefehl vom Master über die Replikation, zum anderen wird der Löschvorgang lokal durch den Constraint ausgelöst, was zu Konflikten führt. Hybride Modelle Hybride Modelle kombinieren die Eigenschaften der Multimaster- und der Materialized View-Replikation. Sie sind vor allem dort empfehlenswert, wo Daten auf eine größere Anzahl von Rechnern repliziert werden sollen. Bei hybriden Modellen kommt es darauf an, die Zahl der Master Sites möglichst klein zu halten – nach Möglichkeit nicht mehr als drei – und den Großteil der Systeme über Materialized Views zu replizieren. Auf diese Weise wird einerseits das Kommunikationsvolumen reduziert, andererseits bleiben die Möglichkeiten der automatisierten Konfliktlösungen voll erhalten.
Festlegung der Replikationsobjekte und Replikationsgruppen Ist das optimale Replikationsmodell verabschiedet, kommt es als Nächstes darauf an, die zu replizierenden Datenbankobjekte auszuwählen und die entsprechenden Replikationsgruppen zu planen. Die Auswahl der Datenbankobjekte richtet sich naturgemäß nach den Anforderungen der vorhandenen Anwendungen. Bei abhängigen Objekten wie Triggern und von diesen bearbeiteten Tabellen kann es notwendig werden, Anpassungen am Code vorzunehmen. Ein kleines Beispiel soll dies verdeutlichen: 5.
So genannte Deferred Constraints.
Sandini Bib
560
Verteilte Datenbanktechniken
Die Tabelle kunden soll repliziert werden. In ihrem Kontext ist der Trigger tr$kunden definiert, der bei INSERT-, UPDATE- und DELETE-Operationen auf kunden entsprechende Log-Einträge in die Tabelle kunden_log vornimmt. Würden nun alle Tabellenobjekte dieses „Minimodells“ geradewegs repliziert, gäbe es doppelte Einträge in der Log-Tabelle, die ihre Daten einerseits über den Trigger und andererseits über die Replikationsmechanismen erhalten würde. In diesem Beispiel sind vielmehr zwei korrekte Ansätze denkbar: In Variante 1 werden die Tabelle kunden und der unmodifizierte Trigger tr$kunden repliziert. Die Log-Tabelle kunden_log dagegen wird zwar auf allen Master Sites angelegt, jedoch nicht repliziert, d.h., die Daten der Tabelle kunden_log werden nicht zwischen den Master Sites ausgetauscht. Wird nun auf einem Rechner beispielsweise ein Satz eingefügt, gelangt er über den Trigger in die lokale Log-Tabelle, über den Replikationsmechanismus auf die übrigen Master Sites, deren Trigger dafür sorgen, dass die Log-Einträge in den entsprechenden kunden_Log -Tabellen landen. Variante 2 dagegen repliziert kunden, die Log-Tabelle kunden_log, sowie den Trigger tr$kunden. Der Trigger tr$kunden jedoch wird dahingehend modifiziert, dass er nur bei lokalen Operationen zündet.
.XQGHQ
9DULDQWH
.XQGHQB/RJ
Abbildung 8.10: Trigger-Logik (Variante 1)
.XQGHQ
.XQGHQB/RJ
Sandini Bib
Replikation
.XQGHQ
561
9DULDQWH
.XQGHQB/RJ
.XQGHQ
.XQGHQB/RJ
Abbildung 8.11: Trigger-Logik (Variante 2)
Bei der Replikation einer Tabelle werden – wie bereits erwähnt – die zugehörigen Indizes nicht mitrepliziert. Sofern diese für die Zugriffe relevant sind, müssen sie explizit als replizierte Objekte angelegt werden. Sind die Objekte gefunden, gilt es, die Replikationsgruppen zu planen. Hierbei sind die folgenden Kriterien in der angegebenen Reihenfolge zu beachten, die Anzahl der Objekte ist dabei von untergeordneter Bedeutung:
: : :
Objekte, die logisch zusammengehören, wie z.B. Master- und Detailtabellen, sollten gemeinsam in einer Gruppe angelegt werden. Objekte, die identische Master Sites haben, können in einer Gruppe zusammengefasst werden. Objekte, deren Daten über ein gemeinsames Übertragungsverfahren – synchron oder asynchron – repliziert werden, können sich eine Replikationsgruppe teilen.
Im Umkehrschluss heißt dies, dass Objekte, die über unterschiedliche Übertragungsverfahren auf unterschiedliche Master Sites repliziert werden, in keinem Fall eine gemeinsame Gruppe bilden können.
Sandini Bib
562
Verteilte Datenbanktechniken
Konfliktlösungen Konflikte entstehen – wie bereits erwähnt – wenn bei asynchronen Übertragungsverfahren innerhalb eines Aktualisierungsintervalls widersprüchliche Änderungen an identischen Datensätzen vorgenommen werden. Für die Erkennung von Konflikten sind die „alten“ Spaltendaten, d.h. die Daten vor der Änderung, maßgeblich. Konflikte werden – abhängig von ihrem DML-Kontext – in drei Typen unterteilt:
: :
:
Update-Konflikte liegen vor, wenn die alten Daten des sendenden Masters nicht mit den aktuellen Daten des empfangenden Masters übereinstimmen. Eindeutigkeitskonflikte werden erkannt, wenn ein Primärschlüssel oder ein Uniqueness-Constraint verletzt werden. Eindeutigkeitskonflikte können sowohl durch Insert- als auch durch Update-Operationen hervorgerufen werden, sofern – sträflicherweise – die Änderung von Schlüsselattributen von der Anwendung erlaubt wird. Delete-Konflikte entstehen, wenn ein geänderter oder gelöschter Datensatz des sendenden Masters nicht auf dem empfangenden Master identifiziert werden kann, z.B. weil er dort bereits gelöscht wurde.
Alle oben beschriebenen Konfliktszenarien setzen voraus, dass replizierte Datensätze eindeutig identifiziert werden können. Dies geschieht normalerweise durch einen Primärschlüssel. Ist dieser nicht vorhanden, muss unbedingt ein alternativer Primärschlüssel definiert werden6, ansonsten ist die Replikation der betreffenden Tabelle nicht möglich. Die Einführung eines alternativen Primärschlüssels ist auch dort dringend anzuraten, wo die Anwendung die Änderung des ursprünglichen Primärschlüssels verlangt. Oracle bietet für die ersten beiden Konflikttypen eine Reihe vorbereiteter Lösungsstrategien. Zum Beispiel prüft die Methode latest timestamp den Zeitstempel zugeordneter Datensätze und bevorzugt die Variante mit den aktuellsten Datums- und Zeitangaben. Die für die Konfliktlösungen notwendigen Hilfsdaten – hier der Zeitstempel – müssen explizit im Datenmodell angelegt und mit Daten versorgt werden. In unserem Beispiel wäre also eine Date-Spalte zur Verfügung zu stellen, die bei jeder DML-Operation mit dem über einen Trigger generierten aktuellen Datum und der aktuellen Zeit gefüllt wird. Gleichfalls ist es wichtig, die maximal empfohlene Anzahl Master Sites für jede Methode zu berücksichtigen; andernfalls können divergierende Daten die Folge sein. Die Anzahl der Materialized View Sites hingegen ist nicht begrenzt. Für den Fall, dass eine Methode nicht erfolgreich sein kann, etwa weil die Zeitstempel aller Varianten identisch sind, lässt sich eine alternative Lösungsstrategie konfigurieren. Alle Methoden werden grundsätzlich im Kontext von Spaltengruppen (column groups) definiert. Jede Spaltengruppe enthält dabei eine oder mehrere Spalten einer Tabelle. Jede Tabelle kann durchaus mehr als eine Spaltengruppe haben. Dies bedeutet, dass unterschiedliche Lösungsstrategien für die Spalten einer Tabelle definierbar sind. Die Konsistenz eines Datensatzes muss bei der Modellierung von Spaltengruppen natürlich unbedingt beachtet werden.
6.
Oracle bietet hierzu ein spezielles API (dbms_repcat.set_columns)
Sandini Bib
Replikation
563
Die folgende Tabelle gibt eine kurze Übersicht über die vordefinierten Methoden, die empfohlene Anzahl Master und die Bedingungen der Datenkonvergenz : Methode
Typ
Master > 1
Konvergenz
Minimum Value
Update
ja
Abnehmende Werte oder < 3 Master Sites
Maximum Value
Update
ja
Zunehmende Werte oder < 3 Master Sites
Latest Timestamp
Update
ja
Zunehmende Werte oder < 3 Master Sites
Earliest Timestamp
Update
ja
< 3 Master
Discard
Update
nein
< 2 Master
Discard
Uniqueness
ja
Nie garantiert
Overwrite
Update
nein
< 2 Master
Additive
Update
ja
immer
Average
Update
nein
< 2 Master
Site Priority
Update
nein
< 2 Master
Priority Group
Update
ja
Bei festem Workflow
Append Sitename
Uniqueness
ja
Nie garantiert
Append Sequence
Uniqueness
ja
Nie garantiert
Tabelle 8.1: Vorkonfigurierte Konfliktlösungsmethoden
Die Methode latest timestamp wird laut Tabelle 8.1 beispielsweise für die Lösung von Update-Konflikten vorgeschlagen. Sie eignet sich für Umgebungen, die mehr als eine Master Site haben, garantiert jedoch nur dann übereinstimmende, d.h. konsistente Daten, wenn die Anzahl der Master Sites nicht größer als zwei ist oder die Anwendung stets zunehmende Zeitstempelwerte garantiert. In allen anderen Fällen können inkonsistente Daten entstehen, welche die Datenbank nicht als solche erkennt, d.h. keine entsprechenden Fehlermeldungen ausgibt. Die Konsistenz der Daten müsste in solchen Umgebungen explizit über entsprechende Prozeduren geprüft werden. Dort, wo die vordefinierten Methoden nicht genügen, können eigene Algorithmen programmiert und integriert werden (user defined conflict resolution). Es ist dringend zu empfehlen, auch dort Konfliktlösungsstrategien zu konfigurieren, wo nur selten mit Konflikten gerechnet werden muss, da die manuelle Auflösung von Konflikten in der Regel mit hohem zeitlichem und personellem Aufwand verbunden ist. Kann es prinzipiell zu Konflikten kommen, sollte versucht werden, diese zu minimieren, etwa durch entsprechend verkürzte Synchronisierungsintervalle. Die beste Konfliktlösungsstrategie ist nach wie vor die Konfliktvermeidung, etwa durch die Nutzung des Modells „Primary Site“ oder durch ein Workflow-Konzept. Eindeutigkeitskonflikte lassen sich sehr gut durch ein verteiltes Schlüsselkonzept vermeiden, bei dem jede Master Site einen vorgegebenen Nummern- oder Schlüsselkreis zur Verfügung hat.
Sandini Bib
564
Verteilte Datenbanktechniken
Sicherheit Wie überall, so sollte auch im Bereich replizierter Umgebungen nicht an der Planung und Konfiguration von geeigneten Sicherheitsmechanismen gespart werden. Sicherheitsplanung bei der Multimaster-Replikation Die Sicherheit im Bereich der
Administration von Master Sites zu planen bedeutet im Einzelnen:
: : :
Benutzerkategorien für die Administration und Datenübertragung festzulegen, Vertrauensbeziehungen zwischen den Master Sites zu etablieren und die Verschlüsselungsalgorithmen für die Übertragung der Daten über Netzwerkleitungen festzulegen.
Darüber hinaus ist es natürlich wichtig, die Privilegien der Endbenutzer den sicherheitstechnischen Anforderungen der betreffenden Anwendung anzupassen. Diese letztgenannte Privilegisierung unterscheidet sich durch nichts von der in Kapitel 4 besprochenen. Im Rahmen der Multimaster-Replikation stehen drei Benutzerkategorien zur Verfügung:
: :
:
Replikationsadministratoren (replication administrators) übernehmen die Installation und Konfiguration der replizierten Umgebungen, Absender (propagator) sind für die Weiterleitung verzögerter Transaktion zuständig, Empfänger (receiver) regeln den Empfang der eintreffenden Transaktionsdaten.
Jede Benutzerkategorie ist an ein Schema geknüpft und auf Grund dessen durch spezifische Datenbankprivilegien gekennzeichnet. Diese Privilegien werden über das Replikations-API an spezifische Datenbankbenutzer vergeben. Im einfachsten Fall werden alle drei Kategorien in einem Benutzer zusammengefasst, der dann als „universeller“ Replikationsadministrator aufgesetzt wird und in dessen Schemakontext sowohl die Administration aller Replikationsgruppen als auch die Weiterleitung und der Empfang der Transaktionsdaten stattfindet. Dieser universelle Replikationsadministrator hat damit Zugriff auf alle Daten der lokalen wie der entfernten Master. Genauso gut können die genannten Kategorien auf unterschiedliche Datenbankbenutzer verteilt werden. Der Replikationsadministrator ist in diesem Fall entweder global definiert, d.h., er verwaltet alle Replikationsgruppen einer Master Site, oder ist als Schema-Administrator privilegiert für die Verwaltung von Replikationsobjekten im Kontext eines vorgegebenen Datenbank-Schemas. Im letzteren Fall können auch mehrere Replikationsadministratoren pro Master Site angelegt werden, wobei jeder nur Zugriff auf die Objekte seines Schemas hat. Im Gegensatz dazu lässt sich maximal nur ein Propagator pro Datenbank konfigurieren. Vertrauensbeziehungen regeln die Sichtbarkeit der replizierten Daten im Kontext der Benutzerkategorien Propagator und Receiver, sind also nur dort ein Thema, wo die entsprechenden Kategorien auf unterschiedliche Datenbankbenutzer verteilt worden sind. Ist die Vertrauensstellung zwischen zwei Master Sites gegeben (trusted
Sandini Bib
Replikation
565
security), hat der lokale Receiver – und über ihn auch der entfernte Propagator – Zugriff auf alle lokalen Replikationsobjekte. Im umgekehrten Fall (untrusted security) lassen sich die Privilegien der Receiver an vorgegebene Master-Gruppen koppeln, so dass auf diese Weise auch die entfernten Propagatoren nur Zugriff auf Daten „ihrer“ Master-Gruppen erhalten.
5* 5HSOLNDWLRQVJUXSSHQ 3 3URSDJDWRU 5 5HFHLYHU Abbildung 8.12: Replikation – Trusted Security
5* 5HSOLNDWLRQVJUXSSHQ 3 3URSDJDWRU 5 5HFHLYHU Abbildung 8.13: Replikation – Untrusted Security
Sandini Bib
566
Verteilte Datenbanktechniken
Auch Vertrauensbeziehungen manifestieren sich in Form von Datenbankprivilegien, die über das entsprechende Replikations-API den betreffenden Benutzern zugeteilt werden können. Findet die Replikation in einem sicherheitstechnisch sensiblen Umfeld statt, ist es empfehlenswert, die Daten, die im Kontext der verzögerten Transaktionen über das Netz geleitet werden, zu verschlüsseln. Oracle unterstützt eine Reihe unterschiedlicher Verschlüsselungsprotokolle mit verschiedenen Schlüssellängen, wie z.B. DES, Triple-DES und RSA RC4. Die Konfiguration dieser Protokolle wird – ohne großen Aufwand – im Rahmen der Konfiguration von Oracle Net vorgenommen7. Sicherheitsplanung in Materialized View-Umgebungen Die Konzepte, die bei der
Sicherheitsplanung von Materialized View-Umgebungen zur Verfügung stehen, sind denen der im Abschnitt Sicherheitsplanung bei der Multimaster-Replikation beschriebenen sehr verwandt. Auch hier existieren für jede Materialized View Site die Benutzerkategorien Materialized View Replication Administrator und Propagator, statt des Receivers gibt es jedoch einen Refresher, unter dessen Privilegien die Aktualisierung der Materialized View durchgeführt werden. Für jede Master Site gibt es zusätzlich die Kategorien des Proxy Refreshers, das ist der Benutzer, mit dem der Refresher der Materialized View Site kommuniziert und den Proxy Materialized View Replication Administrator der mit dem Materialized View Replication Administrator der Materialized View Site verbunden ist. Analog zu den Multimaster-Konzepten können auch hier alle Kategorien in einem Datenbankbenutzer zusammengefasst oder auf verschiedene Benutzer aufgeteilt werden. Die Regelung der Vertrauensbeziehungen zwischen der Materialized Viewund der Master Site ist identisch mit der im vorangehenden Abschnitt beschriebenen. Bei Materialized View Site sollte ebenfalls die Verschlüsselung der Daten bei der Übertragung über Netzleitungen diskutiert werden. Urladung der Daten und Installationspakete Beim Definieren von Tabellen als replizierte Objekte oder Materialized Views werden nicht nur die Datenstrukturen sondern auch die bereits vorhandenen Datensätze auf den entsprechenden Master Sites oder Materialized View Sites repliziert. Für diese „Urladung“ (instantiation) der Daten stehen unterschiedliche Verfahren zur Verfügung, die – vor allem bei großen Datenmengen – sorgfältig geplant werden müssen, da sie erheblichen Einfluss auf die Performance der Konfiguration haben. Bei dem Standardverfahren, der Online-Instantiation, werden die Datensätze im Zuge der Definition des betreffenden Objektes online über das Netz vom jeweiligen Master abgezogen. Im Gegensatz dazu lassen sich bei der Offline Instantiation die Daten auf alternativen Medien, beispielsweise CD-ROMs, auslagern und ohne Online-Verbindung zu dem betreffenden Master-Objekt einspielen. Das Offline Instantiation-Verfahren steht sowohl in Multimaster-Umgebungen als auch für Materialized Views zur Verfügung. Darüber hinaus lassen sich ganze Materialized View-Umgebungen in Form von Installationspaketen (deployment templates) bündeln. Diese Pakete enthalten sowohl die notwendigen Objektdefinitionen als auch die Daten und sind für die effiziente Installation großer Replikationsumge7.
Siehe hierzu Kapitel 5.
Sandini Bib
Replikation
567
bungen unerlässlich. Beide Verfahren werden im Abschnitt Offline-Instantiation in Abschnitt 8.2.5 detaillierter vorgestellt. Kapazitätsplanung Replizierte Umgebungen produzieren zusätzliche Daten in Form von verzögerten Transaktionen oder Log-Einträgen und benötigen aus diesem Grunde zusätzliche Ressourcen. Die folgenden Ressourcen sind hier von Bedeutung und sollten im Zuge einer Testinstallation quantifiziert werden:
:
:
:
Verzögerte Transaktionen werden in der so genannten Deferred Transaction Queue gespeichert. Die Deferred Transaction Queue besteht aus Tabellen des Schemas System8. Diese Tabellen sind standardmäßig in dem Tablespace System angelegt, können jedoch bei Bedarf auch verschoben werden. Die Größe dieser Tabellen hängt einerseits von der Anzahl und Größe der Transaktionen, andererseits von der Häufigkeit und den Zeitintervallen der Löschoperationen ab. Löschoperationen werden – wie weiter unten dargestellt – über einen speziellen Purge-Job konfiguriert. Änderungen an Master-Objekten, denen eine oder mehrere Materialized View zugeordnet sind, werden über interne Trigger in Materialized View Log-Tabellen protokolliert. Die Größe dieser Log-Tabellen hängt sowohl von der Änderungsrate als auch von den Aktualisierungszyklen der abhängigen Materialized View Sites ab. Log-Einträge werden erst dann gelöscht, wenn die letzte der registrierten Materialized Views ihre Refresh-Operation durchgeführt hat. Besonders in Umgebungen, deren Master Sites nur manuelle und damit nicht planbare Aktualisierungen vornehmen, kann dies zu unkontrolliertem Wachstum der Logs führen. Tablespaces, die diese Log-Tabellen aufnehmen, müssen demnach ausreichend dimensioniert und beobachtet werden. Deferred Transaction Queues und Aktualisierungen von Materialized Views übertragen während der Synchronisationen ihre Daten mit Hilfe von Datenbank-Links über Netzverbindungen. Die Bandbreite dieser Verbindungen muss die anfallende Last bewältigen können. Das Datenvolumen aller Link-Verbindungen lässt sich mit Hilfe der Tabelle v$sysstat und dort über den Parameter bytes received via SQL*Net from dblink und bytes sent via SQL*Net to dblink abfragen.
8.2.4
Installation und Konfiguration
In den folgenden Abschnitten wird anhand eines Beispiels die Planung und schrittweise Konfiguration einer replizierten Umgebung besprochen. Beispielumgebung Die replizierte Umgebung soll für die fiktive Firma Ganzbillig GmbH aufgebaut werden, die preiswerte Gerbrauchsartikel an ihre Kunden verkauft. Diese Firma unterhält zwei Hauptgeschäftsstellen, eine in Köln und eine in München. Jeder 8.
Hier vor allem die Tabellen Def$Aqcall und Def$Lob.
Sandini Bib
568
Verteilte Datenbanktechniken
Geschäftsstelle sind eine Reihe von Filialen zugeordnet; manche Filiale hat darüber hinaus eine oder mehrere Außenstellen. In allen Niederlassungen werden separate Datenbanken betrieben, die jedoch aus Gründen der Aktualität und Datenkonsistenz replizierte Objekte enthalten. Das stark vereinfachte Datenmodell dieser Firma besteht aus den Tabellen kunden, kunden_vermerke, auftraege, auftr_positionen und artikel.
.XQGHQ
.XQGHQB9HUPHUNH
$XIWUDHJH
$XIWUB3RVLWLRQHQ
$UWLNHO Abbildung 8.14: ER-Diagramm der Beispieltabellen
Die Tabellen werden wie folgt aufgebaut: CREATE TABLE kunden (kdnr vorname nachname plz ort adresse CONSTRAINT pk_kunden PRIMARY KEY (kdnr) ) / CREATE TABLE kunden_vermerke (kdnr lfd_nr datum vermerk CONSTRAINT pk_kunden_vermerke
VARCHAR2(20) NOT NULL, VARCHAR2(50), VARCHAR2(50), VARCHAR2(20), VARCHAR2(50), VARCHAR2(50),
VARCHAR2(20) NOT NULL, NUMBER NOT NULL, DATE, VARCHAR2(1000),
Sandini Bib
Replikation
569
PRIMARY KEY (kdnr,lfdnr) ) / CREATE TABLE artikel (artikel_nr artikelbezeichnung preis CONSTRAINT pk_artikel PRIMARY KEY (artikel_nr) ) / CREATE TABLE auftraege (auftrag_nr datum kdnr CONSTRAINT pk_auftraege PRIMARY KEY (auftrag_nr) ) /
VARCHAR2(20) NOT NULL, VARCHAR2(50), NUMBER,
VARCHAR2(20) NOT NULL, DATE, VARCHAR2(20) NOT NULL,
CREATE TABLE auftr_positionen (auftrag_nr VARCHAR2(20) NOT NULL, position INTEGER NOT NULL, artikel_nr VARCHAR2(20), CONSTRAINT pk_auftr_positionen PRIMARY KEY (auftrag_nr, position) ) / Listing 8.7: Beispielumgebung
Alle Tabellen werden in einem Schema namens reptest angelegt. Die Firmenleitung wünscht eine komplette Replikation aller Tabellen im Kontext der beiden Hauptgeschäftsstellen. In den Filialen sollen nur für die jeweilige Filiale relevante Daten gespeichert werden. Dies sind im Einzelnen: alle Artikel, Kunden und Kundenvermerke des der Filiale zugeordneten Postleitzahlbereiches sowie alle Aufträge dieser Kunden. Die Außenstellen erhalten alle Daten ihrer Filiale. Artikeldaten werden nur in den Hauptgeschäftsstellen gepflegt, in den Filialen und Außenstellen nur gelesen. Kunden- und Auftragsdaten dagegen werden sowohl in den Filialen als auch in den Hauptgeschäftsstellen verändert. Im Falle eines Konfliktes soll bei Kunden- und Auftragsdaten der Zeitstempel der Änderung maßgeblich sein. Der Organisation der Firma entsprechend werden die Hauptgeschäftsstellen als Multimaster-Umgebung konfiguriert, Filialen und Außenstellen als Materialized View Sites. Die Materialized Views der Außenstellen beziehen sich auf die Master Materialized View der Filialen.
Sandini Bib
570
Verteilte Datenbanktechniken
Änderungen werden grundsätzlich asynchron an die Master übertragen, einzige Ausnahme ist die Tabelle kunden_vermerke, die eventuelle Sperrvermerke in Bezug auf einen Kunden enthält und synchron gekoppelt werden soll. Wegen dieser synchronen Kopplung wird für kunden_vermerke eine eigene Replikationsgruppe geplant; alle anderen Objekte werden gemeinsam in einer zweiten Gruppe angelegt. Aus Sicherheitsgründen werden Replikationsadministratoren auf Schemaebene konfiguriert und separate Benutzer für die Kategorien Propagator und Receiver angelegt. Die globalen Namen der Beispieldatenbanken sind wie folgt vergeben: Lokalität
Globaler Datenbankname
Hauptgeschäftsstelle Köln
gs_koeln.ganzbillig
Hauptgeschäftsstelle München
gs_muenchen.ganzbillig
Beispielfiliale in Rosenheim bei München
fil_20.ganzbillig
Außenstelle Miesbach
as_miesbach.ganzbillig
Tabelle 8.2: Verteilte Datenbanken und ihre globalen Namen
Grundkonfiguration Die folgende Beschreibung setzt voraus, dass die Enterprise Edition vorliegt und die Replikationsoption bereits auf allen beteiligten Datenbanken installiert wurde. Eine Kontrolle kann jederzeit über die virtuellen Tabellen v$version und v$option durchgeführt werden. Nach erfolgreicher Installation müssen darüber hinaus die Pakete dbms_repcat und dbms_reputil mit ihren Namensvettern gültig vorliegen. Gleichfalls muss Oracle Net zuvor installiert und konfiguriert worden sein, d.h., die Namen aller beteiligten Master Sites und Materialized View Sites müssen für Oracle Net interpretierbar sein. Systemparameter Vor der Konfiguration replizierter Umgebungen sind als Erstes einige Systemparameter zu prüfen und bei Bedarf neu einzustellen:
: :
:
:
compatible sollte auf den aktuellen Versionsstand eingestellt werden, z.B. auf
9.0.1. global_names = true zwingt zu einem globalen Namensmodell, d.h., Daten-
bank-Links müssen identisch wie die globalen Namen der Datenbanken, auf die sie zeigen, benannt werden. Der Parameter muss in replizierten Umgebungen auf true gesetzt werden. job_queue_processes gibt die Anzahl der Hintergrundprozesse für die Jobver-
waltung an. Der Parameter muss mindestens auf 1 gesetzt werden, besser noch auf die Zahl der gleichzeitig auszuführenden Datenbankjobs. In MultimasterUmgebungen mit n Mastern, die möglicherweise zeitgleich übertragen, auf mindestens n-1. open_links gibt die maximale Anzahl der für jede Sitzung gleichzeitig zu öffnenden Datenbank-Links an. Der Parameter ist vor allem bei synchronen Über-
Sandini Bib
Replikation
: :
571
tragungsverfahren sorgfältig zu prüfen und auf die Anzahl der konfigurierten Master Sites minus 1 zu setzen. Die Parameter parallel_max_servers und parallel_min_servers konfigurieren die Prozesse für parallele Operationen der Instanz. Sie sind zu setzen, wenn die Deferred Transaction Queue parallel übertragen werden soll (parallel propagation). replication_dependency_tracking = true aktiviert die Prüfung von Abhän-
gigkeiten zwischen Transaktionen. Diese Abhängigkeitsprüfungen sind entscheidend für die parallele Übertragung verzögerter Transaktionen.
Benutzer und Datenbank-Links anlegen Im nächsten Schritt sind die geplanten
Benutzer für die Administration der replizierten Umgebung anzulegen, zu privilegieren sowie entsprechende Datenbank-Links aufzubauen. Diese Schritte lassen sich über die Konsole des Werkzeugs Enterprise Manager, dort unter dem Menüpunkt REPLIKATION, dann SETUP WIZARD, erledigen, falls ein globaler Replikationsadministrator gewünscht wird. In unserem Beispiel dagegen soll aus Sicherheitsgründen ein Schema-Replikationsadministrator angelegt werden. In diesem Fall empfiehlt sich – wie im Folgenden dokumentiert ist – die Nutzung von SQL-Scripts und keinesfalls die Arbeit über den Enterprise Manager. Zunächst jedoch legen wir auf jeder Master Site Public Links an, welche nur die entsprechende USING-Klausel für die geplanten Master Sites enthalten. Auf gs_muenchen.ganzbillig: CREATE PUBLIC DATABASE LINK gs_koeln.ganzbillig USING 'gs_koeln.ganzbillig';
Auf gs_koeln.ganzbillig: CREATE PUBLIC DATABASE LINK gs_muenchen.ganzbillig USING 'gs_muenchen.ganzbillig';
Als Nächstes sind die administrativen Benutzer auf jedem Master anzulegen und zu privilegieren. Der Benutzer REPTEST, dem auch die zu replizierenden Objekte gehören, wird Schema-Replikationsadministrator, REPPROP wird Propagator und gleichzeitig Receiver: /* Administrator */ CREATE USER reptest IDENTIFIED BY geheim; BEGIN DBMS_REPCAT_ADMIN.GRANT_ADMIN_SCHEMA( USERNAME => 'REPTEST'); END; / Listing 8.8: Erstellung Benutzer reptest
Damit der Schema-Replikationsadministrator, der ja bewusst keine DBA-Privilegien erhalten hat, auch die Enterprise Manager-Konsole aufrufen und die Replikations-
Sandini Bib
572
Verteilte Datenbanktechniken
Menüs benutzen kann, muss ihm das Recht zum Selektieren des Data Dictionarys gegeben werden: GRANT SELECT ANY DICTIONARY TO reptest; /* Propagator */ CREATE USER repprop IDENTIFIED BY geheim; BEGIN DBMS_DEFER_SYS.REGISTER_PROPAGATOR( USERNAME => 'REPPROP'); END; / GRANT EXECUTE ANY PROCEDURE TO repprop; /* Receiver */ BEGIN DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP( USERNAME => 'REPPROP', PROVILEGE_TYPE => 'receiver', LIST_OF_GNAMES => NULL ); end; / Listing 8.9: Erstellung Benutzer repprop
Für den Benutzer reptest wird nun für jede zusätzliche Master Site ein privater Datenbank-Link angelegt, der auf den Benutzer reptest der Gegenseite verweist. Auf Grund des globalen Namensmodells werden die allgemeinen und privaten Datenbank-Links beim Verbindungsaufbau gemeinsam interpretiert. CONNECT reptest/geheim@gs_muenchen.ganzbillig CREATE DATABASE LINK gs_koeln.ganzbillig CONNECT TO reptest IDENTIFIED BY geheim;
Analog wird auf der Master Site gs_koeln.ganzbillig verfahren. Da in unserem Beispiel Propagator und Receiver separat definiert wurden, müssen nun für jede Master Site private Datenbank-Links vom Propagator zum Receiver aufgebaut werden. Für die Geschäftsstelle München bedeutet dies: CONNECT repprop/geheim@gs_muenchen.ganzbillig CREATE DATABASE LINK gs_koeln.ganzbillig CONNECT TO repprop IDENTIFIED BY geheim;
Sandini Bib
Replikation
573
0QFKHQ
.|OQ
Abbildung 8.15: Datenbank-Links im Mulitmaster-Umfeld
Jobs Nach dem Aufbau der Datenbank-Links, Benutzer und Privilegien werden
Jobs definiert. Jede Master Site erhält drei Arten von Jobs: Für jede Ferndatenbank jeweils einen Job zum Übertragen der Deferred Transaction Queue (Scheduled Link), einen Job zum Löschen der bereits abgearbeiteten verzögerten Transaktionen und einen zum Ausführen von verteilten administrativen Aufgaben, wie z.B. das Anlegen eines neuen Replikationsobjektes. Der Job zum Übertragen der Transaktionsdaten wird über den Replikationsadministrator, hier reptest, angelegt: CONNECT reptest/geheim@gs_muenchen.ganzbillig BEGIN DBMS_DEFER_SYS.SCHEDULE_PUSH( DESTINATION => 'gs_koeln.ganzbillig', INTERVAL => 'sysdate + 15/1440', NEXT_DATE => sysdate, STOP_ON_ERROR => FALSE, DELAY_SECONDS => 60, PARALLELISM => 0); END; / Listing 8.10: Einstellung Job für Übertragung der Transaktionsdaten
In diesem Beispiel wird der Job alle 15 Minuten ausgeführt. Nach Beendigung der Übertragung bleibt er noch 60 Sekunden aktiv (delay_seconds), um auf neue Transaktionen zu warten, bevor er sich schlafen legt. Die Übertragung der Daten wird hier nicht parallelisiert (parallelism => 0). Im Falle eines Fehlers wird die Übertragung nicht abgebrochen, sondern weitergeführt (stop_on_error). Der Job zum Löschen abgearbeiteter Einträge der Transaction Queue wird ebenfalls über den Replikationsadministrator angelegt: CONNECT reptest/geheim@gs_muenchen.ganzbillig
Sandini Bib
574
Verteilte Datenbanktechniken
BEGIN DBMS_DEFER_SYS.SCHEDULE_PURGE( NEXT_DATE => SYSDATE, INTERVAL => '/*1:Hr*/ sysdate + 1/24', DELAY_SECONDS => 0, ROLLBACK_SEGMENT => ''); END; / Listing 8.11: Erstellung Job für Löschen der Einträge
In diesem Beispiel wird die Warteschlange mit sofortiger Wirkung einmal pro Stunde gelöscht. Die Verzögerung von 0 (delay_seconds) bewirkt, dass der Job nach Ausführung der Löschoperation sofort beendet wird. Der Job zum Übertragen administrativer Aufgaben wird beim Anlegen von Replikationsgruppen automatisch erstellt. Auf diese Weise erhält jede Replikationsgruppe ihren eigenen Administrations-Job. Multimaster-Replikation Nachdem die Benutzer, die Jobs und die Datenbank-Links aufgebaut wurden, kann mit dem Anlegen der Replikationsgruppen und replizierten Objekte begonnen werden. Gruppen und Objekte anlegen In unserem Beispiel sind zwei Replikationsgruppen
zu erstellen. Die Master Site, auf der die Gruppe angelegt wird, wird automatisch zur Master Definition Site dieser Gruppe. Mit den folgenden Befehlen wird die erste Gruppe, RG1, auf gs_muenchen.ganzbillig angelegt:
CONNECT reptest/geheim@gs_muenchen.ganzbillig BEGIN DBMS_REPCAT.CREATE_MASTER_REPGROUP ( GNAME => 'RG1' , GROUP_COMMENT => 'Hauptgruppe, enthält die meisten Tabellen' , MASTER_COMMENT => 'Master-Site in München'); end; / Listing 8.12: Erstellung Gruppe RG1
Die neue Gruppe ist nun bereit, die ersten replizierten Objekte aufzunehmen. Alle für diese Gruppe vorgesehenen Tabellen existieren in unserem Beispiel bereits – inklusive Datensätze – im Schema reptest. Der folgende Aufruf wird ebenfalls unter dem Benutzer reptest durchgeführt: BEGIN DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( GNAME => 'RG1'
Sandini Bib
Replikation
575
, TYPE => 'TABLE' , ONAME => 'KUNDEN' , SNAME => 'REPTEST' , USE_EXISTING_OBJECT => TRUE , COPY_ROWS => TRUE); END; / Listing 8.13: Einfügen von Tabellen in die Gruppe RG1
Die Prozedur geht davon aus, dass die betreffende Tabelle kunden auf den anderen Master Sites, hier das noch zu definierende System gs_koeln.ganzbillig, bereits leer angelegt wurde (use_existing_object), dass die Datensätze jedoch online im Zuge der Definition der Master Sites übertragen werden (copy_rows => true). Ist der Schema-Replikationsadministrator – wie in unserem Fall – auch der Eigentümer der zu replizierenden Objekte, kann in diesem Fall problemlos mit use_existing_object => false gearbeitet werden, so dass die betreffenden Objekte beim Aufbau der Master Sites automatisch dort angelegt werden. Gleichermaßen werden die notwendigen sekundären Objekte als replizierte Objekte definiert: im folgenden Beispiel der Index i$kunden_nachname auf dem Attribut Nachname der Tabelle kunden. BEGIN DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( GNAME => 'RG1' , TYPE => 'INDEX' , ONAME => 'I$KUNDEN_NACHNAME' , SNAME => 'REPTEST' , USE_EXISTING_OBJECT => FALSE ); END; / Listing 8.14: Aufbau Index I$KUNDEN_NACHNAME
Es versteht sich, dass die Prozedur create_master_repobject für jedes replizierte Objekt der Replikationsgruppe aufzurufen ist. Gibt es Abhängigkeiten zwischen den Tabellenobjekten einer Gruppe in Form von Fremdschlüsseln (foreign key constraints), sollten die entsprechenden Constraints vor dem Aufruf der Prozedur und dem Hinzufügen weiterer Master Sites ausgeschaltet werden (disable) oder die Objekte vorher manuell – und in der richtigen Reihenfolge – auf allen weiteren Master Sites angelegt werden. Bei selbstbezüglichen oder zirkularen9 Fremdschlüsselbeziehungen ist der vorherige manuelle Aufbau und das Befüllen mit Daten, etwa durch Export und Import, unbedingt notwendig! Die entsprechenden Constraints werden dann nach dem Abschluss der Konfiguration und vor dem Aktivieren der replizierten Umgebung wieder eingeschaltet. Für den Aufbau der replizier-
9.
Tabelle A weist auf Tabelle B und umgekehrt.
Sandini Bib
576
Verteilte Datenbanktechniken
ten Objekte sind in diesem Fall die Parameter copy_rows use_existing_object => true zu setzen.
=>
false
und
Master Sites hinzufügen Sind alle replizierten Objekte angelegt, werden die weite-
ren Master Sites der Gruppe deklariert: BEGIN DBMS_REPCAT.ADD_MASTER_DATABASE ( GNAME=> 'RG1' , MASTER => 'GS_KOELN.GANZBILLIG' , PROPAGATION_MODE => 'ASYNCHRONOUS'); END; Listing 8.15: Hinzufügen einer Master Site
Im vorangehenden Beispiel wird die Gruppe RG1 auf die Master Site gs_koeln.ganzbillig repliziert. Die Prozedur add_master_database ist stets auf der Master Definition Site und dort für jede weitere Master Site auszuführen. Die Übertragung der Transaktionsdaten soll in diesem Beispiel asynchron erfolgen. Alle Prozeduraufrufe, die in diesem Zusammenhang notwendig sind, werden in eine separate Warteschlange gestellt und von dort aus über einen eigenen Job ausgeführt. Der betreffende Job ruft die Prozedur dbms_repcat.do_deferred_repcat_ admin auf. Diese Prozedur führt die Aufrufe der administrativen Warteschlange aus, die über die View dba_repcatlog angezeigt werden können. Nach erfolgreicher Ausführung aller Aktionen ist diese View leer. Bei Fehlern bleiben die Einträge erhalten, die entsprechende Fehlermeldung erscheint in der Spalte Error dieser View. Fehler der Master Sites werden stets an die Master Definition Site zurückgemeldet. Fehlerhafte Einträge müssen explizit über die Prozedur dbms_repcat. purge_master_log entfernt werden. Es empfiehlt sich, den Aufbau großer replizierter Umgebungen in mehrere Arbeitsschritte zu untergliedern und den jeweiligen Folgeschritt erst nach der fehlerfreien Abarbeitung aller vorangehenden Aufrufe zu starten, d.h., erst dann, wenn die oben genannte Warteschlange leer ist. Generierung interner Trigger und Pakete Nachdem alle Master Sites der Gruppe definiert wurden, können nun die internen Trigger und Pakete generiert werden, die für die Übertragung der verzögerten Transaktionen notwendig sind. Diese Generierung ist nur für Tabellen und Pakete notwendig und möglich. Alle anderen replizierten Objekttypen, wie z.B. Indizes, Views, Synonyme usw., werden nur mit ihrer DDL-Definition repliziert. Die Spalte generation_status der View dba_repobject zeigt an, für welche Objekte dies notwendig ist10. Eine erfolgreich abgeschlossene Generierung lässt sich zum einen an der leeren administrativen Warteschlange, zum anderen an den Spalten replication_trigger_exists und internal_package_exists der View dba_repobject – beide mit dem Wert Y – ablesen. Die internen Objekte können nicht – wie dies für PL/SQL-Objekte möglich ist – in ihrem Source Code angezeigt werden. Eine Übersicht über alle internen Pakete liefert darüber hinaus die View dba_repgenobjects. 10. Der Wert NEEDSGEN, wenn die Generierung läuft, dann DOINGGEN.
Sandini Bib
Replikation
577
Im folgenden Beispiel werden für die Tabelle kunden des Schemas reptest die internen Objekte erzeugt: BEGIN DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( SNAME => 'REPTEST' , ONAME => 'KUNDEN' , TYPE => 'TABLE' ); END; / Listing 8.16: Erzeugen der internen Objekte
Aktivierung der Replikationsgruppen und Benutzerbetrieb Im Verlaufe der Gene-
rierung überträgt Oracle auch – sofern dies über den Parameter copy_rows angegeben wurde – die Daten auf die neuen Master Sites. Nach erfolgreichem Abschluss der Generierungsphase stehen die Tabellen bereits für lesende Zugriffe zur Verfügung. Ändernde Zugriffe sind jedoch erst dann möglich, wenn die betreffende Replikationsgruppe vorher über die Master Definition Site, wie Im folgenden Beispiel gezeigt, aktiviert wurde: BEGIN DBMS_REPCAT.RESUME_MASTER_ACTIVITY(GNAME => 'RG1'); END; / Listing 8.17: Aktivieren der Replikation
DML-Aktionen sind danach möglich und werden wie gewohnt durchgeführt: UPDATE kunden SET plz = 5678, ort = 'Musterdorf' WHERE kdnr = 'K5566';
Durch die internen Trigger wird nun ein Paketaufruf generiert und in die Transaktionswarteschlange eingereiht. Diese Warteschlange kann über den Replikationszweig des Enterprise Managers oder über die Views deftran und defcall des Schemas sys angezeigt werden. SELECT deferred_tran_id, delivery_order, destination_list, to_char(start_time,'dd.mm.yy hh24:mi:ss') start_time FROM deftran; DEFERRED_T DELIVERY_ORDER DESTINATION_LIST START_TIME ---------- -------------- -------------------- ----------------3.30.85 356737 R 26.01.02 09:18:46 Listing 8.18: deftran
Sandini Bib
578
Verteilte Datenbanktechniken
Abbildung 8.16: Verzögerte Transaktionen über den Enterprise Manager
Die Identifizierungsnummer der verzögerten Transaktion – hier 3.30.85 – wird gebildet aus der Nummer des Rollback-Segmentes, das die Originaltransaktion verwaltet hat, und der Index- sowie der Versionsnummer des Transaktionseintrags im Header-Block dieses Rollback-Segmentes. Der Zieleintrag R verweist auf die View all_repsites, welche die Übertragungsziele dieser Transaktion bestimmt. Entsprechend lässt sich in unserem Beispiel durch die folgende Abfrage ermitteln, wohin die Übertragung durchgeführt wird: SELECT gname, dblink, masterdef md, master m FROM all_repsites WHERE gname = 'RG1' AND dblink <> dbms_reputil.global_name; GNAME DBLINK MD M ------ ------------------------------ ---- ---RG1 GS_MUENCHEN.GANZBILLIG Y Y Listing 8.19: all_repsites
Alternative Möglichkeiten, diese Abfrage zu realisieren, bestehen über die Views deftrandest und defcalldest. Die einzelnen Prozeduraufrufe jeder verzögerten Transaktion sind über die View Defcall abzufragen. Für Tabellen, die keine LOB-Spalten enthalten, wird pro modi-
Sandini Bib
Replikation
579
fiziertem Datensatz ein Aufruf generiert. Im folgenden Beispiel wurde ein UPDATEBefehl auf der Tabelle Kunden durchgeführt, der einen Datensatz verändert und aus diesem Grunde nur einen Aufruf erzeugt hat: SELECT * FROM defcall; CALLNO DEFERRED_T SCHEMANAME PACKAGENAME PROCNAME ARGCOUNT ------- ---------- ----------- ------------- ---------- -------0 3.30.85 REPTEST KUNDEN$RP REP_UPDATE 15 Listing 8.20: defcall
Bei der Übertragung der Transaktion 3.30.85 wird von gs_koeln.ganzbillig die Paketprozedur kunden$rp.rep_update auf gs_muenchen.ganzbillig aufgerufen, die den entsprechenden Update-Befehl auf dem Zielsystem durchführt. Die inhaltlichen Details der einzelnen Aufrufe lassen sich nicht direkt über Views abfragen, sondern müssen mit Hilfe der Prozeduren des Paketes dbms_defer_query umständlich ermittelt werden. Eine komfortablere Möglichkeit bietet hier der Enterprise Manager, wie die vorangehende Abbildung 8.16 zeigt. Je nachdem, wie der Job zum Löschen der Transaktionswarteschlange konfiguriert wurde, werden Einträge sofort nach der erfolgreichen Übertragung oder mit zeitlicher Verzögerung aus der Warteschlange entfernt. Die Views deftran und defcall können also auch solche Transaktionen anzeigen, die bereits erfolgreich übermittelt wurden. Noch nicht übermittelte Transaktionen und die ihnen zugeordneten Aufrufe finden sich in den Views deftrandest und defcalldest, die für die Filterung von Deftran leicht herangezogen werden können: SELECT deferred_tran_id, delivery_order, destination_list, to_char(start_time,'dd.mm.yy hh24:mi:ss') start_time FROM deftran WHERE deferred_tran_id IN (SELECT deferred_tran_id FROM deftrandest); Listing 8.21: deftran und deftrandest
Konflikterkennung und Konfliktauflösung Auf die Möglichkeit, dass Konflikte bei
asynchronen Übertragungsverfahren auftreten, für den Fall, dass innerhalb eines Synchronisierungsintervalles widersprüchliche Änderungen an identischen Datensätzen durchgeführt werden, wurde bereits hingewiesen. Diese Konflikte werden grundsätzlich von Oracle erkannt. Ob sie automatisch aufgelöst werden oder zu einem Fehler führen, hängt davon ob, ob entsprechende Konfliktlösungsstrategien konfiguriert wurden oder nicht. Im folgenden Beispiel wird für den Kunden M1 die Adresse und der Vorname in München und in Köln geändert. Auf gs_muenchen.ganzbillig wird eingegeben UPDATE kunden SET adresse = 'Musterstrasse 23a' WHERE kdnr = 'M1';
Sandini Bib
580
Verteilte Datenbanktechniken
Auf gs_koeln.ganzbillig wird eingegeben: UPDATE kunden SET vorname = 'Ottochen' WHERE kdnr = 'M1';
Bei der anschließenden Übertragung der Daten, die in unserem Beispiel auf Grund der Jobterminierung zuerst von Köln nach München erfolgt, kommt es zu einem Fehler – no data found –, und die fehlerhafte Transaktion wird auf dem Zielsystem, hier gs_muenchen.ganzbillig, in eine spezielle Fehlerwarteschlange eingereiht. Die Erkennung von Konflikten ist durch den Vergleich der alten Spaltenwerte des Quellsystems mit den aktuellen Spaltenwerten des Zielsystems möglich. In unserem Fall stimmt der alte Wert des Attributes Strasse, Beispielweg 3, nicht mit dem aktuellen Wert, Musterstr. 23a, auf gs_muenchen.ganzbillig überein. Der entstandene Fehler ist in diesem Beispiel doppelt ärgerlich, weil die Änderungen auf unterschiedlichen Attributen des Kunden M1 durchgeführt wurden. Gleichermaßen führt auch die anschließende Übertragung von München nach Köln zu einem Fehler, weil nun der alte Wert des Attributes Vorname, Otto, nicht identisch ist mit dem aktuellen Vornamen Ottochen auf gs_koeln.ganzbillig. Mehr noch: Jede Folgetransaktion die den gleichen Datensatz manipuliert, ganz gleich auf welcher Seite, wird ebenfalls Fehler bei der Übertragung verursachen! Die Aufrufe fehlgeschlagener Transaktionen lassen sich über die View deferror selektieren. Eine grafische Darstellung ist auch in diesem Zusammenhang über den Enterprise Manager möglich und empfehlenswert, da er auch die entsprechenden Argumente anzeigen kann:
Abbildung 8.17: Fehlgeschlagene verzögerte Transaktion über den Enterprise Manager
Sandini Bib
Replikation
581
Fehlgeschlagene verzögerte Transaktionen können nicht ignoriert werden, da sie – wie gezeigt – zu Folgefehlern führen werden. Oberste Priorität hat die Wiederherstellung der Konvergenz der betreffenden Datensätze. Je zügiger diese Konvergenz erreicht wird, desto geringer ist die Zahl der möglichen Folgefehler. Für die Auflösung von fehlgeschlagenen Transaktionen stehen nur manuelle Verfahren zur Verfügung, die äußert zeitaufwändig und komplex werden können, vor allem dann, wenn bereits eine große Zahl von Fehlern aufgelaufen ist. Aus diesem Grunde ist es dringend zu empfehlen, automatisierte Verfahren zur Konfliktauflösung immer dann zu konfigurieren, wenn das Auftreten von Konflikten nicht zu 100 % ausgeschlossen werden kann. Zur Abschreckung sei an dieser Stelle die manuelle Auflösung der oben beschriebenen Fehler kurz skizziert. Im Überblick lassen sich zwei Strategien unterscheiden:
: :
Löschen der entsprechenden Aufrufe der Fehlerwarteschlange und anschließender, manueller, nicht replizierter Abgleich der betreffenden Datensätze, oder Ausräumen des Konfliktpotenzials in den betreffenden Datensätzen und anschließende Ausführung der Aufrufe der Fehlerwarteschlange.
In beiden Fällen ist zunächst ein gründliches Studium der Fehlertransaktionen und eine entsprechende inhaltliche Vorentscheidung notwendig! Bei Anwendung der ersten Strategie wird in unserem Beispiel zunächst die Transaktion 14.45.9 in München aus der Warteschlange gelöscht: BEGIN DBMS_DEFER_SYS.DELETE_ERROR(DEFERRED_TRAN_ID=> '14.45.9', DESTINATION => null); END; / Listing 8.22: Löschen von Transaktionen
Der anschließende Abgleich der Datensätze muss so erfolgen, dass die durchgeführten Änderungen nicht wieder als verzögerte Transaktionen registriert werden und dann zu weiteren Fehlern führen. Der folgende Prozeduraufruf verhindert dies, ohne die Änderungen auf den Tabellen generell zu unterbinden: -- auf gs_muenchen.ganzbillig BEGIN DBMS_REPUTIL.REPLICATION_OFF(); END; / Listing 8.23: Deaktivieren der Replikation für eine Sitzung
Dieser Aufruf aktiviert eine globale Variable, welche die Replikation aller Objekte dieser Sitzung – und nicht mehr – außer Kraft setzt. Andere Benutzer können daher weiterhin Änderungen vornehmen, die auch entsprechend repliziert werden und möglicherweise weitere ungelöste Konflikte produzieren! Die Lösung dieses Problems hängt von der Logik des zugrunde liegenden Geschäftsprozesses und der
Sandini Bib
582
Verteilte Datenbanktechniken
betreffenden Anwendung ab. Mögliche Lösungen können das exklusive Sperren der betreffenden Objekte oder sogar der exklusive Start11 der jeweiligen Instanz sein. In keinem Fall hilft das Herunterfahren der Replikationsgruppe12, da hierbei die Replikationsobjekte überhaupt nicht mehr manipuliert werden können! Im zweiten Schritt findet nun der Abgleich der Daten mit gewohnten SQL-Befehlen statt. In unserem Fall wird der Datensatz des Kunden m1 von Köln in München übernommen: -- auf gs_muenchen.ganzbillig UPDATE kunden k1 SET(vorname,nachname,plz,ort,adresse) = (SELECT vorname,nachname,plz,ort,adresse FROM kunden@gs_koeln.ganzbillig k2 WHERE k2.kdnr=k1.kdnr) WHERE kdnr = 'M1'; Listing 8.24: Manuelles Update
Sind alle Anpassungen manuell durchgeführt worden, kann die Replikation wieder eingeschaltet werden: -- auf gs_muenchen.ganzbillig BEGIN DBMS_REPUTIL.REPLICATION_ON(); end; / Listing 8.25: Reaktivieren der Replikation
Eine Kontrolle des Zustandes kann über die Prozedur replication_is_on des gleichen Paketes durchgeführt werden. Aus dem kleinen Beispiel ist bereits ersichtlich, wie mühsam eine manuelle Konfliktauflösung sein kann. In produktiven Umgebungen, wo sich in kurzer Zeit bereits eine Vielzahl von Folgefehlern einstellen können, potenzieren sich die Aufwände. Aus diesem Grunde ist es dringend notwendig, automatische Konfliktauflösungen überall dort zu konfigurieren, wo UPDATE-, INSERT- oder DELETEOperationen auf mehr als einer Master Site möglich sein können. Konfliktauflösungen arbeiten im Kontext von Spaltengruppen. Spaltengruppen fassen eine oder mehrere Spalten einer replizierten Tabellen zusammen. Pro Spaltengruppe ist eine der enthaltenen Spalten verantwortlich für die Auflösung von Konflikten. Es können durchaus mehrere Spaltengruppen pro Tabelle definiert werden. Jeder Spaltengruppe können eine oder mehrere Konfliktlösungsroutinen zugeordnet werden. Die Routinen einer Spaltengruppe sind hierarchisch angelegt: bei Fehlschlag der ersten wird die zweite angewandt usw. Sind mehrere Spaltengruppen pro Tabelle definiert, kann es vorkommen, dass durch die unterschiedli11. STARTUP RESTRICT ..... 12. dbms_repcat.suspend_master_activity
Sandini Bib
Replikation
583
chen Lösungsroutinen Konflikte innerhalb eines Datensatzes unterschiedlich aufgelöst werden und damit Spalten verschiedener Master „gewinnen“. Bei der Konfiguration von Spaltengruppen ist daher mit größter Vorsicht zu planen, in den meisten Fällen genügt es, pro Tabelle eine Spaltengruppe anzulegen. Die folgende Grafik verdeutlicht diesen auf den ersten Blick verwirrenden Sachverhalt.
7DEHOOH.XQGHQ NGQU
6SDOWHQJUXSSHQ .RQIOLNWO|VXQJHQ
YRUQDPH QDFKQDPH
6* D ODWHVWWLPHVWDPS E VLWHSULRULW\
SO]
RUW
DGUHVVH
6* D 6LWHSULRULW\ E SULRULW\JURXS
Abbildung 8.18: Spaltengruppen und Konfliktlösungsmethoden
In unserem Beispiel sollen Konflikte, die beim Verändern von Kundendaten entstehen, in Abhängigkeit von Zeitstempeln aufgelöst werden. Die aktuellsten Änderungen sollen gewinnen, mit anderen Worten, wir werden im Folgenden die vorkonfigurierte Routine Latest Timestamp konfigurieren. Um dies zu erreichen, ist vorbereitend Folgendes durchzuführen: 1. Die Tabelle kunden muss um eine Date-Spalte erweitert werden. 2. Ein Trigger muss bei Update- und Insert-Operationen dafür sorgen, dass die Date-Spalte mit dem aktuellen Zeitstempel versorgt wird. Da wir uns in diesem Beispiel bereits in einer funktionsfähigen replizierten Umgebung befinden, müssen wir die geplanten Anpassungen so durchführen, dass die anderen Master Sites diese ebenfalls übernehmen und keine Benutzertransaktionen unsere Aktivitäten durchkreuzen. Aus diesem Grunde wird die Replikationsgruppe RG1 zunächst von der Master Definition Site aus heruntergefahren: BEGIN DBMS_REPCAT.SUSPEND_MASTER_ACTIVITY('RG1'); END; / Listing 8.26: Stoppen der Replikation
Das Herunterfahren der Gruppe kann einige Zeit in Anspruch nehmen, vor allem dann, wenn die Transaktionswarteschlange noch Einträge aufweist, die vor dem
Sandini Bib
584
Verteilte Datenbanktechniken
Stoppen abgearbeitet werden müssen. Der Status der Gruppe kann wie folgt kontrolliert werden: SELECT gname, status FROM all_repgroup WHERE gname = 'RG1'; GNAME STATUS ------------------------------ --------RG1 QUIESCED Listing 8.27: QUIESCED-Status
Der Status QUIESCED zeigt in diesem Fall an, das die Gruppe vollständig heruntergefahren wurde und wir nun weiterarbeiten können. Damit die geplante Tabellenänderung auf allen Master Sites zur Anwendung kommt, wird der ALTER TABLE-Befehl über einen Aufruf des Paketes dbms_repcat abgesetzt: BEGIN DBMS_REPCAT.ALTER_MASTER_REPOBJECT ( SNAME => 'REPTEST' , ONAME => 'KUNDEN' , TYPE => 'TABLE' , DDL_TEXT => 'ALTER TABLE kunden ADD(dml_date DATE)' ); END; / Listing 8.28: Änderung eines Replikationsobjekts
Im Anschluss daran darf nicht vergessen werden, die internen Trigger und Prozeduren neu zu generieren: BEGIN DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( SNAME => 'REPTEST' , ONAME => 'KUNDEN' , TYPE => 'TABLE' , MIN_COMMUNICATION => TRUE); END; / Listing 8.29: Generierung der internen Trigger
Als Nächstes wird der Trigger angelegt. Dieser soll bei lokalen INSERT- und UPDATE-Operationen die neue Spalte automatisch mit einem Zeitstempel füllen, jedoch nicht bei Operationen reagieren, die von anderen Mastern stammen, um die originalen Werte des Zeitstempels für die korrekte Konfliktauflösung zu erhalten. Der Trigger wird zunächst wie folgt auf der Master Site definiert:
Sandini Bib
Replikation
585
CREATE OR REPLACE TRIGGER T$KUNDEN_UI_BR BEFORE INSERT OR UPDATE ON KUNDEN FOR EACH ROW begin -- Nur für lokale Operationen IF NOT DBMS_REPUTIL.FROM_REMOTE() THEN :new.dml_date := sysdate; END IF; END; / Listing 8.30: Erstellung eines Triggers für Konfliktbehandlung
Sollten sich die Master Sites in unterschiedlichen Zeitzonen befinden, ist darauf zu achten, dass für die Konfliktlösung eine gemeinsame Zeitzone verwendet wird, d.h., der Trigger ist entsprechend anzupassen! Mit dem folgenden Aufruf wird dieser Trigger auf alle Master Sites der Gruppe übertragen: BEGIN DBMS_REPCAT.CREATE_MASTER_REPOBJECT( GNAME => 'RG1', SNAME => 'REPTEST', ONAME => 'T$KUNDEN_UI_BR', TYPE => 'TRIGGER'); END; / Listing 8.31: Replikation des Triggers
Über die View all_repcatlog kann kontrolliert werden, ob alle administrativen Prozeduraufrufe in diesem Zusammenhang erfolgreich durchgeführt werden konnten. Ist dies der Fall, kann nun die Spaltengruppe definiert werden, die alle Spalten der Tabelle kunden enthalten soll: BEGIN DBMS_REPCAT.MAKE_COLUMN_GROUP ( SNAME => 'REPTEST', ONAME => 'KUNDEN', COLUMN_GROUP => 'KUNDEN_CG1' , LIST_OF_COLUMN_NAMES => 'KDNR,VORNAME,NACHNAME,PLZ,ORT,ADRESSE,DML_DATE'); END; / Listing 8.32: Erstellen einer Spaltengruppe
Spaltengruppen und ihnen zugeordnete Spalten lassen sich über die Views all_repcolumn_group und all_repgrouped_column13 abfragen.
Sandini Bib
586
Verteilte Datenbanktechniken
Im nächsten Schritt wird die Konfliktlösungsroutine im Kontext dieser Spaltengruppe angelegt. In unserem Beispiel wird die Methode Latest Timestamp an erster und einziger Stelle in der Gruppe definiert. In jedem Fall muss die für die Konfliktauflösung verantwortliche Spalte – hier dml_date – angegeben werden: BEGIN DBMS_REPCAT.ADD_UPDATE_RESOLUTION ( sname => 'REPTEST' , oname => 'KUNDEN' , COLUMN_GROUP => 'KUNDEN_CG1' , SEQUENCE_NO => 1 , METHOD => 'LATEST TIMESTAMP' , PARAMETER_COLUMN_NAME => 'DML_DATE'); END; / Listing 8.33: Anlegen Konfliktlösungsroutine
Nicht zu vergessen ist auch hier die Generierung interner Objekte, wie oben bereits angegeben! Auskunft über bereits definierte Methoden und ihre Gruppen gibt die View all_represolution. Sind alle administrativen Aufrufe erfolgreich abgearbeitet, d.h., die View all_repcatlog zeigt keine Einträge mehr, kann die Gruppe RG1 wieder gestartet
und für den DML-Betrieb geöffnet werden: BEGIN DBMS_REPCAT.RESUME_MASTER_ACTIVITY('RG1'); END; / Listing 8.34: Starten der Replikation
Bevor die Tabelle jedoch der Schar der Benutzer wieder zugänglich gemacht wird, sollte – unter Ausschaltung der Replikation mit Hilfe von dbms_reputil.repliction_off – die neue Spalte dml_date pauschal mit dem aktuellen Datum aufgefüllt werden, um einen fehlerfreien Datumsvergleich bei der Konfliktlösung zu gewährleisten. Ein kleiner Test soll abschließend die Leistungsfähigkeit der Konfliktlösung unter Beweis stellen. Für den Kunden m2 wird zunächst in München die Adresse angepasst, dann in Köln der Nachname – wegen einer Heirat – verändert: UPDATE kunden SET nachname = 'Frey-Conrad' WHERE kdnr = 'M2'
Beim nachfolgenden Übertragen der Transaktionsdaten von München nach Köln wird kein Fehler gemeldet. Die Daten von Köln werden jedoch nicht verändert, weil im auftretenden Konflikt Köln wegen des aktuelleren Zeitstempels gewinnt. In München werden ebenfalls die Kölner Daten des Kunden m2 übernommen, 13. Wie immer gibt es auch hier die DBA- und User-Variante.
Sandini Bib
Replikation
587
wodurch in diesem Fall die Adressänderung verloren geht. Dieses Szenario ließe sich perfektionieren, wenn beispielsweise zwei Spaltengruppen mit unterschiedlichen Lösungsroutinen definiert würden, die jeweils die Adress- oder Namensdaten enthalten. Wenn es für den Replikationsadministrator wichtig ist, Informationen über erfolgreich gelöste Konflikte zu erhalten, müssen für die betreffende Tabelle Auflösungsstatistiken aktiviert werden. Die Prozedur muss auf allen Master Sites gestartet werden; die betreffende Replikationsgruppe muss hierzu jedoch nicht gestoppt werden: BEGIN DBMS_REPCAT.REGISTER_STATISTICS(SNAME => 'REPTEST', ONAME => 'KUNDEN'); END; / Listing 8.35: Aktivieren von Konfliktlösungsstatistiken
Statistiken können im Anschluss daran wie folgt auf dem System abgefragt werden, das bei der Konfliktauflösung „verloren“ hat, dessen Daten also überschrieben wurden. In unserem Beispiel ist dies München: SELECT to_char(resolved_date,'dd.mm.yy hh24:mi:ss') resolved_date ,primary_key_value, sname, oname, conflict_type , reference_name FROM all_represolution_statistics; RESOLVED_DATE PRIM SNAME ONAME CONFLICT_TYPE REFERENCE_NAME ------------------ ---- ------- ------ ------------- -------------29.01.02 11:47:20 M2 REPTEST KUNDEN UPDATE KUNDEN_CG1 Listing 8.36: all_represolution_statistics
Zum
Löschen
nicht
mehr
benötigter
Statistiken
steht
die
Prozedur
purge_statistics des Paketes dbms_repcat bereit. Diese Löschoperation sollte auf
jeden Fall in regelmäßigen Abständen durchgeführt werden. Materialized View-Replikation Im folgenden Abschnitt wird nun schrittweise eine Materialized View Site aufgebaut. Exemplarisch wird dies auf der Datenbank mit dem globalen Namen fil20.ganzbillig durchgeführt, deren Materialized Views mit der Münchener Geschäftsstelle, d.h. der Datenbank gs_muenchen.ganzbillig kommunizieren sollen. In unserem Beispiel sollen alle Kunden aus dem Postleitzahlbereich 8 und die für sie erfassten Aufträge – hier nur die Kopfdaten – repliziert werden. Um die Übertragung der Daten zu beschleunigen, wird eine „schnelle“ Aktualisierung über Materialized View Logs geplant. Vorbereitung der Master Site Die Replikationsgruppe auf der Master Site wurde
bereits im vorangehenden Abschnitt angelegt und konfiguriert, d.h., die genannten Tabellen sind bereits als replizierte Objekte Bestandteil der Replikationsgruppe rg1. Für die schnelle Aktualisierung der Materialized Views von fil20.ganzbillig
Sandini Bib
588
Verteilte Datenbanktechniken
sind nun entsprechende Logs auf der Master Site anzulegen. Im folgenden Beispiel wird dieses Log zunächst für die Tabelle kunden erzeugt: CREATE MATERIALIZED VIEW LOG ON reptest.kunden TABLESPACE users WITH PRIMARY KEY EXCLUDING NEW VALUES; Listing 8.37: Erstellung eines Materialized View Logs
Dieser Befehl erzeugt einen internen Trigger für kunden sowie die Hilfstabellen mlog$kunden und rupd$kunden, welche die ändernden Operationen anhand des Primärschlüssels kdnr protokollieren. Die Tabelle auftraege verlangt eine gesonderte Behandlung, da die für die Replikation verantwortliche Spalte plz nur über die abhängige Tabelle kunden abrufbar ist. Die Materialized View auftraege wird daher später über eine geeignete Unterabfrage zu realisieren sein: SELECT * FROM auftraege a WHERE EXISTS (SELECT 1 FROM kunden k WHERE a.kdnr = k.kdnr AND substr(k.plz,1,1) = 314 ) / Listing 8.38: Materialized View auftraege
Um für diese Abfrage eine „schnelle“ Aktualisierung zu ermöglichen, ist es notwendig, die in der Unterabfrage zusätzlich zum Primärschlüssel referenzierten Spalten – hier plz – als so genannte Filterspalten zusätzlich in das Materialized View Log von kunden aufzunehmen: ALTER MATERIALIZED VIEW LOG ON kunden ADD(plz);
Darüber hinaus ist natürlich auch ein Log für die Tabelle auftraege anzulegen: CREATE MATERIALIZED VIEW LOG ON auftraege; Vorbereitung der Materialized View Site Die vorbereitenden Aktivitäten der Mate-
rialized View Site sind denen der Master Site sehr ähnlich. Auch hier müssen die genannten Systemparameter kontrolliert und der globale Name eingestellt werden. Ebenso ist für die Administration der Materialized Views ein Administrator anzulegen und zu privilegieren, in unserem Beispiel sei dies snapadmin: BEGIN DBMS_REPCAT_ADMIN.GRANT_ADMIN_ANY_SCHEMA (USERNAME => 'SNAPADMIN'); END; / Listing 8.39: Replikationsadministrator 14. Hier wird der Einfachheit halber vorausgesetzt, dass PLZ immer numerisch beginnt, also niemals D-12345 etc. enthält.
Sandini Bib
Replikation
589
Soll snapadmin auch in der Lage sein, Verwaltungswerkzeuge wie den Enterprise Manager aufzurufen und im Rahmen seiner Privilegien zu nutzen, ist ihm ein zusätzliches Systemprivileg zum Lesen des Data Dictionary zu erteilen: GRANT SELECT ANY DICTIONARY TO snapadmin;
Es ist jedoch in vielen Fällen einfacher und weniger fehleranfällig, Materialized View-Objekte über entsprechende Scripts aufzubauen – wie im Folgenden gezeigt wird – und den Enterprise Manager nur für Aufgaben des Monitoring einzusetzen. Sicherheitsmodell In vielen Fällen ist es empfehlenswert, die Aktualisierungen
und die Übertragung der verzögerten Transaktionen nicht über einen globalen Administrator abzuwickeln, sondern hierfür separate Benutzer mit genau dosierten Privilegien aufzubauen. Auf diese Weise hat die Materialized View Site nur Zugriff auf die für sie relevanten Objekte der Master Site und nicht auf alle, die in der entsprechenden Replikationsgruppe auf dem Master definiert wurden. Der Aufbau dieses abgesicherten Kommunikationsmodells (untrusted security) wird in den folgenden Abschnitten beschrieben. Der erste Schritt in dieser Richtung ist der Aufbau des Propagator-Benutzers, über dessen Schema die verzögerten Transaktionen auf den Master geschickt werden. Dieser Benutzer wird wie folgt privilegisiert: BEGIN DBMS_DEFER_SYS.REGISTER_PROPAGATOR (USERNAME => 'SNAPPROP'); END; / Listing 8.40: Propagator
Sowohl der Materialized View Administrator als auch der Propagator benötigen auf der Master Site Kommunikationspartner, deren Privilegien wohl dosiert werden sollten. Dem entsprechend wird auf der Master Site als Erstes der Benutzer proxy_snapadmin angelegt und privilegisiert. Mit dem nachfolgenden Aufruf werden auch alle notwenigen Objektprivilegien im Kontext einer Replikationsgruppe zugeteilt, in unserem Fall sind dies Select-Rechte auf den Tabellen kunden und auftraege des Benutzers reptest: BEGIN DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP( username => 'PROXY_SNAPADMIN', privilege_type => 'proxy_snapadmin', list_of_gnames => 'RG1'); END; / Listing 8.41: proxy_snapadmin
Da der Benutzer snapadmin der Materialized View Site mit proxy_snapadmin der Master Site kommuniziert, wird der entsprechende private Datenbank-Link aufgebaut, der den gleichnamigen Public Link mit einer using-Klausel voraussetzt:
Sandini Bib
590
Verteilte Datenbanktechniken
CREATE DATABASE LINK gs_muenchen.ganzbillig CONNECT TO proxy_snapadmin IDENTIFIED BY geheim; Listing 8.42: Database Link für proxy_snapadmin
Ebenso wird der Benutzer proxy_receiver auf der Master Site aufgebaut, der mit dem Propagator der Materialized View Site kommuniziert. Der folgende Aufruf vergibt entsprechende Execute-Rechte auf den internen Paketen der replizierten Tabellen der betreffenden Replikationsgruppe. BEGIN DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP( username => 'PROXY_RECEIVER', privilege_type => 'receiver', list_of_gnames => 'RG1'); END; / Listing 8.43: proxy_receiver
Für die Kommunikation ist der Datenbank-Link von dem Propagator auf der Materialized View Site zu proxy_receiver auf Master Site aufzubauen: CREATE DATABASE LINK gs_muenchen.ganzbillig CONNECT TO proxy_receiver IDENTIFIED BY geheim; Listing 8.44: Database Link für proxy_receiver
Schließlich wird auf der Master Site der Benutzer proxy_refresher erzeugt, der mit dem Eigentümer der Materialized Views während der Aktualisierungen kommuniziert. Dieser Benutzer benötigt neben den Select-Privilegien auf den Master-Tabellen auch noch entsprechende Privilegien auf den Materialized View Logs, sofern, wie in unserem Beispiel, mit „schnellen“ Aktualisierungen gearbeitet wird. GRANT CREATE SESSION TO proxy_refresher; -- als Objekt-Owner GRANT SELECT ON kunden TO proxy_refresher; GRANT SELECT ON auftraege TO proxy_refresher; GRANT SELECT ON mlog$kunden TO proxy_refresher; GRANT SELECT ON mlog$auftraege TO proxy_refresher; Listing 8.45: Rechtevergabe an proxy_refresher
Der private Datenbank-Link von dem Besitzer der Materialized Views zu proxy_refresher der Master Site darf keinesfalls vergessen werden: CREATE DATABASE LINK gs_muenchen.ganzbillig CONNECT TO proxy_refresher INDENTIFIED BY geheim; Listing 8.46: Database Link für proxy_refresher
Sandini Bib
Replikation
591
Hiermit sind die Einstellungen der Vertrauensstellung abgeschlossen. Die nachfolgende Grafik fasst die Kommunikationspartner und ihre Datenbank-Links noch einmal zusammen.
! Abbildung 8.19: Datenbank-Links im Umfeld von Materialized Views
Job-System Analog zur Master Site sind nun als nächstes Jobs auf der Materialized View Site unter dem Benutzer snapadmin anzulegen. -- Stündliches Löschen abgearbeiteter verzögerter Transaktionen BEGIN DBMS_DEFER_SYS.SCHEDULE_PURGE ( next_date => SYSDATE, interval => 'SYSDATE + 1/24', delay_seconds => 0, rollback_segment => ''); END; / -- Stündliche Übertragung verzögerter Transaktionen BEGIN DBMS_DEFER_SYS.SCHEDULE_PUSH ( destination => 'GS_MUENCHEN.GANZBILLIG', interval => 'SYSDATE + 1/24', next_date => SYSDATE, stop_on_error => FALSE, delay_seconds => 0, parallelism => 0); END; / Listing 8.47: Erstellung der Jobs
Sandini Bib
592
Verteilte Datenbanktechniken
Damit sind alle Vorbereitungen auf Seiten der Materialized View Site abgeschlossen. Aufbau der Materialized Views Nachdem die notwendigen Benutzer, DatenbankLinks und das Job-System konfiguriert wurden, können nun die Materialized Views – in unserem Beispiel kunden und auftraege – angelegt werden. Auch hier sollte die Arbeit mit Hilfe von Scripts und nicht über den Enterprise Manager erfolgen, vor allem dann nicht, wenn auf Seiten der Master Site ein Schema-Replikationsadministrator anstelle eines globalen Administrators konfiguriert wurde.
Es ist wichtig, die Materialized Views unter dem gleichen Schema wie die entsprechenden Master-Tabellen anzulegen, in unserem Beispiel ist dies das Schema reptest. Dem Benutzer müssen u.a. die Systemprivilegien create database link, create snapshot und alter any snapshot zugeteilt werden. Darüber hinaus benötigt er – wie bereits erwähnt – einen Datenbank-Link zum proxy_refresher der Master Site. Im nächsten Schritt kann dann eine leere Materialized View-Gruppe angelegt werden, die den Namen nach mit der Replikationsgruppe des Masters übereinstimmen muss. In unserem Beispiel wird darüber hinaus der asynchrone Modus zum Übertragen lokaler Änderungen an den Master eingestellt: BEGIN DBMS_REPCAT.CREATE_MVIEW_REPGROUP ( gname => 'RG1', master => 'GS_MUENCHEN.GANZBILLIG', propagation_mode => 'ASYNCHRONOUS'); END; / Listing 8.48: Anlegen einer Materialized View-Gruppe
Danach geht es an den Aufbau einer leeren Aktualisierungsgruppe, damit alle Materialized Views in einem Zug konsistent aktualisiert werden können. Die Gruppe soll stündlich aktualisiert werden, vor ihrer Aktualisierung alle anstehenden verzögerten Transaktionen auf den Master übertragen (push_deferred_rpc) und bei Auftreten eines Fehlers gestoppt werden: BEGIN DBMS_REFRESH.MAKE ( name => 'SNAPADMIN.FIL20MV1', list => '', next_date => SYSDATE, interval => 'SYSDATE + 1/24', implicit_destroy => FALSE, rollback_seg => '', push_deferred_rpc => TRUE, refresh_after_errors => FALSE); END; / Listing 8.49: Erstellung einer Refresh-Gruppe
Sandini Bib
Replikation
593
Im nächsten Schritt können nun die Materialized Views wie geplant unter dem Schema reptest angelegt werden: CREATE MATERIALIZED VIEW reptest.kunden REFRESH FAST WITH PRIMARY KEY FOR UPDATE AS SELECT * FROM reptest.kunden@gs_muenchen.ganzbillig where substr(plz,1,1) = 3; CREATE MATERIALIZED VIEW reptest.auftraege REFRESH FAST WITH PRIMARY KEY FOR UPDATE AS SELECT * FROM reptest.auftraege@gs_muenchen.ganzbillig a where exists (select 1 from reptest.kunden@gs_muenchen.ganzbillig k where k.kdnr = a.kdnr and substr(k.plz,1,1) = 3); Listing 8.50: Erstellung der Materialized Views
Diese Views müssen nun der bereits angelegten Materialized View-Gruppe hinzugefügt werden. Diese Aktion wird wieder unter dem Benutzer snapadmin ausgeführt: BEGIN DBMS_REPCAT.CREATE_MVIEW_REPOBJECT ( gname => 'RG1', sname => 'REPTEST', oname => 'KUNDEN', type => 'SNAPSHOT', min_communication => TRUE); DBMS_REPCAT.CREATE_MVIEW_REPOBJECT ( gname => 'RG1', sname => 'REPTEST', oname => 'AUFTRAEGE', type => 'SNAPSHOT', min_communication => TRUE); END; / Listing 8.51: Hinzufügen der Views zur Gruppe
Unter dem gleichen Benutzer werden die Objekte nun der Aktualisierungsgruppe hinzugefügt: BEGIN DBMS_REFRESH.ADD ( name => 'SNAPADMIN.FIL20MV1', list => 'REPTEST.KUNDEN,REPTEST.AUFTRAEGE', lax => TRUE); END; / Listing 8.52: Hinzufügen der Objekte zur Refresh-Gruppe
Sandini Bib
594
Verteilte Datenbanktechniken
Da wir in diesem Beispiel mit veränderbaren Materialized Views arbeiten, muss dafür gesorgt werden, dass interne Trigger und Log-Tabellen für die Aufzeichnung der verzögerten Transaktionen zur Verfügung stehen. Dies erledigt der folgende Aufruf auf der Materialized View Site: BEGIN DBMS_REPCAT.GENERATE_MVIEW_SUPPORT( sname => 'REPTEST', oname => 'KUNDEN', type => 'SNAPSHOT', generate_80_compatible => FALSE); DBMS_REPCAT.GENERATE_MVIEW_SUPPORT( sname => 'REPTEST', oname => 'AUFTRAEGE', type => 'SNAPSHOT', generate_80_compatible => FALSE); END; / Listing 8.53: Erstellen von Protokolltabellen generate_mview_support erstellt zusätzlich zu den internen Triggern die beiden Hilfstabellen uslog$_kunden und uslog$_auftraege, die lokale Transaktionen auf der Materialized View Site protokollieren und auf diese Weise verhindern, dass lokale Änderungen bei Aktualisierungen noch einmal auf die Materialized View Site rückübertragen werden.
Da die Materialized Views veränderbar sind, muss mit Konflikten gerechnet werden. Konflikte, die im Kontext von Materialized Views auftreten, werden über die Konfliktlösungsroutinen des betreffenden Masters gelöst. Da diese bereits für die Tabelle kunden auf gs_muenchen.ganzbillig generiert wurden, genügt es nun, die für die Konfliktauflösung definierte Spalte dml_date auf Seiten der Materialized View mit einem Trigger zu versorgen. Analog der Lösung auf der Master Site soll dieser Trigger nur bei lokalen Transaktionen und nicht bei Refresh-Operationen zünden. Der Trigger ist wie folgt aufzusetzen: CREATE OR REPLACE TRIGGER "REPTEST"."T$KUNDEN_UI_BR" BEFORE INSERT OR UPDATE ON "KUNDEN" FOR EACH ROW begin -- Nicht bei Refreh-Operationen zünden IF NOT dbms_mview.i_am_a_refresh() THEN :new.dml_date := sysdate; END IF; END; / Listing 8.54: Konfliktlösung
Sandini Bib
Replikation
595
Die Materialized View-Umgebung ist nun vollständig konfiguriert und bereit für Benutzertransaktionen. Für den Kunden m1 wird beispielsweise die Adresse entsprechend angepasst: UPDATE kunden SET ADRESSE = 'Testweg 25' WHERE kdnr = 'M1';
Diese Transaktion verursacht einerseits einen Eintrag in der Hilfstabelle uslog$_kunden, andererseits einen Paketaufruf in der Transaktionswarteschlange. Über den Trigger wird darüber hinaus die Spalte dml_Date mit dem aktuellen Zeitstempel gefüllt. Findet auf der Master Site vor der nächsten Synchronisation ebenfalls eine Änderung der Kundendaten von m1 statt, beispielsweise die Änderung des Nachnamens, sorgt die Konfliktauflösung dafür, dass die Version mit dem aktuellsten Zeitstempel gewinnt. Gewinnen die Daten des Masters, werden bei der nächsten Aktualisierung auch die Daten der Materialized View Site an den Stand des Masters angepasst und die lokal durchgeführten Änderung möglicherweise wieder überschrieben. Für die Kontrolle und Beobachtung von Materialized Views stehen eine Reihe von Views in ALL-, USER- und DBA-Varianten zur Verfügung, die wichtigsten von ihnen sind:
: : :
dba_refresh und dba_refresh_children listen Aktualisierungsgruppen und
ihre Objekte. dba_mview_logs und dba_mview_log_filter_cols geben Auskunft über Materialized View Logs und ihre Filterspalten. dba_mviews zeigt Materialized Views an.
8.2.5
Administration
In den vorangehenden Abschnitten wurde der Aufbau einer replizierten Umgebung besprochen. Neben einer sorgfältigen Planung und Installation gehören zum produktiven Betrieb von replizierten Umgebungen jedoch auch tägliche Routineaufgaben, um die Funktionsfähigkeit der Umgebung sicherzustellen. Zu diesen Routineaufgaben lassen sich das Monitoring der Transaktionswarteschlange und der Datenbankjobs genauso zählen, wie die Behandlung auftretender Fehler oder die Anpassung der Replikationsgruppen, etwa durch Hinzufügen neuer Master Sites oder neuer replizierter Objekte. Die folgenden Abschnitte geben einen kurzen Überblick über die wichtigsten dieser Aufgaben. Monitoring Jobverwaltung Verzögerte Transaktionen, administrative Aufrufe und Löschoperationen der Warteschlange werden – wie oben dargestellt wurde – über entsprechende Datenbankjobs realisiert. Der Beobachtung dieser Jobs kommt daher eine hohe Priorität zu. Die folgende Abfrage gibt Auskunft über die Ausführungszeiten, Fehlschläge (failures) und den Zustand (broken) aller Jobs einer Datenbank:
Sandini Bib
596
Verteilte Datenbanktechniken
SELECT job, broken, failures , last_date, last_sec, next_date ,next_sec FROM dba_jobs; JOB ---------6 7 64
B FAILURES LAST_DATE LAST_SEC NEXT_DATE - ---------- --------- -------- --------N 0 18-FEB-02 09:09:58 18-FEB-02 N 0 18-FEB-02 09:40:06 18-FEB-02 N 3 18-FEB-02 09:09:57 18-FEB-02
NEXT_SEC -------10:09:58 09:50:06 10:09:57
Listing 8.55: dba_jobs
Zusätzlich ließe sich hier auch die Spalte what selektieren, die Auskunft über die Prozedur des betreffenden Jobs gibt. Jeder Job läuft im Schemakontext seines jeweiligen „Eigentümers“, in unserem Beispiel snapadmin: SELECT job, log_user, priv_user, schema_user FROM DBA_JOBS; JOB ---------6 7 63
LOG_USER --------------SNAPADMIN SNAPADMIN SNAPADMIN
PRIV_USER --------------SNAPADMIN SNAPADMIN SNAPADMIN
SCHEMA_USER --------------SNAPADMIN SNAPADMIN SNAPADMIN
Listing 8.56: dba_jobs Eigentümer
In unserem Beispiel hat der Job mit der Nummer 64 drei Fehlschläge zu verzeichnen. Ungeachtet dieser Fehler ist er jedoch immer noch aktiv, was an der Spalte broken = N zu erkennen ist. Auf jeden Fall muss Jobfehlern nachgegangen werden, um dem „Brechen“ von Jobs, das nach 16 Fehlschlägen in Folge durchgeführt wird und zu „Staus“ in der Warteschlange führt, vorzubeugen. Die Ursache von Jobfehlern und die mit ihnen verbundenen Fehlermeldungen können nur aus den entsprechenden Trace-Dateien abgelesen werden. Die TraceDateien der Jobprozesse wie auch die Alert-Datei der Datenbank befinden sich in dem über den Systemparameter background_dump_dest bestimmten Verzeichnis auf Seiten des Datenbankservers. Ein erster Hinweis auf den Fehler findet sich in der Alert-Datei, die ihrerseits auf die Trace-Datei des betreffenden Jobprozesses verweist. Diese enthält weitergehende Informationen. Im Folgenden findet sich ein Ausschnitt aus einer Alert-Datei: Errors in file /opt/oracle/admin/o9rep/bdump/j000_1049.trc: ORA-12012: error on auto execute of job 64 ORA-23324: error ORA-02068: following severe error from GS_MUENCHEN ORA-01034: ORACLE not available ORA-27101: shared memory realm does not exist
Im oben stehenden Fall ist die Interpretation des Fehlers einfach und erfordert keinen Zugriff auf die referenzierte Datei J000_1049.trc: Die Datenbank gs_muenchen war zum Zeitpunkt der Ausführung des Jobs nicht gestartet.
Sandini Bib
Replikation
597
Ist ein Job einmal „gebrochen“ – broken = Y – muss er explizit, nach Behebung des Fehlers, wieder entsperrt werden: BEGIN DBMS_JOB.BROKEN( job => 36, broken => false , next_date => sysdate + 1/24); END; / Listing 8.57: Entsperren eines Jobs
Im obigen Beispiel wird der Job 36 aktiviert. Er soll der erste Mal eine Stunde nach seiner Aktivierung ausgeführt werden. Wird next_date nicht angegeben, startet der Job unmittelbar nach seiner Aktivierung, was in manchen Fällen unerwünscht sein kann. Es versteht sich, dass mit dem Neustart und der erfolgreichen Ausführung auch die Spalte failures wieder auf null gestellt wird. Grundsätzlich können Datenbankjobs nur von ihren „Eigentümern“ – in diesem Fall snapadmin – administriert werden, auch sys hat hier keine Chance und wird mit einer wenig hilfreichen Fehlermeldung abgespeist: * ERROR at line 1: ORA-23421: job number 64 is not a job in the job queue ORA-06512: at "SYS.DBMS_SYS_ERROR", line 86
Leider gibt es auch unter Oracle9i kein Systemprivileg, das einem Benutzer die Administration eines „fremden“ Jobs erlauben würde. Transaktionen Verzögerte Transaktionen, die von Benutzern im Kontext replizierter Objekte ausgelöst werden, werden in den Tabellen def$_aqcall und def$_lob15 im Schema system gespeichert. Bei umfangreichem Transaktionsaufkommen oder bei Fehlern, die nicht rechtzeitig aufgelöst werden können und dadurch die Warteschlange „verstopfen“, sollten diese Tabellen unbedingt hinsichtlich ihres Speicheraufkommens beobachtet werden. SELECT sum(dbms_lob.getlength(user_data)+100) FROM system.def$_aqcall;
Das vorangehende Beispiel kalkuliert die Datenmenge der maßgeblichen LobSpalte user_data und addiert für alle anderen Spalten pauschal 100 Byte pro Datensatz. Für exakte Kalkulationen sind entsprechende VSIZE-Funktionen in das SQL-Kommando zu integrieren. Wer generelle Statistiken über verzögerte Transaktionen wünscht, kann diese über die View v$replqueue erhalten. Die hier ausgegebenen Zahlen gelten ab dem letzten Start der Instanz:
15. Def$_Lob ist nur beteiligt, wenn das replizierte Objekt LOBs enthält.
Sandini Bib
598
Verteilte Datenbanktechniken
SELECT txns_enqueued, calls_enqueued, txns_purged , to_char(last_enqueue_time, 'dd.mm.yyhh24:mi:ss') last_enqueue_time , to_char(last_purge_time, 'dd.mm.yy hh24:mi:ss') last_purge_time FROM v$replqueue; TXNS_ENQUEUED CALLS_ENQUEUED TXNS_PURGED LAST_ENQUEUE_TIME LAST_PURGE_TIME ------------- -------------- ----------- ----------------- ----------------4 5 1 18.02.02 12:18:28 18.02.02 11:18:25 Listing 8.58: v$replqueue
Die View v$replqueue ist darüber hinaus für eine ganze Reihe weiterer Statistiken gut. Die folgende Abfrage gibt die durchschnittliche Anzahl verzögerter Transaktion pro Sekunde seit dem Start der Instanz aus: SELECT (r.txns_enqueued / ((SYSDATE - i.startup_time)*24*60*60)) "Average TPS" FROM v$replqueue r, v$instance i;
Diese Statistik ist sehr gut als globaler Indikator für die „Last“ im Zusammenhang mit der replizierten Umgebung zu gebrauchen. Fehler, die im Kontext von verzögerten Benutzertransaktionen aufgetreten sind, können über die View deferror auf der Zielseite abgerufen werden. Um Folgefehler und damit einhergehende umfangreiche Transaktionsaufrufe zu vermeiden, ist eine schnelle Reaktion und die Behebung der jeweiligen Ursachen dringend anzuraten. Sind die Fehler beseitigt, können die Transaktionen – entweder einzeln oder pauschal – aus der Fehlerwarteschlange heraus erneut aufgerufen werden. Im folgenden Beispiel werden alle fehlerhaften Transaktionen für die Geschäftsstelle München erneut ausgeführt: BEGIN DBMS_DEFER_SYS.EXECUTE_ERROR(deferred_tran_id => null, destination => 'GS_MUENCHEN.GANZBILLIG'); END; / Listing 8.59: Explizite Ausführung fehlerhafter Transaktionen
Ist die Auflösung des Fehlers nicht möglich oder nicht wünschenswert, muss die Transaktion über die Prozedur dbms_defer_sys.delete_error aus der Fehlerwarteschlange gelöscht werden. Sich daraus ergebende Divergenzen mit anderen Master Sites liegen in der Verantwortung des Administrators und können u.U. zu unliebsamen Folgefehlern führen. Netzverkehr Den durchschnittlichen Netzverkehr pro verzögerter Transaktion gibt
die folgende Abfrage für die Verbindungen nach München aus: SELECT DECODE(total_txn_count, 0, 'No Transactions' ,((total_bytes_sent + total_bytes_received) / total_txn_count)) "Average Bytes" ,DECODE(total_txn_count, 0, 'No Transactions' ,(total_round_trips/ total_txn_count)) "Average Round Trips"
Sandini Bib
Replikation
599
FROM defschedule WHERE dblink = 'GS_MUENCHEN.GANZBILLIG'; Listing 8.60: defschedule
Alle Statistiken, die über die View defschedule ausgegeben werden, lassen sich bei Bedarf, beispielsweise vor der Durchführung von Performance-Tests, zurücksetzen: BEGIN DBMS_DEFER_SYS.CLEAR_PROP_STATISTICS ( dblink => 'GS_MUENCHEN.GANZBILLIG'); END; / Listing 8.61: Zurücksetzen von Statistiken
Performance Prozedurale Replikation Standardmäßig wird die Replikation von Tabellen auf Zeilenbasis durchgeführt (row level replication). Dies bedeutet, dass für jede geänderte Tabellenzeile ein entsprechender entfernter Prozeduraufruf in die Transaktionswarteschlange gestellt wird. Bei umfangreichen Transaktionen, die im Kontext von Batch-Programmen ausgeführt werden, kann dies zu erheblichen Performance-Einbussen und einer entsprechend „aufgeblähten“ def$_aqcallTabelle führen. In diesen Fällen empfiehlt sich der Einsatz der prozeduralen Replikation (procedural replication). Hierbei werden die DML-Aktionen über entsprechende Paketprozeduren ausgeführt. Die Pakete werden als replizierte Objekte deklariert und die Replikationsunterstützung entsprechend generiert. Auf diese Weise entstehen so genannte Wrapper-Prozeduren, die – anstelle der ursprünglichen Prozedur aufgerufen – dafür sorgen, dass der Aufruf sowohl lokal als auch auf allen beteiligten Master Sites ausgeführt wird. Die Transaktionswarteschlange enthält auf diese Weise nur den entsprechenden Prozeduraufruf. Die prozedurale Replikation kann parallel zu der Replikation auf Zeilenbasis eingesetzt werden. Es ist jedoch darauf zu achten, dass Daten, die über die prozedurale Methode repliziert werden, nicht noch einmal über die Zeilenreplikation in die Transaktionswarteschlange gelangen. Dies wird durch den folgenden Aufruf erreicht, der entsprechend in die Prozeduren zu integrieren ist: .... dbms_reputil.replication_off; -- Prozedur-code dbms_reputil.replication_on; ....
Des Weiteren stehen die vorkonfigurierten Konfliktlösungsmethoden nicht für die prozedurale Methode zur Verfügung. Im Bedarfsfall muss der Benutzer daher eigene Algorithmen in die Paketprozeduren integrieren. Minimierung der Transaktionsdaten Neben der im vorangehenden Abschnitt erwähnten prozeduralen Replikation stehen weitere Verfahren zur Verfügung, um das Volumen von verzögerten Transaktionen zu minimieren und damit die Performance beim Replizieren zu steigern. Verzögerte Transaktionen speichern im
Sandini Bib
600
Verteilte Datenbanktechniken
schlimmsten Falle alle alten und neuen Spaltenwerte aller Spalten jedes modifizierten Datensatzes. Dies geschieht, um mögliche Konflikte erkennen zu können, führt aber in den meisten Fällen zu einem unnötig großen Aufkommen von Transaktionsdaten. Dieses Datenvolumen lässt sich nun durch zwei aufeinander aufbauende Methoden systematisch minimieren. Das erste Verfahren sorgt dafür, dass Altdaten nur für den Primärschlüssel und alle Spalten der modifizierten Spaltengruppe übertragen werden. Darüber hinaus werden Neudaten natürlich für alle geänderten Spalten gespeichert. Eine geschickte Aufteilung der Spaltengruppen kann hier wesentliche Vorteile bringen. Das genannte Verfahren wird über den Parameter min_communication der Prozedur generate_replication_support des Paketes dbms_repcat aktiviert. Der Parameter ist standardmäßig auf true eingestellt und sollte nur zurückgenommen werden, falls die Replikation auch im Kontext von Oracle7 arbeiten muss.
:5/,90
6* $OWZHUWH 1HXZHUWH
6*
Abbildung 8.20: Wirkungsweise des Parameters min_communication
Die vorangestellte Grafik zeigt die Änderung der Spalte nachname der Tabelle kunden und die durch diese Änderung anfallenden Alt- und Neudatenvolumen. Wird min_communication eingesetzt, kann darüber hinaus ein weiteres Verfahren eingeschaltet werden, mit dessen Hilfe für jede Spalte explizit festgesetzt werden kann, ob alte Werte übertragen und auf der Gegenseite verglichen werden sollen. Auf diese Weise können – neben dem Primärschlüssel – nur die Spalten mit ihren Altdaten übertragen werden, die für die Erkennung und Auflösung von Konflikten relevant sind. Im folgenden Beispiel wird für die Tabelle kunden auf gs_muenchen.ganzbillig so konfiguriert, dass im Falle einer UPDATE-Operation nur die Altdaten des Primärschlüssels und der Zeitstempel-Spalte dml_date übertragen und verglichen werden:
Sandini Bib
Replikation
601
BEGIN DBMS_REPCAT.SEND_OLD_VALUES( sname => 'REPTEST', oname => 'KUNDEN', column_list => 'VORNAME,NACHNAME,PLZ,ORT,ADRESSE', operation => 'UPDATE', send => FALSE ); END; / BEGIN DBMS_REPCAT.SEND_OLD_VALUES( sname => 'REPTEST', oname => 'KUNDEN', column_list => 'KDNR,DML_DATE', operation => 'UPDATE', send => TRUE ); END; / BEGIN DBMS_REPCAT.COMPARE_OLD_VALUES( sname => 'REPTEST', oname => 'KUNDEN', column_list => 'VORNAME,NACHNAME,PLZ,ORT,ADRESSE', operation => 'UPDATE', compare => FALSE ); END; / BEGIN DBMS_REPCAT.compare_OLD_VALUES( sname => 'REPTEST', oname => 'KUNDEN', column_list => 'KDNR,DML_DATE', operation => 'UPDATE', compare => TRUE ); END; / Listing 8.62: Minimierung der Transaktionsdaten
Die Aktion erfordert ein Herunterfahren der Replikationsgruppe. Im Anschluss an die Änderung ist der Support für die Replikation neu zu generieren. Die durchgeführten Einstellungen können über die View all_repcolumn oder ihre Namensvetter kontrolliert werden. Offline-Instantiation In Umgebungen mit „großen“ replizierten Tabellen kommt der Urladung der Objekte eine entscheidende Bedeutung zu. Das Standardverfahren copy_rows => true, bei dem die Daten im Zuge der Konfigurationsprozeduren übertragen werden, führt in diesen Umgebungen zu unvertretbaren Laufzeiten.
Sandini Bib
602
Verteilte Datenbanktechniken
Hier ist es empfehlenswert, die Tabellen vorher auf allen Master Sites explizit anzulegen und über geeignete Verfahren, wie z.B. Export und Import zu füllen. Bei der Konfiguration der replizierten Umgebung wird dann über die Parameter copy_rows => false und use_existing_object16 => true dafür gesorgt, dass die Struktur der Objekte verglichen wird, die Datenübertragung aber nicht mehr stattfindet. Der Administrator trägt damit natürlich die Verantwortung für die Konsistenz. Das oben geschilderte Verfahren ist gut für die Erstkonfiguration einer replizierten Umgebung. Wird jedoch eine bereits produktive Replikationsgruppe durch eine neue Master Site erweitert, werden standardmäßig Copy_Rows-Verfahren mit den entsprechenden Performance-Einbussen eingesetzt. Alternativ ist in diesem Kontext die so genannte Offline Instantiation zu empfehlen, bei welcher der neue Master „extern“ initialisiert werden kann. Das Verfahren wird zum großen Teil über das Paket dbms_offline_og realisiert. Ein großer Vorteil dieses Verfahrens gegenüber der standardisierten Ladung ist die relativ kurze Zeit, während der die Replikationsgruppe heruntergefahren werden muss. Folgendes Vorgehen ist für die Offline-Instantiation im Detail notwendig: 1. Grundinstallation der neuen Master Site durch den Aufbau der notwendigen Schemabenutzer, Datenbank-Links und Privilegien. 2. Herunterfahren der betreffenden Replikationsgruppe auf der Master Definition Site. 3. Beginn
der
Offline
Instantiation
durch
die
Prozedur
dbms_offline_og.begin_instantiation.
4. Durchführen eines Exports der beteiligten Tabellen und Übertragung der Dump-Dateien auf die neue Master Site. 5. Partielle Aktivierung der Replikationsgruppe ohne die neue Master-Site über dbms_offline_og.resume_subset_of_masters. Damit steht die Replikationsgruppe auf allen alten Master Sites schon wieder für DML-Operationen zur Verfügung. 6. Auf
der
neuen
Master
Site
das
Laden
der
Daten
vorbereiten:
dbms_offline_og.begin_load
7. Danach kann dort der Import durchgeführt werden. 8. Nach dem Import wird der Ladeprozess beendet: dbms_offline_og.end_load. 9. Auf der Master Definition Site muss zum Abschluss noch die Offline Instantiation beendet werden: dbms_offline_og.end_instantiation. Dadurch wird die neue Master Site vollständig in die Gruppe eingebunden. Ein vergleichbares Verfahren steht für umfangreiche Materialized Views über die Prozedur dbms_offline_snapshot zur Verfügung. Hierbei werden die Materialized Views zunächst auf der Master Site angelegt, dann exportiert und schließlich auf der Materialized Views Site per Import geladen. Überall dort, wo eine große Zahl von identischen Materialized View Sites aufzubauen ist, können Deployment Templates sinnvoll eingesetzt werden. Hierbei wird 16. Im Rahmen von dbs_repcat.create_master-repobject
Sandini Bib
Replikation
603
die entsprechende Umgebung mitsamt den dazugehörigen Daten auf der Master Site definiert und vorbereitet, an die Materialized View Site übermittelt und dort mit Hilfe des Templates vollständig installiert. Anpassung der replizierten Umgebung Datenstrukturen leben – so auch die von replizierten Umgebungen. Änderungen an den replizierten Objekten sind in vieler Hinsicht möglich, erfordern aber – im Vergleich zu nicht replizierten Umgebungen – ein angepasstes Vorgehen. In der Regel ist die betreffende Replikationsgruppe herunterzufahren, die Änderungen an dem Objekt sind dann über eine entsprechende Prozedur, wie z.B. dbms_repcat.alter_master_repobject, auf der Master Definition Site zu implementieren, damit die Änderungen an alle Master Sites der Gruppe übermittelt werden können. Nicht vergessen werden darf die erneute Generierung der internen Pakete und Trigger. Vorsicht ist immer dann geboten, wenn die betreffende Tabelle als Master-Objekt für abhängige Materialized Views fungiert. alter_master_repobject schlägt nicht auf abhängige Materialized Views durch! Die betreffenden Views müssen daher neu aufgebaut und entsprechend geladen werden, ansonsten drohen Folgefehler, wenn – bei schreibbaren Views – die ersten Transaktionen von der Materialized View Site auf die Master Site übertragen werden. Die Master Site ist in diesem Falle nicht mehr in der Lage, die Spalten korrekt zuzuordnen! Backup und Recovery Replizierte Umgebungen sind verteilte Umgebungen. Recovery-Operationen in verteilten Umgebungen verlangen – vor allem, wenn es sich um ein unvollständiges Recovery handelt – ein koordiniertes Vorgehen, das alle Master Sites aller Replikationsgruppen der betreffenden Datenbank mit einschließt. Die gewählte Recovery-Strategie ist im Einzelfall von vielen Faktoren abhängig:
: : : :
Ist das defekte System Master Definition Site für eine oder mehrere Gruppen? Existieren abhängige Materialized Views? Sind DML-Operationen auf replizierten Objekten grundsätzlich zulässig oder handelt es sich um ein reines Lesesystem? Ist eine „globale“ Konsistenz aller beteiligten Systeme erforderlich oder können einzelne Systeme zeitlich versetzt arbeiten?
Die erforderliche Strategie kann bei unvollständigem Recovery schnell sehr komplex werden und kann hier aus Platzgründen nicht detailliert besprochen werden.
Sandini Bib
604
8.3
Verteilte Datenbanktechniken
Advanced Queueing
Im Gegensatz zu Funktionen wie verteilte Transaktionen und Replikation, die von einer mehr oder weniger fest konfigurierten Anzahl von Kommunikationspartnern bezüglich der Verteilung von Daten mit identischen Datenstrukturen ausgehen, bietet das Advanced Queueing einen weitaus flexibleren Ansatz zur Verteilung von Informationen basierend auf Nachrichtenübermittlung (Messaging Services). Die Funktionen des Advanced Queueing stehen in allen Editionen der Oracle9i Database zur Verfügung. Sie liefern Queueing-Funktionen in ähnlicher Art und Weise wie Spezialprodukte für diese Aufgabe, etwa IBMs MQ Series. Die OracleLösung verspricht jedoch Queueing-Funktionen in Verbindung mit Datenbankrobustheit: Da die Queues letztendlich in Oracle-Tabellen gespeichert werden, stehen alle Oracle-Vorteile wie Sicherheit, Skalierbarkeit usw. zur Verfügung. Die Flexibilität spiegelt sich zunächst dadurch wider, dass Queues mit unterschiedlichen Eigenschaften und Mechanismen erstellt werden können:
: :
Bei der Point-to-Point-Methode gibt es genau einen Sender und genau einen Empfänger pro Nachricht. Eine in dieser Art und Weise genutzte Queue wird auch als Single-Consumer-Queue bezeichnet. Bei der Multiple-Consumer-Queue hingegen kann eine Nachricht von mehreren Empfängern konsumiert werden. Hierbei werden die Varianten Broadcast (der Sender weiß nichts über die Empfänger) und Point-to-Multipoint (der Sender sendet die Nachricht an eine von ihm selbst bestimmte Menge von Empfängern) unterschieden.
Der Zugriff auf die einzelnen Funktionen zum Erstellen und Abholen von Nachrichten kann innerhalb verschiedener Programmierumgebungen erfolgen: Neben diversen PL/SQL-Paketen werden Zugriffe aus OCI, Visual Basic mit Oracle Objects for OLE (OO4O), Java und Java Messaging Service (JMS) sowie über die Internet Data Access Presentation (IDAP) – eine Möglichkeit, strukturierte Nachrichten in XML über Internetprotokolle wie HTTP oder SMTP zu übertragen – unterstützt. Die administrativen Funktionen zum Einrichten, Überwachen und Anpassen von Queues werden in PL/SQL, Visual Basic und Java unterstützt. Die Beispiele in diesem Buch sind in PL/SQL gehalten, um den Umfang an dieser Stelle nicht zu sprengen. Die zusätzlichen Informationen, die benötigt werden, um Beispiele in den anderen Programmiersprachen zum Laufen zu bringen, finden sich im Oracle Handbuch zum Thema Advanced Queueing.
8.3.1
Was ist eine Queue?
Eine Queue ist ein Speicher für Nachrichten, die nach festzulegenden Regeln in die Queue gestellt bzw. aus der Queue ausgelesen werden können. Eine Nachricht besteht aus Metadaten, also Informationen über die Nachricht – wer hat sie wann und mit welchen Parametern in die Queue gestellt – sowie aus dem Inhalt der Nachricht, der auch als Payload bezeichnet wird.
Sandini Bib
Advanced Queueing
605
Wenn alle Empfänger die Nachricht ausgelesen haben, wird die Nachricht i.A. automatisch aus der Queue entfernt. Das Auslesen der Nachrichten erfolgt meist nach dem FIFO-Prinzip (first in first out), vergleichbar mit einer Schlange an der Kaufhauskasse. Eine Queue wird auf Datenbankebene mit Hilfe von Tabellen dargestellt. Die Tabelle liefert hierbei bereits einige Basiseigenschaften der Queue, wie z.B. den Datentyp des Queue-Inhalts, und die Information, ob es sich um eine MultipleConsumer-Queue handelt. Die Payload kann entweder ungetypt sein (dann wird der Oracle-Datentyp RAW verwendet) oder aus einem Oracle Objekttyp (deklariert mit einer PL/SQL-TYPE-Definition) bestehen. Dies ist insofern von Vorteil, als dass man nicht nur flache Strukturen, sondern auch verschachtelte Strukturen und Collections abbilden kann. LOB-Elemente sind ebenfalls erlaubt. Die Idee einer Queue ist nun, eine Nachricht zur weiteren Verarbeitung zu hinterlassen, um diese von einem oder mehreren Empfängern verarbeiten zu lassen. Die Verarbeitung erfolgt asynchron, d.h., die Transaktion bzw. Sitzung des Senders wird mit der Logik der Nachrichtenverarbeitung nicht belastet (im Gegensatz z.B. zu einer Trigger-Verarbeitung). Je nach Anforderung kann die Nachricht zum einmaligen Verarbeiten (z.B. zum Verarbeiten von Druckanforderungen mittels mehrerer Druckserver) oder zum Verarbeiten durch mehrere Empfänger (z.B. zur Aufnahme neuer Kundendaten von mehreren Systemen wie Auftragsbearbeitung, Buchhaltung und Marketing) in eine Queue eingestellt werden. Die Flexibilität des Oracle Advanced Queueing Systems ergibt sich nun aus folgenden Eigenschaften:
: : : :
Es stehen neben PL/SQL-Paketen direkte Schnittstellen für praktisch alle wichtigen Programmierumgebungen zur Verfügung. Natürlich können all diese Umgebungen auch PL/SQL-Pakete aufrufen, die direkten Schnittstellen ergeben jedoch programmiertechnisch ein runderes Bild. Für Multiple-Consumer-Queues können Nachrichten entweder an alle Interessenten (Subscriber) oder an eine beim Enqueue angegebene Liste von Empfängern adressiert werden. Das Ablegen einer Nachricht ist entweder Bestandteil der aktuellen Transaktion oder eine eigene (autonome) Transaktion, die unabhängig vom Ausgang der aktuellen Transaktion bestätigt wird. Queue Propagation sorgt dafür, dass eingegangene Nachrichten automatisch an andere Queues weitergeleitet werden, z.B. auch an entfernte Queues.
Der Einsatz von Queues bietet sich überall an, wo Verarbeitungsschritte abhängig vom Eingang einer bestimmten Information gestartet werden können. Dabei kann sowohl der Eingang der Information als auch das Abholen sowohl manuell – z.B. von einer interaktiven Oberfläche aus – als auch automatisiert vonstatten gehen.
Sandini Bib
606
Verteilte Datenbanktechniken
Bei der Oracle Server Enterprise Edition wird beispielsweise der Workflow Server mitausgeliefert, der auf der Advanced Queueing-Technologie basiert. Eigene Implementierungen auf Basis von Advanced Queueing sind lohnend, wenn entweder innerhalb eines Anwendungssystems Vorgänge nachrichtenbasiert gesteuert werden oder Daten zwischen verschiedenen Anwendungen zum Austausch anstehen. Der Austausch von Daten zwischen verschiedenen Anwendungssystemen auf Basis von Advanced Queues basiert auf folgender Idee: Möchte man mit herkömmlichen Mitteln Daten zwischen verschiedenen Anwendungssystemen austauschen, so müssen für n Anwendungssysteme n – 1 bidirektionale Schnittstellen entwickelt werden – jeweils mit entsprechendem Pflege- und Wartungsaufwand. Stattdessen kann ein Queueing-System implementiert werden, das für den zentralen Austausch der Daten verantwortlich ist. Hierfür ist lediglich eine (ebenfalls bidirektionale) Schnittstelle pro Anwendungssystem erforderlich.
8.3.2
Die Praxis
Mit dem Advanced Queueing verhält es sich wie mit vielen Bereichen innerhalb der Oracle Database: Die Anzahl der Möglichkeiten und Optionen macht eine Sache für den Anfänger so unübersichtlich, dass er versucht ist, die Flinte ins Korn zu werfen. In diesem Abschnitt geht es darum, in Ansätzen die Advanced Queueing-Funktionen vorzustellen und gleichzeitig einige Optionen zu erläutern. Es wird einige Seiten dieses Buches in Anspruch nehmen, die Vorbereitungen für die erste Nachricht zu treffen, die in eine Queue gestellt wird. Dabei ist die eigentliche Schwierigkeit, auseinander zu halten, welche Option auf welcher Ebene (Queue-Tabelle, Queue, Enqueue, Dequeue) zur Verfügung steht; die einzelnen Optionen sind nicht weiter kompliziert. Um die Angelegenheit nicht unnötig kompliziert zu machen, ist die Diskussion um Release 8.0-kompatible Queues so weit wie möglich außen vor gelassen worden. Vorbereitung der Instanz Queue-Operationen werden zu großen Teilen „im Hintergrund“, asynchron zu den Enqueue- bzw. Dequeue-Operationen, ausgeführt. Hierzu sind einerseits die JobQueue-Prozesse notwendig, die auch für die Abarbeitung der Datenbankjobs (Paket dbms_job) zuständig sind; weiterhin gibt es für die zeitliche Behandlung (Time Monitoring) von Nachrichten weitere spezielle Hintergrundprozesse. Eine Mindestkonfiguration sieht z.B. wie folgt aus: job_queue_processes = 2 aq_tm_processes = 2
Je nach Anforderung kann auch eine größere Einstellung, insbesondere der job_queue_processes, sinnvoll sein. Wenn z.B. bereits Datenbankjobs verarbeitet werden, kann es sinnvoll sein, den bestehenden Wert für job_queue_processes entsprechend zu erhöhen.
Sandini Bib
Advanced Queueing
607
Die Hintergrundprozesse für job_queue_processes sehen für Oracle8i und Oracle9i unterschiedlich aus. Oracle8i startet beim Instanz-Start die in job_queue_processes angegebene Anzahl von Prozessen, die mit SNP0, ..., SNP9, SNPA, ..., SNPZ bezeichnet werden. Aus der Bezeichnung der Prozesse ergibt sich ein Maximum von 36 Job-Queue-Prozessen. Bei Oracle9i wurde die Implementierung geändert, um wesentlich mehr JobQueue-Prozesse erlauben zu können – das Maximum wurde von 36 auf 1.000 erhöht. Die Job-Queue-Prozesse werden aber nunmehr dynamisch gestartet, um das Serversystem bei geringer Jobauslastung nicht über die Prozesszahl zu belasten. Wenn der Parameter job_queue_processes auf einen von 0 unterschiedlichen Wert gesetzt wird, wird der Job Queue Coordinator CJQ0 gestartet, der die Jobtabelle überwacht und bei Bedarf Job-Queue-Prozesse startet, maximal so viele wie angegeben. Die Job-Queue-Prozesse selbst werden mit J000, ..., J999 bezeichnet. Das Time Monitoring von Queues wird bei beiden Versionen identisch über den Parameter aq_tm_processes gesteuert, der die Anzahl der Queue-Monitor-Prozesse QMN0, ..., QMN9 bestimmt. Hiervon gibt es maximal 10 Stück. Bei beiden diskutierten Parametern ist der Standardwert 0; sie müssen also vor der Benutzung von Advanced Queueing gesetzt werden. Die administrative PL/SQL-Schnittstelle In diesem Abschnitt erfolgt ein Überblick über das administrative PL/SQL-Paket dbms_aqadm, mit dem Queue-Tabellen und Queues verwaltet werden. Es sei darauf
hingewiesen, dass die Schnittstellen hier nicht vollständig dokumentiert sind – hierzu steht im Detail insbesondere der Band Supplied PL/SQL Packages and Types Reference aus dem jeweils aktuellen Oracle Release zur Verfügung. In diesem und den folgenden Abschnitten wird versucht, einen Überblick über die notwendigen und als sinnvoll erachteten Mechanismen des Advanced Queueing zu verschaffen. Der Queue-Administrator Für administrative Aufgaben, wie z.B. das Einrichten
von Queuetabellen und Queues, steht eine PL/SQL-Schnittstelle in Form des Pakets dbms_aqadm. Den Umgang mit der administrativen Schnittstelle sollen einige Bei-
spiele Im Folgenden verdeutlichen. Zunächst legt man den Queue-Administrator an, aqhl in diesem Beispiel, der Zugriff auf die vordefinierte Rolle aq_administrator_role bekommt. Diese Rolle umfasst den Zugriff auf alle relevanten Pakete, wie z.B. dbms_aq und dbms_aqadm. CREATE USER aqhl IDENTIFIED BY aqhl QUOTA UNLIMITED ON data / GRANT CONNECT, RESOURCE, AQ_ADMINISTRATOR_ROLE TO aqhl / REVOKE UNLIMITED TABLESPACE FROM aqhl / Listing 8.63: Erstellen eines Queue-Administrators
Sandini Bib
608
Verteilte Datenbanktechniken
Die Beispiele werden zunächst vollständig unter dem angegebenen Benutzer durchgeführt. Weiter unten wird das Thema Sicherheit und Zugriff anderer Benutzer auf Queues behandelt. Im Beispiel wurde die RESOURCE-Rolle vergeben, damit der Benutzer aqhl u.a. Prozeduren und Objekttypen anlegen kann. Die Queue-Tabelle Unter dem Benutzer aqhl muss nun (zumindest für eine
getypte Queue) ein Datentyp für die Payload der Queue kreiert werden. Der hier verwendete Typ problem_message soll den Eingang einer Problemmeldung, z.B. bei einer Hotline, darstellen. CREATE TYPE problem_message AS OBJECT (kunde VARCHAR2(100), problem_kurz VARCHAR2(100), anrufzeit DATE, prio NUMBER(1) ) / Listing 8.64: Anlegen des Datentyps für Payload
Als Basis für Queues muss nun zunächst eine Queue-Tabelle mit Hilfe der Prozedur create_queue_table des Pakets dbms_aqadm erzeugt werden. BEGIN DBMS_AQADM.CREATE_QUEUE_TABLE( QUEUE_TABLE => 'aqhl.problem_message_tab', QUEUE_PAYLOAD_TYPE => 'aqhl.problem_message', STORAGE_CLAUSE => 'tablespace data', MULTIPLE_CONSUMERS => TRUE ); END; / Listing 8.65: Anlegen der Queue-Tabelle
Sowohl der Name der Tabelle (queue_table) als auch der Name des Datentyps für die Payload (queue_payload_type) müssen angegeben werden. Um Fehler zu vermeiden, sollten die Schemanamen grundsätzlich vorangestellt werden. Über den Parameter storage_clause können entsprechende Optionen wie tablespace, storage, lob storage usw. mitgegeben werden. Weiterhin entscheidet sich an dieser Stelle mit dem Booleschen Parameter multiple_consumers, ob die später für diese Tabelle angelegten Queues SingleConsumer- oder Multiple-Consumer-Queues sind. Zusätzlich zu den im Beispiel verwendeten Optionen können folgende weitere Optionen für die Prozedur create_queue_table angegeben werden: Mit Hilfe der Option sort_list kann eine Kombination der Spalten enq_time und priority angegeben werden, die als (aufsteigendes!) Sortierkriterium für den Dequeue-Vorgang verwendet werden. Standard ist 'ENQ_TIME', d.h. die klassische FIFO-Queue ohne Prioritäten.
Sandini Bib
Advanced Queueing
609
Die Option message_grouping erlaubt mit dem Wert dbms_aqadm.transactional, eine Menge von Nachrichten, die in der gleichen Transaktion enqueued werden, im Dequeue-Vorgang als Gruppe zu behandeln. Der Standardwert ist dbms_aqadm.none, d.h., die Gruppierung wird nicht berücksichtigt. Ein Kommentar für das Data Dictionary kann mit der Option comment übergeben werden. Bei RAC-Konfigurationen erlauben die Parameter primary_instance und secondary_instance die Angabe der Instanz, die standardmäßig bzw. im Fehlerfall das Time Monitoring bzw. die Queue Propagation behandeln soll. Dies bezieht sich auf die Operationen im Hintergrund – Enqueue- und Dequeue-Operationen können mit jeder Instanz durchgeführt werden. Schließlich erlaubt die Option compatible mit den möglichen Werten '8.0' und '8.1' die Anpassung der Funktionalität auf einen anderen Wert, als es der Initialisierungsparameter compatible vorgibt. Dieser bestimmt jedoch den Standardwert für die Option. Durch den Aufruf der Prozedur werden im Schema aqhl einige Objekte erzeugt. Zunächst ist dies die Queue-Tabelle problem_message_tab mit folgendem Aufbau: Name Null? ----------------------------------------- -------Q_NAME MSGID NOT NULL CORRID PRIORITY STATE DELAY EXPIRATION TIME_MANAGER_INFO LOCAL_ORDER_NO CHAIN_NO CSCN DSCN ENQ_TIME ENQ_UID ENQ_TID DEQ_TIME DEQ_UID DEQ_TID RETRY_COUNT EXCEPTION_QSCHEMA EXCEPTION_QUEUE STEP_NO RECIPIENT_KEY DEQUEUE_MSGID SENDER_NAME SENDER_ADDRESS
Type -------------VARCHAR2(30) RAW(16) VARCHAR2(128) NUMBER NUMBER DATE NUMBER DATE NUMBER NUMBER NUMBER NUMBER DATE NUMBER VARCHAR2(30) DATE NUMBER VARCHAR2(30) NUMBER VARCHAR2(30) VARCHAR2(30) NUMBER NUMBER RAW(16) VARCHAR2(30) VARCHAR2(1024)
Sandini Bib
610
SENDER_PROTOCOL USER_DATA
Verteilte Datenbanktechniken
NUMBER PROBLEM_MESSAGE
Listing 8.66: problem_message-tab
Neben den Spalten zur Verwaltung der Nachrichten findet sich in der letzten Spalte user_data der parametrierte Datentyp der Payload problem_message wieder. Neben der Queue-Tabelle wird eine View mit dem Namen aq$, im Beispiel also aq$problem_message_tab, angelegt. Diese hat die folgende Struktur: Name Null? ----------------------------------------- -------QUEUE MSG_ID NOT NULL CORR_ID MSG_PRIORITY MSG_STATE DELAY EXPIRATION ENQ_TIME ENQ_USER_ID ENQ_TXN_ID DEQ_TIME DEQ_USER_ID DEQ_TXN_ID RETRY_COUNT EXCEPTION_QUEUE_OWNER EXCEPTION_QUEUE USER_DATA PROPAGATED_MSGID SENDER_NAME SENDER_ADDRESS SENDER_PROTOCOL ORIGINAL_MSGID ORIGINAL_QUEUE_NAME ORIGINAL_QUEUE_OWNER EXPIRATION_REASON CONSUMER_NAME ADDRESS PROTOCOL
Type --------------VARCHAR2(30) RAW(16) VARCHAR2(128) NUMBER VARCHAR2(13) DATE NUMBER DATE NUMBER VARCHAR2(30) DATE NUMBER VARCHAR2(30) NUMBER VARCHAR2(30) VARCHAR2(30) PROBLEM_MESSAGE RAW(16) VARCHAR2(30) VARCHAR2(1024) NUMBER RAW(16) VARCHAR2(30) VARCHAR2(30) VARCHAR2(19) VARCHAR2(30) VARCHAR2(1024) NUMBER
Listing 8.67: aq$problem_message_tab
Diese View dekodiert einige Informationen aus der Queue-Tabelle (z.B. den Status state der Queue-Tabelle in das Zeichenketten-Feld msg_state mit den lesbaren Werten ready, wait, processed und expired) und ermöglicht die einfachere Lesbarkeit. Falls es sich um eine Multiple-Consumer-Queue handelt, werden neben der QueueTabelle und der View einige weitere Tabellen als IOTs (Index-Only-Tables) angelegt:
Sandini Bib
Advanced Queueing
: : : : :
611
Die IOT aq$__t enthält Informationen über Queue-MonitorOperationen. Die IOT aq$__i enthält Informationen über Dequeue-Operationen; falls es sich nicht um eine Multiple-Consumer-Queue handelt, ist dies ein Index auf der Queue-Tabelle. Die IOT aq$__s enthält Subscriber-Informationen. Die IOT aq$__nr enthält Regeln von Subscriptions. Die IOT aq$__h enthält historische Informationen über Dequeue-Operationen.
Die View aq$ wird für Multiple-Consumer-Queues als Join zwischen der Queue-Tabelle und zwei IOTs angelegt, so dass in der View alle Nachrichten mit ihren Stati pro Subscriber abgefragt werden können. Eine neu angelegte Queue-Tabelle enthält bereits eine Queue mit dem Namen aq$__e. Dies ist eine so genannte Exception-Queue, in der die Nach-
richten landen, bei deren Verarbeitung Fehler aufgetaucht sind. Dies kann beispielsweise eine überschrittene vordefinierte expiration-Zeit sein. Die Queue Eine benutzerdefinierte Queue muss aber noch mit der Prozedur CREATE_QUEUE aus dem Paket dbms_aqadm definiert werden.
BEGIN DBMS_AQADM.CREATE_QUEUE( QUEUE_NAME => 'aqhl.problem_message_q', QUEUE_TABLE => 'aqhl.problem_message_tab' ); END; / Listing 8.68: Erstellung einer benutzerdefinierten Queue
Auch hier gibt es einige zusätzliche Parameter: Mit queue_type kann gesteuert werden, ob es sich um eine normale (dbms_aqadm.normal_queue) oder um eine Exception-Queue (dbms_aqadm. exception_queue) handelt. max_retries bestimmt die maximale Anzahl der möglichen nicht erfolgreichen Dequeue-Versuche, d.h., die Transaktion, die das Dequeue durchführt, wird zurückgerollt. Wenn max_retries erreicht wird, wird die Nachricht auf die Exception-Queue verschoben. Der Standardwert hierfür ist NULL. Retry_delay bestimmt für den Fall, dass die Nachricht in der Queue verbleibt, wie lange es dauert, bis die Nachricht wieder zum Dequeue zur Verfügung steht. Der Standard hierfür ist 0 (Sekunden), d.h., die Nachricht steht sofort wieder zur Verfügung.
Die retention_time bestimmt, wie lange eine Nachricht nach erfolgreichem Dequeue noch in der Queue-Tabelle gespeichert wird. Der Standard ist 0, neben Angaben in Sekunden ist auch dbms_aqadm.infinite für eine unbegrenzte Speicherung möglich.
Sandini Bib
612
Verteilte Datenbanktechniken
An dieser Stelle sei nochmals darauf hingewiesen, dass die Single- bzw. MultipleConsumer-Eigenschaft einer Queue bereits beim Anlegen der Queue-Tabelle festgelegt wird. Bevor die Queue benutzt werden kann, muss sie gestartet werden. Dies erfolgt mit der Prozedur dbms_aqadm.start_queue: BEGIN DBMS_AQADM.START_QUEUE(QUEUE_NAME => 'aqhl.problem_message_q'); END; / Listing 8.69: Starten der Queue
Auch hier können optional weitere Parameter angegeben werden: Mit den beiden Booleschen Parametern enqueue und dequeue kann die Queue gezielt nur für einen der beiden Vorgänge gestartet werden; standardmäßig sind beide Parameter TRUE. Zum Beenden einer Queue kann in identischer Art und Weise die Prozedur dbms_aqadm.stop_queue benutzt werden.
Bereits bei der Erstellung der Queue-Tabelle wird automatisch eine so genannte Exception-Queue mit dem Namen aq$__e, in unserem Beispiel also aq$_problem_message_tab_e, angelegt. Wenn bei der Weiterleitung von Nachrichten Probleme auftauchen oder etwa die benutzerdefinierte Ablaufzeit einer Nachricht vorüber ist, wird die Nachricht automatisch in die Exception-Queue verschoben. Somit stehen grundsätzlich Informationen zu Fehlern zur Verfügung. Obwohl die Exception-Queue Nachrichten erhalten kann, ist sie standardmäßig nicht gestartet. Will man also Fehler bereinigen und Nachrichten aus der ExceptionQueue entfernen, so muss sie zunächst zumindest für die Dequeue-Operation mit o.a. Prozedur dbms_aqadm.start_queue gestartet werden. Einen Überblick über bestehende Queues und deren Status liefert die View dba_queues. Sie stellt u.a. den Zusammenhang zwischen Queues und Queue-Tabel-
len her. SQL> SELECT * FROM dba_queues 2 WHERE owner='AQHL'; OWNER NAME ------------------------------ -----------------------------QUEUE_TABLE QID QUEUE_TYPE ------------------------------ ---------- -------------------MAX_RETRIES RETRY_DELAY ENQUEUE DEQUEUE ----------- ----------- ------- ------RETENTION ---------------------------------------USER_COMMENT -------------------------------------------------AQHL AQ$_PROBLEM_MESSAGE_TAB_E PROBLEM_MESSAGE_TAB 6757 EXCEPTION_QUEUE
Sandini Bib
Advanced Queueing
0 0 exception queue AQHL PROBLEM_MESSAGE_TAB 5 0
613
0
NO
NO
0
PROBLEM_MESSAGE_Q 6759 NORMAL_QUEUE YES YES
Listing 8.70: dba_queues
Die View dba_queue_tables liefert Informationen über die Queue-Tabellen. SQL> SELECT * FROM dba_queue_tables 2 WHERE owner='AQHL'; OWNER QUEUE_TABLE TYPE ------- -------------------- ------MESSAGE_GROUP COMPA PRIMARY_INSTANCE ------------- ----- ---------------AQHL PROBLEM_MESSAGE_TAB OBJECT NONE 8.1.3 0
OBJECT_TYPE SORT_ORDER RECIPIEN --------------------- ------------- -------SECONDARY_INSTANCE OWNER_INSTANCE USER_COMMENT ------------------ -------------- -----------AQHL.PROBLEM_MESSAG ENQUEUE_TIME MULTIPLE 0 1
Listing 8.71: dba_queue_tables
Die operative PL/SQL-Schnittstelle Datentypen Bevor es nun zu den eigentlichen Queue-Operationen geht, müssen
noch einige Datentypen beschrieben werden, die für diese Operationen zwingend benötigt werden. Sie sind für die strukturierte Übergabe von Optionen an die Schnittstelle gedacht. Man kann hier sicherlich diskutieren, inwieweit solche Strukturen notwendig sind. Statt einer Record-Struktur kann man ja auch die Parameterliste einer PL/SQL-Prozedur verlängern. Andererseits können die Typdefinitionen in der vorliegenden Form sofort in entsprechendem PL/SQL-Code verwendet werden. Zunächst gibt es den Datentyp message_properties_t, der sowohl beim Enqueue als auch beim Dequeue verwendet wird. Attribut
Beschreibung
Standardwert
PRIORITY
Priorität; kleinerer Wert bedeutet höhere Priorität.
1
DELAY
Anzahl Sekunden nach dem Enqueue, nach der eine Nachricht zum Dequeue zur Verfügung steht. Während der Delay-Phase hat die Nachricht den Zustand WAITING, danach READY.
DBMS_AQ.NODELAY
Sandini Bib
614
Verteilte Datenbanktechniken
Attribut
Beschreibung
Standardwert
EXPIRATION
Anzahl Sekunden, die eine Nachricht zum Dequeue zur Verfügung steht. Falls die Nachricht in dieser Zeit nicht abgeholt wird, wandert sie im Status EXPIRED in die Exception-Queue.
DBMS_AQ.NEVER
CORRELATION
Benutzerdefinierter Wert
NULL
ATTEMPTS
Anzahl der bisher durchgeführten DequeueVersuche.
RECIPIENT_LIST
Eine von der Liste der Subscriber abweichende Liste der Nachrichtenempfänger.
EXCEPTION_QUEUE
Die Exception-Queue, die für diese Nachricht verwendet werden soll.
ENQUEUE_TIME
Enqueue-Zeitpunkt der Nachricht
STATE
Status der Nachricht zum Dequeue-Zeitpunkt. (0 READY, 1 WAITING, 2 PROCESSED, 3 EXPIRED)
SENDER_ID
Anwendungsspezifische Senderinformation
NULL
ORIGINAL_MSGID
Wird für das Weiterleiten von Nachrichten benutzt.
NULL
NULL
Tabelle 8.3: Typbeschreibung MESSAGE_PROPERTIES_T
Der Typ enqueue_options_t wird beim Enqueue verwendet: Attribut
Beschreibung
Standardwert
VISIBILITY
Transaktionsverhalten des EnqueueVorgangs. Standard ist die Einbettung in die äußere Transaktion; mit DBMS_AQ.IMMEDIATE erfolgt ein COMMIT innerhalb des Enqueues.
DBMS_AQ.ON_COMMIT
RELATIVE_MSGID
Bezeichnet den Vorgänger einer Nachricht in einer Kette von Nachrichten. Nur gültig, wenn DBMS_AQ.BEFORE im nächsten Parameter angegeben wird.
NULL
SEQUENCE_DEVIATION
Ermöglicht Nachrichtenketten. Mit DBMS_AQ.TOP wird die erste Nachricht eingegeben, danach mit DBMS_AQ.BEFORE weitere.
NULL
TRANSFORMATION
Transformation, die vor dem Enqueue einer Nachricht passiert. Der Typ der Funktion muss dem Payload-Typ entsprechen.
NULL
Tabelle 8.4: Typbeschreibung ENQUEUE_OPTIONS_T
Sandini Bib
Advanced Queueing
615
Schließlich wird beim Dequeue der Type dequeue_options_t verwendet: Attribut
Beschreibung
Standardwert
CONSUMER_NAME
Name des Consumers; muss bei MultipleConsumer-Queues einer der Subscriber bzw. Adressaten sein.
NULL
DEQUEUE_MODE
Mit BROWSE kann nur gelesen werden (entspricht SELECT); mit LOCKED wird gesperrt, aber noch nicht gelöscht (entspricht SELECT FOR UPDATE); mit REMOVE wird die Aktion vollständig durchgeführt; mit REMOVE_NODATA wird das Übertragen der Payload übergangen.
DBMS_AQ.REMOVE
NAVIGATION
Spezifiziert die Position der nächsten Nachricht. Bei FIRST_MESSAGE wird im Gegensatz zu NEXT_MESSAGE die interne Abfrage neu ausgeführt.
DBMS_AQ.NEXT_MESSAGE
NEXT_TRANSACTION führt zur Nachricht der nächsten Transaktion bei aktiviertem MESSAGE_GROUPING in der QueueTabelle. VISIBILITY
s. enqueue_options_t
DBMS_AQ.ON_COMMIT
WAIT
Spezifiziert, wie lange gewartet werden soll, wenn aktuell keine Nachricht vorliegt. NO_WAIT wartet nicht, FORVEVER unendlich, und mit einer positiven Zahl wird eine Anzahl Sekunden angegeben.
DBMS_AQ.FOREVER
MSGID
Identifikation der Nachricht zum Dequeue (Alternativ zum Suchen)
NULL
CORRELATION
Korrelationszeichenkette; kann % und _ enthalten.
NULL
DEQ_CONDITION
Bedingung (wie WHERE-Klausel) zum Dequeue. Kann auf Spalten der QueueTabelle sowie auf die Payload (Präfix tab.user_data) angewandt werden.
NULL
TRANSFORMATION
Transformationsfunktion, die beim Dequeue auf die Payload angewandt wird.
NULL
Tabelle 8.5: Typbeschreibung DEQUEUE_OPTIONS_T
Bei Multiple-Consumer-Queues muss je nach Aktion der Producer oder Consumer einer Nachricht angegeben werden. Dies geschieht mit Hilfe der Datenstruktur sys.aq$_agent, die als eine der wenigen Datenstrukturen nicht im dbms_aq-Paket angelegt ist.
Sandini Bib
616
Verteilte Datenbanktechniken
Attribut
Beschreibung
NAME
Name des Producers/Consumers einer Nachricht
ADDRESS
Protokollspezifische Adresse; bei Protokoll 0 von der Form [SCHEMA.]QUEUE[@DBLINK]
PROTOCOL
Protokoll für die Angabe der Adresse. Der Standardwert ist der einzige mögliche Wert.
Standardwert
0
Tabelle 8.6: Typbeschreibung SYS.AQ$_AGENT
Weiterhin müssen manchmal Listen von Agenten verwaltet werden, z.B. im Sinne von adressierten Empfängern (dbms_aq.aq$_recipient_list_t) oder Agenten in Warteposition (dbms_aq.aq$_agent_list_t). Diese sind jeweils als TABLE OF sys.aq$_agent INDEX BY BINARY_INTEGER
deklariert und – im Gegensatz zum Basistyp – im Paket dbms_aq vorhanden. Registrieren von Subscribern bei Multiple-Consumer-Queues Dieser Abschnitt kann
übergangen werden, wenn es sich um eine Single-Consumer-Queue handelt. Auch eine Multiple-Consumer-Queue kann bereits mit Nachrichten beschickt werden, wenn beim Enqueue eine Liste von Empfängern angegeben wird (Point to Multipoint). Meist wird jedoch das Publish-Subscribe-Verfahren angewandt, bei dem die Liste der Empfänger nicht beim Enqueue, sondern durch eine Anzahl von SubscribeAktionen („Abonnement der Nachrichten“) festgelegt wird. Standardmäßig erhalten alle Subscriber jede Nachricht der Queue (solange sie versuchen, diese im Zeitfenster, das durch die DELAY- und EXPIRIATION-Optionen festgelegt wird, abzuholen). Die Prozedur dbms_aqadm.add_subscriber registriert einen Subscriber für eine Queue: BEGIN DBMS_AQADM.ADD_SUBSCRIBER( QUEUE_NAME => 'aqhl.problem_message_q', SUBSCRIBER => SYS.AQ$_AGENT('A007', NULL, NULL) ); END; / Listing 8.72: Anlegen eines Subscribers
Zusätzlich zu den angegebenen Parametern können die Parameter rule (eine Art WHERE-Klausel, die bestimmt, welche Nachrichten an den Subscriber gehen) und transformation (eine PL/SQL-Funktion, die beim Dequeue dieses Subscribers angewandt wird) angegeben werden. Zum Ändern der letzten beiden Parameter kann die Prozedur dbms_aqadm.alter_subscriber aufgerufen werden. Hierbei werden immer beide Parameter geändert. Einen Subscriber löschen kann man mit
Sandini Bib
Advanced Queueing
617
dbms_aqadm.remove_subscriber, wobei nur die Parameter queue_name und subscriber angegeben werden.
Im o.a. Beispiel wird ein Subscriber definiert, der selbständig das Dequeue vornimmt. Es ist jedoch auch möglich, einen Subscriber zu definieren, der die Nachricht automatisch an eine andere Queue weiterleitet (Queue Propagation). Hierbei wird bei der Definition des Agenten die andere Queue als ADDRESS spezifiziert: BEGIN DBMS_AQADM.ADD_SUBSCRIBER( QUEUE_NAME => 'aqhl.problem_message_q', SUBSCRIBER => SYS.AQ$_AGENT( 'A008', 'aqhl.problem_message_q2', 0 ) ); END; / Listing 8.73: Registrierung eines Subscribers für Queue Propagation
Damit die Nachrichten weitergeleitet werden, muss dies noch auf Queue-Ebene definiert werden: BEGIN DBMS_AQADM.SCHEDULE_PROPAGATION( QUEUE_NAME => 'aqhl.problem_message_q', DESTINATION => NULL ); END; / Listing 8.74: Definition der Weiterleitung destination bezeichnet einen Datenbank-Link für Remote Queues. Der Standardwert NULL steht für die lokale Datenbank. Mit den optionalen Parametern start_time, duration und next_time kann der Startzeitpunkt der Weiterleitung, die Dauer des Zeitfensters in Sekunden sowie eine Formel zur Berechnung der nächsten Startzeit aus der Endzeit des laufenden Fensters angegeben werden. Mit latency kann angegeben werden, wie viele Sekunden eine Nachricht bei leerer Queue innerhalb des Zeitfensters maximal warten muss, bis sie weitergeleitet wird. Je kleiner latency ist, desto mehr busy waits werden von den Hintergrundprozessen ausgeführt.
Enqueue- und Dequeue-Operationen Nunmehr ist endlich genug Rüstzeug vorhanden, um eine Nachricht in eine Queue zu stellen, was mit Enqueue bezeichnet wird. Folgender PL/SQL-Block stellt eine Nachricht in eine Queue:
Sandini Bib
618
Verteilte Datenbanktechniken
DECLARE enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T; message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; message_handle RAW(16); message aqhl.problem_message; BEGIN message_properties.delay := 10; message_properties.expiration := 1000; message := aqhl.problem_message('Kunde 1', 'Tablespace voll', sysdate, 1); DBMS_AQ.ENQUEUE(QUEUE_NAME => 'aqhl.problem_message_q', ENQUEUE_OPTIONS => enqueue_options, MESSAGE_PROPERTIES => message_properties, PAYLOAD => message, MSGID => message_handle); COMMIT; END; / Listing 8.75: Einstellen einer Nachricht in eine Queue
Im Bereich der Enqueue-Optionen sind nur Standardwerte verwendet worden; bei den Message Properties ist das Delay auf 10 sec, die Expiration auf 1.000 sec gesetzt worden. Das COMMIT am Ende des Blocks sorgt dafür, dass dann die Nachricht für alle sichtbar in der Queue steht (siehe Enqueue-Option visibility). Der folgende Block ist in der Lage – wenn er im entsprechenden Zeitfenster aufgesetzt wird –, die Nachricht aus der Queue zu lesen. DECLARE dequeue_options DBMS_AQ.DEQUEUE_OPTIONS_T; message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; message_handle RAW(16); message aqhl.problem_message; BEGIN dequeue_options.consumer_name := 'A007'; dequeue_options.wait := 30; DBMS_AQ.DEQUEUE(QUEUE_NAME => 'aqhl.problem_message_q', DEQUEUE_OPTIONS => dequeue_options, MESSAGE_PROPERTIES => message_properties, PAYLOAD => message, MSGID => message_handle); COMMIT; EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20000, 'DeQ failed'); END; / Listing 8.76: Lesen der Nachricht aus der Queue
Sandini Bib
Advanced Queueing
619
Da der Wert für dequeue_options.wait auf 30 sec eingestellt wurde, steigt die Prozedur – in diesem Fall aus SQL*Plus – wie folgt aus, falls keine entsprechende Nachricht zum Dequeue vorliegt: DECLARE * ERROR at line 1: ORA-20000: DeQ failed ORA-06512: at line 17
Dies passiert, weil mit dem allgemeinen Exception-Handler (WHEN OTHERS THEN...) ein eigener Fehler produziert wird. Der Fehler, der aus dem DBMS_AQ-Paket gemeldet wird, ist: ORA-25228: timeout or end-of-fetch during message dequeue from AQHL.PROBLEM_MESSAGE_Q Queue-Sicherheit Die Sicherheitsaspekte beim Betrieb von Advanced Queues beziehen sich einerseits auf die entsprechenden Pakete, andererseits auf die benutzerspezifischen Zugriffsrechte auf einzelne Queues. Für den Zugriff auf die von Oracle mitgelieferten Pakete existieren zwei Rollen, die bereits erwähnte Rolle aq_administrator_role sowie aq_user_role. Hierbei umfasst aq_user_role diejenigen Pakete, mit denen Enqueue- und Dequeue-Operationen durchgeführt werden; in aq_administrator_role sind zusätzlich die zur Konfiguration notwendigen Pakete enthalten. Die Alternative zur Zuweisung dieser Rollen ist die direkte Zuweisung der jeweils benötigten Pakete, so dass diese auch z.B. innerhalb von selbst entwickelten gespeicherten Prozeduren usw. benutzt werden können.
Um Queue-Tabelle und Queues im eigenen Schema erzeugen zu können, wird mindestens der Zugriff auf das Paket dbms_aqadm sowie das CREATE_TABLE-Privileg benötigt. Mit dem Systemprivileg manage any queue können diese Operationen auch für fremde Schemas durchgeführt werden. Für eigene Queues sind generell auch die Operationen Enqueue und Dequeue erlaubt. Diese Operationen sind für Queues in fremden Schemas erlaubt, wenn die Systemprivilegien enqueue any queue bzw. dequeue any queue zugewiesen sind, oder die Privilegien enqueue, dequeue oder all (für beide) explizit für eine Queue erteilt sind. All diese Privilegien werden im Übrigen nicht mit GRANT- bzw. REVOKEKommandos erteilt und zurückgenommen, sondern über die Prozeduren grant_system_privilege, revoke_system_privilege, grant_queue_privilege und revoke_ queue_privilege im Paket dbms_aqadm. Ein Beispiel zum Erteilen des enqueue-Privilegs auf eine Queue lautet: EXECUTE DBMS_AQADM.GRANT_QUEUE_PRIVILEGE( PRIVILEGE => 'ENQUEUE', QUEUE_NAME => 'AQHL.PROBLEM_MESSAGE_Q', GRANTEE => 'SCOTT', GRANT_OPTION => FALSE) Listing 8.77: Rechtevergabe für Queues
Sandini Bib
620
Verteilte Datenbanktechniken
Es ist weiterhin zu beachten, dass eventuell zusätzliche Privilegien notwendig sind, um in einer sinnvollen Art und Weise mit einer Queue aus einem fremden Schema zu arbeiten. Hierzu gehört z.B. das execute-Privileg auf den Objekttyp, der als Basis für die Queue definiert wurde, also in unserem Beispiel GRANT EXECUTE ON problem_message TO scott /
Administration und Monitoring Die Administration von Advanced Queues umfasst die Beobachtung der QueueStatistiken, d.h., die Anzahl der in der Queue gespeicherten Nachrichten mit den verschiedenen Stati sollte regelmäßig überwacht werden. Eventuell müssen fehlerhafte Zustände manuell bereinigt werden. Das umfasst z.B. das Aufräumen der Exception-Queue, wenn viele unerwartete Fehler dort aufgelaufen sind. Die Beobachtung der Queues kann entweder manuell über die bereits erwähnten Views erfolgen oder mit Hilfe des Enterprise Managers, der im Bereich Schema Informationen über Advanced Queues enthält. Aus diesem Bereich können die PL/ SQL-Schnittstellen komfortabel bedient werden. Als Beispiel hierzu die Ansicht der Seite, die durch den Punkt DETAILS ANZEIGEN/BEARBEITEN für eine Queue aufgeblendet wird.
Abbildung 8.21: Queue-Administration mit dem Enterprise Manager
Sandini Bib
Advanced Queueing
8.3.3
621
Advanced Queueing vs. Replikation
In diesem Abschnitt werden die Möglichkeiten von Advanced Queueing mit denen der Replikation verglichen. Immerhin stehen mit den beiden Verfahren zwei unterschiedliche Ansätze für verteilte Systeme zur Verfügung. Die Gegenüberstellung der Verfahren soll jedoch auf keinen Fall in einen Vorteil/Nachteil-Vergleich münden; es geht vielmehr darum, eigenständige Merkmale herauszustellen. Diese ergeben dann in einem konkreten Umfeld verschiedene Lösungsansätze – mit entsprechenden Vor- und Nachteilen für das Umfeld. Der größte Unterschied zwischen beiden Verfahren ist sicherlich, dass die Replikation datenorientiert ist, im Gegensatz zum ereignisorientierten Advanced Queueing-Verfahren. Datenorientiert heißt im Falle der Replikation insbesondere, dass auf beiden Seiten zumindest in Teilen identische Datenstrukturen vorliegen. Beim Advanced Queueing wird lediglich die Datenstruktur der Nachricht betrachtet – welche Datenstrukturen die am Nachrichtenaustausch beteiligten Systeme zur Datenspeicherung verwenden, ist letztendlich nicht von Bedeutung. Somit deckt die Replikation Anwendungsgebiete ab, bei denen Tabellen, bzw. Teile davon, in einer verteilten Umgebung mehrfach zur Verfügung gestellt werden müssen, um die allgemeine Systemverfügbarkeit zu erhöhen und/oder Antwortzeiten zu verbessern. Dabei stellt die Replikation Mechanismen mit verschiedenen Eigenschaften zur Verfügung (z.B. Materialized Views, Multi-Master-Replikation usw.), die jeweils einem unterschiedlichen Anwendungsprofil der replizierten Tabellen entsprechen. Die Replikation stellt mit all diesen unterschiedlichen Verfahren sicher, dass die Inhalte der Tabellen, eventuell mit einem mehr oder weniger großen Zeitversatz, an allen Stellen zur Verfügung stehen, unabhängig von der Art und Weise, wie die Daten entstanden sind. Dieser Ansatz ist z.B. auch mit einer Advanced Queueing-Technik zu realisieren, indem man das Ereignis „INSERT eines Datensatzes“ als Nachricht in eine entsprechende Queue stellt. Mit Advanced Queueing sind jedoch auch beliebige andere Ereignisse, die eine strukturierte Zusatzinformation enthalten, abzubilden, seien es Druckaufträge, Prüfroutinen innerhalb einer Anwendung oder auch die Information vieler unterschiedlicher Systeme über die Entstehung eines Datensatzes. Weiterhin ist beim Advanced Queueing festzustellen, dass es sich im Gegensatz zur Replikation um keine fertige Anwendung handelt, die lediglich konfiguriert werden muss, sondern um eine Basisfunktionalität, die einen hohen Programmieraufwand erfordert. Die Komplexität einer solchen Anwendung ist nicht zu unterschätzen; allein das voliegende Kapitel ist lediglich ein Überblick über die Möglichkeiten. Betrachtet man die weiteren zur Verfügung gestellten Schnittstellen sowie die vielen ausgelassenen Themen am Rande, so ist eine Einarbeitung in das Thema Advanced Queueing mit Sicherheit keine Sache für einen einzigen langen Abend...
Sandini Bib
Sandini Bib
9
Monitoring/Reorganisation
Die Überwachung einer Oracle-Datenbank ist immer wieder ein Thema, über das kontrovers diskutiert werden kann. Zunächst einmal gibt es diverse Hersteller von schönen grafischen Werkzeugen, die einem suggerieren sollen, dass mit Hilfe einer optischen Darstellung des Füllgrades einer Datendatei gar nichts mehr schief gehen kann. In der Praxis ist es aber oftmals so, dass diese Werkzeuge zum Teil sehr dürftig und nicht auf die Belange einer speziellen Datenbank einstellbar sind. Zum andern müssen große Beträge aufgewendet werden, um ein effektives Monitoring durchzuführen. Oracle reiht sich in die Liste der Anbieter mit den Zusatzpaketen des Enterprise Managers ein. Auch hier können Sie nicht davon ausgehen, ein „RundumSorglos-Paket“ zu erhalten. Im folgenden Kapitel wird anhand einiger Beispiele beschrieben, welche Parameter wie überwacht werden können, um anschließend den Spezialfall Reorganisation herauszunehmen, da oftmals das Monitoring in der Erkenntnis mündet, dass die Datenbank oder bestimmte Bereiche davon reorganisiert werden müssen.
9.1
Was wird beobachtet
Für jeden Datenbankadministrator ist es zunächst einmal wichtig, frühzeitig über mögliche Ressourcenengpässe informiert zu werden. Daher ist es wichtig, alle Parameter, die zu Engpässen führen könnten, aufzuschreiben und dann zu überlegen, welche Schwellenwerte für die Beobachtung einzurichten sind. Natürlich sind diese Parameter je nach Art und Größe der Datenbank anzupassen und können je nach der verwendeten Oracle-Version komplizierter oder simpler sein.
9.1.1
Platzbedarf
Als Erstes fällt wahrscheinlich jedem Oracle Administrator die Ressource Platzbedarf ein. Sie gliedert sich bei einer Datenbank in folgende Bereiche:
: : : : : :
Datendatei Tablespace Extent Rollback-Segmente Archive Destination Filesystem
Sandini Bib
624
Monitoring/Reorganisation
Jeder der oben genannten Bereiche kann dazu führen, dass keine DML-Befehle mehr möglich sind, d.h., es kann nicht mehr gearbeitet werden, da zunächst wieder Platz geschaffen werden muss. Um diese Informationen überwachen zu können, reicht es in der Regel aus, die entsprechenden Oracle- oder Betriebssystemparameter in relativ großen Abständen zu messen. Gerade bei diesen Parametern spielt aber auch das Betriebssystem eine große Rolle, so dass man hierbei normalerweise nicht mit der Ausführung von SQLBefehlen auskommt.
9.1.2
Grenzen
Als Nächstes sind die harten Limitierungen einer Datenbank zu beobachten, als da wären:
: : : : :
Anzahl Prozesse Anzahl Datenbankdateien Anzahl Redolog-Dateien Anzahl Datenbanksitzungen Anzahl gleichzeitig geöffneter Cursor
Diese Parameter führen zwar nicht zu einem Stillstand der Datenbank, jedoch zu einer abnormalen Beendigung einer Datenbanksitzung. Es wird dem einzelnen Anwender aber einerlei sein, weshalb seine Anwendung abgebrochen wurde.
9.1.3
Tuningparameter
Natürlich gehören auch die performancerelevanten Parameter in den Bereich des Monitoring, da sie zwar nicht zum Abbruch von Transaktionen oder zum Stillstand der Datenbank führen, jedoch je nach Anwendung zu sehr kritischen Situationen, da sich das System unter Umständen aufschaukeln kann.
: : :
Buffer Cache Library Cache Redo Buffer
9.2
Wie wird beobachtet
Es gibt viele verschiedene Anbieter von Monitoring-Software. Dabei wird in der Regel zwischen dem Online-Monitoring und der Ereignis- oder Alarmsteuerung unterschieden. Die Grundstruktur ist bei unterschiedlichen Herstellern jedoch sehr verschieden, so gibt es zum Beispiel von der Firma Quest Software Inc. das Werkzeug Spotlight on Oracle, das für das Online-Monitoring sehr gut geeignet ist, leider aber kein Ereignis-Management bietet.
Sandini Bib
Wie wird beobachtet
625
Einen wichtigen Aspekt bei der Auswahl eines Monitoring-Werkzeugs stellt natürlich auch die Performance bzw. die zur Verfügung stehende Infrastruktur dar. Wenn Sie über eine 64Kbit-Leitung eine Datenbank überwachen wollen, können Java-Programme, die über das Netz geladen werden, eher hinderlich sein, d.h., in solchen Fällen sollten Sie die guten alten SQL-Scripts zur Hand haben, um die wichtigen Funktionen über die Dictionary-Views zu ermitteln. Aber selbst wenn Sie sich in einem LAN befinden, werden Sie feststellen, dass die grafischen Werkzeuge sehr lange brauchen, um die benötigte Information anzuzeigen. Gerade der Performance Monitor des Enterprise Managers stellt den Administrator oftmals auf eine harte Probe. Im Folgenden wird deshalb immer wieder auch auf den Einsatz von SQL-Befehlen zurückgegriffen.
9.2.1
Alert-Datei
Je nach Art des Problems sollten Sie zunächst einmal einen Blick auf die Alert-Datei der Datenbank werfen. In vielen Fällen hat diese recht einfache Methode das Problem schon gelöst. Wichtig ist dabei, dass Sie genau wissen, wo sich diese Datei befindet, denn sie ist die einzige Informationsquelle, die es Ihnen ermöglicht, auf einen Blick zu erkennen, ob es Ressourcenengpässe gegeben hat, und wenn ja, wo. Sollten Sie nicht sicher sein, wo sich diese Datei befindet, so melden Sie sich an die Datenbank an und setzen folgenden Befehl ab: sqlplus "/ as sysdba" SQL> show parameter background_dump NAME TYPE VALUE ---------------------- ----------- -----------------------------background_dump_dest string D:\oracle\admin\JA817\bdump Listing 9.1: Background Dump Destination
In diesem Verzeichnis befindet sich die Datei alertJA817.log, d.h. die Alert-Datei der entsprechenden Instanz. Diese Datei protokolliert alle Fehler der Hintergrundprozesse und zusätzlich Informationen zu den Redolog-Switches sowie dem Hochund Herunterfahren des Oracle-Systems und liefert die Information, dass andere Prozesse einen Fehler gemeldet haben. Hat diese Datei keine entsprechenden Einträge, können Sie schon einmal beruhigt sein, denn es ist kein Fehler aufgetreten, der auf mangelnde Überwachung zurückzuführen ist. Im Diagnostic-Pack des Oracle Enterprise Managers gibt es ein Ereignis (AlertDatei), das diese Datei überwacht und Meldungen mit den Fehlernummern ORA006*, ORA-01578 und ORA-00060 als Fehler und alle anderen ORA-Fehlermeldungen als Warnung ausgibt. Wenn Sie also das Enterprise Manager Diagnostic Pack oder das Standard-Pack lizenziert haben, sollten Sie dieses Ereignis auf jeden Fall benutzen. Dabei sollte das
Sandini Bib
626
Monitoring/Reorganisation
Zeitintervall auf fünf Minuten eingestellt werden, da diese Fehler als sehr kritisch einzuschätzen sind.
9.2.2
Tablespace und Datendatei
Anhand der Dictionary-Views dba_data_files und dba_free_space wird überwacht, wie groß der maximale freie Bereich in der entsprechenden Datendatei ist. Sollten Sie dieses Script selbst schreiben, dann müssen Sie folgendes beachten: Benutzen Sie MAX(blocks) und zusätzlich SUM(blocks), wenn sie den freien Platz in einer Datendatei ermitteln wollen. Benutzen Sie einen Outer-Join bei der Verknüpfung von dba_data_files und dba_free_space, da es durchaus vorkommen kann, dass es keinen Eintrag mehr in dba_free_space gibt, weil alles belegt ist. Überprüfen Sie, ob ein AUTOEXTEND der Datendatei gesetzt ist und ob die maximale Größe unter Umständen auf UNLIMITED gesetzt wurde. Wenn dem so ist, müssen Sie über Betriebssytemmittel (z.B. df –k) den Platz in den einzelnen Filesystemen überwachen. SELECT ts.tablespace_name, df_bytes sumbytes, (df_bytes - free_bytes) bytes_used, free_bytes freespace, (df_bytes - free_bytes)/df_bytes*100 percent_used, DECODE(df_autoextend,0,'NEIN',1,'JA') autoextend, df_maxbytes FROM dba_tablespaces ts, ( SELECT df2.tablespace_name tn, SUM(bytes) df_bytes, SUM(DECODE(maxbytes,0,bytes,maxbytes)) df_maxbytes, MAX(DECODE(autoextensible,'YES',1,'NO',0)) df_autoextend FROM dba_data_files df2 GROUP BY tablespace_name ) df2, ( SELECT fs.tablespace_name tn, sum(bytes) free_bytes FROM dba_free_space fs GROUP BY tablespace_name ) fs WHERE ts.tablespace_name=df2.tn AND ts.tablespace_name=fs.tn (+) AND (df_bytes - free_bytes)/df_bytes*100 >= 75 ORDER BY tablespace_name; Listing 9.2: Überwachung von Tablespaces mit mehr als 75 % Füllgrad
Sandini Bib
Wie wird beobachtet
627
Dieses Beispiel zeigt die Überwachung der Tablespaces einer Datenbank, so dass bei mehr als 75 % Füllgrad eine entsprechende Ausgabe erfolgt. Dabei wird auch berücksichtigt, dass für bestimmte Datendateien eine automatische Erweiterung eingeschaltet ist und damit die maximale Größe der Datei noch nicht erreicht ist.
9.2.3
Extents
Sicherlich ist alleine aus historischer Sicht die Überwachung der Anzahl von Extents immer noch möglich und von Fall zu Fall auch notwendig. Allerdings sollte man wegen der wesentlich besseren Performance und der einfacheren Administrierbarkeit auf Locally Managed Tablespaces übergehen und sich damit der Aufgabe entledigen, die Anzahl der Extents zu überwachen. Dennoch ist es notwendig, ein Augenmerk auf die Extents zu haben, da es vorkommen kann, dass ein zusätzliches Extent nicht allokiert werden kann, weil kein Platz mehr im Tablespace ist. Die Überwachung eines solchen Ereignisses ist jedoch schwierig, wenn nicht unmöglich. Zwar kann man kann überwachen, ob sich ein nächstes Extent in einem Tablespace noch allokieren lässt (Oracle Enterprise Manager-Ereignis CHUNK SMALL), aber speziell bei Indizes kann der Fall eintreten, dass einige Sätze in eine Tabelle eingefügt werden, die dazu führen, dass gleichzeitig mehrere Indizes der Tabelle versuchen, ein zusätzliches Extent zu allokieren. Daher steht man hier vor dem Problem, einerseits rechtzeitig gewarnt zu werden aber andererseits nicht zu viel Platz als Reserve zu benutzen. Es hat sich als sinnvoll herausgestellt, sich nicht das letztmögliche, sondern das vorletzte allokierbare Extent als Meldung ausgeben zu lassen. Dadurch hat man in der Regel ausreichend Zeit, entsprechende Maßnahmen zu ergreifen, und sollten tatsächlich zwei Segmente gleichzeitig ein Extent allokieren, führt dies noch nicht zum Chaos. SELECT seg.owner, seg.segment_name, seg.segment_type, seg.tablespace_name, seg.extents, seg.initial_extent, seg.next_extent, seg.pct_increase, tbs.free_bytes FROM dba_segments seg, ( SELECT fs.tablespace_name, MAX(fs.bytes) + (DECODE(df.maxbytes,0,df.bytes,df.maxbytes) - df.bytes) free_bytes FROM dba_free_space fs, dba_data_files df, dba_segments seg
Sandini Bib
628
Monitoring/Reorganisation
WHERE fs.tablespace_name (+) = df.tablespace_name
GROUP BY fs.tablespace_name, df.maxbytes, df.bytes ) tbs WHERE tbs.tablespace_name = seg.tablespace_name AND (seg.next_extent + seg.next_extent*(1+seg.pct_increase/100)) > tbs.free_bytes Listing 9.3: Die nächsten zwei Extents sind nicht möglich
Leider funktioniert dieses Script nicht mit Locally Managed Tablespaces, da hier der Wert next_extent in der View dba_segments nicht mehr gepflegt wird. Auch dieses Ereignis lässt sich sehr effektiv über den Oracle Enterprise Manager überwachen, dabei besteht dann die Möglichkeit, sich eine Warnung bei der Überschreitung eines bestimmten Schwellenwertes (z.B. noch 3 Extents) geben zu lassen und einen Alarm, wenn nur noch ein Extent allokiert werden kann. Im realen Betrieb ist die Einführung solcher Warnungen und Alarme aber oftmals sehr schwierig. Es kann zum Beispiel sein, dass ein Objekt in einem Tablespace gerade ein Extent mit der Größe von 500 Mbyte allokiert hat und dadurch ab sofort als Warnung ausgegeben wird, weil weitere 1000 Mbyte in dem Tablespace nicht zur Verfügung stehen. Daher sollten, wenn die Statistiken auf den Objekten in regelmäßigen Abständen aktualisiert werden, diese Informationen mit in dieses Ereignis einfließen. Damit kann sichergestellt werden, dass eine solche Tabelle nicht permanent erscheint und dadurch die Informationen verfälscht oder vom Wesentlichen ablenkt. Andererseits wird aber gerade an diesem Beispiel auch klar, wie wichtig es ist, für unterschiedlich große Tabellen entsprechende Tablespaces aufzubauen. Außerdem sollten statische Tabellen, die eine gewisse Größe haben, aber nicht weiterwachsen, ebenfalls einen eigenen Tablespace erhalten, der dann aus dem Monitoring herausgenommen wird.
9.2.4
Filesystem
Gerade durch die eingeführten Erleichterungen zur Verwaltung der Oracle-Ressourcen, z.B. Locally Managed Tablespaces, Oracle Managed Files und automatische Erweiterung von Datendateien bergen die Gefahr, dass die entsprechenden Ereignisse nicht mehr genutzt werden können, die Betriebssystemressourcen aber trotzdem plötzlich knapp sind. Es liegt klar auf der Hand, dass es wesentlich einfacher ist, eine Datendatei zu erweitern oder für ein neues Tablespace eine neue Datendatei zu erzeugen, als eine neue Festplatte ins Betriebssystem einzubinden. Es ist daher anzuraten, dass es immer Obergrenzen bei der Verwendung der OracleDateien geben sollte, damit man mit einem einfachen Befehl eine – und sei es temporäre – Lösung des Problems herbeiführen kann.
Sandini Bib
Wie wird beobachtet
629
Dennoch kommt der Überwachung der Betriebssystemressourcen und hier primär den Festplatten ein besonderes Augenmerk zu. Wenn eine Oracle-Ressource in die Begrenzung läuft, führt dies in der Regel dazu, dass die entsprechende Anwendung mit einem Fehler beendet wird, andere jedoch nicht betroffen sind. Wenn aber das Verzeichnis für die archivierten Redolog-Dateien voll ist, führt dies dazu, dass auf der gesamten Datenbank keine Transaktionen mehr ausgeführt werden. Sie kann in diesem Fall weder ordentlich heruntergefahren werden, noch durch irgendeinen Befehl zum Weiterarbeiten ermuntert werden. Nur die Vergrößerung der Plattenkapazität oder – in den meisten Fällen – das Löschen von archivierten Dateien, ermöglicht es dem System, weiterzuarbeiten. Ein Datenbankadministrator sollte also, auch wenn es entsprechende Überwachungswerkzeuge auf Betriebssystemebene gibt, immer den freien Platz im Archivierungsverzeichnis im Auge haben. Hierbei empfiehlt es sich, diesen Platz häufiger zu überwachen als andere Bereiche, da ein einziger Batch-Lauf durchaus ein Vielfaches des zu ändernden Datenbestandes als Log-Information schreibt. Der Oracle Enterprise Manager hat hierfür ebenfalls ein entsprechendes Ereignis. ARCHIV VOLL ermöglicht es, den Füllgrad des Filesystems mit den archivierten Redolog-Dateien zu überwachen. Der voreingestellte Wert hat aber keinen praktischen Nutzen. Die Werte für Alarm und Warnung sollten wie folgt kalkuliert werden: Eine Warnung wird ausgegeben, wenn noch mindestens doppelt so viel Platz vorhanden ist, wie die Gesamtgröße aller Online-Redolog-Dateien benötigt. Ein Alarm wird ausgegeben, wenn der Platz kleiner ist als die Gesamtgröße aller Online-Redolog-Dateien. Diese Werte gelten natürlich unabhängig davon, ob der Enterprise Manager oder ein anderes Werkzeug benutzt wird.
9.2.5
Oracle Enterprise Manager Advanced Events
Im Oracle Enterprise Manager versteht man unter Event- oder Ereignis-Management die Überwachung vorgegebener Schwellenwerte bzw. das Erreichen von harten Grenzen. Ob Sie nun den Enterprise Manager verwenden oder von anderen Herstellern Tools im Einsatz haben, sei Ihnen überlassen. Im Wesentlichen können Sie alle Ressourcen auch über eigene Scripts überwachen. Wichtig ist hierbei nur, dass es je nach Ressource unterschiedliche Zeitintervalle gibt, in denen die Limits erreicht werden können. Nur so kann vermieden werden, dass das Überwachungswerkzeug selbst zu einem Performance-Killer wird. Ein erfolgreicher und nicht nervtötender Einsatz von Ereignissen kann aber nur dann erfolgen, wenn lediglich die wichtigsten Ereignisse gemeldet werden. Es gibt im Oracle Enterprise Manager 9i zurzeit 111 Ereignisse, von denen ca. 10 wirklich wichtig sind. Alle anderen sollten Sie nur unter dem Gesichtspunkt betrachten, dass Sie viel Zeit verwenden werden, um sie an Ihre Bedürfnisse anzupassen.
Sandini Bib
630
Monitoring/Reorganisation
Die Ereignisse im Einzelnen: 1. Datenbankfehler: Neuer Eintrag in der Alert-Datei1
–
Alarm
–
Archivierungsprozess hängt
–
Benutzerblöcke
Blockierende Prozesse (blocking – waiting – lock)2
2. Datenbankplatz: –
Archiv voll
Dateisystem mit archivierten Redolog-Dateien voll
–
Archiv voll (%)
alternativ zu Archiv voll in Prozent statt absoluten Werten
–
Chunk klein
Ein Objekt kann kein neues Extent mehr anlegen3
–
Max. Extents
Maximale Anzahl Extents erreicht
–
Mehrere Extents
Eine bestimmte Grenze von Extents wurde überschritten
–
SnapShot-Log voll
Füllgrad der Snapshot-Log-Tabellen
–
Tablespace voll
Füllgrad eines Tablespaces4
3. Knoten-Platz –
Platte voll
Dateisystem voll
–
Platte voll (%)
alternativ zu Platte voll in Prozent statt absoluten Werten
Alleine diese Ereignisse optimal zu parametrieren, kann für mehrere Datenbanken einige Zeit in Anspruch nehmen. Wichtig sind in diesem Zusammenhang, dass Sie den Parameter Chunk klein und die Extent-Anzahl nur im stündlichen Rhythmus abfragen, die Fehler in der Alert-Datei aber durchaus in 5-Minuten-Intervallen. Sehr schwer einzustellen ist der Parameter Benutzerblöcke (die Übersetzung aus dem Englischen ist hier wohl etwas misslungen, es müsste eigentlich blockierende Benutzerprozesse heißen). Um eine effektive Warnung zu erhalten, sollte das Zeitintervall möglichst kurz gewählt werden, dann wird aber der Performance-Einfluss sehr schnell wachsen. Somit kann dieser Parameter nur für einen bestimmten Zeitraum eingesetzt werden, um die Fehlerursache zu lokalisieren und zu beheben. Im regulären Betrieb muss davon ausgegangen werden, dass diese Fehlerart selten auftritt und dann durch den Anruf des betroffenen Benutzers gemeldet wird.
1. 2. 3. 4.
Es werden alle ora-0006*, 006* und ora-01578 als Alarm ausgegeben, alle anderen ora- werden als Warnung ausgegeben (tcl-Script: alert.tcl). Das Ereignis funktioniert nur, wenn das Script dbms_lock.sql ausgeführt worden ist. Funktioniert nicht bei Locally Managed Tablespaces. Funktioniert nicht bei Tablespaces mit Autoextend.
Sandini Bib
Wie wird beobachtet
631
Abbildung 9.1: Advanced Events
Neben den schon erwähnten Zeitintervallen ist es natürlich auch sinnvoll, die Ereignisse auf bestimmte Objekte einzuschränken. So kann der Parameter CHUNK KLEIN auf die Tablespaces eingeschränkt werden, in denen die Anwendungsdaten liegen, andere Tablespaces, z.B. für ein Repository, werden dann nicht überwacht. Dies verkürzt zum einen die Ausführungszeit und zum anderen wird vermieden, dass uninteressante Ereignisse die wichtigen überlagern. Als problematisch beim Ereignis-Management stellen sich statische Objekte heraus, also Tabellen, die sehr groß sind, aber nicht mehr wachsen (z.B. historische Daten). Sie sollten besser in einen gesonderten Tablespace gelegt werden. Wenn neue Anwendungen mit einer neuen Datenbank aufgesetzt werden, kann es außerdem sinnvoll sein, die Ereignisse für die Ressourcen entsprechend zu überwachen. In der Regel werden diese Parameter zwar großzügig gesetzt, in diesem Fall kann aber durch ungenaue Beschreibungen der Anwendung ein solcher Parameter zu klein gewählt worden sein.
9.2.6
Online-Monitoring
Online-Monitoring kommt oft dann zum Tragen, wenn „das Kind in den Brunnen gefallen ist“! Das heißt, es gibt ein gravierendes Problem in der Datenbank, das dazu führt, dass die Anwender nicht mehr produktiv arbeiten können. Das kann bedeuten, dass tatsächlich eine Tabelle ihre maximale Anzahl von Extents erreicht hat – in diesem Fall hat in der Regel der DBA geschlafen, denn das Problem hätte eigentlich durch einen Alarm frühzeitig gemeldet werden müssen! – oder der Anwender meldet sich mit dem bekannten Satz „Meine Anwendung geht nicht!“. In diesem Fall ist der Administrator darauf angewiesen, entweder möglichst schnell
Sandini Bib
632
Monitoring/Reorganisation
den Engpass zu finden und dann zu beheben oder dem Anwender zu sagen, er möge Geduld haben, da es nun einmal seine Zeit braucht, bis 1 Million Datensätze auf dem Bildschirm dargestellt werden. Die Abfrage geschieht in der Regel auf Basis der virtuellen v$-Tabellen. Zunächst einmal sollte man die entsprechenden Selektionskriterien vom Anwender erfragen (z.B. Schemaname oder Betriebssystembenutzer, Name des Objektes etc.). Mit diesen Informationen lassen sich dann die entsprechenden SQL-Befehle aus der Datenbank mittels der virtuellen Tabelle v$session oder v$sqlarea ermitteln. SQL> SELECT a.sid, a.serial#, a.username, a.schemaname, a.osuser, a.program FROM v$session a WHERE a.schemaname = 'DEMO'; SID SERIAL# USERNAME SCHEMANAME --- ------- --------- ---------8 5 DEMO DEMO 9 7 DEMO DEMO
OSUSER PROGRAM ------------------- -------------HLLAP33\jahrends sqlplus.exe HLLAP33\jahrends TOAD.exe
Listing 9.4: Beispiel v$session
Mit den Informationen aus der virtuellen Tabelle v$session kann dann zum Beispiel ein Tracing der entsprechenden Anwendung durchgeführt werden. SQL> execute dbms_system.set_sql_trace_in_session(8,5,true);
Nachdem
dieses
Package
ausgeführt
wurde,
wird
in
dem
Verzeichnis
user_dump_dest eine Datei erstellt und alle Informationen dieser Sitzung werden
gespeichert. In vielen Datenbanken ist eine Obergrenze für die Dateigröße mit max_dump_file_size vorgegeben, so dass das Tracing spätestens mit Erreichen die-
ser Größe ausgeschaltet wird. Alternativ kann das Tracing mit dem Befehl: SQL> execute dbms_system.set_sql_trace_in_session(8,5,false);
wieder ausgeschaltet werden. Generell sollte man natürlich mit dem Befehl sparsam umgehen, da die Performance darunter leidet und natürlich eine Menge an Informationen entsteht. Als Initialisierungsparameter gibt es für Notfälle auch noch den Parameter sql_trace = true. Da dieser Parameter die gesamte Instanz in den Trace-Modus setzt, kann er nur für kurze Zeit aktiviert werden.
Sandini Bib
Wie wird beobachtet
633
Mit diesen Informationen kann in Verbindung mit den Informationen über das Tuning einer Abfrage (siehe Kapitel 7) eine grobe Aussage über das Zeitverhalten gegeben werden. Zum Beispiel kann mit dem Befehl: tkprof ora_12345.trc out1.tkp explain=demo/demo
eine vorher erstellte Trace-Datei formatiert werden, so dass alle SQL-Befehle mit dem Ausführungsplan und den Statistiken über den CPU-Verbrauch, Plattenzugriffe etc. analysiert werden können. Natürlich kann auch der Enterprise Manager einige dieser Informationen darstellen. Speziell die neu gestaltete Konsole weist eine sehr gute Funktionalität für das Monitoring von einzelnen Sitzungen auf.
Abbildung 9.2: Session-Monitoring mit dem Oracle Enterprise Manager
In diesem Beispiel wird der Ausführungsplan der SQL-Anweisung, die gerade ausgeführt wird, angezeigt. Performance Monitor Wenn Sie das Standard Management Pack nutzen oder das Oracle Diagnostic Pack lizenziert haben, haben Sie die Möglichkeit, ein Online-Monitoring Ihrer Datenbanken mit dem Performance Monitor durchzuführen.
Sandini Bib
634
Monitoring/Reorganisation
Während dieses Werkzeug in der Enterprise Manager Version 2.x noch einen sog. Data Gatherer auf dem Zielsystem benötigte, greift die neue Version auf den Enterprise Manager Agent zu. Das bedeutet aber auch eine Inkompatibilität zwischen den Releases. Für das Arbeiten mit dem Enterprise Manager gilt aber generell, dass auf dem Server die neuesten Komponenten (also Agent oder Management Server) installiert sein sollten. Das kann sehr einfach durch eine Installation in einem neuen ORACLE_HOME erfolgen. Bei dem Einsatz dieses Werkzeuges muss man allerdings genau wissen, welche Informationen relevant sind, da es eine derart große Anzahl an Diagrammen bietet, dass es ansonsten Stunden dauern kann, bis man bei dem richtigen Diagramm angekommen ist. Als erster Einstieg eignen sich hierbei die Diagramme im Verzeichnis ÜBERBLICK LEISTUNG. Interessant ist, dass diese Diagramme die Möglichkeit bieten, über Aufgliederungen Detailinformationen zu erhalten.
ÜBER
Abbildung 9.3: Übersichtsdiagramm Datenbankintegrität
Die hier betrachteten Überwachungswerkzeuge und Ereignisse gelten für eine Standard-Datenbank ohne spezielle Komponenten. Je nachdem, welche zusätzlichen Funktionen der Datenbank genutzt werden (z.B. Replikation, Data Guard) sind zusätzliche Werkzeuge und Ereignisdienste erforderlich.
Sandini Bib
Reparieren/Reorganisieren
9.3
635
Reparieren/Reorganisieren
Bis einschließlich Version 7 gab es keine Möglichkeit, ein Objekt über DDL-Operationen zu reorganisieren. Es wurde von Oracle vorgeschlagen, einen Export/Import durchzuführen, damit wäre die Sache dann erledigt. Mit der Version 8.0 gab es dann zunächst die Möglichkeit eines Index-Rebuild, womit sich die Möglichkeiten der Indexreorganisation schon sehr vereinfacht haben. Die Weiterführung des Online-Rebuild mit Version 8i ist sicherlich für Hochverfügbarkeitssysteme der richtige Weg. Für die Tabellen hat Oracle in der Version 8i ziemlich unscheinbar die Möglichkeit einer Reorganisation über den Befehl ALTER TABLE ... MOVE TABLESPACE ... eingeführt. Offensichtlicher wird dies mit der Online-Reorganisation in Oracle9i. Damit entfällt eigentlich mit Version 9i die Notwendigkeit, irgendwelche Werkzeuge für die Reorganisation einzusetzen. Wirklich? Generell sollte man vermeiden, Daten aus der Datenbank herauszuladen und sie dann wieder zu laden. Zunächst einmal kann es zu Fehlern beim Exportieren kommen (jeder kennt das Problem der fehlenden Umlaute!), und außerdem muss man mit mindestens der doppelten Zeit einer direkten Übertragung rechnen. Daher ist die geeignete Vorgehensweise in den meisten Fällen, die betroffenen Tabellen in einen anderen Tablespace zu verschieben. Dadurch wird zum einen das Oracle Transaktionskonzept genutzt, d.h., es können keine Fehler dadurch auftreten, dass Datensätze fehlen, zum anderen wird dadurch die Zeitdauer minimiert, da nur eine Operation notwendig ist. Im Gegensatz dazu sind beim Export/Import zwei Operationen erforderlich, die beide Zeit brauchen und fehleranfällig sind. Wenn Sie Tabellen im gleichen Tablespace reorganisieren wollen, sollten Sie beachten, dass der Tablespace wahrscheinlich hinterher stärker fragmentiert ist als vorher. Da die anderen Segmente den Platz aufteilen, kann ein einzelnes Objekt oftmals nur am Ende des Tablespaces eingefügt werden (speziell dann, wenn die Extentgrößen neu definiert wurden). Daher sollten Sie überlegen, ob es in solchen Fällen nicht sinnvoller ist, einen neuen Tablespace zu erstellen und alle Segmente in diesen zu verschieben. Anschließend kann der alte Tablespace komplett gelöscht werden. Bevor aber eine Reorganisation durchgeführt wird, sollte eine physikalische Sicherung der gesamten Datenbank durchgeführt werden. Im Folgenden werden jetzt die einzelnen Verfahren für eine Reorganisation besprochen. Dabei unterscheiden sich diese sehr stark anhand der Vorgaben, wie z.B. Oracle-Version, Verwendung von LONG-Feldern und natürlich Einfachheit. Oftmals ist es sinnvoll, die entsprechenden Objekte mit den neuen Parametern separat anzulegen und dann über ein entsprechendes Kommando zu füllen. Oder es ist erforderlich, alle abhängigen Objekte, wie z.B. Indizes, Constraints, Trigger oder Rechte nach einer Reorganisation neu zu erstellen. Für alle diese Aufgaben bietet es sich an, entsprechende Werkzeuge zu benutzen, die die jeweilige Syntax aus der bestehenden Datenbank heraus generieren können.
Sandini Bib
636
Monitoring/Reorganisation
Die Konsole des Enterprise Managers ermöglicht es, ein DDL-Script für eine Tabelle zu erstellen. Leider wird dabei nur die Basisinformation abgespeichert, d.h. Tabellenstruktur und Constraints, nicht jedoch zusätzliche Indizes, Grants und Trigger.
Abbildung 9.4: Objekt-DDL generieren
Wenn Sie das Change Management Pack oder das Standard Management Pack nutzen, können Sie auch das Werkzeug Datenbankobjekte erfassen (DB-Capture) nutzen, um das entsprechende DDL-Script zu generieren. Hierbei können zwar die Rechte mit generiert werden, die Indizes und Trigger werden jedoch trotz einer entsprechenden Anzeige nicht erzeugt. Alternativ kann das Produkt TOAD der Firma Quest Inc. für die Erstellung von SQLScripts genutzt werden. Dieses Werkzeug kann ein Script erstellen, das alle notwendigen Informationen zum Wiederaufbau einer Tabelle enthält.
Sandini Bib
Reparieren/Reorganisieren
637
Abbildung 9.5: DDL-Generierung mit TOAD
Natürlich gibt es noch eine ganze Reihe anderer Verfahren, mit deren Hilfe man sich die entsprechenden DDL-Scripts erstellen kann. Wichtig ist nur, dass das Script vor dem ersten Einsatz ausführlich getestet wird, um sicherzustellen, dass alle notwendigen Informationen generiert werden.
9.3.1
Export/Import
Diese uralten Oracle-Kommandos sind sicherlich für viele immer noch die wichtigsten, wenn es um Reorganisationen geht, da es kein Werkzeug gibt, das unkomplizierter ist – wenn man gewisse Regeln einhält. Allerdings ist es die langsamste Methode. Auch wenn der Export über den Direct Path noch recht schnell ist, der Import kann durchaus die doppelte Zeit verbrauchen. Bei einem Export werden oftmals sehr große Dateien erzeugt, die u.U. die maximale Dateigröße überschreiten. Dies kann durch die Aufteilung der Tabellen oder durch die Benutzung von WHERE-Klauseln für einzelne Tabellen vermieden werden. Man sollte sich jedoch überlegen, ob es dann nicht sinnvoller ist, eine größere Partition für die Dump-Datei zur Verfügung zu stellen bzw. ein System einzusetzen, das keine Begrenzung hinsichtlich der Dateigrößen hat.
Sandini Bib
638
Monitoring/Reorganisation
Sinnvoll ist der Einsatz des Export/Import immer dann, wenn LONG- oder LONGRAWFelder eingesetzt werden oder wenn die komplette Datenbank reorganisiert werden soll, da hierbei auch die Constraints, Indizes, Grants und PL/SQL-Prozeduren neu aufgebaut werden. Hier kann es dann auch hilfreich sein, die Daten über NamedPipes von einer in eine andere Datenbank zu verschieben. Die Benutzung von Pipes ist im Kapitel 6.2 bereits beschrieben worden. Vorsicht ist geboten, wenn über ein Script exportiert, gelöscht und wieder importiert wird. Wie schon beim alten Tablespace Manager im Oracle Enterprise Manager (bis OEM Version 1.5) kann es dabei zu dem Problem kommen, dass beim Export etwas schief geht (z.B. nicht genügend Platz), die Tabelle dann aber gelöscht wird und der Import natürlich ebenfalls nicht funktioniert. Bei der Verwendung des Export/Imports sollte Folgendes beachtet werden: 1. Verwenden Sie kein COMPRESS, da dadurch beim Import die Tabelle wieder mit mindestens der gleichen Größe angelegt wird, die sie auch beim Export hatte. Sehr problematisch wird dies im Zusammenspiel mit den Dictionary Managed Tablespaces, da hier ein Extent mit der Gesamtgröße der Tabelle angelegt wird. Wenn die Tabelle die Größe einer Datendatei übersteigt, können Sie die Tabelle nicht wieder importieren. Dieses Problem gibt es zwar bei Locally Managed Tablespaces nicht, allerdings werden entsprechend viele kleine Extents angelegt. 2. Am besten erstellen Sie die Tabelle vor dem Import mit einem entsprechenden Script und setzen den Import-Parameter IGNORE=YES. 3. Setzen Sie vor dem Import die sort_area_size auf einen entsprechend großen Wert, da hierdurch der Aufbau von Indizes wesentlich beschleunigt werden kann. Vergessen Sie aber nicht, ihn anschließend wieder zurückzunehmen. SQL> ALTER SYSTEM SET sort_area_size = 100000000 DEFERRED;
4. Alternativ
kann
hierzu
in
der
Version
9i
auch
der
Parameter
pga_aggregate_target genutzt bzw. vergrößert werden.
SQL> ALTER SYSTEM SET pga_aggregate_target = 20M;
Damit sollte ein Export/Import in einer akzeptablen Zeit durchführbar sein. Beachten Sie aber bitte auch die bereits in Kapitel 6.2 beschriebenen Parameter.
9.3.2
CREATE TABLE ... AS SELECT ... (CTAS)
Dieser Befehl ist sicherlich der schnellste Weg, eine Tabelle zu reorganisieren. Allerdings sollte das Ganze in einem Tool eingebettet sein, da ja auch die zugehörigen Indizes, Constraints, Trigger etc. neu aufgebaut werden müssen. Ein großer Vorteil dieses Befehls sind die Optionen NOLOGGING und PARALLEL, mit denen die Protokollierung ausgeschaltet werden kann und alle zur Verfügung stehenden Ressourcen genutzt werden können. Wenn Sie die Option NOLOGGING nutzen, sollten Sie Folgendes beachten: 1. Wenn die Datenbank im NOARCHIVELOG-Modus betrieben wird, wird dieser Befehl nicht protokolliert.
Sandini Bib
Reparieren/Reorganisieren
639
2. Wird die Datenbank im ARCHIVELOG-Modus betrieben, dann wird nur der Befehl protokolliert, aber nicht die eingefügten Daten. 3. Die Option wird ignoriert, wenn die Daten von einer anderen Datenbank über einen Datenbank-Link gelesen werden. RENAME kunden TO kunden_alt; CREATE TABLE kunden_neu TABLESPACE users STORAGE (INITIAL 1M NEXT 1M PCTINCREASE 0) AS SELECT /*+ PARALLEL 4 */ * FROM ( SELECT /*+ PARALLEL 4 */ * FROM kunden_alt ORDER BY nachname) NOLOGGING; ALTER TABLE kunden_alt DROP CONSTRAINT pk_kunden; ALTER TABLE kunden_neu ADD CONSTRAINT pk_kunden PRIMARY KEY ( kdnr ) USING INDEX TABLESPACE demo PCTFREE 10 STORAGE ( INITIAL 1M NEXT 1M)); CREATE INDEX demo.idx_ort_neu ON demo.kunden(ort, plz) TABLESPACE demo STORAGE(INITIAL 1M NEXT 1M) NOLOGGING; RENAME kunden_alt TO kunden; GRANT SELECT ON kunden TO heyo; Listing 9.5: CREATE-TABLE-AS-SELECT mit Sortierung der Tabelle
In diesem Beispiel wird die Tabelle kunden in einem neuen Tablespace aufgebaut. Außerdem wird sie während der Erstellung nach nachname sortiert, um einen schnelleren Zugriff für bestimmte Abfragen zu erhalten. Bei größeren Tabellen empfiehlt es sich, vor der Ausführung die sort_area_size bzw. pga_aggregate_target entsprechend zu setzen. Vorsicht bei der gleichzeitigen Verwendung der Option parallel! Hier kann je Prozess die sort_area_size verwendet werden, d.h., Sie sollten bedenken, dass der maximal verwendete Hauptspeicher parallel * sort_area_size werden kann. Dadurch, dass zunächst die ursprüngliche Tabelle kunden in kunden_alt umbenannt wurde und erst als letztes die neue Tabelle kunden_neu wieder in kunden geändert wird, kann man sich ein Sperren der Tabelle während der Operation sparen.
Sandini Bib
640
9.3.3
Monitoring/Reorganisation
SQL*Plus-Befehl COPY
Dieser SQL*Plus-Befehl ist sehr simpel und kann anstelle des Befehls CTAS bei kleinen Tabellen eingesetzt werden. Die Möglichkeiten sind allerdings sehr beschränkt, so dass es sicherlich effektiver ist, bei größeren Tabellen auf das CTAS zurückzugreifen.
9.3.4
REBUILD INDEX
Dieser mit der Version 8.0 eingeführte und mit der Version 8i um eine OnlineKomponente erweiterte Befehl ermöglicht es sehr effektiv, einen Index auf einen bereits bestehenden aufzubauen. Vorteil ist zunächst einmal die Geschwindigkeit, da die Datensätze nicht mehr neu sortiert werden müssen, und zum anderen die Möglichkeit, während eines Rebuild neue Parameter wie zum Beispiel einen neuen Tablespace anzugeben. Leider funktioniert der Rebuild in der Version 8i nur für normale Indizes, nicht aber für Function-based Indexes. Der Befehl zum Online Rebuild eines Indexes unter Version 9i kann z.B. so aussehen: SQL> ALTER INDEX idx_kdname REBUILD TABLESPACE indx STORAGE (INITIAL 1M NEXT 1M) ONLINE NOLOGGING; Listing 9.6: Online Index Rebuild
9.3.5
MOVE TABLESPACE
Dieser mit der Version 8i eingeführte Befehl erlaubt es, Tabellen von einem in einen anderen Tablespace zu verlagern ohne dabei Indizes, Constraints oder Ähnliches neu aufzubauen. Damit ist ein effektiver Weg gegeben, Tabellen inkl. Storage-Klauseln zu reorganisieren. Einziger Nachteil dieses Scripts ist, dass hierfür die Tabelle gesperrt werden muss, d.h., die Anwendung kann für die Dauer nicht genutzt werden. Außerdem besteht keine Möglichkeit einer Parallelisierung oder des Ausschaltens von Redolog Informationen. Der Befehl kann nicht auf Tabellen mit LONG-Feldern eingesetzt werden. Der gesamte Befehl kann lauten: SQL> ALTER TABLE kunden MOVE TABLESPACE demo;
Nachdem dieser Befehl durchgeführt worden ist, müssen nur noch die Indizes mit einem Rebuild neu aufgebaut werden.
Sandini Bib
Reparieren/Reorganisieren
9.3.6
641
Online-Table-Reorganisation
Mit Version 9i hat Oracle angekündigt, dass es die Möglichkeit gibt, Tabellen online zu reorganisieren. Ursprünglich gab es Informationen, dass dies mit der Erweiterung des Befehls: ALTER TABLE MOVE TABLESPACE ONLINE funktioniert. Diesen Befehl gab es in Oracle8i schon, mit der Einschränkung, dass er nur für IOTs (Index-Organized Tables) funktioniert. Leider ist dem nicht so! Stattdessen gibt es ein Package dbms_redefinition, dass die Möglichkeit eröffnen soll, eine neue Tabelle als Kopie der Originaltabelle aufzubauen, die Kopie wird synchronisiert, und dann wird der Eintrag im Data Dictionary auf den neuen Tabellennamen geändert. Das bedeutet, dass alle Indizes, Constraints, Trigger, etc. neu aufgebaut werden müssen. Die Funktionalität basiert auf den Materialized Views. Das folgende Beispiel zeigt eine Online-Reorganisation der Tabelle kunden, die während der Reorganisation von einem Tablespace in einen anderen verlagert wird: 1. Überprüfung, ob die Tabelle online reorganisiert werden kann: execute dbms_redefinition.can_redef_table('DEMO','KUNDEN');
2. Erstellen einer neuen Tabelle als Kopie der Originaltabelle, hierbei ist es möglich, Spalten zu ändern oder sogar wegzulassen: CREATE TABLE x_kunden TABLESPACE users AS SELECT * FROM kunden WHERE ROWNUM < 1;
3. Starten des Kopiervorgangs von der Originaltabelle kunden in die Zieltabelle x_kunden: execute dbms_redefinition.start_redef_table ('DEMO','KUNDEN','X_KUNDEN');
4. Aufbau der Constraints für die neue Tabelle: ALTER TABLE x_kunden ADD CONSTRAINT pk_kunden_x PRIMARY KEY (KDNR); ALTER TABLE auftrag ADD CONSTRAINT fk_kunden_kdnr_x FOREIGN KEY (kdnr) REFERENCES demo.x_kunden (KDNR) ;
5. Beenden des Kopiervorgangs: execute dbms_redefinition.finish_redef_table ('DEMO','KUNDEN','X_KUNDEN');
Mit dem Beenden des Kopiervorgangs werden die Namen der Originaltabelle und der Reorganisierten vertauscht und eventuelle Foreign-Key-Constraints auf die alte Tabelle werden ausgeschaltet. Dieser Schritt bedingt eine kurzzeitige Sperre der Tabelle, kann jedoch zu beliebiger Zeit ausgeführt werden.
Sandini Bib
642
9.3.7
Monitoring/Reorganisation
Oracle Enterprise Manager-Reorganisationen
Wenn Sie das Oracle Enterprise Manager Tuning Pack lizenziert haben, haben Sie mit dem Reoganisations-Assistenten und dem Tablespace-Map zwei grafische Werkzeuge für die Durchführung von Reorganisationen. Der Reorganisations-Assistent wird über die Enterprise Manager-Konsole aufgerufen, wobei der zu reorganisierende Tablespace bereits angewählt sein muss. Über einen sogenannten Scratch-Tablespace werden dann alle Objekte mit den notwendigen Befehlen in diesen Tablespace verschoben und anschließend wieder in den ursprünglichen Tablespace zurück. Das generierte Script kann dann als TCL-Job über den Oracle Agent sofort oder zu einem späteren Zeitpunkt ausgeführt werden. Es ist zwar möglich, das Script auch als HTML-Datei abzulegen, in dieser Datei fehlen aber die generierten PL/SQLAnweisungen für das Verschieben von Tabellen mit LONG-Spalten. Merkwürdigerweise werden in dem Script zunächst die Indizes mit einem Rebuild in den Zwischen-Tablespace verschoben. Durch die anschließende Verschiebung der Tabellen werden diese dann aber wieder unbrauchbar. Leider ist es nicht möglich, mit dem Reorganisations-Assistenten ein anderes Verfahren (z.B. CREATE-TABLE-AS-SELECT) durchzuführen oder den Index-Rebuild zunächst wegzulassen. Alternativ zum Reorganisations-Assistenten kann über den Punkt TABLESPACE-MAP eine echte Analyse und Reorganisation einzelner Objekte durchgeführt werden.
ANZEIGEN
Bei der Analyse werden folgende Parameter berücksichtigt:
: :
: : :
Segmente mit mehr als 1.024 Extents (nicht bei Locally Managed Tablespaces) Segmente, die nur noch ein Extents bis zu MAXEXTENTS allokieren können (nicht bei Locally Managed Tablespaces) Nicht ausreichend freier Platz im Tablespace (nicht bei AUTOEXTEND ON) Segmente mit mehr als 10 % Zeilenverkettungen (Chained-Rows) Fragmentierte Indizes
Die hier aufgeführten Werte sind die Standardwerte, die entsprechend den Anforderungen über den Menüpunkt TABLESPACE-ANALYSE-OPTIONEN angepasst werden können. Nach der Analyse können dann Objekte für die Reorganisation ausgewählt werden. In diesem Schritt ist es möglich, ein Objekt in ein anderes Tablespace zu verschieben oder andere Parameter wie zum Beispiel die Storage Klauseln zu ändern. Die zu reorganisierenden Objekte können dann im laufenden Betrieb über das Package dbms_redefinition oder mit einer Tabellensperre über den Befehl MOVE TABLESPACE verschoben werden.
Sandini Bib
Reparieren/Reorganisieren
643
Interessanterweise wird auch bei der Online-Reorganisation eine Tabellensperre gesetzt, und zwar, um die Indizes, die für die neue Tabelle erstellt werden, umzubenennen. Da die ganze Verarbeitung sequentiell, d.h. Tabelle für Tabelle, durchgeführt wird, bedeutet dies, dass zwischenzeitlich immer wieder Tabellen-Sperren aufgebaut werden, was eine echte Online-Reorganisation unmöglich macht. Da aber die Umbenennung der Indizes sehr schnell geht, kann in einer Zeit mit niedriger Systemlast davon ausgegangen werden, dass die Reorganisation durchläuft. Da das Prinzip der Online-Reorganisation auf Snapshots bzw. Materialized Views basiert, ist die gesamte Verarbeitung als performancekritisch zu betrachten und sollte deshalb in einer Zeit durchgeführt werden, in der keine umfangreichen Operationen laufen.
Sandini Bib
Sandini Bib
10
Neue Technologien
10.1 Objektrelationale Datenstrukturen Das Oracle-Datenbanksystem unterstützt seit Oracle8 (Release 8.0) neben den relationalen Datenstrukturen auch objektrelationale (OR) Strukturen. Daher wird es auch als ORDBMS (Object-Relational Data Base Management System) bezeichnet. Die Tatsache, dass die OR-Technologie bei Oracle8 als kostenpflichtige Object Option vertrieben wurde, sowie einige fehlende Eigenschaften der OR-Datentypen, wie z.B. die Vererbung, haben zunächst dazu geführt, dass OR-Datenmodelle keine weite Verbreitung gefunden haben. Mit Oracle8i wurde dann der Umstand beseitigt, dass die Object Option Zusatzkosten verursacht, indem sie in alle Editionen integriert wurde. Dies ist sicherlich u.a. dadurch begründet, dass weitere Optionen, wie z.B. Advanced Queueing, für gewisse Funktionen die Object Option voraussetzt. Mit Oracle9i wurde dann zusätzlich das OR-Modell umfangreich erweitert. Damit sind einige der oft vorgebrachten Argumente gegen OR-Modellierung und -Programmierung im Oracle-Umfeld beseitigt worden. Eine kurze Bemerkung zum Thema dieses Kapitels: Dies ist nicht etwa eine Einführung in die objektorientierte bzw. objektrelationale Datenmodellierung! Dieses Thema ist für sich bereits so umfangreich, dass dieses Buch keinen Platz mehr für andere Themen hätte. Im Folgenden soll eine Übersicht über die in Oracle9i vorhandenen OR-Features vermittelt werden, so dass Experten eine bessere Abschätzung darüber leisten können, ob der Einzug von OO-Technologie in den Datenbankserver in ihrem aktuellen Projekt sinnvoll ist, und OO-Neulinge einen Einstieg bekommen, der eventuell Lust auf ein Buch über OO-Modellierung und -Programmierung macht.
10.1.1 Objekttypen Das OR-Modell der Oracle-Datenbank basiert zunächst auf der Erzeugung von Objekttypen. Im einfachsten Fall werden mit deren Hilfe Tabellen aufgebaut. Im folgenden Beispiel wird ein Objekttyp telefon_t erzeugt, auf dessen Basis dann eine Objekttabelle telefon_tab1 erstellt wird: CREATE TYPE telefon_t AS OBJECT ( typ VARCHAR2(10), nr VARCHAR2(20) ) /
Sandini Bib
646
Neue Technologien
CREATE TABLE telefon_tab1 OF telefon_t / Listing 10.1: Anlegen einer einfachen Objekttabelle
Dabei sind zunächst als Attributtypen für Objekttypen die gängigen skalaren OracleTypen möglich. Allerdings können Objekttypen auch verschachtelt werden, d.h., neben den skalaren Typen sind in Objekttypdefinitionen auch selbst definierte Objekttypen erlaubt. Die oben erstellte Tabelle kann man einerseits als Tabelle mit einer Spalte des definierten Objekttyps telefon_t betrachten, andererseits als zweispaltige „flache“ Tabelle. Beides ist mit INSERT-Befehlen nachzuvollziehen: INSERT INTO telefon_tab1 VALUES (telefon_t('Mobil', '0170/1234567')) / INSERT INTO telefon_tab1 VALUES ('ISDN', '099/9876543') / Listing 10.2: Einfügen von Daten in eine Objekttabelle
Der erste INSERT-Befehl verwendet hierbei bereits den automatisch mit dem Objekttyp erstellten Konstruktor telefon_t(), der als Parameter eine Liste von passenden Attributwerten bekommt und daraus ein Objekt des angegebenen Typs erzeugt (instantiiert). Ähnlich flexibel verhält es sich mit der Abfrage. Ein „flaches“ SELECT erzeugt das Bild einer zweispaltigen Tabelle: SELECT * FROM telefon_tab1 / TYP NR ---------- -------------------Mobil 0170/1234567 ISDN 099/9876543 Listing 10.3: Lesen von Daten aus einer Objekttabelle
Sandini Bib
Objektrelationale Datenstrukturen
647
Mit der VALUE-Funktion lässt sich die Ausgabe jedoch einfach in ein Format bringen, das der OR-Sicht entspricht: SELECT VALUE(t) FROM telefon_tab1 t / VALUE(T)(TYP, NR) ------------------------------------------------------TELEFON_T('Mobil', '0170/1234567') TELEFON_T('ISDN', '099/9876543') Listing 10.4: Lesen von Daten aus einer Objekttabelle
Die VALUE-Funktion nimmt als Parameter den Alias einer Objekttabelle und liefert entsprechende Instanzen des Objekttyps als Ergebnis. Eine der wichtigsten Eigenschaften des OR-Modells ist die Definition von Collections, d.h. Datentypen, die eine endliche Menge von Objekten gleichen Typs enthalten. Eine Möglichkeit hierzu sind Nested Tables, bei denen zunächst aus einem Basistyp oder einem bereits bestehenden Datentyp ein TABLE-Typ erzeugt wird: CREATE TYPE telefon_tab_t AS TABLE OF telefon_t /
Der Objekttyp telefon_tab_t kann beim Erstellen einer Tabelle als Attributtyp verwendet werden, d.h., die Objekttypen werden hier verschachtelt: CREATE TYPE person_t AS OBJECT ( id NUMBER(5,0, name VARCHAR2(30), vorname VARCHAR2(30), adresse adresse_va, telefon telefon_tab_t ) / Listing 10.5: Geschachtelte Objekttypen
Bei der Speicherung der Objekttabelle werden Nested Tables als eigenes Segment gespeichert. In der Objektbetrachtung hat dabei jedes Objekt der Haupttabelle als Attribut eine eigene Nested Table; physikalisch werden jedoch alle Instanzen in einem Segment abgelegt. In obigem Beispiel wird zusätzlich der Objekttyp adresse_va verwendet, der wie folgt definiert ist: CREATE TYPE adresse_t AS OBJECT ( strasse VARCHAR2(30), hausnr VARCHAR2(5),
Sandini Bib
648
Neue Technologien
plz VARCHAR2(5), ort VARCHAR2(30), staat VARCHAR2(30), region VARCHAR2(30) ) / CREATE TYPE adresse_va AS VARRAY(5) OF adresse_t / Listing 10.6: VARRAY
Beim Objekttyp adresse_va wurde die zweite für Oracle gültige Möglichkeit eines Collection-Typs (neben den Nested Tables), das Varray, verwendet. Hierbei steht Varray für Variable Size Array, d.h. ein Array mit variabler Anzahl von Elementen. Es muss allerdings eine maximale Anzahl angegeben werden. Varrays werden i.A. inline gespeichert, also nicht in einem eigenen Segment wie Nested Tables. Erst bei einer entsprechenden Größe werden Varrays als BLOBs behandelt und damit wieder in einem eigenen Segment gespeichert. Ein INSERT-Befehl für eine nunmehr verschachtelt aufgebaute Objekttabelle sieht z.B. wie folgt aus: INSERT INTO person_tab VALUES (person_t(1, 'Unbescheid', 'Günter', adresse_t('Holzweg', '77', '99999', 'Dorf', 'Deutschland', NULL ), telefon_tab_t(telefon_t('Mobil', '0777/1234567'), telefon_t('Büro', '09999/987654321') ) ) ) / Listing 10.7: Einfügen von Datensätzen in eine geschachtelte Objekttabelle
Entsprechend können die Daten wieder ausgelesen werden: SELECT * FROM person_tab / ID NAME, VORNAME -----------------------------------------------------------ADRESSE(STRASSE, HAUSNR, PLZ, ORT, STAAT, REGION) -----------------------------------------------------------TELEFON(TYP, NR) -----------------------------------------------------------1 Unbescheid Günter
Sandini Bib
Objektrelationale Datenstrukturen
649
ADRESSE_VA(ADRESSE_T('Holzweg', '77', '99999', 'Dorf', 'Deutschland', NULL)) TELEFON_TAB_T(TELEFON_T('Mobil', '0777/1234567'), TELEFON_T('Büro', '09999/987654321')) Listing 10.8: Lesen von Datensätzen aus einer geschachtelten Objekttabelle
Spezielle Abfragen sehen nunmehr etwas ungewöhnlich aus (für relationale Verhältnisse), da z.B. für die Frage „Welche Mobil-Nr. hat Herr Unbescheid?“ folgendes Konstrukt benutzt wird: SELECT nr FROM TABLE (SELECT telefon FROM person_tab WHERE name = 'Unbescheid') WHERE typ = 'Mobil' / NR -------------------0777/1234567 Listing 10.9: Lesen von Datensätzen aus einer geschachtelten Objekttabelle
Wie man leicht erkennen kann, hat die Verschachtelung der Datentypen in vielen Fällen eine Verschachtelung der SQL-Befehle zur Folge. Die innere SQL-Abfrage (innerhalb der Klammern) liefert die Nested Table mit den Telefonnummern von Herrn Unbescheid, die äußere sucht sich entsprechend die Mobil-Nummer. Die Frage nach allen Telefonnummern von Herrn Unbescheid kann jedoch auch einfach mit der inneren SQL-Abfrage gelöst werden und hat dann folgendes Ergebnis: TELEFON(TYP, NR) -----------------------------------------------------------------TELEFON_TAB_T(TELEFON_T('Mobil', '0777/1234567'), TELEFON_T('Büro', '09999/987654321'))
10.1.2 Vererbung Ein Thema, das erst mit Oracle9i in die Datenbank Einzug gehalten hat, ist die Vererbung. Hierbei ist es möglich, Subtypen für bereits bestehende Objekttypen zu erstellen. Hierzu müssen diese Objekttypen den Status NOT FINAL haben, wobei FINAL der Standardwert für neu erstellte Objekttypen – und natürlich der einzig mögliche Wert in der Oracle8i-Welt – ist. Der Status ist über ein ALTER TYPE-Kommando änderbar: ALTER TYPE person_t NOT FINAL /
Sandini Bib
650
Neue Technologien
Hier gelten allerdings Einschränkungen, wenn bereits Tabellen existieren, die auf diesem Objekttyp aufgebaut sind. Hier müssen dann alle Datensätze (bzw. Objektinstanzen) revalidiert werden, was bei Tests auch schon einmal nicht funktioniert hat. Falls man also mit Vererbung arbeiten möchte, ist es sinnvoll, von vorneherein alle Objekttypen als NOT FINAL zu definieren. Die Definition eines Subtyps erfolgt z.B. wie folgt: CREATE TYPE emp_t UNDER person_t ( empid NUMBER(5,0), mgr REF emp_t ) / Listing 10.10: Definition eines Subtyps
Hiermit erbt der Subtyp emp_t alle Attribute des Supertyps person_t und wird durch die beiden Attribute empid und mgr ergänzt. In die bereits erstellte Tabelle person_tab können nun auch Objekte des Typs emp_t eingefügt werden: INSERT INTO person_tab VALUES (emp_t(2, 'Ahrends', 'Johannes', adresse_va(adresse_t('Holzweg', '77', '99999', 'Dorf', 'Deutschland', NULL)), telefon_tab_t(telefon_t('Mobil', '0777/1234567'), telefon_t('Büro', '09999/987654321') ), 101, NULL ) ) / Listing 10.11: Einfügen von Sätzen des Subtyps
Bei einer allgemeinen Abfrage der Tabelle person_tab erhält man nun alle Objekte vom Typ person_t; allerdings kann man sich auch mit der VALUE-Funktion weiterhelfen: SELECT VALUE(p) FROM person_tab p WHERE p.name = 'Ahrends' / VALUE(P)(ID, NAME, VORNAME -----------------------------------------------------------ADRESSE(STRASSE, HAUSNR, PLZ, ORT, STAAT, REGION) -----------------------------------------------------------TELEFON(TYP, NR) ------------------------------------------------------------
Sandini Bib
Objektrelationale Datenstrukturen
651
EMP_T(2, 'Ahrends', 'Johannes', ADRESSE_VA(ADRESSE_T ('Holzweg', '77', '99999', 'Dorf', 'Deutschland', NULL)), TELEFON_TAB_T(TELEFON_T('Mobil', '0777/1234567'), TELEFON_T('Büro', '09999/987654321')), 101, NULL) Listing 10.12: Lesen von Sätzen des Subtyps
10.1.3 REFs Bei der Definition des Subtyps emp_t ist gleich ein weiterer wichtiger Aspekt der OR-Datenmodellierung eingeführt worden: der REF-Datentyp, der einem Zeiger (pointer) entspricht. Solche Zeiger erlauben die Navigation innerhalb eines ORDatenmodells, indem man den Zeigern über die DEREF-Funktion folgt. REFs werden manchmal mit Fremdschlüssel-Constraints verglichen, da sie für die logischen Verbindungen zwischen Objektinstanzen zuständig sind. Im Gegensatz zur logischen Struktur der Fremdschlüssel sind sie jedoch reine Zeigerstrukturen, die allerdings streng getypt sind. Durch die Verwendung der Funktion REF auf ein Objekt kann der Zeiger auf das Objekt abgefragt werden. SELECT REF(p) FROM person_tab p WHERE p.id = 2; REF(P) -------------------------------------------------------------------------------------0000280209279C381A2D5E46F9A574D73841B63C9F1A0067047EA443419D5CD118D0A6F9FC00C007220002 Listing 10.13: REF
Die Länge eines REFs hängt von einigen Faktoren ab, als Minimum gilt 16 Bytes. Die REF-Funktion liefert sowohl Zeiger auf den Typ der oben angegebenen Tabelle als auch Zeiger auf alle definierten Subtypen. Standardmäßig wird als Typ der Tabellentyp bzw. Zeiger auf den Tabellentyp (REF person_t) angenommen. Durch die TREAT-Funktion kann der Ergebnisdatentyp so manipuliert werden, dass z.B. ein bestimmter Subtyp ausgegeben wird. Der Ausdruck REF(p) aus obiger SELECT-Liste würde z.B. TREAT(REF(p) AS REF emp_t)
heißen, wenn man als Ergebnistyp einen Zeiger auf den Subtyp emp_t voraussetzt. Das Ergebnis ist im Übrigen das gleiche, da es sich um einen physischen Zeiger handelt. Die TREAT-Funktion behandelt nicht nur REF-Typen, sondern auch normale Objekttypen, d.h., sie kann auch in Ausdrücken wie TREAT(VALUE(p) AS emp_t) verwendet werden.
Sandini Bib
652
Neue Technologien
10.1.4 Methoden Der in objektorientierten Modellen geübte Leser möge dem Autoren dieses Kapitels nachsehen, dass sich die Betrachtungen bisher auf die Datenstrukturen der objektrelationalen Modellierung konzentriert haben, wo doch die Einheit von Daten und Funktionen in objektorientierten Modellen einer der zentralen Aspekte überhaupt ist. Da dies bei relationalen Systemen nun einmal anders ist, sind die ersten Seiten des OR-Kapitels aus reiner Gewohnheit den Datenstrukturen gewidmet. Auch an dieser Stelle zeigt sich das Oracle-OR-Modell als recht vollständig, da man die Möglichkeit hat, bei der Definition des Objekttyps dessen Methoden (member methods) mitzudefinieren. Eine Standardmethode wurde weiter oben bereits implizit eingeführt: der identisch zum Typ benannte Konstruktor, der z.B. beim INSERT benutzt wird, um eine Objektinstanz zu erzeugen. Als Parameter besitzt der Konstruktor alle Attribute eines Objekttyps bzw. eine Liste von Objekten gleicher Art bei Nested Tables und Varrays. Die Methoden eines Objekttyps beziehen sich meist auf eine Objektinstanz und werden mit .<methode>(<param1>, ..., <paramN>)
aufgerufen, wobei die Klammern zwingend erforderlich sind. Auf die Attribute der aktuellen Objektinstanz kann entweder durch die Attributnamen oder den Ausdruck SELF. zugegriffen werden. Im folgenden Beispiel wird der Objekttyp emp_t um die Methode set_mgr erweitert, die einen entsprechenden Zeiger (auf den Manager des Mitarbeiters) setzt. Zunächst wird in der TYPE-Definition die Methode set_mgr deklariert: CREATE TYPE emp_t UNDER person_t ( empid NUMBER(5,0), mgr REF emp_t, MEMBER PROCEDURE set_mgr(ref_emp IN REF emp_t) ) / Listing 10.14: Erstellen einer Methode
In der nunmehr zusätzlich erforderlichen TYPE BODY-Definition wird die Methode ausprogrammiert: CREATE TYPE BODY emp_t AS MEMBER PROCEDURE set_mgr(ref_emp IN REF emp_t) AS BEGIN SELF.mgr := ref_emp; END; END; / Listing 10.15: Programmierung der Methode
Sandini Bib
Objektrelationale Datenstrukturen
653
Spätestens ab dieser Stelle befinden wir uns mitten in der PL/SQL-Programmierung, bei der zwei kurze Hinweise genereller Art angebracht sind: 1. Statt des Befehls CREATE kann auch CREATE OR REPLACE verwendet werden. Im Gegensatz zu CREATE schlägt letzterer nicht fehl, falls das zu erstellende Objekt bereits existiert. Es bleiben zudem alle abhängigen Definitionen, wie z.B. Objektprivilegien, erhalten. 2. Falls die Kommandos als Scripts in SQL*Plus ausgeführt werden, empfiehlt es sich, hinter jedem CREATE- oder ALTER-Kommando das SQL*Plus-Kommando SHOW ERROR auszuführen. Falls das Kommando nicht fehlerhaft ist, dürfte die Antwort No errors. nicht weiter stören, falls doch, bekommt man statt des wenig aussagekräftigen Type created with compilation errors noch die genaue Fehlerspezifikation. Im folgenden Programmierbeispiel wird die eben definierte Methode verwendet. Als Eingabeparameter erhält die Prozedur die ID des Mitarbeiters, dessen MGR-Attribut gesetzt werden soll, und die ID des Managers. In der Prozedur werden zunächst über die gegebenen IDs Zeiger vom Typ emp_t selektiert. Um das entsprechende Objekt zu sperren und zu selektieren, wird die Prozedur lock_object aus dem Paket utl_ref benutzt. Über die Methode set_mgr wird das Objekt dann manipuliert und mit utl_ref.update_object in die Datenbank zurückgeschrieben. Die Prozeduren lock_object und update_object entsprechen in etwa den Befehlen SELECT ... FOR UPDATE und UPDATE für relationale Tabellen. CREATE OR REPLACE PROCEDURE set_mgr (p_emp_id IN NUMBER, p_mgr_id IN NUMBER) AS r_emp REF emp_t; r_mgr REF emp_t; v_emp emp_t; BEGIN --- REF des Mitarbeiters selektieren -SELECT TREAT(REF(p) AS REF emp_t) INTO r_emp FROM person_tab p WHERE p.id = p_emp_id; --- REF des Managers selektieren -SELECT TREAT(REF(p) AS REF emp_t) INTO r_mgr FROM person_tab p WHERE p.id = p_mgr_id; --- Objektinstanz des Mitarbeiters sperren und holen,
Sandini Bib
654
Neue Technologien
-- mit dem REF des Managers verändern und -- zurückschreiben -UTL_REF.LOCK_OBJECT(r_emp, v_emp); v_emp.set_mgr(r_mgr); -- Methode UTL_REF.UPDATE_OBJECT(r_emp, v_emp); END; / Listing 10.16: Erstellen einer Prozedur mit einer Methode
Diese Prozedur kann z.B. mit EXECUTE set_mgr(2, 3)
aufgerufen werden. Die hiermit implizit geöffnete Transaktion muss im Folgenden noch mit COMMIT oder ROLLBACK beendet werden. Die identische Namensgebung sowohl der Prozedur als auch der Methode mit set_mgr ist absichtlich vorgenommen worden, um auch im praktischen Beispiel zu zeigen, dass allein durch den Aufruf jederzeit eindeutig bestimmt wird, ob die Prozedur oder die Methode gemeint ist. Überschreiben von Methoden Wenn eine Methode im Subtyp anders definiert sein soll als im Supertyp, so kann dies durch Überschreiben (overriding) realisiert werden. Die Methode wird dabei sowohl im Subtyp als auch im Supertyp definiert. Da das Überladen von Methoden in der gleichen Art und Weise wie bei Prozeduren und Funktionen möglich ist, muss beim Überschreiben der Methoden darauf geachtet werden, deren Typsignatur nicht zu verändern. Wenn eine Methode überschrieben wird, muss dies durch das Schlüsselwort OVERRIDING angezeigt werden. Im folgenden Beispiel wird die Methode set_name am Objekttyp person_t definiert und am Subtyp emp_t überschrieben: CREATE TYPE person_t AS OBJECT ( id NUMBER(5,0), name VARCHAR2(30), vorname VARCHAR2(30), adresse adresse_va, telefon telefon_tab_t, MEMBER procedure set_name(new_name IN VARCHAR2), ) NOT FINAL / CREATE TYPE BODY person_t AS MEMBER PROCEDURE set_name(new_name IN VARCHAR2)
Sandini Bib
Objektrelationale Datenstrukturen
655
AS BEGIN SELF.name := new_name; END; END; / CREATE TYPE emp_t UNDER person_t ( empid NUMBER(5,0), mgr REF emp_t, OVERRIDING MEMBER procedure set_name(new_name IN VARCHAR2), MEMBER PROCEDURE set_mgr(ref_emp IN REF emp_t) ) / CREATE TYPE BODY emp_t AS OVERRIDING MEMBER PROCEDURE set_name(new_name IN VARCHAR2) AS BEGIN SELF.name := new_name; -- zusätzlicher Code, z.B. informiere Manager END; MEMBER PROCEDURE set_mgr(ref_emp IN REF emp_t) AS BEGIN SELF.mgr := ref_emp; END; END; / Listing 10.17: Überschreiben einer Methode
MAP- und ORDER-Methoden Es existieren zwei weitere spezielle Arten von Methoden, die zum Vergleich von Objektinstanzen genutzt werden können. Dabei bilden MAP-Methoden Objektinstanzen auf einen Wert eines skalaren Datentyps wie NUMBER, REAL, VARCHAR2 usw. ab, um den Vergleich mittels des abgebildeten Werts durchführen zu können. Sie sind also immer dann sinnvoll, wenn ein Vergleich zwischen zwei Objekten auf den Vergleich eines einfachen Datentyps abzubilden ist. Für komplexere Vergleiche kann eine ORDER-Methode verwendet werden. Diese bekommt zwei Objektinstanzen als Eingabewerte und liefert eine negative Zahl, die Zahl Null oder eine positive Zahl zurück, wenn das erste Objekt kleiner, gleich oder größer als das zweite Objekt ist.
Sandini Bib
656
Neue Technologien
Ein Objekttyp kann ausschließlich eine von beiden Funktionen (MAP oder ORDER) besitzen. Für Typhierarchien gilt, dass MAP- oder ORDER-Methoden zwingend im Wurzeltyp, d.h. in dem Supertyp, von dem alle anderen Typen abgeleitet werden, definiert werden müssen. Die Subtypen können dann optional diese Methode überschreiben, falls es sich um eine MAP-Methode handelt. ORDER-Methoden können nicht überschrieben werden.
10.1.5 Typerweiterungen Einer der größten Kritikpunkte an Oracles OR-Modell bis einschließlich Oracle8i ist, dass Objekttypen sich nicht mehr verändern lassen, sobald die erste Objekttabelle kreiert ist. Es ist klar, dass sich Objekttypen nicht mehr komplett „umkrempeln“ lassen, sobald zumindest erste Objektinstanzen in den Tabellen enthalten sind; das Fehlen sämtlicher Möglichkeiten zur Modifikation wird jedoch zu Recht als großes Manko betrachtet. Gerade im Oracle-Umfeld wird eine gewisse Flexibilität grundsätzlich erwartet, wo doch die ALTER TABLE-Möglichkeiten der Oracle Database im relationalen Modell problemlos das Hinzufügen, unter bestimmten Umständen das Ändern und ab Oracle9i sogar das Löschen von Spalten bzw. ihrer Datentypen erlauben. Ab Oracle9i ist es jedoch möglich, mit ALTER TYPE- und ALTER TABLE-Befehlen bestehende Objekttypen zu verändern. Es können neue Attribute hinzugefügt und gelöscht werden; ebenfalls können bei skalaren Datentypen die Definitionen erweitert werden (z.B. bei NUMBER eine größere Präzision; bei VARCHAR2 eine größere maximale Länge). Hierbei ist es nun wichtig, dass beim ALTER TYPE-Kommando entschieden werden muss, ob die Daten in den zugrunde liegenden Tabellen sofort oder später angepasst werden sollen. Diese Entscheidung erfolgt in der CASCADE-Klausel, bei der entweder INCLUDING TABLE DATA oder NOT INCLUDING TABLE DATA angegeben wird. Im ersten Fall werden die Anpassungen der Objektinstanzen sofort vorgenommen; im zweiten Fall werden sie verschoben. Die spätere Anpassung der Tabellendaten kann dann durch einzelne UPDATEs (bei denen z.B. der Inhalt des Objekts mit sich selbst überschrieben wird) oder durch ein ALTER TABLE-Kommando mit der Klausel UPGRADE INCLUDING DATA erfolgen. Auch wenn beim ALTER TYPE die Daten nicht angepasst werden, werden sie bei Abfragen ab sofort im neuen Format zurückgegeben, d.h., beim SELECT wird automatisch eine Transformation durchgeführt. ALTER TYPE person_t ADD ATTRIBUTE schuhgroesse VARCHAR2(10) CASCADE INCLUDING TABLE DATA / ALTER TYPE person_t MODIFY ATTRIBUTE vorname VARCHAR2(50) CASCADE NOT INCLUDING TABLE DATA /
Sandini Bib
Objektrelationale Datenstrukturen
657
ALTER TABLE person_tab UPGRADE INCLUDING DATA / ALTER TYPE person_t DROP ATTRIBUTE adresse CASCADE INCLUDING TABLE DATA / Listing 10.18: Typerweiterung
10.1.6 Objekt-Views Da der relationale Teil des Oracle-Systems auf der Speicherung von Daten in Tabellen sowie der Darstellung von Teilmengen, Verknüpfungen usw. in Views basiert, ist es nicht verwunderlich, dass es im OR-Bereich ebenfalls Views gibt. Diese sind jedoch insbesondere für die Fälle gedacht, in denen relationale Strukturen z.B. für Entwicklungs- und Testzwecke als objektrelationale Elemente dargestellt werden sollen. Einige Erweiterungen des View-Konzepts helfen dabei, auch komplexe Strukturen abzubilden. Natürlich sind auch Objekttabellen und -Views als Basis für Objekt-Views erlaubt. Ein Beispiel, basierend auf den weiter oben definierten Objekttypen person_t, adresse_va und telefon_tab_t, soll den Ansatz der Objekt-Views erklären. Damit eine Objekt-View erstellt werden kann, die auf relationalen Strukturen basiert, werden zunächst die entsprechenden „flachen“ Tabellen personen, adressen und telefone benötigt. CREATE TABLE personen (pid NUMBER(5,0), name VARCHAR2(30), vorname VARCHAR2(30), CONSTRAINT personen_pk PRIMARY KEY (pid) ) / CREATE TABLE adressen (aid NUMBER(5,0), pid NUMBER(5,0), strasse VARCHAR2(30), hausnr VARCHAR2(5), plz VARCHAR2(5), ort VARCHAR2(30), staat VARCHAR2(30), region VARCHAR2(30), CONSTRAINT adressen_ref_personen FOREIGN KEY (pid) REFERENCES personen, CONSTRAINT adressen_pk PRIMARY KEY (pid, aid), CONSTRAINT adressen_chk_5 CHECK (aid in (1, 2, 3, 4, 5)) ) /
Sandini Bib
658
Neue Technologien
CREATE TABLE telefone (pid NUMBER(5,0), typ VARCHAR2(10), nr VARCHAR2(20), CONSTRAINT telefone_ref_personen FOREIGN KEY (pid) REFERENCES personen, CONSTRAINT telefone_pk PRIMARY KEY (pid, typ) ) / Listing 10.19: Anlegen von Tabellen
Für die Tabellen sind einige Constraints definiert worden, so dass ein typisches relationales Modell vorliegt. Mit der folgenden Objekt-View-Definition wird dieses Modell nunmehr in die objektrelationale Welt abgebildet: CREATE VIEW person_v OF person_t WITH OBJECT IDENTIFIER (id) AS SELECT pid, name, vorname, CAST( MULTISET( SELECT strasse, hausnr, plz, ort, staat, region FROM adressen a WHERE a.pid = p.pid) AS adresse_va), CAST( MULTISET( SELECT typ, nr FROM telefone t WHERE t.pid = p.pid) AS telefon_tab_t) FROM personen p / Listing 10.20: Anlegen einer Objekt-View
Hierbei ist zunächst zu beachten, dass das CREATE VIEW-Kommando den Zusatz OF erhält, mit dem man, wie bei einer Objekttabelle, einen Objekttyp zuordnet. Für Objekt-Views, die auf relationalen Strukturen basieren, muss ein aus einem oder mehreren Werten zusammengesetzter Objekt-Identifier spezifiziert werden. Hier bietet sich ein Primärschlüssel an. Mit Hilfe der CAST- und MULTISET-Operatoren können Ergebnisse aus Subselects als Collections in die Objektstruktur „gedreht“ werden. Nunmehr können Werte, die z.B. per INSERT in die Basistabellen geflossen sind, aus der Objekt-View gelesen werden. Problematisch ist jedoch die Manipulation der Objekt-View selbst: Der Versuch, einen passend getypten Datensatz in die ObjektView einzufügen, mündet in einen Fehler, da die künstlichen Schlüsselinformationen für die referentielle Integrität nicht automatisch erzeugt werden können.
Sandini Bib
Objektrelationale Datenstrukturen
659
Aus diesem Grund wurde zeitgleich zur Einführung der Objekttechnologie in das Oracle-System der Instead-Of-Trigger für Views eingeführt. Dieser hängt ebenso wie die bekannten Tabellen-Trigger an den DML-Operationen INSERT, UPDATE und DELETE, mit dem Unterschied, dass er nicht vor bzw. nach der eigentlichen DMLOperation ausgeführt wird, sondern anstatt der DML-Operation. Ein INSERT-Trigger für die Objekt-View person_v könnte wie folgt aussehen: CREATE OR REPLACE TRIGGER person_v_insert INSTEAD OF INSERT ON person_v FOR EACH ROW BEGIN INSERT INTO personen VALUES (:NEW.id, :NEW.name, :NEW.vorname); FOR v_loop IN 1..:NEW.adresse.COUNT LOOP INSERT INTO adressen VALUES (v_loop, :NEW.id, :NEW.adresse(v_loop).strasse, :NEW.adresse(v_loop).hausnr, :NEW.adresse(v_loop).plz, :NEW.adresse(v_loop).ort, :NEW.adresse(v_loop).staat, :NEW.adresse(v_loop).region); END LOOP; FOR v_loop IN 1..:NEW.telefon.COUNT LOOP INSERT INTO telefone VALUES (:NEW.id, :NEW.telefon(v_loop).typ, :NEW.telefon(v_loop).nr); END LOOP; END; / Listing 10.21: Anlegen eines Instead-Of-Triggers
Hierbei wird das neu einzufügende Objekt in seine Bestandteile zerlegt und mit Hilfe von Schleifenstrukturen auf Master- und Detaildatensätze verteilt. Dadurch, dass die unterliegenden flachen Tabellen mit Primär- und Fremdschlüsseln versehen sind, wird automatisch die logische Konsistenz der Daten überwacht. Mit Hilfe der Objekt-Views können also relationale Strukturen in die Objektwelt abgebildet werden; mit Hilfe der Instead-Of-Trigger kann diese Abbildung sogar funktional vollständig sein. Somit können z.B. beim Übergang von einem relationalen zu einem objektrelationalen Datenmodell bereits neue Anwendungen erstellt und auf den bestehenden Daten getestet werden. Ein potenzieller Vorteil bei der Verwendung von Objekt-Views in Client-Software ist die Übertragung des gesamten Objekts in einem Netzwerkzyklus anstelle der Übertragung von einzelnen Zeilen oder Zeilenmengen im relationalen Fall. Hierbei handelt es sich sozusagen um eine Weiterentwicklung des Array-Fetch-Modells der Oracle-Client-Software. Ansonsten sind die Instead-Of-Trigger sicherlich auch interessant für andere Anwendungen, da sie keineswegs auf Objekt-Views eingeschränkt sind. Somit ist es
Sandini Bib
660
Neue Technologien
möglich, INSERT-Befehle abzufangen und mit den gelieferten Daten etwas ganz anderes zu tun, sie z.B. in eine Advanced Queue übergeben.
10.1.7 Privilegien für Objekttypen Zum Erstellen eines Objekttyps wird das Systemprivileg create type benötigt, zum Erstellen von Objekttypen in beliebigen Schemas create any type. Als datenbankweite Systemprivilegien existieren zusätzlich alter any type (beliebigen Objekttyp ändern), drop any type (beliebigen Objekttyp löschen), execute any type (Typedefinition nutzen, Tabellen von diesem Typ erstellen usw.) sowie under any type (Subtypen für diesen Objekttyp erstellen). In ähnlicher Art und Weise gibt es under any view für Objekt-Views. Als Objektprivilegien können execute und under, optional mit der Klausel with hierarchy option, vergeben werden, um die Privilegien sowohl für den genannten Typ als auch für dessen Subtypen zu vergeben.
10.1.8 Programmierumgebungen Bei der Bewertung der OR-Eigenschaften der Oracle Database stellt sich letztlich die Frage nach der Unterstützung in den diversen Programmierumgebungen. Hierbei kann unterschieden werden zwischen den klassischen Oracle-Entwicklungswerkzeugen wie Forms und Reports und Programmiersprachen wie Java, C und C++. Zu den klassischen Entwicklungswerkzeugen ist zu sagen, dass die Integration der Objekt-Welt mit Forms und Reports Release 6/6i erfolgt ist. Die Architektur und grundsätzliche Ausrichtung dieser Werkzeuge ist jedoch eher auf die relationale Welt ausgelegt als auf die objektorientierte, so dass diese auch eher in Projekten auftauchen, in denen es um relationale Datenmodelle geht. Anders sieht es bei Java, C und C++ aus. Hierbei sind Java und C++ selbst OO-Programmiersprachen, so dass sich hier eine durchgängige Unterstützung erwarten lässt. Allerdings unterstützt Oracle die Sprache C++ erst ab Oracle9i direkt mit einer eigenen Schnittstelle, dem Oracle C++ Call Interface (OCCI), und der Unterstützung des Header-Datei-Generators Oracle Type Translator (OTT) für C++-Syntax. In den Oracle8i-Releases unterstützt der OTT lediglich die Erzeugung von Header-Dateien in C-Syntax, d.h., er generiert struct-Anweisungen. C-Programme können über das Oracle Call Interface (OCI) auf den Datenbankserver zugreifen. Es existiert eine eigene Menge von Calls für den Zugriff auf Objektstrukturen, inklusive Calls zur dynamischen Abfrage von Objekttypen. Typinformationen können jedoch auch sehr komfortabel über OTT in eine C-Header-Datei generiert werden. Sowohl OCI als auch OCCI werden in Form einer Bibliothek ausgeliefert, die in entsprechenden Handbüchern dokumentiert ist. Es gibt also keine Werkzeuge oder Programmieroberflächen zur eigentlichen Programmerstellung. Eine Spezialität der Schnittstellen OCI und OCCI ist der Objekt-Cache, in dem Kopien von persistenten Objekten gehalten werden, so dass der Programmcode
Sandini Bib
Objektrelationale Datenstrukturen
661
sehr effizient darauf zugreifen kann. Das Laden und Zurückschreiben von Objekten erfolgt dabei sehr komfortabel. Ein weiteres Werkzeug zur Erstellung von C- bzw. C++-Programmen ist Pro*C/C++. Dieses Programm ist ein Präprozessor, der grundsätzlich C-Syntax sowie die ANSInormierte Embedded-SQL-Syntax versteht. Hierbei ist anzumerken, dass die C++Unterstützung sich im Wesentlichen auf das Ausschalten des C-Präprozessors beläuft, d.h., wie beim OCI werden Objekttypen lediglich dann unterstützt, wenn sie programmseitig als struct definiert sind. object-Definitionen sind auch hier nicht erlaubt. Die Unterstützung von Java hebt sich durch die Vielzahl der angebotenen Schnittstellen hervor: JDBC-Treiber in verschiedenen Varianten, SQLJ sowie diverse zusätzliche Bibliotheken und Schnittstellen ermöglichen den Zugriff auf OracleDatenbanken praktisch aus jedem Java-Programm heraus. Generell steht mit dem JPublisher ein Werkzeug zur Erstellung von Java-Klassen für Oracle-Objekttypen, REFs, Collections sowie von Zugriffsklassen für PL/SQL-Programme zur Verfügung. Zusätzlich bietet Oracle mit dem JDeveloper ein Integrated Development Environment (IDE) an, das die Entwicklung unterschiedlichster Java-Programme und -Module ermöglicht. Eine spezielle Betrachtung ist für die OO-Programmierung unter MS-Windows notwendig. OO-Programmierung wird unterstützt von Oracle Objects for OLE (OO4O). Dies ist eine von Oracle ausgelieferte Schnittstelle, die das MS-COM-Programmiermodell unterstützt und somit für viele Anwendungen unter MS-Windows, wie z.B. MS-Excel und MS-Access, zur Verfügung steht. Ansonsten wird eine Unterstützung von Objekttypen in der Dokumentation des Oracle-ODBC-Treibers weder erwähnt noch ausgeschlossen. Bei der vor kurzem im Internet aufgetauchten Schnittstelle Oracle Data Provider for .Net, die sich noch im Beta-Stadium befindet, ist die Unterstützung für Objekttypen definitiv ausgeschlossen. Abschließend noch eine allgemeine Bemerkung zu diesem Abschnitt: Auf Programmierbeispiele ist absichtlich verzichtet worden, da diese i.A. sehr umfangreich sind. Es sei an dieser Stelle explizit auf die OTN (Oracle Tech Net, URL: http:// otn.oracle.com) verwiesen, wo eine Vielzahl an Programmierbeispielen zu finden ist.
10.1.9 Verteilte Datenbanken Ab Oracle9i werden Objekttypen, Objekttabellen und Objekt-Views bei der Advanced Replication (Multi Master-Replikation, Updateable Snapshots) unterstützt. In Oracle8i ist das noch nicht der Fall. Folgende Fehlermeldung erscheint jedoch bei allen Versionen beim Versuch, über Datenbank-Links auf Objekttabellen zuzugreifen: ORA-22804: remote operations not permitted on object tables or user-defined type columns
In verteilten Datenbanken sind Objekttypen momentan nicht nutzbar. Auch können z.B. keine PL/SQL-Variablen auf remote Typdefinitionen angelegt werden.
Sandini Bib
662
Neue Technologien
Damit ist für alle Umgebungen, die momentan auch nur eine kleine Möglichkeit sehen, verteilte Datenhaltung einzuführen, die Objekttechnologie (noch) nicht empfehlenswert.
10.2 XML-Unterstützung in der Datenbank XML steht für die vom W3C (World Wide Web Consortium) festgelegte eXtended Markup Language und hat seit Oracle8i Einzug in die Datenbank gehalten. Das hat zwei zentrale Gründe: 1. XML ist mittlerweile ein etablierter Standard zum Datenaustausch zwischen verschiedenen Systemen bzw. in der Business-to-Business-Welt (B2B). Es sieht so aus, als könne XML mittelfristig Standards wie EDI (Electronic Data Interchange) ablösen. 2. Die Zeitgleichheit der Entwicklungen hat letztendlich ergeben, dass viele Programmierbeispiele und erste Anwendungen für XML in Java geschrieben wurden. Das hat zur Einführung der Java-Technologie in den Oracle8i-Server hervorragend gepasst. Auch in diesem Kapitel verfolgen wir die Strategie, kein Einführungsbuch in eine neue Technologie schreiben zu wollen. Für den Bereich XML haben das bereits einige Autoren getan, mit mehr oder weniger Bezug zu Oracle8i bzw. Oracle9i. Zwei grundsätzliche Aussagen zu XML können jedoch getroffen werden: 1. In vielen Diskussionen wird XML als Ablösung oder Erweiterung von HTML behandelt. Das trifft jedoch nicht den Kern von XML. Es handelt sich zwar jeweils um Markup Languages, bei denen sog. Tags benutzt werden, um ein Dokument zu strukturieren, allerdings geht es bei HTML primär um die Präsentation, bei XML um die Struktur der Dokumente. Da jede Sprache ihre Rolle unabhängig von der jeweils anderen einnehmen kann, gibt es auch keinen Grund, HTML durch XML zu ersetzen. 2. XML ist als zentraler Begriff in einem Sammelsurium von eng zusammenhängenden Begriffen zu sehen. Einige der wichtigsten sind: –
Document Type Definition (DTD): Legt den Aufbau von Dokumenten fest. Hiermit ist es z.B. möglich, B2B-Datenaustausch zu standardisieren.
–
eXtended Stylesheet Language (XSL): Definiert die Konvertierung von XMLDokumenten, z.B. zwischen verschiedenen DTDs oder von XML nach HTML zur Darstellung im Browser.
Eine zentrale Quelle für weiterführende Informationen ist die Website des W3C, http://www.w3.org.
Sandini Bib
Java in der Datenbank
663
Die Unterstützung von XML besteht aus folgenden Bereichen: Speicherung von XML-Daten in der Datenbank, Analyse von XML-Daten und Erzeugung von XMLDaten sowie die Übertragung von XML-Dokumenten, etwa mit Advanced Queues und IDAP (Internet Data Access Presentation). Für die Speicherung stehen grundsätzlich zwei Varianten zur Verfügung: entweder das Auseinanderpflücken der Dokumente mit strukturierter Ablage der Daten (in flachen oder Objekttabellen) oder – ab Oracle9i – die Möglichkeit, den systemdefinierten Datentyp SYS.XMLTYPE zu verwenden, der Methoden zur Analyse und Abfrage von XML-Dokumenten mitbringt. SYS.XMLTYPE basiert intern auf dem Datentyp CLOB, d.h., es können z.B. Textindizes auf Spalten mit XML-Inhalt aufgebaut werden. Zur Bearbeitung von XML-Daten stehen XML Developer Kits (XDKs) für die Sprachen Java, C, C++ sowie PL/SQL zur Verfügung. Hierin sind jeweils die zwei gebräuchlichsten APIs für den Zugriff auf XML-Dokumente enthalten: DOM (Document Object Model) und SAX (Simple API for XML). DOM ist hierbei die vom W3C empfohlene Schnittstelle. Ab Oracle9i wird Version 2.0 der DOM- und SAXStandards unterstützt. DOM-Parser analysieren ein XML-Dokument und erzeugen eine Baumstruktur, die mit Programmlogik bearbeitet werden kann. Viele XML-Editoren benutzen einen DOM-Parser. Er kann u.a. dazu eingesetzt werden, ein XML-Dokument gegen eine DTD zu verifizieren. Oracle8i und Oracle9i unterstützen zusätzlich viele weitere Schnittstellen im XMLUmfeld sowohl auf Datenbank- als auch auf Application Server-Ebene. Zurzeit ist im Application Server-Bereich der Oracle9 iAS Release 2 aktuell. Da die Oracle-Unterstützung von XML und weiteren Standards meist auf Java- bzw. PL/SQL-Modulen basiert, sind aktuelle Versionen und eine große Menge an Beispielen und Demos im OTN (Oracle Tech Net, URL: http://otn.oracle.com) zu finden. Diese Quelle empfehlen wir als Startpunkt für die Erforschung der Oracle-XML-Welt.
10.3 Java in der Datenbank Die letzten Jahre wurden geprägt durch eine rapide Entwicklung im Umfeld der Programmiersprache Java und eine ebenso heftige Diskussion darüber, welche Bedeutung dieses neue Paradigma für die Erstellung von Datenbankanwendungen hat. Die Firma Oracle hatte sich schon früh Java auf ihre Fahnen geschrieben: Einerseits wurden die wichtigsten Oracle-Werkzeuge nach Java portiert, andererseits hielt Java ab der Version 8.1.5 auch Einzug in die Datenbank selbst. Die folgenden Abschnitte geben einen kurzen Überblick über die Möglichkeiten, die uns in der Version 9i in Sachen Java zur Verfügung stehen. Sie können das umfangreiche und komplexe Thema jedoch nur kurz anreißen. Auch zu diesem Thema bietet das Internet eine Fülle aktueller Informationen, vor allem unter http:// java.sun.com.
Sandini Bib
664
Neue Technologien
10.3.1 Java-Grundlagen Java ist eine objektorientierte Sprache. Softwareobjekte, die wir mit objektorientierten Sprachen wie Java modellieren, befinden sich alle in einem Zustand und zeigen bestimmte Verhaltensweisen. Zustände finden in Variablen ihren Niederschlag, Verhaltensweisen in Methoden. Aus dieser Sicht stellt ein Objekt ein Softwarebündel aus Variablen und damit zusammenhängenden Methoden dar. Ein Auto kann beispielsweise durch folgende Variablen beschrieben werden: wie hoch die aktuelle Geschwindigkeit ist – 120 km/h –, wie viele Liter der Tank enthält – 45 Liter –, welcher Gang im Augenblick eingelegt ist – der dritte Gang. Darüber hinaus benötigt das Auto Methoden, wie z.B. die Methode „Gangwechsel“, die sein Verhalten bestimmen. Schematische Darstellungen von Objekten zeigen die Variablen im „schützenden“ Kern, umgeben von dem Ring aus Methoden, die die Variablen „einkapseln“.
9DULDEOHQ
0HWKRGHQ
Abbildung 10.1: Schematische Darstellung eines Objekts
Damit ein Objekt in einem größeren Ganzen, wie z.B. einem Programm, mit anderen Objekten interagieren kann, müssen Nachrichten ausgetauscht werden. Variablen und Methoden, die für Objekte einer bestimmten Art charakteristisch sind, werden in Klassen definiert. In diesem Sinne stellen Klassen Baupläne oder Prototypen von Objekten dar: Die Klasse Automobile beschreibt prototypisch verschiedene individuelle Autos, wobei jedes Fahrzeug eine Instanz der Klasse Automobile darstellt. Die Begriffe Objekt, Instanz und Klasse werden im täglichen Gebrauch jedoch oft inkonsistent gebraucht. Klassen können entweder von Grund auf neu definiert werden oder auf bereits existierenden Klassen aufbauen, indem sie deren Variablen und Methoden erben (Vererbung) und diese ergänzen oder überschreiben. Auf diese Weise kann eine Klassenhierarchie entstehen. Klassen werden schließlich in Paketen zusammengefasst.
Sandini Bib
Java in der Datenbank
665
Java bietet eine Reihe von vordefinierten Standardpaketen, wie z.B. java.lang, die eine Fülle von Methoden und Variablen für grundlegende Funktionalitäten zur Verfügung stellen. Java-Klassen werden in gleich lautendenden Dateien mit der Erweiterung .java erstellt – die Klasse automobile beispielsweise wird in der Datei mit Namen automobile.java definiert. Der Übersetzer erstellt daraus eine Klassendatei automobile.class, die den plattformunabhängigen Java-Bytecode enthält. Dieser plattformunabhängige Bytecode ist es, der einen Großteil zur Verbreitung der Sprache Java beigetragen hat. Zum Ausführen des Bytecodes ist schließlich ein JavaIntepreter erforderlich, der das betreffende Java-Programm im Kontext der virtuellen Java-Maschine (java virtual machine – JVM) auf einem konkreten Betriebssystem interpretiert. Um die Interpretation des Bytecodes zu beschleunigen, wurden in den letzten Jahren Just In Time-Konzepte entwickelt, die über den Java-Interpreter per Parameter aktiviert werden können und den Java-Bytecode während der Laufzeit in plattformspezifischen C-Code umwandeln. Die JVM bildet zusammen mit den Standardpaketen die Java-Plattform. Über die Standards JDBC und SQLJ besteht die Möglichkeit, aus Java-Programmen heraus direkt auf relationale Datenbanksysteme zuzugreifen. Java-Code kann für unterschiedliche Kontexte mit jeweils eigenen Paradigmen programmiert werden. Jedes mögliche „Programmiermodell“ wird dabei über eine eigene Namensgebung identifiziert: Java-Applets, Enterprise Java Beans (EJB), Servlets, Java Server Pages (JSP), um nur einige der Modelle zu nennen. Diese Begriffsvielfalt spiegelt die Flexibilität der Sprache wider, trägt aber leider auch viel zur allgemeinen Verwirrung bei und wirkt in vielen Fällen eher abschreckend als motivierend.
10.3.2 Java-APIs in der Datenbank Um Java-Code nicht nur in der Datenbank zu speichern, sondern auch ausführen zu können, ist eine virtuelle Java-Maschine notwendig. Diese wurde bereits ab der Version 8.1.5 in der Oracle-Datenbank implementiert – damals JDK 1.1. Unter Oracle9i Release 1 wird derzeit der Standard Java 2 (JDK 1.2) mit JDBC 2.0 unterstützt. Ein Merkmal der Oracle-JVM ist, dass sie in dem jeweiligen Session-Kontext des ausführenden Datenbankbenutzers läuft, wodurch sich einige Besonderheiten gegenüber Java-Programmen außerhalb der Datenbank ergeben:
: : :
Der datenbankinterne Java-Code ist von Haus aus thread safe. Die automatisierte Speicherplatzverwaltung (garbage collector) arbeitet im Kontext nur eines Benutzers, statt sich um die Speicherverwaltung aller Benutzer kümmern zu müssen. Beim dynamischen Laden von Klassen (dynamic class loading) werden die benötigten Java-Klassen zum Zeitpunkt der Anforderung in den Shared Memory-Bereich der SGA übertragen. Auf diese Weise stehen sie danach für alle weiteren Sessions zur Verfügung.
Sandini Bib
666
Neue Technologien
Darüber hinaus verwendet Oracle zur Speicherung von Java-Code in der Datenbank die Methode der statischen Kompilierung (static compilation), bei welcher der Bytecode zunächst in plattformunabhängigen C-Code gewandelt wird. Dieser CCode wird dann von plattformspezifischen C-Compilern in ausführbaren Code kompiliert. Wie der vorangehende Abschnitt gezeigt hat, kann Java in unterschiedlichen Kontexten eingesetzt werden. Zum Zeitpunkt der Version 9i stehen die folgenden Kontexte oder APIs zur Verfügung, um mit Java-Objekten in der Datenbank zu arbeiten:
:
:
:
Java Stored Procedures und Functions können über PL/SQL-Code aufgerufen werden oder können ihrerseits PL/SQL-Code aufrufen. Die Nutzung dieser Prozeduren und Funktionen ist vollkommen transparent für den betreffenden Benutzer, d.h., er kann den Code innerhalb einer normalen Datenbanksitzung explizit aufrufen oder – im Falle einer Funktion – im Kontext von SQL-Befehlen benutzen. Java Servlets und Java Server Pages spielen im Rahmen von HTML-Anwendungen eine Rolle und werden über entsprechende HTTP-Aufrufe ausgeführt. Wenn die Servlets und Java Server Pages nicht auf dem middle tier, sondern, wie hier besprochen, in der Datenbank gespeichert werden, müssen die HTTP-Aufrufe über HTTP-Server direkt an die Datenbank weitergeleitet werden. Durch die Unterstützung der CORBA1- und EJB2-Standards3 ist es möglich, Java Komponenten in der Datenbank zu speichern und mit anderen CORBA- oder EJB-Komponenten kommunizieren zu lassen. Im Gegensatz zu Servlets und Java Server Pages kommunizieren CORBA- und EJB-Komponenten über das von der Object Management Group spezifizierte Internet Inter-ORB Protocoll, kurz IIOP. IIOP ist eine Implementierung des General Inter-ORB Protocol (GIOP) über TCP/IP-Verbindungen. Die mögliche Speicherung dieser Komponenten in der Datenbank bringt es mit sich, dass direkte IIOP-Verbindungen im Kontext von Oracle-Datenbanken möglich sein müssen, um mit diesen Komponenten zu arbeiten.
Die Speicherung von Java-Code in der Datenbank macht es grundsätzlich möglich, Anwendungen der traditionellen „Mittelschicht“ in der Datenbankschicht zu installieren.
10.3.3 Installation Die Installation der JVM-Option lässt sich am besten über den Database Configuration Assistant und durch Auswahl der entsprechenden Option bewerkstelligen. Der Asisstent führt dann eine Reihe von SQL-Scripts aus den Verzeichnissen $ORACLE_HOME/javavm/install, $ORACLE_HOME/jsp/install und $ORACLE_HOME/
1. 2. 3.
CORBA = Common Object Request Broker Architecture, Architektur für verteilte Anwendungen mit Komponenten in unterschiedlichen Programmiersprachen EJB = Enterprise Java Beans, Architektur für verteilte Anwendungen mit Java-Komponenten Zum Zeitpunkt der Drucklegung dieser Publikation erfahren wir, dass in Oracle9i Release 2 die CORBA- und EJB-Unterstützung in der Datenbank aufgekündigt wird! Objekte dieser Art sind demnach zukünftig nur noch im middle-tier installierbar.
Sandini Bib
Java in der Datenbank
667
rdbms/admin aus; Log-Dateien mit gleichem Namen wie die SQL-Dateien werden im Zuge der Installation erstellt.
Abbildung 10.2: Installation der JServer-Option durch den Konfigurationsassistenten
Im Zuge der Installation werden auch die folgenden drei Benutzer angelegt und aus Sicherheitsgründen sofort gesperrt.
: : :
Aurora$Jis$Utility$ OSE$Http$Amin Aurora$Orb$Unauthenticated
Der DBA muss diese drei Benutzer entsperren, wenn die Datenbank zur Speicherung von Servlets, Java Server Pages, Enterprise Java Beans oder CORBA-Objekten genutzt werden soll: ALTER USER aurora$orb$unauthenticated ACCOUNT UNLOCK;
Abhängig von den genutzten Java-APIs sind auch spezifische Verbindungsprotokolle zur Datenbank im Kontext der Dateien listener.ora und tnsnames.ora zu konfigurieren (die Einzelheiten dieser Konfigurationen werden in Kapitel 5 besprochen):
: : :
Zum Aufruf von Java Stored Procedures oder Functions genügt eine „normale“ Oracle Net TTC-Verbindung, beispielsweise über TCP/IP. Die Arbeit mit HTML-generierenden PL/SQL-Prozeduren, Servlets oder Java Server Pages erfordert HTTP-Verbindungen über einen geeigneten HTTP-Server. Der HTTP-Server kann entweder im Rahmen eines Application Servers oder in Form des Oracle HTTP-Servers bereitgestellt werden. Zur Kommunikation mit EJB- und CORBA-Komponenten ist das IIOP-Protokoll erforderlich, das über die Datei listener.ora konfiguriert werden muss.
Sandini Bib
Zusätzlich sind die folgenden Systemparameter zu konfigurieren oder zu kontrollieren:
: : : :
shared_pool_size – der shared pool-Bereich der SGA wird zum Laden von JavaKlassen und zum Ausführen von Java-Objekten benötigt, wobei jede Klasse etwa 8 Kbyte Speicher benötigt. Für die Initialisierung der Datenbank mit etwa 8.000 Klassen ergibt sich daraus ein minimaler Bedarf von etwa 64 Mbyte. java_pool_size – spezifiziert den Speicherbereich für die Methoden- und Klassendefinitionen mit einem Minimum von 20 Mbyte. java_soft_sessionspace_limit – definiert die „weiche“ maximale Grenze des Java-Speicherplatzes pro Session. Beim Überschreiten dieser Grenze wird eine Warnung in eine Trace-Datei geschrieben. java_max_sessionspace_size – definiert eine „harte“, maximale Obergrenze für den Speicherplatz pro Java-Session. Der Standardwert von 4 Gbyte ist extrem hoch gewählt worden.
Der aktuelle Verbrauch von Speicherplatz in der SGA kann nach wie vor über die dynamische View v$sgastat abgerufen werden.
Sandini Bib
11
Data Warehousing
Dieses Kapitel beschäftigt sich mit den Datenbankkomponenten und Befehlen, die sich speziell für den Aufbau von Data Warehouse-Datenbanken eignen. Wie in einem Data Warehouse-Projekt üblich, gliedert es sich in die Bereiche ETL1 (Kapitel 11.1), die Verwaltung im Warehouse (Kapitel 11.2) und die Darstellung (Kapitel 11.3). Im Rahmen des Buches würde die gesamte Betrachtung des Data Warehouses jedoch zu weit führen, daher beschränken wir uns hier auf die Komponenten, die direkt oder indirekt mit der Oracle9i-Datenbank zu tun haben. Elemente wie die Darstellung der Ergebnisse oder die Extraktion der Daten werden nicht behandelt. Ebenso werden die Datenbankoptionen OLAP und Data Mining, die bei der Enterprise Edition in den Kernel integriert werden können, nicht in diesem Kapitel behandelt. Auch der Oracle Warehouse Builder, der den Aufbau und Betrieb eines Data Warehouses sehr gut unterstützt, wird in diesem Kapitel keine weitere Beachtung finden. Die Kriterien, die zum Aufbau eines Data Warehouses führen, sind sehr vielfältig. Zum einen ist es die Möglichkeit Ad-hoc-Queries, d.h. frei definierte Abfragen auf eine große Datenmenge durchzuführen. Zum anderen ist es die Notwendigkeit, für analytische Abfragen auf historische Daten über mehrere Jahre zugreifen zu können. Damit einher geht die Forderung, Verdichtungen der Basisinformationen durchzuführen. Daher unterscheidet sich ein Data Warehouse hinsichtlich der Datenmenge und der Art der Anwendungen stark von einem operativen System. Während ein operatives System prozessorientiert arbeitet, wird ein Data Warehouse für analytische Aufgaben genutzt. Für das Design bedeutet dies, dass bewusst denormalisiert wird und ein so genanntes Star- oder Snowflake-Schema verwendet wird. Dabei gibt es wenige sehr große Faktentabellen (z.B. eine Umsatztabelle), die über Dimensionstabellen (z.B. Produktinformationen, Zeitreihen) mit Attributen versorgt werden. Auf Basis dieser Tabellen werden dann Verdichtungsstufen (z.B. Umsatz pro Produktgruppe pro Monat) aufgebaut. Dies führt dazu, dass wir es in diesem Umfeld immer häufiger mit Datenbanksystemen mit mehr als einem Terabyte (1.000 Gbyte) Größe und mit Tabellen mit mehreren 100 Millionen oder Milliarden an Datensätzen zu tun haben. Der Fokus beim Aufbau einer solchen Datenbank muss also sein, dass große Datenmengen zum einen schnell abgefragt werden können, zum anderen aber eine Administration in endlicher Zeit möglich ist. Alleine die Frage der Sicherung eines solchen Systems bzw. des Wiedereinspielens der Daten stellt viele Unternehmen vor ein kaum lösbares Problem.
1.
ETL = Extraction, Transformation, Loading
Sandini Bib
670
Data Warehousing
11.1 Extraktion, Transformation, Laden Die Qualität der geladenen Daten bestimmt die Akzeptanz eines Data Warehouses! Für die Designer eines solchen Systems kommt es also darauf an, die geeigneten Informationen in den operativen Systemen zu finden, sie mit anderen Systemen zu vergleichen und zu konsolidieren und dann in das Data Warehouse zu übertragen. Dabei ist oftmals die Qualität der Daten die zeitaufwendigste Arbeit, da es darum geht, unterschiedliche Datenquellen mit u.U. ähnlichen Dateninhalten mit einander zu vergleichen. Ein einfaches Beispiel soll dies verdeutlichen: In einem Versicherungsunternehmen werden Daten über neuere Verträge in einer Oracle Datenbank gehalten, ältere Verträge liegen auf einem IBM-Mainframe. Außerdem kauft das Unternehmen regelmäßig Personendaten von einem Marketingunternehmen. In diesem Fall gibt es also drei Quellen für Personendaten, mit der Gefahr, dass ein und die selbe Person mit unterschiedlichen Informationen in allen drei Quellen enthalten ist. Im klassischen Data Warehouse-Konzept heißt dies, dass die Daten zunächst aus den Quellsystemen in flache Dateien extrahiert werden, dann mit einem ETLWerkzeug transformiert und bereinigt werden, um im dritten Schritt über Laderoutinen in der Data Warehouse-Datenbank zu landen. Hier werden dann die entsprechenden Verdichtungen über PL/SQL oder andere Programme durchgeführt. Da relationale Datenbanken für operative Systeme eine immer größere Rolle spielen, bietet es sich an, diese Vorgehensweise zu vereinfachen. Über die in der OracleDatenbank direkt verfügbare Gateway-Technologie ist es möglich, Datenbanken wie Microsoft SQL-Server oder IBM DB/2 über ODBC wie eine Oracle-Datenbank anzusprechen. Diese Funktionalität kann über die Tranparent Gateway-Technologie von Oracle auf andere Systeme und Verfahren erweitert werden. Damit besteht eine direkte Verbindung zwischen Quellsystemen und dem Data Warehouse mit dem Vorteil, dass über SQL oder PL/SQL in einer einheitlichen Sprache eine Bereinigung, Transformation und Verdichtung der Daten erfolgen kann. Die einzig fehlende Komponente sind die Systeme, die keine direkte Anbindung an die Oracle-Datenbank haben. Hier existiert immer noch nur der Weg über die Extraktion der Daten in flache Dateien. Mit der Version 9 können diese als externe Tabellen definiert werden und stehen so dem Data Warehouse in gleicher Art wie die direkt angebundenen Systeme zur Verfügung. Außerdem existiert noch die Einbindung von Tablespaces als Kopie einer anderen Oracle-Datenbank.
11.1.1 Transportable Tablespaces Wenn Sie beabsichtigen Tabellen über diesen Mechanismus in ein Data Warehouse zu übernehmen, sollten Sie folgende Restriktionen beachten (siehe auch Kapitel 3.7):
Sandini Bib
Extraktion, Transformation, Laden
671
1. Die Hardware bzw. das Betriebssystem der Quell- und Zieldatenbank müssen identisch bzw. binärkompatibel sein. 2. Die Zeichensätze von Quell- und Zieldatenbank müssen identisch sein bzw. die Zieldatenbank kann eine Obermenge der Quelldatenbank sein. Alleine an dieser Restriktion scheitern die meisten Übernahmen. So ist zum Beispiel der Zeichensatz WE8ISO8859P15 keine Obermenge des Zeichensatzes WE8ISO8859P1. Dies ist deshalb erwähnenswert, weil in der Vergangenheit die meisten Datenbanken mit WE8ISO8859P1 erstellt wurden, dort aber das Euro-Symbol fehlt und deshalb heute in den meisten Fällen WE8ISO8859P15 verwendet wird. 3. Es dürfen keine Beziehungen der Objekte aus den zu transportierenden Tablespaces in andere Tablespaces existieren. 4. In der Zieldatenbank muss für die Blockgröße des Tablespaces ein entsprechender Cache eingerichtet worden sein. Beispiel für den Transport des Tablespaces DEMO: Der Tablespace demo mit den Benutzern demo und sh wird aus der Datenbank sundb in die Datenbank sundwh transportiert. SQL> EXECUTE sys.dbms_tts.transport_set_check('DEMO', TRUE); SQL> SELECT * FROM sys.transport_set_violations; VIOLATIONS ------------------------------------------------------------------Default Partition (Table) Tablespace TS1 for VERKAEUFE not contained Default Partition (Table) Tablespace TS2 for VERKAEUFE not contained Default Partition (Table) Tablespace TS3 for VERKAEUFE not contained Default Partition (Table) Tablespace TS4 for VERKAEUFE not contained
in in in in
SQL> ALTER TABLE verkaeufe MODIFY DEFAULT ATTRIBUTES TABLESPACE ts1; SQL> ALTER TABLESPACE demo READ ONLY; % exp parfile=exp_trans_ts.par 11.1: Transportable Tablespaces exportieren
Dabei hat die Parameterdatei exp_trans_ts.par folgende Syntax: USERID="system/manager as sysdba" TRANSPORT_TABLESPACE=y TABLESPACES=('DEMO') LOG=exp_trans_ts.log TRIGGERS=Y CONSTRAINTS=N GRANTS=N FILE=/oradata1/SUNDB/expdemo_ts.dmp 11.2: Export-Parameterdatei
transportable transportable transportable transportable
set set set set
Sandini Bib
672
Data Warehousing
Die oben aufgetretenen Fehler beim Test, ob ein Tablespace transportiert werden kann, sind typisch für die Verwendung von Partitionen. Eine partitionierte Tabelle bekommt zusätzlich ein Default Tablespace zugewiesen, das identisch mit dem Default Tablespace des anlegenden Benutzers ist. Beim Erstellen der partitionierten Tabelle kann dieser Tablespace nicht verändert werden, sondern muss nachträglich angepasst werden. Nachdem der Tablespace an die neue Position kopiert worden ist, kann er mittels Import in die neue Datenbank eingehängt werden. % imp parfile=imp_trans_ts.par
Dabei hat die Parameterdatei imp_trans_ts.par folgende Syntax:: USERID="system/manager as sysdba" TRANSPORT_TABLESPACE=y TABLESPACES=('DEMO') DATAFILES=('/oradata2/SUNDWH/demo01.dbf') LOG=imp_trans_ts.log FILE=/oradata1/SUNDB/expdemo_ts.dmp 11.3: Import-Parameterdatei
Beim Import gibt es neben einer Reihe von Fehlern in Bezug auf falschen Zeichensatz oder nicht existierende Schemata einen weiteren schwer zu erkennenden Fehler: ora-19721 Cannot find datafile with absolute file number %s in tablespace %s Dieser Fehler tritt unter anderem dann auf, wenn ein falsches Tablespace kopiert wurde oder das Tablespace nicht Read-Only gesetzt war. Insofern eine korrekte Fehlermeldung. Sie tritt als Bug in den Versionen 8.1.x und 9.0.1 aber auch dann auf, wenn ein bereits einmal transportiertes Tablespace weitertransportiert werden soll. Die Benutzung von transportablen Tablespaces ist sicherlich insofern interessant, als es die schnellste Methode ist, Daten von einer in eine andere Datenbank zu kopieren. In der Realität scheitert die Benutzung allerdings oftmals an den diversen Einschränkungen. Außerdem sollten Sie beachten, dass während des Exports der Data Dictionary-Information der Tablespace auf Read-Only gesetzt sein muss, was in der Praxis für viele operative Systeme jedoch einen K.O.-Punkt darstellt. Die Frage ist auch, wie man einzelne Partitionen aus einem operativen Umfeld in ein Data Warehouse überträgt und dort wieder in eine vorhandene partitionierte Tabelle integriert. Durch die Einschränkung, dass keine Referenzen außerhalb des zu transportierenden Tablespaces existieren dürfen, würde die Prozedur dbms_tts.transport_set_check einen Fehler bringen. Um diesen zu umgehen, wird die Partition über den Befehl PARTITION EXCHANGE in eine Tabelle umgewandelt. Sollten Sie globale Indizes für die partitionierten Tabellen verwenden, dann macht es Sinn, die neue Option UPDATE GLOBAL INDEXES (evtl. mit dem Zusatz PARALLEL n) zu verwenden. Mit dieser Methode werden bei Änderungen von Partitionen die globalen Indizes mitangepasst, so dass es nicht mehr zu dem Status
Sandini Bib
Extraktion, Transformation, Laden
673
UNUSABLE für die Indizes kommt. In der Praxis hat sich gezeigt, dass der Partition
Exchange in der unten angegebenen Form schneller ist als ein Partition Exchange ohne Anpassung der globalen Indizes mit anschließendem Neuaufbau (REBUILD). SQL> ALTER TABLE sales EXCHANGE PARTITION q1_01 WITH TABLE verkaeufe_Q1_01 INCLUDING INDEXES UPDATE GLOBAL INDEXES; 11.4: Update Global Indexes
Auf der Data Warehouse-Seite kann dann in umgekehrter Form eine Wiedereingliederung in die entsprechende Tabelle durchgeführt werden. Um die bei großen Tabellen sehr lang andauernde Validierung zu vermeiden, sollte hier mit der Option WITHOUT VALIDATION gearbeitet werden.
11.1.2 Parallelisierung Die Parallelisierung, die Oracle mit der Version 7 eingeführt hat, war der erste Schritt für die Nutzung einer Oracle-Datenbank als Data Warehouse. Während in Version 7 zunächst nur lesende Zugriffe und das Laden von Massendaten über SQL*Loader oder CREATE TABLE AS SELECT parallelisiert werden konnten, wurde mit der Einführung der Partitionierung in der Version 8 auch ein paralleles Einfügen von Daten in partitionierte Tabellen möglich. Folgende parallele Operationen sind möglich:
: : : :
Abfragen Erstellen von Indizes DML-Operationen auf Massendaten Erstellen von Tabellen
Gerade beim Laden bzw. Konsolidieren von Daten in einem Data Warehouse kann diese Möglichkeit effektiv ausgenutzt werden. In der Regel steht für das Laden der Daten bei zunehmender Größe eines Data Warehouses ein immer kleinerer Zeitraum zur Verfügung. Durch die Skalierbarkeit der Systeme (mehr CPUs oder evtl. Einsatz von Real Application Cluster, RAC) stehen aber auch mehr Ressourcen zur Verfügung. Durch die Parallelisierung kann jetzt tatsächlich eine größere Datenmenge in einem kleineren Zeitraum geladen werden. Unterstützt werden sollte dieser Mechanismus durch die Partitionierung der entsprechenden Tabellen. Durch Cache-Fusion können ab Version 9 auch Real Application Cluster-Systeme von der Parallelisierung ohne Performance-Verluste profitieren. Mit zunehmender Größe eines Data Warehouses steigt oftmals auch die Anzahl Anwender, die auf die Daten zugreifen. Die daraus resultierende zusätzliche CPUund I/O-Last macht eine Performance-Verbesserung durch Parallelisierung der Abfragen zunichte. In vielen Anwendungen wird deshalb auf diese Möglichkeit der Parallelisierung verzichtet und alleine bei administrativen Tätigkeiten (Konsolidie-
Sandini Bib
674
Data Warehousing
rung von Daten, Aufbau von Indizes, Laden von Data Marts2) die Parallel-QueryFunktionalität genutzt. Die Verwendung der Parallelisierung setzt die Oracle Enterprise Edition voraus. Außerdem müssen die Initialisierungsparameter parallel_min_servers und parallel_max_servers entsprechend gesetzt sein. Die Verwendung von Parallelisierung kann die Ressourcen eines Systems optimal ausnutzen, je nach verwendetem Parallelisierungsgrad und Operation kann es jedoch sein, dass die verfügbaren Ressourcen die Grenzen des Systems sprengen. Ein einfaches Beispiel soll dies verdeutlichen: SQL> ALTER SESSION SET sort_area_size = 100.000.000; SQL> SELECT /*+ PARALLEL(kunden,10) */ DISTINCT nachname FROM kunden; 11.5: Ressourcenverbrauch einer einfachen Abfrage
In diesem Beispiel wird für die Sitzung ein Sortierbereich von ca. 100 Mbyte zur Verfügung gestellt. Die anschließende Abfrage wird jetzt mit dem Faktor 10 parallelisiert. Durch diese Abfrage entstehen 20 Prozesse (10 für die Selektion der Daten und 10 für die Sortierung). Dabei kann jeder der Prozesse bis zu 100 Mbyte für Sortierungen belegen. In diesem Fall also ca. 1 Gbyte für die Sortierung mit DISTINCT. Das führt speziell dann zu Ressourcenproblemen, wenn gleichzeitig mehrere Indizes aufgebaut werden. Paralleles Laden Oracle bietet mit dem SQL*Loader ein effektives Werkzeug für das Laden von Daten in die Oracle-Datenbank. Der Direct-Path ermöglicht es dabei, direkt in freie Blöcke zu schreiben, ohne über die SGA zu gehen (siehe Kapitel 6.2.5). Daneben besteht außerdem die Möglichkeit der Parallelisierung des Ladevorgangs durch den Parameter parallel=true als Option für den Ladeprozess. Hierbei sind aber derart viele Einschränkungen zu beachten, dass diese Option nur selten genutzt wird. Die wichtigsten Einschränkungen sind:
: : : :
Je parallelem Prozess muss eine eigene Datendatei zur Verfügung stehen. Es werden keine Indizes gepflegt. Alle Constraints und Trigger müssen ausgeschaltet (DISABLE) werden. Es kann nur die Ladeoption APPEND verwendet werden, REPLACE, TRUNCATE und INSERT sind nicht möglich.
Generell gilt aber, dass das parallele Laden von Daten aus mehreren Dateien eher die Ausnahme ist, da oftmals nur eine Quelldatei zur Verfügung steht.
2.
Data Mart = eigenständiger Substrakt eines Data Warehouses für einen bestimmten Bereich bzw. eine bestimmte Aufgabe
Sandini Bib
Extraktion, Transformation, Laden
675
Für das Laden von Daten über einen Datenbank-Link gilt diese Einschränkung jedoch nicht mehr. Ab Version 9 ist es möglich, den Befehl CREATE TABLE AS SELECT oder einen INSERT INTO TABLE AS SELECT über einen Datenbank-Link zu parallelisieren. Zusammen mit der Option NOLOGGING beim Erstellen der Tabelle bzw. Direct-Path beim Einfügen von Daten mit INSERT /*+ APPEND */ kann damit die Ladeoperation optimiert werden. Externe Tabellen Über die Einbindung von externen Tabellen besteht auch bei einzelnen Dateien die Möglichkeit einer Parallelisierung, wenn die Dateien zum Beispiel auf einem Raid-03-System liegen. CREATE TABLE auftrag ( aufnr NUMBER (10), kdnr NUMBER (10), aufdatum DATE ) ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY dat_dir ACCESS PARAMETERS (RECORDS DELIMITED BY NEWLINE BADFILE dat_dir:'auftrag%p.bad' LOGFILE dat_dir:'auftrag%p.log' FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY "'" ( "AUFNR" float external NULLIF "AUFNR"=BLANKS, "KDNR" float external NULLIF "KDNR"=BLANKS, "AUFDATUM" DATE "ddmmyyyyhh24miss" TERMINATED BY 'Ç' NULLIF "AUFDATUM"=BLANKS ) ) LOCATION ('auftrag_extract.ctl') ) PARALLEL 5 REJECT LIMIT UNLIMITED; 11.6: Externe Tabellen
Die hierdurch erstellte Tabelle auftrag kann jetzt im Data Warehouse wie jede andere Tabelle angesprochen werden. Das bedeutet, auf den Umweg über das Laden einer Basistabelle und anschließender Bereinigung oder Verdichtung kann verzichtet werden.
3.
Raid-0 = Striping (Verteilung von Daten über mehrere Platten, wobei je Platte immer ein Stripeset in der Größe zwischen 8 Kbyte und 1 Mbyte angelegt wird)
Sandini Bib
676
Data Warehousing
11.1.3 Komplexe Laderoutinen Ein wichtiger – wenn nicht der wichtigste – Prozess in einem Data Warehouse ist die Bereinigung und Integration der Daten. Mit Oracle9i hat Oracle hierfür einige Möglichkeiten in die Datenbank integriert, die dieses Verfahren vereinfachen und beschleunigen können. Merge Eine eigentlich recht simple Aufgabe für das Einfügen von Daten in eine bereits gefüllte Tabelle lautet: „Wenn der Schlüsselbegriff noch nicht vorhanden ist, wird ein neuer Datensatz eingefügt, wenn er bereits vorhanden ist, soll eine Änderung des Satzes erfolgen.“ Bis zur Version 8i kam für die Lösung der Aufgabe nur eine entsprechende Programmierung in Frage, z.B. in Form von PL/SQL. Für einfache Ladeoperationen z.B. aus externen Tabellen oder über einen Datenbank-Link direkt aus einem produktiven System ist es mit Version 9i einfacher, den Befehl MERGE zu nutzen. Der Befehl sieht wie folgt aus: MERGE INTO USING ON ( = ) WHEN MATCHED THEN UPDATE SET = ... WHEN NOT MATCHED THEN INSERT (,...) VALUES (,...) 11.7: Beschreibung MERGE
Wichtig ist hierbei die Beziehung zwischen der Quelltabelle (kann auch wie im Beispiel eine SELECT-Anweisung sein) und der Zieltabelle in Form des Vergleichs von zwei Spalten. Leider ist es nicht möglich, mehrere Spalten als Vergleich anzugeben, man kann sich aber helfen, indem man die Spalten zu einer zusammensetzt (concatination). Eine wichtige Einschränkung gilt es zu beachten: Jede Zeile der Zieltabelle kann nur einmal mit einem MERGE geändert werden. Das heißt, die Quelltabelle muss vorher verdichtet worden sein, um zu vermeiden, dass zwei Änderungsoperationen auf die gleiche Zeile durchgeführt werden würden. Das folgende Beispiel zeigt, wie Daten aus den Quelltabellen auftraege und positionen direkt über einen Datenbank-Link in die Zieltabelle verkaeufe geladen werden können. Es wird dabei angenommen, dass diese Informationen wöchentlich geladen werden (sysdate-7). Der Join über die Tabellen aufraege und positionen muss zusätzlich um eine Gruppierung erweitert werden, um die oben angegebene Restriktion, dass jede Zeile nur maximal einmal geändert werden darf, einzuhalten.
Sandini Bib
Extraktion, Transformation, Laden
677
MERGE INTO verkaeufe v USING (SELECT TRUNC(a.auf_datum) auf_datum, b.pos_prodnr, SUM(b.pos_menge) menge, SUM(b.pos_menge * b.pos_einzelpreis) preis FROM auftraege@DBLINK a, positionen@DBLINK b WHERE a.auf_nr = b.pos_aufnr AND a.auf_status = 10 -- Bezahlter Auftrag AND a.auf_lieferdatum > TRUNC(sysdate) - 7 GROUP BY TRUNC(a.auf_datum), b.pos_prodnr) s ON (v.datum||v.prodnr = s.auf_datum||s.pos_prodnr) WHEN MATCHED THEN UPDATE SET v.menge = v.menge + s. menge, v.gesamtpreis = v.gesamtpreis + s.preis WHEN NOT MATCHED THEN INSERT(datum, prodnr, menge, gesamtpreis) VALUES(s.auf_datum, s.pos_prodnr, s.menge, s.preis); 11.8: Beispiel: MERGE
Interessant war bei den Tests folgende Fehlermeldung: ORA-30926: Stabile Zeilengruppe in den Quelltabellen kann nicht eingelesen werden
Diese Fehlermeldung trat dann auf, wenn statt eines TRUNC(a.auf_datum) das komplette Datum angegeben wurde, das bedeutet, es waren dann zu viele Gruppen vorhanden. Multi-Table Insert Eine ähnliche Aufgabe wie der Befehl MERGE erfüllt auch der Multi-Table Insert. Oftmals wird beim Übergang eines operativen Systems in ein Data Warehouse das Datenmodell geändert, so dass z.B. Zeilen und Spalten vertauscht oder mehrere Quelltabellen zu einer Zieltabelle verbunden werden. Beim Einfügen der Datensätze muss jetzt je nach Struktur der Quelltabelle entschieden werden, in welche Zieltabelle bzw. welche Zielspalte dieser Wert eingefügt werden soll. In der Vergangenheit war das ausschließlich durch eine Programmierung, z.B. in PL/SQL, zu realisieren. Mit Version 9i besteht die Möglichkeit, eine bedingte INSERT-Anweisung auszuführen. Dabei gibt es folgende Möglichkeiten: 1. Einfügen von Datensätzen aus mehreren Quellspalten in dieselbe Zielspalte. Beispiel: In einem operativen System wird eine Auftragstabelle in der Form gepflegt, dass die Produkte nach Stückzahlen, Volumen oder Gewicht eingeteilt sind. Damit ergibt sich folgende Tabellenstruktur:
Sandini Bib
678
SQL> desc positionen Name ---------------------pos_aufnr pos_nr pos_prodnr pos_stueck pos_stueckpreis pos_volumen pos_volumenpreis pos_gewicht pos_gewichtpreis
Data Warehousing
Null? -------NOT NULL NOT NULL NOT NULL
Typ ---------------NUMBER(10) NUMBER(10) NUMBER(10) NUMBER(10,2) NUMBER(7,2) NUMBER(10,2) NUMBER(7,2) NUMBER(10,2) NUMBER(7,2)
Listing 11.9: Tabelle positionen
Aus dieser und der zugehörigen Auftragstabelle soll jetzt eine Verkaufstabelle gebildet werden, in der nur noch der Gesamtpreis und der Typ (Stückzahl, Volumen oder Gewicht) vorkommt. INSERT ALL WHEN stueckpreis IS NOT NULL THEN INTO verkaeufe VALUES (auf_datum, pos_prodnr, 'S',stueckpreis) WHEN volumenpreis IS NOT NULL THEN INTO verkaeufe VALUES (auf_datum, pos_prodnr, 'V',volumenpreis) WHEN gewichtspreis IS NOT NULL THEN INTO verkaeufe VALUES (auf_datum, pos_prodnr, 'G',gewichtpreis) SELECT TRUNC(a.auf_datum) auf_datum, b.POS_PRODNR, SUM(b.pos_stueck * b.pos_stueckpreis) stueckpreis, SUM(b.pos_volumen * b.pos_volumenpreis) volumenpreis, SUM(b.pos_gewicht * b.pos_gewichtpreis) gewichtpreis FROM AUFTRAEGE a, POSITION2 b WHERE a.auf_nr = b.pos_aufnr AND a.auf_status = 10 GROUP BY TRUNC(a.auf_datum), b.pos_prodnr; Listing 11.10: Conditional Insert
In diesem Beispiel wird in die Tabelle verkaeufe der entsprechende Gesamtpreis und der Preistyp eingetragen. Man hätte statt dieser Funktion auch einen UNION-SELECT aufbauen können, nur dann wäre die SELECT-Anweisung dreimal ausgeführt worden, während sie hier nur einmal ausgeführt werden muss.
Sandini Bib
Extraktion, Transformation, Laden
679
2. Einfügen von Datensätzen aus einer Quelltabelle in mehrere Zieltabellen. Die INSERT ALL-Bedingung kann gut benutzt werden, wenn aus einer Quelltabelle in mehrere Zieltabellen verzweigt werden muss. So kann z.B. gleichzeitig eine Tabelle verkaeufe mit den Verkaufsinformationen und eine Tabelle kosten mit den korrespondierenden Kosten gefüllt werden. INSERT ALL INTO verkaeufe VALUES (datum, prodnr, menge, gesamtpreis) INTO kosten VALUES (prodnr, ekpreis) SELECT TRUNC(a.auf_datum) datum, b.pos_prodnr prodnr, SUM(b.pos_menge) menge, SUM(b.pos_menge * b.pos_einzelpreis) gesamtpreis, SUM(b.pos_menge * p.prod_preisek ) ekpreis FROM auftraege a, positionen b, produkte p WHERE a.auf_nr = b.pos_aufnr AND b.pos_prodnr = p.prod_nr AND a.auf_status = 10 GROUP BY TRUNC(a.auf_datum), b.pos_prodnr Listing 11.11: Multi-Table Insert
Table-Functions Für den Aufbau der eigentlichen Data Warehouse-Tabellen werden oft so genannte Staging-Tabellen verwendet, in denen Zwischenergebnisse gespeichert werden müssen, da die Verarbeitungslogik so kompliziert ist, dass sie nicht in einem Programmschritt durchgeführt werden kann. Mit den Table-Functions ist es jetzt möglich, kaskadierende Funktionen aufzubauen, die als Ergebnis eine temporäre Tabelle liefern, die dann sofort weiterverwendet werden kann. Die verfügbaren Funktionen können dabei eine Vorselektion durchführen, aber auch autonome Transaktionen starten, um beispielsweise fehlerhafte Datensätze zu protokollieren, ohne die Verarbeitung zu behindern. Das folgende Beispiel zeigt, wie aus einer externen Tabelle neue_auftraege zunächst die Aufträge herausgefiltert werden, die den Status 10 (geliefert) oder 99 (storniert) haben, und dann im zweiten Schritt die stornierten Aufträge in einer separaten Tabelle stornierte_auftraege protokolliert und aus der Verarbeitung herausgenommen werden. Als Ergebnis wird eine Tabelle gueltige_auftraege erstellt, die nur die Datensätze enthält, die den Status 10 haben. CREATE OR REPLACE TYPE auftraege_t AS object ( aufnr NUMBER (10), prodnr NUMBER(10), datum DATE, lieferdatum DATE,
Sandini Bib
680
status grpnr menge preis
Data Warehousing
NUMBER, NUMBER(10), NUMBER, NUMBER);
/ CREATE OR REPLACE TYPE auftraege_t_table AS TABLE OF auftraege_t; / CREATE OR REPLACE PACKAGE cursor_PKG AS TYPE auftraege_t_rec IS RECORD ( aufnr NUMBER (10), prodnr NUMBER(10), datum DATE, lieferdatum DATE, status NUMBER, grpnr NUMBER(10), menge NUMBER, preis NUMBER); TYPE auftraege_t_rectab IS TABLE OF auftraege_t_rec; TYPE s_refcur_t IS REF CURSOR RETURN auftraege_t_rec; TYPE refcur_t IS REF CURSOR; END; / CREATE TABLE stornierte_auftraege (prodnr NUMBER, text VARCHAR2(2000)); CREATE OR REPLACE FUNCTION gelieferte_auftraege_pipe (cur cursor_pkg.s_refcur_t) RETURN auftraege_t_table PIPELINED PARALLEL_ENABLE (PARTITION cur BY ANY) IS aufnr NUMBER (10); prodnr NUMBER(10); datum DATE; lieferdatum DATE; status NUMBER; grpnr NUMBER(10); menge NUMBER; preis NUMBER; objset auftraege_t_table := auftraege_t_table(); i NUMBER := 0; BEGIN LOOP FETCH cur INTO aufnr, prodnr, datum, lieferdatum, status, grpnr, menge, preis; EXIT WHEN cur%NOTFOUND; IF STATUS > 9 THEN PIPE ROW (auftraege_t(aufnr, prodnr, datum, lieferdatum, status, grpnr, menge, preis));
Sandini Bib
Extraktion, Transformation, Laden
681
-- liefert den Datensatz aus der Pipe END IF; END LOOP; CLOSE cur; RETURN; END; / CREATE OR REPLACE FUNCTION stornierte_auftraege_dml (cur cursor_pkg.s_refcur_t, aufstatus number DEFAULT 99) RETURN auftraege_t_table PIPELINED PARALLEL_ENABLE (PARTITION cur BY ANY) -- Baut eine Pipeline auf, die die Sätze nacheinander ausgibt IS PRAGMA AUTONOMOUS_TRANSACTION; aufnr NUMBER (10); prodnr NUMBER(10); datum DATE; lieferdatum DATE; status NUMBER; grpnr NUMBER(10); menge NUMBER; preis NUMBER; i NUMBER := 0; BEGIN LOOP FETCH cur INTO aufnr, prodnr, datum, lieferdatum, status, grpnr, menge, preis; EXIT WHEN cur%NOTFOUND; IF STATUS = aufstatus THEN INSERT INTO stornierte_auftraege VALUES (aufnr,'Auftrag Storniert für Produkt '||prodnr); ELSE PIPE ROW (auftraege_t(AUFNR, PRODNR, DATUM, LIEFERDATUM, STATUS, GRPNR, MENGE, PREIS)); -- liefert den Datensatz aus der Pipe für die Weiterverarbeitung END IF; END LOOP; COMMIT; CLOSE cur; RETURN; END; / Listing 11.12: Typen und Prozeduren für Table-Functions
Sandini Bib
682
Data Warehousing
Es werden also in diesem Beispiel zwei Funktionen, gelieferte_auftraege_pipe für die Auswahl aller Aufträge mit dem Status 10 oder 99, und stornierte_auftraege_dml für die Einträge der stornierten Aufträge in die Tabelle stornierte_auftraege, erstellt. Der Auftragsstatus von stornierten Aufträgen wird variabel gehalten, so dass auch andere Auftragsstati abgefragt werden können. Nähere Informationen über den Aufbau einer solchen Prozedur finden Sie in der Oracle Dokumentation, PL/SQL User’s Guide and Reference. Die Abfrage der gültigen Datensätze für eine weitere Verarbeitung erfolgt jetzt über folgende SQL-Anweisung: CREATE TABLE gueltige_auftraege AS SELECT aufnr, prodnr, status, datum, grpnr, menge, preis FROM TABLE(stornierte_auftraege_dml (CURSOR(SELECT * FROM TABLE(gelieferte_auftraege_pipe (CURSOR(SELECT * FROM neue_auftraege)))) )); Listing 11.13: Abfrage der gültigen Aufträge
Die innere SELECT-Anweisung wird zuerst ausgeführt und liefert damit die gewünschten Aufträge mit dem Status 10 oder 99. Das Ergebnis wird an die zweite SELECT-Anweisung übergeben, die die Aufträge mit dem Status 99 herausfiltert. In dieser SELECT-Anweisung wird eine autonome Transaktion ausgeführt, die die Tabelle stornierte_auftraege füllt.
11.1.4 Überwachung der Ladeoperation Resumable Statements Bei umfangreichen Ladeoperationen kann es natürlich zu Engpässen im System kommen (Tablespace zu klein, Rollback-Segmente zu klein etc.). In der Regel führen diese Ressourcen-Engpässe dazu, dass die Transaktion abgebrochen und zurückgerollt wird. Diese Rollback-Operation kann durchaus mehrere Stunden dauern. Mit Version 9i ist es möglich, dass der gerade ausgeführte Befehl beim Auftreten eines Engpasses angehalten wird und nach der Behebung des Fehlers selbständig wieder anläuft. Damit können im laufenden Betrieb folgende Fehler behoben werden: ORA-1650 ORA-1653 ORA-1654 ORA-1628 ORA-1631 ORA-1654 ORA-1536
unable to extend rollback segment ... in tablespace ... unable to extend table ... in tablespace ... unable to extend index ... in tablespace ... max # extents ... reached for rollback segment ... max # extents ... reached in table ... max # extents ... reached in index ... space quote exceeded for tablespace ...
Listing 11.14: Liste der durch Resumable Statements tolerierten Fehler
Sandini Bib
Extraktion, Transformation, Laden
683
Vor der Ausführung der eigentlichen Operation wird die Session in den ResumableModus gesetzt. Zusätzlich kann angegeben werden, wie lange der Befehl warten soll, bis er endgültig abgebrochen wird. Es kann außerdem ein Name mitgegeben werden, über den die Session identifiziert werden kann. Tritt ein Fehler auf, wird dieser mit dem Namen der Operation in der Alert-Datei protokolliert, der Befehl wird angehalten und der Datenbankadministrator hat TIMEOUT-Sekunden Zeit, um den Engpass zu beheben. Folgendes Beispiel zeigt den Wiederanlauf einer INSERT-Operation auf die Tabelle verkaeufe, wenn das entsprechende Tablespace mini zu klein ist. SQL> ALTER SESSION ENABLE RESUMABLE TIMEOUT 1200 NAME 'verkaeufe'; SQL> INSERT INTO verkaeufe ...
In der Alert-Datei findet sich dann folgender Eintrag: statement in resumable session 'verkaeufe' was suspended due to ORA-01653: Tabelle DEMO.VERKAEUFE kann nicht um 16 in Tablespace MINI erweitert werden
Mit dem Befehl: ALTER DATABASE DATAFILE ... AUTOEXTEND ... wird der Fehler behoben. Danach läuft das Statement wieder an und in der Alert-Datei findet man den Eintrag: ALTER DATABASE DATAFILE 'e:\oracle\oradata\ja901\o1_mf_mini_yfq8r600_.dbf' AUTOEXTEND ON NEXT 10M MAXSIZE 20M Completed: ALTER DATABASE DATAFILE 'e:\oracle\oradata\ja901\o statement in resumable session 'verkaeufe' was resumed Listing 11.15: Resumable Statement
Natürlich ist es wichtig, die Einträge in der Alert-Datei regelmäßig auszulesen, um entsprechende Fehler schnell genug zu erkennen. Anderenfalls wird der Befehl abgebrochen, weil die maximale Zeit des Wartens auf die Fehlerbehebung abgelaufen ist. Außerdem werden bei DML-Operationen die entsprechenden Zeilen gesperrt, so dass andere Anwendungen nicht weiterarbeiten können. Die Alert-Datei kann am besten mit dem Oracle Enterprise Manager (Event Management) oder anderen Anwendungen überwacht werden. Außerdem ist es möglich, einen Datenbank-Trigger auf die Suspend-Operation aufzusetzen, um beim Auftreten des Fehlers eine E-Mail oder andere Meldung zu schicken. CREATE OR REPLACE TRIGGER resumable_default AFTER SUSPEND ON DATABASE ... Listing 11.16: Datenbank-Trigger auf Suspend
Sandini Bib
684
Data Warehousing
Überwachung von Jobs Gerade bei der Verarbeitung umfangreicher Operationen stellt sich immer wieder die Frage, wie man feststellen kann, wie lange dieser Vorgang noch dauern wird bzw. welcher Befehl gerade abgearbeitet wird. Dafür gibt es schon seit der Version 8i die Möglichkeit, lange laufende Befehle zu überwachen. Zum einen kann dies über die Abfrage der virtuellen Tabelle v$session_longops geschehen. Wesentlich einfacher ist aber die Benutzung des Oracle Enterprise Managers. Wenn man sich die SESSIONS anzeigen lässt, werden Sitzungen, in denen Befehle eine bestimmte Zeit überschritten haben, mit dem Symbol einer Uhr gekennzeichnet. Für diese Sitzungen stehen jetzt unter dem Detail LANGE VORGÄNGE Informationen über bereits abgeschlossene und noch laufenden Befehle zur Verfügung.
Abbildung 11.1: Long Running Job
Voraussetzung für die Verwendung dieser Funktion ist, dass der Initialisierungsparameter timed_statistics = true gesetzt ist.
Sandini Bib
Datenbankdesign für Data Warehouses
685
11.2 Datenbankdesign für Data Warehouses Beim Datenbankdesign ist zunächst einmal wichtig, auf welcher Hardware und welchem Betriebssystem die Datenbank installiert werden soll. Dabei sind folgende Fragen zu klären: 1. Wie groß wird die Datenbank? 2. Wie viele Benutzer arbeiten mit dem System? 3. Welche Ausfallzeiten können toleriert werden? 4. In welchen Zyklen werden die Datensätze in das Data Warehouse eingepflegt? 5. Kann es zu Änderungsoperationen im Data Warehouse kommen? Die Beantwortung dieser Fragen ist von entscheidender Bedeutung für den Erfolg oder Misserfolg dieses Projektes und sollte deshalb wohl überlegt sein. Zu Frage 1: Gerade bei einem Data Warehouse bewahrheitet sich der Spruch „Der Appetit kommt beim Essen“. Wenn die ersten Daten aus dem Warehouse in einer schönen grafischen Oberfläche zur Verfügung stehen, kommt meist sofort die Frage, ob man nicht noch weitere Informationen haben könnte. Dadurch wird dieses System schnell zu einem Selbstläufer und daher ist es wichtig, hier eine entsprechende Skalierung vorzusehen. Zu Frage 2: Wie auch in Frage 1 kommen im Laufe der Zeit immer mehr Benutzer auf das System, das bedeutet, es muss möglich sein, mehr Prozessoren oder sogar zusätzliche Systeme an das Warehouse anzuschließen. Zu Frage 3: Bei einer ersten Befragung wird wahrscheinlich herauskommen, dass ein Ausfall von einem Tag toleriert werden kann. Wenn dann das System einen entsprechenden Stellenwert im Unternehmen hat, kann dies durchaus dazu führen, dass die tolerierbare Ausfallzeit auf wenige Stunden sinkt. Sie sollten dabei aber bedenken, dass im gleichen Maße die Datenmenge gestiegen ist. Zu Frage 4: In der Regel wird ein Data Warehouse-System tagesaktuell sein, d.h., während der Nacht werden die neuen Daten in das System geladen. Was passiert aber, wenn das System im Internet zur Verfügung stehen soll (also 24 StundenBetrieb)? Was passiert, wenn Auslandsgesellschaften ihre Daten ebenfalls in dem System abspeichern sollen. Mit zunehmender Größe der Datenbank wird aber unter Umständen der Ladevorgang entsprechend länger dauern. Zu Frage 5: Sicherlich ist in vielen Unternehmen eine Forderung an ein Data Warehouse die, dass sich die Daten nicht mehr ändern dürfen. Doch was ist, wenn sich Gebietsstrukturen ändern oder ein Unternehmen neu strukturiert wird? Müssen dann die historischen Daten nachgepflegt werden, damit ein entsprechender Vergleich überhaupt noch möglich ist? Diese Fragen dienen im Folgenden als Anhaltspunkte für die Oracle-Funktionen beim Aufbau eines Data Warehouse-Systems.
Sandini Bib
686
Data Warehousing
11.2.1 Hardware-Architekturen Die wichtigste Komponente beim Aufbau eines Data Warehouse ist das I/O-Subsystem. Da sehr große Datenmengen in einer kurzen Zeit durchsucht werden müssen, kann der Hauptspeicher sicherlich nicht allen Anforderungen gerecht werden. Es ist daher die erste Aufgabe ein geeignetes I/O-System zu finden, das den Anforderungen nach großer I/O-Bandbreite und hoher Verfügbarkeit gerecht wird. Die Bandbreite wird im Wesentlichen durch die Komponenten Controller und Platten bestimmt. Um also einen optimalen I/O-Durchsatz zu erhalten, sollten die Datenbankdateien über möglichst viele Platten mit möglichst vielen Controllern verteilt werden. Dies erreicht man am besten durch Hardware-Striping (Raid-0) über alle verfügbaren Platten. Die Größe der einzelnen Stripe-Sets liegen dabei zwischen 64 Kbyte und 256 Kbyte je nach verwendetem Betriebssystem. Jede Platte sollte zusätzlich über Raid-1 gespiegelt werden, um eine optimale Verfügbarkeit zu gewährleisten. In vielen großen Unternehmen ist die Firma EMC2 mit den Symmetrix-Modellen heute als Anbieter gesetzt, da sie eine gute Performance bei gleichzeitig hoher Verfügbarkeit gewährleistet. Leider verwendet EMC2, wie auch andere Hardware-Hersteller, heute sehr große Platten (bis zu 181 Gbyte). Damit wird selbst bei großen Data Warehouse-Systemen die Möglichkeit der Verteilung eingeschränkt. Daneben bietet EMC2 mit dem Produkt Timefinder eine sehr effektive Möglichkeit, große Datenbanken schnell zu sichern und wieder herzustellen. Dabei wird ein zusätzlicher Spiegel (BCV = Business Continuance Volumes) der Festplatten aufgesetzt, der jederzeit entkoppelt werden kann und dann als eigenständiges System zur Verfügung steht. Während der Entkoppelung werden alle Änderungen auf den Platten mitprotokolliert, so dass für die Wiedereingliederung der BCV’s nur die geänderten Blöcke überschrieben werden. Alle Hardware-Hersteller bieten heute Mehrprozessorsysteme an, die durch Hinzunahme weiterer CPUs oder Memory-Boards entsprechend skalierbar sind. Die Oracle Architektur kann solche Systeme auch ohne die Parallel-Query-Funktionalität unterstützen, da es keinen Prozess gibt, der zu einem Engpass führen könnte. Sie können heute mehrere DBWR- oder LGWR- Prozesse konfigurieren und die Benutzer sind in der Regel sowieso über einen dedizierten Prozess mit der Instanz verbunden. Durch die Parallel-Query Option, die Oracle mit der Version 7.1 eingeführt hat, kommt zusätzlich die Möglichkeit hinzu, auch einen einzelnen Benutzerprozess auf mehrere CPUs zu verteilen. Neben der SMP-Fähigkeit bieten die Hardware-Hersteller je nach Art der CPU zusätzliche 64bit Betriebssysteme an. Während bei den 32-Bit-Versionen die Obergrenze für die Oracle-SGA bei 3,6 Gbyte liegt, können mit einer 64-Bit-Version beliebig große Bereiche für die SGA adressiert werden (20 Gbyte und mehr sind heute keine Seltenheit). Sie sollten also beim Neuaufbau einer solchen Datenbank darauf achten, dass Sie ein entsprechendes Betriebssystem (z.B. SUN Solaris 8 oder Compaq True64) und die dazu passende Oracle-Software einsetzen.
Sandini Bib
Datenbankdesign für Data Warehouses
687
Neben der Skalierbarkeit ist die Ausfallsicherheit eines Hardware-Clusters in Verbindung mit dem Oracle Real Application Cluster ein wichtiger Aspekt für den Einsatz in einem Data Warehouse. Dabei sollte allerdings beachtet werden, dass einige Anpassungen im Bezug auf das Datenbankdesign durchgeführt werden sollten. Denn trotz der Möglichkeit, die Datenbank-Blöcke über das Netzwerk zwischen den Instanzen hin und her zu kopieren (Cache Fusion), liegt es auf der Hand, dass es performanter ist, wenn sich alle Daten in der lokalen SGA befinden und somit keine Netz- oder Plattenzugriffe nötig sind. Real Application Cluster Der Real Application Cluster wurde schon in Kapitel 2.6 beschrieben, es sollen deshalb hier nur die Einsatzgebiete im Data WarehouseData Warehouse-Bereich erläutert werden. Der Real Application Cluster zeichnet sich gegenüber anderen Systemen durch zwei wesentliche Punkte aus: 1. Erhöhung der Verfügbarkeit durch zusätzliche Knoten 2. Skalierbarkeit über die Grenzen eines Knotens hinaus Hier nochmals die wesentlichen Merkmale eines Real Application Clusters:
Abbildung 11.2: Real Application Cluster
Wie Abbildung 11.2 zeigt, greifen jetzt mehrere Knoten auf einen gemeinsamen Datenbestand zu. Notwendig hierfür ist neben der entsprechenden Oracle-Software die Möglichkeit, ein Plattensubsystem im Shared-Modus zu betreiben, so dass tatsächlich ein gleichzeitiger Zugriff auf den Datenbestand möglich ist. Diese Architektur wird heute mit spezieller Hardware von allen gängigen Betriebssystemen (SUN Solaris, HP/UX, IBM AIX, Compaq True64, Linux, Compaq VMS und MS-Windows 2000) unterstützt. Auf den meisten Betriebssystemen (bis auf IBM AIX und Compaq VMS) müssen für den Aufbau einer derartigen Datenbank alle Datenbankkomponenten (Datenbank-
Sandini Bib
688
Data Warehousing
dateien, Kontrolldateien, Redolog-Dateien) auf Raw-Devices installiert werden. Da aus Administrationsgründen auf Raw-Devices gerne verzichtet wird, bedeutet dies für einen Umstieg auf Real Application Cluster oftmals einen nicht zu unterschätzenden Migrationsaufwand. Sollten Sie also ein Data Warehouse aufsetzen wollen und bezüglich der Skalierbarkeit eine Real Application Cluster-Architektur für die Zukunft ins Auge gefasst haben, dann sollten Sie schon frühzeitig auf Raw-Devices umsteigen. Während in der Vergangenheit der Vorgänger des Real Application Clusters (Oracle Parallel Server) nur sehr bedingt skalierbar war, kann durch die Neuimplementierung (ca. 70% des gesamten Codes wurden neu erstellt) davon ausgegangen werden, dass ein Sklalierungsfaktor von 90% und mehr beim Einsatz von Real Application Cluster gerade im Umfeld Data Warehouse erreicht werden kann. Dies gilt sowohl für die Abfrage als auch für das Laden von Daten über mehrere Knoten hinweg. Für die Anwender kann durch den Einsatz eines effektiven Connection-Load-Balancing zusätzlich ohne großen Aufwand eine Gleichverteilung der Last auf alle Knoten erreicht werden. Erreicht wird dies über die Konfiguration des Oracle Net Clients und den Oracle Net Listener (siehe auch Kapitel 5). Oracle ermöglicht schon seit der Version 8.1 ein Connection-Load-Balancing, allerdings nur über die Multi-Threaded-Server-Konfiguration, d.h., die Verbindungen können nur über sog. Dispatcher auf verschiedene Server verteilt werden. Mit der Version 9 ist dies auch bei der Verwendung von dedizierten Verbindungen, der Standardkonfiguration von Oracle Net, möglich. Erforderlich sind für den Einsatz von Connection-Load-Balancing folgende Initialisierungsparameter: service_name instance_name remote_listener
Das bedeutet für die in Real Application Cluster gezeigte Konfiguration:
:
Initialisierungsparameter auf K01 (Knoten 1) service_name instance_name db_name remote_listener
:
= = = =
DWH.hl.de DWH01 DWH listener_dwh02
Listener-Konfiguration auf K01 LISTENER_DWH01 = ( DESCRIPTION = (ADDRESS = (PROTOKOLL = TCP) (HOST = K01) (PORT = 1521)))
Sandini Bib
Datenbankdesign für Data Warehouses
:
Initialisierungsparameter auf K02 (Knoten 2) service_name instance_name db_name remote_listener
:
689
= = = =
DWH.hl.de DWH02 DWH listener_dwh01
Listener-Konfiguration auf K02 LISTENER_DWH02 = ( DESCRIPTION = (ADDRESS = (PROTOKOLL = TCP) (HOST = K02) (PORT = 1521)))
:
Konfigurationsdatei auf dem Client (tnsnames.ora) DWH.hl.de = ( DESCRIPTION = (LOAD_BALANCE = ON) (ADDRESS = (PROTOKOLL = TCP) (HOST = K01) (PORT = 1521)) (ADDRESS = (PROTOKOLL = TCP) (HOST = K01) (PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = DWH.hl.de)
Eine Beschreibung der Instanzen für einen Listener (SID_LIST_LISTENER) muss nicht angegeben werden, da ab der Version 8.1 der PMON-Prozess der entsprechenden Instanz diese beim Listener anmeldet. Durch die Verwendung des Initialisierungsparameters REMOTE_LISTENER wird die Instanz über den Service-Namen auch bei der entfernten (REMOTE) Datenbank angemeldet. Neben dem Connection-Load-Balancing kann natürlich auch ein automatisches Failover von einer Instanz auf die andere konfiguriert werden. Dies ist aber in der Regel in einem Data Warehouse-System nicht erwünscht, weil durch die zusätzliche Verbindung Ressourcen belegt werden. Wenn ein System wie oben beschrieben einmal konfiguriert ist, kann durch die Hinzunahme weiterer Knoten die Skalierung über die Grenzen eines Systems hinaus erreicht werden. Durch den mit Version 8.1 eingeführten und in Version 9 optimierten Mechanismus Cache-Fusion ist es möglich, selbst beim Laden von Daten eine Verteilung über die Knoten hinweg vorzunehmen. Das bedeutet, dass DMLOperationen über Knotengrenzen hinweg parallelisiert werden können.
Sandini Bib
690
Data Warehousing
Es liegen leider zur Zeit noch keine Messergebnisse für ein Load-Balancing bei DML-Operationen vor, allerdings muss davon ausgegangen werden, dass die Performance hier nicht den Skalierungsfaktor des Load-Balancing von Abfragen erreicht. Dies ist schon darin begründet, dass Datenbankblöcke je nach eingesetzter Hardware über das Netzwerk von einer auf die andere Instanz übertragen werden müssen. Daher sollten Sie auch weiterhin darauf achten, dass ein gleichzeitiger schreibender Zugriff von mehreren Instanzen auf den gleichen Block vermieden wird.
11.2.2 Tablespace-Layout Neben dem Aufbau von unterschiedlichen Partitionen für Tabellen spielt auch die Verteilung und der Aufbau von Tablespaces eine entscheidende Rolle für die Performance und Administrierbarkeit eines Data Warehouses. Für das Anlegen der Tablespaces sollte Folgendes beachtet werden: 1. I/O-Performance 2. Administrierbarkeit 3. Aufteilung von Partitionen 4. Blockgröße 5. Logging 6. Transportable Tablespaces Das Thema I/O-Performance wurde schon im Kapitel Hardware-Architekturen beschrieben. Da beim Aufbau eines Data Warehouse oftmals Raid-0-Technologie eingesetzt wird, wird dem Thema I/O-Verteilung kein großes Augenmerk geschenkt. In kleineren Systemen wird dieses Thema durch das direkte Anlegen mehrerer Datendateien für einen Tablespace abgedeckt, da dann die Extents gleichmäßig über alle Dateien verteilt werden. Bei der Administrierbarkeit schlagen zwei Herzen in einer Brust. Zum einen sollte man vermeiden, zu viele Tablespaces zu erstellen, da man dann die Übersicht verliert bzw. Werkzeuge wie den Oracle Enterprise Manager kaum noch einsetzen kann, weil die Darstellung nicht ausreicht. Zum anderen ist es aber sinnvoll, große Tabellen – wenn sie nicht partitioniert sind – in einem separaten Tablespace zu halten, da dadurch das Backup und Recovery vereinfacht wird und bei partitionierten Tabellen einzelne Tablespaces Read-Only gesetzt werden können. Durch die Verwendung von unterschiedlichen Blockgrößen in den einzelnen Tablespaces kann man diese natürlich ebenfalls weiter diversifizieren, so dass kleine Tabellen eine andere Blockgröße als große bekommen. Sie sollten dabei aber beachten, dass Sie für jede verwendete Blockgröße auch einen entsprechenden Platz in der SGA zur Verfügung stellen müssen. Außerdem müssen alle Partitionen einer Tabelle oder eines Indexes in Tablespaces der gleichen Blockgröße liegen. In einem Data Warehouse kann man davon ausgehen, dass man mit zwei oder drei unterschiedlichen Blockgrößen auskommt. Dies sind:
Sandini Bib
Datenbankdesign für Data Warehouses
: : :
691
4 Kbyte oder 8 Kbyte für die System- und Dimensionstabellen und Verwaltungsinformationen. 8 Kbyte oder 16 Kbyte für die wesentlichen Faktentabellen, d.h. der Großteil des Data Warehouse. 16 Kbyte oder 32 Kbyte für Tabellen mit LOB-Spalten.
Damit ist der Verwaltungsaufwand in Grenzen gehalten und der Großteil der Daten wird über die mittlere Blockgröße anfallen und somit die Größe der SGA bestimmen. NOLOGGING In der Regel stehen die Informationen, die in ein Data Warehouse geladen werden, zusätzlich in operativen Systemen zumindest noch eine gewisse Zeit zur Verfügung. Daher können viele Operationen (Laden von Daten, Aufbau von Indizes, Verdichten von Daten) ohne Transaktionsprotokolle durchgeführt werden, da bei einem Absturz des Systems die Information ohne Probleme noch einmal abgerufen werden kann. Es bietet sich also an, wenn nicht die Lade- bzw. Verarbeitungsroutinen selbst schon entsprechende Vorkehrungen getroffen haben, die Objekte mit der Option NOLOGGING anzulegen. Damit werden bei Massendaten-Operationen nur noch die Befehle in den Redolog-Dateien gespeichert, nicht jedoch die Daten selbst. Als ersten Schritt können dabei die Tablespaces mit der Option angelegt werden, da diese dann auf die entsprechenden Objekte (Tabellen, Indizes, Partitionen) vererbt werden. SQL> CREATE TABLESPACE demo_ts ... NOLOGGING;
Mit dem Befehl ALTER TABLESPACE ... NOLOGGING können natürlich auch bereits vorhandene Tablespaces verändert werden, es sollte aber beachtet werden, dass sich diese Änderung nur auf neu angelegte Objekte bezieht, nicht aber auf bereits existierende. Dann ist es sinnvoll, zusätzlich die bereits vorhandenen Objekte mit der NOLOGGING-Option zu versehen, z.B. ALTER TABLE ... NOLOGGING. Die Vorteile sind:
: : :
Weniger Platzbedarf für Redolog- bzw. archivierte Redolog-Dateien Schnellere Verarbeitung, da weniger I/O Kürzere Recovery-Zeiten (allerdings müssen dann die Befehle auf noch vorhandene Daten aufsetzen können)
Wenn Objekte die NOLOGGING-Option gesetzt haben, werden folgende Operationen nicht mehr protokolliert.
: : :
Direct-Path (INSERT /*+ APPEND */ oder /*+ PARALLEL */) SQL*LOADER (DIRECT = TRUE) DDL-Operationen (z.B. CREATE TABLE ... AS SELECT)
Sandini Bib
692
Data Warehousing
Wenn es in einem solchen Fall zu einem Media-Recovery kommt, dann werden die entsprechenden Blöcke als logisch korrupt gekennzeichnet, d.h., sie müssen gelöscht und neu angelegt werden. Oftmals umgeht man dieses Problem, indem man nach einer solchen Operation ein Backup durchführt.
11.2.3 Partitionierung Oracle hat mit der Version 8 die Partitionierung als eine wichtige Erweiterung für den Aufbau von Data Warehouses eingeführt. Aber gerade auch die Erweiterungen von Version 8.1 und Version 9i erlauben einen sehr effektiven Einsatz der einzelnen Partitionierungsoptionen. Damit wird einmal die Administration von großen Datenbanken vereinfacht (Löschen und Hinzufügen von Partitionen) und zum anderen eine weitere Optimierung bei der Verwendung von Parallelisierung ermöglicht (paralleler Index-Range-Scan) (siehe auch Kapitel 3.4). Range Partition Da in einem Data Warehouse die Detaildaten (Fact Tables) oftmals ein Datum enthalten, liegt es nahe, diese Tabellen und zugehörige Indizes nach dem Datum (Monat, Quartal) zu partitionieren. Der Vorteil liegt zum einen in einem schnellen Zugriff auf die Daten durch die Möglichkeit, nicht betroffene Datumsbereiche auszusparen (Partition Pruning), zum anderen in der effektiveren Administration (Rolling Window). CREATE TABLE verkaeufe ( rechnungsnr NUMBER, datum DATE, prodnr NUMBER, menge NUMBER, preis NUMBER ) PARTITION BY RANGE (datum) ( PARTITION q1_01 VALUES LESS TABLESPACE ts1, PARTITION q2_01 VALUES LESS TABLESPACE ts2, PARTITION q3_01 VALUES LESS TABLESPACE ts3, PARTITION q4_01 VALUES LESS TABLESPACE ts4, PARTITION q1_02 VALUES LESS TABLESPACE ts1);
THAN (to_date('01042001','DDMMYYYY')) THAN (to_date('01072001','DDMMYYYY')) THAN (to_date('01102001','DDMMYYYY')) THAN (to_date('01012002','DDMMYYYY')) THAN (MAXVALUE)
Listing 11.17: Range Partitioning
SQL> SELECT sum(menge * preis) FROM verkaeufe WHERE datum BETWEEN to_date(’30.09.2001’,’DD.MM.YYYY’) AND to_date(’05.11.2001’,’DD.MM.YYYY’);
Sandini Bib
Datenbankdesign für Data Warehouses
693
Ausführungsplan: OPERATION OPTIONS POSITION START STOP ------------------------- ---------------- ---------- ----- ---SELECT STATEMENT () 300 SORT AGGREGATE() 1 PARTITION RANGE ITERATOR() 1 3 4 TABLE ACCESS FULL(VERKAEUFE) 1 3 4 Listing 11.18: Partition Elimination
An diesem Beispiel wird deutlich, dass nur auf die Partitionen 3 und 4 zugegriffen wird, leider ist es uns aber bisher nicht gelungen nachzustellen, dass auf eine Partition über den Index und auf die andere über einen Full-Table-Scan zugegriffen wird. Wie im Beispiel sichtbar, wird, obwohl in der Partition 3 nur der 30. September selektiert wird, auf beide Partitionen über einen Table-Scan zugegriffen. Neben dem Partition Pruning bietet diese Form der Partitionierung den Vorteil, dass alte Daten per DDL-Operation gelöscht werden können (DROP PARTITION) und neue Daten über ein Partition Exchange aus bereits bestehenden Tabellen sehr schnell übernommen werden können. In vielen Data Warehouse-Systemen ist daher diese Art der Partitionierung in der vergangenen Zeit die erste Wahl gewesen. In diesem Zusammenhang wird immer wieder der Begriff Rolling Window genannt. Gemeint ist damit, dass sich das Zeitfenster für die Betrachtung verschiebt. Im obigen Beispiel könnte man auf die Idee kommen, das 1. Quartal 2001 auszulagern (zum Beispiel auf ein Read-Only-Medium) und ein neues Quartal für das Jahr 2002 hinzuzunehmen. Sie sollten aber vorsichtig mit dem Befehl SPLIT PARTITION sein. Es liegt zunächst nahe zu sagen, alle Daten des Jahres 2002 wandern zunächst in die Partition Q1_02. Am Ende des Quartals wird dann diese Partition aufgespalten (SPLIT PARTITION) und damit eine neue Partition Q2_02 angelegt. Dabei werden aber alle Daten der ursprünglichen Partition bewegt, d.h., die komplette Partitionsinformation der Partitionen Q1_02 und Q2_02 werden neu eingepflegt, was durchaus einige Zeit dauern kann und entsprechende Rollback- und Redolog-Information erzeugt. Besser ist es daher, immer eine „Dummy“-Partition zu benutzen, um dann auf einer leeren Partition die entsprechende Spaltung auszuführen. Ein Beispiel verdeutlicht dies: Angenommen, es ist Jahresende 2001 und es wird erwartet, dass die ersten Daten für das Jahr 2002 in die Tabelle verkaeufe eingegeben werden (siehe Beispiel Range Partitioning). Es ist jetzt an der Zeit, eine neue Partition für das 2. Quartal 2002 aufzubauen in der Form:
Sandini Bib
694
Data Warehousing
ALTER TABLE verkaeufe SPLIT PARTITION q1_02 AT (TO_DATE('01042002','DDMMYYYY')) INTO (PARTITION q1_02, PARTITION q2_02 TABLESPACE ts2); Listing 11.19: Partition Split
Damit wird sichergestellt, dass nur wenige Daten verschoben werden müssen, allerdings auf Kosten einer zusätzlichen immer leeren Partition. Wenn Sie sicherstellen können, dass keine Daten in die mit MAXVALUE limitierte Partition eingegeben werden, können Sie natürlich auch ganz auf die Partition verzichten und dann zu gegebener Zeit über den Befehl ADD PARTITION eine neue Partition anlegen. ALTER TABLE verkaeufe ADD PARTITION q2_02 VALUES LESS THAN (to_date('01072002','DDMMYYYY')) TABLESPACE ts2; Listing 11.20: ADD PARTITION
Dieser Befehl fügt eine Partition an der oberen Partitionsgrenze ein, kann also nicht genutzt werden, wenn eine Partition mit der Grenze MAXVALUE angelegt worden ist. Hash Partition Fälschlicherweise wird oftmals angenommen, Hash-Partitionierung käme nur dann zum Einsatz, wenn ein Striping auf Betriebssystemebene (Raid-0) nicht möglich ist. Sicherlich kann auch das ein Grund für diese Art der Partitionierung sein. Viel wichtiger aber ist die Möglichkeit, auf diese Weise sehr effektive Join-Operationen zwischen großen Tabellen durchzuführen. Wenn zwei große Tabellen beide über den gleichen Hash-Schlüssel partitioniert worden sind (Equi-Partitioning), so kann bei einem Join über diese Tabellen auf einen Indexzugriff verzichtet werden; wenn noch andere Einschränkungen in einer Abfrage existieren, können diese dann über die zusätzlichen Indizes verwaltet werden. Ein Beispiel soll dies verdeutlichen: Zwei Tabellen werden nach einer Kundennummer partitioniert: CREATE TABLE verkaeufe ( rechnungsnr NUMBER, kdnr NUMBER, datum DATE, prodnr NUMBER, menge NUMBER, preis NUMBER
Sandini Bib
Datenbankdesign für Data Warehouses
PARTITION BY HASH (kdnr) ( PARTITION v1_01 TABLESPACE PARTITION v2_02 TABLESPACE PARTITION v3_03 TABLESPACE PARTITION v4_04 TABLESPACE
695
ts1, ts2, ts3, ts4);
CREATE TABLE kunden ( kdnr NUMBER (10) NOT NULL, anrede VARCHAR2 (5), vorname VARCHAR2 (50), nachname VARCHAR2 (50), adresse VARCHAR2 (50), ort VARCHAR2 (50), plz NUMBER (6)) PARTITION BY HASH (kdnr) ( PARTITION k1_01 TABLESPACE ts1, PARTITION k2_02 TABLESPACE ts2, PARTITION k3_03 TABLESPACE ts3, PARTITION k4_04 TABLESPACE ts4); Listing 11.21: Hash Partition
SQL> SELECT sum(menge * preis) FROM verkaeufe v, p_kunden k WHERE v.kdnr = k.kdnr AND k.nachname = 'Behrends' AND k.ort = 'Leer' AND k.kdnr = 109756; Plan Table -------------------------------------------------------------------| | Operation | Name | Rows | Pstart| Pstop | |------------------------------------------------------------------| | SELECT STATEMENT | | 1 | | | | SORT AGGREGATE | | 1 | | | | HASH JOIN | | 1 | | | | TABLE ACCESS BY LOCAL I |P_KUNDEN | 1 | 2 | 2 | | INDEX RANGE SCAN |IDX_ORT | 1 | 2 | 2 | | TABLE ACCESS FULL |VERKAEUFE | 58 | 2 | 2 | ------------------------------------------------------------------Listing 11.22: Partition-Wise Join
Der Ausführungsplan zeigt, dass hier nur die Partition 2 der beiden Tabellen p_kunden und verkaeufe genutzt wird.
Sandini Bib
696
Data Warehousing
Composite Partition Aus den oben genannten Beispielen für die Vorteile von Range und Hash Partitioning wird deutlich, dass bei sehr großen Tabellen eine Verknüpfung der beiden Methoden Sinn macht. Damit wird einmal eine effektive Administration und zum anderen ein schneller Zugriff auf die Daten erreicht. Der Aufbau und die Verwendung dieser Art der Partitionierung wird schon in Kapitel 3.4 ausführlich behandelt, daher wird an dieser Stelle auf ein Beispiel verzichtet. List Partition In größeren Data Warehouse-Systemen kommt es immer häufiger vor, dass Informationen nach Gebieten eingeteilt werden müssen. Da bei einer Range Partition nur ein Grenzwert eingegeben werden kann, hat man sich in der Vergangenheit mit der Nummernvergabe für Gebiete beholfen. Ein Data Warehouse lebt aber von der direkten Lesbarkeit der Daten (Denormalisierung), um umfangreiche Join-Operationen zu vermeiden. Mit der Verwendung von Listen als Partitionskriterium ist jetzt die Möglichkeit geschaffen worden, Tabellen nach Gebieten einzuteilen. Ansonsten verhält sich eine List Partition wie eine Range Partition, d.h., es sind die gleichen Befehle möglich. CREATE TABLE verkaeufe ( rechnungsnr NUMBER, gebiet CHAR(3), datum DATE, prodnr NUMBER, menge NUMBER, preis NUMBER ) PARTITION BY LIST (gebiet) ( PARTITION l1 VALUES ('NRW') TABLESPACE ts1, PARTITION l2 VALUES ('NIE','SH','HH','HB') TABLESPACE ts2, PARTITION l3 VALUES ('BER','BRA') TABLESPACE ts3, PARTITION l4 VALUES ('MVP','SAC','SAA','TH') TABLESPACE ts4, PARTITION l5 VALUES ('HES','BWB') TABLESPACE ts1, PARTITION l6 VALUES ('BAY') TABLESPACE ts2, PARTITION l7 VALUES ('RHP') TABLESPACE ts3 ); Listing 11.23: List Partition
Sandini Bib
Datenbankdesign für Data Warehouses
697
Ausnahmen: Es gibt keinen Dummy-Wert für den Rest (wie MAXVALUE bei Range Partition), und es können keine zusammengesetzten Spalten verwendet werden. Außerdem kann diese Art der Partitionierung nicht mit der Hash Partitionierung kombiniert werden. Es muss also bei List Partitionen darauf geachtet werden, dass jeder Wert, der vorkommen kann, auch einer Partition zugewiesen wurde. Ansonsten erscheint die Fehlermeldung: ORA-14400: Eingefügter Partitionsschlüssel kann keiner Partition zugeordnet werden
Allerdings kann ein zusätzlicher Wert in eine Partition eingefügt werden. Im obigen Beispiel fehlt ein Eintrag für das Saarland, dieser kann über den folgenden Befehl eingefügt werden. SQL> ALTER TABLE verkaeufe MODIFY PARTITION l7 ADD VALUES ('SAL'); Listing 11.24: Modify Partition
Im Gegensatz zur Range Partition ergibt sich bei der Verwendung von List-Partitionen in der Regel kein Administrationsvorteil. Im Beispiel macht es wenig Sinn, bestimmte Partitionen Read-Only zu setzen oder sogar einen TRUNCATE- oder DROPBefehl abzusetzen. Auch das Partition Pruning ist seltener anzutreffen als bei der Range Partitionierung, wo oftmals auf das aktuelle Datum bzw. auf den aktuellen Zeitraum zugegriffen wird. Es kann aber durchaus andere Beispiele geben, bei denen die Administration oder die Partition Eleminiation im Vordergrund stehen. Für dieses Beispiel gilt das jedoch nur eingeschränkt.
11.2.4 Indizierung Natürlich spielen auch die normalen Indizes eine Rolle in einem Data Warehouse. Allerdings sind Indizes, die ausschließlich der Eindeutigkeit von Datensätzen dienen (Primary Key- oder Unique Key-Indizes) eher lästig. Sie verbrauchen viel Platz und verlangsamen den Ladevorgang. Durch die Einschränkung DISABLE VALIDATE beim Anlegen eines Constraints wird kein Index erzeugt, die Eindeutigkeit wird aber dennoch sichergestellt. Nun ist es natürlich noch problematischer, in einer großen Tabelle die Eindeutigkeit von Datensätzen ohne Index sicherzustellen. Oftmals sind die Daten aber schon vorher bereinigt und es ist damit sichergestellt, dass keine doppelten Schlüssel vorkommen. Damit kann dann vor dem Laden der Daten der Constraint gelöscht und hinterher wieder neu angelegt werden. Dieses Vorgehen ist wesentlich effektiver als der Aufbau eines Indexes. Oft wird dieses Verfahren beim Partitionsbefehl EXCHANGE PARTITION eingesetzt, um zu vermeiden, dass Indizes gepflegt werden müssen, aber um sicherzustellen, dass keine ungültigen Werte in die Partition eingetragen werden.
Sandini Bib
698
Data Warehousing
Im Zusammenspiel mit den Primary Key Constraints sind natürlich dann die Foreign Keys interessant. Für sie gilt, dass der Ladeprozess verlangsamt wird, wenn jetzt auf dem Primary Key kein Index mehr existiert. Aus diesem Grund wird der Foreign Key mit DISABLE NOVALIDATE angelegt, wenn durch die Datenbereinigung sichergestellt werden kann, dass der zugehörige Primary Key existiert. Bitmapped Indizes Die entscheidende Rolle für die Indizierung von Tabellen in Data WarehouseDatenbanken spielen die Bitmapped Indizes (siehe auch Kapitel 3.3.3). Mit ihrer Hilfe können große Datenmenge effizient indiziert werden, ohne das zu viel Platz verbraucht wird. Da außerdem die Tabellen in denormalisierter Form vorliegen, bräuchte man zu viele normale Indizes, um alle auftretenden Abfragen abzufangen. Folgendes recht einfache Beispiel soll dies verdeutlichen. CREATE TABLE kdnr anrede vorname nachname adresse plz ort bundesland gebiet vertrieb
KUNDEN ( NUMBER VARCHAR2 VARCHAR2 VARCHAR2 VARCHAR2 NUMBER VARCHAR2 VARCHAR2 VARCHAR2 NUMBER
(10), (5), (50), (50), (50), (6), (50), (50), (5), (10))
Listing 11.25: Kundentabelle Data Warehouse
Die Indizierung dieser Tabelle muss jetzt folgende Abfragen unterstützen:
: : :
Ermitteln einzelner Personen (über Nachname, ev. Vorname, ev. Ort, ev. PLZ) Ermitteln eines Gebietes (über Gebiet oder Ort oder PLZ) Ermitteln von Statistiken (Anrede, PLZ, Ort, Bundesland, Gebiet)
Diese Aufgabe kann über normale Indizierung kaum erfüllt werden. Durch die logische Verknüpfung von Bitmapped Indizes können jetzt alle Spalten (bis auf die Kundennummer kdnr) einzeln indiziert werden und diese werden dann bei Bedarf miteinander verknüpft. CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE
BITMAP BITMAP BITMAP BITMAP BITMAP BITMAP BITMAP BITMAP
INDEX INDEX INDEX INDEX INDEX INDEX INDEX INDEX
b_anrede b_vorname b_nachname b_adresse b_ort b_plz b_bland b_gebiet
ON ON ON ON ON ON ON ON
kunden kunden kunden kunden kunden kunden kunden kunden
(anrede); (UPPER(vorname)); (UPPER(nachname)); (UPPER(adresse)); (UPPER(ort)); (plz); (bundesland); (gebiet);
Sandini Bib
Datenbankdesign für Data Warehouses
699
SQL> ANALYZE TABLE dwh_kunden COMPUTE STATISTICS FOR TABLE FOR ALL INDEXES FOR ALL indexed COLUMNS; SQL> SELECT FROM WHERE AND AND AND
* kunden UPPER(vorname) like 'M%' UPPER(nachname) like 'AHR%' UPPER(ort) = 'HANNOVER' anrede = 'Frau';
Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=5 Card=1 Bytes=57) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'KUNDEN' (Cost=5 Card=1 Bytes=57) 2 1 BITMAP CONVERSION (TO ROWIDS) 3 2 BITMAP AND 4 3 BITMAP INDEX (SINGLE VALUE) OF 'B_ORT' 5 3 BITMAP INDEX (SINGLE VALUE) OF 'B_ANREDE' 6 3 BITMAP MERGE 7 6 BITMAP INDEX (RANGE SCAN) OF 'B_NACHNAME' Listing 11.26: Zugriff über mehrere Bitmapped Indizes
In diesem Beispiel wird deutlich, dass der Einsatz der Bitmapped Indizes sehr effektiv genutzt werden kann. Speziell die Verbindung mit Funktionen (z.B. UPPER(nachname)) führt bei der Abfrage zu einer schnellen und kostengünstigen Ermittlung des Ergebnisses. Bitmapped Join-Index Die nächste Stufe von Bitmapped Indizes ist die Verwendung von Bitmapped JoinIndizes (siehe Kapitel 3.3.4). Hierbei wird der Bitmapped Index nicht auf eine Spalte der zu referenzierenden Tabelle aufgesetzt. Im obigen Beispiel gibt es die beiden Spalten vertrieb und gebiet, die auf entsprechende Vertriebsmitarbeiter bzw. Verkaufsgebiete referenzieren. Daher ist es erforderlich, eine Beziehung zwischen diesen Tabellen herzustellen, um beispielsweise festzustellen, welcher Vertriebsmitarbeiter für einen bestimmten Ort bzw. Kunden zuständig ist. SQL> CREATE TABLE mitarbeiter( m_nr NUMBER (10) NOT NULL, m_anrede VARCHAR2 (5), m_vorname VARCHAR2 (50), m_nachname VARCHAR2 (50), m_adresse VARCHAR2 (50), m_ort VARCHAR2 (50), m_plz NUMBER (6), m_telefon VARCHAR2 (20));
Sandini Bib
700
Data Warehousing
SQL> ALTER TABLE mitarbeiter ADD CONSTRAINT pk_mitarbeiter PRIMARY KEY (m_nr); SQL> CREATE ON FROM WHERE
BITMAP INDEX b_join_vertrieb kunden(m.m_nachname) kunden k, mitarbeiter m k.vertrieb = m.m_nr;
SQL> SELECT FROM WHERE AND
k.ort kunden k, mitarbeiter m k.vertrieb = m.m_nr m.m_nachname = 'Ahrends';
Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=40) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'KUNDEN' (Cost=2 Card=1 Bytes=40) 2 1 BITMAP CONVERSION (TO ROWIDS) 3 2 BITMAP MINUS 4 3 BITMAP INDEX (SINGLE VALUE) OF 'B_JOIN_VERTRIEB' 5 3 BITMAP INDEX (SINGLE VALUE) OF 'B_VERTRIEB' Listing 11.27: Bitmapped Join-Index
An diesem Beispiel wird deutlich, dass jetzt nicht mehr auf die Tabelle mitarbeiter zugegriffen wird, sondern alle Informationen aus den Indizes der Tabelle kunden ermittelt werden.
11.2.5 Konsolidierung und Verdichtung Eine wichtige Aufgabe in einem Data Warehouse ist es, die von den meisten Anwendern gestellten Fragen schon als Ergebnismengen zur Verfügung zu stellen. Diese Verdichtungsebenen kosten einerseits Platz, viel problematischer aber ist es, dass sichergestellt werden muss, dass eine Abfrage auf eine Ergebnismenge die gleiche Information bringt, wie die gleiche Abfrage auf die Basistabellen. Sollten Sie also ein Data Warehouse konzipieren oder betreuen, dann stellt sich als Erstes die Frage: Wie aktuell ist die Information in dem Data Warehouse? Wenn die Antwort lautet: „Identisch mit dem operativen System“, dann können Sie die meisten Funktionen eines solchen Systems vergessen. Ein solches System ist derart komplex zu verwalten, dass man lieber auf das operative System zugreifen sollte, statt ein Data Warehouse aufzusetzen. In den meisten Fällen wird die Antwort aber lauten: Tagesaktuell!
Sandini Bib
Datenbankdesign für Data Warehouses
701
Damit ist gewährleistet, dass die Daten der operativen Systeme einmal pro Tag (normalerweise Nachts) in das Data Warehouse geladen werden und dann bis zur nächsten Nacht nur noch lesend darauf zugegriffen werden darf. Natürlich gibt es auch noch andere Szenarien, die hier aber nicht weiter betrachtet werden sollen. Um jetzt Unterschiede zwischen Basistabellen und Verdichtungsebenen zu vermeiden, wird ein Prozess aufgesetzt, der zunächst die Basistabellen lädt, und in einem weiteren Schritt alle Verdichtungsebenen anlegt. Es gibt zwar die Alternative, die Verdichtungsebenen gleichzeitig mit den Basistabellen zu pflegen (z.B. über Trigger), dadurch wird der Ladevorgang aber erheblich beeinträchtigt. Materialized Views Oracle bietet seit der Version 8i in der Enterprise Edition die Funktion der Materialized Views. Zunächst einmal übernehmen sie anstelle der Snapshots die Aufgabe der Replikation von Daten zwischen unterschiedlichen Datenbanken (siehe Kapitel 8.2). Diese Replikation von Daten kann aber auch dafür genutzt werden, um Verdichtungen in der lokalen Datenbank zu erstellen. Der Name Materialized Views basiert darauf, dass oft benötigte Abfragen, die früher in Form von Views in der Datenbank abgespeichert wurden, in einem Data Warehouse derart komplex werden können, dass es Sinn macht, die Ergebnismenge einer solchen View abzuspeichern. In der einfachsten Form ist eine Materialized View also nichts anderes als: SQL> CREATE TABLE verdichtung AS SELECT TRUNC(a.auf_datum) datum, b.pos_prodnr prodnr, SUM(b.pos_menge) gesamtmenge, SUM(b.pos_menge * b.pos_einzelpreis) gesamtpreis FROM auftraege a, positionen b WHERE a.auf_nr = b.pos_aufnr GROUP BY TRUNC(a.auf_datum), b.pos_prodnr; Listing 11.28: Einfache Verdichtung
Die jetzt entstandene Tabelle verdichtung hat allerdings den Nachteil, dass sie altert, d.h., wenn sich die Tabellen auftraege oder positionen ändern, wird die Tabelle verdichtung nicht gepflegt, und es kommt zu dem oben genannten Problem, dass der SELECT-Befehl auf auftraege und positionen ein anderes Ergebnis liefert als der SELECT-Befehl auf verdichtung. An dieser Problematik sind in der Vergangenheit einige Data Warehouse-Projekte gescheitert, da die Akzeptanz der Anwender durch solche Fehler verloren geht. Die gleiche Funktion erfüllt zunächst einmal folgender Befehl: SQL> CREATE MATERIALIZED VIEW verdichtung_mv BUILD IMMEDIATE REFRESH COMPLETE ON DEMAND ENABLE QUERY REWRITE AS SELECT TRUNC(a.auf_datum) datum, b.pos_prodnr prodnr,
Sandini Bib
702
Data Warehousing
SUM(b.pos_menge) gesamtmenge, SUM(b.pos_menge * b.pos_einzelpreis) gesamtpreis FROM auftraege a, positionen b WHERE a.auf_nr = b.pos_aufnr GROUP BY TRUNC(a.auf_datum), b.pos_prodnr; Listing 11.29: Einfache Materialized View
Zwei wichtige Unterschiede gibt es zu dem Beispiel einer einfachen Verdichtung. Zunächst einmal die Klausel ENABLE QUERY REWRITE, die im folgenden Unterkapitel näher beschrieben wird, und zum anderen die Klausel REFRESH COMPLETE ON DEMAND, die in diesem Fall besagt, dass die Materialized View nur komplett (COMPLETE) und nur nach einem entsprechenden Befehl (ON DEMAND) geändert wird. Was bedeutet das im Einzelnen? Wie für eine Materialized View im Replikationsumfeld ist es möglich, Materialized View Logs anzulegen, die dann jede Änderung der Basistabellen (in diesem Fall auftraege und positionen) protokollieren. Damit kann dann ein sog. Fast-Refresh durchgeführt werden, d.h., statt die gesamte Verdichtungstabelle neu aufzubauen, werden die geänderten Datensätze eingepflegt. Der Aufbau der Materialized View Logs erfolgt mit dem Befehl: SQL> CREATE MATERIALIZED VIEW LOG ON auftraege WITH PRIMARY KEY; SQL> CREATE MATERIALIZED VIEW LOG ON positionen WITH PRIMARY KEY; Listing 11.30: Materialized View Logs
Damit werden jetzt alle Änderungen an den Tabellen auftraege und positionen in Tabellen mit dem Namen mlog$_auftraege bzw. mlog$_positionen gespeichert. Im ersten Moment scheint diese Lösung einleuchtend, und man wird zunächst davon ausgehen, dass dieser Aufbau für alle Aggregationen sinnvoll ist. Wenn man sich jedoch das Verfahren näher betrachtet, werden die Einschränkungen schnell deutlich. Zunächst einmal führt natürlich die Pflege der Materialized View Logs zu einer stärkeren Belastung des Systems beim Einfügen, Ändern und Löschen von Sätzen auf den Basistabellen. Da die Zeitfenster für die Ladeoperationen oftmals sehr knapp bemessen werden, kann dies dazu führen, dass diese Operationen nicht mehr in der vorgegebenen Zeit zu bewältigen sind. Außerdem muss geprüft werden, ob die Änderung von Datensätzen auf den Basistabellen überhaupt 1:1 auf die Materialized View reproduziert werden kann. Das bedeutet, dass bevor über die Verwendung von Materialized View Logs nachgedacht wird, zunächst einmal geprüft werden sollte, welche Verdichtungsstufen als Fast-Refresh in Frage kommen. Oracle bietet ein Package dbms_mview an, in dem eine Prozedur (explain_mview) überprüft, ob eine vordefinierte Abfrage über einen Fast-Refresh geändert werden
Sandini Bib
Datenbankdesign für Data Warehouses
kann.
Diese
Prozedur
schreibt
703
alle
Informationen
in
eine
Tabelle
mv_capabilites_table, die dann über einen SELECT-Befehl oder besser, wie unten
angegeben, über anonymes PL/SQL ausgelesen werden kann. Für das Anlegen der Tabelle gibt es ein Script im Verzeichnis ORACLE_HOME/rdbms/admin mit dem Namen utlxmv.sql. exec dbms_mview.explain_mview ('SELECT count(*), TRUNC(a.auf_datum), b.pos_prodnr, count(b.pos_menge), SUM(b.pos_menge), count(b.pos_menge * b.pos_einzelpreis), SUM(b.pos_menge * b.pos_einzelpreis) FROM auftraege a, positionen b WHERE a.auf_nr = b.pos_aufnr GROUP BY TRUNC(a.auf_datum), b.pos_prodnr'); set serveroutput on BEGIN FOR crec IN ( SELECT capability_name, possible, related_text, msgtxt FROM mv_capabilities_table ORDER BY 1) LOOP dbms_output.put_line(crec.capability_name ||':'||crec.possible); dbms_output.put_line(crec.related_text||': '||crec.msgtxt); END LOOP; END; / PCT: N : PCT: N : PCT_TABLE: N AUFTRAEGE: relation is not a partitioned table PCT_TABLE: N AUFTRAEGE: Relation ist keine partitionierte Tabelle PCT_TABLE: N POSITIONEN: relation is not a partitioned table PCT_TABLE: N AUFTRAEGE: no partition key or PMARKER in select list PCT_TABLE: N AUFTRAEGE: Kein Partitionsschlüssel oder PMARKER in SELECT-Liste PCT_TABLE: N POSITIONEN: Relation ist keine partitionierte Tabelle REFRESH_COMPLETE: Y :
Sandini Bib
704
Data Warehousing
REFRESH_COMPLETE: Y : REFRESH_FAST: Y : REFRESH_FAST: Y : REFRESH_FAST_AFTER_ANY_DML: Y : REFRESH_FAST_AFTER_ANY_DML: Y : REFRESH_FAST_AFTER_INSERT: Y : REFRESH_FAST_AFTER_INSERT: Y : REFRESH_FAST_AFTER_ONETAB_DML: Y : REFRESH_FAST_AFTER_ONETAB_DML: Y Listing 11.31: Überprüfung einer Materialized View
Dieses Ergebnis zeigt, dass der in der Prozedur dbms_mview.explain_mview angegebene SQL-Befehl für alle DML-Operationen über einen Fast-Refresh aktualisiert werden kann. Der Unterschied des SQL-Befehls gegenüber der oben erstellten Materialized View sind ausschließlich die Zähler (COUNT) auf die einzelnen Spalten. Nur mit Hilfe dieser Zähler können Verdichtungen, die auf Summationen (SUM), Durchschnittsbildung (AVG, STDDEV, VARIANCE) oder Minimal und Maximalwerte (MIN, MAX) basieren, über einen Fast-Refresh aktualisiert werden. Damit steht der endgültigen Erstellung der Materialized View verdichtung_mv nichts mehr im Wege. CREATE MATERIALIZED VIEW verdichtung_mv BUILD IMMEDIATE REFRESH FAST ON DEMAND ENABLE QUERY REWRITE AS SELECT count(*) anzahl, TRUNC(a.auf_datum) datum, b.pos_prodnr prodnr, SUM(b.pos_menge) gesamtmenge, count(b.pos_menge) mengenanzahl, SUM(b.pos_menge * b.pos_einzelpreis) gesamtpreis, count(b.pos_menge * b.pos_einzelpreis) anzahlpreis FROM auftraege a, positionen b WHERE a.auf_nr = b.pos_aufnr GROUP BY TRUNC(a.auf_datum), b.pos_prodnr; Listing 11.32: Materialized View mit Fast-Refresh
Sandini Bib
Datenbankdesign für Data Warehouses
705
Die Klausel ON DEMAND kann ersetzt werden durch ON COMMIT, die besagt, dass nach jeder Änderung der Quelltabellen die Zieltabelle nachgeführt wird. In einem Data Warehouse wird diese Option aber nur selten eingesetzt, da die Ladeoperationen in mehreren Stufen ablaufen. Es werden zunächst die Basistabellen erstellt, und dann werden die entsprechenden Verdichtungen durchgeführt. Die Aktualisierung der Verdichtungen im gleichen Kontext wie das Laden der Daten würde unweigerlich zu einer Verschlechterung des Gesamtdurchsatzes führen. Die Klausel ON DEMAND führt also dazu, dass es einen dedizierten Befehl gibt, der die Materialized View abgleicht. Dies geschieht nicht etwa durch einen ALTER MATERIALIZED VIEW ... REFRESH-Befehl (den es auch gibt, der aber nur das Standardverhalten für eine Aktualisierung ändert), sondern durch das Package dbms_mview:
: : :
dbms_mview.refresh aktualisiert ein oder mehrere Materialized Views. dbms_mview.refresh_all_mviews aktualisiert alle zum Schema gehörenden Ma-
terialized Views. dbms_mview.refresh_dependent aktualisiert alle Materialized Views, die zu einer spezifischen Tabelle bzw. einer Liste von Tabellen gehören.
Bezogen auf die Ladeoperationen in einem Data Warehouse ist es daher sinnvoll, in einem Schritt alle Materialized View abzugleichen. SET SERVEROUTPUT ON SIZE 100000 DECLARE failures NUMBER; BEGIN dbms_mview.refresh_all_mviews(failures,'?','',FALSE,FALSE); dbms_output.put_line('failures = '||failures); END; / Listing 11.33: Materialized View Refresh
Der Parameter failures ist der Ausgabewert, wie viele Fehler beim Abgleich aufgetreten sind. Das ? gibt an, dass ein Refresh-Force durchgeführt werden soll. Alternativ sind hier ein Fast-Refresh F oder ein Complete-Refresh C möglich. Es kann mit dem dritten Parameter ein spezifisches Rollback-Segment angegeben werden. Da wir aber unter Oracle9i mit automatischem Undo-Management arbeiten, entfällt diese Option. Soll beim Auftreten eines Fehlers der Abgleich abgebrochen werden, so kann der vierte Parameter auf TRUE gesetzt werden. Der letzte Parameter sorgt dafür, dass alle Abgleiche in eigenen Transaktionen durchgeführt werden. Ein TRUE an dieser Stelle bewirkt, dass alle Abgleiche als eine Transaktion ausgeführt werden. Natürlich können auf die Materialized View auch entsprechende Indizes angelegt werden. So ist es sicher sinnvoll, einen Index auf das Datum zu legen, zum Beispiel in der Form: CREATE INDEX idx_verdichtungsdatum ON verdichtung_mv (datum); Listing 11.34: Index auf Materialized View
Sandini Bib
706
Data Warehousing
Interessanterweise muss für dieses Beispiel jetzt kein Function-based Index angegeben werden, wie es auf der Basistabelle notwendig wäre. Dort würde der entsprechende Index so aussehen: CREATE INDEX idx_auftraegedatum ON auftraege (trunc(auf_datum)); Listing 11.35: Index auf die Basistabelle
Query Rewrite Mit der Version 8i hat Oracle die wohl interessanteste Data Warehouse-Funktion, Query Rewrite, eingeführt. Mit dieser Funktion hat der Oracle Optimizer die Möglichkeit, statt auf die Basistabellen zuzugreifen, die Abfrage auf eine Materialized View umzuleiten. Als Voraussetzung für den Einsatz dieser Funktion gibt es zwei Initialisierungsparameter: query_rewrite_enabled = true query_rewrite_integrity = trusted
Diese Parameter können allerdings auch dynamisch mit dem Befehl ALTER SYSTEM SET ... bzw. für eine Session über den Befehl ALTER SESSION SET ... gesetzt werden. Für die oben angegebene Materialized View könnte eine Abfrage jetzt wie folgt aussehen: SELECT TRUNC(a.auf_datum) datum, b.pos_prodnr prodnr, SUM(b.pos_menge * b.pos_einzelpreis) gesamtpreis FROM auftraege a, positionen b WHERE a.auf_nr = b.pos_aufnr AND trunc(a.auf_datum) > to_date('01.05.2002','DD.MM.YYYY') GROUP BY TRUNC(a.auf_datum), b.pos_prodnr; Ausführungsplan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=10 Card=7299 Bytes=255465) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'VERDICHTUNG_MV' (Cost=10 Card=7299 Bytes=255465) 2 1 INDEX (RANGE SCAN) OF 'IDX_VERDICHTUNGSDATUM' (NON-UNIQUE) (Cost=2 Card=7299) Listing 11.36: Abfrage mit Query-Rewrite
Selbst auf einer relativ geringen Datenmenge (ca. 300.000 Aufträge und 1.000.000 Positionen) ergab sich ein Performance-Unterschied von Faktor 10 zwischen dem Zugriff auf die Tabellen oder dem Zugriff auf die Materialized View.
Sandini Bib
Datenbankdesign für Data Warehouses
707
Summary Advisor Mit dem Summary Advisor unterstützt Oracle die Entwicklung bzw. Optimierung von Data Warehouse-Anwendungen. Wie der Name schon sagt, werden mit diesem Werkzeug Vorschläge gemacht, welche Summationen, d.h. Verdichtungstabellen, in Form von Materialized Views sinnvoll wären. Voraussetzungen für den Einsatz des Werkzeugs sind die Installation der Java Virtual Machine (Oracle JVM) und die Konfiguration von Oracle Net für externe Prozeduren. Die Oracle JVM wird entweder über den DATABASE CONFIGURATION ASSISTENT oder über das SQL-Script initjvm.sql im Verzeichnis ORACLE_HOME/javavm/install installiert. Die Konfiguration von Oracle Net für den Aufruf von externen Prozeduren kann wie folgt aussehen:
:
listener.ora
LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap33)(PORT = 1521)) (ADDRESS = (PROTOCOL = IPC)(KEY = extproc)) ) ) ) SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = JA901) (ORACLE_HOME = D:\oracle\product\9.0.1) (SID_NAME = JA901) ) (SID_DESC = (ORACLE_HOME = D:\oracle\product\9.0.1) (SID_NAME = plsextproc) (PROGRAM=extproc) ) ) Listing 11.37: Konfiguration listener.ora für externe Prozeduren
:
tnsnames.ora
JA901 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = hllap33)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = JA92)))
Sandini Bib
708
Data Warehousing
extproc_connection_data, extproc_connection_data.world = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = IPC)(KEY = extproc))) (CONNECT_DATA = (SID = plsextproc))) Listing 11.38: Konfiguration tnsnames.ora für externe Prozeduren
Wenn alle diese Voraussetzungen erfüllt sind, steht dem Einsatz des Summary Advisors nichts mehr im Wege. Die Basis für die Analyse bildet dabei in den meisten Fällen die momentan aktive Instanz; d.h., der Summary Advisor erhält die Informationen aus dem aktuellen Workload. Alternativ ist es möglich, Oracle Trace oder vordefinierte Statements als Basis zu nutzen. Die zu verwendenden Funktionen sind in dem Package dbms_olap zusammengefasst, dies ist allerdings nur ein Synonym für das Package dbms_summary. Die gesamte Funktionalität kann über den Oracle Enterprise Manager gestartet werden (dann ist die Konfiguration von Oracle Net für externe Prozeduren nicht notwendig) oder als Script aus SQL*Plus heraus. Das Ergebnis der Analyse kann dann in HTML-Form oder direkt als SQL-Script ausgegeben werden. Gerade die Ausgabe als SQL-Script bietet gegenüber dem Enterprise Manager den Vorteil, dass die Implementierung zu einem beliebigen Zeitpunkt ohne das Job-System erfolgen kann. Das folgende Beispiel zeigt die Verwendung des Summary Advisors als SQL-Script. Zunächst wird der Cache der SGA mit der Prozedur load_workload_cache ausgelesen. Die hierfür notwendige Identifizierungsnummer w_id wird über die Prozedur create_id generiert. Dann wird über die gelesenen SQL-Befehle die eigentliche Analyse mit der Prozedur recommend_mview_strategy durchgeführt. Hier wird eine ebenfalls über die Prozedur create_id ermittelte run_id als Identifizierung mitgeliefert. Außerdem wird der aktuelle Workload über die w_id als Parameter übergeben. Weitere Einschränkungen, wie zum Beispiel die maximale Größe einer Materialized View oder bestimmte Tabellen, können über Parameter angegeben werden. In diesem Fall wurden keine weiteren Einschränkungen vorgenommen. DECLARE run_id NUMBER; w_id NUMBER; BEGIN dbms_olap.create_id (w_id ); dbms_olap.load_workload_cache (w_id, dbms_olap.workload_new, dbms_olap.filter_none, NULL,NULL); dbms_olap.create_id (run_id); dbms_olap.recommend_mview_strategy(run_id, w_id, NULL, 100000000, 10,NULL,NULL);
Sandini Bib
Datenbankdesign für Data Warehouses
709
dbms_olap.generate_mview_report('E:\temp\advisor.html', run_id,dbms_olap.rpt_all); dbms_olap.generate_mview_script('E:\temp\advisor.sql', run_id,'DWH_DEMO'); END; / Listing 11.39: Benutzung von Summary Advisor
Die Ausgabe des Reports erfolgt in der Datei advisor.html bzw. als SQL-Script in der Datei advisor.sql. Das Ergebnis als SQL-Script sieht dann so aus: /******************************************************************** Rangfolge 1 ** Speicherung 3.000 Byte ** Gewinn 99,99% ** Leistungsverhältnis 250.225.995,00 ** ** SELECT dwh_demo.kunden.bundesland, dwh_demo.kunden.gebiet, sum( ** dwh_demo.verkaeufe.preis), ** count(dwh_demo.verkaeufe.preis), ** count(*) ** FROM dwh_demo.verkaeufe, dwh_demo.kunden ** WHERE dwh_demo.verkaeufe.kdnr = dwh_demo.kunden.kdnr ** GROUP BY dwh_demo.kunden.bundesland, dwh_demo.kunden.gebiet ******************************************************************/ CREATE MATERIALIZED VIEW mv_id_50_rangfolge_1 TABLESPACE dwh_demo BUILD IMMEDIATE REFRESH COMPLETE ENABLE QUERY REWRITE AS SELECT DWH_DEMO.KUNDEN.BUNDESLAND, DWH_DEMO.KUNDEN.GEBIET, SUM("DWH_DEMO"."VERKAEUFE"."PREIS"), COUNT("DWH_DEMO"."VERKAEUFE"."PREIS"), COUNT(*) FROM DWH_DEMO.VERKAEUFE, DWH_DEMO.KUNDEN WHERE DWH_DEMO.VERKAEUFE.KDNR = DWH_DEMO.KUNDEN.KDNR GROUP BY DWH_DEMO.KUNDEN.BUNDESLAND, DWH_DEMO.KUNDEN.GEBIET; Listing 11.40: Ausgabe Summary Advisor
In dem Kommentar-Block des SQL-Scripts findet man dann die Informationen über den Gewinn des Einsatzes einer solchen Materialized View und die ungefähre Größe der Tabelle.
Sandini Bib
710
Data Warehousing
11.2.6 Aggregationsfunktionen Aggregationsfunktionen sind in einem Data Warehouse ein entscheidendes Element für Auswertungen. Wichtig sind dabei neben den Standardfunktionen, wie SUM, AVG, MIN, MAX und COUNT, mehrdimensionale und gruppierte Abfragen. Die relativ simple Frage nach den Top Ten der verkauften Produkte stellt mit dem Standardumfang von SQL eine fast unlösbare Aufgabe dar. Ähnlich verhält es sich, wenn neben einer Gesamtsumme auch Teilsummen ausgegeben werden sollen. SQL*Plus hält hierfür die eingebaute Funktionen wie z.B. COMPUTE bereit, aber welcher Anwender will schon mit SQL*Plus arbeiten. Für diese und weitere Bespiele gibt es in der aktuellen Oracle-Datenbank eine Reihe von Funktionen, die neben der einfacheren Syntax des entsprechenden SQLBefehls eine eigene Logik für die Ermittlung der Daten enthalten. CUBE und ROLLUP Die einfachsten Funktionen sind CUBE und ROLLUP für die Zwischensummenbildung bei GROUP BY-Abfragen. Wenn zum Beispiel ein Bezug zwischen den Verkäufen für ein Gebiet und ein Bundesland hergestellt werden soll: SELECT k.gebiet, k.bundesland, SUM(v.preis) Umsatz FROM kunden k, verkaeufe v WHERE k.kdnr = v.kdnr GROUP BY ROLLUP(k.gebiet, k.bundesland); Listing 11.41: ROLLUP-Funktion
Mit dieser Abfrage wird der Gesamtumsatz, der Umsatz je Gebiet und der Umsatz je Bundesland ausgegeben. SELECT z.jahr, z.quartal, z.monat, SUM(v.preis) Umsatz FROM zeiten z, verkaeufe v WHERE z.zeitnr = v.zeitnr GROUP BY CUBE(z.jahr, z.quartal, z.monat); Listing 11.42: CUBE-Funktion
In diesem Beispiel wird der Umsatz nach Jahren und Quartalen ausgegeben. Die CUBE-Funktion ermöglicht hier den direkten Vergleich der Umsätze in den einzelnen Quartalen oder Monaten, z.B. für die Frage: „In welchem Quartal machen wir den größten Umsatz?“.
Sandini Bib
Datenbankdesign für Data Warehouses
711
GROUPING Die Funktion GROUPING ist eine Erweiterung der Gruppierfunktionen ROLLUP und CUBE. Bei umfangreichen Ergebnismengen sind die Zwischenergebnisse oftmals schwer zuzuordnen, d.h., es ist nicht klar ersichtlich, um welche Ebene der Gruppierung es sich handelt. Hierfür können mit der Klausel GROUPING in der Selektionsliste JA-/NEIN-Felder eingefügt werden. Beim obigen Beispiel würde es sich empfehlen, die folgende Erweiterung vorzunehmen: SELECT z.jahr, z.quartal, z.monat, SUM(v.preis) Umsatz, GROUPING (z.jahr) J, GROUPING (z.quartal) Q, GROUPING (z.monat) M FROM zeiten z, verkaeufe v WHERE z.zeitnr = v.zeitnr GROUP BY CUBE(z.jahr, z.quartal,z.monat) ORDER BY z.jahr, z.quartal, z.monat; JAHR QUARTAL MONAT UMSATZ J Q M ---------- ---------- ---------- ----------- ----- ------ -----... 2002 20.937.673 0 1 1 1 1 15.170.745 1 0 0 1 2 13.718.001 1 0 0 1 3 14.621.739 1 0 0 1 43.510.486 1 0 1 2 4 14.759.490 1 0 0 2 5 15.247.713 1 0 0 ... 4 12 14.964.159 1 0 0 4 45.100.763 1 0 1 1 15.170.745 1 1 0 2 13.718.001 1 1 0 ... 12 14.964.159 1 1 0 177.679.738 1 1 1 Listing 11.43: GROUPING und CUBE
Die Felder J, Q, M geben an, auf welcher Ebene die Aggregation durchgeführt wurde (J = 1 Jahresebene; Q = 1 Quartalsebene; M = 1 Monatsebene). Die letzte Zeile gibt den Gesamtumsatz über alle Jahre aus.
Sandini Bib
712
Data Warehousing
GROUPING SETS Jede umfangreiche SQL-Aggregation führt zwangsläufig dazu, dass aufwändige Gruppierungen gemacht werden müssen, da SQL es standardmäßig nicht zulässt, dass einzelne Werte nicht als Gruppierungsschlüssel verwendet werden. GROUPING SETS erlauben es, Vorgaben für die Gruppierungsschlüssel vorzunehmen. In einem Data Warehouse, in dem es eine Reihe von Dimensionstabellen gibt, auf deren Basis gruppiert werden soll, kann das wie folgt aussehen.
SELECT k.gebiet, k.bundesland, z.jahr, z.quartal, SUM(v.preis) FROM kunden k, zeiten z, verkaeufe v WHERE k.kdnr = v.kdnr AND z.zeitnr = v.zeitnr GROUP BY GROUPING SETS ((k.gebiet, k.bundesland), (z.jahr, z.quartal)); GEBIE ----Ost Ost ... West
BUNDESLAND JAHR QUARTAL SUM(V.PREIS) -------------------- ---------- ---------- -----------Berlin 20.549.822 Sachsen 5.666.940 Nordrhein-Westfalen 2000 2000
1 2
54.756.743 10.921.986 10.935.408
Listing 11.44: GROUPING SETS
Dieses Beispiel zeigt die Möglichkeit, in einer Abfrage nach Gebiet und Bundesland sowie nach Jahr und Quartal zu summieren. Wichtig ist hierbei die Verwendung der äußeren Klammern, die die Untergruppierung angeben. WITH-Klausel Die WITH-Klausel erlaubt es, eine einmal durchgeführte Aggregation in der gleichen Abfrage wieder zu verwenden, ohne dass die Abfrage nochmals ausgeführt werden muss. Wenn zum Beispiel die Bundesländer ausgegeben werden sollen, in denen mehr als 25 % des Gesamtumsatzes erzielt worden sind, so kann dies über folgende SQLAnweisung geschehen: WITH laenderumsatz AS ( SELECT k.bundesland, SUM(v.preis) AS umsatz FROM kunden k, verkaeufe v
Sandini Bib
Darstellung
713
WHERE k.kdnr = v.kdnr GROUP BY k.bundesland ) SELECT bundesland, umsatz FROM laenderumsatz WHERE Umsatz > ( SELECT sum(umsatz) * 0.25 FROM laenderumsatz); Listing 11.45: WITH-Beispiel
In diesem Beispiel wird zunächst eine normale Gruppierung mit einer Summenbildung durchgeführt. Dadurch wird der Umsatz je Bundesland ermittelt. Dieses Ergebnis wird unter dem Namen laenderumsatz temporär gespeichert (erfolgt als Temporär-Segment der Sitzung). Die zweite SELECT-Anweisung kann jetzt auf dieses Temporär-Segment zugreifen und über einen Gesamtumsatz (SUM(umsatz)) das Verhältnis des Einzelumsatzes je Bundesland bestimmen. Interessant ist hierbei der Ausführungsplan, der ausschließlich die Temporär-Segmente angibt: Ausführungsplan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=10 Bytes=400) 1 2 RECURSIVE EXECUTION OF 'SYS_LE_2_0' 2 0 TEMP TABLE TRANSFORMATION 3 2 VIEW (Cost=2 Card=10 Bytes=400) 4 3 TABLE ACCESS (FULL) OF 'SYS_TEMP_0FD9D660D_44D05' (Cost=2 Card=10 Bytes=260) 5 3 SORT (AGGREGATE) 6 5 VIEW (Cost=2 Card=10 Bytes=130) 7 6 TABLE ACCESS (FULL) OF 'SYS_TEMP_0FD9D660D_44D05' (Cost=2 Card=10 Bytes=260) Listing 11.46: Ausführungsplan WITH-Beispiel
11.3 Darstellung Ein immer wieder im Zusammenhang mit Data Warehouse-Anwendungen gebrauchter Begriff ist Star-Schema oder Snowflake-Schema. Das bedeutet, dass die Daten in einem Data Warehouse nach Fakten und Dimensionen getrennt werden. Die Faktentabellen sind dadurch gekennzeichnet, dass sie ein sehr großes Datenvolumen haben (mehrere Hundertmillionen Datensätze) und über entsprechende Attribute klassifiziert werden. Die Dimensionstabellen beschreiben dann diese Attribute.
Sandini Bib
714
Data Warehousing
Als Beispiel soll eine einfache Verkaufstabelle dienen, die für Marketingzwecke zur Verfügung gestellt werden soll. Während in einem operativen System die Daten in normalisierter Form abgelegt werden (z.B. kunden, auftraege, auftragspositionen etc.), werden diese Informationen in einem Data Warehouse gemischt und mit Zusatzinformationen über den Kunden, die verkauften Produkte und die Zeiträume angereichert. In dem Data Warehouse-Modell ist die Tabelle verkaeufe die zentrale Information, die alle Informationen der auftraege- und auftragspositionen-Tabelle enthält und zusätzlich mit Informationen wie Verkaufsgebiet, Woche und Produktgruppe angereichert worden ist. Darum herum gruppieren sich die näheren Informationen zur Produktgruppe, zum Verkaufsgebiet, zu Zeitabschnitten und Einzelheiten zu den Kunden. Diese Art des Datendesigns wird Star-Schema genannt, da sich die Dimensionstabellen um eine zentrale Tabelle gruppieren. In einem Snowflake-Schema sind Fakten- und Dimensionstabellen kaskadierend miteinander verbunden. Im obigen Fall könnte zum Beispiel eine Produkthistorie gebildet werden, um zusätzlich darzustellen, wie sich der Verkaufspreis im Laufe der Jahre verändert hat.
Abbildung 11.3: Star-Schema
11.3.1 Dimensionen Neben der Benennung einer Tabelle als Dimensionstabelle (auch Lookup-Tabelle genannt) gibt es in der Oracle-Datenbank auch die Möglichkeit, Dimensionen mit dem Befehl CREATE DIMENSION zu definieren. In diesem Fall wird eine Abhängigkeit der in einer Tabelle enthaltenen Daten erzeugt. Es handelt sich hierbei aber nicht um eine Tabelle, sondern nur um eine Struktur. Ein einfaches Beispiel soll dies zeigen: Für ein Data Warehouse ist die Kundentabelle oftmals eine wichtige Dimensionsinformation, dabei spielen unterschiedliche Felder dieser Tabelle eine Rolle. Es kann z.B. die Frage gestellt werden, wie das Käuferverhältnis von Frauen zu Männern ist
Sandini Bib
Darstellung
715
oder an welchen Orten am meisten verkauft wurde. Gerade die zweite Frage birgt aber schon eine sehr große und schwer lesbare Ergebnismenge. Daher wird oftmals zunächst mit Gebieten (z.B. Nord, Ost, West, Süd, Mitte), dann mit Bundesländern und dann ev. noch mit Regionen gearbeitet. Erst danach wird auf den Ort und ev. sogar auf Ortsteile oder Straßen heruntergebrochen. Dieser Fall stellt eine typische Hierarchie dar, die in einer Dimension abgelegt und dann als Drill down für Abfragen genutzt werden kann. Folgendes Beispiel veranschaulicht die Verwendung von Dimensionen bei Materialized Views. Die Grundlage hierfür bildet die Tabelle kunden, die wie in Abbildung 11.3 Star-Schema um die Felder bundesland und gebiete erweitert wurde. Auf diese Tabelle wird die Dimension kunden_dim angelegt, so dass eine Hierarchie in Form kdnr, ort, bundesland, gebiet entsteht. Als Nächstes wird eine Materialized View angelegt, die die Verkäufe pro Ort aggregiert. Vergessen Sie nicht, das Schema oder zumindest die beteiligten Tabellen zu analysieren. CREATE DIMENSION kunden_dim LEVEL kunden IS kunden.kdnr LEVEL ort IS kunden.ort LEVEL bundesland IS kunden.bundesland LEVEL gebiet IS kunden.gebiet HIERARCHY geograf_rollup ( kunden CHILD OF ort CHILD OF bundesland CHILD OF gebiet ) ATTRIBUTE kunden DETERMINES (kunden.nachname, kunden.vorname, kunden.adresse, kunden.plz, kunden.ort) ATTRIBUTE ort
DETERMINES (kunden.ort)
ATTRIBUTE bundesland DETERMINES (kunden.bundesland) ATTRIBUTE gebiet
DETERMINES (kunden.gebiet);
Listing 11.47: Dimension kunden_dim
CREATE MATERIALIZED VIEW kunden_mview BUILD IMMEDIATE REFRESH COMPLETE ENABLE QUERY REWRITE AS SELECT k.ort, SUM(v.preis) FROM kunden k, verkaeufe v WHERE v.kdnr = k.kdnr GROUP BY k.ort; Listing 11.48: Materialized View kunden_mview
Sandini Bib
716
Data Warehousing
Über die Verwendung der Dimension ist es jetzt möglich, dass auch Abfragen, die nicht direkt verdichtet wurden, über den Query-Rewrite-Mechanismus auf die Materialized View umgelenkt werden können. Das folgende Beispiel erstellt einen Report über die Verkäufe je Gebiet und Bundesland. Da diese Abfrage keine Gruppierung nach Ort aufweist, würde sie, wenn die Dimension kunden_dim nicht existieren würde, auf die Basistabellen kunden und verkaeufe zugreifen müssen. Der Ausführungsplan zeigt aber, dass in diesem Fall auf die Materialized View kunden_mview und die Tabelle kunden für die Ermittlung der Dimensionen zugegriffen wird. SELECT k.gebiet, k.bundesland, SUM(v.preis) FROM kunden k, verkaeufe v WHERE v.kdnr = k.kdnr GROUP BY ROLLUP(k.gebiet,k.bundesland); Listing 11.49: Abfrage über Dimension
Ausführungsplan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=113 Card=36 Bytes=2376) 1 0 SORT (GROUP BY ROLLUP) (Cost=113 Card=36 Bytes=2376) 2 1 HASH JOIN (Cost=99 Card=1025 Bytes=67650) 3 2 TABLE ACCESS (FULL) OF 'KUNDEN_MVIEW' (Cost=2 Card=41 Bytes=1640) 4 2 VIEW (Cost=96 Card=425 Bytes=11050) 5 4 SORT (UNIQUE) (Cost=96 Card=425 Bytes=11050) 6 5 TABLE ACCESS (FULL) OF 'KUNDEN' (Cost=35 Card=10000 Bytes=260000) Listing 11.50: Ausführungsplan Dimension
Dieses Beispiel für die Verwendung von Dimensionen ist relativ einfach gehalten. Neben der Definition von Dimensionen über eine Tabelle (in diesem Fall kunden) sind auch Dimensionen über mehrere Tabellen möglich. Außerdem können auch alternative Hierarchien definiert werden. Da es bei der Definition von Dimensionen einige Restriktionen gibt (so müssen z.B. die Hierarchien eine 1:n-Beziehung haben), ist es empfehlenswert, komplexere Dimensionen über den Oracle Enterprise Manager anzulegen. Alternativ kann eine Dimension mit dem Package dbms_olap.validate_dimension überprüft werden, da es bei der Erstellung einer Dimension keine Fehlermeldung gibt, falls Restriktionen verletzt wurden.
Sandini Bib
Darstellung
717
11.3.2 Parallele Abfragen Ob eine Parallelisierung von Abfragen möglich ist und gewünscht wird, hängt von verschiedenen Faktoren ab. Zum einen ist die Gesamtauslastung des Systems sicherlich interessant. Es bringt keine Vorteile, auf einem System, das zu 80% ausgelastet ist, Abfragen zu parallelisieren. Außerdem sollte bei einer Parallelisierung vermieden werden, dass kritische Befehle durch die Parallelisierung untergeordneter Prozesse ausgebremst werden. Oracle kann über unterschiedliche Methoden eine Abfrage parallelisieren: 1. Über die Tabellen-Option PARALLEL, die beim Erstellen der Tabelle bzw. über die Änderung angegeben wird. SQL> ALTER TABLE kunden PARALLEL (degree 4); SQL> ALTER TABLE kunden PARALLEL; SQL> ALTER TABLE kunden NOPARALLEL;
Das erste Beispiel setzt für alle parallelisierbaren Operationen den Faktor auf 4. Das zweite Beispiel ermöglicht die Parallelisierung von Operationen; der entsprechende Faktor wird dann durch die Initialisierungsparameter und die verfügbaren Ressourcen festgelegt. Das dritte Beispiel nimmt die Möglichkeit der Parallelisierung wieder zurück. 2. Über einen Hinweis (Hint) beim Aufruf eines Befehls: SQL> SELECT /*+ PARALLEL (kunden,4) */ * FROM kunden; SQL> SELECT /*+ PARALLEL_INDEX(kunden,idx_kunden,4) */ * FROM kunden WHERE kdnr BETWEEN 1000 AND 2000; Listing 11.51: Parallele Abfrage
Das erste Beispiel setzt den Parallelisierungsfaktor für diese Abfrage auf den Wert 4. Das zweite Beispiel kann einen Indexzugriff parallelisieren, allerdings nur, wenn der Index entsprechend partitioniert ist. In diesem Fall wäre ein Hash Partitioning über die Kundennummer sinnvoll. 3. Über Initialisierungsparameter: parallel_min_servers parallel_max_servers parallel_min_percent parallel_automatic_tuning
= = = =
1 20 50 true
Speziell die Initialisierungsparameter sollten mit Bedacht gewählt werden. Wenn der Parameter parallel_max_servers zu groß gewählt wird, kann es sein, dass zu
Sandini Bib
718
Data Warehousing
wenig Ressourcen zur Verfügung stehen und damit die Parallelisierung zu einer Verschlechterung der Performance führt. Der Parameter parallel_automatic_tuning nimmt dem Administrator die Entscheidung ab, ob und mit wie viel Prozessen parallelisiert werden soll. Hier wird entsprechend den verfügbaren Ressourcen (u. a. cpu_count) eine Parallelisierung von Operationen auf den Tabellen durchgeführt, die die Option parallel gesetzt haben. Die Initialisierungsparameter wie parallel_max_servers, db_file_multiblock_ read_count und andere beeinflussen aber auch den Zugriffspfad bei Abfragen, so dass der Cost-based-Optimizer u.U. einen Full-Table-Scan vorziehen wird, statt über einen Index auf die Daten zuzugreifen.
11.3.3 Analysefunktionen Die Oracle9i-Datenbank kann um einen OLAP-Server erweitert werden. In diesem Umfeld stehen dann umfangreiche Analysefunktionen wie zum Beispiel Trendanalysen und Budgetierungen zur Verfügung. Es würde den Umfang dieses Buches sprengen, wenn wir diese – wie auch andere Erweiterungen der Datenbank – hier beschreiben würden. Daher beschränken wir uns auf die Analysefunktionen, die im Oracle Server enthalten sind und somit ohne Zusatzoptionen auch bei der Standard-Edition angewendet werden können. Zu diesen Funktionen gehören:
: : : :
Rangfolgen und Verhältnisse Berechnungen über Zeitfenster Erster/Letzer Lineare Regressionsstatistiken
Wichtig ist in diesem Zusammenhang der Begriff Partition, der in diesem Zusammenhang nichts mit der Partitionierung von Tabellen zu tun hat, sondern die Gruppierung beschreibt, auf die die analytische Funktion jeweils angewendet werden soll. Diese Partitionierung wird auf die selektierte Ergebnismenge ausgeführt. Das bedeutet, es gibt keine Performance-Verbesserungen gegenüber selbst geschriebenen Lösungen. Das folgende Schaubild zeigt die Reihenfolge der Verarbeitung einzelner Klauseln eines SQL-Befehls. An dem Beispiel einer Top-Ten-Analyse soll die Ausführung bzw. Benutzung des Befehls RANG (Reihenfolge) verdeutlicht werden. Es sollen die zehn meistverkauften Produkte aus dem Join der beiden Tabellen verkaeufe und produkte ermittelt werden.
Sandini Bib
Darstellung
719
Abbildung 11.4: Analysefunktionen
SELECT * FROM ( SELECT p.prodname, SUM(v.preis) Produktpreis, RANK() OVER (ORDER BY (SUM(v.preis)) DESC ) Reihenfolge FROM verkaeufe v, produkte p WHERE v.prodnr = p.prodnr GROUP BY p.prodname ); WHERE Reihenfolge <= 10;Ausführungsplan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE 1 0 VIEW 2 1 WINDOW (SORT PUSHED RANK) 3 2 SORT (GROUP BY) 4 3 HASH JOIN 5 4 TABLE ACCESS (FULL) OF 'PRODUKTE' 6 4 TABLE ACCESS (FULL) OF 'VERKAEUFE' Listing 11.52: Top Ten-Analyse
In diesem Fall muss ein Sub-Select gewählt werden, um aus der Gesamtmenge die Top Ten herauszufinden. An dieser Stelle zeigt sich auch die Limitierungen einer solchen Analyse. Während in einer multidimensionalen Datenbank die einzelnen Werte einen Bezug zueinander haben (je nach Definition der Dimension z.B. die Verkaufszahlen je Produkt, je Datum, je Filiale), gibt es in einer relationalen Datenbank solche Beziehungen nicht. Daher muss zunächst die Gesamtmenge ermittelt werden, und erst danach kann eine Einschränkung erfolgen. Für diese Top Ten-Analyse gibt es noch die Frage, wie viele Prozent des Gesamtumsatzes mit diesen Produkten jeweils erzielt wurde. In dem folgenden Beispiel wurde dafür die Funktion RATIO_TO_REPORT genutzt, die die entsprechenden Verkaufszahlen je Produkt in Beziehung zu einander setzt. Außerdem wird in diesem Beispiel noch die Gesamtsumme ausgegeben. Die Syntax hier SUM(SUM…) OVER() bedeutet, dass es eine Summe (die Gesamtsumme) über alle Einzelsummen gibt (OVER()).
Sandini Bib
720
Data Warehousing
SELECT * FROM ( SELECT p.prodname, SUM(v.preis) Produktpreis, SUM(SUM(v.preis)) OVER() Gesamtpreis, RANK() OVER (ORDER BY (SUM(v.preis)) DESC ) Reihenfolge, ROUND((RATIO_TO_REPORT(SUM(v.preis)) OVER())*100) anteil FROM verkaeufe v, produkte p WHERE v.prodnr = p.prodnr GROUP BY p.prodname ) WHERE Reihenfolge <= 10; Listing 11.53: Analyse mit Gesamtsummation
Das letzte Beispiel soll die Verwendung von Partitionen verdeutlichen. Es sollen die Verkäufe je Produkt und Jahr dargestellt werden. Dabei soll je Jahr die Rangefolge der Produkte (vom besten zum schlechtesten) und je Produkt der prozentuale Absatz in dem betreffenden Jahr und der Gesamtumsatz dargestellt werden. SELECT z.jahr, p.prodname, SUM(v.preis) Produktumsatz, SUM(SUM(v.preis)) OVER(PARTITION BY p.prodname) Gesamtumsatz, RANK() OVER (PARTITION BY z.jahr ORDER BY (SUM(v.preis)) DESC ) Reihenfolge, ROUND((RATIO_TO_REPORT(SUM(v.preis)) OVER(PARTITION BY p.prodname))*100) Anteil FROM verkaeufe v, produkte p, zeiten z WHERE v.prodnr = p.prodnr AND v.zeitnr = z.zeitnr GROUP BY z.jahr ,p.prodname ORDER BY reihenfolge, jahr; JAHR PRODNAME PRODUMSATZ GESUMSATZ RANG ANTEIL ----- -------------------- ------------ ------------ ---- ------1998 Infinity Kappa 1.057.611 7.699.388 1 14 1999 Infinity Kappa 1.938.453 7.699.388 1 25 2000 Infinity Kappa 1.902.963 7.699.388 1 25 2001 Infinity Kappa 1.999.038 7.699.388 1 26 2002 Infinity Kappa 801.323 7.699.388 1 10 1998 Grundig Fine Arts 798.068 6.057.984 2 13 ... Listing 11.54: Analyse mit Partitionen
Die abschließende ORDER BY-Klausel stellt zusätzlich sicher, dass die Datensätze je Produkt und nicht je Jahr dargestellt werden und somit leichter verglichen werden können. Andere Funktionen können genutzt werden, um den ersten oder letzten Satz einer Partition auszugeben oder um hypothetische Annahmen mit in die Analyse einzu-
Sandini Bib
Darstellung
721
betten. Außerdem können NULL-Werte über die Klausel NULLS FIRST oder NULLS LAST als höchster bzw. niedrigster Wert eingegliedert werden. Es sei hier aber nochmals darauf hingewiesen, dass diese Funktionen auf eine bereits ermittelte Ergebnismenge ausgeführt werden, die ihrerseits sehr komplexe Abfragen generieren kann. Dadurch kann die Performance eines Data WarehouseSystems stark beeinträchtigt werden. Wichtig ist es daher, bei der Planung eines Data Warehouses Verdichtungsstufen einzuplanen, um damit solche Abfragen zu beschleunigen.
Sandini Bib
Sandini Bib
Stichwortverzeichnis :A
Abhängige Objekte 45 add_grouped_policy 301 add_policy_context 299 ADMINISTER RESOURCE MANAGER 322 Administrator-Authentifizerung 84 Advanced Queueing 604 Aggregation 702 Aggregationsfunktion 710 Aktualisierungsgruppen 556 Alarm 624 Alert-Datei 419, 535, 625 Alias-Namen 509 ALL_CONTROL 309 all_repcatlog 585–586 all_repcolumn_group 585 all_repgrouped_column 585 all_represolution 586 all_repsites 578 ALL_ROWS 498, 509 all_sa_user_labels 314 all_sa_users 314 all_users 247 ALTER DATABASE 114, 230 Character Set / National Character Set 114 CONTROLFILE 237 NOARCHIVELOG 638 RENAME GLOBAL_NAME 114, 131 RESETLOGS 425 ALTER INDEX COALESCE 162 MONITORING USAGE 162 REBUILD 161 ALTER MATERIALIZED VIEW LOG 588 ALTER PROFILE 319 ALTER RESOURCE 318 ALTER ROLE 292 ALTER ROLLBACK SEGMENT 206 ALTER SESSION 158 ENABLE PARALLEL DML 187 ALTER SESSION SET CONSTRAINTS 197 ALTER SYSTEM 114 DISCONNECT SESSION 115 ENABLE / DISABLE RESTRICTED SESSION 115 FLUSH SHARED POOL 116 KILL SESSION 115 SUSPEND / RESUME 116 ALTER TABLE 146, 153, 185, 188, 195, 330 CACHE 517
MINIMIZE RECORDS_PER_BLOCK 153 MOVE TABLESPACE 635, 640 ALTER TABLESPACE 214, 224–225 End Backup 417 ALTER USER 247, 250, 253, 292, 317 alter_any_type-Privileg 660 ALTER_TYPE 656 Analysefunktionen 718 ANALYZE 177, 493 COMPUTE 493 DELETE 494 ESTIMATE 494 INDEX 161 VALIDATE STRUCTURE 494 Analyze Database 495 Analyze Schema 495 ANSI-Standard 471 Anti-Join 513 Anwenderfehler 427 Anwendungs-Tracing 479 Applikationskontext 295 aq_administrator_role 619 Architektur 19 Archive Destination 623 ARCHIVE LOG 411, 639 LIST 234, 411, 639 START 235 STOP 235 Archivelog-Modus 430 Archivierte Redolog-Datei 421, 426, 429 Archivierung, automatische 412, 464–465 Archivierungsmodus 409, 416 Archivierungsverzeichnis 629 ARCn-Prozess 228, 233, 412 Array Fetch 471 Asynchrone Replikation siehe Übertragungsmethode Asynchrones I/O 64 AUDIT 330 Auditing 39, 329 Audit-Trigger 334 Ausführungsplan 482, 487, 499 Authentifizierung 244 externe 245, 247 globale 245, 249 interne 244–245 AUTOEXTEND 219, 626 Automatic Segment Space Management 534 AUTOTRACE 499
Sandini Bib
724
:B
B*Index 151 Backup 69, 397 Blockrecover 442 CROSSCHECK 444 Delete Expired 444 Full 432, 446 Full Online 438 Incremental 429, 446 inkonsistent 415 inkrementell 432 Offline 429, 439 Online 463 Pieces 433 Templates 446 Validate 444 VALIDATE BACKUPSET 444 Backup-Level 432 Backup-Management 430 Backup-Set 430, 433 Before Image 30 BEGIN BACKUP 416, 429 Benutzerplanung 243 Benutzerverwaltung 252 interne 244 Betriebssysteme 61 Linux 61 MS-Windows 61 Unix 61 Betriebssystemressourcen 629 Bindevariablen 468, 470 Bitmap Join-Index 154, 699 Bitmap-Index 152, 504, 506, 510 Block Media Recovery 442 Blockgröße 70, 219, 528, 690 Blockierende Benutzer 630 Block-Korruption 442 Block-Logging 429, 439 Blockpuffer siehe Buffer Cache Branch Node 149 Breakable Parse Locks 41 Buffer Cache 528, 624 Byte-Semantik 37
:C
Cache Fusion 539, 687 Cache-Events Waits 474 CAST-Operator 658 Certificate Authority 265 Chained Rows 495, 642 char_to_label 312 Character-Semantik 37 CHECK-Constraint 194 Checkpoint 53, 117, 228, 535
Stichwortverzeichnis Checkpoint Queue 53 choose 498, 509 Chunk small 627 clear_pending_area 323 Client-Server-Kommunikation 33 Client-Server-Verbindungen 338 Clone-Datenbank 428 CLUSTER 510 Cluster 136, 518 Cluster-Schlüssel 518 Column Groups siehe Spaltengruppen Column Objects siehe Spaltenobjekte Column Subsetting 554 COMMIT 30, 203 COMMIT FORCE 547 Commit Point Site 546 Compartment 305 complete refresh 554 composite_limit 317 Composite-Partitionierung 140, 165, 168, 519 COMPRESS 507 Conditional Insert 678 connect_time 317 Connection-Load-Balancing 688 consistent gets 473, 527 Constraints 189 ein- und ausschalten 195 verzögerte Prüfung 197 Context Area 468 Control-Dateien 235 Controlfile Autobackup 437, 446 COPY 640 Cost-based Optimizer 718 Covert Disclosure 242 CPU Time 485 cpu_per_call 316 cpu_per_session 316 Crash Recovery 420 CREATE ANY CONTEXT 297 CREATE ANY TYPE-Privileg 660 CREATE BITMAP INDEX 152, 156 CREATE CLUSTER 136–137 CREATE CONTEXT 297 CREATE CONTROLFILE 131, 238, 418 CREATE DATABASE 95, 236 CREATE DATABASE LINK 544, 572, 590 CREATE DEFAULT TEMPORARY TABLESPACE CREATE DIRECTORY 140 CREATE GLOBAL TEMPORARY TABLE 142 CREATE INDEX 136, 138, 142, 151, 157, 159–160, 174
CREATE MATERIALIZED VIEW 593 CREATE MATERIALIZED VIEW LOG 588 CREATE OUTLINE 523 create_policy_group 301
Sandini Bib
Stichwortverzeichnis CREATE PROFILE 318 CREATE ROLE 278, 291–292, 294 CREATE ROLLBACK SEGMENT 205 CREATE SESSION 278, 287 CREATE_STORED_OUTLINES 522 CREATE SYNONYM 545 CREATE TABLE 136–137, 144–147, 166–168, 200 externe 141 Index-organisiert 138 CREATE-TABLE-AS-SELECT 639 CREATE TABLESPACE 205, 217–218 CREATE TEMPORARY TABLESPACE 223 CREATE TYPE 144–145, 147, 645 CREATE TYPE-Privileg 660 CREATE UNDO TABLESPACE 209 CREATE USER 245–246, 248, 250, 278, 318 CREATE VIEW 144, 658 CUBE 710 Cursor 46, 468 Cursor Handling 530 cwallet.sso 272
:D
Data Definition Language 20 Data Dictionary 29, 200 extern 97 Data Gatherer 634 Data Manipulation Language 20 Data Mart 674 Data Mining 669 Data Warehouse 504, 519, 528, 669 Database Buffer Cache 473, 527–528, 535 Database Configuration Assistent 104, 106 Database Recovery 424 Database Resource Manager 320 Datenbank Katastrophenfall 398 verteilte 541 Datenbankbenutzer 37 Datenbankblöcke 28 Datenbankblockgröße 29, 528 Datenbankdesign 685 Datenbank-Kopie 439 Datenbank-Link 542, 571, 675 global 543 private 543 public 543 Datenbankmodus 72 Datenbankname 71 Datenbankoptimierung 532 Datenbanksegmente 30 Datenbanksicherheit 241 Datenbank-Tracing 480 Datenbank-Trigger 683 Datendateien 28, 74, 215 Datensatzsperren 41
725 Datensicherung 397 Datentyp-Konvertierung implizit 484 Datenverfügbarkeit 459 db block gets 527 db file scattered read 473 db file sequential read 473 dba_2pac_pending 547 dba_audit_trail 331 dba_cons_columns 199 dba_constraints 199 dba_context 303 dba_data_files 626 dba_free_space 626 dba_global_context 303 dba_histograms 504 dba_indexes 506 dba_jobs 596 dba_mview_log_filter_cols 595 dba_mview_logs 595 dba_mviews 595 dba_outline_hints 524 dba_outlines 524 dba_policies 303 dba_policy_contexts 303 dba_policy_groups 303 dba_priv_audit_opts 332 dba_profiles 319 dba_proxies 250 dba_queue_tables 613 dba_queues 612 dba_refresh 595 dba_refresh_children 595 dba_repgenobjects 576 dba_repobject 576 dba_rollback_segs 212 dba_rsrc_consumer_groups 324 dba_rsrc_manager_system_privs 322 dba_rsrc_plan_directives 327 dba_rsrc_plans 324 dba_sa_groups 311 dba_sa_labels 311 dba_sa_policies 309 dba_segments 628 dba_stmt_audit_opts 332 dba_tab_columns 504 dba_tab_modifications 497 dba_tab_privs 289 dba_undo_extents 212 dba_users 247, 319 DBA-Sichten 99 DB-Capture 636 DBID 460 dbms_aq 607 dbms_aqadm 607, 611, 617, 619 dbms_backup_restore 429
Sandini Bib
726 dbms_defer_query 579 dbms_defer_sys 572–574, 581, 589, 591, 598–599 dbms_fga 333 dbms_job 597 dbms_logmnr 454 dbms_logmnr_d 454 dbms_mview 702, 705 dbms_offline_og 602 dbms_offline_snapshot 602 dbms_olap 708, 716 dbms_outln 524 dbms_outln_edit 523 dbms_redefinition 641 dbms_refresh 592–593 dbms_repcat 570, 574–577, 583–587, 592–594, 601, 603
dbms_repcat_admin 571–572, 588–590 dbms_reputil 570, 581–582, 585 dbms_resource_manager 320, 322, 328 dbms_resource_manager_privs 322 dbms_shared_pool 530 dbms_stats 177, 495–497, 520–521 dbms_summary 708 dbms_system 480 dbms_tts 225, 672 dbms_utility 495 DCE 249 DDL-Script 636 DDL-Sperren 40 Dead Connection Detection 343, 420 Deadlocks 42 Dedicated Server 23, 339 def$_aqcall 599 verzögerte 597 def_level 313 DEFAULT STORAGE 220 Default Tablespace 253, 672 defcall 579 defcalldest 578 Deferred Transaction Queue 543, 552, 567 Deferred Transactions 552 Deferror 580 verzögerte 598 defschedule 599 deftran 577, 579 deftrandest 578 DELETE-Konflikte 562 Denormalisierung 532, 669 Density 504 Dependency Tracking 45, 531 Deployment Templates 566 DEREF-Funktion 651 Dictionary Cache 472, 529 Dictionary Managed Tablespaces 222 Dienstebenennung 369 Digitale Zertifikate 257
Stichwortverzeichnis Dimension 714 Dimensionstabelle 669, 712–713 Direct Path 516, 637 Direct-Load-Insert 187 Directory Information Tree 260 Direktiven 320 Dirty Blocks 53 Discretionary Access Control 304 Dispatcher 26, 373 Distinguished Name 258, 261, 265, 271–272 DML-Sperren 40 DROP ANY TYPE-Privileg 660 DROP TABLE 194 DROP TABLESPACE 194 DROP USER 254 DTD 662 Dummy-Operation 492 Dynamic Class Loading 665 Dynamisches SQL 469
:E
Eindeutigkeitskonflikte 562 Elapsed Time 485 EMC2 686 BCV 686 Timefinder 686 Enterprise Manager 708 Ad-hoc-Query 669 Advanced Events 629 Agent 127 Backup-Verwaltung 445 Change Management Pack 636 Diagnostic-Pack 625 Konsole 125, 636 LogMiner Viewer 449 Management Server 126 Outline Management 525 Pakete 56 Performance Monitor 625 Reoganisations-Assistent 642 SQL Analyze 486, 499 Standard-Pack 625 Tablespace-Map 642 TopSessions 487, 499 TopSQL 486 Tuning-Pack 471, 525 Enterprise-Benutzer 256, 276 Enterprise-Rollen 256, 276 Equi-Partitioning 519, 694 ETL 669 Euro-Symbol 36 ewallet.der 272 execute count 473 Exemp Access Policy 303 EXITS 513 exp_full_database 400
Sandini Bib
Stichwortverzeichnis explain 481, 487 Explain-Plan 499, 501 Export 56, 62, 186, 398, 635, 637 Charset 407 COMPRESS 402, 638 Consistent 402 Direct Path 403 Query 403 Recordlength 403 Tables 403 Exportdatei 400, 404 eXtended Markup Language siehe XML eXtended Stylesheet Language siehe XSL Externe Prozeduren 352 Externe Tabellen 675 Extraktion 670
:F
failed_login_attempts 318 Failover 458, 460 Faktentabelle 669, 713 Fast Refresh 554, 702 Fehleranalyse 419 Feld-Statistik 521 FETCH-Phase 468 fga_log$ 333 Filesystem 626, 628 Fine Grain Access Control siehe Virtual Private Database Fine-Grain-Auditing 333 first_rows 498, 509 Flashback-Query 204, 402 Flat File Unload 407 Foreign Key-Constraint 191 Free Block List 516 Freelist 220, 474, 534, 538 Full-Block-Logging 416 Full-Table-Scan 135, 473, 492, 497, 499, 501–502, 508, 517
Function-based Index 157, 489, 508, 532, 640
:G
Garbage Collector 665 Gateway-Technologie 670 Geheimhaltungspflicht 242 GRANT 140, 252, 287, 289 GROUP BY 501 Grouping 711 GROUPING SETS 712
:H
Hardware-Cluster 687 Hardware-Striping 686 Hash-Cluster 136, 518 Hash-Join 497, 512, 515, 537 Hash-Partitionierung 139, 165, 168, 519, 533
727 Hierarchie 715 High Water Mark 135 Hint 508 global 513 Hintergrundprozess 23 AQTM 25 ARCn 25 CJQ0 25 CKPT 24 DBWn 24 DBWO-Prozess 228 Dnnn 25 Jnnn 25 LCKn 25 LGWR 24 LGWR-Prozess 226 PMON 24 Pnnn 25 QMNn 25 RECO 25 SMON 24 Snnn 25 SNPn 25 Histogramm 495, 502–503 HTML 662 HTTP-Server 386 Konfiguration 388 mod_ose 386 mod_plsql 386 Hybride Modelle 556, 559
:I
I/O-Bandbreite 403, 533 I/O-Leistung 538 I/O-Subsystem 686 I/O-Verteilung 533 idle_time 317 IIOP 666 Import 62, 186, 398, 404, 672 COMMIT 406 FROMUSER/TOUSER 405 FULL 405 IGNORE 405 INDEXFILE 406 TABLES 406 Incarnation Number 55 Index 148 global partitioniert 172 global prefixed 174 konkateniert 504 local nonprefixed 173 local prefixed 173 lokal partitioniert 172 nonprefixed 172 partitioniert 171 prefixed 172
Sandini Bib
728 RANGE SCAN 501 REVERSE 507 ROWID 501 INDEX_COMBINE 510 Index-Cluster 136, 518 Index-Fast-Full-Scan 511 Indexkomprimierung 158 Index-Organized Tables 506, 641 Indexreorganisation 161 Index-Scan 515 Index-Statistik 521 init.ora siehe Initialisierungsparameterdatei Initialisierungsparameter 91, 474, 536 aq_tm_processes 606–607 audit_trail 330 background_dump_dest 93, 596, 625 bitmap_merge_area_size 506, 698 buffer_pool_keep 527 buffer_pool_recycle 527 commit_point_strength 546 compatible 71, 570 control_files 92, 237, 239 controlfile_record_keep_time 445 core_dump_dest 93 cpu_count 718 create_bitmap_area_size 153, 505 cursor_sharing 518, 522 cursor_space_for_time 530 db_block_buffers 73, 527 db_block_checkpoint_batch 118 db_block_size 69, 93, 225, 528 db_cache_size 70, 73, 219, 522, 527 db_create_file_dest 75, 96, 218 db_create_online_log_dest_ 218 db_create_online_log_dest_1 96 db_create_online_log_dest_N 75 db_create_online_log_dest_n 232, 238 db_domain 130 db_file_multiblock_read_count 497, 718 db_keep_cache_size 528 db_name 92, 130 db_nk_cache_size 70, 73, 219, 529 db_recycle_cache_size 528 dispatchers 373, 394 fast_start_io_target 536 global_names 130, 542, 570 hash_area_size 497, 512, 537 instance_name 92 java_max_sessionspace_size 668 java_pool_size 668 java_soft_sessionspace_limit 668 job_queue_processes 570, 606–607 license_max_sessions 254 license_max_users 254 license_sessions_warning 254 log_archive_dest 233, 422
Stichwortverzeichnis log_archive_dest_n 233, 422 log_archive_dest_state_n 233 log_archive_duplex_dest 233 log_archive_format 233, 235 log_archive_log_dest 426 log_archive_max_processes 234 log_archive_min_succeed_dest 234 log_archive_start 234–235 log_archive_trace 234 log_buffer 226, 529 log_checkpoint_interval 119, 229, 236, 536
log_checkpoint_timeout 229, 236, 536 max_dispatchers 373 max_dump_file_size 481 max_enabled_roles 294 max_shared_servers 373 optimizer_index_cost_adj 537 optimizer_max_permutations 498 optimizer_mode 498, 526 os_authent_prefix 248 parallel_automatic_tuning 718 parallel_max_servers 571, 717 parallel_min_servers 160, 571 partition_view_enabled 188 pga_aggregate_target 506, 639 query_rewrite_enabled 489, 515, 706 query_rewrite_integrity 706 remote_login_passwordfile 94, 251–252 remote_os_authent 248 rollback_segments 93 service_names 92, 132, 350 session_cached_cursors 530 shared_pool_size 74, 472, 668 shared_servers 373 sort_area_size 214, 406, 497, 512, 522, 531, 537, 639
spin_count 474, 531 sql_trace 479–480, 632 transactions 208 transactions_per_rollback_segment 208 undo_management 72, 97 undo_retention 202, 204, 210 user_dump_dest 93 Initialisierungsparameterdatei 32, 92, 116 initjvm.sql 707 INSERT ALL 679 Installation 59 Java in der Datenbank 666 Installationsanweisungen 62 Installationsplanung 67 Betriebssystem 68 Datenbanken 69 Oracle-Version 67 Instance-Crash 410 Instance-Recovery 409, 420, 537
Sandini Bib
Stichwortverzeichnis Instantiation 566 Instanz 28 Instanzabbruch 54 Instanzoptimierung 527 Instanzplanung 69 Instanzverwaltung 109 Instead-Of-Trigger 659 Inter-Connect 539 Internet Directory 256 Internet Inter-ORB Protocoll siehe IIOP invalid_rows 494 Invertierte Listen 506 Isolation Level 43
:J
Java 664 Java Pool 21 Java Virtual Machine (JVM) 665, 707 JDBC 665 JDBC-Treiber 661 Job Queues 25 Jobfehler 596 Jobverwaltung 595 Join 511–512
:K
Kardinalität 505 Kerberos 249 Kollektionen 143, 146 Konfliktlösung 562, 579, 582 Konfliktlösungsmethoden 563 Konfliktlösungsstrategien 563 Konsistente Datenbank 397 Konsumentengruppen 320, 327 Kontextattribute 298 Kontrolldatei 31, 74, 408, 410 Kopieren der Produktionsdatenbank 461
:L
Label 304, 306 label_tag 311 Label-Bezeichner siehe label_tag Large Pool 21, 530 Lastverteilung 61 Latch 52, 527 Events 474 Statistik 474 Waits 474 Latch-Contention 534 LDAP 38, 256 LDAP-Server 261 LDAP-Verzeichnis Namensauflösung 383 Leaf-Block 507 Leaf Node 149 Least Recently Used-Algorithmus 44, 527
729 Legato Networker 429 Lesekonsistenz 42, 470, 484 Level 305 Library Cache 529, 624 Library Cache-Statistik 472 Listener Control Utiliy 345 List-Partitionierung 140, 165, 169 Literale 522, 529 Load Balancing 539 load_workload_cache 708 LOB-Felder 528 Locally Managed Tablespace 222, 627, 642 Lock Escalation 41 lock_object siehe Methoden Locks siehe Sperren Log Buffer 529 Log Switch siehe Wechsel der aktuellen Redolog-Gruppe LOGGING-Klausel 219 logical_reads_per_call 317 logical_reads_per_session 317 Logische Sicherung 428 LogMiner 397, 447, 466 Online Dictionary 448 Redo 453 Redolog Dictionary 448 Statistiken 456 Undo 453 Logon-Trigger 302 Logpuffer 21 Log-Sequence-Number 425 Logwriter-Prozess 529 LRU-Algorithmus siehe Least Recently UsedAlgorithmus LRU-Ende 44 LRU-Verwaltung 517
:M
Maintenance-Release 20 Mandatory Access Control 304 MAP-Methoden 655 Master Definition Site 552 Master Site 550 Materialized View 515, 559, 701 Materialized View-Replikation 550, 554, 587 Materialized View-Typen 555 max_level 313 MAXEXTENTS 207, 214 Media Management Library 429, 444 Media-Recovery 421, 692 Mehrprozessorsystem 686 Member Functions siehe Objekttypen Member Methods siehe Methoden MERGE 511, 516, 676 Merge-Join 497, 512, 515 Messaging Services 604
Sandini Bib
730
Stichwortverzeichnis
Metadaten 29 Methoden 652 Migrated-Row 535 Migration 398, 407 62
min_communication 600 min_level 313 Minimierung der Transaktionsdaten 599 MINIMUM EXTENT 220 Modified Block List 535 Monitoring 497, 595, 623 Ereignis 624 Online 624 von Indizes 162 Monitoring-Software 624 MOUNT-Status 410 MRU-Ende 44 MS-Windows Dienst 65 Threads 65 Multimaster-Replikation 550, 558, 574 MULTISET-Operator 658 Multi-Table INSERT 677 Multi-Threaded Server siehe auch Shared Server 25, 530, 688 Multi-Threaded-Architektur 65
:N
Named Pipes 407 Namenskonventionen 129 Datenbanken 130 Objektnamen 132 names.directory_path 270 National Language Support 33, 406 NESTED LOOP 501 Nested Loop 497, 511, 537 Nested Tables 146, 647 Net Manager 367 Network Manager 340 Netzverkehr verzögert 598 NLS_LANG 406 NLS_LANGUAGE 34 NLS-Parameter 532 NLS_SORT 532 binary 532 No Data Loss 459 NO_PUSH_PRED 517 NO_UNNEST 517 NOAUDIT 330 NOCACHE 517 NOLOGGING 638, 675, 691 nonpopular values 503 NOPARALLEL 514 Normalisierung 532 NOT-IN 513
NST7 475 NST8 475 num_buckets 504
:O
Object Request Broker 395 Objekt-Auditing 332 Objektprivilegien 288 Objekttabellen 145 Objekttypen 143, 645 Objekt-Views 657 OCCI siehe Oracle C++ Call Interface OCI siehe Oracle Call Interface ocopy.exe 416 OFA siehe Oracle Flexible Architecture OFFLINE IMMEDIATE 421 Offline-Instantiation 566, 601 Offline-Sicherung 414 Offline-Tablespace 224 OID Control Utility 262 oidctl 263 oidmon 263 OID-Monitor 262 ol$ 522 ol$hints 522 ol$nodes 522 OLAP 669 Online-Aufbau von Indizes 160 Online-Index-Rebuild 635 Online-Monitoring 631 Online-Reorganisation 635 Online-Sicherung 409, 415, 418 Online-Table-Reorganisation 641 OO4O siehe Oracle Objects for OLE open_cursors 468 open_links 570 Optimierung 467 Datenbank 467 Instanz 467 Netzwerk 467 Zugriffe 467 Optimizer 490 Hint 499, 508 kostenbasiert 490, 493, 498, 502, 509 regelbasiert 491, 498, 509 Oracle C++ Call Interface 660 Oracle Call Interface 660 Oracle Data Guard siehe Standby-Datenbank Oracle Data Provider for .Net 661 Oracle Database Configuration Assistant 277 Oracle Enterprise Login Assistant 265 Oracle Enterprise Manager siehe Enterprise Manager Oracle Enterprise Security Manager 278 Oracle Flexible Architecture 89 Oracle Internet Directory 257, 261
Sandini Bib
Stichwortverzeichnis Oracle JVM siehe Java Virtual Machine Oracle Managed Files 75, 96, 218, 628 Oracle Managed Standby 461, 464 Oracle Names 266, 379 LDAP-Proxy 383 Oracle Net 33, 337, 464 $TNS_ADMIN 341 cman.ora 376 Connection Manager 375 Connection Multiplexing 376 Firewall 386 IIOP-Verbindungen 393 Konfiguration von Benennungsmethoden 364 Konfiguration von DirectoryVerwendung 365 Konfigurationsdateien 341 ldap.ora 270, 277 Listener 339, 342 listener.ora 273, 280, 342 Listener-Konfiguration 362 lsnrctl 345 NAMES 343 NAMESCTL 380 Net-Konfigurationsassistent 361 Oracle Listener 464 SDU 351 SERVICE_NAME 349 SID_LIST_LISTENER 342 SQLNET.AUTHENTICATION_SERVICES 248, 344
SQLNET.EXPIRE_TIME 343 sqlnet.ora 273, 280, 341 tnsnames.ora 275, 343 tnsping 354 Trace Assistant 357 Tracing 356 Verbindungsaufbau 349 Oracle Net Configuration Assistant 267 Oracle Net Manager 269, 273 Oracle Objects for OLE 661 Oracle Security Manager 273 ORACLE_SID 81 Oracle Trace 485 Oracle Type Translator 660 Oracle Universal Installer 75 Oracle Wallet Manager 265, 271 Oracle Warehouse Builder 669 Oracle8i 19 Oracle9i 19 Enterprise Edition 58 Personal Edition 58 Standard Edition 58 Oracle9i Database 57 Oracle9i Developer Suite 57
731 Oracle9iAS 57 Oracle-Block siehe Blockgröße Oracle-Installation 64-Bit-Versionen 64 Linux 66 MS-Windows 64 Oracle-Loader siehe SQL*Loader Oracle-SGA siehe System Global Area Oracle-Umgebung Unix 81 Windows 85 oradim 94 oraenv 82 orapwd 252 94
ORB siehe Object Request Broker ORDBMS 645 ORDERED 511 ORDERED_PREDICATES 517 ORDER-Methoden 655 OS_ROLES 293 OSDBA 251 OSOPER 251 OTT siehe Oracle Type Translator Outlines, private 523 OUTLN 522 Overriding siehe Überschreiben
:P
PARALLEL 514, 638 Parallele Abfragen 717 Paralleles Laden 674 Parallelisierung 673 bei Indizes 159 Parallel-Query 519, 533 Parameterdatei siehe Initialisierungsparameterdatei Parametrierung 116 Parse Call 478 parse count 473 Parse-Time 498 Parsing 491, 498, 529 Partition 162, 515, 519, 533, 692 aufteilen 185 Composite 696 Elimination 693 Exchange 672, 693 Hash 694 hinzufügen 184 leeren 186 Level Optimization 519 List 696 löschen 183 Pruning 519, 692 Range 139, 164, 166, 519, 533, 692 umbenennen 186
Sandini Bib
732 umorganisieren 185 zusammenlegen 186 Partitioned Fine Grain Access Control siehe Virtual Private Database Partitionstausch 184 Partition-Wise-Joins 519 password_grace_time 319 password_lifetime 318 password_lock_time 319 password_reuse_max 318 password_reuse_time 318 password_verify_function 319 Passwörter 246 Patches 21 Patchset 21 PCM-Locking 25 PCT_FREE 535 PCT_USED 535 PCTFREE 220–221 PCTUSED 220–221 Performance 467, 624 Performance Monitor 633 Performance-Tabellen 471 PERFSTAT siehe Statspack PGA siehe Process Global Area physical reads 527 Pinned Package 530 Pinning 530 PIPE ROW 680 PIPELINED 680 Plan Stability 521 plan_table 499 Platten-Crash 410 Plattenfehler 413 Platzbedarf 623 PLUSTRACE 499 Point-In-Time-Recovery 409, 456 Policy siehe auch Sicherheitsrichtlinie 295, 304–305, 309
Popular Values 503 Primary Key-Constraint 191 Primary Site-Modell 553 private_sga 317 Privilegien-Auditing 332 Pro*C/C++ 661 Process Global Area 530 PRODUCT_PROFILE-Tabelle zuweisen 104 Profile 316 Propagator 564 Protokoll TCP/IP 339 Proxy Materialized View Replication Administrator 566 Proxy Refreshers 566 Proxy-Authentifizierung 245, 249
Stichwortverzeichnis Prozedurale Replikation 599 Prozessarchitektur 63 Prozesse 22 Public Key-Kryptografie 264 PUBLIC-Benutzer 287 Publish-Subscribe-Verfahren 616 PUSH_PRED 517 PUSH_SUBQ 517
:Q
Query Rewrite 706 Query Server 515 QUERY_REWRITE 702 Quoten 253
:R
RAC-Datenbank siehe Real Application Cluster RADIUS 249 RAID 216, 533, 538, 686 RANG 718 RATIO_TO_REPORT 719 Raw-Devices 688 RDBMS 20 rdbms_server_dn 277 Read 309 Read Committed 43 READ_CONTROL 305 Read-Only 43 Read-Only Tablespace 223, 672 Real Application Cluster 119, 538, 673, 687 DLM 120 Installation 120 Linux 66 Starten 123 REBUILD INDEX 640 receiver 564 recommend_mview_strategy 708 RECOVER DATABASE 441 Recovery 69, 397, 440 auto 422 cancel-based 422 change-based 428 Data Dictionary 424 database 421 datafile 421 Modus 458 Online 423 tablespace 421 Tablespace Point in Time 428 Tablespaces SYSTEM 424 teilweise 429 Time-based 427 unvollständige Wiederherstellung 426 vollständig 429
Sandini Bib
Stichwortverzeichnis Recovery Manager 397, 429 Allocate Channel 435 Channel 433–434 Datenbank-ID 434 Default Device 434 Disk 434 Duplicate 436 Format 434 Kompatibilität 431 Maxpiecesize 435 Parallelisierung 433 Register Database 436 Reporting 443 Repository 431 SBT 434 Tape 434 Target 430 Recovery Manager Repository siehe Recovery-Katalog Recovery-Katalog 433, 435 Redo Buffer 624 Redo Buffer Allocation 529 Redo Buffer Allocation Retries 227 Redo Byte Address 53 Redolog archiviert 412 Datei 31, 74, 226, 529, 536 Gruppe 31, 536 Member 31 size 473 Switch 625 sync 473 REF-Datentyp 651 REF-Funktion 651 Refresh Complete 705 Fast 705 Force 705 Refresh Groups siehe Aktualisierungsgruppen Relative Distinguished Name 260 Reorganisation 398, 623, 635 Replication Administrators 564 Replication Group siehe Replikationsgruppen Replication Propagators 543 replication_dependency_tracking 571 Replikation 465, 549 asynchron 466 Replikationsgruppen 550 Replikationsmodell 558 Request Queue 26 resource_limit 316 resource_manager_plan 328 Response Queue 26 Ressourcenengpass 623
733 Ressourcenfresser 490 Ressourcenpläne 320 Restore 440 RESTORE DATABASE 441, 444 Resumable 682 Retention Policies 444 Reverse Key-Index 157, 507 REVOKE 288–289 Richtliniengruppen 300 rman 429 Roll Forward 55, 420 ROLLBACK 30, 201 Rollback 55, 420 OPTIMAL 474, 534 ROLLBACK FORCE 547 Rollback-Segment 30, 52, 71, 201, 208, 534 Rollback-Tablespace 101 Rollen 38, 289 globale 257 vordefinierte 290 Rolling Upgrade 458 Rolling Window 693 ROLLUP 710 root block 150 Row Exclusive siehe Tabellensperren Row Label 304 row_level 313 Row Object siehe Zeilenobjekte Row Splitting 70 Row-Chaining 535 ROWID 510 RULE 498, 509
:S
sa_components 310 sa_label_admin 311 sa_sysdba 309 sa_user_admin 312–313, 315 Scheduled Link 543, 573 Schwellenwert 623 SCN siehe System Change Number SCOPE 146 Secure Sockets Layer siehe SSL Segment Header 474 Segment-Space-Management 220 SELECT-Befehl 46 Semaphoren 63 SEMI-Join 513 serial# 480 Serializable 43 Serverparameterdateien siehe Initialisierungsparameterdateien Session 26 session_per_user 316 Session-Label 304, 306–307 SET ROLE 292
Sandini Bib
734 SET TRANACTION USE ROLLBACK SEGMENT 206 SET_CONTEXT 298 SET_SQL_TRACE_IN_SESSION 480 SGA siehe System Global Area sga_max_size 527 Share Mode siehe Tabellensperren Share Row Exclusive siehe Tabellensperren Shared Pool 21, 74, 469, 472, 478, 486, 529–530 Shared Schema 243, 257–258, 276 Shared Server 338, 373, 506 Shared Server-Datenbank 458 Shared Server-Prozesse 25 Shared-Modus 687 SHUTDOWN 109, 112 ABORT 113, 411 IMMEDIATE 88, 113 NORMAL 112 TRANSACTIONAL 113 Sicherheitsrichtlinie 295, 301 Sicherung 397, 409 physikalisch 397 Sicherungskonzept 397, 460 Sicherungsverfahren 432 sid 480 Silent-Installation 80 Simulation 520 Single Sign On 249, 256 Sitzung 26 SLEEP 531 sleeps 474 Snapshot 475, 701 Snapshot-Controlfile 430 Snowflake-Schema 669, 713 Software Packager 89 SORT 501 Sort Area 30, 47 Spaltengruppen 562, 582, 585 Spaltenobjekte 144 spauto siehe Statspack Sperren 40 Sperr-Konflikt 505 SPFILE 91, 474 spreport siehe Statspack SQL 19 SQL*Loader 56, 187, 408 SQL*Net 337 SQL*Plus 56 SQL-Area 478–479 SQL-Befehl rekursiv 469 SQLJ 661, 665 SQL-Tracing 479 SSL 256, 264, 275 SSL-Port 281 STANDBY CONTROLFILE 461
Stichwortverzeichnis Standby-Datenbank 458 Read-Only 460 Standby-Kontrolldatei 463 STANDBY-Modus 464 STAR_TRANSFORMATION 516 Star-Query 511 Star-Schema 669, 713 Startup 109–110 FORCE 111 MOUNT 110 MOUNT Oracle Parallel Server 112 NOMOUNT 110 OPEN 111 OPEN RECOVER 111 RESTRICTED 111 static compilation 666 Statisches SQL 469 Statistik 520 Buffer-Busy-Wait 474 für partitionierte Objekte 176 gespeicherte 520 Latch 474 Rollback-Segment 474 STATS$ 472 STATS$STATPACK_PARAMETER siehe Statspack Statspack 475 Stored Outlines 522 Export und Import 525 Striping 497, 533 submit_pending_area 323 SUM OVER 719 Summary Advisor 707 Suspend 683 synchrone Replikation siehe Übertragungsmethode Synchronisationszeitpunkt 416 Synonym 531, 544 privat 531 SYSDBA 251–252 SYSOPER 251–252 System Change Number 46, 470 System Global Area 21 system_privilege_map 332 Systemabsturz 420 Systemprivilegien 282 Systemstatistiken 496
:T
Tabellen externe 140 Heap-organisiert 135 Index-organisiert 138 partitionierte 139 temporäre 142, 214 Tabellen-Cluster 510
Sandini Bib
Stichwortverzeichnis Tabellensperren 160 Tabellen-Trigger 532 Table-Function 679 Tablespace 215, 399 erstellen 217 Layout 690 Manager 638 TCL-Job 446 Temporärsegmente 30 Temporary Tables siehe Tabellen, temporäre Temporary Tablespace 223, 253, 497 anlegen 102 zuweisen 102 Thread 27 TKPROF 56, 481, 484, 499 TOAD 636 Top-5-Liste 478 Trace-Datei 481 Tracing 499, 632 Tranparent Gateway 670 trans_tbl_waits 474 Transaktion 39 autonome 40, 679 Redo 447 Undo 447 verteilt 541, 545 verzögert 597 Transaktionseintrag 528 Transaktions-Lesekonsistenz 40 Transaktionsmanagement 71 Transformation 670 Transportable Tablespace 225, 402, 670 TREAT-Funktion 651 Trigger 485 TRUNCATE 222 Trust Points 265 Trusted Security 565 Two-Phase-Commit 545 Typerweiterungen 656
:U
Überschreiben 654, 664 Übertragungsmethode 552 Überwachung 623 Umgebungsvariable ORACLE_HOME 77 under_any_type-Privileg 660 undo header 474 Undo Tablespace 72
undo_management 202, 208–209 UNDO_POOL 210 Undo-Segmente 30 Unicode 36 UNIQUE-Constraint 190 uniqueness 506
735 Unix-Pipes 407 UNLIMITED 214 UNNEST 517 UNRECOVERABLE 443 untrusted security 565, 589 Update Anywhere-Modell 553 UPDATE-Befehl 47 Update-Konflikte 562 US7ASCII 406 User-Defined Datatypes siehe Objekttypen User Label 306 user_ind_columns 157–158, 176 user_ind_expressions 158 user_ind_partitions 176 user_ind_subpartitions 176 user_indexes 157–158, 176 user_part_indexes 176 user_part_key_columns 170 user_part_tables 170 user_subpart_key_columns 170 user_tab_partitions 170 user_tab_subpartitions 170 user_tables 170 user_users 247 USING BACKUP CONTROLFILE 427 utl_ref siehe Methoden utlbstat 472 utlestat 472 utlxmv.sql 703 utlxpls.sql 502
:V
v$archived_log 413 v$backup 417 v$backup_corruption 443 v$context 303 v$controlfile 239, 414 v$database 411 v$datafile 98, 414, 419 v$globalcontext 303 v$log 412 v$log_history 412 v$logfile 231, 414 v$loghist 231, 412 v$loghistory 231 v$logmnr_contents 454 v$object_usage 162 v$process 98 v$pwfile_users 252 v$recover_file 419 v$replqueue verzögerte 597–598 v$rollname 212 v$rollstat 207, 212, 474, 534 v$rsrc_consumer_group 329 v$rsrc_plan 328
Sandini Bib
736 v$session 480, 632 v$session_longops 684 v$sgastat 668 v$sqlarea 478, 486, 632 v$sqltext 479, 486 v$sysstat 227, 473, 527, 529 v$-Tabellen 471, 476, 632 v$tablespace 419 v$transaction 212 v$vpd_policy 303 validate_pendig_area 323 VALUE-Funktion 647, 650 Varray 146, 648 Verarbeitungsgeschwindigkeit 490 Verbindungsaufbau 339 Verdichtung 701 Vererbung 649, 664 Verfügbarkeit 69 Verteilte Datenhaltung 427, 532 Verzeichnisdienst 38 Verzeichnisdienste 257, 260 Virtual Private Database 38, 295 Vollständige Wiederherstellung 420
Stichwortverzeichnis
:W
Wait-Event 473, 478 Wallet 275, 280 Wechsel der aktuellen Redolog-Gruppe 53 Wiederherstellung siehe Recovery WITH ADMIN OPTION 287, 293 WITH-Klausel 712 Workflow-Modell 553 Workload 496, 708 Wrapper 553 Write Through Cache 51 WRITE_CONTROL 305–306 Writedown 309 Writeup 309
:X
XML 662 XML Developer Kit 663 XSL 662
:Z
Zeichensätze 35, 70 Zeilenobjekte 145 Zertifikate, digitale 264 Zugriffskontrollen 243 Zugriffsoptimierung 467, 490
Sandini Bib
Copyright Daten, Texte, Design und Grafiken dieses eBooks, sowie die eventuell angebotenen eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir lediglich als persönliche Einzelplatz-Lizenz zur Verfügung! Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und Informationen, einschliesslich •
der Reproduktion,
•
der Weitergabe,
•
des Weitervertriebs,
•
der Platzierung im Internet, in Intranets, in Extranets,
•
der Veränderung,
•
des Weiterverkaufs
•
und der Veröffentlichung
bedarf der schriftlichen Genehmigung des Verlags. Insbesondere ist die Entfernung oder Änderung des vom Verlag vergebenen Passwortschutzes ausdrücklich untersagt! Bei Fragen zu diesem Thema wenden Sie sich bitte an: [email protected] Zusatzdaten Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die Zurverfügungstellung dieser Daten auf unseren Websites ist eine freiwillige Leistung des Verlags. Der Rechtsweg ist ausgeschlossen. Hinweis Dieses und viele weitere eBooks können Sie rund um die Uhr und legal auf unserer Website
http://www.informit.de herunterladen