DB-ZWO zusammengefasst von Felizitas Ottemeier, Christian Pfeiffer 1 Inhalt 1. DATENBANKEN – WOZU? ............................................................................................... 9 Geschichtliche Entwicklung:................................................................................................................. 9 Einsatzarten: .......................................................................................................................................... 9 Anforderungen seit der relationalen Phase: ...................................................................................... 10 Anforderungen an Relationale Datenbank Management Systeme ................................................. 10 Standardisierungen: ............................................................................................................................ 11 Entwicklungen (RDBMS): .................................................................................................................. 11 Begriffe: ................................................................................................................................................ 12 Retrieval: Wiedergewinnung / Wiederherstellung von Daten ........................................................... 12 2. DATENBANKMODELLE ................................................................................................. 13 Das hierarchische Modell: ................................................................................................................... 13 IMS ........................................................................................................................................................ 14 Die ANSI/SPARC – Architektur: ....................................................................................................... 16 Datenbank – Administrator (DBA) .................................................................................................... 18 Tupel-Identifier .................................................................................................................................... 21 Cluster ................................................................................................................................................... 22 Index ...................................................................................................................................................... 22 Index über Feldkombinationen .......................................................................................................... 23 Pointerketten ...................................................................................................................................... 24 Der Optimierer (Optimizer)................................................................................................................ 26 Datenkompression.............................................................................................................................. 30 Speicherung von Daten (Beispiel: MS SQL Server) ........................................................................ 30 3. RELATIONALE DBMS .................................................................................................... 32 Anforderungen ..................................................................................................................................... 32 Basisregeln ............................................................................................................................................ 33 Strukturregeln: .................................................................................................................................... 34 Manipulationsregeln ............................................................................................................................ 34 2 Integritätsregeln ................................................................................................................................... 35 SQL Standard....................................................................................................................................... 35 Entry-Level, ....................................................................................................................................... 35 Intermediate-Level ............................................................................................................................. 35 Full-Level. .......................................................................................................................................... 35 Aufteilung der Dokumentation: ......................................................................................................... 36 SQL92 ................................................................................................................................................ 36 SQL Standard ..................................................................................................................................... 36 Sprachelemente: ................................................................................................................................. 37 Datenbankstruktur: ............................................................................................................................. 38 Zeichensätze:...................................................................................................................................... 40 Constraints: ........................................................................................................................................ 40 DDL - Data Definition Language: ..................................................................................................... 42 permamente Tabellen (Basis-Tabellen): ............................................................................................ 45 Entzug von Rechten: .......................................................................................................................... 49 DML – Datenretrieval: ....................................................................................................................... 51 DCL - Datenkontrolle ........................................................................................................................ 53 Transaktionen ..................................................................................................................................... 53 Besonderheiten von DB2 ..................................................................................................................... 55 Besonderheiten von Oracle ................................................................................................................. 55 4. SCHNITTSTELLEN.......................................................................................................... 56 Grundlagen:.......................................................................................................................................... 57 Schnittstellen - Cursor-Konzept:........................................................................................................ 57 Schnittstellen – Status: ....................................................................................................................... 60 Schnittstellen - Indikator-Variable:.................................................................................................... 62 Schnittstellen - Module-Schnittstelle: ................................................................................................ 63 Embedded SQL .................................................................................................................................... 65 konkretes Beispiel: ............................................................................................................................. 65 Embedded SQL Beispiel: ................................................................................................................... 65 Aufgaben des Precompilers: .............................................................................................................. 67 Ausnahmebedingungen: ..................................................................................................................... 69 Statische SQL-Anweisungen:.............................................................................................................. 70 Vorteile: ............................................................................................................................................. 70 Dynamisches SQL: ............................................................................................................................... 72 Problem: einmaliger Zugriff oder wiederholter Zugriff?................................................................... 72 CLI: ....................................................................................................................................................... 76 Sprach- und DBMS-unabhängige Schnittstelle von Prozeduraufrufen ............................................. 77 Nachteile gegenüber Embedded SQL: ............................................................................................... 77 Typische Verarbeitung: ...................................................................................................................... 78 Initialisierung: .................................................................................................................................... 78 Noch ein Beispiel: .............................................................................................................................. 79 Transaktionsverarbeitung:.................................................................................................................. 80 Terminierung: .................................................................................................................................... 80 3 Innerhalb der Transaktionsverarbeitung: ........................................................................................... 81 ODBC .................................................................................................................................................... 82 JDBC = Java Data Base Connectivity ................................................................................................ 82 Vorteile Java im Hinblick auf Vereinfachung der Anwendungsentwicklung: .................................. 82 Eigenschaften von Java: ..................................................................................................................... 83 Anbindungsmöglichkeiten an (relationale) Datenbanken:................................................................. 83 JDBC besteht aus Klassen und Interfaces. Die wichtigsten sind: ...................................................... 84 Schritte zur Verbindung JDBC und DB............................................................................................. 84 JDBC 2.0 ............................................................................................................................................... 94 java.sql .................................................................................................................................. 94 javax.sql ............................................................................................................................... 98 OPTIMIERUNG .................................................................................................................. 102 Optimierung eines Knotens ............................................................................................................... 102 Installation des DBMS ..................................................................................................................... 102 Bereitstellung von physischem Speicherplatz ................................................................................. 104 Denormalisierung ............................................................................................................................. 104 Partitionierung von Tabellen............................................................................................................ 105 Clustern ............................................................................................................................................ 105 Indexierung ...................................................................................................................................... 106 Knotenübergreifend ........................................................................................................................... 106 Verteilung ........................................................................................................................................ 106 Replikation ....................................................................................................................................... 107 6. DATENBANKEN ENTWURF ......................................................................................... 108 1. Analyse ............................................................................................................................................ 109 2. Konzeptuelle Phase ........................................................................................................................ 112 Redundanzen und Anomalien: ......................................................................................................... 112 Funktionale Abhängigkeiten: ........................................................................................................... 113 Normalformen: ................................................................................................................................. 114 ER-Modell: ...................................................................................................................................... 117 Objektorientierung ........................................................................................................................... 119 3. Logischer Entwurf ......................................................................................................................... 123 4. physikalischer Entwurf ................................................................................................................. 123 Entwurf und Integration ................................................................................................................... 124 Phase 2: Zusammenführung der Teilmodelle .................................................................................. 124 7. SYNCHRONISATION UND REPLIKATION................................................................... 128 Gründe für die Schaffung eines verteilten Informationssystems sind: ......................................... 128 Probleme bei verteilten Informationssystemen: ............................................................................. 129 Auf Grund der Probleme bei verteilten Informationssystemen gilt: ................................................ 129 4 Transaktion ........................................................................................................................................ 129 Anschauliche Darstellung: .............................................................................................................. 130 Globale Transaktionsunterstützung: ................................................................................................ 130 Zwei-Phasen-Commit ...................................................................................................................... 130 Synchronisation .................................................................................................................................. 134 Verlorene Änderungen (lost updates): ............................................................................................. 134 Schmutziges Lesen (dirty read): ...................................................................................................... 134 Inkonsistentes Lesen (inconsistent reads): ....................................................................................... 134 Lesen von Phantomen (phantom reads): .......................................................................................... 134 Sperrverfahren.................................................................................................................................. 135 Zwei-Phasen-Sperrprotokoll ............................................................................................................ 136 Zeitstempelverfahren ....................................................................................................................... 137 Optimistische Synchronisationsverfahren ....................................................................................... 138 Replikation.......................................................................................................................................... 141 Korrektheit ....................................................................................................................................... 142 Replikationsverfahren ...................................................................................................................... 142 Oracle: .............................................................................................................................................. 146 DB2: ................................................................................................................................................. 147 8. DRDA: DISTRIBUTED RELATIONAL DATABASE ARCHITECTURE ......................... 149 RDA (Remote Database Access) (ISO, ANSI-Standard Komitee) ................................................ 149 Remote Database Access RDA ........................................................................................................ 149 DRDA unterstützt unter anderem .................................................................................................... 150 Application Requester ...................................................................................................................... 150 Application Server ........................................................................................................................... 150 Kommunikation zwischen Application Requester und Application Server .................................... 151 Database Server ............................................................................................................................... 151 Rückgabe nach kompletter Bearbeitung der Anforderung .............................................................. 152 Limited Block Protocol: ................................................................................................................... 152 Es gibt noch weitere Standards, auf denen DRDA aufsetzt: ........................................................... 152 DRDA bietet 5 unterschiedliche Ebenen für die Unterstützung von Verteilung ............................. 153 Übersicht über die DRDA-Ebenen .................................................................................................. 153 DRDA Managers ............................................................................................................................. 153 SNA- bzw. TCP/IP-Manager ........................................................................................................... 154 Agent ................................................................................................................................................ 154 Supervisor ........................................................................................................................................ 154 Security Manager ............................................................................................................................. 154 Directory .......................................................................................................................................... 154 Dictionary ........................................................................................................................................ 154 Resynchronization Manager ............................................................................................................ 154 Sync Point Manager ......................................................................................................................... 154 SQL Application Manager ............................................................................................................... 154 Relational Database Manager .......................................................................................................... 155 DRDA Kommando-Fluss................................................................................................................. 155 Distributed Database: viel Aufwand und wenig Nutzen COMPUTERWOCHE Nr. 50 vom 16.12.1994 ......................................................................................................................................... 156 9. DATAWAREHOUSE ...................................................................................................... 159 5 Stärken und Schwächen Data Warehouse ....................................................................................... 159 Woher kommt der Ansatz? ............................................................................................................... 160 Mögliche Aus- und Aufgaben eines DSS sind z.B.: ........................................................................ 160 Wie ist der Zusammenhang zwischen Datenbanken und DSS zu sehen? ....................................... 160 Datenbank (Data Warehouse) mit folgenden Eigenschaften: ........................................................ 161 OLAP vs. OLTP ................................................................................................................................. 161 Vergleich OLTP - Data Warehouse ................................................................................................. 162 OLTP .................................................................................................................................. 162 DATA WAREHOUSE ......................................................................................................... 162 Generelle Struktur ............................................................................................................................. 164 Entwurf eines Data Warehouse ........................................................................................................ 164 Betrieb eines Data Warehouse .......................................................................................................... 165 Was ist eine Data Mart? ................................................................................................................... 166 Gründe für Data Marts ..................................................................................................................... 166 Probleme .......................................................................................................................................... 166 Typische Methoden beim Einsatz eines RDBMS ............................................................................ 166 Laden eines DataWareHouse ............................................................................................................ 167 Ueberlegungen hinsichtlich der Einführung von Redundanz ....................................................... 167 STAR-Schema .................................................................................................................................... 167 SNOWFLAKE-Schema:.................................................................................................................... 169 Multidimensionale Datenbanken (typisch unter Einbeziehung der Zeit) .................................... 171 MOLAP: multidimensionale DBS ............................................................................................... 171 ROLAP: relationales DBS .......................................................................................................... 171 Multidimensionale Daten: ................................................................................................................. 173 Spezielle multidimensionale Datenbank-Architektur ...................................................................... 173 RDBMS mit Aufsatz ........................................................................................................................ 174 Anlegen und Laden eines Data Warehouses vom OLTP ............................................................... 174 SQL-Anweisungen während off-Zeit des OLTP ............................................................................. 175 Snapshot ........................................................................................................................................... 175 Log sniffing ...................................................................................................................................... 175 Insert-, Update-, Delete-Trigger ...................................................................................................... 175 spezielle Data Extract Programme während off-Zeit des OLTP ..................................................... 176 10. OBJEKT-RELATIONALE DBMS ................................................................................. 177 Was sind objekt-relationale Datenbanken ??? ................................................................................. 177 Wieso braucht man objekt-relationale Datenbanken ??? ................................................................. 177 6 Was ist so toll an objekt-relationalen relationale DBMS ??? .......................................................... 177 Wie wird das umgesetzt ???............................................................................................................. 177 OODB-Manifesto: .............................................................................................................................. 178 notwendige Anforderungen ............................................................................................................. 178 optionale Anforderungen ................................................................................................................. 178 Erweiterung von RDBMS ................................................................................................................. 179 Beispiel Oracle 8 .............................................................................................................................. 179 SQL3-Standard: ............................................................................................................................... 179 Einordnung von Oracle8 .................................................................................................................. 179 User-Defined Datatypes (UDT): ....................................................................................................... 180 Object Types - Objekttypen .............................................................................................................. 180 Object Types - Vereinbarung: .......................................................................................................... 180 Object Types in Tabellen ................................................................................................................. 181 Verwendung Abstrakter Datentypen bei der Einrichtung eines komplexen Objekttyps ... ............. 181 Methoden für Objekttypen ............................................................................................................... 183 Einsatz von Methoden...................................................................................................................... 184 Get- und Set-Methoden .................................................................................................................... 184 Vergleichsmethoden ........................................................................................................................ 184 Kollektionstypen .............................................................................................................................. 185 Referenzen ....................................................................................................................................... 185 noch ausstehend auf dem Wege zur Objektorientierung: ................................................................ 186 11. OBJEKT-ORIENTIERTE DBMS .................................................................................. 187 Definition eines OODBS .................................................................................................................... 189 OOPL OODBS ............................................................................................................................ 190 System-Eigenschaften eines OO-DBMS .......................................................................................... 190 Persistenz ............................................................................................................................................ 191 Nebenläufigkeit .................................................................................................................................. 192 Transaktionen, Concurrency Control ............................................................................................... 192 Das OODBMS POET ........................................................................................................................ 197 Datenbankmodell: ............................................................................................................................ 197 Anfragen: ......................................................................................................................................... 197 Weitere Komponenten: .................................................................................................................... 198 Poet in Form von Beispielen ............................................................................................................ 198 Das OODBS Versant.......................................................................................................................... 203 Grundprinzip: ................................................................................................................................... 203 Datenbankmodell: ............................................................................................................................ 203 Schema-Evolution: ........................................................................................................................... 203 Schnittstellen und Werkzeuge: ........................................................................................................ 203 Weitere Komponenten: .................................................................................................................... 204 Versant ............................................................................................................................................. 204 Versant "Architektur" ...................................................................................................................... 204 Performance ..................................................................................................................................... 205 7 Availability ...................................................................................................................................... 205 Flexibilität ........................................................................................................................................ 205 Installationsvoraussetzungen ........................................................................................................... 205 Persistenz hinzufügen: ..................................................................................................................... 209 Datenbank anlegen: .......................................................................................................................... 210 Übersetzen und Ausführen:.............................................................................................................. 210 Was passiert bei einer Referenz? ..................................................................................................... 211 Verändern von Objekten: ................................................................................................................. 212 Schemaveränderungen ..................................................................................................................... 215 Default Locking Strategie: ............................................................................................................... 216 12. GLOSSAR .................................................................................................................... 219 Cluster .............................................................................................................................................. 219 Commit ............................................................................................................................................ 219 Datenbank ........................................................................................................................................ 219 Datenbanksystem ............................................................................................................................. 219 DCL.................................................................................................................................................. 219 DDL ................................................................................................................................................. 219 Dirty Read, Dirty Write ................................................................................................................... 219 DML................................................................................................................................................. 220 EOT .................................................................................................................................................. 220 Hashing ............................................................................................................................................ 220 Index ................................................................................................................................................ 220 JDBC ................................................................................................................................................ 220 Katalog ............................................................................................................................................. 220 Knoten .............................................................................................................................................. 220 Kreuzprodukt (zweier Tabellen) ...................................................................................................... 220 Objektorientiertes Datenbanksystem ............................................................................................... 220 Objekt-relationales Datenbanksystem ............................................................................................. 221 ODBC .............................................................................................................................................. 221 Replikation ....................................................................................................................................... 221 Transaktion ...................................................................................................................................... 221 Trigger.............................................................................................................................................. 221 Verklemmung, Deadlock ................................................................................................................. 221 Verteiltes DBMS .............................................................................................................................. 221 Virtuelle Tabelle .............................................................................................................................. 221 Vorübersetzer / Precompiler ............................................................................................................ 222 Zwei-Phasen-Commit ...................................................................................................................... 222 8 1. Datenbanken – Wozu? Geschichtliche Entwicklung: Datei – System: In einem Dateisystem ist die Struktur des Programms eng mit der Datenstruktur verknüpft. Dadurch entsteht sich logische Datenabhängigkeit. Daraus folgt, dass bei Änderung an den Strukturen einer Datei sämtliche Programme, die mit dieser Datei arbeiten, geändert, bzw. neu programmiert werden müssen. Z.B. Änderung an einer Artikel – Datei. Eine Abteilung benötigt bestimmte Daten eines Artikels, die bislang noch nicht in der Artikeldatei vorhanden sind. Dazu muss diese geändert werden. Allerdings müssen auch ebenso alle Programme die auf diese Datei zugreifen geändert werden, auch wenn sie die neuen Daten nicht benötigen. Ebenso müssen sämtliche Programme geändert werden, wenn die Art der Speicherung der Daten geändert werden soll oder bei Einführung neuer Hardware. physikalische Datenabhängigkeit Zur Wahrung der Konsistenz der Daten sind Abgleichprogramme eingesetzt worden, die die Daten überprüft haben. Prä-relationale DBMS: invertierte Listen, hierarchische DBMS, Netzwerk DBMS Relationale DBMS: DB2, Oracle, MySQL, MSSQL ... Post-Relationale DBMS: Objekt-Relational, Objekt-Orientiert Einsatzarten: - "traditionelle" Einsatzarten: kleine bis mittlere Komplexität der Datenstruktur, geringe Transaktionsrate, kleines bis mittleres Transaktionsvolumen, kleines bis großes Datenvolumen, "formatierte Daten" Beispiele: Lagerhaltung, Personalverwaltung, Geschäftsvorgänge - "neue" Anwendungen: mittlere bis hohe Komplexität der Datenstruktur, viele lesende Zugriffe pro Zeiteinheit: Datenvolumen oder Zahl der lesenden Transaktionen geringe schreibende Transaktionsrate, sehr geringes Transaktionsvolumen, mittleres bis sehr großes Datenvolumen Beispiele: Data Warehouse, Web-Anwendungen geringe bis mittlere Komplexität der Datenstruktur, geringe lesende Zugriffe pro Zeiteinheit, extrem hohe Transaktionsraten, extrem hohes Transaktionsvolumen, mittleres bis sehr großes Datenvolumen Beispiele: Daten für Energieversorger, Daten für Telefonabrechnung (insb. Handy) 9 geringe bis sehr hohe Komplexität der Datenstruktur, geringe lesende Zugriffe pro Zeiteinheit, geringe Transaktionsraten, ggf. sehr lange Transaktionsdauern, extrem hohes Transaktionsvolumen, mittleres bis sehr großes Datenvolumen Beispiele: Dokumentenretrieval-Systeme, CAD/CAMSysteme, geographische Datenbanken Anforderungen seit der relationalen Phase: Programmierung unabhängig von Datenhaltung Adressierung logisch über Eigenschaften Sichern der Integrität Kontrolle der Zugriffe Transaktionsunterstützung Backup und Recovery Verteilung Anforderungen an Relationale Datenbank Management Systeme Anforderungen nach Codd: Basis Regeln: Daten werden in Tabellenform dargestellt jeder gespeicherte Wert ist logisch durch die Kombination von Tabellenname, Primärschlüssel und Spaltenname erreichbar Der Null – Wert wird unterstützt, er ist von allen anderen Werten verschieden Der Systemkatalog (Data-Dictionary) ist wie alle anderen Daten auch in Tabellen gespeichert es muss eine Datenbank-Sprache geben, die Datendefinition Datenmanipulation Datenretrieval Integritätsbeschränkungen Autorisierungen Transaktionen unterstützt. theoretisch änderbare virtuelle Tabellen müssen auch vom System geändert werden Relationen können als Operanden behandelt werden Anwendungsprogramme bleiben logisch unberührt von Änderung der Datenspeicherung Anwendungsprogramme bleiben logisch unberührt von Änderung der Datenstruktur Integritätsregeln werden in relationaler DB-Sprache definiert und im Systemkatalog gespeichert. Das DBMS überwacht sie eigenständig und unabhängig vom Anwendungsprogramm Das DBMS ist verteilungsunabhängig 10 falls eine "low level" – Schnittstelle existiert, können damit nicht Integritäts- und Autorisierungsregeln umgangen werden Strukturregeln: Beziehungen zwischen Feldern und Tabellen nur über benannte Spalten und unnummerierte Zeilen alle gespeicherten Daten sind in Basistabellen enthalten Ergebnis einer Abfrage ist wiederum eine Tabelle Daten einer virtuellen Tabelle werden bei Ausführung dynamisch erzeugt gespeicherte Tabellenkopien erhalten einen Eintrag im Katalog das Konzept der Domänen wird unterstützt jede Tabelle hat einen Primärschlüssel stammt eine Spaltenkombination aus der gleichen Domäne, wie der Primärschlüssel einer anderen Tabelle, so handelt es sich um einen Fremdschlüssel zu der Tabelle Manipulationsregeln: folgende Operationen werden zumindest unterstützt: Selektion von Zeilen bezüglich Vergleichsoperatoren = /<= / >= / < / > / <> Projektion auf Spalten Join von Tabellen / Outer Join Division Mengenorientierte Operationen (Union, Intersect, set Difference) Integritätsregeln: Primärschlüssel darf nicht Null sein für jeden Fremdschlüssel, der nicht Null ist, muss ein Primärschlüssel existieren Anwendungsbezogene Integritätsregeln müssen in der DB-Sprache unterstützt und im Systemkatalog eingetragen werden Standardisierungen: CODASYL ANSI/SQL, ISO NIST X/Open ODMG Entwicklungen (RDBMS): Trigger Verteilung Objekt – Relational 11 Begriffe: virtuelle Tabelle: Views werden aus existierenden Basis – Tabellen abgeleitet. Das System trägt die Eigenschaften eines Views in die Systemtabellen ein. Lediglich die Einträge in Systemtabellen existieren physisch von einem View, deshalb werden Views auch virtuelle Tabellen genannt. Domäne: Attribute beziehen ihre Werte aus abgegrenzten Wertebereichen, die Domänen gennnt werden, z.B. ganze Zahlen / Boolean usw. Diese Wertebereiche lassen sich eingrenzen / einschränken, z.B. Notenwerte (1.0, 1.3, 1.7, 2.0, ..., 5.0). Projektion: Bei der Projektion wählt man aus der relationalen Struktur einer Relation nur einige, besonders interessante Attribute aus (die Tabelle wird auf wenige, besonders interessante Spalten beschränkt). Man kann mit der Projektion aber auch die Struktur einer Tabelle durch umsortieren verändern. Die Auswahl der Spalten in einer Select-Anweisung wird "Projektion" und die Auswahl der Reihen "Selektion" genannt. Retrieval: Wiedergewinnung / Wiederherstellung von Daten low-level-Schnittstelle: Unterscheiden muss man zwischen Low-Level- und HighLevel-Schnittstellen. ODBC, OLEDB und ADO.NET bieten Low-Level-Techniken mit direktem Zugriff auf die Schnittstellen der Datenbank. Jeder dieser drei Low-LevelTechniken verwendet ein Treiber-Konzept, um auf eine Vielzahl von Datenbanken zugreifen zu können. Diese Treiber heißen: - ODBC Driver für ODBC - OLEDB Provider für OLE DB - Managed Data Provider für ADO.NET (.NET Data Provi-der) High-Level-Schnittstellen RDO, DAO und ADO sind High-Level-Schnittstellen, die auf den Low-LevelSchnittstellen basieren. Die Remote Data Object (RDO) und die Data Access Objects (DAO) gelten dabei als veraltert. 12 2. Datenbankmodelle Das hierarchische Modell: Im hierarchieschen Modell nimmt der Benutzer die Daten hierarchisch wahr. Die Daten haben eine hierarchische Beziehung untereinander. Eine hierarchische Struktur lässt sich in Form eines Baumes darstellen. Die Eigenschaften des hierarchischen Modells sind: - es ist zyklenfrei - es gibt genau einen speziellen Knoten, die Wurzel. Dieser Knoten hat keinen Vorgänger - jeder andere Knoten hat genau einen Vorgänger Definition des hierarchischen Modells: - es gibt eine Menge benannter Entitätstypen (Segmente) und eine Menge von unbenannten Beziehungen. - Jede Entität (Segment Occurence) gehört zu einem Entitäts-Typ - Alle Entitäten innerhalb der Datenbankstruktur sind total (hierarchisch) geordnet - Jede Entität ist nur über das Wurzelsegment erreichbar Beispiel: Modellierung Student Problem: 1. Ebene Student oder Prüfung? Entscheidung für die Ebenen: 1. Student mit Matrikelnummer, Name, Anschrift 2. Grundstudium - Hauptstudium 3. Fächer mit Nr., Dozent, Semester, Ergebnis Besonderheiten im Hauptstudium: Projekt, Arbeit, Kolloquium in IMS Strukturbeschreibung in Assembler-Datei durch die Übersetzung werden ausführbare Dateien und Bibliotheken erzeugt: zum physischen Anlegen der Datenspeicher zum Erzeugen von Zugriffsmethoden, mit deren Hilfe kann aus einem Programm heraus auf die Daten zugegriffen werden 13 graphische Darstellung IMS Kurzbeschreibung der DB-Struktur von IMS IMS besteht in der Regel nicht aus einer einzigen, sondern aus mehreren Datenbanken. IMS erlaubt den Aufbau hierarchisch strukturierter Datenbestände, die für das System in 3 verschiedenen Stufen beschrieben werden. Man unterscheidet zwischen der Beschreibung des hierarchischen Datenbankaufbaus, der Beschreibung des Zugriffs für ein bestimmtes Programm und der Beschreibung der Segmente mit den Datenfeldern. Als Segment bezeichnet man die kleinste Zugriffseinheit, das ist die kleinste Menge an Daten, die durch DL/1-Operationen transportiert werden kann (DL/1 ist die Sprache (DDL, DML)) von IMS. Zur Beschreibung des hierarchischen Aufbaus einer physischen Datenbank dient die „Data Base Description (DBD)“. Eine physische Datenbank ist die tatsächlich gespeicherte Datenbank, im Gegensatz zum Datenbankausschnitt (program communication block, PCB), der dem Benutzer zur Verfügung gestellt wird. Die Beschreibung des speziellen DatenbankZugriffs für ein Programm erfolgt im "program specification block (PSP)". Felder und Struktur eines Segments werden im Programm selbst beschrieben, sie entsprechen den Konventionen der jeweiligen Wirtsprache. (Sauer, Datenbanken – Skript SS2002, Uni Regensburg) Skizzierung des DD-Files (Datendefinition) DBD NAME=STUDIES SEGM NAME=STUDENT,BYTES=100 FIELD NAME=(MATRNR#,SEQ),BYTES=7,START=1 FIELD NAME=NAME,BYTES=30,START=8 FIELD NAME=ADDRESS,BYTES=63,START=38 SEGM NAME=GRUNDST,PARENT=STUDENT;BYTES=2 FIELD NAME=(NR#,SEQ),BYTES=1,START=1 FIELD NAME=DONE,BYTES=1,START=2 SEGM NAME=VORLES,BYTES=35 FIELD NAME=(NR#,SEQ),BYTES=2,START=1 FIELD NAME=CODE,BYTES=7,START=3 FIELD NAME=DOZENT,BYTES=20,START=10 14 FIELD NAME=SEMSTR,BYTES=2,START=30 FIELD NAME=RESULT,BYTES=3,START=32 ... Skizzierung des PCB-Files (Sicht) PCB DBDNAME=STUDIES SENSEG NAME=STUDENT,PROGOPT=G SENFLD NAME=MATRNR,START=1 SENFLD NAME=NAME,START=8 SENSEG NAME=GRUNDST,PROGOPT=G Damit wird festgelegt, welche Felder der Benutzer sieht wie er auf die Felder zugreifen darf Skizzierung der Operationen Verwendet werden Funktionsaufrufe (z.B. in PL/I), deren Parameter die entsprechende Aktion angeben: GU GN GNP GHU REPL ISRT DLET REPL Get Unique Get Next Get Next under current Parent wie GU mit der Möglichkeit eines anschließenden DLET oder entsprechend GHN und GHNP InSeRT new segment DeLETe existing segment REPLace existing segment GU dient auch der Initialisierung (initial position). Navigierender Zugriff (Pseudo-Code): GU STUDENT WHERE MATRNR# = ' ... ' ; do until no more GRUNDST ; GN GRUNDST ; do until no more VORLES ; GNP VORLES ; /* mach was damit */ end ; end ; 15 Besonderheiten Logical Database Secondary Indexes Recovery Concurrency: Record (Segment) locking Security (via PCB) Integrity: Uniqueness (seq), Regeln für logische Datenbanken Die ANSI/SPARC – Architektur: Die ANSI/SPARC - Architektur sieht 3 Ebenen vor: 1. Eine mittlere konzeptuelle Ebene, die alle drei Anwendersichten zu einer Art gemeinschaftlichen Sicht vereinigt 1. Eine interne Ebene, die es gestattet, unter Kenntnis von Anwenderprofilen und verfügbarer Hard- und Grundsoftware die leistungsfähigsten Speicher- und Zugriffsmethoden zu wählen 3. Eine externe Ebene mit beliebig vielen Anwendersichten Im Mittelpunkt der verschiedenen Betrachtungen (Sichten) steht das allumfassende Konzept für die Anwendung der Daten. Datenbanken stellen auf der einen Seite die Mittel zur Verfügung, die die jeweiligen Dateien für die spezifischen Anwendungen bereitstellen. Auf der anderen Seite sorgen sie für die Speicherung der Daten (internes Schema, Speicherschema). Entscheidend ist in beiden Fällen das Datenmodell, das der allgemeinen Beschreibung zugrunde liegt. Das Datenmodell soll möglichst genau die realen Verhältnisse (die reale Welt) wiedergeben, d.h. die unterschiedlichen Objekte (Entitäten) und ihre Beziehungen. Ein Datenmodell ist dann das Muster (das Schema), nach dem die Daten logisch organisiert werden. Im Hinblick zu den Anwenderprogrammen ist auf Datenneutralität und mit Blickrichtung auf die physische Datenbank auf Datenunabhängigkeit zu achten. Datenneutralität bedeutet: Neue Anwendungen und neue Benutzersichten sollen keinen Einfluss auf existierende Anwendungen und Sichten ausüben. Datenunabhängigkeit bedeutet: Neue Geräte, verbesserte Speichertechnologien, veränderte Zugriffspfade sollen sich in Anwendungen nur durch Leistungsverbesserung, nicht durch Funktionsänderung bemerkbar machen. Bei vollständiger Datenneutralität ist es möglich, durch unterschiedliche Benutzersichten (Netze, Hierarchien, Relationen) das Basis-Schema zu betrachten. Eine Sicht (view) wird mit Hilfe der Datenmanipulationssprache (DML) aus der Basis, deren Struktur durch eine Datendefinitionssprache (DDL) festgelegt wurde, bestimmt. Auf der anderen Seite sollte eine Reihe von Abbildungen das "Interne Schema" zur Beschreibung physischer Strukturen erzeugen. Sie enthalten mit ihren Katalogen die Details zu Zugriffspfaden und zur physischen Speicherung. Eine Speicherstrukturierungssprache (SSL) unterstützt die verschiedenen Alternativen zur physischen Speicherung. 16 Ein hohes Maß an Datenunabhängigkeit und -neutralität ist mit hierarchischen und auch mit netzwerkorientierten Datenbanken nicht zu erreichen. (Sauer, Datenbanken – Skript SS2002) Vereinfacht ausgedrückt: Ein Vorteil eines einheitlichen Datenbestandes für alle Anwendungen ist es, dass die Datenbearbeitung und die Verarbeitung der Daten voneinander getrennt sind. Man spricht dann auch von Datenunabhängigkeit. Dies erreicht man dadurch, dass man bei der Datenbankentwicklung ein Konzept heranzieht, dass von vornherein Datenunabhängigkeit garantieren soll. Drei Ebenen Konzept In der Konzeptionellen Ebene werden sämtliche Daten, die in der Datenbank gespeichert werden sollen, beschrieben. Es wird also die Struktur der Daten beschrieben. Die externen Schemata beschreiben die Ausschnitte, die für die einzelnen Benutzergruppen relevant sind. Die interne Ebene beschäftigt sich mit der physischen Speicherung der Daten. Ziel ist es, bei Änderungen auf einer Ebene die nächsthöhere Ebene nicht ebenfalls ändern zu müssen. ANSI/SPARC - Architektur: drei Ebenen-Architektur: 17 Wie eine Anfrage bearbeitet wird: Datenbank – Administrator (DBA) Die hauptsächlichen Aufgaben eines Datenbank – Administrators sind: - Erstellen der konzeptionellen Sicht (also Erstellen der Datenstruktur): Alle Aspekte der zu modellierenden Welt werden erfasst und eindeutig und redundanzfrei modelliert - Erstellen der internen Sicht (Speicherung der Daten): Damit wird wesentlich die Performance des Systems beeinflusst: Daten werden in einer Form gespeichert, die für einen effizienten Zugriff geeignet ist. Zusätzlich werden ggf. Hilfsstrukturen zur Unterstützung des Zugriffs angelegt - Erstellen der externen Sichten, insbesondere Zugriffsrechte für die Anwender: Die so entstehenden Ausschnitte beschränken damit die Zugriffsrechte des jeweiligen Benutzers. Zu diesen Aufgaben kommen noch: - Regeln für Sicherheit und Integrität der Daten implementieren (Konsistenz der Daten) - Erstellen von Backup – Strategien und Recovery- Prozeduren (Gewährleistung der Datensicherheit) - Überwachung und Steigerung der Perfomance - Installation des DBMS und Einbinden neuer Hardware 18 Eingriffsmöglichkeiten zur Steigerung der Perfomance für den Datenbank – Administrator: auf unterster (physikalischer) Ebene: - Reservieren von Hauptspeicher für Systempuffer zum Zeitpunkt der Installation des DBMS - Verteilung der Daten af verschiedene Festplatten (Zeitpunkt: Anlegen der Datenbank) - Anschaffung neuer Speicherperipherie (zusammen mit Betriebssystemgruppe, Zeitpunkt: Lebenszyklus einer Datenbank) - auf unterer Ebene (Speicherung der Daten): Füllungsgrad der Speicherseiten beeinflussen Reorganisation / Clustern der Daten auf den Speicherseiten Bereitstellen von Sekundärindizes Typ eines Sekundärindex bestimmen (soweit das DBMS das zulässt) - auf höherer Ebene (Zugriff auf Daten): Informationserhaltende Strukturänderungen Bereitstellung von Datenbank-Prozeduren Zugriffspfad-Analyse und –Optimierung - - 19 Generelle Struktur eines DBMS 20 Tupel-Identifier = Indirektion und damit einfache Verschiebbarkeit von Informationen auf einer Seite. Um Tupel (Records) flexibel zu speichern, wird üblicherweise eine zweigeteilte Adressierung gewählt: Seitenadresse, Offset innerhalb der Seite. Im Offset der Seite steht dann die eigentliche Speicheradresse des Tupels auf der Seite. Diese Art der Speicherung ermöglicht eine leichte Verschiebbarkeit eines Tupels in der Seite. Damit lassen sich leicht Lücken auf einer Seite zusammenziehen und somit Platz für neue Einträge schaffen. Grund: nach mehreren Einfügungen, Löschungen und Änderungen von Datensätzen in einer Seite entstehen Lücken, da die gespeicherten Datensätze in der Regel unterschiedleich lang sind. Bei Garbage – Collection kann wieder ausreichend Platz auf der Seite beschafft werden Beim Tupel-Identifier-Konzept wird die Information wo der Datensatz steht auf die Seite verschoben, auf der der Datensatz gespeichert ist kürzere Informationswege über den Speicherort bei Garbage – Collection braucht nur der Index auf der Seite geändert werden Beim Verschieben des Datensatz auf Überlaufseite (z.B. bei Clusterung) muss nur der Eintrag im Seitenindex geändert werden 21 Cluster Erfolgt häufig ein Zugriff auf Datensätze in einer bestimmten Reihenfolge, kann eine Clusterung die Performance steigern: die Datensätze werden so auf die Seiten verteilt, dass Sätze, die in der Ordnung (Clusterindex) aufeinanderfolgen, so weit wie möglich jeweils auf einer Seite zusammengefasst werden => bei der Verarbeitung in Reihenfolge des Clusterindex werden die physischen Speicherzugriffe minimiert Problem: liegen Daten geclustered vor und erfolgen eine Reihe von Änderungen, so können nach gewisser Zeit Datensätze nicht mehr auf diejenige Seite geschrieben werden, auf die sie auf Grund der Clusterung kommen müssten => Überlaufseiten zur Aufnahme der Datensätze Lösungen: o Füllungsgrad der Seiten verändern o Reorganisation Index Die Suche nach Datenwerten , die durch eine SELECT-Anweisung mit der WHEREBedingung festgelegt sind, kann auf zwei verschiedene Weisen durchgeführt werden: sequentiell indiziert Sequentielle Suche bedeutet, dass jede Reihe einer Tabelle einzeln auf die Bedingung in der WHERE-Klausel hin überprüft wird. Nacheinander werden also alle Reihen in der Reihenfolge, wie sie physikalisch gespeichert sind, geprüft. Die indizierte Suche kennzeichnet das gezielte Suchen nach den Reihen, die die angegebene Bedingung erfüllen. Welche Art der Suche angewendet wird hängt primär von der Speicherstruktur, mit der die Reihen einer Tabelle auf der Platte gespeichert sind, ab. Einige Speicherstrukturen erlauben den Zugriff auf Daten mit Hilfe eines Schlüssels. In diesem Fall ist die indizierte Suche möglich. Falls der Zugriff auf Daten ohne Schlüssel durchgeführt wird, muss die sequentielle Suche angewendet werden. Ein Index kann mit dem Inhaltsverzeichnis eines Buches verglichen werden. Mit Hilfe eines Inhaltsverzeichnisses ist es möglich, einen Begriff, der im Buch ein- oder mehrmals vorkommt, gezielt zu suchen und anschließend im Text ausfindig zu machen. Aufgabe eines Indexes ist es, einen schnellen Zugriff auf gewünschte Information zu ermöglichen Zugriff auf Datensätze in sortierter Reihenfolge direkter Zugriff auf einen Datensatz Bereichsanfrage Dazu wird der Schlüssel zusammen mit dem => die zu speichernde Datenmenge ist wesentlich reduziert TID gespeichert 22 Zum Suchen gut geeignete Strukturen: Pointerketten Index-sequentiell B-Tree Hash Die Art des Index ist in den meisten Fällen bereits durch die Wahl des DBMS vorgegeben Ein Index speichert Schlüssel und TID, die zu speichernde Datenmenge ist somit in der Regel wesentlich kleiner als die Datenmenge des Records. Ferner wird eine zum Suchen gut geeignete Struktur gewählt: z.B. BTree oder auch Hashverfahren. Wird nach einem bestimmten Schlüsselwert gefragt, so kann mit wenigen Zugriffen auf den Index die Menge der zugehörigen TIDs ermittelt werden und dann direkt auf die Tupel zugegriffen werden. (Beim Hashing wird der TID im Prinzip sogar ohne weiteren Zugriff direktechnet). Einsatz eines Indexes um auf die Einträge in der Reihenfolge, die durch den Index vorgegeben wird - d.h. sortiert -, zuzugreifen; um zusammenhängende Bereiche herauszufiltern: z.B. bei numerischen Daten alle Einträge mit Werten im Intervall von a bis b; um auf einen Wert direkt zuzugreifen: z.B. bei numerischen Daten auf denjenigen Eintrag (bzw. diejenigen Einträge) mit dem Wert a. Nur bei einem eindeutigen Index ist garantiert, dass der angegebene Wert höchstens einmal gespeichert ist. Die ersten beiden Möglichkeiten scheiden bei Einsatz von Hashverfahren aus. Vorteil eines Indexeinsatzes: Schneller direkter Zugriff Nachteil: bei sehr kleinen Dateien (nur wenige Datenblöcke) erzeugt ein Index zusätzlichen Overhead Bei Änderungen und Einfügen von Daten verlangsamt der Index, da auch der Index mitgepflegt werden muss Index über Feldkombinationen Indexe können auch über Feldkombinationen der zugrundeliegenden Tupel erstellt werden. Beim Wiederauffinden kann ein solcher Index nur dann sinnvoll benutzt werden, wenn für die Kombination von links her die Werte ohne Lücken bekannt sind: Beispiel: enthalten die Tupel z.B. Felder für Länge, Breite und Höhe von Quadern und wird in dieser Reihenfolge - ein kombinierter Index angelegt, so kann der Index sinnvoll eingesetzt werden, wenn alle Einträge mit Länge a, Breite b und Höhe c gesucht werden, 23 Länge a und Breite b oder nur mit Länge a gesucht werden Suchen nach Bereichen sind ebenso zulässig. Der Index kann jedoch z.B. nicht ausgewertet werden, wenn alle Einträge mit Breite b und Höhe c gewünscht sind: zum sinnvollen Einsatz fehlt Information über die Länge. Pointerketten Anstelle eines Index können Pointerketten verwendet werden: jeder Wert erscheint nur einmal, im Eintrag steht anstelle des Wertes ein Pointer, über den Einträge mit gleichem Wert verkettet sind (lineare Liste, Anker ist der mit dem gespeicherten Wert verbundene erste Pointer). Obwohl die Algorithmen für Einfügen und Löschen in der Regel einfacher sind als bei der Verwendung eines Indexes, ist die Verwendung von Pointerketten mit Nachteilen verbunden. Vergleiche Übungen. Index-sequentiell Voraussetzung: Speicherung auf den Daten-Seiten in Schlüsselreihenfolge (sequentiell) Im Index wird für jede Daten-Seite der Schlüssel (und TID) des letzten Records aufgenommen (desjenigen mit größtem Schlüsselwert) Index selbst sequentiell geordnet Verfahren kann mehrstufig benutzt werden Bereichsanfragen sowie sortierter Zugriff sind sehr gut Suchen: vgl. "Algorithmen..." Besonderheiten: geeignet z.B. als Cluster-Index Überlauf-Organisation Reorganisations-anfällig B-Tree insbesondere: ausgeglichener sortierter B-Tree Spezialfall von Index-sequentiell wird mit k die für den Baum vereinbarte Schlüsselanzahl bezeichnet, so gilt: der Baum ist sortiert jeder Knoten (bis auf die Wurzel) enthält mindestens k und max. 2k Schlüssel der Weg von der Wurzel zu jedem Blatt ist gleich lang k beschreibt die Breite (Fan Out) des Baumes: k=100 bedeutet z.B., dass man mit nur zwei Zugriffen 100x100=10000 TIDs auffinden kann, mit drei Zugriffen einen Datensatz in 10000 Datensätzen lesen kann schneller Zugriff Bereichsanfragen möglich sortierter Zugriff möglich Problem: Reorganisation Einsatz typisch für RDBMS 24 Hash die Verbindung zwischen Schlüssel und TID erfolgt über eine Funktion, kein Lesezugriff besonders schnell Problem: keine Bereichsanfrage möglich! kein Zugriff in sortierter Reihenfolge möglich Wahl der geeigneten Hash-Funktion Beim Hashing werden die Datensätze in einem Feld mit direktem Zugriff gespeichert. Die Hash-Funktion ermöglicht für jeden gespeicherten Wert den direkten Zugriff auf den Datensatz. Hashing(engl.: to hash=zerhacken) beschreibt eine spezielle Art der Speicherung der Elemente einer Menge durch Zerlegung des Schlüssel-Universums. Die Position des DatenElements im Speicher ergibt sich (zunächst) durch Berechnung direkt aus dem Schlüssel. Die Menge aller möglichen Schlüssel (der Wertebereich) sei D (Domain). Der Speicher wird ebenfalls zerlegt in m gleich große Behälter (Buckets). Es ist |D| sehr viel größer als m. Eine Hash-Funktion h kann nun für jeden Schlüssel s die Nummer des Buckets h(s) 0,1,..., m 1 berechnen. Ideal wäre eine eindeutige Speicher-Zuordnung eines Datums mit Schlüssel s zum Bucket mit Nummer h(s): Einfügen und Suchen könnten in konstanter Zeit (O(1))erfolgen. Tatsächlich treten natürlich Kollisionen auf: Mehrere Elemente können auf die gleiche Hash-Adresse abgebildet werden. Kollisionen müssen (auf eine von verschiedenen Arten) behandelt werden. Hash-FunktionenDef.: Es sei D ein Wertebereich von Schlüsseln und m dieAnzahl der Behälter Bo , ... , Bm-1zum Speichern einer gegebenen Menge {e1, .. en}von Elementen (Datensätzen)Eine HashFunktion hist eine (totale) Abbildung h: D .{0, .. m-1}, die jedem Schlüsselwert w D eine Nummer h(w)und damit einen Behälter Bh(w)zuordnet. Die Nummern der Behälter werden auch als Hash-Adressenund die Menge der Behälter als Hash-Tabellebezeichnet. (Vorlesung ALG 2, ...) Index Nur eindeutiger Index garantiert, dass angegebener Wert höchstens einmal vorhanden ist Vorteile beim Einsatz: schnelles Suchen von Datenätzen Nachteile beim Einsatz: bei Änderungen (Einfügen, Löschen, Ändern von Datensätzen) muss Index mitgepflegt werden => Verlangsamung bei sehr kleinen Dateien (nur wenige Seiten) erzeugt Index sogar beim Lesen zuviel Overhead Index: kombinierte Spalten Index kann aus mehreren Attributen kombiniert sein. => Index kann beim Auffinden nur dann sinnvoll benutzt werden, wenn Attribute von links her ohne Lücken bekannt sind: 25 Tabelle Prüfungen MatrNr VName Semester Note 4711 Programmierung 1 Sommer 2000 2.0 4712 Programmierung 1 Sommer 2000 3.0 4712 Programmierung 2 Winter 2000 3.0 4711 4711 Datenbanken Sommer 2001 1.0 Programmierung 2 Sommer 2001 1.3 werden Informationen über Prüfungen verwaltet und ein Index über MatrNr, VName und Note (in dieser Reihenfolge) angelegt, so kann Index ausgenutzt werden, wenn MatrNr, VName und Note MatrNr und VName MatrNr bekannt sind, sonst jedoch nicht. Manche DBMSe ermöglichen es, mit einem Zugriff auf den Index auszukommen ohne auf die Datensätze zuzugreifen, wenn gesuchte Information bereits im Index vorhanden ist. Anmerkung: die Reihenfolge des Indexspalten muss nicht mit der Reihenfolge der Spalten in der Tabelle übereinstimmen Der Optimierer (Optimizer) Der Optimierer ist jene Komponente eines relationalen DBMS, die für die effiziente Ausführung der Abfrageoperationen zuständig ist. Nach der Kostenschätzung aller ausgewählten Ausführungspläne entscheidet sich der Optimierer für den aus seiner Sicht günstigsten Plan. In relationalen Datenbankmanagementsystemen werden zwei Grundtechniken vom Optimierer verwendet, um Datenbankoperationen effizient auszuführen: heuristische Regeln und systematische Kostenschätzung Diese beiden Techniken werden meistens kombiniert angewendet. Die Existenz der heuristischen Regeln basiert darauf, dass im relationalen Datenmodell ein Ausdruck auf mehrere unterschiedliche Arten dargestellt werden kann. Die Verknüpfung zweier Tabellen kann in den meisten Fällen sowohl durch eine Unterabfrage als auch durch einen Join äquivalent dargestellt werden. Die wichtigste heuristische Regel ist, dass unäre Datenbankoperationen (Selektion, Projektion) immer vor binären Operationen (Join, Vereinigung) ausgeführt werden sollten. Die Existenz von Indizes für Tabellenspalten beeinflusst maßgeblich die Auswahl des Ausführungsplan und damit auch die Performance einer gegeben Abfrage. Das gilt besonders für Filter, d.h. die Spalten, die in der WHERE-Klausel erscheinen. Die 26 Entscheidung, ob ein Index verwendet wird oder nicht, hängt von der Indexselektivität ab und vom Indextyp. Ist die Indexselektivität hoch (es werden nur wenige Reihen identifiziert und ausgewählt), wird der Index verwendet.(MS SQLServer) select * from arbeiten where einst_dat = '01.01.1989' and aufgabe = 'Sachbearbeiter' Beispiel: Die Tabelle arbeiten hat je einen Index für die Spalten einst_dat und aufgabe. Welcher Index wird zuerst verwendet ? Gesamtanzahl von Reihen: 100 000 geschätzte Anzahl Reihen, die die Bedingung in einst_dat erfüllen = 100 geschätzte Anzahl Reihen, die die Bedingung in aufgabe erfüllen = 40 000 Mit Hilfe dieser Statistiken kann der Optimierer die Selektivität berechnen. Zuerst würde der Optimierer den Index für die Spalte einst_dat ausführen (100 / 100 000 = 0,1), dann den Index für die Spalte aufgabe (40 000 / 100 000), weil die Selektivität für die Spalte einst_dat wesentlich höher ist als die Selektivität für die Spalte aufgabe. [Dusan Pethovic, MS-SQL-SERVER 2000] Kriterien für "günstigen" Pfad: keine Regel-basiert o Reihenfolge der Tabellen im SELECT-Statement o wenn möglich, Index verwenden o ... Kosten-basiert o Ermittlung mehrerer Alternativen o abschätzende Bewertung der jeweiligen Kosten Plattenzugriffe CPU-Belastung Speicherbedarf o Auswahl der günstigsten Alternative Aufgabe der Komponente, Optimizer: Ermitteln von Zugriffspfaden Ermitteln des "günstigsten" Pfads Kriterien für "günstigen" Pfad: keine Regel-basiert o Reihenfolge der Tabellen im SELECT-Statement 27 o o wenn möglich, Index verwenden ... Kosten-basiert Ermittlung mehrerer Alternativen abschätzende Bewertung der jeweiligen Kosten Plattenzugriffe CPU-Belastung Speicherbedarf o Auswahl der günstigsten Alternative o o Beispiel Tabelle Student MatrNr Name Vorname Anschrift ImmatrikDatum ExmatrikDatum ... 4711 Mustermann Demo Irgendwo 11.11.1999 - ... 4712 Element ... - ... ... ... Tabelle Prüfungen MatrNr VName Semester Note 4711 Programmierung 1 Sommer 2000 2.0 4712 Programmierung 1 Sommer 2000 3.0 4712 Programmierung 2 Winter 2000 3.0 4711 Datenbanken 4711 Programmierung 2 Sommer 2001 1.3 Sommer 2001 1.0 Index auf Student.Name und Prüfungen.Matr.Nr Anfrage: SELECT Student.MatrNr, Name, VName, Semester, Note FROM Student, Prüfungen WHERE Name = "Mustermann" AND Vorname = "Demo" Mögliche Zugriffspfade? Beispiele für Zugriffspfade Einige Beispiele: ohne Indexe: 28 Sequentielles Abarbeiten von Student, zu jedem akzeptierten Datensatz sequentielles Abarbeiten von Prüngen o umgekehrt: Abarbeiten von Prüfungen und für jeden akzeptierten Datensatz Abarbeiten von Student o Vorsortieren von Prüfungen hinsichtlich des Attributs MatrNr, sequentielle Verarbeitung von Student, für jeden akzeptierten Datensatz binäres Suchen in der sortierten Tabelle von Prüfungen o Vorsortieren beider Tabellen nach dem Attribut MatrNr und Zusammenfügen, danach satzweises Abarbeiten o mit Einsatz von Indexen Sequentielles Abarbeiten von Student, für jeden akzeptierten Datensatz direkter Zugriff auf Prüfungen o Direkter Zugriff auf akzeptierte Datensätze von Student, danach direkter Zugriff auf Prüfungen o ... o ... und wenn beide Tabellen nach MatrNr geclustered vorliegen? Regel-basiert: Direkter Zugriff auf akzeptierte Datensätze von Student, danach direkter Zugriff auf Prüfungen Je nach Regelsatz bleibt nur dieser Ansatz übrig. Nicht immer optimal! (?) Kosten-basiert: ohne Indexe: Sequentielles Abarbeiten von Student, zu jedem akzeptierten Datensatz sequentielles Abarbeiten von Prüngen ergeben sich aus dem sequentiellen Lesen der Tabelle Student und dem wiederholten sequentiellen Lesen der Tabelle Prüfungen Dabei geht die Selektivität der Anfrage hinsichtlich der Tabelle Student ein o umgekehrt: Abarbeiten von Prüfungen und für jeden akzeptierten Datensatz Abarbeiten von Student Kosten: ? o Vorsortieren von Prüfungen hinsichtlich des Attributs MatrNr, sequentielle Verarbeitung von Student, für jeden akzeptierten Datensatz binäres Suchen in der sortierten Tabelle von o 29 Prüfungen Kosten: ? o Vorsortieren beider Tabellen nach dem Attribut MatrNr und Zusammenfügen, danach satzweises Abarbeiten Kosten: ? mit Einsatz von Indexen Sequentielles Abarbeiten von Student, für jeden akzeptierten Datensatz direkter Zugriff auf Prüfungen Kosten: ? o Direkter Zugriff auf akzeptierte Datensätze von Student, danach direkter Zugriff auf Prüfungen Kosten: ? o ... o ... und wenn beide Tabellen nach MatrNr geclustered vorliegen? Datenkompression Durch Verwendung von Kompressionstechniken wird das gespeicherte Datenvolumen verringert. Dies wirkt sich positiv bei physischen Zugriffen auf die Platten aus. Dafür muss mehr Rechenleistung aufgewendet werden, um die komprimierten Daten wieder zu dekomprimieren. Eine interessante Möglichkeit der Datenkompression bietet sich bei der Verbindung zu Clustern: der clusternde Wert braucht ggf. nur einmal gespeichert zu werden, außerdem lässt sich ausnutzen, dass die Clusterwerte sortiert vorliegen. Speicherung von Daten (Beispiel: MS SQL Server) Die Datenspeicherung beim SQL Server basiert auf zwei physikalischen Einheiten: - physikalische Seite extent Die wichtigste Einheit für die Datenspeicherung beim SQL Server ist die physikalische Seite. Eine physikalische Seite weist eine feste Größe von 8 KB auf. Jede Seite hat einen Anfangsbereich von 96 Bytes, der für die Speicherung der Systeminformation benutzt wird. Daten werden unmittelbar nach dem Anfangsbereich gespeichert. Es gibt 6 unterschiedliche Typen von physikalischen Seiten (Datenseite, Indexseite ...). Bei der Erstellung einer Tabelle oder eines Index wird vom SQL Server zuerst ein fester Speicherbereich zur Verfügung gestellt. Falls der zur Verfügung stehende Speicherbereich nicht für die Daten ausreicht, wird vom System zusätzlicher Speicher zugewiesen. Die physikalische Einheit, die vom System in so einem Fall zugewiesen 30 wird, heißt extent. Ein extent umfasst acht nebeneinander liegende physikalische Seiten. Der SQL Server unterscheidet zwei Arten von extents: - einheitliche extents mixed-extents Ein einheitliches extent wird ausschließlich für die Speicherung der Werte einer Tabelle (z.B. eines Index) benutzt, während ein mixed-extent Daten von maximal acht Tabellen (oder Indizes) aufnehmen kann. 31 3. Relationale DBMS Anforderungen SQL Standard Ausgewählte Besonderheiten von speziellen DBMS-Implementationen o Besonderheiten von DB/2 o Besonderheiten von Oracle Anforderungen Zunächst muss festgehalten werden, dass dieser Abschnitt - zumindest zum Teil - zu dem Kapitel "DB-Modelle" gehört. Dennoch werden relationalen DBMS aufgrund ihrer derzeitigen Bedeutung ein eigenständiger Abschnitt eingeräumt. Im Gegensatz zu hierarchischen und Netzwerk-DBMS ist es nicht die interne Struktur, die ein DBMS als relational kennzeichnet. Gerade davon soll ja Abstand genommen werden, um die damit verbundene Hardware-Abhängigkeit weiter zu reduzieren. Um 1970 entstanden die Arbeiten von Codd, der auf die Ausgewogenheit eines relationalen Ansatzes hinwies. Auch nach der Implementation einer relationalen Datenbank lassen sich nämlich völlig neue Fragestellungen leicht bewältigen, da einerseits die Datenzugriffe nicht nur auf eine spezielle Fragestellung hin optimiert sind und andererseits die Datenstruktur erweitert werden kann, um bislang nicht erfasste Sachverhalte mit Hilfe einer Strukturerweiterung aufnehmen zu können. So könnte der Wunsch bestehen, zu der Information, welcher Lieferant Ware liefern kann und wie viel die jeweilige Ware kostet, auch aufzunehmen, ab wann der Lieferant die Ware zu den angegebenen Bedingungen liefern kann. Eine weitere Forderung könnte lauten, die Verkaufspreise zu erfassen. Zwischen 1974 und 1976 entstanden die ersten Implementationen, um 1978 das erste marktreife relationale Datenbanksystem. Seit dieser Zeit erleben relationale Datenbanksysteme eine stürmische Entwicklung. Dieser Umstand ist auf mehrere Ursachen zurückzuführen: - - Die Struktur einer erstellten Datenbank kann noch im Nachhinein modifiziert werden, um Schwächen des Designs auszugleichen sowie neue Fragestellungen zu ermöglichen. Die Pflege des Datenbestandes ist wesentlich weniger aufwendig als bei hierarchischen oder Netzwerk-strukturierten Datenbanksystemen. Die Datenintegrität wird vom System überwacht. Somit kann auch ein Benutzer interaktiv mit der Datenbank arbeiten, ohne Gefahr zu laufen, Dateninkonsistenzen zu erzeugen. Echt relationale Datenbanksysteme besitzen die Eigenschaft, dass sie entweder bereits als „Verteilte Datenbanksysteme“ (VDBMS) eingesetzt werden können oder aber vom Hersteller 32 dahingehend erweitert werden können (so Codd in seinen Anforderungen an „echt“ relationale Datenbanksysteme). Diese Entwicklung ist heute bei vielen Datenbanksystemen zu sehen, die bereits Verteilung ermöglichen. Bezogen auf das Beispiel würde die Firma beim Aufbau einer neuen Niederlassung eine verteilte Datenbank einrichten, bei der die jeweils lokal benötigten Informationen vor Ort gespeichert werden. [Achilles, SQL] Entscheidend ist nicht, dass Daten möglicherweise in Records gespeichert werden, so dass die Sichtweise der Tabelle auch in physischer Form nachgebildet wird. Die meisten kommerziellen RDBMS (Relationale DBMS) nutzen tatsächlich diese Speicherform. Entscheidend ist vielmehr, dass das DBMS eine Reihe von Regeln erfüllt. Diese Regeln wurden ca. 1982 von Codd formuliert. Heutige kommerzielle DBMS erfüllen viele dieser Anforderungen, jedoch durchaus nicht alle. Im folgenden sollen die Regeln in modifizierter Form dargestellt werden. Nach einer Regel folgt in vielen Fällen ein kurzer Kommentar. Basisregeln Aus logischer Ebene sind alle Daten, auch die Datenbankbeschreibung = Katalog, auf genau eine Weise als Werte in Tabellen repräsentiert. Dies betrifft - im Gegensatz z.B. zum hierarchischen Modell - auch auf den Katalog zu. Auf diese Weise wird ermöglicht, flexible Schnittstellen zu anderen Softwarepaketen zu erstellen. Jeder gespeicherte Wert kann logisch durch eine Kombination aus Tabellenname, Primärschlüssel und Spaltenname eindeutig erreicht werden. Auch wenn es weitere Arten geben mag, auf Daten zuzugreifen, so gibt es doch hiermit einen implementations-unabhängigen Weg, der nur dem relationalen Ansatz unterliegt. Der Begriff "Primärschlüssel" bekommt eine herausragende Bedeutung. Der NULL-Wert wird unterstützt; er unterscheidet sich von allen anderen Werten. Insbesondere muss es möglich sein, den NULL-Wert für den Primärschlüssel zu unterbinden. Dies sollte aus Integritätsgründen auch für andere Spalten möglich sein. Es muss zumindest eine Datenbanksprache geben, die DDL (Data Definition Language), DML (Data Manipulation Language), DCL (Data Control Language - Autorisierung, Transaktionen,) sowie Integritätsbedingungen unterstützt. Damit sollte es kaum noch nötig sein, die Datenbank zu stoppen, um DB-Objekte anzulegen, zu löschen oder zu verändern. Auch die Sicherung einer Datenbank sollte weitgehend online erfolgen können. Die Trennung in die verschiedenen Sprachbereiche, die von den älteren Modellen herrührt, wird verwischt. Virtuelle Tabellen, die bzgl. einer Datenmanipulation "theoretisch" änderbar sind, müssen auch vom DBMS geändert werden. Nicht nur die SELECT-Anweisung, auch INSERT, UPDATE, DELETE sollen eine Relation als Operanden behandeln können. Ist dies wirklich gewährleistet, kann das DBMS besser optimieren. Insbesondere für verteilte DBMS kann es zu einer gewünschten Verringerung der Kommunikation führen. 33 Anwenderprogramme bleiben logisch unberührt von einer Veränderung der Speicherrepräsentation oder der Zugangsmethoden. Ebenso berühren informationserhaltende Änderungen der Tabellen die Programme logisch nicht. Dies bringt die gewünschte Trennung zwischen der Programmlogik und dem physischen IO. Die physische Repräsentation der Daten ist allein Angelegenheit des DBMS. Insbesondere können zur Performance-Steigerung informationserhaltende Änderungen des Designs vorgenommen werden, ohne die Anwenderprogramme modifizieren zu müssen. Integritätsregeln müssen in der DB-Sprache definiert und im Katalog gespeichert werden können. Die Überprüfung dieser Regeln hat unabhängig vom Anwenderprogramm zu erfolgen. Integritätsregeln gehen über die Regeln für den Primärschlüssel und die Referenzregeln weit hinaus. Das DBMS ist verteilungsunabhängig. Jedes Programm behandelt die Daten so, als wären sie alle an einem zentralen Knoten gespeichert. Existiert eine "Low-Level-Schnittstelle", so können darüber nicht die Integritätsregeln und die Zugriffsrechte ausgehebelt werden. Wäre diese Regel nicht erfüllt, so wären wesentliche Aspekte, die für den Einsatz eines DBMS sprechen, hinfällig. Strukturregeln: Beziehungen zwischen Feldern und Tabellen erfolgen nur über benannte Spalten und unnummerierte Zeilen. Einer Zeile wird keine bestimmte Position zugewiesen. Es gibt keine Wiederholungsgruppen. Alle gespeicherten Daten sind in Basistabellen enthalten. Das Ergebnis einer Abfrage ist wieder eine Tabelle, die gespeichert und weiterverarbeitet werden kann. Tabellenkopien, die als Tabellen in der Datenbank gespeichert werden, erhalten einen Eintrag im Katalog. Jede Spalte einer relationalen Tabelle kann als Attribut aufgefasst werden. Das Domänenkonzept wird unterstützt. Dies ist insbesondere für den Entwurf sowie für die referentielle Integrität wichtig: Spalten, denen die gleiche Domäne zugrunde liegt, stellen eine natürliche Verbindung dar. Jede reale Tabelle hat einen Primärschlüssel. Stammt eine Spalte aus der gleichen Domäne wie der Primärschlüssel einer Tabelle, so bildet diese Spalte einen Fremdschlüssel zu der Tabelle. Entscheidend für die Unterstützung referentieller Integrität. Manipulationsregeln Folgende Operationen sind zu unterstützen: 34 Selektion von Zeilen bzgl. der üblichen Vergleichsoperatoren, Projektion auf Spalten, Join von Tabellen aufgrund des Vergleichs von Spalten mittels Vergleichsoperatoren, Outer Join, die Division (Umkehrung der Kreuzproduktbildung), UNION (Vereinigung), INTERSECT (Durchschnittsbildung von Mengen), SET DIFFERENCE (Differenzbildung). Integritätsregeln Ein Primärschlüssel darf in keiner seiner Komponenten den Wert NULL haben. Für jeden Fremdschlüssel, der nicht NULL ist, muss es einen Eintrag mit dem übereinstimmenden Primärschlüssel in der referenzierten Tabelle geben. Anwendungsbezogene Integritätsregeln müssen von der Datenbanksprache unterstützt werden und im Katalog gespeichert sein. Hierzu gehören insbesondere: Wertebereiche für Spalten, auch in dynamischer Abhängigkeit von anderen Feldinhalten derselben oder einer anderen Tabelle, Prüfroutinen für bestimmte Ereignisse, d.h. Trigger. SQL Standard Der derzeitige Standard ist immer noch SQL92. Dieser Standard hatte eine Reihe von Vorgängern: zumindest SQL86 und SQL89. Um den "Übergang" für die DBMS-Hersteller zu erleichtern, besteht der SQL92-Standard aus drei Stufen: Entry-Level, dieser Level muss erfüllt sein, damit überhaupt von SQL92-kompatibel gesprochen werden darf, Der "Entry Level" erweitert den vorhergehenden Standard um eine Standardisierung von Fehlermeldungen sowie eine Erweiterung der Hostsprachen. Im wesentlichen handelt es sich um eine Fortschreibung von SQL/89 Intermediate-Level Der "Intermediate Level" fügt dem Standard dynamisches SQL, referentielle Aktionen, Domains, die Schemaänderungen mittels ALTER sowie den Outer Join und EXCEPT und INTERSECT hinzu. Full-Level. Der "Full Level" beschreibt den Verbindungsaufbau zwischen Client und Server, nichtsequentiell arbeitende Cursor, die nur an ein Schema gebundene Überprüfung (ASSERTION) usw. [Achilles, SQL] Der SQL92-Standard wurde 1995 und 1996 erweitert durch Hinzunahme von CLI (Call Level Interface) und 35 PSM (Persistent Stored Modules). Nachfolger SQL3, jetzt verabschiedet unter SQL 1999 Aufteilung der Dokumentation: 1. Framework 2. Foundation (SQL Kern) 3. SQL/CLI (Call Level Interface) 4. SQL/PSM (Persistent Atored Modules) 5. SQL/Temporal (Working draft) 6. SQL/MED (Management of External Data) 7. SQL/OLB (Object Language Bindings) 8. SQL Schemata (Information and Definition Schemas) 9. SQL/JRT (Working draft: Java Routines and Types) 10.SQL/XML (Working draft: XML-Related Specifications) SQL92 Dieser Abschnitt enthält ausschließlich Stichworte; es wird auf die Literatur verwiesen. Wichtige Aspekte des SQL92-Standards (Full-Level): INFORMATION_SCHEMA Constraints und CHECK-Regel DBMS-Objekte: o Schemata o Tabellen, reale und temporäre o Virtuelle Tabellen o Domänen o Zeichensätze, Übersetzungsvorschriften, Anordnungen Rechte SQL Standard Sprache besteht aus: Definitionssprache Datenretrieval Datenmanipulation Kontrolle Sprachanbindungen: Module Embedded SQL CLI JDBC 36 Sprachelemente: Datentypen, Konstanten, NULL vordefinierte Variable o CURRENT_DATE usw. o CURRENT_USER usw. skalare Funktionen o numerische Funktionen POSTION, EXTRACT, CHARACTER_LENGTH, OCTET_LENGTH, BIT_LENGTH o Zeichenkettenfunktionen o o CONVERT, LOWER, SUBSTRING, TRANSLATE, TRIM, COLLATE, UPPER, || CAST CASE mit NULLIF, COALLESCE Spaltenfunktionen AVG, COUNT, MAX, MIN, SUM Zeilenkonstruktor (Row Value Constructor) ausdruck oder (ausdruck1[, ausdruck2[,...]]) oder Tabellenkonstruktor (subquery) VALUES zk1[, zk2[,...]] Ausdrücke o skalare Ausdrücke o Tabellenausdrücke - Join-Tabellenausdruck - Tabellenname - geklammerter allgemeiner Tabellenausdruck Prädikate o einfache Prädikate BETWEEN, EXISTS, IN, IS NULL, LIKE, MATCH, OVERLAPS, UNIQUE o quantifizierte Prädikate z.B: >= ALL, >= ANY, >= SOME gefolgt von einem Subselect 37 Datenbankstruktur: SQL-Umgebung: DBMS-Instanz zusammen mit allen Datenbanken, auf die diese Instanz zugreifen kann angelegten Benutzern Programmen Katalog enthält eine Menge von SQL-Schemata, SQL-Schema ist jeweils einem Benutzer zugeordnet, aber Benutzer kann mehrere Schemata besitzen Schema enthält eine Reihe von realen Einträgen wie z.B. Tabellen, Views, etc. Katalog: eine Menge logisch zusammengehörender Tabellen, Schema: ein spezieller Ausschnitt daraus Implementation eines Kataloges: DBMS-Hersteller jedoch: Standard fordert pro Katalog genau ein spezielles Schema mit dem Namen INFORMATION_SCHEMA "Dictionary" - Metainformation aller in den Schemata gespeicherten Objekte Ein Katalog dient zur Verwaltung einer DBMS-Umgebung und enthält ein oder mehrere Schemata; auf jeden Fall gibt es in jedem Katalog das Schema INFORMATION_SCHEMA, das die Views auf die zugehörigen System-Tabellen enthält. Die Namen der Schemata innerhalb eines Kataloges müssen eindeutig sein. Jedes Schema wiederum bildet eine Verwaltungseinheit für Tabellen, die unter einem qualifizierenden Namen, dem Schema-Namen, zusammengefasst werden können. Innerhalb eines Schemas müssen die Tabellennamen eindeutig sein. Einem "Benutzer" können ein oder sogar mehrere Schemata gehören, er kann je nach Autorisierung sogar eigene Schemata anlegen. ... Ein voll qualifizierter Tabellenname besteht somit aus folgenden Teilen: katalog.schema.tabelle. ... [Achilles, SQL, Seite 19] INFORMATION_SCHEMA: Der Standard beschreibt zwar nicht, wie das DBMS die Daten zur Verwaltung der Datenbankobjekte zu speichern hat, aber er beschreibt, in welcher Form eine gewisse Mindestinformation über die Objekte des jeweiligen Katalogs im Schema INFORMATION_SCHEMA als nicht änderbare SQL-Views zur Verfügung gestellt werden muss. Es müssen zumindest folgende Views vorhanden sein: INFORMATON_SCHEMA_CATALOG_NAME enthält ausschließlich den Namen des Katalogs, SCHEMATA beschreibt alle Schemata, die zu diesem Katalog gehören und vom Benutzer angelegt worden sind, DOMAINS zeigt alle zugreifbaren Domains an, TABLES enthält alle zugreifbaren realen Tabellen ... VIEWS beschreibt alle zugreifbaren Views, COLUMNS … TABLE_PRIVILEGES, COLUMN_PRIVILEGES, USAGE_PRIVILEGES gibt die vom Benutzer vergebenen Rechte bzw. die von ihm empfangenen Rechte an jeweiligen Objekten an, zeigen alle vom Benutzer angelegten zu überwachenden Einschränkungen der entsprechenden Objekte an, DOMAIN_CONSTRAINTS 38 KEY_COLUMN_USAGE beschreibt alle Spalten von realen Tabellen, die als Schlüssel- oder Fremdschlüsselspalten vom Benutzer eingerichtet wurden, ASSERTIONS beschreibt alle vom Benutzer angelegten generellen Einschränkungen, CHARACTER_SETS, COLLATIONS, TRANSLATIONS enthält alle Zeichensätze, Anordnungen und Übersetzungen, auf die der Benutzer zugreifen darf, VIEW_TABLE_USAGE, VIEW_COLUMN_USAGE beschreibt, von welchen Tabellen bzw. Spalten Views abhängen, die der Benutzer erzeugt hat, CONSTRAINT_TABLE_USAGE, CONSTRAINT_COLUMN_USAGE gibt für alle vom Benutzer erzeugten Einschränkungen an, von welchen Tabellen bzw. Spalten sie abhängen, COLUMN_DOMAIN_USAGE gibt für alle zugreifbaren Spalten die Domäne an, die zur Definition der jeweiligen Spalte verwendet wurde, SQL_LANGUAGES besagt, welche SQL-Dialekte (SQL 86/89/92) unterstützt werden. INFORMATION_SCHEMA_CATALOG_NAME_CARDINALITY (Assertion) ist eine Einschränkung, die garantiert, dass im View INFORMATION_SCHEMA_CATALOG_NAME genau eine Zeile existiert, SQL_IDENTIFIER (Domain) ist eine Domäne, die die gültigen Namen von SQL-Bezeichnern beschreibt, CHARACTER_DOMAIN (Domain) enthält Informationen über die gültigen Zeichensätze, CARDINAL_NUMBERS (Domain) ist die Domäne, die die zulässigen nicht-negativen ganzen Zahlen beschreibt [Achilles, SQL, Seite 100] Benennung (voll-qualifiziert): Zur eindeutigen Identifizierung müssen die einzelnen gespeicherten Datenbankobjekte benannt werden. Die Konventionen sind für SQL/92 bereits durch die gegebene Struktur vorgeschrieben, ein voll qualifizierter Name wird gebildet durch: katalog_name.schema_name.objekt_name Vielfach reicht es, nur schema_name.objekt_name oder gar objekt_name anzugeben, da der mit der Sitzung verbundene Katalog-Name bzw. Schema-Name ergänzt wird. Eine volle Qualifizierung ist nur dann nötig, wenn auf Objekte zugegriffen werden soll, die nicht im voreingestellten Schema bzw. Katalog liegen. Auch Spalten müssen ggf. qualifiziert werden: katalog_name.schema_name.objekt_name.spalten_name [Achilles, SQL, Seite 102] SQL-Sitzung: SQL-Anweisungen können nur durchgeführt werden, wenn eine Verbindung zum DBMS aufgebaut worden ist. Hierzu dient die Connect-Anweisung. Mit dem Aufbau einer Verbindung wird eine SQL-Sitzung erstellt, innerhalb derer eine Reihe von Transaktionen gestartet werden können, bis die Sitzung schließlich mit DISCONNECT beendet wird. Verbindung: CONNECT Ende mit: DISCONNECT Eine Anwendung kann nacheinander mehrere Verbindungen und damit mehrere Sitzungen aufbauen; die jeweils vorhergehenden Sitzungen werden damit vorübergehend in Ruhe versetzt, können aber jederzeit durch eine SET CONNECTIONAnweisung wieder aktiviert werden. [Achilles, SQL, Seite 103] CONNECT TO ... SET CONNECTION ... 39 Zeichensätze: zur Unterstützung internationaler Zeichensätze eigene Zeichensätze können vereinbart werden CREATE CHARACTER SET alphabetische Sortierreihenfolge kann vereinbart werden CREATE COLLATION Übersetzungsvorschrift kann vereinbart werden CREATE TRANSLATION Constraints: Constraints sind Einschränkungen, die die Daten erfüllen müssen, um in die Tabellen eingetragen werden zu können. Damit wird sichergestellt, dass bestimmte Regeln – Referenzintegrität, entsprechende Datenbereiche usw. – vom DBMS systemseitig eingehalten werden. Einschränkungen können für ein Schema mit Hilfe von CREATE ASSERTION bzw. für eine Domain, eine Tabelle oder für eine Tabellenspalte innerhalb der jeweiligen CREATE-Anweisung angelegt werden. Im ersten Fall wird eine Einschränkung durch die CREATE ASSERTION-Anweisung mit einem Namen versehen, da es sich um ein eigenes Datenbankobjekt handelt. In den anderen drei Fällen kann die Einschränkung mit einem Namen versehen werden. Durch die Benennung ist es möglich, später eine benannte Einschränkung durch Löschen mittels DROP wieder aufzuheben. [Achilles, SQL, Seite 109] Constraints (benannt oder unbenannt) sind möglich für Schema (nur unbenannt) Domain Tabelle Tabellenspalte Constraints können sofort oder erst am Ende einer Transaktion (verzögert) überprüft werden (IMMEDIATE / DEFERRED) Sie lauten somit (innerhalb der jeweiligen CREATE Anweisung): [CONSTRAINT name] einschränkung [[INITIALLY DEFERRED | INITIALLY IMMEDIATE] [[NOT] DEFERRABLE] ] Constraints (Einschränkung): CHECK (prädikat) Die Einschränkung wirkt, als würde entsprechend die Anweisung: SELECT * FROM tables WHERE NOT (prädikat) ausgeführt. 40 Enthält diese Ergebnistabelle Zeilen, so wäre die CHECK-Einschränkung verletzt. Constraints (Einschränkung) in einer Tabellendefinition: Tabelleneinschränkungen werden aktiviert, wenn Änderungen an den Daten der Tabellen vorgenommen werden. ... Neben der CHECK-Einschränkung können bei den Tabellenund Spalteneinschränkungen auch andere Einschränkungen vereinbart werden, wie z.B. Primärschlüssel, weitere Schlüsselkandidaten, Fremdschlüssel für die Überwachung referentieller Integrität usw. ... Alternativ kann neben der bereits diskutierten CHECK-Einschränkung der Primärschlüssel mit PRIMARY KEY angegeben, es kann ein Schlüsselkandidat mit UNIQUE vereinbart oder eine Referenzregel für Fremdschlüssel mit FOREIGN KEY aufgestellt werden. Primärschlüssel, Schlüsselkandidaten und Referenzregeln können sich bei dieser Art der Einschränkung auf mehrere Spalten beziehen. [Achilles, SQL, Seite 111] PRIMARY KEY ( ... ) UNIQUE ( ... ) FOREIGN KEY ( ... ) REFERENCES tabelle [((...)] [ MATCH {FULL|PARTIAL} ] [ ON UPDATE {CASCADE|SET NULL|SET DEFAULT|NO ACTION} ] [ ON DELETE {CASCADE|SET NULL|SET DEFAULT|NO ACTION} ] Primärschlüssel, Eindeutigkeit und Fremdschlüssel-Vereinbarungen CASCADE: wenn eine Zeile aus der referenzierten Tabelle gelöscht oder geändert wird, werden auch automatisch alle (eindeutig) referenzierenden Zeilen aus der refernzierenden Tabelle entfernt bzw. geändert. SET DEFAULT, SET NULL: wird eine Zeile der referenzierten Tabelle gelöscht oder geändert, so werden alle Teile des Fremschlüssels der (eindeutig) referenzierenden Zeilen auf den Default-Wert bzw. den NULL-Wert gesetzt. [Achilles, SQL, Seite 116] Constraints (Einschränkung) in einer Spaltendefinition: Spalteneinschränkungen werden aktiviert, wenn eine Datenänderung diese Spalte der Tabelle betrifft, also insbesondere bei Einfügen oder Löschen in der Tabelle. NOT NULL PRIMARY KEY UNIQUE REFERENCES tabelle [((...)] [ MATCH {FULL|PARTIAL} ] [ ON UPDATE {CASCADE|SET NULL|SET DEFAULT|NO ACTION} ] [ ON DELETE {CASCADE|SET NULL|SET DEFAULT|NO ACTION} ] 41 Unzulässigkeit von NULL-Werten, Primärschlüssel, Eindeutigkeit und FremdschlüsselVereinbarung DDL - Data Definition Language: Ursprünglich gingen die ersten Versionen des SQL-Standards von der Vorstellung aus, dass die Struktur einer Datenbank zeitlich festgeschrieben und durch die Struktur der Tabellen und Zugriffsrechte festgelegt ist. Deshalb war ursprünglich nur die Möglichkeit vorgesehen, Datenbankobjekte anlegen zu können, die dann nicht mehr verändert oder gelöscht werden konnten. Um Zugriffsrechte überprüfen zu können, wurde beim Anlegen eines Objekts der Eigentümer mit vermerkt. Da aber auch Datenbank-Anwendungen den üblichen Software-Zyklen unterliegen, boten viele DBMS-Hersteller die Möglichkeit an, Datenbankobjekte zu löschen bzw. zu verändern. Ein Teil dieser von den Anwendern benötigten Funktionalität wurde bereits in den vergangenen Standard aufgenommen, der Sprachstandard SQL/92 geht darüber noch hinaus. Je mehr Datenbankobjekte interaktiv geändert werden können, desto wichtiger wird die Information über die vorhandenen DBMS-Objekte. In diesem Kontext zeigt sich die Bedeutung der durch SQL/92 vereinheitlichten Beschreibung der Datenbankobjekte. Unabhängig vom jeweils verwendeten DBMS und seinen spezifischen Fähigkeiten muss eine standardisierte Darstellung der wichtigsten Informationen aller DBMS-Objekte eines Kataloges im Schema INFORMATION_SCHEMA existieren. ... Schemata: Beim Anlegen eines Schemas wird ein Mittel bereitgestellt, um inhaltlich zusammengehörige Objekte logisch zu verwalten und unter einheitlicher Namensgebung zugreifbar zu machen. Beim Anlegen eines Schemas können gleichzeitig Datenbankobjekte erzeugt werden. Dabei sind alle Objekte, die in einem Schema angelegt werden können, zugelassen. Da zu den Objekten auch Zugriffsrechte zählen, können auch diese vergeben werden. Werden bei Objekten, die als Teil einer Schema-Erzeugung zugleich mit vereinbart werden, qualifizierte Namen verwendet, so muss derjenige Namensbestandteil, der dem Schema entspricht, mit dem Namen des erzeugten Schemas übereinstimmen. Da alle Objekte, die bei einer CREATE SCHEMA-Anweisung vereinbart sind, zusammen mit dem Schema angelegt werden, können Objekte erzeugt werden, die sich gegenseitig aufeinander beziehen. So ist es damit möglich, zwei Tabellen anzulegen, bei denen jede einen Fremdschlüssel auf die jeweils andere enthält. Die Syntax lautet: CREATE SCHEMA { schema_name | AUTHORIZATION authid | schema_name AUTHORIZATION authid } [ DEFAUTLT CHARACTER SET charset ] [ { CREATE DOMAIN domain_definition | CREATE TABLE table_definition | CREATE VIEW view_definition | CREATE ASSERTION regel_definition | CREATE CHARACTER SET charset_definition | CREATE COLLATION anordnungs_definition | CREATE TRANSLATION übersetzungs_definition | GRANT rechte_definition } 42 ] […]…; ...Der Name des Schemas - schema_name – kann voll qualifiziert sein: cluster_name.catalog_name.schema_name. Werden Cluster und Katalog nicht angegeben, so wird eine implementationsabhängige Voreinstellung benutzt. Wird für das Schema kein Name angegeben, so ist die mittels AUTHORIZATION spezifizierte authid zugleich Name des Schemas. Dies entspricht dem alten Standard, bei dem davon ausgegangen wurde, dass einem Benutzer (durch authid angegeben) auch nur ein Schema zugeordnet ist. Der Name des Schemas muss in jedem Falle im Katalog eindeutig sein. Das Recht, Schemata anzulegen, ist implementationsabhängig geregelt. Sofern keine AUTHORIZATION-Klausel verwendet wird, ist derjenige, der das Schema erzeugt, auch dessen Eigentümer.... Wird jedoch die AUTHORIZATION-Klausel verwendet, so wird der durch authid angegebene Benutzer Eigentümer des angelegten Schemas sowie der darin enthaltenen Objekte. [Achilles, SQL, Seite 120] temporäre Tabellen: In temporären Tabellen abgelegte Daten werden nur innerhalb der Sitzung aufbewahrt und vom System anschließend gelöscht. Es kann sogar erzwungen werden, dass die Daten jedes Mal am Ende einer Transaktion gelöscht werden. Obwohl temporäre Tabellen unter einem Namen im Schema abgelegt sind, kann ein Benutzer dennoch nur auf diejenigen Daten zugreifen, die er selbst während der Sitzung (bzw. Transaktion) in der Tabelle gespeichert hat. Greift ein anderer Benutzer gleichzeitig auf dieselbe temporäre Tabelle zu, so "sieht" er dennoch ausschließlich seine eigenen Daten. CREATE TABLE {GLOBAL|LOCAL} TEMPORARY name ... [ ON COMMIT {DELETE|PRESERVE} ROWS ] Der Unterschied zwischen globalen und lokalen temporären Tabellen liegt im Gültigkeitsbereich. Während auf globale temporäre Tabellen analog zu globalen Variablen von allen Programmen und Modulen während einer Sitzung auf die gemeinsamen Daten zugegriffen werden kann, wird für lokale temporäre Tabellen für jede Übersetzungseinheit eine eigene Instanz angelegt, d.h. die Daten können nicht zwischen den Modulen ausgetauscht werden – analog zu lokalen Variablen. Die ON COMMIT-Klausel beschreibt, ob die Daten jeweils am Ende einer Transaktion gelöscht (DELETE ROWS) oder bis zum Sitzungsende aufbewahrt werden sollen (PRESERVE ROWS). Voreingestellt ist ON COMMIT DELETE ROWS. Sollte eine Transaktion mit ROLLBACK abgebrochen werden, so werden auch bzgl. temporärer Tabellen alle in der Transaktion vorgenommenen Änderungen zurückgesetzt. Besonderheiten: - Gültigkeitsbereich (GLOBAL, LOCAL) Aufbewahrungsdauer(ON COMMIT DELETE ROWS/PRESERVE ROWS) Foreign Key handelt es sich um eine globale temporäre Tabelle, so muss auch die Tabelle, auf die verwiesen wird, eine globale temporäre Tabelle sein, handelt es sich um eine lokale temporäre Tabelle, so kann auf eine globale oder lokale temporäre Tabelle verwiesen werden, 43 ist zusätzlich ON COMMIT DELETE ROWS für diejenige Tabelle vereinbart, auf die verwiesen wird, so muss dies auch für die Tabelle mit der FOREIGN KEY-Klausel gelten. Check handelt es sich um eine globale temporäre Tabelle, so darf das Prädikat ebenfalls nur auf globale temporäre Tabellen Bezug nehmen, bei einer lokalen temporären Tabelle dürfen globale und temporäre Tabellen angesprochen werden, falls für die Tabelle, die die CHECK-Klausel enthält, ON COMMIT PRESERVE ROWS vereinbart wurde, kann keine Tabelle mit der Vereinbarung ON COMMIT DELETE ROWS referenziert werden. [Achille, SQL, Seite 123] - - Views: Neben realen und temporären Tabellen sind virtuelle Tabellen (view) ein wichtiges Mittel, um eine Datenbank zu strukturieren. Nur die Beschreibung, wie die virtuellen Tabellen erzeugt werden, ist in der Datenbank gespeichert. In den SQL-Anweisungen werden virtuelle Tabellen wie reale oder temporäre Tabellen verwendet. Im Augenblick des Zugriffs werden die Daten aufgrund der gespeicherten Beschreibung zusammengestellt. Gründe: Information kann auf Sicht des jeweiligen Benutzers angepasst werden Basis-Tabellen können unabhängig von Benutzersicht strukturell verändert werden Die Struktur der Tabellen, mit denen der einzelne Benutzer umgeht, wird weitgehend unabhängig von derjenigen Struktur, in der die Daten gespeichert werden. Die realen Tabellen können strukturell verändert werden, um eine bessere Gesamtleistung des Systems zu erzielen, ohne dass die Benutzer davon etwas bemerken oder in ihrer Arbeit gestört werden. Virtuelle Tabellen können – je nach Definition – einen Ausschnitt aus einer, aber auch eine Zusammenfassung mehrerer realer Tabellen zeichen. Damit wird eine weitere Unabhängigkeit von der physichen Speicherung der Daten erzielt. Datenschutz Je nach den Aufgaben, die einzelne Mitarbeiter zu bearbeiten haben, werden die benötigten Daten in virtuellen Tabellen bereitgestellt, und Rechte für diese Tabellen an die Mitarbeiter vergeben. Die Mitarbeiter können dann nur auf diejenigen Daten zugreifen, für die sie explizit Rechte eingeräumt bekommen haben, andere Daten können sie nicht sehen. Die Beschreibung, wie die virtuelle Tabelle zu erzeugen ist, erfolgt mit Hilfe einer SELECT-Anweisung oder allgemeiner mit einem Tabellenausdruck. Dabei sollte beachtet werden, dass diese SELECT-Anweisung keine ORDER BY-Klausel besitzen kann, da eine Tabelle prinzipiell eine nicht geordnete Menge von Tupeln ist. Genauer: ORDER BY ist nicht Bestandteil eines Tabellenausdrucks. CREATE VIEW view_name AS SELECT ... 44 ... [ WITH [CASCADED|LOCAL] CHECK OPTION ] nicht erlaubt rekursive Definition ausgeschlossen Überprüfung der VIEW-Definition Datenänderung durch Views: änderbare VIEWs ORDER BY Virtuelle Tabellen werden in Schemata erzeugt, sie können nur vom Eigentümer des entsprechenden Schemas angelegt werden, view_name muss eindeutig unter allen realen, temporären und virtuellen Tabellennamen sein und der Eigentümer muss die benötigten Rechte an allen Tabellen besitzen, die in der Anfrage select_anweisung angesprochen werden. Rekursive Definitionen sind dabei natürlich ausgeschlossen: betrachtet man die in select_anweisung angesprochenen Tabellen, so dürfen diese keine Tabellen enthalten, die direkt oder indirekt auf die gerade definierte virtuelle Tabelle Bezug nehmen. Jede in select_anweisung enthaltene virtuelle Tabelle erzeugt eine Ebene, die aufgelöst werden muss, ohne auf die hier definierte Tabelle view_name zuzugreifen.[Achilles, SQL, Seite 125] Domains: Mit der CREATE DOMAIN-Anweisung können eigene Wertebereiche (DOMAIN) vereinbart werden. Durch Verwendung von getrennten Wertebereichen kann man z.B. logische Unterschiede zwischen Spalten ausdrücken: so können z.B. Bestellnummern und Telefonnummern gleich aussehen, ein Vergleich macht aber keinen Sinn. Werden eigene Domänen gebildet, so kann kein Vergleich zwischen Werten zweier unterschiedlicher Domänen vorgenommen werden, es sind keine Vergleichsoperatoren dafür vorgesehen. Neben dem zugrundeliegenden Datentyp kann ein Default-Wert angegeben werden, es kann eine Einschränkung in Form einer CHECK-Klausel vereinbart werden (constraint). Über die COLLATE-Klausel wird die zugrundeliegende Anordnung bei Zeichenketten vereinbart. CREATE DOMAIN ... [ DEFAULT ... ] [ constraint ] [ COLLATE ].... permamente Tabellen (Basis-Tabellen): CREATE TABLE ... ( spalte ... [ spalten_constraint ] [ DEFAULT ... ] [ COLLATE ... ], ... [ tabellen_constraint, ... ] ) CREATE TABLE lager (regal SMALLINT NOT NULL, fach SMALLINT NOT NULL, tnummer CHARACTER(5), 45 anzahl SMALLINT, mgewicht FLOAT NOT NULL, PRIMARY KEY (regal, fach) ) [Achilles, SQL, 123] Assertions (An Schemata gebundene Einschränkungen): Bei dieser Einschränkung (Constraint) handelt es sich um ein eigenständiges Datenbankobjekt innerhalb eines Schemas, das mit Hilfe einer CHECK-Klausel eine allgemeine durch das DBMS zu überprüfende Regel formuliert. Wird in einer SQLAnweisung diese Regel verletzt, so führt das DBMS die SQL-Anweisung nicht aus; in der Regel muss die Transaktion, innerhalb derer die Anweisung ausgeführt wurde, mit ROLLBACK zurückgesetzt werden. Diese Einschränkung existiert unabhängig von irgendeiner Tabelle und kann in dem Prädikat der CHECK-Klausel auf jede reale Tabelle (bzw. Views, denen ausschließlich reale Tabellen zugrunde liegen) des Schemas Zugriff nehmen. Mit dieser Konstruktion lässt sich z.B. überprüfen, ob eine Tabelle nicht leer ist. Dies kann nicht innerhalb der Tabellendefinition CREATE TABLE in einer Spalten- oder Tabelleneinschränkung erzielt werden, da diese erst in dem Moment überprüft werden, wenn eine Datenmanipulation vorgenommen wird, die die Tabelle betrifft. Die Syntax lautet: CREATE ASSERTION constraint_name... CHECK ( prädikat ) [ [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ [NOT] DEFERRABLE ] Im Gegensatz zu Tabellen-Einschränkungen gelten diese Einschränkungen generell Tabellen-Einschränkungen werden nur überprüft, wenn eine Datenänderung vorgenommen wird, die diese Tabelle betrifft typische Erweiterungen: CREATE FUNCTION CREATE INDEX CREATE PROCEDURE CREATE TABLESPACE CREATE TRIGGER Ergänzungen der Standard-Anweisungen um Angaben, die den Speicherort festlegen das Logging beeinflussen Clustern/Partitionieren unterstützen Art der Replikation beeinflussen ... typische Erweiterung: Trigger Trigger sind für eine Reihe von Aufgaben wichtig: 46 - - - zum Replizieren von Änderungen, d.h. eine Änderung in einer Tabelle wird – mit einem gewissen Zeitverzug – in einer anderen Tabelle, die sich in der Regel in einer anderen Datenbank auf einem anderen Rechner befindet, nachvollzogen, um komplexe Geschäftsregeln nachzubilden, die über referentielle Integrität hinausgehen, um Änderungen zu protokollieren, zum automatischen Erzeugen redundanter Informationen, z.B. um Spaltensummen in einer anderen Tabelle zum schnellen Zugriff bereitzustellen und für den Datenschutz. Als Beispiel sollen die Aktionen, die den Lagerbestand verändern, in einer Tabelle lagerprotokoll mitgeführt werden. Wird eine geeignete Struktur der protokollierenden Tabelle lagerprotokoll vorausgesetzt, könnte das Kommando zur Erzeugung eines Triggers, der alle Änderungen in der Tabelle lager mithält, lauten: CREATE TRIGGER lagerprotokoll AFTER UPDATE ON lager FOR EACH ROW BEGIN ATOMIC INSERT INTO lagerprotokoll VALUES (USER, CURRENT TIMESTAMP, lager.tnummer, lager.anzahl) END Dieser Trigger wird ausgelöst, wenn eine UPDATE-Anweisung auf die Tabelle lager erfolgt. Die im Trigger vereinbarte INSERT-Anweisung protokolliert dann, wer die Änderung in der Datenbank vornimmt, zu welchem Zeitpunkt die Änderung erfolgt und welche Ware in welcher Menge betroffen ist. Entsprechende Trigger müssten noch für INSERT- und DELETE-Operationen auf der Tabelle lager angelegt werden. Probleme können bei Triggern dadurch entstehen, dass ein Trigger weitere Trigger auslösen kann: die Operationen werden bei unvorsichtigem Gebrauch kaum noch nachvollziehbar, die Zahl der Änderungen innerhalb einer Transaktion kann "explosionsartig" anwachsen oder es gar zu Deadlocks kommen. CREATE TRIGGER Diese Anweisung dient dazu, Veränderungen an realen Tabellen über den Kern des DBMS mit bestimmten Triggeraktionen zu verbinden. Trigger können dazu benutzt werden, zusammen mit Einschränkungen Integritätsregeln zu unterstützen, automatische Datenkonvertierungen vorzunehmen, Warnungen zu erzeugen, Daten zugleich in andere Tabellen (z.B. aggregierte Werte) einzutragen usw. Veränderung sind Einfügen (INSERT), Ändern (UPDATE) bzw. Löschen (DELETE). Der Trigger wird spezifisch für eine dieser Veränderungen an einer bestimmten Tabelle vereinbart. Die vereinbarte Triggeraktion kann vor (NO CASCADE BEFORE) oder nach (AFTER) der Datenänderung, die den Trigger auslöst, ausgeführt werden. Die erlaubten Triggeraktionen hängen davon ab, ob die Triggeraktion vorher oder nachher ausgeführt werden soll; nach der Veränderung sind SELECT-, INSERT-, DELETE-, UPDATE-Anweisungen und das Signalisieren von SQLSTATE erlaubt, vor der Veränderung hingegen nur die SELECT-anweisung, das Setzen eines geänderten Wertes (vergleichbar dem UPDATE...SET) und das signalisieren von SQLSTATE. ... 47 NO CASCADE BEFORE definiert einen Trigger, der vor jeder Datenänderung ausgeführt werden soll, AFTER einen Trigger, der nach der Datenänderung in Kraft tritt. ON tabelle gibt die Tabelle an, für die der jeweilige Trigger erzeugt werden soll, INSERT, ... die Änderungsaktion auf der Tabelle, mit der der Trigger verknüpft werden soll. UPDATE kann insbesondere auf spezielle Spalten der Tabelle eingeschränkt werden. In der REFERENCING-Klausel können Referenznamen für die Zeilen bzw. Tabellen vor (OLD...) und nach (NEW...) der Datenänderung vereinbart werden. Die Klausel FOR EACH STATEMENT kann nur verwendet werden, wenn es sich um einen Trigger, der mit AFTER vereinbart wurde, handelt. In diesem Falle wird nur einmal auf die gesamte Änderungsanweisung reagiert, auch dann, wenn durch die Anweisung keine Daten in der Tabelle tabelle verändert wurden. Ansonsten gilt FOR EACH ROW, d.h. auf jede veränderte Zeile wird Bezug genommen. [Achilles, SQL, 141] CREATE TRIGGER ... { BEFORE | AFTER | INSTEAD OF } { INSERT | DELETE | UPDATE } ON tabelle... [ REFERENCING [ OLD AS ref_old ] [ NEW AS ref_new ] ] { FOR EACH ROW | FOR EACH STATEMENT } [ WHEN ( bedingung ) ] trigger_aktion Rechte: Ein Datenschutz wird dadurch erreicht, dass bei der Definition eines Datenbankobjekts als Eigentümer diejenige Benutzerkennung gilt, der das Schema gehört, in dem das Objekt angelegt wurde. Bei einem Schema selbst werden die Eigentümerrechte in der Regel durch die AUTHORIZATION-Klausel geregelt. Der Eigentümer eines Objektes kann Rechte an diesem Objekt an andere Benutzer weitergeben. Sollen Rechte an alle Benutzer vergeben werden, so werden sie an PUBLIC vergeben. Dies gilt für reale, temporäre und virtuelle Tabellen, Domänen, Zeichensätze, Anordnungen und Übersetzungsvorschriften. Rechte an Schemata und Assertions lassen sich nicht vergeben. Als Recht kann die Erlaubnis zum Auswählen, Einfügen, Ändern bzw. Löschen von Datenzeilen einer Tabelle gegeben werden. Weiter können das Recht, auf Spalten einer Tabelle zu referenzieren (REFERENCES), sowie das Recht USAGE vergeben werden. Diese Rechte können in beliebiger Kombination zusammengestellt werden. Der Eigentümer der Tabelle kann die Benutzer zugleich ermächtigen, die ihnen erteilten Rechte weiterzugeben. Dazu dient in der unten beschriebenen Syntax die Klausel WITH GRANT OPTION. ... Wie in der folgenden Kommandobeschreibung deutlich wird, können die Rechte für INSERT, UPDATE und REFERENCES auf bestimmte Spalten eingeschränkt werden. Fehlt eine Spaltenangabe, so gelten diese Rechte für alle Tabellenspalten. 48 ALL PRIVILEGES bezieht sich auf alle anwendbaren Rechte, die vergeben werden können. Insbesondere ist ALL PRIVILEGES die einzige Form, die für temporäre Tabellen vergeben werden darf. GRANT { ALL PRIVILEGES | SELECT | DELETE | INSERT [( ... )] | UPDATE [( ... )] | REFERENCES [( ... )] } ON TABLE table_name... TO { benutzer1 [, benutzer2,...]} | PUBLIC [ WITH GRANT OPTION ] Für Datenbankobjekte wie DOMAIN, COLLATION usw. lautet die Rechtevergabe GRANT USAGE ON ... TO ... | PUBLIC [ WITH GRANT OPTION ] Beispiele: Muss der Lagerverwalter die Anzahl der Teile in der Tabelle teile verändern und die übrige Information sehen können, so müssen ihm folgende Rechte eingeräumt werden: GRANT select, update(anzahl)ON lager TO lagerverwalter Soll der Lagerverwalter in der Datenbank nachhalten, dass Teile dem Lager entnommen, hinzugefügt oder umgelagert worden sind, so müssen ihm weitergehende Rechte eingeräumt werden: GRANT select, update(tnummer, anzahl)ON lager TO lagerverwalter Entzug von Rechten: Nur derjenige, der ein Recht vergeben hat, kann es auch wieder entziehen. Mit dem Entzug eines Rechtes werden auch alle davon abhängigen Rechte zurückgenommen. REVOKE [ GRANT OPTION FOR ] recht ON objekt FROM benutzer1 | PUBLIC { CASCADE | RESTRICT } GRANT OPTION FOR entzieht die GRANT OPTION CASCADE löscht auch abhängige Objekte Falls RESTRICT angegeben ist, wird das Recht oder – sofern die Option GRANT OPTION FOR angegeben ist – nur die Option WITH GRANT OPTION entzogen, wenn davon keine weiteren Rechte direkt oder indirekt und keine anderen Objekte wie virtuelle Tabellen abhängig sind. Ist dies hingegen der Fall, so endet REVOKE mit einem Fehler. Ist CASCADE zusammen mit GRANT OPTION FOR vereinbart, so bleibt das vergebene Recht erhalten, jedoch wird die Option WITH GRANT OPTION und alle abhängigen Rechte entfernt sowie die von den entfernten Rechten abhängigen Objekte gelöscht. 49 Ist CASCADE ohne GRANT OPTION FOR angegeben, so werden das Recht und alle abhängigen Rechte und Objekte gelöscht. Veränderung des SQL-Environments: SET CONNECTION ... Sind mehrere Sitzungen mit der CONNECT-Anweisung aufgebaut, so kann die derzeit aktive Sitzung damit in den Ruhezustand versetzt und die benannte Verbindung aktiviert werden. SET CONSTRAINTS ... { DERFERRED | IMMEDIATE } SET TRANSACTION { ISOLOATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZE } | { READ ONLY | READ WRITE } ... | } SET CONNECTION dient dazu, die aktive Verbindung zu SET CONSTRAINTS verändert den Zeitpunkt, zu dem SET o o o wechseln die Prüfung durchgeführt wird. Der Zeitpunkt der Überprüfung wird mit DEFERRED auf das Transaktionsende, mit IMMEDIATE sofort nach Ausführung jeder Anweisung gelgt. TRANSATION beeinflusst die Performance (Nebenläufigkeit von Transaktionen) sowie die gegenseitige Beeinflussung: volle Serialisierbarkeit: SERIALIZE Parallele Transaktionen, die SERIALIZABLE sind, werden vom DBMS so verwaltet, dass die Transaktionen immer die Datenbank von einem konsistenten Zustand in den neuen konsistenten Zustand überführen. Aufgrund der internen Sperren, die das DBMS zur Konsistenzverwahrung setzen muss, können sich solche Transaktionen gegenseitig behindern. Wenn erlaubt ist, dass bei erneutem (gleichen) SELECT innerhalb einer Transaktion auch Datensätze erscheinen können, die von anderen Transaktionen inzwischen eingefügt wurden: REPEATABLE READ (Zeilen, die gelesen wurden, bleiben unverändert), Phantom Read, Eine Transaktion liest eine Menge von Zeilen, die einer Suchbedingung genügen, eine andere Transaktion fügt weitere Zeilen mit INSERT ein oder ändert mit UPDATE so, dass weitere Zeilen die Suchbedingung der ersten Transaktion erfüllen. Stellt die erste Transaktion die gleiche Suchanfrage noch einmal, so bekommt sie eine andere Ergebnistabelle zurückgeliefert. REPEATABLE READ erlaubt dieses Phänomen wenn bei erneutem gleichen SELECT innerhalb einer Transaktion auch die gelesenen Zeilen von einer anderen Transaktion geändert werden dürfen: READ COMMITTED ,Non-repeatable Read, nachdem eine 50 Transaktion eine Zeile gelesen hat, ändert oder löscht eine zweite Transaktion diese Zeile und schreibt die Änderung mit COMMIT fest, bevor die erste Transaktion abgeschlossen wird. Sollte die erste Transaktion versuchen, dieselben Daten wieder zu lesen, so bekommt sie andere Ergebnisse als beim ersten Mal. READ COMMITED lässt neben Phantom Read auch das Phänomen Non-repeatable Read zu. wenn auch Zeilen gelesen werden dürfen, die von anderen Transaktionen noch nicht freigegeben wurden: READ UNCOMMITTED Dirty Read, eine Transaktion liest eine von einer anderen Transaktion geänderte Zeile, bevor die zweite Transaktion diese Zeile mit Commit freigegeben hat; bricht die zweite Transaktion ihre Transaktion nun stattdessen mit Rollback ab, so wurde eine Zeile gelesen, die zu keinem konsistenten Zustand der Datenbank gehört hat. Nur Read Committed lässt alle drei Phänomene zu; aus diesem Grund gilt bei Angabe von Read Uncommitted die weitere Voreinstellung Read only, d.h. die Transaktion soll typischerweise nur lesen und statische Informationen gewinnen. Der Parallelisierungsgrad lesender Transaktionen wird dadurch erhöht. [Achilles, SQL] o DML – Datenretrieval: Sprachelemente, die zur Veränderung des Datenbestandes einer Datenbank sowie zum Suchen innhalb des Datenbestandes dienen. SELECT FROM WHERE GROUP BY HAVING .... .... .... .... .... JOIN tabelle1 (spalte) in der FROM-Klausel: JOIN tabelle2 ON tabelle1 USING tabelle1 NATURAL JOIN ON tabelle2 und weitere Tabellenausdrücke Unteranfragen - ungebunden: in einer Subquery wird eine Ergebnismenge ermittelt und ein Vergleich mit einem Record (ggf. mit Allquantor) durchgeführt Unteranfrage - gebunden: durch Einführung einer Tabellenreferenz und Benutzung der Referenz in der Subquery wird die Subquery jeweils für die gerade betrachtete Zeile berechnet SQL stellt die Möglichkeit zur Verfügung, die Unteranfrage in Abhängigkeit von der aktuell betrachteten Zeile der übergeordneten 51 Anfrage zu ermitteln. Hierzu bedient sich SQL der in der FROM-Klausel festgelegten Referenznamen. Soll nachgeschaut werden, welche Teile nachzubestellen sind, so muss für jede Teilenummer geprüft werden, ob die gelagerte Menge unter das vereinbarte Minimum gefallen ist. Die Formulierung deutet schon auf die Bindung zwischen übergeordneter Anfrage und Unteranfrage hin. In SQL kann eine gebundene Unteranfrage folgendermaßen erzeugt werden: SELECT tnummer FROM teile tx WHERE minimum > (SELECT SUM(anzahl) FROM lager WHERE tnummer = tx.tnummer) Durch die Qualifizierung mit dem Referenznamen tx in der Spaltenreferenz tx.tnummer wird die Auswertung der Unteranfrage an die gerade ausgewählte Zeile der übergeordneten Anfrage gebunden. Verbindung von SELECT-Anfragen: SELECT .... FROM .... WHERE .... .... UNION | INTERSECT | EXCEPT SELECT FROM WHERE .... .... .... .... Geordnete SELECT-Anfragen: SELECT-Anweisung ORDER BY .... Problem mit NULL: Es gilt nicht allgemein SUM(spalte)/COUNT(*) = AVG(spalte) da bei AVG die Null-Werte in die Berechnung miteinfließen DML - Einfügen INSERT INTO tabelle [ (spalte1 ,... ) ] { SELECT-Anweisung | Tabellen-Konstruktor } DML - Löschen DELETE FROM tabelle [ WHERE CURRENT OF cursor | WHERE Suchbedingung 52 ] DML - Ändern UPDATE tabelle SET spaltei = { ausdrucki | NULL | DEFAULT } .... [ WHERE CURRENT OF cursor | WHERE Suchbedingung ] DCL - Datenkontrolle Die Datenkontrollsprache dient dazu, die Transaktionseinheiten festzulegen und Sperren auf die benutzten Datenbankobjekte anzufordern. Transaktionen Eine Transaktion ist eine Folge von Datenbankoperationen, die für die Datensicherung und die Synchronisation eine Einheit bildet. Diese Einheit soll die Datenbank aus einem konsistenten Zustand in einen neuen konsistenten Zustand überführen. Konsistent heißt dabei, dass die in der Datenbank abgelegten Daten die im Modell erfasste Wirklichkeit fehlerfrei beschreiben. COMMIT Die -Anweisung gibt dem Benutzer die Möglichkeit, die vorgenommenen Änderungen festzuschreiben und damit allen anderen Benutzern sichtbar zu machen. ROLLBACK Mit der Anweisung wird der Zustand vor Beginn der Transaktion wieder hergestellt. Alle Cursor werden geschlossen. kann im Gegensatz zu allen anderen SQLAnweisungen nicht fehlschlagen. Eine Transaktion wird durch oder beendet, die nächste Transaktion beginnt mit der ersten darauf folgenden ausführbaren SQL-Anweisung. [Achilles, SQL, 230] Erweiterungen: SAVEPOINT save Die Anweisung dient dazu, innerhalb einer Transaktion einen Sicherheitspunkt anzulegen, hinter den die Transaktion zurückgesetzt werden kann. Vor diesem Sicherungspunkt liegende Änderungen bleiben erhalten, danach vorgenommene Änderungen gehen beim Rücksetzen verloren. Eine Transaktion kann mehr als einen Sicherungspunkt umfassen, die Sicherungspunkte müssen deshalb benannt werden save. ROLLBACK SAVEPOINT save Beim Zurücksetzen auf mit bleibt dieser Sicherungspunkt sowie vorhergehende Sicherungspunkte erhalten, nachfolgende Sicherungspunkte werden gelöscht. Somit kann eine Transaktion wiederholt auf den Sicherungspunkt zurückgesetzt werden. Erst am Ende der Transaktion, das durch oder bewirkt wird, werden alle Sicherungspunkte zurückgesetzt. [Achilles, SQL, 234] LOCK TABLE tabelle IN {SHARE|EXCLUSIVE} MODE Die LOCK-Anweisung dient zum Sperren einer Tabelle oder einer Tabellenzeile. 53 Ist SHARE MODE vereinbart, so können die gesperrten Objekte nur gelesen, aber von keiner Transaktion verändert werden. EXCLUSIVE MODE garantiert, dass die setzende Transaktion die Objekte verändern darf, aber hingegen parallele Transaktionen die Objekte höchstens im Isolationsgrad 0 lesen dürfen, ansonsten aber keinen Zugriff auf die gesperrten Objekte besitzen. (Der Isolationsgrad einer Transaktion bestimmt, welche Phänomene auftreten können, wenn andere Transaktionen parallel ablaufen [Achilles, SQL, 334]). Die gesperrten Objekte können aber, sofern sie nicht verändert wurden, mit bereits vor dem Ende der Transaktion freigegeben werden. [Achilles, SQL, 235] Sperrmechanismen sind nicht notwendig, da das DBMS für den Benutzer transparent die notwendigen Sperren setzen und freigeben muss, um die Integrität von Transaktionen zu garantieren. Dennoch gibt es gute Gründe dafür, dem Benutzer zu ermöglichen, Sperren zu setzen. Diese treten in der Regel nur bei umfangreichen Transaktionen zutage: durch das Anfordern der nötigen Sperren kann ein Deadlock vermieden werden; es kann garantiert werden, dass Batch-Arbeiten ungestört zum Abschluss kommen, je nach Implementation des Sperr-Managers kann eine Sperr-Eskalation vermieden werden, d.h. es werden zunächst viele Objekte feiner Granularität gesperrt, bis der Sperr-Manager "erkennt", dass wenige Sperren größerer Granularität effektiver sind. Granularität bedeutet, dass von atomaren Werten bis hin zur gesamten Klassenhierarchie unterschiedlich viele und unterschiedlich große Daten und Objekte gesperrt werden können [Heuer, Objektorientierte Datenbanken] je nach Implementation kann dadurch die Anzahl der Aufrufe des Sperr-Managers reduziert werden. [Achilles, SQL, 232] 54 Besonderheiten von DB2 Bereitstellung externer Funktionen sowie Registrierung externer DatenbankProzeduren bei einem Datenbank-Server in C und Java. Einführung von Triggern. Partitionierung und Replikation von Tabellen wird unterstützt. In der SELECT-Anweisung erfolgt eine Erweiterung der GROUP BY-Klausel sowie die Einführung der WITH-Klausel. Mischbarkeit von DML- und DDL-Anweisungen in einer Transaktion. Besonderheiten von Oracle Bereitstellung von Funktionen sowie Registrierung von Datenbank-Prozeduren bei einem Datenbank-Server extern in C oder intern in PL/SQL. Einführung von Triggern, insbesondere \text{INSTEAD OF}-Triggern. Partitionierung und Replikation von Tabellen wird unterstützt. Zur Erleichterung strukturierter Rechtevergabe wird der Begriff ROLE eingeführt. Das Objekt SEQUENCE dient zur Erzeugung einer eindeutigen Folge von Integerzahlen. Erweiterung der SELECT-Anweisung durch die CONNECT BY-Klausel. Einführung von SAVEPOINTs in einer Transaktion. DB2, ORACLE und INGRES – Relationale Datenbanksysteme Relationale Datenbanksysteme sind derzeit in einer Vielzahl auf dem Markt präsent. Zu den wichtigsten RDBS zählen DB2, ORACLE, INGRES, INFORMIX, SYBASE und ADABAS D. Gemeinsame Merkmale dieser Systeme sind eine Drei-Ebenen-Architektur nach ANSI-SPARC eine einheitliche Datenbanksprache (SQL) eine Einbettung dieser Sprache in kommerziellen Programmiersprachen, diverse Werkzeuge für die Definition, Anfrage und Darstellung von Daten und den Entwurf von Datenbank-Anwendungsprogrammen und der Benutzer-Interaktion, sowie kontrollierter Mehrbenutzerbetrieb, Datenschutz- und Datensicherheitsmechanismen. [Heuer, Saake; Datenbanken, Konzepte und Sprachen] 55 4. Schnittstellen Die interaktive SQL-Schnittstelle soll hier nicht weiter betrachtet werden. Jedoch sollen folgende Bereiche mehr oder weniger intensiv aufgeführt werden: Embedded SQL o Statisches SQL o Dynamisches SQL CLI ODBC JDBC DRDA (an anderer Stelle) Überblick: Spracherweiterungen haben sich nicht durchgesetzt Module-Sprache: insbesondere als Definitionsgrundlage für SQL92 Konzept: o Trennung zwischen SQL und Programmiersprache, o wohldefinierter Übergabemechanismus zwischen Programm und Module o aber: Implementation völlig von DBMS-Hersteller abhängig In eigenen Modulen, deren Anbindung an das DBMS völlig dem DBMSHersteller obliegt, werden pro Prozedur genau eine SQL-Anweisung bereitgestellt. Zudem gibt es eine Routine, die es ermöglicht, die Module-Prozeduren aufzurufen und Argumente zu übergeben. [Achilles, SQL, 237] embedded SQL Konzept: o Einbetten der SQL-Anweisungen in den Programm-Quelltext o Verwendung eines Precompilers o aber: Probleme bei der "Vermischung" von Einbettung und Programmiersprache Aus Programmen heraus können SQL-Anweisungen aufgerufen werden. Hierbei werden SQL-Anweisungen nach bestimmten Regeln in eine Programmiersprache eingebettet. Ein "Vorübersetzer" bereitet die SQLAnweisungen so auf, dass der gewünschte Sprachübersetzer das mit dem Precompiler erzeugte Programm übersetzen kann. Call-Level-Interface wichtiger Standard: Trennung zwischen SQL und Programmiersprache, wohldefinierter Übergabemechanismus zwischen Programm und CLI-Routine o Implementation weitgehend Datenbank-unabhängig o o 56 CLI ist eine standardisierte Datenbankschnittstelle. Diese Schnittstelle erzeugt dynamische SQL-Anweisungen, die vom DBMS interpretiert und umgesetzt werden müssen. Vorteile gegenüber anderen Schnittstellen liegen darin, dass kein Precompiler benötigt wird und die Programme aufgrund des dynamischen SQL nicht gebunden werden müssen. JDBC wichtiger (kommender) Standard, insbesondere für DB-Prozeduren, Web-Anbindungen standardisierte DBMS-Schnittstelle zu Java Grundlagen: Cursor-Konzept Status und Fehlererkennung NULL-Wert und Indikator-Variablen Schnittstellen - Cursor-Konzept: Wozu wird ein Cursor benötigt? Die prozeduralen Programmiersprachen sind darauf ausgerichtet, einzelne Datensätze, nicht jedoch eine Relation, d.h. eine Menge von Datensätzen zu lesen. Somit muss beim Einsatz einer Programmiersprache die Ergebnismenge einer SELECT-Anweisung in eine Folge einzeln abrufbarer Datensätze aufgelöst werden. Hierzu dient der Cursor. [Achilles, SQL, 239] SELECT-Anweisung ergibt eine Ergebnistabelle Prozedurale Programmierung ist auf satzweise Verarbeitung abgestellt SELECT ... INTO :arg1, ... FROM ... WHERE ... ...erlaubt, wenn höchstens eine Zeile ermittelt wird... Lösung des allgemeinen Problems? Das Cursor-Prinzip dient dazu, eine Ergebnismenge in eine Folge einzeln einlesbarer Datensätze aufzulösen DECLARE cname [INSENSITIVE] [SCROLL] CURSOR FOR { SELECT-Anweisung | prepared-Anweisung } der Cursor-Name ist keine Variable, sondern eine statische Referenz auch der Kursor kann "dynamisch" behandelt werden Die Option INTENSIVE bewirkt, dass beim Öffnen des Cursors explizit eine Kopie der Ergebnismenge erzeugt wird. Damit wird erreicht, dass beim Lesen Änderungen von gleichzeitig laufenden Transaktionen anderer Benutzer auf keinen Fall sichtbar werden. Ob Änderungen durch andere Transaktionen sichtbar werden, wenn INTENSIVE nicht angegeben wurde, ist implementationsabhängig. 57 Das Konzept des Cursors bietet eine abstraktere Sichtweise auf eine Relation, realisiert als Liste, an: Ein Cursor ist ein Iterator über eine Liste von Tupeln, d.h. ein Zeiger der vor- (und in einigen Realisierungen auch zurück-) gesetzt werden kann. Ein Cursor wird mit der 'declare cursor'-Anweisung deklariert. Ein Cursor über einen Teil der Relation Bücher kann etwa wie folgt deklariert werden: declare AktBuch cursor for select ISBN, Titel, Verlagsname from Bücher where Verlagsname = 'Thomson'; Auf die einzelnen Tupel einer Relation kann durch die fetch-Anweisung des Cursors zugegriffen werden. fetch realisiert das Weitersetzen des Cursor-Zeigers und den Datentransfer in das Anwendungsprogramm. [Heuer, Saake; Datenbanken, Konzepte und Sprachen] Ein Cursor speichert das Ergebnis einer Select-Anweisung in der Form, dass eine Programmiersprache anschließend zeilenweise auf das Ergebnis zugreifen kann. Die Vorgehensweise gleicht dem Arbeiten mit einer Datei. Der Cursor muss zunächst geöffnet werden; sodann kann zeilenweise mittels FETCH auf die Ergebnisse zugegriffen werden, und nach erfolgter Verarbeitung muss der Cursor geschlossen werden. [Achilles, SQL, 240] 58 Nutzung eines Cursors: Problem: Erkennung des Endes Öffnen eines Cursors => Zeitpunkt, zu dem die SELECT-Anweisung ausgewertet wird OPEN cname [ USING ...] Der Augenblick des Öffnens eines Cursors ist der Zeitpunkt, zu dem die SELECTAnweisung ausgewertet wird. Die Ergebnistabelle wird erstellt und dabei wird eine Reihenfolge der Zeilen intern – oder bei Verwendung von ORDERED BY extern festgelegt. Ohne die USING-Klausel wird der Cursor für das Öffnen festcodierter selectAnweisungen eingesetzt. Auch in diesem Falle kann die SELECT-Anweisung auf Parameter (bei Einsatz von Modules) bzw. Hostvariablen (Embedded SQL) zugreifen, um eine gewisse Flexibilität zu gewähren. ...[Achilles, SQL, 242] Position des Cursors: vor der ersten Ergebniszeile USING ... dient zur Übergabe von Hostvariablen bei prepared Anweisungen 59 Die USING-Klausel wird erst bei Einsatz von dynamischen SQL benötigt. Wenn die dort erzeugten SELECT-Abfragen positionale Parameter in Form des Fragezeichens (?) besitzen, so müssen diese Stellen beim Öffnen mit Werten gefüllt werden. ... Beim Öffnen wird der Cursor in der Ergebnismenge vor die erste Zeile positioniert. Eine FETCH (genauer: FETCH NEXT) –Anweisung positioniert den Cursor auf die nächste Zeile der Ergebnismenge. Sind alle Zeilen durchlaufen, so wird er statt dessen hinter die letzte Zeile positioniert. ... [Achilles, SQL, 242] Schließen eines Cursors: CLOSE cname Soll über den Cursor cname nicht mehr zugegriffen werden, so bewirkt CLOSE cname die Freigabe von Ressourcen. Die mit dem Öffnen des Cursors angelegte Ergebnistabelle steht danach nicht mehr zur Verfügung. Lesen eines Datensatzes mittels Cursor: => Cursor wird auf den nächsten Satz der Ergebnismenge geschoben Das Lesen aus einem geöffneten Cursor erfolgt mit Hilfe der FETCH-Anweisung. Diese Anweisung platziert den Cursor aufgrund der Vereinbarung auf die entsprechende Zeile der Ergebnistabelle und macht dadurch die dort ermittelten Werte sichtbar. FETCH [ ABOLUTE n | FIRST | LAST | NEXT | PRIOR | RELATIVE n ] FROM cname INTO { Liste von Hostvariablen | SQL DESCRIPTOR dname } Die Voreinstellung ist NEXT, d.h. die Ergebnistabelle wird sequentiell abgearbeitet. Das hängt damit zusammen, dass nicht-sequentielle Verarbeitung die Cursor-Option SCROLL voraussetzt. Wenn die Option SCROLL bei der Vereinbarung des Cursors nicht angegeben wurde, so ist die FETCHAnweisung nur in der Form FETCH NEXT zulässig, dies ist die Voreinstellung. Wenn hingegen die Option SCROLL vereinbart wurde, so sind sämtliche Formen von FETCH zulässig. Absolute Positionierung ist durch die Richtungen FIRST, LAST und ABSOLUTE n möglich. Damit wird der erste, der letzte bzw. der n.-te Satz der Ergebnismenge gelesen. Außer dem immer zulässigen NEXT, mit dem der nachfolgende Satz gelesen wird, kann relative Positionierung durch PRIOR bzw. RELATIVE n erzielt werden, d.h. es wird der vorhergehende bzw. der im Abstand von n zur gegenwärtigen Position befindliche Satz gelesen. Schnittstellen – Status: Jede SQL-Anweisung erzeugt eine Status-Information, die Auskünfte über Erfolg oder Misserfolg der Anweisung gibt. Normierung in SQL92: Variable SQLSTATE 5 Byte, aufgeteilt in 2 Byte "Klasse" und 3 Byte "Unterklasse" wichtige Klassen: 60 Klasse Bedeutung 00 erfolgreiche Ausführung 01 Warning 02 Daten nicht vorhanden 08 Connection error 23 Constraint violation (Integritätsverletzung) 27 Triggered data Datenänderung) change violation (Trigger-bedingte fehlerhafte SQL-Environment enthält "Diagnostic Area": Zu jeder aktiven SQL-Umgebung gehört eine "Diagnostic Area" (Speicherbereich für diagnostische Informationen), die dazu dient, für die jeweils letzte SQL-Anweisung detailierte Informationen bzgl. Fehlersituationen aufzubewahren. Diese Area wird vor der Ausführung jeder weiteren SQL-Anweisung zunächst zurückgesetzt. Um auf die Area zugreifen zu können, wird die Anweisung GET DIAGNOSTICS bereitgestellt. Da damit das "Interface" definiert ist, steht es jedem DBMS-Hersteller frei, die Struktur der Area selbst zu bestimmen. [Achilles, SQL, 247]] Ein Teil der Informationen erhält man durch GET DIAGNOSTICS hostvar = NUMBER | MORE | COMMAND_FUNCTION | DYNAMIC_FUNCTION | ROW_COUNT Damit wird der Hostvariablen (bzw. dem Parameter) ein Wert zugewiesen, der sich aus der nachfolgenden "Quelle" bestimmt. Die Quellen haben folgende Bedeutung: NUMBER: ermittelt die Anzahl der gespeicherten Fehlersituationen. Bei der Bearbeitung einer Anweisung können mehrere Fehlersituationen auftreten und gespeichert werden, die in einer Art "Stack" verwaltet werden. MORE: liefert "Y" oder "N" zurück. Mit Y wird signalisiert, dass mehr Fehler aufgetreten sind, als in der Diagnostic Area erfasst werden können; N zeigt an, dass alle erkannten Fehler dort beschrieben wurden. COMMAND_FUNCTION: gibt eine Zeichenkette zurück, die die zugrundeliegende SQL-Anweisung identifiziert. DYNAMIC_FUNCTION: falls die ausgeführte Anweisung EXECUTE oder EXECUTE IMMEDIATE war, wird hiermit ebenfalls eine Zeichenkette zurückgegeben, die die dynamische Anweisung identifiziert. ROW_COUNT: gibt die Anzahl der Zeilen an, die durch die SQL-Anweisung direkt betroffen sind. Dies gilt für INSERT sowie DELETE und UPDATE ohne cursor. Um spezielle Informationen über eine bestimmte aufgetretene Fehlersituation zu erhalten, muss zu folgender Syntax gegriffen werden: GET DIAGNOSTICS EXCEPTION nr hostvar = 61 CONDITION_NUMBER | RETURNED_SQLSTATE | CONNECTION_NAME | CONSTRAINT_NAME | TABLE_NAME | COLUMN_NAME | CURSOR_NAME | MESSAGE_TEXT nr bezeichnet die Nummer der Fehlerbedingung, über die nähere Informationen eingeholt werden soll. Diese muss zwischen 1 und der durch NUMBER ermittelten Zahl liegen. nr kann als fester Wert, als Hostvariable oder als Parameter angegeben werden. Für nr = 1 wird diejenige Information ausgegeben, die mit dem Wert von SQLSTATE (bzw. SQLCODE in der älteren Form) korrespondiert. Die Reihenfolge der Fehlerbedingungen ist implementationsabhängig. Auch hier ist es wieder möglich, eine oder mehrere Hostvariablen bzw. Parameter mit der durch die Quelle gegebenen Information füllen zu lassen. RETURNED_SQLSTATE: MESSAGE_TEXT: hier wird der zum n-ten Fehler gehörige Wert in der durch SQLSTATE beschriebenen Darstellung ausgegeben. Wäre nur dieser Fehler aufgetreten, so hätte die Variable SQLSTATE diesen Wert. eine Implementation kann hier einen eigenen fehlerbeschreibenden Text ausgeben, um so spezifischere Meldungen für den Benutzer zu erzeugen. [Achilles, SQL, 249] Schnittstellen - Indikator-Variable: Da die Hostsprachen im Gegensatz zu SQL kein Äquivalent zum NULL-Wert kennen, muss auf andere Weise überprüfbar sein, ob der NULL-Wert übertragen wurde. Dazu dienen Indikatorvariablen. Die Indikatorvariable überprüft die Übertragung derjenigen Variablen, der sie direkt zugeordnet ist. [Achilles, SQL, 254] Zusammen mit einer Hostvariablen (vgl. Module-Sprache, embedded SQL) kann eine Indikatorvariable benutzt werden (kein Komma zwischen Host- und zugehöriger Indikatorvariable): Wird aus der Datenbank gelesen, so besagen die Werte der Indikator-Variablen nach Ausführung der SQL-Anweisung =0 Übertragung korrekt >0 bei Übertragung wurden Stellen abgeschnitten Anzahl der abgeschnittenen Stellen = Wert der Indikatorvariable <0 NULL-Wert wurde übertragen wird in die Datenbank geschrieben, so gilt: 62 wird vor Ausführung Wert < 0 gesetzt: NULL-Wert wird in Datenbank geschrieben nach Ausführung werden die Werte = 0 und > 0 wie oben interpretiert Schnittstellen - Module-Schnittstelle: Die zugrundeliegende Idee besteht darin, von einer Programmiersprache aus Module aufzurufen, die in einer anderen Sprache geschrieben und getrennt von der eigentlichen Übersetzung mit einem anderen Compiler übersetzt worden sind. Diese Module sind in einer Sprache geschrieben, die es ausschließlich ermöglicht, in den Prozeduren jeweils eine SQL-Anweisung auszuführen, der ggf. noch Argumente übergeben werden können. Wie die Übersetzung und Anbindung dieser Modules geschieht, wird im Standard nicht weiter geregelt und bleibt somit den DBMSHerstellern überlassen. Somit muss die jeweilige Sprache, in der die Applikation geschrieben wird, in keiner Weise geändert werden. Diese Sprache wird in der Regel im Gegensatz zu den SQL-Modules als Hostsprache bezeichnet. Die Trennung von Hostsprache und SQL-Module bietet einige konzeptionelle Vorteile. So lassen sich Module und Programm getrennt optimieren. Es wird kein Precompiler benötigt. Durch die Trennung entfallen auch weitere Probleme, die bei Embedded SQL auftreten können, z.B. in manchen Sprachen die zweifache Bedeutung von SELECT im Quelltext und in den eingebetteten SQL-Anweisungen, die unterschiedliche Scopes (Gültigkeitsbereiche) von SQL-Bezeichnern und Sprachobjekten, die zum Teil unterschiedliche Bedeutung der Operatoren in Sprache und eingebetteter SQL-Anweisung, usw. ... [Achilles, SQL, 251] Aufruf von Modulen dadurch Trennung von Host-Sprache und SQL Module sind in eigener "Sprache" geschrieben o pro Module eine SQL-Anweisung o Argumentübergabe möglich Vorteile: o Module und Programm können getrennt optimiert werden o kein Precompiler o kein Konflikt zwischen SELECT (Programmiersprache) und SELECT (SQL) Übersetzung und Anbindung der Module aber nicht geregelt, DBMS-Hersteller-abhängig Beispiel: MODULE beispiel LANGUAGE PLI SCHEMA demo DECLARE cursor_stud_pruefungen CURSOR FOR SELECT vname, semester, note FROM pruefungen WHERE matrnr = :matrstud; --DECLARE-CURSOR-Anweisungen werden ueblicherweise am Anfang --des Modules zusammengefasst PROCEDURE commit (SQLSTATE); COMMIT WORK; 63 PROCEDURE rollback (SQLSTATE); ROLLBACK WORK; PROCEDURE open_cursor_stud_pruefungen ( SQLSTATE, :matrstud CHAR(7) ); OPEN open_cursor_stud_pruefungen; PROCEDURE close_cursor_stud_pruefungen ( SQLSTATE); CLOSE open_cursor_stud_pruefungen; PROCEDURE lies_cursor_stud_pruefungen ( SQLSTATE, :vorlesname CHAR(20) :semester CHAR(11), :note CHAR(3), :i_note INTEGER); FETCH NEXT FROM cursor_stud_pruefungen INTO :vorlesname, :semester, :note INDICATOR :i_note; Beispiel für Programm: /* Variablen für Module-Kommunikation bereitstellen und initialisieren */ DCL sqlstate CHAR( 5); DCL student CHAR( 7); DCL vorlesung Char(20); DCL semester CHAR(11); DCL note CHAR( 3); DCL inote BIN FIXED; /* SQL-Fehlerbehandlung */ ON CONDITION (SQLEXCEPTION) BEGIN ... END; ... student = '4711'; /* Cursor zum Auslesen aus der Tabelle */ CALL open open_cursor_stud_pruefungen(sqlstate, student); IF SUBSTR(sqlstate, 1, 2) > '02' THEN SIGNAL SQLEXCEPTION; /* Ergebnis zeilenweise auslesen und verarbeiten */ DO WHILE ('1'b); CALL lies_cursor_stud_pruefungen(sqlstate, vorlesung, semester, note, inote); IF SUBSTR(sqlstate, 1, 2) > '02' THEN SIGNAL SQLEXCEPTION; IF SUBSTR(sqlstate, 1, 2) = '02' THEN LEAVE; IF SUBSTR(sqlstate, 1, 2) > '00' THEN PUT ('Warnung beim Lesen'); ELSE DO; IF itext < 0 THEN text='???'; PUT LIST (vorlesung, semester, note); END; END; /* Schliessen des Cursors */ CALL close_cursor_stud_pruefungen; ... 64 Embedded SQL Sollen SQL-Anweisungen im Quelltext eingebettet werden, so muss ein Precompiler verwendet werden, um daraus den entsprechenden Code zu generieren, der anschließend vom Compiler verarbeitet werden kann.[Achilles, SQL, 257] SQL-Anweisungen werden in den Quelltext eingebettet: EXEC SQL SQL_Anweisung; konkretes Beispiel: EXEC SQL INSERT INTO pruefungen VALUES (:student, :vorlesung, :semester, :note:inote) ; Einleitung und Ende der eingebetteten Anweisung ergeben sich aus der gewählten Programmiersprache Embedded SQL Beispiel: /* Vereinbarung der Hostvariablen */ EXEC SQL BEGIN DECLARE SECTION; DCL sqlstate CHAR( 5); DCL student CHAR( 7); DCL vorlesung Char(20); DCL semester CHAR(11); DCL note CHAR( 3); DCL inote BIN FIXED; EXEC SQL END DECLARE SECTION; EXEC SQL DECLARE cursor_stud_pruefungen CURSOR FOR SELECT vname, semester, note FROM pruefungen WHERE matrnr = :student; ... student = '4711'; EXEC SQL WHENEVER NOT FOUND GOTO ENDE; EXEC SQL OPEN cursor_stud_pruefungen; DO WHILE ('1'b); EXEC SQL FETCH cursor_stud_pruefungen INTO :vorlesung, :semester : note:inote; IF SUBSTR(sqlstate, 1, 2) > '00' THEN PUT ('Warnung beim Lesen'); ELSE DO; IF itext < 0 THEN text='???'; PUT LIST (vorlesung, semester, note); END; END; ENDE: EXEC SQL CLOSE cursor_stud_pruefungen; ... 65 Die SQL-Anweisungen werden für den Precompiler durch eine "Einleitung" und ein "Ende" eindeutig gekennzeichnet - für PL/I z.B. EXEC SQL sql-Anweisung; Wie jeder Precompiler, so kann auch dieser Precompiler den Quellcode nur in der Reihenfolge der Niederschrift, nicht jedoch in der – erst zur Laufzeit bekannten Befehlsabfolge – bearbeiten. [Achilles, SQL, 258] Um korrekte Datenübertragungen zwischen Datenbank und Hostvariablen (Gemeinsame Variablen, dienen dem Datenaustausch zwischen Programm und Datenbank, werden mit vorangestellten ":" gekennzeichnet) vorzunehmen, muss der Precompiler die Datentypen der Hostvariablen kennen. Das ist der Grund für denjenigen Programmabschnitt, der durch BEGIN DECLARE SECTION eingeleitet und durch END DECLARE SECTION beendet wird. Hierbei handelt es sich nicht um SQL-Anweisungen, sondern um Anweisungen an den Precompiler. Da Hostvariablen im Programm wie normale Variablen der jeweiligen Sprache behandelt werden, hängen die für Hostvariablen einsetzbaren Datentypen natürlich von der gewählten Programmiersprache ab. Damit der Precompiler die Datenstrukturen korrekt in das DBMS-Format übertragen kann, müssen ihm in besonderen Programmabschnitten diejenigen Variablen bekannt gegeben werden, die sowohl in den SQL-Anweisungen als auch in den "normalen" Programmanweisungen Verwendung finden: EXEC SQL BEGIN DECLARE SECTION; vereinbarungen; EXEC SQL END DECLARE SECTION; Der zu verwendende Precompiler hängt sowohl von der Sprache als auch vom DBMS ab. Der Precompiler bearbeitet die Programmdatei mit den eingebetteten SQL-Anweisungen sequentiell. Trifft er auf eine SQL-Anweisung, die er aufgrund der Einleitung kennt, so liest er zunächst die gesamte SQL-Anweisung bis zum Endekennzeichen ein und überprüft sie in Zusammenarbeit mit dem Datenbanksystem. ... Alle eingestreuten SQL-Anweisungen müssen mit dem Schlüsselwort 'exec sql' beginnen, um vom Vorübersetzer erkannt zu werden. Die bereits angeführte CursorDeklaration würde im Programmtext also wie folgt lauten: exec sql declare AktBuch cursor for select ISBN, Titel, Verlagsname from Bücher where Verlagsname = 'Thomson'; … Da SQL-Anweisungen getrennt von Anweisungen der Programmiersprache übersetzt werden, müssen Programmvarialben, die sowohl in SQL-Anweisungen als auch außerhalb benutzt werden, Dgesondert definiert und in SQL-Anweisungen syntaktisch hervorgehoben werden. Im Englischen werden diese Variablen auch als host variables bezeichnet. Die Deklaration derartiger Variablen erfolgt ebenfalls in einem seperaten 'declare section'-Block: exec sql begin declare section; BuchISBN char(10); Neuer Preis real; 66 exec sql end declare section; Deklarierte Variablen können in SQL-Anweisungen direkt wie Konstanten benutzt werden. Sie werden dabei durch ein vorangestelltes ':'-Zeichen gekennzeichnet. exec sql update Buch_Versionen set Preis = :NeuerPreis where ISBN = :BuchISDN; Die explizite Kennzeichnung der Variablen erlaubt es, dass Variablen die gleichen Namen wie Attribute der Relation haben können. Mit dieser Methode können auch Tupel in die Datenbank eingefügt werden: exec sql insert into Buch_Versionen values (:NeuISBN, :NeuAuflage, 1995, :Seiten, :Preis); ... Um mit einem Cursor arbeiten zu können, werden 3 Anweisunhgen bereitgestellt: Ein Cursor kann geöffnet werden, ein aktuelles Tupel kann von der Datenbank in das Anwendungsprogramm transferiert werden (inklusive Weitersetzen des Cursors), und er kann schlussendlich wieder geschlossen werden. Das Öffnen eines Cursors erfolgt mit der 'open'-Anweisung. Der Cursor wird mittels dieser Anweisung initialisiert: exec sql open AktBuch; Der Transfer eines Tupels in Variablen des Anwendungsprogramms erfolgt mittels der 'fetch'-Anweisung. Der Cursor wird dabei auf das nächste Tupel weitergesetzt: exec sql fetch AktBuch; into :ISBN, :Titel, :Verlagsname; Die 'close'-Anweisung beschließt den Transfer zwischen DBMS und Anwendungsprogramm: exec sql close AktBuch; ... [Heuer, Saake; Datenbanken, Konzepte und Sprachen] Aufgaben des Precompilers: Syntaktische Prüfung der eingebetteten SQL-Anweisungen (durch Übermittlung an das DBMS, das die Prüfung soweit möglich vorab vollzieht) Logische Überprüfung der eingebetteten SQL-Anweisungen (ebenfalls durch das DBMS): sind alle verwendeten Objekte (Tabellen, Indexe, Views usw.) vorhanden? Rechteüberprüfung, soweit zur Übersetzungszeit möglich derjenige, der das Programm ausführt, ist in der Regel nicht derselbe, der das Programm erstellt und übersetzt. Ermittlung des optimalen Zugriffspfades und Speicherung in der DB dies ist stark abhängig vom jeweiligen DBMS; eine Optimierung zur Übersetzungszeit beschleunigt die Programmausführung solange die Objekte und die Verteilung der Daten einigermaßen stabil bleiben; treten hier jedoch stärkere Schwankungen auf, so sind Optimierungen zur Laufzeit trotz der anfallenden Kosten günstiger. Übersetzung der eingebetteten SQL-Anweisungen in die entsprechenden Quellcode-Anweisungen. 67 Precompiler übersetzt eingebettete Anweisungen in Statements der jeweiligen Programmiersprache: arbeitet vor Übersetzungszeit => keine Kenntnis von Information zur Zeit der Ausführung arbeitet rein sequentiell prüft zusammen mit DBMS für jede eingebettete Anweisung: o ist Anweisung syntaktisch korrekt o sind alle referenzierten Objekte in DB vorhanden o sind Zugriffsrechte gegeben nach erfolgreicher Prüfung: o ersetzt Anweisung durch Quelltext und benötigte Datenstrukturen o ggf. ermitteln "optimalen" Zugriffspfad Die Arbeitsweise eines Precompilers kann nur sequentiell nach der Programmniederschrift erfolgen. Aspekte, die erst zur Laufzeit bekannt sind, können natürlich vom Precompiler nicht ausgewertet werden. Ist bekannt, dass erst nach der Vorübersetzung Objekte in die Datenbank eingefügt werden, die im Programmlauf benutzt werden, so muss im Precompilerlauf die Überprüfung ausgeschaltet werden, ob alle referenzierten Objekte vorhanden sind. ... Nach erfolgreicher Überprüfung ersetzt der Precompiler die eingebettete SQL-Anweisung durch die benötigten Datenstrukturen sowie Prozeduraufrufe in der Sprache des verwendeten Compilers. Die Prozeduren befinden sich in einer Bibliothek, die als Schnittstelle zur Kommunikation mit dem DBMS dient. Wesentliche Aufgabe dieser Bibliothek ist neben der Kommunikation mit dem DBMS darin zu sehen, dass die Umwandlung der Daten der Hostvariablen zwischen Datenbank und Programm unterstützt wird. ... Im Anschluss an die Ersetzung der eingebetteten SQL-Anweisung werden noch Codesequenzen eingefügt, die nach der Ausführung der umgewandelten SQL-Anweisung den Rückgabewert überprüfen und deren Aufgabe es ist, in standardisierter Form auf Fehler zu reagieren. (siehe Ausnahmebehandlung...) Je nach DBMS-Hersteller ist nun die Aufgabe des Precompilers erledigt. In diesem Falle muss bei jedem Aufruf des Programms eine Phase durchlaufen werden, in dem für jede eingebettete SQL-Anweisung ein "optimaler" Zugriffspfad auf die Objekte der Datenbank ermittelt wird. Andere DBMS-Hersteller ermitteln während des Precompilerlaufs bereits für alle statischen SQL-Anweisungen einen "optimalen" Zugriffspfad und speichern diesen in der Datenbank selbst ab. Beide Verfahren haben Vor- und Nachteile: wird bei jedem Programmlauf erst der optimale Zugriffspfad ermittelt, so wird unnötige Leistung verschwendet, wenn sich die Daten nur unwesentlich verändert haben, andererseits kann bei starken Änderungen in den Daten jedes mal ein guter Zugriffspfad ermittelt werden, wird der Zugriffspfad in der Datenbank gespeichert, so entfällt bei jedem Programmaufruf die Leistung, zu Beginn den Zugriffspfad ermitteln zu müssen, die Programme werden dadurch schneller; ändern sich die Daten jedoch merklich, so ist ggf. der Zugriffspfad nicht mehr gut, so dass nun an anderer Stelle Leistung verschwendet wird. Das DBMS muss in diesem Falle außerdem Mechanismen bereitstellen, um Zugriffspfade als ungültig zu kennzeichnen, damit sie automatisch beim nächsten Programmaufruf wieder erzeugt werden können – dies ist z.B. nötig, wenn ein Index gelöscht wird, auf den der ursprüngliche Zugriffspfad zugegriffen hat. 68 [Achilles, SQL, 260] Generell gibt es eine deutliche Trennung zwischen DBMS und Programm. Operatoren im Programmcode und in den eingebetteten Anweisungen haben unterschiedliche Bedeutung, Exception-Handling durch DBMS-Ausnahmen lassen sich (zumindest nicht direkt) vom Programm erkennen. Bei der Ausführung einer eingebetteten SQL-Anweisung gibt das DBMS über entsprechende Datenstrukturen einen Rückgabewert zurück, der Aufschluss darüber gibt, ob die Anweisung vom DBMS korrekt abgearbeitet wurde: SQLSTATE. Hierüber wird auch ermittelt, ob alle Ergebnisse einer SQL-SELECT-Anweisung ausgelesen wurden. Host-Variablen, d.h. Variablen, die im Quellcode sowie in eingebetteten SQL-Anweisungen benutzt werden, müssen in den eingebetteten Anweisungen mit einem Doppelpunkt (:) eingeleitet werden. Sie können zusätzlich mit Indikatorvariablen versehen werden, deren Aufgabe es ist, bei der Übertragung zwischen Programm und DBMS bzw. DBMS und Programm NULL-Werte sowie das Auftreten von Rundungen/Abschneidungen zu kontrollieren und anzuzeigen. IndikatorVariablen sind vom Typ Integer, sie werden ebenfalls mit einem Doppelpunkt eingeleitet und stehen direkt hinter den zu überwachenden Host-Variablen: itest = -1; /* in eine Tabelle soll an bestimmter EXEC SQL INSERT INTO TABELLE VALUES (5, :test:itest, 0 ); Stelle NULL eingegeben werden */ Negative Werte von Indikator-Variablen erzwingen die Übertragung des NULL-Wertes vom Programm zum DBMS, bzw. zeigen eine solche Übertragung vom DBMS zum Programm hin an. Ist der Wert einer Indikator-Variablen nach der Übertragung 0, so ist die Übertragung korrekt gelaufen, ist er > 0, so musste bei der Übertragung aufgrund von Dateninkompatibilitäten eine Abschneidung vorgenommen werden, d.h. die übertragenen Daten sind nicht mehr genau. Ausnahmebedingungen: EXEC SQL WHENEVER NOT FOUND | SQLERROR GOTO label | CONTINUE Diese Anweisung erzeugt nach jeder durch den Precompiler übersetzten SQL-Anweisung Code zur Überprüfung der Variablen SQLSTATE. Aufgrund des Wertes der Variablen und der in der WHENEVER-Anweisung getroffenen Vereinbarungen werden im laufenden Programm (sprachabhängige) Verzweigungen ausgelöst (im Prinzip handelt es sich um GOTOAnweisungen). Die in der WHENEVER getroffenen Vereinbarungen gelten bis zur nächsten WHENEVER-Anweisung. Der Precompiler kann auf folgende Ausnahmen reagieren: NOT FOUND: beim Lesen aus einer Ergebnistabelle wird festgestellt, dass diese keine Daten enthält oder – beim sequentiellen Lesen – dass der Cursor hinter die letzte Zeile der Ergebnistabelle positioniert wird, SQLERROR: das DBMS signalisiert über einen Wert von SQLSTATE, der mit einer Zeichenkette > 02 beginnt, dass bei der Bearbeitung der SQLAnweisung ein Fehler aufgetreten ist. 69 In dem durch den Precompiler erzeugten Code bewirkt eine Ausnahme je nach vereinbarter Aktion folgende Reaktion: GOTO label: einen Sprung zur angegebenen Marke label. Das Aussehen der Marken ist sprachabhängig, CONTINUE: zum Ignorieren der Ausnahme, d.h. der Precompiler unterdrückt die Erzeugung entsprechender Codeteile zum Prüfen von SQLSTATE bzgl. der angesprochenen Ausnahme. Statische SQL-Anweisungen: alle Informationen sind bereits zum Zeitpunkt der Programmierung bekannt: Namen der Objekte Struktur der Manipulationsanweisung Struktur der WHERE-Klausel verwendete Host-Variablen ... Offen bleiben darf nur der Wert der in Ausdrücken verwendeten Host-Variablen Vorteile: je nach DBMS kann der Zugriffspfad ermittelt und in der DB gespeichert werden damit entfällt das Berechnen während der Ausführungsphase einzig Rechte müssen noch überprüft werden Oracle schaut in einem Cache nach, ob SQL-Anweisung bereits bekannt. Schreibweise muss präzise übereinstimmen => dann wird zugehörige Ausführungsform aus dem Cache übernommen Die statische Einbettung ist eine Folge des sogenannten Vorübersetzer-Prinzips: SQL-Anweisungen werden in den Programmtext eingestreut und gegebenenfalls speziell syntaktisch notiert. Ein Vorübersetzer (engl. Precompiler) analysiert den Quelltext, der aus Anweisungen der Programmiersprache und zusätzlichen SQL-Anweisungen besteht, und wandelt alle SQL-Anweisungen in Prozeduraufrufe um. Das erhaltene Programm kann dann von einem normalen Programmiersprachen-Übersetzer weiterbearbeitet werden. Das Vorübersetzer-Prinzip erfordert, dass die benötigten SQL-Anweisungen zur Übersetzungszeit feststehen. Es können also nicht zur Laufzeit die Suchkriterien einer Anfrage beliebig festgelegt werden. Aus diesem Grunde spricht man von einer statischen Einbettung. [Heuer, Saake; Datenbanken, Konzepte und Sprachen] SQL-Anweisungen, deren Struktur zur Übersetzungszeit feststeht, werden "statisch" genannt. Derartige Anweisungen können nur noch dadurch geändert werden, dass Hostvariablen verwendet werden, die zur Ausführungszeit unterschiedliche Werte annehmen können. Die SQL-Anweisungen können bis auf die Rechte vollständig vom DBMS überprüft werden. 70 Zur Übersetzungszeit sind insbesondere die Struktur der SELECT-Anfragen sowie deren WHERE-Klauseln etc. bekannt. Somit ist auch die Struktur der Ergebnistabellen bekannt. Zum Einlesen von Ergebnistabellen wird das Cursor-Prinzip verwendet. Im ursprünglichen Ansatz handelt es sich dabei um eine Vorgehensweise, die mit dem Auslesen sequentieller Dateien vergleichbar ist: EXEC SQL DECLARE c CURSOR FOR SELECT name, anschrift FROM STUDENT WHERE name like ?; /* ? ist ein positionaler Parameter, der beim "öffnen" durch eine Hostvariable ersetzt wird. diese Anweisung entspricht der Vereinbarung eines Dateiformates */ EXEC SQL OPEN c USING :name; /* diese Anweisung entspricht dem Öffnen einer sequentiellen Datei. Zur Laufzeit wird die SELECT-Anweisung mit dem entsprechenden Wert der Host-Variablen ausgeführt, die Ergebnistabelle kann dann sequentiell ausgelesen werden. */ EXEC SQL WHENEVER NOT FOUND GOTO ENDE; /* hierdurch wird der Precompiler veranlasst, nach jeder SQL-Anweisung die Variable SQLSTATE zu überprüfen und je nach Ergebnis entsprechende Aktionen einzuleiten. (Abbruchbedingung, wenn alle Zeilen gelesen wurden) */ Do While ( TRUE ); EXEC SQL FETCH c INTO :studname, :anschrift; /* Lesen der durch den Cursor identifizierten Zeile der Cursor wird automatisch vorgerückt */ /* hier folgt die Verarbeitung */ End; :ENDE /* hierhin wird nach fertigem Lesen verzweigt */ EXEC SQL CLOSE c; 71 Dynamisches SQL: Nicht alle Probleme lassen sich mit statischem SQL lösen, ein offensichtlich damit nicht lösbares Problem ist es, eine Oberfläche zu erzeugen, in der man interaktiv SQLAnweisungen eingeben und abarbeiten lassen kann. Dynamisches SQL ist dadurch gekennzeichnet, dass die Anweisungen erst zur Laufzeit bekannt sind und somit auch erst zur Laufzeit vom DBMS geprüft, übersetzt und ausgeführt werden können. => es muss Möglichkeiten geben, eine Zeichenkette an das DBMS zu übergeben, die zur Laufzeit ausgewertet und als SQL-Anweisung ausgeführt wird. Problem: einmaliger Zugriff oder wiederholter Zugriff? Bei wiederholtem Zugriff mit Hilfe der ermittelten Anweisung müsste jeweils die AnalysePhase erneut durchlaufen werden Performance! einmaliger Zugriff: Wird eine SQL-Anweisung ermittelt und nur einmal ausgeführt, eignet sich die folgende Form: satz = "DELETE TABLE test"; EXEC SQL EXECUTE IMMEDIATE :satz; Beispiel: EXEC SQL BEGIN DECLARE SECTION; DCL zeichenkette CHAR(200); EXEC SQL END DECLARE SECTION; zeichenkette = 'CREATE TABLE KUNDEN (' || ' KNUMMER SMALLINT PRIMARY KEY,' || ' KNAME CHARACTER(20) NOT NULL, ' | ' KTEXT CHARACTER(50) )' ; EXEC SQL EXECUTE IMMEDIATE :zeichenkette ; mehrfacher Zugriff: Anders sieht es hingegen aus, wenn eine INSERT-Anweisung erzeugt und mehrfach mit unterschiedlichen Werten ausgeführt werden soll. Dynamisch wird eine SQL-Anweisung erzeugt, die ggf. Ein- oder Ausgabevariablen enthalten und mehrfach aufgerufen werden soll. In diesem Fall muss die Vorbereitung von der Ausführung getrennt werden. Hierzu sind die Anweisungen PREPARE zur Vorbereitung, EXECUTE zur Ausführung und DELLOCATE PREPARE zur Freigabe der Ressourcen vorgesehen. [Achilles, SQL, 262] satz = "INSERT INTO student VALUES ( ?, ? ,? ); EXEC SQL PREPARE ins FROM :satz; Do While (...); 72 Read matrikelnr, studname, anschrift; EXEC SQL EXECUTE ins USING :matrikelnr, :studname, :anschrift End; --------------------------------------------------------------------EXEC SQL BEGIN DECLARE SECTION; DCL zeichenkette CHAR(200); EXEC SQL END DECLARE SECTION; zeichenkette = 'INSERT INTO KUNDEN ' || ' VALUES( ?, ?, ? ) ' EXEC SQL PREPARE prep_anweisung FROM :zeichenkette ; Die PREPARE-Anweisung Diese Anweisung erzeugt unter dem Namen prep_anweisung eine geprüfte, vorbereitete SQL-Anweisung zusammen mit einem Zugriffspfad. Der Name prep_name ist keine Hostvariable! Die aufzubereitende SQL-Anweisung ist in der Hostvariablen zeichenkette (siehe oben) enthalten, deren Datentyp eine Zeichenkette sein muss.[Achilles, SQL, 263] Ausführung/Die EXECUTE-Anweisung Eine mit PREPARE aufbereitete Anweisung wird mit EXECUTE zur Ausführung gebracht. Dabei sind Ein- und Ausgabevariablen an die positionalen Parameter zu übergeben. prep_anweisung – hierbei ist keine Indikatorvariable erlaubt – bezeichnet die aufbereitete SQL-Anweisung. ... Die USING-Klausel übergibt die Werte der Hostvariablen bzw. die im Deskriptor gespeicherten Werte von links nach rechts an die positionalen Parameter in der Reihenfolge ihres Auftretens. ... [Achilles, SQL, 265] EXEC SQL EXECUTE prep_anweisung USING :var1, :var2, :var3 ; Anmerkungen: prep_anweisung ist ein Bezeichner, keine Host-Variable! :zeichenkette muss gültige SQL-Syntax besitzen es sind nur positionale Parameter erlaubt keine Kommentare, keine Host-Variablen erlaubte DML-Anweisungen: INSERT, DELETE, UPDATE sowie single SELECT (liefert nur eine Ergebniszeile) alle DDL-Anweisungen DCL-Anweisungen: COMMIT, ROLLBACK an Stelle von USING ... kann auch allgemeiner ein SQL-Descriptor verwendet werden. Verbindung durch Deskriptoren: 73 Was muss geschehen, um z.B. eine mit einem Cursor verbundene dynamisch erzeugte SELECT-Anweisung auszuführen? Das Problem hierbei ist, dass die Struktur der Ergebnistabelle und damit die Struktur der FETCH-Anweisung erst zur Laufzeit bekannt ist. SQL stellt hierfür einen Deskriptor (DESCRIPTOR AREA) zusammen mit den Anweisungen ALLCOTE DESCRIPTOR DEALLOCATE DESCRIPTOR GET DESCRIPTOR SET DESCRIPTOR DESCRIBE Mit ALLOCATE DESCRIPTOR wird im Programm ein Speicherbereich reserviert, der der Kommunikation zwischen Programm und DBMS dient. Dieser Speicherbereich besteht im wesentlichen aus einem Zähler, der die Anzahl der folgenden Datenstrukturen angibt, sowie einem Array von Datenstrukturen, wobei jede Datenstruktur einen Wert – z.B. eine Spalte einer Ergebniszeile oder einer Hostvariablen – übertragen kann. Jede Datenstruktur enthält zumindest folgende Information, wobei nicht alle Informationen in jedem Falle gültige Informationen tragen: NAME enthält als Zeichenkette den Spaltennamen UNNAMED ist 1, falls die Spalte unbenannt ist, 0 sonst TYPE spezifiziert den übertragenen Datentyp LENGTH gibt die Länge an DATA enthält die übertragenen Daten PRECISION gibt bei Zahlentypen die "Precision" an SCALE beschreibt bei Zahltypen die "Scale" INDICATOR ist negativ, falls der NULL-Wert übertragen wurde Um den Deskriptor zu initialisieren, wird die Anweisung DESCRIBE OUTPUT prep_name USING SQL DESCRIPTOR desc_name aufgerufen. Damit wird Anzahl der Spalten sowie die Datentypen ermittelt. Mit jedem FETCH ... INTO SQLDESCRIPTOR desc_name wird die entsprechende Zeile aus der Ergebnistabelle ausgelesen und die Werte in die Felder DATA und INDICATOR in den entsprechenden Datenstrukturen des Descriptors gefüllt. Dann können sie mit entsprechenden GET DESCRIPTOR-Anweisungen ausgelesen werden. [Achilles, SQL, 267] Anlegen eines Deskriptors In diesem Fall muss die durch PREPARE vorbereitete SQL-Anweisung mittels DESCRIBE ausgewertet und ein "Descriptor" erstellt werden, der dann für die Umsetzung und Auswertung der Struktur verwendet werden kann. satz = "SELECT * FROM student"; EXEC SQL PREPARE prep FROM :satz; EXEC SQL DECLARE c1 CURSOR FOR prep; EXEC SQL ALLOCATE DESCRIPTOR desc; EXEC SQL DESCRIBE OUTPUT prep USING SQL DESCRIPTOR desc; EXEC SQL OPEN c1; /* Lese- und Verarbeitungsschleife mit: */ EXEC SQL FETCH c1 INTO SQL DESCRIPTOR desc; EXEC SQL GET DESCRIPTOR desc VALUE 1 :matrnr = DATA ; ... ; /* Ende der Lese- und Verarbeitungsschleife */ EXEC SQL CLOSE c1; EXEC SQL DEALLOCATE DESCRIPTOR desc; 74 Dies wird insbesondere bei dynamischen SELECT-Anweisungen benötigt: EXEC SQL ALLOCATE DESCRIPTOR demo_descriptor ; // Initialisieren des Descriptors EXEC SQL DESCRIBE prep_anweisung USING SQL DESCRIPTOR demo_descriptor ; // Zugriff: EXEC SQL GET DESCRIPTOR demo_descriptor :anzahl = COUNT ; EXEC SQL GET DESCRIPTOR demo_descriptor VALUE :i :var1= INFO, ... die wichtigsten Eigenschaften sind NAME, UNNAMED, TYPE, LENGTH, DATA, PRECISION; SCALE, INDICATOR SELECT sql_frage = 'SELECT KNUMMER, KNAME FROM KUNDEN WHERE KNAME LIKE ?' ; EXEC SQL PREPARE prep FROM :sql_frage; EXEC SQL ALLOCATE curs CURSOR FOR prep; EXEC SQL ALLOCATE DESCRIPTOR d_in ; EXEC SQL ALLOCATE DESCRIPTOR d_out; EXEC SQL DESCRIBE INPUT prep USING SQL DESCRIPTOR d_in; EXEC SQL DESCRIBE OUTPUT prep USING SQL DESCRIPTOR d_out; EXEC SQL SET DESCRIPTOR d_in VALUE 1 DATA=:string; EXEC SQL OPEN curs USING SQL DESCRIPTOR d_in; // Schleife zum Auslesen ... EXEC SQL FETCH curs INTO SQL DESCRIPTOR d_out; Bei der statischen Einbettung müssen alle SQL-Anweisungen bereits ausformuliert sein – die einzige Laufzeitmodifikation ist die Belegung von Variablen der Wirtssprache mit Werten. Es ist somit unmöglich, die Bedingungen im where-Teil einer SQL-Anfrage beliebig zur Laufzeit zu bestimmen (etwa vom Anwender interaktiv zusammenstellen zu lassen). Um derartige Modifikationen zur Laufzeit einer Anwendung zu ermöglichen, wurde die sogenannte dynamische Einbettung unter dem Namen Dynamic SQL entwickelt. In Dynamic SQL werden SQL-Anfragen als Zeichenketten in Variablen der Wirtssprache abgelegt. Spezielle SQL-Variablen (vom Datentyp statement) enthalten die übersetzte und optimierte Anfrage. Folgerichtig benötigen wir zwei Anweisungen zum Arbeiten mit Dynamic SQL: Die Anweisung prepare erzeugt einen internen optimierten Anfrageplan aus einer Zeichenkette, und execute führt die umgesetzte Anfrage dann aus. In einem konkreten Beispiel kann das wie folgt aussehen: exec sql begin declare section; dcl AnfrageString char (256) varying; exec sql end declare section; exec sql declare AnfrageObjekt statement; AnfrageString = 'DELETE FROM Vorlesungen WHERE SWS < 2'; exec sql prepare AnfrageObjekt from :AnfrageString; 75 exec sql execute AnfrageObjekt; In der Anfrage haben wir bewusst die Schlüsselwörter der Löschanweisung nicht hervorgehoben, um deutlich zu machen, dass es sich hier tatsächlich nur um eine Zeichenkette handelt. Die beiden aufeinanderfolgenden Anweisungen prepare und execute können zu einem execute immediate zusammengefasst werden. Sollen Variablen der Wirtssprache als Parameter der SQL-Anfrage genutzt werden, wie es in der statischen Einbettung üblich ist, müssen in der SQL-Anfrage Platzhalter (das Symbol ?) eingesetzt und die aktuellen Werte bei der Ausführung mittels der Angabe using übergeben werden. Das Prinzip zeigt das folgende Beispiel: ... AnfrageString= 'DELETE FROM Buch_Versionen '+ 'WHERE ISBN = ? AND Auflage = ?'; exec sql prepare AnfrageObjekt from :AnfrageString; exec sql execute AnfrageObjekt using :LöschISBN, :LöschAuflage; Der Transfer von Ergebnissen einer Anfrage unter Dynamic SQL in das Anwendungsprogramm ist naturgemäß aufwendiger als im statischen Fall. Das Datenbanksystem legt in einer speziellen Datenstruktur (sqlda für SQL Description Area) die Typinformationen bezüglich der Ergebnisrelation einer Anfrage bereit. Das Anwendungsprogramm muss diese Information interpretieren, dynamisch Speicherplatz für Ergebnistupel anfordern und kann danach mit der bekannten fetch-Anweisung auf den Anfrageergebnissen arbeiten... [Heuer, Saake; Datenbanken, Konzepte und Sprachen] Prinzipielle Probleme durch die Verwendung des Precompilers in Zusammenarbeit mit dem DBMS sind die problematische Anbindung zwischen Programm und DBMS: kein ExceptionHandling, unterschiedliche Operatoren, Abhängigkeit von DBMS- und Precompiler-spezifischen Bibliotheken, die schlechte Portierbarkeit auf andere Systeme, ggf. schwieriges Debugging. CLI: Bei Benutzung von eingebetteten SQL-Anweisungen treten folgende Probleme auf: - - Die Verbindung zwischen Host-Sprache und eingebetteten SQL-Anweisungen ist problematisch: je nach Hostsprache unterscheiden sich Operatoren in Programm und SQL-Anweisung, es existiert eine nur geringe Rückkopplung der Ausnahmebehandlung durch die WHENEVER-Anweisung. Die zur Laufzeit ermittelten SQL-Anweisungen (dynamisches SQL) müssen noch durch die Aufrufe von PREPARE und EXECUTE übersetzt werden. Da die Standardisierung auf Quelltextebene erfolgt, wird auch in diesem Falle keine Unabhängigkeit vom Precompiler gegeben: zumindest müssen die spezifischen Bibliotheken vorhanden sein, die die Prozeduren enthalten, auf die der durch den speziellen Precompiler übersetzte Quelltext zugreift. 76 - Schon durch die Verwendung eines Precompilers sind Anwendungen nicht mehr ohne weiteres auf andere Systeme portierbar. Sprach- und DBMS-unabhängige Schnittstelle von Prozeduraufrufen keine Inkonsistenzen zwischen Hostsprache und SQL Übersetzung der SQL-Anweisungen zur Laufzeit dazu wird nur das DBMS benötigt Bibliotheken sind sprach- und DBMS-unabhängig => Software-Firmen können Anwendungen im Object-Code weitergeben Zugriff auf mehr als ein DBMS möglich Debugging wird erleichtert CLI zielt darauf ab, eine sprach- und DBMS-unabhängige standardisierte Schnittstelle zu schaffen. Dabei wird die Verbindung zum DBMS durch eine Bibliothek von Prozeduren/Funktionen hergestellt. Dieser Ansatz löst die oben aufgezeigten Probleme: - - - Da nur noch die Host-Sprache benutzt wird, treten die alten Inkonsistenzen zwischen Hostsprache und SQL nicht mehr auf. Es bleibt zwar die Übersetzung der SQL-Anweisungen zur Laufzeit, diese wird aber ausschließlich vom DBMS vorgenommen. Die entsprechenden ProzedurAufrufe sind standardisiert, so dass die Bibliotheken generell verfügbar sind, unabhängig von einem speziellen DBMS. Somit können Anwendungen von Software Firmen als Object-Code ohne weiter Zusätze weitergereicht werden. Aufgrund der Standardisierung werden die Programme zugleich unabhängig vom jeweiligen DBMS. Sie können ohne Modifikation mit unterschiedlichen Datenbanksystemen arbeiten. Der gleichzeitige Zugriff auf mehrere DBMS wird durch geeignete Programmierung möglich. Zusätzlich ergibt sich eine Verbesserung beim Debugging eines Programms mit CLI-Bindung: da kein Precompiler zusätzlichen Code generiert, müssen nur die selbst geschriebenen Code-Teile überprüft werden. Es stellt sich die Frage, was dann noch der Vorzug von Embedded SQL ist. Zwei Aspekte müssen dabei betrachtet werden: Jede SQL-Anweisung, die von CLI übermittelt wird, muss als dynamische SQL-Anweisung aufgefasst werden. Betrachtet man z.B. die statischen eingebetteten SQL-Anweisungen bei DB2, so steht den für CLI aufgezeigten Vorteilen zumindest bei dem DBMS DB2 der Nachteil einer Performance-Einbuße gegenüber, sofern sich die in den Tabellen zugrundeliegenden Daten nicht zu schnell ändern und damit andere Zugriffspfade günstiger werden. Zum anderen kann durch das Binden, das bei Programmen mit Embedded SQL notwendig ist, eine weitere Sicherheitsstufe bzgl. der Programmausführung geschaffen werden. [Achilles, SQL] Nachteile gegenüber Embedded SQL: durch Binden lassen sich bei Embedded SQL weitere Sicherheitsstufen einbauen 77 bei statischem SQL sind unter Umständen durch Voroptimierung effizientere Programme möglich, da bei CLI jede SQL-Anweisung erst vom DBMS übersetzt und optimiert werden muss. Typische Verarbeitung: Während bei eingebetteten SQL-Anweisungen nur die Verbindung zur Datenbank mittels einer CONNECT-Anweisung erfolgen muss, ist bei einer CLI-Anwendung etwas mehr Aufwand nötig. Durch entsprechende Aufrufe müssen vor der eigentlichen Transaktionsverarbeitung Datenstrukturen und "Handle" (Zeiger) auf diese Strukturen bereitgestellt werden. Deshalb findet man in einer CLI-Anwendung folgende Schritte: Initialisierung, Transaktionsverarbeitung und Terminierung. Die zur Steuerung der Anwendung benötigten Handle – und damit die Datenstrukturen können in drei Typen eingeteilt werden. Die Umgebungshandle (Environmenthandle) dient zur Beschreibung des globalen Zustands der Anwendung. Zu jeder konkreten Verbindung muss eine eigene Datenstruktur mit einem darauf verweisenden Verbindungshandle (Connectionhandle) erzeugt werden. Hiermit werden die für diese Verbindung gültigen Operationen, der Transaktionsstatus, generelle Status- und diagnostische Informationen usw. verwaltet. Für jede SQL-Anweisung muss eine entsprechende Datenstruktur mit Anweisungshandle (Statementhandle) bereitgestellt werden, der darauf verweist. Initialisierung: Das folgende Beispiel stellt die zur Initialisierung nötigen Schritte vor. Es werden nur die relevanten Ausschnitte eines Programms dargestellt, wobei davon ausgegangen wird, dass die durch server, user und password angegebenen Zeichenketten entsprechend initialisiert sind. In dem Beispiel werden die Reihenfolge der Aufrufe, das Anlegen der Handles sowie die Argument-Übergabe für die Funktion SQLConnect() demonstriert. Als erstes muss ein Handle für die SQL-Umgebung angelegt werden. Der Aufruf SQLAllocHandle dient grundsätzlich zur Erzeugung und Initialisierung der benötigten Datenstrukturen sowie der Rückgabe des Handles. Erst nachdem eine SQL-Umgebung in Form eines Handles vorhanden ist, kann ein Verbindungshandle erzeugt werden. Damit stehen die benötigten Datenstrukturen bereit, um einen Verbindungsaufbau herzustellen. Der hierzu benötigte Aufruf SQLConnect benötigt als Argumente den Verbindungshandle, die Zieldatenbank (oder SQL-Server), die Benutzerkennung sowie das zugehörige Passwort. Da diese letzten drei Argumente als Zeichenketten übergeben werden, muss noch übermittelt werden, ob diese Zeichenketten durch eine Längenangabe bestimmt oder durch 0 terminiert werden. Hierzu dient der nach jeder Variablen übergebene Wert SQL_NTS. /*Verbindungsaufbau*/ /*Vereinbarungen*/ 78 SQLHENV henv; SQLHDBC hdbc; SQLCHAR *server; /* identifiziert den SQL-Server */ SQLCHAR *user; /* identifiziert den Benutzer */ SQLCHAR *password; /* das zugehoerige Passwort */ ... /* SQL-Umgebung bereitstellen */ rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ); /* Verbindungshandle anlegen */ rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ); /* Verbindungsaufbau SQL_NTS: Null-terminierte Zeichenkette, SQL_Success: erfolgreiche Ausführung */ if (SQLConnect (hdbc, server, SQL_NTS, user, SQL_NTS, password, SQL_NTS ) !=SQL_SUCCESS) return ( print_err(...) ); Noch ein Beispiel: /* Verbindungsaufbau es folgen einige "Handles" */ SQLHENV henv; SQLHDBC hdbc; SQLCHAR *server; SQLCHAR *user; SQLCHAR *password; SQLHSTMT hstmt; SQLCHAR stmt[] = "INSERT INTO student VALUES (?, ?, ?); SQLHSTMT hstmt; SQL_CHAR matrnr[7] = "1111111"; SQL_CHAR name[10] = "Mustermann"; SQL_CHAR adresse[10] = "Irgendwo 1"; /* SQL-Umgebung bereitstellen */ rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ); /* Verbindungshandle anlegen */ rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ); /* Verbindungsaufbau */ if (SQLConnect( hdbc, server, SQL_NTS, user, SQL_NTS, 79 password, SQL_NTS ) != SQL_SUCCESS ) return ( print_err(...) ); Transaktionsverarbeitung: Die Transaktionsverarbeitung besteht aus fünf Schritten: 1. Zuerst wird ein Handle angelegt, der auf eine Datenstruktur zur Steuerung der SQL-Anweisung verweist, 2. aufgrund der dynamischen Struktur von CLI muss die Anweisung vorbereitet und ausgeführt (SQLPrepare und SQLExecute) oder aber direkt ausgeführt werden (SQLExecDirect), 3. anschließend müssen die Ergebnisse verarbeitet und 4. die Transaktion mit COMMIT oder ROLLBACK durch einen Aufruf von SQLEndTran beendet werden. 5. Wird die SQL-Anweisung danach nicht mehr benötigt, so muss die Datenstruktur und das zugehörige Handle wieder freigegeben werden. (Zur Verdeutlichung sei hier darauf hingewiesen, dass für mehrere SQLAnweisungen die benötigten Handles gleichzeitig in Benutzung sein können.) /* Transaktionsverarbeitung */ rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ); rc = SQLPrepare( hstmt, stmt, SQL_NTS ); // da jede Anweisung dynamisch /* zur Parameterübergabe: */ rc = SQLGetStmrAttr( hstmt, SQL_ATTR_APP_PARAM_DESC, &hdesca, 0L, (SQLINTEGER *)NULL ); rc = SQLGetStmtAttr( hstmt, SQL_ATTR_IMP_PARAM_DESC, &hdesci, 0L; (SQLINTEGER *)NULL ); rc = SQLSetDescRec( hdesca, 1, SQL_C_CHAR, ... 7, ... (SQLPOINTER)matrnr), ...); rc = SQLSetDescRec( hdesci, 1, SQL_CHAR, ... 7, ...); ... rc = SQLExecute( hstmt ); rc = SQLEndTran( henv, SQL_COMMIT ); rc = SQLFreeStmt( hstmt, SQL_DROP ); Terminierung: Entsprechend der Initialisierung muss die Terminierung die Verbindung beenden und die Datenstrukturen sowie die darauf verweisenden Handle wieder freigeben. Das folgende Beispiel zeigt einen Verbindungsabbau. Es werden die gleichen Namen wie beim Verbindungsaufbau gewählt. Die Reihenfolge des Vorgehens ist derjenigen beim Verbindungsaufbau genau entgegengesetzt: zunächst muss die Verbindung zum DBMS beendet werden, sodann kann der Verbindungshandle und erst dann der Umgebungshandle freigegeben werden. /* Terminierung, Verbindungsabbau */ rc = SQLDisconnect( hdbc ); /* anschliessend kann der Handle fuer die Beschreibung einer Verbindung 80 (sowie entsprechende Datenstruktur freigegeben werden */ rc = SQLFreeHandle (SQL_HANDLE_DBC, hdbc); /* und nun kann auch die Umgebung vergessen werden */ rc = SQLFreeHandle( SQL_HANDLE_ENV, henv ); ... Beispiel: /* Terminierung */ rc = SQLDisconnect( hdbc ); rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ); rc = SQLFreeHandle( SQL_HANDLE_ENV, henv ); Innerhalb der Transaktionsverarbeitung: Statement-Handle bereitstellen: SQLAllocHandle() direkte Ausführung: SQLExecDirect(...) mehrfache Ausführung: o Vorbereiten: SQLPrepare() o Parameter übergeben: SQLSetDescRec() o Ausführen: SQLExecute() Ergebnisse bearbeiten: o Zeilenstruktur erkennen und Variablen an Zeilenstruktur binden Struktur beschreiben: SQLDescribeCol() Binden: SQLBindCol() o Zeile holen: SQLFetch() o Daten auslesen: SQLGetData() wurden Daten verändert: Bestimmung der Anzahl veränderter Zeilen: SQLRowCount() Transaktion beenden: SQLEndTran() Statement-Handle freigeben: SQLFreeHandle() Die typische Verarbeitung besteht aus Initialisierung, Transaktionsverarbeitung und Terminierung. Dies wird in dem folgenden "Beispiel" dargestellt: /* Verbindungsaufbau es folgen einige "Handles" */ SQLHENV henv; SQLHDBC hdbc; SQLCHAR *server; SQLCHAR *user; SQLCHAR *password; SQLHSTMT hstmt; SQLCHAR stmt[] = "INSERT INTO student VALUES (?, ?, ?); SQLHSTMT hstmt; SQL_CHAR matrnr[7] = "1111111"; SQL_CHAR name[10] = "Mustermann"; SQL_CHAR adresse[10] = "Irgendwo 1"; /* SQL-Umgebung bereitstellen */ rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ); /* Verbindungshandle anlegen */ rc = SQLAllocHandle( SQL_HANDLE_DBC, 81 henv, &hdbc ); /* Verbindungsaufbau */ if (SQLConnect(hdbc,server, SQL_NTS, user, SQL_NTS, password, SQL_NTS)!=SQL_SUCCESS) return ( print_err(...) ); /* Transaktionsverarbeitung */ rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc &hstmt ); rc = SQLPrepare( hstmt, stmt, SQL_NTS ); // da jede Anweisung dynamisch /* zur Parameterübergabe: */ rc = SQLGetStmrAttr(hstmt, SQL_ATTR_APP_PARAM_DESC, &hdesca, 0L,(SQLINTEGER*)NULL ); rc = SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_PARAM_DESC, &hdesci, 0L,(SQLINTEGER*)NULL); rc = SQLSetDescRec( hdesca, 1, SQL_C_CHAR, ... 7, ... (SQLPOINTER)matrnr), ...); rc = SQLSetDescRec( hdesci, 1, SQL_CHAR, ... 7, ...); ... rc = SQLExecute( hstmt ); rc = SQLEndTran( henv, SQL_COMMIT ); rc = SQLFreeStmt( hstmt, SQL_DROP ); /* rc rc rc Terminierung */ = SQLDisconnect( hdbc ); = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ); = SQLFreeHandle( SQL_HANDLE_ENV, henv ); ODBC Die Entwicklung von ODBC und die Standardisierung von CLI beeinflussen sich gegenseitig. Während CLI nicht direkt die Kommunikation über ein Netz adressiert, ist dies in ODBC integriert. ODBC setzt bei den Clients eine Microsoft-Umgebung voraus. IDAPI von Borland ist ebenso eine genormte Schnittstelle, die einen gleichzeitigen Einsatz unterschiedlicher Frontend-Systeme verschiedener Hersteller unabhängig vom eingesetzten Datenbank-Verwaltungssystem erlaubt. [Günter Matthiessen, Michael Unterstein; Relationale Datenbanken und SQL] Die wohl am weitesten verbreitete Version einer Call-Schnittstelle ist zur Zeit ODBC unter Microsoft Windows. Im wesentlichen stützt sich ODBC auf einen CLI-Standard von X/Open und der SQL Access Group. Diese Spezifikation wurde bei der ISO als Erweiterung von SQL vorgeschlagen und hat große Chancen als SQL/CLI-Norm übernommen zu werden. Die ODBC-Ebenen Eine ODBC-Anwendung hat fünf logische Ebenen (Layer): Anwendung, ODBCSchnittstelle, Treibermanager, Treiber und Datenquelle. [Sauer,Datenbanken] JDBC = Java Data Base Connectivity Vorteile Java im Hinblick auf Vereinfachung der Anwendungsentwicklung: - anstatt Anwendungen für jede Plattform neu zu entwickeln – insbesondere bzgl. der Oberflächenprogrammierung -, reicht eine Version, die ohne jeglichen Portierungsaufwand auf allen Plattformen eingesetzt werden kann, 82 - durch die Integration der Vernetzung ist diese Sprache prädestiniert für verteilte Applikationen, insbesondere für den Zugriff auf entfernte Datenbanken über ein Netzwerk, das Programmierparadigma verspricht zudem Unterstützung bei der Entwicklung von wiederverwendbarer Software – bis hin zu den heute wahrnehmbaren Ansätzen von Komponentensoftware. [Achilles, SQL] - Eigenschaften von Java: Sprache ist objektorientiert weitestgehend unabhängig von BS Vernetzung wird direkt unterstützt weitgehede Sicherheit eingebaut JDBC: Schnittstelle zu DBMS normiert, beruht auf CLI und SQL/92 Entry-Level Inzwischen bieten namhafte DBMS-Hersteller die Möglichkeit an, Java-DBMSProzeduren einzubinden Java: objekt-orientierte, Netzwerkfähige Sprache, die in kurzer Zeit große Bedeutung gewonnen hat. JDBC ist die Java-Schnittstelle zu relationalen DBM-Systemen, die auf CLI und SQL/92-Entry-Level aufsetzt. Anbindungsmöglichkeiten an (relationale) Datenbanken: 1. JDBC-ODBC-Bridge: Die als erstes entwickelte Verbindung setzte die JDBC-Aufrufe über eine spezielle Software in ODBC-Aufrufe um. Diese Entwicklung wurde vorgenommen, da die meisten Datenbanksysteme eine ODBC-Schnittstelle aufweisen. [Achilles, SQL] o schlechte Performance wegen mehrfacher Umsetzung, o ODBC-Treiber muss auf demselben Rechner wie die Java-Applikation installiert sein. 2. Java-DBMS-spezifische API: anstatt Umweg über ODBC kann direkt auf DBMS zugegriffen werden. Nachteile: o mangelnde Portabilität, o DBMS-Treiber muss auf demselben Rechner wie Java-Applikation installiert sein. 3. JDBC-Netz mit Pure Java Treiber: JDBC-Aufrufe werden mittels reinen Java-Treibern in ein Netzwerk-Protokoll übersetzt, das DBMS-unabhängig ist. Java-Server nimmt Aufrufe entgegen, übersetzt diese in DBMS-spezifische Aufrufe und kommuniziert mit dem DBMS. Die Kommunikation des Servers zur Datenbank beruht auf einer Herstellerspezifischen Schnittstelle. Dieser Ansatz ist sehr flexibel. Er ermöglicht die Anbindung verschiedener DBMS, macht hinsichtlich der Vernetzung keine Einschränkungen und lässt den Zugriff auf den Server nicht nur über Applikationen, sondern auch über Applets auf HTML-Seiten zu. 4. Natives Protokoll mit Pure Java Treiber: Im Gegensatz zum Vorhergehenden wandelt der Treiber die JDBC-Aufrufe sofort in 83 das vom DBMS verwendete Netzwerk-Protokoll um. Damit wird der DBMS-Server direkt vom Client aus aufgerufen. Der Vorteil liegt in dem minimierten Kommunikationsaufwand, er wird jedoch erkauft durch eine stärkere Hersteller-Bindung. [Achilles, SQL] Middleware: EJB-Technologie ermöglicht es, mehrere DBMS-Server einzubinden, unterstützt Skalierbarkeit, erzwingt Anwendung von Geschäftslogik JDBC besteht aus Klassen und Interfaces. Die wichtigsten sind: dient zum Laden eines Treibers und zum Aufbau einer DB-Verbindung java.sql.Connection stellt eine DBMS-Verbindung dar java.sql.Statement dient dazu, SQL-Anweisungen auszuführen java.sql.ResultSet erlaubt es, Ergebiszeilen auszuwerten java.sql.DriverManager Zugang wie bei CLI in Form eines "abgemagerten Beispiels". Zunächst muss zum Zugriff auf die Datenbank, die via url adressiert wird, ein entsprechender Treiber geladen werden. Dies erfolgt in der ersten try-catch-Klausel. Über die Klassenmethode forName wird im CLASSPATH nach einer Klasse mit dem Namen jdbc.Treibername gesucht und diese geladen. Diese Klasse wird in der Regel vom DBMSHersteller zur Verfügung gestellt. Durch das Laden wird der Treiber auch automatisch durch den Treibermanager (DriverManager) registriert. Da url neben der Adresse der Datenbank auch einen Verweis auf den Treiber enthält, kann mit der Klassenmethode getConnection anschließend eine Verbindung zur Datenbank aufgebaut werden. Schritte zur Verbindung JDBC und DB Schritt 1: Aufbau einer Datenbankverbindung Um mit einer Datenbank kommunizieren zu können, muss zuerst eine Verbindung hergestellt werden. Dazu ist ein Treiber erforderlich, der die Schnittstelle zwischen JDBCAPI und dem konkreten Datenbanksystem implementiert. Mit dem folgenden Kommando wird der JDBC-ODBC-Brückentreiber von Sun und Intersolv geladen: Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Über die URL der Datenbank findet der DriverManager, den passenden JDBC-Treiber. Der DriverManager ist eine Fabrikklasse die alle geladenen Treiber verwaltet. Er erzeugt ein Connection-Objekt, das die Datenbankverbindung repräsentiert. Alle SQL-Befehle werden über dieses Objekt gegen die Datenbank abgesetzt. Im Quelltext wird das Programm mit der Datenbank pizzaservice verbunden, das Connection-Objekt conn repräsentiert die Verbindung zu pizzaservice. Connection conn = DriverManager.getConnection("jdbc:odbc:pizzaservice"); Schritt 2: Erzeugen einer Tabelle SQL-Befehle werden mit Statement-Objekten gegen die Datenbanken abgesetzt. Für Anfragen und Änderungen stellt das Statement-Interface die Methoden executeQuery und executeUpdate zu Verfügung. Die Tabelle wird eigentlich mit dem Befehl CREATE TABLE erzeugt. Das Statement-Objekt übernimmt die Versendung. 84 Statement stmt = conn.createStatement(); stmt.executeUpdate("CREATE TABLE PizzaTabelle (" + " id INTEGER, " + " name CHAR(20), " + " preis FLOAT )" ); Schritt 3: Füllen der Tabelle Die Pizza Margherita wird mit INSERT in die PizzaTabelle geschrieben. Wie in Schritt 2 setzt das Statement-Objekt den Befehl ab. Die eigentliche Arbeit wird von dem SQL-Befehl erledigt. stmt.executeUpdate ("INSERT INTO PizzaTabelle" + "(id, name, preis) VALUES(12, 'Margherita', 7.20)"); Schritt 4: Anfragen Anfragen werden mit SELECT formuliert. Im Beispiel sollen aus der Tabelle alle Pizzen gelesen werden, die 9.80 DM kosten. Von diesen sollen alle verfügbaren Daten angezeigten werden. SELECT * FROM PizzaTabelle WHERE preis = 9.80 Für Anfragen wird ein Statement-Objekt verwendet, wie schon in den vorangegangenen Schritten. Die executeQuery Methode setzt den SELECT-Befehl ab und liefert ein ResultSet-Objekt als Ergebnis zurück. Schritt 5: Analyse des Ergebnisses Das Datenbanksystem erzeugt eine Tabelle als Ergebnis der Anfrage. Die Tabelle wird als ResultSet zur Verfügung gestellt. Dieses wird Element für Element durchlaufen. Jedem Element des ResultSets entspricht eine Zeile in der Ergebnistabelle. ResultSet rs = stmt.executeQuery("SELECT * FROM "+"PizzaTabelle WHERE preis = 9.80"); Die next-Methode steuert den Lesezeiger (Cursor) des ResultSets. Der erste Aufruf stellt den Lesezeiger an den Anfang, jeder weitere Aufruf verschiebt den Zeiger um jeweils ein Element. Der Rückgabewert der next-Methode ist vom Typ boolean. Solange der Lesezeiger auf ein Element der Treffermenge verschoben wird, liefert next als Rückgabewert true. Der Rückgabewert ist false, wenn das Ende der Treffermenge erreicht ist. while (rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); float preis = rs.getFloat("preis"); System.out.println ("Treffer: "+name+" , "+preis);} Jeder Datentyp XXX (z.B. String oder int) wird mit entsprechenden getXXX-Methoden aus dem ResultSet gelesen. Strings werden beispielsweise mit getString() gelesen, Integer mit getInt(). JDBC führt darüber eine Abbildung zwischen den SQL-Datentypen der Datenbank und den Java-Datentypen durch. 85 Schritt 6: Schließen der Verbindung und freigeben der Ressourcen Bei Beendigung des Programms müssen die belegten Ressourcen freigegeben werden, und dazu gehört auch eine Datenbankverbindung. Findet die Freigabe nicht statt, gehen begrenzte Datenbankressourcen wie Cursor oder Verbindungen aus, im schlimmsten Fall kann auf die Datenbank nicht mehr zugegriffen werden. rs.close(); stmt.close(); conn.close(); Querschnittsfunktion: Fehlerbehandlung Die Korrektheit der SQL-Strings kann erst zur Laufzeit geprüft werden. Zusätzliche Fehler können während des Zugriffs auf eine Datenbank auftreten. Eine geworfene SQLException repräsentiert einen Fehler. Dieser muss vom Programm behandelt werden. Im Beispiel wird nur der Fehlertext ausgegeben. try{ \\ der oben behandelte Code } catch (SQLException ex) { System.err.println(ex.getMessage()); } [Zimmermann, Beneken; Verteilte Komponenten und Datenbankanbindung; 173] Beispiel Verbindungsaufbau: try { Class.forName( "jdbc.Treibername" ); // Laden des Treibers Connection conn = DriverManager.getConnection( url, "userid", "password" ); } catch (java.lang.ClassNotFoundException e) { ... } catch (java.sql.SQLWarning e) { ... } catch (java.sql.SQLException e) { ... } beim Laden eines Treibers wird der statische Initialisierer aufgerufen dieser registriert "sich" beim DriverManager => damit kann der DriverManager bei Verbindungsanfragen auf den Treiber zugreifen die Klassen-Methode getConnection der Klasse DriverManager dient zum Aufbau der Verbindung zu einer Datenbank: o das erste Argument spezifiziert Treibertyp und Datenbank, z.B.: jdbc:odbc:DemoDB URL-Darstellung, immer mit jdbc beginnend; in diesem Falle eine JDBC-ODBC-Bridge. DemoDB ist der Name der Datenbank o das zweite Argument ist die Benutzerkennung o das dritte Argument das zu dieser Benutzerkennung gehörige Passwort 86 Achtung: Voreinstellung für autoCommit ist true (vgl.: Java-Transaktionen) das Objekt conn vom Typ Connection besitzt eine Implementation der Schnittstelle Connection damit kann es o Statement-Objekte erzeugen, um SQL-Anweisungen an die Datenbank zu übergeben o PreparedStatement-Objekte erzeugen, um SQL-Anweisungen aufzubereiten und wiederholt parametrisiert auszuführen o CallableStatement-Objekt erzeugen, um Stored Procedures aufzurufen o mit der Methode natievSQL( String sqlAnweisung ) die aus der JDBC-sqlAnweisung erzeugte native SQL-Anweisung anzeigen, die an das DBMS übermittelt wird o Metadaten über die Verbindung abfragen, Informationen über unterstützte SQL-Grammatik, Stored Procedures, Tabellen, usw. o die Verbindung schließen ( close() ) geschieht automatisch, wenn Gabage Collector das Verbindungsobjekt löscht o nur lesende Zugriffe erlauben o Transaktionen unterstützen entweder im autoCommit-Modus oder direkt durch commit() und rollback() o den Isolationsgrad durch setTransactionIsolation(..) setzen (vgl. SET TRANSACTION) Ein anderes Beispiel: try { Class.forName( "jdbc.Treibername" ); Connection conn = DriverManager.getConnection( url, "userid", "password" ); } catch (java.lang.ClassNotFoundException e) { ... } catch (java.sql.SQLWarning e) { ... } catch (java.sql.SQLException e) { ... } Statement stmt = conn.createStatement(); try { stmt.executeUpdate( "INSERT INTO student VALUES( '701199', 'Meier', 'Irgendwo' )" ); ResultSet result = stmt.executeQuery( "SELECT * FROM student" ); while ( result.next() ) { String matrnr = result.getString( 1 ); String name = result.getString( 2 ); if ( result.wasNull() ) System.out.println( "Fehler: kein Name für " + matrnr + " angegeben" ); ... } catch (java.sql.SQLException e) {...} Für eine SQL-Anweisung, die nur einmal durchgeführt werden soll, wird mit Statement anweisung = verbindung.createStatement(); in einer bestehenden Verbindung ein Obekt der Klasse Statement erzeugt. 87 Wie dieses Beispiel zeigt, kann für eine bestehende Verbindung mit der Methode createStatement ein Objekt erzeugt werden, mit Hilfe dessen parameterlose SQL-Anweisungen ausgeführt werden können. So kann eine solches Objekt benutzt werden, um mittels executeUpdate die gewünschte INSERT-, UPDATE- oder DELETE-Anweisung direkt auszuführen. Ebenso können damit CREATE, DROP-, GRANT- oder REVOKE-Anweisungen durchgeführt werden. int n = anweisung.executeUpdate("INSERT INTO teile " + "VALUES('A0110', 'walze', 10, 5.20,'lange Walze')"); Der Integerwert n gibt die Anzahl der veränderten Zeilen zurück. Ausführen von SQL-Anweisungen: innerhalb eines Connection-Objektes stehen die Methoden createStatement() erzeugt ein Statement-Objekt prepareStatement( String sqlAnweisung ) erzeugt ein PreparedStatement-Objekt prepareCall( String sqlAnweisung ) erzeugt ein CallableStatement-Objekt bereit, um die Voraussetzungen zu schaffen, SQL-Anweisungen zu bearbeiten Statement-Interface: int anzahl; Statement stmnt = conn.createStatement(); anzahl = stmnt.executeUpdate( "CREATE TABLE test " + "(NUMMER INTEGER, NAME VARCHAR(20)) " ); anzahl = stmnt.executeUpdate( "INSERT INTO test " + "VALUES( 1, 'Demozeile' )" ); ResultSet rs = stmnt.executeQuery( "SELECT * FROM test" ); ... stmnt.close(); Das Interface enthält als wichtigste Methoden: executeUpdate( String sqlAnweisung ) diese dient dazu, eine SQL-INSERT-, UPDATE- oder DELETEAnweisung oder SQL-DDL-Anweisungen ohne Parameter an das DBMS zu übermitteln und direkt auszuführen executeQuery( String sqlSelect ) übergibt beliebige parameterlose SQL-SELECT-Anweisungen an das DBMS und erzeugt ein Objekt vom Typ ResultSet, das die Ergebniszeilen enthält und zugreifbar macht. (Vgl. Cursor-Konzept) 88 Um eine SELECT-Anweisung auszuführen, muss die Methode executeQuery verwendet werden. Diese liefert ein Objekt vom Typ ResultSet zurück. ResultSet ergebnis = anweisung.executeQuery("SELECT * FROM lager" + "WHERE REGAL = 1"); Ein Objekt der Klasse ResultSet entspricht dem Cursor-Konzept: beim Erzeugen durch executeQuery wird eine Menge von Ergebniszeilen ermittelt, der "Cursor" wird vor die erste Zeile dieser Menge gestellt. Mittels der boolschen Methode next wird die jeweils nächste Ergebniszeile bereitgestellt. Diese Methode liefert den Wert false, falls keine weitere Ergebniszeile vorhanden ist. Zugriffsmethoden getString, getInt usw. geben die Daten der gewünschten Spalte zurück. Die Spalte kann über einen Index oder über ihren Namen adressiert werden. Nach dem Auslesen einer Spalte kann mittels der Methode wasNull abgefragt werden, ob der NULL-Wert übergeben wurde. Neben diesen Methoden gibt es weitere Methoden um: die maximale Länge von Ergebnisfeldern abzufragen bzw. zu begrenzen die maximale Anzahl von Ergebniszeilen abzufragen oder zu begrenzen ein Timeout für die Dauer der Ausführung der Anweisung abzufragen oder zu begrenzen die SQL-Warnings auszulesen einen Cursor-Namen zu vereinbaren bei SELECT FOR UPDATE kann dann in einem anderen Statement positioniertes UPDATE, DELETE (WHERE CURRENT OF cursor) verwendet werden beliebige SQL-Prozeduren aufzurufen, die ggf. mehrere SELECTAnfragen beinhalten: execute( String sqlProzedur ) Methoden, um weitere ResultSet bzw. UpdateCounts zu ermitteln, wenn mehrere erzeugt worden sind um das Statment-Objekt zu schließen: close() Nachdem ein solches Objekt zur Verfügung steht, können darauf eine Reihe von Methoden angewendet werden; die Wichtigsten sind: - - - - executeUpdate(); das Argument dieser Methode enthält eine INSERT-, UPDATE- oder DELETEAnweisung, die ausgeführt wird, executeQuery(); die einen Resultset zurückgibt; ein Resultset entspricht in gewissem Sinne dem Cursor, execute(); um auch z.B. gespeicherte Prozeduren, die ggf. mehrere Resultsets zurückgeben, bearbeiten zu können, getResultSet(); 89 hiermit kann auf die erzeugte Ergebnismenge zugegriffen werden. Mit getMoreResults() lässt sich z.B. bei gespeicherten Prozeduren auf weitere Ergebnismengen zugreifen, setQueryTimeout(); um die Anzahl von Sekunden zu begrenzen, bis der Treiber die Ausführung der Anweisung abbricht, falls sie bis dahin nicht beendet wurde, und close(); um die Ressourcen des Objekts freizugeben [Achilles, SQL] PreparedStatement-Interface: (ist von Statement abgeleitet) PreparedStatement prep = conn.prepareStatement( "INSERT INTO test VALUES( ?, ? )" ); prep.setInt( 1, 2); prep.setString(2, "Zeile 2"); prep.executeUpdate(); Soll eine Anweisung mehrfach während eines Programmlaufs benutzt werden, so ist es sinnvoller und effizienter, sie nur einmal aufzubereiten und dann mehrfach auszuführen. Dies entspricht der Verwendung von PREPARE und EXECUTE bei embedded SQL, die zugehörige Klasse heißt deshalb PreparedStatement. Die Verwendung soll zunächst an der Einfügung mehrerer Zeilen in die Tabelle student gezeigt werden: PreparedStatement prepStmt = conn.prepareStatement( "INSERT INTO student VALUES (?, ?, ?)" ); /* Die folgenden Anweisungen werden dann mehrfach wiederholt */ /* Einlesen der einzufügenden Daten ..., ...., ..... */ prepStmt.setString( 1, "..." ); prepStmt.setString( 2, "...." ); prepStmt.setString( 3, "....." ); prepStmt.executeUpdate(); /* und wieder einlesen, siehe oben */ Dieses Beispiel zeigt zugleich, wie mit Parametern gearbeitet wird: wie bei embedded SQL werden bei der vorzubereitenden SQL-Anweisung positionale Parameter mit Hilfe des Zeichens "?" verwendet. Vor Ausführen der aufbereiteten Anweisung müssen die positionalen Parameter noch explizit mit Daten gefüllt werden. Hierzu werden die Zugriffsmethoden setString, setInt usw. benötigt, die als erstes Argument die Position des zu füllenden Parameters, als zweites die zu übergebenden Daten enthalten. Nachdem alle Daten übergeben wurden, wird dann die Ausführung mit der bereits bekannten Methode executeUpdate durchgeführt. In Zugriffsschichten werden Datenbankanfragen oder Änderungen sehr häufig durchgeführt. Der Parser der Datenbank ist jedes Mal gezwungen, den SQL-String zu analysieren und auf seine Korrektheit zu prüfen. Häufig wiederkehrende SQL-Befehle, bei denen sich höchstens die Parameter ändern, können als Prepared Statements (Vorübersetzte Befehle) effizienter formuliert werden. Der SQL-String wird genau ein Mal vom Datenbanksystem geparst und auf seine Korrektheit geprüft. Bei jeder Anfrage oder Änderung wird der Befehl nur noch mit konkreten Werten gefüllt. Betrachten wir das einführende Beispiel. Siehe brauner Text bei Aufbau der Datenbankverbindung. 90 Dort wird die Datenbanktabelle mit konkreten Pizzen gefüllt. Für jede Pizza wird eine neue SQL-Anweisung an die Datenbank geschickt. Für jeden Befehl muss das Datenbanksystem den Befehls-String parsen. Dieses Update kann eleganter und performanter über ein Prepared-Statement realisiert werden: PreparedStatement fuelleMitPizza = conn.prepareStatement( "INSERT INTO PizzaTabelle (id, name, preis)" + "VALUES (?,?,?); //... fuelleMitPizza.setInt(1,12); fuelleMitPizza.setString(2, "Margherita"); fuelleMitPizza.setFloat(3, 7.2f); fuelleMitPizza.executeUpdate(); Im PreparedStatement wird jeder variable Teil durch ein Fragezeichen gekennzeichnet. Das Fragezeichen ist ein Platzhalter für die Variablen. Analog zu den Lesemethoden der ResultSets stellt das PreparedStatement-Interface Methoden bereit, mit denen die Variablenwerte gefüllt werden können. Für jeden Datenttyp XXX existiert eine setXXX()Methode, um den Platzhalter mit Werten zu belegen. Jeder Platzhalter kann über einen Index referenziert werden. Im Beispiel belegen wir das erste Fragezeichen mit der ID der Pizza, das zweite mit dem Namen und das dritte Fragezeichen mit dem Preis. Der Index ist immer der erste Parameter in der setXXXMethode. ... [Zimmermann, Beneken; Verteilte Komponenten und Datenbankanbindung] Die SQL-Anweisung wird an das DBMS zur Analyse und "Vorübersetzung" geschickt. Das Interface enthält als wichtigste Methoden executeUpdate() diese dient dazu, die vorbereitete SQL-INSERT-, UPDATE- oder DELETE-Anweisung oder SQL-DDL-Anweisungen mit den vereinbarten Parametern an das DBMS zu übermitteln und auszuführen executeQuery() übergibt mit den vereinbarten Parametern die SQL-SELECTAnweisungen an das DBMS und erzeugt ein Objekt vom Typ ResultSet, das die Ergebniszeilen enthält und zugreifbar macht. (Vgl. Cursor-Konzept) Neben diesen sowie den ererbten Methoden gibt es weiterhin: clearParameter() hiermit werden alle vereinbarten Parameterwerte gelöscht set...( int nr, ... wert ) setzt den Parameter nr auf den angegebenen wert setNull( int nr, int sqlType ) setzt den angegebenen Parameter auf den NULL-Wert CallableStatement-Interface: (ist von PreparedStatement abgeleitet) // Vorbereitung: in der Regel nicht in rufenden // Programm enthalten 91 int anzahl; Statment stmnt = conn.createStatement(); anzahl = stmnt.executeUpdate( "create procedure SHOW_TEST "+ "AS select * FROM test WHERE NUMMER = ?" ); // Ende der Vorbereitung CallableStatement cstmnt = conn.prepareCall( "{call SHOW_TEST(?)}" ); cstmnt.setInt( 1, 2); ResultSet rs = cstmnt.executeQuery(); Eine Prozedur ist (in der Regel) unabhängig von der Ausführung eines Programmes in der Datenbank vorhanden und vorübersetzt. Das Interface enthält als wichtigste Methoden: execute() falls mehrere SQL-Anweisungen (insbesondere SELECT) durch die Prozedur zusammengebunden sind. executeUpdate() diese dient dazu, die Prozedur mit den vereinbarten Parametern aufzurufen und auszuführen executeQuery() erzeugt ein Objekt vom Typ ResultSet und führt die Prozedur mit den vereinbarten Parametern aus Neben den ererbten Methoden gibt es weitere Methoden um Ausgabe-Parameter zu registrieren registerOutParameter( int nr, int sqlType ) AusgabeParameter auszulesen var = get...( int nr ) den gerade ausgelesenen Parameterwert Auslesen von Ergebnistabellen auf NULL zu prüfen ResultSet-Interface: ResultSet rs = stmt.executeQuery( "SELECT * FROM test"); System.out.println("Nummer, Name "); while (rs.next()) { String eins = Integer.toString(rs.getInt( 1 ).toString()); String zwei = rs.getString( 2 ); System.out.println( eins + ", " + zwei ); } Die Klasse ResultSet entspricht dem Cursor-Modell. Beim Erzeugen des ResultSet wird der Cursor vor die erste Zeile positioniert, jeder Aufruf der next()-Methode rückt den Cursor eine Zeile weiter vor. Der in Java bereitgestellte Cursor kann ausschließlich als sequentieller Cursor verwendet werden. Gegenüber dem diskutierten Cursor-Modell sind also Einschränkungen vorhanden. Das folgende Beispiel skizziert die Ermittlung dieser Informationen: 92 int i; String sel = new String( "SELECT * FROM student" ); ResultSet rs = stmt.executeQuery( sel ); ResultSetMetaData rsMetaData = rs.getMetaData(); int AnzahlSpalten = rsMetaData.getColumnCount(); int sqlSpaltenTypen[] = new int[ (AnzahlSpalten+1) ]; // um Zählung bei 1 zu beginnen for ( i=1; i<=AnzahlSpalten; i++) { sqlSpaltenTypen[ i ] = rsMetaData.getColumnType( i ); } /* Bearbeitungsschleife */ String spaltenDaten[] = new String[ (AnzahlSpalten+1) ]; while ( rs.next() ) { for ( i=1; i <=AnzahlSpalten; i++ ) { spaltenDaten[ i ] = rs.getString( i ); } /* weitere Verarbeitung */ } Die wesentlichen Methoden sind: next() um die nächste Zeile zu lesen (den Cursur eine Zeile weiterzuschieben) get...( int nr ) bzw. get...( String spaltenName ) um die entsprechende Spalte, auf der der Cursor derzeit positioniert ist, auszulesen wasNull() um festzustellen, ob in der zuletzt ausgelesenen Spalte der NULL-Wert übertragen wurde getMetaData() um die Struktur des ResultSet analysieren zu können Analysieren der Struktur von Ergebnistabellen: ResultSetMetaData-Interface ResultSet rs = stmt.executeQuery( "SELECT * FROM test"); ResultSetMetaData rsmd = rs.getMetaData(); System.out.println("Anzahl der Spalten:"+ rsmd.getColumnCount()); for (int i = 1; 1 <= rsmd.getColumnCount(); i++) { int jdbcType = rsmd.getColumnType( i ); String tname = rsmd.getColumnTypeName( i ); String cname = rsmd.getColumnName( i ); } Ein Objekt vom Typ ResultSetMetaData enthält Methoden: getColumnCount() getColumnType( int nr ) getColumnName( int nr ) um die Anzahl der Spalten zu bestimmen um den JDBCType der entsprechenden Spalte zu bestimmen um den Namen der entsprechenden Spalte zu bestimmen 93 getPrecision( int nr ) getScale( int nr ) um Information über die Interna der Zahldarstellung der entsprechenden Spalte zu bekommen isAutoIncrement( int nr ) isCaseSensitive( int nr ) isSearchable( int nr ) isCurrency( int nr ) isNullable( int nr ) isSigned( int nr ) isReadOnly( int nr ) isWritable( int nr ) um weitere Informationen über die entsprechende Spalte zu bekommen JDBC 2.0 JDBC 2.0 ist zweigeteilt: Paket java.sql ist der Kern der SQL-Schnittstelle, der auch die alte API JDBC 1.0 enthält. Änderungen liegen in o Verbesserungen des ResultSet Scrollbar und änderbar o neue Datentypen: BLOB, CLOB o Batch-Updates Paket o o o o javax.sql JNDI Unterstützung Connection Pooling distributed Transactions RowSet-Objekte java.sql Ein Objekt vom Typ ResultSet muss nicht nur sequentiell mit next() durchlaufen werden, es gibt weitere Methoden zum beliebigen Zugriff: absolute( int nr ) positioniert auf die Zeile nr afterLast() beforeFirst() first() getRow() positioniert direkt hinter das Ende der letzten Zeile positioniert direkt vor die erste Zeile positioniert auf die erste Zeile liefert die Nummer der aktuellen Zeile zurück isAfterLast() isBeforeFirst() isFirst() gibt an, ob hinter der letzten Zeile positioniert ist gibt an, ob vor der ersten Zeile positioniert ist zeigt an, ob die Position auf der ersten Zeile liegt 94 isLast() last() entsprechend, ob die Position auf der letzten Zeile ist positioniert auf die letzte Zeile moveToInsertRow() hierbei handelt es sich um eine spezielle Zeile, die mit einem änderbaren ResultSet-Objekt verknüpft ist. Dadurch kann eine neue Zeile in das Objekt eingefügt werden. Bei dem Aufruf wird die aktuelle Position des Cursurs gemerkt moveToCurrentRow() steht der Cursur auf der Eingabezeile, so wird er daraufhin auf die ehemalige Position zurückgesetzt next() bereits in JDBC 1.0: positioniert auf die folgende Zeile previous() relative( positioniert auf die vorhergehende Zeile int verschiebt die Position um bei negativem Vorzeichen in Richtung Anfang anzahl anzahl ) Zeilen, Damit ein Objekt vom Typ ResultSet entsprechende Eigenschaften hat, muss das Statement-Objekt darauf eingerichtet werden: Statement stmnt = conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, // Scrolling zugelassen // Änderungen anderer // werden nicht wahrgenommen ResultSet.CONCUR_UPDATABLE); // Änderungen zugelassen Ist ein Objekt vom Typ ResultSet änderbar, so können folgende Methoden darauf angewandt werden: deleteRow() insertRow() löscht die aktuelle Zeile aus der Datenbank fügt den Inhalt der Eingabezeile in die Datenbank ein rowDeleted() rowInserted() rowUpdated() zeigt an, ob eine Zeile gelöscht wurde gibt an, ob eine Zeile eingefügt wurde zeigt, ob eine Zeile geändert wurde update...( int nr, typ wert ) updateNull( int nr ) updateRow() ändert in der aktuellen Zeile die Spalte nr auf wert setzt in der aktuellen Zeile die Spalte nr auf NULL ändert in der Datenbank die der aktuellen Zeile zugehörige Zeile Ändern einer Zeile in der Datenbank mittels eines änderbaren ResultSet-Objekts Statement stmnt = conn.createStatement( 95 ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmnt.executeQuery("SELECT * FROM test"); rs.absolute(2); // aktuelle Zeile ist Zeile 2 rs.updateString("NAME", "Zeile ZWEI"); // Ändern der zweiten Spalte der // aktuellen Zeile in "Zeile ZWEI" rs.updateRow(); // Eintragen in die Datenbank ... conn.commit(); // Transaktion beenden // damit Änderung für andere // sichtbar machen Einfügen in die Datenbank mittels eines änderbaren ResultSet-Objekts ... rs.moveToInsertRow(); // zur Eingabezeile gehen rs.updateInt( 1, 3); rs.updateString( 2, "3. Zeile" ); // Ändern der Spalten der Eingabezeile rs.updateRow(); // Eingabezeile in Datenbank eintragen rs.moveToCurrentRow(); // zurück zur alten aktuellen Zeile ... conn.commit(); // Transaktion beenden // damit Änderung für andere // sichtbar machen Weitere Verbesserungen des ResultSet: stmnt.setFetchSize( 25 ); ResultSet rs = stmnt.executeQuery( "SELECT * FROM test" ); // es werden zunächst nur 25 Zeilen // in den ResultSet rs geladen Weitere Ergebnisse mittels stmnt.getMoreResults() Neue Datentypen: die neuen SQL-Datentypen: BLOB (Binary Large Object) CLOB (Character Large Object) max. Länge 2 GB, auf Daten vom Typ CLOB kann nur beschränkt durch SQLAnweisungen zugegriffen werden. Andererseits können sie über einen eigenen Zugriffsmechanismus (LOB-Locator) abschnittweise gespeichert bzw. ausgelesen werden. ARRAY REF werden unterstützt, es gibt entsprechende Interfaces und get...(...) und set...(...)-Methoden in ResultSet 96 Auch benutzerdefinierte Typen werden durch das Interface Struct sowie die ResultSetMethoden getObject(...) und setObject(....) bereitgestellt. BLOB und CLOB wurden mit SQL-99 eingeführt und besitzen gegenüber LONG und LONG RAW meist erweiterte Funktionalität, was die interne Verwaltung im Datenbanksystem betrifft. Sie können beim Oracle-Server Daten bis zu 4 GB Größe aufnehmen und basieren beide auf so genannten LOB-Lokatoren. LOB-Lokatoren sind vereinfacht ausgedrückt Strukturen, die Zugang zu den LOB-Daten bieten. Die Daten selbst können dabei innerhalb oder außerhalb eines Datensatzes gespeichert werden. Der Zugriff auf BLOB- und CLOB-Typen kann auch genau wie auf LONG bzw. LONG RAW durchgeführt werden, so dass die Lokatoren weitestgehend verborgen bleiben. Beim Einfügen neuer LOB-Spalten mit Oracle ist jedoch zu beachten, dass zunächst mit der Methode empty_blob() bzw. empty_clob() LOB-Lokatoren erzeugt werden müssen, die später über UPDATE-Anweisungen mit Daten gefüllt werden können: ... long tit_id; // SQL-Anweisung initialisieren String sql = "INSERT INTO titel VALUES(?,?,?,?,?,?,?,empty_blob(),?,?,?)" PreparedStatement prep = con.prepareStatement(sql); // Parameter setzen und Anweisung ausführen ... prep.close(); String sql = "UPDATE titel SET bild = ? WHERE tit_id = ?"; PreparedStatement prep = con.prepareStatement(sql); // Parameter setzen und Anweisung ausführen [http://www.dpunkt.de/java/Programmieren_mit_Java/Java_Database_Connectivity/44 .html] Performance-Verbesserung durch "Batch": Statement stmnt = conn.createStatement(); conn.setAutoCommit( false ); stmnt.addBatch("INSERT INTO test VALUES( 4, 'Z4' )" ); stmnt.addBatch("INSERT INTO test VALUES( 5, 'zeile fuenf' )" ); stmnt.addBatch("INSERT INTO test VALUES( 6, 'sechs' )" ); int [] updateCounts = stmnt.executeBatch(); ... conn.commit(); Die Anweisungen werden in der Reihenfolge ausgeführt, in der sie dem Batch hinzugefügt wurden jede einzelne Anweisung muss eine Zahl zurückliefern, die die Anzahl der Änderungen angibt; diese Zahl wird dem Array updateCounts hinzugefügt. Ist dies nicht der Fall, wird eine BatchUpdateException geworfen. ein JDBC-Treiber muss nicht notwendig Batch unterstützen und die Methoden addBatch(...), clearBatch() und executeBatch() unterstützen Aufschluss über den letzten Punkt liefern die DatabaseMetaData: 97 DatabaseMetaData dbmd = conn.getMetaData(); if (dbmd.supportsBatchUpdates()) System.out.println( "der Treiber unterstützt Batch" ); Bei großen Änderungen in der Datenbank, die durch mehrere SQL-Befehle ausgeführt werden, sind die normalen JDBC-Mechanismen nicht besonders effizient, da jeder Befehl einzeln mit executeUpdate gegen die Datenbank abgesetzt wird. Das bedeutet jedesmal Kommunikation über das Netzwerk zwischen Anwendung und Datenbankserver. Mit JDBC 2.0 wurden daher Batches eingeführt. Mit den Methoden addBatch() und executeBatch() lassen sich mehrere SQL-Befehle zu einer einzigen Operation zusammenfassen. Die Befehle werden gemeinsam effizienter gegen den Datenbankserver abgesetzt und ausgeführt. SQL-Befehle sind nur dann batchfähig, wenn sie einen Zähler zurückliefern, der die Anzahl der geänderten Zeilen angibt. Die Befehle INSERT, UPDATE und DELETE sind batchfähig, CREATE TABLE, DROP TABLE und ALTER TABLE liefern 0 als Wert des Änderungszählers zurück und können auch verwendet werden. SELECT erzeugt dagegen eine Ergebnismenge und ist nicht batchfähig. Wird ein SELECT-Befehl in einen Batch integriert, wird eine BatchUpdateException geworfen. [Zimmermann, Beneken; Verteilte Komponenten und Datenbankanbindung] javax.sql JNDI: DataSource-Objekt repräsentiert eine Datenquelle: DBMS, Tabelle, Datei, ... wird vom Administrator mit entsprechendem Werkzeug bei JNDI (Java Naming and Directory Interface) Dienst registriert Anwendung kann unter logischem Namen danach beim JNDI suchen und dann die Verbindung herstellen Informationen über die Datenquelle - Name, Server, usw. - sind als Eigenschaften im DataSource-Objekt enthalten => müssen nicht mehr hart codiert werden => bei Verlagerung der Datenquelle muss Code nicht verändert werden Das Java Naming and Directory Interface dient dazu, auf beliebige Namens- und Verzeichnisdienste zuzugreifen. Ein Namensdienst liefert zu einem bestimmten Namen ein genau ein oder kein Objekt. Der Domain Name Service (DNS) ist ein solcher Dienst: Zu einem Host-Namen (z.B. www.dpunkt.de) liefert er die IP-Adresse (194.120.34.150). Ein Name dient also dazu, ein beliebiges Objekt genau zu identifizieren. [http://www.dpunkt.de/java/Programmieren_mit_Java/Java_Naming_and_Directory_In terface_(JNDI)/1.html#x2142] Verbindung mittels JNDI-API ohne Verwendung von Treibern: String lname = new String("jdbc/DemoDB"); // logischer Name für Datenquelle Context ctx = new InitialContext(); // JNDI-API 98 DataSource ds = (DataSource)ctx.lookup( lname ); // unter dem Namen "jdbc/DemoDB" wird // eine Datenquelle gesucht Connection conn = ds.getConnection( "NAME", "passwort" ); Verbindungsaufbau über JNDI ist insbesondere dann wichtig, wenn verteilte Transaktionen oder Connection Pooling eingesetzt werden soll Pooled Connection: um die Performance zu verbessern, ist es bei häufigen Zugriffen sinnvoll, eine Verbindung nicht völlig zu zerstören, sondern sie wiederzubenutzen durch entsprechende Maßnahmen stellt der Administrator einen Pool von Verbindungen zu einer Datenquelle bereit für die Programmierung ändert sich (fast) nichts Im folgenden sei unter dem logischen Namen jdbc/poolDB ein Pool von Verbindungen bereitgestellt. ctx = new InitialContext(); ds = (DataSource)ctx.lookup("jdbc/poolDB"); try { Connection conn = ds.getConnection( "NAME", "passwort" ); // und hier wird damit gearbeitet } catch (Exception e) {... } finally { if (conn != null) conn.close(); } Die finally-Klausel bewirkt, dass die Verbindung auf jeden Fall geschlossen wird, auch dann, wenn eine Ausnahme geworfen wird. Damit steht die Verbindung wieder im Pool bereit und wird nicht durch die Anwendung lange blockiert. Pooled Connections können zur Implementierung eines Connection Pools eingesetzt werden. Sie implementieren allgemein wiederverwendbare Datenbankverbindungen. Abbildung zeigt die generelle Funktionsweise einer Pooled Connection. 99 Abbildung 18.24: Wiederverwendung von Verbindungen in einem Connection Cache Nachdem man einen Verweis auf ein Exemplar der Klasse ConnectionPoolDataSource erhalten hat, kann man durch Aufruf von getPooledConnection() eine neue Verbindung erzeugen: PooledConnection pc = ds.getPooledConnection("shop", "shop"); Bei diesem Aufruf wird eine neue Verbindung zur Datenbank aufgebaut und intern in der Klasse PooledConnection zwischengespeichert. Je nachdem, ob man Benutzer und Passwort bereits in der Datenquelle gesetzt hat, muss man beim Aufruf von getPooledConnection() Benutzer und Passwort übergeben (wie hier im Beispiel). Die Klasse PooledConnection stellt ihrerseits die Methode getConnection() zur Verfügung, die ein Exemplar vom Typ Connection zurückliefert, das für die Datenbankabfrage benutzt werden kann: Connection con = pc.getConnection(); // Hier Datenbankabfragen ... Mit jeder Pooled Connection ist eine physische Datenbankverbindung assoziiert. Beim Aufruf von getConnection() wird ein logisches Connection-Exemplar erzeugt, das intern die physische Verbindung zugewiesen bekommt. Damit ist die physische Verbindung einem Client zugeordnet. Die logische Verbindung hat die Funktion einer Wrapperklasse und leitet intern die Aufrufe an die physische Verbindung weiter. Hat der Client seine Arbeit beendet und die Verbindung wird nicht mehr benötigt, ruft er die close()-Methode der logischen Verbindung auf. Dadurch wird allerdings nicht wirklich die physische Verbindung zur Datenbank geschlossen. Diese wird lediglich wieder freigegeben. Man sollte beachten, dass Pooled Connections keine Synchronisations-Mechanismen besitzen. Erfolgt ein zweiter Aufruf von getConnection(), bevor die erste Verbindung mit close() geschlossen wurde, wird die physische Verbindung der gerade aktiven logischen Verbindung entzogen und der neu erzeugten Verbindung zugewiesen. Bei nachfolgenden Zugriffen auf die erste Verbindung wird eine SQL-Exception mit der Fehlermeldung »Logisches Handle nicht mehr gültig« ausgelöst. [http://www.dpunkt.de/java/Programmieren_mit_Java/Java_Database_Connectivity/48.html#i d423] 100 Verteilte Transakionen: auch hier wird die wesentliche Arbeit beim "Deployen" erledigt: die Datenquelle muss korrekt beim JNDI angemeldet werden und dabei mit einer XADataSource verbunden werden die Anmeldung im Programm verläuft wieder wie gehabt, d.h. verteilte Transaktionen sind für den Programmierer nahezu transparent ein TransactionManager verwaltet im Hintergrund die Transaktion einzig folgende Restriktionen sind zu beachten: verboten sind die Aufrufe conn.commit() conn.rollback() conn.setAutoCommit(true) RowSet: dient als "Behälter" für Zeilen Implementation ist ein Aufsatz auf den Treiber erweitert ResultSet unterstützt das JavaBeans Modell => hat Methoden um Listener hinzuzufügen, zu entfernen und deren Eigenschaften festzulegen eine spezielle Eigenschaft ist das Kommando, das gesetzt und ausgeführt werden kann => ein RowSet kann sein Kommando selbst einstellen und ausführen und sich somit selbst mit Daten versorgen ein RowSet kann sich nach dem Laden von der Datenquelle abkoppeln es kann in abgekoppelten Zustand serialisiert werden => es eignet sich zur Versendung über das Netz z.B. zu einem PDA es kann aktualisiert und dann zum Datenabgleich erneut mit seiner Datenquelle verbunden werden 101 Optimierung Dieser Abschnitt soll in Stichworten einige Aspekte des physischen Entwurfs weiter erläutern. Die Optimierung einer DB-Implementation kann zumindest in folgende Aspekte unterteilt werden: Bezogen auf einen Knoten (auf eine einzelne Datenbank, auf einem Rechner): o Installation des DBMS o Bereitstellung von physischem Speicherplatz und Plazierung der Tabellen o Denormalisierung o Partitionierung der Tabellen o Clusterung o Indexierung Knotenübergreifend (einzelne Datenbank, verteilte Datenbanken, im Rechnernetz): o Verteilung o Replikation Optimierung eines Knotens Installation des DBMS An dieser Stelle kann in der Regel folgendes beeinflusst werden: Für die Installation eines Datenbanksystems ist es bzgl. Performance eher günstig, viele kleinere Platten zu haben, und die verschiedenen Dateien darauf zu verteilen, als wenige große Platten, da Datenbanksysteme „Ressourcenfresser“ sind! Insbesondere sollten Index-, Daten und Logdateien immer auf verschiedenen Platten liegen. Größe und Zugriffverhalten auf das Dictionary Das DD ist eine Metadatenbank (manchmal auch catalog genannt), die alle Informationen über die Datenbank strukturiert vorhält. Diese Informationen kann man unterteilen in statische und dynamische Informationen: statisch: welche Objekte (Tabellen, Indizes, Sequences, User), welche Rechteverteilung, Quoten, ..., welche Datenfiles, Logfiles existieren, usw... dynamisch: welcher User ist aktiv mit welchen Transaktionen, welche Transaktionen sind offen, abgeschlossen, in welche Logdateien wird geschrieben, usw. All diese Informationen sind z. B. in relationalen Datenbanksystemen wieder in Tabellen abgelegt. Das DBMS muss das komplette DD jederzeit in unmittelbarem Zugriff haben, wenn nicht die Abfragebearbeitung stocken soll, weil auf Informationen gewartet werden muss. Je aktiver und größer eine Datenbank ist, desto umfangreicher ist das DD. Ziel muss sein, das DD komplett im Hauptspeicher des Datenbank-Servers zu halten! 102 Managementaufgabe: Einstellen gewisser Datenbank-Parameter, so dass das DD komplett in den Arbeitsspeicher passt. Vermeidung von Congestion (Duden: Anhäufung), also Engpässen beim Zugriff auf das Dictionary. Überwachung der Datenbank durch regelmäßiges Kontrollieren bestimmter Informationen des DD. Blockgrössen und somit Zugriffsverhalten des physischen IO auf die Daten: Die Informationen müssen in einer Datenbank permanent gespeichert werden. Dateien spielen daher in Datenbanken eine große Rolle. Die Ausführungen über invertierte Systeme haben gezeigt, dass diese Daten nicht in einer einfachen Satzstruktur aufgebaut sind. Sogar Informationen über die Struktur der Daten müssen in Dateien gespeichert werden. Grundlage für Datenstrukturen sind Blöcke (kleinste physikalische Bearbeitungseinheit für fast alle Datenbank-Komponenten.). Die Größe eines Datenbankblocks ist nicht generell festgelegt. Sie kann beim Anlegen der Datenbank den Gegebenheiten (Anforderungen, Anwendung und Betriebssystem) angepasst werden (gängige Werte: 2, 4 und 8Kbytes). Blöcke sind identisch mit Speicherseiten. Sicherungskonzepte: Dual Logging, Logging auf externe Medien usw. Logdateien sind ein wichtiges Instrument einer Datenbank zur Protokollierung aller Änderungen im laufenden Betrieb. Logdateien enthalten die Informationen darüber, welcher Benutzer mit welcher Transaktion welche Werte welcher Objekte wie verändert hat (geändert, gelöscht, neu hinzugefügt). Das heißt insbesondere, daß bei jeder Datenänderung der Wert vor und der Wert nach der Änderung festgehalten wird. Da der Wert vor der Änderung protokolliert wird, hat der user (oder das DBMS) die Möglichkeit, seine Aktionen bis zu einem gewissen Punkt wieder rückgängig zu machen. Dies ist vor allem im laufenden Betrieb ein notwendiges Instrumentarium. Da die Werte nach der Änderung nicht nur in den Datendateien, sondern auch in den Logdateien gespeichert werden, kann das DBMS auch bei Verlust einer Datendatei einen fast-aktuellen konsistenten Datenbankzustand wiederherstellen. Man kann also z. B. ein delete from Kunde-Statement unter gewissen Bedingungen durch den rollback-Befehl wieder rückgängig machen! Dabei liest dann das DBMS alle gelöschten Datensätze aus der Logdatei zurück in die Datendatei (über die Log.bzw. Datenpuffer!) Wie an diesem Beispiel schon zu sehen ist, wachsen die Logdateien in einer aktiven Datenbank sehr schnell: jedes Statement mit seinen Auswirkungen (z.B. 1000 gelöschte Datensätze) wird festgehalten. Nun sind aber z. B. die Werte vor einer Änderung ab einer gewissen Zeit nicht mehr interessant, weil z. B. die Tabelle inzwischen mehrfach geändert wurde, o. ä. Analoges gilt für die Datenwerte nach der Änderung. Dieser Punkt wird u. a. auch bei Oracle dazu benutzt, das unbegrenzte Wachstum der Logdateien durch zyklisches Überschreiben zu verhindern. Man arbeitet also hier mit zwei oder mehr Logdateien fester Größe: eine wird beschrieben; ist sie voll, wird die zweite beschrieben; ist diese voll, wird die erste überschrieben, usw. Dadurch geht natürlich, wenn diese Logdateien zu klein gewählt werden, schnell Information verloren. Hier ist also die Managementaufgabe, die Anzahl und Größe der Logdateien zu bestimmen und im laufenden Betrieb zu überwachen. Zusätzlich bietet Oracle auch noch die Möglichkeit, die Logdateien vor 103 dem Überschreiben zu archivieren (etwa auf ein Band). Dies ist für recoveryOperationen unter Umständen notwendig! Siehe hierzu auch Kap. III.5. Insgesamt gesehen, sind die Logdateien so etwas wie das Gedächtnis des DBMS, in denen alle Aktionen protokolliert sind nach ihrem Wertgehalt. Managementaufgabe: Erzeugung einer geeigneten Anzahl von Logdateien mit einer geeigneten Größe! Überwachung des Datenbank-Verhaltens bzgl. dieser Logdateien und gegebenenfalls Änderung (Anzahl, Größe) Bereitstellung von physischem Speicherplatz Aufgabe der Systemadministration ist es, durch Bereitstellung von genügend physischen Platten an mehreren Kontrollern dafür zu sorgen, dass im laufenden Betrieb die I/O-Zugriffe gut verteilt sein werden, so dass hier keine Engpässe auftreten. Bei großen Anwendungen sollte über Möglichkeiten nachgedacht werden, für die Trennung folgender Teile zu sorgen: die DBMS-System-Dateien, das Dictionary, die Log-Bereiche, temporären Plattenplatz für große Sortiervorgäge, (mehrere) Bereiche für die Daten, ggf. eigene Index-Bereiche usw. Es gibt zwei Arten von Datendateien: die eigentlichen Datendateien und Indexdateien. Datendateien nehmen die Daten der Datenbankobjekte (Tabellen, Klassen) physisch auf. Der DBA muss als darauf achten, dass immer genügend Speicherplatz für die Datenbankobjekte zur Verfügung steht. Parallel dazu ist es vor allem aus Gründen der Performanceverbesserung sinnvoll, Indizes zu benutzen, die den Zugriff auf die Daten schneller machen. Sinnvollerweise ist hier darauf zu achten, dass Daten-, Index- und Logdateien auf physikalisch verschiedenen Platten liegen, damit parallel gesucht und geschrieben werden kann. Liegen die drei Arten von Dateien auf einer Platte, muss z. B. beim Lesevorgang der Schreib/Lesekopf der Platte beim Wechsel zwischen Index- und Datendatei jedes Mal neu positioniert werden. Das kostet Zeit, die nicht notwendig ist! Managementaufgabe: Bestimmung von Größe und Anzahl von Daten- und Indexdateien bei der Planung der Datenbank. Verteilung auf verschiedene Platten im laufenden Betrieb: - eventuell neuen Speicherplatz reservieren - optimale Verwendung der Indizes kontrollieren (Tuning) Denormalisierung Selbstverständlich sollte dieser Schritt sehr sorgfältig in seinen Konsequenzen bedacht werden, da damit die Ergebnisse der bisherigen Entwurfsschritte teilweise wieder rückgängig gemacht werden. Andererseits gibt es viele große Anwendungen, die ohne gezielte Denormalisierung nicht die gewünschte Performance erreichen. Denormalisierung kann bedeuten, dass Verdichtungen der Daten in regelmäßigen Abständen berechnet und physisch gespeichert werden, um I/O-Operationen und 104 Rechenzeit zu sparen. Anstatt jedes Mal auf die Originaldaten zuzugreifen, erfolgt nur ein kurzer Zugriff auf die redundant gespeicherten Daten. Denormalisierung kann auch bedeuten, dass für einige Daten die Normalisierung schon frühzeitig beendet wird, um Join-Operationen zu sparen. Denormalisierung kann auch einfach eine Verdopplung von Tabellen oder Spalten darstellen, um damit mehr Zugriffsmöglichkeiten für den lesenden Zugriff bereitzustellen. Besondere Probleme ergeben sich daraus für ändernde Zugriffe. Weitere Formen der Denormalisierung werden bei der Verteilung und Replikation angesprochen. In jedem Falle werden flankierende Maßnahmen benötigt, um nicht durch die auftretende Redundanz Probleme zu bekommen. Eine wichtige Tuning-Komponente ist das Datenbankdesign. Generelle Faustregel: je kleiner das Datenbankschema (d.h. .je weniger Relationen), desto performanter die Datenbank. Natürlich muss man wegen gewisser Eigenheiten des Relationalen Modells viele Relationen in Kauf nehmen, die ursprünglich zu einem Objekt gehörten! D. h. bei jeder Normalisierung ist abzuwiegen und zu testen, ob die Performance darunter leidet und wie stark! Je mehr joins notwendig sind um eine Information zu gewinnen, desto langsamer ist die Verarbeitung! Tuning von Anfragen kann auch über das Anlegen von Indexen geschehen: diejenigen Attribute, die sehr oft in where-Bedingungen vorkommen, sollten indexiert werden! Entweder in einem oder in verschiedenen Indexen! Partitionierung von Tabellen Aufteilung von Tabellen dient dazu, bei den Anfragen im Mittel mit weniger physischen I/OVorgängen auszukommen. Zudem können Partitionen, auf die häufig zugegriffen werden muss, auf möglichst schnellen Platten vorgehalten werden. Einige DBMSe unterstützen transparent eine horizontale Partitionierung anhand eines Indexes. Der Vorteil liegt darin, dass Table-Scans dann in der Regel nur über eine Partition und somit über ein viel kleineres Datenvolumen als die ganze Tabelle - durchgeführt werden müssen. Die Struktur der Tabelle ändert sich bei dieser Art der Aufteilung nicht. Horizontale Partitionierung = Speicherung der zusammengehörigen Tupel in eigene Bereiche Im Gegensatz dazu steht die vertikale Partitionierung. Sie erfordert eine Strukturänderung, die Schlüsselspalten müssen in den Partitionen wiederholt werden. Schneller werden aufgrund des geringern IOs diejenigen Zugriffe, die nur eine Partition betreffen. Partitionsübergreifende Zugriffe setzen jedoch einen Join voraus und werden dadurch erheblich teurer. Diese Art der Zerlegung ist deshalb sehr sorgfältig zu planen. Clustern Die Tabellenzeilen werden physisch anhand eines Sortierkriteriums - in der Regel eines Indexes - so abgelegt, dass "nahe benachbarte" Zeilen auch physisch nahe benachbart gespeichert werden. Damit werden insbesondere solche Zugriffe beschleunigt, bei denen anhand des benutzten Sortierkriteriums zugegriffen wird. 105 Indexierung Indexe bilden die einfachste Art der Veränderung, da hierbei die bestehende Struktur in keiner Weise verändert wird. Jedoch müssen auch diese Maßnahmen anhand des Zugriffsverhaltens der gesamten Anwendung überdacht werden: bei kleinen Datenvolumen der Tabellen (wenige Pages) kostet ein Zugriff über einen Index mehr als ein Table-Scan (sequentielles Lesen einer Tabelle), bei jeder Änderung der Tabelle muss das DBMS alle Indexe auf die Tabelle mitpflegen. Indexe sollten deshalb bei Tabellen, in die häufig geschrieben wird, nur auf diejenigen Spalten bzw. Spaltenkombinationen erstellt werden, die einen "Gewinn" bringen: Schlüsselspalten, sofern das DBMS dies nicht automatisch selbst vornimmt, Spalten, die in Join-, Group-, Having- und Sort-Operationen benötigt werden, je nach DBMS: wenn bereits der Index die gesamte benötigte Information enthält, so dass nicht mehr auf die Tabellenzeile selbst zugegriffen werden muss. Knotenübergreifend Verteilung Verteilung von Daten ist ohne und mit Replikation (vgl. Abschnitt Replikation) zu betrachten. Dieser Teil betrachtet die Verteilung ohne Replikation. Geht man davon aus, dass die Übertragung von Daten zwischen beteiligten Datenbankknoten der begrenzende Faktor ist, so ist über das gesamte geplante System die Anzahl der Datentransfers zu minimieren. Diese Datentransfers sind von folgenden Faktoren abhängig: der Verteilung der Daten auf die Datenbank-Knoten, den verwendeten Anwendungen, der Häufigkeit, mit der eine bestimmte Anwendung auf einem bestimmten DatenbankKnoten gestartet wird, Weitere Aspekte, die je nach Gesamtinstallation in Betracht gezogen werden müssen, sind unter anderem die Ausfallsicherheit der einzelnen Datenbank-Knoten, die Anzahl und Qualität der Verbindungen zwischen den Datenbank-Knoten, die Auslastung der einzelnen Datenbank-Knoten, ggf. limitierende Faktoren bei der Auslegung der einzelnen Knoten. Vordergründig kann als Entwicklungsziel angesehen werden, die Fragementation und Allokation so zu gestalten, dass bei der geplanten Applikation ein möglichst geringer Datenstrom das Netz belastet, da in der Regel das Netz der limitierende Faktor sein wird. Faktoren: Art und Häufigkeit der Transaktionen an den verschiedenen Datenbankknoten, die aufgrund der Transaktionen an den einzelnen Datenbankknoten benötigten Daten – insbesondere auch Tabellenteile limitierende Faktoren eines bestimmten Knotens: CPU-Leistung, Auslastung und Größe des Hauptspeichers und Plattenplatz, die Geschwindigkeit der Netzverbindungen, die Zuverlässigkeit der Netzverbindungen, 106 Konsequenzen bei Ausfall eines bestimmten Knotens Unterstützung der Einhaltung von Integritätsregeln bei verteilten Daten Unterstützung verteilter Anfragen durch das VDBMS, insbesondere die Frage, ob das verwendete VDBMS es erlaubt, dass Transaktionen automatisch Subtransaktionen an entfernten Knoten starten können. [Achilles, SQL, 340] - Replikation Hier wird gezielt Redundanz in das Gesamtsystem eingeführt, indem auf verschiedenen Knoten dieselben Daten vorgehalten werden. Dies erfolgt in der Regel in Form einer oder mehrerer Tabellen, die parallel auf verschiedenen Datenbank-Knoten gehalten werden. Replikation ist völlig unproblematisch, sofern es sich dabei um Daten handelt, auf die nur lesend zugegriffen wird. Sobald jedoch die replizierten Daten auch verändert werden sollen, treten eine Reihe von Problemen auf (vgl. Abschnitt Replikation). Aus diesem Grunde gilt die "Regel": Soviel replizierte Daten, wie nötig, so wenig replizierte Daten, wie möglich. Hintergrund ist, dass bei einer Änderung replizierter Daten alle Datenbank-Knoten, die Replikate dieser Daten enthalten, die Änderung ebenfalls nachvollziehen müssen. Dies muss ferner so geschehen, dass der Transaktionsbegriff auch im verteilten System gilt. Handelt es sich also um eine Replikation von Daten, die auch geändert werden, so sind Vorund Nachteile gegeneinander abzuwägen. Die Vorteile liegen - je nach Ausführung - in einer größeren Verfügbarkeit der Daten und damit des Gesamtsystems, bei lesenden Transaktionen in einer höheren Performance, da vielfach auf einen Datentransfer via Netz verzichtet werden kann, die Nachteile sind in einem erhöhten Systemaufwand, erhöhter Netzkommunikation und ggf. Verlangsamung bei ändernden Transaktionen zu sehen. 107 6. Datenbanken Entwurf Der Entwurf einer Datenbank gliedert sich in 4 Phasen: 1. 2. 3. 4. Analyse konzeptueller Entwurf logischer Entwurf physischer Entwurf Ziel dieser Vorgehensweise ist eine möglichst frühe Berücksichtigung von Informations- und Datenverarbeitungsanforderungen, möglichst späte Festlegung auf ein bestimmtes DBMS (damit man das optimale DBMS findet) und die Hardware und das Betriebssystem sollen erst ganz zum Schluss mit in die Überlegungen einbezogen werden. Fragestellung: von der "Idee" zur implementierten Datenbank (einschließlich "zentraler Programme/DB-Prozeduren"): wie? es muss sichergestellt werden, dass Datenbasis über langen Zeitraum gestellten Anforderungen genügt Randbedinungen ähnlich dem Entwurf von Programm-Systemen Rückgriff auf Methoden und Erkenntnisse des Software Engineering 108 1. Analyse Abgrenzung des Anwendungsbereichs: Systemanalyse zur Bestimmung der Information, die für Geschäfts- Produktions-, Dienstleistungsprozesse ... nötig ist. Festzuhalten sind unter anderem: Herkunft, Ziel, Volumen, Zugriffe auf Daten, Operationen auf den Daten, >Ereignisse, die Operationen auslösen ... In der Analysephase wird ermittelt, was die Datenbank leisten muss und in welcher Systemumgebung sie eingesetzt wird. Es müssen verschiedene Dinge berücksichtigt werden, wie z.B. der Anwendungsbereich der Datenbank und wer später mit ihr arbeiten wird. Das Datenvolumen, die Datenstruktur und die Art der Daten (Zahlen, Text, Bilder etc.) sind, ebenso wie die Häufigkeit der Zugriffe und Veränderung der Daten, wichtige Informationen, die in der Analysephase ermittelt werden müssen. Abgrenzung des Anwendungsbereichs, Konkretisierung (vgl. Systemanalyse) Daten: Herkunft, Ziel, Volumen ermitteln Prozesse: rechnergestützt, andere Datenbank dient der Informationsablage und Informationsbedarf detailliert beschrieben werden –gewinnung, daher muss der Unterschiedliche Aspekte müssen in getrennten Verzeichnissen festgehalten werden: Datenverzeichnisse: beschreiben die zu speichernde Fakten Operationsverzeichnisse: beschreiben Verwendung der Daten Ereignisverzeichnisse: beschreiben, welches Ereignis eine Operation auslöst. Daraus ergeben sich die Abläufe. Endanwender-orientiert, deshalb wird hier nur schwach formalisiertes Vorgehen vorgestellt, das z.B. auf Formularen, Arbeitsabläufen und -beschreibungen, Mitarbeiterbefragungen, Dokumenten usw. basiert Schritte: 1. Erfassen und Beschreiben der benötigten Daten 2. Beseitigen von o Synonymen (sinnverwandtes Wort – Worte mit gleicher Bedeutung) und Homonymen (doppeldeutig - gleiche Worte mit unterschiedlicher Bedeutung) o Redundanzen 3. Erfassung nur implizit vorhandener Information 4. Klassifizierung: Aufteilung und Zuordnung zu Daten/ Operationen/ Ereignisse, die Operationen auslösen Zusammenfassung Analyse: Die Analyse ist der erste Schritt des Entwurfs einer neuen Datenbank. In der Analyse werden die Anforderungen ermittelt, die die DB erfüllen muss und die Voraussetzungen, 109 unter denen sie entwickelt wird. Wichtig ist, dass die Art der zu erfassenden Daten, das Datenvolumen, die Zugriffs- und Manipulationshäufigkeit der Daten genau ermittelt werden. Es ist notwendig, sich ein exaktes Bild davon zu machen, in was für einer Umgebung die Datenbank eingesetzt wird (Hardware, Geschäftsprozesse) und wird damit später arbeitet. Analyse-Phase: Abgrenzung des Anwendungsbereichs, Konkretisierung (vgl. Systemanalyse) Daten: Herkunft, Ziel, Volumen ermitteln Prozesse: rechnergestützt, andere Analyse-Phase (detailierter): Datenbank dient der Informationsablage und -gewinnung Informationsbedarf muss detailiert beschrieben werden Unterschiedliche Aspekte müssen in getrennten Verzeichnissen festgehalten werden: Datenverzeichnisse: beschreiben die zu speichernde Fakten Operationsverzeichnisse: beschreiben Verwendung der Daten Ereignisverzeichnisse: beschreiben, welches Ereignis eine Operation auslöst. Daraus ergeben sich die Abläufe. Endanwender-orientiert, => hier wird nur schwach formalisiertes Vorgehen vorgestellt basiert z.B. auf Formularen, Arbeitsabläufen und -beschreibungen, Mitarbeiterbefragungen, Dokumenten usw. Schritte: 1. 2. 3. 4. Erfassen und Beschreiben der benötigten Daten Beseitigen von a. Synonymen und Homonyen b. Redundanzen Erfassung nur implizit vorhandener Information Klassifizierung: Aufteilung und Zuordnung zu Daten/ Operationen/ Ereignisse Datenverzeichnis (FH) Nr. D001 Name Student Beschreibung Identifikation MatrNr Klassifikation Person Daten Name, Anschrift, FB, Datum Immatrikulation, -Exmatrikulation Zusatz-Info Synonyme immatrikulierter Student, aktiver Student ehemaliger Student Kardinalität 150000 Oberbegriff Mitglied 110 D002 D003 D004 Identifikation PersNr Klassifikation Person Daten Name, Anschrift, FB, Raum, Telefon, Lehrgebiet Professor Synonyme Dozent Karinalität 500 Oberbegriff Mitglied Synonyme Fachprüfung, Leistungsnachweis, Projektarbeit, Diplomarbeit, Kolloquium Kardinalität 5000 Oberbegriff Zensur Identifikation PrüfNr Klassifikation Studienleistung Daten Fach, Professor, Datum, Vorleistungen Prüfung Identifikation LNr Klassifikation Studienleistung Daten Student, Prüfung, Wiederholung, Note Studentische Prüfungsleistung Synonyme Kardinalität 50000000 Oberbegriff - Operationsverzeichnis (FH) Nr. Name Beschreibung Zusatz-Info O001 Student immatrikulieren Eingabe Name, Anschrift, FB, Datum Ausgabe eindeutige MatrNr Häufigkeit selten Bezugsdaten D001 DB Einfügen O002 Student exmatrikulieren Eingabe Name, Anschrift, Datum Exmatrikulation Ausgabe - Häufigkeit selten Bezugsdaten D001 DB Suchen, Ändern O003 Notenspiegel erstellen Eingabe Name, Anschrift Ausgabe Fächer, Noten Häufigkeit mittel Bezugsdaten D001, D002, D003, D004 DB Suchen Noten eingeben Häufigkeit häufig Eingabe MatrNr, PrüfNr, Bezugsdaten D001, D003, Wiederholung, Note D004 Ausgabe [endgültig nicht[ bestanden DB Suchen, Einfügen O004 O005 Prüngsliste erstellen Eingabe Fach, Professor, Datum Ausgabe Student, Note Häufigkeit häufig Bezugsdaten D002, D003, D004 DB Suchen Ereignisverzeichnis (FH) Nr. Name Bedingung Syntax elementar Semantik konditional (falls) löst aus E001 Ankunft Studentenanwärter O001 E002 Eingang Notenliste Syntax elementar Semantik konditional O003, O002 E003 Anforderung Ergebnisspiegel Syntax elementar Semantik temporal (wenn) O005 111 2. Konzeptuelle Phase vergleichbar mit Spezifikationsphase bei Software-Entwicklung um Sachverhalte und Gesetzmäßigkeiten in formale Gestalt überführen Beschreibungsmittel eines semantischen Modells verwenden Ziel: vorgegebene Sachverhalte vollständig und korrekt innerhalb der festgelegten Strukturen des Modells zu beschreiben, dabei wird angestrebt, dass das Ergebnis unabhängig von einem speziellen Datenmodell eines DBMS ist. wünschenswert: Transformation vom semantischen zum logischen Modell automatisieren. Wenn relationales Modell auch für semantische Zwecke geeignet ist, kann es als Ausgangsund Zielpunkt sukzessiver Transformationen genommen werden, allerdings muss die Abhängigkeit zwischen Attributen betrachtet werden. Gütekriterium bei Transformation: Verringerung der Speicherredundanzen und Anomalien Der Entwurfsansatz kann dann zur Optimierung bestehender Relationenschemata als auch bei Neuentwicklung benutzt werden. Redundanzen und Anomalien: Werden zur Verdeutlichung die kompletten Informationen über die Professoren in den Vorlesungen aufgeführt: Doznr 001 001 001 002 002 003 dann: - - Name Meier Meier Meier Schmidt Schmidt Schulze Vorname Telnr Veranstnr Veransttyp Horst 123 07 V Horst 123 08 Ü Horst 123 09 V Sabine 456 01 V Sabine 456 09 V Karin 789 02 P Veransttitel Datenbanken Datenbanken Mathematik Rechnernetze Mathematik Programmieren Ändern sich die Daten eines Professors => an vielen Stellen Änderungen notwendig (Änderungsanomalie) Einfügen von Daten eines neuen Professors => neue Vorlesung muss angegeben werden, ohne Vorlesung nicht möglich! (Einfügeanomalie) Löschen einer Vorlesung, die als einzige Daten eines Professors enthält => Informationen über diesen verschwinden ebenfalls (Löschanomalie) 112 Funktionale Abhängigkeiten: Definition: Seien A und B Mengen von Attributen derselben Relation. B ist dann von A funktional abhängig (A -> B), wenn Tupel t1 und t2 in allen Attributen von A übereinstimmen, dann müssen sie auch in allen Attributen von B übereinstimmen. Vereinfacht: Wenn ich die Attributwerte von A kenne, dann kann ich durch entsprechende Inspektion der Datenbank die Attributwerte von B ermitteln. Beispiel: Student (matrikel_nr, name, vorname, studiengang, fachbereich, studienbegin) Zwei Studierende, die den gleichen Studiengang studieren, gehören damit auch automatisch demselben Fachbereich an. Der Fachbereich ergibt sich aus dem Studiengang. Dies ist eine funktionale Abhängigkeit. studiengang -> fachbereich (Krägeloh) Voll funktional abhängig: Ist eine Attributmenge funktional abhängig von einer Attributmenge, nicht aber von einer Teilmenge dieser Attributmenge, so nennt man diese Abhängigkeit voll funktional abhängig Schlüssel: Ein Entitäts – Schlüssel (Schlüsselkandidat, „candidate-key“) ist dann ein Attribut, das Entitäten innerhalb einer Entitätsmenge eindeutig identifiziert. Ein Entitätstyp kann mehrere Schlüsselkandidaten haben. Es ist sinnvoll, aus den Schlüsselkandidaten einen Primärschlüssel („primary key“) auszuwählen. Soweit es möglich ist, sollte man zusammengesetzte Schlüssel vermeiden. .(Sauer, Datenbanken, Uni Regensburg) Ein Schlüssel ist eine Attributmenge, von der die Relation voll funktional abhängt => diese Attributmenge ist minimal identifizierend für die Relation. Eine Relation kann mehrere unterschiedliche Schlüssel haben . (Achilles) transitiv Abhängig: Schlüssel K bestimmt Attributmenge X funktional. Attributmenge Y ist aber funktional abhängig von X. transitive Abhängigkeit: K -> X -> Y K -> Y Für den Schlüssel S lässt sich die funktionale Abhängigkeit A -> A nach dem Transivitätsgesetz aus S -> T und T -> A ableiten. (Krägeloh) 113 Eine funktionale Abhängigkeit heißt transitiv abhängig, wenn sie durch 2 nicht-triviale funktionale Abhängigkeiten ersetzt werden kann. (Achilles) Join Dependency Eine Relation erfüllt JD bzgl. der disjunkten, aufspannenden Attributmengen A, B, C, ..., wenn die Relation durch Join aus den Projektionen R|A, R|B, R|C, ... entsteht. Normalformen: 1. Normalform Eine Relation ist in der ersten Normalform, wenn sie ausschließlich atomare, das heißt nicht weiter zerlegbare, Werte besitzt. (Zahlen, Zeichenketten, Datumswerte ...) 2. Normalform Eine Relation befindet sich in der zweiten Normalform, wenn sie keine funktionale Abhängigkeiten von Teilen des Schlüssels enthält. Mit anderen Worten, jede Spalte dieser Tabelle, die den Primärschlüssel nicht bildet, darf nur vom ganzen Primärschlüssel (und nicht nur von einem Teil dieses Schlüssels) funktional abhängig sein. Eine Relation ist in der zweiten Normalform, wenn jedes Nicht-Schlüsselattribut voll funktional von jedem Schlüssel abhängt. (Achilles) 3. Normalform Die dritte Normalform besagt, dass zwischen Spalten einer Tabelle, die nicht den Primärschlüssel bilden, keine Abhängigkeiten existieren dürfen. kein Nicht-Schlüsselattribut darf von einem anderen Nicht-Schlüsselattribut abhängig sein. Die Bedingung der dritten Normalform wird auch häufig so ausgedrückt: „Es gibt keine transitiven funktionalen Abhängigkeiten“ (Krägeloh) Eine Relation ist in der dritten Normalform, wenn es kein Nicht-Schlüsselattribut gibt, das transitiv von einem Schlüssel abhängt (Achilles) 4. Boyce/Codd-Normalform Eine Relation ist dann in Boyce/Codd-Normalform, falls jedes (funktional) determinierende Attribut zugleich Schlüsselkandidat ist. Ein (funktional) determinierendes Attribut (z.B. Ai) bzw. eine determinierende Attributkombination liegt dann vor, wenn jeder Attributwert des determinierenden Attributs (bzw. der determinierenden Attributkombination) genau einen Attributwert eines anderen Attributs (z.B. Aj) bzw. einer anderen Attributkombination festlegt. Man spricht in diesem Zusammenhang auch von Determinanten. Eine Determinante ist demnach ein Attribut oder eine Gruppe von Attributen (Schlüsselkandidat), von der beliebig andere Attribute funktional abhängig sind.(Sauer, Datenbanken, Uni Regensburg) Alle Attribute hängen voll funktional von jedem Schlüssel ab. (Achilles) 5. vierte Normalform Ein einführendes Beispiel: Gegeben ist die folgende, nicht normalisierte Relation: 114 In dieser Tabelle werden folgende Fakten ausgedrückt: - - - Eine bestimmte Vorlesung kann von beliebig vielen Dozenten gehalten werden und kann beliebig viele Merkmale zeigen. Zwischen Dozenten und Merkmalen eines Kurses (Vorlesung) bestehen keinerlei Abhängigkeiten Dozenten und Merkmale können mit jedem beliebigen Kurs in Verbindung stehen Es handelt sich um eine Dreifachbeziehung, die normalisiert folgende Form aufweist: Die vorliegende, normalisierte Relation enthält redundante Daten, die zu Anomalien führen können!. Soll z.B. ein neuer Dozent Datenbanken (DB) mit den bekannten Merkmalen lehren, dann sind zwei Tabellenzeilen in die Relation aufzunehmen. Die vorliegende, normalisierte Relation ist aber sogar in BCNF, denn alle Attributwerte sind Primärschlüssel. Es gibt außer der Kombination der Attribute VORLESUNG, DOZENTNAME, MERKMAL kein weiteres funktional determinierendes Attribut. Spaltet man die vorliegende Tabelle in zwei Relationen auf (Projektionen der ursprünglichen Relation), so ergibt sich die Lösung des Problems: 115 Für jede von einer bestimmten Person gehaltene Vorlesung gibt es eine identische Menge von Merkmalswerten. Man sagt, dass Attribut MERKMAL ist mehrwertig abhängig (multi value dependent) vom Attribut VORLESUNG. bzw. DOZENT. Das führt zu der folgenden Definition einer mehrwertigen Abhängigkeit: In dem Relationenschema R ? {Ai.Aj,Ak}ist das Attribut Ak vom Attribut Ai mehrwertig abhängig, falls zu einem Ai -Wert, für jede Kombination dieses Ai -Werts mit einem Aj -Wert, eine identische Menge von Ak -Werten erscheint. Mehrwertige Abhängigkeiten erscheinen in einer Relation immer paarweise. Werden diese mehrwertigen Abhängigkeiten beseitigt, dann spricht man von einer Relation in vierter Normalform. Eine Relation ist in der vierten Normalform, falls sie in der dritten Normalform, bzw. BCNF ist und keine mehrwertigen Abhängigkeiten zeigt. Verstöße gegen die vierte Normalform entstehen häufig bereits in der Entwurfsphase. So hätte man im vorliegenden Beispiel erkennen können, dass die Beziehung zwischen VORLESUNG und DOZENT bzw. VORLESUNG und MERKMAL voneinander unabhängig sind und keine Dreifachbeziehung darstellen. [Sauer, Datenbanken] Eine Relation in 3NF ist in 4NF, wenn es außer funktionalen Abhängigkeiten keine MVDs gibt. (Achilles) MVD's sind Verallgemeinerungen von funktionalen Anhängigkeiten: - - jede funktionale Abhängigkeit ist eine MVD, bei der die Menge V der abhängigen Werte, die zu einem bestimmten Wert gehören, immer einwertig ist ! es gibt MVD's, die keine funktionalen Abhängigkeiten sind 6. fünfte Normalform Es kann noch den Fall geben, dass eine verlustfreie Zerlegung nicht in 2, wohl aber in mehr Relationen möglich ist. Dieser Fall wird durch die 5. Normalform beschrieben. Eine Relation in 4NF ist in 5NF, wenn alle JDs nur auf Schlüsselkandidaten beruhen. Die Zerlegung kann mit Werkzeugen unterstützt werden. 116 Höhere Normalformen bewirken verringerte Redundanz weniger Anomalien besser hinsichtlich Datenänderungen Aber: in der Regel mehr Tabellen mehr Joins verringerte Effizienz beim Lesen deswegen wird die Normalisierung bei der Implementierung relationaler Datenbanken in vielen Fällen bereits nach der zweiten Normalform beendet. Die Relationentheorie ist gut, wenn sie auf den logischen Entwurf einer Datenbank abgestimmt ist, daher ist sie gut geeignet für relationale Datenbanken. Semantik wird generell nur sehr eingeschränkt unterstützt. Die Relationentheorie ist nur wenig geeignet, um konzeptuelle Modellierung weitgehend unabhängig vom Datenmodell eines DBMS durchzuführen. ER-Modell: Das ER-Modell ist ein semantisches Modell zur Darstellung des konzeptuellen Entwurfs einer Datenbank. Zur Implementierung der Datenbank muss das ER-Modell noch in die jeweilige Datenbank-Sprache übersetzt werden. Das ER-Modell ist ca. 25 Jahre alt und in einer Zeit entstanden, als über objekt-orientierte Techniken noch nicht diskutiert wurde. Die Vorteile des ER-Modells sind, dass es eine intuitive Semantik und eine einfache graphische Darstellung besitzt, sowie anschaulich und gut lesbar ist. Entity: (Gegenstand) abstraktes oder physisches Objekt der zu modellierenden Welt Entity Type: Zusammenfassung aller Entities gleicher Bedeutung Attribut: dienen der Beschreibung und zur eindeutigen Identifizierung von Entities Domäne: Wertebereich eines Attributs Relationship: beschreibt Zusammenhang zwischen mehreren Entities ggf. mit zusätzlicher Information n-stelliger Relationship-Type : kombiniert eine feste Menge von n Entity-Types (nicht notwendig unterschiedliche Entity-Types) 117 Graphische Darstellung: Beispiel zeigt: Entity-Types mit Attributen Relationship-Types insbesondere 3-stelligen Relationship-Typ Kardinalitäten macht für einen Relationship-Typ eine Aussage über Mindest- und Höchstzahl des Auftretens einer Ausprägung eines Entity-Types Darstellung: <min,max> (max=*: keine Beschränkung) Aggregation (blau) Relationship: nur zwischen Entities möglich Aggreation: Zusammenfassung eines Relationship-Types mit seinen Entity-Types zu einem neuen Entity-Type Generalisierung: Zusammenfassung ähnlicher Entity-Types zu einem neuen generischen Entity-Type. für das eingangs betrachtete Beispiel: Professor Student (Mitarbeiter) durch Generalisierung ggf. FH-Angehöriger 118 Weak Entity-Type Ein Weak Entity-Type (schwaches Entity Type) kann nicht für sich alleine existieren, es bedarf (mindestens) eines zugehörigen Relationship-Types Kardinalität: <1,1> Beispiel: Student, Prüfungsleistung Wird Information über Student entfernt, so auch seine Prüfungsleistungen Darstellung: Die Stärke des Entity-Relationship-Modells liegt in seiner Einfachheit. Es gibt nur Entity- und Relationship-Types. Dies ist aber auch gleichzeitig die Schwäche des ER-Modells, die sich in einer mangelnden formalen Fundierung niederschlägt. Besonders die Kardinalitätsangaben sind anfällig für Fehler. Objektorientierung 119 Relationentheorie: Die Relationentheorie weist ausschließlich strukturelle Merkmale auf. Sie zeigt nicht das Verhalten, Operatoren oder Ereignisfolgen, sondern die Daten und Datenstrukturen. Allerdings sind die Datenstrukturen und die sie verarbeitenden Algorithmen eng miteinander verzahnt. Einerseits sollten die Datenhaltung und die Anwendungsprogramme streng voneinander getrennt sein, da die Anwendungsprogramme eine kürzere Lebensdauer, als die Datenbanken haben. Andererseits erfordert die Optimierung der Leistung ein Vorhersagen über Anwendungen, die Abfolge von Programmabläufen usw. Daher ist ein Einsatz objektorientierter Techniken naheliegend. Die objektorientierte Modellierung besteht aus 3 Phasen, die in der Regel nacheinander ausgeführt werden. 1. Strukturelle Modellierung Hier erfolgt die Beschreibung aller relevanten Eigenschaften. 2. Dynamikmodellierung Beschreibung der Objektzustände und der einwirkenden Ereignisse 3. Funktionsmodellierung Beschreibung der Aktivitäten als Ausführung von Operatoren Strukturelle Modellierung: Klasse anstelle von Entity-Type Beziehungsdarstellung mittels Kardinalitäten 120 mehrstellige attributierte Assoziation Aggregation (ist Bestandteil von) und Generalisierung (Vererbungsbeziehung) 121 Dynamikmodellierung Zeitveränderliche Aspekte, Kontrollfluss zwischen den Objekten Zustandsübergangsdiagramme: zulässige Zustände und mögliche Übergänge Funktionsmodellierung Funktionsmodell basiert auf klassischem Datenflussdiagramm Prozesse Datenspeicher Akteuren Vergleichbar der Spezifikationsphase in der Software-Entwicklung. Die für die DBAnwendung wichtigen Sachverhalte sollen dabei möglichst system-unabhängig in ein formales Modell überführt werden. Zur Modellierung wird in dieser Phase häufig das E-R-Modell eingesetzt. Nachteil sowohl der Relationentheorie als auch des E-R-Modells sind die ausschließliche Konzentration auf strukturelle Merkmale. Verhaltensfragen wie z.B. Ereignisabfolgen können damit nicht ausgedrückt werden. Der objektorientierte Entwurf (vgl. Software-Technik) 122 verbindet im Begriff der Klasse die strukturellen Merkmale mit den darauf zulässigen Operatoren. 3. Logischer Entwurf Unter Verwendung von Gütekriterien wird der konzeptuelle Entwurf in das logische Modell eines konkreten DBMS überführt. Werden als Zielsysteme relationale Systeme betrachtet, so können als Gütekriterien die Normalformen angewendet werden. 4. physikalischer Entwurf prinzipiell gilt: die Kosten durch den physischen Zugriff sind zu minimieren dies kann bei RDBMS durch folgenden Ansatz geschehen: Festlegung von Speicherbereichen und Zuordnung zu Plattenpartitionen Vereinbarung von Tabellenbereichen zur Aufnahme einer oder ggf. mehrerer gleichartig zu behandelnder Relationen Anzugeben sind o Speicherbereich o Anfangsgröße o erwartete Wachstumsrate o Seitengröße Zuordnung von Relationen zu Tabellenbereichen Clusterung Erzeugen von Indexen manche werden automatisch durch das verwendete RDBMS angelegt, ggf. ist noch der Speicherbereich anzugeben o Clusterindex o Primärindex o Sekundärindexe o zur Unterstützung von Fremdschlüsseln weitere Indexe Installation des gewählten DBMS Anpassung der Installationsparameter an die Anforderungen dies betrifft unter anderem Directory-Größe Größe für temporäre Tabellenbereiche (Sortieren usw.) im Speicher zu reservierender Bereich für DBMS Cache für Datenseiten Cache für DB-Kommandos und -Zugriffspfade Bereitstellen der Sichten Benutzerverwaltung Rechtevergabe Implementation der Integritätsregeln Implementation der DB-Prozeduren 123 5. Verzahnung der Entwurfsphasen Entwurf und Integration Problem: die Zahl der Entity-Types kann bei Entwürfen schnell auf mehrere 100 kommen => Übersichtlichkeit nicht mehr gegeben Vorgehensweise: Der konzeptuelle Entwurf wird aufgeteilt Gleiches Vorgehen, wenn bereits existierende Datenbanken zusammengeführt werden müssen im ersten Fall: die zu modellierenden Ausschnitte im zweiten Fall: Ausschnitte sind unkoordiniert entstanden entstehen koordiniert Überlegung: jede Anwendergruppe hat eine ihrer Aufgabenstellung gemäße Sicht der Datenbasis Phase 1: identifiziere die verschiedenen Anwendergruppen entwickle konzeptuelles Modell Phase 2: integriere die so entstandenen Modelle Problem ist das Auffinden der Arbeitsgruppen, ansonsten: Entwicklung der Teilmodelle ist bereits behandelt Phase 2: Zusammenführung der Teilmodelle Welche Probleme können auftreten? Namenskonflikte: gleicher Sachverhalt wird mit unterschiedlichen Namen belegt (Synonyme) unterschiedliche Sachverhalte werden mit gleichem Namen belegt (Homonyme) Merkmalskonflikt: gleicher Sachverhalt wird in unterschiedlichen Teilmodellen unterschiedlich betrachtet und führt zu unterschiedlich vielen oder nur teilweise überlappenden Satz an Attributen Strukturkonflikt: gleicher Sachverhalt wird in den Teilmodellen unterschiedlich modelliert z.B. im E-R-Modell als Attribut-Domänenpaar oder als Relationship mit zweitem Entity-Type Bedingungskonflikt: funktionale oder mehrwertige Abhängigkeiten, Schlüsseleigenschaften, Kardinaltitäten... im E-R-Modell z.B. unterschiedliche Kardinalitäten bei Teilmodellen Abstraktionskonflikt: gleicher Sachverhalt in unterschiedlichen Teilmodellen unterschiedlich detailliert modelliert 124 Phase 2: Zusammenführungs-Strategie erster Ansatz scheidet in der Regel aus Komplexitätsgründen aus Ansätze 2 und 3 aus Sicht der Komplixität her möglich liefern aber je nach Zusammenfassung, Reihung unterschiedliche Ergebnisse Phase 2: Zusammenführungs-Strategie: Leitermodell n-1 gleichartige Konsolidierungsschritte jeder Schritt: Konfliktanalyse beide Sichten vergleichen Konfliktbereinigung für jeden ausgemachten Konflikt: eine Sicht "gibt z.B: bei Abstraktionskonflikt diejenige mit geringerem Detailierungsgrad Sichtenverbindung zu einem Schema zusammenführen: o identische Teile nur einmal erfassen o disjunkte Teile vollständig übernehmen o bei Abstraktionskonflikten: einpassen nach", Entwurf und Integration Phase 2: Zusammenführungs-Strategie Komplexitätsreduzierung ??? Entwurf und Integration Phase 2: Zusammenführungs-Strategie 125 Systematik der Anordnung ??? Entwurf und Integration Phase 2: Zusammenführungs-Strategie 126 Systematik der Reihenfolge ??? 127 7. Synchronisation und Replikation Replikation Bündel von Methoden, die in einem verteilten Datenbanksystem kontrollierte Redundanz einführen, um zeitkritische Zugriffe über das Netz zu verringern. Synchronisation besagt, dass die "parallele" Auführung mehrerer Transaktionen von verschiedenen Benutzern serialisiert werden kann: das Ergebnis der parallelen Ausführung darf sich nicht von einer beliebigen seriellen Ausführung der betrachteten Transaktionen unterscheiden. [Achilles, SQL] Gründe für die Schaffung eines verteilten Informationssystems sind: größere Ausfallsicherheit Auch wenn ein Knoten ausfällt, kann noch auf andere Knoten - und damit auf die dort gespeicherten Daten - zugegriffen werden erhöhte Datenverfügbarkeit Kann als "Korollar" der ersten Aussage angesehen werden; insbesondere eine Duplizierung von Daten gestattet die Erreichbarkeit auch bei Ausfall von Knoten. Jedoch: diese Aussage gilt nur bei rein lesendem Zugriff; Änderungen können Probleme bereiten: vgl. Transaktionen Verbesserung des Durchsatzes Durch Duplizierung von Daten auf den einzelnen Knoten kann eine Reduzierung der Netzlast erreicht werden - da Anwendungen parallel auf den Knoten laufen, kann damit eine Verbesserung des Durchsatzes erzielt werden Lastausgleich Insbesondere bei Anfragen kann bei geeigneter Zwischenschicht die Auslastung der einzelnen Knoten (und Netzverbindungen) berücksichtigt werden um eine gleichmäßige Auslastung zu erreichen Mobilität Dieses Argument ist anders gelagert als die vorherigen: externe Mitarbeiter bekommen zur Unterstützung Laptops, deren Daten nahtlos in das "Firmendatenmodell" eingefügt werden sollen 128 Probleme bei verteilten Informationssystemen: Aktualität der Daten auf den einzelnen Knoten Wie rechtzeitig werden Änderungen an die anderen Knoten weitergereicht? Kommunikationsaufwand, o Daten, die nicht auf dem Knoten liegen, auf dem eine Anfrage erfolgt, müssen über das Netz geholt werden. o Bei Duplikaten muss bei einer Datenänderung die Änderung "rechtzeitig" an alle Knoten weitergegeben werden. Konsistenz der Daten (bei Replikation) Bei Duplizieren der Daten tritt auf Grund der obigen Aussagen das Problem auf, dass Daten ggf. nicht mehr (oder auch nur zeitweise nicht) konsistent über die Datenbasis aller beteiligten Knoten sind. Auf Grund der Probleme bei verteilten Informationssystemen gilt: die Verteilung ist sorgfältig zu planen Duplizierung der Daten ist sorgfältig zu planen das Verfahren, duplizierte Daten zu aktualisieren, entscheidet über die Art, wie das System eingesetzt werden kann Wie bei Normalisierung gilt: Verteilung und Duplizierung nur soviel wie nötig Transaktion Auch bei verteilten Systemen müssen Transaktionen wie in einem lokalen DBMS unterstützt werden. D.h. die Eigenschaften : A Atomicity (Atomarität) eine Änderung der Daten wird entweder vollständig oder überhaupt nicht vorgenommen C Consistency (Konsistenz) geänderte Daten müssen Konsistenz-Bedinungen erfüllen I Isolation (isolierte Zurücksetzbarkeit) ein Zurücksetzen betrifft ausschließlich die Änderungen, die in der Transaktion vorgenommen wurden D Durability (Dauerhaftigkeit) die Daten einer erfolgreichen Transaktion werden dauerhaft gespeichert müssen gewährleistet sein 129 Anschauliche Darstellung: eine Transaktion ist eine zusammengefasste Folge von Operationen, die eine logische Einheit bilden sie werden entweder alle ausgeführt oder es wird keine Änderung sichtbar die Datenbasis wird aus einem konsistenten Zustand in einen neuen konsistenten Zustand überführt anschaulich: am Ende einer Transaktion wird wieder ein korrekter Zustand der abzubildenden Welt dargestellt wird eine Transaktion zurückgesetzt, so werden Änderungen anderer Transaktionen nicht davon betroffen Änderungen, die innerhalb einer Transaktion gemacht werden, werden am Ende permanent gespeichert lokale Transaktionen betreffen nur ein DBMS (einen Datenbank-Knoten) globale Transaktionen in einem Verteilten System betreffen mehrere Knoten Verfahren zur Transaktionsunterstützung an einem Knoten: typisch für bekannte relationale DBMSe: Sperrverfahren weitere Verfahren in diesem Abschnitt Verfahren zur globalen Transaktionsunterstützung? Eine Transaktion soll somit eine Folge von Operationen derart zusammenfassen, dass sie als logische Einheit betrachtet wird, die entweder komplett oder aber gar nicht ausgeführt wird. Dabei wird eine Datenbasis, die sich in einem konsistenten Zustand befindet, in einen (neuen) konsistenten Zustand überführt. Muss eine Transaktion zurückgenommen werden, so werden Änderungen anderer Transaktionen davon nicht betroffen. Eine von einer Transaktion durchgeführte Änderung wird permanent in der Datenbank gespeichert. Globale Transaktionsunterstützung: setzt auf der lokalen Transaktionsunterstützung auf durch Kommunikation der beteiligten Knoten muss gewährleistet werden, dass die auf den beteiligten Knoten laufenden Subtransaktionen gemeinsam ausgeführt oder verworfen werden üblicherweise verwendetes Protokoll: Zwei-Phasen-Commit-Protokoll Während lokale Transaktionen nur einen Knoten betreffen, greifen globale Transaktionen auf mehrere Knoten zu. Damit wird ein Abstimmungsprozess der beteiligten Knoten notwendig. Zwei-Phasen-Commit Technik des Transaktionsabschlusses in einem verteilten Datenbanksystem. Wurden in einer Transaktion Veränderungen an mehreren Knoten vorgenommen, so müssen alle diese Knoten die Änderungen vollziehen oder ablehnen. 130 Im Zwei-Phasen-Commit wird in der ersten Phase die Bereitschaft aller beteiligten Knoten zu einem Commit hergestellt, in der zweiten Phase vollzieht jeder Knoten das Commit. Commit: Beenden einer Transaktion. Dabei werden die Veränderungen, die innerhalb der Transaktion vorgenommen wurden, für alle Datenbankbenutzer sichtbar. Das Datenbanksystem bewahrt den ursprünglichen Zustand bis zum Ende der Transaktion auf. Knoten: Ein DBMS, das Teil eines verteilten Datenbanksystems ist. Es verwaltet (in der Regel) eine lokale Datenbank und ermöglicht Zugriffe auf externe Datenbanken, d.h. auf Datenbanken, die von einem anderen DBMS auf einem anderen Rechner verwaltet werden. [Achilles, SQL] Dieses Protokoll soll die Konsistenz gewährleisten: die auf den einzelnen Knoten laufenden Subtransaktionen werden alle gemeinsam durchgeführt oder verworfen. Das Protokoll kann vereinfacht so beschrieben werden: Der Knoten, der die globale Transaktion auslöst, - der Koordinator - schickt an alle beteiligten Knoten ein Prepare-to-commit. Die beteiligten Knoten informieren daraufhin den Koordinator, ob sie die Transaktion lokal durchführen können (Commit) oder verwerfen müssen (Abort), die Teiltransaktion wird jedoch noch nicht abgeschlossen, sondern wartet auf die Rückmeldung vom Koordinator. Erhält der Koordinator von allen Subtransaktionen die Meldung Commit, so sendet er diese Meldung an alle beteiligten Knoten zurück, die daraufhin das eigentliche Commit vollziehen. Erhält der Koordinator jedoch von einem Knoten die Meldung Abort, so fordert er alle beteiligten Knoten zum Abort auf. Abschluss der Transaktion: 1. der Koordinator schickt an alle an der Transaktion beteiligten Knoten die Meldung Prepare-to-commit 2. die Knoten informieren daraufhin den Koordinator, ob sie o die Transaktion lokal durchführen können (Commit) o die Transaktion verwerfen müssen (Abort) Die jeweilige Subtransaktion wird jedoch noch nicht vollzogen, vielmehr warten die Knoten auf die endgültige Mitteilung des Koordinators 3. der Koordinator sammelt alle Rückmeldungen auf und informiert die Knoten: o falls alle Rückmeldungen Commit lauten, mit der Meldung Commit o falls wenigstens eine Rückmeldung Abort lautet, mit Abort 4. die Knoten vollziehen ihre Aktion auf Grund der endgültigen Meldung des Koordinators Die folgende Abbildung zeigt die Aktionen von Koordinator und Knoten: 131 Wenn keine Ausfälle und Verklemmungen auftreten, arbeitet dieses Protokoll korrekt. Jedoch kann z.B. die Kommunikation zwischen Koordinator und einem Knoten gestört sein. Um auch solche Fälle abfangen zu können, muss in den WAIT-Phasen ein TimeoutMechanismus laufen. Kommt nach Ablauf des Timeouts keine Nachricht an, so muss auf diesen Fehler geeignet reagiert werden, um eine Blockierung aufzuheben. Stellt ein Knoten fest, dass sein Timeout abgelaufen ist, d.h. dass die Kommunikation zum Koordinator gestört ist, so kann er, indem er andere beteiligte Knoten abfragt, in folgenden Fällen sinnvoll reagieren wenigstens ein anderer Knoten hat die eigene Teiltransaktion ist ebenfalls zurückzusetzen (selbst Abort vollziehen) mit Abort gestimmt: 132 ein anderer Knoten hat bereits die globale Commit- oder die globale Abort-Meldung erhalten: Dann muss dementsprechend ein COMMIT oder ein ABORT durchgeführt werden. In allen anderen Fällen ist der Knoten solange blockiert, bis eine erneute Kommunikation mit dem Koordinator aufgebaut ist. Knotenausfall - Koordinator Auch nach Knotenausfall kann auf einen Teil der auftretenden Probleme in der RecoveryPhase reagiert werden. Für den Koordinator gilt: Findet er im Protokoll ein END-Record, so kann er davon ausgehen, dass alle beteiligten Teiltransaktionen abgeschlossen sind. Findet er einen Abort- oder Commit-Record, so werden alle beteiligten Knoten darüber informiert. andernfalls wird ein globales Abort an alle gesendet, da der Koordinator offensichtlich sich noch in seiner WAIT-Phase befunden hat. Für die Knoten gilt: Ein Commit- oder Abort-Record in der eigenen Protokoll-Datei führt zu einem Redo oder Undo, um sicherzustellen, dass die Änderung korrekt durchgeführt oder zurückgenommen wird, ein Ready-Record zwingt, das globale Abstimmungsergebnis nachzufragen, andernfalls wird die Transaktion abgebrochen, da offensichtlich das Commit-Protokoll noch nicht begonnen wurde. Das wesentliche Problem dieses Protokolls liegt in der Blockade der Knoten bei ausgefallenem Koordinator. Der Koordinator muss Informationen auch über beendete Transaktionen aufbewahren. 133 Synchronisation Wie auch bei lokalen Änderungen muss dafür Sorge getragen werden, dass die folgenden Probleme weitgehend vermieden werden. Der Transaktionsbegriff sollte ausreichen, jedoch versucht man durch Abschwächung den Parallelisierungsgrad zu erhöhen. Verlorene Änderungen (lost updates): zwei Transaktionen greifen "gleichzeitig" auf ein Datenobjekt zu, um es zu ändern; nur die Auswirkung der zweiten Transaktion bleibt sichtbar, die Änderung der ersten Transaktion geht verloren. Transaktionen heißen serialisierbar, wenn dieses Phänomen nicht auftreten kann. Schmutziges Lesen (dirty read): eine lesende Transaktion greift auf ein Datenobjekt zu, das von einer zweiten Transaktion verändert wurde; anschließend wird die zweite Transaktion zurückgesetzt, der ursprüngliche Wert des Datenobjekts wieder hergestellt; die lesende Transaktion enthält somit inkonsistente Werte, sie ist in keiner Weise gegen andere Transaktionen isoliert. Inkonsistentes Lesen (inconsistent reads): die lesende Transaktion ist gegen Änderungen anderer Transaktionen an den Daten, auf die gerade ihr Cursor zeigt, geschützt. Andererseits können bereits gelesene Daten, die der Cursor wieder freigegeben hat, von einer anderen Transaktion geändert werden. Wird das Lesen von der ersten Transaktion wiederholt, so werden die geänderten Daten gefunden. Diese Isolationsstufe heißt READ COMMITTED. Lesen von Phantomen (phantom reads): eine Transaktion liest Daten, während eine andere Transaktion neue Daten einfügt, die der Suchbedingung der ersten Transaktion genügen. Wird nun die zweite Transaktion mit COMMIT beendet und die erste Transaktion öffnet erneut den Cursor, so findet sie die neuen Zeilen vor. Kann nur dieses Phänomen auftreten, so heißt der Isolierungsgrad REPEATABLE READ. Kann keins dieser Probleme auftreten, so heißt der Isolationsgrad SERIALIZABLE. Zwei Klassen von Verfahren werden eingesetzt, um den sicheren Ablauf von Transaktionen zu gewährleisten: Sperrverfahren Dies wird bei nahezu allen bekannten RDBMS verwendet. Transaktionskonflikte werden augeschlossen, jedoch wird dies durch die Gefahr von Deadlocks erkauft. Optimistische Synchronisationsverfahren Hierbei handelt es sich um eine Reihe von Verfahren, die zunächst einmal Transaktionskonflikte zulassen um diese im Nachhinein zu korrigieren. Deadlocks werden dadurch vermieden. 134 Sperrverfahren Ein Datenbanksystem muss in der Lage sein, bei Transaktionen zu garantieren, dass die Reihenfolge der Lese- und Schreiboperationen korrekt bleibt, auch wenn mehrere Benutzer "gleichzeitig" Anforderungen starten, die konkurrierende Zugriffe beinhalten. Nur dadurch kann Transaktionskonsistenz hergestellt werden. Ein Datenbanksystem kann eine korrekte Serialisierbarkeit, die als Methode zur Transaktionsverwaltung eingesetzt werden kann, nicht direkt benutzen. Vielmehr wird die Serialisierung selbst durch das Setzen von Sperren ermittelt: das Datenbanksystem erlaubt es, Objekte, die verändert werden, für den Zugriff anderer Benutzer zu sperren. So kann die Änderung vorgenommen und nach erfolgter Änderung die Objekte wieder freigegeben werden.... Die Systeme setzen benötigte Sperren automatisch, erlauben aber auch, mit der Anweisung LOCK Sperren für Objekte anzufordern. [Achilles, SQL] Bei Sperrverfahren werden die von einer Transaktion betroffenen Datenobjekte mit einer entsprechenden Lese- bzw. Schreibsperre versehen. Am Ende der Transaktion werden die gesperrten Datenobjekte wieder freigegeben. Eine Transaktion, die ein bereits gesperrtes Datenobjekt ihrerseits sperren will, wird blockiert und muss warten, bis dieses Objekt von der anderen Transaktion freigegeben wird. Damit ist die Gefahr von Deadlocks gegeben. Deadlock: Zustand einer Datenbank, in dem sich mehrere Benutzer gegenseitig durch Sperren gemeinsam benötigter Objekte blockieren. Dieser Zustand kann erst dann gelöst werden, wenn mindestens einer dieser Benutzer auf die Bearbeitung seiner Probleme zum gegenwärtigen Zeitpunkt verzichtet. [Achilles, SQL] Entscheidend für Parallelisierungsgrad und die Performance des Systems sind die folgenden Parameter die "Größe der gesperrten Daten die Art der Sperren Die Größe der gesperrten Datenobjekte : das Objekt selbst, der Record, die das Objekt enthaltende Page, die Tabelle, ... 135 Die Art der Sperren: zum Lesen - mehrere Transaktionen können eine solche Sperre gleichzeitig anfordern, es kann jedoch keine Transaktion das Objekt verändern – Sperre von Objekten einer Datenbank, die es einem Benutzer ermöglicht, Daten zu lesen, ohne dass andere Benutzer während dieser Zeit Daten ändern können. Eine Sperre zum Lesen bewirkt somit, dass die Daten für den anfordernden Benutzer konsistent bleiben. In der Regel brauchen solche Sperren nur von Programmen aus angefordert werden. Der englische Begriff shared lock ist klarer: die Daten können gemeinsam gelesen, aber von keinem verändert werden. [Achilles, SQL] zum Schreiben - die sperrende Transaktion lässt keine anderen Sperren zu – Sperre von Objekten einer Datenbank, die es einem Benutzer ermöglicht, Daten zu verändern, ohne dass andere Benutzer während dieser Zeit möglicherweise inkonsistente Daten sehen können (exclusive lock). Eine Sperre zum Schreiben erlaubt also demjenigen Benutzer, der sie setzt, die gesperrten Daten zu verändern, während alle anderen Benutzer diese Daten nicht lesen und natürlich auch nicht verändern können. ... Die Eskalation der Sperren usw. variiert von System zu System. Die verschiedenen Parameter haben einen wichtigen Einfluss auf den möglichen Parallelisierungsgrad und die Performance des Systems. Zwei-Phasen-Sperrprotokoll Das System sperrt zunächst einmal selbsttätig die benötigten Objekte. Will der Benutzer viele Zeilen in einer Tabelle ändern, so empfiehlt es sich, dass er selbst dem System mitteilt, welche Tabelle zu sperren ist. Damit kann er das System von unnötigen Prüfungen rechtzeitig entlasten. Alle beteiligten Transaktionen müssen jedes Datenobjekt, auf das sie im Laufe der Transaktion zugreifen, mit einer entsprechenden Sperre belegen und dürfen nach Freigabe einer Sperre keine weiteren Sperren mehr anfordern. Ein solches Sperrprotokoll sammelt im Laufe der Transaktion in der ersten Phase immer mehr Sperren an, um sie nach erfolgten Änderungen in der zweiten Phase wieder freizugeben. Am einfachsten zu implementieren ist die vollständige Freigabe aller Sperren einer Transaktion am Transaktionsende. (EOT) Die Sperren werden in der Regel in einer Sperrtabelle vermerkt, die für eine Sperre zumindest folgende Information enthalten muss: die Transaktionsnummer zur Identifizierung der Transaktion, das gesperrte Objekt und (Spalte, Zeile, Tabelle, Speicherraum, Speicherseite) die Art der Sperre. (lesen / schreiben) Aufbau Sperrprotokoll: 136 Sperren werden in Sperrtabelle vermerkt, Einträge müssen zumindest enthalten o Transaktionsnummer o gesperrtes Objekt o Art der Sperre Zugriff auf Sperrtabelle muss exklusiv erfolgen bei verteilten Systemen könnte zentrale Sperre verwendet werden o Vorteil: Synchronisation der Transaktionen wie im lokalen System o Nachteile: Kommunikation zum zentralen Knoten sowie Autonomieverlust der übrigen Knoten dezentrale Sperrtabellen: jede Transaktion fordert bei dem jeweiligen lokalen Sperrmanager Sperren an Problem: globale Deadlocks Der Zugriff auf die Sperrtabelle muss für jeden Eintrag exklusiv erfolgen. Bei verteilten Systemen kann eine zentrale Sperrtabelle oder aber dezentrale Sperrtabellen verwendet werden. Eine zentrale Sperrtabelle bietet den Vorteil, dass die Synchronisation der Transaktionen wie in einem lokalen System erfolgt, jedoch den gravierenden Nachteil, dass für jede Sperranforderung der Aufbau einer Kommunikation zum zentralen Knoten erfolgen muss; zudem verlieren die anderen Knoten ihre Autonomie. Dezentrale Sperrtabellen werden auf jedem Knoten separat gepflegt; eine Transaktion fordert bei dem jeweiligen lokalen Sperrmanager des DBMS eine Sperre für das zu bearbeitende Objekt an. Das Problem liegt darin, dass nun globale Deadlocks auftreten können, die durch die lokal arbeitenden Sperrmanager nicht mehr erkannt werden können. Zeitstempelverfahren Anstelle Sperrtabelle: jede Transaktion besorgt sich zu Beginn einen Zeitstempel bei Zugriff auf ein Objekt wird dieser in ein zusätzliches Feld des Objektes eingetragen (Erweiterung der Datenstruktur) (Basic Timestamp Odering): eine Transaktion, die ein Objekt sperren will, das bereits einen jüngeren Zeitstempel trägt wird zugunsten der jüngeren Transaktion zurückgesetzt Vorteil: garantierte Deadlockfreiheit Nachteile: o Erweiterung der Datenstrukturen o Benachteiligung länger laufender Transaktionen Problem: Zeitstempel bei verteilten Systemen o zentraler Zeitstempelserver o zweitteiliger Zeitstempel: Zeitmarke + RechnerID Anstelle einer Sperrtabelle wird jede Transaktion zu Beginn mit einem Zeitstempel versehen. Dieser Zeitstempel wird bei Zugriff auf ein Objekt in eine dafür vorgesehenes zusätzliches Feld des Objektes eingetragen. Die Datenstruktur muss also für jedes Datenobjekt um ein oder mehrere Zeitstempelfelder erweitert werden. 137 Das Basic Timestamp Ordering Verfahren kann nun grob so beschrieben werden: Will eine Transaktion ein Datenobjekt sperren, welches einen jüngeren Zeitstempel als die Transaktion selbst trägt, so muss die Transaktion zurückgesetzt werden, damit die "jüngere" Transaktion ordnungsgemäß zu Ende gebracht werden kann. Zeitstempel können von einem globalen Zeitstempel-Server erzeugt werden mit all den damit verbundenen Nachteilen. Es kann jedoch auch ein zweiteiliger Zeitstempel, bestehend aus Zeitmarke und Rechner-ID, verwendet werden. Voraussetzung dafür ist, dass die Uhren der beteiligten Rechner synchronisiert werden. In diesem Falle kann der Zeitstempel lokal besorgt werden, der Kommunikationsaufwand des globalen Zeitstempel-Servers entfällt. Der Vorteil des Zeitstempelverfahrens ist die garantierte Deadlock-Freiheit. Zumindest zwei Probleme sind jedoch mit dem Zeitstempelverfahren verbunden: die Erweiterung der Datenstrukturen, die Benachteiligung länger laufender Transaktionen; diese werden durch die Ankunft neuerer Transaktionen zurückgesetzt, sobald sie auf Daten zugreifen müssen, die bereits von der jüngeren Transaktion berührt wurden. Optimistische Synchronisationsverfahren greifen nicht in den Ablauf einer Transaktion ein sie überprüfen statt dessen am Ende einer Transaktion, ob Konflikt aufgetreten ist => in dem Falle wird Transaktion zurückgesetzt Der Ansatz optimistischer Verfahren liegt darin, dass vorbeugende Sperren als unnötiger Aufwand angesehen werden. Dieser Standpunkt kann nur dann eingenommen werden, wenn Transaktionskonflikte auf Grund der Natur des Problems sehr selten auftreten. Derartige Synchronisationsverfahren greifen nicht in den Ablauf einer Transaktion ein. Bei Transaktionsende wird überprüft, ob ein Konflikt aufgetreten ist. Sollte ein Konflikt aufgetreten sein, so muss auch in diesem Falle eine Transaktion zurückgesetzt werden. Optimistische Synchronisationsverfahren bewirken, dass Transaktionen in drei Phasen ablaufen: 1. Lesephase: Die benötigten Datenobjekte werden gelesen und in einem Read-Set gespeichert; werden sie geändert, so werden diese Datenobjekte in einem Write-Set gepuffert, nicht aber zurückgeschrieben. In der Lesephase wird die eigentliche Transaktionsverarbeitung vorgenommen, d.h. es werden Objekte der Datenbank gelesen und modifiziert. Jede Transaktion führt dabei ihre Änderungen auf private Kopien in einem ihr zugeordneten Transaktionspuffer durch, der für keine andere Transaktion zugänglich ist. [Härder, Rahm; Datenbanksysteme] 138 2. Validierungsphase: Am Ende der Transaktion wird geprüft, ob die zu beendende Transaktion mit irgend einer anderen Transaktion in Konflikt steht. Die Validierungsphase muss exklusiv durchlaufen werden, d.h. es darf jeweils immer nur eine Transaktion validiert werden. Insbesondere für verteilte Anwendungen muss hier besonderer Aufwand getrieben werden, um die Exklusivität zu garantieren. Im Gegensatz zu Sperrverfahren, bei denen Blockierungen das primäre Mittel zur Behandlung von Synchronisationskonflikten sind, werden hier Konflikte stets durch Zurücksetzen einer oder mehrerer beteiligter Transaktionen aufgelöst. Es ist so mit mehr Rücksetzungen als bei Sperrverfahren zu rechnen; andererseits können bei optimistischen Verfahren keine Deadlocks entstehen. [Härder, Rahm; Datenbanksysteme] 3. Schreibphase: Hat die Transaktion die Validierungsphase erfolgreich durchlaufen - und nur in diesem Falle - werden die gepufferten Änderungen zurückgeschrieben. Dadurch werden die Änderungen für andere Transaktionen erst sichtbar. Vorteile Deadlock-frei geringer Kommunikationsaufwand Probleme vergleichsweise grosser Aufwand bei Transaktionskonflikten Die Durchführung von Änderungen auf privaten Objektkopien bringt Vor- und Nachteile mit sich. Zum einen ist es ein allgemeiner Ansatz, andere Transaktionen vor schmutzigen Änderungen zu schützen. Es kann zeitgleich zur Änderung ein Lesezugriff auf die ungeänderte Version erfolgen, wodurch sich möglicherweise eine höhere Parallelität einstellt. Weiterhin sind Rücksetzungen von Transaktionen einfach zu realisieren, da hierzu lediglich die privaten Änderungen der Transaktion "wegzuwerfen" sind, da diese noch nicht in der Datenbank sichtbar gemacht wurden. Andererseits verursachen Kopien einen höheren Speicherbedarf sowie eine komplexere DBPufferverwaltung. ... Es lassen sich optimistische Synchronisationsverfahren gemäß ihrer Validierungsstrategie grob in zwei Klassen unterteilen. Bei den rückwärtsorientierten Verfahren (Backward Oriented Optimistic Concurrency Control, BOCC) erfolgt die Validierung ausschließlich gegenüber bereits beendeten Transaktionen. Bei den vorwärtsorientierten Verfahren (Forward Oriented Optimistic Concurrency Control, FOCC) dagegen wird gegen noch laufende Transaktionen validiert. In beiden Fällen wird durch die Validierung sichergestellt, dass die validierende Transaktion alle Änderungen von zuvor erfolgreich validierten Transaktionen gesehen hat. Damit ist die Serialisierungsreihenfolge durch die Validierungsreihenfolge gegeben. [Härder, Rahm; Datenbanksysteme] 139 Rückwärts orientierte Validierungsverfahren In der Validierungsphase wird geprüft, ob das durch die zu validierende Transaktion geänderte Datenobjekt zwischenzeitlich von einer anderen Transaktion verändert wurde. Dazu wird das Read-Set der Transaktion mit allen Write-Sets derjenigen Transaktionen, die während der Lesephase dieser Transaktion validiert wurden, verglichen. Bei Übereinstimmung gilt die zu überprüfende Transaktion als validiert. Typischerweise haben langlaufende Transaktionen häufiger Probleme mit der Validierung als kurzlaufende. Im ursprünglichen BOCC-Verfahren wird bei der Validierung überprüft, ob die validierende Transaktion ein Objekt gelesen hat, das während ihrer Lesephase geändert wurde. Dazu wird in der Validierungsphase der Read-Set der validierenden Transaktion T1 mit den WriteSets aller Transaktionen T2 verglichen, die während der Lesephase von T1 validiert haben. Ergibt sich eine Überschneidung mit einem dieser Write-Sets, wird die validierende Transaktion zurückgesetzt, da sie möglicherweise auf veraltete Daten zugegriffen hat (die am Konflikt beteiligten Transaktionen können nicht mehr zurückgesetzt werden, da sie bereits beendet sind). Die Validierungen werden dabei in einem kritischen Abschnitt durchgeführt, der sicherstellt, dass zu einem Zeitpunkt höchstens eine Validierung vorgenommen wird. ... Ein schwerwiegendes Problem ist die Gefahr des "Verhungerns", dass also Transaktionen bei der Validierung ständig scheitern. Dies ist vor allem für lange Transaktionen zu befürchten, da sie einen großen Read-Set aufweisen und sich gegenüber vielen Transaktionen validieren müssen. Weiterhin verursacht das späte Zurücksetzen am Transaktionsende ein hohes Maß an unnötig verrichteter Arbeit. [Härder, Rahm; Datenbanksysteme] Vorwärtsorientierte Verfahren Bei FOCC erfolgt die Validierung nicht gegen bereits beendete Transaktionen, sondern gegenüber aktiven Transaktionen. In der Validierungsphase, die nur von Änderungstransaktionen durchzuführen ist, wird untersucht, ob eine der in der Lesephase befindlichen Transaktionen ein Objekt gelesen hat, das die validierende Transaktion zu ändern im Begriff ist. In diesem Fall muss der Konflikt durch Zurücksetzen einer (oder mehrerer) der beteiligten Transaktionen aufgelöst werden. Anstatt der validierenden Transaktion können also auch die betroffenen laufenden Transaktionen zurückgesetzt werden, um z.B. den Arbeitsverlust zu verringern. Auch das Verhungern von Transaktionen kann verhindert werden, in dem z.B. bei der Auswahl der "Opfer" die Anzahl der bereits erfolgten Rücksetzungen berücksichtigt wird. Im Gegensatz zum BOCC-Ansatz führen bei FOCC daneben nur echte Konflikte zu Rücksetzungen. [Härder, Rahm; Datenbanksysteme] Die zu validierende Transaktion wird nicht gegen bereits validierte, sondern gegen zum Zeitpunkt der Validierung aktive Transaktionen geprüft. Dabei wird ermittelt, ob parallel ablaufende Transaktionen in der Lesephase auf die durch die überprüfte Transaktion zu ändernden Datenobjekte zugreifen. In diesem Falle gibt es zwei mögliche Reaktionen: die überprüfte Transaktion wird zurückgesetzt, die anderen Transaktionen, die in Konflikt sind, werden zurückgesetzt. (Somit kann auch eine länger laufende Transaktion eine gute Chance bekommen.) 140 nach vagen Informationen: Navision native DBMS ist ein Beispiel für ein RDBMS mit optimistischem Synchronisationsverfahren Allerdings kann Navision auch mit anderen RDBMS betrieben werden Probleme bei verteilten DBMS: langsame Kommunikationsverbindungen fehleranfällige Verbindungen => Daten nicht verfügbar entfernter Rechner ggf. stark überlastet Replikation adressiert diese Probleme: (einige) Datenobjekte werden mehrfach (auf mehreren Knoten) gespeichert: o höhere Datenverfügbarkeit o Performance-Verbesserung jedoch: Widerspruch zur Redundanzfreiheit jeder Fakt wird genau einmal gespeichert => jeder Zugriff auf Daten liefert immer aktuellen Wert Replikation Replikation bedeutet, dass ein Datenobjekt mehrfach gespeichert wird. Dies steht im Widerspruch zur Redundanzfreiheit der Datenbasis: jeder Fakt wird genau einmal gespeichert. Der Grund für Replikation liegt in dem Ziel der besseren Erreichbarkeit von Daten. Replikation - oder das Verlassen des Grundsatzes der Redundanzfreiheit - kann auch bei einem zentralen DBMS benutzt werden, um die Performance zu steigern: Daten, auf die von vielen Anwendungen "parallel" üblicherweise nur lesend zugegriffen wird, können z.B. mehrfach gespeichert werden. Eine besondere Rolle spielt Replikation aber in verteilten DBMS. Wird in einem verteilten DBMS in einer Transaktion auf Datenobjekte zugegriffen, die auf einem entfernten Rechner liegen, so treten folgende Probleme auf: In der Regel hat man mit einer - im Vergleich zu den übrigen Operationen langsamen Verbindung zu tun, es muss eine Kommunikation zwischen den Rechnern aufgebaut werden, die Transaktion dauert lange: die Daten sind "schwer" erreichbar. Zusätzlich kann noch der entfernte Rechner stark belastet sein, was ebenfalls die Daten schlecht erreichbar macht. Ist die Verbindung zusammengebrochen, so kann die Transaktion nicht durchgeführt werden: die Daten sind nicht erreichbar. Als Vorteil ist jedoch anzusehen, dass die Transaktion immer aktuelle Daten erhält. 141 Will man nur lesend auf die entfernten Daten zugreifen, so wäre häufig schon damit gedient, eine (ggf. nicht ganz aktuelle) Kopie der Daten lokal zu besitzen. Dann könnte direkt in dieser Kopie gelesen werden, die obigen Probleme entfallen: die Zugriffsgeschwindigkeit wird (in der Regel) wesentlich verbessert, die Zuverlässigkeit ebenfalls. Die entstehenden Probleme sind einerseits beanspruchter Plattenplatz (in der Regel ein unwichtiges Argument) sowie die Verletzung der Redundanzfreiheit. Dies ist ein Grund, weswegen das Verteilungsschema sorgfältig durchdacht und geplant werden muss. Ein weiterer Grund wird in der folgenden Überlegung deutlich. Wird auf einem Knoten ein Replikat einer Tabelle angelegt, so nimmt die Verfügbarkeit der Daten bei lesenden Transaktionen offensichtlich zu, das gesamte System wird gegenüber Ausfällen stabiler. Ganz anders wirken sich hier Änderungstransaktionen aus: da jede weitere Komponente die Ausfallwahrscheinlichkeit für das Gesamtsystem erhöht, eine Änderung bei allen Replikationen im Prinzip "gleichzeitig" durchgeführt werden muss, treten offensichtlich mit einer Erhöhung der Anzahl an Replikaten in diesem Falle Probleme auf, die Aktualität der Daten sinkt. Replikation verstößt gegen das Prinzip der Redundanzfreiheit. Man muss sich also fragen, welche Gründe für eine Replikation bei verteilten DB-Anwendungen sprechen, d. h. für eine redundante Datenhaltung, bei der Änderungen an die Knoten (transparent für den Benutzer durch die beteiligten DBMS) weitergegeben werden. Im wesentlichen sprechen folgende Gründe dafür: die Lokalität von Anwendungen kann gewahrt bleiben, wenn alle Daten, die die Anwendungen brauchen, vor Ort vorhanden sind; damit entfällt der langsame Zugriff übers Netz, die Verfügbarkeit des Gesamtsystems wird erhöht; auch wenn ein Knoten ausfällt, können die Anwendungen auf den anderen Knoten weiterlaufen, da die benötigten Daten repliziert sind, die Performance des Gesamtsystems wird erhöht, da die Lese- und Schreibzugriffe entzerrt werden (können) [Achilles, SQL, 341] Korrektheit Damit die globale Konsistenz nicht beeinträchtigt wird, muss eine Änderung an einem replizierten Datenobjekt auf allen Knoten, die Replikate dieses Objekts besitzen, durchgeführt werden. Dabei muss diese Änderung so erfolgen, dass zugreifende Transaktionen eine konsistente Version des Objekts "sehen". Über die Synchronisation hinaus muss für Replikate noch Korrektheitskriterium gelten: Für jede globale Folge von Transaktionen gilt: die an den Knoten entstehenden (Teil)Transaktionen sind lokal jeweils serialisierbar, die Menge aller lokalen Transaktionsfolgen kann in eine serielle Ausführungsreihenfolge gebracht werden, die äquivalent zu einer globalen Folge ist. Replikationsverfahren Das im vorigen Abschnitt angeführte Korrektheitskritierum muss von solchen Replikationsverfahren beachtet werden, die zur Gruppe der syntaktischen Verfahren zählen. Ist spezielles Anwendungswissen gegeben, so können in manchen Fällen semantische Verfahren eingesetzt werden. Semantische Verfahren sind deshalb nicht universell einsetzbar. 142 Aus diesem Grunde wird im folgenden nur eine Übersicht über die syntaktischen Verfahren gegeben. Syntaktische Replikationsverfahren absolutistische Kopienübergreifende Synchronisation Beispiele: Primary Copy, Token, Exclusive Writes Voting-basierte kopienübergreifende Synchronisation o unstrukturiertes Quorum statisches Quorum Beispiele: Majority-Consensus, Weighted Voting, Voting with Witness, Voting with Ghosts, Voting with Bystanders dynamisches Quorum Beispiele: Dynamic Voting, Voting Class o strukturiertes Quorum statisches Quorum Beispiele: Tree Quorum, Grid-Protocol dynamisches Quorum Beispiele: Reconfigurable Tree-Quorum, reconfigurable Grid-Protocol Read-One-Copy kopienübergreifende Synchronisation Beispiele: ROWA, Available Copies, Virtual Partitions, Missing Writes, Replica Regeneration, CDDR Primary Copy Nur an einer ausgezeichneten Primärkopie dürfen Änderungen durchgeführt werden. Diese Änderungen werden an die Kopien asynchron weitergeleitet. Lesende Transaktionen greifen auf die lokale Kopie zu, können dabei aber nicht ohne weiteres damit rechnen, die neueste Information dort vorzufinden. Dateninkonsistenzen sind ausgeschlossen, jedoch können beim Lesen veraltete Informationen zu Problemen führen. Ein Vorteil ist die Schnelligkeit der schreibenden Transaktionen. [Achilles, SQL] Im Gegensatz zum ROWA-Verfahren erfolgt die Durchführung von Änderungen nicht synchron auf allen Replikaten. Vielmehr erhalten alle Replikate eines Datenobjekts (Tabelle) die Änderungsinformationen > asynchron von einem ausgezeichneten Knoten. Jede Änderung dieses Datenobjekts darf deshalb nur auf diesem ausgezeichneten Knoten erfolgen (Primärkopie). Schließt eine Transaktion die Änderung der Primärkopie erfolgreich ab, so übernimmt der Primärknoten die Verteilung der Änderungsinformation an alle Knoten, die Replikate dieses Objektes tragen. Die Wahl des Ortes der Primärkopie beeinflusst den Kommunikationsaufwand. Der Kommunikationsaufwand wird weiter verringert, wenn Änderungsinformationen auf dem Primärknoten lokal gesammelt und verzögert gebündelt an die anderen Knoten verteilt wird. Damit sinkt allerdings die Aktualität der Replikate. Je nach Anforderung bzgl. der Aktualität können Transaktionen beim Lesezugriff unterschiedliche Methoden einschlagen: Lesen von der Primärkopie Vorteile der Replikation verschwinden völlig 143 Anfordern einer Lesesperre auf der Primärkopie, lokales Lesen Nachteile nahezu wie im ersten Fall rein lokales Lesen Vorteile der Replikation werden ausgeschöpft, auf Aktualität wird aber verzichtet Nachteil dieses Verfahrens liegt in der zentralen Stellung des Primärknotens. Ausfall des Primärknotens verhindert Änderungstransaktionen. Jedoch sind im Gegensatz zu ROWA Netzpartionierungen mit weniger Nachteilen verbunden. Voting-Verfahren Voting-Verfahren holen vor der Bearbeitung (Schreiben sowie Lesen) eines replizierten Datenobjekts in einer "Umfrage" die Zustimmung der replikatführenden Knoten ein. Beim unstrukturierten Quorum (vgl. z.B. Majority Consensus) werden beliebige replikat-tragende Knoten befragt, beim strukturieren Quorum (vgl. z.B. Tree Quorum) sind die Knoten in einer festgelegten Struktur (z.B. Baum-Struktur) zu befragen. Der transaktions-initiiernde Knoten befragt die beteiligten replikat-tragenden Knoten - bei strukturierten Quoren entlang der Hierarchie - und sammelt die Stimmen. Jeder befragte Knoten gibt eine positive Antwort, sofern das betreffende Datenobjekt lokal frei ist, eine Verneinung, falls das Datenobjekt gesperrt sein sollte. Wird eine "ausreichende" Menge positiver Antworten ermittelt, so darf der Zugriff erfolgen. Dabei wird das Ziel verfolgt, dass nur eine von mehreren konkurrierenden Transaktionen die Mehrheit der abgegebenen Stimmen erhält und somit fortfahren darf. Voting-Verfahren: Majority Consensus: unstrukturiertes Quorum Änderungen: jeder Knoten, der ein Replikat hat, muss alle anderen Knoten kennen, die ein entsprechendes Replikat besitzen. Der Knoten, an dem eine Transaktion initiiert wird, muss alle beteiligten Replikat-tragenden Knoten befragen jeder befragte Knoten antwortet positiv, falls das betreffende Datenobjekt lokal frei ist (und sperrt es für die Transaktion), negativ falls es bereits gesperrt ist der fragende Knoten sammelt die Antworten ist die Mehrheit der Antworten positiv d.h. Hälfte aller Knoten + 1, darf die Änderung erfolgen (denn keine andere Transaktion kann entsprechend viele Stimmen erlangen) Vor der durchzuführenden Änderung muss die Mehrheit der Replikate mit einer Schreibsperre versehen sein. Mehrheit bedeutet: die Hälfte aller replikat-tragenden Knoten + 1. Lesetransaktionen beruhen auf dem gleichen Prinzip. Damit lassen sich Dirty-Reads und Inconsistent Reads vermeiden. Vorteil des Verfahrens liegt in der Stabilität gegen Knotenausfälle, nachteilig ist jedoch der hohe Kommunikationsaufwand. 144 Voting-Verfahren: Tree Quorum: strukturiertes Quorum Die Verminderung des Kommunikationsaufwandes liegt den strukturierten Quoren zu Grunde. Es geht nicht mehr um die Mehrheit der beteiligten Knoten, sondern um die Mehrheit der Ebenen, die es zu gewinnen gilt. Die Mehrheit einer Ebene gilt als erreicht, sobald die Mehrheit der Knoten dieser Ebene der Transaktion die Zustimmung erteilt. Beim Tree Quorum liegt der einzuhaltenden Struktur ein Baum zu Grunde, die Anfrage startet auf Grund der Baumstruktur vom Wurzelknoten aus. Dies kann zu Kommunikationsengpässen führen. Bei Ausfall mehrerer Knoten kann ggf. keine entscheidungsfähige Mehrheit zustande kommen. Dynamische Quoren Problem bisherigen Vorgehens: Anzahl der Rückmeldungen starr auch wenn Knoten ausfallen: wird die ursprüngliche Anzahl von positiven Antworten eingefordert Vorgehen: Mache Anzahl der geforderten positiven Antworten von Anzahl der erreichbaren Knoten abhängig. Hier versucht man, die Anzahl der positiven Rückmeldungen nicht starr zu halten, sondern dynamisch mit der Anzahl der erreichbaren Knoten zu verändern. Damit erhöht sich die Verfügbarkeit, jedoch können Netzpartitionierungen zu ungewünschten Effekten führen. Dynamische Quoren: Netzpartitionierung ROWA: Read One - Write ALL Alle Kopien sind stets auf dem gleichen Stand, in der Regel sind auch alle gleichberechtigt, d.h. alle Kopien dürfen verändert werden. Lokales Lesen ist problemlos, die Implementation 145 ist einfach, der Nachteil dieses Vorgehens liegt jedoch darin, dass alle lokalen DBMS, die eine Kopie der entsprechenden Tabelle enthalten, auch verfügbar sein müssen. Dadurch wird die Verfügbarkeit des Gesamtsystems verringert. Außerdem bewirken schreibende Transaktionen eine verhältnismäßig hohe Laufzeit. [Achilles, SQL] Jede Lesetransaktion kann davon ausgehen, dass sie zu jeder Zeit den aktuellsten Datenbestand sieht. Datenänderungen müssen deshalb synchron an allen Replikaten durchgeführt werden. Änderungstransaktionen können somit nicht nur das zu ändernde Datenobjekt, sondern müssen zugleich alle Replikate dieses Objekts sperren. Dies ist zugleich ein problematischer Nachteil des Verfahrens: fällt ein replikat-führender Knoten aus, so kann kein globales Commit erfolgen. Die Qualität hängt entscheidend von der System-Verfügbarkeit ab. Für Lesezugriffe gelten jedoch alle Vorteile der replizierten Datenhaltung. Es gibt Erweiterungen des ROWA-Verfahrens, um den eben betrachteten Nachteil zu umgehen: Änderungen werden nur auf den aktuell erreichbaren Knoten durchgeführt. Damit tritt aber das Problem der Netzpartitionierung auf: es kann dann vorkommen, dass der nicht erreichbare Knoten wegen einer Kommunikationsstörung nur für die ändernde Transaktion nicht erreichbar, sonst aber durchaus aktiv für andere Transaktionen zur Verfügung steht. Neben der langen Ausführungszeit von schreibenden Transaktionen ist ferner nachteilig, dass komplexe Wiederanlauf-Prozeduren vorgesehen werden müssen, damit die nicht erreichbaren Kopien auf den aktuellen Stand gebracht werden. [Achilles, SQL] Oracle: Basic Replication: Änderung auf Primärtabelle, Datenverteilung asynchron auf Replikate Replikate als Snapshot der Primärtabelle Änderungs-LOG der Primärtabelle wird benutzt, um die Änderungen zu propagieren entspricht dem Primary Copy Als Basic Replication wird in Oracle die letzte Version bezeichnet. Die Änderungen erfolgen ausschließlich auf einer Primärtabelle, die Daten werden asynchron auf mehrere Kopien repliziert. Eine Kopie wird zunächst als ein Snapshot der Primärtabelle angelegt, die folgenden Änderungen können entweder als Snapshot durchgeführt werden, was in der Regel aufgrund des zu übermittelnden Datenvolumens sehr kritisch ist, oder als "Fast-Refresh". Bei diesem Verfahren wird aus dem Änderungs-LOG der Primärtabelle abgeleitet, welche Änderungen an die Kopien zu übermitteln sind. [Achilles, SQL] Advanced Replication Symmetrische Replikation mit asynchroner Aktualisierung 146 alle Replikate sind gleichberechtigt, Änderungen werden an alle übrigen Replikate asynchron weitergereicht keine Behandlung des DELETE-Konfliktes Symmetrische Replikation von Tabellen wird in Oracle "Advanced Replication" genannt. Dieses Vorgehen entspricht der asynchronen symmetrischen Aktualisierung: alle Kopien sind gleichberechtigt, die Änderungen werden an alle Kopien weitergereicht. eine Behandlung des DELETE-Konflikts ist nicht vorgesehen. [Achilles, SQL] Änderbare Snapshots Variante der Beiden vorhergehenden Arten: Primärtabelle verteilt weiterhin die Änderungen asynchron an alle Replikate, Replikate richten die Änderungsmitteilung mit Hilfe des INSTEAD OFTriggers an die Primärtabelle Änderbare Snapshots einer Primärtabelle. Hier handelt es sich um eine Variante beider vorhergehenden Arten: die Primärtabelle verteilt weiterhin die Änderungen an alle Kopien, die Kopien richten mit Hilfe des INSTEAD OF-Triggers die Änderungsmitteilungen an die Primärtabelle. [Achilles, SQL] Symmetrische synchrone Aktualisierung: (ROWA) ist nicht vorgesehen DB2: Replikationen werden durch den DataPropagatorRelational ermöglicht. Dieses Produkt überwacht die Änderungen an Quelltabellen und schreibt diese Änderungen in eine eigene Datenstruktur, von der aus sie nach bestimmten Zeiten oder auf Anforderung an die Kopien weiter verteilt werden. [Achilles, SQL] Asynchrone Aktualisierung unter Einsatz einer Primärtabelle: es werden nur transaktions-konsistente, aber nicht transaktions-basierte Änderungen verteilt Verringerung der Netzbelastung, indem zwischen zwei Replikationszeiten Änderungen zusammengefasst werden Bei dieser Form werden nur transaktionskonsistente, aber nicht transaktionsbasierte Änderungen verteilt. Der Unterschied liegt darin, dass Änderungen hinsichtlich eines Records, die sich zwischen zwei Replikationszeiten befinden, zu einer Änderung zusammengefasst werden, um so die Netzbelastung zu verringern. [Achilles, SQL] 147 Transaktions-basierte asynchrone Aktualisierung unter Einsatz einer Primärtabelle Primary Copy Asynchrone Aktualisierung unter Einsatz einer Primärtabelle mit änderbaren Kopien sowohl Replikate als auch Primärtabelle erzeugen Änderungsmitteilungen, Änderungsmitteilungen der Replikate gehen an Primärtabelle, die auf Konsistenz überprüft, Primärtabelle übernimmt Verteilung Hier erzeugen sowohl die Kopien als auch die Primärtabelle Änderungsmitteilungen, die transaktionsbasiert sind. Die Änderungsmitteilungen der Kopien richten sich an die Primärtabelle, von der aus sie allen anderen Kopien zur Verfügung stehen. Bei der Übernahme der Änderungsmeldungen von Kopien wird auf Dateninkonsistenz überprüft. [Achilles, SQL] Symmetrische synchrone Aktualisierung: (ROWA) ist nicht vorgesehen 148 8. DRDA: Distributed Relational Database Architecture DRDA (Distributed Relational Database Architecture) wurde 1998 festgelegt als "Blueprint", d.h. als Architekturbeschreibung, um Anwendungen und relationale Datenbanken auf Basis einer Verteilung miteinander zu verbinden. DRDA definiert Methoden zur koordinierten Kommunikation zwischen verteilten DBMS, wobei der Zugriff auf entfernte Tabellen für den Benutzer wie ein lokaler Zugriff erscheint. Diese Beschreibung ist in der "Open Group" Hersteller-unabhängig veröffentlicht. DRDA beschreibt die Architektur und die Regeln des Zugriffs. Für die Implementation von DBMS werden von diversen Herstellern APIs angeboten, die sich an den Regeln/Protokollen von DRDA orientieren müssen. DRDA greift dabei auf eine Reihe von bereits bestehenden Produkten und "Blueprints" zurück, die durch die Klammer der DRDA-Produkte (Implementation der DRDA-Manager) "zusammengebunden" werden: DBMS, Kommunikationsprotokolle, DDM - Distributed Data Management Architecture, FD:ODC - formatted Data Object Content Architecture, SQL RDA (Remote Database Access) (ISO, ANSI-Standard Komitee) Unterschiede: RDA: Standard-Subset von SQL, das auf allen Plattformen verfügbar ist DRDA: arbeitet mit Plattform-spezifischen Erweiterungen von SQL RDA: nur dynamisches SQL DRDA: auch statisches SQL Remote Database Access RDA Die spezielle Kommunikation zwischen Datenbank-Server und Datenbank-Client in einem Netz ist von der ISO 1993 in einer ersten Version als Remote Database Access (RDA) als internationaler Standard verabschiedet worden. RDA spezifiziert Kommunikationsdienste und Kommunikationsprotokolle zum flexiblen Zugriff von Clients auf entfernte Datenbanken in heterogenen Netzen; allerdings nur auf der logischen Ebene! (d. h. die logische Struktur, die Funktionalität und das Aufrufprotokoll). Die 149 konkrete Beschreibung der Schnittstellen (call interface) oder konkrete Implementierung ist nicht Teil dieses Standards. Der ISO-RDA-Standard besteht aus zwei Teilen: a) generischer RDA: Hier sind die Funktionen zum Initialisieren, Öffnen und Schließen einer Session, zum Anstoßen der Ausführung, zum Commit usw. beschrieben, die unabhängig vom Typ eines eingesetzten DBMS gelten. b) spezifischer RDA: Hier ist beschrieben, welche SQL-Syntax unterstützt wird (im Prinzip ein Verweis auf den SQL-Standard). DRDA unterstützt unter anderem die Protokolle TCP/IP und SNA, RUOW (remote unit of work): pro Unit of Work kann 1 DBMS mit mehreren Requests auf dieses DBMS angesprochen werden, die Anwendung löst das COMMIT aus, das auf dieses DBMS alleine wirkt, DUOW (distributed unit of work): pro Unit of Work kann auf mehrere DBMS mit Requests zugegriffen werden, die Anwendung steuert die Verteilung der Zugriffe, pro Request kann jeweils nur 1 DBMS angesprochen werden, doe Anwendung löst COMMIT aus, das als 2-PhasenCOMMIT die beteiligten DBMS koordiniert, die Verwendung von Stored Procedures in DOUW, in DUOW ein optimiertes 2-Phasen-COMMIT, Sicherheitsmechanismen, ggf. Lastausgleich, Verteilter Zugriff wird in DRDA mit drei Funktionen verwirklicht, die miteinander operieren: Application Requester (AR) Application Server (AS) Database Server (DS) Application Requester Der Application Requester ermöglicht SQL und entsprechende Anforderungen durch Programme. Er nimmt SQL-Anforderungen vom Programm entgegen und sendet sie zur Weiterverarbeitung an die entsprechenden Server. Falls Daten ausschließlich lokal vorliegen, wird kein DRDA benötigt. Falls Daten nur entfernt vorliegen, wird ein lokales DBMS benötigt. Application Server Der Applikation Server empfängt die Anforderungen des Application Requester und bearbeitet diese. Sofern möglich, werden die Anforderungen direkt bearbeitet. SQLAnweisungen werden an den Database-Server zur Bearbeitung weitergeleitet. 150 Kommunikation zwischen Application Requester und Application Server Das Kommunikationsprotokoll zwischen Application Requester und Application Server heißt Application Support Protocol. Es sorgt für eine entsprechende Datenumwandlung, z.B.ASCII-EBCDIC Database Server Der Database Server erhält vom Application Server oder einem anderen Database Server eine Anforderung. Dies kann eine SQL-Anweisung oder „Programmvorbereitung“ sein. So wie der Application Server bearbeitet der Database Server die Anforderung so weit wie möglich und gibt den Rest weiter an andere Database Server (z.B. Join von Tabellen, die auf unterschiedlichen Database Servern liegen). Für die Kommunikation zwischen Application Server und Database Server oder zwischen zwei Database Servern wird das Database Support Protocol benutzt. Die Beziehungen zwischen Anwendung und DBMS zeigt die folgende Abbildung: 151 Rückgabe nach kompletter Bearbeitung der Anforderung Der Apllication Server gibt einen ReturnCode und ein ResultSet (sofern erzeugt) an den Apllication Requester. Der ReturnCode ist vom Typ SQLSTATE. Bei den Befehlen INSERT, UPDATE, DELETE wird kein ResultSet erzeugt, ebenso, wenn es bei einer Select-Anweisung keine Ergebniszeilen gibt. Auch bei DCL (Data Control Language) oder DDL (Data Definition Language) wird kein ResultSet erzeugt. Limited Block Protocol: Die Voraussetzung für das Limited Block Protocol ist ein Read only Cursor. Dieser sendet mehrere Zeilen über das Netz, auch wenn der Fetch jeweils nur eine Zeile bearbeiten kann. Dadurch entsteht eine Verringerung des Netzverkehrs und damit Performance-Verbesserung . Es gibt noch weitere Standards, auf denen DRDA aufsetzt: Advanced Program to Program Comunication (APPC) Kommunikations-Unterstützung LU6.2 zwischen funktional gleichberechtigten logischen Einheiten Distributed Data Management (DDM) definiert Methoden, um verteilte Daten über Netz mittels APPC anzusprechen Daten können entweder Files oder Tabellen in einem RDBMS sein Formatted Data: Object Content Architecture (FD:OCA) Architektur, um Daten-Felder auszutauschen Daten und ihre Beschreibung werden zusammen verpackt, so dass jedes DRDA-unterstützende DMBS Struktur und Inhalt verstehen kann Character Data Representation Architecture (CDRA) unterstützt den Austausch von Zeichen zwischen den unterschiedlichen Hardware- und BS-Architekturen Application und DBMS können auf unterschiedlichen Hardware- und Betriebssystemsplattformen basieren, im Falle von DUOW können auch die angesprochenen DBMS in einer Unit of Work von unterschiedlichem Typ sein. DRDA beschreibt die Aktionen zwischen Application und Server, um folgende Funktionen auszuführen: Verbindungsaufbau einschließlich Identifikation, Binden der Hostvariablen und des SQL-Statements an ein entferntes DBMS, Ausführung des SQL-Statements im entfernten DBMS für die Application und Rückgabe der ermittelten Daten, Ausführen dynamischer SQL-Anweisungen für die Application und Rückgabe der ermittelten Daten, Unterstützung der Transaktionen, Abbau der Verbindung. 152 DRDA bietet 5 unterschiedliche Ebenen für die Unterstützung von Verteilung 1. 2. 3. 4. 5. User-Assisted Remote Request Remote Unit of Work (RUW) Distributed Unit of Work (DUW) Distributed Request Übersicht über die DRDA-Ebenen # SQLAnweisungen DRDA-Ebene # DBMS pro Einheit # DBMS pro SQLAnweisung User-Assisted - - - Remote Request 1 1 1 Remote Unit of Work >1 1 1 Distributed Unit of Work >1 >1 1 Distributed Request >1 >1 >1 User-Assisted Distribution Der Benutzer nimmt die physische Verteilung wahr, er kann nur die Daten aus dem System extrahieren und Daten in das System laden. Dies kann nützlich sein z.B. bei der Erstellung von Snapshots, kann aber auch zu Problemen bei der Replikation führen. Remote Request Wenn ein DBMS DRDA Remote Request Fähigkeiten unterstützt, dann kann eine einzige SQL-Anweisung pro Single Unit of Work an ein entferntes DBMS gestellt werden um Daten zu lesen oder zu verändern Remote Unit of Work Mehrere SQL-Anweisungen können in einer Transaktion gegen genau ein entferntes DBMS gestellt werden Distributed Unit of Work Mehrere SQL-Anweisungen können in einer Transaktion gegen mehrere entfernte DBMS gestellt werden. Pro SQL-Anweisung kann jedoch nur ein DBMS ngesprochen werden. Das 2-Phasen-Commit-Protokoll dient zur Synchronisation der Transaktion. Distributed Request bedeutet vollständige Verteilung: eine SQL-Anweisung kann mehrere DBMS betreffen mehrere Anweisungen können in einer Transaktion verwendet werden Anmerkung: derzeit gibt es keine Produkte, die Distributed Request Eigenschaft besitzen DRDA Managers Zugrunde liegt das DDM (Distributed Data Management Architecture) System, das aus Managern aufgebaut ist, die zusammenarbeitend Server bilden. So ist es die Aufgabe des Application-Requester, DDM-Kommandos, -Parameter und -Daten zu erzeugen und an den entsprechenden Application-Server zu schicken, sowie die Meldungen des Servers zu 153 empfangen und wieder korrekt für die Application aufzubereiten. Der Application-Server muss die Meldungen des Application-Requesters empfangen können, in Abhängigkeit der empfangenen Kommandos die richtige Antwort erzeugen, in einen DDM-Datnestrom umsetzen und dem Application-Requester zusenden. SNA- bzw. TCP/IP-Manager Diese Manager stellen den Kommunikationssupport bereit, stellen das DRDAKommunikationsprotokoll bereit, das auf dem Transportprotokoll aufsetzt, erzeugt bzw. zerlegt die DDM-Datenströme. Agent Im Application-Requester bildet der Agent ein Interface zwischen dem SQL Application Manager und dem jeweiligen Kommunikations-Interface. Im Application-Server geht die Aufgabe darüber hinaus: der Agent wählt denjenigen Manager aus, an den ein Kommando weitergeleitet werden muss, er involviert den Security-Manager des Application-Servers, damit jeder Zugriff überprüft wird, mit Hilfe des Supervisors werden die dem Requester zugeteilten Ressourcen überwacht. Supervisor Verwaltet eine Menge von Managern innerhalb eines bestimmten Betriebssystems, dient als Interface zu Directory- und Security-Diensten und den anderen Managern innerhalb des Systems. Security Manager Dient der Identifizierung der Endbenutzer gegenüber den verwendeten DBMS und Betriebssystemen, garantiert dadurch, dass der Requester nur diejenigen Zugriffe ausführen kann, für die er auch autorisiert ist. Directory Dient dazu, Namen von Manager-Objekten auf ihre Adressen abzubilden. Damit werden diese Objekte erreichbar. Dictionary Resynchronization Manager Dieser Manager greift ein, wenn eine COMMIT-Anweisung scheitert. Während der Transaktion geschützte Ressourcen werden wieder hergestellt. Sync Point Manager Hierdurch werden COMMIT- und ROLLBACK-Anweisungen koordiniert. Bei verteilten Updates kooperieren die beteiligten Sync Point Manager, um einen konsistenten Zustand zu gewährleisten. SQL Application Manager Dieser Dienst nimmt sowohl im Application-Requester als auch im Application-Server die benötigten Umwandlungen der Daten vor: 154 aufgrund der Anforderungen der Application ruft der SQLAM des ApplicationRequester die zugehörigen Operationen im Application-Server durch DRDAKommandos auf, der SQLAM des Application-Server greift dadurch auf die entsprechenden Operationen des DBMS zu, und entsprechend läuft die Übermittlung der Ergebnisse. Darüber hinaus werden numerische Daten und Character bei Bedarf konvertiert. Auf beiden Seiten muss sich der SQLAM beim Sync Point Manager anmelden, damit COMMIT- und ROLLBACK-Operationen entsprechend unterstützt werden können. Relational Database Manager Dieser bildet das Interface zum DBMS. DRDA Kommando-Fluss Die nachfolgende Abbildung verdeutlicht, wie die diversen Manager ineinander greifen: 155 Distributed Database: viel Aufwand und wenig Nutzen COMPUTERWOCHE Nr. 50 vom 16.12.1994 Negativer Einfluss auf die Performance und Zwang zur Homogenitaet zu einer Zeit, in der eigentlich Offenheit gefordert ist, sind nur zwei Punkte, die gegen verteilte Datenbanken sprechen. Funktionsaufrufe statt SQL-Befehle sowie gezielte Redundanz und Datenverteilung sind die bessere Loesung. Von Michael Bauer* Verteilte Datenbanken stellen ein eigenartiges Phaenomen dar: Obwohl die dafuer erforderlichen Loesungskonzepte seit fast 20 Jahren existieren, gibt es erst seit einiger Zeit lauffaehige Produkte und selbst diese sind in ihrer Funktionalitaet noch unvollstaendig. Woran liegt das? Es ist einleuchtend, dass Softwarehersteller nicht in aufwendige Entwicklung investieren, wenn bei den Anwendern kein Bedarf dafuer besteht. Zwar hat die Tendenz zu verteilten Systemen dazu gefuehrt, dass aus Entwicklungen in Richtung Distributed Databases auch einsatzfaehige Produkte entstanden sind. Doch sind ernsthafte Implementierungen in der Praxis noch Mangelware. Eine verteilte Datenbank soll dem Benutzer - interaktiver Benutzer oder Anwendungsprogramm die Moeglichkeit bieten, mit auf verschiedenen Rechnern verteilten Daten genauso zu operieren, als waeren sie in dem lokalen DBMS (Database Management Systems) gespeichert. Chris Date, der im Zusammenhang mit relationalen Datenbanken als "Schueler" von Dr. Codd recht bekannt wurde, hat diese Anforderungen einmal in zwoelf Regeln zusammengefasst und damit die gaengige Lehrmeinung in eine knappe Form gegossen. .... Damit ist natuerlich nicht gesagt, dass man diese Technologie auch in der Praxis einsetzen kann. Speziell in bezug auf die Performance treten grosse Probleme auf, die gegen eine verteilte Datenbank sprechen. Erstes Problem: die Performance Die Arbeitsweise von Distributed Databases baut darauf auf, dass ein SQL-Befehl ueber das Netz zu dem DBMS gesandt wird, in dem die betreffenden Daten gespeichert sind. Jeder SQL-Befehl wird so zu einem 156 Nachrichtenpaar: SQL-Befehl hin und Antwort zurueck. Bei operativen Anwendungen kann sich das toedlich auf die Performance auswirken, denn eine Transaktion umfasst ueblicherweise eine Vielzahl von SQL-Befehlen. Dazu ein Beispiel: Wenn bei einer Client-Server-Loesung auf einem dezentralen PC Auftraege erfasst und anschliessend in einer entfernten Datenbank gespeichert werden sollen, entstehen leicht 20 oder 30 SQL-Befehle. Wenn jeder davon zu einer Nachricht wird, die eine Sekunde benoetigt, dauert der ganze Prozess 20 bis 30 Sekunden. Loest man das Problem dagegen in Form einer kooperativen Verarbeitung, dann residiert der Teil der Anwendung, der die Auftragsdaten verwaltet, auf dem Server, auf dem auch die Daten gespeichert sind. In diesem Fall sendet der Client nur eine Nachricht mit allen Daten eines Auftrags an den Server. Dort werden dann die SQL- Befehle ausgeloest. Das Nachrichtenaufkommen reduziert sich also betraechtlich .... Selbst wenn diese Nachricht laenger ist, dauert der gesamte Prozess hoechstens 20 Sekunden. SQL-Befehle in einem verteilten System (Remote Database Access) zu versenden ist nur dann sinnvoll, wenn fuer eine Transaktion ein SQL-Befehl ausreicht, also fuer Anzeigefunktionen. Aber auch bei solchen Informationsabfragen kann eine verteilte Datenbank Performance-kritisch sein, falls zwischen den DB- Systemen ein aufwendiger Prozess ablaeuft. Hierzu ein weiteres Beispiel: Die Abfrage "Zeige alle Kunden mit Namen "Bauer" an, die auf ihrem Konto einen Saldo >1000 haben" laesst sich in einem einzigen SQL-Befehl formulieren. Sind aber die Kundendaten auf einem und die Kontendaten auf einem anderen Rechner gespeichert, kann es sein, dass erst viele Datensaetze von einem zum anderen System transportiert werden, um nachher vielleicht festzustellen, dass ueberhaupt keine Daten diesen Bedingungen entsprechen .... Unabhaengig von der Frage, wie gut ein DBMS diesen Befehl aufzuloesen versteht - Stichwort: "Globale Optimierung" -, ist es in solchen Faellen besser, die Datenbestaende nicht ueber mehrere Rechner zu verteilen, etwa weil sie haeufig zusammen gebraucht werden, oder sie auf mehreren Systemen redundant zu speichern. Redundanz ist stets das "Schmiermittel" fuer performante Datenbanken. Das gilt sowohl innerhalb einer einzigen Datenbank als auch fuer verteilte Datenbanken. Diese Redundanzen automatisch zu pflegen, ohne dass die Anwendungen betroffen sind, zaehlt zu den Anforderungen an letztere. Doch wie sieht das in der Praxis aus? Wenn ein Unternehmen beispielsweise in jeder seiner Niederlassungen eine Kopie des Artikelbestands redundant speichert, verbessern sich dadurch zunaechst die Zugriffszeiten der lokalen Anwendungen. Eine Aenderung der Artikeldaten dauert jedoch so lange, bis die korrespondierenden Aenderungsbefehle an allen beteiligten Datenbanksystemen der Distributed Database durchgefuehrt wurden. Da ein solcher Prozess aber Schutz gegen Abstuerze und Unterbrechungen braucht, wird der beruehmte "Two Phase Commit" - ein zweistufiges Bestaetigungsprotokoll - notwendig. Dieses beinhaltet nochmals vier zusaetzliche Nachrichten je beteiligtes DBMS. Eine Aenderung dauert somit um ein Mehrfaches laenger als in einer lokalen Datenbank. Deshalb gilt die Regel, dass nur Daten mit geringer Aenderungshaeufigkeit fuer eine redundante Speicherung (Replikation) geeignet sind. Unabhaengig von der Antwortzeit gibt es bei redundanten Daten noch ein weiteres Problem. Was passiert, wenn eines der beteiligten DB- Systeme zum Zeitpunkt einer Aenderung nicht aktiv oder nicht erreichbar ist? Nach dem Konzept einer korrekten Transaktion duerfte dann die Aenderung nicht ausgefuehrt werden. Dadurch waere die Verfuegbarkeit des Gesamtsystems allerdings dramatisch beeintraechtigt. Eine Loesung hierfuer ist das Konzept der "asynchronen Replikation": Dabei werden die Aenderungen zunaechst in einer besonderen Log-Datei gespeichert und durch einen asynchronen Task verteilt. Ein DBMS erhaelt die Aenderungen dann, wenn es wieder verfuegbar ist. Durch die zeitliche Differenz in der Aktualitaet der Daten laesst sich ein solches Konzept, das auch unter der Bezeichnung "Replication Server" angeboten wird, nur mit Einschraenkungen nutzen. Das groesste Hindernis ist, dass auf den Kopiebestaenden keine Aenderungen zulaessig sind, weil sonst unloesbare Konflikte entstehen. Es darf also nur auf der Master-Kopie geaendert werden, waehrend die anderen Replikate read-only sind. Das schraenkt jedoch die allgemeine Verwendbarkeit dieses Konzepts ein. Ein weiteres Problem der Distributed Database liegt im Mehrbedarf an CPU-Zeit. Jeder Datenbankbefehl, auch wenn er letztlich lokal ausgefuehrt wird, bedarf hinsichtlich seiner Auswirkungen auf die verteilte Datenbank einer Analyse. Wenn auf einem Rechner 95 Prozent aller Datenbankbefehle lokal und nur fuenf Prozent entfernt ausgefuehrt werden, steigt der Overhead fuer alle diese Befehle gewaltig. Ein besonderes Problemkind scheint hier DB2/MVS zu sein. So belegte der Testbericht eines Anwenders, dass das lokale DBMS, das den Befehl nur an ein entferntes weiterleitete, mehr CPU-Zeit verbraucht hatte, als wenn es die Arbeit selbst getan haette. Die 157 gesamte CPU-Zeit fuer einen verteilten Datenzugriff erhoehte sich so um 235 Prozent bis 400 Prozent gegenueber einer lokalen Ausfuehrung. Dieser Test wurde mit der Version 2.2 durchgefuehrt. Es bleibt nur zu hoffen, dass neuere Fassungen weniger CPU-Zeit verbrauchen werden. Wenn man die heute verfuegbaren Produkte im Bereich verteilter Datenbanken analysiert, fallen noch zwei weitere Aspekte ins Auge: - Zwar bietet jeder DBMS-Hersteller zu seinem Produkt auch eine Distributed-Database-Komponente, doch sind diese teilweise noch weit davon entfernt, alle Anforderungen zu erfuellen. - Verteilte Datenbanken funktionieren heute nur dann gut, wenn es sich bei allen beteiligten DB-Systemen um das gleiche Produkt handelt. Die unterschiedliche Leistungsfaehigkeit der verteilten Datenbanken laesst sich transparent machen, indem man den Erfuellungsgrad der Anforderungen in vier Stufen gliedert ... Keines der marktgaengigen Produkte erreicht zur Zeit die hoechste Stufe. Die besten liegen etwa bei Stufe 3,5 (zum Beispiel Ingres, Adabas, Informix, Oracle, Sybase), waehrend andere Produkte niedriger rangieren. So ist beispielsweise DB2/MVS, Version 3.1 in Stufe 2 einzuordnen. Andere IBM-Datenbanken liegen noch tiefer. Allerdings wird bei dieser Gruppierung davon ausgegangen, dass es sich bei allen Komponenten der verteilten Datenbanken um das gleiche DBMS handelt. Das ist gerade in einer Client-Server-Welt unwahrscheinlich. Wir wollen im Client-Server-Bereich "offen" sein, das heisst, beliebige Produkte verschiedener Hersteller problemlos einsetzen koennen - und das sollte gerade im Datenbanksektor gelten. Wenn ein Unternehmen DB2, SQL/Base und Informix in seiner Client- Server-Welt kombinieren moechte, ergeben sich zwei Probleme: - Die unterschiedlichen DB-Systeme muessen sich untereinander verstaendigen koennen. - Die Anwendungen muessen ihre SQL-Befehle unabhaengig von dem jeweiligen DBMS absetzen. Fuer ersteres bietet sich die Standard-Schnittstelle DRDA (Distributed Relational Database Architecture) von IBM an, die inzwischen von verschiedenen DB-Systemen genutzt wird. In der Praxis findet zur Zeit allerdings nur eine rudimentaere Art der Zusammenarbeit statt ... Da aber DRDA keinen Standard fuer die SQL-Befehle enthaelt, die zwischen den beteiligten DBSystemen verschickt werden, muessen die Anwendungsprogramme Disziplin ueben: Sie duerfen nur SQL-Anweisungen aus dem kleinsten gemeinsamen Nenner aller DB-Systeme verwenden. Das entspricht zur Zeit dem Befehlsumfang von DB2. Als Konsequenz aus diesen Darstellungen ergibt sich, dass eine Distributed Database wenig hilfreich fuer verteilte Systeme ist. Vorrangiger ist es: - die Daten so an die dezentralen Rechner zu verteilen, dass keine oder nur wenige Zugriffe auf entfernte Datenbanken noetig sind; - nur Daten, die weitgehend statisch sind, redundant zu halten (hierfuer genuegt File-Transfer als Aktualisierungsmechanismus), waehrend Update-intensive Daten nur einmalig zentral gespeichert werden; - statt SQL-Befehle ueber das Netz zu versenden, lieber Funktionsaufrufe im Rahmen von Cooperative Processing zu versenden. Wer seine Daten zu sehr streut, ist selbst daran schuld, wenn er sie hinterher wieder muehsam zusammensuchen muss. * Michael Bauer ist Geschaeftsfuehrer der Informatik Training GmbH in Radolfszell. Anforderungen an verteilte Datenbanken "location transparency" In den DB-Anweisungen muss keine Ruecksicht auf den Speicherort der Daten genommen werden. "distribution transparency" Die Art der Verteilung - un kat, replikat oder partitioniert - darf keine Auswirkungen auf die Befehle haben. Dies umfasst auch automatisches Nachziehen von Aenderungen. Vollstaendige Funktionalitaet Alle DBOperationen - auch Updates - muessen genauso moeglich sein wie bei lokalen Datenbanksystemen. DB-uebergreifende Operationen Ein DB-Befehl muss gegen mehrere DB-Systeme innerhalb der verteilten Datenbanken ausgefuehrt werden koennen. Dies schliesst auch eine netzweite Optimierung ein. Netzweite Integritaet Sperr-, Ruecksetz- und Wiederherstellfunktionen muessen netzweit funktionieren. Besondere Anforderungen Rechner-Unabhaengigkeit Die Datenbank sollte sich ueber Rechner verschiedener Hersteller und Betriebssysteme verteilen lassen. DBMSUnabhaengigkeit Die verteilte Datenbank sollte auch mit unterschiedlichen Datenbanksystemen realisiert werden. 158 9. DataWareHouse Das Data Warehouse-Konzept hat sowohl in der Theorie als auch in der Praxis große Aufmerksamkeit erreicht. ... Aufgrund der Vielzahl von unterschiedlichen betrieblichen und externen Informationsquellen ist das Management einer Unternehmung darauf angewiesen, benötigte Informationen verständlich zur Verfügung gestellt zu bekommen. Aufgabe eines Data Warehouse-Systems ist es dabei, konsistente Informationen zur Unterstützung des Managements bereitzustellen. Zu diesem Zweck sind verschiedene Komponenten notwendig, an die unterschiedliche Anforderungen gestellt werden müssen. Data Warehouse-Systeme unterstützen das Management bei operativen und strategischen Aufgabenstellungen. Gerade im Bereich der strategischen Aufgaben besteht eine Vielzahl von Potentialen, durch die Wettbewerbsvorteile erlangt werden können. Dies gilt sowohl in bezug auf die Erreichung der Unternehmensziele als auch in bezug auf den Prozess der strategischen Unternehmensführung. Voraussetzung dafür ist allerdings eine geeignete Vorgehensweise bei der Systemeinführung. Auch hier sind verschiedene Anforderungen zu stellen, durch die gewährleistet werden soll, dass die strategischen Potentiale erreicht werden können. In der Praxis wird allerdings deutlich, dass nicht alle Anforderungen an das Konzept erfüllt werden. Auf der Seite der Anbieter werden z.Zt. noch viele Produkte verkauft, die vor allem für den Einsatz in Transaktionssystemen geeignet sind. Hier zeichnet sich jedoch ab, dass immer mehr Komponenten entwickelt werden, die an den besonderen Erfordernissen eines Data Warehouse-Systems ausgerichtet sind. Die strategischen Potentiale werden bei derzeitigen Data Warehouse-Lösungen nur begrenzt erreicht. Ein Hauptgrund ist hier der bisher geringe Systemumfang, so dass zukünftig eine höhere strategische Bedeutung des Konzepts zu erwarten ist. Zudem werden mit Hilfe von neuen Komponenten Erweiterungen möglich, die heute vor allem aus technischen Gründen nur begrenzt umgesetzt werden können. Im Zuge eines härter werdenden Wettbewerbs wird in immer mehr Unternehmungen die Notwendigkeit bestehen, Data Warehouse-Systeme aufzubauen. Die Bedeutung des Konzepts in der Praxis wird daher noch weiter steigen. [http://lwi2.wiwi.uni-frankfurt.de/mitarbeiter/paulzen/Diplomarbeit_Paulzen.pdf] Stärken und Schwächen Data Warehouse Ein Vorteil eines Data Warehouse ist die verbesserte Datenqualität. Die Daten sind genauer und liegen durch einfache Transformation und Bereinigung in einem konsistenten Zustand vor. Ein Data Warehouse kann die Abfrageperformance beschleunigen, wodurch eine schnellere Informationsbeschaffung ermöglicht wird. Die Historisierung der Daten lässt ferner historische Trends erkennen. Die Leistung, die die Verarbeitung operativer Daten ermöglicht, wird durch den Einsatz eines Data Warehouse zusätzlich besser nutzbar. Nicht zuletzt unterstützt ein Data Warehouse Restrukturierungsmassnahmen und erhöht wegen der geringen Komplexität der Systemarchitektur die Flexibilität. Aus allgemeiner Unternehmenssicht ermöglicht der Einsatz eines Data Warehouse dem Unternehmen eine Verbesserung der Kundenbeziehungen. Durch die Erstellung von Kauf- und Kundenprofilen kann der Anbieter individuell auf die Kundenpräferenzen eingehen (z.B. mit Sonderangeboten). Ein Data Warehouse steigert ferner die Effizienz eines Unternehmens und hilft, Implementierungs- und Wartungskosten eines Data Warehouse zu kontrollieren. [http://www.diko-project.de/dokumente/ausarbeitungen/stuehrenberg.pdf] 159 Woher kommt der Ansatz? Entscheidungsfindung bei Geschäftsvorgängen: DSS (Decision Support System) Interaktive Verbindung von Regeln sowie Intuition von Experten Ziele: ad hoc Modellierung jeweils neuer Situationen Simulation eines Ausschnitts der realen Welt Ein DSS (Decision Support System) soll bei der Entscheidungsfindung bei Geschäftsvorgängen unterstützen. Deshalb soll ein DSS Regeln sowie die Intuition des Experten interaktiv verbinden. Das Ziel ist dabei die ad hoc Modellierung jeweils neuer Situationen inklusive der Simulation eines Ausschnittes der realen Welt. Seit dem Ende der 60er Jahre wird versucht, Unterstützungshilfen für das Management zu entwickeln. Ein erster Schritt waren die MIS, die dazu dienen sollten, Managern die Informationen aus verschiedenen Transaktionssystemen zur Verfügung zu stellen. Das Fehlen jeglicher Unterstützung durch Modelle und Methoden sowie die einfache Aufbereitung der Informationen in Berichte führte zur Ablehnung der Systeme und zur Entwicklung von Decision Support Systemen (DSS). Diese sollten Unterstützung bei schlecht strukturierten Problemen bieten, sind aber für ungeübte Benutzer wie das TopManagement schwer zu bedienen. Nachfolger: EIS und ESS, Executive Information System / Executive Support System [http://lwi2.wiwi.uni-frankfurt.de/mitarbeiter/paulzen/Diplomarbeit_Paulzen.pdf] Mögliche Aus- und Aufgaben eines DSS sind z.B.: Management Information System Standard Reports, Sales Forcast usw. Testen von Hypothesen Modellierung Erzeugung eines Modells und Validierung an Hand der historischen Daten Erkennung unbekannter Trends Wie ist der Zusammenhang zwischen Datenbanken und DSS zu sehen? Grundlage des DSS ist eine Datenbank - DataWareHouse - mit folgenden Eigenschaften: Das DataWareHouse fasst die Daten themenorientiert zusammen. Transaktionen wie im OLTP (on line transaction processing) sind dabei nicht von Interesse. Ein DSS stellt an das DataWareHouse in der Regel nur lesende Fragen, die Zugriffe sind also ReadOnly. Aus diesen Gründen können die Daten, die typischerweise aus einem transaktionsorientierten OLTP-System kommen, während der Ruhephasen des OLTPSystems bereitgestellt werden. Eine Vorverdichtung ist dabei üblich, da von einer Reihe von Detail-Informationen abstrahiert werden kann. Zudem reduziert eine Vorverdichtung den Aufwand bei Anfragen an das System. Aus diesem Grunde werden in der Regel stark denormalisierte Daten eingesetzt, d.h. anstelle der "schlanken" Tabellen im OLTP werden im DataWareHouse "fette" Tabellen mit vielen redundanten Spalten gespeichert; Joins werden vorab vollzogen, damit bei den Anfragen die Performance nicht leidet. 160 DSS benötigt Datenbasis Datenbasis muss flexibel und bei OLAP-Anforderungen (OnLine Analytical Processing) online zur Verfügung stehen: Datenbank (Data Warehouse) mit folgenden Eigenschaften: themenorientierte Zusammenfassung von Daten lesende Anfragen Verarbeitung großer Datenvolumina pro Anfrage regelmäßiges Update durch Daten aus dem OLTP-System (OnLine Transaction Processing), das die aktuellen Geschäftsvorgänge unterstützt Administrationssysteme, auch operative Systeme oder Transaktionssysteme genannt, dienen der Abbildung der Prozesse der betrieblichen Leistungserstellung und sollen Routineaufgaben rationalisieren. Transaktionssysteme, die interaktiv und mit schnellen Antwortzeiten arbeiten, werden auch als On-Line Transaction Processing (OLTP)-Systeme bezeichnet. ... Ein weiteres Kennzeichen von OLTP-Systemen ist das regelmäßige Überschreiben von Datensätzen im Falle von Änderungen. Aus Performance- und Speicherplatzgründen wird darauf verzichtet, bei jeder Änderung oder Löschung von Datensätzen neue Sätze anzulegen und die alten Sätze entsprechend zu kennzeichnen. Um Geschäftsentwicklungen genau nachvollziehen zu können, werden alte Sätze in der DW-Datenbasis dagegen nicht geändert, sondern dieser mit den Zeitstempeln versehen dauerhaft hinzugefügt. Während OLTP-Systeme bei gleichen Auswertungen zu verschiedenen Zeitpunkten auch zu unterschiedlichen Ergebnissen kommen können, ist dies bei DW-Systemen nicht mehr möglich. Außer bei fehlerhaften Daten werden also keine Updates im DW-System durchgeführt. ... Zugriffe in OLTP-Systemen unterscheiden sich deutlich von Zugriffen in DW-Systemen: während im Transaktionsbereich Abfragen regelmäßig gestartet werden und nur einen geringen Teil des Datenbestands durchlaufen, sind Auswertungen des Managements meist unvorhersehbar und komplex. Das DBS muss daher Zugriffe auf die Datenbasis optimieren können, indem z.B. häufig angeforderte Daten direkt vorgehalten werden.... [http://lwi2.wiwi.uni-frankfurt.de/mitarbeiter/paulzen/Diplomarbeit_Paulzen.pdf] OLAP vs. OLTP Bei der Feinabstimmung einer Datenbank ist zuerst der Einsatzzweck der Datenbank zu bestimmen. Eine Datenbank für Online-Analysen (OLAP - Online Analytical Processing) ist ein System, das dem Endbenutzer Abfragemöglichkeiten für statistische und allgemeine Informationen liefern soll. In derartigen Umgebungen werden oft Daten für statistische Berichte abgerufen und im Entscheidungsprozeß eines Unternehmens herangezogen. Daher spricht man auch von Systemen zur Entscheidungsunterstützung (DSS - Decision Support Systems). Eine Datenbank für die Online-Transaktionsverarbeitung (OLTP - Online Transactional Processing) stellt in erster Linie die Umgebung für die Eingaben von Endbenutzern bereit und kann gegebenenfalls Abfragen bezüglich aktueller Informationen realisieren. OLTPSysteme werden für die Manipulation der Datenbankinformationen auf täglicher Basis eingesetzt. Data Warehouses und Systeme zur Entscheidungsunterstützung erhalten ihre Daten aus OLTP-Datenbanken und manchmal von anderen OLAP-Systemen. 161 http://www.mut.de/media_remote/buecher/SQL/data/kap15.htm Die Struktur des DataWareHouse basiert auf der Struktur, die für das Informationssystem entwickelt wurde, unterscheidet sich aber dennoch deutlich davon, da die DataWareHouseStruktur performance-orientiert hinsichtlich lesender Anfragen ist. aus Sicht der Informatik werden folgende Problemstellungen angesprochen was unterscheidet ein Data Warehouse von einem OLTP spezielle Datenstrukturen, Komprimierung relationale DBMS - Spezialsysteme nicht behandelt werden wirtschaftliche Aspekte Problematik historischer Daten Vergleich OLTP - Data Warehouse OLTP Data Warehouse Tabellengröße klein groß Zeilen pro Tabelle wenig viel Umfang/Dauer Transaktion gering/kurz groß/sehr lang Anzahl Benutzer online sehr hoch nur wenige Anzahl Updates sehr hoch nahezu keine Full Table Scan selten häufig historische Daten wenig fast ausschießlich Normalisierungsgrad hoch stark denormalisiert 162 [http://www.thepulex.de/datawarehouseburkhardt.pdf] Nach [CD97] basieren OLTP-Systeme auf strukturierten, oft wiederholten Tasks mit kurzen, atomaren, isolierten Transaktionen. Diese Transaktionen benötigte detaillierte Daten auf dem neuesten Stand. Sie lesen oder ändern wenige (Dutzend) Datensätze, der Zugriff erfolgt typischerweise über den Primärschlüssel. Operationale Datenbanken tendieren zu Größenordnungen von Hunderten von Megabyte bis in den Gigabytebereich hinein. Das Hauptaugenmerk liegt auf einer guten ThroughputPerformance. Konsequenterweise widerspiegelt die das Datenbankdesign die operationale Semantik dieser auf der Datenbank arbeitenden Applikationen. Data Warehouse-Systeme dagegen sind entscheidungsunterstützende Systeme. Die hier benötigten Daten sollen nicht möglichst detailliert sein, sondern eine Zeit- und Gesamtübersicht ermöglichen. Da Data Warehouses viele Daten (aus verschiedenen Datenbanken) enthalten, sind sie größer als operationale Datenbanken, zu entwickelnde Systeme sind in Größenordnungen von Terrabyte projektiert. Die Arbeitslast besteht größtenteils aus ad-hoc-Queries, komplexe Queries, die auf Millionen von Datensätzen zugreifen. Query-Throughput und Antwortzeit sind hier wichtiger als Transaktions-Throughput. [http://dbs.uni-leipzig.de/seminararbeiten/semSS98/arbeit6/anfrage.html] 163 Generelle Struktur Entwurf eines Data Warehouse Was soll dargestellt werden? Welche Datenquellen? Transformation - wie? Datenqualität? Datenstrukturen Data Marts 164 Betrieb eines Data Warehouse Starten der Prozesse zur Datenextraktion Performance-Überwachung Erstellung von Data Marts 165 Was ist eine Data Mart? - eine Teilmenge des Data Warehouse inhaltliche Beschränkung auf bestimmten Themenkomplex oder Geschäftsbereich führt zu verteilter DW-Lösung Gründe für Data Marts • - Performance: schnellere Anfragen, weniger Benutzer, Lastverteilung • - Eigenständigkeit, Datenschutz • - ggf. schnellere Realisierung Probleme • - zusätzliche Redundanz • - zusätzlicher Transformationsaufwand • - erhöhte Konsistenzprobleme http://www.thepulex.de/datawarehouseburkhardt.pdf Um bei den zu erwartenden großen Datenmengen pro (lesender) Transaktion eine angemessene Performance zu erreichen: De-Normalisierung (Redundanz!) der OLTP-Datenbank o Pre-Join mehrerer Tabellen Ziel ist es, die Join-Operationen weitgehend zu vermeinden führt zu STAR- oder SNOWFLAKE-Schema o Pre-Aggregation bereits werden des Ladens werden auf unterschiedlichen Stufen Aggregate gebildet anstelle einer kontinuierlichen Änderung periodisches Update mittels Batch ...Erweiterte relationale Datenbanksysteme (Objekt-realtionale DB) eignen sich ebenfalls zur Unterstützung der multidimensionalen Datenmodellierung. Diese wird in allen relationalen DBS mit Star-, Snowflake oder gemischten Schemata über eine gezielte Denormalisierung realisiert. In erweiterten relationalen DBS kann die Behandlung solcher Strukturen automatisiert und um Auswertungsroutinen ergänzt werden. Die Trennung zwischen Datenbasis und Auswertungswerkzeugen wird hierdurch allerdings aufgehoben. ... [http://lwi2.wiwi.uni-frankfurt.de/mitarbeiter/paulzen/Diplomarbeit_Paulzen.pdf] Typische Methoden beim Einsatz eines RDBMS Pre-Join mehrerer Tabellen (Fact Table in STAR Schema): Ausgangspunkt ist dabei die normalisierte online DB. Pre-Aggregation: bereits während des Ladens werden auf unterschiedlichen Stufen Aggregate gebildet und gespeichert. Derart verdichtete Daten lassen sich jedoch in der Regel nur mit großem Aufwand wieder in die Detail-Information zerlegen. Periodisches Update mittels Batch. 166 Laden eines DataWareHouse In der Regel wird sich ein DataWareHouse in zwei Zuständen befinden: es wird geladen, danach wird mit ReadOnly auf die Daten zugegriffen. Folgende Methoden bieten sich zum Laden an: Log sniffing Update-, Insert-, Delete-Trigger Snapshot Logs (Replikate) Data Extract Programs (während der "off"-Zeiten des OLTP) ...siehe letzte Überschrift des Kapitel DW Ueberlegungen hinsichtlich der Einführung von Redundanz Zwei Faktoren sind dabei zu betrachten: die Größe der Daten sowie die Änderungshäufigkeit. Die Größe der Daten beeinflusst die Menge des Speicherplatzes und somit der Plattenkosten. Die Änderungshäufigkeit beeinflusst im Wesentlichen CPU und IOZeit. Somit läßt sich Redundanz in einem Data Warehouse nur in einem gewissen Bereich sinnvoll einsetzen, wie die grüne Fläche in der folgenden Abbildung nahe legen soll: STAR-Schema Unter einem STAR-Schema versteht man eine aus normalisierten Tabellen mittels Join gewonnene Fakt-Tabelle, die neben den Schlüsseln weitgehende Information enthält. Als Indexe (Dimensionen) bleiben darum herum angeordnet die Schlüssel (ggf. mit zusätzlicher Information) der Kern-Entities. Die folgende Abbildung soll dies anhand eines in der Veranstaltung besprochenen Beispiels verdeutlichen: 167 Fakt-Tabelle ist aus den normalisierten Tabellen mittels Join gewonnen. Enthält neben den Schlüsseln weitgehend sämtliche Information Schlüssel werden als Indexe (Dimensionen) verwendet (ggf. mit zusätzlicher Information) Das Star-Schema ist ein relationales Datenmodell. In diesem Modell werden zwei Tabellen implementiert: Einerseits die Faktentabelle, welche Daten enthält, die aus den verschiedenen Vorgängen und Abfragen im System entstehen und sich über die Zeit ändern, andererseits die Dimensionstabelle, welche über die Zeit relativ statisch ist und die grundlegenden Datensätze von verschiedenen Objekten im System enthalten. Die Faktentabelle enthält eine Anzahl an Fremdschlüsseln und bildet den eigenen Primärschlüssel aus der Zusammensetzung der Fremdschlüssel. Abbildung 3.6 zeigt ein Beispiel für ein Datenmodell nach dem Star-Schema. Die Tabellen Student, Instructor, Course, und Semester sind in diesem Beispiel Dimensionstabellen und die Tabelle Attendance bildet die Faktentabelle ab. Die Faktentabelle enthält alle Primärschlüssel der Dimensionstabellen und bildet daraus den eigenen Primärschlüssel, der in diesem Fall ein zusammengesetzter ist. Die Faktentabelle enthält im Vergleich zu den Dimensionstabellen viel mehr an Daten. 168 Der Nachteil dieses Schemas ist, dass nur die Faktentabellen hochnormalisiert sind und die Dimensionstabellen vollständig denormalisiert sind. Denormalisiert bedeutet, dass die Tabellen redundanzbehaftet sind. Die Nachteile, die sich daraus ergeben sind: Die Bildung von Aggregaten ist schwierig. Bei sehr großen Dimensionstabellen kann es bei häufiger Abfrage der Elemente von Hierarchieobjekten zu Einbußen des Antwortzeitverhaltens kommen. Änderungen des semantischen Datenmodells führen zu umfangreichen Reorganisationen der Tabellen im Data Warehouse. Redundante Einträge in den Dimensionstabellen. Das denormalisierte Schema birgt aber nicht nur Nachteile, sondern auch einige wesentliche Vorteile: Es ist ein einfaches, intuitives Datenmodell. Es benötigt nur eine geringe Anzahl an RDBMS-join-Operationen. Es benötigt nur eine geringe Anzahl an physikalischen Tabellen im Data Warehouse. Der Wartungsaufwand des Data Warehouse' ist relativ gering. Aufgrund des intuitiven Datamodells können die Metadaten sehr einfach definiert werden. [http://www.iicm.edu/wrichter/thesis-final/node44.html] SNOWFLAKE-Schema: Verbindung mehrerer unterschiedlich thematisierter STAR-Schemata Snowflake-Schema: Normalisierung der Dimensionstabellen • - leicht geringere Redundanz, geringerer Änderungsaufwand • - höhere strukturellere Komplexität (mehr Tabellen) • - erhöhte Zugriffskosten (höherer Join-Aufwand) 169 http://www.thepulex.de/datawarehouseburkhardt.pdf Das Snowflake-Schema ist dem Star-Schema ähnlich. In diesem Schema werden die Dimensionstabellen normalisiert. Dadurch wird Speicherplatz gespart. Der große Speicherplatzverbrauch der Faktentabellen beim Star-Schema wird hier durch die Normalisierung vermieden. Abbildung 3.7 zeigt ein Datenmodell nach dem SnowflakeSchema. Die Tabelle Student ist normalisiert und enthält Fremdschlüssel zur Tabelle Major und zur Tabelle Minor. Die Beziehung zwischen der Tabelle Student und Major ist manyto-one. Wenn die Beziehung many-to-many wäre, würde das eine Kette an Tabellen für die Dimensionstabellen nach sich ziehen. Das macht dieses Datenmodell 170 schwieriger zu verstehen für den User und erschwert auch die Verwendung. Andererseits erhöht das Snowflake-Schema die Browsing-Funktionalität [http://www.iicm.edu/wrichter/thesis-final/node45.html] Multidimensionale Datenbanken (typisch unter Einbeziehung der Zeit) spezielle Architektur MOLAP (Multidimensional OnLine Analytical Processing) konventionelles RDBMS mit Aufsatz ROLAP (Relational Online Analytical Processing) MOLAP: multidimensionale DBS ROLAP: relationales DBS Eine Umsetzungsmöglichkeit des multidimensionalen Datenmodells ist dessen Abbildung auf das relationale Datenmodell des Datenbanksystems. Eine Alternative wäre die direkte multidimensionale Datenspeicherung. Beide Möglichkeiten sind in kommerziellen OLAP-Produkten unterschiedlich realisiert. So gibt es einerseits das etablierte ROLAP (relationale OLAP) mit komplexen SQL-Anweisungen und das jüngere MOLAP (multidimensionale OLAP) mit einer einfacheren Anfrageformulierung. Im Vergleich zu OLAP analysiert ROLAP die Daten ohne speziellen zwischengeschalteten Server und erzielt damit schnellere Anfragen [G96]. Ein ROLAP-System besteht aus einem relationalem Data Warehouse mit einer OLAPSchnittstelle. Ein MOLAP-System umfasst hingegen eine multidimensionale Datenbank mit direkt eingebauten OLAP-Funktionen.Während MOLAP zwar kurze Antwortzeiten bietet, ermöglicht ROLAP zusätzlich noch gute Skalierbarkeit und stellt einen offenen Standard dar. Da MOLAP-Systeme die Datenwürfel direkt auf den Speicher abbilden, sind alle möglichen Werte darstellbar. Durch ROLAP werden die Daten in Relationen gespeichert, wodurch nur vorhandene Werte abbildbar sind (vgl.[G96]). Sinnvoll ergänzen können sich beide Ansätze in einer kombinierten Architektur mit einem grossen, relational implementierten Data Warehouse und davon abhängigen, kleineren multidimensionalen Systemen. [http://www.diko-project.de/dokumente/ausarbeitungen/stuehrenberg.pdf] ... Serverarchitekturen Wie im letzten Abschnitt gezeigt, sind herkömmliche Datenbanksysteme nicht oder kaum in der Lage, multimensionale Sichten auf Daten zu unterstützen. Jedoch unternehmen viele Anbieter von Datenbanksystemen jetzt Anstrengungen, diese zusätzlichen Anforderungen zu erfüllen. Neben den traditionellen Datenbank-Servern kann man drei Kategorien von Servern unterscheiden, die speziell für entscheidungsunterstützende Systeme entwickelt werden: spezialisierte SQL-Server Ein Beispiel für diese Klasse Server ist Redbrick. Das Hauptaugenmerk hier liegt auf der Bereitstellung einer erweiterten Anfragesprache und der Unterstützung von SQL-Queries über Star- und Snowflake-Schematas. ROLAP-Server Data Warehouse-Systeme können auch auf standardisierten oder erweiterten 171 relationalen Datenbanksystem implementiert werden. In diesem Fall spricht man von relationalen OLAP-Servern (ROLAP). ROLAP-Server sind Zwischenserver zwischen relationalen Back-End-Servern (auf denen die Daten des Data Warehouse gespeichert sind) und Client-FrontEnd-Tools. Microstrategy ist ein Beispiel für diese Art von Servern. ROLAPServer erweitern herkömmliche relationale Server mit spezialisierter Zugriffsund Implementierungsmethoden sowie SQL-Erweiterungen für eine effiziente Unterstützung multidimensionaler OLAP-Queries. Die Stärke von ROLAP-Servern ist die Ausnutzung der Skalierbarkeit und der Transaktions-Eigenschaften relationaler Systeme. Allerdings können Unstimmigkeiten zwischen OLAP-Queries und SQL zu Flaschenhälsen hinsichtlich der Performance von OLAP-Servern werden. MOLAP-Server Multidimensionale OLAP-Server (MOLAP) unterstützen direkte die multidimensionale Sicht auf Daten durch eine multidimensionale Storage-Engine. Sie speichern Daten direkt in speziellen Datenstrukturen (z.B. Arrays) und implementieren OLAPOperationen über diesen speziellen Datenstrukturen. Dies ermöglicht die Implementierung multidimensionaler Front-End-Queries auf der Speicherschicht via Direkt-Mapping. Ein Beispiel für diese Art von Server ist Essbase (Arbor). Dieser Ansatz hat den Vorteil exzellenter Indexeigenschaften, nutzt jedoch den Speicher schlecht aus, speziell bei dünnen Datensätzen. Einige MOLAP-Server versuchen diesen Nachteil durch einen 2-Level-Speicherung zu umgehen und nutzen dabei Index-Strukturen und kleinere Arrays. Vergleich von ROLAP- und MOLAP-Architektur 172 http://dbs.uni-leipzig.de/seminararbeiten/semSS98/arbeit6/anfrage.html Multidimensionale Daten: Spezielle multidimensionale Datenbank-Architektur Vorteil: gute Performance speziell bei beliebigen Ausschnitten Nachteil: Skalierbarkeit 173 In Transaktionssystemen werden die Daten meist unter Zugrundelegung des Relationenmodells weitgehend normalisiert abgelegt. Diese Form der Datenmodellierung unterstützt die funktionsorientierten Applikationen und vermeidet Redundanzen. Kennzeichen der Denkweise des Managements ist jedoch die Betrachtung von verschiedenen Dimensionen. Aus diesem Grund sollten die Daten im DW-System multidimensional modelliert werden. Ziel dieser Modellierung ist es, dem Management durch eine höhere Verständlichkeit und intuitive Bedienbarkeit des Systems eine bessere Unterstützung bieten zu können. Zusätzlich werden Geschwindigkeitsvorteile erreicht, da die den Abfragen zugrunde liegenden Datenbankstrukturen dem Informationsbedarf des Managements angepasst sind. DBS in DW-Umgebungen sollten daher diese Form der Datenmodellierung unterstützen. Grundsätzlich geeignet sind hierzu sowohl relationale als auch multidimensionale DBS. Zu beachten ist hierbei, dass vor allem multidimensionale DBS über Verfahren zur Optimierung dünn besetzter Strukturen verfügen. ... Im Gegensatz zu relationalen Datenbanken werden keine zweidimensionalen Tabellen, sondern multidimensionale Würfel aufgebaut, in denen jedes Feld einzeln angesprochen werden kann. Alle DBS verfügen hier über Komprimierungsmechanismen, um zu verhindern, dass durch unbesetzte Felder das Datenvolumen unnötig erhöht wird. [http://lwi2.wiwi.uni-frankfurt.de/mitarbeiter/paulzen/Diplomarbeit_Paulzen.pdf] RDBMS mit Aufsatz Vorteil: o o Flexibilität wesentlich besser Skalierbarkeit wesentlich besser als bei MOLAP Nachteil: Performance hinsichtlich einiger Operationen kann teilweise ausgeglichen werden durch o entsprechenden Entwurf o DBMS-unterstützte Partitionierung o Mehrprozessor-Einsatz Anlegen und Laden eines Data Warehouses vom OLTP SQL-Anweisungen während off-Zeit des OLTP Snapshot Log sniffing 174 Insert-, Update-, Delete-Trigger spezielle Data Extract Programme während off-Zeit des OLTP [http://www.thepulex.de/datawarehouseburkhardt.pdf] SQL-Anweisungen während off-Zeit des OLTP können insbesondere dazu benutzt werden, Pre-Joins anzulegen Snapshot Überführung einer Tabelle in das Data Warehouse Ausnutzen von Replikation - Periodisches Kopieren des Datenbestandes in Datei - Vergleich von Snaphots zur Identifizierung von Änderungen [http://www.thepulex.de/datawarehouseburkhardt.pdf] Log sniffing mit Spezialprogramm die Logs auf Änderungen untersuchen und diese in das Data Warehouse einbringen - Analyse von Transaktions-Log-Dateien der DBMS zur Erkennung von Änderungen http://www.thepulex.de/datawarehouseburkhardt.pdf Insert-, Update-, Delete-Trigger direktes Übernehmen jeder Änderung - Auslösen von Triggern bei Datenänderungen und Kopieren der geänderten Tupel in andere Bereiche http://www.thepulex.de/datawarehouseburkhardt.pdf 175 spezielle Data Extract Programme während off-Zeit des OLTP dieses Vorgehen bietet die besten Möglichkeiten, vor dem Einfügen Daten zu aggregieren 176 10. Objekt-Relationale DBMS Was sind objekt-relationale Datenbanken ??? Relationale DBMS erweitert um einige OO-Features Bsp: Oracle, DB2 Wieso braucht man objekt-relationale Datenbanken ??? Relationale DBMS halten neuen Anforderungen nicht Stand Anbieter relationale DBMS haben Marktanteil von ca. 98 % und den wollen sie halten! reine OO-DBMS haben eine schlechte Performance Bsp: GemStone, ONTOS Was ist so toll an objekt-relationalen DBMS ??? sind robust wie relationale DB und flexibel wie objektorientierte Datenbanken keine Schwierigkeiten bei Datenübernahme aus relationalen DB 1:1-Mapping von EER-Modell auf objekt-relationale DB Wie wird das umgesetzt ??? Einführung des neuen Standards SQL:1999 [http://www.dbis.informatik.uni-frankfurt.de/TEACHING/DBSeminar/2002_SS/Folien/FolienORDB.pdf] Bei der Entwicklung objektorientierter Datenbanksysteme waren von Anfang an zwei Linien erkennbar. Die Vertreter der einen Linie waren der Ansicht, dass man objektorientierte Datenbanken völlig neu entwickeln müsse, um eine adäquate Technik zu schaffen, die das objektorientierte Paradigma möglichst effektiv realisiert. Die bisherige Datenbanktechnologie hielten sie für unbrauchbar, weil diese auf einer völlig anderen theoretischen Grundlage entstanden ist. Dagegen argumentierten die Vertreter der anderen Linie, dass die Entwicklung der relationalen Datenbanktechnologie bis zum heutigen Reifegrad Millionen von Entwicklungsstunden gekostet habe, die man nicht einfach auf den Müllhaufen der Geschichte werfen sollte. Aus diesen Erwägungen ergab sich der Ansatz, vorhandene relationale Datenbanksysteme um objektorientierte Konzepte zu erweitern, ohne das relationale Datenmodell damit aufzugeben. Dieser Ansatz wird "objektrelational" genannt. Er hat in den SQL-Standard Einzug gehalten und wird von etablierten Anbietern relationaler DBMS vorangetrieben. [Matthiessen,Unterstein;Relationale Datenbanken und SQL;284] 177 oder nach Balzert: Objekt-relationale Datenbanksystem verfolgen das Ziel, die besten Ideen aus der relationalen und der objektorientierten Welt zu verbinden. Das grundlegende Konzept bleibt weiterhin die Tabelle. Es wird um objektorientierte Konzepte wie Abstrakte Datentypen, Objektidentität, Operationen und Vererbung erweitert. OO-Methoden der Software-Entwicklung wirken sich auf Anforderungen an DBMS aus. OODB-Manifesto: notwendige Anforderungen o o o o o o o o o o o o komplexe Objekte Objekt-Identität, die gespeicherte Objekte von Werten, die sie besitzen unterscheiden kann, Kapselung Typen und Klassen Typen- und Klassenhierarchie Overriding, Polymorphie, Overloading, Late Binding Berechnungsvollständige Datenbankprogrammiersprache Erweiterbarkeit Persistenz Sekundärspeicherverwaltung Synchronisation und Recovery von Transaktionen Anfragesprachen optionale Anforderungen o o o o o Mehrfachvererbung statische Typisierung und Typ-Inferenz Verteilung Entwurfstransaktionen Versionen Grundbausteine: Basiselemente des objektorientierten Datenbankmodells sind Objekte und Literale. Jedes Objekt hat eine eindeutige Identität. Ein Objekt kann grundsätzlich im Laufe seiner Existenz seinen Zustand ändern. Ein Literal hat keine Identität; es hat auch keinen änderbaren Zustand, sondern beschreibt einen Wert. So ist ein Mitarbeiter oder ein Artikel ein Objekt; eine Zahl, eine Zeichenkette oder eine feste Uhrzeit ist ein Literal. Objekte und Literale werden durch Typen kategorisiert. Alle Elemente eines gegebenen Typs haben dieselbe Menge an abstrakten Eigenschaften (Attribute) und dasselbe Verhalten. Ein Objekt wird als Instanz seines Typs bezeichnet. Der Zustand eines Objekts wird durch die Werte beschrieben, die seine Eigenschaften aufweisen, und durch die Beziehungen, die es zu anderen Objekten hat. Das Verhalten eines Objekts wird durch die Menge an Operationen beschrieben, die das Objekt ausführen kann. ... Eine Operation kann ein typisiertes Ergebnis zurückgeben. Eine objektorientierte Datenbank speichert Objekte. Sie basiert auf einem Schema und enthält Instanzen, die auf den im Schema definierten Typen basieren. ... [Matthiessen,Unterstein;Relationale Datenbanken und SQL;285] 178 Zwei Ansätze: Erweiterung der RDBMS Neuentwicklung von OODBMS Erweiterung von RDBMS Komplex strukturierte Typen, Typkonstruktoren Objekt-Identifikation und Referenzen Spezialisierung, sowohl auf Objektebene als auch auf Klassenebene Typen können von Benutzern definiert werden. Ausgehend von primitiven Datentypen (wie numerischen Datentypen, Zeichenketten, logischen Werten, Datum, Uhrzeit, Aufzählungstypen) können durch Konstruktoren orthogonal neue Datentypen zusammengesetzt werden. Einen Datentyp, der aus mehreren Komponenten (unterschiedlicher) Datentypen zusammengesetzt ist, erhalten wir durch den STRUCTKonstruktor. [Matthiessen,Unterstein;Relationale Datenbanken und SQL;286] Beispiel Oracle 8 komplexe Typen Referenzen SQL3-Standard: baut auf SQL92 auf Erweiterung hinsichtlich ODBMS: o Konzept benutzerdefinierter abstrakter Datentypen (ADT) Funktionen der ADT werden analog zu Methoden durch das DBMS verwaltet o Tapeltypen (row) o auf ADT ist Subtypkonzept mit Vererbung realisiert Redefinition von Attributen und Funktionen ist erlaubt o Typkonstruktoren list, set, multiset nicht-atomare Wertebereiche für Attribute, können zusammen mit row verwendet werden o Identifikatoren können für Tupel vergeben werden und können als Referenzen verwendet werden SQL3 umfasst somit strukturelle vorhergehenden SQL-Versionen Konzepte von ODBMS bei Kompatibilität zu Einordnung von Oracle8 keine Vererbungshierarchie Beschränkung auf einen Kollektionstyp (Tabelle) Objekt-Views 179 Komplexe Datentypen - Objekttypen User-Defined Datatypes (UDT): Object Types Collection Types Object Types - Objekttypen bestehen aus Namen des Typs Attributmenge Methoden Object Types - Vereinbarung: create type Typ_Adresse as object ( Strasse varchar2(30), Nummer integer, Zusatz varchar2(3), PLZ integer, Ort varchar2(30) ); Typ_Adresse kann z.B. durchgängig in den DBs der FH für die Speicherung von Adressen verwendet werden Prinzip der Wiederverwendung Hinzufügen oder Modifizieren von Attributen impliziert ausschließlich Änderungen an der Objektdefinition Object-Types können in weiteren Objekttypen als Wertebereich eingesetzt werden: create type Typ_Student as object ( Nachname varchar2(40), Vorname varchar2(40), Matrikelnr varchar2(7), Adresse Typ_Adresse ); zyklischer Verweis durch ref-Attribute. Zur Auflösung durch DDL-Compiler ist Forward-Deklaration nötig: create type Typ_XXX; 180 Object Types in Tabellen als Objekttabellen als Attributbereiche Objekttabellen create table T_Student of Typ_Student ( Matrikelnr primary key); Attributbereiche create table T_Student_Heimat ( Matrikelnr varchar2(7), Anschrift T_Anschrift, Matrikelnr primary key); Einfügen: insert into T_Student_Heimat values ('1234567', Typ_Adresse('Strasse', 5, '', 47110, 'Irgendwo') ); Konstruktormethoden werden nicht explizit definiert, vielmehr automatisch bei Anlegen eines neuen Objekttyps erzeugt Zugriff durch Punkt-Operator select T.Matrikelnr, T.Adresse.Ort from T_Student_Heimat T where T.Adresse.PLZ between 40000 and 41200; … Verwendung Abstrakter Datentypen bei der Einrichtung eines komplexen Objekttyps ... Es wird ein Objekttyp erzeugt, der dann als Basis für eine Objekttabelle dient. CREATE OR REPLACE TYPE otyp_kunde AS OBJECT ( kunden_nr otyp_kunden_key, status varchar2(1), name varchar2(30), telefonliste varr_telefonliste, adresse otyp_adresse, letzte_bestellung date, letzte_werbeaktion date, zahlungsart char(1); Wir benutzen hier die ADTs als Typangabe für die Attribute kunden_nr, telefonliste, adresse. ... Dir Struktur des Objekttyps otyp_kunde ist nun definiert. Hätten wir Methoden mit angegeben, so müssten diese anschließend implementiert werden. Um den Typ zu instanziieren, benötigen wir 181 einen Behälter (Extent), der die Objekte aufnehmen kann. Hier liegt der wesentliche Unterschied zwischen objektorientierten und objektrelationalen Datenbanken: Der Behälter für Objekttypen ist eine Tabelle. Die CREATE TABLE-Anweisung kommt in neuer Form daher, um solche typisierte Tabellen zu erstellen: CREATE TABLE otab_kunde OF otyp_kunde ( status NOT NULL, CONSTRAINT chk_status CHECK (status IN ('S', 'W' ,'G')), adresse NOT NULL, zahlungsart NOT NULL, CONSTRAINT chk_zahlart CHECK (zahlungsart IN ('R', 'B', 'N', 'V', 'K'))) Hier werden Integritätsbedingungen formuliert. Sie werden nicht auf der Ebene der Typdefinition festgelegt, sondern auf der Ebene der Definition der Extents. (Wir halten es für einen Mangel des objektorientierten Datenmodells, dass Integritätsbedingungen nicht deklarativ auf Typebene formuliert werden können. Reine objektorientierte DBMS erlauben dies nicht einmal auf Ebene eines Extents. Es müssen dafür jeweils Methoden definiert werden, die beim Einfügen oder Ändern einer Objektinstanz die Einhaltung von Bedingungen überprüfen. Eine recht umständliche Angelegenheit! Darüber hinaus ist das Redefinieren eines Typkonstruktors vielfach bei OODBMS nicht möglich – im objektrelationalen Modell ebenfalls nicht.) Das führt zu einem Konflikt. Legen wir bei der Kundennummer Wert darauf, dass sie die Fähigkeit hat, selbst fortlaufende Nummern zu erzeugen und nicht mit Artikelnummern vergleichbar zu sein, oder legen wir Wert darauf, dass die Primärschlüsseleigenschaft festgehalten wird? Letztere brauch wir zwar in objektorientierten Datenbanken nicht wegen der Entitätsintegrität – die OID ist ein besserer Ersatz für den Primärschlüssel. Als Anwender wollen wir aber vielleicht doch nicht auf die identifizierende Funktion der Kundennummer verzichten. Beides zugleich geht jedenfalls nicht so ohne weiteres. Die PRIMARY KEY-Klausel ist zwar für Objekttabellen erlaubt, aber nicht für Attribute, deren Basis ein ADT ist! Also haben wir wohl oder übel als Wertebereich für Kunden_nr den Standardtyp Number (4,0) einzusetzen und können dann die Anweisung CREATE TABLE otab_kunde um die Klausel CONSTRAINT pk_kunde PRIMARY KEY (kunden_nr) ergänzen. Die Verwendung von ADTs als Wertebereich für Attribute erfordert Sorgfalt im Hinblick auf die Verarbeitung ihrer Werte. Wir können beim Einfügen eines Kunden-Tupels in die neue Tabelle nicht einfach drei Strings als Adresse übergeben, sondern müssen als Attributwert ein Objekt vom Typ otyp_adresse konstruieren und dieses komplett verarbeiten. Gleiches gilt für die Telefonliste. INSERT INTO otab_kunde (kunden_nr, name, telefonliste, letzte_bestellung, letzte_werbeaktion, status, zahlungsart) adresse, VALUES (100, 'Voss, Hans', varr_telefonliste ('04335-3499', '0170-3456890'), otyp_adresse ('Kuhdamm 12', '23863', 'Nienwohld'), NULL; TO_DATE ('01-12-1999', 'DD-MM-YYYY'), 'S', 'N') ...Einrichtung einer eigenen Tabelle für die Mehrwertsteuersätze: Diese Sätze ändern sich nicht sehr häufig und kommen immer wieder bei jedem Verkauf eines Artikels zur Anwendung. Aus demselben Grund ist auch die Einrichtung einer eigenen Objekttabelle für die Mehrwertsteuer im objektrelationalen Modell sinnvoll. Wir zeigen an dieser Variante einer Typdefinition die Möglichkeit, eine eigene Methode für die Sortierung einzurichten. Außerdem enthält dieses Beispiel eine Methode für die Anzeige des Prozentsatzes. Letztere brauchen wir eigentlich in diesem Falle nicht, da die Attribute einer Objekttabelle nicht gekapselt sind. Wir würden sie aber benötigen, wenn dies nicht der Fall wäre. CREATE OR REPLACE TYPE otyp_mwstsatz AS OBJECT ( mwst integer, prozent number (3,3), beschreibung varchar2(10), -- Mit der MAP-Funktion wird eine Sortierung ermöglicht 182 MAP MEMBER FUNCTION mwst_order RETURN REAL, PRAGMA RESTRICT_REFERENCES (mwst_order, RNDS, WNDS, RNPS, WNPS), MEMBER FUNCION zeige_prozent RETURN REAL, PRAGMA RESTRICT_REFERENCES (zeige_prozent, WNDS, WNPS) ); Die Implementation der Methoden erfolgt separat. CREATE OR REPLACE TYPE BODY otyp_mwstsatz AS MAP MEMBER FUNCION mwst_order RETURN REAL IS BEGIN RETURN prozent; -- Unqualified attributes refer to the "self" object. END mwst_order; MEMBER FUNCTION zeige_prozent RETURN REAL IS BEGIN RETURN self.prozent; END zeige_prozent; END; Die MAP-Funktion bildet ein Objekt vom Typ otyp_mwstsatz auf eine Zahl ab. Die Abbildungsvorschrift wird mit der Implementation festgelegt. Wir haben hier einfach den Prozentsatz genommen. Es könnte aber jeder beliebige numerische Ausdruck sein, der sich beispielsweise bei einer geometrischen Figur aus einer mehr oder weniger komplizierten Flächenberechnung ergäbe. Die Definition dieser Methode eröffnet uns die Möglichkeit, bei der Ausgabe der Tupel mit der ORDER BY VALUE-Klausel eine Standardsortierung anzufordern. SELECT * FROM otab_mwstsatz m ORDER BY VALUE (m); Die Angabe PRAGMA RESTRICT_REFERENCES (mwst_order, RNDS, WNDS, RNPS, WNPS), ist eine "Compiler-Direktive". Sie ist notwendig, um "Seiteneffekte" zu kontrollieren und besagt, dass weder Datenbankzustände gelesen oder verändert werden noch Prozedurvariablen. ... Der Bezeichner self zeigt zur Laufzeit auf das Objekt (Exemplar), bei dessen Bearbeitung die Methode aufgerufen wurde. In der Objekttabelle können wir nun Tupel auf die gewohnte Art einfügen, z.B.: INSERT INTO otab_mwstsatz VALUES (2,.07,'halbe') [Matthiessen, Unterstein; Relationale Datenbanken und SQL] Methoden für Objekttypen create type Typ_Student_FH as object ( student Typ_Student, member function semester return number, pragma RESTRICT_REFERENCES (semester, WNDS) ); lediglich Typ-Definition der Methode Implementierung erfolgt unabhängig unter Ausnutzung von PL/SQL pragma RESTRICT_REFERENCES dient zum Kontrollieren der Seiteneffekte: Referenzen auf Tabellen und Package-Variablen create type body Typ_Student_FH as member function semester return number is maxsem number; begin select max(semester) into maxsem from T_Belegung; 183 return (maxsem); end; end; vorausgesetzt, T_Belegung ist eine geeignete Sicht auf die Fächerbelegung für den jeweiligen Studenten Anforderung an Methoden: die pragma-Anweisung beschränkt die Referenzen auf Tabellen und PackageVariablen damit werden die Seiteneffekte der Methoden eingeschränkt Einsatz von Methoden select T.Student.Name, T_Student_FH.semester() from T_Student_FH where T.Student.Matrkelnr = 47110 Get- und Set-Methoden bei echter Kapselung würden diese Methoden benötigt, jedoch unterstützt Oracle8 dies noch nicht Vergleichsmethoden damit Oracle auf Gleichheit/Ungleichheit testen kann, müssen entsprechende Funktionen bereitgestellt werden dazu gibt es zwei Arten der Festlegung: map member function Vergleichswert return number; order member function Ordnung(x in Typ_...) return integer; Die Map-Methode erzeugt für ein Objekt einen Datenwert, der zur Sortierung verwendet werden kann Die Order-Methode vergleicht zwei Objekte und liefert für o < einen negativen Wert o = den Wert 0 o > einen positiven Wert mögliche Implementationen map member function Vergleichswert return number is begin return Matrikelnr; end; order member function Ordnung( x in Typ_Student_FH ) return integer is 184 begin return Matrikelnr - x.Matrikelnr; end; Kollektionstypen arrays nested tables Kollektionstypen: Arrays create type Werte_array as varray(anzahl) of number; Kollektionstypen: Nested Tables create type Typ_Adressen_Tabelle as table of Typ_Adresse; create table T_Student_Neu ( PK_Matrikelnr varchar2( 7) primary key, Name varchar2(40), Adressen Typ_Adressen_Tabelle) nested table Adressen store as Studenten_Adressen_Liste; Anzahl mit count abfragbar, kann dann in for benutzt werden Realisierung: zwei Tabellen, verbunden über system-generierte ID Einfügen durch "Entschachtelung": insert into the ( select Adressen from T_Studenten_Neu where PK_Matrikelnr = ... ) values (...) /* Hier stehen die Werte der Adresse */ Selektieren mittels Cursor: select T.PK_Matrikelnr, T.Name, cursor ( select * from table (T.Adressen) ) from T_Studenten_Neu T; Referenzen Konzept der Objektidentifikation: Datentyp ref als Referenz auf Row-Objekte noch ausstehend: Objektidentität vollständige Kapselung 185 Vererbung noch ausstehend auf dem Wege zur Objektorientierung: - Objektidentität vollständige Kapselung Verebung 186 11. Objekt-orientierte DBMS Der ursprüngliche Ansatz bei DBMS-Systemen zielt auf die Trennung von Programmen und Daten - im Gegensatz zum Dateisystem, bei dem Programme und Daten miteinander verquickt sind. Die Entwicklung hat sich insbesondere auf die folgenden Bereiche konzentriert: Datenmodelle: diese stellen Konzepte zur Abstraktion der abzubildenden Welt her, modellieren Struktur und Semantik der Daten. DB-Sprachen: DB-Sprachen stellen im Vergleich zu höheren Programmiersprachen nur eine eingeschränkte Manipulationsfähigkeit zur Verfügung - so fehlt z.B. bei SQL ein Schleifenkonstrukt. Andererseits besitzen diese Sprachen zum Teil andere und für die Datenselektion günstigere Eigenschaften als prozedurale Programmiersprachen - es wird nicht beschrieben, wie die Daten zu finden sind, sondern welche Eigenschaften die Daten haben sollen. Transaktion und Mehrbenutzerfähigkeit: Benutzer sollen "parallel" auf die Datenbestände zugreifen können. Dafür müssen Synchronisationsverfahren, Sicherungskonzepte und Wiederanlaufstrategien bereitgestellt werden. DB-Systeme setzen hierfür das Transaktionskonzept ein. Datenstrukturen: Datenstrukturen und Zugriffsverfahren sind für einen effizienten Zugriff wichtig. Im wesentlichen stellten kommerzielle Anwendungen die Anforderungen an ein DBMS, die folgendermaßen beschrieben werden können: einfache, fest-formatierte Datensätze, einfache Datentypen, weitgehend vorformulierbare Anfragen, In-Place-Updates, kurze Transaktionen bei hohen Transaktionsraten. Diese Anforderungen werden weitgehend durch heutige relationale Systeme abgedeckt. 187 Durch den vermehrten Einsatz von Anwendungen im wissenschaftlich-technischen Bereich z.B. CAD, Büro-Informationssysteme, GIS, Multimedia-Systeme usw. - die ebenfalls DBMSUnterstützung verlangen, verschieben sich die Anforderungen: Modellierung komplexer Objekte und Datentypen, ggf. Modellierung von Verhalten, d.h. objekt-spezifische Methoden, die durch das Datenmodell beschreibbar sind. So zeigt z.B. der Versuch, Werkzeug-Roboter mit mehreren Greifarmen usw. mittels relationaler Techniken zu beschreiben, die Grenzen dieses Ansatzes auf. Der Zwang zu flachen Relationen erzeugt eine große Anzahl von "Hilfsstrukturen"; zusammengesetzte oder gar mengenwertige Attribute, Aggregationen, Spezialisierungen usw. sind nur schwer darzustellen. Dies führt zu bekannten OO-Forderungen: Typdeklarationen sollen ähnlich wie in Programmiersprachen aufgestellt werden können, d.h. Strukturen sollen beliebig verschachtelt werden können, Information soll wiederverwendet werden können: o bereits vorhandene Information soll durch Referenzierung zu neuer Information aggregiert werden können, o durch Vererbung sollen Spezialisierungen gebildet werden können. Entitäten können mit speziellem "Verhalten" ausgestattet werden, die jeweiligen Operationen (Methoden) werden exklusiv an diese gebunden, eine hierarchische Vererbung von Struktur und Verhalten soll ermöglicht werden. Darüber hinaus ist wünschenswert, dass Struktur sowie Verhalten erweiterbar ist, Objektidentität unterstützt wird und eine einheitliche Sprache für Daten-Definition, -Manipulation, -Verwaltung und Anwendungs-Programmierung existiert Für die objekt-orientierte Datenmodellierung sind folgende Eigenschaften von Bedeutung: Modellierbarkeit komplexer Objekte: komplexe Objekte entstehen aus atomaren bzw. bereits erzeugten Objekten durch die Anwendung von tuple-, set-, bag-, list- und array-Konstruktoren. Im Gegensatz zu den relationalen Konstruktoren (set ist nur auf Tupel, tuple ist nur auf atomare Werte anwendbar) sollen die Konstruktoren "orthogonal" (frei, ohne Einschränkungen) auf Objekte anwendbar sein. Komponenten eines Objektes können als komplexer Wert 188 oder als Referenz zu verbundenen Objekten (Wiederverwendung von Information) gestaltet sein. Orthogonalität: Während Adäquatheit die Unterstützung aller Konzepte des Datenmodells in einer Anfragesprache erfordert, bezieht sich die Orthogonalität auf die Art und Weise, wie diese Konzepte unterstützt werden. Orthogonaler Sprachentwurf heißt, dass die Konzepte frei und möglichst ohne künstliche Einschränkungen miteinander kombiniert werden sollten. Eine Sprache wie SQL, in der bestimmte Funktionen oder Operationen in bestimmten Situationen nicht erlaubt sind, ist also nicht orthogonal. Die Realationenalgebra selbst ist dagegen orthogonal. (Heuer, Objektorientierte Datenbanken) Unterstützung der Objekt-Identität: beim relationalen Ansatz ist nicht direkt entscheidbar, ob zwei Objekte "gleich" oder "identisch" sind, in manchen Fällen muss dazu erst ein künstlicher Schlüssel eingeführt werden. Objekt-Identität vermeidet diese Schwierigkeit: gleiche Objekte werden als zwei Objekte mit gleichen Werten erkannt. Im Gegensatz zum "künstlichen" Schlüssel handelt es sich bei Objekt-Identität um eine systemseitig bereitgestellte Eigenschaft. Objektidentität: 1. Jedes Objekt besitzt eine Identität, die es von allen anderen Objekten unterscheidet. Selbst wenn zwei Objekte zufällig dieselben Attributwerte besitzen, haben sie eine unterschiedliche Identität. 2. In objektorientierten Datenbanksystemen werden Objektidentitäten automatisch vom System generiert und verwaltet. Sie besitzen keine (verwendbare) Semantik und sind dem Programmierer nicht bekannt. Objektidentitäten können in objektorientierten Datenbanksystemen beispielsweise als Surrogate realisiert werden. (Balzert) Unterscheidung von Typen und Klassen: Typen bilden den strukturellen Anteil einer Klasse: zeitinvariante Beschreibung einer Menge von (komplexen) Werten; außer ggf. generischen Operatoren, wie z.B. +, sind an einen Typ keine spezifischen Operationen gebunden. Der Begriff Klasse kapselt Struktur und Verhalten. Insbesondere enthält eine Klasse Methoden zum Erzeugen und Löschen von Objekten. Die Begriffe „Klasse“ und „Typ“ werden oft synonym verwendet. Genau genommen gibt es einen Unterschied, den wir im folgenden betrachten wollen. Der Typ (type) legt fest, auf welche Botschaften das Objekt reagieren kann, d.h. er definiert die Schnittstellen eines Objekts. Die Klasse (class) definiert, wie Objekte implementiert werden, d.h. sie definiert den internen Zustand der Objekte und die Implementierung der Operationen. Eine Klasse ist eine mögliche Implementierung eines Typs. Das bedeutet, dass die Klasse die Implementierung von Objekten definiert, während der Typ festlegt, wie diese Objekte verwendet werden. Kurz ausgedrückt: Die Klasse implementiert den Typ. (Balzert) Unterstützung von Klassenhierarchien: Spezialisierung ist eine IS-A-Beziehung; in OO-Datenbanken kann dieser Zusammenhang durch Vererbung adäquat beschrieben werden, Struktur und Verhalten werden vererbt. Definition eines OODBS Ein OODBS ist ein System, das 189 1. ein Objektorientiertes Datenmodell mit Strukturteil, Operationenteil und höheren Konstrukten unterstützt. 2. Erweiterbarkeit zumindest auf der konzeptuellen Ebene bietet. Das heißt, dass im Datenbanksystem neue Datentypen eingeführt werden können (z.B.ADT`s), die nachher wie Standard-Datentypen benutzt werden können. Dazu müssen dann auf der internen Ebene nicht unbedingt neue Speicherstrukturen entworfen werden. (...) 3. Persistenz, Dateiorganisationsformen und Zugriffspfade, Transaktionen, Concurrency Control und Recovery realisiert 4. neben einer interaktiv nutzbaren Anfragesprache auch eine komplette Programmierumgebung enthält. Objektorientierte DBMS weichen von der Drei-Ebenen-Architektur relationaler DBMS ab. In vielen Fällen wird die Ebenentrennung völlig aufgehoben und man programmiert direkt auf den internen Strukturen. Das hat folgende Gründe: - Durch eine fehlende Anfragesprache und ein dadurch bedingt fehlendes Sichtkonzept gibt es keinerlei Möglichkeiten, auf der externen Ebene anwendungs- oder anwenderabhängige Strukturen zu schaffen. - Durch übertriebenes Effizienzdenken wurde die Trennung zwischen konzeptueller Repräsentation eines Objekts und interner Repräsentation eines Objekts völlig aufgehoben. Die konzeptuelle Repräsentation entspricht oft der internen, doch daraus folgt nicht immer bessere Effizienz. - Die enge Anbindung objektorientierter Programmiersprache an objektorientierte Datenbank schien die Drei-Ebenen-Architektur nicht zu erfordern. OOPL OODBS (Objektorientierte Programmiersprache Objektorientiertes Datenbanksystem) Ausgehend von einer OOPL (etwa C++) wird durch Realisierung der Datenbankkonzepte wie Persistenz, Speicherstrukturen und Zugriffspfade, Transaktionen und Concurrency Control, sowie Recovery-Mechanismen ein OODBS entwickelt. Die Systeme dieser Entwicklungslinie werden objektorientierte Datenbank Programmiersprachen genannt. System-Eigenschaften eines OO-DBMS Persistenz: Objekte, die von Anwendern bearbeitet wurden, müssen die Ausführung des Prozesses "überleben". Sie können dann in anderen Zugriffen wiederverwendet werden. Diese Eigenschaft ist automatisch durch das OODBMS zu garantieren. Der Benutzer sollte zwischen persistenten und transienten Objekten unterscheiden können. Mehrbenutzerfähigkeit: Es muss ein Transaktionskonzept existieren, damit Mehrbenutzerfähigkeit ermöglicht wird. Die Transaktionen müssen nach dem ACID-Prinzip (atomar, consistency, isolation, durable) ausgeführt werden. Sekundärspeicher-Verwaltung: Die Datenbestände müssen auf Sekundärspeicher - in der Regel Platten - gehalten werden, das DBMS muss eine entsprechende Funktionalität bereitstellen, um auf die gespeicherten Daten (effizient) zuzugreifen. Verwendete Techniken sind für den Benutzer transparent und schließen Index-Verwaltung, Clusterung, PufferVerwaltung, Anfrage-Optimierung, Zugriffspfad-Verwaltung mit ein. Damit wird physische Datenunabhängigkeit realisert. 190 Fehlertoleranz: In Zusammenhang mit dem Transaktionskonzept steht, dass das System bei Fehlern, welche den Inhalt der Daten im Hauptspeicher betreffen, auf einen konsistenten Zustand zurücksetzen kann. Analoges gilt für Soft- und Hardware-Fehler. Persistenz Um den "Impedance Mismatch" (Nichtzusammenpassen von Programmiersprachen- und Datenbankkonzepten) relationaler Modelle zu vermeiden, muss eine nahtlose Integration von Programmiersprache und Datenbank geschaffen werden. Das bedingt auch, eine Antwort auf die frage der Behandlung transienter und persistenter Objekte zu finden. Persistenz sollte folgende Eigenschaften aufweisen: ein Objekt eines beliebigen Typs sollte persistent sein können (Orthogonalität), für den Programmierer soll sie in dem Sinne transparent sein, dass kein Unterschied zwischen persistenten und transienten Objekten erkennbar ist, sie sollte unabhängig vom Speichermedium sein, es sollten keine expliziten Lese und Schreiboperationen erforderlich sein. Es gibt meherere Ansätze, Persistenz in der Sprache zu realisieren: Verwendung von persistenten Klassen - dies entspricht dem Ansatz eines Schemas in der Datenbank. Dadurch muss im Allgemeinen der Programmierer persistente Objekte in transiente Bereiche bringen und umgekehrt. Verwendung von persistent instanziierten Objekten - Klassen müssen damit nicht mehr als persistent gekennzeichnet werden. Probleme treten auf, wenn persistente Objekte transiente referenzieren. Verwendung von Erreichbarkeit: ein Objekt ist automatisch persistent, wenn es von einem persistenten Objekt aus referenziert wird. Jedes Objekt, das mit einem benutzer-definierten Namen adressiert wird, ist damit automatisch persistent. Persistenz wird definiert als: Fähigkeit der Daten (Werte, Objekte), beliebige Lebensdauern (so kurz wie möglich oder so lang wie nötig) anzunehmen, wobei zwei Prinzipien eingehalten werden müssen: Typ-Orthogonalität: Daten beliebiger (auch komplexer) Typen sollen persistent gemacht werden können. Unabhängigkeit der Programme von der Persistenz: Programme sollen unverändert bleiben, wenn die Daten ihre Lebensdauer ändern. Das zweite Prinzip bedeutet, dass Persistenz implizit in der Sprache enthalten sein soll. Nachdem wir bei bestimmten Daten die Lebensdauer verändert haben, sollen keine Moveoder Copy-Befehle extra nötig sein, um diese Persistenz zu verwirklichen. Typischerweise sind etwa ein Drittel des Codes der meisten kommerziellen Programme Operationen zum Transport von Daten zwischen Speichermedien. Oft wird die Persistenz nur in zwei Stufen definiert: Daten sind transient, wenn ihre Lebensdauer am Ende eines Blocks, einer Prozedur oder eines Programms endet. Daten sind persistent, wenn sie das Programmende und sogar Systemabstürze und Plattenfehler überleben. Impedance mismatch: Die Kluft zwischen Konzepten der Programmiersprachenumgebung und des 191 Datenbanksystems ist natürlich bei der OODBPL (Objektorientierte Datenbank Programmiersprache) vollkommen überbrückt. Geht es einem also um eine einheitliche Anwendungsentwicklung mit persistenten Objekten, so ist diese Linie zu bevorzugen. In ORDBs (Objektrelationale DBMS) dagegen befinden sich die Objekte in Relationen, eine objektorientierte Programmierschnittstelle muss also wieder über Umwege mit den Anwendungsobjekten arbeiten. (Heuer, Objektorientierte Datenbanken) Nebenläufigkeit Damit Prozesse parallel abgearbeitet werden können, muss eine Transaktionsverwaltung existieren. Dieses ist in OODBMS im Gegensatz zum relationalen Ansatz ein Problem, da die Objekte sehr groß sein können. Sperren können verwendet werden, um Transaktionen zu implementieren. Dieses Verfahren zusammen mit dem 2-Phasen Protokoll eignet sich dann, wenn in einer Transaktion jeweils nur auf wenige, bekannte Objekte zugegriffen wird. Beispiel: CAD/CAM-Anwendungen. Optimistische Verfahren eignen sich ebenfalls (z.B. in GemStone eingesetzt). GemStone ist ein Vertreter der Linie objektorientierte DatenbankProgrammiersprachen. GemStone wurde auf Smalltalk-Basis entwickelt und ist eines der ersten kommerziell erhältlichen OODBS gewesen. (Heuer, Objektorientierte Datenbanken) Transaktionen, Concurrency Control Transaktionen sollen in relationalen Systemen dem ACID-Prinzip genügen, d.h. die Transaktionen sollen atomar, konsistent, isoliert und dauerhaft sein. Die Transaktionen sollen zwar parallel ablaufen, die Concurrency Control sichert in Datenbanksystemen aber die Serialisierbarkeit zu: die Ergebnisse der Transaktionen sind äquivalent zu den Ergebnissen, die eine serielle Abarbeitung der Transaktionen geliefert hätte. In objektorientierten Datenbanken gibt es mit diesem klassischen Transaktionsbegriff einige Probleme: Andere Struktur: Die Transaktionen in relationalen Systemen bestehen aus einfachen Update- oder Anfrage-Operationen. In OODBSs werden Transaktionen aber komplizierter aufgebaut sein. Insbesondere bestehen sie aus Teiltransaktionen. Beispiel: Man stelle sich dazu das Eintragen der Information über einen neuen Zeitschriftenband in eine Datenbankvor: für den Band muß ein Komponentenobjekt der Klasse Zeitschriften, ein komplexer Wert des Attributes Hefte, in diesem je ein komplexer Wert des Attributes Artikel und in diesem je ein komplexer Wert des Attributes Autoren (neben anderen Informationen) eingetragen werden. Die Transaktion ist also sehr lang und besteht aus mehreren Teiltransaktionen. Andere Anforderungen: Speziell in Entwurfsanwendungen wie im CAD oder CASE ist etwa die Isoliertheit und Konsistenzerhaltung der Transaktionen nicht immer wünschenswert. 192 Sollen in einem EntwurfsProzess mehrere Ingenieure zusammenarbeiten, so ist es sinnvoll, dass diese anderen Mitgliedern des Teams auch inkonsistente Zustände zur Verfügung stellen können. Auch sollte eine (Teil-)Transaktion abgeschlossen werden können, ohne dass ein global konsistenter Zustand erreicht ist (siehe Abschnitt 2.2). Das Aufgeben der klassischen ACID-Forderungen ist sehr umstritten. Wie gleich noch erläutert wird, kann man entweder "lange" oder "Entwurfstransaktionen" einführen, die das AGID-Prinzip auf gewissen Stufen umgehen, oder zu "geschachtelten" oder "MehrschichtenTransaktionen" übergehen, die die klassische Theorie unter Beibehaltung des AGID-Prinzips erweitern. Lange Transaktionen: Die primitivste Technik zur Umgehung der oben genannten Schwierigkeiten ist die unkontrollierte Verlängerung der Transaktion durch einen Check-Out—Check-lnMechanismus: die Transaktion besorgt sich ein Objekt oder eine Menge von Objekten mit einem Check-Out und arbeitet mit diesen in einem eigenen Arbeitsbereich (workspace). Die in den Arbeitsbereich kopierten Objekte sind für die anderen Transaktionen nicht gesperrt (optimistisches Concurrency Control, siehe unten). Nach Ende der Transaktion werden die geänderten Objekte mit dem Check-in wieder in die Datenbank eingetragen. Falls die Objekte in der Zwischenzeit aber auch von einer anderen Transaktion geändert wurden, gibt es nun zwei Möglichkeiten: Das Check-in schlägt fehl und die Transaktion muß ohne Ergebnis beendet werden. Dies ist die Grundtechnik in GemStone, die aber in neueren Versionen durch geeignete Maßnahmen (zusätzliches Sperren von Objekten) entschärft wurde. Das Check-in legt zwei Versionen für die geänderte Menge von Objekten an. Dies ist die in ObjectStore verwendete Technik. Die relativ unkontrollierten langen Transaktionen können in bestimmten Anwendungsbereichen besser strukturiert und somit auch besser synchronisiert werden. Beispielsweise können für Entwurfsanwendungen Transaktionen in mehrere Schichten unterteilt werden. Kooperative Transaktionen Kooperative Transaktionen oder Entwurfstransaktionen bestehen aus Projekt-Transaktionen, die dem ACID-Prinzip genügen. Jede Projekt-Transaktion besteht aus mehreren kooperierenden Transaktionen, die Ergebnisse bereits vor Abschluss einer Transaktion den anderen Transaktionen innerhalb dieser Projekt-Transaktion übermitteln können, also keine ACID-Transaktionen sind. Jede kooperierende Transaktion besteht wiederum aus atomaren Transaktionen des einzelnen Ingenieurs. Diese sind kurze Transaktionen, die wiederum abgeschlossen sein müssen, bevor Ergebnisse auf der Ebene der kooperierenden Transaktionen weitergegeben werden können. Diese Entwurfstransaktionen sind zwar schon strukturierter als die oben beschriebenen langen Transaktionen, bergen aber innerhalb der Ebene der kooperierenden Transaktionen durch die Aufhebung der ACID-Eigenschaft noch einige Gefahren. 193 Geschachtelte Transaktionen Bauen wir Transaktionen aus Teiltransaktionen auf, die jeweils wieder strukturiert sein können, so kommen wir zu geschachtelten Transaktionen. In dieser Schachtelung werden jedoch die Transaktionsprinzipien auf keiner Ebene aufgehoben. Ein solcher Aufbau ist in ONTOS zu finden. Ist eine Teiltransaktion abgeschlossen, so übernimmt die sie umgebende Transaktion noch die Kontrolle über die in der Teiltransaktion erzielten Ergebnisse. Eventuell kann sie die Teiltransaktion auch noch zurücksetzen. Daher ist es notwendig, die von der Teiltransaktion getätigten Sperren nach ihrer Beendigung in der sie umgebenden Transaktion aufrecht zu erhalten. Diese Transaktionsart heißt geschlossen geschachtelte Transaktion. Beispiel: Wenn bei der Eintragung eines Zeitschriftenbandes das Eintragen der Informationen über einen Artikel aufgrund von nicht eingehaltenen Integritätsbedingungen fehlschlägt, muss nicht die ganze Transaktion zurückgesetzt werden, sondern kann mit dem von dieser Teiltransaktion unabhängigen "Rest" erfolgreich abgeschlossen werden. Ist das Eintragen eines Artikels erfolgreich gewesen, so kann diese Information aber noch nicht anderen Teiltransaktionen zur Verfügung gestellt werden, da eventuell die bereits abgeschlossene Teiltransaktion "Eintragen eines Artikels" von der sie umgebenden Transaktion "Eintragen eines Heftes" wieder zurückgesetzt werden kann. Im Gegensatz dazu kann man nach Ende der Teiltransaktion die dort getätigten Sperren wieder freigeben. Diese Transaktionsart heißt offen geschachtelte Transaktion. Falls Teilergebnisse nun aber weiterverarbeitet werden, bevor diese Teiltransaktion später wieder abgebrochen werden muß, werden Kompensations-Transaktionen gestartet, um die betroffenen Transaktionen wieder rückgängig zu machen. Mehrschichten-Transaktionen Während die Semantik der Schachtelung von der Anwendung abhängt, kann man eine Transaktion auch in mehreren Schichten bezüglich der zugrundeliegenden Datenbankarchitektur betrachten. Diese Mehrschichten-Transaktionen sind somit ein Spezialfall der anwendungsabhängigen geschachtelten "Transaktionen. Beispiel: Die geschachtelte Transaktion "Zeitschriftenband eintragen" besteht aus den Teiltransaktionen "Heft eintragen", "Artikel eintragen", "Autoren eintragen". Dagegen kann eine Mehrschichten-Transaktion gemäß der Architektur des OODBSs in die Teiltransaktionen "Objekt eintragen", "komplexes Tupel eintragen" und "Seite eintragen" unterteilt werden. Eine Implementierung dieser Mehrschichten-Transaktionen bietet das DASDBSSystem. Transaktionen im ODMG-Standard ODMG fordert ACID-Transaktionen und optional auch verteilte Transaktionen nach ISO-XA oder OMG-OTS (siehe [Dad96] für nähere Erläuterungen). Transiente Objekte unterliegen dabei nicht der Transaktionskontrolle. Das Sperren von Objekten wird im Standard vorgesehen, optional sind auch andere Granularitäten der Sperren wie Seiten möglich. Die Sperren werden nach dem READ-WRITE-Modell ausgeführt. Es gibt also getrennte Sperren für Anfragen und Updates. Die Schnittstelle Transaction bietet folgende Operationen: 194 • begin() für den Start einer Transaktion • conmit() für das erfolgreiche Ende einer Transaktion • abort() für den Abbruch einer Transaktion • Checkpoint () für die Synchronisation laufender Transaktionen, um einen konsistenten Zustand im Log-Protokoll zu erreichen • active() zu Test aufeine aktive Transaktion Die Schnittstelle Database bietet darüberhinaus auch noch Administrationsfunktionen wie • open, close(), bind, lookup für Datenbanken und • optional move, copy, reorganize, backup, restore für die Datensicherung. Geschachtelte Transaktionen waren in alten Versionen des Standards (etwa 1.1) enthalten, wurden aber im aktuellen Standard ODMG 2.0 wieder aus der Forderungsliste entfernt. Workflow-Systeme Das Problem der langen Transaktionen kann — wie eben gesehen — mit der Schachtelung klassischer ACID-Transaktionen gelöst werden. Andererseits sind auch andere Ansätze vorhanden, die den Begriff der Serialisierbarkeit durch einen allgemeineren Begriffersetzen und deren Transaktionsmodell auch allgemeiner ist: ein Beispiel dafür ist das ConTractModell. Im ConTract-Modell werden Transaktionen durch eine Reihe elementarer Schritte (Steps) und einen davon getrennten Kontrollfluß (Skript) beschrieben. Zu jedem Schritt gehört ein Kompensationsschritt, der im "Notfall" zur Zurücksetzung der gesamten Transaktion benötigt wird. Als Kriterium für die Korrektheit des parallelen Ablaufs von Transaktionen werden statt der Serialisierbarkeit allgemeine Invarianten angegeben, die mit den Vor- und Nachbedingungen der Methoden in Eiffel verglichen werden können. Das ConTract-Modell ist somit ein erster Schritt, die Semantik der Transaktion unabhängig von ihrer Programmierung zu spezifizieren und diese Semantik in der Concurrency Control auch auszunutzen. Concurrency Control Im wesentlichen gibt es auch in klassischen Datenbanksystemen zwei Strategien zur Concurrency Control: Pessimistische Verfahren sperren Seiten, Sätze, Tupel, Objekte oder Objektmengen, um Konflikte mit anderen Transaktionen beim versuchten Zugriff auf die Daten zu erkennen und zu vermeiden. Optimistische Verfahren sperren dagegen nicht, sondern versuchen durch andere Techniken, beim Schreiben von Daten Konflikte zu entdecken. Diese Verfahren reichen von Zeitstempelverfahren (siehe etwa [U1188]) bis zu den oben beschriebenen langen Transaktionen, die erst beim Check-in einen Konflikt bemerken. Die Sperren können gerade in objektorientierten Datenbanken unterschiedliche Granularität haben, d.h. man kann von atomaren Werten bis hin zu gesamten Klassenhierarchien unterschiedlich viele und unterschiedlich große Daten und Objekte sperren. Ein Beispiel dafür ist ORION. Einige OODBSs verwenden hybride Techniken zwischen optimistischen und pessimistischen Verfahren. So ist es in GemStone in den neueren Versionen möglich, neben den langen 195 Transaktionen mit optimistischer Concurrency Control auch einzelne Objekte zu sperren, um einen eventuellen Check-ln-Konflikt zu vermeiden. Recovery Eine Transaktion kann aus verschiedenen Gründen abgebrochen werden: 1. Die Transaktion kann eine Integritätsverletzung in der Datenbank hervorrufen. 2. Die Concurrency Control entdeckt Konflikte zwischen mehreren parallel ablaufenden Transaktionen und setzt eine Transaktion zurück. 3. Das System stürzt durch Fehler im Anwendungsprogramm, im Datenbanksystem oder im Betriebssystem ab. 4. Das System stürzt durch einen Stromausfall oder ähnliche äußere Ursachen ab. 5. Daten gehen durch einen Hardware-Fehler wie einen Platten-''Crash" verloren. Nach den ersten drei Arten von Fehlern kann durch Recovery-Mechanismen ein letzter konsistenter Datenbankzustand rekonstruiert werden. Als Voraussetzung dafür müssen die Veränderungen der Datenbank mitprotokolliert werden, entweder in einem Log-Protokoll oder in einem Schattenspeicher auf Platte, in den der Hauptspeicherinhalt regelmäßig gesichert wird. Gegen die vierte Art des Fehlers helfen nur vollständige Sicherungen oder automatische Erzeugung von Duplikaten der Datenbank. Solche automatischen Duplikate sind zum Beispiel in GemStone möglich. Auch in OODBSs sollen Recovery-Mechanismen für alle oben genannten Fehlersituationen verfügbar sein. Da sie stark abhängig sind vom gewählten Transaktionsmodell und der zugrundeliegenden Strategie des Concurrency Control, soll hier auf keine weiteren Details eingegangen werden. (Heuer, Objektorientierte Datenbanken) 196 Bei objektorientierten Datenbanken wurde auf eine enge Anbindung an Programmiersprachen geachtet. Abb. 8.4-4 zeigt den typischen Umgang mit einem objektorientierten Datenbanksystem. Der Programmierer schreibt zunächst eine Schemadeklaration, die vom Präprozessor in das Datenbankschema und einen deklarationsteil der Programmiersprache (PL-Deklaration) übersetzt wird. Diese Schemadeklaration kann entweder in ODL (Object-Definition-Language) oder in PL-ODL (z.B. C++-ODL) erfolgen. Desweiteren erstellt ein Programmierer das Anwendungsprogramm in einer objektorientierten Programmiersprache. Dabei müssen Klassenbibliotheken benutzt werden, die eine Manipulation der Datenbank erlauben. PLDeklaration und das Anwendungs-Quellprogramm werden übersetzt und mit dem Laufzeitsystem der Datenbank gebunden, damit eine lauffähige Anwendung entsteht. (Balzert) Das OODBMS POET POET gehört zur Linie objektorientierte Datenbank-Programmiersprachen und erweitert C++ um persistente Objekte. Persistenz ist in POET jedoch weder orthogonal noch unabhängig, da sie auf Klassenebene definiert wird (persistente Klassen erben von einer bestimmten, vordefinierten Oberklasse). Das Speichern und Holen von Objekten muss außerdem explizit geschehen. Sämtliche Optionen für wählbare Speicherstrukturen und Zugriffspfade haben Auswirkungen auf die Definition des Datenbankschemas. Weiterhin werden nicht all C++Konzepte wie die Mehrfachvererbung unterstützt. Datenbankmodell: Das Datenbankschema wird in C++-Header-Dateien mit einer erweiterten C++-Syntax definiert und danach mit einem Precompiler in die vorhandenen C++-Versionen übersetzt. Die Erweiterungen betreffen: - die Deklaration von persistenten Klassen durch persistent class - die optionale Angabe ondemand, falls Kommandoobjekte von in den Hauptspeicher geladenen Objekten nicht automatisch dazugeladen werden sollen, - die optionale Angabe transient zur Kennzeichnung von temporären Attributen (nicht Objekten !!) in einer persistenten Klasse - verschiedene generische Mengenklassen, die unterschiedliche Speichermodelle realisieren (CSet für kleine Mengen, LSet für große Mengen und HSet für beliebig große Mengen) - die optionale Angabe von depend bei Komponentenobjekten, die dadurch zu abhängigen Komponentenobjekten werden, sowie - die Angabe von Indizes für Klassen (einschließlich Pfadindizes). Anfragen: Für Anfragen müssen zunächst Klassen definiert werden, die Unterklassen von PTQuery, einer vordefinierten POET-Klasse, sind. Anfragen werden durch die Parameter „Vergleichswert“, „Vergleichsoperand“ und „Logische Verknüpfung“ definiert. Im wesentlichen könnenso einige von den Pfadausdrücken und Selektionen beschrieben werden, die in ObjectStore möglich sind, nur mit sehr viel elementareren Mitteln.Weiterhin steht eine Rumpfversion der ODMG-OQL zur Verfügung. Leider sind fast alle interessanten Klauseln von OQL bei POET noch nicht implementiert. 197 Weitere Komponenten: Versionen und verschiedene Cluster-Mechanismensind in POET nicht verfügbar. Transaktionen sind durch die Verfügbarkeit von Sperren zumindest per Hand programmierbar. (Heuer, Objektorientierte Datenbanken) Persistenz wird in POET über persistente Klassen erzielt. Eine Klasse, deren Objekte gespeichert werden sollen, erhält das Attribut persistent. Ein Precompiler erzeugt daraus entsprechende C++-include-Dateien, die ein Klassen-Dictionary für die Datenbank sowie eine spezifische Klasse von Administrations-Funktionen erstellt, die den Zugriff auf die gespeicherten Objekte ermöglichen. Transaktionen werden durch Sperren erreicht. Sowohl die Art als auch die "Tiefe" einer Sperre können beeinflusst werden: Art der Sperre: dies ist von anderen Systemen her in ähnlicher Form bereits bekannt. Bis auf NONE und EXCLUSIVE werden immer zwei Bezeichnungen angegeben: das was der eigene Prozess tun will und was ein anderer Prozess nicht tun darf. Dabei gilt die Ordnung READ - WRITE - DELETE. Tiefe der Sperre: analog zum Speichern kann o nur das Objekt selbst, o zusätzlich alle abhängigen Objekte, o und darüber hinaus noch alle referenzierten Objekte gesperrt werden. Die Sperren sind unabhängig von der Transaktionsverwaltung zu sehen. Sie können jedoch dazu benutzt werden, um für eine Transaktion den Zugriff auf die benötigten Objekte zu sichern. Zur Transaktionsverwaltung gibt es die Methoden BeginTransaction CommitTransaction sowie AbortTransaction. Durch die Bereitstellung von BeginTransaction können jetzt geschachtelte Transaktionen erzeugt werden. Eine Transaktion ist erst dann vollständig abgeschlossen, wenn auch die äußerste Transaktion abgeschlossen ist. Intern werden bis zu diesem Zeitpunkt alle durch die Transaktion betroffenen Objekte in einem Transaktions-Cache aufbewahrt und sind damit für andere Prozesse gesperrt. Transaktionen setzen also - genau so wie bei relationalen DBMS - selbsttätig die benötigten Sperren, sofern sie nicht durch den Programmierer vorab gesetzt wurden. Durch CommitTransaction bzw. AbortTransaction werden die durch die Transaktion selbst gesetzten Sperren zurückgesetzt, nicht aber die durch den Programmierer eigenhändig erzeugten. Poet in Form von Beispielen Eine persistente Klasse zur Speicherung von Personen könnte so aussehen: persistent class Person { private: PtString name; // variable Zeichenkette short age; // Adresse am andren Ort definiert sein 198 Adresse adresse; short iq; // transientes Objekt transient Darstellung *sicht; public: // Mehrfache Referenz auf ein Objekts möglich, // wenn z.B. mehrere Kinder zu einem Vater gespeichert werden Person* vater; // 1-n Referenzen mit Hilfe von Mengen cset< Person* > kinder; // abhängige Objekte depend Person *alter_ego; // Laden nur auf Anforderung ondemand< Person > wichtigBezugsPerson; } Diese Definition muss in einer Datei mit der Erweiterung .hdc niedergelegt sein. Der PoetPrecompiler erzeugt daraus die entsprechenden include-Dateien sowie spezifische administrative Klassen zum Zugriff auf die gespeicherten Objekte der Klasse Person. Für die spätere Arbeit mit Anfragen müssen auch Mengen definiert werden, die die Ergebnismenge enthalten können. Dies muss ebenfalls in .hcd-Dateien erfolgen und könnte z.B. so aussehen: typedef lset PersonSet; Der Zugang zur Datenbank wird durch folgendes Code-Stück ermöglicht (Fehlerprüfungen sind hierbei nicht berücksichtigt; fehler müsste dazu ausgewertet werden): #include < stdlib.h > #include < poet.hxx > main () { int fehler; PtBase oodb; // Verbindung zum Server LOCAL herstellen fehler = oodb.Connect( "LOCAL" ); // Datenbank base önnen fehler = oodb.Open( "base" ); // ... // hier folgt jetzt die Transaktionsverarbeitung // ... // Schließen der Datenbank fehler = oodb.Close(); // Verbindung zum Server trennen fehler = oodb.DisConnect(); return 0; } Soll nach dem Öffnen der Datenbank ein Objekt der persistenten Klasse Person gespeichert werden, so muss zunächst das entsprechende Objekt mit Assign der Datenbank zugewiesen werden - hiermit wird die Objektidentität ermöglicht - und kann dann mit Store gespeichert werden: Person* pPerson = new Person; pPerson->Assign( &oodb ); err = pPerson->Store(); Assign und Store sind Methoden, die durch den Precompiler bereitgestellt werden. 199 Wird ein Objekt referenziert, so wird es in der Regel automatisch gespeichert bzw. gelesen, wenn das referenzierende Objekt gespeichert bzw. gelesen wird. Hier sind jedoch einige Besonderheiten zu beachten: die Objektidentität erzwingt beim Lesen; dass ein bereits im Speicher befindliches nicht noch einmal in den Speicher gebracht wird, vielmehr wird im Speicher die Referenz auf das bereits im Speicher vorhandene Objekt gesetzt und ein LinkCount erhöht (analog zum Link Count in einem Unix-BS). Beim Schreiben bemerkt Poet ebenfalls, dass das Objekt bereits in der Datenbank gespeichert ist, und vermeidet ein erneutes Speichern. Das Attribut ondemand bewirkt, dass das referenzierte Objekt nicht automatisch mit gelesen bzw. geschrieben wird; beim Anlegen muss mit der Methode SetReference(...) die Referenz explizit gesetzt werden. Ein wichtiger Grund für die Verwendung von ondemand liegt im Einsparen von Speicherplatz: das referenzierte Objekt muss explizit vom Programmierer bei Bedarf behandelt werden und belegt. Wenn es nicht benötigt wird, keinen Platz. Wird ein referenziertes Objekt mit dem Attribut depend gekennzeichnet, so wird es mit dem Löschen des zugrunde liegenden Objektes ebenfalls gelöscht. In dem gewählten Beispiel würde mit einer bestimmten Person auch das "alter_ego" mit gelöscht. Transiente Objekte werden vom Speichern ausgeschlossen. Besitzt eine persistente Klasse transiente Komponenten, so müssen diese im Konstruktor, der von Poet aufgerufen wird, wenn ein zugehöriges Objekt aus der Batenbank in den Speicher gelesen wird, jedesmal initialisiert werden. Im obigen Beispiel kann die Menge der Kinder erweitert werden durch die Methode Append: pPerson->kinder.Append( &nochEinKind ); Immer wieder taucht die Aufgabe auf, mit allen gespeicherten Objekten einer Klasse etwas zu machen, z.B. die selbstgeschriebene Methode MachWas() darauf anzuwenden. Diese Aufgabe wird durch die Klasse ...AllSet ermöglicht, die für eine persistente Klasse ... vom Precompiler angelegt wird. Ein entsprechender Code-Ausschnitt, der auf die gespeicherten Objekten der Klasse Person einwirkt, sieht dann so aus: PersonAllSet* allePersonen = new PersonAllSet( &oodb ); Person* = pPerson; long i; for (i = 0; allePersonen->Get( pPerson, i, PtSTART ) == 0; i++) { pPerson->MachWas(); allePersonen->Unget( pPerson ); } delete allePersonen; Die Methode Get(...) liest das nächste gespeicherte Objekt der Klasse Person aus. Die Methode Unget(...) dient dazu, den Speicher wieder freizugeben, der durch das nicht länger benötigte Objekt belegt wurde. Eine weitere Aufgabe muss ein Datenbanksystem erfüllen: man muss Daten nach einem gewissen Kriterium wiederfinden können. Dies soll zunächst am Beispiel aller Personen gezeigt werden, deren Namen mit "A" beginnen. Der Precompiler erzeugt hierfür aus der persistenten Klasse die Klasse PersonQuery: class PersonQuery: public PtQuery { public: SetName( PtString& parameter, PtCmpOp co = PtEQ); 200 ... } Mit Hilfe der so generierten Methoden kann für jede Objektvariable der zu vergleichende Wert sowie der Vergleichsoperator vereinbart werden. Wird die Anfrage mit den so vereinbarten Werten durchgeführt, so wird diejenige Menge von Objekten zurückgeliefert, die diese Anfrage erfüllen: PersonAllSet *alle = new PersonAllSet( &oodb ); PersonSet *ergebnis = new PersonSet; PersonQuery anfrage; Person* pPerson; anfrage.SetName( (PtString) "A*", PtEQ ); // Wildcards sind erlaubt alle->Query( &anfrage, ergebnis ); for ( int i = 0; ergebnis->Get( pPerson, i, PtSTART ) == 0; ++i ) { pPerson->MachWas(); ergebnis->Unget( pPerson ); } delete alle; delete ergebnis; Komplexere Anfragen könnten nach allen Eltern suchen, die Kinder mit einem IO über 140 haben: PersonAllSet *alle = new PersonAllSet( &oodb ); PersonSet *ergebnis = new PersonSet; PersonQuery eltern, kinder; kinder.SetIq( 140, PtGE ); eltern.SetKinder( 1, PtGTE, &kinder ); // wenigstens ein Kind und IQ gross alle->Query( &eltern, ergebnis ); ... Auf entsprechende Weise stellt der Precompiler auch Sort-Methoden zur Verfügung, so dass Ergebnismengen sortiert werden können. Diese Zugriffe können bei vielen Objekten sehr lange dauern, Poet ermöglicht deshalb den Einsatz von Indexen. Soll über den Namen auf eine Person zugegriffen werden, so kann durch den Einsatz des folgenden Indexes ein erheblicher Geschwindigkeitgewinn erzielt werden: persistent class Person { PtString name; ... // wie oben useindex PersonIndex; } indexdef PersonIndex: Person { name[10]; // nur die ersten 10 Buchstaben eines Namens gehen in den Index ein } Zusätzlich zur Transaktionsverwaltung unterstützt Poet noch explizite Sperren, die dazu verwendet werden können, dass die gewünschten Objekte verfügbar sind. Die Transaktionsverwaltung ist jedoch unabhängig von expliziten Sperren. 201 PtLockSpec LockSpezifikation( PtLK_WRITEvWRITE, PtFLAT ); // Schreibsperre setzen und Objekt holen allePersonen->Get( pPerson, 0, PtSTART, &LockSpezifikation ); pPerson->MachWas(); pPerson->Store(); // Lock und Speicher freigeben allPersonen->Unget( pPerson, &LockSpezifikation ); Um Poet richtig verstehen zu können, müsste jetzt ein gründlicher Überblick über die verschiedenen von Poet bereitgestellten Klassen erfolgen. Statt dessen werden nur die wichtigsten Klassen und deren Methoden kurz vorgestellt. Poet implementiert einige Datentypen selbst: PtDate für Datumswerte PtTime für Zeitwerte PtString für Zeichenketten und PtBlob für große binäre Objekte. Dies erfolgt vor dem Hintergrund, dass es ohne diese Vereinheitlichung durch Poet keine einheitliche Implementation dieser wichtigen Datentypen und der zugehörigen Methoden gibt. Alle persistenten Objekte erben von der Klasse PtObject. Die wichtigesten Methoden dieser Klasse sind Assign( PtBase *pb ), mit Hilfe derer das Objekt eine eigenständige "Identität" in der spezifizierten Datenbank bekommt; Delete( PtDepthMode Mode=PtSHALLOW ); diese Methode löscht das Objekt aus der Datenbank. PtDepthMode kann die Werte o PtFLAT: nur das Objekt selbst, o PtSHALLOW : das Objekt und abhängige Objekte, o PtNO_ONDEMAND: das Objekt und alle referezierten Objekte, sofern sie nicht als OnDemand erklärt sind, o PtDEEP: das Objekt und alle referenzierten Objekte annehmen; reduziert den LinkCount um 1 und löscht das Objekt aus dem Hauptspeicher, falls der LinkCount 0 ist; GetLinkCount(): liefert den aktuellen LinkCount für das Objekt; IsStored(): gibt an, ob das Objekt bereits in der Datenbank gespeichert ist oder nicht; IsAssigned(): antwortet auf die Frage, ob das Objekt bereits eine Objektidentität in der Datenbank besitzt oder nicht; Refresh(): liest das Objekt erneut aus der Datenbank und ersetzt den Speicherinhalt des Objekts; Remember(): erhöht den LinkCount um 1; Store( PtDepthMode Mode = PtDEEP ): speichert das Objekt in der Datenbank. Für Mode gelten die gleichen Angeben wie bei der Methode Delete; Lock( PtLockSpec *pSpec=0 ): setzt eine Sperre für das Objekt; Unlock( PtLockSpec *pSpec=0 ): entfernt die gesetzte Sperre; Forget() Die Klasse PtBase liefert Objekte, die die Datenbank selbst repräsentieren. Die zugehörigen Methoden dienen insbesondere zum Öffnen bzw. Schließen, zum Verbindungsauf- und abbau und zur Transaktionsverwaltung. 202 Die Klasse PtObjectSet ist Basisklasse für alle Mengen persistenter Objekte. Wichtige bereitgestellte Methoden sind Append() und Insert zum An- und Einfügen von Objekten, Delete zum Löschen eines Objektes, Find zum Positionieren auf einem bestimmten Objekt der Menge sowie Get zum Lesen des Objektes. und PtOnDemandSet sind Klassen, die im Zusammenhang mit ondemand spezifizierten Objekten benötigt werden. PtOnDemand ist eine Klasse, die zur Generierung für Anfragen benötigt wird. Der Precompiler erzeugt für jede persistente Klasse eine spezifische Anfragenklasse, die von PtQuery abgeleitet ist. PtQuery Das OODBS Versant VERSANT wird von Versant Object Technology (früher: Object Sciences) entwickelt und angeboten. Die hier beschriebene Version ist VERSANT Release 5. Das System ist seit 1990 auf dem Markt. Die VERSANT-Architektur umfasst mehrere Server und mehrere Clients und ist auf vielen UNIX-Workstations einsatzfähig. Grundprinzip: VERSANT gehört zur Linie objektorientierte Datenbank-Programmiersprachen und ist ein Baukastensystem, das mehrere Bestandteile eines OODBS anbietet und andere Bestandteile von Fremdherstellern integriert. Im wesentlichen besteht der VERSANT-Kern aus einem Objekt- und Seitenmanager (VERSANT ODBMS) und einer Klassen- und Methodenbibliothek für C und C++. Mehrere C und C++ Compiler von Fremdherstellern werden unterstützt. Persistenz wird durch Unterklassenbildung von einer VERSANT-Klasse Persistent erreicht. Anfragen werden in einer SQL-ähnlichen Anfragesprache Object SQL gestellt, die aufgrund der vorliegenden Informationen Ähnlichkeiten mit ONTOS Object SQL hat – auch in ihren Schwächen. Datenbankmodell: Das Datenbankmodell besteht aus den für C und C++ mitgelieferten Klassendefinitionen und ihren Methoden. Beziehungen zwischen Klassen können durch definierbare Links spezifiziert und verwaltet werden. Schema-Evolution: Dynamische Änderung der Zugehörigkeit von Objekten zu Klassen sowie Änderungen der Klassendefinitionen sind mit Einschränkungen möglich. So ist es erlaubt, selbst bei vorhandenen Instanzen zu ändern, solange diese keine Unterklassen mehr besitzen. Die Instanzen werden dann angepasst. Schnittstellen und Werkzeuge: Als sehr offenes Produkt unterstützt VERSANT nicht nur eigene Werkzeuge wie einen Browser (Object Navigator), sondern auch Schnittstellen zu - verschiedenen RDBSs verschiedenen Programmiersprachen (C, C++, Smalltalk) sowie 203 - anderen Systemen, wie beispielsweise aus dem CIM-Bereich durch Bereitstellung von VERSANT STEP / EXPRESS, einer Schnittstelle zur Übernahme und Bereitstellung von Daten in einem genormten ProduktDatenmodell Weitere Komponenten: VERSANT bietet kurze und lange Transaktionen, ein Versionskonzept und Indexverwaltung in Form von B-Bäumen und Hashverfahren sowie Cluster-Strukturen. (Heuer-Objektorientierte Datenbanken, 1997) Versant Multithreaded, multi-session Client, multi-Threaded Server Automatic failover Balanced use of network resources Event notification für Datenbank-Ereignisse Dual Caching => schneller Zugriff auf gespeicherte Objekte Logische Objekt-ID, um Objekte auch im Speicher einheitlich zu referenzieren Versant "Architektur" 204 Java und C++ Schnittstelle => transparenter Zugriff durch übliche IDE unterstützt komplexe Datenmodelle Persistentes Datenmodell ist das gleiche wie das Business Aplikationsdatenmodell GUI Tools: o Administrationskonsole o Objekt-Inspektor o Monitoring Konsole o Entwicklerkonsole Performance Multi-Session, multi-threading Dual Caching Direkte Objekt-Objekt-Navigation bei den persistenten Objekten weiter Bereich von Locking Optionen Availability Fehler-toleranter Server High Speed Online Backup Incremental Online Backup Incremental Online Schema Evolution Flexibilität Zugriff vollständig über API von C, C++, Java => volle Integration in Applikation Dynamischer Query-Support Load Balncing durch Replikation Verteiltes Transaktions-Management auch SQL,JDBC,ODBC Zugriff auf Objekte Installationsvoraussetzungen Pentium PC Windows NT 128 64 MB RAM (recommended) o Windows: 60 MB o DB-Server: 4 MB o Sourcecode-Editor: 1 MB o JVM: 16 MB 35 - 60 MB Plattenkapazität CD-ROM Word, WinZip 205 Java-Programm: 206 Kompilieren und Ausführen: läuft ausschließlich im Hauptspeicher 207 Persistenz hinzufügen: 208 Persistenz hinzufügen: ein Session-Objekt erzeugen enthält o eine Liste der Datenbanken, zu denen Verbindung existiert 209 eine aktive Transaktion einen Client-Cache Änderungen validieren: commit-Methode o commit validiert die Transaktion o startet neue Transaktion o o o Datenbank anlegen: makedb Company createdb Company Konfigurationsdatei, um Persistenz zu vereinbaren (config.jvi) Übersetzen und Ausführen: javac Main.java java com.versant.Enhance . java Main browser Company 210 kein (direkter) DB-Code, um Objekte zu speichern bzw. zu ändern DBMS unterstützt Vererbung, Referenzen, Assoziationen Was passiert bei einer Referenz? DBMS prüft, ob Referenz bereits in Client-Cache bekannt falls nicht, sucht DBMS automatisch in Datenbank sobald dort gefunden und ein shared read lock erhalten, wird Objekt in Cache kopiert Aus Sicht der Applikation: Objekt war schon immer im Speicher Beispiel: 211 Verändern von Objekten: wird ein Attribut verändert, so wird das Objekt als dirty im Client-Cache gehalten beim nächsten commit werden alle modifizierten Objekte an den Server gesendet Server führt Update durch Server entfernt alls Locks auf diesen Objekten Hintergrund: Versant vergibt für jedes Objekt eine eindeutige Nummer OID beim Speichern werden alle Referenzen auf andere Objekte durch deren OIDs ersetzt wird ein Objekt geladen, so sind durch die referenzierten OIDs alle Objekte, auf die es sich bezieht, bekannt und können geladen werden bei Veränderungen wird geprüft, ob referenzierte Objekte bereits im Speicher; andernfalls werden sie über OID ermittelt und geladen Versant verwaltet Cache mittels Cache Object Descriptor Table; dieser enthält zu jedem gecachten Objekt (Java Referenz muss vorliegen) zur OID den Speicherplatz sowie Indikatoren (z.B. dirty) 212 Suchen nach Objekten mit bestimmten Eigenschaften (Anfragesprache) kann sich nur auf jeweils eine Klasse beziehen SQL-ähnlich SELECT * FROM [ONLY] Class WHERE attribute Klassennamen müssen voll angegeben werden ONLY: Subklassen sind ausgeschlossen Code-Beispiel: Code-Beispiel mit Navigation: Mit einer Anfrage können nicht nur die Objekte, die diese refüllen, sondern auch verbundene Objekte geholt werden: 0: nur die Objekte in der Klasse, die angesprochen wurde 1: zusätzlich Objekte, auf die durch die Klasse zugegriffen wird ... -1: der gesamte Objekt-Graph Code-Beispiel: 213 214 Schemaveränderungen kein Schema vereinbart, Versant erledigt dies automatisch auch Schemaveränderungen kann Versant nachvollziehen, dies erfolgt aber nicht automatisch, sondern muss veranlasst werden: 215 Default Locking Strategie: mit Zugriff auf ein Objekt (Select oder Navigation) wird read lock gesetzt => andere Transaktionen können Objekt noch lesen mit Verändern wird write lock gesetzt andere Transaktionen können nicht mehr auf Objekt zugreifen mit Transaktionsende (commit) werden die gesetzten Sperren wieder aufgehoben alle Caches werden entsprechend behandelt! durch Default: Deadlock-Problematik 216 Event Notification, um Caches zu synchronisieren, sobald ein Objekt verändert wurde: 217 218 12. Glossar Cluster Eine Gruppe von zwei oder mehr Tabellen, die aufgrund eines gemeinsamen Teils von Spalten zusammen gespeichert werden. Commit Beenden einer Transaktion. Dabei werden die Veränderungen, die innerhalb der Transaktion vorgenommen wurden, für alle Datenbankbenutzer sichtbar. Datenbank Die Zusammenfassung von DBMS und einer Reihe von Tabellen, die einen „Ausschnitt der Welt“ für eine Benutzergruppe beschreiben. Sie beschreiben die funktionalen Zusammenhänge der Daten aus der Sicht dieser Benutzer. Die Verwaltung der Tabellen geschieht mit Hilfe eines DBMS. Datenbanksystem Ein Datenbanksystem besteht aus einer oder mehreren Datenbanken, einem Data Dictionary und einem Datenbankmanagementsystem. In der Datenbank sind alle Daten gespeichert. Das Data Dictionary enthält das Datenbankschema, das den Aufbau der Daten der Datenbank(en) beschreibt. Die Verwaltung und zentralle Kontrolle der Daten ist Aufgabe des Datenbankmanagementsystems. [Balzert, Lehrbuch der Objektmodellierung] DCL Data Control Language, Spachanweisungen, die zur Verwaltung der Transaktionen, und damit zur Parallelisierung dienen. DDL Data Definition Language, Sprachelemente, die zur Veränderung des Datenbestandes einer Datenbank sowie zum Suchen innerhalb des Datenbestandes dienen. Die Datendefinitionssprache ist eine Sprache, die ein relationales Datenbanksystem zur Verfügung stellt und die zur formalen Definition des logischen Schemas – d.h. den leeren Tabellen der relationalen Datenbank – dient. [Balzert, Lehrbuch der Objektmodellierung] Dirty Read, Dirty Write Mit "schmutzigen" Daten werden geänderte Objekte bezeichnet, deren Änderungen von Transaktionen stammen, die noch nicht beendet sind. Da diese Transaktionen noch zurückgesetzt werden können, ist die Dauerhaftigkeit der Änderungen nicht gesichert. [Härder, Rahm; Datenbanksysteme] 219 DML Data Manipulation Language, Sprachelemente, die zur Veränderung des Datenbestandes einer Datenbank sowie zum Suchen innerhalb des Datenbestandes dienen. EOT End Of Transaction Hashing ist eine spezielle sehr schnelle Zugriffsmethode, die den Speicherplatz aufgrund des Inhalts durch Berechnung ermittelt. Index ist eine geordnete Menge von Werten mit Zeigern zu den zugehörigen Datensätzen, üblicherweise als B-Tree organisiert. Er ermöglicht einen schnellen Direktzugriff auf eine Tabelle über die Werte der Spalte(n), auf die der Index definiert ist. Ein Index erfordert zusätzlichen Verwaltungsaufwand bei jeder Änderung der Tabelle; er sollte nur definiert werden, wenn sehr häufig auf die entsprechende(n) Spalte(n) zugegriffen wird. JDBC Java Data Base Connectivity ist eine standardisierte DBMS-Schnittstelle zu Java Katalog Die Menge der Systemtabellen, in denen alle Informationen über die übrigen realen und virtuellen Datenbank-Tabellen, Indexe, Rechte, Zugriffspfade usw. verzeichnet sind. Knoten Ein DBMS, das Teil eines verteilten Datenbanksystems ist. Es verwaltet (in der Regel) eine lokale Datenbank und ermöglicht Zugriffe auf externe Datenbanken, d.h. auf Datenbanken, die von einem anderen DBMS auf einem Rechner verwaltet werden. Kreuzprodukt (zweier Tabellen) Tabelle, in der jede Zeile eine Verkettung einer Zeile der ersten mit einer Zeile der zweiten Tabelle ist. Dabei ist jede Zeile der ersten Tabelle mit jeder Zeile der zweiten kombiniert. Objektorientiertes Datenbanksystem Dem objektorientiertem Datenbanksystem liegt ein objektorientiertes Datenmodell zugrunde. Es integriert die Eigenschaften einer Datenbank mit den Möglichkeiten von objektorientierten Programmiersprachen. [Balzert, Lehrbuch der Objektmodellierung] 220 Objekt-relationales Datenbanksystem Objekt-relationale Datenbanksysteme verfolgen das Ziel, die besten Ideen aus der relationalen und der objektorientierten Welt zu verbinden. Das grundlegende Konzept bleibt weiterhin die Tabelle. Es wird um objektorientierte Konzepte wie Abstrakte Datentypen, Objektidentität, Operationen und Vererbung erweitert. [Balzert, Lehrbuch der Objektmodellierung] ODBC ODBC ist eine standardisierte Schnittstelle für den Zugriff auf relationale Datenbanksysteme. Sie wurde ursprünglich von Microsoft spezifiziert, hat sich aber inzwischen zu einem betriebsübergrefenden, allgemein akzeptierten de-facto-Standard entwickelt. Replikation Bündel von Methoden, die in einem verteilten Datenbanksystem kontrollierte Redundanz einführen, um zeitkritische Zugriffe über das Netz zu verringern. Transaktion Eine Folge von Datenbankoperationen – d.h. Zustandsänderungen - , die bezüglich der Datenintegrität eine Einheit bilden. Die Datenbank ist vor und nach der Ausführung einer Transaktion in konsistentem Zustand. Eine Transaktion wird durch Anforderung von Sperren initialisiert und durch Freigabe dieser Sperren abgeschlossen. Trigger Eine Ausnahmebedingung, die es ermöglicht auf bestimmt Änderungen zu einem festgelegten Zeitpunkt zu reagieren. Die Reaktion besteht in der Regel darin, gespeicherte Prozeduren aufzurufen, die ihrerseits entsprechende Prüfungen vornehmen. Trigger werden in der Regel direkt im Rahmen einer Datenänderung oder am Transaktionsende "gefeuert". Verklemmung, Deadlock Zustand einer Datenbank, in dem sich mehrere Benutzer gegenseitig durch Sperren gemeinsam benötigter Objekte blockieren. Dieser Zustand kann erst dann gelöst werden, wenn mindestens einer dieser Benutzer auf die Bearbeitung seiner Probleme zum gegenwärtigen Zeitpunkt verzichtet. Verteiltes DBMS Mehrere DBMS, die auf vernetzten Rechnern installiert sind und die über ein geeignetes Protokoll miteinander kommunizieren. Virtuelle Tabelle Sicht auf eine oder mehrere Tabellen. Es besteht die Möglichkeit, Benutzer nur bestimmte Teile von Tabellen sichtbar zu machen. Bei jedem Zugriff auf eine virtuelle Tabelle wird diese mit Hilfe der im Katalog gespeicherten Beschreibung neu zusammengestellt. 221 Vorübersetzer / Precompiler Ein Programm, das einen Quelltext, der eingebetteten SQL-Anweisungen enthält, so aufbereitet, dass der gewünschte Sprachübersetzer das mit dem Vorübersetzer erzeugte Programm übersetzen kann. Zwei-Phasen-Commit Technik des Transaktionsabschlusses in einem verteilten Datenbanksystem. Wurden in einer Transaktion Veränderungen an mehreren Knoten vorgenommen, so müssen alle diese Knoten die Änderungen vollziehen oder ablehnen. Im Zwei-Phasen-Commit wird in der ersten Phase die Bereitschaft aller beteiligten Knoten zu einem Commit hergestellt, in der zweiten Phase vollzieht jeder Knoten das Commit. [Achilles, SQL] 222