Oracle 10g für den DBA
EDITION Oracle Oracle 10g Hochverfügbarkeit – Die ausfallsichere Datenbank mit RAC, Data Guard und Flashback Andrea Held ISBN 3-8273-2163-8 Oracle-Programmierung – Datenbankprogrammierung und -administration Heinz-Gerd Raymans ISBN 3-8273-1733-9 Oracle9i für den DBA – Effizient konfigurieren, optimieren und verwalten Johannes Ahrends, Dierk Lenz, Günter Unbescheid, Uwe Herrmann ISBN 3-8273-1559-X
Johannes Ahrends, Dierk Lenz, Patrick Schwanke, Günter Unbescheid
Oracle 10g 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
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 und weitere Stichworte und sonstige Angaben, die in diesem Buch verwendet werden, sind als eingetragene Marken geschützt. Da es nicht möglich ist, in allen Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht, wird das Symbol ® in diesem Buch nicht verwendet. Umwelthinweis: Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt. Die Einschrumpffolie – zum Schutz vor Verschmutzung – ist aus umweltverträglichem und recyclingfähigem PE-Material. 10 9 8 7 6 5 4 3 2 1 08 07 06 ISBN 3-8273-2171-9 © 2006 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: Herstellung: Satz: Druck und Verarbeitung: Printed in Germany
Thomas Arlt,
[email protected] Sylvia Hasselbach,
[email protected] Sandra Gottmann,
[email protected] Elisabeth Prümm,
[email protected] Michael und Silke Maier,
[email protected] Bercker, Kevelaer
Inhaltsverzeichnis 1
Einführung ....................................................................................................... 15 1.1 Allgemeines ........................................................................................... 15 1.1.1 Kleine Versionshistorie ............................................................... 15 1.2 Oracle-Komponenten............................................................................. 17 1.2.1 Funktionsumfang....................................................................... 17 1.2.2 Optionen................................................................................... 20 1.2.3 Weitere Produkte ....................................................................... 21 1.3 Datenbank-Paradigmen.......................................................................... 22 1.3.1 Das Transaktionsverhalten ......................................................... 22 1.4 Aufgaben eines DBA............................................................................... 26 1.4.1 Kerngebiete der DB-Administration............................................ 27 1.4.2 Bereiche mit DBA-Unterstützung ............................................... 28 1.4.3 Aufgaben, die nicht beim DBA angesiedelt sein sollten .............. 29
2
Installation und Aufbau einer Datenbank ....................................................... 31 2.1 Basisinstallation ...................................................................................... 32 2.2 Installationsplanung ............................................................................... 34 2.2.1 Hardware und Betriebssystem.................................................... 35 2.2.2 Art der Anwendung ................................................................... 43 2.2.3 Versionstechnische Planung ....................................................... 45 2.2.4 Betriebssystemspezifische Planung ............................................. 45 2.2.5 Software-Komponenten............................................................. 46 2.2.6 Globalization Support ................................................................ 48 2.2.7 Die Planung von Instanzen und Datenbanken............................ 49 2.3 Software-Installation............................................................................... 55 2.3.1 Vorbereitungen ......................................................................... 55 2.3.2 Oracle Flexible Architecture (OFA) ............................................. 57 2.3.3 Universal Installer....................................................................... 59 2.3.4 Silent Installation ....................................................................... 63 2.3.5 Cluster Ready Services ............................................................... 65 2.4 Datenbankkonfiguration......................................................................... 66 2.4.1 Database Configuration Assistant (DBCA) .................................. 66 2.4.2 Skriptbasierte Installation ........................................................... 75 2.5 Patches und Patch-Sets .......................................................................... 81 2.5.1 Patch-Sets.................................................................................. 81 2.5.2 Interim-Patches.......................................................................... 83 2.6 Release-Wechsel ..................................................................................... 83 2.6.1 Vorbereitung ............................................................................. 84 2.6.2 Database Upgrade Assistant (DBUA) .......................................... 85 2.6.3 Manueller Upgrade.................................................................... 88 2.6.4 Downgrade ............................................................................... 93
6
Inhaltsverzeichnis
3
Datenbank-Architektur .................................................................................... 95 3.1 Namenskonventionen ............................................................................ 95 3.1.1 Datenbanken ............................................................................. 96 3.1.2 Systemobjekte ........................................................................... 99 3.2 Komponenten einer Oracle-Datenbank ................................................ 100 3.3 Tablespaces und Datendateien............................................................. 101 3.3.1 Planung ................................................................................... 102 3.3.2 Erstellen eines Tablespaces....................................................... 103 3.3.3 SYSTEM- und SYSAUX-Tablespace ........................................... 109 3.3.4 Temporär-Tablespaces und Temporärsegmente....................... 114 3.3.5 Undo-Tablespaces.................................................................... 116 3.3.6 Read-only-Tablespaces............................................................. 122 3.3.7 Tablespaces offline setzen ........................................................ 122 3.4 Datenbankblöcke ................................................................................. 123 3.5 Online-Redolog-Dateien....................................................................... 124 3.5.1 Konfiguration .......................................................................... 125 3.5.2 Administrationskommandos .................................................... 128 3.5.3 Überwachung von Redolog-Dateien ........................................ 129 3.5.4 Überlegungen zur Spiegelung von Redolog-Dateien ................ 130 3.6 Kontrolldateien .................................................................................... 131 3.6.1 Administration der Kontrolldateien .......................................... 132 3.7 Parameterdateien ................................................................................. 135 3.8 Block-Change-Tracking-Datei ............................................................... 136 3.9 Physikalisches Layout............................................................................ 138 3.9.1 Dateisystem ............................................................................. 138 3.9.2 Cluster-Dateisystem ................................................................. 143 3.9.3 Raw Devices ............................................................................ 144 3.9.4 Automatic Storage Management (ASM) .................................. 145 3.10 Ältere Funktionen................................................................................. 153 3.10.1 Dictionary-Managed Tablespaces............................................. 153 3.10.2 Rollback-Segmente .................................................................. 154
4
Instanz-Verwaltung ....................................................................................... 157 4.1 Werkzeuge und Voraussetzungen......................................................... 157 4.1.1 Startup .................................................................................... 158 4.1.2 Shutdown................................................................................ 160 4.1.3 Alter Database ......................................................................... 161 4.1.4 Alter System ............................................................................ 162 4.2 Parametrierung .................................................................................... 164 4.2.1 Checkpoints ............................................................................ 166 4.2.2 Dynamische SGA ..................................................................... 167 4.3 Oracle Cluster Synchronization Service Daemon................................... 170 4.4 ASM-Instanzen ..................................................................................... 171 4.5 Ältere Versionen ................................................................................... 172
Inhaltsverzeichnis
7
5
Datenbankobjekte ......................................................................................... 173 5.1 Namenskonventionen .......................................................................... 173 5.2 Datenobjekte ....................................................................................... 175 5.2.1 Datentypen ............................................................................. 176 5.2.2 Tabellen................................................................................... 179 5.2.3 Partitionierte Tabellen.............................................................. 180 5.2.4 Indexorganisierte Tabellen (IOT).............................................. 183 5.2.5 Temporäre Tabellen................................................................. 184 5.2.6 Externe Tabellen ...................................................................... 185 5.2.7 Cluster..................................................................................... 188 5.2.8 Objekttypen und Kollektoren ................................................... 190 5.3 Indexstrukturen.................................................................................... 195 5.3.1 Allgemeine Regeln ................................................................... 196 5.3.2 B*Tree Index............................................................................ 197 5.3.3 Bitmap-Index........................................................................... 198 5.3.4 Bitmap-Join-Index.................................................................... 201 5.3.5 Function-based Index .............................................................. 203 5.3.6 Partitionierte Indizes ................................................................ 204 5.3.7 Komprimierung von Indizes ..................................................... 209 5.3.8 Reverse Key-Indizes.................................................................. 210 5.3.9 Weitere Aspekte der Indexverwaltung...................................... 210 5.4 Constraints........................................................................................... 213 5.4.1 Constraint-Definitionen ........................................................... 214 5.4.2 Constraint-Handhabung .......................................................... 218 5.5 Views ................................................................................................... 223 5.5.1 Standard-Views........................................................................ 223 5.5.2 Materialized Views ................................................................... 229 5.5.3 Object-Views ........................................................................... 230 5.6 PL/SQL-Objekte.................................................................................... 232 5.7 Directory-Objekte für den Dateizugriff.................................................. 242
6
Administrationswerkzeuge............................................................................ 245 6.1 Oracle Enterprise Manager ................................................................... 245 6.1.1 Enterprise Manager Database Control...................................... 247 6.1.2 Enterprise Manager Grid Control ............................................. 257 6.2 Scheduler............................................................................................. 264 6.2.1 Alter Scheduler ........................................................................ 264 6.2.2 Neuer Scheduler ...................................................................... 267 6.3 Weitere Werkzeuge .............................................................................. 275 6.3.1 SQL*Plus.................................................................................. 275 6.3.2 TOAD ...................................................................................... 276 6.3.3 Hora ........................................................................................ 278
8
Inhaltsverzeichnis
7
Zugriff auf die Datenbank ............................................................................. 281 7.1 Oracle Net ........................................................................................... 281 7.1.1 Architektur und Konfiguration ................................................. 281 7.1.2 Shared Server .......................................................................... 306 7.1.3 Spezielle Parameter.................................................................. 312 7.1.4 Instant Client ........................................................................... 316 7.2 Alternative Methoden zur Namensauflösung ........................................ 317 7.2.1 Hostnaming und Easy Connect ................................................ 317 7.2.2 JDBC Thin Driver ..................................................................... 318 7.2.3 LDAP-Verzeichnisse.................................................................. 319 7.2.4 Welche Methode ist die beste? ................................................ 321 7.3 Connection Manager ........................................................................... 323 7.4 Firewall ................................................................................................ 326 7.5 Java in der Datenbank .......................................................................... 327 7.5.1 Java-Grundlagen ...................................................................... 327 7.5.2 Java-APIs in der Datenbank ...................................................... 329 7.5.3 Server-seitige Installation ......................................................... 330 7.5.4 Clientseitige Installation ........................................................... 332 7.5.5 JDBC-Treiber............................................................................ 333 7.5.6 Verbindungen via JDBC ........................................................... 334 7.5.7 NLS-Einstellungen für JDBC...................................................... 335 7.5.8 Java-Objekte in der Datenbank ................................................ 337 7.5.9 Resolving ................................................................................. 338 7.5.10 Tools zur Java-Verwaltung........................................................ 338 7.5.11 Ausgabeumleitung................................................................. 340 7.5.12 Publishing von Java-Klassen ................................................... 340 7.5.13 Deinstallation der Oracle JVM ................................................ 341 7.6 Die Oracle XML DB .............................................................................. 341 7.6.1 Installation der XML DB ........................................................... 342 7.6.2 Einrichtung der Protokollserver ................................................ 343 7.6.3 Benutzung der Protokollserver ................................................. 344 7.6.4 Konfiguration der Protokollserver............................................. 346
8
Globalization Support ................................................................................... 347 8.1 Überblick ............................................................................................. 347 8.2 Grundeinstellung ................................................................................. 348 8.3 Sprachen und landesspezifische Konventionen ..................................... 349 8.3.1 Sprache, Gebiet und Datumsformat......................................... 349 8.3.2 Zeitzonen, Zeitstempel und Intervalle ...................................... 352 8.3.3 Sortierreihenfolgen .................................................................. 354 8.3.4 Weitere NLS-Parameter............................................................ 355
Inhaltsverzeichnis
8.4
9
9
Zeichensätze ........................................................................................ 355 8.4.1 Single-Byte-Zeichensätze ......................................................... 356 8.4.2 Multi-Byte-Zeichensätze, insbesondere UNICODE.................... 357 8.4.3 Migration von Zeichensätzen................................................... 359
Sicherheit ....................................................................................................... 363 9.1 Einführung ........................................................................................... 363 9.2 Grundlegende Maßnahmen ................................................................. 366 9.2.1 Maßgeschneiderte Installation ................................................. 366 9.2.2 Standardpasswörter ................................................................. 366 9.2.3 Vordefinierte Rollen und Grants ............................................... 368 9.2.4 Patches .................................................................................... 369 9.3 Sichern der Datenübertragung ............................................................. 370 9.3.1 Konfiguration des Listener-Prozesses ........................................ 370 9.3.2 Verschlüsselung und Integrität ................................................. 374 9.4 Benutzerplanung.................................................................................. 376 9.5 Interne Benutzerverwaltung ................................................................. 379 9.5.1 Möglichkeiten der Authentifizierung ........................................ 380 9.5.2 Interne Authentifizierung ......................................................... 380 9.5.3 Externe Authentifizierung ........................................................ 382 9.5.4 Globale Authentifizierung ........................................................ 385 9.5.5 Proxy-Authentifizierung ........................................................... 385 9.5.6 Authentifizierung von Datenbankadministratoren .................... 390 9.5.7 Benutzerverwaltung................................................................. 392 9.6 Internet Directory, LDAP und SSL ......................................................... 395 9.6.1 Die Möglichkeiten im Überblick ............................................... 396 9.6.2 Grundlegende Standards und Begriffe ..................................... 399 9.6.3 Modell 1: Auflösung von Dienstbenennungen ......................... 408 9.6.4 Modell 2: Authentifizierung globaler Benutzer ......................... 411 9.6.5 Modell 3: Enterprise-Benutzer und Enterprise-Rollen ................ 417 9.6.6 Verwaltung von Oracle Internet Directory................................ 429 9.7 Privilegien und Rollen........................................................................... 430 9.7.1 Systemprivilegien..................................................................... 430 9.7.2 Objektprivilegien ..................................................................... 436 9.7.3 Rollen ...................................................................................... 438 9.8 Virtual Private Database........................................................................ 448 9.8.1 Einführung............................................................................... 448 9.8.2 Aufbau einer VPD-Umgebung.................................................. 450 9.9 Labels................................................................................................... 462 9.9.1 Überblick ................................................................................. 462 9.9.2 Die Grundlagen ....................................................................... 463 9.9.3 Konfiguration eines Label-Systems ........................................... 467
10
Inhaltsverzeichnis
9.10
9.11
9.12
Profile .................................................................................................. 473 9.10.1 Management von Ressourcen .................................................. 473 9.10.2 Password-Management ........................................................... 475 Management von Ressourcen mit dem Resource Manager................... 476 9.11.1 Überblick ................................................................................. 476 9.11.2 Der Aufbau einer Beispielumgebung........................................ 477 9.11.3 Monitoring .............................................................................. 484 Auditing............................................................................................... 484 9.12.1 Zwanghaftes Auditing.............................................................. 485 9.12.2 Aktivieren von Auditing ........................................................... 486 9.12.3 Kommando-Auditing ............................................................... 487 9.12.4 Privilegien-Auditing ................................................................. 488 9.12.5 Objekt-Auditing ....................................................................... 488 9.12.6 Fine-Grain-Auditing ................................................................. 489 9.12.7 Audit-Trigger ........................................................................... 490 9.12.8 Empfehlungen ......................................................................... 491
10 Wiederherstellungstechniken........................................................................ 493 10.1 Planung ............................................................................................... 493 10.1.1 Generelles................................................................................ 493 10.1.2 Hardware................................................................................. 494 10.1.3 Archivierung ............................................................................ 494 10.1.4 Flash-Recovery Area ................................................................. 501 10.2 Sicherung und Wiederherstellung ........................................................ 503 10.2.1 Fehleranalyse ........................................................................... 504 10.2.2 Wiederherstellungsstrategie ..................................................... 505 10.2.3 Instanzwiederherstellung, Prozess- und Netzwerkfehler............ 506 10.2.4 Wiederherstellung von Medienfehlern ..................................... 507 10.2.5 Anwenderfehler ....................................................................... 509 10.3 Der Recovery Manager......................................................................... 510 10.3.1 Architektur............................................................................... 512 10.3.2 Sicherung ................................................................................ 521 10.3.3 Rücksicherung und Wiederherstellung ..................................... 527 10.3.4 Berichte und Überprüfung ....................................................... 531 10.3.5 Aufräumen .............................................................................. 532 10.3.6 Verwaltung im Oracle Enterprise Manager ............................... 532 10.4 Flashback Database .............................................................................. 535 10.5 Tablespace-Point-in-Time Recovery (TSPITR) ........................................ 538
Inhaltsverzeichnis
10.6
10.7
11
Objektbasierte Techniken ..................................................................... 540 10.6.1 Data Pump .............................................................................. 540 10.6.2 Export und Import ................................................................... 550 10.6.3 LogMiner................................................................................. 558 10.6.4 Flashback Query ...................................................................... 560 10.6.5 Flashback Table ....................................................................... 563 Ältere Techniken zur Sicherung ............................................................ 567 10.7.1 Offline-Sicherung..................................................................... 567 10.7.2 Online-Sicherung..................................................................... 569 10.7.3 Spezielle Techniken.................................................................. 571
11 Tuning ............................................................................................................ 573 11.1 Strategie .............................................................................................. 573 11.2 Hilfsmittel............................................................................................. 575 11.2.1 Oracle Performance-Views ....................................................... 575 11.2.2 Monitoring und Engpassanalyse .............................................. 583 11.2.3 Anwendungs-Tracing............................................................... 593 11.3 Der Optimizer ...................................................................................... 609 11.3.1 Die Ausführung von SQL-Code ............................................... 609 11.3.2 Erstellung und Pflege von Statistiken....................................... 612 11.3.3 Serverparameter mit Relevanz für den Query Optimizer........... 621 11.4 Zugriffsoptimierung ............................................................................. 623 11.4.1 Ausführungspläne.................................................................... 623 11.4.2 Indizierung .............................................................................. 632 11.4.3 Hints........................................................................................ 638 11.4.4 Automatisches SQL-Tuning...................................................... 649 11.5 Ältere Features ..................................................................................... 659 11.5.1 Regelbasierter Optimizer.......................................................... 659 11.5.2 Optimizer-Statistiken mittels ANALYZE..................................... 659 11.5.3 Diverse Optimizer-Hints ........................................................... 659 11.5.4 Oracle-Trace ............................................................................ 659 11.5.5 Erweitertes SQL-Tracing........................................................... 660 12 Troubleshooting ............................................................................................ 661 12.1 Einführung ........................................................................................... 661 12.2 Informationsquellen und Anwendungskontext ..................................... 661 12.3 Die Strategien ...................................................................................... 665 12.4 Werkzeuge und Fehlersituationen......................................................... 666 12.4.1 Log- und Trace-Dateien ........................................................... 667 12.4.2 Statistiken, Metriken, servergenerierte Alerts ............................ 676 12.4.3 Programmatische Möglichkeiten.............................................. 685 12.4.4 Validieren von Blöcken............................................................. 688 12.4.5 Feature-Nutzung und Hochwassermarken ............................... 694 12.4.6 Die Arbeit mit Events ............................................................... 694
12
Inhaltsverzeichnis
13 Hochverfügbarkeit ......................................................................................... 709 13.1 Einleitung............................................................................................. 709 13.2 Hardware-Architekturen ....................................................................... 710 13.2.1 Speicher .................................................................................. 710 13.2.2 Server ...................................................................................... 712 13.2.3 Infrastruktur............................................................................. 713 13.3 Oracle Real Application Clusters ........................................................... 713 13.3.1 Architektur............................................................................... 714 13.3.2 Lage der Datendateien ............................................................ 717 13.3.3 Software-Installation ................................................................ 718 13.3.4 Konfiguration einer RAC-Datenbank ........................................ 724 13.3.5 Oracle Net-Konfiguration......................................................... 728 13.4 Oracle Data Guard ............................................................................... 730 13.4.1 Physical-Standby-Datenbank.................................................... 732 13.4.2 Logical Standby ....................................................................... 742 13.4.3 Data Guard Broker................................................................... 751 13.5 Replikation ........................................................................................... 756 13.5.1 Replikationsarten ..................................................................... 757 13.5.2 Advanced Replication .............................................................. 759 13.5.3 Oracle Streams ........................................................................ 785 13.5.4 Shareplex ................................................................................ 800 14 Monitoring/Reorganisation........................................................................... 807 14.1 Was wird beobachtet?.......................................................................... 807 14.1.1 Platzbedarf .............................................................................. 807 14.1.2 Grenzen................................................................................... 808 14.1.3 Tuningparameter..................................................................... 808 14.2 Wie wird beobachtet? .......................................................................... 808 14.2.1 Alert-Datei ............................................................................... 809 14.2.2 Tablespace und Datendatei...................................................... 811 14.2.3 Extents .................................................................................... 812 14.2.4 Filesystem ................................................................................ 814 14.2.5 Unvorhergesehene Engpässe ................................................... 815 14.2.6 Online-Monitoring................................................................... 816 14.3 Reorganisieren ..................................................................................... 819 14.3.1 Warum reorganisieren?............................................................ 819 14.3.2 Wie wird reorganisiert? ............................................................ 820 14.3.3 Womit wird reorganisiert? ....................................................... 822 14.3.4 CREATE TABLE ... AS SELECT ... (CTAS) .................................... 824 14.3.5 COPY Table ............................................................................. 826 14.3.6 REBUILD INDEX ....................................................................... 826
Inhaltsverzeichnis
13
14.3.7 Move Tablespace..................................................................... 827 14.3.8 Shrink Space............................................................................ 828 14.3.9 Online-Table-Reorganisation.................................................... 829 14.3.10 Oracle Enterprise-Manager-Reorganisationen........................... 831 15 Data Warehousing ......................................................................................... 835 15.1 Extraktion, Transformation, Laden........................................................ 836 15.1.1 Transportable Tablespaces ....................................................... 837 15.1.2 Parallelisierung........................................................................ 842 15.1.3 Komplexe Laderoutinen.......................................................... 844 15.1.4 Laden aus Non-Oracle-Datenbanken ....................................... 847 15.1.5 Überwachung der Ladeoperation............................................. 850 15.2 Datenbankdesign für Data Warehouses ................................................ 852 15.2.1 Hardware-Architekturen.......................................................... 853 15.2.2 Tablespace-Layout ................................................................... 857 15.2.3 Partitionierung........................................................................ 859 15.2.4 Indizierung ............................................................................. 865 15.2.5 Konsolidierung und Verdichtung ............................................ 868 15.2.6 Aggregationsfunktionen .......................................................... 877 15.3 Darstellung .......................................................................................... 880 15.3.1 Dimensionen ........................................................................... 881 15.3.2 Parallele Abfragen.................................................................... 883 Stichwortverzeichnis...................................................................................... 885
Einführung 1.1
Allgemeines
Das relationale Datenbankmanagementsystem (RDBMS) Oracle Database 10g ist ein kommerzielles Produkt, das auf Basis von theoretischen Grundlagen implementiert wurde. Als Standardprodukt basiert die Datenbank auf der Datenbanksprache SQL (steht für Structured Query Language, »SEQUEL« gesprochen1). Es erfüllt in weiten Teilen die Bedingungen an Core SQL:2003, den Pflichtteil des SQL:2003-Standards, der 2003 sowohl von der ANSI- als auch von den ISO/IEC-Organisationen verabschiedet wurde. Neben den Standardelementen enthält Oracle SQL eine Reihe von Erweiterungen. Genaue Angaben zur Standardkonformität finden sich im Anhang B der Dokumentation Oracle 10g SQL Reference. 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 sei die theoretische Grundlage für relationale Systeme genannt, E.F. Codd: A Relational Model of Data for Large Data Banks, Communications 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 als zusätzliche CD sowohl im HTML- als auch im PDF-Format mit zur Softwarelieferung gehören.
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 1
Man erkennt an dieser Wortwahl, dass die Abfrage (engl. Query) im Vordergrund steht, dennoch sind natürlich auch Datenmanipulationen (DML) möglich.
16
Einführung
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 Folge-Release von Oracle mit Oracle8i bezeichnet; die Release-Nummer 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 seit Oracle9i schlicht Oracle Net. Mit Version 10g wurde dann ein weiterer Paradigmenwechsel eingeleitet. Das »g« steht für Grid-Control. Unter diesem heute von Hard- und Softwarefirmen verwendeten Begriff versteht man die Verknüpfung unterschiedlicher Ressourcen für eine gemeinsame Aufgabe. Für Oracle ist dies im Wesentlichen die Weiterentwicklung der Oracle Parallel Server (OPS) bzw. Real-Application-Clusters(RAC)-Architektur zu einem Verbund an Rechnern. Dafür wurden bereits in der Version 9i die Grundlagen durch eine eigene Cluster-Software gelegt, die mit Version 10g jetzt auch eine eigene Filesystem-Implementierung (ASM, Automatic Space Management) umfasst. Leider ist es derzeit noch nicht möglich, Hardware mit unterschiedlichen Betriebssystemen zu verknüpfen, aber weitere Releases werden dieser Möglichkeit sicher ein Stück näher kommen. 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: Verbunden mit: Oracle Database 10g Enterprise Edition Release 10.1.0.4.0 - Production
Normalerweise bezeichnet die dritte Stelle der Versionsnummer das MaintenanceRelease, das nicht mit neuen Funktionen aufwartet, höchstens mit kleineren Schnittstellenänderungen im Rahmen von Fehlerkorrekturen oder PerformanceVerbesserungen. Für Oracle9i und Oracle 10g gilt wieder die alte Logik, d.h., Oracle 10g steht für Version 10.1; das als Nächstes erscheinende Oracle 10g Release 2 für Version 10.2. 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. 10.1.0.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 10.1.0.4.1 für MS-Windows. Damit Oracle-Administratoren 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 10.1.0 gibt es SQL*Plus Version 10.1.0, Oracle Net Version 10.1.0 usw.
Oracle-Komponenten
1.2
17
Oracle-Komponenten
Oracle Database 10g gibt es in vier unterschiedlichen Editionen, die teilweise über zusätzliche Optionen erweitert werden können. Oracle Database 10g Personal Edition (PE) ist eine spezielle Einplatzlösung mit allen Funktionen der Oracle Database 10g Enterprise Edition inklusive der Optionen mit Ausnahme des Real Application Clusters. Oracle Database 10g Standard Edition One ist eine spezielle Lizenz für den Einsatz auf Rechnern mit einer maximalen Kapazität von zwei Prozessoren. Der Funktionsumfang ist identisch mit der Oracle Database 10g Standard Edition bis auf die Möglichkeit, Real Application Clusters zu nutzen. Oracle Database 10g Standard Edition (SE) ist eine erweiterte Lizenz für den Einsatz auf Systemen mit einer maximalen Kapazität von vier Prozessoren, die entweder in einem System oder verteilt auf bis zu vier Knoten in einer RealApplication-Clusters-Umgebung eingesetzt werden können. Oracle Database 10g Enterprise Edition (EE) enthält alle möglichen Funktionen des Oracle-Datenbank-Kerns und ist über zusätzliche Optionen (z.B. Partitioning) erweiterbar. Auch wenn es einige Dokumente gibt, die etwas anderes behaupten, so ist die Standard Edition bzw. Standard Edition One in der Anzahl der Benutzer oder der Größe der Datenbank nicht beschränkt. Wenn Sie also mit der Funktionalität und der Anzahl der Prozessoren auskommen, sollten Sie sich überlegen, ob SE für Sie nicht ausreichend ist. Interessant ist auch, dass die Personal Edition von ihrem Funktionsumfang mit der Enterprise Edition identisch ist, so dass es möglich ist, auf einem Arbeitsplatz-PC eine PE für die Anwendungsentwicklung zu installieren, die anschließend in einer EE zum Einsatz kommt.
1.2.1 Funktionsumfang Die folgende Tabelle listet den Funktionsumfang der Standard Edition gegenüber der Enterprise Edition auf. Die Standard Edition One ist hierbei identisch mit der Standard Edition, die Personal mit der Enterprise Edition. Funktion
Standard Edition
Enterprise Edition
Oracle Data Guard (physical und logical)
NEIN
JA
Online Reorganisation (dbms_redefinition)
NEIN
JA
Flashback Query
JA
JA
Flashback Table, Database, Transaction Query
NEIN
JA
Block-Level Media Recovery
NEIN
JA
Incremental Backup und Recovery
JA
JA
Point-in-Time Tablespace Recovery
NEIN
JA
18
Einführung
Funktion
Standard Edition
Enterprise Edition
Transportable Tablespaces
NEIN
JA
Trial Recovery
NEIN
JA
JA
JA
JA
JA
Oracle Failsafe
a
Oracle Real Application Clustersb Automatic Workload Management
JA
JA
Advanced Security*)
NEIN
JA
Oracle Label Security*)
NEIN
JA
Encryption Toolkit
JA
JA
Virtual Private Database
NEIN
JA
Fine grained Auditing
NEIN
JA
Reguläre Ausdrücke
JA
JA
VLM und 64-Bit-Support für Windows
JA
JA
Oracle Change Management Pack*)
NEIN
JA
Oracle Configuration Management Pack*)
NEIN
JA
Oracle Diagnostic Pack*)
NEIN
JA
Oracle Tuning Pack*)
NEIN
JA
Enterprise Manager Database Control
JA
JA
Automatic Memory Management
JA
JA
Automatic Storage Management
JA
JA
Legato Storage Manager
JA
JA
Duplex Backup Sets
NEIN
JA
Database Resource Manager
NEIN
JA
Oracle Partitioning*)
NEIN
JA
Oracle OLAP*)
NEIN
JA
Oracle Data Mining*)
NEIN
JA
Data Compression
NEIN
JA
Analytische Funktionen
JA
JA
Bitmapped Index und Bitmapped Join Index
NEIN
JA
Function-Based Index
JA
JA
Parallelisierungen
NEIN
JA
Materialized View Query Rewrite
NEIN
JA
Externe Tabellen
JA
JA
Oracle Streams
NEIN
JA
Oracle-Komponenten
19
Funktion
Standard Edition
Enterprise Edition
Advanced Queuing
JA
JA
Messaging Gateway
NEIN
JA
Basic Replication
c
Advanced Replication
JA
JA
NEIN
JA
Distributed Queries and Transactions
JA
JA
Heterogeneous Services
JA
JA
Oracle Connection Manager
NEIN
JA
Oracle Names
JA
JA
Infiniband Support
NEIN
JA
Oracle Spatial*)
NEIN
JA
Oracle Database Workspace Manager
JA
JA
Ultra Search
JA
JA
interMedia
JA
JA
Oracle Text
JA
JA
Index-organized Tables
JA
JA
LogMiner
JA
JA
Multiple Block Size Support
JA
JA
Temporary Tables
JA
JA
a. b. c. *)
nur MS-Windows Nicht für Standard Edition One und Personal Edition, bei der Enterprise Edition kostenpflichtige Option Nur Updatable Materialized View Diese Optionen sind kostenpflichtig in der Enterprise Edition verfügbar.
Diese Liste deckt nur einen Teil der Funktionen ab, kann aber in vielen Fällen als Hinweis dienen, ob sich der Kauf der erheblich teureren Enterprise Edition rentiert. In unseren Projekten hat sich herausgestellt, dass speziell die Data-Guard-Funktionalität, die Bitmapped Indexes, Transportable Tablespaces sowie die Advanced Replication den Ausschlag für den Einsatz der Enterprise Edition gegeben haben. Da diese Liste einer permanenten Anpassung unterzogen wird, bitten wir Sie, im Bedarfsfall auf die Oracle Homepage zu gehen und dort nach »Product Family« zu suchen. Leider ist die Dokumentation nicht immer eindeutig. Es gibt ein Dokument Oracle Database 10g Product Family, das als Grundlage für die Tabelle diente und aus der hervorgeht, dass analytische Funktionen mit der SE möglich sind, laut aktuellem Overview auf der Oracle Homepage sind diese jedoch scheinbar nicht möglich.
20
Einführung
1.2.2 Optionen Wie bereits erwähnt, gibt es für die Enterprise Edition eine Reihe von Optionen, die teilweise auch in diesem Buch besprochen werden. Dazu gehören: Oracle Real Application Clusters (RAC): Diese Option ermöglicht den Aufbau eines Rechnerverbundes mit einer zentralen Datenbank. Sie bildet bei Oracle die Basis für das Grid-Computing. Nähere Informationen dazu finden Sie in Kapitel 13. Oracle Partitioning: Damit können Tabellen und Indizes aufgeteilt werden, ohne dass die Anwendung hiervon etwas mitbekommt. Durch Partitionen können große Objekte einfacher verwaltet werden. Außerdem kann der Zugriff optimiert werden. Wir gehen auf die Möglichkeiten der Partitionierung in den Kapiteln 5 und 15 näher ein. Oracle Advanced Security: Hiermit können die Möglichkeiten der Verschlüsselung von Daten im Netzwerk und in der Datenbank erweitert werden. Dazu gehört z.B. ein Single-Sign-One über Kerberos oder Radius-Server. Oracle Label Security: Hierbei handelt es sich um die Funktion, die früher als Trusted Oracle bekannt war. Es ist damit möglich, eine sehr fein granulare Zugriffssteuerung zu erreichen. Nähere Informationen dazu bekommen Sie in Kapitel 9. Oracle OLAP: Diese Kernel-Erweiterung ist die Fortführung der von Oracle Ende der Neunzigerjahre gekauften Datenbank Express der Firma IRI. Damit ist es möglich, in der Oracle-Datenbank multidimensionale Analysen durchzuführen. Oracle Data Mining: Diese Option erlaubt über eine Java API den Aufbau einer Datenbank speziell für den Bereich Data Mining. Oracle Spatial: Mit dieser Option kann die Datenbank um Funktionen für die Speicherung von geokodierten Daten erweitert werden. Weitere Optionen gibt es für die Erweiterung des Oracle Enterprise Managers Grid Controls: Oracle Change Managment Pack: Hiermit können über den Enterprise Manager Strukturänderungen verwaltet bzw. synchronisiert werden. Darüber hinaus können komplette Schemata kopiert und als Skript abgelegt werden. Oracle Diagnostic Pack: Dieses Paket bietet als wesentliches Werkzeug eine grafische Unterstützung des Automatic Database Diagnostic Monitors (ADDM). Außerdem gibt es Monitoring Tools und eine event-basierte Überwachung. Oracle Tuning Pack: Über den SQL Access Advisor und SQL Tuning Advisor können hiermit SQL-Befehle einfach optimiert werden. Das Tool Reorganize Objects bietet außerdem eine Schnittstelle für die Online-Reorganisation von Tabellen und Indizes.
Oracle-Komponenten
21
Oracle Configuration Managment Pack: Während es die anderen drei Pakete schon in der Version 8 und folgende gab, ist dieses Paket in Oracle 10g neu hinzugekommen. Oracle empfiehlt den Einsatz dieses Paketes auch deshalb, weil es dadurch möglich ist, Patches automatisch einzuspielen. Ein direkter Link zum Oracle Metalink ermöglicht dies. Außerdem kann eine Oracle-Installation komplett kopiert (Cloning) und Konfigurationen können verglichen werden. Mit einigen dieser Funktionen haben wir uns im Buch näher beschäftigt, da sie häufiger in Projekten zum Einsatz kommen. Andere Funktionen (wie z.B. die Spatial Option) haben einen derart spezialisierten Anwendungskontext, dass wir nicht näher darauf eingehen.
1.2.3 Weitere Produkte In der folgende Auflistung werden einige Produkte erwähnt, die im Umfeld der Oracle Database 10g eine Rolle spielen: Oracle Database Lite: Diese Datenbank ist speziell für den Einsatz auf mobilen Systemen mit wenig Hauptspeicher und Plattenkapazität (z.B. PDA, Windows Mobile) entwickelt worden. Da sie eine eigene Architektur hat, die von der »Standard«-Datenbank abweicht, werden wir sie nicht weiter betrachten. Hervorzuheben ist, dass es umfangreiche Funktionen für den Abgleich von Oracle Database Lite mit der Oracle Database 10g gibt. HTML DB: Hierbei handelt es sich nicht, wie eventuell vermutet, um eine Datenbank, sondern um die Möglichkeit, über einen Webbrowser schnell und bequem Datenbankanwendungen zu schreiben. Sie ist in allen Oracle Database 10g-Editionen enthalten, und auf der Oracle Homepage gibt es eine Vielzahl von Dokumenten für den Einsatz von HTML DB. Oracle Application Server 10g: Sie bildet die Basis für internetbasierende Anwendungen im Oracle-Kontext. Als Middleware wird sie z.B. für den Aufbau von LDAP-Servern (siehe Kapitel 9) oder für den Oracle Developer verwendet. Oracle Collaboration Suite 10g: Hierbei handelt es sich um eine fertige Software für die Informationssammlung bzw. die Kommunikation in Unternehmen. Als Konkurrenzprodukt zu Microsoft Exchange bilden die Oracle Database 10g und der Oracle Application Server 10g die Basis, auf dem dann E-Mails und Terminplanung, aber auch eine eigene Dateiverwaltung implementiert sind. Sicherlich gibt es eine ganze Reihe weitere Produkte, die im Umfeld der OracleDatenbank zum Einsatz kommen. Ihnen allen ist aber gemein, dass die zugrunde liegende Datenbank eine Oracle Database 10g ist.
22
1.3
Einführung
Datenbank-Paradigmen
1.3.1 Das Transaktionsverhalten Hinter dem Begriff Transaktionsverhalten verbirgt sich eine Reihe von 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. 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. 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 (Data Manipulaton Language)- und DDL(Data Definition Language)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 sich diese 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.
Datenbank-Paradigmen
23
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. 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- (der Satz wird exklusiv gesperrt) oder Share-Modus haben (der Satz wird zwar gesperrt, aber nicht exklusiv, d.h., weitere Share-Sperren sind möglich). 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-DML-Sperre auf der gleichen Tabelle. Kompatible Sperren können gleichzeitig von verschiedenen Sitzungen gehalten werden; inkompatible Sperren führen zu Wartezuständen. Übersetzt in Befehle heißt das z.B., dass ein CREATE INDEX-Befehl, der eine ShareModus-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 SQL> ALTER INDEX
REBUILD ...
ab Oracle8i die Option ONLINE, mit deren Hilfe man einen Index auch bei laufenden Anwendungen neu aufbauen 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 INDEX- oder 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.
24
Einführung
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: SQL> LOCK TABLE IN EXCLUSIVE MODE;
Oft lassen sich Laufzeiten hiermit um etwa die Hälfte (!) reduzieren. 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 TABLE-Befehlen explizit angefordert werden. Deadlocks Mit einem Deadlock ist eine Situation bezeichnet, 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. Tabelle 1.1: Deadlock
Datenbank-Paradigmen
Sitzung 1
25
Sitzung 2
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.1: Deadlock (Forts.)
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. 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 Ä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,
26
Einführung
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. Praxisrelevant ist außerdem der Isolation Level Read Only. Dieser setzt wie Serializable den Lesekonsistenzzeitpunkt auf den Beginn der Transaktion, erlaubt jedoch keine eigenen DML-Kommandos, sondern ausschließlich SELECT-Befehle. Hiermit können z.B. in sich konsistente Berichte bei gleichzeitig laufenden Transaktionen erzeugt werden. Mit der Einführung der Flashback-Technologie ist es über die Flashback-Query außerdem möglich, über den Zusatz AS OF TIMESTAMP … den Zeitpunkt für die Selektion der Daten zu bestimmen.
1.4
Aufgaben eines DBA
Welches Aufgabenspektrum sich hinter der Bezeichnung Datenbankadministration verbirgt, ist pauschal nicht so einfach zu beantworten und erfahrungsgemäß auch nicht unumstritten. Wir möchten daher an dieser Stelle aus unseren Erfahrungen heraus Antworten und Empfehlungen auf einige zentrale Fragen geben: Was sollten die zentralen Aufgaben eines DBA sein (das Kerngebiet)? Wo müssen Interdependenzen mit anderen Teilen der IT-Infrastruktur (Storage, Netzwerk, Betriebssystem, kaufmännischer Bereich etc.) berücksichtigt werden? In welchen Bereichen sollte der DBA unterstützend bzw. für strategische Entscheidungen beratend arbeiten? Welche Aufgaben sollten nicht beim DBA angesiedelt sein, sind es aber in der Praxis? Wo sind Kompetenzüberschneidungen mit anderen IT-Abteilungen zu erwarten?
Aufgaben eines DBA
27
1.4.1 Kerngebiete der DB-Administration Dazu gehören sicherlich die folgenden Themen, die eindeutig in die Kompetenz des DBA fallen, da sie zentrale Datenbankressourcen betreffen bzw. schema-übergreifende und anwendungsunabhängige Auswirkungen haben. Installation von Oracle-Software und -Datenbanken. Vorher muss geklärt werden, welche Anforderungen bzgl. Datenbankfunktionen seitens der Benutzer bzw. Anwendungen bestehen und ob entsprechende Lizenzen zur Verfügung stehen. Sicherung der Datenbanken. Bei der Sicherung existiert ein breites Spektrum von Varianten, wie dieses Thema technisch umgesetzt wird. Auf der einen Seite kann bei wenigen, kleinen Datenbanken das Thema vollständig beim DBA angesiedelt sein. Dagegen existieren gerade bei größeren Datenbanken oder umfangreichen DB-Landschaften starke Abhängigkeiten zum Storage-Bereich, wo mit Technologien wie z.B. EMC2 BCVs das Splitting einzelner Disk-Gruppen und das Abziehen der BCVs auf Band geleistet wird. Die Koordinierung der Backup-Jobkette geschieht häufig über Scheduler wie bspw. Maestro. Im Extremfall beschränkt sich die Arbeit des DBA auf das Scripting einzelner Schritte der Job-Kette. Rücksicherung/Wiederherstellung einer Datenbank. Diese Arbeit lässt sich viel weniger automatisieren als das Backup, da zahlreiche Szenarien mit sehr unterschiedlichen, sich zum Teil überschneidenden Lösungswegen denkbar sind. Eine genaue Situationsanalyse (Sichtung des Alert-Logs und sonstiger Trace-Dateien) mit spezifischem Datenbank-Know-how ist nötig, bevor eine Entscheidung für eine bestimmte Wiederherstellungsprozedur gefällt werden kann. Sind Plattensysteme beeinträchtigt, ist ggf. wiederum eine Abstimmung mit dem StorageBereich angesagt, ebenso für die Rücksicherung einzelner Komponenten. Monitoring der Datenbanken. Abhängig von der Art auftretender Probleme ist eine Lösung entweder selbsttätig möglich (z.B. Hinzufügen einer Datendatei), oder es ist eine Abstimmung mit anderen Beteiligten notwendig. Damit – vor allem im ersten Fall – nach außen hin nicht der unzutreffende Eindruck entsteht, die Datenbank sei ein Selbstläufer (typische Frage: »Was macht eigentlich unser DBA?«), sollte Monitoring immer auch mit einem Reporting, also der Erstellung regelmäßiger Berichte (wöchentlich oder monatlich) über das Verhalten der Datenbank sowie aufgetretene und gelöste Probleme verbunden sein (»Health Checks«). Einspielen von Updates und Patches: Bei 24x7-Systemen ist hier eine Abstimmung über eine mögliche Auszeit notwendig. Wichtig ist, solche Operationen vorher einmal möglichst realitätsnah durchzuspielen, um auftretende Probleme zu erkennen und eine zeitliche Abschätzung geben zu können. In manchen Fällen wird von einer Anwendung nur ein bestimmter Oracle-Patch-Level (z.B. 10.1.0.4) unterstützt, höhere Patch-Level dagegen werden (noch) nicht offiziell unterstützt.
28
Einführung
Troubleshooting: Auftretende Probleme verlangen zum einen spezifisches Datenbank-Know-how, zum anderen auch die Fähigkeit einzuschätzen, ob das Problem datenbankseitig zu lösen ist oder eher Ursachen im Storage- oder Netzwerkbereich hat. Entsprechende Informationen (Performance-Statistiken) finden sich in V$-Statistiken und deren archivierten Varianten, den dba_hist%Tabellen (bspw. schlechte I/O-Zeiten für einzelne Datendateien oder unrealistisch hohe CPU-Zeiten, die auf ein Paging seitens des Betriebssystems hinweisen). An dieser Stelle kann es immer wieder zu Problemen kommen, wenn die Oracle-seitigen Statistiken von anderen IT-Beteiligten nicht anerkannt werden und auf diese Weise Pingpong mit den Verantwortlichkeiten gespielt wird. Regelmäßige Performance-Berichte (»Health Checks«) können auch hier eine große Hilfe darstellen, da sie allmähliche oder plötzliche Veränderungen gut dokumentieren. Grundlegendes Tuning der Datenbank: Hier geht es nicht um SQL-Tuning oder das Anlegen von Indizes, sondern um datenbankweite Maßnahmen wie Instanz-Parametrierung oder die Analyse von Trefferquoten. Globale Sicherheitsaspekte, z.B. Auditing, also das Überwachen bestimmter Aktionen wie An- und Abmeldungen, die Verschlüsselung der Oracle Net-Kommunikation (nicht jedoch die Verschlüsselung von Daten, das ist Aufgabe der Anwendungen) sowie Zugriffsrechte auf Datenbankdateien, die PasswortVerwaltung für Administrator-Accounts, Instanz-Parametrierung etc.
1.4.2 Bereiche mit DBA-Unterstützung In einigen Bereichen sollte der DBA unterstützend bzw. in Abstimmung mit anderen Gruppen arbeiten, insbesondere: bei strategischen Entscheidungen für oder gegen bestimmte Tools, Programme, und Technologien. Hierfür ist neben monetären Aspekten vor allem eine Einschätzung über die Praxistauglichkeit einer Technologie und über ihre Verträglichkeit mit anderen bereits eingesetzten Technologien notwendig. Dies erfordert in den allermeisten Fällen tief gehendes Know-how und Erfahrungswerte. Natürlich fallen solche Fragen nicht vom Himmel, sondern ergeben sich aus den Anforderungen von Entwicklern und Anwendungen bzw. aus Service-Level-Agreements (z.B. Hochverfügbarkeit durch Cluster- und Replikationslösungen oder RAC). Hier wirkt der DBA gewissermaßen als Dienstleister, der ein bestimmtes Technologie-Portfolio bereitstellt. Der DBA sollte auch mit der Lizenzpolitik und den lizenztechnischen Einzelheiten von Oracle vertraut sein, um kaufmännische Entscheidungen bzgl. Erwerb, Aufstockung oder Konsolidierung von Lizenzen zu unterstützen.
Aufgaben eines DBA
29
1.4.3 Aufgaben, die nicht beim DBA angesiedelt sein sollten Benutzer-, Rollen- und Rechteverwaltung für Anwendungen: Obwohl dies häufig als eine der typischen DBA-Tätigkeiten angesehen wird, möchten wir dieser Auffassung hier widersprechen. Der DBA hat in den meisten Fällen keine Sachkompetenz im Hinblick auf Privilegien. Er kann nicht entscheiden, ob ein bestimmter Anwender das Recht haben darf, bestimmte Tätigkeiten im Rahmen einer Applikation auszuführen. Da die technische Durchführung einer Rechtevergabe unproblematisch ist, stellt sich die Frage, warum der DBA überhaupt mit dem ganzen Thema berührt werden sollte. Sinnvoller erscheint uns folgende Aufgabenteilung: Alle Rechte, die von einer Anwendung und deren Benutzer benötigt werden, werden von den Entwicklern in geeigneten Rollen zusammengestellt. Die Standardbenutzer einer Anwendung (Eigentümer der Objekte, Staging-Benutzer usw.) werden ebenfalls durch die Anwendungsentwicklung vorgegeben und mit Rechten versehen. Das Anlegen und die Rechteausstattung sonstiger Anwender kann technisch in PL/SQL-Prozeduren ausgelagert werden, die bereits entsprechende Plausibilitätsprüfungen enthalten. Diese Prozeduren werden vom DBA bereitgestellt, Ausführungsrechte werden an spezielle Anwendungsadministratoren gegeben, die eine Schnittstelle bilden zwischen den Entwicklern und dem DBA. Diese können somit im Rahmen der Plausibilitäten autonom entscheiden, wer welche Rechte für die Anwendung erhält. Unterstützung bei der Anwendungsentwicklung: Auch wenn ein DBA sicherlich gute Tipps bspw. im Hinblick auf Performance-Aspekte bei der Entwicklung (Anlegen geeigneter Indizes, Schreiben von effizientem SQL) geben kann, ist es schon aus Zeitgründen i.A. nicht möglich, dies regelmäßig zu tun. Es sollte vielmehr Aufgabe der bereits genannten Anwendungsadministratoren sein, die Entwickler zu betreuen und für diese eine Schnittstelle zum DBA zu bilden. Anwendungs-Tuning: Die Argumente des letzten Punkts können hier analog wiederholt werden. Es kommt noch hinzu, dass ein Großteil des AnwendungsTunings aus dem Überarbeiten von SQL-Kommandos sowie dem Abschätzen von Datenmengen und Datenverteilungen besteht. Dies setzt ein genaues fachliches Verständnis der Anwendungsobjekte und SQL-Befehle voraus (»Was soll diese Abfrage eigentlich liefern?«), daher ist hier Teamarbeit zwischen den Entwicklern und den Anwendungsadministratoren notwendig. Neue Software-Releases: Auch hier gilt dieselbe Argumentation: Natürlich ist vor dem Einspielen eines neuen Software-Release eine Abstimmung zwischen Anwendungsadministrator und DBA erforderlich, eine tiefer gehende Beschäftigung mit den technischen Eigenheiten des neuen Release sollte aber nicht notwendig sein. Allerdings liegt es im Aufgabenbereich eines Administrators, sich bezüglich der Oracle-Releases auf dem Laufenden zu halten. Naturgemäß lassen sich nicht alle Situationen in die oben genannten Schubladen einordnen, speziell in kleineren Unternehmen gibt es immer wieder Überschneidungen zwischen Entwicklung und Administration, aber auch in großen Unternehmen sollten Administratoren gleichberechtigt beim Aufbau neuer Anwendungen beteiligt sein.
Installation und Aufbau einer Datenbank In diesem Kapitel wollen wir Ihnen zeigen, wie Sie eine Datenbank schnell und einfach aufbauen können, die in vielen Fällen ausreichend für den Betrieb einer produktiven Anwendung ist. Oracle verfolgt mit der Version 10g den Ansatz, die Installation und Konfiguration einer Standarddatenbank möglichst unkompliziert zu machen, d.h., ohne die diversen Optionen, Parameter und Spezialfälle zu betrachten. Das wird schon dadurch ersichtlich, dass für die Software nur eine CD benötigt wird. Nach deren Einlegen wird wie bei Windows-Systemen üblich das Setup aufgerufen, durch das der Universal Installer gestartet wird. Auf dem Eingangsbildschirm können dann alle erforderlichen Parameter eingegeben werden, um damit eine so genannte Basisinstallation durchzuführen. Diese Installationsart werden wir in Kapitel 2.1 als Erstes betrachten. Im Weiteren werden wir dann auf einige alternative Konfigurationsmöglichkeiten eingehen. Bevor wir aber mit der Installation starten, sollen zum besseren Verständnis einige Variablen geklärt werden: ORACLE_BASE: Dieser Parameter kennzeichnet das Basisverzeichnis für alle Installationen. Wenn dieser Parameter gesetzt wird, werden die Komponenten Software, Datenbank und administrative Dateien automatisch voneinander getrennt (z.B. D:\oracle). Näheres hierzu finden Sie im Kapitel 2.3 (Software Installation). ORACLE_HOME: Dieser Parameter ist der wichtigste für alle Oracle-Datenbanken. Zunächst gibt er bei der Installation an, in welches Verzeichnis die Software installiert werden soll (z.B. D:\oracle\product\10.1.0\db). Nach der Installation befindet sich im Unterverzeichnis bin der Oracle-Kernel, so dass hierüber während des normalen Betriebs angegeben wird, mit welchem Kernel diese Datenbank arbeitet. ORACLE_SID: Dieser Parameter kennzeichnet den Namen der Datenbankinstanz und damit in den meisten Fällen zunächst den Namen der Datenbank. Bei einer neuen Installation über Easy Installation oder den Database Configuration Assistant wird diese Variable mit dem Datenbanknamen gefüllt. Der hier verwendete Name darf allerdings nicht länger als acht Zeichen sein. ORACLE_HOME_NAME: Außerdem erhält jede Oracle-Installation einen eigenen logischen Namen, über die z.B. unter MS-Windows die Dienste identifiziert werden können. (z.B. Ora10g_home1). In der MS-Windows Registry finden Sie unter dem Eintrag HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE das Unterverzeichnis KEY_%ORACLE_ HOME_NAME% mit allen wichtigen Parametern dieser Installation.
32
Installation und Aufbau einer Datenbank
Sie sollten immer darauf achten, wie diese Parameter gesetzt sind. Beispiel Unix: ORACLE_BASE=/app/oracle ORACLE_HOME=$ORACLE_BASE/product/10.1.0/db_1 ORACLE_SID=SUN10G
Beispiel MS-Windows set ORACLE_BASE=D:\oracle set ORACLE_HOME=%ORACLE_BASE%\product\10.1.0\db_1 set ORACLE_SID=WIN10G
2.1
Basisinstallation
Das folgende Bild erscheint, wenn Sie den SETUP-Befehl auf der CD ausführen oder unter Unix den Befehl runInstaller im Basisverzeichnis der CD aufrufen.
Abbildung 2.1: Basisinstallation
Der erste Bereich kennzeichnet die Basisinstallation – auch Easy Installation genannt, in der Sie die zu installierende Version und den Speicherort auswählen. Im Gegensatz zu früheren Versionen wird als Speicherort ein weiteres Unterverzeichnis (hier Db_1) angelegt. Der Grund hierfür ist unter anderem, dass der Enterprise Manager Grid Control ein eigenes ORACLE_HOME braucht. In einigen Fällen kann es außerdem sinnvoll sein, je Produktionsdatenbank eine eigene Software zu installieren, da dadurch im Falle eines Release-Wechsels oder dem Einspielen eines Patches alle Datenbanken einzeln migriert werden können. Natürlich sind auch
Basisinstallation
33
andere Verzeichnisstrukturen möglich, Sie sollten aber immer bedenken, dass diese Struktur ein Höchstmaß an Flexibilität gewährleistet. Das gewählte Verzeichnis sollte leer sein (Unterverzeichnis Lost+Found bei Unix-Filesystemen ist natürlich erlaubt). Bei den verwendeten Versionen können Sie wählen zwischen Personal, Standard und Enterprise Edition. Diese sollte Ihrer tatsächlich lizenzierten Version entsprechen. Nähere Informationen erhalten Sie im Kapitel 2.2. Als Nächstes haben Sie die Möglichkeit, eine Datenbank direkt mit anzulegen. Dabei müssen Sie dann den Datenbanknamen sowie das Kennwort der wichtigsten Datenbank-Schemata (SYS, SYSTEM, SYSMAN und DBSNMP) angeben. Bekannte Kennwörter wie z.B. MANAGER, CHANGE_ON_INSTALL, SYSMAN oder DBSNMP werden abgelehnt. Außerdem ist es nicht möglich, unterschiedliche Kennwörter zu vergeben, später können Sie das natürlich nachholen. Nachdem Sie diese Informationen eingegeben haben, bekommen Sie nochmals eine Übersicht über die ausgewählten Komponenten, bevor dann mit der Installation begonnen wird. Bei MS-Windows-Systemen wird nach einiger Zeit folgende Fehlermeldung erscheinen:
Abbildung 2.2: OCR-Fehlermeldung
An dieser Stelle müssen Sie ein DOS-Fenster öffnen und eine Änderung vornehmen. Gehen Sie dafür in das ORACLE_HOME\bin–Verzeichnis, und führen Sie folgende Befehle aus: > clscfg –local –o %ORACLE_HOME% -l > net start oraclecsservice
Danach sollte der Oracle Cluster Synchronization Service gestartet sein, und Sie können mit der Installation fortfahren. Wenn Sie keine ASM-Instanzen benötigen (siehe Kapitel 2.4), können Sie die Fehlermeldung einfach ignorieren. Zum Schluss erhalten Sie dann die Meldung, dass die Datenbank erfolgreich angelegt worden ist. Hier haben Sie dann nochmals die Möglichkeit, die Kennwörter der Administrationsschemata zu ändern. Sie können jetzt mit verschiedenen Werkzeugen als J2EE-Anwendungen auf die Datenbank zugreifen. Die Liste der verfügbaren Werkzeuge mit den entsprechenden TCP-Ports erhalten Sie auf der letzten Seite der Installation.
34
Installation und Aufbau einer Datenbank
Abbildung 2.3: J2EE-Anwendungen
Diese Liste finden Sie nochmals im Verzeichnis %ORACLE_HOME%/install in der Datei portlist.ini. Diese Installation dauert unter MS-Windows ca. eine Stunde, und danach haben Sie eine voll funktionsfähige Oracle-Datenbank. Natürlich ist es später jederzeit möglich, bestimmte Parameter zu ändern; alternativ können Sie aber auch direkt zur benutzerdefinierten Installation wechseln, die wir im Folgenden besprechen.
2.2
Installationsplanung
Nachdem wir in Kapitel 2.1 eine Basisinstallation besprochen haben, wenden wir uns jetzt einer komplexeren Installation zu, in der alle Komponenten und Optionen wählbar sind. Diese Art der Installation findet man in allen größeren Unternehmen, bei denen Hochverfügbarkeit (z.B. Trennung von Software und Datenbank) eine Rolle spielt oder in denen eigene Verfahren bzw. Verzeichnisstrukturen verwendet werden. Die hier mögliche größere Flexibilität bedeutet aber auch, dass es vor der eigentlichen Installation eine Planung geben muss. Diese teilt sich in folgende Bereiche: 1. Hardware und Betriebssystem 2. Art der Anwendung 3. Benötigte Optionen und Features 4. Anzahl Datenbanken
Installationsplanung
35
Im Kapitel 2.2.1 werden wir uns daher zunächst einmal näher mit den unterschiedlichen Hardware-Komponenten und Betriebssystemen befassen, bevor wir in Kapitel 2.2.2 die Anwendungen betrachten und damit auch schon auf die Optionen von Kapitel 2.2.3 eingehen. In Kapitel 2.2.4 schließlich beschäftigen wir uns mit der Frage, wie viele Datenbanken man braucht bzw. wann eine Konsolidierung oder Diversifizierung notwendig ist.
2.2.1 Hardware und Betriebssystem 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 Software-Systeme 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 EA-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. 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. Natürlich spielt auch die Lizenzierung der Oracle-Software eine Rolle, da in der Regel die Software je CPU lizenziert werden muss. Daher ist ein sehr leistungsfähiger Prozessor (z.B. AMD Opteron oder Intel Itanium) weniger starken Mehrprozessorsystemen vorzuziehen. Die eingesparten Lizenzkosten sind sicherlich größer als die Mehrkosten durch neue CPUs.
36
Installation und Aufbau einer Datenbank
Der Hauptspeicherausbau für ein Oracle-System sollte auf keinen Fall weniger als 1 GByte betragen. Je nach Konfiguration nimmt die Oracle-Instanz im Minimalfall 100 MByte in Anspruch, dazu kommen Ressourcen für das Betriebssystem und zusätzliche Oracle-Prozesse, wie z.B. der Enterprise Manager. Je nach Anwendung und Zahl der Verbindungen beträgt die Größe des Hauptspeichers eines Oracle-Servers durchaus einige GB bis einige zehn GB. Daher sollte auf die Skalierbarkeit des Hauptspeichers geachtet werden, eine 64-Bit-CPU ist somit erste Wahl. Beim EA-System sind neben den reinen Kapazitätsüberlegungen auch Lastverteilungs- und Redundanzfragen zu klären. Grundsätzlich ist eine Verteilung anzustreben, in der Betriebssystem- und Oracle-Software-Installation, eventuelle Auslagerungsbereiche, Datendateien, Redo-Log-Dateien sowie die archivierten Redo-Log-Dateien und Recovery-Bereiche jeweils auf unterschiedlichen Festplatten oder Festplattengruppen liegen. Diese Verteilung ist mit modernen Festplattensystemen 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 EA-Ressourcen 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 EA-Kapazität ist eine durchaus häufig vorkommende – und durch die am Kapitelanfang diskutierte Eigenschaft des Oracle-Datenbanksystems meist erfolgreiche – Maßnahme. Betriebssystem Die Wahl eines geeigneten Betriebssystems für eine Oracle-Software-Installation 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. 1
Um ein ständiges Aufzählen der möglichen Varianten für Oracle-Serverinstallationen, nämlich MSWindows 2000, MS-Windows 2003, MS-Windows XP etc., zu vermeiden, wird ab sofort MS-Windows als Synonym für alle Varianten verwendet. Nur bei der expliziten Betrachtung werden die Varianten jeweils benannt.
Installationsplanung
37
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. Für Oracle gibt es eine einfache Antwort auf diese Frage: Wählen Sie das Betriebssystem, das zu Ihnen bzw. den Hard- und Software-Anforderungen passt. Das heißt, Oracle bietet die gleiche Datenbanksoftware für unterschiedliche Betriebssysteme an, wobei es auch keinen Unterschied in der Administration macht, mal abgesehen davon, dass beim Betriebssystem VMS ein Verzeichnis anders aussieht als unter Unix oder MS-Windows. Die Frage nach dem Betriebssystem wird also entweder durch Vorgaben des Unternehmens (welches Betriebssystem wird bereits eingesetzt, wo haben wir das größte Know-how) geklärt, oder es richtet sich nach der benötigten Hardware. Wir werden nur in wenigen Fällen eine Unterscheidung zwischen des Systemen machen und uns in den Beispielen auf MS-Windows (Windows 2000 und Windows XP), SUN Solaris und Linux beschränken. Betriebssystemunabhängige Eigenschaften der Oracle-Datenbank 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 bzw. die in Oracle 10g erstmals vorhandenen Tools DataPump-Export und Import. Ihre Unabhängigkeit erlangen diese mit dem Export-Dateiformat, 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 (nur Export/Import). Mit einigen Tricks2 – und dem Verzicht auf Beibehaltung neuester Merkmale – kann man 2
Hierbei handelt es sich um das Einspielen eines älteren Exportkatalogs sowie den Zugriff mit einem der Versionsnummer entsprechenden Exportwerkzeug auf die Datenbanksoftware mit neuerer Versionsnummer.
38
Installation und Aufbau einer Datenbank
sogar Daten in einen Export mit kleinerem Versionsstand entladen, so dass das Zurückmigrieren 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 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 Hardware-Ressourcen 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 Patch-Level 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://otn.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 UnixDerivat (Sun) Solaris auch die Entwicklungsplattform für die Oracle Database-Software; andere Derivate wie HP-UX, (IBM) AIX und HP-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 Performance-Eigenschaften 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).
Abbildung 2.4: Oracle-Prozesse unter Unix mit Speicherstruktur SGA
Installationsplanung
39
Diese Struktur lässt sich sofort an der Ausgabe eines ps-Kommandos (in diesem Beispiel unter Linux) nachvollziehen: UID oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle oracle
PID PPID C STIME TTY TIME CMD 2204 1 0 13:37 ? 00:00:00 ora_pmon_JAUX10G 2206 1 0 13:37 ? 00:00:00 ora_mman_JAUX10G 2208 1 0 13:37 ? 00:00:00 ora_dbw0_JAUX10G 2210 1 0 13:37 ? 00:00:00 ora_lgwr_JAUX10G 2212 1 0 13:37 ? 00:00:00 ora_ckpt_JAUX10G 2214 1 0 13:37 ? 00:00:00 ora_smon_JAUX10G 2216 1 0 13:37 ? 00:00:00 ora_reco_JAUX10G 2218 1 0 13:37 ? 00:00:00 ora_cjq0_JAUX10G 2222 1 0 13:37 ? 00:00:00 ora_rvwr_JAUX10G 2226 1 0 13:38 ? 00:00:00 ora_arc0_JAUX10G 2228 1 0 13:38 ? 00:00:00 ora_arc1_JAUX10G 2230 1 0 13:38 ? 00:00:00 ora_ctwr_JAUX10G 2233 1 0 13:38 ? 00:00:00 ora_qmnc_JAUX10G 2236 1 1 13:38 ? 00:00:00 ora_mmon_JAUX10G 2238 1 0 13:38 ? 00:00:00 ora_mmnl_JAUX10G 2292 1 14 13:38 ? 00:00:02 ora_j000_JAUX10G 2295 1 6 13:38 ? 00:00:00 ora_q000_JAUX10G 2224 1 6 13:38 ? 00:00:03 oracleJAUX10G (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
Listing 2.1: Oracle-Prozesse unter Unix
Am obigen Beispiel wird deutlich, dass im Standardbetrieb durchaus mehr Hintergrundprozesse existieren. Die weiteren werden wir an entsprechender Stelle näher beschreiben. 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 zu konsultieren. Je nach Plattform sind zusätzliche Schritte vor der eigentlichen Installation durchzuführen. Unter IBM Unix-Derivat AIX wird z.B. ein spezieller, von Oracle mitgelieferter Post-Wait-Treiber für die Oracle-Interprozesskommunikation verwendet. Dieser wird als AIX-Kernel-Erweiterung installiert und muss während der Oracle-Installation bereits vorhanden sein. Typischerweise muss hierzu die Datei rootpre.sh vom Oracle-Installationsmedium als Benutzer root ausgeführt werden. Neben der Installation des Post-Wait-Treibers wird in diesem Skript dafür gesorgt, dass im AIX Kernel der asynchrone IO 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.
40
Installation und Aufbau einer Datenbank
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 TB) 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 GB. Für diese Unix-Derivate 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 GB 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. Die Oracle Server-Installation setzt im übrigen nicht voraus, dass eine MS-Windows Server-Version installiert ist; auch auf den MS-Windows 2000 Workstation-Varianten oder MS-Windows XP Home 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. Ein grundlegender Unterschied zwischen der Oracle-Implementierung unter MSWindows und praktisch allen anderen Implementierungen ist die Prozessarchitektur: Anstelle der sonst üblichen Multiprozess-Variante wurde der Oracle Server unter MS-Windows mit Hilfe der Multi-Threaded-Architektur des Betriebssystems implementiert.
Installationsplanung
41
Abbildung 2.5: Einzelprozessarchitektur unter MS-Windows mit Threads-Abbildung
Mit dieser Architektur ist eine Betriebssystemressource 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 der Abbildung 2.6 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 19. 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.
3
An dieser Stelle ist der »Prozess« in seiner Oracle-Bedeutung gemeint!
42
Installation und Aufbau einer Datenbank
Abbildung 2.6: Oracle-Prozess mit Threads unter MS-Windows
Oracle unter Linux Es gibt derzeit vier (!) unterschiedliche Oracle-Portierungen für Linux. Zunächst einmal die sicherlich meist verbreitete Version für 32 Bit Intel CPUs (x86). Daneben für die erweiterten 64 Bit CPUs (z.B. AMD64, EM64T) die Linux x86-64. Für neuere Prozessoren (Intel Itanium und AMD Opteron) gibt es eine spezielle Version Linux Itanium. Die vierköpfige Familie wird dann durch die 64 Bit z/Linux-Variante für IBM eServer komplettiert. Wichtig ist, dass nur spezielle Linux-Derivate zertifiziert sind, dazu gehören Red Hat Enterprise Linux AS/ES und SuSE Linux Enterprise Server. Die komplette Liste finden Sie jederzeit in der Zertifizierungsmatrix im Oracle-Metalink (metalink.oracle.com). 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, IBM MVS oder Apple Mac OS X. Auch hier gibt es Eigenheiten und spezielle Eigenschaften, allerdings ist die Verbreitung der Oracle-Datenbank auf diesen Plattformen nicht sonderlich groß. Wir verweisen daher auf die jeweiligen Installationsanweisungen.
Installationsplanung
43
2.2.2 Art der Anwendung Was wird mit der Datenbank gemacht? Das ist die Frage, nach der sich die Art der Anwendung richtet. Dabei wird zwischen folgenden Anwendungen unterschieden: OLTP4: Diese Art der Anwendung zeichnet sich durch eine große Anzahl von Anwendern mit relativ einfachen Abfragen und einer kontinuierlichen Transaktionslast aus. Dabei sind die einzelnen Transaktionen eher klein, beispielsweise die Auftragsannahme eines Großhandels. Die SQL-Befehle sind immer die gleichen, und die Datenbankgröße liegt wahrscheinlich im Bereich einiger Gigabyte. Für eine solche Datenbank ist es wichtig, ein optimales Backup-Konzept zu haben, da der Verlust von Daten kaum zu tolerieren ist. Außerdem muss diese Datenbank in der Regel hochverfügbar sein, da ein Ausfall erhebliche Kosten nach sich zieht. Das bedeutet, die Redo-Log-Dateien sollten gespiegelt werden, und die Archivierung muss auf eine separate Festplatte erfolgen. Das Ganze muss von der Hardware optimal unterstützt werden (IO-Verteilung). Die eingesetzte Hardware sollte außerdem in der Lage sein, die Anzahl der Benutzer optimal zu unterstützen (Anzahl CPUs) und die wesentlichen Daten aus dem Cache zur Verfügung zu stellen (Größe des Hauptspeichers). Von Seiten der Performance muss gewährleistet sein, dass Abfrageergebnisse in wenigen Sekunden verfügbar und die Änderungen sofort gespeichert sind. Oracle-Optionen sind in der Regel für diese Art der Anwendung nicht notwendig. Eine Ausnahme bildet die Real-Application-Cluster-Option für die Verfügbarkeit sowie die Oracle Enterprise Manager Packages für Monitoring und Diagnose. OLAP5 oder Data Warehouse: Die Datenbank kann unter Umständen mehrere Terabyte groß sein. Auf Basis dieser Daten werden von relativ wenigen Anwendern umfangreiche Berichte als Reports oder Analysen erstellt. Die SQL-Befehle sind kaum vorhersehbar. Die Transaktionslast ist zu bestimmten Spitzenzeiten (z.B. nachts) sehr groß, weil dann neue Daten geladen werden. Ein Data Warehouse wird in der Regel nicht online, sondern über Batch-Jobs aktualisiert. Einen Spezialfall hierbei bilden so genannte Data Marts, die aus einem Data Warehouse erzeugt werden, um mit einer kleineren Datenmenge komplexe Berechnungen z.B. auch für den Bereich Data Mining anzustellen. Für diese Datenbank gibt es zwei unterschiedliche Konfigurationen: Während der Ladeoperationen muss eine genügend große IO-Bandbreite zur Verfügung stehen, da große Datenmengen in kurzer Zeit verarbeitet werden müssen (z.B. nachts). Während des Tagesbetriebs muss hingegen ein möglichst großer Cache die aktuellsten Daten vorhalten. Außerdem kann über eine Parallelisierung der Abfragen (Parallel Query) nachgedacht werden, um damit die Abfragegeschwindigkeit noch weiter zu steigern.
4 5
OLTP = Online Transaction Processing OLAP = Online Analytic Processing
44
Installation und Aufbau einer Datenbank
Für die Hardware gibt es nur ein Ziel: in möglichst kurzer Zeit die Daten zu liefern. Daher ist hier die IO-Optimierung entscheidendes Kriterium für die Hardware. Natürlich gilt: Je mehr Hauptspeicher, umso besser. Im Gegensatz zum OLTP-System ist es hierbei aber üblich, dass Abfragen einige Minuten benötigen. Batch-Reports können durchaus eine Dauer von mehreren Stunden haben. Als Optionen kommt hier vor allen Dingen die Partitioning-Option zum Einsatz, da nur durch sie die großen Datenmengen effektiv bearbeitet werden können. Die Real Application Clusters-Option wird hier vor allen Dingen als Skalierungsoption eingesetzt, um damit neben der Ausfallsicherheit eine bessere Verteilung der Last zu erreichen. Für Data Marts kommen dann die OLAPund Data Mining-Option zum Einsatz. Mischbetrieb: In diesen Datenbanken werden OLTP-Anteile und abfrageorientierte Anwendungen gemischt. Dabei enthalten diese Datenbanken oftmals auch noch eine Batch-Komponente, die z.B. nachts Daten von nachgelagerten Systemen ausliest. Welche Anforderungen an die einzelnen Bereiche gestellt werden, richtet sich im Wesentlichen nach der Abfragelast, da diese den OLTPBereich immer behindern wird. Wenn es also nicht zu vermeiden ist, ein solches System aufzubauen, sollte der Bereich Data Warehouse möglichst klein bleiben, ansonsten wird das gesamte System in Mitleidenschaft gezogen. Es ist bei diesen Systemen davon abzuraten, tatsächlich frei wählbare SQL-Abfragen starten zu können (so genannte Power User, die mit Werkzeugen wie Quest TOAD oder dem guten alten SQL*Plus arbeiten), da die Konfiguration dann kaum noch auf die unterschiedlichen Anforderungen anpassbar ist. In dieser Konstellation kann die Real-Application-Cluster-Option sehr effektiv eingesetzt werden, indem die OLTP-Anwendungen auf einem Server und Abfrage-Anwendungen auf einem anderen Server verteilt werden, die immer noch auf den gleichen Datenbestand zugreifen. Spezialanforderungen: Neben diesen weit verbreiteten Anwendungen gibt es spezielle Anforderungen z.B. für die Verarbeitung von Multimedia-Daten oder geokodierten (Spatial) Informationen. Da diese Fälle jedoch Ausnahmen sind, werden wir nicht weiter darauf eingehen. Wenn Sie ein solches System aufbauen wollen, sollten Sie sich entsprechende Unterstützung aus Beratungsunternehmen holen. Sicherlich gibt es neben diesen Arten noch weitere, wie z.B. Fileserver oder reine Batchsysteme, die sich aber im Wesentlichen in die oben genannten Beispiele eingliedern lassen. Neben der Art der Anwendung spielt sicherlich noch die Anzahl der Anwender und Größe der Datenbank eine entscheidende Rolle. Hier ist auch die Frage zu stellen, welche Oracle-Edition eingesetzt werden soll. Die Größe der Datenbank und die Anzahl der Benutzer hat dabei keinen direkten Einfluss auf die Edition, wohl aber die eingesetzte Hardware. Die Standard Edition One darf nur auf Systemen mit bis zu zwei CPUs eingesetzt werden, die Standard Edition auf bis zu vier CPUs. Die Größe des Hauptspeichers oder gar die Plattenkapazität ist davon nicht betroffen. Allein die Möglichkeit, Optionen zu verwenden, kann damit ein Grund sein, die
Installationsplanung
45
Enterprise Edition einzusetzen. Im nächsten Kapitel werden daher zunächst die Editionen beschrieben und anschließend auf die Optionen eingegangen.
2.2.3 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. 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 Nutzung der Replikation über Oracle Streams kann z.B. die Migration von Oracle8i oder Oracle9i nach Oracle 10g 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.4 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.
46
Installation und Aufbau einer Datenbank
2.2.5 Software-Komponenten Die Aufteilung der Software-Komponenten auf Installationsmedien bzw. Installationssets hat sich für Oracle 10g grundlegend geändert. Für die Installation der Oracle Database 9i Release 2 unter MS-Windows waren drei CDs notwendig. Diese enthielten neben der reinen Datenbank-Software u.a. den kompletten Enterprise Manager inklusive der zentralen Komponente Management Server, Beispieldaten, den Oracle HTTP Server (einen um einige Oracle Mods erweiterten Apache Server) und vieles mehr. Natürlich kann man das alles unter gewissen Umständen gut gebrauchen; in den meisten Fällen braucht man jedoch die Zusatzkomponenten nicht. Im Gegenteil – was haben Beispieldaten auf einer produktiven Datenbankumgebung verloren? Die Installation der Oracle Database 10g-Software unter MS-Windows findet nun mit genau einer CD (nicht etwa DVD!) statt. Es befinden sich jedoch nur noch die wirklich datenbanknahen Komponenten darauf – alles andere befindet sich auf weiteren CDs. Oracle Database 10g Dies ist zentrale Installationskomponente: die Oracle Datenbank-Software. Gegenüber früheren Versionen wurde sie deutlich entschlackt, was sich in einer wesentlich kürzeren Installationszeit bemerkbar macht. Dieses Kapitel beschreibt hauptsächlich die Installation dieser Datenbank-Software. Zusätzlich zur Datenbank-Software sind hier lediglich die wirklich datenbanknahen Werkzeuge (SQL*Plus, Data Pump, Loader, DB-Verify usw.), der Enterprise Manager Database Control sowie iSQL*Plus untergebracht. Der Enterprise Manager Database Control wird nicht mehr – wie von den 9er-Versionen gewohnt – als Java-Client ausgeliefert, sondern läuft als Serverprozess zusätzlich zu einer Instanz. Bedient wird der Enterprise Manager Database Control über einen Webbrowser – daher benötigt ein DBA keine zusätzliche Software-Installation mehr. Die größte Einschränkung der Database Control-Variante des Enterprise Managers ist, dass sie an genau eine Datenbank gekoppelt ist. Will man mehr als eine Datenbank aus einer Anwendung heraus überwachen, so muss man den Enterprise Manager Grid Control ins Spiel bringen, der aber auf der Database-CD nicht enthalten ist. Weiterhin wird bei jeder Installation der Datenbank-Software eine »kleine Version« der Oracle Clusterware installiert, sofern die Cluster Ready Services nicht bereits installiert sind. Dies wird benötigt, wenn man die von Oracle entwickelte Speichervariante ASM für Datenbankdateien verwenden möchte. Oracle Database 10g Companion-CD Auf dieser CD gibt es diverse Produkte, die bei früheren Versionen auf der Database CD enthalten waren und meist sogar ohne Nachfrage mitinstalliert wurden. Es handelt ich u.a. um:
Installationsplanung
47
Beispielschemata und Daten den Oracle HTTP-Server die Datenbank-Programmierumgebung HTML DB die Sicherungssoftware Legato Single Server einige Java- und XML-Produkte Die Beispielschemata sind in einem eigenen Handbuch dokumentiert und sicherlich hilfreich beim Testen von Anwendungen, Optionen usw. Bei einer produktiven Datenbanksoftware-Installation haben sie jedoch nichts zu suchen und sind demnach richtigerweise auf einer eigenen CD. Gleiches gilt für den Oracle HTTP Server und HTML DB. Gerade letzteres Produkt erfreut sich großer Beliebtheit und ist – gerade als kostenloses Add-on – sehr sinnvoll zur Erstellung kleinerer Anwendungen. Aber auch hier gilt der Ausschluss bei Standard-Datenbanksoftware-Installationen. Die Kooperation zwischen Legato und Oracle besteht nunmehr auch seit einigen Versionen. Für den Oracle-Kunden hat das den Vorteil, dass für Maschinen, die sowohl Datenbanksoftware als auch die Sicherung der Datenbank betreiben, keine weitere Software angeschafft werden muss, um mit dem Recovery Manager ein belastbares Sicherungskonzept zu betreiben. Oracle Database 10g Client Der Client enthält alle Softwarekomponenten, die für eine Anbindung von Arbeitsplätzen an eine Oracle Database benötigt werden. Hier gibt es mittlerweile eine recht große Bandbreite an Techniken: Oracle Net, ODBC, JDBC usw. Auf der CD sind – je nach Betriebssystem – die entsprechenden Treiber und Komponenten vorhanden. Des Weiteren gibt es hier viele Bibliotheken, die z.B. zum Betrieb einer OCI-Anwendung notwendig sind. Oracle Cluster Ready Services Die Installation der Cluster Ready Services (CRS) ist Voraussetzung für eine RACInstallation. Hierbei werden die CRS vor der Installation der Oracle Database in ein eigenes ORACLE_HOME installiert. Instant Client Eine komplett neue Variante der Client-Installation bietet der Instant Client: Dieser wird nicht mehr über eine Installationsprozedur bzw. den Universal Installer installiert, sondern durch einfaches Kopieren von Bibliotheken. Diese müssen lediglich vom Betriebssystem gefunden werden (PATH-Variable). Falls die geplante Anwendung OCI-, OCCI- oder JDBC-OCI-basiert ist, kann der Instant Client als Ersatz für den Standard-Client verwendet werden. Für einige Spezialfälle gibt es Erweiterungen (z.B. eine spezielle SQL*Plus-Version und für ODBC). Im Zweifelsfall sollte dies ausprobiert werden. Ein großer Vorteil des Instant Clients ist die einfache Handhabung für große Umgebungen, bei denen manchmal auch eigene Installationsvorschriften und -verfahren eingesetzt werden. Als nachteilig
48
Installation und Aufbau einer Datenbank
kann sich die fehlende Komplexität dann herausstellen, wenn zusätzliche Optionen für den Client eingeschaltet werden sollen (z.B. Tracing), was mangels der fehlenden Oracle Net-Umgebung nicht geht. Oracle Enterprise Manager 10g Grid Control Die Grid Control-Variante des Enterprise Managers wird zur zentralen Verwaltung komplexer Datenbankumgebungen benötigt. Hierfür wird dann in der Regel ein eigener Rechner vorgesehen, dessen Ausstattung, insbesondere im Hauptspeicherbereich, nicht zu knapp bemessen sein sollte. Die Minimalausstattung liegt bei 1 GB – ohne den Hauptspeicherbedarf für die zugehörige Oracle-Instanz zur Verwaltung der Daten. Der Vorteil der »großen« Variante des Enterprise Managers ist sicherlich die zentrale Sicht auf mehrere bzw. viele Datenbanken. Weiterhin können mit Grid Control nicht nur Datenbanken, sondern auch Listener, Application Server u.v.m. administriert werden. Wie beim Enterprise Manager Database Control erfolgt der Zugriff auf die GridControl-Komponenten über einen Webbrowser, so dass auch für dieses Werkzeug keine Installation auf dem Administrator-Arbeitsplatz notwendig ist.
2.2.6 Globalization Support Unter dem Thema Globalization Support (früher: National Language Support, NLS) werden alle Themen im Oracle-Umfeld zusammengefasst, die mit verschiedenen Sprachen, ländertypischen Konventionen und Zeichensätzen zu tun haben. Das Thema an sich ist recht umfangreich; daher ist Kapitel 8 für eine genauere Diskussion vorgesehen. An dieser Stelle muss lediglich der Sachverhalt der Datenbank-Zeichensätze geklärt werden, da man bei der Erstellung einer Datenbank die Zeichensätze auswählen muss. Diese Entscheidung kann für eine bestehende Datenbank praktisch nicht mehr rückgängig gemacht werden. Pro Datenbank sind zwei Zeichensätze auszuwählen, weil es zwei Sätze von Datentypen gibt, die Zeichenketten definieren. Die Standard-Datentypen für Zeichenketten sind CHAR, VARCHAR2 und CLOB. Hierfür muss der Datenbank-Zeichensatz ausgewählt werden. Die gängigsten Zeichensätze hierfür sind: WE8ISO8859P1: ISO 8859-1 West-European WE8ISO8859P15: ISO 8859-15 West-European WE8MSWIN1252: MS-Windows Code Page 1252 8-bit West European Viele Datenbanken, die bereits länger existieren und über einige Oracle-Versionen immer wieder migriert worden sind, nutzen den ISO-Zeichensatz WE8ISO8859P1. In früheren Versionen wurde dieser Zeichensatz bei Installationen unter MS-Windows standardmäßig eingestellt, so dass bei der Verwendung dieser Clients keine Zeichensatzkonvertierung zwischen Client und Server stattfinden musste. Die Migration zu WE8ISO8859P15, einer Weiterentwicklung von WE8ISO8859P1, die das Euro-Symbol enthält, hat nur selten stattgefunden, da bei der Verwendung des neuen Zeichensatzes ältere Clients oft keine Verbindung aufbauen konnten.
Installationsplanung
49
Da seit einigen Versionen der Standard-Zeichensatz für MS-Windows-Installationen WE8MSWIN1252 ist, bietet sich dieser Zeichensatz nunmehr für viele Installationen an, insbesondere im Client-Server-Umfeld. Sobald Web- bzw. Applikationsserver ins Spiel kommen und Webbrowser das Frontend darstellen, bieten sich eher die ISO-Zeichensätze an, da viele Webbrowser standardmäßig damit arbeiten. Der zweite Zeichensatz einer Datenbank wird als nationaler Zeichensatz bezeichnet und muss (seit Oracle 9i) ein Unicode-Zeichensatz sein. Man hat die Wahl zwischen AL16UTF16 und UTF8. Der nationale Zeichensatz ist relevant für die Datentypen NCHAR, NVARCHAR2 und NCLOB. Weitere Informationen über Zeichensätze, insbesondere über Unicode, befinden sich in Kapitel 8.
2.2.7 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. Bei der hier angesprochenen Planung von Datenbanken sollten vor allem folgende Aspekte Beachtung finden: Zum einen ist zu entscheiden, welche Anwendungen und Schemata 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 operative Geschäft sämtlicher Abteilungen gefährden. Der zweite Aspekt, der bei der Installationsplanung Beachtung finden muss, ist die Festlegung all jener Datenbankparameter, 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 Schemata eine in Sachen Verfügbarkeit und Laufzeitverhalten optimierte Umgebung zu bieten. Beide Aspekte werden im Folgenden näher erläutert.
50
Installation und Aufbau einer Datenbank
Das »Datenbankmodell« Die Frage, welche Daten und Schemata 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 Serverparameter db_block_size festgelegt wird und Größen zwischen 2 K und 64 K annehmen kann. Die Blockgröße stellt die kleinste Dateneinheit und EA-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 aufgebaut werden6, um nicht mit einem erhöhten Risiko für Zugriffskonflikte konfrontiert zu werden. Da der minimale Platzbedarf für Tabellen zwei 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. Aufgrund dieser Sachverhalte sind Datenbanken mit großen durchschnittlichen Satzlängen und einem großen Datenvolumen pro Objekt prädestiniert für Blockgrößen von 16 K und mehr. Die erhöhten Blockgrößen reduzieren in diesem Fall das Aufteilen von Datensätzen über mehrere Blöcke (Row Splitting, Row Chaining) 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 4 K oder 8 K. 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 aufgrund ihrer Speicheranforderungen separat installiert werden mussten, gemeinsam in einer Datenbank betrieben werden. Der oben erwähnte Serverparameter 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 zwi6
Die Anzahl der Transaction Entries pro Datenblock lässt sich sehr einfach über den Storage-Parameter initrans festlegen.
Installationsplanung
51
schen 2 K und 32 K 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 Serverparameter 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. 120M – 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 vorgegebene Maximalgröße7 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 Zieldatensatz 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 Befehl8 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 WE8SO8859P15. Festlegung des Datenbanknamens Jede Datenbank hat einen globalen Namen, der – in verteilten Umgebungen – die Namensgebung von Datenbankverbindungen (Database Links) bestimmt.9 Der globale Name einer Oracle-Datenbank wird bei der Initialisierung aus den Serverparametern 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-Befehl10 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. 7 8
Bestimmt über den Serverparameter sga_max_size. Die Befehle lauten: alter database character set ; bzw. alter database national character set ;
9
Dies gilt für Instanzen, bei denen das globale Namensmodell eingeschaltet ist (Serverparameter global_names = true).
10 alter database rename global_name to ;
52
Installation und Aufbau einer Datenbank
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 Serverparameters 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 der Transaktionsverwaltung In der Version 9i können die bis dahin gebräuchlichen Rollback-Segmente durch eine automatische Undo-Verwaltung ersetzt werden. Über den Serverparameter undo_management wird für jede Instanz die Art der Transaktionsverwaltung festgelegt, der Wert AUTO schaltet auf die hier besprochene Methode der automatischen UndoVerwaltung. Der Undo-Tablespace ist zuvor über den Befehl CREATE UNDO TABLESPACE anzulegen und mit dem Serverparameter undo_tablespace für die betreffende Instanz zu reservieren. In Oracle9i wurde alternativ auch noch die herkömmliche Nutzung von Rollback-Segmenten unterstützt, mit Version 10g sollte diese Alternative nicht mehr benutzt werden. Die Festlegung des Datenbankmodus Jede Datenbank hat einen Datenbankmodus, der ihr Verhalten im Falle von Backupund Recovery-Operationen bestimmt. Oracle-Datenbanken können im ArchiveLog- oder Noarchive-Log-Modus betrieben werden. Der Datenbankmodus legt fest11, ob alle Datenmodifikationen – in Form von so genannten Offline-Redo-Log-Dateien – fortlaufend archiviert werden oder nicht. Für Datenbanken im Archive-LogModus 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 Noarchive-Log-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. Neben dem Archive-Modus steht in der Version 10g auch noch die Flashback-Database-Funktionalität zur Verfügung, die ebenso wie die Archivierung in der MountPhase aktiviert werden kann. Mit der Flashback-Database-Funktionalität kann die Datenbank auf einen Zeitpunkt zurückgesetzt werden, ohne ein Backup einspielen zu müssen. Anwendungen, die aufgrund 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, mit gleichen Datenbankversionen arbeiten können, über ein gemeinsames Transaktionsmanagement betrieben werden können, 11 Die Einstellung erfolgt in der Mount-Phase über den Befehl alter database archivelog;.
Installationsplanung
53
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 Instanzen12 bedient werden. Die in den Oracle-Versionen 9i und 10g 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 parametriert 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 waren schon in der Version 9i 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. Da der Parameter sga_max_size den notwendigen Speicherplatz zwar überprüft, aber nicht allokiert, kann dieser Parameter entsprechend hoch gesetzt werden, um im laufenden Betrieb die Möglichkeit zu haben, die SGA zu vergrößern. Für die Version 10g empfiehlt sich das Automatische Shared-Memory-Management (Automatic Memory Management). Hierbei wird nur noch die Gesamtgröße des Shared Memorys über den Serverparameter sga_target vorgegeben. Aufgrund von Systemstatistiken, die über den Serverparameter statistics_level = TYPICAL oder ALL ermittelt werden, werden dann die einzelnen Komponenten (Buffer Cache, Shared Pool, Large Pool und Java Pool) automatisch parametriert und im laufenden Betrieb ebenfalls automatisch geändert. Alternativ können wie bisher die Parameter manuell gesetzt werden: Blockpuffer (Database Buffer Cache) Der Blockpuffer speichert Kopien von Oracle-Blöcken aus den Datendateien der Datenbank. Er ist Teil der System Global Area. Ab Oracle9i sind hierfür die bereits erwähnten Parameter db_cache_size und db_nk_cache_size zuständig, welche die Größe des Pufferbereiches (in Byte) festschreiben. In älteren OracleVersionen wurde der Bereich über den Parameter db_block_buffers angegeben, der die Anzahl der Datenbank-Blöcke angab.
12 Die Real-Application-Cluster-Konfiguration erlaubt den Zugriff über mehrere Instanzen auf eine Datenbank. Die Instanzen können in einer Cluster- oder Massiv-Parallel-Umgebung konfiguriert sein.
54
Installation und Aufbau einer Datenbank
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 Bereiche gelten allerdings nur für Objekte in Tablespaces mit der Standardblockgröße (db_block_size). Gemeinsamer Pool (Shared Pool) 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 Serverparameter shared_pool_size festgelegt. Weitere spezielle Shared-Memory-Bereiche existieren für Java und Oracle Streams. Die entsprechenden Parameter werden zu gegebener Zeit erklärt. Des Weiteren müssen die Verzeichnisstrukturen und Namen der Dateien festgelegt werden. Dazu gehören: Kontrolldateien (Parameter Control Files). Sie 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. Sie enthalten alle Benutzer- und Metadaten der betreffenden Datenbank. Die Häufigkeit und die Art der Zugriffe hängen vom Zugriffsverhalten der abhängigen Anwendungen und darüber hinaus auch von der Größe des Buffer-Caches ab – je größer der Buffer-Cache, desto geringer die Anzahl der physischen Zugriffe. Der Zugriff auf Datendateien erfolgt stets wahlfrei. Redo-Log-Dateien. Sie enthalten Änderungsprotokolle, die durch Datenmanipulationen generiert und über den Log-Puffer der System Global Area in die Redo-Log-Dateien geschrieben werden. Redo-Log-Dateien werden im laufenden Datenbankbetrieb nur geschrieben, während eines Recovery dagegen auch gelesen. Zugriffe auf Redo-Log-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 Redo-Log-Dateien jedoch zu den im Hinblick auf die Ein- und Ausgabe am intensivsten genutzten Dateien eines Oracle-Systems. Zusätzlich kann es Bereiche für das Backup und Recovery geben (Flash Recovery Area), die ebenfalls über die Datenbank verwaltet werden (siehe Kapitel 10). Die Installationsplanung hat auf der einen Seite die Aufgabe, ein Regelwerk zum Aufbau von Verzeichnisstrukturen13 und Namenskonventionen zu schaffen, das den Administratoren eine schnelle Orientierung auf unterschiedlichen Rechnern des Unternehmens erlaubt und auch Skripte 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 Serverparameter 13 Oracle bietet hierzu die so genannte OFA-Struktur an (Oracle flexible Architecture).
Software-Installation
55
aktiviert: db_create_file_dest bezeichnet das – bereits vorhandene – Verzeichnis, das die Datendateien aufnehmen soll. db_create_online_log_dest_n gibt die Verzeichnisse für die Redo-Log-Dateien und die Steuerdateien vor – 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. Datenund Redo-Log-Dateien werden mit einer anfänglichen Größe von 100 MByte 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 IO-Anforderungen entsprechend sinnvoll zu verteilen. Als Minimalforderung für produktive Systeme gilt hier die strikte Trennung von Steuer-, Daten- und Redo-Log-Dateien auf den Platten des Systems.
2.3
Software-Installation
Im Kapitel 2.1 haben wir schon einmal die Software-Installation beschrieben. Warum also noch mal ein Kapitel? Die Antwort ist recht einfach: Die Basisinstallation ist zwar für eine einfache Installation ausreichend, sie kann aber unter Umständen dazu führen, dass Sie Software installieren und eine Datenbank konfigurieren, die Sie in der Form nicht lizenziert haben. Wenn Sie also die Enterprise Edition über die Basisinstallation anwählen, werden folgende Optionen automatisch installiert, die Sie in der Regel nicht lizenziert haben. Dies sind in der Version 10.1.0.3: Oracle Advanced Security Oracle Partitioning Oracle Spatial Oracle OLAP Sowie die Enterprise Manager Packages Natürlich ist es kein Lizenzverstoß, wenn Sie die Software installieren. Wenn Sie allerdings eine Datenbank anlegen und diese Optionen verwenden, müssen Sie die entsprechenden Lizenzen besitzen. Aufgrund dieser Tatsachen wählen wir in der Regel bei der Enterprise Edition die benutzerdefinierte Installation, da dadurch Funktionen und Optionen gezielt ausgewählt werden können.
2.3.1 Vorbereitungen Während auf MS-Windows nur darauf geachtet werden muss, dass genügend Plattenkapazität (ca. 1,5 GByte) zur Verfügung steht, müssen unter den diversen UnixDerivaten unterschiedliche Voraussetzungen geprüft werden. Dazu gehört z.B. der Post-Wait-Treiber unter IBM-AIX.
56
Installation und Aufbau einer Datenbank
Unter Windows sollte die Installation immer als lokaler Administrator erfolgen, die Installation über einen Terminalserver-Client ist nicht möglich. In jedem Fall (ob MS-Windows oder Unix) muss eine grafische Benutzeroberfläche zur Verfügung stehen, es sei denn, Sie verwenden eine so genannten Silent Installation. Unter Unix sollte die Software jedoch nicht als Administrator (Root), sondern unter einem separaten Benutzer installiert werden. Das bedeutet, dass Sie bei der Erstinstallation unter Unix einen Benutzer und eine Gruppe anlegen müssen. Im einfachsten Fall ist dies der Benutzer oracle mit der Gruppe dba. Natürlich können die Namen beliebig gewählt werden, allerdings sollten Sie bedenken, dass in den meisten Dokumentationen genau diese Benennungen benutzt werden. Offen ist allerdings, ob man für die Installation unterschiedlicher Oracle-Versionen auch unterschiedliche Benutzer wählen sollte. Diese Frage wird sicherlich nur im Rahmen von Sicherheitsrichtlinien beantwortet werden können, prinzipiell raten wir aber davon ab, da man sich natürlich die Passwörter merken muss. In vielen Oracle-Dokumenten wird zusätzlich empfohlen, die Gruppe oinstall anzulegen und die Oracle Software Installation unter dieser Gruppe durchzuführen. Der Vorteil ist hierbei, dass Datenbank- und Software-Installation voneinander getrennt verwaltet werden, allerdings bringen zusätzliche Gruppen immer auch einen Mehraufwand bei der Pflege mit sich. Wann ist es sinnvoll, getrennte Gruppen (dba und oinstall) zu haben? Die Gruppe dba wird bei der Datenbankkonfiguration verwendet, um festzulegen, welche Gruppenmitglieder sich ohne Passwort als SYSDBA an die Datenbank anmelden können. Daher stellt diese Gruppe ein Sicherheitsrisiko dar, so dass sie nur wenige Mitglieder haben sollte. Die Gruppe oinstall hingegen legt fest, welche Mitglieder die Oracle-Software und Patches installieren dürfen. Damit ist es in großen Unternehmen möglich, diese Aufgaben zu verteilen und damit den Sicherheitsanforderungen gerecht zu werden. In kleineren Unternehmen oder in Unternehmen, bei denen die Installation der Software und Konfiguration der Datenbank in einer Gruppe vereint sind (und das ist wohl in den meisten Unternehmen der Fall), reicht es daher aus, nur mit der Gruppe dba zu arbeiten. Wir werden daher im Weiteren auf die Gruppe oinstall verzichten. Nachdem Benutzer und Gruppe eingerichtet sind, empfiehlt es sich, für die Software ein separates Filesystem auszuwählen. In unseren Beispielen – aber auch in vielen Dokumenten) wird dieses in der Regel mit dem Mount-Point /app angesprochen. Unter diesem Mount-Point wird dann noch ein Unterverzeichnis (z.B. oracle) angelegt, und damit sind die wesentlichen Voraussetzungen für die Installation erfüllt. Natürlich muss das Verzeichnis /app/oracle dem Betriebssystembenutzer oracle und der Gruppe dba gehören. Je nach Unix-Derivat müssen vor dem Aufbau einer Datenbank außerdem die Semaphore- bzw. Shared-Memory-Segmente konfiguriert werden. Unter SUN Solaris bedeutet dies, dass Sie in die Datei /etc/system folgende Mindestgrößen eintragen müssen:
Software-Installation set set set set set set set set set
57
noexec_user_stack=1 semsys:seminfo_semmni=100 semsys:seminfo_semmns=1024 semsys:seminfo_semmsl=256 semsys:seminfo_semvmx=32767 shmsys:shminfo_shmmax=4294967295 shmsys:shminfo_shmmin=1 shmsys:shminfo_shmmni=100 shmsys:shminfo_shmseg=10
Listing 2.2: Shared Memory und Semaphore für SUN Solaris
Weitere Informationen auch bezüglich Betriebssystempatches finden Sie in der entsprechenden Installationsdokumentation für Ihr Betriebssystem.
2.3.2 Oracle Flexible Architecture (OFA) Wenn Sie die Oracle Software installieren, sollten Sie beachten, dass es unterschiedliche Komponenten gibt. Daher empfiehlt es sich, eine gewisse Verteilung vorzunehmen. Oracle bietet mit der Oracle Flexible Architecture (OFA) seit der Version 8 eine entsprechende Gruppierung an. Dazu gehören: Das Verzeichnis mit der installierten Software, das durch die Variable ORACLE_HOME gekennzeichnet ist. Dieses Verzeichnis enthält alle Programme (binVerzeichnis), Skripte, Packages und Komponenten für den Betrieb einer Datenbank. Das wichtigste Programm in diesem Verzeichnis ist oracle bzw. oracle.exe, d.h. der Kernel der Datenbank. Falls Sie also unterschiedliche Oracle Software-Versionen benutzen, ist es wichtig, den »richtigen« Pfad für die Programme zu wählen, da Sie sonst u.U. die Datenbank mit dem falschen Kernel starten. Des Weiteren befinden sich in diesem Verzeichnis die Konfigurationsdateien der Datenbank (dbs- bzw. database-Verzeichnis) und der Netzwerkkomponenten (network/admin). Ab Oracle 10g gibt es außerdem ein Unterverzeichnis für die Oracle Enterprise Manager Database Control Konfiguration. Das Verzeichnis, in dem die versionsunabhängigen Komponenten installiert werden. In der Vergangenheit waren dies der Universal Installer sowie die Informationen über die installierte Software (Inventory). Mit Version 10 bzw. auch bei den Oracle9i Patches ab Version 9.2.0.5 gibt es je Version wieder einen eigenen Installer, so dass diese Software jetzt im ORACLE_HOME liegt. Je Datenbank ein Verzeichnis für die zugehörigen Log- und Trace-Dateien Ein oder mehrere Verzeichnisse für die Datenbankdateien Zusätzliche Verzeichnisse für Sicherungen (Archivierungen, Flash-Recovery, Backup)
58
Installation und Aufbau einer Datenbank
Abbildung 2.7: Oracle Flexible Architecture
Während es bei den vorherigen Versionen üblich war, je Oracle-Version ein eigenes ORACLE_HOME zu haben, bei der die Versionsnummer in dreistelliger Form den Abschluss bildete (z.B. D:\oracle\product\9.2.0), wird bei Version 10g standardmäßig noch ein weiteres Unterverzeichnis hinzugefügt, also wie in Abbildung 2.7 D:\oracle\product\10.1.0\db_1. Der Grund hierfür ist die Versionsgleichheit für unterschiedliche Oracle Software-Pakete. Dadurch kann z.B. im Verzeichnis db_1 die Datenbank-Software, im Verzeichnis em_1 der Enterprise Manager, im Verzeichnis as_1 der Application-Server und im Verzeichnis ag_1 der Enterprise-ManagerAgent installiert werden; alle in der Version 10.1.0. Ob Sie allerdings diese Unterscheidung vornehmen oder wie in den Vorgängerversionen nur bis zur Produktversion gehen, bleibt Ihnen überlassen.
Software-Installation
59
2.3.3 Universal Installer Nachdem Sie unter Windows den Befehl setup gestartet (falls das CD-ROM-Laufwerk kein autorun unterstützt) oder unter Unix den Befehl runInstaller aufgerufen haben, wird zunächst einmal ein Check des Systems durchgeführt. Dabei wird geprüft, ob die notwendigen Voraussetzungen erfüllt sind. Dazu gehören u. a.: Hauptspeicher (mindestens 512 MB) Swap-Space (ca. 1 GB) Temp-Space (ca. 400 MB) Betriebssystem und Patches (wichtig beim Einsatz eines Linux-Derivats) Bei MS-Windows taucht daher für kurze oder längere Zeit ein DOS-Fenster auf. Mit dem Aufruf runInstaller –ignoreSysPrereqs kann der Check übersprungen werden. So ist es z.B. möglich, eine Installation unter Debian-Linux durchzuführen. Es versteht sich natürlich, dass Sie damit keinen Anspruch auf Support haben, d.h., diese Option sollten Sie nur bei Testinstallationen verwenden. Anschließend sollte das Fenster mit dem Oracle Universal Installer und der Willkommen-Meldung erscheinen. Falls es die erste Installation auf diesem Host ist, können Sie auf Unix-Systemen anschießend die Lage des Oracle-Inventorys angeben. In diesem Verzeichnis werden alle Installationen, die mit dem Universal Installer ausgeführt wurden, protokolliert.
Abbildung 2.8: Inventory unter Unix
60
Installation und Aufbau einer Datenbank
Auf Unix-Systemen empfiehlt es sich, vorher die Variable ORACLE_BASE zu setzen, so dass als Standardvorgabe dann das Verzeichnis $ORACLE_BASE/oraInventory gewählt wird. Außerdem erfolgt bei Unix-Betriebssystemen noch die Abfrage nach der Betriebssystemgruppe, unter der die Software installiert werden soll, in diesem Fall dba; aber wie bereits besprochen, sollte hier bei einer Trennung von Software-Installation und Datenbankkonfiguration die Gruppe oinstall gewählt werden. Bei MS-Windows erfolgt diese Abfrage nicht, sondern es wird standardmäßig das Verzeichnis C:\Programme\Oracle\Inventory gewählt. Um das zu verhindern, sollten Sie den Befehl setup aus einer DOS-Box heraus starten und vorher die Variable ORACLE_BASE auf das Verzeichnis stellen, in das Sie diese versionsunabhängigen Komponenten speichern möchten. Also z.B.: set ORACLE_BASE=D:\oracle
Damit wird während der Installation ein Unterverzeichnis inventory erstellt, in dem sich alle Installations-Logs sowie Informationen über die installierte Software befinden. Die Lage dieser Dateien kann bei späteren Installationen nicht mehr verändert werden, so dass Sie sich kurz Gedanken machen sollten, wohin Sie diese Informationen speichern wollen. Wichtig: Beim Verlust der Inventory-Informationen können keine weiteren Patches etc. installiert werden. Daher empfiehlt es sich, dieses Verzeichnis regelmäßig mit der Oracle-Software zu sichern. Daher wählen wir bei der Installation oftmals das gleiche Verzeichnis aus, in dem sich auch die Oracle-Software befindet (siehe Beispiel). Bei der Installation unter Unix wird als Nächstes die Meldung erscheinen, dass bestimmte Aktionen als root ausgeführt werden müssen. Öffnen Sie also ein zusätzliches X-Windows und führen Sie das Skript orainstRoot.sh aus (steht im o.a. Inventory-Verzeichnis). Mit diesem Befehl werden je nach Betriebssystem zusätzliche Dateien außerhalb des Oracle-Installationskontextes angelegt. Die wichtigsten sind: oratab: In dieser Datei werden später die Namen der Instanzen und deren ORACLE_HOME-Verzeichnisse eingetragen. oraInst.loc: In dieser Datei steht, wo sich das Inventory-Verzeichnis befindet und unter welcher Gruppe die Software installiert wurde (dba oder oinstall). In den meisten Fällen befinden sich die Dateien im Verzeichnis /etc, bei SUN Solaris im Verzeichnis /var/opt/oracle.
Software-Installation
61
Nachdem Sie das Skript ausgeführt haben, können Sie mit der Installation fortfahren. Sie gelangen jetzt zur Auswahl des ORACLE_HOME-Verzeichnisses, dem Sie einen eindeutigen Namen (ORACLE_HOME_NAME) geben müssen.
Abbildung 2.9: Dateiverzeichnisse
Als Nächstes kommen wir dann zum entscheidenden Punkt, der Auswahl der Installationsart. Wie bereits angesprochen, empfehlen wir Ihnen, bei der Enterprise-Edition die benutzerdefinierte Installation auszuwählen.
62
Installation und Aufbau einer Datenbank
Abbildung 2.10: Benutzerdefinierte Installation
Bitte beachten Sie, dass Sie für die Standard Edition in keinem Fall eine benutzerdefinierte Installation durchführen dürfen. Diese Installationsart bezieht sich ausschließlich auf die Enterprise Edition. Auf der folgenden Seite finden Sie die verfügbaren Produktkomponenten. Für eine in den meisten Fällen ausreichende Datenbank empfehlen wir Ihnen, folgende Komponenten auszuwählen: Oracle Database 10g Keine Enterprise-Edition-Optionen Oracle Net Services Oracle Enterprise Manager Database Control Oracle Development Kit iSQL*Plus Legato Networker Single Server (falls Sie keine andere Backup-Software einsetzen) Anschließend kann die Software installiert und – falls gewünscht – die Datenbank aufgebaut werden. Am Schluss werden Sie, wie bei der Basisinstallation, die Liste der verwendeten Ports erhalten (siehe Abbildung 2.3).
Software-Installation
63
Abbildung 2.11: Ausgewählte Produktkomponenten
2.3.4 Silent Installation Die Installation der Oracle-Software mit Hilfe des Universal Installers ist grundsätzlich übersichtlich gestaltet und komfortabel. Allerdings gibt es zwei Nachteile: 1. Wenn man viele Installationen gleicher Art durchzuführen hat, ist die wiederholte Auswahl der Komponenten zeitraubend und verleitet zu Fehlern. 2. Die interaktive Installation setzt ein grafisches Benutzerinterface voraus (XWindows) – was bei reinen Servermaschinen nicht immer gegeben ist. Man kann diese Nachteile mit einer so genannten Silent Installation in den Griff bekommen. Bei der Silent Installation gibt es keinerlei Benutzereingaben; alle Informationen, die der Installationsprozess benötigt, werden in einer Parameterdatei (response file) definiert. Die Silent Installation ist sowohl für Basisinstallationen (meist mit InstallationsCDs) als auch für Patchsets möglich. Die unten angeführten Beispiele beziehen sich auf die Installation der Oracle Database 10g-Komponenten; Silent Installationen sind aber auch für andere Komponenten möglich und machen insbesondere bei Client-Software Sinn, da für diesen Fall viel mehr Installationen anfallen als für Serverkomponenten.
64
Installation und Aufbau einer Datenbank
Vorlagen für Parameterdateien befinden sich grundsätzlich auf den Installationsmedien im Verzeichnis response. Meist gibt es je eine Datei pro Installationsart, also z.B. custom.rsp für eine Custom Installation der Enterprise Edition oder standard.rsp für eine Installation der Standard Edition. Diese Dateien müssen dann zunächst auf die eigene Umgebung angepasst werden. Sie enthalten einige Variablen; hier ein Beispiel inklusive des Originalkommentars: #-----------------------------------------------------------------#Name : ORACLE_HOME #Datatype : String #Description: Complete path of the Oracle Home. #Example: ORACLE_HOME = "C:\OHOME1" #-----------------------------------------------------------------ORACLE_HOME=
Die Zeile mit der Variablen muss angepasst werden, d.h., man trägt den gewünschten Wert ein: ORACLE_HOME = "C:\OraBase\Product\O1010"
Anstelle der – recht aufwändigen – Anpassung der Vorlagen kann man sich die Parameterdatei auch während einer interaktiven Installation erzeugen lassen. Dazu verwendet man folgenden Installer-Aufruf:14 runInstaller –record –destinationFile
gibt die zu erstellende Parameterdatei (Empfehlung: mit vollständigem
Pfad) an. Die erstellte Parameterdatei kann eventuell noch eigenen Wünschen angepasst werden. Die eigentliche Installation mit Hilfe der Parameterdatei erfolgt schließlich mit: runInstaller –silent –responseFile
Der Universal Installer schreibt wie gewohnt sämtliche Log-Informationen in das logs-Unterverzeichnis des Inventorys. Allerdings gibt es auf dem Bildschirm (Unix: stdout/stderr) eine gut lesbare Zusammenfassung der Installation mit allen durchgeführten Checks, so dass sich ein Aufruf folgender Art empfiehlt: runInstaller –silent –responseFile 2>&1 | tee screen.log
Hierdurch kann man sowohl die Installation auf dem Bildschirm verfolgen als auch später noch einmal nachvollziehen. Die komplette Ausgabe wäre an dieser Stelle zu umfangreich; daher hier nur ein Beispiel für einen der Prerequisite Checks: Performing check for GLIBC Checking recommended glibc version Expected result: 2.2.4.31.7 Actual Result: 2.3.2.95.6 Check complete. The overall result of this check is: Passed Check complete: Passed
14 Bitte bei den Parametern peinlich genau auf Groß-/Kleinschreibung achten!
Software-Installation
65
Bei einer Installation unter Unix müssen nach dem Installer-Aufruf noch ein oder mehrere Aktionen als root durchgeführt werden: 1. Falls es sich um die erste Installation auf dem System handelt, muss die Datei /etc/oraInst.loc erzeugt und mit Inhalt gefüllt werden. Dies wird durch das Skript orainstRoot.sh erreicht, das während der Installation im Hauptverzeichnis des Inventorys abgelegt wird. 2. Im ORACLE_HOME-Verzeichnis wird das Skript root.sh abgelegt, das weitere Strukturen im Unix-Verzeichnisbaum sowie bei Single-Node-Installationen die entsprechende »kleine« Variante der Cluster-Services erzeugt. Es ist möglich, mit einem späteren Aufruf aus einer grafischen Benutzerumgebung die von Oracle empfohlenen Konfigurationswerkzeuge aufzurufen. Wenn man jedoch die Oracle Software-Installation bereits automatisiert, dann macht es wahrscheinlich mehr Sinn, die Oracle Net-Parameterdateien ebenfalls per Skript auf die Maschinen zu bringen.
2.3.5 Cluster Ready Services Die Cluster Ready Services (CRS) werden auf einer eigenen CD ausgeliefert und stellen die Oracle Clusterware dar. Sie sind nicht etwa als Plug-in für bestehende Cluster-Systeme gedacht, sondern enthalten alles, was die Oracle Database für den Betrieb eines Datenbank-Clusters (mit RAC) benötigt. Da Cluster-Software mit Funktionen wie Bereitstellung von virtuellen IP-Adressen, Quorum, Heartbeat usw. recht tief ins Betriebssystem eingreift, sind die Abhängigkeiten zu Betriebssystem und Hardware in diesem Bereich besonders hoch. Bei der Installation ist darauf zu achten, dass die im betriebssystemspezifischen Installations-Handbuch beschriebenen Voraussetzungen sehr genau eingehalten werden. Falls dies nicht geschieht, wird entweder die weitere Installation fehlschlagen oder sich zumindest sehr schwierig gestalten; außerdem kann das Verhalten des späteren RAC-Systems Unregelmäßigkeiten (z.B. Performance-Probleme bei der Verwendung der falschen Netzwerkschnittstellen für die Cluster-Kommunikation) aufweisen. Bei der Installation der CRS werden sowohl interne als auch externe Netzwerke (mit eigenen Schnittstellen) definiert. Das interne Netzwerk ist ausschließlich für die Cluster-Kommunikation vorgesehen, während das externe Netzwerk für die Anbindung der Clients vorgesehen ist. Die fest mit den Knoten verbundenen primären IP-Adressen werden ergänzt durch virtuelle IP-Adressen, die für die Verbindungen von Clients benutzt werden. Die Definition des Clusters mit all seinen Adressen und Beziehungen wird in die Cluster-Registrierung eingetragen. Dies ist entweder eine eigene Raw Partition oder eine Datei im Cluster-Dateisystem, natürlich grundsätzlich im Zugriff von allen Cluster-Knoten.
66
Installation und Aufbau einer Datenbank
Die CRS selber sind unter MS-Windows als Dienst implementiert (und automatisch gestartet); unter Unix wird der Start der entsprechenden Prozesse im Betriebssystemstart verankert. Ein kill-Kommando reicht nicht aus, um die CRS zu stoppen: Das Betriebssystem startet nach kurzer Zeit automatisch Prozesse nach. Abhilfe schafft erst der Aufruf: /etc/init.d/init.cssd stop
Mit dem Parameter start werden die Prozesse erneut gestartet. Diese Vorgehensweise braucht man, wenn die CRS gepatched werden sollen.
2.4
Datenbankkonfiguration
Nachdem Sie die Software erfolgreich installiert und eventuelle Patches nachgespielt haben, ist es jetzt an der Zeit, die Datenbanken anzulegen. Tipp: Installieren Sie alle Patches, bevor Sie die Datenbanken anlegen, ansonsten müssen Sie nach der Patch-Installation die Datenbanken ebenfalls upgraden. Daher sollten Sie immer überlegen, ob die sofortige Konfiguration der Datenbank bei der SoftwareInstallation sinnvoll ist. Die einfachste Form ist, den Datenbank-Konfigurations-Assistenten aufzurufen, da dieser für jede Version und jeden Patch angepasst ist. Alternativ kann man natürlich auch eigene Skripte benutzen, hier sollte man jedoch darauf achten, diese von Zeit zu Zeit an die neuen Anforderungen anzupassen. Dies gilt speziell für die Oracle 10g-Konfiguration, da ein unter Oracle9i oder älter erstelltes Skript unter 10g nicht lauffähig ist (es fehlt u.a. der SYSAUX-Tablespace).
2.4.1 Database Configuration Assistant (DBCA) Unter MS-Windows sollten Sie im Startmenü unter PROGRAMME → ORACLE → CONFIGURATION AND MIGRATION TOOLS den DATABASE CONFIGURATION ASSISTANT finden. Unter Unix setzen Sie bitte Ihr ORACLE_HOME und den Pfad entsprechend, und rufen Sie dbca auf, z.B. in der Form: % % % %
ORACLE_BASE=/app/oracle ORACLE_HOME=$ORACLE_BASE/product/10.1.0/db_1 PATH=$PATH:$ORACLE_HOME/bin dbca
Listing 2.3: Aufruf dbca unter Unix (Bourne-Shell)
Nach dem Aufruf werden Sie wieder willkommen geheißen und können im Schritt 1 auswählen, ob Sie eine neue Datenbank erstellen oder eine Vorlage (Template) verwalten wollen. Die Verwaltung von Vorlagen bietet sich an, wenn Sie mehrere Datenbanken in der gleichen Form (unterschiedliche Namen, aber gleiche Struktur) anlegen wollen.
Datenbankkonfiguration
67
Für die Erstinstallation wählen Sie hier DATENBANK ERSTELLEN aus und gelangen bei Schritt 2 zu einer Auswahlliste wie in Abbildung 2.12.
Abbildung 2.12: Auswahlliste Datenbankvorlagen
Wenn Sie eigene Vorlagen erstellt haben, werden diese ebenfalls hier dargestellt. Der rechte Teil (»Umfasst Datendateien«) gibt an, dass diese Datenbank nicht neu erstellt wird, sondern dass es bereits eine vorkonfigurierte Datenbank gibt, die nur noch an die entsprechende Stelle kopiert wird (die Vorlagen befinden sich im Verzeichnis ORACLE_HOME/assistants/dbca/templates). Dadurch kann die Installation in wenigen Minuten erfolgen, allerdings mit dem bereits erwähnten Nachteil, dass auch Komponenten installiert werden, die Sie nicht benötigen bzw. für die Sie gar keine Lizenzen besitzen. Die drei Vorlagen (ALLGEMEINE AUFGABEN, DATA WAREHOUSE, TRANSAKTIONSVERARBEITUNG) unterscheiden sich nur hinsichtlich der Größe der Datenbankdateien sowie je nach Betriebssystem der Größe der Datenbankblöcke (db_block_size). Im Schritt 3 müssen Sie den Namen der Datenbank sowie den Namen der Instanz (SID) angeben. In der Regel werden beide Namen identisch sein, daher trägt der Wizard den angegebenen Datenbanknamen automatisch als Instanznamen ein. Eine Ausnahme bilden hierbei die Real Application-Cluster-Datenbanken, da dort mehrere Instanzen auf eine Datenbank zugreifen.
68
Installation und Aufbau einer Datenbank
Schritt 4 enthält die Informationen zur Konfiguration des Oracle Enterprise Managers.
Abbildung 2.13: Verwaltungsoptionen
Wenn Sie den Enterprise Manager Grid Control verwenden und bereits einen entsprechenden Agenten auf dem System installiert haben, können Sie die Datenbank in dieses Management Framework einhängen. In unserem Beispiel in Abbildung 2.13 kann nur der Enterprise Manager Database Control benutzt werden, da keine Agenten installiert sind. Für kleinere Umgebungen reicht der Database Control sicherlich aus und sollte daher an dieser Stelle mit installiert werden. In großen Umgebungen sollte man den Enterprise Manager Grid Control verwenden und daher entweder einen bereits installierten Agenten einbinden oder an dieser Stelle auf die Konfiguration des Enterprise Managers verzichten. Da der Enterprise Manager bereits vorkonfigurierte Alarme verwendet, kann an dieser Stelle entschieden werden, ob im Fehlerfall E-Mails versendet werden sollen. Außerdem kann hier schon der Recovery Manager parametriert werden, so dass täglich zu einer festgelegten Zeit über den Enterprise Manager ein Backup der Datenbank erfolgt.
Datenbankkonfiguration
69
In Schritt 5 können dann die Passwörter für die Standardschemata der Datenbank gesetzt werden. Im Gegensatz zur Basisinstallation sind hier auch die »alten« Passwörter »manager« oder »change_on_install« möglich, Sie sollten aber vielleicht doch langsam von diesen Passwörtern Abschied nehmen und sicherheitshalber andere verwenden. In Schritt 6 wird das Speicherungsverfahren gewählt.
Abbildung 2.14: Speicherungsoptionen
Die Speicherung im Dateisystem ist sicherlich immer noch erste Wahl, d.h., die Datenbankdateien werden in einem oder mehreren Verzeichnissen gespeichert. Sie sollten darauf achten, dass es sich hierbei um neu formatierte Dateisysteme handelt, in denen ausschließlich Datenbankdateien gespeichert werden, da es sonst auf Betriebssystemebene zu Fragmentierungen kommen kann. Die Speicherung auf so genannten Raw Devices hat im Unix-Umfeld immer noch große Anhänger, speziell wenn es um die optimale I/O-Performance geht, da hier jeglicher Betriebssystem-Overhead ausgeschaltet wird. Messungen auf unterschiedlichen Betriebssystemen zeigen, dass durch die Speicherung auf Raw Devices ein bis zu 20% besserer I/O-Durchsatz erreicht werden kann. Neu ist in Oracle 10g die Möglichkeit, die Dateien im Automatic Storage Management (ASM) zu speichern.
70
Installation und Aufbau einer Datenbank
Nähere Informationen zu den Speicherungsarten finden Sie in Kapitel 3.9. In der Regel werden Sie hier die Speicherung im Dateisystem auswählen und kommen dann in Schritt 7 zur Auswahl des Speicherortes. Bei großen Datenbanken empfiehlt es sich, unterschiedliche Dateisysteme für die Speicherung der Dateien auszuwählen, bei kleineren Datenbanken kann hier die Option GEMEINSAMEN SPEICHERORT FÜR ALLE DATENBANKDATEIEN VERWENDEN ausgewählt werden. Damit muss nur noch das Verzeichnis angegeben werden, in das diese Dateien installiert werden sollen. Während der Installation wird in diesem Verzeichnis ein Unterverzeichnis mit dem Namen der Datenbank erstellt, und in diesem Verzeichnis werden alle Datenbankdateien angelegt. Alternativ kann die Speicherung als ORACLE MANAGED FILES erfolgen, wobei dann keine Namen für die Dateien angegeben werden müssen, sondern Oracle diese Dateien verwaltet. Hierzu finden Sie ebenfalls in Kapitel 3.9 nähere Informationen. Neu ist in der Version 10g der Schritt 8, die Wiederherstellungsoptionen für die Datenbank. Hier werden das Verzeichnis und die Größe des Flash-Recovery-Bereiches angegeben. Achten Sie bitte darauf, dass die Größe für Ihre Anwendung ausreichend bemessen ist, die vorgegebenen 2 GB reichen in den wenigsten Fällen aus. Sie sollten hier ein eigenes Dateisystem mit einer ausreichenden Größe zur Verfügung stellen.
Abbildung 2.15: Wiederherstellungsoptionen
Datenbankkonfiguration
71
An dieser Stelle können Sie bereits die Archivierung aktivieren, allerdings ist das in den seltensten Fällen sinnvoll, da es wahrscheinlich noch einige Zeit dauern wird, bis Ihre Datenbank in Produktion geht, und erst zu dem Zeitpunkt ist eine Archivierung sinnvoll bzw. erforderlich. Nähere Informationen zu diesen Optionen finden Sie in Kapitel 10. Schritt 9 gibt die möglichen Komponenten an, die in dieser Datenbank installiert werden können. Die Optionen, die Sie bei der Software-Installation mit ausgewählt haben oder die zum Standardumfang der Installation gehören, können Sie hier auswählen, die anderen sind ausgegraut.
Abbildung 2.16: Datenbankkomponenten
Wie bereits erwähnt, sollten Sie sich vorher informieren, ob Sie die entsprechenden Komponenten lizenziert haben. Abbildung 2.16 zeigt, dass die Oracle OLAPOption nicht installiert worden ist, die Oracle Data-Mining-Komponente lässt sich jedoch installieren, ist aber ebenfalls kostenpflichtig. Die Beispielschemata können – obwohl sie zum Standardumfang gehören – nicht ausgewählt werden, da diese nicht installiert worden sind. Die Skripte und Anwendungen sind nicht auf der Basis-CD, sondern müssen über die Companion-CD nachinstalliert werden. Unter dem Punkt STANDARD-DATENBANKKOMPONENTEN befindet sich die Liste der nicht kostenpflichtigen Pakete, die je nach Bedarf mit installiert werden können.
72
Installation und Aufbau einer Datenbank
Abbildung 2.17: Standard-Datenbankkomponenten
Ob Sie in jedem Fall Intermedia und die XML DB brauchen, sollten Sie von Fall zu Fall entscheiden, dabei aber immer beachten, dass ein Upgrade oder eine PatchInstallation durch diese Komponenten erheblich länger dauern kann. Bei der Installation der Oracle Java Virtual Machine (JVM) scheiden sich die Geister. Einerseits gibt es mittlerweile einige Oracle-Anwendungen, die diese Komponente benutzen, andererseits sind Installation oder Upgrade gerade für Java eine langwierige Prozedur. Sie müssen entscheiden, welchen Nutzen Sie aus der Installation ziehen. In Schritt 10 geht es um die Datenbankparameter.
Abbildung 2.18: Serverparameter
Datenbankkonfiguration
73
Zunächst wird die Größe der SGA (System Global Area) und der PGA (Process Global Area) angegeben. Diese beiden Parameter bestimmen, wie viel Hauptspeicher auf dem Server für den Betrieb der Datenbank verwendet werden soll. Alternativ zur Angabe dieser beiden Parameter kann auch einfach ein Prozentsatz des gesamten physikalischen Hauptspeichers angegeben werden. Im Reiter SKALIERUNG können die Blockgröße (Standard 8 KB) und die maximale Anzahl von Prozessen (Standard 150) geändert werden. Der Reiter ZEICHENSÄTZE dient zur Auswahl des Datenbank-Zeichensatzes und des länderspezifischen Zeichensatzes (National Characterset). Der Reiter VERBINDUNGSMODUS gibt abschließend an, ob je Datenbankverbindung ein separater Prozess erzeugt werden soll (Dedicated Server) oder ob sich eine Anzahl von Verbindungen einen Prozess teilen soll (Shared Server). Im Schritt 11 der Datenbankkonfiguration schließlich können die Datenbankdateien parametriert werden. Wenn Sie für alle Dateien ein Verzeichnis ausgewählt haben oder die Oracle-Managed Files verwenden, bleibt Ihnen hier nicht viel zu tun. Wenn Sie allerdings die Datendateien auf unterschiedliche Filesysteme verteilen wollen oder mit Raw Devices arbeiten, dann können Sie hier die notwendigen Einstellungen vornehmen. Folgende Einstellungen sollten Sie aber in jedem Fall vornehmen. Standardmäßig sind die Datendateien mit der Option Autoextend angelegt, wodurch sich diese Dateien bei Erreichen der vorgegebenen Größe automatisch um eine bestimmte Größe erweitern; und dieses bis zur maximal möglichen Größe je Betriebssystem.
Abbildung 2.19: Autoextend TEMP-Tablespace
74
Installation und Aufbau einer Datenbank
In Abbildung 2.19 bedeutet dies, dass sich die Datei des Tablespaces TEMP immer um 640 KB erweitert, wenn zusätzlicher Platz für Sortierungen benötigt wird. Die maximale Größe ist nicht beschränkt, sodass die Datei auf dem dargestellten MS-Windows-System bei einer Standard-Blockgröße von 8 KB 32 GB groß werden kann, bei 16 KB Blockgröße 64 GB. Da es nur schwer möglich ist, einen einmal allokierten Platz wieder freizugeben, könnte diese Einstellung zu Problemen im Produktionsbetrieb führen. Daher empfehlen wir, wenn Sie die Option Autoextend für Datendateien benutzen, dass Sie die maximale Größe entsprechend beschränken, so dass die Datendateien zwar wachsen können, Sie aber immer einen Puffer im Filesystem behalten. Außerdem sollten Sie die Erweiterungen (Inkrement) so wählen, dass diese Funktion nur selten ausgeführt wird, da dies ein zusätzlicher Overhead beim Betrieb der Datenbank ist. Die oben angegebene Größe von 640 KB für den TEMP-Tablespace ist sicherlich sehr ungünstig gewählt, da in diesem Tablespace jedes Segment normalerweise 1 MB groß ist. Sie sollten daher folgende Inkrement-Einstellungen verwenden: Für Dateien bis ca. 1 GB Größe: Inkrement = 10 MB Für Dateien von 1 bis 10 GB Größe: Inkrement = 100 MB Darüber: Inkrement = 1000 MB Damit ist die Konfiguration der Datenbank abgeschlossen, und der Installation steht nichts mehr im Wege. In Schritt 12 können Sie jetzt die Datenbank direkt erstellen lassen, die Konfiguration als Vorlage speichern oder die Konfiguration als Skripte abspeichern.
Abbildung 2.20: Erstellen der Datenbank
Datenbankkonfiguration
75
Das Sichern der Skripte ist sicherlich in jedem Fall zu empfehlen, da hiermit zunächst einmal eine nachvollziehbare Dokumentation entsteht und zusätzlich die Möglichkeit geschaffen wird, eine fehlerhafte Installation zu wiederholen, ohne nochmals auf den DBCA zuzugreifen. Leider mussten wir immer wieder feststellen, dass die Speicherung der Skripte nicht mit dem übereinstimmt, was passiert, wenn man die Datenbank direkt erstellen lässt. Zum Abschluss erhalten Sie eine HTML-Datei mit der Konfiguration Ihrer Datenbank. Vergessen Sie nicht, diese abzuspeichern. Im folgenden Kapitel werden wir die erzeugten Skripte für eine skriptbasierte Installation benutzen.
2.4.2 Skriptbasierte Installation Für die Verwendung von Skripten bietet es sich an, entsprechend der Oracle Flexible Architecture entsprechende Verzeichnisse anzulegen und die Skripte im Unterverzeichnis create oder scripts abzulegen. Die aus dem DBCA erstellten Skripte werden, wenn Sie die Variable ORACLE_BASE gesetzt haben, im Verzeichnis scripts abgelegt (siehe Abbildung 2.7 und 2.20). In diesem Verzeichnis finden Sie die Dateien zur Erstellung der notwendigen Verzeichnisse und der Datenbank. Das folgende Beispiel ist für die Datenbank WIN10G unter MS-Windows erstellt worden. Bis auf die Lage der Datenbankdateien und der Verwendung einer Batch-Datei anstelle eines Shell-Skriptes ist es aber ebenso unter Unix lauffähig. WIN10G.bat mkdir D:\oracle\admin\WIN10G\bdump mkdir D:\oracle\admin\WIN10G\cdump mkdir D:\oracle\admin\WIN10G\create mkdir D:\oracle\admin\WIN10G\pfile mkdir D:\oracle\admin\WIN10G\udump mkdir D:\oracle\flash_recovery_area mkdir D:\oracle\oradata\WIN10G mkdir D:\oracle\product\10.1.0\db1\database set ORACLE_SID=WIN10G D:\oracle\product\10.1.0\db1\bin\oradim.exe -new -sid WIN10G -startmode manual -spfile D:\oracle\product\10.1.0\db1\bin\oradim.exe -edit -sid WIN10G -startmode auto -srvcstart system D:\oracle\product\10.1.0\db1\bin\sqlplus /nolog @D:\oracle\admin\WIN10G\scripts\WIN10G.sql Listing 2.4: WIN10G.bat
Zunächst werden die benötigten Verzeichnisse erstellt. Mit dem Befehl oradim, den Sie immer mit vollem Pfad aufrufen sollten, wird der Diensteintrag in MS-Windows durchgeführt. Der erste Aufruf erstellt den Dienst WIN10G und besagt, dass dieser Dienst die Serverparameter aus einer Serverparameterdatei (SPFILE) erhalten soll.
76
Installation und Aufbau einer Datenbank
Der zweite Aufruf veranlasst, dass der Dienst beim Starten des Systems automatisch unter dem Benutzer Lokales System gestartet werden soll. Als Letztes erfolgt der Aufruf von sqlplus mit dem SQL-Skript WIN10G.sql. Auch beim Aufruf von sqlplus sollten Sie darauf achten, die richtige Version zu verwenden. WIN10G.sql set verify off PROMPT specify a password for sys as parameter 1; DEFINE sysPassword = &1 PROMPT specify a password for system as parameter 2; DEFINE systemPassword = &2 PROMPT specify a password for sysman as parameter 3; DEFINE sysmanPassword = &3 PROMPT specify a password for dbsnmp as parameter 4; DEFINE dbsnmpPassword = &4 host D:\oracle\product\10.1.0\db1\bin\orapwd.exe file=D:\oracle\product\10.1.0\db1\database\PWDWIN10G.ora password=&&sysPassword force=y @D:\oracle\admin\WIN10G\scripts\CreateDB.sql @D:\oracle\admin\WIN10G\scripts\CreateDBFiles.sql @D:\oracle\admin\WIN10G\scripts\CreateDBCatalog.sql @D:\oracle\admin\WIN10G\scripts\emRepository.sql @D:\oracle\admin\WIN10G\scripts\postDBCreation.sql Listing 2.5: WIN10G.sql
Zunächst werden hier die Passwörter für die vordefinierten Benutzer abgefragt. Anschließend wird mit dem Befehl orapwd eine neue Passwortdatei erstellt, die für die Remote-Administration der Datenbank erforderlich ist. Zum Schluss werden nacheinander die Skripte zur Erstellung der Datenbank ausgeführt. CreateDB.sql connect SYS/&&sysPassword as SYSDBA set echo on spool D:\oracle\product\10.1.0\db1\assistants\dbca\logs\CreateDB.log startup nomount pfile="D:\oracle\admin\WIN10G\scripts\init.ora"; CREATE DATABASE "WIN10G" /* 1. */ MAXINSTANCES 8 /* 2. */ MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100 DATAFILE 'D:\oracle\oradata\WIN10G\system01.dbf' /* 3. */ SIZE 300M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE 500M EXTENT MANAGEMENT LOCAL SYSAUX /* 4. */ DATAFILE 'D:\oracle\oradata\WIN10G\sysaux01.dbf'
Datenbankkonfiguration
77
SIZE 120M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE 500M DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE 'D:\oracle\oradata\WIN10G\temp01.dbf' SIZE 100M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE 500M UNDO TABLESPACE UNDOTBS1 DATAFILE 'D:\oracle\oradata\WIN10G\undotbs01.dbf' SIZE 100M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE 500M CHARACTER SET WE8ISO8859P15 /* 5. */ NATIONAL CHARACTER SET AL16UTF16 LOGFILE /* 6. */ GROUP 1 ('D:\oracle\oradata\WIN10G\redo01.log') SIZE 10240K, GROUP 2 ('D:\oracle\oradata\WIN10G\redo02.log') SIZE 10240K, GROUP 3 ('D:\oracle\oradata\WIN10G\redo03.log') SIZE 10240K USER SYS IDENTIFIED BY "&&sysPassword" /* 7. */ USER SYSTEM IDENTIFIED BY "&&systemPassword"; spool off Listing 2.6: CreateDB.sql
In Schritt 1 erfolgt die Anmeldung an die Datenbank als SYSDBA mit dem im Skript WIN10G.sql angegebenen Passwort. Diese Anmeldung kann auf MS-Windows-Systemen nur erfolgen, wenn der Dienst bereits gestartet ist. Mit dem Befehl spool werden die folgenden SQL-Befehle protokolliert. Das Protokollverzeichnis ist %ORACLE_HOME%\assistants\dbca\logs, wodurch manchmal eine gewisse Verwirrung herrscht, wo die Dateien zu finden sind. Eventuell sollten Sie das Verzeichnis für alle folgenden SQL-Skripte anpassen. Mit dem Befehl STARTUP NOMOUNT wird die Instanz gestartet, die Parameter hierfür werden aus der ebenfalls in diesem Verzeichnis befindlichen Initialisierungsdatei init.ora genommen. Mit dem Befehl CREATE DATABASE wird die Datenbank erstellt. Im Folgenden werden die wesentlichen Befehlsteile beschrieben. Diese sind im Skript mit /* Nr. */ gekennzeichnet. 1. CREATE DATABASE “WIN10G“ gibt an, wie die Datenbank heißen soll. 2. Die MAX-Werte bezeichnen Limitierungen in der Kontrolldatei der Datenbank; damit wird in dieser Datei ein entsprechender Platz allokiert. Je größer die Werte, umso mehr Platz muss reserviert werden, aber umso länger dauert u.U. das Einfügen oder Suchen von Informationen. Eine spätere Änderung ist zwar möglich, allerdings nur indem eine neue Kontrolldatei erzeugt wird, was mit einem gewissen Aufwand verbunden ist. Die Parameter im Einzelnen: – MAXINSTANCES 8: Diese Datenbank kann beim Betrieb als Real Application Cluster (RAC) maximal acht Instanzen besitzen. In dem meisten Fällen kann hier 1 eingetragen werden, wenn kein RAC benutzt wird.
78
Installation und Aufbau einer Datenbank
– MAXLOGHISTORY 1: Dieser Parameter ist nur im Umfeld einer Real-ApplicationCluster-Datenbank interessant, und zwar für das so genannte Cross Instance Recovery. In diesen Fällen sollte der Wert laut Oracle-Dokumentation ein Vielfaches des Parameters MAXINSTANCES sein. Warum dieser Wert bei einer Konfiguration über den dbca auf 1 steht, entzieht sich derzeit unserer Kenntnis. Bei einer Single-Instance-Installation wird der Parameter dynamisch angepasst. – MAXLOGFILES 16: Maximale Anzahl von Redo-Log-Gruppen. Dieser Wert bezieht sich auf alle Online-Redo-Log-Dateien, inklusive einer eventuellen logischen Spiegelung über Logfile-Member. – MAXLOGMEMBERS 3: Maximal ist eine dreifache Spiegelung der Online-Redo-LogDateien möglich. Der Wert ist absolut ausreichend. – MAXDATAFILES 100: Diese Datenbank kann maximal 100 Datendateien enthalten. In dem meisten Fällen reicht diese Größe aus, da eine Datendatei mehrere GB groß sein darf. 3. Als Nächstes wird der SYSTEM-Tablespace angelegt. Dieser Tablespace hat keine explizite Tablespace-Klausel, sondern es werden nur der Name und das Verzeichnis der zugehörigen Datendatei angegeben. 4. Die weiteren Tablespaces, die für den Minimalbetrieb einer Datenbank notwendig sind, werden erstellt. Dazu gehören der in Oracle 10g neue Tablespace SYSAUX, der Tablespace für temporäre Objekte TEMP und der Tablespace für die UNDOSegmente. Bei allen Tablespaces ist die Option REUSE angegeben. Da damit eine bereits vorhandene Datei überschrieben wird, sollte die Option mit Vorsicht genutzt werden. 5. Der Datenbank-Zeichensatz (hier: westeuropäischer nach ISO 8859 normierter Zeichensatz mit Euro-Symbol = WE8ISO8859P15) und der nationale Zeichensatz der Datenbank (AL16UTF16) werden angegeben. 6. Es werden drei Online-Redo-Log-Dateien mit einer Größe von je 10 MB angelegt. Eine Spiegelung (Member) erfolgt nicht. 7. Den Datenbankschemata SYS und SYSTEM wird das im Skript WIN10G.sql eingegebene Passwort zugewiesen. CreateDBFiles.sql connect SYS/&&sysPassword as SYSDBA set echo on spool D:\oracle\admin\WIN10G\scripts\CreateDBFiles.log CREATE TABLESPACE "USERS" LOGGING DATAFILE 'D:\oracle\oradata\WIN10G\users01.dbf' SIZE 100M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE 500M EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO ; ALTER DATABASE DEFAULT TABLESPACE "USERS"; spool off Listing 2.7: CreateDBFiles.sql
Datenbankkonfiguration
79
Mit diesem SQL-Skript wird der Tablespace USERS angelegt, der anschließend Standard-Tablespace für alle Datenbankbenutzer wird. In diesem Beispiel erfolgt die Protokollierung in das gleiche Verzeichnis, in dem auch die Skripte liegen, um so eine bessere Kontrolle zu haben. CreateDBCatalog.sql connect SYS/&&sysPassword as SYSDBA set echo on /* Besser set echo off */ spool D:\oracle\admin\WIN10G\scripts\CreateDBCatalog.log @D:\oracle\product\10.1.0\db1\rdbms\admin\catalog.sql; @D:\oracle\product\10.1.0\db1\rdbms\admin\catblock.sql; @D:\oracle\product\10.1.0\db1\rdbms\admin\catproc.sql; @D:\oracle\product\10.1.0\db1\rdbms\admin\catoctk.sql; @D:\oracle\product\10.1.0\db1\rdbms\admin\owminst.plb; connect SYSTEM/&&systemPassword @D:\oracle\product\10.1.0\db1\sqlplus\admin\pupbld.sql; connect SYSTEM/&&systemPassword set echo on spool D:\oracle\admin\WIN10G\scripts\sqlPlusHelp.log /* Löschen */ @D:\oracle\product\10.1.0\db1\sqlplus\admin\help\hlpbld.sql helpus.sql; spool off spool off /* Löschen */ Listing 2.8: CreateDBCatalog.sql
In diesem Skript werden das externe Data Dictionary sowie zusätzliche Pakete und Hilfstabellen angelegt. Tipp: Ändern Sie den ersten Befehl set echo on auf set echo off, da dadurch die Protokollierung verkleinert und die Laufzeit dieses Skriptes erheblich reduziert wird. Die hier aufgerufenen Skripte sind: 1. catalog.sql: Mit diesem Skript wird das externe Data Dictionary erstellt. 2. catblock.sql: Es werden Views erzeugt, um blockierende Prozesse anzeigen zu können (so genannte Blocking/Waiting Locks). 3. catproc.sql: Das Skript erstellt die Basispakete für die Benutzung von PL/SQL. 4. catoctk.sql: Es werden Pakete für ein kryptografisches Toolkit und die Erzeugung von Zufallszahlen erstellt. 5. owminst.plb: Die Prozeduren und Tabellen für den Oracle Workspace Manager werden eingespielt. 6. pupbld.sql: Für das Werkzeug SQL*Plus wird die PRODUCT_USER_PROFILE-Tabelle angelegt. Die Tabelle kann benutzt werden, um SQL*Plus-Benutzern die Ausführung von Befehlen zu erlauben oder zu verweigern.
80
Installation und Aufbau einer Datenbank
7. hlpbld.sql: Ebenfalls für das Werkzeug SQL*Plus werden die englischen Hilfetexte erstellt, die mit dem Befehl HELP angezeigt werden können. Leider sind bei der Erstellung dieses Skriptes über den DBCA die Spool-Informationen etwas verrutscht, daher empfiehlt es sich, den zweiten SPOOL-Befehl und den letzten SPOOL OFF-Befehl zu löschen. postDBCreation.sql connect SYS/&&sysPassword as SYSDBA set echo on spool D:\oracle\admin\WIN10G\scripts\postDBCreation.log connect SYS/&&sysPassword as SYSDBA /* Löschen */ set echo on /* Löschen */ create spfile='D:\oracle\product\10.1.0\db1\database\spfileWIN10G.ora' FROM pfile='D:\oracle\admin\WIN10G\scripts\init.ora'; shutdown immediate; connect SYS/&&sysPassword as SYSDBA startup ; select 'utl_recomp_begin: ' || to_char(sysdate, 'HH:MI:SS') from dual; execute utl_recomp.recomp_serial(); select 'utl_recomp_end: ' || to_char(sysdate, 'HH:MI:SS') from dual; spool D:\oracle\admin\WIN10G\scripts\postDBCreation.log Listing 2.9: postDBCreation.sql
Warum der Connect-Befehl hier doppelt vorhanden ist, weiß wahrscheinlich nur das DBCA. Also können der zweite connect und das set echo on einfach gelöscht werden. Mit dem Befehl create spfile … wird aus der init.ora eine Serverparameter-Datei erzeugt. Anschließend wird die Datenbank heruntergefahren und durch den Befehl startup ohne Parameter mit der neuen Parameterdatei gestartet. Mit dem Befehl execute utl_recomp_recomp_serial() werden alle DatenbankPackages noch einmal kompiliert. emRepository.sql connect SYS/&&sysPassword as SYSDBA set echo off spool D:\oracle\admin\WIN10G\scripts\emRepository.log @D:\oracle\product\10.1.0\db1\sysman\admin\emdrep\sql\emreposcre D:\oracle\product\10.1.0\db1 SYSMAN &&sysmanPassword TEMP ON; spool off Listing 2.10: emRepository.sql
Dieses optionale Skript legt das Repository für den Oracle Enterprise Manager Database Control an.
Patches und Patch-Sets
2.5
81
Patches und Patch-Sets
Zunächst einmal muss man bei der Installation von Patches zwischen einem Interim-Patch und einem Patch-Set unterscheiden. Prinzipiell werden Fehlerbehebungen immer in Patch-Sets angeboten. Wenn ein Kunde einen Bugfix benötigt, muss er zunächst das letztgültige Patch-Set installiert haben. Wenn der Fehler damit nicht behoben ist, kann er einen Interim-Patch (auch »One-off« Patch genannt) anfordern. Ein Interim-Patch wird immer auf Basis des aktuellsten Patch-Sets aufgesetzt, was in machen Umgebungen zu Problemen führen kann, da ein Patch-Set in der Regel eine längere Auszeit für die Anwendung erfordert. Zusätzlich kann es erforderlich sein, für die Fehlerbehebung zunächst einen Diagnostic-Patch einzuspielen, mit dem dann der eigentliche Fehler lokalisiert werden kann. Bitte erwarten Sie an dieser Stelle kein generelles Kochrezept für das Einspielen von Patches, da es ein solches nicht gibt und geben kann. Es ist ein Unterschied, ob Sie z.B. den Universal Installer, der Datenbank-Kernel oder der Oracle Cluster Ready Service angepasst werden muss. Daher sollten Sie in jedem Fall zunächst die mit dem Patch oder Patch-Set mitgelieferte Dokumentation lesen. In jedem Fall sollten Sie aber vor der Installation eines Patches ein vollständiges Backup Ihrer Datenbank und der Software durchführen.
2.5.1 Patch-Sets Patch-Sets werden in unregelmäßigen Abständen herausgegeben und sind kumulativ, d.h., Sie müssen nur die letzte Version installieren, da diese alle Informationen vorheriger Patch-Sets enthält. Beim Einspielen eines Patch-Sets ändert sich die Versionsnummer der Oracle-Software an der vierten Stelle. Bei der Entstehung dieses Buches gab es für MS-Windows das Basis-Release 10.1.0.2 und das Patch-Set 10.1.0.4. Die Installation des Patch-Sets erfolgt über den Universal Installer, wobei es vorkommen kann, dass Sie zunächst den Universal Installer selbst anpassen müssen, bevor Sie mit der eigentlichen Installation beginnen können. Eine unschöne Einschränkung gibt es nach der Installation des Patch-Sets 10.1.0.3. Sie können nach dem Einspielen keine Datenbankoptionen mehr nachinstallieren, sondern erhalten in einem solchen Fall die Fehlermeldung, dass die installierte Version neuer ist als diejenige, die Sie nachinstallieren wollen. Der Fehler ist bei Oracle bekannt, und unter der Bug-Nummer 3870317 können Sie aus dem Oracle-Metalink einen Universal Installer laden, mit dem eine Nachinstallation von Optionen möglich ist. Generell gilt aber bei Nachinstallationen, dass Sie anschließend nicht vergessen sollten, das Patch-Set nochmals für diese Komponente durchlaufen zu lassen. Die Installation eines Patch-Sets gliedert sich in folgende Schritte: 1. Preinstallation: Herunterfahren der Datenbank und zugehöriger Komponenten, wie z.B. Listener, Agents oder Database Control.
82
Installation und Aufbau einer Datenbank
2. Installation: Das Patch-Set wird mit dem mitgelieferten Universal Installer eingespielt. Sie müssen dabei das richtige Zielverzeichnis (ORACLE_HOME) eingeben. Weitere Eingaben werden in der Regel nicht erwartet, da der Universal Installer im Inventory nachsieht, welche Komponenten installiert worden sind und somit angepasst werden müssen. Der Universal Installer ist in der Regel genauso aufzurufen wie bei einer »normalen« Software-Installation. Auch eine Silent Installation eines Patch-Sets ist daher möglich. 3. Postinstallation: Nach der Installation werden zunächst die Dienste wieder gestartet, allerdings nicht die Datenbankinstanz. Vor deren Hochfahren müssen einige Parameter überprüft werden, so kann es z.B. erforderlich sein, den Bereich für Java-Komponenten (java_pool_size) zu erhöhen. Gestartet wird die Instanz dann aus SQL*Plus mit dem MIGRATE-Befehl: Dieser Befehl sorgt dafür, dass einige zusätzliche Parameter gesetzt und eventuelle System-Trigger ausgeschaltet werden. Nachdem die Instanz gestartet ist, wird dann das Skript catpatch.sql aus dem Verzeichnis $ORACLE_HOME/rdbms/admin gestartet. Leider erfolgt hier keine automatische Protokollierung. Die vollständige Syntax für das Einspielen eines PatchSets sieht demnach folgendermaßen aus: SQL> SQL> SQL> SQL>
STARTUP MIGRATE spool c:\temp\patch10103.log @?/rdbms/admin/catpatch15 spool off
Listing 2.11: Einspielen eines Patch-Sets
Anschließend muss die Datenbankinstanz noch einmal neu gestartet werden, und es sollten alle PL/SQL-Programmpakete neu kompiliert werden. Dies geschieht mit folgenden Befehlen: SQL> SHUTDOWN IMMEDIATE SQL> STARTUP SQL> @?/rdbms/admin/utlrp Listing 2.12: Rekompilieren der PL/SQL-Pakete
Beachten Sie bitte, dass ein Patch-Set in der Regel nicht wieder deinstalliert werden kann. Es kann daher sinnvoll sein, ein neues Verzeichnis für die Oracle-SoftwareInstallation zu wählen und darin eine Basisinstallation und die Patch-Installation durchzuführen. Der Vorteil ist, dass während der Software-Installation die Datenbank weiter genutzt werden kann, und erst in der dritten Phase die Instanz neu gestartet werden muss. Der Ausfall der Datenbank beschränkt sich hierdurch je nach Anzahl und Komplexität der Java- und PL/SQL-Programmlogik auf wenige Minuten. Tipps für die Installation in einer Hochverfügbarkeitsumgebung (Real Application Clusters oder Data Guard) erhalten Sie in Kapitel 13.
15 Das »?« kann bei der Verwendung von SQL*Plus als Platzhalter für das ORACLE_HOME verwendet werden
Release-Wechsel
83
2.5.2 Interim-Patches Im Gegensatz zu den Patch-Sets werden Interim-Patches über ein eigenes Kommando »opatch« installiert. Während dieses Werkzeug in älteren Oracle-Versionen nicht enthalten war und daher zunächst umständlich im Oracle-Metalink gesucht und dann installiert werden musste, gibt es ab Version 9.2 ein eigenes Verzeichnis im ORACLE_HOME. Das Skript basiert auf der Sprache Perl und dementsprechend muss eine Perl-Umgebung installiert sein, was aber ab Oracle 9.2 ebenfalls gegeben ist. Bevor Sie einen Patch installieren, sollten Sie aber nochmals kontrollieren, ob eventuell doch eine neuere opatch-Version benötigt wird. Die Installation eines Patches erfolgt dann durch Aufruf von opatch mit dem Verzeichnis, in dem sich die Patch-Software (ausgepackt) befindet. Also z.B.: D:\oracle\product\10.1.0\db1\opatch\opatch C:\temp\patch_3874444 Listing 2.13: Aufruf von opatch
Im Gegensatz zu den Patch-Sets ist es bei Interims-Patches teilweise möglich, diese über den Befehl opatch –rollback <Patchid> wieder zu deinstallieren. Weitere Optionen erhalten Sie mit opatch –h.
2.6
Release-Wechsel
Für einen Release-Wechsel sollte man sich folgende Fragen stellen: 1. Welche Auswirkungen hat ein Release-Wechsel auf die Anwendungen? 2. Welche Auszeit steht zur Verfügung? 3. Welche neuen Funktionen sollten und können genutzt werden? Der wichtigste Punkt ist zunächst einmal die Frage nach den Anwendungen. Auch wenn Oracle immer versucht, eine entsprechende Kompatibilität zu gewährleisten, ist es dennoch Aufgabe des Software-Anbieters zu untersuchen, ob es Unverträglichkeiten zu einzelnen Oracle-Releases gibt. Der Betrieb von Oracle 10g ist in den meisten Fällen unkritisch, allerdings gibt es bezüglich der Oracle-Clients und Oracle Net-Komponenten einige Einschränkungen. Die verfügbare Auszeit ist oftmals entscheidend für die Wahl des Upgrade-Verfahrens und damit indirekt auch für die dritte Frage, welche neuen Funktionen genutzt werden können. Wenn die Auszeit nur wenige Stunden beträgt, dann kann ein Upgrade in der Regel nur über die direkte Anpassung der Datenbank erfolgen, wie sie über den Database Upgrade Assistant durchgeführt wird. Wenn eine längere Auszeit möglich ist, dann kann darüber nachgedacht werden, ob das Neuaufsetzen einer Datenbank mit anschließendem Import der Daten sinnvoller ist, da hierbei neue Funktionalitäten genutzt werden können. Das betrifft im Wesentlichen die Konfiguration der Tablespaces, erst recht, wenn die Datenbank noch – wie in Oracle8 üblich – mit Dictionary Managed Tablespaces betrieben wird.
84
Installation und Aufbau einer Datenbank
Beim Neuaufbau der Datenbank besteht die Möglichkeit, alle Tablespaces (inklusive des System-Tablespaces) als Locally Managed Tablespaces aufzubauen und für die Daten außerdem die ASSM-Funktionalität (Automatic Segment Space Management) zu nutzen. Ein weiterer Effekt beim Neuaufbau einer Datenbank ist sicherlich die Reorganisation aller Tabellen sowie eine Bereinigung des Data Dictionarys. In diesem Kapitel werden wir uns mit dem direkten Upgrade der Datenbank befassen. Die Möglichkeit, eine Datenbank mit minimaler Auszeit neu aufzubauen, besprechen wir in Kapitel 13, in dem es um die Hochverfügbarkeit von Datenbanken geht.
2.6.1 Vorbereitung Zunächst einmal muss festgelegt werden, welche Voraussetzungen für den Betrieb einer neuen Oracle-Version benötigt werden. Dazu gehören: Hardware-Ressourcen (Plattenplatz für die Oracle-Software, Memory-Bedarf) Betriebssystemversion und Patches Oracle Patches Wenn alle Voraussetzungen erfüllt sind, muss noch geprüft werden, in welcher Form ein Upgrade16 durchgeführt werden kann. Oracle erlaubt einen direkten Upgrade nur von folgenden Versionen: Oracle8 Version 8.0.6 Oracle8i Version 8.1.7 Oracle9i Version 9.0.1 Oracle9i Version 9.2.0 Diese Versionen werden als »Final Releases« bezeichnet, und alle Oracle Supportund Upgrade-Notizen beziehen sich auf diese. Wenn Sie also eine andere Version einsetzen, müssen Sie diese zunächst auf das Final Release bringen und können erst dann das endgültige Upgrade durchführen. Das bedeutet, wenn Sie beispielsweise Version 8.1.6 einsetzen, müssen Sie zunächst ein Upgrade nach Version 8.1.7 durchführen und können dann auf Version 10g upgraden. Patches oder Patch-Sets sind allerdings keine Voraussetzung für das Upgrade. Von Version 7.3.4 oder älteren Versionen aus gibt es keinen direkten Upgrade-Pfad. Der Oracle 10g Database Upgrade Guide gibt für diesen Fall als einzigen offiziellen Weg das Upgrade zunächst auf Version 8.1.7.4 und dann weiter auf Oracle 10g vor. Angesichts der zahlreichen neuen Funktionen ist in einem solchen Fall aber zu überlegen, ob es nicht besser ist, die Daten mit dem Exportbefehl aus der Datenbank herauszulesen und in eine neue Datenbank zu importieren.
16 Seit Oracle9i wird bei Oracle jeder Release-Wechsel als Upgrade bezeichnet
Release-Wechsel
85
Bevor Sie dann mit dem Upgrade beginnen, sollten Sie ein Backup der Datenbank und des Software-Verzeichnisses machen. Außerdem sollten Sie sich eine Liste aller »invaliden« Objekte in der Datenbank anfertigen. Warum sollten ungültige Objekte in der Datenbank vorhanden sein? Der Gründe sind vielfältig; es kann sich um Views handeln, die auf nicht mehr existierende Tabellen verweisen, Prozeduren, die nicht endgültig in Betrieb genommen wurden, oder Software-Pakete, die nicht »sauber« installiert worden sind. Am einfachsten kann man sich die Objektliste mit folgendem Befehl generieren. SQL> set lines 120 SQL> set object_name format a30 SQL> SELECT owner, object_name, object_type FROM dba_objects WHERE status = 'INVALID' ORDER BY owner, object_name; Listing 2.14: Liste der ungültigen Objekte
Nachdem Sie die Liste erstellt haben, sollten Sie zunächst herausfinden, warum die Objekte ungültig sind, und am besten die nicht mehr benötigten löschen. Wenn Sie alle Voraussetzungen erfüllt haben, sollten Sie als Nächstes die Software wie eingangs beschrieben in einem neuen ORACLE_HOME installieren. Wenn Sie keine Betriebssystem-Patches benötigen, kann diese Installation während des normalen Betriebs erfolgen. Ausnahme hierfür ist der Oracle Real Application Cluster, da die Oracle Cluster-Software in jeder bisherigen Oracle-Version exklusiv war, so dass eine gleichzeitige Nutzung unterschiedlicher Release-Stände nicht möglich war.
2.6.2 Database Upgrade Assistant (DBUA) Während der Installation der Software wird der Oracle Universal Installer Ihnen eine Liste der Datenbanken anzeigen, die migriert werden können. Nach unserer Erfahrung ist es sinnvoller, zunächst die Installation der Software zu beenden und erst in einem zweiten Schritt das Upgrade der Datenbanken durchzuführen. Bitte beachten Sie auch, dass Sie zunächst das Basis-Release einspielen und danach noch weitere Patches. Wenn Sie also direkt eine Migration aus dem Installer anstoßen würden, würden die entsprechenden Datenbanken auf das Basis-Release migriert, und Sie müssten dann, nachdem Sie die Patches eingespielt haben, die Datenbank nochmals upgraden. Wenn Sie mit der Software-Installation fertig sind, können Sie das Upgrade der Datenbank am einfachsten über den Database Upgrade Assistant (DBUA) durchführen. Bei MS-Windows-Systemen befindet sich das Programm im Menü CONFIGURATION AND MIGRATION TOOLS, bei Unix-Systemen wird es einfach über den Befehl dbua aufgerufen. Der Vorteil der Benutzung dieses Werkzeugs liegt darin, dass zunächst alle erforderlichen Voraussetzungen geprüft und im Umfeld des Real Application Clusters alle Knoten mit einbezogen werden. Außerdem ist hierbei ein Zurückrollen im Fehlerfall möglich.
86
Installation und Aufbau einer Datenbank
Nach dem Aufruf erscheint zunächst der obligatorische Willkommensbildschirm, anschließend erhalten Sie ein Auswahlmenü mit der Liste der verfügbaren Datenbanken. Hier wählen Sie die zu migrierende Datenbank aus und geben den Benutzernamen und das Kennwort eines SYSDBA-Benutzers an. Im nächsten Schritt müssen Sie die Größe und Lage des für Oracle 10g obligatorischen SYSAUX-Tablespace angeben.
Abbildung 2.21: Auswahl des SYSAUX Tablespace
Bei kleineren Datenbanken reicht die vorgegebene Größe von 500 MB aus. Die vorgegebene Erweiterung um 1 MB bis zur »unendlichen« Größe ist jedoch nicht sinnvoll. Besser ist es, eine Erweiterung um jeweils 10 MB vorzusehen und eine obere Grenze von 1 oder 2 GB zu wählen. Als Nächstes erfolgt eine Abfrage, ob ungültige Objekte am Ende der Installation neu kompiliert werden sollen. Die Dauer der Kompilierung hängt stark von der Anzahl der verwendeten PL/SQL- und Java-Prozeduren ab. In der Regel ist die sofortige Kompilierung sinnvoller, da bei Fehlern noch eine Nachbearbeitung erfolgen kann, ohne dass die Anwender betroffen sind. Wenn Sie allerdings nur eine sehr begrenzte Zeit für das Upgrade zur Verfügung haben, können Sie die Kompilierung auch den Anwendungsprozessen überlassen. In diesem Fall werden wie üblich alle ungültigen Objekte beim ersten Aufruf neu kompiliert. Nachdem nochmals abgefragt wurde, ob ein aktuelles Backup existiert, folgt die Konfiguration des neuen Oracle Enterprise Managers. Je nachdem, ob Sie die Database Control oder Grid Control verwenden, d.h., bereits einen Agenten installiert haben, können Sie hier die entsprechende Auswahl vornehmen. Beachten Sie bitte, dass keine Auswahl eines Tablespace erfolgt, da der Enterprise Manager seine Objekte im SYSAUX-Tablespace ablegt.
Release-Wechsel
87
Bevor das Upgrade durchgeführt wird, erfolgt eine Zusammenfassung.
Abbildung 2.22: Upgrade-Zusammenfassung
Hier sehen Sie auch einen weiteren Vorteil des Upgrade Assistants. Die nicht mehr benötigten Serverparameter werden automatisch entfernt. Ebenso werden Parameter, die während der Installation eine Minimalgröße haben müssen (in der Regel shared_pool_size und java_pool_size), automatisch gesetzt.
88
Installation und Aufbau einer Datenbank
Wichtig: Während des Upgrades mit dem Database Upgrade Assistant wird die automatische Archivierung ausgeschaltet. Bei der Verwendung von Data-Guard-Datenbanken kann dies zur Folge haben, dass diese neu aufgebaut werden müssen. Daher sollten Sie dieses Verhalten, sofern Sie eine lückenlose Archivierung benötigen, vorher ändern. Im Oracle-Metalink gibt es hierfür eine Notiz (Note: 276301.1, DBUA Took Primary to NOARCHIVELOG Mode During Migration). Daraus geht hervor, dass vor dem Aufruf des Database Upgrade Assistants folgende Änderung durchgeführt werden muss: Im Verzeichnis $ORACLE_HOME/assistants/dbma liegt die XML-Datei mep.cfg. Darin gibt es folgenden Eintrag:
Diesen Eintrag ändern Sie bitte auf:
Dadurch wird die Archivierung auch während des Upgrades gewährleistet. Beachten Sie aber bitte, dass während des Upgrades eine Reihe von archivierten RedoLog-Dateien anfallen, wodurch die gesamte Zeitdauer verlängert wird. Am Ende des Upgrades erhalten Sie eine Ergebnisseite mit den alten und neuen Parametern, und Ihre Datenbank läuft unter Oracle 10g. Wenn Sie mehrere Datenbanken in dieser Form upgraden wollen, bietet es sich an, die Silent Installation zu wählen. Dabei wird der Database Upgrade Assistant mit der Option -silent und unter Angabe der Datenbank-SID aufgerufen, z.B. in der Form: % dbua –silent –sid QJA92 Listing 2.15: DBUA Silent Installation
2.6.3 Manueller Upgrade In einigen Fällen kann es schneller und sinnvoller sein, das Upgrade manuell, d.h., anhand von Skripten durchzuführen. Dabei sind aber allerhand Vorkehrungen zu treffen, so dass Sie diese Art nur dann wählen sollten, wenn Sie: ein erfahrener Oracle Administrator sind sehr wenig Zeit für das Upgrade haben vor dem Upgrade Ihrer Produktionssysteme einige Male das Upgrade geübt haben Bevor Sie mit dem Upgrade beginnen, sollten Sie das Skript utlu101i.sql ausführen. Es liegt im Verzeichnis $ORACLE_HOME/rdbms/admin17. Dieses Skript wird als SYSDBA ausgeführt und liefert eine komplette Liste aller wichtigen Punkte, die für das Upgrade betrachtet werden müssen. 17 Hier ist das neue ORACLE_HOME gemeint, also z.B. /app/oracle/product/10.1.0/db_1.
Release-Wechsel
Das folgende Listing zeigt die Ausgabe des Skriptes für die Datenbank QJA92. Oracle Database 10.1 Upgrade Information Tool 02-19-2005 16:28:06 . ************************************************************************* Database: ************************************************************************* --> name: QJA92 --> version: 9.2.0.6.0 --> compatibility: 9.2.0.0.0 . ************************************************************************* Logfiles: [make adjustments in the current environment] ************************************************************************* --> The existing log files are adequate. No changes are required. . ************************************************************************* Tablespaces: [make adjustments in the current environment] **************************************************************** ******** --> SYSTEM tablespace is adequate for the upgrade. .... minimum required size: 286 MB --> TEMP tablespace is adequate for the upgrade. .... minimum required size: 50 MB . ************************************************************************* Options: [present in existing database] ************************************************************************* --> Partitioning WARNING: Listed option(s) must be installed with Oracle Database 10.1 . ************************************************************************* Update Parameters: [Update Oracle Database 10.1 init.ora or spfile] ************************************************************************* WARNING: --> "shared_pool_size" needs to be increased to at least "150944944" --> "pga_aggregate_target" is already at "104857600" calculated new value is "104857600" --> "large_pool_size" is already at "8388608" calculated new value is "8388608" . ************************************************************************* Deprecated Parameters: [Update Oracle Database 10.1 init.ora or spfile] ************************************************************************* -- No deprecated parameters found. No changes are required. . ************************************************************************* Obsolete Parameters: [Update Oracle Database 10.1 init.ora or spfile] ************************************************************************* --> "hash_join_enabled" .
89
90
Installation und Aufbau einer Datenbank
************************************************************************* Components: [The following database components will be upgraded or installed] ************************************************************************* --> Oracle Catalog Views [upgrade] VALID --> Oracle Packages and Types [upgrade] VALID --> Oracle Workspace Manager [upgrade] VALID . ************************************************************************* . ************************************************************************* SYSAUX Tablespace: [Create tablespace in Oracle Database 10.1 environment] ************************************************************************* --> New "SYSAUX" tablespace .... minimum required size for database upgrade: 500 MB Please create the new SYSAUX Tablespace AFTER the Oracle Database 10.1 server is started and BEFORE you invoke the upgrade script. . ************************************************************************* Listing 2.16: Check einer Oracle9i-Datenbank mit utlu101i.sql
Im
obigen
Fall
bedeutet
dies,
dass
Sie
zunächst
den
Serverparameter
shared_pool_size auf 150 MB vergrößern müssen. Außerdem sollte der Parameter hash_join_enabled gelöscht werden, da er nicht mehr ausgewertet wird. Wichtiger
wäre es, wenn so genannte deprecated Parameter aufgelistet worden wären, da das Starten der Datenbank unter Version 10g mit einem solchen Parameter nicht funktioniert. Der obsolete Parameter hash_join_enabled würde hingegen nur zu einer Warnung in der Alert-Datei führen. Das Starten einer zu migrierenden Datenbank unter Version 10g ist nur möglich, wenn der Parameter compatible mindestens den Wert 9.2.0 hat. Der manuelle Upgrade sieht also wie folgt aus: 1. Installation der Oracle 10g-Software in ein neues Home-Verzeichnis 2. Stoppen des Listeners Wenn Sie nur eine Datenbank je Listener verwenden, ist es sinnvoll, diesen zu stoppen, da dadurch jeglicher Zugriff durch Dritte vermieden werden kann. 3. Check der notwendigen Änderungen mit utlu101i.sql SQL> connect / as sysdba SQL> spool c:\temp\preupgrade.log SQL> @D:/oracle/product/10.1.0/rdbms/admin/utlu101i.sql18 SQL> spool off
4. Backup der Datenbank 18 Hier darf nicht das »?« als Substitution für ORACLE_HOME verwendet werden, da es sich ja nicht um das aktuelle ORACLE_HOME handelt. Wenn Sie wollen, können Sie sich das Skript natürlich in ein anderes Verzeichnis kopieren.
Release-Wechsel
91
5. Erstellen einer neuen Initialisierungsdatei mit den angepassten Parametern Sie sollten für die Oracle 10g-Datenbank eine so genannte Serverparameterdatei verwenden. Wenn Sie das Upgrade aus der Version 9i heraus durchführen und dort schon ein SPFILE verwendet haben, können Sie die folgenden Parameter mit dem Befehl ALTER SYSTEM SET … SCOPE = SPFILE setzen. Alternativ können Sie mit dem Befehl CREATE SPFILE … FROM PFILE … eine editierbare Initialisierungsdatei erstellen. COMPATIBLE >= 9.2.0 SHARED_POOL_SIZE >= 150 MB PGA_AGGREGATE_TARGET >= 100 MB JAVA_POOL_SIZE >= 50 MB19 LARGE_POOL_SIZE >= 8 MB
Falls Sie mit einer init.ora gearbeitet haben, erstellen Sie jetzt ein SPFILE im neuen ORACLE_HOME. SQL> CREATE SPFILE = 2>
’D:\oracle\product\10.1.0\database\QJA92.ora’
3>
FROM PFILE=’D:\temp\initQJA92.ora’;20
Falls Sie bereits ein SPFILE verwenden, kopieren Sie es in das neue Zielverzeichnis. 6. Kopieren der Passwortdatei in das neue $ORACLE_HOME/dbs- (Unix) bzw. %ORACLE_HOME%\database-Verzeichnis (MS-Windows). 7. Stoppen der Datenbank 8. Bei MS-Windows-Systemen muss jetzt der Service-Eintrag gelöscht und mit dem neuen ORACLE_HOME wieder eingetragen werden: set ORACLE_SID=QJA92 set ORACLE_HOME=D:\oracle\product\9.2.0 D:\oracle\product\9.2.0\bin\oradim –delete –sid QJA92 set ORACLE_HOME=D:\oracle\product\10.1.0 D:\oracle\product\10.1.0\bin\oradim –new –sid QJA92 –startmode a –spfile
9. Starten der Datenbank im neuen ORACLE_HOME mit der Option upgrade. SQL> startup upgrade
10.Erstellen des SYSAUX-Tablespace SQL> CREATE TABLESPACE SYSAUX 2>
DATAFILE 'D:\oradata\QJA92\sysaux01.dbf' SIZE 500M
3>
AUTOEXTEND ON NEXT 10M MAXSIZE 1000M
4>
EXTENT MANAGMENT LOCAL
5>
SEGMENT SPACE MANAGEMENT AUTO;
19 JAVA_POOL_SIZE muss nur gesetzt sein, wenn die Java –Virtual Machine in der Datenbank konfiguriert ist. 20 Bei Unix-Betriebssystemen ist das Zielverzeichnis dbs anstelle von database zu wählen.
92
Installation und Aufbau einer Datenbank
11.Anpassen des Data Dictionarys Dafür müssen Sie je nach Version, von der aus Sie kommen, ein entsprechendes Skript ausführen. Wenn Sie von der Version 9.2.0 kommen, heißt das Skript u0902000.sql. Version
Skript
8.0.6
u0800060.sql
8.1.7
u0801070.sql
9.0.1
u0900010.sql
9.2.0
u0902000.sql
Tabelle 2.1: aus unterschiedlichen Versionen
SQL> spool c:\temp\upgrade.log SQL> @?/rdbms/admin/u0902000.sql SQL> spool off
12.Optionaler Check des Upgrades Nach dem Upgrade können Sie sich das Ergebnis mit dem Skript utlu101s.sql ansehen. Es liegt im Verzeichnis $ORACLE_HOME/rdbms/admin und wird mit der Option TEXT aufgerufen. SQL> spool c:\temp\post_upgrade.log SQL> @?/rdbms/admin/utlu101s.sql TEXT SQL> spool off
13.Stoppen und Starten der Datenbank SQL> shutdown immediate SQL> startup restrict
14.Kompilieren der ungültigen Objekte SQL> spool c:\temp\recomp.log SQL> @?/rdbms/admin/utlrp.sql SQL> spool off
Bei der Verwendung von Mehrprozessorsystemen wird die Kompilierung auf Basis des Serverparameters cpu_count automatisch parallelisiert. 15.Starten der Datenbank für den normalen Betrieb SQL> shutdown immediate SQL> startup
16.Anpassung des Listeners. Wenn Sie eine listener.ora-Datei verwenden, müssen Sie zum Abschluss noch den neuen ORACLE_HOME-Pfad eintragen. In jedem Fall muss aber der Oracle 10g Listener für den Remote-Zugriff auf die Datenbank verwendet werden. Anschließend steht die Datenbank für den normalen Betrieb zur Verfügung.
Release-Wechsel
93
2.6.4 Downgrade Auch bei der besten Vorbereitung kann es doch passieren, dass nach einiger Zeit festgestellt wird, dass der Betrieb der Datenbank unter Version 10g nicht ordnungsgemäß möglich ist. Daher stellt sich die Frage, wie man am schnellsten wieder zurück auf die alte Version kommt. Sicherlich wäre es möglich, eine neue Datenbank unter der Version 9i oder älter aufzubauen und die Daten aus der 10g-Datenbank zu exportieren, um sie dann in die alte Datenbank wieder zu importieren. Dieser Vorgang kann aber bei großen Datenbanken Tage in Anspruch nehmen, währenddessen die Datenbank nicht zur Verfügung steht. Oracle bietet dafür schon seit einiger Zeit die Möglichkeit, ähnlich wie bei einem Upgrade, ein Downgrade auf das vorherige Release durchzuführen. Das bedeutet, dass eine Oracle 10g-Datenbank auf die Version 9.2.0 zurückgesetzt werden kann21. Voraussetzung für das Downgrade ist, dass noch keine Funktionalitäten benutzt wurden, die erst mit Oracle 10g möglich sind. Dafür gibt es den Serverparameter compatible. Mit diesem Parameter wird verhindert bzw. erlaubt, dass neue Funktionen benutzt werden können. Dieser Parameter muss also für dendas Downgrade auf Oracle9i einen Wert 9.2.x haben. Ein älterer Wert ist für die 10g-Datenbank nicht erlaubt, ein neuerer Wert führt unweigerlich zum Verlust der DowngradeMöglichkeit. Für das Downgrade sind folgende Schritte durchzuführen: 1. Ermitteln, ob ein Downgrade möglich ist SQL> show parameter compatible
2. Kopieren der Serverparameterdatei in das alte ORACLE_HOME 3. Stoppen der Datenbank SQL> shutdown immediate
4. Starten der Datenbank mit der Option downgrade (in der Oracle 10g-Umgebung) SQL> startup downgrade
5. Anpassen des Data-Dictionarys aus Oracle 10g-Sicht (Oracle 10g-Umgebung) SQL> spool c:\temp\downgrade.log SQL> @?/rdbms/admin/d0902000.sql SQL> spool off
6. Herunterfahren der Datenbank SQL> shutdown immediate
7. Ändern des ORACLE_HOME und – bei MS-Windows – Ändern der Service-Einträge für eine Oracle9i-Datenbank
21 Im Gegensatz zum Upgrade ist hier allerdings der Patch-Level der Oracle9i-Version wichtig. Es muss sich mindestens um die Version 9.2.0.3 handeln.
94
Installation und Aufbau einer Datenbank
8. Hochfahren der Datenbank unter dem alten ORACLE_HOME (Oracle9i) mit der Option MIGRATE SQL> startup migrate<
9. Endgültige Anpassung des Data Dictionarys SQL> spool c:\temp\relod.log SQL> @?/rdbms/admin/catrelod.sql SQL> spool off
Mit diesem Skript wird ein Reload der PL/SQL- und Java-Prozeduren sowie des externen Data Dictionarys durchgeführt. 10.Stoppen und Starten der Datenbank SQL> shutdown immediate SQL> startup
11.Kompilieren aller ungültigen Objekte SQL> spool c:\temp\recomp.log SQL> @?/rdbms/admin/utlrp.sql SQL> spool off
Damit ist das Downgrade geschafft, und die Datenbank arbeitet wieder in der alten Umgebung.
Datenbank-Architektur 3.1
Namenskonventionen
Beim Umgang mit einer Datenbank werden auf den verschiedensten Ebenen Dinge benannt: Datenbanken, Instanzen, Dienste, Dateien, Tablespaces usw. Neben den allgemein gültigen Regeln für die Namensvergabe, 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, Net-Aliasname 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. Im Folgenden wird zunächst über Datenbanken und deren Namensgebung diskutiert; im Anschluss daran über die Namensgebung bei Systemobjekten, also Tablespaces und Datendateien. Groß-, Kleinschreibung und Sonderzeichen Es ist möglich, alle Benennungen sowohl in Groß- als auch in Kleinbuchstaben vorzunehmen. In vielen Teilen sind außerdem auch Sonderzeichen möglich. Man muss allerdings zwischen der einfachen Schreibweise (CREATE TABLESPACE temp) und der tatsächlichen Maskierung (CREATE TABLESPACE "temp") unterscheiden. Im zweiten Fall wird tatsächlich ein Data-Dictionary-Eintrag mit Kleinbuchstaben generiert, während im ersten Fall Großbuchstaben verwendet werden. In der Praxis sollten Sie allerdings beachten, wenn Sie tatsächlich Sonderzeichen und Kleinbuchstaben verwenden, dass einige Tools unter Umständen nicht mehr funktionieren, da nicht jedes Werkzeug auf diese Besonderheit ausgelegt ist. Außerdem müssen Sie bei Abfragen ebenfalls diese Maskierung benutzen. In der Regel werden wir daher unmaskierte Namen verwenden, so dass wir ohne Maskierung auskommen. Für die ORACLE_SID verwenden wir außerdem oftmals auf Betriebssystemebene Großbuchstaben, da diese dadurch bei Pfadangaben oder Dateinamen besser erkennbar ist.
96
Datenbank-Architektur
3.1.1 Datenbanken Bei der Benennung von Datenbanken ist zunächst 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 Parametern zusammengesetzt wird, jedoch auch – unabhängig davon – explizit gesetzt werden kann. Die Instanz, also die Prozess- und Speicherstrukturen, die auf die Datenbank zugreifen, werden über einen Instanznamen (ORACLE_SID) identifiziert. Die folgenden Abschnitte erläutern die Zusammenhänge zwischen diesen und weiteren Namen. 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 Serverparameter) interner Bestandteil des Datenbanknamens; zusammen ergeben diese Namen auch den Standardwert für den Serverparameter service_names, der ab Oracle8i zur Adressauflösung bei den Netzwerkdiensten genutzt werden kann.1 Net-Aliasnamen, 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 Empfehlung lautet, die Domänen in beiden Fällen gezielt zu nutzen und identisch zu halten. Mittels eines weiteren Serverparameters 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 der globale Name der Zieldatenbank. Diese Forderung ist gerade in gewachsenen Datenbanken schwer einzuhalten, da der funktionale Verlust, der durch das Deaktivieren eines DatenbankLinks 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 zumindest ähnlichen) Netzwerkdomänen sein müssen, können mit 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.
1
In der CONNECT_DATA-Klausel wird hierzu statt des Parameters (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.
Namenskonventionen
97
Datenbanknamen Ausgehend davon, dass Domänen verwendet werden, kann sich der Datenbankname auf die Funktion der Datenbank fokussieren. Datenbanknamen wie oradb sind wenig sinnvoll. Es sollten eher Namen wie dwh für Data Warehouse, crm für die Datenbank eines CRM-Systems 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 oder Versionsbezeichnung hinzuzufügen, also z.B. pps01 oder pps10g. Bei Datenbanken, die als RAC (Real Application Clusters, siehe Kapitel 13) ausgebaut werden, sollte der Datenbankname nicht länger als sieben Zeichen sein, um bei den Instanznamen (die ebenfalls maximal acht Zeichen lang sein dürfen) die Instanznummer als Suffix an den Datenbanknamen anhängen zu können. Der Datenbankname wird als Serverparameter 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 Serverparametern zu arbeiten. Arbeitet man z.B. mit der falschen Serverparameterdatei, so geht das CREATE DATABASE-Kommando schief, und das ist gut so. Der globale Datenbankname wird beim Anlegen der Datenbank aus den Serverparametern db_name und db_domain abgeleitet, und zwar als db_name. db_domain. Dieser kann über die View global_name abgefragt werden: SQL> SELECT global_name FROM global_name;
Er kann nach Erstellung der Datenbank unabhängig vom eigentlichen Datenbanknamen und der Domäne beliebig geändert werden: SQL> ALTER DATABASE RENAME GLOBAL_NAME TO globdb.firma.de;
Der globale Datenbankname wird dazu verwendet, die Namen von DatenbankLinks zu erzwingen. Mit gesetztem Serverparameter global_names = true
muss – wie bereits erwähnt – ein Datenbank-Link immer genauso heißen wie der globale Datenbankname der Zieldatenbank. Eine nachträgliche Änderung des Datenbanknamens kann über das Kommandozeilen-Tool nid erfolgen. Dazu muss die Datenbank exklusiv gemountet sein, also sich im MOUNT-Zustand befinden, und (im Falle einer RAC-Datenbank) der Serverparameter cluster_database=FALSE gesetzt sein. Bei gesetzter Umgebungsvariable ORACLE_SID ändert folgender Aufruf dann den Datenbanknamen: $ nid target=sys/passwort dbname=newname
Anschließend muss die Datenbank heruntergefahren und der Serverparameter db_name entsprechend angepasst werden. Bei Oracle 10g geht dies über ein Kommando der Form: SQL> ALTER SYSTEM SET db_name = newdb SCOPE=SPFILE;
Anschließend kann die Datenbank wieder hochgefahren werden.
98
Datenbank-Architektur
Eindeutigkeit von Datenbanknamen Vor der Version Oracle 10g galt die Restriktion, dass unterschiedliche Datenbanken auf demselben Knoten unterschiedliche Datenbanknamen (db_name) haben müssen. In den meisten Fällen ist dies nicht weiter problematisch. Manchmal kommt es allerdings vor, dass man zu Testzwecken eine Datenbank auf demselben Knoten klonen möchte. In diesem Fall musste man zunächst die Referenzdatenbank herunterfahren, die Klondatenbank mounten, mit dem oben beschriebenen nid-Werkzeug den db_name ändern, um anschließend beide Datenbanken hochfahren zu können. Dieses etwas umständliche Verfahren ist mit Oracle 10g nicht mehr notwendig. Möglich macht dies der neue Serverparameter db_unique_name. Unterschiedliche Oracle 10g-Datenbanken auf demselben Knoten müssen lediglich unterschiedliche Werte für db_unique_name haben. Der db_unique_name lässt sich einfach über die Parameterdatei oder im NOMOUNT-Status der Datenbank ändern: SQL> ALTER SYSTEM SET db_unique_name = neudb SCOPE=SPFILE;
Die db_unique_names von 10g-Datenbanken sowie die db_names älterer Datenbanken müssen nun also pro Knoten eindeutig sein. Der db_unique_name ist – wenn nicht explizit gesetzt – mit dem db_name identisch. Für Oracle 10g-Datenbanken besteht daher eigentlich kein Grund mehr, den db_name nachträglich zu ändern. Es sollte – wenn nichts dagegen spricht – auf das einfachere Verfahren der Änderung des db_unique_name ausgewichen werden. Achtung: Verstößt man versehentlich gegen die genannten Eindeutigkeitsforderungen, lässt sich die zweite Instanz zwar noch hochfahren, den MOUNT-Versuch quittiert Oracle aber mit der etwas irritierenden Fehlermeldung: ORA-01102: Datenbank kann nicht im EXCLUSIVE-Modus mit Mount angeschlossen werden.
Da der db_unique_name auch noch in anderen Zusammenhängen eine wichtige Rolle bei der Namensgebung spielt, beispielsweise für Data-Guard-Konfigurationen (siehe Kapitel 13) sowie für Oracle Managed Files (siehe Kapitel 3.9), ist es zu empfehlen, ihn nicht nur pro Knoten, sondern über die gesamte Datenbankumgebung eindeutig zu halten. Dies lässt sich u.U. am einfachsten erreichen, indem er mit dem globalen Datenbanknamen gleichgesetzt wird. Die Länge des db_unique_name ist allerdings auf 30 Zeichen begrenzt. Instanznamen In der Oracle-Architektur sind Datenbank und Instanz getrennt, und somit können auch unterschiedliche Namen vergeben werden. Der Instanzname verfügt nicht über eine Domäne; er muss allerdings – wie der Datenbankname auch – pro 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 dwh10g.prod.firma.de den Namen pdwh10g tragen, um die Eigenschaft Produktivsystem auch im Instanznamen zu verdeutlichen.
Namenskonventionen
99
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. Bei RAC-Datenbanken empfiehlt es sich, die Instanzen mittels eines Suffix durchzunummerieren, z.B. pdwh10g1 und pdwh10g2. Datenbanken im Netzwerk Sobald man auf eine Datenbank im Netzwerk zugreifen will, kommt zusätzlich zu den bereits diskutierten Namen ein Net-Aliasname ins Spiel. Hiermit wird die Datenbank im Netzwerk identifiziert. Net-Aliasnamen 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 Net-Aliasnamen identisch zu den Datenbanknamen inklusive Domäne wählen. Oft gibt es für eine Datenbank mehrere Net-Aliasnamen. Dabei wird für jede Anwendung ein spezieller Net-Aliasname verwendet, so dass die Anwendungsdaten bei Bedarf zwischen verschiedenen Datenbanken verschoben werden können. Dieses Konzept findet sich auch bei den Dienstnamen als Serverparameter wieder: Hiermit kann jeder Instanz eine Liste von Diensten (Serverparameter 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 Systemobjekte Auch für Systemobjekte wie Tablespaces und Datendateien 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 Undo- und Temporärsegmente sollten immer gleich genannt werden, z.B. undotbs und temp. Bei Tablespaces für Anwendungsdaten 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. Folgt man der zumindest für sehr große Datenbanken empfehlenswerten Strategie, Tabellen und Indizes sehr unterschiedlicher Größen in unterschiedlichen Tablespaces zu speichern, sollte sich dies auch im Tablespace-Namen widerspiegeln, z.B. x_data_big für die größten Tabellen, x_index_small für Indizes auf kleinen Tabellen etc.
100
Datenbank-Architektur
Bei den Datendateien sollte gewährleistet sein, dass man am voll qualifizierten Dateinamen folgende Eigenschaften erkennen kann: Diese Datei gehört zu einer Oracle-Datenbank (z.B. Pfad /oradata). Den Datenbanknamen (ohne Domäne) (z.B. Pfad /oradata/PROD10G/) Den Tablespace-Namen (z.B. Dateiname: temp01.dbf) Eine laufende Nummer für die n-te Datei des Tablespaces Die Benennung von Rollback-Segmenten sollte kein Thema mehr sein, da seit der Version Oracle9i die automatische Undo-Verwaltung zu empfehlen ist (siehe Kapitel 3.3.5).
3.2
Komponenten einer Oracle-Datenbank
Auf physikalischer Ebene besteht eine Oracle-Datenbank aus einer Reihe von Komponenten. Im Standardfall sind diese Komponenten als Dateien innerhalb eines normalen Dateisystems (z.B. NTFS, ReiserFS etc.) ausgeführt. Es gibt aber auch die Möglichkeit, anstelle eines Dateisystems so genannte Raw-Devices zu benutzen oder – seit Oracle 10g – den mitgelieferten Volume-Manager ASM. Diese Methoden werden weiter unten besprochen. Der Einfachheit halber spricht man aber in allen Fällen von Dateien, den so genannten Datenbankdateien. Folgende Komponenten sind unverzichtbar, gehören also in jedem Fall zu einer Oracle-Datenbank: Datendateien nehmen die eigentlichen Nutzdaten sowie sämtliche Metadaten auf. Sie determinieren in vielen Fällen den Gesamtspeicherbedarf einer Datenbank (eine Ausnahme bilden Datenbank mit sehr hoher Datenänderungsrate). Online-Redolog-Dateien bilden das Transaktionsprotokoll einer Datenbank. Es muss mindestens zwei Redolog-Dateien geben, typischerweise verwendet man zwischen drei und fünf (diese können ggf. noch gespiegelt werden, was die nominelle Anzahl entsprechend erhöht). Die Kontrolldatei enthält Metadaten über die physikalische Struktur und logische Konsistenz der Datenbank sowie backup-relevante Informationen. Sie ist typischerweise wenige MB groß und sollte einfach oder zweifach gespiegelt sein. Die Parameterdatei beinhaltet die gesamte Konfiguration der Oracle-Instanz. Sie ist nur wenige KB groß. Einige weitere Komponenten sind optional: Temporärdateien sind Container für Daten, die nur temporär anfallen (z.B. Zwischenergebnisse für Sortierungen). Zwar kann eine Datenbank auch ohne Temporärdateien betrieben werden, in der Praxis sollte aber aus PerformanceGründen jede Datenbank mindestens einen Temporär-Tablespace aus Temporärdateien haben. Archivierte Redolog-Dateien sind – wie der Name andeutet – im Wesentlichen Archivierungen, also Kopien voll geschriebener Online-Redolog-Dateien. Für Datenbanken mit hoher Änderungsrate können diese einen erheblichen Anteil des Gesamtspeicherbedarf einer Datenbank ausmachen. Produktionsdatenbanken
Tablespaces und Datendateien
101
sollten aus Gründen der Wiederherstellung im Fehlerfall unbedingt im Archivierungsmodus betrieben werden, für Test- und Entwicklungsumgebungen kann dies eventuell entfallen (siehe Kapitel 10.1). Die Flashback-Log-Dateien stellen eine Neuerung in Oracle 10g dar. Sie enthalten Abbilder alter Datenbankinhalte und werden für die Funktion FLASHBACK DATABASE benötigt. Je nach Änderungsrate der Datenbank und eingestellter Aufbewahrungszeit kann ein höherer Gesamtspeicherbedarf anfallen. Dieser kann aber durch geeignete Konfiguration nach oben limitiert werden. Weitere Informationen zu Flashback-Log-Dateien befinden sich in Kapitel 10.4. Die Block Change Tracking-Datei speichert Informationen darüber, welche Datenbankblöcke seit dem letzten Backup geändert wurden. Sie ist typischerweise wenige 10 MB groß. Die Passwortdatei erlaubt Administratoren eine spezielle Authentifizierung gegenüber der Datenbank, insbesondere um eine heruntergefahrene Datenbank zu starten (die normale Authentifizierung von Benutzern bei geöffneter Datenbank findet unabhängig davon durch die Datenbank selbst statt). Die Dateigröße beträgt wenige KB. Auf die Datei kann optional verzichtet werden, dann läuft die Authentifizierung über Gruppenzugehörigkeiten auf Betriebssystemebene. Alle Komponenten werden in den folgenden Abschnitten dieses Kapitels näher beleuchtet.
3.3
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.1: Tablespaces und Datendateien
102
Datenbank-Architektur
3.3.1 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 IO-Kanäle optimiert werden, wie kann man Fragmentierungen vermeiden? Verfügbarkeit Wie kann im Fall eines Medienfehlers 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? 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 GB sind keine Seltenheit), so muss man sich fragen, wie man zum Beispiel die Verfügbarkeitsanforderung bei einer Datenbankgröße von weniger als 10 GB 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 GB Datenvolumen verwendet man logische Devices, bei denen die physikalischen Platten mittels Raid 0+1 zunächst einmal gespiegelt (Raid 1) und dann über mehrere Controller in Stücken à 64 KB oder 128 KB »gestriped« (Raid 0) werden. Dadurch ist ein Optimum an Verfügbarkeit und IO-Verteilung (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!
Tablespaces und Datendateien
103
Des Weiteren stellt auch ein Raid 5- oder Raid 1-System keine Garantie für hohe Verfügbarkeit dar. Ein 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; sofern der Leser nicht selber DBA ist: Der DBA wird es Ihnen danken! Folgende Tablespaces sollten deshalb bei jeder Datenbank zusätzlich zu den Tablespaces SYSTEM und SYSAUX (ab Oracle 10g) angelegt werden. Die Tablespace-Namen sind als Vorschläge gedacht und haben sich in der Praxis gut bewährt: 1. Temporär-Tablespace, z.B. temp 2. Undo-Tablespace, z.B. undotbs 3. Tablespace für Werkzeuge wie den Oracle Enterprise Manager, z.B. tools 4. Mindestens je ein Tablespace für die Daten einer Anwendung, z.B. xyz_data für eine Anwendung XYZ 5. Mindestens je ein Tablespace für die Indizes einer Anwendung, z.B. xyz_index für eine Anwendung XYZ 6. Eventuell ein Tablespace für Tests und Benutzerdaten, z.B. users 7. Eventuell ein oder mehrere Tablespaces für ungewöhnlich große Objekte, z.B. xyz_data_big, xyz_index_big für eine Anwendung XYZ Je nach Datenbank können zusätzliche Tablespaces notwendig sein, z.B. beim Einsatz von Partitionen.
3.3.2 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. SQL> CREATE SMALLFILE TABLESPACE kunden_daten DATAFILE '/oradata1/PDWH10G/kunden_daten01.dbf' SIZE 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 5000M BLOCKSIZE 8K LOGGING EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M SEGMENT SPACE MANAGEMENT AUTO; Listing 3.1: CREATE TABLESPACE-Kommando
Die Klauseln im Einzelnen: TABLESPACE
Um einen 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ärsegmenten oder dem Undo-Management dient. Es bietet sich an, dem Tablespace einen Namen zu geben, mit dem er eindeutig seiner
104
Datenbank-Architektur
Bestimmung zugeordnet werden kann, also z.B. lager_data, 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. Wie bereits erwähnt, warnen wir allerdings davor, dies zu tun. 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.2 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. Die Endung .dbf steht demnach für eine Datendatei, die Endung .tmp für eine Temporärdatei. Oracle Managed Files Mit dem Serverparameter db_create_file_dest ist es ab Oracle9i möglich, ein Verzeichnis für die Erstellung von Datendateien vorzugeben, deren Name beim CREATE TABLESPACE oder ALTER TABLESPACE ADD DATAFILE nicht angegeben wird. Als Größe wird dabei 100 MB gewählt, wenn sie nicht explizit angegeben ist. Zusammen mit der seit Oracle9i möglichen Nutzung von Locally Managed Tablespaces 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 Serverparameter gesetzt ist. Der Serverparameter db_unique_name sei auf PDWH10G gesetzt. SQL> ALTER SYSTEM SET db_create_file_dest = '/oradata1/'; SQL> CREATE TABLESPACE demo_data DATAFILE AUTOEXTEND ON NEXT 10M MAXSIZE 500M;
Auf die Angabe DATAFILE AUTOEXTEND sollte generell nicht verzichtet werden, da ansonsten die Datei beliebig wachsen kann. Dieser Befehl legt in diesem Beispiel einen Tablespace demo_data an mit der Datendatei: /oradata1/PDWH10G/datafile/o1_mf_demo_dat_1g4o4ycv_.dbf
Zu beachten ist, dass der Name des Tablespaces in der Datendatei auf acht Zeichen beschränkt wird, um ausreichend Platz für Prä- und Postfix zu behalten. Für nähere Informationen über Oracle Managed Files siehe Kapitel 3.9. 2
Endungen von Datenbankdateien haben weder Standardwerte noch sind sie Pflicht. Wir empfehlen jedoch wegen der besseren Lesbarkeit, die angegebenen oder ähnliche Endungen zu verwenden.
Tablespaces und Datendateien
105
SIZE
Mit einer initialen Größe (SIZE) wird Platz auf der Festplatte bzw. dem Filesystem angegeben. 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 MB 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-Bitund auch einigen 32-Bit-Betriebssystemen bei mehr als 2 GB bis hin zu 256 GB. SMALLFILE
Diese Klausel ist neu in Oracle 10g und erleichtert die Verwaltung sehr großer Datenbanken. Bis einschließlich Oracle9i ist nämlich die Maximalgröße einer Datendatei (unabhängig von Betriebssystemgrenzen) von der verwendeten OracleBlockgröße des Tablespaces abhängig, die Obergrenze liegt konkret bei 4M Blöcken. Für eine Blockgröße von 8 KB ergibt sich somit eine maximale Datendateigröße von 32 GB. Über diese Grenze hinaus kann der Tablespace nur durch Hinzufügen weiterer Datendateien vergrößert werden. Unter Oracle 10g gibt es nun einen Ausweg: die so genannten BIGFILE-Tablespaces können bis zu 4G Blöcke umfassen, kommen bei einer Blockgröße von 8 KB also auf bis zu 32 TB Datendateigröße. Dies ist aber nur für Umgebungen mit Volume-Managern zu empfehlen, die ein Striping oder RAID leisten, auch vor dem Hintergrund, dass ein solcher Tablespace auf eine einzige Datendatei beschränkt bleibt. Die Möglichkeit, die logischen Volumes dynamisch – also im laufenden Betrieb – zu erweitern, sollte ebenfalls Voraussetzung für die Verwendung solcher Tablespaces sein. BIGFILE-Tablespaces sind nur als Locally Managed Tablespaces mit automatischer Segmentplatzverwaltung (ASSM) möglich (s.u.), hiervon ausgenommen sind das System-Tablespace, Temporär-Tablespaces und Undo-Tablespaces. Bei diesen Tablespaces ist die Bigfile-Option auch mit manueller Segmentverwaltung möglich.
Um kompatibel mit existierenden Skripten zu bleiben, ist die Klausel SMALLFILE die Standardeinstellung nach Erstellung einer Datenbank und hätte im obigen Beispiel somit weggelassen werden können. Durch die Klausel BIGFILE wird entsprechend ein BIGFILE-Tablespace erzeugt. Es ist sogar möglich, die Standardeinstellung der Datenbank zu ändern: SQL> ALTER DATABASE SET DEFAULT BIGFILE TABLESPACE; SQL> CREATE TABLESPACE bigts …;
Da ein BIGFILE-Tablespace nur aus einer einzigen Datendatei bestehen kann, ist für Größenänderungen dieser Datendatei nur der Tablespace-Name erforderlich, z.B.: SQL> ALTER TABLESPACE bigts RESIZE 200M;
Es muss auch berücksichtigt werden, dass im Falle einer Beschädigung und anschließenden Wiederherstellung eines Tablespaces die unterste Granularitätsstufe, nämlich Recovery einer einzelnen Datendatei, mit BIGFILE-Tablespaces grundsätzlich identisch zum Recovery des gesamten Tablespaces ist. Bei großen Tablespaces kann dies erheblich länger dauern als das Recovery einer oder weniger Datendateien des betroffenen Tablespaces.
106
Datenbank-Architektur
AUTOEXTEND
Mit der Option AUTOEXTEND ON kann eine automatische Vergrößerung der Datendatei nach Bedarf erfolgen. In diesem Falle wird, wenn der Platz in der Datendatei nicht mehr ausreicht, diese Datei um die Größe NEXT vergrößert – bis zu einer maximalen Größe von MAXSIZE. Wird der Parameter NEXT nicht angegeben, wird die Datei jeweils um einen einzigen Datenbankblock vergrößert! (Bei Oracle Managed Files immer um 100 MB.) Dies kann zu erheblichen Performance-Einbußen führen, so dass anzuraten ist, den Parameter NEXT nicht zu klein zu wählen (10 MB oder größer) und die Initialgröße von vornherein ausreichend zu dimensionieren. Sollten Sie mehrere Datendateien in einem Dateisystem anlegen, müssen Sie darauf achten, dass jede mit AUTOEXTEND angelegte Datei unter Umständen Platz reserviert, 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 reservieren 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 Standardblockgröße der Datenbank 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 Serverparameter 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 Serverparameter gibt. Dies sind: 2 KB, 4 KB, 8 KB, 16 KB und 32 KB. LOGGING
Die Klausel LOGGING steht an dieser Stelle für das Standardverhalten der Objekte, die in dem Tablespace gespeichert werden. Logging besagt, dass wie üblich alle DMLOperationen über den Redolog-Mechanismus protokolliert werden. Alternativ kann durch ein NOLOGGING erreicht werden, dass bestimmte DML-Operationen (so genannte Direct Loads, beispielsweise durch den Oracle SQL*Loader) nicht mitprotokolliert werden. Das bedeutet, falls ein Media-Fehler auftritt, können die geladenen Daten nicht wiederhergestellt werden, und die zugehörige Data-DictionaryInformation (z.B. Extent-Verwaltung) wird als logisch korrupt gekennzeichnet.
Tablespaces und Datendateien
107
EXTENT MANAGEMENT LOCAL
Diese Klausel definiert den Tablespace als so genannten Locally Managed Tablespace (LMTS). Bei dieser Methode verwaltet der Tablespace seine Extents über eine lokale Bitmap-Struktur in jeder zugehörigen Datendatei. Seit Oracle8i ersetzt diese Methode zunehmend die alte Variante der so genannten Dictionary Managed Tablespaces (DMTS). Die Extent-Allokierung wird beschleunigt, und die früher üblichen rekursiven Operationen entfallen, es muss auch keine Rollback-Information erzeugt werden. Darüber hinaus wird die Verwaltung der Extents vereinfacht, so dass ein Zusammenlegen (Coalesce) von freien Extents entfallen kann. LM-Tablespaces sind mittlerweile die Standardeinstellung und haben sich in der Praxis ausnahmslos bewährt. Die alten DM-Tablespaces sollten nicht mehr verwendet werden. Damit entfällt auch die Notwendigkeit, die früher üblichen Klauseln für Default-Storage-Parameter sowie für eine minimale Extent-Größe anzugeben. Bei der Angabe der Extent-Größe für Objekte gibt es jetzt nur noch zwei Alternativen: UNIFORM SIZE legt eine einheitliche Größe für alle Extents fest, AUTOALLOCATE (Standard) kalkuliert die Größe der Extents. Dabei werden die Extents in der Regel wie folgt angelegt. 64 KB für die ersten 16 Extents 1 MB ab dem 17. Extent 8 MB ab dem 80. Extent 64 MB ab dem 200. Extent Die tatsächlich allokierten Extent-Größen können von diesem Schema abweichen, insbesondere z.B. bei der Nutzung von ALTER TABLE ALLOCATE EXTENT. Die Benutzung von AUTOALLOCATE empfiehlt sich fast immer; auch große Objekte können hiermit effizient behandelt werden. Lediglich für extrem große Objekte sollten Tablespaces mit UNIFORM SIZE benutzt werden. SQL> CREATE TABLESPACE kunden_daten_small DATAFILE '/oradata1/PDWH10G/kunden_daten_small01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 300M EXTENT MANAGEMENT LOCAL AUTOALLOCATE; Listing 3.2: Locally Managed Tablespace mit AUTOALLOCATE
SEGMENT SPACE MANAGEMENT
Die Verwaltung der freien Blöcke für ein Segment geschah bis einschließlich Oracle8i 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 Freiliste gelöscht. Wird durch Änderungsoder Löschoperationen eine zweite Marke (PCTUSED) in einem Block unterschritten, dann wird der entsprechende Block wieder in die Freilisten eingetragen.
108
Datenbank-Architektur
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. Als Tuning-Maßnahme war es üblich, die Parameter FREELISTS und FREELIST GROUPS hoch zu setzen, damit nicht alle INSERT-Operationen über die gleiche Freiliste abgewickelt werden. Die Änderung des Parameters FREELIST GROUPS kann jedoch nur durch eine Reorganisation der gesamten Tabelle erfolgen, wohingegen FREELISTS auch durch einen ALTER TABLE-Befehl angepasst werden kann. Seit Oracle9i und bei Verwendung von Locally Managed Tablespaces kann durch die Klausel SEGMENT SPACE MANAGEMENT AUTO auf eine Verwaltung über Freilisten verzichtet werden. Bei dieser Methode (ASSM für 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 dritte 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
Tablespaces und Datendateien
109
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 kleiner Nachteil dieser Freiplatzverwaltung, da u.U. Platz verschwendet wird (natürlich werden die Blöcke bei einer nächsten Formatierung mit benutzt). Der Vorteil des Verfahrens ist aber die geringe Latch-Contention (Sperren auf der Freelist eines Segmentes) und schnellere Vergabe von freiem Platz. Nach unseren Erfahrungen kann die automatische Segmentplatzverwaltung in den meisten Fällen uneingeschränkt empfohlen werden. Eine Ausnahme bilden jedoch Tablespaces, in denen LOB-Segmente gespeichert werden, da die Kombination von LOB-Segmenten und ASSM sowohl in Oracle9i als auch in Oracle 10g Gegenstand zahlreicher Bugs im Zusammenhang mit der Speicherplatzverwaltung war und ist. Hier muss sich letztlich zeigen, ob diese Problematik mit den nächsten SoftwarePatches entschärft wird. Bestimmte Anwendungen können aber nach wie vor von der manuellen Segmentplatzverwaltung profitieren. Hierzu gehören solche Anwendungen, in denen von Zeit zu Zeit größere Datenmengen gelöscht werden, ohne dass komplette Blöcke geleert werden. Bei der klassischen Segmentverwaltung führte dies dazu, dass die freien Bereiche unter Umständen nicht wieder verwendet wurden. Mit ASSM werden die neuen Daten jetzt auf alle teilgefüllten Blöcke verteilt. Obwohl dies im ersten Schritt besser erscheinen mag, birgt es einen – u.U. – entscheidenden Nachteil. Neue Daten haben oft eine Beziehung zueinander, z.B. die aktuellen Auftragseingänge. Durch die Verteilung über ASSM müssen in der Regel mehr Blöcke in den Buffer Cache gelesen werden, als es mit der älteren Methode, bei der neue Daten in einem neuen, d.h., leeren Block landen, der Fall gewesen wäre. Wenn Sie Objekte haben, bei denen das der Fall ist, sollten Sie überlegen, ob Sie für diese Objekte einen eigenen Tablespace mit manueller Segmentplatzverwaltung anlegen.
3.3.3 SYSTEM- und SYSAUX-Tablespace Jedem, der schon einmal eine Oracle-Datenbank administriert hat, wird der SYSTEMTablespace ein Begriff sein. Seit jeher handelt es sich hierbei um den ersten Tablespace einer Datenbank, in dem sämtliche Metadaten und Verwaltungsinformationen der Datenbank, das so genannte Data Dictionary, abgespeichert werden. Aus diesem Grund ist der SYSTEM-Tablespace höchst sensibel und sollte für alle »normalen« Benutzer oder Anwendungsbenutzer tabu sein. Der SYSAUX-Tablespace hingegen ist neu in Oracle 10g. Genau wie der SYSTEMTablespace ist er zwingender Bestandteil einer Oracle 10g-Datenbank. Dies ist insbesondere bei Migrationen von älteren Versionen nach Oracle 10g zu berücksichtigen. Der SYSTEM-Tablespace Der SYSTEM-Tablespace wird bei der Erstellung der Datenbank generiert. Seine Datendateien müssen über die DATAFILE-Klausel des CREATE DATABASE-Kommandos angegeben werden, es sei denn, es werden Oracle Managed Files verwendet, so dass die Datendatei mit Standardparametern angelegt werden kann. Wie bei jeder anderen Erstellung eines Tablespaces können bei Bedarf auch mehrere Dateien durch
110
Datenbank-Architektur
Kommata getrennt angegeben und die automatische Erweiterbarkeit (Klausel AUTOEXTEND) eingeschaltet werden. Sie sollten unbedingt auch die Klausel EXTENT MANAGEMENT LOCAL verwenden, da im Gegensatz zu anderen Tablespaces der SYSTEM-Tablespace standardmäßig noch als Tablespace des alten Typs (Dictionary-Managed) angelegt wird. Zu beachten ist allerdings, dass Sie dann generell keine DictionaryManaged Tablespaces mehr anlegen können. 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 SYSTEM-Tablespace und werden durch die Endung »$« gekennzeichnet. Es ist nicht erlaubt, DML-Befehle3 (INSERT, UPDATE, DELETE) auf Data-Dictionary-Tabellen auszuführen; die einzige Ausnahme bildet die Audit-Trail-Tabelle aud$, da sie vom Administrator in regelmäßigen Abständen bereinigt werden muss. Das interne Data Dictionary wird den Administratoren und Benutzern durch eine Reihe von Sichten (externes Data Dictionary) zur Verfügung gestellt. Das interne Data Dictionary Wie bereits erwähnt, 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 »normalen« Tabellen wird hierauf jedoch nicht mit DML-Befehlen, sondern mit DDL-Befehlen zugegriffen. Warum dies notwendig ist, zeigt folgendes Beispiel: SQL> CREATE TABLE personen ( persnr NUMBER NOT NULL, anrede VARCHAR2 (5), vorname VARCHAR2 (20), nachname VARCHAR2 (20), geburtstag DATE ) TABLESPACE users; Listing 3.3: Erstellen einer Tabelle
Mit diesem Befehl wird eine Tabelle mit dem Namen personen und fünf Spalten im Tablespace users angelegt. Was als DDL-Befehl CREATE TABLE nur wenige Zeilen benötigt, wird durch den Kernel in 53 (!) Befehle 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 TABLE-Kommando absetzen?« »Hat er das Recht, im Tablespace users eine Tabelle anzulegen?« Dann muss überprüft werden, ob in dem Tablespace ausreichend Platz für ein Extent mit der vordefinierten Größe vorhanden ist. Außerdem müssen die Speichereigenschaften 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 3
DML steht für Data Manipulation Language (INSERT, UPDATE, DELETE), DDL für Data Definition Language (CREATE, ALTER, DROP).
Tablespaces und Datendateien
111
den Namen der Tabelle und col$ für die Spalten der Tabelle. Die folgende Liste zeigt alle Tabellen des Data Dictionarys, in die in diesem Fall Einträge vorgenommen wurden: obj$, seg$, tsq$, con$, tab$, col$, ccol$, cdef$
Auffallend ist die Endung »$«, die anzeigt, dass es sich hierbei um die Tabellen des Data Dictionarys 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: SQL> SELECT * FROM user_tab_columns;
Dieser Befehl greift auf folgende Data-Dictionary-Tabellen zu: obj$, user$, col$, coltype$, hist_head$, tab$
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 im Folgenden besprochene SQL-Skript catalog.sql jederzeit wiederhergestellt werden können. Das externe Data Dictionary Mit dem Skript catalog.sql (Verzeichnis: $ORACLE_HOME/rdbms/admin) wird die Benutzersicht auf das interne Data Dictionary aufgebaut. sqlplus / as sysdba @?/rdbms/admin/catalog.sql
Das »?« steht hierbei für das ORACLE_HOME-Verzeichnis und kann sowohl unter Unix als auch MS-Windows verwendet werden. Dieses Skript baut verschiedene Views auf. 1. Virtuelle Views (v$, gv$) Dies sind Informationen der Kontrolldateien sowie Zähler und Strukturen der Prozesse und des Shared Memorys. Zum Beispiel gibt v$datafile die Liste der Datenbankdateien aus Sicht der Kontrolldatei an. SQL> SELECT name,value FROM v$parameter WHERE name LIKE '%undo%'; NAME VALUE ------------------------------ ---------------undo_management AUTO undo_tablespace UNDOTBS1 undo_retention 7200 Listing 3.4: Auszug aus der View v$parameter
112
Datenbank-Architektur
Globale virtuelle Views sind eine Erweiterung für den RAC(Real Application Clusters)-Betrieb. Sie zeigen die entsprechenden Informationen zusammenfassend für alle Instanzen in einem RAC. Diese Views beginnen mit gv$ anstelle von v$. 2. DBA-Views (dba_) Dies ist die komplette Repräsentation des internen Data Dictionarys, d.h., über diese Views 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 ---------------------------------------D:\ORACLE\ORADATA\PS10\SYSTEM01.DBF D:\ORACLE\ORADATA\PS10\UNDOTBS01.DBF D:\ORACLE\ORADATA\PS10\SYSAUX01.DBF D:\ORACLE\ORADATA\PS10\INDX01.DBF D:\ORACLE\ORADATA\PS10\USERS01.DBF D:\ORACLE\ORADATA\PS10\TOOLS01.DBF
TABLESPA BYTES -------- ---------SYSTEM 272629760 UNDOTBS1 209715200 SYSAUX 209715200 INDX 209715200 USERS 209715200 TOOLS 104857600
Listing 3.5: Die View dba_data_files
3. Views für alle Benutzer (all_) Diese Views erlauben es den Benutzern, auf Objekte zuzugreifen, auf denen ihnen Rechte gegeben wurden. Dazu gehören natürlich auch die eigenen Objekte. Als Beispiel wird hier mit der View all_tables eine Liste aller lesbaren Tabellen für den momentan angemeldeten Benutzer (in diesem Fall demo) erstellt. SQL> SELECT owner, table_name FROM all_tables; OWNER ---------SYS SYS SYS SYS SYS SYS SYS SYS SYS SYS
TABLE_NAME --------------------------SCHEDULER$_JOB_STEP_STATE AUDIT_ACTIONS STMT_AUDIT_OPTION_MAP TABLE_PRIVILEGE_MAP SYSTEM_PRIVILEGE_MAP DUAL PLAN_TABLE$ KU$NOEXP_TAB ODCI_WARNINGS$ ODCI_SECOBJ$
Tablespaces und Datendateien SYS SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM WMSYS WMSYS WMSYS WMSYS DEMO DEMO DEMO DEMO DEMO DEMO DEMO DEMO
113
PSTUBTBL HELP DEF$_TEMP$LOB OL$NODES OL$HINTS OL$ WM$VERSION_HIERARCHY_TABLE WM$NEXTVER_TABLE WM$VERSION_TABLE WM$WORKSPACES_TABLE AUFPOSITIONEN PRODUKTE AUFTRAEGE AUFSTATUS TELNUMMERN ADRESSEN TYPEN KUNDEN
Listing 3.6: Die View all_tables für den Benutzer demo
Für den Datenbankadministrator besteht oftmals kein Unterschied zwischen den dba- und den all-Views. 4. Views 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 -------------------------KUNDEN TYPEN ADRESSEN TELNUMMERN AUFSTATUS AUFTRAEGE PRODUKTE AUFPOSITIONEN Listing 3.7: Die View user_tables für den Benutzer demo
Zusätzlich zu dem Skript catalog.sql gibt es weitere Skripte, die das Data Dictionary für unterschiedliche Anwendungen (XML, Java etc.) erweitert (siehe Kapitel 2).
114
Datenbank-Architektur
Der SYSAUX-Tablespace Im Laufe der Oracle-Versionen ist eine ganze Reihe von erweiterten Funktionen entstanden, die zwar zum Teil eigenständige Schemata belegen, ihre Objekte aber dennoch im SYSTEM-Tablespace speichern, z.B. die Verwaltung von Stored Outlines (Schema OUTLN), der Workspace-Manager (Schema WMSYS), der Log Miner usw. Dies ist ungünstig, da diese Funktionen eine gewisse Dynamik mit sich bringen, die im sensiblen SYSTEM-Tablespace fehl am Platze ist. Andere Funktionen wie z.B. die XML DB oder das Performance-Werkzeug Statspack konnten ihre Daten in einem benutzerdefinierten Tablespace speichern. Oracle 10g kommt schließlich mit einigen neuen Funktionen, die insbesondere eine Archivierung diverser Performance-Statistiken beinhalten (Stichwort AWR, siehe auch Kapitel 11.2), was zu erheblichem Platzbedarf führen kann. Man hat daher die Gelegenheit genutzt, mit dem Wildwuchs diverser Daten-Repositories aufzuräumen und stattdessen einen einheitlichen Standard-Tablespace namens SYSAUX hierfür zu benutzen. Der SYSAUX-Tablespace wird beim Erstellen der Datenbank angelegt, seine Datendatei(en) müssen über die SYSAUX DATAFILE-Klausel angegeben werden (wie beim SYSTEM-Tablespace können natürlich auch hier Oracle Managed Files verwendet werden). Die View v$sysaux_occupants gibt Auskunft darüber, welche Komponenten der Datenbank den SYSUAX-Tablespace benutzen und wie viel Platz jede einzelne Komponente belegt. Für einige Komponenten besteht auch die Möglichkeit, sie in einen alternativen Tablespace zu migrieren. Das Verfahren dafür ist über die Spalten move_procedure und move_procedure_desc beschrieben. Als Startwert sollte für den SYSAUX-Tablespace ein Platzbedarf zwischen 500 MB und wenigen GB gewählt werden. Im Rahmen eines Upgrades von älteren Datenbankversionen muss der SYSAUXTablespace erstellt werden. Dies muss nach dem Hochfahren der Datenbank mittels STARTUP UPGRADE, aber noch vor dem Aufruf des Upgrade-Skripts (z.B. u0902000.sql) geschehen. Für Näheres siehe Oracle 10g Database Upgrade Guide.
3.3.4 Temporär-Tablespaces und Temporärsegmente In einem DBMS fallen immer wieder Sortier- oder Hash-Operationen oder damit verwandte Operationen wie Gruppierungen oder Index-Aufbau 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 ein so genannter Sortierbereich benutzt. Dieser befindet sich im Hauptspeicher des Datenbanksystems und wird über den Serverparameter sort_area_size explizit oder pga_aggregate_target als Gesamtheit festgelegt. Werden allerdings größere Mengen Speicherplatz angefordert, so wird automatisch auf Temporärsegmente ausgewichen, d.h., es wird ein spezielles Segment in der Datenbank reserviert, das Zwischenergebnisse und das Endergebnis aufnimmt.
Tablespaces und Datendateien
115
Im Unterschied zu allen anderen Segmenttypen werden Temporärsegmente grundsätzlich implizit angelegt und können nicht explizit angesprochen oder ausgelesen werden. Die bisher einzige Ausnahme hierfür sind globale Temporärtabellen, deren Inhalte ebenfalls als Temporärsegmente abgelegt werden. Nach erfolgreicher Durchführung der Sortierung oder Gruppierung werden Temporärsegmente wieder freigegeben; der Inhalt von globalen Temporärtabellen wird je nach Definition nach Transaktions- bzw. Sitzungsende freigegeben. Durch den mit Oracle8i eingeführten Befehl CREATE TEMPORARY TABLESPACE ist es möglich, einen so genannten Temporär-Tablespace speziell für die Aufnahme von Temporärsegmenten aufzubauen. Entscheidend ist, dass die gesamte Verwaltung eines solchen Tablespaces ohne Beteiligung des Data Dictionarys stattfindet. Da Dateien eines Temporär-Tablespaces (so genannte Temporärdateien) 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 die Temporärdateien einfach neu. SQL> CREATE TEMPORARY TABLESPACE temp TEMPFILE '/oradata1/PDWH10G/temp01.tmp' size 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 5000M EXTENT MANAGEMENT LOCAL UNIFORM SIZE 10M; Listing 3.8: Anlegen eines Temporär-Tablespaces
Mit diesem Befehl wird ein Tablespace mit Namen temp erstellt und durch die Angabe EXTENT MANAGEMENT LOCAL als Locally Managed Tablespace verwaltet. Auch hier ist die Angabe EXTENT MANAGEMENT LOCAL optional, da es zurzeit keine andere Möglichkeit gibt. Um Temporärdateien auch betriebssystemseitig von Datendateien unterscheiden zu können, empfiehlt es sich, sie mit der Endung .tmp anzulegen. Die Erstellung von Temporärdateien läuft unabhängig von ihrer Größe im Sekundenbereich ab, da für die Temporärdateien im Gegensatz zu Datendateien lediglich Plattenplatz reserviert, aber keine Oracle-Blockformatierung durchgeführt wird. Jedem Datenbankbenutzer ist ein Temporär-Tablespace zugewiesen, in dem vom Oracle-Server für umfangreiche Sortieroperationen Temporärsegmente angelegt werden. Findet keine explizite Zuweisung statt, wird dem Benutzer standardmäßig der SYSTEM-Tablespace als Temporär-Tablespace zugeordnet. Dies sollte natürlich nicht passieren. Um zu verhindern, dass dies versehentlich passiert, kann ein Temporär-Tablespace als Default –Temporary Tablespace für die Datenbank ausgewählt werden: SQL> ALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp;
Diese Zuweisung kann auch gleich bei der Erstellung der Datenbank im Rahmen des CREATE DATABASE-Kommandos geschehen. Wichtig zu wissen ist, dass der Default-Temporär-Tablespace einer Datenbank – wenn er erst einmal als solcher definiert ist – nicht mehr gelöscht werden kann, bevor nicht ein anderer Temporär-Tablespace seine Rolle übernommen hat. Damit wird verhindert, dass die Benutzer auf den SYSTEM-Tablespace »zurückfallen«.
116
Datenbank-Architektur
Temporär-Tablespace-Gruppen Mit Oracle 10g ist es möglich, mehrere Temporär-Tablespaces zu einer Gruppe zusammenfassen und eine solche Gruppe wie oben beschrieben einem Benutzer zuzuordnen oder datenbankweit als Standard zu definieren. Dies ist vor allem im Hinblick auf bessere I/O-Verteilung beim Umgang mit Temporärsegmenten gedacht, da nun zufällig ausgewählt wird, in welchem Tablespace ein Temporärsegment erstellt wird. Die Temporärdateien der einzelnen Tablespaces sollten also möglichst verteilt liegen, um eine echte I/O-Parallelisierung zu erreichen. In Umgebungen mit Striping oder RAID 5 ist eine Parallelisierung ohnehin gegeben, so dass der Vorteil hier eher gering ist. Eine Tablespace-Gruppe wird nicht explizit definiert, sondern automatisch angelegt, wenn ein Tablespace der Gruppe zugeordnet wird, z.B.: SQL> SQL> SQL> SQL>
ALTER ALTER ALTER ALTER
TABLESPACE temp TABLESPACE GROUP temp_group; TABLESPACE temp2 TABLESPACE GROUP temp_group; DATABASE DEFAULT TEMPORARY TABLESPACE temp_group; USER demo TEMPORARY TABLESPACE temp_group;
Auch hier gilt, dass – sofern eine Tablespace-Gruppe als datenbankweiter Default definiert ist – kein Mitglied dieser Gruppe gelöscht werden kann. Um einen Tablespace aus einer Gruppe zu entfernen, wird er der leeren Gruppe '' zugewiesen: SQL> ALTER TABLESPACE temp TABLESPACE GROUP '';
Auch das Löschen einer Tablespace-Gruppe geschieht nicht explizit, sondern automatisch, sobald der letzte Tablespace aus ihr entfernt wird. Vorhandene Tablespace-Gruppen können über die View dba_tablespace_groups eingesehen werden. Achtung: Tablespaces und Tablespace-Gruppen teilen sich einen gemeinsamen Namensraum, können also nicht identische Namen haben.
3.3.5 Undo-Tablespaces Ein Undo-Tablespace beinhaltet ausschließlich Undo-Segmente. Primäre Aufgabe der Undo-Segmente ist es, den alten Zustand von Feldinhalten (before images) so lange zu speichern, bis der neue Zustand in der Datenbank festgeschrieben wurde. Dadurch kann sichergestellt werden, dass Befehle entweder vom System (PMONProzesss) 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 ein spezielles Undo-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 Undo-Segmente, die zyklisch beschrieben werden.
Tablespaces und Datendateien
117
Seit Oracle9i gibt es die Möglichkeit, die Instanz mit automatischer Undo-Verwaltung zu betreiben (Serverparameter undo_management = AUTO). Sowohl für Oracle9i als auch für Oracle 10g ist diese Technik der herkömmlichen, manuellen UndoVerwaltung vorzuziehen, daher wird hier auch nur dieser Fall betrachtet. Für ältere Datenbanken und Migrationsmöglichkeiten wird auf Kapitel 3.10 verwiesen. Bei automatischer Undo-Verwaltung werden die notwendigen Segmente vom System in einem speziellen Undo-Tablespace automatisch angelegt, der Administrator hat keinerlei Einfluss auf Anzahl und Größe der Undo-Segmente. Die interne Verwaltung der Undo-Segmente erfolgt in Form von Ringpuffern. Jedes Undo-Segment kann eine oder mehrere Transaktionen beherbergen, auch kann eine einzelne Transaktion sich durchaus über mehrere Undo-Segmente erstrecken. Jedes Extent eines Undo-Segmentes kann ebenfalls eine oder mehrere Transaktionen speichern. Es versteht sich, dass eine Transaktion umso mehr Speicherplatz belegt, je umfangreicher ihre Änderungen ausfallen. Undo-Segmente sind – wie bereits erwähnt – als logische »Ringe« aufgebaut sind. Ist ein Extent gefüllt, wird entweder das nächste, bereits existierende Extent wieder verwendet, aber nur dann, wenn es keine aktiven Transaktionen mehr enthält, oder eine neues Extent angelegt und logisch in den Ring eingefügt. Die automatische Undo-Verwaltung übernimmt nicht nur die Verwaltung von Anzahl und Größe der Undo-Segmente, sondern kann mit weiteren Raffinessen aufwarten: Nach Möglichkeit wird nur eine schreibende Transaktion pro Undo-Segment zugelassen, um die Wahrscheinlichkeit von Zugriffskonflikten 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 before images aus beendeten Transaktionen für potenzielle Leser zur Verfügung gehalten werden sollen (Lesekonsistenz und Flashback Query). Diese »Freigabezeit« kann jedoch unterschritten werden, wenn der Platz in der Undo-Tablespace knapp zu werden droht (Space Pressure). Die Segmentverwaltung 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 dem betreffenden Tablespace zu sparen, ein Extent eines fremden Undo-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 Undo-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 images) überschrieben werden.
118
Datenbank-Architektur
Neben dieser Möglichkeit des Zurückrollens von Transaktionen erlauben die UndoSegmente 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. fünf 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 Lesekonsistenz-Modell von Oracle greift die Abfrage automatisch auf das before image der bereits geänderten Datensätze 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 ORDER BY abtnr; Listing 3.9: Lesekonsistenz-Modell
Abbildung 3.2: Consistent Read
Entscheidend ist in diesem Zusammenhang der Serverparameter undo_retention. Er gibt eine Zeitdauer an (Standardwert sind 15 Minuten), bis zu der auf before images für Lesekonsistenz oder sog. Flashback Queries zugegriffen werden kann. Allerdings gilt auch hier, dass bei unzureichend dimensioniertem Undo-Tablespace 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. Als Alternative bietet Oracle 10g die Möglichkeit, die Undo-Retention zu garantieren. Da dies den operativen Betrieb jedoch beeinträchtigt, kommt er nur selten zum Einsatz.
Tablespaces und Datendateien
119
Das folgende Bild veranschaulicht das Transaktionsmanagement anhand eines Undo-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.
Abbildung 3.3: Undo-Segmente
Die automatische, d.h., systemgesteuerte Undo-Verwaltung erfordert Undo-Tablespaces. Ein Undo-Tablespace kann direkt beim Erstellen der Datenbank angelegt oder nachträglich aufgebaut werden. Im folgenden Beispiel wird der Undo-Tablespace UNDOTBS mit einer Größe von 2000 MB und einer automatischen Erweiterung auf maximal 5000 MB aufgebaut: SQL> CREATE UNDO TABLESPACE undotbs DATAFILE '/oradata1/PDWH10G/undotbs01.dbf' SIZE 2000M AUTOEXTEND ON NEXT 100M MAXSIZE 5000M;
Undo-Tablespaces sind stets Locally-Managed Tablespaces, deren Extent-Größen vom System bestimmt werden (AUTOALLOCATE). Zusätzliche Klauseln, wie die DEFAULT STORAGE- oder SEGMENT SPACE MANAGEMENT-Klausel, sind hierbei nicht zulässig und werden mit einer Fehlermeldung quittiert. CREATE UNDO TABLESPACE legt nicht nur einen Tablespace vom Typ UNDO (Attribut contents der View dba_tablespaces mit Wert UNDO) an, sondern erzeugt in diesem
Tablespace auch sofort zehn Undo-Segmente. Die Namen der Undo-Segmente lauten _SYSSMUxx$, wobei xx eine pro Datenbank fortlaufende Nummer darstellt.
120
Datenbank-Architektur
Undo-Tablespaces können darüber hinaus wie andere Tablespaces verwaltet werden: Über den Befehl ALTER TABLESPACE lassen sich zusätzliche Dateien anfügen oder der AUTOEXTEND-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 der 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: SQL> 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 Undo-Segment des neu aktivierten Tablespace zugeordnet. Achtung: Dies bedeutet auch, dass in RAC(Real Application Clusters)-Umgebungen jede aktive Instanz ihren eigenen Undo-Tablespace benötigt. Es muss hier also mindestens so viele Undo-Tablespaces wie gleichzeitig aktive Instanzen geben. Diese werden zweckmäßigerweise durchnummeriert, z.B. UNDOTBS01, UNDOTBS02 etc. Undo Management konfigurieren Die automatische Konfiguration von Undo-Segmenten wird pauschal über den Serverparameter 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. 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 Rollbacksegmenten um, die aus älteren Versionen von Oracle bekannt sind. Diese Einstellung ist zwar noch immer der Standardwert, aber nicht mehr zu empfehlen. Weitere Parameter Die automatische Undo-Verwaltung bringt einen weiteren Vorteil mit sich: Der Verbleib von Undo-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 Undo-Informationen pro Transaktion nach dem COMMIT für weitere 3600 Sekunden – also eine Stunde – für lesende Transaktionen verfügbar sind: undo_retention = 3600
Tablespaces und Datendateien
121
Achtung! Da Undo-Segmente nicht die gleiche Ringpuffer-Struktur fester Minimalgröße aufweisen wie Rollbacksegmente, zeigt die Erfahrung, dass in Produktivsystemen der Wert für undo_retention auf keinen Fall auf dem Standardwert (900 Sekunden) belassen werden sollte. Die hier gezeigte Alternative von einer Stunde ist der grundsätzlich bessere Startwert. Falls man Kenntnis über lang laufende Abfragen oder Transaktionen hat, empfiehlt es sich, mit der undo_retention großzügig über deren Laufzeit hinauszugehen. Der Parameter undo_retention 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 Wermutstropfen: Der DBA wird hier nicht von allen Überlegungen zur Konfiguration entlastet. Sollte der aktive UndoTablespace nicht genügend Platz für neu startende Transaktionen bereithalten und auch nicht dynamisch erweiterbar sein, werden Undo-Einträge abgeschlossener Transaktionen auch bereits vor dem Ablauf dieser Zeitspanne entfernt! Mit der Option RETENTION GUARANTEE wird garantiert, dass für die Dauer der undo_retention die alten Daten nicht überschrieben werden, auch wenn dies u.U. zu Fehlern bei der Transaktionsverarbeitung (ORA-01650 unable to extend rollback segment…) führen würde. Den in Oracle9i eingeführten Parameter undo_suppress_errors, mit dem Fehlermeldungen wie die unten abgebildete unterdrückt werden konnten, gibt es in Oracle 10g nicht mehr, entsprechende Fehler werden immer ignoriert. SQL> SET TRANSACTION USE ROLLBACK SEGMENT "_SYSSMU13$"; * FEHLER in Zeile 1: ORA-30019: Unzulässiger Rollback-Segment-Vorgang in Automatic Undo-Modus
Data Dictionary Views Die aus den Oracle-Versionen 7 und 8 bekannten Views sind auch im Kontext der automatischen Undo-Verwaltung noch relevant: dba_tablespaces listet die Undo-Tablespaces unter contents = 'UNDO'. dba_rollback_segs listet sowohl systemgenerierte Undo- als auch manuell erstellte Rollback-Segmente. Alle generierten Segmente von nicht aktiven Undo-Tablespaces haben konsequenterweise den Status Offline. dba_segments führt die systemgenerierten Undo-Segmente unter segment_type = 'TYPE2 UNDO'. v$rollstat und v$rollname geben in der gewohnten Weise Auskunft über aktive Undo- und Rollback-Segmente und ihre Statistiken. v$transaction erlaubt die Zuordnung von Transaktionen zu Undo-Segmenten. Seit Oracle9i gibt die View dba_undo_extents u.a. die letzte COMMIT-Zeit für jedes Extent des Undo-Tablespaces aus.
122
Datenbank-Architektur
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 zehn 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 unxpblkrelcnt – Freisetzen von Extents, deren Retention-Periode noch nicht ab-
gelaufen war, für andere Transaktionen. Die angestrebte Retention-Zeit konnte also nicht eingehalten werden. ssolderrcnt – Anzahl aufgetretener ORA-01555 Fehler (»snapshot too old«). Hohe Zahlen weisen auf einen zu geringen Wert für undo_retention oder (im Zusammentreffen mit hohen Werten der Spalte unxpblkrelcnt) auf einen zu kleinen Undo-Tablespace hin.
3.3.6 Read-only-Tablespaces Für spezielle Operationen kann es sinnvoll sein, einen Tablespace als Read-only zu spezifizieren, so dass nur lesend auf die Daten zugegriffen werden kann, DML-Operationen aber nicht mehr möglich sind. Ein Tablespace kann 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! 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 wiederholter Backups entfällt. Das Schreiben eines Checkpoints wird in diesem Fall ignoriert. Dadurch kann ein Recovery auf einem älteren Stand – einer einzigen Kopie des Read-only-Tablespaces – aufsetzen. Somit bieten sich Read-only-Tablespaces als Mittel zur Reduzierung des Sicherungsaufkommens an, wenn z.B. Tabellen mit nicht änderbarem Inhalt bzw. »alte Partitionen« von Tabellen in Read-only-Tablespaces ausgelagert werden.
3.3.7 Tablespaces offline setzen 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 wiederhergestellt 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:
Datenbankblöcke
123
SQL> 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. Dies ist die Standardoption. SQL> ALTER TABLESPACE demo OFFLINE TEMPORARY;
Für die noch geöffneten Datendateien wird ein Checkpoint geschrieben. Sollten alle zugehörigen Datendateien geöffnet sein, so ist das Verhalten identisch zur Option NORMAL. Der Befehl wird normalerweise verwendet, wenn eine oder mehrere Datendateien defekt sind und deshalb ein OFFLINE NORMAL nicht mehr funktioniert. SQL> 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. SQL> ALTER TABLESPACE demo OFFLINE FOR RECOVER;
Der Tablespace eines Recovery-Sets wird für Point-in-Time-Recovery offline gesetzt. Ein Recovery-Set bezieht sich hierbei auf eine Anzahl Tablespaces, welche die Konsistenz einer Anwendung gewährleisten können und damit für ein Point-in-TimeRecovery als Einheit betrachtet werden sollen.
3.4
Datenbankblöcke
Die in einem Datenbankmanagementsystem gehaltenen Daten müssen aus Gründen der Wiederherstellbarkeit permanent gespeichert werden, so dass Dateien naturgemäß eine zentrale Rolle für Datenbanken spielen. Die Dateien eines relationalen Datenbankmanagementsystems dürfen aber nicht als »flache Dateien«, d.h. Dateien mit einer simplen Satzstruktur, aufgebaut sein, da Änderungen der Datenstruktur, wie das Hinzufügen von Spalten an bestehende Tabellen, im laufenden Betrieb möglich sein müssen. 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. 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 der 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
124
Datenbank-Architektur
Vielfaches von 1 KB, gängige Werte sind 4, 8 oder 16 KB. Wenn die Datenbank einmal angelegt ist, ist die Datenbankblockgröße nicht mehr änderbar und gilt für den SYSTEM-Tablespace und als Standardwert für alle weiteren Tablespaces. Innerhalb einer Datenbank können jedoch mehrere Blockgrößen verwendet werden, jedoch nicht innerhalb einer Datendatei oder eines Tablespaces. Für die Dateien des Datenbanksystems, die Daten enthalten, gilt, dass ihre Dateigröße ein ganzzahliges Vielfaches ihrer Blockgröße ist. 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 hingegen am Blockende und wächst zum Anfang hin.
Abbildung 3.4: Datendatei und Datenbankblock
3.5
Online-Redolog-Dateien
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 Datenbankmanagementsystem – ohne sie wäre ein produktiver Einsatz nicht möglich. Redolog-Dateien speichern also redo-Informationen des Oracle-Systems, d.h. Informationen, die zum Wiederherstellen (redo) von Blockzuständen notwendig sind – im Gegensatz zu den Undo-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 Undo-Blöcken). Notwendig wird das Transaktionsprotokoll durch die asynchrone Arbeitsweise des Database-Writer-Prozesses, der 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.
Online-Redolog-Dateien
125
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(SMON)-Prozess angestoßen, die Transaktionen aus den benötigten Redolog-Dateien nachgefahren. Eine Oracle-Datenbank kennt zwei Typen von Redolog-Dateien: die vom RDBMS ständig zyklisch beschriebenen Online-Redolog-Dateien sowie die (weiter unten beschriebenen) 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-Dateikopien entstehen.
3.5.1 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 wenige Aktivitäten stattfinden. Bei extrem hohen Anforderungen sollte auch über Plattenstriping für die Redolog-Dateien nachgedacht werden. 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 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 als Checkpoint bekannt. 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.
126
Datenbank-Architektur
Da 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 Die Archivierungsprozesse ARCn sichern voll geschriebene Redolog-Dateien in ein dafür konfiguriertes Verzeichnis, idealerweise auf einer eigenen Platte bzw. einem eigenen Volume. Ist der ARCn-Prozess damit noch nicht fertig, wenn die Datei wieder überschrieben werden soll, so erzeugt das einen Wartezustand. Das kann gerade bei hoher Transaktionslast auftreten. Diese Lastspitzen 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 ARCH-Prozess damit mehr Zeit zur Verfügung hat, diese zu sichern. 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. 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 erfahrungsgemäß einige Minuten Instance-Recovery-Zeit. Die genau benötigte Zeit lässt sich schwer voraussagen; sie ist einerseits abhängig von den Leistungsdaten des Systems, andererseits von der Art der protokollierten Aktionen. In den allermeisten Fällen erweist sich diese Zeit nicht als kritisch. 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. Dieses Risiko kann 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 Redolog-Dateien mit einer Größe von mindestens 100 MB (was mittlerweile dem Standardwert, zumindest für Oracle Managed Files, entspricht) empfehlenswert, bei großen Systemen werden durchaus 500 MB und mehr konfiguriert.
Online-Redolog-Dateien
127
Abbildung 3.5: Redolog-Gruppen und Redolog-Member
Alle Redolog-Gruppen sollten identische Dateigrößen aufweisen. Auch wenn die Datenbank prinzipiell unterschiedliche Redolog-Größen zulässt, führt dies in der Praxis nur zu Problemen und sollte daher vermieden werden. Abhängige Serverparameter Zur Beeinflussung des Checkpoint-Verhaltens der Oracle Instanz gibt es diverse Parameter, die als historisch gewachsene Strukturen betrachtet werden können: log_checkpoint_interval und log_checkpoint_timeout sind die auch schon in früheren Oracle-Versionen eingesetzten Parameter, die harte Checkpoints innerhalb der Befüllung einer Redolog-Datei ausgelöst haben. Die Werte werden für log_checkpoint_interval in 512-B-Blöcken, für log_checkpoint_timeout in Sekunden angegeben. Eine grundsätzliche Konfigurationsempfehlung war früher, Checkpoints innerhalb von Redolog-Dateien zu vermeiden und somit Anzahl und Häufigkeit von Checkpoints durch die Größe der Redolog-Dateien zu steuern. Hierzu setzte man log_checkpoint_interval größer als die Redolog-Datei-Größe und log_checkpoint_timeout auf den Wert 0. Die aktuelle Empfehlung lautet, die Parameter auf den Wert 0 zu setzen oder nicht zu setzen, womit ihre Funktion ausgeschaltet ist. Mit Oracle8i wurde für die Enterprise Edition der Parameter fast_start_io_target eingeführt, der die Anzahl der notwendigen IOs für eine Instanzwiederherstellung beschränken sollte. Der Parameter ist zwar auch noch in Oracle 10g vorhanden, wird aber grundsätzlich nicht mehr empfohlen.
128
Datenbank-Architektur
Die Empfehlung gilt aktuell für den mit Oracle9i eingeführten Parameter fast_start_mttr_target, der eine Vorgabe bezüglich der erlaubten Zeit für eine Instanzwiederherstellung in Sekunden erlaubt (auch hier gilt: für die Enterprise Edition). Wie der zuvor genannte Parameter wird hiermit Fast Start Checkpointing aktiviert. Das bedeutet, dass der Database Writer so viel zusätzliche Schreiblast bekommt, um den nächsten Checkpoint bereits im Vorfeld so weit voranzutreiben, dass die angegebene Zeit für die Instanzwiederherstellung ausreichend ist. In Oracle 10g wurde der zugrunde liegende Algorithmus insofern verbessert, dass Zeiten, in denen IO-Kapazitäten frei sind, bevorzugt für diesen Zweck genutzt werden. Für Systeme mit definierten Anforderungen an Wiederanlaufzeiten im Fehlerfall stellt die Möglichkeit der Zeitvorgabe eine komfortable Realisierung der Anforderungen dar.
3.5.2 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 Oracle 10g SQL Reference verwiesen. Die hier vorgestellten Kommandos gelten genauso für Oracle9i und Oracle8i. Zusätzlich können Redolog-Dateien über Oracle Managed Files verwaltet werden. Dabei werden dann die Dateinamen und ev. Größen automatisch vergeben (siehe Kapitel 3.9). Anlegen einer neuen Redolog-Gruppe SQL> ALTER DATABASE ADD LOGFILE GROUP 3 '/disk1/verzeichnis/redo_3_1.log' SIZE 50M;
Der Name der Redolog-Datei sollte die Gruppennummer (hier 3) und die Nummer des Mitglieds einer Gruppe beinhalten (hier 1). Die Dateigröße als Eigenschaft der Redolog-Gruppe sollte angegeben werden, um nicht auf versionsspezifischen Standardwerten zu landen. Hinzufügen eines Mitglieds zu einer Redolog-Gruppe SQL> ALTER DATABASE ADD LOGFILE MEMBER '/disk1/verzeichnis/redo_3_2.log' TO GROUP 3;
Umbenennen von Redolog-Dateien SQL> ALTER DATABASE RENAME FILE '/disk1/verzeichnis/redo_1_1.log' TO '/disk2/verzeichnis_neu/redo_1_1.log’;
Hiermit wird nicht etwa die Redolog-Datei selbst verschoben, sondern lediglich ihr Name in der Kontrolldatei geändert. 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.
Online-Redolog-Dateien
129
Löschen eines Mitglieds einer Redolog-Gruppe SQL> ALTER DATABASE DROP LOGFILE MEMBER '/disk1/verzeichnis/redo_3_2.log';
Dieser Befehl löscht den Eintrag aus der Kontrolldatei. Auf Betriebssystemebene muss die Datei zusätzlich gelöscht werden. Bei Oracle Managed Files werden die Dateien automatisch von der Platte gelöscht. Löschen einer Redolog-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 Betriebssystemebene 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 Redolog-Gruppe oder auch eine einzelne RedologDatei initialisiert werden. 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, dass 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.5.3 Überwachung von Redolog-Dateien Zur Überwachung der Redolog-Dateien stehen folgende V$-Tabellen zur Verfügung: v$log Die Information listet unter anderem die Größe der Dateien (BYTES), den Status der Archivierung (ARCHIVED) und den Status der Datei (STATUS) auf. Folgende Status sind dabei möglich: – INACTIVE: wird zurzeit nicht benutzt, kann also gelöscht werden, solange mehr als zwei Gruppen übrig bleiben. – ACTIVE: Die Datei wird für ein Instance-Recovery benötigt, kann also nicht gelöscht werden. – UNUSED: Die Datei wurde noch nie benutzt, z.B. nach dem neuen Anlegen. – CURRENT: in dieser Datei wird zurzeit geschrieben.
130
Datenbank-Architektur
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. Um sich die Größe und Lage der Redolog-Dateien anzusehen, muss man einen Join über die Tabellen v$log und v$logfile mit der Spalte GROUP# durchführen, z.B. in der Form: SQL> SELECT v.group#, vl.member, v.bytes, v.status FROM v$log v,v$logfile vl WHERE v.group# = vl.group#; GROUP# MEMBER BYTES STATUS ---------- ----------------------------------- ---------- ---------------1 D:\ORACLE\ORADATA\QJA10G\REDO01.LOG 10485760 INACTIVE 2 D:\ORACLE\ORADATA\QJA10G\REDO02.LOG 10485760 CURRENT 3 D:\ORACLE\ORADATA\QJA10G\REDO03.LOG 10485760 INACTIVE Listing 3.10: Redolog-Informationen
v$loghist und v$log_history 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 Kontrolldateien. 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.
3.5.4 Überlegungen zur Spiegelung von Redolog-Dateien Redolog-Dateien sind die kritischen Dateien einer Oracle-Datenbank im Fehlerfall. Datendateien und Kontrolldateien können wiederhergestellt werden, vorausgesetzt, es existiert eine Sicherung. Redolog-Dateien beinhalten aktuelle 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 Redolog-Dateien zu spiegeln. Dabei steht zur Auswahl, entweder eine Oracle-seitige Spiegelung einzuschalten (also pro Redolog-Gruppe mindestens zwei Member auf verschiedenen Platten zu konfigurieren) oder die Dateien der Redolog-Gruppen auf betriebssystem- oder hardwareseitig gespiegelte Platten zu legen. Von einer Spiegelung über RAID 5 sollte abgesehen werden, da die benötigte IO-Kapazität durch solche Systeme i.A. nicht gewährleistet werden kann. 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. Betriebssystem- oder hardwareseitige Spiegelungen sind für den Logwriter-Prozess transparent.
Kontrolldateien
3.6
131
Kontrolldateien
Eine zentrale Aufgabe haben 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 Kontrolldateien sind die kleinsten Komponenten (wenige MB) einer OracleDatenbank, haben aber sowohl für die Verfügbarkeit als auch für die Konsistenz der Datenbank eine zentrale Bedeutung, besonders im Wiederherstellungsfall. In einer Kontrolldatei sind Informationen über die Datenbank und alle Dateien abgelegt, die zur Datenbank gehören. Dabei besteht eine Eins-zu-eins-Zuordnung der Kontrolldatei zu einer Datenbank. Wichtige Informationen, die in einer Kontrolldatei gespeichert werden, sind unter anderem: der Name und Erstellungszeitpunkt der Datenbank (v$database) die Namen der zur Datenbank gehörenden Kontroll-, Daten-, Temporär- und Redolog-Dateien mit kompletter Pfadangabe und Statusinformationen wie Offline, Read-only usw. (v$controlfile, v$datafile, v$tempfile, v$logfile, v$log) Informationen über Tablespaces (v$tablespace) Informationen über den Archivierungsstatus (v$archived_logs) Redolog-Historie (v$log_history) Informationen für den Recovery-Manager (v$backup_<xxx>) die aktuelle Log-Sequence-Nummer Checkpoint-Informationen Die Tatsache, dass die Informationen aus den o.a. v$-Views aus der Kontrolldatei kommen, kann leicht überprüft werden, indem man sie im MOUNT-Status einer Instanz abfragt. Die Kontrolldateien sind sowohl beim Starten des Oracle-Systems als auch während des normalen Datenbankbetriebs im Zugriff. Die Aktualisierung der Kontrolldateien erfolgt über die Instanz beim Auftreten eines Checkpoints oder bei Strukturänderungen an der Datenbank. Strukturänderungen der Datenbank sind beispielsweise das Hinzufügen, Umbenennen und Löschen von Datendateien oder Tablespaces, RedologGruppen oder Redolog-Membern. Konsistenzinformationen bezüglich der Datendateien werden redundant in der Kontrolldatei und in den Header der betreffenden Dateien gespeichert und bei Bedarf – z.B. beim Starten der Datenbank – verglichen. Ein Abgleich der Informationen findet darüber hinaus bei einem Checkpoint statt. Zudem speichert der Checkpoint-Prozess in Intervallen von drei Sekunden den Status der Redolog-Dateien in der Kontrolldatei, um parametrierte Grenzen wie z.B. log_checkpoint_interval oder log_checkpoint_timeout abgleichen zu können.
132
Datenbank-Architektur
Diese Konsistenzinformationen bestimmen bei einer Instanzwiederherstellung oder bei einer Medienwiederherstellung, welche Informationen aus RedologDateien 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 eine unvollständige Medienwiederherstellung durchgeführt werden, was einen Datenverlust nach sich zieht. Die Kontrolldateien 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 durchgeführt werden, sollte anschließend sofort eine Sicherung der Kontrolldatei vorgenommen werden.
3.6.1 Administration der Kontrolldateien Anlegen der Kontrolldateien Die Kontrolldatei wird automatisch beim Anlegen der Datenbank erzeugt. Die Lage der Kontrolldatei wird dabei über den Serverparameter control_files bestimmt. Die Größe wird abhängig vom CREATE DATABASE-Kommando der 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 Kontrolldatei zu lösen, was man in der Praxis jedoch vermeiden sollte. Spiegelung der Kontrolldateien Die Wichtigkeit der Kontrolldateien, 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 sehr empfehlenswert, die Kontrolldateien zu spiegeln. Auch hier stehen datenbank-, betriebssystem- und hardwareseitige Spiegelung zur Auswahl. Im Folgenden wird das Verfahren zur Einrichtung einer datenbankseitigen Spiegelung beschrieben (Pfadangaben für Unix): Der aktuelle Eintrag in der Parameterdatei laute beispielsweise: control_files = '/oradata1/PDWH10G/control01.ctl'
Zunächst wird der Eintrag geändert auf: control_files = '/oradata1/PDWH10G/control01.ctl', '/oradata2/PDWH10G/control02.ctl'
Dies geschieht entweder manuell bei Verwendung einer herkömmlichen Parameterdatei oder – bei Verwendung einer Serverparameterdatei – über folgendes Kommando:
Kontrolldateien
133
SQL> ALTER SYSTEM SET CONTROL_FILES = '/oradata1/PDWH10G/control01.ctl', '/oradata2/PDWH10G/control02.ctl' SCOPE = SPFILE;
Anschließend wird die Instanz heruntergefahren und die Kontrolldatei auf Betriebssystemebene kopiert: $ cp /oradata1/PDWH10G/control01.ctl /oradata2/PDWH10G/control02.ctl
Zum Schluss wird die Instanz wieder hochgefahren. Es ist unbedingt zu beachten, dass die Kontrolldateien 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. Umbenennen oder Verlagern der Kontrolldateien Für das Umbenennen oder Verlagern der Kontrolldateien 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 Kontrolldateien Eine Kontrolldatei kann während des laufenden Betriebes durch folgendes Kommando gesichert werden: SQL> ALTER DATABASE BACKUP CONTROLFILE TO '/orabackup/PDWH10G/control_bck.ctl';
Bei Verlust der Kontrolldatei 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 Skripts 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 das CREATE CONTROLFILE-Kommando, inklusive Kommentierung der einzelnen Schritte. Dieses Skript 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 Skript kann editiert werden, wobei man dann höhere MAX-Werte einträgt. Das Erzeugen einer Kontrolldatei ist jedoch immer ein Vorgang, der große Sorgfalt erfordert und für den das Oracle-System gestoppt werden muss. In der Oracle-Dokumentation wird angeraten, sowohl vor als auch nach der Ausführung des CREATE CONTROLFILE-Kommandos eine Sicherung zu machen.
134
Datenbank-Architektur
Beispiel eines CREATE CONTROLFILE-Kommandos: STARTUP NOMOUNT CREATE CONTROLFILE REUSE DATABASE "PDWH10G" ARCHIVELOG MAXLOGFILES 32 MAXLOGMEMBERS 3 MAXDATAFILES 254 MAXINSTANCES 1 MAXLOGHISTORY 454 LOGFILE GROUP 1 '/oradata1/PDWH10G/redo_1_1.log' GROUP 2 '/oradata1/PDWH10G/redo_2_1.log' GROUP 3 '/oradata1/PDWH10G/redo_3_1.log' DATAFILE '/oradata1/PDWH10G/system01.dbf', '/oradata1/PDWH10G/sysaux01.dbf', '/oradata1/PDWH10G/undotbs01.dbf', '/oradata1/PDWH10G/users01.dbf', '/oradata1/PDWH10G/tools01.dbf', '/oradata1/PDWH10G/indx01.dbf' CHARACTER SET WE8ISO8859P15 ;
NORESETLOGS
SIZE 50M, SIZE 50M, SIZE 50M
Kontrolldateien und Oracle Managed Files Die Kontrolldateien können auch als Oracle Managed Files angelegt werden. Das bedeutet, dass nicht durch den Serverparameter control_files die Namen bestimmt werden, sondern dass das Oracle-System beim Anlegen der Datenbank eigene eindeutige Dateinamen generiert. Die Lage der Kontrolldateien wird dann über den Serverparameter db_create_online_log_dest_n = /platte/pfad
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 anschließend über den Parameter control_files eingetragen werden. Bei Verwendung einer Serverparameterdatei entfällt diese Maßnahme.
Parameterdateien
3.7
135
Parameterdateien
Die Parameterdatei enthält sämtliche Serverparameter für einen Oracle-Server. Hieraus werden beim Systemstart die Konfiguration und das Verhalten der Instanz bestimmt. Unter anderem enthält die Parameterdatei den oder die Namen der Kontrolldateien. Seit Oracle9i gibt es sie in zwei Varianten. Herkömmliche Parameterdatei (PFILE bzw. init.ora) Zum Begriff Parameterdatei 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 initPDWH10G.ora; er kann aber auch frei gewählt werden. Beim Hochstarten der Datenbanken wird – wenn nichts anderes angegeben wird – standardmäßig die Datei mit dem Namen init.ora im Verzeichnis \database (für MS-Windows) bzw. /dbs (für andere Plattformen) benutzt, daher findet man die Parameterdatei häufig unter diesem Pfad. 2. Die Start- oder Serverparameter einer Oracle-Instanz heißen in der Oracle-Anwendergemeinde »init.ora-Parameter«, da sie traditionell in der »init.ora-Datei« gespeichert werden. Da die Speicherung der Parameter in der init.ora-Datei nur noch eine von vielen Möglichkeiten ist, wird in diesem Buch die Bezeichnung Serverparameter vorgezogen. Serverparameterdatei Die Konfiguration einer Instanz über eine herkömmliche Parameterdatei ist problematisch, wenn Start- und Stoppvorgänge in einer verteilten Rechnerumgebung vorgenommen werden. Das liegt daran, dass das Client-Werkzeug, das den STARTUPBefehl ausführt, die Parameterdatei 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. Seit Oracle9i besteht die Möglichkeit, alternativ zur herkömmlichen Parameterdatei eine so genannte Serverparameterdatei zu nutzen. Diese wird in einem Binärformat auf dem Server gespeichert und kann aus einer bestehenden herkömmlichen Parameterdatei erzeugt werden. Falls eine Serverparameterdatei existiert, wird diese anstelle der herkömmlichen Parameterdatei zur Konfiguration beim Instanzstart benutzt. Der Inhalt der Serverparameterdatei wird mit Hilfe von ALTER SYSTEMBefehlen modifiziert. Die Serverparameterdatei wird beim STARTUP-Kommando stets auf der Serverseite im Verzeichnis $ORACLE_HOME/dbs (auf Unix) bzw. %ORACLE_HOME%\database (auf MSWindows) unter dem Namen spfile.ora gesucht.
136
Datenbank-Architektur
Achtung: Auch wenn eine Serverparameterdatei auf den ersten Blick bequem im Texteditor manuell editiert werden kann, stellt sich auf den zweiten Blick heraus, dass sie Prüfsummen enthält. Nach einer manuellen Veränderung ist die Serverparameterdatei daher meistens unbrauchbar und wird beim Versuch, die Instanz zu starten, abgelehnt. Stattdessen kann über die Kommandos SQL> CREATE SPFILE='/pfad/auf/server/spfileXYZ.ora' FROM PFILE ='/pfad/auf/client/initXYZ.ora';
bzw. SQL> CREATE PFILE ='/pfad/auf/client/initXYZ.ora' FROM SPFILE='/pfad/auf/server/spfileXYZ.ora';
zwischen einer herkömmlichen Parameterdatei und einer Serverparameterdatei umgewandelt werden. Am einfachsten kann dieser Befehl mit den Standardvorgaben verwendet werden. Der Befehl SQL> CREATE SPFILE FROM PFILE;
erstellt die Datei spfile.ora im Standardverzeichnis ($ORACLE_HOME/dbs bzw. %ORACLE_HOME%\database), wenn diese noch nicht existiert bzw. wenn die Datenbank nicht mit dieser Datei hochgefahren wurde. Ansonsten wird der Befehl abgelehnt. SQL> CREATE PFILE FROM SPFILE;
Hiermit wird ebenfalls im Standardverzeichnis die Datei init.ora erstellt. Allerdings sollten Sie hierbei aufpassen, da eine ältere Version ohne Rücksicht überschrieben wird. Den Trick, mit CREATE PFILE FROM SPFILE eine temporäre herkömmliche Parameterdatei zu erzeugen, diese zu editieren und dann mit CREATE SPFILE FROM PFILE vor dem STARTUP wieder eine Serverparameterdatei zu erzeugen, benötigt man u.a. dann, wenn man einen Parameter ganz austragen will oder sich ein Fehler eingeschlichen hat, mit dem der STARTUP nicht mehr möglich ist – das ALTER SYSTEM SET-Kommando mit SCOPE = SPFILE funktioniert nämlich ausschließlich bei hochgefahrener Instanz.
3.8
Block-Change-Tracking-Datei
Neben den Redologs, die grundsätzlich gepflegt werden, sowie den Flashback-Logs, die optional eingeschaltet werden können, gibt es einen weiteren Mechanismus, um Änderungen der Datenbank zu protokollieren. Der Hintergrund beim so genannten Block Change Tracking ist es, inkrementelle Sicherungsstrategien zu erleichtern. Mit dem mitgelieferten Werkzeug RMAN (Recovery Manager) kann eine OracleDatenbank aufbauend auf einem initialen vollständigen Backup jeweils inkrementell gesichert werden, es werden also nur die Änderungen seit dem letzten Backup gesichert (siehe Kapitel 10). Dies funktioniert insbesondere bei Datenbanken mit geringem bis mäßigen Änderungsvolumen sehr gut. Bis Oracle9i musste nichtsdestoweniger zur Erstellung des inkrementellen Backups der gesamte Datenbankinhalt gelesen werden, um alle seit dem letzten Backup geänderten Blöcke zu finden.
Block-Change-Tracking-Datei
137
Mit Oracle 10g ist die Möglichkeit geschaffen worden, alle Blockänderungen von vornherein mitzuprotokollieren. Im Gegensatz zu den Redologs geht es hierbei nicht darum, die geänderten Daten selbst zu protokollieren und im Recovery-Fall nachspielen zu können, sondern es genügt – unabhängig von der Anzahl und Art der Änderungen eines Blocks –, lediglich ein Flag zu pflegen, das anzeigt, dass der Block geändert wurde. Dabei dürfen natürlich auch Einfügungen durch Direct-Loads, die in den Redolog-Dateien u.U. nicht protokolliert werden, für das Backup nicht verloren gehen. Aus diesen Anforderungen heraus erklärt sich, dass ein weiterer, eigenständiger Logging-Mechanismus, nämlich das Block Change Tracking, geschaffen wurde. Die binäre Log-Datei enthält Flags, die für jeden 32 KB-Block der Datenbank anzeigen, ob der Block geändert wurde (die Granularität beträgt unabhängig von den tatsächlichen Oracle-Blockgrößen stets 32 KB). Daher sind der Protokollierungs-Overhead und der Umfang der anfallenden Logging-Daten minimal. Alle Log-Daten einer Datenbank werden in einer einzigen Block-Change-Tracking-Datei abgespeichert, deren Größe ca. 1/30000 der Gesamtgröße aller Datendateien beträgt (je 32 KB Daten werden auf ein Bit abgebildet, außerdem werden bis zu 8 Bitmaps zurückliegender Backups gepflegt), aufgerundet auf volle 10 MB sowie auf 320 KB pro Datendatei. Für Datenbanken bis 300 GB beträgt die Größe dieser Log-Datei also lediglich 10 MB, bis 600 GB Datenbankgröße 20 MB etc. Bei vielen, kleinen Datendateien kann sie wegen der erwähnten Aufrundung etwas größer werden. Bei mehreren Redolog-Threads (in RAC-Umgebungen) ist die so ermittelte Größe noch mit der Anzahl der aktiven Threads zu multiplizieren. Das Block Change Tracking kann im laufenden Betrieb unter Angabe der LoggingDatei eingeschaltet werden: SQL> ALTER DATABASE ENABLE BLOCK CHANGE TRACKING USING FILE '/disk1/verzeichnis/block_changes.chg';
Verwendet man Oracle Managed Files, empfiehlt es sich, die USING-Klausel wegzulassen. Der Zielort für die Block-Change-Tracking-Datei ergibt sich dann aus den Serverparametern db_create_file_dest und db_unique_name, als: //changetracking Abgesehen von der Möglichkeit, die Log-Datei zu verschieben, ist die Verwaltung der Datei ansonsten vollständig automatisiert. Auch die Nutzung der Datei durch RMAN im Rahmen inkrementeller Sicherungen geschieht automatisch. Über die Spalte status der View v$block_change_tracking kann abgefragt werden, ob Block Change Tracking zurzeit aktiviert ist. Die eigentliche Protokollierung wird durch den CTWR-Hintergrundprozess geleistet, der bei Redolog-Schreibvorgängen vom LGWR-Prozess angestoßen wird. Beim inkrementellen Backup liest RMAN nur noch diejenigen Blöcke, die laut Tracking-Datei geändert wurden. Dies kann auch über die Spalte used_change_tracking der View v$backup_datafile nachvollzogen werden. Die Tracking-Datei selbst ist nicht Bestandteil der Sicherung. Achtung: Inkrementelle Backups mit RMAN – mit oder ohne Block Change Tracking – sind nur mit der Enterprise Edition der Oracle 10g-Datenbank möglich! Außerdem sollte Block Change Tracking erst ab dem Patch-Level 10.1.0.3 verwendet werden, da die Funktionalität zuvor durch verschiedene Software-Bugs deutlich eingeschränkt war.
138
3.9
Datenbank-Architektur
Physikalisches Layout
Das physikalische Layout der Datenbank entscheidet sowohl über die Performance der Datenbank als auch über Administrierbarkeit und Übersichtlichkeit. In vielen Fällen wird der Standard verwendet – ein lokales Dateisystem. Unter MS-Windows sind NTFS, unter Unix diverse Derivate wie Reiser-FS unter Linux Beispiele hierfür. Eine grundsätzliche Empfehlung ist, immer Logging-Dateisysteme für den Betrieb von Datenbanken zu wählen, da diese gegenüber Systemabstürzen wesentlich stabiler und nach Systemabstürzen deutlich schneller wieder verfügbar sind. Also: unter MS-Windows »Finger weg von FAT«! Es gibt zwei Gründe, kein lokales Dateisystem zu verwenden: Performance und der Einsatz von RAC. Die Performance-Frage bezieht sich darauf, dass ein Dateisystem grundsätzlich mit einem Cache im RAM arbeitet. Dieser wird zwar von Oracle grundsätzlich nicht genutzt – zumindest alle Schreiboperationen arbeiten mit write through cache –, er muss jedoch trotzdem verwaltet werden und nimmt einen nicht unerheblichen Teil des RAM in Anspruch. Weicht man z.B. auf Raw Devices aus, so entfällt der Dateisystem-Cache komplett, was per se zu einem besseren IO-Durchsatz führt. Der Dateisystem-Cache ist auch der Grund dafür, dass ein lokales Dateisystem nicht für RAC-Konfigurationen verwendet werden kann – es ist nun einmal für einen Rechner lokal und damit in diesem Moment für die anderen nicht nutzbar.4 RAC setzt aber den gleichberechtigten, gleichartigen Zugriff für alle Rechner voraus.
3.9.1 Dateisystem Oracle gibt im Rahmen der so genannten Optimal Flexible Architecture (OFA) bestimmte Empfehlungen hinsichtlich der Speicherung von Datendateien. Diese Empfehlungen haben sich (teilweise in leicht abgewandelter Form) in der Praxis als sehr sinnvoll herausgestellt: Alle Datenbankdateien außer Parameterdatei und Passwortdatei sollten auf einem anderen physikalischen Datenträger gespeichert werden als die OracleSoftware Für Unix: Die Mountpoints für die Datenbankdateien sind von der Form /<mp>, wobei <mp> für einen beliebigen, kurzen String steht und eine laufende Nummer darstellt. Typische Mountpoints sind beispielsweise /u01, /u02 … oder /disk01, /disk02 … Für MS-Windows: Die Mountpoints für die Datenbankdateien sind von der Form X:\oracle, wobei X für einen Laufwerksbuchstaben steht. Typische Mountpoints sind beispielsweise D:\oracle, E:\oracle etc.
4
Die Verwendung von NFS-Filesystemen ist nur in Ausnahmefällen mit spezieller Hardware erlaubt (z.B. Network Applicance oder kurz NetApp).
Physikalisches Layout
139
Unterhalb eines Mountpoints befindet sich ein Verzeichnis oradata und darunter ein Verzeichnis mit dem Datenbanknamen (Serverparameter db_name bzw. db_unique_name für Oracle 10g-Datenbanken). Dies ist das Verzeichnis für die Datenbankdateien, beispielsweise /u01/oradata/PDWH10G für eine Datenbank mit dem Namen PDWH10G. Redolog- und Archivelog-Dateien sollten sich auf einem anderen physikalischen Datenträger als die Datendateien befinden, damit im Fall eines Medienfehlers des Datenträgers mit den Datendateien eine Wiederherstellung mit Hilfe der Log-Dateien möglich ist. Wird die Kontrolldatei gespiegelt, sollten sich die verschiedenen Kontrolldateien auf unterschiedlichen physikalischen Datenträgern befinden, damit im Fall eines Medienfehlers nicht alle Kontrolldateien beschädigt sind. Zwecks besserer Unterscheidbarkeit sollten für Datenbankdateien die folgenden Dateiendungen verwendet werden: – .dbf für Datendateien (auch für System-, SysAux- und Undo-Tablespaces), – .tmp für Temporärdateien (Temporär-Tablespaces) – .log für Online-Redolog-Dateien – .arc für archivierte Redolog-Dateien (einstellbar über den Serverparameter log_archive_format) – .ctl für Kontrolldateien (einstellbar über den Serverparameter control_files) – .bct für Block-Change-Tracing-Dateien (einstellbar bei der Aktivierung des Block Change Trackings) – .flb für Flashback-Logs (werden automatisch erstellt und verwaltet) Daten- und Temporärdateien sollten im Dateinamen den Namen des Tablespaces sowie eine zweistellige fortlaufende Nummer enthalten, z.B. system01.dbf, temp01.tmp etc. Online-Redolog-Dateien sollten das Wort »redo« sowie die Gruppen- und Member-Nummer enthalten, also beispielsweise redo_02_1.log für den ersten Member der zweiten Redolog-Gruppe. Werden ausschließlich Hardware- oder RAIDSpiegelungen benutzt, kann die Member-Nummer auch weggelassen werden. Archivierte Redolog-Dateien sollten den Datenbanknamen (Serverparameter db_name bzw. db_unique_name für Oracle 10g-Datenbanken), die so genannte LogSequence-Number sowie die Nummer des Redolog-Threads enthalten. Dies wird über die Einstellung des Serverparameters log_archive_format erreicht. Für Oracle 10g-Datenbanken sollte außerdem unbedingt die Resetlogs-ID mit angegeben werden, um ein Recovery zu vereinfachen. Empfehlenswert ist hier beispielsweise für eine Datenbank mit dem Namen PDWH10G der Wert: log_archive_format = PDWH10G_%r_%t_%s.arc.
140
Datenbank-Architektur
Oracle Managed Files Seit Oracle9i kann die Verwaltung von Datenbankdateien auf Wunsch auch weitestgehend der Datenbank überlassen werden. Zu diesem Zweck müssen Standardpfade für neue Datenbankdateien konfiguriert werden. Anschließend können bei der Erstellung von Tablespaces, beim Hinzufügen von Daten-, Temporär- oder Redolog-Dateien oder auch bei der Erstellung einer neuen Datenbank die Klauseln, die sich auf Dateinamen und Größen beziehen, einfach weggelassen werden. Zum Beispiel: SQL> SQL> SQL> SQL>
CREATE TABLESPACE users; ALTER TABLESPACE users ADD DATAFILE; ALTER DATABASE ADD LOGFILE GROUP 4; CREATE DATABASE;
Listing 3.11: Listing 3.1: Beispiele für Oracle Managed Files
Für die verschiedenen Arten von Datenbankdateien können unterschiedliche Pfade konfiguriert werden. Dabei spielen folgende Serverparameter eine Rolle: Der Parameter db_create_file_dest gibt ein Basisverzeichnis für Daten- und Temporärdateien an. Die Parameter db_create_online_log_dest_ ( = 1, 2, 3, 4, 5) geben bis zu fünf Basisverzeichnisse für Redolog-Gruppen und Kontrolldateien an. Die angegebenen Pfade sollten auf jeweils unterschiedlichen physikalischen Datenträgern und auf einem anderen Datenträger als db_create_file_dest liegen. Hintergrund ist, dass die einzelnen Member (Spiegel) einer Redolog-Gruppe sowie die Spiegel der Kontrolldatei entsprechend auf die angegebenen Pfade verteilt werden. Der Parameter db_recovery_file_dest ist erst ab Oracle 10g definiert und gibt ein Basisverzeichnis für Flashback-Logs und archivierte Redolog-Dateien an. In Oracle9i werden die entsprechenden Dateien als Oracle Managed Files direkt in den beschriebenen Basisverzeichnissen abgespeichert. In Oracle 10g hat man etwas mehr Ordnung hereingebracht. In dem Basisverzeichnis wird zunächst ein Unterverzeichnis mit dem Datenbanknamen angelegt (Serverparameter db_unique_name), hierin wird ein weiteres Unterverzeichnis gemäß dem Dateityp (z.B. onlinelog für die Online-Redolog-Dateien) angelegt. Der letzte Schritt entspricht zwar formal nicht den OFA-Regeln, bringt aber jedenfalls noch etwas mehr Übersichtlichkeit. Abbildung 3.6 zeigt noch einmal zusammenfassend die Speicherung von Datenbankdateien als Oracle Managed Files in Oracle 10g. Der grau unterlegte Bereich gilt für Oracle9i.
Physikalisches Layout
141
Abbildung 3.6: Speicherorte und Dateiendungen für Oracle –Managed Files
Neben den beschriebenen Standardpfaden ist auch die Namensgebung für Oracle – Managed Files festgelegt. Diese Dateien haben stets Namen der Form o1_mf__.<endung>. Dabei steht <endung> für eine der aufgeführten Dateiendungen, ist eine Zeichenkette, die einerseits eine eindeutige Beziehung zu dem zugrunde liegenden Objekt schaffen, andererseits den Dateinamen auch eindeutig machen soll. Für Datendateien ist beispielsweise von der Form _, wobei der auf acht Zeichen abgeschnittene Name des Tablespaces und eine eindeutige achtstellige Zeichenkombination darstellt. z.B.: SQL> CREATE TABLESPACE daten_big; SQL> SELECT file_name FROM dba_data_files WHERE tablespace_name = 'DATEN_BIG'; FILE_NAME -----------------------------------------------------------D:\ORACLE\ORADATA\PS10\DATAFILE\O1_MF_DATEN_BI_1GBKDX9R_.DBF
142
Datenbank-Architektur
Nach der Erstellung können OMF wie andere Dateien auch behandelt werden, insbesondere können sie umbenannt und verschoben werden. Für den Status als OMF ist nicht der Pfad, sondern ausschließlich der Dateiname relevant. Jede Datei mit einem Dateinamen der Form o1_mf_*_.<endung> wird von Oracle als OMF identifiziert. Das explizite Anlegen einer solchen Datei z.B. als Datendatei oder RedologDatei ist nicht erlaubt und wird mit einer Fehlermeldung quittiert, z.B.: SQL> CREATE TABLESPACE daten_big DATAFILE 'D:\ORACLE\ORADATA\PS10\O1_MF_DATEN_BI_1GBKDX9R_.DBF'; CREATE TABLESPACE daten_big * FEHLER in Zeile 1: ORA-01276: Datei D:\ORACLE\ORADATA\PS10\O1_MF_DATEN_BI_1GBKDX9R_.DBF kann nicht hinzugefügt werden. Datei hat Name von Oracle Managed Files.
Ein nachträgliches Umbenennen einer Datendatei in eine OMF-Datei und auch ein nachträgliches Verschieben einer OMF-Datei in ein anderes Verzeichnis ist jedoch möglich, z.B.: SQL> ALTER TABLESPACE daten_big OFFLINE; Tablespace wurde geändert. SQL> -- Verschieben der Datendatei auf Betriebssystemebene SQL> ALTER DATABASE RENAME FILE 'D:\ORACLE\ORADATA\PS10\DATAFILE\O1_MF_DATEN_BI_1GBLCKON_.DBF' TO 'D:\ORACLE\ORADATA\PS10\O1_MF_DATEN_BI_1GBLCKON_.DBF';
Letztlich ist jedoch die entscheidende Frage, worin die Vorteile von Oracle Managed Files besteht und wie man diese Funktionalität am besten einsetzen sollte. OMF vereinfachen die Erstellung und Erweiterung von Tablespaces und Redolog-Gruppen. Setzt man dies konsequent ein, werden sämtliche Datenbankdateien außer Parameter- und Passwortdatei automatisch erzeugt und benannt. Dies ist vor allem für Test- und Entwicklungsumgebungen ein Vorteil. In produktiven Umgebungen ist die automatische Erstellung von Daten- und Temporärdateien nur sinnvoll, wenn es einen einzigen Mountpoint gibt, der über die darunter liegende Hardware eine I/O-Parallelisierung durchführt. Liegen dagegen mehrere Mountpoints vor bzw. wird die I/O-Verteilung eher manuell durch geschicktes Verteilen der Tablespaces über die Mountpoints durchgeführt, kommen OMF dafür nicht in Frage. Das versehentliche Erstellen einer Datendatei in einem nicht dafür vorgesehenen Verzeichnis ist ausgeschlossen. Beim Löschen eines Tablespaces oder einer Redolog-Gruppe werden die zugehörigen Dateien auf Betriebssystemebene automatisch gelöscht. Das versehentliche Löschen einer falschen Datei ist dadurch ausgeschlossen. Für Daten- und Temporärdateien gibt es diese Möglichkeit allerdings bereits durch die Klausel INCLUDING CONTENTS AND DATAFILES des DROP TABLESPACE-Kommandos. Außerdem kommt das Löschen eines Tablespaces im produktiven Betrieb nicht häufig vor, wohl aber in Test- oder Entwicklungsumgebungen.
Physikalisches Layout
143
SQL-Skripte, die Tablespace-Definitionen enthalten, können plattformunabhängig geschrieben werden. Lediglich die genannten Serverparameter müssen zuvor plattformabhängig gesetzt werden. Sie verhindern häufig fruchtlose Diskussionen über geeignete Namensgebungen für Datenbankdateien. Zusammenfassend lässt sich sagen, dass OMF für Test- und Entwicklungsumgebungen eine gute Wahl darstellen sowie für Produktionsumgebungen, die über ein leistungsfähiges SAN-Storage verfügen, das dem DBA Fragen bzgl. I/O-Verteilung abnimmt. Ggf. sollte trotzdem eine SIZE-Klausel mit angegeben werden (Standardgröße für Daten-, Temporär- und Redolog-Dateien ist 100MB), auf jeden Fall sollte im Rahmen der AUTOEXTEND-Klausel eine Maximalgröße gesetzt werden, da OMF sonst mit unbegrenztem Wachstum erstellt werden. Für Oracle9i muss unbedingt auch die Erweiterungsgröße (NEXT-Klausel) vom Standardwert (ein Block bei Oracle9i, 100 MB bei Oracle 10g) auf einen sinnvollen Wert geändert werden, also z.B.: SQL> CREATE TABLESPACE users DATAFILE SIZE 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 5000M; SQL> ALTER TABLESPACE users ADD DATAFILE SIZE 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 5000M;
3.9.2 Cluster-Dateisystem Cluster-Dateisysteme werden meist vom Systemhersteller als Zusatzoption für Cluster-Systeme angeboten; für Linux existiert das Projekt Oracle Cluster File System im Rahmen des Oracle Technology Networks, das unter GNU General Public License (GPL) veröffentlicht wird. Cluster-Dateisysteme werden wie lokale Dateisysteme in den Verzeichnisbaum integriert, mit dem Unterschied, dass dies auf mehreren Rechnern gleichzeitig passieren kann. Damit können sie für RAC-Konfigurationen verwendet werden. Dadurch dass bei Cluster-Dateisystemen im Normalfall wiederum DateisystemCaches vorhanden sind, sind sie in den meisten Fällen langsamer als Raw Devices; allerdings sind die Vorzüge bei der Administrierbarkeit nicht zu unterschätzen. Bei einigen Cluster-Dateisystemen ist es möglich, die Installation der Oracle Software im Cluster-Dateisystem durchzuführen. Damit wird der Installationsaufwand minimiert, z.B. auch für neue Knoten, die ins Cluster integriert werden sollen, allerdings zum Preis einer weniger flexiblen Konfiguration. Für Umgebungen mit Forderungen für absolut kleine Auszeiten bei Wartungsarbeiten ist eine lokale Installation auf jedem einzelnen Knoten vorzuziehen. Dieses Konzept wird vom Univeral Installer ebenfalls komfortabel unterstützt. Ansonsten ist über Cluster-Dateisysteme wenig Allgemeines zu sagen – dazu sind die einzelnen Lösungen zu systemspezifisch.
144
Datenbank-Architektur
3.9.3 Raw Devices Raw Devices sind eine Spezialität von Unix-Systemen und seit langer Zeit die Alternative zu Dateisystemen. Übrigens bieten viele Systeme mittlerweile einen Logical Volume-Manager an, der wesentlich mehr Komfort für Raw Devices bietet als das reine Betriebssystem. Mit einem Logical Volume-Manager lassen sich Logical Volumes erzeugen, für die praktisch alle Aussagen über Raw Devices ebenfalls zutreffen. Bei einem normalen Filesystem, wie es unter Unix und Linux in diversen Versionen zur Verfügung steht, wird ein physikalischer Plattenbereich, ein so genanntes Device, entsprechend formatiert, z.B. mit dem Befehl newfs. Dieses Filesystem wird dann als Mountpoint angeschlossen und kann jetzt von jedem, der die Berechtigung dazu hat, mit Dateien gefüllt werden. Ein Buffercache im Memory sorgt dafür, dass die wichtigsten Daten sowie die Dateisystemstruktur immer im Hauptspeicher bleiben und somit eine optimale Performance gewährleistet ist. Wenn man sich die Oracle-Datenbankstruktur ansieht, stellt man fest, dass Oracle genauso funktioniert: Mit dem Befehl CREATE TABLESPACE … DATAFILE … wird ein entsprechender Bereich formatiert (in Oracle-Blöcken), und über die SGA wird ein Buffercache im Memory zur Verfügung gestellt. Also stellt sich die Frage: Wofür braucht man noch ein Filesystem? Ganz im Gegenteil, bei Schreiboperationen muss verhindert werden, dass die Daten im Betriebssystemcache hängen bleiben. Somit ist dieser für Oracle fast wertlos. Also ist es unter Umständen sinnvoller, die Oracle-Datendateien direkt auf die Raw Devices zu platzieren und damit den Overhead des Betriebssystems zu eliminieren. Das wird jedoch mit einer Einschränkung in der Flexibilität erkauft. Raw Devices haben eine bestimmte Größe, die, wenn überhaupt, nur mit Betriebssystemkommandos geändert werden kann. Je Raw Device kann außerdem nur genau eine Oracle-Datei benutzt werden, so dass von vornherein klar sein muss, wie groß die Dateien werden. Ein AUTOEXTEND der Datendatei ist also nicht möglich. Außerdem ist dem Betriebssystem oft nicht bekannt, dass die Dateien in Benutzung sind, somit kann jederzeit mit dem Befehl newfs ein Filesystem auf das Raw Device angelegt und damit die Datenbank zerstört werden. An dieser Stelle empfehlen sich Logical Volumes, deren Namen man bei der Erstellung bestimmen kann. Hier sollte man für Oracle Logical Volumes Standards wie lora__xxx benutzen. Ein weiterer gerne genutzter Trick ist, die Raw Devices nicht direkt als Datenbankdateien zu verwenden, sondern ein Verzeichnis zu erstellen, das symbolische Links auf die Raw Devices enthält. Die Namen der symbolischen Links können dann wieder sprechend bezüglich ihrer Bedeutung in der Datenbank sein. Die symbolischen Links (inklusive des vollständigen Pfads) werden dann als Namen für die Datenbankdateien verwendet. Mit einem Listing des Verzeichnisses hat der Administrator nun eine einfache Möglichkeit, die verwendeten Raw Devices abzufragen. Obwohl Raw Devices grundsätzlich schnellere IOs erlauben als Dateisysteme, sollten sie nicht ohne Vorüberlegungen eingesetzt werden. Die Administration einer Oracle-Datenbank mit Raw Devices ist um einiges komplexer als bei der Verwendung von normalen Dateien. Weiterhin werden die Vorteile im IO-Bereich oft gar nicht bemerkt, da z.B. alle DBW0-IOs asynchron zu den SQL-Befehlen im Hintergrund laufen. Solange das IO-System nicht überlastet ist, sind bei den Anwendungen keine verbesserten Antwortzeiten messbar. Den größten messbaren Vorteil
Physikalisches Layout
145
erzielt man oft bei der Verwendung von Raw Devices für Redolog-Member bei Systemen mit hoher Transaktionslast, da COMMIT-Befehle synchron mit IOs des LGWRProzesses laufen.
3.9.4 Automatic Storage Management (ASM) Mit Oracle 10g führt Oracle ein eigenes Filesystem (ASM, Automatic Storage Management) ein, das unabhängig vom Betriebssystem (z.Z. Unix und MS-Windows) die optimale Implementierung für den Betrieb von Oracle-Datenbanken darstellen soll. Neben der Möglichkeit der Mehrfachspiegelung werden die Filesysteme über alle verfügbaren Devices gestriped und entsprechen damit der von Oracle seit längerem vertretenen These S.A.M.E (Stripe and Mirror Everything). Ein paar Worte zur Historie: Oracle hat sich im Umfeld Oracle Parallel Server und Real Application Clusters in der Vergangenheit schwer getan, die Storages zu verwalten. Zunächst wurden nur Raw Devices unterstützt, was dazu führte, dass nur mit fest vorgegebenen Dateigrößen gearbeitet werden konnte. Mit Version 8i wurde dann auf einigen Plattformen (z.B. AIX) das von den Betriebssytemherstellern entwickelte Global File System unterstützt. Leider war hier das Problem »auf einigen Plattformen«. Mit Version 9i hat Oracle dann das Oracle Cluster File System (OCFS), also eine eigene Implementierung des Global File Systems eingeführt. Dieses ist betriebssystemunabhängig und kann als separates Produkt eingesetzt werden, die Verzeichnisse sind aber z.B. unter MS-Windows als normale Dateisysteme zu erkennen, und somit besteht die Gefahr – wie wir sie schon erlebt haben – , dass diese Verzeichnisse durch Unachtsamkeit zerstört und damit die Datenbank korrumpiert wird. Außerdem steht OCFS nur für den Betrieb von Real Application Clusters zur Verfügung. Mit Version 10g wird jetzt mit ASM ein unabhängiges Produkt geschaffen, das für alle Oracle-Datenbanken zur Verfügung steht und für das Betriebssystem unsichtbar ist. Funktionalität ASM besteht aus einer eigenen Instanz, in der die Disk-Devices verwaltet werden. Eine Oracle-Datenbank nimmt über den ebenfalls in Oracle 10g neu eingeführten Oracle Cluster Synchronization Service (OCSS) eine Verbindung zur ASM-Instanz auf und erhält über diesen die entsprechenden Ressourcen, die vorher eingerichtet worden sind. Intern werden diese Ressourcen wie bei einem normalen Filesystem in Verzeichnissen verwaltet. Dabei werden die Devices speziell formatiert und stehen somit dem Betriebssystem nicht mehr zur Verfügung. Die Gefahr einer unbedachten Formatierung ist dadurch minimiert. Da es sich hierbei um eine interne Kommunikation handelt, muss unter MS-Windows der Parameter SQLNET.AUTHENTICATION_ SERVICES= (NTS) in der Datei sqlnet.ora gesetzt sein. Das Zusammenspiel von Datenbank- und ASM-Instanz über den OCSS-Daemon hat den Nachteil, wenn die ASM-Instanz oder der OCSSD Prozess abstürzt, werden die beteiligten Datenbanken ebenfalls beendet. Die ASM-Instanz wird standardmäßig über die ORACLE_SID »+ASM« angegeben. Folgende Parameter sind dabei notwendig:
146
Datenbank-Architektur
instance_type
='ASM'
asm_diskgroups
='ORA_ASM'
Nähere Informationen zu den Instanzparametern erhalten Sie im Kapitel 4.4. Aufbauen einer Oracle-Datenbank mit ASM Um eine ASM-Instanz aufzubauen, werden unformatierte Devices benötigt. Wenn ein Unix- bzw. Linux-Betriebssystem verwendet wird, reicht es, wenn die Devices dem Oracle-Benutzer und der Gruppe gehören. Außerdem darf hier der erste Block der physikalischen Platte nicht genutzt werden. Zum Löschen der ASM-Informationen müssen die ersten Blöcke jeder Partition überschrieben werden, dies geschieht z.B. mit dem Befehl: dd if=/dev/zero of=/dev/rdsk/c3t0d0s4 bs=8192 count=100 Listing 3.12: Löschen der ASM-Informationen unter Unix
Unter Windows müssen die Partitionen vorhanden, dürfen jedoch nicht mit Betriebssystemmitteln formatiert worden sein. Bevor sie als Diskgruppen benutzt werden können, müssen sie mit dem Werkzeug asmtool (Kommandozeile) oder asmtoolg (grafische Oberfläche) vorformatiert (stamp) werden. Diese Partitionen stehen jetzt für das Betriebssystem nicht mehr zur Verfügung. Um sie wieder »normal« nutzbar zu machen, müssen Sie wiederum das ASM-Tool aufrufen und die Stempel löschen. Das folgende Bild zeigt das Tools asmtoolg mit der Anzeige der möglichen Partitionen und deren Größe.
Abbildung 3.7: asmtoolg
Sobald die Partitionen für ASM genutzt werden, haben sie zusätzlich einen ASM Link Name, der sich aus »ORCLDISK«, dem Präfix und einer eindeutigen Nummer zusammensetzt.
Physikalisches Layout
147
Abbildung 3.8: ASM Link Name
Bei der Verwendung des Database Configuration Assistants (DBCA) für die Erstellung einer Datenbank können Sie Automatic Storage Management als Speicheroption auswählen.
Abbildung 3.9: ASM-Installation über DBCA
Sollte es hier noch keine entsprechende ASM-Instanz geben, wird diese jetzt automatisch angelegt und hochgefahren, dafür können Sie in einem weiteren Schritt das SYS-Passwort und die Serverparameter angeben. Als Nächstes können dann die Diskgruppen angelegt bzw. verwaltet werden.
148
Datenbank-Architektur
Abbildung 3.10: Erstellen einer Diskgruppe
Folgende Parameter müssen angegeben werden: Name der Diskgruppe (hier ora_asm) Redundanz, hier sind folgende Optionen möglich: – Hoch: dreifache Spiegelung – Normal: einfache Spiegelung – Extern: keine Spiegelung Die möglichen Devices (Kandidaten). Dabei sollt ein Vielfaches der gewählten Redundanz an Devices zur Verfügung stehen, da ASM sonnst auf der gleichen Platte spiegelt (es ist theoretisch möglich, eine dreifache Spiegelung mit nur einer Diskgruppe durchzuführen). Eine Größe für Striping kann an dieser Stelle nicht angegeben werden, es gibt für die Verwendung von ASM nur zwei Größen: FINE mit 128 KB und COARSE mit 1 MB. Wenn an dieser Stelle die Devices nicht angezeigt werden, kann das unterschiedliche Gründe haben, einige davon sind: Unter MS-Windows wurden die Devices nicht mit dem asmtool vorformatiert. Unter Unix stimmen die Berechtigungen (Oracle-Benutzer und -Gruppe) nicht. Der Pfad, unter dem die Devices gesucht werden sollen (Serverparameter asm_disk_string), ist gesetzt, zeigt aber auf einen anderen Bereich).
Physikalisches Layout
149
Sind alle Eingaben korrekt, wird als Nächstes die Diskgruppe angelegt, und im DBCA werden die verfügbaren Diskgruppen angezeigt.
Abbildung 3.11: Konfigurierte Diskgruppe
Unschönerweise sind die Größen (Größe und Frei) nicht entsprechend der Redundanz, sondern als Summe der verfügbaren Devices angegeben; in diesem Fall also ca. 70 GB anstelle der tatsächlich zur Verfügung stehenden 35 GB. Als Speicherort für die Datendateien werden jetzt Oracle Managed Files mit dem Namen der ASM-Instanz angeboten (+ORA_ASM). Die weitere Vorgehensweise für die Konfiguration der Datenbank entspricht der für Oracle Managed Files. ASM-Layout Bei einer Standardinstallation werden alle Komponenten der Datenbank im ASMFilesystem abgelegt. Dazu gehören: Datendateien Kontrolldateien Online-Redolog-Dateien Temporäre Dateien Parameterdateien Flashback-Logs Backup-Sets Archivierte Redolog-Dateien
150
Datenbank-Architektur
Diese werden in den zugehörigen Unterverzeichnissen, die automatisch angelegt werden, abgespeichert. Die gesamte Speicherung erfolgt als Oracle Managed Files (OMF), kann aber zusätzlich mit eigenen Namen und Verzeichnissen erweitert werden. Wenn keine speziellen Einstellungen über Templates vorgenommen werden, sind die Kontroll- und Online-Redolog-Dateien mit 128 KB Stripegröße (Fine) eingestellt, alle anderen Bereiche mit 1 MB (Coarse). Eine fertige mit ASM-verwaltete Datenbank sieht also z.B. wie folgt aus: SQL> SELECT tablespace_name, file_name, bytes/1024/1024 MByte FROM dba_data_files; TABLESPACE_NAME FILE_NAME MB ---------------- ---------------------------------------- ------SYSTEM +ORAASM1/sunasm/datafile/system.264.1 300 UNDOTBS1 +ORAASM1/sunasm/datafile/undotbs1.265.1 500 SYSAUX +ORAASM1/sunasm/datafile/sysaux.266.1 230 USERS +ORAASM1/sunasm/datafile/users.268.1 5 DEMO +ORAASM1/sunasm/datafile/demo.270.1 1000 SQL> SELECT name FROM v$controlfile; NAME --------------------------------------------+ORAASM1/sunasm/controlfile/current.256.1 +ORAASM1/sunasm/controlfile/current.257.1 Listing 3.13: Mit ASM verwaltete Datenbank
Diese Information kommt wie üblich aus der Datenbank (in diesem Beispiel heißt diese SUNASM. Um die gleichen Daten auch in der ASM-Instanz darstellen zu können, bedarf es eines etwas umfangreicheren SQL-Befehls: SELECT '+'||dg.name||'/'||sid.name||'/'||typ.name||'/'||datei.name Filename, round(info.bytes/1024/1024) MByte FROM v$asm_diskgroup dg, v$asm_alias sid, v$asm_alias typ, v$asm_alias datei, v$asm_file info WHERE sid.group_number = dg.group_number AND typ.group_number = dg.group_number AND datei.group_number = dg.group_number AND sid.reference_index = typ.parent_index AND typ.reference_index = datei.parent_index AND datei.file_number = info.file_number;
Physikalisches Layout
151
FILENAME MBYTE ----------------------------------------------------------- ----+ORA_ASM1/SUNASM/CONTROLFILE/Current.256.565036357 2 +ORA_ASM1/SUNASM/ONLINELOG/group_1.258.565036359 20 +ORA_ASM1/SUNASM/ONLINELOG/group_2.259.565036359 20 +ORA_ASM1/SUNASM/ONLINELOG/group_3.260.565036361 20 +ORA_ASM1/SUNASM/ONLINELOG/group_4.261.565036363 20 +ORA_ASM1/SUNASM/DATAFILE/SYSTEM.262.565036365 210 +ORA_ASM1/SUNASM/DATAFILE/INDX.268.565036827 100 +ORA_ASM1/SUNASM/DATAFILE/UTILS.267.565036827 10 +ORA_ASM1/SUNASM/DATAFILE/TSUNDO.263.565036381 100 +ORA_ASM1/SUNASM/DATAFILE/SYSAUX.264.565036385 200 +ORA_ASM1/SUNASM/DATAFILE/DATA.266.565036397 100 +ORA_ASM1/SUNASM/TEMPFILE/TEMP.265.565036397 50 +ORA_ASM/SUNASM/PARAMETERFILE/spfile.269.565036399 0 +ORA_ASM/SUNASM/FLASHBACK/log_1.270.565036406 8 +ORA_ASM/ARCHIVELOG/2004_06_23/thread_1_seq_50.271.565036415 9 +ORA_ASM/ARCHIVELOG/2004_06_23/thread_1_seq_51.272.565036416 0 Listing 3.14: Datenbankdateien aus ASM-Sicht
Manuelle ASM-Konfiguration Natürlich kann eine ASM-Instanz auch manuell aufgesetzt werden. Dafür muss zunächst, ähnlich wie beim Anlegen einer Datenbank, eine leere Instanz hochgefahren und anschließend müssen die Diskgruppen erzeugt werden. Als Beispiel wird folgende Initialisierungsdatei mit dem Namen init+ASM.ora im $ORACLE_HOME/dbs Verzeichnis erstellt. *.instance_type ='ASM' *.asm_diskgroups ='ORA_ASM' *.background_dump_dest ='/oracle/admin/+ASM/bdump' *.core_dump_dest ='/oracle/admin/+ASM/cdump' *.large_pool_size =12M *.remote_login_passwordfile ='EXCLUSIVE' *.user_dump_dest = '/oracle/admin/+ASM/udump' Listing 3.15: Initialisierungsdatei der ASM-Instanz
Als Nächstes wird die Datenbank gestartet: % set ORACLE_SID=+ASM % sqlplus / as sysdba SQL> startup Listing 3.16: Starten der ASM-Instanz
Jetzt können die Diskgruppen mit dem Befehl CREATE DISKGROUP angelegt werden. SQL> CREATE DISKGROUP ora_asm NORMAL DISK '\\.\ORCLDISKDATA1', '\\.\ORCLDISKDATA2'; Listing 3.17: Anlegen einer Diskgruppe
152
Datenbank-Architektur
Neben dem Befehl CREATE DISKGROUP gibt es nur noch die Befehle ALTER DISKGROUP und DROP DISKGROUP; insofern eine überschaubare Anzahl von Befehlen für die Verwaltung von ASM-Instanzen. Dennoch ist die Verwendung des DBCA der manuellen Erstellung vorzuziehen, da dort alle verfügbaren Devices mit der entsprechenden Größe automatisch angezeigt werden. Verwalten von Tablespaces bzw. Datendateien über ASM Die Verwaltung von Tablespaces über ASM entspricht der von Oracle Managed Files. Das bedeutet, Sie geben in der Regel keinen Dateinamen an, wenn Sie den Tablespace anlegen. Beim Löschen desselben werden dann die zugehörigen Datendateien automatisch gelöscht. SQL> CREATE TABLESPACE blub DATAFILE SIZE 100M; Listing 3.18: Anlegen eines Tablespaces SQL>DROP TABLESPACE blub; Listing 3.19: Löschen des Tablespaces
Wenn Sie jedoch explizit einen Namen für die Datendatei angeben, werden in der ASM-Instanz zwei Einträge generiert, der eine mit der ASM-eigenen Namensgebung und ein zweiter Eintrag (wie ein Link) mit Ihrem gewählten Namen. Beim Löschen des Tablespaces müssen Sie nachfolgend beide Einträge für die Datendateien mit dem Befehl ALTER DISKGROUP separat löschen. Das folgende Beispiel verdeutlicht dies: SQL> CREATE TABLESPACE blub DATAFILE '+ORA_ASM/SUNASM/DATAFILE/blub01.dbf' SIZE 100M; SQL> DROP TABLESPACE blub; SQL> ALTER DISKGROUP ora_asm DROP FILE '+ORA_ASM/SUNASM/DATAFILE/blub01.dbf'; SQL> ALTER DISKGROUP ora_asm DROP FILE '+ORA_ASM/SUNASM/DATAFILE/blub01.dbf' SQL> ALTER DISKGROUP ora_asm DROP FILE '+ORA_ASM/SUNASM/DATAFILE/BLUB.288.565038087' Listing 3.20: Manuelles Anlegen und Löschen eines Tablespaces
Über den Bereich ADMINISTRATION und SPEICHERUNG kann im Enterprise Manager der Menüpunkt PLATTENGRUPPEN ausgewählt werden, mit dem man sich an einer ASM-Instanz anmelden kann. Hier kann man sich dann z.B. die Konfiguration und Platzbelegung sowie Performance-Informationen ansehen.
Ältere Funktionen
153
Abbildung 3.12: ASM-Darstellung im Oracle Enterprise Manager
Allerdings sollten Sie auch hier bei der Angabe der Größen bedenken, dass die Redundanz nicht berücksichtigt ist, der maximal verfügbare Platz also im obigen Fall nicht 20 GB, sondern nur 10 GB beträgt.
3.10
Ältere Funktionen
3.10.1 Dictionary-Managed Tablespaces In den Datenbankversionen bis einschließlich Oracle 8.0 wurden alle Informationen zu Datenbankobjekten – insbesondere auch für die Verwaltung der Tablespaces – im Data Dictionary gespeichert. 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 Dictionarys durchführen. Die entsprechenden Änderungen in der Extent-Verwaltung erzeugen 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 der Temporär-Tablespace aus dieser Verwaltung herausgetrennt werden, wodurch sich Sortierungen und auch die generelle Verwaltung beschleunigen ließen. Mit der Version 8.1 wurde 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. Die Tablespaces des alten Typs sollten spätestens mit der Version Oracle 10g nicht mehr benutzt werden. Eine Migration bestehender DM-Tablespaces erfordert zunächst eine Abschätzung darüber, ob die Migration online, d.h. im laufenden Betrieb, durchgeführt werden muss oder ob eine hinreichend lange Auszeit möglich ist.
154
Datenbank-Architektur
Ist eine entsprechende Auszeit möglich, kann innerhalb der bestehenden Datenbank ein neuer LM-Tablespace angelegt werden, in den über Kommandos der Form ALTER TABLE … MOVE TABLESPACE newts die Tabellen dieses Tablespaces verschoben werden. Indizes können einfach in einem neuen LM-Tablespace neu aufgebaut werden; dies geht sogar im laufenden Betrieb über den Befehl ALTER INDEX … REBUILD TABLESPACE newts ONLINE. Ist keine entsprechende Auszeit möglich, kann auch mit den in Oracle und von Drittherstellern zur Verfügung stehenden Reorganisationsmethoden (z.B. dbms_redefinition) gearbeitet werden. Hierbei werden die Tabellen im laufenden Betrieb reorganisiert. Je nachdem, ob nur ein Tablespace oder die gesamte Datenbank betroffen ist, muss alternativ darüber nachgedacht werden, eine neue Datenbank aufzubauen und diese aus der aktuellen Datenbank zu füllen. Um die Zeitdauer hierbei zu minimieren, gibt es Software, wie z.B. SharePlex von der Firma Quest Software, die hierbei unterstützen kann. Das in der Datenbank enthaltene Package dbms_space_admin bietet im Rahmen der Prozedur tablespace_migrate_to_local scheinbar eine weitere einfache Möglichkeit, einen DM-Tablespace direkt in einen LM-Tablespace zu migrieren. Der Tablespace wird dabei lediglich umetikettiert, und die Extent-Bitmap wird hinzugefügt. Die Migration ist im laufenden Betrieb möglich, lediglich umfangreiche Lade-Operationen, die zur Reservierung neuer Extents führen, werden blockiert. Dennoch ist diese Variante in den meisten Fällen nicht praxistauglich, da sie nur eine Umwandlung in einen LM-Tablespace mit einheitlicher Extent-Größe (UNIFORM SIZE) zulässt, wobei als Extent-Größe der größte gemeinsame Teiler aller im DM-Tablespace vorhandenen Extent-Größen genommen wird. Dies liegt meistens sehr nahe an der Oracle-Blockgröße und ist somit viel zu klein. Nur für den Fall, dass der DM-Tablespace mit einer MINIMUM SIZE-Storage-Option konfiguriert war, kann die Migration zu einem guten Ergebnis kommen.
3.10.2 Rollback-Segmente Bis Oracle8i musste die Undo-Verwaltung auf manuellem Wege durchgeführt werden. Bei Erstellung der Datenbank oder unmittelbar danach wurde eine Anzahl Rollback-Segmente erzeugt. Diese manuell erzeugten Rollback-Segmente sind von den automatisch erzeugten Undo-Segmenten (siehe Kapitel 3.3.5) zu unterscheiden. Die manuelle Erstellung geschieht durch Kommandos der Form: SQL> CREATE ROLLBACK SEGMENT r01 TABLESPACE rbs;
Der Tablespace rbs ist dabei ein ganz normaler Tablespace. Wesentliche Nachteile dieser Art der Undo-Verwaltung sind: Das Anlegen, die Bestimmung einer geeigneten Größe sowie das Löschen von Rollback-Segmenten muss manuell durch den DBA geschehen Insbesondere muss ein geeigneter Wert für den so genannten OPTIMAL-Parameter gefunden werden.
Ältere Funktionen
155
Um Fehlermeldungen der Art ORA-01555 (Snapshot too old) möglichst zu unterdrücken, müssen Anzahl, Größe und OPTIMAL-Parameter der Rollback-Segmente sorgfältig austariert werden. Eine Transaktion kann sich nicht über mehrere Rollback-Segmente erstrecken. Für sehr umfangreiche Transaktionen im Rahmen von Batch-Verarbeitungen muss ein dediziertes Rollback-Segment angelegt und in den Skripten kodiert werden. Die ab Oracle9i eingeführten Flashback-Funktionen sind mit Rollback-Segmenten nicht nutzbar. Es ist daher sehr zu empfehlen, ab Oracle9i die automatische Undo-Verwaltung zu benutzen. Die Migration von manueller zu automatischer Undo-Verwaltung ist relativ einfach. Eine kurze Auszeit wird benötigt, da die Datenbank einmal durchgestartet werden muss. Folgendes Verfahren kann dafür genutzt werden (dabei wird davon ausgegangen, dass eine Serverparameterdatei benutzt wird; andernfalls müssen die Serverparameter durch Editieren der Parameterdatei geändert werden): Zunächst sollte ein Undo-Tablespace angelegt werden, z.B.: SQL> CREATE UNDO TABLESPACE undotbs DATAFILE '…' SIZE 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 5000M;
Für den nächsten Neustart der Instanz wird die automatische Undo-Verwaltung eingestellt. Der Parameter undo_retention gibt die Zeit in Sekunden an, für die Undo-Informationen aufbewahrt werden sollen, um Lesekonsistenz für Abfragen zu gewährleisten. Der Parameter undo_tablespace enthält den Namen des soeben erstellten Tablespaces. Mit undo_management wird jetzt auf die automatische Undo-Verwaltung umgeschaltet. SQL> SQL> SQL> SQL> SQL>
ALTER SYSTEM SET ALTER SYSTEM SET ALTER SYSTEM SET -- den folgenden ALTER SYSTEM SET
undo_management=AUTO SCOPE=SPFILE; undo_tablespace=undotbs SCOPE=SPFILE; undo_retention=1800 SCOPE=SPFILE; Befehl nur unter Oracle9i undo_suppress_errors=TRUE SCOPE=SPFILE;
Nach dem nächsten Neustart der Instanz arbeitet die Datenbank mit automatischer Undo-Verwaltung. Der ursprüngliche Rollback Tablespace kann jetzt gelöscht werden. Außerdem sollten Sie jetzt auf jeden Fall ein Backup Ihrer Datenbank und der Parameterdatei durchführen.
Instanz-Verwaltung Die zentralen Befehle für die Instanz-Verwaltung 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 den Wechsel des Red-Log zu initiieren, steht das ALTER-SYSTEM-Kommando zur Verfügung. Bestimmte Teilbereiche der Instanz können im laufenden Betrieb manuell oder auch automatisch neu skaliert werden, um auf unterschiedliche Lastprofilen im Tagesverlauf abzustellen. Diese Technik wird ebenfalls vorgestellt. Abschließend werden noch Checkpoints behandelt.
4.1
Werkzeuge und Voraussetzungen
Das bekannteste Werkzeug zur Administration eines Oracle-Systems ist wohl SQL*Plus. Der früher ebenfalls verwendete Server-Manager wird bereits seit der Version Oracle9i nicht mehr mit ausgeliefert und wird daher an dieser Stelle nicht behandelt. 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 Skripten wird auch noch CONNECT INTERNAL zu finden sein, was nur noch aus Kompatibilitätsgründen unterstützt wird, aber bereits seit Oracle9i nicht mehr verwendet werden kann. Um ein CONNECT / AS SYSDBA ausführen zu können, muss der Betriebssystembenutzer über das Betriebssystem privilegiert worden 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 den Kapiteln 3 und 9 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 Skripte, die den Server-Manager aufrufen, auf die Benutzung von SQL*Plus umgestellt werden.
158
Instanz-Verwaltung
Daneben gibt es für die Remote-Administration von Instanzen und Datenbanken den Enterprise Manager, der in einem eigenen Kapitel behandelt wird, und Werkzeuge von Fremdherstellern, welche 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.
4.1.1 Startup Ein Oracle-System wird grundsätzlich in drei Phasen gestartet. Die Phasen werden als NOMOUNT, MOUNT und OPEN bezeichnet. Im Folgenden wird hierzu das startup-Kommando vorgestellt, Wie bereits erwähnt, ist eine privilegierte Anmeldung an das Oracle-System mit connect / as sysdba Voraussetzung. Syntax: STARTUP[FORCE][RESTRICT][PFILE=filename] [OPEN [READ ONLY | READ WRITE]] | [MOUNT] | [NOMOUNT]
NOMOUNT In der ersten Phase, der NOMOUNT-Phase, wird die Instanz gestartet. Das bedeutet, dass in dieser Phase die SGA als Hauptspeicherstruktur angelegt 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 4.2 wird näher darauf eingegangen. Oracle versucht permanent, so viele Parameter wie möglich dynamisch änderbar zu implementieren. Beispielsweise können ab Oracle9i die Bereiche der SGA dynamisch verändert werden, wobei die Vergrößerung eines Bereichs zu Lasten eines anderen fällt. Auch darauf wird im Folgenden genauer eingegangen. In der NOMOUNT-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 sind 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 Kontrolldateien sind geöffnet. Damit sind sämtliche Verweise auf die Redo-Log-Dateien und die Datendateien mit den dazugehörigen Konsistenzinformationen bekannt.
Werkzeuge und Voraussetzungen
159
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 kompletten 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. In diesem Fall werden also automatisch alle drei Phasen durchlaufen. In der OPEN-Phase werden die Redo-Log-Dateien und die Datendateien, die in den Kontrolldateien verzeichnet sind, geöffnet, die Konsistenzinformationen 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 Recoverys, 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 Redo-LogDateien 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 10 (Wiederherstellungstechniken) eingehend behandelt. OPEN READ ONLY Der Parameter OPEN mit dem Zusatz READ ONLY öffnet die Datenbank im Read-onlyModus, d.h., es ist ausschließlich lesender Zugriff erlaubt. Auch das Anlegen oder Ändern von Datenbank-Objekten, z.B. Benutzern, ist nicht möglich, da dies Änderungen in Data-Dictionary-Tabellen implizieren würde. 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 Zusatz FORCE fasst die Einzelbefehle SHUTDOWN ABORT (s. nächster Abschnitt) und das jeweilige STARTUP zusammen. Dieser Befehl findet typischerweise seine Anwendung, wenn ein Oracle-System nach einem Systemabsturz, aus welchen Gründen auch immer, wieder gestartet werden soll, aber noch Fragmente der abgestürzten Instanz vorhanden sind und das Starten verhindern.
160
Instanz-Verwaltung
4.1.2 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 der Speicherbereich 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 (siehe Abschnitt 4.2.1) initialisiert, damit alle modifizierten Datenbankblöcke durch den Database-Writer-Prozess in die Datendateien geschrieben werden. Danach wird die Datenbank, d.h. die Daten- und Redo-Log-Dateien, 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 Skript abgemeldet und die Agenten gestoppt werden, oder man verwendet eine der beiden folgenden Optionen. 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 die 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.
Werkzeuge und Voraussetzungen
161
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 besteht jedoch die Gefahr, 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 nachfolgenden STARTUP ein Instance Recovery durchgeführt werden muss. Eine solche Datenbank sollte man nicht als Grundlage einer Offline-Sicherung verwenden. Dieses Kommando ist vielmehr 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 heruntergefahren. Auf Unix-Systemen kann in solchen Fällen unter dem Verzeichnis $ORACLE_HOME/dbs noch eine Datei namens lk<sid> zu finden sein, die als Sperrdatei für die Hintergrundprozesse der betreffenden Instanz dient. Beim versuchten Neustart wird dann die Meldung ausgegeben, dass die Instanz bereits gestartet ist, ein SHUTDOWN bringt wiederum die Meldung, dass die Instanz nicht gestartet ist. Ein solcher Zustand wird mit SHUTDOWN ABORT beseitigt. SHUTDOWN ABORT wird implizit auch durch das Kommando STARTUP FORCE durchge-
führt.
4.1.3 Alter Database Einige Einstellungen von Instanz und Datenbank lassen sich nicht im STARTUPKommando spezifizieren, sondern nur über das ALTER DATABASE-Kommando. 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 my.global.name geändert werden. Per Default ergibt sich der globale Datenbankname aus den beiden Initialisierungsparametern ..
162
Instanz-Verwaltung
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 derjenigen 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 Das Character Set und das 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 Obermenge 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. Eine Auflistung aller möglichen Konvertierungen findet sich in der Dokumentation Oracle 10g Globalization Support Guide.
4.1.4 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 Oracle 10g SQL Reference verwiesen. 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 betreffende 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.
Werkzeuge und Voraussetzungen
163
Beispiel: SQL> SELECT username,sid,serial# FROM v$session WHERE username='SCHWANKE'; USERNAME SID SERIAL# ------------------------------ ---------- ---------SCHWANKE 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 ------------------------------ ---------- -------SCHWANKE 13 KILLED Listing 4.1: 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 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.
Dies kann benutzt werden, um bei einer starken Fragmentierung des Shared Pools einige Bereiche freizugeben. Speicher für Objekte, die gerade benutzt oder ausgeführt werden, sowie so genannte »fixierte Objekte« (mittels DBMS_SHARED_POOL.KEEP) wird allerdings nicht freigegeben. Auch findet keinerlei Defragmentierung des Shared Pools statt. Außerdem ist zu beachten, viele SQL-Kommandos nun erneut »geparst« werden müssen, was insbesondere bei komplexen Statements zu deutlichen Performance-Reduktionen unmittelbar nach dem Aufräumvorgang führt. FLUSH BUFFER_CACHE Leert den Buffer-Cache der SGA. Dies ist für Entwicklung- und Testumgebungen gedacht, um Performance-Messungen einzelner Statements besser vergleichen zu können. Da im Rahmen von Autotracing (siehe Kapitel 11) jedoch ohnehin die Gesamtzahl gelesener Blöcke (unabhängig von Caching-Effekten) geliefert wird und in einer produktiven Umgebung letztlich die Performance mit Cache entscheidet, ist die Bedeutung dieses Kommandos eher gering.
164
Instanz-Verwaltung
SWITCH LOGFILE Im normalen Betrieb wird der Wechsel der Redo-Log-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 Redo-Log-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, Redo-Log-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 (s.u.).
4.2
Parametrierung
Eine Oracle-Instanz lässt sich in der Version 10g mit über 250 Parametern einstellen. Diese Parameter werden, wie vorher schon beschrieben, immer beim STARTUP in der NOMOUNT-Phase ausgelesen. Es gibt zwei Möglichkeiten, diese Parameter zu spezifizieren: In einer Serverparameterdatei (SPFile). Diese muss im Dateisystem des Servers liegen. Der SPFile hat den Namen SPFILE<sid>.ora und befindet sich auf UnixSystemen unter $ORACLE_HOME/dbs, auf MS-Windows unter %ORACLE_HOME%\database. Vorteilhaft ist bei dieser Variante, dass die Initialisierungsparameter an zentraler Stelle liegen und insbesondere die Datenbank problemlos von einem entfernten Client aus gestartet werden kann. In einer herkömmlichen Parameterdatei. Diese heißt standardmäßig init<sid>.ora und muss im Dateisystem des SQL*Plus-Clients liegen. Der genaue Ort sowie Dateiname kann über die PFILE-Klausel des STARTUP-Kommandos mitgegeben werden, standardmäßig wird auch hier im Verzeichnis $ORACLE_HOME/ dbs bei Unix-Systemen bzw. %ORACLE_HOME%\database auf MS-Windows gesucht. Ein typisches Problem hierbei ist, dass sich die Datenbank zwar von jedem Client aus herunterfahren lässt, das Starten aber eine dezentrale Parameterdatei (beim Client) erfordert. Die wichtigsten Parameter, die nachträglich nicht oder nur schwer änderbar sind, wurden bereits 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)
Tabelle 4.1: Die virtuelle Tabelle V$PARAMETER
Parametrierung
165
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 Änderungen über ALTER SESSION an.
isadjusted
TRUE oder FALSE zeigt an, ob der Parameter automatisch vom Datenbanksystem auf einen gültigen Wert korrigiert wurde.
isdeprecated
Zeigt an, ob der Parameter veraltet ist. Solche Parameter sind nur aus Kompatibilitätsgründen noch vorhanden und sollten, wenn möglich, nicht benutzt werden.
description
Beschreibung des Parameters
SYS_MODIFIED zeigt Änderung über ALTER SYSTEM an.
Tabelle 4.1: Die virtuelle Tabelle V$PARAMETER (Forts.)
Die Initialisierungsdatei wird, wie vorher schon beschrieben, immer beim STARTUP in der NOMOUNT-Phase ausgelesen. Dies führte in älteren Oracle-Versionen dazu, dass Parameteränderungen nur nach dem Neustart der Instanz erkannt wurden. Mit neueren Oracle-Versionen werden jedoch 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 Oracle 10g Database Reference zu finden. Zu jedem Parameter ist dort zu finden, ob er 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, wird der Befehl ALTER SYSTEM SET parameter=wert;
verwendet. Wichtig ist hierbei, dass solche Anpassungen im laufenden Betrieb bei Verwendung einer Parameterdatei nicht in diese übertragen werden und somit nach einem erneuten Start der Datenbank verloren sind, sofern sie nicht manuell nachgetragen werden. Bei Verwendung eines SPFiles hingegen erfolgt automatisch eine Synchronisation zwischen laufendem System und SPFile. Ist dies unerwünscht oder – wie im Falle statischer Parameter – nicht möglich, kann der Wirkungsbereich auf das laufende System oder das SPFile alleine beschränkt werden: ALTER SYSTEM SET parameter=wert [SCOPE=MEMORY|SPFILE|BOTH];
166
Instanz-Verwaltung
4.2.1 Checkpoints Ein Checkpoint ist ein notwendiger Mechanismus, um die Konsistenz der Datenbank zu garantieren. Bedingt wird dieses durch die asynchrone Arbeitsweise des Database-Writer-Prozesses, der in der SGA modifizierte Blöcke nicht sofort auf die Platte zurückschreibt. Zwar wird dieses Problem durch den Log Writer und die Redo-Log-Dateien gelöst, jedoch werden die im Falle eines Absturzes der OracleInstanz benötigten Informationen in den Redo-Log-Dateien zyklisch wieder überschrieben. In diesem Fall ist es unverzichtbar, diejenigen Blöcke aus der SGA auf die Platte zurückzuschreiben, die aufgrund 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. 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 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-BufferCache der SGA auf die Festplatten zurückzuschreiben. Die Dauer eines Checkpoints ist also von der Größe des Database-Buffer-Caches in Verbindung mit der Transaktionsaktivität abhängig. Ein Checkpoint, der durch den Wechsel einer Redo-Log-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.
Parametrierung
167
Problematisch werden kann das Schreiben von Checkpoints während Zeiten hoher Transaktionslast. Wenn durch mehrfaches Umschalten der Redo-Log-Gruppe wieder auf eine Redo-Log-Gruppe umgeschaltet werden soll, deren Checkpoint noch nicht beendet ist, kommt es zu einem datenbankweiten Wartezustand, bis der Checkpoint geschrieben ist. Genau diese Situation gilt es zu vermeiden. Man findet eine Protokollierung dieser Wartezustände in der Alert-Datei der Instanz mit der Meldung checkpoint not complete. Zur Vermeidung der Wartezustände gibt es drei Möglichkeiten: Eine Vergrößerung der Redo-Log-Dateien führt zu einer Reduktion der Anzahl der Checkpoints. Durch das Anlegen zusätzlicher Redo-Log-Gruppen können mehr Checkpoints parallel laufen. Anders formuliert: Es dauert länger, bis wieder auf eine bestimmte Redo-Log-Gruppe umgeschaltet wird. Durch Setzen des Initialisierungsparameters log_checkpoint_interval auf einen von 0 verschiedenen Wert wird bereits vor dem eigentlichen Log-Switch mit dem Schreiben des Checkpoints begonnen (inkrementeller Checkpoint), beim Log-Switch müssen dann maximal so viele Betriebssystemblöcke geschrieben werden wie durch den Parameter gesetzt. Der gesetzte Wert sollte also kleiner sein als die Größe der Redo-Log-Dateien in Betriebssystemblöcken. Ähnliche Effekte lassen sich über die Parameter log_checkpoint_timeout und fast_start_mttr_target erreichen.
4.2.2 Dynamische SGA Bis auf den Log-Buffer sind alle Komponenten der SGA (Buffer-Cache, Shared Pool, Large Pool etc.) dynamisch, d.h., ihre Größe kann im laufenden Betrieb angepasst werden. Dies geschieht einfach durch ein entsprechendes ALTER SYSTEM-Kommando, z.B. SQL> ALTER SYSTEM SET db_cache_size=500M;
Voraussetzung hierfür ist natürlich, dass überhaupt genügend Speicherplatz verfügbar ist. Eine harte Obergrenze für die Gesamtgröße der SGA ist durch den Parameter SGA_MAX_SIZE gegeben. Wenn nicht von vornherein alle SGA-Komponenten entsprechend den physikalischen Limits (Hauptspeichermenge) des Servers dimensioniert sind, sollte dieser Parameter explizit gesetzt werden, da er ansonsten implizit einfach auf die Gesamtgröße aller Komponenten beim Instanzstart gesetzt wird und eine nachträgliche Erhöhung im laufenden Betrieb nicht möglich ist. Die kleinste Speichereinheit, die zwischen den SGA-Komponenten bewegt werden kann, ist eine Granule. Für SGA-Größen unter 1 GB beträgt die Granulengröße 4 MB. Die Größe kann auch direkt abgefragt werden: SQL> SELECT bytes FROM v$sgainfo WHERE name = 'Granule Size';
Mit Oracle 10g stehen zwei Modi zur Verwaltung der SGA zur Verfügung.
168
Instanz-Verwaltung
Manuelle SGA-Verwaltung In der Standardeinstellung befindet sich Oracle 10g in diesem Modus. Die manuelle Verwaltung wird durch Setzen des Initialisierungsparameters SGA_TARGET auf 0 ausgewählt. Im manuellen Modus müssen sämtliche Operationen zur SGA-Verwaltung explizit durch den DBA vorgenommen werden. Soll eine Komponente vergrößert werden, muss ggf. eine andere Komponente zuvor verkleinert werden. Häufig auftretende Verwaltungsaufgaben können als Datenbank-Jobs über den Scheduler (siehe Kapitel 6) programmiert werden, beispielsweise: Vor dem Starten von Batch-Jobs oder Reports in Data-Warehouse-Umgebungen ist es meistens günstig, den Buffer-Cache möglichst großzügig zu dimensionieren. Vor dem Beginn eines Backups mittels RMAN sollte der Large Pool entsprechend dimensioniert werden. Nach einer typischen Laufzeit für diese Tasks plus Zeitreserve muss außerdem der Zustand für den produktiven Betrieb wiederhergestellt werden. Automatische SGA-Verwaltung Der Parameter SGA_TARGET kann jederzeit auf einen von 0 verschiedenen Wert gesetzt werden (Anzahl Bytes, evtl. mit Suffix K, M, G). Dadurch wird die automatische SGAVerwaltung aktiviert. Dieser Modus bietet zum einen den Vorteil, dass vor einer Vergrößerung einer Komponente ggf. automatisch andere Komponenten verkleinert werden. Zum anderen werden bestimmte Operationen vollautomatisch durchgeführt. Voraussetzung für diesen Modus ist, dass der Parameter STATISTICS_LEVEL auf TYPICAL (Default) oder ALL gesetzt ist. Durch SGA_TARGET wird die Gesamtgröße der Instanz angegeben. In der Praxis sollte dieser Wert mit dem Wert von SGA_MAX_SIZE identisch sein. Die herkömmlichen Parameter DB_CACHE_SIZE, SHARED_POOL_SIZE etc. können, aber müssen nicht verwendet werden (zur Bedeutung dieser Parameter bei automatischer SGA-Verwaltung siehe unten). Im Gegensatz zu älteren Oracle-Versionen umfasst der durch SGA_TARGET gegebene Wert die Gesamtgröße der Instanz inklusive »fixed SGA«. Dadurch ist eine exakte Kontrolle über die endgültige Größe der SGA gegeben. Einige Komponenten können in diesem Modus automatisch vom System angepasst werden, nämlich der Buffer-Cache (nur der Default-Buffer-Cache) sowie Shared Pool, Java Pool und Large Pool. Nicht angepasst werden demnach der Keep und Recycle Pool sowie alle Buffer Pools, die nicht der Standardblockgröße entsprechen. Für die automatische Anpassung werden u.a. so genannte Advisories genutzt, konkret sind dies die Performance-Views V$DB_CACHE_ADVICE, V$SHARED_POOL_ADVICE und V$JAVA_POOL_ADVICE. Diese geben für alternative Größen der entsprechenden Komponente (zwischen 10% und 200% der aktuellen Größe) an, welche Performance-
Parametrierung
169
Auswirkungen eine entsprechende Dimensionierung der betreffenden Komponente auf das System hätte, z.B. die Trefferrate im Buffer-Cache für einen doppelt so großen Buffer-Cache. Das Verfahren, nach dem die automatische Anpassung läuft, ist nicht im Einzelnen dokumentiert. Für das Release 10.1.0 kann jedoch Folgendes festgehalten werden: Lediglich Default-Buffer-Cache, Shared Pool, Java Pool und Large Pool werden von der automatischen Anpassung berücksichtigt. Das macht das Verfahren vor allem für kleinere Systeme mit einer SGA-Größe von wenigen hundert MB interessant, da bei großen System praktisch keine Konkurrenz zwischen Shared Pool und Java Pool einerseits sowie Buffer-Cache andererseits besteht. Eine Vergrößerung des Shared Pools bzw. des Java Pools zulasten des Buffer-Cache findet statt, wenn ein entsprechender Mehrwert durch die Advisories angezeigt wird. Diese Situation tritt vor allem dann auf, wenn Batch-Jobs und Reports beendet sind und das Tagesgeschäft wieder anläuft. Die Anpassung geschieht allerdings sehr langsam. Alle fünf Minuten werden eine oder wenige Granulen transferiert. Für ressourcenintensive Abfragen, wie sie in Batch-Jobs oder Reports vorkommen, ist dieser Mechanismus daher zu träge. Auch hier bilden lediglich Systeme mit wenig Hauptspeicher eine Ausnahme. Eine moderate Verkürzung dieses Reaktionsintervalls kann durch Setzen des versteckten Parameters _memory_broker_stat_interval auf eine Anzahl Sekunden erreicht werden (Default ist 300). Eine Vergrößerung des Buffer Cache zulasten des Shared Pools oder Java Pools ist in der Standardeinstellung nicht möglich! Dies ist darauf zurückzuführen, dass die beiden Pools häufig fragmentiert sind und daher gar nicht mehr verkleinert werden können. Eine automatische Defragmentierung der Pools ist auch nicht eingebaut, der Shared Pool kann aber zumindest manuell »aufgeräumt« werden (siehe Abschnitt 4.1.4). Auch hier ist der einzige Ausweg das Setzen eines versteckten Parameters (_memory_broker_shrink_heaps auf 1; Default ist 0). Das Fragmentierungsproblem ist damit aber dennoch nicht gelöst. Durch Setzen der herkömmlichen Parameter DB_CACHE_SIZE, SHARED_POOL_SIZE etc. werden Untergrenzen für die entsprechenden Komponenten spezifiziert. Wichtig ist, dass dadurch offenbar gleichzeitig auch Obergrenzen für die anderen Komponenten gesetzt werden. Insbesondere für den Buffer-Cache sollte dies auch genutzt werden, um eine zu starke Einengung durch die beiden Pools zu verhindern. Freigegebener Platz im Large Pool (z.B. nach Abschluss eines RMAN-Backups) wird schnellstmöglich, d.h. beim nächsten Granulen-Transfer, an den BufferCache übertragen. Abschätzungen, wie lange das Backup benötigt, um rechtzeitig wieder auf die Tagesgeschäftkonfiguration zurückzuschalten, sind also nicht mehr notwendig. Dies ist eindeutig ein Vorteil. Die Übertragung von BufferCache an den Large Pool vor Beginn des Backups läuft aber nicht automatisch, sondern muss weiterhin per Job verdrahtet werden.
170
Instanz-Verwaltung
Überwachung Alle manuellen oder automatischen Speichertransfers werden in der View V$SGA_ RESIZE_OPS festgehalten. Die aktuellen Größen stehen über die View V$SGA_ DYNAMIC_COMPONENTS bereit. SQL> SELECT component, current_size 2 FROM v$sga_dynamic_components; COMPONENT CURRENT_SIZE ------------------------------ -----------shared pool 201326592 large pool 16777216 java pool 104857600 streams pool 0 DEFAULT buffer cache 104857600 KEEP buffer cache 0 RECYCLE buffer cache 0 DEFAULT 2K buffer cache 0 DEFAULT 8K buffer cache 0 DEFAULT 16K buffer cache 104857600 DEFAULT 32K buffer cache 0 OSM Buffer Cache 0
Der Hintergrundprozess MMON ist für die automatische SGA-Verwaltung zuständig. Falls für die Instanzparametrierung ein SPFile benutzt wird, werden beim Herunterfahren der Datenbank die aktuellen Größen der SGA-Komponenten über die Parameter __DB_CACHE_SIZE, __SHARED_POOL_SIZE etc. im SPFile abgelegt. Nach einem Instance-Crash und anschließendem Wiederanstarten schließt das System daher nahtlos an das vorherige Lastprofil an.
4.3
Oracle Cluster Synchronization Service Daemon
Dieser Prozess (ocss) wird nach einer Oracle 10g-Installation automatisch installiert und gestartet. Leider schlägt der Start unter Windows auch bei der Version 10.1.0.3 fehl, da hier ein entsprechender Eintrag fehlt.
Abbildung 4.1: OCSS-Fehlermeldung
Der Fehler kann sehr einfach mit folgendem Befehl behoben werden: "clscfg -local -o %ORACLE_HOME% -l NA"
Damit kann der Prozess gestartet und benutzt werden.
ASM-Instanzen
171
Dieser Prozess ist notwendig für die Kommunikation zwischen Instanzen, also z.B. für eine Real Application Cluster-Datenbank, bei der mehrere Instanzen auf eine gemeinsame Datenbank zugreifen. Des Weiteren wird der Prozess für die Kommunikation einer Oracle-Instanz mit einer ASM-Instanz benötigt. Wenn Sie also kein ASM und kein RAC verwenden, können Sie den Prozess stoppen. Unter Unix gestaltet sich dies allerdings etwas umständlicher. Wer gehofft hat, dass man mit dem schönen Befehl kill –9 weiterkommt, wird enttäuscht, da der Prozess automatisch nachgestartet wird. Je nach Plattform finden Sie einen Eintrag in der Datei /etc/inittab oder eine Datei init.cssd im Verzeichnis /etc/rc3.d.
Mit dem Befehl /etc/init.d/init.cssd stop wird der Prozess endgültig beendet.
4.4
ASM-Instanzen
Die Verwaltung von ASM-Instanzen ist recht simpel. Neben dem wichtigsten Parameter instance_type = ASM gibt es nur noch wenige Einstellungsmöglichkeiten. Hierzu gehören: asm_diskgroups: die Liste der von dieser Instanz verwalteten ASM-Gruppen asm_diskstring: eine mögliche Einschränkung der Disks, die für die ASM-Konfiguration zur Verfügung stehen soll. Wenn dieser Parameter nicht gesetzt ist, werden alle Disks angeboten. background_dump_dest: Wie üblich, das Verzeichnis für die Logs der Hintergrundprozesse core_dump_dest: das Verzeichnis für die, hoffentlich nie auftretenden, CoreDumps user_dump_dest: Verzeichnis für Dumps von Benutzerprozessen remote_login_passwordfile: die Möglichkeit, die ASM-Instanzzugriffe über ein Kennwort zu schützen. large_pool_size: die Größe des Caches der ASM-Instanz. Hier reichen in der Regel 20 MByte aus. Diese Parameter werden, wie bei einer Datenbankinstanz, über ein SPFILE verwaltet. Das Starten der Instanz erfolgt wie oben dargestellt mit dem Befehl STARTUP; vor einer Konfiguration in den Zustand NOMOUNT und mit einer bestehenden ASMGruppe in den MOUNT-Status. Ein Öffnen ist nicht erforderlich. Das Herunterfahren der Instanz wird mit dem Befehl SHUTDOWN durchgeführt. Es sollte aber beachtet werden, dass mit dem Stoppen der ASM-Instanz alle zugehörigen Datenbanken ebenfalls beendet werden, sofern diese mit ASM arbeiten.
172
4.5
Instanz-Verwaltung
Ältere Versionen
Mit der Version 9i wurde die Server-Parameterdatei (SPFILE) eingeführt. Zusätzlich gibt es aber wie bisher die Möglichkeit, die Parameter über eine Initialisierungsdatei, kurz init.ora zu verwalten. Der Vorteil dieser Datei ist, dass sie direkt editierbar ist und als Textdatei die Möglichkeit bietet, umfangreiche Kommentare (z.B. alte Werte) zu speichern. Dem steht der Nachteil gegenüber, dass die Parameter nicht dynamisch anpassbar sind.
Datenbankobjekte 5.1
Namenskonventionen
Die generellen Namenskonventionen für eine Datenbank haben wir bereits in Kapitel 3.1 besprochen. Ähnliche Vorgaben gelten auch für die Datenbankobjekte. Bei diesen gibt es einen zusätzlichen Punkt, der bei der Datenbank selbst unter Umständen eine eher untergeordnete Rolle spielt. Aus den Objektnamen sollte sich der Kontext der Anwendung erschließen lassen (z.B. personen für eine Tabelle, die personenbezogene Daten enthält). Allerdings gibt es in den Unternehmen und auch in diversen Dokumentationen eine Vielzahl von Regelungen, die mehr oder weniger sinnvoll sind, so dass wir hier nicht näher in eine Diskussion einsteigen wollen. Eines sei allerdings noch gesagt. Es gibt Regelungen, in denen der Name eines Objektes auch den Objekttyp enthält, z.B. t_personen für die Personentabelle, v_personen für die View und s_personen für ein Synonym. Bei solchen Benennungsmethoden sollten Sie bedenken, dass die Flexibilität, welche die Oracle-Datenbank in Bezug auf eine Anwendung mit sich bringt, hierdurch verloren geht. Für eine Anwendung ist es egal, ob auf eine Tabelle oder ein Synonym zugegriffen wird, in Teilen (SELECT) gilt dies auch für Views. Die oben beschriebene Namenskonvention macht aber gerade diese Möglichkeit zunichte. Spätestens beim ersten Release-Wechsel werden Sie feststellen, dass die Regeln entweder behindern oder Sie diese nicht mehr einhalten können. Also sollten Sie von vornherein auf derartige Restriktionen verzichten. Jedes heute gebräuchliche Werkzeug ist in der Lage, Ihnen genau darzustellen, um was für einen Objekttyp es sich handelt, auch wenn dieser keine entsprechende Kennzeichnung enthält. Grundregeln Folgende Regeln existieren für die Namensgebung von Objekten in der Datenbank: 1. Namen sind bis zu 30 Byte lang. (Ausnahme: 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 sowie die Zeichen »_$#« enthalten; Namen von Datenbank-Links zusätzlich ».@«. 6. Reservierte Wörter dürfen nicht verwendet werden. 7. dual darf nicht verwendet werden. 8. Auch nicht reservierte Wörter, die aber eine Bedeutung im Oracle-Umfeld haben (z.B. DIMENSION oder SEGMENT), dürfen nicht verwendet werden.
174
Datenbankobjekte
9. Zwei Objekte im gleichen Namensraum (d.h. Schema) dürfen nicht den gleichen Namen haben. Ausnahme sind Synonyme. 10.Die Spalten einer Tabelle bzw. einer View müssen alle unterschiedliche Namen haben. Spalten verschiedener 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 (Maskierung). In diesem Fall treffen die Regeln 3 bis 8 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. Die Objekte sollten möglichst nicht maskiert werden. Das gilt speziell, wenn man Tabellen von anderen Datenhaltungssystemen wie z.B. Access übernimmt, da hier Groß- und Kleinschreibung sowie Leerzeichen des Öfteren vorkommen. Zwar ist es in der Oracle-Datenbank möglich, solche Objekte anzulegen, Sie werden aber bei vielen Werkzeugen auf Probleme in der Handhabung solcher Objekte haben. 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.
Datenobjekte
5.2
175
Datenobjekte
Die Analyse der Anforderungen und die daran anschließende Entwicklung eines konzeptionellen Datenmodells sind 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 der OracleDatenbank – 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, Datenobjekte (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. 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 partitionierte Tabellen, die physisch unabhängige Partitionen zu einer »logischen« Tabelle zusammenfassen indexorganisierte Tabellen, deren Daten über B*Baumstrukturen organisiert sind externe Tabellen, die auf externe, in Dateiform abgelegte Daten zugreifen temporäre Tabellen, die Daten für die Dauer einer Transaktion oder Session speichern im Cluster abgelegte Tabellen, deren Daten in Abhängigkeit von Cluster-Schlüsseln physisch gespeichert werden Objekttabellen, deren Datensätze über Objektbezeichner referenzierbar sind und welche die Einbettung von geschachtelten Tabellen (Nested Tables) erlauben Diese Organisationsformen werden mit ihren Besonderheiten in den folgenden Abschnitten im Detail besprochen.
176
Datenbankobjekte
5.2.1 Datentypen Alle Datenobjekte, die im Folgenden beschrieben werden, bestehen – bei allen Unterschieden in der physischen Speicherung – logisch gesehen aus beliebig vielen Zeilen mit einer festen Spaltenstruktur. Jede Spalte ist von einem bestimmten Datentyp, wobei in den allermeisten Fällen die eingebauten Oracle-Datentypen verwendet werden, die in diesem Abschnitt kurz beschrieben und untereinander verglichen werden sollen. In der objektrelationalen Welt können weitere, benutzerdefinierte Datentypen Verwendung finden. Davon wird in Abschnitt 5.2.8 berichtet. Die Standarddatentypen Einige Datentypen sind seit vielen Jahren und Versionen in der Oracle-Datenbank enthalten. Die Benutzung dieser Datentypen ist zu empfehlen, wenn nicht starke Argumente dagegen sprechen, da Bugs oder sonstige »Kinderkrankheiten« eher unwahrscheinlich sind und sie außerdem von allen Tools und Schnittstellen verstanden und unterstützt werden. Dazu gehören: VARCHAR2(n) und NVARCHAR2(n) für Zeichenketten bis zu 4000 Byte Länge. VARCHAR2 speichert Strings im Datenbank-Zeichensatz (CHARACTER SET-Klausel beim CREATE DATABASE-Kommando), NVARCHAR2 im Alternativ-Zeichensatz (NATIONAL CHARACTER SET-Klausel). Diese Datentypen haben beim Speicherverbrauch Vorteile gegenüber CHAR und NCHAR (s.u.). Auch die Typen VARCHAR und NVARCHAR (also ohne das Suffix »2«) sollten nicht benutzt werden (dies ist ein entscheidender Unterschied zu ANSI-SQL und muss bei Portierungen von Skripten für Fremddatenbanken berücksichtigt werden). Zu erwähnen ist noch, dass bei Zeichensätzen mit variabler Kodierungslänge (z.B. UTF8) oder fixen Kodierungslängen von mehr als einem Byte (z.B. AL16UTF16) Stringlänge und Byte-Zahl nicht identisch sind. Dies muss bei der Dimensionierung des Datentyps berücksichtigt werden. Der Platzverbrauch entspricht der Byte-Größe der konkreten Zeichenkette. CHAR(n) und NCHAR(n) speichern Zeichenketten der fixen Länge n Bytes (maximal 2000 Byte). Diese sollten daher auch nur benutzt werden, wenn die Zeichenkettenlänge einer Spalte für die gesamte Lebensdauer der Tabelle garantiert feststeht, z.B. für eine Spalte geschlecht = m | f. Werte einer Spalte vom Typ CHAR(n) belegen immer n Bytes. Das Einfügen längerer Zeichenketten liefert eine Fehlermeldung, kürzere Zeichenketten werden rechts mit Leerzeichen aufgefüllt. Beim Vergleich mit anderen CHAR- oder NCHAR-Feldern oder String-Konstanten wird der kürzere der beiden Operanden rechts mit Leerzeichen aufgefüllt und anschließend verglichen. In der Praxis ist daher nur CHAR(1) zu empfehlen, in allen anderen Fällen sollte stattdessen VARCHAR2(n) benutzt werden. NUMBER zur Speicherung von Zahlen. Im Hinblick auf Speicherplatz kann ruhigen Gewissens NUMBER ohne Dimensionierung verwendet werden. Der tatsächliche Speicherplatzverbrauch ergibt sich allein aus der Größe der konkret abgespeicherten Zahl. Soll der Wertebereich allerdings im Sinne einer Integritätsbedingung eingeschränkt werden, ist eine Dimensionierung à la NUMBER(10) oder NUMBER(8,2) besser und performanter als ein entsprechender CHECK-Constraint.
Datenobjekte
177
DATE für das Ablegen von Datumswerten und Zeitstempeln. Leider ist keine genauere Speicherung als auf Sekunden-Granularität möglich. Datumsarithmetik ist – etwas umständlich – durch Addieren oder Subtrahieren von Zahlen möglich, die als Anzahl Tage (oder entsprechende Bruchteile eines Tages) interpretiert werden. Der Platzverbrauch ist konstant 7 Byte. Für internationale Unternehmen taucht außerdem bisweilen als Problem auf, dass unterschiedliche Zeitzonen nicht berücksichtigt werden; es ist Aufgabe des Clients bzw. der Anwendung, die Ortszeit in eine Standardzeit (z.B. GMT) zu transformieren (siehe auch Kapitel 8.3). RAW(n) dient der Abspeicherung von Zeichenketten, die nicht gemäß der NLSEinstellung von Client und Datenbank transformiert, sondern in jedem Fall unverändert übertragen werden sollen. Dieser Datentyp ist für die Speicherung von Binärdaten oder Byte-Ketten zu empfehlen. Die Maximallänge beträgt 2000 Byte. Der Speicherbedarf entspricht der Byte-Größe der konkreten Byte-Kette (RAW ist also das Pendant zu VARCHAR2, einen Datentyp VARRAW gibt es nicht). CLOB, NCLOB und BLOB für Zeichenketten, die länger als 4000 Byte sind (Character Large Objects) sowie für umfangreiche Binärdaten (Binary Large Objects). Die Maximalgröße der abzuspeichernden Objekte ist jeweils (2^32 – 1) Oracle-Blöcke. Im Gegensatz zum Datentyp LONG (siehe unten) kann eine Tabelle mehrere LOBSpalten enthalten. Für jede LOB-Spalte kann ein eigenes so genanntes LOB-Segment in einem dedizierten Tablespace zur Speicherung der LOB-Werte angegeben werden (LOB-Klausel beim CREATE TABLE-Kommando). Über die Klausel ENABLE STORAGE IN ROW kann konfiguriert werden, dass LOB-Werte bis ca. 4 KB Länge in der Tabelle selbst gehalten werden, um das zusätzliche Lesen des LOB-Segments einzusparen. LOBs können über das Package dbms_lob abschnittweise geladen und manipuliert werden, die Byte-Größe der Abschnitte lässt sich über die CHUNK-Klausel einstellen (ein Vielfaches der Oracle-Blockgröße, maximal 32K). BFILE als Pointer auf eine externe Datei. Diese bilden die Alternative zu den erwähnten LOB-Varianten, wenn die Speicherung nicht in der Datenbank, sondern im Dateisystem erfolgen soll. Die eingebaute SQL-Funktion BFILENAME stellt eine Verknüpfung zwischen einer BFILE-Tabellenspalte und einer Datei her, Dateioperationen sind über das Package dbms_lob verfügbar. Neuere Datentypen In den Oracle-Versionen 9i und 10g sind einige Datentypen neu hinzugekommen. Diese sind zwar auf den ersten Blick redundant, da sie ebenfalls der Abspeicherung von Datumswerten und Zahlen dienen. Sie haben dennoch ihre Berechtigung, wie im Folgenden beschrieben wird: TIMESTAMP und INTERVAL dienen der Speicherung von Datumswerten und Zeitdauern. Im Gegensatz zu DATE braucht man hier nicht mehr mit winzigen Tagesbruchteilen zu arbeiten, um Datumsarithmetik durchzuführen, sondern kann die Sekunden, Minuten etc. direkt angeben. Dadurch werden auch Rundungsfehler vermieden. Zum Beispiel: SYSTIMESTAMP + INTERVAL '0:30' MINUTE TO SECOND statt SYSDATE + 1 / 24 / 60 / 2
178
Datenbankobjekte
Außerdem können Sekunden mit bis zu neun Nachkommastellen Genauigkeit gespeichert werden. Bei TIMESTAMP ist auch eine automatische Umrechnung entsprechend der Zeitzone des Clients möglich (TIMESTAMP WITH LOCAL TIME ZONE), was für internationale Unternehmen mit Clients in unterschiedlichen Zeitzonen eine erhebliche Vereinfachung bedeutet. Beide Datentypen entsprechen dem ANSI-SQL-Standard. Da sie bereits mit der Version 9i eingeführt wurden, ist mittlerweile auch eine Unterstützung durch die meisten Tools gegeben. BINARY_FLOAT und BINARY_DOUBLE können zur Speicherung von Fließkommazahlen nach dem IEEE 754-Standard verwendet werden. Die Vorteile sind hier die sehr kompakte Speicherung (4 bzw. 8 Byte) sowie die Möglichkeit, arithmetische Operationen extrem schnell direkt mit Maschinenbefehlen durchzuführen. Diese Datentypen gibt es erst seit Oracle 10g, so dass einige Tools sie noch nicht unterstützen. Außerdem können durch die Speicherung der Mantisse als Binärzahl unerwartete Rundungseffekte auftreten. Nicht empfohlene Datentypen Spalten vom Typ LONG bzw. LONG RAW können Zeichenketten bzw. Byteketten bis zu 2 GB Größe aufnehmen. Jedoch wird dieser Datentyp seit langem nur noch aus Kompatibilitätsgründen gepflegt und unterliegt zahlreichen Einschränkungen. So ist beispielsweise die Reorganisation oder das Verschieben einer Tabelle mit LONG-Spalte sehr aufwändig. Die meisten fortgeschrittenen Funktionalitäten arbeiten nicht mit Tabellen zusammen, die eine LONG-Spalte enthalten. Daher sollte statt LONG immer einer der LOB-Datentypen verwendet werden (s.o.). Bestehende LONG-Datentypen sollten entsprechend migriert werden. Dass Oracle selbst im Data Dictionary weiterhin an zahlreichen Stellen den Typ LONG einsetzt, ist schlicht unverständlich. VARCHAR(n) und NVARCHAR(n) (also ohne das Suffix »2«) sind bis einschließlich Oracle 10g mit den Datentypen VARCHAR2 und NVARCHAR2 äquivalent. Dies wird aber für die Zukunft seitens Oracle nicht garantiert. Die Benutzung dieser Datentypen wird von Oracle zurzeit nicht empfohlen. Werden CREATE-Skripte von anderen Datenbanken mit ANSI-SQL-Datentypen (z.B. DB2) benutzt, werden die ANSI-Datentypen [NATIONAL] CHARACTER VARYING konsequenterweise auch in [N]VARCHAR2 übersetzt. Der Datentyp UROWID kann zur Speicherung von ROWIDs, also von physischen Datensatzadressen verwendet werden. Die persistente Speicherung solcher Adressen ist aber gefährlich, da sich im Rahmen eines Neuaufbaus bzw. einer Reorganisation einer Tabelle alle Satzadressen ändern. Auch bei Replikationen zwischen eigenständigen Datenbanken kommt es zu Problemen, da die Satzadressen auf Quell- und Zieldatenbank unterschiedlich sind.
Datenobjekte
179
5.2.2 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 oder Bitstrukturen (ASSM) 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 Delete-Operationen kann dies bedeuten, dass entsprechend viele leere Blö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 Datenobjekte, 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. Für größere Datenmengen eignen sich u.U. partitionierte Tabellen (s.u.) besser. Da die Partitionierungsoption aber immer noch eine kostenpflichtige Erweiterung der Enterprise Edition ist, werden für die meisten Datenbanken fast ausschließlich heap-organisierte Tabellen eingesetzt. 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 kdnr kname kadresse ) ORGANIZATION
kunde ( NUMBER CONSTRAINT kunde_pk PRIMARY KEY, VARCHAR2(100), VARCHAR2(500) HEAP;
Listing 5.1: Erstellung einer heap-organisierten Tabelle
180
Datenbankobjekte
5.2.3 Partitionierte Tabellen Partitionierte Tabellen bieten die Möglichkeit, Datensätze nach vorgegebenen Verteilungskriterien physikalisch unabhängig, d.h. in separaten Tablespaces mit unterschiedlich Speicherparametern, 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. Durch die Aufteilung der Daten in »kleinere« Partitionssegmente kann grundsätzlich eine bessere Verwaltbarkeit und ein effizienterer Aufbau der Indizes erreicht werden. 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 EA-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: 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 vielen Millionen schon eher.
Datenobjekte
181
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-Betrieb1 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-Anwendungen2, 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 indirekt3 synchronisieren lassen. Modifikationen der Partitionsstrukturen, wie z.B. das Löschen einer Partition, 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. Für wirklich große Tabellen, d.h. Tabellen im Gigabyte-Bereich, sollte die Partitionierung auf jeden Fall in Erwägung gezogen werden. Typen der Partitionierung Es stehen mehrere unterschiedliche Partitionierungsmethoden zur Verfügung: Range-Partitioning 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 jedes 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 Zugriffe auf einzelne Partitionen beschränken. Diese Partitionierung ist überall dort angebracht, wo aufgrund der Tabellenstruktur und der Spaltenwerte »natürliche« Partitionierungskriterien vorliegen, die darüber hinaus auch annäherungsweise eine Gleichverteilung der Daten garantieren können.
1 2 3
OLTP steht für OnLine Transaction Processing und wird – im Gegensatz zum Batch-Betrieb – durch kleine Online-Transaktionen charakterisiert. Rolling Window = ein »Fenster« aktiv vorgehaltener Daten, z.B. Aufträge, die vom Tagesdatum aus zwei zurückliegende Jahre vorgehalten werden. 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.
182
Datenbankobjekte
Hash-Partitioning Bei der Hash-Partitionierung ü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. Aufgrund 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 daher in diesem Falle nicht über das Löschen der Partition realisiert werden. Beim Zugriff kann man dann von der Partitionierung profitieren, wenn mehrere Tabellen mit dem gleichen Schlüssel partitioniert wurden (Partition Join, siehe Kapitel 15). Auf der anderen Seite bietet die Hash-Partitionierung 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. List-Partitioning 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. Derzeit lässt sich bei der List-Partitionierung – im Gegensatz zu den vorangehenden Methoden – nur eine einzige Spalte als Partitionierungskriterium definieren. Die Abgrenzung der einzelnen Partitionen wird – wie auch bei der Range-Partitionierung – über eine VALUES-Klausel erreicht. Composite-Partitioning Die Composite-Partitionierung stellt eine Kombination der 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 oder nach der List-Methode angelegt. Jede Subpartition ist hierbei speichertechnisch unabhängig, d.h., sie kann mit eigenen Speicherparametern ausgestattet 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« Kriteriums – auf Basis der Kundennummer Hashpartitioniert. 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.
Datenobjekte
183
5.2.4 Indexorganisierte Tabellen (IOT) Indexorganisierte Tabellen speichern ihre Daten – sortiert nach dem Primärschlüssel – in Form eines B*-Indexbaumes. Im Gegensatz zu normalen B*-Indexbä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. Es lassen sich auch so genannte 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 Indexbaum. Da Einträge in Indexbäumen durch INSERT- und UPDATE-Operationen und damit verbundenen Split-Operationen auf den Indexblä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 indexorganisierte 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 im 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 5.2: Index-organized Table
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); Listing 5.3: Zusätzlicher Index auf IOT
Wie normale Indizes, so lassen sich auch indexorganisierte 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 Verkürzung der Datensätze in den Blättern des Indexbaumes erreicht, die den Index kompakter und damit für EA-Operationen effizienter machen.
184
Datenbankobjekte
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 Indexblattes 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 5.4: IOT mit Komprimierung
Indexorganisierte Tabellen sind sehr gut geeignet für die Umsetzung aller Datenobjekte, 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-Relationen4 des Datenmodells auflösen, und große Referenztabellen, die nur wenige Spalten enthalten, die nicht zum Schlüssel gehören.
5.2.5 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 die gerade aktive Session sichtbar. Physisch speichern temporäre Tabellen ihre Daten in dem 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 Redo-Log-Informationen für ein eventuelles Rollback, nicht jedoch für die geänderten Datenblöcke.
4
Jedes A bezieht sich auf ein oder mehrere B, und umgekehrt kann sich jedes B auf ein oder mehrere A beziehen.
Datenobjekte
185
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 5.5: Erstellen einer temporären 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, dass die betreffende Tabelle in allen aktuell angemeldeten Sessions vollständig leer ist. CREATE INDEX tidxload 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 Listing 5.6: Fehler bei der Indexerstellung einer IOT
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 eigenen Segmentes anlegen, sondern diesen – beim Vorhandensein von Daten – aus dem Speichervolumen des temporären Tablespace beanspruchen. 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.
5.2.6 Externe Tabellen Seit 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-, INSERT- und 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.
186
Datenbankobjekte
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 Directory-Objekt angelegt werden. Dies ist lediglich ein Alias-Name für ein Dateisystemverzeichnis auf dem Datenbankserver (siehe Abschnitt 5.7). Im folgenden Beispiel wird dem Datenbankverzeichnis dat_dir das externe Verzeichnis /home/oracle zugeordnet: CREATE OR REPLACE DIRECTORY dat_dir AS '/home/oracle'; Listing 5.7: Create Directory
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 patrick;
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 patrick;
Im nächsten Schritt kann dann die externe Tabelle – in diesem Fall neue_auftraege – definiert werden: CREATE TABLE neue_auftraege ( 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" NULLIF "AUFDATUM"=BLANKS ) ) LOCATION ('neue_auftragsdaten.dat') ) PARALLEL 5 REJECT LIMIT UNLIMITED; Listing 5.8: Erstellung einer externen Tabelle
Datenobjekte
187
In diesem Beispiel wird die externe Tabelle neue_auftraege mit den Spalten aufnr, kdnr und aufdatum 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 in diesem Fall über den Treiber ORACLE_LOADER – siehe die TYPE-Klausel – zugegriffen. Die Datei neue_auftragsdaten.dat 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 mit der Prozessnummer des betreffenden Serverprozesses (Substitutionsvariable %p) qualifiziert. Jeder Zugriff wird darüber hinaus in einer Log-Datei – LOGFILE-Klausel – protokolliert. Zugriffe werden über die gewohnte SQL-Syntax 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. Neben der Methode des Ladens über den Oracle Loader, die schon in Oracle9i möglich war, gibt es bei Oracle 10g auch die Möglichkeit, die Funktion des Data Pump für das Ein- und Auslesen der Daten zu nutzen (TYPE ORACLE_DATAPUMP). Damit ist es erstmals möglich, Daten über externe Tabellen zu entladen. Im Gegensatz zum Loader handelt es sich bei der Ausgabe allerdings um ein internes Oracle-Format, d.h., die Daten können auch nur über Data Pump weiter verarbeitet werden. Das folgende Beispiel erzeugt ein Dump-File (neue_auftragsdaten.dmp) als externe Tabelle. Durch den Befehl CREATE TABLE AS SELECT entfallen auf der Quellseite die Spaltenangaben. CREATE TABLE auftraege_ext ORGANIZATION EXTERNAL ( TYPE ORACLE_DATAPUMP DEFAULT DIRECTORY pump_dir ACCESS PARAMETERS ( LOGFILE 'auftraege.log') LOCATION ('auftragsdaten.dmp' )) AS SELECT aufnr, kdnr, aufdatum FROM demo.auftraege Listing 5.9: Externe Tabelle mit Data Pump erstellen
Mit einem SELECT-Befehl kann jetzt wie üblich auf diese externe Tabelle zugegriffen werden. Diese Methode bietet sich überall dort an, wo Tabelleninhalte in regelmäßigen Abständen zwischen Systemen transferiert werden müssen. Die erstellte Datei (auftragsdaten.dmp) kann allerdings nicht überschrieben werden, d.h., nach der Übertragung sollten Sie die Dump-Datei löschen und mit dem oben angegebenen Befehl bei Bedarf wieder neu anlegen. DML-Befehle sind bei externen Tabellen generell nicht möglich. Weitere Informationen über die Benutzung von Data Pump erhalten Sie in Kapitel 10.6.
188
Datenbankobjekte
Beachten sollten Sie außerdem, dass bei der Verwendung von externen Tabellen und der Angabe einer Log-Datei (LOGFILE) jeder Zugriff protokolliert wird. Wenn also eine größere Anzahl Benutzer auf die Daten zugreift, sollten Sie ohne LogDatei (NOLOGFILE) arbeiten. 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, an Parameter- oder Referenztabellen gejoint 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.
5.2.7 Cluster In diesem Kapitel geht es nicht um Hardware-Cluster, sondern um eine spezielle Form der Speicherung von Daten. Daher sollten Sie, wenn Sie sich mit jemandem über »Cluster« unterhalten, frühzeitig abklären, was damit gemeint ist! 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 der Zugriff auf diese Sätze wird über zwei unterschiedliche Verfahren – durch Indizierung und HashAlgorithmen – 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.
Datenobjekte
189
Im folgenden Beispiel wird der Index-Cluster testcl mit den Tabellen kunde und auftrag angelegt: CREATE CLUSTER kd_auftraege (kdnr NUMBER) INDEX; CREATE INDEX i$kd_auftraege ON CLUSTER kd_auftraege; CREATE TABLE kunden ( kdnr NUMBER, nachname VARCHAR2(100), vorname VARCHAR2(100) ) CLUSTER kd_auftraege (kdnr); CREATE TABLE auftraege ( aufnr NUMBER, kdnr NUMBER, aufdatum DATE ) CLUSTER kd_auftraege (kdnr); Listing 5.10: 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 dem ein Cluster-Schlüssel zu speichern ist. Die Hash-Funktion gibt in der Regel den Blockversatz relativ zum Beginn des betreffenden Segmentes an. Damit nicht mehrere Cluster-Schlüssel einen Datenblock teilen, muss beim Anlegen eines Hash-Clusters die erwartete maximale Anzahl von ClusterSchlü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 kd_auftraege (kdnr NUMBER) HASHKEYS 1000 HASH IS kdnr; CREATE TABLE kunden ( kdnr NUMBER, nachname VARCHAR2(100), vorname VARCHAR2(100) ) CLUSTER kd_auftraege (kdnr); CREATE TABLE auftraege ( aufnr NUMBER, kdnr NUMBER, aufdatum DATE ) CLUSTER kd_auftraege (kdnr); Listing 5.11: Hash-Cluster
190
Datenbankobjekte
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 Index »sortierte« Speicherung der Datensätze Diesen Vorteilen steht jedoch eine Reihe von Nachteilen gegenüber: Für den Fall, dass nur eine der im Cluster abgelegten Tabellen gelesen wird, kommt es zu einer erhöhten Anzahl an Blockzugriffen. Nur partiell gefüllte Hash-Cluster führen ebenfalls zu einer erhöhten 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. Die 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. Cluster können nicht repliziert und partitioniert werden. Diese Überlegungen machen deutlich, dass Cluster-Implementierungen nur selten zum Einsatz kommen dürften.
5.2.8 Objekttypen und Kollektoren Seit der Version 8.0 des Oracle-Datenbanksystems steht 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 Oracle 10g umzusetzen. 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
Datenobjekte
191
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, wieder verwendbare 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. CREATE OR REPLACE TYPE adresse AS OBJECT ( strasse VARCHAR2(50), postfach VARCHAR2(20), plz VARCHAR2(20), ort VARCHAR2(50), land VARCHAR2(50) ); Listing 5.12: Objekttyp
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 Tabellen 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 firma ( id INTEGER CONSTRAINT pk_firma PRIMARY KEY, name VARCHAR2(100), anschrift adresse ); Listing 5.13: Erstellen einer Tabelle mit Objekttypen
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) ); Listing 5.14: Einfügen in eine Tabelle mit Objekttypen
192
Datenbankobjekte
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 5.15: View auf eine objektrelationale Tabelle
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 );
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:
Datenobjekte
193
CREATE OR REPLACE TYPE auftrag AS OBJECT ( aufnr INTEGER, datum DATE, auftraggeber REF person, kommentar VARCHAR2(500) );
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 Personenreferenzen 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 SELECT FROM WHERE AND
INTO auftraege 12345, SYSDATE, REF(p), 'Kommentar' personen p p.nachname = 'Müller' p.vorname = 'Otto';
Beim Selektieren der Auftragsdaten ist die Syntax – dank der Möglichkeit der impliziten Dereferenzierung – einfacher. Für diese Dereferenzierung muss auf jeden Fall ein Alias-Name 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.
194
Datenbankobjekte
Nested Tables – sind ungeordnete Kollektionen von Elementen gleichen Datentyps, die nicht in ihrer Maximalzahl festgelegt werden und aus nur einem Attribut 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 5.16: Objekttabelle mit VARRAY
pers_tel kann dann – wie oben beschrieben – weiterverwendet werden. Zum Einfü-
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 /
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 5.17: Objekttabelle mit Nested Table
Die Kopplung 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 IOT angelegt und der Indexbaum zusätzlich komprimiert werden. Die Speicherung als Index hat die Sortierung der Daten (Clustering) mit der nested_table_id als Präfix zur
Indexstrukturen
195
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 5.18: Einfügen in eine nested Table
5.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 so genannter Unique Index – eindeutige Wertemengen garantieren. Für den Datenbankadministrator wie auch den Anwendungsentwickler 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 (z.B. Tablespace) 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. 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 Oracle 10g steht 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.
196
Datenbankobjekte
5.3.1 Allgemeine Regeln Indizes lassen sich im Kontext von Tabellen und Clustern anlegen. Vorhandene Indizes werden durch INSERT, UPDATE 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 Optimizers5. 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 dass 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 Indexblätter (Leaf Node) verteilt. Zeiger auf die Endpunkte dieser Indexblätter werden in einem Indexbaum in so genannten Indexzweigen (Branch Node) zusammengefasst, die den schnellen Zugriff auf konkrete Schlüsselwerte garantieren.
Abbildung 5.1: Struktur eines Indexbaums 5
Zusammengesetzte Indizes können in der Regel nur genutzt werden, wenn alle oder die führenden Spalten spezifiziert werden.
Indexstrukturen
197
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 Indexblä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 Indexbaumes 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 Indexbä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 in der Regel alle oder zumindest die führenden Spalten sein. Eine Ausnahme ist der so genannte SkipScan, der die führende Spalte überspringen kann, wenn diese nur wenige unterschiedliche Werte (geringe Kardinalität) aufweist. 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. In den folgenden Abschnitten werden die Besonderheiten der einzelnen Indextypen vorgestellt.
5.3.2 B*Tree Index B*Indizes sind die »klassischen« Indizes in Oracle-Datenbanken. Im folgenden Beispiel wird ein nicht eindeutiger B*Index mit Namen idx_ang_name für die Spalte name der Tabelle angestellte aufgebaut. CREATE INDEX idx_ang_name ON angestellte (name);
Für den Aufbau dieses Index werden die Spaltenwerte von name sortiert. Jeder Name wird zusammen mit der ihm zugehörigen Satzadresse (Rowid) in den Indexblättern gespeichert. Über die Blätter wird dann der restliche Indexbaum erzeugt. Da die Syntax keine Storage-Klausel enthält, wird das Indexsegment in diesem Fall im DefaultTablespace des betreffenden Schemabenutzers angelegt. B*Indizes enthalten keine NULL-Werte, es sei denn, es handelt sich um zusammengesetzte Indizes. D.h., Abfragen mit IS NULL-Klauseln können einen solchen Index in der Regel nicht benutzen. Im zweiten Beispiel wird ein zusammengesetzter Index erzeugt, der an erster Stelle die Abteilungsnummer und an zweiter den Namen setzt. CREATE INDEX idx_ang_abtname ON angestellte (abtnr, name) TABLESPACE indx;
198
Datenbankobjekte
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. Aufgrund 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). 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.
5.3.3 Bitmap-Index Im Gegensatz zu B*Indizes speichern Bitmap-Indizes ihre Schlüssel nicht mit den zugehörigen Satzadressen, sondern in Form von Bitmaps. Zu jedem Spaltenwert der Tabelle enthält der Bitmap-Index eine logische Bitmap. Diese 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-Index 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.
Indexstrukturen
199
Die folgende Abbildung zeigt den Aufbau einer Bitmap.
Abbildung 5.2: Struktur einer Bitmap
Auf die physischen Bitmaps eines Bitmap-Index wird über eine Baumstruktur – vergleichbar einem B*Index – zugegriffen. Im folgenden Beispiel wird der nicht eindeutige Bitmap-Index bidx_ang_dat für die Spalte einstelldatum der Tabelle angestellte aufgebaut: CREATE BITMAP INDEX bidx_anrede ON kunden(anrede);
Auch dieser Index wird – wegen der fehlenden Storage-Klausel – im Default-Tablespace des betreffenden Schemas angelegt. Der Speicherplatz, der für die Sortierung der Daten und den Aufbau der Bitmaps notwendig ist, wird in der Regel im Rahmen der dynamischen PGA-Verwaltung (pga_aggregate_target bzw. workarea_size_policy) verwaltet. Alternativ kann er über den Serverparameter create_bitmap_area_size eingestellt werden, dessen Standardwert 8 MByte beträgt. Eine weitere Optimierung der Bitmap-Indizes lässt sich über die Festlegung der maximalen Anzahl von Datensätzen pro Oracle-Block erreichen: ALTER TABLE kunden MINIMIZE RECORDS_PER_BLOCK;
Dieser Befehl sorgt dafür, dass die maximale Anzahl von Datensätzen pro Block für die betreffende Tabelle festgeschrieben wird 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 kalkuliert werden, sondern können auf Basis der konkret vorgefundenen Anzahl von Datensätzen pro Block angegeben 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 Nullwerte: 6
Der Plan wurde in SQL*Plus über den Befehl Set Autotrace On generiert.
200
Datenbankobjekte
SELECT * FROM kunden WHERE anrede IS NULL; Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=1 Card=1 Bytes=63) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'KUNDEN' (TABLE) (Cost=1 Card=1 Bytes=63) 2 1 BITMAP CONVERSION (TO ROWIDS) 3 2 BITMAP INDEX (SINGLE VALUE) OF 'BIDX_ANREDE' (INDEX (BITMAP)) Listing 5.19: Bitmap-Index-Ausführungsplan
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: Bitmap-Indizes werden extrem kompakt gespeichert. Aufgrund dessen sind die Kosten für Zugriffe auf diese Indizes sehr gering. 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 ein so genanntes Bitmap-Index-Fragment gesperrt. Davon sind unter Umständen alle Zeilen betroffen, die den gleichen Wert der Bitmap-Spalte enthalten. 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 Zugriffe existieren, deren Prädikate diese Spalten verwenden auf der Tabelle mehrere Bitmap-Indizes existieren und sich dadurch Vorteile durch die gleichzeitige Verwendung ergeben
Indexstrukturen
201
Bitmap-Indizes dürfen in keinem Fall – wegen des oben beschriebenen Sperrverhaltens – für Spalten angelegt werden, die gleichzeitig von vielen Transaktionen verändert werden! Bei 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.
5.3.4 Bitmap-Join-Index 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.
Abbildung 5.3: Speicherstrukturen von Bitmap-Join-Indizes
7
ALTER INDEX ... REBUILD;
202
Datenbankobjekte
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 2004 wie folgt ermitteln: SELECT FROM WHERE AND AND AND
SUM(amount_sold) sales s , times t, products p t.time_id = s.time_id p.prod_id = s.prod_id t.calendar_year = 2004 p.prod_name = 'Linen Big Shirt';
Ohne Aufbau eines Bitmap-Join-Index 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): 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)
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;
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. Während des Index-Aufbaus werden sofort Statistiken generiert.
8 9
Die Beispieltabellen dieses Abschnitts sind dem Oracle Demo-Schema Sales History entlehnt, das jeder Installation beigefügt ist. Die Ausgabe wurde über den Befehl SET AUTOTRACE ON in Sql*Plus erzeugt.
Indexstrukturen
203
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 5
3 4
BITMAP CONVERSION (TO ROWIDS) BITMAP-INDEX (SINGLE VALUE) OF 'BJ_INDEX'
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 times 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 BitmapJoin-Indizes für indexorganisierte 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 im Abschnitt 5.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 werden11.
5.3.5 Function-based Index Funktionsbasierte 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 die von dem Ausdruck zurückgegebenen Werte indiziert. Die indizierten Funktionen können sowohl vordefinierte SQL-Funktionen als auch vom Benutzer selbst erstellte Funktionen sein. Das folgende Beispiel erzeugt den zusammengesetzten funktionsbasierten Index fidx_name der Tabelle kunden für die SQL-Funktion UPPER auf den Spalten kd_nachname und kd_vorname: CREATE INDEX fidx_name ON angestellte (UPPER(kd_nachname),UPPER(kd_vorname));
10 Oracle 10g Version 10.1.0.3 11 Bei Bitmap-Join-Indizes werden – im Gegensatz zu Bitmap-Indizes – mehr als zwei physische Bitmaps in einem Oracle-Block gespeichert.
204
Datenbankobjekte
Für den Aufbau eines funktionsbasierten Index ist das Systemprivileg QUERY REWRITE erforderlich, außerdem muss für die Datenbank oder zumindest für die Session der Parameter query_rewrite_enabled = TRUE eingestellt werden. ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE;
Abfragen, welche die SQL-Funktion UPPER nutzen, werden danach über den funktionalen Index ausgeführt: SELECT * FROM kunden WHERE UPPER(kd_nachname) = 'AHRENDS' AND UPPER(kd_vorname) = 'GERD'; Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=5 Bytes=315) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'KUNDEN' (TABLE) (Cost=2 Card=5 Bytes=315) 2 1 INDEX (RANGE SCAN) OF 'FIDX_NAME' (INDEX) (Cost=1 Card=1)
Funktionsbasierte Indizes können als B*Index oder Bitmap-Index angelegt werden, als B*Index sind sie auch als Reverse Index 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 weist 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. Zu beachten ist bei funktionalen Indizes, dass damit natürlich genau eine Funktion benutzt werden kann. Die oben genannte Funktion UPPER führt bei der Abfrage dazu, dass der Index benutzt wird, die alternative Funktion LOWER hingegen würde keinen Indexzugriff ermöglichen.
5.3.6 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änkungen12 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.
12 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 (Equipartitionierung).
Indexstrukturen
205
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 Index 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:
206
Datenbankobjekte
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 Tabellenpartitionen 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 aufgrund 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. – Zugriffe sind – wegen der fehlenden Equipartitionierung – aufwändiger als über prefixed Indizes, denn Schlüsselwerte können in mehreren Partitionen vorkommen.
Indexstrukturen
207
Global prefixed Index Ein Index wird als global prefixed bezeichnet, wenn er nach anderen Kriterien als der zugrunde liegenden Tabelle partitioniert ist, die für die Partitionierung verantwortliche Spalte jedoch mit indiziert ist. Die Partitionierung bei Global prefixed Indizes darf jedoch nur vom Typ 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 pidx_verkauf1 angelegt, der, genau wie seine Basistabelle verkauf, range-partitioniert ist. Er enthält alle Partitionierungsspalten dieser Tabelle. Partitionsnamen werden in diesem Beispiel explizit vergeben, wie auch die betreffenden Tablespaces. Eine VALUES-Klausel ist wegen der Equipartitionierung nicht zulässig. CREATE INDEX pidx_verkauf1 ON verkauf(verkjahr, verkmonat,verktag) LOCAL (PARTITION vi1 TABLESPACE tsi1, PARTITION vi2 TABLESPACE tsi2, PARTITION vi3 TABLESPACE tsi3, PARTITION vi4 TABLESPACE tsi4); Listing 5.20: Equipartitionierter Index
Im zweiten Beispiel wird für die indexorganisierte Tabelle verkauf_iot, die nach den Spalten verkjahr, verkmonat und verktag partitioniert ist, der lokale Sekundärindex pidx_verkauf_iot1 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.
208
Datenbankobjekte
CREATE INDEX pidx_verkauf_iot1 ON VERKAUF_IOT(VERKMONAT, VERKTAG) LOCAL (PARTITION vi1 TABLESPACE tsi1, PARTITION vi2 TABLESPACE tsi2, PARTITION vi3 TABLESPACE tsi3, PARTITION vi4 TABLESPACE tsi4); Listing 5.21: Local nonprefixed Index
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 pidx_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 im Default-Tablespace des betreffenden Schemas gespeichert. CREATE INDEX pidx_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 anrede geplant. Ein lokaler eindeutiger Index müsste – neben der Spalte anrede – aus den Partitionierungsspalten aufdatum (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 angelegt13, der nach anrede partitioniert werden muss. CREATE UNIQUE INDEX puidx_auftrag ON auftrag(anrede) GLOBAL PARTITION BY RANGE (anrede) (PARTITION p1 VALUES LESS THAN(1000), PARTITION p2 VALUES LESS THAN(2000), PARTITION p3 VALUES LESS THAN (MAXVALUE) ); Listing 5.22: Global prefixed Index
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 Index, die für alle Partitionen gültigen Speicherparameter und die Anzahl der Partitionen. user_ind_partitions – enthält Informationen zu den einzelnen Hauptpartitionen, d.h. Namen, Partitionierungskriterien, Speicherparametern und Statistiken.
13 Als Alternative käme hier auch ein nicht partitionierter, eindeutiger Index in Frage.
Indexstrukturen
209
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.
5.3.7 Komprimierung von Indizes 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 Indexblatt nur einmal gespeichert; Suffixe verweisen auf die Präfixe ihres 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 Index für die Spalten gehalt und kommission der Tabelle angestellte: CREATE INDEX idx_ang_com ON angestellte (gehalt, kommission) COMPRESS;
Die folgende Abfrage gibt die Eigenschaften des neuen Index aus: SELECT index_name, index_type, compression, prefix_length FROM user_indexes WHERE index_name = 'IDX_ANG_COM'; INDEX_NAME INDEX_TYPE COMPRESS PREFIX_LENGTH --------------- ----------------------- -------- ------------IDX_ANG_COM NORMAL ENABLED 2 Listing 5.23: Compressed Index
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 Index gegenüber einem identischen ohne Komprimierung betrug etwa 30%.14 Die Länge von Präfixen kann aber auch explizit definiert werden. Im folgenden Beispiel wird die Anzahl der Spalten des Präfix – hier nur die führende Spalte gehalt – in der COMPRESS-Klausel angegeben: CREATE INDEX idx_ang_com ON angestellte (gehalt, kommission) COMPRESS 1;
Es versteht sich, dass der Speicherbedarf bei sinkender Komprimierungsrate steigt.
14 Die Tabelle Angestellte bestand aus 29.000 Einträgen; die Indexgrößen betrugen 550 KByte (nicht komprimiert) und 300 KByte (komprimiert).
210
Datenbankobjekte
Komprimierte Indizes empfehlen sich überall dort, wo großer Wert auf kompakte Speicherung gelegt wird, Bitmap-Indizes jedoch aufgrund 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.
5.3.8 Reverse Key-Indizes B*Indizes lassen sich auch als Reverse Key-Indizes aufbauen. In diesem Fall werden die Schlüsselwerte in den Indexblättern in umgekehrter Bit-Reihenfolge abgespeichert. Im folgenden Beispiel wird der Index idxr_ang_abt als Reverse Key-Index für die Spalte abt_nr der Tabelle angestellte angelegt: CREATE INDEX idxr_ang_abt ON angestellte (abt_nr) REVERSE;
Durch die umgekehrte Speicherung der Zeichenketten werden Schlüssel, die normalerweise in einem Indexblatt 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, IO-Operationen besser auf die Indexblätter zu verteilen. Interessant sind Reverse Key-Indizes auch für Indexspalten, die chronologisch mit wachsenden Spaltenwerten gefüllt werden, also z.B. ein Erfassungsdatum oder eine Auftragsnummer, die aus einer Sequenz generiert wird. Bedingt durch den Mechanismus, mit dem B*Indizes gepflegt werden, haben solche Indizes nach einer gewissen Zeit einen schlechten Füllgrad (maximal 50%), durch Benutzung eines Reverse Key-Index wird dieses Verhalten beseitigt. Auf der anderen Seite werden aufgrund der umgekehrten Speicherung Wertebereiche, die normalerweise über Range-Zugriffe im Index gelesen werden können, einzeln abgearbeitet. Wenn aber sowieso hauptsächlich Einzelzugriffe auf Datensätze über den Index vorkommen, dann sollte ein Reverse Key-Index in Betracht gezogen werden. 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.
5.3.9 Weitere 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 Schlüsselwerte zu sortieren. Im folgenden Beispiel wird der Index idx_aufdatum mit zweifacher Parallelisierung angelegt: CREATE INDEX idx_aufdatum ON auftraege (aufdatum) PARALLEL 4; Listing 5.24: Parallele Erstellung eines Index
Indexstrukturen
211
Entsprechende Hintergrundprozesse müssen in diesem Fall vorher vom DBA über die Serverparameter parallel_min_servers und 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 eigene Extents 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 Fehler15, 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 idx_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, dass 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 ShareSperren 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 fünfstelliger, 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 Index genutzt, um die angefallenen Änderungen diesem anzufügen. Die ONLINE-Klausel ist für Bitmap- und Cluster-Indizes nicht nutzbar.
15 ORA-00054: resource busy and acquire with NOWAIT specified
212
Datenbankobjekte
Indexreorganisation Durch häufiges Einfügen und Löschen16 von Indexschlüsseln kann es notwendig werden, Indexbä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 Indexbaumes 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 auf der Basis des alten Index als
Datenquelle 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 einen neuen Tablespace zu verschieben 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 bereiten, steht die COALESCE-Klausel bereit: ALTER INDEX i$brev COALESCE;
COALESCE zieht benachbarte Blätter eines Indexzweiges 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: 16 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 Index also keine Updates. (Die Ausnahme sind Bitmaps.)
Constraints
213
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 Wert17 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. Generell gilt für das Monitoring von Indizes, dass diese Information sehr effektiv erstellt wird, da die Daten nur zyklisch in die entsprechenden Data-DictionaryTabellen geschrieben werden. Das bedeutet zwar, dass bei einem plötzlichen Systemausfall Informationen verloren gehen, da diese jedoch unkritisch sind, ist das zu verschmerzen.
5.4
Constraints
Constraints sind eine grundlegende und sehr nützliche 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. 17 Über den Zusatz Keep n, wobei n die Anzahl der Bytes oberhalb der Hochwassermarke angibt.
214
Datenbankobjekte
5.4.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. Bei der Implementierung eines Datenmodells empfiehlt es sich, Tabellen- und Constraint-Definitionen in verschiedene Skripte 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. dass 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) );
Constraints
215
Die Überprüfung der Eindeutigkeit erfolgt mit Hilfe eines Index. 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 );
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 aufpos_pk ON auftragspositionen (auftr_id, pos_id) TABLESPACE appl_idx;
oder ALTER TABLE auftragspositionen ( CONSTRAINT aufpos_pk PRIMARY KEY (auftr_id, pos_id) );
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 Primärschlüssel oder ein beliebiges UNIQUEConstraint einer übergeordneten »Master«-Tabelle beziehen. Es versteht sich, dass 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 einen FOREIGN KEY-Constraint der Tabelle auftragspositionen referenziert: ALTER TABLE auftragspositionen ( CONSTRAINT aufpos_fk_auftraege FOREIGN KEY (auftr_id) REFERENCES auftraege );
216
Datenbankobjekte
Soll statt des Primärschlüssels ein Unique-Constraint referenziert werden, so ist dies explizit in Form der betreffenden Spalten anzugeben: ALTER TABLE auftragspositionen ( CONSTRAINT aufpos_fk_auftraege FOREIGN KEY (auftr_id) REFERENCES auftraege (auf_unique) );
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 Bespiel: Tabelle A hat zwei Primärschlüsselspalten a1 und a2, welche 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) * FEHLER in Zeile 1: ORA-02291: Integritäts-Constraint (SYSTEM.SYS_C001782) verletzt - übergeordneter Schlüssel nicht gefunden 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.
Constraints
217
Beim Durchlesen der o.a. Zeilen sind die Reaktionen des Datenbanksystems größtenteils in Ordnung.; 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.u.). 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. Das heißt, 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 Update- und 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 mit gelöscht werden, so lautet obige Fremdschlüsseldefinition wie folgt: ALTER TABLE auftragspositionen ( CONSTRAINT aufpos_ref_auftraege FOREIGN KEY (auftr_id) REFERENCES auftraege 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«. Die ON DELETE-Klausel kann sich zu einem späteren Zeitpunkt jedoch als Problem erweisen, und zwar dann, wenn die Tabellen repliziert werden sollen (siehe Kapitel 13). In diesem Fall können solche Funktionen zu Synchronisierungsproblemen führen. 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 und 10g agieren 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 Oracle 10g-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.
218
Datenbankobjekte
Tipp: Grundsätzlich sollten Fremdschlüssel indiziert werden. Hiermit werden Probleme mit Sperren verhindert. 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 DROP TABLESPACE appl_data -INCLUDING CONTENTS -CASCADE CONSTRAINTS; --
CONSTRAINTS; -- oder: Lösche den ganzen Tablespace sowie alles, was drin ist und alle Fremdschlüssel-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.o.): 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)));
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 führen.
5.4.2 Constraint-Handhabung 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
Constraints
219
ENABLE und NOVALIDATE beim DISABLE der Standard ist. 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 Index 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 INDEX-Klausel, da hier auch ein bestehender Index mit USING INDEX <schema>.
oder ein komplettes CREATE INDEX-Kommando mit USING INDEX (CREATE INDEX ...)
angegeben werden kann. Seit 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 CONSTRAINT USING INDEX <schema>. /
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 mit der KEEP INDEX- bzw. DROP INDEX-Option über das Verbleiben des Index, der zur Prüfung des Constraints genutzt wurde, entschieden werden. Eine elementare Eigenschaft des VALIDATE-Prozesses ist die Möglichkeit, ConstraintVerletzungen 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
220
Datenbankobjekte
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 Skript $ORACLE_HOME/rdbms/admin/utlexcpt.sql
angegeben ist: CREATE TABLE exceptions( row_id ROWID, owner VARCHAR2(30), table_name VARCHAR2 (30), constraint VARCHAR2 (30) );
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. 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. RELY wird bei Materialized Views im Zusammenhang mit ausgeschalteten Con-
straints benötigt. 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
Constraints
221
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: 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 C ---------- --------------1 x 2 y 3 z 1 a SQL> COMMIT; commit * ERROR at line 1: ORA-02091: transaction rolled back ORA-00001: unique constraint (DIERK.T1_PK) violated Listing 5.25: 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:
222
Datenbankobjekte
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 negativ ausgehen, ist auch der Zusatzaufwand für den Datenbankserver nicht zu unterschätzen. Es entstehen Aufwände im Bereich der Undo-Segmente sowie des Redo-Log 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. Metadaten Die Views dba_constraints und dba_cons_columns sind zum Monitoring von Constraints vorgesehen. Hier einige ausgewählte Spalten: R_OWNER: Eigentümer der referenzierten Tabelle bei Fremdschlüsseln R_CONSTRAINT_NAME: Name des referenzierten Constraints bei Fremdschlüsseln BAD: YES bedeutet, dass ein Datum mit einem zweistelligen Jahresformat verwendet wird (und somit zu falschen Ergebnissen führen kann). LAST_CHANGE: Datum des letzten ENABLE oder DISABLE CONSTRAINT_TYPE: – P: Primärschlüssel – U: Eindeutiger Schlüssel – R: Fremdschlüssel – C: Check-Constraint – V: View mit Check-Option – O: Read-only-View POSITION: Spaltenposition (wichtig für mehrspaltige Schlüssel) in dba_cons_columns
Views
5.5
223
Views
5.5.1 Standard-Views Views sind virtuelle Tabellen. Ihr Inhalt besteht wie bei Tabellen aus Zeilen und Spalten, liegt aber nicht physisch irgendwo in der Datenbank, sondern wird erst bei Bedarf »on the fly« ermittelt. Die Daten, die eine View beinhaltet, sind von anderen Daten (aus echten Tabellen) abgeleitet. Dennoch können Views in SQLAbfragen wie normale Tabellen behandelt werden. Auch der Inhalt einer View selbst wird durch eine SQL-Abfrage definiert. Diese kann direkt auf echte Tabellen oder selber wiederum auf andere Views Bezug nehmen. Auf diese Weise leitet sich der Inhalt einer View direkt oder indirekt aus einer oder mehreren Basistabellen ab. Unter diesem Aspekt kann eine View auch als benannte Abkürzung für eine SQL-Abfrage gesehen werden. Außer dem Text dieser Abfrage wird praktisch kein weiterer Speicherplatz benötigt. Im Gegensatz zu Tabellen bilden Views also keine Segmente, tauchen also z.B. nicht in dba_segments auf, wohl aber in dba_objects. Natürlich ist Schreibfaulheit nicht der einzige Grund dafür, Views zu benutzen. In den folgenden Abschnitten wird das Thema daher etwas eingehender beleuchtet. Vereinfachung von SQL-Abfragen Komplexe SQL-Abfragen können schnell unleserlich werden. Insbesondere wenn Unterabfragen ([NOT] EXISTS oder [NOT] IN) beteiligt sind, lohnt sich manchmal eine »Auslagerung« der Unterabfrage in eine View. Bei der Anwendungsentwicklung wird das Schreiben und Austesten von SQLAbfragen oft stiefmütterlich behandelt. Performance-Aspekte werden häufig vollständig an die spätere Datenbankadministration »delegiert«. Im produktiven Einsatz zeigen sich dann früher oder später die Mängel, und es muss mit manchmal hohem Aufwand nachgebessert werden, dafür werden Optimizer-Hints und Indexstrukturen nachgepflegt etc. Mit dem nächsten Software-Release und/oder OracleMigration wird das Ganze iteriert. Stammt die Software von einem Drittanbieter, ist es meist nicht möglich, in den Entwicklungsprozess einzugreifen. Wird jedoch auch im eigenen Hause entwickelt, lohnt sich eine Aufgabenteilung: Die Entwickler formulieren schriftlich, welche Abfragen sie brauchen, d.h., welche Daten zurückgegeben werden sollen. Die Datenbanktruppe formuliert entsprechende SQL-Abfragen und stellt für diese, wenn möglich, Views zur Verfügung.
224
Datenbankobjekte
In der Praxis stößt man dabei relativ schnell auf das Problem, dass die meisten Abfragen Bindevariablen beinhalten, Views aber nicht parametriert werden können. Beispielsweise kann folgende Abfrage zur Umsatzbestimmung in einem gegebenen Zeitraum nicht ohne weiteres als View formuliert werden: SQL> SELECT FROM WHERE AND
SUM(ap.anzahl * ap.einzelpreis) AS umsatz auftraege a, aufpositionen ap a.aufnr = ap.aufnr a.aufdatum BETWEEN :b1 AND :b2;
In einigen Fällen lässt sich dieses Problem wie folgt lösen: Vor der eigentlichen Abfrage werden die Parameter in einer temporären Tabelle abgelegt. In der ViewDefinition werden die Bindevariablen durch Unterabfragen auf die temporäre Tabelle ersetzt. Die resultierenden SQL-Kommandos sehen zwar deutlich länglicher aus; da es sich um nichtkorrelierte Unterabfragen handelt, ist die Verarbeitung aber sehr einfach. SQL> CREATE GLOBAL TEMPORARY TABLE param_table ( vname VARCHAR2(20) -- Generische ,param VARCHAR2(20) -- Parametertabelle, ,value_vc VARCHAR2(200) -- wird ,value_num NUMBER -- einmalig ,value_date DATE -- angelegt ) ON COMMIT DELETE ROWS; SQL> CREATE VIEW umsatz_zahlen AS SELECT SUM(ap.anzahl * ap.einzelpreis) AS umsatz FROM auftraege a, aufpositionen ap WHERE a.aufnr = ap.aufnr AND a.aufdatum BETWEEN ( SELECT value_date FROM param_table WHERE vname='ums' AND param='b1') AND ( SELECT value_date FROM param_table WHERE vname='ums' AND param='b2'); SQL> INSERT VALUES SQL> INSERT VALUES
INTO param_table (vname, param, value_date) ('ums', 'b1', sysdate-20); INTO param_table (vname, param, value_date) ('ums', 'b2', sysdate);
SQL> SELECT * from umsatz_zahlen; Listing 5.26: Verknüpfung von View und temporärer Tabelle
Die Parametertabelle kann selbstverständlich für alle Abfragen gemeinsam verwendet werden. Allerdings funktioniert dieser Trick nicht, wenn für eine effiziente Abfragebearbeitung Histogramm-Informationen auf der Spalte aufdatum benötigt werden. Häufig ist es für Benutzer, die Leserechte auf anderen Schemata haben, bequem, eine View zum Lesen der Daten zu definieren. Dabei tritt immer wieder folgende auf den ersten Blick widersprüchliche Situation auf:
Views
225
SQL> CREATE SELECT FROM CREATE VIEW
VIEW alle_kunden AS * appl.kunden; alle_kunden AS SELECT * FROM appl.kunden * FEHLER in Zeile 1: ORA-01031: Unzureichende Berechtigungen SQL> SELECT * FROM appl.kunden; KDNR -----1 2 3
ANRED ----Herr Herr Frau
VORNAME ----------Gerd Gerd Hildegard ...
NACHNAME ----------Müller Müller Dursch
GEBURTST -------03.07.50 15.11.71 22.08.66
Listing 5.27: Rechteproblem mit Views
Obwohl der Benutzer offensichtlich Leserecht auf die betreffende Tabelle hat, kann keine View definiert werden. Der Grund ist, dass das Recht nicht direkt, sondern über eine Rolle (indirektes Recht) an den Benutzer gegeben wurde. Für Abfragen oder DML-Operationen macht dies keinen Unterschied. Innerhalb von Schemaobjekten – also z.B. bei der Definition einer View, analog aber auch bei PL/SQL-Prozeduren oder Triggern – müssen alle benötigten Rechte als direkte Rechte vorhanden sein (der Hintergrund ist, dass Rollen pro Session aktiviert oder deaktiviert werden können, wodurch die View in Sessions ohne Rolle ungültig wäre). In diesem Fall lässt sich das Problem also wie folgt lösen: SQL> GRANT SELECT ON appl.kunden TO demo;
Views aus Security-Gründen Views bieten ein einfaches, allerdings auch beschränktes Sicherheitskonzept. Beispielsweise wird einem Benutzer nicht das Leserecht auf eine bestimmte Tabelle gegeben, sondern das Leserecht auf eine View, die nur diejenigen Sätze der Tabelle zurückliefert, die der Benutzer sehen darf. Der Benutzer sieht sozusagen nur »seinen« Teil der Tabelle. Beispielweise könnte ein Sachbearbeiter für alle Kunden mit Nachnamen von F bis N zuständig sein: SQL> CREATE VIEW kunden_fn AS SELECT * FROM kunden WHERE nachname BETWEEN 'F' AND 'N'; SQL> GRANT SELECT ON kunden_fn TO schwanke; Listing 5.28: View als Sicherheitskonzept
Sollen auch Änderungen auf der Tabelle erlaubt sein, genügt natürlich das reine SELECT-Recht nicht. Hier stehen unterschiedliche Techniken zur Verfügung. Im einfachsten Fall werden zusätzlich UPDATE-, INSERT- oder DELETE-Rechte auf die View vergeben. Dies erlaubt entsprechende DML-Operationen auf den durch die View freigegebenen Teil der Tabelle.
226
Datenbankobjekte
Problematisch ist dabei, dass durch UPDATE- oder DELETE-Kommandos Datensätze in den eigentlich nicht sichtbaren Teil der Tabelle verschoben bzw. eingefügt werden können. Um das zu verhindern, sollten betroffene Views immer mit der Klausel WITH CHECK OPTION angelegt sein. Benutzer mit entsprechenden Rechten auf Views können durch folgende Abfrage ermittelt werden: SQL> SELECT FROM WHERE AND
AND UNION SELECT FROM WHERE AND
AND GRANTEE ---------SCHWANKE SCHWANKE SCHWANKE
grantee, owner, table_name AS view_name, privilege dba_tab_privs p owner = 'APPL' EXISTS ( SELECT 1 FROM dba_views v WHERE v.owner = p.owner AND v.view_name = p.table_name) privilege <> 'SELECT' grantee, owner, table_name AS view_name, privilege dba_col_privs p owner = 'APPL' EXISTS ( SELECT 1 FROM dba_views v WHERE v.owner = p.owner AND v.view_name = p.table_name) privilege <> 'SELECT'; OWNER ---------APPL APPL APPL
VIEW_NAME ---------KUNDEN_FN KUNDEN_FN KUNDEN_FN
PRIVILEGE ---------DELETE INSERT UPDATE
Listing 5.29: Ermitteln von Rechten auf Views
In diesem Fall hätte der Benutzer schwanke DML-Rechte auf die View kunden_fn. Diese sollte daher mittels Check-Option geschützt sein. Die mit Check-Option angelegten Views sowie Read-only-Views werden wie folgt aufgelistet: SQL> SELECT FROM WHERE AND
table_name AS view_name -- alle Views dba_constraints owner = 'APPL' constraint_type IN ('V','O');
VIEW_NAME ---------KUNDEN_FN Listing 5.30: Auflistung von Views
Eine Alternative zur Vergabe von DML-Rechten auf Views ist der Aufbau einer Business-API, die alle Änderungsoperationen in PL/SQL-Aufrufen kapselt. Vorteilhaft ist, dass auch komplexere Plausibilitätsprüfungen eingebaut werden können. Über autonome Transaktionen ist auch ein Logging kritischer Änderungen möglich. Außerdem ist diese Lösung auch für Views möglich, die »non-updateable« sind, also aus technischen Gründen keine DML-Operationen zulassen. In diesem Fall sollten die Views mit der WITH READ ONLY-Klausel definiert werden. Die gesamte
Views
227
Rechtevergabe läuft dann über EXECUTE-Privilegien auf den PL/SQL-Objekten der Business-API. Die Vorteile der beiden Techniken (transparenter Zugriff über normale DML-Kommandos einerseits und flexiblere Sicherheitsmechanismen andererseits) können durch Verwendung so genannter INSTEAD OF-Trigger kombiniert werden. Dabei wird die PL/SQL-Logik in einen Trigger integriert, der die entsprechende Änderungsoperation auslöst. Beispiele für INSTEAD OF-Trigger finden Sie in Abschnitt 5.5.3. Die Views sollten in diesem Fall mit der Check-Option definiert sein (für den Fall, dass ein Trigger versehentlich gelöscht oder deaktiviert wird). Es werden ganz normal DML-Rechte auf die View vergeben. Die Möglichkeit, die sichtbaren Datenmenge durch Views einzuschränken, ist allerdings nicht allzu flexibel. Hat man es mit dynamischen Einschränkungskriterien zu tun, ist jedes Mal eine Neuerzeugung der View notwendig. Auch steigt die Anzahl der notwendigen Views mit der Anzahl der Benutzer rapide an. Der Administrations- und Pflegeaufwand wird entsprechend hoch. Leistungsfähigere und besser skalierbare Sicherheitslösungen bieten beispielsweise die Technologien Fine Grain Access (FGA) bzw. Virtual Private Database (VPD), die in Kapitel 9.8 beschrieben werden. Views zur Datenabstraktion Ein weiterer Grund für die Verwendung von Views ist die Absicherung von Anwendungen oder Tools vor Änderungen des darunter liegenden Datenmodells. Neben dem Security-Aspekt ist dies meist das zentrale Argument für die Integration von Views in eine Business-API. Oracle selbst hat diese Technik konsequent im Rahmen der Data-Dictionary- sowie der V$-Performance-Views eingesetzt. Diese Technik wird auch gerne in Projekten eingesetzt, wenn eine Anpassung oder Reorganisation des Datenmodells durchgeführt werden soll. Dabei wird in zwei Umgebungen parallel gearbeitet. In einer Entwicklungs- und Testumgebung wird die Software an das neue Datenmodell angepasst. Parallel wird auf dem Produktionssystem bereits schrittweise das Datenmodell angepasst und/oder reorganisiert. Über eine Business-API bestehend aus Views und INSTEAD OF-Triggern wird der produktiven Anwendung weiterhin das alte Datenmodell vorgegaukelt. Die eigentliche Umschaltung auf die neue Anwendung kann irgendwann einfach durch Einspielen des neuen Software-Release geschehen. Die Datenbank ist an dieser Stelle bereits vorbereitet. Views und Performance Der unsachgemäße Einsatz von Views kann auch Nachteile mit sich bringen. Insbesondere das Prinzip der Datenabstraktion wird manchmal falsch verstanden, was zu Architekturen führt, in denen über den Basistabellen mehrere Schichten von Views aufgetürmt sind.
228
Datenbankobjekte
Beliebt ist auch eine Argumentation über Wiederverwendung bereits vorhandenen Codes (Code in diesem Fall das SQL-Statement), die seitens der Programmentwicklung gebracht wird. Wird ein Bericht um einige Funktionen erweitert, nutzt man die vorhandenen Views (in denen ja häufig eine Menge Definitionsarbeit steckt) und verknüpft via Joins noch ein, zwei Tabellen oder andere Views dazu. Diese Methodik birgt aber einige Nachteile: Das Ausrechnen des Dateninhalts einer solchen View geschieht in den meisten Fällen sequenziell über mehrere Stufen. Dabei werden in jedem Schritt neue Spalten (aus anderen Tabellen) angeknüpft, ganze Tabellen werden über die SELECTKlausel wieder ausgeblendet, manchmal in einem weiteren Schritt wieder angeknüpft etc. Dies ist prinzipiell aufwändiger als eine View, die von vornherein auf den benötigten Basistabellen aufsetzt. Der Optimizer hat Probleme, solche aufeinander aufbauenden Views in gute Ausführungspläne zu übersetzen. Insbesondere das Verschmelzen von Views und die Weitergabe von Filterbedingungen an unten liegende Views funktioniert längst nicht allen Fällen. Das Resultat sind schlechte Ausführungspläne, die zudem unübersichtlich sind, was den Tuning-Aufwand erhöht. Das Tuning solcher Abfragen und Views mittels Optimizer-Hints ist ebenfalls kritisch. Erfahrungsgemäß ist das Ergebnis solcher Maßnahmen sehr empfindlich gegenüber Änderungen in den Datenvolumen sowie Upgrades auf eine neue Oracle-Version (die interne Arbeitsweise des Optimizers kann sich mit jedem Release ändern). Ein häufiges Nachpflegen der eingebauten Hints wird notwendig. Es sollte daher unbedingt angestrebt werden, nur eine einzige View-Schicht über den Basistabellen zu haben. Wiederverwendung von Code ist zwar im Programmierumfeld eine gute Technik, für SQL-Abfragen im beschriebenen Sinne aber ungeeignet. Auch bei einfachen Views wird man aber nicht immer um Tuning-Maßnahmen herumkommen. Ist der Einbau von Optimizer-Hints geplant, sollten diese aber nicht innerhalb der SELECT-Anweisung der View-Definition untergebracht werden, da man dadurch Abfragen negativ beeinflussen könnte, die diese View ebenfalls verwenden, aber andere WHERE-Klauseln haben. Stattdessen ist hier die Benutzung so genannter globaler Hints anzuraten (für Beispiele siehe Kapitel 11.4). View-Definitionen in Skripten An dieser Stelle sollen noch einige Tipps zum Scripting für Views gegeben werden: Bei einfachen Views ist es bequem, in die SELECT-Liste einfach den * zu schreiben, um alle Spalten der darunter liegenden Tabelle(n) zu übernehmen. Der * wird aber zur Erzeugungszeit der View in eine konkrete Spaltenliste expandiert. Werden die Basistabellen oder Views später um neue Spalten erweitert, werden diese nicht in die darüber liegende View propagiert. Auch ein Rekompilieren der View hilft hier nicht. Sollen die neuen Spalten mit aufgenommen werden, muss die View neu erzeugt werden: CREATE OR REPLACE VIEW ... AS SELECT * ...
Views
229
Die Verwendung der FORCE-Klausel (CREATE FORCE VIEW ...) sorgt für eine höhere Robustheit in Skripten, da ansonsten die Erzeugung der View fehlschlägt, wenn die darunter liegenden Tabellen/Views noch nicht vorhanden sind. Mit der FORCE-Option wird die View erzeugt und ist ggf. noch ungültig. Wenn auf einer Basistabelle ein funktionsbasierter Index neu erzeugt wurde, sollten Views, die direkt oder indirekt auf dieser Tabelle basieren, neu kompiliert werden (ALTER VIEW ... COMPILE). Ein entsprechendes Compile-Skript sollte zur Sicherheit nach den Indexdefinitionen aufgerufen werden.
5.5.2 Materialized Views Dem Vorteil herkömmlicher Views, keinen Speicherplatz zu verbrauchen, steht der Nachteil gegenüber, dass der Inhalt erst einmal berechnet werden muss, was natürlich Ressourcen kostet. Greifen viele Benutzer auf dieselbe View zu, werden diese Berechnungen immer wieder durchgeführt. Insbesondere in Data-Warehouse Umgebungen hat man es meist mit großen Mengen an Rohdaten zu tun, die für Reporting-Zwecke eingeschränkt und verdichtet werden. Hier ist man oft bereit, Speicherplatz zur Verfügung zu stellen, um das Ergebnis einer SQL-Abfrage oder View physikalisch abzuspeichern. Bei der Abfrage einer solchen Materialized View wird der Inhalt nicht »on –the fly« berechnet, sondern einfach aus dem zugehörigen Segment gelesen. Materialized Views sind echte Segmente wie Tabellen auch. Ihre Dateninhalte sind zwar redundant. Im Gegensatz zu einer manuell erstellten Summationstabelle, deren Konsistenz und Aktualität vom Benutzer überwacht und gepflegt werden müssen, ist diese Redundanz aber der Datenbank bekannt und wird automatisch kontrolliert sowie ggf. zur inkrementellen Pflege des View-Inhalts genutzt. Grundsätzlich kann jede View auch materialisiert werden. In der Praxis ist vor allem interessant, wie die Pflege der Materialized Views möglichst ressourcenschonend gestaltet werden kann. Dabei sind zwei grundlegende Fragen zu beantworten: Die fachliche Frage nach den Anforderungen an die Datenaktualität muss gestellt werden. Die Antwort darauf bestimmt das Intervall, in dem eine Aktualisierung (Refresh) der Materialized Views durchgeführt werden muss. Auf technischer Ebene ist zu klären, ob die durch die View bereitgestellten Daten inkrementell aktualisiert werden können. Mit der Version Oracle 10g wird für die technische Realisierung einer Materialized View ein Expertensystem – der so genannte MView-Advisor – mitgeliefert. Durch die Query-Rewrite-Funktionalität (Klausel ENABLE QUERY REWRITE) wird die Existenz einer Materialized View für die Anwendung transparent. SQL-Abfragen brauchen nicht angepasst zu werden, stattdessen prüft der Optimizer, ob zur Beantwortung einer Abfrage eine Materialized View herangezogen werden kann. Details und Beispiele zur Definition und Benutzung von Materialized Views sowie des MView-Advisors finden Sie in Kapitel 15.2.5.
230
Datenbankobjekte
5.5.3 Object-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 objektrelationalen 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 Objekttypen person und telnummern, 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 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 telefone (pid NUMBER(5,0), nr VARCHAR2(20), CONSTRAINT telefone_ref_personen FOREIGN KEY (pid) REFERENCES personen, CONSTRAINT telefone_pk PRIMARY KEY (nr) ) / Listing 5.31: „Normale“ Tabellen als Basis für Objekt-Views
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 OR REPLACE TYPE telnummern_t AS VARRAY(10) OF VARCHAR2(20) / CREATE OR REPLACE TYPE person_t AS OBJECT ( id NUMBER(5,0), vorname VARCHAR2(30), nachname VARCHAR2(30), telnummern telnummern_t) / CREATE VIEW person_v OF person_t WITH OBJECT IDENTIFIER (id) AS
Views
231
SELECT pid, vorname, name, CAST( MULTISET( SELECT nr FROM telefone t WHERE t.pid = p.pid) AS telnummern_t) FROM personen p / Listing 5.32: Erstellen 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 eingebaut 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 referenzielle Integrität nicht automatisch erzeugt werden können. 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 statt 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.nachname, :NEW.vorname); FOR v_loop IN 1..:NEW.telnummern.COUNT LOOP INSERT INTO telefone VALUES (:NEW.id, :NEW.telnummern(v_loop)); END LOOP; END; / Listing 5.33: Instead-of-Trigger
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 zugrunde liegenden flachen Tabellen mit Primär- und Fremdschlüsseln versehen sind, wird automatisch die logische Konsistenz der Daten gewährleistet.
232
Datenbankobjekte
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 möglich, INSERT-Befehle abzufangen und mit den gelieferten Daten etwas ganz anderes zu tun, sie z.B. an eine Advanced Queue übergeben.
5.6
PL/SQL-Objekte
Eine Anwendung besteht nie ausschließlich aus SQL-Skripten, sondern ist in einer so genannten Host-Sprache geschrieben, z.B. C++, Delphi, Java etc. SQL-Kommandos werden an entsprechenden Stellen in den Quellcode eingebunden, entweder durch Prozeduraufrufe oder – komfortabler – als Klartext-Befehle, die von einem Precompiler in Prozeduraufrufe der Host-Sprache übersetzt werden. PL/SQL ist so eine Host-Sprache. Von anderen unterscheidet sie sich im Wesentlichen durch zwei Merkmale: Sowohl der Precompiler als auch die Laufzeitumgebung für PL/SQL sind fester Bestandteil der Oracle Server-Software und in den Oracle-Kernel integriert. Daraus folgt, dass bei der Ausführung eines SQL-Kommandos aus einer Prozedur heraus kein Overhead durch Netzwerk- oder Interprozess-Kommunikation auftritt. Außerdem ist das Zusammenspiel von SQL und PL/SQL auf Codierungsebene verhältnismäßig gut und unkompliziert. Dies reicht so weit, dass die Grenzen zwischen SQL-Engine und PL/SQL-Engine bisweilen regelrecht verwischen. Insbesondere die Datentypen und eingebauten Funktionen beider Umgebungen sind nahezu deckungsgleich. Intern wird aber wie bei jeder anderen Host-Sprache auch konvertiert. Jede Ausführung eines SQL-Kommandos in einer PL/SQLProzedur führt zu einem Kontext-Switch, der CPU-Overhead erzeugt. PL/SQL ist sehr datenbanknah und verfügt über keine grafische Ausgabe und nur sehr begrenzt über die Möglichkeit der Textausgabe. In der Praxis findet daher häufig eine Aufgabenteilung dergestalt statt, dass eine andere Sprache als PL/SQL als Host-Sprache für die Anwendung verwendet wird, aus der heraus SQL-Kommandos ausgeführt und/oder PL/SQL-Konstrukte aufgerufen werden. Auf diese Weise wird die eigentliche Datenbanklogik in PL/SQL formuliert, während der Rest des Quellcodes in einer Drittsprache vorliegt.
PL/SQL-Objekte
233
PL/SQL ist normalerweise eine interpretierte Sprache, d.h., der Quellcode wird nicht in Maschinenbefehle übersetzt, sondern in eine Zwischenschicht – den so genannten M-Code –, der erst zur Laufzeit von der PL/SQL-Engine interpretiert und ausgeführt wird. Die dadurch erreichte Plattformunabhängigkeit des Objektcodes wird durch einen Performance-Nachteil gegenüber kompilierten Sprachen erkauft. Insbesondere bei CPU-intensiven Routinen lohnt es sich daher, Native Compilation oder sogar die Realisierung in einer anderen Programmiersprache in Betracht zu ziehen (siehe unten, Abschnitt Laufzeit-Optimierung). Die Datentypen von PL/SQL entsprechen weitgehend den SQL-Datentypen. Es existieren dennoch einige Abweichungen. Die wichtigste ist, dass der Datentyp VARCHAR2 in PL/SQL bis zu 32767 Zeichen aufnimmt, was bei entsprechenden Funktionsaufrufen in SQL-Kommandos zu Problemen führen kann. Auch der PL/SQLeigene Datentyp BOOLEAN kann leider nicht aus der SQL-Engine heraus angesprochen werden. Remote-Aufrufe von PL/SQL-Routinen auf anderen Datenbanken sind möglich, soweit es einen Datenbank-Link zu der betreffenden Datenbank gibt. Die Ausführung geschieht auf der Remote-Datenbank. Diese Möglichkeit kann natürlich auch ein Sicherheitsproblem darstellen. Auf produktiven Systemen sollte daher kein Benutzer-Account, der über einen Datenbank-Link erreichbar ist, Ausführungsrechte für PL/SQL-Objekte haben, die nicht zur Anwendung gehören. Einige der mitgelieferten PL/SQL-Packages sind unter Security-Aspekten ohnehin kritisch, da sie in einer Standarddatenbank von jedem Benutzer ausführbar sind. Dabei handelt es sich speziell um die Packages utl_file, utl_tcp, utl_http, utl_smtp, dbms_random, dbms_lob, dbms_sql, dbms_sys_sql, dbms_job, dbms_scheduler und owa_util. Der allgemeine Zugriff auf diese Packages sollte verhindert werden, z.B.: SQL> REVOKE EXECUTE ON sys.dbms_job FROM public;
Anschließend können Ausführungsrechte gezielt an einzelne Benutzer vergeben werden. Alle PL/SQL-Objekte können über die View dba_objects abgefragt werden (object_type IN ('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY')). Der Quelltext ist über dba_source verfügbar, die Parameterlisten über all_arguments. Komfortabler ist aber die Verwendung geeigneter Tools, z.B. TOAD von Quest, Hora von Keeptool oder im Oracle Enterprise Manager. Genau wie bei Views gilt auch für die Erstellung von PL/SQL-Objekten und Triggern, dass alle benötigten Rechte als direkte Rechte vorhanden sein müssen, die indirekte Erlaubnis über eine Rolle genügt nicht. Debugging Für jedes PL/SQL-Objekt können im M-Code zusätzliche Informationen zu Debugging-Zwecken abgelegt werden (DEBUG-Klausel des ALTER PROCEDURE-Kommandos). Für das eigentliche Debugging sind Ausführungsrechte auf dem Package dbms_debug notwendig. Da dieses normalerweise für alle Benutzer ausführbar ist, stellt es kein Problem dar.
234
Datenbankobjekte
Neu in Oracle 10g ist, dass außerdem das Systemprivileg DEBUG CONNECT SESSION benötigt wird. Für PL/SQL-Objekte in anderen Schemas kommen noch die Systemprivilegien EXECUTE ANY PROCEDURE und DEBUG ANY PROCEDURE hinzu. Debugging ist prinzipiell nicht für solche Objekte möglich, die mit Native Compilation erzeugt, also in Maschinencode übersetzt wurden. Der Kompilierungsmodus sowie das Vorhandensein von Debug-Informationen können aus dem Data Dictionary abgefragt werden: SQL> SELECT name, type, plsql_code_type, plsql_debug FROM dba_plsql_object_settings WHERE owner = 'DEMO'; NAME ---------DEMOPKG DEMOPKG
TYPE --------------PACKAGE PACKAGE BODY
PLSQL_CODE_TYPE --------------INTERPRETED INTERPRETED
PLSQL_DEBUG ----------FALSE FALSE
Listing 5.34: Kompilierungsmodus und Debug überprüfen
Debugging ist für alle Prozeduren und Funktionen (standalone oder als Bestandteil eines Packages) sowie für Trigger möglich. Methoden innerhalb von Objekttypen (erzeugt über den SQL-Befehl CREATE TYPE ...) sind nicht Debug-fähig. Dasselbe gilt für anonyme PL/SQL-Blöcke (DECLARE ... BEGIN ... END), hier muss ggf. eine separate Prozedur mit dem betreffenden Block als Inhalt für das Debugging definiert werden. Das Debugging sollte nach Möglichkeit nicht manuell, sondern tool-gestützt (Quest TOAD, Keeptool Hora, PL/SQL-Developer etc.) durchgeführt werden. Wichtig zu wissen ist, dass das Debugging eine zeitlupenartige Ausführung des entsprechenden PL/SQL-Objekts darstellt. Während eines Debugging-Laufs sind daher das betreffende Objekt sowie alle davon direkt oder indirekt benutzten PL/SQL-Objekte, Tabellen, Views etc. in den Oracle Library-Cache geladen und dort gesperrt. Daher sind »hängende« Debugging-Sessions in einer Entwicklungs- oder Testumgebung ein sehr lästiges Problem. Kompilierungsversuche durch einen Benutzer oder in einer anderen Session führen dazu, dass diese Session ebenfalls hängt. Häufig ist der schnellste Weg, diese Situation aufzulösen, mit Administratorrechten die Debug-Session zu killen (ALTER SYSTEM KILL SESSION ...). In solchen Umgebungen sollte unbedingt die Disziplin angemahnt werden, Debug-Sessions stets sauber zu beenden (jedes Tool hat dafür einfach einen entsprechenden Button, man muss ihn eben nur benutzen ...). Wrapping Der Quellcode eines PL/SQL-Objekts kann geschützt werden, indem man das Objekt verhüllt, neudeutsch wrappt. Dies bedeutet, dass der eigentliche Quellcode durch den M-Code ersetzt wird. Auf diese Weise kann eine Anwendung ausgeliefert werden, ohne Einblick in den Quellcode zu gewähren. Auch über die oben genannte View dba_source ist der Quellcode nicht mehr einsehbar. Die meisten mitgelieferten Oracle-Packages (dbms_*) liegen ausschließlich als M-Code vor.
PL/SQL-Objekte
235
Es ist nicht möglich, ein PL/SQL-Objekt in die Datenbank einzuspielen und nachträglich ein Wrapping durchzuführen. Stattdessen findet das Wrapping der Objektdefinition innerhalb eines Skripts statt, das anschließend eingespielt wird. Im Unterverzeichnis bin innerhalb des Oracle-Homes befindet sich das Tool wrap (wrap.exe unter MS-Windows), das die eigentliche Konvertierung leistet, z.B.: $ wrap iname=create_procs.sql oname=create_procs_wrapped.sql SQL> @create_procs_wrapped.sql Listing 5.35: PL/SQL-Wrapper
Aus dem Originalskript create_procs.sql wird ein neues Skript erzeugt. Sämtliche CREATE-Kommandos für Funktionen, Prozeduren, Packages, Package Bodies, Typen sowie Typ-Bodies werden in den M-Code übersetzt, alle anderen Kommandos bleiben unverändert. Alleine das Skript create_procs_wrapped.sql wird anschließend eingespielt. Da eine Wiederherstellung des Quellcodes aus dem M-Code nicht möglich ist, muss für Updates stets das Originalskript gepflegt und anschließend für die Auslieferung erneut verhüllt werden. Einige wichtige Hinweise zum Wrapping sollen an dieser Stelle noch gegeben werden: In den PL/SQL-Code eingebettete SQL-Kommandos können trotz Wrapping durch SQL-Tracing der Anwendung (siehe Kapitel 11.2) oder durch Inspektion der View v$sql sichtbar gemacht werden. Das Exportieren und Importieren von verhüllten PL/SQL-Objekten mittels Data Pump oder konventionellem Export/Import (siehe Kapitel 10.6) ist problemlos möglich. Die Objekte bleiben dabei verhüllt. Der Quellcode von Triggern kann nicht verhüllt werden. Stattdessen muss eine eigene Prozedur für den Trigger-Quellcode geschrieben und das Wrapping danach durchgeführt werden. Der Trigger ruft anschließend einfach diese Prozedur auf. Passwörter oder sonstige Werte, die als Konstanten oder als Default-Werte für Variablen im Quellcode eingebaut sind, werden durch das Wrapping nicht verschlüsselt, sondern tauchen auch im verhüllten Code im Klartext auf! In solchen Fällen sollte das Passwort stattdessen verschlüsselt in einer entsprechend geschützten Datenbanktabelle oder Betriebssystemdatei gespeichert werden. Über die Packages dbms_obfuscation_toolkit oder dbms_crypto (Letzteres sollte ab der Datenbankversion 10g benutzt werden) stehen verschiedene Ver- und Entschlüsselungsalgorithmen zur Verfügung, u.a. DES, 3DES, AES, MD5 und SHA-1. Die Datenbank, in die ein verhülltes Objekt eingespielt wird, muss von derselben oder einer neueren Version sein als die Datenbank, in der das Wrapping stattfand. Das Einspielen in eine ältere Datenbankversion ist nicht möglich.
236
Datenbankobjekte
Tabellenfunktionen Oracle bietet mit den so genannten Tabellenfunktionen die Möglichkeit, benutzerdefinierte PL/SQL-Funktionen als Datenquellen in SQL-Abfragen einzusetzen. Dies ist auch für administrative Zwecke interessant, da auf diese Weise zum Beispiel Monitoring-Skripte zentral in der Datenbank abgespeichert und gepflegt werden können. Ein entsprechender Report kann dann jederzeit von jedem Client aus abgegriffen werden, ohne dass erst das richtige Skript gesucht werden muss. Der Report wird zeilenweise von einer PL/SQL-Funktion erzeugt. Für eine detaillierte Beschreibung der Benutzung von Tabellenfunktionen wird auf die Oracle-Dokumentation Oracle 10g PL/SQL User’s Guide and Reference sowie Data Cartridge Developer’s Guide verwiesen. Hier soll lediglich ein einfaches Beispiel gegeben werden. SQL> CREATE TYPE report_typ AS TABLE OF VARCHAR2(200); / SQL> CREATE OR REPLACE FUNCTION datenbank_report RETURN report_typ PIPELINED AS CURSOR c1 IS SELECT owner, table_name FROM dba_tables WHERE last_analyzed IS NULL AND owner NOT IN ('SYS','SYSTEM') ORDER BY owner, table_name; BEGIN PIPE ROW ('************************************'); PIPE ROW ('Datenbank-Report ' || TO_CHAR(SYSDATE,'DD.MM.YYYY HH24:MI:SS')); PIPE ROW ('************************************'); PIPE ROW (''); PIPE ROW ('Tabellen ohne Optimizer-Statistiken:'); PIPE ROW ('------------------------------------'); FOR t IN c1 LOOP PIPE ROW (t.owner || '.' || t.table_name); END LOOP; -- weitere Tests PIPE ROW (''); PIPE ROW ('Report-Ende'); RETURN; END; / SQL> SET PAGESIZE 0 SQL> SET LINESIZE 120 SQL> SELECT * FROM TABLE(datenbank_report);
PL/SQL-Objekte
237
************************************ Datenbank-Report 04.03.2005 21:44:36 ************************************ Tabellen ohne Optimizer-Statistiken: -----------------------------------DEMO.AUFPOSITIONEN DEMO.AUFTRAEGE DEMO.KUNDEN DEMO.PRODUKTE Report-Ende 12 Zeilen ausgewählt. Listing 5.36: Table Function
Überwachung kritischer DML-Operationen mit Triggern Der Zugriff auf sensible Daten einer Anwendung wird in den meisten Fällen über Rechtevergaben genau geregelt sein. Änderungen solcher Daten mittels DML-Operationen können außerdem mit Hilfe von Triggern protokolliert werden. Führen solche Änderungen allerdings zu einer Constraint-Verletzung, wird die SQL-Operation und mit ihr die Protokollierung durch den Trigger zurückgerollt. Unter Security-Gesichtspunkten ist es manchmal interessant, gerade diese zurückgewiesenen Änderungen zu protokollieren. Die Lösung dafür liegt in der Verwendung so genannter autonomer Trigger. Dabei wird der Inhalt des Triggers, also die Protokollierung, in einer eigenständigen Transaktion ausgeführt und unabhängig vom Ausgang der auslösenden DML-Operation festgeschrieben. Ein normaler Trigger kann einfach in einen autonomen Trigger verwandelt werden, indem im Deklarationsteil das Compiler-Pragma AUTONOMOUS_TRANSACTION eingefügt wird. Für die Aufträge-Tabelle kann das z.B. wie folgt aussehen: SQL> CREATE OR REPLACE TRIGGER auftraege_protokoll AFTER INSERT ON auftraege FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; -- dies ist entscheidend BEGIN INSERT INTO auftraege_log (datum, benutzer, aufnr) VALUES (SYSDATE, USER, :new.aufnr); COMMIT; END; / Listing 5.37: Autonome Transaktion
238
Datenbankobjekte
Problemfälle Bei allen Annehmlichkeiten und Möglichkeiten, welche die Benutzung von PL/SQL mit sich bringt, soll hier auch auf Konstellationen hingewiesen werden, auf welche die Autoren in der Praxis gestoßen sind und die problematisch sein können: In PL/SQL können sehr einfach Hauptspeichertabellen definiert und verwaltet werden (so genannte PL/SQL-Tabellen, Index-by-Tabellen oder Nested-Tabellen). Theoretisch können diese Konstrukte bis zu 2^31, also ca. 2 Mrd. Zeilen enthalten. Dennoch sollte mit diesen Tabellen nicht verschwenderisch umgegangen werden. Der Inhalt wird nämlich komplett im Hauptspeicher gehalten. Es findet keine Auslagerung in Temporär-Segmente statt. Auch Begrenzungen des Hauptspeichers über Serverparameter wie sort_area_size oder pga_aggregate_target spielen in diesem Zusammenhang keine Rolle! Bei vielen parallelen Session multipliziert sich der Gesamtspeicherbedarf entsprechend. Ist nicht genügend Hauptspeicher vorhanden, tritt auf Betriebssystemebene irgendwann massives Paging auf, was natürlich erhebliche Performance-Nachteile mit sich bringt (datenbankseitig manifestiert sich dies in deutlichem Ansteigen der CPU-Zeiten, betriebssystemseitig schafft bei Unix das vmstat-Kommando Klarheit). Im Extremfall hängt sich der Datenbankserver komplett auf. Ist das Kind schon in den Brunnen gefallen, kann durch HauptspeicherAusbau oder Lastverteilung über eine RAC-Datenbank Entlastung geschaffen werden. Der Einsatz von benutzerdefinierten Funktionen in Abfragen anstelle von mengenorientierten Operationen wie Joins und Aggregationen erscheint häufig verlockend, sollte aber nur in Ausnahmefällen wirklich realisiert werden, da er entscheidende Nachteile mit sich bringt. Dies soll an den beiden folgenden Abfragen verdeutlicht werden, die scheinbar dasselbe tun: SQL> CREATE FUNCTION anz_auftraege (i_kdnr IN NUMBER) RETURN NUMBER AS ergebnis NUMBER; BEGIN SELECT COUNT(*) INTO ergebnis FROM auftraege WHERE kdnr = i_kdnr; RETURN ergebnis; END; / SQL> SELECT k.kdnr, COUNT(a.aufnr) AS anz_auftraege FROM kunden k, auftraege a WHERE k.kdnr = a.kdnr (+) GROUP BY k.kdnr; SQL> SELECT kdnr, anz_auftraege(kdnr) AS anz_auftraege FROM kunden; Listing 5.38: Vergleich von Funktion und SQL-Befehl
PL/SQL-Objekte
239
Beide Abfragen ermitteln die Anzahl der Aufträge jedes Kunden. Die zweite Abfrage erscheint übersichtlicher und einfacher lesbar, da auch kein Outer-Join benötigt wird, um Kunden ohne Aufträge zu erfassen. Die Funktion anz_auftraege kann auch in anderen Abfragen wiederverwendet werden, der Join dagegen müsste stets aufs Neue formuliert werden. Leider handelt es sich aber tatsächlich nur um codierungstechnische Vorteile, denen zwei gewichtige Nachteile bei der Ausführung gegenüberstehen: Die Performance der zweiten Abfrage ist fast immer schlechter, da auf prozeduralem Wege so etwas wie ein Nested-Loop-Join erzwungen wird, wohingegen die erste Abfrage von alternativen Join-Methoden des Optimizers wie MergeJoins oder Hash-Joins profitieren kann. Auch alternative Join-Reihenfolgen der beteiligten Tabellen sind in der prozeduralen Variante offenbar nicht möglich. Außerdem müssen für jeden Kunden insgesamt vier so genannte Kontext-Switches zwischen SQL- und PL/SQL-Engine durchgeführt werden, die zusätzlichen CPU-Overhead erzeugen. Werden während der Laufzeit der Abfrage Aufträge geändert, storniert oder neu generiert, gewährleistet die Datenbank bekanntlich Lesekonsistenz durch Rückgriff auf die Undo-Segmente (siehe Kapitel 1.3.1). Weniger bekannt ist die Tatsache, dass bei der zweiten Abfrage keine (!) Lesekonsistenz besteht, da jede einzelne Abfrage der Aufträge-Tabelle ihren eigenen Konsistenz-Zeitpunkt hat. Die zurückgelieferten Auftragsinformationen müssen also weder mit den Kundeninformationen noch untereinander konsistent sein. Dies fällt beim Entwickeln und Testen nicht so schnell auf, da es erst bei gleichzeitigen DML-Operationen akut wird. Ist hier das Kind schon in den Brunnen gefallen, besteht der einzige Ausweg darin, vor der Abfrage über das Kommando SET TRANSACTION READ ONLY einen einzigen Konsistenz-Zeitpunkt für die gesamte Transaktion (die nur aus einer oder aus mehreren Abfragen besteht) festzulegen. Vor der nächsten DML-Operation muss dann ein COMMIT stehen, um den Read-only-Modus wieder zu verlassen. Ohne Eingriffe in den Quellcode ist hier also nichts zu retten. Laufzeit-Optimierung von PL/SQL-Code Vor dem Einsatz von Techniken zur Laufzeit-Verbesserung von PL/SQL-Code sollte eine Performance-Analyse stehen, welche die Frage klärt, wo eigentlich die ganze Laufzeit verbraucht wird: in den SQL-Kommandos oder in PL/SQL-Konstrukten wie Schleifen oder umfangreichen Hauptspeicheroperationen. Hierfür ist der so genannte PL/SQL-Profiler bestens geeignet. Über das mitgelieferte Package dbms_profiler werden Laufzeitstatistiken für die Ausführung von PL/SQL-Objekten gesammelt, die beschreiben, wie viel Zeit in jeder durchlaufenen Quellcodezeile verbracht wird. Einige Anmerkungen zu der Benutzung des Profilers: Um die Messergebnisse nicht zu verfälschen, werden während der Ausführung die Laufzeitstatistiken im Hauptspeicher gepflegt. Erst nach der Ausführung werden die endgültigen Werte in Tabellen geschrieben. Dadurch sind diese Werte tatsächlich sehr verlässlich.
240
Datenbankobjekte
Die Auswertung dieser Tabellen (plsql_profiler_data, plsql_profiler_units und plsql_profiler_runs) geschieht vorzugsweise über ein Tool, um übersichtliche Darstellungen wie z.B. Balken- oder Kuchendiagramme nutzen zu können. Quest TOAD oder der PL/SQL-Developer bieten entsprechende Schnittstellen. Die genannten Tabellen müssen zuvor über das Skript proftab.sql im Verzeichnis $ORACLE_HOME/rdbms/admin erstellt werden. Sie können wahlweise in mehreren Schemata oder in einem zentralen Schema erstellt werden. In letzterem Fall wird über entsprechende Synonyme und Rechtevergaben der Zugriff mehrerer Benutzer geregelt. In den Datenbankversionen bis einschließlich Oracle9i muss außerdem das Package dbms_profiler manuell im Schema SYS erstellt werden (Skript profload.sql). Der erste Aufruf eines PL/SQL-Objekts liefert meist unbrauchbare Laufzeitwerte, da rekursive (interne) SQL-Kommandos die Messungen verfälschen. Dieser Aufruf sollte daher nicht ausgewertet werden. Stellt sich heraus, dass SQL-Kommandos (Abfragen, Cursor-Durchläufe sowie DMLOperationen) den Flaschenhals bilden, sollte mit der Optimierung zunächst dort begonnen werden. SQL-Tracing ist in diesem Fall ein guter Start, um weitere Details und Ansatzpunkte für Tuning-Maßnahmen zu erhalten (siehe Kapitel 11.2). Erst wenn echte PL/SQL-Kommandos den Großteil der Zeit beanspruchen, sollte PL/SQL-Optimierung in Betracht gezogen werden. Betriebssystemseitig bedeutet dies meistens, dass bei wachsender Last zuerst die CPU vor dem I/O-System an ihre Grenzen stößt. Abgesehen von Änderungen am Quellcode gibt es zwei Möglichkeiten, die Performance von PL/SQL-Code zu verbessern: Generierung von optimiertem M-Code: Der PL/SQL-Compiler wird über den Serverparameter plsql_optimize_level angewiesen, bestimmte Techniken anzuwenden. Folgende Werte sind möglich: – 0: entspricht der normalen Kompilierung wie in der Datenbankversion 9i – 1: beinhaltet kleinere Optimierungen, z.B. werden unnötige Berechnungen oder Ausführungen weggelassen – 2: aktiviert weitergehende Techniken, insbesondere »Code Reordering«, also Anpassungen der Reihenfolge der einzelnen Anweisungen. Entgegen der Dokumentation ist die Default-Einstellung dieses Serverparameters nicht 0, sondern 2. Standardmäßig findet also bereits eine Optimierung statt. Kompilieren des M-Codes in Maschinencode (»Native Compilation«): Anstatt des interpretierten M-Codes wird direkt ausführbarer Maschinencode in Form von Shared Libraries (.dll-Dateien unter MS-Windows, .so-Dateien unter Unix) erzeugt. Voraussetzung hierfür ist das Vorhandensein eines von Oracle zertifizierten C-Compilers und Linkers auf dem Datenbankserver (diese Komponenten werden nicht von Oracle ausgeliefert, sondern müssen eigenständig lizenziert und installiert werden). Eine Übersicht lizenzierter Compiler findet sich im Oracle 10g Installation Guide für die jeweilige Plattform sowie auf der Oracle Metalink-Seite. Unter Oracle9i führte die sehr flexible Konfiguration für Native Compilation zu erheblichen Security-Problemen, in Oracle 10g wurde sie daher stark überarbeitet und vereinfacht:
PL/SQL-Objekte
241
Der Serverparameter plsql_code_type = NATIVE | INTERPRETED regelt, ob explizite Kompilierungen mittels CREATE ... oder ALTER ... COMPILE Maschinencode oder MCode erzeugen. Default-Einstellung ist INTERPRETED. Der Parameter kann auch auf Session-Ebene gesetzt werden. Zusammen mit dem Parameter plsql_debug ersetzt er den aus Oracle9i bekannten Parameter plsql_compiler_flags. Letzterer existiert aus Kompatibilitätsgründen noch, sollte aber nicht mehr verwendet werden. Der Kompilierungsmodus jedes PL/SQL-Objekts wird im Data Dictionary abgespeichert (Spalte PLSQL_CODE_TYPE der View dba_plsql_object_settings) und für automatische Neukompilierungen durch Oracle herangezogen (z.B. nach der Änderung einer vom Objekt referenzierten Tabelle). Auch durch SQL-Kommandos der Form ALTER ... COMPILE REUSE SETTINGS kann der aktuelle Kompilierungsmodus beibehalten werden. Achtung: Bei einem Export via Data Pump oder konventionellem Export (siehe Kapitel 10.6) gehen die Informationen über Kompilierungsmodi verloren. Über den Serverparameter plsql_native_library_dir wird das Zielverzeichnis für die Shared Libraries angegeben. Die Shared Libraries werden aber auch im Data Dictionary gespeichert. Ein versehentliches Löschen auf OS-Ebene führt somit nicht mehr wie bei Oracle9i zu einem Laufzeitfehler, sondern die Dateien werden automatisch aus dem Data Dictionary in das Dateisystem zurückgeschrieben. Da die betreffende Tabelle (SYS.NCOMP_DLL$) im SYSTEM-Tablespace liegt, muss dieser ggf. vergrößert werden, bevor eine größere Menge von PL/SQL-Objekten kompiliert wird. Das Shared-Library-Verzeichnis sollte unter dem Verzeichnis angelegt werden, das auch die Datendateien des SYSTEM-Tablespace enthält, und ausschließlich für die Benutzer oracle und root schreibbar sein. Die Datei spnc_commands im Verzeichnis $ORACLE_HOME/plsql enthält den plattformspezifischen Aufruf des C-Compilers bzw. Linkers. In den meisten Fällen braucht diese nicht angepasst zu werden, einzig der Pfad zum Compiler-Programm sollte vor der ersten Kompilierung verifiziert werden. Es versteht sich, dass aus Security-Gründen auch diese Datei höchstens für oracle und root schreibbar sein darf. Trigger-Verwaltung Trigger stellen ein sehr mächtiges Werkzeug dar, da sie komplexe Reaktionen ermöglichen (erst recht in der Form der oben beschriebenen autonomen Trigger). Sie bringen aber auch einen Overhead mit sich. In vielen Systemen treten regelmäßig Massenoperationen wie Batch-Läufe oder Ladeprozesse auf. Dabei sollte überprüft werden, ob wirklich alle Trigger aktiv sein müssen. Häufig lässt sich eine deutliche Beschleunigung des Prozesses erzielen, wenn einige oder alle Trigger vor der Massenoperation deaktiviert und anschließend reaktiviert werden. Entsprechende Befehle dafür sind: SQL> ALTER TRIGGER DISABLE | ENABLE; SQL> ALTER TABLE DISABLE | ENABLE ALL TRIGGERS;
242
Datenbankobjekte
Bei Ladeoperationen über den direkten Pfad mit dem Werkzeug SQL*Loader werden Insert-Trigger der betreffenden Tabellen für die Dauer des Ladelaufs automatisch deaktiviert. In Replikationsumgebungen müssen ebenfalls Vorkehrungen getroffen werden, damit keine Doppel-Ausführungen der Trigger-Aktionen auf der Zieldatenbank auftreten: Bei einer Master-Slave-Replikation werden einfach alle Trigger der Slave-Datenbank deaktiviert. Bei einer Multi-Master-Replikation müssen auf allen Datenbanken die Trigger um WHEN-Klauseln ergänzt werden, die bewirken, dass der Trigger nur feuert, wenn die Änderung nicht durch den Replikationsmechanismus eingebracht wurde, z.B. durch eine Ergänzung der WHEN-Klausel um die Bedingung USER <> 'ReplUser'. Das Replikations-Tool Quest Shareplex bringt beispielsweise Skripte mit, die diese Anpassung automatisch durchführen. Die Views dba_triggers und dba_trigger_cols bieten Informationen über Trigger.
5.7
Directory-Objekte für den Dateizugriff
Häufig ist es notwendig, aus der Datenbank heraus auf Dateien zuzugreifen, sei es lesend im Rahmen von Ladeoperationen, sei es schreibend, z.B. um Daten in einem bestimmten Format zu exportieren. Dafür gibt es mittlerweile eine Reihe von Möglichkeiten; die wichtigsten sind: Das mitgelieferte Package utl_file, das aus PL/SQL-Routinen heraus lesenden und/oder schreibenden Zugriff in beliebigen Ausgestaltungen erlaubt. Der Import und Export von Daten auf dem Datenbank-Server mittels Data Pump (siehe Abschnitt 10.6). Die Definition so genannter »externer Tabellen« (siehe Abschnitt 5.2.6), die lesenden Zugriff auf Data-Pump-Dump-Dateien sowie Dateien in einem SQL*Loader-kompatiblen Format ermöglichen und den Dateiinhalt als Tabelleninhalt präsentieren. Das mitgelieferte Package dbms_file_transfer (neu in der Version 10g), das Dateien über Datenbank-Links hinweg zwischen Datenbankservern kopieren kann (eine Art triviales FTP, wobei der Datenbank-Link als Tunnel verwendet wird). Mit der Version 10.1.0.3 funktioniert dies aber nur für Data-Pump-Dump-Dateien (siehe auch Abschnitt 10.6)! Der Zugriff über einen BFILE-Locator für Tabellenspalten vom Typ BFILE über die eingebaute SQL-Funktion BFILENAME. In allen Fällen geschieht der Zugriff auf das Dateisystem des Datenbankservers durch den Oracle-Serverprozess (nicht zu verwechseln mit einem clientseitigen Dateizugriff durch das Kommandozeilen-Tool SQL*Plus nach einem SPOOL-Kommando). Prinzipielle Voraussetzung ist daher, dass der Betriebssystembenutzer, unter dem der Serverprozess läuft (oracle auf Unix, Lokales System unter MS-Windows) entsprechende Zugriffsrechte hat. Unter Unix lässt sich dies ggf. durch Kommandos wie chown, chgrp und chmod erreichen.
Directory-Objekte für den Dateizugriff
243
Unter MS-Windows stößt man zusätzlich auf das Problem, dass das lokale Systemkonto, unter dem der gesamte Oracle-Prozess standardmäßig läuft, keinerlei Zugriffsrechte auf Netzwerkfreigaben hat. Der Zugriff auf Dateien über Freigaben (z.B. Z:\testdatei.txt oder als UNC-Pfad \\server\freigabe\testdatei.txt) scheitert daher regelmäßig. In diesem Fall müssen der Oracle-Dienst und der TNS-Listener als ein privilegierter Benutzer angemeldet werden. In Windows XP kann diese Anmeldeinformation unter Systemsteuerung Verwaltung Dienste eingestellt werden (siehe Ändern der Anmeldeinformationen für den Oracle-Dienst). Es kann ein beliebiger Benutzer eingetragen werden, der lesend und/oder schreibend auf die Netzwerkfreigabe zugreifen kann.
Abbildung 5.4: Ändern der Anmeldeinformationen für den Oracle-Dienst
Kann der Oracle-Serverprozess auf eine Datei prinzipiell zugreifen, sind als zweite Stufe die Zugriffsrechte der Datenbankbenutzer zu regeln. Bei einer neu aufgesetzten Datenbank hat zunächst kein Datenbankbenutzer Zugriffsrechte auf Dateien. So genannte Directory-Objekte repräsentieren einzelne Dateisystemverzeichnisse innerhalb der Datenbank und bilden sowohl bei der Angabe von Dateipfaden als auch bei der Zugriffskontrolle die Schnittstelle zwischen Dateisystem und Datenbankbenutzern. Lese- und Schreibrechte können also nicht pro Datei, sondern nur pauschal für alle Dateien eines Verzeichnisses gewährt werden. Das Erstellen oder Löschen eines Directory-Objekts hat keine Auswirkung auf die Existenz des betreffenden Dateisystemverzeichnisses, es handelt sich nur um einen Pointer.
244
Datenbankobjekte
Das Erstellen und Löschen von Directory-Objekten ist nur mit den Systemprivilegien CREATE | DROP ANY DIRECTORY möglich. Directory-Objekte sind streng genommen keine Schema-Objekte, da sie nicht zum Schema des erzeugenden Benutzers, sondern immer zum Schema SYS gehören. Ihre Namen müssen daher datenbankweit eindeutig sein. Benutzer mit mindestens einem der oben genannten Systemprivilegien haben pauschal Lese- und Schreibrechte auf alle Directory-Objekte. Einzelne Zugriffsrechte werden über die Objektprivilegien READ und WRITE zugeteilt, z.B.: SQL> CREATE DIRECTORY alertlog_dir AS 'C:\ORACLE\ADMIN\PS10\BDUMP'; SQL> GRANT READ ON DIRECTORY alertlog_dir TO schulung; SQL> GRANT READ, WRITE ON DIRECTORY alertlog_dir TO admin; Listing 5.39: Erstellen von Directories
Die Rechtevergabe bezieht sich stets nur auf das angegebene Verzeichnis, Unterverzeichnisse sind nicht inbegriffen. Beim Zugriff auf eine Datei über einen der oben beschriebenen Wege wird die Datei durch Verzeichnis und Dateiname identifiziert, das Verzeichnis wird dabei nicht direkt, sondern über ein Directory-Objekt mitgegeben, z.B. der Parameter location der Funktion utl_file.fopen, der Parameter directory beim Data-Pump-Export und -Import etc. Der Serverparameter utl_file_dir, der ebenfalls Zugriffsrechte auf Dateien regelt, sollte nicht mehr verwendet werden, da er keine Differenzierung zwischen Lese- und Schreibrechten zulässt, er keine Differenzierung zwischen Datenbanknutzern zulässt, für eine Anpassung ein Neustart der Instanz notwendig ist, zur Pfadangabe trotzdem ein Directory-Objekt benötigt wird. Aus Security-Gründen sollte auf jeden Fall vermieden werden, dass utl_file_dir=* gesetzt ist, da sonst wahlfreier Dateizugriff für alle Benutzer gegeben ist. Informationen über Directory-Objekte finden sich in der View dba_directories (Name und Pfad, die Spalte owner ist immer SYS). Über Schreib- und Leserechte gibt die folgende Abfrage Auskunft: SQL> SELECT
t.grantee, t.privilege, d.directory_name, d.directory_path FROM dba_tab_privs t, dba_directories d WHERE t.owner = d.owner AND t.table_name = d.directory_name ORDER BY t.grantee, d.directory_name, t.privilege;
Listing 5.40: Berechtigungen für Directories
Administrationswerkzeuge In diesem Kapitel werden die Werkzeuge von Oracle und anderen Herstellern aufgeführt, die für die Basisadministration der Datenbank verwendet werden. Dazu gehört natürlich zunächst einmal der Oracle Enterprise Manager, der in der Version 10g komplett neu aufgebaut ist, aber auch das gute alte SQL*Plus, ohne das auch mit der Version 10g eine Oracle-Datenbankinstallation nicht möglich wäre. Exemplarisch werden hier zusätzlich die Produkte TOAD von Quest Software und HORA von Keeptool besprochen, da sie im Bereich Oracle-Administration eine weite Verbreitung haben. Tools, bei denen das Monitoring bzw. die Überwachung der Datenbank im Vordergrund stehen, werden im Kapitel 14 besprochen.
6.1
Oracle Enterprise Manager
Mit Version 7.3 hat Oracle den Enterprise Manager als Werkzeug für alle administrativen Aufgaben einer Oracle-Datenbank eingeführt. Mit der Version 8i wurde das Produkt neu in Java implementiert und als Framework für die Datenbankadministration, aber auch die Verwaltung des Oracle Application Servers angeboten. Durch die Verwendung von Java war es somit erstmals möglich, die Datenbanken auch über Webbrowser zu administrieren. Die ebenfalls mit der Version eingeführte Dreischichten-Architektur erlaubte es außerdem, unterschiedliche Aufgaben in einem speziellen Enterprise Manager Repository zu verwalten und somit speziell für große Unternehmen ein flexibles Werkzeug für Administration, Monitoring und auch Entwicklung zu schaffen. Die neue Enterprise-Manager-Version verabschiedet sich jetzt vom Java-Client und wird nur noch als Webanwendung angeboten. Dabei gibt es zwei unterschiedliche Konfigurationsarten: 1. Enterprise Manager Database Control für die Verwaltung einer einzelnen Datenbank 2. Enterprise Manager Grid Control für die Verwaltung von unterschiedlichen Datenbanken, aber auch anderen Anwendung wie Application Server etc. Während der Enterprise Manager Database Control mit jeder Installation direkt installiert werden kann, muss für das Grid Control zunächst eine eigene Umgebung geschaffen werden. In Kapitel 6.1.1 werden wir daher zunächst die Basisversion beschreiben, bevor wir in Kapitel 6.1.2 auf die recht komplexe Installation und Konfiguration des Enterprise Manger Grid Controls eingehen. Es sei aber an dieser Stelle schon gesagt, dass hier nur die Grundlagen zur Benutzung gelegt werden können, da die Komplexität dieses Werkzeuges die Grenzen des Buches sprengen würde. Da es sich in beiden Fällen um eine Webanwendung handelt, sollten Sie beachten, dass im Normalfall ein Caching der Informationen auf Rechner erfolgt. Für die
246
Administrationswerkzeuge
Benutzung des Enterprise Managers müssen Sie auf jeden Fall die Option »Bei jedem Zugriff auf die Seite nach einer neueren Version suchen« aktivieren. Im Microsoft Internet Explorer finden Sie diese Option unter »Internet-Optionen – Temporäre Internetdateien – Einstellungen«.
Abbildung 6.1: Einstellungen für den Internet Explorer
Ein Vorteil bei der Benutzung eines Webbrowsers besteht darin, dass man die Spracheinstellungen umschalten kann. Dies macht sich der Enterprise Manager zunutze, so dass Sie z.B. zwischen deutscher und englischer Umgebung jederzeit umschalten können. Während der Entstehung des Buches war das von großem Nutzen, da die Fehlersuche mit einer englischen Version im Oracle Metalink wesentlich einfacher ist.
Abbildung 6.2: Umschaltung im Enterprise Manager
Mit »Refresh« bzw. »Aktualisieren« wird dann die neue Einstellung sichtbar.
Oracle Enterprise Manager
247
6.1.1 Enterprise Manager Database Control Wenn Sie eine Datenbank über den Database Configuration Assistant installieren, haben Sie in Schritt 4 die Möglichkeit, die Datenbank für die Verwendung des Enterprise Managers zu konfigurieren (siehe Abbildung 6.3).
Abbildung 6.3: Enterprise-Manager-Konfiguration
In diesem Beispiel sehen Sie auch, dass es hier nicht möglich ist, das Grid Control zu konfigurieren, da kein Agent auf dem Server installiert ist. Zusätzlich können Sie an dieser Stelle eine E-Mail-Benachrichtigung konfigurieren und ein tägliches Backup aktivieren. Beide Optionen sollten jedoch unseres Erachtens erst mit der tatsächlichen Produktionsaufnahme der Datenbank eingerichtet werden – was in der Regel erst nach einigen Tagen, Wochen oder Monaten der Fall sein wird. Im Schritt 9 der Installation können Sie, wie in Abbildung 6.4 dargestellt, dann noch den Tablespace für die Speicherung des Repositorys angeben. Der Tablespace SYSAUX, der, wie bereits erwähnt, zwingend in der Oracle 10g-Datenbank vorhanden sein muss, ist hierfür vorgesehen und sollte auch nicht geändert werden. In diesem Tablespace wird jetzt das Enterprise Manager Repository angelegt. Der hierfür gewählte Benutzer heißt SYSMAN, das Kennwort können Sie in Schritt 5 eingeben.
248
Administrationswerkzeuge
Abbildung 6.4: Enterprise Manager Repository
Nach der Konfiguration und anschließenden Erstellung der Datenbank kann der Enterprise Manager genutzt werden. Dafür existiert unter MS-Windows ein neuer Dienst mit dem Namen OracleDBConsole<SID>. Unter dem Betriebssystem Unix wird der entsprechende Prozess mit folgendem Befehl gestartet: % emctl start dbconsole Listing 6.1: Starten DBConsole unter Unix
Sollte dieser Befehl nicht erfolgreich sein (was unter verschiedenen Linux-Derivaten vorkommen kann), muss die Konfiguration angepasst werden. Hierbei hat sich folgendes Vorgehen als erfolgversprechend erwiesen. 1. Zunächst wird die notwendige Basiskonfiguration neu angelegt. Dies geschieht mit dem Befehl emca –r. Mit diesem Befehl wird die OC4J-Instanz, welche die Grundlage für den Enterprise Manager bildet, neu konfiguriert. Die Option »-r« gibt dabei an, dass das Repository in der Datenbank schon existiert und somit nicht neu angelegt werden muss. Zur Konfiguration sind dann einige Angaben, wie z.B. die Passwörter sowie der Listener-Port (Standard 1521), notwendig. Nach der Beendigung der Konfiguration sollte im ORACLE_HOME ein Verzeichnis in der Form _ existieren. 2. Im Verzeichnis _/sysman/config gibt es eine Datei mit dem Namen emd.properties. In dieser Datei muss jetzt der Eintrag EMD_URL geändert werden, da wahrscheinlich der Port fehlt. Beispiel: http://hllinux1:1830/emd/main.
Oracle Enterprise Manager
249
Danach sollte sich der Prozess problemlos starten lassen. Jede auf dem Server installierte Datenbank benötigt dabei ihre eigene »Database Control«, d.h., je Datenbank gibt es ein Unterverzeichnis im ORACLE_HOME und entsprechende Prozesse mit eigenen Ports. Der Aufruf des Enterprise Managers hängt also im Folgenden von den verwendeten Ports ab. Die Liste der Ports lässt sich am einfachsten aus der Datei portlist.ini im Verzeichnis ORACLE_HOME/install ermitteln. Hier finden Sie z.B. folgende Einträge: Enterprise Manager Console HTTP Port (LINUX10G) = 5500 Enterprise Manager Agent Port (LINUX10G) = 1830 Listing 6.2: Enterprise Manager Portlist
Das bedeutet, dass der Agent für die Datenbank LINUX10G (den Sie u.U. in der Datei emd.properties manuell angegeben haben) den Port 1830 und die Konsole für die Datenbank den Port 5500 benutzt. Vorsicht beim Löschen des Schemas SYSMAN. In diesem Fall wird zwar das Repository gelöscht, einige Einträge bleiben jedoch erhalten und verhindern, dass das Repository neu angelegt werden kann. Es müssen alle Public-Synonyme, die mit MGMT beginnen, das Synonym setemviewusercontext sowie die Rolle mgmt_user manuell gelöscht werden, bevor mit dem Befehl emca (ohne Optionen) ein neues Repository angelegt werden kann. Alternativ kann man folgenden Befehl verwenden: Verzeichnis %ORACLE_HOME%/sysman/admin/emdrep/bin % Repmanager –sys_password <password> -action drop
z.B. in der folgenden Form: Repmanager hllap34 1521 JA10G -sys_password manager -action drop Listing 6.3: Löschen des Repositorys
Dabei wird dann der Benutzername des Repositorys (SYSMAN) und dessen Kennwort abgefragt. Unter MS-Windows gibt es dabei eine unschöne Fehlermeldung, da das Perl-Skript für Unix geschrieben wurde und mit dem Befehl stty das Echo des Kennwortes ausgeschaltet wird, was so aber unter Windows nicht funktioniert. Falls es Sie stört, können Sie in dem Perl-Script emrepmgr.pl die entsprechenden Zeilen auskommentieren. Es hat aber keinen Einfluss auf die Ausführung des Skriptes. In einigen Fällen ist es allerdings passiert, dass der User mgmt_view nicht gelöscht wird. Also kontrollieren Sie am besten, ob es noch Objekte gibt, die mit mgmt beginnen. Mit dem gleichen Befehl, aber der Option create wird das Repository dann neu angelegt. Also z.B.: repmanager hllap34 1521 JA10G -sys_password manager -action create Listing 6.4: Anlegen des Repositorys
250
Administrationswerkzeuge
Leider gibt es dabei einige Ungereimtheiten, d.h., in einigen Fällen ist es vorgekommen, dass der Enterprise Manager anschließend nicht genutzt werden konnte. Als Alternative kann das Repository auch über den Database Configuration Assistant neu installiert werden. Anmeldung an den Enterprise Manager Um mit dem Enterprise Manager arbeiten zu können, wird jetzt ein Browser gestartet und darin die Adresse der Konsole eingetragen. In unserem Beispiel also: http://hllinux1:5000/em
Zunächst meldet man sich dann an die Datenbank an.
Abbildung 6.5: OEM-Anmeldung
Beim ersten Aufruf erhalten Sie anschließend eine Abfrage, welche Optionen (Management Packs) Sie lizenziert haben. Folgende optionalen Pakete sind möglich: Oracle Diagnostic Pack: Hierzu gehört – wie in früheren Versionen – das EventManagement, mit dem es möglich ist, Informationen zu sammeln und bei Bedarf Warnungen oder Alarme per E-Mail zu versenden oder auf der Konsole anzuzeigen. Neu hinzugekommen ist die grafische Implementierung von ADDM (Automatic Database Diagnostic Monitor), den wir in Kapitel 11 (Tuning) in der Basisversion näher beschreiben werden. Dazu noch ein Hinweis: Das Database Diagnostic Pack ist lizenzpflichtig – und damit auch der Punkt ADDM. Die Funktionalität, die dahinter steckt, ist jedoch im Basisumfang der Datenbank enthalten. Das Gleiche gilt auch für das Automatic Workload Repository.
Oracle Enterprise Manager
251
Oracle Tuning Pack: Zu diesem Paket gehören wie in älteren Version Werkzeuge für Anwendungstuning und Reorganisation. Oracle Configuration Pack: Dieses Paket gibt es in der Version 10 erstmals, und es enthält Werkzeuge für die Software-Verteilung und Patch-Installation, aber auch Tools für die Überprüfung der Datenbankkonfiguration. Oracle Change Management Pack: Im Gegensatz zu den bereits genannten Optionen steht dieses Paket nur als Java-Anwendung zur Verfügung und ist daher nicht über den hier besprochenen Enterprise Manager nutzbar. Stattdessen muss der optionale java-basierende Enterprise Manager installiert werden. Dieser ist identisch mit der bereits in Oracle8i und Oracle9i genutzten Version und wird an dieser Stelle nicht weiter betrachtet. Im Unterschied zu älteren Versionen des Enterprise Managers gliedern sich hier die Packages in die Konsole ein, so dass man beim normalen Arbeiten keinen Unterschied zwischen Standardfunktionalität und kostenpflichtigen Packages bemerkt. Sie können die Benutzung der einzelnen Pakete im laufenden Betrieb aber jederzeit ändern. Dafür gehen Sie auf den Menüpunkt »Setup«, den Sie oben und unten auf jeder Enterprise-Manager-Seite finden. Dort befindet sich auf der linken Seite das Untermenü »Management Pack Access«, in dem Sie dann die einzelnen Beschreibungen finden und ein- bzw. ausschalten können. Standardverzeichnis Kommen wir zurück zum Basisumfang des Enterprise Managers. Wenn Sie sich angemeldet haben, gelangen Sie zum STANDARDVERZEICHNIS (Reiter Datenbank). Dieses Fenster ist in unterschiedliche Bereiche unterteilt. Dazu zählen allgemeine Informationen (Name und Status der Datenbank), aktuelle Statistikwerte (CPUVerbrauch oder angemeldete Benutzer), aber auch Informationen über Alarme und durchgeführte Jobs. Bereich Allgemein
Abbildung 6.6: Bereich Allgemein
Neben Informationen über Namen der Datenbank und der Verfügbarkeit können Sie von hier aus die Datenbank stoppen (HERUNTERFAHREN).
252
Administrationswerkzeuge
Abbildung 6.7: Hoch- und Herunterfahren der Datenbank
Der eingetragene Betriebssystembenutzer (johannes) muss auf dem Rechner die Berechtigung Anmelden als Stapelverarbeitungsauftrag haben.
Abbildung 6.8: Hochfahren der Datenbank
Oracle Enterprise Manager
253
Für das Starten der Datenbank sind über den Menüpunkt ERWEITERTE OPTIONEN weitere Optionen möglich.
Abbildung 6.9: Optionen für das Starten der Datenbank
Interessant ist auch der Unterpunkt HOST im Bereich ALLGEMEIN, da hier die wichtigsten Werte des Rechners angezeigt werden – in dieser Form sucht man so etwas auf vielen Systemen vergeblich. Leider sind in anderen Bereichen nur Basiswerte verfügbar, eine Aufgliederung verlangt die Nutzung des Database Diagnostic Packs.
254
Administrationswerkzeuge
Abbildung 6.10: Hostparameter
High Availability Ein weiterer wichtiger Bereich ist HIGH AVAILABILITY, da von diesem Punkt aus die Archivierung und die Flash-Recovery-Area konfiguriert werden kann. Weitere Informationen hierzu finden Sie in Kapitel 10 (Wiederherstellungstechniken).
Abbildung 6.11: High Availability
Oracle Enterprise Manager
255
Alerts Dieser Punkt ist eine entscheidende Bereicherung des neuen Enterprise Managers, da jetzt zum ersten Mal die Informationen aus der Alert-Datei, aber auch aus anderen Bereichen dargestellt werden – ohne das eine zusätzliche Konfiguration notwendig ist. Leider gilt auch hier die Einschränkung, dass nur eine Überschrift angezeigt wird, wer nähere Informationen benötigt – die in diesem Fall sicherlich angebracht sind –, wird auf das Diagnostic Pack verwiesen. Alternativ kann aber natürlich auch in der entsprechenden Datei (z.B. Alert-Log) nachgesehen werden. Einige Meldungen (wie z.B. aus der Kategorie USER AUDIT) sind aber auch selbsterklärend.
Abbildung 6.12: Alarme und Warnungen
Zugehörige Links Die Meldungen werden über Metriken verwaltet. Einige Metriken sind dem Diagnostic Pack vorbehalten, eine ganze Reihe kann aber auch im Standard-Enterprise-Manager verwaltet werden. Im Bereich ZUGEHÖRIGE LINKS kann über den Punkt METRIKEN VERWALTEN die Standardeinstellung verändert werden. Zunächst wird dabei die aktuelle Einstellung angezeigt, über den Menüpunkt SCHWELLENWERTE BEARBEITEN gelangt man dann in die eigentliche Einstellung (siehe Abbildung 6.13). Hier kann dann z.B. die Meldung über Anmeldungen als Benutzer »SYS« ausgeschaltet werden. Ein weiterer Punkt in diesem Bereich ist INHALT VON ALERT LOG, mit dem die gesamte Alert-Datei der Datenbank als Textdatei angezeigt wird. Das kann zum Beispiel als Hilfe dienen, wenn im Bereich ALERT Meldungen der Kategorie ALERT LOG angezeigt werden. Leider dauert der Aufruf dieser Datei sehr lange, so dass es oftmals sinnvoller ist, sich direkt auf dem Rechner anzumelden und die Datei mit einem Standardeditor anzuzeigen.
256
Administrationswerkzeuge
Abbildung 6.13: Schwellenwerte einstellen
Weitere Verzeichnisse Neben dem Standardverzeichnis gibt es das Verzeichnis PERFORMANCE, auf das Sie nur dann einen Zugriff haben, wenn Sie das Diagnostic Pack lizenziert haben. Über das Verzeichnis ADMINISTRATION können Sie alle wesentlichen Teile der Datenbank administrieren. Wir gehen an dieser Stelle nicht weiter auf diesen Bereich ein, da die einzelnen Punkte in entsprechenden Kapiteln ausführlich behandelt werden und es sich hier ja nur um die grafische Repräsentation von SQL-Befehlen handelt. Interessant ist hier eventuell noch der in Abbildung 6.14 dargestellte Menüpunkt STATISTIKEN DER DATENBANKVERWENDUNG im Bereich KONFIGURATIONSVERWALTUNG, da hier alle Datenbankfunktionen und ihre Verwendung dargestellt werden. Gerade bei Audit-Aktionen sind diese Informationen hilfreich. Das letzte Verzeichnis WARTUNG beinhaltet schließlich das Thema Backup und Recovery, Export – Import sowie Reorganisation (siehe auch Kapitel 10). Bei Verwendung des Configuration Management Packs können hier deren wichtigste Funktionen aufgerufen werden.
Oracle Enterprise Manager
257
Abbildung 6.14: Statistiken der Datenbankverwendung
6.1.2 Enterprise Manager Grid Control Der Enterprise Manager Grid Control ist eine Dreischichten-Architektur bestehend aus einer Verwaltungsdatenbank (Grid Control Database), Agenten auf den zu überwachenden Rechnern und den zu verwaltenden Anwendungen, zu denen sowohl das Betriebssystem als auch die einzelnen Datenbanken zählen. Diese Software ist unabhängig von einer Oracle-Datenbank oder einem Application Server und wird somit in allen Komponenten separat installiert. Das bedeutet, dass Sie auf dem Datenbankserver einen Agenten in einem eigenen ORACLE_HOME installieren müssen, der dann die Datenbanken und das Betriebssystem überwacht. Ein Rechner muss für das Grid Control zur Verfügung gestellt werden. Da dieses die Daten aller Agenten auswerten und darstellen muss, ist es anzuraten, diesen Rechner mit mindestens 2 GByte Hauptspeicher auszustatten. Dieser Rechner ist es, auf den sich von jetzt an die Administratoren anmelden, um die einzelnen Datenbanken zu verwalten.
258
Administrationswerkzeuge
Grid-Control-Installation Folgendes Bild zeigt die auswählbaren Komponenten:
Abbildung 6.15: Komponenten des Enterprise Manager Grid Controls
Die in der Abbildung dargestellten Installationsoptionen haben folgenden Inhalt: ENTERPRISE MANAGER 10G GRID CONTROL USING A NEW DATABASE 10.1.0.3 installiert die Grid-Control-Software sowie die komplette Datenbank-Software in der Version Oracle 9.0.1.5. Da diese Version von Oracle nur für den Einsatz von Grid Control unterstützt ist, können wir diese Option nicht empfehlen. ENTERPRISE MANAGER 10G GRID CONTROL USING AN EXISTING DATABASE 10.1.0.3 installiert ebenfalls die Grid-Control-Software. Das Repository wird allerdings in eine bereits existierende Datenbank der Version 9.2.0.4 oder höher installiert. Diese Datenbank muss eine Enterprise-Edition sein und muss laut Dokumentation die Option Label Security installiert und konfiguriert haben. Es gibt allerdings einen Metalink-Eintrag (Doc-Id: 285209.1), laut dem es sich hierbei um einen Dokumentations-Bug handeln soll. ADDITIONAL MANAGEMENT SERVICE 10.1.0.3 installiert ausschließlich die GridControl-Software, ohne das Repository zu erstellen. ADDITIONAL MANAGEMENT AGENT 10.1.0.3 installiert die Agent-Software für die zu überwachenden Datenbanken, Webserver, Application Server und Systeme.
Oracle Enterprise Manager
259
Für die von uns durchgeführten Tests haben wir zunächst die Oracle 10g-Datenbank-Software installiert und darauf eine Datenbank (EM10G) erstellt. Diese benutzen wir als Repository für Grid Control. Für die Repository-Datenbank müssen folgende Initialisierungsparameter gesetzt sein: session_cached_cursors >= 200 aq_tm_processes >= 1 shared_pool_size >= 130 MB Wenn diese Parameter nicht entsprechend gesetzt sind, erhalten Sie eine Fehlermeldung, können aber mit der Installation fortfahren. In der ausgewählten Datenbank werden zwei neue Tablespaces MGMT und MGMT_ECM_DEPOT angelegt. Während der Installation können Sie die Lage der Datendateien angeben.
Abbildung 6.16: Management Repository
In der obigen Abbildung sehen Sie die notwendigen Angaben für die Installation von Grid Control für eine bereits bestehende Datenbank. Aus unerfindlichen Gründen darf der mit der Version 10.1.0.3 erstmals konfigurierte Scheduler-Job für die Sammlung der Systemstatistiken nicht benutzt werden. Sie müssen diesen Job also vor oder während der Installation deaktivieren. SQL> exec dbms_scheduler.disable('SYS.GATHER_STATS_JOB');
260
Administrationswerkzeuge
Leider sind Enterprise Manager Grid Control und Enterprise Manager Database Control nicht kompatibel, so dass Sie eine bereits angelegte Database-Control-Konfiguration (Schema SYSMAN) vorher löschen müssen. Das Gleiche gilt, wenn Sie Grid Control nicht mehr verwenden wollen, sondern zurück zum Database Control wollen. Verwenden Sie dafür das in Kapitel 6.1.1 angegebene Verfahren zum Löschen und Anlegen des Schemas SYSMAN. Bei der Installation unter Linux gab es einige Besonderheiten, die zwar störend, aber nicht kritisch sind. So gab es eine Fehlermeldung, die besagte, dass das Verzeichnis oradata im ORACLE_HOME der Grid-Software nicht existiert. Da die Software gerade neu installiert wird, kann es auch gar nicht existieren. Also muss man von Hand dieses Verzeichnis anlegen und kann dann mit der Installation fortfahren. Benutzt wird dieses Verzeichnis jedoch nur, wenn man die Verzeichnisse der beiden Tablespaces MGMT und MGMT_ECM_DEPOT nicht anpasst. Während der Installation werden weitere Konfigurationsparameter abgefragt. Dazu gehören: Das Passwort des Benutzers SYSMAN, das mindestens fünf Zeichen und eine Zahl enthalten muss Die Konfiguration einer automatischen Benachrichtigung per E-Mail Metalink-Zugriffsdaten für die automatische Verwaltung von Patches Proxy-Informationen, um mit den Agenten oder auch externen Datenbanken (wie z.B. Metalink) über Grid-Control kommunizieren zu können. Anschließend wird zunächst die Grid-Control-Software in dem ausgewählten Verzeichnis installiert. Außerdem wird der Agent in einem separaten Verzeichnis parallel zum ORACLE_HOME der Grid-Control-Software installiert. Das bedeutet, für die Konfiguration inklusive der Oracle-Datenbank-Software werden drei unterschiedliche ORACLE_HOME-Verzeichnisse benötigt: Datenbank: /app/oracle/product/10.1.0/db_1 Grid-Control: /app/oracle/product/10.1.0/grid Agent: /app/oracle/product/10.1.0/agent Der Zugriff auf die Grid-Control Console erfolgt über die folgende HTML-Seite: http://servername:7780/em
WICHTIG: Der Servername muss auf dem Client aufgelöst werden können (Host-Datei oder DNS). Bei der direkten Eingabe der IP-Adresse kann es vorkommen, dass man auf einer falschen Seite landet. Nach der ersten Anmeldung erhalten Sie wie beim Database Control die Aufforderung, die Packages anzugeben, die Sie benutzen bzw. lizenziert haben. Anschließend bekommen Sie die Übersicht über die Systeme, Datenbanken etc. wie in der unten angegebenen Form.
Oracle Enterprise Manager
261
Abbildung 6.17: Enterprise Manager Grid Control
Eine ausführliche Beschreibung des Enterprise Manager Grid Controls würde an dieser Stelle zu weit führen. Da die Funktionsweise allerdings sehr gut beschrieben ist (sogar, wie in der Abbildung zu erkennen, in Deutsch), sollten Sie in der Lage sein, sich im Enterprise Manager schnell zurechtzufinden. Agent-Installation Die Installation eines Agenten für die Verwaltung mit Grid Control ist sehr einfach. Es wird lediglich ein Verzeichnis für die Installation angegeben und dann der Punkt ADDITIONAL MANAGEMENT AGENT 10.1.0.3 ausgewählt. Nach dem Starten des Agenten werden der Host, die Datenbanken, Web- und Application Server automatisch im Grid-Control angezeigt. Wenn Sie anschließend eine neue Datenbank erstellen, können Sie wie im folgenden Bild gezeigt die Verwendung des Agenten konfigurieren.
262
Administrationswerkzeuge
Abbildung 6.18: Datenbank für Grid Control konfigurieren
Administration Zum Schluss einige Bemerkungen zur Administration, d.h. Starten und Stoppen der einzelnen Komponenten. Wichtig ist, dass Sie, speziell auf Unix-Systemen, die Umgebungsvariablen richtig setzen. Wir haben aus diesem Grund die Datei /etc/oratab bzw. /var/opt/oracle/ oratab um die notwendigen Einträge erweitert: oratab EM10G:/app/oracle/product/10.1.0/db_1:N GRID:/app/oracle/product/10.1.0/grid:N AGENT:/app/oracle/product/10.1.0/agent:N % . oraenv ORACLE_SID = [EM10G] ? GRID Listing 6.5: Environment für Grid Control
In diesem Beispiel können wir jetzt zwischen den einzelnen Umgebungen mit dem Befehl oraenv wie dargestellt hin- und herschalten (im Beispiel von der Umgebung der Datenbank EM10G auf die Grid-Control-Software). Mit dem folgenden Befehl werden der Management-Server sowie die OC4J-Instanzen und der Webcache gestoppt und wieder gestartet. Dieser Befehl bietet sich generell an, wenn der Management-Server neu durchgestartet werden soll.
Oracle Enterprise Manager
263
% . oraenv ORACLE_SID = [EM10G] ? GRID % cd $ORACLE_HOME/opmn/bin % ./opmnctl stopall # Stoppen aller Services % ./opmnctl startall # Starten aller Services Listing 6.6: Stoppen und Starten aller Management-Server-Komponenten
Alternativ können die Komponenten über den Befehl emctl auch einzeln verwaltet werden. Da dieser Befehl im Verzeichnis ORACLE_HOME/bin liegt, kann er in der Regel ohne Pfadangabe aufgerufen werden. % emctl status oms Oracle Enterprise Manager 10g Release 10.1.0.3.1 Copyright (c) 1996, 2005 Oracle Corporation. All rights reserved. Oracle Management Server is Up Listing 6.7: Statusabfrage Oracle Management Server
Für die Verwaltung des Agenten müssen die Umgebungsvariablen wieder entsprechend umgestellt werden. Also: % . oraenv ORACLE_SID = [EM10G] ? AGENT % emctl stop agent % emctl start agent Listing 6.8: Stoppen und Starten des Enterprise-Manager-Agenten
Für eine weitergehende Administration des Enterprise Manager Grid Controls empfiehlt sich das Dokument Oracle Enterprise Manager Advanced Configuration (Part No. B12013-03). Anmerkung Die Installation des Enterprise Manager Grid Controls erwies sich während der Entstehung des Buches als überaus schwierig. Eine Installation unter MS-Windows (2000 und XP) ist uns trotz mehrerer Versuche nicht gelungen. Während der Installation gab es immer wieder die Fehlermeldung, dass die Pfadlänge 1023 Zeichen überschritten habe (was bei größeren Installationen mit mehreren unterschiedlichen Oracle Software-Versionen natürlich keine Seltenheit ist). Schlussendlich setzte aber der KONFIGURATIONSASSISTENT FÜR JAVA-SICHERHEIT (engl.: Java Security Configuration Assistant) der Installation ein Ende. Diesbezügliche Anfragen bei Oracle blieben leider ohne Erfolg. Generell kann hier nur nochmals darauf hingewiesen werden, sich exakt an die Vorgaben zu halten, d.h., alle Voraussetzungen zu prüfen. Nur so lassen sich tagelange Tests vermeiden. Außerdem hatten wir sowohl mit dem Database Control als auch mit dem Grid Control Probleme, den Status der Datenbanken abzufragen. Nach Stoppen und Starten des Management-Servers bzw. der Konsole wurde als Status der Datenbank immer wieder »Heruntergefahren« gemeldet, obwohl Datenbanken und Agenten liefen.
264
Administrationswerkzeuge
.
Tipp: Wenn unter Unix die Datenbank-Software und der Management-Server wie oben dargestellt installiert werden (also drei ORACLE_HOME-Verzeichnisse), kann es vorkommen, dass der Oracle Net-Listener-Prozess sehr viel Last erzeugt. Dies ist darauf zurückzuführen, dass der Universal Installer sowohl für die DatenbankSoftware als auch für die Grid-Control-Software die gleichen Ports für den Notification Server (ONS) konfiguriert hat. Als Lösung sollte in dem entsprechenden Verzeichnis der Datenbank-Software (z.B. /app/oracle/product/10.1.0/db_1/grid/opmn/conf) die Datei ons.config umbenannt werden. Danach kann der Listener einmal durchgestartet werden und läuft wieder normal.
6.2
Scheduler
Mit einem Scheduler ist man in der Lage, regelmäßig anfallende Aufgaben automatisiert auszuführen. In der Datenbank findet man diese Möglichkeit auch – neben Möglichkeiten der Betriebssysteme sowie spezieller Software. Bei den Betriebssystemen sind unter Unix die cron-Funktionalität, unter Windows so genannte at-Jobs bekannt. In vielen Umgebungen werden diese Scheduler auch genutzt, um Datenbankaufgaben zu starten. Mit dem Scheduler in der Datenbank gibt es hierzu eine Alternative. Ob und wann es Sinn macht, den Scheduler in der Datenbank zu benutzen, verschieben wir auf den letzten Abschnitt dieses Unterkapitels, nachdem die Funktionsweise und Möglichkeiten des Schedulers erklärt worden sind. Um die grundsätzliche Verwirrung ein bisschen zu steigern, gibt es bei Oracle 10g zwei unterschiedliche Scheduler: den mit Oracle7 eingeführten »alten« Scheduler sowie einen neu entwickelten 10g-Scheduler. Beide Scheduler können parallel betrieben werden. Somit ist es möglich, »alte« Jobs, die bei einer Migration übrig geblieben sind, weiter mit dem alten Scheduler zu betreiben, gleichzeitig jedoch neue Jobs direkt im neuen Scheduler aufzusetzen.
6.2.1 Alter Scheduler Der alte Scheduler wird über ein mitgeliefertes PL/SQL-Modul dbms_job gesteuert. Hiermit können Jobs eingestellt, geändert und gelöscht werden. Hierzu ein Beispiel: VAR j NUMBER EXECUTE dbms_job.submit (job => :j, what => dbms_lock.sleep(10);', next_date => sysdate, interval => 'sysdate + 1/24') COMMIT /
Scheduler
265
Hiermit wird ein neuer Job eingestellt, der über den OUT-Parameter JOB eine eindeutige systemgenerierte Jobnummer zugewiesen bekommt. Für praktisch alle Aufrufe des dbms_job-Packages gilt, dass sie letztendlich Einträge in den Jobverwaltungstabellen machen, die durch COMMIT bestätigt werden müssen. In den dbms_job-Prozeduren selbst ist kein COMMIT eingebaut – es müssen also alle Aufrufe explizit COMMITed werden! In den weiteren Beispielen ist das COMMIT nicht immer mit aufgeführt. Über die Jobnummer kann der eben eingerichtete Job in der View dba_jobs wieder gefunden werden. Der zugehörige Datensatz sieht wie folgt aus:
Abbildung 6.19: Datensatz aus dba_jobs
Unter what kann nachgeschaut werden, was der Job tut (in diesem Fall zehn Sekunden warten). Es handelt sich hierbei um PL/SQL-Prozeduraufrufe bzw. anonyme PL/ SQL-Blöcke. Das abschließende Semikolon ist hierbei unerlässlich! Im Übrigen empfiehlt es sich, längere Blöcke als Prozedur zu definieren und diese dann als Job auszuführen – schon alleine deshalb, weil man Verarbeitungslogik möglichst nicht in Scheduler-Definitionen verpacken sollte. Für Prozeduraufrufe können Parameter angegeben werden; allerdings sind IN OUT- und OUT-Parameter nicht erlaubt. Wichtig
266
Administrationswerkzeuge
ist, dass alle Privilegien, die einem Benutzer über Rollen zugewiesen sind, innerhalb von Jobs nicht zur Verfügung stehen – genau wie bei PL/SQL Prozeduren, Packages usw. Im obigen Beispiel benötigt der Benutzer SYSTEM das direkte EXECUTE-Privileg des Packages sys.dbms_lock – das Recht EXECUTE ANY PROCEDURE aus der Rolle dba zieht in diesem Fall nicht! Die letzte an dieser Stelle genannte Einschränkung für Jobs ist die folgende: Innerhalb der Jobs können keine Datenbank-Links genutzt werden, die ohne CONNECT TO- und IDENTIFIED BY-Klauseln definiert sind. Normalerweise werden diese Informationen aus dem aktuellen Sitzungskontext genommen und an die entfernte Datenbank weitergeleitet. Da bei der Jobausführung dieser Sitzungskontext nicht vorhanden ist, funktionieren solche Datenbank-Links innerhalb von Jobs eben nicht. Alle _user-Felder der View haben den Inhalt SYSTEM; dies spiegelt wider, dass der Job (wie in diesem Fall geschehen) unter SYSTEM angelegt worden ist und auch unter dieser Benutzerkennung läuft. Die DATE-Felder last_date, this_date und next_date geben an, wann der Job zuletzt gestartet (und ohne Fehler beendet) worden ist, wann er für die aktuelle Ausführung gestartet worden ist und wann er das nächste Mal gestartet wird. Da in vielen Umgebungen das Anzeigeformat für DATE-Felder NLS_DATE_FORMAT nur das Datum und keine Zeiten beinhaltet, zeigt die View Stunden, Minuten und Sekunden zusätzlich in den _sec-Feldern an. In der obigen Anzeige stand NLS_DATE_FORMAT auf DD.MM.YYYY HH24:MI:SS, so dass die zusätzliche Anzeige nicht nötig ist. Wichtig ist der Inhalt von interval: Hier wird eine Funktion vom Typ DATE erwartet. Sie wird immer genau dann ausgeführt, wenn der Job seine Ausführung beendet, und berechnet dann den Zeitpunkt der nächsten Ausführung (und wird damit in next_date eingetragen). Ist interval nicht gefüllt (NULL), so erfolgt die Ausführung des Jobs nur einmal. Im Beispiel wird auf das aktuelle Datum der Wert 1/24 addiert – mit dem Zusatzwissen, dass DATE-Funktionen bei Oracle mit der Einheit Tag rechnen, ist klar, dass der Job jeweils nach einer Stunde neu ausgeführt wird. In der Spalte nls_env werden alle NLS-Einstellungen (Sprache, Datumsformat, Sortierreihenfolgen usw.) der Sitzung festgehalten, die den Job eingestellt haben. Diese Einstellungen werden auch jeweils für die ausführende Sitzung (im Hintergrundprozess) verwendet. Voraussetzung für die Ausführung von Jobs ist das Setzen des Serverparameters job_queue_processes auf einen von 0 unterschiedlichen Wert. Hierdurch wird der Hintergrundprozess CJQ0 (Central Job Queue Coordinator) permanent gestartet. Dieser startet bei Bedarf Jobprozesse Jnnn, maximal die im Serverparameter angegebene Anzahl. Diese Prozesse führen die Jobs selbst aus. Da die Jnnn-Prozesse zu den Hintergrundprozessen gehören, schreiben sie ihre TraceDateien in das entsprechende Verzeichnis (Serverparameter background_dump_ dest). Sobald bei der Ausführung eines Jobs auf oberster Ebene1 Fehler auftauchen, werden diese in der Trace-Datei protokolliert. In der View dba_jobs werden Fehler nur durch den Zähler failures angezeigt. Hiermit wird die Anzahl der Fehler seit der letzten erfolgreichen Ausführung angezeigt. 1
Da es sich um PL/SQL-Code handelt, können natürlich Fehler auftauchen, die über einen Exception Handler abgefangen werden. Diese werden nicht nach außen weitergegeben und somit auch nicht als Fehler gewertet.
Scheduler
267
Mit jeder fehlerhaften Ausführung wird demnach failures hochgezählt; zusätzlich wird next_date auf einen etwas späteren Zeitpunkt gesetzt. Dabei werden die Abstände zum nächsten Ausführungsversuch mit höheren failures-Werten immer länger – wohl in der Hoffnung, dass die abgelaufene Zeit die »Wunden« heilt und zu einer fehlerfreien Ausführung führt ... Nach 16 fehlerhaften Versuchen bekommt der Job den Status Broken (Feld broken auf Y, next_date auf 1. Januar 4000). Es wird dann nicht mehr versucht, den Job auszuführen. Eine weitere Möglichkeit, einen Job auf BROKEN zu setzen, ist der Aufruf einer entsprechenden Prozedur: EXECUTE dbms_job.broken (job => 3, broken => TRUE)
Mit der Prozedur dbms_job.broken kann ein Job auch wieder zurückgesetzt werden, z.B. wenn man das Problem gelöst hat, das zum Fehlverhalten des Jobs geführt hat. Als weiteren Parameter erlaubt die Prozedur deshalb auch ein next_date: EXECUTE dbms_job.broken (job => 3, broken => FALSE, next_date => SYSDATE)
Mit dem Aufruf EXECUTE dbms_job.run(job => 3)
besteht die Möglichkeit, einen Job unabhängig von Broken-Status und next_date sofort auszuführen. Die Ausführung erfolgt allerdings in der aktuellen Sitzung (d.h. nicht innerhalb eines Jnnn-Prozesses!). Dies kann z.B. für Tests sehr nützlich sein; die Blockierung der aktuellen Sitzung ist jedoch gerade bei Jobs mit langen Ausführungszeiten eher unpraktisch. Nach einer erfolgreichen Ausführung wird der Broken-Status aufgehoben und das next_date laut interval neu gesetzt. Die Ausführung des Jobs ist übrigens ausschließlich unter dem Benutzer, der den Job angelegt hat, möglich.
6.2.2 Neuer Scheduler Wie so oft, wenn neue Funktionen in das Oracle DBMS eingeführt werden, sind diese so komplex, dass eine einfache Erweiterung der »alten« Strukturen nicht reicht. Auch in diesem Fall ist ein kompletter neuer Scheduler implementiert worden – und damit auch die bisher verwendeten Jobs weiterlaufen, ist der »alte« Scheduler zunächst komplett erhalten geblieben. Der Grund für den Parallelbetrieb beider Scheduler dürfte sein, dass es keinen einfachen Weg gibt, alte Jobs automatisch zu migrieren, da z.B. die Einstellung der Ausführungszeiten anders funktioniert als beim alten Scheduler. Außerdem gibt es weiterhin Komponenten, die Jobs für den alten Scheduler erstellen, z.B. Materialized Views mit automatischem Refresh oder der Enterprise Manager 10g Database Control (EMD_MAINTENANCE.EXECUTE_EM_DBMS_JOB_PROCS(); unter dem Benutzer SYSMAN).
268
Administrationswerkzeuge
Es ist damit zu rechnen, dass beide Scheduler für zwei oder mehr Oracle-Versionen parallel betrieben werden können. Nach einer Übergangsphase, in welcher der alte Scheduler nur noch über undokumentierte Serverparameter erreichbar sein wird, wird er dann ganz verschwinden ... Warum ein neuer Scheduler? Diese Frage ist berechtigt, da der alte Scheduler ja nach wie vor funktioniert und dies i.A. auch sehr verlässlich tut. Allerdings gibt es Anforderungen an ein Scheduler-System, die mit dem alten Scheduler nicht vereinbar sind, z.B.: Spezifikation der Laufzeiten: Natürlich ist mit dem next_date-Mechanismus und der Oracle DATE-Arithmetik praktisch alles an Laufzeitmustern abbildbar. Allerdings ist es manchmal schon kompliziert, einfache Dinge wie »alle 10 Minuten«, »jede Stunde außer von 23 bis 2 Uhr« usw. hinzuschreiben. Berechtigungen: Jobs können nur vom Ersteller ausgeführt werden. Dies ist insbesondere beim Testen bzw. »Wiederanlaufenlassen« von einer DBA-Konsole aus unangenehm, wenn nicht alle Jobs über den DBA-Account laufen. Logging: Im alten Scheduler sind immer nur Informationen über die letzte Ausführung vorhanden. In den Trace-Dateien der Jobprozesse finden sich Fehlermeldungen bei nicht erfolgreichen Versuchen. In der View dba_scheduler_job_log sind nunmehr Informationen über alle Ausführungen (erfolgreiche und nicht erfolgreiche!) vorhanden – bis diese in der Regel nach drei Wochen gelöscht werden. Prioritäten: Ganz neu ist die Einbindung von Ressource Consumer Groups über die Jobklasse und somit die Zuordnung von Prioritäten. Weiterhin kann über den instance-Parameter ein Job einer speziellen RAC-Instanz zugeordnet werden. Im neuen Scheduler geschieht die Zuordnung über Dienstnamen (in der Jobklasse), was eine größere Flexibilität ermöglicht, z.B. die Zuordnung zu mehreren Instanzen. Dies sind nur einige »Anforderungen« an den Neuen – nunmehr ist klar, dass der neue Scheduler noch viel mehr in die Richtung »Professionelles Job-Management« geht als der Alte. Betrachten wir also die Möglichkeiten von vorne: Zunächst einmal ist der Job im neuen Scheduler wesentlich modularer aufgebaut als im Alten. Hier wurden die Task, das Zeitverhalten usw. für jeden Job einzeln festgelegt. Im neuen Scheduler gibt es diese Möglichkeit auch (man legt einen Job an); man kann jedoch auf vorbereitete Definitionen von Zeitplänen (Schedules) und Programmen zurückgreifen. Dies macht z.B. Sinn, wenn man einen bestimmten Zeitplan (etwa: alle fünf Minuten) für diverse Jobs benötigt. Voraussetzungen Der neue Scheduler ist unabhängig von der Einstellung von Serverparametern wie job_queue_processes einsatzfähig. Dabei wird der Central Job Queue Coordinator CJQ0
bei Bedarf gestartet – wenn er nicht sowieso für die Verarbeitung von alten Jobs gestartet ist – und übernimmt die Steuerung weiterer Jobprozesse Jnnn. Die Maximalzahl der für den neuen Scheduler gleichzeitig gestarteten Jobs kann mit dem globa-
Scheduler
269
len Scheduler-Attribut max_job_slave_processes gesetzt werden.2 Standardmäßig ist dies auf NULL gesetzt, d.h. CJQ0 bestimmt abhängig von Maschinenauslastung und der Anzahl zu verarbeitender Jobs die Anzahl der notwendigen Jobprozesse. Weiterhin muss bei Windows-Systemen der Dienst OracleJobScheduler<SID> gestartet sein, damit externe Programme gestartet werden können. Für interne Programme (PL/SQL-Prozeduren und Blöcke) ist dies nicht notwendig. Bei Unix-Systemen müssen u.U. Berechtigungen für das ausführbare Programm extjob geändert werden. Es empfiehlt sich grundsätzlich, bei neuen Releases oder Patch-Sets auf Informationen zu diesem Thema gesondert zu achten. Programme, Schedules und Jobs Der neue Scheduler erlaubt den strukturierten Aufbau von Jobs. Es werden nicht mehr unbedingt alle vorhandenen Informationen in einen einzigen Aufruf (wie bei dbms_job.submit) verpackt, sondern es besteht die Möglichkeit, Programme, Schedules und Jobs getrennt zu definieren. Programme Dabei definiert man mit einem Programm zunächst eine mögliche auszuführende Arbeitseinheit. Neu ist, dass bei den Programmen der program_type angegeben wird. Hierbei hat man die Auswahl aus PLSQL_BLOCK, STORED_PROCEDURE und EXECUTABLE. Hierbei ist bei PLSQL_BLOCK in etwa das gemeint, was der alte Scheduler im what-Parameter erlaubt hat. Im Falle von STORED_PROCEDURE gibt man lediglich den Aufruf der Prozedur an und spart sich zunächst das Semikolon. Wirklich neu ist der Typ EXECUTABLE, womit man tatsächlich ein Programm (ausführbares Programm oder Skript) auf Betriebssystemebene aufrufen kann. Zunächst
ein
Beispiel
für
die
Definition
eines
Programms
vom
Typ
STORED_PROCEDURE: EXEC dbms_scheduler.create_program (program_name => 'SP', program_type => 'stored_procedure', program_action => 'job_sp', enabled => TRUE, comments => 'Just a test...')
Definierte Programme können in der View dba_scheduler_programs angezeigt werden. Für Programme vom Typ STORED_PROCEDURE und EXECUTABLE können Argumente fest definiert werden. Hierzu gibt es einen eigenen Satz an Definitions- und Übergabeprozeduren im Package dbms_scheduler. Im angegebenen Beispiel wird das Programmattribut enabled auf TRUE gesetzt. Damit ist das Programm sofort einsetzbar. Wird das Attribut nicht angegeben, wird FALSE angenommen. Dies gilt auch für Schedules und Jobs. Zum Aktivieren kann die Prozedur dbms_scheduler.enable genutzt werden.
2
Das Setzen von globalen Scheduler-Attributen wird weiter unten noch genauer behandelt.
270
Administrationswerkzeuge
Schedules Ebenfalls getrennt vom eigentlichen Job können Schedules definiert werden. Der Schedule steht für ein Ausführungszeitschema. Zunächst auch hierzu ein Beispiel: EXEC dbms_scheduler.create_schedule (schedule_name => 'M_SCHED', repeat_interval => 'FREQ=MINUTELY;BYSECOND=0', comments => 'Will it Work?')
Zur Abfrage der Schedules dient die View dba_scheduler_schedules. Jeder, der bereits einige Jobs mit Hilfe des alten Schedulers implementiert hat, wird wohl beim Anblick des repeat_interval-Parameters erleichtert aufatmen: Die interval-Funktion des alten Schedulers erlaubte zwar durch den Zugriff auf die komplette DATE-Arithmetik des Oracle-Kerns die Berechnung praktisch beliebiger Intervalle, die Lesbarkeit der resultierenden Ausdrücke war jedoch nicht immer gegeben. Zum Vergleich die beiden Ausdrücke für »genau zu jeder Viertelstunde«: Alter Scheduler: trunc(sysdate, 'HH24') + ((trunc(to_char(sysdate, 'MI') / 15) + 1) * 15) / (24 * 60)
Neuer Scheduler: FREQ=HOURLY;BYMINUTE=0,15,30,45;BYSECOND=0
Der repeat_interval-Parameter kann entweder mit einem kalendarischen Ausdruck oder einer PL/SQL-Funktion gesetzt werden. Das o.a. Beispiel für viertelstündlich dokumentiert bereits die Struktur sowie die Lesbarkeit der kalendarischen Ausdrücke. Ein kalendarischer Ausdruck besteht aus einer FREQ-Klausel, einer optionalen INTERVAL-Klausel sowie optional einer oder mehreren BY-Klauseln. Die FREQ-Klausel legt die Ausführungsfrequenz auf die Werte YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY oder SECONDLY fest. Die INTERVAL-Klausel legt fest, wie viele Einheiten der FREQ-Klausel zwischen zwei Ausführungen vergehen sollen. Die BY-Klausel(n) legt (legen) weitere Details für die gewählte Frequenz fest. Es gibt die Varianten BYMONTH, BYWEEKNO, BYYEARDAY, BYMONTHDAY, BYDAY, BYHOUR, BYMINUTE sowie BYSECOND. BY-Klauseln können Wertelisten enthalten. Somit kann die Frequenz »alle 10 Minuten« z.B. mit folgenden Varianten dargestellt werden: FREQ=MINUTELY;INTERVAL=10 FREQ=HOURLY;BYMINUTE=0,10,20,30,40,50
Für undefinierte obere Grenzen von BY-Klauseln können negantive Werte eingesetzt werden, z.B. BYMONTHDAY=-1 für den letzten Tag im Monat. Weitere Details zu kalendarischen Ausdrücken können z.B. dem Handbuch »PL/ SQL Packages and Types« entnommen werden.
Scheduler
271
PL/SQL-Funktionen als Alternative zum kalendarischen Ausdruck zur Definition von repeat_interval müssen als Ergebnistyp DATE oder TIMESTAMP liefern. Falls durch repeat_interval keine Zeitzone definiert wird, wird diese vom Wert der Variablen start_date übernommen. Falls start_date ebenfalls keine Zeitzone definiert, wird sie vom globalen Scheduler-Attribut default_timezone übernommen.3 Globale Scheduler-Attribute können mit Hilfe der Prozedur dbms_scheduler.set_scheduler_attribute gesetzt und mit der Prozedur dbms_scheduler.get_scheduler_attribute oder der View dba_scheduler_global_attribute abgefragt werden (obwohl Letztere im Handbuch »Oracle Database Reference« nicht definiert ist). Jobs Nachdem Schedule und Programm definiert sind, kann man zur Definition des Jobs übergehen. Im einfachsten Fall werden hierbei ein Programm und ein Schedule verknüpft: EXEC dbms_scheduler.create_job (job_name => 'LS_JOB', program_name => 'LS', schedule_name => 'M_SCHED', enabled => TRUE)
Man kann die Definition von Programmen und Schedules weglassen und die JobArgumente job_type, job_action, start_date und repeat_interval direkt setzen. Im Sinne einer Strukturierung der Jobs ist dies jedoch nicht empfehlenswert. Übersicht über Jobs erlangt man durch Abfragen der View dba_scheduler_jobs. Ähnlich wie beim alten Scheduler findet man Dinge wie last_start_date, next_run_date, nls_env und einige weitere Informationen. Anstelle der Gesamtlaufzeit aller Runs findet man die last_run_duration für die Laufzeit der letzten Ausführung. Zusätzliche Informationen über jeden einzelnen Start eines Jobs findet man in den Views dba_scheduler_job_log und dba_scheduler_job_run_details. Diese beiden Views ersparen z.B. bei der Problemanalyse das lästige Suchen nach und in Tracefiles der Jobprozesse. Setzen von Attributen Attribute für Programme, Schedules und Jobs werden zunächst beim Erzeugen gesetzt, die meisten stehen dann auf ihrem Standardwert. Zum Ändern der Attribute wird die Prozedur dbms_scheduler.set_attribute(, , )
genutzt. Die Attribute sind in den dba_scheduler-Views sofort sichtbar; allerdings wirken sie sich nicht mehr auf bereits laufende Ausführungen aus. Die Liste der möglichen Attribute ist sehr lang und kann im Handbuch »PL/SQL Packages and Types« nachgeschlagen werden. 3
Das erwähnte globale Scheduler-Attribut default_timezone ist bei einer neu kreierten Datenbank zunächst nicht gesetzt. Es wird dringend empfohlen, dies z.B. mit EXEC dbms_scheduler.set_scheduler_attribute ('default_timezone', 'Europe/Berlin') zu setzen. Nach einem Neustart der Instanz funktioniert dann – meist – alles wie erwartet.
272
Administrationswerkzeuge
Fehlerbehandlung Der neue Scheduler unterscheidet im Gegensatz zum alten Scheduler Scheduled Runs und Retries. Scheduled Runs beziehen sich grundsätzlich auf das mit repeat_interval festgelegte Ausführungsschema. Wenn einer der Scheduled Runs einen Fehler verursacht, wird dieser bis zu sechs Mal erneut gestartet (Retry), falls das Jobattribut restartable auf TRUE gesetzt ist (was standardmäßig der Fall ist). Dabei findet der erste Retry eine Sekunde nach dem Ende des Scheduled Runs statt, die Wartezeit für weitere Retries ist jeweils um den Faktor zehn länger. Falls ein Retry erfolgreich ist, alle sechs Retries abgeschlossen sind und zu Fehlern geführt haben oder der Ausführungszeitpunkt des nächsten Retrys nach dem Ausführungszeitpunkt des nächsten Scheduled Runs liegt, werden keine Retries mehr gestartet. Damit wird der aktuelle Scheduled Run als beendet gewertet und der run_count in dba_scheduler_jobs um eins erhöht. Wenn alle sechs Retries zu Fehlern führen, wird auch failure_count um eins erhöht. In der View dba_scheduler_job_log werden Scheduled Runs im Feld operation als RUN gekennzeichnet, Retries als RETRY_RUN. Details zur Fehlerursache findet man in der View dba_scheduler_job_run_details. Diese Views sind zunächst nicht destruktiv, d.h., man findet Informationen über alle möglichen Ausführungen (und -versuche) auch nachträglich in den Views. Das Jobattribut max_failures kann auf einen Wert zwischen eins und 1.000.000 gesetzt werden (Standard ist NULL) und führt dazu, dass der Job auf DISABLED gesetzt wird, falls die angegebene Anzahl von aufeinander folgenden Scheduled Runs zu Fehlern führen. Der Jobstatus (state) wechselt von SCHEDULED auf BROKEN. Achtung! Falls das Jobattribut auto_drop auf TRUE steht (Standard!), wird der Job beim Erreichen von max_failures aus der Jobtabelle gelöscht! Jobklassen, Fenster und Fenstergruppen Jobklassen Mit Hilfe von Jobklassen können einige übergeordnete Parameter gesetzt werden. Dabei gelten die Parameter für alle Jobs, die der Jobklasse zugeordnet sind, d.h., die Jobklasse ist wiederum ein Attribut der einzelnen Jobs. Folgende Parameter sind vorhanden: Durch die Zuordnung einer resource_consumer_group können z.B. Prioritäten von Jobs untereinander bzw. im Verhältnis zum Gesamtsystem geregelt werden. Durch die Benennung eines service werden Jobs ausschließlich auf der oder den Instanzen ausgeführt, die den benannten service in ihrem Serverparameter service_names gesetzt haben. Damit ist es z.B. möglich, Jobs in einer RAC-Umgebung einzelnen Instanzen oder Instanzgruppen zuzuordnen. Der logging_level kann zwischen OFF, RUNS und FULL ausgewählt werden. Dies hat Einfluss darauf, ob kein Logging, lediglich Logging für Ausführungen oder
Scheduler
273
für Ausführungen sowie Änderungsoperationen (Enable, Disable, Setzen von Attributen usw.) erfolgt. Die Aufbewahrungsfrist für Log-Informationen (Standard: 30 Tage) wird mit log_history auf eine Anzahl von 1 bis 999 Tagen gesetzt. Es gibt eine Standard-Jobklasse default_job_class, der alle Jobs standardmäßig zugeordnet werden. Dabei ist der logging_level auf RUNS eingestellt, die anderen Parameter sind mit NULL vorbesetzt. Eine weitere Jobklasse auto_tasks_job_class ist grundsätzlich vorhanden. Diese unterscheidet sich von der default_job_class nur dadurch, dass die resource_ consumer_group mit auto_task_consumer_group voreingestellt ist. Fenster und Fenstergruppen Die Definition von Fenstern und Fenstergruppen ermöglicht grundsätzlich zwei Dinge: 1. Die Aktivierung von verschiedenen Ressourcenplänen zu unterschiedlichen Zeitpunkten im Zusammenspiel mit den Konsumentengruppen der Jobklassen 2. Die Definition von Ausführungszeitfenstern bzw. Gruppen solcher Zeitfenster für Jobs, die ausschließlich zu bestimmten Zeiten laufen sollen Zur Verdeutlichung betrachten wir einen der vordefinierten Jobs im neuen Scheduler, den gather_stats_job. Dieser Job ist für das automatische Sammeln von Statistiken für Datenbankobjekte mit der Prozedur dbms_stats.gather_database_stats_ job_proc verantwortlich und ist im Schema sys untergebracht. Er ist weiterhin der Jobklasse auto_tasks_job_class und der Fenstergruppe maintenance_window_group zugeordnet. Diese Fenstergruppe enthält die Fenster weeknight_window, das an Wochentagen jeweils um 22:00 Uhr beginnt und 8 Stunden dauert, und weekend_ window, das Samstags um 0:00 Uhr beginnt und zwei Tage dauert. Durch diese Zuordnung läuft der Statistikjob nachts bzw. am Wochenende genau im beschriebenen Fenster. Dadurch, dass der Job das Attribut stop_on_window_close auf TRUE gesetzt hat, wird der Job abgebrochen, sobald das Fenster (jeweils nach der o.a. Dauer) geschlossen wird. Berechtigungen Im Gegensatz zur sehr rudimentären Berechtigungsverwaltung des alten Schedulers (EXECUTE-Privileg auf dbms_job reicht zum Anlegen und Administrieren von Jobs; jeder Benutzer kann ausschließlich auf seine eigenen Jobs zugreifen) bietet der neue Scheduler einige zusätzliche Möglichkeiten in diesem Bereich an. Systemprivilegien und Rollen Zunächst gibt es einige Systemprivilegien, die das Arbeiten mit dem Scheduler ermöglichen. CREATE JOB erlaubt das Anlegen von Programmen, Schedules und Jobs im eigenen Schema. Wie bei vielen anderen Privilegien erlaubt das verwandte CREATE ANY JOB
diese Aktionen in beliebigen anderen Schemata.
274
Administrationswerkzeuge
Die Privilegien EXECUTE ANY PROGRAM und EXECUTE ANY CLASS erlauben die Erstellung von Jobs mit Bezug auf beliebige Programme bzw. Jobklassen anderer Schemata. Das Privileg MANAGE SCHEDULER erlaubt weiterhin, Jobklassen, Fenster und Fenstergruppen zu definieren, deren Attribute zu ändern sowie über die entsprechenden Views Informationen zu sehen. Die Rolle scheduler_admin enthält die o.a. Systemprivilegien (jeweils WITH ADMIN OPTION). Die Rolle selber ist in der Rolle dba enthalten. Objektprivilegien Wie bei Prozeduren kann gezielt ein EXECUTE-Privileg auf Programmen und Jobklassen vergeben werden. Dadurch kann im berechtigten fremden Schema ein Job mit Bezug auf das Programm bzw. ein beliebiges Programm der Jobklasse erstellt werden. Mit dem ALTER-Privileg kann für Programme, Schedules und Jobs die Erlaubnis zur Administration vergeben werden. Für Programme, Schedules, Jobs und Jobklassen kann weiterhin das ALL-Privileg vergeben werden, das noch umfassender ist. Migration und Ausblick Bei der Bewertung des neuen Schedulers tritt natürlich auch die Frage der Migration auf. Falls man bereits eine komplexe Job-Umgebung mit dem alten Scheduler betreibt, stellt sich natürlich auch die Frage nach einer automatisierten Übernahme der alten Jobs. Hierbei sollten folgende Argumente beachtet und abgewägt werden: Automatisch erstellte Jobs, z.B. zum Refresh von Materialized Views, sollten zunächst nicht migriert werden, da eine Modifikation der Refresh-Parameter der Materialized Views beim Versuch, den alten Job automatisch zu ändern, ins Leere greifen würde. Beim alten Scheduler sind häufig sehr komplexe next_date-Klauseln zu finden, da geplante Auszeiten und sonstige Unregelmäßigkeiten durch keinen anderen Mechanismus abgefangen werden können. Beim Übergang auf den neuen Scheduler sollten hierfür Mechanismen wie kalendarische Ausdrücke, Fenster und Fenstergruppen eingesetzt werden. Dies ist jedoch kaum automatisiert zu machen, sondern erfordert eine »intelligente« Migration – leider auf manuellem Weg. Zunächst wird also ein Mischbetrieb mit altem und neuem Scheduler in Frage kommen, da es bei einigen Jobs noch keinen Sinn macht, diese zum neuen Scheduler zu migrieren. Ein wesentliches neues Feature des Schedulers ist die Möglichkeit, Programme auf Betriebssystemebene zu starten und somit z.B. die Datenbanksicherung mit einem Recovery-Manager-Skript in die Datenbank selbst zu integrieren. Für das nächste Release wurde von Oracle u.a. die Fähigkeit versprochen, Verknüpfungen für Jobs definieren zu können, wie z.B. »Job 3 startet, wenn Job 1 und Job 2 fehlerfrei abgearbeitet sind«. Anwender, die eine Migration ihrer Datenbankjobs von größeren Jobkontrollsystemen auf den neuen Scheduler in Erwägung ziehen, vermissen dies in den allermeisten Fällen.
Weitere Werkzeuge
275
Weiterhin gibt es offensichtliche Lücken, die noch ergänzt werden müssen. Die View dba_scheduler_jobs enthält das Feld max_run_duration, das nach der Beschreibung im Handbuch »Oracle Reference« nicht etwa die längste bis jetzt aufgetretene Laufzeit eines Jobs enthält, sondern eine Vorgabe, wie lange der Job maximal laufen darf. Dies ist durchaus eine interessante Möglichkeit – allerdings fehlt ein Weg, dieses Feld zu besetzen.
6.3
Weitere Werkzeuge
Neben den von Oracle mitgelieferten Werkzeugen haben sich auf dem Markt viele Tools für die Arbeit mit der Oracle-Datenbank etabliert. Aus dieser Liste greifen wir uns exemplarisch zwei sehr verbreitete Werkzeuge heraus: TOAD von Quest Software Inc. (www.quest.com) und Hora von KeepTool GmbH (www.keeptool.com). Beide Tools werden oft dort eingesetzt, wo es darum geht, schnell auf die OracleDatenbanken zugreifen zu können, ohne zusätzliche Software auf dem Server installieren zu müssen. Beide Produkte können nur auf MS-Windows-Rechnern betrieben werden und brauchen einen Oracle-Client für die Kommunikation zur Datenbank. Zunächst gehen wir noch kurz auf das alt bewährte SQL*Plus ein.
6.3.1 SQL*Plus Dieses Tool gibt es seit Oracle Version 6 und wird von vielen Administratoren immer noch vielseitig eingesetzt. Zum allgemeinen Verständnis: SQL*Plus ist nicht die SQL-Sprache von Oracle, sondern ein Kommandozeilen-Editor, um SQL an die Oracle-Datenbank zu senden. Das »Plus« steht hierbei für einige zusätzliche Befehle, die über den Standard-SQL-Umfang hinausgehen. Dazu gehören unter anderem einige einfache Formatierungen (Zeilen und Seitenlängen, Titel und Nummerierung) und für die Verwaltung der Datenbank. So kann z.B. mit SQL*Plus die Datenbank gestartet und gestoppt oder die Archivierung aktiviert werden. Da die Standardeinstellungen in der Regel unzureichend sind, empfiehlt es sich, die Datei glogin.sql anzupassen (Verzeichnis: $ORACLE_HOME/sqlplus/admin), in der z.B. die Zeilen- und Seitenlänge festgelegt werden können. Weitere anwenderspezifische Anpassungen können in der Datei login.sql vorgenommen werden. Die Lage dieser Datei wird über die Umgebungsvariable SQLPATH bestimmt, wobei hier eine Liste von Pfaden durch Doppelpunkt getrennt angegeben werden kann. Im Folgenden ein Beispiel für glogin.sql oder login.sql: set set set set
pagesize 66 linesize 100 echo on timing on
Listing 6.9: Beispiel für login.sql
276
Administrationswerkzeuge
Mit den oben angegebenen Einträgen wird die Seitenlänge (pagesize) auf 66 Zeilen und die Zeilenlänge (linesize) auf 100 Zeichen geändert. Außerdem wird jeder Befehl vor der Ausführung noch einmal ausgegeben (set echo on) und die Ausführungsdauer zum Schluss angezeigt (set timing on). SQL*Plus wird ebenfalls oft für das Tuning von SQL-Befehlen eingesetzt. Dabei wird der SQL-Befehl über SQL*Plus ausgeführt, und statt (oder zusätzlich zum) Ergebnis werden der Ausführungsplan sowie Informationen über die verarbeiteten Blöcke angegeben. Nähere Informationen hierzu finden Sie in Kapitel 11. Als Erweiterung zum SQL*Plus gibt es den iSQL*Plus, wobei auf dem Server eine J2EE-Instanz gestartet werden muss. Anschließend kann über einen Internet Explorer in der Regel über Port 5560 auf die Anwendung zugegriffen werden. Ansonsten unterscheidet sich die Verwendung nur unwesentlich von der des SQL*Plus.
6.3.2 TOAD Das Produkt TOAD steht für Tool for Oracle Application Development und wurde ursprünglich als Freeware für die Entwicklung von PL/SQL-Programmen angeboten. Quest Software Inc. hat das Tool 1999 samt Entwickler gekauft und vertreibt es heute in unterschiedlichen Konfigurationen für den klassischen Entwicklerbereich, aber auch als Werkzeug für Datenbankadministratoren. Daneben gibt es eine große »Gemeinde« unter www.toadsoft.com, über die auch weiterhin eine Freeware zur Verfügung steht4. Die aktuelle Version (8.5) unterstützt die wesentlichen neuen Funktionen von Oracle 10g wie z.B. den neuen Scheduler. Es gibt im TOAD eine Reihe von Tools, die im Wesentlichen die Aufgabe haben, SQL-Befehle zu erstellen und die Ergebnisse in einem oder mehreren Ergebnisfenstern (so genannten Grids) darzustellen. Diese Ergebnismengen können dann komfortabel z.B. als Excel-Datei oder Tabellenblatt abgespeichert werden. Für Entwickler und Anwender ist die Möglichkeit, sich für jedes Datenbankobjekt oder ein gesamtes Schema ein Skript erstellen zu lassen, sicherlich eine wichtige Funktion. Ergänzt wird das Produkt durch die grafische Modellierung von SQL-Befehlen im SQL-Modeler und die Darstellung von Abhängigkeiten im ER-Diagrammer. In der Abbildung 6.20 ist der SCHEMA BROWSER mit der Option »SAVE GRID CONTENTS« dargestellt. Neben der Abspeicherung als Excel-Datei ist sicherlich auch die Möglichkeit, die Daten als SQL-Loader oder »Insert-Befehl« abzuspeichern, interessant. Neben diesen Standardfunktionalitäten gibt es bereits in der Basisversion einige Tools für die Administration von Datenbanken. Unter anderem gehört der in Abbildung 6.21 gezeigte Session Browser dazu, der die Überwachung von SessionInformationen einer Datenbank ermöglicht.
4
Die Version ist allerdings sehr eingeschränkt und veraltet, so dass derzeit der Zugriff auf Oracle 10g-Datenbanken nur bedingt möglich ist.
Weitere Werkzeuge
Abbildung 6.20: TOAD Schema Browser
Abbildung 6.21: Session Browser
277
278
Administrationswerkzeuge
Durch Zusatzmodule kann der TOAD für unterschiedliche Benutzerkreise erweitert werden. Hier bietet sich das DBA-Modul an, mit dem z.B. Tablespaces und Datafiles verwaltet werden können. Außerdem ist hierin der LogMiner als grafische Oberfläche integriert, so dass es relativ einfach ist, Informationen aus den RedologDateien auszulesen.
6.3.3 Hora Das Werkzeug Hora wird von der Firma Keep Tool5 in Berlin hergestellt. Es ist als Clientanwendung auf allen gängigen Windows-Plattformen ab Windows 95 verfügbar und wendet sich gleichermaßen an Datenbankadministratoren wie Anwendungsentwickler. Hervorzuheben sind an dieser Stelle die kompakten, übersichtlichen Navigationsmöglichkeiten, die alle wesentlichen Funktionsbereiche des Alltagsgeschäftes abdecken. Über thematisch gegliederte »Pages« lassen sich zusammengehörige Menüs aufrufen, die ihrerseits wieder mehrdimensionale Navigationsmöglichkeiten eröffnen. Eine Favoritenseite erlaubt die individuelle Zusammenstellung von einzelnen Menüpunkten. Die Abbildung 6.22 zeigt das Tabellenmenü der Standardseite mit Spalteninformationen und – davon abhängig – zugehörigen Constraints. Die oberen TabReiter ermöglichen die Navigation in unterschiedlichen Kontexten eines Tabellenoder View-Objektes.
Abbildung 6.22: Standardseite von Hora 5
www.keeptool.com
Weitere Werkzeuge
279
Die Anforderungen der Datenbankverwalter werden über die DBA-Seite mit ihren Untermenüs abgedeckt. Neben einer Performance-Anzeige mit Diagrammen der wichtigsten Metriken werden Menüs zu den Funktionsbereichen Tablespaces, Benutzerverwaltung, Sessions, Datenbank, Redolog, Auditing und Data Dictionary angeboten. Die Abbildung 6.23 zeigt den Bereich »SESSIONS« mit Informationen zu einzelnen Sessions, wie z.B. den aktuellen SQL-Befehlen, Locking und Statistiken.
Abbildung 6.23: Sessionmonitor von Hora
Aktionen, die über Menüs generiert werden, können optional vor der Ausführung in SQL-Form angezeigt und bei Bedarf modifiziert werden. Ein separater SQLBereich kann zur Ablage von eigenen SQL-Skripten genutzt werden. Dieses SQLRepository kann in der Windows Registry oder direkt im Filesystem gespeichert werden.
280
Administrationswerkzeuge
Mehrere aktive Datenbankverbindungen lassen sich in jeweils eigenen Fenstern anzeigen. Hora wird ergänzt durch weitere Werkzeuge, die folgende Funktionsbereiche abdecken: Debugging von PL/SQL-Code Generierung von HTML-Dokumenten zur Dokumentation der betreffenden Datenbank SQL-Editor ER-Diagrammer zur Darstellung von Tabellen und ihren Relationen Generierung von DDL-Befehlen mit umfangreichen Filtermöglichkeiten Neben diesen vorgestellten Werkzeugen gibt es viele andere, die sicherlich erwähnenswert wären. Wir haben uns in der Kürze auf die beschränkt, die wir selber in Projekten eingesetzt – und an die wir uns gewöhnt haben.
Zugriff auf die Datenbank 7.1
Oracle Net
Oracle Net ist eine Softwareschicht, die für den transparenten Zugriff von praktisch beliebigen Clients auf Oracle-Datenbanken sorgt. Mittlerweile gibt es diverse Varianten der Oracle Net-Implementierung – als installierter Oracle Client, als Emulation eines solchen Clients mit Hilfe von Java in der Thin JDBC-Schnittstelle oder als eine Sammlung von dynamischen Laufzeitbibliotheken namens Instant Client. Lediglich in einer 3-Schichten-Architektur kommt Oracle Net auf dem Client-Rechner nicht mehr vor. Hierbei kommt meist Oracle Net oder JDBC auf dem Applikationsserver (in der mittleren Schicht) zum Einsatz. Die umfassende Darstellung der Oracle Net-Architektur ist sehr umfangreich und abstrakt. Der hier gewählte Ansatz zur Darstellung von Oracle Net ist pragmatischer Natur: Die Beschreibung der Architektur, der Oracle Net-Komponenten sowie ihrer Konfiguration wird ineinander verschachtelt vorgenommen, so dass die wichtigen Zusammenhänge deutlich werden. Auf eine vollständige Architekturbeschreibung wird daher verzichtet.
7.1.1 Architektur und Konfiguration Die allgemeine Diskussion von Anwendungsarchitekturen (also Client/Server, 3Schicht-Architektur usw.) würde den Rahmen dieses Buches sprengen. Zur Erläuterung der Oracle Net-Architektur betrachten wir aus Richtung der Datenbank das nächste Stück Software, das am anderen Ende der Netzwerkverbindung sichtbar ist, und nennen dies Client. In den meisten Fällen wird auf dem Client auch eine Oracle-Installation durchgeführt. Hierbei werden die jeweils passenden Schnittstellen für die geplanten Anwendungen ausgewählt: OCI und OCCI für Anwendungen, die mit C bzw. C++ programmiert wurden, ODBC für die »traditionelle« MS-kompatible Schnittstelle, Oracle Provider for OLE DB und Oracle Data Provider for .Net für modernere MS-konforme Programme, Oracle Objects for OLE als Oracle-Alternative auf der MS-Plattform, JDBC OCI für Java-Programme usw. Zumindest fast alle Schnittstellen haben als Gemeinsamkeit, dass Oracle Net als Basis für Verbindungen zum Oracle Server dient und im Rahmen des Oracle Clients installiert und konfiguriert sein muss. Thin JDBC ist die eine Ausnahme im JavaUmfeld, die als Komponente z.B. in Applets enthalten ist und somit auf Rechnern laufen kann und muss, die keine Oracle Client-Installation besitzen. Die andere Ausnahme ist der Instant Client, der einerseits nicht mit dem Universal Installer installiert werden muss und andererseits ohne Konfigurationsdateien auskommt (und hierzu die Easy Connect-Methode verwendet).
282
Zugriff auf die Datenbank
Instanzen und Dienste An dieser Stelle dürfte als bekannt vorausgesetzt werden können, dass eine OracleInstanz einen Namen – die ORACLE_SID – besitzt, der sie zumindest auf einem Rechner eindeutig identifiziert. In älteren Oracle-Versionen (Oracle8 und älter) wurde der Instanzname als einziges Kriterium, eine bestimmte Instanz zu adressieren, genutzt. Dies hat sich jedoch aus diversen Gründen als unpraktisch herausgestellt: In RACUmgebungen musste man z.B. in früheren Oracle Net-Versionen die Instanzen identisch benennen, da man zwar eine Liste von Netzwerkadressen, etwa für LoadBalancing-Zwecke, angeben konnte, aber nur einen Wert für die ORACLE_SID. Ein Cluster, in dem alle Instanzen gleich heißen, ist jedoch für den Administrator nicht einfach zu verwalten ... Aus diesem Grund wird hier etwas näher auf Oracle-Dienstnamen eingegangen. Dienste innerhalb der Datenbank sind ein dynamisches und daher äußerst flexibles Gebilde, um den Verbindungsaufbau zu einer Instanz zu gestalten. Grundsätzlich gilt, dass es zwei vordefinierte Dienstnamen (SYS$USERS und SYS$BACKGROUND) sowie einen aus den Werten der Systemparameter db_name und db_domain zusammengesetzten Dienstnamen (.) gibt. Mit dem Systemparameter service_names kann die Liste der aktiven Dienstnamen modifiziert werden, wobei die vordefinierten Dienstnamen immer aktiv sind; sie müssen also nicht in der Liste auftauchen. service_names ist dynamisch auf Systemebene veränderbar (d.h. mit ALTER SYSTEM online veränderbar). Vorsicht ist durch die Tatsache geboten, dass immer die komplette Liste der aktiven Dienste geändert wird, d.h. durch den Befehl ALTER SYSTEM SET service_names = 'NEWSERVICE.HOME.COM' SCOPE = MEMORY;
wird nicht etwa der Dienst NEWSERVICE.HOME.COM zusätzlich aktiviert, sondern anstelle der vorher aktiven Liste der Dienste. Zusätzliche Flexibilität liefert das PL/SQL-Modul dbms_service. Zunächst muss man sich daran gewöhnen, dass ein Dienst innerhalb des Moduls zwei Namen hat: den Dienstnamen, der innerhalb des gesamten Moduls verwendet wird, und den Netzwerknamen, so wie er im Zusammenhang mit Oracle Net verwendet wird. Dabei hat der Dienstname eine Maximallänge von 64 Zeichen, der Netzwerkname bis zu 512 Zeichen. Es hat sich bewährt, falls es irgendwie möglich ist, beide Namen gleich zu lassen (und bitte immer mit Domäne!). Der Netzwerkname kommt lediglich beim Anlegen eines Dienstes vor und wird damit dem Dienstnamen zugeordnet: EXECUTE dbms_service.create_service ( service_name => 'NEWSERVICE.HOME.COM', network_name => 'NEWSERVICE.HOME.COM')
Damit steht der Dienst jedoch noch nicht zur Verfügung. Erst durch das Starten des Dienstes kann auf ihn zugegriffen werden: EXECUTE dbms_service.start_service – ( service_name => 'NEWSERVICE.HOME.COM', instance_name => 'SID1')
Oracle Net
283
Die Angabe von instance_name ist optional und ermöglicht, den Dienst in einer bestimmten Instanz eines RAC-Clusters zu starten. Dies eröffnet später die Möglichkeit, bestimmte Verbindungen gezielt auf einzelne bzw. Gruppen von RACInstanzen zu leiten. Mit der Prozedur dbms_service.stop_service (mit gleichen Parametern wie beim Start) können Dienste ebenfalls wieder gestoppt werden. Auf der aktuellen Instanz (diejenige im RAC, bei der man angemeldet ist) können mit dem Aufruf EXECUTE dbms_service.disconnect_session ( service_name => 'NEWSERVICE.HOME.COM')
alle zu einem Dienst gehörenden Sitzungen beendet werden. Um einen Überblick zu bekommen, welche Sitzungen hiervon betroffen sein werden, enthält die View v$session die Spalte service_name. Zu guter Letzt können Dienste mit dbms_service.delete_service wieder gelöscht werden. Im Data Dictionary sind einige hilfreiche Views zur Administration von Diensten enthalten: all_services bzw. dba_services bieten wie v$services einen Überblick über alle vorhandenen Dienste; v$active_services verrät, welche davon zurzeit aktiv sind. Oracle Net-Architektur Die Client-Server-Architektur der Oracle Database zeichnet sich im Normalfall dadurch aus, dass ein Programm beliebiger Art (der Client) mit einem ihm eigens zugewiesenen (dedicated) Prozess des Oracle Servers kommuniziert, der zur entsprechenden Instanz gehört. Dieses Modell wird deshalb – im Gegensatz zur SharedServer-Architektur, die weiter unten behandelt wird – auch als Dedicated-ServerArchitektur bezeichnet. Schematisch sieht dies wie folgt aus:
Abbildung 7.1: Oracle Net-Architektur
284
Zugriff auf die Datenbank
Der Client nutzt als Aufrufschnittstelle zum Server das Oracle Call Interface OCI; der Server Oracle Program Interface OPI. Im Allgemeinen antwortet der Server auf einen Aufruf aus dem OCI mit einem Aufruf des OPI. Dies erfolgt im Normalfall synchron, d.h., der Client ist blockiert, bis die Antwort des Servers eingetroffen ist. Die Schichten TTC (Two Task Common), TNS (Transparent Network Substrate) und Protocol Support gehören zu Oracle Net. Mit »Netzwerk« sind die unter dem Protocol Support liegenden Schichten der Netzwerkschichten (layer) zusammengefasst. Die Architektur basiert auf dem ISO/OSI 7-Schichten-Modell. In der folgenden Abbildung sind die sieben Schichten des Standardmodells den Oracle Net-Schichten zugeordnet:
Abbildung 7.2: ISO/OSI 7-Schichten-Modell und Oracle Net
Die TTC-Schicht ist für die Konvertierung von Zeichensätzen und Datenformaten zuständig. TNS ist die Hauptkomponente von Oracle Net und für korrekten Aufbau und Verwaltung von Verbindungen zwischen Client und Server verantwortlich. TNS wird manchmal auch als Net Foundation Layer bezeichnet. Innerhalb von TNS sind u.a. Dienste zur Namensauflösung sowie Sicherheitsfunktionen untergebracht. Mit Protocol Support sind letztendlich die Interfaces in die verschiedenen Protokolle gemeint, die Oracle Net unterstützt. Dies sind: TCP/IP, TCP/IP mit SSL, Named Pipes und SDP.1 In der Thin JDBC-Schnittstelle sind alle Oracle Net-Schichten in Java implementiert; JavaNet entspricht im Wesentlichen TNS. Als Protokoll wird ausschließlich TCP/IP unterstützt. Verbindungsaufbau durch den Listener Eine zentrale Aufgabe des TNS ist der Verbindungsaufbau. Da diese Phase zwingend notwendig für eine Verbindung zwischen Client und Server ist, sollte deren Funktionsweise von großem Interesse sein.
1
Oracle Net ist also kein Netzwerkprotokoll! Auf dieses Gerücht stößt man immer wieder ...
Oracle Net
285
Auf der Serverseite ist der Listener für den Verbindungsaufbau zuständig. Dies ist ein eigenständiger, insbesondere von jeglicher Instanz unabhängiger Prozess, der mit der Aufgabe beschäftigt ist, auf mindestens einem Netzwerk-Endpunkt zu »horchen«. Mit Netzwerk-Endpunkt ist im Falle von TCP/IP ein Port einer Schnittstelle bzw. IP-Adresse gemeint. Die Beziehung zwischen Instanzen und Listenern ist eine oft diskutierte Frage. Grundsätzlich sind alle denkbaren Konstellationen möglich, z.B. Jede Instanz hat ein eigenes ORACLE_HOME und einen eigenen Listener. Jede Instanz hat ein eigenes ORACLE_HOME; es gibt aber nur einen einzigen Listener. Es gibt mehrere ORACLE_HOMEs mit unterschiedlich vielen Instanzen und einem Listener pro ORACLE_HOME. Es gibt ein ORACLE_HOME mit vielen Instanzen und einem Listener. Man sollte lediglich beachten, dass man für den Fall, dass ein Listener Verbindungen für Instanzen aus verschiedenen ORACLE_HOMEs aufbaut, grundsätzlich den »neuesten« Listener nehmen sollte – in den allermeisten Fällen ist er entsprechend abwärtskompatibel, so dass ältere Versionen unterstützt werden, und er ist dann in der Lage, für die Instanzen der neueren Oracle-Versionen auch deren Oracle Net Features zu nutzen. Insbesondere gilt für Oracle 10g, dass der Listener zwingend eine 10.1er-Versionsnummer haben muss – ältere Listener können keine Verbindungen zu Oracle 10gInstanzen aufbauen.2
Abbildung 7.3: Der Oracle Net Listener
2
Mit früheren Versionen war dies durchaus möglich; ein Listener mit Version 8.1 kann durchaus zu Instanzen mit Version 9.x Verbindungen aufbauen.
286
Zugriff auf die Datenbank
Ein Client, der den Netzwerk-Endpunkt des Listeners kennen muss, wendet sich unter Angabe seiner Kontaktdaten mit einer Verbindungsanfrage beim Listener. Wenn alle Kontaktdaten zu einer der vom Listener gehörenden Instanzen passen, startet der Listener bei eben dieser Instanz einen Dedicated-Server-Prozess. Im Normalfall wird die Verbindungsanfrage des Clients an den Serverprozess übergeben, so dass dieser im nächsten Schritt dem Client antwortet und die Verbindung somit bereits aufgebaut ist. Diese vom Listener bevorzugte Methode wird auch als direct hand-off bezeichnet. Alternativ hierzu ist auch ein Redirect möglich, bei dem der Listener die Kontaktdaten des von ihm aufgebauten Serverprozesses an den Client übergibt. Hierbei ist die Verbindung zwischen Client und Serverprozess erst einen Schritt später aufgebaut. Die tatsächlich verwendete Methode hängt vom Betriebssystem und der Netzwerkkonfiguration ab – genauen Aufschluss liefert hier wohl nur ein Netzwerktrace. Die Basiskonfiguration Zu einer Basiskonfiguration gehören mindestens ein Server und ein Client. Diese besitzen jeweils eine oder mehrere Konfigurationsdateien. Im Normalfall befinden sich alle Oracle Net-Konfigurationsdateien im Verzeichnis $ORACLE_HOME/network/ admin. Falls man die Konfiguration für verschiedene Installationen getrennt durchführen möchte, z.B. weil man in verschiedenen Umgebungen arbeitet, ist dies so richtig; oft wird aber eine Speicherung an einer zentralen Stelle gewünscht, die nicht unter dem Installationsverzeichnis $ORACLE_HOME liegt. Als Alternative kann man z.B. $ORACLE_BASE/network/admin verwenden. Dies hat zwei Vorteile: 1. Bei mehreren ORACLE_HOMEs muss die Konfiguration nur einmal durchgeführt werden; redundante Speicherorte werden vermieden. 2. Beim Löschen eines Installationsverzeichnisses gehen keine Konfigurationsdaten verloren. Damit die Oracle-Software (Client und Server) in einem anderen als dem Standardverzeichnis nach Oracle Net-Konfigurationsdateien sucht, muss die Variable TNS_ADMIN auf das gewünschte Verzeichnis gesetzt werden.3 Falls TNS_ADMIN gesetzt ist, die Konfigurationsdateien aber nicht vorhanden sind, werden sie dennoch im Standardverzeichnis $ORACLE_HOME/network/admin gesucht. Die Konfiguration wird meist beim Server begonnen. Hier wird mindestens ein Listener konfiguriert. Hierzu wird mindestens die Datei listener.ora, oft auch sqlnet.ora benötigt. Die Datei sqlnet.ora sollte auf der Serverseite im Falle eines MS-Windows Servers mindestens die Zeile SQLNET.AUTHENTICATION_SERVICES = (NTS)
3
Unter Unix gibt es alternativ die Möglichkeit, mit Links zu arbeiten. Da es hier und dort Werkzeuge (oder Versionen von Werkzeugen ...) gibt, die auf $TNS_ADMIN nicht reagieren, ist diese Möglichkeit auch in Betracht zu ziehen.
Oracle Net
287
enthalten. Dies hat zwar nichts mit der Netzwerkkonfiguration zu tun; falls der Eintrag nicht da ist, kann jedoch die lokale Anmeldung AS SYSDBA ohne Passwort (für Mitglieder der Windows-Gruppe ORA_DBA) nicht genutzt werden. Als Beispielprotokoll verwenden wir zunächst das Protokoll TCP/IP, da dies bei den meisten Installationen verwendet wird. Eine einfache Listener-Konfiguration in der Datei listener.ora sieht wie folgt aus: LOG_DIRECTORY_LISTENER = /orabase/network/log LOG_FILE_LISTENER = listener.log LISTENER = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = rhlinux)(PORT = 1521)) )
Wichtig ist das Verständnis, dass in jedem der drei definierten Parameter der Name des Listeners (in diesem Falle LISTENER) vorkommt. Parameter für einen weiteren Listener würde man in der gleichen Datei hinterlegen; sie heißen dann z.B. LOG_DIRECTORY_LSNR2, LOG_FILE_LSNR2 und LSNR2 für einen Listener LSNR2. Die Parameter LOG_DIRECTORY_LISTENER und LOG_FILE_LISTENER legen erwartungsgemäß Pfad und Dateinamen für eine Logdatei fest. Der Parameter LISTENER enthält zunächst einen Protokoll-Endpunkt, auf dem der Listener horcht. Im Beispiel wird der Standardport 1521 für Oracle Net verwendet; es kann aber auch ein beliebiger freier Port eingetragen werden. Im Übrigen verbirgt sich hinter dem Hostnamen (in diesem Fall rhlinux) eine Netzwerkschnittstelle bzw. IP-Adresse. Die Zuordnung von IP-Adressen zu Netzwerkschnittstellen erfolgt entweder manuell (durch Konfiguration des Servers) oder automatisch mit DHCP4. An dieser Stelle sei dringend empfohlen, Rechner mit Serverfunktionen wie Instanzen, Listenern oder Connection Managern ausschließlich manuell zu konfigurieren. Die Änderung einer IP-Adresse kann für solche Serverdienste enorm viel Ärger bereiten, was oft genug heißt, dass die Dienste für eine mehr oder weniger lange Zeit nicht zur Verfügung stehen. Sobald die Konfiguration vorhanden ist, kann man mit dem Listener Control Utility LSNRCTL und dem Kommando START den Listener starten: $ lsnrctl start LSNRCTL for Linux: Version 10.1.0.3.0 - Production on 04-FEB-2005 16:39:22 Copyright (c) 1991, 2004, Oracle.
All rights reserved.
Starting /orabase/product/O1010/bin/tnslsnr: please wait... TNSLSNR for Linux: Version 10.1.0.3.0 – Production System parameter file is /orabase/network/admin/listener.ora Log messages written to /orabase/network/log/listener.log Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=rhlinux)(PORT=1521)))
4
Dynamic Host Configuration Protocol
288
Zugriff auf die Datenbank
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1521))) STATUS of the LISTENER -----------------------Alias LISTENER Version TNSLSNR for Linux: Version 10.1.0.3.0 – Production Start Date 04-FEB-2005 16:39:22 Uptime 0 days 0 hr. 0 min. 0 sec Trace Level off Security ON: Local OS Authentication SNMP OFF Listener Parameter File /orabase/network/admin/listener.ora Listener Log File /orabase/network/log/listener.log Listening Endpoints Summary... (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=rhlinux)(PORT=1521))) The listener supports no services The command completed successfully
Das Listener Control Utility kann entweder auf der Kommandozeile mit allen Parametern für einen Befehl bestückt (wie im o.a. Beispiel) oder als interaktives Werkzeug benutzt werden. Für den letzten Fall ruft man es ohne weitere Parameter auf. In der Ausgabe der Listener Control Utilities sind verschiedene Dinge zu sehen. Der Listener bestätigt die mit TNS_ADMIN gesetzten Orte für die Konfigurationsdatei (system parameter file bzw. Listener Parameter File). Die konfigurierte Logdatei wird ebenfalls bestätigt (log messages written to bzw. Listener Log File). Die Listening Endpoints Summary bestätigt die konfigurierte Auswahl. Offensichtlich kann man mit dem Listener ansonsten noch nichts tun: The listener supports no services. In diesem Zustand würde jeder Versuch, einen Verbindungsaufbau über diesen Listener anzufordern, in folgender Fehlermeldung enden: TNS-12514: TNS:listener does not currently know of service requested in connect descriptor
Erst nach dem automatischen Anmelden einer Instanz beim Listener ist diese auch erreichbar. Dieser Vorgang wird als Dienstregistrierung (service registration) bezeichnet. Eine Instanz versucht die automatische Anmeldung grundsätzlich an der Standardnetzwerkschnittstelle auf dem Port 1521. Läuft der Listener auf einer anderen Schnittstelle oder einem anderen Port, so muss der Initialisierungsparameter local_listener der Instanz auf die gültige Listener-Adresse zeigen: local_listener = '(ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1521))'
Alternativ kann als Wert für den Parameter local_listener ein Net-Aliasname gesetzt werden, der in der lokalen Datei tnsnames.ora in eine Adresse bzw. Adressliste übersetzt wird: local_listener = 'LISTENER.LOCAL'
Oracle Net
289
Der Eintrag für die Datei tnsnames.ora sieht wie folgt aus: LISTENER.LOCAL= (ADDRESS_LIST= (ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1521)) )
Die Ausgabe des Kommandos STATUS in das Listener Control Utility hat nach der Instanzanmeldung (zusätzlich zum fast identischen Aussehen zum START-Kommando) folgenden Inhalt: Services Summary... Service "RH10.hl.de" has 1 instance(s). Instance "RH10", status READY, has 1 handler(s) for this service...
Bei der Anmeldung am Listener hinterlässt die Instanz sowohl ihren Instanznamen (RH10) als auch ihren Dienstnamen (RH10.hl.de). Der Instanzname entspricht dem Wert der Variablen ORACLE_SID; der Dienstname setzt sich bei nicht gesetztem Systemparameter service_names aus db_name und db_domain zusammen. Nun kann man zur Konfiguration des Clients übergehen. Beim Client sollten die beiden Dateien sqlnet.ora und tnsnames.ora konfiguriert werden – das Verzeichnis wird wie beim Server festgelegt. Die Datei sqlnet.ora sollte zur lokalen Namensauflösung zumindest die beiden Einträge erhalten: NAMES.DIRECTORY_PATH = (TNSNAMES) NAMES.DEFAULT_DOMAIN = hl.de
Hiermit wird einerseits festgelegt, dass die Auflösung von Net-Aliasnamen in einer tnsnames.ora-Datei erfolgt. Net-Aliasnamen haben die Form .<domain> und bekommen eine Zieladresse (die einem Listener entsprechen muss) sowie einen Servicenamen zugewiesen. Andererseits wird ein Standardwert für die Domäne festgelegt, so dass beim späteren Verbindungsaufbau für .<domain> die Angabe von reicht, falls <domain> dem Standardwert entspricht. Die Datei tnsnames.ora muss mindestens einen Eintrag wie den folgenden enthalten: RH10.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = rhlinux) (PORT = 1521) ) ) (CONNECT_DATA = (SERVICE_NAME = RH10.hl.de) ) )
290
Zugriff auf die Datenbank
Hiermit wird dem Net-Aliasnamen RH10.HL.DE sowohl eine Adresse (nämlich die gleiche, die als Listener-Endpunkt definiert ist) als auch ein Dienstname zugeordnet. Der Net-Aliasname und der Dienstname der Instanz sind im Übrigen nur zufällig identisch; für beide können auch unterschiedliche Namen gewählt werden. In vielen Fällen werden jedoch beide aus Datenbanknamen und -domäne zusammengesetzt. Basiskonfiguration mit dem Net-Konfigurationsassistenten Alternativ zur manuellen Konfiguration kann man z.B. den Net-Konfigurationsassistenten verwenden, um eine Basiskonfiguration zu erstellen. Der Assistent wird z.B. auch während der Basisinstallation aufgerufen, um einen Listener, Benennungsmethoden und einen Aliasnamen zu konfigurieren. Die hier gezeigte Sitzung mit dem Net-Konfigurationsassistenten stammt nicht aus der Installation, sondern ist ein manueller Aufruf. Daher ist auf der ersten Seite die Konfigurationsauswahl zu sehen; während der Installation sind die entsprechenden Schritte vorgegeben. Der Aufruf selbst erfolgt unter MS-Windows aus dem Startmenü oder alternativ – für alle Plattformen inklusive MS-Windows – mit dem Aufruf netca aus der Kommandozeile. Im Einstiegsbildschirm wurde zunächst die Listener-Konfiguration ausgewählt. Zum Bestätigen der Fenster wird im Verlauf der Sitzung jeweils die Schaltfläche Weiter angeklickt.
Abbildung 7.4: Einstiegsbildschirm
Da noch kein Listener konfiguriert ist, muss mit Hinzufügen die einzig mögliche Variante ausgewählt werden.
Oracle Net
291
Abbildung 7.5: Listener hinzufügen
Der vorgegebene Name des Listeners ist wie bei der o.a. Beispielkonfiguration LISTENER.
Abbildung 7.6: Listener benennen
Im nächsten Fenster können die Protokolle des Listeners ausgewählt werden. Auch hier bliebt TCP die einzige Auswahl.
292
Zugriff auf die Datenbank
Abbildung 7.7: Protokolle für den Listener auswählen
Im nächsten Schritt wird der Port für den Listener ausgewählt. Der Standard-Port 1521 ist voreingestellt.
Abbildung 7.8: Listener-Port
Es können mehrere Listener konfiguriert werden. Für die Basiskonfiguration reicht einer auf jeden Fall aus.
Oracle Net
Abbildung 7.9: Weitere Listener
Damit ist die Listener-Konfiguration abgeschlossen.
Abbildung 7.10: Abschluss der Listener-Konfiguration
Der nächste Schritt ist die Auswahl der Benennungsmethoden.
293
294
Zugriff auf die Datenbank
Abbildung 7.11: Benennungsmethoden
Um die Aliasnamen in einer tnsnames.ora-Datei auflösen zu können, muss mindestens Lokale Benennung ausgewählt werden. Zusätzliche Methoden können ebenfalls ausgewählt werden.
Abbildung 7.12: Auswahl der Benennungsmethoden
Oracle Net
295
Damit ist dieser Schritt bereits abgeschlossen.
Abbildung 7.13: Abschluss Benennungsmethoden
Abschließend sollte mindestens ein Aliasname konfiguriert werden, damit man die bisher gemachten Eingaben testen kann.
Abbildung 7.14: Auswahl Konfiguration Aliasname
296
Zugriff auf die Datenbank
Auch hier sind alle Optionen außer Hinzufügen zunächst nicht anwählbar.
Abbildung 7.15: Aliasnamen hinzufügen
Zunächst muss der Dienstname der Datenbank bzw. Instanz angegeben werden (siehe Abschnitt auf Seite 282).
Abbildung 7.16: Dienstnamen angeben
Als Nächstes wird das Protokoll ausgewählt. Meistens handelt es sich um TCP.
Oracle Net
Abbildung 7.17: Protokollauswahl
Im Falle von TCP/IP fehlen nun noch Hostname oder IP-Adresse und Port.
Abbildung 7.18: Auswahl von Hostname und Port
297
298
Zugriff auf die Datenbank
Der neue Aliasname kann bereits jetzt getestet werden. Da der Listener in diesem Fall noch nicht aktiv ist, kann der Test weggelassen werden.
Abbildung 7.19: Test des Aliasnamen
Abschließend wird der Aliasname selbst noch benannt. Oft ist es sinnvoll, diesen Namen identisch zum Dienstnamen der Datenbank zu wählen.
Abbildung 7.20: Aliasname
Oracle Net
299
Auch hier können mehrere Aliasnamen definiert werden. In diesem Beispiel wird dies nicht genutzt.
Abbildung 7.21: Weitere Aliasnamen
Das Fenster zum Abschluss der Konfiguration von Aliasnamen wird nun bestätigt.
Abbildung 7.22: Abschluss Konfiguration von Aliasnamen
300
Zugriff auf die Datenbank
Die Konfiguration ist hiermit beendet und wird mit einem Klick auf Beenden abgeschlossen und in die Oracle Net-Konfigurationsdateien geschrieben.
Abbildung 7.23: Beenden des Net-Konfigurationsassistenten
Das Resultat der Konfiguration ist jeweils eine Datei listener.ora, sqlnet.ora und tnsnames.ora mit folgenden Inhalten: # listener.ora Network Configuration File: /orabase/network/admin/listener.ora # Generated by Oracle configuration tools. SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = PLSExtProc) (ORACLE_HOME = /orabase/product/db/10.1.0) (PROGRAM = extproc) ) ) LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = rhas4)(PORT = 1521)) ) (ADDRESS_LIST = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC)) ) ) ) Listing 7.1: Datei listener.ora
Oracle Net
301
Die Datei hat einige Ähnlichkeit mit der o.a. listener.ora. Es gibt in der SID_LIST_LISTENER einen Eintrag für externe Prozeduren (eine Funktion, mit der man externe Bibliotheken in PL/SQL integrieren kann), der aber nur selten gebraucht wird. Es fehlen andererseits die Einträge zur gezielten Ablage der Logdatei des Listeners. # sqlnet.ora Network Configuration File: /orabase/network/admin/sqlnet.ora # Generated by Oracle configuration tools. NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT) Listing 7.2: Datei sqlnet.ora
In der Datei sqlnet.ora sind lediglich die Benennungsmethoden konfiguriert. Es fehlt die Standarddomäne. # tnsnames.ora Network Configuration File: /orabase/network/admin/tnsnames.ora # Generated by Oracle configuration tools. RH4.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = rhas4)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = RH4.hl.de) ) ) Listing 7.3: Datei tnsnames.ora
Die Datei tnsnames.ora ist genau nach Vorgabe konfiguriert. Zur Aufbereitung der Konfiguration können die Dateien entweder manuell ergänzt oder mit einem weiteren Werkzeug, dem Net Manager, bearbeitet werden. Dieses Werkzeug kann unter MS-Windows aus dem Startmenü oder auf allen Plattformen mit dem Programmnamen netmgr aufgerufen werden. Der Net Manager hat auf der linken Seite einen Navigationsbaum, der für die lokale Konfiguration die Bereiche Profil, Dienstbenennung und Listener (für die Dateien sqlnet.ora, tnsnames.ora sowie listener.ora) enthält. In der Kopfzeile wird grundsätzlich das aktuelle Konfigurationsverzeichnis angegeben, mit dem der Net Manager gerade arbeitet. Hierdurch wird sichergestellt, dass die richtige Konfiguration bearbeitet wird.
302
Zugriff auf die Datenbank
Abbildung 7.24: Der Net Manager
Durch einen Klick auf Profil gelangt man in den Bereich zur Konfiguration der Datei sqlnet.ora. Die Auswahlbalken oben auf dem Bildschirm sollte auf Namensgebung eingestellt werden. Dann kann die Standarddomäne hl.de eingegeben werden.
Abbildung 7.25: Standard-Domäne setzen
Oracle Net
303
Mit einem Klick auf den bereits konfigurierten Listener LISTENER gelangt man in den Bereich zur Konfiguration des Listeners. Dort wählt man mit dem oberen Auswahlbalken zunächst Allgemeine Parameter aus, dann den Karteireiter Protokollierung & Tracing. Nun kann der gewünschte vollständige Pfadname für die Logdatei nach den eigenen Wünschen geändert werden.
Abbildung 7.26: Pfadangaben für Listener-Logdatei
Um die Änderungen zu speichern, wählt man im Menü Datei den Punkt Netzwerkkonfiguration speichern... aus.
304
Zugriff auf die Datenbank
Abbildung 7.27: Speichern der Konfiguration
Nach dem Speichern der Konfiguration kann man die Anpassung der Parameter in den Dateien listener.ora und sqlnet.ora nachvollziehen. # listener.ora Network Configuration File: /orabase/network/admin/listener.ora # Generated by Oracle configuration tools. SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = PLSExtProc) (ORACLE_HOME = /orabase/product/db/10.1.0) (PROGRAM = extproc) ) ) LOG_DIRECTORY_LISTENER = /orabase/network/log LOG_FILE_LISTENER = LISTENER.log
Oracle Net
305
LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = rhas4)(PORT = 1521)) ) (DESCRIPTION = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC)) ) ) Listing 7.4: Datei listener.ora nach Änderung # sqlnet.ora Network Configuration File: /orabase/network/admin/sqlnet.ora # Generated by Oracle configuration tools. NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT) NAMES.DEFAULT_DOMAIN = hl.de Listing 7.5: Datei sqlnet.ora nach Änderung
Wie erwartet, sind in der Datei listener.ora die Parameter LOG_DIRECTORY_LISTENER und LOG_FILE_LISTENER sowie in der Datei sqlnet.ora der Parameter NAMES.DEFAULT_ DOMAIN ergänzt worden. Wie man recht schnell beim Ausprobieren der Werkzeuge erkennen kann, bietet der Net Manager bei weitem mehr Möglichkeiten als der Konfigurationsassistent. Daher empfehlen wir grundsätzlich, den Net Manager einzusetzen. Auch einfachste Konfigurationen sind mit dem Net-Konfigurationsassistenten nicht wesentlich schneller fertig. Konfiguration von Instanzen für den Listener Die weiter oben aufgeführte Basiskonfiguration für den Listener enthält keine Liste der Instanzen, da diese sich nach dem Start automatisch beim Listener anmelden. Diese Art der Konfiguration hat z.B. den Vorteil, dass gewisse Instanz-Statusinformationen an den Listener weitergegeben werden können. Sobald eine Instanz in den RESTRICTED SESSION-Modus gesetzt ist, verweigert der Listener eine Verbindung mit der Fehlermeldung: ORA-12526: TNS:listener: all appropriate instances are in restricted mode
Auch in der Ausgabe des STATUS-Kommandos des Listener Control Utilitys kann der RESTRICTED-Modus nachvollzogen werden: Services Summary... Service "RH10.hl.de" has 1 instance(s). Instance "RH10", status RESTRICTED, has 6 handler(s) for this service...
Dies ist zwar zunächst positiv zu bewerten, da man hiermit den Zugriff auf den Datenbankserver aus dem Netzwerk komplett blockieren kann; allerdings erhalten diese Fehlermeldung auch Oracle-Benutzer, die das Privileg RESTRICTED SESSION besitzen, sich also eigentlich anmelden dürfen.
306
Zugriff auf die Datenbank
Es kann auch aus weiteren Gründen vorteilhaft sein, Instanzen für den Listener zu konfigurieren, z.B. wenn man in der Lage sein möchte, die Instanz über eine Oracle Net-Verbindung zu starten. Hierzu muss die Datei listener.ora zusätzlich zu den bereits bekannten Parametern eine SID-Liste enthalten: SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = RH10.hl.de) (ORACLE_HOME = /orabase/product/O1010) (SID_NAME = RH10) ) )
Führt man mit dem neuen Parameter einen Neustart des Listeners oder das Kommando RELOAD aus, so ändert sich die Ausgabe des STATUS-Kommandos wie folgt: Services Summary... Service "RH10.hl.de" has 2 instance(s). Instance "RH10", status UNKNOWN, has 1 handler(s) for this service... Instance "RH10", status RESTRICTED, has 6 handler(s) for this service...
Der Listener führt intern eine weitere Instanz des Services, die grundsätzlich den Status UNKNOWN hat. Mit dieser Konfiguration sind Verbindungen an die Instanz möglich, auch wenn diese sich im RESTRICTED SESSION-Modus befindet oder heruntergefahren ist.
7.1.2 Shared Server Architektur Die am häufigsten benutzte Methode für Serverkonfiguration ist die Eins-zu-einsBeziehung zwischen Clients bzw. Sitzungen (Sessions) und Serverprozessen. Diese wird auch als Dedicated Server bezeichnet. Dieses Konzept kann in bestimmten Situationen zu Problemen führen – etwa wenn in Summe zu viele Sitzungen existieren oder wenn Sitzungen zu häufig geöffnet und geschlossen werden, z.B. von Applikationsservern. Als Alternative gilt dann der Shared-Server-Modus, bei dem die Clients beim Öffnen der Sitzung einem Dispatcher fest zugeordnet werden. Ein Dispatcher kann für mehrere Clients da sein und bleibt während des Bestehens einer Sitzung fester Ansprechpartner. Über Queue-Mechanismen verteilt der Dispatcher die Anfragen der Clients an die Shared-Server-Prozesse, deren Zuordnung zu Clients bzw. zu einer Sitzung immer nur für die Dauer der Bearbeitung eines einzelnen Aufrufs bestehen bleibt. Zum Verständnis der Architektur sind folgende Anmerkungen wichtig: Die Zuordnung zwischen Client und Shared Server ist lose und dauert genauso lange wie die Abarbeitung eines einzelnen Aufrufs. Der nächste Aufruf kann also bereits von einem anderen Shared Server bearbeitet werden. Es können die Phasen Execute und Fetch zur Cursor-Abarbeitung von verschiedenen Prozessen durchgeführt werden. Daher wandern im Falle von Shared-Server-Sitzungen
Oracle Net
307
Informationen, die bei Dedicated-Server-Sitzungen in der PGA der Prozesse gespeichert werden, in die SGA; dies sind z.B. Cursor-Informationen und Sort Areas. Daraus folgt, dass ein oft vorgebrachtes Argument für Shared-Server-Architekturen, nämlich eine Einsparung großer Mengen von Hauptspeicher für Prozesse, nur teilweise gilt. Die SGA muss bei der Benutzung von Shared Servern i.A. um den entsprechenden Betrag vergrößert werden. Ein einzelner Aufruf kann z.B. die Execute-Phase eines komplexen SQL-Befehls sein, der mehrere Minuten dauert. In diesem Fall ist der Shared Server für die komplette Zeit an diese Sitzung gebunden, d.h., für die anderen Sitzungen geht ein Shared-Server-Prozess für diese Zeit verloren. Shared-Server-Prozesse werden mit S000, S001 … Snnn; Dispatcher mit D000, D001 … Dmmm bezeichnet.
Abbildung 7.28: Dedicated und Shared Server
Bei den Queues handelt es sich um genau eine Request Queue, in der die Dispatcher alle Anfragen zur Bearbeitung durch die Shared-Server-Prozesse hinterlegen. Die Abarbeitung erfolgt durch einen beliebigen freien Shared-Server-Prozess, der die Antwort für den Client in einer Response Queue, die dem Dispatcher fest zugeordnet ist, hinterlegt. Jeder Dispatcher verfügt über eine eigene Response Queue. Hiermit werden Wartezustände bei der Verteilung der Antworten vermieden.
308
Zugriff auf die Datenbank
Konfiguration Shared Server werden nicht über Oracle Net, sondern über Datenbankparameter konfiguriert. Die einfachste Möglichkeit, dies zu tun, ist, den Initialisierungsparameter shared_servers auf einen vom Standardwert 0 unterschiedlichen Wert zu setzen. Dies bestimmt die initiale und minimale Anzahl der Shared-Server-Prozesse; im weiteren Verlauf ist deren Anzahl dynamisch und wird vom Oracle-System selbst bestimmt. Mit max_shared_servers kann die Maximalzahl der Shared Server vorgegeben werden; hierzu muss dieser Parameter mindestens auf den Wert von shared_servers eingestellt werden. Wenn max_shared_servers kleiner als shared_servers eingestellt ist, kann das Oracle-System praktisch beliebig viele Shared Server starten. Dabei lässt es immer mindestens 1/8 der maximalen Anzahl von Prozessen (Initialisierungsparameter processes) für Dedicated-Server-Prozesse frei. Die Anzahl der benötigten Shared Server für ein bestimmtes System ergibt sich praktisch automatisch aus dem Verhalten des Systems. Als erste Schätzung kann 1/10 der erwarteten Sitzungen angenommen werden. Falls die Systemlast auch »Langläufer« enthält, kann die Zahl der benötigten Shared Server größer sein; falls nur kurze Aufrufe an das OCI gemacht werden, kann sich auch eine kleinere Zahl ergeben. Shared_servers sollte auf jeden Fall so gewählt werden, dass nur in Ausnahmefällen zusätzliche Shared-Server-Prozesse gestartet werden und nicht permanent. Bei den Dispatchern ist die Bestimmung der benötigten Anzahl ein bisschen schwieriger, insbesondere weil Oracle bei Bedarf nicht automatisch Dispatcher nachstartet – hier hat der DBA die Pflicht, sich aus einigen V$-Views Informationen über die Auslastung der Dispatcher zu beschaffen. Falls – wie oben angegeben – ausschließlich shared_servers gesetzt wird, um Shared Server zu aktivieren, wird damit implizit dispatchers = '(PROTOCOL=TCP)'
gesetzt und genau ein Dispatcher gestartet. Möchte man mehr als einen Dispatcher gestartet haben, geht das z.B. mit dispatchers = '(PROTOCOL=TCP)(DISPATCHERS=3)'
Für die Dispatcher können mehrere Parameterwerte angegeben werden. Falls man mit einer Initialisierungsparameterdatei arbeitet, können mehrere aufeinander folgende Zeilen mit dem Parameter dispatchers eingetragen werden. Im Falle einer Serverparameterdatei oder bei ALTER SYSTEM-Kommandos werden einfach mehrere Parameter in Hochkommata als Liste (mit Komma getrennt) angegeben. Dies wird z.B. benötigt, wenn man für jeden Dispatcher einen eigenen Port angeben möchte, um somit Kontrolle über die verwendeten Ports zu bekommen, etwa um diese in einer Firewall gezielt freischalten zu können. Dies könnte wie folgt aussehen: dispatchers = '(ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1522))' dispatchers = '(ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1523))'
Mit der gleichen Methode können auch unterschiedliche IP-Adressen angegeben werden. In unserem Beispiel sind die Ports 1522 und 1523 mit Dispatchern belegt. Das kann über das Kommando SERVICES des Listener Control Utilitys überprüft werden:
Oracle Net
309
Services Summary... Service "RH10.hl.de" has 1 instance(s). Instance "RH10", 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:972 state:ready DISPATCHER <machine: rhlinux, pid: 6685> (ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1523)) "D000" established:0 refused:0 current:0 max:972 state:ready DISPATCHER <machine: rhlinux, pid: 6683> (ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1522))
Jeder Dispatcher wird mit Prozessnummer und Port aufgeführt. Sollten die Dispatcher im Listener nicht aufgeführt sein, so kann dieser auch keine Verbindungen im Shared-Server-Modus aufbauen. Meist liegt die Ursache darin, dass der Listener nicht auf der erwarteten Adresse horcht, so dass der Initialisierungsparameter local_listener gesetzt werden muss. Es gibt einen weiteren Parameter mts_max_dispatchers, den zumindest Oracle 10g Release 1 nicht weiter betrachtet.5 In früheren Releases konnte hiermit eine online nicht änderbare Maximalzahl von Dispatchern festgelegt werden. Die Konfiguration des oder der Dispatcher lässt sich über die View v$dispatcher_ config überprüfen. Hierbei gibt es für jeden dispatchers-Eintrag eine Zeile, die über die Spalte conf_indx eindeutig identifiziert werden kann. Dies ist wichtig, wenn man online die Konfiguration eines Eintrags bzw. eines einzelnen Dispatchers ändern möchte. Durch die Verwendung der Option (INDEX=n) wird das Kommando der Konfiguration zugeordnet, bei der conf_indx den Wert n enthält. Connection Pooling Eine interessante Option für Dispatcher ist das Connection Pooling. Sie ist gedacht für eine große Zahl von logischen Verbindungen mit relativ langen »Denkpausen«. Dabei wird die Anzahl der benötigten Netzwerkverbindungen dadurch reduziert, dass die Verbindungen einzelnen momentan inaktiven Sitzungen entzogen werden, um sie für aktive Sitzungen zu nutzen. Connection Pooling wird über den zusätzlichen Eintrag (POOL=<x>) des Parameters dispachers aktiviert Dabei kann <x> die folgenden Werte annehmen: ON, YES, TRUE oder BOTH, wenn Connection Pooling sowohl für eingehende als auch für ausgehende Verbindungen aktiviert werden soll, IN für eingehende Verbindungen, OUT für ausgehende Verbindungen sowie OFF, NO oder FALSE für nicht aktiviert.
5
Zitat Oracle Database Administrator’s Guide: In this release of Oracle Database, you can increase the number of dispatchers to more than the limit specified by the max_dispatchers parameter. It is planned that max_dispatchers will be taken into consideration in a future release.
310
Zugriff auf die Datenbank
Dabei gilt ein Standardwert für 10 Ticks als Timeout für die Verbindungen. Soll vom Standardwert abgewichen werden, kann dies mit den Parametern IN und OUT wie folgt gesetzt werden: (POOL=(IN=20)(OUT=50))
Die Dauer eines Ticks wird bei Bedarf mit (TICKS=)
als weitere Option in Sekunden angegeben; der voreingestellte Wert ist hier 1. Eine komplette Dispatcher-Konfiguration für Connection Pooling kann wie folgt angegeben werden dispatchers = '(ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1523))\ (POOL=(IN=15)(OUT=20))(TICKS=2)'
Eine weitere Option zur Konfiguration des Dispatchers, Session Multiplexing, wird im Zusammenhang mit dem Connection Manager weiter unten erläutert. Verbindungsaufbau Sind Shared Server eingerichtet, so können in der Regel ohne weitere Änderungen auf dem Client Verbindungen an diese aufgebaut werden. Hat der Listener beim Verbindungsaufbau die Wahl zwischen Dedicated und Shared Server, so wird er grundsätzlich Shared-Server-Verbindungen aufbauen. Mit dem Parameter shared_server_sessions kann eine maximale Anzahl von Shared Server Sessions bestimmt werden; jede weitere bekommt bei der Anmeldung den Fehler: ORA-00018: maximum number of sessions exceeded
Zur Überprüfung, ob eine Verbindung tatsächlich im Shared-Server-Modus läuft, kann z.B. die View v$session mit folgender Abfrage herangezogen werden: SELECT saddr, username, program, server FROM v$session;
Ein Auszug aus der Antwort sieht dann wie folgt aus: SADDR -------5D38F964 5D391D34 5D392F1C 5D394104
USERNAME --------------SYSTEM SYSTEM SYSTEM SYSTEM
PROGRAM -----------------------------sqlplusw.exe sqlplusw.exe sqlplusw.exe sqlplusw.exe
SERVER --------SHARED NONE NONE DEDICATED
Der Benutzer SYSTEM ist hier mit vier SQL*Plus-Sitzungen (unter Windows) an das System angemeldet; davon gibt es eine Sitzung im Dedicated-Server-Modus (SERVER ist DEDICATED); die anderen drei sind im Shared-Server-Modus. Die Anzeige unter SERVER wechselt zwischen NONE und SHARED, je nachdem, ob gerade ein Shared Server zugeordnet ist (also ein Aufruf über OCI ausgeführt wird) oder nicht. In diesem Beispiel hat die SQL*Plus-Sitzung in der ersten Zeile die Abfrage ausgeführt, daher ist auch ein Shared Server zugeordnet.
Oracle Net
311
Die Zuordnung der Shared Server zu Sitzungen kann in der View v$circuit nachvollzogen werden: SELECT saddr, dispatcher, server, queue FROM v$circuit WHERE queue = 'SERVER';
Hier die Ausgabe: SADDR DISPATCH SERVER QUEUE -------- -------- -------- ---------------5D38F964 5D306048 5D306558 SERVER
Die Adresse der Sitzung SADDR stimmt mit der obigen Ausgabe überein. Der Dispatcher lässt sich aus der nächsten Ausgabe herauslesen: SELECT name, paddr, network FROM v$dispatcher; NAME ---D000 D001
PADDR -------5D305B38 5D306048
NETWORK -------------------------------------------------(ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1522)) (ADDRESS=(PROTOCOL=TCP)(HOST=rhlinux)(PORT=1523))
Es handelt sich also um den Dispatcher D001 auf Port 1523. In ähnlicher Art und Weise lässt sich der Shared Server aus der View v$shared_server identifizieren. Weiter unten im Abschnitt über den Connection Manager werden weitere Konfigurationsvarianten für Shared Server beschrieben. Auswahl zwischen Dedicated und Shared Server Bei Shared-Server-Verbindungen sind für den Verbindungstyp kurze Befehle mit kleinen Ergebnismengen optimal. Lange und lang laufende Befehle sowie die Übertragung großer Ergebnismengen sind eher ungeeignet. Für DBA-Aufgaben wie Instanzstart und -stopp können Shared Server überhaupt nicht eingesetzt werden: SQL> SHUTDOWN ORA-00106: cannot startup/shutdown database when connected to a dispatcher
Da die Verwendung von Shared Servern immer dann stattfindet, wenn es möglich ist, empfiehlt es sich beim Einsatz von Shared Servern, zusätzliche Oracle NetAliasnamen zu konfigurieren, die explizit Dedicated Server anfordern: RH10D.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = rhlinux)(PORT = 1521)) ) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = RH10.hl.de) ) )
312
Zugriff auf die Datenbank
Ein solcher Eintrag kann dann sowohl für DBAs als auch für Batches, Reports usw. genutzt werden. Falls ein Client grundsätzlich Dedicated-Server-Verbindungen erhalten soll, unabhängig von der Parametrierung der einzelnen Aliasnamen, kann in der Datei sqlnet.ora der Parameter USE_DEDICATED_SERVER = ON
gesetzt werden. Dedicated oder Shared Server? Die Diskussion, ob Dedicated oder Shared Server eingesetzt werden sollen, wird recht häufig geführt. Die Erfahrung (insbesondere mit früheren Oracle-Versionen) zeigt grundsätzlich, dass man so lange Dedicated Server betreiben sollte, wie sich damit keine Probleme zeigen. Häufig zeigt sich, dass moderne Rechner mit großen Prozesszahlen keine besonderen Schwierigkeiten haben. Auch das Starten und Beenden von Prozessen ist nicht mehr so aufwändig für das System. Dies spricht grundsätzlich für den Einsatz von Dedicated Servern. Ein weiterer Grund spricht dafür, ein funktionierendes Dedicated-Server-System nicht umzukonfigurieren: Wenn die Ressourcen für den Betrieb von Dedicated Server ausreichend sind, so ist dieser immer schneller als der Betrieb von Shared Servern, da die Datenübertragung mit Hilfe von Queues sowie die Prozesswechsel von Dispatcher zu Shared Server und zurück eingespart werden. Sind doch Gründe für die Einführung von Shared Servern vorhanden (also extrem große Zahl von Prozessen und/oder sehr häufiges Starten und Beenden von Sitzungen), so muss unbedingt die Auslastung der Shared Server und Dispatcher beobachtet werden, da die Queue-Mechanismen schnell zum Engpass werden können. Ein Grund für die Einführung einer Shared-Server-Konfiguration ist oft eine Firewall zwischen den Clients und dem Server: Man ist mit Hilfe der Dispatcher-Konfiguration in der Lage, die TCP/IP-Port für die Client-Server-Kommunikation exakt zu bestimmen, was bei einer Dedicated-Server-Konfiguration nicht gegeben ist. Weiterhin ist zu empfehlen, Anwendung für Anwendung zu entscheiden, ob sie Shared-Server-tauglich ist, da ein Mischbetrieb, wie weiter oben beschrieben, möglich ist.
7.1.3
Spezielle Parameter
In diesem Abschnitt werden einige Oracle Net-Parameter besprochen, die in Spezialfällen benötigt werden. Einige sind besonders für Hochverfügbarkeitsumgebungen mit RAC und/oder Data Guard sinnvoll (dies sind Client-Loadbalancing, Connect-Time Failover und Transparent Application Failover), die Einstellung der SDUGröße ist eher im Bereich Performance-Tuning einzuordnen, Dead Connection Detection zielt schließlich in den Bereich Troubleshooting.
Oracle Net
313
Client-Loadbalancing und Connect-Time Failover Hier geht es um zwei Oracle Net Client-Parameter, die beim Verbindungsaufbau wirken und zum einen für die etwa gleichmäßige Verteilung der Clients auf verschiedene Knoten sorgen und zum Anderen den Ausfall eines Knotens sofort durch den automatischen Kontakt des nächsten Knotens kompensieren. Die beiden Parameter werden gemeinsam besprochen, weil sie an der gleichen Stelle auf der ClientSeite (in der Datei tnsnames.ora) konfiguriert werden. Bei beiden Parametern werden Verbindungen an verschiedene Listener-Endpunkte aufgebaut, bei denen der Instanzname meist unterschiedlich ist. Daher ist es wichtig, dass zur logischen Adressierung in der CONNECT_DATA-Sektion der Net-Aliasnamendefinition nicht die vor Oracle8i übliche SID-Syntax, sondern die SERVICE_NAMEVariante verwendet wird. Weiterhin sollte man dafür sorgen, dass der angegebene Servicename in allen zum Verbindungsaufbau vorgesehenen Instanzen aktiviert wird; entweder durch Setzen des Systemparameters service_names oder durch entsprechende Aufrufe des Pakets dbms_service. Client-Loadbalancing wird durch den Parameter (LOAD_BALANCE = on) in der ADDRESS_LIST-Sektion einer Net-Aliasnamendefinition eingeschaltet und bewirkt, dass für den Verbindungsaufbau einer der ADDRESS-Einträge zufällig ausgewählt und benutzt wird. Damit erreicht man praktisch eine Gleichverteilung der Verbindungen z.B. auf alle Knoten eines RAC-Systems. Ein weiterer Parameter für die ADDRESS_LIST-Sektion der Net-Aliasnamendefinition ist (FAILOVER = on) und schaltet den Connect Time Failover an. Hierdurch wird einfach eine weitere Adresse aus der Liste genommen und für den Verbindungsaufbau verwendet, falls der Verbindungsaufbau mit der zuvor gewählten Adresse nicht funktioniert. Wenn Client-Loadbalancing angeschaltet ist, wird auch die nächste Adresse zufällig aus den übrig gebliebenen ausgewählt, wenn es ausgeschaltet ist, werden die Adressen der angegebenen Reihenfolge nach genutzt. Somit kann über den Connect-Time Failover die Nicht-Verfügbarkeit eines Knotens transparent behandelt werden, so dass beim Client (außer der vielleicht etwas längeren Zeit für den Verbindungsaufbau) keinerlei Unterschied zu bemerken ist. In Verbindung mit Client Load Balancing sind sowohl Umgebungen mit gleichberechtigten Servern, z.B. mit RAC, als auch Failover-Systeme, auch auf Basis von Data Guard oder Replikationsmechanismen, abbildbar. Abschließend ein Beispiel für eine Net-Aliasnamendefinition mit beiden Optionen: MYFAILOVER.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (FAILOVER = on) (LOAD_BALANCE = on) (ADDRESS = (PROTOCOL = TCP)(HOST = rac1)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = rac2)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = MYFAILOVER.hl.de) ) )
314
Zugriff auf die Datenbank
TAF (Transparent Application Failover) Während die oben beschriebenen Optionen lediglich beim Verbindungsaufbau wirken, ist TAF eine Oracle Net-Funktion, die dafür sorgt, dass bereits aufgebaute Verbindungen auf einer anderen Instanz fortgesetzt werden, falls die bestehende Verbindung abbricht, z.B. aufgrund eines Knotenausfalls. Es sei der Hinweis gestattet, dass TAF keine RAC-Funktion ist, obwohl sie im RACUmfeld am meisten Sinn macht. Sie ist aber auch mit Data Guard oder Replikationslösungen von Drittanbietern anwendbar. Selbst komplett unabhängige Instanzen, die einen Verbindungsaufbau mit identischen Benutzerinformationen (inklusive Passwort) erlauben, können mit TAF konfiguriert werden. Hierbei gehen grundsätzlich Informationen verloren: begonnene Transaktionen sind nach einem TAF zurückgerollt und PL/SQL-Statusinformationen (z.B. Variableninhalte in Paketen) sind nicht mehr vorhanden. Allerdings kann die Anwendung ohne neue Verbindung weiterarbeiten; für SELECTs kann optional sogar die Fortsetzung der Fetch-Phase an exakt der gleichen Stelle gewährleistet werden. Wurde eine Transaktion vor der Übernahme der Sitzung angefangen, so reagiert die Anwendung auf weitere DML-Befehle mit Fehlermeldungen, bis ein ROLLBACK ausgeführt worden ist und die Anwendung somit wieder synchron zum Datenbankstatus ist. Die Konfiguration von TAF zeigt folgendes Beispiel: TAF.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (FAILOVER = on) (LOAD_BALANCE = on) (ADDRESS = (PROTOCOL = TCP)(HOST = rac1)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = rac2)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = rac3)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = TAF.hl.de) (FAILOVER_MODE = (TYPE = SESSION) (METHOD = BASIC) ) ) )
Es ähnelt zunächst dem Beispiel für Client-Loadbalancing und Connect-Time Failover; im CONNECT_DATA-Bereich ist zusätzlich die Option FAILOVER_MODE konfiguriert. Hierbei sind die Optionen TYPE und METHOD angegeben. Der Wert SESSION für TYPE bedeutet, dass die Sitzung im Fehlerfall rudimentär übernommen wird. Alternativ kann SELECT angegeben, so dass Fetches fortgesetzt werden können. Hierbei entsteht auch im Normalbetrieb ein gewisser Overhead. Der Wert NONE entspricht dem Ausschalten von TAF. Bei METHOD kann BASIC (Übernahme der Sitzung im Fehlerfall) oder PRECONNECT (Aufbau der zweiten Verbindung im Voraus) verwendet werden. Im letzten Fall geht das Umschalten schneller; allerdings werden im Nicht-
Oracle Net
315
Fehlerfall erhebliche Ressourcen allokiert. Weitere Optionen sind BACKUP für die Spezifikation eines anderen Net-Aliasnamens für die zweite Verbindung, RETRIES für die Anzahl der Verbindungsversuche im Fehlerfall sowie DELAY für die Wartezeit in Sekunden zwischen den Versuchen. Abschließend sei die Bemerkung gestattet, dass der Einsatz von TAF wohl überlegt sein sollte. Eine Anwendung muss hierfür in den meisten Fällen neu strukturiert werden. Eine Alternative ist die einfache Reaktion mit dem Schließen und Neuaufbau einer Verbindung oder auch mit dem Schließen der Anwendung auf Verbindungsfehler wie: ORA-03113: end of file on communication channel
SDU-Größe Ein weiteres Beispiel ist die Spezifikation der SDU-Größe (Session Data Unit). Der Standardwert hierfür ist 2 KB (2048). Insbesondere bei Client-Server-Konfigurationen mit großen Datensätzen bzw. Transfer von großen Datenmengen kann es sinnvoll sein, die SDU-Größe zu verändern. Sie sollte auf ein Vielfaches der MSS (Maximum Segment Size) gesetzt werden. Die MSS für TCP/IP Version 4 auf Ethernet beträgt 1460. Falls auf Oracle Net-Ebene keine Verschlüsselung gewählt wird, d.h. in den meisten Fällen, sollte noch eins dazuaddiert werden, also z.B.: RH10.HL.DE = (DESCRIPTION = (SDU = 5841) (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = rhlinux) (PORT = 1521) ) ) (CONNECT_DATA = (SERVICE_NAME = RH10.hl.de) ) )
Die SDU-Größe muss sowohl auf der Client- als auch auf der Serverseite gesetzt werden. Für Dedicated-Server-Verbindungen kann die SDU-Größe lediglich für den Fall gesetzt werden, dass die Instanz manuell beim Listener registriert wird: SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SDU = 5841) (GLOBAL_DBNAME = RH10.hl.de) (ORACLE_HOME = /orabase/product/O1010) (SID_NAME = RH10) ) )
Für Shared Server wird der SDU-Parameter im Initialisierungsparameter DISPATCHERS gesetzt.
316
Zugriff auf die Datenbank
Dead Connection Detection Ein oft wiederkehrendes Problem im Client-Server-Umfeld ist der »abgestürzte« Client (oder auch: im Betrieb ausgeschalteter PC). Problematisch ist hier, dass der Server zunächst nichts von dieser Situation bemerkt – für ihn unterscheidet sich die Situation nicht von einer weiterhin verbundenen Sitzung, die momentan keine Aufrufe absetzt. Normalerweise ist hierfür das Protokoll selbst verantwortlich. Hierzu ist zu bemerken, dass TCP/IP eine entsprechende Funktion hat: das so genannte keepalive. Allerdings ist der Timeout für keepalive bei vielen Systemen so hoch gesetzt, dass die Anwendung keinen Sinn macht; bei vielen MS-Windows-Versionen ist keepalive sogar deaktiviert. An dieser Stelle übernimmt die Oracle Net-Funktion Dead Connection Detection: Diese ist serverbasiert und sendet im festgelegten Abstand ein Testpaket zum Client, wenn dieser inaktiv ist. Antwortet der Client nicht, so wird die Sitzung beendet und die entsprechenden Ressourcen freigegeben. Dead Connection Detection wird auf der Serverseite mit dem Parameter SQLNET.EXPIRE_TIME aktiviert; der Wert bestimmt den Timeout in Minuten. Die Einstellung SQLNET.EXPIRE_TIME = 10
würde demnach alle zehn Minuten eine Kommunikation mit dem Client auslösen. Hierzu eine Bemerkung: Obwohl die Dead Connection Detection als Funktion seit SQL*Net Version 2.1 vorhanden ist, scheint sie momentan nicht richtig zu funktionieren. Mit diversen MS-Windows- und Linux-Testinstanzen konnte die Funktion nicht nachgewiesen werden. Hinzu kommt, dass die Dokumentation hierzu verwirrend ist: Es gibt Stellen, die behaupten, dass SQLNET.EXPIRE_TIME in Sekunden angegeben wird, andere sprechen von Minuten. Auch ist man sich nicht einig darüber, ob der Parameter beim Client oder beim Server gesetzt werden muss. Grundsätzlich kann man nur empfehlen, ihn auf beiden Seiten zu setzen. Als Lektüre zu dieser Problematik empfiehlt sich der Metalink-Artikel 151972.1 mit dem Titel »Dead Connection Detection (DCD) Explained«.
7.1.4 Instant Client Mit dem Instant Client existiert erstmalig eine von Oracle offiziell unterstützte Lösung, eine Clientinstallation ohne den Universal Installer durchzuführen. Der Client ist für diverse Plattformen verfügbar und besteht lediglich aus einigen Bibliotheken. Diese werden in ein beliebiges Verzeichnis kopiert und über die %PATH%-Variable (unter MS-Windows) bzw. $LD_LIBRARY_PATH-Variable (unter UNIX) erreichbar gemacht. Damit sind OCI-, OCCI- sowie JDBC-OCI-Anwendungen ausführbar. Zusätzlich zu einem Basispaket sind diverse Zusatzpakete für weitere Anwendungstypen erhältlich (z.B. unter MS-Windows JDBC, ODBC sowie SQL*Plus inklusive ausführbarem Programm).
Alternative Methoden zur Namensauflösung
317
Der Instant Client kann als ZIP-Archiv von der Oracle-Website heruntergeladen werden (Größe ca. 30 MB). Nach dem Auspacken in ein Verzeichnis (z.B. C:\oracle\InstantClient) sollte ein kleines Skript geschrieben werden, das Umgebungsvariablen für den Client setzt und ggf. (auf UNIX) exportiert. Das Beispiel für MS-Windows kann folgendermaßen aussehen: SET SET SET SET SET
PATH=C:\oracle\InstantClient;%PATH% TNS_ADMIN=C:\oracle\InstantClient LD_LIBRARY_PATH=C:\oracle\InstantClient SQLPATH=C:\oracle\InstantClient NLS_LANG=<entsprechend Client-NLS-Umgebung>
In das durch TNS_ADMIN angegebene Verzeichnis sollten auch die zu benutzende tnsnames.ora sowie sqlnet.ora gelegt werden.
7.2
Alternative Methoden zur Namensauflösung
Im bisherigen Kapitel haben wir implizit die meistgenutzte Methode zur Auflösung von Oracle Net-Aliasnamen genutzt: die tnsnames.ora-Datei. Oracle Net wäre jedoch kein richtiges Oracle-Produkt, gäbe es nicht noch einige zusätzliche Möglichkeiten zur Namensauflösung. Dabei gibt es Ergänzungen sowohl am oberen Ende der Skala für zentrale Organisation, in diesem Fall die Speicherung von Oracle Net-Konfigurationsdaten in einem LDAP-Server wie dem Oracle Internet Directory OID, als auch am unteren Ende: Hostnaming und Easy Connect. Für Kenner von früheren Oracle-Versionen: Das LDAP-Verzeichnis hat Oracle Names nun endgültig ersetzt. In Oracle 10g gibt es keinerlei Support für Oracle Names mehr, auch nicht für die Oracle Names Proxies, die Clients unter Verwendung von Oracle Names-Mechanismen mit Informationen aus einem LDAP-Verzeichnis versorgt haben.
7.2.1 Hostnaming und Easy Connect Mit der «einfachen Verbindung« Easy Connect begibt sich Oracle Net nach langer Zeit wieder in früher bekannte Gefilde, bei denen es möglich ist, ohne eine gespeicherte Konfiguration eine Verbindung aufzubauen.6 Dass dies funktioniert, hat auch die Verwendung des Thin JDBC-Treibers gezeigt: Auch hier werden Verbindungen nicht konfiguriert, da das Konzept dieses Treibers voraussetzt, dass keinerlei Installation und Konfiguration auf dem entsprechenden Rechner stattgefunden hat. Die als Hostnaming bekannte Methode wurde bereits mit Oracle8i eingeführt und ist ein Spezialfall der Easy-Connect-Methode. Der Oracle Net-Bezeichner sieht wie folgt aus: [//][:<port>][/<service>]
6
Wer Versionen vor Oracle7 Release 7.3 kennt, erinnert sich vielleicht noch an SQL*Net Version 1 mit so genannten Connectstrings der Form T::<SID>.
318
Zugriff auf die Datenbank
Der einzige nicht-optionale Parameter ist – damit ist die HostnamingMethode elegant integriert. Falls <port> nicht angegeben wird, gilt der Standardwert 1521. Als Standardwert für <service> wird angenommen. Wer Angaben in Form einer URL mag, kann den Doppelslash voranstellen. Eine Verbindung kann somit wie folgt aufgebaut werden: sqlplus scott/tiger@localhost:1521/O10.test.hl.de
Die Easy-Connect-Methode kann verwendet werden, wenn entweder keine Datei sqlnet.ora in $TNS_ADMIN bzw. $ORACLE_HOME/network/admin existiert oder die verwendete Datei für den Parameter NAMES.DIRECTORY_PATH den Wert EZCONNECT enthält, wie z.B. in: NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT)
Bei der Verwendung einer sqlnet.ora-Datei kann das tnsping-Werkzeug zur Kontrolle eingesetzt werden: > tnsping localhost/O10.test.hl.de TNS Ping Utility for 32-bit Windows: Version 10.1.0.4.0 - Production on 13-APR-2005 21:40:44 Copyright (c) 1997, 2003, Oracle.
All rights reserved.
Used parameter files: D:\OraBase\Network\Admin\sqlnet.ora Used EZCONNECT adapter to resolve the alias Attempting to contact (DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=O10.test.hl.de)) (ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))) OK (20 msec)
Der Easy-Connect-Bezeichner wird für den Test in das Oracle Net-Format gebracht und der Listener entsprechend kontaktiert.
7.2.2 JDBC Thin Driver Der JDBC Thin Driver stellt eine Ausnahme dar, da keine Oracle Client-Installation existiert – noch nicht einmal ein Instant Client. Im JDBC Thin Driver wird daher die Client-Funktionalität innerhalb von Java emuliert. Da die bekannten Mechanismen und Dateien nicht zur Verfügung stehen, müssen die Verbindungsdetails dem JDBC Thin Driver auf eine andere Art und Weise übermittelt werden. Das passiert im Programm in etwa wie folgt: OracleDataSource ods = new OracleDataSource(); String URL = "jdbc:oracle:thin:@//myhost:1521/orcl", ods.setURL(URL); ods.setUser("scott"); ods.setPassword("tiger"); Connection conn = ods.getConnection();
Alternative Methoden zur Namensauflösung
319
Es ist auch möglich, einen Net-Aliasnamen in einer tnsnames.ora-Datei aufzulösen. Allerdings ist es eher üblich, die oben angegebene Methode zu verwenden, da der JDBC Thin Driver in den allermeisten Fällen eben nicht vom Vorhandensein einer tnsnames.ora-Datei ausgehen kann.
7.2.3 LDAP-Verzeichnisse Die Auflösung von Net-Aliasnamen durch LDAP-Abfragen (LDAP-Benennung) bietet sich in größeren Umgebungen an. Hierzu ist es erforderlich, einen Oracle Internet Application Server zu betreiben. Das Internet Directory ist Bestandteil der Identity-Management-Komponente des Oracle Internet Application Servers. Da es sich hierbei um ein separates Produkt handelt, das nicht im Rahmen der Oracle Database 10g zur Verfügung gestellt wird, wird die Installation und Konfiguration des Internet Directorys an dieser Stelle nicht im Detail behandelt. Um einen Client für die Verwendung der LDAP-Benennung zu konfigurieren, muss diese Methode zunächst mit dem Net-Konfigurationsassistenten eingerichtet werden. Hierfür wählt man auf dem ersten Bildschirm den Punkt Konfiguration von Directory-Verwendung aus.
Abbildung 7.29: Grundkonfiguration LDAP-Benennung
320
Zugriff auf die Datenbank
Auf der nächsten Seite kann ausgewählt werden, welcher Typ von Verzeichnisdienst zur Verfügung steht. Neben dem Oracle Internet Directory steht auch die Möglichkeit, ein MS-Active Directory anzusprechen, zur Verfügung. Wir gehen hier von einem Oracle Internet Directory aus.
Abbildung 7.30: Auswahl des Verzeichnistyps
Weiterhin muss angegeben werden, auf welchem Rechner das Verzeichnis installiert ist und welche Ports verwendet werden. In einem weiteren Fenster kann dann ein DN (Distinguished Name) angegeben werden, der bestimmt, an welcher Stelle im Verzeichnis der Oracle Context abgelegt ist. Dieser enthält die Directory-Einträge zur Namensauflösung. Die Konfigurationsergebnisse werden in einer ldap.ora-Datei abgelegt. Diese befindet sich, wie die anderen Net-Konfigurationsdateien, im Verzeichnis $ORACLE_HOME/ network/admin bzw. $TNS_ADMIN. Der Inhalt einer solchen Datei sieht etwa wie folgt aus: # ldap.ora Network Configuration File: /orabase/network/admin/ldap.ora # Generated by Oracle configuration tools. DIRECTORY_SERVERS= (ldapsrv:389:636) DIRECTORY_SERVER_TYPE = OID DEFAULT_ADMIN_CONTEXT="o=Oracle,c=US" Listing 7.6: Datei ldap.ora
Alternative Methoden zur Namensauflösung
321
Abbildung 7.31: Host und Ports des Verzeichnisses
Sobald eine erste Einrichtung mit dem Net-Konfigurationsassistenten erfolgt ist, können weitere Konfigurationsschritte mit dem Net Manager durchgeführt werden. Im Bereich Profil kann z.B. die Methode LDAP hinzugefügt werden; die Rangordnung der Benennungsmethoden kann durch die Schaltflächen Vorziehen und Zurückstufen beeinflusst werden. Weiterhin enthält der Navigationsbaum des Net Managers nunmehr den Teilbaum Verzeichnis, mit dem Net-Aliasnamen im Verzeichnis gepflegt werden können. Durch die Nennung von LDAP an erster Stelle wird in der Datei sqlnet.ora der Parameter NAMES.DIRECTORY_PATH wie folgt verändert: NAMES.DIRECTORY_PATH= (LDAP, TNSNAMES, EZCONNECT)
Dies bedeutet, dass für die Auflösung eines Net-Aliasnamens zunächst ein Verzeichnisdienst, dann eine tnsnames.ora-Datei und zuletzt die Easy-Connect-Methode verwendet wird.
7.2.4 Welche Methode ist die beste? Den schnellsten Erfolg liefert sicherlich die Easy-Connect-Methode – zumindest dann, wenn man gerade eben den Listener konfiguriert hat und somit alle Kontaktdaten auswendig kennt. Falls eine Anwendung betrieben werden soll, ist es in den allermeisten Fällen angebracht, mit der Auflösung von logischen Namen (Net-Aliasnamen) zu arbeiten. Das hat den Vorteil, dass z.B. bei der Verlagerung einer Instanz von einem Server auf den anderen keine Programme geändert werden müssen, sondern eben nur die Konfiguration.
322
Zugriff auf die Datenbank
Abbildung 7.32: LDAP-Benennungsmethode
Für viele Umgebungen sind tnsnames.ora-Dateien praktikabel, insbesondere wenn nicht allzu häufig Serverdaten geändert werden oder neue Datenbanken hinzukommen. Ab einer gewissen Zahl von Clients ist es allerdings ratsam, sich über die automatisierte Verteilung der Dateien Gedanken zu machen – kein DBA kopiert gerne manuell immer wieder die gleiche Datei an Dutzende Clients. Von der Methode, die Net-Konfigurationsdateien auf einem zentralen Laufwerk abzulegen und über die Variable $TNS_ADMIN zu adressieren, wird, zumindest bei großen tnsnames.ora-Dateien, also ab einigen Dutzend Einträgen, abgeraten. Bei der Namensauflösung greift der Oracle Net Client zeilenweise auf die Datei zu, so dass die Geschwindigkeit für die Namensauflösung im Netzwerk stark beeinflusst wird. Für die Verwendung von LDAP als Auflösung von Net-Aliasnamen ist zunächst eine Lizenz für den Oracle Internet Application Server erforderlich. Es fällt schwer, die Anschaffung eines weiteren, nicht gerade billigen, Produkts zu empfehlen, nur weil Konfigurationsdaten für den Verbindungsaufbau dort verwaltet und aufgelöst werden. Allerdings macht die Verwendung eines Verzeichnisdienstes in größeren Umgebungen Sinn, insbesondere wenn aus anderen Gründen bereits ein Internet Application Server (oder ein MS Active Directory) im Einsatz ist.
Connection Manager
7.3
323
Connection Manager
Der Connection Manager ist eine Art Proxyserver innerhalb der Oracle Net-Umgebung. Mit Hilfe des Connection Managers können Verbindungen über bestimmte Rechner geroutet und dabei die verwendeten Ports definiert werden. Es ist weiterhin möglich, eine Zugriffskontrolle durchzuführen. Schließlich ist im Zusammenhang mit speziellen Dispatcher-Konfigurationen das Session Multiplexing möglich, bei dem mehrere logische Verbindungen über eine einzige tatsächliche Netzwerkverbindung geführt werden. Dies kann im WAN-Umfeld sowohl Performance- als auch Kostenvorteile bringen. Es gibt zwei Einschränkungen für den Connection Manager: 1. Diese Komponente ist der Enterprise Edition der Oracle Database vorbehalten. 2. Die Konfiguration des Connection Managers wird durch keinerlei Werkzeuge unterstützt. Zur Konfiguration eines Connection Managers muss demnach grundsätzlich eine Datei manuell gepflegt werden. Diese heißt cman.ora und ist im Verzeichnis $ORACLE_HOME/network/admin oder $TNS_ADMIN untergebracht. Ein Beispiel für eine Konfiguration folgt: CMWIN= (CONFIGURATION= (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.149.111)(PORT=1525)) (RULE_LIST= (RULE=(SRC=192.168.149.0/24)(DST=*)(SRV=*)(ACT=accept)) (RULE=(SRC=hllap11)(DST=127.0.0.1) (SRV=cmon)(ACT=accept)) ) (PARAMETER_LIST= (LOG_DIRECTORY=D:\OraBase\Network\Log) (LOG_LEVEL=USER) (TRACE_DIRECTORY=D:\OraBase\Network\Log) (TRACE_LEVEL=off) (CONNECTION_STATISTICS=yes) (MAX_CONNECTIONS=20) (MIN_GATEWAY_PROCESSES=5) (MAX_GATEWAY_PROCESSES=20) ) )
Hiermit wird ein Connection Manager namens CMWIN konfiguriert. Im ADDRESSBereich wird die Listener-Adresse des Connection Managers eingestellt; hier mit Port 1525, da 1521 durch den Listener selbst belegt ist. In der RULE_LIST werden ein oder mehrere RULEs (Regeln) angegeben, die beschreiben, wie der Connection Manager funktionieren soll. Es müssen immer mindestens zwei Regel angegeben werden, weil: die Standardeinstellung für Situationen, die nicht über eine Regel beschrieben sind, ist, dass die Verbindung blockiert wird und dass eine zweite Regel für den Monitorprozess (SRV=cmon) vorhanden sein muss.
324
Zugriff auf die Datenbank
In der Parameterliste PARAMETER_LIST können dann noch zusätzliche Parameter für den Connection Manager für das allgemeine Verhalten, z.B. Logging oder Tracing, angegeben werden. Die Kommunikation mit dem Datenbankserver wird durch die Gateway-Prozesse durchgeführt. Man kann mit MIN_GATEWAY_PROCESSES und MAX_GATEWAY_PROCESSES deren minimale und maximale Anzahl bestimmen, wobei das Maximum jeweils 64 ist. MAX_CONNECTIONS bestimmt, wie viele logische Verbindungen bzw. Sitzungen ein Gateway-Prozess verwalten kann; hier liegt das Maximum bei 1024. In Summe können also bis zu 65536 Verbindungen über einen Connection Manager laufen. Zur Administration des Connection Managers wird cmtl benutzt. Ähnlich lsnrctl kann man das kommandozeilenbasierte Werkzeug aufrufen und interaktiv nutzen; alternativ gibt es einen Kommandozeilenmodus. Aus der Kommandozeile ruft man z.B. zum Starten des Connection Managers CMWIN auf: cmctl startup -c cmwin
Mit dem Kommando HELP bekommt man eine Liste der vorhandenen Kommandos. Wichtig für die weitere Administration sind folgende Kommandos: cmctl reload -c für die Aktualisierung der Konfiguration aus der Datei cman.ora cmctl show status -c cmctl show services -c Clients können mit Hilfe der Adressliste explizit konfiguriert werden, indem man sowohl die Adresse des Connection Managers als auch die des Listeners angibt. Dann muss in der Adressliste zusätzlich der Parameter (SOURCE_ROUTE = YES) angegeben werden. RH4CM.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (SOURCE_ROUTE = YES) (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.149.111) (PORT = 1526)) (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.149.211) (PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = RH4.hl.de) ) )
Eine weitere Möglichkeit besteht darin, der Instanz über die Konfiguration des Systemparameters remote_listener den Connection Manager anzugeben. In diesem Fall bekommt der Connection Manager von der Instanz selbst die Konfigurationsdaten des lokalen Listeners sowie der verfügbaren Dienste (Service Registration, wie beim Listener), so dass für den Client lediglich die Adresse des Connection Managers konfiguriert werden muss.
Connection Manager
325
RH4CM.HL.DE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.149.111) (PORT = 1526)) ) (CONNECT_DATA = (SERVICE_NAME = RH4.hl.de) ) )
Session Multiplexing Diese Option wird für Dispatcher an der Instanz konfiguriert, betrifft jedoch sowohl den Dispatcher als auch den Connection Manager. Session Multiplexing bewirkt, dass alle Verbindungen zwischen dem Connection Manager und dem Dispatcher über eine einzige logische Netzwerkverbindung laufen. Im Normalfall bekommt jede Oracle Net-Verbindung auch eine eigene Netzwerkverbindung. Die Konfiguration erfolgt dadurch, dass bei der Dispatcher-Konfiguration die zusätzliche Option (MULTIPLEX=<x>) angegeben wird, wobei <x> für einen der folgenden Werte steht: 1, ON, YES, TRUE oder BOTH bedeuten, dass Session Multiplexing sowohl für eingehende als auch für ausgehende Verbindungen verwendet wird, IN für eingehende Verbindungen, OUT für ausgehende Verbindungen sowie 0, OFF, NO oder FALSE für abgeschaltet. Die Funktionsweise ist auf dem Rechner, wo der Connection Manager läuft, z.B. unter MS-Windows mit dem Kommando netstat -a
aus einer DOS-Box leicht nachzuvollziehen. Dort bekommt man für jede Netzwerkverbindung eine Zeile, die wie folgt aussieht: TCP
hllap11:1743
192.168.45.119:1527
HERGESTELLT
Hierbei läuft der Connection Manager auf dem Rechner hllap11 und hat eine Verbindung, ausgehend von Port 1743, zum Rechner 192.168.45.199 auf Port 1527. Für dieses Beispiel wurde auf der letzten Adresse ein Dispatcher konfiguriert. Ist Session Multiplexing ausgeschaltet, so bekommt man je eine solche Zeile (mit verschiedenen Ausgangsports und der identischen Zieladresse inklusive Port) pro Verbindung. Mit Session Multiplexing ist eine Zeile pro Connection-Manager-GatewayProzess vorhanden (normalerweise zwei). Auch bei vielen Verbindungen (z.B. zehn SQL*Plus-Aufrufe) erhöht sich die Anzahl der Verbindungen nicht.
326
7.4
Zugriff auf die Datenbank
Firewall
Das Zusammenspiel von Firewalls mit Oracle Net ist in den Fällen problematisch, in denen die Firewall selber ausschließlich über die Freischaltung von Ports konfiguriert werden kann. Da für die meisten Client-Server-Verbindungen der Port 1521 lediglich für den Verbindungsaufbau genutzt wird, die Kommunikation im Weiteren über einen beliebigen Port durchgeführt wird, bleibt diese Konfiguration oft in der Firewall hängen. Hierfür gibt es vier brauchbare Lösungsansätze: 1. Oracle-taugliche Firewall Es gibt Firewalls, die den Oracle-Mechanismus »verstehen« und dynamisch weitere Ports – ausschließlich für bestehende Verbindungen – freischalten. Dies ist sicherlich die eleganteste Methode, da alle möglichen Oracle-Konfigurationen hiermit funktionieren. 2. Dispatcher mit fest zugewiesenen Ports Für den Fall einer Shared-Server-Konfiguration können dem oder den Dispatcher(n) feste Ports zugewiesen werden. Somit muss man diese Ports zusätzlich zum Listener-Port freischalten. Diese Methode hilft natürlich nur im Falle einer Shared-Server-Konfiguration weiter. Sie hat des Weiteren zur Folge, dass jeder nicht mehr benutzte oder neu konfigurierte Dispatcher in der Firewall nachkonfiguriert werden muss – immer die Strategie vor Augen, keine Firewall-Löcher auf Reserve zu konfigurieren. 3. Connection Manager Der im vorangegangenen Abschnitt beschriebene Connection Manager hat wie ein Dispatcher feste, vorkonfigurierte Kommunikationsports. Diese können ebenfalls freigeschaltet und dann zur Dedicated-Server-Kommunikation genutzt werden. Als Nachteil könnte sich herausstellen, dass die gesamte Kommunikation über einen Port läuft und dass mit dem Connection Manager eine weitere Komponente im Einsatz ist, die administriert und beobachtet werden muss. 4. Listener-Port teilen für MS-Windows-Systeme In der Registrierung kann unter dem Schlüssel \\HKEY_LOCAL_MACHINE\SOFTWARE \ORACLE\KEY_ eine Zeichenkette USE_SHARED_SOCKET eingerichtet werden, deren Wert auf TRUE gesetzt wird. Damit kann der Port des Listeners mit den Verbindungen geteilt werden, d.h., falls der Listener auf 1521 horcht, laufen alle Verbindungen ebenfalls über 1521. Nach der Einrichtung sollten sowohl Listener als auch Instanz neu gestartet werden. Für das Monitoring aller vier Lösungsansätze sind sowohl Oracle Net-Client-Tracing als auch das netstat-Kommando sehr hilfreich. Client-Tracing kann in der Datei sqlnet.ora eingeschaltet werden mit folgenden Einträgen: TRACE_LEVEL_CLIENT = 16 TRACE_DIRECTORY_CLIENT = D:\OraBase\Network\Trace
Java in der Datenbank
327
Für den Parameter TRACE_LEVEL_CLIENT können laut Handbuch die Parameter USER, ADMIN oder SUPPORT gesetzt werden. Diese entsprechen jedoch auch Zahlenwerten; und ein noch höherer Zahlenwert als SUPPORT ist mit 16 der höchste Trace-Level. Als Zielverzeichnis muss natürlich ein auf dem konkreten System vorhandenes Verzeichnis angegeben werden. Die wichtigste Empfehlung bezüglich Tracing lautet jedoch: Bitte unbedingt wieder ausschalten, nachdem die gewünschten Ergebnisse nachvollzogen sind.
7.5
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 10g 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 ganze Fülle aktueller Informationen, vor allem unter http://java.sun.com.
7.5.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, welche die Variablen »einkapseln«. 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.
328
Zugriff auf die Datenbank
Abbildung 7.33: Schematische Darstellung eines Objekts
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. 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 lautenden 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 Java-Intepreter 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 Justin-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 in der Datenbank
329
7.5.2 Java-APIs in der Datenbank 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. 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 Oracle 10g wird derzeit der Standard Java 2 (JDK 1.2, 1.3 und 1.4) mit JDBC 2.0 sowie nahezu allen Funktionen von JDBC 3.0 unterstützt. JDK 1.1 wird dagegen nicht mehr unterstützt, ein Migrationspfad wird in der Dokumentation Oracle 10g JDBC Developer’s Guide and Reference beschrieben. 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-MemoryBereich der SGA übertragen. Auf diese Weise stehen sie danach für alle weiteren Sessions zur Verfügung. Wie der vorangehende Abschnitt gezeigt hat, kann Java in unterschiedlichen Kontexten eingesetzt werden. Zum Zeitpunkt der Version 10g stehen die folgenden Kontexte oder APIs im Rahmen der Oracle-Datenbank zur Verfügung: Per JDBC können aus Applikationen oder Applets heraus SQL-Kommandos ausgeführt sowie PL/SQL-Code aufgerufen werden. Dabei wird von dem Client-Programm aus eine normale Oracle-Session aufgebaut, und über diese werden entsprechende SQL-Befehle ausgeführt. 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. Die Speicherung von Java-Code in der Datenbank macht es grundsätzlich möglich, Anwendungen der traditionellen »Mittelschicht« in der Datenbankschicht zu installieren.
330
Zugriff auf die Datenbank
Fortgeschrittenere J2EE-Technologien wie Java Servlets (ehemals Oracle Servlet Engine, OSE), Java Server Pages (ehemals OJSP), CORBA oder EJB konnten bis zur Version 9.0.1 direkt in der Oracle-Datenbank eingerichtet werden. Mit den Datenbank-Versionen 9.2.0 sowie 10g wird dies jedoch nicht mehr unterstützt, hierfür wird stattdessen der Oracle Application Server (iAS) mit den Oracle Containers for Java (OC4J) benutzt. Da dieser nicht zur eigentlichen Datenbank gehört, wird im Folgenden nicht weiter auf die damit verbundenen Möglichkeiten eingegangen. Innerhalb der Datenbank werden ausschließlich J2SE-Technologien unterstützt, nämlich JDBC und Java-Prozeduren und Funktionen. SQLJ (Java mit eingebauten SQL-Statements, die von einem Präprozessor in JDBC-Aufrufe umgewandelt werden) wird mit der Version 10g dagegen nicht mehr unterstützt. Hier sollten stattdessen reine JDBC-Anwendungen benutzt werden.
7.5.3 Server-seitige Installation Die Installation der JVM-Option lässt sich am besten über den Database Configuration Assistant und durch Auswahl der entsprechenden Option bewerkstelligen. Der Assistent führt dann eine Reihe von SQL-Skripten aus den Verzeichnissen $ORACLE_HOME/javavm/install, $ORACLE_HOME/xdk/admin und $ORACLE_HOME/rdbms/admin aus; Log-Dateien mit gleichem Namen wie die SQL-Dateien werden im Zuge der Installation erstellt.
Abbildung 7.34: Installation der Oracle JVM durch den Konfigurationsassistenten
Java in der Datenbank
331
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 wurden bereits in Kapitel 7.1.1 besprochen. Sowohl für JDBC als auch zum Aufruf von von Java Stored Procedures oder Functions genügt eine »normale« Oracle Net-Verbindung, beispielsweise über TCP/IP. Zusätzlich sind die folgenden Serverparameter zu konfigurieren oder zu überprüfen: 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 KB Speicher benötigt. Für die Initialisierung der Datenbank mit über 10000 Core-Klassen sollten mindestens 80 MB, besser jedoch ca. 150 MB bereitgestellt werden. java_pool_size – spezifiziert den Speicherbereich für die Methoden- und Klassendefinitionen mit einem Minimum von 20 MB. 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 GB ist extrem hoch gewählt worden und sollte reduziert werden. Beim Überschreiten dieser Grenze wird die Session abgebrochen. Ob die Oracle JVM überhaupt in der Datenbank installiert ist, kann am einfachsten durch folgende Abfrage festgestellt werden: SQL> SELECT comp_id, comp_name, version, status FROM dba_registry COMP_ID COMP_NAME VERSION STATUS -------- ------------------------------ ---------- -----JAVAVM JServer JAVA Virtual Machine 10.1.0.3.0 VALID CATJAVA Oracle Database Java Packages 10.1.0.3.0 VALID
Der aktuelle Verbrauch von Speicherplatz in der SGA kann über die dynamische View v$sgastat abgerufen werden: SQL> SELECT * FROM v$sgastat WHERE pool = 'java pool';
POOL -----------java pool java pool java pool
NAME BYTES -------------------------- ---------joxs heap 149184 free memory 7055040 joxlod exec hp 5378688
Bevor die Datenbank für Entwickler oder Endbenutzer freigegeben wird, sollte auch ein einfacher Funktionstest der Oracle JVM durchgeführt werden. Dies kann z.B. mit folgendem Mini-Java-Programm geschehen (Skript dbatest.java):
332
Zugriff auf die Datenbank
public class dbatest { public static void main (String[] args){ for (int i=0; i<args.length;i++) System.out.println(args[i]); } }
Das Skript wird zunächst kompiliert und die resultierende Klassendatei in die Datenbank geladen: $ javac dbatest.java $ loadjava -user username/password@ps10 -verbose -resolve dbatest.class creating : class dbatest loading : class dbatest created : CREATE$JAVA$LOB$TABLE resolving: class dbatest
Die Java Stored Procedure wird nun als PL/SQL-Prozedur veröffentlicht und ausgeführt. SQL> CREATE OR REPLACE PROCEDURE dba_test ( s1 varchar2, s2 varchar2 ) AS LANGUAGE JAVA NAME 'dbatest.main(java.lang.String[])'; / Prozedur wurde angelegt. SQL> SET SERVEROUTPUT ON SQL> EXEC dbms_java.set_output(5000); PL/SQL-Prozedur wurde erfolgreich abgeschlossen. SQL> EXEC dba_test('Test 1', 'Test 2'); Test 1 Test 2 PL/SQL-Prozedur wurde erfolgreich abgeschlossen.
7.5.4 Clientseitige Installation Voraussetzung für den Aufruf von Java Stored Procedures und Functions ist zunächst eine Anmeldung an die Datenbank. Dafür wird entweder eine Oracle Client-Installation benötigt oder der seit der Datenbank-Version 10g ebenfalls verfügbare »Oracle Instant Client« (siehe Kapitel 7.1.4).
Java in der Datenbank
333
7.5.5 JDBC-Treiber Mit der Oracle-Datenbank 10g bzw. den Client-Installationen werden vier verschiedene JDBC-Treiber ausgeliefert, die für unterschiedliche Szenarien optimiert sind: Der JDBC Thin-Treiber ist komplett in Java geschrieben und daher plattformunabhängig. Er benötigt keinerlei Oracle-Installation. Dieser Treiber kann für alle Arten von Java-Clients, also Java-Applikationen und auch Java-Applets, benutzt werden (in letzterem Fall wird der Treiber einfach in das Applet heruntergeladen). Die Kommunikation mit dem Datenbank-Listener läuft via Java-Sockets über TCP/IP, andere Protokolle sind nicht möglich. Für Applets ist die Benutzung dieses Treibers die einzig mögliche Option. Der JDBC OCI-Treiber benötigt eine vorhandene Oracle Client- oder InstantClient-Installation und übersetzt JDBC-Aufrufe in OCI-Aufrufe. Er liegt als Shared Library vor, ist somit plattformspezifisch und kann daher ausschließlich in Applikationen, nicht jedoch in Applets verwendet werden (ein Herunterladen in das Applet ist offenbar nicht möglich). Nur dieser Treiber ist in der Lage, alle Oracle Net-Adapter (TCP/IP, IPC etc.) zu nutzen. Außerdem bietet er Unterstützung für einige spezielle OCI-Features. Der JDBC Server-Side Internal-Treiber (auch KPRB-Treiber genannt) läuft nicht auf dem Client, sondern auf der Datenbank. Er bietet maximale Performance für Java Stored Procedures, die auf die Datenbank zugreifen müssen. Bei Benutzung dieses Treibers findet keinerlei Netzwerk-Kommunikation statt, sondern lediglich Prozeduraufrufe, da alle beteiligten Komponenten (Oracle-Server, SQL-Engine, JVM und JDBC-Treiber) in demselben Prozess und Adressraum liegen. Der Funktionsumfang ist identisch mit dem des JDBC OCI-Treibers. Zu beachten ist, dass aufgrund der Architektur nur die vorhandene Connection (die so genannte Default-Connection) genutzt werden kann. Weitere Verbindungen an dieselbe oder an andere Datenbanken sind mit diesem Treiber prinzipiell nicht möglich. Der JDBC Server-Side Thin-Treiber ist im Hinblick auf den Funktionsumfang mit dem Thin-Treiber identisch, aber speziell für die Benutzung in Java Stored Procedures und Functions ausgelegt. Er läuft nicht auf dem Client, sondern direkt in der Datenbank und bietet daher die beste Performance beim Zugriff auf die betreffende Datenbank. Im Gegensatz zum Server-Side Internal-Treiber sind aber auch Connects an andere Datenbanken möglich. Dieser Treiber ist interessant, wenn die betreffende Datenbank als Middle-Tier agiert und auf Daten von anderen Datenbanken zugreifen muss. Hier sollen noch einmal einige Entscheidungshilfen für die Wahl des richtigen Treibers gegeben werden: Für Client-Applikationen sollte – wenn nichts dagegen spricht – der Thin-Treiber gewählt werden, da er die beste Performance und Plattformunabhängigkeit bietet und außerdem sowohl für Applikationen als auch für Applets verwendet werden kann. Für Applets muss der Thin-Treiber verwendet werden.
334
Zugriff auf die Datenbank
Für Netzwerke, die nicht auf TCP/IP basieren, kommt nur der OCI-Treiber in Frage Für die Benutzung von LDAP over SSL muss der Thin-Treiber benutzt werden. Bestimmte Oracle-Features, z.B. TAF (Transparent Application Failover, siehe Kapitel 7.1.3), oder die Verwendung von PL/SQL-Index-by-Tabellen werden nur vom OCI-Treiber unterstützt. Genauere Angaben hierzu finden sich in der Dokumentation Oracle 10g JDBC Developer’s Guide and Reference. Läuft der Java-Code auf Server-Seite (also in Java Stored Procedures und Functions) und ist kein Zugriff auf weitere Sessions oder andere Datenbanken nötig, sollte der Server-Side Internal-Treiber verwendet werden, da er hierfür die beste Performance bietet Es muss aber abgeschätzt werden, ob die Beschränkung auf eine einzige Datenbank-Session auf Dauer haltbar ist. Läuft der Java-Code auf Server-Seite, benötigt aber auch Zugriffe auf andere Datenbanken und/oder andere Sessions, sollte der Server-Side Thin-Treiber benutzt werden.
7.5.6 Verbindungen via JDBC Der Aufbau einer JDBC-Connection bildet eine Schnittstelle zwischen Administration und Entwicklung, da hier Besonderheiten der jeweiligen Datenbank bzw. des verwendeten JDBC-Treibers zu berücksichtigen sind. Daher soll dieses Thema hier anhand von Code-Beispielen erläutert werden. Weitergehende Programmbeispiele wie das Absetzen von SQL-Abfragen und die Verarbeitung der Ergebnismengen sind dagegen durch die JDBC-APIs standardisiert und gehören daher eindeutig in den Bereich Java-Entwicklung. Die Oracle-JDBC-Klassen befinden sich in dem Package oracle.jdbc. Für den Verbindungsaufbau wird außerdem das Package oracle.jdbc.pool benötigt. Der einschlägige Java-Code zur Erzeugung eines Connection-Objekts sieht dann wie folgt aus: import oracle.jdbc.*; import oracle.jdbc.pool.OracleDataSource; ... OracleDataSource ods = new OracleDataSource(); String URL = "JDBC-URL siehe unten"; ods.setURL(URL); ods.setUser("schwanke"); // Benutzername ods.setPassword("password"); // Passwort Connection conn = ods.getConnection(); ... conn.close();
Die JDBC-URL hat grundsätzlich das Format jdbc:oracle:driver_type:[username/password]@database_specifier
Java in der Datenbank
335
wobei für driver_type je nach zu verwendendem JDBC-Treiber thin (für den ThinTreiber), oci (für den OCI-Treiber) oder kprb (für den Server-Side Internal-Treiber) eingesetzt wird. Beispiele für JDBC-URLs: Mit jdbc:oracle:thin:@//hlsun:1521/sun10g wird eine Thin-Treiber-Verbindung (impliziert TCP/IP) an die Datenbank mit dem Service-Namen SUN10G auf dem Host HLSUN mit Listener auf Port 1521) aufgebaut. Da keine Oracle-Client-Installation vorausgesetzt wird, können auch keine TNS-Namen benutzt werden. Die Informationen für einen TNS-Eintrag (Host, Port und Service-Name) werden daher direkt in der URL mitgegeben. Bei der Verwendung des OCI-Treibers kann über die URL jdbc:oracle:oci:@sun10g direkt ein TNS-Name (hier SUN10G) angegeben werden. Für den Server-Side Internal-Treiber kann keine Verbindungsinformation angegeben werden, da stets die aktuelle Connection (Default-Connection) benutzt wird. Als URL kann wahlweise jdbc:oracle:kprb oder jdbc:default:connection benutzt werden. Einen Spezialfall bildet eine Anmeldung mit SYSDBA- oder SYSOPER-Privileg. Diese kann z.B. wie folgt geschehen: OracleDataSource ods = new OracleDataSource(); java.util.Properties prop = new java.util.Properties(); prop.put("user", "sys"); prop.put("password", "syspassword"); prop.put("internal_logon", "sysdba"); ods.setConnectionProperties(prop); String url = "jdbc:oracle:oci:@"; ods.setURL(url);
Ein solche Verbindung ist grundsätzlich nicht mit dem Server-Side Internal-Treiber möglich, da hier keine Authentifizierung durch das Betriebssystem möglich ist. Auch gibt es einige weitere Besonderheiten des Server-Side Internal-Treibers, die beachtet werden sollten: Cursor, also Select-Abfragen, müssen explizit geschlossen werden. Ggf. sollte außerdem der Serverparameter open_cursors angehoben werden. Auto-Commit (implizites Commit nach jedem SQL-Statement) ist nicht möglich. Die aktuelle Connection (Default-Connection) kann nicht geschlossen werden.
7.5.7 NLS-Einstellungen für JDBC Java-Methoden wie getString(), setString() oder toString() finden sich in diversen JDBC-Klassen (z.B. in java.sql.ResultSet, oracle.sql.CLOB oder oracle.sql.CHAR) und benötigen offensichtlich Informationen über die verwendeten Zeichensätze, d.h. Client-Zeichensatz sowie Datenbank-Zeichensatz, um geeignete Konvertierungen durchzuführen. Innerhalb einer JVM, also sowohl in Java Stored Procedures als auch in ClientApplikationen oder Applets, wird als Zeichensatz grundsätzlich UTF-16 verwendet.
336
Zugriff auf die Datenbank
Dabei handelt es sich um einen Zeichensatz mit variabler Kodierungslänge (2 Byte oder 4 Byte pro Zeichen), die meisten Zeichen benötigen 2 Byte. Der Client-Zeichensatz ist also festgelegt, eine evtl. gesetzte Umgebungsvariable NLS_LANG wird nicht beachtet. Die eigentliche Konvertierung ist etwas ungewöhnlich realisiert und erfolgt ggf. in zwei Schritten. Wenn als Datenbank-Zeichensatz US7ASCII oder WE8ISO8859P1 verwendet wird, wird direkt in diesen bzw. aus diesem Zeichensatz konvertiert. Ansonsten wird durch den JDBC-Treiber zunächst in UTF-8 konvertiert. Dies hat den Vorteil, dass die über das Netzwerk zu übertragende Datenmenge geringer ist, da die gebräuchlichen ASCII-Zeichen in UTF-8 jeweils 1-ByteRepräsentationen haben. Der zweite Konvertierungsschritt zwischen UTF-8 in dem Datenbank-Zeichensatz wird beim OCI-Treiber und beim Server-Side Internal-Treiber ebenfalls vom Treiber selbst geleistet. Beim Thin-Treiber dagegen wird dieser Schritt vom Datenbank-Server durchgeführt, da der Treiber nicht Informationen über alle Oracle-Zeichensätze hat. Die Sprach- sowie Territoriumseinstellungen werden normalerweise clientseitig über die Parameter NLS_LANGUAGE und NLS_TERRITORY eingestellt. Diese Parameter werden aber vom JDBC-Treiber bei der Anmeldung an die Datenbank gemäß den entsprechenden Einstellungen der JVM (Property user.language) gesetzt, in welcher der Treiber läuft. Dies stellt sicher, dass beispielsweise Oracle-Fehlermeldungen oder Wochentagsbezeichnungen beim Java-Client in dessen Sprache ankommen. Weitergehende Einstellungen sind leider nicht über die NLS-Umgebungsvariablen möglich, sondern müssen innerhalb der Java-Applikation auf Session-Ebene durch die JDBC-Schnittstelle hindurch getätigt werden, es müssen also per JDBC SQLKommandos z.B. der folgenden Art abgesetzt werden. ALTER SESSION SET NLS_DATE_FORMAT=’DD.MM.RRRR’ ALTER SESSION SET NLS_SORT=GERMAN
Eine Komplikation bezüglich der Zeichensatzkonvertierung kann in folgender Situation auftreten: Der Datenbank-Zeichensatz ist weder US7ASCII noch WE8ISO8859P1. Es ist also eine Konvertierung in zwei Schritten notwendig. Der JDBC Thin-Treiber wird benutzt. Dies ist der einzige Treiber, bei dem der zweite Konvertierungsschritt (von UTF-8 in den Datenbank-Zeichensatz) vom Datenbank-Server selbst ausgeführt wird. Eine Bindevariable vom Typ CHAR oder VARCHAR2 wird benutzt. Da die Ergebnisse des zweiten Konvertierungsschritts dem JDBC Thin-Treiber nicht bekannt sind, stellt sich die Frage, wie lang der Wert für eine solche Bindevariable clientseitig sein darf, ohne dass es serverseitig (nach der Konvertierung) zu einem Überlauf und damit einer Datenkorruption kommt. Diese Problematik wird durch einen Expansionsfaktor gelöst, der als konservative Obergrenze für die Verlängerung eines Strings im Rahmen der Konvertierung angesehen werden kann und eindeutig durch den Datenbank-Zeichensatz bestimmt ist. Der Expansionsfaktor entspricht dabei der maximalen Byte-Länge in dem betreffenden Zeichensatz (Ausnahme: UTF8 und AL32UTF8).
Java in der Datenbank
337
Günstig sind daher als Datenbank-Zeichensätze alle Zeichensätze mit fixer Codierungslänge 1 Byte sowie UTF8 oder AL32UTF8, da hier der Expansionsfaktor offensichtlich 1 ist und bis zu 4000 Byte lange Strings gebunden werden können. Ein Zeichensatz wie z.B. JA16EUC dagegen mit dem Expansionsfaktor 3 lässt maximal 4000/3 = 1333 Byte lange Strings zu. Dies führt in der Applikation oft zu Laufzeitfehlern, die schwierig zu finden und zu lösen sind.
7.5.8 Java-Objekte in der Datenbank Neben dem Zugriff via JDBC auf die Datenbank gibt es auch die Möglichkeit, JavaKlassen direkt in der Datenbank abzulegen, wobei der Datenbank-Server die Rolle einer JVM übernimmt. Auf diese Weise können Prozeduren, Funktionen und ganze Java-Applikationen in der Datenbank gespeichert und ausgeführt werden. Konzeptuell ist dies mit PL/SQL-Objekten vergleichbar, allerdings steht über die Programmiersprache Java gleich eine weite Welt an Standards, Implementierungen und Lösungen für die verschiedensten Probleme bereit. Auch das Ausführen von SQLKommandos aus Java-Objekten heraus ist über die JDBC-Treiber, hier insbesondere einen der Server-Side-Treiber, problemlos möglich. Folgende Java-Objekte können in der Datenbank gespeichert werden: Java-Source-Dateien, also .java-Dateien Java-Class-Dateien, also durch die Oracle JVM interpretierbarer Java-Bytecode Java-Resource-Dateien, z.B. mit den Endungen .properties oder .ser Alle vorhandenen Objekte können durch folgende Abfrage ermittelt werden: SQL> SELECT * FROM dba_objects WHERE object_type IN ( 'JAVA CLASS', 'JAVA SOURCE', 'JAVA DATA', 'JAVA RESOURCE');
Über die SQL-Kommandos CREATE/ALTER/DROP JAVA können Java-Objekte in der Datenbank erstellt, verwaltet und gelöscht werden. Üblicher und besser ist jedoch der Zugriff über die Kommandozeilen-Tools loadjava und dropjava, da durch diese Tools bestimmte Verwaltungsinformationen gepflegt werden (s.u.). Außerdem sollten Java-Source-Dateien stets außerhalb der Datenbank kompiliert (mittels javac) und debuggt und anschließend nur die Class-Dateien mittels loadjava geladen werden. Mit loadjava können auch ganze .jar- und .zip-Dateien mit beliebig vielen Klassen- und Resource-Dateien geladen werden. Sollen dagegen Source- und Class-Datei in der Datenbank verwaltet werden, sind beide Objekte voneinander abhängig. Das Class-Objekt kann nicht unabhängig geladen werden, sondern muss durch Kompilierung aus dem Source-Objekt hervorgehen (dies geschieht automatisch, wenn das loadjava-Tool benutzt wird). Ein erneutes Laden oder Löschen ist dann nur für das Source-Objekt möglich und führt ggf. zu einer Invalidierung des Class-Objekts (auf diese Weise werden inkonsistente Stände zwischen Source- und Class-Objekt verhindert). Der Versuch, das ClassObjekt direkt zu verändern, führt typischerweise zu der Fehlermeldung: ORA-29537: class or resource cannot be created or dropped directly
338
Zugriff auf die Datenbank
7.5.9 Resolving Beim Laden oder aber spätestens bei der Ausführung einer Klasse müssen Referenzen, also Bezugnahmen auf andere Klassen, aufgelöst werden, d.h., referenzierte Klassen müssen eindeutig identifiziert werden können. Normalerweise geschieht dies in Java durch Setzen der Umgebungsvariablen CLASSPATH, die angibt, in welchen Verzeichnissen nach den betreffenden Class-Dateien (ggf. in JAR- oder ZIPDateien) gesucht werden soll. Für die Oracle JVM, die Klassen ja nicht im Dateisystem, sondern in der Datenbank speichert und verwaltet, muss es hier offenbar einen anderen Mechanismus geben. Dieses so genannte Resolving, also das Auffinden einer referenzierten Klasse, geschieht in der Oracle JVM durch Angabe einer Liste von Schemata, die nach der betreffenden Klasse gesucht werden. Diese Liste wird »Resolver« genannt. Der Default-Resolver sucht zunächst im aktuellen Schema (also demjenigen Schema, in das die Klasse geladen wurde) und dann im Schema PUBLIC, wo sämtliche CoreKlassen aus dem SYS-Schema per Synonym zugreifbar sind. Befinden sich alle Java-Objekte in einem Schema, genügt daher der Default-Resolver. Sind die benötigten Java-Klassen in der Datenbank dagegen über mehrere Schemata verteilt, muss ein entsprechender Resolver angegeben werden. Dieser wird über eine Kommandozeilen-Option des loadjava-Tools mitgegeben, beispielsweise: $ loadjava –user system/manager@ps10 -schema SCHWANKE -resolve –resolver „((* SCHWANKE) (* AHRENDS) (* PUBLIC))“ dbatest.class
In diesem Fall werden referenzierte Klassen zunächst im Schema SCHWANKE, dann im Schema AHRENDS und schließlich unter den Core-Klassen gesucht. Im Gegensatz zum CLASSPATH, der als Umgebungsvariable global für alle Klassen gesetzt wird, hat in der Oracle JVM jede Klasse ihren eigenen Resolver. Dies erlaubt eine sehr feine granulare Steuerung des Resolving-Mechanismus, kann aber auch lästig und fehleranfällig sein, wenn immer wieder derselbe Resolver angegeben werden muss. Der Resolver und auch alle anderen Parameter können daher auch als Default-Optionen in einer Tabelle abgelegt werden (siehe nächster Abschnitt). Wird eine Klasse nicht gefunden, ist das Java-Objekt anschließend zwar vorhanden, aber invalid. Um dies bewusst zu verhindern, kann als letztes Argument im Resolver (* -) angegeben werden. In diesem Fall werden ggf. Laufzeitfehler ausgelöst. Weitere Steuerungsmöglichkeiten beim Resolving sind in der Dokumentation Oracle 10g Java Developer’s Guide beschrieben.
7.5.10 Tools zur Java-Verwaltung Zur Datenbanksoftware gehören auch die beiden bereits erwähnten Tools loadjava und dropjava. Ihnen sollte der Vorzug vor den SQL-Kommandos CREATE JAVA bzw. DROP JAVA gegeben werden, da sie einige für die Entwicklung transparente, für die Administration aber sehr nützliche Funktionen mitbringen.
Java in der Datenbank
339
Die Basisfunktionalität des loadjava-Tools wie auch des CREATE JAVA-Kommandos ist, eine Java-Klassen- oder Resource-Datei in die Datenbank zu laden, also zu einem für die Oracle JVM ausführbaren Java-Klassen- oder Resource-Objekt zu machen. Das dropjava-Tool sowie der DROP JAVA-Befehl entfernen ein entsprechendes Java-Objekt aus der Datenbank. Die beiden Varianten (SQL-Kommando oder Tool) sollten in ihrer Benutzung grundsätzlich nicht vermischt werden, da der Mehrwert der Tools unter anderem in der Pflege bestimmter Verwaltungsinformationen liegt, die nur dann konsistent vorliegen, wenn die Benutzung dieser Tools auch konsequent erfolgt. Insbesondere bei der Benutzung von Makefiles sowie bei umfangreichen JAR- und ZIP-Dateien oder Lade-Skripten zahlt sich eine konsequente Benutzung von loadjava aus, da dieses Tool eine so genannte Digest-Tabelle schreibt, in der jedem Klassen-Objekt in der Datenbank ein 16-Byte-Hashwert (nach dem MD5-Algorithmus) des Klasseninhalts zugeordnet wird. Bei einem erneuten Laden wird das KlassenObjekt nur dann ersetzt, wenn sich der Hash-Wert (auch Digest genannt) und damit der Klassen-Inhalt geändert haben. Die Digest-Tabelle befindet sich im Zielschema der Java-Objekte und trägt den Namen JAVA$CLASS$MD5$TABLE. Ein Löschen oder Manipulieren dieser Tabelle führt dazu, dass beim nächsten Mal evtl. unnötige Ladeoperationen durchgeführt werden. Auch das dropjava-Tool pflegt diese Tabelle. Sollte der Tabelleninhalt irgendwie korrumpiert worden sein, z.B. weil versehentlich eine Klasse über die SQL-Kommandos neu eingespielt wurde, kann mit der loadjava-Option –force ein erneuter Abgleich erzwungen werden. Für die Tabelle sollte kein Public Synonym angelegt sein, da sie nur für schemainterne Verwaltung ausgelegt ist, insbesondere wird Eindeutigkeit der Klassennamen vorausgesetzt. Nach dem ersten loadjava-Aufruf findet sich im Zielschema außerdem eine Tabelle CREATE$JAVA$LOB$TABLE, die den Inhalt einer Java-Datei in eine LOB-Spalte aufnimmt und daraus anschließend das Klassenobjekt definiert. Dieser Mechanismus erlaubt es, mittels loadjava ohne Vergabe von Zugriffsrechten auf Dateisystemebene den Inhalt einer Java-Datei zu lesen und in die Datenbank zu übertragen. Die Tabelle kann gelöscht werden, wird aber beim nächsten loadjava-Aufruf automatisch neu erstellt. Beim Laden von Java-Resource-Dateien ist zu beachten, dass der Name des Resource-Objekts nicht wie bei Klassen- oder Source-Dateien in der Datei selbst steht. Daher wird einfach der Dateiname inklusive angegebenem Pfad literal als Objektname übernommen. Es macht durchaus einen Unterschied, ob ein relativer oder ein absoluter Pfad angegeben wird. In der Praxis sollte versucht werden, Klassen- und Resource-Dateien in einer JAR-Datei zu bündeln, um diese Problematik zu beseitigen. Ist dies nicht der Fall, sollte loadjava aus dem so genannten PackageRoot-Verzeichnis heraus aufgerufen werden und zu ladende Resource-Dateien relativ zu diesem Verzeichnis qualifizieren.
340
Zugriff auf die Datenbank
7.5.11 Ausgabeumleitung Java-Ausgaben via system.out bzw. system.err gehen per Default in die Trace-Datei der Oracle-Session (das Verzeichnis für solche Trace-Dateien wird durch den Serverparameter user_dump_dest festgelegt). Diese kann daher u.U. stark anwachsen. Hier sollte vorsichtshalber eine Größenbegrenzung der Trace-Dateien mittels des Serverparameters max_dump_file_size etabliert werden. Alternativ kann durch folgenden Prozeduraufruf die Java-Ausgabe für den Rest der Session in den DBMS_OUTPUT-Puffer der Datenbank umgeleitet werden, also wie normale Ausgaben mittels DBMS_OUTPUT behandelt werden (der Parameter gibt die maximale Puffergröße an): SQL> EXECUTE dbms_java.set_output(5000); SQL> SET SERVEROUTPUT ON SIZE 5000
7.5.12 Publishing von Java-Klassen Aus Security-Gründen ist nicht jede in die Datenbank geladene Java-Klasse gleich allgemein verfügbar. Die Bekanntmachung, das so genannte Publishing, einer JavaKlasse, muss vielmehr explizit durch Definition eines Aufruf-Interfaces in Form einer herkömmlichen PL/SQL-Prozedur oder Funktion erfolgen. Eine solche PL/SQLRoutine dient einfach als Wrapper für eine Methode einer Java-Klasse. Im Abschnitt »Serverseitige Installation« (s.o.) ist ein entsprechendes Beispiel gegeben. Aus Gründen der Übersichtlichkeit können und sollten solche Wrapper-Routinen in PL/SQLPackages zusammengefasst werden. Auch Objektmethoden im Rahmen von SQLObjekttypen sind als Wrapper zugelassen. Die Package- bzw. Objekttyp-Deklaration sollte dabei bereits die LANGUAGE JAVA-Klausel umfassen, ein Package-Body oder TypeBody ist dann nicht notwendig. Zum Beispiel: SQL> CREATE OR REPLACE PACKAGE myjava AS PROCEDURE dba_test ( s1 varchar2, s2 varchar2 ) AS LANGUAGE JAVA NAME 'dbatest.main(java.lang.String[])'; END myjava; /
Um eine Java-Methode aufrufen zu können, ist es häufig interessant zu wissen, ob und – wenn ja – welche PL/SQL-Routine diese Java-Methode wrappt. Die Zuordnung von PL/SQL-Wrapper-Routinen zu Java-Methoden ist leider nicht direkt über eine Data-Dictionary-View zu haben. Ist auch kein entsprechendes EntwicklerKnow-how verfügbar, kann man sich aber mit folgender Abfrage behelfen: SQL> SELECT o.owner ,o.object_name AS ,i.procedurename AS ,j.classname AS ,j.methodname AS ,j.usersignature AS FROM sys.procedurejava$ ,sys.procedureinfo$ ,dba_objects o
plsql_object plsql_routine java_class java_method javasignature j i
Die Oracle XML DB WHERE AND AND
341
j.obj# = o.object_id j.obj# = i.obj# j.procedure# = i.procedure#;
Achtung: Diese Abfrage liefert nur dann alle Zuordnungen, wenn – wie oben angeraten – bereits in der Package- bzw. Objekttyp-Deklaration die LANGUAGE JAVA-Klausel angegeben wurde. Leider ist dies auch nicht für alle mitgelieferten PublishingWrapper der Fall.
7.5.13 Deinstallation der Oracle JVM Die Deinstallation der Oracle JVM geschieht, indem entsprechende kompensierende Skripte zu den Installationsskripten in umgekehrter Reihenfolge aufgerufen werden. Dies sind insbesondere in dieser Reihenfolge:
$ORACLE_HOME/rdbms/admin/catnoexf.sql $ORACLE_HOME/rdbms/admin/catnojav.sql $ORACLE_HOME/xdk/admin/rmxml.sql $ORACLE_HOME/javavm/install/rmjvm.sql
Zur Sicherheit sollte man sich bei der Installation der Oracle JVM vom DBCA ein Skript generieren lassen. Dort finden sich alle aufgerufenen Skripte. Die zugehörigen kompensierenden Skripte sind meist relativ leicht zu finden.
7.6
Die Oracle XML DB
Seit der Datenbankversion Oracle9i ist es möglich, XML-Daten und XML-Dokumente als solche in der Datenbank zu speichern, zu verwalten und zu verarbeiten (vorher war bestenfalls eine Speicherung in CLOB- oder LONG-Spalten möglich). Dies kann manuell durch den Benutzer eingerichtet werden, indem so genannte XMLTYPE-Tabellen oder Spalten mit XMLTYPE-Datentyp zur Speicherung solcher Dokumente definiert werden. Alternativ steht ein vorgefertigtes Repository zur Aufnahme von XML-Dokumenten zur Verfügung, das nach außen hin wie ein Dateisystem präsentiert werden kann (zugreifbar beispielweise über FTP oder Windows Explorer). Intern ist das Repository über Tabellen und Indizes in einem eigenen Schema XDB realisiert. Der Zugriff auf dieses Repository ist über diverse Schnittstellen möglich: Durch die Views RESOURCE_VIEW und PATH_VIEW im XDB-Schema Durch das PL/SQL-Package DBMS_XDB Via FTP, HTTP oder WebDAV. Hierbei kommen die so genannten XML DB-Protokollserver zum Einsatz. Im Folgenden werden die administrativen Aspekte bei der Arbeit mit der XML DB beschrieben, insbesondere die Installation sowie Konfiguration des Repositories und der Protokollserver.
342
Zugriff auf die Datenbank
7.6.1 Installation der XML DB Bei der Erzeugung einer Datenbank mit dem Database Configuration Assistant (DBCA) kann die Installation der XML DB unter dem Punkt »Standard-Datenbankkomponenten« angewählten werden:
Abbildung 7.35: Installation der XMLDB durch den Konfigurationsassistenten
Die Voreinstellung (Speicherung im Tablespace SYSAUX) ist nur eingeschränkt zu empfehlen. Wenn absehbar ist, dass nicht nur geringfügige Datenmengen abgespeichert werden sollen, ist ein eigener Tablespace für das XML-DB-Repository anzuraten. Ob die XML-DB überhaupt in der Datenbank installiert ist, kann am einfachsten durch folgende Abfrage festgestellt werden: SQL> SELECT comp_id, comp_name, version, status FROM dba_registry COMP_ID COMP_NAME VERSION STATUS -------- ------------------------------ ---------- -----XDB Oracle XML Database 10.1.0.3.0 VALID
Eine manuelle Nachinstallation des XML-DB ist einfach durch Aufruf folgender Skripte unter dem Benutzer SYS möglich: SQL> @?/rdbms/admin/catqm.sql <XDB-Passwort> <XDB-Tablespace> <XDB-Temp-Tablespace> SQL> @?/rdbms/admin/catxdbj.sql
Bei der Installation werden zwei Benutzer angelegt (XDB und ANONYMOUS). Beide Accounts sind zunächst gesperrt. Der Benutzer XDB ist der Besitzer des Repositories und sollte auch gesperrt bleiben. Der Benutzer ANONYMOUS hat überhaupt keine Objekte. Er kann zum Zwecke eines HTTP-Zugriffs ohne Logon entsperrt werden (siehe unten).
Die Oracle XML DB
343
7.6.2 Einrichtung der Protokollserver Der Zugriff auf die in der XML DB abgelegten Dokumente ist neben dem Weg über programmatische APIs (PL/SQL, Java, C etc.) auch über Standardprotokolle (FTP und HTTP) sowie aus WebDAV-Clients wie beispielsweise dem Windows Explorer heraus möglich. Der Zugriff geschieht dabei über TCP/IP-Ports auf dem Datenbankserver. Diese Ports werden durch den normalen Datenbank-Listener abgehört. Ein gestarteter Listener ist daher Voraussetzung für die Benutzung der Protokollserver. Achtung: Nach einem Neustart des Listeners dauert es ca. eine Minute, bis die Datenbank beim Listener automatisch registriert wird. Für Hochverfügbarkeitsumgebungen kann eine explizite Registrierung über den SQL-Befehl ALTER SYSTEM REGISTER durchgeführt werden. Per Default sind der Port 8080 für HTTP- und WebDAV-Zugriff sowie der Port 2100 für FTP-Zugriff eingerichtet. Die aktuellen Werte sind zwar nicht in der ListenerKonfigurationsdatei eingetragen, können aber dennoch über den Listener abgefragt werden: $ lsnrctl status ... Zusammenfassung Listening-Endpunkte ... (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP53)(PORT=1521))) (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP53)(PORT=2100)) (Presentation=FTP)(Session=RAW)) (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=HLLAP53)(PORT=8080)) (Presentation=HTTP)(Session=RAW)) Services Übersicht ... Dienst "PS10" hat 1 Instance(s). Instance "PS10", Status READY, hat 1 Handler für diesen Dienst ... Dienst "PS10XDB.WORLD" hat 1 Instance(s). Instance "ps10", Status READY, hat 1 Handler für diesen Dienst ... ...
Die beiden Listener-Endpunkte mit dem Argument Presentation geben die aktuellen Ports an. Bei einer Connect-Anforderung über einen dieser Ports wird durch den Listener eine Verbindung zur Datenbank im Shared-Server-Modus aufgebaut. Die Anmeldung geschieht dabei über den Dienst PS10XDB.WORLD. Als Anmeldeinformationen muss ein Oracle-Benutzer mit seinem Passwort angegeben werden. Damit dieser Dienst im Shared-Server-Modus benutzt werden kann, muss folgender Serverparameter gesetzt sein: dispatchers='(PROTOCOL=TCP) (SERVICE=XDB)'
Der DBCA setzt diesen Parameter beim Erzeugen der Datenbank automatisch. Im Falle einer Nachinstallation ist ein manuelles Setzen des Parameters (z.B. mittels ALTER SYSTEM-Kommando) inklusive anschließendem Neustart der Datenbank notwendig.
344
Zugriff auf die Datenbank
7.6.3 Benutzung der Protokollserver FTP-Zugriff Der FTP-Zugriff auf die XML-DB kann über jeden beliebigen FTP-Client erfolgen: $ ftp ftp> open hllap53 2100 Verbindung mit HLLAP53 wurde hergestellt. 220 HLLAP53 FTP Server (Oracle XML DB/Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 - Production) ready. Benutzer (HLLAP53:(none)): system 331 pass required for SYSTEM Kennwort: 230 SYSTEM logged in ftp>
Anschließend kann mit den üblichen FTP-Kommandos (get, put, mkdir etc.) gearbeitet werden. HTTP-Zugriff Über die URL http://hllap53:8080 ist der lesende Zugriff aus einem Webbrowser heraus möglich.
Abbildung 7.36: Zugriff auf die XML DB via Webbrowser
Es kann auch ein anonymer HTTP-Zugriff (ohne Login) ermöglicht werden. Dazu ist in der Datenbank der Benutzer ANONYMOUS zu entsperren. SQL> ALTER USER anonymous ACCOUNT UNLOCK;
Die Oracle XML DB
345
Zugriff via WebDAV In MS-Windows 2000 und XP kann die XML DB über die Netzwerkumgebung auch im Windows Explorer oder in Dateiauswahl-Dialogen angesprochen werden. Dort wird die gesamte XML DB als Verzeichnis dargestellt, als so genannter Web-Folder. Um einen solchen Web-Folder unter MS-Windows XP einzurichten, wird zunächst der Menüpunkt »NETZLAUFWERK VERBINDEN...« aufgerufen, mit dem auch die üblichen Windows-Freigaben eingebunden werden. Anschließend wird aber kein Freigaben-Name eingetragen, sondern der Link »MIT EINEM NETZWERKSERVER VERBINDEN« ausgewählt.
Abbildung 7.37: Einrichtung eines Web-Folders
Der restliche Vorgang ist durch einen Assistenten geführt. Als Netzwerkadresse wird dieselbe URL wie oben für den HTTP-Zugriff verwendet (WebDAV ist technisch gesehen eine Erweiterung des HTTP-Protokolls), also beispielsweise http:// hllap53:8080. Nach Eingabe der Anmeldeinformationen kann ein beliebiger Verzeichnisname für den Web-Folder vergeben werden. Damit ist die Einrichtung schon komplett. Achtung: Im Gegensatz zu Netzlaufwerken wird einem Web-Folder kein Laufwerksbuchstabe zugeordnet. Stattdessen erscheint er mit seinem zugeordneten Namen unter der Windows-Netzwerkumgebung. Anders als bei Netzlaufwerken ist es auch nicht möglich, den Web-Folder direkt auf ein bestimmtes Verzeichnis der XML-DB (im Sinne einer Freigabe) zeigen zu lassen. Der Benutzer muss daher stets selbst in entsprechende Unterverzeichnisse navigieren. Da WebDAV als HTTP-Erweiterung ein zustandsloses Protokoll ist, gestaltet sich die Anzeige und Bearbeitung von Verzeichnissen mit sehr vielen Dateien aber performanter als bei den üblichen Windows-Verzeichnissen oder Freigaben.
346
Zugriff auf die Datenbank
7.6.4 Konfiguration der Protokollserver Die Protokollserver werden nicht über die Listener-Konfigurationsdatei konfiguriert, sondern haben eine eigene Konfigurationsdatei, die selber innerhalb der XML DB liegt. Ist letztere z.B. via FTP oder WebDAV verfügbar, kann sie entsprechend editiert werden. Die betreffende Datei liegt direkt im Hauptverzeichnis der XML DB und heißt xdbconfig.xml. Hier ein Ausschnitt aus der Datei xdbconfig.xml, in dem u.a. die Ports für die Protokollserver eingetragen sind: ... 2100 local_listener tcp 0 <session-timeout>6000 8192 8080 local_listener tcp <max-http-headers>64 <max-header-size>16384 <max-request-body>2000000000 <session-timeout>6000 <server-name>XDB HTTP Server 0 ...
Wird diese Datei durch eine veränderte Version ersetzt, werden die neuen Einstellungen automatisch sofort wirksam.
Globalization Support 8.1
Überblick
Unter dem Oberbegriff Globalization Support sind bei Oracle alle Mechanismen und Möglichkeiten zusammengefasst, die sich mit der Unterstützung von internationalen Anwendungen befassen. Dies betrifft Sprachen, z.B. für Fehlermeldungen, landesspezifische Konventionen, wie Dezimal- und Tausendertrennzeichen, Währungssymbole und Formate, sowie diverse Zeichensätze. In früheren Oracle-Versionen wurde hierfür die Bezeichnung National Language Support verwendet. Die alte Bezeichnung trifft den Hintergrund der Vorgehensweise, die damals im Fokus stand: In jedem Land sollten die dort verwendete Sprache sowie die für deren Darstellung üblichen Schriftzeichen unterstützt werden, d.h., die Betonung lag auf National. Heute ist es jedoch für Unternehmen unerlässlich, sich dem Trend der Globalisierung in der Weltwirtschaft anzuschließen. Daher müssen nicht mehr nur die eigene Sprache und vielleicht die des Nachbarlandes unterstützt werden, sondern zumindest die eines Kontinents – was in Europa bereits eine sehr anspruchsvolle Aufgabe ist – oder sogar der ganzen Welt. Somit ist der Name Globalization Support für diese neuen Anforderungen treffend gewählt.1 Damit diverse Sprachen, Konventionen und Zeichensätze gleichzeitig von verschiedenen Clients einer Instanz genutzt werden können, sind praktisch alle Parameter für den Globalization Support sowohl im Client als auch im Server einstellbar. Die Serverparameter haben den Sinn, Standardwerte für die Clients zu setzen, die keinen expliziten Wert setzen. Diese haben jedoch praktisch keine Auswirkungen auf irgendwelche Verbindungen, da durch den meist immer verwendeten Parameter NLS_LANG auf der Clientseite ebenfalls Standardwerte für die gewählte Sprache gesetzt werden. Daher werden Serverparameter in der Regel nicht benutzt. Zwei Parameter auf der Serverseite werden bereits beim Anlegen der Datenbank gesetzt und können dann nur noch unter recht scharfen Bedingungen und mit großem Aufwand geändert werden: der Datenbankzeichensatz und der nationale Datenbankzeichensatz. Diese beiden Zeichensätze bestimmen, wie sämtliche Zeichenketten innerhalb der Datenbank gespeichert werden – und damit natürlich auch, welche Zeichen dafür zur Verfügung stehen. Auf der Clientseite wird für jede Sitzung der passende Zeichensatz eingestellt. Die TTC-Schicht von Oracle Net ist dafür zuständig, die Zeichen für die Client-ServerKommunikation zu konvertieren, falls Client und Server nicht die gleichen Zeichensätze benutzen.
1
Trotz des Namenswechsel tragen die meisten Parameter nach wie vor das Kürzel NLS im Namen – eine Umbenennung wäre wohl auch zu viel des Guten.
348
8.2
Globalization Support
Grundeinstellung
Zunächst bestimmt man beim Anlegen der Datenbank mindestens den Datenbankzeichensatz sowie optional den nationalen Datenbankzeichensatz. Dies erfolgt innerhalb des CREATE DATABASE-Befehls mit den folgenden Optionen: ... CHARACTER SET WE8MSWIN1252 NATIONAL CHARACTER SET UTF8 ...
In diesem Beispiel werden als Datenbankzeichensatz der westeuropäische MS-Windows-Zeichensatz mit der Codepage 1252, als nationaler Datenbankzeichensatz der UNICODE-Zeichensatz UTF8 verwendet. Alle CHAR-Datentypen (wie CHAR, VARCHAR, VARCHAR2) benutzen in einer so erzeugten Datenbank den Zeichensatz WE8MSWIN1252, alle NCHAR-Datentypen (wie NCHAR, NVARCHAR, NVARCHAR2) UTF8. Bei der Auswahl der Zeichensätze ist darauf zu achten, dass alle Zeichen, die man in den CHAR- und NCHAR-Feldern der Datenbank speichern möchte, darin enthalten sind. Im zweiten Schritt muss der Client nur noch bestimmen, mit welchem Zeichensatz er arbeitet. Wird MS-Windows als Client verwendet, so ist dies zumindest in Deutschland (und wahrscheinlich auch im restlichen Westeuropa) ebenfalls WE8MSWIN1252. Der Parameter NLS_LANG, mit dem der Zeichensatz ausgewählt wird, enthält zusätzlich zum Zeichensatz je eine Komponente für die Sprache und das Gebiet in der folgenden Form: <Sprache>_.
Ein vollständiges Beispiel ist: NLS_LANG = GERMAN_GERMANY.WE8MSWIN1252
Beim Einsatz von MS-Windows steht dieser Parameter naturgemäß in der Registrierung unter dem Pfad: \\HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_
Unter Unix ist NLS_LANG als Umgebungsvariable zu setzen.
Sprachen und landesspezifische Konventionen
8.3
349
Sprachen und landesspezifische Konventionen
8.3.1 Sprache, Gebiet und Datumsformat Die Auswahl von Sprache und Gebiet über NLS_LANG ist sicher eine komfortable Möglichkeit, den Anwender einer Oracle-basierten Anwendung zu unterstützen. Gerade diese Auswahlmöglichkeit kann jedoch zu einiger Verwirrung bei der Ausführung von Anwendungen führen. Als Beispiel soll hier die Ausgabe zu folgendem SQL-Befehl dienen: SELECT TO_DATE('01.03.2005', 'DD.MM.YYYY') datum FROM DUAL /
Mit der Einstellung AMERICAN_AMERICA.WE8MSWIN1252 sieht die Ausgabe wie folgt aus: DATUM --------01-MAR-05
Folgendes Ergebnis erhält man mit GERMAN_GERMANY.WE8MSWIN1252: DATUM -------01.03.05
Ein weitere Variante ist GERMAN_AMERICA.WE8MSWIN1252: DATUM --------01-MRZ-05
Für diejenigen, die bereits mit älteren Oracle-Versionen gearbeitet haben: Die dreistellige Abkürzung für März war bis einschließlich Oracle9i Release 2 immer MÄR. Dabei handelt es sich aber offensichtlich um einen Bug, und mit dem Release 9.2.0.6 und in der Oracle 10g wurde dies in MRZ geändert (Bug 2964856). Aus den Ausgaben kann man schließen, dass offensichtlich die Einstellungen für Sprache und Gebiet Auswirkungen auf andere Parameter haben, etwa das Datumsformat (DD-MON-RR2 für das Gebiet Amerika, DD.MM.RR für Deutschland) und die Datumssprache (entsprechend der Sprache). An dieser Stelle sei erwähnt, dass Werte vom Datentyp DATE intern in einem Binärformat abgelegt werden, das vom Darstellungsformat unabhängig ist. Daher ist z.B. sichergestellt, dass Jahreszahlen grundsätzlich vierstellig gespeichert werden. Das Datumsformat ist zur Ein- und Ausgabe von DATE-Werten da. Bei der Ausgabe wird grundsätzlich die SQL-Funktion to_char mit der auf Sitzungsebene aktiven Formatmaske durchlaufen, bei der Eingabe von Werten entsprechend die SQL-Funktion to_date. 2
Das RR-Format ist ein zweistelliges Jahreszahlformat, bei dem das Jahrhundert etwas intelligenter gesetzt wird als beim YY-Format. Letzteres nimmt als Jahrhundert grundsätzlich das aktuelle Jahrhundert an. Beim RR-Format wird das vorangegangene Jahrhundert angenommen, wenn man sich in der ersten Hälfte eines Jahrhunderts befindet und eine Zahl größer oder gleich 50 als Jahreszahl eingibt. Bei der Eingabe von 98 im Jahr 2005 wird also 1998 angenommen anstelle von 2098 beim YY-Format. Analog wird in der zweiten Hälfte eines Jahrhunderts das Folgejahrhundert angenommen, wenn man eine Zahl kleiner 50 eingibt.
350
Globalization Support
Eine Zusammenfassung aller NLS-Parameter und deren für die aktuelle Sitzung gültigen Werte liefert die View nls_session_parameters. Hier die Ausgabe eines SELECTBefehls auf diese View mit der NLS_LANG-Einstellung GERMAN_GERMANY.WE8MSWIN1252: PARAMETER -----------------------------NLS_LANGUAGE NLS_TERRITORY NLS_CURRENCY NLS_ISO_CURRENCY NLS_NUMERIC_CHARACTERS NLS_CALENDAR NLS_DATE_FORMAT NLS_DATE_LANGUAGE NLS_SORT NLS_TIME_FORMAT NLS_TIMESTAMP_FORMAT NLS_TIME_TZ_FORMAT NLS_TIMESTAMP_TZ_FORMAT NLS_DUAL_CURRENCY NLS_COMP NLS_LENGTH_SEMANTICS NLS_NCHAR_CONV_EXCP
VALUE -----------------------------------GERMAN GERMANY € GERMANY ,. GREGORIAN DD.MM.RR GERMAN GERMAN HH24:MI:SSXFF DD.MM.RR HH24:MI:SSXFF HH24:MI:SSXFF TZR DD.MM.RR HH24:MI:SSXFF TZR BINARY BYTE FALSE
Auffällig ist, dass man nicht NLS_LANG, sondern zwei seiner Komponenten, die Sprache und das Gebiet, als NLS_LANGUAGE und NLS_TERRITORY wiederfindet. Diese beiden unterscheiden sich von den anderen dadurch, dass sie auf Sitzungs- und Systemparameterebene einzeln modifizierbar sind, als Umgebungsvariable jedoch nicht. Alle anderen Parameter können überall vorgegeben werden: als Systemparameter, als Umgebungsvariable und über einen ALTER SESSION-Befehl auf Sitzungsebene. Ist keine der Varianten vorgegeben, so zieht die jeweilige Standardeinstellung, die in den allermeisten Fällen der amerikanischen Variante entspricht. Ebenfalls auffällig ist, dass der eingestellte Clientzeichensatz nicht in der Liste vorkommt. Dieser ist auch mit anderen Mitteln nicht abfragbar! Eine mögliche Erklärung hierfür ist, dass der Clientzeichensatz bzw. dessen Konvertierung in den Datenbankzeichensatz transparent von der TTC-Schicht in Oracle Net übernommen wird, so dass beim Server keinerlei Information über den Clientzeichensatz ankommt. Sogar die Abfrage der sys_context-Funktion3 mit dem Parameter LANGUAGE ergibt zwar eine Zeichenkette, deren Format dem NLS_LANG-Parameter entspricht, enthält jedoch als dritte Komponente den Datenbankzeichensatz (und nicht den Clientzeichensatz): SQL> SELECT sys_context('USERENV', 'LANGUAGE') 2 FROM dual; SYS_CONTEXT('USERENV','LANGUAGE') --------------------------------AMERICAN_AMERICA.WE8ISO8859P15 3
Die sys_context-Funktion ist Bestandteil der Oracle SQL-Funktionen und erlaubt es, diverse Informationen über die aktuelle Sitzung abzufragen. Sie ersetzt die (aus Kompatibilitätsgründen nach wie vor vorhandene) userenv-Funktion.
Sprachen und landesspezifische Konventionen
351
Weitere wichtige NLS-Parameter sind NLS_DATE_FORMAT und NLS_DATE_LANGUAGE. Sie bestimmen das Standardformat für die Ein- und Ausgabe von Werten vom Datentyp DATE. Im o.a. Beispiel wurde das Format abhängig von der Gebietseinstellung verändert. Sowohl das Format als auch die Sprache können innerhalb der Sitzung bzw. über Umgebungsvariablen verändert werden: SQL> SELECT TO_DATE('01.03.2005', 'DD.MM.YYYY') datum 2 FROM DUAL 3 /
DATUM --------01-MAR-05 SQL> ALTER SESSION SET nls_date_format = 'DD.MM.YYYY HH24:MI:SS'; Session altered. SQL> SELECT TO_DATE('01.03.2005', 'DD.MM.YYYY') datum 2 FROM DUAL 3 / DATUM ------------------01.03.2005 00:00:00 SQL> SELECT sysdate FROM dual; SYSDATE ------------------03.06.2005 15:41:43
Möchte man das zuletzt verwendete Datumsformat inklusive Uhrzeit als Standard einstellen, kann man den Parameter NLS_DATE_FORMAT als Umgebungsvariable setzen: NLS_DATE_FORMAT="dd.mm.yyyy hh24:mi:ss" export NLS_DATE_FORMAT
Unter MS-Windows ist ein entsprechender Wert in der Registrierung zu setzen. Beim Oracle Datums- und Uhrzeitformat gibt es viele mögliche Einstellungen, u.a. für ausgeschriebene oder abgekürzte Tages- und Monatsbezeichnungen. Hierzu ist die Einstellung NLS_DATE_LANGUAGE wichtig:
352
Globalization Support
SQL> SELECT to_char(sysdate, 'Day') FROM dual; TO_CHAR(S --------Friday SQL> ALTER SESSION SET NLS_DATE_LANGUAGE = 'Spanish'; Session altered. SQL> SELECT to_char(sysdate, 'Day') FROM dual; TO_CHAR(S --------Viernes
Eine weitere Einstellung bezüglich des Datums ist NLS_CALENDAR. Für viele ist die Verwendung des gregorianischen Kalenders selbstverständlich – andere Kulturen verwenden jedoch auch andere Kalender. Momentan werden die Kalender Japanese Imperial, ROC Official (Republic of China), Thai Buddha, Persian, Arabic Hijrah und English Hijrah unterstützt. Die Darstellung setzt meist einen bestimmten Zeichensatz voraus.
8.3.2 Zeitzonen, Zeitstempel und Intervalle Eine Erweiterung des DATE-Datentyps ist TIMEZONE. Dieser enthält zusätzlich zu den Sekunden deren Bruchteile sowie optional Zeitzonen-Informationen. Mit den Zeitzonen verhält es sich wie mit den Zeichensätzen: Sowohl die Datenbank als auch jede Sitzung haben eine Zeitzone eingestellt, und wenn man nichts weiter unternimmt, stellt die Oracle-Software entsprechende Standardwerte ein. Diese werden dann entsprechend den Einstellungen des jeweiligen Betriebssystems übernommen. Die möglichen Werte für Zeitzonen sind: Offsets von der Coordinated Universal Time (UTC, entspricht Greenwich Mean Time) Ortsangaben, die implizit die Zeitzone enthalten (wie z.B. Europe/Berlin) Abkürzungen für Standardzeiten bzw. Sommerzeiten (wie CET oder CEST) Die Datenbankzeitzone wird beim CREATE DATABASE eingestellt, entweder auf einen vom Betriebssystem ausgelesenen Wert oder den Wert, der mit der SET TIME_ZONEKlausel des CREATE DATABASE-Befehls angegeben wird. Die Datenbankzeitzone kann mit einem ALTER DATABASE-Befehl später geändert werden, es sei denn, in der Datenbank existieren bereits Tabellen mit Spalten vom Datentyp TIMESTAMP WITH LOCAL TIME ZONE. Oracle empfiehlt, die Datenbankzeitzone für alle Datenbank auf UTC zu normieren, damit beim Datenaustausch zwischen den Systemen keine zeitaufwändigen Konvertierungen stattfinden. Die Datenbankzeitzone kann mit der SQL-Funktion dbtimezone abgefragt werden.
Sprachen und landesspezifische Konventionen
353
Die Einstellung der Zeitzone auf Sitzungsebene erfolgt entweder über die Umgebungsvariable ORA_SDTZ oder einen ALTER SESSION-Befehl wie: ALTER SESSION SET TIME_ZONE = 'CET';
Zur Abfrage der Sitzungszeitzone gibt es ebenfalls eine SQL-Funktion, nämlich sessiontimezone. Sommerzeiten (engl. Daylight Savings Time) werden von Oracle automatisch behandelt. Gültige Werte für Zeitzonen sind über die View v$timezone_names abfragbar. Der Inhalt dieser View entspricht der Zeitzonendatei, die Oracle gerade verwendet. Es werden grundsätzlich zwei Zeitzonendateien im Verzeichnis $ORACLE_HOME/oracore/ zoneinfo ausgeliefert. Es handelt sich um eine umfassende Datei timezlrg.dat sowie um eine Datei timezone.dat, die etwa die Hälfte der Einträge der ersten Datei besitzt – laut Oracle die am häufigsten genutzten Zeitzonen (allerdings ist z.B. Europe/Berlin nicht enthalten). Standardmäßig wird die große Datei benutzt.4 Will man die andere Datei benutzen, so muss vor dem Start der Instanz die Umgebungsvariable ORA_TZFILE gesetzt werden: ORA_TZFILE=$ORACLE_HOME/oracore/zoneinfo/timezone.dat export ORA_TZFILE
Es besteht jedoch aus Sicht der Autoren keinerlei Veranlassung zur Verwendung der kleinen Datei. Nachdem nun die Zeitzonen definiert sind, kann der Datentyp für Zeitstempel, TIMESTAMP, behandelt werden. Er enthält zusätzlich zu den in DATE vorhandenen Feldern Sekundenbruchteile mit 0 bis 9 Stellen Genauigkeit (Standardwert ist 6). Die Genauigkeit für Sekundenbruchteile kann bei der Deklaration in Klammern angegeben werden. Der Datentyp TIMESTAMP existiert weiterhin in drei Varianten: TIMESTAMP, TIMESTAMP WITH TIME ZONE und TIMESTAMP WITH LOCAL TIME ZONE. Für TIMESTAMP und TIMESTAMP WITH LOCAL TIME ZONE wird keine Zeitzoneninformation im Datensatz gespeichert, wobei für letzteren Datentyp die gespeicherten Werte auf die Datenbankzeitzone normiert werden, d.h., bei der Ein- und Ausgabe von Werten wird zwischen Sitzungs- und Datenbankzeitzone konvertiert, falls diese unterschiedlich sind. Für TIMESTAMP WITH TIME ZONE wird die Zeitzoneninformation im Datensatz abgelegt. Auch TIMESTAMP-Werte werden wie DATE-Werte in einem internen Binärformat gespeichert; daher sind ebenfalls Formatmasken für die Ein- und Ausgabe von Werten zuständig. Für Werte vom Typ TIMESTAMP und TIMESTAMP WITH LOCAL TIME ZONE ist die Variable NLS_TIMESTAMP_FORMAT, für Werte vom Typ TIMESTAMP WITH LOCAL TIME ZONE ist es NLS_TIMESTAMP_TZ_FORMAT. Zusätzlich zu den Formatelementen des DATE-Datentyps wird die Sekundenangabe (typischerweise SS) ergänzt um XFF[n]. Dabei steht das X für das Dezimaltrennzeichen zwischen Sekunden und Bruchteilen (und entspricht damit in etwa dem D-Formatelement bei den NUMBER-Formaten). Das FF steht für die eigentlichen Bruchteile und übernimmt die Anzahl Stellen vom Datentyp. Optional kann die Stellenzahl zwischen 1 und 9 auch explizit gewählt werden. 4
Dies ist ein Unterschied zu den Vorgängerversionen, die standardmäßig die kleine Datei benutzt haben.
354
Globalization Support
Zeitzonen werden im Format entweder über die Felder TZH und TZM (als Stunden und Minuten Differenz von UTC), die Regionsbezeichnung TZR (z.B. Europe/Berlin) bzw. die Standardabkürzung der Zeitzone inklusive Sommerzeitinformation TZD (z.B. CET bzw. CEST) dargestellt. Für international genutzte Anwendungen haben die TIMESTAMP WITH [LOCAL] TIME ZONE-Datentypen große Vorteile gegenüber DATE, da durch die Mitbetrachtung der Zeitzone die Zeitunterschiede zwischen den verschiedenen Benutzern der Anwendungen keine Fehler mehr verursachen können. Die Auswahl des Datentyps (LOCAL oder nicht) ist davon abhängig zu machen, ob die explizite Zeit inklusive Zeitzoneninformation später eine Rolle spielen kann oder nicht. Die zusätzlichen Datentypen zur Darstellung von Intervallen INTERVAL YEAR TO MONTH und INTERVAL DAY TO SECOND unterstützen die TIMESTAMP-Datentypen, so dass Berechnungen hiermit einfach möglich sind. Die bekannten Funktionen für die DATEArithmetik (wie z.B. add_months) sollten für TIMESTAMP-Berechnungen nicht verwendet werden, da diese eine implizite Typkonvertierung zu DATE durchführen und somit sowohl die Sekundenbruchteile als auch die Zeitzoneninformation verlieren.
8.3.3 Sortierreihenfolgen Die Einstellung der Sortierreihenfolge wird über den Parameter NLS_SORT gesteuert, dessen Standardwert BINARY ist. Wird die Sprache (NLS_LANGUAGE) auf GERMAN gesetzt, so gilt diese Einstellung zunächst auch für NLS_SORT. Allerdings gibt es insgesamt vier deutsche Sortierreihenfolgen für Oracle: GERMAN, GERMAN_DIN, XGERMAN und XGERMAN_DIN. Alle basieren auf der Norm DIN 5007, unterscheiden sich jedoch in der Behandlung von Groß- und Kleinschrift, den Umlauten gegenüber AE, OE und UE sowie des »ß«. Zur Einstellung der gewünschten Sortierreihenfolge sollte man die Möglichkeiten ausprobieren und die gewünschte Variante auswählen. Nähere Informationen hierzu finden sich auch in der folgenden Metalink Notiz »Note: 130318.1 How Sorting with NLS_SORT=GERMAN Works«. Wichtig im Zusammenhang mit Sortierreihenfolgen ist, dass Indizes auf CHARDatentypen grundsätzlich binär sortiert sind. Damit ist es (unabhängig von allen anderen Optimierungskriterien) grundsätzlich nicht möglich, eine ORDER BYAbfrage durch einen Standardindex auf dem Sortierfeld zu unterstützen, sobald NLS_SORT auf einem von BINARY unterschiedlichen Wert steht. Das Problem kann dadurch umgangen werden, dass ein funktionsbasierter Index mit der SQL-Funktion nlssort aufgebaut wird, z.B.: CREATE INDEX kunden_name_xgerman_din ON kunden (nlssort(name, 'NLS_SORT = Xgerman_DIN')) ...
Dieser Index kann zur indexunterstützten Sortierung wiederum verwendet werden.
Zeichensätze
355
8.3.4 Weitere NLS-Parameter Der Parameter NLS_NUMERIC_CHARACTERS bestimmt, welche Zeichen als Dezimal- und Tausendertrennzeichen bei der Formatierung von NUMBER-Werten benutzt werden. Hiermit wird hauptsächlich der Umstand abgefangen, dass im Englischen der Punkt als Dezimal- und das Komma als Tausendertrennzeichen verwendet wird; im Deutschen ist es genau umgekehrt. Die Voreinstellung ist abhängig von der Wahl des Gebiets. Dieser Parameter kann bei einigen Anwendungen, die auf die OracleDatenbank zugreifen, Ursache für Fehler sein. Da der Parameter über die Standardsprache (NLS_LANGUAGE) entsprechend gesetzt wird, kann es daher vorkommen, dass Fehlermeldungen, wie z.B. »ungültige Zahl (ORA-01722)«, von der Anwendung geliefert werden. In der Regel ist dies auf eine fehlerhafte Kodierung zurückzuführen, bei der Punkt und Komma explizit gesetzt wurden. Für Währungen können die Parameter NLS_CURRENCY und NLS_ISO_CURRENCY verwendet werden, wobei NLS_CURRENCY das Währungssymbol (etwa € oder $) enthält, NLS_ISO_CURRENCY die Bezeichnung des ISO-Währungssymbols (also AMERICAN oder GERMAN). Bei der Verwendung des Formatelements L wird dann das Währungssymbol, bei C die ISO-Abkürzung der Währung (USD, EUR usw.) ausgegeben. Aus der Zeit der Euroumstellung ist ein weiterer Parameter, NLS_DUAL_CURRENCY, vorhanden, mit dem ein zweites Währungssymbol definiert werden kann. Dieser ist aktuell nicht mehr dokumentiert, aber nach wie vor vorhanden. Weitere NLS-Parameter werden im nächsten Abschnitt erläutert.
8.4
Zeichensätze
Die Auswahl der Zeichensätze für eine Datenbank ist keine triviale Aufgabe. Im Gegensatz zum englischsprachigen Raum ist es jedoch unerlässlich, einen passenden Zeichensatz auszuwählen – da der Standardwert für den Datenbankzeichensatz US7ASCII ist und somit z.B. keine Umlaute enthält. Es wird im Übrigen dringend von dem Trick abgeraten, die Datenbank mit US7ASCII zu betreiben und alle Clients ebenfalls mit der Einstellung US7ASCII zu fahren. Damit führt die TTC-Schicht von Oracle Net keinerlei Konvertierung durch – und es ist somit möglich, z.B. mit MS-Windows-Clients zu arbeiten und alle üblichen Umlaute und Sonderzeichen in die Datenbank hinein und sogar wieder heraus zu bekommen. Allerdings fehlt der Datenbank damit auch jegliches Wissen über diese Umlaute, und das bedeutet, dass weder richtige Sortierreihenfolgen noch spätere Integration von anderen Clients oder Umstellungen auf andere Zeichensätze möglich sind. Die Auswahl der Zeichensätze sollte im Falle einer Umgebung mit mehreren Datenbanken besonders gut überlegt sein. Die Möglichkeit, Daten zwischen verschiedenen Datenbanken mit Hilfe von transportablen Tablespaces auszutauschen, wird seit mehreren Versionen unterstützt und funktioniert für Oracle 10g-Datenbanken sogar bei Datenbanken mit verschiedenen Betriebssystemplattformen (siehe hierzu Abschnitt 15.1.1). Allerdings müssen sowohl die Zeichensätze als auch die nationalen Zeichensätze von Quell- und Zieldatenbank übereinstimmen – bzw. der Zei-
356
Globalization Support
chensatz der Zieldatenbank muss eine strikte Obermenge des jeweiligen Zeichensatzes der Quelldatenbank sein. Die letzte Einschränkung deckt jedoch fast ausschließlich Fälle ab, in denen die Quelldatenbank mit US7ASCII betrieben wird, das eine strikte Teilmenge von fast allen Single-Byte-Zeichensätzen ist. Ein Zeichensatz X wird als strikte Obermenge eines anderen Zeichensatzes Y bezeichnet, wenn alle Zeichen aus Y in X enthalten sind und für alle Zeichen aus Y gilt, dass ihre Binärdarstellung (hierfür wird auch der Begriff Code Point verwendet) in X und Y identisch ist. Y wird dann auch als strikte Teilmenge bezeichnet. Eine gute Übersicht über alle hier besprochenen Zeichensätze findet sich im Internet unter der URL http://en.wikipedia.org/wiki/Character_encoding. Für die weiter unten besprochenen UNICODE-Zeichensätze empfiehlt sich ebenfalls die URL http://www.unicode.org.
8.4.1 Single-Byte-Zeichensätze Übliche Single-Byte-Zeichensätze für deutsche Installationen sind WE8ISO8859P1 (insbesondere dann, wenn die Datenbank bereits länger existiert), WE8ISO8859P15 (wie der vorige, enthält jedoch zusätzlich das €-Symbol) oder WE8MSWIN1252. Bei einer neu einzurichtenden Datenbank mit Single-Byte-Zeichensatz würde man grundsätzlich WE8MSWIN1252 den Vorzug geben, falls größtenteils mit MS-WindowsClients gearbeitet wird. Neben den meisten Unix-Umgebungen nutzen viele Javaund Webanwendungen ISO-Zeichensätze; hierbei wird heute meist WE8ISO8859P15 der Vorzug gegeben, weil es einerseits der neuere Zeichensatz ist und andererseits das €-Symbol enthält. Die ältere Variante, WE8ISO8859P1, wird oft genutzt, wenn ältere Datenbanken migriert werden und man daher auch weiß, dass das €-Symbol nicht benutzt wird. Nach der Einrichtung der Datenbankzeichensätze ist die richtige Einstellung des Clientzeichensatzes letztendlich bei jedem Programmaufruf zu überprüfen. Hierzu folgende Beispiele: Ein deutsches MS-Windows verwendet auf der grafischen Oberfläche den oben genannten Zeichensatz WE8MSWIN1252. Innerhalb einer DOS-Box verwendet es WE8PC850 (DOS Codepage 850). Daher arbeitet die grafische Version von SQL*Plus (sqlplusw.exe) mit dem ersten, die Kommandozeilenversion (sqlplus.exe) mit dem zweiten Zeichensatz. Lädt man Daten mit dem SQL*Loader in die Datenbank, so sollte man den Zeichensatz mit NLS_LANG auswählen, der die zu ladenden Daten beschreibt. Je nachdem, wo die Daten herkommen, hat dieser Zeichensatz nichts mit dem Zeichensatz des Clients zu tun. Beim Export/Import von Daten werden Meldungen über Zeichensätze angezeigt, z.B. wie folgende: Export done in WE8ISO8859P1 character set and UTF8 NCHAR character set server uses WE8ISO8859P15 character set (possible charset conversion)
Zeichensätze
357
Gerade die Anmerkung »possible charset conversion« könnte zu dem Schluss verleiten, dass die Daten vom Datenbankzeichensatz WE8ISO8859P15 in den eingestellten Clientzeichensatz WE8ISO8859P1 konvertiert werden – allerdings bezieht sich dies lediglich auf Data Dictionary-Informationen wie Tabellennamen usw. In früheren Export-Versionen wurde tatsächlich konvertiert, was oft zu Verlust von Umlauten, Sonderzeichen usw. führte. Seit Oracle9i konvertiert ein Export jedoch (glücklicherweise) nicht mehr, sondern belässt alle Zeichenketten im Zeichensatz der Datenbank.
8.4.2 Multi-Byte-Zeichensätze, insbesondere UNICODE Multi-Byte-Zeichensätze werden in dem Moment erforderlich, wo es nicht mehr ausreicht, alle Zeichen zu erfassen, die in einem Land, einer Region oder einem Teilkontinent verwendet werden. Diese Art der Abbildung von Regionen oder sprachlich verwandten Ländern wird beispielsweise durch das Konzept der ISO-Zeichensätze abgebildet. Es existieren u.a. spezielle Multi-Byte-Zeichensätze für Sprachen, die eine große Anzahl von Schriftzeichen benötigen, wie Chinesisch oder Japanisch. Diese spielen in Europa jedoch keine große Rolle, da diese Zeichensätze unsere ASCII-Zeichen i.A. nicht enthalten und erst recht keine Umlaute. Interessanter sind da die UNICODE-Zeichensätze, bei denen versucht wird, alle benötigten Schriftzeichen für internationale Anwendungen, also auch für alle Sprachen, in einem Zeichensatz zusammenzufassen. Hierbei gibt es unterschiedliche Kodierungsschemata (Encodings) und Versionen, da nach und nach immer mehr Sprachen und Zeichen integriert werden. An dieser Stelle sollte sofort klar sein, dass Single-Byte-Zeichensätze hierfür nicht geeignet sind und selbst 16-BitZeichensätze nicht ausreichen. Das meist genutzte Kodierungsschema wird mit UTF-8 bezeichnet und ist variabel lang: Zeichen werden mit einer Länge von einem bis vier Bytes kodiert. Dabei entsprechen die 1-Byte-Zeichen den ASCII-Zeichen. Umlaute werden z.B. bereits mit 2 Bytes dargestellt. Bei Oracle 10g sind neben UTF-8 auch die Kodierungen UCS-2 und UTF-16 wichtig. UCS-2 ist eine 2-Byte-Kodierung. UTF-16 ist eine strikte Obermenge von UCS-2 neueren Datums (UNICODE Version 3.2) und lässt zusätzlich 4-Byte-Darstellungen, insbesondere für Sonderzeichen, die bei UCS-2 nicht enthalten sind, zu. UTF-16 wird z.B. von MS-Windows 2000 und Java genutzt. Als Datenbankzeichensatz unterstützt Oracle 10g zwei UTF-8-Kodierungen: UTF8 und AL32UTF8. Der Unterschied zwischen den beiden Zeichensätzen ist, dass mit UTF8 die UTF-8-Kodierung der UNICODE-Version 3.0 unterstützt wird: die im Übrigen identisch zu Oracle8i und Oracle9i ist. AL32UTF8 unterstützt die jeweils neueste UNICODE-Version, was für Oracle 10g Version 3.2 bedeutet, für Oracle9i Version 3.1 und für Oracle8i Version 3.0. Für hostbasierte Umgebungen wird mit UTFE zusätzlich eine UTF-EBCDIC-Kodierung unterstützt.
358
Globalization Support
Die Unterstützung für nationale Zeichensätze unterscheidet sich von der für Datenbankzeichensätze: Hier werden ausschließlich die Zeichensätze UTF8 (wie oben) und AL16UTF16 akzeptiert. Letzterer entspricht der UTF-16-Kodierung der UNICODE-Version 3.2. Besonderheiten weisen die Oracle-Datentypen CLOB und NCLOB auf: Sobald der Datenbankzeichensatz ein Multi-Byte-Zeichensatz ist, werden CLOBWerte in UCS-2 kodiert, unabhängig davon, welcher Zeichensatz für die Datenbank gewählt wurde. NCLOB-Werte werden grundsätzlich (unabhängig vom Datenbankzeichensatz und vom nationalen Datenbankzeichensatz) in UTF-16 kodiert. Generell bedeutet die Verwendung von UNICODE als Datenbankzeichensatz, dass die Darstellung von Zeichenketten tendenziell verlängert wird. Die tatsächliche Verlängerung variiert zumindest bei der Verwendung der UTF-8-Kodierung: Je mehr Umlaute und Sonderzeichen verwendet werden, desto länger wird die Darstellung. Bei UCS-2- und UTF-16-Kodierungen verdoppelt sich der benötigte Speicherplatz gegenüber der Single-Byte-Darstellung. Längensemantik Bei der Arbeit mit Multi-Byte-Zeichensätzen stellt sich eine Frage, die bei SingleByte-Zeichensätzen nicht auftaucht: Was ist mit VARCHAR2(n) gemeint? Die Standardantwort überrascht ein bisschen: Es ist gemeint, dass die Darstellung einer Zeichenkette die Länge von n Bytes nicht überschreiten darf, und nicht etwa, dass n Zeichen als Länge der Zeichenkette nicht überschritten werden dürfen. Beim Übergang von einem Single-Byte-Zeichensatz auf UNICODE sind daher Probleme vorprogrammiert: Lässt man die Tabellendefinitionen so, wie sie sind, passen eventuell in ein Feld nicht mehr alle Zeichen hinein, die vorher enthalten waren. Zur Lösung des Problems kann die Längensemantik von BYTE (was der obigen Beschreibung entspricht) auf CHAR umgeschaltet werden. Dies geschieht entweder durch die Angabe der gewünschten Semantik in der Typdefinition (z.B. VARCHAR2(30 CHAR)) oder durch Änderung des NLS-Parameter NLS_LENGTH_SEMANTICS (auf Sitzungs- oder Instanzebene) auf einen der Werte BYTE oder CHAR. Für die meisten Anwendungen macht die CHAR-Längensemantik mehr Sinn als BYTE. Daher ist es empfehlenswert, den Parameter NLS_LENGTH_SEMANTICS mit dem Wert CHAR als Standardparameter aufzunehmen – und dies nicht nur für Datenbanken mit Multi-Byte-Zeichensätzen, sondern auch bei Single-Byte-Zeichensätzen. Bei Feldern, die auf dem nationalen Zeichensatz basieren (NCHAR usw.), gilt unabhängig von der Einstellung des Parameters NLS_LENGTH_SEMANTICS immer die CHARSemantik. Weiterhin gilt die Einschränkung, dass die Maximallängen für Zeichenketten in Bytes festgelegt sind (2000 Bytes für CHAR/NCHAR, 4000 Bytes für VARCHAR2/NVARCHAR2) und auch bei CHAR-Semantik nicht überschritten werden können. Dies bedeutet,
Zeichensätze
359
dass bei der Definition von z.B. VARCHAR2(4000 CHAR) je nach verwendetem Zeichensatz und den enthaltenen Zeichen die maximal mögliche Zeichenzahl kleiner als 4000 ist. Programmierung Die Behandlung von speziellen Zeichen erfordert oft die Benutzung von speziellen Funktionen. Ein Beispiel wurde mit der Funktion NLSSORT, mit der landesspezifische Sortierreihenfolgen abgebildet werden können, weiter oben bereits angegeben. Die SQL-Funktionen LOWER, UPPER und INITCAP sind jeweils in einer weiteren Version NLS_LOWER, NLS_UPPER und NLS_INITCAP vorhanden. In den NLS-Versionen werden landesspezifische Konventionen berücksichtigt, wie folgendes Beispiel zeigt: SQL> SELECT nls_upper('Fußball', 'NLS_SORT=German') 2 FROM dual; NLS_UPP ------FUßBALL SQL> SELECT nls_upper('Fußball', 'NLS_SORT=XGerman') 2 FROM dual; NLS_UPPE -------FUSSBALL
Die Originalversionen der Funktionen kennen solche Feinheiten nicht und manipulieren Zeichenketten immer nur Zeichen für Zeichen, wobei die Ergebniszeichenkette immer genauso lang ist wie der Ausgangswert. Mit der Funktion CONVERT(<str>, [, ]) können Zeichenketten in einen anderen Zeichensatz konvertiert werden. Der Quellzeichensatz ist normalerweise der Datenbankzeichensatz; allerdings können mit dieser Funktion unter Angabe des Quellzeichensatzes auch »falsche Daten« korrigiert werden. Diese können entstehen, wenn Clients mit falscher NLS_LANG-Einstellung Daten in die Datenbank schreiben.
8.4.3 Migration von Zeichensätzen Oft stellt sich bei einer Datenbankmigration (z.B. auf eine neue Version) die Frage, ob der Zeichensatz geändert werden soll. Aber auch ohne eine solche Migration stellt sich manchmal die Frage nach einem anderen Datenbankzeichensatz, z.B. wenn die Anforderung zur Darstellung von speziellen Zeichen auftaucht. Man muss unterscheiden, ob diese Migration mit der bestehenden Datenbank (In–PlaceMigration) oder durch einen Neuaufbau der Datenbank inklusive Ent- und Beladen der Daten, z.B. mittels Export und Import erfolgen muss. Bei der In-Place-Migration bleibt der Datenbankzeichensatz zunächst erhalten. Mit Hilfe des CSALTERSkripts kann dann für eine bestehende Datenbank, gewisse Vorbedingungen vorausgesetzt, der Datenbankzeichensatz geändert werden.
360
Globalization Support
Neuaufbau der Datenbank Beim Neuaufbau der Datenbank ist man in der Wahl des Zeichensatzes nicht sehr eingeschränkt; man sollte sicherstellen, dass der neue Zeichensatz eine Obermenge des alten ist oder dass der neue Zeichensatz zumindest alle verwendeten Zeichen des alten Zeichensatzes enthält. Beim Import werden alle Zeichen in den neuen Zeichensatz konvertiert. Zu beachten ist, dass beim Import die Feldwerte für die Längensemantik von der Quelldatenbank übernommen werden. Beim Import zieht die Einstellung von NLS_LENGTH_SEMANTICS also nicht. Möchte man die Längensemantik umstellen, so müssen zunächst die Tabellen über Skripte mit der gewünschten Einstellung von NLS_LENGTH_SEMANTICS angelegt werden. Danach kann der Import in die bestehenden Tabellen erfolgen. Verwendung des CSALTER-Skripts Zunächst eine Warnung: Mit der Umstellung des Zeichensatzes bzw. des nationalen Zeichensatzes einer Datenbank wird ein zentraler Parameter der Datenbank umgestellt, der extrem viel Einfluss auf die Funktionsweise und das Verhalten des Gesamtsystems hat. Diese Umstellung ist nicht trivial und erfordert ein Höchstmaß an Sicherheitsvorkehrungen. Für produktive Systeme gelten mindestens die folgenden Voraussetzungen: Die Umstellung muss zunächst an einer Kopie des produktiven Systems getestet werden. Der Test bezieht sich nicht nur auf die reine Konvertierung des Zeichensatzes, sondern auch auf die Funktionsfähigkeit sämtlicher Programme, die auf die Datenbank zugreifen. Vor der Umstellung des produktiven Systems muss in jedem Fall eine vollständige Sicherung durchgeführt werden. Empfehlenswert ist ebenfalls eine weitere Sicherung nach der erfolgten Umstellung. Das CSALTER-Skript verpackt den Befehl ALTER DATABASE [NATIONAL] CHARACTER SET INTERNAL_USE
in eine Umgebung, die versucht, mögliche Fehler bei der Konvertierung von Zeichensätzen auszuschließen. Während in früheren Version der oben angegebene Befehl direkt eingegeben werden konnte, gilt für Oracle 10g, dass ausschließlich der offizielle Weg über das CSALTER-Skript unterstützt wird. Das CSALTER-Skript erlaubt die Konvertierung des Datenbankzeichensatzes dann und nur dann, wenn für alle vorhandenen Zeichen in Benutzertabellen gilt, dass sie im neuen Zeichensatz die gleiche Binärdarstellung haben wie im alten Zeichensatz. Das bedeutet, dass zumindest für die Teilmenge der benutzten Zeichen gilt, dass der neue Zeichensatz eine strikte Obermenge des alten Zeichensatzes ist. Hierzu einige Beispiele: Die Konvertierung von US7ASCII in einen ISO-, Windows- oder UNICODE-Zeichensatz sollte praktisch immer funktionieren.
Zeichensätze
361
Die Konvertierung eines ISO-Zeichensatzes in UNICODE funktioniert nur dann, wenn alle verwendeten Zeichen im Bereich des US7ASCII-Zeichensatzes liegen. Mit anderen Worten: wenn keine Umlaute vorhanden sind. Falls von einem Single-Byte- in einen Multi-Byte-Zeichensatz konvertiert wird, dürfen keine CLOB-Spalten in Benutzertabellen vorhanden sein. Daraus folgt, dass das CSALTER-Skript keinerlei Konvertierungen auf Benutzerdaten vornimmt. Allerdings werden Zeichen im Data Dictionary passend konvertiert. Daher muss vorher mit dem Characterset Scanner Utility CSSCAN untersucht werden, ob diese Konvertierung verlustfrei durchgeführt werden kann. Voraussetzung für die Durchführung des CSALTER-Skripts ist ein vollständiger Durchlauf von CSSCAN, der nicht länger als sieben Tage zurückliegt. Das Characterset Scanner Utility benötigt seinerseits einige Datenbankobjekte, die mit dem Skript $ORACLE_HOME/rdbms/admin/csminst.sql angelegt werden. Das Skript legt u.a. den Benutzer CSMIG an, für den ein Passwort eingegeben werden muss. Der Aufruf des CSSCAN-Utilities sieht wie folgt aus: csscan system/ tochar=al32utf8 array=1000000 process=1 full=y
Mit dem Parameter TOCHAR wird der Zielzeichensatz angegeben. Alternativ kann mit TONCHAR auch ein geänderter nationaler Zeichensatz bestimmt werden. Mit ARRAY wird die Puffergröße für das Lesen von Daten eingestellt, mit PROCESS die Anzahl der Scanprozesse. Mit FULL wird bestimmt, dass die gesamte Datenbank gescannt werden soll. Es gibt einige weitere Parameter, mit denen das Verhalten von CSSCAN beeinflusst werden kann; einen Überblick bekommt man mit: csscan help=y
Das CSSCAN-Utility erzeugt mindestens eine Datei scan.txt, in der die Ergebnisse des Scans enthalten sind. Dort findet man u.a. Hinweise, ob eine Konvertierung ohne Risiko durchgeführt werden kann oder nicht. Falls die Konvertierung nicht durchgeführt werden kann, sollten die Gründe hierfür analysiert werden. Wenn ein Großteil der Datenbank Daten enthält, die einer Konvertierung im Wege stehen, so bietet sich eine Export-/Import-Umstellung in eine neue Datenbank an. Falls nur wenige Datenbankobjekte betroffen sind, können diese exportiert, gelöscht und nach der Konvertierung wieder importiert werden. Das CSALTER-Skript wird wie folgt aufgerufen: sqlplus / as sysdba @?/rdbms/admin/csalter.plb
Es benötigt eine SYSDBA-Anmeldung, da es zunächst die Instanz in den RESTRICTED SESSION-Modus setzt und dann, nach einer Reihe von weiteren Prüfungen, den zu Beginn dieses Abschnitts dargestellten ALTER DATABASE-Befehl zur tatsächlichen Änderung des Zeichensatzes (bzw. nationalen Zeichensatzes) absetzt. Falls das Skript erfolgreich durchläuft, muss der RESTRICTED SESSION-Modus anschließend wieder aufgehoben werden. Wie weiter oben bereits erwähnt, ist das CSALTER-Skript keine risikolose Angelegenheit; deshalb ist eine Vollsicherung vorher unerlässlich. Insbesondere für den Fall, dass Objekte mit Export/Import behandelt werden, ist eine weitere Vollsicherung nach der Aktion ebenfalls notwendig.
Sicherheit 9.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 einzig und allein 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 Oracle9i und Oracle 10g 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 und Implementierung, 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üsselwörtern, 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: »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
364
Sicherheit
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 wesentlich 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: 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 die gesamte Tabelle kann eine Verletzung der Geheimhaltung bedeuten.) 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.) Das folgende Kapitel soll daher eine Anleitung zur Planung und Konfiguration einer sicheren Datenbankumgebung liefern. Dabei ist vor allem auch wichtig, dass Datenbanksicherheit auch das hardware- und softwaretechnische Umfeld betrachten muss. Das bedeutet konkret: Datenbanksicherheit ist nur dann möglich, wenn auch das umgebende Betriebssystem und die Netzwerkumgebung entsprechend abgesichert werden. Darüber hinaus gilt es, in dem Kräftedreieck aus Kosten, Sicherheitsanforderungen und Performance eine Lösung zu finden, die der entsprechenden Anwendungsumgebung und dem zur Verfügung stehenden Budget gerecht wird. Nicht jede Lösung erfordert die höchste Sicherheitsstufe, aber umgekehrt darf Sicherheit auch nicht dem – konfiguratorischen – Zufall überlassen werden. 1
Castano et al., Database Security, Seite IX.
Einführung
365
Die folgenden Meilensteine können das Projekt Datenbanksicherheit markieren: Identifizierung: Sensible Daten können nur dann geschützt werden, wenn zugreifende und ändernde Benutzer eindeutig identifiziert und aufgrund der Identifizierung sicher authentifiziert werden können. Dies wird durch eine gute Benutzerplanung erreicht. Privilegierung: Die eindeutige Identifizierung der Benutzer gibt den Weg für ihre Privilegierung frei, durch die nur solche Daten sichtbar und modifizierbar sind, die für den betreffenden Benutzer freigegeben sind (Least Privilege-Prinzip). Systemüberwachung: Sicherheitstechnik ist wertlos, wenn sie nicht überwacht wird. Es ist daher wichtig, sensible Bereiche auch mit Mitteln des Auditings zu kontrollieren und die entstehenden Zugriffsprotokolle auch auszuwerten! Verschlüsselung: Unzureichend geplante Sicherheitssysteme können leicht durch »Maskerade« (Masquerading oder Spoofing) geknackt werden, indem Externe die Identität registrierter Benutzer annehmen und dadurch – scheinbar legal – Informationen einsehen können. Um Maskerade zu verhindern oder zumindest zu erschweren, ist nicht nur eine starke Authentifizierung notwendig, sondern ebenso die durch Verschlüsselung geschützte Übertragung der Daten über die vorhandenen Kommunikationswege. In besonders sensiblen Fällen kann es auch notwendig werden, Daten innerhalb der Datenbank zu verschlüsseln, um sie der Interpretation von SELECT ANY Benutzern zu entziehen. Dem Verwalter stehen dabei aus Sicht der Datenbank folgende Instrumente zur Verfügung: Identifizierung und Authentifizierung: Die Authentifizierung von Benutzern kann über die Datenbank – mit oder ohne Passwort – erfolgen oder über externe Instanzen, wie z.B. LDAP-Directory Services, Kerberos und verwandte Verfahren. Datenbankbenutzer können dabei wahlweise individuell oder als »Gruppenbenutzer« konfiguriert werden. Für die Privilegierung der Benutzer stehen System- und Objektprivilegien zur Verfügung. Über Rollen lassen sich diese Privilegien bündeln und den Benutzern zuordnen. Für besondere Anforderungen kann die Aktivierung der Rollen an Passwörter gebunden oder über definierte und gesicherte Packages ausgeführt werden, um zu verhindern, dass Benutzer eigenmächtig Privilegien in nicht freigegebenen Kontexten nutzen. Rollen lassen sich auch zentralisiert – als Enterprise Roles – im Rahmen von Oracle Internet Directory definieren und steuern dann die Aktivierung der Datenbankrollen in konkreten Zielsystemen. Dort wo die objektbezogene Privilegierung nicht ausreicht, lässt sich eine zeilen- und spaltenspezifische Freigabe von Daten konfigurieren. Hierzu stehen die Techniken Virtual Private Database und Label Security zur Verfügung. Besonders sensible Daten können in der Datenbank mit Hilfe des Pakets DBMS_CRYPTO2 verschlüsselt werden. Die Übertragung der Daten von und an die jeweiligen Clients kann über Parameter im Kontext von Oracle NET konfiguriert werden. 2
Der Vorgänger dieses Pakets (Version 9) war DBMS_OBFUSCATION_TOOLKIT.
366
Sicherheit
Vielfältige Auditing-Funktionen ermöglichen eine maßgeschneiderte Überwachung der Zugriffe. Die oben zusammenfassend erwähnten Maßnahmen sind für jedes Projekt und jede Anwendung individuell zu planen und zu konfigurieren. Darüber hinaus gibt es jedoch eine Reihe von allgemeinen konfiguratorischen Aktionen, die der Verwalter unabhängig von einzelnen Anwendungen im Kontext der Datenbank durchführen sollte, um die Grundlage für eine sichere Umgebung zu schaffen. Diese grundlegenden Maßnahmen werden im folgenden Abschnitt dargestellt. Es versteht sich, dass diese Maßnahmen im Umfeld der Netzwerke und Betriebssysteme zu ergänzen sind.
9.2
Grundlegende Maßnahmen
Wie bereits erwähnt gibt es einige Maßnahmen, die der Verwalter unabhängig von den die Datenbank nutzenden Anwendungen aus Gründen der Sicherheit durchführen sollte.
9.2.1
Maßgeschneiderte Installation
Bei der Installation der Software sollten nur die Komponenten aufgespielt werden, die im Rahmen des betreffenden Home-Verzeichnisses auch tatsächlich benötigt werden. Hier bietet die CUSTOM- Auswahl des Universal Installers die entsprechenden Möglichkeiten. Das Gleiche gilt auch für die Installation und Konfiguration der einzelnen Datenbanken. Viele Optionen, wie z.B. Intermedia oder Spatial, legen in eigenen Schemata Objekte in der Datenbank ab. Die jeweiligen Schemabenutzer werden mit Standardpasswörtern angelegt, sind in der Regel hoch privilegiert und stellen – wenn sie nicht genutzt und dementsprechend konfiguriert werden – ein beträchtliches Risiko für die Sicherheit der Datenbank dar.
9.2.2
Standardpasswörter
Standardpasswörter sind auf jeden Fall zu vermeiden. Dies gilt nicht nur für die hochrangigen Benutzer SYS und SYSTEM und die im vorangehenden Abschnitt erwähnten Optionsbenutzer, sondern auch für die – möglicherweise – zahlreichen Benutzer, die durch Skripte und Tools nach der eigentlichen Installation angelegt werden und die in vielen Fällen mit sehr üppigen Privilegien ausgestattet sind. Pete Finnigan hat sich zusammen mit einige Kollegen die Mühe gemacht, diese Benutzer und ihre Standardkennwörter auf seiner Website3 zu veröffentlichen. Seine Liste weist zum Zeitpunkt der Drucklegung dieses Buches knapp 600 Einträge auf! Der Datenbank-Konfigurationsassistent bietet neuerdings die Möglichkeit, unterschiedlichen Systembenutzern – die Auswahl ist abhängig von den gewählten Installationsoptionen – eigene Kennwörter zuzuteilen. Hier sollten unbedingt unterschiedliche Kennwörter verwendet und auf die Zuteilung desselben Kennwortes verzichtet werden. 3
Die URL lautet: http://www.petefinnigan.com/default/default_password_list.htm
Grundlegende Maßnahmen
367
Abbildung 9.1: Anpassung von Standardpasswörtern
Darüber hinaus werden zum Ende der Installation einige der Accounts für Optionen, wie z.B. LBACSYS für die Label Security, gesperrt. Dies ist sicherlich sehr sinnvoll. Trotz allem bleiben hohe Risiken, weil einige Benutzer erst nachträglich über Installationsskripte von externen Werkzeugen, wie z.B. SQL Navigator, angelegt werden oder aber Optionsbenutzer nach der Installation wieder aktiviert und durch ihr kompromittierendes Kennwort zum Risiko werden können. Neben Benutzern legen Werkzeuge auch Rollen an, die kritische Privilegien enthalten können. Es ist daher dringend zu empfehlen, produktive Systeme nach diesen Standardbenutzern und neue Rollen zu durchforsten. Im Einzelnen ist folgendes Vorgehen ratsam: Feststellen, welche Standardbenutzer installiert wurden. Wenn diese Benutzer noch mit dem Standardkennwort versehen sind, sollte dieses sofort über den Befehl alter user (s.u.) geändert werden. Für alle Accounts, deren Objekte zwar benötigt werden, die jedoch kein direktes Connect erfordern, ist das Privileg create session über den Befehl revoke zu entziehen. Hierbei ist zu beachten, dass dieses Privileg durchaus redundant vergeben worden sein kann, etwa über eine oder mehrere Rollen oder auch als direktes Systemprivileg. Abschnitt Privilegien und Rollen dieses Kapitels beschreibt die hierfür wichtigen Informationsquellen. Zusätzlich oder alternativ kann das Schema über den Befehl alter user auch gesperrt werden. Accounts, deren Objekte überhaupt nicht benötigt werden, sollten vollständig gelöscht werden: drop user <username> cascade;
368
Sicherheit
Über die bereits erwähnte Webseite von Pete Finnigan lässt sich auch ein kleines Werkzeug laden, mit dem Datenbanken auf Standardbenutzer und ihre unveränderten Passwörter hin untersucht werden können. Dieses Werkzeug besteht aus einer Hilfstabelle mit den betreffenden Daten der Standardbenutzer und einer kleinen PL/SQL-Prozedur, welche die »gehashten« Kennwortdaten4 der View dba_users mit den Standarddaten der Hilfstabelle vergleicht. Das Ergebnis ist ein kleiner Report, der auf die gefundenen Schwachstellen hinweist. Die Prozedur untersucht jedoch nicht, ob hoch privilegierte Rollen von Werkzeugen bereits dritten Benutzern zugeteilt wurden.
Abbildung 9.2: Beispielausgabe des Password-Checkers
9.2.3
Vordefinierte Rollen und Grants
Nach der Installation der Datenbank steht bekanntlich eine ganze Reihe von vordefinierten Rollen, allen voran die Rollen CONNECT, RESOURCE und DBA, zur Verfügung. Vor allem die Privilegien der Rollen CONNECT und RESOURCE sollten vom DBA geprüft und ggf. angepasst werden, bevor sie leichtfertig an Endbenutzer vergeben werden. In vielen Fällen werden eigene Standardrollen – z.B. _connect – angelegt, die den Benutzern grundlegende Systemprivilegien in einer Form zuteilen, die konform zu den jeweiligen Sicherheitsrichtlinien ist. Alle Einzelheiten zur Arbeit mit Rollen finden sich in Abschnitt Privilegien und Rollen. 4
Passwörter für Benutzer oder Rollen werden in den Metadaten des Data Dictionarys nicht verschlüsselt, sondern »gehasht« als hexadezimale Zeichenkette der Länge 16 gespeichert. Gehashte Zeichenketten lassen sich – im Gegensatz zu verschlüsselten Daten – nicht in den Originalwert zurückführen. Wohl aber ergibt jede Zeichenkette immer wieder einen identischen Hashwert. Auf diese Weise funktioniert der Mechanismus der Authentifizierung.
Grundlegende Maßnahmen
369
Gleichfalls sollten Grants, die im Kontext von Tabellen, Views oder Prozeduren an PUBLIC vergeben wurden, bekannt sein und überprüft werden. Die durch die Installation vergebenen Grants für die Pakete utl_smtp, utl_tcp, utl_http und utl_file sollten auf jeden Fall zurückgenommen werden. Grundsätzlich gilt auch hier, dass Privilegien nur für die Benutzer erteilt werden, die mit den Rechten legitim arbeiten müssen. Ein häufiges Problem stellen in diesem Zusammenhang Anwendungen dar, die herstellerunabhängig entwickelt wurden und aus diesem Grunde nicht sehr differenziert mit Privilegien umgehen – mit anderen Worten, Zugriffsfehler dadurch eliminieren, dass sie höchstprivilegierte Rechte voraussetzen. Hier kann es notwendig werden, derartige Anwendungen in separaten Instanzen zu isolieren, wo sie den geringsten möglichen Schaden anrichten können.
9.2.4
Patches
Software ist niemals vollständig und für alle Zeiten sicher. Dies gilt auch für OracleDatenbanken. Aus diesem Grunde sollten relevante Sicherheits-Patches so zügig wie möglich5 eingespielt werden. Seit dem Jahr 2005 veröffentlicht Oracle im Internet6 vierteljährlich so genannte Critical Patch Updates, die relevante Sicherheitsprobleme beschreiben und entsprechende Patches bereitstellen. Die Veröffentlichung findet jeweils am ersten Dienstag nach dem 15. der Monate Januar, April, Juli und Oktober statt. Die veröffentlichte Liste enthält auch Verweise auf Metalink-Dokumente, welche die Einzelheiten der betreffenden Patches beschreiben. In den vorangehenden Jahren wurden stattdessen in unregelmäßiger Folge Security Alerts bereitgestellt, die relevante Sicherheitsprobleme und ihren Kontext beschrieben haben und auf entsprechende Patches verwiesen. Die oben erwähnte URL gibt eine vollständige Übersicht über alle verfügbaren Patch-Updates und Alerts. Darüber hinaus enthält das Metalink-Dokument 237007.1 mit dem Titel FAQ for Security Alerts und Critical Patch Updates eine gute Einführung in das Thema sowie die Liste aller Alerts und Patches seit November 2001. Der Support-Status für Oracle 10g Release 1 sowie verfügbare Alerts werden auch in dem Dokument mit der ID 263719.1 beschrieben. Entsprechende Dokumente sind auch für ältere Versionen über Metalink verfügbar7.
5
6 7
Der Zeitpunkt ist einerseits abhängig von der individuellen betriebsinternen Situation, andererseits auch von technischen Kontroversen – siehe hierzu die kritische Diskussion von Patches am Beispiel des Juli 2005 Patches unter http://red-database-security.com. Die URL lautete zur Drucklegung: http://otn.oracle.com/deploy/security/alerts.htm Für die Version 9i Release 2 das Dokument 189908.1, für Version 9i das Dokument 149018.1 und für Version 8.1.7 das Dokument 120607.1
370
9.3
Sicherheit
Sichern der Datenübertragung
Vorbei sind die Zeiten, da Benutzer direkt auf den Server-Maschinen ihre Datenbankverbindungen aufgenommen haben. In der Regel werden Sessions from remote, sei es aus Client-Applikationen heraus oder über einen Application-Server, initiiert. In diesen Fällen werden die Daten über mehr oder weniger sichere Netzwerke transportiert. Wenn auch der eigentliche Authentifizierungsprozess, d.h., die Übermittlung des Benutzerkennwortes in verschlüsselter Form und damit hinreichend sicher erfolgt, ist es trotzdem aus unterschiedlichen Gründen sinnvoll, zusätzlich in die Netzwerksicherheit zu investieren: Werkzeuge zum »Schnüffeln« in Netzwerken (Network Sniffer) können leicht aus dem Internet besorgt und problemlos installiert werden. Der komplette Datenverkehr außerhalb der Authentifizierung läuft unverschlüsselt ab. Damit können alle SQL-Befehle und die zurückfließenden Antworten im Klartext abgefangen und ausgewertet werden. Bei dem Datenverkehr können auch Kennwörter unverschlüsselt gesendet werden, wenn beispielsweise Rollen, die über Passwörter geschützt sind, mit dem Befehl set role aktiviert werden. Neben der Verschlüsselung des Datenstromes, der sicherstellt, dass Pakete von Unbefugten nicht gelesen werden können, sollten auch Modifikationen dieser Daten während der Übertragung vereitelt werden. Letzteres lässt sich durch den Einsatz von kryptografischen Hash-Funktionen erreichen, die Prüfsummen der übermittelten Datenpakete vergleichen und im Falle einer Modifikation entsprechende Meldungen ausgeben. Schließlich ist es wichtig, die für die Datenbankverbindung notwendigen Prozesse – hier vor allem den Listener-Prozess – und die NET-Konfigurationsdateien vor unerwünschten Modifikationen zu schützen. Die folgenden Abschnitte beschreiben die hierfür notwendigen Schritte.
9.3.1
Konfiguration des Listener-Prozesses
Der Listener-Prozess wird bekanntlich benötigt, um eingehende Verbindungsanforderungen an Datenbanken entgegenzunehmen, zu verarbeiten und dafür zu sorgen, dass die Kommunikation des Clients mit der geforderten Datenbank hergestellt werden kann. Die benutzten Authentifizierungsmechanismen sorgen letzten Endes dafür, ob die gewünschte Verbindung erfolgreich aufgebaut werden kann. Bis zur Version 9i war es dringend zu empfehlen, das Herunterfahren und Neuladen des Listener-Prozesses mit Hilfe des Befehls lsnrctl über ein Passwort zu schützen. Dies war vor allem auch deshalb ratsam, weil Listener-Prozesse grundsätzlich auch from remote administriert werden können. Hierzu ist lediglich das lsnrctl-Programm und eine jeweils lokale listener.ora-Datei nötig, die einen Eintrag mit entsprechender host-Spezifikation für den betreffenden Listener auf der remoten Maschine enthält. Mit diesen Mitteln lassen sich dann alle lsnrctl-Befehle außer dem start-Befehl absetzen!
Sichern der Datenübertragung
371
Ab der Version 10g wird der Listener-Prozss mit Mitteln des jeweiligen Betriebssystems geschützt. Das bedeutet: Der Listener kann nur von dem Betriebssystembenutzer gestoppt oder neu konfiguriert werden, der ihn auch gestartet hat; und das auch nur auf dem Rechner, auf dem der betreffende Listener gestartet wurde. Diese Default-Einstellung kann über den Befehl lsnrctl stat leicht kontrolliert werden. Security
ON: Local OS Authentication
Wird in dieser Konfiguration versucht, den Listener zu stoppen, erscheint die folgende Fehlermeldung: LSNRCTL> stop Connecting to (DESCRIPTON=(ADDRESS=(PROTOCOL=TCP)(HOST=NandaDevi)(PORT=1529))) TNS-01190: The user is not authorized to execute the requested listener command
Die Konfiguration eines Passwortes empfiehlt sich aus diesem Grunde nur dort, wo ein anderer Benutzer legitim das Stoppen oder Neuladen des Listeners ausführen oder die Administration des Listeners auch from remote möglich sein soll. Die Konfiguration kann über das Werkzeug Oracle Net Manager – Aufruf über netmgr – oder, vielleicht einfacher, direkt mit Hilfe des Kommandozeilenprogramms lsnrctl (Listener Control) erfolgen. Für die erstmalige Passwortkonfiguration eines Listeners mit Namen Listener2 sind beispielsweise die folgenden Kommandos erforderlich: LSNRCTL> set current_listener listener2 Current Listener is listener2 LSNRCTL> change_password Old password: New password: Reenter new password: Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=NandaDevi)(PORT=1529))) Password changed for listener2 The command completed successfully LSNRCTL> save_config Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=NandaDevi)(PORT=1529))) Saved listener2 configuration parameters. Listener Parameter File /app/oracle/product/10gR1/network/admin/listener.ora Old Parameter File /app/oracle/product/10gR1/network/admin/listener.bak The command completed successfully
Nach dem Anlegen – und natürlich auch Ändern – des Passwortes über change_password muss die neue Einstellung mit save_config in die Konfigurationsdatei listener.ora übernommen werden. Diese speichert das Kennwort in »gehashter« Form. lsnrctl fügt darüber hinaus – anders als netmgr – entsprechende Kommentare hinzu: #----ADDED BY TNSLSNR 11-AUG-2005 21:58:30--PASSWORDS_LISTENER2 = (B86693A9CB9FB57D) #--------------------------------------------
372
Sicherheit
Zur Kontrolle der Einstellungen zeigt lsnrctl stat anschließend folgendes Bild: Security
ON: Password or Local OS Authentication
Es ist auf jeden Fall davon abzuraten, das Passwort direkt in die Datei listener.ora zu schreiben, weil es in diesem Fall unverschlüsselt erscheint und damit leicht kompromittierbar ist. Der Benutzer, unter dem der Listener gestartet wurde lässt sich – unter Unix – leicht über das Kommando ps –ef | grep <listener_name> ermitteln: oracle
8512
1
0 Aug11 ?
00:00:00 /app/oracle/product/10gR1/bin/tnslsnr listener2
In diesem Beispiel läuft der Prozess unter dem Oracle Installations-Account oracle. Folglich müssen Dritte, die den Listener listener2 stoppen oder neu konfigurieren, das eingestellte Passwort nutzen: LSNRCTL> set current_listener listener2 Current Listener is listener2 LSNRCTL> set password Password: The command completed successfully LSNRCTL> stop listener2 Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=NandaDevi)(PORT=1529))) The command completed successfully
Die Online-Modifikation sämtlicher Listener-Parameter kann neuerdings auch vollständig über den Parameter ADMIN_RESTRICTIONS_<listenername> = on unterbunden werden. Der Parameter bewirkt, dass keine set-Befehle von lsnrctl akzeptiert werden. Die Änderung der Parameter kann jedoch immer noch durch Modifikation der Parameterdatei listener.ora und anschließendes Neuladen – reload – des Listeners erfolgen. Der gewährte Schutz ist also nur von begrenzter Natur. Auch für den Listener gilt, dass die sicher eingestellte Konfiguration kontrolliert werden sollte. Hierzu reicht es aus, das Logging einzuschalten – und auch zu sichten –, um die abgesetzten Befehle und damit eventuelle Attacken leichter erkennen zu können. Die folgenden Befehle sind hierzu notwendig. Auf die Eingabe des Passwortes kann – wie oben dargelegt – im Standardfall verzichtet werden: LSNRCTL> set current_listener <listener name> LSNRCTL> set password Password: <enter listener password> LSNRCTL> set log_directory /network/log LSNRCTL> set log_file <sid name>.log LSNRCTL> set log_status on LSNRCTL> save_config
Das Log- wie auch das Konfigurationsverzeichnis sollten gut geschützt werden, d.h., Lese- und Schreibrechte sollten nur für den Oracle-Installationsbenutzer gewährt werden. Alle nicht benötigten Services, die explizit in der listener.ora-Datei konfiguriert oder über Kopieraktionen leichtfertig übernommen wurden, sollten gelöscht werden. Per Default findet sich dort häufig ein Eintrag (key = extproc) für externe Pro-
Sichern der Datenübertragung
373
zeduraufrufe, der nur gerechtfertigt ist, wenn – z.B. über die Intermedia-Option – tatsächlich mit externen Programmaufrufen gearbeitet wird. Zusätzlich können dem Listener IP-Adressen übergeben werden, denen er vertrauen oder nicht vertrauen darf. Diese Option ist vor allem dort von Interesse, wo die Anzahl der zulässigen IP-Adressen bekannt bzw. überschaubar ist und auch keine zu große Dynamik aufweist – idealerweise bei Betrieb eines Application-Servers, über den alle Verbindungsanforderungen an die Datenbank abgesetzt werden. Diese Option ist zwar nicht völlig »wasserfest«, da IP-Adressen bekanntlich gefälscht werden können (Spoofing), setzt den Schwierigkeitsgrad für potenzielle Eindringlinge jedoch ein ganzes Stück nach oben. Die Konfiguration erfolgt über die Profile-Datei sqlnet.ora und kann dort entweder per Editor oder mit Hilfe des Net-Manager-Werkzeugs8 vorgenommen werden. Die Parameter erlauben das Aktivieren oder Deaktivieren der Prüfung sowie die konkrete Einstellung der Adressen oder Hostnamen. Es werden keine Wildcards akzeptiert: TCP.VALIDNODE_CHECKING = YES TCP.INVITED_NODES= (192.168.33.120, MyServer)
Über den Parameter TCP.EXCLUDED_NODES lassen sich entsprechende Schwarzlisten konfigurieren. Des Weiteren kann überlegt werden, den Standard-Listenerport 1521 sowie die häufig genutzten Ports 1522 bis 1540, die gerne von Hackern für Portscans genutzt werden, zu meiden und stattdessen eine weniger bekannte »Port-Nische« zu nutzen. Diese Maßnahme erhöht den Aufwand für die genannten Portscans erheblich und verbessert auf diese Weise den Schutz. Für den Fall, dass externe Prozeduraufrufe nötig sind, sollten diese über einen separaten Listener-Prozess ausgeführt werden, der nicht unter dem Oracle-Benutzer läuft. Ein Sicherheitsrisiko kann in diesem Bereich deshalb entstehen, da die externen Programme die Privilegien des Oracle-Installations-Accounts und damit die Zugriffsrechte auf die Datenbankdateien erben könnten. Aus diesem Grunde sind die folgenden Maßnahmen ratsam: Konfiguration eines separaten Listeners mit eigenem Namen – beispielsweise listener_ext –, eigener Portnummer und eigenem Log-Verzeichnis. Start dieses Listeners über lsnrctl start <listenername> unter einem gering privilegierten Benutzer. Damit dies gelingt, muss der Betreffende Zugriff auf das Kommando lsnrctl, Leserechte auf der Konfigurationsdatei listener.ora sowie Schreibrechte in dem konfigurierten Log-Verzeichnis haben. Beginnend mit der Version 9.2.0 hat Oracle den Zugriff auf externe Programme standardmäßig auf das Verzeichnis $ORACLE_HOME/bin (unter Windows) oder $ORACLE_HOME/lib (unter Unix) beschränkt. Programme, die sich in anderen Verzeichnissen befinden, können zunächst nicht aufgerufen werden, es sein denn, der Listener wird explizit dafür konfiguriert. Die Konfiguration kann zusätzlich zu den bestehenden Standards oder explizit erfolgen und wird über den envsParameter der Datei listener.ora gesteuert. 8
Die Einstellung erfolgt über Profil -> Allgemein -> Zugriffsrechte.
374
Sicherheit
Im folgenden ersten Beispiel wird die Konfiguration in Erweiterung der Standardvorgaben vorgenommen, im zweiten Ausschnitt exklusiv. Es versteht sich, dass dieser Parameter genauestens kontrolliert werden muss. LISTENER_EXT= (DESCRIPTION= (ADDRESS_LIST= (ADDRESS=(PROTOCOL=tcp)(HOST=myserver)(PORT=1599)) (ADDRESS=(PROTOCOL=ipc)(KEY=extproc)) ) ) SID_LIST_LISTENER_EXT= (SID_LIST= (SID_DESC= (GLOBAL_DBNAME=global.db.name) (ORACLE_HOME=/u01/app/oracle) (SID_NAME=test10)) (SID_DESC= (SID_NAME=plsextproc) (ORACLE_HOME=/oracle) (PROGRAM=extproc) (ENVS="EXTPROC_DLLS=/u01/app/oracle/common/shell.so"))) Listing 9.1: Erweiterung des Standard-DLL-Pfades (ENVS="EXTPROC_DLLS=ONLY:/u01/app/oracle/common/shell.so") Listing 9.2: Ausschnitt aus listener.ora für exklusive DLL-Zuweisung.
9.3.2
Verschlüsselung und Integrität
Um die Daten während der Übertragung vor unerlaubtem Lesen und vor unberechtigten Veränderungen zu schützen, d.h., die Geheimhaltung (Data Privacy) und Integrität zu garantieren, ist es notwendig, Algorithmen für die Verschlüsselung sowie für die Generierung von Prüfsummen zu konfigurieren. Dies ist sowohl für Clients möglich, die über Oracle Net Services mit der Datenbank kommunizieren, als auch für solche, die über »dünne« JDBC-Treiber (thin JDBC) ihre Verbindungen aufbauen. Das Prozedere, das in beiden Umgebungen durchlaufen wird, ist im Wesentlichen identisch: Client und Server stimmen sich über die von ihnen unterstützten Algorithmen und ihre Bereitschaft zu verschlüsseln ab, generieren Zufallszahlen, tauschen über das Diffie-Hellmann-Verfahren ihre Session-Keys aus und nutzen das Oracle Login-Protokoll. Die Verschlüsselung und Integrität wird – im Kontext von Oracle Net Services – über die Profildatei sqlnet.ora gesteuert. Beide Verfahren können unabhängig voneinander konfiguriert werden, wenn sie auch in der Regel im Verbund eingesetzt werden, um einen umfassenden Schutz zu garantieren. Die Konfiguration kann direkt durch Editieren der Datei sqlnet.ora oder – komfortabler – mit Hilfe des Net Managers und dort über PROFIL – ORACLE ADVANCED SECURITY sowie die Tab-Reiter INTEGRITÄT und VERSCHLÜSSELUNG konfiguriert werden. Es werden die Einstellungen für Client und Server jeweils getrennt konfiguriert. Für beide Parteien lässt sich, neben den unterstützten Algorithmen, auch das Verhalten in Bezug auf Verschlüsselung und Integritätsprüfung getrennt angeben:
Sichern der Datenübertragung
375
zurückgewiesen (rejected) – weist die Anforderung zurück. Sollte die Gegenseite auf der Anforderung bestehen, kann die Verbindung nicht aufgebaut werden. akzeptiert (accepted) – erklärt die Bereitschaft für den Fall, dass die Gegenseite die Verschlüsselung anfordert (requested) oder obligatorisch voraussetzt (required). angefordert (requested) – verschlüsselt oder prüft die Integrität, es sei denn, die Gegenseite weist die Anforderung zurück (rejected). obligatorisch (required) – besteht auf der Verschlüsselung bzw. Integritätsprüfung. Wenn die Gegenseite hierzu nicht bereit ist, wird die Verbindung abgelehnt. Bei den Einstellungen ist darauf zu achten, dass die Verhaltensweisen eindeutig genug konfiguriert werden. Wählt man »akzeptiert« und die Gegenseite »akzeptiert« ebenfalls, kann eine Verbindung aufgebaut werden, jedoch ohne Verschlüsselung und Integritätsprüfung! Schließlich ist auch noch ein Verschlüsselungsschema (Crypto Seed) vorhanden, d.h. eine beliebige alphanumerische Zeichenfolge, die als Grundlage für die Generierung einer Zufallszahl genommen wird, über welche die Session-Keys erzeugt werden.
Abbildung 9.3: Oracle Net Manager: Konfiguration von Advanced Security
Die entsprechende sqlnet.ora-Datei enthält beispielsweise die folgenden Einträge: SQLNET.CRYPTO_SEED = jfkdjfks4384kjfkds SQLNET.ENCRYPTION_SERVER = required SQLNET.ENCRYPTION_CLIENT = accepted SQLNET.ENCRYPTION_TYPES_CLIENT= (3DES168, RC4_128) SQLNET.ENCRYPTION_TYPES_SERVER= (3DES168) SQLNET.CRYPTO_CHECKSUM_CLIENT = requested SQLNET.CRYPTO_CHECKSUM_SERVER = required SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER= (SHA1) SQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT= (SHA1) Listing 9.3: sqlnet.ora-Parameter für Verschlüsselung und Integritätsprüfung
376
Sicherheit
Es versteht sich, dass auf der Client-Seite nur die client-spezifischen Parameter gesetzt werden müssen. Eine Verbindung zwischen Client und Server kommt nach der Aktivierung immer dann zustande, wenn die konfigurierten Verhaltensweisen kompatibel sind und für den Fall, dass verschlüsselt wird bzw. die Prüfsummen gebildet werden, gemeinsame Algorithmen auf beiden Seiten gefunden werden. In unserem Beispiel wären das 3DES168 und SHA1. Kommt es zu keiner Übereinkunft der Algorithmen oder der Verhaltensweisen – eine Seite verweigert möglicherweise die Verschlüsselung –, kommt es zu folgender Fehlermeldung, und die Verbindung wird nicht aufgebaut: ORA-12660: Encryption or crypto-checksumming parameters incompatible Listing 9.4: Fehlgeschlagene Verbindung bei Advanced Security
Es ist durchaus möglich, dass die Verschlüsselung und Integritätsprüfung die Performance negativ beeinflusst. Dies hängt von vielen Faktoren, u.a. von den gewählten Algorithmen, ab. So sind die triple DES-Verfahren im Allgemeinen langsamer als die DES-Verfahren. Genaue Zahlen können nur durch individuelle Tests gewonnen werden. Bei der Entscheidung, welche Verfahren zum Einsatz kommen, sollte jedoch nicht nur die Performance im Vordergrund stehen!
9.4
Benutzerplanung
Beim Aufbau eines Sicherheitskonzeptes ist die Planung und Konfiguration von Datenbankbenutzern ein ganz wesentlicher Faktor. Erst über die vertrauenswürdige Identifikation und Authentifizierung von Benutzern ist eine sichere Autorisierung möglich. Es sind im Einzelnen die folgenden Kriterien zu beachten: 1. Wer greift aus welchem Kontext bzw. aus welcher Applikation auf die Systeme zu? 1. Welche Datenbereiche sind schützenswert? 2. Wie und in welchem Kontext soll die Authentifizierung der Benutzer durchgeführt werden? Wer soll über die Datenbank, wer extern authentifiziert werden? 3. Welche Benutzer erhalten welche Privilegien, und wie werden die Privilegien vergeben? 4. Ü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. Dies bedeutet, dass alle physischen Benutzer, die sich über einen Datenbankbenutzer an der Datenbank anmelden, mit identischen Privilegien arbeiten und auch von Auditing-Verfahren als ein Benutzer erkannt werden.
Benutzerplanung
377
Um den besonderen Anforderungen von webbasierten Anwendungen gerecht zu werden, wurden schon in der Version 9i so genannte Shared Schemas bereitgestellt, bei denen die Authentifizierung und Autorisierung über Verzeichnisdienste gesteuert werden9. Die Zuteilung der Privilegien wird dort mit Hilfe von Enterprise Roles geregelt, die ihrerseits mit globalen Datenbankrollen korrespondieren. Auf diese Weise können sich beliebig viele physische Benutzer ein Datenbankschema teilen, trotzdem erhält jeder dieser Benutzer nur die Privilegien, die seiner geschäftlichen Funktion angemessen sind. Ebenfalls mit Blick auf Webanwendungen wurden Secure Application Roles geschaffen, die nur über autorisierte Pakete aktiviert werden können. Auf diese Weise lassen sich ebenfalls unterschiedliche Privilegienprofile wechselweise in einem Schemakontext realisieren. Schließlich gibt es noch das Verfahren Proxy Authentication, bei dem ein Benutzer im Namen anderer für zentralisierte Login-Verfahren genutzt werden kann. Datenbankbenutzer A kann also als Datenbankbenutzer B agieren – sofern er über spezielle grant-Befehle dazu autorisiert wurde – und erhält ganz oder teilweise dessen Privilegien. Auch dieses Verfahren ist vornehmlich für Webapplikationen interessant, die einen zentralen Benutzer für die Verbindungsanforderungen aus dem Middle-Tier heraus nutzen und trotzdem individuelle Privilegien vergeben wollen. Benutzer, die mit ihren eigenen Objekten arbeiten, haben grundsätzlich alle möglichen Rechte in Bezug auf diese Objekte und können diese Rechte nach eigenem Gutdünken an Dritte weitergeben10. Aus diesem Grund wird in der Regel das Schema, das die Objekte der betreffenden Applikation enthält, nicht für Connects genutzt. Zugriffskontrollen (auditing) können ebenfalls nur im Kontext von Datenbankbenutzern und in ihrem Kontext gesetzten Client-Identifiern durchgeführt werden. Teilen sich also mehrere physische Benutzer ein Schema, so sind sie aus Sicht des Auditings nicht differenzierbar. 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, Secure Application Roles oder Proxy Authentication. Arbeiten alle Benutzer 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.
9 Siehe hierzu den Abschnitt Variante 3: Enterprise-Benutzer und Enterprise-Rollen auf Seite 397 10 Dies wird als »Discretionary Access Control« bezeichnet. Ein alternatives Modell, das über Labels arbeitet, steht mit dem so genannten Mandatory Access Control zur Verfügung. Zu Labels siehe den Abschnitt Labels.
378
Sicherheit
Aus diesen Gründen sollte auf jeden Fall für jede bekannte, physische Person, die mit der Datenbank arbeitet und sensible Datenbereiche nutzt, entweder ein eigener Datenbankbenutzer erzeugt oder ein schlüssiges Konzept für die individuelle Privilegienzuteilung über zentralisierte, extern authentifizierte Benutzer vorgelegt 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 einfachen Regeln werden leider immer dort verletzt, wo eine Anwendung für unterschiedliche Datenbanksysteme tauglich sein soll, die über unterschiedliche technische Möglichkeiten verfügen. Aus Sicht der Applikation ist es wichtig, dass sensible Daten nur eindeutig authentifizierten, individuellen Benutzern zugänglich gemacht werden. Hierfür stehen Passwörter, Zertifikate oder biometrische Verfahren zur Verfügung. Aus Sicht der Datenbank ist die eindeutige Identifizierung ausschlaggebend für eine individuelle Privilegierung. Hierbei kann jeder natürlichen Person ein Datenbankbenutzer zugeordnet werden, es können aber auch – wie bereits erwähnt – »zentrale« Applikationsbenutzer eingerichtet werden, über die Gruppen von Personen authentifiziert werden können und die trotzdem eine individuelle Privilegierung Einzelner sicherstellen. Für die Authentifizierung Einzelner stehen aus Sicht der Datenbank unterschiedliche Wege offen: Das für die Authentifizierung notwendige Passwort wird direkt in der Datenbank gespeichert. Die Authentifizierung findet demnach in der Datenbank statt. In diesem Verfahren sind individuelle Datenbankbenutzer nötig. Die Datenbank speichert selbst kein Passwort und »vertraut« externen Verfahren und Instanzen. Hiermit lassen sich auch Single-Sign-on-Prozesse realisieren. Es stehen in diesem Zusammenhang unterschiedliche Verfahren zur Verfügung, die in den folgenden Abschnitten unter den Rubriken »externe« und »globale« Authentifizierung gehandelt werden – Das Betriebssystem authentifiziert die Benutzer, Oracle ordnet diesen Benutzern automatisch interne Benutzer zu und verzichtet auf die Eingabe eines Passwort (externe Authentifizierung). In einer erweiterten Variante ist es sogar möglich, externen Rechnern und deren Betriebssystemen zu vertrauen und deren Benutzer ohne zusätzliche Authentifizierung zuzulassen. – Die Anmeldung nutzt das SSL-Protokoll für die direkte Anmeldung an die Datenbank. Der im Zertifikat des Wallets des Benutzers ausgewiesene Distinguished Name steuert die Zuordnung zu einem Datenbankbenutzer. – LDAP-Verzeichnisse, wie z.B. das Oracle Internet Directory, authentifizieren und autorisieren den Benutzer. Für die Authentifizierung können Passwörter oder Zertifikate im Rahmen des SSL-Protokolls genutzt werden. Die Zuordnung dieser Benutzer zu konkreten Datenbankbenutzern kann flexibel, z.B. über Shared Schemas oder exklusiv über den ausgewiesenen Distinguished Name des Benutzers erfolgen. – Dienste wie Kerberos und RADIUS authentifizieren die Benutzer und geben die erfolgreiche Authentifizierung an die Datenbank weiter.
Interne Benutzerverwaltung
379
Die Möglichkeiten der externen Authentifizierung sind, wie diese kurze Übersicht bereits deutlich macht, dermaßen komplex, dass deren detaillierte Darstellung die Intentionen dieses Buches bei weitem übersteigen würde. Aus diesem Grunde konzentrieren wir uns in diesem Kapitel auf die am häufigsten eingesetzten Verfahren. 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. Für den DBA kann dagegen die genaue Ermittlung der Privilegien für einzelne Benutzer komplexer werden, wenn diese über externe Verfahren wie z.B. Enterprise Roles zugewiesen werden. Zusätzlich zu der Authentifizierung der Applikationsbenutzer muss auch die Authentifizierung der DBAs konfiguriert werden. Natürlich können alle DBA-Aufgaben pauschal über die Benutzer SYS oder SYSTEM abgewickelt werden. Bei großen Umgebungen, die mehrere Personen in der Rolle des DBA beschäftigen, ist in der Regel die Schaffung individueller DBA-Benutzer zu empfehlen, um die Verantwortlichkeiten klarer zu regeln. Diese Benutzer können dann auch ganz gezielte Verwaltungsrechte zur Erfüllung ihrer Aufgaben erhalten. Vor diesem Hintergrund ist beispielsweise ein Sicherheitsadministrator denkbar und auch über entsprechende Systemprivilegien konfigurierbar.
9.5
Interne Benutzerverwaltung
Der Zugriff auf Oracle-Datenbanken erfolgt stets in Form von Sitzungen (Sessions). Sitzungen wiederum laufen im Kontext von Benutzern (Usern) ab, 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ühren11. Je differenzierter die Benutzerstrukturen in der Datenbank oder in externen Diensten aufgebaut werden, desto differenzierter lassen sich Identitäten feststellen und über diese notwendige Privilegienmuster ableiten und initialisieren. Der Zugriff über Pauschal- oder 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 aufwändig 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.
11 Beim Einsatz von Verzeichnisdiensten kann die Autorisierung auch extern erfolgen. Siehe hierzu den Abschnitt Internet Directory, LDAP und SSL.
380
9.5.1
Sicherheit
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. Für die globale Identifizierung kann ein gültiger X.509-Name oder ein Leerstring angegeben werden. Im letzten Fall erfolgt die Zuordnung eines externen zu dem entsprechenden internen Benutzer über Enterprise-User-Definitionen des Verzeichnisdienstes (Internet Directory). Bei der Proxy-Authentifizierung übernimmt eine Mittelschicht (Middle-Tier) die Authentifizierung der Clients und meldet sich über einen zentralen Applikationsbenutzer im Namen des betreffenden Clients bei der Datenbank an. Diese Weiterleitung kann mit oder ohne Übergabe des originalen Client-Passwortes erfolgen. In beiden Fällen müssen die betreffenden Benutzer der Datenbank bekannt sein, d.h., dort angelegt worden sein (create user). Eine abgewandelte Form der Proxy-Authentifizierung (Application User Proxy Authentication) übergibt lediglich die Identitätsdaten an die Datenbank, die diese dann in Form von ClientIdentifiern den betreffenden Sessions übergibt. In diesem Fall ist es nicht erforderlich, die betreffenden Benutzer in der Datenbank anzulegen und zu verwalten. Die einzelnen Verfahren werden in den folgenden Abschnitten detailliert besprochen.
9.5.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 Dictionarys verglichen. Da Passwörter in »gehashter« Form im Data Dictionary gespeichert werden, erfolgt ihr Vergleich entsprechend in »gehashter« Form. 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. Aus diesem Grunde wird das Verfahren auch als »schwache« Authentifizierung bezeichnet. Die interne Authentifizierung ist zweifelsfrei die einfachste Methode, hat jedoch auch eine Reihe gravierender Nachteile:
Interne Benutzerverwaltung
381
»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 Datenbanken 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, was bei einer großen Benutzerzahl zu einer entsprechenden administrativen Belastung führt. Im folgenden Beispiel wird der Benutzer guenter mit dem Passwort unbescheid definiert: SQL> CREATE USER guenter IDENTIFIED BY unbescheid PASSWORD EXPIRE;
Für die Benennung von Benutzern stehen im Prinzip alle Zeichen des betreffenden Zeichensatzes der Datenbank zu Verfügung, Kennwörter dagegen dürfen jedoch nur aus Zeichen mit einem Byte Länge bestehen. Um Probleme beim Wechsel von Zeichensätzen oder Migrationen von Schemata zu vermeiden, wird dringend empfohlen, die Bezeichner für Benutzer und Kennwörter aus dem Vorrat von ASCII-Zeichen zu wählen. 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 muss12. 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üsselwörtern festzulegen und den Benutzern zu empfehlen. Die grundlegende Anforderung an Schlüsselwörter 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 Wörter auszuwählen und nach bestimmten Regeln zu kombinieren, z.B. durch »Mischen« der Wörter auf Buchstabenebene: Erstes Wort: »Haus« Zweites Wort »1234« Daraus resultierendes Schlüsselwort: »h1a2u3s4« Schlüsselwörter sollten darüber hinaus in regelmäßigen Abständen geändert und nicht niedergeschrieben werden.
12 Siehe hierzu und zu den Regeln der Passwortvergabe auch den Abschnitt Password-Management.
382
Sicherheit
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. 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
Das Passwort des Benutzers wird – wie bereits erwähnt – in gehashter Form gespeichert und bei dieser Abfrage auch entsprechend – hexadezimal mit 16 Zeichen – angezeigt. Die – hier sichtbare – verschlüsselte Form kann keinesfalls als Eingabe für Authentifizierungen benutzt werden, weil die Eingabe während des Login-Verfahrens nochmals verschlüsselt wird und die Authentifizierung damit fehlschlägt. Wohl aber kann über die values-Klausel die verschlüsselte Form eines Kennwortes direkt in die Datenbank übernommen werden. Dies ist in manchen Fällen hilfreich, wenn z.B. ein nicht bekanntes, jedoch temporär geändertes Kennwort auf den alten Wert zurückgesetzt werden soll, so dass sich der betreffende Benutzer ohne Störungen anmelden kann: SQL> ALTER USER guenter IDENTIFIED BY VALUES '86F7130824E83895';
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.
9.5.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üsselwörtern erfolgt vielmehr mit aus Sicht der Datenbank fremden 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 /@test10
Wie oben bereits erwähnt wurde, gibt es sehr unterschiedliche Verfahren für die externe Authentifizierung, die sich nicht nur technologisch erheblich unterscheiden. Sie werden daher im Folgenden getrennt voneinander behandelt.
Interne Benutzerverwaltung
383
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. Im folgenden Beispiel wird der Benutzer johannes mit externer Authentifizierung in der Datenbank angelegt: SQL> CREATE USER ops$johannes IDENTIFIED EXTERNALLY;
In diesem Fall würde der Betriebssystembenutzer johannes ohne Angabe eines Passwortes mit dem Benutzer ops$johannes der Datenbank verbunden. johannes hätte – da für ihn kein Passwort hinterlegt ist – auch keinerlei Möglichkeit, sich anderweitig zu authentifizieren. 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, dass 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 Verzeichnisdiensten13 und Authentifizierungsservern. Die dargestellte Methode mutet etwas antiquiert an, hat jedoch auch heutzutage noch einige Vorteile: Die Benutzer müssen sich keine zusätzlichen Passwörter für ihre Datenbankverbindungen merken und können sich sicher authentifizieren für den Fall, dass sie direkt auf dem Datenbankserver arbeiten. Batch-Programme, die sehr häufig direkt auf dem Server zur Ausführung gebracht werden, kommen ohne hart kodierte Passwortanweisungen aus. Das Verfahren hat jedoch auch Nachteile: Die Einwahl von entfernten Clients (remote Login) ist in der Regel extrem unsicher und sollte auf jeden Fall vermieden werden. Jeder externe Benutzer kann immer nur mit einem speziellen internen Benutzer verbunden werden.
13 Siehe hierzu die ausführliche Besprechung in den Abschnitten Internet Directory, LDAP und SSL f.
384
Sicherheit
Unter den Betriebssystemen Windows 2000 und XP werden Authentifizierungen – transparent für den Benutzer – über eigene Authentifizierungsprotokolle durchgeführt14. 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, das auf jeder Oracle-CD für Windows enthalten ist und separat installiert werden muss. 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 kann 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 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 Kontexten außerhalb von Oracle eingesetzt werden und entsprechende administrative Erfahrungen vorliegen. Sie ermöglichen die Authentifizierung nach dem 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.ora15 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.
14 Dies sind standardmäßig Kerberos für Windows 2000 und NT LAN Manager für Windows NT. 15 Hier vor allem über den Parameter SQLNET.AUTHENTICATION_SERVICES.
Interne Benutzerverwaltung
9.5.4
385
Globale Authentifizierung
Bei der globalen Authentifizierung werden Benutzer über digitale Zertifikate oder über Kennwörter 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 kann hierbei ebenfalls durchgeführt werden. 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 Internet Directory, LDAP und SSL auf Seite 395 besprochen.
9.5.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. Es stehen unterschiedliche Modelle und Technologien zur Verfügung, um die Authentifizierung im 3-Schicht-Betrieb sicherzustellen. 1. Im einfachsten Fall stellt der Application-Server eine zentrale Verbindung zu der betreffenden Datenbank her. Die Authentifizierung zwischen Applikationsserver und Datenbank erfolgt über ein Kennwort, das explizit und hart codiert im Kontext der Anwendung auf dem Applikationsserver verankert werden muss. Auf diese Weise stehen jedem Benutzer prinzipiell alle Privilegien des zentralen Datenbankbenutzers zur Verfügung. Individuelle, einschränkende Privilegienzuteilungen an einzelne Benutzer müssen über den jeweiligen Applikationscode geregelt werden. Hinzu kommt, dass Kennwortänderungen auf Seiten der Datenbank Codeanpassungen der Applikation nach sich ziehen. Es versteht sich, dass diese Art der Authentifizierung wegen der erwähnten Nachteile nur in Ausnahmefällen zu empfehlen ist, z.B. dort, wo die Authentifizierung individueller Clients gegenüber der Datenbank nicht gefordert wird. Darüber hinaus wird diese Methode in strengem Sinne nicht unter dem Terminus Proxy Authentication gehandelt. 2. In einem zweiten Modell wird der Client von der Mittelschicht über eine beliebige Methode authentifiziert. Die Mittelschicht authentifiziert sich gegenüber der Datenbank – hart codiert oder über geeignete kennwortlose Verfahren – über einen zentralen Applikationsbenutzer, trägt jedoch die Identität des betreffenden Endbenutzers über entsprechende Client-Identifier in die Datenbank hinein. Die Privilegierung des Benutzers kann dann – abhängig von dem gesetzten Client-Identifier – über eine Startprozedur erfolgen, die entsprechende Application Roles16 aktiviert. Die Frage, welche Rollen für welche Benutzer zu aktivieren sind, kann entweder über die Applikation selbst oder über »Dummy«-Benutzer innerhalb der Datenbank erfolgen. Diese Dummy-Benutzer sind in der Datenbank ohne das Privileg create session jedoch mit den für sie wichtigen Application Roles angelegt. Diese Benutzer dienen demnach nur als »Repository« für die 16 Application Roles werden in Abschnitt 9.7.3 besprochen.
386
Sicherheit
Aktivierung der Rollen über die betreffende Applikation. Die zugeteilten Rollen können von den Benutzern selbst jedoch niemals direkt aktiviert werden, weil die zur Aktivierung vorgesehene Prozedur im Schema des Applikationsbenutzers liegt. Der zugewiesene Client-Identifier erlaubt darüber hinaus auch die Nutzung von Auditing-Verfahren und ist über die Funktion sys_context jederzeit innerhalb von SQL-Anweisungen abrufbar. Der Vorteil dieser Methode gegenüber der oben erwähnten ersten besteht in der individuellen Privilegierung von Endbenutzern und in der zentralen Verwaltung der Privilegien innerhalb der Datenbank. Die folgenden Codezeilen skizzieren die für dieses Modell mögliche Syntax in Ausschnitten. Es handelt sich dabei keinesfalls um eine fertige und ausführbare Prozedur. Einige der hier genutzten Konstrukte werden im Detail erst in den nachfolgenden Abschnitten behandelt. Security-Kontext für Applikations-DEMO -- Einrichten von Secure Application Roles für Benutzerprofile ENDUSER und ADMIN -- Die Rollen werden geschaltet über das Schema APPUSER CREATE ROLE demo_admin IDENTIFIED USING appuser.appstart; CREATE ROLE demo_enduser IDENTIFIED USING appuser.appstart; -- Kontrolle der angelegten Application Roles SELECT ROLE, SCHEMA, PACKAGE FROM dba_application_roles WHERE SCHEMA = 'APPUSER'; -- Einrichten des Schema-Owners (enthält alle Datenbankobjekte) CREATE USER appowner IDENTIFIED BY ownpwd; -- zuteilen der Owner-Privilegien, z.B. GRANT CONNECT, RESOURCE TO ownpwd; -- Aufbau der Objekte und .. -- Zuteilung der Objektprivilegien an die Application Roles -- GRANT select, update ON tabelle1 TO demo_enduser; -- Einrichten der Endbenutzer, kein connect vorgesehen CREATE USER u4711 IDENTIFIED EXTERNALLY; -- Zuteilung der Application Roles an die Benutzer -- keine weiteren Systemprivilegien GRANT demo_enduser TO u4711; -- Application Roles sollen keine Default Rollen sein: ALTER USER u4711 DEFAULT ROLE NONE; -- ## Einrichten des separaten zentralen "Proxy"-Benutzers, -- der von der Mittelschicht angewählt wird und die Rollen aktiviert CREATE USER appuser IDENTIFIED BY apppwd; -- Grant von minimalen Privilegien, z.B. GRANT CREATE SESSION TO appuser; -- Anlegen eines Startpaketes für Appuser, z.B. über separaten DBA-user -- dadurch braucht APPUSER keine entsprechenden Systemprivilegien -- die Mittelschicht übergibt den authentifizierten Endbenutzer -- ... der vorgestellte Code enthält nur Fragmente! CREATE OR REPLACE PROCEDURE appuser.appstart ( client_in IN v$session.client_identifier%TYPE )
Interne Benutzerverwaltung
387
AUTHID CURRENT_USERüfen etc. IF sys_context('userenv', 'ip_address') IN ..... THEN -- ... um schliesslich die gegranteten Rollen zu ermitteln FOR rec_role in (SELECT granted_role FROM dba_role_privs WHERE granted_role IN ( SELECT ROLE FROM dba_application_roles WHERE SCHEMA = USER ) AND grantee = client_id_in) LOOP -- hier einen kommaseparierten String aufbauen END LOOP; -- ... diesen String schliesslich zum Aktivieren nutzen DBMS_SESSION.SET_ROLE (lv_rolestring); END IF; DBMS_SESSION.set_identifier (cliend_in); EXCEPTION WHEN ..... END appstart; / -- Der gesetzte Client-Identifier kann dann beliebig im SQL-Kontext genutzt werden select * FROM my_view WHERE benutzer = sys_context('userenv', 'client_identifier');
Ein drittes mögliches Modell arbeitet mit der Proxy-Authentifizierung im eigentlichen Sinne. Hierbei wird ebenfalls ein Applikationsbenutzer angelegt, der selbst nur minimale Privilegien erhält und über den sich der Application-Server einwählt. Die Authentifizierung dieses Benutzers in der Datenbank kann über ein Passwort oder über ein Zertifikat per SSL erfolgen: CREATE USER application1 IDENTIFIED BY ......; GRANT .... TO applikation1;
Die für die Anwendung nötigen Endbenutzer sind ebenfalls in der Datenbank angelegt worden und haben die für ihre Aufgaben nötigen Datenbankrollen erhalten. Für den Fall, dass sie außerhalb der Anwendung keine separaten Aktivitäten durchführen sollen, kann ihnen das Privileg create session vorenthalten werden: CREATE USER client1 IDENTIFIED .....; GRANT rolle1,rolle2 TO client1;
Im nächsten Schritt erhält nun der Anwendungsbenutzer das Recht, client1 für den Sitzungsaufbau als Proxy zu nutzen: ALTER USER client1 GRANT CONNECT THROUGH applikation1 WITH ROLE rolle2;
Zusätzlich wird in diesem Beispiel für client1, wenn er über den Applikationsbenutzer applikation1 mit der Datenbank verbunden wird, nur die Rolle rolle2 aktiviert. Die Mittelschicht ist nun in der Lage, die Session von applikation1 im Namen und mit den Privilegien von client1 zu nutzen, unter der Voraussetzung, dass die Verbindung über den »dicken« JDBC-Treiber17 aufgebaut wird. Im angegebenen Beispiel wird die Session ohne weitere Authentifizierung im Namen von client1 17 Auch OCI JDBC-Treiber genannt, weil er auf den Oracle Call Interface APIs aufbaut. Im Gegensatz zum »dünnen« JDBC-Treiber setzt dieser Treiber die Installation von ORACLE Net auf der Client-Seite voraus.
388
Sicherheit
eröffnet. Alternativ sind jedoch Varianten denkbar, bei denen der Applikationsbenutzer zum Verbindungsaufbau im Namen des Clients zusätzliche Authentifizierungsmethoden einsetzen muss: -- (a) Passwort von CLIENT1 muss mit angegeben werden ALTER USER client1 GRANT CONNECT THROUGH applikation1 AUTHENTICATED USING PASSWORD; -- (b) Zertifikat von CLIENT1 muss geliefert werden ALTER USER client1 GRANT CONNECT THROUGH applikation1 AUTHENTICATED USING CERTIFICATE; -- (c) Distinguished Name von CLIENT1 muss mit angegeben werden ALTER USER client1 GRANT CONNECT THROUGH applikation1 AUTHENTICATED USING DISTINGUISHED NAME;
Proxy-Einstellungen dieser Art lassen sich über die View dba_proxies18 abfragen: PROXY CLIENT AUTHENTICATION AUTHORIZATION_CONSTRAINTROLE ------------- ------- -------------- ------------------------ ---------------APPLICATION1 CLIENT1 NO PROXY MAY ACTIVATE ROLECONNECT
Die Vorteile der Proxy-Authentifizierung liegen vor allem darin, dass über eine physische Verbindung unterschiedliche Sessions im Namen und mit den Privilegien bekannter Datenbankbenutzer aufgebaut werden können. JDBC nutzt dazu den OCI Connection-Pool, der in der Lage ist, so genannte Lightweight Sessions zu initialisieren, indem bereits initiierte physische Verbindungen zu der Datenbank für unterschiedliche Sessions genutzt werden. Das folgende kurze Codebeispiel illustriert das Vorgehen im Kontext eines Java-Client-Programms. Da – wie bereits erwähnt – zur Nutzung der Proxy-Authentifizierung der »dicke« JDBC-Treiber benötigt wird, ist es wichtig, den Klassenpfad vor der Ausführung des Programms auf $ORACLE_HOME/jdbc/lib zu setzen. Dieses Verzeichnis enthält die »dicken« JDBC-Treiber. Wenn dieser Test mit Hilfe vom JDeveloper ausgeführt wird, lässt sich der Pfad einstellen über: – Project Properties – Profiles – Development – Libraries. package mypackage1; import java.sql.*; import java.util.*; // Pfad muss auf DICKES JDBC zeigen import oracle.jdbc.*; import oracle.jdbc.pool.OracleOCIConnectionPool; import oracle.jdbc.oci.OracleOCIConnection; public class ProxConn { public static void main (String [] args) { String aliasName = "(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = " + " (PROTOCOL = TCP) (HOST = myServer) (PORT = 1521)))" + " (CONNECT_DATA = (SERVICE_NAME = TEST10.DBCONSULT.DE)))"; 18 Unter Oracle8i ist die View proxy_users zu benutzen.
Interne Benutzerverwaltung
389
try { OracleOCIConnectionPool db = new OracleOCIConnectionPool(); db.setURL("jdbc:oracle:oci:@"+aliasName); // Benutzer für Applikationsidentität db.setUser("application1"); db.setPassword("apppwd"); Properties pr = new Properties(); // OCI Connection-Pool:Initiale + maxim. Anzahl physischer Connects pr.setProperty(OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT,"1"); pr.setProperty(OracleOCIConnectionPool.CONNPOOL_INCREMENT,"1"); pr.setProperty(OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT,"10"); db.setPoolConfig(pr); // Einstellungen fuer Proxy-User Properties proxyUser = new Properties(); proxyUser.setProperty(OracleOCIConnectionPool.PROXY_USER_NAME, "client1"); Connection co = db.getProxyConnection(OracleOCIConnectionPool.PROXYTYPE_USER_NAME, proxyUser); System.out.println("Erfolgreich!"); // Abwarten, um ueber v$session zu beobachten Thread.sleep(15000); co.close(); } catch (Exception ex) { System.out.println(ex.toString()); } } }
Auf Seiten der Datenbank lässt sich über die View v$session der Verbindungsaufbau gut verfolgen: SELECT schemaname, status, username, type, server FROM v$session WHERE username IS NOT NULL; 01 SCHEMANAME STATUS USERNAME TYPE SERVER 02 ------------ ------------ ------------ --------- ----------03 CLIENT1 INACTIVE CLIENT1 USER PSEUDO 04 APPLICATION1 INACTIVE APPLICATION1 USER DEDICATED 05 SYSTEM ACTIVE SYSTEM USER DEDICATED
Zeile 4 zeigt die dedizierte Verbindung über den Benutzer application1, die der OCI Connection-Pool minimal initiiert. Durch den Proxy-Connect wird eine Session unter client1 erzeugt (Zeile 3), welche die physische Verbindung von application1 nutzt, jedoch in der View als Pseudo-Server angezeigt wird. Die Session in Zeile 5 hat die Abfrage abgesetzt. Die Übergabe des Passwortes für den Applikationsbenutzers application1 erfolgt in unserem Beispielprogramm hart codiert. Alternativ könnten Verfahren, beispielsweise über SSL, zum Einsatz kommen, bei denen kein Passwort explizit übergeben werden muss oder bei denen durch die Verschlüsselung und Integritätsprüfung die übertragenen Daten entsprechend abgesichert werden. Für Verbindungen aus dem OCI-Kontext stehen in diesem Zusammenhang grundsätzlich die gleichen Mechanismen wie für Oracle Net bereit.
390
9.5.6
Sicherheit
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 Privilege SYSOPER
STARTUP, SHUTDOWN
SYS (eingeschränkt)
CREATE SPFILE ALTER DATABASE OPEN/MOUNT/BACKUP archivelog Recovery Restricted Session Privilege Tabelle 9.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. sqlplus /nolog SQL> CONNECT / AS SYSDBA
Interne Benutzerverwaltung
391
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 force=n
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 den Benutzer SYS. Privilegien, die über Oracle-Passwortdateien verwaltet werden, lassen sich über die View v$pwfile_users auflisten.
392
9.5.7
Sicherheit
Benutzerverwaltung
Zur Benutzerverwaltung gehört mehr als das Festlegen des Benutzernamens und der geplanten Authentifizierungsmethode. Die wichtigsten Aufgaben werden in den folgenden Abschnitten besprochen. Tablespaces und Quoten Jedem Benutzer, der in der Datenbank definiert wird, 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, dass Benutzer in ihrem Default Tablespace 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. Ab 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;
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. Das Sperren von Benutzern wird gerne verwendet, um Schemata, die Datenbankobjekte enthalten, vor dem direkten Zugriff zu schützen.
Interne Benutzerverwaltung
393
ALTER USER scott ACCOUNT LOCK;
Die Sperre kann vom Administrator jederzeit durch die UNLOCK-Klausel aufgehoben werden. 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) gleichzeitig aktiven Benutzern oder Datenbanksitzungen (Concurrent Usage) Zur Überwachung der im Einzelfall vereinbarten Maximalwerte stehen die folgenden, dynamischen Systemparameter zur Verfügung: sessions_max 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. sessions_warning setzt den Schwellenwert für Warnungen im Zusammenhang 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. sessions_current gibt die aktuelle Anzahl von Sessions an. sessions_highwater gibt die maximale Anzahl von Sessions an, die über die Instanz seit ihrem Start betrieben wurden. users_max gibt die maximale Anzahl von Benutzern (Named User) an, die in der Datenbank angelegt werden können. Ü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 – wie bereits eingangs erwähnt wurde – 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 KONFIGURATIONSASSISTENTEN 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;
394
Sicherheit
Die folgende Tabelle gibt einen Überblick über die wichtigsten Standardbenutzer. Benutzer
Standardpasswort
Kontext
Privilegien
Bemerkungen
SYS
CHANGE_ON_INSTALL
Schema des Data Dictionarys
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 9.2: Vordefinierte Datenbankbenutzer
Nach Änderung Datei snmp_rw.ora anpassen
Internet Directory, LDAP und SSL
9.6
395
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 Kennwörtern führt bei der Menge der Systeme zu schwachen, leicht zu erratenden Kennwörtern, 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 Privilegierung 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 Datenbankschemata 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.
396
9.6.1
Sicherheit
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. LDAP19 – regeln den Zugriff auf diese Verzeichnisdienste. Am Markt sind unterschiedliche LDAP-Server verfügbar. Einer von ihnen ist der Server des Oracle Internet Directorys (OID), der die Verzeichnisdaten gemäß den standardisierten Verzeichnisstrukturen in einer Oracle-Datenbank 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. Digitale Zertifikate können in Containern, so genannten Wallets, gespeichert werden. Wallets lassen sich über Kennwörter öffnen und authentifizieren dann deren Benutzer für den Zugriff auf Datenbanken oder andere Ressourcen. Protokolle für die Verschlüsselung, Authentifizierung und Integritätsprüfung – wie z.B. SSL20 – 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 oder Passwort 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, von denen nur die wichtigsten in diesem Zusammenhang besprochen werden können: 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 19 LDAP steht für Lightweight Directory Access Protocol. 20 SSL steht für Secure Sockets Layer. Das Protokoll sorgt für die Authentifizierung, Verschlüsselung und Integritätsprüfung einer TCP/IP-Verbindung.
Internet Directory, LDAP und SSL
397
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 Variante 2 wird in diesem Modell die Zuordnung der Benutzer zu bestimmten Datenbankschemata ü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. EnterpriseRollen 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 EnterpriseBenutzer mit jeweils unterschiedlichen Privilegien ein Datenbankschema nutzen. Die Authentifizierung der Benutzer erfolgt in diesem Modell über Kennwörter, die für den Enterprise-Benutzer im Verzeichnisdienst gespeichert werden, oder Zertifikate. Der Verbindungsaufbau zur Datenbank erfolgt über Oracle Net oder – bei der Nutzung von Zertifikaten – über SSL. Im letzteren Fall werden auch die Verschlüsselung der Daten und die Integritätsprüfung durchgeführt.
398
Sicherheit
Enterprise User - Global User Enterprise User Enterprise Role Global Role Global User Privilegien
Directory Service
Datenbank
Abbildung 9.4: Beziehungen zwischen Enterprise-Objekten und globalen Objekten
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 Bei Nutzung von SSL: gültige digitale Zertifikate für den betreffenden Benutzer und die Zieldatenbank Globale Datenbankbenutzer ohne Angabe eines Distinguished Names sowie globale Rollen in den Zielsystemen, welche die entsprechenden Privilegien enthalten Bei Nutzung von SSL: 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 Schemata 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.
Internet Directory, LDAP und SSL
399
Die zur technischen Umsetzung dieser Modelle notwendigen Konfigurationsmaßnahmen werden in den Abschnitten Modell 1: Auflösung von Dienstbenennungen bis Modell 3: Enterprise-Benutzer und Enterprise-Rollen im Einzelnen erläutert.
9.6.2
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.
400
Sicherheit
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. 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.
Internet Directory, LDAP und SSL
401
LDAP-Server Instanzen
LDAP-Server
LDAP Anforderungen
OID Listener
LDAP-Server
Net Listener
LDAP-Server
Oracle Net
Abbildung 9.5: LDAP-Diagramm
Directory Replication-Server Der Directory Replication-Server sorgt für die Replikation der Verzeichnisdaten. 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 Services21). 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.
21 Oracle Net Services ist der neue Name für SQL*Net und Net8. Er wurde mit Oracle9i eingeführt.
402
Sicherheit
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. Anwendungen Zur Administration und Nutzung des Internet Directorys stehen diverse Webanwendungen und Java-Client-Programme zur Verfügung, wie z.B. Enterprise Manager Application Server Control zum Starten und Stoppen der OIC-Instanzen oder der Enterprise Security Manager zur Verwaltung von LDAP-Benutzern. Installation und Konfiguration Oracle Internet Directory ist seit der Version 10g in die Identity-ManagementInfrastruktur des Oracle Application-Servers integriert und wird aus diesem Kontext heraus auch installiert. Die Software ist derzeit über die Option 1 – »Oracle Application-Server – Portal and Wireless« über das Technologie-Netzwerk22 herunterzuladen und nach den aktuellen Lizenzbestimmungen nutzbar. Es ist dringend zu empfehlen, vor der Installation die entsprechenden Installationsvoraussetzungen zu beachten. Hierzu stehen wie üblich die plattform-spezifische Dokumentation sowie Readme-Dateien zur Verfügung. Zusätzlich bietet Metalink für Linux-Plattformen unter der Nummer 309401.1 ein Dokument mit genauen Prüfroutinen an. In diesem Zusammenhang steht auch ein sehr nützliches Shell-Skript zur Prüfung der Installationsvoraussetzungen zum Download bereit. Bevor dieses Skript nicht fehlerfrei durchlaufen wird, sollte nicht an eine Installation gedacht werden! Die Installation selbst wird – wie gewohnt – über den Universal Installer und dort über die Installationsart »OracleAS Infrastructure« und anschließend »Identity Management und Metadaten-Repository« ausgeführt. Sie hat in einem separaten Home-Verzeichnis zu erfolgen. In einem weiteren Fenster sind dann die einzelnen Komponenten auszuwählen: Hier sollte neben ORACLE INTERNET DIRECTORY auf jeden Fall noch DELEGATED ADMINISTRATION SERVICE ausgewählt werden, um einige Webanwendungen zur Benutzerverwaltung zu installieren. Diese Installationsart installiert Komponenten, wie den HTTP-Server, eine 10gDatenbank als Repository für die Infrastruktur-Komponenten, unter ihnen auch Oracle Internet Directory, einen minimalen Application-Server (ORACLEAS CONTAINERS FOR J2EE) für die administrativen Anwendungen sowie explizit ausgewählten Komponenten.
22 http://technet.oracle.com
Internet Directory, LDAP und SSL
403
Abbildung 9.6: Installation von Oracle Internet Directory
Abbildung 9.7: Auswahl der zu installierenden Komponenten
Nach der erfolgreichen Installation findet sich eine gute Zusammenfassung der installierten Komponenten sowie der URLs für die diversen Anwendungen in der Datei $ORACLE_HOME/install/setupinfo.txt. Hier finden sich alle relevanten Informationen, die während der Installation interaktiv abgefragt wurden.
404
Sicherheit
Die Installation hinterlässt eine fertig gestartete Umgebung des Application-Servers. Die Startseite ist unter der in der Setup-Info angegebenen URL erreichbar und über sie auch die Webanwendung Enterprise Manager 10g Application Server Control. Dort können alle installierten Komponenten, so auch das Internet Directory, administriert werden. Die Home-Page der betreffenden Server-Farm zeigt die Komponenten.
Abbildung 9.8: IAS Control-Homepage
Die Seite von Internet Directory kann über diese Homepage erreicht werden und zeigt in unserem Beispiel zwei gestartete OID-Instanzen sowie nützliche Links für die Arbeit: Um auch nach dem Neustart des Rechners eine gut funktionierende OID-Umgebung vorzufinden, sollen an dieser Stelle kurz die Schritte zusammengefasst werden, die zum manuellen Start der Umgebung unter Unix nötig sind. Es versteht sich, dass diese Schritte in einer produktiven Umgebung automatisiert werden: Als Erstes sind die Umgebungsvariablen einzustellen – beispielsweise über folgendes Shell-Skript: export PATH=${PATH}:/usr/local/bin export ORACLE_SID=IADB export ORAENV_ASK=NO . oraenv export LD_LIBRARY_PATH=/usr/lib:$ORACLE_HOME/lib export PATH=${PATH}:$ORACLE_HOME/bin:$ORACLE_HOME/dcm/bin:$ORACLE_HOME/opmn/ bin:$ORACLE_HOME/oca/bin export ORAENV_ASK=YES
Internet Directory, LDAP und SSL
405
Abbildung 9.9: OID-Homepage
Nachdem die Umgebung eingestellt wurde, können der Listener und die Repository-Datenbank wie üblich gestartet werden. Dies ist notwendig, damit im nächsten Schritt der Start der Hintergrundprozesse gelingt. Für das Prozessmanagement der Hintergrundprozesse des Application-Servers steht das Zeilenwerkzeug opmnctl zur Verfügung. Hierüber können einzelne oder alle Prozesse des Servers gestartet oder gestoppt werden. Mit dem Kommando opmnctl startall werden beispielsweise alle Hintergrundprozesse aktiviert. Nach kurzer Wartezeit gibt dann opmnctl status Auskunft über den Status:
Abbildung 9.10: Ausgabe von opmnctl status
Im letzten Schritt ist jetzt noch die Anwendung Enterprise Manager IAS Control wie folgt zu starten: emctl start iasconsole
406
Sicherheit
Neben den erwähnten administrativen Werkzeugen wird die inhaltliche Arbeit mit den Verzeichniseinträgen von OID über zusätzliche Tools geregelt, die alle im Zuge der Installation auf Platte kopiert werden: Der »Oracle Directory Manager« ist ein Java-Client-Werkzeug, über das sämtliche Verzeichnisstrukturen zugänglich und manipulierbar sind. Es wird jedoch für die praktische Arbeit mit Enterprise-Benutzern und für die Registrierung von Datenbanken nur selten genutzt, weil es dem Anwender eine genaue Kenntnis der internen Speicherstrukturen abverlangt. Das Werkzeug wird über oidadmin aufgerufen und erfordert zur Anmeldung an das Repository einen Benutzernamen – standardmäßig orlcadmin – und das entsprechende Passwort. Der »Enterprise Security Manager« ist ebenfalls ein Java-Client-Werkzeug, mit dem alle Aufgaben im Kontext mit Enterprise-Benutzern und Enterprise-Rollen sowie deren Zuordnung zu den registrierten Datenbanken komfortabel durchgeführt werden können. Das Werkzeug ist leider nur über die Client-Installation verfügbar. Es kann entweder direkt über den Befehl esm oder über die Java Enterprise Manager Console mit oemapp esm aufgerufen werden. Schließlich steht noch eine Webanwendung zur Verfügung, die auch den Titel »Enterprise Security Manager« trägt, jedoch in der Funktionalität etwas eingeschränkt wurde. Über sie können nur Enterprise-Benutzer angelegt und verwaltet werden, jedoch keine Zuordnung zu den Datenbanken und EnterpriseRollen vorgenommen werden. Die URL zum Aufruf dieser Anwendung lautet beispielsweise (die Portnummer kann von Installation zu Installation variieren): http://myServer:7780/oiddas/ui/oideushome
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-Schemata – ü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 Modell 1: Auflösung von Dienstbenennungen bis Modell 3: Enterprise-Benutzer und Enterprise-Rollen.
Internet Directory, LDAP und SSL
407
Jede Oracle-Datenbank, die Verzeichnisdaten enthält, wird demnach durch die folgenden Merkmale charakterisiert: Sie enthält im Datenbankschema ods Tabellen, Pakete und Sequenzen zur Speicherung von Metadaten und Benutzerdaten. 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. 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, das 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 entsprechend 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.
408
Sicherheit
Alle identifizierenden Daten einer Entität – das Schlüsselpaar, das Zertifikat sowie vertrauenswürdige Trust Points – werden in Form eines so genannten Wallets 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 Zertifikatsanforderungen und Verwalten von Wallets zur Verfügung. Zertifikatsanforderungen können hier exportiert und – nach der Bearbeitung durch eine vertrauenswürdige Zertifizierungsstelle – als fertiges Zertifikat wieder importiert werden. 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-Projektes23 kostenfrei zur Verfügung. 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.
9.6.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
23 Informationen und Downloads finden sich unter der Internet-Adresse www.openssl.org.
Internet Directory, LDAP und SSL
409
Planung und Definition von Dienstbenennungen Einträge in Verzeichnisdiensten erfolgen – wie bereits in Abschnitt »Verzeichnisdienste« auf Seite 399 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 Oracle-Kontext 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 In diesem Beispiel gehen wir davon aus, dass die spezifischen Objektklassen (Oracle-Schema) bereits im Rahmen der Installationsprozedur oder nachträglich über den Oracle Internet Configuration Assistant (oidca) aufgebaut wurden. Die nötigen Objektklassen sind also bereits vorhanden. Das Vorhandensein eines Oracle-Kontexts sowie seine versionsspezifische Verträglichkeit lassen sich ebenfalls über oidca im Voraus überprüfen. Das folgende Beispiel prüft den Kontext dc=dbconsult,dc=de erfolgreich: oidca mode=CREATECTX -silent oidhost=myServer nonsslport=3060 dc=orcladmin pwd=kennwort contextdn=“dc=dbconsult,dc=de“ Oracle Context ist aktuell.
Die Konfiguration der Dienstbenennungen über den Verzeichnisdienst kann über den Enterprise Manager oder den Net Manager vorgenommen werden. In beiden Fällen ist dem Client, von dem aus das Werkzeug aufgerufen werden soll, beizubringen, auf welchem Server sich der betreffende Verzeichnisdienst befindet und in welchem Bereich der dortigen Baumstruktur der Oracle Context angelegt wurde, der die Einträge aufnehmen soll. Diese Grundkonfiguration kann über den Net Configuration Assistant generiert werden, der die Datei ldap.ora erzeugt, die im Verzeichnis $ORACLE_HOME/network/admin abgelegt. wird. # ldap.ora Network Configuration File: H:\Oracle\Client10R1\network\admin\ldap.ora # Generated by Oracle configuration tools. DIRECTORY_SERVERS= (myServer:3060:3130) DEFAULT_ADMIN_CONTEXT = "dc=dbconsult,dc=de" DIRECTORY_SERVER_TYPE = OID Listing 9.5: LDAP.ora-Datei zur Bekanntmachung eines Verzeichnisdienstes
Die oben abgebildete ldap.ora-Datei hat den Port 3060 für normale und den Port 3130 für SSL-Verbindungen des OID-Verzeichnisdienstes auf myServer konfiguriert. Der administrative Kontext – unter dem standardmäßig Einträge erstellt und gesucht werden – ist dc=dbconsult,dc=de.
410
Sicherheit
Nachdem diese Voreinstellungen abgeschlossen sind, kann nun der Net Manager aufgerufen werden. Im linken Auswahlmenü wird ab sofort der Eintrag »Verzeichnis« angezeigt, über den Dienstbenennungen und Aliasnamen für Dienstbenennungen erzeugt oder modifiziert werden können. Dienstbenennungen spezifizieren den kompletten Kontext für die Verbindung – wie aus der Syntax der Datei tnsnames.ora hinlänglich bekannt sein dürfte –, Aliasnamen dagegen verweisen auf Dienstbenennungen, die im gleichen oder in fremden administrativen Kontexten angelegt wurden. Beim erstmaligen Aufklappen des Verzeichnisbaumes muss sich der Benutzer zunächst beim Verzeichnisdienst authentifizieren. Standardmäßig kann hierzu der LDAP-Benutzer cn=orcladmin oder ein beliebiger anderer genutzt werden. Wichtig ist nur, dass der betreffende für die Verwaltung von Dienstbenennungen privilegiert wurde und in dem konkreten administrativen Kontext – hier dc=dbconsult,dc=de – bekannt ist. Die folgende Abbildung zeigt Dienstbenennungen und Aliasnamen.
Abbildung 9.11: Oracle Net Manager zur Verwaltung von Dienstbenennungen und Aliasnamen über einen Verzeichnisdienst
Vorhandene Dienstnamen können – ebenfalls über Oracle Net Manager – aus einer lokalen Datei tnsnames.ora in das Verzeichnis importiert werden. Hierzu wird über die Menüleiste BEFEHL – DIRECTORY – NET SERVICE NAMES EXPORTIEREN aufgerufen. Im anschließenden Dialog lassen sich die Dienstnamen und die administrativen Kontexte auswählen. Konfiguration des Clients Die Konfiguration von Clients ist im Anschluss 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 über die Datei ldap.ora
Internet Directory, LDAP und SSL
411
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 Manager24 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 des Punktes 2 ist – wie bereits erwähnt – ein anderes Werkzeug, der Oracle Net Configuration Assistant, zuständig. Die Datei ldap.ora kann natürlich auch von Hand editiert werden. Der Verbindungsaufbau von Clientseite kann nun erfolgreich in der gewohnten Syntax durchgeführt werden: sqlplus scott/tiger@test9
Der Dienst- bzw. Aliasname test9 wird für den Zugriff auf den Verzeichnisdienst auf Grund des zugrunde liegenden administrativen Kontexts umgewandelt in: cn=test9,cn=OracleContext,dc=dbconsult,dc=de
Die Namensauflösung über Verzeichnisdienste ist – wegen des erforderlichen Zugriffs auf den LDAP-Server – geringfügig aufwändiger als die über die lokale Datei tnsnames.ora. Dem stehen jedoch die Vorteile der zentralisierten Namensverwaltung gegenüber.
9.6.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 zwischen Client und Datenbank. Die SSL-Verbindung sorgt auch für die Verschlüsselung und Integritätsprüfung der übermittelten Datenpakete. 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
24 Unter Oracle8i heißt dieses Werkzeug Oracle Net8 Assistant.
412
Sicherheit
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 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, CN=dbconsult. Bei der Generierung ist ferner ein entsprechendes Passwort anzugeben und eine Schlüssellänge auszuwählen. Die Anforderung wird im vorgeschlagenen Standardverzeichn25is oder anderweitig 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. Wie bereits erwähnt wurde, lässt sich für Testzwecke eine eigene Zertifizierungsstelle mit Hilfe von openSSL anlegen. Von der betreffenden Zertifizierungsstelle 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. Das Importieren kann dann entweder durch Einlesen der gelieferten Datei oder über Cut-und-Paste-Aktionen durchgeführt werden. Die Zertifikatsanforderung erhält dadurch den Status bereit und mutiert zu einem beglaubigten Zertifikat, sofern die ausstellende Zertifizierungsstelle mit ihrem Zertifikat als »vertrauenswürdig« im Oracle Wallet Manager aufgenommen wurde. Der Distinguished Name, den das Zertifikat beglaubigt hat, erscheint auf der rechten Seite des Wallet-Manager-Fensters unter »Betreff« – in unserem Beispiel CN=Guenter, CN=dbconsult. Die Zertifikate vertrauenswürdiger Zertifizierungsstellen erscheinen 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 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. In gleicher Weise werden Zertifikate für die erforderlichen Datenbanken generiert. Der Distinguished Name der Datenbank kann dabei dem verwendeten Servicenamen entsprechen.
25 Unter Windows2000: c:\Dokumente und Einstellungen\Administrator\ORACLE\WALLETS
Internet Directory, LDAP und SSL
413
Abbildung 9.12: Oracle Wallet Manager mit Benutzerzertifikat
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: SQL> CREATE USER guenter PROFILE default IDENTIFIED GLOBALLY AS 'CN=Guenter, CN=dbconsult' DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp ACCOUNT UNLOCK;
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. Den Anforderungen entsprechende Privilegien sind dem Benutzer danach über geeignete GRANT-Befehle zu erteilen.
414
Sicherheit
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 Anmeldung26 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.
Abbildung 9.13: Oracle Net Manager mit SSL-Konfiguration für den Server
26 Dort unter dem Menüpunkt WALLET
Internet Directory, LDAP und SSL
415
Die Konfiguration wird vom Oracle Net Manager in den Dateien listener.ora und Sqlnet.ora gespeichert. Die nachfolgenden Listen zeigen die relevanten Ausschnitte: # listener.ora Network Configuration File: /app/oracle/product/10gR1/network/admin /listener.ora # Generated by Oracle configuration tools. LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = myServer)(PORT = 1525)) ) (DESCRIPTION = (ADDRESS = (PROTOCOL = TCPS)(HOST = myServer)(PORT = 2484)) ) ) SSL_CLIENT_AUTHENTICATION = FALSE WALLET_LOCATION = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = /app/oracle/admin/test10/wallet) ) Listing 9.6: Ausschnitte aus der Datei listener.ora auf dem Server SQLNET.AUTHENTICATION_SERVICES= (BEQ, TCPS) SSL_VERSION = 0 NAMES.DIRECTORY_PATH= (TNSNAMES) SSL_CLIENT_AUTHENTICATION = TRUE WALLET_LOCATION = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = /app/oracle/admin/test10/wallet) ) ) Listing 9.7: Ausschnitte aus der Datei sqlnet.ora auf dem Server
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 test10ssl:
416
Sicherheit
TEST10SSL = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCPS)(HOST = myServer)(PORT = 2484)) ) (CONNECT_DATA = (SERVICE_NAME = test10.nandadevi.dc) ) ) Listing 9.8: 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 – wie bereits erwähnt –, 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: WALLET_LOCATION = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = C:\oracle\wallets) ) ) SSL_CIPHER_SUITES= (SSL_RSA_EXPORT_WITH_RC4_40_MD5) SSL_SERVER_DN_MATCH = No SSL_CLIENT_AUTHENTICATION = TRUE SSL_VERSION = 3.0 NAMES.DIRECTORY_PATH= (TNSNAMES) Listing 9.9: Ausschnitt aus der Datei sqlnet.ora auf dem Client
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 wurden. Das zeigt das Häkchen bei AUTOMATISCHE ANMELDUNG im Menü des Wallet Managers. 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.
Internet Directory, LDAP und SSL
417
Schließlich kann der Verbindungstest erfolgen: sqlplus /@test10ssl
Die Verbindung sollte nun zu dem globalen Benutzer guenter der Zieldatenbank hergestellt werden, dessen global eindeutiger Name mit dem Distinguished Name des verfügbaren Zertifikats übereinstimmt. Zur Kontrolle lässt sich in der betreffenden Session folgende Abfrage starten: SELECT global_name, user , sys_context('userenv','external_name') external_user FROM global_name; GLOBAL_NAME USER EXTERNAL_USER -------------------- ---------- -----------------------------TEST10.NANDADEVI.DC GUENTER cn=Guenter,cn=Users
9.6.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 Modell 2: Authentifizierung globaler Benutzer beschrieben wurde, aufgebrochen. Enterprise-Benutzer werden im Verzeichnisdienst definiert und korrespondieren mit globalen Benutzern, die ohne Zuordnung eines Distinguished Nam27es in der Datenbank angelegt werden. Die Zuordnung von Enterprise-Benutzern und ihren Identitäten zu den Benutzern vorgegebener Datenbanken erfolgt ausschließlich über einen Verzeichnisdienst. Auf diese Weise lassen sich mehrere Enterprise-Benutzer 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 so genannten 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. Die Authentifizierung der Enterprise-Benutzer kann über Zertifikate oder Passwörter erfolgen. Im letzten Fall werden die Passwörter zentral im Verzeichnisdienst verwaltet, die Benutzer melden sich unter ihrem Enterprise-Namen und Passwort bei einer Zieldatenbank an, diese überprüft die Identität mit Hilfe des Verzeichnisdienstes und verbindet den Betreffenden mit dem für ihn konfigurierten globalen Schema der Datenbank. Auf diese Weise lassen sich Passwörter zentral verwalten. Für dieses Modell sind die folgenden Komponenten notwendig: Funktionsfähiger Verzeichnisdienst/LDAP-Dienst Registrierung der Zieldatenbanken bei dem Verzeichnisdienst Datenbanken mit globalen Benutzern und – möglicherweise – globalen Rollen Konfiguration der Enterprise-Benutzer im Verzeichnisdienst
27 In einer Sonderform kann die Identifizierung auch über Distinguished Names erfolgen. Diese Variante wird hier jedoch nicht beschrieben.
418
Sicherheit
Zur Implementierung dieses Modells sind dementsprechend die folgenden Arbeiten durchzuführen: 1. Grundinstallation des Verzeichnisdienstes mit dem Aufbau des Oracle-Schemas und des Oracle-Kontextes – wie bereits beschrieben. Optional kann ein Identity Management Realm angelegt werden. 2. Konfiguration der Directory-Anbindung und Registrierung der betreffenden Datenbanken bei dem Verzeichnisdienst 3. Anlegen von globalen Benutzern und Rollen in den Zieldatenbanken 4. Anlegen von Enterprise-Benutzern und -Rollen in dem Verzeichnisdienst 5. Zuordnung der Enterprise-Benutzer und -Rollen zu den globalen Rollen der Datenbanken Diese Aufgaben sollen nun – sofern dies nicht schon in vorangehenden Abschnitten geschehen ist – im Detail besprochen werden: Anlegen eines Identity Management Realms Unter einem Identity Management Realm versteht man einen Teil der gesamten DIT-Baumes eines Verzeichnisses, der Identitäten und mit ihnen verbundene Richtlinien administrativ zusammenfasst. Auf diese Weise lassen sich unterschiedliche Benutzerpopulationen und für sie verantwortliche Administratoren konfiguratorisch festlegen. Bereits während der Installation wird standardmäßig das Realm »Default Company« angelegt. Über die SELF-SERVICE-CONSOLE28 von Oracle Internet Directory können jedoch jederzeit neue Realms angelegt oder bestehende modifiziert werden. Diese Konsole bietet einen separaten Arbeitsbereich »Realm Management«, über den die notwendigen Arbeiten ausgeführt werden können. Die Konfiguration eines Realms besteht letzten Endes aus Verzeichnispunkten für Benutzer und Gruppen. Beim Anlegen eines Realms wird unter seinem jeweiligen Wurzelpunkt – in unserem Fall dc=Dcintern, dc=de – ein eigener Oracle Context angelegt, der von Oracle-Produkten und Applikationen für interne Informationen genutzt wird. In unserem Beispiel werden Details des Realms »DCintern« angezeigt. In dem STANDARDVERZEICHNIS genannten Bereich der Self-Service-Konsole – dort unter dem Tab-Reiter KONFIGURATION – lassen sich schließlich das Realm einstellen, mit dem die Konsole arbeiten soll, sowie weitere Einstellungen vornehmen.
28 Diese Konsole kann entweder über die der Enterprise Manager IAS Console – OID – zugehörigen Links erreicht werden oder direkt über die URL http://<servername>:7780/oiddas. Es versteht sich, dass die Portnummer je nach Installation variieren kann.
Internet Directory, LDAP und SSL
419
Abbildung 9.14: Auswahlseite Identity Management Realms
Abbildung 9.15: Details eines ausgewählten Identity Management Realms
Registrierung der Datenbanken Die Registrierung der Datenbanken erfolgt über das Werkzeug Oracle Database Configuration Assistant. Damit dies gelingt, ist vorher über den Net Configuration Assistant unter der Option »Konfiguration von Directory-Verwendung« oder manuell die Datei ldap.ora zu generieren, die auch den Pfad zu dem betreffenden Identity Management Realm oder administrativen Kontext enthält – in unserem Beispiel dc=dbconsult,dc=de. DIRECTORY_SERVERS= (Nandadevi:3060:3130) DEFAULT_ADMIN_CONTEXT = "dc=dbconsult,dc=de" DIRECTORY_SERVER_TYPE = OID Listing 9.10: Datei ldap.ora mit den Einstellungen für den Verzeichnisdienst sowie dem Identity Management Realm für das betreffende Home-Verzeichnis
Nun kann der Configuration Assistant aufgerufen werden. Über die Option DATENBANKOPTIONEN KONFIGURIEREN wird die betreffende Datenbank ausgewählt und im vierten Schritt schließlich die Authentifizierung bei dem Verzeichnisdienst – mit vollem Distinguished Name – vorgenommen sowie das Passwort für das Datenbank-Wallet angegeben.
420
Sicherheit
Abbildung 9.16: Registrierung der Datenbank
Im Einzelnen wird bei der Registrierung Folgendes ausgeführt: Im Verzeichnisdienst wird unter dem in der Datei ldap.ora angegebenen administrativen Kontext und dort unter dem obligatorischen Oracle Context die Datenbank mit dem ihr zugeordneten Unterbaum eingetragen. Die Datenbank mit dem Namen (db_unique_name von v$database) test10 wird demnach im administrativen Kontext dc=dbconsult,dc=de mit dem folgenden Distinguished Name erfasst: cn=test10, cn=OracleContext, dc=dbconsult, dc=de. Der neue Eintrag kann über das Java-Client-Werkzeug Oracle Directory Manager29 oder das Werkzeug Enterprise Security Manager30 verifiziert werden. Innerhalb jedes realm können Enterprise Domains angelegt werden, die der Gruppierung von Datenbanken und Enterprise-Rollen dienen. Bereits beim Anlegen eines realm wird ein Standard Enterprise Domain mit Namen OracleDefaultDomain erzeugt. Diesem Standard-Domain wird die neu registrierte Datenbank zugeschlagen. Der Administrator hat natürlich die Möglichkeit, weitere Domains innerhalb des realm anzulegen und die Datenbank dorthin zu transferieren – Datenbanken müssen immer eindeutig einem Enterprise Domain zugeteilt werden.
29 Aufruf über oidadmin 30 ESM gibt es als Webapplikation und als Java-Client-Programm. Zu Verwaltung der Datenbankeinträge ist leider nur der Java-Client zu gebrauchen. Der Programmstart erfolgt über esm.
Internet Directory, LDAP und SSL
421
Abbildung 9.17: Der Java Client Enterprise Security Manager mit registrierten Datenbanken eines realm
Innerhalb jedes Realms lässt sich der Standard für die Berechtigungsprüfung der registrierten Datenbanken gegenüber dem Verzeichnisdienst festlegen. Der Standard für die Berechtigungsprüfung lautet password, was bedeutet, dass sich registrierte Datenbanken per Default mittels Passwörtern beim Verzeichnisdienst anmelden müssen. Alternativ können sich Datenbanken auch per SSL beim Verzeichnisdienst authentifizieren. Während der Registrierung wird demnach für jede Datenbank auch ein internes Passwort generiert. Dieses Passwort darf nicht verwechselt werden mit dem Passwort, das bei der Registrierung angegeben wird und nur zum Öffnen des Datenbank-Wallets geeignet ist. Das interne Passwort der Datenbank hingegen wird einerseits im Verzeichnisdienst in »gehashter« Form, andererseits im Datenbank-Wallet gespeichert. In Abhängigkeit von der für das betreffende Realm festgelegten Authentifizierungsmethode wird der Systemparameter ldap_directory_access vorbelegt. In unserem Beispiel wurde für das realm dbconsult der Standard belassen. Dementsprechend wird generiert: ldap_directory_access=password
Der Parameter kann dynamisch über den Befehl alter system verändert werden. Ein Neustart der Instanz ist also nicht erforderlich. Der Parameter kann auch sehr sinnvoll verwendet werden, um den Zugriff auf den Verzeichnisdienst – vorübergehend oder dauerhaft – zu unterbinden: alter system set ldap_directory_access=none scope=both;
422
Sicherheit
Abbildung 9.18: Enterprise Security Manager: Festlegen der Berechtigungsprüfung für Datenbanken
Wie bereits erwähnt wurde, wird auch ein Datenbank-Wallet generiert. Dieses Wallet enthält neben dem Passwort der Datenbank auch deren Distinguished Name, wie er im Verzeichnisdienst eingetragen wurde. Das Wallet enthält jedoch kein Zertifikat der Datenbank. Dieses muss – für den Fall, das eine Authentifizierung über SSL gewünscht ist – nachträglich bei einer vertrauenswürdigen CA beantragt und importiert werden. Dieses Verfahren wird hier nicht im Detail beschrieben. Das Wallet wird – unter Unix – im Administrationsverzeichnis der betreffenden Datenbank und dort in dem Unterverzeichnis wallet abgelegt: $ORACLE_BASE/admin/$ORACLE_SID/wallet
Über den Oracle Wallet Manager, der über den Befehl owm aufgerufen wird, lässt sich das generierte Wallet öffnen. Bei der Passwortabfrage ist das Passwort, das im Dialog des Configuration Assistants ausgewählt wurde, anzugeben. Die folgende Abbildung zeigt den Zustand nach der erfolgreichen Registrierung: Das Zertifikat ist leer, und im Bereich Secret Store erscheinen die Abschnitte Distinguished Name (ORACLE.SECURITY.DN) und Password (ORACLE.SECURITY.PASSWORD), die der Wallet Manager nicht im Detail anzeigt. Über das Zeilenkommando mkstore können diese Bereiche auch inhaltlich ausgegeben werden. Es versteht sich, dass hierzu auch das Passwort für das Wallet erfolgreich angegeben werden muss:
Internet Directory, LDAP und SSL
423
Abbildung 9.19: Oracle Wallet Manager mit Datenbank-Wallet nach der erfolgreichen Registrierung mkstore -wrl /app/oracle/admin/test10/wallet -viewEntry ORACLE.SECURITY.DN Kennwort eingeben ORACLE.SECURITY.DN = cn=test10,cn=OracleContext,dc=dbconsult,dc=de oracle@NandaDevi:~> mkstore -wrl /app/oracle/admin/test10/wallet -viewEntry ORACLE.SECURITY.PASSWORD Kennwort eingeben ORACLE.SECURITY.PASSWORD = /X7WRKF8 Listing 9.11: Anzeigen des Secret Store des Wallets über das Kommando mkstore
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: CREATE USER jedermann PROFILE DEFAULT IDENTIFIED GLOBALLY AS '' DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp;
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;
424
Sicherheit
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. Globale Benutzer und globale Rollen sind in allen Zieldatenbanken aufzubauen, die über Enterprise-Benutzer des Verzeichnisdienstes versorgt werden sollen. Enterprise-Benutzer und Enterprise-Rollen Im nächsten Schritt sind nun Enterprise-Benutzer und -Rollen anzulegen und ihnen entsprechende globalen Benutzer und Rollen zuzuweisen. Diese Arbeitsschritte können vollständig über das Java-Client-Werkzeug Enterprise Security Manager ausgeführt werden. Das Anlegen von Benutzern lässt sich alternativ auch über die Webapplikation Enterprise Security Manager erledigen. Diese Anwendung ist Bestandteil der Komponente OC4J_SECURITY der Identity-Management-Infrastruktur des Application-Servers und wird im Rahmen der Delegated Administration Services installiert. Sie kann entweder aus dem Client-Werkzeug heraus – über VORGÄNGE – ESM-KONSOLE STARTEN – oder über folgende URL aufgerufen werden: http://myserver:7780/oiddas/ui/oideushome
Es versteht sich, dass der Servername und ggf. auch die Portnummer den konkreten Testverhältnissen anzupassen sind. Nach erfolgreicher Anmeldung stehen die Service-Seiten zur Verfügung. In der folgenden Abbildung wird der Enterprise-Benutzer johannes mit allen erforderlichen Attributen angelegt. Die Kopfleiste zeigt, dass viele zusätzliche Attribute eingegeben werden können.
Abbildung 9.20: Webanwendung Enterprise Security Manager: Anlegen eines neuen Benutzers
Internet Directory, LDAP und SSL
425
Als eine weitere Alternative zum Anlegen von Benutzern bietet sich die – sehr ähnliche – Webapplikation OID Self-Service-Konsole an. Sie kann aus der Enterprise Manager IAS Control oder direkt über die folgende URL aufgerufen werden: http://myserver:7780/oiddas
Über die Seiten dieser Anwendung können auch Gruppen angelegt und verwaltet werden, welche die Administration von Enterprise-Benutzern vereinfachen. Enterprise-Benutzer lassen sich Gruppen zuordnen und diese wiederum Enterprise-Rollen, was die Arbeit bei einer großen Anzahl von Benutzern erheblich vereinfachen kann. Die folgende Abbildung zeigt die Anwendung mit der ApplikationsgruppeX.
Abbildung 9.21: OID Self-Service-Konsole mit der Gruppenseite
Die weiteren Arbeitsschritte können nur über das oben erwähnte Client-Werkzeug ausgeführt werden. Es empfiehlt sich hierbei das folgende Vorgehen: Datenbankschema-Zuordnung: Hierbei werden Enterprise-Benutzern eines realm globale Benutzer – Shared Schema – von registrierten Datenbanken zugeordnet. Die Zuordnung kann individuell für einzelne Datenbanken oder pauschal für Enterprise-Domänen erfolgen. Im letzteren Fall gilt die Zuweisung für sämtliche Datenbanken, die in der betreffenden Domäne konfiguriert wurden. Zusätzlich lässt sich die Auswahl der Enterprise-Benutzer individuell, d.h. auf Basis eines einzelnen Eintrags, oder für einen ganzen Zweig des Verzeichnisbaumes durchführen. Die Konfigurationsmöglichkeiten sind also recht vielfältig. Die folgende Abbildung zeigt einen Ausschnitt aus dem Client-Werkzeug Enterprise Security Manager. Es wird dort für alle Datenbanken, die in der Domäne OracleDefaultDomain des Realms dbconsult konfiguriert wurden, festgelegt, dass der Enterprise-Benutzer johannes mit dem globalen Benutzer jedermann verbunden wird. Der Benutzer muss natürlich auf allen Datenbanken vorhanden sein. Des Weiteren werden alle Enterprise-Benutzer, die in dem Unterbaum cn=Users, dc=DBintern, dc=de angelegt wurden, mit dem globalen Benutzer gben verbunden.
426
Sicherheit
Abbildung 9.22: Enterprise Security Manager: Zuordnung von globalen Datenbankschemata zu Enterprise-Benutzern
Zuordnung von globalen Rollen zu Enterprise-Rollen: Nach Auswahl der betreffenden Enterprise-Rolle wird über den Tab-Reiter GLOBALE DATENBANKROLLEN über den Knopf HINZUFÜGEN eine Zieldatenbank ausgewählt und nach der Authentifizierung eine Liste gültiger globaler Rollen angezeigt. Hier können eine oder mehrere Rollen ausgewählt und zugeordnet werden, wie die folgende Abbildung zeigt. Die vorgenommenen Änderungen werden erst dann dauerhaft gespeichert, wenn der Knopf ANWENDEN betätigt wurde.
Abbildung 9.23: Enterprise Security Manager: Enterprise-Rollen und globale Rollen
Internet Directory, LDAP und SSL
427
Zuordnung von Enterprise-Rollen zu Enterprise-Benutzern: Nach Auswahl einer Enterprise-Rolle lassen sich über den Tab-Reiter BENUTZER und den Knopf HINZUFÜGEN Enterprise-Benutzer oder Gruppen auswählen, denen die entsprechende Enterprise-Rolle zugeteilt wird. Gruppen wie Benutzer müssen vorher – wie besprochen – angelegt worden sein. Mit diesen Einstellungen wäre die Beispielkonfiguration von Enterprise-Benutzern, die über Passwörter authentifiziert werden, komplett. Ein erster Verbindungsversuch kann wie folgt unternommen werden: sqlplus johannes/testpw@test10
In diesem Beispiel wird zunächst eine Verbindung zur Zieldatenbank über den Aliasnamen test10 hergestellt. Wie dieser Name aufgelöst wird, hängt von der Konfiguration ab: entweder über die Datei tnsnames.ora oder über den Verzeichnisdienst wie in Abschnitt xx besprochen. In der Zieldatenbank wird zunächst eine lokale Authentifizierung versucht. Gelingt diese, d.h., gibt es den lokalen Benutzer johannes und ist das Passwort gültig, wird entsprechend verbunden. In unserem Beispiel existiert jedoch kein Datenbankbenutzer johannes. Aus diesem Grunde wird der Systemparameter ldap_directory_access geprüft, der in unserem Fall die Verbindung zum Verzeichnisdienst über die Passort-Authentifizierung vorsieht. Die Datenbank nimmt daher mit Hilfe der Datei ldap.ora Verbindung über den dort angegebenen SSL-Port zum Verzeichnisdienst auf und authentifiziert sich dort mit Hilfe des Passwortes, das sie aus ihrem Wallet liest. Damit die Verbindung klappt, ist es wichtig, dass über den konfigurierten SSL-Port Verbindungen ohne Berechtigungsprüfung akzeptiert werden. Diese Verbindungen erfordern keine Zertifikate, sondern nutzen lediglich die Möglichkeiten der Verschlüsselung von SSL. Sollte es während des Verbindungsaufbaus zu folgendem Fehler kommen ERROR: ORA-28030: Server ist beim Zugriff auf LDAP-Verzeichnisdienst auf Probleme gestoßen
sind auf jeden Fall die Portnummer und die Instanzen des Verzeichnisdienstes zu überprüfen. Die Prüfung erfolgt über das Java-Client-Werkzeug Oracle Directory Manager. Dort werden unter SERVER-VERWALTUNG und DIRECTORY-SERVER diverse Konfigurationsgruppen aufgelistet. Für die genutzte SSL-Portnummer muss auf jeden Fall für SSL-BERECHTIGUNGSPRÜFUNG KEINE SSL-BERECHTIGUNGSPRÜFUNG ausgewählt worden sein. Dies ist der Fall, wenn die standardmäßigen Voreinstellungen ohne Modifikationen benutzt werden. Alternativ kann die Prüfung auch über die Webapplikation Enterprise Manager IAS Control erfolgen. Dort werden nach Anwahl der Systemkomponente OID die gestarteten Instanzen des Verzeichnisdienstes aufgelistet und mit ihnen auch die für die Instanzen gültigen Konfigurationsgruppen. Nach Auswahl des betreffenden Links werden die Details der betreffenden Gruppe angezeigt, wie die nachfolgende Abbildung verdeutlicht.
428
Sicherheit
Abbildung 9.24: IAS Control: Anzeige der Konfigurationsparameter für Instanzen des Internet Directory Servers
Kann die Verbindung zum Verzeichnisdienst jedoch erfolgreich aufgebaut werden, wird der Benutzer des Connect-Strings – in unserem Beispiel johannes – im angegebenen administrativen Kontext lokalisiert und über das Passwort authentifiziert. Der zugeordnete globale Benutzer wird ermittelt sowie die globalen Rollen, die über die zugeteilten Enterprise-Rollen aktiviert werden müssen. Dementsprechend wird die Verbindung zur Zieldatenbank hergestellt. Nach erfolgreicher Anmeldung kann der Betreffende das ihm zugeteilte Schema sowie sein externe Herkunft wie folgt verifizieren: SQL> SELECT user, sys_context('userenv','external_name') extern FROM dual; USER EXTERN --------------- -------------------------------------------------JEDERMANN cn=johannes,cn=users,dc=dbconsult,dc=de
Die aktivierten Datenbankrollen lassen sich über die View session_roles leicht ermitteln. Schlussbetrachtung Die Authentifizierung von Enterprise-Benutzern über Passwörter und die Nutzung von Enterprise-Rollen bieten gute Möglichkeiten, eine beliebig große Anzahl von Benutzern funktionsgerecht im Kontext von Zieldatenbanken zu authentifizieren und autorisieren. Der laufende Verwaltungsaufwand in diesem Bereich kann mit diesem Modell langfristig deutlich reduziert werden. Für die Anwendungen ist dieses Modell ebenfalls transparent. Durch die Einbindung des Verzeichnisdienstes wird die Grundkonfiguration allerdings zunächst einmal komplex, vor allem dann, wenn die gesamte Infrastruktur in Form des Oracle Identity Managements noch eingerichtet und trainiert werden muss. Die – verwirrende – Anzahl der beteiligten
Internet Directory, LDAP und SSL
429
Werkzeuge – Directory Manager, Net Configuration Assistant, Network Manager, Database Configuration Assistant, Enterprise Security Manager, Wallet Manager sowie diverse Selbstbedienungskonsolen – tragen nicht gerade dazu bei, den Einarbeitungsaufwand zu minimieren. Der DBA muss darüber hinaus, bei der individuellen Prüfung von Benutzern und deren Privilegien, nicht nur die lokalen DatenbankViews, sondern ebenso die Anzeigen des Enterprise Security Managers berücksichtigen! Trotz alledem bieten Verzeichnisdienste für Oracle-Datenbanken sehr elegante Möglichkeiten der zentralisierten Benutzer- und Privilegienverwaltung. Für den Fall, dass neben der zentralisierten Benutzerverwaltung auch noch die Zertifizierung von Clients und Servern sowie die Verschlüsselung des Datenverkehrs gefordert wird, können Enterprise-Benutzer auch im Kontext von SSL konfiguriert werden. Bei diesem Modell sind für alle Beteiligten, d.h. Endbenutzer und Datenbanken, gültige Zertifikate zu installieren. Dieses Modell wird hier jedoch aus Platzgründen nicht besprochen31.
9.6.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 kommt 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
31 Details zur Konfiguration finden sich in Avanced Security Administrator´s Guide der Oracle-Dokumentation.
430
9.7
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, wie in den vorangehenden Abschnitten beschrieben erfolgen.
9.7.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 den privilegierten SQL-Befehlen überein. Die Liste der Systemprivilegien ist sehr umfangreich. Sie enthält mittlerweile über 100 unterschiedliche Privilegien. Das hat zur Folge, dass die Datenbankrechte jedes einzelnen Benutzers exakt an seine Aufgaben angepasst werden können. In Abschnitt Rollen 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 eine Auswahl der wichtigsten Systemprivilegien, gruppiert nach Bereichen oder Objekttypen, die sie betreffen. Eine vollständige Liste findet sich in der Oracle Dokumentation SQL Reference und dort im Kontext des grant-Befehls. Unter den Privilegien finden sich auch einige any-Typen, wie z.B. drop any table. Die Wirkung dieser Privilegien hängt von dem Systemparameter o7_dictionary_accessibility ab. Der Standardwert false macht das jeweilige Privileg ungültig für das SYS-Schema. In unserem Beispiel können Tabellen also in allen Schemata mit Ausnahmen von SYS gelöscht werden. Bei Einstellung auf true gilt diese Einschränkung nicht! 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 FULL-Imports benötigt)
ALTER USER
Verändern von Benutzerparametern anderer Benutzer (für eigenes Passwort nicht notwendig)
Benutzer
Tabelle 9.3: Übersicht Systemprivilegien
Privilegien und Rollen
431
Bereich
Privileg
Berechtigung zu ...
DROP USER
Benutzer entfernen
Cluster
CREATE CLUSTER
Cluster im eigenen Schema anlegen
CREATE ANY CLUSTER
Cluster in beliebigem Schema anlegen
ALTER ANY CLUSTER
beliebige Cluster verändern
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
CREATE ANY CONTEXT
Namensbereich für Kontexte anlegen
Context DatenbankLinks
Dimensionen
Directories Indextypen
Indizes
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
Tabelle 9.3: Übersicht Systemprivilegien (Forts.)
432
Sicherheit
Bereich
Privileg
Berechtigung zu ...
Anwendung
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 Schemata 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 in eigenem Schema löschen
DROP ANY LIBRARY
Bibliothek in beliebigem Schema löschen
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)
Libraries
Materialisierte Views
Operatoren
Outlines
Privilegien
Tabelle 9.3: Übersicht Systemprivilegien (Forts.)
Privilegien und Rollen
433
Bereich
Privileg
Berechtigung zu ...
Prozeduren
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
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
Profile
Rollen
RollbackSegmente
Sessions
Sequenzen
Synonyme
Tabelle 9.3: Übersicht Systemprivilegien (Forts.)
434
Bereich
Tabellen
Tablespaces
Transaktionen
Trigger
Sicherheit
Privileg
Berechtigung zu ...
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
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)
Tabelle 9.3: Übersicht Systemprivilegien (Forts.)
Privilegien und Rollen
435
Bereich
Privileg
Berechtigung zu ...
Objekttypen
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 Schemata
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
UNDER ANY VIEW
Für Objekt-Views: 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- Privilegien, 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.
Views
Administration
Tabelle 9.3: Übersicht Systemprivilegien (Forts.)
Jeder Benutzer, der sich an die Datenbank anmeldet, muss das Privileg CREATE SESSION besitzen. Der Entzug dieses Privilegs 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 Schemata 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 Schemata 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
436
Sicherheit
Benutzer kann somit ein Skript 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 mit der Klausel 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. GRANT CREATE SESSION TO guenter, johannes, dierk; GRANT CREATE TABLE, CREATE VIEW TO patrick 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.
9.7.2
Objektprivilegien
Während die Systemprivilegien die erlaubten Kommandos und Aktionen eines Benutzers festlegen, 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 Software-Lö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.
Privilegien und Rollen
437
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. 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 patrick WITH GRANT OPTION; INSERT (empno, ename, deptno, mgr, hiredate) ON emp TO dierk; ALL ON dept TO PUBLIC; EXECUTE ON hire_employee TO dierk, johannes, 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, also die Klausel WITH ADMIN OPTION. Objektprivilegien, die einer Rolle oder einem Benutzer zugewiesen wurden, können über die View dba_tab_privs abgefragt werden.
438
9.7.3
Sicherheit
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 Skripte realisiert werden. Diese wiederum 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: Rolle
Privileg
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 Dictionarys
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 Managers
RECOVERY_CATALOG_OWNER
Privilegien für den Eigentümer des Recovery-Katalogs (Recovery Manager)
Tabelle 9.4: Vordefinierte Rollen
Privilegien und Rollen
439
Rolle
Privileg
HS_ADMIN_ROLE
Privilegien für Heterogeneous Services
LOG_STDBY_ADMINISTRATOR
Zur Administration von Logical Standby Databases
SCHEDULER_ADMIN
Alle Privilegien zum Administrieren des Job Schedulers
OEM_MONITOR
Privilegien zum Monitoring der Datenbank über den Enterprise Manager
LBAC_DBA
Rolle zum Administrieren der Label Security
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 9.4: Vordefinierte Rollen (Forts.)
Beim GRANT der Rollen RESOURCE und DBA wird gleichzeitig das Systemprivileg UNLIMITED TABLESPACE, bei der Rolle DBA mit der Klausel WITH ADMIN OPTION zugewiesen. Diese Zuweisung erfolgt nicht als Bestandteil der Rolle, sondern als direktes Systemprivileg. In den meisten Fällen empfiehlt es sich, dies nicht bestehen zu lassen, sondern mit expliziten Quoten für einzelne Tablespaces zu arbeiten.32 Beim Aufsetzen eines Datenbanksystems erweisen sich die Rollen CONNECT, RESOURCE und DBA als praktisch, da man sofort ohne eigenes Sicherheitskonzept Benutzer privilegieren 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 RESOURCE-Privilegien 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; 32 Das UNLIMITED TABLESPACE-Privileg wird aus Kompatibilitätsgründen zu Oracle Version 6 zugewiesen.
440
Sicherheit
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. 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.
Privilegien und Rollen
441
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;
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 vorenthalten bleiben. Es versteht sich, dass die im Anwendungscode hart codierten Passwörter ein ernst zu nehmendes Risiko für die Wartung und die Sicherheit darstellen. 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. Zusätzlich ist zu bemerken, dass die Übermittlung der Passwörter zur Aktivierung der Rollen nicht verschlüsselt wird, wie dies beispielsweise mit Passwörtern beim Anmelden an die Datenbank geschieht. Aus diesem Grunde sind Passwörter im Kontext von Rollen nur dann übertragungstechnisch sicher, wenn die Datenpakete für die Netzübertragung entsprechend verschlüsselt werden. Secure Application Roles Eine wesentlich elegantere Methode, Rollen in spezifischen, für den Benutzer nicht nachvollziehbaren oder nicht kontrollierbaren Kontexten sicher zu aktivieren, stellen die so genannten Secure Application Roles dar. Diese Rollen werden so angelegt, dass eine namentlich genannte PL/SQL-Programmeinheit für ihre Aktivierung verantwortlich zeichnet. Innerhalb dieser Prozedur lassen sich dann sinnvolle Plausibilitäten einbauen, bevor die genannte Rolle aktiviert wird. Es versteht sich, dass die genannte Programmeinheit weder im Schema des Begünstigten liegen noch der Betreffende Ausführungsrechte für diese Programmeinheit haben sollte. Gleichfalls sollte die Rolle nicht als Default-Rolle an die Begünstigten vergeben werden. In der Regel wird ein separates Schema – beispielsweise ein Applikationsbenutzer – geschaffen, in dessen Kontext die entsprechende Programmeinheit angelegt wird. Im folgenden Beispiel wird die Rolle demo_enduser angelegt, die über die Programmeinheit app des Schemas appuser aktiviert werden soll. Für das Anlegen der Rolle ist es nicht notwendig, dass die Programmeinheit und der Benutzer bereits existieren: CREATE ROLE demo_enduser IDENTIFIED USING appuser.app;
Existierende Application Roles können über die View dba_application_roles selektiert werden. Zur Aktivierung der neuen Rolle ist nun im Schema appuser die Prozedur – oder das Paket – app anzulegen. Die Aktivierung erfolgt dann letztendlich über den Aufruf
442
Sicherheit
der set_role-Prozedur des Paketes DBMS_SESSION. Damit dies gelingt, muss die Prozedur app als Invokers-Right-Code deklariert worden sein. Gleichzeitig stehen alle möglichen Mechanismen zur Verfügung, vor der Aktivierung diverse Plausibilitätsprüfungen durchzuführen. Darüber hinaus kann die Prozedur auch »gewrapped« werden, um die Logik der Plausibilitätsprüfungen zu verschleiern. Schließlich sollte der Applikationsbenutzer – in unserem Beispiel appuser – durch starke Authentifizierungsmaßnahmen zusätzlich vor Missbrauch geschützt werden. Das folgende Codebeispiel zeigt Fragmente einer möglichen Aktivierungsprozedur: CREATE OR REPLACE PROCEDURE app (user_in IN VARCHAR2) AUTHID CURRENT_USER IS -- hier z.B. IP-Adresse des Application Servers, der sich einwählt lv_valid_ip CONSTANT VARCHAR2 (50) := '192.168.25.113'; -- Hostname des App-Server Rechners lv_valid_host CONSTANT VARCHAR2 (50) := 'myserver'; -- Externer Name bei einer Authentifizierung über Enterprise-Benutzer lv_valid_external CONSTANT VARCHAR2 (50) := 'cn=guenter,cn=users,dc=dbconsult,dc=de'; BEGIN -- .. je mehr kombiniert wird, desto sicherer IF SYS_CONTEXT ('userenv', 'ip_address') = lv_valid_ip AND SYS_CONTEXT ('userenv', 'host') = lv_valid_host AND SYS_CONTEXT ('userenv', 'external_name') = lv_valid_external THEN -- Rolle aktivieren DBMS_SESSION.set_role ('DEMO_ENDUSER'); -- Client-Identifier für authentifizierten Benutzer DBMS_SESSION.set_identifier (user_in); -- ... und Schema auf den Owner schalten spart Synonyme EXECUTE IMMEDIATE ('alter session set current_schema = APP_OWNER'); -- ggf. weitere Einstellungen: Client-Identifier/Client Info etc. END IF; EXCEPTION WHEN OTHERS THEN -- hier entsprechende Routinen RAISE; END app; / Listing 9.12: Fragment einer Programmeinheit zur Aktivierung von Secure Application Roles
Um die Logik der oben dargestellten Prozedur weitergehend zu schützen, bietet es sich an, den Code zu »wrappen«. In der Version 10g wurde dieses Feature dahingehend verbessert, dass nun sämtliche Zeichenketten in unleserlicher Form auftauchen und damit Rückschlüsse auf den Programmablauf nicht mehr möglich sind. Um die Prozedur app zu »wrappen«, wird im ersten Schritt der Code in eine Datei geschrieben – in unserem Beispiel die Datei app.sql. Auf der Kommandozeile kann dann das Hilfsprogramm wrap in folgender Form aufgerufen werden:
Privilegien und Rollen
443
wrap iname=app.sql PL/SQL Wrapper: Release 10.1.0.4.0- Production on Mon Aug 22 10:53:32 2005 Copyright (c) 1993, 2004, Oracle.
All rights reserved.
Processing app.sql to app.plb Listing 9.13: Wrap der Prozedur app
Die neue Datei app.plb enthält den »gewrappten« Code. Ein Blick auf den Inhalt zeigt keinerlei interpretierbare Zeichenketten, wie der folgende Ausschnitt aus der Datei app.plb zeigt: abcd 7 31d 223 abmdzXjvd7hFJQbws1ew0M8o9rQwg/DxzPYVfI4C/mgPUprlymWkSnkGhDxxF2fr8Rr8Qebq ahsRpHmNzZq7yU1Z31JrqHkpOrmtxHjMUkZ6XOdWoQ73J8MrWg72l8Mh4OUFdFQnYKyEicUC JVS1Lsr1pqY/0LCfl9SsuvfdOOktd0Chx0ZnjL9VRgf7RpD4SJjHErG5M4OQ/y60tQKIlYNx Listing 9.14: »Gewrappter« Code der Prozedur app
Zum Vergleich ein kurzes Fragment derselben Prozedur, »gewrapped« unter Version 9i. Deutlich sind hier sämtliche Konstanten sowie Teile der Programmlogik zu erkennen! 1APP: 1USER_IN: 1VARCHAR2: 1AUTHID: 1CURRENT_USER: 1LV_VALID_IP: 1CONSTANT: 150: 1192.168.25.113: 1LV_VALID_HOST: 1myserver: 1LV_VALID_EXTERNAL: 1cn=guenter,cn=users,dc=dbconsult,dc=de: 1SYS_CONTEXT: 1userenv: 1ip_address: 1=: 1host: 1external_name: 1DBMS_SESSION: 1SET_ROLE: 1DEMO_ENDUSER: 1SET_IDENTIFIER: 1EXECUTE: 1IMMEDIATE: 1alter session set current_schema = APP_OWNER: Listing 9.15: Prozedur app, „gewrapped“ unter Version 9i
444
Sicherheit
Globale Rollen Globale Rollen wurden bereits in Abschnitt Modell 3: Enterprise-Benutzer und Enterprise-Rollen im Zusammenhang mit Enterprise-Rollen erwähnt. Sie sind bekanntlich die in den Zieldatenbanken verankerten Gegenspieler der Enterprise Rollen. Globale Rollen werden über die Klausel IDENTIFIED GLOBALLY wie folgt angelegt: CREATE ROLE grole_demo IDENTIFIED GLOBALLY;
Existierende globale Rollen lassen sich über die View dba_roles ermitteln: SELECT ROLE FROM dba_roles WHERE password_required = 'GLOBAL';
Objekt- und Systemprivilegien oder normale Rollen werden globalen Rollen wie gewohnt über grant-Befehle zugeteilt bzw. über revoke wieder entzogen. Im Gegensatz zu normalen Rollen lassen sich globale Rollen selbst jedoch nicht an Benutzer oder andere Rollen granten: SQL>GRANT grole_demo TO scott; grant grole_demo to scott * FEHLER in Zeile 1: ORA-28021: Globale Rollen koennen nicht erteilt werden Listing 9.16: Fehler beim Zuteilen globaler Rollen
Die Nutzung globaler Rollen kann demnach nur im Kontext von Enterprise-Rollen des Verzeichnisdienstes erfolgen. Externe Rollen Externe Rollen werden – ähnlich wie globale Rollen – über externe Instanzen den Benutzern zugeteilt. Die externe Instanz ist bei externen Rollen jedoch nicht der Verzeichnisdienst, sondern das Betriebssystem oder die DCE33-Umgebung. Im folgenden Beispiel wird die externe Rolle ext_role angelegt: CREATE ROLE ext_role IDENTIFIED EXTERNALLY;
Existierende externe Rollen lassen sich über die View dba_roles selektieren: SELECT ROLE FROM dba_roles WHERE password_required = 'EXTERNAL';
Externe Rollen können zwar Benutzern oder anderen Rollen zugeteilt werden, sind aber nur dann wirksam, wenn der Betreffende die Rolle als Default-Rolle zugeteilt bekommen hat. Das explizite Aktivieren dieser Rollen über den set role-Befehl produziert hingegen die folgende Fehlermeldung:
33 DCE = Distributed Computing Environment, eine Middleware zwischen verteilten Applikationen und dem Betriebssystem, die diverse Netzwerkdienste, u.a. auch Sicherheitsdienste, bereitstellt
Privilegien und Rollen
445
SQL> set role ext_role; set role ext_role * FEHLER in Zeile 1: ORA-01989: Rolle 'EXT_ROLE' ist nicht vom Betriebssystem autorisiert Listing 9.17: Aktivierung externer Rollen
Externe Rollen werden in der Regel dort eingesetzt, wo die Rollenzuteilung einzig und allein über das Betriebssystem geregelt wird und keine Rollen-Grants im Kontext von Datenbankbenutzern durchgeführt werden. Auf diese Weise kann ein Betriebssystembenutzer immer mit den gleichen externen Rollen arbeiten, unabhängig davon, unter welchem Datenbankbenutzer es sich anmeldet. 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 der Datenbank auf das Betriebssystem über, die Zuweisungen innerhalb der Datenbank haben keinerlei Bedeutung mehr.34 Eine Alternative stellt die in Abschnitt Modell 3: Enterprise-Benutzer und Enterprise-Rollen beschriebene Zuweisung von Rollen über Verzeichnisdienste dar. Die Verwaltung und Zuteilung von Rollen wird im Falle der Verwaltung über das Betriebssystem über 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 OPTIONzur Verfügung. 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.
34 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.
446
Sicherheit
Empfehlungen für die Nutzung von Rollen 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, da jede aktive Rolle einige Bytes in der so genannten Program Global Area benötigt. Die Forderung wird andererseits dadurch begründet, dass der Sicherheitsscheck in der Parse-Phase von SQL-Befehlen länger dauert, je mehr Rollen aktiviert sind. Es lässt sich eine systemweite Grenze aktivieren, welche die Anzahl der gleichzeitig aktiven Rollen pro Sitzung einschränkt, wobei die Unterrollen in einer Hierarchie mitzählen. Die Grenze wird vom Initialisierungsparameter max_enabled_roles vorgegeben, dessen Standardwert in der Version 10g 150 beträgt. Der Parameter wird in Version 10g allerdings nur noch aus Gründer der Abwärtskompatibilität unterstützt. Beim Anlegen von Rollen ist zu beachten, dass der anlegende Benutzer die neue Rolle automatisch mit Administratorrechten und als Default-Rolle zugeteilt bekommt. Dies führte unter der Version 935 häufig dazu, dass Rollen anlegende Benutzer sehr schnell an die durch max_enabled_roles vorgegebene Grenze stießen und eine Anmeldung nicht mehr möglich war. Hier hilft es, die Default-Rollen dieser Benutzer auf die für ihre Funktionen notwendigen einzuschränken. Ganz allgemein sollte darüber hinaus gelten: Benutzer erhalten nur die Rollen als DefaultRollen zugeteilt, die ihnen Rechte zuteilen, die für sie in allen möglichen Umgebungen automatisch gelten sollten. Rechte, die nur in speziellen Anwendungen zur Geltung kommen dürfen, werden stets über Rollen erteilt, die explizit – über Passwörter oder externe Komponenten – zu aktivieren sind. Auf diese Weise kann der Betreffende die anhängenden Rechte nicht – ohne nur schwer – in »offenen« Umgebungen, wie z.B. SQL*Plus, nutzen. Default-Rollen können über den alter user-Befehl eingestellt werden. Im folgenden Beispiel wird für den Benutzer scott nur die connect-Rolle als Default konfiguriert: ALTER USER scott DEFAULT ROLE connect;
Über die View dba_role_privs ist die Kontrolle über die Rollen möglich, die dem Betreffenden direkt zugeteilt wurden. Jedoch ist hier Vorsicht geboten: Alle Rollen, die über die direkt zugeteilten Rollen für den Betreffenden aktiv sind, erschienen bei dieser Abfrage nicht! SELECT granted_role, default_role FROM dba_role_privs WHERE grantee = 'SCOTT'; Listing 9.18: Ermittlung direkt zugeteilter Rollen
35 Unter der Version 9 war der Parameter mit dem Wert 20 vorbelegt, der Maximalwert betrug 148.
Privilegien und Rollen
447
Für die Gestaltung von 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 unterschiedlicher Anwendungsbereiche enthalten. In der Ebene darüber können dann Anwendungsprofile für verschiedene Benutzertypen erstellt werden, die aus den Rollen für einzelne Anwendungsbereiche zusammengesetzt sind. Rollen für Administratoren In der Standardrolle DBA sind alle Systemprivilegien mit 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;
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. Auf diese Weise lassen sich auch andere Verwaltungsbereiche über Rollen definieren, wie etwas ein Security-Administrator.
448
Sicherheit
9.8
Virtual Private Database
9.8.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 sowohl unter Oracle9i und als auch unter 10g funktional erweitert. VPD steht im Rahmen der Enterprise Edition von Oracle 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: Um die für die Generierung der where-Klausel wichtigen, individuellen Parameter – wie z.B. die Abteilungsnummer oder den Einsatzort – zu speichern, kann ein spezifischer Anwendungskontext (Application Context) aufgebaut werden. Dieser Anwendungskontext muss innerhalb der Datenbank einen eindeutigen Namen haben und kann mit beliebigen Attributen und ihnen zugeordneten Werten belegt werden. Beim Anlegen des Kontextes wird gleichzeitig eine Programmeinheit definiert, die autorisiert ist, die Attribute und Attributwerte des betreffenden Kontextes zu definieren. Zusätzlich werden Funktionen benötigt, welche die Where-Klauseln für Tabellen, Views oder Synonyme generieren. Hierzu können die Funktionen die genannten Attributwerte eines Applikationskontextes nutzen. Damit VPD wirksam wird, benötigen wir darüber hinaus Richtlinien (Policies36), welche die zu schützenden Tabellen, Views oder Synonyme mit den erwähnten Funktionen verbinden. Diese Richtlinien lassen sich darüber hinaus explizit mit bestimmten DML-Operationen – z.B. SELECT oder DELETE – verknüpfen. VPD sorgt letzten Endes dafür, dass der originale SQL-Befehl im Rahmen der zutreffenden Richtlinie durch die generierte Where-Klausel erweitert und der Zugriff entsprechend gefiltert wird. VPD kann in diesem Sinne auch salopp als Automatische Where-Klausel-Generierung beschrieben werden. Die beschriebene Generierung der Where-Klauseln ist natürlich auch ohne Applikationskontexte möglich. Gleichwohl stellen diese eine eleganten und performante Möglichkeit dar, individuelle Attributwerte im Rahmen einer Session zu propagieren. Die Möglichkeiten, Applikationskontexte zu setzen, wurden in den letzten Versionen beträchtlich erweitert. Mittlerweile lassen sich zwei grundlegende Typen von Kontexten unterscheiden: Lokale Kontexte gelten jeweils im Rahmen einer Session und werden damit – umgekehrt formuliert – für jede Session neu initialisiert. Lokale Kontexte werden im Kontext der UGS gespeichert. Sie sind vor allem dort interessant, wo individuelle Benutzer mit jeweils eigenen Sessions arbeiten. Für die Initialisierung der Werte stehen – neben den erwähnten PL/SQL-Programmeinheiten – die folgenden alternativen Methoden zur Verfügung: 36 Die offizielle Übersetzung von Policy in den Oracle-Tools lautet »Strategie«.
Virtual Private Database
449
Die globale Initialisierung nutzt LDAP und einen Verzeichnisdienst, um Attributwerte, die im Kontext von Enterprise-Benutzern angelegt wurden, beim Connect des betreffenden Benutzers zu aktivieren. Die externe Initialisierung kann Attribute über die OCI-Schnittstelle setzen. Globale Kontexte werden im Kontext der SGA gespeichert und können dementsprechend von unterschiedlichen Sessions aus immer wieder genutzt werden. Sie sind vor allem dort interessant, wo eine große Anzahl von Endbenutzern sich über Application-Server mit einem zentralen Datenbankbenutzer verbinden. In diesem Modell werden die Sessions des zentralen Benutzers vom Appliction-Server wechselweise für unterschiedliche Endbenutzer aktiviert. Globale Applikationskontexte erlauben es dann, individuelle Attributwerte an Client-Identifier zu koppeln. Wenn der Application-Server bei Datenbankanforderungen die aktuelle Kennung des jeweiligen Endbenutzers in Form eines Client-Identifiers aktiviert37, werden die für diese Kennung relevanten Attributwerte bereitgestellt, ohne dass der gesamte Kontext jedes Mal initialisiert werden muss. Globale Kontexte dürfen nicht mit der oben besprochenen globalen Initialisierung lokaler Kontexte verwechselt werden. Da unter Oracle8i 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. Aus diesem Grund wurden die Konzepte von Richtlinien seither deutlich ausgeweitet. Richtlinien für Objekte können mittlerweile über Richtliniengruppen (Policy Groups) gruppiert werden. Für jedes Objekt, definiert über seinen Schema- und Objektnamen, können beliebig viele Richtliniengruppen mit eindeutigen Namen angelegt werden. Für unterschiedliche Objekte können demnach durchaus gleichnamige Richtliniengruppen existieren. Richtlinien für einzelne Objekte können dann im Kontext dieser Gruppen aufgebaut werden. Richtlinien, die nicht explizit einer Gruppe zugeteilt wurden, werden der Standardgruppe SYS_DEFAULT untergeordnet und sind dem entsprechend stets aktiv. Für alle anderen Richtliniengruppen lässt sich jeweils ein »treibender« Kontext (Driving Application Context) definieren, über den die Richtlinien der betreffenden Gruppe aktiviert werden können. Auf diese Weise lassen sich für ein Datenbankobjekt unterschiedliche Sicherheitsrichtlinien definieren, die – abhängig von der zugreifenden Applikation – eingeschaltet werden können. Richtliniengruppen, deren treibender Kontext nicht festgelegt wurde, sind mit ihren Richtlinien stets aktiv. Unter der Version 10g wurde die Funktionalität von VPD nochmals erweitert. Nun ist es möglich, die VPD-Richtlinien in Abhängigkeit von Spalten zu definieren. Auf diese Weise wird die Richtlinie erst wirksam, wenn eine definierte Spalte selektiert wird, oder sie sorgt dafür, dass die Werte der betreffenden Spalte nur im vorgegebenen Kontext angezeigt und ansonsten mit null-Werten ausgegeben werden (Column Masking).
37 Dies geschieht über das Paket DBMS_SESSION.
450
9.8.2
Sicherheit
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: Gegeben sind die Tabellen auftraege und mitarbeiter im Schema scott. Beide Tabellen werden von Mitarbeitern unterschiedlicher Firmen – hier FA und FB – genutzt. Jede Firma nutzt jeweils zwei unterschiedliche Anwendungen: eine Serviceanwendung (SE) für Reklamationen und eine Verkaufsanwendung (VE) für Abverkäufe. Jede Firma soll jedoch nur ihre eigenen Daten sehen. Darüber hinaus soll auch jede Anwendung nur die für sie relevanten Daten lesen und bearbeiten und dies auch in Abhängigkeit von dem angemeldeten Benutzer. Für Zugriffe auf die Tabelle auftraege gilt im Einzelnen: Jeder Benutzer sieht nur die Daten seiner Firma. Zusätzlich gilt: Jede Anwendung sieht und bearbeitet nur die in ihrem Kontext anfallenden Aufträge. Ferner gilt: Für den Verkauf sollen Manager alle Aufträge bearbeiten dürfen, die von ihnen selbst oder von Mitarbeitern ihrer Abteilung aufgenommen wurden. Die einfachen Mitarbeiter dagegen haben nur Zugriff auf ihre eigenen Aufträge. Diese Unterscheidung gilt nicht für den Service. Dort können alle Benutzer alle Serviceaufträge lesen, die ihnen im Rahmen der ersten beiden Bedingungen zugänglich sind. Für Zugriffe auf die Tabelle mitarbeiter gilt im Einzelnen: Alle Mitarbeiter haben lesenden Zugriff auf sämtliche Mitarbeiter ihrer Firma – mit Ausnahme der Spalte gehalt. Die Spalte gehalt steht lesend und schreibend nur Managern zur Verfügung und auch ihnen nur im Kontext ihrer eigenen Abteilung. Für normale Mitarbeiter werden beim Lesen dieser Spalte nur die eigenen Daten angezeigt. Darüber hinaus sollen die folgenden allgemeinen Rahmenbedingungen für unsere Testumgebung gelten: Die Authentifizierung der Benutzer erfolgt in der Datenbank über individuelle Datenbankbenutzer, die benannt sind nach der eindeutigen Personalnummer der betreffenden Person.
Virtual Private Database
451
Feinkonzept Aus den oben genannten Anforderungen lässt sich das folgende technische Implementierungskonzept ableiten: Die für VPD notwendigen Programmeinheiten sollen im Schema scott_sec angelegt werden. Da wir mit individuellen Datenbank-Sessions arbeiten, nutzen wir einen lokalen Anwendungskontext. Er soll unter dem Namen scott_con angelegt werden und über das Paket sec_init im Schema scott_sec befüllt werden. Das Attribut mit Name app soll innerhalb dieses Kontextes den Namen der Anwendung, das Attribut pos die Position des Mitarbeiters, das Attribut fir die Firma und abt die Abteilung speichern. Der Kontext scott_con soll über einen Logon-Trigger für die einzelnen Benutzer befüllt werden. VPD-Implementierung Die Benutzer scott und scott_sec werden wie gewohnt angelegt. Scott wird über die Rollen connect und resource privilegiert. Für das Anlegen der Objekte von scott_sec ergeben sich zwei unterschiedliche Möglichkeiten: Die Objekte werden von einem hochprivilegierten Benutzer – zum Beispiel system – für scott_sec angelegt. Scott_sec benötigt in diesem Fall keine expliziten Systemprivilegien. Die notwendigen Objektprivilegien sind identisch mit denen, die im folgenden Abschnitt genannt werden. Scott_sec legt die notwendigen Objekte direkt an und benötigt in diesem Fall folgende Systemprivilegien: create session, create procedure, create any context, exempt access policy. Darüber hinaus sind folgende Objektprivilegien notwendig: select auf die Tabelle mitarbeiter von scott, execute für das Paket dbms_rls von sys. Die Testtabellen werden nun im Schema scott angelegt. Das Beispiel zeigt den rudimentären Code, in der Praxis würden ggf. zusätzliche Trigger und Constraints benötigt: CREATE TABLE scott.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 kontext VARCHAR2(2) NOT NULL, -- Kuerzel der Anwendung firma VARCHAR2(20) NOT NULL, -- Name der anlegenden Firma CONSTRAINT auf_pk PRIMARY KEY(a_nr), CONSTRAINT kont_chk CHECK (kontext IN ('SE','VE')) -- SErvice und VErkauf ); Listing 9.19: Anlegen der Tabelle auftraege
452
Sicherheit
Beim Anlegen eines Auftrages sorgen Trigger für das Befüllen der Personal- und Abteilungsnummer des bearbeitenden Mitarbeiters. Alle Endbenutzer bekommen die für sie nötigen Grundprivilegien – select, insert, update oder delete – für diese Tabelle über entsprechende Rollen. Die Tabelle mitarbeiter wird wie folgt angelegt: CREATE TABLE scott.mitarbeiter( m_mitarb VARCHAR2(10) NOT NULL, -- Personalnr des Mitarbeiters m_abt VARCHAR2(10) NOT NULL, -- Abteilung m_vorname VARCHAR2(50), m_nachname VARCHAR2(100), m_position VARCHAR2(100), m_gehalt NUMBER(6), firma VARCHAR2(20), CONSTRAINT mit_pk PRIMARY KEY(m_mitarb)); Listing 9.20: Anlegen der Tabelle mitarbeiter
Für die Tabelle wird ein direktes select-Privileg an den Benutzer scott_sec vergeben, damit dieser die Daten beim Initialisieren des Applikationskontextes lesen kann. Im nächsten Schritt kann nun der geplante Applikationskontext angelegt werden: CREATE CONTEXT
scott_con USING scott_sec.sec_init;
Listing 9.21: Anlegen eines Applikationskontextes
Beim Anlegen des Kontexts ist es nicht erforderlich, dass die angegebenen Programmeinheit – hier sec_init – bereits existiert. Sie kann nachträglich wie folgt aufgebaut werden: CREATE OR REPLACE PACKAGE scott_sec.sec_init AS lc_service CONSTANT VARCHAR2 (2) := lc_verkauf CONSTANT VARCHAR2 (2) := lc_manager CONSTANT VARCHAR2 (50) := lc_verkaeufer CONSTANT VARCHAR2 (50) :=
'SE'; 'VE'; 'Manager'; 'Verkäufer';
PROCEDURE init (user_in VARCHAR2, application_in VARCHAR2); END; / CREATE OR REPLACE PACKAGE BODY scott_sec.sec_init IS PROCEDURE init (user_in VARCHAR2, application_in VARCHAR2) IS lv_position scott.mitarbeiter.m_position%TYPE; lv_abt scott.mitarbeiter.m_abt%TYPE; lv_firma scott.mitarbeiter.firma%TYPE; BEGIN -- Userdaten ermitteln ACHTUNG: ohne VPD SELECT m.m_position, m.m_abt, m.firma INTO lv_position, lv_abt, lv_firma FROM scott.mitarbeiter m WHERE m.m_mitarb = user_in;
Virtual Private Database
453
-- VOR dem Setzen des Kontexts noch Plausis einbauen! -- Attributwerte für Position, Abteilung und Firma setzen DBMS_SESSION.set_context ('SCOTT_CON', 'POS', lv_position); DBMS_SESSION.set_context ('SCOTT_CON', 'ABT', lv_abt); DBMS_SESSION.set_context ('SCOTT_CON', 'FIR', lv_firma); DBMS_SESSION.set_context ('SCOTT_CON', 'APP', application_in); --- hier noch entsprechendes Exception-Handling hinzufügen EXCEPTION WHEN OTHERS THEN raise_application_error (-20001, SQLERRM (SQLCODE)); END init; -END; / Listing 9.22: Anlegen des Security-Paketes
Da die Tabelle mitarbeiter des Schemas scott, die im Rumpf dieses Paketes gelesen wird, selbst auch über VPD geschützt wird, ist es für eine fehlerfreie Funktion dieses Paketes unbedingt erforderlich, dem Benutzer sec_init das Systemprivileg exempt access policy zu geben. Ansonsten würde er nur einen Ausschnitt von mitarbeiter sehen und möglicherweise keine korrekte Initialisierung des Kontextes vornehmen können. Darüber hinaus versteht es sich, dass vor dem Setzen der Kontextattribute geeignete Prüfungen durchgeführt werden – z.B. Maschinen- oder Programmnamen oder IP-Adressen mit Hilfe des sys_context-Funktion. Nun werden die Funktionen angelegt, die für die Generierung der where-Klauseln zuständig sind. Um eine bessere Übersicht zu haben, unerwünschte Nebeneffekte auszuschließen und eine bessere Kombinierbarkeit zu erreichen, ist es empfehlenswert, pro Funktion immer nur ein Prädikat zu generieren. Dadurch, dass für jedes Objekt mehrere Policies definiert werden können, lassen sich Funktionen den Anforderungen entsprechend kombinieren. CREATE OR REPLACE FUNCTION scott_sec.aw_basic_function ( owner VARCHAR2, objname VARCHAR2 ) RETURN VARCHAR2 IS BEGIN -- Filtern nach Firma RETURN ' firma = SYS_CONTEXT(''SCOTT_CON'',''FIR'')'; END; / Listing 9.23: Filterfunktion für FIR
454
Sicherheit
CREATE OR REPLACE FUNCTION scott_sec.aw_basic2_function ( owner VARCHAR2, objname VARCHAR2 ) RETURN VARCHAR2 IS BEGIN -- Filtern nach Anwendung RETURN ' kontext = SYS_CONTEXT(''SCOTT_CON'',''APP'')'; END; / Listing 9.24: Filterfunktion für APP CREATE OR REPLACE FUNCTION scott_sec.aw_sal_function ( owner VARCHAR2, objname VARCHAR2 ) RETURN VARCHAR2 IS BEGIN -- Filtern nach Position oder User - je nach Position IF SYS_CONTEXT ('SCOTT_CON', 'POS') = 'Manager' THEN RETURN ' m_abt = SYS_CONTEXT(''SCOTT_CON'',''ABT'')'; ELSIF SYS_CONTEXT ('SCOTT_CON', 'POS') = 'Verkäufer' THEN RETURN ' m_mitarb = user'; ELSE RETURN ' 1 = 2'; END IF; END; / Listing 9.25: Filterfunktion für die Gehaltsspalte von Mitarbeitern
Gemäß dem oben dargelegten Feinkonzept können diese Funktionen nun über Richtlinien mit Datenbankobjekten verbunden werden. Die Tabelle mitarbeiter erhält demnach zwei – immer aktive – Standardfilter, einen für die Firma des Benutzers und einen für den Fall, dass die Gehaltsspalte selektiert wird. Standardfilter werden stets über die Richtliniengruppe sys_default angelegt: BEGIN DBMS_RLS.add_grouped_policy (object_schema => 'SCOTT', object_name => 'MITARBEITER', policy_group => 'SYS_DEFAULT', policy_name => 'FIR_FILTER', function_schema => 'SCOTT_SEC', policy_function => 'AW_BASIC_FUNCTION' );
Virtual Private Database DBMS_RLS.add_grouped_policy (object_schema => object_name => policy_group => policy_name => function_schema => policy_function => sec_relevant_cols => ); END; /
455
'SCOTT', 'MITARBEITER', 'SYS_DEFAULT', 'GEH_FILTER', 'SCOTT_SEC', 'AW_SAL_FUNCTION', 'M_GEHALT'
Listing 9.26: Standardrichtlinien für die Tabelle mitarbeiter
Da in dem vorangehenden Beispiel keine expliziten Angaben zum Befehlstyp gemacht wurden, gelten die Richtlinien gleichermaßen für select-, insert-, updateund delete-Befehle. Für auftraege gelten ebenfalls zwei Standardfilter: der Firmen- und der Applikationsfilter, die mit dem folgenden Code aktiviert werden: BEGIN DBMS_RLS.add_grouped_policy (object_schema => 'SCOTT', object_name => 'AUFTRAEGE', policy_group => 'SYS_DEFAULT', policy_name => 'FIR_FILTER', function_schema => 'SCOTT_SEC', policy_function => 'AW_BASIC_FUNCTION' ); DBMS_RLS.add_grouped_policy (object_schema => 'SCOTT', object_name => 'AUFTRAEGE', policy_group => 'SYS_DEFAULT', policy_name => 'APP_FILTER', function_schema => 'SCOTT_SEC', policy_function => 'AW_BASIC2_FUNCTION' ); END; / Listing 9.27: Standardrichtlinien für die Tabelle auftraege
Nach den Standardrichtlinien werden im Folgenden die Richtlinien angelegt, die exklusiv für die einzelnen Applikationen – SE und VE – gelten sollen. Hier wurden im Feinkonzept nur explizite Regel für VE vereinbart. Diese zusätzlichen, sich gegenseitig ausschließenden Richtlinien werden über jeweils eigene Richtliniengruppen gesteuert, die wechselweise zu den Standardrichtlinien zugeschaltet werden können.
456
Sicherheit
In einem ersten Schritt ist zunächst einmal festzulegen, dass das Attribut app des Kontextes scott_con für die Tabelle auftraege verantwortlich für das Zuschalten zusätzlicher Richtlinien ist: BEGIN DBMS_RLS.add_policy_context (object_schema => 'SCOTT', object_name => 'AUFTRAEGE', namespace => 'SCOTT_CON', attribute => 'APP' ); END; / Listing 9.28: Anlegen des Kontextes für Richtlinien
Im Anschluss daran können nun Richtliniengruppen angelegt werden, die den gleichen Namen wie die möglichen Werte des Attributs app von scott_con – nämlich VE und SE – haben: BEGIN DBMS_RLS.create_policy_group (object_schema object_name policy_group ); DBMS_RLS.create_policy_group (object_schema object_name policy_group ); END; /
=> 'SCOTT', => 'AUFTRAEGE', => 'VE' => 'SCOTT', => 'AUFTRAEGE', => 'SE'
Listing 9.29: Anlegen von Richtliniengruppen
Nun benötigen wir noch Funktionen, welche die where-Klauseln für die zusätzlichen Filter der Tabelle auftraege generieren. Für die VE-Applikation bedeutet dies nach der Feinspezifikation: CREATE OR REPLACE FUNCTION scott_sec.aw_ve_function ( owner VARCHAR2, objname VARCHAR2 ) RETURN VARCHAR2 IS BEGIN -- Filtern nach Position oder User - je nach Position IF SYS_CONTEXT ('SCOTT_CON', 'POS') = 'Manager' THEN RETURN ' a_abt = SYS_CONTEXT(''SCOTT_CON'',''ABT'')'; ELSIF SYS_CONTEXT ('SCOTT_CON', 'POS') = 'Verkäufer' THEN RETURN ' a_mitarb = user';
Virtual Private Database
457
ELSE RETURN ' 1 = 2'; END IF; END; / Listing 9.30: Filter für die VE-Applikation
Da die SE-Applikation für die Tabelle auftraege keine besonderen Regeln benötigt, generiert die Funktion eine nicht filternde Dummy-Klausel 1 = 1: CREATE OR REPLACE FUNCTION scott_sec.aw_se_function ( owner VARCHAR2, objname VARCHAR2 ) RETURN VARCHAR2 IS BEGIN RETURN ' 1 = 1'; END; / Listing 9.31: Filter für die SE-Applikation
Nun müssen die Tabelle auftraege, die neuen Richtliniengruppen und Funktionen über Richtlinien verbunden werden: BEGIN DBMS_RLS.add_grouped_policy (object_schema => 'SCOTT', object_name => 'AUFTRAEGE', policy_group => 'VE', policy_name => 'VE_FILTER', function_schema => 'SCOTT_SEC', policy_function => 'AW_VE_FUNCTION' ); DBMS_RLS.add_grouped_policy (object_schema => 'SCOTT', object_name => 'AUFTRAEGE', policy_group => 'SE', policy_name => 'SE_FILTER', function_schema => 'SCOTT_SEC', policy_function => 'AW_SE_FUNCTION' ); END; / Listing 9.32: Richtlinien für zusätzliche Richtliniengruppen
458
Sicherheit
Zum Schluss muss noch dafür gesorgt werden, dass die Initialisierung des Kontextes automatisch ausgeführt wird. In unserem Feinkonzept wurde hierfür ein LogonTrigger vorgesehen. Im Kernbereich dieses Triggers werden die jeweiligen Richtlinien dann wie folgt aktiviert: scott_sec.sec_init.init ( user_in => USER , application_in => lv_application ); Listing 9.33: Aktivierung der Richtlinien
Bei der Implementierung dieses Triggers ist zu beachten, dass die Plausibilitätsprüfungen innerhalb des aufgerufenen Paketes sec_init stark genug sind, um den jeweiligen Benutzer auf die richtige Anwendung zu lenken und Missbrauch auszuschließen. Darüber hinaus dürfen die Endbenutzer keinerlei Ausführungsprivilegien für das Initialisierungspaket – hier sec_init – haben! Diese Privilegien sind nur für den Benutzer notwendig, der den Logon-Trigger anlegt und in dessen Schema er gespeichert wird. Aus diesem Grunde wird der Logon-Trigger direkt im Schema scott_sec angelegt, um keine gefährdenden execute-Privilegien nach außen vergeben zu müssen. Damit auch scott_sec kein create any trigger-Privileg benötigt – was für das Anlegen von Logon-Triggern nötig wäre –, wird der Trigger von system für scott_sec aufgebaut: CREATE TRIGGER scott_sec.set_vpd ....
Ist der Kontext initialisiert, werden alle relevanten Richtlinien und die mit ihnen verbundenen Where-Klauseln für Zugriffe auf die Tabellen über AND-Verknüpfungen bereitgestellt. Für das Anlegen und Verwalten von Richtlinien und Anwendungskontexten steht alternativ auch ein Java-Client-Werkzeug, der Oracle Policy Manager, zur Verfügung. Das Werkzeug wird im Rahmen einer Client-Installation bereitgestellt und kann wie folgt aufgerufen werden: oemapp opm
Es versteht sich, dass die Funktionen und Pakete, die für die Richtlinien benötigt werden, nicht über dieses Werkzeug aufgebaut werden können. In der Regel empfiehlt sich das Werkzeug weniger zum Aufbau als vielmehr zur Verwaltung von VPD-Umgebungen, um beispielsweise bestehende Richtlinien zu aktivieren oder deaktivieren. Die folgende Abbildung zeigt die in unserem Beispiel angelegte VPD-Konfiguration in Ausschnitten aus der Sicht von OPM:
Virtual Private Database
459
Abbildung 9.25: Anwendungskontext im Oracle Policy Manager
Die folgende Grafik fasst noch einmal die komplexen Beziehungen aller beschriebenen VPD-Objekte zusammen.
Appl-Context
Paket Attribut
Policy-Function
Policy-Context Tabelle DML-Type
P Policy-Group
P
= Policy
Abbildung 9.26: Beziehungsgeflecht der VPD-Objekte
460
Sicherheit
Richtlinien: Typen und Caching Die Funktionen, die für die Generierung von Prädikaten verantwortlich sind, werden standardmäßig bei jeder parse- oder execute-Phase eines zugehörigen SQLBefehls zur Ausführung gebracht. Diese Strategie ist überall dort notwendig und sinnvoll, wo die Möglichkeit besteht, dass sich die für die Generierung nötigen Attributwerte sehr häufig ändern und daraus unterschiedliche Where-Klauseln resultieren. Diese Strategie kann aber unnötige Ressource kosten, wenn die Ergebnisse der VPD-Funktionen eher statischen Charakter haben. Aus diesem Grunde wurden bereits in der Version 9 unterschiedliche Richtlinientypen eingeführt, die in der Version noch erweitert wurden. Ziel dieser Typen ist es, die Dynamik der VPD-Funktionen genau konfigurieren zu können. Die Richtlinientypen werden beim Anlegen einer Richtlinie definiert über dbms_rls.add_policy oder dbms_rls.add_grouped_policy. Dort gibt des den IntegerParameter policy_type. Der boolesche Parameter static_policy wird nur noch aus Gründen der Rückwärtskompatibilität unterstützt und nur ausgewertet, falls policy_type auf dem Standardwert null belassen wurde. Die Angaben zu policy_type werden über die in der folgenden Übersicht angegebenen Konstanten definiert. Derzeit werden die folgenden Typen unterstützt: Dynamic (dbms_rls.DYNAMIC) – Standardwert. Die VPD-Funktion wird bei jedem parse oder execute ausgeführt. Static (dbms_rls.STATIC) – die VPD-Funktion wird einmalig ausgeführt und das resultierende Prädikat – zentral für alle Sessions – in der SGA gespeichert. Shared Static (dbms_rls.SHARED_STATIC) – wie static, nur kann die Funktion von mehreren Objekten genutzt werden. Shared Static (dbms_rls.SHARED_STATIC) – VPD-Funktionen, die für mehrere Objekte zum Einsatz kommen, werden nur einmalig ausgeführt. Context Sensitive (dbms_rls.CONTEXT_SENSITIVE) – nutzt das Caching von VPD-Funktionen, bis ein Applikationskontext verändert wird. Shared Context Sensitive (dbms_rls.SHARED_CONTEXT_SENSITIVE) – wie Context Sensitive, nur können VPD-Funktionen von mehreren Objekten genutzt werden. 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 DDViews 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 EXEMPT ACCESS POLICY lässt sich VPD pauschal für einen Benutzer deaktivieren, so dass für den Betreffenden keine where-Klauseln generiert werden!
Virtual Private Database
461
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. Tracing von VPD Werden VPD-Funktionen und Richtlinien nicht sehr sorgfältig geplant und umgesetzt, kann es oft zu unerwarteten und schwer zu diagnostizierenden Fehlern kommen. Für die Fehlersuche kann es hilfreich sein, die betreffende VPD-Funktion isoliert über einen SQL-Befehl abzufragen, etwa in der Form: SELECT vpd_function(......) FROM DUAL;
Für eine eingehendere Analyse dagegen sei an dieser Stelle kurz der Event 10730 erwähnt, der über die folgende Syntax innerhalb einer Session aktiviert werden kann: ALTER SESSION SET EVENTS '10730 trace name context forever, level 12'; Listing 9.34: Setzen des Events 10730
Der Event listet dann in einer Trace-Datei, die im Verzeichnis user_dump_dest gespeichert wird, die im Rahmen von VPD ergänzten Prädikate. Das folgende Beispiel enthält einen Ausschnitt aus einer solchermaßen generierten Trace-Datei. Auslöser war der SQL-Befehl SELECT * FROM scott.auftraege; ------------------------------------------------------------Logon user : P10 Table/View : SCOTT.AUFTRAEGE Policy name : APP_FILTER Policy function: SCOTT_SEC.AW_BASIC2_FUNCTION RLS view : SELECT "A_NR","A_DATUM","A_KUNDE","A_MITARB","A_ABT","KONTEXT","FIRMA" FROM "SCOTT"."AUFTRAEGE" "AUFTRAEGE" WHERE ( kontext = SYS_CONTEXT('SCOTT_CON','APP')) ------------------------------------------------------------Logon user : P10 Table/View : SCOTT.AUFTRAEGE Policy name : FIR_FILTER Policy function: SCOTT_SEC.AW_BASIC_FUNCTION RLS view : SELECT "A_NR","A_DATUM","A_KUNDE","A_MITARB","A_ABT","KONTEXT","FIRMA" FROM "SCOTT"."AUFTRAEGE" "AUFTRAEGE" WHERE ( firma = SYS_CONTEXT('SCOTT_CON','FIR')) -------------------------------------------------------------
462
Sicherheit
Logon user : P10 Table/View : SCOTT.AUFTRAEGE Policy name : VE_FILTER Policy function: SCOTT_SEC.AW_VE_FUNCTION RLS view : SELECT "A_NR","A_DATUM","A_KUNDE","A_MITARB","A_ABT","KONTEXT","FIRMA" FROM "SCOTT"."AUFTRAEGE" "AUFTRAEGE" WHERE ( a_abt = SYS_CONTEXT('SCOTT_CON','ABT')) Listing 9.35: Ausgabe des Events 10730
9.9
Labels
9.9.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 Dritten38 vergeben werden. Neuerdings gibt es auch das Systemprivileg grant any object privilege, das dem Begünstigten die Zuteilung von Objektprivilegien an Dritte erlaubt! 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. Label-Systeme erfordern darüber hinaus die Übereinstimmung des jeweiligen Benutzer- oder 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 aufgrund 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 MACLabel 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 38 Die WITH GRANT OPTION Klausel des GRANT-Befehls
Labels
463
wird, sind ebenfalls für den Einsatz von Labels prädestiniert. Ein großer Vorteil des Label-Systems 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 entsprechende trusted-Version der Datenbank zu realisieren. Oracle Label Security (OLS) baut intern auf dem VPD39-Konzept auf, das in Abschnitt Virtual Private Database 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 Managers40 realisieren.
9.9.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 9.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:
39 VPD = Virtual Private Database 40 Aufruf im Unix-Umfeld über oemapp opm
464
Sicherheit
– 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 (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 implementiert 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 Schemata 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 Levels lesen, allerdings nur bis zu seinem minimalen Level schreiben. – Sein Default-Level schließlich gibt den Level an, unter dem er standardmäßig operiert.
Labels
465
– 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 Schreibrechte erhält und ob die genannte Komponente Bestandteil seines standardmäßigen Session-Labels (Default) sowie Daten-Labels (Row) wird.
Abbildung 9.27: Zuordnung von Label-Komponenten zu Benutzern (1)
Ein Beispiel soll den vorangehenden Abschnitt verdeutlichen. Dem Benutzer scott werden 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 werden 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 Session- und 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 RowLabel haben, mindestens die Gruppe rs oder keine Gruppe sowie ausschließlich das Compartment mk oder kein Compartment haben. 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
466
Sicherheit
Abbildung 9.28: Zuordnung von Label-Komponenten zu Benutzern (2)
Datensätze ändern, die mindestens seinem minimalen Level g entsprechen, die mindestens die Gruppe rs sowie maximal das Compartment mk enthalten.
Tabelle T1 Row-Label
Session-Label G:MK:RS
G
MK,VK
RS
G
MK
RS
SG
MK
RS,RN
G
RS,RN
level compartment group
Abbildung 9.29: Kompatibilität von Session Labels und Row Labels
Labels
467
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 Row-Labeln bis zum maximalen Level des ausführenden Benutzers
WRITEDOWN
Gestattet die Veränderung der Level-Komponente von Row-Labeln bis zum minimalen Level des ausführenden Benutzers
READ
Gibt dem Betreffenden volles Leserecht auf alle Daten der betreffenden Richtlinie
Tabelle 9.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).
9.9.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 Row-Labels 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; /
Erstellte Richtlinien können über die View dba_sa_policies selektiert werden: POLICY_NAME COLUMN_NAME STATUS --------------------- -------------------- -------TEST_POLICY LABTEST_COL ENABLED POLICY_OPTIONS -------------------------------------------------------------READ_CONTROL, INSERT_CONTROL, UPDATE_CONTROL, DELETE_CONTROL, LABEL_DEFAULT, LABEL_UPDATE, CHECK_CONTROL
468
Sicherheit
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; /
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, short_name => 'VK', long_name => 'Verkauf'); END; /
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.
Labels
469
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; /
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 Schemata 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', schema_name => 'SCOTT', table_name => 'EMP'); END; /
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 sichtbar41 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;
41 Nicht sichtbar für DESCRIBE- und SELECT *-Befehle. Die Spalte kann allerdings explizit selektiert werden.
470
Sicherheit
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
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', min_level => 'G', def_level => 'G', row_level => 'G'); END; /
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; /
Labels
471
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; /
Ü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:
Abbildung 9.30: Generierte Benutzer-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. BEGIN sa_user_admin.set_user_privs ( policy_name => 'TEST_POLICY', user_name => 'SCOTT', privileges => 'WRITEUP'); END; /
472
Sicherheit
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 LabelSpalte der betreffenden Tabelle offen gelegt, können darüber hinaus die DatenLabels direkt abgefragt werden: SELECT empno, deptno, FROM emp; EMPNO DEPTNO ---------- ---------7369 20 7876 20
label_to_char(labtest_col) label LABEL ---------G:MK:RS G:MK:RS
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; /
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; /
Profile
9.10
473
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.
9.10.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 Ressourcenlimitierung 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_useranamen mit der Datenbank arbeiten. cpu_per_sessionrten. 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_callPARSE, EXECUTE, FETCH) gemessen werden. Das macht oft dann Sinn, wenn auf einem sehr ausgelasteten OLTP-System gelegentliche Abfragen durchgeführt werden, da diese bei Erreichen des 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_sessioncpu_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_callPARSE, 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.
474
Sicherheit
idle_timeatenbank 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_timeine 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_sgacomposite_limitService Units beschränkt. Damit werden sowohl CPUZeit 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. 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 9.36: Erstellen und Zuweisen eines Profils
Profile
475
9.10.2 Password-Management Neben der Limitierung von Ressourcen ist ein weiteres Thema der Profile die Überwachung von Kennwörtern. Damit existiert die Möglichkeit, ähnlich wie auf Betriebssystemebene, Vorgaben bezüglich der Passwörter zu machen. Im Gegensatz zu den Ressourcen müssen diese Parameter nicht erst über den ALTER SYSTEM-Befehl oder einen Initialisierungsparameter aktiviert werden, sondern sind immer aktiv. failed_login_attemptspassword_lock_time-Tagen oder durch den Administrator wieder freigegeben. password_lifetimePASSWORD eingegeben werden. Vorher wird der Benutzer eine Zeit lang (password_grace_time) aufgefordert, ein neues Kennwort einzugeben. password_reuse_timerwendet werden kann. password_reuse_maxpassword_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. password_lock_timeeder freigegeben wird. password_grace_timefgefordert werden. Dieser Parameter ist nur in Verbindung mit password_life_time sinnvoll. password_verify_functionutlpwdmg.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 9.37: Password-Management
Mit diesem Beispiel wird zunächst die Funktion verify_function erstellt und anschließend dem Profil p_verwaltung zusammen mit anderen Passwortmechanismen 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 wel-
ches Profil verwenden.
476
9.11
Sicherheit
Management von Ressourcen mit dem Resource Manager
9.11.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 ParallelServerprozessen 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 Managers42 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 mehreren Unterplänen bestehen. Die Vorgaben der Ressourcenpläne werden allerdings erst dann wirksam, wenn der betreffende Plan aktiviert wurde. Zu einem 42 In der Version 9.0.1 des Enterprise Manager sind nicht alle Einstellungen über die grafische Oberfläche möglich.
Management von Ressourcen mit dem Resource Manager
477
bestimmten 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.
9.11.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 Schemata. In der Vergangenheit gab es immer wieder Beschwerden darüber, dass OLTP-Transaktionen, die Kundenbestellungen verwalten, aufgrund 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 CPU-Zyklen 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 9.7: Tagesplan
478
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 9.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; /
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 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 und muss schließlich – nachdem alle Aufrufe abgesetzt werden
Management von Ressourcen mit dem Resource Manager
479
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 im 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; /
create_consumer_group bietet noch den Parameter cpu_mth (CPU-Methode), der 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: 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; /
480
Sicherheit
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. Über die Views dba_rsrc_consumer_groups und dba_rsrc_plans können Ressourcenpläne und Konsumentengruppen 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; /
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, 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 im 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,
Management von Ressourcen mit dem Resource Manager active_sess_pool_p1 switch_time switch_group switch_estimate parallel_degree_limit_p1 undo_pool
=> => => => => =>
481
10, 300, 'Batch', TRUE, 4, 500000);
END; /
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, active_sess_pool_p1 => 10, switch_time => 300, switch_group => 'Batch', switch_estimate => TRUE, parallel_degree_limit_p1 => 4, undo_pool => 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,
482
Sicherheit
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', 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 Batch-Programme 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; /
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:
Management von Ressourcen mit dem Resource Manager
483
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( 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; /
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 Serverparameter 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.
484
Sicherheit
9.11.3 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
Der hohe CPU-Anteil der Gruppe batch in diesem Beispiel wurde dadurch verursacht, dass die Sitzung der Gruppe team_a erst später startete.
9.12
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 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 Tabelleninformationen, betrifft. Es ist über das BefehlsAuditing möglich, die zu protokollierenden Aktionen auf ganz bestimmte Zeilen oder Spalten einer Tabelle zu beschränken.
Auditing
485
9.12.1 Zwanghaftes Auditing Das Starten und Stoppen von Instanzen und Datenbanken sowie die Authentifizierung von Benutzern der Rollen sysdba und sysoper gehören zu den Operationen, die ohne Ausnahme immer protokolliert werden. Neben der bekannten ALERTDatei steht zu diesem Zweck das Unterverzeichnis $ORACLE_HOME/rdbms/audit zur Verfügung43. Die Audit-Einträge werden dort in eine einzelne Datei mit Namen ora_.aud geschrieben, wobei für die Prozessnummer des betreffenden Serverprozesses steht. Das oben genannte Audit-Verzeichnis kann über den Systemparameter audit_file_dest angepasst werden. Das folgende Fragment enthält einen Ausschnitt aus einer Audit-Datei: Instance name: test10 Redo thread mounted by this instance: 1 Oracle process number: 10 Unix process pid: 4892, image: oracle@NandaDevi (TNS V1-V3) Mon Sep 5 09:18:06 2005 ACTION : 'CONNECT' DATABASE USER: '/' PRIVILEGE : SYSDBA CLIENT USER: oracle CLIENT TERMINAL: pts/1 STATUS: 0 Listing 9.38: Ausschnitt aus der Audit-Datei ora_4892.aud
Für das Auditing von weiteren Aktionen, die unter dem Benutzer SYS oder den Rollen sysoper oder sysdba ablaufen, steht der Serverparameter audit_sys_operations zur Verfügung, der wie folgt aktiviert werden kann: ALTER SYSTEM SET audit_sys_operations=TRUE SCOPE=SPFILE;
Für diesen Parameter ist – aus Sicherheitsgründen – ein Neustart der Instanz erforderlich. In der Folge werden dann alle Aktionen, die über SQL- oder PL/SQLBefehle ausgeführt werden, in dem oben genannten Audit-Verzeichnis und dort in eigenen Dateien protokolliert. Das folgende Beispiel zeigt einen kleinen Ausschnitt dieser Datei: Mon Sep 5 14:54:04 2005 ACTION : 'select to_char(taddr) from sys.v_$session where audsid = userenv('SESSIONID')' DATABASE USER: 'SYS' PRIVILEGE : SYSDBA CLIENT USER: Administrator CLIENT TERMINAL: STATUS: 0 Listing 9.39: Auditing von SYS-Operationen
43 Unter Windows werden Audit-Sätze dieser Art in das Event-Log geschrieben.
486
Sicherheit
9.12.2 Aktivieren von Auditing Zur Nutzung des Auditings sind – mit Ausnahme der im vorangehenden Abschnitt genannten Fälle – zwei Schritte notwendig: Erstens muss der DBA über den Systemparameter audit_trail die Datenbank für das Auditing vorbereiten, zweitens muss konfiguriert, werden, welche Aktionen oder Statements im Rahmen des Auditings protokolliert werden sollen. Für den ersten Schritt ist ein Neustart der Instanz notwendig, der zweite Schritt kann im laufenden Betrieb unternommen werden. Der Parameter audit_trail kann die folgenden Werte haben: os – speichert die Audit-Protokolle über das Betriebssystem. db oder true – speichert die Protokolle in der Datenbank, dort in der SYS-Tabelle aud$.
db_extended – ist eine Neuerung unter der Version 10g, speichert in der Datenbank wie db oder true, legt aber zusätzlich noch die genutzten SQL-Befehle sowie die Werte der darin enthaltenen Bindevariablen in den Spalten SQLBIND und SQLTEXT der Tabelle aud$ ab. none oder false – (der Standardwert) schaltet das Auditing aus. Die Konfiguration dessen, was protokolliert werden soll, 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 AuditDateien 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 Storage-Klauseln zu ändern44. Zwar ist als Standardeinstellung PCTINCREASE 50 und MAXEXTENTS 256
Auditing
487
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)
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.
9.12.3 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 USERNAME TERMINAL TIMESTAM ACTION_NAME RETURNCODE ---------- ---------- ---------- -------- ------------ ---------jahrends GERD HLLAP33 10.09.01 LOGON 1017 jahrends ANNA HLLAP33 10.09.01 LOGOFF 0 jahrends GERD HLLAP33 10.09.01 LOGON 0 Listing 9.40: 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. 44 Der Tablespace darf nicht geändert werden, da dies bei Upgrades zu Problemen führen könnte.
488
Sicherheit
Insgesamt gibt es 144 mögliche Kommando-Auditing-Befehle, angefangen beim UNKNOWN bis zum ALTER OPERATOR, so dass hiermit alle möglichen DDL-Befehle ü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.
9.12.4 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.
9.12.5 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 USERNAME TIMESTAM OWNER ACTION_NAME RETURNCODE -------- -------- -------- ------ ----------- ---------HLLAP33 ANNA 11.09.01 DEMO INSERT 2004 HLLAP33 GERD 11.09.01 DEMO UPDATE 0 Listing 9.41: Objekt-Auditing
Auditing
489
Die Fehlermeldung ORA-02004 security violation im Falle einer insert-Operation des Benutzers anna ist ein spezieller Eintrag in die Audit-Trail-Tabelle, der Benutzer bekommt die Meldung 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.
9.12.6 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 => 'DEMO', object_name => 'KUNDEN2', policy_name => 'CHECK_LIQ', audit_condition => 'LIQUIDITAET > 400000', audit_column => 'LIQUIDITAET'); END; / 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 9.42: Fine-Grain-Auditing
Die Information kann dann über die Tabelle sys.fga_log$ abgefragt werden. Diese mit der Version 9i eingeführte Variante des Auditings ermöglicht ein viel gezielteres Überwachen von Statements inklusive Abfragen. Ab der Version 10g ist diese Art des Auditings für alle DML-Befehle zulässig. Mit weiteren Prozeduren des Packages dbms_fga kann das Auditing an- oder ausgeschaltet bzw. gelöscht werden.
490
Sicherheit
9.12.7 Audit-Trigger Neben den beschriebenen Verfahren des Auditings 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 9.43: 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.
Auditing
491
9.12.8 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 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 Audit-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, Audit-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.
Wiederherstellungstechniken Die Sicherung von Oracle-Datenbanken gehört sicherlich zum Standardrepertoire eines Datenbankadministrators. Bedingt durch diese immer wiederkehrende Aktion hat sich bei vielen Oracle-Spezialisten ein bestimmtes Vorgehen eingeschliffen, das in einigen Fällen auf Erfahrungen aus der Oracle-Zeit der Version 6 herrührt. Damals gab es zum Teil hitzige Diskussionen über Online- oder Offline-Backups, Export und Import von Daten, Sicherung auf Band oder Festplatte oder die generelle Aktivierung der Oracle-Redo-Log-Archivierung. Leider gab es zu dieser Zeit von Oracle und auch später keine Werkzeuge bzw. technische Unterstützung für die Sicherung – alle Sicherungsverfahren beruhten im Wesentlichen auf mehr oder weniger optimalen Skripten. Nicht wenige Datenbanken werden noch heute nach dem Verfahren gesichert: Instanz herunterfahren und entsprechendes Laufwerk sichern. Dieses Vorgehen birgt große Gefahren in sich: Datenbanken werden immer größer und somit die Zeit für die Sicherung immer länger. Da die Datenbank während der Sicherung nicht zur Verfügung steht, besteht die Gefahr, dass während der Sicherung die Datenbank wieder gestartet werden muss. Weitaus größer ist allerdings das Risiko, nicht alle Datenbankdateien zu sichern, weil z.B. aus Platzmangel Datenbankdateien auf andere Platten gelegt wurden, die im Backup-Skript nicht enthalten sind. Wenn man dann noch die Frage stellt, wann denn das letzte Mal eine Sicherung überprüft, d.h., wieder eingespielt wurde, dann bekommt man eventuell zur Antwort: »Als wir die Datenbank damals neu aufgebaut haben.«
10.1
Planung
10.1.1 Generelles Für die Planung einer Sicherungs- und Wiederherstellungsstrategie müssen folgende Punkte beachtet werden: Welche Server-Hardware wird benutzt? Auf welchem Medium wird gesichert? Gibt es Redundanzen? Wie schnell muss die Datenbank wieder zur Verfügung stehen? Wie groß sind Gefahren durch fehlerhafte Anwendungen?
494
Wiederherstellungstechniken
Wie groß ist die Datenbank? Welche Komponenten müssen zusätzlich gesichert werden? Gibt es Abhängigkeiten zu anderen Systemen? Wann wird was gesichert?
10.1.2 Hardware Zur Server-Hardware zählt im Wesentlichen die eingesetzte Speicherarchitektur, z.B. die Spiegelung der Festplatten. Aber natürlich spielt auch die Anzahl der CPUs und die Bandbreite des I/O-Systems eine entscheidende Rolle. Es muss darauf geachtet werden, dass die Sicherung den normalen Betrieb nicht zu sehr stört. Sicherungsmedium Wenn über Sicherungen nachgedacht wird, denkt man zunächst natürlich an die Bandsicherung. Sicherlich ist es sinnvoll, mit diesem Verfahren eine Historisierung der Sicherungen zu betreiben; allerdings sind Bandsicherungen oft problematischer als alleinige Absicherung, da die Rücksicherung zumindest bei großen Datenbanken zu viel Zeit in Anspruch nimmt. Ähnliches gilt für optische Medien. Immer häufiger trifft man daher auf mehrstufige Verfahren, bei denen zunächst auf weitere Festplatten gesichert wird – natürlich möglichst physisch unabhängig von den Festplatten, auf denen die Datenbankdateien liegen. Von diesem Sicherungsplattenpool aus werden dann weitere Sicherungen, z.B. auf Bändern, angefertigt. Dieses Verfahren kann auch indirekt betrieben werden, indem man die Sicherungen z.B. auf einer Schattendatenbank, die auf Redo-Log-Shipping basiert, durchführt. Auch der Recovery Manager unterstützt solche indirekten Verfahren.
10.1.3 Archivierung Wie Sie schon im Kapitel 3 erfahren haben, sind die wichtigsten Dateien der Datenbank die Redo-Log-Dateien, da in diesen alle Transaktionsinformationen hinterlegt sind. Wenn es also um die Verfügbarkeit eines Systems geht, dann ist es die primäre Aufgabe eines Datenbankadministrators, dafür zu sorgen, dass keine abgeschlossenen Transaktionen verloren gehen. Dies wird zunächst über die Spiegelung der Redo-Log-Dateien geschehen, zusätzlich ist es aber notwendig, jede Redo-LogDatei zu sichern. Mit dieser Sicherung, im Oracle-Umfeld Archivierung genannt, lässt sich jede abgeschlossene Transaktion als roll forward aus einer Sicherung wieder herstellen. Das gilt sowohl für Sicherungen einer nicht aktiven (offline) als auch einer aktiven (online) Datenbank. Diese Archivierung der Redo-Log-Dateien bilden somit die notwendige Grundlage für jede Art der Online-Sicherung.
Planung
495
Man könnte jetzt auf die Idee kommen, die Archivierung mit Betriebssystemmitteln durchzuführen. Hierbei sind aber folgende Punkte zu beachten: Eine zyklisch beschriebene Redo-Log-Datei darf erst dann überschrieben werden, wenn der alte Inhalt archiviert worden ist. Wenn eine Archivierung nicht mehr möglich ist, z.B. weil kein Platz mehr im Filesystem zur Verfügung steht, darf keine Transaktion mehr durchgeführt werden, da sonst ein Datenverlust bei Fehlern droht. Da diese Punkte vom Betriebssystem kaum bewältigt werden können, bietet Oracle die optionale Konfiguration der Archivierung aus der Datenbank heraus. Dabei sorgen ein oder mehrere Archivierungsprozesse dafür, dass mit dem Logswitch die beschriebene Redo-Log-Datei in ein anderes Verzeichnis kopiert wird. Das bedeutet, dass es im Wesentlichen zwei Parameter für die Archivierung gibt: Soll archiviert werden oder nicht? Der Name der Datei bzw. des Verzeichnisses, in das archiviert werden soll. 1. Zu bedenken gibt es allerdings, dass das Archivierungsverzeichnis nicht mehr zum Oracle-Datenbankkontext gehört, d.h. aus der Oracle-Datenbank heraus nicht administriert bzw. überwacht werden kann. 2. Eine Ausnahme bildet hierbei die in Oracle 10g eingeführte Flash-Recovery Area, die später noch näher besprochen wird. Archivierung aktivieren Die Aktivierung erfolgt in zwei Schritten. Zunächst wird über Initialisierungsparameter festgelegt, wohin die Dateien gesichert werden bzw. wie die Dateien heißen sollen. Dafür stehen folgende Parameter zur Verfügung: 1. log_archive_dest Dieser seit der Version 6 gültige Parameter setzt das Verzeichnis und optional ein Präfix des Dateinamens für die Archivierung. Beispiel: log_archive_dest = F:\oracle\archive\WIN10G\
2. log_archive_dest_1 bis log_archive_dest_10 Diese Parameter sind nur in der Enterprise Edition erlaubt. Im Unterschied zu log_archive_dest werden sie immer als Zeichenkette angegeben, da sie aus verschiedenen Optionen und Werten zusammengesetzt sind. Man beachte, dass die Angabe eines Verzeichnisses über die LOCATION-Option erfolgt. Neben einem Verzeichnis kann hier auch ein Net-Aliasname angegeben werden, so dass eine Archivierung über Oracle Net auf eine andere Datenbank möglich ist. Dies wird für Schattendatenbanken mit Data Guard genutzt. Daneben sind zusätzliche Parameter möglich, wie z.B. ob diese Archivierung zwingend (MANDATORY) oder nur optional (OPTIONAL) ist. Das bietet sich dann an, wenn aus Verfügbarkeitsgründen mehrfach archiviert wird.
496
Wiederherstellungstechniken
Beispiel: log_archive_dest_1 = 'LOCATION=/ora_arch/LINUX10G/ MANDATORY' log_archive_dest_2 = 'SERVICE = STDY10G OPTIONAL REOPEN=60'
Weitere Parameter sind für die Data-Guard-Funktionalität möglich und werden im entsprechenden Kapitel besprochen. Die gleichzeitige Verwendung von log_archive_dest und log_archive_dest_n ist nicht möglich. 3. log_archive_dest_state_1 bis log_archive_dest_state_10 Für diese Parameter gibt es drei unterschiedliche Werte: – ENABLE (Standardwert):
Der Parameter wird benutzt.
– DEFER:
Ist belegt, wird aber (noch) nicht benutzt.
– ALTERNATE:
Wird benutzt, wenn eine andere Lokation nicht benutzt werden kann.
4. log_archive_duplex_dest Für die Standard Edition ist es mit diesem Parameter möglich, eine doppelte Archivierung (allerdings nur lokal) aufzusetzen. 5. log_archive_format Dateiformat der archivierten Redo-Log-Dateien. Folgende Parameter können gesetzt werden: – %s bzw. %S:
Log-Sequenznummer (groß, 8-stellig)
– %t bzw. %T:
Instanz-Thread-Nummer (groß, 4-stellig)
– %a:
Activation-ID der Datenbank
– %d:
Datenbank-ID (nicht ORACLE_SID)
– %r:
Reset-Logs-ID
Die Parameter %s, %t und %r, optional in der Großbuchstabenvariante, sollten grundsätzlich angegeben werden! Beispiel: log_archive_format = 'log_%t_%S_%r.arc'
6. log_archive_max_processes [1 … 10] Maximale Anzahl der Archivierungsprozesse 7. log_archive_min_succeed_dest [1 … 10] Bei mehrfacher Archivierung kann hierdurch gesteuert werden, wann eine Online-Redo-Log-Datei wiederverwendet werden kann. D.h., wenn dieser Parameter auf 2 steht, aber auf drei unterschiedliche Lokationen (log_archive_dest_1, log_archive_dest_2, log_archive_dest_3) gesichert wird, kann es vorkommen, dass die Archivierung auf eine der drei Lokationen noch nicht beendet ist, die Redo-Log-Datei aber dennoch überschrieben wird. Dies ist z.B. dann sinnvoll, wenn eine Lokation über ein Netzwerk angebunden ist, das keine hohe Verfügbarkeit hat.
Planung
497
Der nächste Schritt ist dann die eigentliche Aktivierung des Archivierens. Hierfür muss die Instanz heruntergefahren und im Mount-Status gestartet werden. Nur in diesem Zustand kann die Archivierung aktiviert oder deaktiviert werden. Die komplette Aktivierung der Archivierung kann also wie folgt aussehen: SQL> SQL> SQL> SQL> SQL> SQL>
ALTER SYSTEM SET log_archive_dest_1 = 'LOCATION = /app/oracle/ora_arch/LINUX10G/'; ALTER SYSTEM SET log_archive_format = 'log_%t_%S_%r.arc' scope = spfile; SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE ARCHIVELOG; ALTER DATABASE OPEN;
Listing 10.1: Aktivierung der Archivierung
Wichtig ist, dass die Datenbank konsistent heruntergefahren wird (also mit der Option NORMAL, IMMEDIATE oder TRANSACTIONAL), ansonsten kann die Archivierung nicht aktiviert werden. Tipp: Setzen Sie immer ans Ende der Zeichenfolge für das Archivierungsziel ein »/« bzw. »\«. Damit vermeiden Sie, wenn das Verzeichnis nicht existiert, dass die archivierten Redo-Log-Dateien im übergeordneten Verzeichnis landen. Bei der Festlegung des Namens wird der Dateiname einfach durch eine Konkatinierung von Destination und Format erstellt. Wichtig ist dies vor allen Dingen bei Unix-Systemen, wenn als Archivierungsverzeichnis ein Mount-Point benutzt wird. Überprüfen der Archivierung Zunächst bietet es sich an, nach dem Einschalten der Archivierung die Funktion zu testen. Am einfachsten geschieht dies durch einen Logswitch. Dabei wird jede Online-Redo-Log-Gruppe einmal archiviert. Im Beispiel für 3 Online Redo-Log-Gruppen wird also folgender Befehl ausgeführt: SQL> ALTER SYSTEM SWITCH LOGFILE; SQL> ALTER SYSTEM SWITCH LOGFILE; SQL> ALTER SYSTEM SWITCH LOGFILE; Listing 10.2: Testen der Archivierung
Nach dem dritten Logswitch sollte der SQL-Prompt nach kurzer Zeit wieder erscheinen. Ansonsten wird in der Alert-Datei ein entsprechender Eintrag protokolliert. Folgende Befehle zeigt die Informationen der Archivierung: SQL> SELECT archiver FROM v$instance; ARCHIVE ------STARTED Listing 10.3: Archiver gestartet
498
Wiederherstellungstechniken
SQL> SELECT log_mode FROM v$database; LOG_MODE -----------ARCHIVELOG Listing 10.4: Archivierung aktiviert
Über SQL*Plus kann, wenn man mit AS SYSDBA angemeldet ist, auch folgender Befehl ausgeführt werden: SQL> ARCHIVE LOG LIST; Datenbank-Log-Modus Archive-Modus Automatische Archivierung Aktiviert Archivierungsziel /app/oracle/ora_arch/JAUX10G/ Älteste Online-Log-Sequenz 75 Nächste zu archivierende Log-Sequenz 77 Aktuelle Log-Sequenz 77 Listing 10.5: Archivierungsinformation
Überprüfen kann man die archivierten Redo-Log-Dateien über die View v$archived_log z.B. in der Form: SQL> SELECT name, sequence#, archived, completion_time, ROUND((blocks*block_size)/1024/1024) MByte FROM v$archived_log WHERE completion_time > sysdate - 1; NAME SEQUENCE# ARC COMPLETION_TIME MBYTE -------------------------------------------------- ---------- --- ------------------- ---------E:\ORA_ARCH\JA10G\LOG_1_00157_522936157.ARC E:\ORA_ARCH\JA10G\LOG_1_00158_522936157.ARC E:\ORA_ARCH\JA10G\LOG_1_00159_522936157.ARC D:\ORACLE\ORAARCH\JA10G\LOG_1_00160_522936157.ARC D:\ORACLE\ORAARCH\JA10G\LOG_1_00161_522936157.ARC D:\ORACLE\ORAARCH\JA10G\LOG_1_00162_522936157.ARC D:\ORACLE\ORAARCH\JA10G\LOG_1_00163_522936157.ARC D:\ORACLE\ORAARCH\JA10G\LOG_1_00164_522936157.ARC E:\ORA_ARCH\JA10G\LOG_1_00165_522936157.ARC E:\ORA_ARCH\JA10G\LOG_1_00166_522936157.ARC E:\ORA_ARCH\JA10G\LOG_1_00167_522936157.ARC
157 158 159 160 161 162 163 164 165 166 167
YES YES YES YES YES YES YES YES YES YES YES
21.05.2004 21.05.2004 21.05.2004 21.05.2004 21.05.2004 21.05.2004 21.05.2004 21.05.2004 21.05.2004 21.05.2004 21.05.2004
17:21:04 17:21:10 17:21:13 17:22:39 17:22:40 17:22:41 17:24:33 17:24:37 17:25:48 17:25:53 17:25:56
10 10 10 10 10 10 10 10 10 10 10
Listing 10.6: Überprüfung der archivierten Redo-Log-Dateien
Hier
sieht
man,
dass
temporär
die
Archivierung
in
das
Verzeichnis
D:\oracle\oraarch\JA10G erfolgte. Vorher und nachher wurde das Verzeichnis E:\ora_arch\JA10G gewählt.
Planung
499
Ressourcenproblemlösung Die laufende Archivierung kann anhand der Redo-Log-Dateien abgefragt werden. Hierdurch ist es frühzeitig möglich zu erkennen, ob ein Ressourcenproblem vorliegt, also bevor die Instanz stehen bleibt. SQL> SELECT group#, sequence#, bytes, archived, status FROM v$log; GROUP# SEQUENCE# BYTES ARCHIVED STATUS ---------- ---------- ---------- ---------- ---------------1 149 10485760 NO CURRENT 2 148 10485760 NO ACTIVE 3 147 10485760 NO INACTIVE Listing 10.7: Überprüfung Archivierung
Der Wert »NO« in der Spalte archived gibt an, dass keine der Online-Redo-LogDateien archiviert worden ist. Das bedeutet, so lange, bis die Redo-Log-Datei mit status »CURRENT« noch Platz für weitere Redo-Log-Daten hat, haben Sie Zeit für eine Überprüfung der Archivierung – danach sind keine weiteren Transaktionen mehr möglich. Das Verzeichnis der archivierten Redo-Log-Dateien kann, wie das Beispiel zeigt, im laufenden Betrieb geändert werden. Damit kann, wenn ein Verzeichnis voll ist, auf ein anderes Verzeichnis umgeschaltet werden. Das dabei angegebene Verzeichnis muss allerdings vorher existieren. Ansonsten erhalten Sie die Fehlermeldung: ORA-02097: ORA-16032: ORA-09291: OSD-04018: O/S-Error:
Parameter kann nicht verändert werden, da angegebener Wert ungültig ist Zielzeichenfolge von Parameter LOG_ARCHIVE_DEST_1 kann nicht übersetzt werden sksachk: Ungültiges Verzeichnis für Archivierungsziel angegeben Auf das angegebene Verzeichnis oder Gerät kann nicht zugegriffen werden. (OS 2) Das System kann die angegebene Datei nicht finden.
Listing 10.8: Fehlerhaftes Archivverzeichnis
Hier ein MS-Windows-Beispiel: Ein Anwender meldet das Problem, dass ein DML-Befehl nicht beendet wird. Ein Abbruch bleibt ohne Erfolg. Alternativ meldet eine Monitoring-Software, dass es neue Fehlermeldungen in der Alert-Datei gibt. Eine Überprüfung der Alert-Datei bringt folgende Information: ARC1: Archiving not possible: No primary destinations ARC1: Failed to archive log 1 thread 1 sequence 127 (4) Fri May 21 16:19:43 2004 ARC0: Evaluating archive log 1 thread 1 sequence 127 Fri May 21 16:19:43 2004 Errors in file d:\oracle\admin\ja10g\bdump\ja10g_arc1_3420.trc: ORA-16014: Log 1 Sequenz-Nr. 127 nicht archiviert, keine verfügbaren Ziele ORA-00312: Online-Log 1, Thread 1: 'D:\ORACLE\ORADATA\JA10G\REDO01.LOG' Listing 10.9: Fehlermeldung in der Alert-Datei
500
Wiederherstellungstechniken
Als Lösung könnte man die archivierten Redo-Log-Dateien löschen. Aber Vorsicht, wenn dann die Datenbank einen Fehler produziert, fehlen Ihnen für eine Wiederherstellung die notwendigen archivierten Redo-Log-Dateien. Besser ist es zu schauen, ob auf einer anderen Platte bzw. einem anderen Filesystem noch ausreichend Platz ist, und dann die Archivierung auf dieses Verzeichnis umzuhängen. Dies geschieht im Beispiel durch folgenden Befehl: SQL> ALTER SYSTEM SET log_archive_dest_1 = 'LOCATION=D:\oracle\oraarch\JA10G\'; Listing 10.10: Neues Archivierungsverzeichnis
In der Alert-Datei stellt sich das wie folgt dar: ARC1: Evaluating archive log 1 thread 1 sequence 127 Fri May 21 16:19:46 2004 Committing creation of archivelog 'D:\ORACLE\ORAARCH\JA10G\LOG00128_0522936157_001.arc' Archiver process freed from errors. No longer stopped Fri May 21 16:19:48 2004 Private_strands 7 at log switch Thread 1 advanced to log sequence 130 Current log# 2 seq# 130 mem# 0: D:\ORACLE\ORADATA\JA10G\REDO02.LOG Fri May 21 16:19:49 2004 Committing creation of archivelog 'D:\ORACLE\ORAARCH\JA10G\LOG00127_0522936157_001.arc' Fri May 21 16:19:49 2004 Listing 10.11: Wiederanlauf der Archivierung
Jetzt kann das alte Archivverzeichnis gesichert werden, die archivierten Redo-LogDateien werden gelöscht, und zum Schluss wird die Archivierung wieder auf das alte Verzeichnis zurückgesetzt. Vergessen Sie aber nicht, die archivierten Redo-Log-Dateien des temporären Verzeichnisses auch noch zu sichern oder in das alte Verzeichnis zu kopieren. Enterprise Manager Alternativ kann die Konfiguration auch über den Enterprise Manager durchgeführt werden. Bild 10.1 zeigt die Übersichtsinformation über die Archivierung (in diesem Fall ausgeschaltet).
Abbildung 10.1: Übersicht Archivierung und Flashback
Planung
501
Wenn man den Hyperlink »Deaktiviert« anwählt, kommt man in ein zweites Menü, in dem die Archivierung eingeschaltet und konfiguriert werden kann (siehe Bild 10.2)
Abbildung 10.2: Einschalten der Archivierung
Das Archive-Log-Ziel log_archive_dest_10 ist standardmäßig mit dem Initialisierungsparameter USE_DB_RECOVERY_FILE_DEST vorbelegt. Das bedeutet, wenn Sie bei der Installation der Datenbank eine Flash-Recovery Area angegeben haben, wird automatisch in dieses Verzeichnis archiviert (siehe auch Kapitel 10.1.4).
10.1.4 Flash-Recovery Area In den Oracle-Versionen vor 10g gab es eine strikte Trennung zwischen Datendateien und Sicherungen. Das bedeutet auch, dass das Verzeichnis, in das die archivierten Redo-Log-Dateien gesichert werden, nicht zur Datenbank gehört und somit nicht mit Datenbankmitteln überprüft werden kann. Trotzdem ist dieses Verzeichnis kritisch, da die Datenbank keine Transaktionen mehr zulässt, wenn dieses Verzeichnis voll ist.
502
Wiederherstellungstechniken
Mit Version 10g führt Oracle einen zusätzlichen Datenbankbereich – die FlashRecovery Area – ein, der für unterschiedliche Zwecke genutzt werden und damit auch die Verwaltung der archivierten Redo-Log-Dateien übernehmen kann. Dieser Bereich wird über zwei Variablen parametriert: db_recovery_file_dest legt das Verzeichnis fest. Es sollte sich hierbei immer um ein eigenes Filesystem handeln. db_recovery_file_dest_size gibt die maximale Größe des von Oracle kontrollierten Verzeichnisinhalts an. Der Füllgrad bzw. das Vorhandensein dieses Verzeichnisses wird jetzt von der Datenbank aus kontrolliert, und bei entsprechenden Schwellenwerten wird ein Eintrag in der Alert-Datei generiert. Das Verzeichnis kann jetzt für folgende Aktionen genutzt werden: Archivierung Sicherung der Datenbank Flashback Database Aus diesen Informationen kann leicht die benötigte Größe des Verzeichnisses und damit der Parameter db_recovery_file_dest_size bestimmt werden: Anzahl noch nicht gesicherter archivierter Redo-Log-Dateien Anzahl notwendiger Backup-Sets (Retention) Flashback-Größe Für jede der oben genannten Aktionen werden automatisch eigene Unterverzeichnisse generiert. Außerdem wird darunter wiederum ein Verzeichnis für jeden Tag angelegt. Folgendes Beispiel zeigt die Nutzung der Flash-Recovery Area. Dabei wurde die Archivierung eingeschaltet, jedoch nicht der Parameter log_archive_dest bzw. log_archive_dest_n gesetzt. SQL> ALTER SYSETM SET db_recovery_file_dest = '/oraflash'; SQL> ALTER SYSTEM SET db_recovery_file_dest_size = 1G; SQL> SELECT * FROM v$recovery_file_dest; NAME SPACE_LIMIT SPACE_USED SPACE_RECLAIMABLE NUMBER_OF_FILES --------------- ----------- ---------- ----------------- --------------/oraflash 1073741824 882509824 3872768 31 Listing 10.12: Flash-Recovery-Area-Parameter und Abfrage
Die archivierten Redo-Log-Dateien heißen jetzt: /oraflash/JAUX10G/archivelog/2004_08_06/o1_mf_1_1_0k75gyfc_.arc /oraflash/JAUX10G/archivelog/2004_08_06/o1_mf_1_2_0k75tjg1_.arc Listing 10.13: Archivierte Redo-Log-Dateien in der Flash-Recovery Area
Sicherung und Wiederherstellung
503
Es wird schon in diesem einfachen Fall deutlich, dass mit der Zeit einige Verzeichnisse entstehen werden, und auch die Namen der archivierten Redo-Log-Dateien (Oracle Managed Files) sind gewöhnungsbedürftig. Wenn jetzt eine Sicherung mit dem Recovery Manager durchgeführt wird, wird standardmäßig auch diese in die Flash-Recovery Area geschrieben (siehe folgendes Kapitel). Obwohl die Flash-Recovery Area auch für die Standard Edition gesetzt werden kann, ist es nicht möglich, die archivierten Redo-Log-Dateien in dieses Verzeichnis zu sichern, da die Parameter log_archive_dest bzw. log_archive_duplex_dest für die Flash-Recovery Area nicht benutzt werden können.
10.2
Sicherung und Wiederherstellung
Bei der Wiederherstellung einer Datenbank unterscheidet man zwischen dem Rücksichern der Datenbankdateien und dem Wiederherstellen des Datenbankinhalts. Beim Rücksichern werden die betroffenen Dateien (Daten-, Kontroll-, Redo-LogDateien) aus einer physikalischen Sicherung heraus an die entsprechende Stelle eingespielt. Die Dauer dieser Aktion ist also ausschließlich von der I/O-Zeiten (Festplatte, Controller, Bandlaufwerk) abhängig. Bei der Wiederherstellung wird über die Informationen aus den Redo-Log-Dateien zunächst ein roll forward aller Transaktionen durchgeführt. Da in den Redo-LogDateien auch nicht abgeschlossene Transaktionen gespeichert werden, erfolgt danach ein Rollback aller offenen Transaktionen. Die hierzu notwendigen Informationen sind in den Undo-Segmenten vorhanden, die durch den roll forward ebenfalls wiederhergestellt worden sind. Im Folgenden 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. In der Regel wird man die Variante wählen, welche 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. Verschiedene Fehlerfälle, die in der Praxis sicherlich auch in Kombination auftreten, werden anschließend mit entsprechenden Lösungen erläutert.
504
Wiederherstellungstechniken
10.2.1 Fehleranalyse Um das Ziel der schnellstmöglichen Fehlerbehebung 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 Oracle-Fehlermeldung. Aufgabe des DBA 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. Prinzipiell kann man davon ausgehen, dass bei einem Plattenfehler eine entsprechende Fehlermeldung in der Alert-Datei der Datenbank existiert und z.B. über die Enterprise-Manager-Konsole angezeigt wird.
Abbildung 10.3: Fehlermeldung im Enterprise Manager
Wenn man den entsprechenden Link anwählt, erhält man einen Auszug aus der Alert-Datei mit allen relevanten Fehlereinträgen.
Abbildung 10.4: Auszug aus der Alert-Datei
Sicherung und Wiederherstellung
505
In diesem Beispiel ist zu erkennen, dass die Datei /oradata/JAUX10G/ts_demo01.dbf korrupt ist. Als Nächstes muss herausgefunden werden, warum dieser Fehler aufgetreten ist. Der Ausfall einer Festplatte ist wesentlich leichter zu beheben als die in diesem Fall aufgetretene Korruption einer Datei. In diesem Fall muss zunächst eine eingehende Untersuchung des Filesystems (in dem vielleicht noch andere Datenbankdateien liegen) erfolgen. Erst wenn diese Untersuchung ein Resultat liefert (z.B. Fehler des I/O-Controllers, Festplattenfehler oder logischer Fehler), kann eine entsprechende Lösung erfolgen (z.B. eine neue Festplatte einbauen, Dateien auf ein anderes Filesystem verschieben oder durch Einschränkung von Rechten im Dateisystem dafür sorgen, dass kein Benutzer unbeabsichtigt eine Datenbankdatei zerstören kann). Wenn die Instanz nicht mehr zur Verfügung steht und eine Platte ausgefallen ist, muss herausgefunden werden, welche Komponenten auf dieser Platte lagen. Sobald die Instanz in den Status MOUNT gestartet werden kann, kann dies über die Views v$datafile und v$tablespace geschehen. Bei einem laufenden System können fehlerhafte Tablespaces auch ü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. Da es sich hierbei um logische Fehler handelt, ist eine Lösung in diesem Fall komplexer. Für die reine Wiederherstellung der Datenbank werden durch die Flashback-Funktionalität und den LogMiner entsprechende Hilfsmittel bereitgestellt.
10.2.2 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 Undo-Segmenten betroffen? 3. Sind alle Voraussetzungen für eine vollständige Wiederherstellung gegeben? 4. Soll eine vollständige Wiederherstellung durchgeführt werden, oder muss die Datenbank auf einen früheren Zeitpunkt zurückgesetzt werden? 5. Können Teile der 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, welche 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.
506
Wiederherstellungstechniken
10.2.3 Instanzwiederherstellung, Prozess- und Netzwerkfehler Das Oracle-System besitzt interne Mechanismen, die eine 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 eine Instanzwiederherstellung durchzuführen. Dazu werden zunächst in der »Roll Forward Phase« alle Transaktionen aus den noch nicht abgeschlossenen Redo-Log-Dateien nachzufahren. Anschließend wird die Datenbank geöffnet und steht wieder zur Verfügung. Noch offene Transaktionen werden als dead gekennzeichnet und im Folgenden in der »Rollback Phase« durch den SMON oder einen Benutzerprozess, der auf entsprechende Einträge trifft, zurückgerollt. In der Alert-Datei stellt sich dieser Vorgang wie folgt dar: ALTER DATABASE OPEN Sat May 22 14:47:55 2004 Beginning crash recovery of 1 threads Sat May 22 14:47:56 2004 Started first pass scan Sat May 22 14:47:56 2004 Completed first pass scan 2256 redo blocks read, 413 data blocks need recovery Sat May 22 14:47:56 2004 Started redo application at Thread 1: logseq 125, block 17823, scn 0.0 Recovery of Online Redo Log: Thread 1 Group 2 Seq 125 Reading mem 0 Listing 10.14: Alert-Eintrag für Instanzwiederherstellung
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.
Sicherung und Wiederherstellung
507
10.2.4 Wiederherstellung von Medienfehlern Der Begriff Wiederherstellung von Medienfehlern beschreibt die Wiederherstellung von Datenbanken oder einzelnen Dateien nach Beschädigung einer Platte bzw. einer Datenbankdatei. In diesen Fällen muss oft zunächst ein Hardware-Fehler behoben werden, und dann müssen über ein Restore die fehlenden oder fehlerhaften Dateien aus einer Sicherung zurückgelesen werden. Alternativ kann eine Wiederherstellung auf ein anderes Filesystem bzw. eine andere Festplatte erfolgen. Nachdem die Dateien zurückgespielt worden sind, kann dann die entsprechende Wiederherstellung durchgeführt werden. Zu diesen Medienfehlern gehören: Verlust von Dateien eines Daten-Tablespaces oder des SYSAUX 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. Ähnliches gilt für das SYSAUX-Tablespace. Jobs, wie zum Beispiel die automatische Generierung von Statistikinformationen, werden fehlschlagen, und diese Information wird in der Alert-Datei protokolliert. Die Wiederherstellung des Tablespace kann im laufenden Betrieb des OracleSystems durchgeführt werden. Anwendungen, die auf andere Bereiche der Datenbank zugreifen, können dabei ohne Einschränkung weiterarbeiten. Die Wiederherstellung kann für den kompletten Tablespace oder eine spezifische Datendatei erfolgen. Verlust von Dateien eines Index-Tablespaces Prinzipiell ist es für ein Restore und Recovery unerheblich, ob es sich um Daten oder Indizes handelt. Dennoch kann es u.U. bei einem Index-Tablespace sinnvoller sein, den Tablespace neu anzulegen und die Indizes mit den entsprechenden »CREATE INDEX«-Befehlen neu anzulegen. Dafür müssen natürlich die entsprechenden Skripte vorhanden sein. Verlust von Dateien des SYSTEM-Tablespaces Der Tablespace SYSTEM beinhaltet das Data Dictionary und damit zentrale Informationen, ohne die ein Oracle-System nicht lauffähig ist. Die Instanz ist so nicht mehr nutzbar und wird, so sie noch nicht von einem internen Prozess beendet wurde, durch ein SHUTDOWN ABORT heruntergefahren. Nachdem die Datenbank wieder gemountet wurde (STARTUP MOUNT), kann eine Wiederherstellung auf Tablespace- oder Datendateiebene durchgeführt werden. Anschließend kann die Datenbank wieder geöffnet werden. Verlust von Dateien des Undo-Tablespace Dieser Tablespace ist ebenso kritisch wie der SYSTEM-Tablespace. Hinzu kommt, dass Fehler in diesem Tablespace leicht zu einer Korruption der gesamten Datenbank führen können. Nur über die Informationen der Undo-Segmente kann ein fehlerfreies Rollback offener Transaktionen durchgeführt werden.
508
Wiederherstellungstechniken
Prinzipiell gilt für den Undo-Tablespace die gleiche Vorgehensweise wie beim SYSTEM-Tablespace. Da der Tablespace offene Undo-Segmente enthält, ist eine Fehlerbehebung im laufenden System nicht möglich. Die Datenbank muss heruntergefahren und die Wiederherstellung im Mount-Status durchgeführt werden. Verlust der Online-Redo-Log-Dateien Der Verlust der Online-Redo-Log-Dateien ist einer der schlimmsten Fälle. Die Instanz stürzt ab, da der LGWR-Prozess Informationen aus dem Log-Puffer nicht mehr auf Platte schreiben kann. Alle Transaktionen, die in einer aktiven Redo-Log-Datei protokolliert sind, gehen verloren. Es ist einer der Fälle, die zu einer unvollständigen Wiederherstellung der Datenbank führen. Werden lediglich so viele Member aus Redo-Log-Gruppen verloren, so dass jede Gruppe noch mindestens ein verbleibendes und intaktes Member hat, zählt dies nicht unmittelbar als Verlust – die Instanz wird weiter funktionieren, und die Datenbank bleibt konsistent. Erst wenn eine Gruppe vollständig verloren ist, tritt der hier betrachtete Worst Case ein. Fehlermeldung z.B.: Tue Jun 1 10:26:03 2004 Errors in file /app/oracle/admin/JAUX10G/bdump/jaux10g_lgwr_3143.trc: ORA-00316: log 1 of thread 1, type 26997 in header is not log file ORA-00312: online log 1 thread 1: '/oradata/JAUX10G/redo01.log' Tue Jun 1 10:26:03 2004 LGWR: terminating instance due to error 316 Instance terminated by LGWR, pid = 3143
Zur Vermeidung dieses Falles ist es, wie bei der Vorbereitung der Datenbank beschrieben, unbedingt anzuraten, die Redo-Log-Dateien entweder mit OracleMitteln (mehrere Member pro Gruppe) oder über das Betriebssystem bzw. Controller zu spiegeln. Verlust der archivierten Redo-Log-Dateien Der Verlust der archivierten Redo-Log-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 ein Archivierungsprozess ARCn nicht mehr in sein Verzeichnis 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_1 = 'LOCATION=/oraarch2/JAUX10G/arch/';
Kein Stillstand tritt auf, wenn die Archivierung gespiegelt und die minimale Anzahl der erfolgreichen Destinationen nicht unterschritten wird oder nicht mandatorische Destinationen ausfallen.
Sicherung und Wiederherstellung
509
Sollte zu dem Verlust der archivierten Redo-Log-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.
10.2.5 Anwenderfehler Anwenderfehler sind aus Sicht der Wiederherstellung sehr problematisch. Bezeichnet wird damit das unbeabsichtigte Löschen, Ändern oder Hinzufügen von Tabellen oder Datensätzen. Je nachdem, ob und wie die Datenbank auf die Wiederherstellung vorbereitet ist, ist ein solcher Fehler schneller oder langsamer zu beheben. Es muss aber immer damit gerechnet werden, dass sich durch diesen Fehler logische Inkonsistenzen ergeben. Als Beispiel sei eine Anwendung genannt, welche die Anwendungslogik vollständig in einem Applikationsserver abbildet und daher in der Datenbank auf die Verwendung von Constraints verzichtet (z.B. SAP/R3). Das unbeabsichtigte Leeren einer Tabelle (TRUNCATE TABLE) kann nur über eine Rücksicherung der Tabelle wieder hergestellt werden. Dieses Backup ist jedoch nicht zeitaktuell, so dass abhängige Tabellen unter Umständen Einträge haben, die auf nicht mehr existierende Daten dieser Tabelle verweisen. Bei diesem Beispiel wird wieder einmal deutlich, wie wichtig die Verwendung von Constraints ist. Die Lösung des Problems hängt im Wesentlichen von der Zeit und den zur Verfügung stehenden Ressourcen ab. Fehlerhafte Batch-Jobs Bei Batch-Jobs (inklusive Spezialfällen von Batch-Jobs wie Datenmodell-Upgrades) kann es zu schwer korrigierbaren Fehlern kommen. Oft weiß man schon im Vorfeld, dass diese Gefahr besteht. Daher empfiehlt es sich, in diesem Fall vorsorglich Exports der betroffenen Tabellen zu machen oder Kopien an anderer Stelle in der Datenbank. In diesem Fall ist eine Rücksicherung sehr einfach durch ein RENAME möglich und der alte Zustand schnell wieder hergestellt. Die weiter unten besprochene Flashback-Database-Funktion kann hier ebenfalls weiterhelfen. Anwenderfehler DML-Operationen Der Zustand von Datensätzen vor DML-Operationen wird im Undo-Tablespace für eine gewisse Zeit in Form der Before Images gespeichert, so dass über die Flashback-Table-Funktion der alte Zustand wieder hergestellt werden kann. Sind die Daten nicht mehr im Undo-Tablespace, kann alternativ der LogMiner benutzt werden, um die Daten aus den Redo-Log-Dateien zu lesen.
510
Wiederherstellungstechniken
Anwenderfehler DROP TABLE Mit Oracle 10g wird mit dem Befehl DROP TABLE die Tabelle in der Regel nicht gelöscht, sondern umbenannt, und landet im Recyclebin. Wie beim Papierkorb von MS-Windows steht die Tabelle damit weiterhin zur Verfügung und kann über die Flashback-Table-Funktion wieder hergestellt werden. Anwenderfehler TRUNCATE TABLE Dieser Befehl wird zurzeit nicht über den Recyclebin abgesichert, so dass in diesem Fall, genau wie bei einem DROP TABLE ohne Recyclebin, eine aufwändige Wiederherstellung durchgeführt werden muss. Das kann z.B. ein TablespacePoint-in-Time-Recovery, ein Flashback-Database oder aber der Export der Tabelle aus einer Clone-Datenbank sein. Die Verfahren für Flashback-Database und Tablespace-Point-in-Time-Recovery werden im Folgenden beschrieben.
10.3
Der Recovery Manager
Nachdem Oracle viele Jahre keinerlei Werkzeuge für die Sicherung der Datenbank mitgeliefert hatte, gibt es seit Oracle8 den Recovery Manager.1 Mit ihm ist es 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-Sicherung, inkrementelle Sicherung, vollständige Wiederherstellung (bis zur letzten Transaktion) sowie unvollständige Wiederherstellung. Bedient wird der Recovery Manager über eine grafische Erweiterung des Enterprise Managers oder über das Kommandozeilenwerkzeug rman, das sich auch für die Batch-Verarbeitung über die crontab unter Unix oder den MS-Windows-AT-Befehl eignet. Die Eingabe von Kommandos erfolgt entweder interaktiv oder in Form von Skripten, die beim Aufruf mit dem Parameter CMDFILE angegeben werden können. Zur Verarbeitung stehen dann diverse Kommandos zum Erstellen und Zurückspielen von Sicherungen, für die Wiederherstellung, zum Abgleich der gespeicherten Informationen über Datenbankdateien mit der Situation auf dem Server sowie zur Erstellung von Listen und Berichten zur Verfügung. Ursprünglich wurden Kommandos zur Sicherung bzw. Rücksicherung immer in RUN-Blöcke zusammengefasst, die alle erforderlichen Aktionen zusammengefasst haben. Durch die Möglichkeit, diverse Optionen mit CONFIGURE-Befehlen für den Standardfall festzulegen, reduziert sich die Durchführung solcher Aktionen in den allermeisten Fällen auf einen einzigen Befehl. Da eine Blockstruktur hier keinen Sinn mehr macht, wird der RUNBlock denn auch als optional angesehen. Eine Eingabe von Befehlen wie STARTUP, SHUTDOWN und ALTER DATABASE ist ebenfalls im Recovery Manager möglich.
1
Das mit Oracle7 eingeführte Enterprise Backup Utility erwähnen wir absichtlich nur am Rande.
Der Recovery Manager
511
Die Sicherung erfolgt entweder auf die Festplatte oder über eine Media Management Library (MML2) auf ein Bandgerät. Es wird von Oracle hierfür der Legato Networker in einer Application Specific License (ASL3) mitgeliefert. Diese Version ist eingeschränkt dadurch, dass z.B. ausschließlich lokal angeschlossene Bandlaufwerke unterstützt werden. Der entscheidende Vorteil des Recovery Managers gegenüber selbst geschriebenen Sicherungsmethoden (Shell-Skripte usw.) ist zum einen die Integration in die Oracle-Datenbank, 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 Redo-Log-Dateien ein automatisches Löschen dieser Dateien veranlasst werden. 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 Block Logging, das gerade in großen Datenbanken für erheblich mehr Redo-Log-Informationen sorgt, entfällt somit.
Abbildung 10.5: Recovery-Manager-Architektur
2 3
MML = Media Management Library, eine Laufzeitbibliotheken zur Ansteuerung von Media-ManagementWerkzeugen, wie Tivoli Storage Manager mit Tivoli Data Protection for Oracle, Legato Networker usw. ASL = Application Specific License ist die Lizenzierung eines Produktes nur für einen ganz bestimmten Einsatz.
512
Wiederherstellungstechniken
10.3.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 Archive-LogModus befindet, ist der Enterprise Manager allerdings zu aufwändig. Hier genügt die Eingabe: rman target system/manager@<SID> RMAN> BACKUP DATABASE PLUS ARCHIVELOG DELETE INPUT; Listing 10.15: Recovery-Manager-Sicherung einer einfachen Datenbank
Damit wird die gesamte Datenbank inklusive der angefallenen archivierten RedoLog-Dateien in zwei Backup-Sets (eines für die archivierten Redo-Log-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. Durch die DELETE INPUTKlausel werden alle archivierten Redo-Log-Dateien nach der Sicherung automatisch gelöscht. Da während des Backups der Datenbank an dieser auch Strukturänderungen durchgeführt werden können, muss vom Recovery Manager sichergestellt werden, dass es einen definierten Zustand zum Sicherungszeitpunkt gibt. Dies erfolgt durch eine Kopie der Kontrolldatei als Snapshot-Kontrolldatei. Standardmäßig ist der Name der Snapshot-Kontrolldatei %ORACLE_HOME%\DATABASE\SNCF.ora unter MSWindows und $ORACLE_HOME/dbs/snapcf_.f unter Unix; dieser kann über den Befehl CONFIGURE SNAPSHOT CONTROLFILE NAME TO ... geändert werden. Damit ist für die Dauer der Sicherung bekannt, welche Datenbankdateien, Kontrolldateien, Online- und archivierten Redo-Log-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. Die Informationen über zu sichernden Dateien, aber auch über bereits gesicherte archivierte Redo-Log-Dateien, erhält der Recovery Manager in diesem Fall aus den Kontrolldateien. Da bei der ersten Sicherung oftmals nicht alle archivierten RedoLog-Dateien vorhanden sind (weil sie z.B. aufgrund von Platzmangel gelöscht wurden), ist es erforderlich, zunächst eine Prüfung der noch vorhandenen archivierten Redo-Log-Dateien vorzunehmen. Dies geschieht mit dem Befehl: RMAN> CROSSCHECK ARCHIVELOG ALL; Listing 10.16: Überprüfung der vorhandenen archivierten Redo-Log-Dateien
Der Recovery Manager
513
Damit wird ein Abgleich der Backup-Informationen in den Kontrolldateien hergestellt. Voraussetzungen Um eine Datenbank mit dem Recovery Manager sichern zu können, muss es möglich sein, sich mit dem SYSDBA-Privileg an der Datenbank anzumelden. Das bedeutet, dass für Anmeldungen über Oracle Net der Serverparameter remote_login_passwordfile auf exclusive oder shared gesetzt sein muss, und es muss eine 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 mit dem Recovery Manager an der entsprechenden Datenbank anmelden, zum Beispiel mit dem Befehl: rman TARGET system/manager@SUNDB
Der Aufruf des Recovery Managers lokal unter einem privilegierten Benutzer (Mitglied der Gruppe dba unter Unix oder Mitglied der Gruppe ORA_DBA unter Windows) funktioniert wie folgt: % rman taget / Listing 10.17: Lokaler Recovery-Manager-Aufruf
Der Recovery Manager ist abwärtskompatibel, d.h., Sie können mit dem Recovery Manager der Version 10 ältere Datenbanken sichern, nicht jedoch mit dem Recovery Manager der Version 9 eine Oracle 10g-Datenbank. 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 Redo-Log-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> RMAN> RMAN>
BACKUP BACKUP BACKUP BACKUP BACKUP BACKUP BACKUP BACKUP
ARCHIVELOG ALL; CURRENT CONTROLFILE FOR STANDBY; DATABASE; DATABASE PLUS ARCHIVELOG; DATAFILE ; RECOVERY AREA; SPFILE; TABLESPACE ;
Listing 10.18: Backup-Beispiele
514
Wiederherstellungstechniken
Dies sind nur einige Beispiele, die miteinander kombinierbar und erweiterbar sind. Anstelle der Namen für Datendateien und Tablespaces können auch deren Nummern (aus v$datafile bzw. v$tablespace) angegeben werden. 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 Backup-Sets. Ein Backup-Set stellt sich auf Betriebssystemebene als einzelne Datei dar und enthält meist mehrere Daten- oder Redo-Log-Dateien. Der Inhalt eines Backup-Sets ist zwar nicht komprimiert, seine Größe ist aber oft viel kleiner als die Gesamtgröße der enthaltenen Dateien. Das kommt daher, dass in Backup-Sets ausschließlich mit Daten-, Indexoder sonstigen wichtigen Strukturen belegte Blöcke gespeichert werden. Leere Blöcke oder Blöcke aus Temporär-Segmenten werden nicht gespeichert. Die Sicherung erfolgt entweder als Full Backup oder in verschiedenen Stufen als inkrementelles Backup. Full Backup Mit einem Full Backup ist in diesem Fall keine Sicherung der gesamten Datenbank gemeint, sondern die Sicherung aller genutzten Blöcke der zu sichernden Einheit (Datei, Tablespace usw.). 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 können die Dauer der Sicherung sowie die notwendigen Kapazitäten (Bandbreite des Netzwerkes oder Anzahl Bänder) minimiert werden. Die inkrementelle Sicherung bezieht sich nur auf Datendateien, nicht jedoch auf Kontroll- oder Redo-Log-Dateien. Beim inkrementellen Backup können unterschiedliche Backup-Level aufgebaut werden, um damit den notwendigen Speicherplatz zu minimieren, aber auch um zum Beispiel bei der Sicherung über ein Netzwerk die Netzwerkressourcen 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.
Der Recovery Manager
515
Das folgende Beispiel zeigt den Aufbau eines inkrementellen Backups, das für die meisten größeren Datenbanken ausreichend sein sollte. 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 Redo-Log-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;
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 Redo-Log-Dateien seit dem letzten Backup 4. Bei der Sicherung auf Festplatten sollten Sie beachten, dass zunächst eine Kopie der Datenbankdateien entsteht und erst zum Schluss das Backup-Set aufgebaut wird. FOR RECOVER OF COPY
5. Dem Vorteil der inkrementellen Sicherung – der Platzbedarf – steht der Nachteil gegenüber, dass für eine Rücksicherung bzw. Wiederherstellung eine Vollsicherung sowie eine oder mehrere inkrementelle Sicherungen eingespielt werden müssen. Mit der angegebenen Option ist es möglich, die Vollsicherung »vorzurollen«, d.h., wenn eine inkrementelle Sicherung erfolgt, wird diese mit der bestehenden Vollsicherung zu einer neuen, aktuellen Vollsicherung verbunden. Allerdings muss die Sicherung als Datendateikopie, also nicht als Backup-Set, erfolgen. Das folgende Beispiel soll dies verdeutlichen: RMAN> RUN { RMAN> RECOVER COPY OF DATABASE WITH TAG 'JAUX10G_inkrementell'; RMAN> BACKUP INCREMENTAL LEVEL 1 FOR RECOVER OF COPY WITH TAG 'JAUX10G_inkrementell' DATABASE; RMAN> } Listing 10.19: Datenbankkopie mit inkrementeller Sicherung
Bei der ersten Ausführung dieses Befehls wird eine Vollsicherung erstellt, d.h., der Befehl RECOVER COPY ... hat keinen Effekt. Bei der zweiten Ausführung wird eine inkrementelle Sicherung erstellt. Auch hier hat der Befehl RECOVER COPY ... keinen Effekt. Ab der dritten Ausführung wird die vorhergehende inkrementelle Sicherung mit der Vollsicherung zu einer neuen Vollsicherung zusammengeführt. Damit wird für das Rücksichern und Wiederherstellen lediglich die Vollsicherung und die letzte inkrementelle Sicherung benötigt.
516
Wiederherstellungstechniken
Change Tracking Für die Ermittlung der geänderten Datenbankblöcke ist es in der Regel erforderlich, die gesamte Datenbank zu durchsuchen, da für jeden Block die höchste SCN gesucht und mit der letzten Sicherung verglichen werden muss. Alternativ kann eine Datei erzeugt werden, in der die Liste der geänderten Blöcke gespeichert wird. Eingeschaltet wird Change Tracking mit folgendem Befehl: SQL> ALTER DATABASE ENABLE BLOCK CHANGE TRACKING USING FILE '/oradata/JAUX10G/change_tracking.ctf’; Listing 10.20: Einschalten von Change Tracking
Damit wird ein zusätzlicher Prozess4 gestartet, der die Informationen über geänderte Blöcke in die entsprechende Datei protokolliert. Die Datei hat anfangs eine Größe von 10 MB und erweitert sich bei Bedarf um weitere 10 MB. Laut Oracle ist die Größe von 10 MB für eine Datenbankgröße bis zu 1 TB und acht Stufen der inkrementellen Sicherung ausreichend. Backup-Sets Backup-Sets sind ein Oracle-eigenes Sicherungsformat, das entweder die Sicherung von einer oder mehreren Datenbankdateien oder eine Anzahl archivierter RedoLog-Dateien enthält, wobei leere Blöcke nicht mitgesichert werden. Während der Sicherung führt der Recovery Manager damit gleichzeitig eine Überprüfung der Blöcke durch. Eine Komprimierung der Backup-Sets mit Werkzeugen wie ZIP oder COMPRESS ist nicht zu empfehlen. Wenn ein Backup komprimiert werden soll, kann dies über die Option AS COMPRESSED BACKUPSET geschehen. Bei Komprimierungsfunktionen einer Tape-Library ist dieses der Recovery-Manager-Komprimierung vorzuziehen. Backup-Sets können aus einer oder mehreren Dateien (Backup-Pieces) bestehen, je nachdem, wie groß die Datenbank ist. Es werden jedoch immer die Datenbankdateien und die archivierten Redo-Log-Dateien in unterschiedlichen Backup-Sets gespeichert. Die Informationen, die in einem Backup-Set enthalten sind, werden in den Kontrolldateien der Datenbank und optional in einem Recovery-Katalog abgelegt. Das impliziert, dass eine komplette Sicherung der Datenbank immer auch eine Sicherung der Kontrolldateien enthalten sollte. Die Wiederherstellung der Kontrolldateien aus einem Backup-Set, die z.B. in einem Desasterfall notwendig ist, ist nur dann möglich, wenn ein Recovery-Katalog vorhanden ist, und auch in diesem Fall nur mit einer recht komplexen Vorgehensweise. Daher bietet es sich an, die Kontrolldateien getrennt zu sichern, so dass sie schnell wieder herstellbar sind. Die effektivste Möglichkeit hierfür ist, über den Parameter CONTROLFILE AUTOBACKUP ON diese Funktion generell einzuschalten. Hiermit werden nach jeder Sicherung sowohl die Kontrolldateien als auch das SPFILE in einer eigenen Einheit gesichert. In diesem Fall entfällt die Sicherung innerhalb des Backup-Sets.
4
Unter UNIX: ora_ctwr_
Der Recovery Manager
517
Der Befehl: BACKUP DATABASE PLUS ARCHIVELOG sichert die Datenbank standardmäßig in einem Backup-Set und die archivierten Redo-Log-Dateien in zwei weiteren (vor und nach der Datenbanksicherung). Über den Parameter PARALLELISM oder über explizite Allokation von Channels kann das Backup der Datenbank auch auf mehrere Backup-Sets erfolgen. Über den Befehl: RMAN> BACKUP NOT BACKED UP SINCE TIME ’SYSDATE – 7’ DATABASE;
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. Die Alternative zum Aufbau von Backup-Sets sind Image Copies, d.h. die ein Einszu-eins-Sicherung der physikalischen Dateien. RMAN> BACKUP DATABASE AS COPY; Listing 10.21: Erstellen einer Backup-Kopie der Datenbank
Channels Die Kommunikation mit einem externen Sicherungswerkzeug, aber auch die Speicherung auf einer anderen Platte erfolgt über 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. Ab der Version 9 ist es möglich, die Geräte und Channel 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 ein Channel vom Typ Disk genutzt, und die Sicherung erfolgt je nach Konfiguration in das Standardverzeichnis (MS-Windows %ORACLE_HOME\database) oder in die Flash-Recovery Area. 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
518
Wiederherstellungstechniken
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: – %a
Aktivierungs-ID der Datenbank
– %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
– %I
Datenbank-ID
– %M
Monat
– %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
– %%
%
4. Wie auch in den Vorgängerversionen kann die automatische Konfiguration mit dem Befehl ALLOCATE CHANNEL im RUN-Block ü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 10.22: Beispiel: Manuelle Channel-Allokation
Der Recovery Manager
519
5. 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 (Oracle Database 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 Sicherungen und einer eventuellen Wiederherstellung sowie die Speicherung von Skripten ermöglicht. Dabei werden alle relevanten Informationen (Lage und Name der Datendateien, Informationen über die archivierten Redo-Log-Dateien etc.) in einem Repository abgelegt und regelmäßig mit der zu sichernden Datenbank abgeglichen (siehe auch Abbildung 10.6: Recovery-Manager-Architektur). 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 Schemanamen für den Recovery-Katalog den Namen RMAN. Da es hierbei aber leicht zu Verwirrungen zwischen dem Befehl und dem Benutzer kommt, werden wir im Weiteren den Benutzer RMC (RMAN-Catalog) als Benutzer wählen. Das folgende Beispiel legt diesen Benutzer mit den erforderlichen Rechten an und erstellt dann den Katalog. SHELL% sqlplus system/manager@rmandb SQL> CREATE USER rmc IDENTIFIED BY mypwd DEFAULT TABLESPACE TOOLS; SQL> ALTER USER rmc QUOTA UNLIMITED ON TOOLS; SQL> GRANT RECOVERY_CATALOG_OWNER TO rmc; SHELL% rman CATALOG rmc/mypwd@rmandb RMAN> CREATE CATALOG; Listing 10.23: Erstellen eines Recovery-Katalogs
Zu beachten ist bei der Verwendung eines Recovery-Katalogs, dass die DatenbankID (DBID) eindeutig sein muss. Diese wird beim Aufbau der Datenbank generiert und ist somit bei allen Kopien, die z.B. für Data-Guard-Datenbanken erstellt werden, identisch. Eine solche Datenbank kann nur mit der FOR STANDBY-Option des Befehls DUPLICATE in das Repository eingetragen werden. Um eine Datenbank über den Recovery-Katalog zu verwalten, ist es somit notwendig, sich sowohl an der zu sichernden Datenbank als auch an dem Repository anzumelden. Dabei muss die Datenbank zunächst registriert werden, und von Zeit zu Zeit muss ein Abgleich der tatsächlichen Datenbankstruktur mit der im RecoveryKatalog verwalteten erfolgen (RESYNC).
520
Wiederherstellungstechniken
Das folgende Beispiel zeigt die Anmeldung sowie die Registrierung der Datenbank. Anschließend wird (überflüssigerweise) ein RESYNC durchgeführt. SHELL% rman catalog rmc/rmc@rmandb target sys/manager@JA10G RMAN> REGISTER DATABASE; RMAN> RESYNC CATALOG; Listing 10.24: Anmeldung an den Recovery-Katalog
Der Recovery-Katalog ändert sich mit der Datenbankversion. Daher kann er mit Hilfe des UPGRADE CATALOG-Befehls angepasst werden. Die Version des Recovery-Katalogs muss immer größer oder gleich der Version der zu sichernden Datenbank sein. Dabei kann er ohne Probleme in einer Datenbank liegen, deren Version wiederum unterschiedlich ist. Automatische Kontrolldateisicherung Diese Funktionalität beim Recovery Manager ab Version 9.0 erstellt automatisch eine Sicherung der Kontrolldatei nach jeder Sicherung mit dem Befehl BACKUP oder COPY. Falls vorhanden, wird das SPFILE dabei automatisch mitgesichert. Die beiden Dateien werden dann in einer eigenen Struktur gesichert. Diese Struktur ist kein Backup-Set. Standardmäßig ist die automatische Kontrolldateisicherung 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 Informationen für die notwendige Rücksicherung werden dann aus der automatischen Kontrolldateisicherung gewonnen, die als Erstes zurückzusichern ist. Die wiederhergestellte Kontrolldatei ist genau deshalb vollständig, weil sie genau nach der Erstellung des letzten Backup-Sets kopiert wurde! Es ist in jedem Fall anzuraten, die automatische Kontrolldateisicherung zu konfigurieren! 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 mit zu sichern, 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;
Der Recovery Manager
521
10.3.2 Sicherung Um das geeignete Sicherungsverfahren zu wählen, müssen zunächst die Randbedingungen geklärt werden. Diese sind im Folgenden: Größe der Datenbank Zeitraum der Sicherung Größe der Sicherung Online- oder Offline-Sicherung 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 erhält dann als Zusatz den Parameter CATALOG .... Vollständige Online-Sicherung der Datenbank Der einfachste Befehl für eine komplette Sicherung der Datenbank ist: RMAN> BACKUP DATABASE PLUS ARCHIVELOG DELETE INPUT;
Hierdurch wird automatisch vor und nach der Sicherung ein ALTER SYSTEM ARCHIVE LOG CURRENT durchgeführt. Die während der Sicherung angefallenen archivierten Redo-Log-Dateien werden zum Schluss ebenfalls gesichert. Danach werden alle gesicherten Redo-Log-Dateien gelöscht (DELETE INPUT). In diesem Fall stehen also keine archivierten Redo-Log-Dateien mehr auf dem System für eine schnelle Wiederherstellung zur Verfügung. Oftmals ist aber das Archivverzeichnis so eingerichtet, dass es möglich ist, die archivierten Redo-LogDateien für mehrere Tage online zur Verfügung zu halten, was im Bedarfsfall die Wiederherstellung natürlich wesentlich beschleunigt, da die Dateien nicht erst von Tape zurückgesichert werden müssen. In einer solchen Konstellation empfiehlt es sich, die Redo-Log-Dateien ein- oder zweimal zu sichern und nach einigen Tagen über den entsprechenden RMAN-Befehl zu löschen. Oracle bietet dazu folgende Möglichkeiten: 1. CONFIGURE BACKUP OPTIMIZATION ON; Mit diesem Parameter stellt der Recovery Manager sicher, dass nur noch die Dateien gesichert werden, die sich seit der letzten Sicherung verändert haben (sofern die RETENTION_POLICY auf 1 gesetzt ist) . 2. Explizite Angabe der zu archivierenden und zu löschenden Dateien
522
Wiederherstellungstechniken
RMAN> BACKUP ARCHIVELOG ALL NOT BACKED UP 2 TIMES; RMAN> DELETE ARCHIVELOG ALL COMPLETED AFTER ‘SYSDATE – 3’; Listing 10.25: Sicherung der archivierten Redo-Log-Dateien
Das folgende Beispiel konfiguriert den Recovery Manager für eine Sicherung auf Festplatte und führt anschließend die eigentliche Sicherung durch. Die Konfiguration wird nur einmal durchgeführt, da die entsprechenden Informationen in den Kontrolldateien abgelegt werden. Wenn anschließend ein Recovery-Manager-Katalog aufgebaut wird, werden die Informationen automatisch übernommen. rman target=system/manager@SUN10G RMAN> CONFIGURE DEFAULT DEVICE TYPE TO DISK; RMAN> CONFIGURE DEVICE TYPE DISK PARALLELISM 3; 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; RMAN> BACKUP ARCHIVELOG ALL NOT BACKED UP 2 TIMES; RMAN> DELETE ARCHIVELOG ALL COMPLETED AFTER ‘SYSDATE – 3’ Listing 10.26: Konfiguration und Sicherung einer Datenbank
Anschließend werden für die Sicherungen auf diese Art nur noch die letzten drei Befehle verwendet. Tipp: Mit dem Befehl SHOW ALL wird die Konfiguration des Recovery Managers angezeigt. Mit Drag & Drop kann man sich daraus die notwendigen Konfigurationsbefehle erstellen. Einzig der Befehl für die Konfiguration des Channels ist hier nicht abgelegt. Oracle empfiehlt, bei der Sicherung auf Platte immer eine Datenbankkopie zu erstellen und nicht mit Backup-Sets zu arbeiten. Der Hintergrund ist, dass dann ein RECOVER OF COPY genutzt werden kann. Es ist aber zu bedenken, dass eine Datenbankkopie mehr Platz beansprucht als ein Backup-Set. Sicherung mit Flash-Recovery Area Die Sicherung in die Flash-Recovery Area ist die Standardeinstellung des Recovery Managers, insofern diese konfiguriert ist. Es müssen dann keine weiteren Konfigurationen durchgeführt werden. Sollten Sie bereits mit dem Recovery Manager bestimmte Parameter eingestellt haben und wollen die Flash-Recovery Area nutzen, so ist es sinnvoll, diese Konfiguration wieder zurückzusetzen. RMAN> CONFIGURE CONTROLFILE AUTOBACKUP clear; RMAN> CONFIGURE CONTROLFILE AUTOBACKUP FORMAT clear; RMAN> CONFIGURE CHANNEL DEVICE TYPE DISK clear; Listing 10.27: Zurücksetzen von Recovery-Manager-Parametern
Jetzt kann die Sicherung in die Flash-Recovery Area erfolgen.
Der Recovery Manager
523
RMAN> BACKUP DATABASE PLUS ARCHIVELOG;
Im Verzeichnis /oraflash befinden sich jetzt folgende Dateien und Verzeichnisse: ./JAUX10G/archivelog/2004_08_06/o1_mf_1_1_0k75gyfc_.arc ./JAUX10G/archivelog/2004_08_06/o1_mf_1_2_0k75tjg1_.arc ./JAUX10G/archivelog/2004_08_06/o1_mf_1_3_0k7693bh_.arc ./JAUX10G/archivelog/2004_08_06/o1_mf_1_4_0k76j9b1_.arc ./JAUX10G/archivelog/2004_08_06/o1_mf_1_5_0k76nj14_.arc ./JAUX10G/archivelog/2004_08_06/o1_mf_1_6_0k773yd7_.arc ./JAUX10G/archivelog/2004_08_06/o1_mf_1_7_0k777qpn_.arc ./JAUX10G/archivelog/2004_08_06/o1_mf_1_8_0k77cfm1_.arc ./JAUX10G/autobackup/2004_08_06/o1_mf_s_533495072_0k77j3tx_.bkp ./JAUX10G/backupset/2004_08_06/o1_mf_annnn_TAG20040806T170207_0k7ckj8_.bkp ./JAUX10G/backupset/2004_08_06/o1_mf_nnndf_TAG20040806T170224_0k7d9p9_.bkp ./JAUX10G/backupset/2004_08_06/o1_mf_annnn_TAG20040806T170424_0k7ht5w_.bkp Listing 10.28: Sicherung in Flash-Recovery Area
Warum ist die Verwendung einer Flash-Recovery Area sinnvoll? In Kapitel 10.1.4 wurde die Größe der Recovery-Area auf 1 GByte festgelegt. Was passiert, wenn diese Grenze erreicht wird? Zunächst einmal überprüft der Archivierungsprozess, ob noch genügend Platz in der Recovery-Area vorhanden ist, ist dies nicht der Fall, werden ältere Sicherungen (Backup-Sets), die aufgrund der RETENTION POLICY nicht mehr gebraucht werden, gelöscht. JAUX10G; ARC1: Creating local archive destination LOG_ARCHIVE_DEST_1: '/oraflash/ JAUX10G/archivelog/2004_08_06/o1_mf_1_14_%u_.arc' (thread 1 sequence 14) ARCH: Connecting to console port... Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_annnn_TAG20040806T164743_0k76jlc5_.bkp Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_annnn_TAG20040806T164743_0k76jt7c_.bkp Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_nnndf_TAG20040806T164801_0k76k4lr_.bkp Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_ncsnf_TAG20040806T164801_0k76n615_.bkp Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_annnn_TAG20040806T164953_0k76nmrm_.bkp Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_annnn_TAG20040806T165807_0k7741xt_.bkp Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_nnndf_TAG20040806T165818_0k774dwc_.bkp Fri Aug 6 17:55:22 2004 JAUX10G; ARC1: Closing local archive destination LOG_ARCHIVE_DEST_1: '/oraflash/ JAUX10G/archivelog/2004_08_06/o1_mf_1_14_0k7bhbjh_.arc' ARCH: Connecting to console port... Committing creation of archivelog '/oraflash/JAUX10G/archivelog/2004_08_06/ o1_mf_1_14_0k7bhbjh_.arc' Created Oracle managed file /oraflash/JAUX10G/archivelog/2004_08_06/ o1_mf_1_14_0k7bhbjh_.arc Listing 10.29: Löschen der Backup-Sets durch den Archive-Prozess
524
Wiederherstellungstechniken
Umgekehrt überwacht auch der Recovey-Manager-Prozess die Flash-Recovery Area und löscht alte Backup-Sets. Dabei werden in der Alert-Datei entsprechende Einträge generiert, die aufgrund ihres umfangreichen Textes und der immer wiederkehrenden Warnungen (weniger als 15% verfügbarer Platz) bzw. Fehlermeldungen (weniger als 3% verfügbarer Platz) dazu führen können, dass diese Datei sehr groß wird. Sie sollte also von Zeit zu Zeit geleert werden. Mit der View dba_outstanding_alerts können diese Einträge außerdem ausgelesen werden. Die Einträge sehen z.B. folgendermaßen aus: ORA-19815: WARNING: db_recovery_file_dest_size of 1048576000 bytes is 99.63% used, and has 3872768 remaining bytes available. ************************************************************* You have the following choices to free up space from flash recovery area: 1. Consider changing your RMAN retention policy. If you are using dataguard, then consider changing your RMAN archivelog deletion policy. 2. Backup files to tertiary device such as tape using the RMAN command BACKUP RECOVERY AREA. 3. Add disk space and increase the db_recovery_file_dest_size parameter to reflect the new space. 4. Delete unncessary files using the RMAN DELETE command. If an OS command was used to delete files, then use RMAN CROSSCHECK and DELETE EXPIRED commands. ************************************************************* Deleted Oracle managed file /oraflash/JAUX10G/backupset/2004_08_06/ o1_mf_nnndf_TAG20040806T175900_0k7bp7z3_.bkp Listing 10.30: Auszug aus Alert-Datei für Flash-Recovery Area
Hier sieht man auch, dass der Recovery Manager nicht mehr aktuelle Sicherungen selbstständig löscht. Damit wird dieser Bereich jetzt sowohl vom Recovery Manager als auch vom Archive-Prozess überwacht und die Gefahr, dass das Verzeichnis nicht mehr ausreicht, minimiert. Sicherung der Flash-Recovery Area Es ist durchaus sinnvoll, eine Bandsicherung mit einer Sicherung in die Flash-Recovery Area zu kombinieren. Dabei wird zunächst eine Sicherung mit dem Recovery Manager in die Flash-Recovery Area durchgeführt und anschließend ebenfalls mit dem Recovery Manager die Flash-Recovery Area auf Band gesichert. Damit wird erreicht, dass der Plattenplatz optimal ausgenutzt wird (es stehen möglichst viele Informationen für eine schnelle Rücksicherung direkt zur Verfügung) und trotzdem eine regelmäßige Sicherung auf Bänder erfolgt. Außerdem ist es bei der Verwendung von inkrementellen Sicherungen oder der Verwendung der Komprimierung für Sicherungen sinnvoll, zunächst auf Festplatte zu sichern, da bei Bändern ein optimaler Durchsatz nur dann erreicht wird, wenn ein kontinuierlicher Datenstrom verfügbar ist.
Der Recovery Manager
525
Die Sicherung der Flash-Recovery Area auf ein Band erfolgt mit dem Befehl: RMAN> BACKUP RECOVERY AREA;
Damit ist diese Information im Recovery-Katalog bzw. in den Kontrolldateien der Datenbanken verfügbar. Damit können Sicherungen, die bereits auf Band ausgelagert worden sind, bei Bedarf überschrieben werden. Ein explizites Löschen der Backup-Sets in der Flash-Recovery Area kann also entfallen. Offline-Sicherung Bisher war die Rede davon, dass ein spezieller Befehl (z.B. BACKUP) ausgeführt wird und dieser eine Datenbank inklusive der archivierten Redo-Log-Dateien sichert. Um eine Offline-Sicherung bzw. die Sicherung einer Datenbank ohne archivierte Redo-Log-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 die Sicherung genutzt werden. SHELL% RMAN> RMAN> RMAN> RMAN>
rman system/manager@JA10G SHUTDOWN IMMEDIATE; STARTUP MOUNT; BACKUP DATABASE; ALTER DATABASE OPEN;
Listing 10.31: 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. Datenbankkopie 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. Dieses findet immer dann automatisch über den LGWR statt, wenn Datendateien mit anderen Mitteln online kopiert und die entsprechenden Tablespaces in den dafür erforderlichen BEGIN BACKUP-Modus gesetzt werden. Eine sehr effektive Methode zur Erstellung von Kopien einer kompletten Datenbank ist der Recovery-Manager-Befehl DUPLICATE. Damit wird die gesamte Datenbank auf dem Zielsystem aufgebaut, es wird eine neue Datenbank-ID vergeben, und es kann ein neuer Datenbankname benutzt werden. Die Datenbank wird automatisch wiederhergestellt und anschließend mit RESETLOGS-Option geöffnet. Voraussetzung hier für, dass es eine Revovery-Manager-Sicherung der Quelldatenbank gibt und diese auf dem Zielsystem eingelesen werden kann.
526
Wiederherstellungstechniken
Im Folgenden wird auf dem Zielsystem hltest eine Datenbank mit dem Namen WIN10G aus einer Produktionsdatenbank WIN10G auf dem Rechner hlserver erstellt. Es wird kein Recovery-Katalog benutzt. Auf dem Zielsystem liegen die Datenbankdateien in einer ASM-Instanz. Auf dem Quell- und Zielsystem wird die Datei tnsnames.ora so angepasst, dass auf beide Datenbanken zugegriffen werden kann. WIN10G = (DESCRIPTION = (ADDRESS_LIST = (GLOBAL_DBNAME = WIN10G) (ADDRESS = (PROTOCOL = TCP)(HOST = hlserver)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = WIN10G))) WIN10GDUP = (DESCRIPTION = (ADDRESS_LIST = (GLOBAL_DBNAME = WIN10G) (ADDRESS = (PROTOCOL = TCP)(HOST = hltest)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = WIN10G))) Listing 10.32: tnsnames.ora für DUPLICATE DATABASE
Jetzt wird auf dem Quellsystem eine Initialisierungsparameterdatei angelegt und auf das Zielsystem kopiert. Dort wird der Parameter für die Benutzung von ASM z.B. wie folgt angepasst: *.db_create_file_dest = '+WIN10G_ASM'
Auf dem Zielsystem (hltest) wird die Instanz jetzt im NOMOUNT-Status hochgefahren. Bei MS-Windows-Systemen muss vorher noch der entsprechende Dienst mit dem Befehl oradim erstellt werden. Für eine einfache Kopie ist es sinnvoll, dass das Backup-Verzeichnis für Quell- und Zielsystem identisch sind. Unter Unix-Systemen kann dies durch ein NFS-Mount sichergestellt werden, bei MS-Windows-Systemen durch ein Netzwerklaufwerk oder eine physikalische Kopie. Damit steht der Duplizierung der Datenbank nichts mehr im Wege. Zunächst erfolgt dafür die Anmeldung an die beteiligten Instanzen und dann der Aufruf des DUPLICATE-Befehls: % rman target sys/manager@WIN10G auxiliary sys/manager@WIN10GDUP connected to target database: WIN10G (DBID=4027871133) connected to auxiliary database: WIN10G (not mounted) RMAN> DUPLICATE TARGET DATABASE TO WIN10G;
Damit existiert eine neue Datenbank mit dem gleichen Inhalt wie die Produktionsdatenbank. Das gleiche Verfahren kann auch für die Erstellung einer StandbyDatenbank verwendet werden, dort muss dann Option FOR STANDBY beim DUPLICATEBefehl verwendet werden. In diesem Fall liegen die Kontrolldateien weiterhin in einem »normalen« Filesystem, also nicht unter einer ASM-Instanz. Die Methode, die im Verfahren Migrating a Database into ASM im Oracle Database Backup and Recovery Advanced User’s Guide
Der Recovery Manager
527
beschrieben ist, funktioniert in diesem Fall nicht. Wenn beim Anlegen der Initialisierungsdatei der Parameter control_files weggelassen wird, bricht der Kopierprozess bei dem Befehl CREATE CONTROLFILE ab mit der Oracle-Fehlermeldung ora-01276 Cannot add file .... File has an Oracle Managed Files file name. Es empfiehlt sich daher, nach erfolgreicher Duplizierung die Datenbank herunterzufahren. Danach wird der Parameter aus der Initialisierungsparameterdatei gelöscht und die Datenbank mit NOMOUNT hochgefahren. Mit dem Befehl RESTORE CONTROLFILE FROM kann dann eine ASM-Datei angelegt werden.
10.3.3 Rücksicherung und Wiederherstellung Solange es keine Probleme mit dem MML gibt, ist eine Wiederherstellung der Datenbank oder von Teilen davon sehr einfach. Mit dem Befehl RESTORE kann jeder beliebige Teil der Datenbank zurückgesichert werden. Im Folgenden werden exemplarisch einige Szenarien beschrieben. 1. Verlust eines Tablespaces Solange es sich nicht um den SYSTEM-Tablespace, einen Tablespace mit aktiven Rollback-Segmenten oder einen aktiven Undo-Tablespace handelt, kann die Wiederherstellung im laufenden Betrieb geschehen. RMAN> RMAN> RMAN> RMAN>
SQL "ALTER TABLESPACE users OFFLINE IMMEDIATE"; RESTORE TABLESPACE users; RECOVER TABLESPACE users; SQL "ALTER TABLESPACE users ONLINE";
Listing 10.33: Wiederherstellung eines Tablespace
2. Verlust einer Datendatei Auch hier gilt, dass die Wiederherstellung im laufenden Betrieb erfolgen kann, solange es sich nicht um den SYSTEM-Tablespace, einen Tablespace mit aktiven Rollback-Segmenten oder einen aktiven Undo-Tablespace handelt. SQL>
ALTER DATABASE DATAFILE 'e:/oradata/JA10G/users01.dbf' OFFLINE IMMEDIATE; RMAN> RESTORE DATAFILE 'e:/oradata/JA10G/users01.dbf'; RMAN> RECOVER DATAFILE 'e:/oradata/JA10G/users01.dbf'; SQL> ALTER DATABASE DATAFILE 'e:/oradata/JA10G/users01.dbf' ONLINE; Listing 10.34: 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. ORA-00202: Kontrolldatei: 'D:\ORACLE\ORADATA\JA10G\CONTROL03.CTL' ORA-27041: Offnen der Datei nicht möglich
528
Wiederherstellungstechniken
OSD-04002: Datei kann nicht geöffnet werden O/S-Error: (OS 2) Das System kann die angegebene Datei nicht finden.
Wenn die Datenbank mit mehreren Kontrolldateien aufgebaut wurde, reicht es in der Regel, eine noch vorhandene an die entsprechende Position der fehlerhaften zu kopieren. Sollten jedoch alle Kontrolldateien verloren gegangen sein, ist es notwendig, eine Rücksicherung mit anschließender unvollständiger Wiederherstellung durchzuführen. Da die Datenbank mit der Option RESETLOGS geöffnet werden muss, sollte anschließend eine neue Sicherung der Datenbank erfolgen. % sqlplus / as sysdba SQL> STARTUP NOMOUNT % rman target / RMAN> set DBID=4027871133 RMAN> SET CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO 'D:\orabackup\JA10G\JA10G_%F.ctl'; RMAN> RESTORE CONTROLFILE FROM AUTOBACKUP; RMAN> ALTER DATABASE MOUNT; RMAN> RECOVER DATABASE; RMAN> ALTER DATABASE OPEN RESETLOGS; Listing 10.35: Wiederherstellung der Datenbank nach Verlust aller Kontrolldateien
Wenn die Kontrolldateien nicht mehr vorhanden sind und kein Recovery-Katalog benutzt wird, muss die Datenbank-ID (DBID) bekannt sein und mit dem SET-Befehl gesetzt werden. Daher ist es sinnvoll, sich diese als Parameter mit abzuspeichern. In unserem Fall wurde diese ID als Bestandteil des Namens (%F) des Backups der Kontrolldatei gesichert. % dir D:\orabackup\JA10G JA10_C-4027871133-20040806-01.CTL
4. Verlust der gesamten Datenbank Es wird jetzt angenommen, dass die gesamte Datenbank inklusive der Kontrolldateien, archivierten Redo-Log-Dateien und Parameterdatei nicht mehr zur Verfügung steht. Wenn die Sicherung mit dem Recovery Manager durchgeführt wurde und der Parameter CONTROLFILE AUTOBACKUP ON gesetzt war, können alle Datenbankdateien und die Parameterdatei wieder hergestellt werden. Natürlich kommt es zu einem Datenverlust, da die Online-Redo-Log-Dateien nicht mehr zur Verfügung stehen. Zunächst wird eine Initialisierungsparameterdatei mit mindestens folgenden Parametern benötigt 5: db_name = JAUX10G control_files = /tmp/control01.ctl compatible = 10.1.0.2.0 Listing 10.36: Minimale Initialisierungsparameterdatei für die Rücksicherung
5
init.ora im Verzeichnis $ORACLE_HOME/dbs (Unix) bzw. %ORACLE_HOME%\DATABASE (MS-Windows)
Der Recovery Manager
529
Der Parameter control_files kann auf ein beliebiges Verzeichnis zeigen, da er zu einem späteren Zeitpunkt mit dem echten Parameter überschrieben wird. Leider muss der Parameter compatible so gesetzt werden, wie er als Initialisierungsparameter ursprünglich angegeben war. Ein fehlerhafter Eintrag führt zum Abbruch der Rücksicherung des SPFILES, dann erhält man aber den richtigen Wert und muss die Prozedur nochmals durchführen. Eine gute Empfehlung ist die getrennte Aufbewahrung der Initialisierungsparameterdatei bzw. des SPFILEs – dies erspart in hektischen Situationen fehleranfälliges Ausprobieren. Auch das »Merken« der DBID (vielleicht als Kommentar zu db_name) gehört dazu. Als Nächstes wird die Minimalinstanz gestartet und die Wiederherstellung der Kontrolldatei und des SPFILEs ausgeführt. % sqlplus "/ as sysdba" SQL> STARTUP NOMOUNT % rman target / RMAN> SET DBID=3291768378 RMAN> SET CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/orabackup/JAUX10G/ %F.ctl'; RMAN> RESTORE SPFILE FROM AUTOBACKUP; Listing 10.37: Wiederherstellung der Parameterdatei (SPFILE)
Danach muss die Instanz noch einmal beendet und mit den neuen Parametern gestartet werden. Dieser Vorgang sollte aus dem Recovery Manager heraus durchgeführt werden, denn dadurch behält man die eingestellten Werte (DBID und CONTROLFILE AUTOBACKUP). Ist dies geschehen, kann das Rücksichern der Datenbank und die Wiederherstellung erfolgen. RMAN> RMAN> RMAN> RMAN> RMAN> RMAN> RMAN>
SHUTDOWN; STARTUP NOMOUNT; RESTORE CONTROLFILE FROM AUTOBACKUP; ALTER DATABASE MOUNT; RESTORE DATABASE; RECOVER DATABASE; ALTER DATABASE OPEN RESETLOGS;
Listing 10.38: Wiederherstellung der Datenbank mit Recovery Manager
Abschließend sollte natürlich sofort eine neue Sicherung erstellt werden. 5. Wiederherstellung von Blöcken Neben der Möglichkeit, die gesamte Datenbank oder bestimmte Objekte (Tablespace oder Datendatei) wiederherzustellen, ist es seit der Version 9 möglich, auch einen einzelnen Block wiederherzustellen, wobei nur dieser Block während der Wiederherstellung gesperrt wird und die übrige Datenbank unangetastet bleibt. Dieser Vorgang ist dann sinnvoll, wenn durch einen Hardware- oder Betriebssystemfehler einige wenige Blöcke korrupt sind.
530
Wiederherstellungstechniken
Bei einer Sicherung mit dem Recovery Manager wird automatisch geprüft, ob 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/SUN10G/users01.dbf Listing 10.39: Blockkorruption
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 zunächst einmal ermittelt werden, welche Blöcke tatsächlich fehlerhaft sind. Normalerweise führen Zugriffe auf fehlerhafte Blöcke zu Trace-Dateien, die im Verzeichnis, das durch den Parameter user_dump_dest bestimmt wird, 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/SUN10G/users01.dbf’ Listing 10.40: Fehlermeldung Blockkorruption
Damit steht fest: Der Block Nummer 3 in der Datenbankdatei 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 eine Sicherung 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 eine Sicherung wie folgt aussehen: RMAN> run { set maxcorrupt for datafile 7 to 999; backup datafile '/oradata1/SUN10G/users01.dbf'; } Listing 10.41: Backup fehlerhafter Blöcke
Ü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 CURRUPT 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.
Der Recovery Manager
531
10.3.4 Berichte und Überprüfung Berichte Es gibt zwei wesentliche Befehle für die Erstellung von Berichten mit dem Recovery Manager. 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 Redo-Log-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 Überwachungsskripte: COLUMN COLUMN COLUMN COLUMN SELECT
FROM WHERE ORDER
set_stamp FORMAT 999G999G999 HEADING 'Id' backup_type FORMAT a20 HEADING 'Backup Art' start_time HEADING 'Startzeit' completion_time HEADING 'Beendet' set_stamp, decode(backup_type, 'D','Full', 'I','Incremental Level ' || incremental_level, 'L','Redologs', null) backup_type, start_time, completion_time v$backup_set start_time >= trunc(sysdate) - 7 BY start_time;
Listing 10.42: Überwachungsskript für den Recovery Manager
Überprüfung Es gibt beim Recovery Manager drei Arten der Überprüfung: 1. Datendateien und archivierte Redo-Log-Dateien können auf Fehler untersucht werden (z.B. korrupte Blöcke oder fehlende archivierte Redo-Log-Dateien) mit dem Befehl: RMAN> BACKUP VALIDATE DATABASE ARCHIVELOG ALL;
2. Die Sicherungen können mit dem Rücksicherungstest überprüft werden: RMAN> RMAN> RMAN> RMAN>
RESTORE RESTORE RESTORE RESTORE
DATABASE VALIDATE; TABLESPACE VALIDATE; ARCHIVELOG ALL VALIDATE; CONTROLFILE VALIDATE;
532
Wiederherstellungstechniken
3. Die Backup-Sets können überprüft werden: RMAN> VALIDATE BACKUPSET ;
10.3.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: 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;
3. 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 mit dem BACKUP-Befehl ermöglicht dies. 4. Das KEEP FOREVER ist allerdings nur möglich, wenn ein Recovery-Katalog verwendet wird, da die Informationen in den Kontrolldateien über den Serverparameter controlfile_record_keep_time gesteuert werden.
10.3.6 Verwaltung im Oracle Enterprise Manager 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. Dann stehen die folgenden Menüpunkte unter der Option WARTUNG zur Verfügung.
Der Recovery Manager
533
Abbildung 10.6: Oracle Enterprise Manager, Backup/Recovery
Über den Menüpunkt BACKUP-EINSTELLUNGEN KONFIGURIEREN wird die Konfiguration für Sicherungen vorgenommen.
Abbildung 10.7: Backup-Einstellungen
534
Wiederherstellungstechniken
Hierbei ist es direkt möglich, eine Sicherung zu testen. Unter dem Menüpunkt POLICY können weitere Konfigurationseinstellungen vorgenommen werden.
Abbildung 10.8: Konfigurationseinstellungen
Unter dem Menüpunkt BACKUP PLANEN kommt man zu einem Wizard, der ein Recovery-Manager-Skript für die tägliche Sicherung der Datenbank über den Enterprise Manager aufbaut.
Flashback Database
535
Abbildung 10.9: Backup planen
Damit wird eine physikalische Sicherung (kein Backup-Set) der Datenbank erstellt mit der inkrementellen Sicherung des letzten Tages und des »Vorwärtsrollens« der letzten Vollsicherung. Andere Sicherungsmethoden sind natürlich einstellbar, wie auch der Zeitpunkt, zu dem die Sicherung erfolgen soll.
10.4
Flashback Database
In einigen – hoffentlich seltenen – Fällen ist es notwendig, die gesamte Datenbank auf einen älteren Zustand zurückzusetzen. Dies kann zum Beispiel erforderlich sein, wenn ein Batch-Job Fehler produziert hat oder wenn ein beteiligtes System Inkonsistenzen feststellt, so dass ein gemeinsamer Wiederaufsetzpunkt gefunden werden muss. Oft wird auch das Zurücksetzten der gesamten Datenbank notwendig, wenn ein Update auf die Datenbankstrukturen eines Anwendungsschemas, z.B. im Rahmen eines Software-Updates, durchgeführt wird und fehlschlägt, weil etwa Constraints oder Indizes nicht wie geplant aufgebaut werden können.
536
Wiederherstellungstechniken
In der Vergangenheit war dies bei der Oracle-Datenbank nur durch ein vollständiges Rücksichern der Datenbank mit unvollständiger Wiederherstellung möglich. Da dieses Verfahren für große Datenbanken durchaus einige Stunden in Anspruch nehmen kann, stellt sich die Frage nach einer alternativen Methode, bei der nur die geänderten Blöcke wieder zurückgesetzt werden. Von Hardware-Herstellern gibt es schon länger die Möglichkeit, einen so genannten Snapshot von logischen Bereichen (LUNs) zu erstellen, die bei Bedarf den alten Zustand wieder herstellen. Dieses Verfahren ist allerdings recht teuer und nur bei bestimmten Hardware-Herstellern (z.B. EMC) möglich. Über die Flash-Recovery Area verfügt die Oracle 10g-Datenbank über eine Möglichkeit, alte Datenbankzustände zu speichern und im Zusammenspiel mit den archivierten Redo-Log-Dateien daraus jeden beliebigen Zeitpunkt wieder herzustellen, insofern dieser noch durch die Flash-Recovery Area abgedeckt wird. Voraussetzung für die Verwendung ist, dass eine Flash-Recovery Area konfiguriert ist und die Datenbank im Archive-Log-Modus arbeitet. Außerdem ist die Funktionalität auf die Enterprise Edition beschränkt. Mit dem Parameter db_flashback_retention_target wird angegeben, wie weit in die Vergangenheit die Änderungen aufbewahrt werden sollen. Dieser Parameter wird in Minuten (!) angegeben und steht standardmäßig auf 1440 (entspricht einem Tag). Flashback Database kann jetzt wie folgt eingeschaltet werden: SQL> SQL> SQL> SQL> SQL> SQL> SQL>
ALTER SYSTEM SET db_file_recovery_dest = '/oraflash'; ALTER SYSTEM SET db_file_recovery_dest_size = 10G; ALTER SYSTEM SET db_flashback_retention_target = 1440; SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE FLASHBACK ON; ALTER DATABASE OPEN;
Listing 10.43: Aktivieren der Flashback-Database-Funktion
Hierdurch wird ein zusätzlicher Prozess gestartet6, der den alten Zustand von geänderten Datenbankblöcken in die Flash-Recovery Area schreibt. Dieser Prozess wird bei der ersten Änderung eines Blockes aktiv sowie in regelmäßigen Abständen, wenn ein Block mehrfach geändert wird. Dadurch wird erreicht, dass eine Wiederherstellung mit wenigen Informationen aus den archivierten Redo-Log-Dateien möglich ist. Ein Flashback-Database-Szenario kann jetzt wie folgt aussehen: SQL> TRUNCATE TABLE kunden;
Der Anwender hat durch diesen Befehl die Applikation unbrauchbar gemacht. Eine Wiederherstellung mit Flashback-Query oder Flashback-Table ist nicht möglich, da sich die Struktur geändert hat. Die verbleibenden Möglichkeiten sind ein Tablespace-Point-in-Time-Recovery oder eben ein Flashback Database. 6
Unter Unix: ora_rvwr_
Flashback Database
537
Da für die Anwendung die Tabelle eine zentrale Rolle spielt und keine anderen Anwendungen mit dieser Datenbank arbeiten, entscheiden wir uns dafür, die Datenbank auf einen Stand vor diesem fatalen Befehl zurückzusetzen. Die erste Aufgabe besteht jetzt darin festzustellen, um welche Zeit (die SCN zu kennen ist unwahrscheinlich) der Befehl ausgeführt wurde. SQL> ALTER SESSION SET nls_date_format = 'DD.MM.YYYY HH24:MI:SS'; SQL> SELECT object_name, last_ddl_time FROM dba_objects WHERE object_name = 'KUNDEN'; OBJECT_NAME LAST_DDL_TIME ------------------------------ ------------------KUNDEN 11.08.2004 13:54:16 Listing 10.44: Ermitteln der Zeit des TRUNCATE-Befehls
Das funktioniert gut, wenn der Anwender nicht anschließend noch einen anderen DDL-Befehl für die Tabelle abgesetzt hat. Jetzt wird die Datenbank heruntergefahren und mit Mount gestartet. Bei Oracle Real-Application-Clusters müssen beide Instanzen gestoppt, eine Instanz muss danach exklusiv gestartet werden. Danach erfolgt das Flashback Database. SQL> SHUTDOWN IMMEDIATE; SQL> STARTUP MOUNT; SQL> FLASHBACK DATABASE TO TIMESTAMP TO_DATE('11.08.2004 13:54:11','DD.MM.YYYY HH24:MI:SS'); Listing 10.45: Flashback Database
Ob der Zeitpunkt optimal gewählt wurde, kann jetzt überprüft werden, indem die Datenbank im READ ONLY-Modus geöffnet wird. SQL> ALTER DATABASE OPEN READ ONLY;
Jetzt kann geprüft werden, ob die Daten in Ordnung sind. Sollten Daten fehlen, kann ein weiteres Recovery der Datenbank durchgeführt werden. Sollte der Fehler mit eingespielt worden sein, muss ein weiteres Flashback Database auf einen älteren Stand erfolgen. Bei der Wahl des Zeitpunkts sollte beachtet werden, dass es eine Unschärfe gibt, die bei ca. drei Sekunden liegt. Im Zweifelsfall ist ein Sicherheitspolster von einigen zusätzlichen Sekunden einzuplanen. Wenn das Flashback Database erfolgreich war, wird die Datenbank mit RESETLOGS geöffnet. Das bedeutet auch, dass es an dieser Stelle keinen Weg zurück gibt. Ein nochmaliges Flashback Database ist jetzt nicht mehr möglich. Mit dem Öffnen der Datenbank werden alle »alten« Flashback Logs automatisch gelöscht. Die FLASHBACK-Befehle können, wie im Beispiel, aus SQL*Plus heraus aufgerufen werden. Alternativ kann auch der Recovery Manager verwendet werden. Dieser hat den Vorteil, dass eventuell notwendige archivierte Redo-Log-Dateien oder Sicherungen der Flash-Recovery Area automatisch von Band eingespielt werden. Ansonsten unterscheidet sich die Syntax nicht.
538
Wiederherstellungstechniken
Die Möglichkeit, die Datenbank auf einen beliebigen älteren Zustand zurückzusetzen, hat jedoch ihre Grenzen. So ist die mit dem Parameter db_flashback_retention_ target angegebene Zeitdauer nicht zwingend. Wenn der Platz in der Flash-Recovery Area für andere Objekte (z.B. archivierte Redo-Log-Dateien) benötigt wird, werden die Flashback-Logs gelöscht, und somit besteht keine Möglichkeit mehr, die Datenbank auf einen älteren Zustand zurückzusetzen. Natürlich spielt auch die Frage eine Rolle, ob ein Zurücksetzen der Datenbank aufgrund anderer Anwendungen, die ja auch davon betroffen wären, möglich ist. Die Alternative hierzu ist das Tablespace-Point-in-Time-Recovery, das im Folgenden besprochen wird.
10.5
Tablespace-Point-in-Time Recovery (TSPITR)
Es muss sicherlich gut abgewogen werden, ob ein Flashback Database oder ein Tablespace-Point-in-Time-Recovery durchgeführt wird. Wenn die Flashback-Database-Funktionalität nicht eingeschaltet ist, erübrigt sich natürlich die Diskussion. Ansonsten ist ein Flashback Database sicherlich schneller als ein TSPITR, da in diesem Fall eine zweite (Auxiliary-)Datenbank aufgebaut werden muss und erst aus dieser heraus der Tablespace wieder erstellt werden kann. Außerdem muss zunächst überprüft werden, ob es irgendwelche Abhängigkeiten außerhalb des zurückzuspielenden Tablespace gibt (z.B. Primary Key Constraint, Materialized Views, Partitionen). Des Weiteren ist ein TSPITR nicht möglich nach einem DROP TABLESPACE Befehl. Als Beispiel soll wieder der Befehl TRUNCATE TABLE dienen, da dieser Befehl nicht über eine andere Aktion rückgängig gemacht werden kann. SQL> TRUNCATE TABLE kunden;
Mit der in Kapitel 10.4 gezeigten SQL-Anweisung kann jetzt herausgefunden werden, zu welchem Zeitpunkt der Befehl abgesetzt worden ist. Jetzt ist die Entscheidung gefallen, dass ein TSPITR des Tablespace ts_data erfolgen soll, da nur ein geringer Teil der Datenbank betroffen ist. Daher muss zunächst herausgefunden werden, ob es Abhängigkeiten in andere Tablespaces gibt. Hierfür gibt es die View ts_pitr_check.
Tablespace-Point-in-Time Recovery (TSPITR) SQL> SELECT * FROM ts_pitr_check WHERE TS1_NAME = 'TS_DATA' OBJ1_OWNER -----------------------------OBJ1_SUBNAME -----------------------------OBJ2_NAME -----------------------------OBJ2_OWNER -----------------------------CONSTRAINT_NAME ------------------------------
539
OBJ1_NAME -----------------------------OBJ1_TYPE TS1_NAME ---------------- -----------------------------OBJ2_SUBNAME OBJ2_TYPE ------------------------------ --------------TS2_NAME ------------------------------
REASON -------------------------------------------------------------------------------PROD KUNDEN TABLE TS_DATA PK_KUNDEN INDEX PROD USERS Tables and associated indexes not fully contained in the recovery set; Listing 10.46: TSPITR-Check
In diesem Fall ist also der Primärschlüsselindex in einem anderen Tablespace gespeichert und müsste ebenfalls zurückgesichert werden. Wir entscheiden uns alternativ dafür, den Index zu löschen und anschließend neu anzulegen. Damit steht der Wiederherstellung nichts mehr im Wege. RMAN> RECOVER TABLESPACE ts_data UNTIL TIME "to_date('17.08.2004 10:16:00','DD.MM.YYYY HH24:MI:SS')" AUXILIARY DESTINATION 'D:\oraaux\JA10GX';
Mit diesem Befehl wird jetzt im Verzeichnis 'D:\oraaux\JA10GX' eine Minimaldatenbank mit einer Kontrolldatei, zwei Redo-Log-Dateien, dem SYSTEM- und dem UndoTablespace aufgebaut. In der Produktionsdatenbank (JA10G) wird der Tablespace ts_data offline gesetzt und die Datendatei 'D:\oracle\oradata\JA10G\ts_data01.dbf' aus der Sicherung überschrieben. Dies ist ein kritischer Punkt, denn dieser Tablespace muss jetzt in jedem Fall, auch wenn das TSPITR fehlschlägt, wiederhergestellt werden. db_name=JA10G compatible=10.1.0.2.0 db_block_size=8192 db_unique_name=tspitr_JA10G_CfsD large_pool_size=1M #No auxiliary parameter file used db_create_file_dest=D:\oraaux\JA10GX control_files=D:\oraaux\JA10GX/cntrl_tspitr_JA10G_CfsD.f Listing 10.47: TSPITR-Instanzparameter
540
Wiederherstellungstechniken
Anschließend wird die Interimdatenbank gestartet und bis zum TSPITR-Zeitpunkt wiederhergestellt. Aus dieser Datenbank wird dann ein Export der Objektinformationen durchgeführt. Dafür gibt es sowohl beim Export als auch beim Import einen Parameter point_in_time_recovery, der allerdings scheinbar nirgendwo dokumentiert ist. Mit dieser Exportdatei wird dann die Information im Data Dictionary der Produktionsdatenbank überschrieben. Als Letztes wird die Interimsdatenbank wieder heruntergefahren, und sämtliche Datendateien werden gelöscht. In der Produktionsdatenbank muss der entsprechende Tablespace allerdings manuell wieder online gesetzt werden. SQL> ALTER TABLESPACE ts_data ONLINE;
In unserem Fall müsste jetzt als letzter Punkt noch der Primärschlüsselindex neu angelegt werden. Durch diesen vollständigen Automatismus ist ein TSPITR sicherlich einfach durchzuführen. Dennoch sollte beachtet werden, dass es sich hierbei um eine absolute Notlösung handelt, da in der Regel nicht davon auszugehen ist, dass es keine Abhängigkeiten außerhalb eines Tablespace gibt. Außerdem dauert es natürlich bei großen Datenbanken einige Zeit, bis die Interimsdatenbank aufgebaut und bis zum vorgesehenen Punkt vorgespielt worden ist. Auch der zusätzliche Platzbedarf für die Interimsdatenbank sollte nicht unterschätzt werden. Alternativ zu dem hier beschriebenen Verfahren kann auch eine manuelle Konfiguration erfolgen. Dabei wird eine eigenständige Datenbank aufgebaut und dann über die Funktion der transportablen Tablespaces in der Produktion ausgetauscht. Dieses Verfahren bietet sich an, wenn es z.B. eine Data-Guard-Datenbank gibt.
10.6
Objektbasierte Techniken
10.6.1 Data Pump Data Pump ist ein neues Werkzeug, das direkt zur Datenbank-Software gehört. Es besteht aus einem serverseitigen Teil (dem Package dbms_datapump) sowie den beiden Kommandozeilenwerkzeugen expdp und impdp (Data Pump Export und Data Pump Import), die als Clients die Benutzerschnittstelle zum serverseitigen Teil bilden. Beide Werkzeuge sind stark an die schon länger existierenden Tools exp und imp (konventioneller Export und Import, siehe Abschnitt Export und Import) angelehnt. Data Pump ist als Nachfolger dieser Werkzeuge anzusehen. Mit Data Pump Export alleine können Sicherungen, in Zusammenarbeit mit Data Pump Import aber auch versions- und plattformübergreifende Migrationen und Reorganisationen einzelner Objekte, Benutzer, Tablespaces oder auch der ganzen Datenbank erstellt werden.
Objektbasierte Techniken
541
Unterschiede zum konventionellen Export/Import Während beim konventionellen Export/Import sämtliche I/O-Aktivität (Schreiben/Lesen von Dump-Dateien) clientseitig stattfindet, dient bei Data Pump der Client lediglich als Kommando-Schnittstelle für den Benutzer. Die eigentliche Arbeit (I/O-Aktivität) findet ausschließlich auf dem Server selbst statt. Dadurch müssen die Daten nicht mit Oracle Net über das Netzwerk übertragen werden, was ansonsten immer ein Performance-Problem darstellte. Soll in eine andere Datenbank importiert werden, müssen die Dump-Dateien mittels Betriebssystemkommandos wie ftp, scp usw. übertragen werden. Die Übertragung wurde also vollkommen vom Export/Import entkoppelt und ist somit davon unabhängig. Der Benutzer kann nicht zwischen konventionellem und direktem Pfad wählen. Sowohl für den Data-Pump-Export als auch für den Data-Pump-Import wird – soweit möglich – stets der direkte Pfad benutzt. Insbesondere für den Import stellt dies eine erhebliche Beschleunigung dar. Data Pump arbeitet joborientiert. Export- und Importvorgänge können unterbrochen, umparametriert und wieder aufgenommen werden. Eine Parallelisierung des Jobs durch mehrere Slave-Prozesse ist möglich. Diese Funktion ist allerdings auf die Enterprise Edition beschränkt. Metadaten werden nicht als DDL-Skript, sondern in einer XML-Darstellung abgespeichert. Dadurch werden Anpassungen beim Import (Änderung von Tabellennamen oder Tablespaces etc.) erleichtert. Bei der Parametrierung der Kommandozeilenwerkzeuge wurde »aufgeräumt«. Leider sind die Dump-Dateien von Data Pump bzw. konventionellem Export/ Import nicht miteinander kompatibel. Mit dem einen Werkzeug erstellte DumpDateien können also mit dem anderen Werkzeug nicht verwendet werden. Einige neue Features der Oracle-Version 10g werden nur von Data Pump unterstützt, wohingegen Export/Import seit Oracle9i nicht mehr weiterentwickelt wurde. Allerdings kann Data Pump wegen des serverseitigen Zugriffs auf das Package dbms_datapump auch ausschließlich mit Oracle 10g-Datenbanken verwendet werden. Architektur Data Pump ist jobgesteuert, d.h., es gibt eine Konfigurationsphase, in der ein Name für den Data-Pump-Job vergeben und festgelegt wird, was zu tun ist (Export oder Import, welche Daten etc.) sowie eine Ausführungsphase, während welcher der eigentliche Export/Import läuft. Letztere kann beliebig oft unterbrochen und wiederaufgenommen oder auch vorzeitig abgebrochen werden. Eine Fortschrittsanzeige steht ebenfalls zur Verfügung. Achtung: Data-Pump-Jobs sind unabhängig von benutzerdefinierten Datenbank-Jobs, die mittels dbms_job oder dem Scheduler definiert werden können (siehe Abschnitt 6.2).
542
Wiederherstellungstechniken
Die gesamte Konfiguration und Steuerung wird über die Client-Programme expdp und impdp durchgeführt. Datenbankseitig wird die eigentliche Arbeit durch so genannte Worker-Prozesse geleistet. Diese sind Oracle-Hintergrundprozesse mit den Bezeichnungen DWnn, wobei nn für eine Zahl von 00 bis 99 steht. Wie viele Worker-Prozesse an dem Job arbeiten, also der Parallelisierungsgrad des Jobs, kann jederzeit vor und während der Job-Ausführung eingestellt bzw. geändert werden. Für jeden Data-Pump-Job gibt es außerdem einen Master-Prozess DMnn, der in regelmäßigen Intervallen die aktuelle Job-Konfiguration ausliest und entsprechend die Arbeit der Worker-Prozesse koordiniert und protokolliert. Dieses Protokoll bildet auch die Grundlage für die Fortschrittsanzeige des Jobs. Technisch ist es als Tabelle implementiert, die bei der Definition des Jobs automatisch im Schema des aufrufenden Benutzers erstellt wird und für die Dauer des Jobs existiert. Diese Tabelle heißt auch Master-Tabelle und trägt denselben Namen wie der Job. Achtung: Dies bedeutet in der Tat, dass Tabellen und Data-Pump-Jobs in demselben Namensraum liegen, d.h., ein neu zu definierender Data-Pump-Job darf nicht den Namen einer bereits existierenden Tabelle tragen. Nach erfolgreicher Beendigung oder explizitem Abbruch des Jobs wird die MasterTabelle automatisch gelöscht. Bei einem automatischen Unterbrechen oder einem Absturz des Jobs bleibt sie hingegen erhalten und kann zum Wiederanstarten des Jobs genutzt werden. Ist Letzteres nicht gewollt, muss sie allerdings manuell gelöscht werden. expdp oder impdp
Client Server Master-Tabelle DataPump API (DBMS_ DATAPUMP)
- Tabellen - Views - etc.
DW01 DW02 DW03
LogDatei DumpDatei DumpDatei DumpDatei
...
Metadata API (DBMS_ METADATA)
DB-Objekte:
DM01
Worker-Pool
Vorbereitungen Da alle beteiligten Dateien im Dateisystem des Servers liegen bzw. dort erstellt werden, muss zunächst sichergestellt werden, dass Schreib- bzw. Leseberechtigungen für diese Dateien bestehen. Dabei handelt es sich in jedem Fall um die DumpDatei(en) mit den Daten sowie um Log-Dateien zur Protokollierung. Optional kann auch ein SQL-Skript geschrieben werden (siehe unten). Die Zugriffsrechteverwaltung hierfür geschieht über Directory-Objekte. Diese werden in der Datenbank definiert und stellen einfach einen Aliasnamen für ein Datei-
Objektbasierte Techniken
543
systemverzeichnis dar, über den das Verzeichnis aus der Datenbank heraus zugänglich gemacht wird. Für Directory-Objekte siehe auch Abschnitt 5.7. Ein entsprechendes Directory-Objekt muss zunächst durch einen DBA oder einen Benutzer mit dem Systemprivileg CREATE ANY DIRECTORY erstellt werden. Wenn regelmäßig Daten via Data Pump unter Benutzung derselben Dump-Datei übertragen werden, ist dies natürlich ein einmaliger Vorgang. SQL> CREATE DIRECTORY pumpdir AS 'C:\dpump';
Anschließend müssen dem Data-Pump-Aufrufenden Lese- bzw. Schreibrechte auf dem Directory zugewiesen werden. SQL> GRANT READ, WRITE ON DIRECTORY pumpdir TO schwanke;
Achtung: Für das Verzeichnis mit der Log-Datei werden in jedem Fall Schreibrechte benötigt, für das Verzeichnis mit den Dump-Dateien kann ggf. auf Nur-Lese- bzw. Nur-Schreib-Zugriff beschränkt werden. Für das Verzeichnis mit den Dump-Dateien kann auch ein ASM-Pfad angegeben werden, z.B.: SQL> CREATE DIRECTORY pumpdir AS '+DATAFILES/';
Sollen Objekte aus einem anderen Schema exportiert werden, wird außerdem die Rolle EXP_FULL_DATABASE benötigt. Beim Import wird entsprechend die Rolle IMP_FULL_DATABASE benötigt. Data Pump Export Der Data-Pump-Export kennt vier verschiedene Granularitäten: TABLE: In dieser Variante werden einzelne Tabellen und/oder Partitionen sowie abhängige Objekte, d.h. Indizes, Constraints, Trigger und Objektprivilegien, zu den betreffenden Tabellen exportiert. SCHEMA: Diese Granularität wird benutzt, um alle Datenbankobjekte eines Benutzers, also sein vollständiges Schema (Tabellen, Views, Synonyme, PL/SQL-Objekte etc.), zu exportieren. FULL: Mit dieser Variante wird die gesamte Datenbank exportiert, also alle Benutzer, aber auch beispielsweise Tablespace-Definitionen, Rollen, DirectoryObjekte und Public-Synonyme, also Objekte, die nicht einem bestimmten Benutzer zugeordnet werden können. Dieser Modus ist z.B. für plattformübergreifende Migrationen nicht zu großer Datenbanken interessant. TABLESPACE: Hiermit werden alle Tabellen eines Tablespace inklusive ihrer abhängigen Objekte exportiert. Welche Granularität benutzt wird und welche Objekte in der gewählten Einheit berücksichtigt werden, wird über die Parametrierung des Data Pump Exports ausgewählt, ebenso wie der Name der Export-Dump-Datei und einiges mehr. Ein Data-Pump-Export wird beispielsweise durch folgenden Aufruf gestartet: $ expdp schwanke@ps10 directory=pumpdir dumpfile=myexp.dmp logfile=myexp.log schemas=schwanke job_name=myexpjob
544
Wiederherstellungstechniken
Dieser Aufruf definiert einen Data-Pump-Job mit dem Namen myexpjob und konfiguriert diesen, alle Objekte des Benutzers schwanke in die Dump-Datei myexp.dmp im Verzeichnis pumpdir zu exportieren (das Directory-Objekt pumpdir muss existieren). Alle Bildschirmausgaben sollen in die Log-Datei myexp.log in demselben Verzeichnis geschrieben werden. Anschließend wird der Job gestartet. Die Liste aller Parameter, von denen einige Standardeinstellungen haben, bekommt man durch den Aufruf: $ expdp help=y
Data-Pump-Export kann wahlweise auf zwei verschiedene Arten gestartet werden: im Zeilenmodus oder unter Verwendung einer Parameterdatei. Im Zeilenmodus werden die Parameter direkt beim Aufruf eingegeben so wie im obigen Beispiel. 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. $ expdp parfile=parameterdatei.par
Im Folgenden werden die wichtigsten Exportparameter vorgestellt. Einige Parameter können nur die Werte 'Y' oder 'N' annehmen. In diesem Fall wird der Parameter als gesetzt oder nicht gesetzt bezeichnet. Exportparameter
Bedeutung
JOB_NAME
Der Name des Jobs wird als Handle für weitere Bezugnahmen auf den Job (via ATTACH, siehe unten) verwendet. Außerdem entspricht er dem Namen der Master-Tabelle. Die Maximallänge beträgt 30 Zeichen.
DUMPFILE
Eine feste Liste von Dump-Dateien der Form [:], ...
Der Default ist SYS_EXPORT__
Bspw. pumpdir:exp01.dmp, pumpdir:exp02.dmp Oder eine dynamische Liste unter Verwendung der Substitutionsvariablen %U (wird der Reihe nach in 00, 01 … 98, 99 expandiert). Z.B. liefert exp%U.dmp maximal 100 Dump-Dateien. FILESIZE
Maximale Größe jeder Dump-Datei (Suffixe K,M,G sind möglich). Beispiele: 100000000; 100M; 1G
LOGFILE, NOLOGFILE
Name der Log-Datei: [:] Ist NOLOGFILE gesetzt, wird keine Log-Datei geschrieben
DIRECTORY
Default-Directory-Objekt für DUMPFILE und LOGFILE
Tabelle 10.1: Parameter für den Data Pump-Export
Objektbasierte Techniken
545
Exportparameter
Bedeutung
TABLES
Liste zu exportierender Tabellen und/oder Partitionen, jeweils in der Form [Schema.]Tabelle[:Partition], z.B. (KUNDEN,AUFTRAEGE, AUFPOSITIONEN). Impliziert die Granularität TABLE. Für jede Tabelle werden auch zugehörige abhängige Objekte (Constraints, Indizes, Trigger, Grants) exportiert.
SCHEMAS
Liste der zu exportierenden Benutzer, z.B. (SCHWANKE,AHRENDS). Impliziert die Granularität SCHEMA.
TABLESPACES
Liste der zu exportierenden Tablespaces (nur bei Granularität TABLESPACE)
FULL
Granularität FULL, falls gesetzt
CONTENT
Umfang des Exports: METADATA_ONLY (Objektdefinitionen), DATA_ONLY (Daten) oder ALL (beides). ALL ist Default.
QUERY
Export einer Teilmenge der Daten (siehe unten)
INCLUDE, EXCLUDE
Export einer Teilmenge der Objekte (siehe unten)
Tabelle 10.1: Parameter für den Data Pump-Export (Forts.)
Einige der vorgestellten Parameter sollen an dieser Stelle noch genauer erläutert werden: QUERY
Um nur eine Teilmenge einer oder mehrerer Tabellen auszulesen, z.B. alle Produkte, die mit 'A' beginnen, kann pro Tabelle eine Filterbedingung in Form einer WHEREKlausel mitgegeben werden. $ expdp schwanke@ps10 directory=pumpdir dumpfile=myexp.dmp logfile=myexp.log schemas=schwanke job_name=myexpjob query=kunden:"WHERE kd_nr > 5" query=produkte:"WHERE prod_name LIKE 'A%'"
Die WHERE-Klausel wird in doppelte Hochkommata eingeschlossen, da Leerzeichen innerhalb der Klausel auftreten. Je nach Betriebssystem und verwendeter Kommando-Shell müssen die doppelten Hochkommata noch mit Escape-Zeichen versehen werden. Achtung: Aus der Exportdatei ist anschließend nicht mehr ersichtlich, dass der Export mit Filterbedingungen ausgeführt wurde. Außerdem verhindert dieser Parameter die Verwendung des direkten Pfads (siehe unten). INCLUDE, EXCLUDE
Mit diesen beiden Parametern kann genauer eingegrenzt werden, welche Objekte und/oder Objekttypen exportiert werden sollen. Damit wird die recht große Lücke zwischen dem feingranularen Tabellenexport und dem schon relativ groben Schemaexport geschlossen.
546
Wiederherstellungstechniken
Beispielsweise bewirkt folgende Parametrierung, dass ausschließlich Tabellen und Primärschlüsselindizes (per Konvention enden diese auf PK) exportiert werden: $ expdp ... INCLUDE=TABLE INCLUDE=INDEX:"LIKE '%PK'"
Um alles außer Constraints zu exportieren, genügt folgende Parametrierung: $ expdp ... EXCLUDE=CONSTRAINT
Die Dump-Datei(en) wird (werden) durch den Data-Pump-Export erstellt und dürfen vorher nicht existieren. Dies bedeutet, dass z.B. unter Unix keine Named Pipes als Dump-Datei verwendet werden können. Die Möglichkeit einer gleichzeitigen Komprimierung oder Übertragung via ftp oder scp (siehe konventioneller Export/ Import) ist mit Data Pump daher nicht gegeben. Eine Alternative, um zumindest Export- und Übertragungsvorgang zu parallelisieren, wird weiter unten beschreiben. Data-Pump-Import Import kann Data-Pump-Exportdateien lesen und logisch gesicherte Datenbankstrukturen und -objekte wiederherstellen. Genau wie Data-Pump-Export kann Data-Pump-Import im Zeilenmodus oder mit einer Parameterdatei betrieben werden. Der Import muss nicht durch denselben Benutzer durchgeführt werden, der den Export durchgeführt hat. Alle beschriebenen Exportparameter außer FILESIZE finden sich mit analoger Bedeutung auch beim Import. Einige wichtige importspezifische Parameter werden im Folgenden vorgestellt: Importparameter
Bedeutung
TABLE_EXISTS_ACTION
Was passiert, wenn eine zu importierende Tabelle bereits vorhanden ist? SKIP (keine Aktion, Default), APPEND (Daten werden eingefügt), TRUNCATE (der Tabelleninhalt wird ersetzt) oder REPLACE (die Tabelle wird gelöscht und neu erstellt)
REMAP_SCHEMA
REMAP_SCHEMA=SCHWANKE:AHRENDS bewirkt, dass alle exportierten Objekte des Benutzers SCHWANKE in das Schema AHRENDS importiert werden. Der Parameter kann beliebig oft vorkommen.
REMAP_TABLESPACE
REMAP_TABLESPACE=TOOLS:USERS bewirkt, dass alle TablespaceKlauseln entsprechend angepasst werden. Der Parameter kann beliebig oft vorkommen.
Tabelle 10.2: Zusätzliche Parameter für den Data-Pump-Import
Benutzung des direkten Pfads Beim so genannten 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. Wie groß die Performance-Vorteile sind, ist von der Datenbankblockgröße und der IO-Bandbreite abhängig.
Objektbasierte Techniken
547
Analog wird es bei einem Direct-Path-Import ermöglicht, direkt in freie Blöcke zu schreiben, ohne über die SGA zu gehen, auch hier mit deutlichen PerformanceGewinnen. Sowohl Data-Pump-Export als auch Data-Pump-Import benutzen – wenn möglich – den direkten Pfad, was insbesondere beim Import einen erheblichen Performance-Gewinn gegenüber dem konventionellen Import darstellt, der dazu nicht fähig ist. In einigen Fällen ist jedoch kein Direct-Path-Import möglich, nämlich bei: Tabellen mit aktiven (enabled) Fremdschlüssel-Constraints Tabellen mit aktiven (enabled) Triggern Tabellen mit Regeln für Fine Grained Access für Einfüge-Operationen Tabellen, die anders partitioniert sind als während des Exports Weitere, seltene Ausnahmen sind in der Dokumentation aufgeführt. Wenn eine dieser Ausnahmebedingungen erfüllt ist, wird die Dump-Datei als externe Tabelle behandelt. Der Zugriffstreiber ORACLE_DATAPUMP ist in der Lage, das Data-Pump-Dateiformat zu lesen. Anschließend wird der konventionelle Pfad für den Import benutzt. Der Benutzer hat keinen Einfluss darauf, welcher Pfad genutzt wird; Data Pump entscheidet dies autonom. Wegen des Performance-Verlusts sollte abgeklärt werden, ob es nicht möglich ist, Fremdschlüssel und Trigger vor dem Import und für die Dauer des Imports zu deaktivieren. Monitoring von Data-Pump-Jobs Alle
aktiven
Data-Pump-Jobs
können
über
die
Data-Dictionary-View
dba_datapump_jobs identifiziert werden. Hier sind alle Jobs zu sehen, solange sie
nicht erfolgreich beendet oder abgebrochen wurden, insbesondere also auch abgestürzte oder explizit unterbrochene Jobs. Die Spalte state gibt den aktuellen Status des Jobs wieder. SELECT FROM WHERE AND
operation, job_mode, state, degree dba_datapump_jobs owner_name = 'SCHULUNG' --Benutzer job_name = 'MYEXPJOB'; --Jobname
Während des eigentlichen Imports oder Exports wird außerdem eine Fortschrittsprotokollierung über die View v$session_longpos gepflegt. Die Spalten sofar und totalwork geben an, wie viele Daten schon übertragen wurden und wie viel insgesamt übertragen werden muss. SELECT FROM WHERE AND
target_desc, sofar, totalwork, units v$session_longops username = 'SCHULUNG' --Benutzer opname = 'MYEXPJOB'; --Jobname
548
Wiederherstellungstechniken
Administration laufender Data-Pump-Jobs Über die Client-Utilities expdp und impdp ist es auch möglich, sich jederzeit während der Lebenszeit eines Jobs in diesen Job »einzuklinken«, z.B. um festzustellen, warum der Job unterbrochen wurde, ggf. Umparametrierungen vorzunehmen und den Job anschließend wiederaufzunehmen. Durch den Aufruf $ expdp schwanke@ps10 attach=myexpjob
wird eine einfache Kommandozeilen-Shell gestartet, über die der Job mit dem Namen myexpjob jederzeit administriert werden kann. In diesem »interaktiven Modus« läuft der Job im Hintergrund weiter (sofern er nicht gerade gestoppt wurde), die üblichen Fortschrittsmeldungen werden jedoch nicht ausgegeben. Stattdessen stehen innerhalb dieser Shell folgende Kommandos zur Verfügung: STOP_JOB, START_JOB, KILL_JOB: Damit lässt sich der Job anhalten, wiederaufnehmen bzw. endgültig abbrechen. PARALLEL= ändert den Parallelisierungsgrad des Jobs ADD_FILE=[:] ist nur für Export-Jobs verfügbar und bewirkt, dass eine weitere Dump-Datei zur Ausgabe benutzt werden kann. Dieses Kommando wird z.B. benutzt, nachdem ein Job wegen Platzmangels in den Dump-Dateien unterbrochen ist. STATUS gibt den aktuellen Status des Jobs aus. Über STATUS= wird dies alle Sekunden ausgegeben. Über das Kommando EXIT_CLIENT wird die Shell wieder verlassen. Alternativ kann mit dem Befehl CONTINUE_CLIENT die Job-Ausführung wieder in den Vordergrund geholt werden, d.h., es werden wieder Fortschrittsmeldungen angezeigt, Kommandos können jedoch nicht eingegeben werden. Dies ist derselbe Zustand, der auch beim ursprünglichen Start eines Data-Pump-Jobs vorliegt. Mittels CTRL+C kann wieder in den interaktiven Modus und damit die Kommando-Shell zurückgewechselt werden. Data Pump und Globalization Support Data Pump benutzt die Einstellungen der Umgebungsvariablen NLS_LANG lediglich für die Interaktion mit dem Benutzer. Als Zeichensatz für den Data-Pump-Export wird der Datenbankzeichensatz verwendet und in der Dumpdatei vermerkt. DataPump-Import vergleicht dann den Zeichensatz aus der Dump-Datei mit dem Zeichensatz der Zieldatenbank und führt entsprechende Konvertierungen automatisch durch. Parallelisierung von Export und Dateitransfer Wenn Data Pump für eine Übertragung von Daten zwischen zwei Datenbanken genutzt werden soll, fällt nach der bisherigen Beschreibung eine dreistufige Vorgehensweise an: der Export auf dem Quellserver, die Übertragung der Dump-Dateien (z.B. mittels ftp oder scp) und abschließend der Import auf dem Zielserver.
Objektbasierte Techniken
549
Aus Performance-Gründen kann der Übertragungsvorgang mit einem der beiden anderen Schritte zusammengefasst werden. Im Folgenden wird beschrieben, wie Export und Dateitransfer auf diese Weise »gepipelined« werden können. Dazu wird der Export des Quellservers vom Zielserver aus durchgeführt. Alle zu exportierenden Daten werden via Datenbank-Link vom Quellserver gelesen und in DumpDateien auf den Zielserver geschrieben. Diese können anschließend ganz normal importiert werden. Voraussetzung hierfür ist lediglich, dass auf dem Zielserver ein Datenbank-Link zum Quellserver existiert, über den die Daten gelesen werden können. Ggf. muss dieser zuvor erstellt werden. Existiert ein entsprechender Datenbank-Link mit dem Namen SUNDB, wird der Export z.B. wie folgt parametriert: $ expdp schwanke@ps10 directory=pumpdir dumpfile=myexp.dmp logfile=myexp.log schemas=schwanke job_name=myexpjob network_link=sundb
Alle Objekte werden nun von der Datenbank gelesen, auf die der Datenbank-Link SUNDB zeigt, die Dump-Dateien werden ins Dateisystem der zum TNS-Namen PS10 gehörigen Datenbankservers geschrieben und können von dort aus importiert werden. Alternativ kann auf dem Quellsystem der Export normal durchgeführt und anschließend ebenfalls auf dem Quellserver via Datenbank-Link direkt in den Zielserver importiert werden. Bei dieser Variante muss der Datenbank-Link offenbar »in die entgegengesetzte Richtung zeigen«. In beiden Varianten entfällt der Dateitransfer vollständig, stattdessen werden die eigentlichen Daten über einen Datenbank-Link, also via Oracle Net, übertragen. Daher bilden diese zwei Varianten auch Lösungen für restriktive Umgebungen, in denen der Dateitransfer aus Sicherheitsgründen nicht möglich ist (z.B. bei gesperrten ftp- und scp-Ports). Bei der Übertragung via DB-Link findet natürlich auch eine Zeichensatzkonvertierung statt. Bei der ersten Variante enthält die Dump-Datei daher die NLS-Einstellungen des Zielservers. Auch hier gilt aber, dass während des gesamten Ablaufs eine korrekte NLS-Konvertierung automatisch und unabhängig von Client-Einstellungen erfolgt. Leider ist mit diesem Verfahren kein Export bzw. Import aus/in Datenbanken älterer Versionen möglich. Beide beteiligten Datenbanken müssen Oracle 10g-Datenbanken sein.
550
Wiederherstellungstechniken
Spezialfunktionen Mit Data Pump können auch Migrationen vom Datentyp LONG in die Datentypen CLOB oder NCLOB durchgeführt werden. Beispielsweise sei die Tabelle artikel betrachtet: SQL> DESCRIBE artikel Name -----------------ARTIKEL_NR NAME BESCHREIBUNG
Null? -------NOT NULL NOT NULL
Typ ----------------------NUMBER VARCHAR2(100) LONG
Eine Umwandlung der Spalte beschreibung in den Datentyp CLOB kann mittels Data Pump wie folgt realisiert werden: Export der alten Tabelle: $ expdp schwanke@ps10 directory=pumpdir dumpfile=longtab.dmp logfile=longtab.log tables=artikel job_name=longexp
Ersetzen der alten Tabelle durch eine neue, leere Tabelle mit Datentyp CLOB statt LONG. SQL> ALTER TABLE artikel RENAME TO artikel_old; SQL> 2 3 4
CREATE SELECT FROM WHERE
TABLE artikel AS artikel_nr, name, EMPTY_CLOB() AS beschreibung artikel_old 0 = 1;
Import in die neue Tabelle: $ impdp schwanke@ps10 directory=pumpdir dumpfile=longtab.dmp logfile=longtab.log tables=artikel job_name=lobimp table_exists_action=append
10.6.2 Export und Import Export und Import sind ein Paar von Werkzeugen, die zur Datenbank-Software gehören. Gemeinsam stellen sie den Vorgänger des mit Oracle 10g eingeführten Tools Data Pump dar (siehe Abschnitt Data Pump). Während Data Pump ausschließlich auf Oracle 10g-Datenbanken anwendbar ist, können mit Export und Import auch Datenbanken älterer Versionen angesprochen werden, insbesondere sind Migrationen oder Datentransfer zwischen Oracle 10g- und älteren Datenbanken damit möglich. Zur besseren Unterscheidung werden die beiden Tools Export und Import auch als konventioneller Export/Import bezeichnet.
Objektbasierte Techniken
551
Mit dem Exportwerkzeug alleine können Sicherungen, in Zusammenarbeit mit dem Importwerkzeug aber auch versions- und plattformübergreifende Migrationen und Reorganisationen einzelner Objekte, Benutzer, Tablespaces oder auch der ganzen Datenbank erstellt werden. Dabei werden neben den Daten auch die Befehle zur Erstellung der Datenbankobjekte, wie Tablespaces, Tabellen, Indizes, Benutzer usw., in einem Oracle-eigenen Binärformat in einer Exportdatei, auch Dump-Datei genannt, abgelegt. Dieses Format kann ausschließlich über das Werkzeug Import, das Gegenstück zum Export, gelesen und verarbeitet werden, um die Strukturen und Daten wieder in eine vorhandene Datenbank einzuspielen. Eine Kompatibilität zum Dump-Dateiformat von Data Pump besteht leider nicht. Export kennt vier verschiedene Granularitäten: TABLE: In dieser Variante werden einzelne Tabellen und/oder Partitionen sowie optional auch abhängige Objekte, d.h. Indizes, Constraints, Trigger sowie Objekt-Privilegien, zu den betreffenden Tabellen exportiert. Es kann auch ausgewählt werden, ob lediglich die Tabellenstruktur oder auch der Inhalt exportiert werden soll. USER (OWNER): Diese Granularität wird benutzt, um alle Datenbankobjekte eines Benutzers, also sein vollständiges Schema (Tabellen, Views, Synonyme, PL/SQLObjekte etc.), zu exportieren. FULL: Mit dieser Variante wird die gesamte Datenbank exportiert, also alle Benutzer, aber auch beispielsweise Tablespace-Definitionen, Rollen, DirectoryObjekte und Public-Synonyme, also Objekte, die nicht einem bestimmten Benutzer zugeordnet werden können. Dieser Modus ist aber zumeist nur im Rahmen von Migrationen kleinerer Datenbanken zu empfehlen, da der zugehörige Import ansonsten sehr zeitaufwändig wird. TABLESPACE: Diese Variante bildet einen Sonderfall, da ausschließlich Meta-Informationen über einen Tablespace exportiert werden. Die eigentlichen Daten werden durch ein Kopieren der zugehörigen Datendateien auf Betriebssystemebene übertragen. Das »Einhängen« des Tablespace in eine andere wird auf diese Weise ermöglicht, indem auf der Zieldatenbank ein entsprechender Import im TABLESPACE-Modus durchgeführt wird. Für nähere Informationen und Anwendungen hierzu siehe Abschnitt 15.1.1 (Transportable Tablespaces). Welche Granularität benutzt wird und welche Objekte in der gewählten Einheit berücksichtigt werden, wird über die Parametrierung des Exportbefehls ausgewählt, ebenso wie der Name der Exportdatei, Puffergrößen, Konsistenzanforderungen und einiges mehr. Jeder Anwender kann seine eigenen Daten, also Objekte seines Schemas, 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.
552
Wiederherstellungstechniken
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, d.h. in der vom Export vorgegebenen Reihenfolge, 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
Im Folgenden werden die am häufigsten benutzten Exportparameter vorgestellt. Einige Parameter können nur die Werte Y oder N annehmen. In diesem Fall wird der Parameter als gesetzt oder nicht gesetzt bezeichnet. Exportparameter
Bedeutung
USERID
Benutzername/Kennwort@NetAlias. Das Kennwort kann weggelassen werden und wird dann interaktiv abgefragt.
FILE
Liste von Ausgabedateien, z.B. (file1.dmp,file2.dmp)
FILESIZE
Maximale Größe jeder Dump-Datei
LOG
Name der Log-Datei
TABLES
Liste zu exportierender Tabellen und/oder Partitionen, jeweils in der Form [Schema.]Tabelle[:Partition], z.B. (KUNDEN,AUFTRAEGE,AUFPOSITIONEN). Impliziert die Granularität TABLE.
GRANTS, INDEXES, TRIGGERS, CONSTRAINTS
Falls gesetzt, werden die zu den Tabellen gehörenden Privilegien, Indizes, Trigger bzw. Constraints ebenfalls exportiert
ROWS
Falls gesetzt, werden auch die Inhalte von Tabellen exportiert
QUERY
Export einer Teilmenge aller Zeilen entsprechend der angegebenen WHERE-Klausel (siehe unten)
OWNER
Liste der zu exportierenden Benutzer, z.B. (HLADMIN). Impliziert die Granularität USER.
FULL
Granularität FULL, falls gesetzt
Tabelle 10.3: Parameter für den konventionellen Export
Objektbasierte Techniken
553
Exportparameter
Bedeutung
COMPRESS
Falls gesetzt, werden beim nachfolgenden Import alle Daten in ein einziges Extent geladen (siehe unten)
DIRECT
Falls gesetzt, direktes Lesen aus den Datendateien unter Umgehung der Instanz (siehe unten)
CONSISTENT
Falls gesetzt, werden alle Daten mit demselben Konsistenzzeitpunkt gelesen (siehe unten)
TRANSPORT_TABLESPACE
Falls gesetzt, Export mit der Granularität TABLESPACE
TABLESPACES
Liste der zu exportierenden Tablespaces (nur bei Granularität TABLESPACE)
Tabelle 10.3: Parameter für den konventionellen Export (Forts.)
Einige der vorgestellten Parameter sollen an dieser Stelle noch genauer erläutert werden: COMPRESS
Dieser Parameter (Standardeinstellung Y) bewirkt, dass der initiale 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 zurzeit 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. Vor dem Hintergrund der Tatsache, dass seit Oracle8i die Problematik großer Extentzahlen durch Locally-Managed Tablespaces beseitigt wurde, empfehlen wir, diesen Parameter stets explizit auf N zu setzen. Diese Empfehlung gilt auch für Dictionary-Managed Tablespaces. CONSISTENT
Bei einem Export, der bei laufendem Oracle-System ausgeführt wird, wird jede Tabelle für sich lesekonsistent exportiert. Bei Fremdschlüsselbeziehungen der Tabellen untereinander kann es passieren, dass z.B. Auftragsdatensätze exportiert werden, deren zugehöriger Kunde nicht exportiert wurde, weil er beim Export der Kundentabelle noch nicht existierte. Durch Setzen des Parameters CONSISTENT werden alle Tabellen konsistent exportiert. Der Nachteil hierbei ist, dass die Anforderungen an die Undo-Segmente bei lange laufenden Exports und gleichzeitig hoher Transaktionslast auf dem System entsprechend groß sind. Es besteht die Gefahr eines ORA-01555: Snapshot too old. QUERY
Um nur eine Teilmenge einer oder mehrerer Tabellen, z.B. alle Aufträge des Kunden mit der Kunden-Nr. 100, auszulesen, kann eine Filterbedingung in Form einer WHERE-Klausel mitgegeben werden. $ exp hladmin/hladmin file=exp_schwanke.dmp tables=auftraege query="where kdnr=100"
Die WHERE-Klausel wird in doppelte Hochkommata eingeschlossen, da Leerzeichen innerhalb der Klausel auftreten. Je nach Betriebssystem und verwendeter Kom-
554
Wiederherstellungstechniken
mando-Shell müssen die doppelten Hochkommata ggf. noch mit Escape-Zeichen versehen werden. Der Parameter kann nur bei der Granularität TABLE angegeben werden. Die angegebene Filterbedingung muss auf alle spezifizierten Tabellen anwendbar sein. Dies ist leider immer dann ein Problem, wenn z.B. die Kunden-Nr. in verschiedenen Tabellen leicht unterschiedliche Namen hat (z.B. kd_kdnr in der Kundentabelle, auf_kdnr in der Aufträgetabelle) Achtung: Aus der Exportdatei ist anschließend nicht mehr ersichtlich, dass der Export mit Filterbedingungen ausgeführt wurde. DIRECT
Beim so genannten 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. Wie groß die Performance-Vorteile sind, ist von der Datenbankblockgröße und der IO-Bandbreite abhängig. Außerdem können keine Filterbedingungen angegeben werden (Parameter QUERY). Achtung: Im Rahmen von Virtual Private Database und Oracle Label Security (siehe Abschnitt 9.6) definierte Zugriffsrechte auf einzelnen Tabellenspalten werden beim Direct-Path-Export nicht (!) berücksichtigt, da diese ebenfalls auf Filterbedingungen beruhen. Komprimieren von Exportdateien Oftmals stellt sich die Frage, ob es möglich ist, die Exportdatei(en) während des Exportierens zu komprimieren, um Zeit und Platz zu sparen. Unter dem Betriebssystem 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 z.B. mit einem GZip-Befehl aus dieser zu lesen: $ /sbin/mknod /tmp/exp_pipe p $ exp demo/demo compress=n tables=kunden file=/tmp/exp_pipe > export.log 2>&1 & $ cat /tmp/exp_pipe | gzip -c > /tmp/exp_user.ora & Listing 10.48: Listing 10.1: Export mit gleichzeitiger Komprimierung der Dump-Datei
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 Redo-Log-Dateien kann jedoch nicht angeschlossen werden.
Objektbasierte Techniken
555
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. Import-Parameter
Bedeutung
USERID
Analog zu Export
FILE
Liste von Eingabedateien, z.B.(file1.dmp,file2.dmp)
FILESIZE
Beim Export angegebene Maximalgröße der Dump-Dateien
LOG
Log-Datei mit Inhalt der Bildschirmausgabe
TABLES
Liste zu importierender Tabellen und/oder Partitionen, Format analog zu Export
GRANTS, INDEXES, CONSTRAINTS
Falls gesetzt, werden die zu den Tabellen gehörenden Privilegien, Indizes bzw. Constraints ebenfalls importiert.
ROWS
Falls gesetzt, werden auch die Inhalte von Tabellen importiert
SHOW
Nur Inhalt der Dump-Datei, kein tatsächlicher Import
IGNORE
Fehler beim Erstellen von DB-Objekten ignorieren (siehe unten)
FULL
Falls gesetzt, gesamten Inhalt der Dump-Datei importieren
FROMUSER, TOUSER
Nur die Objekte der unter FROMUSER aufgelisteten Benutzer werden importiert, z.B. FROMUSER= (AHRENDS,SCHWANKE).Optional enthält TOUSER eine Liste der zugehörigen Zielschemata (siehe unten)
COMMIT, BUFFER
Einstellen eines Commit-Intervalls (siehe unten)
INDEXFILE
Schreibt ein Erstellungsskript für Tabellen und Indizes in die angegebene Datei (siehe unten)
RESUMABLE, RESUMABLE_NAME, RESUMABLE_TIMEOUT
Der Import wird als so genannte »Resumable Session« ausgeführt. Dies ist für umfangreichere Ladevorgänge im Rahmen von Data Warehouses interessant (siehe Kapitel 14).
Tabelle 10.4: Parameter für den konventionellen Import
556
Wiederherstellungstechniken
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 Schemata 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 von einem DBA wieder importiert werden. FROMUSER kann auch dazu verwendet werden, aus einem FULL-Export nur Objekte eines Schemas selektiv zu importieren. 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 Undo-Segmente der Zieldatenbank führen kann. Über die Einstellung COMMIT=Y wird ein CommitBefehl nach jedem Puffer, dessen Größe über BUFFER=NNNNN eingestellt werden kann, ausgeführt. INDEXFILE
Mit dem Befehl: imp schwanke@hlsun1 file=expdat.dmp indexfile=create_index.sql
können Sie aus einer bestehenden Exportdatei ein SQL-Skript 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. Der Sinn dieses Skripts ist es, den Import ohne Indizes durchführen und diese dann später mit einer speziell definierten sort_area_size, eventuell auch parallelisiert, anlegen zu können. Durch Setzen des Parameters CONSTRAINTS werden auch Indizes, die über einen Primärschlüssel definiert worden sind, hier berücksichtigt. Es ist so aber auch eine elegante Möglichkeit geboten, Skripte für den Neuaufbau einer Datenbank zu generieren und diese mit eventuell vorhandenen Skripten abzugleichen.
Objektbasierte Techniken
557
Globalization Support für Export und Import Frühere Versionen von Export und Import haben für den Datenstrom die Zeichensatzkomponente der Umgebungsvariablen NLS_LANG ausgewertet. Dies führte oft zu Fehlern, bei denen z.B. Umlaute verloren gegangen sind. Seit Oracle9i Release 2 verwendet der Export den Datenbankzeichensatz. Dieser Zeichensatz wird in der Exportdatei abgelegt. Import interpretiert dann den Zeichensatz aus der Exportdatei und führt entsprechende Konvertierungen (ebenfalls ohne Umweg über den Client-Zeichensatz) durch. Grundsätzlich ist zu empfehlen, sowohl für den Export als auch für den Import die Umgebungsvariable NLS_LANG auf den Zeichensatz der Quell-Datenbank zu setzen, auch wenn die Zieldatenbank einen anderen Zeichensatz hat. Export und Import über Named Pipes unter Unix 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 mit nachfolgendem Import verbraucht aufgrund des seriellen Charakters unnötig Zeit und Platz. Wünschenswert ist hier eine Parallelisierung von Export und Import. Hier kann man unter Unix auf 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-Vorgang 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 10.49: Export-/Import-Vorgang über Named Pipes unter Unix
Es soll 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. LONG- nach LOB-Migration Analog zu dem in Kapitel Data Pump vorgestellten Verfahren kann auch mit dem konventionellen Export/Import eine Migration vom Datentyp LONG nach CLOB oder NCLOB durchgeführt werden.
558
Wiederherstellungstechniken
10.6.3 LogMiner Mit Oracle8i hat Oracle den LogMiner eingeführt, mit dem die Informationen der Online- und Offline-Redo-Log-Dateien ausgelesen werden können. Das Werkzeug ist zunächst über eine Reihe von PL/SQL-Prozeduren realisiert und seit Oracle9i 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. Außerdem kann ein Audit erfolgen, da alle DDL- und DML-Befehle in den RedoLog-Dateien gespeichert sind. Die Quelldatenbank und die Mining-Datenbank können voneinander getrennt sein. In diesem Fall ist es möglich, aus einer Oracle 10g-Datenbank als MiningInstanz die Redo-Log-Dateien einer Oracle8-Datenbank (bis hinunter zu Version 8.0.6) zu verarbeiten. In Oracle8 muss hierzu das Package dbms_logmnr_d mit den entsprechenden Skripten aus $ORACLE_HOME/rdbms/admin einer neueren Datenbankversion erstellt werden. 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-Datenbankversion 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 ab der Version 9 auch die Möglichkeit, das Data Dictionary zu nutzen oder die Dictionary-Information in einer Redo-Log-Datei mit abzuspeichern. Folgende Vor- und Nachteile ergeben sich bei der jeweiligen Verwendung eines Dictionarys: Online Dictionary Das Online-Data-Dictionary wird bei der lokalen Anwendung des LogMiners (Quell-Datenbank und Mining-Instanz sind gleich) benutzt. SQL> EXECUTE DBMS_LOGMNR.START_LOGMNR( OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG); Listing 10.50: LogMiner mit Online Dictionary
Dictionary als Datei Es ist notwendig, mit einem Befehl (PL/SQL-Prozedur oder Enterprise Manager LOGMINER VIEWER) eine solche Datei im Dateisystem 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.
Objektbasierte Techniken
559
SQL> EXECUTE DBMS_LOGMNR_D.BUILD( 'dictionary.ora', 'D:\oracle\admin\udump\dictionary.ora', DBMS_LOGMNR_D.STORE_IN_FLAT_FILE); Listing 10.51: LogMiner mit Datei-Dictionary
Redolog Dictionary Hierbei wird die Information des Data Dictionarys in die Redo-Log-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 außerdem zu zusätzlichen archivierten RedoLog-Dateien führen. Der Vorteil liegt jedoch bei der besseren Performance des LogMiner Viewers bzw. der entsprechenden PL/SQL-Prozeduren gegenüber einer externen Datei. SQL> EXECUTE DBMS_LOGMNR_D.BUILD( OPTIONS=> DBMS_LOGMNR_D.STORE_IN_REDO_LOGS); Listing 10.52: Redo-Log Dictionary
Allen drei Konfigurationen ist aber gemeinsam, dass sie nur eine Momentaufnahme des Data Dictionarys ermöglichen. Das bedeutet speziell beim Zugriff auf archivierte Redo-Log-Dateien. dass es vorkommen kann, dass es das entsprechende Objekt gar nicht mehr in der Datenbank gibt. Im Weiteren werden wir uns auf die Verwendung des Online-Dictionarys beschränken. Zunächst wird der Umfang der Mining-Sitzung festgelegt. Dieser kann als Zeitdauer (starttime, endtime) oder als SCN (startscn, endscn) festgelegt werden. Während es in der Version 9 noch notwendig war, alle in Frage kommenden Redo-Log-Dateien anzugeben (dbms_logmnr.add_logfile), genügt in der Version 10 die Angabe (dbms_logmnr.continuous_mine), wodurch der LogMiner die notwendigen Online- und archivierten Redo-Log-Dateien selbstständig erkennt. Außerdem können bei dem Aufbau der Mining-Sitzung schon Optionen mitgegeben werden, so z.B. dbms_logmnr.committed_data_only, wodurch die erfasste Datenmenge eingeschränkt werden kann. Diese Option hat aber den Nachteil, dass zunächst die Datenmenge erfasst wird und erst anschließend die Einschränkung erfolgt. Dadurch kann es leicht zum Fehler out of memory kommen. Außerdem haben wir den interessanten Nebeneffekt festgestellt, dass durch diese »Einschränkung« die ermittelte Datenmenge (SELECT COUNT(*) FROM v$logmnr_contents WHERE commit_timestamp IS NOT NULL) teilweise größer war als ohne. Es ist daher oftmals sinnvoller, auf diese Option zu verzichten und erst bei der Darstellung der Ergebnismenge einzuschränken. Das Ergebnis einer Mining-Sitzung kann über die View v$logmnr_contents angezeigt werden. Wie aus dem Namen ersichtlich, handelt es sich hierbei um eine virtuelle Tabelle, die nur während der Mining-Sitzung existiert. Es ist daher erforderlich, die PL/SQL-Prozedur dbms_logmnr.start_logmnr und die Abfrage auf v$logmnr_contents in der gleichen Sitzung auszuführen. Neben den Informationen über die Transaktion (Zeitpunkt, SCN, Segment-Name) enthält diese View die Spalten sql_redo und
560
Wiederherstellungstechniken
sql_undo, womit Transaktionen noch einmal (sql_redo) durchgeführt werden können bzw. zurückgesetzt (sql_undo) werden können. Die Spalte sql_undo ist nur bei
DML-Befehlen gefüllt. In Beispiel wurden einige Tabellen fälschlicherweise geleert, gelöscht und neu angelegt, so dass ein Flashback nicht in Frage kommt. Die Ermittlung des TRUNCATEBefehls über dba_objects ist ebenfalls nicht möglich, da ja nur der letzte DDL-Befehl gespeichert wird. Es muss also herausgefunden werden, wann der erste Löschbefehl stattgefunden hat, eine grobe Zeitangabe gibt es hierbei (zwischen 10:30 Uhr und 11:30 Uhr). Außerdem ist bekannt, welcher Befehl zuerst abgesetzt worden ist (TRUNCATE TABLE kunden). SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'DD.MM.YYYY HH24:MI:SS'; SQL> BEGIN DBMS_LOGMNR.START_LOGMNR( STARTTIME => '17.08.2004 10:30:00', ENDTIME => '17.08.2004 11:30:00', OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.CONTINUOUS_MINE + DBMS_LOGMNR.COMMITTED_DATA_ONLY); END; / SQL> SELECT table_name, timestamp, operation, sql_redo FROM V$LOGMNR_CONTENTS WHERE upper(sql_redo) like '%TRUNCATE TABLE KUNDEN%'; TABLE_NAME TIMESTAMP OPERATION SQL_REDO -------------------------------- ------------------- -------------------------------------------------------KUNDEN 17.08.2004 11:16:09 DDL truncate table kunden; Listing 10.53: Ermittlung der Zeit des ersten DDL-Befehls
In diesem Fall wurde also der Befehl TRUNCATE TABLE kunden um 11:16:09 Uhr ausgeführt, so dass jetzt ein Flashback Database oder ein TSPITR auf diesen Zeitpunkt (Minus 5 Sekunden) erfolgen kann. Natürlich ist es auch möglich, DML-Befehle über den LogMiner zurückzusetzen (Spalte sql_undo). Die Notwendigkeit hierfür hat aber durch die Flashback-Techniken in Oracle 10g an Relevanz verloren und wird daher hier nicht mehr besprochen.
10.6.4 Flashback Query Immer wieder kommt es vor, dass ein Benutzer oder ein Batch-Job fehlerhafte Änderungen durchführt. Ein sehr menschlicher Fehler ist beispielsweise das Vergessen einer WHERE-Klausel in einer UPDATE- oder DELETE-Anweisung. Wird dies erst nach dem COMMIT-Befehl bemerkt, stellt sich natürlich die Frage, wie die dadurch entstandene logische Datenkorruption wieder bereinigt werden kann. Der in Abschnitt 10.6.3 beschriebene LogMiner bietet hierfür eine Möglichkeit; das Verfahren ist jedoch etwas langwierig, da zunächst ein Skript generiert werden muss, das kompensierende Aktionen ausführt. Sind bis zur Ausführung dieses
Objektbasierte Techniken
561
Skripts bereits weitere Änderungen der betroffenen Tabelle eingegangen, verkompliziert dies die Bereinigung eventuell weiter. Ein einfacherer Weg steht bereits seit Oracle9i zur Verfügung, die so genannte Flashback Query. Im Gegensatz zum LogMiner wird hierbei nicht Redo-Log-Information, sondern Rollback-Information genutzt, die ja in Undo-Segmenten in den Datendateien oder sogar im Buffer-Cache steht. Bei näherer Betrachtung stellt man fest, dass Oracle diese Technik schon seit langem verwendet, um bei Abfragen konsistent Daten zu lesen. Flashback Queries stellen nun einfach ein Benutzer-Interface in Form einer bestimmten SQL-Syntax dar, um diese Technik explizit zu nutzen, also z.B. den Inhalt einer Tabelle vor einer Stunde zu sehen: SQL> SELECT * FROM kunden AS OF TIMESTAMP SYSDATE – 1/24;
Vorrausetzungen Damit diese Abfrage ausgeführt werden kann, ist die Verwendung von Automatic Undo Management (siehe Abschnitt 3.3.5) erforderlich. Außerdem müssen natürlich entsprechend alte Rollback-Informationen noch in den Undo-Segmenten vorhanden sind. Dies kann durch den Initialisierungsparameter undo_retention konfiguriert werden. Die Einstellung undo_retention = 7200
bedeutet beispielsweise, dass Rollback-Informationen für zwei Stunden (7200 Sekunden) aufbewahrt werden sollen, bevor sie überschrieben werden. Damit das auch tatsächlich funktionieren kann, muss der Undo-Tablespace ausreichend dimensioniert sein. Über den UNDO ADVISOR im Enterprise Manager kann der Platzbedarf für den Undo-Tablespace abgeschätzt werden. Eine gewisse Reserve, z.B. 10%, sollte von vornherein einkalkuliert oder zumindest über den Auto-ExtendMechanismus der Datendateien verfügbar sein. Ist der Undo-Tablespace zu klein, z.B. durch eine temporär sehr hohe Transaktionslast, werden letztlich auch Rollback-Daten, die jünger sind als undo_retention, überschrieben, damit die Transaktionen und damit die produktive Arbeit nicht unterbrochen werden muss. Eine entsprechende Flashback Query wird dann mit einer Fehlermeldung quittiert: ORA-01555: snapshot too old: rollback segment too small
Mit Oracle 10g ist es auch möglich, die durch undo_retention spezifizierte gewünschte Rückblickzeit zu garantieren: SQL> ALTER TABLESPACE RETENTION GUARANTEE;
Achtung: Dies führt dazu, dass Transaktionen mit einer Fehlermeldung abbrechen, wenn der Undo-Tablespace belegt ist. Daher sollte diese Einstellung nur in Ausnahmesituationen erfolgen und nach Zurückschaltung auf den Normalbetrieb unbedingt wieder deaktiviert werden (Klausel RETENTION NOGUARANTEE).
562
Wiederherstellungstechniken
Anwendung Alternativ zu der oben gezeigten Flashback Query kann statt eines Zeitpunkt auch eine SCN (die interne Änderungsnummer einer DML-Anweisung) angegeben werden. SQL> SELECT * FROM kunden AS OF SCN 312675424;
Da diese jedoch zumeist weniger bekannt ist als der Zeitpunkt, auf den zurückgeschaut werden muss, ist diese Variante für die Praxis weniger geeignet. Intern rechnet Oracle aber auch bei der Timestamp-Variante den angegebenen Zeitpunkt in eine SCN um. Diese Umrechnung geschah bei Oracle9i mit einer Granularität von fünf Minuten; das bedeutet, dass der tatsächliche Rückblick-Zeitpunkt bis zu fünf Minuten vor dem angeforderten Zeitpunkt liegen konnte. Die Flashback Query zu Anfang dieses Kapitels konnte also auch den Tabelleninhalt vor einer Stunde und fünf Minuten zurückliefern. Mit Oracle 10g ist diese Ungenauigkeit auf etwa drei Sekunden reduziert worden. Da der Zeitpunkt einer fehlerhaften DML-Operation im Allgemeinen zunächst nicht besser als ca. eine Minute bekannt ist, ist dies völlig ausreichend. Ist der letztmögliche Zeitpunkt vor der fehlerhaften Anweisung (z.B. durch Trial & Error) gefunden, kann dieser als Rückblick-Zeitpunkt zur Rekonstruktion der Tabelle verwendet werden (da eine Timestamp-Konstante durch das Schlüsselwort TIMESTAMP eingeleitet wird, muss dieses Wort hier tatsächlich zweimal stehen): SQL> CREATE TABLE kunden_vorher AS 2 SELECT * 3 FROM kunden AS OF TIMESTAMP TIMESTAMP '2004-08-10 16:25:30'; SQL> DROP TABLE kunden; SQL> ALTER TABLE kunden_vorher RENAME TO kunden; Listing 10.54: Wiederherstellung der Kundentabelle mit Flashback Query
Der Nachteil hierbei ist, dass abhängige Objekte (Indizes, Constraints, Trigger) manuell neu erstellt sowie Privilegien neu vergeben müssen werden. Dieses Problem tritt bei der Benutzung von Flashback Table (siehe Abschnitt Flashback Table) nicht auf. Die Flashback-Query-Funktion ist daher vor allem zum Einsehen des Tabelleninhalts zu einem bestimmten Zeitpunkt sowie zum Ermitteln eines geeigneten Rücksetz-Zeitpunkts bei logischen Fehlern interessant; für das Rücksetzen selbst sollte stattdessen die Flashback-Table-Funktionalität verwendet werden. Es kann auch nicht über ein TRUNCATE-Kommando, ein Löschen der Tabelle (DROP TABLE) oder irgendein Kommando, das die Spaltenstruktur der Tabelle ändert, hinweggeschaut werden. Für den Fall einer versehentlichen Löschung der Tabelle ist eine Wiederherstellung mittels der Flashback-Table-Funktion (siehe Abschnitt 10.6.5) möglich.
Objektbasierte Techniken
563
Sicherheit DBAs können mit dem Systemprivileg FLASHBACK ANY TABLE für alle Tabellen Flashback Queries ausführen. Andere Benutzer, die nur auf bestimmten Tabellen Flashback Queries ausführen müssen, benötigen neben dem SELECT-Recht auch das FLASHBACK-Privileg. SQL> GRANT SELECT, FLASHBACK ON kunden TO ahrends;
10.6.5 Flashback Table Was ist zu tun, wenn ein Benutzer irrtümlich eine Tabelle gelöscht hat, z.B. weil er zu spät bemerkt hat, dass er sich statt in einer Testumgebung gerade auf dem Produktionssystem befindet? Oder wenn er bei einem UPDATE- oder DELETE-Statement die WHERE-Klausel vergessen hat und dies erst nach dem COMMIT bemerkt? Für das erste Szenario gab es bis einschließlich Oracle9i keine einfache Lösung. Sowohl der Log-Miner (Abschnitt 10.6.3) als auch die Flashback-Query-Funktion (Abschnitt Flashback Query) sind nicht in der Lage, DDL-Operationen wie das Löschen einer Tabelle rückgängig zu machen. Stattdessen musste beispielsweise aus einer möglichst aktuellen Sicherung mittels Rücksicherung und Wiederherstellung zu einem bestimmten Zeitpunkt der Zustand kurz vor der versehentlichen Löschung wiederhergestellt und mittels Export und Import die Tabelle wieder in das Produktionssystem übertragen werden. Im zweiten Fall ist eine Wiederherstellung mit den beiden erwähnten Tools möglich, aber mit einem gewissen Aufwand verbunden. Mit Oracle 10g sind für beide Szenarien alternative, deutlich einfachere Lösungswege geschaffen worden. Beide laufen unter der Bezeichnung Flashback Table, stellen aber ganz unterschiedliche Mechanismen dar. Zurücksetzen von Transaktionen Nachdem z.B. mittels Flashback Queries (siehe Abschnitt 10.6.4) der korrekte Rücksetzzeitpunkt für eine fehlerhafte Transaktion gefunden wurde, kann das eigentliche Zurücksetzen am bequemsten mittels eines FLASHBACK TABLE-Kommandos erfolgen. Dabei werden intern entsprechende kompensierende DML-Operationen generiert und auf die Tabelle angewendet. Alle abhängigen Objekte (Constraints, Indizes, Trigger) sowie Objektprivilegien bleiben erhalten. Zuvor wird die Tabelle exklusiv gesperrt, während des Flashbacks können also keine Benutzer auf der Tabelle arbeiten. Lesende Zugriffe sind jedoch möglich. Voraussetzung ist, dass das so genannte ROW MOVEMENT für die Tabelle aktiviert ist (diese Eigenschaft erlaubt die Wiederherstellung von Zeilen unter einer anderen ROWID). Ist dies nicht der Fall, kann es einfach aktiviert werden: SQL> ALTER TABLE auftraege ENABLE ROW MOVEMENT;
Der Rücksetzzeitpunkt wird analog zu den Flashback Queries entweder als Timestamp oder als SCN angegeben. Bezüglich der Verfügbarkeit entsprechender Rollback-Informationen sowie Security-Regeln gilt ebenfalls das dort Gesagte. Für die auftraege-Tabelle sieht das z.B. so aus:
564
Wiederherstellungstechniken
SQL> FLASHBACK TABLE auftraege TO TIMESTAMP SYSDATE – 45/1440;
Existieren Abhängigkeiten zu anderen Tabellen, kann es natürlich zu Verletzungen von Fremdschlüssel-Constraints kommen. In diesem Fall schlägt das Kommando fehl. Als Ausweg ist hier nur das Deaktivieren des betreffenden Constraints möglich, oder aber es werden beide Tabellen gleichzeitig auf denselben Zeitpunkt zurückgesetzt: SQL> FLASHBACK TABLE auftraege, aufpositionen 2 TO TIMESTAMP SYSDATE – 45/1440;
Auf die Reihenfolge der Tabellen kommt es nicht an. Intern läuft diese Operation in einer Transaktion. Bei einem Fehlschlag bleiben also alle Tabellen auf dem Originalstand. Trigger auf den Tabellen werden standardmäßig für die Dauer der Flashback-Operation deaktiviert. Sollen beispielsweise Protokoll-Trigger dennoch aktiviert bleiben, kann dies (allerdings nur pauschal für alle Trigger) eingestellt werden: SQL> FLASHBACK TABLE auftraege TO TIMESTAMP SYSDATE – 45/1440 2 ENABLE TRIGGERS;
Eine Flashback-Table-Operation kann nicht zurückgerollt werden; jedoch kann durch ein weiteres Flashback Table mit einem etwas früheren Rücksetzzeitpunkt eine Art ROLLBACK simuliert werden. Das Zurücksetzen von Data-Dictionary-Tabellen (um DDL-Operationen rückgängig zu machen) ist nicht möglich. Hierfür muss stattdessen die Flashback-DatabaseFunktion genutzt werden (siehe Abschnitt 10.4). Auch für andere Objekte, die (versehentlich) im SYSTEM-Tablespace liegen, ist kein Flashback möglich. Es sollte z.B. durch die Definition eines datenbankweiter Default-Tablespace verhindert werden, dass Objekte einzelner Benutzer versehentlich im SYSTEM-Tablespace liegen. Wiederherstellen gelöschter Tabellen Zur Rekonstruktion einer gelöschten Tabelle wird derselbe Ansatz benutzt wie bei MS-Windows für Dateien. Oracle hat eine eingebaute Papierkorb-Funktion (»Recyclebin«). Das Löschen einer Tabelle führt bei Oracle 10g nicht mehr zu einem physischen Löschen, sondern die Tabelle wird umbenannt, und es wird ein Flag gesetzt, das indiziert, dass die Tabelle gelöscht ist. Der Speicherplatz wird zunächst nicht freigegeben. Zur Wiederherstellung wird das Flag einfach wieder zurückgesetzt. Natürlich kann auch ein echtes, physisches Löschen angefordert werden. Dieser Mechanismus braucht nicht konfiguriert zu werden, sondern ist von vornherein aktiviert, insofern Locally-Managed Tablespaces verwendet werden. Beispielhaft soll diese Funktionalität anhand der kunden-Tabelle demonstriert werden. Auf der Kundentabelle ist ein Primärschlüssel pk_kunden auf der Spalte kd_nr definiert sowie ein Trigger tr_neuer_kunde, der beim Einfügen eines neuen Kunden eine neue Kundennummer aus einer Sequenz zieht.
Objektbasierte Techniken
565
Nach einem versehentlichen Löschen der Kundentabelle liefert ein Blick in den Papierkorb Folgendes: SQL> SELECT object_name,original_name,type FROM recyclebin; OBJECT_NAME ORIGINAL_NAME TYPE ------------------------------ --------------- ------BIN$H94Oz1MiTs6mZc5CrlGHMQ==$0 PK_KUNDEN INDEX BIN$aHK64lpfTGC5OJtZqJTsXw==$0 TR_NEUER_KUNDE TRIGGER BIN$5gCoXywZQiyCGevvx/rJ4A==$0 KUNDEN TABLE Listing 10.55: Auflistung des Papierkorbinhaltes
Auch alle abhängigen Objekte (Trigger, Indizes, Constraints) sind also noch vorhanden. Die Spalte object_name gibt den (kryptischen) Recyclebin-Namen an. Welches ursprüngliche Objekt sich dahinter verbirgt, ist in den Spalten original_name und type aufgeschlüsselt. Falls dieselbe Tabelle abermals erstellt und gelöscht wurde, können zusätzlich die Spalten createtime und droptime hinzugezogen werden, um eine eindeutige Identifizierung zu ermöglichen. In SQL*Plus gibt es als Abkürzung das Kommando: SQL> SHOW RECYCLEBIN
Die Papierkörbe aller Benutzer können über die View dba_recyclebin abgefragt werden. Auch der Inhalt der gelöschten Tabelle kann abgefragt werden. Die gelöschte Tabelle wird dabei wie eine ganz normale Tabelle behandelt. Allerdings muss der Recyclebin-Name verwendet werden. Da dieser meistens Sonderzeichen und Kleinbuchstaben enthält, ist er in doppelte Hochkommata einzufassen: SQL> SELECT * FROM "BIN$5gCoXywZQiyCGevvx/rJ4A==$0";
Die Wiederherstellung der Tabelle inklusive aller abhängigen Objekte geht nun einfach durch folgenden Befehl: SQL> FLASHBACK TABLE kunden TO BEFORE DROP;
Die Tabelle wird dabei unter ihrem ursprünglichem Namen wiederhergestellt. Dies sollte auch für abhängige Objekte gelten, ein Bug führt jedoch dazu, dass Trigger, Constraints und Indizes unter ihrem Recyclebin-Namen wiederhergestellt werden (bis einschließlich 10.1.0.4 getestet). Hier ist leider ein manuelles Umbenennen mittels entsprechenden ALTER-Kommandos notwendig. Wichtig ist dabei, sich die Originalnamen vor der Wiederherstellung zu merken, da diese nach der Wiederherstellung nicht mehr in der Recyclebin stehen und somit nicht mehr verfügbar sind. Hinzu kommt, dass Constraints gelöschter Tabellen zwar in dba_constraints, nicht aber in dba_recyclebin aufgeführt sind. Befinden sich mehrere Objekte mit demselben Originalnamen im Papierkorb (die Recyclebin-Namen sind in jedem Fall unterschiedlich), wird das jüngste dieser Objekte wiederhergestellt. Alternativ kann explizit eine bestimmte Version des Objekts ausgewählt werden, indem beim Flashback-Kommando statt des Originalnamens der Recyclebin-Name eingesetzt wird, z.B. SQL> FLASHBACK TABLE "BIN$5gCoXywZQiyCGevvx/rJ4A==$0" 2 TO BEFORE DROP;
566
Wiederherstellungstechniken
Hat ein Benutzer vor dem versehentlichen Löschen einer Tabelle bereits DML-Operationen auf der Tabelle ausgeführt, müssen diese nach der Wiederherstellung der Tabelle noch zurückgesetzt werden. Außerdem müssen in jedem Fall Fremdschlüssel-Constraints manuell neudefiniert werden. Es sollte daher zunächst verhindert werden, dass Anwendungen oder Benutzer auf die frisch wiederhergestellte Tabelle zugreifen können. Um dies auszuschließen, wird die Tabelle zunächst unter einem anderen Namen wiederhergestellt. Anschließend wird mittels Flashback Queries ein geeigneter Rücksetzzeitpunkt ermittelt und auf diesen zurückgeschaltet. Zum Schluss wird wieder der Originalname eingesetzt. SQL> SQL> 2 SQL> SQL> SQL> 2 SQL> 2 SQL> 2 SQL>
FLASHBACK TABLE kunden TO BEFORE DROP RENAME TO kunden_fb; FLASHBACK TABLE kunden_fb TO TIMESTAMP TIMESTAMP '2004-08-10 16:25:30'; -- Fremdschlüssel neu definieren -- Ggf. ursprüngliche Namen abhängiger Objekte herstellen ALTER TABLE kunden_fb RENAME CONSTRAINT "BIN$A6ViryXMTIGjZFNgbKpewg==$0" TO kunden_pk; ALTER TRIGGER "BIN$aHK64lpfTGC5OJtZqJTsXw==$0" RENAME TO tr_neuer_kunden ALTER INDEX "BIN$H94Oz1MiTs6mZc5CrlGHMQ==$0" RENAME TO pk_kunden; ALTER TABLE kunden_fb RENAME TO kunden;
Listing 10.56: Beispielskript für die Wiederherstellung der kunden-Tabelle
Da der Speicherplatz gelöschter Tabellen und Indizes nicht mehr unmittelbar freigegeben wird, ist der belegte Platz in einem Tablespace zunächst höher als ohne Papierkorb. Dieser Platz wird auch als belegter Platz bezüglich der Benutzer-Quota gezählt. Dennoch ist der Papierkorb für den Benutzer bzw. die Applikation transparent, da Recyclebin-Objekte automatisch endgültig gelöscht werden, sobald durch CREATE- oder INSERT-Operationen eine Benutzer-Quota überschritten oder eine Datendatei vergrößert würde. Monitoring-Tools, die unter anderem den Füllgrad der Tablespaces bestimmen, bemerken den Papierkorb ebenfalls nicht, da die View dba_free_space, die als Basis für entsprechende Berechnungen benutzt wird, insofern angepasst wurde, dass Papierkorb-Objekte zum Freiplatz gezählt werden. Allerdings werden dadurch auch Abfragen auf diese View langsamer, wenn sich viele Objekte im Papierkorb befinden. In regelmäßigen Zeitabständen sollte der Papierkorb daher geleert werden. SQL> SQL> SQL> SQL>
PURGE TABLE kunden; -- löscht die Kundentabelle endgültig PURGE RECYCLEBIN; -- leert den eigenen Papierkorb PURGE DBA_RECYCLEBIN; -- leert Papierkörbe aller Benutzer DROP TABLE kunden PURGE; -- gar nicht erst in den Papierkorb
Listing 10.57: Verschiedene Kommandos zum endgültigen Löschen von Objekten
Die gesamte Papierkorb-Funktion kann deaktiviert werden, indem der undokumentierte Parameter _recyclebin auf FALSE gesetzt wird.
Ältere Techniken zur Sicherung
10.7
567
Ältere Techniken zur Sicherung
10.7.1 Offline-Sicherung Das einfachste Verfahren für die Sicherung einer Datenbank ist die Offline-Sicherung. Offline bedeutet, dass während der Sicherung keine Änderungen in der Datenbank möglich sind. Dies wird durch folgenden Befehle erreicht: SQL> SHUTDOWN [NORMAL | IMMEDIATE | TRANSACTIONAL];
Nachdem die Instanz heruntergefahren wurde, ist eine Sicherung aller Datenbankdateien im konsistenten Zustand möglich. Zur Offline-Sicherung gehören alle Dateien der Datenbank außer den Dateien der temporären Tablespaces, also Kontrolldateien, Redo-Log-Dateien und sämtliche Datendateien. Um eine aktuelle Liste der zu sichernden Dateien zu erhalten, ist es sinnvoll, die Datenbank in den MOUNT-Status hochzufahren und dann die Informationen aus den Kontrolldateien über entsprechende v$-Views abzufragen. SQL> SQL> SQL> SQL> SQL> SQL> SQL>
STARTUP MOUNT; SET trimspool on; SPOOL backuplist.lst; SELECT name FROM v$datafile; SELECT member FROM v$logfile; SELECT name FROM v$controlfile; SPOOL OFF;
Listing 10.58: Abfragen der v$-Informationen im MOUNT-Status
Hiermit ist sichergestellt, dass auch bei Strukturänderungen der Datenbank jederzeit alle erforderlichen Dateien gesichert werden. Die Dateien der temporären Tablespaces werden nicht gesichert, da sie zum einen keine wichtigen Informationen enthalten und zum anderen im laufenden Betrieb jederzeit wiederhergestellt werden können. Die eigentliche Sicherung erfolgt dann mit Betriebssystembefehlen, wie copy unter MS-Windows oder tar bzw. cpio bei Unix. Natürlich kann hierfür auch eine spezielle Software wie z.B. Veritas NetBackup, HP Omniback oder Brightstor Arcserve genutzt werden. Neben der Sicherung der Datenbankdateien sollte zusätzlich die Parameterdatei (SPFILE oder init.ora) regelmäßig gesichert werden. Nach der Sicherung kann die Datenbank mit einem der folgenden Befehle wieder aktiviert werden: Nach dem Herunterfahren der Instanz: SQL> STARTUP;
568
Wiederherstellungstechniken
Wenn die Instanz im MOUNT-Status war: SQL> ALTER DATABASE OPEN;
Der Nachteil dieses einfachen Verfahrens ist, dass die Datenbank für die Dauer der Sicherung nicht zur Verfügung steht. Außerdem wird die gesamte Datenbank gesichert, d.h. auch Dateien, die wenig oder gar nicht gefüllt sind. Der im Abschnitt 10.3 besprochene Recovery Manager vereinfacht die OfflineSicherung, so dass nur die gefüllten Blöcke weggeschrieben werden. Außerdem ermittelt der Recovery Manager selbstständig die zu sichernden Dateien. Offline-Rücksicherung und Wiederherstellung Die generelle Frage, die sich für ein Offline-Recovery stellt, ist: »Wurde archiviert oder nicht?« Keine Archivierung Wenn keine archivierten Redo-Log-Dateien zur Verfügung stehen, muss davon ausgegangen werden, dass die Datenbank nur auf den Zeitpunkt der letzten Sicherung zurückgesetzt werden kann. Das bedeutet, es gibt keine Wiederherstellung, sondern es werden die Dateien aus der Sicherung in die entsprechenden Verzeichnisse kopiert, und die Instanz wird mit dieser Information hochgefahren. Eine Ausnahme ist, wenn die Online-Redo-Log-Dateien noch zur Verfügung stehen und seit der letzten Sicherung noch keine (!) überschrieben worden ist. Es gibt Datenbanken, bei denen die Anzahl und Größe der Online-Redo-Log-Dateien so bemessen wird, dass diese Möglichkeit besteht. Wir möchten aber davor warnen, damit ein produktives Umfeld zu betreiben. Es reicht eine ungewöhnlich große Transaktion, um dieses Kartenhaus zum Einsturz zu bringen. Archivierung Wenn die Archivierung zum Zeitpunkt des Fehlers eingeschaltet war, kann eine Rücksicherung und eine anschließende Wiederherstellung durchgeführt werden. Die Vorgehensweise unterscheidet sich dabei nicht von derjenigen, die für die Wiederherstellung einer Online-Sicherung notwendig ist. Beispiel: Die Anwendung bricht mit folgender Fehlermeldung ab: ORA-00376: Datei 5 kann zur Zeit nicht gelesen werden ORA-01110: Datendatei 5: '/oradata/JAUX10G/ts_demo01.dbf' Listing 10.59: Fehlerhafte Datendatei
Zunächst wird der Tablespace (in diesem Fall ts_demo) offline gesetzt: SQL> ALTER TABLESPACE ts_demo OFFLINE IMMEDIATE;
Die Option IMMEDIATE muss angegeben werden, weil kein Checkpoint mehr geschrieben werden kann, da ja die zugehörige Datei nicht mehr verfügbar ist.
Ältere Techniken zur Sicherung
569
Die Datei /oradata/JAUX10G/ts_demo01.dbf wird jetzt vom Band wieder eingespielt. Danach erfolgt die Wiederherstellung, und der Tablespace wird wieder online gesetzt: SQL> ALTER DATABASE RECOVER AUTOMATIC DATAFILE '/oradata/JAUX10G/ts_demo01.dbf'; SQL> ALTER TABLESPACE ts_demo ONLINE; Listing 10.60: Offline-Wiederherstellung
10.7.2 Online-Sicherung Für die physikalische Sicherung muss nun ein Werkzeug verwendet werden, das geöffnete Dateien sichern kann. Die unter Unix verwendeten Werkzeuge wie cpio, tar oder dd bieten diese Möglichkeit, unter MS-Windows müssen Werkzeuge von Fremdanbietern benutzt werden, z.B. Arcserve oder Arkaia. Eher zum Testen geeignet ist das von Oracle mit der Datenbank-Software ausgelieferte OCOPY-Programm, das geöffnete Dateien kopieren kann. 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. 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 Tablespace wird auf Full Block Logging umgeschaltet. Der Checkpoint stellt einen konsistenten Stand der Dateien des Tablespace her. Da zum gleichen Zeitpunkt die Header-Informationen der Dateien eingefroren werden, existiert also ein definierter Synchronisationszeitpunkt, der als Startpunkt einer Wiederherstellung dient. Dass auf Full Block Logging umgeschaltet werden muss, hat seinen Grund in der unterschiedlichen Blockung von Datenbank und Betriebssystem. So wird vom Sicherungswerkzeug nicht ein kompletter OracleBlock in einer Operation gesichert und kann sich vor dem Kopieren des restlichen Teils verändern, so dass er dann auf der Sicherung inkonsistent ist. Kompensiert wird das dadurch, dass komplette Inhalte von Oracle-Blöcken in die Redo-LogDateien geschrieben werden. Als Folge steigt die Menge der Redo-Log-Dateien, die zur Archivierung anstehen, an. 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, solange die physikalische Sicherung läuft, in den Backup-Status gesetzt werden.
570
Wiederherstellungstechniken
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 Full Block Logging wird ausgeschaltet. Geprüft werden kann der Status der Datendateien über folgenden Befehl: SQL> SELECT * FROM v$backup; FILE# STATUS CHANGE# TIME ---------- ------------------ ---------- ------------------1 NOT ACTIVE 375471 14.05.2004 19:30:34 2 NOT ACTIVE 375475 14.05.2004 19:30:53 3 NOT ACTIVE 375478 14.05.2004 19:31:16 4 NOT ACTIVE 375481 14.05.2004 19:31:56 5 ACTIVE 375467 14.05.2004 19:32:23 Listing 10.61: Backup-Status für Online-Sicherung
Die Online-Sicherung wird also auf Ebene der Tablespaces durchgeführt. Bei der Online-Sicherung sind die Redo-Log-Dateien nicht Bestandteil der Sicherung, da diese während des Sicherungsvorganges weiterhin beschrieben werden und auch Wechsel der Redo-Log-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 RedoLog-Dateien 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> SQL> SQL> SQL>
ARCHIVE LOG LIST SELECT name FROM v$controlfile; SELECT * FROM v$log; SELECT name FROM v$datafile;
Listing 10.62: Ermitteln der zu sichernden Dateien
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;
Ältere Techniken zur Sicherung
571
Um im Fehlerfall eine Online-Sicherung für die Wiederherstellung verwenden zu können, müssen mindestens alle Redo-Log-Dateien vom Start der Sicherung bis zu deren Ende vorhanden sein. Gesichert werden typischerweise die archivierten Redo-Log-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 Redo-Log-Gruppen, der eine Archivierung auslöst. Zusätzlich kann in diesem Zuge eine Online-Sicherung der Kontrolldatei erstellt werden. Ratsam ist es auch, sich eine Trace-Datei mit dem passenden CREATE CONTROLFILE-Befehl 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 10.63: Sichern der Kontrolldateien
Nun sollte der zu Ende der Sicherung aktuelle Status der Redo-Log-Dateien als Ende des Protokolls ausgegeben werden. SQL> ARCHIVE LOG LIST SQL> SPOOL OFF SQL> EXIT Listing 10.64: Protokollierung
Wichtig ist, dass diese Sicherung nur zusammen mit den während der Sicherung anfallenden Redo-Log-Informationen eine komplette Datenbanksicherung ergibt.
10.7.3 Spezielle Techniken Insbesondere Hersteller von Speicherlösungen verwenden zum Teil eigene Verfahren, um eine Datenbank bzw. beliebige Dateien möglichst komfortabel und schnell zu sichern. Das am weitesten verbreitete Verfahren ist hierbei die Business Copy (BC). Dabei wird im Prinzip die Spiegelung (Raid-1) der Plattensysteme aufgehoben und der abgetrennte Spiegelteil über ein beliebiges Werkzeug gesichert. Die Datenbank läuft während dieser Zeit ungespiegelt. Die Firma EMC erlaubt eine solche Kopie (BCV = Business Continuance Volume) nur, wenn ein zusätzlicher Spiegel vorhanden ist. Ziel dieses Verfahrens ist zunächst einmal die möglichst geringe Beeinflussung der Produktionsdatenbank. Nachteil ist jedoch, dass in jedem Fall nur auf physikalischer Ebene gesichert wird (LUN = Logical Unit), d.h., dass die unterschiedlichen Datenbereiche einer Oracle-Datenbank (Daten-Tablespace, Temporär-Tablespace, Undo-Tablespace, Redo-Log-Dateien, archivierte Redo-Log-Dateien, tatsächlich gefüllter Platz in der Datenbank) keine Rolle spielen. Das führt in der Regel dazu, dass die gesicherte Datenmenge wesentliche größer ist als erforderlich.
572
Wiederherstellungstechniken
Nach einer erfolgreichen Sicherung kann der Spiegel wieder eingeschaltet werden. Die während der Sicherung in der Produktion angefallenen Änderungen werden in eigenen Log-Dateien protokolliert, so dass nur geänderte Blöcke synchronisiert werden müssen. Aber Vorsicht: Auch hier sind Betriebssystemblöcke und nicht etwa Oracle-Blöcke gemeint. Für die Sicherung der Oracle-Datenbank bedeutet dieses Verfahren, dass die gesamte Datenbank kurzzeitig in den BACKUP-Modus gesetzt werden muss. Hierfür gibt es den Befehl: ALTER DATABASE BEGIN BACKUP;
Zusätzlich kann die Datenbank in den Suspend-Modus versetzt werden. In diesem Modus werden alle I/O-Operationen der Datenbank verhindert. Dieser Modus wird eingeschaltet durch den Befehl ALTER SYSTEM SUSPEND;
Der Suspend-Modus ist bei vielen Herstellern die Voraussetzung für das Aufbrechen von Spiegeln. Nun kann einerseits die Sicherung auf dem abgetrennten Spiegel gestartet werden. Die I/O-Operationen können praktisch gleichzeitig mit ALTER SYSTEM RESUME;
wieder aktiviert werden. Auch der BACKUP-Status der Datenbank kann mit ALTER DATABASE END BACKUP;
wieder aufgehoben werden. Es sei an dieser Stelle noch einmal darauf hingewiesen, dass es sich bei diesem Verfahren um ein generelles Backup-Verfahren handelt, das nicht auf die Eigenarten der Oracle-Datenbank eingeht. Daher sollte geprüft werden, ob eine Sicherung mit dem Recovery Manager nicht effektiver und eventuell sogar schneller ist. Beachten Sie dabei: Es geht nicht nur um die Sicherung der Datenbank, sondern insbesondere um eine möglichst schnelle Wiederherstellung. Und dazu gehört zum Beispiel, dass im Fehlerfall eventuell nur ein Tablespace zurückgesichert werden muss. Bei einer Business Copy und der bei großen Datenbanken üblichen RAID-10-Verteilung der Daten müssen Sie mit großer Wahrscheinlichkeit die gesamte Datenbank zurücksichern. Eine Rücksicherung der Datenbank aus einer Business Copy ist dabei eventuell noch schneller als die Rücksicherung einer Datendatei aus einer Recovery-Manager-Sicherung. Die anschließende Wiederherstellung der Datenbank über die archivierten Redo-Log-Dateien kann aber ein Vielfaches an Zeit dauern, je nachdem, ob Sie die gesamte Datenbank oder nur einen Tablespace wiederherstellen müssen.
Tuning Akzeptierte Antwortzeiten, gute Skalierbarkeit und eine ausreichende Verfügbarkeit sind die drei Säulen, die nach wie vor eine erfolgreiche Datenbankinstallation auszeichnen. Die Skalierbarkeit wird dabei durch einen sparsamen Umgang mit Datenbankressourcen erreicht, der garantiert, dass auch bei wachsenden Benutzerzahlen und Datenmengen die vorgegebenen Antwortzeiten eingehalten werden können. Bei der Vielzahl an Merkmalen und Funktionalitäten, die Oracle 10g mittlerweile bietet, ist es nicht immer leicht, diese drei Säulen dauerhaft und zuverlässig zu implementieren. Das vorliegende Kapitel »Tuning« konzentriert sich auf die ersten beiden – Antwortzeiten und Skalierbarkeit – und zeigt, wie Datenbankinstanzen und Anwendungen, die mit ihnen arbeiten, systematisch analysiert und erfolgreich optimiert werden können. In der Praxis ist es nicht immer leicht, »Tuning« von »Troubleshooting« zu unterscheiden. Ist beispielsweise die lange Laufzeit einer PL/SQL-Prozedur, die durch Wartezyklen und Hang-Situationen beim Locking verursacht wird, ein Problem, das durch Tuning- oder Troubleshooting-Maßnahmen behoben wird? Wie verhält es sich mit Verzögerungen bei Schreiboperationen, die zustande kommen, weil die betreffende Session auf die Fertigstellung eines Checkpoints warten muss und aus diesem Grunde kein Log Switch durchgeführt werden kann? Im Kontext dieses Buches verstehen wir »Tuning« als Summe aller Maßnahmen, welche die Optimierung der Antwortzeiten und die Verbesserung der Skalierbarkeit zum Ziele haben. Tuning-Maßnahmen legitimieren sich nicht durch auftretende Fehler. Im Gegensatz dazu bezeichnet »Troubleshooting« alle Aktivitäten zur Analyse und Behebung von konkreten Fehlersituationen. Fehlersituationen werden durch Fehlermeldungen im Kontext von Sessions oder in entsprechenden Log-, Trace- oder Alert-Dateien ausgewiesen. Ergänzend hierzu verstehen wir unter »Monitoring« alle Aktivitäten, die der bewertenden Erfassung diverser Datenbankressourcen dienen und als Ziel die frühzeitige Erkennung möglicher Fehlerquellen oder Performance-Engpässe haben. Den Themen »Troubleshooting« und »Monitoring« werden aus diesem Grunde eigene Kapitel gewidmet.
11.1
Strategie
Sorgfältig geplante und entsprechend entwickelte Systeme benötigen keine Tuning-Maßnahmen, sondern liefern im Rahmen der für sie definierten Kontexte zufrieden stellende Antwortzeiten und ausreichende Skalierungen. Diese Aussage ist zugegebenermaßen radikal, entbehrt jedoch nicht einer gewissen realistischen Grundlage. Trotz allem sind – wie wir alle wissen – Tuning-Maßnahmen häufig notwendig. Die Gründe hierfür können vielfältig sein: Die Realität hat sich geändert, und daraus resultieren neue Anforderungen an die Datenbank und Instanz.
574
Tuning
Die Implementierung einer Anwendung wurde nicht Oracle-spezifisch, sondern offen für unterschiedliche Datenhaltungssysteme konzipiert. Bei entsprechendem Datenvolumen oder entsprechender Last können daher vorgegebene Antwortzeiten nicht mehr eingehalten werden. Die Anwendung wurde ohne gründliche Funktions- und Anforderungsanalyse konzipiert und »heiß gestrickt«. Bei produktivem Einsatz offenbaren sich die konzeptionellen Schwachstellen. Allmähliche funktionale Erweiterungen haben eine vormals gut optimierte Anwendung über die Jahre ausgehöhlt. Eine Konsolidierung und Optimierung ist daher angesagt. Die Ressourcenanforderungen einer Anwendung sind (noch) unbekannt. Nach der Installation in eine bereits genutzte Instanz kommt es zu Performance-Problemen. Aus diesen wenigen Beispielen lassen sich bereits wichtige Maßnahmen ableiten, die den Tuning-Aufwand erheblich minimieren helfen und im Vorfeld schon gute Antwortzeiten und Skalierungen erwarten lassen: Das Feinkonzept sollte auf der Grundlage einer gründlichen Anforderungsanalyse erstellt werden, die – soweit möglich – zukünftige Entwicklungen mit berücksichtigt. Die physische Implementierung des Datenmodells sollte mit Blick auf die technischen Möglichkeiten einer Oracle-Datenbank erfolgen: Es werden mittlerweile vielfältige Tabellen- und Indextypen unterstützt, die – sinnvoll eingesetzt – erhebliche Performance-Vorteile bieten können. Eine sinnvolle Modularisierung sollte dafür sorgen, dass aufwändige Datenmanipulationen möglichst »datennah« realisiert werden und die Programmlogik effizient aufgesetzt wird. Bei der Konfiguration der Datenbank sollten konsequent neue Techniken, die sich bewährt haben, genutzt werden, so z.B. Locally Managed Tablespaces, automatisiertes Undo Management und automatisierte Platzverwaltung in Segmenten (ASSM). Gleichzeitig sollten die grundlegenden Ressourcen, wie z.B. die SGA und der Redo-Log-Bereich, ausreichend dimensioniert sein. Anwendungen mit derart konzipierter Basis lassen sich in der Regel mit vertretbarem Aufwand optimieren, wenn sich eine Veränderung des Zeitverhaltens abzeichnet. Tuning-Maßnahmen, die sich in den oben genannten Bereichen bewegen und beispielsweise Anpassungen am Datenmodell vornehmen müssen, sind entsprechend aufwändig, zeitintensiv und damit teuer. Bei der Optimierung von Instanzen lassen sich unterschiedliche Strategien anwenden: Mit Hilfe eines allgemeinen Health Check lassen sich allgemeine Kennzahlen ermitteln, die grobe Anhaltspunkte für den »Gesundheitszustand« der betreffenden Instanz liefern. Hierzu zählen beispielsweise die Trefferquoten im Buffer Pool und im Library Cache, eine Statistik der Wartezyklen und dergleichen mehr. Das im Abschnitt Monitoring und Engpassanalyse vorgestellte Werkzeug Statspack kann in diesem Kontext gut zum Einsatz kommen. Die gelieferten
Hilfsmittel
575
Kennzahlen können zu einer angepassten Parametrierung der Instanz führen, lassen aber nur wenige Rückschlüsse auf die Performance der einzelnen Anwendungen zu, welche die Datenbank nutzen. Tuning im engeren Sinne des Wortes kümmert sich um die Sicherstellung von akzeptablen Antwortzeiten für geschäftsrelevante Prozesse. Antwortzeiten lassen sich in CPU- und Wartezeiten untergliedern. CPU-Zeiten entstehen beispielsweise durch das Parsing von SQL-Befehlen oder die Ausführung von Prozeduren. Wartezeiten ergeben sich immer dann, wenn die Datenbank auf die Bereitstellung von Ressourcen oder die Fertigstellung »externer« Anforderungen – z.B. IO-Operationen – warten muss. Tuning reagiert in diesem Zusammenhang immer auf konkrete Probleme durch die Erstellung eines detaillierten Lastprofils, das die anfallenden CPU- und Wartezeiten im Kontext eines konkretes Programmmoduls oder SQL-Befehls auflistet. Die Optimierung des betreffenden Prozessen wird dann erreicht, indem die markantesten Problembereiche dieses Lastprofils analysiert und optimiert werden. Zeigt das Lastprofil einer Prozedur beispielsweise, dass 60% der Wartezeiten aufgrund von IO-Operationen entstehen und nur 5% durch Latch Contention, werden in erster Linie die IO-Operationen für eine Optimierung in Frage kommen, weil sie das größte Potenzial für die Verkürzung der Antwortzeit bergen. Da aggregierte Instanzstatistiken keine Möglichkeiten bieten, konkrete Rückschlüsse auf die Engpässe einzelner Anwendungen zu ziehen, ist der oben erwähnte Problembezug für das Tuning von enormer Bedeutung. Darüber hinaus ist Tuning immer auch Teamarbeit: Der DBA mit seiner detaillierten Kenntnis der Instanz und ihrer Interaktionen braucht in der Regel die Unterstützung eines »Anwendungsadministrators«, der die Datenstrukturen und Funktionsabläufe der betreffenden Anwendung kennt.
11.2
Hilfsmittel
11.2.1 Oracle Performance-Views Die Oracle-Datenbank stellt eine große Menge von Performance-Statistiken in so genannten Performance-Views (V$-Views) zur Verfügung. Dabei handelt es sich um vordefinierte Views im Schema SYS. Im Gegensatz zu den Data-DictionaryViews (USER_*, ALL_*, DBA_*) basieren diese jedoch nicht auf festen Tabellen, die den Inhalt der Datenbank beschreiben, sondern auf speziellen Performance-Tabellen (X$-Tabellen), die u.a. Speicherstrukturen der SGA – also des von Oracle benutzten Shared-Memory-Bereichs – abbilden. Auf diese Weise werden interne PerformanceWerte dem Benutzer in Tabellenform zugänglich gemacht. Diese Methode hat den Charme, dass komplexe SQL-Befehle zur Aufarbeitung der dargebotenen statischen Rohdaten eingesetzt werden können. Zu beachten ist, dass die X$-Tabellen zwar zugänglich sind, aber zumeist kryptischen Inhalt haben, nicht dokumentiert sind und auch die Struktur und Namensgebung sich jederzeit ändern kann. Diese sollten daher i.A. nicht verwendet werden (Oracle verwendet diese jedoch intern z.B. für das Füllen des Automatic Workload Repositorys). Stattdessen sollten Zugriffe über die V$-Views realisiert werden.
576
Tuning
In jeder Datenbankversion kommt stets eine nicht unerhebliche Zahl neuer Performance-Views hinzu, daher soll an dieser Stelle vorrangig eine strukturierte Übersicht über die unterschiedlichen Messzahlen gegeben werden. Außerdem werden die wichtigsten Views vorgestellt. Grundlegendes Es stehen Statistiken für zahlreiche Funktionskontexte der Datenbank zur Verfügung. Die wichtigsten dieser Kontexte sind: Sessions, z.B. Wartezeiten für jede einzelne Session Services, also beispielsweise verschiedene Anwendungen innerhalb einer Datenbank. Statistiken auf Service-Ebene stehen erst seit Oracle 10g zur Verfügung. Datendateien, z.B. Umfang und Performance von Lese- und Schreibzugriffen pro Datei Segmente, z.B. die Anzahl logischer oder physischer Lese- und Schreibzugriffe pro Tabelle, Index etc. SQL-Kommandos, die sich im Cursor-Cache (SQL-Area) befinden, die beispielsweise Anzahl der Ausführungen, die dadurch verursachten Lesezugriffe, der Ausführungsplan etc. Aktive Transaktionen, beispielsweise der Startzeitpunkt, I/O-Daten Undo-Segmente Sperrverhalten von Oracle, insbesondere Sperren für Datensätze (Enqueues) sowie interne Sperren (Latches) Außerdem gibt es Gesamtstatistiken (Systemebene), die Summenwerte über alle Sessions darstellen. In den Versionen bis einschließlich Oracle9i wurden ausschließlich kumulative Performance-Werte bereitgestellt, es handelte sich also um Gesamtstatistiken seit dem Start der Instanz. Eine Reinitialisierung dieser Performance-Werte ist nicht möglich, ohne die Instanz neu zu starten. Das bedeutet auch, dass kurzfristige Schwankungen, Ausreißer oder plötzliche Performance-Einbrüche, z.B. wenn eine Datendatei seit einer halben Stunde ein schlechteres I/O-Verhalten zeigt, sich in diesen Views nicht auf den ersten Blick zeigen. Die anomalen Werte werden durch die über Wochen oder Monate der Instanzlaufzeit gesammelten normalen Werte »weggemittelt«. Voraussetzung für ernsthafte Performance-Untersuchungen ist daher die Bildung von Snapshots, indem beispielsweise alle 30 Minuten ein Auszug dieser Performance-Werte ermittelt wird und anschließend die Differenzwerte zwischen Endund Anfangszeitpunkt eines solchen Intervalls gebildet werden. Erst dadurch zeigt sich das Verhalten innerhalb dieses Intervalls. Performance-Tools wie Statspack/ AWR oder Precise bauen auf dieser Snapshot-Technik auf. Außerdem sollten regelmäßig Baselines, also Performance-Daten über ein Intervall mit einer bestimmten Standardlast, erzeugt und archiviert werden, um längerfristige Entwicklungen zu erkennen und analysieren zu können. Auch dies wird durch entsprechende Tools geleistet (für Statspack/AWR siehe den Abschnitt Monitoring und Engpassanalyse).
Hilfsmittel
577
Einen Spezialfall bilden Sessions. Eine Session befindet sich stets in einem von drei Zuständen: Die Session ist inaktiv, d.h., sie wartet auf ein neues SQL-Kommando vom Client. Die Session ist aktiv und verbraucht CPU-Zeit. Die Session ist aktiv, aber befindet sich in einem Wartezustand, z.B. es wird auf die Beendigung einer physischen Lese-Operation gewartet. Anzahl und Dauer aller Wartezustände werden in V$SESSION_EVENT kumulativ protokolliert. Kumulativ bedeutet hierbei »seit Beginn der Session«. Die Statistiken auf Service- und Systemebene ergeben sich durch Aufsummierung der Statistiken aller entsprechenden Sessions. Für Wartezustände sowie für Block-Leseoperationen ist auch eine Histogramm-Darstellung, also eine Auftragung nach Wartezeit bzw. Zugriffszeit, verfügbar. Auch hier sind erst über die oben beschriebene Snapshot-Technik aktuelle Entwicklungen nachvollziehbar. Damit diese Histogramm-Daten verfügbar sind, muss der Serverparameter timed_statistics = TRUE gesetzt sein (dies ist der Default-Wert). Neuerungen in Oracle 10g Seit Oracle 10g sind nun auch direkt in der Datenbank einige Statistiken verfügbar, die sich auf ein aktuelles Intervall bzw. auf historische Intervalle beziehen. Diese werden als Metriken bezeichnet. Eine Nachbearbeitung mit Hilfe der SnapshotTechnik ist für diese Werte nicht mehr notwendig. Dabei wird als Intervalllänge meist eine Minute angesetzt. Ausnahmen davon bilden: Metriken auf Tablespace-Ebene (10-Minuten-Intervalle) Einige Metriken auf Session- und Systemebene, z.B. verbrauchte CPU-Zeit sowie Anzahl logsicher und physischer Lese-Operationen (15-Sekunden-Intervalle) Für einige Metriken existieren separate Views, die nicht nur das aktuelle, sondern auch die letzten historische Intervalle darstellen. Eine Übersicht über alle Metriken findet sich in der View V$METRICNAME. Die Implementierung in den einzelnen Performance-Views ist leider nicht einheitlich. Teilweise sind die einzelnen Metriken als Spalten abgebildet (z.B. in V$SESSMETRIC und V$EVENTMETRIC), teilweise als Zeilen mit der Join-Spalte metric_id (z.B. in V$SYSMETRIC). In V$METRICGROUP wird noch eine Kategorisierung der einzelnen Metriken vorgenommen. Die Kategorie einer Metrik entscheidet auch über die Intervalllänge und die Anzahl historischer Intervalle (Spalten interval_size und max_interval). Mit Oracle 10g werden auch die Wartezustände in Kategorien unterteilt (Spalte wait_class in V$EVENT_NAME). Dies ist insbesondere zur Aussortierung »unechter« Wartezustände – so genannter Idle Events – sehr nützlich. Darunter fällt beispielsweise das Warten auf SQL-Kommandos vom Client, das in den meisten Fällen nicht performance-relevant ist, aber auch eine ganze Reihe weiterer Zustände (wait_class = 'Idle'). Andere interessante Eingrenzungen sind:
578
Tuning
Physische Lese- und Schreiboperationen: (wait_class = 'User I/O') Wartezustände, die zunächst einmal durch reine Konfigurationsmaßnahmen entschärft werden können, z.B. kann das Warten auf Checkpoints durch mehr oder größere Redo-Log-Dateien beseitigt werden (wait_class = 'Configuration') Wartezustände wegen Cache- oder Sperrsynchronisation in RAC-Umgebungen (wait_class = 'Cluster') Netzwerk-Latenzen, z.B. das Lesen via DB-Link (wait_class = 'Network') Statistiken zur Beanspruchung von Betriebssystemressourcen werden erstmalig in Oracle 10g automatisch gesammelt. Diese Funktion ist unabhängig von dem bereits in älteren Datenbankversionen bekannten Serverparameter timed_os_statistics, der deutliche Performance-Auswirkungen hat und daher sehr vorsichtig benutzt werden sollte. Zur Bedeutung der einzelnen Statistiken wie OS-Statistiken siehe Dokumentation Oracle 10g Database Reference. Statistiken (kumulativ)
Wartezustände (kumulativ)
Sessions
V$SESSION V$SESSTAT V$MYSTAT V$SESS_IO
Services
Metrik (aktuelles Intervall)
MetrikHistorie (aktuelle und historische Intervalle)
V$SESSION_ EVENT V$SESSION_ WAIT V$SESSION_ WAIT_ CLASS
V$SESSMETRIC
V$ACTIVE_ SESSION_ HISTORY
V$SERVICE_ STATS
V$SERVICE_ EVENT V$SERVICE_ WAIT_CLASS
V$SERVICEMETRIC
V$SERVICE METRIC_ HISTORY
System
V$SYSSTAT
V$SYSTEM_ EVENT V$SYSTEM_ WAIT_CLASS
V$EVENT_ HISTOGRAM
V$EVENTMETRIC V$SYSMETRIC V$SYSMETRIC_ SUMMARY V$WAITCL ASSMETRIC
V$SYSMETRIC_ HISTORY V$WAIT CLASS METRIC_ HISTORY V$METRIC _HISTORY
Dateien
V$FILESTAT V$TEMPSTAT
V$FILE_ HISTORAM V$TEMP_ HISTORAM
V$FILEMETRIC
V$FILEMETRIC_ HISTORY
Segmente
V$SEGSTAT V$SEGMENT_ STATISTICS
Tabelle 11.1: V$Tabellen und Funktionskontexte
Histogramme (kumulativ)
Hilfsmittel
579
Statistiken (kumulativ)
SQL
V$SQL V$SQL_PLAN V$SQL_PLAN_ STATISTICS
Transaktionen
V$TRANSACTION
UndoSegmente
V$ROLLSTAT
Sperren (Enqueu es)
V$TRANSACTION_ ENQUEUE V$ENQUEUE_LOCK V$ENQUEUE_STAT V$LOCK V$LOCKED_OBJECT
Latches
V$LATCH V$LATCHHOLDER V$LATCH_MISSES
Betriebssystem
V$OSSTAT
Wartezustände (kumulativ)
Histogramme (kumulativ)
Metrik (aktuelles Intervall)
MetrikHistorie (aktuelle und historische Intervalle)
V$SQL_ WORKAREA_ HISTORAM
V$UNDOSTAT
Tabelle 11.1: V$Tabellen und Funktionskontexte (Forts.)
In manchen der aufgelisteten Performance-Views findet sich jeweils auch der Name der entsprechenden Statistik oder Metrik, manchmal ist jedoch nur ein Fremdschlüssel auf eine Referenztabelle vorhanden (z.B. Spalte statistic# in V$SESSTAT und V$SEGSTAT, Spalte event# in V$EVENTMETRIC etc.) Dann kann zumindest per Join mit der Referenztabelle der entsprechende Name dazugebunden werden. Die benutzten Referenztabellen sind: V$METRICNAME für Metriken. Die Spalte metric_id ist Join-Spalte, metric_name beschreibt die entsprechende Metrik. Über die Spalte metric_unit ist auch die Maßeinheit gegeben. Die Metrik-Kategorien sind in V$METRICGROUP zusammengefasst. V$EVENT_NAME für Wartezustände. Die Spalte event# ist Join-Spalte, name enthält die Bezeichnung des Wartezustands. Die Maßeinheit ist hier immer die Dauer des Wartezustandes in hundertstel Sekunden (Centisekunden). Eine Ausnahme bildet die Spalte time_waited_micro, die in Mikrosekunden (millionstel Sekunden) misst und ausschließlich für sehr kurze Wartezeiten einen sinnvollen Genauigkeitsvorteil bietet.
580
Tuning
V$STATNAME für Statistiken auf Session-, Service- und Systemebene. Die Spalte statistic# ist Join-Spalte, name enthält die Statistikbezeichnung. Die Spalte class gibt an, zu welcher Performance-Kategorie die Statistik gehört. Für diese Kategorien gibt es aber keine eigene Referenztabelle, sondern es gilt folgendes Schema: 1: Benutzer-Sessions 2: Redo-Log-Aktivität 4: Sperrverhalten (Enqueues) 8: Caching (physischer und logischer I/O) 16: Betriebssystem (diese Statistiken werden nur dann gepflegt und angezeigt, wenn der Serverparameter timed_os_statistics auf einen Wert größer 0 gesetzt ist) 32: RAC (Real Application Cluster) 64: SQL-Kommandos (Zugriffsmethoden auf Tabellen, Parsing, Sortierungen) 128: Debugging (interne Statistiken) Liegt eine Zugehörigkeit zu mehreren Kategorien vor, wird dieses Schema additiv verwendet. Zur Eingrenzung auf eine Kategorie muss also eine bitweise ANDVerknüpfung (Funktion BITAND) durchgeführt werden. V$SEGSTAT_NAME für Statistiken auf Segmentebene. Die Spalte statistic# ist JoinSpalte, name enthält die Statistikbezeichnung. V$LATCHNAME für Statistiken auf Latch-Ebene. Die Spalte latch# ist Join-Spalte, name enthält den Namen des Latches. Advisories Ein sehr nützliches Hilfsmittel für den Bereich Instance-Tuning stellen die so genannten Advisories dar. Dabei handelt es sich um Empfehlungen für die Dimensionierung von Buffer-Cache, Shared-Pool, Java-Pool und PGA-Pool. Die Advisories sind als Histogramme aufgebaut und geben für verschiedene Größen des entsprechenden Pools das Laufzeitverhalten an (beispielsweise Trefferraten im BufferCache, Sortieroperationen mit Auslagerung in Temporär-Segmente). Für den Buffer-Cache (Default-Buffer-Cache mit 8-K-Blockgröße) sieht das beispielsweise so aus: SQL> SELECT size_for_estimate ,size_factor ,buffers_for_estimate ,estd_physical_read_factor ,estd_physical_reads ,estd_physical_read_time FROM v$db_cache_advice WHERE name = 'DEFAULT' AND block_size = 8192;
AS AS AS AS AS AS
size_est factor buffers read_fct phy_reads phy_rtime
Hilfsmittel
581
SIZE_EST FACTOR BUFFERS READ_FCT PHY_READS PHY_RTIME ---------- ------ ---------- ---------- ---------- --------4 ,1 501 5,5853 125998 2397 8 ,2 1002 3,3464 75490 1347 12 ,3 1503 2,6664 60152 1029 16 ,4 2004 2,2532 50830 835 20 ,5 2505 2,0398 46016 735 24 ,6 3006 1,6026 36152 530 28 ,7 3507 1,3471 30389 410 32 ,8 4008 1,1751 26508 329 36 ,9 4509 1,0887 24559 289 40 1,0 5010 1 22559 247 44 1,1 5511 ,9437 21288 221 48 1,2 6012 ,8933 20152 197 52 1,3 6513 ,8467 19101 175 56 1,4 7014 ,7896 17813 148 60 1,5 7515 ,7596 17135 134 64 1,6 8016 ,7183 16203 115 68 1,7 8517 ,686 15474 100 72 1,8 9018 ,6469 14593 82 76 1,9 9519 ,6243 14085 71 80 2,0 10020 ,6108 13779 65
Es werden verschiedene Cache-Größen zwischen 10% und 200% der aktuellen Cache-Größe betrachtet. Die ersten drei Spalten geben die betrachtete Cache-Größe an, die folgenden Spalten geben absolute und relative Werte für physische Lese-Operationen an, beispielsweise gilt: Eine Verdopplung des Buffer-Caches führt zu einer Reduktion der physischen Lese-Operationen auf ca. 61% (gerechnet seit Instanzstart oder seit der letzten Änderung der Buffer-Cache-Größe). Um einen Eindruck von der tatsächlichen Zeiteinsparung zu bekommen, sollte auch die letzte Spalte betrachtet werden, welche die Gesamtzeit für physisches Lesen in hundertstel Sekunden angibt. Für den Shared Pool kann die Parsing-Zeit für SQL-Kommandos in Abhängigkeit von der Pool-Größe untersucht werden. Analog ist dasselbe für den Java-Pool möglich (V$JAVA_POOL_ADVICE) SQL> SELECT shared_pool_size_for_estimate ,shared_pool_size_factor ,estd_lc_load_time ,estd_lc_load_time_factor FROM v$shared_pool_advice;
AS AS AS AS
size_est factor load_time l_factor
Auch für den PGA-Pool (dimensioniert durch den Serverparameter pga_aggregate_ target) steht eine Advisory zur Verfügung. Die View V$PGA_TARGET_ADVICE_HISTOGRAM liefert für verschiedene Größen des PGA-Pools je ein Histogramm über die Anzahl von Operationen, die eine bestimmte PGA-Größe beansprucht haben. Ein Auszug aus dieser Performance-View soll dies verdeutlichen:
582 SQL> SELECT pga_target_for_estimate ,pga_target_factor ,low_optimal_size ,high_optimal_size ,estd_optimal_executions ,estd_onepass_executions ,estd_multipasses_executions FROM v$pga_target_advice_histogram;
Tuning AS AS AS AS AS AS AS
size_est factor lower_lim upper_lim in_memory pass_1 pass_n
SIZE_EST FACTOR LOWER_LIM UPPER_LIM IN_MEMORY PASS_1 PASS_N --------- ------ --------- --------- --------- ------ -----... 23592960 ,75 4194304 8388607 0 0 0 23592960 ,75 2097152 4194303 0 0 0 23592960 ,75 1048576 2097151 3 0 2 23592960 ,75 524288 1048575 223 0 8 23592960 ,75 262144 524287 40 0 0 23592960 ,75 131072 262143 18 0 0 23592960 ,75 65536 131071 47 0 0 23592960 ,75 32768 65535 0 0 0 23592960 ,75 16384 32767 0 0 0 23592960 ,75 8192 16383 0 0 0 23592960 ,75 4096 8191 0 0 0 23592960 ,75 2048 4095 16817 0 0 23592960 ,75 1024 2047 0 0 0 23592960 ,75 0 1023 0 0 0 ...
Dies bedeutet, dass bei einem PGA-Pool mit 75% der aktuellen Größe die meisten Operationen (Sortierungen, Hash-Joins sowie Aufbau und Merging von BitmapIndizes) weiterhin im Speicher hätten stattfinden können. Für die weitaus meisten – nämlich 16817 Operationen – genügt dafür sogar ein Arbeitsbereich zwischen 2 KB und 4 KB innerhalb des PGA-Pools. Allerdings hätten insgesamt zehn Operationen (mit Sortiervolumina zwischen 512 KB und 2 MB) auch eine mehrfache Auslagerung in Temporär-Segmente erfordert (Spalte pass_n). Der PGA-Pool sollte so dimensioniert werden, dass die meisten Operationen im Hauptspeicher ausgeführt werden können. Weniger als 10% aller Operationen sollten eine einzige Auslagerung in Temporär-Segmente benötigen (Spalte pass_1). Bei OLAP-Systemen kann diese Anforderung etwas gelockert werden. Mehrfach-Auslagerungen sollten aber in jedem Fall vermieden werden. Die von den Advisories projizierten Werte sind sehr verlässlich, da intern einfach ein entsprechend großer Pool-Bereich simuliert wird, ohne jedoch konkrete Inhalte (z.B. Blöcke im Buffer-Cache) abzuspeichern. Bei einer dynamischen Vergrößerung oder Verkleinerung eines Pools (manuell via ALTER SYSTEM-Kommando oder automatisch bei gesetztem Serverparameter sga_target) wird die zugehörige Advisory reinitialisiert.
Hilfsmittel
583
Persistente Performance-Daten Seit Oracle 10g werden im Rahmen des AWR (Automatic Workload Repository) Snapshots der meisten oben genannten Performance-Views regelmäßig in persistenten Tabellen gesichert. Damit sind beispielsweise bei den oben genannten Metrik-Historien auch ältere Versionen zugänglich. Über die AWR-Reports können dann auch gleich Auswertungen nach der Differenzmethode vorgenommen werden. Dieser Mechanismus ist nach Erstellung der Datenbank automatisch aktiviert. Für weitere Informationen zum AWR siehe auch Abschnitt Monitoring und Engpassanalyse.
11.2.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 14 beschrieben, das sich generell mit dem Thema Monitoring auseinander setzt. Diesen Werkzeugen liegen unterschiedliche Ansätze zugrunde. Einige greifen auf die virtuellen Performance-Views (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 müssen lizenziert werden. 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 Skripte erstellen, die auch oft in der Literatur zum Thema Oracle-Tuning 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. Hierin ist sicher ein Nachteil zu den farbigen Grafiken der Werkzeuge zu sehen, jedoch sind die Ausgaben der Skripte im Gegenzug nicht grafisch überfrachtet und liefern direkt die gewünschten Informationen. In diesem Kapitel wird ausschließlich die Nutzung von SQL-Befehlen und Skripten aus dem Lieferumfang von Oracle 10g beschrieben, da wir nicht davon ausgehen können, dass jedem Leser ein zusätzliches Werkzeug zur Verfügung steht und wir auch keine Gebrauchsanweisungen für die genannten Werkzeuge liefern, sondern einen generellen Überblick über die Tuning-Möglichkeiten geben möchten.
584
Tuning
Statspack Statspack ist die Weiterführung des früheren Tools utlbstat/utlestat. Es besteht aus Skripten, die mit der Oracle Server-Software ausgeliefert werden. Beim Aufruf dieser Skripte werden in einem speziellen Schema Tabellen installiert, in die 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. Hervorzuheben ist, dass Statspack PerformanceDaten vornehmlich aus Sicht der Instanz darstellt, ein problemorientiertes Tuning von einzelnen Modulen daher nicht optimal unterstützt. Installation Zur Installation von Statspack startet man, als SYSDBA angemeldet, ein Skript, das einen Benutzer PERFSTAT anlegt. Das Skript verlangt nach der Angabe eines Passwortes für diesen Benutzer, 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 SQL> @?/rdbms/admin/spcreate
Benutzung Nach der Installation der Packages können nun nach Anmeldung als Benutzer PERFSTAT-Snapshots erstellt werden, die jeweils einen Abzug der V$-Tabellen darstellen. SQL> connect perfstat/perfstat SQL> execute statspack.snap
Es bietet sich an, diese Snapshots in regelmäßigen Intervallen 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 hierfür das Skript 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. SQL> @?/rdbms/admin/spreport
Hilfsmittel
585
Einstellungen und Pflege der Tabellen Wie viele Informationen im Rahmen eines Snapshots gesammelt werden, hängt von dem so genannten »Snap-Level« ab. Standardeinstellung ist der Level 5. Diese Einstellung ist auch durchaus sinnvoll, da schon umfangreiche Informationen über die Instanz und auch ressourcenintensive SQL-Befehle geliefert werden. 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 );
Bei der Erstellung des Snapshots wirken die gesetzten Thresholds alternativ, d.h., ein SQL-Statement wird ausgegeben, wenn es mindestens einen der Thresholds überschreitet. Im obigen Beispiel würden also solche SQL-Statements ausgegeben, die mehr als 10000 Blöcke gelesen oder mehr als 1000 Blöcke physikalisch gelesen haben. Die Level 0 bis 4 haben identische Funktionalität. Unter den ausgegebenen Informationen sind vor allem folgende relevant (alle angegebenen Informationen beziehen sich auf den ausgewählten Zeitraum): Allgemeine Performance-Daten, insbesondere Lastprofil, Trefferraten im BufferCache, Library-Cache etc. Wartezustände Systemstatistiken I/O-Statistiken pro Tablespace und pro Datafile Statistiken über den Buffer-Cache-, Shared-Pool und PGAs der Serverprozesse, jeweils auch simulierte Statistiken für größere/kleinere Dimensionierung der jeweiligen Komponenten Statistiken über Undo-Segmente Veränderungen von Serverparametern
586
Tuning
Der Level 5 ergänzt diese Informationen um eine Liste der SQL-Statements mit dem höchsten Ressourcenverbrauch unter Benutzung der oben beschriebenen Thresholds. Level 6 gibt außerdem die Ausführungspläne dieser Statements aus. Level 7 speichert außerdem Segmentstatistiken, analog zu dem obigen Beispiel können auch hier Thresholds übergeben werden, z.B. für die Anzahl logischer oder physischer Reads (Parameter i_seg_log_reads_th und i_seg_phy_reads_th). Level 10 schließlich speichert außerdem detaillierte Informationen über Latches. Dies sollte jedoch nur in Ausnahmefällen verwendet werden, da es relativ aufwändig ist. 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. Es bietet sich an, in regelmäßigen Abständen, z.B. wöchentlich, einen Satz umfangreicherer Snapshots zu erzeugen (Level 6 oder Level 7) und diese aufzubewahren, um eine Referenz auch für langfristige Vergleiche zu haben. Da man aber meistens aus Gründen des Speicherplatzbedarfs nicht sämtliche Snapshots der letzten Monate behalten möchte, wird zumeist via DBMS_JOB ein automatisches Löschen älterer Snapshots eingerichtet. Eine Lösung bildet hier die Definition so genannter »Baselines«, darunter sind gewissermaßen »löschgeschützte« Snapshots zu verstehen, die durch oben beschriebenes Purge-Skript eben nicht gelöscht werden. SQL> execute statspack.make_baseline( i_begin_date => TRUNC(SYSDATE) ,i_end_date => SYSDATE );
etikettiert alle heute angelegten Snapshots als Baselines. Über die Prozedur CLEAR_BASELINE kann analog der Baseline-Status wieder aufgehoben werden. Interpretation der Ausgabe Die Präsentation der Ergebnisse ist recht übersichtlich, sämtliche Trefferraten oder sonstigen Werte sind aufbereitet und mit guten Überschriften und Kommentaren versehen. Auch werden WAIT-Events schon nach ihrer Relevanz geordnet als Top-5-Liste ausgegeben, ebenso wie I/O-Statistiken oder Undo-Segment-Statistiken.
Hilfsmittel
587
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. Eine detaillierte Beschreibung der Statspack-Funktionen enthält die Datei rdbms\doc\spdoc.txt im Oracle Home-Verzeichnis.
Als weitere Auswertungsmöglichkeit hat sich die Webseite www.oraperf.com bewährt. Dort kann ein erzeugter Statspack-Report hochgeladen werden. Ein automatischer Analyse-Engine erzeugt daraus einen weiteren Report in HTML-Form, der noch mehr Übersichtlichkeit sowie zahlreiche Lösungsvorschläge insbesondere im Zusammenhang mit aufgetretenen Wartezuständen bietet. AWR (Automatic Workload Repository) Das mit der Oracle-Version 10g eingeführte AWR (Automatic Workload Repository) benutzt denselben Ansatz wie Statspack. Auch hier werden regelmäßig Auszüge aus verschiedenen Performance-Tabellen generiert und in Tabellen abgespeichert, um anschließend über beliebige Intervalle Auswertungen erstellen zu können. Allerdings braucht hierzu kein spezielles Schema angelegt zu werden, stattdessen werden die Snapshot-Daten in dafür vorgesehenen Tabellen im Schema SYS abgelegt. Da u.U. sehr viele Daten anfallen können, liegen diese Tabellen nicht im SYSTEM-, sondern im SYSAUX-Tablespace. Die gesammelten Daten können über Data-Dictionary-Views (DBA_HIST_*) abgefragt werden, die zugehörigen Data-Dictionary-Tabellen haben Namen der Form WRH$_* und WRM$_*. Außerdem wird aus Performance-Gründen für die AWRSnapshots überwiegend auf X$-Tabellen statt auf V$-Views zugegriffen.
588
Tuning
Benutzung Ein AWR-Snapshot kann manuell erstellt werden durch folgenden Aufruf: SQL> execute dbms_workload_repository.create_snapshot( flush_level => 'TYPICAL');
Der optionale Parameter flush_level bestimmt, welche Daten in den Snapshot mit einbezogen werden. Zurzeit sind zwei Werte erlaubt. TYPICAL ist der Default und unterscheidet sich vom alternativen Wert ALL nur dadurch, dass für Latch-Statistiken keine Daten über Child- und Parent-Latches extrahiert werden (dies entspricht dem Snapshot-Level 10 bei Statspack). Dies sollte nur dann genutzt werden, wenn bekannt ist, dass Latching-Probleme für die Performance der Datenbank entscheidend sind. In der View DBA_HIST_SNAPSHOT, die alle Snapshots im AWR anzeigt, steht in der Spalte snap_level der Wert 1 für einen TYPICAL-, 2 für einen ALL-Snapshot. Außerdem werden in regelmäßigen Abständen automatisch AWR-Snapshots erstellt (immer als TYPICAL-Snapshots), diese Erstellung geschieht aber anscheinend nicht im Rahmen eines Oracle-Serverprozesses oder eines Hintergrundprozesses. Voraussetzung hierfür ist, dass der Serverparameter statistics_level auf TYPICAL (Default) oder ALL steht. Die Intervalle, in denen diese automatischen Snapshots generiert werden, sowie die maximale Aufbewahrungszeit für AWR-Snapshots lassen sich ebenfalls konfigurieren: SQL> execute dbms_workload_repository.modify_snapshot_settings( 7*24*60,30);
Der erste Parameter gibt die maximale Aufbewahrungszeit in Minuten an (in diesem Fall also eine Woche). Im Gegensatz zu Statspack braucht also kein eigener Job zum automatischen Löschen älterer Snapshots eingerichtet zu werden. Der zweite Parameter stellt die Zeit zwischen zwei automatischen AWR-Snapshots in Minuten dar (in diesem Fall also eine halbe Stunde). Für beide Parameter kann NULL übergeben werden, wodurch der bisherige Wert beibehalten wird. Die aktuelle Konfiguration kann mittels SQL> SELECT snap_interval, retention FROM dba_hist_wr_control; SNAP_INTERVAL RETENTION ------------------------- ------------------------+00000 00:30:00.0 +00007 00:00:00.0
abgefragt werden. Ein explizites Deaktivieren der AWR-Automatik ist möglich, indem als SnapshotIntervall 0 gesetzt wird. Leider ist dann aber auch keine manuelle Snapshot-Erstellung mehr möglich. Stattdessen kann aber z.B. der Maximalwert (100 Jahre) benutzt werden, was praktisch einer Deaktivierung der AWR-Automatik gleichkommt, manuelle Snapshots aber weiterhin zulässt. Ein völliges Deaktivieren des AWR (sowohl automatisch als auch manuell) ist möglich, indem der undokumentierte Serverparameter _awr_restrict_mode auf TRUE gesetzt wird. Jeder Versuch, das AWR zu benutzen, wird anschließend mit einer Fehlermeldung quittiert. Der Parameter ist statisch, eine erneute Freigabe des AWR ist in diesem Fall also nur nach einem Neustart der Instanz möglich.
Hilfsmittel
589
Der momentane Speicherverbrauch für das AWR (in KBytes) kann durch folgende Abfrage kontrolliert werden: SQL> SELECT space_usage_kbytes FROM v$sysaux_occupants
Der zu erwartende Speicherbedarf im SYSAUX-Tablespace hängt natürlich von der Aufbewahrungszeit und dem Snapshot-Intervall und damit von der Anzahl aufzubewahrender Snapshots ab. Je nach Datenbank muss mit einem bis einigen MB Speicherbedarf pro aufzubewahrendem Snapshot gerechnet werden. Wie auch beim Statspack können ein oder mehrere Snapshots vor dem Löschen geschützt werden, indem sie als Baseline definiert werden. Dazu müssen zunächst die Snap-IDs der zu sichernden Snapshots ermittelt werden. Zum Beispiel können typische Performance-Daten für den Lauf eines täglichen Batch-Jobs gesichert werden. Dazu wird als Stichprobe der Batch-Lauf vom 02.10.2004 (02:00 Uhr bis 04:30 Uhr) herangezogen. SQL> SELECT MIN(snap_id), MAX(snap_id) FROM dba_hist_snapshotSQL> execute dbms_workload_repository.create_baseline( 92,96,'Täglicher Batch-Lauf');
Die beiden ersten Parameter geben ein Intervall von Snapshot-IDs an. Alle betreffenden Snapshots werden unter dem Namen »Täglicher Batch-Lauf« gesichert. Über die Prozedur DROP_BASELINE kann der Baseline-Status (Löschschutz) für die betreffenden Snapshots wieder aufgehoben werden. Genau wie bei Statspack können vorhandene Snapshots ü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. Der Auswertungszeitraum darf keinen Neustart der Instanz beinhalten. Es kann auch gewählt werden, ob der Report als Text- oder HTML-Datei generiert werden soll. SQL> @?/rdbms/admin/awrrpt
Anders als bei Statspack liegt der eigentliche Report nicht als SQL*Plus-Skript vor, vielmehr ruft das oben angegebene Skript eine Tabellenfunktion auf, die den Report Zeile für Zeile zurückgibt. Die gesamte Report-Logik ist in dieser Funktion gekapselt und insbesondere nicht editierbar. Eine Übersicht über die einzelnen SQL-Abfragen des Reports kann allerdings durch ein SQL-Tracing gewonnen werden. Die direkte Erstellung eines AWR-Reports ist einfach durch einen direkten Aufruf besagter Tabellenfunktion möglich: SQL> SELECT output FROM TABLE(dbms_workload_repository.awr_report_text( 2744428495,1,92,96));
Die ersten beiden Parameter sind die DB-ID und Instanznummer. Falls diese sich seit der Erstellung der Snapshots nicht geändert haben (das dürfte meistens der Fall sein), können sie einfach aus V$DATABASE und V$INSTANCE entnommen werden. Ansonsten (z.B. nach einem Öffnen der Datenbank mit RESETLOGS-Klausel) finden sich historische Werte in DBA_HIST_DATABASE_INSTANCE.
590
Tuning
Für einen HTML-Report wird analog die Tabellenfunktion AWR_REPORT_HTML benutzt. Innerhalb des OEM 10g Database Control ist die AWR-Verwaltung im Abschnitt ADMINISTRATION und dort unter dem Link AUTOMATISCHES WORKLOAD REPOSITORY zu finden. Dort kann u.a. die so genannte »Erfassungsebene« geändert werden. Dies entspricht dem Serverparameter statistics_level. Baselines (Sequenzen löschgeschützter Snapshots) finden sich hier unter dem Link BEIBEHALTENE SNAPSHOT-SETS. Für eine Baseline oder für eine sonstige Snapshot-Sequenz kann aus einer Dropdown-Liste eine der oben beschriebenen Aktionen ausgewählt werden (Löschen der Snapshots, Erstellen eines AWR-Reports oder eines ADDM-Reports sowie Deklaration als Baseline), vorhandene Löschschutze via Baselines können natürlich aufgehoben werden. Migration Statspack AWR Es gibt keinen direkten Migrationspfad von Statspack nach AWR. Hier ist lediglich ein Umstieg vom einen auf das andere Tool möglich. Bei einem beabsichtigten Umstieg von Statspack auf AWR sollten für einen Übergangszeitraum (z.B. 1 Monat) beide Tools parallel gefahren werden. Auf diese Weise können im Zweifelsfall Daten aus beiden Repositories miteinander verglichen werden. Interpretationsprobleme die gesammelten Daten betreffend lassen sich so einfacher lösen. Eine Migration bestehender Statspack-Repositories auf Statspack 10g ist mit den mitgelieferten Skripten spup.sql möglich, z.B. Migration von Oracle9iR2: SQL> @?/rdbms/admin/spup92
Auf längere Sicht ist der alleinige Einsatz von AWR zu empfehlen, da das Erstellen eines AWR-Snapshots deutlich ressourcensparender ist als die Erstellung eines entsprechenden Statspack-Reports. Außerdem benutzt auch der Oracle Enterprise Manager 10g ausschließlich die Daten aus dem AWR, nicht die Statspack-Daten. Das neue Diagnose-Tool ADDM (siehe unten) baut ebenfalls auf dem AWR auf. Merkwürdig ist, dass Statspack, nicht jedoch AWR, auch Performance-Statistiken über Oracle Streams verarbeitet, so z.B. gestartete Capture-, Sender-, Receiver- und Apply-Prozesse, Subscriber, Streams-Regeln sowie Queue-Aktivitäten. Wird Oracle Streams eingesetzt und sind diese Informationen gewünscht, führt zurzeit (Stand: Version 10.1.0) kein Weg an der Benutzung von Statspack vorbei. Der zusätzliche Overhead durch Statspack kann hierbei jedoch gering gehalten werden, da diese Daten bereits durch einen Level 0-Snapshot extrahiert werden. Um Lastspitzen durch das Monitoring zu vermeiden, sollte bei einem – vorübergehenden oder dauerhaften – parallelen Einsatz von Statspack und AWR darauf geachtet werden, dass die Snapshot-Zeitpunkte nicht zusammenfallen, sondern versetzt laufen, also beispielsweise bei stündlichen Reports der AWR-Snapshot zur vollen Stunde und der Statspack-Snapshot jeweils eine halbe Stunde später läuft.
Hilfsmittel
591
ADDM (Automatic Database Diagnostic Monitor) Mit der Version Oracle 10g ist ein weiteres Diagnose-Tool hinzugekommen. ADDM baut auf den mittels AWR gesammelten Daten auf. Nach Angabe zweier SnapshotIDs wird ein Performance-Report über das zugehörige Intervall generiert. Im Gegensatz zu den oben beschriebenen AWR-Reports werden hier ausschließlich Informationen darüber ausgegeben, wie viel Datenbankzeit (elapsed Time) im Rahmen verschiedener Tuning-Ansätze eingespart werden könnte. Dazu gehören z.B.: Wie viel Einsparung (in Zeit) bringt eine Vergrößerung des Buffer-Cache, Shared-Pool oder der PGA? Gibt es bestimmte SQL- oder PL/SQL-Statements, die einen signifikanten Teil der Datenbankzeit verbrauchen, und, wenn ja, welche sind das? Wie viel Zeit wurde durch welches Wait-Event verbraucht? Wie ist die Performance des I/O-Systems gegenüber einer (durch den DBA vorzugebenden) »Norm«-Performance? Für die manuelle Erstellung eines Reports wird ein SQL-Skript 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. Der Auswertungszeitraum darf keinen Neustart der Instanz beinhalten. In der Standardeinstellung wird jedoch bereits automatisch für jeden abgeschlossenen AWR-Snapshot (manuell oder automatisch) eine ADDM-Analyse für den Zeitraum seit dem vorigen AWRSnapshot durchgeführt. Da auch die AWR-Snapshots automatisch erzeugt werden, läuft der ganze Mechanismus, ohne dass irgendetwas konfiguriert wurde. Über das AWR-Snapshot-Intervall wird indirekt auch die Häufigkeit der ADDM-Analysen gesteuert. Bei jedem ADDM-Aufruf werden die Ergebnisse zunächst datenbankseitig persistent gespeichert. Die gesammelten Daten können über Data-Dictionary-Views (DBA_ADVISOR_*) abgefragt werden, die zugehörigen Data-Dictionary-Tabellen haben Namen der Form WRI$_*. Außerdem wird aus Performance-Gründen für die ADDMReports überwiegend direkt auf die WRH$_*- und WRM$_*-Tabellen des AWR zugegriffen. Sollten die automatischen ADDM-Analysen ein Performance-Problem darstellen oder sonstige Probleme verursachen, gibt es einen – allerdings nicht dokumentierten – Serverparameter, um den Automatismus zu deaktivieren. Dieser kann im laufenden Betrieb gesetzt werden: SQL> ALTER SYSTEM SET "_addm_auto_enable" = FALSE;
ADDM versucht auch, die Performance des I/O-Systems innerhalb des zugrunde liegenden Intervalls zu beurteilen. Dazu ist zuvor eine Eichung notwendig, indem eine »Sollzeit« für das Lesen eines einzelnen Oracle-Blocks definiert wird. Die einfachste, aber nicht immer einsetzbare Variante besteht darin, einen bestimmten Wert als Default für alle zukünftigen ADDM-Reports festzulegen, z.B. 9000 Mikrosekunden: SQL> execute dbms_advisor.set_default_task_parameter( 'ADDM','DBIO_EXPECTED',9000);
592
Tuning
Ein realistischer Durchschnittswert lässt sich aus den Systemstatistiken ablesen, wenn diese gesetzt sind (siehe Abschnitt Erstellung und Pflege von Statistiken): SQL> SELECT pval1*1000 FROM sys.aux_stats$ WHERE pname = 'SREADTIM';
-- Milli Mikro
Der so ermittelte Wert bezieht sich wohlgemerkt auf das Lastprofil, für das die Systemstatistiken erstellt wurden, und ist nicht ohne weiteres auf ein anderes Lastprofil übertragbar. Der Grund dafür ist, dass in den Durchschnittswert natürlich auch Latenzzeiten für die Positionierung des Schreib-/Lesekopfes eingehen, die bei wahlfreiem ganz anders aussehen können als beim Full-Table-Scan einer Tabelle. Diese Problematik kann jedoch umgangen werden, indem einmalig eine Systemstatistik für das Lastprofil eines betreffenden Jobs erstellt und der oben genannte Wert eingesetzt wird. Weiter unten wird gezeigt, wie der gesetzte Default-Wert für eine konkrete ADDM-Analyse überschrieben werden kann. In jedem Fall handelt es sich aber um einen Durchschnittswert über alle Datendateien. In der Praxis ist es jedoch nicht immer sinnvoll, von einem einzigen durchschnittlichen Wert auszugehen, insbesondere wenn ein bezüglich der Performance inhomogenes I/O-System verwendet wird, also unterschiedlich schnelle Platten oder Plattensysteme vorliegen. Eine genauere Aufschlüsselung in Form durchschnittlicher Lesezeiten pro Datendatei kann z.B. durch folgende Abfrage ermittelt werden: SQL> SELECT f.name ,s.singleblkrdtim/s.singleblkrds*10000 FROM v$datafile f ,v$filestat s WHERE f.file# = s.file#;
-- Zenti Mikro
Eine möglicherweise vorhandene Streuung der Performance-Werte über Datendateien hinweg kann im Rahmen von ADDM leider nicht berücksichtigt werden. ADDM-Berichte können wie folgt generiert werden: SQL> @?/rdbms/admin/addmrpt
Der aufrufende Benutzer benötigt hierzu EXECUTE-Recht auf dem Package DBMS_ADVISOR sowie das ADVISOR-Systemprivileg. Diese Rechte können bei Bedarf wie folgt zugewiesen werden: SQL> GRANT EXECUTE ON dbms_advisor TO perfstat; SQL> GRANT ADVISOR TO perfstat;
Falls während des betrachteten Intervalls sehr wenig Aktivität stattfand, d.h., der Gesamtverbrauch an Datenbankzeit zu gering ist, wird der Report mit einer Fehlermeldung abgebrochen: THERE WAS NOT ENOUGH INSTANCE SERVICE TIME FOR ADDM ANALYSIS.
Die gesamte Logik sowie die eigentliche Skripterstellung sind in dem Package DBMS_ADVISOR gekapselt. Durch den direkten Aufruf entsprechender Prozeduren kann ein ADDM-Report parametriert werden, insbesondere lässt sich eine »SollPerformance« für das I/O-System mitgeben (Parameter DBIO_EXPECTED):
Hilfsmittel
593
SQL> DECLARE id NUMBER; name VARCHAR2(20) := 'ADDM-Report Batch'; descr VARCHAR2(100) := 'ADDM-Report täglicher Batch-Lauf'; BEGIN dbms_advisor.create_task('ADDM',id,name,descr); dbms_advisor.set_task_parameter(name,'START_SNAPSHOT',2); dbms_advisor.set_task_parameter(name,'END_SNAPSHOT',3); dbms_advisor.set_task_parameter(name,'INSTANCE',1); dbms_advisor.set_task_parameter(name,'DB_ID',2749483799); dbms_advisor.set_task_parameter( name,'DBIO_EXPECTED',12000); dbms_advisor.execute_task(name); END; / SQL> SELECT dbms_advisor.get_task_report( 'ADDM-Report Batch', 'TEXT', 'TYPICAL') FROM dual;
11.2.3 Anwendungs-Tracing 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 unterschiedlichen Ebenen eingeschaltet werden: Für eine einzelne laufende Oracle-Session (Session-Tracing) Für einen oder mehrere Oracle-Clients. Dies ist immer dann erforderlich, wenn keine eindeutige Zuordnung zwischen Clients und Sessions möglich ist, z.B. wenn Clients lediglich indirekt (über einen Middle-Tier) auf die Datenbank zugreifen. Auch im Rahmen von Parallel-Query bzw. Parallel-DML ist dieses Vorgehen anzuraten, da hier mehrere PX-Slave-Prozesse für einen Client-Task arbeiten, die jeweils eigene Trace-Files erstellen (Client-Tracing). Für die gesamte Datenbank, d.h. für alle laufenden und neuen Sessions (Datenbank-Tracing) Außerdem gibt es verschiedene Ausbaustufen, die sich durch Art und Umfang der gesammelten Informationen unterscheiden: Beim Basis-Tracing werden Ausführungsstatistiken von SQL- und PL/SQL-Statements gesammelt. Beim erweiterten Tracing werden zusätzlich zu den Ausführungsstatistiken auch Informationen über Wait Events und/oder Bindevariablen gesammelt. Wait Events sind für die Erstellung eines genauen Lastprofils unerlässlich.
594
Tuning
Session-Tracing Für jede Oracle-Session kann das Basis-Tracing der SQL-Befehle über ein alter session-Kommando 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 daher vornehmlich vom Entwickler oder Datenbankadministrator genutzt werden, der SQL-Befehle, die er näher untersuchen möchte, in einem Script separiert hat. Für Anwendungen bietet sich auf der anderen Seite die Möglichkeit an, das SQLTracing »von außen« für eine Oracle-Session an- und auszuschalten. Dafür steht das Package DBMS_MONITOR mit der Prozedur SESSION_TRACE_ENABLE zur Verfügung. Für die Parametrierung der Prozedur müssen sid und serial# der Session bekannt sein. Sollte eine Session ü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
Für die beschriebene Session des Benutzers DEMO wird ein erweitertes SQL-Tracing mit Wait-Event- und Bindevariablen-Informationen wie folgt aktiviert: SQL> execute dbms_monitor.session_trace_enable(8,30,TRUE,TRUE);
Die beiden booleschen Parameter geben an, ob Wait-Informationen (1. Parameter) bzw. Bind-Informationen (2. Parameter) gesammelt werden sollen. Beide Parameter sind optional, als Default wird dann ein erweitertes Tracing mit Wait-Event-Informationen durchgeführt. Das Basis-Tracing für die bezeichnete Session wird also wie folgt aktiviert: SQL> execute dbms_monitor.session_trace_enable(8,30,FALSE);
Nach einer gewünschten Beobachtungszeit wird deaktiviert über: SQL> execute dbms_monitor.session_trace_disable(8,30);
Sollte die Session vorher beendet werden, ist das Tracing automatisch beendet. Es ist jedoch darauf zu achten, dass entsprechende Trace-Dateien vom Server auch
Hilfsmittel
595
geschlossen werden. Der nachträgliche Aufruf von session_trace_disable stellt dies sicher. Das Protokoll des Tracings wird in das Verzeichnis geschrieben, das über den Serverparameter user_dump_dest eingestellt ist. Die Namen der erzeugten Trace-Dateien variieren je nach Betriebssystem. Bestandteil des Namens ist die BetriebssystemProzessnummer 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. Über den Serverparameter tracefile_identifier lassen sich darüber hinaus markante Zeichenketten definieren, die als Infix Eingang in den Namen der generierten TraceDateien finden. Zu ergänzen ist noch: Erzeugung Trace-Statistiken, Cursor-Closing: Ausführungspläne werden erst dann schrieben, wenn der Cursor geschlossen wird – daher Tracing nicht explizit schließen, sondern nur Session beenden. Client- und anwendungsbasiertes Tracing Client- und anwendungsbasiertes Tracing nutzt die Möglichkeit, Oracle-Sessions seitens des Clients bzw. der Anwendung zu markieren, um diese datenbankseitig problemlos und automatisch identifizieren zu können. Dies geschieht mittels Prozeduren des Pakkages DBMS_APPLICATION_INFO (SET_MODULE und SET_ACTION) sowie DBMS_SESSION (Prozeduren SET_IDENTIFIER und CLEAR_IDENTIFIER). Über diese Prozeduren kann vom Client eine Identifikation an die Datenbank durchgereicht werden, die anschließend z.B. in V$SESSION (Spalten MODULE, ACTION und CLIENT_IDENTIFIER) sichtbar ist. Alle drei Werte können im Laufe einer Session beliebig oft verändert werden, die beabsichtigte Verwendung ist jedoch wie folgt: Achtung: Die Prozedur DBMS_APPLICATION_INFO.SET_CLIENT_INFO setzt eine ClientInformation, die über die Spalte CLIENT_INFO in V$SESSION abgefragt werden kann. Hierfür funktioniert das Client-Tracing jedoch nicht! Es besteht hier leider starke Verwechslungsgefahr. Über SET_IDENTIFIER werden Informationen über den Client mitgegeben, z.B. der Name der Anwendung oder – bei Connection-Pooling – der Name des authentifizierten Benutzers. Dies sollte möglichst unmittelbar nach der Anmeldung an die Datenbank geschehen, um im Rahmen eines Client-Tracings wirklich alle vom Client abgesetzten SQL-Statements zu erfassen. Mittels SET_MODULE und SET_ACTION kann der Eintritt in einen bestimmten Code-Abschnitt der Client-Anwendung mitgeteilt werden, z.B. ein bestimmtes Formular, ein Report oder ein Batch-Lauf. Entsprechende Bezeichner für Clients sowie Module oder einzelne Aktionen des Clients sollten auf Seiten der Anwendungsentwicklung definiert und dokumentiert werden. Erfahrungsgemäß ist diese Funktionalität in vielen Anwendungen leider noch nicht verwendet. Soll in diesem Fall dennoch Client-Tracing verwendet werden, ist dies nur über eine entsprechende Anpassung der Anwendung möglich. Dazu müssen im allgemeinen an den Einstiegs- und Ausstiegspunkten der Anwendungsmodule entsprechende Aufrufe des Packages DBMS_APPLICATION_INFO bzw. DBMS_SESSION einprogrammiert werden.
596
Tuning
Abbildung 11.1: Client- und anwendungsbasiertes SQL-Tracing
Verfügt eine Anwendung über diese Funktionalität, kann durch den DBA veranlasst werden, dass für alle Oracle-Sessions ein selektives Tracing durchgeführt wird in dem Sinne, dass jede Session nur in solchen Zeiträumen getracet wird, in denen entsprechende Client-Markierungen gesetzt sind. Bei entsprechender Verwendung dieser Markierungen wie oben beschrieben, führt dies im Resultat dazu, dass datenbankweit genau diejenigen SQL-Statements getracet werden, die zu den gewählten Anwendungsmodulen bzw. Code-Abschnitten gehören. Beispielsweise könnte ein in PL/SQL geschriebenes Reporting-Tool im Rahmen einer Report-Generierung folgenden Marker setzen: BEGIN dbms_application_info.set_module( module_name => 'Verkaufsbericht (heute)' ,action_name => 'Initialisierung' ); /* Erstellung des Reports … */
dbms_application_info.set_module( module_name => NULL ,action_name => NULL ); END;
Hilfsmittel
597
Der DBA kann vor der Erstellung des Reports wie folgt ein Client-Tracing für diesen und andere Reports vereinbaren, z.B.: SQL> execute dbms_monitor.serv_mod_act_trace_enable('SUN10G', 'Verkaufsbericht (Woche)'); SQL> execute dbms_monitor.serv_mod_act_trace_enable('SUN10G', 'Verkaufsbericht (heute)','Initialisierung');
Der erste Parameter ist ein Service-Name, unter dem die Datenbank erreichbar ist. Dies ist der einzige Parameter, der unbedingt erforderlich ist. Es werden nur solche Sessions getracet, die unter dem angegebenen Service-Namen auf die Datenbank zugreifen. Sessions, die nicht über einen Service-Namen, sondern lokal über eine SID angemeldet sind, werden mit dem speziellen Service-Namen SYS$USERS ausgestattet. Für Oracle-Hintergrundprozesse wird der spezielle Service-Name SYS$BACKGROUND benutzt. Damit kann also auch ein Tracing für Hintergrundprozesse (SMON, PMON etc.) durchgeführt werden, wenn Performance-Probleme an dieser Stelle vermutet werden. Im Zweifelsfall kann der Service-Name einer Session aus der Spalte SERVICE_NAME in V$SESSION abgelesen werden. Die ersten drei Parameter dieser Prozedur (service_name, module_name, action_name) bilden ein hierarchisches Schema zur Definition von Tracing-Regeln ab: Wird lediglich ein Service-Name übergeben, entspricht dies einem datenbankweiten Tracing mit der Einschränkung, dass nur solche Sessions getracet werden, die über den entsprechenden Service-Namen an die Datenbank angemeldet sind. Bedient eine Datenbank mehrere Anwendungen, sollte daher jeder Anwendung ein separater Service-Name zugeordnet sein, um auf diese Weise ein Tracing auf Anwendungsebene zu ermöglichen (siehe Abbildung). Wird außerdem ein Modulname angegeben, werden diese Sessions nur getracet, solange der entsprechende Modulname gesetzt ist. Damit kann eine bestimmte Komponente innerhalb einer Anwendung getracet werden. Wird außerdem ein Aktionsname angegeben, werden diese Sessions nur getracet, solange der entsprechende Modul- und Aktionsname gesetzt ist. Ein Tracing eines bestimmten Code-Abschnitts innerhalb einer Anwendung ist auf diese Weise möglich. Sowohl für den Modul- als auch für den Aktionsnamen kann NULL übergeben werden, dann wird jede Session nur getracet, solange kein Modul bzw. keine Aktion gesetzt ist. Vorsichtshalber sollte dies immer durchgeführt werden, wenn nicht sicher ist, dass die Anwendung diese beiden Marker setzt. Für jede Tracing-Regel kann außerdem angegeben werden, ob ein Basis-Tracing oder ein erweitertes Tracing durchgeführt werden soll (boolesche Parameter waits und binds). In RAC-Umgebungen (siehe Kapitel 13) kann auch eine Beschränkung auf eine Instanz erfolgen (Parameter instance_name), wenn bekannt ist, dass nur bei dieser Instanz Probleme auftreten. Service-Name, Modul und Aktion bilden, wenn sie wie oben beschrieben verwendet werden, eine hierarchisches Schema, das die Struktur der Anwendung auf Seiten der Datenbank bekannt macht. Davon unabhängig stellt die Client-Markierung Informationen über den Client auf Seiten der Datenbank bereit. Ein ClientTracing auf Basis der Client-Markierung wird daher wie folgt durchgeführt:
598
Tuning
Das oben erwähnte Reporting-Tool setzt nach der Anmeldung an die Datenbank eine Client-Markierung. Dabei wird die Login-Information des Clients sozusagen durchgereicht: BEGIN dbms_session.set_identifier( client_id => 'Ahrends' ); END;
Um nun alle von diesem Benutzer ausgelösten SQL-Statements zu tracen, ist folgender Aufruf notwendig: SQL> execute dbms_monitor.client_id_trace_enable('Ahrends');
Jeder Aufruf von DBMS_MONITOR.SERV_MOD_ACT_TRACE_ENABLE bzw. DBMS_MONITOR.CLIENT_ ID_TRACE_ENABLE definiert eine Tracing-Regel wie oben beschrieben. Es können beliebig viele Tracing-Regeln vereinbart werden. Diese wirken kumulativ, d.h. für jede Session wird getracet, solange mindestens eine Tracing-Regel erfüllt ist. Aktivierte Client-Tracings können über dba_enabled_traces abgefragt werden, aktivierte Session-Tracings aber leider nicht. Ob das Tracing auf Datenbankebene aktiviert ist, kann durch Inspektion des Parameterwerts für SQL_TRACE in V$PARAMETER ermittelt werden. SQL> SQL> SQL> SQL>
column primary_id format a10 column qualifier_id1 format a25 column qualifier_id2 format a15 SELECT trace_type,primary_id,qualifier_id1 ,qualifier_id2,waits,binds FROM dba_enabled_traces; TRACE_TYPE PRIMARY_ID QUALIFIER_ID1 QUALIFIER_ID2 WAITS BINDS --------------------- ---------- ------------------------- --------------- ----- ----SERVICE_MODULE_ACTION SUN10G Verkaufsbericht (heute) Initialisierung TRUE FALSE SERVICE_MODULE SUN10G Verkaufsbericht (Woche) TRUE FALSE CLIENT_ID Ahrends TRUE FALSE
Nach beendetem Tracing kann das Client-Tracing wieder deaktiviert werden, z.B.: SQL> execute dbms_monitor.serv_mod_act_trace_disable('SUN10G', 'Verkaufsbericht (Woche)'); SQL> execute dbms_monitor.serv_mod_act_trace_disable('SUN10G', 'Verkaufsbericht (heute)','Initialisierung'); SQL> execute dbms_monitor.client_id_trace_disable('Ahrends');
Achtung: Regeln für Client-Tracing werden in Datenbanktabellen abgespeichert und bleiben daher über den Neustart der Instanz hinweg erhalten. Eine explizite Deaktivierung solcher Tracing-Regeln wie oben gezeigt ist daher erforderlich!
Hilfsmittel
599
Datenbank-Tracing Für eine komplette Oracle-Instanz kann das Tracing aller SQL-Befehle über ein ALTER SYSTEM-Kommando eingeschaltet werden. SQL> ALTER SYSTEM SET sql_trace = TRUE;
Ist der Serverparameter gesetzt, wird jeder Prozess protokolliert. Dadurch kann es zu nicht unerheblichen Belastungen des Systems kommen, sowohl in Bezug auf die CPU als auch auf den I/O, besonders auf der Platte, auf die der Serverparameter user_dump_dest verweist. Zudem wird unter Umständen enorm viel Platz auf dieser Platte benötigt. Die Größe einer Trace-Datei lässt sich über den Serverparameter 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. Konsolidierung von Trace-Dateien Da für jede Oracle-Session eine Trace-Datei geschrieben wird, werden insbesondere beim Client-Tracing i.A. mehrere Trace-Dateien generiert. Um diese mit ReportingTools wie TKProf (siehe unten) aufzubereiten, ist es zunächst erforderlich, sie zu einem einzigen Gesamt-Trace zu konsolidieren. Ein weiteres Problem erwächst aus dem Sachverhalt, dass die Namen von TraceFiles eindeutig gemacht werden, indem die Prozess-ID des Serverprozesses Teil des Dateinamens ist. Dies ist problematisch, wenn Connection-Pooling benutzt wird und die Serverprozesse somit sehr langlebig sind. Es ist dann durchaus wahrscheinlich, dass ein bestimmter Serverprozess schon einmal getracet wurde und in der zugehörigen Trace-Datei auch bereits alte Trace-Informationen liegen. Aber auch bei kurzlebigen Connections kann dieses Problem auftreten, nämlich wenn eine Prozess-ID zum wiederholten Male verwendet wird. Dann werden neue TraceInformationen einfach an die bestehende Trace-Datei angehängt. In beiden Fällen ist es also erforderlich, alte von neuen Trace-Einträgen zu trennen. Das Werkzeug TRCSESS löst einige der beschriebenen Probleme. Es konsolidiert mehrere Trace-Dateien. Gleichzeitig können unerwünschte Einträge auf Basis verschiedener Kriterien ausgefiltert werden. Das Aufruf-Skript befindet sich in $ORACLE_HOME/bin, das Werkzeug ist in JAVA geschrieben. Ein Aufruf ohne Parameter gibt eine Syntax-Hilfe aus. Aufruf: $ trcsess output=trace_cons.trc module="Verkaufsbericht (heute)" action="Initialisierung" ps10_ora_1452.trc ps10_ora_1556.trc ps10_ora_1640.trc
600
Tuning
output
Ausgabedatei für die Konsolidierung
module
Nur Einträge mit dem angegebenen Modul-Wert werden für die Konsolidierung berücksichtigt.
action
Nur Einträge mit dem angegebenen Action-Wert werden für die Konsolidierung berücksichtigt.
*.trc
Namen der Trace-Dateien, die konsolidiert werden sollen
Analog zu den Parametern module und action sind auch folgende Parameter möglich: service
Eingrenzung nach Service-Namen des Clients
clientid
Eingrenzung nach Client-ID
session
Eingrenzung nach Oracle-Session in der Form <SID>.<Serial#> Beispiel: session=146.78
Mindestens einer der Filter-Parameter muss angegeben werden. Leider gibt es keine Möglichkeit, nach dem Datum des Trace-Eintrags zu filtern. Das Abtrennen alter Einträge muss daher ggf. zuvor manuell erfolgen. Achtung: Die für das Filtern notwendigen Trace-Einträge (Module-, Action-Wert etc.) werden nicht in die Ausgabedatei übernommen. Daher kann die Ausgabedatei (trace_cons.trc im obigen Beispiel) nicht für einen weiteren Konsolidierungsschritt benutzt werden. Eine Konsolidierung in mehreren Stufen ist also nicht möglich. 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 der Trace-Datei durch eine explizite Datenbankverbindung ermittelt werden sollen – statt sie direkt aus der Trace-Datei zu übernehmen. 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 wird nicht aus der Trace-Datei gelesen,
Hilfsmittel
601
sondern wird zum Zeitpunkt des TKPROF-Aufrufs ermittelt. Vorsicht: Nach dem Tracing angelegte oder gelöschte Indizes können daher den Ausführungsplan verfälschen. Eine Methode, um garantiert an die korrekten Ausführungspläne zu kommen, wird weiter unten beschrieben. Wird explain nicht angegeben, generiert TKPROF die Pläne direkt aus den Angaben der Trace-Datei. 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)
(prsela,fchela)
Summe der Gesamtzeiten für Parsing und Auslesen
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 der Ausführungsplan dargestellt. Im dem unten aufgeführten Beispiel sollen diese Ausführungspläne nicht aus der rohen Trace-Datei, sondern direkt über eine Datenbankverbindung ermittelt werden. Die Interpretation von Ausführungsplänen wird im Abschnitt Ausführungspläne 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
602 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 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 user SQL statements in session. 17 internal SQL statements in session. 25 SQL statements in session. 5 statements EXPLAINed in this session. *************************************************************** Trace file: ora00031.trc Trace file compatibility: 9.00.01 Sort options: default 3 sessions in tracefile. 11 user SQL statements in trace file. 32 internal SQL statements in trace file.
Tuning
Hilfsmittel
603
25 20 5
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 sessions in tracefile. 11 user SQL statements in trace file. 32 internal SQL statements in trace file. 25 SQL statements in trace file. 20 unique SQL statements in trace file. 5 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 11.1: Durch TKPROF formatierte Trace-Datei
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 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 Undo-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. Falsche Ausführungspläne durch Änderungen am Schema Die Ausführungspläne der SQL-Befehle werden in der Regel1 mit in die Trace-Datei geschrieben, bei Nutzung der explain-Klausel jedoch neu aus der Datenbank generiert. In solchen Fällen ist es möglich, dass in der Zwischenzeit angelegte oder gelöschte Indizes einen vom Original abweichenden Ausführungsplan ausgeben. 1
Bei abnormaler Beendigung der Session kann es vorkommen, dass diese Pläne nicht in der rohen Trace-Datei erscheinen.
604
Tuning
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 CPUZeit 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. Darüber hinaus gehen die Ausführungszeiten rekursiver Calls mit in die Elapsed-Zeiten ihrer auslösenden Befehle ein. Höherer Ressourcenverbrauch durch Trigger In den Statistiken wird der komplette Ressourcenverbrauch 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. Trace Analyzer (TRCA) Ein Nachteil von TKProf ist, dass insbesondere bei SQL-Befehlen mit Bindevariablen TKProf lediglich Summenwerte über alle Ausführungen des Kommandos liefert, die Performance jedoch in einigen Fällen von den konkreten Werten für Bindevariablen abhängt (z.B. bei schlecht ausbalancierten Indizes). Außerdem können Wartezustände einen Großteil der Gesamtzeit (elapsed Time) ausmachen bzw. die Ergebnisse verfälschen. Prinzipiell können Werte von Binde-Variablen sowie aufgetretene Wartezustände mittels erweitertem Tracing in die Trace-Datei mit einbezogen werden. Diese zusätzlichen Einträge werden jedoch von TKProf nicht vollständig interpretiert. Oracle stellt daher über die Metalink-Seite (Note 224270.1) das Werkzeug Trace Analyzer (TRCA) zur Verfügung, das alle Informationen im Rahmen des erweiterten Tracings interpretiert und ein detailliertes Last- und Ressourcenprofil der gemessenen Zeitspanne liefert. Im Gegensatz zu TKProf besteht TRCA aus einer Sammlung von SQL- und PL/SQL-Skripten und läuft vollständig in der Datenbank, wo auch ein Repository verwaltet wird. Die Skripte erlauben einen genauen Einblick in die Arbeitsweise des Tools und sind beliebig anpassbar und erweiterbar. Es wird zunächst ein Gesamtbericht generiert, der u.a. alle Informationen eines TKProf-Berichts beinhaltet. Über einen Drill-down-Mechanismus können weitere Detailberichte erzeugt werden (siehe Abbildung 11.2). Die zusätzlichen Funktionen von TRCA zusammen mit der Ad-hoc-Einsatzfähigkeit von TKProf führen dazu, dass beide Werkzeuge sich hervorragend ergänzen in dem Sinne, dass nach einer »groben Sichtung« mittels TKProf entschieden werden kann, ob eine genauere Analyse mittels TRCA angebracht ist. Beide Werkzeuge sind mithin als komplementär zu bezeichnen.
Hilfsmittel
605
Abbildung 11.2: Funktionsweise des Trace Analyzers
TRCA-Administration TRCA verwaltet ein Repository in der Datenbank, bestehend aus Tabellen und Indizes, deren Namen sämtlich mit TRCA$ beginnen, einem Package TRCA$ sowie einem Directory-Alias mit dem Namen udump. Sämtliche Skripte laufen im Schema des Aufrufenden ab (die Skripte führen kein CONNECT aus). Alle Skripte haben die Form TRCA*.sql, bspw. TRCACREA.sql: CREA, DROP: Erstellen/Löschen des Repositories. Alle Objekte werden im Default Tablespace des Aufrufenden erstellt. Der Directory-Alias udump zeigt auf das user_dump_ dest-Verzeichnis. GRNT, REVK <user>: Zuweisen/Entziehen von SELECT-Rechten auf einige DBA- und V$Views sowie des READ-Rechtes auf den Directory-Alias für den Benutzer <user>. Diese Rechte werden benötigt, um den Trace Analyzer auszuführen. TRNC: Leert alle Repository-Tabellen PURG : Löscht alle Repository-Einträge, die älter als Tage sind.
Generierung eines Gesamtberichts Ein Aufruf von TRCANLZR.sql liest zunächst zeilenweise die angegebene Trace-Datei und speichert den interpretierten Inhalt im Repository. Dabei wird eine Trace-ID zugewiesen, mittels derer im weiteren Verlauf auf den Inhalt dieser Trace-Datei Bezug genommen werden kann. Daran anschließend wird der Gesamtbericht erstellt. Beim Aufruf muss der Directory-Alias für das Verzeichnis angegeben werden, in dem die Trace-Datei liegt (standardmäßig udump) sowie der Name der TraceDatei. SQL> @TRCANLZR
udump
606
Tuning
Folgende Informationen werden in den Gesamtbericht geschrieben: Die Top 5 SQL-Cursor bezüglich CPU-Zeit, Elapsed-Zeit, Non-Idle- und IdleWartezustände (jeweils Gesamtwerte über alle Ausführungen). Der Übersicht halber werden zunächst nur die Cursor-ID (wird von TRCA analog zu tkprof vergeben), die User-ID des Ausführenden (0 für SYS) und der Oracle Command Type aufgelistet. Letzterer ist in der Trace-Datei als Eintrag oct codiert und wird über die Tabelle AUDIT_ACTIONS aufgelöst. Häufige Command Types sind SELECT, INSERT, UPDATE, DELETE, PL/SQL EXECUTE, ANALYZE TABLE. Für jeden Cursor, der nach mindestens einem Kriterium zu den Top 5 gehört, wird eine Zeile dargestellt. Aufgetretene ORA-Fehler während des Tracings. Gaps (Zeiträume ohne Aktivität) werden anhand des Vergleichs aufeinander folgender tim-Einträge im Trace-File ermittelt und ausgegeben. Abgeschlossene Transaktionen (XCTEND) im Trace-File, zusammen mit der Information, ob mit COMMIT oder ROLLBACK beendet wurde und ob DML-Aktivität stattfand oder nicht. Ausführungsstatistiken pro Benutzer, getrennt nach Recursive/Non-Recursive SQL. Dies erlaubt insbesondere eine Differenzierung zwischen »User Recursive SQL« (Inhalt von PL/SQL-Blöcken) und »System recursive SQL«. Jeweils eine Zeile für Parse-/Exec-/Fetch-Phase (analog zu TKProf) Eine Zeile pro Kommandotyp Wartezustandsstatistiken pro User, getrennt nach Recursive/Non-Recursive SQL. Idle-Waits stehen jeweils als Letztes. Außerdem werden jeweils Teilsummen-Zeilen für alle Idle-Waits bzw. Non-Idle-Waits ausgegeben. Für einige Non-Idle-Waits, z.B. db file {sequential | scattered} read werden außerdem Statistiken pro Datenbank-Objekt (z.B. Tabelle) ausgegeben. Die »Hottest 5 blocks« (die Blöcke mit der höchsten Wartezeit) und Cursor-IDs der entsprechenden Cursor. Kommandotyp, Ausführungsstatistiken (à la TKProf) sowie Non-Idle/Idle-Wartezeiten pro Cursor. Damit kann sehr schnell eine Vorauswahl relevanter SQLKommandos vorgenommen werden. Cursorliste: Dabei werden (analog zu TKProf) Gesamt-Ausführungsstatistiken und Wartezustandsstatistiken sowie der Ausführungsplan dargestellt. Außerdem werden die Substitutionswerte aller Bindevariablen pro Ausführung sowie Ausführungs- und Wartezustandsstatistiken pro Ausführung dargestellt. An dieser Stelle lassen sich sehr gut einzelne Ausreißer erkennen. In der Trace-Datei und auch in den TRCA-Reports sind leider nicht die Namen der Bindevariablen eingetragen. Stattdessen sind diese entsprechend der Reihenfolge ihres Vorkommens im SQL-Statement mit 0 beginnend aufsteigend durchnummeriert. Die Zuordnung zu entsprechenden evtl. mit sprechenden Namen versehenen Bindevariablen muss daher ggf. durch Abzählen der Positionen der Bindevariablen innerhalb des SQL-Kommandos vorgenommen werden. Falls eine Bindevariable mehrfach vorkommt, wird bei allen außer dem ersten Vorkommen als Substitutionswert NSBBE (no separate bind buffer exists) ausgegeben.
Hilfsmittel
607
Einige Obergrenzen sind in den TRCA-Skripten fest eingetragen. So werden maximal 2000 Cursor in den Gesamtbericht geschrieben. Pro Cursor werden maximal 100 Ausführungen (zehn bei Benutzer SYS) angezeigt. All diese Begrenzungen können natürlich angepasst bzw. aufgehoben werden. Ganz oben im Gesamtbericht ist auch die Trace-ID eingetragen, die für die Detailberichte verwendet werden muss. Generierung von Detailberichten Falls aufgrund der genannten Obergrenzen nicht alle Ausführungen eines Cursors im Gesamtbericht gelistet wurden, kann ein entsprechender Detailbericht erstellt werden, der sämtliche Ausführungen umfasst: SQL> @TRCACRSR
<cursor-id>
Ein entsprechendes Beispiel findet sich unterhalb der Ausführungsliste im Gesamtbericht in Form folgender Zeile, z.B.: REPORTING ONLY FIRST 100... (TO REPORT ALL: SQL> START TRCACRSR.sql 11 2; )
Hier muss lediglich die gewünschte Cursor-ID eingesetzt und per Copy and Paste ins SQLPlus-Fenster übertragen werden. Cursor-IDs werden im Gesamtbericht mit 1 beginnend aufsteigend vergeben. Durch Einsetzen von 0 als Cursor-ID werden alle Ausführungen für alle Cursor ausgegeben. Ein Bericht über den detaillierten Ablauf einer einzelnen Ausführung schließlich kann unter Angabe der Bind-Line erzeugt werden. Diese ist in den vorgenannten Berichten in der Spalte binds trc_line zu finden und entspricht der Zeilennummer im ursprünglichen Trace-File. SQL> @TRCAEXEC
<cursor-id>
Auch hier findet sich im Gesamtbericht unterhalb der Ausführungsliste eine entsprechende Beispielzeile. Durch Einsetzen von 0 als Bind-Line werden Detailinformationen über alle Ausführungen des betreffenden Cursors geliefert. Hier ein Ausschnitt aus einem solchen Bericht, der gewissermaßen eine lesbare Darstellung der entsprechenden Zeilen der Trace-Datei darstellt. Für Wartezustände, bei denen dies möglich ist, werden die Parameter p1, p2, p3 in Segmentname und Extent-Nummer aufgelöst, so dass unmittelbar erkennbar ist, worauf gewartet wurde.
608
Tuning
Abbildung 11.3: Ausschnitt aus einem Trace-Analyzer-Bericht
Tracing und Ausführungspläne Wie bereits erwähnt, ist das nachträgliche Erstellen eines Ausführungsplans (via explain-Parameter) mit Hilfe des TKProf-Werkzeugs problematisch, da der so gefundene Ausführungsplan nicht zwangsläufig dem tatsächlichen Ausführungsplan entspricht. Seit Oracle9i werden prinzipiell aber auch die Ausführungspläne jedes SQL-Kommandos in die Trace-Datei geschrieben. Die TKProf-Werkzeuge ab Oracle9i geben diese auch korrekt aus. Eigentlich besteht also gar keine Notwendigkeit mehr für das nachträgliche Generieren eines Ausführungsplans. Allerdings merkt man in der Praxis recht schnell, dass seltsamerweise nicht für alle SQL-Kommandos tatsächlich Ausführungspläne in die Trace-Datei geschrieben werden. Dies sorgt oftmals für Verwirrung, da auch scheinbar bei jedem Lauf andere Kommandos von diesem Umstand betroffen sind. Des Rätsels Lösung liegt darin, dass der Ausführungsplan eines SQL-Kommandos erst in dem Moment in die Trace-Datei geschrieben wird, in dem der zugehörige SQL-Cursor im Library-Cache geschlossen wird. Dies kann zeitlich weit hinter der eigentlichen Ausführung und sogar nach der Beendigung des Tracings liegen. In letzterem Fall tritt das beschriebene Problem auf. Da kaum vorherzusagen ist, wann der Cursor geschlossen wird, kann man sich – gerade bei häufig benutzten SQLKommandos – nicht auf diesen Mechanismus verlassen. Der einzige Weg, ein Schließen aller SQL-Cursor und damit das Schreiben aller Ausführungspläne in die Trace-Datei zu erzwingen, besteht darin, das Tracing nicht (!) sauber zu beenden, sondern einfach die Session zu beenden (via Disconnect oder SQL*Plus-Kommando quit). Bei einer Anwendung mit Connection-Pool ist das natürlich nicht immer so einfach, es stellt aber leider die einzige Lösung dar, die garantiert zum gewünschten Ergebnis führt.
Der Optimizer
11.3
609
Der 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 aufgrund der WHERE-Klausel ausgeführt werden kann, bei mehreren vorhandenen Indizes auch über welchen. Bei Join-Operationen, 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). Der »regelbasierte Optimizer« (RBO), der in den vergangenen Oracle-Versionen stets noch unterstützt, wenn auch nicht mehr empfohlen wurde, wird mit dem Release Oracle 10g nicht mehr unterstützt und wird daher an dieser Stelle auch nicht behandelt. Die Funktionalität des RBO ist noch vorhanden, jedoch leistet Oracle keinen Support für deren Benutzung. Es sollte daher ausschließlich der kostenbasierte Optimizer (CBO) benutzt werden. Mit der Oracle-Version 10g ist dieser außerdem in »Query Optimizer« umbenannt worden. Der Query Optimizer ist ein Expertensystem, das die optimalen Zugriffspfade zu Oracle-Tabellen aufgrund 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 Instanzressourcen und Parametrierungen der Instanz relevant, die im Folgenden noch erläutert werden. Die Nachteile, die beim regelbasierten Optimizer festgestellt wurden, sollen durch den Query Optimizer eliminiert werden, da dieser die Größen der Tabellen ebenso wie die Selektivität der Indizes berücksichtigen kann. Zur Ermittlung des optimalen Pfades werden zunächst alle möglichen Permutationen von möglichen Zugriffen gebildet. Zu jedem Pfad werden dann auf Grundlage der Statistiken die entsprechenden Kosten errechnet, welche 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.
11.3.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.
610
Tuning
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 Serverparameters open_cursors – beliebig viele Cursors öffnen. Weiterhin werden in der 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.). 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-Servers 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-Servers 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 Optimizer
611
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 (soft parse). 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 zugreifen?) sowie der 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. Nach diesem hard parse 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 Zeitpunkt der Lesekonsistenz 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.
612
Tuning
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. 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.
11.3.2
Erstellung und Pflege von Statistiken
Es gibt zur Zeit zwei voneinander unabhängige Varianten, um Statistikinformationen zu erzeugen. Dabei handelt es sich um den ANALYZE-Befehl sowie um das Package DBMS_STATS. Die Funktionalität beider Tools überlappt sich zum Teil, andererseits gibt es auch Funktionen, die nur jeweils eines der beiden Tools beherrscht. Zur konkreten Anwendbarkeit ist Folgendes zu sagen: Alle Statistikinformationen, die vom Query Optimizer benutzt werden, sollten ausschließlich mit dem Package DBMS_STATS erzeugt und verwaltet werden, da es hierfür erheblich erweiterte Möglichkeiten im Vergleich zum ANALYZE-Kommando bietet.
Der Optimizer
613
Lediglich die weiter unten beschriebenen Spezialfunktionen sollten mit dem ANALYZE-Kommando durchgeführt werden. Die Ergebnisse dieser Analysen werden vom Optimizer ohnehin nicht verwendet, sondern geben beispielsweise Anhaltspunkte für bestimmte Reorganisationen von Tabellen oder Indizes: Die Statistikinformationen werden 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
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. Statistikerstellung über DBMS_STATS Das Package DBMS_STATS bietet reichhaltige Möglichkeiten, Statistiken zu erzeugen und zu verwalten. Es ist sowohl aus administrativen als auch aus PerformanceGesichtspunkten dem ANALYZE-Kommando in der Erstellung relevanter Statistikinformationen überlegen. Im Folgenden soll ein Überblick über die wichtigsten Features und deren Funktionsweise gegeben werden: Erstellung der Statistiken Es ist möglich, Statistiken für einzelne Tabellen, Indizes oder Tabellenspalten (Histogramme) zu generieren bzw. zu verwalten (z.B. die Prozeduren GATHER_TABLE_STATS, GATHER_INDEX_STATS und GATHER_COLUMN_STATS). Alternativ können jedoch auch Statistiken für ein ganzes Schema oder für die gesamte Datenbank erzeugt werden (Prozeduren GATHER_SCHEMA_STATS und GATHER_DATABASE_STATS). Insbesondere das Arbeiten auf Schema-Ebene ist zu empfehlen, da so beim Anlegen neuer Tabellen keine Anpassung vorhandener Statistikskripte und/oder -jobs notwendig ist. Über entsprechende Prozeduren DELETE_*_STATS können Statistiken ersatzlos gelöscht werden. Statistikwerte schätzen Das Berechnen der genauen Statistiken kann bei großen Tabellen extrem zeitaufwändig sein und einen hohen Ressourcenverbrauch erzeugen. Daher können Statistikinformationen geschätzt werden. Dazu wird ein bestimmter Prozentsatz der Daten gelesen, und die daraus ermittelten Statistiken werden auf den gesamten Datenbestand hochgerechnet. Der Prozentsatz kann über den Parameter estimate_ percent eingestellt werden. In diesem Zusammenhang sollte auch das so genannte Block-Sampling benutzt werden (Parameter block_sample auf TRUE setzen), damit ein entsprechender Anteil aller Blöcke gelesen wird. Enthält für eine bestimmte Tabelle beispielsweise jeder Oracle-Block ca. 100 Zeilen, so würde eine Statistikschätzung
614
Tuning
mit 2% ohne Block-Sampling jede 50. Zeile lesen, also müsste wahrscheinlich jeder Block einmal geladen werden. Performance-technisch wäre gegenüber einer exakten Statistikberechnung nichts gewonnen. Bei einem Block-Sampling wird hingegen jeder 50. Block geladen, und alle Zeilen aus diesem Block werden gelesen. Parallelisierung Die Ermittlung exakter bzw. geschätzter Statistikwerte kann parallel durch mehrere Slave-Prozesse erfolgen. Hierzu kann über den Parameter degree z.B. ein konkreter Wert für den Parallelisierungsgrad übergeben werden. Weitere Varianten hierfür sind der Dokumentation zu entnehmen. Indexstatistiken und Histogramme Bei der Ermittlung von Statistiken auf Tabellen-, Schema- oder Datenbankebene kann eingestellt werden, dass neben den Tabellenstatistiken auch Statistiken für Indizes dieser Tabellen sowie Histogramme für Tabellenspalten generiert werden sollen. Dies ist stark anzuraten, da diese weitere essenzielle Informationen für den Optimizer darstellen. Indexstatistiken werden zusätzlich gesammelt, indem der Parameter cascade auf TRUE gesetzt wird. Histogramme größtmöglicher Genauigkeit werden erstellt, indem für den Parameter method_opt Folgendes übergeben wird: 'FOR ALL COLUMNS SIZE 254'. Beide Optionen sind sehr zu empfehlen. 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. Statistiken können aus dem Data Dictionary in eine so genannte Benutzer-Statistiktabelle exportiert werden. Dabei handelt es sich um eine normale Tabelle im Schema eines Benutzers, die zuvor über die Prozedur CREATE_STAT_TABLE erstellt werden muss. Anschließend kann über eine der Prozeduren EXPORT_*_STATS ein Statistikexport des Produktionsschemas durchgeführt werden. Als Ziel wird die soeben erstellte Benutzer-Statistiktabelle angegeben. Diese Statistiktabelle kann auf ein Testsystem übertragen werden, wo die Statistiken mittels einer der Prozeduren IMPORT_*_STATS in das DataDictionary übertragen werden. Über diesen Weg kann ohne physikalischen Platzbedarf eine große Datenbank für den Optimizer simuliert 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.
Der Optimizer
615
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'
Optionaler Bezeichner für diesen Export
TRUE
CASCADE=TRUE, d.h., Statistiken für Indizes und Spalten werden mit-
exportiert HLADMIN
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 Data-Pump oder exp/imp auf das Testsystem übertragen werden. Hier können optional noch Statistikinformationen verändert werden, um andere Datenmengen oder Schlüsselverteilungen zu simulieren (siehe den folgenden Abschnitt 'Manipulierte Statistiken'). 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');
Manipulierte Statistiken Über die Prozeduren SET_*_STATS können Statistikinformationen auch explizit verändert werden, um andere Datenmengen oder Schlüsselverteilungen zu simulieren. Die Manipulation kann direkt am Data Dictionary ansetzen oder zunächst nur an einer Benutzer-Statistiktabelle, die erst anschließend importiert wird. SQL> execute dbms_stats.set_table_stats ('HLADMIN','KUNDEN',NULL,'STAT_TAB', '1',10000,1000,NULL,NULL,'HLADMIN');
Hier wird für die Benutzer-Statistiktabelle HLADMIN.STAT_TAB eingestellt, dass die Tabelle KUNDEN 10.000 Sätze hat, die auf 1.000 Blöcke verteilt sind. Die restlichen Statistikwerte werden nicht modifiziert.
616
Tuning
SQL> execute dbms_stats.set_table_stats ('HLADMIN','KUNDEN',NULL,NULL, '1',10000,1000,NULL,NULL,NULL);
Hier wird dieselbe Statistikinformation direkt ins Data Dictionary geschrieben. Die Parameter für den Namen und Eigentümer der Statistiktabelle wurden dazu auf NULL gesetzt. Automatische Statistiken Oracle 10g protokolliert automatisch DML-Aktivitäten für Tabellen (Voraussetzung dafür ist, dass der Serverparameter statistics_level auf TYPICAL oder ALL gesetzt ist. In Oracle9i musste diese Protokollierung für jede Tabelle aktiviert werden, in Oracle 10g gibt es lediglich einen versteckten Instanzparameter _dml_monitoring_enabled, der per Default auf TRUE steht). Dabei werden für jede Tabelle die Anzahl eingefügter, geänderter und gelöschter Zeilen nachgehalten. Diese Informationen können aus der View dba_tab_modifications abgelesen werden. Bei der Erstellung von Statistiken auf Schema- oder Datenbank-Ebene kann durch Setzen des Parameters options auf den Wert GATHER AUTO erreicht werden, dass nur für solche Tabellen neue Statistiken generiert werden, für die: die Gesamtzahl der Einfügungen, Änderungen und Löschungen seit der letzten Analyse 10% der Zeilenzahl überschreitet, seit der letzten Analyse ein TRUNCATE durchgeführt wurde oder noch keine Statistiken existieren. 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 aufweisen, viele hingegen relativ statisch sind. Auf diese Weise lässt sich das für die Statistikgenerierung benötigte Zeitfenster ohne negative Auswirkungen auf die Aktualität der Statistiken deutlich verringern. SQL> BEGIN dbms_stats.gather_schema_stats( ownname => 'HLADMIN' ,options => 'GATHER AUTO' ,estimate_percent => 5 ,block_sample => TRUE ); END;
Systemstatistiken Neben den beschriebenen Objektstatistiken kann der Optimizer auch Informationen über die Performance des CPU- und I/O-Systems berücksichtigen. Dazu gehören u.a. die unten aufgeführten Statistiken:
Der Optimizer
617
Statistik
Parametername (PNAME) in SYS.AUX_STATS$
Benötigt Lastprofil
Durchschnittliche Latenzzeit für Positionierung des Schreib-/Lesekopfes (in Millisekunden)
IOSEEKTIM
nein
CPU-Geschwindigkeit (in MHz)
CPUSPEED
nein
Durchschnittliche Wartezeit für das Lesen eines einzelnen Blocks (in Millisekunden)
SREADTIM
ja
Durchschnittliche Wartezeit für das Lesen einer Blocksequenz »Multi-Block-Read« (in Millisekunden)
MREADTIM
ja
Durchschnittliche Anzahl gelesener Blöcke bei Multi-Block-Reads (siehe auch Abschnitt Erstellung und Pflege von Statistiken)
MBRC
ja
Einige dieser Werte können nur bezüglich eines bestimmten Lastprofils sinnvoll ermittelt und verwendet werden. 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. Um Systemstatistiken z.B. für einen bestimmten Batch-Job zu erstellen, wird vor dem Starten des Batch-Jobs die Statistiksammlung aktiviert: SQL> execute dbms_stats.gather_system_stats('START');
Nach Beendigung des Jobs wird die Statistiksammlung beendet. SQL> execute dbms_stats.gather_system_stats('STOP');
Ist der Zeitraum a priori bekannt, z.B. das Tagesgeschäft einer Anwendung, kann die Beendigung auch automatisiert werden. Dazu würde um 08:00 Uhr folgendes Kommando abgesetzt: SQL> execute dbms_stats.gather_system_stats('INTERVAL',9*60);
Der zweite Parameter gibt die Dauer der Statistiksammlung in Minuten an. Im Hintergrund wird ein Datenbank-Job erzeugt, der nach der angegebenen Zahl Minuten die Statistiksammlung beendet. Eine vorzeitige explizite Beendigung via 'STOP' ist jedoch ebenfalls problemlos möglich. Sind die Statistiken einmal gesammelt, sollten sie in eine Benutzer-Statistiktabelle exportiert werden (Prozedur EXPORT_SYSTEM_STATS). Wichtig ist hierbei, einen sprechenden Bezeichner für den Parameter statid zu verwenden (z.B. 'Tagesgeschäft'), um später die richtigen Statistiken für das jeweilige Lastprofil wiederzufinden. Anschließend wird ein Datenbank-Job definiert, der wochentags um 08:00 Uhr genau diese Statistiken unter Angabe der vergebenen statid wieder importiert (Prozedur IMPORT_SYSTEM_STATS).
618
Tuning
Analog wird für die übrigen Lastprofile verfahren. Dadurch wird automatisch zu bestimmten Zeiten gegenüber der Datenbank eine Laständerung mitgeteilt. Die aktuellen Statistiken können aus der Tabelle SYS.AUX_STATS$ abgefragt werden: SQL> SELECT pval1 FROM sys.aux_stats$
Im Gegensatz zu Objektstatistiken werden bei einem Wechsel der Systemstatistiken (z.B. durch Import) vorhandene Ausführungspläne betroffener SQL-Befehle nicht ungültig. Dies bedeutet, dass der beschriebene Lastwechsel auf bestehende Ausführungspläne zunächst keine Auswirkung hat, da keine Neubewertung der Kosten durch den Optimizer stattfindet. Dies erscheint auf den ersten Blick widersinnig (wozu werden dann überhaupt Systemstatistiken benutzt, wenn sie keinen Einfluss auf die Ausführungspläne haben?), wird jedoch in den meisten Situationen dadurch gelöst, dass ja nach einem Lastwechsel auch ganz andere SQL-Kommandos ausgeführt werden als zuvor. Für diese neuen Kommandos wird somit ohnehin ein erneutes Parsing inklusive Kostenabschätzung durchgeführt. Im Zweifelsfall kann für ein gegebenes SQL-Kommando in V$SQL unter der Spalte LAST_LOAD_TIME nachgeschaut werden, wann das letzte Parsing stattfand. Dieser Zeitpunkt sollte zeitlich nach dem Lastwechsel liegen. Ist dies für die meisten SQLKommandos nicht der Fall, bleibt als Ausweg nur das explizite Löschen aller Ausführungspläne via SQL> ALTER SYSTEM FLUSH SHARED_POOL;
Achtung: Dieser Befehl sollte erst dann ausgeführt werden, wenn auch sichergestellt ist, dass der Lastwechsel auch tatsächlich stattgefunden hat und somit die aktuellen SQL-Kommandos nicht mehr benötigt werden, da sonst kurzfristig ein erheblicher Performance-Einbruch für diese Kommandos zu erwarten ist. Mittels DELETE_SYSTEM_STATS können die vorhandene Systemstatistiken ersatzlos deaktiviert werden. Statistikhistorisierung Jede mittels DBMS_STATS-Prozeduren vollzogene Änderung der Statistiken im DataDictionary – nicht in Benutzer-Statistiktabellen – wird automatisch historisiert. Eine maximale Aufbewahrungszeit kann über die Prozedur ALTER_STATS_HISTORY_RETENTION definiert werden. Ältere Statistiken werden dann automatisch gelöscht. Sollten aus den neuen Statistiken Ausführungspläne mit schlechterer Performance resultieren, können über die Prozeduren RESTORE_*_STATS historische Statistiken (unter Angabe des gewünschten Zeitpunkts) reaktiviert werden. Ggf. kann zuvor mittels GET_STATS_ HISTORY_AVAILABILITY überprüft werden, ob für den betreffenden Zeitpunkt historische Statistiken gespeichert sind.
Der Optimizer
619
SQL> SELECT dbms_stats.get_stats_history_availability FROM dual; GET_STATS_HISTORY_AVAILABILITY ---------------------------------------------------------------01.04.04 18:19:36,635000000 +01:00 SQL> BEGIN dbms_stats.restore_schema_stats( ownname => 'SCHULUNG' ,as_of_timestamp => SYSTIMESTAMP - INTERVAL '2 00:00:00' DAY TO SECOND ); END;
Gesperrte Statistiken Sollen für eine oder mehrere Tabellen bestimmte Statistikinformationen verbindlich festgeschrieben werden, können diese eingetragen und anschließend mittels der Prozedur LOCK_TABLE_STATS gewissermaßen »schreibgeschützt« werden. Dabei werden auch Statistiken abhängiger Objekte (Indexstatistiken und Histogramme) schreibgeschützt. Bei extrem dynamischen Tabellen kann hierüber das so genannte »Dynamic Sampling« erzwungen werden, indem evtl. vorhandene Statistiken gelöscht werden und anschließend der Schreibschutz aktiviert wird. Werden anschließend auf Schema- oder Datenbankebene Statistiken erstellt, werden die so geschützten Objekte einfach übersprungen. Mit der Prozedur LOCK_SCHEMA_STATS kann analog ein ganzes Schema schreibgeschützt werden. Über die zugehörigen UNLOCK_*_STATS-Prozeduren wird der Schreibschutz aufgehoben. Die meisten Prozeduren verfügen außerdem über einen Parameter force, der – auf TRUE gesetzt – sich über den Schreibschutz hinwegsetzt.
Abbildung 11.4: Verwaltung von Optimizer-Statistiken via DBMS_STATS
620
Tuning
Speichern von Default-Optionen Für einige Parameter (u.a. cascade, degree, estimate_percent, method_opt) können Default-Werte gesetzt werden. Dies kann beispielsweise einmalig nach dem Setup der Datenbank geschehen, um auf diese Weise »zentrale Richtlinien« für die Statistikerzeugung abzulegen und um diese Werte nicht bei jeder Benutzung wiederholen zu müssen. Das Setzen bzw. Abfragen der Default-Optionen geschieht über die Prozedur SET_PARAM bzw. die Funktion GET_PARAM. SQL> SET SERVEROUTPUT ON SIZE 10000 SQL> execute dbms_output.put_line(dbms_stats.get_param('cascade')); DBMS_STATS.AUTO_CASCADE SQL> execute dbms_stats.set_param('cascade','TRUE');
Spezialfunktionen des ANALYZE-Kommandos Erstellen einer Liste mit verketteten Sätzen SQL> ANALYZE TABLE kunden LIST CHAINED_ROWS INTO CHAINED_ROWS;
Die Tabelle chained_rows kann über ein Skript 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. Diese können anschließend für eine Reparatur zwecks Beseitigung der verketteten Sätze benutzt werden. Validieren von Tabellen, Indizes oder Materialized Views SQL> ANALYZE TABLE kunden VALIDATE STRUCTURE [INTO INVALID_ROWS] CASCADE;
Die Tabelle invalid_rows kann über ein Skript im Verzeichnis $ORACLE_HOME/ rdbms/admin mit dem Namen utlvalid.sql erstellt werden. Bei der Validierung eines Index werden außerdem einige Indexstatistiken geschrieben, die über die Data-Dictionary-Views INDEX_STATS und INDEX_HISTOGRAM verfügbar sind. Diese können Anhaltspunkte für einen Neuaufbau des Index liefern. Validieren von Referenzen in Tabellen 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.
Der Optimizer
621
11.3.3 Serverparameter mit Relevanz für den Query Optimizer pga_aggregate_target Der Parameter pga_aggregate_target bestimmt die Gesamtspeichermenge des Hauptspeichers, die Serverprozessen zugewiesen wird (die so genannte PGA, Process Global Area). Die Serverprozesse nutzen diesen Speicherbereich u.a. für Sortierungen und für Hash-Algorithmen im Rahmen von Hash-Joins. Je mehr Platz hier zur Verfügung gestellt wird, desto seltener müssen Sortier- und HashZwischenergebnisse in den Temporär-Tablespace ausgelagert werden. Dies führt aber auch dazu, dass der Optimizer tendenziell zu häufig Merge Joins oder Hash Joins verwendet, die für die Ressourcen belastender als Nested Loop Joins sind. Zu beachten ist, dass es bestimmte Obergrenzen für die PGA-Größe geben kann, z.B. werden einem einzelnen Server-Prozess nicht mehr als 5% des gesamten durch pga_aggregate_target definierten Volumens zugeordnet. Prozesse, die mit der Parallel-Query-Funktionalität laufen, können bis zu 30% des Volumens beanspruchen. Die maximale Hauptspeichermenge, die einem einzelnen Serverprozess zugeordnet werden kann, lässt sich durch folgende Abfrage bestimmen: SQL> SELECT value, unit FROM v$pgastat WHERE name = 'global memory bound';
sort_area_size / hash_area_size Als Alternative zur automatischen Verwaltung der PGA-Größen mittels pga_aggregate_target gibt es noch die Möglichkeit, feste Maximalgrößen für verschiedene Arbeitsbereiche festzulegen. 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 Hash Join zur Verfügung. Auch hier gilt: Je größer diese Werte sind, desto seltener müssen Zwischenergebnisse in den Temporär-Tablespace ausgelagert werden. Auch hier wird der Optimizer in diesen Fällen zu häufig Merge Joins oder Hash Joins verwenden, die für die Ressourcen belastender als Nested Loop Joins sind. db_file_multiblock_read_count Über diesen Parameter kann eingestellt werden, wie viele Oracle-Blöcke im Rahmen eines Full-Table-Scans jeweils mit einem Betriebssystem-I/O in die SGA geholt werden sollen. Die Standardeinstellung ist 8. Insbesondere bei einem Striping der Platten mit »64-KByte-Chunks« harmoniert dies bei einer Datenbankblockgröße von 8 KByte hervorragend mit der I/O-Größe. Dieser Wert sollte nur dann heraufgesetzt werden, wenn auch Systemstatistiken benutzt werden (siehe Abschnitt Erstellung und Pflege von Statistiken). Der Hintergrund hierfür ist, dass der Optimizer bei höheren Einstellungen Full-Table-Scans stärker favorisiert, da aus seiner Sicht dann eine einzelne I/O-Operation für eine große Menge von Daten ausreicht. Verschärft wird diese Problematik noch dadurch, dass genau genommen maximal acht Blöcke pro I/O-Operation gelesen werden. Befinden sich einzelne Blöcke bereits im Buffer-Cache, wird die I/O-Operation aufgeteilt,
622
Tuning
so dass der bereits im Cache befindliche Block übersprungen wird. Auch über Extent-Grenzen hinweg wird nicht mit einer I/O-Operation gelesen. Werden Tabellen nun vorwiegend unter Verwendung von Indizes gelesen, führt dies häufig zu einer Zersplitterung der I/O-Zugriffe für einen Full-Table-Scan, da viele einzelne Blöcke der Tabelle bereits im Buffer-Cache liegen. Im Rahmen der Systemstatistiken wird daher u.a. ermittelt, wie viele Blöcke im laufenden Betrieb im Durchschnitt tatsächlich gelesen werden. Dieser Wert kann wie folgt abgefragt werden: SQL> SELECT pval1 FROM sys.aux_stats$ WHERE pname = 'MBRC';
Sind Systemstatistiken vorhanden, wird der dort gespeicherte Wert anstelle des über den Parameter db_file_multiblock_read_count gesetzten Wertes für die Kostenschätzungen des Optimizers benutzt. Eine Manipulation dieses Wertes wie in Kapitel Erstellung und Pflege von Statistiken beschrieben ist ebenfalls möglich. In der Praxis tritt häufig das Problem auf, dass eine Anwendung mit Hilfe von ALTER SESSION-Kommandos Optimizer-relevante Serverparameter verändert. Es ist dann nicht so einfach, eine identische Tuning-Umgebung herzustellen, da diese Kommandos u.U. irgendwo in der Anwendung »versteckt« sind. Seit Oracle 10g gibt es für diese Situation eine Lösung: die View V$SES_OPTIMIZER_ ENV, welche die Optimizer-Einstellungen jeder Session zeigt. SQL> SELECT name, value, isdefault FROM v$ses_optimizer_env WHERE sid = <Session-SID>; NAME -----------------------------parallel_execution_enabled optimizer_features_enable cpu_count active_instance_count parallel_threads_per_cpu hash_area_size bitmap_merge_area_size sort_area_size sort_area_retained_size db_file_multiblock_read_count pga_aggregate_target parallel_query_mode parallel_dml_mode parallel_ddl_mode optimizer_mode cursor_sharing star_transformation_enabled optimizer_index_cost_adj optimizer_index_caching
VALUE ---------true 10.1.0.3 1 1 2 2000000 1048576 65536 0 16 51200 KB enabled disabled enabled choose similar false 100 0
ISD --YES YES YES YES YES NO YES YES YES NO YES YES YES YES NO NO YES YES YES
Zugriffsoptimierung query_rewrite_enabled query_rewrite_integrity workarea_size_policy optimizer_dynamic_sampling statistics_level skip_unusable_indexes
623 true trusted auto 2 typical true
YES NO YES YES YES YES
Für besonders harte Fälle kann auch eine vollständige Liste aller (auch undokumentierten) Optimizer-Einstellungen einer Session abgerufen werden: SQL> SELECT pname_qksceserow AS name ,pvalue_qksceserow AS value ,DECODE(BITAND(flags_qksceserow, 2),0,'NO','YES') AS isdefault FROM x$qksceses WHERE sid_qksceserow = <Session-SID>;
11.4
Zugriffsoptimierung
11.4.1 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 Enterprise Manager, Quest TOAD und viele weitere grafische Tools. SQL-Tracing von Anwendungen und Erstellung der Ausführungspläne aus der entsprechenden Trace-Datei (z.B. über 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 für ein SQL-Kommando mit dem SQL*Plus-Befehl EXPLAIN PLAN und dem Package DBMS_XPLAN. Alleinige Ermittlung eines Ausführungsplans für ein SQL-Kommando im Cursor-Cache (abfragbar über V$SQL) oder für ein im AWR (Automatic Workload Repository) gespeichertes SQL-Kommando über das Package DBMS_XPLAN. 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 und die im Kontext der Phasen aufgetretenen Wartezustände ermittelt.
624
Tuning
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
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
Zugriffsoptimierung 503 2 5 0 1
625
bytes received via SQL*Net from client SQL*Net roundtrips to/from client sorts (memory) sorts (disk) rows processed
Listing 11.2: Ausführungsplan mit SQL*Plus
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. Dies ist darauf zurückzuführen, 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.
626
Tuning
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 AND a.auf_nr = p.pos_aufnr AND UPPER(k.kd_nachname) = :nachname AND UPPER(k.kd_vorname) = :vorname GROUP BY k.kd_ort;
Das Anzeigen des Ausführungsplans geschieht über eine Abfrage der Tabellenfunktion DBMS_XPLAN.DISPLAY: SQL> SELECT plan_table_output FROM TABLE( dbms_xplan.display('plan_table','demo_explain','basic' )); PLAN_TABLE_OUTPUT --------------------------------------------------------------Plan hash value: 1679115540 ------------------------------------------------------------| Id | Operation | Name | ------------------------------------------------------------| 0 | SELECT STATEMENT | | | 1 | SORT GROUP BY | | | 2 | TABLE ACCESS BY INDEX ROWID | POSITIONEN | | 3 | NESTED LOOPS | | | 4 | NESTED LOOPS | | | 5 | TABLE FULL SCAN | KUNDEN | | 6 | INDEX RANGE SCAN | AUFTRAEGE_IDX_002 | | 7 | INDEX RANGE SCAN | POSITIONEN_IDX_003 | ------------------------------------------------------------14 Zeilen ausgewählt.
Der dritte Parameter ist optional und kann außer basic noch die Werte typical und all annehmen, die weitere Informationen zum Ausführungsplan ausgeben. Default und für den Normalfall zu empfehlen ist typical, hierbei werden auch Kostenschätzungen mit ausgegeben. Handelt es sich um ein SQL-Kommando, das im Cursor-Cache – also über die View V$SQL – sichtbar ist oder bereits im AWR (Automatic Workload Repository) gespeichert ist, kann es über die Prozeduren DISPLAY_CURSOR und DISPLAY_AWR in demselben
Package angezeigt werden. Die Aufrufe sind analog. Dabei wird auf ein SQL-Kommando im Cursor-Cache durch Angabe der SQL-ID sowie der Child-Number Bezug
Zugriffsoptimierung
627
genommen. Unterschiedliche Child-Nummern zu derselben SQL-ID identifizieren unterschiedliche Ausführungspläne für dasselbe Kommando. Zum Beispiel: SQL> SELECT sql_id, child_number FROM v$sql WHERE ...; SQL_ID CHILD_NUMBER ------------- -----------ffwhd4jkg425q 0 SQL> SELECT plan_table_output FROM TABLE( dbms_xplan.display_cursor('ffwhd4jkg425q','0','all' ));
Der Aufrufende benötigt SELECT-Rechte auf den Views V$SQL, V$SQL_PLAN und V$SQL_PLAN_STATISTICS_ALL, sonst wird eine entsprechende Meldung (keine Fehlermeldung !) ausgegeben. Ein im AWR gespeichertes Kommando wird ebenfalls über seine SQL-ID identifiziert. Diese taucht in jedem AWR- oder ADDM-Report auf oder kann direkt den AWR-Views entnommen werden, zum Beispiel: SQL> SELECT sql_id FROM dba_hist_sqltext
Gibt es unterschiedliche Ausführungsplänen für dasselbe Kommando, werden alle angezeigt. Die Einschränkung auf eine Variante geschieht hier nicht über die Child-Number, sondern über den Plan-Hashwert (Spalte plan_hash_value in V$SQL oder DBA_HIST_SQL_PLAN), der als zweiter Parameter übergeben werden kann. Der dritte Parameter ist die Datenbank-ID. Im Normalfall wird auf das AWR der lokalen Datenbank Bezug genommen, so dass dieser Parameter ebenfalls auf NULL gesetzt werden kann. Der Aufrufende benötigt SELECT-Rechte auf den Views dba_hist_ sql_plan, dba_hist_sqltext und V$DATABASE. 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.
628
Tuning
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. Für Details wird auf den Abschnitt Erstellung und Pflege von Statistiken verwiesen, wo die notwendigen Schritte und Prozeduren dafür bereits beschrieben wurden. Auch das Aufbewahren historischer Statistiken war und ist ein gutes Mittel, um ggf. alte Statistiken zurückzuholen, wenn aus den neuen Statistiken Ausführungspläne mit schlechterer Performance resultieren. Mit Oracle 10g werden Statistiken – wie bereits berieben wurde – automatisch historisiert, ein manuell erstelltes Skript hierfür ist daher nicht mehr nötig. 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. Eine Änderung des Ausführungsplans kann naturgemäß jederzeit durch Aktualisierung der Statistiken stattfinden, aber auch durch Serverparameter, die sich von denen des Testsystems unterscheiden. Besonders geht es hier um Parameter wie pga_aggregate_target, sort_area_size, hash_area_size oder db_file_multiblock_ read_count. Die Lösung dieses Problems heißt Plan Stability. Ein Ausführungsplan für einen SQL-Befehl kann während der Ausführung aufgezeichnet werden. Solchermaßen gespeicherte Ausführungspläne werden auch als Stored Outlines bezeichnet. Sobald ein SQL-Befehl ausgeführt wird, der identisch mit dem gespeicherten ist, wird der 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 Serverparameter cursor_sharing = force | similar erreicht werden kann – wie im Folgenden noch ausgeführt werden wird. 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 werden implizit angelegt, wenn ein Outline in eine neue Kategorie verschoben oder in dieser neu erstellt wird.
Zugriffsoptimierung
629
Voraussetzungen Um mit Stored Outlines wirklich konstante Ausführungspläne zu garantieren, müssen die Serverparameter query_rewrite_enabled, star_transformation_enabled und optimizer_features_enable bei der Erstellung der Stored Outlines und bei deren Benutzung identische Werte haben. Zur Erstellung von Stored Outlines ist außerdem das Systemprivileg CREATE ANY OUTLINE notwendig. Anlegen von Stored Outlines Zum Anlegen von Stored Outlines gibt es drei 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;
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 bei dieser Art der Erstellung der Serverparameter cursor_sharing nicht berücksichtigt wird, so dass bei Befehlen mit Literalen – wie noch beschrieben wird – keine Übereinstimmung erkannt wird. SQL> CREATE OUTLINE zugriff_1 FOR CATEGORY rule_cat ON SELECT ...;
3. Benutzung der Prozedur DBMS_OUTLN.CREATE_OUTLINE Auch ein SQL-Befehl aus dem Cursor-Cache (View V$SQL) kann direkt zur Angabe der Parameter hash_value und child_number (aus den gleichnamigen Spalten in der View V$SQL) für die Erstellung eines Stored Outlines herangezogen werden. In der Version 10.1.0.3 ist diese Methode aber noch mit derart vielen Bugs behaftet, dass sie praktisch nicht brauchbar ist. 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_outline_1 ON SELECT ...;
630
Tuning
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_outline_1 FROM outline_1;
Private
Outlines
werden
dann
verwendet,
wenn
über
die
Prozedur
dbms_outln_edit.change_join_pos die Join-Reihenfolge vertauscht werden soll
(Änderung des LEADING-Hints). 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> execute dbms_outln_edit.refresh_private_outline (priv_outline_1);
Nach einem Test kann die Private Outline wieder in die Public Outline überstellt werden. SQL> CREATE OR REPLACE OUTLINE outline_1 FROM PRIVATE priv_outline_1;
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 Serverparameter 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 Serverparameter 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.
Zugriffsoptimierung
631
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. Bei Anwendungen, die dynamisches SQL verwenden, können bei der Erstellung der Stored Outlines SQL-Kommandos auftauchen, die später nie wieder vorkommen (»Eintagsfliegen«). Deren Outlines verbrauchen sonst unnötigen Platz. update_by_cat: Ordnet alle Stored Outlines einer Kategorie einer anderen zu. Export und Import von Stored Outlines Mit Hilfe der Stored Outlines ist es nun möglich, feste Zugriffspfade für SQLZugriffe zusammen mit einer Anwendung auszuliefern. 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 (für Data Pump sowie konventionellen Export/Import siehe auch Kapitel 10). Zur Laufzeit wird anhand eines Hashwertes, der so genannten Signatur, überprüft, ob für das betreffende SQL-Kommando ein Stored Outline hinterlegt ist. Da der Hash-Algorithmus mit der Oracle-Version variiert, muss im Falle eines Imports aus einer älteren Datenbankversion nach dem Import einmalig die Prozedur DBMS_OUTLN.UPDATE_SIGNATURES aufgerufen werden, damit die Stored Outlines gefunden werden.
632
Tuning
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, was spätestens im Rahmen einer Migration auf Oracle 10g geplant werden sollte. 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 Serverparameters 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. Unerwartete Ergebnisse Seit Oracle8i gibt es – völlig unabhängig vom Konzept der Plan Stability – die Möglichkeit, Cursor-Sharing zu erzwingen (siehe Abschnitt Hints). In den vergangenen Oracle-Versionen gab es verschiedene Bugs, die bei Kombination der beiden Funktionalitäten Cursor-Sharing und Plan Stability zu falschen Ergebnissen bei Abfragen führten. Diese Probleme scheinen mit Oracle 10g gelöst zu sein, allerdings können auch bei korrektem Verhalten des Optimizers zumindest unerwartete Ausführungspläne auftreten. Folgende Konstellationen sind möglich, sollten jedoch vermieden werden: Cursor-Sharing ist aktiviert (cursor_sharing = force | similar). Stored Outlines wurden aber mit dem CREATE OUTLINE-Kommando oder unter der Einstellung cursor_sharing=exact angelegt. Damit wurde der Text des SQL-Statements unverändert übernommen. Wird dasselbe SQL-Statement nun ausgeführt, greift die automatische Ersetzung, und das Stored Outline wird nicht benutzt. Die Stored Outlines sollte daher besser durch Setzen des Session-Parameters create_stored_ outlines erzeugt werden. Cursor-Sharing ist auf similar gesetzt, d.h., Literale sollen nur ersetzt werden, wenn dies keine Auswirkung auf Histogramm-Benutzungen hat. Die Stored Outlines wurden mittels create_stored_outlines erzeugt, enthalten also Bindevariablen. Damit wird aber immer der gespeicherte Ausführungsplan benutzt, was der Idee von cursor_sharing=similar widerspricht.
11.4.2 Indizierung 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. Grundlegendes über Indizes ist in Kapitel 5 beschrieben.
Zugriffsoptimierung
633
Index-Histogramme Histogramme sind zwar kein eigener Indextyp, jedoch sind sie eine Erweiterung der Indizes. Wie bereits beschrieben, nutzt der Query-Optimizer Statistiken, um einen Zugriff optimal zu gestalten. Dazu werden auch Informationen über Indizes betrachtet, wie z.B. die Anzahl der unterschiedlichen Schlüsselwerte. In den meisten Fällen ist ein indizierter Zugriff auf Daten einer Tabelle nur dann sinnvoll, wenn weniger als 15 % des Tabelleninhaltes als Ergebnismenge geliefert werden2. 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: 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 Status (2 bis 4). Über eine Anwendung können sich Sachbearbeiter die offenen Aufträge anzeigen lassen. In der Statistik des Index findet der Optimizer die Information: distinct_keys = 5; Ein solcher Index würde vom 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 11.5: 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, welche die Sätze der Tabelle abbilden. Bei ungleichmäßiger Schlüsselverteilung ergibt sich eine unterschiedliche Anzahl von Schlüsseln in den Buckets. Pro Bucket werden Endpunkte (Endpoints) verwaltet, welche die Schlüsselwerte am Anfang und am Ende eines Buckets angeben. 2
Der Schwellenwert hängt von der Blockgröße und durchschnittlichen Satzlänge ab und kann dementsprechend nach unten oder oben variieren.
634
Tuning
Oracle hat sowohl höhen- als auch breitenbalancierte Histogramme implementiert, die Realisierung ist dabei abhängig von der Size-Klausel bei der Generierung der Statistiken. Wird die Size-Klausel größer oder gleich der Anzahl distinktiver Schlüsselwerte gesetzt, entsteht ein breitenbalanciertes Histogramm, wird sie kleiner gesetzt, wird höhenbalanciert generiert. Bei höhenbalancierten Histogrammen betrachtet der Optimizer 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
Abbildung 11.6: Höhenbalanciertes Histogramm
Der Schlüsselwert 1 erscheint 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 drei Buckets definiert wird. SQL> ANALYZE TABLE kunde COMPUTE STATISTICS FOR COLUMNS kredit SIZE 3;
Wie viele Buckets tatsächliche angelegt wurden, 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, gering selektiver Kriterien eine hohe Gesamtselektivität erzeugen. Mit herkömmlichen Indizes kann in diesem Fall nicht gearbeitet werden, da ansonsten für sämtliche Permutationen der in der WHERE-Klausel kombinierten Einschränkungen dementsprechend zusammengesetzte 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 aufgrund der physikalischen Speicherung der Bitmap-Indizes auftreten und im Folgenden noch behandelt werden.
Zugriffsoptimierung
635
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. Jedes Bit repräsentiert dabei einen Datensatz. 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. O | 00010000010001000001 ... Anzahl Sätze ____________________________ A | 11101111101110111110 ... Anzahl Sätze Abbildung 11.7: Bit-Leiste eines Bitmap-Index
Physikalisch werden diese Bit-Leisten in Teilbereichen gespeichert, die jeweils maximal die Größe eines halben Oracle-Blocks haben. Die Bit-Leisten selbst werden über eine B*Baumstruktur navigierbar. Zusätzlich sind die Anfangs- und Endadressen der Datenblöcke jeder Leiste in Form von Rowids gespeichert. Bytes jeder Leiste, deren Bits vollständig aus Nullen bestehen, werden darüber hinaus komprimiert. Die Anzahl der Bit-Positionen pro Datenblock ergibt sich entweder aus der per Tabellendefinition minimal möglichen Satzlänge – aus der die maximal denkbare Anzahl Sätze pro Datenblock abgeleitet wird, oder aus der tatsächlich maximal vorgefundenen Anzahl Datensätze. Im letzteren Fall ist diese Anzahl vor der Erstellung des betreffenden Bitmap Index durch den Befehl alter table minimize records_per_block zu ermitteln und im Data Dictionary festzuschreiben. Unter Vorgabe der errechneten oder festgeschriebenen Satzanzahl sowie der begrenzenden Blockadressen der Bit-Liste wird bei Zugriffen über einen Algorithmus aus den Bit-Positionen eine Satzadresse berechnet. Daraus ergibt sich aber auch, dass bei Änderung der minimalen Satzlänge durch einen ALTER TABLE-Befehl der Bitmap-Index ungültig werden kann und reorganisiert werden muss. Die erwähnte Komprimierung verringert den Platzbedarf des Index und damit auch die IO-Operationen, die für sein Lesen notwendig sind. So benötigen BitmapIndizes häufig nur wenige Prozent des Platzes von B*Bäumen. Das ist natürlich sehr abhängig von der Anzahl der unterschiedlichen Schlüsselwerte und der Anzahl der Sätze. Je größer die Anzahl der Satzadressen pro Schlüsselwert und die Anzahl der Schlüsselwerte selbst ist, desto günstiger kann sich die oben erwähnte Komprimierung auswirken. Daraus ergeben sich folgende Vorteile: Geringerer Platzbedarf, besonders bei geringer Kardinalität, also bei 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).
636
Tuning
Nachteil: Werden durch DML-Operationen indizierte Spalten verändert, muss der gesamte physische Bitmap-Bereich – wie erwähnt maximal ein halber Block – 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 Serverparameter: create_bitmap_area_size (Default: 8 MB) Bestimmt für einen Prozess die Größe des Hauptspeicherbereichs, der für die Erstellung eines Bitmap-Index zur Verfügung steht. Je geringer die Selektivität der zu indizierenden Spalte, desto mehr Hauptspeicher wird für den Indexaufbau benötigt. Dieser Parameter wird nur aus Kompatibilitätsgründen und für SharedServer-Konfigurationen weiter unterstützt. Ansonsten wird auf den Parameter pga_aggregate_target verwiesen. bitmap_merge_area_size (Default: 1 MB) 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 die Gesamtspeichermenge für alle Prozesse definiert, die u.a. für Bitmap-Operationen verwendet werden kann. Für eine genaue Beschreibung siehe Abschnitt Serverparameter mit Relevanz für den Query Optimizer. Das Anlegen eines Bitmap-Index 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 index_type zu erkennen. Index-organized Tables Streng genommen sind Index-organized Tables keine Spezialform eines Index, sondern Tabellen, deren Daten in einer B*Baumstruktur 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, können auch die Daten eines Satzes, die nicht zum Primärschlüssel gehören, direkt mit in der B*Baumstruktur gespeichert werden. Das bedeutet, dass neben der ROWID auch noch die ansonsten redundant im Index und in der Tabelle gespeicherten Schlüsselfelder nur einfach gehalten werden.
Zugriffsoptimierung
637
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 wenig effizient wird. Aus diesem Grunde kann ein Überlaufbereich definiert werden, in den Daten ausgelagert werden, die einen definierbaren Schwellenwert (PCTTHRESHOLD) bezüglich des prozentualen Anteils der gesamten Satzlänge überschreiten. SQL> CREATE TABLE inhaltsverzeichnis (begriff VARCHAR2(50), dokument_nr NUMBER, fundstelle NUMBER) CONSTRAINT cons_iot PRIMARY KEY (begriff) ORGANIZATION INDEX TABLESPACE ts1 PCTTHRESHOLD 20 OVERFLOW TABLESPACE ts2; Listing 11.3: Index-organized Table
Nachteilig können Zugriffe über Sekundärschlüssel sein, die auch für Index-organized Tables angelegt werden können. Die Sekundärschlüssel können nicht immer sicher über ROWIDs auf die Sätze im B*Baum verweisen, da diese durch Blockaufteilungen und -verschmelzungen verschoben werden können. Die im Sekundärindex gespeicherte so genannte logische ROWID enthält daher zusätzlich zu der physischen ROWID – die bei der Erstellung des Index immer korrekt ist – auch noch den zugehörigen Primärschlüsselwert. Der Zugriff erfolgt dann zunächst über die physische ROWID, falls der betreffende Satz in der Zwischenzeit »migriert« wurde, im Anschluss daran über den Primärschlüssel. Im letzteren Fall entstehen zusätzliche Blockzugriffe, wodurch sich die erwähnten Nachteile ergeben. Besondere Berücksichtigung sollte der Parameter COMPRESS finden. Es kann eine Ganzzahl angegeben werden, die bestimmt, wie viele Felder des Primärschlüssels als »Präfixe« nur einmal pro Indexblock gespeichert werden. Über diesen Parameter können – je nach Beschaffenheit der Schlüsselwerte – u.U. erhebliche Platzersparnisse für indexorganisierte Tabellen – aber auch für herkömmliche B*Indizes – 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 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
638
Tuning
Auf diese Art und Weise wird eine höhere Verteilung der Werte auf verschiedenen Leaf-Blöcken eines Index 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 Index aufgehoben werden. SQL> ALTER INDEX r_ind1 REBUILD NOREVERSE;
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ß- und 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. Stattdessen 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.
11.4.3 Hints Trotz diverser Möglichkeiten der Indizierung und der Nutzung von Histogrammen 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.
Zugriffsoptimierung
639
Syntax SQL> SELECT /*+ hint */ * FROM ...;
oder SQL> SELECT --+ hint * FROM ...; -- neue Zeile erforderlich
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 ist das Pluszeichen 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 Pluszeichen 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 insbesondere in älteren Versionen die Leerzeichen unbedingt, um die Hints erkennen zu können. Eine zweite Besonderheit ist bei der Verwendung von Aliasnamen für Tabellennamen zu beachten. Werden in der FROM-Klausel Aliasnamen verwendet, müssen diese ebenfalls im Hint eingesetzt 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;
Dies funktioniert! SQL> SELECT /*+ full(auftrag) */ sum(auftragswert) FROM auftrag a;
Dies funktioniert nicht! In den folgenden Abschnitten wird eine Übersicht über die möglichen OptimizerHints gegeben. Innerhalb jedes Abschnitts wird auch eine Priorisierung der einzelnen Hints vorgenommen. Die zuerst genannten spielen die größte Rolle in der praktischen Tuning-Arbeit. Globale Hints Eine Problematik bei der Verwendung von Hints stellt sich, wenn in der FROM-Klausel 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.
640
Tuning
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';
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. In den folgenden Abschnitten kann für tablespec stets wahlweise ein einfacher oder ein globaler Hint eingesetzt werden. Hints für Unterabfragen Hints können auch in Unterabfragen verwendet werden. SQL> SELECT /*+ ordered */ k.kdnr, k.vorname, k.nachname, COUNT(a.aufnr) AS anz_auftraege FROM kunden k, auftraege a WHERE k.kdnr = a.kdnr (+) AND k.kdnr NOT IN ( SELECT /*+ index(t idx$telnummern_kdnr) */ t.kdnr FROM telnummern t WHERE t.kdnr = k.kdnr ) GROUP BY k.kdnr, k.vorname, k.nachname;
Dabei wirken sich die durch den Hint gemachten Vorschläge ausschließlich für die betreffende Unterabfrage aus, die äußeren Abfrageblöcke bleiben unberührt (wichtig zum Beispiel bei Hints wie ORDERED, USE_CONCAT etc., die sich nicht auf eine Tabelle beziehen). Entsprechendes gilt für unterschiedliche Zweige einer Abfrage mit UNION, INTERSECT oder MINUS.
Zugriffsoptimierung
641
Mit Oracle 10g gibt es nun eine Möglichkeit, alle Hints eines komplexen SQL-Kommandos übersichtlich zu Beginn des Kommandos – also hinter dem ersten, äußersten SELECT – zu versammeln. Dazu kann jedem Abfrageblock (Zweig oder Unterabfrage) ein Name zugewiesen werden. Dies geschieht durch den speziellen Hint QB_NAME, der als einziger in dem Abfrageblock verbleibt. Alle anderen Hints werden hinter das erste, äußerste SELECT gesetzt und um den Abfrageblock-Namen ergänzt. Die Syntax hierfür ist: @blockname tablespec anstatt tablespec alleine. Die obige Abfrage kann damit wie folgt dargestellt werden: SQL> SELECT /*+ ordered index(@sub_tel t idx$telnummern_kdnr) */ k.kdnr, k.vorname, k.nachname, COUNT(a.aufnr) AS anz_auftraege FROM kunden k, auftraege a WHERE k.kdnr = a.kdnr (+) AND k.kdnr NOT IN ( SELECT /*+ qb_name(sub_tel) */ t.kdnr FROM telnummern t WHERE t.kdnr = k.kdnr ) GROUP BY k.kdnr, k.vorname, k.nachname;
Hints zur Auswahl des Optimierungsziels Mit diesen Hints kann pro SQL-Befehl die Benutzung eines bestimmten Optimierungsansatzes gewählt werden. ALL_ROWS
Optimierung auf Gewinnung der gesamten Ergebnismenge (Standardeinstellung bei CHOOSE). FIRST_ROWS(n)
Optimierung auf schnellstmögliche Gewinnung der ersten n Sätze. Sinnvoll für Online-Anwendungen oder wenn bekannt ist, dass via Cursor-Fetch-Operationen ohnehin nur einer oder wenige Datensätze gelesen werden. 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 aufgrund der Statistiken als nicht selektiv betrachtet, für eine bestimmte Abfrage mit einem fest definierten Wertebereich der indizierte Zugriff aber sinnvoll ist. FULL(tablespec)
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.
642
Tuning
INDEX(tablespec 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. INDEX_ASC(tablespec indname), INDEX_DESC(tablespec 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. INDEX_DESC muss angegeben werden, damit ein Index-Scan in absteigender Reihenfolge durchgeführt wird, z.B. für eine absteigende Sortierung einer Ergebnismenge. INDEX_FFS(tablespec indname)
Es wird ein Index-Fast-Full-Scan angefordert. Hierbei wird der gesamte Index im multiblock-io durchgelesen. Kann über die Felder des angegebenen Index die Abfrage beschickt werden, so kann dadurch ein »Full-Table-Scan« auf die Tabelle ersetzt werden. INDEX_COMBINE(tablespec 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. INDEX_SS(tablespec indname),INDEX_SS_DESC(tabalias indname)
Diese Hints versuchen einen indizierten Zugriff auf die angegebene Tabelle. Die Besonderheit besteht darin, dass der Indexzugriff auch dann möglich ist, wenn die erste Indexspalte nicht in der WHERE-Klausel eingegrenzt wird (Präfix-Kriterium ist nicht erfüllt). Dies ist für Indizes gedacht, deren erste Spalte geringe Selektivität, also nur wenige Ausprägungen hat, z.B. Geschlecht, Status-IDs oder MandantenIDs. Für jede Ausprägung wird ein entsprechender Indexzugriff durchgeführt, und die Ergebnisse werden anschließend zusammengefügt. Diese Methode wird als Index-Skip-Scan bezeichnet. INDEX_SS_DESC muss angegeben werden, damit ein Index-Skip-Scan in absteigender Reihenfolge durchgeführt wird, z.B. für eine absteigende Sortierung einer Ergebnismenge. NO_INDEX(tablespec [indname [indname]]), NO_INDEX_SS(tablespec [indname [indname]])
Mit diesen Hints kann die Benutzung einzelner Indizes oder aller Indizes für den Optimizer ausgeschaltet werden, die auf der spezifizierten Tabelle liegen. CLUSTER(tablespec), HASH(tablespec)
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 »Cluster Scan« oder einen »Hash Scan« an.
Zugriffsoptimierung
643
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. LEADING(tablespec)
Mit dem Hint LEADING kann genau eine Tabelle angegeben werden, die als treibende Tabelle benutzt wird. Im Gegensatz zum ORDERED-Hint ist also nicht die vollständige Reihenfolge, sondern nur das erste Glied der Join-Kette festgelegt. 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 ORDEREDHint überschreibt den LEADING-Hint. USE_NL(tablespec [tablespec...]), USE_NL_WITH_INDEX(tablespec [indname indname ...])
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 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. Damit der Zugriff auf die Positionstabelle nicht aus Versehen über einen Full-TableScan passiert (z.B. weil der entscheidende Index in einem neuen Software-Release nicht mehr existiert), kann der USE_NL_WITH_INDEX-Hint verwendet werden. Auf diese Weise wird der Nested-Loop-Join nur dann gewählt, wenn einer der angegebenen Indizes existiert. Ist kein Index angegeben, sucht der Optimizer, ob er einen geeigneten Index findet. Existiert kein geeigneter Index, wird der Hint ignoriert. USE_MERGE(tablespec [tablespec...])
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 Hauptspeicher-Sortierbereich pro Prozess (eingestellt über die Serverparameter sort_area_size bei manueller PGA-Verwaltung oder pga_aggregate_target bei automatischer PGA-Verwaltung) überschritten ist und die
644
Tuning
Sortierzwischenschritte auf den Temporär-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(tablespec [tablespec...])
Dieser Hint hat die gleiche Parametrierung wie die beiden vorhergehenden. Hier werden die spezifizierten Tabellen über einen Hash-Join verbunden, wobei der 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 Serverparameter hash_area_size (bei manueller PGA-Verwaltung, Standardwert ist das Doppelte der sort_area_size) bzw. pga_aggregate_target (bei automatischer PGA-Verwaltung) eingestellt. NO_USE_NL(tablespec),NO_USE_MARGE(tablespec), NO_USE_HASH(tablespec)
Diese Hints verbieten entsprechende Join-Methoden für die betreffende Tabelle. DRIVING_SITE(tablespec)
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 AND k.kdnr = a.kdnr;
Hints zur Parallelisierung PARALLEL(tablespec 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 Wert den Parallelisierungsgrad an.
Zugriffsoptimierung
645
Wird der Wert DEFAULT spezifiziert, so werden die Werte der entsprechenden Serverparameter bzw. der Tabellen-Parallelisierungsgrad 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. NO_PARALLEL(tablespec)
Mit dem Hint NO_PARALLEL kann eine auf Tabellenebene eingestellte Parallelisierung ausgeschaltet werden. Achtung: Dieser Hint lautete bis einschließlich Oracle9i NOPARALLEL. Der alte Hint wird zwar ebenfalls noch unterstützt, sollte aber möglichst nicht mehr verwendet werden. PQ_DISTRIBUTE(tablespec_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: HASH, HASH
Beide Tabellen sind ä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ßerer 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.
646
Tuning
PARALLEL_INDEX(tablespec indname 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 Wert nach dem Namen des Index den Grad der Parallelisierung. NO_PARALLEL_INDEX(tablespec indname)
Schaltet den auf Indexebene eingestellten Grad der Parallelisierung aus. Achtung: Dieser Hint lautete bis einschließlich Oracle9i NOPARALLEL_INDEX. Der alte Hint wird zwar ebenfalls noch unterstützt, sollte aber möglichst nicht mehr verwendet werden. 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, REWRITE(mview [mview ...])
Bei der Verwendung von Materialized Views können Abfragen auf Tabellen durch Oracle auf die Verwendung dieser Materialized Views umgeschrieben werden. Dazu muss der Serverparameter query_rewrite_enabled auf TRUE gesetzt sein. Der Hint erzwingt dieses Verfahren ohne Berücksichtigung der kalkulierten Kosten. Ggf. können auch gleich eine oder mehrere in Frage kommende materialisierte Views mitgegeben werden. NO_REWRITE
Verbietet das Umschreiben einer Abfrage, auch wenn der Serverparameter query_rewrite_enabled auf TRUE gesetzt ist. Achtung: Dieser Hint lautete bis einschließlich Oracle9i NOREWRITE. Der alte Hint wird zwar ebenfalls noch unterstützt, sollte aber möglichst nicht mehr verwendet werden. MERGE(tablespec)
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(tablespec)
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.
Zugriffsoptimierung
647
STAR_TRANSFORMATION, FACT(tablespec), NO_FACT(tablespec)
Wird der Hint STAR_TRANSFORMATION angegeben, so wird der Optimizer angewiesen, nach dem besten Zugriffsplan unter Einschluss einer Star-Query-Transformation der Abfrage zu ermitteln. In einem Data-Warehouse-Umfeld kann durch eine solche Transformation eine schnellere Verarbeitung von Joins zwischen einer Faktenund mehreren Dimensionstabellen erreicht werden (siehe auch Kapitel 15). Voraussetzung ist die Existenz von Bitmap-Indizes auf den Join-Spalten der Faktentabelle oder von Bitmap-Join-Indizes auf den dazugehörigen Spalten der Dimensionstabellen. Über die Hints FACT und NO_FACT kann in diesem Zusammenhang weitere Information mitgegeben werden, welche der beteiligten Tabellen eine Faktentabelle ist. Voraussetzung für diese Transformation ist auch, dass der Serverparameter star_transformation_enabled auf TRUE oder auf TEMP_DISABLE gesetzt ist. NO_STAR_TRANSFORMATION
Unterbindet den Versuch einer Star-Query-Transformation. UNNEST
Dieser Hint versucht die Umschreibung von Unteranfragen in einen Join, um dem Optimizer andere Zugriffspfade zu ermöglichen. NO_UNNEST
Der NO_UNNEST-Hint deaktiviert die Möglichkeit der Auflösung von Unteranfragen in Joins für einen Block. NO_QUERY_TRANSFORMATION
Verhindert sämtliche Abfragetransformationen. 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. NOAPPEND
Der Append-Modus ist die Standardeinstellung bei paralleler Verarbeitung. Über den Hint NOAPPEND kann dieser Modus in der Parallelverarbeitung deaktiviert werden.
648
Tuning
CURSOR_SHARING_EXACT
Der Serverparameter cursor_sharing = exact | force | similar 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. Damit können trotz aktiviertem Cursor-Sharing für ein SQL-Kommando Histogramm-Informationen genutzt werden. CACHE(tablespec)
Blöcke einer Tabelle, die durch einen Full-Table-Scan gelesen werden, werden nicht über den LRU-Algorithmus (least recently used) 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 Speicherparameter CACHE auf Tabellenebene setzen). NOCACHE(tablespec)
Mit NOCACHE kann eine auf Tabellenebene gesetzte LRU-Verwaltung für Full-TableScans für einen Befehl deaktiviert werden. 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 (diese werden normalerweise vom Optimizer zuletzt ausgeführt) 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 Reihenfolge der Ausführung von benutzerdefinierten Funktionen, Typmethoden und Subqueries.
Zugriffsoptimierung
649
Spezial-Hints Die folgenden beiden Hints sind nicht dokumentiert und sollten nur in Ausnahmefällen verwendet werden: CARDINALITY([tablespec] n)
Damit nimmt der Optimizer an, dass die betreffende Tabelle n Zeilen zurückliefert. Interessant ist dieser Hint für temporäre Tabellen sowie für Tabellenfunktionen. In diesen Fällen hat der Optimizer keine anderen Möglichkeiten, die Zeilenzahl abzuschätzen. Wird kein Tabellenalias angegeben, heißt das, dass die gesamte Abfrage n Zeilen zurückliefert. Dies ist in den genannten Fällen für Unterabfragen interessant. SELECTIVITY([tablespec] s)
Damit nimmt der Optimizer an, dass die Gesamtselektivität aller Filterbedingungen für die betreffende Tabelle s beträgt. Dies ist für Abfragen interessant, in denen auf Spalten eingegrenzt wird, deren Werte nicht voneinander unabhängig sind, beispielsweise Ort und PLZ. Da der Optimizer unabhängige Spaltenausprägungen annimmt (Einzelselektivitäten werden einfach miteinander multipliziert), trifft er in solchen Situationen regelmäßig falsche Abschätzungen für die Größe von Ergebnissen oder Zwischenergebnissen.
11.4.4 Automatisches SQL-Tuning Mit Oracle 10g ist eine Reihe von Begrifflichkeiten aufgekommen, die in die Richtung »automatisches Tuning« weisen, wie beispielsweise: Automatic SQL Tuning SQL Tuning Advisor Automatic Tuning Optimizer SQL Tuning Sets Das vorliegende Kapitel soll eine Ordnung in diesen Begriffsdschungel bringen sowie klären, welche Möglichkeiten tatsächlich durch Einführung neue TuningTechniken geschaffen wurden. Der Automatic Tuning Optimizer In den vergangenen Versionen der Oracle-Datenbank gab es zwei Technologien, SQL-Kommandos in konkrete Ausführungspläne übersetzen zu lassen: den regelbasierten (RBO) sowie den kostenbasierten Optimizer (CBO). Mit Oracle 10g ist der regelbasierte zwar noch vorhanden, aber endgültig zum Auslaufmodell erklärt worden und sollte daher nicht mehr benutzt werden. Der RBO wird daher im Folgenden vollständig ignoriert. Der CBO ist dagegen zu einem Expertensystem ausgebaut worden. Er ist nicht nur in der Lage, unter den gegebenen Umständen einen möglichst guten Ausführungsplan zu berechnen, sondern kann nun auch Maßnahmen vorschlagen, die zu einer weiteren Verbesserung des betreffenden Ausführungsplans führen könnten. Hierzu
650
Tuning
gehört z.B. ob – und, wenn ja, welche – Indizes, Materialized Views, Statistiken oder sonstige Objekte erstellt werden sollten. Auch bestimmte Rewrite-Techniken werden betrachtet. Es geht also nicht um das Vorschlagen von Optimizer-Hints, die den CBO ja nur zur Wahl eines bereits möglichen Ausführungsplans überreden sollen, sondern um die Ermöglichung ganz neuer Ausführungspläne. Dies bedingt offenbar einen nicht unerheblichen Analyseaufwand sowie die Möglichkeit, entsprechende Tuning-Empfehlungen einem menschlichen Benutzer mitzuteilen. Beides passt nicht in den Kontext, in dem der CBO normalerweise arbeitet, nämlich zur Ausführungszeit eines SQL-Kommandos – also live – im Hintergrund möglichst schnell einen möglichst guten Ausführungsplan mit den vorhandenen Indizes, Materialized Views etc. zu erstellen. Daher wurde eine Aufteilung des Optimizers in zwei Komponenten vorgenommen: Der Query Optimizer entspricht in seiner Funktionalität dem alten CBO Der Automatic Tuning Optimizer (ATO) ist neu. Es handelt sich um ein Expertensystem mit den oben beschriebenen erweiterten Analyse-Möglichkeiten sowie einer Schnittstelle, um generierte Tuning-Empfehlungen an den Benutzer weiterzureichen. Dieser Ansatz bietet einen großen, prinzipiellen Vorteil gegenüber den zahlreichen sonst benutzten Tuning-Tools. Solche Tools müssen nämlich immer auf dem neuesten Stand sein, was die Möglichkeiten des Optimizers angeht, also möglichst umfassendes Know-how über die einzelnen Ausführungsschritte sowie die Bewertungsregeln für vollständige Ausführungspläne besitzen, um (abgesehen von Optimizer-Hints) gute Empfehlungen geben zu können. Da beide Komponenten denselben Regelsatz benutzen und kennen, fällt diese Problematik bei der Benutzung des ATO offenbar weg. Die Kostenschätzungen und damit Verhaltensprognosen sind damit garantiert kohärent zum tatsächlichen Verhalten des Query Optimizers. Neue Optimizer-Techniken sind automatisch mit berücksichtigt. Die praktische Effizienz des ATO hängt damit nur noch davon ab, wie viele Heuristiken für die Erzeugung von Tuning-Empfehlungen eingebaut werden. Dies ist natürlich auch das eigentliche Betriebsgeheimnis, und es ist davon auszugehen, dass dieser Satz von Regeln und Heuristiken mit jedem DatenbankRelease und/oder Patchset mehr oder weniger stark erweitert wird. Die Abbildung verdeutlicht noch einmal die Architektur des CBO. Der Query Optimizer bearbeitet unbemerkt vom Benutzer zur Ausführungszeit die ankommenden SQL-Kommandos. Der ATO dagegen wird nur aktiv, wenn er explizit über eine Schnittstelle von einem Benutzer angesprochen wird. Bei dieser Schnittstelle handelt es sich um den SQL Tuning Advisor, der in dem mitgelieferten Package DBMS_SQLTUNE implementiert ist. Mit dem Begriff Automatic SQL Tuning ist nichts anderes als die Benutzung des ATO über diese Schnittstelle gemeint. Dies läuft im Rahmen eines so genannten Tuning-Tasks an, was in den folgenden Abschnitten näher beschreieben wird. Auch auf die so genannten SQL-Profile, die mit der OracleVersion 10g neu hinzugekommen sind, wird weiter unten genauer eingegangen.
Zugriffsoptimierung
651
Abbildung 11.8: Query Optimizer und Automatic Tuning Optimizer
Arbeitsweise des ATO Als Eingabe für den ATO können einzelne SQL-Kommandos oder ganze Kollektionen von Kommandos verwendet werden. Diese werden entweder direkt mit dem SQL-Text eingegeben, oder man nimmt auf Kommandos Bezug, die im CursorCache (View V$SQL) vorliegen oder in einem AWR- oder ADDM-Report als kritisch eingestuft wurden. Ausgabe sind in jedem Fall Tuning-Empfehlungen, Begründungen sowie Abschätzungen zu möglichen Einsparungen. Gleichzeitig werden die entsprechenden SQL-Kommandos zur Umsetzung der Empfehlungen mitgegeben. Die gesamte Interaktion zwischen Benutzer und ATO geschieht über Prozeduraufrufe des Packages DBMS_SQLTUNE. Dies kann wahlweise per SQL oder über den Enterprise Manager Database Control erfolgen (dort über den Punkt ADVISOR CENTRAL und weiter über SQL TUNING ADVISOR). Der ausführende Benutzer benötigt in jedem Falle die Rolle DBA sowie das Systemprivileg ADVISOR. Wie bereits erwähnt, dürften sich die Fähigkeiten des ATO von Version zu Version erweitern. Mit der Version 10.1.0.3 sind mindestens folgende Möglichkeiten eingebaut: Simulation von Indizes und Materialized Views. Es werden Ausführungspläne und Kosten berechnet, als wenn entsprechende Objekte vorhanden wären. Ersetzen von UNION durch UNION ALL, wenn ableitbar ist, dass keine Duplikate vorkommen können Ersetzen von NOT IN- durch NOT EXISTS-Unterabfragen
652
Tuning
Ersetzen von Filterbedingungen der Form TO_CHAR(datumswert) = datumsstring durch Bedingungen der Form datumswert BETWEEN datumsstring_1 AND datumsstring_2
Beseitigung kartesischer Produkte (in der Praxis meistens gepaart mit anschließender Duplikat-Elimination via DISTINCT) Überprüfung der Existenz und Gültigkeit von Objektstatistiken Benutzung des ATO Um den Ablauf und die Arbeitsweise des ATO zu verstehen, ist es nützlich, einen Tuning-Vorgang einmal Schritt für Schritt zu verfolgen: Zunächst wird ein Tuning-Task erstellt. Dabei wird festgelegt, welches Statement bzw. welche Statements untersucht werden sollen; ggf. können Werte für Bindevariablen festgesetzt werden (Parameter sql_text und bind_list). Die Variable sql_text ist vom Typ CLOB, Probleme mit langen SQLKommandos gibt es daher nicht. unter welchem Schema das Statement ausgeführt wird (Parameter user_name). ob auch SQL-Profile erstellt werden sollen (SCOPE_COMPREHENSIVE) oder nicht (SCOPE_LIMITED). Da die Erstellung von SQL-Profilen Teilausführungen des/der SQL-Kommandos beinhaltet, die u.U. eine Weile dauern, kann in diesem Fall ein Zeitlimit für die gesamte Analyse festgelegt werden (Parameter time_limit, Angabe in Sekunden, Default-Wert ist eine halbe Stunde). Ohne SQL-Profile kann man von einer Laufzeit von etwa einer Sekunde pro SQL-Statement ausgehen. Für den Task wird ein Name vergeben (task_name; wenn nichts übergeben wird, wird ein systemgenerierter Name zurückgegeben), der in den folgenden Aufrufen als Handle für den Tuning-Task dient. SQL> DECLARE my_task_name VARCHAR2(30); my_sqltext CLOB; BEGIN my_sqltext := 'SELECT * FROM kunden k, auftraege a ' || 'WHERE k.kdnr = a.kdnr ' || 'AND k.nachname = :b1'; my_task_name := dbms_sqltune.create_tuning_task ( sql_text => my_sqltext ,bind_list => sql_binds(anydata.ConvertVarchar2('Seglitz')) ,user_name => 'schwanke' ,scope => DBMS_SQLTUNE.SCOPE_COMPREHENSIVE ,time_limit => 60 ,task_name => 'my_sql_tuning_task' ,description => 'Tuning-Auftraege eines Kunden'); END; /
Zugriffsoptimierung
653
Die Prozedur CREATE_TUNING_TASK ist mehrfach überladen. Soll z.B. ein SQL-Kommando aus dem Cursor-Cache verwendet werden, werden statt sql_text und bind_list die Parameter sql_id und plan_hash_value verwendet, welche die Werte der gleichnamigen Spalten aus V$SQL übernehmen. Über plan_hash_value werden unterschiedliche Ausführungspläne für dasselbe SQL-Kommandos auseinander gehalten (z.B. bei unterschiedlichen Schemata oder wenn der Optimizer aufgrund veränderter Objektstatistiken einen anderen Ausführungsplan bevorzugt). Analog können SQL-Statements verwendet werden, die in AWR-Reports auftauchen, dazu muss der Report-Zeitraum (begin_snapshot_id und end_snapshot_id) übergeben werden. Um mehrere SQL-Kommandos zu tunen, sind nicht entsprechend viele TuningTasks erforderlich, sondern die betreffenden Statements können in einer Kollektion, einem so genannten SQL Tuning Set (STS), zusammengefasst werden. Der Aufbau eines solchen SQL Tuning Sets auf der Basis von AWR-Workloads ist in Abschnitt 15.2.5 beschrieben. Bei der Erzeugung des Tuning-Tasks wird der Name des STS (Parameter sqlset_name) übergeben. Für weitere Parameter zum Filtern und Ranken der einzelnen Kommandos siehe die Dokumentation Oracle 10g PL/SQL Packages and Types Reference. Der so definierte Tuning-Task wird nun gestartet: SQL> BEGIN dbms_sqltune.execute_tuning_task ( task_name => 'my_sql_tuning_task' ); END; /
Bei lang laufenden Tuning-Tasks kann auch der Fortschritt des Tasks einfach überwacht werden: SQL> SELECT status FROM dba_advisor_log WHERE task_name = 'my_sql_tuning_task'; STATUS ----------COMPLETED SQL> SELECT sofar,totalwork,units,time_remaining, elapsed_seconds,message FROM v$session_longops WHERE opname = 'SQL Tune'; SOFAR TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS ------ ---------- --------------- -------------- --------------MESSAGE --------------------------------------------1 1 SQL Statements 0 2 SQL Tune: : 1 out of 1 SQL Statements done
654
Tuning
Ist die Bearbeitung abgeschlossen, kann ein Ergebnisreport abgefragt werden. Es bietet sich an, diesen per SPOOL-Kommando direkt in eine Datei zu leiten: SQL> SQL> SQL> SQL>
SET LONG 1000000 SET LINESIZE 100 SPOOL sqltune_report.txt SELECT dbms_sqltune.report_tuning_task ( 'my_sql_tuning_task','TEXT','TYPICAL','ALL') FROM DUAL; SQL> SPOOL OFF
Dieser Aufruf generiert den Bericht als Textdatei. Auch eine Ausgabe im HTMLoder XML-Format ist vorgesehen (TEXT | HTML | XML), im Release 10.1.0.3 aber noch nicht implementiert. Der Umfang der Ausführungspläne kann eingestellt werden (BASIC | TYPICAL | ALL), außerdem kann auf einzelne Berichtsabschnitte eingeschränkt werden (ALL | FINDINGS | PLANS | INFORMATION | ERRORS), z.B. liefert FINDINGS nur die Ergebnisse und Kommandos zur Umsetzung der Empfehlungen. Die oben benutzten Werte sind die Default-Werte. Die entsprechenden CREATE INDEX-Kommandos können direkt aus dem Report herauskopiert werden, sollten aber noch angepasst werden hinsichtlich sprechender Index-Namen, Tablespaces etc. In der Spalte Cost (%CPU) ist zu erkennen, dass sich die geschätzten Gesamtkosten von 238 auf vier Kosteneinheiten verringern. Entgegen der Spaltenüberschrift handelt es sich nicht um reine CPU-Kosten, sondern um I/O- plus CPU-Kosten. Weiter oben ist entsprechend die Einsparung mit 98,32% angegeben. Sind diese Maßnahmen umgesetzt, kann gleich ein weiterer Analyselauf angestoßen werden, um ggf. weiteres Tuning-Potenzial auszunutzen. Der Tuning-Task muss dazu nicht neu erstellt werden, lediglich die bisherigen Ergebnisse müssen gelöscht werden. SQL> BEGIN dbms_sqltune.reset_tuning_task ( task_name => 'my_sql_tuning_task' ); END; /
Anschließend geht es mit einem erneuten Aufruf von EXECUTE_TUNING_TASK weiter. Analog kann über die Prozeduren {INTERRUPT | RESUME | CANCEL}_TUNING_TASK eine lang laufende Analyse unterbrochen, wiederaufgenommen oder vollständig abgebrochen werden. Da die Tuning-Tasks persistent sind, also auch nach Beendigung der Session weiterexistieren, sollte man nach einer abgeschlossenen Analyse mittels DROP_TUNING_TASK aufräumen. Einziger Parameter ist jeweils task_name.
Zugriffsoptimierung
655
SQL-Profile In manchen Fällen empfiehlt der ATO die Erstellung eines so genannten SQL-Profils. Dabei handelt es sich um eine Art »Korrekturstatistik«, die speziell für das untersuchte SQL-Kommando hinterlegt wird, um dem Query-Optimizer genauere Kostenschätzungen zu ermöglichen. Die herkömmlichen Objektstatistiken, die der Query-Optimizer insbesondere zur Schätzung der Größe von Zwischenergebnissen benutzt, können aus verschiedenen Gründen zu systematischen Fehlschätzungen führen, beispielsweise: Der Query-Optimizer geht davon aus, dass es keine Datenkorrelationen zwischen unterschiedlichen, in der WHERE-Klausel eingeschränkten Spalten gibt. Bei einer Eingrenzung z.B. auf den Wohnort und das Geburtsdatum eines Kunden geht dies in den meisten Fällen gut, da die beiden Eigenschaften weitgehend unabhängig voneinander sein dürften. Bei einer Eingrenzung auf Wohnort und PLZ jedoch ist offensichtlich eine Abhängigkeit vorhanden. Natürlich kann man in diesem Fall argumentieren, dass die PLZ den Ort eindeutig determiniert und somit Letzterer einfach weggelassen werden kann. Ist das SQL-Kommando in einer Anwendung codiert, evtl. sogar dort dynamisch erzeugt, ist eine Anpassung aber nicht mehr so einfach. Außerdem müssen es nicht immer deterministische Zusammenhänge sein. Zum Beispiel ist bei einer Eingrenzung auf Wohnort und Beschäftigungsstatus nicht einer von Unabhängigkeit der beiden Attribute auszugehen, da Arbeitslosigkeitsraten offenbar regional differieren. Durch Spalten-Histogramme ist das Problem nicht lösbar, da diese lediglich eine »Innenansicht« einer Spalte bieten, aber keine Abhängigkeiten zu anderen Spalten aufdecken. Ein ähnliches Problem kann bei Joins auftreten, wenn beide betroffenen Tabellen eingeschränkt werden. Sucht man beispielsweise alle via Internet übermittelten Aufträge (Einschränkung auf der Aufträge-Tabelle) von über 60-jährigen Kunden (Einschränkung auf der Kundentabelle), so kann der Query-Optimizer die Größen der eingeschränkten Tabellen durch Benutzung von Histogrammen zwar korrekt schätzen. Wenn aber die über 60-jährigen Kunden verhältnismäßig selten per Internet bestellen, ist der Join der beiden Teilmengen sehr dünn besetzt. Dies kann der Optimizer aber nicht wissen. Die Ergebnismenge würde systematisch zu groß geschätzt. Für solche und ähnliche Probleme gab und gibt es weiterhin die Möglichkeit, Stored Outlines – wie bereits beschrieben – zu definieren, wodurch sämtliche Statistiken und Histogramme ignoriert werden und ein ganz bestimmter, vorher festgelegter Ausführungsplan erzwungen wird. Der Nachteil hierbei ist, dass Entwicklungen der Tabellengrößen oder Werteverteilungen vom Optimizer nicht mehr berücksichtigt werden, stattdessen müssen ggf. irgendwann die Stored Outlines manuell angepasst werden. Die mit Oracle 10g eingeführten SQL-Profile stellen in dieser Hinsicht einen Mittelweg dar. Im Gegensatz zu Stored Outlines werden für ein betroffenes SQL-Kommando nicht der komplette Ausführungsplan, sondern lediglich einige weitere Statistikinformationen speziell für dieses SQL-Kommando persistent hinterlegt. Diese stellen Korrekturfaktoren für die oben angesprochenen Situationen dar (so genannte Filter- und Join-Selek-
656
Tuning
tivitäten). Die herkömmlichen Objektstatistiken werden weiterhin benutzt, die SQLOptimierung ist daher flexibler als mit Stored Outlines. Beiden Verfahren ist aber gemein, dass sie SQL-Tuning von Anwendungs-SQL ohne Eingriffe in die Anwendung ermöglichen. Auch sollten beide Wege erst dann beschritten werden, wenn klar ist, dass die normalen Objektstatistiken nicht ausreichen. Dies ist insbesondere bei den Empfehlungen des ATO zu berücksichtigen, die manchmal neben anderen Vorschlägen auch die Erstellung eines SQL-Profiles beinhalten. In diesem Fall sollten – wenn möglich – zuerst die anderen Vorschläge umgesetzt werden, wie z.B. die Erstellung von Indizes, Materialized Views, die Aktualisierung von Objektstatistiken und Histogrammen etc.) und anschließend ein erneuter Analyselauf angestoßen werden. Häufig tauchen die SQL-Profile dann bereits nicht mehr im Analysebericht auf. Aus dem oben Gesagten ist klar, dass die Notwendigkeit eines SQL-Profils nur erkannt werden kann, indem die Größenschätzungen des Query-Optimizers mit den tatsächlichen Größen der Ergebnisse und Zwischenergebnisse verglichen werden. Das bedeutet, dass der ATO bei der Analyse die betreffende SQL-Abfrage konkret ausführt. Um Zeit zu sparen, wird bei großen Ergebnismengen mit Teilausführungen gearbeitet und die Ergebnisgröße hochgerechnet. Über die Parameter scope und time_limit wird eingestellt, ob dieser Vergleich durchgeführt werden soll, sowie ein Zeitlimit für die Ausführung gesetzt. Während der Analyse wird ggf. ein SQL-Profil vorbereitet. Im Analysebericht findet sich dann im Abschnitt Findings ein Hinweis sowie ein SQL*Plus-Kommando, um das SQL-Profil tatsächlich zu übernehmen.
Abbildung 11.9: Analysebericht mit SQL-Profil-Empfehlung
SQL-Profile können in Kategorien eingeordnet werden. Für produktive Sessions (beispielsweise einer Anwendung) kann nun über den Serverparameter sqltune_category gesteuert werden, ob und, wenn ja, welche SQL-Profile genutzt werden (dies ist analog zum Parameter use_stored_outlines bei Stored Outlines).
Zugriffsoptimierung
657
Die Standardkategorie heißt DEFAULT, kann aber über den Serverparameter sqltune_category geändert werden. Beim Aufruf von accept_sql_profile sollte zusätzlich über den Parameter category eine Zielkategorie für das neue Profil mitgegeben werden. Ansonsten landet es in der Kategorie DEFAULT, ist also für laufende Sessions unmittelbar aktiv. Besser ist es, zunächst eine Testkategorie zu benutzen. Also z.B.: SQL> DECLARE profile_name VARCHAR2(200); BEGIN profile_name := dbms_sqltune.accept_sql_profile( task_name => 'my_sql_tuning_task' ,name => 'my_sql_profile' ,category => 'TEST'); END; /
Anschließend kann der Effekt des SQL-Profils durchgetestet werden. Eine Testumgebung wird einfach durch Setzen der zu verwendenden Kategorie erzeugt: SQL> ALTER SESSION SET sqltune_category = TEST; SQL> -- Ausführen des SQL-Kommandos
Die Verknüpfung eines SQL-Befehls mit vorhandenen Profilen geschieht über den Text des SQL-Befehls. Dieser muss abgesehen von Whitespace (Leerzeichen, Tabulator, Return) und Groß- und Kleinschreibung (außer in Literalen) identisch sein. Zur Übernahme in den produktiven Betrieb wird einfach die Kategorie des Profils geändert. Ist der Profilname nicht bekannt, kann er über die Spalte name der View DBA_SQL_PROFILES herausgefunden werden. SQL> BEGIN dbms_sqltune.alter_sql_profile( 'my_sql_profile' ,'CATEGORY' ,'NEUE_KATEGORIE'); END; /
Sollten dennoch Probleme auftreten, ist ein vorübergehendes Deaktivieren des Profils möglich: SQL> BEGIN dbms_sqltune.alter_sql_profile( 'my_sql_profile' ,'STATUS' ,'DISABLED'); -- analog 'ENABLED' END; /
Über die Prozedur drop_sql_profile wird ein Profil gelöscht. Die beschriebenen Verwaltungsschritte für SQL-Profile erfordern die Systemprivilegien {CREATE | ALTER | DROP} ANY SQL PROFILE. In der für Tuning-Tasks benötigten DBARolle sind diese Privilegien aber ohnehin enthalten.
658
Tuning
Leider gibt es keine Möglichkeit, SQL-Profile von einer Test-Datenbank zu exportieren und direkt in ein Produktionssystem zu importieren (Stand: Release 10.1.0.3). Ein Verfahren analog zu Stored Outlines (Export und Import der zugrunde liegenden Tabellen im Data Dictionary) ist nicht möglich, da die betreffenden Tabellen zum Schema SYS gehören. Sollte dies mit einem späteren Release möglich werden, ist natürlich zu beachten, dass die Wirksamkeit eines SQL-Profils stark von den konkreten Daten abhängt, also nur dann Sinn macht, wenn die Testdaten eine repräsentativen Teilmenge der Produktionsdaten darstellen. Zusammenspiel mit anderen Funktionen Es wurde bereits beschrieben, wie SQL-Profile und Stored Outlines zueinander abgegrenzt werden. In der Praxis ist für ein konkretes SQL-Kommando abzuwägen, welche Methode bessere Ergebnisse liefert. Dadurch, dass Stored Outlines ebenfalls per Kategorie verwaltet und ein- oder ausgeschaltet werden können, ist eine große Flexibilität möglich. Liegen bei der Ausführung eines SQL-Befehls sowohl ein SQLProfil als auch ein Stored Outline vor, hat das Stored Outline Priorität. Im Rahmen von SQL-Tuning ist auch folgendes Vorgehen interessant, das letztlich zu einem Stored Outline führt: 1. Ein SQL-Profil für den betreffenden SQL-Befehl wird erstellt und übernommen. Dies führt zu einem optimierten Ausführungsplan. 2. Anschließend wird die SQL-Profil-Kategorie für die Session gesetzt, so dass das erzeugte Profil benutzt wird und ein Stored Outline erstellt. Dieses enthält dann den optimierten Ausführungsplan. Das SQL-Profil wird anschließend wieder gelöscht. Da die Effektivität eines SQL-Profils offenbar von konkreten Werteverteilungen in den Daten abhängt, sollte bei SQL-Kommandos mit Bindevariablen gut überlegt werden, ob es sinnvoll ist, ein Profil zu hinterlegen. Das Verhalten von SQL-Profilen in Zusammenhang mit dem Serverparameter cursor_sharing (automatische Ersetzung von Literalen durch Bindevariablen) ist nicht dokumentiert, eigene Tests zeigten aber, dass unabhängig von der Einstellung des Parameters weder bei der Erstellung eines Profils noch beim Verknüpfen eines SQL-Kommandos mit einem Profil Bindevariablen eingesetzt werden. SQL-Profile werden also immer für Kommandos mit konkreten Werten angelegt. Nur wenn der Benutzer explizit ein Kommando mit Bindevariablen an den ATO gibt, wird hiervon eine Ausnahme gemacht. Aus den erwähnten Gründen macht diese Regelung auch Sinn.
Ältere Features
11.5
659
Ältere Features
Einige Funktionen, die aus den vorherigen Datenbankversionen wohl bekannt und vertraut sind, wurden in die Oracle 10g-Datenbank nicht mehr mit aufgenommen oder werden nicht mehr unterstützt. Die wichtigsten sollen hier in Form einer Negativliste aufgelistet werden.
11.5.1 Regelbasierter Optimizer Der regelbasierte Optimizer ist noch in Oracle 10g enthalten, auch die OptimizerHints RULE und CHOOSE funktionieren weiterhin. Jedoch wird keine dieser Funktionen mehr unterstützt. Für evtl. auftretende Bugs oder Fragestellungen wird also kein Support geleistet. Betroffene Anwendungen sollten unbedingt auf kostenbasierte Optimierung umgestellt werden. Der kostenbasierte Optimizer wurde in »Query-Optimizer« umbenannt. Für eine »sanfte« Migration können zunächst Stored Outlines für kritische SQLKommandos der Anwendung erzeugt werden. Anschließend wird auf kostenbasierte Optimierung umgestellt. Durch Deaktivieren einzelner Stored Outlines kann dann schrittweise der kostenbasierte Optimizer auf die SQL-Kommandos »losgelassen« werden (siehe auch Abschnitt x.y).
11.5.2 Optimizer-Statistiken mittels ANALYZE Die Erzeugung von Optimizer-Statistiken sollte nicht mehr über das SQL-Kommando ANALYZE, sondern mit dem Package DBMS_STATS durchgeführt werden. Die »Kinderkrankheiten« des DBMS_STATS-Package aus den Oracle-Versionen 8i und 9i sind mittlerweile beseitigt. Das Package bietet gegenüber dem ANALYZE-Befehl – wie bereits beschrieben – zahlreiche Möglichkeiten wie bspw. Block-Sampling, Parallelisierung, Statistikhistorisierung etc.
11.5.3 Diverse Optimizer-Hints Folgende Optimizer-Hints funktionieren noch, sollten aber nicht mehr verwendet werden: AND_EQUAL, {HASH | MERGE | NL}_{SJ | AJ}, ROWID, STAR, EXPAND_GSET_TO_UNION, ORDERED_PREDICATES. Die Hints NOPARALLEL, NOPARALLEL_INDEX, and NOREWRITE wurden umbenannt (siehe Abschnitt Hints), die alten Schreibweisen funktionieren aber noch.
11.5.4 Oracle-Trace Das Tool Oracle-Trace wurde schon für Oracle9i nicht mehr empfohlen. In Oracle 10g existiert es nicht mehr. Tracing sollte mit SQL-Trace und tkprof durchgeführt werden (siehe Abschnitt Anwendungs-Tracing).
660
Tuning
11.5.5 Erweitertes SQL-Tracing Im Rahmen von SQL-Tracing können auch Informationen über aufgetretene Wartezustände und Werte von Bindevariablen in die Trace-Datei geschrieben werden. Dieses so genannte erweiterte Tracing musste bis einschließlich Oracle9i entweder durch Setzen des Diagnostic-Events 10046 (für die eigene Session), durch einen Aufruf des nicht dokumentierten Packages DBMS_SYSTEM (für beliebige Sessions) oder über das via Oracle Support erhältliche Package DBMS_SUPPORT (für beliebige Sessions) aktiviert werden. Mit Oracle 10g sollte stattdessen der Weg über das mitgelieferte und dokumentierte Pakkage DBMS_MONITOR gewählt werden. Dieses bietet auch weitere, neue Möglichkeiten (Stichwort anwendungs- und client-basiertes Tracing). Für Details hierzu siehe Abschnitt Anwendungs-Tracing.
Troubleshooting 12.1
Einführung
Oxford Advanced Learner’s Dictionary erklärt den Begriff Troubleshooting lapidar mit »solving problems in a company or an organization«. Im Kontext eines OracleDatenbanksystems würde demnach zum Troubleshooting das Erkennen und Lösen jeglicher Probleme gehören: Schlechte Performance würde ebenso in diese Kategorie fallen wie logische Programm- oder ausgewiesene ORA-Fehler. Die Bereiche Tuning, Troubleshooting und Monitoring wären vor diesem Hintergrund nur schwer auseinander zu halten. In diesem Kapitel jedoch wollen wir von einer dermaßen globalen Sicht des Begriffes Abstand nehmen und Troubleshooting im engeren Sinne als die Analyse von und unmittelbare Reaktion auf ungeplante Fehler- oder Ausnahmesituationen der Datenbank und ihres Umfeldes verstehen. Hierzu können beispielsweise ORA-00600er-Fehler, Blockkorruptionen oder Blockaden von Ressourcen (Hang) gehören. Letztere lösen bekanntlich selbst keine expliziten Fehler aus. Trotz dieser begrifflichen Trennung sind die drei oben genannten Bereiche nach wie vor sehr eng miteinander verbunden: Vorausschauendes Tuning – schon während der Entwicklungszeit – minimiert den Bedarf an Troubleshooting, sorgfältiges Monitoring beschleunigt die Fehleranalyse und erhöht damit die Chancen der Fehlerbehebung. Die gründliche Systemanalyse kann wiederum nachfolgende TuningMaßnahmen auslösen.
12.2
Informationsquellen und Anwendungskontext
Um eine effiziente Analyse und nachhaltige Behebung von Ausnahmesituationen zu gewährleisten, sind einige wichtige Voraussetzungen zu erfüllen: Zunächst sind alle verfügbaren Informationen zur Eingrenzung und Beschreibung der Fehlersituation auszuwerten. Im Falle eines expliziten Fehlers existieren häufig Trace- und Log-Dateien, die wertvolle Zusatzinformationen zu Meldungen liefern, die den betroffenen Anwendern über die Bedienoberflächen ausgegeben werden. Eine schnelle und unkomplizierte Navigation zu diesen relevanten Dateien und deren Auswertung ist hierbei unerlässlich. Häufig verzögert die »manuelle« Navigation über cd-, ls- und vi-Kommandos die Analyse. Darüber hinaus sorgen fehlende Konventionen im Umgang mit den Trace- und Log-Dateien dafür, dass der betroffene DBA sich durch einen Berg alter und für das Problem nicht relevanter Log-Einträge wühlen muss. Ein gutes Beispiel gibt hier die Oberfläche des neuen Enterprise Manager 10g – Database Control –, über die kritische Fehler1 des Alert-Logs, aber auch der aktuelle Inhalt dieser 1
Welche Fehler als kritisch zu betrachten sind, lässt sich konfigurieren. Die Navigation zu den Alert-Fehlern führt über STANDARDVERZEICHNIS – DIAGNOSEZUSAMMENFASSUNG – ALERT LOG.
662
Troubleshooting
Datei2 im Browser angezeigt werden können. Eine Ausweitung dieses Konzepts auf sämtliche verfügbaren Trace- und Log-Dateien auch im Kontext von Oracle Net Services und Application Server ist dringend anzuraten.
Abbildung 12.1: Enterprise Manager Alert Log-Fehler
In manchen Ausnahmesituationen – wie etwa bei Hangs und Loops – werden keine Fehlermeldungen ausgegeben. Hier ist es wichtig, vorhandene Statistiken, Metriken, Alerts oder Wait-Events zu konsultieren, um zusätzliche Details des betreffenden Problems zu erhalten. Hierbei helfen eine Reihe von Views des Data Dictionarys sowie diverse V$-Tabellen, wie sie im Abschnitt Werkzeuge und Fehlersituationen näher beschrieben werden. Ein weiteres Mittel der Wahl zur Präzisierung der Fehlerbeschreibung ist die Generierung von Block-Dumps oder das Setzen von Events, um z. B. Prozesskontexte beim Auftreten vorgegebener Fehler herauszuschreiben. Sind der Fehler und sein Kontext einmal umfassend analysiert worden, müssen geeignete Maßnahmen zu seiner Behebung geplant und umgesetzt werden. Auch in diesem Zusammenhang gibt es Rahmenbedingungen, die entscheidend zum Erfolg der Maßnahmen beitragen: Eine genaue Kenntnis der Oracle-Serverkomponenten und ihrer Interaktion ist hierfür ebenso unerlässlich wie grundlegende Kenntnisse über die verursachende Anwendung. Während die erste Voraussetzung in aller Regel von Datenbankadministratoren zufrieden stellend erfüllt wird, stellt die Kenntnis des Umfeldes der verursachenden Anwendung in vielen Fällen ein großes Problem dar, das mit der steigenden Zahl datenbankgestützter Anwendun2
Es werden die letzten 100.000 Bytes der Datei angezeigt. Navigation über ALERT-LOG.
ZUGEHÖRIGE
LINKS – INHALT
VON
Informationsquellen und Anwendungskontext
663
gen stetig an Bedeutung gewinnt. Auch die diversen Werkzeuge, die in der Hand der Administratoren gute Arbeit leisten, können diese übergeordneten Anwendungsinformationen nicht in dem geforderten Umfang verwalten. Um es kurz zu machen: Ohne detaillierte Kenntnis der Anwendung wie auch der Datenbank ist eine effiziente Fehlerbehebung in der Regel nicht oder nur unzureichend möglich. Einige wenige Beispiele aus der Praxis sollen dies verdeutlichen: 1. Mangelnde Kenntnis der Komponenten der Datenbank: Im Laufe weniger Stunden werden sämtliche Rollback-Segmente von lang laufenden Transaktionen blockiert. Als Folge hiervon wächst die Zahl ihrer Extents und mit der Zahl der Extents der Speicherplatz in den betreffenden Tablespaces. In letzter Konsequenz ist der Speicherplatz im zugehörigen Dateisystem erschöpft, eine erneute Erweiterung der Segmente schlägt fehl, die Datenbank »hängt«. Die Vermutung, dass umfangreiche Transaktionen die Segmente aufgebläht haben, bestätigt sich nicht, da die Entwickler nach DML-Befehlen konsequent Commit-Operationen implementiert haben. Vielmehr zeigt sich, dass Select-Anweisungen, die über Database-Links operieren, Transaktionseinträge in den Rollback-Segmenten generieren, ohne dass im Coding die betreffenden Transaktionen explizit beendet werden. Folgt diesen Select-Anweisungen aufgrund der Benutzerinteraktion keine weitere DML-Anweisung, kommt es zur beschriebenen Blockade. Mit der großen Zahl der Anwender wächst die Wahrscheinlichkeit, dass früher oder später alle verfügbaren Rollback-Segmente betroffen sind. Durch die genaue Kenntnis der verursachenden Module kann in kürzester Zeit die fehlende Transaktionssteuerung implementiert und dadurch die Fehlerquelle behoben werden. 2. Mangelnde Sorgfalt: Nächtliche Datenbank-Jobs schlagen fehl. Die betreffende Log-Datei zeigt Ora-00600er-Fehler, die auf korrupte Strukturen im Bereich von Buffern hinweisen, die Index- und Header-Blöcke speichern3. Die Validierung der angemahnten Bereiche mittels ANALYZE und DBMS_REPAIR meldet jedoch keine korrupten Blöcke. Nach einem Neustart der Datenbank ist die betroffene Tabelle fehlerfrei les- und schreibbar. Gleichwohl lässt sich das Problem immer dann reproduzieren, wenn die betroffene Tabelle durch parallel laufende, umfangreiche Insert-Operationen bearbeitet wird. Bei der Prüfung der Tabellendefinition zeigt sich, dass – im Rahmen einer Reorganisation – nur eine Freiliste statt der geplanten fünf angelegt wurde. Die Erweiterung der Anzahl der Freilisten beseitigt das Problem. 3. Mangelnde Kenntnis des Anwendungskontexts: Benutzerdialoge wie auch Batch-Jobs werden fehlerhaft abgebrochen. Die Analyse zeigt, dass die Fehler im Rahmen von TO_CHAR-Operationen auf date-Feldern auftreten. Die betreffenden Blöcke werden »gedumpt«. Bei der Auswertung werden 0-Werte in den Uhrzeitbereichen der date-Felder – Stunde, Minute, Sekunde – ausgemacht. Dies ist abnormal, da Zeitangaben zur Vermeidung von 0-Werten normalerweise um 1 erhöht werden, 0:00:00 also als »111« abgespeichert wird. Zur Analyse des Fehlers wäre es wichtig gewesen festzustellen, welches Modul (Programmiersprache) über welche Netzverbindung die Daten in die betreffende Tabelle einfügt. Da dies nicht zu ermitteln war, konnte die genaue Fehlerursache nicht festgestellt werden. 3
Argument (12207)
664
Troubleshooting
Die vorangehenden Abschnitte sollen jedoch nicht missverstanden werden: Keinesfalls kann der DBA detaillierte Kenntnisse aller Anwendungen haben, die seine Datenbanken als Speicherort nutzen. Einige grundlegende Informationen sind jedoch für eine erfolgreiche Fehlerbehebung unerlässlich und sollten sorgfältig gepflegt werden. Zu diesen Grundlagen gehören für jede Anwendung auf jeden Fall folgende Angaben: Namen und Kontaktinformationen von verantwortlichen Ansprechpartnern (Entwicklern/Firmen) Welche Datenbank/welches Schema werden zur Datenhaltung benutzt? Welche Programmiersprachen kommen zum Einsatz? Welche Features der Datenbank benötigt die Anwendung? (z.B. Partitionierung, Queuing, Virtual Private Database etc.) Wie wird authentifiziert und autorisiert? Für welche Datenbankversion ist die Anwendung freigegeben? Welche Abhängigkeiten existieren: zu anderen Datenbanken/Anwendungen/ Schemata? (z.B. durch Replikation oder Datenübernahmen) Welche Anforderungen werden an die Verfügbarkeit gestellt? Schreibt die Anwendung außerhalb der Datenbank eigene Log- und TraceDateien? Wenn ja: in welche Verzeichnisse? Werden innerhalb der Datenbank Log-Tabellen gefüllt? Wie viele Benutzer arbeiten mit der Anwendung? Diese Informationen lassen sich naturgemäß nicht vollständig über herkömmliche DBA-Werkzeuge verwalten, sollten aber trotzdem zentral verfügbar und leicht – z.B. über Browser – abrufbar sein. Der Aufbau eines entsprechenden »Application Repositorys« stellt keine großen technischen Anforderungen und kann in kurzer Zeit selbst mit einfachen Mitteln realisiert werden. In diesem Zusammenhang bietet sich beispielsweise die HTML-DB-Technik von Oracle 10g an. Die nötigen Angaben können dann von den Verantwortlichen per »Self Service« aktuell gehalten werden. Das »Gespür« bei der Analyse und Behebung von Ausnahmefällen reduziert sich vor diesem Hintergrund auf die folgenden Bereiche: Die gute Kenntnis der Architektur und Interaktion von Oracle-Serverkomponenten Die systematische Nutzung der verfügbaren Werkzeuge und Informationsquellen anhand von gemeinsam erarbeiteten Konventionen Die gute Kommunikation mit den betroffenen Personen Bei alledem sollte niemals vergessen werden: Troubleshooting ist in den allermeisten Fällen Teamarbeit für Entwickler, Anwender und Administratoren!
Die Strategien
12.3
665
Die Strategien
Die kurzen Beispiele des vorangehenden Abschnitts haben gezeigt, wie unterschiedlich Lösungsansätze für die Behebung von Ausnahmeproblemen ausfallen können. Trotz dieser Vielfalt lassen sich einige allgemein gültige Strategien formulieren, die eine strukturierte Analyse und Behebung von Fehlersituationen ermöglichen sollen. Die im Folgenden beschriebene Vorgehensweise hat sich in der Praxis durchaus bewährt: 1. Problemkontext ermitteln Zur Problemanalyse ist es in der Regel nicht ausreichend, den an der Oberfläche angezeigten Fehler – wenn denn überhaupt eine Meldung ausgegeben wird – zur Analyse heranzuziehen. Die ausgegebene Meldung sollte auf jeden Fall durch die Sichtung verfügbarer Log- und Trace-Dateien ergänzt werden. Darüber hinaus ist nach Möglichkeit der exakte Anwendungskontext zu ermitteln: Welche Anwendung verursacht bei welcher Aktion und mit welchen Ein- bzw. Ausgabedaten den betreffenden Fehler? An welchen Tagen und zu welchen Uhrzeiten taucht das Problem auf? Welche Programme sind zu dieser Zeit ebenfalls auf dem Rechner bzw. in der Datenbank aktiv? Zeigen die Log-Dateien Spuren vergleichbarer Fehlersituationen in der Vergangenheit? 2. Problem reproduzieren Zur Verifizierung des Fehlerkontextes ist es unerlässlich, den Fehler reproduzieren zu können. Dabei sind vor allem die im vorangehenden Abschnitt erwähnten zeitlichen und inhaltlichen Aspekte zu berücksichtigen. Wenn eben möglich, sollte die Reproduktion im originalen Kontext, d.h. im ursprünglichen Umfeld, versucht werden. Nur in Ausnahmefällen ist ein Testsystem heranzuziehen. Die Reproduzierbarkeit eines Fehlers bestätigt in der Regel die korrekte Bestimmung des betreffenden Kontextes. 3. Bug-Database einschalten Bevor wir uns an eine – möglicherweise zeitraubende – Analyse begeben, sollten auf jeden Fall die Oracle Bug-Database bzw. das Metalink4 konsultiert und die erzielten Treffer ausgewertet werden. Ist das Problem bekannt, existieren in der Regel erprobte Lösungsstrategien, deren Anwendung uns wertvolle Zeit sparen hilft. 4. Analyse: exakte Fokussierung Für den Fall, dass Probleme nicht auf Bugs zurückzuführen sind und daher möglicherweise keine Lösungsstrategien vorliegen, sind wir selbst in der Pflicht, eine exakte Analyse der Ursachen durchzuführen. Die Informationsquellen, die in diesem Zusammenhang genutzt werden können, wurden im vorangehenden Abschnitt einführend vorgestellt und werden in den folgenden Abschnitten im Detail besprochen. Bei der Nutzung dieser Quellen ist generell darauf zu achten, sich so präzise wie möglich auf das Problem zu fokussieren. Dies kann im Einzelnen bedeuten: 4
Die URL lautet http://metalink.oracle.com. Die Benutzung erfordert eine Registrierung.
666
Troubleshooting
Kennzahlen und Wait Events für die betreffende Session und nicht für die gesamte Instanz zu generieren. Systemstate Dumps, die Detailinformationen von allen in der Instanz aktiven Prozessen liefern, lassen sich nur schwer interpretieren, weil sie in der Regel zu umfangreich sind. Viel übersichtlicher sind Processstate Dumps für die betroffenen Serverprozesse. Kennzahlen zunächst durch relativ grobe Polling-Verfahren – z.B. durch Abfragen von v$session_wait im Abstand von wenigen Sekunden – zu ermitteln und erst bei Bedarf aufwändigere Trace-Verfahren – z.B. SQL_TRACE oder den Event 10046 – einzusetzen. 5. Ursachenbehebung oder Umgehungslösung? Probleme lassen sich nicht immer durch die Behebung der direkten Ursachen aus der Welt schaffen. In dem Kräftedreieck aus Fehleranalyse, verfügbarer Zeit und der Präsentation eines brauchbaren Lösungsansatzes ist in manchen Fällen auch das Bauchgefühl des Analysten gefordert: Wie viel Zeit investiere ich in die Aufdeckung einer komplexen Fehlerursache, und ab wann entschärfe ich das Problem durch eine geeignete Umgehungslösung? Die einzige generelle Empfehlung, die in diesem Punkt gegeben werden kann, ist, in dem Eifer der Analyse die grundlegende Option einer Umgehungslösung nicht aus den Augen zu verlieren.
12.4
Werkzeuge und Fehlersituationen
Die im Abschnitt Informationsquellen und Anwendungskontext erwähnten Werkzeuge zur Fehleranalyse werden in den folgenden Abschnitten im Detail besprochen. Für alle hier diskutierten technischen Details gilt gleichermaßen, dass sie ihren Nutzen erst dann voll entfalten können, wenn sie in konkrete Konventionen für ihre Nutzung bzw. Anwendung eingebettet werden. Im Rahmen dieser Konventionen müssen beispielsweise folgende Fragen verbindlich, einheitlich und übersichtlich für bestimmte Datenbankumgebungen geregelt werden: Welche Verzeichnisstrukturen gelten für Log- und Trace-Dateien? Wie werden diese Dateien archiviert, wie lange und über welche Werkzeuge sind sie online verfügbar? Welche Programmierkonventionen sind zu befolgen, um die Fehleranalyse zu vereinfachen? In welcher Form werden geltende Regelungen und Konventionen dokumentiert? Wer ist dafür verantwortlich? Die getroffenen Vereinbarungen müssen so eingängig, kurz und übersichtlich sein, dass sie von den Betroffenen auch in Stresssituationen zuverlässig angewandt werden können!
Werkzeuge und Fehlersituationen
667
12.4.1 Log- und Trace-Dateien RDBMS Im Bereich des Datenbankkerns existieren zwei Arten von Dateien, die laufende Operationen und in ihrem Kontext auftretende Fehlermeldungen protokollieren: Die eigentlichen Trace-Dateien enthalten Fehlermeldungen und Kontextinformationen von Server- und Hintergrundprozessen. Sie werden für jede Art von Prozess im Falle von internen Fehlern oder – nur für Hintergrundprozesse – bei Beendigung des Prozesses geschrieben. Die so genannte Alert-Datei wird für jede Instanz geschrieben und enthält chronologische Meldungen zu administrativen Aktionen der Datenbank – wie z. B. den Start der Instanz – sowie konsolidierte Informationen zu internen Fehlermeldungen, die auf die betreffenden Trace-Dateien verweisen. Aus diesem Grunde dient die Alert-Datei im Fehlerfall häufig als »Einstiegspunkt« für die Analysen. In die Gruppe der oben genannten internen Fehler fallen im Wesentlichen drei Fehlerkategorien: ORA-00600er-Fehler werden immer dann ausgegeben, wenn Fehlerbedingungen im Kernel-Code ausgelöst werden, die nicht explizit spezifizierbar sind. Sie entsprechen – im übertragenen Sinn – der when others-Bedingung im Kontext von PL/SQL-Exceptions. Die genauen Fehlerkontexte von 600er-Fehlern werden in den nachfolgenden, geklammerten Argumenten mitgeliefert, die für eine genaue Analyse unerlässlich sind: ORA-00600: internal error code, arguments: [kdddgb2], [435816], [2753588], [],[], [], [], []
ORA-07445er-Fehler signalisieren eine Ausnahmebedingung (Fatal Signal) des betreffenden Betriebssystems, die z. B. durch das Schreiben an eine illegale Speicheradresse verursacht wird. Auch hier existieren zusätzliche Argumente, die auf den genauen Kontext verweisen, wie das folgende Beispiel zeigt: ORA-7445: exception encountered: core dump [10] [2122262800] [261978112] [] [] []
ORA-00060er-Fehler verweisen auf Deadlock-Situationen. Die betreffenden Trace-Dateien enthalten neben der eigentlichen Fehlermeldung weiterführende Kontextinformationen, wie z.B. einen Deadlock-Graphen, der eine tabellarische Übersicht über die auslösenden Sessions liefert. Zusätzlich zu diesen Log- und Trace-Dateien werden bisweilen CORE Dumps erzeugt, die das Speicherabbild eines Prozesses zum Zeitpunkt seines Absturzes enthalten. CORE Dumps werden beispielsweise durch den Zugriff auf unerlaubte Speicherbereiche generiert. In der Regel existieren in solchen Fällen zusätzliche Trace-Dateien, welche die Analyse vereinfachen, weil sie den übergeordneten ORA07445-Fehler, einen Call Stack Trace sowie weitere Kontextinformationen der betroffenen Sessions enthalten.
668
Troubleshooting
Für die Konfiguration des Log- und Trace-Apparates von Oracle-Datenbanken steht eine Reihe von Serverparametern zu Verfügung: background_dump_dest legt das Verzeichnis für die Trace-Dateien der Hintergrundprozesse sowie der Alert-Datei fest. Der Parameter kann dynamisch im Rahmen der Instanz geändert werden. user_dump_dest legt das Verzeichnis für die Serverprozesse von Sessions fest. Auch dieser Parameter kann dynamisch für die Instanz geändert werden. core_dump_dest konfiguriert das Verzeichnis für CORE-Dumps. Auch dieser Parameter ist dynamisch. Über zwei weitere Parameter – background_core_dump und shadow_core_dump – lässt sich einstellen, ob die SGA in den Dump integriert wird (full) oder nicht (partial). Der Standardwert partial ist in den meisten Fällen zur Vermeidung von übergroßen Dump-Dateien zu bevorzugen. Die maximale Größe von Trace-Dateien – mit Ausnahme der Alert-Datei (!) – wird über max_dump_file_size eingestellt. Der Parameter kann sowohl im Kontext der Sessions als auch der Instanz dynamisch verändert werden und akzeptiert neben ganzzahligen Angaben in Betriebssystemblöcken auch Angaben in Megabyte und Kilobyte bzw. das Schlüsselwort unlimited5. Wurde die eingestellte Maximalgröße überschritten, erscheint eine entsprechende Meldung am Ende der betreffenden Datei, z.B. *** DUMP FILE SIZE IS LIMITED TO 50000 BYTES ***. Bei umfangreichen Analysen ist es auf jeden Fall wichtig, dass vollständige Trace-Informationen vorliegen, um formatierte Ergebnisse – z.B. von TKPROF – nicht zu verfälschen. Bei Trace-Dateien, die für Archivierprozesse geschrieben werden, lässt sich über den Parameter log_archive_trace festlegen, welche Trace-Informationen zusätzlich zu den oben genannten Fehlermeldungen geschrieben werden sollen. Die Angaben erfolgen über Ganzzahlen. Die Voreinstellung ist 0 (kein zusätzliches Tracing); der Wert 2 beispielsweise schreibt Statusinformationen für jedes Ziel (Archive Destination). Der Parameter ist vor allem für Standby- bzw. Data-GuardUmgebungen interessant. Das Namensformat von Trace-Dateien ist nicht beeinflussbar und richtet sich nach der Art des schreibenden Prozesses. Dateinamen von Hintergrundprozessen bestehen aus den Bestandteilen <sid>__.trc, also beispielsweise t10g_lgwr_ 15351.trc für die Trace-Datei des Logwriter-Prozesses der Instanz t10g mit der Prozessidentifizierung 15351. Serverprozesse schreiben unter dem Namen <sid>_ora_ .trc, beispielsweise t10g_ora_1244.trc für den dedizierten Serverprozess mit der Prozessnummer 1244, der für die Instanz t10g arbeitet. Namen von AlertDateien werden nach dem Muster alert_<sid>.log gebildet, wie z.B. alert_T10G.log. Da Trace-Dateien von Prozessen abhängig sind, Sessions aber – im Falle von Shared-Servern oder parallelen Query-Servern – mehr als einen Serverprozess nutzen können, kann es vorkommen, dass Fehlerprotokolle von Sessions über mehrere Dateien verteilt werden. In solchen Fällen kann es hilfreich sein, Trace-Dateien mit eindeutigen Kennzeichnern über den Parameter tracefile_identifier zu markieren, um die Suche nach den Trace-Informationen zu erleichtern: 5
MAX_DUMP_FILE_SIZE = {integer [K | M] | UNLIMITED}
Werkzeuge und Fehlersituationen
669
ALTER SESSION SET tracefile_identifier = 'GU03';
Trace-Dateien, die für Serverprozesse nach Eingabe dieses Kommandos angelegt werden, haben beispielsweise folgendes Namensformat: <sid>_ora__GU03.trc. Inhaltlich lassen sich die Trace-Dateien in die folgenden Bereiche gliedern Allgemeine Informationen (Header) über Softwarestände sowie den auslösenden Hintergrund- oder Serverprozess: /app/oracle/admin/T10G/udump/t10g_ora_11835_GU03.trc /app/oracle/admin/T10G/udump/t10g_ora_2417.trc Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 – Production With the Partitioning, OLAP and Data Mining options ORACLE_HOME = /app/oracle/product/10.1.0 System name: Linux Node name: NandaDevi Release: 2.4.21-243-default Version: #1 Thu Aug 12 15:22:14 UTC 2004 Machine: i686 Instance name: T10G Redo thread mounted by this instance: 1 Oracle process number: 18 Unix process pid: 2417, image: oracleT10G@NandaDevi Listing 12.1: Header-Teil einer Oracle Trace-Datei
Nach dem allgemeinen Teil wird der genaue Session-Kontext mit Zeitstempeln ausgegeben. Er besteht aus der Session-ID, dem Servicenamen sowie den Modulund Actionnamen, die möglicherweise von der betreffenden Session eingestellt wurden6. Es ist durchaus möglich, dass eine Trace-Datei Informationen zu mehreren Sessions enthalten kann, wie übrigens auch eine Session sich über mehrere Trace-Dateien erstrecken kann. *** *** *** *** ***
2004-10-28 16:27:18.895 ACTION NAME:() 2004-10-28 16:27:18.894 MODULE NAME:(SQL*Plus) 2004-10-28 16:27:18.894 SERVICE NAME:(T10G.NandaDevi.de) 2004-10-28 16:27:18.894 SESSION ID:(42.13) 2004-10-28 16:27:18.894
Listing 12.2: Session-Kontext einer Oracle Trace-Datei
Unmittelbar im Anschluss an den Session-Kontext finden sich die Kerndaten der Datei, die je nach der Art des Fehlers von Inhalt und Format her variieren können. Das folgende Beispiel zeigt eine Trace-Datei, die für einen Deadlock geschrieben wurde. Leicht lassen sich die beteiligten SQL-Befehle in den Zeilen 3 und 27 lokalisieren. Der Ressourcenname besteht aus einem Kürzel – hier TX für Transaction-Lock – und zwei weiteren, identifizierenden Ganzzahlen. Im Falle von TX-Locks beschreibt die erste Zahlenreihe – 00050029 in Zeile 11 – die Nummer des zugeordneten Rollback-Segments (5) und die Indexnummer (Slot) des Transaktionseintrages im Header-Block dieses Rollback-Segmentes (29). Die zweite Zahlenreihe – 0000007a – gibt die Versionsnummer des betreffenden 6
Die Einstellung kann über das Paket DBMS_APPLICATION_INFO erfolgen.
670
Troubleshooting
Slots an (7a). Jede Transaktion lässt sich demnach eindeutig über das Rollbacksegment, die Slot-Nummer und die Versionsnummer des Slots identifizieren. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
DEADLOCK DETECTED Current SQL statement for this session: update test set datum = sysdate where id=1 The following deadlock is not an ORACLE error. It is a deadlock due to user error in the design of an application or from issuing incorrect ad-hoc SQL. The following information may aid in determining the deadlock: Deadlock graph: ---------Blocker(s)-------- ---------Waiter(s)--------Resource Name process session holds waits process session holds waits TX-00050029-0000007a 18 42 X 17 45 X TX-00040028-000006b1 17 45 X 18 42 X session 42: DID 0001-0012-00000002 session 45: DID 0001-0011-00000002 session 45: DID 0001-0011-00000002 session 42: DID 0001-0012-00000002 Rows waited on: Session 45: obj - rowid = 0000B45E – AAALReAAEAAAAAQAAB (dictionary objn - 46174, file - 4, block - 16, slot - 1) Session 42: obj - rowid = 0000B45E – AAALReAAEAAAAAQAAA (dictionary objn - 46174, file - 4, block - 16, slot - 0) Information on the OTHER waiting sessions: Session 45: pid=17 serial=2 audsid=4410 user: 49/SCOTT O/S info: user: oracle, term: pts/2, ospid: 2413, machine: NandaDevi program: sqlplus@NandaDevi (TNS V1-V3) application name: SQL*Plus, hash value=3669949024 Current SQL Statement: update test set datum = sysdate where id=2 End of information on OTHER waiting sessions.
Listing 12.3: Kerndaten einer Trace-Datei nach einem Deadlock
Alert-Dateien haben ein eigenes Präsentationsformat, das im Wesentlichen aus den folgenden Bereichen besteht: Start- und Stopp-Informationen der Instanz und der Datenbank. In diesem Abschnitt werden auch die nicht standardmäßig eingestellten Systemparameter aufgelistet und Details zum Start der aktivierten Hintergrundprozesse gegeben. Im Anschluss an die Startinformationen werden fortlaufend Ereignisse und Fehler aufgelistet, die relevant für die gesamte Instanz und Datenbank sind. Zu den relevanten Ereignissen gehören beispielsweise das Anlegen von Tablespaces, das Setzen von Events oder der Wechsel von Redo-Log-Dateien. Fehlerhafte Datenbank-Jobs, ORA-00600- oder ORA-07445-Fehler werden ebenfalls vermerkt, dagegen keine »Benutzerfehler« wie z.B. ORA-00942 (Tabelle oder View nicht vorhanden). Sämtliche Angaben erfolgen mit den entsprechenden Zeitangaben. Im Falle von Fehlern wird – wo vorhanden – auch ein Verweis auf die zugeordnete Trace-Datei gegeben.
Werkzeuge und Fehlersituationen
671
Für jede Instanz wird immer genau eine Alert-Datei geschrieben, die beim Starten entweder fortgeschrieben oder – falls nicht vorhanden – neu angelegt wird. Der nachfolgende Abschnitt zeigt einen Ausschnitt aus einer Alert-Datei. Nach einem fehlerbedingten shutdown abort wurde in diesem Beispiel die Datenbank über das Kommando startup neu gestartet. Wie nicht anders zu erwarten, zeigt die AlertDatei die Details des Instance Recovery: Zunächst werden die Online-Redo-LogDateien gelesen und die für die Recovery-Aktion nötigen Redo- und die über sie referenzierten Datenblöcke ermittelt (Zeilen 03 bis 07). Der genaue Startpunkt des Recoverys wird in Form der Redo-Block-Adressen und SCN-Nummern (Zeilen 09– 12 und 17) angegeben. Die notwendigen Redo-Log-Dateien werden im Zuge der Aktion ausgegeben, und schließlich wird eine Zusammenfassung der behandelten und applizierten Blöcke angezeigt (Zeile 18). 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
Beginning crash recovery of 1 threads Wed Jan 19 23:53:57 2005 Started redo scan Wed Jan 19 23:53:57 2005 Completed redo scan 340 redo blocks read, 85 data blocks need recovery Wed Jan 19 23:53:57 2005 Started redo application at Thread 1: logseq 499, block 1998, scn 0.0 Wed Jan 19 23:53:57 2005 Recovery of Online Redo Log: Thread 1 Group 1 Seq 499 Reading mem 0 Mem# 0 errs 0: /usr/oradata/T10G/T10G/redo01.log Wed Jan 19 23:53:57 2005 Completed redo application Wed Jan 19 23:53:57 2005 Completed crash recovery at Thread 1: logseq 499, block 2338, scn 0.1456746 85 data blocks read, 85 data blocks written, 340 redo blocks read Wed Jan 19 23:53:57 2005
Listing 12.4: Ausschnitt aus einer Alert-Datei
Beim Auftreten von Fehlern werden in einigen Fällen zu den Fehlermeldungen auch Verweise auf zusätzliche Trace-Dateien angegeben, wie das folgende Beispiel zeigt: Tue Mar 25 13:59:07 2003 Errors in file /u01/app/oracle/product/8.1.7/rdbms/log/ora_27558.trc: ORA-12012: Fehler beim autom Ausführen von Job 41 ORA-20001: PACK_TR_CAL Kontext Nr. 27 Listing 12.5: Verweise aus einer Alert-Datei
672
Troubleshooting
Oracle NET Services Fehler, die im Kontext von Oracle Net Services auftreten, werden standardmäßig in entsprechende Log-Dateien geschrieben. Die unterschiedlichen NET-Komponenten wie Listener, Connection Manager und der NET-Client auf der Client bzw. Server-Seite unterhalten jeweils eigene Log-Dateien, die individuell konfiguriert werden können. Darüber hinaus besteht die Möglichkeit, weitergehende Informationen in TraceDateien zu protokollieren. Auch in diesem Umfeld lassen sich die einzelnen NETKomponenten eigenständig konfigurieren. Vier unterschiedliche Trace-Level – off, user, admin und support – steuern dabei den Detaillierungsgrad. Zur Konfiguration der Log-Dateien steht eine Reihe von Parametern zu Verfügung, die in den unterschiedlichen Konfigurationsdateien eingestellt werden können. Die folgende Tabelle gibt hierzu einen kurzen Überblick Komponente
Konfiguration sdatei
Parameter
Bedeutung
Listener
listener.ora
LOGGING_<listener>
Schaltet Logging ein (on) oder aus (off).
LOG_DIRECTORY_<listener>
Gibt Verzeichnis und Name der Log-Datei an.
LOG_FILE_<listener>
ist durch den Namen des Listeners zu ersetzen.
Client/Datenbank
sqlnet.ora
LOG_DIRECTORY_CLIENT LOG_FILE_CLIENT LOG_DIRECTORY_SERVER LOG_FILE_SERVER
Die Parameter stellen sowohl die Verzeichnisse als auch die Namen der LogDateien ein.
Connection Manager
cman.ora
EVENT_GROUP LOG_DIRECTORY LOG_LEVEL
- Gibt ein oder mehrere Events an, die geloggt werden sollen, z.B. conn_hdlg (Connection Handling) oder init_and_term (Initialization and Termination). Die beiden restlichen Parameter legen das Verzeichnis und den Detaillierungsgrad (off, user, admin, support) der Einträge fest.
Tabelle 12.1: Log Parameter
Werkzeuge und Fehlersituationen
673
Die Protokollierung der Fehler in den Log-Dateien von Oracle Net Services orientiert sich an den Schichten der NET-Architektur. Das folgende Beispiel zeigt einen Ausschnitt aus einer Log-Datei auf Seiten des Clients. Die Zeilennummern sind nicht Bestandteil der originalen Datei. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17
*********************************************************************** Fatal NI connect error 12541, connecting to: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.55.22)(PORT=1522)) (CONNECT_DATA=(SID=p02)(CID=(PROGRAM=)(HOST=NandaDevi)(USER=oracle)))) VERSION INFORMATION: TNS for Linux: Version 10.1.0.3.0 – Production TCP/IP NT Protocol Adapter for Linux: Version 10.1.0.3.0 – Production Time: 25-OCT-2004 20:59:52 Tracing not turned on. Tns error struct: ns main err code: 12541 TNS-12541: TNS:no listener ns secondary err code: 12560 nt main err code: 511 TNS-00511: No listener nt secondary err code: 111 nt OS err code: 0
Der vorstehende Log-Eintrag wurde generiert, weil ein Net-Aliasname eine falsche Portnummer für den Listener einhielt. Dem Anwender wurde die folgende Meldung auf dem Bildschirm angezeigt: ORA-12541: TNS: Kein Listener
Die Log-Datei zeigt zunächst die ausgegebene Fehlermeldung der obersten NetworkInterface-Schicht (NI, Zeile 2) sowie den vollständig ausgewiesenen Connect-String (Zeilen 3–4) inklusive der Information über den verursachenden Betriebssystembenutzer (oracle). Nach den Versionsinformationen und dem Zeitstempel folgen die detaillierten Fehler der unteren Net-Service-Schichten: network session (ns) und network transport (nt). Das Protokoll zeigt, dass bereits auf der nt-Ebene der Listener auf dem betreffenden Host nicht erreicht werden konnte. Log-Dateien, die von Listenern geschrieben werden, haben ein grundlegend anderes Format. Es lassen sich die folgenden Abschnitte leicht in jeder Datei erkennen: Der erste Abschnitt enthält allgemeine Informationen zu der Software-Version sowie den Konfigurations-, Log- und Trace-Dateien. Im zweiten Abschnitt finden sich Informationen zu den Protokollen und Services, die der Listener unterstützt. Der Hauptteil jeder Listener-Log-Datei wird von Audit- und Registrierungsinformationen eingenommen, wie die folgenden Ausschnitte zeigen. Auch hier sind die Zeilennummern nicht Bestandteil der originalen Log-Datei:
674 01 02 03 04 05 06 07
Troubleshooting TNSLSNR for Linux: Version 10.1.0.3.0 - Production on 25-OCT-2004 10:51:58 Copyright (c) 1991, 2004, Oracle.
All rights reserved.
System parameter file is /app/oracle/product/10.1.0/network/admin/listener.ora Log messages written to /app/oracle/product/10.1.0/network/log/listener.log Trace information written to /app/oracle/product/10.1.0/network/trace /listener.trc 08 Trace level is currently 0 09 Started with pid=2316 10 Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC))) 11 Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp) (HOST=NandaDevi.local)(PORT=1521))) 12 13 14 15
TIMESTAMP * CONNECT DATA [* PROTOCOL INFO] * EVENT [* SID] * RETURN CODE 25-OCT-2004 10:52:27 * service_register * T10G * 0 25-OCT-2004 10:52:36 * service_update * T10G * 0 25-OCT-2004 20:45:03 * (CONNECT_DATA=(SID=T10G)(CID=(PROGRAM=)(HOST=NandaDevi) (USER=oracle))) * (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.45.65)(PORT=38779)) * establish * T10G * 0 16 25-OCT-2004 20:49:03 * service_died * T10G * 12547
Die Zeile 12–15 des vorangehenden Beispiels zeigen die Audit- und Registrierungsinformationen. Die Registrierung einer Instanz bei dem Listener wird durch service_register ausgewiesen. Service_update sorgt für eine Aktualisierung der Registrierung, service_died zeigt den Verbindungsabbau zum PMON-Prozess einer Instanz an, der in diesem Beispiel mit dem Fehlercode TNS-12547 verbunden war. Connect-Anforderungen und ihre Return-Codes werden durch die connect_data Bereiche ausgewiesen. Log-Dateien von Listener-Prozesses können sehr schnell wachsen. Aus diesem Grunde sind auch in diesem Bereich sinnvolle Archivierungs- und Löschregeln gefragt. Werden detailliertere Informationen zur Fehleranalyse benötigt, besteht – wie bereits erwähnt – die Möglichkeit, Trace-Dateien schreiben zu lassen. Die Konfigurationsdateien bieten hierzu eigene Parameter an. Die folgende Tabelle gibt hierzu eine kurze Übersicht:
Werkzeuge und Fehlersituationen
675
Komponente
Konfiguration sdatei
Parameter
Bedeutung
Listener
listener.ora
TRACE_LEVEL_<listener> TRACE_DIRECTORY_<listener> TRACE_FILE_<listener> TRACE_FILELEN_<listener> TRACE_FILENO_<listener> TRACE_TIMESTAMP_<listener>
Die Parameter haben analoge Bedeutung zu den entsprechenden von sqlnet.ora.
Client/ Datenbank
sqlnet.ora
TRACE_DIRECTORY_CLIENT TRACE_FILE_CLIENT TRACE_DIRECTORY_SERVER TRACE_FILE_SERVER TRACE_LEVEL_CLIENT TRACE_LEVEL_SERVER
Die Parameter stellen sowohl die Verzeichnisse als auch die Namen der Trace-Dateien sowie den TraceLevel ein. Alle Einstellungen lassen sich für die Client- und Serverseite getrennt regeln.
TRACE_FILELEN_CLIENT TRACE_FILELEN_SERVER TRACE_FILENO_CLIENT TRACE_FILENO_SERVER
Gibt die Größe (in KB) und Anzahl von TraceDateien für Clients bzw. Server an und erlaubt so die zyklische Nutzung der Dateien.
TRACE_TIMESTAMP_CLIENT TRACE_TIMESTAMP_SERVER
Schreibt erweiterte Zeitstempel in die Trace-Dateien: dd-mon-yyyy hh:mi:ss:mil
TRACE_UNIQUE_CLIENT
Generiert individuelle Trace-Dateien für jede Session (on) Connection Manager
cman.ora
TRACE_LEVEL TRACE_DIRECTORY TRACE_FILELEN TRACE_FILENO TRACE_TIMESTAMP
Die Parameter haben analoge Bedeutung zu den entsprechenden von sqlnet.ora.
Tabelle 12.2: Trace-Parameter
Trace-Dateien von Oracle NET Services bestehen aus einem ersten, allgemeinen Teil, der die aktiven Trace- und Log-Parameter auflistet. Danach folgen die Protokolle der einzelnen Funktionsaufrufe, die – je nach Trace-Level – sehr umfangreich und daher schwer interpretierbar werden können. Es empfiehlt sich daher, die Trace-Dateien zur leichteren Analyse zu formatieren. Hierzu steht der Trace Assistant zur Verfügung. Das Werkzeug wird im Zeilenmodus vom Betriebssystem aus aufgerufen und arbeitet mit allen Trace-Dateien, die auf dem Level support generiert wurden. Das folgende Beispiel zeigt die unterschiedlichen Aufrufoptionen:
676
Troubleshooting
Verwendung: trcasst [options] [options] Standardwerte sind -odt -e0 –s immer das letzte Argument -o[c|d][u|t][q] Net Services- und TTC-Informationen [c] Zusammenfassung der Net Services-Informationen [d] Detaillierte Net Services-Informationen [u] Zusammenfassung der TTC-Informationen [t] Detaillierte TTC-Informationen [q] SQL-Befehle -s Statistiken -e[0|1|2] Fehlerinformationen, Standard ist 0 [0] NS-Fehlernummern übersetzen [1] Fehlerübersetzung [2] Fehlernummern ohne Übersetzung -l[a|i ] Verbindungsinformationen [a] Auflisten aller Verbindungen in einer Trace-Datei [i ] Decodieren einer angegebenen Verbindung Listing 12.6: Aufrufoptionen des Trace Assistants
Die Ausgabe des Werkzeugs erfolgt standardmäßig auf den Bildschirm, kann aber – unter Unix – leicht in eine Datei umgeleitet werden. Die Formatierung erfolgt nach Paketen, für jedes Datenpaket werden der Zeitstempel, der Umfang sowie bei Bedarf weitere Detailinformationen aufgelistet.
12.4.2 Statistiken, Metriken, servergenerierte Alerts Durch die im vorangehenden Abschnitt beschriebenen Trace- und Log-Dateien erhalten wir detaillierte Informationen zu den auftretenden Fehlersituationen und ihren Kontexten. Zu Analyse und Verifizierung möglicher Lösungsansätze sind jedoch häufig zusätzliche Informationen wie z. B. Statistiken und Metriken notwendig. Darüber hinaus treten Ausnahmesituationen auf, die möglicherweise keine Fehlermeldungen produzieren: Eine Endlosschleife in einem PL/SQL-Modul lässt sich in der Regel nicht über Alert- oder Trace-Dateien erkennen, sondern erfordert eine Analyse der CPU-Zeiten von Sessions sowie der Ausführungszyklen (Executions) von SQL-Befehlen. Aus inhaltlicher Sicht stehen uns hierzu die folgenden Kategorien von Informationen zur Verfügung: Kumulierte Kennzahlen auf Basis der Instanz oder der einzelnen Sessions Zu diesen Basiszahlen zählen beispielsweise das Volumen des geschriebenen Redo-Logs (redo size), die Anzahl der Commit-Aktionen (user commits), die verbrauchte CPU-Zeit (CPU used by this session) und vieles andere mehr. Diese Statistiken werden permanent aktualisiert und sind darüber hinaus flüchtig, wenn nämlich die betreffende Session beendet oder die Instanz heruntergefahren wird. Sie sind aus diesem Grunde für die nachträgliche und damit rückblickende Analyse von Fehlersituationen nur bedingt oder gar nicht geeignet.
Werkzeuge und Fehlersituationen
677
Aktuelle Kontextinformationen von Sessions, wie z. B. die im Cache befindlichen SQL-Statements oder die aktuellen Wartezustände. Auch diese Informationen sind flüchtig. Vordefinierte Metriken setzen Kennzahlen in Beziehung zueinander und ermöglichen dadurch qualitative Aussagen. Oracle 10g generiert auf der Grundlage der Kennzahlen standardmäßig über 180 dieser Metriken, die in älteren Versionen durch aufwändige SQL-Skripte berechnet werden mussten. An dieser Stelle seien nur einige zu nennen: Disk Sort Per Txn, Total Table Scans Per Txn, Total Time Waited, Buffer Cache Hit Ratio usw. Die Metriken werden darüber hinaus in Gruppen eingeteilt, wie z. B. event metrics und service metrics, wodurch eine mehrdimensionale Analyse möglich wird. Historien von Kennzahlen, Metriken und Kontextinformationen. Bereits in der System Global Area und dort in dem zirkulären Puffer des Shared Pools werden Historien von Kennzahlen, Metriken und Kontextinformationen gesammelt. Im Rahmen der so genannten Active Session History – abgekürzt ASH – werden Daten von aktiven Sessions, konkret Informationen über Wartezustände und Cursor, im Sekundentakt archiviert. Desgleichen werden auch historische Informationen über Metriken erhalten. Die zeitlichen Intervalle, mit denen diese Metrik-Snapshots generiert werden, werden im Rahmen der einzelnen Metrikgruppen festgelegt. Für jede Metrik lassen sich darüber hinaus jeweils eine Warnschwelle, ein kritischer Wert und die maximal tolerierbaren Überschreitungen dieser Werte definieren. Werden diese Werte überschritten, generiert Oracle entsprechende Warnhinweise (server-generated Alerts), die über die Advanced-Queuing-Mechanismen publiziert werden und entsprechend abrufbar sind. In konfigurierbaren Zeitintervallen schreiben Hintergrundprozesse wie MMON und MMNL7 die Inhalte der Buffer im Rahmen von Snapshots persistent in das so genannte Automatic Workload Reepository (AWR). Die Tabellen dieses Repositorys liegen in der SYSAUX-Tablespace. Neben den Zeitintervallen ist auch die Verweildauer der Daten im Repository (Retention Period) konfigurierbar. Snapshots, die signifikante Zeitabschnitte markieren und aus diesem Grunde über die konfigurierte Verweildauer hinaus von Interesse sein könnten, lassen sich erhalten, indem Paare von ihnen in so genannten Baselines dauerhaft gespeichert werden. Die in den vorangehenden Abschnitten beschriebenen Informationen lassen sich über eine Fülle von V$-Tabellen, Data Dictionary Views und PL/SQL-Prozeduren sowie über die grafischen Oberflächen des neuen Enterprise Managers nutzen. Im Folgenden werden die wichtigsten dieser Werkzeuge vorgestellt.
7
MMON = Memory Monitor; MMNL = Memory Monitor light
678
Troubleshooting
Für die Ausgabe der kumulierten Kennzahlen und Statistiken stehen die – bereits aus älteren Versionen bekannten – Statistiktabellen zur Verfügung: v$statname – listet alle verfügbaren Systemstatistiken bzw. Kennzahlen auf. v$sysstat und v$sesstat – geben die kumulierten Statistiken und Kennzahlen für die gesamte Instanz bzw. einzelne Sessions aus. Aktuelle Kontextinformationen zu der Instanz und einzelnen Sessions finden sich in den folgenden Tabellen: v$system_event – gibt eine kumulierte Übersicht über alle im Kontext der betreffenden Instanz aufgetretenen Wartezustände (Wait Events) mit ihrer Anzahl, den gesamten sowie den durchschnittlichen Wartezeiten sowie der Summe der aufgetretenen Timeouts8. v$session_event – enthält die gleiche Übersicht, jedoch aus der Sicht der einzelnen Sessions. v$session_wait – gibt für alle Sessions den jeweils aktuellen Wartezustand aus. Über drei weitere Attribute – p1, p2 und p3 – werden weitere Details des betreffenden Wait Events angezeigt. Die Tabelle v$event_name gibt eine Übersicht über alle möglichen Wartezustände und die Bedeutung ihrer jeweiligen Detailattribute. SELECT name, parameter1, parameter2, parameter3 FROM v$event_name WHERE name LIKE 'db file%read%'; NAME PARAMETER1 PARAMETER2 ----------------------------------------db file sequential read file# block# db file scattered read file# block# db file parallel read files blocks
PARAMETER3 ---------blocks blocks requests
Listing 12.7: Ausgabe V$event_name
Unter Oracle 10g ist es nun erstmals möglich, die aktuellen Wartezustände der Sessions direkt über die View v$session abzufragen. Aufwändige Join-Operationen zwischen v$session_wait und v$session entfallen damit. Gleichfalls lassen sich die Wartezustände erstmalig gruppieren. Auf diese Weise lassen sich z. B. die so genannten Idle Events, die auf die Messung der Performance oder die Fehleranalyse in der Regel keinen Einfluss ausüben, leicht herausfiltern. Die Tabelle v$system_wait_class zeigt diese Klassen an und enthält auch die akkumulierten Wartezeiten pro Klasse pro Instanz. V$session_wait_class gibt die gleichen Statistiken aus Sicht der einzelnen Sessions aus.
8
Spalte TOTAL_TIMEOUTS. Events können unterschiedliche maximale Wartezeiten haben. Beim Erreichen dieser Zeiten wird einer neuer Wartezustand begonnen und entsprechend protokolliert.
Werkzeuge und Fehlersituationen
679
SELECT wait_class, total_waits, time_waited FROM v$system_wait_class; WAIT_CLASS ---------------Other Application Configuration Concurrency Commit Idle Network User I/O System I/O
TOTAL_WAITS ----------815 11025 34783 131 5227 405508 119885 47967 50740
TIME_WAITED ----------1973 4568 6944 109 18042 124224126 1748 8515 175652
Listing 12.8: V$system_wait_class
v$osstat – gibt Informationen über die Anzahl und Auslastung der CPUs auf Seiten des Servers, zum Paging und IO-Verhalten v$sess_time_model und v$sys_time_model – gruppieren die Elapsed- und CPU-Zeiten von Sessions bzw. der gesamten Instanz. Die View v$sess_time_model ist besonders hilfreich, um CPU-Lastprofile von Sessions zu erstellen: SELECT a.sid, b.username, a.stat_name, ROUND((a.value / 1000000),3) time_secs FROM v$sess_time_model a, v$session b WHERE a.sid = b.sid AND b.sid = 25 AND ROUND((a.value / 1000000),3) > 0 ORDER BY 4 DESC; SID USERNAME ---------------25 SCOTT 25 SCOTT 25 SCOTT 25 SCOTT 25 SCOTT 25 SCOTT 25 SCOTT 25 SCOTT
STAT_NAME ------------------------------------------DB time sql execute elapsed time DB CPU parse time elapsed hard parse elapsed time connection management call elapsed time PL/SQL compilation elapsed time PL/SQL execution elapsed time
TIME_SECS --------3,427 2,96 2,841 0,315 0,307 0,012 0,009 0,001
Listing 12.9: Gruppierung der CPU- und Elapsed-Zeiten
Der Benutzer Scott des vorangehenden Beispiels hat einen Großteil seiner Rechenzeit mit dem Ausführen von SQL-Befehlen verbracht. Nur verschwindend kleine Anteile gehen auf das Konto von Parsing und PL/SQL.
680
Troubleshooting
Neben den aktuellen Kennzahlen und Statistiken, die durch die Views der vorangehenden Abschnitte ausgegeben werden, existieren weitere Views, die Kontextinformationen zu den Sessions und der gesamten Instanz liefern. Einige von ihnen sind für die Fehleranalyse sehr hilfreich: v$transaction – gibt Auskunft über alle offenen, schreibenden Transaktionen der Instanz. Über diese View lassen sich wichtige Informationen zu dem von der betreffenden Session genutzten Rollback-Segment, dem Platzverbrauch und IOVerhalten gewinnen. Im folgenden Beispiel wird v$transaction für den Benutzer Scott nach einem Insert über 100.000 Rows konsultiert und gibt neben dem Namen des benutzten Rollback-Segmentes und den Details der dortigen Transactions-Tabelle9 das logische und physische IO sowie die benutzten Undo-Blöcke aus: SELECT s.username, t.xidusn,r.name, t.xidslot, t.xidsqn , t.used_ublk, t.phy_io, t.log_io FROM v$transaction t, v$rollname r, v$session s WHERE s.saddr = t.ses_addr AND r.usn = t.xidusn AND s.username = 'SCOTT'; USERNAME XIDUSN NAME XIDSLOT XIDSQN USED_UBLK PHY_IO LOG_IO --------- ------ ------------ ------- ---------- --------------------SCOTT 4 _SYSSMU4$ 39 1763 1865 2 719281
v$sqlarea – gibt kumulative Statistiken zu SQL-Befehlen und allen Cursorn aus, die mit identischer Syntax arbeiten. v$sql dagegen zeigt Statistiken für einzelne Cursor. Ein bestimmter SQL-Befehl, wie z.B. SELECT * FROM emp, kann von beliebig vielen Sessions syntaktisch identisch ausgeführt werden. Jede Session kann jedoch mit diesem Befehl semantisch unterschiedlich umgehen, indem abweichende Optimizer-Einstellungen – optimizer_mode – aktiv sind oder ganz einfach unterschiedlich strukturierte Emp-Objekte im Zugriff liegen. Mit anderen Worten: Jede SQL-Syntaxausprägung kann einen oder auch mehrere Cursor nutzen. Für die Fehleranalyse sind naturgemäß nur die konkreten Cursor einer betreffenden Session mit ihren jeweiligen Kennzahlen interessant. Im folgenden Beispiel werden einige Kennzahlen und Statistiken der aktuellen Cursor des Benutzers Scott ausgegeben. Die akkumulierten Wartezeiten enthalten alle Wartezustände der betreffenden Warteklassen, die sich auf den angezeigten SQL-Befehl beziehen. Die Zeitangaben werden in diesem Beispiel von Mikrosekunden in Sekunden umgerechnet. Da die betreffenden SQL-Befehle in diesem Beispiel recht kurz waren, wurde die Ausgabe über die Spalte sql_text realisiert. Für Befehle, die länger als eintausend Zeichen sind, steht ab der Version 10g das clob-Attribut sql_fulltext zur Verfügung und erspart uns dadurch einen Join mit der View v$sql_text. Die Wartezeiten werden darüber hinaus auf jeweils eine Ausführung (execution) zurückgerechnet:
9
xidusn = undo segment number – Eindeutige Nummer des Rollback-Segmentes; xidslot – Index des Transaktionseintrages in der Transaktionstabelle; xidsqn – Versionsnummer des Slots
Werkzeuge und Fehlersituationen
681
SELECT s.SID, q.sql_text, q.sorts, q.executions ,ROUND ((q.application_wait_time / 1000000 /executions ), 3 ) application_wait_time_sec ,ROUND ((q.concurrency_wait_time / 1000000 /executions ), 3 ) concurrency_wait_time_sec ,ROUND ((q.user_io_wait_time / 1000000 /executions), 3 ) user_io_wait_time_sec ,ROUND ((q.plsql_exec_time / 1000000 /executions), 3 ) plsql_exec_time_sec ,ROUND ((q.plsql_exec_time / 1000000 /executions), 3 ) elapsed_time_sec ,q.rows_processed FROM v$session s, v$sql q WHERE username = 'SCOTT' AND ( q.sql_id = s.sql_id OR q.sql_id = s.prev_sql_id ); Listing 12.10: QL-Statistiken einer Session
Der nachfolgende Insert-Befehl wurde im Kontext von SQL*Plus über einen anonymen PL/SQL-Block in einer Schleife einhunderttausend Mal ausgeführt. Die nachfolgende Ergebnisliste wurde während des Loops generiert und zeigt den Child-Cursor des übergeordneten PL/SQL-Blocks: SID SQL_TEXT SORTS EXECUTIONS APPLICATION_WAIT_TIME_SEC CONCURRENCY_WAIT_TIME_SEC USER_IO_WAIT_TIME_SEC PLSQL_EXEC_TIME_SEC ELAPSED_TIME_SEC ROWS_PROCESSED
25 INSERT INTO TABELLE VALUES (:B1 , 'IregendeinText' || :B1 ) 0 181920 0 0 ,16 0 ,17 181920
Listing 12.11: Ausgabe der SQL-Statistik
Werden Ausführungspläne von Cursorn sowie Statistiken zu den einzelnen Zugriffsoperationen der Pläne benötigt, stehen u.a. die Views v$sql_plan, v$workarea und v$sql_plan_statistics zur Verfügung. Die Werte von Bindevariablen, die im Rahmen von PL/SQL oder Precompiler-Programmen genutzt werden, können über die View v$sql_bind_capture ausgegeben werden. Ein Novum unter Oracle 10g stellen die vordefinierten Metriken dar, die Kennzahlen in Beziehung zueinander setzen und auf diese Weise unterschiedliche Quoten zur Verfügung stellen, die qualitative Aussagen über die Instanz oder die betreffende Session ermöglichen. Derzeit sind 144 unterschiedliche Metriken definiert, die auf insgesamt 10 Metrikgruppen – siehe die View v$metricgroup – verteilt werden und in den meisten Fällen einmal pro Minute ermittelt werden. Manche der Metriken gehören zwei unterschiedlichen Gruppen an, so dass uns die View v$metricname 184 Metriken anzeigt. Das folgende Beispiel gibt beispielsweise alle Metriken im Kontext von Dateien und Trefferquoten aus:
682
Troubleshooting
SELECT group_name, metric_name, metric_unit FROM v$metricname WHERE metric_name LIKE '%File%' OR metric_name LIKE '%Hit%' / METRIC_NAME --------------Physical Block Writes (Files-Long) Physical Block Reads (Files-Long) Physical Writes (Files-Long) Physical Reads (Files-Long) Average File Write Time (Files-Long) Average File Read Time (Files-Long) PGA Cache Hit % Library Cache Hit Ratio Row Cache Hit Ratio Cursor Cache Hit Ratio Redo Allocation Hit Ratio Buffer Cache Hit Ratio Library Cache Hit Ratio Buffer Cache Hit Ratio
METRIC_UNIT ------------Blocks Blocks Writes Reads CentiSeconds Per Write CentiSeconds Per Read % Bytes/TotalBytes % Hits/Pins % Hits/Gets % CursorCacheHit/SoftParse % (#Redo - RedoSpaceReq)/#Redo % (LogRead - PhyRead)/LogRead % Hits/Pins % (LogRead - PhyRead)/LogRead
Listing 12.12: Diverse Metriken
v$metric und v$sysmetric – geben die jeweils aktuell gemessenen Werte pro Metrik für die gesamte Instanz aus. Die Messintervalle werden über die Metrikgruppen bestimmt und lassen sich über v$metricgroup abfragen: SELECT name, interval_size FROM v$metricgroup;
Zusätzlich existiert eine Reihe von Views, die relevante Metriken für die unterschiedlichsten Kontexte ausgeben. Die Namen sprechen für sich: v$sessmetric, v$filemetric, v$eventmetric und v$servicemetric. Die »Histogramm«-Familie der V$-Views bietet Histogramme für IO-Operationen auf Datenbankdateien oder für Events. Folgende Views existieren: v$temp_histogram, v$file_histogram und v$event_histogram. SELECT event, wait_time_milli, wait_count , round(wait_count/summe.total*100,2) "wait%" FROM v$event_histogram , (SELECT sum(wait_count) total FROM v$event_histogram WHERE event = 'db file scattered read') summe WHERE event = 'db file scattered read' / EVENT ---------------------db file scattered read db file scattered read db file scattered read db file scattered read db file scattered read db file scattered read
WAIT_TIME_MILLI -----------------1 2 4 8 16 32
WAIT_COUNT -----------4307 18 6 19 68 135
wait% ------90,39 0,38 0,13 0,4 1,43 2,83
Werkzeuge und Fehlersituationen db file scattered read db file scattered read db file scattered read
683 64 128 256
162 45 5
3,4 0,94 0,1
Die vorangehenden Statistiken zeigen, dass über 90% des IO für Multiblock Reads (sScattered Read) bis zu einer Millisekunde dauerten. Neben den aktuellen Informationen, welche die Views der vorangehenden Abschnitte ausgeben konnten, werden unter Oracle 10g auch historische Daten zu den diversen Kennzahlen, Statistiken und Metriken erhalten. Das Verfahren ist in diesem Zusammenhang zweistufig: Zunächst werden die Daten über zirkuläre Puffer in der SGA gehalten, um dann von dort aus in größeren Zeitintervallen – wie bereits erwähnt – als »Snapshots« in die Tabellen des Automatic Workload Repositorys (AWR) geschrieben zu werden. Damit der Snapshot-Mechanismus automatisch arbeitet, ist es unbedingt notwendig, dass der Systemparameter statistics_level auf typical oder all eingestellt ist. Andernfalls lassen sich Snapshots nur explizit generieren. Die jeweils aktuellen Einstellungen zu den Snapshot-Intervallen und der Vorhaltezeit lassen sich über die View dba_hist_wr_control gewinnen. Die Angaben sind als Intervall von Tagen, Stunden, Minuten zu verstehen. In diesem Beispiel wird jede Stunde in das Repository geschrieben, und die Daten werden für vier Tage vorgehalten. DBID 2223592370
SNAP_INTERVAL +00 01:00:00.000000
RETENTION +04 00:00:00.000000
Listing 12.13: Einstellungen des Active Workload Repositorys
Die Einstellungen können über folgende Prozedur angepasst werden: BEGIN dbms_workload_repository.modify_snapshot_settings (interval => 45 -- Minuten ,retention => 20160 –- Minuten = 2 Wochen); END; / Listing 12.14: Anpassen der WR-Einstellungen
Auch im Zusammenhang mit historischen Daten steht ein Fülle von Views und Tabellen zur Verfügung. Zunächst wurden die V$-Views um eine »History«-Familie erweitert. An erster Stelle ist hier die so genannte Active Session History (ASH) zu erwähnen, die für alle Sessions, die momentan aktiv sind oder sich in einem Wartezustand befinden, der nicht der Klasse idle angehört, im Sekundentakt Informationen über ausgeführte SQL-Befehle, Wartezustände und IO-Operationen sammeln. Die Daten der ASH, die sich noch in der SGA befinden, sind über die View v$active_session_history abrufbar. Weitere »History«-Views, wie z.B. v$sysmetric_history, v$filemetric_history, v$waitclassmetric_history und v$servicemetric_history, bieten gleichermaßen historische Daten aus der SGA in ihrem Kontext an. V$session_wait_history enthält für jede aktive Session die letzten zehn Wartezustände mit den entsprechenden Detailinformationen in den Spalten p1, p2, p3.
684
Troubleshooting
Der Speicherplatz, den Active Session History in der SGA belegt, hängt von der Anzahl und dem SQL-Aufkommen der Sessions sowie von der Häufigkeit der Snapshot-Generierung ab. Der folgende SQL-Befehl ermittelt den Verbrauch: SELECT * FROM v$sgastat WHERE name = 'ASH buffers'; POOL --------------shared pool
NAME -----------ASH buffers
BYTES -------2097152
Listing 12.15: Speicherverbrauch der ASH-Buffer in der SGA
Die View dba_hist_active_sess_history dagegen zeigt die per Snapshot in das Repository übertragenen Daten der aktiven Sessions. Eine Reihe weiterer DBA_HISTViews10 steht für den Zugriff zur Verfügung: dba_hist_snapshot – gibt Informationen zu den gespeicherten Snapshots aus. Alle Snapshots werden über eine eindeutige snap_id gekennzeichnet. Die View gibt darüber hinaus den Anfang und das Ende der Snapshot-Periode sowie die aufgetretenen Fehler aus. Details zu den aufgetretenen Fehlern finden sich über dba_hist_snap_errors. Alle weiteren DBA_HIST-Views beziehen sich in der Folge auf die eindeutige snap_id. Die folgende Liste zählt einige der wichtigsten Views auf: dba_hist_sqlstat – zeigt Statistiken zu den gespeicherten SQL-Befehlen. dba_hist_sql_plan – gibt die Zugriffspläne dieser Befehle aus. dba_hist_sqlbind – zeigt die benutzten Bindevariablen und ihnen zugewiesene Werte. dba_hist_sys_time_model – bietet Statistiken der CPU-Nutzung für die gesamte Instanz. dba_hist_sessmetric_history – gibt die historischen Metriken für Sessions aus. dba_hist_undostat – gibt Statistiken für die Nutzung der Rollback-Segmente aus. Bei der Fülle der zur Verfügung stehenden Informationen ist es wichtig, ein genaues Konzept zu entwickeln, welche Applikationen welche Informationen für die Beobachtung und Fehleranalyse benötigen. Wie bereits erwähnt, werden die Daten der Snapshots für eine bestimmte Dauer in dem AWR-Repository vorgehalten (Retention Periode). Markante Perioden, deren Kennzahlen als Referenzen längerfristig erhalten bleiben sollen, lassen sich als so genannte baselines unabhängig von der Verweildauer erhalten. Das Paket dbms_workload_repository bietet hierzu die notwendigen Schnittstellen an. Die Prozedur create_baseline fordert hierbei den Anfang und das Ende der Periode über entsprechende Snapshot-Nummern an: BEGIN DBMS_WORKLOAD_REPOSITORY.CREATE_BASELINE (start_snap_id => 270, end_snap_id => 280, baseline_name => 'Hochlast Wochenende', dbid => 3310949047); END; / 10 Derzeit stehen 67 Views der HIST-Familie zur Verfügung.
Werkzeuge und Fehlersituationen
685
Gespeicherte Baselines lassen sich über die View dba_hist_baselines ausgeben. Ein weiteres wichtiges Hilfsmittel für die Fehlererkennung und -analyse sind die »Alert«-Meldungen (Server-generated Alerts), die der Datenbankserver automatisch generieren kann. Alerts werden entweder beim Auftreten eines Fehlers – wie z.B. snapshot too old – oder beim Überschreiten eines Schwellenwertes generiert und in die vordefinierte, persistente Queue ALERT_QUE geschrieben. Schwellenwerte können auf zwei Ebenen generiert werden: für das Auslösen einer Warnung oder als kritischer Höchstwert. Das Paket DBMS_SERVER_ALERT bietet die nötigen Schnittstellen an. Im folgenden Beispiel werden die Schwellenwerte für die CPUZeiten pro Call gesetzt: DBMS_SERVER_ALERT.SET_THRESHOLD( DBMS_SERVER_ALERT.CPU_TIME_PER_CALL –- Art des Schwellwertes: CPU pro CALL , DBMS_SERVER_ALERT.OPERATOR_GE, '8000' -- Warnschwelle > 8000 Mikrosekunden , DBMS_SERVER_ALERT.OPERATOR_GE, '10000' –- kritische Schwelle > 10000 MS , 1 –- Beobachtungsdauer in Minuten , 2 –- Anzahl der Überschreitungen, bis ein Alert generiert wird , 'T10G' – Name der Instanz , DBMS_SERVER_ALERT.OBJECT_TYPE_SERVICE, 'appl1.dcconsult.de') –- Datenbank-Service, für den der Schwellenwert gelten soll Listing 12.16: Setzen von Schwellenwerten
Die für die einzelnen Metriken eingestellten Schwellenwerte lassen sich über die View DBA_THRESHOLDS auflisten. Eine Auswahl aller gültigen Alert-Typen und der mit ihnen verknüpften Metriken bietet v$alert_types. Metriken, Baselines und Alerts lassen sich auch über den neuen Enterprise Manager verwalten. Unter dem Tab-Reiter Datenbank und dort unter Standardverzeichnis befindet sich der Abschnitt Alerts, der aktuelle Alert-Meldungen anzeigt. Weiter unten auf derselben Seiten in der Rubrik Zugehörige Links findet sich die Verzweigung Metriken verwalten, über die Schwellenwerte sowie Baselines eingestellt werden können.
12.4.3 Programmatische Möglichkeiten Zur effizienten Analyse von Fehlern, die im Kontext von Sessions auftreten, ist es in vielen Fällen hilfreich, den genauen programmatischen Kontext des betreffenden Problems, wie z.B. den Namen der Applikation oder der Prozedur, zu ermitteln. In diesem Zusammenhang bietet Oracle mit Hilfe der Packages dbms_application_info und dbms_session die Möglichkeit, Modulnamen, Aktionsnamen, Client-Informationen und Client-Identifier zu setzen. Entsprechend gesetzt, können diese Informationen dann genutzt werden, um Sessions und SQL-Befehle mit Hilfe verschiedener V$-Views zu filtern bzw. die zugehörigen Programme zu »tracen«. Da die Namen frei zu vergeben sind, empfiehlt es sich, geeignete Konventionen zu vereinbaren. Modulnamen können beispielsweise den Namen des ausgeführten Packages oder der aufrufenden Bildschirmseite tragen. Aktionsnamen lassen sich für die feinere Unterteilung logischer Programmbereiche innerhalb von Modulen nutzen. Client-Informationen können genutzt werden, um den Namen der Applikation zu übermitteln.
686
Troubleshooting
In dem folgenden Beispiel wird die Client-Information auf »MyApplication« gesetzt. Der Aufruf könnte – im Client-Umfeld – beim Start der gleichnamigen Applikation erfolgen oder – im Bereich von dreischichtigen Java-Applikationen – beim Aktivieren des betreffenden Application Moduls über den betreffenden Application-Server: begin dbms_application_info.set_client_info ( client_info => 'MyApplication' ); end; / Listing 12.17: Client-Formationen setzen
Beim Aufruf der Bildschirmseite »Customer« im Administrationsbereich dieser Anwendung könnte dann der Modulname auf »ADMIN.customer« gesetzt werden. Die Aktion wird in diesem Beispiel nicht explizit gesetzt: begin dbms_application_info.set_module ( module_name => 'ADMIN.customer', action_name => null ); end; / Listing 12.18: Modulinformationen setzen
Client-Informationen und Client-Identifier werden häufig verwechselt. Letztere werden über das Package dbms_session gesetzt und können genutzt werden, um eindeutige, identifizierende Informationen für die betreffende Session zu setzen. Auf diese Weise lassen sich beispielsweise eindeutige Benutzerangaben auch in mehrschichtigen Anwendungen realisieren, die sich über zentrale Applikationsbenutzer mit der Datenbank verbinden. Im Gegensatz zu Client-Informationen werden Client-Identifier auch im Rahmen des Audit Trail erfasst und sind dementsprechend auswertbar. Im folgenden Beispiel wird der Client-Identifier auf »U4711« gesetzt: begin dbms_session.set_identifier('U4711'); end; / Listing 12.19: Client-Identifier setzen
Zum Zurücksetzten der Client-Identifier steht die Prozedur dbms_session.clear_ identifier zur Verfügung.
Werkzeuge und Fehlersituationen
687
Einmal gesetzt lassen sich die Modul- und Aktionsnamen sowie die Client-Informationen nutzen, um Session-Informationen und Performance-Daten über V$Views zu filtern. Die folgende Abfrage lokalisiert Sessions, die sich über die Anwendung »MyApplication« und den Datenbankbenutzer appuser mit der Datenbank verbunden haben. Die identifizierten Endbenutzer sind u4711 und u4712: select sid, serial#, username, machine, client_info, client_identifier from v$session where username = 'APPUSER'; SID SERIAL# --- --------29 924 41 1400
USERNAME -------------APPUSER APPUSER
MACHINE ---------------HL\HLLAP11 PROD\EU3202
CLIENT_INFO -------------MyApplication MyApplication
CLIENT_IDENTIFIER ----------------U4711 U4712
Listing 12.20: Session-Identifizierung über Client-Identifier
SQL-Befehle und ihre statistischen Daten können ebenfalls mit Hilfe der gesetzten Modul- und Aktionsnamen gefiltert werden. Die Views v$sql und v$sqlarea sind dazu geeignet. Das Beispiel gibt die Statistiken für alle Select-Befehle aus, die über das Modul ADMIN.customer ausgeführt wurden: select substr(sql_text,1,100) sql, executions, disk_reads/executions from v$sql where module = 'ADMIN.customer' and command_type = 3; Listing 12.21: Filtern von SQL-Statistiken
Gleichermaßen lassen sich die Trace-Dateien auf Basis der Modul- oder Client-Vorgaben über das Paket dbms_monitor generieren. Im folgenden Beispiel wird für das oben genannte Modul im Rahmen des Datenbank-Service T10G.NandaDevi.de das SQL-Tracing aktiviert. begin dbms_monitor.serv_mod_act_trace_enable ( service_name => 'T10G.NandaDevi.de' , module_name => 'ADMIN.customer' , action_name => dbms_monitor.all_actions , waits => true , binds => true , instance_name => null ); end; / Listing 12.22: SQL-Trace für Module
Alle aktiven Trace-Einstellungen können über die View dba_enabled_traces ausgegeben werden.
688
Troubleshooting
12.4.4 Validieren von Blöcken Es gibt verschiedene Werkzeuge, mit deren Hilfe sich Oracle-Blöcke prüfen und validieren lassen. Solche Blockprüfungen können aus unterschiedlichen Gründen notwendig werden: Der DBA will sich von der physischen Unversehrtheit von Datendateien oder Segmenten überzeugen und ausschließen, dass es bisher unentdeckte Blockkorruptionen gibt. Durch den Zugriff auf korrupte Blöcke werden Fehlermeldungen wie die folgende generiert, und der DBA will diese Meldungen verifizieren, bevor er geeignete Recovery-Maßnahmen einleitet: ORA-01578: ORACLE data block corrupted (file # 8, block # 12617) ORA-01110: data file 22: '/oracle1/oradata/V90/oradata/V10/users01.dbf'
In einigen Situationen kann es auch zu ORA-00600-Fehlern kommen. Um das betreffende Datenbankobjekt zweifelsfrei lokalisieren zu können, ist es wichtig, zwischen relativen und absoluten Dateinummern zu unterscheiden – in unserem Beispiel ist die relative Dateinummer 8 und die absolute 22. Relative Dateinummern sind eindeutig innerhalb einer Tablespace – und können maximal 1023 betragen –, während absolute Dateinummern innerhalb der Datenbank eindeutig sind. Die View dba_data_files gibt beide Nummernbereiche aus. Für die Zuordnung korrupter Blöcke zu Datenbankobjekten ist grundsätzlich erforderlich, die absolute Dateinummer heranzuziehen, wie das folgende Syntaxbeispiel zeigt: SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents WHERE file_id = 22 and 12617 between block_id AND block_id + blocks - 1
Grundsätzlich gilt: Korrupte Blöcke führen nur dann zu Fehlern, wenn sie durch einen Zugriff entdeckt werden. Im Zuge ihrer Entdeckung werden sie in der Regel auch als korrupt markiert. Markierte Blöcke wiederum, die Benutzerdaten enthalten, können beim Lesen ignoriert werden, sofern bestimmte Events gesetzt sind oder das Segment entsprechende Einstellungen über das Package dbms_repair empfangen hat, wie im Folgenden beschrieben wird. Header-Blöcke dagegen, die zentrale Daten für ihnen zugewiesene Segmente einhalten, wie z.B. Segment-Header oder Bitmap-Blöcke, führen im Korruptionsfall immer zum Ausfall des kompletten Segments. Umgekehrt bedeutet dies, dass in einer Datenbank korrupte Blöcke auf Dauer existieren können – beispielsweise korrupte Blöcke von Indizes, die niemals vom Optimizer für Zugriffe ausgewählt werden.
Werkzeuge und Fehlersituationen
689
Das Analyze-Kommando Die einfachste Möglichkeit, einzelne Segmente zu prüfen, bietet das analyze-Kommando mit der validate structure-Klausel. Im folgenden Beispiel wird die Tabelle emp des Schemas scott zusammen mit ihren Indizes validiert: ANALYZE TABLE scott.emp VALIDATE STRUCTURE CASCADE;
Das analyze-Kommando prüft die Blöcke des betreffenden Segments bis zur Hochwassermarke. Während des Prüfvorgangs wird eine exklusive Sperre auf die Segmente gesetzt, was zu entsprechenden Problemen bei gleichzeitigen Zugriffen führen kann. Neben diesen Einschränkungen ist vor allem zu beachten, dass analyze korrupte Blöcke nicht markiert, sondern sie lediglich anzeigt. Hierdurch wird der praktische Nutzen dieses Werkzeugs erheblich eingeschränkt. In der Regel ist analyze nur dazu geeignet, ein vermutlich korruptes Segment vor der Wiederherstellung zu verifizieren. Das Package dbms_repair Wie analyze prüft auch das Paket dbms_repair einzelne Segmente, weist jedoch gegenüber ersterem einige entscheidende Vorteile auf: Die Konsistenzprüfung berücksichtigt sowohl die Cache- als auch die Data-Layer der Datenblöcke. Im Gegensatz dazu prüft analyze nur die Cache-Layer. Die Cache-Layer enthalten Versionsnummern, Adressen und Prüfsummen11 von Datenblöcken. Geprüfte und für korrupt befundene Blöcke werden markiert. Wird die Korruption direkt nach dem Lesen von der Platte erkannt (Media Corrupt), wird die im Cache-Layer des Blockes befindliche SCN-Nummer12 auf 0 gesetzt. Wird sie erkannt, nachdem der Block bereits im Cache verändert wurde (Soft Corrupt), wird die Sequenznummer des Cache-Layers auf den Maximalwert gebracht. Für Segmente, die korrupte Datenblöcke enthalten, kann individuell das Attribut skip_corrupt aktiviert werden. Dadurch werden korrupte Blöcke überlesen und damit entsprechende Fehlermeldungen vermieden. Skip_corrupt hat damit einen entscheidenden Vorteil gegenüber den Events 10231 und 10233, die pauschal für die gesamte Instanz korrupte Blöcke überlesen. Beide Events werden im folgenden Abschnitt detailliert behandelt.
11 Prüfsummen werden über den Systemparameter db_block_checksum = true oder false ein- bzw. ausgeschaltet. Der Standardwert unter 10g ist true. 12 SCN = »System Change Number« oder »System Commit Number« – der interne »Transaktionszähler« jeder Datenbank
690
Troubleshooting
Zusätzlich zu den oben geschilderten Funktionen lässt sich dbms_repair nutzen, um Hilfstabellen für die Blockanalyse anzulegen, Indexeinträge zu protokollieren, die auf korrupte Datenblöcke verweisen (Orphan Keys), Freilisten neu zu berechnen, Bitmaps in ASSM-Segmenten13 neu zu berechnen oder Blöcken in ASSM-Segmenten explizite Füllgrade zuzuschreiben – beispielsweise können auf diese Weise korrupte Blöcke als »voll« markiert werden. Bevor Segmente geprüft werden können, müssen Hilfstabellen erzeugt werden. Es wird jeweils eine Hilfstabelle für die Korruptionsprüfung und die Orphan-Key-Analyse benötigt. Im folgenden Beispiel werden die Hilfstabelle repair_table im aktuellen Schema – hier sys – und der Tablespace users angelegt. Gleichzeitig wird die View dba_repair_table angelegt. Das Package gehört sys und hat standardmäßig keine Grants an andere Benutzer. BEGIN DBMS_REPAIR.ADMIN_TABLES ( TABLE_NAME => 'REPAIR_TABLE', TABLE_TYPE => dbms_repair.repair_table, ACTION => dbms_repair.create_action, TABLESPACE => 'USERS'); END; /
Einmal angelegt können die Tabellen für Analysen benutzt werden. Im folgenden Beispiel wird die Tabelle test von scott untersucht: DECLARE num_corrupt INT; BEGIN num_corrupt := 0; DBMS_REPAIR.CHECK_OBJECT ( SCHEMA_NAME => 'SCOTT', OBJECT_NAME => 'TEST', REPAIR_TABLE_NAME => 'REPAIR_TABLE', CORRUPT_COUNT => num_corrupt); DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt)); end; /
Werden im Laufe der Analyse korrupte Blöcke entdeckt – und in der Gesamtzahl ausgegeben –, können die Details der Analyse über die View dba_repair_table ausgegeben werden.
13 ASSM = Automatic Segment Space Management, siehe Kapitel 3
Werkzeuge und Fehlersituationen
691
DBVERIFY Mit Hilfe des Werkzeugs DBVERIFY (dbv) lassen sich Blöcke von Datendateien überprüfen. dbv arbeitet sowohl mit offenen als auch geschlossenen Daten und überprüft sowohl die Cache- als auch die Data-Layer der entsprechenden Blöcke. dbv prüft nur einzelne Blöcke und kann aus diesem Grund keine Metadaten einbeziehen, um beispielsweise Daten- und Indexeinträge gegeneinander abzugleichen. Das Werkzeug wird von der Kommandozeile aus aufgerufen und kann – gesteuert über entsprechende Eingabeparameter – in unterschiedlichen Kontexten genutzt werden: durch Angabe einer Datendatei, die entweder vollständig oder – bei Angabe eines Start- und Endblockes – partiell geprüft werden kann. Überprüfung eines Segments unter Angabe der numerischen Bezeichner für die zugehörige Tablespace, die Header-Datei und den Header-Block. Blöcke, die Korruptionen in ihren Cache-Layern aufweisen, werden entsprechend markiert. dbv eignet sich jedoch nicht zur Prüfung von Control- oder Redo-LogDateien. Im folgenden Beispiel wird die Tabelle test des Benutzers scott geprüft, deren Segment-Header-Block sich in der Tablespace mit Nummer 4, Datei 4 und Block 11 befindet. Die numerischen Angaben für die Eingabeparameter können wie folgt ermittelt werden: SELECT t.ts#, seg.header_file, seg.header_block FROM ts$ t INNER JOIN dba_segments seg ON t.name = seg.tablespace_name WHERE owner = 'SCOTT' AND segment_name = 'TEST';
Das Aufruf des Werkzeugs lässt sich dann wie folgt gestalten: dbv userid=scott/tiger segmentment_id=4.4.11
Die generierte Ausgabe weist in diesem Fall keine Korruptionen aus: DBVERIFY: Release 10.1.0.3.0 - Production on Fri Feb 4 07:57:33 200 Copyright (c) 1982, 2004, Oracle.
All rights reserved.
DBVERIFY - Verification starting : SEGMENT_ID = 4.4.11 DBVERIFY - Verification complete Total Total Total Total Total Total Total Total Total
Pages Pages Pages Pages Pages Pages Pages Pages Pages
Examined Processed Failing Processed Failing Processed Processed Failing Empty
: (Data) : (Data) : (Index): (Index): (Other): (Seg) : (Seg) : :
16 13 0 0 0 2 1 0 0
692
Troubleshooting
Total Pages Marked Corrupt Total Pages Influx Highest block SCN
: 0 : 0 : 1812186 (0.1812186)
Das folgende Beispiel jedoch zeigt bei der Überprüfung der Datei users01.dbf unterschiedliche Probleme. Zum einen gibt es korrupte Pointer im Datenbereich des Blocks 3 (Zeilen 2 bis 4), zum anderen sind die Blöcke 10 und 12 in ihren CacheLayern korrupt und wurden dementsprechend markiert. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
DBVERIFY - Verification starting : FILE = users01.dbf kdbchk: a row ends in the middle of another tab=0 slot=1 begin=0x7a0 len=0x14 Page 3 failed with check code 5 Page 10 is marked software corrupt Page 12 is marked software corrupt DBVERIFY - Verification complete Total Pages Examined : 512 Total Pages Processed (Data) : 1 Total Pages Failing (Data) : 1 Total Pages Processed (Index): 0 Total Pages Failing (Index): 0 Total Pages Empty : 507 Total Pages Marked Corrupt : 2 Total Pages Influx : 0
Es kann durchaus vorkommen, dass dbv Blockkorruptionen meldet, entsprechende analyze-Proben jedoch keine Fehler ausgeben. In diesen Fällen ist es möglich, dass korrupte Blöcke in ungenutzten Blockbereichen der betreffenden Tablespace liegen – außerhalb von Segmenten – und aus diesem Grunde von analyze nicht erfasst werden. Solche Blöcke werden in der Regel neu formatiert, wenn sie Daten im Kontext eines neuen Segments erhalten. Fehler, die dbv in diesem Zusammenhang ausgibt, können als getrost ignoriert werden. Events für korrupte Blöcke Der Umgang der Instanz, mit Blöcken, die als korrupt markiert wurden, kann über verschiedene Events gesteuert werden. Im Normalfall wird beim Lesen eines korrupten Blokkes – wie bereits erwähnt wurde – ein Fehler ausgegeben. Die folgenden Events14 verändern dieses Verhalten dahingehend, dass korrupte Blöcke überlesen werden. Die Daten sind in diesen Fällen natürlich nicht mehr über SQL-Befehle abrufbar. Folgende Event-Nummern sind in diesem Kontext von Interesse: Event 10231 – überliest korrupte Datenblöcke während eines Full Table Scans und ermöglich damit beispielsweise den Export von Tabellen mit korrupten Blöcken. Event 10233 – überliest korrupte Daten- oder Indexblöcke bei einem Index-Scan. Dieser Event ist vor allem für korrupte, indexorganisierte Tabellen interessant.
14 Für eine ausführlichere Beschreibung von Events siehe den Abschnitt Die Arbeit mit Events.
Werkzeuge und Fehlersituationen
693
Event 10232 – schreibt formatierte Dumps von korrupten Blöcken in eine TraceDatei. Über die Trace-Dateien können dann ggf. – in mühsamer Kleinarbeit – die Daten der korrupten Blöcke rekonstruiert werden. Event 10210 – forciert Blockprüfungen bei jeder logischen Blockänderung und kann daher zu einer frühzeitigeren Erkennung von Korruptionen führen. Dieser Event ist mit Vorsicht einzusetzen, da er Auswirkungen auf die Performance der gesamten Instanz haben kann. Der Event wirkt nur im Kontext von BenutzerTablespaces, im System-Tablespace sind Blockprüfungen immer aktiv. Event 10211 – wie Event 10210, jedoch werden hier Indexblöcke überwacht – mit identischen Auswirkungen auf die Performance. Event 10212 – wie Event 10210, jedoch wirksam für Cluster-Blöcke. Auch bei diesem Event ist Vorsicht geboten. Die oben angegebenen Events werden sinnvollerweise über die Parameterdatei eingeschaltet und wirken – im Gegensatz zu den dargestellten Techniken von dbms_repair – für die gesamte Instanz. Sie sollten daher – wenn überhaupt – dann nur vorübergehend eingesetzt werden, bis die jeweilige Fehlerquelle – wie etwa ein defekter Plattencontroller – ausgetauscht wurde. Ihr Nutzen besteht lediglich darin, die auftretenden Oracle-Fehler zu unterdrücken. Fehlende Daten können jedoch trotzdem noch zu erheblichen logischen Inkonsistenzen im System führen. Zum Aktivieren dieser Events ist die Instanz neu zu starten, eine dynamische Umschaltung ist nicht möglich. Im folgenden Beispiel wird der Event 10231 für alle Instanzen einer Systemparameterdatei eingeschaltet: ALTER SYSTEM SET EVENT ='10231 trace name context forever,level 10' COMMENT='Skip corrupted blocks during a full table scan' SCOPE=SPFILE;
Nach dem Beheben des Fehlers sollte dieser Event so schnell wie möglich wieder ausgeschaltet werden. Im folgenden Beispiel geschieht dies für alle Instanzen. Auch hier ist wieder ein Neustart jeder Instanz erforderlich:
ALTER SYSTEM RESET event SCOPE=SPILE SID='*'; Die Events 10210, 10211 und 10212 können auch gemeinsam über den Serverparameter db_block_checking = true aktiviert werden. Dieser Parameter kann dynamisch über die jeweilige Session, aber auch für die aktuelle Instanz geändert werden. Es gelten sinngemäß die Empfehlungen der vorangehenden Abschnitte. db_block_cecking sollte nicht verwechselt werden mit db_block_checksum. Letzterer bewirkt die Berechnung einer Prüfsumme, die unmittelbar vor dem Schreiben des betreffenden Blokkes in seinem Cache-Layer abgelegt wird. Nach dem Lesen wird die gespeicherte mit einer über dem aktuellen Inhalt des Blockes berechneten Prüfsumme verglichen. Im Falle einer Korruption weichen die Inhalte voneinander ab. Auch dieser Parameter, der für die Instanz dynamisch geändert werden kann, verhindert und behebt keine Blockkorruptionen.
694
Troubleshooting
12.4.5 Feature-Nutzung und Hochwassermarken Statistiken über die Nutzung von Datenbankmerkmalen sind nicht nur für die Ermittlung korrekter Lizenzkosten wichtig. Auch im Fehlerfall kann es hilfreich sein, über die Nutzung bestimmter Merkmale, wie z.B. PL/SQL Native Compilation, Client-Identifier oder Advanced Replication, informiert zu werden. Wenn das Active Workload Repository konfiguriert wurde, werden dem DBA über die View dba_feature_usage_statistics Statistiken über insgesamt 59 Merkmale ausgegeben. Die Statistiken umfassen u.a. einen Zähler für die Häufigkeit der Nutzung, ein Indikator, ob das Merkmal überhaupt genutzt wurde, sowie Zeitstempel, welche die Erfassungsperioden und -intervalle ausgeben. Die Statistiken werden darüber hinaus in Abhängigkeit von der Version geführt. Die folgende Abfrage ermittelt die Statistiken für alle genutzten Merkmale unter der Version 10.1.0.3: SELECT version, name, detected_usages , to_char(last_usage_date,'dd.mm.yy hh24:mi') last_usage_date , to_char(last_sample_date, 'dd.mm.yy hh24:mi') last_sample_date FROM dba_feature_usage_statistics WHERE currently_used = 'TRUE' AND version = '10.1.0.3.0';
Das Listing zeigt einen Ausschnitt der zurückgegebenen Antwort: VERSION NAME DETECTED_USAGES LAST_USAGE_DATE LAST_SAMPLE_DATE; 10.1.0.3.0 Audit Options 1,00 04.02.05 07:18 04.02.05 07:18 Automatic Segment 6,00 04.02.05 07:18 04.02.05 07:18 Space Management (system)
Neben den Nutzungsstatistiken lassen sich auch diverse Hochwassermarken über die View dba_high_water_mark_statistics abrufen, wie das folgende Beispiel zeigt: SELECT name, highwater, last_value FROM dba_high_water_mark_statistics WHERE VERSIO = '10.1.0.3.0' AND name IN ('DB_SIZE','SESSIONS'); NAME --------------DB_SIZE SESSIONS
HIGHWATER ------------------1.059.061.760,00 19,00
LAST_VALUE -------------917.504.000,00 14,00
12.4.6 Die Arbeit mit Events Ein weiteres wichtiges Hilfsmittel bei der Analyse von Fehlersituationen sind Oracle Events. Oracle Events können genutzt werden, um zusätzliche Debug- und Trace-Informationen zu generieren, das Verhalten von Oracle-Prozessen zu ändern oder Fehlerprüfungen zu beeinflussen. Oracle Events sind nicht zu verwechseln mit den Oracle Wait Events, die in Kapitel 11 besprochen wurden. Der vorliegende Abschnitt gibt eine Einführung in das Thema und listet einige der wichtigsten Events auf, erhebt jedoch nicht den Anspruch auf Vollständigkeit. In jedem Fall ist es empfehlenswert, vor dem Einschalten eines Events sich genau über die technischen Auswirkungen klar zu werden, aktuelle Informationen aus Metalink-Artikeln abzurufen.
Werkzeuge und Fehlersituationen
695
Events können über numerische Bezeichner oder symbolische Namen aktiviert werden. Der Nummernkreis von 10000 bis 10999 ist im Rahmen der Oracle-Fehlermeldungen für diese Zwecke reserviert. Zusätzlich existieren SQL-Klauseln und symbolische Namen, die auf einzelne Event-Nummern verweisen, so verweist z.B. sql_trace, das über alter session aktiviert werden kann, auf den Event 10046. Dieser Event aktiviert das Tracing von SQL-Befehlen. Viele Events werden zusätzlich über Level-Angaben gesteuert, die – in Abhängigkeit von dem jeweiligen Funktionsbereich – den Kontext oder Umfang des Events bestimmen. Der bereits erwähnte Event 10046 beispielsweise kennt folgende Level: Level
Bedeutung
1
Standardverhalten: Tracing der Parse-, Execute- und Fetch-Calls sowie der Zugriffspfade (Explain Plan)
4
wie 1, jedoch werden zusätzlich Bindevariablen und ihre Werte ausgegeben
8
wie 1, jedoch werden zusätzlich Wait Events ausgewiesen
12
höchste Stufe, kombiniert die Ebenen 4 und 8
Tabelle 12.3: Level-Angaben für Event 10046
Viele Events erzeugen Trace-Dateien, die in den Verzeichnissen user_dump_dest oder background_dump_dest mit einer maximalen Größe von max_dump_file_size geschrieben werden. Diese Trace-Dateien sind normalerweise nur für den jeweiligen OracleInstallationsbenutzer lesbar. Über den – nicht dokumentierten – Initialisierungsparameter _trace_files_public mit dem Wert true lässt sich diese Voreinstellung ändern. Events lassen sich inhaltlich in die folgenden Kategorien gliedern: 1. Diagnose-Dumps, die einmalig bestimmte Informationen ausgeben. Hierzu zählt beispielsweise der Dump einer Control-Datei, der über den symbolischen Namen controlf ausgelöst werden kann. 2. On-Error-Dumps geben Diagnoseinformationen im Kontext von vorgegebenen Oracle-Fehlern aus. So lässt sich beispielsweise im Falle eines Deadlocks (ORA00060) der komplette Prozesskontext des auslösenden Prozesses schreiben. 3. Dauerhafte Verhaltensänderungen von Hintergrundprozessen: So kann der SMON-Prozess zum Beispiel über den Event 10269 davon abgehalten werden, das Verschmelzen von freigegebenen Extents innerhalb der Dictionary-managed Tablespaces durchzuführen. 4. Kontinuierliches Schreiben von Diagnoseinformationen: Der bereits erwähnte Event 10046 schaltet die Diagnose ein und schreibt so lange, bis entweder die Session beendet oder der Event explizit ausgeschaltet wird. Syntaktisch können Events auf unterschiedliche Weise aktiviert werden. Die Art der Aktivierung hängt dabei auch von der Kategorie des Events und dem Kontext der beabsichtigten Wirkung ab. Die Syntax ist dabei keinesfalls konsistent, wie die folgenden Beispiele zeigen werden. Dies zeigt sich beispielsweise in der Verwendung von Kommata, die in einigen, aber nicht allen Fällen vor der Level-Klausel erscheinen.
696
Troubleshooting
Über den Serverparameter event lassen sich dauerhafte Einstellungen erreichen. Dieser Weg eignet sich vor allem für die Kategorien 2 und 3. Beim Eintrag in die Parameterdatei ist darauf zu achten, dass alle Event-Parameter entweder hintereinander oder die einzelnen Einstellungen durch Doppelpunkt getrennt hinter einem einzigen Event-Parameter aufgelistet werden! EVENT ='10325 trace name context forever,level 10'
Über die Parameterdatei aktivierte Events werden beim Starten der Instanz in die betreffende Alert-Datei eingetragen. Bei Verwendung einer Serverparameterdatei neuen Stils oder bei Events, die für die Instanz dynamisch verändert werden können, empfiehlt sich der Befehl alter system. Im folgenden Beispiel wird der Event 10325 mit einem entsprechenden Kommentar angegeben, um nach dem Neustart der Instanz aktiviert zu werden: ALTER SYSTEM SET EVENT ='10325 trace name context forever,level 10' COMMENT='Debug tracing of control and rollback' SCOPE=SPFILE;
Sollen mehrere Events auf diese Weise aktiviert werden, müssen die Angaben in einer set event-Klausel angegeben werden, um sich nicht gegenseitig zu überschreiben: ALTER SYSTEM SET EVENT='10325 trace name context forever,level 10:10015 trace name context forever, level 1' COMMENT='Debug tracing of control and rollback' SCOPE=SPFILE;
Events der Kategorie eins, die einmalig und unmittelbar Diagnoseinformationen erzeugen sollen, oder Events der Kategorie vier, die im Rahmen der eigenen Session aktiviert werden sollen, werden in der Regel über alter session-Befehle ein- und ausgeschaltet. Man beachte, dass hier der Parameter event durch die Klausel events (Plural-s) ersetzt wurde: ALTER SESSION SET EVENTS = '942 trace name errorstack';
In dem vorangehenden Beispiel wird für die aktuelle Session beim Auftreten des Fehlers ORA-00942 (table or view does not exist) der Fehlerspeicher (Error Stack) in eine Trace-Datei in user_dump_dest geschrieben. Diese Trace-Datei enthält im Einzelnen: – Informationen über die auslösende Session wie Modul- und Aktionsnamen, Servicename und Session-Identifier – Den auslösenden SQL-Befehl – Eine Liste interner Funktionsaufrufe bis zum Auftreten des Fehlers (Call Stack Trace) – Weitere Speicherauszüge (Memory Dump) des betreffenden Serverprozesses Zusätzlich werden in die Alert-Datei entsprechende Verweise auf die betreffende Trace-Datei geschrieben. Für Analysen sind vor allem die Session-Informationen und der SQL-Befehl wichtig. Events der Kategorie vier müssen explizit ausgeschaltet werden, wenn sie nicht mehr benötigt werden. In unserem Beispiel erledigt dies der folgende Befehl:
Werkzeuge und Fehlersituationen
697
ALTER SESSION SET EVENTS = '942 trace name errorstack off';
Numerische Events, die innerhalb der eigenen Session aktiv sind, lassen sich mit Hilfe der Prozedur dbms_system.read_ev auslesen. Der folgende PL/SQL-Block liefert jedoch im Falle von Events der Kategorie zwei – wie in unserem Beispiel – keine Ergebnisse: DECLARE event_level NUMBER; BEGIN FOR i IN 10000 .. 10999 LOOP SYS.DBMS_SYSTEM.read_ev ( i, event_level ); IF ( event_level > 0 ) THEN DBMS_OUTPUT.put_line ('Event ' || TO_CHAR ( i ) || ' gesetzt auf level '|| TO_CHAR ( event_level )); END IF; END LOOP; END;
Für die Aktivierung von Events, die in spezifischen, fremden Sessions gelten sollen, stehen unterschiedliche Verfahren zur Verfügung. Den allgemein gültigen Ansatz bietet die Prozedur dbms_system.set_ev, mit der prinzipiell jeder geeignete numerische Event gesetzt werden kann. In diesem Zusammenhang sind auch die Prozeduren set_bool_param_in_session und set_int_param_in_session desselben Paketes zu erwähnen, mit denen dynamische Serverparameter im Kontext fremder Sessions verändert werden können. Im folgenden Beispiel wird für die Session mit der Identifizierung 3.441 der Parameter timed_statistics auf true gesetzt und das erweiterte SQL-Tracing über den Event 10046 auf dem Level 12 eingeschaltet: dbms_system.set_bool_param_in_session (4, 441, 'timed_statistics', true); dbms_system.set_ev(72, 166, 10046, 12, '');
Der Event lässt sich in dieser Form ausschalten, indem der Level auf 0 gesetzt wird. Speziell für den Event 10046 bieten sich alternativ die folgenden Prozeduren an: – dbms_system.set_sql_trace_in_session ermöglicht das Ein- und Ausschalten auf dem Standard-Level 1, bei dem keine Bindevariablen und keine Wartezustände protokolliert werden. – Besser, weil vielseitiger, ist dbms_support.start_trace_in_session und – entsprechend – stop_trace_in_session. Hier können alle Level aktiviert werden. Das Paket steht standardmäßig nicht zur Verfügung, sondern muss explizit über die Prozedur dbmssupp.sql15 installiert werden. – Seit der Version 10g kommt in diesem Zusammenhang noch das Paket dbms_monitor hinzu, welches mit Abstand die vielseitigsten Trace-Möglichkeiten bietet und im Rahmen der aktuellen Version den anderen Lösungen vorzuziehen ist. 15 Diese Prozedur findet sich im Verzeichnis $ORACLE_HOME/rdbms/admin.
698
Troubleshooting
Eine weitere Möglichkeit, Events jeder Art zu setzen, stellt das Werkzeug oradebug dar, das aus dem Kontext von SQL*Plus heraus aufgerufen werden kann. Der Funktionsumfang von oradebug geht weit über die in diesem Zusammenhang interessanten Merkmale hinaus. Einen syntaktischen Überblick über die Möglichkeiten erhält man mit oradebug help. Für die Arbeit mit Events sind vor allem die folgenden Klauseln wichtig: – setospid oder setorapid – setzen den Fokus auf einen bestimmten Serverprozess. Die Identifizierung kann dabei über die ID des Betriebssystems oder die Oracle-interne Prozess-ID erfolgen. – event – aktiviert den gewünschten Event für die im ersten Schritt ausgewählten Prozesse. – session_event – aktiviert den gewünschten Event für eine bestimmte Session. Eine typische Analyse über oradebug könnte sich wie folgt abspielen: 01 -- Ermittlung der betreffenden Prozessnummer, hier über den Benutzernamen 02 SQL> SELECT pid orapid, spid ospid 03 FROM v$process WHERE addr IN 04 (SELECT paddr FROM v$session WHERE username = 'SCOTT'); 05 06 ORAPID OSPID 07 ---------- -----------08 18 13056 09 -- Fokussierung von oradebug und Einstellen der Trace-Dateigrösse 10 SQL> oradebug setospid 13056 11 Oracle pid: 18, Unix process pid: 13056, image: oracle@NandaDevi (TNS V1-V3) 12 SQL> oradebug unlimit 13 Anweisung verarbeitet 14 -- Einschalten des Events 10046 15 SQL> oradebug event 10046 trace name context forever, level 8 16 Anweisung verarbeitet. 17 -- Das zu messende Programm arbeitet, ... danach wird 10046 wieder ausgeschaltet 18 SQL> oradebug event 10046 trace name context off 19 Anweisung verarbeitet. Die folgende Tabelle listet die Event-Syntax gruppiert nach den oben genannten vier Kategorien auf: Kategorie
Syntaxbeispiel
1
--Formatierter Dump der Control-Datei alter session set events 'immediate trace name controlf level 10'; -- oder oradebug dump controlf 10
2
event = '60 trace name processstate level 1’
Tabelle 12.4: Event-Syntax nach Kategorien
Werkzeuge und Fehlersituationen
Kategorie
Syntaxbeispiel
3
-- SMON coalescing ausschalten event = '10269 trace name context forever, level 10';
4
-- Rollback-Sgm. Recovery-Informationen bei Startup event = "10015 trace name context forever,level 10"
699
Tabelle 12.4: Event-Syntax nach Kategorien (Forts.)
Abschließend sind in der folgende Tabelle einige typische Events unterschiedlicher Kategorien aufgelistet, die für die Analysearbeit von Interessen sein könnten. Die Tabelle erhebt keinen Anspruch auf Vollständigkeit und verzichtet bei einigen Events auf die Bedeutung der entsprechenden Level-Angaben. Es sei an dieser Stelle noch einmal darauf hingewiesen, dass der Einsatz einzelner Events nur dann sinnvoll und zielführend ist, wenn der Funktionsumfang und die Auswirkungen dem Verantwortlichen voll bewusst sind und durch entsprechende Tests hinreichend verifiziert werden konnten, der Nummerncode, der kann darüber hinaus von Version zu Version geändert werden! Im Zweifelsfall ist mit Events mehr Schaden als Nutzen zu erzielen. Es gibt keine vollständige Dokumentation aller verfügbaren Events. Eine Kurzübersicht mit einigen wenigen, englischen Kommentaren liefert die Message-Datei oraus.msg im Verzeichnis $ORACLE_HOME/rdbms/msg. Diese Übersicht ist allerdings weit davon entfernt, eine ausreichende Beschreibung der einzelnen Events zu liefern. In wenigen Fällen lassen sich zusätzliche Metalink-Beiträge lokalisieren, die genauere Anweisungen zum Einsatz einzelner Events liefern. Diese Beiträge sollten – soweit vorhanden – unbedingt zurate gezogen werden. In vielen Fällen werden Events in enger Zusammenarbeit mit dem Oracle Support zum Einsatz kommen. Da numerische Events den Nummernkreise 10000 bis 10999 belegen, lässt sich über die PL/SQL-Funktion SQLCODE eine Kurzübersicht wie folgt generieren: SET SERVEROUTPUT ON DECLARE err_msg VARCHAR2 ( 120 ); BEGIN DBMS_OUTPUT.ENABLE ( 1000000 ); FOR err_num IN 10000 .. 10999 LOOP err_msg := SQLERRM ( -err_num ); IF err_msg NOT LIKE '%Message ' || err_num || ' not found%' THEN DBMS_OUTPUT.put_line ( err_msg ); END IF; END LOOP; END; / Listing 12.23: Ausgabe numerischer Events mit Kurzbeschreibung
700
Troubleshooting
In ähnlicher Weise kann die Ausgabe über ein Unix-Shell-Skript mit Hilfe des Befehls oerr angezeigt werden: event=10000 while [ $event -ne 10999 ] do event=`expr $event + 1` oerr ora $event done Listing 12.24: Shell-Skript zur Ausgabe numerischer Events
Die folgende Tabelle listet einige numerische Events – mit ihrer englischen Kurzbeschreibung aus der MSG-Datei – auf. Event
Beschreibung (Kurztext aus oraus.msg)
Einsatzgebiet
10015
Undo Segment Recovery
Blockkorruption
10046
enable SQL statement timing
Tuning
10053
CBO Enable optimizer trace
Tuning
10060
CBO Enable predicate dump
Tuning
10269
Don't do coalesces of free space in SMON (setting this event prevents SMON from doing free space coalesces)
Tuning
10501
periodically check selected heap (Level: 0x01 PGA, 0x02 SGA, 0x04 UGA, 0x08 current call, 0x10 user call, 0x20 large allocation pool)
Speicherkorruption
10049
protect library cache memory heaps (Use the OS memory protection (if available) to protect library cache memory heaps that are pinned.)
Speicherkorruption
10104
dump hash join statistics to trace file
Tuning
10131
use v$sql_plan code path for explain plan
Tuning
10231
skip corrupted blocks on _table_scans_
Blockkorruptionen
10233
skip corrupted blocks on index operations
Blockkorruptionen
10232
dump corrupted blocks symbolically when kcbgotten (Action: puts corrupted block in trace file)
Blockkorruptionen
10210
check data block integrity
Blockkorruptionen
10212
check cluster integrity
Blockkorruptionen
10608
trace create bitmap index (Comment: enables analysis of create bitmap index - kkrb row source )
Tuning
10606
trace parallel create index (Comment: enables analysis of parallel create index - kkri slaves)
Tuning
10246
print trace of PMON actions to trace file
divers
Tabelle 12.5: Numerische Beispiel-Events
Sämtliche Events der folgenden Tabelle erzeugen formatierte Dumps der in ihrer Beschreibung genannten Bereiche.
Werkzeuge und Fehlersituationen
Event
701
Beschreibung
Kategorie
controlf
Formatierter Dump der Control-Datei
diverse
heapdump
Speicherdump von SGA (Level: 0x01 PGA, 0x02 SGA, 0x04 UGA)
Speicherkorruption
row_cache
Formatierter Dump des Dictionary Caches des Shared Pools
Speicherkorruption
buffers
Dump der Buffer-Cache (Level 1 header, Level 4 mit Latches, Level 8 mit Warteschlangen
Speicherkorruption
library_cache
Dump des Library Caches des Shared Pools
Speicherkorruption
treedump
Formatierter Dump eines Indexbaumes, Level gibt Objektnummer an
Tuning
Tabelle 12.6: Events der Kategorie 1 mit symbolischen Namen
Das folgende Beispiel zeigt die umfassende Analyse eines SQL-Befehls und die für seine Ausführung notwendigen Operationen. Es bedient sich der folgenden Events: 10046 mit dem Level 12 – um alle Operationen des Befehls mit den ihnen zugeordneten Wartezeiten sowie die Werte möglicher Bindevariablen auszugeben; 10053 – um die internen Berechnungen und Entscheidungen des Optimizers auszugeben sowie 10060 – um die interne Abarbeitung der Prädikate in einer Hilfstabelle mit dem vorgegebenen Namen kkoipt_table zu erfassen. Die erzeugte Trace-Datei wird darüber hinaus mit dem Infix »maxtrace« markiert. Das Skript gibt schließlich den Namen der relevanten Trace-Datei auf Seiten des Servers aus. Diese Datei ist im Anschluss daran über TKPROF oder vergleichbare Werkzeuge zu formatieren. Die Protokolle des CB-Optimizers dagegen werden über TKRPOF nicht mit ausgegeben und müssen direkt in der rohen, d.h., unformatierten Trace-Datei analysiert werden. Wie die Syntax verdeutlicht, ist das Skript über SQL*Plus auszuführen: SET PAGES 50 LIN 100 VER OFF FEED OFF TRIMS ON; SPOOL maxtrace.txt -- Vorbereitung fuer Event 10060 DROP TABLE kkoipt_table; CREATE TABLE kkoipt_table( c1 NUMBER, c2 VARCHAR2(80)); -- Vorlauf ALTER SESSION SET timed_statistics = TRUE; ALTER SESSION SET max_dump_file_size = UNLIMITED; ALTER SESSION SET tracefile_identifier = 'maxtrace'; ALTER SESSION SET sql_trace = TRUE; -- Events schalten ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 12'; ALTER SESSION SET EVENTS '10053 TRACE NAME CONTEXT FOREVER, LEVEL 1'; SELECT TO_CHAR ( SYSDATE, 'DD-MON-RRRR HH24:MI:SS' ) "Beginn" FROM DUAL; SELECT host_name, instance_name
702
Troubleshooting
FROM v$instance; SET term off; ALTER SESSION SET EVENTS '10060 TRACE NAME CONTEXT FOREVER'; -- *** Zu messende(s) Statement(s) @@bib.sql -- *** Ende Statement -- Events etc. wieder ausschalten ALTER SESSION SET EVENTS '10060 TRACE NAME CONTEXT OFF'; SET TERM ON; SELECT TO_CHAR ( SYSDATE, 'DD-MON-RRRR HH24:MI:SS' ) "Ende" FROM DUAL; ALTER SESSION SET EVENTS '10053 TRACE NAME CONTEXT OFF'; ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF'; -- Ausgabe fuer Event 10060 SELECT * FROM kkoipt_table; -SET PAGES 24 LIN 80 VER ON FEED ON TRIMS OFF; -- Ausgabe des Trace-Dateinamens -- (Hinweis:Instanznamen werden immer gross ausgegeben!) SELECT ( SELECT VALUE FROM v$parameter WHERE NAME = 'user_dump_dest' ) || '/' || ( SELECT instance_name FROM v$instance ) || '_ora_' || ( SELECT spid FROM v$process WHERE addr = paddr ) || ( SELECT DECODE ( VALUE, NULL, NULL, '_' || VALUE ) FROM v$parameter WHERE NAME = 'tracefile_identifier' ) || '.trc' raw_sql_trace FROM v$session WHERE audsid = USERENV ( 'SESSIONID' ) / SPOOL OFF; SET PAGES 24 LIN 80 VER ON FEED ON TRIMS OFF; Listing 12.25: Maximale SQL-Analyse über Events
Wie bereits erwähnt, ist TKPROF nicht in der Lage, die Trace-Einträge des Events 10053 zu formatieren. Hier ist die Analyse direkt in der unformatierten Trace-Datei vorzunehmen. Der Event wirk nur dann, wenn die betreffenden SQL-Befehle über den cost based Optimizer optimiert werden und der Befehl neu in den Shared Pool der SGA geladen werden muss (hard parse). Die Einträge, die der Event 10053 in der Trace-Datei vornimmt, sind wie folgt gegliedert:
Werkzeuge und Fehlersituationen
703
1. Nach dem allgemeinen Datei-Header von Trace-Dateien wird der analysierte SQL-Befehl ausgegeben (Sektion QUERY). 2. Im Anschluss daran werden die Bindevariablen ausgegeben, deren Werte der Optimizer für die Ausführung evaluiert (Peeked values of the binds in SQL statement). 3. Es folgen die Serverparameter, die für die Entscheidungen des Optimizers relevant sind (PARAMETERS USED BY THE OPTIMIZER). 4. Ausgabe der Basisstatistiken der zugrunde liegenden Tabellen und ihrer Indizes (BASE STATISTICAL INFORMATION) 5. Berechnung der Kosten für den Zugriff auf die individuellen Tabellen (SINGLE TABLE ACCESS PATH) 6. In den letzten Abschnitten der Trace-Datei werden schließlich die vom Optimizer errechneten Statistiken und Join-Strategien aufgelistet und nach den zu erwartenden Kosten bewertet. Das folgende Listing zeigt Ausschnitte einer Trace-Datei, die mit Hilfe des Events 100053 erzeugt wurde und welche die Arbeit des cost based Optimizers bei Entscheidungsfindung für den optimalen Zugriffspfad dokumentiert. Die Ausschnitte werden jeweils durch drei Punkte (<...>) gekennzeichnet: *** SESSION ID:(11.9) 2005-02-24 19:36:01.540 QUERY select e.last_name, d.department_name from hr.EMPLOYEES e, hr.DEPARTMENTS d where d.department_id = e.department_id *************************************** PARAMETERS USED BY THE OPTIMIZER ******************************** ************************************* PARAMETERS WITH ALTERED VALUES ****************************** db_file_multiblock_read_count = 16 sqlstat_enabled = true ************************************* PARAMETERS WITH DEFAULT VALUES ****************************** optimizer_mode_hinted = false optimizer_features_hinted = 0.0.0 parallel_execution_enabled = true parallel_query_forced_dop = 0 <...> *************************************** BASE STATISTICAL INFORMATION *********************** Table stats Table: DEPARTMENTS Alias: D TOTAL :: CDN: 27 NBLKS: 1 AVG_ROW_LEN: 20 Column: DEPARTMENT Col#: 1 Table: DEPARTMENTS Alias: NDV: 27 NULLS: 0 DENS: 1.8519e-002 FREQUENCY HISTOGRAM: #BKT: 27 #VAL: 27 -- Index stats
D
704
Troubleshooting
INDEX NAME: DEPT_ID_PK COL#: 1 TOTAL :: LVLS: 1 #LB: 25 #DK: 100 LB/K: 1 CLUF: 800 <...> *************************************** OPTIMIZER STATISTICS AND COMPUTATIONS *************************************** GENERAL PLANS *********************** Join order[1]: DEPARTMENTS [ D] EMPLOYEES [ E] Now joining: EMPLOYEES [ E] ******* NL Join Outer table: cost: 3 cdn: 27 rcz: 16 resp: 2 Inner table: EMPLOYEES Access path: tsc Resc: 2 Join: Resc: 56 Resp: 56 Access path: index (join index) Index: EMP_DEPARTMENT_IX TABLE: EMPLOYEES RSC_CPU: 21914 RSC_IO: 2 IX_SEL: 0.0000e+000 TB_SEL: 9.0909e-002 Join: resc: 56 resp: 56 Join cardinality: 52 = outer (27) * inner (107) * sel (1.8172e-002) [flag=0] Best NL cost: 57 resp: 56 <...>
DB/K: 1
Die Trace-Datei enthält eine Reihe von Abkürzungen. Die wichtigsten sind in der folgenden Tabelle zusammengefasst: Abkürzung
Bedeutung
CDN
Kardinalität
NBLKS
Die Anzahl der Oracle-Blöcke unterhalb der Hochwassermarke (Number of Blocks)
NDV
Anzahl der distinktiven Werte (Number of distinct Values)
DENS
Dichtefunktion (Density: 1/NDV oder anders)
FREQUENCY
Value-Based Histogram, Anzahl der Buket = NDV
Tabelle 12.7: Benutzte Abkürzungen für Trace10053
Dump-Befehle im Überblick In manchen Fällen kann es hilfreich sein, eine Auflistung fehlerhafter Bereiche der Datenbank für Analysezwecke zu generieren. Hierfür existiert eine Reihe so genannter Dump-Befehle, die vorgegebene Kontexte in kommentierter und formatierter Form in Trace-Dateien schreiben. Der folgende Abschnitt stellt eine Liste der wichtigsten Dump-Befehle dar. Die detaillierte Analyse der durch diese Befehle erzeugten Trace-Dateien und der in ihrem Kontext benutzten Abkürzungen sprengt den Rahmen dieses Buches. In diesem Zusammenhang sei auf die entsprechende Metalink16-Dokumente verwiesen. Zusätzlich zu den hier genannten Dump-Befeh16 www.metalink.com – die offizielle Supportseite von ORACLE
Werkzeuge und Fehlersituationen
705
len lassen sich Dumps auch über einige Event-Nummern generieren. Wie die Events schreiben auch die folgenden Dump-Befehle ihre Informationen in TraceDateien von user_dump_dest. alter system dump datafile block min block max ; – generiert formatierte Block-Dumps eines Blockbereichs einer vorgegebenen Datendatei. Sind formatierte Dumps – z.B. wegen Blockkorruptionen – nicht mehr möglich, kann die Ausgabe über den Event 10289 auch im HEX-Format initialisiert werden: -- Einschalten ALTER SESSION SET EVENTS '10289 trace name context forever, level 1'; -- Ausschalten ALTER SESSION SET EVENTS '10289 trace name context off';
alter system dump undo header ; – erzeugt einen formatierten Dump des Header-Blocks des angegebenen Rollback-Segments. alter system dump undo block xid ; – erzeugt eine Auflistung aller Undo-Daten einer vorgegebenen Transaktion. Die Kennung der Transaktion erfolgt über den Namen und die Nummer des zugeordneten Rollback-Segments sowie den Index (slot) und die Versionsnummer (wrap) des entsprechenden Eintrags in der Transaktionstabelle des Segments. Die können über die folgende Abfrage ermittelt werden: SELECT s.username, r.NAME, t.xidusn, t.xidslot, t.xidsqn FROM v$transaction t, v$session s, v$rollname r WHERE r.usn = t.xidusn AND s.saddr = t.ses_addr;
Die Prozedur dbms_space_admin.segment_dump – erzeugt Dumps der Header-Blöcke des angegebenen Segments. alter system dump logfile ; – generiert eine Trace-Datei mit den Inhalten der angegebenen Log-Datei. Error Dumps Wie bereist erwähnt wurde, ist es möglich, Events in Abhängigkeit von Oracle-Fehlermeldungen zu aktivieren. Prinzipiell kommen hierfür alle Meldungen des Kernels, d.h. alle ORA-Fehler in Frage. In Abhängigkeit von dem betreffenden Fehler lassen sich unterschiedliche Aktionen definieren: errorstack – gibt beim Auftreten des spezifizierten Fehlers, neben dem SQL-Befehl, den genauen Fehlerkontext aus. Der Detaillierungsgrad wird über die Level-Klausel geregelt: 1 entspricht der Ausgabe des Call Stack Trace; 2 gibt zusätzlich noch den Prozesskontext aus. processstate – gibt den kompletten Prozesskontext der verursachenden Datenbanksitzung, nicht aber den Error Stack aus. Der Detaillierungsgrad ist auch hier über die Level-Klausel regelbar.
706
Troubleshooting
systemstate – schreibt den kompletten Systemkontext, d.h. den Inhalt der SGA und die Kontexte sämtlicher Sitzungen, in eine Trace-Datei. Die Datei ist in der Regel sehr umfangreich und aus diesem Grunde für eine genaue Fehleranalyse nur in Ausnahmefälle geeignet. Error Dumps können sowohl permanent über entsprechende Event-Parameter oder auch temporär im Kontext einer Sitzung oder der Instanz aktiviert werden. In den folgenden Beispielen wird auf unterschiedliche Weise das Generieren einer DumpDatei bei Auftreten des Fehlers ORA-00942 – table or view does not exist aktiviert: -- Variante 1, einschalten alter system set events '942 trace name errorstack level 1'; -- Ausschalten alter system set events '942 trace name errorstack off'; -- Variante 2 alter session set events '942 trace name processstate level 2'; -- Variante 3, dauerhaft über Init.ora event='942 trace name errorstack level 2';
Fehler, die in aktiven Event-Kontexten stehen, werden darüber hinaus in der AlertDatei protokolliert. flash freeze Um komplexe Fehler und Hang-Situationen besser analysieren zu können, gibt es die Möglichkeit, Instanzen über flash freeze in definierbaren Kontexten »einzufrieren«. Hierbei werden – wie der Name nahe legt – alle beteiligten Prozesse angehalten und auf diese Weise verhindert, dass »flüchtige« Fehlersituationen dem Analysten entgehen. Flash freeze kann manuell über das oradebug-Kommando von SQL*Plus oder Event-gesteuert aktiviert werden. Die folgenden Beispiele dokumentieren die manuelle Nutzung: SQL> oradebug ffbegin Anweisung verarbeitet -- Friert die Instanz ein. Schreibt alle Aktionen in das Alert-Log -- Debug-Informationen können nun abgerufen/dokumentiert werden SQL> oradebug ffstatus Anweisung verarbeitet -- Schreibt den aktuellen Status von Flash Freeze in das Alert-Log SQL> oradebug ffresumeinst Anweisung verarbeitet -- Hebt Flash Freeze wieder auf. Normaler Datenbankbetrieb
In den Fällen, in denen Fehler in typischen Kontexten auftreten, ist es sinnvoller, flash freeze über die Event-Steuerung einzuschalten, weil auf diesem Wege explizite Rahmenbedingungen formuliert werden können, die flash freeze aktivieren. Im folgenden Beispiel wird flash freeze beim ersten Auftreten des internen Fehlers ksuwaitsysevent_1 aktiviert: event=“600 flashfreeze after 1 times on error ksuwaitsysevent_1“
Werkzeuge und Fehlersituationen
707
Im zweiten Beispiel wird die Instanz eingefroren, wenn im Kontext des PMON-Prozesses der interne Fehler 1301 auftritt: event=“600 flashfreeze on error 1301,proc=PMON“
Hanganalyze Hanganalyze ist ein Werkzeug mit dem sich Hang-Situationen einer Oracle-Datenbank dadurch analysieren lassen, dass Detailinformationen blockierender Ressourcen in Trace-Dateien geschrieben werden. Hang-Situationen können durch interne Deadlocks oder – ganz allgemein – durch gegenseitige Abhängigkeiten unterschiedlicher Datenbankprozesse entstehen. Im Gegensatz zu Deadlocks im Kontext von benutzergesteuerten DML-Aktionen werden interne Deadlock nicht immer automatisch aufgelöst. Hang-Situationen können zu erheblichen Wartezeiten der involvierten Sitzungen führen, dürfen aber nicht mit allgemeinen Performance-Problemen verwechselt werden, die in der Regel durch unbarmherzigen Gebrauch von Systemressourcen entstehen. Das Werkzeug Hanganalyze wurde bereits in der Version 8.1.6 eingeführt und unter der Version 9 dahingehend erweitert, dass auch Cluster-Installation unterstützt werden. Hanganalyze wird – wie die bereits vorgestellten Events – über den EventParameter oder den oradebug-Befehl aktiviert und im Detail über Level parametrisiert. Das folgenden Syntaxbeispiel zeigt die Aktivierung des Events über die eigene Session. Die Hang-Informationen werden natürlich im Rahmen der gesamten Instanz ausgewertet: ALTER SESSION SET EVENTS 'immediate trace name hanganalyze level 2';
Alternativ kann Hanganalyze auch über den oradebug-Befehl von SQL*Plus aktiviert werden. Im folgenden Beispiel wird der Level 3 eingeschaltet: SQL> oradebug hanganalyze 3 Hang Analysis in /app/oracle/admin/T10G/udump/t10g_ora_5200.trc
Es stehen folgende Level zur Verfügung: Level 1 und 2 generieren eine minimale Ausgabe ohne Prozesskontexte. Level 3 gibt zusätzlich zu Level 2 noch die Prozesskontexte aller Prozesse aus, die sich in einer Hang-Situation befinden. Level 4 gibt zusätzlich zu Level 3 alle blockierenden Prozesse aus. Level 5 gibt zusätzlich zu Level 4 alle in Warteschlangen befindlichen Prozesse aus, und der höchste Level 10 schließt alle Prozesse der Instanz mit ein. Es versteht sich, dass Trace-Dateien, die von Level 3 aufwärts generiert werden, sehr umfangreich und damit schwer interpretierbar werden können.
708
Troubleshooting
Die von Hanganalyze generierte Ausgabedatei betrachtet abhängige Sessions bzw. Prozesse einer Instanz aus unterschiedlichen Perspektiven und gliedert sich im Wesentlichen in die folgenden Abschnitte: 1. cycles – listet Prozesse auf, die sich in Deadlock-Situationen befinden. 2. blocker of many sessions – zeigt Prozesse die mehr als zehn weitere Sessions blockieren. 3. open chains – gibt alle Prozesse an, die sich in Wartezuständen befinden. 4. state of nodes – gibt alle Prozesse und ihre Status wieder. 5. Abhängig vom benutzten Level können zusätzlich Prozessinformationen (Process Dumps) auftauchen.
Hochverfügbarkeit 13.1
Einleitung
Durch das Internet, Globalisierung und die geänderten Lebensgewohnheiten der Menschen ist es immer schwieriger für Systeme, die in diesem Umfeld eingesetzt werden, eine Auszeit zu finden. Als Beispiele seien hier drei Anwendungen herausgegriffen, die jede eine unterschiedliche Anforderung im Lastprofil und im Benutzerverhalten haben. Zunächst einmal ein System, auf dem die Benutzernamen und Passwörter für ein kommerzielles E-Mail-System gespeichert sind. Das Datenvolumen ist eher klein, die Verwaltung von 50 Millionen Teilnehmern kann in einer Oracle-Datenbank sicherlich mit weniger als 20 GB Datenvolumen auskommen. Die Änderungshäufigkeit ist ebenfalls gering; nur wenn neue Benutzer hinzukommen, ihr Kennwort ändern oder irgendwelche Basisdaten gepflegt werden müssen, fallen Änderungen an. Allerdings gibt es sicherlich einige Pflegeroutinen, die umfangreiche Änderungen durchführen, z.B. den Aufbau einer Struktur für die neuen Domain-Richtlinien. Da die hier gespeicherten Daten keine realen Kosten verursachen, kann der Ausfall des Systems nur unter dem Gesichtspunkt der Reputation des Unternehmens betrachtet werden. Wie viele Kunden wandern ab, wenn das E-Mail-System nicht zur Verfügung steht, weil man sich nicht anmelden kann? Das nächste System ist schon etwas größer, hier werden Daten gespeichert, die eine Möbelproduktion steuern. Da es sich um einen großen Fabrikanten handelt, werden hier ca. 200 GB an Daten in der Datenbank gespeichert. Das Änderungsvolumen ist enorm, so dass pro Tag ca. 10 GB an Redo-Log-Dateien anfallen. Die Verfügbarkeit an Werktagen ist hochkritisch, da die Produktion zu 100% auf die Daten aus der Datenbank angewiesen ist. An Feiertagen sind jedoch Wartungsarbeiten ohne Einschränkung möglich. Beim dritten System kommen wir zu dem heute wichtigsten Markt für uns alle: die Mobilfunkanbieter. In einem System, das die Gesprächsdaten aufzeichnet, fallen schnell mehrere Terabyte an Daten an. Das Änderungsvolumen durch neue Calls ist riesig, und zusätzlich müssen permanent Daten aus dem System gelöscht werden. Zum einen, um überhaupt noch mit dem Volumen umgehen zu können, zum anderen aber, da Gesprächsdaten laut deutscher Rechtsprechung nur maximal 90 Tage aufbewahrt werden dürfen, bevor sie anonymisiert werden müssen. Dass dieses System zu keiner Zeit ausfallen darf, steht außer Frage. Dabei sind die Kosten, die ein Ausfall verursacht, leicht messbar anhand der Gesprächskosten, die für diesen Zeitraum nicht erfasst werden können.
710
Hochverfügbarkeit
Schon in diesen drei Fällen wird deutlich, dass es die eine Lösung für die Hochverfügbarkeit eines Systems nicht geben kann, es sei denn, man hat beliebig viel Geld zur Verfügung – und wer hat das schon ?
13.2
Hardware-Architekturen
Hardware-Architekturen können in folgende Kategorien eingeteilt werden: Speicher Server (CPU, Memory, Controller) Infrastruktur
13.2.1 Speicher Auch wenn oft der Server an erster Stelle genannt wird, ist es doch der Speicher, der in einer ersten Stufe ausfallsicher ausgelegt werden wird. Ziel ist es, eine physikalische Festplatte so auszulegen, dass ein Hardware-Fehler nicht zu einem Datenverlust führt. Dies sollte für alle, die eine produktive Oracle-Datenbank betreiben, die oberste Prämisse sein. Ausfälle, die dazu führen, dass Daten verloren gehen, sind für kaum ein Unternehmen tolerierbar, und der verantwortliche Datenbankadministrator wird sicherlich gefragt werden, warum er nichts dagegen unternommen hat. Ausfallsichere Speicher reichen von Raid-5-Systemen, die in der Regel aus vier Festplatten bestehen, die über eine Paritätsinformation so ausgelegt sind, dass eine Platte ausfallen kann und die dadurch fehlende Information aus den verbleibenden Platten zurückgewonnen wird. Da es sich hier um eine softwaretechnische Implementierung handelt, ist damit zu rechnen, dass es Zeit kostet, eine solche Information zu schreiben. Beim »normalen« Lesen hingegen braucht ja die Paritätsinformation nicht berücksichtigt zu werden, d.h., der Lesevorgang wird über alle vier Festplatten verteilt. Somit ergibt sich automatisch eine gute Verteilung der I/OLast bei lesenden Zugriffen. Die nächsthöhere Stufe wird durch ein Raid-1-System erreicht. Hierbei werden alle Daten redundant auf zwei Festplatten abgelegt. Das bedeutet, dass bei schreibenden Zugriffen die Festplattencontroller die Aufgabe übernehmen, die Daten redundant zu halten, eine Software ist also nicht erforderlich. Bei lesenden Zugriffen können die Daten wahlweise von einer der beteiligten Platten gelesen werden, so dass hier eine leichte I/O-Verteilung möglich ist. Allerdings wird in diesem einfachen Fall ein Raid-5-System schneller als das Raid-1-System sein. Vorteilhaft bei kleineren Installation ist noch, dass man tatsächlich nur zwei Festplatten braucht – die ja in der Regel mehr als 100 GB groß sind – im Gegensatz zu den vier Festplatten bei Raid-5.
Hardware-Architekturen
711
Bei größeren Systemen wird man die Raid-1-Systeme noch erweitern und ein kombiniertes Raid-01 aufbauen. Raid-0 ist keine Hochverfügbarkeit – im Gegenteil eher eine geringere Verfügbarkeit –, sondern eine Verteilung der Daten für eine optimale Performanz. Dies wird erreicht, indem die Daten in so genannten Slices auf unterschiedliche Festplatten verteilt werden. Diese Slices sind in der Regel zwischen 64 KB und 1 MB groß, so dass der Zugriff jetzt optimal auf mehrere Platten verteilt werden kann. Oracle propagiert diese Methode mit der S.A.M.E.-Architektur (Stripe And Mirror Everything), d.h., alle Daten werden über alle verfügbaren Platten verteilt und gespiegelt. Verwechseln Sie diese Methode nicht damit, alle Ihre Daten in einem Tablespace zu verwalten – hier geht es ausschließlich um die Verfügbarkeit und Performance, nicht aber um die Administrierbarkeit der Datenbank. Tipp: Verwenden Sie Raid-10 und nicht Raid-01. Der Unterschied ist, dass bei Raid-01 zuerst ein Stripe-Set über alle Platten gebildet und dieses dann gespiegelt wird. Das bedeutet, wenn eine beteiligte Platte ausfällt, ist ein komplettes Stripe-Set betroffen. Raid-10 spiegelt zunächst die Platte und bildet dann die Stripe-Sets, so dass jetzt beim Ausfall einer Platte nur diese gespiegelte Platte nicht mehr redundant arbeitet, der Rest aber immer noch gespiegelt ist. Einige Hardware-Hersteller bieten weitere Verfahren an, die sich aber im Wesentlichen auf diese Methoden reduzieren lassen. Die nächsthöhere Verfügbarkeit ist zwar immer noch im Umfeld Raid-1 zu finden, bedeutet aber, dass die Spiegelung in einen anderen Speicherschrank bzw. an einen anderen Ort erfolgt. Dabei können unter Umständen mehrere Kilometer zwischen den gespiegelten Systemen liegen, was aber natürlich zu Lasten der Performance geht, da hierbei die Latenzzeit nicht zu vernachlässigen ist. Außerdem haben einige Hardware-Hersteller hier Einschränkungen bezüglich der Verfügbarkeit des entfernten Plattensystems, da die Spiegelung im Master-Slave-Prinzip erfolgt, d.h., schreibend darf nur auf den Master zugegriffen werden. Dieser versorgt dann den Slave mit den Daten. Mehrfache Redundanzen bieten sich dann an, wenn die Plattenspiegelung zusätzlich für Backups oder den Aufbau nachgelagerter Systeme (Data-Warehouse) genutzt werden sollen. Eine weit verbreitete Methode sind hierbei die BCVs (Business Contiguous Volumes), welche die Firma EMC für ihre Symmetrix- und Clariion-Modelle anbietet. Damit kann ein Spiegel aus dem normalen Betrieb herausgelöst und als Basis für ein Backup oder eine neue Datenbank genutzt werden. Nach Beendigung der Arbeit wird der Spiegel wieder synchronisiert, was in der Regel in kürzester Zeit möglich ist, da nur die geänderten Betriebssystemblöcke ausgetauscht werden. Das in Oracle 10g zur Verfügung gestellte Automatic Storage Management (ASM) ist eine Raid-10-Implementierung.
712
Hochverfügbarkeit
13.2.2 Server Im Gegensatz zum Speicher, bei dem in erster Linie die Vermeidung von Datenverlusten im Vordergrund steht, geht es bei den Servern um die Reduzierung der Ausfallzeiten. Im einfachsten Fall gibt es einen weiteren Server, auf dem die OracleSoftware installiert ist. Fällt der Produktionsrechner aus, wird das Speichersystem abgekoppelt und an das neue System angeschlossen. Danach kann die Anwendung wieder hochgefahren werden. Obwohl diese Methode durchaus funktioniert, kann an dieser Stelle nur davor gewarnt werden! Der Grund: »Warum wollen Sie ein System hochverfügbar auslegen?« – »Weil im Fehlerfall die Anwendung schnell wieder zur Verfügung stehen soll.« Ein Fehlerfall ist immer ein Prozess, bei dem der Adrenalinspiegel in die Höhe schnellt und alle Beteiligten Stress mit den Anwendern, den Managern und eventuell sogar direkt mit den Kunden haben. In diesem Fall jemanden zu beauftragen, bestimmte Stecker umzustecken, ist sehr gefährlich und kann im ungünstigsten Fall dazu führen, dass auch noch das Speichersystem ausfällt, z.B. weil Festplatten falsch angehängt wurden und es beim Hochfahren der Datenbankinstanz zu einer Korruption der Datenbankdateien kommt. Da dieser Fehler hardware-technisch nicht zu beheben ist, kann das zu einem Ausfall von mehreren Stunden führen. Wer es nicht glaubt, hier ein Beispiel aus unserer Praxis: In einem Raid-1-Speichersystem fiel eine Festplatte aus. Der Techniker kam, tauschte im laufenden Betrieb die defekte Festplatte durch eine neue aus und spiegelte anschließend – weil das tatsächlich manuell geschehen musste – die neue Festplatte auf die noch laufende. Damit war die Datenbank zerstört und musste umständlich wieder zurückgesichert werden. Wenn also der Server redundant ausgelegt werden soll, dann bitte mit einer kombinierten Hard- und Software-Lösung, bei der im Fehlerfall eine automatische Übernahme des Speichers und der Wiederanlauf der Anwendung auf dem verbliebenen Rechner erfolgen kann. Diese HA(High Availability)-Lösungen gibt es heute für alle Systeme (Unix, VMS, MVS, MS-Windows), und Oracle ist auf solchen Systemen unproblematisch zu installieren und zu betreiben. Für MS-Windows-Systeme gibt es hierfür eine spezielle Oracle-Lösung mit dem Namen Failsafe, welche die Einbindung von Oracle-Datenbanken in die MS-Windows-Cluster-Technologie erlaubt. Diese Systeme können jetzt im Zusammenspiel mit den Speichersystemen über Standorte verteilt und somit auch für ein so genanntes Desaster Recovery (DR) genutzt werden. In einem solchen – hoffentlich nie eintreffenden – Fall fällt ein gesamtes Gebäude aus (z.B. durch Stromausfall, Brand etc.), und der Betrieb wird über das Ausfallrechenzentrum weitergeführt. Wenn der Rechner schon redundant ausgelegt ist, d.h., ein zusätzlicher Rechner gekauft und so konfiguriert ist, dass er im Fehlerfall die Last des Produktionssystems übernehmen kann, dann ist die Frage, ob nicht die beteiligten Rechner in einem Verbund arbeiten können. D.h., während der »normalen« Zeit werden die Anwendungen auf die Rechner verteilt; fällt ein System aus, muss das andere System – oder die anderen Systeme – diese Last mit übernehmen. Und damit sind wir bei der Oracle-Lösung Real Application Clusters.
Oracle Real Application Clusters
713
Weitere Informationen bezüglich der Auswahl und dem Betrieb von hochverfügbaren Systemen im Oracle-Umfeld finden Sie auch in dem Buch »Oracle 10g Hochverfügbarkeit« von Andrea Held.
13.2.3 Infrastruktur Zum Betrieb einer Anwendung gehört neben dem Datenbank- und Anwendungsserver aber sicherlich auch das Netzwerk. Die höchste Verfügbarkeit der Server bringt Ihnen wenig, wenn Sie nur einen Router benutzen, über den sämtliche Anwender mit der Datenbank bzw. dem Applikationsserver kommunizieren. Auch Leitungen, die aus dem Gebäude herausgehen bzw. auf öffentlichem Grund liegen, müssen redundant ausgelegt werden, damit Sie nicht beim nächsten Straßenbau ohne Netzwerk sind. Oracle kann mit Hilfe der Oracle Net-Konfiguration hier eine kleine Hilfe sein, im Wesentlichen sind es aber die Hardware- und Diensteanbieter, die hierbei für eine redundante Anbindung sorgen müssen. Last but not least gehört zum Betrieb einer Hochverfügbarkeitslösung auch, dass es mehr als einen Datenbankadministrator geben muss, denn die am häufigsten auftretenden Fehler sind Anwender- bzw. Anwendungsfehler. Und dann ist jede noch so hochverfügbare Hardware überfordert.
13.3
Oracle Real Application Clusters
Die Idee einer hochverfügbaren Datenbank hatte Oracle bereits Anfang der Neunzigerjahre mit einer speziellen Oracle Version 6.2 für Digital VMS-Systeme. In dieser Architektur greifen zwei oder mehrere Instanzen auf eine gemeinsame Datenbank zu. In den Versionen Oracle7, Oracle8 und Oracle8i wurde das Prinzip des Oracle Parallel Servers (OPS) auf andere Systeme ausgeweitet. Warum also mit den Versionen 9i und 10g der Wechsel zum Real Application Clusters? Die Oracle Cluster-Implementierung ist von jeher eine so genannte Shared DiskKonfiguration, d.h., die physikalischen Festplatten werden von mehreren Systemen gleichberechtigt benutzt, es gibt keine Vorrechte eines Knotens. Das bedingt aber, dass es eine übergeordnete Instanz geben muss, welche die Daten des Hauptspeichers überwacht. In der Vergangenheit war dies der Distributed Lock Manager (DLM), der alle Datenbankressourcen verwaltet hat. Diese Implementierung führte aber dazu, dass Datenbankblöcke, die von einer auf eine andere Instanz transferiert werden mussten, zunächst wieder auf die Platte geschrieben wurden. Die dadurch verursachten Schreib- und Lesezugriffe bezeichnete man als Pinging, und es liegt auf der Hand, dass die Performance einer solchen Lösung entscheidend davon abhängt, wie viele Daten zwischen den Instanzen hin und her transportiert werden müssen. Eine Anwendung, die eine solche Struktur nutzen will, muss speziell dafür entwickelt bzw. angepasst werden. Optimal ist diese Lösung, wenn unterschiedliche Anwendungen mit einer Datenbank arbeiten, sich aber aufgrund unterschiedlicher Schemata oder zumindest Tabellen nicht »in die Quere« kommen.
714
Hochverfügbarkeit
In der Version 8i hat Oracle versucht, dieses Prinzip aufzuweichen. Die Neuentwicklung nannte sich Cache Fusion und wurde in dieser Version dazu genutzt, Datenbankblöcke über das Netzwerk zwischen den Rechnern hin und her zu schicken. Leider gab es in Version 8i die Einschränkungen, dass nur lesende Zugriffe diesen Mechanismus nutzen konnten. War ein Block von einer Datenbankinstanz geändert worden, musste er erst auf die Platte geschrieben werden, bevor er der anderen Instanz zur Verfügung gestellt werden konnte. Die zugrunde liegende Architektur scheint mit Version 8i an ihre Grenzen gestoßen zu sein, so dass sich Oracle mit Version 9i entschlossen hat, fast die gesamte Cluster-Software neu zu schreiben. Daher auch der mit Oracle9i eingeführte neue Name Real Application Clusters im Gegensatz zur vorherigen Implementierung Oracle Parallel Server. Grundlage für den Betrieb einer Real Application Clusters-Datenbank bildet der Cluster-Manager. In der Version 9i wurde diese Software in der Regel vom Hardware-Hersteller zur Verfügung gestellt, was dazu führte, dass es ganz spezielle – vom Hersteller zertifizierte – Komponenten für den Betrieb einer RAC-Datenbank gab. Einzige Ausnahmen waren der Betrieb unter Linux, bei dem Oracle den ClusterManager mitlieferte, und MS-Windows, wobei Oracle nur die Basiskomponenten von Microsoft benötigte. In der Version 10g liefert Oracle jetzt alle Komponenten für den Betrieb einer RACDatenbank aus, d.h. auch den Cluster-Manager und sogar eine spezielle Dateisystem-Implementierung für den Shared Disk-Einsatz (Automatic Storage Management). Wenn Sie also eine RAC-Datenbank aufsetzen möchten, reicht es in der Regel, ein Plattensystem und mindestens zwei, maximal 64 Rechnern zu haben, die gleichberechtigt auf diese Platten zugreifen können. Als Plattensystem bietet sich dabei ein Storage Attached Network (SAN) an.
13.3.1 Architektur In Abbildung 13.1 sind die wesentlichen Komponenten einer Real-ApplicationCluster-Architektur abgebildet. Dazu gehören: Der Cluster-Manager: Er ist für die Kommunikation zwischen den Systemen zuständig. Dazu gehören die Verwaltung und Überwachung der Knoten sowie die Kommunikation zwischen den Instanzen. Die Instanzen: Ein RAC-System besteht aus mindestens zwei und zurzeit maximal 64 Instanzen. Der Grundaufbau einer Instanz unterscheidet sich dabei nicht vom Single-Instance-Betrieb. Die Netzwerkadapter: Für die Kommunikation zwischen den Systemen wird ein separates Netzwerk benötigt (LAN 2). Da hierüber der Cluster-Manager die Ressourcen verteilt, ist es erforderlich, die Bandbreite dieses Netzwerks möglichst groß auszulegen, also mindestens ein Gigabit-Netzwerk. Ob die Kommunikation zum Plattensystem über LAN oder Fibre-Channel erfolgt, ist für die Architektur nicht relevant. Außerdem ist es in Hochverfügbarkeitssystemen in der Regel so, dass die Anwendung ein eigenes (in diesem Fall drittes) Netzwerk benutzt.
Oracle Real Application Clusters
715
Abbildung 13.1: Real-Application-Cluster-Architektur
Das Plattensystem: Auf Basis der heute verfügbaren Plattensysteme (SAN, NAS etc.) kann davon ausgegangen werden, dass die Daten zunächst in einem batteriegepufferten Cache landen. Auch die Verteilung der Daten auf die Festplatten übernimmt in der Regel das Plattensystem selbst. Daher ist der von Oracle verfolgte Ansatz Stripe and Mirror Everything (SAME) in dieser Konstellation sicherlich der effektivste. Die einzelnen Datenbereiche finden sich dementsprechend auf dem Plattensystem wieder. Oracle Portable Clusterware Die Oracle Portable Clusterware (Oracle Clusterware) ist die Kernkomponente für die Oracle 10g Real-Application-Cluster-Implementierung. Die Software stand in ähnlicher Form schon in Oracle9i für MS-Windows und Linux zur Verfügung, wurde aber für Oracle 10g nochmals überarbeitet. Grundlage bildet der von Digital bzw. Compaq entwickelte Cluster-Manager, dessen Quellcode Oracle gekauft und weiterentwickelt hat. Die Clusterware hat die Aufgabe, die Hinzunahme oder den Ausfall einer am Cluster beteiligten Komponente (Knoten oder Interconnect) zu erkennen und eine entsprechende Rekonfiguration durchzuführen. Ein wichtiger Aspekt hierbei ist ein so genannter Split Brain. In diesem Fall arbeiten zwar alle Cluster-Knoten, können aber nicht mehr miteinander kommunizieren. Wenn es keine übergeordnete Instanz gibt, die dafür sorgt, dass ein Knoten heruntergefahren wird, kann es in dieser Situation zu Korruptionen in der Datenbank kommen. Die Oracle Clusterware besteht im Wesentlichen aus zwei Schichten.
716
Hochverfügbarkeit
Oracle Cluster Synchronisation Service (CSS): Dieser verwaltet die Mitglieder des Cluster-Verbunds und stellt die Kommunikationsebene für die Knoten zur Verfügung. Wenn bereits ein Cluster-Manager (z.B. Veritas Cluster, HP MC/Service Guard, IBM HACMP etc.) im Einsatz ist, so bildet diese Komponente die Schnittstelle und übernimmt die Informationen von diesem. Cluster Ready Service (CRS): Dieser bildet das Herzstück der Hochverfügbarkeit, denn er sorgt für die Schnittstelle innerhalb des RAC-Aufbaus. Er kommuniziert mit den Instanzen und stellt eine virtuelle IP-Adresse für jeden Cluster-Knoten zur Verfügung. Im Fehlerfall stellt er die Instanzverfügbarkeit sicher und versucht, Prozesse, die beendet wurden, nachzustarten. Außerdem gibt es noch den Event Manager (EVM), der im Fehlerfall Events auslöst. Leider gibt es zu diesem Prozess kaum weitere Informationen. Eine Einschränkung gibt es allerdings bei der Verwendung der Oracle Clusterware. Im Gegensatz zur Clusterware von Drittherstellern wird nur die Oracle-Datenbank überwacht, nicht aber andere Komponenten. Wenn also z.B. Anwendungen auf einem Cluster-Knoten arbeiten, die im Fehlerfall »geschwenkt« werden müssen, so kann dies noch nicht mit der Oracle Clusterware geschehen. Hier ist dann der Einsatz eines unabhängigen Cluster-Managers nötig. Eine globale IP-Adresse, wie bei anderen Implementierung, gibt es bei der Oracle Clusterware ebenfalls nicht, da über Oracle Net andere Methoden für Load Balancing und Application Failover genutzt werden. Hardware und Betriebssystem Welche Hardware und welches Betriebssystem Sie einsetzen wollen, bleibt bis auf die Mindestanforderungen bezüglich Netzwerk und Plattensystem Ihnen überlassen. Sicherlich kann gerade die Unterstützung von Linux in diesem Umfeld ein Kriterium sein, da es damit erstmals möglich ist, mit minimalen Kosten eine hochverfügbare Lösung aufzubauen. Aber bitte lassen Sie sich dadurch nicht täuschen! Hochverfügbarkeit ist, wie bereits erwähnt, eine sehr komplexe Aufgabenstellung, und daher sollte an den entscheidenden Punkten nicht gespart werden. Nichtsdestoweniger kann speziell für Tests eine RAC-Installation mit Linux interessant sein. Die Systeme sollten in jedem Fall über ausreichend Hauptspeicher (mind. 512 MB je System) verfügen. Außerdem werden wie bereits erwähnt mindestens zwei Netzwerkkarten benötigt, unabhängig davon, welche Anbindung der Plattenperipherie Sie einsetzen wollen. Je nach Betriebssystem gibt es zusätzliche Abhängigkeiten, z.B. Einschränkungen bezüglich der Transportprotokolle für die Festplatten (SCSI, iSCSI, Fibre Channel etc.). Die genauen Informationen finden Sie im Oracle-Metalink z.B. unter Real Application Clusters Certification.
Oracle Real Application Clusters
717
13.3.2 Lage der Datendateien Mit Oracle 10g gibt es drei unterschiedliche Arten, Dateien abzulegen: Raw Devices: Über die Basisschnittstelle des Betriebssystems werden bestimmte Bereiche (Partitionen) auf der Festplatte bzw. dem Volume-Manager zur Verfügung gestellt. Die Partitionen haben eine feste Größe und sind dem Betriebssystem nicht weiter bekannt. Oracle Cluster Filesystem (OCFS): Dieses von Oracle mit der Version 9i zur Verfügung gestellte Dateisystem stellt für unterschiedliche Betriebssysteme ein globales Dateisystem zur Verfügung. Automatic Storage Management (ASM): Diese bereits besprochene Art erlaubt die Verwaltung aller Oracle-Strukturen in einem einheitlichen Dateisystem. Dabei stellt das Betriebssystem wie bei Raw Devices nur die Partitionen zur Verfügung. Die folgende Tabelle zeigt einige Vor- und Nachteile der einzelnen Varianten: Art
Vorteil
Nachteil
Raw Devices
Kein Betriebssystem-Overhead
Komplizierte Administration
Hohe Performance
Kein Autoextend von Dateien möglich
Keine zusätzliche Software
Unflexibel Kein Schutz vor Überschreiben (z.B. Neuanlage eines Dateisystems) Striping und Mirroring nur über zusätzliche Hard- oder Software OCFS
Einfache Administration
Zusätzliche Software
Kann auch für »Nicht-Oracle«-Dateien genutzt werden
Nicht für alle Plattformen verfügbar
Im Betriebssystem integriert
Betriebssystem-Caching und damit Overhead Langsam Striping und Mirroring nur über zusätzliche Hard- oder Software
ASM
Kaum Betriebssystem-Overhead
Zusätzliche Software
Hohe Performance (Vergleichbar mit Raw Devices)
Eigene Instanz mit Verwaltung
SAME-Implementierung (Stripe and Mirror Everything)
Backup nur mit RMAN möglich
Keine zusätzlichen Kosten (in allen Oracle-Versionen enthalten)
Nur mit Oracle-Mitteln zu Verwalten Nur »Oracle-eigene« Dateien Kein Schutz vor Überschreiben (z.B. Neuanlage eines Dateisystems)
Tabelle 13.1: Vergleich der Dateiarten für Real Application Clusters
718
Hochverfügbarkeit
Der Vergleich zwischen Raw Devices und ASM gilt in diesem Fall auch für SingleInstance-Datenbanken, denn auch hier können diese Implementierungen zum Einsatz kommen. Zusätzlich zur Speicherungsart sind natürlich auch im RAC-Betrieb die grundsätzlichen Kriterien zur Lage der Daten-, Redo-Log- und archivierten Redo-Log-Dateien sowie der Backups zu beachten. Einziges Augenmerk gilt noch der Lage der Software, d.h., ob es ein gemeinsames ORACLE_HOME (Shared) oder je Knoten ein eigenes ORACLE_HOME (Private) geben soll. Die Shared-Installation hat den Vorteil, dass die Software nur einmal existiert und damit die Installation schneller durchgeführt werden kann. Dem steht allerdings ein gravierender Nachteil gegenüber: Beim Einspielen eines Patches müssen alle Instanzen gleichzeitig beendet werden, ein so genanntes Rolling Upgrade, wie es ab Oracle9i bei bestimmten Patches möglich ist, kann nicht durchgeführt werden. Außerdem brauchen Sie dafür ein globales Dateisystem. Zurzeit wird ein Shared ORACLE_HOME im OCFS nur für MS-Windows unterstützt. Sicherlich spielt auch eine Rolle, ob es sich um einen Cluster-Verbund mit zwei oder zwanzig Knoten handelt.
13.3.3 Software-Installation Im Folgenden wird am Beispiel des Betriebssystems Linux unter Verwendung von ASM erklärt, wie die Installation durchzuführen ist. Da es je nach Betriebssystem und zusätzlichen Komponenten zum Teil erhebliche Unterschiede gibt, sollten Sie vor der Installation die entsprechende Dokumentation zurate ziehen (z.B. Oracle Real Application Clusters Installation and Configuration Guide) . Die Software-Installation gliedert sich in folgende Bereiche: 1. Vorbereitung 2. Installation der Clusterware 3. Installation der Oracle 10g-Datenbank-Software Vorbereitung Bevor Sie mit der Installation beginnen, müssen Sie folgende Voraussetzungen schaffen: Betriebssystemspezifische Parameter: Je nach Betriebssystem müssen bestimmte Kernel-Parameter vorher gesetzt sein, dabei gelten die gleichen Voraussetzungen wie bei der Installation einer Single-Instance-Datenbank. Ressourcen: Je Knoten werden mindestens 512 MB Hauptspeicher und 1 GB Swap-Space benötigt. Außerdem für die Oracle-Software bis zu 4 GB Plattenplatz und während der Installation 400 MB im Temp-Verzeichnis. IP-Adressen und Hostnamen: Je System werden drei IP-Adressen benötigt, eine für das Public Network, eine für den Interconnect und einen als virtuelle IPAdresse. Die virtuelle IP-Adresse muss für Ihr Public Network gelten, da die Oracle Net-Verbindung über diese Adresse arbeiten wird.
Oracle Real Application Clusters
719
Knoten 1
Knoten 2
IP-Adresse
Hostname
IP-Adresse
Hostname
Public
192.168.149.10
hllinux1
192.168.149.11
hllinux2
Private
10.0.0.1
hlclu1
10.0.0.2
hlclu2
Virtuelle
192.168.149.211
rac1
192.168.149.212
rac2
Tabelle 13.2: IP-Adressen
Diese Adressen und Hostnamen sollten Sie in die lokalen Hostdateien (/etc/ hosts) eintragen. Benutzer und Gruppe: Wie bei jeder Oracle-Installation unter Unix müssen Benutzer und Gruppe bereits angelegt sein. Wichtig ist hierbei, dass die Namen und IDs auf allen beteiligten Systemen gleich sind. Kommunikation zwischen den Systemen: Für Unix-Systeme muss es möglich sein, einen Befehl auf einem Remote-Knoten auszuführen, ohne eine Kennwortabfrage zu bekommen. Grund hierfür ist, dass die Software nur auf einem Knoten installiert wird und dann per ssh (Secure Shell) oder rsh (Remote Shell) auf alle anderen Knoten verteilt wird. Dabei wird zunächst versucht, eine gesicherte Verbindung über ssh herzustellen. Nur wenn diese Software nicht installiert ist, erfolgt die Verbindung über rsh. Um die Kommunikation zu testen, empfiehlt es sich, sich als entsprechender Benutzer an jedem Server anzumelden und dann je nach verwendeter Shell einen der folgenden Befehle auszuführen: %linux1: %linux1: %linux2: %linux2:
rsh rsh rsh rsh
cluster1 cluster2 cluster1 cluster2
date date date date
Diese Befehle sollten ohne zusätzliche Kennwortabfrage und ohne zusätzliche Textinformationen das Datum ausgeben. Konfiguration der Platten: Je nach verwendeter Speicherart müssen Sie die entsprechenden Raw Devices zur Verfügung stellen bzw. das Dateisystem vorbereiten. Die ASM-Installation erfolgt erst zu einem späteren Zeitpunkt, da auch diese im RAC installiert werden muss. Wenn ASM benutzt werden soll, müssen zusätzlich zwei Raw Devices angelegt werden. Ein Device wird für die Cluster Registry (OCR mind. 100 MB) und das zweite als Quorum oder Voting Disk (mind. 20MB) benutzt. Beide Devices müssen dem entsprechenden Oracle-Benutzer und der Gruppe gehören. Clusterware-Installation Im Gegensatz zu früheren Oracle-Installationen ist es mit Version 10g nicht mehr möglich, die RAC-Software zu installieren, wenn die Voraussetzungen nicht erfüllt sind1. Daher muss zunächst das Framework, die Oracle Cluster Ready Services, installiert werden. Sie befinden sich, wie bereits in Kapitel 2 besprochen, auf einer eigenen CD. Die Installation erfolgt in ein eigenes ORACLE_HOME.
720
Hochverfügbarkeit
Die CRS-Software muss auch dann installiert werden, wenn Sie einen ClusterManager eines Drittanbieters einsetzen. Während der Installation wird dies erkannt, und einige Komponenten (z.B. das Voting-Device) werden nicht installiert; stattdessen hängt sich der CRS in die bestehende Cluster-Software ein. Nach der obligatorischen Abfrage des ORACLE_HOME-Verzeichnisses werden zunächst die IP-Adressen bzw. Hostnamen abgefragt. Außerdem muss ein globaler ClusterName (im Beispiel hlcluster) gewählt werden.
Abbildung 13.2: Cluster-Konfiguration
Als Nächstes erfolgt, wie in Abbildung 13.3 ersichtlich, die Abfrage der Netzwerkadapter für Private und Public Network. Kritisch kann die Abfrage der Oracle Cluster Registry und der Voting Disk werden, da hier das entsprechende Device konfiguriert sein muss und die notwendigen Berechtigungen gesetzt sein müssen. Es empfiehlt sich, diesem und dem Voting Device zunächst alle Rechte (chmod 777) zu geben, da die notwendigen Rechte durch die Installation automatisch gesetzt werden. Bitte beachten Sie, dass die Devices auf allen beteiligten Knoten erkannt und mit den notwendigen Rechten versehen werden müssen.
1
In älteren Oracle-Versionen war es möglich, die Parallel Server-Software zu installieren, ohne dass die Grundvoraussetzungen für den Betrieb erfüllt waren.
Oracle Real Application Clusters
Abbildung 13.3: Netzwerkadapter
Abbildung 13.4: Oracle Cluster Registry
721
722
Hochverfügbarkeit
Bevor die eigentliche Installation beginnt, müssen Sie, falls dies die erste OracleInstallation auf dem System ist, noch das Shell-Skript orainstRoot.sh ausführen. Dieses wird in der Regel im Verzeichnis $ORACLE_BASE/oraInventory liegen. Danach erfolgen die Software-Installation des CRS auf dem lokalen Knoten und die Verteilung per ssh oder rsh auf die anderen Knoten. Als Letztes müssen Sie auf jedem Knoten das Skript root.sh aufrufen (im ORACLE_HOME). Beachten Sie dabei bitte, die Skripte sequenziell auszuführen. Zwar werden wie üblich die Berechtigungen gesetzt sowie die Shell-Skripte (oraenv, coraenv, dbhome) kopiert. Dann wird aber auf dem ersten Knoten das Voting Device formatiert. Aus diesem Grund dürfen die Skripte auf den anderen Knoten erst ausgeführt werden, wenn die Formatierung abgeschlossen ist. Als Letztes wird auf dem ersten Knoten der CRS-Dienst gestartet, die anderen Knoten melden sich bei diesem an. Bevor mit der Installation fortgefahren wird, sollte überprüft werden, ob die CRSInstallation erfolgreich war. Dafür gibt es im Installationsverzeichnis $ORACLE_HOME/ bin das Programm olsnodes, mit dem eine Liste der Cluster-Knoten angezeigt werden kann. Datenbank-Software-Installation Die Installation entspricht in weiten Teilen der bereits in Kapitel 2 besprochenen. Zusätzlich wird bei der Installation abgefragt, ob die Software auf allen oder nur auf einem Cluster-Knoten installiert werden soll.
Abbildung 13.5: Installation für Hardware-Cluster
Oracle Real Application Clusters
723
Sollten Sie diese Abfrage nicht bekommen, funktioniert die CRS-Software nicht richtig oder wurde nicht gestartet. Sie sollten hier nicht weitermachen, da wie bereits erwähnt die Cluster-Software nur installiert wird, wenn die Voraussetzungen erfüllt sind. Wenn Sie eine benutzerdefinierte Installation durchführen, können Sie bei der Auswahl der Produktkomponenten die Oracle Real-Application-Clusters-Option anwählen.
Abbildung 13.6: Produktkomponenten
Der letzte Punkt während der Installation betrifft die virtuellen IP-Adressen. Über den VIP-Konfigurationsassistenten geben Sie nochmals die virtuellen IP-Adressen für den Cluster an. Die Verteilung der Software auf die beteiligten Knoten erfolgt wiederum automatisch am Ende der Installationsprozedur. Damit ist die Software installiert, und es kann mit der Konfiguration der Datenbank begonnen werden.
724
Hochverfügbarkeit
Abbildung 13.7: VIP-Konfigurationsassistent
13.3.4 Konfiguration einer RAC-Datenbank Wie bereits bei einer Standardinstallation ist es auch hier am einfachsten, die Datenbank mit dem DATABASE CONFIGURATION ASSISTANT (dbca) anzulegen. Wenn die Software-Installation fehlerfrei durchgeführt worden ist, werden Sie auf dem Eingangsbildschirm die Abfrage erhalten, ob Sie eine Single-Instance- oder eine Real-Application-Cluster-Datenbank aufbauen möchten. Wenn Sie diese Meldung nicht erhalten, haben Sie bei der Software-Installation einen Fehler gemacht, oder die entsprechenden Dienste (CRS) sind nicht gestartet. Wenn Sie sich für die RAC-Installation entschieden haben, bekommen Sie im Schritt 2 die Abfrage, für welche Knoten die Datenbank installiert werden soll. Weitere Schritte folgen wie bei einer Single-Instance-Installation. Im Unterschied dazu können Sie bei der Abfrage des Speicherverfahrens in Schritt 7 zwischen ClusterDateisystem, Raw Devices und ASM wählen. Oracle empfiehlt die Verwendung von ASM für den RAC-Betrieb. Sollten Sie eine RAC-Datenbank mit der Standard Edition aufbauen wollen, müssen Sie ASM als Speicherverfahren wählen, weil andere Optionen nicht unterstützt sind. Im Schritt 12 können Sie auswählen, welche Netzwerk-Services für die Datenbankinstanzen eingerichtet werden sollen.
Oracle Real Application Clusters
725
Abbildung 13.8: Services für RAC-Datenbank
Zunächst sehen Sie auf der linken Seite nur Ihren Standard-Service (in unserem Fall RACDB). Durch den Button HINZUFÜGEN können Sie dann weitere Services anlegen und für jeden Service auf der rechten Seite die Verfahren bestimmen. Dadurch ist es möglich, dedizierte Services für das Transparent Application Failover (TAF) oder für die Auswahl einer bestimmten Instanz einzurichten. Im Schritt 14 erhalten Sie wie gewohnt die Liste mit den erforderlichen Tablespaces, Kontrolldateien und Redo-Log-Dateien. Im Unterschied zur SingleInstance-Datenbank brauchen Sie hier für jede Instanz einen eigenen Undo-Tablespace und eigene Redo-Log-Dateien. In Abbildung 13.9 sehen Sie, dass zwei Undo-Tablespaces angelegt wurden sowie vier Redo-Log-Gruppen (zwei je Instanz). Damit ist die Konfiguration abgeschlossen, und die Datenbank kann wie gewohnt erstellt werden. Bitte beachten Sie auch hier, dass die Maximalgrößen und die Erweiterungsschritte für die Datendateien angepasst werden sollten.
726
Hochverfügbarkeit
Abbildung 13.9: Datenbankdateien der RAC-Datenbank
Serverparameter Die wesentlichen Parameter unterscheiden sich bei einer RAC-Datenbank nicht von einer Single-Instance-Datenbank. Unterschiede gibt es vor allem in der generellen Bekanntgabe, dass es sich um eine RAC-Datenbank handelt, und bei den instanzspezifischen Parametern, z.B. welcher Undo-Tablespace zu welcher Instanz gehört. Das bedeutet, es gibt eine Liste von Parametern, die für alle Instanzen gleich sein müssen, und es gibt Parameter, die je Instanz unterschiedlich sein können oder unterschiedlich sein müssen. Zunächst stellt sich die Frage, wie instanzspezifische Parameter überhaupt gesetzt werden. Wenn Sie eine Oracle 10g-Datenbank betreiben, haben Sie sich hoffentlich für die Verwendung einer Serverparameterdatei (SPFILE) entschieden. Bei einer RAC-Datenbank mit ASM wird diese in der ASM-Instanz verwaltet. Entweder erstellen Sie eine Textversion (init.ora) über den Befehl CREATE PFILE=… FROM SPFILE. oder Sie setzen die Parameter mit dem Befehl ALTER SYSTEM ….
Oracle Real Application Clusters
727
Bei der Verwendung einer init.ora wird der Instanzname vor den Parameter gesetzt. Also in der Form: *.db_name=RACDB # Alle Instanzen RACDB1.undo_tablespace='UNDOTBS1' RACDB2.undo_tablespace='UNDOTBS2' Listing 13.1: Serverparameter für RAC-Datenbank
Bei dem Befehl ALTER SYSTEM wird der Instanzname als zusätzlicher Parameter mitgegeben. SQL> ALTER SYSTEM SET shared_pool_size=500M SID=’RACDB1’;
Folgende Parameter müssen auf allen Instanzen gleich sein: active_instance_count archive_lag_target cluster_database control_files db_block_size db_domain db_files db_name db_recovery_file_dest db_recovery_file_dest_size db_unique_name max_commit_propagation_delay trace_enabled undo_management Listing 13.2: Global gültige Parameter
Nicht alle diese Parameter müssen gesetzt sein; neben den generellen Parametern wie db_name ist nur der Parameter cluster_database zu setzen, der bestimmt, dass es sich um eine RAC-Instanz handelt. Die aus OPS-Zeiten stammenden Befehle für das Starten und Stoppen einer OPS-Datenbank (STARTUP PARALLEL) gibt es nicht mehr. Die folgenden Parameter müssen für jede Instanz eindeutig gesetzt sein: instance_name instance_number undo_tablespace thread Listing 13.3: Instanzspezifische Parameter
Die Parameter thread und instance_name sind nicht zwingend erforderlich, es empfiehlt sich aber, sie zu setzen, wobei thread den gleichen Wert wie instance_number haben sollte. Über den Parameter thread werden die Redo-Log-Dateien einer Instanz eindeutig zugeordnet. Ist dieser Parameter nicht gesetzt, entscheidet die Reihenfolge beim Start der Instanzen, welche Redo-Log-Dateien welcher Instanz zugeordnet werden.
728
Hochverfügbarkeit
Verwalten der RAC-Datenbank Die einfachste Verwaltung einer RAC-Datenbank erfolgt wie gewohnt über den Oracle Enterprise Manager. Hierüber können die Instanzen, aber auch die gesamte Datenbank, überwacht und administriert werden. Daneben gibt es das Kommandozeilen-Werkzeug Server Control (srvctl) (bitte nicht mit dem alten Servermanager verwechseln!), über das die RAC-Datenbank über die Kommandozeile administriert werden kann. Dabei geht es nicht um die Datenbankadministration als solche, die natürlich auch über SQL*Plus oder andere Werkzeuge gemacht werden kann, sondern um cluster-spezifische Aufgaben, wie z.B. das Starten und Stoppen aller Instanzen. Das Kommando srvctl muss immer aus dem ORACLE_HOME der RAC-Instanz aufgerufen werden, die administriert werden soll. Über den Befehl können zum einen Kommandos an den Cluster Ready Service (CRS) übergeben (z.B. das Starten und Stoppen von Instanzen) und zum anderen Änderungen an der Oracle Cluster Registry (OCR) durchgeführt werden. Folgende Aufgaben können über den Befehl ausgeführt werden: Konfigurationsänderungen an der Cluster-Datenbank Hinzufügen oder Löschen von Instanzen zu einer Cluster-Datenbank Starten und Stoppen von Instanzen oder der gesamten Datenbank Abfrage von Statusinformationen Administration von Cluster-Anwendungen Administration von ASM-Instanzen So kann zum Beispiel die Konfiguration der Cluster-Datenbank wie folgt angezeigt werden: % srvctl config database –d RACDB => hllin1 RACDB1 hllin2 RACDB2 Listing 13.4: Abfrage der Cluster-Knoten und Instanznamen
Vorteilhaft ist die Benutzung von srvctl auch beim Starten und Stoppen von Instanzen, da hier nicht der umständliche Weg über die Verbindung mit SQL*Plus gewählt werden muss, sondern über den CRS-Prozess der entsprechende Befehl an jede beliebige Instanz im RAC-Verbund geschickt wird.
13.3.5 Oracle Net-Konfiguration Die Konfiguration für Oracle Net wurde bereits in Kapitel 7 besprochen. Insbesondere die Client-seitigen Funktionen Client-Loadbalancing, Connect-Time Failover und Transparent Application Failover sind für hochverfügbare Systeme wichtig. An dieser Stelle geht es um die serverseitige Konfiguration von Oracle Net im Zusammenspiel mit hochverfügbaren Systemen.
Oracle Real Application Clusters
729
Virtuelle IP-Adressen Zunächst sollen die weiter oben bereits angesprochenen Virtuellen IP-Adressen (VIPs) nochmals erwähnt sein. Diese sollten im RAC-Umfeld unbedingt für die Oracle Net-Konfiguration verwendet werden, da sie – im Unterschied zu den physischen Adressen – von den Oracle Cluster Ready Services bei Ausfall eines Knotens auf einem anderen Knoten im Cluster übernommen werden. Dort wird dann zwar kein Listener gestartet, allerdings reagiert der Knoten mit einer entsprechenden Fehlermeldung auf Verbindungsversuche, so dass das u.a. Connect Time Failover schnell abgewickelt werden kann. Verschwindet die Adresse einfach aus dem Netzwerk, so kann es einige Minuten dauern, bis die Clients sich wieder verbinden können. Listener Load Balancing Listener Load Balancing setzt RAC voraus und funktioniert demnach nicht für andere hochverfügbare Konfigurationen. Listener Load Balancing basiert auf der dynamischen Dienstregistrierung von Instanzen bei den Listenern. Für jede Instanz werden die Listener der anderen RAC-Instanzen mit dem Systemparameter remote_listener definiert; der Listener auf dem lokalen Knoten mittels local_listener. Man kann für die beiden Serverparameter die TNS-Syntax direkt verwenden – übersichtlicher wird es meist, wenn man Net-Aliasnamen definiert und diese verwendet. In der Datei tnsnames.ora auf Knoten rac1 werden z.B. folgende Einträge definiert: LOCAL.LISTENER = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = rac1)(PORT = 1521)) ) ) REMOTE.LISTENER = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = rac2)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = rac3)(PORT = 1521)) ) )
Folgende Befehle sorgen für die Anmeldung der Instanz bei den entsprechenden Listenern: ALTER SYSTEM SET local_listener = 'LOCAL.LISTENER' SCOPE = BOTH / ALTER SYSTEM SET remote_listener = 'REMOTE.LISTENER' SCOPE = BOTH /
730
Hochverfügbarkeit
Nun können alle Instanzen von allen Listenern angesprochen werden. Im Unterschied zum Client-Loadbalancing muss die Clientkonfiguration nicht alle RACInstanzen von vorneherein kennen, muss also (zumindest nicht komplett) RACaware sein.
13.4
Oracle Data Guard
Die Oracle Real-Application-Cluster-Datenbank bietet einen hohen Schutz gegen Hardware-Fehler. Da mit mehr als einem Knoten auf eine Datenbank zugegriffen wird, kann beim Ausfall eines Knotens ohne Auszeit weitergearbeitet werden. Da in diesem Fällen immer auch ein Raid-System zum Einsatz kommt, kann auch davon ausgegangen werden, dass ein Plattenfehler ebenfalls toleriert wird. Keinen Schutz bietet die RAC-Datenbank allerdings gegenüber Anwendungs- bzw. Anwenderfehlern. Ein fehlerhafter Befehl, wie z.B. DROP TABLESPACE …, führt unweigerlich zum Stillstand der gesamten Datenbank, der nur über das Wiedereinspielen einer Sicherung zu beheben ist. Als Schutz vor derartigen Fehlern oder auch bei so genannten Desaster-Recovery(DR)-Konfigurationen, wo der Ausfall eines kompletten Rechenzentrums überbrückt werden muss, bietet Oracle seit vielen Jahren die Standby-Datenbank an. Bereits in der Version 6 gab es diese Konfiguration – allerdings nicht von Oracle unterstützt. Dabei wird eine physikalische Kopie der Datenbank über die Inhalte der Redo-Log-Dateien synchronisiert. Das Unternehmen Libelle Informatik bietet für alle Oracle-Versionen eine entsprechende Software (DBShadow) an, die eine Standby-Datenbank aufbauen und administrieren kann. Oracle hat mit Version 7.3 zum ersten Mal einen offiziellen Support für StandbyDatenbanken zur Verfügung gestellt. Mit den folgenden Releases wurde die Funktionalität erweitert, und mit der Version 8.1.7 kam zum ersten Mal eine grafische Oberfläche für die Administration und Überwachung hinzu. Prinzipiell besteht der Data Guard aus unterschiedlichen Komponenten: 1. Standby-Datenbank: eine physikalische Kopie einer Datenbank, die über die Inhalte der Redo-Log-Dateien synchronisiert wird 2. Grafische Oberfläche zur Administration 3. Data Guard Broker: Prozesse für die Konfiguration und Überwachung 4. Parameter und Befehle für den automatischen Betrieb Die Data-Guard-Funktionalität gehört zum Umfang der Enterprise Edition, was aber nicht bedeutet, dass eine Standby-Datenbank nicht mit der Standard Edition aufgebaut werden kann. Nur die Punkte 2 bis 4 stehen bei der Standard Edition nicht zur Verfügung. Ausgangsbasis für den Aufbau einer Data-Guard-Konfiguration ist also immer eine physikalische Kopie einer Datenbank. Dies ist notwendig, da die Informationen für das Zielsystem aus den Redo-Log-Dateien gelesen werden. Im einfachsten Fall bedeutet dies, dass sich das Zielsystem im permanenten Recovery-Modus befindet und jede archivierte Redo-Log-Datei vom Quellsystem auf das Zielsystem kopiert
Oracle Data Guard
731
und dort recovered wird. Diese Art ist die einfachste, aber auch effektivste Methode, die Verfügbarkeit des Systems erheblich zu verbessern. Der Nachteil dieser Methode ist allerdings, dass im Fehlerfall unter Umständen die Transaktionen einer ganzen Redo-Log-Datei verloren gehen. Seit Version 9i gibt es daher von Oracle unterschiedliche Arten, die bis zu einer so genannten No-Data-Loss-Konfiguration führen können. Nachteilig für die Standby-Datenbank war bisher allerdings, dass sich die Zieldatenbank im normalen Betrieb nicht nutzen ließ. Zwar war es seit Version 8i möglich, die Datenbank für den lesenden Betrieb zu öffnen, während dieses Betriebs erfolgte jedoch kein Recovery mehr. Seit der Version 9i Release 2 gibt es jetzt zusätzlich die Möglichkeit, eine so genannte Logical-Standby-Datenbank aufzubauen. Dabei werden nicht mehr die Redo-Log-Dateien recovered, sondern die Informationen per Log Miner aus den Redo-Log-Dateien ausgelesen und als DML- oder DDL-Befehle in das Zielsystem eingepflegt. Damit kann diese Datenbank fast ganz normal genutzt werden. Allerdings können keine Änderungen an den übertragenen Daten vorgenommen werden. Für den Betrieb einer Data-Guard-Konfiguration werden in der Regel mindestens zwei Systeme verwendet, eine primäre Datenbank (Produktion) und eine oder mehrere sekundäre Datenbanken (Standby). Diese müssen vom gleichen Hersteller sein bzw. das gleiche Betriebssystem haben. Eine Ausnahme bildet die bereits erwähnte No-Data-Loss-Konfiguration, an der mindestens drei Systeme beteiligt sind. Die Hardware-Ausstattung kann je nach Aufgabe durchaus unterschiedlich sein. Beim Betrieb als Hochverfügbarkeitslösung sollten die Systeme aber identisch ausgestattet sein, um beim Umschalten nicht in Performance-Probleme zu laufen. Der Umschaltvorgang kann zwei Ursachen haben: Failover: Das primäre System fällt mit einem Fehler aus Switchover: Die Rollen der Systeme werden getauscht, z.B. für Wartungsarbeiten an der Hardware. Der Switchover wird teilweise auch als Graceful Switch bezeichnet und kommt nicht nur bei Wartungen zum Einsatz, sondern auch, wenn nach einem Failover wieder auf das ursprüngliche System zurückgeschaltet werden soll, weil z.B. dieses System leistungsfähiger ist oder das Rechenzentrum eine bessere Infrastruktur hat. Aus diesem Grunde hat Oracle mit der Version 10g die Möglichkeit geschaffen, die Konfiguration so aufzubauen, dass alle beteiligten Datenbanken von vornherein die notwendigen Parameter eingestellt haben, um als primäre oder sekundäre Datenbank arbeiten zu können. Ab der Version 10.1.0.3 sind bei der Logical-Standby-Datenbank auch unterschiedliche Release-Stände möglich, so dass hier ein so genanntes Rolling Upgrade durchgeführt werden kann. Da alle Daten aus den Redo-Log-Dateien gelesen werden, sind Befehle, die mit der Option NOLOGGING arbeiten, zu vermeiden. Am sinnvollsten ist es daher, für die gesamte Datenbank die Option FORCE LOGGING einzustellen.
732
Hochverfügbarkeit
13.4.1 Physical-Standby-Datenbank Unter einer Physical-Standby-Datenbank versteht man eine Zieldatenbank, welche die Transaktionen aus den Redo-Log-Dateien über das Database Recovery einspielt. Daher steht diese Datenbank nicht für den normalen Betrieb zur Verfügung.
Abbildung 13.10: Einfacher Aufbau einer Standby-Datenbank
Abbildung 13.10 zeigt den einfachen Aufbau einer Standby-Datenbank. Dabei werden die auf dem Produktionssystem archivierten Redo-Log-Dateien per CopyBefehl (FTP oder Ähnliches) auf die Standby-Seite übertragen und dort über den Befehl RECOVER … eingelesen. Diese Funktionsweise ist mit jeder Oracle-Version möglich und ohne großen Aufwand einsetzbar. Allerdings sollte in einem Produktionsumfeld das Ganze so vorbereitet sein, dass ein Neuaufbau der Standby-Datenbank und die Übertragung der Redo-Log-Dateien per Skript bzw. automatisch erfolgen. Einziges Problem in dieser Konstellation ist, dass Änderungen an der Datenbank (neue Tablespaces oder Datendateien) nicht mit übertragen werden. Außerdem besteht die Gefahr, dass fehlerhaft übertragene Dateien nicht früh genug erkannt werden und das Recovery daher nicht ordnungsgemäß durchgeführt werden kann. Die Firma Libelle Informatik bietet mit DBShadow ein Produkt an, das diese fehlenden Funktionen übernimmt, so dass dann auch ein gefahrloser Betrieb z.B. mit einer Standard Edition möglich ist. Beim Betrieb einer Enterprise Edition empfiehlt es sich jedoch, auf die zusätzlichen Möglichkeiten von Data Guard zurückzugreifen. Eine ähnliche Konfiguration wie die in Abbildung 13.10 gezeigte würde in diesem Umfeld folgendermaßen aussehen.
Oracle Data Guard
733
Abbildung 13.11: Data-Guard-Architektur
In diesem Fall wird zunächst einmal der Transport der archivierten Redo-LogDateien von einem Archivierungsprozess (arcn) initiiert. Auf der Gegenseite werden die Dateien dann vom Remote File Server (rfs) entgegengenommen. Diese Dateien werden als Standby-Redo-Log-Dateien bezeichnet und werden dann vom Managed Recovery Process (mrp) eingespielt. Nach dem Recovery der Dateien können sie als archivierte Redo-Log-Dateien auf dem Standby-System gespeichert werden. Die gesamte Funktionalität wird von einem Fetch Archive Log-Server (FAL-Server) und Fetch Archive Log-Client (FAL-Client) überwacht, so dass bei fehlenden oder fehlerhaft übertragenen Redo-Log-Dateien automatisch eine Rückmeldung an das Produktionssystem erfolgt und die Daten nochmals geschickt werden. Im Folgenden wird der Aufbau und die Funktion dieser Architektur kurz beschrieben. Daneben gibt es eine Reihe weiterer Konfigurationen, deren Beschreibung den Umfang dieses Buches sprengen würde. Wir verweisen daher nochmals auf das Buch »Oracle 10g Hochverfügbarkeit« und auf die Oracle-Dokumentation. Vorbereitung Um sicherzustellen, dass alle relevanten Informationen auch in den Redo-LogDateien gespeichert werden, sollte unbedingt die Datenbank-Option FORCE LOGGING aktiviert werden. Dies geschieht mit dem Befehl: SQL> ALTER DATABASE FORCE LOGGING; Listing 13.5: Force Logging
734
Hochverfügbarkeit
Das bedeutet aber auch, dass sich unter Umständen die Laufzeit von Batch-Prozessen, die bisher mit der Option NOLOGGING arbeiteten, erheblich verlängern kann und zusätzliche archivierte Redo-Log-Dateien anfallen. Bevor also diese Option eingeschaltet wird, muss geprüft werden, welche Prozesse davon betroffen sind. Außerdem ist es erforderlich, dass die Datenbank auch über das Netzwerk administriert werden kann; daher muss es eine Passwort-Datei geben, und der entsprechende Serverparameter remote_login_passwordfile = EXCLUSIVE muss gesetzt werden (siehe Kapitel 9.5.6). Primäre Datenbank Jetzt werden die für die Data-Guard-Konfiguration notwendigen Parameter in der Produktionsdatenbank (hier PROD) gesetzt. Hilfreich ist hierbei die in Oracle9i eingeführte Möglichkeit, die Datenbank-SID mit anzugeben. So kann eine Initialisierungsdatei gepflegt werden, die für beide Datenbanken gültig ist. *.archive_lag_target = 900 PROD.db_unique_name = PROD STDBY.db_unique_name = STDBY *.service_names = PROD *.log_archive_config = 'DG_CONFIG=(PROD,STDBY)' PROD.log_archive_dest_1 = 'LOCATION=/archive/PROD/ VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=PROD' STDBY.log_archive_dest_1 = 'LOCATION=/archive/PROD/ VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=STDBY' PROD.log_archive_dest_2 = 'SERVICE=STDBY VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=STDBY' STDBY.log_archive_dest_2 = 'SERVICE=PROD VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=PROD' *.log_archive_format = 'PROD_%t_%s_%r.arc' PROD.fal_server = PROD STDBY.fal_server = STDBY PROD.fal_client = STDBY STDBY.fal_client = PROD *.standby_file_management = AUTO *.standby_archive_dest = /archive/STDBY_ARCHIVE/ Listing 13.6: Serverparameter der Datenbanken PROD und STDBY
Oracle Data Guard
735
Die Parameter im Einzelnen: archive_lag_target: Nach spätestens 900 Sekunden (also 15 Minuten) wird ein Log-Switch durchgeführt. Damit wird der potenzielle Datenverlust im Fehlerfall auf ca. 15 Minuten beschränkt. db_unique_name: Dieser Name unterscheidet die beteiligten Datenbanken. Der db_name ist ja aufgrund der physikalischen Kopie für beide Datenbanken identisch. service_names: Hiermit wird die Instanz über den Listener identifiziert. log_archive_config: Dieser Parameter ist für den Data Guard Broker bestimmt und kennzeichnet, welche Datenbanken zu dieser Konfiguration gehören. Als Name wird dabei der db_unique_name angegeben. log_archive_dest_1: Lage der archivierten Redo-Log-Dateien für die Datenbank, die den db_unique_name »PROD« hat. Dabei gilt dieses Verzeichnis unabhängig davon, ob die Datenbank primäre oder sekundäre Datenbank ist (ALL_ROLES), und unabhängig davon, ob es sich um die archivierten Online- oder um die Standby-Redo-Log-Dateien handelt (ALL_LOGFILES). log_archive_dest_2: Hier werden die Online-Redo-Log-Dateien an einen Oracle Net Service mit dem Namen STDBY übergeben. Dies geschieht nur für die primäre Datenbank (PRIMARY_ROLE). fal_server: Auf dieser Datenbank (db_unique_name) soll der FAL-Server-Prozess gestartet werden? fal_client: Auf dieser Datenbank (db_unique_name) soll der FAL-Client-Prozess gestartet werden? standby_file_management: Mit dem Wert AUTO wird angegeben, dass Änderungen an der Datenbank (Tablespaces, Datafiles etc.) automatisch auf die sekundäre Datenbank übertragen werden sollen. standby_archive_dest: Dieser Parameter bestimmt, wohin auf der Standby-Datenbank die archivierten Redo-Log-Dateien des Produktionssystems geschrieben werden sollen. Wenn dieser Parameter nicht gesetzt ist, steht der Standardwert laut v$parameter (show parameter standby_archive_dest) auf $ORACLE_HOME/dbs/arch. Wenn allerdings der Parameter db_recovery_file_dest gesetzt ist, werden die Dateien in ein entsprechendes Unterverzeichnis geschrieben. Zusätzlich können, falls die Verzeichnisstrukturen auf dem primären und sekundären System unterschiedlich sind, über die Parameter db_file_name_convert und log_file_name_convert automatische Anpassungen der Verzeichnisse vorgenommen werden. Sie sollten aber versuchen, solche Unterschiede zu vermeiden, da das eine zusätzliche Fehlerquelle mit sich bringt. Unsere Empfehlung ist daher, die Verzeichnisstrukturen immer identisch zu halten.
736
Hochverfügbarkeit
Mit diesen Parametern kann jetzt die Archivierung für die primäre Datenbank aktiviert werden: SQL> SQL> SQL> SQL>
SHUTDOWN IMMEDIATE STARTUP MOUNT ALTER DATABASE ARCHIVELOG; ALTER DATABASE OPEN;
Listing 13.7: Aktivieren der Archivierung
Der Parameter log_archive_dest_2 gibt an, dass es einen Oracle Net-Eintrag »STDBY« gibt, der die Standby-Datenbank identifiziert. Daher muss auf dem Produktionsrechner noch ein zusätzlicher TNS-Eintrag für diese Datenbank aufgesetzt werden. Wie bereits in Kapitel 7 erwähnt, empfehlen wir, Datenbank-Server mit festen IPAdressen und lokalen Oracle Net-Konfigurationen (tnsnames.ora) zu administrieren. Der Eintrag könnte wie folgt aussehen: PROD = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = linux01)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = PROD) ) ) STDBY = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = linux02)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = PROD) ) ) Listing 13.8: Data Guard tnsnames.ora
Damit ist die Produktion so weit vorbereitet, dass auf dieser Basis eine neue Standby-Datenbank generiert werden kann. Sekundäre Datenbank (Standby) Auf der sekundären Datenbank muss jetzt zunächst die entsprechende Initialisierungsdatei erstellt werden. Da wir alle Parameter schon auf dem Primärsystem gesetzt haben, entfällt die Notwendigkeit von Anpassungen. % sqlplus / as sysdba SQL> CREATE PFILE FROM SPFILE; SQL> EXIT; % scp $ORACLE_HOME/dbs/initPROD.ora oracle@linux02:/app/oracle/product/10.1.0/db_1/dbs
Oracle Data Guard
737
Als Nächstes müssen alle Verzeichnisse erstellt werden; dies gilt für die DatenDateien, archivierte Redo-Log-Dateien und eine eventuell eingestellte Flash Recovery Area. Außerdem werden die Verzeichnisse für Dump-Dateien benötigt (udump, bdump und cdump). Die Dateien tnsnames.ora und listener.ora können wiederum von der Produktion übernommen werden, in der listener.ora muss allerdings der Hostname geändert werden. Als Letztes wird jetzt noch die Passwortdatei und die Serverparameterdatei erstellt und anschließend der Listener gestartet. Dann wird die Datenbank mit der Option NOMOUNT hochgefahren. % orapwd file=orapwPROD password=manager entries=5 % sqlplus / as sysdba SQL> CREATE SPFILE FROM PFILE; SQL> STARTUP NOMOUNT SQL> EXIT; % lsncrtl start; Listing 13.9: Starten der Sekundärdatenbank
Kopieren der Produktionsdatenbank Eine Kopie der Produktionsdatenbank kann am einfachsten über den Recovery Manager erstellt werden. Wie bereits in Kapitel 10 besprochen, gibt es hierbei die Option einer Hilfsverbindung (Auxiliary). Zunächst wird auf dem Primärsystem ein Backup der Datenbank durchgeführt: % rman TARGET / RMAN> BACKUP DATABASE INCLUDE CURRENT CONTROLFILE FOR STANDBY PLUS ARCHIVELOG; Listing 13.10: Backup für den Aufbau einer Standby-Datenbank
Im Unterschied zu einem »normalen« Backup wird hier zusätzlich die Kontrolldatei mit der Option FOR STANDBY gesichert. Sollten Sie bereits ein Backup der Produktionsdatenbank haben, so reicht es in diesem Fall, nur ein Backup der Kontrolldatei zu erstellen mit dem Befehl: RMAN> BACKUP CURRENT CONTROLFILE FOR STANDBY; Listing 13.11: Erstellen einer Standby-Kontrolldatei
Anschließend werden die Dateien in das identische Verzeichnis auf dem Sekundärsystem kopiert und dann wiederum über den Recovery Manager zurückgespielt. % rman TARGET / AUXILIARY sys/manager@STDBY Recovery Manager: Release 10.1.0.4.0 – Production Copyright (c) 1995, 2004, Oracle. All rights reserved. connected to target database: PROD (DBID=4266805191) connected to auxiliary database: PROD (not mounted) RMAN> DUPLICATE TARGET DATABASE FOR STANDBY NOFILENAMECHECK; Listing 13.12: Erstellen der Standby-Datenbank
Damit steht auf dem Sekundärsystem die Datenbank zur Verfügung.
738
Hochverfügbarkeit
Als Nächstes wird die Sekundärdatenbank in den »Managed-Standby«-Modus geschaltet. Dadurch werden automatisch alle Redo-Log-Dateien vom Primärsystem in die Datenbank eingespielt. SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION; Listing 13.13: Managed Standby
Jetzt ist die Datenbank im Standby-Modus, und alle Änderungen der Produktionsdatenbank werden automatisch eingespielt. Sie sollten die Funktion an dieser Stelle noch einmal überprüfen: Ob die Übertragung und das Recovery der archivierten Redo-Log-Dateien tatsächlich funktionieren, wird durch den Vergleich der letzten Sequence-Nummer auf der Quelle mit der letzten applizierten Sequence-Nummer auf dem Zielsystem überprüft. Quelle: SQL> ALTER SYSTEM SWITCH LOGFILE; SQL> SELECT MAX(sequence#) FROM v$archived_log; MAX(SEQUENCE#) -------------756
Ziel: SQL> SELECT MAX(sequence#) FROM v$archived_log WHERE applied='YES'; MAX(SEQUENCE#) -------------756 Listing 13.14: Überprüfung des Recoverys
Auch in den Alert-Dateien des Primär- und Standby-Systems sollten Sie jetzt die entsprechenden Einträge finden. Da der Parameter standby_file_management = AUTO gesetzt worden ist, werden auch Strukturänderungen, wie z.B. neue Tablespaces, übertragen. Ein Eintrag aus der Alert-Datei der Standby-Datenbank zeigt dies. Recovery created file /data/PROD/tsdemo01.dbf Successfully added datafile 5 to media recovery Datafile #5: '/data/LINPROD/tsdemo01.dbf' Listing 13.15: Erstellen eines Tablespace auf der Sekundärseite
Eine Einschränkung stellt allerdings der Temporär-Tablespace dar, da die zugehörigen Dateien nicht mit übertragen wurden. Daher empfiehlt es sich, die Datenbank einmal im Read-only-Modus zu starten und dann eine entsprechende Datei anzulegen. Da in unserem Fall die Datenbank bereits im Managed-Recovery-Modus betrieben wird, muss diese zunächst abgeschaltet werden. Erst dann kann die Datenbank hochgefahren werden.
Oracle Data Guard
739
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; SQL> ALTER DATABASE OPEN READ ONLY;
Wenn Sie an dieser Stelle einen Fehler erhalten, sollten Sie nochmals zurück auf das Managed-Recovery schalten und auf dem Primärsystem einige Log-Switches ausführen. SQL> ALTER TABLESPACE temp ADD TEMPFILE '/data/PROD/temp01.tmp' size 100M AUTOEXTEND ON NEXT 10M MAXSIZE 1000M; SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION; Listing 13.16: Hinzufügen einer temporären Datendatei
Um in den Managed-Recovery-Modus zurückzukehren, muss die Datenbank nicht gestoppt und wieder gestartet werden. Die Option READ ONLY kann übrigens entfallen, da die Datenbank erkennt, dass sie sich im Recovery-Modus befindet und daher nur im Lesemodus geöffnet wird. Rollentausch Seit der Version 9i gibt es die Möglichkeit, dass die Datenbanken die Rollen tauschen, d.h., die primäre Datenbank wird zur Standby-Datenbank, und die sekundäre wird zur Produktion. In früheren Releases war dies nur möglich, indem die bisherige Standby-Datenbank gestartet und anschließend eine neue Standby-Datenbank auf dieser Basis erstellt wurde. Der Vorgang wird als Graceful Switch bezeichnet und vollzieht sich in zwei Schritten. Zunächst wird die Produktionsseite deaktiviert und als Standby-Datenbank hochgefahren. Anschließend wird die ursprüngliche Sekundärdatenbank als neue Produktion gestartet. Wichtig ist, dass Sie diese Schritte in der richtigen Reihenfolge ausführen. % sqlplus "sys/manager@PROD as sysdba" SQL> ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY; SQL> SHUTDOWN IMMEDIATE; SQL> STARTUP MOUNT; SQL> EXIT; % sqlplus "sys/manager@STDBY as sysdba" SQL> ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY; SQL> SHUTDOWN IMMEDIATE; SQL> STARTUP; % sqlplus "sys/manager@PROD as sysdba" SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION; Listing 13.17: Graceful Switch
Damit haben beide Datenbanken die Rollen getauscht.
740
Hochverfügbarkeit
Protection Mode Die Physical-Standby-Datenbank kann, wie bereits beschrieben, in unterschiedlichen Modi (Protection Mode) betrieben werden.
Abbildung 13.12: Schutzmodus
Am Beispiel des Enterprise Manager Grid Controls können die einzelnen Modi ausgewählt werden: Maximaler Schutz (Maximum Protection): Das bedeutet, dass auf keinen Fall Daten verloren gehen dürfen (No Data Loss). Jede Redo-Log-Information wird synchron auf die Standby-Datenbank übertragen, erst dann wird die Transaktion commited. Ist das nicht möglich, wird die Produktionsdatenbank heruntergefahren. In der Praxis bedeutet dies, dass mindestens zwei Standby-Datenbanken vorhanden sein müssen, da sonst die Gefahr von Produktionsstillständen zu groß ist. Die Performance leidet darunter, dass die Redo-Log-Information synchron übertragen wird. Maximale Verfügbarkeit (Maximum Availability): Auch in diesem Modus erfolgt ein synchroner Redo-Log-Transfer, d.h., jede Transaktion wird erst dann als commited gekennzeichnet, wenn die Daten auf mindestens einer Standby-Datenbank angekommen sind. Im Unterschied zum maximalen Schutz wird bei Fehlern im Transfer allerdings nicht die Datenbank heruntergefahren, sondern automatisch in den asynchronen Transfermodus umgeschaltet. Damit bleibt die Produktion aktiv, die Performance leidet aber im normalen Betrieb. Maximale Performance (Maximum Performance): Dies ist die niedrigste Verfügbarkeitsstufe, die sich wiederum in zwei weitere Einstellungen einteilen lässt:
Oracle Data Guard
741
– Asynchroner Log-Transport, bei dem die Informationen der Redo-Log-Dateien so schnell wie möglich transferiert werden, allerdings durch einen entkoppelten Prozess, so dass die Produktionsdatenbank weniger belastet ist. – Transport der archivierten Redo-Log-Dateien, was der klassischen StandbyMethode entspricht, bei der erst die archivierten Redo-Log-Dateien auf das Zielsystem kopiert und dort über den Recovery-Mechanismus eingelesen werden. Im Fehlerfall kann hier eine nicht unerhebliche Transaktionsmenge verloren gehen, je nachdem, wie groß die Redo-Log-Dateien sind bzw. wie oft ein Log-Switch und damit eine Archivierung erfolgt. Speziell in diesem Modus ist es sinnvoll, den Serverparameter archive_lag_target zu setzen. Als guter Kompromiss hat sich die maximale Performance mit asynchronem LogTransport erwiesen, da sich die Belastung für die Produktion in Grenzen hält und die Verfügbarkeit des Gesamtsystems in der Regel ausreichend ist. Für alle Modi bis auf die Übertragung der archivierten Redo-Log-Dateien gilt, dass es zusätzlich zu den »normalen« Redo-Log-Dateien auf dem Standby-System so genannte Standby-Redo-Log-Dateien geben muss, in denen die Transaktionsinformationen aus dem Primärsystem gespeichert werden. Diese Redo-Log-Dateien sind unabhängig von denen des Primärsystems, müssen aber mindestens deren Größe und Anzahl haben. SQL> ALTER DATABASE ADD STANDBY LOGFILE '/archive/STDBY_LOGS/stdby_log1.log' SQL> ALTER DATABASE ADD STANDBY LOGFILE '/archive/STDBY_LOGS/stdby_log2.log' SQL> ALTER DATABASE ADD STANDBY LOGFILE '/archive/STDBY_LOGS/stdby_log3.log' SQL> ALTER DATABASE ADD STANDBY LOGFILE '/archive/STDBY_LOGS/stdby_log4.log'
size 10M; size 10M; size 10M; size 10M;
Listing 13.18: Erstellung der Standby-Redo-Log-Dateien
Achten Sie bitte darauf, diese Änderung auf allen beteiligten Systemen durchzuführen, damit Sie bei einem Switchover die gleiche Funktionalität benutzen können. Jetzt kann der Modus auf den Systemen entsprechend geändert werden: Auf dem primären System (PROD): SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_2 = 'SERVICE=STDBY MANDATORY LGWR ASYNC AFFIRM VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=STDBY';
742
Hochverfügbarkeit
Auf dem Standby-System (STDBY): SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_2 = 'SERVICE=PROD MANDATORY LGWR ASYNC AFFIRM VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=PROD'; Listing 13.19: Maximum Performance mit Log-Transport
Das Recovery wird jetzt auf den Log-Transport geändert. SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT; Listing 13.20: Umschalten in den Log-Transport-Modus
Damit ist der Log-Transport aktiviert. Kontrolliert werden kann er am besten, indem man sich die Struktur der Standby-Redo-Log-Dateien ansieht mit: SQL> SELECT * FROM v$standby_log;
Weitere
Informationen
über
den
Status
können
über
die
View
v$archive_dest_status erhalten werden, z.B. in folgender Form: SQL> SELECT * FROM v$archive_dest_status WHERE dest_id in (1,2); DEST_ID STATUS TYPE DATABASE_MODE RECOVERY_MODE PROTECTION_MODE DESTINATION DB_UNIQUE_NAME ------- ------ -------- --------------- ----------------------- -------------------------------- -------------1 VALID LOCAL OPEN IDLE MAXIMUM PERFORMANCE /archive/PROD/ PROD 2 VALID PHYSICAL MOUNTED-STANDBY MANAGED REAL TIME APPLY MAXIMUM PERFORMANCE STDBY STDBY Listing 13.21: Ausgabe v$archive_dest_status
Weitere Views entnehmen Sie bitte der Oracle-Dokumentation.
13.4.2 Logical Standby Zwar kann die Physical-Standby-Datenbank – wie bereits erwähnt – für den lesenden Zugriff geöffnet werden, allerdings erfolgt während dieser Zeit kein Recovery. Daher ist diese Möglichkeit nur eingeschränkt nutzbar. Mit Version 9i Release 2 hat Oracle die Möglichkeit geschaffen, die Datenbank zu öffnen und trotzdem ein Recovery durchzuführen. Diese Funktion nennt sich Logical Standby und hat einen anderen Log-Transportmechanismus, der auf dem in Oracle8i eingeführten Log Miner basiert. Ein wesentlicher Unterschied zur physikalischen Kopie ist, dass es in diesem Fall Restriktionen gibt, d.h., es können nicht alle Datentypen übertragen werden. Dies sind unter Oracle 10g im Wesentlichen die objektrelationalen Datentypen:
Oracle Data Guard
743
BFILE ROWID UROWID REFs VARRAY Nested Tables XMLType User Defined Datatypes Listing 13.22: Nicht unterstützte Datentypen
Außerdem werden die von Oracle mitgelieferten Schemata wie z.B. DBSNMP, SYSTEM sowie Tabellen mit Table Compression nicht übertragen. Mit der View dba_logstdby_unsupported kann eine Liste der nicht unterstützten Typen und Objekte ausgegeben werden. Neben diesen Einschränkungen werden einige DDL-Befehle nicht übertragen. Die komplette Liste finden Sie in der Oracle-Dokumentation. Klar ist sicherlich, dass hierzu die Befehle CREATE DATABASE und ALTER SESSION gehören. Kritischer ist, dass Materialized Views nicht unterstützt werden. Wenn man sich allerdings überlegt, dass es sich hierbei um eine Replikation handelt, ist es in der Regel effektiver, Materialized Views auf dem Zielsystem neu anzulegen und nicht zu übertragen. Keine Sorgen muss man sich allerdings um Datenbank-Jobs, Constraints und Trigger machen, die bei einer Standardreplikation zu durchaus unangenehmen Nebeneffekten führen können. Bei der Logical-Standby-Datenbank gilt: Constraints werden nicht überprüft und Trigger nicht »gefeuert«, wenn die entsprechenden Daten über den Apply-Prozess übertragen wurden. Constraints und Trigger auf Tabellen, die nicht über den Apply-Prozess übertragen wurden, werden ganz normal ausgeführt. Datenbank-Jobs werden nicht ausgeführt, sondern es werden nur deren Metainformationen (z.B. über den nächsten Ausführungszeitpunkt) übertragen. Durch die Einschränkungen passt das Prinzip der logischen Standby-Datenbank nur bedingt zum Thema des Kapitels »Hochverfügbarkeit«. Andererseits ermöglicht Oracle ab der Version 10.1.0.3 ein so genanntes Rolling Upgrade über genau diese Funktion. Damit ist es mit Oracle-Mitteln erstmalig möglich, eine hochverfügbare Datenbank im laufenden Betrieb zu migrieren, d.h., einen Datenbank-Patch oder ein neues Release einzuspielen. Mit Oracle Real Application Cluster ist dies, bis auf wenige explizite Ausnahmen, nicht möglich, genauso wenig wie mit der PhysicalStandby-Datenbank. Als Grundvoraussetzung für den Betrieb einer Logical-Standby-Datenbank muss das so genannte Supplemental Logging in der Datenbank aktiviert werden. Supplemental Logging Ohne die Aktivierung von Supplemental Logging werden nur Daten in die RedoLog-Dateien gespeichert, die für das Recovery der Daten für die entsprechende Datenbank benötigt werden. Das sind in der Regel die Row-ID und die geänderten Daten. Nicht dazu gehören z.B. Informationen über verkettete oder migrierte Sätze
744
Hochverfügbarkeit
(Chained Rows bzw. Migrated Rows) und natürlich Primärschlüssel (soweit sie nicht zu den geänderten Daten gehören). Damit ist es nicht möglich, Datensätze aus den Redo-Log-Dateien für eine andere Datenbank zu nutzen. Supplemental Logging kann auf Datenbank- oder auf Tabellenebene eingeschaltet werden, in unserem Fall ist natürlich nur die Datenbankebene interessant. Daneben gibt es unterschiedliche Stufen, je nachdem, wie viele zusätzliche Informationen in den Redo-Log-Dateien gespeichert werden sollen. Sie sollten also, bevor Sie die Funktion nutzen, beachten, dass die Aktivierung einen Einfluss auf ihre Transaktionen hat. SUPPLEMENTAL LOG DATA: Speichert zusätzliche Informationen für die Verwaltung von verketteten Zeilen und Cluster-Segmenten. Diese Option sollten Sie benutzen, wenn Sie mit dem Log Miner arbeiten wollen, um z.B. alte Transaktionen rückgängig zu machen. SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS: Speichert zusätzlich bei jeder Transaktion die Primärschlüssel ab. SUPPLEMENTAL LOG DATA (UNIQUE) COLUMNS: Jetzt werden neben dem Primärschlüssel auch die für die Identifikation erforderlichen eindeutigen Schlüssel gespeichert. SUPPLEMENTAL LOG DATA (FOREIGN KEY) COLUMNS: Bei Tabellen mit einem Fremdschlüssel werden bei deren Änderung auch alle anderen Spalten des Fremdschlüssels gespeichert. SUPPLEMENTAL LOG DATA (ALL) COLUMNS: Speichert alle Spalten der Datensätze mit Ausnahme von LONG, LOB und UDTs! Gerade die letzte Option erzeugt je nach System natürlich einen erheblichen Overhead und sollte nur in absoluten Ausnahmen verwendet werden. Für die Logical-Standby-Datenbank benötigen wir mindestens die Speicherung der Primärschlüssel, besser die Speicherung von Primärschlüsseln und eindeutigen Indizes. Daraus ergibt sich, dass für die Quelldatenbank folgender Befehl ausgeführt werden sollte: SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY, UNIQUE) COLUMNS; Listing 13.23: Einschalten des Supplemental Loggings
Die Überprüfung erfolgt über die View v$database: SELECT supplemental_log_data_min supp_min, supplemental_log_data_pk supp_pk, supplemental_log_data_ui supp_ui, supplemental_log_data_fk supp_fk, supplemental_log_data_all supp_all FROM v$database; SUPP_MIN SUPP_PK SUPP_UI SUPP_FK SUPP_ALL ---------- ---------- ---------- ---------- ---------IMPLICIT YES YES NO NO; Listing 13.24: Supplemental-Log-Überprüfung
Oracle Data Guard
745
Ausgeschaltet werden kann Supplemental Logging mit dem Befehl: SQL> ALTER DATABASE DROP SUPPLEMENTAL LOG DATA; Listing 13.25: Ausschalten des Supplemental Loggings
Aufbau der Logical-Standby-Datenbank Als Basis für den Aufbau der Logical-Standby-Datenbank dient die bereits besprochene Physical-Standby-Datenbankank. Da die Daten für die Übertragung eindeutig identifizierbar sein müssen, sollte zunächst überprüft werden, ob alle Tabellen einen Primärschlüssel oder zumindest einen eindeutigen Index haben. Folgender Befehl gibt die Tabellen aus, die keinen entsprechenden Schlüssel haben: SQL> SELECT owner, table_name, bad_column FROM dba_logstdby_not_unique; Listing 13.26: Ermittlung der Tabellen ohne Primary bzw. Unique Key
Für die Tabellen, die jetzt aufgelistet werden, sollte ein solcher Schlüssel angelegt werden. Ist dies nicht möglich, werden bei jeder Datenänderung alle skalaren Spalten (wie bei SUPPLEMENTAL LOG DATA (ALL) COLUMNS) in den Redo-Log-Dateien gespeichert und dadurch das Redo-Log-Volumen entsprechend vergrößert. Außerdem bedeutet dies, dass für jede Änderung (UPDATE, DELETE) auf dem Zielsystem ein Full Table Scan ausgeführt wird. Im folgenden Beispiel werden wir allerdings eine neue Konfiguration für ein MSWindows-System aufbauen, bei dem sich die Standby-Datenbank auf dem gleichen Rechner wie die Produktionsdatenbank befindet. Das bedeutet unter anderem, dass die Standby-Datenbank einen anderen Namen und eine andere Verzeichnisstruktur bekommen muss. Dies ist jedoch beim Aufbau einer solchen Umgebung durchaus üblich, da die Datenbank ja ebenfalls produktiv genutzt werden kann, z.B. als Data-Warehouse. Daher werden die Datenbanken im Folgenden QJA10G (Produktion) und DWH1 (Standby) genannt. Zunächst wird die Produktionsdatenbank für den Aufbau einer Standby-Umgebung vorbereitet. Da es sich hier um unterschiedliche Aufgaben handelt, werden die Serverparameter entsprechend angepasst, so dass es nicht sinnvoll erscheint, eine gemeinsame Datei wie bei der physikalischen Standby-Datenbank zu benutzen. Sinnvoll ist es hier wiederum, zunächst eine Textdatei der Parameter anzulegen (PFILE), diese zu editieren und anschließend wieder ein SPFILE zu erzeugen. Neben den Standardparametern werden für die Datenbank QJA10G folgende Parameter eingestellt: *.archive_lag_target = 900 *.db_unique_name = QJA10G *.service_names = QJA10G *.log_archive_config = 'DG_CONFIG=(QJA10G,DWH1)' *.log_archive_dest_1 = 'LOCATION=D:\oracle\oraarch\QJA10G\ VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=QJA10G' *.log_archive_dest_2 = 'SERVICE=DWH1
746
Hochverfügbarkeit
VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=DWH1' *.log_archive_format = 'QJA10G_%t_%s_%r.arc' *.fal_server = QJA10G *.fal_client = DWH1 *.standby_file_management = AUTO Listing 13.27: Parameter für Quelldatenbank in einer Logical-Standby-Konfiguration
Als Nächstes werden die notwendigen Verzeichnisse sowie der neue Dienst angelegt. Außerdem werden wiederum die listener.ora sowie die tnsnames.ora angepasst. CMD> CMD> CMD> CMD> CMD> CMD> CMD> CMD> CMD>
mkdir E:\oracle\oradata\DWH1 mkdir E:\oracle\oraarch\DWH1 mkdir D:\oracle\admin\DWH1 mkdir D:\oracle\admin\DWH1\pfile mkdir D:\oracle\admin\DWH1\udump mkdir D:\oracle\admin\DWH1\bdump mkdir D:\oracle\admin\DWH1\cdump set ORACLE_SID=DWH1 oradim –new –sid DWH1 –startmode m –spfile
Listing 13.28: Verzeichnisse und Dienst SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = QJA10g) (ORACLE_HOME = D:\oracle\product\10.1.0) (SID_NAME = QJA10g) ) (SID_DESC = (GLOBAL_DBNAME = DWH1) (ORACLE_HOME = D:\oracle\product\10.1.0) (SID_NAME = DWH1) ) ) LISTENER = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) (HOST = EU3202) (PORT = 1521)) ) Listing 13.29: Listener.ora QJA10G = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = LAPTOP1)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = QJA10g) ) )
Oracle Data Guard
747
DWH1 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = LAPTOP1)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = DWH1) ) ) Listing 13.30: Tnsnames.ora
Die für die Produktion erstellte Parameterdatei dient als Vorgabe für die StandbyDatenbank. Da hier einige Namen unterschiedlich sind, hier nochmals das komplette Listing: *.background_dump_dest = 'D:\oracle\admin\DWH1\bdump' *.compatible = '10.1.0.4.0' *.control_files = 'E:\oracle\oradata\DWH1\control01.ctl' *.core_dump_dest = 'D:\oracle\admin\DWH1\cdump' *.db_block_size = 8192 *.db_file_multiblock_read_count = 16 *.db_name = 'QJA10G' *.db_recovery_file_dest = 'E:\oracle\flash_recovery_area' *.db_recovery_file_dest_size = 1048576000 *.job_queue_processes = 10 *.open_cursors = 300 *.pga_aggregate_target = 104857600 *.processes = 150 *.remote_login_passwordfile = 'EXCLUSIVE' *.sga_target = 100M *.undo_management = 'AUTO' *.undo_tablespace = 'UNDOTBS1' *.user_dump_dest = 'D:\oracle\admin\DWH1\udump' *.archive_lag_target = 900 *.db_unique_name = DWH1 *.service_names = DWH1 *.log_archive_config = 'DG_CONFIG=(QJA10G,DWH1)' *.log_archive_dest_1 = 'LOCATION=E:\oracle\oraarch\DWH1\ VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=DWH1' *.log_archive_dest_2 = 'SERVICE=QJA10G VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=QJA10G' *.log_archive_format = 'DWH1_%t_%s_%r.arc' *.fal_server = QJA10G *.fal_client = DWH1 *.standby_file_management = AUTO *.db_file_name_convert = ('D:\oracle\oradata\QJA10G','E:\oracle\oradata\DWH1') *.log_file_name_convert = ('D:\oracle\oradata\QJA10G', 'E:\oracle\oradata\DWH1') Listing 13.31: Standby-Serverparameter
748
Hochverfügbarkeit
Bitte beachten Sie, dass Sie an dieser Stelle den Parameter db_name nicht ändern dürfen, da es sich zunächst um eine Kopie der Produktionsdatenbank handelt. Später werden wir diesen Parameter ebenfalls anpassen. Aus dieser Parameterdatei wird jetzt ein SPFILE erstellt und die Datenbank im NOMOUNT-Status hochgefahren. Vorher wird allerdings noch die Passwortdatei erstellt. CMD> set ORACLE_SID=DWH1 CMD> orapwd file=D:\oracle\product\10.1.0\database\PWDDWH1.ora entries=5 password=manager CMD> sqlplus / as sysdba SQL> CREATE SPFILE FROM PFILE = 'D:\oracle\admin\DWH1\pfile\initDWH1.ora'; SQL> STARTUP NOMOUNT Listing 13.32: Starten der Standby-Datenbank
Jetzt kann, so Sie kein aktuelles Backup haben, die Sicherung der Produktionsdatenbank erfolgen, die anschließend als Standby-Datenbank genutzt wird. CMD> rman target / RMAN> BACKUP DATABASE INCLUDE CURRENT CONTROLFILE FOR STANDBY PLUS ARCHIVELOG; Listing 13.33: Backup der Produktionsdatenbank CMD> rman target / auxiliary sys/manager@DWH1 Recovery Manager: Release 10.1.0.4.0 – Production Copyright (c) 1995, 2004, Oracle. All rights reserved. connected to target database: QJA10G (DBID= 565294000) connected to auxiliary database: DWH (not mounted) RMAN> DUPLICATE TARGET DATABASE FOR STANDBY NOFILENAMECHECK; Listing 13.34: Erstellen der Standby-Datenbank
Damit steht jetzt eine Physical-Standby-Datenbankank (DWH1) auf dem gleichen System wie die Produktion zur Verfügung. Entsprechend dem Kapitel 13.4.1 können Sie jetzt weitere Tests durchführen, um die Funktionsweise zu überprüfen. Allerdings ist ein Rollentausch nicht möglich, da die Datenbankparameter unterschiedlich sind. Um aus der physikalischen Standby-Datenbank eine logische zu machen, wird zunächst auf der Produktion eine spezielle Kontrolldatei erstellt, mit der die Standby-Datenbank dann hochgefahren wird. Da wir beide Datenbanken auf dem gleichen Rechner installiert haben, entfällt die Kopieraktion. CMD> CMD> SQL> SQL> CMD> CMD> SQL>
set ORACLE_SID=QJA10G sqlplus sys/manager@DWH1 as sysdba SHUTDOWN IMMEDIATE EXIT; del E:\oracle\oradata\DWH1\control01.ctl sqlplus / as sysdba ALTER DATABASE CREATE LOGICAL STANDBY CONTROLFILE AS 'E:\oracle\oradata\DWH1\control01.ctl'
Oracle Data Guard SQL> CMD> SQL> SQL>
749
EXIT; sqlplus sys/manager@DWH1 as sysdba STARTUP MOUNT ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;
Listing 13.35: Erstellen der Kontrolldatei
An dieser Stelle müssen Sie warten, bis das Media Recovery fertig ist. In der AlertDatei der Standby-Datenbank sollte ein Eintrag ähnlich dem Folgenden stehen: Media Recovery Applied UNTIL CHANGE 3605943 Listing 13.36: Media-Recovery-Information
Jetzt kann die Standby-Datenbank umgestellt werden. Dafür wird sie zunächst aktiviert und gestoppt. Anschließend wird die Datenbank in den Mount-Zustand gebracht, um den Datenbanknamen zu ändern. Ist dies erfolgreich, muss der entsprechende Serverparameter db_name angepasst und eine neue Passwort-Datei erstellt werden. Als Letztes wird die Datenbank mit RESETLOGS hochgefahren. CMD> CMD> SQL> SQL> SQL> SQL> SQL> CMD> CMD> CMD>
set ORACLE_SID=DWH1 sqlplus / as sysdba ALTER DATABASE ACTIVATE STANDBY DATABASE; SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER SYSTEM SET db_name=DWH1 scope=SPFILE; EXIT; nid TARGET=sys/manager DBNAME=DWH1 del D:\oracle\product\10.1.0\database\PWDDWH1.ora orapwd file=D:\oracle\product\10.1.0\database\PWDDWH1.ora entries=5 password=manager CMD> sqlplus / as sysdba SQL> STARTUP MOUNT; SQL> ALTER DATABASE OPEN RESETLOGS; Listing 13.37: Starten der Standby-Datenbank mit neuem Datenbanknamen
Den Abschluss bildet die Aktivierung des SQL-Apply-Prozesses. Zunächst muss in der Zieldatenbank der globale Datenbankname geändert werden, und daraufhin wird der Prozess gestartet. SQL> ALTER DATABASE RENAME GLOBAL_NAME TO DWH1; SQL> ALTER DATABASE START LOGICAL STANDBY APPLY; Listing 13.38: Starten des SQL-Apply-Prozesses
750
Hochverfügbarkeit
Troubleshooting Die wesentlichen Funktionen der Standby-Datenbank können über die entsprechenden Alert-Dateien überprüft werden. In einem Fall kam es bei Tests zu folgendem Eintrag in der Alert-Datei, der zum Stoppen des Apply-Prozesses führte: LOGSTDBY stmt: update "SYS"."JOB$" set "LAST_DATE" = TO_DATE('31.07.05', 'DD.MM.RR'), "THIS_DATE" = NULL, "NEXT_DATE" = TO_DATE('31.07.05', 'DD.MM.RR'), "TOTAL" = ,0246527777777777777777777777777777777799, "FAILURES" = 0, "FLAG" = 0 where "JOB" = 65 and "LAST_DATE" = TO_DATE('31.07.05', 'DD.MM.RR') and "THIS_DATE" = TO_DATE('31.07.05', 'DD.MM.RR') and "NEXT_DATE" = TO_DATE('31.07.05', 'DD.MM.RR') and "TOTAL" = ,0246527777777777777777777777777777777799 and "FAILURES" = 0 and "FLAG" = 0 and ROWID = 'AAAAAAAABAAAAWaAAO' LOGSTDBY status: ORA-06550: line 1, column 536: PLS-00103: Encountered the symbol "," when expecting one of ( - + case mod new not null count current exists max min prio ORA-06550: line 1, column 598: PLS-00103: Encountered the symbol "," when expecting one of ( - + case mod new not null count current exists max min prio LOGSTDBY Apply process P004 pid=22 OS id=2796 stopped
the following: avg
the following: avg
Listing 13.39: Fehler in der Alert-Datei
Wie hier ersichtlich, gab es einen Fehler bei der Ausführung des Datenbank-Jobs mit der Nummer 65. Es handelt sich um einen normalen Job in der Datenbank, der minütlich ausgeführt wird. Ein Überspringen des Fehlers ist damit ausgeschlossen. In der Zeile, die mit »TOTAL« beginnt, fällt jedoch auf, dass hier ein Komma verwendet wird, der dementsprechend die Fehlermeldung PLS-00103 generiert. Grund hierfür war wieder einmal die deutsche Sprachumgebung. Auf dem Produktionssystem waren, da die Datenbank mit dem DBCA angelegt wurde, folgende Serverparameter gesetzt: nls_language = 'GERMAN' nls_territory = 'GERMANY' Listing 13.40: Fehlerhafte NLS-Parameter
Das Territory führt dazu, dass Punkt und Komma bei Dezimaldarstellungen vertauscht werden. Der Fehler konnte auf der Standby-Seite einfach behoben werden, indem die Parameter gelöscht wurden.
Oracle Data Guard
751
Eine weitere Überprüfung kann mit der V$-View v$logstdby erfolgen, z.B. in der Form: SQL> SELECT type, status FROM v$logstdby; TYPE STATUS ------------ -------------------------------COORDINATOR ORA-16116: no work available READER ORA-16116: no work available BUILDER ORA-16116: no work available PREPARER ORA-16116: no work available ANALYZER ORA-16116: no work available APPLIER ORA-16116: no work available Listing 13.41: Überprüfung über v$logstdby
Als Letztes noch eine weitere View, welche die Übersicht über noch ausstehende Transaktionen gibt: dba_logstdby_progress. SQL> SELECT applied_time, read_sequence#,newest_sequence#, applied_scn, newest_scn FROM dba_logstdby_progress; APPLIED_T READ_SEQUENCE# NEWEST_SEQUENCE# APPLIED_SCN NEWEST_SCN --------- -------------- ---------------- ----------- ---------31-JUL-05 796 796 3620849 3620849 Listing 13.42: Überprüfung der Sequence-Nummern und SCN
13.4.3 Data Guard Broker Zusätzlich zur manuellen Verwaltung der Data-Guard-Konfiguration gibt es die Möglichkeit, den Data Guard Broker zu benutzen. Er steht als grafisches Werkzeug im Enterprise Manager Grid Control oder als Kommandozeile (dgmgrl) zur Verfügung. Bevor man sich mit dem Broker beschäftigt, sollte man bedenken, dass dieser alle manuellen Befehle übersteuert. Das bedeutet, dass zum Beispiel die manuelle Umschaltung des Protection-Modes durch den Broker wieder zurückgenommen wird. Für die Verwaltung der Data-Guard-Datenbanken über den Enterprise Manager ist er aber zwingend erforderlich. Das bedeutet, dass Sie in der Regel um die Benutzung kaum herumkommen, es sei denn, Sie verzichten auf den Enterprise Manager. Leider ist es uns in mehreren Versuchen nicht gelungen, eine Data-Guard-Konfiguration mit dem Enterprise Manager aufzubauen. Daher haben wir zunächst die Standby-Datenbank manuell aufgebaut, dann den Data Guard Broker konfiguriert und waren dann in der Lage, die weitere Administration über den Enterprise Manager durchzuführen. Die Konfiguration des Data Guard Brokers ist relativ einfach (zumal wenn man vorher die Data-Guard-Datenbank schon erstellt hat). Im folgenden Beispiel wird die bereits erstellte Data-Guard-Datenbank für den Broker konfiguriert. Der Name der Konfigurationsdatei ist STDBTEST1. Der Aufruf erfolgt auf dem primären Datenbankserver, so dass eine lokale Datenbankverbindung
752
Hochverfügbarkeit
erfolgt. Natürlich kann der Data Guard Broker auch über Oracle Net aufgerufen werden. Bei der Vergabe der Namen sollte darauf geachtet werden, dass die Standardeingabe (ohne Hochkommata) in Kleinbuchstaben erfolgt. Als Beispiel haben wir den Namen der primären Datenbank (PROD) in Hochkommata und großgeschrieben, den Namen der Data-Guard-Datenbank (STDBY) jedoch klein und ohne Hochkommata. 1. Aufruf des Data Guard Broker Managers % dgmgrl DGMGRL for Linux: Version 10.1.0.2.0 Production Copyright (c) 2000, 2004, Oracle. All rights reserved. Welcome to DGMGRL, type "help" for information. DGMGRL> connect / Connected.
2. Erstellen der Konfiguration mit dem Namen STDBTEST1 DGMGRL> create configuration 'STDBTEST1' as > primary database is 'PROD' > connect identifier is PROD; Configuration "STDBTEST1" created with primary database "PROD". DGMGRL> show configuration Configuration Name: STDBTEST1 Enabled: NO Protection Mode: MaxPerformance Databases: PROD - Primary database Current status for "STDBTEST1": DISABLED DGMGRL> add database 'STDBY' as > connect identifier is STDBY > maintained as physical; Database "STDBY" added.
DGMGRL> show configuration Configuration Name: STDBTEST1 Enabled: NO Protection Mode: MaxPerformance Databases: PROD - Primary database stdby - Physical standby database Current status for "STDBTEST1": DISABLED
Oracle Data Guard
753
3. Überprüfung der Konfiguration (auf beiden Datenbanken): DGMGRL> show database verbose stdby Database Name: stdby Role: PHYSICAL STANDBY Enabled: YES Intended State: ONLINE Instance(s): STDBY Properties: InitialConnectIdentifier = LogXptMode = Dependency = DelayMins = Binding = … LogArchiveFormat = LatestLog = TopWaitEvents = Current status for "stdby": DISABLED DGMGRL> show database verbose 'PROD'; Database Name: PROD Role: PRIMARY Enabled: NO Intended State: OFFLINE Instance(s): PROD Properties: InitialConnectIdentifier = LogXptMode = Dependency = DelayMins = Binding = … LogArchiveFormat = LatestLog = TopWaitEvents = Current status for "PROD": DISABLED
'STDBY' 'ARCH' '' '0' 'OPTIONAL' 'PROD_%t_%s_%r.arc' '(monitor)' '(monitor)'
'prod' 'ARCH' '' '0' 'OPTIONAL' 'PROD_%t_%s_%r.arc' '(monitor)' '(monitor)'
754
Hochverfügbarkeit
4. Aktivierung der Konfiguration DGMGRL> enable configuration Enabled. DGMGRL> show configuration Configuration Name: STDBYTEST1 Enabled: YES Protection Mode: MaxPerformance Databases: PROD - Primary database stdby - Physical standby database Current status for "STDBYTEST1": SUCCESS Listing 13.43: Konfiguration des Data Guard Brokers
Damit ist der Broker konfiguriert und kann jetzt, wie im nächsten Bild ersichtlich, über den Oracle Enterprise Manager Grid Control weiter verwaltet werden.
Abbildung 13.13: Verwaltung mit dem Enterprise Manager Grid Control
Über den Edit-Befehl im Data Guard Broker Manager können Sie die einzelnen Parameter, die mit dem Befehl SHOW DATABASE VERBOSE angezeigt werden, ändern. Dazu gehört unter anderem der Protection Mode. Im folgenden Beispiel wird der Protection Mode auf die maximale Verfügbarkeit (Maximum Availability) geändert. Dafür muss zunächst der Redo-Log-Transport auf den synchronen Modus geändert werden. Grundvoraussetzung ist, wie bereits erwähnt, dass die Data-Guard-Datenbank so genannte Standby-Redo-Log-Dateien konfiguriert hat. Sie sollten immer wieder darauf achten, dass unter Umständen die Rollen vertauscht werden können, d.h., jede Änderung sollte für alle beteiligten Datenbanken (primär und Standby) durchgeführt werden.
Oracle Data Guard
755
DGMGRL> edit database 'PROD' set property LogXptMode = 'SYNC'; Property "logxptmode" updated. DGMGRL> edit database stdby set property LogXptMode = 'SYNC'; Property "logxptmode" updated. Listing 13.44: Log-Transport-Modus setzen
Anschließend wird dann der neue Protection Mode gesetzt. Bisher hatten wir uns über die Umgebungsvariable ORACLE_SID direkt an die Datenbank angemeldet (connect / as sysdba, bzw. im DG-Manager einfach connect /). Für die Änderung des Protection Modes reicht das nicht aus, stattdessen ist hier die Eingabe von Benutzername (SYS) und Passwort notwendig. DGMGRL> connect sys/manager DGMGRL> EDIT CONFIGURATION SET PROTECTION MODE AS MAXPROTECTION; Operation requires shutdown of instance "PROD" on database "PROD". Shutting down instance "PROD"... Database closed. Database dismounted. ORACLE instance shut down. Operation requires startup of instance "PROD" on database "PROD". Starting instance "PROD"... Unable to connect to database ORA-12514: TNS:listener does not currently know of service requested in connect dscriptor Failed. You are no longer connected to ORACLE Please connect again. Unable to start instance "PROD". You must start instance "PROD" manually. Listing 13.45: Protection Mode ändern
Vorsicht! Wenn der Protection Mode geändert wird, wird die primäre Datenbank ohne Nachfrage heruntergefahren und neu gestartet! Wie im obigen Beispiel ersichtlich, wurde die Datenbank zwar ordnungsgemäß heruntergefahren, das Starten der Datenbank scheiterte jedoch. Der Grund hierfür ist, dass der Data Guard Broker eigene Servicenamen definiert (im Beispiel: PROD_DGB und PROD_XPT). Diese Servicenamen sind für den Oracle Net Listener dynamisch konfiguriert, so dass die entsprechenden Einträge nach dem Herunterfahren der Instanz nicht mehr zur Verfügung stehen. Änderungen an den Einträgen in der Datei listener.ora (statische Listener-Einträge) blieben leider erfolglos. Da es sich hier nur um einen Schönheitsfehler handelt, haben wir darauf verzichtet, das Verhalten näher zu untersuchen, und stattdessen die Datenbank wieder hochgefahren.
756
13.5
Hochverfügbarkeit
Replikation
Replikationsmechanismen spielen im Bereich Hochverfügbarkeit eine immer größere Rolle, da durch die bereits beschriebenen Varianten nicht alle Anforderungen abgedeckt werden. Ein in den letzten zwei Jahren immer wieder aufgetauchtes Problem sind Release- oder Hardware-Wechsel. Alle oben genannten Beispiele sind für eine homogene Hard- und Software-Architektur ausgelegt, und nur die logische Standby-Datenbank erlaubt es ab Version 10.1.0.3, ein so genanntes Rolling Upgrade durchzuführen. Plattformwechsel sind hier jedoch noch nicht möglich. Folgende Anforderungen werden von den Standardmethoden Real Application Cluster, Physical Standby und Logical Standby nicht oder nur sehr eingeschränkt abgedeckt: Unterschiedliche Hardware oder Betriebssysteme Aus Kostengründen kann es sinnvoll sein, eine andere Umgebung für den Fehlerfall zu benutzen. Eklatant ist diese Kostenbetrachtung für die Physical-Standby-Datenbankank, bei der Sie nicht nur eine teure Hardware, sondern auch die Oracle-Lizenzen kaufen müssen, um zu hoffen, dass ein Fehler nicht auftritt, d.h., die Produkte nicht zum Einsatz kommen. Ein zweiter Punkt kann der Wechsel des Anbieters sein. Die Leistungsfähigkeit heutiger Linux-Systeme führt in manchen Unternehmen zu der Fragestellung: »Können wir nicht auf preiswertere Hardware umstellen?« Aber wie sieht das in einer Hochverfügbarkeitsumgebung aus? Entfernte Standorte Wenn die Standorte, für welche die Systeme benötigt werden, weit auseinander liegen, kann eine Standby-Lösung und RAC u.U. aufgrund der Latenzzeit und natürlich der Leitungskosten ausscheiden. Hinzu kommt, dass aufgrund der Netzverfügbarkeit gewährleistet sein muss, dass eine lokale Autonomie gegeben ist, d.h., kein Standort darf von einem anderen abhängig sein. Operatorloser Betrieb mit redundanter Datenhaltung Die Standby-Lösungen verlangen in der Regel einen Eingriff des Operators bzw. Administrators, um die Rollen (Primärdatenbank – Standby-Datenbank) zu tauschen. Das führt unweigerlich zu einer nicht zu unterschätzenden Zeitspanne, während der die Produktion nicht zur Verfügung steht. Automatismen gibt es zwar in diesen Fällen, je nach Netzkonfiguration können sie aber auch dazu führen, dass ein permanentes »Bouncing« auftritt, d.h., die Rollen immer wieder hin und her getauscht werden. Partielle Hochverfügbarkeit Wenn man heutige Datenbankgrößen von mehreren Terabyte betrachtet, muss man sich die Frage stellen, ob es tatsächlich notwendig ist, den gesamten Datenbestand mehrfach zu verwalten (doppelt reicht schon nicht, da es in der Regel mindestens eine Spiegelung gibt). Es kann also ausreichend sein, ein Schema oder auch nur einige kritische Tabellen zu replizieren, um damit die kritische Anwendung umschalten zu können.
Replikation
757
Alle diese Gründe (und es gibt sicherlich noch einige weitere) können zu einer Replikation auf Basis von Advanced Replication, Oracle Streams oder einem anderen Produkt führen. Wir beschränken uns im Folgenden auf den Einsatz der Methoden für den Bereich Hochverfügbarkeit. Das Thema Advanced Replication haben wir ausführlicher im Buch »Oracle9i für den DBA« beschrieben, und Oracle Streams in der Komplexität von Advanced Queueing könnte sicherlich einige weitere Bücher füllen.
13.5.1 Replikationsarten In der Praxis werden unterschiedliche Arten der Replikation unterschieden, je nachdem, wie die Anforderungen der Anwendung sind. Dabei geht es in der Regel um die einfache Frage: »Wer darf die Daten ändern«. Mit der Einführung von Oracle7 im Jahre 1992 hat Oracle die verteilte Datenhaltung erlaubt, was zunächst als entscheidender Schritt für zukünftige Datenbankinfrastrukturen gewertet wurde. Eine echte Verteilung von Daten findet man heute jedoch nur noch selten, stattdessen werden die Daten durch die Replikation bewusst redundant abgespeichert. Der Grund ist vor allen Dingen die Verfügbarkeit der Anwendung. Während bei der verteilten Umgebung die Gesamtverfügbarkeit nur dann gegeben ist, wenn alle Komponenten (beteiligte Datenbanken plus Netzwerk) funktionieren, wird bei der Replikation die Verfügbarkeit durch die Redundanz erhöht. Allerdings birgt die Replikation auch die große Gefahr von Inkonsistenzen! Wenn zwei Datenbanken unabhängig voneinander operieren und das Netzwerk zwischen den Systemen zeitweise nicht zur Verfügung steht, kann es vorkommen, dass der gleiche Datensatz auf beiden Systemen geändert wird. Zwar kann dies vermieden werden, indem man zur synchronen Replikation übergeht, allerdings ist dadurch wiederum die Verfügbarkeit herabgesetzt, da eine Transaktion erst dann beendet ist, wenn alle beteiligten Datenbanken die Änderung angenommen haben. Insofern stehen also Verfügbarkeit und Datenkonsistenz gegeneinander. Folgende Arten von Inkonsistenzen können bei der Replikation auftreten: Primary-Key-Verletzung: Beim Einfügen eines Datensatzes wird festgestellt, dass es den Datensatz schon gibt. Dieser Konflikt kann am einfachsten dadurch gelöst werden, dass jede beteiligte Datenbank einen eigenen Satz an Schlüsseln bekommt. Das kann ein zusammengesetzter Schlüssel aus Datenbankname und Primärschlüssel sein oder ein Offset bzw. Nummernkreis bei Sequenzen (eine Datenbank die geraden, die andere die ungeraden Zahlen). No Data Found: Ein Datensatz sollte gelöscht werden, existiert aber nicht. Man könnte in diesem Fall natürlich sagen: »Macht nichts, der Datensatz sollte ja sowieso gelöscht werden.« Doch was ist mit der Konsistenz von abhängigen Sätzen? Ist diese dann noch gewährleistet? Besser ist es, wenn man in replizierten Umgebungen das Löschen von Datensätzen aus der Anwendung heraus vermeidet. Das bedeutet, dass die Anwendung einen Datensatz nur als gelöscht markiert (Update) und über einen nachgelagerten Prozess (Batchlauf) die so markierten Sätze von Zeit zu Zeit gelöscht werden. Update-Konflikt: Um eine solche Inkonsistenz zu erkennen, benötigt man eine spezielle Konflikterkennung. Dabei wird vor dem Update der Inhalt der Spalte
758
Hochverfügbarkeit
mit dem ursprünglichen Inhalt (Before-Image) auf dem Quellsystem verglichen. Dafür muss bei jedem Update dieses Before-Image mit repliziert werden. Für die Lösung eines solchen Konfliktes muss es einen Verantwortlichen geben, der entscheidet, welche Information die »richtige« ist. Wobei es je nach Anwendung sehr schwierig ist, zu entscheiden, was »richtig« bedeutet. Aus diesem Grund kann eine Replikation niemals als Aufgabe eines Datenbankadministrators angesehen werden, sondern sollte als eigenständiges Projekt mit den Verantwortlichen aus den Fachabteilungen und der Anwendungsentwicklung aufgesetzt werden. Dabei muss geklärt werden, wie Inkonsistenzen vermieden werden können bzw. was passiert, wenn eine Inkonsistenz auftritt. Folgende Arten der Replikation werden unterschieden: Read-only-Replikation: Hier werden alle Änderungen auf einer zentralen Datenbank (Master) durchgeführt und diese dann als Kopie an die beteiligten Replikationsdatenbanken (Snapshots) geschickt. Es kann also nicht zu Inkonsistenzen kommen, da die Replikate keine Schreibberechtigung haben. Für die Verfügbarkeit bedeutet dies allerdings, dass alle Anwendungen einen Zugriff auf die zentrale Datenbanken haben müssen (z.B. über Datenbank-Links) und beim Ausfall dieses Systems nur noch lesende Zugriffe möglich sind. Diese Replikationsart kommt oft für Anwendungen im Außendienst zum Einsatz, bei denen die Mitarbeiter die Daten (z.B. Versicherungspolicen eines Klienten) vom zentralen Server bekommen und dann vor Ort nur neue Policen erstellen, die per Uplink an den Server geschickt werden. Updatable Snapshot: Diese Erweiterung der Read-only-Replikation erlaubt die Änderung der Daten auf allen beteiligten Systemen. Auf dem Master findet jedoch eine Verifizierung statt, bei der Konflikte erkannt und hoffentlich behoben werden. Durch diese Zentrale ist es möglich, eine einfache Konfliktlösung – z.B. ältester oder jüngster Zeitstempel gewinnt – zu implementieren. Multi-Master-Replikation: Hier hat jede Datenbank die gleichen Rechte und Pflichten. Das bedeutet auch, dass alle Daten auf allen Systemen geändert werden können und zudem eine Konflikterkennung und -behebung stattfinden kann. Während bei der Snapshot- und Read-only-Replikation auch Teilbestände (bestimmte Spalten oder bestimmte Zeilen) repliziert werden können, werden bei der Multi-Master-Replikation in der Regel alle Daten repliziert. Eine MultiMaster-Replikation kann so weit aufgebaut werden, dass sowohl DML- als auch DDL-Operationen übertragen werden, so dass schlussendlich die gesamte Datenbank repliziert werden kann. Die Gefahr einer Inkonsistenz ist in diesem Fall am größten. Außerdem ist eine Konfliktlösung bei mehr als zwei beteiligten Datenbanken nur noch schwer zu realisieren. Primär-Sekundär-Replikation: Dieser Spezialfall wird in der Regel aus der MultiMaster-Replikation entwickelt. Dabei wird sichergestellt, dass sich die Anwendung zu einem Zeitpunkt nur an eine Datenbank anmelden kann. Dies kann z.B. durch eine Login-Prozedur geschehen, die überprüft, ob es sich bei dieser Datenbank um die Primärdatenbank handelt. Es sollte daher nicht zu Inkonsistenzen kommen. Das Gesamtkonzept einer solchen Replikation ähnelt dem der Standby-Datenbank, daher werden wir dieses Prinzip hier nicht weiter betrachten.
Replikation
759
Bei der Entwicklung einer Replikationsumgebung mit Updatable Snapshots oder Multi-Master-Replikation muss also eine Routine zur Konflikterkennung und Konfliktlösung gefunden werden. Ein relativ einfacher Fall kann z.B. so aussehen, dass über einen Staffelstab bzw. Token, der von der Anwendung abgefragt wird, das Schreibrecht auf Anwendungsebene geregelt ist. Dies ist z.B. in der Auftragsverarbeitung hilfreich, wo je nach Bearbeitungszustand der Mitarbeiter das Änderungsrecht an einem Auftrag erhält. Alle im Anschluss vorgestellten Lösungen (Advanced Replication, Oracle Streams, Quest Shareplex) bieten standardmäßig eine Konflikterkennung und eine Reihe von Konfliktlösungsroutinen. Es ist jedoch Aufgabe der Anwendungsentwicklung bzw. des betroffenen Fachbereiches zu entscheiden, welche Art der Konfliktlösung (oder Kombination) zum Einsatz kommt. Konfliktlösung bedeutet immer, dass ein Datensatz, der von einem Anwender ordnungsgemäß eingegeben wurde, durch das System geändert wird. Daher gehört einige Erfahrung dazu, ein solches System aufzubauen.
13.5.2 Advanced Replication Oracle Advanced Replication ist in der Oracle Enterprise Edition verfügbar und erlaubt den Aufbau von gleichberechtigten (Multi-Master-)Replikationen zwischen mehreren Datenbanken. Basis für die Replikation über diesen Mechanismus bilden die Datenbank-Links, das Two-Phase-Commit-Protokoll sowie Trigger. Die Oracle Trigger-Technologie haben wir bereits in Kapitel 5.5 angesprochen. Im Folgenden werden wir Datenbank-Links und das Two-Phase-Commit-Protokoll kurz vorstellen und anschließend die Funktionsweise einer Multi-Master-Replikation erklären. 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 Serverparameter 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 folgendem Befehl geändert werden: SQL> ALTER DATABASE RENAME GLOBAL_NAME TO SUNDB.HL.DE;
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.
760
Hochverfügbarkeit
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 einem Directory Server angelegt. Sie enthalten keine expliziten Benutzernamen, sondern benutzen den Namen des aufrufenden Benutzers mit seinem aktuellen Kennwort für die Anmeldung. Außerdem existiert im Umfeld der Replikation der Name Scheduled Link. Hierbei handelt es sich jedoch nicht um einen Datenbank-Link, sondern um 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. Beispiel für Datenbank-Links SQL> CREATE PUBLIC DATABASE LINK ja10g USING 'JA10G'; SQL> SELECT table_name FROM user_tables@ja10g; Listing 13.46: Erstellen eines Public-Datenbank-Links
In diesem Beispiel wird ein Public Link auf die Datenbank mit der Adresse ja10g erstellt. Die anschließende Abfrage gibt alle Tabellennamen des äquivalenten Benutzers auf der anderen Datenbank aus. SQL> CREATE PUBLIC DATABASE LINK ja10g_demo CONNECT TO demo IDENTIFIED BY demo USING 'JA10G'; SQL> SELECT table_name FROM user_tables@ja10g_demo; Listing 13.47: 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.
Replikation
761
SQL> CREATE DATABASE LINK ja10g CONNECT TO demo IDENTIFIED BY demo USING 'JA92'; SQL> SELECT table_name FROM user_tables@ja10g; Listing 13.48: Private Link auf ein spezifisches Schema
Obwohl es bereits einen Public Link ja10g auf die Datenbank mit der Adresse ja10g gibt, kann der Benutzer einen Private Link mit gleichem Namen auf die Datenbank mit der Adresse ja92 erstellen. In diesem Fall greift dieser Benutzer immer auf die Datenbank ja92 und den Benutzer demo zu, während alle anderen auf die Datenbank ja10g 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. SQL> CREATE SYNONYM kunden FOR kunden@ja10g; SQL> SELECT nachname FROM kunden; Listing 13.49: Einsatz von Synonymen
Gerade dieses Beispiel ist interessant für die Migration von Anwendungen, da das Synonym jederzeit geändert und somit die Tabelle kunden von einer auf die andere Datenbank verschoben werden kann, ohne dass die Anwendung dies merkt. Two Phase Commit 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. SQL> INSERT INTO KUNDEN (kdnr, anrede, vorname, nachname) VALUES (100001, 'Frau', 'Carina','Ahrends'); SQL> INSERT INTO KUNDEN@ja10g (kdnr, anrede, vorname, nachname) VALUES (100001, 'Frau', 'Carina','Ahrends'); SQL> COMMIT; Listing 13.50: Verteilte Transaktion und Two Phase Commit
762
Hochverfügbarkeit
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, wie im Beispiel, für synchrone Replikate 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 Redo-Log-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 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 wird über den Serverparameter commit_point_strength ermittelt. 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.
Replikation
763
Abbildung 13.14: Two Phase Commit
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 Commits 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 Redo-Log-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. In diesem Fall gibt es einen Eintrag in der Tabelle dba_2pc_pending. Über die lokale oder globale Transaktions-ID (LOCAL_TRAN_ID bzw. GLOBAL_TRAN_ID) kann die Transaktion jetzt zurückgerollt (ROLLBACK FORCE ) oder festgeschrieben (COMMIT FORCE ) werden. Anschließend wird der Eintrag in der Regel aus der Tabelle gelöscht und die Transaktion damit abgeschlossen. In seltenen Fällen kann es vorkommen, dass eine Transaktion selbst mit dieser Methode nicht ordnungsgemäß abgeschlossen werden kann. In diesem Fall wird die Spalte MIXED in der Tabelle dba_2pc_pending auf den Wert YES gesetzt. Solche Einträge können dann nur mit der Prozedur dbms_transaction.purge_mixed
764
Hochverfügbarkeit
behoben werden. Ähnliches gilt, wenn eine Datenbank in einer verteilten Transaktion neu aufgebaut werden muss (incomplete Recovery). Da in diesem Fall die Transaktion nicht mehr ausgeführt werden kann, müssen Sie die entsprechenden Einträge manuell löschen. Dies geschieht mit der Prozedur dbms_transaction.purge_lost_db_entry. 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. Multi-Master-Replikation Das Grundprinzip der Multi-Master-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 Spalten und Zeilen auf jedem Master vertreten sind. Änderungen auf einem Master werden dementsprechend auf allen anderen Mastern – zeitversetzt oder synchron – repliziert.
Abbildung 13.15: Multi-Master-Replikation
Replikationsobjekte werden in so genannten Replikationsgruppen (Replication Group) zusammengefasst. Jede Replikationsgruppe kann Objekte aus einem oder mehreren Schemata enthalten, und umgekehrt können Objekte eines Schemas in unterschiedlichen Replikationsgruppen konfiguriert sein. Jedes Replikationsobjekt darf jedoch nur in einer Gruppe enthalten sein.
Replikation
765
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 13.16: Replikationsgruppen
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 überträgt Ä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. Aufgrund der synchronen Übertragung sind Datenkonflikte per se ausgeschlossen.
766
Hochverfügbarkeit
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: Tabellen werden mit ihrer Struktur und ihren Daten repliziert. Zur Struktur zählen hier nicht nur die Spalten, sondern auch die Constraints, nicht aber im Kontext der Tabelle definierte Trigger oder Indizes. Letztere müssen explizit 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 Spaltenwerte, um Konflikte zu erkennen.
Abbildung 13.17: 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:
Replikation
767
Primary-Site-Prinzip: Änderungen sind nur auf einem und stets demselben Master zulässig. Konflikte sind aufgrund 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 frei bleibenden 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. Beispiel einer Multi-Master-Replikation 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. Das stark vereinfachte Datenmodell dieser Firma besteht aus folgenden Tabellen:
Abbildung 13.18: ER-Diagramm der Beispieltabellen
768
Hochverfügbarkeit
Alle Tabellen werden in einem Schema namens reptest angelegt. Für die Hochverfügbarkeit stehen zwei Datenbanken zur Verfügung: Köln: koeln.ganzbillig München: muenchen.ganzbillig
Grundkonfiguration Die folgende Beschreibung setzt voraus, dass die Enterprise Edition vorliegt. Eine Kontrolle kann jederzeit über die virtuellen Tabellen v$version durchgeführt werden. Über die View v$option kann nochmals überprüft werden, ob die AdvancedReplication-Option tatsächlich installiert ist. Nach erfolgreicher Installation müssen darüber hinaus die Pakete dbms_repcat und dbms_reputil vorhanden sein. Gleichfalls muss Oracle Net zuvor installiert und konfiguriert worden sein, d.h., die Namen der beteiligten Systeme müssen für Oracle Net interpretierbar sein. Da es sich hier um eine bidirektionale Replikation handelt, werden wir die Konfiguration nur für ein System erklären, da ja die beteiligten Systeme gleichberechtigt sind. 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 10.1.0. global_names = true zwingt zu einem globalen Namensmodell, d.h., DatenbankLinks müssen identisch zu den 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 Jobverwaltung an. Der Parameter muss mindestens auf 1 gesetzt werden, besser noch auf die Zahl der gleichzeitig auszuführenden Datenbankjobs. In Multi-Master-Umgebungen mit n Mastern, die möglicherweise zeitgleich übertragen, auf mindestens n-1. Leider wird der neue Oracle Scheduler zurzeit noch nicht unterstützt. open_links gibt die maximale Anzahl der für jede Sitzung gleichzeitig zu öffnenden Datenbank-Links an. Der Parameter ist vor allem bei synchronen Übertragungsverfahren 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ängigkeiten zwischen Transaktionen. Diese Abhängigkeitsprüfungen sind entscheidend für die parallele Übertragung verzögerter Transaktionen.
Replikation
769
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 DatenbankLinks aufzubauen. Diese Schritte lassen sich über die Konsole des Enterprise Managers 9i, dort unter dem Menüpunkt REPLIKATION, dann SETUP WIZARD, erledigen, falls ein globaler Replikationsadministrator gewünscht wird.
Falls der globale Name der Datenbank noch angepasst werden soll, kann dies mit folgendem Befehl durchgeführt werden: SQL> ALTER DATABASE RENAME GLOBAL_NAME TO koeln.ganzbillig;
Zunächst wird auf jeder Master Site ein Public Link angelegt, der die entsprechende USINGKlausel für die geplante Master Site enthält. SQL> CREATE PUBLIC DATABASE LINK muenchen.ganzbillig USING 'muenchen.ganzbillig';
Als Nächstes wird der Replikationsadministrator repadmin auf den Systemen angelegt. SQL> CREATE USER repadmin IDENTIFIED BY geheim; SQL> BEGIN dbms_repcat_admin.grant_admin_any_schema ( USERNAME => 'repadmin'); END; /
Damit der Replikationsadministrator, der ja bewusst keine DBA-Privilegien erhalten hat, auch die Enterprise-Manager-Konsole aufrufen und die Replikationsmenüs benutzen kann, muss ihm das Recht zum Abfragen des Data Dictionarys gegeben werden: SQL> GRANT SELECT ANY DICTIONARY TO repadmin;
Danach werden die Propagator und Receiver registriert. /* Propagator / SQL> BEGIN dbms_defer_sys.register_propagator ( USERNAME => 'repadmin'); END; / /* Receiver */ SQL> BEGIN dbms_repcat_admin.register_user_repgroup ( USERNAME => 'repadmin', PRIVILEGE_TYPE => 'receiver', LIST_OF_GNAMES => NULL); End; /
770
Hochverfügbarkeit
Als Nächstes werden die so genannten Scheduled Links zwischen den Systemen angelegt. Dabei handelt es sich um private Datenbank-Links zwischen den Replikationsadministratoren. SQL> CONNECT repadmin/[email protected] SQL> CREATE DATABASE LINK muenchen.ganzbillig CONNECT TO repadmin IDENTIFIED BY geheim;
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 repadmin, angelegt: SQL> CONNECT repadmin/[email protected] SQL> BEGIN dbms_defer_sys.schedule_push ( DESTINATION => 'koeln.ganzbillig', INTERVAL => 'sysdate + 15/1440', NEXT_DATE => SYSDATE, STOP_ON_ERROR => FALSE, DELAY_SECONDS => 60, PARALLELISM => 0); END; /
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: SQL> CONNECT repadmin/geheim@gs_muenchen.ganzbillig SQL> BEGIN dbms_defer_sys.schedule_purge ( NEXT_DATE => SYSDATE, INTERVAL => 'SYSDATE + 1/24', DELAY_SECONDS => 0); END; /
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.
Replikation
771
Der Job zum Übertragen administrativer Aufgaben wird beim Anlegen von Replikationsgruppen automatisch erstellt. Auf diese Weise erhält jede Replikationsgruppe ihren eigenen Administrations-Job. Aufbau der Replikationsgruppen Nachdem der Benutzer, die Jobs und die Datenbank-Links aufgebaut wurden, kann mit dem Anlegen der Replikationsgruppen und replizierten Objekte begonnen werden. Wir verwenden hier nur eine Gruppe. Natürlich ist es, wie bereits erwähnt, auch möglich, mehrere Gruppen aufzubauen. Die Master Site, auf der die Gruppe angelegt wird, wird automatisch zur Master Definition Site dieser Gruppe. SQL> CONNECT repadmin/[email protected] SQL> BEGIN dbms_repcat.create_master_repgroup ( GNAME => 'repgruppe1', GROUP_COMMENT => 'Replikationsgruppe', MASTER_COMMENT => 'Master-Site in Köln'); END; /
Die neue Gruppe ist nun bereit, die zu replizierenden 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 repadmin durchgeführt: SQL> BEGIN dbms_repcat.create_master_repobject ( GNAME => 'repgruppe1', TYPE => 'table', ONAME => 'kunden', SNAME => 'reptest', USE_EXISTING_OBJECT => TRUE, COPY_ROWS => TRUE); END; /
Die Prozedur geht davon aus, dass die betreffende Tabelle kunden auf den anderen Master Sites, hier das noch zu definierende System muenchen.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 Replikationsadministrator auch der Eigentümer der zu replizierenden Objekte, kann alternativ mit use_existing_object => false gearbeitet werden, so dass die betreffenden Objekte beim Aufbau der Master Sites automatisch dort angelegt werden. 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 (disable) oder die Objekte vorher manuell – und in der richtigen Reihenfolge – auf allen weiteren Master Sites angelegt werden. Bei selbstbezüglichen oder zirkulären2 Fremdschlüsselbeziehungen ist der vorherige manuelle Aufbau und das Befüllen mit Daten, etwa durch
772
Hochverfügbarkeit
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 replizierten Objekte sind in diesem Fall die Parameter copy_rows => false und use_existing_object => true zu setzen. Master Sites hinzufügen Sind alle replizierten Objekte angelegt, werden die weiteren Master Sites der Gruppe deklariert: SQL> BEGIN dbms_repcat.add_master_database ( GNAME => 'repgruppe1', MASTER => 'muenchen.ganzbillig', PROPAGATION_MODE => 'asynchronous'); END; /
Im vorangehenden Beispiel wird die Gruppe repgruppe1 auf die Master Site muenchen.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 ist3. Eine erfolgreich abgeschlossene Generierung lässt sich zum einen an der lee2 3
Tabelle A weist auf Tabelle B und umgekehrt. Der Wert NEEDSGEN, wenn die Generierung läuft, dann DOINGGEN.
Replikation
773
ren 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. Im folgenden Beispiel werden für die Tabelle kunden des Schemas reptest die internen Objekte erzeugt: SQL> BEGIN dbms_repcat.generate_replication_support ( SNAME => 'reptest', ONAME => 'kunden', TYPE => 'table'); END; /
Aktivierung der Replikationsgruppen und Benutzerbetrieb Im Verlaufe der Generierung ü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: SQL> BEGIN dbms_repcat.resume_master_activity ( GNAME => 'repgruppe1'); END; /
DML-Aktionen sind danach möglich und werden wie gewohnt durchgeführt: SQL> UPDATE kunden SET nachname = 'Meier' WHERE kdnr = 12345; SQL> COMMIT;
Durch die internen Trigger wird nun ein Paketaufruf generiert und in die Transaktionswarteschlange eingereiht. Diese Warteschlange kann über den Enterprise Manager oder über die Views deftran und defcall des Schemas sys angezeigt werden: SQL> 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.05.05 09:18:46 Listing 13.51: Deferred Transactions
774
Hochverfügbarkeit
Die Identifizierungsnummer der verzögerten Transaktion – hier 3.30.85 – wird gebildet aus der Nummer des Undo-Segmentes, das die Originaltransaktion verwaltet hat, und der Index- sowie der Versionsnummer des Transaktionseintrags im Header-Block dieses Undo-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: SQL> SELECT gname, dblink, masterdef md, master m FROM all_repsites WHERE gname = 'REPGRUPPE1' AND dblink <> dbms_reputil.global_name; GNAME DBLINK MD M ---------- -------------------------- ---- ---REPGRUPPE1 MUENCHEN.GANZBILLIG Y Y Listing 13.52: Replikationsinformation über 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 modifizierten 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: SQL> SELECT * FROM defcall; CALLNO DEFERRED_T SCHEMANAME PACKAGENAME PROCNAME ARGCOUNT ------- ---------- ----------- ------------- ---------- -------0 3.30.85 REPTEST KUNDEN$RP REP_UPDATE 15 Listing 13.53: View defcall
Bei der Übertragung der Transaktion 3.30.85 wird von koeln.ganzbillig die Paketprozedur kunden$rp.rep_update auf 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 der Version 9. 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:
Replikation
775
SQL> 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);
Konflikterkennung und Konfliktauflösung Auf die Möglichkeit, dass Konflikte bei asynchronen Übertragungsverfahren auftreten, für den Fall, dass innerhalb eines Synchronisierungsintervalls 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 ab, ob entsprechende Konfliktlösungsstrategien konfiguriert wurden oder nicht. Im folgenden Beispiel werden für den Kunden mit der Kundennummer 4711 der Wohnort und die Straße in München und Köln geändert. Auf muenchen.ganzbillig wird eingegeben: SQL> UPDATE SET WHERE AND
adressen ort = 'Bonn' kdnr = 4711 adrnr = 123;
Auf koeln.ganzbillig wird eingegeben: SQL> UPDATE SET WHERE AND
adressen strasse = 'Heimweg 1' kdnr = 4711 adrnr = 123;
Listing 13.54: Update-Konflikt
Bei der anschließenden Übertragung der Daten, die in unserem Beispiel aufgrund 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 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, »Heimweg 1«, auf muenchen.ganzbillig überein. Der entstandene Fehler ist in diesem Beispiel doppelt ärgerlich, weil die Änderungen auf unterschiedlichen Attributen des Kunden 4711 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 ort »Köln« nicht identisch ist mit dem aktuellen Wert »Bonn« auf koeln.ganzbillig. Mehr noch: Jede Folgetransaktion, die den gleichen Datensatz manipuliert, ganz gleich auf welcher Seite, wird ebenfalls Fehler bei der Übertragung verursachen!
776
Hochverfügbarkeit
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. 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 sind 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: SQL> BEGIN dbms_defer_sys.delete_error ( DEFERRED_TRAN_ID => '14.45.9', DESTINATION => null); END; /
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 muenchen.ganzbillig SQL> BEGIN dbms_reputil.replication_off(); END; /
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 betreffenden Anwendung ab. Mögliche Lösungen können das exklusive Sperren
Replikation
777
der betreffenden Objekte oder sogar der exklusive Start4 der jeweiligen Instanz sein. In keinem Fall hilft das Herunterfahren der Replikationsgruppe5, 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 4711 von Köln in München übernommen: -- auf muenchen.ganzbillig SQL> UPDATE adressen a1 SET (strasse, plz, ort, telefon) = (SELECT strasse, plz, ort, telefon FROM [email protected] a2 WHERE a2.kdnr = a1.kdnr AND a2.adrnr = a1.adrnr) WHERE kdnr = 4711 AND adrnr = 123;
Sind alle Anpassungen manuell durchgeführt worden, kann die Replikation wieder eingeschaltet werden: -- auf muenchen.ganzbillig SQL> BEGIN dbms_reputil.replication_on(); END; /
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 kann, potenzieren sich die Aufwände. Aus diesem Grunde ist es dringend notwendig, automatische Konfliktauflösungen überall dort zu konfigurieren, wo UPDATE-, INSERT- oder DELETE-Operationen auf mehr als einer Master Site möglich sein können. Allerdings macht dieses Beispiel auch deutlich, dass eine Konfliktlösung eine »menschliche« Entscheidung ist. Wer kann bei diesem Beispiel sagen, welche Daten »die richtigen« sind? Konfliktauflösungen arbeiten im Kontext von Spaltengruppen. Diese fassen eine oder mehrere Spalten einer replizierten Tabelle 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, und jeder dieser Gruppen 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 unterschiedlichen Lösungsroutinen Konflikte innerhalb eines Datensatzes unterschiedlich aufgelöst werden und damit Spalten verschiedener Master »gewinnen«. Bei der Konfiguration von 4 5
Startup restrict ... dbms_repcat.suspend_master_activity.
778
Hochverfügbarkeit
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.
Abbildung 13.19: Spaltengruppen und Konfliktlösungsmethoden
In unserem Beispiel sollen Konflikte, die beim Verändern von Adressdaten 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 adressen muss um eine DATE-Spalte (dml_datum) erweitert werden. 2. Ein Trigger muss bei UPDATE- und INSERT-Operationen dafür sorgen, dass die DATESpalte 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 repgruppe1 zunächst von der Master Definition Site aus heruntergefahren: SQL> BEGIN dbms_repcat.suspend_master_activity ('REPGRUPPE1'); END; /
Das Herunterfahren der Gruppe kann einige Zeit in Anspruch nehmen, vor allem dann, wenn die Transaktionswarteschlange noch Einträge aufweist, die vor dem Stoppen abgearbeitet werden müssen. Der Status der Gruppe kann wie folgt kontrolliert werden: SQL> SELECT gname, status FROM all_repgroup WHERE gname = 'REPGRUPPE1'; GNAME STATUS ------------------------------ --------REPGRUPPE1 QUIESCED Listing 13.55: Kontrolle der Replikationsgruppe
Replikation
779
Der Status quiesced zeigt in diesem Fall an, dass 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: SQL> BEGIN dbms_repcat.alter_master_repobject ( SNAME => 'REPTEST', ONAME => 'ADRESSEN', TYPE => 'TABLE', DDL_TEXT => 'ALTER TABLE adressen ADD(dml_datum DATE)'); END; / Listing 13.56: Hinzufügen einer Spalte über den Replikationsmechanismus
Im Anschluss daran darf nicht vergessen werden, die internen Trigger und Prozeduren neu zu generieren: SQL> BEGIN dbms_repcat.generate_replication_support ( SNAME => 'REPTEST', ONAME => 'ADRESSEN', TYPE => 'TABLE'. MIN_COMMUNICATION => TRUE); END; / Listing 13.57: Neue Generierung der Replikationstrigger und Prozeduren
Als Nächstes wird der Trigger angelegt. Dieser soll bei lokalen INSERT- und UPDATEOperationen 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: SQL> CREATE OR REPLACE TRIGGER t$adressen_ui_br BEFORE INSERT OR UPDATE ON adressen FOR EACH ROW BEGIN -Nur für lokale Operationen IF NOT DBMS_REPUTIL.FROM_REMOTE () THEN :new.dml_date := sysdate; END IF; END; / Listing 13.58: Trigger für die Pflege des Datumsfeldes
780
Hochverfügbarkeit
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: SQL> BEGIN dbms_repcat.create_master_repobject ( GNAME => 'REPGRUPPE1', SNAME => 'REPTEST', ONAME => 'T$ADRESSEN_UI_BR', TYPE => 'TRIGGER'); END; / Listing 13.59: Übertragung des neuen 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 adressen enthalten soll: SQL> BEGIN dbms_repcat.make_column_group ( SNAME => 'REPTEST', ONAME => 'ADRESSEN', COLUMN_GROUP => 'ADRESSEN_CG1', LIST_OF_COLUMN_NAMES => 'KDNR, ADRNR, STRASSE, PLZ, ORT, DML_DATE'); END; / Listing 13.60: Definition der Spaltengruppe
Spaltengruppen und ihnen zugeordnete Spalten lassen sich über die Views all_repcolumn_group und all_repgrouped_column6 abfragen. 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: SQL> BEGIN dbms_repcat.add_update_resolution ( SNAME => 'REPTEST', ONAME => 'ADRESSEN', COLUMN_GROUP => 'ADRESSEN_CG1', SEQUENCE_NO => 1, METHOD => 'LATEST TIMESTAMP', PARAMETER_COLUMN_NAME => 'DML_DATE'); END; / Listing 13.61: Konfliktlösungsroutine 6
Wie immer gibt es auch hier die DBA- und User-Variante.
Replikation
781
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 repgruppe1 wieder gestartet und für den DML-Betrieb geöffnet werden: SQL> BEGIN dbms_repcat.resume_master_activity ('REPGRUPPE1'); END; /
Bevor die Tabelle jedoch der Schar der Benutzer wieder zugänglich gemacht wird, sollte – unter Ausschaltung der Replikation mit Hilfe von dbms_reputil. replication_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 4712 wird zunächst in München die Straße angepasst, dann in Köln der Ort verändert: SQL> UPDATE SET WHERE AND
adressen ort = 'Burscheid' kdnr = 4712 adrnr = 51
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 4712 übernommen, 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: SQL> BEGIN dbms_repcat.register_statistics ( SNAME => 'REPTEST', ONAME => 'ADRESSEN'); END; /
782
Hochverfügbarkeit
Im Anschluss daran können auf dem System, das bei der Konfliktauflösung »verloren« hat, dessen Daten also überschrieben wurden, wie folgt Statistiken abgefragt werden. In unserem Beispiel ist dies München: SQL> 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.05.05 11:47:20 4712 REPTEST KUNDEN UPDATE KUNDEN_CG1
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. 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 im Beispiel verwendeten 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 MasterObjekt 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 Replikationsumgebungen unerlässlich. 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. Hier ist es empfehlenswert, die Tabellen vorher auf allen Master Sites explizit anzulegen und über geeignete Verfahren, wie z.B. Data-Pump-Export bzw. -Import zu füllen. Bei der Konfiguration der replizierten Umgebung wird dann über die Parameter copy_rows => false und use_existing_object7 => true dafür gesorgt, dass die Struktur der Objekte ver7
Im Rahmen von dbms_repcat.create_master_repobject
Replikation
783
glichen wird, die Datenübertragung aber nicht mehr stattfindet. Der Administrator trägt damit natürlich die Verantwortung für die Konsistenz, d.h., die Anwendung darf zu diesem Zeitpunkt noch nicht produktiv genutzt werden. 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-Einbußen 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. Jetzt kann der Import erfolgen. 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 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.
784
Hochverfügbarkeit
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 Deferred Transaction Queue gespeichert. Die Deferred Transaction Queue besteht aus Tabellen des Schemas SYSTEM8. Diese Tabellen liegen auch in der Version 10g im Tablespace SYSTEM, 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 bereits erwähnt – über einen speziellen Purge-Job konfiguriert. Änderungen an Master-Objekten, denen eine oder mehrere Materialized Views 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 Log-Tabellen 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 Netzwerkverbindungen. 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. Abschlussbemerkung Abschließend sei noch darauf hingewiesen dass es sich bei der Advanced Repliction um ein Auslaufmodell zu handeln scheint. Nur so ist z.B. zu erklären, dass es im Enterprise Manager der Version 10g keine Unterstützung für diese Methode gibt, obwohl dies gerade im Hinblick auf Konflikte, Pending- oder In-Doubt-Transaktionen dringend empfohlen ist. Oracle verweist in der Dokumentation auf den Enterprise Manager der Version 9i. Lediglich die Replikation über Materialized Views, die ja auch in Data-WarehouseUmgebungen eingesetzt werden (siehe Kapitel 15.2.5), wird in Zukunft eine Rolle in diesem Umfeld spielen.
8
Hier vor allem die Tabellen def$_aqcall und def$_lob
Replikation
785
Aufgrund der Komplexität der Advanced Replication für die Hochverfügbarkeit sollten Sie sich überlegen, die im Folgenden beschriebenen Methoden Oracle Streams oder Quest SharePlex anzuwenden.
13.5.3 Oracle Streams Die Replikation von Daten über die Advanced-Queueing-Methode in Verbindung mit dem Log Miner hat Oracle in der Version 9i Release 2 erstmals zur Verfügung gestellt. In Version 10g kommen neue Funktionen hinzu, und die gesamte Konfiguration wurde vereinfacht. Leider gibt es derzeit keine Möglichkeit, die Administration und das Monitoring über den Enterprise Manager Database Control oder Grid Control durchzuführen. Laut Oracle-Dokumentation kann zwar eine Administration über den älteren Enterprise Manager erfolgen, diesen Weg haben wir jedoch nicht mehr betrachtet und hoffen, dass im Release 2 des Enterprise Managers eine vollständige Konfiguration und Monitoring möglich sein werden. Oracle Streams ist kein eigenständiges Produkt, sondern besteht aus einer Reihe von PL/SQL-Packages. Bei der Installation der Oracle-Software werden Sie also vergeblich nach entsprechenden Einträgen suchen. In der Standard Edition ist Streams leider zurzeit nicht enthalten. Streams-Architektur Wie bereits erwähnt, basiert Oracle Streams auf der Advanced-Queueing-Architektur. Das heißt, eigentlich besteht die Aufgabe von Streams darin, Nachrichten (welcher Art auch immer) zu erfassen, diese in Queues zu speichern und dann an unterschiedliche Abonnenten (Subscriber) weiterzureichen. Die spezielle Aufgabe besteht darin, dass es sich bei den Nachrichten um Einträge aus den Redo-LogDateien handelt. Dadurch hat Streams ohne den bei Advanced Replication notwendigen Overhead von Triggern den Zugriff auf alle Datenbankänderungen. Wenn Streams konfiguriert ist, gibt es einen neuen Hintergrundprozess, der Capture genannt wird und der DDL- und DML-Änderungen in den Redo-Log-Dateien erfasst. Diese Befehle werden in so genannte Logical Change Records (LCR) umgewandelt, die dann in einer Queue-Tabelle gespeichert werden. Ein LCR bezieht sich auf eine Änderung (z.B. ein Datensatz), so dass sich eine Transaktion über beliebig viele LCRs erstrecken kann. Aus der Queue-Tabelle werden die LCRs dann in eine andere Queue-Tabelle in der gleichen oder einer anderen Datenbank übertragen (Propagation). Auf der Gegenseite gibt es einen Apply-Prozess, der die Daten aus der Queue entgegennimmt. Dieser verteilt dann die Nachrichten, je nachdem, ob es sich um einen DML- oder DDL-Befehl handelt, an den entsprechenden Message Handler. Da es sich ja um eine Advanced-Queueing-Methode handelt, können auch Benutzernachrichten eingebettet sein, für die es wiederum einen eigenen Message Handler gibt (siehe Abbildung 13.20). Die Übertragung der Daten erfolgt bei Oracle Streams in Form von Job-Prozessen, die ganz normal über dbms_job (leider noch nicht über das verbesserte Scheduling) administriert werden.
786
Hochverfügbarkeit
Abbildung 13.20: Streams-Architektur
Im Gegensatz zu den Standby-Funktionalitäten können die Nachrichten jederzeit durch den Streams-Administrator manipuliert oder gefiltert werden. Dadurch ist es möglich, nur bestimmte Daten zu übertragen oder die Daten nach der Übertragung zu ändern, was zum Beispiel für eine Konfliktlösung bei gleichberechtigter Replikation notwendig ist. Für den Apply-Prozess auf dem Zielsystem ist es notwendig, die Data-DictionaryInformationen der Quelle zu kennen. Daher wird für den Start einer Streams-Replikation ein so genanntes Log Miner Data Dictionary benötigt. Dieses Data Dictionary wird immer dann benötigt, wenn neben DML-Operationen auch DDL-Befehle repliziert werden sollen. Für die Replikation mit Streams stehen unterschiedliche Regeln (Rules) zur Auswahl: Tabelle: Hierbei werden nur die Änderungen für eine einzelne Tabelle repliziert. Schema: Alle Änderungen, die ein bestimmtes Schema betreffen, werden repliziert. Global: Alle Datenbankänderungen werden repliziert. Für jede Regel kann außerdem angegeben werden, ob DML, DDL oder beides repliziert werden soll. Speziell für Tabellen-, aber auch für Schema-Rules macht es zudem Sinn, diese zu so genannten Rule Sets zusammenzufassen. Dabei gibt es positive (inklusive) und negative (exklusive) Rule Sets, so dass es einfach möglich ist, bestimmte Objekte von einer Replikation auszuschließen, ohne dass man eine lange Liste anfertigen muss.
Replikation
787
Eine Regel bezieht sich dabei nicht auf den gesamten Stream, sondern kann für jeden Prozessteil (Capture, Propagation, Apply) einzeln definiert werden. Damit ist es z.B. möglich, zunächst alle Daten zu sammeln (Capture), aber nur einen bestimmten Teil an eine andere Datenbank zu schicken (Propagation). Auf dem Zielsystem können wiederum aus den empfangenen Daten bestimmte Aktionen (DDL) oder bestimmte Datensätze herausgefiltert werden (Apply). Neben diesen Standardregeln gibt es auch die Möglichkeit, Transformationen von Regeln durchzuführen. Dadurch kann z.B. eine Replikation zwischen unterschiedlichen Schemata oder unterschiedlichen Tabellenstrukturen erfolgen. Da wir uns hier im Kapitel Hochverfügbarkeit befinden, werden wir nur die Standardregeln verwenden. Im Gegensatz zur Standby-Datenbank sind bei Replikationen die Datenbanken in der Regel unabhängig voneinander aufgebaut. Da nur Daten aus den Redo-LogDateien übertragen werden, müssen die bereits vorhandenen Daten erst auf das Zielsystem übertragen werden (z.B. per Export/Import), und anschließend muss anhand der SCN-Nummer des Quellsystems eine Synchronisierung erfolgen. Diese SCN wird Instantiation SCN genannt und kann entweder über eine Prozedur oder direkt während des Einladens mit dem Importbefehl angegeben werden. Downstream Capture Kritischer Punkt bei der Replikation mit Streams ist, dass die Daten zunächst lokal in einer Queue-Tabelle zwischengespeichert werden. Dabei handelt es sich um eine ganz normale DML-Operation (INSERT-Befehl), die dem Transaktionsmechanismus von Oracle unterliegt. D.h., es werden Undo-Informationen geschrieben, und die Änderungen werden wiederum in den Redo-Log-Dateien (aus denen sie ja kommen) gespeichert. Das kann bei kritischen Systemen und umfangreichen Replikationen dazu führen, dass die Performance der Datenbank darunter leidet. In diesem Fall ist es ab Version 10 möglich, einen so genannten Downstream Capture aufzubauen, bei dem die Replikation über eine separate Datenbank erfolgt. Dabei werden zunächst die archivierten Redo-Log-Dateien an eine entfernte Datenbank geschickt. In dieser Datenbank wurde Streams so konfiguriert, dass es auf die archivierten Redo-Log-Dateien einer anderen Datenbank zugreifen kann. Wie bereits erwähnt, basiert Streams auf dem Log Miner, und dieser kann – auch schon in der Version 8i – auf archivierte Log-Dateien einer anderen Datenbank zugreifen, wenn die Data-Dictionary-Informationen bekannt sind. Das heißt, für den initialen Start von Streams wird über die Prozedur dbms_capture.build eine Kopie des Data Dictionarys in den Redo-Log-Dateien gespeichert. Auf diese kann der Capture-Prozess dann aufsetzen und das Log Miner Data Dictionary aufbauen. Nachteil dieser Methode ist, dass die Daten erst dann repliziert werden können, wenn die Redo-Log-Datei archiviert worden ist. In hochverfügbaren Umgebungen ist das in der Regel nicht tragbar, daher verzichten wir im Weiteren auf die Betrachtung dieser Methode.
788
Hochverfügbarkeit
Voraussetzungen Wie bereits erwähnt, kann Oracle Streams nur bei der Enterprise Edition angewendet werden. Daneben gibt es einige Serverparameter, die entsprechend gesetzt werden müssen. In Oracle9i war es noch so, dass die Zwischenspeicherung der LCRInformationen ausschließlich über den Shared Pool erfolgte. Dies führte nach einiger Zeit zu einer starken Fragmentierung des Pools und damit zu kritischen Einflüssen auf das Produktionssystem. Mit Version 10g hat Oracle zunächst dafür gesorgt, dass Streams nur noch einen bestimmten Bereich (maximal 10%) im Shared-Pool benutzen kann, aber alternativ ist es möglich, einen separaten Streams Pool anzulegen. Wir raten auf jeden Fall dazu, dies zu tun. Durch die mittlerweile sehr flexible Änderung von SGA-Parametern ohne Reboot kann der Parameter jederzeit gesetzt bzw. angepasst werden. Folgende Serverparameter müssen gesetzt bzw. angepasst werden: compatible global_names job_queue_processes open_links streams_pool_size undo_retention
= = = = = =
10.1.0 TRUE 2 4 10MB 3600
Listing 13.62: Serverparameter für Streams
Die Werte für die genannten Parameter sind die Mindestanforderungen. Speziell die Parameter job_queue_processes und streams_pool_size müssen eventuell angepasst werden. Des Weiteren muss die Quelldatenbank im Archive-Log-Modus betrieben werden, und für die zu replizierenden Objekte muss das Supplemental Logging mit der Option LOG DATA aktiviert werden. Auch hier gibt es einen Unterschied zur Version 9i. Während dort das Supplemental Logging nur auf Datenbankebene konfigurierbar war, kann es jetzt für einzelne Objekte ein- und ausgeschaltet werden. Da die Datenbanken über Oracle Net bzw. Datenbank-Links miteinander kommunizieren, ist es natürlich notwendig, dass die entsprechenden Netzwerklomponenten konfiguriert sind. Die Konfiguration von Streams geschieht über ein separates Datenbankschema, das explizit die Rolle DBA haben muss. In der Version 9i war es auch möglich, die notwendigen Rechte separat zu setzen, leider funktioniert das mit Version 10g nicht mehr. Außerdem gilt für jede Replikation, dass die zu replizierenden Objekte einen Primärschlüssel haben sollten. Schemareplikation mit Streams Als Beispiel werden wir im Folgenden eine bidirektionale Replikation des Schemas DEMO zwischen den Datenbanken (KOELN und TOELZ) aufbauen. Das bedeutet, wir verwenden eine Schemaregel, bei der wir alle Aktionen (DML und DDL) zulassen.
Replikation
789
Für die Namen der wählbaren Streams-Parameter, wie z.B. der Streams-Tabelle, haben wir den Namen des Streams-Administrators und den Zusatz, um welchen Prozess bzw. welches Objekt es sich handelt, gewählt. Als Erstes werden die Parameter gesetzt und die Datenbanken im Archive-LogModus gestartet. Außerdem wird ein Tablespace (STREAMSTS) für die Streams-Dateien und der Streamsadministrator (STREAMSADMIN) angelegt. Da beide Datenbanken im Wesentlichen identisch konfiguriert werden, beschränken wir uns beim folgenden Beispiel zunächst auf die Replikation von KOELN nach TOELZ. KOELN: SQL> SQL> SQL> SQL> SQL>
SQL> SQL> SQL> SQL> SQL>
SQL>
SQL>
ALTER SYSTEM SET global_names = TRUE; ALTER SYSTEM SET job_queue_processes = 10; ALTER SYSTEM SET streams_pool_size = 20M; ALTER SYSTEM SET log_archive_dest_1 = 'LOCATION=/data/archive/KOELN/'; ALTER SYSTEM SET log_archive_format = 'KOELN_%t_%s_%r.arc' SCOPE=SPFILE; SHUTDOWN IMMEDIATE STARTUP MOUNT ALTER DATABASE ARCHIVELOG; ALTER DATABASE OPEN; CREATE TABLESPACE streamsts DATAFILE '/data/KOELN/streamsts01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 500M EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO; CREATE USER streamsadmin IDENTIFIED BY manager DEFAULT TABLESPACE streamsts; GRANT CONNECT, RESOURCE, DBA, AQ_ADMINISTRATOR_ROLE TO streamsadmin;
Listing 13.63: Vorbereitung Datenbank KOELN
Als Nächstes werden die Streams-Prozesse konfiguriert. Zusätzlich wird in jeder Datenbank ein Datenbank-Link angelegt. KOELN: SQL> CREATE DATABASE LINK toelz CONNECT TO STREAMSADMIN IDENTIFIED BY manager USING 'TOELZ';
Mit diesem Befehl wird der Datenbank-Link auf das Zielsystem angelegt. Bitte achten Sie darauf, dass der Linkname dem globalen Datenbanknamen entsprechen muss.
790
Hochverfügbarkeit
BEGIN dbms_streams_adm.set_up_queue( queue_name => 'STREAMS_QUEUE', queue_table => 'STREAMS_QUEUE_TABLE', queue_user => 'STREAMSADMIN'); COMMIT; END; /
Es wird eine neue Queue mit dem Namen STREAMS_QUEUE angelegt. Die Daten werden unter dem Benutzer STREAMSADMIN in die Tabelle STREAMS_QUEUE_TABLE gespeichert. BEGIN dbms_streams_adm.add_schema_rules( schema_name => 'DEMO', streams_type => 'CAPTURE', streams_name => 'STREAMSADMIN_CAPTURE', queue_name => 'STREAMSADMIN.STREAMS_QUEUE', include_dml => TRUE, include_ddl => TRUE, source_database => 'KOELN'); COMMIT; END; /
Eine neue Schemaregel wird erstellt. Diese Regel gilt für den Capture-Prozess, also für das Auslesen der Daten aus den Redo-Log-Dateien. Es sollen alle Änderungen (DML und DDL) des Benutzers DEMO protokolliert werden. Quelldatenbank ist hierbei die lokale Datenbank KOELN. BEGIN dbms_streams_adm.add_schema_propagation_rules( schema_name => 'DEMO', streams_name => 'STREAMSADMIN_PROPAGATE', source_queue_name => 'STREAMSADMIN.STREAMS_QUEUE', destination_queue_name => 'STREAMSADMIN.STREAMS_QUEUE@TOELZ', include_dml => TRUE, include_ddl => TRUE, source_database => 'KOELN'); COMMIT; END; /
Für die Weitergabe der Daten wird eine Propagation-Regel erstellt, in der im Wesentlichen die gleichen Informationen stehen wie in der Capture-Regel. Zusätzlich wird hier die »Gegenstelle«, d.h. die Ziel-Queue, definiert (destination_queue_name). Dafür muss der Datenbank-Link entsprechend gesetzt sein.
Replikation
791
TOELZ: SQL> CREATE DATABASE LINK koeln CONNECT TO STREAMSADMIN IDENTIFIED BY manager USING 'KOELN';
Auch in dieser Datenbank wird zunächst ein Datenbank-Link angelegt. Zwar wird dieser für die unidirektionale Replikation nicht benötigt, aber unter Umständen ist es ganz hilfreich, über den Datenbank-Link kommunizieren zu können. Auch hier gilt, dass der Linkname dem globalen Datenbanknamen entsprechen muss. BEGIN dbms_streams_adm.set_up_queue( queue_table => 'STREAMS_QUEUE_TABLE', queue_name => 'STREAMS_QUEUE', queue_user => 'STREAMSADMIN'); COMMIT; END; /
Es wird wiederum eine Queue mit dem Namen STREAMS_QUEUE angelegt. Die Namen der Queues sowie der Queue-Tabelle sind frei wählbar, sollten aber auf beiden Seiten gleich sein, da es die Lesbarkeit erhöht. BEGIN dbms_streams_adm.add_schema_rules( schema_name => 'DEMO', streams_type => 'APPLY', streams_name => 'STREAMSADMIN_APPLY', queue_name => 'STREAMSADMIN.STREAMS_QUEUE', include_dml => TRUE, include_ddl => TRUE, source_database => 'KOELN'); COMMIT; END; /
Da es sich bei dieser Datenbank zunächst nur um das Zielsystem handelt, wird auch nur der Apply-Prozess konfiguriert. Das Schema DEMO muss an dieser Stelle auf dem Zielsystem noch nicht existieren. Damit sind alle Vorkehrungen für die Replikation des Benutzers DEMO getroffen. Als Nächstes muss für die Tabellen des Benutzers DEMO das Supplemental Logging eingeschaltet werden. Da es sich in der Regel um eine ganze Anzahl von Tabellen handelt, kann man natürlich auch für die gesamte Datenbank die Option aktivieren. Alternativ kann man auch ein SQL*Plus-Skript erstellen, mit dem die Aktivierung automatisch erfolgt:
792
Hochverfügbarkeit
CONNECT demo/demo@KOELN set heading off set feedback off set pages 1000 set lines 1000 set trimspool on spool c:\temp\enable_sup.sql SELECT 'ALTER TABLE DEMO.'||table_name ||' ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;' FROM user_tables / spool off @c:\temp\enable_sup.sql Listing 13.64: Enable Supplemental Logging
Das generierte Skript (enable_sup.sql) sieht etwa wie folgt aus: ALTER ALTER ALTER ALTER ALTER ALTER
TABLE TABLE TABLE TABLE TABLE TABLE
DEMO.KUNDEN ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS; DEMO.AUFTRAEGE ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS; DEMO.POSITIONEN ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS; DEMO.PRODGRUPPEN ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS; DEMO.PRODUKTE ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS; DEMO.STATUS ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
Listing 13.65: Generiertes Skript für Supplemental Logging
Damit ist für alle Tabellen das Supplemental Logging eingeschaltet. Überprüft werden kann die Aktivierung über die View user_log_groups, z.B. in der Form: SQL> SELECT table_name, log_group_type FROM user_log_groups; TABLE_NAME LOG_GROUP_TYPE ------------------------------ -----------------KUNDEN ALL COLUMN LOGGING AUFTRAEGE ALL COLUMN LOGGING POSITIONEN ALL COLUMN LOGGING PRODGRUPPEN ALL COLUMN LOGGING PRODUKTE ALL COLUMN LOGGING STATUS ALL COLUMN LOGGING Listing 13.66: Überprüfung des Supplemental Table-Log
Im nächsten Schritt muss das Schema DEMO mit allen Objekten auf dem Zielsystem angelegt werden. Hierfür kann traditionell der Export-/Importbefehl benutzt werden. Der Import wurde für die Unterstützung von Streams um die Option STREAMS_INSTANTIATION = Y erweitert. Dadurch wird die Instantiation SCN ermittelt und mit übertragen. Da es sich hierbei um eine eindeutige Nummer für alle zu replizierenden Objekte handelt, muss der Export mit der Option CONSISTENT = Y erfolgen. Da es in Oracle 10g aber mit Data Pump eine bessere Methode gibt, werden wir die Initialbefüllung der Zieldatenbank über diesen Mechanismus durchführen. Data Pump arbeitet standardmäßig mit den Oracle Flashback-Funktionen, so dass es nicht notwendig ist, explizit einen Konsistenzpunkt zu setzen. Alternativ kann
Replikation
793
aber eine Flashback-SCN ermittelt und über die Option FLASHBACK_SCN beim Export gesetzt werden. Da der Benutzer streamsadmin alle notwendigen Rechte hat, werden wir den Export und Import über diesen Benutzer durchführen. Über den Parameter NETWORK_LINK ist es zudem möglich, ohne Dump-Datei zu arbeiten. D.h., auf dem Zielsystem (TOELZ) wird ein Directory angelegt und anschließend der Befehl impdp gestartet. Hier kommt uns zugute, dass wir den Datenbank-Link schon angelegt haben. SQL> CREATE DIRECTORY streamsdump AS '/data/dumps/';
Als Nächstes werden die Daten mit dem Befehl impdp auf dem Zielsystem eingelesen: % impdp streamsadmin/manager logfile=imp_demo.dmp directory=STREAMSDUMP schemas='DEMO' content=ALL network_link=KOELN Listing 13.67: Übertragen der Daten mit impdp
Mit den Objekten wurden natürlich auch die Informationen über das Supplemental Logging übertragen, so dass, wenn wir die bidirektionale Replikation aufbauen, dieser Schritt entfallen kann. Jetzt steht der Aktivierung der Replikation nichts mehr im Wege. Zunächst wird auf dem Quellsystem (KOELN) der Capture-Prozess gestartet. SQL> BEGIN dbms_capture_adm.start_capture( capture_name => 'STREAMSADMIN_CAPTURE'); END; /
Anschließend wird der Apply-Prozess auf dem Zielsystem (TOELZ) gestartet. SQL> BEGIN dbms_apply_adm.start_apply( apply_name => 'STREAMSADMIN_APPLY'); END; /
Damit ist die Replikation von KOELN nach TOELZ für das Schema DEMO aktiv. Bitte beachten Sie, dass wir im Beispiel alle Befehle (DML und DDL) replizieren. Das bedeutet, wenn wir in dieser Konfiguration Änderungen an einem Schemaobjekt vornehmen, werden diese sofort repliziert. Vielleicht werden Sie im ersten Moment sagen: »Das ist ja auch richtig.« Sie sollten aber bedenken, dass die häufigste Fehlerursache Anwender- bzw. Anwendungsfehler sind. Gerade der Befehl TRUNCATE, gegen den es in der Version 10g im Gegensatz zum DROP oder DELETE noch kein »Gegenmittel« gibt, kann somit zum Ausfall ihrer kompletten Umgebung führen. Es ist daher anzuraten, DDL-Befehle nicht zu replizieren, sondern gezielt zu ändern. Beachten Sie dabei bitte, dass Sie die Änderungen erst auf dem Sekundärrechner vornehmen und anschließend auf dem Primärsystem, da es ansonsten zu Fehlern beim Einfügen neuer Sätze kommt.
794
Hochverfügbarkeit
Monitoring Für das Monitoring sind folgende Views interessant: Auf der Quellseite gibt die View dba_capture_prepared_tables an, für welche Tabellen der Capture-Prozess Nachrichten sammelt. Auf dem Zielsystem bildet hierzu die View dba_instantiated_objects das Pendant, in der in unserem Fall die gleichen Informationen stehen sollten. Zusätzlich gibt es auf dem Zielsystem die Möglichkeit, Fehlermeldungen aus der View dba_apply_error abzufragen. Dort ist z.B. aufgeführt, wenn für die Konfiguration keine Instantiation-SCN gesetzt worden ist. Der Apply-Prozess wird in diesem Fall abgebrochen. Bidirektionale Replikation Der Übergang auf die bidirektionale Replikation ist trivial. Es müssen nur die entsprechenden Prozesse auf der Gegenseite aktiviert werden, außerdem braucht das neue Ziel natürlich wieder eine Instantiation-SCN. Für TOELZ bedeutet dies, dass der Capture- und der Propagation-Prozess konfiguriert werden müssen. BEGIN dbms_streams_adm.add_schema_rules( schema_name => 'DEMO', streams_type => 'CAPTURE', streams_name => 'STREAMSADMIN_CAPTURE', queue_name => 'STREAMSADMIN.STREAMS_QUEUE', include_dml => TRUE, include_ddl => TRUE, source_database => 'TOELZ'); COMMIT; END; / BEGIN dbms_streams_adm.add_schema_propagation_rules( schema_name => 'DEMO', streams_name => 'STREAMSADMIN_PROPAGATE', source_queue_name => 'STREAMSADMIN.STREAMS_QUEUE', destination_queue_name => 'STREAMSADMIN.STREAMS_QUEUE@KOELN', include_dml => TRUE, include_ddl => TRUE, source_database => 'TOELZ'); COMMIT; END; /
Replikation
795
BEGIN dbms_capture_adm.start_capture( capture_name => 'STREAMSADMIN_CAPTURE'); END; /
Für KOELN muss der Apply-Prozess konfiguriert und aktiviert werden. Außerdem muss die Instantiation-SCN gesetzt werden. BEGIN dbms_streams_adm.add_schema_rules( schema_name => 'DEMO', streams_type => 'APPLY', streams_name => 'STREAMSADMIN_APPLY', queue_name => 'STREAMSADMIN.STREAMS_QUEUE', include_dml => TRUE, include_ddl => TRUE, source_database => 'TOELZ'); COMMIT; END; / DECLARE iscn NUMBER; -- Variable to hold instantiation SCN value BEGIN iscn := dbms_flashback.get_system_change_number@TOELZ; dbms_apply_adm.set_schema_instantiation_scn( source_schema_name => 'DEMO', source_database_name => 'TOELZ', instantiation_scn => iscn, recursive => TRUE); COMMIT; END; / BEGIN dbms_apply_adm.start_apply( apply_name => 'STREAMSADMIN_APPLY'); END; / Listing 13.68: Bidirektionale Replikation
Wenn der Fehler auftritt, dass die Instantation-SCN fehlt, muss eine neue Synchronisierung stattfinden. Sollten sich die Daten während dieser Zeit nicht geändert haben, können Sie jederzeit eine Instantiation-SCN, wie im obigen Beispiel, erzeugen. Am einfachsten geschieht dies durch eine Prozedur, die über den Datenbank-Link als Remote Procedure Call die SCN ausliest und dann entsprechend für die Regel setzt. Wichtig ist hierbei die Angabe von recursive => TRUE, da standardmäßig die SCN für jede Tabelle einzeln gesetzt wird, selbst wenn man die Schema-Instantiation wählt.
796
Hochverfügbarkeit
Konfliktlösung Da es sich jetzt um eine Multi-Master-Replikation handelt, sollte, bevor die Anwendung tatsächlich in Betrieb geht, darüber nachgedacht werden, wie eine Konfliktlösung aussehen kann. Die Konflikterkennung erfolgt automatisch über den Streams-Prozess, die Konfliktlösung über spezielle Prozeduren des Packages dbms_apply_adm. Folgende Konfliktlösungen wenden wir an: 1. Primary-Key-Verletzung: Die Datenbank KOELN erhält Sequenzen mit ungerader Nummer und TOELZ die mit gerader Nummer. 2. No Data Found: Das Löschen von Daten ist aus der Anwendung heraus nicht erlaubt, stattdessen wird eine Spalte GELOESCHT für jede Tabelle eingefügt, die durch die Anwendung entsprechend gesetzt werden kann. 3. Update-Konflikt: Aufgrund der Anforderung der Fachabteilung ist entschieden worden, dass die Datenbank in Köln die Änderungen in Tölz überschreibt. In dem Beispiel wird sowohl DML als auch DDL repliziert. Wenn man jetzt die Sequenzen ändert, werden diese natürlich wiederum repliziert. Daher muss zunächst die Replikation von Sequenzinformationen ausgeschlossen werden. Dafür wird auf beiden Systemen der Capture-Prozess gestoppt, anschließend wird die Capture-Regel für DDL-Änderungen mit dem Befehl dbms_rule_adm.alter_rule geändert und danach der Capture-Prozess wieder gestartet. Für die Änderung einer Regel ist es logischerweise erforderlich zu wissen, wie die Regel heißt. Dafür gibt es drei unterschiedliche Views: dba_rules zeigt die gültigen Regeln mit den so genannten Conditions an. dba_rulesets listet die Rule-Sets auf. dba_rule_set_rules gibt an, welche Regel zu welchem Rule-Set gehört. Im Zusammenhang mit der View dba_capture kann hieraus ermittelt werden, welche Regeln für den Capture-Prozess definiert sind. Im Beispiel sollten zwei Regeln aktiv sein, eine für DML-Operationen und eine für die DDL-Befehle. Für die besprochene Änderung ist nur die DDL-Regel wichtig. BEGIN dbms_capture_adm.stop_capture( capture_name => 'STREAMSADMIN_CAPTURE'); END; / --- Ermitteln des Regelnamens fuer den Capture-Prozess -SELECT r.rule_name, r.rule_condition FROM dba_rules r, dba_rule_set_rules rs, dba_capture c WHERE r.rule_name = rs.RULE_NAME AND r.rule_owner = rs.rule_owner AND rs.RULE_SET_NAME = c.RULE_SET_NAME AND rs.RULE_SET_OWNER = c.RULE_SET_OWNER;
Replikation
797
RULE_NAME RULE_CONDITION ---------- ---------------------------------------------------------------------DEMO18 ((:dml.get_object_owner() = 'DEMO') and :dml.is_null_tag() = 'Y' and : DEMO19 ((:ddl.get_object_owner() = 'DEMO' or :ddl.get_base_tabl BEGIN dbms_rule_adm.alter_rule ( rule_name => 'DEMO19', condition => '('|| '(:ddl.get_object_owner() = ''DEMO'' '|| ' or :ddl.get_base_table_owner() = ''DEMO'') '|| ' and :ddl.is_null_tag() = ''Y'' '|| ' and :ddl.get_source_database_name() = ''TOELZ.SC.QUEST.DE'' '|| ' and :ddl.get_object_type() = ''SEQUENCE'' )' ); COMMIT; END; / BEGIN DBMS_capture_adm.start_capture( capture_name => 'STREAMSADMIN_CAPTURE'); END; / Listing 13.69: Ausschließen der Replikation von Sequenzen
Als Alternative gibt es auch die Möglichkeit, eigene Regeln zu definieren und diese als positive oder negative Regeln an den Capture-Prozess zu binden. Laut OracleDokumentation wird allerdings die negative Regel zuerst ausgewertet, so dass die Möglichkeit, damit einen Ausschluss des Standardverhaltens zu bewirken, entfällt. Durch diese Änderung können anschließend die Sequenzen angepasst werden. In Köln: DROP SEQUENCE DEMO.SEQ_KUNDENNR; CREATE SEQUENCE DEMO.SEQ_KUNDENNR START WITH 10001 INCREMENT BY 2 MINVALUE 1 NOCYCLE CACHE 20 NOORDER;
In Tölz: DROP SEQUENCE DEMO.SEQ_KUNDENNR; CREATE SEQUENCE DEMO.SEQ_KUNDENNR START WITH 10002 INCREMENT BY 2 MINVALUE 1 NOCYCLE CACHE 20 NOORDER; Listing 13.70: Anpassen der Sequences
798
Hochverfügbarkeit
Als Nächstes muss die Anwendung geändert werden, so dass die zusätzliche Spalte GELOESCHT für alle Tabellen gepflegt wird. Dies ist Aufgabe der Anwendungsentwicklung und wird daher hier nicht näher betrachtet. Als Letztes wird exemplarisch für die Tabelle KUNDEN eine Konfliktlösungsroutine eingebaut, die bei Änderungen der gleichen Zeile die Änderung von TOELZ durch KOELN überschreibt. Hierfür gibt es die Prozedur dbms_apply_adm.set_update_conflict_handler, der die folgenden Standardlösungen kennt: MAXIMUM: Der größere von zwei Werten wird eingetragen. MINIMUM: Der kleinere von zwei Werten wird eingetragen. OVERWRITE: Der aktuelle Datensatz wird durch die Replikation überschrieben. DISCARD: Die Änderung durch die Replikation wird ignoriert. Natürlich reichen diese Möglichkeiten in der Praxis nicht aus, dafür müssen dann eigenentwickelte Prozeduren eingesetzt werden. Im Beispiel wird für den ApplyProzess der Datenbank KOELN die Option DISCARD gewählt (Änderungen aus der Datenbank TOELZ werden ignoriert). Für die Datenbank TOELZ wird die Option OVERWRITE gewählt. Damit ist sichergestellt, dass die Datenbank KOELN die Hoheit über die Daten hat. KOELN: DECLARE spalten DBMS_UTILITY.NAME_ARRAY; i NUMBER := 1; BEGIN FOR col_rec IN ( SELECT column_name FROM dba_tab_columns WHERE owner = 'DEMO' AND table_name = 'KUNDEN' ) LOOP spalten(i) := col_rec.column_name; i := i + 1; END LOOP; dbms_apply_adm.set_update_conflict_handler ( object_name => 'DEMO.KUNDEN', method_name => 'DISCARD', resolution_column => 'KD_NR', column_list => spalten); COMMIT; END; / Listing 13.71: Konfliktlösungsmethode für Datenbank KOELN
Replikation
799
TOELZ: DECLARE spalten DBMS_UTILITY.NAME_ARRAY; i NUMBER := 1; BEGIN FOR col_rec IN ( SELECT column_name FROM dba_tab_columns WHERE owner = 'DEMO' AND table_name = 'KUNDEN' ) LOOP spalten(i) := col_rec.column_name; i := i + 1; END LOOP; dbms_apply_adm.set_update_conflict_handler ( object_name => 'DEMO.KUNDEN', method_name => 'OVERWRITE', resolution_column => 'KD_NR', column_list => spalten); COMMIT; END; / Listing 13.72: Konfliktlösungsmethode für Datenbank TOELZ
Der Einfachheit halber wurden alle Spalten übernommen, obwohl es natürlich wenig sinnvoll ist, den Primärschlüssel, die Anrede oder den Vornamen zu ändern. Die aufgeführte Spalte resolution_column dient in diesem Fall der eindeutigen Identifizierung einer Spalte. Löschen der Streams-Replikation Die für die einzelnen Prozesse aufgestellten Regeln (Rules) können einzeln mit der Prozedur dbms_rule_adm.drop_rule wieder gelöscht werden. Ein Rule-Set kann mit der entsprechenden Prozedur dbms_rule_adm.drop_rule_set gelöscht werden. Diese Prozeduren werden vor allen Dingen dann genutzt, wenn Sie eigene Regeln definiert haben. Für die Standardregeln der Prozesse gibt es zusätzlich die Prozedur dbms_streams_adm.remove_rule, bei welcher der zugehörige Prozess (Capture, Propagator oder Apply) angegeben werden kann. Für das Löschen der Streams-Replikation gibt es eine weitere Prozedur im Package dbms_streams_adm: SQL> execute dbms_streams_adm.remove_streams_configuration(); Listing 13.73: Löschen der Streams-Konfiguration
Dieser Befehl stoppt alle Streams-Prozesse und löscht die entsprechenden Einträge. Der Befehl hat beim Aufsetzen dieser Beispiele gute Dienste geleistet, da es damit relativ einfach war, wieder einen initialen Zustand herzustellen.
800
Hochverfügbarkeit
13.5.4 Shareplex Das Produkt Quest Shareplex stellt eine sehr interessante und leistungsstarke Software für Replikationen und Migrationen im Oracle-Umfeld dar. Technisch betrachtet handelt es sich bei Shareplex um eine asynchrone Redo-Log-basierte Replikation, ähnlich wie das im vorigen Abschnitt beschriebene Oracle Streams. Ansonsten gibt es aber wenig Gemeinsamkeiten, insbesondere da Shareplex ein vollkommen eigenständiges Produkt darstellt, das – abgesehen vom Lesen der Redo-Log-Dateien und dem Applizieren von SQL-Kommandos auf der Zielseite – unabhängig von der Datenbank arbeitet. Architektur Auf jedem Rechner, der als Quell- oder Zielrechner an der Replikation beteiligt ist, wird die Shareplex-Software installiert. Unterschiedliche Prozesse sind für das Auslesen der zu replizierenden Änderungen auf dem Quellsystem, den Transport auf das Zielsystem sowie das Applizieren von SQL-Kommandos dort zuständig. Diese Prozesse tauschen Daten entweder direkt über Shared Memory bzw. über TCP und UDP aus. Stauen sich größere Datenmengen auf, werden diese in Queues ausgelagert, die als Dateien ausgeführt sind (im Gegensatz zu Oracle Streams, wo die Queues als Datenbanktabellen implementiert sind, was einen deutlich größeren Overhead in Form von Transaktionsverwaltung, Rollback- und Redo-Log-Erzeugung nach sich zieht). Auch der Datenaustausch über TCP und UDP ist effizienter als über TNS. Folgende Prozesse sind (in zeitlicher Reihenfolge) an der Replikation eines Datensatzes beteiligt Capture: Liest aus den Redo-Log-Dateien (online oder archivierte) Informationen für die zu replizierenden Objekte und schreibt die Daten in die CaptureQueue. Die Daten anderer Objekte werden an dieser Stelle bereits aussortiert. Reader: Liest die Daten aus der Capture-Queue, ermittelt aus der Datenbank über die Row-ID den Primary Key (oder einen Alternativschlüssel) des Datensatzes, fügt Routing-Informationen für eine oder mehrere Zieldatenbanken hinzu und schreibt diese Daten in die Export-Queue. Export: Liest die Daten aus der Export-Queue und schickt die Daten über das Netzwerk auf das Zielsystem. Standardmäßig wird hier der Port 2100 verwendet. Import: Nimmt die Daten eines Exportprozesses entgegen und baut damit die Post-Queue auf. Post: Liest aus der Post-Queue, erstellt die SQL-Befehle und führt sie gegen das Zielsystem aus. Für eine schnellere Verarbeitung ist ein Multi-Threading des Post-Prozesses möglich. Wie in Abbildung 13.21 ersichtlich, laufen nicht alle Prozesse auf jeder Maschine, sondern Capture, Reader und Export auf der Quellmaschine, Import und Post auf der Zielmaschine. Befinden sich beide Datenbanken auf derselben Maschine, so entfallen Export- und Importprozess sowie die Export-Queue.
Replikation
801
Abbildung 13.21: Shareplex generelle Funktionalität
Capture- und Reader-Prozess verfügen über die Fähigkeit, auch Datensätze noch offener Transaktionen zu verarbeiten. Noch bevor eine Transaktion abgeschlossen ist, werden also bereits die ersten Änderungen auf der Zieldatenbank eingebracht. Dies verschafft Shareplex einen Zeitvorteil insbesondere bei langen Transaktionen. Lediglich in dem (seltenen) Fall, dass eine Anwendung die meisten Transaktionen zurückrollt, kann dieses Verhalten nachteilig sein. In diesem Fall liegt aber ohnehin ein Designfehler der Anwendung vor, da die Oracle-Datenbank als Ganzes auf Commits optimiert ist. Einsatzmöglichkeiten Mit der beschriebenen Architektur lassen sich zahlreiche Replikationsszenarien verwirklichen: Einfaches oder zentralisiertes Reporting: Eine oder mehrere Quell-DBs können in eine zentrale Ziel-DB replizieren. Dabei nimmt der Importprozess Daten von einem oder mehreren Exportprozessen auf unterschiedlichen Servern entgegen. Hochverfügbarkeit: Zwei aktive Datenbanken replizieren gegenseitig ineinander. Dabei können ggf. Strategien zur Konfliktlösung etabliert werden. Für jede zu replizierende Tabelle und jede Operation (Insert, Update, Delete) kann eine PL/SQL-Prozedur zur Konfliktlösung eingesetzt werden. Verschiedene Konfliktlösungsstrategien sind mitgeliefert. Im Gegensatz beispielsweise zu Oracle RAC oder Standby-Datenbanken sind hier echte Rolling Upgrades möglich, d.h., die beiden Datenbanken können einzeln gepatcht oder auf einen neuen Versionsstand gebracht werden. Verteilung: Die Daten einer Quell-DB werden aus Gründen der Lastverteilung und/oder besseren Zugreifbarkeit in mehrere Ziel-DBs repliziert. Dabei schickt der Exportprozess dieselben Daten an mehrere Importprozesse.
802
Hochverfügbarkeit
Backup gegen Benutzerfehler oder Datenkorruptionen: Der Post-Prozess kann auf ein zeitverzögertes Applizieren der SQL-Kommandos aus der Post-Queue konfiguriert werden. Damit kann ein Nachlaufen der Ziel-DB um einen Zeitraum bis zu fünf Tagen minutengenau eingestellt werden. Werden versehentlich Datensätze gelöscht oder verändert, kann man die Replikation bis kurz vor den kritischen Zeitpunkt vorspulen und hat damit auf der Ziel-DB den Zustand vor dem Benutzerfehler zur Verfügung. Migrationen (siehe unten) Was wird repliziert? Über eine so genannte Konfigurationsdatei kann ausgewählt werden, welche Tabellen repliziert werden sollen. Dazu wird eine Positivliste aller zu replizierenden Tabellen erstellt (manuell oder per Skript), Negativlisten, z.B. »alle Tabellen im Schema XYZ außer ...«, sind nicht möglich. Auch Pauschalangaben der Form »alle Tabellen im Schema ABC« sind nicht möglich. Standardmäßig werden alle Spalten repliziert, auch solche, die nachträglich neu erstellt werden. Hier kann aber mit Hilfe einer Positivliste auch auf bestimmte Spalten eingegrenzt werden. Nachfolgend eine Übersicht, was mit Shareplex Versionsstand 5.1 repliziert werden kann: Tabellen und Materialized Views. Das Zielobjekt muss aber in jedem Fall eine Tabelle sein. Insert/Update/Delete/Commit/Rollback Direct-Path-Loads, z.B. mit SQL*Loader, wenn die Tabelle die LOGGING-Eigenschaft gesetzt hat, also Redo-Logs geschrieben werden Auch Truncate-Operationen werden standardmäßig repliziert, dies kann aber auch deaktiviert werden, z.B. um versehentliche Truncates durch Anwenderoder Anwendungsfehler nicht auf die Ziel-DB durchzuschleusen. Dies wird über den Parameter SP_OCT_REPLICATE_DDL eingestellt. Hinzufügen, Löschen oder Verändern von Spalten, Änderung von Storage-Klauseln. Auch dies kann mit dem Parameter SP_OCT_REPLICATE_DDL ggf. deaktiviert werden. Sequenzen Wenn Supplemental Logging aktiviert ist: Diverse DDL-Kommandos für Tabellen, Indizes, Views, Synonyme, PL/SQL-Objekte etc. Alle Oracle9i-Datentypen außer INTERVAL und BFILE Nicht repliziert werden: Indexorganisierte und geclusterte Tabellen sowie Objekttabellen Logische Objekte, die keinen eigenen Dateninhalt haben wie z.B. Views, Indizes, Synonyme. Das ist insbesondere bei Indizes auch gewollt, da Quell- und Ziel-DB auf dieser Weise unterschiedliche Indizes haben können.
Replikation
803
Aufsetzen der Replikation Das Aufsetzen einer Shareplex-Replikationsumgebung umfasst folgende Schritte: Installation und Patching der Software. Dies geschieht auf Unix unter dem Benutzer root. Dabei werden auch drei OS-Gruppen erzeugt: spadmin, spopr und spview. Durch Mitgliedschaft in einer dieser Gruppen kann einem OS-Benutzer die Autorisierung für bestimmte Shareplex-Kommandos gegeben werden. Der OS-Benutzer oracle wird standardmäßig in die spadmin-Gruppe aufgenommen und hat damit alle Rechte. Anlegen eines Replikationsbenutzers in der Datenbank, üblicherweise ist dies der Datenbankbenutzer SPLEX. Eine einmalige Anmeldung als DB-Benutzer SYSTEM ist hier notwendig, um dem Benutzer SPLEX die DBA-Rolle zuzuweisen. Anlegen einer Konfigurationsdatei, die beschreibt, welche Objekte wohin repliziert werden sollen Initiale Synchronisation von Quell- und Zieldatenbank Aktivieren der Konfigurationsdatei und damit der Replikation Für die initiale Synchronisation gibt es eine Reihe von Möglichkeiten. In Abhängigkeit vom Gesamtumfang der zu replizierenden Objekte und der Möglichkeit, eine Auszeit für die Quell-DB zu bekommen, kann unter diesen Varianten ausgewählt werden: Synchronisationsmethode
Für große DBs geeignet (> einige 10 G)
Erfordert Auszeit der Quell-DB?
Anfertigung einer Clone-DB via Hot Backup
Ja
Nein
Nachträgliche Synchronisation über das ShareplexKommando compare repair
Nein
Nein
Anfertigung einer Clone-DB via Cold Backup
Ja
Ja
Cloning einzelner Tablespaces via Transportable Tablespaces (mit Oracle 10g plattformübergreifend möglich)
Ja
Tablespaces müssen auf read only gesetzt werden
Data Pump oder konventioneller Export/Import
Nein
Create Table ... As Select via DB-Link
Abhängig von TNS-Performance
Ja (oder anschließendes Compare Repair)
Das Aktivieren einer Shareplex-Konfiguration sowie alle weiteren administrativen Aktionen werden über die Shareplex-Kommandozeilenkonsole (sp_ctrl) ausgeführt. Vor der Aktivierung müssen auf der Ziel-DB Trigger deaktiviert werden, die Aktionen auf den zu replizierenden Tabellen ausführen, da die Trigger-Aktionen bereits von Shareplex repliziert werden und ansonsten doppelt auf der Ziel-DB ankämen. Dasselbe gilt für Fremdschlüssel mit ON DELETE CASCADE-Option sowie für Datenbank-Jobs. Im Falle einer Multi-Master-Replikation können Trigger stattdessen
804
Hochverfügbarkeit
auch mit einer WHEN-Klausel versehen werden, die für den Replikationsbenutzer SPLEX die Auslösung des Triggers unterbindet. Migrationen mit Shareplex Da mit Shareplex Replikationen in einem sehr heterogenen Umfeld möglich sind, bietet es sich auch für Migrationszwecke an. Einige herausragende Vorteile einer solchen Migration sollen hier kurz umrissen werden: Es sind plattformübergreifende Migrationen von Datenbanken auch im Terabyte-Bereich möglich. Auch Zeichensatzmigrationen, die mit Oracle-Bordmitteln nicht möglich sind, können durchgeführt werden, also beispielsweise von WE8ISO8859P1 nach UTF8. Mit der Migration kann gleich eine Reorganisation verbunden werden, wenn die Objekte auf der Zieldatenbank neu aufgebaut oder in andere Tablespaces verschoben werden. Auf diesem Wege können auch gleich neue Oracle-Funktionen (Locally Managed Tablespaces, Automatische Segmentplatzverwaltung etc.) genutzt werden. Da bei der Replikation auch Spalten, Tabellen oder Schemata umbenannt oder weggelassen werden können, kann die Migration auch gleich mit dem Einspielen eines neuen Software-Release bzw. mit Anpassungen des Datenmodells verbunden werden. Wird vor dem Anmelden der Applikationen an die neue Datenbank die Replikation in die Gegenrichtung gestartet, hat man jederzeit eine Fallback-Möglichkeit auf die unveränderte, alte Datenbank. Das eigentliche Umschalten auf die neue Datenbank benötigt nur wenige Minuten Auszeit, um Trigger und Trigger-ähnliche Objekte auf der Ziel-DB zu reaktivieren, ggf. für Fallback-Zwecke die Replikation in die Gegenrichtung zu starten und die Anwendungen mit den Connect-Daten wieder hochzufahren. Weitere Tipps Shareplex ist Cluster-fähig und RAC-fähig. Im Rahmen der Cluster-Fähigkeit ist es insbesondere möglich, mit Floating-IP-Adressen und Floating-ORACLE_SIDs zu arbeiten. Letzteres ist notwendig für den Fall, dass die beiden Oracle-Instanzen des Clusters unterschiedlich heißen. Im Rahmen der RAC-Fähigkeit ist beispielsweise die Fähigkeit gegeben, mehrere Redo-Log-Threads zu verarbeiten. Achtung: Hierfür existiert ein eigenständiges Software-Release namens Shareplex for RAC/OPS. Auch Redo-Logs auf Raw Devices können gelesen werden, nicht jedoch – Stand Shareplex V5.1 – Redo-Logs auf Oracle Cluster Filesystem oder in ASM-Instanzen. Ob Shareplex mit den Änderungen auf der Quell-DB mithalten kann, hängt letztlich vom Redo-Log-Aufkommen und damit von der Änderungsrate ab. Unsere Erfahrungen legen nahe, dass zurzeit ein Durchsatz von etwa 50–80 GB Redo-Logs pro Tag realisierbar ist.
Replikation
805
Wenn der Capture-Prozess bei Lastspitzen die Redo-Logs nicht so schnell verarbeiten kann, wie sie geschrieben werden, greift er bei Bedarf automatisch auf die entsprechenden archivierten Redo-Logs zurück. Kritisch kann es erst werden, wenn ein Aufräumjob regelmäßig archivierte Redo-Logs auf Band verschiebt oder komprimiert, da diese dann vom Capture-Prozess nicht mehr gefunden oder gelesen werden können. In diesem Fall wird eine Fehlermeldung protokolliert: log wrap detected, und das unkomprimierte Archive-Log muss wieder in das Originalverzeichnis oder ein benutzerdefiniertes Alternativverzeichnis (Parameter SP_OCT_ARCH_LOC) kopiert werden. Shareplex kann SNMP-Traps an einen entsprechenden SNMP-Server senden für den Fall, dass ein einzelner Shareplex-Prozess oder die gesamte Software startet oder anhält, dass ein Synchronisationsproblem entdeckt wird oder dass sonstige Fehler aufgetreten sind (Parameter SP_SLG_SNMP_*). Export- und Importprozess kommunizieren standardmäßig über den Port 2100. Seit Oracle9i belegt die Datenbank diesen Port per Default im Rahmen der XML-DB (siehe Kapitel 7.6). Eine der beiden Default-Einstellungen sollte daher angepasst werden; im Falle von Shareplex sind dafür die Parameter SP_COP_UPORT und SP_COP_TPORT zuständig. Es kann aber auch ein SSH-Tunnel benutzt werden (Parameter SP_XPT_USE_LOCALHOST und SP_XPT_PORT_OVERRIDE). Die Shareplex-Prozesse werden vom OS-Benutzer oracle gestartet, laufen aber via SetUID-Bit als Benutzer root. Bei einem Problem ist es daher nicht einfach möglich, sie mittels kill –9 zwangsweise zu beenden. Stattdessen sollte das sp_ctrl-Kommando shutdown force benutzt werden. Ab Oracle9i sollte für die Quell-DB das so genannte Supplemental Logging aktiviert werden (siehe Abschnitt 13.4.2). Ansonsten muss Shareplex während der Aktivierung die Tabellen auf verkettete Zeilen hin analysieren und aus den Ergebnissen eine Mapping-Tabelle aufbauen. Während der Replikation wird diese für verkettete Zeilen mit gelesen und ggf. gepflegt. Dieser Mehraufwand entfällt durch Supplemental Logging.
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. Auch Oracle reiht sich in die Liste der Anbieter mit den Zusatzpaketen des Enterprise Managers ein. Auch hier können Sie nicht davon ausgehen, ein »Rundum-sorglos-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.
14.1
Was wird beobachtet?
Für jeden Datenbankadministrator ist es zunächst einmal wichtig, frühzeitig über mögliche Ressourcen-Engpä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.
14.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 Undo-Segmente Archive Destination Flash-Recovery-Area Filesystem
808
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.
14.1.2 Grenzen Als Nächstes sind die harten Limitierungen einer Datenbank zu beobachten, als da wären: Anzahl Prozesse Anzahl Datenbankdateien Anzahl Redo-Log-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.
14.1.3 Tuningparameter Natürlich gehören auch die für die Performance relevanten Parameter in den Bereich des Monitorings, 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
14.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.
Wie wird beobachtet?
809
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 64-KBit-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-Skripte 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. Im Folgenden wird deshalb immer wieder auch auf den Einsatz von SQLBefehlen zurückgegriffen.
14.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\QJA10G\bdump Listing 14.1: Background Dump Destination
In diesem Verzeichnis befindet sich die Datei alertQJA10G.log, d.h. die Alert-Datei der entsprechenden Instanz. Diese Datei protokolliert alle Fehler der Hintergrundprozesse und zusätzlich Informationen zu den Redo-Log-Switches sowie dem Hoch- und Herunterfahren des Oracle-Systems und liefert die Information, dass andere Prozesse einen Fehler gemeldet haben. Mit der Version 10g wird, wie bereits im Kapitel 10.1.4 beschrieben, zusätzlich der Füllgrad der Flash-Recovery-Area gemeldet, falls dieser einen bestimmten Wert überschreitet. Das führt unter Umständen dazu, dass die Alert-Datei entsprechend groß werden kann, daher sollten Sie zusätzlich immer die Größe dieser Datei überwachen und von Zeit zu Zeit eine Kopie erstellen. Spätestens wenn Sie das erste Mal in der Datei einen Fehlereintrag suchen und feststellen, dass die Größe mittlerweile 100 MB überschritten hat, werden Sie verstehen, warum. 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 Kapitel 12 gehen wir näher auf die möglichen Fehler in der Alert-Datei ein.
810
Monitoring/Reorganisation
Enterprise Manager-Alarme Der Enterprise Manager Database Control bzw. Grid Control gibt, wie bereits in Kapitel 6 beschrieben, für jede Datenbank eine Liste der Alerts aus. Hier handelt es sich jedoch nicht um die Ausgabe der Alert-Datei, sondern um vordefinierte Metriken. Die Übersicht über die Alert-Datei erhalten Sie, wie im folgenden Bild ersichtlich, unter der Gruppe DIAGNOSEZUSAMMENFASSUNG.
Abbildung 14.1: Alert-Datei
Nähere Details dazu erhalten Sie leider nur dann, wenn Sie das Diagnostic Package lizenziert haben. Optional können Sie sich mit dem Menüpunkt »Inhalt von Alert Log« die komplette Alert-Datei anzeigen lassen. Achtung: Dabei wird die gesamte Information auf Ihren Rechner übertragen, so dass es durchaus einige Minuten dauern kann, bis Sie tatsächlich eine Darstellung erhalten.
Abbildung 14.2: Inhalt von Alert Log
Für die Alarmierung über den Enterprise Manager sollten Sie sich die Metriken ansehen und Ihren Bedürfnissen entsprechend anpassen. Im obigen Bild wählen Sie dafür den Menüpunkt »Alle Metriken«, über den Sie dann in das folgende Untermenü gelangen. Hier kann man die einzelnen Gruppen von Alarmen verwalten bzw. die aufgetretenen Alarme näher untersuchen. Die Punkte »Alert Log«, »Inhalt von Alert Log« und »Alert Log-Fehlerstatus« beziehen sich auf die Informationen aus der AlertDatei. Eine gute Übersicht bietet hierbei »Allgemeiner Alert Log-Fehler«, da hier alle aufgetretenen Fehler angezeigt werden können.
Wie wird beobachtet?
811
Abbildung 14.3: Alle Metriken
Über den Menüpunkt »Metriken verwalten« kann man sich zunächst die einzelnen Kriterien für Warnungen und Alarme ansehen. Hier gibt es dann im Untermenü »Schwellenwerte bearbeiten« die Möglichkeit, alle Parameter entsprechend anzupassen.
14.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 Skript selbst schreiben, dann müssen Sie Folgendes beachten: Benutzen Sie daher 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 Betriebssystemmittel (z.B. df –k) den Platz in den einzelnen Dateisystemen ü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
812
Monitoring/Reorganisation
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 14.2: Überwachung von Tablespaces mit mehr als 75 % Füllgrad
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. Generell muss für die Überwachung des Platzes von Dateien jedoch gesagt werden, dass die bei Oracle so beliebte automatische Erweiterung bis »Unendlich« ein großes Problem darstellt. In diesem Fall gibt es scheinbar keine Grenze, d.h., alle Dateien können beliebig groß werden, Alarme treten nicht auf. Dadurch wird aber nur die Überwachung auf das Betriebssystem verlagert, auf das der Datenbankadministrator unter Umständen keinen Einfluss hat. Daher sollten Sie darauf achten, immer eine obere Grenze bei der automatischen Erweiterung von Datendateien mitzugeben und diese für alle nicht kritischen Dateien auf einen Wert einzustellen, der vergleichsweise klein ist. Für die Datei des System-Tablespaces sind z.B. 500 MB in den meisten Fällen (außer bei umfangreicher Benutzung von Stored Procedures) ausreichend.
14.2.3 Extents Generell gehen wir davon aus, dass Sie spätestens mit der Version 10g Abschied von den Dictionary Managed Tablespaces genommen haben. Dann spielt die Überwachung von Extents für Sie keine Rolle mehr, und Sie können die folgenden Informationen vernachlässigen.
Wie wird beobachtet?
813
Dictionary Managed Tablespaces Wenn Sie jedoch noch Dictionary Managed Tablespaces verwenden, 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, obwohl in dem Tablespace selbst noch ausreichend Platz vorhanden ist. Bei der Überwachung eines solchen Ereignisses sollte man darauf achten, nicht nur zu prüfen, ob sich ein nächstes Extent in einem Tablespace allokieren lässt (der Oracle Enterprise Manager überwacht dies generell). Speziell wenn die Tabelle mehrere Indizes hat, kann der Fall eintreten, dass einige Sätze in eine Tabelle eingefügt werden, was dazu führt, 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 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 14.3: Die nächsten zwei Extents sind nicht möglich.
814
Monitoring/Reorganisation
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.
14.2.4 Filesystem Wie bereits erwähnt führt die automatische Erweiterung von Datendateien bis »Unendlich« zur Verlagerung der Überwachung auf das Filesystem. Das bedeutet, dass hier die Betriebssystem- und Datenbankadministratoren Hand in Hand arbeiten müssen, um zu vermeiden, dass ein Ressourcenengpass zum Stillstand der Datenbank führt. In der Vergangenheit kam speziell der Überwachung des Verzeichnisses für die archivierten Redo-Log-Dateien ein entscheidendes Augenmerk zu. Ein Engpass in diesem Bereich führte unweigerlich zum Stillstand der Datenbank. Mit der Einführung der Flash-Recovery-Area wird dieses Problem auf die Ebene der Datenbank verlagert, ist aber natürlich nicht einfach erledigt. Ganz im Gegenteil, eine fehlerhafte Einstellung des Serverparameters db_recovery_file_dest_size kann dazu führen, dass die Datenbank stehen bleibt, obwohl noch ausreichend Ressourcen verfügbar sind. Wenn das Verzeichnis für die archivierten Redo-Log-Dateien voll ist bzw. die Grenze für die Flash-Recovery-Area erreicht ist, können auf der gesamten Datenbank keine Transaktionen mehr ausgeführt werden. Die Datenbank kann in diesem Fall weder ordentlich heruntergefahren werden, noch durch irgendeinen Befehl zum Weiterarbeiten ermuntert werden. Abhilfe schafft in diesen Fällen nur die Vergrößerung des Bereiches oder das Löschen der archivierten Redo-Log-Dateien, wobei allerdings beachtet werden sollte, dass bei der Verwendung der Flash-Recovery-Area ein »Crosscheck« und ein logisches Löschen der Dateien über den Recovery-Manager erfolgen müssen (siehe Kapitel 10.3.5). 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.
Wie wird beobachtet?
815
14.2.5 Unvorhergesehene Engpässe Sicherlich wäre es optimal, wenn man, sobald ein Schwellenwert überschritten wird, einen entsprechenden Alarm bekommen würde. Praktisch ist dies jedoch nicht möglich, da die Sammlung der Informationen mehr oder weniger Zeit in Anspruch nimmt. Gerade für die Überwachung von Tablespaces und Datafiles bedeutet dies in der Regel, dass die Daten nur selten (z.B. zweimal täglich) aufgenommen werden. Der Datenbankadministrator ist also darauf angewiesen, dass es keine unvorhergesehenen Aktionen gibt, die in der Zwischenzeit so viele Daten erzeugen, dass die Ressourcen nicht mehr ausreichen. Optimalerweise wird er informiert, wenn außerplanmäßige Aktionen (z.B. das Einspielen einer neuen Software etc.) anstehen. Hilfreich ist in jedem Fall, wenn er beim Auftreten eines Fehlers erklären kann, dass es sich um eine ungewöhnliche Aktion gehandelt hat. Am einfachsten ist dies, indem man sich eine Matrix über die Redo-Log-Switches anzeigen lässt, aus der die Log-Switches pro Stunde bzw. pro Tag angezeigt werden. Leider gibt es diese Darstellung im Enterprise Manager nicht, so dass wir hier die Darstellung des Quest-Werkzeuges TOAD for Oracle zeigen.
Abbildung 14.4: Log Switch Frequency Map des TOAD
Aus diesem Bild wird ersichtlich, dass am 19.06.2005 in der Zeit von 12 bis 14 Uhr eine extreme Häufung an Log-Switches erfolgte, die für den Administrator zu einer nicht zu kalkulierenden Ressourcenbenutzung geführt hat.
816
Monitoring/Reorganisation
14.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 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 OSUSER PROGRAM --- ------- --------- ---------- ------------------- -------------8 5 DEMO DEMO HLLAP33\jahrends sqlplus.exe 9 7 DEMO DEMO HLLAP33\jahrends TOAD.exe Listing 14.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_monitor.session_trace_enable(8,5); Listing 14.5: Beispiel Tracing
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 dieser Größe ausgeschaltet wird. Alternativ kann das Tracing mit dem Befehl: SQL> execute dbms_monitor.session_trace_disable(8,5);
wieder ausgeschaltet werden.
Wie wird beobachtet?
817
Für Notfälle gibt es auch noch den Serverparameter sql_trace = true. Da dieser Parameter die gesamte Instanz in den Trace-Modus setzt, sollte er nur für kurze Zeit aktiviert werden. Nähere Informationen zum Tracing erhalten Sie in den Kapiteln 11.2.3 (Tuning) und 12 (Troubleshooting). Enterprise Manager Zwar wird auf der Eingangsseite des Enterprise Managers eine Übersicht über die Auslastung des Systems (Host-CPU) und der aktuellen Sessions (aktive Sessions) geliefert, eine nähere Analyse kann jedoch nur dann erfolgen, wenn Sie das Diagnostic Package lizenziert haben. In diesem Fall kann man dann eine weitere Analyse der Informationen vornehmen, wie z.B. über die seit den Anfängen des Enterprise Managers bekannten TopSessions oder Top-SQL.
Abbildung 14.5: Top SQL
818
Monitoring/Reorganisation
Diese Daten können bis hin zum Ausführungsplan dargestellt werden, so dass die Eingabe gut für ein weiteres Tuning geeignet ist. Diese Information ist sicherlich sehr hilfreich, wenn es um die Darstellung eines problematischen Befehls geht. Die Verfolgung von kritischen Zuständen von Anwendungen (z.B. blockierende Prozesse) sind allerdings nur schwer nachvollziehbar. Im Standardmenü (»Standardverzeichnis«) erhält man lediglich eine Meldung unter Alarmen.
Abbildung 14.6: Wait Event
Die weitere Verfolgung liefert allerdings keine Erkenntnisse.
Abbildung 14.7: Wartezustände
Im Bereich Performance findet man eine Grafik mit den Wartezuständen der Sessions. Wenn man hier den Menüpunkt »Application« anwählt, erhält man nähere Informationen zu der wartenden Session. Über ein weiteres Untermenü (»Session Detail«) hat man dann die Möglichkeit, sich die tatsächlichen Sperren und damit die Beziehung der Sessions zueinander anzeigen zu lassen.
Reorganisieren
819
Abbildung 14.8: Blockierende Prozesse
Wie an diesem Beispiel ersichtlich, ist es im Enterprise Manager oftmals nur über mehrere Ebenen möglich, die notwendigen Detailinformationen darzustellen.
14.3
Reorganisieren
Warum sollte eine Tabelle bzw. ganz generell ein Objekt reorganisiert werden? Oracle behauptete schon in der Version 7, dass eine Reorganisation prinzipiell nicht nötig wäre. Dennoch haben sich im Laufe der Jahre unterschiedliche Verfahren für die Reorganisation von Tabellen und Indizes entwickelt. Neben Werkzeugen von Drittanbietern wie BMC, CA oder Quest unterstützt auch der Oracle Enterprise Manager seit langer Zeit die Reorganisation.
14.3.1 Warum reorganisieren? Aber noch einmal zurück zur Frage: Warum? Hier ist eine Liste von historischen und aktuellen Argumenten: »Die Tabelle/der Index hat zu viele Extents, und daher ist der Zugriff bei einem Full-Table-Scan unperformant«: Dieser Grund sollte spätestens nach der Einführung von Locally Managed Tablespaces (LMTS) abgehakt sein. »Die Extents der Tabelle/des Index liegen nicht hintereinander, dadurch sind Zugriffe langsamer«: Da die Verwaltung der Extents bei LMTS über eine sehr schnelle Bitstruktur erfolgt, gilt auch dieses Argument nicht mehr. Nur wenn die Extentgröße tatsächlich extrem klein (kleiner 1 MB) ist und die Tabelle aus mehreren hundert Extents besteht, ist tatsächlich ein Performance-Verlust zu bemerken. »Der Tablespace ist fragmentiert, d.h., es gibt große Lücken, die nicht wieder verwendet werden können«: Bei der Verwendung von LMTS mit Uniform Size
820
Monitoring/Reorganisation
können die Lücken von neuen Extents jederzeit wieder belegt werden. Selbst bei Automatic Storage Management ist durch die Verwendung von Vielfachen (64 KB, 1 MB, 8 MB, 64 MB) eine fast vollständige Wiederauffüllung von Lücken möglich. »Der Indexbaum hat eine zu große Tiefe«: Dies ist sicherlich einer der wichtigsten Gründe für die Reorganisation eines Index. »Die Tabelle hat Migrated Rows« (oft fälschlicherweise als Chained Rows bezeichnet): Da die Verkettung bzw. Migration von Sätzen aus einem Block in einen anderen zu erhöhter I/O-Last führt (statt eines Blockes beim Zugriff über den Index müssen jetzt u.U. zwei gelesen werden), ist auch dies ein Grund für die Reorganisation. Wer vorausplant, kann das Vorkommen von Migrated Rows jedoch durch die richtige Einstellung von PCTFREE vermeiden. »Der Füllgrad in den Blöcken ist zu gering«: Dieser Grund kann speziell nach der Archivierung von Daten und dem darauf folgenden Löschen der Sätze aus der Tabelle auftreten. Grund hierfür ist der Parameter PCTUSED, der verhindert, dass die Blöcke mit neuen Sätzen aufgefüllt werden. Vermieden werden kann dieser Effekt durch die optimale Einstellung von PCTUSED oder aber durch die Verwendung von Automatic Segment Space Management (ASSM). »Aus organisatorischen oder I/O-Gründen sollen die Objekte anders verteilt werden«: Zu diesem Argument zählt auch die Umstellung auf ASSM, da diese Option nur bei der Neuanlage eines Tablespace möglich ist. »Wegen der besseren Performance soll die Tabelle sortiert abgespeichert werden«: Auch wenn dies ein sehr seltener Fall ist und eventuell besser durch eine Index-Organized-Table abgebildet werden kann, ist dieses Argument stichhaltig und kann die Reorganisation notwendig machen. Eventuell fallen Ihnen noch weitere Argumente für eine Reorganisation ein, stets sollten Sie jedoch beachten, dass eine Reorganisation zu einem Fehler führen kann, so dass im ungünstigsten Fall die gesamte Datenbank zurückgesichert werden muss. Nicht umsonst wird in der Oracle-Dokumentation immer wieder darauf verwiesen – und wir schließen uns dieser Anmerkung in jedem Fall an –, dass man vor der Reorganisation ein Backup der Datenbank durchführen sollte. Ein weiterer gewichtiger Grund ist der Neuaufbau einer Datenbank, z.B. nach einem Release-Wechsel oder für den Wechsel der Hardware oder des Betriebssystems. Auch hier können ähnliche Verfahren wie bei der Reorganisation zum Tragen kommen.
14.3.2 Wie wird reorganisiert? 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.
Reorganisieren
821
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. Eine weitere Vereinfachung gibt es in Oracle 10g mit dem Befehl ALTER TABLE … SHRINK SPACE. Dieser lässt sich allerdings nur dann anwenden, wenn der Tablespace mit Automatic Segment Space Management angelegt wurde. Generell gilt, dass man vermeiden sollte, Daten aus der Datenbank herauszuladen und sie dann wieder einzuladen (Export/Import). Zunächst einmal kann es zu Fehlern beim Exportieren kommen, 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. 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, welche die jeweilige Syntax aus der bestehenden Datenbank heraus generieren können. Mit dem Enterprise Manager Database Control oder Grid Control kann man für die Objekte ein entsprechendes DDL-Skript erstellen lassen. Leider werden in diesem Fall jedoch die Berechtigungen und Views nicht mit übernommen, da diese zum Benutzerkontext gehören. Wenn Sie sich also über diese Methode das DDL-Skript generieren lassen, sollten Sie sich zusätzlich die Grants über den Benutzerkontext holen. Das im früheren Change Management Pack vorhandene Werkzeug DB-Capture scheint es im neuen Release nicht mehr zu geben, so dass es keine Möglichkeit gibt, alle DDL-Befehle eines Benutzers zu generieren. Warum ist dies bei der Reorganisation eines Objektes überhaupt von Interesse? Wenn mit dem Export/Import gearbeitet werden soll, ist es hilfreich, nach dem Löschen der Objekte diese zunächst in einem separaten Schritt anzulegen (z.B. weil der Tablespace geändert werden soll oder die Parameter PCTFREE bzw. PCTUSED) und erst dann den Import zu starten. Als Alternative zum Enterprise Manager liefert das bereits mehrfach erwähnte Produkt TOAD for Oracle von Quest Software Inc. alle notwendigen Skripte.
822
Monitoring/Reorganisation
Abbildung 14.9: DDL für Benutzer generieren
In diesem Beispiel wurde außerdem die automatische Generierung der ForeignKey-Beziehungen aktiviert, die ansonsten bei Reorganisationen gerne vergessen wird. Natürlich gibt es noch eine ganze Reihe anderer Verfahren, mit deren Hilfe man sich die entsprechenden DDL-Skripte erstellen kann. Wichtig ist nur, dass das Skript vor dem ersten Einsatz ausführlich getestet wird, um sicherzustellen, dass alle notwendigen Informationen generiert werden.
14.3.3 Womit wird reorganisiert? 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.
Reorganisieren
823
Abbildung 14.10: DDL-Generierung mit TOAD
Sinnvoll ist der Einsatz des Exports/Imports immer dann, wenn LONG- oder LONG RAWFelder 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 Named Pipes von einer in eine andere Datenbank zu verschieben. Die Benutzung von Pipes ist im Kapitel 10.6.2 bereits beschrieben worden. Vorsicht ist geboten, wenn über ein Skript 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.
824
Monitoring/Reorganisation
Bei der Verwendung des Exports/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 Skript und setzen den Importparameter 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. Da ab Version 9i in der Regel der Serverparameter workarea_size_policy = AUTO gesetzt ist, so dass anstelle des Parameters sort_area_size jetzt pga_aggreate_target genutzt wird, sollte dieser für die Dauer des Exports ausgeschaltet werden. SQL> ALTER SYSTEM SET workarea_size_policy = MANUAL SCOPE=MEMORY;
Damit sollte ein Export/Import in einer akzeptablen Zeit durchführbar sein. Vergessen Sie nicht, die Parameter entsprechend wieder auf die ursprünglichen Werte zu setzen, wenn Sie mit dem Import fertig sind.
14.3.4 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. 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. # # Umbenennen der alten Tabelle und zugehöriger Constraints # Damit kann die Anwendung nicht mehr benutzt werden # ALTER TABLE kunden RENAME TO kunden_alt; ALTER TABLE kunden_alt RENAME CONSTRAINT pk_kunden TO pk_kunden_alt; ALTER INDEX pk_kunden RENAME TO pk_kunden_alt;
Reorganisieren # # Erstellen der neuen Tabelle über CTAS # CREATE TABLE KUNDEN_NEU ( kdnr NOT NULL, anrede , vorname , nachname , adresse , ort , plz , telefon ) TABLESPACE demots LOGGING –- hier steht die Tabellendefinition NOCOMPRESS NOCACHE NOPARALLEL -- hier steht die Tabellendefinition MONITORING PCTFREE 20 AS SELECT /*+ PARALLEL 4 */ kdnr, anrede, vorname, nachname, adresse, ort, plz, telefon FROM kunden_alt NOLOGGING; -- diese Option gilt nur während des CTAS # # Erstellen des neuen Index # CREATE UNIQUE INDEX pk_kunden ON kunden_neu (kdnr) NOLOGGING TABLESPACE indxts PARALLEL 4; ALTER TABLE kunden_neu ADD ( CONSTRAINT pk_kunden PRIMARY KEY (kdnr) USING INDEX TABLESPACE indxts); # # Foreign Key Constraints dürfen nicht vergessen werden # ALTER TABLE demo.auftraege RENAME CONSTRAINT fk_auftraege_kunden TO fk_auftraege_kunden_alt; ALTER TABLE demo.auftraege ADD ( CONSTRAINT fk_auftraege_kunden
825
826
Monitoring/Reorganisation
FOREIGN KEY (kdnr) REFERENCES DEMO.KUNDEN (kdnr)); ALTER TABLE demo.AUFTRAEGE DROP CONSTRAINT fk_auftraege_kunden_alt; # # Vergabe der Berechtigungen # GRANT SELECT ON kunden_neu TO carina; GRANT INSERT, UPDATE, DELETE, SELECT ON kunden_neu TO guenter; # # Umbenennen der neuen Tabelle # Damit kann die Anwendung wieder arbeiten # RENAME kunden_neu to kunden;
Hiermit wird die Tabelle kunden in einem neuen Tablespace aufgebaut und der Parameter PCTFREE angepasst. Bei größeren Tabellen empfiehlt es sich, vor der Ausführung den Serverparameter 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 betragen 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.
14.3.5 COPY Table 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. Im Gegensatz zu CTAS kann dieser Befehl auch bei Tabellen eingesetzt werden, die LONG- oder LONG RAW-Spalten enthalten.
14.3.6 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 Rebuilds 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. Ab Oracle9i und natürlich in 10g ist diese Einschränkung jedoch nicht mehr gültig. Es sollte allerdings klar sein, dass der Rebuild nur dann funktioniert, wenn die Funktion auch verfügbar ist. Das folgende Beispiel zeigt für den Index IDX_NAME, wie zunächst die Indextiefe (BLEVEL) festgestellt wird, anschließend ein Rebuild durchgeführt wird und als Letztes die Überprüfung der Indextiefe erfolgt.
Reorganisieren
827
SQL> SELECT index_name, blevel, leaf_blocks, distinct_keys FROM user_indexes WHERE index_name = 'IDX_NAME'; INDEX_NAME BLEVEL LEAF_BLOCKS DISTINCT_KEYS ---------------------------- ------ ----------- ------------IDX_NAME 2 705 49127 SQL> ALTER INDEX idx_name REBUILD TABLESPACE idx_ts ONLINE NOLOGGING COMPUTE STATISTICS; SQL> SELECT index_name, blevel, leaf_blocks, distinct_keys FROM user_indexes WHERE index_name = 'IDX_NAME'; INDEX_NAME BLEVEL LEAF_BLOCKS DISTINCT_KEYS ---------------------------- ------ ----------- ------------IDX_NAME 1 274 49127 Listing 14.6: Online Index Rebuild
Alternativ gibt es mit der Version 10g auch die Möglichkeit, den Platzbedarf eines Index mit dem Befehl SHRINK SPACE zu verringern. Allerdings wird hier keine komplette Reorganisation des Index durchgeführt, sondern es werden nur leere Blöcke entfernt. Diese Option ist also dann interessant, wenn z.B. bei einem Index auf ein Datum immer wieder alte Sätze gelöscht werden. Der gleiche Befehl kommt jedoch auch bei der Reorganisation von Tabellen zum Einsatz und kann dort durchaus effektiv genutzt werden.
14.3.7 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 Skripts ist, dass hierfür die Tabelle gesperrt werden muss, d.h., die Anwendung kann für die Dauer nicht genutzt werden. Zwar gibt es die Option »ONLINE«, diese ist jedoch nur bei indexorganisierten Tabellen (IOTs) anwendbar. Außerdem besteht keine Möglichkeit einer Parallelisierung oder des Ausschaltens von Redo-Log-Informationen. Der Befehl kann nicht auf Tabellen mit LONG-Feldern eingesetzt werden. Wichtig ist, dass zugehörige Indizes anschließend mit dem Befehl REBUILD wieder neu aufgebaut werden müssen. Für die Tabelle kunden sieht dieser Befehl wie folgt aus: SQL> SELECT FROM WHERE AND
table_name, num_rows, blocks, empty_blocks, avg_space, avg_row_len all_tables owner = 'DEMO' table_name = 'KUNDEN';
Listing 14.7: TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE AVG_ROW_LEN
828
Monitoring/Reorganisation
---------- --------- ------- ------------ ---------- -----------KUNDEN 50000 1000 24 4404 69 SQL> ALTER TABLE kunden MOVE TABLESPACE demots; SQL> ALTER INDEX pk_kunden REBUILD TABLESPACE idx_ts NOLOGGING; SQL> ALTER INDEX idx_name REBUILD TABLESPACE idx_ts NOLOGGING; SQL> SELECT table_name, num_rows, blocks, empty_blocks, avg_space, avg_row_len FROM all_tables WHERE owner = 'DEMO' AND table_name = 'KUNDEN'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE AVG_ROW_LEN ---------- --------- ------- ------------ ---------- -----------KUNDEN 50000 512 0 856 69 Listing 14.8: Move Tablespace
Wie in dem Beispiel ersichtlich, wird die Tabelle optimal reorganisiert, so dass hier je Block noch 10 Prozent (AVG_SPACE=856) freier Platz existiert. Dieser Wert entspricht dem Parameter PCTFREE.
14.3.8 Shrink Space Dieser Befehl ermöglicht es, eine Tabelle im laufenden Betrieb zu reorganisieren. Voraussetzung für die Benutzung ist, dass der Tablespace mit Automatic Segment Space Management erstellt wurde und für die Tabelle das Row Movement eingeschaltet worden ist. Sollten Sie beabsichtigen, Tabellen über diesen Befehl zu reorganisieren, dann empfiehlt es sich, schon beim Anlegen der Tabelle diese Option zu setzen, da hierfür eine Tabellensperre erforderlich ist. SQL> ALTER TABLE kunden ENABLE ROW MOVEMENT; Listing 14.9: Row Movement aktivieren
Weitere Einschränkungen sind, dass diese Methode nicht für Tabellen mit LONGoder LOB-Spalten funktioniert und die Tabelle keine funktionsbasierten Indizes haben darf. Weitere Restriktionen bzw. deren Aufhebung entnehmen Sie bitte der Oracle-Dokumentation. Wenn die Tabelle die Voraussetzungen erfüllt, kann sie wie folgt reorganisiert werden: SQL> SELECT FROM WHERE AND
table_name, num_rows, blocks, empty_blocks, avg_space, avg_row_len all_tables owner = 'DEMO' table_name = 'KUNDEN';
Reorganisieren
829
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE AVG_ROW_LEN ---------- --------- ------- ------------ ---------- -----------KUNDEN 50000 1000 24 4409 69 SQL> ALTER TABLE kunden SHRINK SPACE CASCADE; SQL> SELECT table_name, num_rows, blocks, empty_blocks, avg_space, avg_row_len FROM all_tables WHERE owner = 'DEMO' AND table_name = 'KUNDEN'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE AVG_ROW_LEN ---------- --------- ------- ------------ ---------- -----------KUNDEN 50000 444 20 49 69 Listing 14.10: Shrink Space
Die Option CASCADE führt dazu, dass auch alle Indizes mit »zusammengeschoben« werden. Vorsicht! Wie in dem Beispiel ersichtlich, werden die Blöcke komplett gefüllt, d.h., der Parameter PCTFREE wird ignoriert. Das kann dazu führen, dass Sie hier den Teufel mit dem Beelzebub austreiben. Zwar ist die Tabelle jetzt kompakt, allerdings ist die Wahrscheinlichkeit für migrierte Sätze anschließend sehr groß. Die Angabe von Parametern ist bei diesem Befehl nicht möglich.
14.3.9 Online-Table-Reorganisation Bereits mit Version 9i hat Oracle die Möglichkeit geschaffen, Tabellen im laufenden Betrieb zu reorganisieren. Dafür gibt es das Package dbms_redefinition, das die Möglichkeit bietet, eine neue Tabelle als Kopie der Originaltabelle aufzubauen. Diese 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. Mit Version 10g können die zugehörigen Objekte jetzt ebenfalls mit aufgebaut werden. Die Funktionalität basiert auf den Materialized Views. Das folgende Beispiel zeigt die Online-Reorganisation der Tabelle kunden, die während der Reorganisation von einem Tablespace in einen anderen verlagert wird. Die Reorganisation kann in Version 10g optional über die Rowid oder den Primary Key erfolgen. Wenn die RowidOption gewählt wird, wird allerdings eine zusätzliche Spalte (M_ROW$$) an die erstellte Tabelle angefügt, die anschließend über DROP COLUMN wieder gelöscht werden muss. Da es einige weitere Einschränkungen diesbezüglich gibt, empfehlen wir, entweder den Primärschlüssel oder einen anderen eindeutigen Schlüssel zu wählen. Im Beispiel wählen wir den Primärschlüssel der Tabelle kunden mit der Option cons_use_pk.
830
Monitoring/Reorganisation
Zunächst sollte überprüft werden, ob eine Online-Reorganisation überhaupt möglich ist. Dies geschieht über die Prozedur can_redef_table. Die Restriktion, dass Tabellen mit LONG-Feldern nicht reorganisiert werden können, gibt es zwar nicht mehr, allerdings funktioniert die Reorganisation nur dann, wenn die Felder in LOBSpalten umgewandelt werden. BEGIN dbms_redefinition.can_redef_table( uname =>'DEMO', tname =>'KUNDEN', options_flag => dbms_redefinition.cons_use_pk); END; / Listing 14.11: Überprüfung der Online-Reorganisation
Wenn diese Prozedur keinen Fehler ausgibt, steht der Reorganisation nichts mehr im Wege. DECLARE anzahl_fehler PLS_INTEGER; -- Variable für Fehlernummern BEGIN --- Starten der Reorganisation -dbms_redefinition.start_redef_table( uname => 'DEMO', orig_table => 'KUNDEN', int_table => 'KUNDEN_NEU', options_flag => dbms_redefinition.cons_use_pk); --- Erstellen der abhängigen Objekte -dbms_redefinition.copy_table_dependents( uname => 'DEMO', orig_table => 'KUNDEN', int_table => 'KUNDEN_NEU', copy_indexes => dbms_redefinition.cons_orig_params, num_errors => anzahl_fehler); --- Ausgabe der Anzahl von Fehlern bei der Erstellung -dbms_output.put_line('Fehler = '||anzahl_fehler); --- Beenden der Reorganisation (Tausch der Objektnamen) -dbms_redefinition.finish_redef_table( uname => 'DEMO', orig_table => 'KUNDEN', int_table => 'KUNDEN_NEU'); END; / Listing 14.12: Online-Reorganisation mit dbms_redefinition
Reorganisieren
831
Da hier die Tabellennamen im Data Dictionary getauscht werden müssen, wird eine kurzfristige Tabellensperre aufgebaut, die in der Regel aber als unkritisch angesehen werden kann. Ein Vorteil ist, dass Fremdschlüssel, die auf diese Tabelle verweisen, von der Änderung nichts mitbekommen, sie müssen also nicht neu aufgebaut werden. Neben den oben beschriebenen Prozeduren gibt es noch weitere, z.B. um die Reorganisation abzubrechen (abort_redef_table). Da während der Reorganisation alle Änderungen in Materialized View Logs gespeichert werden, kann es vorkommen, dass diese bei großen Tabellen mit vielen Änderungen sehr groß werden. Aus diesem Grund gibt es die Prozedur sync_interim_table, die für einen Zwischenabgleich der Quell- und Zieltabelle sorgt. Ein entscheidender Faktor für die Zuverlässigkeit und Schnelligkeit dieser Reorganisationsmethode stellt die Rekompilierung von Stored Procedures dar, da hierbei unter Umständen viel Zeit verbraucht wird, während der die Prozeduren nicht benutzt werden können und somit die Anwendung nicht zur Verfügung steht.
14.3.10 Oracle Enterprise-Manager-Reorganisationen Natürlich kann diese Prozedur auch über den Oracle Enterprise Manager Database Control oder Grid Control aufgerufen werden. Über den Menüpunkt »Wartung« im Enterprise Manager gelangen Sie zu der Option »Objekte reorganisieren« und können dort angeben, ob Sie einzelne Objekte oder einen ganzen Tablespace reorganisieren möchten. Wir möchten das Buch hier nicht mit weiteren Screenshots belasten und glauben, dass Sie sicher in der Lage sind, die einzelnen Punkte, durch die Sie anschließend geführt werden, selbst einzuordnen. Zwei Schritte sind jedoch noch erwähnenswert, daher hier eine kurze Darstellung: Im Schritt 3 (Optionen) können Sie die Methode (online oder offline) festlegen und zusätzlich einen so genannten Scratch Tablespace wählen. Warum ist das wichtig? Wenn Sie eine Tabelle im gleichen Tablespace reorganisieren, wird die Tabelle logischerweise an einer anderen Stelle angelegt; eventuell muss also der Tablespace erst vergrößert werden, dann wird die Tabelle angelegt, und anschließend ist mitten im Tablespace eine Lücke, weil die alte Tabelle gelöscht worden ist. Über die Option »Scratch Tablespace« wird die Tabelle zunächst in einen anderen Tablespace verlagert, dann wird die ursprüngliche Tabelle gelöscht, und danach wird die Tabelle wieder zurückgelesen. Obwohl es zunächst so erscheint, als ob diese Methode besser wäre, möchten wir davor warnen! Sie führen die Reorganisation zweimal durch – mit allen Konsequenzen, insbesondere dass alle Daten zweimal in den Redo-Log-Dateien gespeichert werden. Wenn Sie also ein derartiges Problem haben, dann reorganisieren Sie besser den gesamten Tablespace, und zwar in der Form, dass Sie einen neuen Tablespace anlegen, alle Objekte in diesen Tablespace reorganisieren und dann den alten Tablespace löschen. Wenn Sie wollen, können Sie danach den neuen Tablespace umbenennen (ab Oracle 10g möglich), so dass der Aufbau wieder wie vorher ist. Dies ist in jedem Fall dem Ansatz mit dem Scratch-Tablespace vorzuziehen.
832
Monitoring/Reorganisation
Abbildung 14.11: Reorganisationsoptionen im Enterprise Manager
Ein angenehmer Effekt bei der Reorganisation über den Enterprise Manager ist, dass dieser die Auswirkungen überprüft und im Schritt 4 (Ausführungsbericht) einen Bericht darüber ausgibt, den man als HTML-Datei speichern kann. Im Schritt 5 werden dann die Daten für die Ausführung des Reorganisationsjobs wie im Bild dargestellt festgelegt.
Reorganisieren
833
Abbildung 14.12: Ausführungsplan
Der Name »Ausführungsplan« ist eventuell etwas irreführend, es geht darum, einen Job aufzusetzen mit den Daten, die hierfür notwendig sind. Leider sieht man an dieser Stelle wieder einmal die fehlende Integration mit den neuen Oracle 10gFunktionen. Obwohl es in der Version 10g einen sehr effektiven und einfach zu konfigurierenden Scheduler gibt (siehe Kapitel 6.2), verwendet der Enterprise Manager immer noch die Ausführung über den Agenten, der an dieser Stelle wegen fehlerhafter Host-ID-Daten fehlschlägt. Da es keine Möglichkeit gibt, sich das generierte Skript in irgendeiner Form anzeigen zu lassen, mussten wir die Reorganisation über den Enterprise Manager an dieser Stelle ohne Erfolg abbrechen. Ob die Überprüfung also funktioniert, können wir derzeit nicht beantworten
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 15.1), Datenbankdesign (Kapitel 15.2) und die Darstellung (Kapitel 15.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 Oracle 10g-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 und 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
836
15.1
Data Warehousing
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 zeitaufwändigste Arbeit, da es darum geht, unterschiedliche Datenquellen mit u.U. ähnlichen Dateninhalten miteinander 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 dieselbe 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. Seit 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.
Extraktion, Transformation, Laden
837
15.1.1 Transportable Tablespaces Wenn Sie beabsichtigen, Tabellen über diesen Mechanismus in ein Data Warehouse zu übernehmen, sollten Sie folgende Restriktionen beachten. 1. 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. Nähere Informationen zu den verwendeten Zeichensätzen finden Sie auch im Kapitel 8 (Globalization Support). 2. Es dürfen keine Beziehungen der Objekte aus den zu transportierenden Tablespaces in andere Tablespaces existieren. Eine Ausnahme bilden Indizes, die durchaus in anderen Tablespaces liegen dürfen. 3. In der Zieldatenbank muss für die Blockgröße des Tablespaces ein entsprechender Cache eingerichtet worden sein. Beispiel für den Transport eines Tablespaces Der Transport eines Tablespaces ist gegenüber den vorhergehenden Versionen stark vereinfacht worden. Sofern ein Datenbank-Link von der Quell- auf die Zieldatenbank vorhanden ist, kann der eigentliche Transport alleine mit Oracle-Tools durchgeführt werden, OS-Mechanismen zum Kopieren der Dateien werden nicht mehr benötigt. Dies ist insbesondere für Umgebungen mit Firewalls sehr interessant. Mit Oracle 10g ist außerdem auch ein plattformübergreifender Transport möglich. Im Folgenden wird beispielhaft der Transport des Tablespaces USERS mit der Datendatei /orabase/data/RH10/datafile/users01.dbf von der Datenbank RH10 auf die Datenbank PS10 gezeigt. RH10 läuft auf SUN Solaris, PS10 auf MS-Windows. Die Datenbankdateien von PS10 liegen im Verzeichnis E:\oracle\oradata\PS10. Zunächst wird auf RH10 geprüft, ob die oben genannten Restriktionen eingehalten sind. SQL> EXECUTE sys.dbms_tts.transport_set_check('USERS', TRUE); SQL> SELECT * FROM sys.transport_set_violations; VIOLATIONS ----------------------------------------------------------------Default Partition (Table) Tablespace TS1 for VERKAEUFE not contained set Default Partition (Table) Tablespace TS2 for VERKAEUFE not contained set Default Partition (Table) Tablespace TS3 for VERKAEUFE not contained set Default Partition (Table) Tablespace TS4 for VERKAEUFE not contained set SQL> ALTER TABLE verkaeufe MODIFY DEFAULT ATTRIBUTES TABLESPACE ts1;
in transportable in transportable in transportable in transportable
838
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. Für die Dauer des Transports muss der betreffende Tablespace auf Read-only gesetzt werden: SQL> ALTER TABLESPACE users READ ONLY;
Transport via Datenbank-Link Am einfachsten ist der Transport, wenn ein Datenbank-Link von PS10 nach RH10 vorliegt. Dann werden zunächst die Datendateien auf den PS10-Server kopiert und dort in die Verzeichnisse für Datendateien gelegt. Dies kann mittels Betriebssystemkommandos (ftp, scp etc.) geschehen. Wenn dies beispielsweise in FirewallUmgebungen ein Problem darstellt, können die Dateien alternativ einfach über den Datenbank-Link geschoben werden. Das Package dbms_file_transfer, das seit Oracle 10g zum Standardumfang gehört, ist dazu in der Lage. Auf Quell- und Zielmaschine müssen Directory-Objekte (hier datadir) vorhanden sein, die Lese- bzw. Schreibrechte auf die Verzeichnisse mit den Datendateien geben. BEGIN dbms_file_transfer.get_file( 'DATADIR' -,'users01.dbf' -,'RH10' -,'DATADIR' -,'users01.dbf' -); END; /
Datendatei auf Quell-DB DB-Link Datendatei auf Ziel-DB
Die Übertragungsrate ist mit der eines FTP-Transfers vergleichbar. In Tests wurden nur wenige Prozent Unterschied festgestellt. Der Fortschritt der Übertragung kann via v$session_longops überwacht werden. Leider ist es zumeist nicht möglich, die Datei vorher zu komprimieren, da die Dateigröße ein Vielfaches von 512 Byte sein muss. Liegen die beteiligten Datenbanken auf unterschiedlichen Plattformen, ist ggf. eine Konvertierung des Binärformats (Little-Endian oder Big-Endian) notwendig. Alle Plattformen, für die eine solche Konvertierung unterstützt wird, finden sich in der View v$transportable_platform. Haben dort beide beteiligten Plattformen dasselbe Binärformat (Spalte endian_format), ist keine Konvertierung notwendig. Ansonsten kann diese vom RMAN ausgeführt werden.
Extraktion, Transformation, Laden SQL> 2 3 4
SELECT FROM WHERE OR
839
platform_name, endian_format v$transportable_platform platform_name LIKE '%Solaris%' platform_name LIKE '%Windows%';
PLATFORM_NAME ----------------------------------Solaris[tm] OE (32-bit) Solaris[tm] OE (64-bit) Microsoft Windows IA (32-bit) Microsoft Windows IA (64-bit) Microsoft Windows 64-bit for AMD
ENDIAN_FORMAT -------------Big Big Little Little Little
In diesem Fall ist offenbar eine Konvertierung notwendig. Die Originaldatei wird dabei nicht verändert, stattdessen wird eine neue, konvertierte Datei angelegt, deren Zielort und Name durch die FORMAT-Klausel bestimmt wird. RMAN> CONVERT DATAFILE 'E:\oracle\oradata\PS10\users01.dbf' 2> TO PLATFORM 'Microsoft Windows IA (32-bit)' 3> FORMAT 'E:\oracle\oradata\PS10\%U';
Zwei wichtige Einschränkungen müssen für solche plattformübergreifenden Transporte beachtet werden: Die Konvertierung ist nur möglich, wenn sowohl Quell- als auch Zieldatenbank die Oracle-Version 10g haben. Eine Konvertierung von Datendateien älterer Versionen mit Hilfe des 10g-Recovery-Managers funktioniert leider nicht. Die Datentypen RAW, BFILE sowie ANYDATA, ANYDATASET und ANYTYPE bleiben bei der Konversion unverändert, da Oracle davon ausgeht, dass deren Inhalt applikationsspezifisch ist. Nachdem alle (ggf. konvertierten) Datendateien an die neue Position kopiert und bei Bedarf umbenannt worden sind, kann der Tablespace mittels Datapump-Import in die neue Datenbank eingehängt werden. Dabei werden über den DatenbankLink die Metadaten der Quell-DB exportiert und in die Ziel-DB eingespielt: $ impdp system@PS10 network_link=rh10 transport_tablespaces=users transport_full_check=n transport_datafiles='E:\oracle\oradata\PS10\users01.dbf'
Anschließend kann auf RH10 der Tablespace wieder auf Read-Write gesetzt werden. Ist ein Tablespace mit demselben Namen in der Zieldatenbank bereits vorhanden, kann dieser einfach umbenannt werden. SQL> ALTER TABLESPACE users RENAME TO users_ps10;
Ein Umbenennen des zu importierenden Tablespaces während des Imports ist hingegen nicht möglich.
840
Data Warehousing
Transport ohne Datenbank-Link Ist ein Datenbank-Link nicht vorhanden, muss die Übertragung der Datendateien mit Betriebssystemmitteln durchgeführt werden. Außerdem ist zunächst ein Export der Metadaten von RH10 erforderlich. Auf beiden Datenbanken muss ein DirectoryObjekt (hier ttsdir) vorhanden sein, um auf die Dump-Dateien zuzugreifen. $ expdp system@rh10 directory=ttsdir dumpfile=tts_users.dmp logfile=tts_users.log transport_tablespaces=users job_name=ttsjob
Die Dump-Datei tts_users.dmp, welche die Metadaten enthält, wird nun auf den PS10-Server kopiert, wo der Tablespace anschließend in die Zieldatenbank eingehängt werden kann. $ impdp system@PS10 directory=ttsdir dumpfile=tts_users.dmp logfile=tts_users.log transport_datafiles='E:\oracle\oradata\PS10\users01.dbf' job_name=ttsjob
Transport von Tablespaces auf Unix Raw-Devices bzw. ASM Auch Tablespaces auf Raw-Devices können transportiert werden. Vor dem oben beschriebenen Transfer der Datendateien (mittels dbms_file_transfer oder mit Betriebssystemmitteln) wird z.B. mit dem Unix-Kommando dd der Inhalt der betreffenden Raw-Devices in Dateien übertragen bzw. umgekehrt. Nach dem Transfer, aber vor dem eigentlichen Import können diese Dateien dann, falls erforderlich, mittels dd wieder in Raw-Devices auf das Zielsystem geschrieben werden. Liegt ein Tablespace in Quell- oder Zieldatenbank auf ASM-Devices, stehen zwei Wege für den Transport offen Bei der Benutzung von dbms_file_transfer kann ein Directory-Objekt angegeben werden, das auf ein ASM-Verzeichnis verweist. Ein solches Directory-Objekt kann z.B. so erzeugt werden: SQL> CREATE DIRECTORY datadir AS '+DATAFILES/';
Alternativ kann mittels RMAN eine Datei zwischen dem normalen Dateisystem und einem ASM-Device verschoben werden, z.B.: RMAN> BACKUP AS COPY DATAFILE '+DATAFILES/system.256.1' to '/u01/oradata/ system.dbf';
Transport einzelner Partitionen Die Benutzung von transportablen Tablespaces ist sicherlich insofern interessant, als es die schnellste Methode ist, Daten von einer Datenbank in eine andere 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 Transports 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
Extraktion, Transformation, Laden
841
Befehl PARTITION EXCHANGE in eine Tabelle umgewandelt. Sollten Sie globale Indizes für die partitionierten Tabellen verwenden, dann macht es Sinn, die Option UPDATE GLOBAL INDEXES (evtl. mit dem Zusatz PARALLEL n) zu verwenden. Mit dieser Methode werden bei Änderungen von Partitionen die globalen Indizes mit angepasst, so dass es nicht mehr zu dem Status 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; Listing 15.1: 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. Ein ähnlicher Mechanismus kann benutzt werden, wenn – wie in Data Warehouses üblich – beispielsweise monatlich die ältesten Daten ausgelagert und archiviert werden sollen. Folgendes Vorgehen kann dabei gewählt werden: Die zu archivierende Partition wird mittels ALTER TABLE EXCHANGE PARTITION in eine Tabelle umgewandelt. Diese sollte in einem eigenen Tablespace liegen. Der Tablespace wird ggf. umbenannt, damit kein Namenskonflikt auf der Archiv-Datenbank auftritt. Der Tablespace wird auf die Archiv-Datenbank transportiert. Die Tabelle wird mittels ALTER TABLE EXCHANGE PARTITION als Partition in die dortige Archivtabelle eingehängt. Transport mit älteren Datenbankversionen Ist eine der beteiligten Datenbanken eine ältere Version als Oracle 10g, kann der Transfer der Datendateien sowie der Dump-Datei nur via Betriebssystem erfolgen. Außerdem muss dann der konventionelle Export/Import (siehe Kapitel 10.6.2) zur Verarbeitung der Metadaten genutzt werden. Für den Export sollte immer das Executable der älteren Oracle-Version genutzt werden, für den Import dasjenige der Zieldatenbank. Außerdem muss die Anmeldung jeweils als SYSDBA erfolgen. $ exp userid='system@rh9 as sysdba' transport_tablespace=y tablespaces=('USERS') log=tts_users.log file=tts_users.dmp $ imp userid='system@ps10 as sysdba' transport_tablespace=y tablespaces=('USERS') log=tts_users.log file=tts_users.dmp datafiles=('E:\oracle\oradata\PS10\users01.dbf')
842
15.1.2
Data Warehousing
Parallelisierung
Oracle 10g bietet für eine Vielzahl von Operationen eine Parallelisierung an, insbesondere für: 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 ev. Einsatz von Real-Application-Clusters, 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 seit Oracle9i auch RealApplication-Cluster-Systeme von der Parallelisierung ohne Performance-Verluste profitieren. Mit zunehmender Größe eines Data-Warehouses steigt oftmals auch die Anzahl der 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 (Konsolidierung 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 Serverparameter parallel_min_servers und parallel_max_ servers entsprechend gesetzt sein. Wenn also die Parallelisierung nur für administrative Zwecke verwendet wird, sollte auch darauf geachtet werden, dass nicht die automatische Vergabe des Sortierbereiches (workarea_size_policy=AUTO) eingestellt ist, da in diesem Fall nur maximal 30% der Gesamtgröße der PGA (pga_aggregate_target) genutzt werden kann. Stattdessen ist es effektiver, den älteren Parameter sort_area_size zu verwenden, aber beachten Sie bitte, dass dieser Parameter je Prozess gilt, d.h., bei einer Parallelisierung die Gesamtgröße des Speichers überschreiten könnte. 2
Data-Mart = eigenständiger Auszug eines Data Warehouses für einen bestimmten Bereich bzw. eine bestimmte Aufgabe
Extraktion, Transformation, Laden
843
Ein einfaches Beispiel unter Verwendung des Parameters soll dies verdeutlichen: SQL> ALTER SESSION SET sort_area_size = 100000000; SQL> SELECT /*+ PARALLEL(kunden,10) */ DISTINCT nachname FROM kunden; Listing 15.2: Ressourcenverbrauch einer einfachen Abfrage
In diesem Beispiel wird für die Sitzung ein Sortierbereich von ca. 100 MB 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 MB für Sortierungen belegen; in diesem Fall also ca. 1 GB 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. 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: Jedem parallelen 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 daher, dass das parallele Laden von Daten aus mehreren Dateien eher die Ausnahme ist, da oftmals nur eine Quelldatei zur Verfügung steht. Für das Laden von Daten über einen Datenbank-Link gilt diese Einschränkung jedoch nicht. Seit 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.
844
Data Warehousing
Externe Tabellen Über die Einbindung von externen Tabellen (siehe Kapitel 5.2.6) 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 ('auftragsdaten.dat') ) PARALLEL 5 REJECT LIMIT UNLIMITED; Listing 15.3: 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ßende Bereinigung oder Verdichtung kann verzichtet werden.
15.1.3
Komplexe Laderoutinen
Ein wichtiger – wenn nicht der wichtigste – Prozess in einem Data Warehouse ist die Bereinigung und Integration der Daten. Seit Oracle9i wurden 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.« Statt einer Programmierung in PL/SQL sollte hier der mit Oracle9i eingeführte MERGE-Befehl genutzt verwendet 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)
Extraktion, Transformation, Laden
845
Der Befehl sieht wie folgt aus: MERGE INTO USING ON ( = ) WHEN MATCHED THEN UPDATE SET = ... WHEN NOT MATCHED THEN INSERT (,...) VALUES (,...) Listing 15.4: 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. Natürlich können auch mehrere Spaltenvergleiche (z.B. bei zusammengesetzten Primärschlüsseln) mit AND verknüpft angegeben werden. Für den Fall, dass ausschließlich Änderungen und keine Einfügungen vorkommen, kann seit Oracle 10g der Zweig WHEN NOT MATCHED weggelassen werden. 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. Häufig wird dies wie im Beispiel durch eine Gruppierung nach den Vergleichsspalten erreicht. Wird dies nicht beachtet, tritt zur Laufzeit die folgende, nicht gerade intuitive Fehlermeldung auf: ORA-30926: Stabile Zeilengruppe in den Quelltabellen kann nicht eingelesen werden
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 auftraege 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. 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 = s.auf_datum AND v.prodnr = 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); Listing 15.5: Beispiel: MERGE
846
Data Warehousing
Die Benutzung des MERGE-Kommandos ist aus Performance-Gesichtspunkten einer PL/SQL-Lösung vorzuziehen, da es intern sehr effizient durch Outer-Joins ausgeführt wird und außerdem zahlreiche Kontext-Switches zwischen SQL- und PL/SQLEngine vermeidet, die ansonsten bei einer Einzelsatzverarbeitung in PL/SQL auftreten würden. 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. Seit der Oracle-Version 9i besteht die Möglichkeit, eine bedingte INSERTAnweisung 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: SQL> desc positionen Name ---------------------pos_aufnr pos_nr pos_prodnr pos_stueck pos_stueckpreis pos_volumen pos_volumenpreis pos_gewicht pos_gewichtpreis
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)
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) vorkommen. 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
Extraktion, Transformation, Laden
847
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 15.6: Conditional Insert
In diesem Beispiel werden in die Tabelle verkaeufe der entsprechende Gesamtpreis und der Preistyp eingetragen. Man hätte statt dieser Funktion auch einen UNIONSELECT aufbauen können, nur dann wäre die SELECT-Anweisung dreimal ausgeführt worden, während sie hier nur einmal ausgeführt werden muss. 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. Auch hier ist der entscheidende Vorteil, dass die SELECT-Anweisung lediglich einmal ausgeführt wird. 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 15.7: Multi-Table-Insert
15.1.4 Laden aus Non-Oracle-Datenbanken Häufig müssen auch Daten aus Fremdsystemen beim Ladeprozess berücksichtigt werden. Dabei gibt es grundsätzlich zwei Vorgehensweisen: Export/Import: Jobgesteuert werden die Daten aus dem Fremdsystem in ein einfach zu verarbeitendes Austauschformat überführt. Meistens handelt es sich dabei um CSV(Comma Separated Vector)-Dateien oder Varianten hiervon. Diese können anschließend – wie oben beschrieben – mit dem SQL*Loader in die Oracle-Datenbank geladen oder als externe Tabelle behandelt werden.
848
Data Warehousing
Laden über einen Datenbank-Link. Im Gegensatz zu einem normalen Datenbank-Link, der ja auf eine andere Oracle-Datenbank zeigt, wird hierbei die »Generic Connectivity«-Funktion genutzt, die dem Oracle-Server erlaubt, auf beliebige andere Datenquellen zuzugreifen, solange nur ein ODBC- oder OLE DB-Treiber für die betreffende Datenquelle vorliegt. Der Zugriff beispielsweise auf Access-, Interbase- oder diverse weitere Datenbanksysteme stellt damit kein Problem dar. Zugriff auf Fremddatenbanken Um eine Verbindung zu einer Fremddatenbank via Datenbank-Link aufzunehmen, muss die Oracle-Server-Software auf der betreffenden Maschine installiert werden. Eine eigene Datenbank ist aber nicht erforderlich, entscheidend ist lediglich, dass ein Listener gestartet werden kann. Außerdem müssen bei der Software-Installation die Punkte »Oracle Transparent Gateways« bzw. »Generic Connectivity« ausgewählt werden. Als Kontrolle kann die Existenz des Unterverzeichnisses hs4 im ORACLE_HOME überprüft werden. Die notwendigen Vorbereitungsschritte sollen nun anhand eines Beispiels aufgezeigt werden. Dabei wird der Zugriff auf eine Microsoft Access-Datenbank (C:\MyFiles\mydb.mdb) auf einem MS-Windows-Rechner eingerichtet (mittlerweile sind auch für Unix-Plattformen ODBC-Treiber bzw. OLE DB-Provider erhältlich). Auf dem Fremdsystem müssen nun folgende Vorbereitungen getroffen werden: Ein geeigneter ODBC-Treiber oder ein OLE DB-Provider für Access muss ggf. installiert werden. Falls ODBC benutzt wird: Über die Systemsteuerung wird für diesen Treiber eine ODBC-Datenquelle (DSN) definiert. Dabei muss es sich um eine System-DSN oder eine Benutzer-DSN handeln (eine Datei-DSN ist nicht möglich). Als Datenquellenname wird z.B. ACCESSDS vergeben. Die Datenquelle wird mit der Datei C:\MyFiles\mydb.mdb verknüpft. Falls OLE DB benutzt wird: In einem beliebigen Verzeichnis wird eine neue Textdatei erstellt und mit der Endung .udl versehen, z.B. accessds.udl. Durch Doppelklick wird die OLE DB-Datenquelle konfiguriert, d.h., der OLE DB-Provider wird ausgewählt und die Datenquelle mit der Datei C:\MyFiles\mydb.mdb verknüpft. In der Datei \network\admin\listener.ora wird die SID-Liste um einen Eintrag – z.B. ACCODBC oder ACCOLEDB – ergänzt. Der SID-Name sollte nicht länger als acht Zeichen sein. Unter PROGRAM wird entweder hsodbc (falls ODBC benutzt wird) oder hsolesql (falls OLE DB benutzt wird) eingetragen.
4
hs steht für Heterogenious Services, d.h. die Unterstützung von »Nicht-Oracle«-Datenbankstrukturen.
Extraktion, Transformation, Laden
849
SID_LIST_LISTENER = (SID_LIST = ... <-- evtl. bereits vorhandene Einträge (SID_DESC = (SID_NAME = ACCODBC | ACCOLEDB) (ORACLE_HOME = C:/oracle/product/10.1.0) (PROGRAM = hsodbc | hsolesql) ) )
Im Verzeichnis \hs\admin muss eine Datei mit dem Namen init <SID_NAME>.ora – also z.B. initACCODBC.ora – angelegt werden. In dieser Datei wird auf die Datenquelle (für ODBC) bzw. auf den Daten-Link (für OLE DB) verwiesen. Für ODBC lautet der Dateiinhalt: HS_FDS_CONNECT_INFO = ACCESSDS. Für OLE DB lautet der Dateiinhalt: HS_FDS_CONNECT_INFO = "UDLFILE=C:/MyFiles/accessds.udl". Achtung: Der Pfad für die UDL-Datei muss mit einfachen Slashes (keine Backslashes) geschrieben werden! Auf dem System mit der Oracle-Datenbank muss nun noch der Zugriff konfiguriert werden. Dazu wird ein TNS-Name für die Fremddatenbank definiert, es ist also beispielsweise folgender Eintrag in die Datei /network/admin/tnsnames.ora zu tätigen. Entscheidend ist dabei die Klausel (HS=OK): ACCODBC = (DESCRIPTION = (ADDRESS = (PROTOCOL = tcp) (HOST = ) (PORT = 1521) ) (CONNECT_DATA = (SID = ACCODBC) ) (HS=OK) )
Anschließend kann ein Datenbank-Link zur Fremddatenbank definiert werden: SQL> CREATE DATABASE LINK accodbc USING 'ACCODBC';
Jetzt können Tabellen in der Access-Datenbank einfach wie folgt angesprochen werden: SQL> SELECT * FROM kunden@ACCODBC;
Falls dabei eine Fehlermeldung der Art ORA-02085: Datenbank-Link ACCODBC.WORLD stellt eine Verbindung her zu HO.WORLD
ausgegeben wird, ist wahrscheinlich der Serverparameter global_names auf TRUE gesetzt. Dadurch wird erzwungen, dass der Name des Datenbank-Links mit dem globalen Namen der Zieldatenbank (.) übereinstimmt. Für Fremddatenbanken ist der globale Name per Default auf HO.WORLD gesetzt. Er kann jedoch über die Parameter HS_DB_NAME und HS_DB_DOMAIN gesetzt werden, z.B.:
850
Data Warehousing
HS_FDS_CONNECT_INFO = ACCESSDS HS_DB_NAME = ACCODBC HS_DB_DOMAIN = WORLD
Einige weitere wichtige HS-Parameter sollen hier kurz vorgestellt werden: HS_LANGUAGE entspricht der Client-Umgebungsvariablen NLS_LANG (siehe Kapitel 8). Insbesondere wird damit der von der Fremddatenbank verwendete Zeichensatz angegeben. Für Wndows-Anwendungen, z.B. eine Access-Datenbank, ist dies WE8MSWIN1252, also beispielsweise HS_LANGUAGE=GERMAN_GERMANY .WE8MSWIN1252. Um Probleme beim Verbindungsaufbau mit der Fremddatenbank zu finden, kann mittels HS_FDS_TRACE_LEVEL=ON ein Fehler-Tracing eingeschaltet werden. Die Trace-Dateien liegen im Verzeichnis /hs/trace. Weitere HS-Parameter sind in der Dokumentation Oracle 10g Heterogeneous Connectivity Administrator’s Guide beschrieben. Transparent Gateways Für spezielle Datenbanken ist eine noch weitergehende Lösung in Form der so genannten Transparent Gateways verfügbar. Im Gegensatz zu Generic Connectivity, wo die Anbindung über eine der beiden standardisierten Schnittstellen ODBC oder OLE DB erfolgt, bietet ein solches Gateway einen spezialisierten Zugriff auf ein bestimmtes Datenbanksystem – z.B. DB2 – mit mehr Möglichkeiten und besserer Performance. Beispielsweise werden verteilte Transaktionen im Rahmen des 2PCProtokolls (Two-Phase-Commit) von den Transparent Gateways unterstützt. Transparent Gateways sind beispielsweise für DB2, Sybase, Microsoft SQL Server, Teradata, Informix, Ingres, Rdb und RMS verfügbar. Die Konfiguration geschieht ähnlich wie bei Generic Connectivity, für jedes Gateway ist aber auch eine separate Dokumentation verfügbar.
15.1.5 Überwachung der Ladeoperation Resumable Statements Bei umfangreichen Ladeoperationen kann es natürlich zu Engpässen im System kommen (Daten- oder Index-Tablespace zu klein, Undo-Tablespace 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. Seit der Version 9i ist es möglich, dass der gerade ausgeführte Befehl beim Auftreten eines Engpasses angehalten wird und nach der Behebung des Fehlers selbstständig wieder anläuft. Damit können im laufenden Betrieb folgende Fehler behoben werden: ORA-01650 ORA-01653 ORA-01654 ORA-01628 ORA-01631 ORA-01654 ORA-01536
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 15.8: Liste der durch Resumable Statements tolerierten Fehler
Extraktion, Transformation, Laden
851
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, und der Befehl wird angehalten. Der Datenbankadministrator hat nun TIMEOUT-Sekunden Zeit, um den Engpass zu beheben. Um ihn davon in Kenntnis zu setzen, wird außerdem ein Alert Resumable Session Suspended ausgelöst. In der Alert-Datei oder über die View dba_resumable erhält der DBA weitere Informationen. SQL> ALTER SESSION ENABLE RESUMABLE TIMEOUT 900 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 15.9: Resumable Statement
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. Vorher können alle Informationen über das Package dbms_resumable ausgelesen werden. CREATE OR REPLACE TRIGGER resumable_default AFTER SUSPEND ON DATABASE BEGIN -- Mail an DBA END; Listing 15.10: Datenbank-Trigger auf Suspend
Der Timeout für den Wiederanlauf der Operation sollte nicht zu hoch gewählt werden, da Sperren und sonstige Ressourcen nicht freigegeben werden, solange die Operation wartet. Daher ist das Versetzen einer Session in den Resumable-Modus auch an das Systemprivileg RESUMABLE gebunden, das ggf. zuvor zugewiesen werden muss. Überwachung von Jobs Gerade bei der Verarbeitung umfangreicher Operationen stellt sich sehr oft 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 mit Hilfe der virtuellen Tabelle v$session_longops zu überwachen. Voraussetzung für die Verwendung dieser Funktion ist, dass der Server-
852
Data Warehousing
parameter timed_statistics = true gesetzt ist. Ab Oracle9i ist dieser Parameter in der Regel gesetzt, weil er über den Parameter statistics_level mit aktiviert wird. Hat dieser mindestens den Wert typical, wird timed_statistics = true gesetzt. Die folgende Abbildung zeigt die Verwendung im TOAD während der Ermittlung von Statistiken.
Abbildung 15.1: Long Ops
15.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.
Datenbankdesign für Data Warehouses
853
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 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-Stunden-Betrieb)? 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.
15.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 liegt dabei zwischen 64 KB und 1 MB je nach verwendetem Betriebssystem. Jede Platte sollte zusätzlich über Raid-1 gespiegelt werden, um eine optimale Verfügbarkeit zu gewährleisten.
854
Data Warehousing
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. 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 BCVs 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 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 64-Bit-Betriebssysteme an. Während bei den 32-Bit-Versionen die Obergrenze für die Oracle SGA je nach Hersteller bei 2 bis 4 GB liegt, können mit einer 64-Bit-Version beliebig große Bereiche für die SGA adressiert werden. Sie sollten also beim Neuaufbau einer solchen Datenbank darauf achten, dass Sie ein entsprechendes Betriebssystem und die dazu passende Oracle-Software einsetzen. Neben der Skalierbarkeit ist die Ausfallsicherheit eines Hardware-Clusters in Verbindung mit dem Oracle Real-Application-Clusters 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 Datenbankblö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-Clusters Der Real-Application-Cluster wurde schon in Kapitel 13.3 beschrieben, es sollen deshalb hier nur die Einsatzgebiete im Data-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:
Datenbankdesign für Data Warehouses
855
Abbildung 15.2: Real-Application-Cluster
Wie Abbildung 15.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. Dieser Shared-Modus kann bei heutigen Systemen in unterschiedlicher Weise realisiert werden. Mit Version 8i hat Oracle für einige Systeme das so genannte Oracle Cluster Filesystem (OCFS) eingeführt, andere Hersteller, wie z.B. IBM haben eine eigene Implementierung mit dem Namen Global Filesystem. Mit Version 10g gibt es darüber hinaus das Oracle Filesystem ASM (Automatic Storage Management). Und nicht zuletzt spielen dank ihrer überragenden Performance auch die Raw Devices immer noch eine Rolle. Sollten Sie also ein Data Warehouse aufsetzen wollen und bezüglich der Skalierbarkeit eine Real-Application-Clusters-Architektur für die Zukunft ins Auge gefasst haben, dann sollten Sie sich frühzeitig über die unterschiedlichen Konfigurationen informieren, da ein späterer Umstieg nur mit erheblichem Aufwand möglich ist. Während in der Vergangenheit der Vorgänger des Real-Application-Clusters (Oracle Parallel Server) nur sehr bedingt skalierbar war, kann durch die Neuimplementierung davon ausgegangen werden, dass ein Skalierungsfaktor von 90% und mehr beim Einsatz von Real-Application-Clusters 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. Implementiert wird dies über die Konfiguration des Oracle Net Clients und den Oracle Net Listener (siehe auch Kapitel 7.1).
856
Data Warehousing
Erforderlich sind für den Einsatz von Connection-Load-Balancing folgende Serverparameter: SERVICE_NAME INSTANCE_MAME REMOTE_LISTENER
Das bedeutet für die in Abbildung 15.1 gezeigte Konfiguration: Serverparameter 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)))
Serverparameter auf K02 (Knoten 2) SERVICE_NAME INSTANCE_NAME DB_NAME REMOTE_LISTENER
= = = =
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)
Datenbankdesign für Data Warehouses
857
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 Serverparameters 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 und 10 optimierten Mechanismus Cache-Fusion ist es möglich, selbst beim Laden von Daten eine Verteilung über die Knoten hinweg vorzunehmen. Das bedeutet, dass DML-Operationen über Knotengrenzen hinweg parallelisiert werden können.
15.2.2 Tablespace-Layout Neben dem Aufbau von unterschiedlichen Partitionen für Tabellen spielen 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 kann dieses Thema durch das direkte Anlegen mehrerer Datendateien für einen Tablespace abgedeckt werden, da dann die Extents gleichmäßig über alle Dateien verteilt werden. Effektiver ist jedoch die Benutzung von ASM, da hierbei eine automatische Verteilung aller Daten erfolgt. 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 werden und bei partitionierten Tabellen einzelne Tablespaces Read-only gesetzt werden können.
858
Data Warehousing
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 Index 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: 4 KB oder 8 KB für die System- und Dimensionstabellen und Verwaltungsinformationen 8 KB oder 16 KB für die wesentlichen Faktentabellen, d.h. der Großteil des DataWarehouses 16 KB oder 32 KB für Tabellen mit LOB-Spalten Damit wird 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)
Datenbankdesign für Data Warehouses
859
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) 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. Sollte das Data-Warehouse wiederum als Quelle für andere Systeme dienen (z.B. Data-Marts), ist hier eventuell die Benutzung von Streams eine Option. Dabei muss allerdings beachtet werden, dass das NOLOGGING dazu führt, dass die Daten nicht über den Streams-Prozess repliziert werden können.
15.2.3
Partitionierung
Oracle hat mit der Version 8 die Partitionierung als eine wichtige Erweiterung für den Aufbau von Data Warehouses eingeführt. 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 5.3). 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_04 VALUES LESS TABLESPACE ts1, PARTITION q2_04 VALUES LESS TABLESPACE ts2, PARTITION q3_04 VALUES LESS TABLESPACE ts3, PARTITION q4_04 VALUES LESS
THAN (to_date('01042004','DDMMYYYY')) THAN (to_date('01072004','DDMMYYYY')) THAN (to_date('01102004','DDMMYYYY')) THAN (to_date('01012005','DDMMYYYY'))
860
Data Warehousing
TABLESPACE ts4, PARTITION q1_05 VALUES LESS THAN (MAXVALUE) TABLESPACE ts1); CREATE INDEX local_verkaeufe_datum ON verkaeufe (datum) LOCAL ( PARTITION li1_04 TABLESPACE its1, PARTITION li2_04 TABLESPACE its2, PARTITION li3_04 TABLESPACE its3, PARTITION li4_04 TABLESPACE its4, PARTITION li1_05 TABLESPACE its1 ); Listing 15.11: Range Partitioning SQL> SELECT sum(menge * preis) FROM verkaeufe WHERE datum BETWEEN to_date(’30.09.2004’,’DD.MM.YYYY’) AND to_date(’05.11.2004’,’DD.MM.YYYY’);
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 15.12: 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 2004 auszulagern (zum Beispiel auf ein Read-only-Medium) und ein neues Quartal für das Jahr 2005 hinzuzunehmen. Sie sollten aber vorsichtig mit dem Befehl SPLIT PARTITION sein. Es liegt zunächst nahe zu sagen, alle Daten des Jahres 2005 wandern zunächst in die Partition Q1_05. Am Ende des Quartals wird dann diese Partition gespalten (SPLIT PARTITION) und
Datenbankdesign für Data Warehouses
861
damit eine neue Partition Q2_05 angelegt. Dabei werden aber alle Daten der ursprünglichen Partition bewegt, d.h., die komplette Partitionsinformation der Partitionen Q1_05 und Q2_05 wird 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 2004 und es wird erwartet, dass die ersten Daten für das Jahr 2005 in die Tabelle verkaeufe eingegeben werden (siehe Beispiel Range Partitioning). Es ist jetzt an der Zeit, eine neue Partition für das 2. Quartal 2005 aufzubauen in der Form: ALTER TABLE verkaeufe SPLIT PARTITION q1_05 AT (TO_DATE('01042005','DDMMYYYY')) INTO (PARTITION q1_05, PARTITION q2_05 TABLESPACE ts2); Listing 15.13: 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_05 VALUES LESS THAN (to_date('01072005','DDMMYYYY')) TABLESPACE ts2; Listing 15.14: 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.
862
Ein Beispiel soll dies verdeutlichen: Zwei Tabellen werden nach einer Kundennummer partitioniert: Tabelle kunden Tabelle verkaeufe CREATE TABLE verkaeufe ( rechnungsnr NUMBER, kdnr NUMBER, datum DATE, prodnr NUMBER, menge NUMBER, preis NUMBER ) PARTITION BY HASH (kdnr) ( PARTITION v1_01 TABLESPACE ts1, PARTITION v2_02 TABLESPACE ts2, PARTITION v3_03 TABLESPACE ts3, PARTITION v4_04 TABLESPACE 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 ); CREATE INDEX lidx_kd_kdnr ON kunden (kdnr) LOCAL ( PARTITION lidxkd1 TABLESPACE its1, PARTITION lidxkd2 TABLESPACE its2, PARTITION lidxkd3 TABLESPACE its3, PARTITION lidxkd4 TABLESPACE its4 ); Listing 15.15: Hash-Partition SQL> SELECT sum(menge * preis) FROM verkaeufe v, kunden k WHERE v.kdnr = k.kdnr AND k.nachname = 'Schmidt' AND k.ort = 'Köln' AND k.kdnr = 3127; PLAN_TABLE_OUTPUT
Data Warehousing
Datenbankdesign für Data Warehouses
863
-------------------------------------------------------------------------------| Id | Operation | Name |Rows |Pstart|Pstop| -------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | | | 1 | SORT AGGREGATE | | 1 | | | | 2 | MERGE JOIN CARTESIAN | | 1 | | | | 3 | PARTITION HASH SINGLE | | 1 | 1 | 1| |* 4 | TABLE ACCESS BY LOCAL INDEX ROWID| KUNDEN | 1 | 1 | 1| |* 5 | INDEX RANGE SCAN | LIDX_KD_KDNR | 1 | 1 | 1| | 6 | BUFFER SORT | | 43 | | | | 7 | PARTITION HASH SINGLE | | 43 | 1 | 1| |* 8 | TABLE ACCESS FULL | VERKAEUFE | 43 | 1 | 1| -------------------------------------------------------------------------------Predicate Information (identified by operation id): --------------------------------------------------4 - filter("K"."NACHNAME"='Schmidt' AND "K"."ORT"='Köln') 5 - access("K"."KDNR"=3127) 9 - access("V"."KDNR"=3127) Partition-Wise Join
Der Ausführungsplan zeigt, dass hier nur die Partition 1 der beiden Tabellen kunden und verkaeufe genutzt wird. 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 werden zum einen eine effektive Administration und zum anderen ein schneller Zugriff auf die Daten erreicht. Der Aufbau und die Verwendung dieser Art der Partitionierung werden schon in Kapitel 5 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 die Möglichkeit geschaffen worden, Tabellen nach Gebieten einzuteilen. Ansonsten verhält sich eine ListPartition wie eine Range-Partition, d.h., es sind die gleichen Befehle möglich.
864
Data Warehousing
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, PARTITION l8 VALUES (DEFAULT) TABLESPACE ts4 ); Listing 15.16: List-Partition
Die letzte Partition bildet eine Dummy-Partition und nimmt alle anderen Werte auf (entspricht MAXVALUE bei Range-Partition). Im Gegensatz zur Range-Partitionierung können keine zusammengesetzten Spalten verwendet werden. Außerdem kann diese Art der Partitionierung nicht mit der Hash-Partitionierung kombiniert werden, wohl aber mit Range-Partititionierung. Es muss also bei List-Partitionen darauf geachtet werden, dass jeder Wert, der vorkommen kann, auch einer Partition zugewiesen wurde oder aber eine Dummy-Partition vorhanden ist. 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 15.17: Modify-Partition
Datenbankdesign für Data Warehouses
865
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 Elimination im Vordergrund stehen. Für dieses Beispiel gilt das jedoch nur eingeschränkt.
15.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 Index. 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. 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 5.3.3). Mit ihrer Hilfe können große Datenmengen effizient indiziert werden, ohne dass 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.
866 CREATE TABLE KUNDEN ( kdnr NUMBER anrede VARCHAR2 vorname VARCHAR2 nachname VARCHAR2 adresse VARCHAR2 plz NUMBER ort VARCHAR2 bundesland VARCHAR2 gebiet VARCHAR2 vertrieb NUMBER
Data Warehousing
(10), (5), (50), (50), (50), (6), (50), (50), (5), (10))
Listing 15.18: Kundentabelle Data Warehouse
Die Indizierung dieser Tabelle muss jetzt folgende Abfragen unterstützen: Ermitteln einzelner Personen (über Nachname, evtl. Vorname, evtl. Ort, evtl. 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 BITMAP INDEX b_anrede ON kunden (anrede); CREATE BITMAP INDEX b_vorname ON kunden (UPPER(vorname)); CREATE BITMAP INDEX b_nachname ON kunden (UPPER(nachname)); CREATE BITMAP INDEX b_adresse ON kunden (UPPER(adresse)); CREATE BITMAP INDEX b_ort ON kunden (UPPER(ort)); CREATE BITMAP INDEX b_plz ON kunden (plz); CREATE BITMAP INDEX b_bland ON kunden (bundesland); CREATE BITMAP INDEX b_gebiet ON kunden (gebiet); SQL> SELECT * FROM kunden WHERE UPPER(vorname) like 'M%' AND UPPER(nachname) like 'AHR%' AND UPPER(ort) = 'HANNOVER' AND 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 15.19: Zugriff über mehrere Bitmapped Indizes
Datenbankdesign für Data Warehouses
867
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 Join Indizes (siehe Kapitel 5.3.4). Hierbei wird der Bitmapped Index 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)); SQL> ALTER TABLE mitarbeiter ADD CONSTRAINT pk_mitarbeiter PRIMARY KEY (m_nr); SQL> CREATE BITMAP INDEX b_join_vertrieb ON kunden(m.m_nachname) FROM kunden k, mitarbeiter m WHERE k.vertrieb = m.m_nr; SQL> SELECT k.ort FROM kunden k, mitarbeiter m WHERE k.vertrieb = m.m_nr AND 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 15.20: 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.
868
15.2.5
Data Warehousing
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. Dieses Data Warehouse ist derart komplex zu verwalten, dass man lieber auf das operative System zugreifen sollte, statt ein separates System aufzusetzen. In den meisten Fällen wird die Antwort aber lauten: Tagesaktuell! 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 die Aufgabe der Replikation von Daten zwischen unterschiedlichen Datenbanken (siehe Kapitel 13.5.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 15.21: Einfache Verdichtung
Datenbankdesign für Data Warehouses
869
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, 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 15.22: 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> 2 3 SQL> 2 3
CREATE MATERIALIZED VIEW LOG WITH SEQUENCE, ROWID (aufnr, INCLUDING NEW VALUES; CREATE MATERIALIZED VIEW LOG WITH SEQUENCE, ROWID (aufnr, INCLUDING NEW VALUES;
ON auftraege aufdatum) ON positionen prodnr, anzahl, einzelpreis)
Listing 15.23: Materialized View Logs
Damit werden jetzt alle Änderungen an den Tabellen auftraege und positionen, die Spalten in der obigen Beispielabfrage betreffen, in Tabellen mit dem Namen mlog$_auftraege bzw. mlog$_positionen gespeichert.
870
Data Warehousing
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, bevor über die Verwendung von Materialized View Logs nachgedacht wird, sollte zunächst einmal geprüft werden, 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 kann. Diese Prozedur schreibt alle Informationen in eine Tabelle mv_capabilities_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 Skript im Verzeichnis ORACLE_HOME/rdbms/admin mit dem Namen utlxmv.sql. BEGIN 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'); END; / SET SERVEROUTPUT ON SIZE 100000 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; /
Datenbankdesign für Data Warehouses
871
PCT:N : PCT_TABLE:N AUFTRAEGE: Relation ist keine partitionierte Tabelle PCT_TABLE:N POSITIONEN: Relation ist keine partitionierte Tabelle PCT_TABLE_REWRITE:N AUFTRAEGE: Relation ist keine partitionierte Tabelle PCT_TABLE_REWRITE:N POSITIONEN: Relation ist keine partitionierte Tabelle REFRESH_COMPLETE:Y : REFRESH_FAST:Y : REFRESH_FAST_AFTER_ANY_DML:Y : REFRESH_FAST_AFTER_INSERT:Y : REFRESH_FAST_AFTER_ONETAB_DML:Y : REFRESH_FAST_PCT:N : PCT bei keiner der Detailtabellen in der Materialized View möglich REWRITE:Y : REWRITE_FULL_TEXT_MATCH:Y : REWRITE_GENERAL:Y : REWRITE_PARTIAL_TEXT_MATCH:Y : REWRITE_PCT:N : Allgemeines Neuschreiben nicht möglich oder PCT bei keiner der Detailtabellen möglich: Listing 15.24: Ü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. Den Unterschied des SQL-Befehls gegenüber der oben erstellten Materialized View machen ausschließlich die Zähler (COUNT) auf die einzelnen Spalten aus. 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
872
Data Warehousing
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 15.25: Materialized View mit Fast Refresh
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 Befehl ALTER MATERIALIZED VIEW ... REFRESH (den es auch gibt, der aber nur das Standardverhalten für eine Aktualisierung ändert), sondern durch das Package dbms_mview: dbms_mview.refresh aktualisiert eine oder mehrere Materialized Views. dbms_mview.refresh_all_mviews aktualisiert alle zum Schema gehörenden Materialized 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 Views 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 15.26: 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 explizites 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 seit Oracle9i mit automatischem Undo-Management arbeiten, entfällt diese Option. Soll beim Auftreten eines Fehlers der Abgleich
Datenbankdesign für Data Warehouses
873
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. Über die View dba_mview_refresh_times kann die Aktualität jeder Materialized-View kontrolliert 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 15.27: Index auf Materialized View
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 15.28: Index auf die Basistabelle
Automatische Generierung Das korrekte Erzeugen der Materialized View Logs sowie Materialized Views mit dem Ziel, möglichst alle Fast-Refresh-Optionen zu unterstützen, ist nicht ganz trivial und war in der Vergangenheit häufig nur mittels Trial & Error zu erreichen. Mit der Version Oracle 10g ist es über den MView-Advisor möglich, alle SQL-Statements zur Erzeugung der Materialized Views und Materialized View Logs automatisch erzeugen zu lassen. Beispielsweise können eine entsprechende Skriptdatei (mv_create.sql) sowie eine weiteres Undo-Skript (mv_undo.sql) zum Löschen der betreffenden Objekte wie folgt generiert werden (das Erzeugen der Dateien verlangt Schreibrechte auf dem entsprechenden Directory-Objekt): CREATE DIRECTORY TUNE_RESULTS AS 'C:\Temp'; DECLARE mystmt VARCHAR2(32000) := 'CREATE MATERIALIZED VIEW verdichtung_mv BUILD IMMEDIATE REFRESH FAST ON DEMAND ENABLE QUERY REWRITE AS SELECT TRUNC(a.aufdatum) AS aufdatum, b.prodnr AS prodnr, SUM(b.anzahl) AS anz_positionen, SUM(b.anzahl * b.einzelpreis) AS positionswert FROM auftraege a, aufpositionen b WHERE a.aufnr = b.aufnr GROUP BY TRUNC(a.aufdatum), b.prodnr'; task_name VARCHAR2(100) := 'myMVTune'; BEGIN dbms_advisor.delete_task(task_name); dbms_advisor.tune_mview (task_name, mystmt); dbms_advisor.create_file(
874
Data Warehousing
dbms_advisor.get_task_script(task_name), 'TUNE_RESULTS', 'mv_create.sql'); dbms_advisor.create_file( dbms_advisor.get_task_script(task_name,'UNDO'), 'TUNE_RESULTS', 'mv_undo.sql');END; /
Für die Benutzung des Packages dbms_advisor wird neben dem EXECUTE-Recht für das Package auch das Systemprivileg ADVISOR benötigt. Die generierten Skripte können direkt ausgeführt werden, enthalten aber noch einige weitere Anweisungen zur Verwaltung des Advisors. 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 Serverparameter: 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. Seit der Version Oracle 10g ist query_rewrite_enabled standardmäßig aktiviert. 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.2005','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 15.29: 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.
Datenbankdesign für Data Warehouses
875
Summary Advisor Oracle bietet über die Advisories Hilfestellungen an, welche Materialized Views sinnvoll wären, und bereitet entsprechende Skripte auf. Die Bedienung dieses Advisorys geschieht über die Packages dbms_advisor und dbms_sqltune. Im Folgenden wird anhand eines Beispiels die Benutzung gezeigt. Einige Operationen müssen in dem Schema ausgeführt werden, in dem die Materialized Views bzw. Materialized View Logs erstellt werden sollen. Dem Besitzer dieses Schemas (hier: PROD) müssen ggf. entsprechende Rechte zugewiesen werden: SQL> GRANT ADVISOR TO prod; SQL> GRANT ADMINISTER SQL TUNING SET TO prod; SQL> GRANT WRITE ON DIRECTORY tune_results TO prod;
Anschließend können über das AWR (Automatic Workload Repository, siehe Kapitel 11.2) zwei Snapshots angefertigt werden. Innerhalb des Snapshot-Zeitraums sollten als Workload die Client-Anwendungen, Batch-Läufe oder Reports etc. laufen, für die ein Tuning via Materialized Views untersucht werden soll. SQL> EXEC dbms_workload_repository.create_snapshot (); -- als DBA -- Ausführen des Workloads als normaler User SQL> EXEC dbms_workload_repository.create_snapshot (); -- als DBA
Anschließend werden aus dem angefallenen Workload die ressourcenintensivsten SQL-Statements ausgesucht und in ein so genanntes SQL-Tuning-Set (STS) geladen, das einfach einen Container zur weiteren Verarbeitung darstellt. Dies sollte als Administrator ausgeführt werden, da Leserechte auf den Data Dictionary Views für das AWR benötigt werden: SQL> SQL> SQL> SQL>
VARIABLE snap_id NUMBER VARIABLE sts_name VARCHAR2(20) EXEC :sts_name := 'MY_STS'; EXEC SELECT MAX(snap_id) into :snap_id FROM dba_hist_snapshot; SQL> EXEC dbms_sqltune.create_sqlset(:sts_name); -- STS erzeugen SQL> DECLARE sts_cursor dbms_sqltune.sqlset_cursor; BEGIN OPEN sts_cursor FOR SELECT VALUE(p) FROM TABLE(dbms_sqltune.select_workload_repository( :snap_id-1 -- Start-Snap-ID ,:snap_id -- Ende-Snap-ID ,'executions > 1 and disk_reads > 100' –- Filter ,NULL -- Object-Filter ,'disk_reads' –- für ORDER-BY-Klausel )) p; dbms_sqltune.load_sqlset(:sts_name, sts_cursor); END; /
876
Data Warehousing
Ggf. können die im SQL-Tuning-Set enthaltenen SQL-Statements nun überprüft werden. SQL> SET LONG 5000 SQL> SELECT sql_text FROM TABLE(dbms_sqltune.select_sqlset(:sts_name)); SQL> -- evtl. Nachbehandlung via DBMS_SQLTUNE.DELETE_SQLSET
Die restlichen Bearbeitungsschritte sollten nun als Benutzer PROD ausgeführt werden, da in diesem Schema später auch die Materialized Views erzeugt werden. Zunächst wird ein Workload-Objekt erzeugt, das mit den SQL-Statements aus dem STS befüllt wird. Für diesen Workload wird daraufhin ein Tuning-Task erzeugt und ausgeführt. SQL> SQL> SQL> SQL> SQL> SQL> SQL> SQL>
VARIABLE workload_name VARCHAR2(20) VARIABLE task_name VARCHAR2(20) VARIABLE saved_stmts NUMBER VARIABLE failed_stmts NUMBER exec :workload_name := 'MY_WORKLOAD'; exec :task_name := 'MY_TASK'; EXEC dbms_advisor.create_sqlwkld(:workload_name); EXEC dbms_advisor.import_sqlwkld_sts( :workload_name, :sts_name, 'NEW', 1, :saved_stmts, :failed_stmts); SQL> EXEC dbms_advisor.create_task ( 'SQL Access Advisor', :task_name); SQL> EXEC dbms_advisor.add_sqlwkld_ref( :task_name, :workload_name); SQL> EXEC dbms_advisor.execute_task(:task_name);
Die Tuning-Vorschläge sind nun im Data Dictionary abgelegt und können von dort bereits abgefragt werden. Komfortabler ist jedoch die Generierung eines Skripts (tuning.sql), das bereits entsprechende SQL-Kommandos zur Erzeugung der notwendigen Objekte enthält. SQL> EXEC dbms_advisor.create_file( dbms_advisor.get_task_script(:task_name), 'ADVISOR_RESULTS', 'tuning.sql');
Anschließend sollte wieder aufgeräumt werden, indem STS, Workload-Objekt und Tuning-Task gelöscht werden. SQL> EXEC dbms_advisor.reset_task(:task_name); SQL> EXEC dbms_advisor.delete_sqlwkld_ref( :task_name, :workload_name); SQL> EXEC dbms_advisor.delete_sqlwkld(:workload_name); SQL> EXEC dbms_advisor.delete_task(:task_name); SQL> EXEC dbms_sqltune.drop_sqlset(:sts_name);
Achtung: Der Summary-Advisor dbms_olap ist mit Oracle 10g nur noch aus Kompatibilitätsgründen verfügbar und sollte nicht mehr benutzt werden.
Datenbankdesign für Data Warehouses
877
15.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 eingebauten 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 15.30: 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 15.31: 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?«
878
Data Warehousing
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 ---------- ---------- ---------- ----------- ----- ------ -----... 2004 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 15.32: 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. GROUPING SETS Jede umfangreiche SQL-Aggregation führt zwangsläufig dazu, dass umfangreiche 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.
Datenbankdesign für Data Warehouses SELECT
FROM WHERE AND GROUP
879
k.gebiet, k.bundesland, z.jahr, z.quartal, SUM(v.preis) kunden k, zeiten z, verkaeufe v k.kdnr = v.kdnr z.zeitnr = v.zeitnr BY GROUPING SETS ((k.gebiet, k.bundesland), (z.jahr, z.quartal)); BUNDESLAND JAHR QUARTAL SUM(V.PREIS) -------------------- ---------- ---------- -----------Berlin 20.549.822 Sachsen 5.666.940
GEBIE ----Ost Ost ... West Nordrhein-Westfalen
2004 2004
1 2
54.756.743 10.921.986 10.935.408
Listing 15.33: 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, welche 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 WHERE k.kdnr = v.kdnr GROUP BY k.bundesland ) SELECT bundesland, umsatz FROM laenderumsatz WHERE Umsatz > ( SELECT sum(umsatz) * 0.25 FROM laenderumsatz); Listing 15.34: WITH-Beispiel
880
Data Warehousing
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 15.35: Ausführungsplan WITH-Beispiel
15.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. 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. Um diese Tabelle 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-
Darstellung
881
Schema sind Fakten- und Dimensionstabellen wie Kaskaden 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 15.3: Star-Schema
15.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 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 die Ergebnismenge auf den Ort und ev. sogar auf Ortsteile oder Straßen verfeinert. 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 der Abbildung 15.3 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.
882
Data Warehousing
Als Nächstes wird eine Materialized View angelegt, welche 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 15.36: 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 15.37: Materialized View kunden_mview
Ü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 15.38: Abfrage über Dimension
Darstellung
883
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 15.39: 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.
15.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 Serverparameter 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;
Das erste Beispiel setzt den Parallelisierungsfaktor für diese Abfrage auf den Wert 4.
884
Data Warehousing
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 Serverparameter: parallel_min_servers parallel_max_servers parallel_min_percent parallel_automatic_tuning
= = = =
1 20 50 true
Speziell die Serverparameter sollten mit Bedacht gewählt werden. Wenn der Parameter parallel_max_servers zu groß gewählt wird, kann es sein, dass zu wenige 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, welche die Option parallel gesetzt haben. Die Serverparameter wie parallel_max_servers, db_file_multiblock_read_count und andere beeinflussen aber auch den Zugriffspfad bei Abfragen, so dass der CostBased-Optimizer einen Full-Table-Scan vorziehen wird, statt über einen Index auf die Daten zuzugreifen.
Stichwortverzeichnis Numerisch 2PC-Protokoll 761
A active workload repository 694 ADDM 591, 627 Ad-Hoc-Query 835 ADMINISTER RESOURCE MANAGER 478 Administrationswerkzeug Hora 278 Oracle Enterprise Manager 245 Scheduler 264 SQL*Plus 275 TOAD 276 Advanced Replication 19, 759 Advanced Security 20 Advisory 580 Aggregation 870 Aggregationsfunktion 877 AL16UTF16 176 AL32UTF8 357 Alarm 808 Alert 255 Alert-Datei 485, 671, 809 Aliasname 295, 639 all_control 463 ALTER DATABASE 128 BACKUP CONTROLFILE TO TRACE 133 BLOCK CHANGE TRACKING 137 RENAME GLOBAL_NAME 97, 161 ALTER DATABASE BEGIN BACKUP 572 ALTER DATABASE CHARACTER SET 162 ALTER DATABASE END BACKUP 572 ALTER DISKGROUP 152 ALTER INDEX 212 ALTER JAVA 337 ALTER MATERIALIZED VIEW 872 ALTER PROCEDURE 233 ALTER PROFILE 475 ALTER RESOURCE 474 ALTER ROLE 441 ALTER SESSION 204 CREATE_STORED_OUTLINES 629 SET CONSTRAINTS 221 ALTER SYSTEM 162, 696 CHECKPOINT 166 DISCONNECT SESSION 163 ENABLE RESTRICTED SESSION 162 FLUSH BUFFER_CACHE 163 FLUSH SHARED_POOL 163
KILL SESSION 162 SET db_cache_size 167 SUSPEND / RESUME 164 SWITCH LOGFILE 164, 166 ALTER SYSTEM RESUME 572 ALTER SYSTEM SUSPEND 572 ALTER TABLE 193, 199, 487 DISABLE CONSTRAINT 218 MINIMIZE RECORDS_PER_BLOCK 199 MOVE TABLESPACE 154 PARALLEL 883 ALTER TABLESPACE BEGIN BACKUP 166 OFFLINE NORMAL / TEMPORARY 166 RESIZE 105 ALTER TABLESPACE OFFLINE 123 ALTER TRIGGER 241 ALTER USER 382, 387–388, 392–393, 440, 474 ANALYZE 613, 620, 659, 689 VALIDATE STRUCTURE 620 ANALYZE INDEX 212 anonymes PL/SQL 234 ANONYMOUS 342 ANSI-Datentyp 178 ANSI-SQL 15, 176 ANSI-Standard 612 Antwortzeiten 575 Anwenderfehler 509 Anwendungs-Tracing 593 application context siehe Applikationskontext application role siehe secure application role Applikationskontext 448 Archive Destination 807 ARCHIVELOG 824 Archivelog-Modus 125, 512 Archivierte Redolog-Datei 100, 139, 149, 508, 511 Archivierung 52, 126, 254, 568 ARCH-Prozess 126 Array-Fetch 232, 612 ASM 16, 46, 69, 717, 840, 855, 857 Administration 728 FINE 148 Kandidat 148 ASM-Instanz 171 asmtool 146 asmtoolg 146 ASSM 105, 179 COARSE 148 Asynchroner I/O 39 ATO 650 Attributgruppe 191
886 AUDIT 486 Auditing 28, 377, 484 Audit-Trigger 490 Ausführungsplan 601, 623 Authentifizierung 363, 378 externe 380, 382 globale 380, 385 globale Benutzer 411 interne 379–380 Automatic Segment Space Management siehe ASSM Automatic Storage Management siehe ASM Automatic Tuning Optimizer 649 Automatic Workload Repository siehe AWR Autonome Transaktion 22 AUTONOMOUS_TRANSACTION 237 Autorisierung 363 Autotrace 624 aux_stats$ 618 AWR 583, 587, 875 AWR_REPORT_HTML 590
B B*Index 183, 197 Background Dump Destination 809 Backup 137, 247, 256 inkrementell 510 Offline 510 Backup Pieces 516 BACKUP VALIDATE 531 Backup-Level 514 Backup-Management 512 Backup-Set 149, 512, 516 Baseline 576, 589, 677 before image 116, 509 Benennungsmethoden 290 Benutzerplanung 376 Benutzerverwaltung 392 interne 379 Betriebssystem 36 BFILE 177 BFILE-Locator 242 BFILENAME 177 Big-Endian 838 Binärformat 838 BINARY_DOUBLE 178 BINARY_FLOAT 178 Bindevariablen 224, 610–611 BITMAP CONVERSION 200 Bitmap-Index 19, 198, 634, 636, 642, 865 Bitmap-Index-Fragment 200 Bitmap-Join-Index 201, 867 BLOB 177 Block Change Tracking 136 Block Change Tracking-Datei 101
Stichwortverzeichnis Blockfüllgrad 820 Blockgröße 50, 858 BLOCKSIZE-Klausel 51 Blockierender Prozess 819 Blockkorruption 530 Block-Logging 525 Blocksize 124 BOOLEAN 233 branch node 196 bucket 633 Buffer Cache 53, 144, 808 Business Contiguous Volume 571, 711 Business Copy 571 Business-API 226
C CACHE 648 Cache-Fusion 714, 854 call stack trace 696 CASCADE CONSTRAINTS 218 CAST-Operator 231 CBO 609 C-Compiler 240 certificate authority 407 chained_rows 620, 820 Change Managment Pack 20 Change Tracking 516 CHAR 176 char_to_label 469 CHARACTER SET 176, 348 CHECK-Constraint 218 Checkpoint 125, 131, 166 Checkpoint not complete 125 CHUNK 177 Chunk small 813 cipher suite 414 CLASSPATH 338 CLEAR UNARCHIVED LOGFILE 129 Client-Identifier 377, 385, 449 Client-Loadbalancing 312 CLOB 177, 358 Cluster 175, 188, 194, 196 Cluster File System 143 Cluster Ready Services 46–47, 65 Cluster Registry 720 Cluster-Manager 714 Cluster-Registrierung 65 Cluster-Schlüssel 175, 188 Clusterware 719 cmctl 324 code point 356 Code Reordering 240 Collection 231 column masking 449 column object siehe Spaltenobjekte
Stichwortverzeichnis COMMIT 22, 117 Companion CD 46 Compiler-Pragma 237 Composite Index 196 Composite-Partitioning 182, 208 Concatenated Index 196 Conditional Insert 847 Configuration Management Pack 21 CONNECT INTERNAL 157 Connect Time Failover 729 Connection Manager 323, 326, 672 MAX_CONNECTIONS 324 MAX_GATEWAY_PROCESSES 324 MIN_GATEWAY_PROCESSES 324 PARAMETER_LIST 324 SOURCE_ROUTE 324 Connection Pooling 309 Connection-Load-Balancing 855 Connect-Time Failover 312 Constraint 213–214 deaktivieren 218 DEFERRABLE 221 DISABLE 219 DISABLE NOVALIDATE 865 DISABLE VALIDATE 865 DROP INDEX 219 ENABLE 218 EXCEPTIONS INTO 220 FOREIGN KEY 215 INITIALLY DEFERRED 221 INITIALLY IMMEDIATE 221 KEEP INDEX 219 NOT DEFERRABLE 221 NOVALIDATE 218 ON DELETE CASCADE 217 ON DELETE SET NULL 217 PRIMARY KEY 215 RELY 220 Spalten 214 Unique 214 VALIDATE 218 verzögerte Prüfung 220 constructor methods siehe Objekttypen Context Area 610 control_files 132 Controlfile Autobackup 520 CONVERT 359 COPY Table 826 CORBA 330 CPU time 604 CREATE BITMAP INDEX 199, 202 CREATE CLUSTER 189 CREATE CONTROLFILE 133–134, 158
887 CREATE DATABASE 132, 158 MAXDATAFILES 78, 132 MAXINSTANCES 77, 132 MAXLOGFILES 78, 132 MAXLOGHISTORY 78, 132 MAXLOGMEMBERS 78, 132 CREATE DIMENSION 882 CREATE DIRECTORY 186 CREATE DISKGROUP 151 CREATE GLOBAL TEMPORARY TABLE 185 CREATE INDEX 185, 189, 197, 203, 207–211 CREATE JAVA 337 CREATE OUTLINE 629 CREATE PROFILE 474 CREATE ROLE 386, 423, 439, 441, 444, 447 CREATE ROLLBACK SEGMENT 154 CREATE TABLE 179, 191–193 ORGANIZATION INDEX 183 CREATE TABLESPACE 103 DATAFILE 104 CREATE TEMPORARY TABLESPACE 115 CREATE TYPE 191–192 CREATE UNDO TABLESPACE 119 CREATE USER 381, 383, 387, 423, 474 CREATE VIEW 192, 228 CREATE DATABASE 348 CREATE VIEW OF 231 create$java$lob$table 339 Critical Patch Updates 369 Crosscheck 814 CROSSCHECK BACKUP 532 CSMIG 361 CSSCAN 361 CTAS 824 CTWR-Prozess 137 CUBE 877 Cursor 610 cursor_sharing 648 CURSOR_SHARING_EXACT 648 cwallet.sso 412
D Data Dictionary 23, 109–110, 153, 186 Data Guard 19, 730 Apply-Prozess 749 Constraint 743 Data Guard Broker 751 Datenbank-Job 743 FAL-Client 733 FAL-Server 733 Graceful Switch 739 Managed Recovery Process 733 Managed Standby-Modus 738 Oracle Net-Konfiguration 736, 746
888 Primärschlüssel 745 Protection Mode 740, 754–755 Remote File Server 733 Restriktionen 742 Rollentausch 739 Rolling Upgrade 731, 743 Serverparameter 734, 745, 747 Standby-Kontrolldatei 737, 749 Supplemental Logging 743 Temporär-Tablespace 738 Trigger 743 Data Mining 20, 835 Data Pump 187, 235, 540 Attach 548 Direkter Pfad 546 Monitoring 547 NETWORK_LINK 793 NOLOGFILE 188 Data Pump Export 540 Query 545 Data Pump Import 540 Data Pump-Jobs 541 Data Warehouse 43 Database Buffer Cache 125 Database Configuration Assistant 66, 330, 342 Skripte 74 Database Configuration Assistant siehe DBCA Database Resource Manager 476 Database Upgrade Assistant 83, 85 Database Writer siehe DBWR-Prozess Data-Dictionary 123 Data-Mart 842 Data-Warehouse 203, 634, 835 DATE 177 DATE-Format 349 Dateisystem 811 Datenbank Downgrade 93 globaler Name 51, 759 Herunterfahren 252 Hochfahren 252 Installation 31 NOARCHIVELOG 824 Parametrierung 53 Stillstand 814 Upgrade 83 Version 52 vorkonfigurierte 67 Zeichensatz 48, 51, 78, 347 Zeitzone 352 Datenbank ID 528 Datenbankadministration 26 Datenbankblock 123 Datenbankdatei 138 Datenbankdesign 835, 852
Stichwortverzeichnis Datenbank-Job 264, 267 Broken 267 Fehler 266 Datenbankkonsistenz 124 Datenbankkopie 525 Datenbank-Link 233, 759, 843 Global 760 Private 760 Public 760 Datenbankmodell 50 Datenbanksicherheit 363 Datenbank-Software 46 Datenbank-Tracing 599 Datenbank-Trigger 851 Datendatei 54, 100, 149, 152 Autoextend 73 Datenmodellierung 195 Datensatzsperre 24 Datentypen 176 Datentyp-Konvertierung implizit 603 dba_audit_trail 487 dba_histograms 634 dba_outline_hints 630 dba_outlines 630 dba_proxies 388 dba_rsrc_manager_system_privs 478 dba_stmt_audit_opts 488 dba_tab_columns 634 dba-View 112 DBCA siehe Database Configuration Assistant DB-Capture 821 DBID 528 DBMS_ADVISOR 592 dbms_advisor 591 dbms_application_info 595 dbms_crypto 365 dbms_monitor 594 dbms_outln 631 dbms_outln_edit 630 dbms_resource_manager 476 dbms_session 595 dbms_sqltune 651, 653 dbms_stats 612, 615, 617, 627 dbms_support 660 dbms_system 660 dbms_workload_repository 589 dbms_xdb 341 dbms_xplan 623 dbtimezone 352 dbv siehe DBVERIFY DBVERIFY 691 DBWR-Prozess 144 DCE 384 DDL 15, 22 Dead Connection Detection 316, 506
Stichwortverzeichnis Deadlock 24 Dedicated Server 283, 311 Default Tablespace 838 DEFAULT TABLESPACE-Klausel 392 Default Temporary Tablespace 115 Deferred Transaction 766 DELETE EXPIRED BACKUPS 532 denormalisieren 835 Desaster Recovery 712 Device 144 dgmgrl 751 DHCP 287 Diagnostic Pack 20 Diagnostic-Patch 81 Dictionary-Managed Tablespace 107, 110, 153 Dienstbenennung 301 Dienstregistrierung 288 Digest-Tabelle 339 Digitale Zertifikate 396 Dimension 881 Dimensionsschlüssel 203 Dimensionstabelle 835, 880 direct hand-off 286 Direct Path 647 Direct-Load 137 Directory 186, 840 information tree 399 Objekt 244 Verwendung 319 Direct-Path 822 Direktiven 476 discretionary access control 462 Diskgruppen 146 Dispatcher 306, 326 MULTIPLEX 325 Distinguished Name 378, 397, 400, 407, 411, 413 DML 15, 22 Domäne 96 Downgrade 93 Data Dictionary 93 DROP JAVA 337 DROP TABLE 218 DROP TABLESPACE 218 DROP USER 393 Dump 704 errorstack 705 processstate 705 systemstate 706 dynamic class loading 329 dynamisches SQL 610
E Easy Installation 32 EJB 329–330 Elapsed Time 604
889 EMC 27, 854 BCV 854 Timefinder 854 emca 248 emctl 248, 263, 405 emd.properties 248 ENABLE QUERY REWRITE 229 encoding 357 Enterprise Domain 420 Enterprise Java Beans siehe EJB Enterprise Manager 152 Recovery Manager 532 Tuning-Pack 583 Enterprise Role 365, 377, 379, 395 Enterprise Security Manager 406, 424 Enterprise-Rollen 417 Enterprise-User 395, 417 Entität 175 Entwicklung 29 Equi-Partitioning 205, 861 ETL 835 Event 700 10046 666, 695 10210 693 10211 693 10212 693 10231 692 10232 693 10233 692 10730 461 Diagnose-Dumps 695 On-Error-Dump 695 Event 10046 660 EXCHANGE PARTITION 219 Exclusive Lock 217 EXECUTE 611 exp siehe Export/Import expdp 544, 840 explain 600 EXPLAIN PLAN 623, 625 Export 256, 541, 550, 841 Compress 553 Consistent 553 Query 553 Export/Import 235, 256, 356, 360, 541, 550–551, 555, 820, 822, 839, 841 Commit 556 COMPRESS 824 Fromuser / Touser 556 Full 556 Ignore 556 Indexfile 556 Streams-Instantiierung 792 Exportdatei 543, 551, 554 Express 20
890
Stichwortverzeichnis
Extent 812, 819 AUTOALLOCATE 107 UNIFORM SIZE 107 Externe Tabelle 175, 185, 242, 844 BADFILE 187 LOCATION 187 LOGFILE 187 TYPE 187 Extraktion 836
Globale virtuelle View 112 Globaler Hint 228 Globalization Support 347, 548 GRANT 386, 391, 436–437 DIRECTORY 186 Gregorianischer Kalender 352 Grid Control 16 GROUPING SETS 878
F
Hanganalyze 707 Hardware-Cluster 854 Hardware-Striping 853 Hash Join 621 Hash-Cluster 189 Hash-Funktion 189 Hash-Join 644–645 Hash-Partitioning 182 Hauptspeicher 36 Health Check 27 Heap-Tabelle 175 Hierarchie 881 High Water Mark 109, 179 Hint 196, 223, 228 ALL_ROWS 641 APPEND 647 CLUSTER 642 FIRST_ROWS 641 Global 639 INDEX_COMBINE 642 LEADING 643 MERGE 646 NO_PUSH_PRED 648 NO_UNNEST 647 NOPARALLEL 645 ORDERED 643 ORDERED_PREDICATES 648 PARALLEL 883 PARALLEL_INDEX 883 PUSH_PRED 648 PUSH_SUBQ 648 STAR_TRANSFORMATION 647 UNNEST 647 Hintergrundprozess CJQn 266, 268 DMnn 542 DWnn 542 Jnnn 266, 268 PMON 506 RECO-Prozess 764 Histogramm 224, 633 Histogramme density 634
Failsafe 712 Faktentabelle 835, 880 fast start checkpointing 128 Fast-Refresh 869 Fehler ORA-00600 667 ORA-01555 122, 155 ORA-07445 667 Fehleranalyse 503 FETCH 612 FETCH-Phase 609 fga_log$ 489 Filesystem 144, 814 Fine Grain Access Control siehe Virtual Private Database Fine-Grain-Auditing 489 Firewall 308, 326 flash freeze 706 Flash Recovery Area 70, 809, 814 Flashback Database 52, 101, 535 Flashback Query 26, 117–118, 560 Flashback Table 563 Flashback-Log 101, 139, 149 Flash-Recovery Area 254, 501, 522, 536 Free Block List 647 FREELIST GROUPS 108 FREELISTS 107 Freelists 179 Fremdschlüssel 213 Full Block Logging 511, 569 Full Table Scan 179 Full-Table-Scan 621, 623, 625, 633, 638, 648 Function-based Index 203, 229, 638, 826
G garbage collector 329 Gateway 324 Gateway-Technologie 836 gather_stats_job 273 Geheimhaltungspflicht 364 Generic Connectivity 848 Geschachtelte Tabelle 175 Global File System 145
H
Stichwortverzeichnis Hochverfügbarkeit 709 Failsafe 712 Infrastruktur 713 MS-Windows 712 Rolling Upgrade 718 Server 712 Shareplex 801 Speichersystem 710 Hora 275, 278 hsodbc 848 hsolesql 848 HTML DB 21, 47 HTTP-Server 47
I I/O-Subsystem 853 I/O-Verteilung 143 IAS siehe Oracle Application Server Identity Management Infrastruktur 402 Identity Management Realm 418 IEEE 754-Standard 178 impdp 839 Index 180, 195 Baum 196 Cluster 188 Coalesce 212 Deallocate 213 distinct_keys 633 Fast-Full-Scan 642 Füllgrad 210 global partitioniert 205 global prefixed 207 Index-by-Tabelle 238 Indexed-organized Tables 636 Index-Scan 646 local nonprefixed 206 local prefixed 206 lokal partitioniert 205 merge 197 Monitoring 213 nonprefixed 205 Online Rebuild 23, 820 Online-Aufbau 211 Parallelisierung 210 prefixed 205 RANGE SCAN 625 REBUILD 826 Rebuild 212, 820 REVERSE 638 Reverse Key 210, 637 ROWID 625 Unique 195 UNUSABLE 841 zusammengesetzt 634 Indexkomprimierung 209 Index-organisierte Tabelle siehe IOT Indexreorganisation 212
891 Indextiefe 820, 826 Indirektes Recht 225 Indizierte Funktion 203 init.ora siehe SPFILE INITCAP 359 Initialisierungsparameter max_dump_file_size 340 Inkrementelles Backup differenziell 514 kumulativ 514 INSERT ALL 847 Installation 31 32-Bit 40 64-Bit 40 Basis-Installation 32 Beispielschemata 47 Betriebssystem 35–36 Cluster Ready Services 47, 65 Clusterware 46, 719 Companion CD 46 Data Dictionary 79 Datenbank-Software 46 Enterprise-Edition 55 Hardware 35 Hauptspeicher 36, 73 HTML DB 47 HTTP-Server 47 Instant Client 47 JDBC 47 Legato Single Server 47 Linux 42 MS Windows 40 Nachinstallation 81 OCCI 47 OCI 47 ODBC 47 Oracle Net 47 Oracle-Client 47 orainstRoot.sh 60, 65 OS-Gruppe 56 Patch 66 Patch-Set 81 Real Application Cluster 47 Recovery Manager 68 Semaphore 56 Shared Memory 56 Silent 56, 63 skriptbasiert 75 Sprache 48 SQL*Plus 47 Standard Edition 62 Terminalserver 56 Universal Installer 59 Unix 38 Zeichensatz 48, 51 Installationsmedium 46 Instance-Recovery 126
892 Instant Client 47, 316 Instanzwiederherstellung 506 INSTEAD OF-Trigger 227 INSTEAD-OF-Trigger 231 Interim-Patch 81, 83 Internet Directory 395 Interprozess-Kommunikation 232 Intersection-Tabelle 184 INTERVAL 177, 354 invalid_rows 620 invertierte Listen 636 IO-Bandbreite 546, 554 IOT 175, 194, 207 IP-Adresse primäre 65 virtuell 65, 716, 718, 723 ISO/OSI 7-Schichten-Modell 284 Isolation Level 25 iSQL*Plus 276
J J2EE 330 J2SE 330 Java 327 Bytecode 328 driver_type 335 Instanz 327 Klassen 327 Klassenhierarchie 328 Methoden 327 Nachrichten 327 Variablen 327 Vererbung 328 Java Server Pages siehe JSP Java Stored Functions 329 Java Stored Procedure 329, 332 java virtual machine siehe JVM java$class$md5$table 339 java.lang 328 Java-Applet 329, 333 javac 337 Java-Intepreter 328 JDBC 328–329 Connection 334 OCI Treiber 333 Server-Side Internal Treiber 333 Server-Side Thin-Treiber 333 Thin Driver 318 Thin Treiber 333 URL 334 JDK 329 Join 180, 643 Hash 239 Merge 239 Nested-Loop 239
Stichwortverzeichnis JSP 329–330 Just in Time 328 JVM 328, 338 user.language 336
K Kardinalität 197, 200, 635 keepalive 316 Keep-Pool 54 Kerberos 20, 384 Kollektion 193 Konstruktor 191 Konsumentengruppen 476, 482 Kontext-Switch 232, 239 Kontrolldatei 54, 100, 131, 139, 149 Spiegelung 132 Standby-Datenbank 737 Konzeptionelles Datenmodell 175 Kosten 198 KPRB siehe JDBC Server-Side Internal Treiber
L Label 462, 464 Compartment 464 def_level 470 Group 464 label_tag 469 Level 464 max_level 470 min_level 470 Label Security 463 Label security 20, 365 label_to_char 472 Label-Bezeichner siehe label_tag Längensemantik 358 LANGUAGE JAVA 340 Lastverteilung Shareplex 801 Latch-Contention 109 LD_LIBRARY_PATH 316 LDAP 319, 365, 395 Distinguished Name 320 Oracle Context 320 LDAP over SSL 334 ldap.ora 320, 409–410, 419 LDAP-Server 400 leaf node 196 Leaf-Block 638 Legato Networker 511 Legato Single Server 47 Lesekonsistenz 22, 25, 117–118, 239, 603, 611 LGWR-Prozess 145 Library Cache 234, 808 lightweight session 388
Stichwortverzeichnis Listener 284, 672 ADMIN_RESTRICTIONS_ 372 envs 373 Konfiguration 370 Logging 372 SID_LIST_LISTENER 857 TCP.EXCLUDED_NODES 373 TCP.INVITED_NODES 373 TCP.VALIDNODE_CHECKING 373 Listener Load Balancing 729 listener.ora 286, 415 Listener-Konfiguration 290 List-Partitioning 182 Literale 628 Lizenzierung 35 loadjava 337–338 Locally Managed Tablespace 107, 115, 153 Locator 195 Lock Escalation 24 lock siehe Sperre LOGFILE GROUP 128 LOGFILE MEMBER 128 logical_reads_per_call 473 logical_reads_per_session 473 LogMiner 558 Online Dictionary 558 Redolog Dictionary 559 Log-Switch 809, 815 Logwriter siehe LGWR-Prozess Lokale Benennung 294 LONG 178 LONG- nach LOB-Migration 557 LONG RAW 178 LOWER 359 LRU-Verwaltung 648 lsnrctl 287, 343, 370
M Maintenance-Release 16 mandatory access control 462 Maskierung 174 Master-Slave-Replikation 242 Materialized View 220, 229, 646, 868 ON COMMIT 872 ON DEMAND 872 Refresh 229 Refresh Complete 872 Refresh Fast 872 Refresh Force 872 M-Code 233 Media Management Library 511 Media Management-Software 532 Media-Recovery 123, 859 Medienfehler 507 Mehrprozessor 854 Member 140
893 member functions siehe Objekttypen Merge 844 Merge Join 621, 643, 645 Meta-Daten 123 Metrik 577 Microsoft Access 848 Migrated Rows 820 Migration Betriebssystem 37 Shareplex 804 Zeichensatz 48, 51 MINIMUM SIZE 154 mkstore 422 Modify-Partition 864 Monitoring 807 Aktive Sessions 817 Archived Logs 814 CPU-Auslastung 817 Datendatei 811 Dictionary Managed Tablespaces 813 Ereignis 808 Extent 812 Filesystem 814 Freiplatz 811 Füllgrad 812 Log-Switch 815 Metrik 810 Online 808, 816 Oracle Enterprise Manager 810 Tablespace 811 Top-Sessions 817 Top-SQL 817 Monitoring-Software 808 Move Tablespace 821, 827 MS-Windows Dienst 41 Oracle-Threads 41 Task-Manager 41 Multi-Byte-Zeichensatz 357 Multi-Master-Replikation 242 MULTISET-Operator 231 Multi-Table Insert 846 MView-Advisor 229
N Named Pipes 557 Namenskonvention 173 names.directory_path 411 NATIONAL CHARACTER SET 176, 348 National Language Support siehe Globalization Support Native Compilation 240 NCHAR 176 NCLOB 177, 358 Nested Loop 621 Nested Tabelle 238
894 Nested Table 175, 194 Net Configuration Assistant 406 Net Foundation Layer 284 Net Manager 301 Net8 16 Net-Aliasname 288 netca 290 netmgr 301 netstat 325 Network Applicance 138 newfs 144 nid 97 NLS_INITCAP 359 NLS_LANG 347, 349, 359, 548 NLS_LOWER 359 nls_session_parameters 350 NLS_SORT 354 NLS_UPPER 359 NOAUDIT 486 NOCACHE 648 NOLOGGING 734, 824, 858 nonpopular values 634 num_buckets 634 NVARCHAR 176, 178 NVARCHAR2 176
O Object-View 230 Objekt-Auditing 488 Objektbezeichner 175 Objekt-Identifier siehe Objektbezeichner Objektprivilegien 436 Objektrelational 190 Objekttabelle 175, 192, 230 Gültigkeitsbereich 193 Objekttyp 190, 230 OC4J 330 OCFS 145, 855 OCI Connection Pool 389 ocss 170 oemapp 406 Offline-Sicherung 525, 567 OID Control Utility 402 OID siehe Oracle Internet Directory oidadmin 406 oidca 409 OID-Monitor 401 OJSP 330 ol$ 628 ol$hints 628 ol$nodes 628 OLAP 20, 43–44, 835 OLE DB 848 OLTP 43–44 OMF 149 One-Off-Patch 81
Stichwortverzeichnis Online Reorganisation 20 Online Sicherung 569 opatch 83 opm 458 opmnctl 263, 405 OPS 16 Optimierung 240 Optimizer 180, 196, 228–229, 609 Hint 638 kostenbasiert 609, 633 ORA_DBA 287 ORA_SDTZ 353 ORA_TZFILE 353 Oracle Application Server 21, 319, 322 Oracle Call Interface 284 Oracle Cluster Filesystem 717 Oracle Cluster Filesystem siehe OCFS Oracle Cluster Synchronization Service Daemon siehe OCSS Oracle Clusterware 715 Oracle Collaboration Suite 21 Oracle Containers for Java siehe OC4J Oracle Database Configuration Assistant 419 Oracle Database Lite 21 Oracle Directory Manager 406, 427 Oracle Enterprise Manager 245 ADDM 250 Administration 262 Agent-Installation 261 Alarm 810 Alert-Datei 810 Anmeldung 250 Aufruf 248, 260 Browser Konfiguration 246 Database Configuration Pack 251 Database Control 245, 247 Database Diagnostic Pack 250, 255–256 Database Tuning Pack 251 Diagnostic Package 817 Grid Control 48, 245, 257 Installation 258 Konfiguration 247 Löschen 249 Management Packs 250 Metrik 811 Optionen 250 Packages 260 Ports 249 Repository 248–249, 259 Schwellenwerte 256 Spracheinstellung 246 Starten 263 Stoppen 263 SYSMAN 247 Oracle Flexible Architecture 57 Oracle Internet Configuration Assistant 409
Stichwortverzeichnis Oracle Internet Directory 396, 400, 402 Oracle Managed Files 54, 70, 104, 137, 140 Oracle Names 317, 408 Oracle NET sqlnet. crypto_checksum_types_server 375 sqlnet.authentication_services 384 sqlnet.crypto_checksum_client 375 sqlnet.crypto_checksum_server 375 sqlnet.crypto_checksum_types_client 375 sqlnet.crypto_seed 375 sqlnet.encryption_client 375 sqlnet.encryption_server 375 sqlnet.encryption_types_client 375 sqlnet.encryption_types_server 375 ssl_cipher_suites 416 ssl_version 416 Oracle Net 16, 281, 347, 355 cman.ora 323 CONNECT_DATA 314 Dienstnamen 282 Easy Connect 317 EZCONNECT 318 FAILOVER 313 FAILOVER_MODE 314 Hostnaming 317 Instant Client 281 LOAD_BALANCE 313 maximum segment size 315 NAMES.DIRECTORY_PATH 318, 321 Netzwerkname 282 Port 287 RULE_LIST 323 SDU 315 SERVICE_NAME 313 SQLNET.AUTHENTICATION_SERVICES 145, 286 SQLNET.EXPIRE_TIME 316 TRACE_DIRECTORY_CLIENT 326 TRACE_LEVEL_CLIENT 326 USE_DEDICATED_SERVER 312 Oracle Net Configurations Assistant 290 Oracle Net Manager 410, 414 Oracle Policy Manager 458, 463 Oracle Program Interface 284 Oracle Servlet Engine 330 Oracle Streams 785 Aktivierung 793 Apply-Prozess 785 Architektur 785 bidirektional 794 Capture-Prozess 785 Capture-Regel 790 Deaktivierung 799 Downstream Capture 787 Initialbefüllung 792
895 Instantiation SCN 787, 792 Konfliktlösung 796 Logical Change Record 785 Message Handler 785 Monitoring 794 Propagation-Prozess 785 Propagation-Regel 790 Queues 785 Replikationsregel 786 Schema-Regel 790 Schemareplikation 788 Serverparameter 788 Supplemental Logging 788 Synchronisierung 787 Transformation 787 Voraussetzungen 788 Oracle Transparent Gateways 848 Oracle Wallet Manager 408, 412 Oracle Warehouse Builder 835 Oracle Server 15 oracle.jdbc 334 oracle.jdbc.pool 334 ORACLE_BASE 31 ORACLE_HOME 31, 111 ORACLE_HOME_NAME 31 ORACLE_SID 31, 96, 99, 145 Oracle-Block 179 Oracle-Client 47 oraclecsservice 33 OracleDataSource 334 OracleDBConsole 248 Oracle-Inventory 59 OracleJobScheduler 269 Oracle-Loader 647 oradebug 698 oraenv 262 oraInst.loc 60 orainstRoot.sh 722 orapwd 391 oratab 60, 262 OS_ROLES 445 OSDBA 390 OSE 330 OSOPER 390 Outlines Private 629 OUTLN 628 owm 422
P Package dbms_advisor 874 dbms_application_info 685 dbms_apply_adm 793 dbms_capture_adm 793, 795
896 dbms_crypto 235 dbms_debug 233 dbms_defer_query 774 dbms_defer_sys 769, 776 dbms_fga 489 dbms_file_transfer 242, 838 dbms_flashback 795 dbms_job 264, 785 dbms_lob 177 dbms_logmnr_d 558 dbms_monitor 687, 697, 816 dbms_mview 870, 872 dbms_obfuscation_toolkit 235 dbms_offline_og 783 dbms_olap 876 dbms_profiler 239 dbms_redefinition 829 dbms_redefnition 154 dbms_repair 688–689 dbms_repcat 768, 771, 773, 778 dbms_repcat_admin 769 dbms_reputil 768, 776, 781 dbms_resource_manager 478–479, 483 dbms_resource_manager_privs 478 dbms_rls 454 dbms_scheduler 269, 271 dbms_server_alert 685 dbms_service 282, 313 dbms_session 442, 685 dbms_space_admin 154 dbms_sqltune 875 dbms_streams_adm 790, 794, 799 dbms_support 697 dbms_system 697 dbms_transaction 763 dbms_tts 837 dbms_utility 436 dbms_workload_repository 683–684, 875 sa_components 468 sa_label_admin 469 sa_policy_admin 469 sa_session 472 sa_sysdba 467 sa_user_admin 470–472 utl_file 242 Papierkorb 564 PARALLEL 644, 824 Parallele Abfragen 883 Paralleles Laden 843 Parallelisierung 842 Parameterdatei 100, 149, 544, 552 PARSE 611 Parse Call 587 Parsing 609
Stichwortverzeichnis PARTITION SPLIT 860 Partition 175, 645 Composite 863 Elimiation 860 Exchange 841, 860 Hash 861 List 863 MAXVALUE 861 Partitioning 20 Index 204 Pruning 859 Range 181, 207, 859 Partitioned Fine Grain Access Control siehe Virtual Private Database Partitionierte Tabelle 180 Partitionierung 838, 859 Passwortdatei 101 Patch 16 Patchset 16, 81 PCTFREE 107–108, 820 PCTUSED 107–108, 820 Performance 239, 808 PERFSTAT siehe Statspack PFILE siehe SPFILE PGA 581 Physikalisches Modell 175, 195 Pinging 713 PL/SQL 232 AUTHID CURRENT_USER 387 clear_pending_area 479 create_policy 467 dba_sa_goups 468 externe Prozeduraufrufe 373 submit_pending_area 479 validate_pendig_area 479 PL/SQL-Engine 233 PL/SQL-Index-by-Tabellen 334 PL/SQL-Profiler 239 PL/SQL-Tabelle 238 Plan Stability 628 plan_table 624 Platzbedarf 807 PLUSTRACE 624 PMON 160 Point-in-Time-Recovery 123 policy 448, 462–463, 467 policy group 449 policy_type 460 Polymorphie 190 popular values 634 portlist.ini 34, 249 Post-Wait-Treiber 39 Precompiler 232 Primärschlüssel 213, 215
Stichwortverzeichnis Privileg 29 ADVISOR 874 CREATE ANY DIRECTORY 244 DEBUG ANY PROCEDURE 234 DEBUG CONNECT SESSION 234 EXECUTE ANY PROCEDURE 234 Privilegien-Auditing 488 Profil 301, 473 Profile composite_limit 474 connect_time 474 cpu_per_call 473 cpu_per_session 473 failed_login_attempts 475 idle_time 474 password_grace_time 475 password_lifetime 475 password_lock_time 475 password_reuse_max 475 password_reuse_time 475 password_verify_function 475 private_sga 474 resource_limit 473 session_per_user 473 Protocol Support 284 Proxy Authentication 377, 385 Proxy-Authentication 380, 385 Proxyserver 323 Public Key-Kryptografie 407 PUBLIC-Benutzer 436 Publishing 340
Q Query Rewrite 204, 220, 229, 869, 874 Query Server 645 Quoten 392
R RAC siehe Real Application Clusters RADIUS 384 Radius 20 RAID-System 710 Raid 0 102 Raid 1 102 Raid-0 853 Raid-1 853 Raid-5 102 Raid-S 102 range scan 197 RAW 177 Raw Device 69, 138, 143–144, 717, 840, 855 RBO 609 RDBMS 15 Read Committed 25 Read Only 26
897 READ_CONTROL 463 Real Application Clusters 20, 713, 842, 854 Administration 728 Cluster Ready Service 716, 719 Cluster Synchronisation Service 716 Datenbankerstellung 724 Event Manager 716 Hauptspeicher 716 Installation 718 IP-Adresse 718 Serverparameter 726 srvctl 728 Voraussetzungen 718 Zertifizierung 716 RECOVER DATABASE 529 Recovery 256 Cross Instance 78 vollständig 510 Recovery Manager 510 ALLOCATE CHANNEL 518 Auxiliary-Verbindung 737 BACKUP DATABASE PLUS ARCHIVELOG siehe Automatische Kontrolldateisicherung BACKUP-Kommando 513 Berichte 531 BLOCKRECOVER 530 Channel 517 CONFIGURE 517 CONTROLFILE AUTOBACKUP siehe Automatische Kontrolldateisicherung Crosscheck 814 Datenbank-ID 518 DEFAULT DEVICE 517 Disk 517 DUPLICATE 525 Duplicate 519 FOR RECOVER OF COPY 515 Format 518 Full Backup 514 Inkrementelles Backup 514 LIST 531 MAXPIECESIZE 519 Parallelisierung 517 REGISTER DATABASE 520 REPORT 531 RESTORE 527 SBT 517 SHOW ALL 522 Tape 517 Target 512 Recovery Manager Repository siehe RecoveryKatalog Recovery-Katalog 519 Recovery-Set 123
898 Recyclebin 510, 564 Recycle-Pool 54 Redirect 286 Redo Buffer 808 Redo-Information 124 Redolog Member 126 Redolog-Datei 54, 100, 124, 139, 149 Spiegelung 78 Redolog-Gruppen 125 Redolog-Thread 137 Redolog-Transport asynchron 740 synchron 740 Redundanz 148 Referenztabelle 184 REF-Operator 193 relative distinguished name 400 Releasewechsel 83 Reorganisation 154, 179, 218, 256, 551, 807, 819 COPY Table 826 CTAS 824 DDL-Skript 823 Export/Import 821–822 Index 820 Index Rebuild 826–827 indexorganisierte Tabelle 827 Indextiefe 826 LONG-Spalte 823, 826–827 Move Tablespace 827 Online 821, 829 Oracle Enterprise Manager 831 Scratch Tablespace 831 Shrink Space 821, 827–828 Tabelle 821 Replikation 242 Advanced Replication 759 asynchron 765, 800 bidirektional 794 Deferred Transaction 766 Deferred Transaction Queue 768 Fehlerwarteschlange 776 Instantiierung 782 Kapazitätsplanung 784 Konflikt 775 Konfliktlösung 780, 796 Master Definition Site 766 Master Site 764, 772 Multi Master 764 Oracle Streams 785 Propagator 769 Receiver 769 Redo-Log-basiert 800 Replikationsadministrator 769 Replikationsgruppe 764, 771 Scheduled Link 770
Stichwortverzeichnis Schema 788 Shareplex 800 Spaltengruppe 777 synchron 765 Request Queue 307 Resolving 338 Response File 63 Response Queue 307 Ressourcen-Engpass 807 Ressourcenpläne 476 RESTORE DATABASE 529, 531 RESTRICTED SESSION 305 Resumable 850 retention period 677 Retention Policiy 532 REVOKE 436–437 rman 136, 510 BACKUP AS COPY 840 CONVERT DATAFILE 839 Roll Forward Phase 506 ROLLBACK 22, 116 Rollback Phase 506 Rollback-Segmente 52 Rolle 225, 438 EXP_FULL_DATABASE 543, 551 externe 444 globale 396, 426, 444 IMP_FULL_DATABASE 543 vordefinierte 438 Rolling Upgrade 718, 731, 743 Rolling Window 181, 859–860 ROLLUP 877 root block 197 Row Directory 24 Row Label 462 Row Movement 563, 828 row object siehe Zeilenobjekte row_level 470 rowid 179, 197, 209 Rücksicherung und Wiederherstellung 527 RUN-Block 510
S SAME-Architektur 711 Satzverkettung 820 Scheduled Link 760, 770 Scheduler 259, 264, 267 Attribute 271 Berechtigung 273 extjob 269 Fehlerbehandlung 272 Fenster 273 Fenstergruppe 273 Intervall 270 Job 271
Stichwortverzeichnis Jobklasse 272 Job-Verknüpfung 274 Logging 272 Migration 274 Programme 269 repeat_interval 270 Retry 272 Run 272 Schedule 270 Windows-Dienst 269 Schwellenwert 807 SCOPE 193 Secure Application Role 377, 441 Secure Sockets Layer siehe SSL Security Alerts 369 Segment 197 SEGMENT SPACE MANAGEMENT siehe ASSM Sekundärschlüssel 214 SELECT FOR UPDATE 211 select_catalog_role 112 Semaphore 39, 56 Sequenz 210 serial# 594 Serializable 25 server generated alerts 677, 685 Serverparameter 140 __db_cache_size 170 __shared_pool_size 170 _addm_auto_enable 591 _awr_restrict_mode 588 _dml_monitoring_enabled 616 _memory_broker_shrink_heaps 169 _memory_broker_stat_interval 169 aq_tm_processes 259 archive_lag_target 735 asm_disk_string 148 asm_diskgroups 146, 171 asm_diskstring 171 audit_file_dest 485 audit_sys_operations 485 audit_trail 486 background_dump_dest 171, 668, 809 bitmap_merge_area_size 636 cluster_database 97 commit_point_strength 762 compatible 52, 90, 93, 528, 768 control files 54 control_files 132, 134, 158, 528 controlfile_record_keep_time 532 core_dump_dest 171, 668 cpu_count 884 create_bitmap_area_size 199, 636 cursor_sharing 628, 632 db_block_buffers 53 db_block_checking 693
899 db_block_checksum. 693 db_block_size 50 db_cache_size 51, 53, 106, 168–169 db_create_file_dest 55, 104, 140, 526 db_create_online_log_dest_ 140 db_create_online_log_dest_n 55, 134 db_domain 51, 96 db_file_multiblock_read_count 621–622, 884 db_file_name_convert 735 db_file_recovery_dest 536 db_file_recovery_dest_size 536 db_flashback_retention_target 536 db_name 51, 96, 528, 749 db_nk_cache_size 51, 53, 106 db_recovery_file_dest 140, 502 db_recovery_file_dest_size 502, 814 db_unique_name 98, 140, 735 deprecated 90 dispatchers 308, 343 pool 309 ticks 310 event 696 fal_client 735 fal_server 735 fast_start_io_target 127 fast_start_mttr_target 128, 167 global_names 96, 759, 761, 768 hash_area_size 621, 644 hs_db_domain 849 hs_db_name 849 hs_fds_connect_info 849 hs_language 850 instance_name 283, 597, 727, 856 instance_number 727 instance_type 146, 151, 171 java_max_sessionspace_size 331 java_pool_size 331 java_soft_sessionspace_limit 331 job_queue_processes 266, 268, 768, 788 large_pool_size 171 ldap_directory_access 421 local_listener 288, 309, 729 log_archive_config 735 log_archive_dest_n 735 log_archive_format 139 log_archive_log_dest 508 log_archive_trace 668 log_checkpoint_interval 127, 131, 167 log_checkpoint_timeout 127, 131, 167 log_file_name_convert 735 max_dump_file_size 599, 668 max_enabled_roles 446 max_shared_servers 308 mts_max_dispatchers 309
900 nls_calendar 352 nls_currency 355 nls_date_format 351 nls_date_language 351 nls_dual_currency 355 nls_language 350 nls_length_semantics 358 nls_numeric_characters 355 nls_territory 350 nls_timestamp_format 353 nls_timestamp_tz_format 353 o7_dictionary_accessibility 430 obsolet 90 open_cursors 610 open_links 768 optimizer_mode 632 os_authent_prefix 383–384 parallel_automatic_tuning 884 parallel_max_servers 211, 768, 842, 884 parallel_min_percent 884 parallel_min_servers 211, 768, 842, 884 pga_aggregate_target 114, 199, 238, 581, 621, 628, 636, 824, 826, 842 plsql_code_type 241 plsql_compiler_flags 241 plsql_debug 241 plsql_native_library_dir 241 plsql_optimize_level 240 processes 308 query_reqwrite_enabled 204 query_rewrite_enabled 874 query_rewrite_integrity 874 remote_listener 324, 729, 856 remote_login_passwordfile 171, 390–391, 513, 734 remote_os_authent 383 replication_dependency_tracking 768 resource_manager_plan 483 service_name 856 service_names 96, 99, 282, 313, 735 session_cached_cursors 259 sessions_current 393 sessions_highwater 393 sessions_max 393 sessions_warning 393 sga_max_size 53, 167–168 sga_target 53, 168, 582 shared_pool_size 54, 168–169, 259, 331 shared_server_sessions 310 shared_servers 308 sort_area_size 114, 238, 621, 824, 826, 842 sql_trace 817 standby_archive_dest 735 standby_file_management 735 statistics_level 53, 588, 616, 852 streams_pool_size 788
Stichwortverzeichnis thread 727 timed_os_statistics 578, 580 timed_statistics 577, 852 tracefile_identifier 595 undo_management 52, 117, 120, 155 undo_retention 117–118, 120, 155, 561 undo_suppress_errors 121 undo_tablespace 52, 155 user_dump_dest 171, 340, 461, 599, 668 utl_file_dir 244 workarea_size_policy 199, 824, 842 service registration 288, 324 Session 577 session data unit 315 session label 464 Session Multiplexing 323, 325 Session-Label 462, 465 sessiontimezone 353 SET ROLE 440–441 SET TRANSACTION READ ONLY 239 SET TIME_ZONE 352 SGA 125, 144, 583 SGA-Verwaltung 168 Share Lock 217 Shared Library 241 Shared Memory 39, 56 Shared Modus 855 Shared Pool 54, 610 Shared Schema 377–378, 396–397, 417, 425 Shared Server 283, 306, 311, 326, 343, 636 SharePlex 154 Aktivieren 803 Initialbefüllung 803 Prozesse 800 SHRINK SPACE 821, 827–828 Shutdown 157, 160 ABORT 161 IMMEDIATE 160 NORMAL 160 TRANSACTIONAL 161 Sicherheit covert disclosure 364 data privacy 374 least privilege 365 masquerading 365 Passwort 366, 381 Patch 369 privacy 364 spoofing 365, 373 Standardbenutzer 393 Sicherung siehe Backup Sicherungsverfahren 514 sid 594 SID-Liste 306 Silent Installation 56, 63 Simulation 628
Stichwortverzeichnis Single Sign On 20, 378, 384–385, 395 Skip-Scan 197 Skript catalog.sql 79, 111 catpatch.sql 82 catproc.sql 79 catqm.sql 342 catxdbj.sql 342 csalter.plb 359 csminst.sql 361 dropjava 337–338 glogin.sql 275 login.sql 275 profload.sql 240 proftab.sql 240 root.sh 65 utlexcpt.sql 220 utlxmv.sql 870 SMON 125 SMP siehe Multiprozessor Snapshot-Controlfile 512 Snapshots 584 Snowflake-Schema 835, 880 Sort Area 114 sort_area_size 556 space pressure 117 Spaltenobjekte 191 Spatial 20 spauto siehe statspack Speicherbedarf 198 Speicherverwaltung dynamisch 53 Sperre 23, 198, 211, 818 Breakable Parse Lock 23 DDL 23 DML 23 Exclusive 211 Konflikt 636 Row Exclusive 211 Row Share 24, 211 Row-Exclusive 24 Share 24 Share Mode 211 Share Row Exclusive 24, 211 SPFILE 164, 529 Spiegelung 710 spnc_commands 241 spreport siehe statspack SQL 15 Statisch 610 SQL 2003 15 SQL*Loader 188, 242, 356, 843 Direct Path 843 NOLOGGING 843 SQL*Net 16
901 SQL*Plus 275, 356 Konfiguration 275 sql_trace 594, 599 SQL-Befehl rekursiv 610 SQLJ 328, 330 sqlnet.ora 145, 286, 415–416 SQLPATH 275 SQL-Profile 655 SQL-Tracing 240, 593–594 SQL-Tuning-Set 875 srvctl 728 SSL 395, 407, 415 SSL-Protokoll 378, 411 stamp 146 Standby-Datenbank 730 Logical Standby 742 Physical Standby 732 Standard-Edition 730 Standby-Redo-Log-Dateien 733, 741 Starschema 835, 880 STARTUP 157 DOWNGRADE-Klausel 93 FORCE 159 MIGRATE-Klausel 82, 94 MOUNT 158 NOMOUNT 158 OPEN 159 OPEN READ ONLY 159 RESTRICTED 159 UPGRADE 114 UPGRADE-Klausel 91 Startup-Befehl 158 Statistik 196, 576, 614 Statistik-Information 615 Statspack 576, 584 Stored Outlines 628–629 export und import 631 Stripe and Mirror Everything siehe SAME Stripe-Set 711 Striping 621, 711 Strukturänderungen 131 Summary Advisor 875 Summery Advisor 875 Supplemental Logging 743, 788 Überprüfung 792 Suspend 851 SYS_CONTEXT 442, 453 sys_context 350, 386 sys_journal siehe Journaltabelle SYSAUX DATAFILE 114 SYSAUX-Tablespace 247, 587 SYSDBA 157, 390–391, 485 SYSOPER 390–391, 485 System Change Number 611
902 system.err 340 system.out 340 Systemabsturz 506 Systemprivileg 430 ANALYZE ANY 435 CREATE SESSION 385, 423, 435 CREATE USER 379 exempt access policy 451, 460 grant any object privilege 462 Read 467 Writedown 467 WRITEUP 467, 471 Systemstatistik 616
T Tabelle 175 Sortierung 820 Tabellencluster 642 Table COMPRESS 637 Tablefunction 236 TABLESPACE GROUP 116 Tablespace 152, 814 AUTOEXTEND 106, 143–144, 811 BIGFILE 105 BLOCKSIZE 106 erstellen 103 EXTENT MANAGEMENT 107 Fragmentierung 819 Layout 857 LOGGING 106 Offline 122 Read-Only 122 SMALLFILE 105 SYSAUX 78, 109, 114 SYSTEM 78, 109 Tablespace-Point-in-Time-Recovery siehe TSPITR TAF siehe Transparent Application Failover TCPS-Protokoll 414 Template 150 Temporärdatei 100, 149 Temporärsegment 115, 880 Temporary Table 175, 184, 224 Temporary Tablespace 114, 621 Temporary Tablespace Group 116 TEMPORARY TABLESPACE-Klausel 392 Thin JDBC 284 thread safe 329 TIMESTAMP 177, 353 TIMESTAMP WITH LOCAL TIME ZONE 352 timezlrg.dat 353 TIMEZONE 352 timezone.dat 353
Stichwortverzeichnis TKPROF 600, 603, 623, 701 TNS_ADMIN 286 tnsnames.ora 289, 415–416 tnsping 318 TOAD 275–276, 815, 821 Top-5-Liste 586 Top-Sessions 817 Top-SQL 817 Trace-Datei 600, 661, 668 tracefile_identifier 668 Tracing 623, 816 Tranparent Gateway 836 Transaction-Lock 669 Transaktion 22 Redo 558 Undo 558 verteilt 761, 763 verzögert 766 Transaktionseintrag 50 Transaktionsprotokoll 124 Transformation 836 Transparent Application Failover 312, 334 Transparent Gateway 850 Transparent Network Substrate 284 Transportable Tablespace 19, 355, 837 TRCA 604 trcsess 599 Trigger 241, 604 autonom 237 intern 772 Troubleshooting 28, 573, 661 Dump 662 hang 661 Loop 662 TRUNCATE 153 Trust Points 407 Trusted Oracle siehe Label Security Tuning 29, 228, 573 Tuning Pack 20 Two Task Common 284 Two-Phase-Commit 761
U Überwachung 807 UNARCHIVED 129 UNDO RETENTION GUARANTEE 121 Undo-Segment 116 Undo-Tablespace 52, 116, 155, 561 RETENTION GUARANTEE 561 Undo-Verwaltung 52, 155 UNICODE 357 uniqueness 636 Universal Installer 59 UNRECOVERABLE 531 UPDATE GLOBAL INDEXES 841
Stichwortverzeichnis Upgrade Data Dictionary 92 Data Guard 88 Fallback 93 Real Application Cluster 85 Silent Installation 88 skriptbasiert 88 SYSAUX-Tablespace 91 Überprüfung 92 Voraussetzungen 88 Zurückrollen 85 UPPER 359 UROWID 178 US7ASCII 355 USE_SHARED_SOCKET 326 user label 464 user-defined Datatypes siehe Objekttypen users_max 393 USING INDEX 215, 219 UTF-16 335 UTF-8 357 UTF8 176 UTFE 357
V V$-Tabelle 583–584, 816 V$-View siehe V$Tabelle VALIDATE BACKUPSET 532 VALIDATE STRUCTURE 212 VARCHAR 176, 178 VARCHAR2 176 Varray 193 Verdichtung 868 Vererbung 190 Verschlüsselung 374 DES-Verfahren 376 Versionsnummer 16 Verzeichnisdienst 320, 396, 399 View 223 all_arguments 233 all_repcatlog 780 all_repcolumn_group 780 all_repgrouped_column 780 all_represolution 781 all_repsites 774 all_sa_user_labels 472 all_sa_users 472 all_services 283 all_tables 112 all_users 382 CREATE FORCE 229 dba_2pc_pending 763 dba_application_roles 441 dba_apply_error 794 dba_capture 796
903 dba_capture_prepared_tables 794 dba_cons_columns 222 dba_constraints 222 dba_context 460 dba_data_files 112, 150, 688, 811 dba_directories 244 dba_enabled_traces 598, 687 dba_feature_usage_statistics 694 dba_free_space 811 dba_global_context 460 dba_high_water_mark_statistics 694 dba_hist_active_sess_history 684 dba_hist_database_instance 589 dba_hist_sessmetric_history 684 dba_hist_snapshot 588–589, 684 dba_hist_sql_plan 627, 684 dba_hist_sqlbind 684 dba_hist_sqlstat 684 dba_hist_sqltext 627 dba_hist_sys_time_model 684 dba_hist_undostat 684 dba_hist_wr_control 588, 683 dba_indexes 636 dba_instantiated_objects 794 dba_jobs 265 dba_logstdby_not_unique 745 dba_logstdby_progress 751 dba_logstdby_unsupported 743 dba_mview_refresh_times 873 dba_obj_audit_opts 489 dba_objects 233 dba_plsql_object_settings 241 dba_policies 460 dba_policy_contexts 460 dba_policy_groups 460 dba_priv_audit_opts 488 dba_profiles 475 dba_registry 331, 342 dba_repgenobjects 773 dba_repobject 772 dba_resumable 851 dba_role_privs 446 dba_roles 440 dba_rollback_segs 121 dba_rsrc_consumer_groups 480 dba_rsrc_plan_directives 482 dba_rsrc_plans 480 dba_rule_set_rules 796 dba_rules 796 dba_rulesets 796 dba_sa_labels 469 dba_sa_policies 467 dba_scheduler_job_log 272 dba_scheduler_job_run_details 272 dba_scheduler_programs 269
904 dba_scheduler_schedules 270 dba_segments 121 dba_services 283 dba_source 233 dba_stmt_audit_opts 488 dba_sys_privs 436, 440 dba_tab_modifications 616 dba_tab_privs 437, 440 dba_tablespace_groups 116 dba_tablespaces 119, 121 dba_thresholds 685 dba_trigger_cols 242 dba_triggers 242 dba_ts_quotas 392 dba_undo_extents 121 dba_users 382, 475 defcall 773 deftran 773 global_name 97, 417 index_stats 212 mv_capabilities_table 870 path_view 341 plsql_profiler_data 240 plsql_profiler_runs 240 plsql_profiler_units 240 procedurejava$ 340 resource_view 341 session_privs 440 session_roles 440 sys$background 597 sys$users 597 SYS.NCOMP_DLL$ 241 system_privilege_map 488 transport_set_violations 837 user_ind_columns 203–204, 209–210 user_ind_expressions 204 user_ind_partitions 208 user_ind_subpartitions 209 user_indexes 203–204, 208, 210 user_log_groups 792 user_part_indexes 208 user_role_privs 440 user_tables 113 user_users 382 v$active_services 283 v$active_session_history 683 v$archive_dest_status 742 v$archived_logs 131 v$asm_alias 150 v$asm_diskgroup 150 v$asm_file 150 v$backup 131 v$backup_corruption 530 v$backup_datafile 137 v$block_change_tracking 137
Stichwortverzeichnis v$circuit 311 v$context 460 v$controlfile 131, 134, 150, 567 v$database 131, 589 v$datafile 111, 131, 505, 567 v$db_cache_advice 168 v$dispatcher 311 v$dispatcher_config 309 v$event_histogram 682 v$event_name 577, 579, 678 v$eventmetric 577, 579, 682 v$file_histogram 682 v$filemetric 682 v$filemetric_history 683 v$globalcontext 460 v$instance 589 v$java_pool_advice 168, 581 v$latchname 580 v$license 393 v$log 129, 131 v$log_history 131 v$logfile 128, 130–131, 567 v$loghist 130 v$loghistory 130 v$logstdby 751 v$metric 682 v$metricgroup 577, 579, 681–682 v$metricname 577, 579, 681 v$object_usage 213 v$osstat 679 v$parameter 164 v$pga_target_advice_histogram 581 v$pwfile_users 391 v$recover_file 505 v$rollname 121 v$rollstat 121 v$rsrc_consumer_group 484 v$rsrc_plan 483 v$segstat 579 v$segstat_name 580 v$servicemetric 682 v$servicemetric_history 683 v$services 283 v$ses_optimizer_env 622 v$sess_time_model 679 v$session 310, 389, 594, 678, 816 v$session_event 577, 678 v$session_longops 838, 851 v$session_wait 666, 678 v$session_wait_history 683 v$sessmetric 577, 682 v$sesstat 579, 678 v$sga_dynamic_components 170 v$sga_resize_ops 170 v$sgainfo 167
Stichwortverzeichnis v$sgastat 331 v$shared_pool_advice 168 v$shared_server 311 v$sql 235, 680, 687 v$sql_bind_capture 681 v$sql_plan 681 v$sql_plan_statistics 681 v$sql_plan_statistics_all 627 v$sql_text 680 v$sqlarea 680, 687, 816 v$standby_log 742 V$STATNAME 580 v$statname 678 v$sys_time_model 679 v$sysaux_occupants 114, 589 v$sysmetric 577, 682 v$sysmetric_history 683 v$sysstat 678 v$system_event 678 v$tablespace 131, 505 v$temp_histogram 682 v$tempfile 131 v$timezone_names 353 v$transaction 121, 680 v$transportable_platform 838 v$undostat 122 v$vpd_policy 460 v$waitclassmetric_history 683 v$workarea 681 WITH CHECK OPTION 226 WITH READ ONLY 226 Virtual Private Database 365, 448 Virtuelle IP-Adresse 729 Virtuelle Tabelle 223 Virtuelle View 111 Vollständige Wiederherstellung 505 Voting Disk 720
W WAIT-Events 586 Wallet 411, 416, 419, 422 wallet 378 Wartezustände 198 WebDAV 341, 343 Web-Folder 345
905 Wiederherstellung Archivierte Redo-Log-Dateien 508 Block 529 Data Dictionary 507 Daten-Tablespace 507 Online-Redo-Log-Dateien 508 SYSTEM-Tablespace 507 Undo-Tablespace 507 Verlust der gesamten Datenbank 528 Verlust einer Datendatei 527 Verlust einer Kontrolldatei 527 Verlust eines Tablespaces 527 worst case 508 Wiederherstellungsstrategie 505 WITH ADMIN OPTION 436, 445 WITH-Klausel 879 wrap 235, 443 wrap.exe 235 Wrapper 340 Wrapping 234 write through cache 138 WRITE_CONTROL 463–464
X X$-Tabelle 575 XDB 341 xdbconfig.xml Protokollserver 346 XML 341 FTP 344 HTTP 344–345 Protokollserver 346 WebDAV 345 XML DB 341 XMLTYPE 341
Z Zeichensatz 48, 51, 335, 355 Ersatzzeichen 51 Euro-Symbol 48 Zeilenobjekt 192 Zertifikate, digitale 407, 412 zoneinfo 353 Zugriffskontrollen 377 Zugriffsplan 199
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