Skriptum zur Vorlesung DATENBANKSYSTEME VO 181.038 (alter Studienplan) VO 181.146 (neuer Studienplan) WS 2002 Gerald Pfeifer Michael Schrefl Katrin Seyr Markus Stumptner 0.2 Inhaltsverzeichnis I Allgemeines 1 1 Einleitung 1.1 Das Datenbanksystem . . . . . . . . . . . . . . . . . . . . . . . . 1.1.1 Die Hardware . . . . . . . . . . . . . . . . . . . . . . . . 1.1.2 Die Software . . . . . . . . . . . . . . . . . . . . . . . . 1.1.3 Die Daten . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.4 Die Benutzer . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Warum ein Datenbanksystem? . . . . . . . . . . . . . . . . . . . 1.2.1 Von Einzellösungen zu Datenbanksystemen . . . . . . . . 1.2.2 Funktionalität von Datenbanksystemen . . . . . . . . . . 1.2.2.1 Persistente Datenhaltung . . . . . . . . . . . . 1.2.2.2 Hintergrundspeicherverwaltung . . . . . . . . . 1.2.2.3 Recovery . . . . . . . . . . . . . . . . . . . . . 1.2.2.4 Concurrency Control . . . . . . . . . . . . . . 1.2.2.5 Ad-hoc-Abfragen . . . . . . . . . . . . . . . . 1.2.2.6 Datenschutz . . . . . . . . . . . . . . . . . . . 1.2.3 Komponenten eines Datenbanksystems . . . . . . . . . . 1.2.4 Vorteile des Einsatzes von Datenbanksystemen . . . . . . 1.3 Architektur eines Datenbanksystems . . . . . . . . . . . . . . . . 1.4 Die Datenmodellierung . . . . . . . . . . . . . . . . . . . . . . . 1.4.1 Begriffe . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.2 Datenmodelle im Datenbankentwurf . . . . . . . . . . . . 1.5 Der Datenbank-Life-Cycle“ . . . . . . . . . . . . . . . . . . . . ” 1.5.1 Die Anforderungsanalyse . . . . . . . . . . . . . . . . . . 1.5.2 Der konzeptionelle Entwurf . . . . . . . . . . . . . . . . 1.5.3 Der logische Entwurf . . . . . . . . . . . . . . . . . . . . 1.5.4 Der physische Entwurf . . . . . . . . . . . . . . . . . . . 1.5.5 Verteilter Entwurf . . . . . . . . . . . . . . . . . . . . . . 1.5.6 Datenbankimplementierung, -überwachung und -wartung . Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 2 2 3 3 4 5 6 7 7 8 9 11 12 12 13 16 17 18 18 19 19 20 22 23 24 24 1 i INHALTSVERZEICHNIS 0.ii II Datenmodellierung 2 3 1 Konzeptionelle Datenmodelle und das ER Modell 2.1 Modellierungskonzepte konzeptioneller Datenmodelle . . . . . . . 2.2 Elementare ER-Konstrukte . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Grundlegende Objekte: Entities, Beziehungen und Attribute 2.2.2 Komplexität einer Beziehung . . . . . . . . . . . . . . . . . 2.2.3 Existenz einer Entity in einer Beziehung . . . . . . . . . . . 2.2.4 Grad einer Beziehung . . . . . . . . . . . . . . . . . . . . 2.2.5 Attribute einer Beziehung . . . . . . . . . . . . . . . . . . 2.3 Erweiterte ER-Konstrukte . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Die Generalisierung . . . . . . . . . . . . . . . . . . . . . 2.3.2 ER-Constraints . . . . . . . . . . . . . . . . . . . . . . . . 2.3.2.1 Exklusionsbedingungen . . . . . . . . . . . . . . 2.4 Objektorientierte Datenmodellierung . . . . . . . . . . . . . . . . . 2.4.1 Objektorientierte Konzepte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 3 3 6 7 8 9 10 10 11 12 13 13 Das Relationenmodell 3.1 Formalisierung des Relationenmodells . . . . . . . . . . . 3.2 Operationen auf Relationen . . . . . . . . . . . . . . . . . 3.2.1 Die Mengenoperationen . . . . . . . . . . . . . . 3.2.2 Die Selektion . . . . . . . . . . . . . . . . . . . . 3.2.2.1 Erweiterung der Selektion . . . . . . . . 3.2.3 Die Projektion . . . . . . . . . . . . . . . . . . . 3.2.4 Der Verbund . . . . . . . . . . . . . . . . . . . . 3.2.4.1 Der natürliche Verbund (natural join) . . 3.2.4.2 Das Kartesische Produkt . . . . . . . . . 3.2.4.3 Der Gleichverbund (equi-join) . . . . . 3.2.4.4 Der Theta-Verbund (theta-join) . . . . . 3.2.5 Die Division . . . . . . . . . . . . . . . . . . . . 3.2.6 Der Semiverbund (semijoin) . . . . . . . . . . . . 3.3 Nullwerte . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Auswertung von Nullwerten . . . . . . . . . . . . 3.3.2 Äußerer Verbund (outer join) . . . . . . . . . . . . 3.4 Übersetzung des ER ins Relationenmodell . . . . . . . . . 3.5 NF2 -Relationen . . . . . . . . . . . . . . . . . . . . . . . 3.6 Weitere Sprachen für das Relationenmodell . . . . . . . . 3.6.1 Der Relationenkalkül . . . . . . . . . . . . . . . . 3.6.1.1 Der Relationenkalkül mit Tupelvariablen 3.6.1.2 QBE — Query By Example . . . . . . . 3.7 Übungsbeispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 4 4 5 6 6 7 7 7 9 10 11 12 13 14 14 15 16 16 18 18 18 21 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . INHALTSVERZEICHNIS 4 5 0.iii SQL 4.1 Interaktives SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Allgemeines . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.2 Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.3 Abfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.3.1 Grundkonstruktion einer SQL-Abfrage . . . . . . 4.1.3.2 Mengenoperationen . . . . . . . . . . . . . . . . 4.1.3.3 Gruppierung und Aggregatfunktionen . . . . . . . 4.1.3.4 Teilabfragen . . . . . . . . . . . . . . . . . . . . 4.1.4 Nullwerte . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.4.1 Der Outer Join in SQL . . . . . . . . . . . . . . . 4.1.5 Datendefinition . . . . . . . . . . . . . . . . . . . . . . . . 4.1.5.1 Erzeugen von Relationenschemata . . . . . . . . 4.1.5.2 Globale Integritätsbedingungen . . . . . . . . . . 4.1.5.3 Ändern von Relationenschemata . . . . . . . . . 4.1.5.4 Entfernen von Relationenschemata . . . . . . . . 4.1.6 Datenmanipulation . . . . . . . . . . . . . . . . . . . . . . 4.1.6.1 Einfügen von Daten . . . . . . . . . . . . . . . . 4.1.6.2 Löschen von Daten . . . . . . . . . . . . . . . . 4.1.6.3 Ändern von Daten . . . . . . . . . . . . . . . . . 4.1.7 Benutzersichten . . . . . . . . . . . . . . . . . . . . . . . . 4.1.8 Zugriffskontrolle . . . . . . . . . . . . . . . . . . . . . . . 4.1.9 Transaktionsverwaltung . . . . . . . . . . . . . . . . . . . 4.1.10 Definition von Dateiorganisationsformen und Zugriffspfaden 4.1.11 Abstrakte Datentypen . . . . . . . . . . . . . . . . . . . . . 4.1.12 Rekursion in SQL-3 . . . . . . . . . . . . . . . . . . . . . 4.1.13 Trigger in SQL-3 . . . . . . . . . . . . . . . . . . . . . . . 4.2 Embedded SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Prinzip der Einbindung . . . . . . . . . . . . . . . . . . . . 4.2.2 Cursor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 SQL-2 versus SQL-3 Standard . . . . . . . . . . . . . . . . . . . . 4.4 Übungsaufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 2 2 4 5 7 7 8 10 13 14 14 15 16 16 16 16 17 17 18 19 20 20 20 22 25 26 26 27 27 30 Datalog 5.1 Motivation . . . . . . . . . . . . . . . . . . . . . 5.2 Die Syntax von Datalog . . . . . . . . . . . . . . 5.2.1 Einschränkungen zur Syntax von Datalog 5.3 Semantik von Datalog . . . . . . . . . . . . . . . 5.3.1 Logische Semantik von Datalog . . . . . 5.3.2 Operationale Semantik von Datalog . . . 5.4 Erweitertes Datalog mit Negation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 2 3 3 5 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 0.iv 5.5 6 7 8 INHALTSVERZEICHNIS 5.4.1 Graphendarstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.2 Semanik von Datalog mit Negation . . . . . . . . . . . . . . . . . . Übungsbeispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Funktionale Abhängigkeiten 6.1 Definition von funktionalen Abhängigkeiten . . . . . . . . . 6.2 Ableitungsregeln für funktionale Abhängigkeiten . . . . . . 6.3 Äquivalenz von Systemen von funktionalen Abhängigkeiten 6.4 Inklusionsabhängigkeiten . . . . . . . . . . . . . . . . . . . 6.4.1 Definition von Inklusionsabhängigkeiten . . . . . . 6.4.2 Ableitungsregeln für Inklusionsabhängigkeiten . . . 6.5 Übungsbeispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Normalformen 7.1 Erste und Zweite Normalform . . . . . . . . . . . . . . . . . . . . . . . 7.2 Die Dritte Normalform . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3 Die Boyce-Codd Normalform . . . . . . . . . . . . . . . . . . . . . . . 7.4 Zerlegungen von Relationenschemata . . . . . . . . . . . . . . . . . . . 7.4.1 Verbundtreue Zerlegung in 3NF bzw. BCNF . . . . . . . . . . . . 7.4.2 Verbund- und abhängigkeitstreue Zerlegung in 3NF bzw. BCNF . 7.4.3 Berechnung von Überdeckungen für eingebettete Abhängigkeiten 7.4.3.1 Der Algorithmus RBR (Reduction By Resolution) . . . 7.4.4 Der Synthesealgorithmus . . . . . . . . . . . . . . . . . . . . . . 7.5 Übungsbeispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Physisches Datenbankdesign 8.1 Grundlegende Begriffe . . . . . . . . . . . . . . . . . . . . . 8.1.1 Clustering . . . . . . . . . . . . . . . . . . . . . . . . 8.1.1.1 Clustering-Index . . . . . . . . . . . . . . . 8.1.1.2 Geclusterte Speicherung von Datensätzen . 8.1.2 Primär- und Sekundärorganisation . . . . . . . . . . . 8.2 Speicherstrukturen für Relationen . . . . . . . . . . . . . . . 8.2.1 Kriterien zur Auswahl von Speicherstrukturen . . . . . 8.2.1.1 Ungeordnete Dateien . . . . . . . . . . . . 8.2.1.2 Indexsequentielle Dateien . . . . . . . . . . 8.2.1.3 Clustered . . . . . . . . . . . . . . . . . . . 8.2.1.4 Hashorganisation . . . . . . . . . . . . . . 8.2.1.5 B ∗ -Baum . . . . . . . . . . . . . . . . . . 8.2.2 Füllgrad . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.3 Zugriffszeitverhalten . . . . . . . . . . . . . . . . . . 8.2.4 Physische Datenorganisation in kommerziellen DBMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 11 14 . . . . . . . 1 1 3 5 9 9 9 11 . . . . . . . . . . 1 1 3 5 5 8 11 13 15 15 17 . . . . . . . . . . . . . . . 1 1 1 2 2 3 3 3 4 5 5 6 7 8 9 10 INHALTSVERZEICHNIS 8.2.4.1 8.2.4.2 8.2.4.3 0.v INGRES . . . . . . . . . . . . . . . . . . . . . . . . . . . ORACLE . . . . . . . . . . . . . . . . . . . . . . . . . . MS-SQL Server . . . . . . . . . . . . . . . . . . . . . . . III Das Datenbankmanagementsystem 9 1 Optimierung 9.1 Logische Abfragenoptimierung . . . . . . . . . . . . . . . 9.1.1 Algebraische Optimierung . . . . . . . . . . . . . 9.1.1.1 Zusammenfassen gleicher Teilausdrücke 9.1.1.2 Regeln für Join und kartesisches Produkt 9.1.1.3 Regeln für Selektion und Projektion . . 9.1.2 Ein einfacher Optimierungsalgorithmus . . . . . . 9.2 Join-Algorithmen . . . . . . . . . . . . . . . . . . . . . . 9.2.1 Nested-loop Join . . . . . . . . . . . . . . . . . . 9.2.2 Join mit Hilfe von Indexen . . . . . . . . . . . . . 9.2.3 Hash-Join . . . . . . . . . . . . . . . . . . . . . . 9.2.4 Clustering . . . . . . . . . . . . . . . . . . . . . . 9.3 Der Semijoin (Semiverbund) . . . . . . . . . . . . . . . . 9.4 Übungsbeispiele . . . . . . . . . . . . . . . . . . . . . . . 10 Concurrency Control 10.1 Begriffsklärungen . . . . . . . . . . . . . . . . . . . . . 10.1.1 Synchronisationsprobleme . . . . . . . . . . . . 10.1.2 ACID Eigenschaften von Transaktionen . . . . . 10.1.3 Ausführung mehrerer Transaktionen . . . . . . . 10.1.4 Konfliktrelation einer Ausführung . . . . . . . . 10.1.5 Serialisierbarkeit . . . . . . . . . . . . . . . . . 10.1.6 Test auf Serialisierbarkeit . . . . . . . . . . . . 10.2 Sperrprotokolle . . . . . . . . . . . . . . . . . . . . . . 10.2.1 Gültige Ausführungen . . . . . . . . . . . . . . 10.2.2 Wohlgeformte Transaktionen . . . . . . . . . . . 10.2.3 Das 2-Phasen-Sperrverfahren (2-Phase-Locking) 10.2.4 Deadlock . . . . . . . . . . . . . . . . . . . . . 10.2.5 Das Baumprotokoll . . . . . . . . . . . . . . . . 10.2.6 Das Hierarchische Sperrprotokoll . . . . . . . . 10.3 Zeitstempelverfahren (Time Stamping) . . . . . . . . . . 10.4 Transaktionen in SQL . . . . . . . . . . . . . . . . . . . 10.5 Übungsbeispiele . . . . . . . . . . . . . . . . . . . . . . 10 10 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 2 3 3 3 5 7 7 8 9 9 10 11 . . . . . . . . . . . . . . . . . 1 1 3 5 6 7 9 10 10 11 12 13 14 14 15 17 19 21 0.vi INHALTSVERZEICHNIS 11 Wiederanlauf (Recovery) 11.1 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1.1 Zielsetzung . . . . . . . . . . . . . . . . . . . . . . . . . 11.1.2 Reihenfolge von Ausführungen . . . . . . . . . . . . . . 11.1.3 Nichtwiederherstellbare Ausführung . . . . . . . . . . . . 11.1.4 ACA Ausführungen . . . . . . . . . . . . . . . . . . . . 11.1.5 Strikte Ausführung von Transaktionen . . . . . . . . . . . 11.2 Pufferverwaltung . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2.1 Privater Arbeitsbereich . . . . . . . . . . . . . . . . . . . 11.2.2 Write Ahead-Protokoll . . . . . . . . . . . . . . . . . . . 11.3 Wiederanlaufverfahren mit Logprotokoll . . . . . . . . . . . . . . 11.3.1 Das Logprotokoll . . . . . . . . . . . . . . . . . . . . . . 11.3.2 Wiederanlauf nach einem Transaktionsabbruch . . . . . . 11.3.3 Wiederanlauf nach einem Systemabsturz . . . . . . . . . 11.3.4 Checkpoints . . . . . . . . . . . . . . . . . . . . . . . . 11.3.5 Wiederanlauf mit Checkpoints nach einem Systemabsturz 11.3.6 Wiederanlauf nach einem Plattenfehler . . . . . . . . . . 11.4 Schattenkopieverfahren (shadow paging) . . . . . . . . . . . . . . 11.4.1 Die Grundidee . . . . . . . . . . . . . . . . . . . . . . . 11.4.2 Die Realisierung . . . . . . . . . . . . . . . . . . . . . . 11.5 Übungsbeispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 3 3 4 4 6 8 9 9 9 11 11 12 12 14 16 16 16 19 Teil I Allgemeines 1 Kapitel 1 Einleitung 1.1 Das Datenbanksystem Ein Datenbanksystem (DBS) ist ein computerisiertes System, das Information speichert und bei Bedarf zur Verfügung stellt. Unter Information verstehen wir in diesem Zusammenhang nicht nur den reinen Wert der Daten, sondern auch deren Bedeutung für die Benutzer. Das Datenbanksystem ist Teil eines Informationssystems. Unter diesem Oberbegriff werden alle Systeme zusammengefasst, die einerseits Informationen über bestimmte Anwendungen bzw. Außenweltsituationen (z.B. customer relationship management einer Firma, eine Bibliothek, Börsenkurse usw.) speichern und (zentral) verwalten. Andererseits ermöglichen sie aber auch das Arbeiten mit diesen Informationen nach bestimmten Gesichtspunkten bzw. mit verschiedenen Zielsetzungen, insbesondere auch von anderen Programmen aus. Definition 1.1 [Vossen 1999] Ein Informationssystem ist ein Werkzeug zur Erfassung und Kommunikation von Information zum Zwecke der Erfüllung der Anforderungen seiner Benutzer, der (Geschäfts-) Aktivitäten ihres Unternehmens und zur Erreichung der Unternehmensziele. Daher unterstützt ein Informationssystem die Unternehmensaktivitäten durch Bereitstellung der benötigten Information oder durch Automatisierung der mit den Aktivitäten zusammenhängenden Vorgänge. Es umfasst sämtliche zu diesem Zweck im Unternehmen vorhandenen Ressourcen, d.h. die Daten, die Datenbanksoftware, die nötige Rechner-Hardware, die Personen, die die Daten nutzen und verwalten, die relevante Anwendungssoftware sowie die Programmierer, die diese entwickeln. Grob gesehen interagieren vier Komponenten in einem Informationssystem: Hardware, Software, die Daten und die Benutzer (siehe Abbildung 1.1). Die Software (das Datenbankmanagementsystem, DBMS) und die Daten (die Datenbank, DB) bilden gemeinsam das eigentliche Datenbanksystem. 1 KAPITEL 1. EINLEITUNG 1.2 Datenbankmanagementsystem Datenbank Daten Daten Applikationsprogramme Endbenutzer Abbildung 1.1: Vereinfachte Sicht eines Informationssystems 1.1.1 Die Hardware Auf die Hardware werden wir im Weiteren nicht näher eingehen, da dies den Rahmen dieser Lehrveranstaltung sprengen würde. Wir wollen an dieser Stelle nur aufzählen, welche Hardware für den Betrieb eines Datenbanksystems notwendig ist: • Das Rechnersystem: Prozessoren, Caches, Hauptspeicher, Buffer, die zur Ausführung der Datenbanksystemsoftware notwendig sind. • Der Sekundärspeicher: meist Platten- und Bandsysteme, die einerseits die Daten und andererseits Datenstrukturen zum schnellen Zugriff (Indexe) und zur Datensicherung (Logs) lokal speichern und den dazugehörigen Input/Output Devices. Weiters sind noch Backup-Geräte zur Sicherung der Daten notwendig. • ein Kommunikationssystem/Rechnernetz, wenn das Datenbanksystem nicht im singleuser Betrieb laufen soll. 1.1.2 Die Software Das Datenbankmanagementsystem (DBMS) ist jener Teil der Software, der zwischen den eigentlichen Daten und den Benutzern dieser Daten liegt und alle Anfragen der Benutzer verarbeitet. Es stellt jene Einrichtungen zur Verfügung, die notwendig sind, um neue Daten anzulegen, Daten zu löschen, Daten abzufragen und Daten zu verändern. Das DBMS ist auch dafür zuständig, alle hardwarespezifischen Details vor dem Benutzer zu verbergen und so transparent zu machen. Dazu gehören z.B. die Anzahl der Platten oder generell die konkrete Datenstruktur der gespeicherten Daten sowie die Anzahl der Prozessoren und Speichergrößen, die zur Datenverarbeitung eingesetzt werden. Weiters realisiert ein DBMS die üblicherweise erwartete Datenbankfunktionalität wie persistente Datenhaltung, Hintergrundspeicherverwaltung, Recovery (Wiederanlauf) und Concurrency Control (Synchronisation). KAPITEL 1. EINLEITUNG 1.3 Heutzutage existiert eine Vielfalt von DBMSen sowohl kommerzieller als auch freier Natur, deren Einsatz von Handhelds bis hin zu Großrechnern und massiven Clustern reicht. Daher ist sowohl Multi-user Betrieb als auch Single-user Betrieb zu ermöglichen. In einem Single-user System wird zu einem bestimmten Zeitpunkt von maximal einem Benutzer auf die Daten zugegriffen, während in einem Multi-user System viele Benutzer gleichzeitig auf die Daten zugreifen. Beispiele für Multi-user Systeme sind Buchungssysteme von Fluglinien oder Anwendungen im Bankenbereich. Eine weitere Aufgabe von DBMSen im Multi-user Betrieb ist, den Benutzern die Sicht eines single-user Betriebs auf die Daten zu geben. Probleme, die in diesem Zusammenhang entstehen, werden in Kapitel 10 behandelt. Die Software besteht heutzutage aber nicht nur aus dem DBMS, sondern auch aus Entwicklungsumgebungen, Designhilfen, Report Writern und so weiter. Die Behandlung dieser Werkzeuge würde jedoch den Umfang dieser Lehrveranstaltung sprengen. 1.1.3 Die Daten Die Daten werden vom DBMS in einer Datenbank abgelegt. Eine Datenbank ist also eine Art Behälter, der eine Menge von logisch zusammengehörigen Daten enthält. In einem DBMS können mehrere verschiedene Datenbanken enthalten sein und eine Applikation kann auch auf mehrere Datenbanken zugreifen. Die Beschreibung der Daten einer Datenbank mit Hilfe eines Datenmodells wird als Datenbankschema bezeichnet. Das Datenbankschema ist von den eigentlichen Daten zu unterscheiden, der Ausprägung der Datenbank. Die Ausprägung umfasst die Gesamtheit der Daten, die in einer bestimmten Datenbank zu einem bestimmten Zeitpunkt vorhanden sind, und wird auch als Datenbankzustand bezeichnet. Eine kurze Einführung in die Datenmodellierung geben wir in diesem Kapitel im Abschnitt 1.4, eine genaue Beschreibung folgt in Kapitel 2. Unter einer integrierten Datenhaltung verstehen wir den Umstand, dass die Datenbank als Sammlung von unterschiedlichen Datenfiles oder Tabellen gesehen werden kann, zwischen denen Redundanz so weit als möglich eliminiert wird. Das war einer der Gründe, warum sich Datenbanksysteme im Laufe der Zeit immer größerer Beliebtheit erfreuten. Ein weiterer war, dass es relativ einfach möglich ist, die Daten mehreren Benutzern für unterschiedliche Zwecke und in unterschiedlichen Sichtweisen zur Verfügung zu stellen, wodurch die Wartung und Aktualisierung der Daten wesentlich erleichtert wird. 1.1.4 Die Benutzer Die Benutzer eines DBS können wir in drei Gruppen einteilen: in Datenbank- und Datenadministratoren, Applikationsprogrammierer und Endbenutzer. Die Datenadministratoren (DA) führen die Datenmodellierung durch, die Datenbankadministratoren (DBA) sind für die Implementierung und technische Realisierung der in der Phase der Datenmodellierung getroffenen Entscheidungen zuständig. In kleineren Projekten sind Datenbankadministrator, Datenadministrator und Anwendungsprogrammierer oft ei- KAPITEL 1. EINLEITUNG 1.4 Produktion Verkauf Fakturierung Zugriffsoperationen Zugriffsoperationen Zugriffsoperationen Angestellte Kunden Kunden Teile Teile Teile Abbildung 1.2: Die Einzellösung ne Person. In großen Anwendungen, wie zum Beispiel im Bankenbereich oder bei Fluglinien, sind eine Gruppe von Datenbankadministratoren nur für die technische Umsetzung, die Performance des DBS und für die Wartung des Systems im Fehlerfall (Soft- bzw. Hardware-Fehler) zuständig. Die Datenadministratoren sind für die Daten an sich zuständig. Sie entscheiden, welche Daten in welcher Form gespeichert werden, welche Verfahren zur Datenwartung eingesetzt werden und wer in welcher Form auf die Daten zugreifen darf. Die Applikationsprogrammierer sind für die Entwicklung der Anwendungen, die auf die Daten im DBS zugreifen, zuständig. Diese Applikationen werden üblicherweise in den heute gängigen objektorientierten oder prozeduralen Programmiersprachen wie Java, C++, C, oder Pascal (Delphi) geschrieben. Vielfach wird dabei über genormte Schnittstellen wie ODBC (Open DataBase Connectivity) oder JDBC (Java DataBase Connectivity) mit dem DBS kommuniziert, d.h., der Code kann unabhängig vom konkreten DBMS, das letztendlich verwendet wird, geschrieben werden. Eine andere Möglichkeit ist, die entsprechenden Features der einzelnen DBMS-Anbieter und die vom DBMS zur Verfügung gestellten Schnittstellen für die jeweiligen Programmiersprachen direkt zu verwenden. Die Endbenutzer schließlich greifen entweder über die im letzten Punkt beschriebenen Applikationen auf die Daten zu oder über ein Interface, das vom DBMS zur Verfügung gestellt wird. Jedes DBMS stellt eine gewisse Anzahl von eingebauten Modulen zur Verfügung, mittels derer die Endbenutzer direkt auf die Daten zugreifen können. Eines dieser Module ist üblicherweise eine interaktive Abfragesprache, wobei derzeit am häufigsten SQL oder eine Abart von SQL anzutreffen sind. 1.2 Warum ein Datenbanksystem? In diesem Abschnitt geben wir zuerst einen kurzen historischen Abriss zur Entstehung von integrierter Datenverarbeitung und damit zur Entwicklung von Datenbanksystemen, danach besprechen wir die Funktionalität von Datenbanksystemen und zum Schluss werden wir kurz die Vorteile, die die Verwendung von Datenbanksystemen mit sich bringt, beschreiben. KAPITEL 1. EINLEITUNG 1.5 Produktion Verkauf Fakturierung Zugriffsoperationen Zugriffsoperationen Zugriffsoperationen Personen Datei Teile Datei Abbildung 1.3: Die Integrierte Datenverarbeitung 1.2.1 Von Einzellösungen zu Datenbanksystemen Informationssysteme sollen leicht wartbar, leicht erweiterbar und ihre Bedienung leicht erlernbar sein. Seit den ersten Implementierungen von Informationssystemen wurden diesbezüglich große Fortschritte gemacht. Die ersten computerunterstützten Informationssysteme wurden in Form von Einzell ösungen (siehe Abbildung 1.2), als einzelne Anwendungsprogramme mit privaten Dateien, realisiert. Diese Programme verwendeten unmittelbar das zugrundeliegende Dateisystem auf dem jeweiligen Rechner. Gleichartige Daten wurden in Dateien (Files) gespeichert, die selbst wieder aus einzelnen Datensätzen (Records) bestanden. Diese wiederum waren aus Einträgen oder Feldern zusammengebaut, die somit die kleinste Dateneinheit darstellten. Diese Systeme waren schwer wartbar, da mehrfach verwendete Daten redundant gespeichert wurden. Diese Redundanz sowohl der gespeicherten Daten als auch des Programmcodes (da für jede Anwendung entsprechende Zugriffsfunktionen implementiert wurden) behinderte sowohl den Betrieb als auch die Wartung solcher Systeme. Daher wurden bei der Integrierten Datenverarbeitung (siehe Abbildung 1.3) Dateien mit Hilfe von Dateisystemen in mehreren Anwendungsprogrammen verwendet und in sogenannten Data Dictionaries Verzeichnisse über die Verwendung von Daten in Programmen zentral geführt. Programme und Dateien waren jedoch voneinander abhängig. Änderungen in der Organisationsform einer Datei (z.B. der Sortierreihenfolge der Datensätze) oder eine Änderung des Satzaufbaus machten eine Änderung aller Programme notwendig, die diese Datei benutzten, auch dann, wenn für diese die Änderung inhaltlich bedeutungslos war. Heute werden Informationssysteme meist mit Hilfe von Datenbanksystemen (siehe Abbildung 1.4) realisiert, die unabhängig von bestimmten Anwendungsprogrammen existieren und eine klare Trennungsebene zwischen Anwendungsprogrammen und Daten darstellen. Einerseits ermöglicht diese Trennung die sogenannte physische Datenunabhängigkeit, d.h. Programme und Ad-hoc-Abfragen sind von den konkreten Speicher- oder Zugriffsmethoden unabhängig. Andererseits stellen DBMSe ein Datenmodell“, also eine Sprache zur ” KAPITEL 1. EINLEITUNG 1.6 Produktion Verkauf Fakturierung Zugriffsoperationen Zugriffsoperationen Zugriffsoperationen Datenbanksystem Personen Datei Teile Datei Abbildung 1.4: Das Datenbanksystem Beschreibung der Datenstrukturen zur Verfügung, die es möglich macht, einzelne Programme auf speziellen logischen Darstellungen der gespeicherten Datenbank arbeiten zu lassen, sodass bestimmte Änderungen der Datenbasis selbst vor den Anwendungsprogrammen versteckt werden können, ein Zustand, den wir logische Datenunabh ängigkeit bezeichnen. Zusammengefasst ergeben sich folgende Vorteile: • Redundanz ist weitgehend vermeidbar, • ein konsistenter Datenbankzustand gemäß Integritätsbedingungen ist gesichert, • flexibler Gebrauch der Daten wird ermöglicht. Konventionelle Datenbanksysteme unterstützen die gemeinsame Verwendung von Daten zwischen mehreren Anwendungen. Objektorienierte Datenbanksysteme (siehe Abbildung 1.5) erweitern diese Idee der gemeinsamen Benutzung“ auf Operationen über diese ” Daten. Das Schema einer objektorientierten Datenbank besteht aus einer Menge von Objektklassen. Eine Objektklasse beschreibt eine Datenstruktur und eine Menge von auf dieser Datenstruktur definierten Operationen. Objekte der zu beschreibenden Welt werden als Instanzen von Objektklassen repräsentiert. Ein solches Objekt darf nur über die für seine Objektklasse definierten Operationen modifiziert werden. 1.2.2 Funktionalität von Datenbanksystemen In diesem Abschnitt beschreiben wir die wichtigsten Eigenschaften von Datenbanksystemen aus Benutzersicht, als da sind: persistente Datenhaltung, Hintergrundspeicherverwaltung, Recovery (Wiederanlauf), Concurrency Control (Synchronisation), Unterstützung von Ad-hocAbfragen und Datenschutz/Zugriffskontrolle. KAPITEL 1. EINLEITUNG 1.7 Produktion Verkauf Fakturierung oo Datenbanksystem Personen Teile Operationen Operationen Daten Daten Abbildung 1.5: Das Objektorientierte Datenbanksystem 1.2.2.1 Persistente Datenhaltung Ein Datenbankmanagementsystem muss Mechanismen zur Verfügung stellen, die eine persistente Speicherung von Daten sicherstellen. Unter Persistenz verstehen wir, dass die Daten in der Datenbank über die Ausführungszeit von Anwendungsprogrammen hinaus erhalten bleiben, im Gegensatz zu Daten, die entweder in Programmvariablen von Anwendungsprogrammen gehalten werden oder Input- bzw. Output-Daten sind, und daher flüchtige (transiente) Daten genannt werden. Input-Daten sind jene Daten, die in das System meist interaktiv über ein Terminal oder mittels OCR (Banküberweisungen) eingegeben werden. Input-Daten können persistente Daten verändern oder selbst zu persistenten Daten werden, sind aber nicht Teil der Datenbank an sich. Ähnlich verhält es sich mit Output-Daten, die meist über Drucker oder Bildschirm ausgegeben werden. Sie leiten sich zwar oft von den persistenten Daten ab, sind aber nicht Teil der Datenbank. Die Daten werden üblicherweise auf einem Hintergrundspeicher (Sekundärspeicher, z.B. Platte) persistent gehalten; Daten, die ausschließlich im Hauptspeicher (Primärspeicher) gehalten werden, sind flüchtig, d.h. sie überleben die Programmausführung nicht. Für den Benutzer eines Datenbankmanagementsystems ist nicht sichtbar, welche Daten sich während der Benutzung der Datenbank nur im Sekundärspeicher befinden und welche vom DBMS kurzfristig zusätzlich im Primärspeicher gehalten werden. 1.2.2.2 Hintergrundspeicherverwaltung Ein Datenbankmanagementsystem unterstützt die Verwaltung großer Datenmengen, die üblicherweise nicht zur Gänze im Primärspeicher Platz finden. Die Datenbank wird persistent im Hintergrundspeicher (oder Sekundärspeicher) gehalten. Nachdem Programme nur auf Daten im Primärspeicher direkt zugreifen können, werden Ausschnitte der Datenbank zeitweise auch in einem Teil des Primärspeichers, dem Datenbankpuffer, verwaltet. 1.8 KAPITEL 1. EINLEITUNG Nachdem ein Plattenzugriff etwa um einen Faktor zehntausend länger dauert als ein Hauptspeicherzugriff, sind spezielle Techniken notwendig, um unnötige Plattenzugriffe zu vermeiden. Üblicherweise werden daher nicht einzelne Datensätze zwischen den Speichermedien transferiert, sondern ganze Bereiche. Die Speichermedien sind in Bl öcke gegliedert, und es werden aus Effizienzgründen jeweils alle Datensätze, die sich in einem Block befinden, übertragen. Spezielle Puffer-Ersatz-Strategien werden verwendet, um bei Platzmangel im Datenbankpuffer zu entscheiden, welche Blöcke wieder auf die Platte ausgelagert werden sollen. Dabei kommen verschiedene Strategien zum Einsatz, wie z.B. least recently used“ oder least fre” ” quently used“. Wenn wir den Haupt- und Hintergrundspeicher mit unserem Schreibtisch und der Ablage im Büro vergleichen, dann lässt sich die Pufferstrategie mit der gewählten Vorgehensweise vergleichen, nach der wir auf dem Schreibtisch durch das Wegräumen von Akten Platz für neue Akten schaffen. Aus Effizienzgründen ist es wichtig, wie die Datensätze den Blöcken im Sekundärspeicher zugeordnet sind. Angenommen wir verteilen jene Unterlagen, die wir für eine wichtige Tätigkeit brauchen, auf fünf verschiedene Ordner, die überdies sehr viel andere Unterlagen enthalten, dann müssen wir jedesmal, wenn wir diese Tätigkeit verrichten, für alle fünf Ordner am Schreibtisch Platz finden. Außerdem verbrauchen die restlichen Unterlagen, die wir in jenem Fall gar nicht benötigen, viel Platz in den Ordnern. Sogenannte Cluster-Techniken gruppieren Datensätze so, dass Datensätze — unter Umständen auch verschiedener Dateien — auf die oft gemeinsam zugegriffen wird, physisch benachbart gespeichert werden. Weiters werden verschiedene Indextechniken verwendet, um Daten auf dem Hintergrundspeicher rasch zu finden. Wie etwa Indexeinträge in Büchern auf die Buchseite verweisen, in denen ein Stichwort erwähnt wird, so verweisen Indexeinträge in Datenbanken auf jene Blöcke, in denen Datensätze mit bestimmten Feldwerten vorkommen. Eine genaue Behandlung dieser Thematik geben wir in Kapitel 8. 1.2.2.3 Recovery Datenbankmanagementsysteme unterstützen Änderungen der Datenbank durch Transaktionen. Eine Transaktion ist eine Folge von Aktionen, das sind Lese- und Schreibzugriffe auf Daten der Datenbank, die eine Datenbank von einem konsistenten Zustand in einen anderen konsistenten Zustand überführt. Die Recovery Einheit eines Datenbankmanagementsystems gewährleistet die Atomarität und die Dauerhaftigkeit (Persistenz) von Transaktionen. Atomarit ät bedeutet, dass alle Aktionen einer Transaktion ausgeführt werden oder keine. Dauerhaftigkeit bedeutet, dass alle Effekte einer einmal erfolgreich abgeschlossenen Transaktion trotz etwaiger anschließend auftretender Hard- und Softwarefehler erhalten bleiben. Fehler, die ein Datenbankmanagementsystem abfangen muss, sind unter anderem: 1. vom Anwendungsprogramm erkannte logische Fehler (z.B. Konto nicht gedeckt“), ” KAPITEL 1. EINLEITUNG 1.9 2. vom System erkannte Fehler (z.B. zyklisches Warten mehrerer Programme auf die Freigabe einer Ressource), 3. der Verlust des Hauptspeicherinhalts (z.B. Stromausfall) und 4. der Verlust der Daten des Plattenspeichers (z.B. Disk Crash). Der Start, der erfolgreiche Abschluss bzw. der Abbruch einer Transaktion werden dem Datenbankmanagementsystem durch die speziellen Befehle begin transaction, commit transaction bzw. abort transaction angezeigt. Beispiel 1.1 Ein typisches Beispiel einer Transaktion ist die Überweisung eines Geldbetrages von einem Gehaltskonto auf ein Sparbuch. Atomarität bedeutet in diesem Fall, dass die Überweisung zur Gänze durchgeführt wird (Abbuchung vom Gehaltskonto und Aufbuchung auf das Sparbuch) oder gar nicht (weder Abbuchung noch Aufbuchung). Tritt während der Überweisung nach der Abbuchung, aber noch vor der Aufbuchung ein Systemabsturz ein, so möchten wir als Kunden davon ausgehen können, dass sich nach dem Wiederanlauf der gesamte Geldbetrag noch auf dem Gehaltskonto befindet. Angenommen, wir zahlen einen Millionengewinn im Lotto auf unser Konto ein. Dann stellt die Dauerhaftigkeit von Transaktionen sicher, dass der Gewinn auch nach einem Systemneustart immer noch auf dem Konto liegt. Für den Wiederanlauf verwenden die meisten relationalen Datenbankmanagementsysteme ein Logprotokoll. In diesem Logprotokoll wird der Start (begin transaction), das Ende (end transaction) und der Abbruch (abort transaction) von Transaktionen verzeichnet, sowie die von Transaktionen durchgeführten Modifikationen (Einfügen, Löschen und Ändern von Datensätzen). Zu jeder Änderung wird der alte Datensatz (before image) und der neue Datensatz (after image) im Logprotokoll verzeichnet. Beim Wiederanlauf werden alle nicht beendeten Transaktionen (commit transaction fehlt im Logprotokoll) unter Verwendung der BeforeImages zurückgesetzt und alle bereits erfolgreich abgeschlossenen Transaktionen (commit transaction steht im Logprotokoll) nachgefahren. Das Logprotokoll sollte sich nicht auf dem selben Hintergrundspeicher (z.B. der selben Platte) wie die Datenbank befinden, denn im Falle eines Plattenfehlers wären das Logprotokoll wie auch die Datenbank verloren. Im Falle eines Systemabsturzes allein wäre die Speicherung des Logs und der Datenbank auf der selben Platte ausreichend. Damit wir das Logprotokoll nicht in die Vergangheit zurück bis zur erstmaligen Verwendung des Datenbanksystems aufbewahren müssen, können wir zu bestimmten Zeitpunkten auch ein Backup der Datenbank anlegen. Eine genauere Beschreibung der unterschiedlichen Algorithmen zum Wiederanlauf geben wir in Kapitel 11. 1.2.2.4 Concurrency Control Die Concurrency Control Einheit eines Datenbankmanagementsystems ermöglicht mehreren Benutzern, eine Datenbank gemeinsam zur selben Zeit zu benutzen, ohne ihre Konsistenz zu gefährden. Das traditionell verwendete Korrektheitskriterium für die parallele (oder KAPITEL 1. EINLEITUNG 1.10 t T1 T2 read(Konto,a) read(Konto,b) a := a + 2.000 b := b − 65 write(Konto,a) write(Konto,b) Abbildung 1.6: Verzahnte Ausführung von Transaktionen verzahnte) Ausführung von Transaktionen im Mehrbenutzerbetrieb ist die Serialisierbarkeit. Die Serialisierbarkeit besagt, dass das Ergebnis der beliebigen Parallelausführung mehrerer Transaktionen dem Ergebnis irgendeiner Hintereinanderausführung dieser Transaktionen entspricht. Beispiel 1.2 Angenommen, wir wollen unsere Telefonrechnung bezahlen. Wir gehen zur Bank und füllen den Zahlschein aus, womit die Abbuchung vom Konto durchgeführt wird. Diese Abbuchung wird nun zufällig gleichzeitig mit der Gehaltsbuchung auf das Konto durchgeführt, d.h., es gibt zwei verschiedene Transaktionen, die zur selben Zeit auf dieselben Daten zugreifen. Betrachten wir dazu die schematische Darstellung in Abbildung 1.6, die eine mögliche verzahnte Ausführung zeigt. Angenommen, der aktuelle Kontostand beträgt 150,-. Zunächst liest Transaktion T1 (die Gehaltsbuchung) den aktuellen Kontostand in eine Programmvariable a (150,-), danach liest Transaktion T2 (die Telefonrechnung) den aktuellen Kontostand in eine Programmvariable b (150,-). Dann erhöht T 1 die Programmvariable a auf 2.150,- und T2 vermindert die Programmvariable b auf 85,-. Schließlich wird von T 1 der neue Kontostand 2.150,- und von T2 der neue Kontostand 85,- in die Datenbank geschrieben. Nachdem beide Transaktionen abgeschlossen wurden, ist der Kontostand Euro 85,-. Jede der beiden möglichen Hintereinanderausführungen der beiden Transaktionen (T 1 vor T2 oder T2 vor T1 ) hätte einen Kontostand von Euro 2.085,- ergeben. Das heißt, die angegebene verzahnte Ausführung ist nicht serialisierbar, und daher nicht korrekt, wie wir leicht anhand des obigen Beispiels sehen können. Um die Serialisierbarkeit von Transaktionen zu gewährleisten, verwenden die meisten Datenbankmanagementsysteme ein Sperrverfahren. Dabei legt eine Transaktion auf Datenobjekte, die sie schreiben oder lesen soll, eine Sperre. Besitzt eine Transaktion auf einem Datenobjekt eine Sperre und fordert eine andere Transaktion für dieses Datenobjekt ebenfalls eine Sperre an, so wird diese Sperre nur dann gewährt, wenn die neu angeforderte Sperre mit der bereits bestehenden Sperre verträglich ist. Ist sie dies nicht, so muss die die neue Sperre anfordernde Transaktion auf die Freigabe der bestehenden Sperre warten. KAPITEL 1. EINLEITUNG 1.11 Meist werden zwei Typen von Sperren verwendet: geteilte Lesesperren und exklusive Schreibsperren. Lesesperren verschiedener Transaktionen für dasselbe Datenobjekt sind miteinander verträglich; eine Schreibsperre einer Transaktion ist mit keiner Sperre einer anderen Transaktion für dasselbe Datenobjekt verträglich. Beispiel 1.3 Bezugnehmend auf Beispiel 1.2 mit den beiden Transaktionen auf dem Gehaltskonto bedeutet das, dass die Transaktion T1 , sobald sie den Wert des Kontos lesen will, diesen Wert exklusiv sperrt, da sie eine Schreiboperation ausführen will. Die Transaktion T 2 muss, wenn sie den Kontostand lesen will, warten, da eine exklusive Sperre vorliegt und daher keine andere Transaktion auf diesen Datenwert zugreifen kann. Erst wenn T 1 den Wert nach erfolgreichem Schreiben wieder freigegeben hat, kann T2 den neuen Wert lesen. Das garantiert, dass eine zu einer seriellen Ausführung äquivalente Ausführung durchgeführt wird. Das Sperren von Datenobjekten ist alleine jedoch nicht ausreichend, um die Serialisierbarkeit mehrerer parallel ausgeführter Transaktionen zu gewährleisten. Es muss darüber hinaus ein Sperrprotokoll eingehalten werden. Das am meisten gebräuchliche Sperrprotokoll ist das 2-Phasen-Sperrprotokoll. Eine Transaktion erfüllt das 2-Phasen-Sperrprotokoll, wenn es nach der ersten Freigabe einer Sperre keine neue Sperre mehr anfordert. Weiters garantiert die Concurrency Control Komponente die Isolation von Transaktionen. Isolation bedeutet, dass Effekte einer Transaktion erst nach ihrem erfolgreichen Abschluss für andere Transaktionen sichtbar werden. Die Isolation von Transaktionen wird durch das strikte 2-Phasen-Sperrprotokoll gewährleistet, wobei eine Transaktion dieses erfüllt, wenn es alle Sperren erst am Ende der Transaktion freigibt, was in der Praxis bei kommerziellen Datenbankmanagementsystemen der Fall ist. Eine genaue Behandlung der in diesem Abschnitt vorgestellten Konzepte werden wir in Kapitel 10 geben. Die in den letzten beiden Abschnitten vorgestellten Eigenschaften von Transaktionen — Atomarität, Konsistenz (Serialisierbarkeit), Isolation und Dauerhaftigkeit — werden oft als ACID-Eigenschaften (atomicity, consistency, isolation, durability) bezeichnet. 1.2.2.5 Ad-hoc-Abfragen Zum Zeitpunkt des Entwurfs einer Datenbank sind üblicherweise nicht alle zu erwartenden Abfragen bekannt. Datenbankmanagementsysteme bieten die Möglichkeit, ad hoc neue Abfragen interaktiv an das Datenbanksystem zu stellen, ohne dass dafür neue Anwendungsprogramme geschrieben werden müssen. Ein gutes Datenbankmanagementsystem unterstützt einfach formulierbare und deklarativ gestellte Abfragen. Deklarativ bedeutet, dass nur die Bedingungen angegeben werden müssen, die die zu selektierenden Daten erfüllen. Es ist nicht nötig, ein prozedurales Vorgehen anzugeben, wie diese Daten in der Datenbank gesucht werden müssen. Weiters wird ein gutes Datenbankmanagementsystem die gestellte Abfrage optimieren, d.h. einen unter Berücksichtigung der Art der Abfrage und der vorhandenen Speicher- und Indexstrukturen optimalen Zugriffsplan ermitteln. Die meisten relationalen 1.12 KAPITEL 1. EINLEITUNG Datenbanksysteme stellen SQL (Structured Query Language) als interaktive Datenbankabfragesprache zur Verfügung. Wir werden in Kapitel 4 genauer darauf eingehen, die Optimierung von Abfragen behandeln wir in Kapitel 9. 1.2.2.6 Datenschutz Datenbankmanagementsysteme bieten die Möglichkeit, den Zugriff auf Ausschnitte der Datenbank für einzelne Benutzer oder Benutzergruppen zu beschränken. Dabei kann hinsichtlich der Art des Zugriffs zwischen Lese-, Änderungs-, Einfüge- und Löschzugriffen unterschieden werden. Wichtig in diesem Zusammenhang ist, wie granular Zugriffsrechte vergeben werden können: z.B. für die gesamte Datenbank, für einzelne Tabellen einer relationalen Datenbank, oder für ausgewählte Zeilen und Spalten einer Tabelle. 1.2.3 Komponenten eines Datenbanksystems Ein Datenbanksystem besteht aus den folgenden Komponenten: Abfragenübersetzer (query parser): übersetzt die Anweisungen einer Abfragesprache in eine niedere Sprache (z.B. Relationale Algebra, Kapitel 3). Abfragenoptimierer (query optimizer, strategy selector): formt das Ergebnis des Abfragenübersetzers in eine effiziente Abfrage mit gleichem Ergebnis um(Kapitel 9). Zugangs- und Integritätsmanager: verhindert unberechtigte Zugriffe und überprüft die Einhaltung vorgegebener Integritätsbedingungen. Puffermanager (buffer manager): führt den Datentransfer vom Sekundär- in den Primärspeicher und umgekehrt durch. Dateimanager (file manager): verwaltet die Dateien und deren Datenstrukturen auf dem Sekundärspeicher. Wiederanlaufeinheit (recovery unit): stellt nach Transaktions-, System- oder Hardwarefehlern einen konsistenten Zustand der Datenbank her (Kapitel 11). Mehrbenutzerkontrolleinheit (concurrency control unit): verhindert, dass sich mehrere Benutzer oder Programme, die das Datenbanksystem gleichzeitig verwenden, gegenseitig stören (Kapitel 10). Das Datenbankmanagementsystem greift über die oben beschriebenen Komponenten auf die Datenbank selbst zu, deren Daten über die folgenden Datenstrukturen verwaltet werden: Dateien (data files): speichern die Daten selbst. KAPITEL 1. EINLEITUNG 1.13 Benutzer Abfragenübersetzer Wiederanlaufmanager Abfragenoptimierer Benutzertransaktion Logdatei Mehrbenutzerkontrolle Sperrenverzeichnis Puffermanager Puffer (Hauptspeicher) Dateimanager Statische Dateien Indexe Systemdaten Platte(Hintergrundspeicher) Benutzerdaten Abbildung 1.7: Komponenten eines Datenbanksystems Datenverzeichnisse (data dictionary): enthält Informationen über die Bedeutung der gespeicherten Daten und deren Aufbau (Struktur der Dateien, Zugriffsbeschränkungen, . . . ). Indexe (indices): werden für den effizienten Zugriff auf bestimmte Daten benötigt (Kapitel 8). Statische Dateien (statical data): enthalten Informationen über die im Datenbanksystem gespeicherten Daten, die etwa vom Abfragenoptimierer verwendet werden können. 1.2.4 Vorteile des Einsatzes von Datenbanksystemen Am Ende dieses Abschnittes möchten wir auf die Vorteile des Einsatzes von Datenbanksystemen in Informationssystemen eingehen, die aufgrund einer zentralisierten Verwaltung der Daten entstehen: • Redundanzen können reduziert bzw. verhindert werden. In Systemen, die ihre Daten nicht in einer Datenbank organisieren, hat jede Applikation oft ihre eigenen Datenfiles. Wenn nun mehrere Applikationen dieselben Daten KAPITEL 1. EINLEITUNG 1.14 verwenden, hat das zur Folge, dass die Daten oftmals mehrfach gespeichert werden, wie wir in Abbildung 1.2 gesehen haben. Bei der Verwendung eines Datenbanksystems können Datenadministratoren diesen Redundanzen begegnen und bei der Erstellung eines Datenmodells verhindern. Wir möchten jedoch an diesem Punkt sehr wohl darauf hinweisen, dass es in in der Praxis manchmal technische oder organisatorische Gründe gibt, nicht alle Redundanzen auszuräumen. Wichtig ist dabei jedoch, dass die Datenadministratoren sich dieser Probleme bewusst sind und etwa im DBMS Vorkehrungen treffen, dass z.B. bei Änderung der Daten diese an allen Stellen, an denen sie redundant gespeichert sind, aktualisiert werden. • Inkonsistenz kann (bis zu einem gewissen Grad) verhindert werden. Für die Entstehung von Inkonsistenzen gibt es vor allem eine Ursache, die wir bei einem ordentlichen Design einer Datenbank verhindern sollten: redundante Daten. Wenn Kundennummer und Kundenname nicht nur an einer Stelle miteinander gespeichert sind, sondern an mehreren, dann kann es notwendig sein, dass nach einer Namensänderung der Name des Kunden an mehreren Stellen geändert werden muss und nicht nur bei den Stammdaten des Kunden. Wenn das nicht geschieht, dann werden die Daten inkonsistent. Es ist auf jeden Fall möglich, Inkonsistenz zwischen den Daten auf Applikationsebene abzufangen und so sicherzustellen, dass die redundant gespeicherten Daten an allen Stellen geändert werden. Dabei stellt sich jedoch das Problem, dass in allen Applikationen auf diesen Umstand Rücksicht genommen werden muss. Daher stellen die meisten kommerziellen Datenbankmanagementsysteme Trigger zur Verfügung (siehe Kapitel 4). Trigger ermöglichen es, aktiv auf Änderungen des Datenbestandes zu reagieren und weitere Änderungen selbst durchzuführen. So ist es den Datenbankadministratoren leicht möglich, die Änderung eines Namens abzufangen und sicherzustellen, dass diese Änderung auch an allen Stellen, an denen der Name sonst noch vorkommt, durchgeführt wird. • Die Daten können mehrfach verwendet werden. Durch die Trennung von Applikationen und den eigentlichen Daten, die nun im Datenbanksystem gehalten werden, können mehrere Applikationen auf einen einzigen Datenbestand zugreifen, und auch neue Applikationen können so entwickelt werden, dass sie auf schon bestehende Daten zugreifen. Wir können die gespeicherten Daten auch sehr leicht erweitern, und etwa zusätzlich zur Telefonnummer und Adresse der Kunden auch eine Email-Adresse speichern, ohne dass wir alle schon bestehenden Applikationen ändern müssen. • Standardisierungen können sichergestellt werden. Durch die zentrale Kontrolle der Administratoren über die Daten kann auf die Einhaltung von Standards bei der Datenorganisation Rücksicht genommen werden. Zu KAPITEL 1. EINLEITUNG 1.15 solchen Standards gehören z.B. innerbetriebliche, industrielle, nationale oder internationale Standards. Der Vorteil einer standardisierten Datenhaltung ist, dass z.B. Datenaustausch und Datentransfer verhältnismäßig leicht realisierbar sind. • Datensicherheit ist leicht realisierbar. Da die Datenbankadministratoren allein für alle technischen Belange der Datenbank zuständig sind, können sie Einfluss darauf nehmen, wie und von wem auf die Daten zugegriffen wird. Das Datenbankmanagementsystem stellt Mechanismen zur Verfügung, mit denen unterschiedlichen Benutzern unterschiedliche Zugriffsrechte (zum Lesen, Ändern, Löschen oder neu Anlegen) vergeben werden können. Weiters sind unterschiedliche Benutzersichten definierbar, wodurch z.B. Abteilungsleiter nur die Daten der ihnen unterstellten Mitarbeiter einsehen können. Wir möchten aber auch darauf hinweisen, dass die Datensicherheit erst bei der Verwendung von zentral gespeicherten Daten zu einem richtigen Problem wird. • Datenintegrität wird sichergestellt. Sicherstellung der Datenintegrität bedeutet, dass die Daten bezüglich bestimmter Kriterien fehlerfrei sind. Es ist natürlich nicht möglich, absolute Korrektheit der Daten sicherzustellen, denn wir können uns bei der Dateneingabe irren und z.B. als Adresse der Abteilung für Datenbanken und Artificial Intelligence den Karlsplatz 13 angeben, statt Favoritenstraße 9-11. Durch eine zentrale Kontrolle der Daten und Einschränkung der Änderungsmöglichkeiten der vielen Benutzer ist es einfacher, diese Art der Fehler zu verhindern. Es ist aber möglich, bestimmte Zusammmenhänge im Datenbankmanagementsystem zu modellieren und somit sicherzustellen, dass diese nicht verletzt werden. Wir könnten z.B. sagen, dass alle Assistenten der TU Wien jeweils genau einem Institut zugeordnet sind. Wenn wir nun das Institut löschen wollen, da es aufgelassen wird, dann muss dies verhindert werden, solange noch Assistenten diesem Institut zugeordnet sind. Weiters ist es möglich Regeln zu definieren, anhand derer beim Ändern der Daten Integritätsbedingungen überprüft werden. So können wir z.B. verlangen, dass das Geburtsjahr der MitarbeiterInnen eines Betriebes nicht mehr als 80 Jahre vom momentanen Jahr zurückliegt. • Widersprüchliche Anforderungen können ausgeglichen werden. Daten- und Datenbankadministratoren, die einen Überblick über die unterschiedlichen Anforderungen des Unternehmens haben, haben die Möglichkeit, auf diese Anforderungen einzugehen. So kann etwa durch die Art der Datenspeicherung eine Performancesteigerung für bestimmte wichtige Applikationen zugunsten von weniger wichtigen durchgeführt werden. Alle hier genannten Vorteile beruhen auf der Erreichung von Datenunabhängigkeit, die wir im nächsten Abschnitt vorstellten werden. KAPITEL 1. EINLEITUNG 1.16 externe Ebene ext. Schema 1 ext. ... Schema n Daten-Definition logische Datenunabhängigkeit Daten-Manipulation konzeptionelle Ebene physische Datenunabhängigkeit interne Ebene Daten-Administration Abbildung 1.8: ANSI/SPARC Architektur eines Datenbanksystems 1.3 Architektur eines Datenbanksystems Moderne Datenbanksysteme unterstützen die ANSI/X3/SPARC Architektur für Datenbanksysteme. Diese vom Standards Planning and Requirements Committee des American National Standards Institute vorgeschlagene Architektur stellt drei verschiedene Sichtweisen auf ein Datenbanksystem und die darin gespeicherten Daten vor (siehe Abbildung 1.8): • Die Interne Ebene ist der physischen Speicherung am nächsten, entspricht ihr jedoch nicht ganz. Wir betrachten hier nicht die Speicherstruktur auf dem Niveau von Bl öcken oder Seiten, sondern als interne Records“ oder Datensätze. Beschrieben wird die in” terne Ebene durch das interne Schema der Daten. Dieses Schema enthält nicht nur die Beschreibung von Art und Aufbau der unterschiedlichen gespeicherten Datenstrukturen, sondern auch von speziellen Zugriffsmechanismen (Indexe), sowie der Anordnung der Datensätze. Weiters wird auf der internen Ebene die Zuordnung der Datensätze auf Sekundärspeicher-Medien verzeichnet. Diese Ebene stellt somit als Schnittstelle zur eigentlichen Datenbank die Abbildung von logischem in physikalischen Adressraum unter Zuhilfenahme von Betriebssystemfunktionen zur Verfügung. Wir gehen auf die Speicherstrukturen in Datenbankmanagementsystemen in Kapitel 8 genauer ein. • Die konzeptionelle Ebene beschreibt die logische Struktur, die logische Gesamtsicht der Daten einer Datenbank im konzeptionellen Schema. In diesem Schema beschreiben wir die Daten und ihre Beziehung zueinander mit den Mitteln der Datenmodellierung (siehe Abschnitt 1.4). Weiters enthält das konzeptionelle Schema Integritätsbedingungen, Sicherheitsregeln und die Definition von Triggern. Die Trennung zwischen der internen und der konzeptionellen Ebene führt zur physischen Datenunabhängigkeit. Diese bedeutet, dass unabhängig von der konkreten physischen Organisation der Daten die logische Organisation der Daten gleich bleibt. Wenn wir z.B. aus Performancegründen Indexe oder Cluster einführen, hat das keine Auswirkungen auf die logische Struktur der Daten und die Anwendungsprogramme, die auf KAPITEL 1. EINLEITUNG 1.17 der Datenbank arbeiten, müssen nicht verändert werden. Die einzige Auswirkung der Änderung ist eine möglicherweise veränderte Laufzeit. Unterstützt ein Datenbankmanagementsystem physische Datenunabhängigkeit, können wir die Datenbank zunächst nur nach inhaltlichen Gesichtspunkten entwerfen und implementieren. Anschließend können wir die Speicherorganisations- und Zugriffsstrukturen der Dateien so modifizieren, dass die wichtigsten Anwendungen und Anfragen schneller ausgeführt werden, ohne diese umschreiben zu müssen. Hat sich mit der Zeit das typische Anfragenprofil an die Datenbank geändert, können wir wiederum eine optimale interne Organisationsform der Daten festlegen, ohne Anwendungsprogramme modifizieren zu müssen. • Die Externe Ebene umfasst alle individuellen Sichten der einzelnen Benutzer, Benutzergruppen oder Anwendungen auf die Datenbank. Jedes externe Schema beschreibt dabei eine dieser Sichten (Views) und enthält dabei genau jenen Ausschnitt der Datenbank den der jeweilige Benutzer, die Benutzergruppe oder die Anwendung sehen will bzw. darf. Die Trennung zwischen konzeptioneller und externer Ebene wird auch als logische Datenunabhängigkeit bezeichnet. Dadurch werden Anwendungen, die auf ein externes Schema zugreifen, von einer Änderung des logischen Aufbaus der Daten des konzeptionellen Schemas entkoppelt. Eine Restrukturierung des konzeptionellen Schemas bedingt keine Änderung der Anwendungen, die auf externe Schemata zugreifen. Eine Erweiterung des konzeptionellen Schemas einer relationalen Datenbank um neue Tabellen oder neue Spalten von Tabellen, sowie eine Verkleinerung des konzeptionellen Schemas betreffen nur jene Anwendungen, die die hinzugefügten oder entfernten Tabellen bzw. Spalten tatsächlich benutzen. Unterstützt ein Datenbankmanagementsystem logische Datenunabhängigkeit, können wir während des Betriebes des Datenbanksystems neue Tabellen oder Spalten hinzufügen, ohne dass alte Anwendungen geändert werden müssen. Durch die ANSI SPARC-Architektur sind auch die Aufgabenprofile der Datenbankadministratoren und der Anwendungsadministratoren festgelegt, die wir schon besprochen haben. Die Datenbankadministratoren sind für die Verwaltung des logischen und des physischen Schemas verantwortlich. Anwendungsadministratoren sind jeweils für die Verwaltung eines oder mehrerer externer Schemata verantwortlich. 1.4 Die Datenmodellierung In diesem Abschnitt werden die wichtigsten Begriffe zur Datenmodellierung erklärt, die danach in Kapitel 2 eingehend behandelt werden. KAPITEL 1. EINLEITUNG 1.18 Anforderungen Konzeptioneller Entwurf z.B.: Entity-Relationship-, UML-Diagramme Konzeptionelles Schema konzeptionelles Datenmodell z.B.: Relationales Modell (Normalisierung) Logischer Entwurf systemunabhängig systemabhängig Logisches Schema logisches Datenmodell z.B.: Indexe, Cluster Physischer Entwurf Physisches Schema physisches Datenmodell Abbildung 1.9: Der Datenbankentwurfsprozess 1.4.1 Begriffe Ein Datenmodell besteht aus einer Menge von Modellierungskonstrukten zur Beschreibung des Inhalts, der Struktur und der Bedeutung von Daten und einer Menge von auf diesen Modellierungskonstrukten definierten Operatoren zur Datenmanipulation. Ein Datenmodell stellt dementsprechend eine Datendefinitionssprache (Data Definition Language, DDL) und eine Datenmanipulationssprache (Data Manipulation Language, DML) zur Verfügung. Datenmodellierung bezeichnet den Vorgang des Entwurfs eines Datenbankschemas für die Verwaltung der Daten eines Informationssystems. Unter Universe of Discourse (oder Problembereich) wird jener Weltausschnitt verstanden, der in der Datenbank repräsentiert werden soll. 1.4.2 Datenmodelle im Datenbankentwurf Im Datenbankentwurf werden verschiedene Datenmodelle entsprechend der ANSI/X3/SPARCArchitektur verwendet. Konzeptionelle Datenmodelle stellen problemnahe Modellierungskonzepte für die ersten Schritte des Datenbankentwurfs zur Verfügung und dienen zur Kommunikation zwischen Endbenutzern und Datenbankentwicklern. Physische Datenmodelle stellen maschinennahe Konzepte zur Verfügung und dienen zur Beschreibung der Organisation von Daten in Dateien, sowie zur Beschreibung von Zugriffsstrukturen, die ein rasches Einfügen, Suchen, Löschen und Ändern von Daten ermöglichen. Logische Datenmodelle dienen der Überbrückung der Kluft zwischen konzeptionellen und physischen Datenmodellen. Sie werden oft auch als Implementierungsmodelle bezeichnet, da sie von Datenbankmanagementsystemen direkt unterstützt werden. Das logische Datenmodell steht dem Entwickler zur Definition eines Datenbankschemas zur Verfügung und wird weitgehend automatisch vom KAPITEL 1. EINLEITUNG 1.19 Datenbankmanagementsystem in ein physisches Datenbankschema übersetzt. Konzeptionelle, logische und physische Datenmodelle sind in verschiedenen Phasen des Datenbankentwurfs relevant (vgl. Abbildung 1.9). In den letzten Jahrzehnten wurden Implementierungsmodelle immer näher an konzeptionelle Modelle herangebracht. Das Netzwerkmodell und das Hierarchische Modell wurden vor allem in den 70er Jahren als Implementierungsmodelle verwendet und waren sehr nahe an physische Modelle angelehnt. Das seit den 80er Jahren immer mehr eingesetzte Relationenmodell steht als logisches Modell zwischen physischen und konzeptionellen Modellen. Die seit den 90er Jahren entwickelten objektorientierten Datenbankmanagementsysteme kommen mit einem objektorientierten Implementierungsmodell den konzeptionellen objektorientierten Modellen bereits weit entgegen, sind aber zur Zeit hinsichtlich der unterstützten Modellierungskonzepte meist noch eingeschränkt. 1.5 Der Datenbank-Life-Cycle“ ” Der Datenbank-Life-Cycle“ beinhaltet alle zum Design, der Erstellung und Wartung einer ” Datenbankapplikation notwendigen Entwicklungsschritte. Der Prozess beginnt mit der Anforderungsanalyse (Requirementsanalyse), die gemeinsam mit den Kunden durchgeführt wird, der Erstellung des konzeptionellen Schemas, des logischen Schemas und zuletzt des physischen Schemas. Nach der Fertigstellung des Designs beginnt die Implementierungsphase, danach kommt die Wartungsphase. In diesem Skriptum verwenden wir als roten Faden das virtuelle Unternehmen R EINE (Restaurant at the End of the InterNEt). R EINE ist ein virtuelles Unternehmen, das Leistungen im Bereich der Gastronomie erbringt. Kunden können über das Internet Leistungen aussuchen und bestellen, die dann geliefert werden. Im Gegensatz zu bereits existierenden Unternehmen, die z.B. Pizzas ausliefern, soll R EINE vielfältigere Leistungen erbringen, denn auch wenn es für den Kunden wie ein einziges Unternehmen aussieht, so besteht es eigentlich aus einer Vielzahl von Unternehmen (Restaurants, Weinbauern, Catering Services, Transportunternehmen), die durch ihre gemeinsame Vermarktung gegenüber den Kunden eine bessere Leistung erbringen können. Aufgrund der Komplexität dieses Anwendungsbeispieles werden wir aber jeweils nur einen Teil der Gesamtanwendung betrachten, der sich für die Erklärung der vorgestellten Theorie eignet. 1.5.1 Die Anforderungsanalyse In der ersten Phase des Zyklus müssen wir als Entwickler mit den Kunden (sowohl mit den Erzeugern als auch den Benutzern der Daten) gemeinsam eine Spezifikation für die Anforderungen erstellen. An dieser Stelle müssen wir sowohl die Art der Daten und deren natürliche Beziehungen untereinander analysieren als auch die zu verwendende Hard- und Software besprechen, da diese oft vom Kunden vorgegeben werden. KAPITEL 1. EINLEITUNG 1.20 name adresse Kunde n knr haube bestellt rnr verkauft 1 adresse n Restaurant name typ m Speise name preis Abbildung 1.10: Beispiel eines Entity-Relationship-Diagramms Beispiel 1.4 In diesem Schritt müssen wir uns überlegen, welche Daten (Objekte des Problembereichs) wir für R EINE und seine Unternehmen speichern. Auf jeden Fall benötigen wir Unternehmen, Produkte, Kunden, Bestellungen und Rechnungen sowie eventuell Mitarbeiter. Diese Konzepte kristallisieren sich während der ersten Projektbesprechungen mit den Kunden heraus. 1.5.2 Der konzeptionelle Entwurf Beim konzeptionellen Entwurf wird ausgehend von den Anforderungen ein konzeptionelles Schema entworfen, das Objekte des Problembereichs mit ihren Eigenschaften und Beziehungen zu anderen Objekten in einem konzeptionellen Datenmodell erfasst. Der konzeptionelle Entwurf der Daten ist unabhängig davon, ob die Daten in verteilter Form (Verteilte Datenbank) oder in einer einzigen zentralen Datenbank gespeichert sind. Das heute am weitesten und in vielen Varianten verbreitete konzeptionelle Datenmodell ist das Entity-Relationship-Modell von Chen (1976). Es fand vor allem auf Grund seiner anschaulichen graphischen Darstellung des Datenbankschemas in Form des Entity-RelationshipDiagramms (ER-Diagramms) großen Anklang. Im ursprünglich von Chen vorgestellten Modell werden Objekte des Problembereichs auf Grund gemeinsamer Eigenschaften zu Objekttypen (Entities) zusammengefasst. Ein Objekttyp wird graphisch durch ein Rechteck repräsentiert und stellt in Form von Ovalen die allen Objekten dieses Typs gemeinsamen Merkmale (Attribute) dar. Eine minimale Menge von Merkmalen, deren Werte ein Objekt eines Objekttyps eindeutig identifizieren, wird als Schlüssel bezeichnet. Der Primärschlüssel, das ist ein Schlüssel, der beim Entwurf besonders ausgezeichnet wird, wird durch Unterstreichen gekennzeichnet. Weiters werden Beziehungstypen (Relationships) zwischen Objekttypen modelliert, die angeben, dass Objekte dieser Typen zueinander in Beziehung stehen. Beziehungs- KAPITEL 1. EINLEITUNG 1.21 name adresse legt 1 Kunde n Bestellung knr bnr datum lieferadresse Abbildung 1.11: ER-Diagramm der Sicht der Kunden legt Kunde 1 n Bestellung n für verkauft m Restaurant 1 n Speise Abbildung 1.12: Integriertes ER-Diagramm (ohne Attribute) typen werden durch Rauten dargestellt, die durch Kanten mit den betreffenden Objekttypen verbunden sind. Eine an der Kante zwischen einem Objekttyp und dem Beziehungstyp angegebene Zahl gibt an, mit wievielen Objekten dieses Objekttyps ein bestimmtes Objekt des jeweils anderen Objekttyps in Beziehung steht. Ein Objekttyp, dessen Objekte nicht eindeutig durch ihre Merkmale identifizierbar sind, sondern erst durch die Zuhilfenahme einer Beziehung, heißt schwacher Objekttyp (weak entity) und wird durch ein doppelt umrahmtes Rechteck dargestellt. Eine genaue Beschreibung der semantischen Strukturen des ER geben wir in Kapitel 2. Beispiel 1.5 Ein Beispiel eines ER-Diagrammes zur Modellierung von Restaurants, deren Speisen und der Kunden, die Speisen bestellen, geben wir in Abbildung 1.10. In großen Projekten sind meist mehrere Personen in die Analyse der Anforderungen involviert, die jeweils unterschiedliche Teilbereiche modellieren. Diese unterschiedlichen Sichten auf das Gesamtproblem müssen im nächsten Schritt zu einem einheitlichen Modell integriert werden. Dabei müssen Redundanzen und Inkonsistenzen eliminiert werden. Beispiel 1.6 In Abbildung 1.10 haben wir den Bereich aus der Sicht der Restaurants modelliert. Die Sicht der Kunden hingegen zeigen wir in Abbildung 1.11, das integrierte Modell in KAPITEL 1. EINLEITUNG 1.22 Restaurant rnr name 1 Gußhaus 2 A Tavola 3 Green Cottage adresse Gußhausstraße 23, 1040 Wien Weihburggasse 3-5, 1010 Wien Kettenbrückengasse 3, 1050 Wien Speise name Gemischter Vorspeisenteller Penne all’ Arrabiata Hühnerfleisch der tausend Geschmäcker Eisei im gebackenen Nudelnest Gebratener Rehrücken mit Serviettenknödel haube 1 2 typ Österreichisch Toskanisch Chinesisch preis rnr 100 2 95 2 65 3 65 3 210 1 Abbildung 1.13: Transformation des ER-Modells in das Relationenmodell Abbildung 1.12. 1.5.3 Der logische Entwurf Beim logischen Entwurf wird das konzeptionelle Schema in ein logisches Schema transformiert, das in dem Implementierungsmodell des ausgewählten Datenbankmanagementsystem beschrieben ist. Das heute am weitesten verbreitete Implementierungsmodell ist das Relationale Datenmodell von Codd (1970). Es beschreibt die Daten einer Datenbank in Form von Tabellen. Das Relationale Datenmodell beschreiben wir eingehend in den Kapiteln 3 und 4, in Kapitel 3 beschreiben wir die Transformation von einem ER-Modell in das Relationenmodell. Beispiel 1.7 Abbildung 1.13 zeigt für R EINE beispielhaft die Tabellen für die Entities Speise und Restaurant. Aus dem ER-Diagramm und der Semantik der Beziehungen der Daten in der Anforderungsanalyse können wir Funktionale Abhängigkeiten (siehe Kapitel 6) ableiten. Funktionale Abhängigkeiten stellen einerseits Abhängigkeiten zwischen Schlüsseln verschiedener Objekttypen dar, andererseits zwischen Schlüsseln und Nichtschlüsselattributen innerhalb eines Objekttyps. Ist zweiteres der Fall, so müssen wir mittels Normalisierung (siehe Kapitel 7) die Tabellen in eine Normalform (3. Normalform oder Boyce-Codd Normalform) überführen, um Anomalien beim Löschen oder beim Ändern von Daten zu vermeiden. Dabei teilen wir eine Tabelle, die die Normalform verletzt, nach bestimmten Regeln in mehrere Tabellen auf. Einen Algorithmus zur Normalisierung von Relationen geben wir ebenfalls in Kapitel 7. KAPITEL 1. EINLEITUNG Satzart ‘R’ ‘S’ Block 1 R S S R Block 2 S S R S 1.23 Satzinhalt rnr name name 2 A Tavola Gemischte. . . Penne all. . . 3 Green Cottage Hühnerf. . . Eisei im N. . . 1 Gußhaus Gebratene. . . Indexeintrag 1 2 3 adresse haube preis Weihbur. . . 100 95 Kettenb. . . 2 65 65 Gußhaus. . . 1 210 typ Toskanisch Chinesisch Österreichisch Verweis Block 2 Block 1 Block 1 Abbildung 1.14: Beispiel eines physischen Datenbankschemas 1.5.4 Der physische Entwurf Der letzte Schritt beim Entwuf einer Datenbank ist der physische Entwurf. Beim physischen Entwurf wird ein dem logischen Schema entsprechendes physisches Schema erstellt mit dem Ziel, das Laufzeitverhalten zu optimieren. Die Umsetzung in ein physisches Schema mit einer bestimmten Organisationsform der Daten wird vom Datenbankmanagementsystem übernommen. Wir können als Entwickler jedoch meist eine von mehreren alternativ möglichen Organisationsformen der Daten wählen (etwa, welche Daten physisch nahe beieinander gespeichert werden – Clustering) und zusätzlich gewünschte Indexstrukturen festlegen, welche die Suche nach bestimmten Suchbegriffen beschleunigen. Die Wahl der Organisationsform und der Indexstruktur richtet sich nach der Art und Häufigkeit der wichtigsten Anfragen an die Datenbank (siehe Kapitel 8). Beispiel 1.8 Abbildung 1.14 zeigt ein mögliches physisches Schema für die relationale Datenbank aus Beispiel 1.7. Die Daten über die Speisen eines Restaurants werden zusammen mit den Daten des Restaurants in einer nach dem Namen des Restaurants sortierten Datei gespeichert (eine Datei mit zwei Satzarten ‘R’ und ‘S’). Weiters ist die Datei nach der Restaurantnummer indiziert. An dieser Stelle kann es passieren, dass wir aus Performancegründen bei gewissen Tabellen wieder eine Denormalisierung durchführen und sie wieder zusammenfassen müssen, da 1.24 KAPITEL 1. EINLEITUNG die Struktur der Abfragen eine häufige Verknüpfung der Tabellen fordert und dies die zeitaufwendigste Operation bei der Abfrageverarbeitung in relationalen DBMS ist. Dieser Schritt ist aber sehr gut abzuwägen, da wir die während des logischen Entwurfs eliminierten Anomalien wieder in die Datenbank bekommen. 1.5.5 Verteilter Entwurf Bei verteilten Datenbanken ist im Entwurfsprozess ein weiterer Schritt notwendig, nämlich der Entwurf der Datenverteilung. Dieser besteht aus zwei Teilen, der Datenfragmentierung und der Datenzuordnung. Das Fragmentierungsschema beschreibt in Form einer 1:1-Abbildung, wie der Datenbestand in einzelne Fragmente unterteilt wird. Fragmente sind logisch zusammengehörende Teile der Daten, die physikalisch an einer oder an mehreren Stellen gespeichert sind. Das Zuordnungsschema beschreibt, an welcher Stelle die einzelnen Fragmente bzw. gegebenenfalls deren Kopien physisch gespeichert sind. Das Zuordnungsschema kann entweder eine 1:1-Abbildung der Fragmente auf die Speicherplätze sein, in diesem Fall erhalten wir einen nichtredundanten, verteilten Datenbankentwurf, oder aber eine 1:n-Abbildung, wodurch wir einen verteilten und replizierten Datenbankentwurf erhalten. Die Trennung der Fragmentierung von der Zuordnung ist wichtig, da die Fragmentierung den logischen Entwurf der Daten betrifft, die Zuordnung den physischen. Intuitiv ist klar, dass eine optimale Fragmentierungs- und Zuordnungsstrategie nicht möglich ist, wenn wir beide Schritte völlig voneinander getrennt betrachten. In der Praxis ist jedoch eine Trennung der beiden Bereiche vor allem in großen Problemkreisen unumgänglich. Weiters müssen Probleme, die durch die Redundanz der Daten im Falle einer replizierten Datenbank entstehen, berücksichtigt werden, und die Unabhängigkeit von lokalen Datenbankmanagementsystemen gegeben sein. Ziele des Entwurfs der Datenverteilung sind minimale Antwortzeiten, minimale Kommunikationskosten und maximale Verfügbarkeit. Beispiel 1.9 R EINE soll österreichweit angeboten werden. Momentan gibt es das Service in Innsbruck und Umgebung, in Linz, in Salzburg und in Wien. Daher ist es sinnvoll, die Daten in einer verteilten Datenbank zu verwalten. Die Fragmentierung der Daten betrifft sowohl Anbieter und Angebote als auch die Kunden; die Zuordnung lösen wir durch die Verwendung von vier Rechnern, die an den jeweiligen Orten stehen, wobei in Wien zentral alle Kundendaten gespeichert werden. 1.5.6 Datenbankimplementierung, -überwachung und -wartung Nach der Entwurfsphase müssen wir den Entwurf unter Verwendung einer Datendefinitionssprache (DDL) eines Datenbankmanagementsystems umsetzen. Mittels der Datenmanipulationssprache (DML) können wir die Datenbank mit Daten füllen, diese abfragen oder Indexe und Cluster setzen. Wir stellen in diesem Skriptum in Kapitel 4 SQL (Structured Query Language) als eine Sprache vor, die sowohl DDL als auch DML Konstrukte enthält. In Kapitel 5 KAPITEL 1. EINLEITUNG 1.25 wird Datalog vorgestellt, deren DML rekursive Abfragen erlaubt. Solche rekursiven Abfragen sind zwar im SQL-3 Standard möglich, allerdings in der Praxis in ORACLE oder Microsoft SQL Server 2000 noch nicht implementiert. Nach erfolgreicher Inbetriebnahme des Datenbanksystems müssen wir beobachten, wie es sich im täglichen Betrieb verhält. Ist das Laufzeitverhalten unbefriedigend, werden wir das System dahingehend verändern, dass es auch diese Erfordernisse erfüllt. Das System muss gewartet werden und meist ändern sich die Anforderungen an das System mit der Zeit und der Life-Cycle“ beginnt von neuem mit Redesign und Änderungen. ” 1.26 KAPITEL 1. EINLEITUNG Literaturverzeichnis [Chen, 1976] Chen, P. P-S.: The Entity-Relationship Model – Toward a Unified View of Data. In Transactions ODS Bd. 1, März 1976, pp 9–36. [Date et al. 1994] Date, C.J. and Darwen, H.: A Guide to the SQL Standard: A User Guide to the Standard Relational Language SQL. 3rd edition, Addison-Wesley Publishing Company, 1994. [Date 1995] Date, C.J.: An Introduction to Database Systems. 6th edition, Addison-Wesley Publishing Company, 1995. [Fortier 1999] Fortier, P.: SQL3 Implementing the SQL Foundation Standard. McGraw-Hill, 1999. [Rumbaugh et al. 1991] Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F. and Lorensen, W.: Object-Oriented Modeling and Design, Prentice Hall, Engelwood Cliffs, NJ, 1991. [Teorey et al. 1986] Teorey, T.J., Yang, D., and Fry, J.P.: “A Logical Design Methodology for Relational Databases Using the Extended Entity-Relationship-Model”, ACM Computing Surveys, Vol.18, No. 2, pp.197-222, 1986. [Teorey, 1999] Teorey, T.J.: Database Modeling & Design. Morgan Kaufmann, San Matteo, California, 1999. [Maier, 1983] Maier, D.: The Theory of Relational Databases. Computer Science Press, Rockville, Maryland, 1983. [Melton et al. 1994] Melton, J. and Simon, A.R.: Understanding the new SQL: A Complete Guide. Morgan Kaufmann, San Matteo, California, 1994. [Ullman, 1988 Bd. I] Ullman, J. D.: Principles of Database and Knowledge-Base Systems. Volume I. Computer Science Press, Rockville, Maryland, 1988. [Ullman, 1988 Bd. II] Ullman, J. D.: Principles of Database and Knowledge-Base Systems. Volume II. Computer Science Press, Rockville, Maryland, 1988. 1 1.2 LITERATURVERZEICHNIS [Vossen 1999] Vossen, G.: Datenbankmodelle, Datenbanksprachen und Datenbankmanagement-Systeme. 3. Auflage, R. Oldenbourg Verlag München Wien, 1999 Teil II Datenmodellierung 1 Kapitel 2 Konzeptionelle Datenmodelle und das ER Modell Das Ziel bei der Entwicklung von konzeptionellen (semantischen) Datenmodellen war, grundlegende Strukturierungsformen für die Datenmodellierung zur Verfügung zu stellen, die weitgehend den natürlichen, in unserer Sprache auftretenden Begriffsstrukturen entsprechen. Die semantischen Strukturen, die in der Anwendungsumgebung auftreten, sollen explizit im Datenbankschema erfasst und dargestellt werden. Neben der Struktur der Daten sollte auch deren Semantik im Datenbankschema ausgedrückt werden können. Die wichtigsten konzeptionellen Datenmodelle sind: • Entity-Relationship-Modell (ER) (Chen 1976), erweitert zum Extended-Entity-Relationship-Modell (EER) (Teorey, Yang, Fry 1986), • SDM (Hammer, McLeod 1978), • RM/T (Codd 1979), • verschiedene objektorientierte Datenmodelle. Weitere bekannte konzeptionelle Datenmodelle sind DAPLEX (Shipman 1979), TAXIS (Mylopoulos, Bernstein und Wong 1980) und IFO (Abiteboul, Hull 1984). Der Beginn der konzeptionellen Datenmodellierung geht auf die frühen sechziger Jahre (Bachman) zurück, als noch Dateisysteme zur Verwaltung der Daten herangezogen wurden. “Recordtypen” wurden als Rechtecke dargestellt und gerichtete Pfeile zwischen Rechtecken zeigten eine 1:n-Beziehung zwischen den Records an. Daraus entwickelte sich das ER-Modell. Dieses zeichnet sich durch eine besonders einfache Darstellung aus und wird daher bis heute von Datenbankdesignern zum Entwurf und zur Kommunikation mit den Endbenutzern verwendet. Das ER-Modell wurde im Jahr 1976 von Chen [Chen, 1976] eingeführt. In der Sicht des Entity-Relationship-Modells (Objekt-Beziehungs-Modell) besteht die Welt aus Entities (Objekttypen) und Relationships (Beziehungen) zwischen diesen Objekttypen. 1 2.2 KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL Im nächsten Abschnitt beschreiben wir allgemeine Abstraktionskonzepte, die sich in jedem konzeptionellen Datenmodell wiederfinden lassen. Danach gehen wir direkt auf das Entity-Relationship-Modell ein, das bis heute am weitesten verbreitete konzeptionelle Datenmodell. In Abschnitt 2.2 werden wir die einfachen Konstrukte, die von Chen eingeführt wurden, vorstellen. Diese Konstrukte verwenden wir, wenn wir im Stadium der Anforderungsanalyse mit den Kunden über den Problembereich reden. An dieser Stelle möchten wir auch erwähnen, dass es verschiedene Arten der Notation für dieselben Konstrukte gibt. Auch werden von den Tools der DBMS-Anbieter oft firmenspezifische Varianten oder Erweiterungen dieser Notation angeboten bzw. unterstützt. Wir übernehmen die Notation von [Teorey et al. 1986], einem Artikel, in dem auch die Transformation vom ER-Modell in das Relationenmodell beschrieben wird.1 In Abschnitt 2.3 beschreiben wir etwas ausgefeiltere Konzepte, die eine sinnvolle Erweiterung des ER in Form des Extended-Entity-RelationshipModells (EER) erlauben, indem sie semantische Strukturen darstellen können, die im ER nicht ausdrückbar sind. 2.1 Modellierungskonzepte konzeptioneller Datenmodelle Wie schon in der Einleitung beschrieben, dient ein Datenmodell der Herstellung einer Abstraktion von Problemen zum Zwecke der Beschreibung derselben. Abstraktion wiederum bedeutet, dass wir bestimmte Charakteristika und Eigenschaften einer Menge von Objekten zu deren Beschreibung auswählen und gleichzeitig andere, nicht relevante ausschließen. Dadurch können wir uns bei der Modellierung auf die wesentlichen Teile des Problembereichs konzentrieren. Allgemein können die folgenden drei Konzepte für die Modellierung in konzeptionellen Datenmodellen identifiziert werden: 1. Klassifikation 2. Aggregation 3. Verallgemeinerung Durch die Klassifikation definieren wir bestimmte Konzepte als Klassen von Objekten mit gemeinsamen Eigenschaften, d.h. wir führen mathematisch gesehen eine Mengenbildung durch. Betrachten wir wieder unser Internetrestaurant R EINE: Wir können die Restaurants der realen Welt zu einer Klasse Restaurants zusammenfassen, wobei es wiederum uns überlassen wird, ob wir alle Restaurants zu einer einzigen Klasse zusammenfassen, oder ob wir z.B. für Heurigen eine eigene Klasse einführen oder für Ketten oder Fast-Food Lokale jeweils eine eigene Klasse einführen. Derlei Entscheidungen müssen wir im Einzelfall anhand der konkreten Anwendung treffen. 1 Diese Arbeit wird als Anhang zum Skriptum der Laborübung verteilt. Sie kann aber auch im Sekretariat der Abteilung kopiert werden. KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL 2.3 Mittels Aggregation definieren wir neue Klassen aus bereits existierenden, die danach Komponenten der neuen Klassen sind. Ein einfaches Beispiel der Aggregation ist die Aggregation von Attributen zu Klassen. So können wir aus den Attributen restaurant name, adresse, typ und haube die Klasse Restaurant definieren. Das Attribut adresse selbst wiederum ist aus der Aggregation der Attribute strasse, ort, plz und land entstanden. Eine weitere Art der Aggregation ist die Aggregation von zwei Klassen, die miteinander in Beziehung stehen. Auf diese Weise können wir eine Klasse Verkauft aus den Klassen Restaurant und Speise aggregieren. In der Verallgemeinerung (Generalisierung) können wir mehrere Klassen zu einer allgemeineren Klasse zusammenfassen, indem wir Gemeinsamkeiten hervorheben und Unterschiede vernachlässigen. So ist die Klasse Person eine Verallgemeinerung der Klassen Kunde und Mitarbeiter. Attribute werden dabei entlang der Verallgemeinerungshierarchie vererbt: alle Attribute der allgemeineren Klasse sind auch Attribute der spezielleren Klasse. In unserem Fall könnte die Klasse Person die Attribute name, geburtsdatum und adresse haben. Damit besitzen sowohl die Klasse Kunde als auch die Klasse Mitarbeiter diese Attribute. Allerdings sehen wir bei Mitarbeitern auch das Attribut svnr, die Sozialversicherungsnummer, bzw. bei den Kunden eine Kundennummer knr vor. 2.2 Elementare ER-Konstrukte Die in der Literatur und im Weiteren in diesem Skriptum verwendeten Begriffe sind folgendermaßen äquivalent: auf Objektebene (= Exemplarebene = Instance level): Objekt = Entity-instance, Beziehung = Relationship-instance auf Objekttypebene (= Objektklassenebene = Schema level): Objekttyp = Entity, Beziehungstyp = Relationship In der Literatur wird statt Entity oft der alte Begriff Entity-set verwendet, statt Entityinstance auch der Begriff Entity. 2.2.1 Grundlegende Objekte: Entities, Beziehungen und Attribute Objekte bzw. Entity-instances repräsentieren jene wohlunterschiedenen Objekte des Problembereichs, über die Informationen gespeichert werden. Ein Objekt kann ein real existierendes Objekt sein, z.B. eine Person, aber auch ein ideelles Objekt, z.B. eine Dienstleistung wie ein Haarschnitt. Objekte mit denselben Eigenschaften werden zu Entities (Objekttypen) zusammengefasst (Klassifikation). Wir verwenden den englischen Begriff Entity, da die deutsche Übersetzung Objekttyp nicht gebräuchlich und eher dürftig ist. Beispiele für Entities sind alle Restaurants oder alle Speisen der Restaurants. 2.4 KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL Konzept Darstellung und Beispiel Restaurant Entity Weak Entity Speise verkauft Beziehung Attribute identifizierend beschreibend mehrwertig rnr name typ strasse komplex adresse ort plz land Abbildung 2.1: Elementare ER Konstrukte Entities werden im ER durch ein Rechteck dargestellt, wobei die Bezeichnung der Entity im Rechteck steht (Abbildung 2.1). Zur klaren Unterscheidung schreiben wir Namen von Entities in diesem Text groß. Beziehungen bzw. Relationship-instances zwischen Objekten haben als solche keine physische oder konzeptionelle Existenz, sondern ergeben sich aufgrund der vorhandenen Objekte. Beziehungen zwischen Entities werden in der Klassifikation zu Relationships (Beziehungstypen) zusammengefasst. In diesem Fall verwenden wir die deutsche Bezeichnung Beziehungstyp, wobei wir aber das Beiwort -typ in weiterer Folge weglassen. Wenn wir von Beziehungen auf Objektebene reden, dann werden wir uns an die englische Bezeichnung anlehnen und von Instanzen einer Beziehung sprechen. Eine Beziehung zwischen zwei oder mehreren Entities ist eine Aggregation zwischen diesen Entities. Die Beziehung wird dabei durch die Rolle der an ihr beteiligten Entities beschrieben. Graphisch stellen wir Beziehungen in Form einer Raute dar, deren Ecken mit den beteiligten Entities verbunden sind. Die Rolle schreiben wir über die Raute (Abbildung 2.1). Attribute sind Charakteristika von Entities, die diese beschreiben. Die einzelnen Attribute werden zu einer Entity aggregiert. Eine bestimmte Ausprägung eines Attributes bezeichnen wir als Wert des Attributs. Graphisch stellen wir Attribute durch Ellipsen dar, die mit der KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL 2.5 Entity, die sie charakterisieren, verbunden sind. Der Name des Attributs wird in die Ellipse geschrieben. Zur Unterscheidung von Entitynamen schreiben wir die Attributnamen klein (Abbildung 2.1). Es gibt zwei Arten von Attributen: identifizierende und beschreibende. Identifizierende Attribute oder Schlüssel sind jene Attribute, die einzelne Objekte einer Entity eindeutig kennzeichnen. Beschreibende Attribute oder Nicht-Schlüsselattribute stellen nicht eindeutige Charakteristika der Objekte dar und dienen zur weiteren Beschreibung. Schlüssel können aus einem oder aus mehreren Attributen bestehen. Jede Entity kann mehrere verschiedene Schlüssel haben, wir stellen im ER aber immer einen ausgezeichneten Schlüssel, den Prim ärschlüssel, durch Unterstreichung des Namens oder der Namen dar. Entities, deren Objekte nur mit Hilfe einer anderen Entity oder mehreren anderen Entities, mit der bzw. denen sie in Beziehung stehen, identifiziert werden können, nennen wir Weak Entities. Eine Weak Entity wird durch doppelte Umrahmung dargestellt. Sie hat keine Attribute, die alleine den Schlüssel bilden, obwohl sie dazu beisteuern können. Attribute können mehrwertig sein, wie etwa der typ eines Restaurants. Mehrwertige Attribute werden durch eine doppelte Verbindung zur Entity gekennzeichnet. Weiters können Attribute komplexe Werte annehmen, wie z.B. das Attribut adresse, das selbst aus mehreren anderen Attributen aggregiert wird. Im ER können wir komplexe Attribute entweder dadurch darstellen, dass sie selbst wieder Attribute haben (Abbildung 2.1), oder wir können die einzelnen Teile direkt an die Entity hängen. Beispiel 2.1 Bei der Modellierung von R EINE sind wir in der Einleitung (Kapitel 1) auf die Entities Restaurant, Speise, Kunde und Bestellung gestoßen. Beispiele für Beziehungen in R EINE sind verkauft oder legt. Die Entity Restaurant hat die Attribute name, adresse und typ. Schlüsselattribute sind in diesem Fall name und adresse, da es möglich ist, dass es zwei oder mehrere Restaurants mit demselben Namen gibt, etwa im Falle einer Kette. Der Einfachheit halber führen wir ein Attribut rnr ein, d.h. eine Nummer, die ein Restaurant identifiziert. Dadurch führen wir ein weiteres Schlüsselattribut ein, das für sich alleine die einzelnen Instanzen kennzeichnet; diesen Schlüssel wählen wir als Primärschlüssel. Die Objektmenge Speise wird durch die Attribute name und preis beschrieben. Der Name einer Speise reicht aber alleine nicht zur Kennzeichnung aus, da dieselbe Speise in verschiedenen Restaurants einen unterschiedlichen Preis haben kann. Daher sehen wir, dass der Name einer Speise nur gemeinsam mit der Nummer des jeweiligen Restaurants eindeutig ist. Speise ist also eine Weak Entity, die den Schlüssel der Entity Restaurant zur eindeutigen Kennzeichnung ihrer Objekte benötigt. Das Attribut typ ist ein typisches Beispiel für ein mehrwertiges Attribut, da ein Restaurant sowohl japanisch als auch koreanisch sein kann. Das Attribut adresse wiederum ist ein schönes Beispiel eines komplexen Attributs, das sich aus den Attributen strasse, ort, plz und land zusammensetzt. KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL 2.6 Konzept 1:1 Darstellung und Beispiel nach [Chen, 1976] Restaurant 1 1 Mitarbeiter Darstellung und Beispiel nach [Teorey et al. 1986] Restaurant wird geleitet 1:n Restaurant 1 n Mitarbeiter wird geleitet Mitarbeiter Restaurant Mitarbeiter hat hat n:m Kunde n m Speise bestellt Kunde Speise bestellt Abbildung 2.2: Komplexität von Beziehungen 2.2.2 Komplexität einer Beziehung Die Komplexität einer Beziehung zwischen Entities beschreibt, mit wievielen Instanzen der jeweils anderen Entity jede Instanz einer Entity in Beziehung stehen kann. Bei einer Beziehung zwischen zwei Entities A und B gibt es die folgenden Möglichkeiten: 1:1 jedes Objekt von A zu genau einem Objekt von B und umgekehrt 1:n jedes Objekt von A zu einem oder mehreren von B, aber jedes Objekt von B nur zu einem von A. m:n jedes Objekt von A zu einem oder mehreren in B und umgekehrt. Die Darstellung der Komplexität einer Beziehung nach Chen geschieht durch Anbringung von Ziffern an den jeweiligen Entities. Dabei wird nur zwischen den Werten 1“ und viele ” ” (n, m)“ unterschieden. Die genaue Anzahl der zugeordneten Objekte, d.h. die Kardinalität, wird selten verwendet, da diese sich bei jeder Instanz einer Beziehung unterscheiden kann. Teorey verwendet in [Teorey et al. 1986] nicht mehr die Werte, die wir neben die Entities schreiben, sondern färbt die Hälften der Beziehung ein, die in einer zu-n“ Verbindung zu ” einer Entity steht. In Abbildung 2.2 geben wir für jedes der eben vorgestellten Konstrukte ein Beispiel in der Notation von Chen und jener von Teorey. Beispiel 2.2 In R EINE hat jedes Restaurant genau einen Mitarbeiter als Geschäftsführer und ein Mitarbeiter führt maximal ein Restaurant, was einer 1:1-Beziehung entspricht. Es gibt auch Mitarbeiter, die kein Restaurant leiten, aber diesen Umstand können wir erst mit Hilfe der optionalen Existenz aus dem nächsten Abschnitt darstellen. KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL Konzept zwingend 2.7 Darstellung und Beispiel Restaurant Mitarbeiter hat optional Restaurant Mitarbeiter wird geleitet unbekannt Kunde Speise bestellt Abbildung 2.3: Existenz von Entities in Beziehungen Ein Restaurant beschäftigt natürlich mehrere Mitarbeiter, aber ein Mitarbeiter kann nur in einem Restaurant angestellt sein. Wir möchten hier auch darauf hinweisen, dass die Rolle der Beziehung unterschiedlich bezeichnet werden kann, je nachdem in welche Richtung wir die Beziehung lesen. Kunden wiederum können mehrere Speisen bestellen und eine Speise kann von mehreren Kunden bestellt werden. 2.2.3 Existenz einer Entity in einer Beziehung Wie im letzten Abschnitt beschrieben, gibt die Komplexität einer Beziehung an, mit wievielen Instanzen der anderen Entity jede Instanz der einen Entity in Beziehung stehen kann. Dabei haben wir bis jetzt immer von einer“ oder von vielen“ Instanzen gesprochen. Wir haben ” ” aber keine Möglichkeit auszudrücken, ob es immer mindestens eine Instanz geben muss, oder ob es in der einen Entity eine Instanz geben kann, die mit keiner Instanz der anderen Entity in Beziehung steht. Das Konzept der Existenz einer Entity in einer Beziehung gibt uns die Möglichkeit auch diesen Sachverhalt zu modellieren. Die Existenz einer Entity in einer Beziehung heißt obligatorisch, wenn es zu jeder Instanz dieser Entity mindestens eine Instanz der mit ihr verbundenen Entity gibt, die mit ihr in Beziehung steht. Ist eine solche Instanz nicht unbedingt nötig, so heißt sie optional. Graphisch stellen wir optionale Existenz mit einem Kreis auf der Verbindung zur Entity, obligatorische mit einem senkrechten Strich dar (siehe Abbildung 2.3). Beispiel 2.3 Ein Restaurant in R EINE hat mehrere Mitarbeiter, aber mindestens einen, und jeder Mitarbeiter ist genau einem Restaurant zugeordnet. In diesem Fall stellen wir die KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL 2.8 Konzept Darstellung und Beispiel nach [Chen, 1976] Darstellung und Beispiel nach [Teorey et al. 1986] m unär Kunde Kunde n verwandt mit binär Lieferant ternär Mitarbeiter 1 n Auto verwandt mit Lieferant Auto hat hat Bestellung n Bestellung 1 1 Auto Mitarbeiter liefert Auto liefert Abbildung 2.4: Grad von Beziehungen zwingende Existenz einer Instanz der Entities Restaurant und Mitarbeiter in der Beziehung hat durch einen senkrechten Strich in Abbildung 2.3 dar. Weiters sind manche Mitarbeiter Geschäftsführer eines Restaurants. Die optionale Existenz einer Instanz der Entity Restaurant in der Beziehung wird geleitet stellen wir durch den Kreis in Abbildung 2.3 dar. In der Beziehung bestellt zwischen den Entities Kunde und Speise lassen wir die Existenz von Instanzen offen. 2.2.4 Grad einer Beziehung Der Grad einer Beziehung ist die Anzahl der Entities, die in dieser Beziehung miteinander verbunden sind. Eine Beziehung heißt n-äre Beziehung, wenn sie vom Grad n ist. Unäre, binäre und ternäre Beziehungen sind Spezialfälle, wobei unäre und binäre Beziehungen die in der realen Welt am häufigsten vorkommenden sind. Unäre Beziehungen, das sind Beziehungen einer Entity mit sich selbst, heißen auch binär rekursive Beziehungen (siehe Abbildung 2.4). Ternäre Beziehungen, also Beziehungen zwischen drei Entities, benötigen wir, wenn binäre Beziehungen den Sachverhalt nicht ausreichend beschreiben. Kann jedoch eine ternäre Beziehung mit Hilfe von zwei oder drei binären Beziehungen ausgedrückt werden, so ist der Einfachheit und Klarheit wegen die Darstellung durch binäre Beziehungen vorzuziehen. Auch bei ternären Beziehungen wird die Komplexität entweder durch Angabe eines Wertes oder Einfärben der Ecken angegeben. Im Falle von ternären Beziehungen hat eine Entity Komplexität eins“, wenn es zu Instanzen der beiden anderen Entities gemeinsam maximal ” KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL 2.9 eine ihrer Instanzen gibt, sie hat Komplexität n“, wenn es zu Instanzen der beiden anderen ” Entities gemeinsam mehrere Instanzen ihrer Entities geben kann. Beispiel 2.4 Wollen wir für Kunden, die miteinander verwandt sind, einen Bonus einführen, so müssen wir die Verwandtschaft mitmodellieren. Daraus erhalten wir eine unäre (binär rekursive) Beziehung zwischen den Kunden. Modellieren wir für R EINE den Bereich der Lieferungen, so identifizieren wir die Entities Lieferant, Mitarbeiter und Auto. Eine Lieferfirma hat mehrere Mitarbeiter und Autos. Daher gibt es zwischen den Entities Lieferant und Auto eine binäre Beziehung, ebenso wie zwischen Lieferant und Mitarbeiter. Für eine konkrete Bestellung wird von der Lieferfirma ein Auto und ein Mitarbeiter abgestellt. Daher erhalten wir folgende ternäre Beziehung, die wir in Abbildung 2.4 graphisch darstellen: • Ein Mitarbeiter verwendet für eine Bestellung genau ein Auto. • Ein Auto wird bei einer Bestellung von genau einem Mitarbeiter gefahren. • Ein Mitarbeiter kann mit einem bestimmten Auto mehrere Bestellungen erledigen. Insgesamt gibt es bei ternären Beziehungen vier verschiedene Möglichkeiten, die Komplexität zu kombinieren: drei zu 1“- Beziehungen, zwei zu 1“- Beziehungen und eine zu ” ” ” n“- Beziehung, eine zu 1“- Beziehung und zwei zu n“- Beziehungen oder drei zu n“- Be” ” ” ziehungen. Eine ausführliche Beschreibung dieser Möglichkeiten wird in [Teorey, 1999] und [Teorey et al. 1986] (im Anhangzum Skriptum der Laborübung) gegeben. 2.2.5 Attribute einer Beziehung Attribute können, wie wir gesehen haben, zu Entities aggregiert werden. Es gibt aber auch die Möglichkeit, Attribute zu Beziehungen zu aggregieren. So können wir die Attribute anzahl und datum zur Beziehung zwischen Kunde und Speise schreiben. Dadurch tragen wir dem Umstand Rechnung, dass ein Kunde eine Speise mehrmals an unterschiedlichen Tagen bestellen kann. Würden wir diese Attribute zum Kunden aggregieren, würden wir ein mehrwertiges Attribut erhalten und zudem die Information verlieren, welche Speise der Kunde zu welchem Datum bestellt hat. Attribute werden üblicherweise jedoch nur zu n:m-Beziehungen aggregiert, da im Falle von 1:1-oder 1:n-Beziehungen zumindest auf einer der beiden Seiten der Beziehung ein einziges Objekt steht und damit die Mehrdeutigkeit kein Problem darstellt. Wollen wir in der Beziehung zwischen Restaurant und Mitarbeiter auch das Einstellungsdatum modellieren, so können wir das Attribut datum zum Mitarbeiter aggregieren. Ändert sich der Grad der Beziehung, d.h. soll es möglich sein, dass Mitarbeiter in mehreren Restaurants arbeiten, dann müssen wir das Attribut datum vom Mitarbeiter zur Beziehung schieben. Wenn wir Attribute zu n:m-Beziehungen aggregieren, müssen wir uns überlegen, ob wir nicht an Stelle der Beziehung eine Weak Entity modellieren, zu der die Attribute aggregiert KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL 2.10 datum datum anzahl Kunde Speise Kunde anzahl Bestellung Speise bestellt Abbildung 2.5: Attribute einer Beziehung vs. Weak Entity werden. Jede n:m-Beziehung entspricht einer Weak Entity, die durch 1:n-Beziehungen mit den beiden sie definierenden Entities verbunden ist (siehe Abbildung 2.5). Beispiel 2.5 Im Falle der n:m-Beziehung bestellt mit den Attributen datum und anzahl ist die Modellierung einer Weak Entity Bestellung sicher klarer, wie wir in Beispiel 2.5 zeigen. 2.3 Erweiterte ER-Konstrukte 2.3.1 Die Generalisierung Das Konzept der Verallgemeinerung konnte mit den Mitteln des im letzten Abschnitt besprochenen ER-Modells nur sehr dürftig dargestellt werden, nämlich als eine spezielle 1:1Beziehung zwischen zwei Entities, die mit is-a gekennzeichnet wurde. So konnten wir die Entities Mitarbeiter und Kunden, die viele gemeinsame Attribute besitzen, zu einer Entity Person verallgemeinern und mit jeweils einer 1:1-Beziehung verbinden. Die Attribute der Person werden entlang der Verallgemeinerungshierarchie vererbt und spezielle Attribute – wie die Sozialversicherungsnummer der Mitarbeiter – nur bei den speziellen Entities gespeichert. Ein erweitertes Konstrukt hingegen, die Generalisierung, ermöglicht es uns, diesem Umstand besser gerecht zu werden und außerdem noch einige andere Sachverhalte auszudrücken. Die Generalisierung gibt an, dass mehrere Entities (Subtyp-Entities) mit bestimmten gemeinsamen Attributen zu einer Entity auf einer höheren Ebene (Supertyp-Entity) generalisiert werden können. Die Disjunktheit der Generalisierung beschreibt, ob die einzelnen SubtypEntities disjunkt (disjoint) oder überlappend (overlapping) sind. Im Falle von überlappenden Subtyp-Entities wurde früher auch von Subsets gesprochen, bei disjunkten Subtyp-Entities von Generalisierung, wobei in diesem Fall die Supertyp-Entity durch ein den Subtyp-Entities gemeinsames Attribut mit unterschiedlichen Werten partitioniert wird. Die Vollständigkeit in der Generalisierung gibt an, ob die Subtyp-Entities die Supertyp-Entity vollständig abdecken oder nur teilweise. Durch die beiden Eigenschaften der Disjunktheit und der Vollständigkeit sind in Summe vier Kombinationen möglich. Eine Subtyp-Entity kann ihrerseits wieder eine Supertyp-Entity bezüglich anderer Entities darstellen. Mehrere derartige Subtyp/Supertyp Strukturen werden auch als Generalisie- KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL Person 2.11 Person o is-a Kunde Mitarbeiter d Mitarbeiter Schreibkraft Angestellter Manager Abbildung 2.6: Beispiel einer Generalisierungshierarchie in R EINE rungshierarchie bezeichnet, entlang der die Attribute jeweils von den Supertyp-Entities zu den Subtyp-Entities weitergegeben werden. Graphisch wird die Generalisierung durch eine Verbindung der Subtyp-Entities mit der Supertyp-Entity dargestellt, wobei in einem Kreis angegeben wird, ob es sich um disjunkte ( d“) oder überlappende ( o“) Subtyp-Entities handelt. Weiters wird das Teilmengen Symbol ” ” auf den Verbindungslinien aufgezeichnet. Im Falle einer vollständigen Überdeckung verwenden wir eine doppelte Linie als Verbindung zwischen der Supertyp-Entity und dem Kreis. Beispiel 2.6 In R EINE werden verschiedenste Personendaten gespeichert. So können wir zwischen Kunden und Mitarbeitern unterscheiden. Beide Entities sind Subtyp-Entities der Entity Person, und da Mitarbeiter auch gleichzeitig Kunden sein können, haben wir zwei überlappende Subtyp-Entities. Da wir keine anderen Personen außer Kunden und Mitarbeiter speichern wollen, handelt es sich hierbei um eine totale überlappende Generalisierung. Die Mitarbeiter selber können wir in die disjunkten Subtyp-Entities Manager, Angestellter und Schreibkraft unterteilen. Da es auch Mitarbeiter gibt, die in keine dieser Kategorien fallen, ist diese Generalisierung nicht vollständig (Abbildung 2.6). 2.3.2 ER-Constraints Für die Modellierung des konzeptionellen Schemas einer Datenbank gibt es nicht nur die ERMethoden, sondern verschiedenste andere Denkansätze, wobei einige eine reichere Semantik als das ER-Modell bieten. Einer dieser Ansätze ist das Binary Relationship Modell, das Basis der Nijssens Information Analysis Method (NIAM) ist. Die Grundkonstrukte im BR-Modell sind lexical object types, nonlexical object types und roles. Diese entsprechen im ER-Modell Attributen, Entities und Relationships. Ein Vorteil dieses Modells ist, dass die Entscheidung, 2.12 KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL Rechnung + Kreditkarte Lieferant Abbildung 2.7: Beispiel einer Exklusionsbedingung in R EINE ob etwas ein Attribut oder eine Entity ist, so spät als möglich gefällt wird. Weiters gibt es die semantischen Konzepte der Generalisierung, Komplexität von Beziehungen und Existenz von Entities in Beziehungen (optional und zwingend). Eine wirkliche Erweiterung der Semantik im Binary Relationship Modell ist allerdings die Hinzunahme von Integritätsbedingungen (integrity constraints) bei roles. Wir zeigen im nächsten Abschnitt, wie eine der Bedingungsarten, nämlich Exklusionsbedingungen (exclusion constraints), dem ER-Modell hinzugefügt werden kann. Wir möchten aber sehr wohl darauf hinweisen, dass eine reichere Semantik im konzeptuellen Modell nicht unbedingt zu einem besseren Entwurf führen muss, da das Modell wesentlich komplexer und dadurch unverständlicher werden kann, als bei der Verwendung einfacher semantischer Konzepte. 2.3.2.1 Exklusionsbedingungen Üblicherweise wird, wenn eine Entity mit mehreren anderen Entities binär verbunden ist, angenommen, dass einige oder alle diese Entities mit der ersten in Beziehung stehen. Die Exklusionsbedingung ermöglicht es uns zu modellieren, dass von mehreren (im Besonderen zwei) Entities immer nur eine in Beziehung zur ersten Entity tritt. Dargestellt wird die Exklusionsbedingung durch eine Verbindung der daran beteiligten Beziehungen, die mit einem Kreis und einem +“ gekennzeichnet ist, wie wir in Abbildung 2.7 sehen können. ” Beispiel 2.7 In R EINE werden zur Bezahlung der Rechnungen mehrere Möglichkeiten angeboten. Eine davon ist über Kreditkarte, eine weitere über Barbezahlung beim Lieferanten. Daher müssen wir bei der Entity Rechnung einerseits eine Beziehung zur Entity Kreditkarte und andererseits auch zur Entity Lieferant haben, wobei jedoch für jede Rechnung entweder nur der Verweis auf die Kreditkarte oder der Verweis auf den Lieferanten von nöten ist, niemals aber beides. Diesen Umstand haben wir in Abbildung 2.7 dargestellt. KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL 2.13 2.4 Objektorientierte Datenmodellierung Objektorientierte Datenbankmanagementsysteme, die bis vor ein paar Jahren noch recht selten benutzt wurden, nehmen langsam aber sicher eine immer wichtigere Rolle auf dem Datenbanksektor ein. Dabei wurden wohlbekannte Konzepte der objektorientierten Programmierung mit neuen Ideen der Datenmodellierung verknüpft. Im objektorientierten Ansatz werden Klassen als eine Menge von Methoden – Operationen auf bestimmten Klassen von Objekten – gesehen, das ER-Modell hingegen beschränkt sich auf die Sicht von Klassen (Sub- und Supertyp) als Beziehung zwischen Objekten und ignoriert das dynamische Verhalten von Objekten. Im folgenden Abschnitt werden wir kurz auf die wichtigsten objektorientierten Konzepte eingehen. 2.4.1 Objektorientierte Konzepte Vier Charakteristika zeichnen den objektorientierten Ansatz aus: Identität, Klassifizierung, Polymorphismus und Vererbung. Identität: Die Daten werden in unterscheidbare Objekte aufgeteilt. Jedes Objekt (Instancelevel) besitzt eine eigene Identität aufgrund seiner inhärenten Existenz und nicht aufgrund von beschreibenden Eigenschaften, die es hat. So sind zwei Äpfel, die gleiches Aussehen haben, dennoch zwei unterschiedliche Dinge, sie können z.B. von verschiedenen Personen gegessen werden. Klassifizierung: Objekte mit denselben Datenstrukturen (Attributen) und demselben Verhalten werden zu einer Klasse zusammengefasst. Die Objekte haben für jedes Attribut eigene Werte, aber die Namen der Attribute und Methoden (Operationen) werden mit den anderen Objekten der Klasse geteilt. Weiters umfasst die Klassifizierung auch die Konzepte der Datenabstraktion (selektive Betrachtung bestimmter Aspekte eines Problems) und –kapselung (Trennung des externen Verhaltens eines Objekts von der konkreten Implementierung). Polymorphismus: Eine bestimmte Operation kann sich innerhalb verschiedener Klassen verschieden verhalten. Eine Operation copy etwa wird unterschiedliche Implementierungen für verschiedene Speichermedien wie Buffer oder Dateien auf der Platte besitzen. Vererbung: Attribute und Operationen werden entlang der Klassenhierarchie vererbt. Jede Klasse kann mehrere Unterklassen besitzen, die Attribute und Operationen ihrer Superklasse erben, und zusätzlich neue Attribute und Operationen definieren. Etwas problematisch und in verschiedenen objektorientierten Programmiersprachen unterschiedlich behandelt ist Mehrfachvererbung, wonach eine Klasse mehrere Superklassen haben kann und daher von unterschiedlichen Seiten erbt. 2.14 KAPITEL 2. KONZEPTIONELLE DATENMODELLE UND DAS ER MODELL Zu den am meisten verbreiteten objektorientierten Analyse- (OOA) und Design- (OOD) Techniken gehören OOA nach Shlaer und Mellor (1988) und Coad und Yourdon (1990), OOD nach Booch und die Object Modeling Technique (OMT) von Rumbaugh. Eine in letzter Zeit immer weiter verbreitete Technik ist die Unified Modeling Language (UML), eine Weiterentwicklung und Zusammenführung von OMT und OOD. Kapitel 3 Das Relationenmodell In diesem Kapitel stellen wir das Relationenmodell vor, das heute die Grundlage vieler kommerzieller Datenbankmanagementsysteme, wie ADABAS, DB2, INFORMIX, INGRES, SYBASE, ORACLE, PROGRESS und UNIFY bildet und somit das am weitesten verbreitete logische Datenmodell ist. Nach der Vorstellung des Relationenmodells und der darauf möglichen Operationen beschreiben wir kurz, wie eine Übersetzung des ER-Modells in das Relationenmodell durchzuführen ist. Am Ende des Kapitels stellen wir weitere Sprachen für das Relationenmodell vor. Das Relationenmodell wurde von E. F. Codd 1970 entwickelt. Es repräsentiert die Daten einer Datenbank als eine Menge von Relationen. Eine Relation können wir uns dabei als Tabelle vorstellen, deren Zeilen Objekte der Anwendungsumgebung oder Beziehungen zwischen Objekten der Anwendungsumgebung beschreiben. Der Tabellenkopf heißt Relationenschema, die einzelnen Spalten werden als Attribute bezeichnet, die einzelnen Zeilen als Tupel. 3.1 Formalisierung des Relationenmodells Ein Relationenschema R ist eine endliche Menge von Attributnamen {A 1 , A2 , ...An }. Attributnamen werden auch kurz als Attribute bezeichnet. Seien R und S zwei Relationenschemata, so bezeichnet RS die Menge aller Attributnamen aus R und S, wobei gleiche Namen nur einmal vorkommen. Zu jedem Attributnamen Ai gibt es eine Menge Di , 1 ≤ i ≤ n, den Wertebereich (domain) von Ai , der auch mit Dom(Ai ) bezeichnet wird. Die Wertebereiche sind beliebige, nicht leere, endliche oder abzählbar unendliche Mengen. Sei D = D1 ∪ D2 ∪ D3 ∪ ... ∪ Dn . Eine Relation r(R) auf einem Relationenschema R ist eine endliche Menge von Abbildungen {t1 , ..., tm } von R nach D, wobei für jede Abbildung tj ∈ r(R), tj (Ai ) aus Di stammt, 1 ≤ i ≤ n, 1 ≤ j ≤ m. Die Abbildungen werden Tupel genannt. Intuitiv stellt ein Relationenschema R eine Menge von gültigen Instanzen r(R) dar. 1 3.2 KAPITEL 3. DAS RELATIONENMODELL Beispiel 3.1 In Kapitel 1 haben wir bei der Vorstellung des logischen Entwurfs schon ein Beispiel (siehe Abbildung 1.13) für eine Relation gesehen. Dabei war Restaurant ein Relationenschema mit den Attributen rnr, name, adresse, haube und typ, Speise ein Relationenschema mit den Attributen name und preis. Die Relationenschemata sehen daher folgendermaßen aus (warum bei der Relation Speise das Attribut rnr vorkommt, werden wir am Ende dieses Abschnittes erklären; intuitiv deshalb, damit wir feststellen können, welche Speise welchem Restaurant zugeordnet ist): Restaurant = {rnr, name, adresse, haube, typ} Speise = {name, preis, rnr} Eine mögliche Relation für Restaurant und Speise zeigen wir in Abbildung 3.1. Beispiel 3.2 Für das Relationenschema Restaurant={rnr, name, adresse, haube,typ} aus Beispiel 3.1 können wir folgende Angaben machen: • Dom(rnr) = Menge aller Integer. • Dom(name) = Menge aller Namen. • Dom(adresse) = Menge aller Adressen. • Dom(haube) = {k | 0 ≤ k ≤ 4}. • Dom(typ) = Menge aller Restauranttypen. • Die Tabelle hat 9 Tupel. Eines von ihnen ist t mit: • t(rnr) = 3, • t(name) = Green Cottage, • t(adresse) = Kettenbrückengasse 3, 1050 Wien, • t(haube) = 2, • t(typ) = chinesisch. Der Wert eines Tupels t für ein Attribut A, t(A) = a, heißt A-Wert von t. Sei X eine Teilmenge von R. Unter der Einengung des Tupels t auf die Attributmenge X ⊂ R, genannt t0 (X), verstehen wir jenes Tupel t0 , das jedem A ∈ X genau dieselben Werte aus Dom(A) zuordnet wie t. Beispiel 3.3 Sei t das Tupel mit t(rnr) = 3, t(name) = Green Cottage, t(adresse) = Kettenbrückengasse 3, 1050 Wien, t(haube) = 2 und t(typ) = chinesisch. • Der adresse-Wert von t ist t(adresse) = Kettenbrückengasse 3, 1050 Wien. • Die Einengung von t auf die Attribute {name, adresse} ist das Tupel t 0 definiert als t0 (name) = Green Cottage, t0 (adresse) = Kettenbrückengasse 3, 1050 Wien. Ein Schlüssel (key) einer Relation r(R) ist eine Teilmenge K von R, sodass für je zwei verschiedene Tupel t1 und t2 aus r(R) immer t1 (K) 6= t2 (K) gilt, und keine echte Teilmenge K 0 von K diese Eigenschaft hat. S ist ein Oberschlüssel (superkey), wenn S einen Schlüssel enthält. Jeder Schlüssel ist also auch ein Oberschlüssel, die Umkehrung gilt hingegen im Allgemeinen nicht. KAPITEL 3. DAS RELATIONENMODELL Restaurant rnr name 1 Gußhaus 2 A Tavola 3 Green Cottage 4 Drei Husaren 5 San Carlo 6 Toko-Ri 7 Steirereck 8 Carpaccio 9 Indian Pavillion adresse Gußhausstraße 23, 1040 Wien Weihburggasse 3-5, 1010 Wien Kettenbrückengasse 3, 1050 Wien Weihburggasse 4, 1010 Wien Mahlerstraße 3, 1010 Wien Franz-Hochedlinger-Gasse 2, 1020 Wien Rasumofskygasse 2, 1030 Wien Paniglgasse 22, 1040 Wien Naschmarkt Stand 74-75, 1040 Wien 3.3 haube 1 2 2 0 4 1 0 Speise name Gebratener Rehrücken mit Serviettenknödel Gefüllte Perlhuhnbrust mit Maroniknöderln Zarte Rotbarbe auf Wildreis Gemischte Käseplatte Gemischter Vorspeisenteller Penne all’ Arrabiata Hühnerfleisch der tausend Geschmäcker Wolfsbarschfilet mit sichuanesischer Lauchsauce Gebratene Seeteufel Eisei im gebackenen Nudelnest Geeiste Karfiolrahmsuppe Gedünstetes Beiried in Zweigeltsauce Tafelspitz mit Markscheiben, Cremespinat und gestürzten Erdäpfeln Orangenblütenmousse in der Babyananas Joghurt-Grießflammeri mit Beeren Husarenpfannkuchen Kleines Sushi Großes Sushi Gemischte Maki für 2 Personen typ österreichisch toskanisch chinesisch österreichisch italienisch japanisch international italienisch indisch preis rnr 21 1 26 1 25 1 10 1 10 2 9,5 2 6,5 3 25 3 23 3 6,5 3 7 4 25 4 23 4 7 4 6,5 4 10 4 12 6 15 6 21 6 Abbildung 3.1: Beispiele einer Relation für Restaurant und Speise in R EINE KAPITEL 3. DAS RELATIONENMODELL 3.4 Beispiel 3.4 Betrachten wir wieder das Relationenschema Restaurant aus Beispiel 3.1. Aus der Tabelle mit den Entity-Instanzen ist ersichtlich, dass alle Attribute bis auf haube und typ als Schlüssel in Frage kommen. Da ein Schlüssel aber auch zeitinvariant sein sollte, und wir nicht wissen, ob wir nicht einmal zwei Restaurants mit demselben Namen in unsere Relation eintragen müssen, ist es sinnvoller, die Restaurantnummer rnr als Schlüssel zu wählen. Genauso ist es möglich, dass an einer Adresse zwei Restaurants, z.B. ein Restaurant und ein Schnellimbiss mit unterschiedlichem Namen eingerichtet werden können. Das Relationenschema für die Speise im ER haben wir als Weak Entity modelliert, da eine Speise mit einem bestimmten Namen in mehreren Restaurants angeboten werden kann. Der Name ist daher nur bezogen auf ein bestimmtes Restaurant eindeutig. Schlüssel, die explizit zu einem Relationenschema angeführt sind, heißen ausgezeichnete Schlüssel (designated keys). Im Allgemeinen wird dabei ein Schlüssel als Prim ärschlüssel ausgezeichnet und im Relationenschema durch Unterstreichen der Schlüsselattribute gekennzeichnet. Beispiel 3.5 Die Relationenschemata für Restaurant und Speise mit gekennzeichnetem Primärschlüssel sehen wie folgt aus: Restaurant = {rnr, name, adresse, haube, typ} Speise = {name, preis, rnr} 3.2 Operationen auf Relationen Um Operationen auf Relationen durchführen zu können, wurde von Codd im Jahr 1972 die relationale Algebra eingeführt. Die wichtigsten Operationen der relationalen Algebra sind Mengenoperationen, Selektion, Projektion, Division und die Verbundoperation (join). Im folgenden bezeichnen r und s Relationen über den Relationenschemata R bzw. S. 3.2.1 Die Mengenoperationen Zu den Mengenoperationen gehören • Durchschnitt ( ∩“), ” • Vereinigung ( ∪“) und ” • Differenz ( −“ oder \“) ” ” von Relationen, die über der gleichen Attributmenge mit derselben Anordnung (der identischen Reihenfolge der Attribute) definiert sind. KAPITEL 3. DAS RELATIONENMODELL 3.5 Beispiel 3.6 r (A a1 a1 a2 B b1 b2 b1 C) c1 c1 c2 s (A a1 a2 a2 B b2 b2 b2 C) c1 c1 c2 r∩s= (A B C) a1 b 2 c1 r∪s= (A B a1 b 1 a1 b 2 a2 b 1 a2 b 2 a2 b 2 r−s= (A B C) a1 b 1 c1 a2 b 1 c2 s−r= (A B C) a2 b 2 c1 a2 b 2 c2 C) c1 c1 c2 c1 c2 3.2.2 Die Selektion Bei der Selektion werden Zeilen ausgewählt, die einem bestimmten Kriterium entsprechen. Formal σA=a (r) = {t ∈ r | t(A) = a} Der Selektionsoperator ist kommutativ bezüglich der Komposition (Zusammensetzung): σA1 =a (σA2 =b (r)) = σA2 =b (σA1 =a (r)). Beispiel 3.7 Wieder zu unserem Beispiel mit den Restaurants. Wir selektieren alle jene Restaurants, die zwei Hauben haben. σhaube=2 (Restaurant) = rnr name adresse 3 Green Cottage Kettenbrückengasse 3, 1050 Wien 4 Drei Husaren Weihburggasse 4, 1010 Wien haube 2 2 typ chinesisch österreichisch KAPITEL 3. DAS RELATIONENMODELL 3.6 3.2.2.1 Erweiterung der Selektion Um die Kriterien, nach denen selektiert werden soll, etwas allgemeiner zu halten, können wir in der erweiterten Selektion beliebige Vergleichsoperatoren verwenden und nicht nur mit Konstanten vergleichen. Sei Θ eine Menge von Vergleichsoperatoren θ ∈ Θ ein Operator aus dieser Menge und a eine Konstante aus dem Wertebereich Dom(A) von A: σAθa (r) = {t ∈ r | t(A)θa} σA1 θA2 (r) = {t ∈ r | t(A1 )θt(A2 )} Noch allgemeiner wird die Selektion, wenn wir erlauben, wohldefinierte Operatoren auf den Attributwerten auszuführen, z.B. arithmetische Operationen auf Zahlwerten, und logische Verknüpfungen von Attributen durch und“ (∧), oder“ (∨) und Negation (¬). ” ” Beispiel 3.8 Nun selektieren wir in der Relation Restaurant alle jenen Restaurants, die mehr als eine Haube, aber keine österreichische oder internationale Küche haben. σhaube>1∧¬(typ=0 österreichisch 0 ∨typ=0 international 0 ) (Restaurant) = rnr name adresse 3 Green Cottage Kettenbrückengasse 3, 1050 Wien haube 2 typ chinesisch 3.2.3 Die Projektion Bei der Projektion werden gewisse Spalten einer Tabelle ausgewählt; wir projizieren nach einer Teilmenge der Attribute: πX (r) = {t(X) | t ∈ r} für X ⊆ R Alternativ kann, falls die Attribute des Relationenschemas geordnet betrachtet werden, die Nummer des projizierten Attributs angegeben werden: z.B.: π2,3,5 (Restaurant) = πname,adresse,typ (Restaurant) Der Projektionsoperator ist kommutativ bezüglich der Selektion, wenn die Attribute, auf denen selektiert wird, in den projizierten Attributen enthalten sind: πA1 ,A2 (σA1 θa (r)) = σA1 θa (πA1 ,A2 (r)) Beispiel 3.9 Wir projizieren die Relation Restaurant nach den Attributen name, adresse und haube. πname,adresse,haube (Restaurant) = KAPITEL 3. DAS RELATIONENMODELL name Gußhaus A Tavola Green Cottage Drei Husaren San Carlo Toko-Ri Steirereck Carpaccio Indian Pavillion 3.7 adresse Gußhausstraße 23, 1040 Wien Weihburggasse 3-5, 1010 Wien Kettenbrückengasse 3, 1050 Wien Weihburggasse 4, 1010 Wien Mahlerstraße 3, 1010 Wien Franz-Hochedlinger-Gasse 2, 1020 Wien Rasumofskygasse 2, 1030 Wien Paniglgasse 22, 1040 Wien Naschmarkt Stand 74-75, 1040 Wien haube 1 2 2 0 4 1 0 3.2.4 Der Verbund 3.2.4.1 Der natürliche Verbund (natural join) Der Verbundoperator verknüpft zwei Relationen über ihre gemeinsamen Attribute: r ./ s = {t(RS) | ∃tr ∈ r und ∃ts ∈ s : tr = t(R) und ts = t(S)}. Der Verbundoperator ist kommutativ. Beispiel 3.10 Nehmen wir wieder Bezug auf unsere Relationen Restaurant und Speise. Der natürliche Verbund verknüpft beide Relationen über die gemeinsamen Attribute und gibt daher jene Tupel aus, bei denen sowohl der Name name des Restaurants und der Name name der Speise als auch die Restaurantnummer rnr des Restaurants und jene der Speise gleich sind. In unserem Fall ist das die leere Menge. Restaurant ./ Speise = rnr name adresse haube typ preis 3.2.4.2 Das Kartesische Produkt Falls R ∩ S = {}, die beiden Relationenschemata also kein gemeinsames Attribut haben, so liefert die Verknüpfung r ./ s das Kartesische Produkt, geschrieben als r × s“. ” Beispiel 3.11 Betrachten wir die folgenden Relationen r und s: r (A a1 a2 B) b1 b1 s (C c1 c2 c2 D) d1 d1 d2 KAPITEL 3. DAS RELATIONENMODELL 3.8 r × s = r ./ s = (A B C D) a1 b 1 c1 d 1 a1 b 1 c2 d 1 a1 b 1 c2 d 2 a2 b 1 c1 d 1 a2 b 1 c2 d 1 a2 b 1 c2 d 2 Wie wir oben gesehen haben, ist das Kartesische Produkt nur für den Fall definiert, dass R ∩ S = {}. Wollen wir das Kartesische Produkt von Relationen bilden, die gemeinsame Attribute haben, so müssen diese in einer der Relationen umbenannt werden. Ist etwa R = {A, B, C} und S = {A, B, D}, so benennen wir die Attribute von S um sodass S = {A 0 , B0 , D} oder kennzeichnen sie durch Voranstellen des Relationennamens, also S = {S.A, S.B, D}. Projektionseigenschaften des Verbundoperators: Seien R und S zwei Relationenschemata q = s ./ r und r0 = πR (q), dann gilt: r0 ⊆ r. Joinen wir also eine Relation r mit einer anderen und projizieren dann nach den ursprünglichen Attributen von r, so können unter Umständen Tupel verloren gehen, wie wir anhand des folgenden Beispieles sehen. Beispiel 3.12 Betrachten wir die folgenden Relationen r und s: r (A a a B) b b0 r ./ s = q (A B C) a b c s (B b C) c πAB (q) = r0 (A B) a b Sei q eine Relation über RS und q0 = πR (q) ./ πS (q), so gilt: q0 ⊇ q. In anderen Worten, ist q eine Relation mit den Attributmengen R und S und projizieren wir q zuerst nach diesen zwei Attributmengen, um die Ergebnisse danach wieder miteinander zu verbinden, so erhalten wir unter Umständen mehr Tupel als in der ursprünglichen Relation. Gilt q0 = q, dann sagen wir, die Relation q(RS) ist verlustfrei zerlegbar (decomposes losslessly) in r(R) = πR (q) und s(S) = πS (q). Eine Relation q = r ./ s ist dann verlustfrei zerlegbar, wenn die Join-Attribute zwischen den Relationen r und s Schlüssel in einer der beiden Relationen sind. Dieses Kriterium wird später für die korrekte Zerlegung von Relationenschemata benötigt (siehe Kapitel 7). KAPITEL 3. DAS RELATIONENMODELL 3.9 Beispiel 3.13 Sei R = AB, S = BC und q der Gestalt: q (A a a B b b’ C) c c’ bzw. q (A a a a’ B b b’ b C) c c’ c’ q0 (A a a B b b’ C) c c’ Im ersten Fall ist q verlustfrei zerlegbar, denn r (A a a B) b b’ s (B b b’ C) c c’ Im zweiten Fall ist q nicht verlustfrei in r und s zerlegbar: q0 = r ./ s enthält 2 überschüssige Tupel: r (A a a a’ B) b b’ b s (B b b’ b C) c c’ c’ q0 (A a a a a’ a’ B b b’ b b b C) c c’ c’ c’ c 3.2.4.3 Der Gleichverbund (equi-join) Seien R und S Relationen, R ∩ S = {}. Ai ∈ R, Bi ∈ S, und Dom(Ai ) = Dom(Bi ), 1 ≤ i ≤ n. Der Gleichverbund von r und s über den Attributen A1 , ..., An und B1 , ..., Bn , notiert als r [ A1 = B1 , ..., An = Bn ] s ist die Relation: q(RS) = {t | ∃ts ∈ s ∧ ∃tr ∈ r : t(R) = tr , t(S) = ts und t(Ai ) = t(Bi ), 1 ≤ i ≤ n}. D.h., wir setzen jeweils zwei Attribute aus den Relationen r und s gleich, was natürlich nur möglich ist, wenn der Wertebereich dieser Attribute übereinstimmt. Wie beim Kartesischen Produkt müssen auch hier gemeinsame Attribute umbenannt werden, falls R ∩ S 6= {}. Beispiel 3.14 Wir wollen nun wissen, welche Speisen in welchem Lokal angeboten werden, wenn wir wieder die Relationen Restaurant und Speise aus Abbildung 3.1 betrachten. Da zwei Attribute in den beiden Relationen denselben Namen haben, müssen wir zumindest eines KAPITEL 3. DAS RELATIONENMODELL 3.10 umbenennen. Wir benennen die Attribute der Relation Speise um, indem wir ein 0 an ihre Namen hängen. Restaurant [ rnr = rnr0 ] Speise = rnr 1 1 1 1 2 2 3 3 3 3 .. . name Gußhaus Gußhaus Gußhaus Gußhaus A Tavola A Tavola Green Cottage Green Cottage Green Cottage Green Cottage .. . 6 Toko-Ri 6 Toko-Ri 6 Toko-Ri adresse haube Gußhau... 1 Gußhau... 1 Gußhau... 1 Gußhau... 1 Weihbu... Weihbu... Ketten... 2 Ketten... 2 Ketten... 2 Ketten... 2 .. .. . . Franz-... Franz-... Franz-... typ öster... öster... öster... öster... toska... toska... chine... chine... chine... chine... .. . name0 Gebratener Reh... Gefüllte Perlh... Zarte Rotbarb... Gemischte Käse... Gemischter Vors... Penne all’ Arra... Hühnerfleisch ... Wolfsbarschfil... Gebratene Seet... Eisei im gebac... .. . japan... Kleines Sushi japan... Großes Sushi japan... Gemischte Mak... preis0 21 26 25 10 10 9,5 6,5 25 23 6,5 .. . rnr0 1 1 1 1 2 2 3 3 3 3 .. . 12 15 21 6 6 6 Anmerkung: Die Lesbarkeit obiger Notation leidet, wenn der Gleichverbund zwischen zwei Kopien der selben Tabelle durchgeführt wird, z.B. wenn wir nach Paaren von Restaurants suchen, die dieselbe Anzahl an Hauben haben: Restaurant [ haube = haube 0 ] Restaurant. Es empfiehlt sich hier einen sprechenden Bezeichner (alias) für jede Kopie zu vergeben, z.B.: Restaurant eins [ haube = haube0 ] Restaurant zwei. 3.2.4.4 Der Theta-Verbund (theta-join) Seien r(R), s(S) Relationen, wobei R ∩ S = {}. Sei A ∈ R, B ∈ S, und die Elemente aus Dom(A) seien mit den Elementen aus Dom(B) mittels der Operatoren aus Θ vergleichbar. Sei θ ∈ Θ. Der Thetaverbund r [ A θ B ] s ist die Relation: q(RS) = {t | ∃ts ∈ s ∧ ∃tr ∈ r : t(R) = tr , t(S) = ts und tr (A)θts (B)}. D.h., wir verfahren wie beim Gleichverbund, nur dass ein allgemeiner Operator, der zu den zu vergleichenden Attributen passt, als Vergleichsoperator verwendet wird. Der Gleichverbund ist also ein Sonderfall des Theta-Verbundes. Falls R∩S 6= {}, müssen wir uns wieder durch Umbenennen der Attribute weiterhelfen. Beispiel 3.15 Wenn wir alle Paare von Restaurants auswählen wollen, die sich um mehr als zwei Hauben unterscheiden, so müssen wir den Theta-Verbund verwenden. KAPITEL 3. DAS RELATIONENMODELL 3.11 Restaurant eins [ haube + 2 < haube0 ] Restaurant zwei = rnr 1 5 8 9 name Gußhaus San Carlo Carpaccio Indian Pa... adresse haube Gußhau... 1 Mahler... 0 Panigl... 1 Naschm... 0 typ rnr0 öster... 7 itali... 7 itali... 7 indi... 7 name0 Steirereck Steirereck Steirereck Steirereck adresse0 Rasum... Rasum... Rasum... Rasum... haube0 4 4 4 4 Wir möchten an dieser Stelle kurz darauf hinweisen, dass es einen Unterschied macht, ob ein Tupel auf einem Attribut den Wert 0“ bzw. den Leerstring annimmt, oder ob nichts ein” getragen ist. Wenn ein Tupel auf einem Attribut keinen Wert annimmt, so nennen wir das einen Nullwert. Mit einem Nullwert können wir, wie das Beispiel zeigt, keine numerischen Vergleiche durchführen, mit dem Wert 0“ hingegen schon (siehe Abschnitt 3.3). ” 3.2.5 Die Division Seien r(R) und s(S) Relationen mit S ⊆ R. Dann ist die Division von r durch s, r ÷ s, die Relation q(R − S) = {t | ∀ts ∈ s : ∃tr ∈ r mit tr (R − S) = t und tr (S) = ts }. D.h., wollen wir die Relation r durch s dividieren, so muss die Attributmenge von s eine Teilmenge der Attributmenge von r sein. Das Ergebnis hat die Differenz der Attributmengen als Attribute und wählt jene Tupel aus r aus, die eingeschränkt auf die Differenz der Attribute R − S für alle Tupel aus s denselben Wert haben. Beispiel 3.16 Angenommen, wir wollen wissen, welche Restaurants Speisen zu bestimmten Preisen anbieten, die in einer Relation Preisliste gespeichert sind. Aus der Relation Speise projizieren wir auf die Attribute preis und rnr. Das Ergebnis dieser Projektion können wir nun durch die Relation Preisliste dividieren und erhalten das gewünschte Resultat. Wir betrachten einmal die Menge der Preise {6.5, 23, 25}, im zweiten Fall die Menge {10, 25} und erhalten jene Restaurants, die Speisen zu allen diesen Preisen anbieten. πpreis,rnr (Speise) ÷ Preisliste A = rnr 3 4 πpreis,rnr (Speise) ÷ Preisliste B = typ0 int... int... int... int... KAPITEL 3. DAS RELATIONENMODELL 3.12 rnr 1 4 wobei die zugrundeliegenden Relationen die folgenden sind: πpreis,rnr (Speise) preis rnr 21 1 26 1 25 1 10 1 10 2 9,5 2 6,5 3 25 3 23 3 6,5 3 7 4 25 4 23 4 7 4 6,5 4 10 4 12 6 15 6 21 6 Preisliste A preis 6,5 23 25 Preisliste B preis 10 25 Wir möchten darauf hinweisen, dass es wichtig ist, den Namen der Speisen vor dem Ausführen der Division wegzuprojizieren; andernfalls wäre das Ergebnis in beiden Fällen die leere Menge, da die Namen der Speisen nicht alle gleich sind. 3.2.6 Der Semiverbund (semijoin) Seien r(R) und s(S) zwei Relationen mit R ∩ S = X 6= {}. Der Semiverbund r n s ist die Relation: q(R) = {tr ∈ r | ∃ts (S) mit tr (X) = ts (X)} Das Ergebnis des Semiverbunds q ist also die Menge aller Tupel von r, die in den Verbund mit s eintreten können. Alternativ können wir den Semiverbund als Kombination von Verbund und Projektion wie folgt darstellen: KAPITEL 3. DAS RELATIONENMODELL 3.13 r n s = πR (r ./ s) Dieser Operator wurde zur Optimierung von Joins auf verteilten Datenbanken entwickelt. Wir werden im Kapitel 9 nochmals darauf zu sprechen kommen. Beispiel 3.17 Wollen wir alle Restaurants auswählen, zu denen es mindestens eine Speise in der Relation Speise gibt, so bilden wir den Semijoin zwischen den Relationen Restaurant und Speise. Das Attribut name in der Relation Speise müssen wir natürlich wieder umbenennen. Restaurant n Speise rnr name adresse 1 Gußhaus Gußhausstraße 23, 1040 Wien 2 A Tavola Weihburggasse 3-5, 1010 Wien 3 Green Cottage Kettenbrückengasse 3, 1050 Wien 4 Drei Husaren Weihburggasse 4, 1010 Wien 6 Toko-Ri Franz-Hochedlinger-Gasse 2, 1020 Wien haube 1 2 2 typ österreichisch toskanisch chinesisch österreichisch japanisch 3.3 Nullwerte Im Rahmen der Erfassung von Daten kommt es häufig vor, dass unvollständige Information modelliert werden muss. Es gibt verschiedene Gründe für unvollständige Information. So kann die Adresse einer Person unbekannt (aber existent) sein, oder es gibt Attribute, die eventuell nicht anwendbar sind, etwa wenn jemand kein Telefon hat. Um unvollständige Information in einer Datenbank zu speichern, müssen wir einen theoretischen Hintergrund erarbeiten, wie die Datenbank mit sogenannten Nullwerten (null values) umgehen soll. Manche Datenmodelle unterscheiden zwischen verschiedenen Arten von Nullwerten (z.B. unbekannt“, nicht anwendbar“), um die fehlende Information trotz ihres ” ” Fehlens näher zu charakterisieren. Die meisten relationalen Datenbankmanagementsysteme unterstützen nur eine Art von Nullwerten, null. Ein Tupel t (eine Relation r), das (die) einen oder mehrere Nullwerte enthält, heißt partiell (partial). Ein Tupel (eine Relation) ohne Nullwerte heißt total, geschrieben t ↓ (r ↓). Ein Attribut A heißt bestimmt (definite), geschrieben als A ↓, wenn der Wert von A nicht null ist. Eine Relation r0 ist eine Vervollständigung (completion) der Relation r, wenn r0 keine Nullwerte mehr enthält und aus r dadurch erhalten wird, dass Nullwerte in r durch Werte aus dem jeweiligen Wertebereich ersetzt werden. Beispiel 3.18 Die Relation Restaurant aus Beispiel 3.1, die wir in Abbildung 3.1 dargestellt haben, ist eine partielle Relation. Ein partielles Tupel ist z.B. das Tupel t(rnr) = 2, da die Anzahl der Hauben des Restaurants A Tavola“ unbekannt ist. Eine mögliche Vervollständigung ” der Relation wäre: KAPITEL 3. DAS RELATIONENMODELL 3.14 Restaurant rnr name 1 Gußhaus 2 A Tavola 3 Green Cottage 4 Drei Husaren 5 San Carlo 6 Toko-Ri 7 Steirereck 8 Carpaccio 9 Indian Pavillion adresse Gußhausstraße 23, 1040 Wien Weihburggasse 3-5, 1010 Wien Kettenbrückengasse 3, 1050 Wien Weihburggasse 4, 1010 Wien Mahlerstraße 3, 1010 Wien Franz-Hochedlinger-Gasse 2, 1020 Wien Rasumofskygasse 2, 1030 Wien Paniglgasse 22, 1040 Wien Naschmarkt Stand 74-75, 1040 Wien haube 1 0 2 2 0 1 4 1 0 typ österreichisch toskanisch chinesisch österreichisch italienisch japanisch international italienisch indisch 3.3.1 Auswertung von Nullwerten Nun ergibt sich natürlich die Frage, wie Abfragen über partiellen Relationen beantwortet werden. Die um Nullwerte erweiterten Wahrheitstabellen sehen folgendermaßen aus ( w“ = wahr, ” f“ = falsch): ” ∧ w f null w w f null f null f null f f f null ∨ w f null w f w w w f w null null w null null ¬ w f null f w null Beispiel 3.19 Betrachten wir noch einmal die partielle Relation aus Beispiel 3.1. Wollen wir wissen, ob es ein Restaurant gibt, das mehr als zwei Hauben und eine internationale Küche hat, so lautet die Antwort ja. Wollen wir hingegen wissen, ob es Restaurants gibt, die weniger als zwei Hauben und eine internationale Küche haben, so ist die Antwort nein. Sind wir aber daran interessiert, ob es ein Restaurant gibt, das mehr als zwei Hauben und eine japanische Küche hat, so ist die Antwort null. 3.3.2 Äußerer Verbund (outer join) Bei einem normalen Join werden nur jene Tupel von Relationen r und s verbunden, die in beiden Relationen auf den gemeinsamen Attributen dieselben Werte annehmen. Beim äußeren Verbund werden die Tupel, die nicht verbindbar (joinable) sind, mit Nullwerten aufgefüllt und zum Ergebnis dazugefügt. Seien r(R) und s(S) zwei Relationen mit R ∩ S = X 6= {}. Sei null(X) definiert als Tupel über X, bestehend nur aus Nullwerten. Sei q = r ./ s, r 0 = r \ πR (q), s0 = s \ πS (q). Der äußere Verbund von r und s (outer join of r and s), geschrieben r ∗ s, ist definiert als KAPITEL 3. DAS RELATIONENMODELL 3.15 r ∗ s = q ∪ (r0 × null(S \ X)) ∪ ( null(R \ X) × s0 ). Beispiel 3.20 Wir wollen eine Liste aller Restaurants und der von ihnen angebotenen Speisen erstellen. Bei dem Versuch, dieses mittels Gleichverbund zu bewerkstelligen, müssen wir erkennen, dass jene Restaurants, für die keine Speisen in der Relation Speise vorkommen, nicht in unserem Ergebnis sind, wie Beispiel 3.14 zeigt. Verwenden wir allerdings den äußeren Verbund, so werden auch Restaurants ohne Speisen in das Ergebnis aufgenommen und die entsprechenden Stellen mit Nullwerten aufgefüllt. Wie gehabt müssen wir das Attribut name in der Relation Speise umbenennen, damit es nicht als Joinattribut verwendet wird. Restaurant ∗ Speise = rnr 1 1 1 1 2 .. . 6 6 7 8 9 name Gußhaus Gußhaus Gußhaus Gußhaus A Tavola .. . adresse Gußhau... Gußhau... Gußhau... Gußhau... Weihbu... .. . Toko-Ri Toko-Ri Steirereck Carpaccio Indian Pavillion Franz-... Franz-... Rasumo... Panigl... Naschm... .. . typ öster... öster... öster... öster... toska... .. . name0 Gebratener Reh... Gefüllte Perlh... Zarte Rotbarb... Gemischte Käse... Gemischter Vors... .. . preis 21 26 25 10 10 .. . 4 1 0 japan... japan... inter... itali... indisch Großes Sushi Gemischte Mak... null null null 15 21 null null null haube 1 1 1 1 Achtung: Der äußere Verbund ist im Gegensatz zum Verbund nicht assoziativ! Beispiel 3.21 (q ∗ r) ∗ s 6= q ∗ (r ∗ s) q (q ∗ r) ∗ s = B C 2 3 (A 1 1 r B C) 2 3 null 4 A 1 B 2 s A C 1 4 q ∗ (r ∗ s) = (A B C) 1 2 4 null 2 3 3.4 Übersetzung des ER ins Relationenmodell Um in praktischen Belangen mit einem Datenmodell zu arbeiten, ist es sinnvoll, mit der Modellierung eines ER zu beginnen. In einem zweiten Schritt müssen wir das ER in das Relationenmodell einbetten. Dies ist immer möglich. Eine genaue Beschreibung dieser Einbettung 3.16 KAPITEL 3. DAS RELATIONENMODELL wird in dem Artikel [Teorey et al. 1986] gegeben1 . Wir geben hier nur eine kurze Einführung, die das Lesen des Artikels nicht ersetzt. Entities und Beziehungen haben keine direkte Entsprechung im Relationenmodell. Alle Sachverhalte werden einheitlich durch Relationen (Beziehungen zwischen Attributen) dargestellt. Bei einer 1:1-Beziehung zwischen zwei Entities wird die Beziehung aufgelöst, indem der Schlüssel der einen Entity in die Relation aufgenommen wird, die der anderen Entity entspricht. Welche Richtung hier verwendet wird, bleibt dem Designer überlassen. Wenn allerdings eine optionale Beziehung besteht, wird der Schlüssel auf der optionalen Seite gespeichert. Im Falle einer 1:n-Beziehung zwischen zwei Entities schreiben wir den Schlüssel der Entity auf der Einser“-Seite in die Relation, die der Entity auf der n“-Seite entspricht – ” ” deswegen ist in unserem laufenden Beispiel das Schlüsselattribut der Entity Restaurant in die Relation Speise gelangt. Bei einer n:m-Beziehung zwischen zwei Entities hingegen führen wir eine neue Relation ein, die die Schlüssel der beiden Entities als Attribute besitzt. Bei Weak Entities, bei denen die eigenen Attribute nicht ausreichen, um ein Tupel eindeutig zu identifizieren, müssen die Schlüsselattribute der damit verbundenen Entities zum Schlüssel dazugenommen werden – deswegen ist das Attribut rnr in der Relation Speise Teil des Schlüssels. 3.5 NF2-Relationen Eine Erweiterung des relationalen Modells bilden die NF2 -Relationen. NF2 sind Non First Normal Form Relations (Relational Model with Relation-Valued Attributes), Relationen, die nicht in erster Normalform sind. Der Begriff Normalform wird in Kapitel 7 definiert. NF 2 Relationen erlauben eine komplexere Kombination der bis jetzt kennengelernten Konzepte: Attributwerte selbst können wieder Relationen sein. Damit können wir komplexe Objekte und hierarchische Strukturen leichter darstellen (z.B.: CAD, Büroumgebung, . . . ). Ein Beispiel dazu finden wir in der Abbildung 3.2 []Schek, Pistor 1982]. 3.6 Weitere Sprachen f ür das Relationenmodell Die relationale Algebra ist eine Abfragesprache für das Relationenmodell. Neben dieser gibt es noch eine Reihe weiterer Abfragesprachen bzw. DML-Sprachen, von denen wir einige kurz vorstellen wollen. Der wichtigsten, nämlich SQL, wird das gesamte nächste Kapitel gewidmet. In Kapitel 5 beschreiben wir eine weitere Spreche, nämlich Datalog. 1 Diese Arbeit wird als Anhang zum Skriptum der Laborübung verteilt. Sie kann aber auch im Sekretariat der Abteilung kopiert werden. KAPITEL 3. DAS RELATIONENMODELL 3.17 ABTEILUNG BÜROANGEST ANR BNR 1 2 TECH-ANGEST ANAME Forschung Entwicklung 21 22 30 40 69 19 25 35 B-ARBEIT Bibliothek Übersetzer Sekretär Patente Sekretär Sekretär Übersetzer Hilfskraft TNR T-ARBEIT KURSE KNR JAHR 51 Programmierer 1 2 5 75 76 79 52 Grundlagenforschung 1 2 82 79 78 Planung 2 4 75 77 50 Entwurf 4 2 75 81 80 Wartung 3 77 Planung 1 2 82 83 81 Abbildung 3.2: NF2 -Relationen nach Schek Die Abrfragesprachen für das Relationenmodell können einerseits nach ihrer Beschreibungsart, andererseits nach der Art der Resultate in jeweils zwei Klassen eingeteilt werden. Nach der Beschreibungsart gibt es folgende zwei Klassen: Prozedurale Sprachen: Diese sind operational: sie stellen eine Beschreibung des Prozesses dar, der die Antwortmenge erzeugt. Die Abarbeitungsreihenfolge ist vorgegeben. Beispiele dafür sind die DML für das Netzwerkmodell, die DML für das Hierarchische Modell und die relationale Algebra, die wir zu Beginn dieses Kapitels vorgestellt haben. Nichtprozedurale Sprachen: Diese sind deskriptiv (oder deklarativ): sie geben eine Beschreibung der Bedingung, die erfüllt sein muss, damit ein Datenelement zur Antwortmenge gehört. Beispiele dafür sind der Relationenkalkül, Datalog und SQL. Teilen wir die Sprachtypen nach Art der verwendeten Datenstrukturen ein, so erhalten wir folgende Klassen: Datensatzorientierte Sprachen: Die Operationen arbeiten auf einzelnen Tupeln bzw. Datensätzen. Werden mehrere Tupel oder Datensätze verarbeitet, so müssen sie explizit sequentiell abgearbeitet werden. Beispiele dafür sind die DML für das Netzwerkmodell und die DML für das Hierarchische Modell. Mengenorientierte Sprachen: Die Operationen arbeiten auf Mengen von Tupeln. Alle relationalen Abfragespachen gehören dieser Klasse an (SQL, QUEL, Datalog, ...). Um mit datensatzorientierten Sprachen auf diesen Mengen arbeiten zu können, gibt es das Cursor-Konzept, das eine Umsetzung in datensatzorientierte Darstellung bietet (4.2.2). KAPITEL 3. DAS RELATIONENMODELL 3.18 3.6.1 Der Relationenkalkül Der Relationenkalkül beruht auf der Prädikatenlogik 1. Stufe (wo nur über Individuenvariable quantifiziert wird, im Gegensatz zur Prädikatenlogik 2. Stufe, wo auch über Prädikate quantifiziert wird). Der Wertebereich der Variablen kann einerseits ein Tupel sein, wenn wir vom Relationenkalkül mit Tupelvariablen (tupel relational calculus) sprechen, andererseits Attributwerte, wenn wir vom Relationenkalkül mit Bereichsvariablen (domain relational calculus) sprechen. 3.6.1.1 Der Relationenkalkül mit Tupelvariablen Die Ausdrücke des Relationenkalküls mit Tupelvariablen haben die Form {x(R)|f (x)}, wobei x eine Tupelvariable darstellt, R eine Menge von Attributen und f eine Funktion über der Tupelvariable nach {wahr, falsch} ist. Die Ergebnisrelation r(R) besteht aus allen Tupeln x(R), für die der Ausdruck f (x) wahr ist. Beispiel 3.22 Gehen wir wieder von den beiden Relationen Restaurant und Speise aus Abbildung 3.1 aus. Wenn wir alle Restaurants (Name und Adresse) mit mehr als einer Haube suchen, so sieht die Abfrage wie folgt aus: {x(name, adresse) | x ∈ Restaurant ∧ x(haube) > 1} Beispiel 3.23 Wie heißen die Speisen, die im Restaurant Drei Husaren“ angeboten werden, ” und was kosten sie? {x(name, preis) | x ∈ Speise ∧ ∃ y ∈ Restaurant : x(rnr) = y(rnr) ∧ y(name) = 0 Drei Husaren0 } 3.6.1.2 QBE — Query By Example QBE wurde um 1977 am IBM Watson Research Center entwickelt und basiert auf dem Relationenkalkül mit Bereichsvariablen. Dem Benutzer werden Tabellengerüste aller relevanten Relationen gezeigt, die aus einer Kopfzeile mit den Attributen bestehen. Durch Eintragungen in die jeweiligen Attributspalten werden die gewünschten Bedingungen und Ausgabewerte angegeben. Bereichsvariable werden unterstrichen und müssen aus dem Wertebereich des betreffenden Attributes stammen. Nicht unterstrichene Zeichenketten stellen Konstante dar. Auszugebende Werte werden durch ein vorgestelltes P. gekennzeichnet. Alle in einer Zeile stehenden Eintragungen werden miteinander logisch UND-verknüpft, die einzelnen Zeilen werden miteinander logisch ODER verknüpft. KAPITEL 3. DAS RELATIONENMODELL 3.19 Beispiel 3.24 Um zu erfahren, welche Speisen es um 21 Euro gibt, brauchen wir ein Schema der Tabelle Speise. Dort tragen wir an der Stelle preis den gewünschten Preis, nämlich 21 ein. Da uns der Name der Speisen interessiert, schreiben wir ein P. in die Spalte name. Optional dazu können wir noch eine Variable angeben, die aus dem Wertebereich stammt, bei uns z.B. Pizza. Unten sehen wir das Eingabeschema mit dem dazugehörigen Ergebnis. Speise name P.Pizza preis rnr 21 Speise name Gebratener Rehrücken mit Serviettenknödel Gemischte Maki für 2 Personen Fü die Selektion können in QBE auch Vergleichsoperatoren herangezogen werden. Dabei werden Vergleichsoperatoren als Präfix von Konstanten oder Variablen verwendet. Beispiel 3.25 Wir wollen wieder die Namen aller Restaurants auswählen, die mehr als drei Haube haben. Restaurant rnr name P. adresse haube >3 typ Restaurant name Steirereck Verwenden wir mehrere Zeilen im Eingabeschema, so werden diese miteinander ODERverknüpft; eine UND-Verknüpfung zwischen Zeilen wird durch die Verwendung derselben Variablen erreicht. Beispiel 3.26 Welches sind die Nummern der Restaurants, die Speisen um 25 Euro und 26 Euro abbieten, oder die Speisen anbieten, die weniger als 7 Euro kosten. Speise name preis 25 26 <7 rnr P. 99 P. 99 P. 77 Speise rnr 1 3 4 Durch die Verwendung derselben Variablen werden auch Beziehungen zwischen Tupel in verschiedenen Relationen ausgedrückt. Wir benötigen in diesem Fall mehrere Relationenschemata und müssen, falls notwendig, auch ein Ergebnisschema mit einem neuen Namen vorgeben. Beispiel 3.27 Sind wir daran interessiert zu sehen, welche Speisen in welchem Restaurant angeboten werden, so müssen wir neben den beiden Relationenschemata für die Abfrage auch ein Ergebnisschema Speise in Restaurant anlegen: Speise name xx preis rnr 99 Restaurant Speise in Restaurant P. name xx rnr name 99 yy name yy adresse zz adresse zz haube typ KAPITEL 3. DAS RELATIONENMODELL 3.20 Damit alle Tupel ausgegeben werden, die diesem Schema angehören, schreiben wir das P. in die Spalte unter den Schemanamen. Eine äquivalente Lösung ist, das P. zu den Variablen xx, yy und zz zu schreiben. Zuletzt können in einer condition box“ Beziehungen zwischen Bereichsvariablen spezi” fiziert werden. Beispiel 3.28 Wir wollen alle Restaurants ausgeben, die entweder mehr als eine Haube haben, oder österreichisch sind, wobei Doppelnennungen nicht vorkommen sollen. Restaurant rnr name P. xx P. yy adresse haube >1 typ österreichisch CONDITION xx 6= yy KAPITEL 3. DAS RELATIONENMODELL 3.21 3.7 Übungsbeispiele Übung 3.1 Gegeben sind folgende Relationen: kh bez beschäftigt arzt (KH#, KH NAME, KH ADRESSE, ANZ BETTEN) (KH#, BEZIRK) (KH#, ARZT#) (ARZT#, NAME, GEHALT, SG) Anmerkung: • SG . . . Spezialgebiet • KH . . . Krankenhaus 1. Formulieren Sie in relationaler Algebra: In welchen Bezirken gibt es Ärzte, die mehr als 20.000,- Euro verdienen? 2. Formulieren Sie in relationaler Algebra: In welchen Bezirken gibt es Krankenhäuser mit mehr als 500 Betten und keinem Herzspezialisten? Übung 3.2 Gegeben sind folgende Relationen: fliegt (Pilot Richter Richter Richter Truman Truman Pires Pires Pires Pires Novak wohnt (Pilot Novak Richter Pires Maschine) 707 727 747 707 727 707 727 747 1011 727 Ort) Wien Frankfurt Lissabon q s (Maschine) 707 landet (Maschine 727 727 707 Geben Sie die Relationen folgender Abfragen (relationale Algebra) an: 1. fliegt ÷q sowie fliegt ÷s (÷ bedeutet Division) (Maschine) 707 727 747 Ort) Wien Frankfurt Frankfurt KAPITEL 3. DAS RELATIONENMODELL 3.22 2. πP ilot (fliegt) - πP ilot ( (πP ilot (fliegt) × q) − fliegt) 3. fliegt ./ wohnt ./ landet. Übung 3.3 Gegeben sind die folgenden Relationen: ölfeld(FELDNAME,QUELLENNAME) (∗ Quellen liegen in Feldern ∗) ölmulti(FIRMENNAME,UMSATZ,HL) (∗ HL steht für Herkunftsland ∗) besitzt(FIRMENNAME,QUELLENNAME) (∗ Quelle gehört Firma ∗) Formulieren Sie in Relationer Algebra: Gesucht sind Quellennamen, Firmennamen und Umsatz aller Ölmultis, die in jedem Ölfeld mindestens eine Quelle besitzen. Übung 3.4 Gegeben sind folgende Relationen: univers (UNINAME, STADT) angebot (UNINAME, STR, SEIT) Anmerkung: STR . . . Studienrichtung SEIT . . . Jahr der Einführung der Studienrichtung Formulieren Sie in Relationenalgebra: In welchen Städten wurden 1979 Studienrichtungen neu eingeführt? Formulieren Sie in Relationenalgebra: In welchen Städten kann man Informatik nicht studieren? Übung 3.5 Gegeben sind folgende Relationen zur Informationsspeicherung von Wasserleitungen zwischen Bassins (= Wasserbehältern): Bassin(NR, BEZ, VOL) Rohr(VON, ZU, DURCHFLUSS). Bassins haben ein bestimmtes Fassungsvermögen (VOL), eine Bezeichnung (BEZ) und werden durch ihre Nummer (NR) identifiziert. Rohre führen von (VON) einem Bassin zu (ZU) einem Bassin und sind dadurch eindeutig bestimmt. Bassins, zu denen keine Rohre hinführen (bzw. wegführen), sind Quellen (bzw. Senken). Jedes Rohr besitzt eine bestimmte Durchflusskapazität (DURCHFLUSS). Formulieren Sie eine Abfrage in relationaler Algebra, die alle Rohre (von, zu) liefert, die von einer Quelle wegführen. Formulieren Sie eine Abfrage in relationaler Algebra, die die Bezeichnung aller Bassins liefert, zu denen Rohre hinführen, deren Durchfluss > 100 ist. KAPITEL 3. DAS RELATIONENMODELL 3.23 Übung 3.6 Eine Sportler-Agentur hält in einer Datenbank Informationen über SportlerInnen, die unter Vertrag stehen (mitglied), sowie Informationen über relevante LeichtathletikVeranstaltungen (veranstaltung) fest. Für statistische Zwecke sowie für künftige Vertragsverhandlungen wird zusätzlich festgehalten welche Mitglieder an welchen Veranstaltungen teilgenommen und welchen Rang sie dabei belegt haben (nimmt teil). Die Höhe der Preisgelder, die bei den verschiedenen Veranstaltungen ausbezahlt werden, wird ebenfalls festgehalten (preisgeld). mitglied(MNAME, ALTER) veranstaltung(VBEZ, VJAHR, ORT) nimmt teil(MNAME, VBEZ, VJAHR, DISZIPLIN, RANG). preisgeld(VBEZ, RANG, BETRAG). Formulieren Sie in relationaler Algebra: In welchen Orten haben alle SportlerInnen, die bei unserer Sportleragentur unter Vertrag stehen, zugleich an einer Veranstaltung teilgenommen? Übung 3.7 Die Relation teilStueck(von-km,nach-km,steigung, zustand) beschreibt Autobahnteilstücke, wobei zustand die Werte 3 (schadhaft), 2 (unbeschädigt) oder 1 (neu) annehmen kann. steigung wird in % angegeben und ist < 0 für abfallende Teilstücke, sonst > 0. Die Relation bruecke(von-km,bauart) kennzeichnet alle jene Teilstücke, die Brücken sind. Ein Brückenteilstück hat immer die Steigung 0. Es kann davon ausgegangen werden, dass zwei oder mehrere Brücken nicht unmittelbar hintereinander auftreten. Formulieren Sie in relationaler Algebra: Welche Brücken (von-km) sind Teil eines Gefälles (vor und nach der Brücke steigung < 0)? Übung 3.8 Über Tennisspieler (SPNR) wird vermerkt, für welches Team (TNR) sie in welchen Tennismatches (MNr) gespielt haben. Jedes Team spielt in einer bestimmten Division (DIVISION) und wird von einem Spieler, dem Kapitän, angeführt. Die Spieler können für beliebige Teams Matches bestreiten. Zu einem Match werden pro Spieler die gewonnenen (G SETS) und die verlorenen Sätze (V SETS) angegeben. Lösen Sie anhand folgender vorgegebener Relationen die nachstehenden Aufgabe: spieler(SPNR NAME ATP-RANG) team(TNR SPNR DIVISION) match(MNR SPNR TNR G SETS V SETS) Gesucht sind die Namen jener Spieler, welche bereits für alle Teams gespielt haben. Übung 3.9 Gegeben sei die folgende relationale Datenbank über den Einsatz von Flugzeugen im internationalen Luftverkehr. 3.24 KAPITEL 3. DAS RELATIONENMODELL flughafen(name,stadt,land) modell(typ nr,#platz,spannweite,hersteller) maschine(f nr,fluglinie,wartung,ankauf,typ nr) flug(f nr,fluglinie,wtag,von,nach) In flughafen wird der Name des Flughafens, die Stadt, zu der er gehört, sowie das Land, in dem er liegt, gespeichert. In modell wird zu jedem Flugzeugtyp (z.B. DC10) angegeben, wieviele Sitzplätze, welche Spannweite, und von welchem Hersteller der Flieger gebaut wurde. In maschine wird zu jedem Flugzeug, das eine Fluggesellschaft kauft, angegeben in welchem Jahr die Maschine das letzte mal gewartet wurde, wann sie angekauft wurde und von welchem Typ sie ist. In flug wird zu jedem Flugzeug gespeichert, an welchem Wochentag der Flug von Flughafen von nach Flughafen nach fliegt. Schreiben Sie eine Abfrage in relationaler Algebra, die alle Länder ausgibt, in denen keine Maschine landet, die mehr als 250 Passagiere aufnehmen kann. Übung 3.10 Gegeben sei die folgende relationale Datenbank der Tiergartenverwaltung Schönbrunn. käfig(k nr,fläche,typ) weg(k nr1,k nr2,dist) tierart(art,gattung,platz,futter) tier(name,art,k nr,geb dat,erwerb) In der Relation käfig wird zu jedem Käfig eine eindeutige Nummer, seine Gesamtfläche (fläche), sowie seine Beschaffenheit (typ: Terrarium, Aquarium, Gehege etc.) gespeichert. Achtung: es müssen nicht notwendigerweise alle Käfige belegt sein. In Relation weg wird der Weg zwischen 2 angrenzenden Käfigen gespeichert, zusammen mit der Entfernung. Die Relation ist symmetrisch, d.h., sowohl Tupel weg(A,B,N), als auch weg(B,A,N) sind gespeichert. Die Relation tierart beschreibt die Arten, die im Zoo gehalten werden durch Gattung, Platzbedarf und Futterart z.B. (panther,raubkatze,15m2,fleisch), die Relation tier hingegen beschreibt die einzelnen, im Zoo vorhandenen Exemplare durch ihren Namen name, der Art art, der sie angehören, den Käfig k nr, in dem sie sich aufhalten, und dem Geburts- und Erwerbsdatum (geb dat, erwerb). Wurde das Tier im Zoo geboren, so sind beide Daten gleich. Schreiben Sie eine Abfrage in relationaler Algebra, die jene Tierarten angibt, von denen alle vorhanden Exemplare nach dem 1.1.1996 geboren worden sind. Übung 3.11 Eine Firma für Tiefkühlprodukte speichert die folgenden Daten zur Herstellung der Speisen in einer relationalen Datenbank: speise(sname,haltbar,vpreis) zutat(zname,preis) rezept(sname,zname,#einheit) KAPITEL 3. DAS RELATIONENMODELL 3.25 In der Relation speise werden der Name (sname), die Haltbarkeitsdauer (haltbar) und der Verkaufspreis (vpreis) des jeweiligen Tiefkühlprodukts gespeichert. Die Relation zutat enthält die Information, wieviel (preis) eine bestimmte Zutat (zname) pro Einheit kostet. Die Relation rezept beschreibt, wieviel Einheiten (#einheit) von einer bestimmten Zutat in einer Speise verwendet werden. Schreiben Sie eine Abfrage in relationaler Algebra, die Name und Kategorie der Speisen angibt, in denen alle Zutaten, die mehr als 20 Euro pro Einheit kosten, verwendet werden. Übung 3.12 In einer relationalen Datenbank der FIS werden die Resultate der vergangenen Schiweltcupsaison gespeichert: sfahr(sname, rennen(rname, gefahren(sname, punkte(platz, geb dat, geschlecht, land) typ, länge, land, geschlecht) rname, typ, dg, zeit, platz) punkte) Ein/e FahrerIn wird identifiziert mit dem Namen, beschrieben durch Geburtsdatum, Geschlecht und Herkunftsland. Ein Rennen identifiziert sich durch den Namen und Typ (z.B. Wengen, Slalom), und wird beschrieben durch die Länge der Strecke, dem Land und für welches Geschlecht das Rennen ausgetragen wurde. Die Tabelle gefahren speichert zu jedem Rennen und den darin angetretenen FahrerInnen die Zeit und die erreichte Plazierung. Für Rennen, die nur aus einem Durchgang bestehen, steht im Attribut dg der Wert ‘‘G’’, ansonsten ‘‘1’’, ‘‘2’’ und ‘‘S’’ für die Gesamtwertung. Im Falle eines Ausscheidens steht in platz NULL. Die Relation Punkte speichert die Anzahl der Punkte, die für eine bestimmte Plazierung vergeben werden. Schreiben Sie eine Abfrage in relationaler Algebra, die Name, Geburtsdatum und Nationalität jener FahrerInnen ausgibt, die in dieser Saison an allen Rennen (ihres Geschlechts) teilgenommen haben. Übung 3.13 In einer relationalen Datenbank der Wiener Fremdenverkehrsverwaltung werden die Buchungen der Wiener Hotels gespeichert. hotel(hname, hadresse, kategorie, betten) zimmer(hname, znr, betten, preis ) belegt(hname, znr, anreise, abreise) Ein Hotel wird identifiziert durch den Namen und beschrieben durch die Adresse, die Kategorie und die Anzahl der vorhandenen Betten. Ein Zimmer identifiziert sich durch den Namen des Hotels und die entsprechende Zimmernummer, und wird beschrieben durch die Anzahl seiner Betten und den Preis pro Nacht und Person für dieses Zimmer. Die Relation belegt speichert zu jedem Zimmer die An- und Abreisetermine der Gäste. Schreiben Sie eine Abfrage in relationaler Algebra, die Name, Adresse und Kategorie aller Hotels angibt, die vom 19. - 26. Juni 1999 noch mindestens ein freies Doppelzimmer haben. 3.26 KAPITEL 3. DAS RELATIONENMODELL Übung 3.14 In einer relationalen Datenbank eines Bankinstituts werden unter anderem Informationen über Kundinnen und deren Sparbücher gespeichert: kunde(Knr, name, geb dat, beruf, adresse) sparbuch(Spnr, Knr, gebunden, von, bis) buchung(Spnr, Bnr, datum, betrag) Eine Kundin wird identifiziert durch eine Kundennummer (Knr) und beschrieben durch Name, Geburtsdatum, Beruf und ihre Adresse. Ein Sparbuch wird identifiziert durch die Sparbuchnummer (Sbnr), weiters wird die dazugehörige Kundin, die Dauer der Bindung in Monaten, und das Datum der Sparbucheröffnung (von) und der Schließung (bis) gespeichert. Ist ein Sparbuch noch offen, so ist der Wert von bis NULL. Eine Buchung ist pro Sparbuch durchnumeriert (Bnr), weiters werden noch das Datum und der Betrag (positiv oder negativ) gespeichert. Schreiben Sie eine Abfrage in relationaler Algebra, die Name und Adresse aller Kundinnen angibt, die mehr als drei laufende Sparbücher haben, aber nur eines, das länger als ein Jahr gebunden ist. Kapitel 4 SQL Die relationale Abfragesprache SQL wurde 1974 für das experimentelle Datenbankmanagementsystem System R von IBM entwickelt – SQL wurde damals SEQUEL (Structured English QUEry Language) genannt – und 1986 von ANSI (American National Standards Institute) und 1987 von ISO (International Standard Organisation) als internationaler Standard einer Sprachschnittstelle für relationale Datenbankmanagementsysteme genormt. Nach einer ersten Überarbeitung im Jahr 1989, wo die Sprache erweitert wurde, um referenzielle Integrität und generelle Integritätsbedingungen zu verarbeiten, wurden 1992 in der zweiten Überarbeitung die Datenmanipulation, Schemamanipulation und Datendefinitionssprache erweitert. Diese zweite Version des Standards war in den letzten Jahren die Referenz und wird als SQL-2 oder SQL-92 bezeichnet. SQL-2 ist relational vollständig, d.h., alles, was im Relationenkalkül ausdrückbar ist, kann auch in SQL ausgedrückt werden. Ab 1992 wurde an einer dritten, großen Überarbeitung des Standards gearbeitet, um objekt-orientierte Konzepte, persistente Objekte, Multimedia-Datentypen und temporale Datentypen und Sprachkonzepte zu inkorporieren und SQL zu einer Turing-vollständigen Sprache (alle berechenbaren Abfragen sind möglich) zu erweitern. Die in diesem Kapitel vorgestellten Sprachkonzepte von SQL orientieren sich am SQL-3 Standard, der zu Beginn des Jahres 2000 veröffentlicht wurde. Wir beginnen in diesem Kapitel mit der Beschreibung der Datendefinitionssprache (Data Definition Language – DDL) und der Datenmanipulationssprache (Data Manipulation Language – DML) und kennzeichnen reine SQL-3 Konstrukte als solche. SQL kann interaktiv verwendet werden oder in eine Wirtsprache (host language), wie C oder C++, eingebettet werden (embedded SQL). In diesem Kapitel wird zuerst interaktives SQL vorgestellt, in Abschnitt 4.2 kurz auf die wichtigsten Konzepte von eingebettetem SQL eingegangen. Einen Überblick über den SQL-3 Standard geben wir in Abschnitt 4.3 dieses Kapitels. Die Präsentation von SQL beschränkt sich auf die wichtigsten Konzepte und erfolgt an Hand von Beispielen, die es ermöglichen sollen, mit Hilfe des SQL-Manuals eines relationalen Datenbankmanagementsystems die Sprache im Detail zu erlernen. Lehrbücher zu SQL, [Date et al. 1994] und [Melton et al. 1994], umfassen mehrere hundert Seiten, wobei in diesen Büchern noch der SQL-2 Standard beschrieben wird, mit einem Ausblick auf den 1 KAPITEL 4. SQL 4.2 bei ihrem Erscheinen noch nicht beendeten SQL-3 Standard. Der SQL-3 Standard wird in [Fortier 1999] beschrieben, wobei der Autor dieses Buches Chairman des SQL-3 Standards Committee war und jahrelang an der Entwicklung des Standards aktiv teilnahm. 4.1 Interaktives SQL 4.1.1 Allgemeines Mit SQL können Relationen und Views (virtuelle Relationen) definiert, abgefragt und manipuliert werden. In SQL werden Relationen als Tabellen (tables), Attribute als Spalten (columns) und Tupel als Zeilen (rows) bezeichnet. Die SQL DDL stellt Befehle zum Erzeugen und Entfernen von Relationen sowie für die Änderung des Schemas einer Relation zur Verfügung. Die SQL DML stellt Befehle zum Abfragen, Einfügen, Ändern und Löschen von Tupeln in Relationen zur Verfügung. Wir besprechen zunächst einige ausgewählte Datentypen von SQL, dann SQL-Abfragen aus der Datenmanipulationssprache, die Datendefinitionssprache und zuletzt die restlichen Befehle der Datenmanipulationssprache. 4.1.2 Datentypen SQL unterstützt unter anderem die folgenden Datentypen: • CHAR(n) Zeichenkette der Länge n. • CHAR VARYING(n) oder VARCHAR(n) Zeichenkette variabler Länge, die kleiner oder gleich n ist. Die maximale Länge von n ist implementierungsabhängig, meist 255. Wollen wir einen String der Länge 5 in eine Spalte schreiben, die einmal mit CHAR(10), ein zweites mal mit VARCHAR(10) definiert wurde, so wird dieser String im ersten Fall mit 5 Leerzeichen aufgefüllt, im zweiten Fall nicht. • BIT(n) bzw. BIT VARYING(n) Bitstrings der fixen bzw. variablen Länge n. • INTEGER und SMALLINT Integerzahlen, wobei im zweiten Fall vom System eine Optimierung durchgeführt und weniger Platz reserviert werden kann. Die genaue Größe der Zahl ist implementierungsabhängig. • NUMERIC(p, s) Fixkommazahl, wobei mit p die Gesamtanzahl der Stellen, mit s die Anzahl der Nachkommastellen angegeben werden kann. Die Darstellung von Fixkommazahlen sieht wie folgt aus: 2.345, 3999.1 oder 87.52436. • REAL und DOUBLE PRECISION Gleitkommazahlen, wobei die Anzahl der Stellen implementierungsabhängig ist, im zweiten Fall aber üblicherweise größer als im ersten. Die Darstellung von Gleitkommazahlen sieht wie folgt aus: 0.2345E0, 0.39991E-4, 0.8752436E2. KAPITEL 4. SQL 4.3 • DATE, TIME(p) und TIMESTAMP DATE ist zehnstellig, 4 Stellen für Jahreszahlen (00019999), zwei für Monats- und zwei für die Tagesangabe. TIME(p) speichert Uhrzeiten. Es stellt zwei Stellen für die Stunde (00-23) und zwei für die Minuten (00-59) zur Verfügung. Für die Sekunden steht der Bereich 00-61.999... 1 zur Verfügung; die Anzahl der Nachkommastellen können wir im Parameter p festlegen, die maximale Größe von p ist implementierungsabhängig, der Defaultwert 0. TIMESTAMP ist eine Kombination aus DATE und TIME, der Defaultwert für die Nachkommastellen der Sekunden ist 6. Auf Zeichenketten, Zahlen und Datumsangaben sind u.a. die Vergleichsoperatoren =, <, >, =<, >=, <> bzw. != mit der üblichen Bedeutung definiert. Bei Zeichenketten gibt es auch den Vergleichsoperator LIKE, der einen Mustervergleich durchführt. Auf Zahlen können die arithmetischen Operatoren +, −, ∗, / mit der üblichen Semantik angewandt werden, auch Klammerungen mittels (“ und )“ sind möglich. ” ” Aus den vorgestellten Datentypen können mit dem Befehl CREATE DOMAIN domainName ” AS Typ“ neue Datentypen definiert werden. Beispiel 4.1 Wir wollen für alle Geldbeträge wie Preise, Gehälter oder Rechnungssummen Beträge mit zwei Nachkommastellen, für Speisen und Restaurants Namen mit maximal 50 Zeichen zulassen; für Namen von Personen erlauben wir maximal 20 Zeichen. CREATE DOMAIN euro AS NUMBER(10,2); CREATE DOMAIN lang_name AS VARCHAR(50); CREATE DOMAIN name AS VARCHAR(20); SQL-3 erweitert SQL-2 um einige Datentypen. • BOOLEAN nimmt die Werte TRUE oder FALSE an. Diese können mit logischen Operatoren verknüpft werden. • LARGE BINARY OBJECT (BLOB) und analog dazu LARGE CHARACTER OBJECT (CLOB) sind große Objekte, die entweder nur aus Binärzeichen oder aus characters bestehen. Für diese gibt es spezielle Zugriffsstrukturen, die eine effiziente Verarbeitung ermöglichen. Auf BLOBs und CLOBs können die Vergleichsoperatoren =, ! = und LIKE angewandt werden, der <-Operator nicht. Sie können nicht als Primärschlüssel verwendet werden und nicht in einer GROUP BY oder ORDER BY Klausel auftreten. • ROW ( Zeile“) ist vom Konzept her völlig neu, da wir hiermit komplexe Attribute dar” stellen können: ROW(attributeDefinitionList)“. ” • Abstrakte Datentypen sind ein weiteres völlig neues Konzept in SQL-3 und stellen eine Verbindung zwischen dem relationalen und dem objektorientierten Datenmodell dar. Wir werden am Ende dieses Abschnittes genauer auf abstrakte Datentypen eingehen. 1 Dass der Bereich der Sekunden nicht nur bis 59 geht, liegt an den Schaltsekunden. KAPITEL 4. SQL 4.4 • Sub- und Supertabellen ermöglichen es, die Generalisierung nicht durch Auflösung in Relationen wie in [Teorey et al. 1986] beschrieben zu realisieren, sondern explizit Subtabellen anzulegen. Subtabellen erben alle Attribute der Supertabellen. Jeder Eintrag einer Subtabelle hat genau einen entsprechenden Eintrag in der Supertabelle, zu jedem Eintrag in einer Supertabelle gibt es maximal einen entsprechenden Eintrag in der Subtabelle. Subtabellen werden mit dem Befehl CREATE TABLE relationName UNDER ” relationName“ angelegt. Beispiel 4.2 Bei den Kreditkartendaten eines Kunden wollen wir auch die Unterschrift des Kunden speichern. Diese legen wir in einem BLOB ab. Die Adresse der Kunden ist ein typisches Beispiel für einen ROW-Typ. CREATE TABLE kunde (vorname nachname sig .... adresse name, name, BLOB, ROW (strasse ort plz land VARCHAR(30), VARCHAR(30), INTEGER, VARCHAR(30))); Wir können entweder bei der Tabellendefinition direkt den Typ ROW verwenden oder eine neue Domain definieren, da wir Adressen vermutlich auch in anderen Tabellen benötigen werden. CREATE DOMAIN adresse AS ROW (strasse ort plz land VARCHAR(30), VARCHAR(30), INTEGER, VARCHAR(30)); Die Modellierung der Kunden und der Mitarbeiter aus Beispiel 2.6 wird mittels Generalisierung dargestellt. CREATE TABLE kunden UNDER person; CREATE TABLE mitarbeiter UNDER person; 4.1.3 Abfragen In diesem Abschnitt besprechen wir zunächst das Prinzip von SQL-Abfragen. Anschließend behandeln wir die Gruppenbildung von Tupeln und Aggregatfunktionen, danach betrachten wir die Möglichkeit, komplexere Abfragen durch Schachtelung von Abfragen zu bilden. Schließlich besprechen wir Mengenoperationen und Nullwerte. KAPITEL 4. SQL 4.5 4.1.3.1 Grundkonstruktion einer SQL-Abfrage Die Grundkonstruktion einer SQL-Abfrage ist von der Form SELECT attributeList FROM relations WHERE condition“ . ” Eine solche SQL-Abfrage wird ausgewertet, indem zunächst das kartesische Produkt der in der FROM-Klausel angegebenen Relationen gebildet wird. Daraus werden dann jene Tupel ausgewählt, die die in der WHERE-Klausel angegeben Bedingungen erfüllen. Zuletzt wird auf die in der SELECT-Klausel angegebenen Attribute dieser Tupel projiziert. Die Bedingung in der SELECT-Klausel kann sich aus mehreren, durch die logischen Operatoren AND, OR und NOT verbundenen Teilbedingungen zusammensetzen. Als Teilbedingungen sind Vergleiche zwischen Attributwerten bzw. zwischen Attributwerten und Konstanten mittels der auf den betreffenden Datentyp anwendbaren Vergleichsoperatoren zugelassen, bzw. durch AND, OR und NOT verbundene Teilbedingungen. Weitere Arten von Teilbedingungen lernen wir später kennen. In SQL werden Duplikate, d.h. Ergebnistupel mit identischen Werten, nicht automatisch eliminiert. Um Duplikate zu eliminieren, muss der Liste von ausgewählten Attributen das Schlüsselwort DISTINCT vorangestellt werden. Durch die Angabe einer ORDER BY-Klausel mit den Schlüsselworten ASC oder DESC kann die Ausgabe aufsteigend bzw. absteigend nach bestimmten Attributen sortiert werden; der Defaultwert ist ASC. Die folgenden Beispiele, anhand derer wir Syntax und Semantik von SQL beschreiben, verwenden wieder die in Beispiel 3.1 beschriebenen Relationenschemata und die in Abbildung 3.1 dargestellten Relationen: Restaurant = {rnr, name, adresse, haube, typ} Speise = {name, preis, rnr} Weiters verwenden wir zur Beschreibung der Operationen, soweit möglich, dieselben Abfragen wie in der Relationalen Algebra. Die Selektion Die Selektion wird durch die Angabe der Bedingungen in der condition realisiert. Bei den Bedingungen können beliebige Vergleichsoperatoren (die für den Datentyp definiert sind) verwendet werden. Beispiel 4.3 Wir selektieren alle jene Restaurants, die zwei Hauben haben. SELECT rnr, name, adresse, haube, typ FROM restaurant WHERE haube = 2; Wir selektieren alle jene Restaurants, die mehr als eine Haube, aber keine österreichische oder internationale Küche haben. 4.6 KAPITEL 4. SQL SELECT rnr, name, adresse, haube, typ FROM restaurant WHERE haube > 1 AND NOT (typ = österreichisch OR typ = international); Die Projektion Die Projektion wird durch Angabe der gewünschten Attribute in der attributeList realisiert. Beispiel 4.4 Wir projizieren die Relation Restaurant nach den Attributen name, adresse und haube. SELECT name, adresse, haube FROM restaurant; Wenn kein Attribut wegprojiziert werden soll, so können wir anstelle der Aufzählung aller Attribute des Schemas *“ als Platzhalter verwenden. ” Der Verbund Um mehrere Relationen im Verbund zu verknüpfen, schreiben wir die Namen der Relationen in die FROM-Klausel. Dadurch wird das kartesische Produkt zwischen den Relationen gebildet. Wenn wir einen Gleichverbund oder Theta-Verbund durchführen wollen, so erreichen wir dies durch Selektion der gewünschten Tupel aus dem Kartesischen Produkt. Gibt es in den Relationen Attribute mit derselben Bezeichnung, so müssen wir bei diesen Attributen auch den Namen der Relation angeben, aus der sie genommen werden. Beispiel 4.5 Wir wollen wissen, welche Speisen in welchem Restaurant angeboten werden. SELECT restaurant.*, speise.* FROM restaurant, speise WHERE restaurant.rnr = speise.rnr; Werden in einer Abfrage zwei Kopien derselben Relation benötigt oder sollen Relationen durch kürzere Namen angesprochen werden, so können in der FROM-Klausel Aliasbezeichner vergeben werden. In der SELECT-Klausel können auch Ausdrücke, die aus Attributen berechnet werden, stehen. Durch das Schlüsselwort AS kann einem so berechneten Ausdruck ein Attributname zugewiesen werden. Beispiel 4.6 Wir wollen alle Paare von Restaurants auswählen, die sich um mehr als zwei Hauben unterscheiden und die Differenz der Hauben ausgeben. Weiters sind wir nur an den Namen der Restaurants interessiert. SELECT r1.name, r2.name, (r2.haube - r1.haube) AS differenz FROM restaurant r1, restaurant r2 WHERE r1.haube + 2 < r2.haube; KAPITEL 4. SQL 4.7 Die Division Es gibt keinen, der Division direkt entsprechenden Operator in SQL. Allerdings kann die Division mit Hilfe der Negation und von Teilabfragen dargestellt werden. 4.1.3.2 Mengenoperationen SQL stellt die Mengenoperationen UNION (Mengenvereinigung), UNION ALL (Multimengenvereinigung, d.h. gleiche Tupel werden nicht eliminiert), INTERSECT (Durchschnitt) und EXCEPT (Mengendifferenz) für typkompatible Relationen (d.h. Relationen mit der gleichen Anzahl von jeweils typkompatiblen Attributen) zur Verfügung. Beispiel 4.7 Wir wollen eine Liste der Namen aller Restaurants und der Namen aller Speisen. (SELECT name FROM restaurant) UNION (SELECT name FROM speise) Mit typkompatiblen Relationen“ sind dabei natürlich nicht die Relationen Restaurant ” oder Speise gemeint, sondern die Ergebnisse der beiden SELECT Statements. 4.1.3.3 Gruppierung und Aggregatfunktionen Der bereits bekannte SELECT − FROM − WHERE“-Block kann um eine Klausel GROUP BY at” ” tributeList“ und eine Klausel HAVING condition“ ergänzt werden, um Gruppen von Tupeln ” zu bilden und auf diese Gruppen Aggregatfunktionen anzuwenden. Eine solche Abfrage wird ausgewertet, indem zunächst wie gehabt aus dem kartesischen Produkt der in der FROMKlausel angegebenen Relationen jene Tupel selektiert werden, die die WHERE-Klausel erfüllen. Danach werden diese Tupel nach gemeinsamen Werten in den in der GROUP BY-Klausel angeführten Attributen gruppiert. Von diesen Gruppen werden jene eliminiert, die die in der HAVING-Klausel angegebene Bedingung nicht erfüllen. Anschließend werden etwaige in der SELECT-Klausel angegebenen Aggregatfunktionen wie AVG, SUM, MAX, MIN und COUNT auf jede der verbliebenen Gruppen angewendet. Diese Aggregatfunktionen (außer COUNT) können auch auf arithmetische Ausdrücke über Attributen angewandt werden. COUNT wird über Booleschen Ausdrücken ausgewertet und zählt jene Tupel, die den jeweiligen Booleschen Ausdruck erfüllen. Der Ausdruck COUNT(∗) zählt alle Tupel. In der SELECT-Klausel und in der HAVING-Klausel dürfen jene Attribute, nach denen gruppiert wurde, nur ohne Aggregatfunktion verwendet werden – nach jenen Attributen, die in der SELECT-Klausel ohne Aggregatfunktionen selektiert werden, muss gruppiert werden. (Zum besseren Verständnis dieser Konstrukte überlegen Sie sich, warum dies so ist.) Beispiel 4.8 Schreiben wir eine SQL-Abfrage, die den Namen und die Anzahl der Hauben jener Restaurants angibt, deren teuerste Speise mehr als 22 Euro kostet. Weiters werden jeweils die Anzahl der Speisen als auch deren Durchschnittspreis ausgegeben. 4.8 KAPITEL 4. SQL SELECT r.rnr, r.haube, count(*), avg(s.preis) FROM restaurant r, speise s WHERE r.rnr=s.rnr GROUP BY r.rnr, r.haube HAVING MAX(s.preis) > 22; Fehlen die GROUP BY und HAVING-Klauseln, so müssen in der SELECT-Klausel entweder auf alle Attribute oder auf kein einziges Attribut Aggregatfunktionen angewendet werden. Werden Aggregatfunktionen angewandt, so wird die Gesamtheit der in der WHERE-Klausel ausgewählten Tupel als einzige Gruppe betrachtet. 4.1.3.4 Teilabfragen Innerhalb der WHERE-Klausel kann an jeder Stelle, an der ein Wert erwartet wird, dieser auch durch eine SQL-Abfrage berechnet werden. Wird in der Teilabfrage auf keine Relation der Hauptabfrage Bezug genommen, so handelt es sich um eine einfache Teilabfrage. Diese wird nur einmal ausgewertet, das Ergebnis dieser Auswertung wird dann in der Hauptabfrage verwendet. Wird in der Teilabfrage auf eine Relation der Hauptabfrage Bezug genommen, so nennen wir das eine korrelierte Teilabfrage. In diesem Fall wird die Teilabfrage für jedes Tupel der Hauptabfrage neu ausgewertet. Weiters können mit einem Vergleichsoperator auch gleich lange Listen positionsweise verglichen werden. Ein solcher Ausdruck liefert wahr, wenn der Vergleich für jede Position der Liste wahr liefert. Beispiel 4.9 Wir wollen alle jene Restaurants selektieren, die gleichviele Hauben haben, wie das Restaurant Drei Husaren. Die Anzahl der Hauben der Drei Husaren bekommen wir aus einer einfachen Teilabfrage. Die Ausgabe soll nach den Namen der Restaurants sortiert sein. SELECT * FROM restaurant WHERE haube = (SELECT haube FROM restaurant WHERE name = ’Drei Husaren’) ORDER BY name; Beispiel 4.10 Wir sind nun an jenen Restaurants interessiert, deren Durchschnittspreise für Speisen höher sind als jener aller Preise der anderen Restaurants mit derselben Anzahl an Hauben. SELECT r.* FROM restaurant r, speise s WHERE r.rnr = s.rnr KAPITEL 4. SQL 4.9 GROUP BY r.rnr, r.name, r.adresse, r.haube, r.typ HAVING AVG(s.preis) > (SELECT AVG(s1.preis) FROM restaurant r1, speise s1 WHERE r1.rnr = s1.rnr AND r1.rnr <> r.rnr AND r1.haube = r.haube); Wichtige spezielle Formen von Teilbedingungen in der WHERE-Klausel sind: • EXISTS query“ liefert wahr, genau dann wenn die Abfrage query mindestens ein Tupel ” selektiert. • expressionList comparisonOp ANY query“ liefert wahr, wenn der Vergleich der Aus” drucksliste expressionList mit irgendeinem von der Abfrage query erzeugten Tupel wahr liefert. • expressionList comparisonOp ALL query“ liefert wahr, wenn der Vergleich der Aus” drucksliste expressionList mit allen von der Abfrage query erzeugten Tupel wahr liefert. • expressionList IN query“ liefert wahr, wenn der Vergleich der Ausdrucksliste expres” sionList mit einem Tupel der Abfrage query identisch ist. • expressionList NOT IN query“ liefert wahr, wenn der Vergleich der Ausdrucksliste ex” pressionList mit keinem Tupel der Abfrage query identisch ist. An Stelle der Ausdrucksliste kann auch ein einzelner Ausdruck stehen. Die Abfrage darf dann auch nur ein Attribut selektieren. Beispiel 4.11 In diesem Beispiel wollen wir zeigen, wie die Division in SQL dargestellt werden kann. Wir wollen wie in Beispiel 3.16 herausfinden, welche Restaurants Speisen zu einer bestimmten Menge von Preisen, die in der Relation Preisliste gespeichert sind, anbieten. SELECT r.* FROM restaurant r WHERE NOT EXISTS (SELECT p.preis FROM preisliste p WHERE p.preis NOT IN (SELECT s.preis FROM speise s WHERE s.rnr=r.rnr)); KAPITEL 4. SQL 4.10 4.1.4 Nullwerte SQL unterstützt den Nullwert NULL. Jeder numerische Vergleich mit einem Nullwert liefert falsch und jede arithmetische Operation, auf einen Nullwert angewandt, liefert NULL. Boolesche Vergleiche mit Nullwerten werden entsprechend der im Abschnitt 3.3 vorgestellten 3-wertigen Logik behandelt. Die speziellen Prädikate IS NULL und IS NOT NULL können verwendet werden, um zu prüfen, ob ein Attribut einen Nullwert enthält bzw. nicht enthält. Für die nachfolgenden Beispiele benötigen wir eine weitere Relation, nämlich die der Mitarbeiter in R EINE. Mitarbeiter haben einen Namen, eine Sozialversicherungsnummer und ein Gehalt. Weiters gibt es für manche Mitarbeiter eine Provision und wir müssen die Beziehung zu dem Restaurant herstellen, in dem jeder Mitarbeiter arbeitet. Da ein Mitarbeiter nur in einem Restaurant angestellt sein kann, handelt es sich um eine 1:n-Beziehung, die wir durch Hinzunahme des Primärschlüssels der Restaurants auflösen. Leere Felder kennzeichnen die Nullwerte. Mitarbeiter = {vname, nname, svnr, gehalt, prov, rnr} Die Relation, die wir für die Beispiele verwenden, ist folgende: Mitarbeiter vname nname Gerti Müller Anton Eder Max Muster Edith Huber Rita Muster Ilse Hofer Rudi Maier Theo Novak Karin Meinl svnr gehalt prov rnr 2435020466 2.000 100 1 8450270768 1.900 50 1 5467151171 1.300 2 9876020170 1.500 2 8350120571 1.800 2 2463300668 1.700 90 3 8533211065 2.100 3 1234240863 2.000 3 8347090964 2.500 120 3 Beispiel 4.12 Wieviele Personen bekommen neben dem Gehalt noch eine Provision? SELECT COUNT(prov) FROM mitarbeiter; COUNT(PROV) ----------4 Enthält eine Spalte einen Nullwert, wird sie nicht mitgezählt. KAPITEL 4. SQL 4.11 Beispiel 4.13 Wieviel verdient jeder Mitarbeiter an Gehalt, Provision und insgesamt? SELECT vname, nname, gehalt, prov, gehalt + prov AS sum FROM mitarbeiter; VNAME -----Gerti Anton Max Edith Rita Ilse Rudi Theo Karin NNAME ------Müller Eder Muster Huber Muster Hofer Maier Novak Meinl GEHALT ------2000 1900 1300 1500 1800 1700 2100 2000 2500 PROV SUM ----- -----100 2100 50 1950 90 1790 120 2620 Bei arithmetischen Operationen ist das Ergebnis ein Nullwert, wenn ein Operand ein Nullwert ist. Als nächstes folgen einige Beispiele, die zeigen, wie SQL mit Nullwerten in Mengenoperationen verfährt. Beispiel 4.14 Wir wollen wissen, welche Mitarbeiter 50 Euro oder 120 Euro Provision bekommen, sowie über welche Mitarbeiter keine Information vorhanden ist. SELECT vname, nname, prov FROM mitarbeiter WHERE prov IN (50, 120, NULL); VNAME -----Anton Karin NNAME PROV ------ ----Eder 50 Meinl 120 Dies ist nicht das gewünschte Ergebnis, denn es gibt Mitarbeiter, von denen nicht bekannt ist, ob sie eine Provision bekommen oder nicht: SELECT vname, nname, prov FROM mitarbeiter WHERE prov IS NULL; KAPITEL 4. SQL 4.12 VNAME -----Max Edith Rita Rudi Theo ENAME PROV ------- ---Muster Huber Muster Maier Novak Die Tupel, die einen Nullwert als Provision haben, kommen bei der ersten Abfrage nicht im Ergebnis vor, da vom System ein numerischer Vergleich zwischen Nullwerten durchgeführt wird und dieser immer einen Nullwert ergibt. Um das gewünschte Ergebnis zu erhalten müssen wir daher folgende Abfrage schreiben: SELECT vname, nname, prov FROM mitarbeiter WHERE prov IN (50, 120) OR prov IS NULL; Beispiel 4.15 Nun wollen wir eine Liste aller Mitarbeiter, deren Provision weder 50 Euro noch 120 Euro beträgt, und deren Provision kein Nullwert ist. SELECT vname, nname, prov FROM mitarbeiter WHERE prov NOT IN (50, 120, NULL); no rows selected Hier werden keine Tupel als Ergebnis selektiert, da für jeden Wert der Provision ein numerischer Vergleich auch mit dem Nullwert durchgeführt wird, was in jedem Fall einen Nullwert ergibt. SELECT vname, nname, prov FROM mitarbeiter WHERE prov IS NOT NULL; VNAME -----Gerti Anton Ilse Karin NNAME PROV ------- ----Müller 100 Eder 50 Hofer 90 Meinl 120 KAPITEL 4. SQL 4.13 Da es aber Mitarbeiter gibt, von denen wir die Provision kennen, müssen wir die korrekte Abfrage wie folgt formulieren: SELECT vname, nname, prov FROM mitarbeiter WHERE prov NOT IN (50, 120) AND prov IS NOT NULL; VNAME -----Gerti Ilse NNAME PROV ------- ----Müller 100 Hofer 90 Beispiel 4.16 Wir wollen nun von jedem Restaurant wissen, wieviel Gehalt und Provision die Mitarbeiter zusammen bekommen und wieviele Mitarbeiter es gibt. SELECT rnr, COUNT (gehalt+prov), SUM(gehalt+prov) FROM mitarbeiter GROUP BY rnr; RNR COUNT(GEHALT+PROV) SUM(GEHALT+PROV) -------- ------------------ ---------------1 2 4050 2 0 3 2 4410 Dass diese Abfrage nicht das gewünschte Ergebnis liefert, ist offensichtlich. 4.1.4.1 Der Outer Join in SQL SQL unterstützt den Outer-Join, den wir im Abschnitt 3.3.2 vorgestellt haben. In SQL haben wir beim Outer Join die Möglichkeit anzugeben, welche der beiden Seiten beim Joinen mit Nullwerten aufgefüllt werden soll. Ein Outer-Join zwischen zwei Relationen wird im FROM-Teil einer SQL-Abfrage durch die Klausel relname1 [FULL|LEFT|RIGHT] OUTER JOIN ” relname2 ON joinCondition“ ausgedrückt. Wir rufen uns die Definition des Outer Join in Abschnitt 3.3.2 in Erinnerung: r ∗ s = q ∪ (r0 × null(S \ X)) ∪ ( null(R \ X) × s0 ). Der Ausdruck (r 0 × null(S \ X)) füllt die Attribute von s an den unbekannten Stellen mit null, der Ausdruck ( null(R \ X) × s0 ) die Attribute von r. In diesem Sinn war die Definition symmetrisch. Die Befehle LEFT OUTER JOIN und RIGHT OUTER JOIN geben in SQL die Möglichkeit, diese Symmetrie aufzubrechen. 4.14 KAPITEL 4. SQL Beispiel 4.17 Schreiben wir eine SQL-Abfrage, die Name und Adresse aller Restaurants liefert, für die die Anzahl der Hauben nicht bekannt ist, sowie die Namen gegebenenfalls angebotener Speisen. SELECT r.name, r.adresse, s.name FROM restaurant r LEFT OUTER JOIN speisen s ON r.rnr=s.rnr WHERE r.haube IS NULL; 4.1.5 Datendefinition In diesem Abschnitt stellen wir die SQL-Befehle zum Erzeugen von Relationen, zur Festlegung von globalen Integritätsbedingungen, zum Ändern von Relationen und zum Entfernen von Relationen vor. 4.1.5.1 Erzeugen von Relationenschemata Mit dem Befehl CREATE TABLE relationName ...“ wird ein Relationenschema definiert und ei” ne leere Relation mit dem Namen relationName zu diesem Schema erzeugt. Zu jedem Attribut wird ein Typ angegeben; optional können eine oder mehrere Integritätsbedingungen angegeben werden. Mögliche Integritätsbedingungen sind u.a. die Angabe, dass das Attribut einen Primärschlüssel darstellt (PRIMARY KEY); dass das Attribut keinen Nullwert annehmen darf (NOT NULL) — diese Bedingung gilt automatisch für Primärschlüsselattribute —; dass ein Attribut eindeutig sein muss (UNIQUE) — diese Bedingung gilt automatisch für Primärschlüsselattribute —; oder eine durch die Klausel CHECK (condition)“ formulierte Wertebereichsein” schränkung. Weiters kann für Attribute durch die Klausel DEFAULT value“ ein Defaultwert ” angegeben werden. Beispiel 4.18 Der folgende SQL-Befehl erzeugt ein Relationenschema mit den Attributen für Restaurants aus Beispiel 3.1 und dazu eine leere Relation mit dem Namen Restaurant. Er legt weiters fest, dass das Attribut rnr ein Primärschlüssel ist, dass die Attribute name und adresse keinen Nullwert annehmen dürfen, und dass haube nur die Werte 0 − 4 annehmen darf. Für den Typ eines Restaurants ist als Defaultwert österreichisch festgelegt. CREATE TABLE restaurant (rnr INTEGER PRIMARY KEY, name name NOT NULL, adresse adresse NOT NULL, haube INT CHECK (haube IN (0, 1, 2, 3, 4)), typ VARCHAR(15) DEFAULT ’österreichisch’); Neben Integritätsbedingungen zu Attributen können auch Integritätsbedingungen zur Relation durch CONSTRAINT-Klauseln angegeben werden, wobei für jede Integritätsbedingung ein innerhalb der Relation eindeutiger Name vergeben wird. KAPITEL 4. SQL 4.15 Eine spezielle Integritätsbedingung (zu Attributen oder zu Relationen) ist die mittels einer REFERENCES-Klausel angegebene Fremdschlüsselbedingung FOREIGN KEY, die eine Inklusionsabhängigkeit, wie sie im Abschnitt 6.4 definiert wird, repräsentiert. Zu jeder Fremdschlüsselbedingung kann durch eine ON UPDATE action“ und eine ON DELETE action“ -Klausel ” ” angegeben werden, wie auf Verletzungen durch Änderung oder Löschen des referenzierten Schlüsselwertes reagiert werden soll. Mögliche Aktionen sind, die Änderung bzw. das Löschen zu verhindern (NO ACTION), die Änderung oder das Löschen zu propagieren (CASCADE) bzw. den Wert des referenzierenden Attributes auf einen Nullwert (SET NULL) oder den Defaultwert des Attributs (SET DEFAULT) zu setzen. Beispiel 4.19 Der nächste SQL-Befehl erzeugt ein Relationenschema mit den Attributen für die Speisen aus Beispiel 3.1 und dazu eine leere Relation mit dem Namen Speise. Die angeführten Integritätsbedingungen legen u.a. fest, dass die Attribute rnr und name gemeinsam den Primärschlüssel der Relation Speise bilden und dass das Attribut rnr der Relation Speise ein Fremdschlüssel ist, der sich auf das Schlüsselattribut rnr der Relation Restaurant bezieht (Speise[rnr] ⊆ Restaurant[rnr]). Die Angabe ON UPDATE CASCADE legt fest, dass eine Änderung der Nummer eines Restaurants bei den entsprechenden Speisen mitgezogen wird, und die Angabe ON DELETE NO ACTION legt fest, dass ein Restaurant nicht gelöscht werden darf, solange noch Speisen für dieses Restaurant vorhanden sind. CREATE TABLE speise (rnr INTEGER, name name, preis euro, CONSTRAINT speise_pk PRIMARY KEY (rnr, name) CONSTRAINT rnr_fk FOREIGN KEY (rnr) REFERENCES restaurant (rnr) ON UPDATE CASCADE ON DELETE NO ACTION CONSTRAINT preis_check CHECK (preis > 0)); 4.1.5.2 Globale Integritätsbedingungen Neben den bei Attributen und Relationen lokal angegebenen Integritätsbedingungen können auch relationenübergreifende globale Integritätsbedingungen mit dem SQL-Befehl CREATE ASSERTION festgelegt werden. Dabei wird ein Name für die Integritätsbedingung und eine boolesche Bedingung angegeben, die in jedem Datenbankzustand erfüllt sein muss. Durch die Angabe des Zusatzes DEFERRABLE kann angegeben werden, dass die Überprüfung der Integritätsbedingung mit dem Befehl SET CONSTRAINT constraintName DEFERRABLE“ bis ” unmittelbar vor das Ende einer Transaktion verschoben werden kann. Durch den Befehl SET CONSTRAINT constraintName IMMEDIATE“ kann wieder auf eine andauernde Überprüfung ” dieser Integritätsbedingung zurückgeschaltet werden. KAPITEL 4. SQL 4.16 Beispiel 4.20 Der nächste SQL-Befehl definiert die globale Integritätsbedingung, dass ein Restaurant nur dann Speisen um mehr als 50 Euro anbieten kann, wenn es mehr als eine Haube hat. Die Integritätsbedingung definieren wir als IMMEDIATE, da sie beim Einfügen neuer Speisen immer gleich überprüft werden soll. CREATE ASSERTION max_preis (1 < ALL (SELECT haube FROM restaurant r, speise s WHERE r.rnr = s.rnr AND s.preis > 50)) IMMEDIATE; 4.1.5.3 Ändern von Relationenschemata Mit dem SQL-Befehl ALTER TABLE relationName ADD attribute“ kann ein Attribut zu einer ” Relation hinzugefügt und durch den SQL-Befehl ALTER TABLE relationName DROP attribute“ ” kann ein Attribut entfernt werden. Beispiel 4.21 Mit folgendem SQL-Befehl fügen wir das Attribut kalorien zur Relation Speise hinzu. ALTER TABLE speise ADD (kalorien INTEGER); 4.1.5.4 Entfernen von Relationenschemata Mit dem SQL-Befehl DROP TABLE relationName“ wird eine Relation aus der Datenbank ent” fernt. 4.1.6 Datenmanipulation In diesem Abschnitt stellen wir die SQL-Befehle zum Einfügen von Tupeln in Relationen, zum Ändern von Attributwerten von Tupeln, und zum Löschen von Tupeln aus Relationen vor. 4.1.6.1 Einfügen von Daten Mit dem SQL-Befehl INSERT INTO relationName (attribute 1, . . . , attribute n) VALUES (va” lue 1, . . . , value n)“ kann ein neues Tupel in eine Relation eingefügt werden. Beispiel 4.22 Mit dem nächsten SQL-Befehl fügen wir ein neues Tupel, das Restaurant Wok“ ” in die Relation Restaurant ein. KAPITEL 4. SQL 4.17 INSERT INTO restaurant (rnr, name, adresse.strasse, adresse.ort, adresse.plz, adresse.land, haube, typ) VALUES (10, ’Wok’ , ’Operngasse’, ’Wien’, 1040, ’Österreich’, 0, ’asiatisch’) Die Syntax zum Einfügen von Werten in Attribute vom Typ ROW ist erst Teil des SQL-3 Standard. Sollen die Ergebnistupel einer beliebigen Abfrage in eine Relation eingefügt werden, so kann dafür der SQL-Befehl INSERT INTO relationName (attribute 1, . . . , attribute n) query“ ” verwendet werden. Beispiel 4.23 Der folgende SQL-Befehl fügt alle österreichischen Restaurants aus der Relation Restaurant in die Relation Inland ein. Die Relation Inland muss bereits existieren. INSERT INTO inland (rnr, name, adresse) SELECT rnr, name, adresse FROM restaurant WHERE typ = ’österreichisch’; 4.1.6.2 Löschen von Daten Der SQL-Befehl DELETE FROM relationName“ löscht alle Tupel aus der Relation relationNa” me und der SQL-Befehl DELETE FROM relationName WHERE condition“ löscht alle Tupel aus ” der Relation relationName, die die angegebene Bedingung condition erfüllen. Beispiel 4.24 Schreiben wir einen SQL-Befehl, der alle Restaurants löscht, zu denen es keine Speise in der Relation Speise gibt: DELETE FROM restaurant WHERE rnr NOT IN (SELECT rnr FROM speise); 4.1.6.3 Ändern von Daten Mit dem SQL-Befehl UPDATE relationName SET attribute = expression WHERE condition“ ” wird für alle Tupel aus der Relation relationName, die die Bedingung condition erfüllen, der Wert des Attributes attribute auf den Wert des Ausdrucks expression gesetzt. Beispiel 4.25 Mit dem nächsten SQL-Befehl erhöhen wir den Preis aller Speisen der Restaurants mit 4 Hauben um 10%. UPDATE speise SET preis = preis*1.1 WHERE rnr IN (SELECT rnr FROM restaurant WHERE haube = 4); 4.18 KAPITEL 4. SQL 4.1.7 Benutzersichten Das Konzept der logischen Datenunabhängigkeit (vergleiche Kapitel 1) wird in SQL durch die Möglichkeit der Definition von Views (Sichtrelationen) unterstützt. Views dienen zum Aufbau von Benutzersichten und sind auf Grund einer Abfrage über Basisrelationen und zuvor definierter Views definiert. Während die Tupel von Basisrelationen gespeichert sind, sind die Tupel von Views virtuell, und werden auf Grund der bei der Definition der View angegebenen Abfrage berechnet. Eine View wird in SQL mit Hilfe des Befehls CREATE VIEW ” relationName (attribute 1, . . . , attribute n) AS query-expression“ definiert. Änderungen über Views, die durch eine Verknüpfung aus mehreren Relationen definiert sind, können nicht immer eindeutig auf Änderungen in den zugrunde liegenden Relationen zurückgeführt werden. Deswegen sind in SQL nur Änderungen über Views, die auf einer Basisrelation oder einer veränderbaren View definiert sind, erlaubt. Weiters darf das Schlüsselwort DISTINCT nicht vorkommen und in der WHERE-Klausel dürfen keine Teilabfragen stehen, die sich in ihrer FROM-Klausel auf dieselbe Tabelle wie die Hauptabfrage beziehen. Es darf keine GROUP BY- oder HAVING-Klausel verwendet werden. Ebenso können errechnete Attributwerte nicht direkt geändert werden. Die Änderung eines Tupels einer View kann dazu führen, dass dieses Tupel nach der Änderung nicht mehr zur View gehören würde. Solche Änderungen können bei der Definition der View durch die Angabe der Klausel WITH CHECK OPTION“ verhindert werden. ” Beispiel 4.26 Mit dem folgenden SQL-Befehl definieren wir eine View Spitze, die die Nummer, den Namen und die Adresse jener Restaurants enthält, die mehr als 2 Hauben haben. CREATE VIEW spitze (rnr, name, adresse, haube) AS SELECT rnr, name, adresse, haube FROM restaurant WHERE haube > 2 WITH CHECK OPTION; Wollen wir in der View Spitze die Anzahl der Hauben verändern, so geht das nur, wenn die Bedingung haube > 2 weiterhin erfüllt ist. Eine View, deren Ausprägung vom augenblicklichen Datenbankbenutzer abhängt, kann durch die Verwendung der SQL-Funktion USER definiert werden. Beispiel 4.27 Die unten definierte View persönlich enthält für jeden Mitarbeiter seine Personaldaten (unter der Annahme, dass Nachname und Username ident sind): CREATE VIEW persönlich AS SELECT * FROM mitarbeiter m WHERE m.nname = USER; Views können mit dem SQL-Befehl DROP VIEW relationName“ entfernt werden. ” KAPITEL 4. SQL 4.19 4.1.8 Zugriffskontrolle In SQL hat der Besitzer einer Basisrelation oder View alle Rechte über diese Relation. Er kann diese Rechte auch anderen Benutzern gewähren und gewährte Rechte wieder zurücknehmen. Ein Benutzer besitzt eine Relation, wenn er diese erzeugt hat. Mit dem Befehl GRANT privilege ON relationName TO authID“ wird in SQL das Recht ” privilege über die Relation relationName dem Benutzer authID gewährt. Zu den in SQL unterstützten Rechten gehören das Lesen von Tupeln bzw. von ausgewählten Attributwerten (SELECT bzw. SELECT(attribute 1, . . . attribute n)), das Einfügen (INSERT) und Löschen (DELETE) von Tupeln, das Ändern von Tupeln bzw. von ausgewählten Attributwerten (UPDATE bzw. UPDATE(attribute)), sowie das Recht, auf Attributen einen Fremdschlüssel zu definieren (REFERENCES (attribute 1, . . . , attribute n)). Die Angabe ALL PRIVILEGES umfasst alle diese Rechte. Werden Rechte mit der Angabe der Klausel WITH GRANT OPTION“ gewährt, so ” dürfen diese vom Empfänger weitergegeben werden, sonst nicht. Beispiel 4.28 Mit dem nächsten SQL-Befehl gewähren wir der Benutzerin Huber alle Rechte über die View Spitze. Sie darf diese Rechte auch weitergeben. GRANT ALL PRIVILEGES ON spitze TO Huber WITH GRANT OPTION; Durch die Angabe des speziellen Autorisierungsidentifikators PUBLIC können Rechte an alle Benutzer, inklusive aller zukünftigen Benutzer, gewährt werden. Beispiel 4.29 Nun erlauben wir jedem Benutzer, seine Personaldaten zu lesen. GRANT SELECT ON persönlich TO PUBLIC; Gewährte Rechte können mit dem SQL-Befehl REVOKE privilege ON relationName FROM ” authID“ entzogen werden. Wurden inzwischen Rechte weitergegeben, so wird jener Zustand hergestellt, der gelten würde, wenn das entzogene Recht nie gewährt worden wäre. Beispiel 4.30 Wollen wir der Benutzerin Huber das Recht entziehen, Nummer und Name der Restaurants von Spitze zu ändern, so sieht das folgendermaßen aus: REVOKE UPDATE(rnr, name) ON spitze FROM Huber; 4.20 KAPITEL 4. SQL 4.1.9 Transaktionsverwaltung Die meisten SQL-Befehle können nur im Rahmen einer Transaktion (siehe Kapitel 10) verwendet werden. Ist in einer interaktiven SQL-Sitzung keine Transaktion aktiv und wird ein SQL-Befehl, der nur innerhalb einer Transaktion ausgeführt werden kann wie INSERT, UPDATE, SELECT, CREATE TABLE an das Datenbankmanagementsystem übergeben, wird automatisch eine Transaktion gestartet. Die Transaktion kann mit dem SQL-Befehl COMMIT erfolgreich abgeschlossen bzw. mit dem SQL-Befehl ROLLBACK abgebrochen werden. In Abschnitt 10.4 gehen wir genauer auf die Behandlung von Transaktionen in SQL ein, da wir die notwendigen Voraussetzungen momentan noch nicht haben. 4.1.10 Definition von Dateiorganisationsformen und Zugriffspfaden SQL-Befehle zur Festlegung von Dateiorganisationsformen für Relationen und von Zugriffspfaden waren Bestandteil der Norm von SQL-89. Sie wurden jedoch aus dem genormten Sprachumfang von SQL-92 gestrichen. Verschiedene relationale Datenbankmanagementsysteme unterstützen zur Zeit unterschiedliche Primär- und Sekundärorganisationsformen für Dateien (vergl. Kapitel 8) und damit verbunden die SQL-Befehle CREATE INDEX/CLUSTER, ALTER INDEX/CLUSTER und DROP INDEX/CLUSTER in unterschiedlichen Varianten. 4.1.11 Abstrakte Datentypen Abstrakte Datentypen (ADTs) stellen die wichtigste konzeptionelle Änderung von SQL-2 auf SQL-3 dar. ADTs unterstützen die Konzepte Objektidentität, Vererbung und Polymorphismus, die aus der objektorientierten Welt kommen. Der Grund für die Erweiterung des relationalen Modells um objektorientierte Konzepte zum Objekt-Relationalen Modell liegt im Aufkommen und Zusammenspiel von objektorientierten Programmiersprachen und objektorientierten Datenbanken. Dieses Zusammenspiel ermöglicht es, Daten der Anwendungen leicht in einem persistenten und sicheren Medium – der Datenbank – abzulegen und dort herauszuholen. Daher begannen die verschiedenen DBMS-Anbieter Unterstützung zur Speicherung und Bearbeitung von nicht-standard Daten zu bieten. Das SQL-3 Komitee schlug daher den Weg ein, die zugrundeliegende Struktur von Tabellen zu erweitern. Eine Tabelle kann nun nicht nur mehr aus einfachen (atomaren) Attributen zusammengesetzt sein, sondern Attribute können selbst zusammengesetzt sein, z.B. als Datentyp ROW oder eben als ADT. Die Spezifikation eines ADT besteht aus zwei Teilen: der Spezifikation der Attribute, aus denen sich der ADT zusammensetzt, und der Spezifikation der Funktionen, mit denen auf den ADT zugegriffen werden kann. Das Verhalten eines ADT ist in der Typdefinition gekapselt. Von außen sind nur die Definition der Attribute und die Schnittstelle der Funktionen sichtbar, nicht jedoch die Details der Implementierung. Für Attribute und Funktionen kann angegeben werden, ob sie public, private oder protected sind. Public bedeutet, dass sie allen Benutzern des ADTs zur Verfügung stehen; private, dass sie nur innerhalb des ADTs verwendet werden KAPITEL 4. SQL 4.21 können; protected, dass neben ADT-internem Code nur Subtypen darauf zugreifen können. ADTs können entweder Wert-ADTs oder Objekt-ADTs sein. Wert-ADTs haben keine Objektidentität, sondern nur Werte für die entsprechenden Instanzen. Objekt-ADTs haben eine Objektidentität (OID), die für jede Instanz des ADTs eindeutig ist. Mit dem Befehl CREATE TYPE typeName (attributeList)“ kann ein ADT definiert werden. ” Mit den Schlüsselwörtern PUBLIC, PRIVATE oder PROTECTED vor Attributen und Funktionen können wir angeben, wie diese zur Verfügung stehen. Attribute können gespeichert oder virtuell sein. Virtuelle Attribute haben keinen bestimmten Wert, sondern eine Funktion muss angeben, wie der Wert des Attributs berechnet werden kann. Zu jedem ADT wird ein Konstruktor und ein Destruktor angelegt. Diese können vom Benutzer überschrieben werden. Für jedes Attribut werden zwei Funktionen angelegt, eine Observer- und eine Mutator-Funktion, mit denen die Werte der Attribute ausgelesen bzw. verändert werden können. Beispiel 4.31 Wir wollen anstelle einer Relation Mitarbeiter einen ADT mitarbeiter anlegen. Die Attribute nname, vname und adresse sollen allgemein zur Verfügung stehen. Die Adresse kann entweder wie zu Beginn des Kapitels beschrieben aus einem ROW Typ bestehen, oder sie kann selbst ein ADT sein. Das Attribut geburt steht nur innerhalb des ADT zur Verfügung. Das Attribut alter ist ein virtuelles Attribut. Die zugehörige Funktion alter stellen wir allgemein zur Verfügung. CREATE TYPE mitarbeiter ( PRIVATE mnr INTEGER, PUBLIC nname name, PUBLIC vname name, PUBLIC adresse adresse, PUBLIC gehalt euro, PUBLIC prov euro, PRIVATE geburt DATE, PUBLIC alter INTEGER VIRTUAL); PUBLIC FUNCTION alter (m mitarbeiter) RETURNS INTEGER BEGIN DECLARE :a INTEGER; SET a = CAST(CURRENT_DATE - geburt(m)); RETURN a; END; Das System generiert für alle Attribute Observer- und Mutator-Funktionen. Die entsprechenden Funktionen für das Attribut name sehen wie folgt aus: FUNCTION nname (mitarbeiter) RETURNS name FUNCTION nname (mitarbeiter, name) RETURNS mitarbeiter 4.22 KAPITEL 4. SQL Wir wollen eine eigene Konstruktor-Funktion schreiben, da wir bestimmte Attribute wie mnr, nname und vname als Parameter übergeben und auch das Gehalt auf den Default-Wert 1.000 setzen wollen. CONSTRUCTOR FUNCTION mitarbeiter (r INTEGER, n name, v name) RETURNS mitarbeiter DECLARE :m mitarbeiter BEGIN NEW :m; SET :m.mnr = r; SET :m.nname = n; SET :m.vname = v; SET :m.adresse = NULL; SET :m.gehalt = 1000; SET :m.prov = NULL; SET :m.geburt = NULL; RETURN m; END; END FUNCTION DESTRUCTOR FUNCTION destr_mitarbeiter ( :m mitarbeiter) RETURNS mitarbeiter BEGIN DESTROY :m; RETURN :m; END; END FUNCTION 4.1.12 Rekursion in SQL-3 Relationale Algebra, Relationenkalkül, QBE und SQL-2 sind relational vollständig. Das heißt, alle Abfragen, die in Relationaler Algebra ausgedrückt werden können, sind auch in den anderen bisher besprochenen Sprachen formulierbar. Das bedeutet allerdings nicht, dass alle überhaupt möglichen Abfragen in diesen Sprachen formuliert werden können. Insbesondere können rekursive Abfragen in diesen Sprachen im Allgemeinen nicht formuliert werden. Diese Einschränkung ist durch die Einführung von Rekursion in SQL-3 aufgehoben worden. Wollten wir bis jetzt in einer Abfrage Probleme wie Finde alle Bestandteile eines bestimmten Teils“ (bill of material), Traveling Salesman“ ” ” oder generelle Graphalgorithmen abarbeiten, so müssen wir das sehr kompliziert durch das Erstellen von verschachtelten Cursor-Konstrukten machen und mithilfe der Einbettung in eine prozedurale Programmiersprache (siehe Abschnitt 4.2.2), eine Lösung mit nacktem“ SQL ” war prinzipiell unmöglich. KAPITEL 4. SQL 4.23 Lieferung von Wien Wien Wien Wien St. Pölten St. Pölten St. Pölten Klosterneuburg Tulln Wr. Neustadt bis lnr Wr. Neustadt 1 Klosterneuburg 1 St. Pölten 1 Linz 1 Krems 2 Melk 2 Linz 2 Tulln 3 Krems 3 Eisenstadt 4 kosten 3 2 6 10 7 6 8 2 3 5 Abbildung 4.1: Beispiel einer Relation für Lieferung Angenommen, wir haben eine Tabelle, die Lieferdaten speichert, den Lieferanten (lnr), der eine Strecke beliefert, und die Kosten für die Lieferstrecken (siehe Abbildung 4.1). Wenn wir wissen wollen, wieviel eine Lieferung in beliebig vielen Etappen von einem Ort zu einem anderen kostet, oder welche Orte wir von Wien aus beliefern können, so können wir mit SQL-2 keine allgemeine Abfrage formulieren, die für jede Instanz der Relation Lieferung das gewünschte Ergebnis liefert. Mit anderen Worten: wir können keine Relation Alle wege erzeugen, die alle Tupel < X, Y > enthält, für die es einen Weg von X nach Y gibt. Schrittweise betrachtet erfordert die Erzeugung der Wege für jede Zwischenstufe einen Join und eine Projektion, z.B.: CREATE VIEW einstop (start, ziel) SELECT l1.von, l2.bis FROM lieferung l1, lieferung l2 WHERE l1.bis = l2.von; CREATE VIEW zweistop (start, ziel) SELECT e.start, l.bis FROM einstop e, lieferung l WHERE e.ziel = l.von; Das Ergebnis der Gesamtabfrage besteht dann aus der Vereinigung aller Teilergebnisse: CREATE VIEW alle_wege (start, ziel) SELECT von, bis FROM lieferung UNION SELECT * FROM einstop KAPITEL 4. SQL 4.24 UNION SELECT * FROM zweistop UNION ..... Da wir aber nicht wissen, wieviele Zwischenstopps in der aktuellen Instanz vorkommen, können wir auch keinen allgemeinen Ausdruck finden, der Alle wege in Abhängigkeit von Lieferung berechnet. In SQL-3 wird eine rekursive Abfrage mit dem Befehl WITH RECURSIVE relationName AS ” (initialQuery UNION ALL recursiveQuery) query“ erzeugt. Um die Erzeugung von Duplikaten zu verhindern, können wir entweder das Schlüsselwort ALL weglassen oder in der Teilabfrage der recursiveQuery das Schlüsselwort DISTINCT verwenden. Im zweiten Fall werden die Duplikate schon bei der Berechnung der Zwischenresultate eliminiert. Wir können mit Hilfe einer SEARCH-Klausel und der Schlüsselworte DEPTH FIRST BY oder BREADTH FIRST BY attributeList SET ordnungAttribut die Abarbeitungsstrategie vorgeben. Das System verwaltet dabei eine Hilfsdatei, die das Attribut ordnungAttribut enthält und füllt. Dieses Attribut enthält einen numerischen Wert, der abhängig von der Abarbeitungsstrategie und den zu beobachtenden Attributen in attributeList die jeweilige Abarbeitungsschicht beschreibt. Dieser Wert wird dann zur Ausgabe in der richtigen Reihenfolge verwendet. Um Zyklen bei der Abarbeitung zu erkennen, gibt es die CYCLE-Klausel, die Zyklen erkennt und die dazugehörende Information in der angegebenen Hilfstabelle speichert. Mit dem Befehl CYCLE attributeList SET attribute TO cycleMarkValue DEFAULT non-cycleMarkValue USING relationName wird eine Relation relationName mit dem Attribut attribute angelegt, die den Defaultwert noncycleMarkValue enthält, der bei der Entdeckung eines Zyklus in der attributeList allerdings auf den Wert cycleMarkValue gesetzt wird. Die Rekursion bringt aber auch aufgrund der Verwendung der Negation das folgende Problem mit sich: wir können Negation in recursiveQuery nur auf Relationen anwenden, die zu diesem Zeitpunkt vollständig bekannt sind. Dieses Konzept nennen wir Stratifikation und es wird im Abschnitt 5.4 genau beschrieben. Warum ist diese Einschränkung notwendig? Wenn wir verlangen, dass ein Tupel t ein Lösungstupel einer Abfrage ist, wenn es nicht einer Relation R angehört, dann darf sich die Relation R nicht mehr verändern. Denn wenn noch neue Tupel zu R dazukommen, könnte es passieren, dass t plötzlich ein Element von R wird und daher nun nicht mehr als Lösungstupel für die Abfrage in Frage kommt. Auch alle auf der Negation aufbauenden Sprachkonstrukte wie INTERSECT und EXCEPT sind von diesem Problem betroffen. Gruppierung und Aggregatfunktionen haben eine ähnliche Auswirkung. Ein Tupel, das bei der rekursiven Verarbeitung als Lösungstupel erkannt wurde, kann wieder aus der Lösungsmenge fallen, wenn sich ein aggregierter Wert während der Rekursion verändert. Aus diesem Grund können auch Aggregatfunktionen nur auf Relationen angewandt werden, die bereits vollständig bekannt sind. Beispiel 4.32 Wir wollen nun anhand der Relation Lieferung herausfinden, welche Orte von Wien aus beliefert werden können und welche Kosten dabei anfallen. Duplikate sollen nicht KAPITEL 4. SQL 4.25 eliminiert werden. Die Suche soll als Breitensuche durchgeführt werden, also sollen zuerst alle Orte ausgegeben werden, die ohne Stop von Wien aus beliefert werden, im nächsten Schritt alle Orte, die mit einem Zwischenstop beliefert werden können usw. Die Information über die Suchtiefe wird im Attribut ordnung abgelegt, das dann zur Sortierung der Ausgabe verwendet wird. Informationen über allfällige Zyklen, die im Attribut bis auftreten, wollen wir in der Tabelle Zyklen mit dem Attribut zyklus ablegen. WITH RECURSIVE alle_wege (von, bis, kosten) AS (SELECT von, bis, kosten FROM lieferung UNION ALL SELECT a.von, l.bis, a.kosten + l.kosten FROM alle_wege a, lieferung l WHERE a.bis=l.von) SEARCH BREADTH FIRST BY von SET ordnung CYCLE bis SET zyklus TO ’1’ DEFAULT ’0’ USING zyklen SELECT * FROM alle_wege ORDER BY ordnung; 4.1.13 Trigger in SQL-3 Trigger, die im SQL-3 Standard definiert werden, erlauben es dem Datenbankmanagementsystem auf Änderungen, die auf den Daten durchgeführt werden, direkt zu reagieren und selbst Aktionen zu setzen. So können wir mit Hilfe von Triggern die Integrität der Datenbank besser sicherstellen. Trigger arbeiten nach dem Event-Condition-Action“-Modell. Das bedeutet, dass wir ” Trigger definieren können, die vor oder nach einem bestimmten Event (dem UPDATE, INSERT oder dem DELETE auf bestimmte Tabellen oder Spalten) abhängig von bestimmten Bedingungen eine bestimmte Aktion durchführen. Mit dem Befehl CREATE TRIGGER triggerName ” BEFORE/AFTER event ON table WHEN triggerCondition triggerAction“ wird ein Trigger angelegt. Mit der Klausel FOR EACH ROW bzw. FOR EACH STATEMENT legen wir die Granularität des Triggers fest. Er kann einmal für jede Änderung einer Zeile oder einmal für das gesamte SQLStatement ausgeführt werden. Mit der Klausel REFERENCING OLD alteDaten NEW neueDaten können wir auf die Werte einer Zeile oder einer ganzen Tabelle aller im Falle eines UPDATES geänderten Daten zugreifen. Diese Klausel ist aber nur zulässig, wenn die Triggergranularität FOR EACH ROW ist. Beispiel 4.33 Der folgende SQL Befehl erzeugt einen Trigger, der bei allen Mitarbeitern, die eine Gehaltserhöhung von mehr als 5% bekommen, die Provision auf 0 setzt. CREATE TRIGGER provision AFTER UPDATE OF gehalt ON mitarbeiter 4.26 KAPITEL 4. SQL REFERENCING OLD as gehalt_alt NEW as gehalt_neu FOR EACH ROW WHEN gehalt_alt * 1.05 < gehalt_neu UPDATE mitarbeiter SET prov = 0; Bei der Verwendung von Triggern müssen wir beachten, keine zyklischen Trigger zu definieren. In obigem Beispiel wäre das etwa der Fall, wenn wir einen Trigger definierten, der, wenn ein Mitarbeiter eines Restaurants mehr als der Durchschnitt aller Mitarbeiter dieses Restaurants verdient, das Gehalt des Mitarbeiters um 20 Euro erhöht. Dieser Trigger reagiert auf ein UPDATE des Attributes gehalt. Durch die Ausführung des Triggers wird das Attribut gehalt nochmals verändert, der Trigger wird wieder gefeuert usw. 4.2 Embedded SQL Im Teil 5 des SQL-3 Standards mit dem Titel SQL Host Language Bindings“ wird die Einbet” tung von SQL in verschiedene Wirtsprachen beschrieben. Die Wirtsprachen, die im Standard behandelt werden sind C, C++, BASIC, Ada und COBOL. 4.2.1 Prinzip der Einbindung Ein Embedded-SQL-Programm besteht aus Befehlen der jeweiligen Wirtsprache und ESQLBefehlen. ESQL-Befehle werden durch das Schlüsselwort EXEC SQL als solche ausgewiesen. Die in einem besonderen Deklarationsteil (der DECLARE SECTION“) definierten Varia” blen können sowohl von Befehlen der Wirtsprache als auch von ESQL-Befehlen gelesen und geschrieben werden, wobei im Fall von ESQL-Befehlen diese Variablen durch einen vorangestellten Doppelpunkt gekennzeichnet werden. Als Befehle stehen alle im letzten Abschnitt vorgestellten SQL-Befehle zur Verfügung. So können wir mittels EXEC SQL UPDATE relation” Name SET attribute = expression WHERE condition“ für alle Tupel aus der Relation relationName, die die Bedingung condition erfüllen, den Wert des Attributes attribute auf den Wert des Ausdrucks expression setzen. Abbildung 4.2 zeigt den Ablauf zur Erstellung eines ausführbaren Programms, das mittels SQL auf eine Datenbank zugreift. Zunächst werden von einem speziellen ESQL-Precompiler die ESQL-Befehle in normale Befehle aus der Wirtsprache übersetzt. Dadurch entsteht ein Programm, das von einem Compiler der Wirtsprache übersetzt werden kann. Zuletzt wird der Objektcode mit der ESQL-Laufzeitbibliothek gelinkt. KAPITEL 4. SQL 4.27 prog.sc ESQL-Precompiler prog.c C Compiler prog.o Linker SQL-Library prog Abbildung 4.2: Ablauf der Erstellung eines ausführbaren Programmes in C 4.2.2 Cursor Beim Zusammenspiel zwischen datensatzorientierten Programmiersprachen, wie sie die Wirtsprachen sind, und der mengenorientierten Sprache SQL entsteht das Problem, dass die Menge der Tupel ein SQL-Abfrage in eine Reihe von Tupeln verwandelt werden muss, da die Wirtsprachen nur ein Tupel nach dem anderen abarbeiten können. Um die Tupel einer Abfrage elementweise abzuarbeiten, wird das Konzept eines Cursors verwendet. Ein Cursor wird mit dem Befehl EXEC SQL DECLARE cursorName CURSOR FOR query “ für ” eine bestimmte Abfrage (query) deklariert. Sollen bestimmte Attributwerte der ausgewählten Tupel in der weiteren Verarbeitung geändert werden, so wird der DECLARE CURSOR-Befehl um die Klausel FOR UPDATE OF attribute-1, . . . , attribute-n ergänzt. Die Deklaration des Cursors bedingt noch nicht die Ausführung der dem Cursor zugeordneten SQL-Abfrage. Diese wird erst durch den Befehl EXEC SQL OPEN CURSOR cursorName“ ” ausgeführt, wobei der Cursor vor das erste Tupel des Ergebnisses gesetzt wird. Mit dem Befehl EXEC SQL FETCH cursorName INTO :var-1, . . . , :var-n“ wird zunächst der Cursor ” um ein Tupel weiterbewegt, danach werden die Attributwerte des Tupels in die angegebenen ESQL-Wirtvariablen gelesen. Ist kein Tupel mehr vorhanden, wird die Statusvariable SQLSTATE gesetzt. Ein Cursor wird mit dem Befehl EXEC SQL CLOSE cursorName“ wieder ” geschlossen. Beim Beenden einer Transaktion mit den Befehlen EXEC SQL COMMIT“ oder ” EXEC SQL ROLLBACK“ werden etwaige offene Cursor automatisch geschlossen. ” 4.3 SQL-2 versus SQL-3 Standard Der Schritt von SQL-2 zu SQL-3 bedeutete eine enorme Erweiterung des Sprachumfangs von SQL. Aufgrund des anspruchsvollen und komplexen Programms haben die Normierungsinstitute ANSI und ISO daher beschlossen, die weitere Entwicklung von SQL in mehrere Stan- 4.28 KAPITEL 4. SQL dards aufzuteilen. Der Standard für die ersten fünf Teile ist bereits bei ANSI erhältlich, die Beschreibung der restlichen Teile wird folgen. Teil 1: ANSI/ISO/IEC 9075-1-1999 Information Technology – Database Languages – SQL Part 1: Framework (SQL/Framework). Dieser Teil gibt einen Überblick über den Standard und beschreibt, in welcher Form die einzelnen Komponenten von SQL zusammenspielen. Teil 2: ANSI/ISO/IEC 9075-2-1999 Information Technology – Database Languages – SQL Part 2: Foundation (SQL/Foundation). In diesem Teil finden wir die Spezifikation aller Datentypen, die Beschreibung der DDL, der DML, die Befehle zur Transaktionskontrolle und zum Verbindungsaufbau mit der Datenbank. Dieser Teil enthält die meisten der vorgestellten Erweiterungen von SQL: die neuen Datentypen und ADTs, die Behandlung der Rekursion und der Trigger. Teil 3: ANSI/ISO/IEC 9075-3-1999 Information Technology – Database Languages – SQL Part 3: SQL/CLI (Call Level Interface). CLI bietet eine Schnittstelle zu einem Datenbankmanagementsystem, wobei kein Preprozessor notwendig ist, um die SQL-Befehle in die entsprechende Programmiersprache der Anwendung zu übersetzen. Es werden die Strukturen und Prozeduren beschrieben, die verwendet werden können, um SQLStatements aus Anwendungen, die in verschiedenen Programmiersprachen geschrieben sind, auszuführen. Damit können wir Resourcen allozieren und deallozieren, die Verbindung zu einem SQL-Server kontrollieren, Transaktionen kontrollieren und SQLStatements ausführen. Grob gesagt erzeugt die Anwendung durch das Absetzen eines SQL-Befehls einen CLI environment handle. Danach erstellt sie einen connect handle, über den die Verbindung mit der Datenbank abläuft. CLI kann nun die SQL-Statements auf der Datenbank durchführen. Nach erfolgreicher Durchführung wird die Verbindung wieder geschlossen, der connect handle und der environment handle freigegeben. Teil 4: ANSI/ISO/IEC 9075-4-1999 Information Technology – Database Languages – SQL Part 4: SQL/PSM (Persistent SQL Modules). PSM beschreibt, wie Stored Procedures und benutzerdefinierte Funktionen einer 3GL (Third Generation Language) in SQL geschrieben werden können. Funktionen und Prozeduren können entweder extern definiert sein oder in ADTs gekapselt sein. Für ADTs werden automatisch Konstruktor- und Destruktor-Funktionen angelegt, die bei der Erstellung einer neuen Instanz eines ADTs und beim Löschen verwendet werden müssen. Für jedes Attribut wird eine Observerund eine Mutator-Funktion angelegt, die zum Auslesen und zum Verändern der Werte verwendet werden. Zur Kontrolle des Programmflusses werden Blockbefehle wie BEGIN und END, Schleifenbefehle wie WHILE, IF THEN ELSE, REPEAT, FOR und LOOP und der Befehl CASE KAPITEL 4. SQL 4.29 zugelassen. Diese müssen nicht mehr von Wirtsprachen ausgeborgt“ werden. Dieser ” Zusatz erweitert SQL zu einer computational vollständigen Sprache. Teil 5: ANSI/ISO/IEC 9075-5-1999 Information Technology – Database Languages – SQL Part 5: SQL/Bindings. Dieser Teil wird aus Kompatibilitätsgründen zu SQL-2 übernommen und auf SQL-3 Konstrukte erweitert. Er stellt drei Methoden vor, wie aus Anwendungsprogrammen, die in einer der gängigen Programmiersprachen geschrieben wurden, auf eine Datenbank zugegriffen werden kann. Die am meisten verwendete Methode ist die Einbettung in eine andere Programmiersprache durch Verwendung eines Precompilers. Weiters gibt es Dynamic SQL und direkten Aufruf von SQL-Statements. Teil 6: SQL/Transactions. Dieser Teil beschreibt die Strategien und Mechanismen, durch die Anwendungsprogramme mit Transaktionsmanager und Resourcemanager interagieren. Der Transaktionsmanager muss die verschiedenen Resourcemanager, z.B. verschiedene Datenbankmanagementsysteme, koordinieren. Die Resourcemanager ihrerseits verwenden two-phase-commit, um die Korrektheit eines Transaktionsablaufs sicherzustellen. Diese Verfahren werden bei verteilten Transaktionen, die verschiedene Datenbankmanagementsysteme auf unterschiedlichen Plattformen betreffen, verwendet. Teil 7: SQL/Temporal. In diesem Teil wird auf den Umstand eingegangen, dass Daten nur für bestimmte Zeitabschnitte gültig sind; z.B. kann ein Mitarbeiter in der Mitarbeiterhierarchie aufsteigen oder ein neues Gehalt bekommen. Nicht mehr gültige Daten können jedoch oft nicht einfach gelöscht werden. In diesem Teil werden Datentypen und Befehle vorgestellt, um über die Zeit veränderte Daten zu verwalten. Teil 8: SQL/Object. In diesem Teil wird beschrieben, wie das Datenbankmanagementsystem auf spezielle Datentypen, die in den Anwendungsprogrammen verwendet werden, zugreifen kann. Zusätzlich zum SQL-3 Projekt gibt es weitere Projekte zur Erweiterung von SQL, die teils neuere Entwicklungen in Informationssystemen aufgreifen. So hat etwa SQL/MM zum Ziel, Standard-Multimedia-Pakete basierend auf ADT’s in SQL-3 zu entwickeln, und SQL/RT will Unterstützung für Echtzeitdatenbanken geben. KAPITEL 4. SQL 4.30 4.4 Übungsaufgaben Übung 4.1 In einer relationalen Datenbank sind Daten über Erdbeben in folgenden Relationen gespeichert: erdbeben(ENR, EPX, EPY, DATUM) schaden(ENR, SNR, KX, KY, OPFER, EURO) erdstoss(ENR, SNR, SX, SY, STAERKE) stadt(KX, KY, SNAME, LAND) Schlüssel sind unterstrichen. Die Erdbeben sind durch eindeutige Nummern identifiziert und durch die kartesischen Koordinaten der Epizentren (X- und Y-Koordinaten, in km) sowie die Zeitpunkte des Auftretens beschrieben. Jedes Erdbeben umfasst (i.a. mehrere, durchnummerierte) Erdstöße, für die jeweils Auftrittsort (=Koordinaten) und Stärke gespeichert sind. Durch einen Erdstoß enstandene Schäden sind in schaden nach Orten (=Koordinaten) gespeichert, wobei jeweils die Anzahl der Opfer und der Sachschaden (Einheit: 100.000 Euro) gespeichert ist. stadt enthält ein Koordinatenverzeichnis aller Städte. Schreiben Sie eine SQL-Abfrage, die das heftigtste Erdbeben (Heftigkeit = stärkster Einzelstoß) ausgibt, zusammen mit dem Datum und der Anzahl der Opfer bei diesem Erdbeben. Schreiben Sie eine SQL-Abfrage, die jene Erdbeben ausgibt, die im Umkreis von 100km (=Abstand vom Epizentrum) einen Gesamtschaden von mehr als 15 Mio Euro verursacht haben. Übung 4.2 Gegeben sind folgende Relationen einer Datenbank über Opernsänger: auftritt(SAENGER, HAUS, TAG, MONAT, JAHR, GAGE) lehrer(MEISTER, SCHUELER) Schlüsselattribute sind unterstrichen. Jedes Tupel in auftritt gibt an, in welchem Opernhaus der Sänger an dem betreffenden Datum aufgetreten ist und wieviel er dafür kassiert hat. Die Tupel in lehrer geben an, welche Sänger Lehrer von anderen Sängern sind. Formulieren Sie eine Abfrage in SQL, die die Namen aller Sänger liefert, welche in einem Zeitraum von zwei aufeinanderfolgenden Kalenderjahren in Summe mehr als 500.000,- Euro Gage kassiert haben. Formulieren Sie eine Abfrage in SQL, die genau jene Tupel aus lehrer liefert, für die gilt, dass der Schüler in einem Opernhaus aufgetreten ist, in dem sein Lehrer nicht aufgetreten ist. Übung 4.3 Gegeben sind folgende Relationen einer Datenbank über Schilifte: lift(LNR,TAL,BERG,KAP,LAENGE), station(SNAME,HOEHE), piste(PNR,START,ZIEL,GRAD,LAENGE) KAPITEL 4. SQL 4.31 Schlüsselattribute sind unterstrichen. Jedes Tupel in lift gibt die eindeutige Nummer, die Tal- und Bergstation, sowie die Förderkapazität (Personen pro Stunde) und die Länge eines Lifts an. Zu jeder Station ist in station ihre Seehöhe gespeichert; zu einer Station können mehrere Lifte hinführen bzw. von dort wegführen. Für jede Piste sind eine eindeutige Nummer, Start und Ziel (jeweils Stationen), der Schwierigkeitsgrad ( blau“ = leicht, rot“ = ” ” mittelschwer, schwarz“ = schwer) und die Länge gespeichert. ” Formulieren Sie eine Abfrage in SQL, die den Namen der höchstgelegenen Station und die Anzahl der Personen ausgibt, die an einem Tag (= in 8 Stunden) maximal dorthin befördert werden können. Anmerkung: Die höchstgelegene Station ist eindeutig. Formulieren Sie eine Abfrage in SQL, die in einer Tabelle die Nummern jener Pisten zusammen mit dem jeweiligen Schwierigkeitsgrad und der entsprechenden Höhendifferenz ausgibt, sodass jede Piste für ihren Schwierigkeitsgrad die höchste Höhendifferenz hat. Ausgabetupel z.B: (1,blau,500) . Übung 4.4 Gegeben sind folgende Relationen aus der Datenbank eines Gemüsegroßanbauers: pflanze(NAME,DUENGER,REIFEDAUER) anbau(FELD,BEET,PNAME,STUECK,WOCHE) weg(WEGNR,FELD1,FELD2,LAENGE) Schlüsselattribute sind unterstrichen. Für jede Pflanze ist ihr eindeutiger Name, ihr wöchentlicher Düngerbedarf und ihre Reifedauer (in Wochen) gespeichert. Jedes Tupel in anbau besagt, dass eine bestimmte Stückzahl einer Pflanze in der angegebenen Woche in einem Beet eines Feldes angepflanzt worden ist. Jedes Feld besteht aus mehreren Beeten, die unterschiedlich bepflanzt sein können. Ernte und Anpflanzung erfolgen jeweils am Wochenbeginn. In weg sind direkte Wege zwischen Feldern und deren Länge (in m) gespeichert. Schreiben Sie eine Abfrage in SQL, die jene Felder liefert, die in der 30. Woche mit Karotten (’KAR’) bepflanzt waren und mehr als 1 kg Dünger für diese benötigt haben, zusammen mit der Düngermenge. Schreiben Sie eine SQL-Abfrage, die jene Beete ausgibt, in denen unmittelbar hintereinander zweimal dieselbe Pflanzenart angebaut worden ist. Übung 4.5 Gegeben sind folgende Relationen aus der Datenbank einer Gärtnerei für Schnittblumen: blume(NAME,DUENGER,WACHSZEIT) anbau(GLASHAUS,BEET,BNAME,STUECK,WOCHE) weg(WEGNR,GLASHAUS1,GLASHAUS,LAENGE) Schlüsselattribute sind unterstrichen. Für jede Blumenart ist ihr eindeutiger Name, ihr wöchentlicher Düngerbedarf (in Gramm) und die Zeit bis zur Schnittreife (in Wochen) gespeichert. Jedes Tupel in anbau besagt, dass eine bestimmte Stückzahl einer Blume in der KAPITEL 4. SQL 4.32 angegebenen Woche in einem Beet eines Glashauses angepflanzt worden ist. Jedes Glashaus hat mehrere Beete, die unterschiedlich bepflanzt sein können. Blumenschnitt und Anpflanzung erfolgen jeweils am Wochenbeginn. In weg sind direkte Wege zwischen Feldern und deren Länge (in m) gespeichert. Formulieren Sie eine Abfrage in SQL, die jene Glashäuser liefert, in denen in der 30. Woche mehr als 2 kg Dünger für Tulpen (’TULPE’) benötigt wurde, zusammen mit der jeweiligen Düngermenge. Schreiben Sie eine SQL-Abfrage, die jene Beete ausgibt, in denen unmittelbar hintereinander zweimal dieselben Blumen gepflanzt wurden. Übung 4.6 Gegeben sind folgende Relationen aus der Datenbank eines Perlenzüchters: muschel(MNAME,PTYP), perle(PTYP,KALIBER,PREIS), stelle(NR,ANZKOERBE,TIEFE), besatz(NR,JAHR,MNAME), ernte(NR,JAHR,KALIBER,ANZPERLEN) Schlüsselattribute sind unterstrichen. Für jede Muschelart ist ihr eindeutiger Name sowie der Perlentyp gespeichert, der von dieser Muschelart produziert werden kann (Annahme hier: nur ein Typ). Für jeden Perlentyp (z.B. weiß, schwarz) ist der Preis einer Perle nach Kaliber (Durchmesser in mm) gespeichert. Die Muscheln werden in Körben an bestimmten nummerierten Stellen ausgesetzt, von denen die Anzahl der Muschelkörbe und die Tiefe (in m), in der sie sich befinden, gespeichert sind. Beim Besatz einer Stelle (höchstens einmal pro Jahr) werden alle Körbe mit Muscheln derselben Art (mname) bestückt, mit je 10 Stück pro Korb. Die Daten der Ernte an einer Stelle sind mit dem Erntejahr bestimmt und geben die Anzahl der Perlen an, die pro Kaliber aus den Muscheln gewonnen wurden. Formulieren Sie eine Abfrage in SQL, die die Nummer(n) jener Stelle(n) liefert, an denen im Jahr 1992 am meisten Perlen des Kalibers 7mm in einer Ernte geerntet worden sind, sowie die betreffende Anzahl. Formulieren Sie eine Abfrage in SQL, die jene Muschelarten liefert, mit denen an Stelle 7 jeweils eine Ausbeute von insgesamt mehr als 5000 weißen Perlen erzielt wurde, zusammen mit der Ausbeute. (Die Ausbeute bezieht sich auf alle Besätze.) Übung 4.7 Gegeben seien die Datenbankrelationen aus Beispiel 3.9. Schreiben Sie eine Abfrage in SQL, die jene Fluglinien ausgibt, die in einem Land nur Inlandsflüge anbieten, zusammen mit dem Land. (Annahme: die Einträge in flug sind symmetrisch, d.h., wenn es einen Flug von Wien nach Frankfurt gibt, gibt es auch einen Flug von Frankfurt nach Wien.) Schreiben Sie eine Abfrage in SQL, die zu jeder Fluggesellschaft angibt, wieviele Flugzeuge von welchen Herstellern zwischen 1970 und 1995 gekauft wurden. KAPITEL 4. SQL 4.33 Übung 4.8 Gegeben seien die Datenbankrelationen aus Beispiel 3.10. Schreiben Sie eine Abfrage in SQL, die den Namen und die Art aller Tiere ausgibt, die in zu dicht besiedelten Gehegen sitzen. Schreiben Sie eine Abfrage in SQL, die Nummer und Typ aller Käfige ausgibt, in denen sich nur Tiere derselben Art befinden. Übung 4.9 Gegeben seien die Datenbankrelationen aus Beispiel 3.11. Schreiben Sie eine Abfrage in SQL, die zu jeder Speise den dazugehörigen Gewinn für die Firma angibt. Schreiben Sie eine Abfrage in SQL, die den Namen aller Zutaten zu den Produkten mit der geringsten Haltbarkeitsdauer angibt. Übung 4.10 Gegeben seien die Datenbankrelationen aus Beispiel 3.12. Die Länderwertung gibt zu jedem Land und Geschlecht die Summe aller in einer Saison erreichten Punkte an. (Achtung bei Rennen mit 2 Durchgängen.) Schreiben Sie eine Abfrage in SQL, die zu jedem Land das stärkere Geschlecht in der Länderwertung ausgibt gemeinsam mit den Punkten. Schreiben Sie eine Abfrage in SQL, die den Namen jener FahrerInnen angibt, die es geschafft haben, sich im 2. Lauf in der Gesamtwertung um mehr als 5 Plätze zu verbessern und wie oft es ihnen gelungen ist. Übung 4.11 Gegeben seien die Datenbankrelationen aus Beispiel 3.13. Schreiben Sie eine Abfrage in SQL, die den Namen und die Kategorie aller jener Hotels ausgibt, die in der Woche vom 14. - 21. August 1999 ausgebucht sind (Zimmer werden immer nur für die ganze Woche vergeben). Schreiben Sie eine Abfrage in SQL, die zu jeder Bettenanzahl Name und Adresse jener Hotels angibt, die die günstigsten Nächtigungspreise für dieser Bettenanzahl haben (Bsp.:(1, Bristol, Kärntnerstr. 1)). Übung 4.12 Gegeben seien die Datenbankrelationen aus Beispiel 3.14. Schreiben Sie eine Abfrage in SQL, die Name, Adresse und die Anzahl der Sparbücher jener Kundinnen ausgibt, die im Jahr 1997 insgesamt mehr Geld eingelegt als abgehoben haben. Schreiben Sie eine Abfrage in SQL, die Name, Adresse und Beruf aller jener Kundinnen ausgibt, die zum 1.1.1997 kein Sparbuch hatten. 4.34 KAPITEL 4. SQL Kapitel 5 Datalog 5.1 Motivation Datalog ist eine Prolog-ähnliche logische Abfragesprache, in der rekursive Anfragen an eine Datenbank direkt (auf nicht-prozedurale Weise) formuliert werden können. Die Relation Alle wege aus Beispiel 4.32 kann in Datalog unter Zuhilfenahme einer Relation Sum(X, Y, Z) (X = Y + Z) wie folgt definiert werden: Alle wege(START, ZIEL, KOSTEN) : − Lieferung(START, ZIEL, , KOSTEN). Alle wege(START, ZIEL, KOSTEN) : − Alle wege(START, BIS, KOSTEN1), Lieferung(BIS, ZIEL, , KOSTEN2), Sum(KOSTEN, KOSTEN1, KOSTEN2). Sollen alle Wege von einem bestimmten Ort (z.B. Wien) berechnet werden, so können wir dies durch Definition der gesamten Relation Alle wege (wie oben) und anschließende Abfrage Alle wege(wien, X, Y)“ realisieren. Effizienter ist es aber, eine spezielle Abfrage zu ” konzipieren, da wir in diesem Fall nur die Wege von Wien weg berechnen und nicht alle möglichen Wege in der Relation. Alle wienwege(START, ZIEL, KOSTEN) : − Lieferung(wien, ZIEL, , KOSTEN). Alle wienwege(START, ZIEL, KOSTEN) : − Alle wienwege(START, BIS, KOSTEN1), Lieferung(BIS, ZIEL, , KOSTEN2), Sum(KOSTEN, KOSTEN1, KOSTEN2). 5.2 Die Syntax von Datalog Die Syntax der Sprache Datalog ist durch folgende BNF-Deklaration gegeben. 1 KAPITEL 5. DATALOG 5.2 <Datalog_Programm> ::= <Datalog_Regel> | <Datalog_Programm> <Datalog_Regel> <Datalog_Regel> ::= <Regelkopf> :- <Regelrumpf>. <Regelkopf> ::= <Literal> <Regelrumpf> ::= <Literal> | <Regelrumpf>, <Literal> <Literal> ::= <Relationen_id>[(<Argumentliste>)] <Argumentliste> ::= <Term> | <Argumentliste>, <Term> <Term> ::= <Konstantensymbol> | <Variablensymbol> <Konstantensymbol> ::= <Zahl> | <Kleinbuchstabe> | <Kleinbuchstabe><String> <Variablensymbol> ::= <Großbuchstabe> | <Großbuchstabe><String> | "_" 5.2.1 Einschränkungen zur Syntax von Datalog < Relationen id > bezeichnet entweder den Namen einer bereits bekannten, in der Datenbank abgespeicherten Relation (z.B. Restaurant) oder einer neuen Relation, die durch das Datalog-Programm definiert wird (z.B. Alle wege). Durch ein Datalog-Programm können gleichzeitig mehrere neue Relationen definiert werden. Namen bereits existierender Relationen dürfen nur in Regelrümpfen vorkommen, da diese Relationen nicht verändert werden sollen. Außer Datenbank-Relationen sind als < Relationen id > auch spezielle Vergleichsprädikate wie =, <>, <, >, usw. zugelassen. Diese werden formal den bekannten Datenbankrelationen gleichgestellt und dürfen daher nur in Regelrümpfen vorkommen. Jede Variable, die im Kopf einer Datalog-Regel vorkommt, muss auch im Rumpf derselben Regel vorkommen. Variablen, die als Argumente spezieller Vergleichsprädikate vorkommen, müssen im selben Regelrumpf auch in Literalen ohne Vergleichsprädikate vorkommen. Jede verwendete < Relationen id > tritt immer mit derselben Anzahl von Argumenten auf. Datalog-Abfragen werden auch Datalog-Programme“ genannt. ” KAPITEL 5. DATALOG 5.3 5.3 Semantik von Datalog Die Semantik von Datalog ohne Negation1 ist formal sehr einfach beschreibbar. Es gibt zwar mehrere verschiedene Semantiken, allerdings können wir zeigen, dass sie äquivalent sind und so dasselbe Ergebnis liefern. Wir stellen in diesem Abschnitt zunächst die logische Semantik von Datalog vor, die einem Programm rein deklarative Bedeutung zuschreibt, danach die operationale Semantik von Datalog, die auf einer konstruktiven Bottom-Up“ Methode basiert. ” 5.3.1 Logische Semantik von Datalog Sei R eine Datalog-Regel der Form L0 :- L1 , L2 , ..., Ln wobei jedes Li ein Literal der Form pi (t1 , . . . tni ) ist und seien x1 , x2 , . . . , xk alle Variablen, die in R vorkommen, Dann bezeichnen wir mit R ∗ die folgende prädikatenlogische Implikationsformel: ∀x1 ∀x2 . . . ∀xk ((L1 ∧ L2 ∧ . . . ∧ Ln ) ⇒ L0 ). Es werden also die Namen von Datenbankrelationen als Prädikatensymbole gedeutet. Sei P ein Datalog-Programm bestehend aus den Regeln R1 , R2 , . . . Rm , dann bezeichnen wir mit P ∗ jene prädikatenlogische Formel, die durch Konjunktion der einzelnen R i∗ entsteht, also: ∗ P ∗ = R1∗ ∧ R2∗ ∧ . . . ∧ Rm Es wird also jedem Datalog-Programm P in (semantisch) eindeutiger Weise eine Formel P zugeordnet. Wir betrachten nun eine in der Datenbank abgespeicherte Relation R. Auch dieser Relation können wir eine prädikatenlogische Formel R∗ zuordnen, die aus der Konjunktion aller Prädikatenausdrücke der folgenden Form besteht: ∗ R(t1 , . . . , to ) für jedes Tupel (t1 , . . . , to ) in R Einzelne Prädikatenausdrücke der Form R(t1 , . . . , to ) nennen wir auch Fakten. Da eine Relation eine (ungeordnete) Menge von Tupeln ist, ist die Zuordnung R → R ∗ nicht eindeutig bestimmt. Um diese Zuordnung eindeutig zu machen, können wir eine beliebige Ordnung (z.B. lexikographische Ordnung) über den Tupeln einer Relation voraussetzen. Die Auswahl der Ordnung spielt keine Rolle, weil die logische Konjunktion kommutativ ist. Eine gesamte Datenbank DB bestehend aus mehreren Relationen R 1 , R2 , . . ., Rk kann nun als entsprechende logische Formel DB* gedeutet werden: 1 Die Negation in Datalog führen wir in Anbschnitt 5.4 ein. KAPITEL 5. DATALOG 5.4 DB ∗ = R∗1 ∧ R∗2 ∧ . . . ∧ R∗k . Sei G eine Konjunktion von Fakten und von Implikationsformeln. Dann ist die Menge der aus G logisch folgenden Fakten eindeutig bestimmt. Wir bezeichnen diese Menge mit cons(G). Die Semantik eines Datalog-Programms P kann nun als Funktion M [P ] dargestellt werden, die jeder Datenbank DB die Menge aller aus der Formel P ∗ ∧ DB ∗“ logisch folgenden ” Fakten zuordnet: M [P ] : DB −→ cons(P ∗ ∧ DB ∗ ) Hierdurch ist die Semantik von Datalog auf sehr einfache und äußerst elegante Weise definiert. Beispiel 5.1 Betrachten wir einen Ausschnitt der Datenbank, die wir für R EINE entworfen haben, nämlich die Relation Lieferung aus Abbildung 4.1. Der Ausdruck Lieferung(wien, wr. neustadt, 1, 30) ist ein Fakt, und die folgende logische Formel DB ∗ entspricht der Datenbank DB: Lieferung(wien, wr.neustadt, 1, 30) Lieferung(wien, st.pölten, 1, 60) Lieferung(st.pölten, krems, 2, 70) Lieferung(st.pölten, linz, 2, 80) Lieferung(tulln, krems, 3, 30) ∧ ∧ ∧ ∧ ∧ Lieferung(wien, klosterneuburg, 1, 20) Lieferung(wien, linz, 1, 100) Lieferung(st.pölten, melk, 2, 60) Lieferung(klosterneuburg, tulln, 3, 20) Lieferung(wr.neustadt, eisenstadt, 4, 50) Betrachten wir dazu das folgende Datalog-Programm P , das Paare von Orten berechnet, die vom Lieferanten 2“ beliefert werden: ” Liefert 2(X, Y) : − Lieferung(V1, X, 2, K1), Lieferung(V2, Y, 2, K2). Dem Datalog-Programm P entspricht die folgende logische Formel P ∗ : ∀ X ∀ Y ∀ V1 ∀ V2 ∀ K1 ∀ K2 : ((Lieferung(V1, X, 2, K1) ∧ Lieferung(V2, Y, 2, K2)) ⇒ Liefert 2(X, Y)). Es ist leicht zu sehen, dass aus der Konjunktion von DB ∗ und P ∗ außer den bereits in DB enthaltenen Fakten die folgenden Fakten logisch ableitbar sind: Liefert 2(krems, krems). Liefert 2(krems, linz). Liefert 2(krems, melk). ∧ ∧ ∧ ∧ KAPITEL 5. DATALOG Liefert Liefert Liefert Liefert Liefert Liefert 5.5 2(linz, krems). 2(linz, linz). 2(linz, melk). 2(melk, krems). 2(melk, linz). 2(melk, melk). Mit anderen Worten definiert das Datalog-Programm P eine neue Relation Liefert 2, deren aktuelle Instanz folgendermaßen aussieht: Liefert 2 Krems Melk Krems Linz Melk Krems Melk Linz Linz Krems Linz Melk 5.3.2 Operationale Semantik von Datalog Bei der operationalen Semantik werden die Datalog-Regeln als einfache Inferenzregeln aufgefasst, die es erlauben, bei Vorhandensein von Fakten, die im Rumpf auftreten, den Fakt im Kopf einer Regel abzuleiten. So kann aus der Regel Liefert(tulln, krems) : − Lieferung(tulln, krems, 3, 30). und dem Fakt Lieferung(tulln, krems, 3, 30) der Fakt Liefert(tulln, krems) gewonnen werden. Eine Regel R, in der Variable auftreten, wird dabei als Repräsentation aller variablenfreien Regeln aufgefasst, die wir durch beliebiges Ersetzen der Variablen mit Konstantensymbolen gewinnen können, die im Programm P oder in der Datenbank DB vorkommen. Diese Regeln nennen wir Grundinstanzen von R bezüglich P und DB, kurz Ground(R; P, DB). Beispiel 5.2 Die allgemeine Regel Liefert(X, Y) : −Lieferung(X, Y, L, K). stellt alle Paare von Orten dar, zwischen denen es eine Belieferung gibt. Die Grundinstanzen dieser Regel bezüglich des Programms P und der Datenbank DB aus Beispiel 5.1 sind (Konstantensymbole = 1, 2, 3, 4, wien, wr. neustadt, . . . , tulln, krems, eisenstadt, 30, 50, 60, 70, 80, 100.) KAPITEL 5. DATALOG 5.6 Liefert(1, 1) : − Lieferung(1, 1, 1, 1). (X = Y = L = K = 1) Liefert(1, 1) : − Lieferung(1, 1, 1, 2). (X = Y = L = 1, K = 2) .. .. . . Liefert(tulln, krems) : − Lieferung(tulln, krems, 3, 30). (X = tulln, Y = krems, L = 3, K = 30) .. .. . . Insgesamt gibt es |Konstante||Variable| Grundinstanzen (von denen natürlich viele nie zur Ableitung angewendet werden können, z.B. die erste Regel, weil der Fakt Lieferung(1, 1, 1, 1) nicht vorhanden ist). Das Resultat der Anwendung eines Datalog-Programms P auf eine Datenbank DB kann nun über iteriertes Ableiten von Fakten bis zum Fixpunkt (keine neuen Fakten werden mehr gewonnen) definiert werden. Dazu fassen wir im weiteren DB auch als Menge von Fakten auf. Wir definieren zunächst einen Operator TP (DB), der als Resultat die Erweiterung von DB (als Faktenmenge) um alle Fakten liefert, die durch unmittelbare Anwendung einer Regel R auf Fakten von DB abgeleitet werden können. TP (DB) = DB ∪ [ {L0 | L0 : −L1 , . . . , Ln ∈ Ground(R; P, DB), L1 , . . . , Ln ∈ DB} R∈P Formal ist der Operator TP eine Abbildung, die jeder Faktenmenge DB eine Menge von Fakten zuordnet. Wiederholte Anwendung von Regeln wird nun durch die folgende Folge Γ ausgedrückt: Γ = hDB, TP (DB), TP (TP (DB)) = TP2 (DB), ··· TP (TPi−1 (DB)) = TPi (DB), . . .i TPi (DB) sind die Fakten, die wir in i Ableitungschritten aus DB erhalten haben. Diese Menge wächst monoton mit der Zahl der Schritte i, d.h., es gilt TPi (DB) ⊆ TPi+1 (DB). Die Folge Γ konvergiert endlich, d.h., es gibt ein n sodass TPm (DB) = TPn (DB) für alle m ≥ n. (Dies muss gelten, weil es nur endlich viele Konstantensymbole gibt und die Menge KAPITEL 5. DATALOG 5.7 der Grundinstanzen jeder Regel R in jedem Schritt i dieselbe ist, d.h., Ground(R; P, DB) = Ground(R; P, TPi (DB)), i ≥ 1. Da mit jeder Grundinstanz höchstens ein Fakt abgeleitet werden kann, und es insgesamt nur endlich viele Grundinstanzen gibt, können zu DB nur endlich viele Fakten hinzukommen.) Die Faktenmenge, zu der Γ konvergiert, wird mit TPω (DB) bezeichnet; sie ist das Resultat der Anwendung von P auf DB. D.h., die operationale Semantik eines Datalog-Programms P ordnet jeder Datenbank DB die Faktenmenge TPω (DB) zu: O[P ] : DB −→ TPω (DB) Wir können zeigen, dass die operationale Semantik mit der logischen Semantik übereinstimmt, und somit für jedes Programm P und jede Datenbank DB gilt: M [P ](DB) = cons(P ∗ ∧ DB ∗ ) = O[P ](DB) = TPω (DB). Anhand der operationalen Semantik können wir einen einfachen Algorithmus zur Auswertung eines Datalog-Programms P über einer Datenbank DB angeben. Algorithmus IN F ER INPUT: Datalog-Programm P , Datenbank DB OUTPUT: TPω (DB) (= cons(P ∗ ∧ DB ∗ )) S Schritt 1. GP := R∈P Ground(R; P, DB), (* GP ist die Menge aller Grundinstanzen *) Schritt 2. OLD := {}; N EW := DB; Schritt 3. while N EW 6= OLD do begin OLD := N EW ; N EW := T P (OLD); end; Schritt 4. output OLD. Subroutine T P INPUT: Faktenmenge D OUTPUT: T P (D) Schritt 1. F := D; Schritt 2. for each rule L0 : −L1 , . . . , Ln in GP do if L1 , . . . , Ln ∈ DB then F := F ∪ { L0 }; Schritt 3. return F ; (* end of T P *) KAPITEL 5. DATALOG 5.8 Beispiel 5.3 Wir wenden das Programm P Alle wege(X, Y) : − Liefert(X, Y). Alle wege(X, Y) : − Liefert(X, Z), Alle wege(Z, Y). zur Berechnung aller Wege auf die Datenbank DB aus Beispiel 5.2 an und verwenden dabei den Algorithmus IN F ER. Schritt 1. Bildung von GP GP = {Alle wege(wien, wien) : − Liefert(wien, wien), Alle wege(wien, linz) : − Liefert(wien, linz), ... Alle wege(wien, wien) : − Liefert(wien, wien), Alle wege(wien, wien), Alle wege(wien, wien) : − Liefert(wien, linz), Alle wege(linz, wien), ... Alle wege(wien, linz) : − Liefert(wien, st.pölten), Alle wege(st.pölten, linz), . . .}. (Insgesamt gibt es 92 + 93 = 810 Grundinstanzen. ) Schritt 2. OLD := {}, N EW := DB; Schritt 3. Die Schleife wird ausgeführt. Vor dem ersten Durchlauf wird OLD zu DB; das Resultat von T P (DB) ist die Menge DB ∪{Alle wege(X, Y) | Liefert(X, Y) ∈ DB}, da mit OLD = DB nur Grundinstanzen der ersten Regel von P angewendet werden können. Im zweiten Durchlauf ist das Resultat von T P (OLD): OLD ∪ {Alle wege(wien, eisenstadt), Alle wege(wien, tulln), Alle wege(wien, krems), Alle wege(wien, melk), Alle wege(klosterneuburg, krems)}. Es kommen also Fakten durch Anwendung von Grundinstanzen der zweiten Regel von P hinzu. Im dritten Durchlauf ist das Resultat von T P (OLD) gleich OLD, es können keine neuen Fakten mehr abgeleitet werden. KAPITEL 5. DATALOG Liefert Wien Wien Wien Wien St. Pölten St. Pölten St. Pölten Klosterneuburg Tulln Wr. Neustadt Wr. Neustadt Klosterneuburg St. Pölten Linz Krems Melk Linz Tulln Krems Eisenstadt 5.9 Alle wege Wien Wien Wien Wien St. Pölten St. Pölten St. Pölten Klosterneuburg Tulln Wr. Neustadt Wien Wien Wien Wien Klosterneuburg Wr. Neustadt Klosterneuburg St. Pölten Linz Krems Melk Linz Tulln Krems Eisenstadt Eisenstadt Tulln Krems Melk Krems Abbildung 5.1: Ergebnis der Anwendung von P auf Liefert Schritt 4. Ausgabe von OLD. Das Resultat entspricht der Erweiterung der Datenbank DB um die neue Tabelle Alle wege (siehe Abbildung 5.1). Der Algorithmus IN F ER realisiert eine naive Methode zur Auswertung von DatalogProgrammen. Er terminiert bei einem festgehaltenen Programm P zwar immer in polynomieller Zeit, ist aber nicht optimal. Es gibt bessere Algorithmen, auf die wir hier jedoch nicht eingehen. 5.4 Erweitertes Datalog mit Negation Die Abfragesprache Datalog ist nicht relational vollständig: es ist nicht möglich, Differenzen zwischen Relationen auszudrücken. Durch die Einführung des Negationszeichens (non) in Regelrümpfen kann dieser Mangel behoben werden. Bei der Verwendung der Negation müssen wir allerdings die folgende wichtige Einschränkung berücksichtigen, die auch bei der Verwendung von Negation in rekursivem SQL Probleme bereitet: Keine Relation darf (direkt oder indirekt) aufgrund ihrer eigenen Negation definiert werden. Die Erfüllung dieser Bedingung kann einfach durch graphentheoretische Hilfsmittel geprüft werden. KAPITEL 5. DATALOG 5.10 ehemann verheiratet * junggeselle mann Abbildung 5.2: DEP (P ) für das Datalog-Programm aus Beispiel 5.4 5.4.1 Graphendarstellung Sei P ein erweitertes Datalog-Programm, welches negierte Literale in Regelrümpfen enthält. Sei DEP (P ) der gerichtete Graph, der für jede in P vorkommende Relation R genau einen Knoten R enthält und dessen Kantenmenge wie folgt definiert ist: Die Knoten R und S sind genau dann durch eine Kante R → S verbunden, wenn es eine Regel in P gibt, in der die Relation R aufgrund der Relation S definiert wird (mit anderen Worten, falls es eine Regel gibt, deren Kopfprädikat R ist, und die im Rumpf das Prädikat S enthält). Zusätzlich markieren wir jede Kante R → S von DEP (P ) mit einem Stern *“, falls es ” eine Regel in P gibt, deren Kopfprädikat R ist, und die im Rumpf ein negiertes Literal mit Prädikat S enthält. Ein um Negation erweitertes Datalog-Programm P ist genau dann zulässig, wenn im Graph DEP (P ) kein gerichteter Kreis vorkommt, der eine durch *“ markierte Kante enthält. Ein ” solches Programm wird auch stratifiziert genannt, da es bezüglich der Negation in eine Hierarchie von Schichten (Strata) zerlegt werden kann. Beispiel 5.4 Betrachten wir das folgende Datalog-Programm, das aus den Regeln ehemann(X) : − mann(X), verheiratet(X). junggeselle(X) : − mann(X), non ehemann(X). besteht. Der dazugehörige Graph in Abbildung 5.2 besteht aus den Knoten ehemann, junggeselle, mann und verheiratet. Von ehemann nach verheiratet und nach mann gibt es aufgrund der ersten Regel Kanten. Aufgrund der zweiten Regel bekommen wir Kanten von junggeselle nach mann und nach ehemann, wobei letztere mit einem Stern gekennzeichnet wird. Wie wir leicht erkennen können, ist dieses Programm stratifiziert. Beispiel 5.5 Als nächstes ersetzen wir die erste Regel aus dem obigen Programm durch die folgende: ehemann(X) : − mann(X), non junggeselle(X). Dadurch erhalten wir den Graphen in Abbildung 5.3 und ein nicht stratifiziertes DatalogProgramm. KAPITEL 5. DATALOG 5.11 ehemann * junggeselle * mann Abbildung 5.3: DEP (P ) für das Datalog-Programm aus Beispiel 5.5 5.4.2 Semanik von Datalog mit Negation Um die Semantik von Datalog-Programmen mit Negation zu definieren, verwenden wir die Darstellung eines Programmes P in Schichten. Eine Schicht besteht aus der größtmöglichen Menge von Prädikaten, für die gilt: 1. Kommt ein Prädikat p im Kopf einer Regel vor, die im Rumpf ein negiertes Prädikat q enthält, so ist p in einer höheren Schicht als q. 2. Kommt ein Prädikat p im Kopf einer Regel vor, die im Rumpf ein nicht negiertes Prädikat q enthält, so ist p in einer mindestens so hohen Schicht wie q. Wir können folgenden Algorithmus anwenden, um ein Programm in Schichten einzuteilen und so herauszufinden, ob es stratifizierbar ist: INPUT: Eine Menge von Datalog-Regeln. OUTPUT: Eine Entscheidung, ob das Programm stratifiziert ist, und wenn ja, eine Einteilung der Prädikate in Schichten. Methode: Setzen wir die Schicht für alle Prädikate auf 1. Nun wiederholen wir die folgenden Schritte für alle Prädikate p. Wenn p im Kopf einer Regel vorkommt, die im Rumpf ein negiertes Prädikat q hat, p aus Schicht i, q aus Schicht j, und falls i ≤ j, so setzen wir i := j + 1. Wenn p im Kopf einer Regel vorkommt, die im Rumpf ein nicht negierten Prädikat q hat, p aus Schicht i, q aus Schicht j und i < j ist, so setzen wir i := j. Wenn wir einen stabilen Zustand erreichen und kein Prädikat mehr einer anderen Schicht zugeordnet werden kann, so ist das Programm stratifiziert. Wird hingegen eine Schicht n ≥ #p (Anzahl der Prädikate) erreicht, so ist das Programm nicht stratifiziert. 2 Beispiel 5.6 Die Relationen r und s seien vorgegeben. Betrachten wir nun das folgende Datalog-Programm P , welches die neuen Relationen u, v und w definiert: 2 Die genaue Formulierung dieses Algorithmus ist in [Ullman, 1988 Bd. I] zu finden. KAPITEL 5. DATALOG 5.12 * w u v w Schicht 3 u Schicht 2 * s r v,r,s Schicht 1 Abbildung 5.4: DEP (P ) für das Datalog-Programm aus Beispiel 5.6 v(X, Y) : − r(X, X), r(Y, Y). u(X, Y) : − s(X, Y), s(Y, Z), non v(X, Y). w(X, Y) : − non u(X, Y), v(Y, X). Wir stellen DEP (P ) in Abbildung 5.4 dar. Dieser Graph enthält keine Kreise, insbesondere keine Kreise, die eine mit *“ markierte Kante enthalten, daher ist P stratifizierbar. Die ” drei Schichten von P sind in der obigen Abbildung angegeben. Bei der Berechnung von Datalog-Anfragen mit Negation ist die Ordnung der Schichten zu beachten: Zuerst werden alle Relationen der ersten Schicht berechnet, das sind alle Relationen, die ohne Verwendung von Negation berechnet werden. Diese Relationen gelten dann als bekannte, unveränderbare Relationen. Danach werden alle Relationen der zweiten Schicht berechnet usw. Dadurch erhält Datalog mit Negation auch eine eindeutige Semantik. Im obigen Beispiel bedeutet das, dass zuerst v aus r berechnet wird, dann u aus s und v und schließlich w aus u und v. Datalog mit Negation ist relational vollständig. Die Mengendifferenz d = r − s zweier (z.B. zweistelliger) Relationen r und s können wir durch das folgende Programm ermitteln: d(X, Y) : − r(X, Y), ¬ s(X, Y). Beispiel 5.7 Betrachten wir den gerichteten Graphen, der in Abbildung 5.5 dargestellt ist. In der Datenbank DB wird der Graph durch Fakten v(X), für jeden Knoten X, und e(X, Y), für jede Kante zwischen X und Y repräsentiert. Nun wollen wir ein Datalog-Programm schreiben, das alle Paare (X, Y ) ausgibt, wo X eine Quelle, Y eine Senke ist, und die miteinander verbunden sind, d.h., es gibt einen Weg von X nach Y . Als Lösung sollten sich die Paare < a, e >, < a, f > und < d, e > ergeben, wie wir aus der Abbildung sehen können. Als erstes definieren wir ein Prädikat p(X, Y), das wahr ist, wenn X eine Quelle und Y eine Senke ist und es einen Weg von X nach Y gibt. p(X, Y) : − quelle(X), senke(Y), weg(X, Y). Das Prädikat weg können wir in zwei Schritten definieren; einerseits gibt es immer einen trivialen Weg vom Knoten X zu sich selbst (Abbruchbedingung), andererseits gibt es einen KAPITEL 5. DATALOG 5.13 p a b f c e quelle senke * * n quelle weg n senke d Abbildung 5.5: Graph aus Beispiel 5.7 Weg von X zu Y , wenn es eine Kante von X zu einem Zwischenknoten Z gibt, von dem aus ein Weg nach Y führt. weg(X, X) : − v(X). weg(X, Y) : − e(X, Z), weg(Z, Y). Wann ist ein Knoten X eine Quelle? Genau dann, wenn es keine Kante gibt, die nach X führt. Wie können wir diesen Umstand in Datalog ausdrücken? Wenn wir es mit der Regel quelle(X) : −non e(Y, X), v(X). versuchen, so wird diese Regel für alle jene Knoten X zu true ausgewertet, für die es einen Knoten Y gibt, von dem es keine Kante nach X gibt, wie z.B. für b, da es von d keine Kante nach b gibt. Wir wollen aber ausdrücken, dass dies für alle Knoten Y gelten muss. Dafür verwenden wir ein Hilfsprädikat n quelle(X) : −e(Y, X)., das wahr ist, wenn ein Knoten keine Quelle ist. In diesem Fall reicht nämlich das Auffinden einer Kante nach X, um das Prädikat wahr zu machen. Die Quelle selbst definieren wir nun durch quelle(X) : −v(X), ¬n quelle(X). Die Abfrage für die Senke ist analog. Wir erhalten das folgende Programm: p(X, Y) : − quelle(X), senke(Y), weg(X, Y). weg(X, X) : − v(X). weg(X, Y) : − e(X, Z), weg(Z, Y). n quelle(X) : − e(Y, X). quelle(X) : − v(X), non n quelle(X). n senke(X) : − e(X, Y). senke(X) : − v(X) non n senke(X). In diesem Beispiel sehen wir noch eine weitere syntaktische Einschränkung von Datalog mit Negation: alle Variablen, die in negierten Literalen vorkommen, müssen auch in einem positiven Literal im Rumpf vorkommen (siehe die Regel für quelle). 5.14 KAPITEL 5. DATALOG 5.5 Übungsbeispiele Übung 5.1 Prüfen Sie, ob das folgende Datalog-Programm stratfizierbar ist (Angabe des Abhängigkeitsgraphen): p(X,Y) :- q(Z), r(X,Z,Y), non h(Y). h(X) :- q(Y), non s(X,Y), w(X,Z). s(X,Y) :- v(X), non p(X,Y), w(X,Y). Hierbei sind r, q, v und w feststehende Datenbankrelationen. Übung 5.2 In einer Datenbank für eine flexible Fertigungsstraße wird für jedes Produkt festgehalten, welche Teile des Produkts in welcher Anzahl von einer Maschine zu anderen Maschinen weitergeleitet werden (Zyklen treten nicht auf): prod(ProdNo, PName) maschine(MaschNo, MName) band(ProdNo, VonMaschNo, NachMaschNo, TeilNo, Anzahl) 1. Schreiben Sie ein stratifiziertes Datalog-Programm, das die Relation v(P, M 1, M 2, T ) definiert, sodass hP, M 1, M 2, T i ∈ v genau dann gilt, wenn T Teil des Produktes P ist, wobei T von Maschine M 1 zu Maschine M 2 - u. U. über andere Maschinen - fließt. 2. Formulieren Sie ein stratifiziertes DATALOG-Programm, das unter Verwendung von v die Relation f(P, M 1, M 2, T ) definiert, wobei hP, M 1, M 2, T i ∈ f genau dann gilt, wenn M 1 und M 2 Anfangs- bzw. Endpunkt des Flusses des Teils T des Produktes P sind. Übung 5.3 Schreiben Sie zu den Relationen aus Beispiel 4.1 in Kapitel 4 eine DatalogAbfrage, die in die zweistellige Relation m harmlos(ENR, SNR) den Erdstoß mit der größten Stärke aufnimmt, der keine Opfer gefordert hat. Übung 5.4 Schreiben Sie zu den Relationen aus Beispiel 4.2 in Kapitel 4 ein stratifiziertes Datalog-Programm, das die Relation p(S1,S2) so berechnet, dass ein Tupel (s1, s2) genau dann zu p gehört, wenn s1 und s2 einen gemeinsamen Lehrer haben, aber nie gemeinsam auf der Bühne gestanden sind. Übung 5.5 Schreiben Sie zu den Relationen aus Beispiel 4.3 in Kapitel 4 ein stratifiziertes Datalog-Programm, das die Relation p(L) so berechnet, dass die Tupel in p genau die Nummern jener Lifte sind, von deren Bergstation aus es eine Schiabfahrt zur Station sudhaus“ ” gibt, aber keine, die nur über leichte Pisten führt. KAPITEL 5. DATALOG 5.15 Übung 5.6 Schreiben Sie zu den Relationen aus Beispiel 4.4 in Kapitel 4 ein stratifiziertes Datalog-Programm, das die Relation t frei so berechnet, dass die Tupel in t frei genau jene Felder sind, für die gilt, dass in einer Entfernung bis zu 4500 m Tomaten (’TOM’) angebaut worden sind. Ein Built-in Prädikat sum(X, Y, Z) ≡ X = Y + Z steht zur Verfügung. (Ann.: Jedes Feld kommt in weg vor.) Übung 5.7 Schreiben Sie zu den Relationen Beispiel 4.5 in Kapitel 4 ein stratifiziertes DatalogProgramm, das die einstellige Relation l frei so berechnet, dass die Tupel in l frei genau jene Glashäuser sind, für die gilt, dass in keinem Glashaus, das näher als 50 m liegt, Lilien (’LILIE’) angebaut worden sind. Ein Built-in Prädikat sum(X, Y, Z) ≡ X = Y + Z steht zur Verfügung. (Ann.: Jedes Glashaus kommt in weg vor.) Übung 5.8 Schreiben Sie zu den Relationen aus Beispiel 4.6 in Kapitel 4 ein stratifiziertes Datalog-Programm, das die Relation best ertrag(stelle, jahr, mname) so berechnet, dass die Tupel in ihr die ertragreichsten Besätze für Kaliber 6mm angeben, d.h., jene Besätze, die bei der späteren Ernte den höchsten insgesamt erzielten Geldwert der Perlen von Kaliber 6mm erbracht haben. Ein Built-in Prädikat prod(X, Y, Z) ≡ X = Y ∗ Z steht zur Verfügung. Übung 5.9 Schreiben Sie zu den Relationen aus Beispiel 3.9 eine Abfrage in stratifiziertem Datalog, das im Prädikat inland(F,L) alle Fluglinien F angibt, die in einem Land L nur Inlandsflüge anbieten. Übung 5.10 Schreiben Sie zu den Relationen aus Beispiel 3.10 eine Abfrage in stratifiziertem Datalog, die im Prädikat aq weg alle Wege zwischen je zwei Aquarien und die Entfernung dazu angibt. Achtung: der Weg kann auch über andere Käfige gehen. Ein Prädikat sum(X,Y,Z) X = Y +Z ist vorhanden (ignorieren Sie das Problem von unendlichen Wegen = Endlosschleife). Übung 5.11 Schreiben Sie zu den Relationen aus Beispiel 3.11 eine Abfrage in stratifiziertem Datalog, die im Prädikat wichtig(Z) den Namen der Zutaten zu den Produkten angibt, die die geringste Haltbarkeitsdauer haben. Übung 5.12 Schreiben Sie zu den Relationen aus Beispiel 3.12 eine Abfrage in stratifiziertem Datalog, die im Prädikat a(NAME) den Namen jener SchifahrerInnen angibt, die nur Auslandssiege gefeiert haben. Übung 5.13 Schreiben Sie zu den Relationen aus Beispiel 3.13 eine Abfrage in stratifiziertem Datalog, die im Prädikat durchgehend(HNAME) alle jene Hotels angibt, bei denen alle Zimmer im August dieses Jahres durchgehend belegt sind. Dazu benötigen Sie ein Prädikat durch zimmer(HNAME,ZNR), das Ihnen alle Zimmer ausgibt, die durchgehend belegt sind. Übung 5.14 Schreiben Sie zu den Relationen aus Beispiel 3.14 eine Abfrage in stratifiziertem Datalog, die im Prädikat durchgehend(KNR) die Kundennummer jener Kundinnen angibt, die zwischen 1.1.1990 und 31.12.1997 immer mindestens ein Sparbuch an der Bank hatten. 5.16 KAPITEL 5. DATALOG Kapitel 6 Funktionale Abh¨ angigkeiten Bei der Modellierung einer Datenbank suchen wir eine Abbildung von Objekttypen der realen Welt auf Relationenschemata R bzw. von Objektexemplaren der realen Welt auf Tupel t(R). Dabei kommt es aber zu Einschränkungen (constraints) auf den Werten von R. Wir wollen die möglichen R-Werte auf solche beschränken, die Abbild eines realen Objektes sein können. Dabei können wir zwei Arten von Einschränkungen unterscheiden: • Statische Einschränkungen beschreiben Zustände der Datenbank, z.B. muss es für jede Speise ein Restaurant geben, das diese Speise anbietet. Statische Einschränkungen müssen in allen Ausprägungen der Datenbank gültig sein und stellen eine spezielle Form von Integritätsbedingungen dar. • Dynamische Einschränkungen regeln die Übergänge zwischen zwei Datenbankzuständen, z.B.: Das Gehalt eines Angestellten darf nur zunehmen“. ” 6.1 Definition von funktionalen Abh¨ angigkeiten Wie wir in Kapitel 1 gesehen haben, sind zwei wichtige Gründe zur Einführung von Datenbanksystemen die Redundanz der Daten zu minimieren und ihre Verlässlichkeit zu maximieren. Wenn wir a priori bekannte Constraints mitmodellieren können, können wir Teile dieser Aufgaben dem Datenbanksystem selber überlassen. Eine Möglichkeit, dieses a-priori-Wissen zu formulieren, sind Datenabhängigkeiten. Eine wichtige Art von Datenabhängigkeiten sind funktionale Abhängigkeiten. Weiters werden wir am Ende dieses Kapitels noch Inklusionsabhängigkeit besprechen. Definition 6.1 Seien X und Y Teilmengen eines Relationenschemas R. Eine Relation r(R) erfüllt (satisfies) die funktionale Abhängigkeit (functional dependency, FD) X → Y , geschrieben, wenn für jedes Paar von Tupeln u,v ∈ r(R) gilt: u(X) = v(X) ⇒ u(Y ) = v(Y ). Formal: 1 6.2 KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN X → Y ⇔ ∀u, v ∈ r(R) : u(X) = v(X) ⇒ u(Y ) = v(Y ) Die funktionale Abhängigkeit ist also jene Eigenschaft zweier Attributmengen X und Y , dass X eindeutig die Werte von Y bestimmt. X kann dabei natürlich auch nur aus einem einzigen Attribut bestehen. Ist eine funktionale Abhängigkeit als statische Einschränkung auf einem Schema R definiert, so muss jede Relation r über R diese funktionale Abhängigkeit zu jedem Zeitpunkt erfüllen. Definition 6.2 Eine funktionale Abhängigkeit X → Y heißt trivial, wenn Y eine Teilmenge von X ist. X → Y trivial ⇔ Y ⊆ X Beispiel 6.1 Welche funktionalen Abhängigkeiten sollten in unserer Relation Restaurant gelten? Auf jeden Fall sollte die Restaurantnummer den Namen und die Adresse des Restaurants bestimmen. Wir erhalten: f1 = rnr → name, adresse Weiters sollen Name und Adresse zusammen die Restaurantnummer eindeutig bestimmen, ebenso die Anzahl der Hauben und den Typ. Daraus erhalten wir: f2 = name, adresse → rnr, haube, typ Die Instanz der Relation Restaurant aus Abbildung 3.1 erfüllt sowohl f 1 als auch f2 . Wollen wir aber das Tupel t mit t(rnr) = 10, t(name) = Green Cottage, t(adresse) = Kettenbrückengasse 3, 1050 Wien, t(haube) = 1 und t(typ) = österreichisch in die Datenbank aufnehmen, so wird f2 verletzt. Wir können nun die in Kapitel 3 eingeführten Begriffe Oberschlüssel“ und Schlüssel“ ” ” unter Zuhilfenahme des Konzepts der funktionalen Abhängigkeit wie folgt definieren: Definition 6.3 Gegeben sei ein Relationenschema R. Eine Teilmenge X von Attributen in R ist ein Oberschlüssel für R genau dann, wenn X die funktionale Abhängigkeit X → R erfüllt. Formal: X ⊆ R ist Oberschlüssel für R ⇔ X → R Ist X minimal, d.h., gilt für jede Teilmenge Y ⊂ X, dass sie die funktionale Abhängigkeit Y → R nicht erfüllt, so ist X ein Schlüssel. Formal: X ist Schlüssel für R ⇔ (X → R und ∀A ⊂ X(X\A 6→ R)) KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.3 Diese Definitionen von Schlüssel und Oberschlüssel und jene in Kapitel 3 sind äquivalent. 6.2 Ableitungsregeln f ür funktionale Abha¨ngigkeiten Wenn eine Menge von funktionalen Abhängigkeiten F gegeben ist, können wir uns die Frage stellen, welche zusätzlichen Abhängigkeiten f durch F impliziert werden (F |= f ). Beispiel 6.2 Betrachten wir nochmals die beiden funktionalen Abhängigkeiten f 1 = rnr → name, adresse und f2 = name, adresse → rnr, haube, typ. Aufgrund von f 1 gilt: wenn zwei Tupel dieselbe Restaurantnummer haben, so haben sie denselben Namen und dieselbe Adresse. Aufgrund von f2 gilt: wenn zwei Restaurants denselben Namen und dieselbe Adresse haben, so haben sie auch denselben Typ und dieselbe Anzahl von Hauben. Wenn wir diese beiden Bedingungen kombinieren, erhalten wir f3 = rnr → haube, typ. Definition 6.4 Die Menge aller funktionalen Abhängigkeiten, die von F auf R impliziert werden, heißt die Hülle (closure) von F auf R und wird als FR+ notiert. Ist die Attributmenge R aus dem Kontext klar, wird nur F + geschrieben. F + = {f |F |= f } Definition 6.5 Unter der Hülle (closure) einer Menge von Attributen X ⊆ R, geschrieben als XF+ (bzw. X + ) bezüglich F verstehen wir die Menge aller Attribute A, sodass X → A in F + . XF+ = {A | X → A ∈ F + } Die folgenden beiden Algorithmen bestimmen die Hülle einer Menge von Attributen bezüglich einer Menge von funktionalen Abhängigkeiten (Algorithmus CLOSURE), bzw. testen, ob eine bestimmte funktionale Abhängigkeit in der Hülle einer Menge von gegebenen funktionalen Abhängigkeiten enthalten ist (Algorithmus MEMBER). Algorithmus CLOSURE INPUT: X Attributmenge, F Menge von FD’s. OUTPUT: XF+ X + := X while ∃ (Y → Z) ∈ F mit Y ⊆ X + und Z 6⊆ X + do X + := X + ∪ Z end return X + KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.4 Algorithmus MEMBER INPUT: X → Y FD, F Menge von FD’s. OUTPUT: true, if F |= X → Y false, if F 6|= X → Y return (Y ⊆ CLOSURE(X, F )) Wir können den Algorithmus CLOSURE verwenden, wenn wir bei einer gegebenen Menge von funktionalen Abhängigkeiten F über einem Relationenschema R feststellen wollen, welche Attribute die Schlüssel zu R sind. X ist nämlich genau dann ein Schlüssel von R, wenn XF+ = R und X minimal ist. Beispiel 6.3 Betrachten wir nochmals die funktionalen Abhängigkeiten aus Beispiel 6.1. F = {rnr → name, adresse name, adresse → rnr, haube, typ} Um die Hülle von rnr zu berechnen, verwenden wir den Algorithmus CLOSURE und sehen, dass rnr ein Schlüssel der Relation Restaurant ist. {rnr}+ F = {rnr, name, adresse, haube, typ} Nun wollen wir überprüfen, ob f3 = rnr → haube, typ aus F folgt. Dazu verwenden wir den Algorithmus MEMBER. Mit diesem wird überprüft, ob haube und typ in der Hülle von rnr liegen. Da das der Fall ist, erhalten wir den Wert TRUE und f 3 folgt aus F. Von Armstrong (1974) stammt die folgende Axiomatisierung. Sie gibt uns ein System von Ableitungsregeln, mit deren Hilfe wir alle durch eine Menge F von funktionalen Abhängigkeiten implizierten funktionalen Abhängigkeiten f berechnen können. Wir können zeigen, dass die Ableitungsregeln einerseits korrekt (sound) sind, d.h., sie leiten von F nur wirklich gültige funktionale Abhängigkeiten ab (F ` f ⇒ F |= f ), und andererseits auch vollst ändig (complete), d.h., sie erzeugen bei wiederholter Anwendung alle von F implizierten Abhängigkeiten (F |= f ⇒ F ` f ). Einen Beweis dazu finden wir in [Ullman, 1988 Bd. I] oder [Maier, 1983]. Anmerkung: • |= ... Gültigkeitsbegriff, modelltheoretisch • ` ... Ableitbarkeitsbegriff, beweistheoretisch F1.: Reflexivität (reflexivity) Y ⊆X ` X →Y KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.5 F2.: Erweiterung (augmentation) X → Y ` XZ → Y Z F3.: Vereinigung (additivity) X →Y,X →Z ` X →YZ F4.: Zerlegung (projectivity) X →YZ ` X →Y,X →Z F5.: Transitivität (transitivity) X →Y,Y →Z ` X →Z F6.: Pseudotransitivität (pseudotransitivity) X → Y , Y W → Z ` XW → Z Anmerkung: Dieses System ist redundant, einige Regeln sind überflüssig. Z.B. folgt Regel F5 unmittelbar aus Regel F6 (W = {}). Die Bestimmung einer nichtredundanten Axiomatisierung wird als Übungsaufgabe empfohlen. 6.3 Äquivalenz von Systemen von funktionalen Abha¨ngigkeiten In diesem Abschnitt befassen wir uns mit dem Versuch, eine möglichst kompakte Darstellung für funktionale Abhängigkeiten zu finden. Diese ist notwendig, da wir etwa im Algorithmus MEMBER gesehen haben, dass die Laufzeit von der Anzahl der funktionalen Abhängigkeiten im Input abhängt. Eine kleinere Menge von funktionalen Abhängigkeiten bringt also besseres Laufzeitverhalten des Algorithmus. Da funktionale Abhängigkeiten in Datenbanken dazu verwendet werden, Konsistenz und Korrektheit zu gewährleisten, bedeuten weniger funktionale Abhängigkeiten geringeren Speicherplatzverbrauch und weniger Tests, wenn die Datenbank modifiziert wird. Bei der Überführung eines Relationenschemas in dritte Normalform (siehe Kapitel 7.4) ist es ebenfalls notwendig, dass wir von einer möglichst geringen Menge von funktionalen Abhängigkeiten ausgehen. Definition 6.6 Zwei Mengen funktionaler Abhängigkeiten G und F sind äquivalent, geschrieben als G ≡ F , wenn sie dieselbe Hülle besitzen. F heißt dann Überdeckung (cover) von G. G ≡ F ⇔ G+ = F + Um feststellen zu können, ob F ≡ G, gehen wir wie folgt vor: 1. prüfe für alle g ∈ G, ob F |= g, KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.6 2. prüfe für alle f ∈ F , ob G |= f . Beispiel 6.4 Seien F und G die zwei unten angegebenen Mengen funktionaler Abhängigkeiten. Gilt F ≡ G ? G = {rnr → name, adresse name, adresse → rnr, haube, typ} F = {rnr → name, adresse name, adresse → rnr, haube, typ rnr → haube adresse, haube → haube} 1. prüfe für alle g ∈ G, ob F |= g. Antwort: ja, trivialerweise (G ⊆ F ). 2. prüfe für alle f ∈ F , ob G |= f . Die ersten beiden funktionalen Abhängigkeiten sind trivialerweise in G enthalten. Für f3 müssen wir wieder die Hülle von rnr in G betrachten, die haube enthält. Daher gilt G |= f3 . Für f4 bilden wir die Hülle von {adresse, haube} bezüglich G, haube ist trivialerweise enthalten. Daher gilt G |= f 4 . Also haben wir insgesamt erhalten dass F ≡ G. Wir konnten von zwei verschiedenen Mengen F und G von funktionalen Abhängigkeiten zeigen, dass sie dieselbe Menge von funktionalen Abhängigkeiten ableiten. Interessiert sind wir nun an einer möglichst kleinen Menge G von funktionalen Abhängigkeiten, die zu einer gegebenen Menge F äquivalent ist. Dazu benötigen wir die folgenden Definitionen. Definition 6.7 Eine Menge funktionaler Abhängigkeiten F heißt kanonisch, wenn für jede FD f ∈ F die rechte Seite nur aus einem Attribut besteht. Aufgrund der Regel F4 der Armstrong Axiome können wir jede nicht-kanonische funktionale Abhängigkeit in mehrere kanonische zerlegen. Definition 6.8 Eine Menge funktionaler Abhängigkeiten F heißt linksreduziert, wenn sie keine FD f mit überflüssigen Attributen auf der linken Seite enthält. B ist überflüssig in XBY → A bzgl. F ⇔ (F \{XBY → A}) ∪ {XY → A} ≡ F. Definition 6.9 Eine Menge funktionaler Abhängigkeiten F heißt nicht-redundant, wenn es keine FD f in F gibt, sodass F \{f } äquivalent zu F ist. f redundant in F ⇔ F \{f } ≡ F. KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.7 Definition 6.10 Eine Menge funktionaler Abhängigkeiten F heißt minimal, wenn sie kanonisch, linksreduziert und nicht-redundant ist. Wir wollen nun zu einer gegebenen Menge von funktionalen Abhängigkeiten eine äquivalente Menge zu finden, die minimal ist. Dass dies immer geht, sagt uns der folgende Satz: Theorem 6.1 Zu jeder Menge funktionaler Abhängigkeiten F gibt es eine minimale Überdeckung. (Beweis in [Ullman, 1988 Bd. I]) Im allgemeinen ist eine minimale Überdeckung nicht eindeutig, es kann mehrere minimale Überdeckungen geben. Eine minimale Überdeckung kann nach dem folgenden Algorithmus berechnet werden. Algorithmus MINCOVER INPUT: Menge F von FD’s OUTPUT: Minimale Überdeckung G für F 1. Zerlegung aller funktionalen Abhängigkeiten in kanonische: G := {X → Ai | X → A1 . . . Ak ∈ F }; 2. Entfernen überflüssiger Attribute (Linksreduziertheit): Für jede FD XB → Y ∈ G : X → Y ∈ G+ ⇒ G := (G \ {XB → Y }) ∪ {X → Y }; 3. Entfernen aller redundanten Abhängigkeiten X → Y : Für jede FD X → Y ∈ G : X → Y ∈ (G \ {X → Y })+ ⇒ G := G \ {X → Y }; 4. output G. Beispiel 6.5 Betrachten wir die folgende Menge G von funktionalen Abhängigkeiten. Um eine minimale Überdeckung zu finden, führen wir im ersten Schritt G über in eine kanonische Form G0 . Im zweiten Schritt testen wir alle funktionalen Abhängigkeiten auf Linksreduziertheit. Im dritten und letzten Schritt berechnen wir G000 , das nur noch aus nichtredundanten funktionalen Abhängigkeiten bestehen soll. Dieser Test wird mit jeder FD durchgeführt. G = {rnr → name, adresse name, adresse → rnr, haube, typ rnr, name → haube adresse, haube → haube} KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.8 1. Berechnung von G0 . G0 = {rnr → name rnr → adresse name, adresse → rnr name, adresse → haube name, adresse → typ rnr, name → haube adresse, haube → haube} 2. Berechnung von G00 . g3 , g4 , g5 und g7 haben jeweils zwei Attribute auf der linken Seite. Um zu überprüfen, ob wir eines der beiden Attribute streichen können, müssen wir überprüfen, ob das Attribut auf der rechten Seite in der Hülle eines der beiden Attribute + auf der linken Seite bezüglich G liegt. Da name + G = {name}, adresse G = {adresse} können wir weder name noch adresse aus g3 , g4 und g5 streichen und auch nicht haube aus g7 . Allerdings ist haube + G = {haube} und daher können wir adresse aus g 7 streichen. Aufgrund ähnlicher Überlegungen können wir g6 links-reduzieren. G00 = {rnr → name rnr → adresse name, adresse → rnr name, adresse → haube name, adresse → typ rnr → haube haube → haube} 3. Berechnung von G000 . Bei der Überprüfung auf redundante Abhängigkeiten müssen wir für jede Abhängigkeit X → Y testen, ob das Attribut Y auf der rechten Seite in der Hülle der Attribute X der linken Seite bezüglich G\(X → Y ) liegt. Da name nicht in rnr+ G00 \{rnr→name} liegt, ist g1 nicht redundant. Gleiches gilt auch für g2 , g3 und g5 . Für g4 gilt: haube liegt in name, adresse + G00 \{name,adresse→haube} und für g6 gilt: haube + liegt in rnrG00 \{rnr→haube} . Sobald wir eine dieser beiden redundanten Abhängigkeiten entfernen, ist die andere jedoch nicht mehr redundant, wir müssen uns also für eine der beiden entscheiden. Für g7 liegt haube ebenfalls in haube+ G00 \{haube→haube} und ist trivialerweise redundant. KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.9 4. Eine minimale Überdeckung für G ist somit: G000 = {rnr → name rnr → adresse name, adresse → rnr name, adresse → haube name, adresse → typ 6.4 Inklusionsabh¨ angigkeiten Eine weitere besondere Form von statischen Integritätsbedingungen sind Inklusionsabhängigkeiten. Sie dienen vor allem zur Gewährleistung der referentiellen Integrität. Dies ist jene Eigenschaft, dass eine Datenbank keine Fremdschlüssel enthält, deren Werte keine Entsprechung mit einem Schlüsselwert haben. Angewandt auf unsere Relationen Restaurant und Speise bedeutet das, dass es keine Speise geben darf, die im Attribut rnr einen Wert stehen hat, der keine Entsprechung in der Relation Restaurant hat. 6.4.1 Definition von Inklusionsabhängigkeiten Eine Inklusionsabhängigkeit (IA) wird als Integritätsbedingung zu zwei Relationenschemata R und S als R[X] ⊆ S[Y ] geschrieben, wobei X und Y Sequenzen von Attributen von R bzw. S sind und | X | = | Y | gilt. Zwei Relationen r(R) und s(S) erfüllen die Inklusionsabhängigkeit R[X] ⊆ S[Y ], falls πX (r) eine Teilmenge von πY (s) ist. Eine Inklusionsabhängigkeit R[X] ⊆ S[Y ] heißt schlüsselbasiert, wenn Y ein Schlüssel für S ist. Schlüsselbasierte Inklusionsabhängigkeiten dienen zur Gewährleistung der referentiellen Integrität. Ist auf einer Attributmenge X eines Relationschemas R eine schlüsselbasierte Inklusionsabhängigkeit R[X] ⊆ S[Y ] definiert, so heißt X Fremdschl üssel und die Inklusionsabhängigkeit Fremdschlüsselbedingung. Beispiel 6.6 Betrachten wir die Relationenschemata Restaurant = {rnr, name, adresse, haube, typ} und Speise = {name, preis, rnr} aus Beispiel 3.1. Dann ist Speise[rnr] ⊆ Restaurant[rnr] eine Inklusionsabhängigkeit; da das Attribut rnr für Restaurant ein Schlüssel ist, ist das Attribut rnr ein Fremdschlüssel des Relationenschemas Speise. 6.4.2 Ableitungsregeln für Inklusionsabhängigkeiten Casanova et. al. haben 1984 eine Reihe von Ableitungsregeln für Inklusionsabhängigkeiten vorgestellt. Diese sind: 6.10 KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN I1: Reflexivität: X Attributsequenz von R ` R[X] ⊆ R[X] I2: Projektion und Permutation: R[X1 . . . Xn ] ⊆ S[Y1 . . . Yn ] ` R[Xk . . . Xm ] ⊆ S[Yk . . . Ym ], wobei k . . . m eine Sequenz von Indizes aus dem Bereich 1 . . . n ist I3: Transitivität: R[X] ⊆ S[Y ], S[Y ] ⊆ T [Z] ` R[X] ⊆ T [Z]. KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.11 6.5 Übungsbeispiele Übung 6.1 F = {AB → C, B → D, CD → E, CE → GH, G → A} • Berechnen Sie AB + . • Gilt AB → E ? • Gilt BG → C ? Übung 6.2 Gegeben ist die Relation r(R): r (A a1 a1 a2 a2 a3 B b1 b2 b1 b1 b2 C c1 c2 c3 c4 c5 D d1 d2 d3 d3 d1 E) e1 e1 e1 e1 e1 Geben Sie an, welche der folgenden Abhängigkeiten r erfüllt: 1. A → D 2. AB → D 3. C → BDE 4. E → A 5. A → E 6. A → BC Übung 6.3 F = {AB → C, DE → AB, A → D, B → E, DE → C, AD → G} Geben Sie F in kanonischer Darstellung an. 1. (AB)+ = ? 2. (DE)+ = ? 3. Gilt AB ≡ DE ? 4. Gilt AB → CDG ? 5. Ist DE → C in F redundant? (Warum? Warum nicht?) KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.12 6. Ist D in AD → G überflüssig? (Warum? Warum nicht?) Geben Sie eine minimale Überdeckung von F an. Übung 6.4 F = {AB → CD, D → E, EC → G, AH → GI, AB → E} 1. Geben Sie F in kanonischer Darstellung an. 2. Berechnen Sie (AB)+ . 3. Ist AB → E in F redundant? (Warum? Warum nicht?) Übung 6.5 Berechnen Sie die Hüllen der linken Seiten von FDs aus F : F = {A → D, AB → DE, CE → G, E → AH}. Berechnen Sie weiters (AC)+ , (BC)+ und (AE)+ . Übung 6.6 Sind folgende Mengen von funktionalen Abhängigkeiten äquivalent? F = {A → BDGH, B → AC, C → DE, D → CGH, H → G} G = {A → B, B → AC, C → D, D → CEH, H → G} Übung 6.7 Sind I bzw. I 0 Überdeckungen bzw. nicht redundante Überdeckungen von H? H = {AB → C, A → B, B → C, A → C} I = {AB → C, A → B, B → C} I 0 = {A → B, B → C} Übung 6.8 Streichen Sie redundante FDs aus Fi : F1 F2 F3 F4 F5 = {A → BC, B → C} = {A → BD, B → C, C → D} = {AB → CD, D → E, EC → G, AH → GI, AB → E} = {AB → CDEF, AC → B, AD → B} = {A → BCGH, BC → EGH, B → E, G → H, BE → DH} Übung 6.9 Erzeugen Sie eine minimale Überdeckung Gi für: F1 F2 F3 F4 F5 F6 = {A → BC, B → C, AB → D} = {A → BCE, AB → DE, BI → J} = {A → BCGH, BC → EGH, G → H, BE → DH} = {A → C, AB → C, C → DI, CD → I} = {CD → BE, CB → I, BE → I, CB → E} = {AB → CD, B → D, CD → A, C → E, EC → AB} Übung 6.10 Gegeben ist die Menge der funktionalen Abhängigkeiten F = {AB → C, C → E, EC → D, HE → ABE, AB → D}. KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.13 1. Geben Sie F in kanonischer Darstellung an. 2. Berechnen Sie (AB)+ . 3. Ist AB → D in F redundant? (Warum? Warum nicht?) Übung 6.11 Gegeben sind die Relationen r(ABCE) und s(ABCF ). Angenommen, r erfüllt die FD A → B und s erfüllt die FD B → C, gilt dann im allgemeinen: 1. r ./ s erfüllt A → B ? 2. r ./ s erfüllt B → C ? 3. r ./ s erfüllt A → C ? 4. πAC (r) × πBE (r) erfüllt A → B ? 5. πAB (r) ∪ πAB (s) erfüllt A → B ? 6. πAB (r) ∩ πAB (s) erfüllt A → B ? Übung 6.12 Es seien p, q und r Instanzen von Relationenschemata P, Q und R, die bestimmte funktionelle Abhängigkeiten erfüllen. Bestimmen Sie, ob auf den folgenden abgeleiteten Relationen die angeführten funktionellen Abhängigkeiten sicher gelten: 1. p(ABCDE), q(BCDF ), p |= A → B, q |= BC → D; Gilt p ./ q |= A → D ? 2. p(ABCD),q(ABCD), p |= A → BC, q |= A → C; Gilt p ∪ q |= A → C ? 3. p(ABCDE), q(ABCDF ), p |= A → CD, q |= CA → D; Gilt p n q |= AC → D ? 4. p(ABCD), q(ABCD), p |= A → B, q |= A → C, q |= CD → B; Gilt p ∩ q |= AD → B ? 5. p(ABCDE), q(DE), p |= ABE → C, q |= D → E; Gilt p ÷ q |= AB → C ? 6. p(ABC), q(CD), p |= A → C, q |= D → C; Gilt σB=5 p ./ q |= AD → B KAPITEL 6. FUNKTIONALE ABHÄNGIGKEITEN 6.14 7. p(ABCD), q(AB), r(CD), p |= A → BD, q |= A → B, r |= C → D; Gilt p − (q × r) |= A → BD ? Übung 6.13 Gegeben seien R = {ABC} und F = {A → B, B → C}. Bestimmen Sie durch Anwendung der Armstrongaxiome alle nichttrivialen von F implizierten funktionalen Abhängigkeiten (Darstellung in kanonischer Form). Übung 6.14 Gegeben ist F = {X → Y, XZ → Y, Y → V W, Y V → W }. Geben Sie eine minimale Überdeckung G für F an. Übung 6.15 Gegeben ist F = {A → BC, AD → E, CD → E, E → AC}. Geben Sie eine minimale Überdeckung G für F an. Übung 6.16 Gegeben ist ein Relationenschema R und eine Menge von funktionalen Abängigkeiten F. Gegeben sind außerdem Attributmengen X und Y , wobei X ⊆ R, Y ⊆ R. X sei ein Schlüssel unter F und Y ∪ X = ∅. Welche der folgenden Aussagen ist richtig, falsch bzw. kann sein (mit Begründung)? X+ = R Y+ = R X+ = F + X → Y ∈ F+ X →Y ∈F Kapitel 7 Normalformen Die Kriterien eines guten Datenbankentwurfs sind einerseits möglichst geringe Redundanz, andererseits die Vermeidung von Einfüge-, Lösch- und Änderungsanomalien. Um Redundanzen und Anomalien zu vermeiden, führen wir den Begriff der Normalformen für Datenbankschemata ein. Eine Normalform ist eine Einschränkung auf dem Datenbankschema, die uns hilft, unerwünschte Eigenschaften der Datenbank zu verhindern. Ziel der Normalisierung ist ein Entwurf, der mindestens die Dritte Normalform (3NF) erfüllt. Erste und Zweite Normalform sind nur ein Zwischenschritt in dieser Entwicklung, sie helfen jedoch beim Verständnis der schrittweisen Verbesserung des Entwurfs. 7.1 Erste und Zweite Normalform Ein Relationenschema R ist in 1. Normalform (1NF), wenn die Wertebereiche aller Attribute von R atomar sind. 1NF ⇔ Wertebereiche atomar Ob ein Wertebereich atomar ist oder nicht, ist allerdings nicht immer ganz einfach zu sagen. Beispiel 7.1 Wenn wir das Schema Mitarbeiter(svnr, nname, vname, adresse, geburt) betrachten und das Geburtsdatum immer nur als ganzen Wert verwenden, ist das Schema in 1. Normalform. Sobald wir aber nur auf Teile des Datums zugreifen wollen, ist es nicht mehr in 1. Normalform. Angenommen wir wollen das Attribut sternzeichen hinzufügen, so erhalten wir die FD geburt → sternzeichen, die es erlaubt, dass Personen, die am selben Tag in verschiedenen Jahren geboren sind, ein unterschiedliches Sternzeichen haben. Spalten wir den Datumswert in drei Attribute tag, monat und jahr auf, so können wir die gewünschte FD mit tag, monat → sternzeichen angeben. Die 1. Normalform genügt aber nicht, um die oben angegebenen Entwurfskriterien zu erfüllen. Um Redundanzen und Datenanomalien zu vermeiden, benötigen wir die 2. und 3. Normalform. 1 KAPITEL 7. NORMALFORMEN 7.2 Beispiel 7.2 Für die Verwaltung der Getränke in R EINE müssen wir wissen, welche Getränke wo gelagert sind, um sie bei einer Bestellung aus einem geeigneten Lager heranzuschaffen. Diese Informationen gewinnen wir aus den Relationenschemata Getränke(gnr, name,hersteller) und Lager(gnr, lnr, menge, adresse), wobei das erste die Informationen zu den Getränken, das zweite zum Lagerort der Getränke liefert. Betrachten wir folgende Relation für Lager: Lager gnr lnr menge 101 1 25 078 2 340 078 1 56 204 3 3000 adresse Wiener Straße 88, 2352 Gumpoldskirchen Lenz Moser-Str. 1, 3495 Rohrendorf bei Krems Wiener Straße 88, 2352 Gumpoldskirchen Billrothstr. 51, 1190 Wien Wie wir leicht erkennen können, ist die Relation in erster Normalform. Angenommen, wir verändern die Lageradresse in der ersten Zeile. Die Redundanz in dieser Spalte bewirkt eine Anomalie nach Adressänderung, da nun das Lager mit der Nummer 1 zwei unterschiedliche Adressen hat. Lager gnr lnr menge 101 1 25 078 2 340 078 1 56 204 3 3000 adresse Neustiftg 51, 2352 Gumpoldskirchen Lenz Moser-Str. 1, 3495 Rohrendorf bei Krems Wiener Straße 88, 2352 Gumpoldskirchen Billrothstr. 51, 1190 Wien Oder wir löschen das Getränk mit gnr = 204 aus dem Lager 3. Dadurch geht uns die ganze Zeile verloren, unter anderem auch die Information über die Adresse dieses Lagers. Lager gnr lnr menge 101 1 25 078 2 340 078 1 56 204 3 3000 adresse Wiener Straße 88, 2352 Gumpoldskirchen Lenz Moser-Str. 1, 3495 Rohrendorf bei Krems Wiener Straße 88, 2352 Gumpoldskirchen Billrothstr. 51, 1190 Wien Diese Anomalien können behoben werden, wenn wir das Schema in zwei Schemata unterteilen, nämlich in Vorrat(gnr, lnr, menge) und Lager(lnr, adresse). Formal gesehen kommen wir auf die neue Einteilung, wenn wir die funktionalen Abhängigkeiten betrachten, die auf dem ursprünglichen Schema gelten: gnr, lnr → menge und lnr → adresse. Wenn wir die Definition der 2. Normalform betrachten, so werden wir sehen, dass die 2. Normalform durch diese Aufteilung des Schemas in zwei Subschemata erfüllt ist. Dazu benötigen wir jedoch erst folgende Definition: KAPITEL 7. NORMALFORMEN 7.3 Definition 7.1 Ein Attribut A heißt prim in einem Relationenschema R, wenn es in mindestens einem Schlüssel von R enthalten ist, nichtprim, wenn es in keinem Schlüssel enthalten ist. Formal: A ist prim ⇔ ∃X : X ist Schlüssel ∧ A ∈ X Definition 7.2 Ein Relationenschema R in 1NF ist in 2. Normalform (2NF), genau dann wenn für alle nichttrivialen funktionalen Abhängigkeiten X → A auf R gilt: entweder ist X keine echte Teilmenge eines Schlüssels oder A ist ein primes Attribut. Formal: 2NF ⇔ X → A ⇒ (A ∈ X ∨ X 6⊂ K, K ein Schlüssel von R ∨ A prim ). Beispiel 7.3 Die primen Attribute der ursprünglichen Relation Lager sind gnr und lnr. Die funktionale Abhängigkeit gnr, lnr → menge verletzt die 2NF nicht, lnr → adresse jedoch schon, da lnr ein Teilschlüssel ist. Daher müssen wir durch Aufteilung des Schemas Lager in zwei Subschemata Vorrat und Lager die 2NF wieder herstellen. Vorrat gnr lnr 101 1 078 2 078 1 204 3 menge 25 340 56 3000 Lager lnr adresse 1 Wiener Straße 88, 2352 Gumpoldskirchen 2 Lenz Moser-Str. 1, 3495 Rohrendorf bei Krems 3 Billrothstr. 51, 1190 Wien Bei der Verlegung von Lager 1 auf eine neue Adresse haben wir nun keine Probleme mehr, die Adresse bleibt konsistent. Auch das Löschen von Getränk 204 aus Lager 3 bringt keine Schwierigkeiten mit sich. Wie das Beispiel im nächsten Abschnitt zeigt, reicht die 2. Normalform jedoch nicht, um Anomalien auszuschließen und ist deshalb nur von historischem Interesse. 7.2 Die Dritte Normalform Beispiel 7.4 Betrachten wir ein Relationenschema, das festlegt, für welchen Händler und in welchem Lager die Lagerarbeiter arbeiten: Einsatz(svnr, lnr, firma). Wenn wir annehmen, dass jedes Lager genau einem Händler zugeordnet ist, bekommen wir die folgende Menge funktionaler Abhängigkeiten: F = {svnr → lnr firma, lnr → firma} Die Relation ist in 2. Normalform, denn der Schlüssel der Relation ist svnr. Die Attribute lnr und firma sind beide nichtprim, da sie keine Schlüsselattribute sind. KAPITEL 7. NORMALFORMEN 7.4 Einsatz svnr lnr 2435020466 1 8450720768 2 5467151171 3 9876020170 2 firma Weinbauer G. Grill Weinkellerei Lenz Moser Kattus Johann GmbH, Hochriegl Sekt Weinkellerei Lenz Moser Wollen wir das Lager 2 einem anderen Händler zuweisen oder den Angestellten 2435020466 entfernen, so erhalten wir dieselben Anomalien wie im vorigen Abschnitt. Einsatz svnr lnr 2435020466 1 8450720768 2 5467151171 3 9876020170 2 firma Weinbauer G. Grill Weingut-Kellerei Müllner Johann Kattus Johann GmbH, Hochriegl Sekt Weinkellerei Lenz Moser Auch hier hilft wieder die Zerlegung in zwei Relationen um die Anomalien zu vermeiden. Einsatz svnr lnr 2435020466 1 8450720768 2 5467151171 3 9876020170 2 Firma lnr firma 1 Weinbauer G. Grill 2 Weinkellerei Lenz Moser 3 Kattus Johann GmbH, Hochriegl Sekt Definition 7.3 Ein Relationenschema R in 1NF ist in 3. Normalform (3NF), wenn für alle nichttrivialen funktionalen Abhängigkeiten X → A auf R gilt: entweder ist X ein Oberschlüssel, oder A ist ein primes Attribut. Formal: 3NF ⇔ X → A ⇒ (A ∈ X ∨ X → R ∨ A prim). Äquivalent zu dieser Definition ist auch die folgende Charakterisierung: Theorem 7.1 Ein Relationenschema R in 1NF ist in 3. Normalform genau dann, wenn kein nichtprimes Attribut von einem Schlüssel in R transitiv abhängt (i.e. aufgrund der Transitivitätsregel aus einem Schlüssel ableitbar ist). Formal: 3NF ⇔ (A nichtprim ⇒ Schlüssel → A nicht transitiv). Zwischen den einzelnen Normalformen gilt die folgende Beziehung: 3N F ⇒ 2N F ⇒ 1N F KAPITEL 7. NORMALFORMEN 7.5 7.3 Die Boyce-Codd Normalform Die strengste Normalform ist die Boyce-Codd-Normalform. Definition 7.4 Ein Relationenschema R in 1NF ist in Boyce-Codd Normalform (BCNF) genau dann, wenn für alle nichttrivialen funktionalen Abhängigkeiten X → A auf R gilt: X ist ein Oberschlüssel. Formal: BCN F ⇔ X → A ⇒ (A ∈ X ∨ X → R). Äquivalent zu dieser Definition ist auch die folgende Charakterisierung: Theorem 7.2 Ein Relationenschema R in 1NF ist in Boyce-Codd Normalform genau dann, wenn kein Attribut transitiv von einem Schlüssel abhängt. BCN F ⇔ X → A ⇒ X → R ∨ A ∈ X Beispiel 7.5 Betrachten wir das Relationenschema R(übung, student, tutor) mit der Menge funktionaler Abhängigkeiten F = {student, übung → tutor, tutor → übung}, die besagen, dass ein Student bei einer Übung genau einem Tutor zugeordnet ist und dass ein Tutor genau einer Übung zugeordnet ist. Die Abhängigkeit tutor → übung verletzt die BCNF (aber nicht die 3NF). Wenn wir das Schema R zerlegen in R1 = (student, tutor) und R2 = (tutor, übung), so haben wir zwei neue Schemata R1 , R2 , die in BCNF sind. Die BCNF hat als einzige Normalform folgende Eigenschaft: Theorem 7.3 Ein Schema ist in BCNF ⇔ das Schema ist redundanzfrei (bez üglich der vorgestellten Redundanzen). Das bedeutet, dass keine Art von Anomalien beim Löschen oder Updaten auftritt. In der Praxis ist dennoch die 3NF wesentlich weiter verbreitet, da nur in der 3NF eine verbund- und abhängigkeitstreue Zerlegung (siehe Abschnitt 7.4) möglich ist. 7.4 Zerlegungen von Relationenschemata Wie wir gesehen haben, kommt es beim Datenbankentwurf darauf an, die Relationenschemata in Normalform zu bringen, um ungewünschte Nebeneffekte zu vermeiden. Dazu ist es notwendig, ein Relationenschema R nach seinen funktionalen Abhängigkeiten zu zerlegen. Bis jetzt haben wir diese Zerlegung immer intuitiv vorgenommen. Im Allgemeinen ist es allerdings nicht so einfach. In diesem Abschnitt wird die dazu nötige Theorie vorgestellt. Im Folgenden wollen wir annehmen, dass ein Relationenschema R ein Paar (S, F ) ist mit den Komponenten KAPITEL 7. NORMALFORMEN 7.6 • S: eine Menge von Attributen • F : eine Menge funktionaler Abhängigkeiten über S. Definition 7.5 Ein Relationales Datenbankschema R ist eine Menge von Relationenschemata: R = {R1 , R2 , . . . , Rn }. Dieses Datenbankschema R ist in 3NF bzw. BCNF, wenn jedes Relationenschema in R in 3NF bzw. BCNF ist. Sei R = (S, F ) ein Relationenschema und R1 = (S1 , F1 ) ein Relationenschema, das über den Attributen S1 ⊆ S definiert ist. Um erkennen zu können, welche FDs auf dem Schema R1 gelten, führen wir das Konzept der eingebetteten FDs ein: Definition 7.6 Eine FD X → Y ∈ F ist eingebettet in S1 , wenn XY ⊆ S1 1 . Die Menge aller in S1 eingebetteten FDs bezeichnen wir mit F [S1 ]. F [S1 ] = {X → Y ∈ F | XY ⊆ S1 }. Intuitiv bedeutet dies, dass wir die Menge aller funktionalen Abhängigkeiten betrachten, deren Attribute in der Teilmenge S1 vorkommen, wir projizieren sozusagen auf die Attribute von S1 . Beispiel 7.6 Betrachten wir nochmals das Relationenschema aus Beispiel 7.5. R = (S, F ) wobei S = {übung, student, tutor} und F = {student, übung → tutor, tutor → übung}. Betrachten wir S1 = {übung, tutor}, so ist die Menge der darin eingebetteten Abhängigkeiten F [S1 ] = {tutor → übung}. Für S2 = {student, tutor} ist F [S2 ] = {}, da es keine funktionale Abhängigkeit gibt, an der nur diese beiden Attribute beteiligt sind. Definition 7.7 Eine Zerlegung eines Relationenschemas R = (S, F ) ist eine Menge von Relationenschemata {R1 = (S1 , F1 ), R2 = (S2 , F2 ), . . . , Rn = (Sn , Fn )}, wobei folgendes gilt: 1. S = S1 ∪ S2 ∪ . . . ∪ Sn 2. Fi ≡ F + [Si ] 3. (F1 ∪ F2 ∪ . . . ∪ Fn )+ ⊆ F + . F + [Si ] ist nach der Definition von eingebetteten Abhängigkeiten die Menge aller funktionalen Abhängigkeiten aus F + , deren Attribute auf der linken und der rechten Seite im Subschema S1 enthalten sind, formal: F + [S1 ] = {X → Y ∈ F + | XY ⊆ S1 }. 1 Die Vereinigung von Attributmengen wird im Allgemeinen ohne das Vereinigungszeichen geschrieben. d.h. XY entspricht X ∪ Y KAPITEL 7. NORMALFORMEN 7.7 Definition 7.8 Eine Zerlegung ist abhängigkeitstreu (dependency preserving, keine Abhängigkeit geht verloren), wenn: (F1 ∪ F2 ∪ . . . ∪ Fn )+ = F + Die Zerlegung ist verbundtreu (verlustfrei, lossless), wenn für jede Relation r(S) gilt: r(S1 ) ./ r(S2 ) ./ . . . ./ r(Sn ) = r(S) Beispiel 7.7 Die Zerlegung in Beispiel 7.5 ist verbundtreu, aber nicht abhängigkeitstreu: die Abhängigkeit student, übung → tutor geht verloren, d.h., wir können den Umstand, dass es für jeden Studenten in einer Übung genau einen Tutor gibt, nicht mehr modellieren. Bei einer Zerlegung in BCNF ist es nicht immer möglich, eine verbund- und abhängigkeitstreue Zerlegung von R zu finden. In einem solchen Fall darf auf die Abhängigkeitstreue verzichtet werden, nicht jedoch auf die Verbundtreue. Die Abhängigkeitstreue stellt nämlich Metainformation dar, die Verbundtreue aber echte Information. Einer der größten Nachteile der BCNF gegenüber der 3NF ist, dass die Existenz einer Zerlegung mit beiden Eigenschaften nicht immer gegeben ist. Das Entscheidungsproblem, ob es eine abhängigkeitstreue (und verbundtreue) Zerlegung eines Datenbankschemas in BCNF gibt, ist NP-vollständig. Der Test, ob ein Datenbankschema in BCNF ist, hingegen ist polynomiell. Beispiel 7.8 Sei R(S, F ) das folgende Relationenschema R mit S = (ABC) und F = {A → B, C → B), und wir zerlegen R in R1 = ({AB}, A → B) und R2 = ({BC}, C → B). Für die erste der beiden nachfolgenden Instanzen erhalten wir eine verbundtreue Zerlegung, für die zweite nicht. r (A a a’ r (A a a’ ⇒ B C) b c b’ c’ ⇒ B b b C) c c’ r1 (A B) a b a’ b’ ./ r1 (A B) a b a’ b ./ r2 (B C) b c b’ c’ = r2 (B C) b c b c’ = r0 (A a a’ B b b’ r0 (A a a a’ a’ B b b b b C) c c’ C) c c’ c c’ Wie können wir eine verbundtreue Zerlegung sicherstellen? Aus dem Beispiel ist ersichtlich, dass die Instanzen des Attributes B für das unterschiedliche Verhalten ausschlaggebend sind. Im ersten Fall, in dem B als Schlüssel für R1 oder R2 in Frage kommt, ist die Zerlegung verlustfrei, im zweiten Fall nicht. Im Allgemeinen können wir feststellen, dass die Zerlegung verbundtreu ist, wenn das Join-Attribut in einer der beiden Teilrelationen Schlüssel ist. KAPITEL 7. NORMALFORMEN 7.8 Theorem 7.4 Eine Zerlegung von R = (S, F ) in {R S1n = (S1 , F1 ), R2 = (S2 , F2 ), . . . , Rn = 0 (Sn , Fn )} ist verbundtreu, wenn bezüglich F = i=1 Fi die Hülle eines der generierten Relationenschemata Si gleich S ist. S ∃Si | Si+ = S bzgl. F 0 = ni=1 Fi ⇒ Zerlegung von S in S1 , S2 , . . . , Sn ist verbundtreu. 7.4.1 Verbundtreue Zerlegung in 3NF bzw. BCNF Im Folgenden beschreiben wir ein Verfahren zur verbundtreuen Zerlegung in 3NF bzw. BCNF. Algorithmus DECOM P INPUT: Relationenschema R = (S, F ) OUTPUT: verbundtreue Zerlegung {R1 = (S1 , F1 ), . . . , Rn = (Sn , Fn )} von R in 3NF bzw. BCNF. METHODE (Prinzip): 1. Wir ersetzen F durch eine minimale Überdeckung, diese heiße weiterhin F . 2. Wir prüfen zunächst, ob F eine bösartige“ Abhängigkeit enthält, d.h., ” 3NF: eine Abhängigkeit der Form X → A, wobei X kein Schlüssel ist und A nichtprim ist. Eine solche Abhängigkeit würde die 3NF-Bedingung für R = (S, F ) verletzen. BCNF: eine Abhängigkeit der Form X → A, wobei X kein Schlüssel von R ist. Eine solche Abhängigkeit würde die BCNF-Bedingung für R = (S, F ) verletzen. Enthält F keine bösartige Abhängigkeit, dann ist R = (S, F ) bereits in 3NF bzw. in BCNF. Fertig. 3. Gibt es eine bösartige Abhängigkeit X → A in F , dann spalten wir R in zwei Teile R1 = (S1 , F1 ) und R2 = (S2 , F2 ) mit: S1 = S \ A und S2 = XA, wobei X der Schlüssel für die neue Relation R2 wird2 . 4. Wir berechnen nun Überdeckungen F1 und F2 für R1 und R2 , aus denen sich alle in R1 bzw. R2 gültigen funktionalen Abhängigkeiten ableiten lassen. D.h., wir berechnen 2 S und X sind Mengen von Attributen, A ist ein Element dieser Mengen. Wir vernachlässigen hier eine eigentlich notwendige Mengenklammerung S \ {A} und X ∪ {A}, da aus dem Kontext klar ist, was gemeint ist. KAPITEL 7. NORMALFORMEN 7.9 Abhängigkeitsmengen F1 und F2 über S1 bzw. S2 , für die gilt: F1 ≡ F + [S1 ] und F2 ≡ F + [S2 ]. (In Abschnitt 7.4.3 werden wir im Detail auf diese Problemstellung eingehen.) 5. Das Verfahren wird nun rekursiv auf R1 = (S1 , F1 ) und R2 = (S2 , F2 ) angewendet. 6. Die Menge aller Subschemata in 3NF bzw. BCNF, die im Laufe des Verfahrens erzeugt werden, ist eine Zerlegung in 3NF bzw. BCNF des ursprünglichen Schemas R. 7. Ist eine möglichst kleine Anzahl von Schemata erwünscht, so können wir folgende Optimierungen durchführen: • Ist ein Schema eine Teilmenge eines anderen Schemas, so lassen wir dieses “Teilschema” einfach weg, da sich sämtliche Attribute und Abhängigkeiten ja bereits im größeren Schema finden. • Weiters fassen wir sämtliche Schemata mit demselben Primärschlüssel zu einem Schema zusammen, soferne das entstehende Schema danach ebenfalls in 3NF ist. (Ein Gegenbeispiel hierzu sind AC und AD mit den FDs A → C, A → D, und C → D.) (Dies alleine führt nicht in allen möglichen Spezialfällen zu einem minimalen Schema, ist für unsere Zwecke aber ausreichend.) Das Verfahren terminiert immer, da die Kardinalität der erzeugten Schemata in jedem Schritt abnimmt. Schlimmstenfalls erhalten wir Schemata der Kardinalität 2 (also mit 2 Attributen); diese sind immer in 3NF bzw. BCNF. Es ist leicht zu sehen, dass diese Zerlegung verbundtreu ist. Jede Einzelzerlegung ist verbundtreu: aus S1 = S \ A und S2 = XA kann durch den Verbund R1 ./ R2 wieder R gewonnen werden, da X ein Schlüssel für R2 ist. Die Korrektheit des Verfahrens ist folglich gegeben, wenn Schritt 2 ( Überprüfung der Normalform) korrekt ist. Dafür müssten vorderhand alle Abhängigkeiten X → A ∈ F + und nicht nur in F überprüft werden. Es kann aber gezeigt werden, dass R = (S, F ) nicht in 3NF bzw. BCNF ist, genau dann wenn F eine bösartige Abhängigkeit enthält (wichtig: F ist eine minimale Überdeckung). Das schwierigste Teilproblem des Verfahrens besteht in der Berechnung von F 1 und F2 aus F und R1 bzw. R2 . Dieses Problem wird später gesondert behandelt (siehe Algorithmus RBR). Die während des Verfahrens entstehenden (bzw. verwendeten) Relationenschemata können als Baum mit Wurzel R = (S, F ) dargestellt werden. Die Blätter des Baumes sind die Bestandteile der Zerlegung (siehe auch das folgende Beispiel). Gibt es in einer Stufe mehrere bösartige Abhängigkeiten, dann kann das Verfahren – je nach Auswahl der bösartigen Abhängigkeit – zu verschiedenen Zerlegungen führen. KAPITEL 7. NORMALFORMEN 7.10 Im Fall von 3NF ist immer eine verbund- und abhängigkeitstreue Zerlegung möglich. Diese ist jedoch von der Reihenfolge der Eliminierung der bösartigen FDs abhängig. Im Beispiel 7.9 werden wir sehen, dass obiger Algorithmus im Gegensatz zum Synthesealgorithmus von Bernstein (siehe 7.4.4) nicht immer eine abhängigkeitstreue Zerlegung in 3NF liefert. Beispiel 7.9 ([Ullman, 1988 Bd. I]) Wir betrachten das Schema S = (C, T, H, R, S, G). Die Attribute haben folgende Bedeutung: C: Course H: Hour S: Student T: Teacher R: Room G: Grade Dazu betrachten wir die folgende Menge F von funktionalen Abhängigkeiten: C → T . . . jede Vorlesung hat höchstens einen Vortragenden. HR → C . . . in einem Hörsaal kann zu einem bestimmten Zeitpunkt nur höchstens eine Vorlesung stattfinden. HT → R . . . ein Vortragender kann zu einem bestimmten Zeitpunkt nur in höchstens einem Hörsaal unterrichten. CS → G . . . jeder Student hat zu jeder Vorlesung höchstens eine Note. HS → R . . . jeder Student kann sich zu einem bestimmten Zeitpunkt in höchstens einem Hörsaal aufhalten. Zuerst berechnen wir sämtliche Schlüssel des Schemas S, und stellen fest, dass HS den einzigen (minimalen) Schlüssel darstellt. Die einzige FD, die nicht böse ist, ist HS → R. Ein Zerlegungsbaum für R(S, F ) ist in Abbildung 7.1 angegeben. Jeder Knoten ist mit dem entsprechenden Teilschema von R, sowie mit den auf diesem Teilschema gültigen Abhängigkeiten markiert. Man beachte, dass diese Abhängigkeiten nicht ganz leicht zu finden sind: z.B. muss beim Übergang von CTHRS auf CHRS eine neue Abhängigkeit CH → R angegeben werden. Diese Abhängigkeit folgt zwar aus F , ist aber nicht Element von F . Sie entsteht durch Verschmelzung der Abhängigkeiten C → T und TH → R durch Anwendung der Pseudotransitivitätsregel. Auf dieses Problem wird im nächsten Abschnitt (Algorithmus RBR) eingegangen. Wir haben allerdings die funktionale Abhängigkeit TH → R verloren. Im Falle der BCNF können wir sagen, dass uns das egal ist, da wir nicht wissen, ob es eine abhängigkeitstreue Zerlegung gibt oder nicht (der Baum ist sowohl in BCNF als auch in 3NF), aber für die 3NF ist das kein akzeptables Ergebnis. KAPITEL 7. NORMALFORMEN 7.11 HSCTRG C->T CS->G HR->C TH->R HS->R CSG CS->G HSCTR C->T TH->R HR->C HS->R CT C->T HSCR CH->R HR->C HS->R CHR bzw. CHR CH->R HR->C HSC HS->C Abbildung 7.1: Verbundtreue Zerlegung von R(S, F ) aus Beispiel 7.9 in 3NF 7.4.2 Verbund- und abhängigkeitstreue Zerlegung in 3NF bzw. BCNF Eine Erweiterung des obigen Algorithmus zur verbundtreuen Zerlegung in 3NF erlaubt es, auch Abhängigkeitstreue zu erhalten. Hierzu zuerst einige Bemerkungen: Der obige Algorithmus ist so konstruiert, dass jedes Schema R2 bereits in 3. Normalform ist und daher eine weitere Zerlegung von R2 nicht notwendig ist. Wenn wir die FDs aus der minimalen Überdeckung F betrachten, die wir in Schritt 1 generiert haben, so können wir folgendes feststellen: • Ist X ein Schlüssel von R und eine FD X → Y kommt explizit in F vor, so ist eine Zerlegung, bei der jedes Subschema aus dem Abspalten einer funktionalen Abhängigkeit besteht, eine abhängigkeits- und verbundtreue Zerlegung. • Ist X ein Schlüssel von R und es gibt keine FD X → Y in F , so zerlegen wir R wie oben, indem wir aus jeder FD ein Subschema erzeugen und geben zum Schluss das Subschema hinzu, das nur aus X besteht. Wiederum erhalten wir eine verbund- und abhängigkeitstreue Zerlegung. Diese Zerlegung ist eine sehr naive Zerlegung, da wir aus jeder FD ein Subschema generieren und das im allgemeinen zu viele Subschemata ergibt. Aus Performancegründen ist es nicht sehr sinnvoll, in der Praxis so vorzugehen, da bei Abfragen die Anzahl der Joinoperationen, die die aufwendigsten Operationen sind, direkt von der Anzahl der Subschemata abhängig ist. KAPITEL 7. NORMALFORMEN 7.12 Dieser naive Algorithmus zeigt jedoch, dass wir uns im Grunde bei einer Zerlegung auf die FDs beschränken können, die wir in Schritt 1 erhalten haben. Ein problematischer Fall bei einer Zerlegung sind zyklische Abhängigkeiten, wie wir im Beispiel 7.9 gesehen haben: F = {C → T, TH → R, HR → C}. Um mit zyklischen Abhängigkeiten umgehen zu können, verwenden wir die folgende modifizierte Zerlegung: Definition 7.9 Eine Pseudo-Zerlegung nach einer FD X → Y ∈ F ist eine Zerlegung, bei der: R1 = (S1 , F1 ), R2 = (S2 , F2 ), mit S1 = S, F1 = F, S2 = XY, F2 ≡ F + [XY ]. Eine Pseudo-Zerlegung nach C → T ergibt nun die beiden Subschemata: S 1 = HSCTR und S2 = CT, wobei auf dem ersten Schema wieder alle vier FDs gelten. Wir modifizieren daher den ursprünglichen Algorithmus, indem wir auch Pseudozerlegungen durchführen. Weiters führen wir eine Variable G ein, die immer die Menge jener FDs enthält, die wir im jeweiligen Schritt noch “unterbringen” müssen – entweder in neu abzuspaltenden Relationen oder in der im rechten Teilbaum verbleibenden Relation. METHODE (Prinzip): 1. Wir ersetzen F durch eine minimale Überdeckung, diese heiße G. 2. Zerlege (echte Zerlegung oder Pseudo-Zerlegung) nur nach FDs aus G. Ist die Zerlegung G-erhaltend, so führen wir eine echte Zerlegung durch (wo R tatsächlich reduziert wird), andernfalls führen wir eine Pseudo-Zerlegung durch. Dabei bezeichnen wir eine Zerlegung R1 = (S1 , F1 ), R2 = (S2 , F2 ) als G-erhaltend, wenn für jede FD X → Y ∈ G gilt XY ⊆ S1 oder XY ⊆ S2 . 3. Entferne bei jeder Zerlegung bzw. Pseudo-Zerlegung alle FDs W → Z aus G, für die WZ ⊆ S2 gilt, gib R2 aus. Sind etwa die beiden FDs AB → C und C → A in G enthalten, so entfernen wir nach einer Pseudozerlegung nach AB → C beide dieser FDs aus G. 4. Das Verfahren wird nun rekursiv angewendet. Setze R := R1 und führe die Zerlegung auf R fort. Abbruchbedingungen: • R hat keine bösartigen Abhängigkeiten mehr, d.h., R ist in 3NF: Gib R aus. • G = {}: Wenn R nicht in 3NF ist, so gib R0 = (S 0 , F 0 ) aus, sodass S 0 ein Schlüssel für R ist und F 0 ≡ F + [S 0 ]. 5. Die Menge aller Subschemata in 3NF bzw. BCNF, die im Laufe des Verfahrens erzeugt werden, ist eine Zerlegung in 3NF bzw. BCNF des ursprünglichen Schemas R. KAPITEL 7. NORMALFORMEN 7.13 6. Ist eine möglichst kleine Anzahl von Schemata gefordert, so gehen wir wie unter 7.4.1 beschrieben vor. Um generell so wenige Subschemata wie möglich zu erhalten, können wir nach der folgenden Heuristik vorgehen: Heuristik: Zerlege nach bösartigen FDs vor gutartigen und nach G-erhaltenden vor nicht G-erhaltenden. Wenden wir nun den modifizierten Algorithmus an, der eine verbund- und abhängigkeitstreue Zerlegung von F aus Beispiel 7.9 liefert. Beispiel 7.9 (Fortsetzung): G := {C → T, HR → C, HT → R, CS → G, HS → R} Bis auf HS → R sind alle FDs bösartig, die einzige G-erhaltende Zerlegung ist die Zerlegung nach CS → G. D.h., G := C → T, HR → C, HT → R, HS → R, wir geben CSG aus. Da im nächsten Schritt keine Zerlegung nach einer der drei bösartigen FDs in G (C → T, TH → R und HR → C) G-erhaltend ist, und R noch nicht in 3NF ist, müssen wir eine PseudoZerlegung durchführen. Wir wählen TH → R aus und zerlegen: S 1 = S = HSCTR und S2 = THR, F1 = F und F2 = {TH → R}; wir setzen G := C → T, HR → C, HS → R und geben THR aus. Im nächsten Schritt zerlegen wir nach C → T (bösartig und G-erhaltend) in CT bzw. HSRC mit den dazugehörigen FDs; wir setzen G := HR → C, HS → R und geben CT aus. Im letzten Schritt zerlegen wir HSRC nach HR → C (bösartig und G-erhaltend) in HRC bzw. HSR mit den dazugehörigen FDs und setzen G := HS → R und geben HRC aus. R ist nun in 3NF, da es keine bösartigen FDs mehr gibt, und wir geben R aus. Abbildung 7.2 zeigt den entsprechenden Zerlegungsbaum. Wie wir sehen, ist die erhaltene Zerlegung verbund- und abhängigkeitstreu. 7.4.3 Berechnung von Überdeckungen für eingebettete Abhängigkeiten Wir suchen nun einen Algorithmus, der uns aus einem Subschema S 1 von S zu den auf S gültigen funktionalen Abhängigkeiten F eine Überdeckung F1 findet, sodass F1 alle auf S1 gültigen Abhängigkeiten repräsentiert. Dabei nehmen wir an, dass F minimal ist. Formal ausgedrückt bedeutet dies: Finde F1 mit F1+ = F + [S1 ]. Die triviale Lösung dieses Problems besteht in F1 = F + [S1 ]. Sie ist aber in doppelter Hinsicht schlecht: 1. Es muss die gesamte Menge F + aller aus F folgenden Abhängigkeiten berechnet (z.B. mittels der Armstrong Axiome) und dann auf S1 projiziert werden ⇒ großer Aufwand (exponentiell in der Anzahl der Attribute). KAPITEL 7. NORMALFORMEN 7.14 HSCTRG C->T CS->G HR->C TH->R HS->R G:={C->T,CS->G,HR->C,TH->R,HS->R} CSG CS->G G:={C->T,HR->C,TH->R,HS->R} HSCTR C->T TH->R HR->C HS->R THR TH->R G:={C->T,HR->C,HS->R} HSCTR C->T TH->R HR->C HS->R CT C->T HSCR CH->R HR->C,HS->R CHR CH->R HR->C HSR HS->R G:={HR->C,HS->R} G:={HS->R} Abbildung 7.2: Verbund- und abhängigkeitstreue Zerlegung von R(S, F ) aus Beispiel 7.9 2. Die Überdeckung F + [S] ist von maximaler Größe und braucht daher viel Speicherplatz (unhandlich). Eine bessere Methode ist die im Folgenden beschriebene. Definition 7.10 Sei f eine Abhängigkeit der Form XAY → Z, wobei X und Y möglicherweise leere Attributmengen darstellen, A ein Attribut, und sei g eine Abhängigkeit der Form V → A. Die aus f und g ableitbare Abhängigkeit h : XVY → Z nennen wir die A-Resolvente von f und g. Jede A-Resolvente von f und g folgt aus {f, g} durch Pseudotransitivität. Beispiel 7.10 Die beiden Abhängigkeiten C → T und TH → R haben als T-Resolvente CH → R. Daher kommt CH → R bei der Zerlegung in Beispiel 7.9 als zusätzliche Abhängigkeit in das Subschema. Definition 7.11 Die Menge aller nichttrivialen A-Resolventen, die unmittelbar (in einem Schritt) aus F erzeugt werden können, bezeichnen wir mit RES(F, A). Mit nichttrivial bezeichnen wir hier jene Abhängigkeiten der Form V → A, für die A in V nicht vorkommt. KAPITEL 7. NORMALFORMEN 7.15 7.4.3.1 Der Algorithmus RBR (Reduction By Resolution) [Gottlob, 1987] (modifizierte Version) Algorithmus RBR INPUT: Schema R = (S, F ), S1 ⊂ S OUTPUT: Überdeckung F1 mit F1+ = F + [S1 ] begin F1 := kanonisch(F ); X := S \ S1 ; while X 6= {} do begin wähle ein Attribut A aus X; X := X \ A; F1 := (F1 ∪ RES(F1 , A)); entferne alle Abhängigkeiten aus F1 , die A enthalten; end; return F1 ; end. Beispiel 7.11 Als Beispiel betrachten wir die dritte Zerlegung aus Beispiel 7.9. INPUT R = ({HSCRT}, {C → T, TH → R, HR → C, HS → R}), S1 = {HSCR}. begin F1 := F ; da F bereits in kanonischer Darstellung X := {T}; while X 6= {} do begin wähle T aus X; X := {}; F1 := (F1 ∪ {CH → R}); \ ∗ F1 = {CH → R, HR → C, HS → R} ∗ \ end; return F1 := {CH → R, HR → C, HS → R}; end. 7.4.4 Der Synthesealgorithmus Der Synthesealgorithmus von [Bernstein, 1976] findet zu jedem gegebenen Relationenschema R = (S, F ) eine verbund- und abhängigkeitstreue Zerlegung in 3NF. Er ist damit eine Alternative zu jenem Verfahren, das wir in Abschnitt 7.4.2 vorgestellt haben. KAPITEL 7. NORMALFORMEN 7.16 1. Bilde eine minimale Überdeckung von F . 2. Wenn F keine Abhängigkeit mit einem Schlüssel für R auf der linken Seite enthält, so finde einen Schlüssel (genannt K) und führe eine Abhängigkeit K → S ein. 3. Bilde Gruppen von Abhängigkeiten. Abhängigkeiten mit gleichen linken Seiten kommen in die gleiche Gruppe. 4. Vereinige zwei Gruppen von Abhängigkeiten mit den linken Seiten X i und Xj , wenn Xi ≡ X j . 5. Bilde für jede Gruppe eine ringförmige zusammengesetzte funktionale Abhängigkeit (annular compound FD, ACFD), wie folgt: Die Abhängigkeiten in einer Gruppe haben die Form: X1 → Y1 , X2 → Y2 , . . . , Xn → Y n . Bilde daraus: X1 → X2 , X2 → X3 , . . . , Xn → X1 , X1 → Y (wobei Y = Y1 ∪ . . . ∪ Yn ). Abgekürzte Schreibweise: (X1 , . . . , Xn ) → Y . X1 Y Xn X2 ... Die Vereinigung all dieser ACFDs G ist eine Überdeckung für F und wird als ringförmige Überdeckung (annular cover) bezeichnet. 6. Reduziere G, d.h., verschiebe verschiebbare Attribute und eliminiere überflüssige Attribute. Ein Attribut heißt verschiebbar (shiftable), wenn es in einer ACFD von einem X i nach Y verschoben werden kann und G äquivalent zu F bleibt. Ein Attribut heißt überflüssig (extraneous), wenn es von Y gestrichen werden kann und G äquivalent zu F bleibt. 7. Die Zerlegung von R = (S, F ) besteht aus jenen Relationen und Abhängigkeiten, die durch die einzelnen ACFDs in G beschrieben werden. Falls unter Punkt 2 die Abhängigkeit K → S eingefügt wurde, ergänze mit der Relation R(K).3 Beispiel 7.12 Wollen wir das Beispiel 7.9 mit dem Synthesealgorithmus lösen, so werden wir sehen, dass sich die einzelnen FDs nicht in ACFDs zusammenfassen lassen. Wir können daher auch nicht reduzieren und erhalten für jede FD ein eigenes Schema. Dies ist dasselbe Ergebnis, das wir auch im Zerlegungsalgorithmus schon erhalten haben. 3 Eine genaue Erklärung dieses Algorithmus und Beispiele dazu stehen in [Maier, 1983] KAPITEL 7. NORMALFORMEN 7.17 7.5 Übungsbeispiele Übung 7.1 Erklären Sie kurz und präzise die Motive, ein relationales Datenbankschema in 3. Normalform zu bringen. Welche Vorteile erhoffen wir uns dadurch? Welche Probleme sollen dadurch vermieden werden? Geben Sie für jedes angeführte Motiv je ein Beispiel, das nicht der Vorlesung entnommen wurde, an. Übung 7.2 Gegeben ist R = {MATRNR, NAME, GEBDAT, ALTER, DA BETREUER, INSTITUT, SEMESTER, LVA, NOTE } mit dem Schlüssel {MATRNR SEMESTER LVA} und den funktionalen Abhängigkeiten MATRNR → NAME GEBDAT ALTER DA BETREUER INSTITUT GEBDAT → ALTER DA BETREUER →INSTITUT Suche eine Zerlegung von R in 3NF. Übung 7.3 Befinden sich 1. R1 = {A, B, C, D} bzgl. F1 = {A → BCD, B → D, C → D} 2. R2 = {A, B, C} bzgl. F2 = {AB → C, C → B} in 2NF, 3NF, BCNF ? (Begründung!) Falls sich R1 , R2 nicht in BCNF befinden, geben Sie eine verlustfreie Zerlegung in BCNF für die jeweilige Relation an. Übung 7.4 Befindet sich das Relationenschema R1 = ABCD und R2 = BEF mit den funktionalen Abhängigkeiten A → D, B → E, BA → C, E → F 1. in 2NF ? (Begründung!) 2. in 3NF ? (Begründung!) Geben Sie eine verlustfreie Zerlegung in BCNF an. Übung 7.5 Gegeben sind ein Relationenschema R und eine Menge von FDs F . R = ABCDEG F = {ABC → D, B → E, B → G} In welcher Normalform ist R? Geben Sie eine abhängigkeitstreue und verbundtreue Zerlegung von R in 3NF an (mit möglichst wenig Relationen). KAPITEL 7. NORMALFORMEN 7.18 Übung 7.6 Gegeben sind ein Relationenschema R und eine Menge von FDs F . R = ABCDE F = {AB → CD, D → E} In welcher Normalform ist R? Geben Sie eine abhängigkeitstreue und verbundtreue Zerlegung von R in 3NF an. Übung 7.7 Beweisen Sie: BCNF =⇒ 3NF =⇒ 2NF Übung 7.8 Sei R ein Relationenschema und F eine Menge von FDs. Sei weiters G eine minimale Überdeckung von F . Zeigen Sie: • R ist in 3NF bzgl. F ⇐⇒ für jede FD X → A ∈ G gilt: X ist Schlüssel von R bzgl. F , oder A ist prim. • R ist in BCNF bzgl. F ⇐⇒ für jede FD X → A ∈ G gilt: X ist Schlüssel von R bzgl. F. Untersuchen Sie: Benötigt man die Minimalität von G? Übung 7.9 Beweisen Sie, dass der Zerlegungsalgorithmus DECOM P korrekt ist, und eine verbundtreue Zerlegung in 3NF bzw. BCNF liefert. Beweisen Sie auch, dass die Erweiterung von DECOM P um Pseudo-Zerlegung wie beschrieben eine verbund- und abhängigkeitstreue Zerlegung in 3NF liefert. Übung 7.10 Beantworten Sie Punkt 1) bis Punkt 3) für die nachfolgenden Angaben: 1. Geben Sie alle möglichen Schlüssel für R an. 2. In welchen Normalformen ist R ? (mit Begründung!) 3. Geben Sie eine abhängigkeitstreue und verbundtreue Zerlegung von R in 3NF an (mit möglichst wenig Relationen), sofern R nicht in 3NF ist. Gegeben sind das Relationenschema R und die Abhängigkeiten F : 1. R = GHIJKL, F = {GH → I, GH → J, I → K, → L, I → J} 2. R = ABCDGH, F = {AB → CD, B → G, G → H} 3. R = ABCDEG, F = {AB → CD, D → E, D → G} 4. R = ABCD, F = {A → D, B → A, B → C, C → D, A → B} KAPITEL 7. NORMALFORMEN 5. R = ABCDEF, F = {AB → CD, C → E, D → F, A → B} 6. R = ABCDEF, F = {A → B, F → A, C → D} 7. R = ABCDEF, F = {AF → AB, AC → D} 8. R = ABCDEF, F = {ABD → E, E → ABCD} 9. R = ABCDEF, F = {F → E, D → F C, E → B, B → A} 10. R = ABCDEF, F = {AB → C, ABC → DEF, EF → B} 11. R = ABCDEF, F = {ABC → DEF, E → E, E → F } 12. R = ABCDEF, F = {AB → CD, E → F } 13. R = ABCDEF, F = {CD → AE, A → F, AF → B} 14. R = ABCDEF, F = {D → C, E → AF, A → D, F → E} 15. R = ABCDE, F = {ABC → D, ABCD → E} 16. R = ABCDE, F = {ABC → D, ABCD → E, CD → E} 17. R = ABCDE, F = {A → B} 18. R = ABCDE, F = {A → BC, E → D} 19. R = ABCDE, F = {E → CD, C → B} 20. R = ABCDEF, F = {EF → A, A → E, A → F, F → E, A → D} 21. R = ABCDEF, F = {AB → CD, AB → E, E → F } Übung 7.11 Gegeben: U = {A1 , . . . , A7 } F = {A1 → A2 , A1 → A3 , A2 A3 → A1 , A3 → A4 , A4 → A 5 , A5 → A 6 , A5 → A 7 , A7 → A 4 } R = {A4 , A5 } Gesucht: G, sodass G+ = F + [R] (mit Hilfe des RBR- Algorithmus) 7.19 7.20 KAPITEL 7. NORMALFORMEN Übung 7.12 Bestimmen Sie für jedes der Relationenschemata RS(R, F ) alle Schlüssel. Stellen Sie fest, in welcher NF sie sind. Geben Sie eine verlustfreie und, wenn möglich, abhängigkeitstreue Zerlegung in BCNF an (mit möglichst wenig Relationen). 1. R = ABCDEF, F = {E → F, B → D, D → C, F → BE} 2. R = ABCDEF, F = {F → E, AC → BD} 3. R = ABCDEF, F = {AF → AB, AC → D} 4. R = ABCDEF, F = {AB → C, ABC → DEF, EF → B} Übung 7.13 Bestimmen Sie für jedes der Relationenschemata RS1 (R1 ,F1 ), RS2 (R2 ,F2 ) und RS3 (R3 ,F3 ) alle Schlüssel. Geben Sie eine verlustfreie und, wenn möglich, abhängigkeitstreue Zerlegung in BCNF an (mit möglichst wenig Relationen). Es gelte: R1 = ABCDE, F1 = {A → E, DB → CA} R2 = ABCDEF, F2 = {E → F, AB → CD} R3 = ABCDEF, F3 = {F → E, A → D, D → C, E → AF } Übung 7.14 Bestimmen Sie für jedes der Relationenschemata RS1 (R1 ,F1 ), RS2 (R2 ,F2 ) und RS3 (R3 ,F3 ) einen Schlüssel. Geben Sie eine verlustfreie und abhängigkeitstreue Zerlegung in 3NF an (mit möglichst wenig Relationen). Es gelte: R1 = ABCDEF, F1 = {CDE → F, F → A, CE → B} R2 = ABCDEF, F2 = {CD → AE, A → F, AF → B} R3 = ABCDEF, F3 = {A → B, F → A, C → D} Übung 7.15 Bestimmen Sie für jedes der Relationenschemata RS1 (R1 ,F1 ), RS2 (R2 ,F2 ) und RS3 (R3 ,F3 ) einen Schlüssel. Geben Sie eine verlustfreie und abhängigkeitstreue Zerlegung in 3NF an (mit möglichst wenig Relationen). Es gelte: R1 = ABCDEF, F1 = {C → A, CB → ADE, E → F } R2 = ABCDEF, F2 = {D → CB, C → F, E → A} R3 = ABCDEF, F3 = {D → B, B → CE, C → F E, CE → D} Übung 7.16 Bestimmen Sie für jedes der Relationenschemata RS1 (R1 ,F1 ), RS2 (R2 ,F2 ) und RS3 (R3 ,F3 ) alle Schlüssel. Geben Sie eine verlustfreie Zerlegung in BCNF mit möglichst wenigen Relationen an. Es gelte: R1 = ABCDE, F1 = {A → D, C → B} R2 = ABCDEF, F2 = {A → BC, B → DA, D → E, CD → F } R3 = ABCDE, F3 = {AB → CDE, E → BC, C → D} KAPITEL 7. NORMALFORMEN 7.21 Übung 7.17 Bestimmen Sie für jedes der Relationenschemata RS1 (R1 ,F1 ), RS2 (R2 ,F2 ) und RS3 (R3 ,F3 ) alle Schlüssel. Geben Sie eine verlustfreie Zerlegung in BCNF mit möglichst wenigen Relationen an. Es gelte: R1 = ABCDE, F1 = {B → E, D → C} R2 = ABCDEF, F2 = {F → AB, A → CF, C → D, BC → E} R3 = ABCDE, F3 = {CD → ABE, B → DE, E → A} Übung 7.18 Geben Sie ein Beispiel für ein Relationenschema R an, das bzgl. einer Menge F von FDs nicht abhängigkeits- und verbundtreu in BCNF zerlegbar ist. Versuchen Sie, ein möglichst kleines Beispiel (möglichst wenige Attribute, FDs) zu finden. Übung 7.19 Bestimmen Sie für jedes der Relationenschemata RS1 (R1 ,F1 ), RS2 (R2 ,F2 ) und RS3 (R3 ,F3 ) alle Schlüssel. Geben Sie eine verlustfreie Zerlegung in 3NF mit möglichst wenigen Relationen an. Es gelte: R1 = ABCDE, F1 = {AB → D, E → A} R2 = ABCDE, F2 = {AD → C, C → E, CE → B} R3 = ABCDE, F3 = {AB → CDE, E → BC, C → D} Übung 7.20 Für die Verwaltung einer wissenschaftlichen Konferenz ist eine Datenbank in 3NF zu entwerfen. Unterstreichen Sie je Relation einen Schlüssel. Verwenden Sie nur die vorgegebenen Attributnamen. (Diese sind nur bei ihrer jeweils ersten Erwähnung angeführt.) Führen Sie keine zusätzlichen Attribute ein. Die Datenbank unterstützt keine Nullwerte. • Alle in der Datenbank verwalteten Personen werden durch die Kombination aus ihrem Namen (NAME) und ihrer email-Adresse (EMAIL) eindeutig identifiziert. Sie haben eine physische Adresse (ADRESSE). • Autoren reichen Artikel ein, die sie auf der Konferenz vortragen möchten. Jeder eingereichte Artikel wird durch eine eindeutige Nummer (ANR) identifiziert. Er hat einen Titel (TITEL), sowie eine bestimmte Seitenanzahl (SANZ). Ein Artikel kann mehrere Autoren haben, es gibt aber immer nur einen Hauptautor. Ein Autor kann an mehreren Artikeln beteiligt sein. Jeder Artikel wird beschrieben durch mehrere KEYWORDs (keine fixe Anzahl). Es ist vermerkt, ob der Artikel für die Konferenz angenommen wurde oder nicht (AANG). • Bevor ein Artikel zum Vortrag zugelassen wird, muss er einer Begutachtung unterzogen werden. Jeder Artikel ist mehreren Gutachtern zugeordnet (keine fixe Anzahl). Jeder Gutachter gibt seine Bewertung des Artikels in puncto Lesbarkeit (LESB), Neuheit (NEU) und Wichtigkeit (WICHT) ab. 7.22 KAPITEL 7. NORMALFORMEN • Das Programm der Konferenz ist in einzelne, eindeutig benannte (SNAME) Sitzungen unterteilt. Für angenommene Artikel ist gespeichert, in welcher Sitzung der Artikel vorgetragen wird, und welcher Autor den Vortrag halten wird. Ein Artikel wird nur einmal vorgetragen. Für die Abhaltung einer jeden Sitzung ist ein eigener Vorsitzender bestimmt. Übung 7.21 Eine Datenbank zur Verwaltung von Erdbebendaten soll in 3NF modelliert werden. Unterstreichen Sie je Relation einen Schlüssel. Verwenden Sie nur die vorgegebenen Attributnamen. (Diese sind nur bei ihrer jeweils ersten Erwähnung angeführt.) Führen Sie keine zusätzlichen Attribute ein. Die Datenbank unterstützt keine Nullwerte. • Messstationen haben eine geographische Position, die durch Länge (L) und Breite (B) angegeben ist. Für jede Messstation ist bekannt, für welche maximale Erdbebenstärke (MAXBEL) sie ausgelegt ist. • Einer Messstation können mehrere Sensoren zugeordnet sein. Jeder Sensor hat eine (für diese Station) eindeutige Nummer (SEN#), das Jahr der Errichtung (JAHR), das Datum der nächsten Generalüberholung (GENERAL), und den Grad der Empfindlichkeit (EMP). • Ein Erdbeben wird identifiziert durch eine laufende Nummer (EBNR) und beschrieben durch die Position des Epizentrums, Datum (DAT), und Uhrzeit (ZEIT). • Angegeben ist außerdem die Stärke des Erdbebens (STAERKE) und die Tiefe des Epizentrums unter der Oberfläche (TIEFE). • Für jede Messung ist der Sensor, das betroffene Erdbeben und die Uhrzeit bekannt, außerdem die Dauer der Messung (DAUER) und das Aktenzeichen des Originalausdrucks (AKZ). Es kann mehrere Messungen je Erdbeben und Sensor geben. • Ein Erdbeben besteht aus einer Reihe von Erdstößen. Jeder Erdstoß hat eine laufende Nummer (ESNR) pro Erdbeben, und die Angaben von Uhrzeit und Stärke. • Schadensmeldungen sind einem bestimmten Erdstoß zugeordnet. Sie sind beschrieben durch ihre Position, die Höhe des Schadens (HOEHE) und die Anzahl der Opfer (OPFER). Übung 7.22 Die Datenbank der NASA über die Experimente-Belegung des Hubble Space Telescope (HST) ist in 3NF darzustellen. Unterstreichen Sie je Relation einen Schlüssel. Verwenden Sie nur die vorgegebenen Attributnamen. (Diese sind nur bei ihrer jeweils ersten Erwähnung angeführt.) Führen Sie keine zusätzlichen Attribute ein. Die Datenbank unterstützt keine Nullwerte. KAPITEL 7. NORMALFORMEN 7.23 • Beobachtungszeiträume für das Teleskop werden über Projekte zugeteilt. Ein Projekt wird von einer Forschungsgesellschaft (FGES) gefördert und hat eine innerhalb dieser Gesellschaft eindeutige Kombination von Projektnamen (Pname) und -nummer (Pnummer). Ein Projekt hat eine Priorität (Prio), einen leitenden Astronomen (LAst) und möglicherweise noch mehrere Mitarbeiter (PMit). • Messgeräte an Bord des HST tragen eine eindeutige Bezeichnung (MGB). Sie werden beschrieben durch Stromverbrauch (SV) und Wartungszustand (WZ). • Fixe Himmelsobjekte haben eine eindeutige Bezeichnung (HOBZ), eine Positionsangabe durch Länge und Breite (L, B), sowie einen Durchmesser (DM) angegeben in Winkelsekunden. • Bewegliche Himmelskörper haben ebenfalls eine Bezeichnung und einen Durchmesser. Für sie ist für jedes Jahr (J) die Himmelsposition am Anfang jedes Monats (M) angegeben. • Beobachtungen geben das Projekt, das Gerät, Jahr, Monat, Tag (T), Uhrzeit (U) und Dauer (D) der Beobachtung an. Eine Beobachtung dient immer nur einem Projekt. Verschiedene Messgeräte können gleichzeitig Beobachtungen durchführen. Übung 7.23 Eine von einer staatlichen Einrichtung geführte Datenbank über den nationalen Waldzustand ist in 3NF darzustellen. Unterstreichen Sie je Relation einen Schlüssel. Verwenden Sie nur die vorgegebenen Attributnamen. (Diese sind nur bei ihrer jeweils ersten Erwähnung angeführt.) Führen Sie keine zusätzlichen Attribute ein. Die Datenbank unterstützt keine Nullwerte. • Ein Land ist in Areale unterteilt. Ein Areal ist identifiziert durch die Koordinaten eines fix zugeordneten Hauptmessortes (X, Y) innerhalb des Areals. Es ist beschrieben durch einen Namen (ANAME), die Fläche (FL), Orientierung (OR), und durchschnittliche Seehöhe (DSH), sowie die darauf wachsenden Baumarten (BMART) mit der Angabe der Bewuchsdichte (BWD) und des Prozentanteils (BPROZ) der jeweiligen Baumart. • Alle Messorte (inkl. Hauptmessorte) werden durch ihre Koordinaten (MX, MY) identifiziert, beschrieben durch ihre Seehöhe (SH) und die Angabe des Areals, in dem sie liegen. • Jahresberichte geben für jedes Areal für jedes Jahr (JAHR) und jede Baumart an, wie hoch in diesem Jahr der Prozentsatz (SPROZ) der Bäume in jeder der zehn möglichen Schadensklassen war (SK). • Niederschlagsberichte geben für jeden Messpunkt die monatliche (MONAT) Niederschlagsmenge (NSM) sowie die vorwiegende Niederschlagsart (NSA) an (für alle in der Datenbank enthaltenen Jahre). 7.24 KAPITEL 7. NORMALFORMEN • Einzelne Areale werden für Experimentierzwecke mit chemischen Wirkstoffen behandelt. Gespeichert wird das Areal, der für die Behandlung auf dem Areal benutzte Wirkstoff (WSTOFF) sowie Jahr und Monat der Behandlung (Ann.: nur eine Behandlung pro Jahr pro Areal). Übung 7.24 Zur Verwaltung von Konstruktionsdaten in einem System zur Entwicklung von elektronischen Steuerungen soll eine relationale Datenbank in 3NF entworfen werden. Unterstreichen Sie je Relation einen Schlüssel. Verwenden Sie nur die vorgegebenen Attributnamen. (Diese sind nur bei ihrer jeweils ersten Erwähnung angeführt.) Führen Sie keine zusätzlichen Attribute ein. Die Datenbank unterstützt keine Nullwerte. • Bauteile werden durch eine eindeutige Bauteilnummer (B#) identifiziert und durch einen Typ (TYP; z.B. Widerstand, Kondensator, ASIC) sowie die Kosten (Kosten) und den Hersteller (Herst) beschrieben. • ASICS werden außerdem durch die Angabe der Pin-Anzahl (PAnz) und der Anzahl der Transistoren (TAnz) beschrieben. • Platinen haben eine eindeutige Nummer (P#) und werden beschrieben durch Angabe ihrer Länge (L) und Breite (B) sowie der daran angebrachten Typen von Steckern (STTyp). Da an einer Platine beliebig viele Stecker angebracht sein können, auch mehrere vom selben Typ, muss außerdem für jeden Typ auf einer Platine die Anzahl gespeichert werden (STAnz). (Anm.: Platinen sind keine Bauteile). • Eine Baugruppe, identifiziert durch eine Typbezeichnung (BGTyp), besteht aus einer Platine mit darauf angebrachten Bauteilen. Auf einer Platine können beliebig viele Bauteile angebracht werden. (Annahme: pro Platine höchstens ein Bauteil von jedem Typ.) Gleichzeitig muss gespeichert werden, welche Bauteile auf der Platine durch Leiterbahnen miteinander verbunden werden. Solche Verbindungen sind immer paarweise (d.h., verbinden zwei Bauteile). Auf einer Platine können auch unverbundene Bauteile existieren. Kapitel 8 Physisches Datenbankdesign 8.1 Grundlegende Begriffe In diesem Kapitel stellen wir die Methoden zur physischen Speicherung von Relationen vor. Eine Relation wird dabei in einer Datei gespeichert, die aus einzelnen S ätzen (records) besteht. Wir gehen davon aus, dass ein Satz aus einer festen Anzahl von Feldern besteht, die zusammenhängend mit fixem Platzbedarf und in fixer Reihenfolge abgespeichert sind. Ein Schl üssel ist ein Feld oder eine Kombination von Feldern, deren Werte einen bestimmten Satz eindeutig identifizieren. Ein Speicherverwaltungssystem bietet Zugriff auf eine Menge gleich großer Blöcke bzw. Seiten (blocks, pages). Der Zugriff auf einen Block erfolgt direkt über dessen Blockadresse. Das Speicherverwaltungssystem liefert unbenutzte Blöcke und übernimmt freigewordene Blöcke. Wir setzen voraus, dass die folgenden Formen der Datenorganisation bekannt sind (siehe VO Algorithmen und Datenstrukturen): ungeordnete Dateien, indexsequentielle Dateien, Hashorganisation, dynamisches Hashing (dynamic hashing), erweiterbares Hashing (extendible hashing) und B ∗ -Baum. 8.1.1 Clustering Eine neue Speicherorganisation ist das Clustering. Hierbei handelt es sich um eine Abart der indexsequentiellen Speicherung. Die Hauptdatei wird dabei nicht nach dem Primärschlüssel (bei dem kein Wert mehr als einmal vorkommen darf) sortiert gespeichert, sondern nach einem anderen Feld. Wir bezeichnen dieses Feld als indiziertes Feld. Dieses wird im Gegensatz zum Relationenmodell in Systemhandbüchern oft auch als Schlüsselfeld“ bezeichnet. Das indizierte Feld stellt im allgemeinen keinen ” Schlüssel im Sinne des Relationenmodells dar, da seine Ausprägung nicht eindeutig einen Datensatz identifiziert. Hingegen dürfen die indizierten Felder verschiedener Datensätze den gleichen Wert annehmen, solche Sätze werden zusammen abgespeichert (clustered). Dies gilt analog für den Fall, dass statt nach einem Feld nach einer Gruppe von Feldern indiziert wird. 1 KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.2 rnr 1 1 1 1 2 rnr 1 2 3 4 Indexdatei (ind. Feld,Blockzeiger) preis name 2 3 3 3 3 4 4 4 4 4 Datei Abbildung 8.1: Ein Clustering-Index der Relation Speise Das Einfügen, Suchen und Löschen ist im Prinzip gleich wie bei der indexsequentiellen Form. 8.1.1.1 Clustering-Index Ein Clustering-Index ist gleich aufgebaut wie ein Index nach dem Primärschlüssel. Wie bereits gesagt besteht der Unterschied darin, dass die Hauptdatei zwar nach dem Sortierfeld geordnet ist, es aber für jeden Wert mehrere Sätze geben kann (siehe Abbildung 8.1). Der Index enthält einen Eintrag pro tatsächlich vorkommendem Wert des Sortierfeldes. Der Blockzeiger zeigt auf den ersten Block, in dem dieser Wert vorkommt. Um alle Sätze eines Wertes zu finden, müssen solange alle Folgesätze – auch in den folgenden Blöcken – gelesen werden, bis das Sortierfeld einen anderen Wert annimmt. 8.1.1.2 Geclusterte Speicherung von Datensätzen Durch die Möglichkeit, mehrere Datensätze zusammen zu clustern, kommen wir zu dem eigentlichen Vorteil dieser Methode. Dabei werden Tupel aus einer oder mehreren Relationen, die in bestimmten Feldern (clustering attributes) identische Werte aufweisen, in denselben Blöcken gespeichert. Aus Effizienzgründen wird dabei meist ein Index über die clustering attributes gelegt. Diese Organisationsform bringt den Vorteil, dass ein prejoin stattfindet, wo- KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.3 durch die Joinoperationen weniger Zeit brauchen. Außerdem benötigen die Tupel weniger Speicherplatz, da idente Felder jeweils nur einmal gespeichert werden. Der Nachteil ist, dass die einzelne Relation auf mehr Blöcke verteilt werden muss, als wenn sie alleine gespeichert wird. Dadurch müssen bei Abfragen, die nur die eine Relation betreffen, mehr Blöcke gelesen werden und der der Zeitaufwand für die Suche erhöht sich. Angewandt wird diese Methode dann, wenn bestimmte Dateien oft miteinander verknüpft werden. 8.1.2 Primär- und Sekundärorganisation Bei der Speicherorganisation unterscheiden wir zwei Schritte: die Primärorganisation und die Sekundärorganisation. Unter Primärorganisation verstehen wir die Speicherungsform der Datensätze einer Datei, unter Umständen eng verbunden mit einer bestimmten, ausgewählten Zugriffsorganisation. Unter einer Sekundärorganisation einer Datei verstehen wir eine neben der primären Zugriffsstruktur (Primärorganisation) alternative Zugriffsstruktur. Eine Datei kann mehrere Sekundärorganisationen besitzen. Eine Sekundärorganisation wird dann verwendet, wenn die Primärorganisation die Suche nach einem bestimmten Feld nicht unterstützt, wenn also die ganze Datei sequentiell gelesen werden müsste. Indexsequentielle Organisation, Hashing und B∗ -Bäume werden sowohl für die Primärals auch für die Sekundärorganisation verwendet mit dem Unterschied, dass bei der Sekundärorganisation dort, wo sich bei der Primärorganisation der Datensatz selbst befindet, nur ein Verweis auf den Datensatz gespeichert ist. Bei der Sekundärorganisation wird hauptsächlich ein dichter Index (dense index) verwendet. Darin existiert für jeden Wert des indizierten Feldes ein Eintrag im Index. Dies ist vergleichbar mit dem Stichwortindex eines Buches. Ein dichter Index kann bei Dateien beliebiger Art – auch ungeordneten und Hash-Dateien – angewendet werden. Mit einem dichten Index kann ein beliebiges Feld indiziert werden, unabhängig davon, ob es sich um ein Schlüsselfeld handelt oder ob und wie die Datei sortiert ist. 8.2 Speicherstrukturen f ür Relationen Relationen werden auf Dateien abgebildet, wobei die Sätze der Datei den Tupeln der Relation entsprechen. 8.2.1 Kriterien zur Auswahl von Speicherstrukturen Es gibt eine Reihe von Kriterien, nach denen eine geeignete Speicherstruktur für eine Datei gewählt werden kann. Zu den wichtigsten Kriterien zählen der Speicherplatzbedarf, die Art der Abfragen, die häufig vorgenommen werden, Änderungsverhalten der Datei und Aufwand für Zugriffsoperationen. Bei den Abfragen können wir grob folgende Arten unterscheiden: KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.4 1. Exakte Abfrage, z.B. name = 0 GreenCottage0 . 2. Bereichsabfragen, z.B. 2 ≤ haube ≤ 4. 3. Pattern matching z.B. name = 0 Gre∗0 . 4. Abfrage nach einem Teilschlüssel, z.B. wenn der Schlüssel {rnr, name}ist, die Suche nach name = 0 Kleines Sushi0 . Im Folgenden betrachten wir die vorgestellten Organisationsformen für Dateien und halten kurz ihre Vor- und Nachteile und mögliche Anwendungsgebiete fest. 8.2.1.1 Ungeordnete Dateien Die Sätze werden ungeordnet sequentiell gespeichert und sequentiell gelesen. Alle Blöcke werden immer gefüllt. Vorteile: • Am schnellsten, wenn viele Sätze eingefügt werden sollen. • Da alle Blöcke immer voll gefüllt werden, benötigt eine solche Datei vergleichsweise wenig Platz (ACHTUNG: Spätere Fragmentierung möglich). • Effizientes Löschen (nachdem der Satz gefunden wurde). Nachteile: • Sehr langsam, wenn nach einigen wenigen Sätzen gesucht wird. • Bei Abfragen nach Werten innerhalb eines bestimmten Bereiches muss jeder Satz gelesen werden. • Der Platz, der durch das Löschen von Sätzen frei wird, kann nur durch eine Reorganisation wiederverwendet werden. Anwendungsgebiet: • Kleine Dateien, die nur wenige Blöcke benötigen. Da nur wenige Blöcke gelesen werden müssen, lohnt sich zusätzlicher Verwaltungsaufwand nicht. • Wenn bei Abfragen häufig alle Sätze gelesen werden müssen, z.B. bei statistischen Auswertungen. • Wenn wir bei einer großen Datei Platz sparen wollen, können wir diese ungeordnet (mit 100% Füllgrad) und mit einem Sekundärindex anlegen. KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.5 8.2.1.2 Indexsequentielle Dateien Vorteile: • Gutes Antwortzeitverhalten für pattern-matching, Bereichsabfragen, Suche nach einem Teilschlüssel, aber auch für exakte Abfragen. • Sortierung muss nicht nach dem Primärschlüssel erfolgen. Nachteile: • Sind sowohl Hauptdatei als auch Index statisch gespeichert, müssen neue Sätze in Überlaufblöcken“ gespeichert werden, was die Suchoperationen verlangsamt vor al” lem, wenn sequentiell viele Datensätze eingefügt werden. Statisch (pinned) bedeutet, dass jeder Datensatz an einer bestimmten, festen physischen Adresse gespeichert ist ( festgenagelt“), die nachträglich nicht mehr verändert und der ” Datensatz daher nicht mehr verschoben werden kann. Statische Organisation vermeidet das Problem ungültiger Verweise (dangling pointers) auf einen Datensatz, die durch Verschieben oder Löschen entstehen können. Durch eine Reorganisation können die Sätze in den Überlaufblöcken in die Hauptdatei eingefügt werden. Anwendungsgebiet: • Bei Dateien, in die später wenige Sätze eingefügt werden, und bei denen flexible Abfragen notwendig sind. • Die Anzahl der Indexblöcke ist gering. 8.2.1.3 Clustered Vorteile: • Gutes Antwortzeitverhalten für pattern-matching, Bereichsabfragen, Suche nach einem Teilschlüssel, aber auch für exakte Abfragen. • Sortierung muss nicht nach dem Primärschlüssel erfolgen. • Es können mehrere Dateien miteinander verwoben gespeichert werden, dadurch schnellerer Zugriff (bei Joins). KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.6 Nachteile: • Sind sowohl Hauptdatei als auch Index statisch (pinned) gespeichert, müssen neue Sätze in Überlaufblöcken gespeichert werden, was die Suchoperationen verlangsamt. Durch eine Reorganisation können die Sätze in den Überlaufblöcken in die Hauptdatei eingefügt werden. • Langsamerer Zugriff, wenn nur die Sätze einer Datei gelesen werden, da hier mehr Blöcke gelesen werden müssen. • aufwendiges Einfügen • aufwendiges Löschen Anwendungsgebiet: • Bei Dateien, in die später wenige Sätze eingefügt werden, und bei denen flexible Abfragen notwendig sind, oder • bei Dateien, die oft miteinander verknüpft werden (joins). 8.2.1.4 Hashorganisation Vorteile: • Effizienter Zugriff: durchschnittlich d n2 e, wobei n = Zahl der Blöcke pro Bucket. (Ein Bucket besteht aus einem oder mehreren Blöcken, die Sätze der Datei werden durch Hashing in eine Menge von Buckets aufgeteilt.) • Schnellste Zugriffsmethode für exakte Abfragen nach dem Schlüssel. Dies sind Abfragen, bei denen kein pattern-matching verwendet werden muss, also z.B. keine Jokerzeichen in Zeichenketten. Nachteile: • Bei Bereichsabfragen muss jeder Satz gelesen werden. • Keine Sortierung möglich. • Ungünstig für Abfragen mit pattern-matching und Abfragen nach Teilschlüsseln, da hierfür alle Sätze gelesen werden müssen. Anwendungsgebiet: • Dateien, deren Abfragen überwiegend in einer exakten Abfrage nach dem Schlüssel bestehen, z.B. Ordernummern, Sozialversicherungsnummer. KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.7 8.2.1.5 B ∗ -Baum (Abhängig von der Implementierung können die Blattknoten anstelle der tatsächlichen Datensätze Zeiger auf die Datensätze enthalten.) Vorteile: • Keine Überlaufprobleme, da sich der Index dynamisch anpasst. • Gutes Antwortzeitverhalten für pattern-matching, Bereichsabfragen, Suche nach einem Teilschlüssel, aber auch für exakte Abfragen. • Der durch das Löschen von Sätzen freigewordene Platz kann ohne Reorganisation wiederverwendet werden. • Da Sätze mit benachbarten Schlüsseln oft im gleichen Blattknoten gespeichert sind, können auch Bereichsabfragen effizient durchgeführt werden. Wenn die Datei oft sequentiell geordnet nach Schlüssel abgearbeitet wird, empfielt es sich, die Blattknoten mittels Zeiger zu verbinden, sodass zusätzlich zur Baumstruktur eine verkettete Liste entsteht. • Es ist keine Reorganisation nach einer bestimmten Zeit nötig. Nachteile: • Höherer Platzverbrauch bei kleinen Dateien, dieser Faktor fällt bei mittleren bis großen Dateien nicht mehr ins Gewicht. • Höherer Verwaltungsaufwand (Einfügen, Löschen) bedingt durch die sofortige Reorganisation. • Zugriff etwas langsamer als bei Indexsequentieller Organisation wegen der komplexeren Zugriffsstruktur. • Geringere Parallelität bei gleichzeitigem Zugriff mehrerer Benutzer (komplizierte Concurrency Control; gegebenenfalls ist Sperren auf allen Baumebenen für eine Änderung notwendig, d.h., fast überhaupt keine Parallelität). Anwendungsgebiet: • Bei Dateien, die flexible Abfragen benötigen. • Bei Dateien, deren Größe stark variiert (häufiges Einfügen, Löschen oder ändern der Werte). KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.8 Beispiel 8.1 Gegeben ist eine Datei, in der Inskriptionsdaten gespeichert sind. Die Primärorganisation ist indexsequentiell, sortiert nach MATRIKELNUMMER. Diese Organisationsform wurde gewählt, weil einerseits viele Abfragen nach Matrikelnummern gestellt werden und andererseits viele Listen sortiert nach der Matrikelnummer ausgegeben werden müssen. Zusätzlich soll auch nach den Feldern STUDIENRICHTUNG, SOZIALVERSICHERUNGSNUMMER und MATURASCHULE zugegriffen werden, was bei dieser Organisation nicht effizient möglich ist. Für das Feld STUDIENRICHTUNG sind nur wenige verschiedene Werte zu erwarten. Daher sollte ein Index verwendet werden, wenn ein effizienter Zugriff nach STUDIENRICHTUNG notwendig ist. Für das Feld SOZIALVERSICHERUNGSNUMMER wäre eine sekundäre Hashorganisation sinnvoll: es wird immer ein Datensatz mit einer bestimmten, vollständig angegebenen Sozialversicherungsnummer gesucht. Ein Anwendungsfall für einen B ∗ -Baum als Sekundärorganisation wäre eine Zugriffsstruktur für das Feld MATURASCHULE: es sind viele unterschiedliche Werte zu erwarten, daher kann über einen B ∗ -Baum effizienter zugegriffen werden als über einen Index. Alternativ wäre eine Hash-Organisation denkbar. Sollen auch Abfragen nach einem Teil des Namens der Schule möglich sein, ist die Hash-Organisation jedoch ungünstig. 8.2.2 Füllgrad Ein wichtiges Element der Optimierung einer Datenbank ist der Füllgrad eines Blocks: Definition 8.1 Der Füllgrad (FG) ist definiert als FG = Anzahl der erwünschten Sätze pro Block Anzahl der möglichen Sätze pro Block Ein Block enthält u.U. Verwaltungsinformation (Pointer) neben Datensätzen, so dass auch bei F G = 100% nicht alle Bytes des Blocks mit Datensätzen belegt sind. Jeder Block wird bis zum Füllgrad gefüllt, der verbleibende Platz wird für update-Operationen reserviert. Das bringt den Vorteil mit sich, dass Überläufe vermieden oder zumindest vermindert werden können, aber auch den Nachteil, dass die Datei mehr Platz benötigt (≈ F1G -fachen Speicherbedarf). Bei der Wahl der Speicherstruktur und besonders bei der Wahl der Sekundärorganisation dürfen wir allerdings nie die Tatsache aus den Augen verlieren, dass jede zusätzliche Zugriffsstruktur ein Ansteigen des Verwaltungsaufwandes – besonders beim Einfügen von Datensätzen – mit sich bringt. Wir müssen also bei jeder Zugriffsstruktur kalkulieren, ob der Mehraufwand an Verwaltung durch Einsparungen beim Zugriff gerechtfertigt werden kann. KAPITEL 8. PHYSISCHES DATENBANKDESIGN 8.9 Ein weiterer wichtiger Aspekt ist die Frage, welches Feld für die Primärorganisation verwendet wird und auf welches Feld über eine Sekundärorganisation zugegriffen wird. Das Entscheidungskriterium für diese Frage ist die Häufigkeit, nach der über ein bestimmtes Feld zugegriffen wird und die Art der Abfrage. Wenn z.B. häufig eine Liste erstellt werden soll, die nach einem bestimmten Feld geordnet ist, dann sollte eine Primärorganisation geordnet nach diesem Feld gewählt werden, bei der dies effizient möglich ist. 8.2.3 Zugriffszeitverhalten Wir wollen kurz das Zugriffsverhalten bei den einzelnen Organisationsformen betrachten und zwar die Suche nach einem bestimmten Wert (exakte Abfrage). Sei n die Anzahl der Datensätze in der Hauptdatei, und nehmen wir an, ein Block der Hauptdatei enthalte e Datensätze und ein Block einer Indexdatei d Indexeinträge. Hashorganisation: unter der Annahme, dass im Durchschnitt ein Bucket aus einem Block besteht, wird ein Zugriff auf das Directory und ein weiterer auf das Bucket benötigt, insgesamt also 2 Zugriffe. Befindet sich im Bucket nicht der Datensatz selbst, sondern ein Verweis auf den Datensatz, z.B. bei einer Sekundärorganisation, so wird ein weiterer Zugriff auf den Block mit dem Datensatz benötigt. Indexsequentiell: Für die Hauptdatei werden ne Blöcke benötigt. Für jeden Block wird ein Eintrag im Index benötigt, d dieser Einträge sind in einem Block; daher besteht die n Indexdatei grob aus ed Blöcken. n Die binäre Suche im Index benötigt daher grob log 2 ( ed ) Blockzugriffe. Unter speziellen Voraussetzungen kann ein anderes Verfahren, z.B. Interpolationssuche auch weniger Zugriffe erfordern. Ein weiterer Blockzugriff wird benötigt, um den Datensatz selbst zu lesen. B ∗ -Baum: Hier seien d und e die Untergrenze für die Anzahl der Datensätze in den inneren Knoten bzw. Blattknoten. Befinden sich die Datensätze in den Blättern des B ∗ -Baumes, so hat dieser Baum höchstens ne Blätter. Die Schicht über den Blättern besteht aus n höchstens ed Knoten, die darüberliegende Schicht aus edn2 Knoten usw. Geht der Pfad von der Wurzel bis einschließlich zum Blatt über i Knoten, so muss gelten: n ≥ d i−1 e (di+1 Blattknoten mit je e Datensätzen). Formen wir nach i um, so erhalten wir i ≤ 1 + logd ( ne ). Wir benötigen also bis zu 1+logd ( ne ) Zugriffe im B ∗ -Baum. Befinden sich in den Blattknoten nicht die Datensätze selbst, sondern nur Verweise, so kommt noch ein Zugriff dazu. (Es ist kein großer Nachteil, wenn d e, weil dadurch unter Umständen der Baum niedriger ist.) 8.10 KAPITEL 8. PHYSISCHES DATENBANKDESIGN Dichter Index (Sekundärorganisation): Die Indexdatei enthält n Einträge und benötigt daher nd Blöcke. Die binäre Suche benötigt log2 ( nd ) Zugriffe1 . Um den Datensatz in der Hauptdatei zu lesen, wird ein weiterer Zugriff benötigt. 8.2.4 Physische Datenorganisation in kommerziellen DBMS Von relationalen Datenbanken werden unterschiedliche Arten der Datenorganisation angeboten. Nachfolgend werden die Möglichkeiten von INGRES, ORACLE und MSQL Server aufgezeigt. 8.2.4.1 INGRES Ingres bietet eine große Auswahl von unterschiedlichen Dateiorganisationen: Heap: entspricht einer ungeordneten Datei – Die Sätze werden ungeordnet sequentiell gespeichert und sequentiell gelesen. Alle Blöcke werden immer voll gefüllt. Hash: ist eine (interne) Hashorganisation, es muss ein Schlüssel dafür angegeben werden (Index sequential access method). Isam: entspricht einer geordneten Datei mit einem Primärindex. Btree: implementiert eine ungeordnete Datei mit einem B ∗ -Baum als Zugriffsstruktur. Zusätzlich können bei jeder der beschriebenen Varianten sekundäre Indexe definiert werden, wahlweise als Hash, Isam oder Btree. 8.2.4.2 ORACLE ORACLE benutzt B ∗ -Baum-Indexe und ungeordnete Dateien, die mit INGRES-heap vergleichbar sind. ORACLE bietet darüber hinaus die Möglichkeit des clusterings (siehe Abschnitt 8.1.1). Wird das clustering auf eine Relation angewendet, dann entspricht dies einer Sortierung nach einem Nichtschlüsselfeld – alle Tupel, in denen das clustering-Feld auftritt, werden zusammen gespeichert. Mit der gleichen Vorgehensweise, allerdings bei Sortierung nach dem Primärschlüssel, kann in ORACLE eine indexsequentielle Primärorganisation erreicht werden. 8.2.4.3 MS-SQL Server MS-SQL Server stellt ungeordnete Dateien und geordnete Dateien mit Indexen als Primärund Sekundärorganisation zur Verfügung. Unter einem Clustered Index wird in diesem Fall die Speicherung einer Datei geordnet nach einem Index-Attribut verstanden. Es gibt keine Möglichkeit verschiedene Dateien auf einer Seite zu speichern. 1 Vgl. Kommentar zur Indexsequentiellen Datei. Teil III Das Datenbankmanagementsystem 1 Kapitel 9 Optimierung Höhere, nichtprozedurale Abfragesprachen wie z.B. SQL oder QBE verlangen keine Kenntnisse des Benutzers über die Implementierung, müssen aber zur Ausführung vom System selbst in eine andere Form (z.B. Relationenalgebra) umgesetzt werden. Um eine effiziente Bearbeitung von Abfragen zu erzielen, gibt es eine interne Umformulierung der Abfragen in eine optimierte Form (Query Optimization). Die dabei verwendeten Strategien erzielen keine optimale Lösung, sondern meist nur eine Verbesserung. Wir stellen im nächsten Abschnitt einen Algorithmus vor, der zur Optimierung verwendet wird. Weiters gibt es unterschiedliche Strategien zur Durchführung von Joins, die, wie wir sehen werden, zu den aufwendigsten Operationen bei der Ausführung einer Abfrage zählen. In Abschnitt 9.2 stellen wir einige der in der Praxis verwendeten Algorithmen vor. Im letzten Abschnitt dieses Kapitels zeigen wir, wie die Operation des Semijoins verwendet werden kann, um Joins von Relationen, die in einer verteilten Datenbank gespeichert sind, zu optimieren. 9.1 Logische Abfragenoptimierung Die aufwendigste Operationen in relationalen Sprachen sind kartesisches Produkt und Join. Bei einfachster Implementierung eines Joins zwischen A und B ist ein Durchlauf aller Tupel von B für jedes Tupel von A notwendig. Sei n die Anzahl der Tupel von A, m die Anzahl der Tupel von B, so beträgt der Aufwand zur Berechnung des Joins oder kartesischen Produktes O(nm). Besonders aufwendig werden diese Operationen in verteilten Datenbanken. • Die Projektion ist aufwendig, da die durch das Projizieren entstandenen Duplikate entfernt werden müssen. • Wenn die Selektionen so früh wie möglich durchgeführt wurde, führt das zu kleineren Zwischenresultaten und erleichtert somit die nachfolgenden Operationen. • Unäre Operationen bedingen je einen Durchlauf aller Tupel, daher sollten mehrere möglichst zusammengezogen werden. 1 KAPITEL 9. OPTIMIERUNG 9.2 − πX πX ./ ./ s r ./ q s r Abbildung 9.1: Darstellung der Abfrage aus Beispiel 9.1 in einem Operatorbaum • Gemeinsame Teilausdrücke brauchen nur einmal ausgewertet werden. Der Aufwand kann dadurch reduziert werden. Der Zeitaufwand für das Untersuchen der verschiedenen Möglichkeiten, eine Abfrage durchzuführen, ist im allgemeinen viel geringer als für das Durchführen einer ineffizienten Abfrage. 9.1.1 Algebraische Optimierung Bei der algebraischen Optimierung verwenden wir zur Darstellung von Abfragen einen Operatorbaum. Beispiel 9.1 Wir stellen den Ausdruck πX (s ./ r) − πX (q ./ r ./ s) in Abbildung 9.1 in einem Operatorbaum dar. Der Operatorbaum wird Bottom-up ausgewertet. Daher ist es für die Laufzeit nicht günstig, wenn die Join-Operatoren nahe bei den Blättern stehen. Andererseits steigt der Zeit- und Platzaufwand binärer Operationen mit der Anzahl der Tupel und der Anzahl der Attribute in den Argumentrelationen. Eines der Grundprinzipien bei der Optimierung ist daher, die unären Operatoren in Richtung der Blätter des Baumes zu verschieben, um eine möglichst frühzeitige Reduktion der Größe der Operanden von binären Operationen (Join, Differenz etc.) zu bewirken. Außerdem erreichen wir durch die Zusammenfassung unärer Operationen, dass diese in einem Schritt durchgeführt werden. Da Projektion eine Entfernung doppelter Tupel bedingt, ist es besser, die Selektion möglichst vor der Projektion durchzuführen. KAPITEL 9. OPTIMIERUNG 9.3 9.1.1.1 Zusammenfassen gleicher Teilausdrücke Das Zusammenfassen gleicher Teilausdrücke geschieht in einem Baum von unten nach oben. Dabei werden die Ausdrücke schrittweise zusammengefasst. Allerdings können algebraische Transformationen die Existenz gleicher Teilausdrücke verschleiern. Beispiel 9.2 Betrachten wir nochmals den in Abbildung 9.1 dargestellten Operatorbaum. In einem ersten Schritt fassen wir die Blätter s und r zusammen, im zweiten den Join, der die beiden Relationen verbindet. Es folgt, dass wir die Operation s ./ r nur einmal durchführen müssen. 9.1.1.2 Regeln für Join und kartesisches Produkt Der Join und das kartesische Produkt sind kommutativ und assoziativ. 1. Kommutativität: E1 ./ E2 ≡ E2 ./ E1 E1 × E 2 ≡ E 2 × E 1 2. Assoziativität: (E1 ./ E2 ) ./ E3 ≡ E1 ./ (E2 ./ E3 ) (E1 × E2 ) × E3 ≡ E1 × (E2 × E3 ) 9.1.1.3 Regeln für Selektion und Projektion In diesem Abschnitt beschreiben wir, unter welchen Umständen wir Selektion und Projektion in Richtung der Blätter verschieben können. 3. Zusammenfassung von Projektionen: Die Zusammenfassung von zwei Projektionen zu einer geht nur unter der Voraussetzung, dass die Menge der Attribute der äußeren Projektion eine Teilmenge der Attribute der inneren Projektion ist. Formal: falls {Ai | i = 1, ..., n} ⊆ {Bi | i = 1, ..., m} so gilt: πA1 ,...,An (πB1 ,...,Bm (E)) ≡ πA1 ,...,An (E) 4. Zusammenlegung/Kommutativität von Selektionen: σF1 (σF2 (E)) ≡ σF1 ∧F2 (E) σF1 (σF2 (E)) ≡ σF2 (σF1 (E)) KAPITEL 9. OPTIMIERUNG 9.4 5. Kommutativität Selektion-Projektion: Die Projektion ist mit der Selektion eingeschränkt kommutativ. Wenn sich die Bedingung F der Selektion nur auf Attribute A i bezieht, nach denen projiziert wird, so gilt πA1 ,...,An (σF (E)) ≡ σF (πA1 ,...,An (E)) Wenn sich F auf alle Attribute Bj und möglicherweise auf Attribute Ai bezieht, dann gilt πA1 ,...,An (σF (E)) ≡ πA1 ,...,An (σF (πA1 ,...,An,B1 ,...,Bm (E))) Das bedeutet, dass wir nur nach jenen Attributen zuerst projizieren dürfen, die wir in der Selektion noch brauchen. Erst in einem zweiten Schritt können wir die gewünschte Projektion durchführen. 6. Kommutativität Selektion-Kartesisches Produkt: Die Selektion kommutiert mit dem kartesischen Produkt nur unter der Bedingung, dass sich F = F1 ∧ F2 auf die Attribute von E1 und E2 beschränkt. Wenn sich Fi nur auf Attribute von Ei beziehen, so gilt σF (E1 × E2 ) ≡ σF1 (E1 ) × σF2 (E2 ) Wenn F1 sich nur auf Attribute von E1 , F2 aber auf Attribute von E1 und E2 bezieht, so gilt: σF (E1 × E2 ) ≡ σF2 (σF1 (E1 ) × E2 ) 7. Kommutativität Selektion-Vereinigung: σF (E1 ∪ E2 ) ≡ σF (E1 ) ∪ σF (E2 ) 8. Kommutativität Selektion-Mengendifferenz/Durchschnitt: σF (E1 − E2 ) ≡ σF (E1 ) − σF (E2 ) Daher gilt natürlich analog auch die Kommutativität zwischen Selektion und Durchschnitt (überlegen Sie sich warum)! 9. Kommutativität Projektion-Kartesisches Produkt: Seien Bi Attribute von E1 , Ci Attribute von E2 und {Ai | i = 1, ..., n} = {Bi | i = 1, ..., m} ∪ {Ci | i = 1, ..., k}, so gilt: πA1 ,...,An (E1 × E2 ) ≡ πB1 ,...,Bm (E1 ) × πC1 ,...,Ck (E2 ) KAPITEL 9. OPTIMIERUNG 9.5 πnname,gehalt,name σhaube>2∧preis>30 ./ ./ Speise Mitarbeiter Restaurant Abbildung 9.2: Operatorbaum zur Abfrage aus Beispiel 9.3 10. Kommutativität Projektion-Vereinigung: πA1 ,...,An (E1 ∪ E2 ) ≡ πA1 ,...,An (E1 ) ∪ πA1 ,...,An (E2 ) Der Join ist darstellbar als Kombination von kartesischem Produkt, Projektion und Selektion. (Wollen wir zwei Relationen R1 und R2 nach dem Attribut A joinen, so müssen wir zuerst das kartesische Produkt der beiden Relationen bilden, wobei wir das Attribut A einmal umbenennen müssen, da das Ergebnis ansonsten zwei gleiche Attribute enthält. Dann selektieren wir jene Tupel, die auf A und dem umbenannten Attribut gleich sind, und zum Schluss projizieren wir das umbenannte Attribut wieder weg.) Daher folgen die Regeln für Kommutativität von Selektion und Join aus den Regeln 4, 5, und 6. Es gilt keine Kommutativität zwischen Mengendifferenz und Projektion und daher auch keine Kommutativität zwischen dem Durchschnitt und der Projektion (überlegen Sie sich warum)! 9.1.2 Ein einfacher Optimierungsalgorithmus 1. Zerlege Selektionen der Art σF1 ∧...∧Fn (E) nach Regel 4 in σF1 (...(σFn (E))...). 2. Schiebe jede Selektion soweit wie möglich in Richtung Blätter mit den Regeln 4-8. 3. Schiebe jede Projektion soweit wie möglich in Richtung Blätter mit den Regeln 3,5,9 und 10. 4. Fasse alle direkt aufeinanderfolgenden Selektionen und Projektionen zu einer einzigen Selektion, einer einzigen Projektion oder einer Selektion gefolgt von einer Projektion mit den Regeln 3-5 zusammen. KAPITEL 9. OPTIMIERUNG 9.6 πnname,gehalt,name πnname,gehalt,name ./ ./ πname,rnr ./ πrnr σpreis>300 πpreis,rnr Speise πnname,gehalt,rnr πname,rnr Mitarbeiter πrnr,name πrnr σhaube>2 σpreis>300 πrnr,name,haube Restaurant ./ Speise πnname,gehalt,rnr Mitarbeiter πrnr,name σhaube>2 Restaurant Abbildung 9.3: Operatorbaum nach Verschiebung der Selektion und Projektion und der optimierte Operatorbaum Beispiel 9.3 Betrachten wir die Relationenschemata Restaurant, Speise und Mitarbeiter aus R EINE. Wir wollen folgende Abfrage formulieren: Wie hoch ist das Gehalt und wie ist der Name der Mitarbeiter, die in Restaurants mit mehr als 2 Hauben arbeiten, in denen es Speisen zu mehr als 30 Euro gibt, und wie heißen die Restaurants? Die Abfrage sieht in SQL wie folgt aus: select distinct m.nname, m.gehalt, r.name from mitarbeiter m, restaurant r, speise s where m.rnr = r.rnr and r.haube > 2 and r.rnr = s.rnr and s.preis > 30; In Relationale Algebra übersetzt ergibt sich folgende Abfrage: πnname,gehalt,name [σhaube>2∧preis>30 (Mitarbeiter ./ Restaurant ./ Speise)] Den Operatorbaum zu dieser Abfrage sehen wir in Abbildung 9.2 Im nächsten Schritt verschieben wir die Selektion nach den Regeln 4-8 so weit wie möglich in Richtung der Blätter, danach die Projektion nach den Regeln 3, 5, 9 und 10 (siehe Abbildung 9.3). Zum Schluss fassen wir die Kaskaden von Selektionen und Projektionen zusammen (Regeln 3 und 4), was in diesem Beispiel nicht notwendig ist, aber Regel 5 ist zweimal anwendbar, also werden die zwei untersten Projektion mit den darüberliegenden Selektionen permutiert und mit der nächsten Projektion verschmolzen. Das garantiert uns, dass die Selektion zuerst ausgeführt wird. Den optimierten Operatorbaum sehen wir in Abbildung 9.3. KAPITEL 9. OPTIMIERUNG A B 9.7 B C 1 2 Abbildung 9.4: Verbesserte Lösung des nested-loop Join 9.2 Join-Algorithmen Wir haben in Kapitel 8 gesehen, wie die Daten der Datenbank in Haupt- bzw. Hintergrundspeicher gehalten werden. Bei der Abarbeitung einer Abfrage müssen die Daten zur Bearbeitung in den Hauptspeicher geladen werden. Join-Algorithmen, d.h. Algorithmen, die den Verbund durchführen, sind, da der Verbund die aufwendigste Operation ist, kritisch für das Laufzeitverhalten einer Abfrage. Wir beschreiben in den nächsten Abschnitten die Prinzipien der wichtigsten Algorithmen zur Ausführung des Verbunds zweier Relationen R(A, B) und S(BC) (kurz: AB ./ BC). Wir gehen dabei davon aus, dass die Relationen in verschiedenen Dateien gespeichert sind. 9.2.1 Nested-loop Join Die einfachste Lösung ist die Ausführung des Verbundes mit zwei Schleifen (nested-loop Join). Beim primitiven nested-loop Join werden in der äußeren Schleife alle Tupel der Datei R durchlaufen und für jedes Tupel ab in der inneren Schleife alle Tupel der Datei S durchlaufen, wobei für jedes Tupel b0 c der Datei S, für das b = b0 gilt, das Tupel abc gebildet wird. Beim primitiven nested-loop Join wird jeder Block der Datei S so oft gelesen, wie R Sätze hat: nR nS nR + bR bS m−1 wobei nR die Anzahl der Sätze in R, nS die Anzahl der Sätze in S, bR die Anzahl der Sätze von R in einem Block, bS die Anzahl der Sätze von S in einem Block und m die Anzahl der Blöcke im Hauptspeicher ist (d e = nächst größere ganze Zahl). Beim verbesserten nested-loop Join (vgl. Abbildung 9.4) werden in der äußeren Schleife soviele Blöcke der Datei R wie möglich in den Hauptspeicher geladen, wobei jedoch Platz für einen Block der Datei S gelassen wird. In der inneren Schleife werden nacheinander alle Blöcke von S gelesen, wobei für jeden Block jedes Tupel b 0 c nicht nur mit einem Tupel ab, sondern mit allen Tupeln der Datei R, die sich im Hauptspeicher befinden, verglichen KAPITEL 9. OPTIMIERUNG 9.8 A B B C u v w x A B B C u u v v w w x x Abbildung 9.5: Join mit Index über S, bzw über R und S wird. Danach werden alle Blöcke der Datei R im Hauptspeicher auf einmal ausgetauscht und der nächste Durchlauf von S wird ausgeführt. Der Aufwand (gemessen an der Anzahl der Blocktransfers zwischen Hauptspeicher und Sekundärspeicher) für den verbesserten nestedloop Join beträgt: nS nR nR + bR bS (m − 1)bR 9.2.2 Join mit Hilfe von Indexen Hat eine der beiden Dateien einen Index auf das Join-Attribut B, dann kann der Verbund in einem Schleifendurchlauf durchgeführt werden. Wenn etwa auf S ein Index für B liegt, dann werden in einer Schleife über R für jedes durchlaufene Tupel ab die Tupel b 0 c mit b = b0 über den Index gesucht. (vgl. Abbildung 9.5). Wenn sowohl auf R als auch auf S ein Index für B liegt, dann können wir den Join als Merge-Operation durchführen. Der Aufwand dabei ist ungefähr nR nS d e+d e bR bS wenn wir annehmen, dass genügend Pufferspeicher für die verbundfähigen Datensätze mit gleichem Attributwert vorhanden ist. KAPITEL 9. OPTIMIERUNG 9.9 Abbildung 9.6: Illustration: Hash-Join R S R1 S1 R2 S2 R3 S3 Abbildung 9.7: Der Hash-Join Wenn wir vor dem Durchführen des Joins zuerst beide Dateien nach dem Join-Attribut B sortieren und danach die Dateien mischen, so erhalten wir das selbe Ergebnis. Dieses Verfahren heißt sort-merge Join (vgl. Abbildung 9.5). 9.2.3 Hash-Join Beim Hash-Join wird zunächst in je einem Durchlauf durch beide Dateien ein Hashindex auf das Join-Attribut B gelegt. Danach partitionieren wir die Operandenrelationen R, S in Buckets Ri , Si in Abhängigkeit vom Wert der Join-Attribute; alle Tupel mit gleichem Attributwert liegen im selben Bucket. Allerdings können auch mehrere verschiedene Werte pro Bucket vorkommen. Im zweiten Schritt führen wir den Join durch: für jedes Paar Buckets wird der Join mit einem normalen“ Verfahren gebildet. Zuletzt vereinigen wir die Einzelresultate, d.h., wir ” ersetzen einen großen Join durch mehrere kleine, wie wir in Abbildung 9.7 sehen können. R ./ S = n [ Ri ./ Si i=1 9.2.4 Clustering Beim Clustering sind die zu verknüpfenden Tupel der Operanden bereits in denselben Blöcken gespeichert, daher benötigen wir nur einen Zugriff auf jeden Block der beiden Relationen. Das Problem dabei ist aber der aufwendige Aufbau einer geclusterten Datei. Weiters ist Clustering nur für einen Join pro Relation möglich. KAPITEL 9. OPTIMIERUNG 9.10 9.3 Der Semijoin (Semiverbund) Am Ende dieses Kapitels wollen wir noch zeigen, wie der Semijoin verwendet werden kann, um Verbundoperationen auf verteilten Datenbanken zu beschleunigen. Wenn in einer verteilten Datenbank ein Teil der Tabellen an einem Knoten, der andere an einem anderen Knoten gespeichert ist, und wir zwei Relationen verbinden wollen, die nicht am selben Knoten liegen, so kann es sehr aufwendig sein, eine ganze Tabelle von einem Knoten zum anderen zu übertragen. Sei R eine Relation, die auf dem Knoten 1 gespeichert ist, S eine Relation auf dem Knoten 2 und B das gemeinsame Attribut. Wenn wir an einem Verbund der beiden Relationen auf Knoten 1 interessiert sind, so ist eine Lösung, Relation S zu Knoten 1 zu schicken und den Verbund durchzuführen. Es kann aber sein, dass nicht alle Tupel, oder nur ein kleiner Teil der Tupel von S den Verbund mit R eingehen können und wir daher viele Daten umsonst übertragen. Als Lösung bietet sich folgende Vorgangsweise an: 1. Wir schicken zuerst r0 = πB (r) von 1 nach 2. 2. Wir bilden s0 = s ./ r0 auf Knoten 2. 3. Wir schicken s0 von 2 nach 1. 4. Wir bilden r ./ s0 . s0 ist gerade der Semijoin s n r. Beispiel 9.4 Seien die folgenden Relationen R und S auf den Knoten 1 und 2 gegeben. R (A 1 1 1 2 2 3 3 3 B) 4 5 6 4 6 7 8 9 S (B 4 4 7 1 1 2 2 2 C 10 11 12 12 12 23 14 15 D) 12 13 14 12 13 14 15 16 R0 = πB (R) (B) 4 5 6 7 8 9 S0 = S ./ R0 (B C D) 4 10 12 4 11 13 7 12 14 Wir sind an einem Verbund von R und S auf Knoten 1 interessiert. Wenn wir S von Knoten 2 nach Knoten 1 schicken, so müssen wir 3 ∗ 8 = 24 Attributwerte übertragen, wobei die letzten 5 Tupel übertragen werden, obwohl wir sie für den Verbund nicht benötigen. Verwenden wir obigen Algorithmus, so übertragen wir zuerst R0 (6 Attributwerte) von Knoten 1 nach 2 und dann S0 (3 ∗ 3 Attributwerte), alle Tupel, die den Verbund mit R eingehen können, von Knoten 2 nach Knoten 1. In diesem Fall übertragen wir in Summe nur 15 Attributwerte. KAPITEL 9. OPTIMIERUNG 9.11 9.4 Übungsbeispiele Übung 9.1 Geben Sie für folgende Ausdrücke den Operatorbaum an, und wenden Sie die algebraische Optimierung darauf an. Die Schemata der Datenbank sind q(AB)D), r(BDF ) und s(F G). 1. σD=d (πBDF (q ./ r) − πBDF (r ./ s)) 2. πAD (q ./ r ./ σG=g (s)) 3. πB (σA=a (σD=d (q) ./ (r − πBDF (r ./ s)))) Übung 9.2 Gegeben sind die Relationen q(ABC), r(BCD) und s(DE) sowie folgender Ausdruck der Relationalen Algebra πAE σB=b πAEB σ(E<e)&(C>c) ((q ./ r) ./ s) Geben Sie den zugehörigen Operationsbaum an und optimieren Sie den Ausdruck algebraisch. Übung 9.3 Gegeben sind die Relationen r(ABC), q(BDF ), s(BEF ) und folgender Ausdruck der Relationenalgebra: πAB σB>b πABC σ(D=d)∨(E=e) (r ./ (q ./ s)) Geben Sie den zugehörigen Operationsbaum an und optimieren Sie den Ausdruck algebraisch. Übung 9.4 Gegeben sind die Relationen q(ABG), r(BCD) und s(CDEF ) und folgender Ausdruck der Relationenalgebra: πAE σE=e πACEG σ(B<b)&(D>d) (q ./ (r ./ s)) Geben Sie den zugehörigen Operationsbaum an und optimieren Sie den Ausdruck algebraisch. Übung 9.5 Gegeben sind die Relationenschemata: p(BCDF G), q(BDF ), r(BCDEG). Optimieren Sie den folgenden algebraischen Ausdruck: σB=3∧D>5 (πBDF (p − (q ./ πCG (r)))) Übung 9.6 Gegeben sind die Relationenschemata: a(BCD), b(ADE), c(ABE). Optimieren Sie den folgenden algebraischen Ausdruck: σB=3∨C<6 πBCD ( (c ./ πCD (a)) ∪ σE6=5 (a ./ b) ) KAPITEL 9. OPTIMIERUNG 9.12 Übung 9.7 Gegeben sind die Relationenschemata: p(ABC), q(CDE), r(ADE). Optimieren Sie den folgenden algebraischen Ausdruck: σB=5∨A<3 πABC ( (r ./ πBC (p)) ∪ σD6=5 (p ./ q) ) Übung 9.8 Gegeben sind die Relationen q(ABE), r(BCDFE) und s(ABD). Optimieren Sie den folgenden Ausdruck algebraisch: πAB σ(D=d)∧(A>a) ((πABD (q ./ r)) − s) Übung 9.9 Gegeben sind folgende zwei Relationen p und q: p (A a1 a1 a2 a2 a2 a2 a2 B b1 b2 b1 b1 b1 b2 b2 C) c1 c1 c2 c4 c6 c8 c9 q (C c1 c1 c3 c5 c6 c7 D) d1 d2 d1 d2 d2 d1 Berechnen Sie p n q. Angenommen p und q sind auf verschiedenen Rechnern, p ./ q wird auf dem Knoten 2 benötigt. Wieviele Attributwerte müssen bei der Bildung von p ./ q übertragen werden, wieviele bei vorheriger Bildung des Semijoin? Übung 9.10 Gegeben sind folgende zwei Relationen r und s: r (A a1 a2 a2 B b1 b2 b2 C) c1 c1 c2 s (B b1 b3 b4 D) d1 d1 d2 Berechnen Sie r n s. Angenommen, r ist auf dem Rechner 1, s auf dem Rechner 2 gespeichert. Sie benötigen r ./ s auf dem Rechner 2. Um wieviele Attributwerte müssen bei vorheriger Bildung des Semiverbundes weniger zwischen den Rechnern übertragen werden als ohne Verwendung eines Semiverbundes? Übung 9.11 Gegeben sind r(A B C) und s(C D E). Berechnen Sie q1 = r n s: r( A B C) a1 b1 c1 a2 b2 c3 a2 b3 c3 s (C D E) c1 d1 e1 c1 d2 e1 c2 d2 e1 c1 d3 e4 KAPITEL 9. OPTIMIERUNG 9.13 Angenommen, r und s sind auf verschiedenen Rechnern, R1 und R2, und r ./ s wird auf dem Rechner R2 benötigt. Wieviele Attributwerte müssen ohne, wieviele mit Verwendung eines Semijoins übertragen werden. Übung 9.12 Ist das Verfahren mit Bilden des Semijoin p n q beschrieben immer effizienter als die normale Vorgangsweise“ ? Begründen Sie die Antwort (Beweis oder Gegenbeispiel). ” Übung 9.13 Welche der Operationen ./ (join) und n (semijoin) sind 1. kommutativ, 2. assoziativ? 9.14 KAPITEL 9. OPTIMIERUNG Kapitel 10 Mehrbenutzerkontrolle (Concurrency Control) In den letzten beiden Kapiteln beschäftigen wir uns mit zwei Grundaufgaben eines Datenbankmanagementsystems, nämlich der parallelen Verarbeitung von Benutzeraufträgen und der Realisierung eines bestimmten Grades der Fehlertoleranz. Da im Allgemeinen mehrere Benutzer gleichzeitig auf eine Datenbank zugreifen, muss das DBMS sicherstellen, dass die Benutzeraufträge einander bei der Abarbeitung nicht stören und die Benutzer auch nichts voneinander bemerken. Diese Anforderungen werden von der Concurrency-Control Komponente eines DBMS erfüllt. Weiters soll das System von sich aus mit gewissen Fehlersituationen, wie etwa einem Plattenfehler, umgehen können. Diese Anforderung wird von der recovery-Komponente des DBMS realisiert. 10.1 Begriffskl¨ arungen Eine Datenbank ist konsistent, wenn sie eine Menge vorgegebener logischer Bedingungen erfüllt, die Integritätsbedingungen genannt werden. Ein Benutzer verwendet eine Datenbank, indem er eine logisch zusammengehörende Folge von Zugriffsbefehlen (Lese- und Schreib-Befehle) auf dieser Datenbank ausführt. Eine derartige Befehlsfolge wird Transaktion genannt und führt die Datenbank von einem konsistenten Zustand in einen anderen, nicht notwendigerweise verschiedenen, konsistenten Zustand über (z.B. Umbuchung von Lohnkonto auf Sparbuch). Beispiel 10.1 Betrachten wir eine Transaktion, die 500 Euro von Konto 123 abbucht und auf das Sparbuch 333 bucht. Wir haben dabei die Relationen Sparbuch(spnr, einlage) und Konto(knr, kstand) zur Verfügung. Die entsprechende Transaktion sieht wie folgt aus: begin transaction update konto 1 KAPITEL 10. CONCURRENCY CONTROL 10.2 set kstand=kstand-500 where knr=123; update sparbuch set einlage=einlage+500 where spnr=333; end transaction Für die Abarbeitung dieser Transaktion muss das DBMS folgende Schritte durchführen: 1. Syntaxüberprüfung und Autorisierungskontrolle 2. Wahl einer Methode zur Ausführung der Operationen (Query-Optimierung) 3. Feststellung, wie die Relationen gespeichert sind und wie auf diese Datenstrukturen zugegriffen werden kann (Indexe) 4. Erzeugung von ausführbarem Code, der • die Relationen aus der Datenbank (dem Hintergrundspeicher) in den DatenbankPuffer (im Hauptspeicher) transferiert, • die oben gewählte Methode implementiert, • das Ergebnis ausgibt. 5. Ausführen des Codes. Wenn wir davon ausgehen, dass wir einen Index über die Attribute knr und spnr angelegt haben, so wäre ein mögliches Programm zur Ausführung der Abfrage: 1. Lade Index von Konto in den Hauptspeicher, suche die passende Kontonummer, lade die entsprechende Seite der Datenbank und verändere den Kontostand. 2. Lade Index von Sparbuch in den Hauptspeicher, suche die passende Sparbuchnummer, lade die entsprechende Seite der Datenbank und verändere den Einlagenstand. Dieser Algorithmus läuft, wie jedes Programm, im Hauptspeicher des betreffenden Datenbankrechners ab, wobei es allerdings Zugriff auf einen Teil des Datenbank-Puffers hat, in welchen Daten aus der Datenbank zur Bearbeitung eingelagert und von wo aus die geänderten Daten wieder in die Datenbank übernommen werden. Für jeden Benutzer einer Datenbank werden die Zugriffe auf die Daten über Transaktionen realisiert. Für jede der Transaktionen werden die oben angeführten Schritte durchgeführt. Daher wird für jede Transaktion ein Programm erstellt und ein eigener Bereich im DatenbankPuffer bereit gestellt, von wo aus die Daten der Datenbank gelesen bzw. wohin sie geschrieben werden. Es kann daher passieren, dass zwei Transaktionen zur gleichen Zeit nicht nur auf KAPITEL 10. CONCURRENCY CONTROL 10.3 derselben Datenbank, sondern auch auf demselben Datensegment arbeiten wollen, z.B. Änderung des Kontostandes des Kontos mit der Kontonummer 123. Beide Transaktionen haben sich die Datenbankseite mit dem aktuellen Kontostand in ihren privaten Datenbank-Puffer geladen und verändern den Kontostand. Danach wird die veränderte Datenbankseite wieder in die Datenbank im Hintergrundspeicher geschrieben. In diesem Fall ist eine Synchronisation notwendig, damit die Effekte auf der Datenbank so sind, als ob zuerst die eine Transaktion, danach die zweite Transaktion den Kontostand geändert hätte. Definition 10.1 Mehrere Transaktionen heißen parallel, wenn ihr Programmcode gleichzeitig im Hauptspeicher des Datenbankrechners existiert. Wenn wir eine Transaktion als ein Datenbankprogramm betrachten, so sehen wir, dass der eigentlich kritische Punkt an der Abarbeitung jener ist, wo die Daten aus der Datenbank gelesen, bzw. in die Datenbank geschrieben werden, da diese Zugriffe sich unter Umständen gegenseitig stören können. Die restliche Ausführung des Programmes läuft unter der Kontrolle des jeweiligen Betriebssystems ab. Diese Abstraktion einer Transaktion auf Lese- und Schreibzugriffe ist ausreichend, um eine Theorie der Synchronisation und der Fehlerbehandlung aufbauen zu können, die in den kommerziellen Systemen angewendet wird. 10.1.1 Synchronisationsprobleme Wir wollen nun anhand von drei Beispielen aufzeigen, zu welchen Problemen es kommen kann, wenn mehrere Transaktionen auf dieselben Daten zugreifen, diese Zugriffe aber nicht korrekt synchronisiert sind. Beispiel 10.2 Zwei Transaktionen T1 und T2 wollen dasselbe Datenobjekt x (z.B. den Kontostand des Kontos 123) verändern, nämlich im ersten Fall 2.000 Euro aufbuchen, im zweiten Fall 5.000 Euro abbuchen. Zeit 1 2 3 4 5 6 T1 READ(x) T2 READ(x) UPDATE(x) UPDATE(x) WRITE(x) WRITE(x) Dieses Problem nennt sich Lost Update, denn das Update der Transaktion T 1 geht verloren. Generell ist unerheblich, was die Transaktionen in ihrem Puffer mit dem Objekt x machen, entscheidend ist, dass T2 unkontrolliert auf die Datenbank schreibt und dadurch die Schreiboperation von T1 überschreibt. KAPITEL 10. CONCURRENCY CONTROL 10.4 Beispiel 10.3 Zwei Transaktionen T1 und T2 wollen dasselbe Datenobjekt x verändern. Die erste Transaktion wird aber nach der Veränderung von x aufgrund eines Fehlers abgebrochen. Zeit 1 2 3 4 5 6 7 T1 T2 READ(x) UPDATE(x) WRITE(x) READ(x) UPDATE(x) ABORT WRITE(x) Offensichtlich liest T2 einen falschen Wert, da nach dem Abbruch von T1 die Veränderungen von T1 wieder rückgängig gemacht werden müssen. Dieses Problem nennt sich Dirty Read. Beispiel 10.4 Eine Transaktion T1 berechnet die Summe dreier Werte, z.B. dreier Kontostände, während T2 eine Umbuchung von einem der drei Kontos auf ein zweites durchführt. Zeit 1 2 3 4 5 6 7 8 9 10 11 12 13 T1 SUM := 0 READ(x) READ(y) SUM := SUM + x SUM := SUM + y T2 READ(z) UPDATE(z) WRITE(z) READ(x) UPDATE(x) WRITE(x) READ(z) SUM := SUM + z T1 berechnet offensichtlich den falschen Wert, da sie den Wert von x vor der Veränderung, den Wert von z aber erst nach der Veränderung durch T 2 liest. Dieses Problem heißt Inconsistent Read oder Unrepeatable Read. Um bei der Abarbeitung mehrerer paralleler Transaktionen solchen Problemen aus dem Weg zu gehen, ist eine Synchronisation der einzelnen Lese- und Schreibzugriffe auf die Datenbank notwendig, die auch mit bestimmten Fehlersituationen (etwa Transaktionsabbrüchen) umgehen kann. Das Transaktionskonzept dient dazu, diese Probleme zu lösen, damit es nach außen für jeden Benutzer scheint, als ob nur seine Abfrage aktiv sei und verschiedene Transaktionen immer nur seriell, d.h. eine nach der anderen und nicht parallel, so wie in den drei letzten Beispielen, ablaufen. KAPITEL 10. CONCURRENCY CONTROL 10.5 10.1.2 ACID Eigenschaften von Transaktionen Wir erwarten klarerweise, dass eine Transaktion wie geplant abläuft und die vorgesehenen Schritte tätigt. Bei der Ausführung von einer bzw. von mehreren Transaktionen kann es aber zu Störungen bzw. Fehlern kommen, die das verhindern. Um diese Störungen auszuschließen, werden gewisse Eigenschaften von Transaktionen gefordert. Diese sind Atomarität, Parallelität, Isolation und Dauerhaftigkeit. Nach den Anfangsbuchstaben der englischen Bezeichnungen werden sie auch ACID Eigenschaften genannt. Atomarität (atomicity): Eine Transaktion wird entweder zur Gänze oder gar nicht ausgeführt. Wenn nicht alle Operationen einer Transaktion ausgeführt werden können, so muss diese abgebrochen werden, und bereits ausgeführte Änderungen müssen rückgängig gemacht werden. Beispiel 10.5 Bei der Umbuchungstransaktion aus Beispiel 10.1 müssen wir sicherstellen, dass beide Aktionen durchgeführt werden, einerseits die Abbuchung vom Lohnkonto, andererseits die Buchung auf das Sparbuch. Bricht die Transaktion nach der Abbuchung und vor der Buchung ab, so wäre das eine Verletzung der Atomarität. Parallelität (concurrency): Das Gesamtergebnis einer parallelen Ausführung von Transaktionen entspricht irgendeiner Hintereinanderausführung dieser Transaktionen. (Da eine Transaktion alleine konsistenzerhaltend ist, ist auch eine Hintereinanderausführung konsistenzerhaltend.) Beispiel 10.6 Angenommen neben der Umbuchungstransaktion aus Beispiel 10.1 findet eine Transaktion statt, die eine Bankomatbehebung vom Lohnkonto abbucht. Der Gesamteffekt ist entweder: 1. vom Lohnkonto abbuchen und am Sparbuch aufbuchen, 2. vom verringerten Lohnkontostand den am Bankomat abgehobenen Betrag abziehen. oder 1. Lohnkontostand um den beim Bankomat abgehobenen Betrag verringern, 2. vom verringerten Lohnkontostand abbuchen und am Sparbuch aufbuchen. Isolation: Teilergebnisse von Transaktionen bleiben bis zum Ende der Transaktion für alle anderen Transaktionen unsichtbar. Beispiel 10.7 Bei der Umbuchungstransaktion wird die Abbuchung vom Lohnkonto erst sichtbar, nachdem auch die Aufbuchung aufs Sparbuch durchgeführt worden ist. Dauerhaftigkeit (durability): Die Ergebnisse einer erfolgreich durchgeführten Transaktion bleiben erhalten. KAPITEL 10. CONCURRENCY CONTROL 10.6 Beispiel 10.8 Nach der Durchführung der Umbuchung muss der neue Kontostand sowohl auf dem Lohnkonto als auch auf dem Sparbuch aufscheinen und kann nicht mehr etwa aus Systemgründen rückgängig gemacht werden. Die Gewährleistung von Atomarität und Dauerhaftigkeit wird von einer Recovery Komponente (siehe Kapitel 11) übernommen, die Sicherstellung der Isolation verhindert Probleme wie das Dirty Read, Konsistenzerhaltung wird durch eine Komponente für Concurrency Control sichergestellt. Im Concurrency Control wird dabei ein Verfahren verwendet, das die Serialisierbarkeit von parallel ablaufenden Transaktionen gewährleistet. 10.1.3 Ausführung mehrerer Transaktionen Wir nehmen ein vereinfachtes Modell der Datenbank an. Sie besteht aus atomaren Objekten, die jeweils einen Namen und einen Wert haben. Der Zugriff auf diese Objekte geschieht mittels der zwei atomaren Operationen READ und WRITE, die einerseits den Wert eines Objektes lesen und andererseits den Wert eines Objektes schreiben. Beispiel 10.9 In unserem Modell sehen die Transaktionen folgendermaßen aus: Sei T 1 eine Transaktion, die eine Überweisung von einem Konto auf ein Sparbuch vornimmt und T 2 eine Transaktion, die die Überweisung einer Telefonrechnung erledigt. Zeit 1 2 3 4 5 6 7 8 T1 T2 READ Konto WRITE Konto READ Sparbuch WRITE Sparbuch READ Konto WRITE Konto READ TEL-Konto WRITE TEL-Konto Definition 10.2 Eine Transaktion T ist eine Folge von Paaren (a1 ,e1 ), . . . , (ai ,ei ), . . . ,(an ,en ), i = 1 . . . n, von Operationen ai auf Objekten ei . Ein Paar (ai ,ei ) nennt man einen Transaktionsschritt, mit |T | bezeichnen wir die Anzahl der Schritte n. Ein Transaktionsschritt zusammen mit der Angabe der ihn ausführenden Transaktion T wird als Ausführungsschritt bezeichnet: (T ,ai ,ei ) Definition 10.3 Die Ausführung I einer Transaktionsmenge T = {T1 , T2 , . . . , Tn } ist eine beliebige Folge von Ausführungsschritten I(k) = (Tj , ai , ei ), k = 1, . . . , m, die folgende Bedingungen erfüllt: P 1. m = nj=1 |Tj |, d.h., I enhält genau soviele Ausführungsschritte wie alle Transaktionen Tj Transaktionsschritte in Summe; KAPITEL 10. CONCURRENCY CONTROL 10.7 2. j ∈ {1, . . . , n} und i ∈ {1, . . . , |Tj |}, d.h., I enthält nur Ausführungsschritte von Transaktionen Tj aus T; und 3. ist I(k) = (Tj , aik , eik ) und I(`) = (Tj , ai` , ei` ) und k < `, dann gilt ik < i` , d.h., alle Transaktionsschritte (ai , ei ) ∈ Tj finden in I in derselben Reihenfolge statt wie in Tj . I(k) wird k-ter Ausführungsschritt genannt. Die Schreibweise I(k) = (T j , ai , ei ) besagt, dass der i-te Transaktionsschritt der Transaktion Tj der k-te Ausführungsschritt in I ist. Definition 10.4 Eine Ausführung I von T ist seriell, wenn für jede Transaktion aus T gilt, dass alle ihre Ausführungsschritte in I unmittelbar hintereinander liegen, d.h., wenn I(k) = (Tj , aik , eik ), I(k ∗ ) = (Tj , aik∗ , eik∗ ), und I(`) = (Tj ∗ , ai` , ei` ) mit k ≤ ` ≤ k ∗ , dann gilt j = j ∗ . (Intuitiv ist I ist von der Form Tπ1 , Tπ2 , . . . , Tπn , wobei π eine Permutation von 1, . . . , n ist.) Beispiel 10.10 Die eben formal definierten Begriffe wollen wir anhand des Beispiels 10.9 anwenden. Ein Transaktionsschritt ist z.B. das Paar (READ, Konto), ein Ausführungsschritt das Paar (T2, WRITE, TEL-Konto). Eine Ausführung von T= {T1,T2} ist z.B. jene, die in Beispiel 10.9 gegeben ist. Sie ist auch seriell. Würden in einem DBMS nur serielle Transaktionen zugelassen, so müssten wir uns nicht um Synchronisation kümmern, denn es könnte zu keinen wie auch immer gearteten Problemen kommen. Durch eine strikte Hintereinander-Ausführung von Transaktionen wäre die Performance des Systems jedoch nicht sehr hoch. Denn bevor ein Benutzer seine Abfrage starten könnte, müsste er warten, bis alle anderen Abfragen, die vor der seinen gestartet wurden, abgearbeitet sind. Daher ist es notwendig, dass wir auch verzahnte Ausführung von Transaktionen erlauben, d.h. aus der Sicht des Benutzers existieren die Transaktionen parallel im System. Wir wollen in den nächsten Abschnitten untersuchen, welche Klasse von Transaktionen einerseits Parallelität erlauben, andererseits aber Probleme, wie wir sie in den Beispielen 10.2, 10.3 und 10.4 gesehen haben, vermeiden. 10.1.4 Konfliktrelation einer Ausführung Bei der Ausführung von mehreren Operationen auf einem Objekt spielt die Reihenfolge der einzelnen Operationen im allgemeinen eine Rolle. Die Probleme in den Beispielen 10.2, 10.3, 10.4 kommen, wie wir leicht sehen können, daher, dass die einzelnen Transaktionen nicht hintereinander, sondern parallel ablaufen. Definition 10.5 Operationen ai , aj auf einem Objekt, deren Reihenfolge eine Rolle spielt, nennen wir Konfliktoperationen und sprechen von einem Konflikt, wenn a i und aj zu verschiedenen Transaktionen gehören. 10.8 KAPITEL 10. CONCURRENCY CONTROL Wie wir leicht sehen, stellen die Paare (WRITE, WRITE), (WRITE, READ) und (READ, WRITE) Konfliktoperationen dar, das Paar (READ, READ) hingegen nicht. Die Konflikte zwischen Transaktionen werden in der Konfliktrelation erfasst. Definition 10.6 Sei I eine Ausführung einer Menge T von Transaktionen auf einer Menge von Objekten E. Die Konfliktrelation D(I) ist jene Teilmenge T ×E× T, die wie folgt definiert ist: (Ti , e, Tj ) ist in D(I) genau dann, wenn es k und l ,1 ≤ k < l ≤ |I|, I(k) = (T i , ain , e), I(l) = (Tj , ajm , e) gibt, so dass gilt: 1. Ti 6= Tj und (ain = WRITE oder ajm = WRITE) 2. Es gibt kein h für k < h < l, sodass I(h) = (Tg , ago , e) wobei Tg 6= Ti und Tg 6= Tj und ago = WRITE Entsprechend dieser Definition gehört ein Tupel (Ti , e, Tj ) zur Konfliktrelation D(I), wenn die folgenden Bedingungen erfüllt sind: Im Schritt k einer Ausführung I wird durch eine Transaktion Ti eine Operation ain auf einem Objekt e ausgeführt. In einem späteren Schritt l der Ausführung I wird durch eine andere Transaktion Tj eine Operation ajm auf demselben Objekt e ausgeführt. Mindestens eine der beiden Operationen ist eine Schreib-Operation. In den Ausführungsschritten dazwischen wird keine Schreib-Operation auf e ausgeführt. Definition 10.7 Zwei Ausführungen I1 und I2 über derselben Transaktionsmenge T heißen (konflikt-)äquivalent genau dann, wenn ihre Konfliktrelationen D(I1 ) und D(I2 ) identisch sind. Beispiel 10.11 Betrachten wir drei verschiedene parallele Ausführungen I 1 , I2 und I3 von zwei Transaktionen T1 und T2 : T1 T2 READ A WRITE A READ A WRITE A READ B WRITE B READ B WRITE B I1 T1 T2 READ A WRITE A READ B WRITE B READ A WRITE A READ B WRITE B I2 T1 READ A WRITE A T2 READ A WRITE A READ B WRITE B READ B WRITE B I3 KAPITEL 10. CONCURRENCY CONTROL 10.9 Die Konfliktrelation von I1 ist D(I1 ) = {(T1 , a, T2 ), (T1 , b, T2 )}, die Konfliktrelation von I2 ist D(I2 ) = {(T1 , a, T2 ), (T1 , b, T2 )}. Da I1 und I2 dieselbe Konfliktrelation haben, sind I1 und I2 konfliktäquivalent. Die Konfliktrelation von I3 ist D(I3 ) = {(T1 , a, T2 ), (T2 , b, T1 )}. Sie stimmt mit den Konfliktrelationen der beiden anderen Ausführungen nicht überein. 10.1.5 Serialisierbarkeit Definition 10.8 Eine Ausführung I1 heißt serialisierbar genau dann, wenn es eine zu I1 äquivalente serielle Ausführung I2 gibt. Serialisierbarkeit besagt, dass eine Ausführung I einer anderen seriellen Ausführung entspricht; dies sichert die Konsistenz-Eigenschaft von Transaktionen. Die serialisierbaren Transaktionen sind also jene Transaktionen, die, da sie zu seriellen Transaktionen äquivalent sind, Probleme vermeiden. Theorem 10.1 Eine Ausführung I über einer Transaktionsmenge T ist genau dann serialisierbar, wenn es eine lineare Ordnung “<” auf T gibt, so dass f ür jedes Paar I(k) = (Ti , a, e), I(l) = (Tj , a0 , e), wo Ti 6= Tj und a, a0 Konfliktoperationen sind, gilt: k < l ⇔ Ti < T j . Es gibt in der Datenbankliteratur auch noch einen schwächeren Begriff der Serialisierbarkeit. Eine Ausführung heißt demnach effektserialisierbar (view-serializable), wenn sie denselben Output und dieselben Effekte auf eine Datenbank hat, wie eine beliebige serielle Ausführung. Es ist natürlich klar, dass jede in unserem Sinn serialisierbare Ausführung auch effektserialisierbar ist. Die Umkehrung muss damit aber nicht gelten. Unsere Serialisierbarkeit ist eine hinreichende, aber keine notwendige Bedingung dafür, dass eine gegebene parallele Ausführung von Transaktionen effektserialisierbar ist. Sie ist nur dann eine notwendige Bedingung, wenn die Constrained Write Assumption (CWA) gilt. Die CWA besagt, dass alle Transaktionen vor einem Schreibzugriff auf ein Objekt dieses auch lesen müssen. Wenn Transaktionen Objekte ohne vorheriges Lesen überschreiben können, so kann Effektserialisierbarkeit auch dann vorliegen, wenn es keine äquivalente serielle Ausführung gibt. Wir gehen aber im Folgenden davon aus, dass die CWA gilt. Beispiel 10.12 Betrachten wir nochmals die drei verschiedenen Ausführungen I 1 , I2 und I3 aus Beispiel 10.11. I2 ist eine mögliche serielle Ausführung. Da I1 und I2 äquivalent sind, ist I1 serialisierbar. Die Konfliktrelation von I3 ist nicht gleich der Konfliktrelation von I2 . Wir können daraus aber nicht schließen, dass I3 nicht serialisierbar ist, da wir zuerst überprüfen müssen, ob es nicht vielleicht eine andere serielle Ausführung gibt, zu der I 3 äquivalent ist. Bei zwei Transaktionen gibt es zwei mögliche serielle Ausführungen: T1 vor T2 bzw. T2 vor T1 . Die KAPITEL 10. CONCURRENCY CONTROL 10.10 Konfliktrelation für die zweite serielle Ausführung ist D(I4 ) = {(T2 , a, T1 ), (T2 , b, T1 )}. I3 ist auch zu dieser Konfliktrelation nicht äquivalent, daher ist I3 nicht serialisierbar. 10.1.6 Test auf Serialisierbarkeit Die Serialisierbarkeit von Ausführungen kann auch mit graphentheoretischen Mitteln überprüft werden, denn im Allgemeinen ist es langwierig, alle Konfliktrelationen der n! seriellen Ausführungen von n Transaktionen zu finden. Definition 10.9 Der Präzedenzgraph für eine Ausführung I über einer Transaktionsmenge T ist ein gerichteter Graph G(T ) = (N, E), dessen Knoten N die Transaktionen in T sind, und in dem eine Kante von Ti nach Tj führt, genau dann wenn (Ti , e, Tj ) ∈ D(I), d.h., • Tj liest oder schreibt ein Objekt, das zuletzt von Ti geschrieben wurde, oder • Ti liest ein Objekt, auf das Tj danach als erste Transaktion schreibt. Die Kanten Ti → Tj in G werden manchmal mit einer Liste jener Objekte e markiert, für die (Ti , e, Tj ) ∈ D(I) gilt. Theorem 10.2 Eine Ausführung I ist serialisierbar genau dann, wenn der Präzedenzgraph G(I) zyklenfrei ist. Durch topologisches Sortieren erhält man eine äquivalente serielle Ausführung. Der Präzedenzgraph gibt uns auch die lineare Ordnung auf T, da diese nat ürlich nur dann existiert, wenn der Graph azyklisch ist. Beispiel 10.13 Wenn wir wieder die Transaktionen aus dem Beispiel 10.11 betrachten, so erhalten wir für I1 und I2 denselben zyklenfreien Präzedenzgraphen. G(I1 ) gibt uns die lineare Ordnung T1 < T2 . Für I3 hingegen ist der Präzedenzgraph zyklisch. a a,b T1 T2 G(I1 ) = G(I2 ) T1 T2 b G(I3 ) 10.2 Sperrprotokolle Die am weitesten verbreitete Methode, Serialisierbarkeit von Ausführungen zu erlangen, ist dynamisches Sperren und Freigeben von Objekten einer Datenbank. Sperren ist eine Aktion auf einem Objekt, die eine Transaktion durchführt, um dieses Objekt vor Zugriffen durch andere Transaktionen zu schützen, während es in einem inkonsistenten Zustand ist. Sperren werden benutzt, um die relative Abfolge von in Konflikt stehenden Operationen zu kontrollieren. KAPITEL 10. CONCURRENCY CONTROL 10.11 10.2.1 Gültige Ausführungen Definition 10.10 Eine Ausführung heißt gültig, wenn für jeden Ausführungsschritt gilt: wenn ein Objekt von einer Transaktion gesperrt ist, dann ist es durch keine weitere Transaktion gesperrt. D.h., für die Gültigkeit einer Ausführung ist es belanglos, ob auf die gesperrten Objekte auch tatsächlich zugegriffen wird. Beispiel 10.14 Betrachten wir die beiden Transaktionen T1 und T2 . Zeit 1 2 3 4 5 6 T1 LOCK A WRITE A LOCK B UNLOCK A WRITE B UNLOCK B Zeit 1 2 3 4 5 6 7 8 T2 LOCK A WRITE A LOCK B WRITE B WRITE A UNLOCK A WRITE B UNLOCK B Folgende Tabelle zeigt zwei gültige Ausführungen I1 und I2 dieser beiden Transaktionen: Zeit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 T1 T2 LOCK A WRITE A LOCK B UNLOCK A LOCK A WRITE A WRITE B UNLOCK B LOCK B WRITE B WRITE A UNLOCK A WRITE B UNLOCK B Zeit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 T1 T2 LOCK A WRITE A LOCK B WRITE B WRITE A UNLOCK A LOCK A WRITE A WRITE B UNLOCK B LOCK B UNLOCK A WRITE B UNLOCK B Die Abhängigkeitsrelationen der obigen Ausführungen sind: D(I1 ) = {(T1 , A, T2 ), (T1 , B, T2 )} D(I2 ) = {(T2 , A, T1 ), (T2 , B, T1 )} KAPITEL 10. CONCURRENCY CONTROL 10.12 10.2.2 Wohlgeformte Transaktionen Definition 10.11 Eine Transaktion ist wohlgeformt, wenn sie folgende Bedingungen erfüllt: 1. Eine Transaktion greift auf ein Objekt nur zu, wenn sie dieses zuvor gesperrt hat. 2. Eine Transaktion sperrt niemals ein Objekt, das sie bereits selbst gesperrt hat. 3. Eine Transaktion versucht niemals, ein Objekt freizugeben, das sie nicht zuvor gesperrt hat. 4. Vor Beendigung einer Transaktion werden die Sperren auf alle Objekte, die von ihr gesperrt wurden, wieder freigegeben. Sperren alleine ist nicht hinreichend, damit eine Transaktion im allgemeinen Fall serialisierbar ist. Die Ausführung in Beispiel 10.15 ist nicht serialisierbar, obwohl jedes Objekt vor dem Schreiben gesperrt wurde. Der Präzedenzgraph enthält einen Zyklus. Beispiel 10.15 Betrachten wir die folgende Ausführung der Transaktionen T 1 und T2 Zeit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 T1 T2 LOCK a LOCK c WRITE a WRITE c UNLOCK a LOCK a WRITE a LOCK b UNLOCK a WRITE b UNLOCK b UNLOCK c LOCK b WRITE b UNLOCK b LOCK c WRITE c UNLOCK c Der dazugehörige Präzedenzgraph sieht folgendermaßen aus: a,c T1 T2 b KAPITEL 10. CONCURRENCY CONTROL 10.13 10.2.3 Das 2-Phasen-Sperrverfahren (2-Phase-Locking) Definition 10.12 Eine Transaktion T = h(ai , ei )i, i = 1, . . . , n ist eine 2-Phasen-Transaktion, wenn für ein j < n und für alle i = 1, . . . , n gilt: 1. i < j ⇒ ai 6= UNLOCK 2. i = j ⇒ ai = LOCK 3. i > j ⇒ ai 6= LOCK Die Schritte 1, 2, . . . , j sind die Sperrphase, die Schritte j + 1, . . . , n sind die Schrumpfungsphase der Transaktion. Der Zeitpunkt des Belegens der letzten Sperre wird als Sperrpunkt (locked point) bezeichnet. Sperren locked point Wachstumsphase Schrumpfungsphase Zeit Eine hinreichende Bedingung für Serialisierbarkeit ist nun die folgende: Theorem 10.3 Wenn alle Transaktionen einer Transaktionsmenge T wohlgeformt und 2-PhasenTransaktionen sind, dann ist jede gültige Ausführung von T serialisierbar. Die Serialisierungsreihenfolge einer solchen Ausführung entspricht der Reihenfolge der Sperrpunkte der einzelnen Transaktionen aus T. Beispiel 10.16 Die folgenden beiden Tabellen zeigen zwei Transaktionen, von denen die erste das 2-Phasen-Sperrprotokoll erfüllt, die zweite nicht. T1 LOCK a LOCK b LOCK c UNLOCK c UNLOCK a UNLOCK b locked point T2 LOCK a LOCK b UNLOCK a LOCK c ←− Nicht 2-Phasen UNLOCK c UNLOCK b In der Praxis werden meist alle UNLOCK-Befehle bis zum Ende der Transaktion verzögert und/oder zu einem Befehl (COMMIT) zusammengefasst, der gleichzeitig das Ende der Transaktion darstellt. KAPITEL 10. CONCURRENCY CONTROL 10.14 10.2.4 Deadlock Dynamisches Sperren von Objekten führt zum Problem des Deadlocks. Deadlocks müssen entweder von vornherein vermieden oder erkannt und aufgelöst werden. T1 LOCK a T2 LOCK b (LOCK b) (LOCK a) ← T1 wartet auf b ← T2 wartet auf a 10.2.5 Das Baumprotokoll In diesem und im nächsten Abschnitt wollen wir zwei Sperrverfahren vorstellen, die Serialisierbarkeit sicherstellen. Das erste, das Baumprotokoll, ist auch deadlockfrei. Gehen wir davon aus, dass wir eine Ansammlung von Objekten, wie z.B. Datenbanken, Anwendungen (Menge von Relationen), Relationen, oder Tupel als Knoten eines Baumes gespeichert haben. Dieser Baum kann z.B. ein B ∗ -Baum (siehe: VO Algorithmen und Datenstrukturen) sein. Definition 10.13 Eine Transaktion T erfüllt das Baumprotokoll, wenn gilt: 1. Ein Objekt O wird nur dann von T gesperrt, wenn T bereits eine Sperre auf den Vater von O hält. 2. Regel 1. gilt nicht für das erste Objekt im Baum, das von T gesperrt wird. 3. Ein Objekt O, das von einer Transaktion T gesperrt und wieder freigegeben wurde, kann von T anschließend nicht mehr gesperrt werden. Eine hinreichende Bedingung für Serialisierbarkeit ist nun: Theorem 10.4 Wenn alle Transaktionen einer Transaktionsmenge T wohlgeformt sind und das Baumprotokoll erfüllen, dann ist jede gültige Ausführung von T serialisierbar. Beispiel 10.17 Betrachten wir den folgenden Baum mit der dazugehörigen Ausführung I. Die Transaktionen T1 , T2 und T3 erfüllen das Baumprotokoll, die Transaktionsmenge T ist wohlgeformt und I ist gültig. Aus diesem Grund ist I serialisierbar, mit T 1 < T3 < T2 oder T3 < T 1 < T 2 KAPITEL 10. CONCURRENCY CONTROL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 T1 LOCK A LOCK B LOCK D UNLOCK B T2 10.15 T3 LOCK B A LOCK C LOCK E B UNLOCK D C LOCK F UNLOCK A D E LOCK G UNLOCK C UNLOCK E F G LOCK E UNLOCK F UNLOCK B UNLOCK G UNLOCK E 10.2.6 Das Hierarchische Sperrprotokoll Beim Hierarchischen Sperrprotokoll betrachten wir zwei Arten von Sperren, das Exclusive Lock (X-Sperre) und das Intention Lock (I-Sperre). Das Intention Lock ist eine Absichtser” klärung“, dass später ein Subobjekt (Teilbaum) gesperrt wird. Definition 10.14 Eine wohlgeformte 2-Phasen-Transaktion T gehorcht dem Hierarchischen Sperrprotokoll, wenn gilt: 1. T greift auf die Knoten des Baumes in hierarchischer Reihenfolge von der Wurzel ausgehend zu. 2. T sperrt einen Knoten K nur dann, wenn sie eine I-Sperre auf alle Vorgänger von K besitzt.1 3. T gibt einen Knoten K erst dann frei, wenn sie alle Nachfolger von K freigegeben hat. Eine hinreichende Bedingung für Serialisierbarkeit ist nun: 1 Es ist nicht nötig einen Knoten mit einer X-Sperre zu belegen, wenn sein Vorgängerknoten schon eine XSperre besitzt. KAPITEL 10. CONCURRENCY CONTROL 10.16 Theorem 10.5 Wenn alle Transaktionen einer Transaktionsmenge T wohlgeformt sind und das Hierarchische Sperrprotokoll erfüllen, dann ist jede gültige Ausführung von T serialisierbar. Kompatibilitätsrelation: Sperranforderung I-Lock X-Lock Bestehende Sperre I-Lock X-Lock + − − − + . . . Verträglich, − . . . Konflikt Beispiel 10.18 Betrachten wir den folgenden Baum mit der dazugehörigen Ausführung I. Die Transaktionen T1 , T2 und T3 erfüllen das Hierarchische Sperrprotokoll, die Transaktionsmenge T ist wohlgeformt und I ist gültig. Aus diesem Grund ist I serialisierbar, mit T1 < T2 < T3 oder T2 < T1 < T3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14 15. 16. 17. 18. 19. 20. T1 I-LOCK A T2 T3 I-LOCK A I-LOCK B I-LOCK A I-LOCK B X-LOCK E X-LOCK D A UNLOCK E UNLOCK D B UNLOCK B UNLOCK A C UNLOCK B X-LOCK B I-LOCK C X-LOCK F D E F G UNLOCK A UNLOCK UNLOCK UNLOCK UNLOCK B F C A In den meisten kommerziellen DBMS gibt es noch einen weiteren Sperrtyp: das S-LOCK (Shared lock), das verwendet wird, wenn ein Objekt nur zum Lesen gebraucht wird. Wie wir KAPITEL 10. CONCURRENCY CONTROL 10.17 aus der folgenden Kompatibilitätstabelle sehen, kann eine Transaktion für ein Objekt, auf dem eine andere Transaktion schon ein S-lock hält, auch ein S-lock erhalten, ohne dass sie auf die Freigabe des Objekts warten muss. Kompatibilitätsrelation: Sperranforderung S-Lock X-Lock Bestehende Sperre S-Lock X-Lock + − − − + . . . Verträglich, − . . . Konflikt 10.3 Zeitstempelverfahren (Time Stamping) Beim Zeitstempelverfahren wird ein Konflikt nicht durch das Setzen von Sperren vermieden, sondern wenn ein Konflikt entdeckt wird, wird die Transaktion, die zu dem Konflikt geführt hat abgebrochen und neu gestartet. Zum Erkennen von Konflikten werden Transaktionen und Datenbankobjekten Zeitstempel (timestamps) zugeordnet: • Jede Transaktion erhält als eindeutigen Zeitstempel den Zeitpunkt des Transaktionsbeginns. • Jedes Datenbankobjekt übernimmt sowohl den Zeitstempel der letzten zugreifenden Schreib-Transaktion, als auch den der letzten Lese-Transaktion. Durch folgende Bedingungen wird die Konsistenz der Datenbank sichergestellt: 1. Eine Transaktion mit Zeitstempel t1 darf ein Objekt mit Schreibstempel tw nicht lesen, wenn tw > t1 gilt, also das Objekt bereits von einer jüngeren Transaktion verändert wurde. Die Transaktion muss in diesem Fall abgebrochen werden. 2. Eine Transaktion mit Zeitstempel t1 darf ein Objekt mit Lese-Zeitstempel tr nicht verändern, wenn tr > t1 gilt, also das Objekt bereits von einer jüngeren Transaktion gelesen wurde. Die Transaktion muss in diesem Fall abgebrochen werden. Eine abgebrochene Transaktion wird neu gestartet und erhält die dem Zeitpunkt des Neustarts entsprechende Zeitmarke. Zu beachten ist, dass zwei Lesezugriffe keinen Konflikt darstellen, und von zwei Schreibzugriffen nur der jüngere - d.h., der von der später gestarteten Transaktion durchgeführte erhalten bleibt, da der ältere Wert überschrieben bzw. gar nicht geschrieben wird. Die Serialisierungsreihenfolge der Transaktionen entspricht der Reihenfolge der Zeitstempel, also der Startzeitpunkte. 10.18 KAPITEL 10. CONCURRENCY CONTROL Um beim Abbruch einer Transaktion alle bereits erfolgreich durchgeführten Operationen dieser Transaktion rückgängig machen zu können, werden die geänderten Werte eines Objekts vorerst in einen zu dem Objekt gehörenden privaten Arbeitsbereich geschrieben (Phase 1); erst bei der erfolgreichen Beendigung der Transaktion werden die geänderten Werte in die Datenbank übernommen (Phase 2). Wir geben nun einen Algorithmus an, der bei diesem Verfahren Zeitstempel verändert und gegebenenfalls Transaktionen abbricht. Angenommen, die Transaktion T will die Operation X auf dem Datenbankobjekt O ausführen. Sei t der Zeitpunkt des Beginns von T , tr der Lesestempel von O, tw der Schreibstempel von O. Nach den Werten dieser Stempel wird genau eine der Aktionen (1) bis (4) ausgeführt. Algorithmus T IM EST AM P INPUT: X Operation der Transaktion T auf einem Datenobjekt O OUTPUT: Lese- oder Schreibstempel von O oder Abbruch von T (1) if X = READ and t ≥ tw then READ if t > tr then tr := t endif; endif; (2) if X = WRITE and t ≥ tr and t ≥ tw then WRITE tw := t; endif; (3) if X = WRITE and tr ≤ t < tw then {do nothing} endif; (4) if (X = READ and t < tw ) or (X = WRITE and t < tr ) then abort(T ) endif; Im Fall (3) ist zu beachten: da die aktuelle Schreiboperation keinerlei Effekte auf die Datenbank hat, kann sie ignoriert werden. Beispiel 10.19 Seien T1 , T2 , T3 drei Transaktionen mit den Zeitstempeln 200, 150 und 175. Zu Beginn der Ausführung haben alle Objekte sowohl Lese- als auch Schreibstempel auf Null gesetzt. Da T1 als erstes auf B lesend zugreifen will, wird der Lesestempel von B auf 200 gesetzt. Danach werden die anderen beiden Lesestempel gesetzt nach (1), T 1 greift schreibend auf B zu, der Schreibstempel wird nach (2) gesetzt. Dasselbe passiert auch mit A. Nun will T2 C beschreiben; der Zeitstempel von T2 ist 150, C hat aber einen Lesestempel von 175. KAPITEL 10. CONCURRENCY CONTROL 10.19 Deshalb wird T2 nach (4) abgebrochen. T3 will noch auf A schreiben, was nach (3) auch geht. T2 bekommt einen neuen Zeitstempel, der größer als 200 ist, z.B. 250. Die Reihenfolge der Transaktionen ist nun: T3 < T1 < T2 . T1 200 1. 2. 3. 4. 5. 6. 7. T2 150 T3 175 A RT = 0 WT = 0 READ B READ A B RT = 0 WT = 0 RT = 200 C RT =0 WT = 0 RT = 150 READ C WRITE B WRITE A RT = 175 WT = 200 WT = 200 WRITE C WRITE A WT = 200 Beim Zeitstempelverfahren gibt es keine Deadlocks wie beim Sperrverfahren. Allerdings kann es auch hier zu unbeschränkter Verzögerung kommen, durch eine unendliche Folge von Abbrüchen, einem sogenannten Livelock (indefinite postponement): T1 100 1. 2. 3. 4. 5. 6. 7. T2 110 T1 120 T2 130 A RT = 0 WT = 0 WRITE B WRITE A B RT =0 WT = 0 WT = 100 WT = 110 READ A WRITE B WT = 120 READ B WRITE A WT =130 READ A Nach dem Abbruch von T1 wird diese Transaktion neu gestartet. Es tritt wieder ein Konflikt mit T2 auf, diesmal wird T2 abgebrochen und neu gestartet. Durch zyklisches Abbrechen tritt eine unbeschränkte Verzögerung auf. 10.4 Transaktionen in SQL In SQL gibt es keinen speziellen Befehl zum Starten einer Transaktion. Die meisten SQLStatements können nur innerhalb einer Transaktion ablaufen (z.B. SELECT, INSERT, CREATE TABLE, nicht aber z. B. CONNECT). Soll ein solches Statement bearbeitet werden und es ist noch keine Transaktion aktiv, wird vom System implizit eine Transaktion gestartet. Eine Transaktion wird mit dem Befehl COMMIT beendet. Alle durchgeführten Änderungen werden dadurch dauerhaft gespeichert. Eine Transaktion kann mit ROLLBACK abgebrochen werden. Alle durchgeführten Änderungen werden ungültig und dadurch zurückgenommen. Mit SET TRANSACTION können verschiedene Attribute gesetzt werden. 10.20 KAPITEL 10. CONCURRENCY CONTROL Durch SET TRANSACTION READ ONLY ist nur ein lesender Zugriff innerhalb der Transaktion möglich, das Gegenteil ist SET TRANSACTION READ WRITE. Im Laufe einer Transaktion können die Probleme auftreten, die wir in den Beispielen 10.3 und 10.4 gesehen haben. Dirty Read: T1 liest einen von T2 veränderten Wert, bevor T2 mit COMMIT abgeschlossen wurde. Nonrepeatable Read: T1 liest einen Satz. Während der Transaktion wird derselbe Satz von T1 noch einmal gelesen. Zwischen den beiden Lesevorgängen hat T 2 Werte dieses Satzes verändert. T1 erhält daher zwei verschiedene Werte für denselben Satz. Phantom Read: T1 liest eine Menge von Sätzen aufgrund bestimmter Kriterien (SELECT * FROM tabelle WHERE bedingung). Dieser Lesevorgang wird später wiederholt. Inzwischen ändert T2 einige Werte. Dadurch erfüllt eine andere Menge von Sätzen die WHERE− Bedingung, sodass T1 beim zweiten Lesevorgang eine andere Menge von Sätzen bekommt. SQL-3 unterstützt zur Vermeidung dieser Phänomene verschiedene Isolationsstufen (Isolation levels). Die folgende Tabelle zeigt, durch welche Optionen welche Phänomene vermieden werden können. Stufe SERIALIZABLE REPEATABLE READ READ COMMITTED READ UNCOMMITTED Dirty Read nicht möglich nicht möglich nicht möglich möglich Nonrepeatable Read nicht möglich nicht möglich möglich möglich Phantom Read nicht möglich möglich möglich möglich Die gewünschte Isolationsstufe wird mit SET TRANSACTION ISOLATION LEVEL für eine Transaktion festgelegt, z. B. SET TRANSACTION ISOLATION LEVEL SERIALIZABLE. Um alle Anomalien zu verhindern, müssten wir nur serialisierbare Transaktionen zulassen. Das ist jedoch aus Performancegründen nicht immer möglich. Es ist daher unsere Aufgabe beim Design der Datenbankapplikation diese Effekte zu überlegen und die richtigen Designentscheidungen zu treffen. KAPITEL 10. CONCURRENCY CONTROL 10.5 10.21 Übungsbeispiele Übung 10.1 Ist die angegebene Ausführung der Transaktionen T 1, T 2, T 3 und T 4 serialisierbar? Warum (nicht)? (Begründung mit Hilfe des Präzedenzgraphen, oder Angabe der äquivalenten seriellen Ausführung) T 1: T 2: READ a T 3: T 4: READ a UPDATE b UPDATE a READ b READ b UPDATE c UPDATE a UPDATE b Übung 10.2 Angenommen wir verwenden das Zeitstempel-Verfahren für die Synchronisierung der Transaktionen in Beispiel 10.1. Welche der 4 Transaktionen wird abgebrochen, wenn wir folgende Voraussetzung für die Zeitstempel der Transaktionen T 1 − T 4 treffen: 1. 300, 310, 320 und 330 2. 250, 200, 210 und 275 Übung 10.3 Das Hierarchische Sperrprotokoll mit I-Sperren und X-Sperren (siehe Vorlesung) wird um S-Sperren (shared locks) erweitert: IS IX S SIX X ... ... ... ... ... Absicht für S-Belegung Absicht für X-Belegung S-Sperre (shared) S-Sperre und Absicht für X-Belegung X-Sperre (exclusive) Geben Sie die Kompatibilitätsrelation mit den Spalten (bzw. Zeilen) X, S, IS, SIX, IX an. Übung 10.4 Gegeben ist folgende Hierarchie von Objekten: KAPITEL 10. CONCURRENCY CONTROL 10.22 A B D C E F G Sind alle möglichen, gültigen Ausführungen der Transaktionen T 1, T 2 und T 3 serialisierbar? (Begründung oder Gegenbeispiel) T 1: lock A, lock B, unlock B, lock C, unlock A, unlock C T 2: lock B, lock E, unlock B, lock G, unlock E, unlock G T 3: lock E, lock F , lock G, unlock E, unlock F , unlock G Übung 10.5 Gegeben ist folgende Parallelausführung von Transaktionen: T 1: UPDATE a T 2: T 3: UPDATE b READ a UPDATE c READ c READ b 1. Stellen Sie die Abhängigkeitsbeziehungen von T 1, T 2 und T 3 durch Angabe des Präzedenzgraphen dar. 2. Ist die angegebene Ausführung von T 1, T 2 und T 3 serialisierbar? Übung 10.6 Gegeben ist eine Ansammlung von Objekten O, die Knoten eines Baumes sind, sowie die Transaktionen T 1 und T 2. Angenommen T 1 und T 2 erfüllen das Hierarchische Sperrprotokoll: Kann es bei einer Ausführung von T 1 und T 2 zu einem Deadlock kommen? Betrachten Sie dazu den Baum mit der Wurzel A und den zwei Kindern B und C. Übung 10.7 Parallele Transaktionen werden mit Hilfe des Zeitstempelverfahrens synchronisiert. Gegeben sind folgende Transaktionen mit ihren Zeitstempeln: KAPITEL 10. CONCURRENCY CONTROL T 1: 80 T 2: 70 WRITE c 10.23 T 3: 60 a RT = W T = 0 READ a RT = .. b RT = W T = 0 c RT = W T = 0 W T = .. W T = .. WRITE b W T = .. WRITE a W T = .. WRITE c READ b RT = .. RT = .. READ c 1. Tragen Sie in der obigen Darstellung die fehlenden Werte für die Lese- und Schreibstempel der Objekte a, b und c ein. Kennzeichnen Sie den Abbruch einer Transaktion mit “∗”. 2. Welche Serialisierungsreihenfolge von T 1, T 2, T 3 wird in der obigen Ausführung durch die Anwendung des Zeitstempelverfahrens erzwungen? Übung 10.8 Gegeben ist folgende Parallelausführung von Transaktionen: T 1: READ a T 2: T 3: READ b UPDATE a UPDATE b READ a READ a 1. Stellen Sie die Abhängigkeitsbeziehungen von T 1, T 2 und T 3 durch Angabe des Präzedenzgraphen dar. 2. Ist die angegebene Ausführung von T 1, T 2 und T 3 serialisierbar? Übung 10.9 Gegeben ist folgende Ansammlung von Objekten, die Knoten eines Baumes sind: A B D C E F G KAPITEL 10. CONCURRENCY CONTROL 10.24 Geben Sie für die Transaktionen T 1, T 2 und T 3 an, ob sie das Baumprotokoll erfüllen. Falls eine Transaktion das Baumprotokoll verletzt, geben Sie das Objekt an, das falsch gesperrt wird. T 1: LOCK A, LOCK B, UNLOCK A, LOCK C, UNLOCK C, UNLOCK B T 2: LOCK B, LOCK E, UNLOCK E, LOCK D, UNLOCK B, UNLOCK D T 3: LOCK A, LOCK E, LOCK F , UNLOCK F , UNLOCK E, UNLOCK A Übung 10.10 In Abschnitt 10.1.5 ist das Konzept der Effektserialisierbarkeit (view serializability) vorgestellt worden. Beweisen oder widerlegen Sie: • Jede serialisierbare Ausführung ist view-serializable. • Unter constraint write assumption (CWA) ist eine Ausführung genau dann serialisierbar, wenn sie view-serializable ist. • Unter Aufgabe der constraint write assumption (CWA) ist eine view-serializable Ausführung nicht notwendigerweise serialisierbar. Übung 10.11 Ist das 2-Phasen-Sperrprotokoll deadlockfrei? Übung 10.12 • Ist das gewöhnliche Baumprotokoll deadlockfrei? • Ist das Hierarchische Sperrprotokoll deadlockfrei? • Angenommen, das Hierarchische Sperrprotokoll verwende nur X-Locks. Ist es unter dieser Annahme deadlockfrei? Übung 10.13 Gegeben ist folgende Parallelausführung von Transaktionen: T 1: T 2: READ b T 3: UPDATE a READ a UPDATE c READ b UPDATE b UPDATE c 1. Stellen Sie die Abhängigkeitsbeziehungen von T 1, T 2 und T 3 durch die Angabe des Präzedenzgraphen dar. 2. Ist die angegebene Ausführung von T 1, T 2, und T 3 serialisierbar? KAPITEL 10. CONCURRENCY CONTROL 10.25 Übung 10.14 Parallele Transaktionen werden mit Hilfe des Zeitstempelverfahrens synchronisiert. Gegeben sind folgende Transaktionen mit ihren Zeitstempeln: T 1: 45 READ a T 2: 65 T 3: 90 a RT = W T = 0 RT = 45 b RT = W T = 0 c RT = W T = 0 W T = 65 WRITE b WRITE c W T = 65 WRITE a WT = ... WT = ... RT = . . . WRITE c READ C RT = . . . READ b 1. Tragen Sie in der obigen Darstellung die fehlenden Werte für die Lese- und Schreibstempel der Objekte a, b und c ein. Kennzeichnen Sie den Abbruch einer Transaktion mit “∗” . 2. Welche Serialisierungsreihenfolge von T 1, T 2 und T 3 wird in der obigen Ausführung durch die Anwendung des Zeitstempelverfahrens erzwungen? Übung 10.15 Geben Sie für die nachfolgende parallele Ausführung der Transaktionen T 1– T 3 den Präzedenzgraphen an. T1 T2 WRITE C T3 READ D WRITE B WRITE C READ A WRITE A WRITE D READ C WRITE B Ist die Ausführung serialisierbar? Wenn nein, wieviele Operationen müssen mindestens gestrichen werden, sodass die Ausführung serialisierbar wird, und welche Operationen? Übung 10.16 Die nachfolgende Parallelausführung von Transaktionen werde mithilfe von Zeitstempeln synchronisiert. KAPITEL 10. CONCURRENCY CONTROL 10.26 T1 .... T2 .... READ a T3 .... a RT=WT=0 RT= . . . . WRITE b b RT=WT=0 c RT=WT=0 WT= . . . . WRITE c WT= . . . . RT= . . . . READ c WRITE b WT= . . . . WT= . . . . WRITE b WRITE a WT= . . . . 1. Wählen Sie Zeitstempel für die Transaktionen so, dass möglichst wenige abgebrochen werden. 2. Welche Reihenfolge zwischen Transaktionen Ti , Tj ist dadurch garantiert? Übung 10.17 Geben Sie für die nachfolgende parallele Ausführung der Transaktionen T 1 − T 3 einen Präzedenzgraphen an: T1 T2 write c T3 write b read a read b read c Präzedenzgraph write a read c read b write b write a Ist die Ausführung serialisierbar? Die Ausführung wird aber nach Streichen von (mindestens) lisierbar, z.B.: Operation(en) seria- Übung 10.18 Parallele Transaktionen werden mit Hilfe des Zeitstempelverfahrens synchronisiert. Gegeben sind folgende Transaktionen mit ihren Zeitstempeln: KAPITEL 10. CONCURRENCY CONTROL T1 100 write c T2 200 T1 300 write a a WT=RT=0 b WT=RT=0 10.27 c WT=RT=0 WT= WT= write b WT= read c read b write a RT= RT= WT= read c read b RT= RT= read a RT= 1. Tragen Sie in der obigen Darstellung die fehlenden Werte für die Lese- und Schreibstempel der Objekte a, b und c ein. Kennzeichnen Sie den Abbruch einer Transaktion mit “∗” . 2. Welche Serialisierungsreihenfolge von T 1, T 2 und T 3 wird in der obigen Ausführung durch die Anwendung des Zeitstempelverfahrens erzwungen? 10.28 KAPITEL 10. CONCURRENCY CONTROL Kapitel 11 Wiederanlauf (Recovery) 11.1 Grundlagen 11.1.1 Zielsetzung Das Ziel der Recovery ist die Wiederherstellung eines konsistenten Datenbankzustandes nach einem Fehler. Wir können folgende Arten von Fehlern unterscheiden: 1. Transaktionsfehler: eine Transaktion muss nach einem logischen Fehler (z.B. “Konto nicht gedeckt”) abgebrochen werden. 2. Systemfehler: alle Änderungen, die nur im Hauptspeicher, aber noch nicht auf dem Hintergrundspeicher durchgeführt wurden, gehen verloren. 3. Plattenfehler: alle Änderungen, die seit der letzten Sicherung auf dem Hintergrundspeicher durchgeführt wurden, gehen verloren. Ein korrektes Wiederanlaufverfahren garantiert Dauerhaftigkeit und Atomarit ät, d.h., die Effekte bereits erfolgreich abgeschlossener Transaktionen bleiben zur Gänze erhalten. Nicht erfolgreich abgeschlossene Transaktionen hinterlassen keinerlei Effekte in der Datenbank. Eine Transaktion kann sich selbst abbrechen (z.B. durch Entscheidung des Programmierers oder durch Laufzeitfehler im Anwendungsprogramm) oder durch das Datenbankmanagementsystem (z.B. durch Concurrency Control oder bei Auftreten von Deadlocks) abgebrochen werden. Die teilweise durchgeführte Transaktion soll keinerlei Effekt auf die Datenbank haben. Alle bereits durchgeführten Aktionen von unvollständig ausgeführten Transaktionen werden rückgängig gemacht (Rückwärts-Recovery, Rollback; siehe Abschnitt 11.3.1). Es ist möglich, Punkte innerhalb einer Transaktion zu definieren, die das Rückgängigmachen nur bis zu diesem Punkt nötig machen. Solche Punkte nennt man Synchronisationspunkte (siehe Abschnitt 11.3.4). 1 11.2 KAPITEL 11. WIEDERANLAUF (RECOVERY) Beispiel 11.1 Betrachten wir wieder das Bankenszenario (Umbuchung) mit den folgenden Datenstrukturen und Integritätsbedingungen. Datenstruktur: SPARBUCH (SPNR, EINLAGE, BESITZER) KONTO (KNR, KSTAND) SPAREINLAGEN GESAMT Integritätsbedingung: KSTAND >= 0 EINLAGE > 0 SPAREINLAGEN GESAMT = Summe EINLAGE Transaktion: Umbuchung von 50 Euro von Konto 123 auf das Sparbuch 321 begin transaction update KONTO set KSTAND=KSTAND-50 where KNR=123; update SPARBUCH set EINLAGE=EINLAGE+50 where SPNR=321 SPAREINLAGEN_GESAMT:= SPAREINLAGEN_GESAMT+50 print (Ueberweisung, Betrag, KNR, SPNR) end transaction Ein Systemabsturz während einer Umbuchung kann eine einseitige Buchung bedeuten. Beim Systemanlauf muss ein konsistenter DB-Zustand (d.h., Buchungen werden vollständig durchgeführt oder gar nicht) wiederhergestellt werden. Beispiel 11.2 In der nächsten Abbildung sehen wir fünf Transaktionen, von denen die Transaktionen T1, T2 und T3 beim Systemabsturz bereits abgeschlossen sind. Ihre Änderungen sind in der Datenbank und gültig, dadurch ist die Dauerhaftigkeit gewährt. Um auch Atomarität zu gewährleisten, müssen T4 und T5 rückgängig gemacht werden, da sie nicht abgeschlossen sind. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.3 T1 T2 T3 T4 T5 Zeit Absturz 11.1.2 Reihenfolge von Ausführungen Definition 11.1 Eine Transaktion Tj liest X von einer Transaktion Ti falls: 1. Tj liest X zum Zeitpunkt tj , Ti schreibt X zum Zeitpunkt ti , und ti < tj . 2. Ti wird nicht vor tj abgebrochen, 3. jede Transaktion Tk , die X zum Zeitpunkt tk , ti < tk < tj schrieb, wurde vor tj abgebrochen. Diese Definition werden wir im weiteren benötigen, um in gewisser Weise eine Reihenfolge von Transaktionen bestimmen zu können und Anomalien zu vermeiden. Beispiel 11.3 Die Transaktion Ti schreibt den Wert X, Tj liest den Wert X und keine andere Transaktion greift dazwischen lesend oder schreibend auf X zu. kein Tk schreibt auf X Ti write(X) Tj read(X) 11.1.3 Nichtwiederherstellbare Ausführung Wenn eine Transaktion z.B. wegen eines Systemabsturzes zurückgesetzt werden muss, kann es zum Problem führen, dass sukzessive auch Transaktionen, die schon erfolgreich abgeschlossen waren, zurückgesetzt werden müssen, was im Widerspruch zur Forderung der Dauerhaftigkeit steht. Diese Problematik heißt kaskadierendes Zurücksetzen (Cascading Abort oder Cascading Rollback). Die Ausführung ist daher nicht mehr wiederherstellbar. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.4 Beispiel 11.4 Wegen des Systemabsturzes muss T3 zurückgesetzt werden. Da x bereits früher freigegeben und sofort von T1 und T2 gelesen wurde, müssen auch T1 und T2 zurückgesetzt werden, um die Atomarität von T3 zu garantieren, da sie auf dem von T3 geschriebenen Wert x aufbauen1 . Da T1 und T2 bereits erfolgreich abgeschlossen waren, stellt dies eine Verletzung der Dauerhaftigkeit dar. read x read y T1 T2 read x write y T3 write x read y Zeit Absturz Cascading Abort kann nicht nur bei einem Systemabsturz, sondern auch beim Abbruch einer Transaktion auftreten. Um Cascading Abort zu vermeiden, darf eine Transaktion ihre Änderungen erst freigeben, wenn sichergestellt ist, dass die Transaktion ordnungsgemäß beendet werden kann (Isolation). Die Isolation wird also eingeführt, um den Widerspruch zwischen Dauerhaftigkeit einerseits und dem Zurücksetzen zur Sicherstellung der Atomarität andererseits zu verhindern und so Wiederherstellbarkeit zu garantieren. In der Praxis erreicht man Isolation, indem alle UNLOCK-Befehle bis zum Ende der Transaktion verzögert werden oder zu einem Befehl (COMMIT) zusammengefasst werden, der gleichzeitig das Ende der Transaktion anzeigt. 11.1.4 ACA Ausführungen Definition 11.2 Eine Ausführung I von Transaktionen verhindert kaskadierendes Zur ücksetzen (avoids cascading aborts, ACA), wenn gilt: immer wenn Ti X von Tj liest, kommt das Commit der Transaktion Tj vor dem readi (X) von Ti in I, d.h., dass eine Transaktion nur von schon erfolgreich abgeschlossenen Transaktionen lesen kann. 11.1.5 Strikte Ausführung von Transaktionen Viele Datenbankmanagementsysteme implementieren das Zurücksetzen einer Transaktion dadurch, dass sie für alle Änderungsoperationen der Transaktion den alten Wert (Before Image) restaurieren, den sie sich bei der Transaktionsausführung gemerkt haben. Dieses einfache Verfahren ist jedoch nur unter der Annahme korrekt, dass Transaktionen Objekte nur dann schreiben, wenn sie zuletzt von erfolgreich abgeschlossenen Transaktionen geschrieben wurden. Die Ausführung in der Abbildung unten verletzt diese Annahme. 1 Rücksetzen von T1 , T2 kann seinerseits das Rücksetzen weiterer Transaktionen veranlassen usw. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.5 Beispiel 11.5 Das Before Image von X ist in T1 = 1, in T2 = 2. Angenommen, dass nach einem Abbruch zuerst T1 , dann T2 restauriert werden, so bedeutet dies, dass am Ende des Rücksetzens X = 2 gilt. T1 WRITE(X,2) T2 WRITE(X,3) x=1 x=2 x=3 x=3 Wie wir gesehen haben, ist die Reihenfolge der Rücksetzungen vom Startzeitpunkt der Transaktionen abhängig. Um diese Anomalie zu vermeiden, wird eine strikte Ausführung von Transaktionen verlangt. Definition 11.3 Eine Ausführung von Transaktionen ist strikt (ST), wenn jede Transaktion nur Objekte liest und schreibt, die zuletzt von abgeschlossenen Transaktionen geschrieben wurden. Es gilt folgende Beziehung: ST ⊂ ACA Die serialisierbaren Transaktionen schneiden alle diese drei Klassen, sind aber unvergleichbar mit ihnen, wie die nächste Abbildung zeigt. Die seriellen Transaktionen sind natürlich im Schnitt aller dieser Klassen enthalten. Ausführungen serialisierbar ACA ST seriell In der Praxis wird strictness für 2-Phasen Sperrverfahren (siehe Kapitel 10) erreicht, wenn folgende Regeln eingehalten werden: 1. Eine Transaktion kann erst schreiben, wenn sie ihren locked point erreicht hat. 2. Eine Transaktion kann erst Locks freigeben, wenn sie das Schreiben in die Datenbank beendet hat. Sperren werden daher nicht freigegeben, bis unmittelbar nach dem Commit. Commit und Freigabe aller Sperren werden auch oft zu einer einzigen Operation zusammengezogen, die die Transaktion beendet. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.6 11.2 Pufferverwaltung Wir unterscheiden die folgenden drei Arten von Speicher: • Primär- oder Hauptspeicher (non-persistent storage, volatile Storage) • Sekundär- oder Hintergrundspeicher (persistent storage, non-volatile storage) • Stabiler Speicher (stable storage): Information geht nie verloren. (Kann mit Mehrfachkopien annähernd erreicht werden, aber nie zu 100%!) Das Datenbankmanagementsystem bewegt Blöcke, die jeweils mehrere Datensätze umfassen, vom Hintergrundspeicher in den Hauptspeicher und umgekehrt (vergleiche die Abbildung unten). Den Teil des Hauptspeichers, der zur Aufnahme von Datenbank-Blöcken gedacht ist, bezeichnet man als Puffer. Blöcke auf dem Hintergrundspeicher werden als physische Bl öcke, Blöcke im Hauptspeicher als Pufferblöcke bezeichnet. input(A) A B B output(B) Hauptspeicher Platte input(X) überträgt den physischen Block, der das Datenobjekt X enthält, in den Hauptspeicher. output(X) überträgt den Pufferblock, der das Datenobjekt X enthält, auf den Hintergrundspeicher und ersetzt dort den entsprechenden physischen Block. Transaktionen interagieren mit dem Datenbanksystem, indem Daten aus Programmvariablen in die Datenbank und Daten aus der Datenbank in Programmvariable übertragen werden: read(X,xi ) weist den Wert des Datenobjekts X der Programmvariable xi zu. 1. Ist der Block, auf dem sich X befindet, noch nicht im Hauptspeicher, dann führe input(X) aus. 2. Weise xi den Wert von X im Pufferblock zu. write(X,xi ) weist den Wert der Programmvariable xi dem Datenobjekt X im Pufferblock zu. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.7 1. Ist der Block, auf dem sich X befindet, noch nicht im Hauptspeicher, dann führe input(X) aus. 2. Ersetze den Wert von X im Pufferblock durch den Wert von xi . Es ist zu beachten, dass eine Änderung des Wertes von X auf dem Hintergrundspeicher nicht unmittelbar nach der Änderung des Wertes von X im Puffer erfolgen muss. Aus Effizienzgründen ist es sinnvoll, ein Datenobjekt, auf das oft zugegriffen wird, länger im Puffer zu behalten. Ein Pufferblock wird vom Pufferverwalter automatisch auf den Hintergrundspeicher übertragen, wenn 1. der Puffer zu klein wird, oder 2. dies mittels output(X) vom Wiederanlaufverwalter verlangt wird (forced write). (Wir werden die Gründe dafür später kennenlernen.) Es ergeben sich demnach folgende mögliche inkonsistente Datenbankzustände nach einem Systemabsturz: • Änderungen abgeschlossener Transaktionen wurden vom Datenbankmanagementsystem nur im Puffer, aber noch nicht auf dem Hintergrundspeicher durchgeführt. • Änderungen noch nicht abgeschlossener Transaktionen wurden bereits auf dem Hintergrundspeicher durchgeführt. Beispiel 11.6 Betrachten wir folgende Transaktion: Zeit 1 2 3 4 5 6 T read(A,a1 ) a1 :=a1 - 50 write(A,a1 ) read(B,b1 ) b1 :=b1 + 50 write(B,b1 ) Die nächsten drei Abbildungen stellen eine mögliche Abfolge des Hauptspeicherzustandes und Hintergrundspeicherzustandes bei der Abarbeitung der Transaktion T dar. Nach dem erfolgreichen Abschluss der Transaktion sind die Änderungen nur im Hauptspeicher, aber nicht auf der Platte durchgeführt. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.8 A=1000 A=1000 B=2000 Hauptspeicher Platte A=950 A=1000 B=2000 B=2000 Hauptspeicher Platte A=950 A=1000 B=2000 B=2050 Hauptspeicher Platte Bei einem Systemfehler geht der Hauptspeicherinhalt verloren, und dadurch auch das Ergebnis der bereits abgeschlossenen Transaktion (Verletzung der Eigenschaft der Dauerhaftigkeit). Es könnte sich aber während der Ausführung von T auch ein Zustand ergeben, bei dem ein Teil der Änderungen bereits auf den Hintergrundspeicher übertragen wurde. Bei einem Systemfehler hinterlässt die Transaktion dann einen Teileffekt auf der Datenbank (Verletzung der Eigenschaft der Atomarität). 11.2.1 Privater Arbeitsbereich Dies ist eine Art der Pufferverwaltung mit dem Zweck, jeder Transaktion einen separaten Puffer zuzuordnen, in dem die Änderung der Daten durchgeführt wird. Die Effekte einer Transaktion T nach diesem Modell können wie folgt beschrieben werden. Begin Transaction T : T wird ein privater Arbeitsbereich als Puffer für Datenbankobjekte zugeordnet. Read Object X: Der private Arbeitsbereich von T wird nach dem Objekt X durchsucht. Nur wenn X nicht gefunden wird, wird X aus der Datenbank in den Arbeitsbereich übertragen. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.9 Write Object X: Wenn das Objekt X im Arbeitsbereich gefunden wird, wird es dort überschrieben. Andernfalls wird der neue Wert im Arbeitsbereich eingetragen. End Transaction T : Alle im Arbeitsbereich geänderten oder neu geschaffenen Werte von Objekten werden in die Datenbank übertragen. Ein spezielles Protokoll garantiert, dass entweder alle oder keine Werte übertragen werden. Danach wird der private Arbeitsbereich freigegeben. 11.2.2 Write Ahead-Protokoll Ein Protokoll, das die obige Anforderung erfüllt, d.h., das das Konzept des privaten Arbeitsbereiches realisiert, ist das Write Ahead-Protokoll. 1. Phase: Alle zu ändernden Werte werden aus dem privaten Arbeitsbereich in einen stabilen Speicherbereich, der sicher zuverlässig ist, übertragen. 2. Phase: Die geänderten Werte werden in die Datenbank selbst eingetragen. Wenn ein Systemausfall während der 1. Phase eintritt, gilt die Transaktion als nicht durchgeführt. Die Datenbank ist und bleibt unverändert. Nach einem Systemausfall während der 2. Phase muss das Datenbanksystem während des Wiederanlaufs alle Updates aus dem stabilen Speicher übernehmen. 11.3 Wiederanlaufverfahren mit Logprotokoll Die private Speicherverwaltung ist zwar korrekt, kann aber in ihrer Realisierung sehr kompliziert sein. Durch das Führen eines Logprotokolls kann der private Speicher ersetzt werden, wenn alle Änderungen sofort in das Logprotokoll eingetragen werden. Weiters können alle Daten im globalen Puffer gehalten werden. 11.3.1 Das Logprotokoll Sämtliche für einen korrekten Wiederanlauf notwendigen Informationen werden in einem Logprotokoll festgehalten. Das Logprotokoll enthält spezielle Logeinträge, die den Start (begin transaction), das Ende (commit transaction) oder den Abbruch (abort transaction) einer Transaktion vermerken, sowie Standard-Logeinträge, die sämtliche durchgeführte Änderungen registrieren. Ein Standardeintrag im Logprotokoll ist wie folgt aufgebaut: 1. Identifikator der Transaktion 2. Identifikator des geänderten Datensatzes KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.10 3. Art der Änderung (insert, delete, update) 4. alter Wert (wird für UNDO benötigt) 5. neuer Wert (wird für REDO benötigt) 6. Hilfsinformation (Zeiger auf vorigen Logeintrag der Transaktion, etc.) Das Logprotokoll kann verwendet werden, um Transaktionen rückgängig zu machen (Rollback, backward recovery): U N DO(T ) oder um Transaktionen nachzufahren (forward recovery): REDO(T ). alter Wert DO neuer Wert Logprotokoll neuer Wert UNDO alter Wert REDO neuer Wert Logprotokoll alter Wert Logprotokoll Da auch während des Wiederanlaufs ein Fehler auftreten kann, müssen die Operationen U N DO und REDO idempotent sein, d.h.: U N DO(U N DO(T )) = U N DO(T ) REDO(REDO(T )) = REDO(T ). Beim Log-Write-Ahead-Protokoll muss der Eintrag in das Logprotokoll vor der Änderung in der Datenbank durchgeführt werden. Wird das Logprotokoll gepuffert, muss vor der Übernahme einer Änderung in die Datenbank die UNDO-Information auf den stabilen Speicher geschrieben werden; weiters müssen vor dem commit einer Transaktion sämtliche Logeinträge der Transaktion auf den stabilen Speicher übernommen werden. Die sequentielle Führung des Logprotokolls auf dem Hintergrundspeicher ist einfacher, als die Änderungen jeweils sofort in den komplexen Datenstrukturen der Datenbank auf dem Hintergrundspeicher vorzunehmen. Außerdem ist es aus Sicherheitsgründen üblich, das Logprotokoll auf einem anderen Hintergrundspeicher als die Datenbank selbst zu führen. Dadurch wird es möglich, nicht nur nach einem Systemabsturz, sondern auch nach einem Plattenfehler wieder aufzusetzen. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.11 11.3.2 Wiederanlauf nach einem Transaktionsabbruch Nach einem Transaktionsabbruch wird für den Wiederanlauf das Logprotokoll mit den alten Werten gebraucht. Algorithmus: UNDO(T): Lies das Logprotokoll vom letzten Eintrag in Richtung Anfang bis zum Eintrag begin transaction T und ersetze sämtliche Änderungen von T in der Datenbank durch die alten Werte. RESTART(T): Starte T neu. 11.3.3 Wiederanlauf nach einem Systemabsturz Im Falle eines Systemabsturzes muss ebenfalls für den Wiederanlauf das Logprotokoll mit den alten Werten verwendet werden. In diesem Fall müssen jedoch nicht nur jene Transaktionen, die beim Systemabsturz aktiv waren, rückgängig gemacht und neu gestartet werden, sondern auch die schon abgeschlossenen Transaktionen müssen nochmals nachgefahren werden, da alle Änderungen im Hauptspeicher verloren gegangen sind und nicht bekannt ist, ob diese Änderungen auch alle auf dem Hintergrundspeicher durchgeführt wurden. Algorithmus: 1. Baue zwei Listen UndoListe und RedoListe auf: • Lies das Logprotokoll von Beginn vorwärts. Wird ein Eintrag begin transaction Ti gefunden, füge Ti zur UndoListe hinzu. • wird ein Logeintrag commit transaction Ti gefunden, füge Ti zur RedoListe hinzu und streiche Ti von der UndoListe. 2. Lies das Logprotokoll vom letzten Eintrag ausgehend rückwärts und mache alle Änderungen von Transaktionen in der UndoListe rückgängig. D.h., führe das UNDO für alle Transaktionen in der UndoListe durch. 3. Lies im Logprotokoll weiter rückwärts, bis die begin transaction-Einträge für alle Transaktionen in der RedoListe gefunden wurden. 4. Lies das Logprotokoll vorwärts und schreibe für jede von einer Transaktion in der RedoListe durchgeführte Änderung den neuen Wert in die Datenbank. D.h., führe ein REDO durch. 5. Starte alle Transaktionen in der UndoListe neu. Beispiel 11.7 Transaktion T 4 wird abgebrochen. Daher muss sie durch ein UNDO zurückgesetzt werden und danach neu gestartet werden. Im Falle eines Systemabsturzes müssen hingegen auch die anderen Transaktionen nachgefahren werden. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.12 REDO T1 T1 T2 T2 T3 T3 UNDO REDO UNDO T4 T4 Zeit REDO Transaktionsabbruch Zeit Systemabsturz 11.3.4 Checkpoints Checkpoints werden zur Vereinfachung des Wiederanlaufs eingeführt um das im letzten Beispiel beschriebene Problem des Nachfahrens von Transaktionen zu verringern. Bei einem Checkpoint werden 1. alle Logeinträge auf den stabilen Speicher geschrieben, 2. alle schmutzigen Pufferblöcke auf die Platte geschrieben (ein Pufferblock ist schmutzig (dirty), wenn dessen Inhalt nicht mit dem ihm entsprechenden physischen Block auf der Platte übereinstimmt), 3. ein spezieller Logeintrag, checkpoint L, auf den stabilen Speicher geschrieben, wobei L die Menge der zum Zeitpunkt des Checkpoints aktiven Transaktion darstellt. Bis zum nächsten Synchronisationspunkt werden sämtliche Änderungen unter Umständen nur im Hauptspeicher und nicht in der Datenbank vorgenommen, jedoch auf alle Fälle im Logprotokoll auf dem Hintergrundspeicher vermerkt. 11.3.5 Wiederanlauf mit Checkpoints nach einem Systemabsturz Die Voraussetzung für einen korrekten Wiederanlauf nach einem Systemabsturz ist, dass das Logprotokoll ab dem Startzeitpunkt der ältesten beim letzten Checkpoint aktiven Transaktionen auf dem stabilen Speicher vorhanden ist. Algorithmus: 1. Baue zwei Listen UndoListe und RedoListe auf: • Suche den letzten Checkpoint-Eintrag checkpoint L; initialisiere die UndoListe mit L und lies von diesem Eintrag an vorwärts im Log (in Richtung des letzten Eintrags). • wird ein Logeintrag commit transaction Ti gefunden, füge Ti zur RedoListe hinzu und streiche Ti von der UndoListe. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.13 • wird ein Logeintrag begin transaction Ti gefunden, füge Ti zur UndoListe hinzu. 2. Lies das Logprotokoll vom letzten Eintrag ausgehend rückwärts und mache alle Änderungen von Transaktionen in der UndoListe rückgängig. D.h., führe das UNDO für alle Transaktionen in der UndoListe durch. 3. Lies im Logprotokoll weiter rückwärts bis die begin transaction-Einträge für alle Transaktionen in der RedoListe gefunden wurden. 4. Lies das Logprotokoll vorwärts und schreibe für jede von einer Transaktion in der RedoListe durchgeführte Änderung den neuen Wert in die Datenbank. D.h., führe ein REDO durch. 5. Starte alle Transaktionen in der UndoListe neu. Beispiel 11.8 Die Aktionen, die in der folgenden Situation gesetzt werden müssen (unter der Annahme einer strikten Ausführung) sind: T1 REDO T2 T3 REDO UNDO T4 UNDO T5 Zeit Checkpoint Absturz • UNDO T4, T5 • REDO T2, T3 • RESTART T4, T5 Anmerkung: Unter Annahme einer strikten Ausführung genügt es, das REDO (Schritte 3 und 4) ab dem Checkpoint durchzuführen. Beispiel 11.9 Bei einer nicht strikten Ausführung macht das UNDO von write(X) in T4 ein REDO von write(X) in T2 notwendig. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.14 T1 write(X) REDO T2 T3 T4 REDO UNDO write(X) UNDO T5 Zeit Checkpoint Absturz 11.3.6 Wiederanlauf nach einem Plattenfehler Bei einem Plattenfehler müssen die Sicherungskopie (Backup) und das Logprotokoll ab dem Zeitpunkt der Sicherungskopie vorhanden sein. Außerdem darf keine Transaktion während der Sicherung aktiv sein. Algorithmus 1. Ersetze die Datenbank durch die Sicherungskopie. 2. Bestimme die RedoListe wie folgt: Eine Transaktion T ist in der RedoListe, falls ein Eintrag begin transaction T und ein Eintrag commit transaction T im Logprotokoll aufscheint. 3. Lies das Log vom Anfang bis zum Ende und übernimm für Änderungen von Transaktionen in der RedoListe die neuen Werte in die Datenbank. Beispiel 11.10 Die Aktionen, die in der folgenden Situation gesetzt werden müssen, sind: T1 T2 REDO T3 T4 T5 Zeit • DB:=Backup • REDO T3 • RESTART T5 Backup Plattenfehler KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.15 In der Praxis ist es nicht sinnvoll, zu verlangen, dass während der Durchführung des Backups keine Transaktionen aktiv sein dürfen. Sind Transaktionen aktiv, so muss das Logprotokoll ab dem Startzeitpunkt der ältesten während des Backups aktiven Transaktion vorhanden sein. Algorithmus 1. Ersetze die Datenbank durch die Sicherungskopie. 2. Bestimme die Undo- und RedoListe wie folgt: • Eine Transaktion T ist in der RedoListe, falls ein Eintrag begin transaction T und ein Eintrag commit transaction T nach dem Backup Eintrag im Logprotokoll aufscheint. • Eine Transaktion T ist in der UndoListe, falls ein Eintrag begin transaction T, aber kein Eintrag commit transaction T im Logprotokoll aufscheint. 3. Lies das Logprotokoll vom Backup Eintrag rückwärts und mache alle Änderungen von Transaktionen in der UndoListe rückgängig. 4. Lies das Log vom Backup Eintrag bis zum Ende und übernimm für Änderungen von Transaktionen in der RedoListe die neuen Werte in die Datenbank. 5. Starte alle Transaktionen in der UndoListe neu. Beispiel 11.11 Die Aktionen, die in der folgenden Situation gesetzt werden müssen, sind: T1 REDO T2 T3 REDO UNDO T4 T5 Zeit • DB:=Backup • UNDO T4 • REDO T2, T3 • RESTART T4, T5 Backup Plattenfehler 11.16 KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.4 Schattenkopieverfahren (shadow paging) 11.4.1 Die Grundidee Die Grundidee des Schattenkopieverfahrens ist es, bei der Ausführung einer Transaktion zwei Kopien der Datenbank zu verwalten: 1. Die Schattenkopie enthält den Datenbankzustand vor dem Start der Transaktion. Sie repräsentiert den nach der letzten erfolgreich abgeschlossenen Transaktion gültigen Datenbankzustand. 2. Die Transaktion führt sämtliche Änderungen auf einer Arbeitskopie durch. Sie wird zu Beginn der Transaktion mit der Schattenkopie initialisiert. Wird die Transaktion abgebrochen, wird die Arbeitskopie verworfen. Wird die Transaktion erfolgreich abgeschlossen, wird die Arbeitskopie die neue Schattenkopie. 11.4.2 Die Realisierung Die Datenbank ist in Seiten (pages) aufgeteilt. (Eine Seite umfasst eine vorgegebene Anzahl Blöcke fixer Länge.) Die Seiten sind nicht notwendigerweise sequentiell gespeichert. Eine Seitentabelle (page table) ordnet jeder Seite, identifiziert durch die Seitennummer, ihre Adresse auf der Platte zu (siehe: Abb. 11.1). Beim Schattenspeicherfahren werden zwei Seitentabellen verwendet: die Schattenseitentabelle und die Arbeitsseitentabelle, die auf die Schatten- bzw. die Arbeitskopie zeigen. Seiten, die in der Schattenkopie und in der Arbeitskopie gleich sind, werden nur einmal gespeichert und von beiden Tabellen referenziert (siehe Abb. 11.2). Eine fixe Speicheradresse auf der Platte enthält einen Zeiger auf die Schattenseitentabelle. Zum Transaktionsbeginn wird die Schattenseitentabelle in die Arbeitsseitentabelle kopiert. Eine Schreiboperation write(X, xj ) auf ein Objekt X, das auf der i-ten Seite liegt, wird wie folgt behandelt: 1. Ist die i-te Seite nicht im Puffer, dann übertrage sie mit input(X). 2. Wird die i-te Seite zum ersten Mal verändert, dann suche eine freie Seite auf der Platte und ordne dieser die i-te Seite in der Arbeitsseitentabelle zu. 3. Weise den Wert xi dem Objekt X im Puffer zu. Um eine Transaktion erfolgreich abzuschließen, werden folgende Schritte gesetzt: 1. Schreibe alle schmutzigen Seiten im Puffer auf die Platte. 2. Schreibe die Arbeitsseitentabelle auf die Platte. KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.17 1 . . . 2 3 4 5 . . . . . . n Seitentabelle Seiten auf der Platte Abbildung 11.1: Seitentabelle 3. Schreibe die Adresse der Arbeitsseitentabelle auf jene fixe Speicheradresse, die die Adresse der Schattenkopie enthält. Das Wiederanlaufverfahren nach einem Systemfehler oder Transaktionsfehler ist einfach: setze die Arbeit mit der Schattenkopie fort. Die Vorteile des Schattenspeicherverfahrens sind die folgenden: 1. Der Aufwand für die Verwaltung eines Logprotokolls entfällt. 2. Der Wiederanlauf ist beträchtlich schneller. Dazu kommen aber die folgenden Nachteile: • Datenfragmentierung • Freispeicherverwaltung • Schwerer als Verfahren mit Logprotokoll auf Mehrbenutzerbetrieb erweiterbar KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.18 AST SST 1 2 3 1 . . . 2 3 4 4 5 5 6 6 7 7 8 . . . Abbildung 11.2: Schattenseitentabelle und Arbeitsseitentabelle KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.5 11.19 Übungsbeispiele Übung 11.1 Das Recovery wird mit Hilfe eines Logprotokolles mit Checkpoints durchgeführt. Gegeben ist folgende Situation vor dem Crash: T1 T2 T3 T4 T5 T6 T7 Checkpoint Crash Welche UNDO- und REDO-Protokolle müssen durchgeführt werden? Welche Transaktionen müssen neu gestartet werden? Übung 11.2 Das Recovery wird mit Hilfe eines Logprotokolls mit Sicherungskopien durchgeführt. Die Situation vor dem Crash ist wie im vorhergehenden Beispiel. Nach dem Einspielen der Backup-Kopie ergibt sich folgendes Bild: T1 T2 T3 T4 T5 T6 T7 Checkpoint Crash Welche UNDO- und REDO-Protokolle müssen durchgeführt werden? Welche Transaktionen müssen neu gestartet werden? Übung 11.3 Für die Durchführung des Recovery nach einem Crash wird ein Logprotokoll mit Checkpoints geführt. Der Crash ereignet sich in folgender Situation: KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.20 T1 T2 T3 T4 T5 T6 T7 Checkpoint Crash Für den Wiederanlauf wird die zum Sicherungspunkt angelegte Backup-Kopie verwendet. Nach dem Einspielen der Sicherungskopie ergibt sich folgende Situation: T1 T2 T3 T4 T5 T6 T7 Checkpoint Crash 1. Zeichnen Sie im obigen Diagramm die notwendigen UNDO- und REDO-Protokolle ein, die nun anhand des Logprotokolles zur Wiederherstellung des konsistenten Datenbankzustandes ausgeführt werden müssen. 2. Welche Transaktionen müssen anschließend neu gestartet werden? Übung 11.4 Die Recovery wird mit Hilfe eines Logprotokolls mit Checkpoints (mit Backup) durchgeführt. Gegeben ist folgende Situation vor dem Crash. Zeichnen Sie die erforderlichen UNDO- und REDO-Protokolle ein. T1 T2 T3 T4 T5 Checkpoint Crash KAPITEL 11. WIEDERANLAUF (RECOVERY) 11.21 Annahme: Aus- und Einspielen eines Backups kostet keinen Zeitaufwand. Ist es möglich, dass bei einem Synchronisationspunkt mit Backup trotzdem mehr Aufwand für Recovery anfällt als bei einem Synchronisationspunkt ohne Backup? 11.22 KAPITEL 11. WIEDERANLAUF (RECOVERY)