X Grundlagen Liebe Seminarteilnehmerin, lieber Seminarteilnehmer, herzlich willkommen zum Seminar „Datenbanksysteme" Dieses „Tafelskript“ dient nur als ergänzende Unterlage zu den Lernmaterialien in Buchform und stellt eine Zusammenfassung (ohne Erklärungen) der wesentlichen Aspekte dar, die im Unterricht entwickelt werden. Für Streiche des „Fehlerteufels“ kann leider keine Haftung übernommen werden,... Ich wünsche Ihnen viel Spaß und Erfolg bei Ihrem Seminar! Ihr Seminarleiter Copyright 2015 Werner Weickert, Westweg 15, 85375 Neufahrn Ich danke meinen Kursteilnehmern, Kunden und Kollegen für ihre Ratschläge und Kritik. Stellvertretend seien Brigitte Fitznar und Hubert Schierl genannt. Unbefugte Vervielfältigung, Verwendung oder Weitergabe sind nicht gestattet! Im Interesse der Kunden werden alle Rechtsmittel genutzt, um gegen Verstöße gegen das Copyright vorzugehen. Warennamen werden ohne Gewähr der freien Verwendung genutzt. Für fehlerhafte Angaben wird keine Haftung übernommen. Vorlage vom 01.03.2015 / skripten2015.dotx Werner Weickert Datenbanksysteme X Werner Weickert Inhaltsverzeichnis Skript Datenbanksysteme 1. Vorteile relationaler DB-Systeme gegenüber Dateisystemen .................... 1 2. Begriffe zum Schichtenmodell ................................................................... 4 3. Datenbankmodelle ...................................................................................... 6 4. Vorgehensweise beim Erstellen einer relationalen DB ............................ 12 5. Normalisierungsprozess............................................................................ 16 6. Übungen zur Normalisierung.................................................................... 21 7. Mehrbenutzerbetrieb und Transaktionskonzept........................................ 25 8. Physische Organisation von Dateisystemen ............................................. 38 9. Physische Organisation bei Datenbanken................................................. 39 10.Primärorganisation von Dateien ............................................................... 53 11.Sekundäre Zugriffspfade........................................................................... 62 12.Recovery und Concurrency....................................................................... 75 13.Verteilte Datenbanken............................................................................... 84 14.Codd´s 12 Regeln für relationale Datenbanken........................................ 91 15.Sicherheit und Integrität............................................................................ 92 Datenbanksysteme Warum sollte ein Unternehmen seine Daten in einer DB speichern? Hauptgrund: Zentrale Kontrolle Bisher: Keine Kontrolle, da jeder Anwender zumeist seine eigenen Dateien, mitunter sogar Bänder und Platten hat →weite Streuung der Daten. DBA (Datenbankadministration) erhält zentrale Verantwortung Vorteile dieser zentralen Kontrolle sind: 1. Redundanz (Mehrfachspeicherung) wird gesenkt In dateiorientierten Systemen hat jede Anwendung ihre eigenen privaten Daten, das führt zu erheblicher Redundanz mit Speicherplatzverschwendung. Beispiel: Eine Personalanwendung und eine Schulungsanwendung speichern beide eine Abteilungsinformation über einen Arbeitnehmer. Diese beiden Dateien könnte man zusammenfassen und Redundanz eliminieren, wenn DBA die Anforderungen der beiden Anwender kennt, d.h. die zentrale Kontrolle hat. Die Redundanz lässt sich i.a. nicht total eliminieren, oft sprechen technische Gründe und sonstige Handhabungen sogar dafür, mehrere Kopien derselben Daten zu speichern. Jedoch, Kontrolle der Redundanz in DB-System sollte immer gegeben sein, d.h. dass das System die vorhandene Redundanz kennt und die Verantwortung für „saubere“ Änderungen übernimmt. 2. Inkonsistenz kann vermieden werden Durch Redundanz entstehen ggf. verschiedene Aktualitätsstände. Beispiel: Arbeiter E3 arbeitet in Abteilung D8 und dies wird an zwei verschiedenen Stellen in DB gespeichert, DBS weiß dies aber nicht, hat also keine Kontrolle darüber. Wenn bei einer Änderung nur ein Satz verändert wird, stimmen die beiden Sätze nicht mehr überein, die DB ist inkonsistent. Eine inkonsistente DB kann unkorrekte, konfliktträchtige Informationen erzeugen. Bei nur einem Eintrag (eliminierte Redundanz) kann dies nicht passieren. 1 3. Die Daten sind teilbar Verschiedene Benutzer haben Zugriff auf dieselben Daten Beispiel: Sowohl Personal- als auch Schulungsabteilung haben Zugriff auf die Informationen Arbeitnehmer, Schulungseintragungen. Außerdem können neue Anwendungen mit denselben Daten arbeiten, d.h. man braucht keine neuen Dateien schaffen, wenn man neue Anwendungen hat. 4. Standards werden gefördert Durch die zentrale Kontrolle über die DB kann DBA die Anwendung sämtlicher möglicher Standards garantieren (unternehmerspezifische, nationale, internationale). Z.B. Standardisierung der Formate gespeicherter Daten ist wünschenswert bei Datenaustausch oder Systemmigration. 5. Verbesserter Datenschutz Durch die zentrale Verfügungsgewalt kann der DBA dafür sorgen, dass der Datenzugriff über die zugelassenen Wege stattfindet und kann Autoritätskontrollen festlegen für jeglichen Zugriff auf „gefährdete“ Daten. Für jede Zugriffsart (Retrieval, Änderung, Löschung.....) kann eine eigene Kontrollmöglichkeit eingebaut werden. Wichtig: Kontrollen jetzt sogar nötiger als vorher, denn Datenschutz in DB wäre sonst noch gefährdeter als in einem traditionellen gestreuten Dateisystem. 6. Integrität lässt sich erzielen Die Daten müssen korrekt sein. Inkonsistenz ist ein Beispiel für fehlende Integrität. Aber sogar nach Eliminierung von Redundanz kann die DB noch fehlerhafte Daten enthalten, z. B. die „Tatsache laut DB“, dass ein Arbeitnehmer 200 Std./Woche gearbeitet hat. Dies lässt sich durch zentrale Kontrolle der DB vermeiden und zwar indem der DBA Wertprüfungsprozeduren definiert, die bei einer UPDATE Operation ausgeführt werden. Integrität in einer DB ist sogar wichtiger als in einem herkömmlichen System, da die Daten teilbar sind damit könnten andere Programme leichter infiziert werden. 2 7. Zuschnitt der Daten auf Anforderungen des Unternehmens So wird z.B. für die hauptsächlich auftretenden Zugriffe hoher Bedienungskomfort (mit z.B. schnellem Zugriff) geboten, auf Kosten von weniger benötigten Anwendungen. Anmerkung: Hauptvorteil bzw. sogar Ziel eines DBS ist jedoch die Datenunabhängigkeit. = Unabhängigkeit der Anwendungen gegenüber einer Änderung der Speicherstruktur (Datenstrukturunabhängigkeit) oder der Zugriffsstrategie (Zugriffspfadunabhängigkeit). Dateiorientierte Anwendungen sind datenabhängig d.h. die Art wie die Daten im Sekundärspeicher organisiert sind, wie auf sie zugegriffen wird, sind abhängig von den Anforderungen der Anwendung, mehr noch, die Kenntnis der Dateiorganisation und der Zugriffstechnik geht sogar in die Anwendungslogik ein, z.B. Speicherung in indexsequentieller Form. Die Anwendung muss wissen, dass es einen Index gibt, wie deshalb die Satzfolge aufgebaut ist. Die Struktur des Programms baut auf dieses Wissen auf. Das Programm hängt somit in hohem Maße von den Details der Schnittstelle ab, die von der IS-Software dargestellt wird. Solch eine Anwendung ist datenabhängig, weil man jetzt nicht einfach die Speicherstruktur (z.B. hash adr. oder seq. ad.) und den Zugriff ändern kann, ohne das Programm ggf. drastisch umzubauen. Innerhalb einer DB kann man sich Datenabhängigkeit nicht erlauben. Beispiele: 1. Zwei Anwendungen A und B, die dasselbe Feld benutzen, werden in eine DB integriert, Redundanz eliminiert, A braucht das Feld dezimal, B braucht es binär. Legt man sich nun fest, dass das Feld dezimal gespeichert wird, so wird es für B jedes Mal umgewandelt. (Ein typischer Fall von Abhängigkeit zwischen Anwendung und physikalischer Speicherung ohne DB) 2. DBA muss Freiheit haben Speicherstruktur und Zugriffsstrategie zu ändern, wenn sich Anforderungen ändern (z.B. neue Standards, neue Betriebsmittel zur Speicherung), ohne schon exist. Anwendungen ändern zu müssen. Änderung der Programme ist zusätzlicher Programmierereinsatz, der besser anderweitig genützt würde. Lösung: Datensubmodelle ( z.B. VIEW, SUBSCHEMA ) 3 Begriffe zu: Datenbanksysteme 1. Betrachtung der gespeicherten Daten in verschiedenen Abstraktionsebenen: a) interne Datensicht: physische Datenorganisation tatsächliche Speicherung der Daten b) konzeptionelle Datensicht: logische Gesamtsicht aller Daten c) externe Datensicht: logische Sichten einzelner Benutzergruppen auf Teile der DB 2. Schema: Abstrakte Beschreibung der Satztypen (Satztyp: Klasse von Sätzen mit qualifizierten Merkmalen und Beziehungen zu anderen Typen. z.B. LIEFERANT, TEIL, MITARBEITER, ....) a) konzeptionelles Schema: beschreibt Aufbau sämtlicher Daten in DB auf logischer Ebene mit DDL. Ankerpunkt des DB-Entwurfs. Ziel: stabiler Bezugspunkt. b) internes Schema: enthält alle Informationen über Aufbau der phys. abgespeicherten Datensätze, die Datenorganisation und die Zugriffspfade. Ziel: Festlegung ideal für Benutzergemeinschaft (Statistik über Zugriffshäufigkeiten) c) externes Schema: (Benutzerschnittstelle) ähnelt formal dem Konzept: Maßgeschneiderte Benutzersicht + Zugriffsschutz DML (Datenmanipulationssprache) ermöglicht Umgang mit logischen Sätzen auf externer Ebene. 4 Benutzer A1 Benutzer A2 Wirtssprache + DSL Wirtssprache + DSL * Externes Schema A Schema und Abbildungen werden definiert und gepflegt vom DBA mit DDL Benutzer B1 Wirtssprache + DSL Benutzer B2 Wirtssprache + DSL * Externes Externe Sicht A Benutzer B3 Wirtssprache + DSL Externe Sicht B Schema B Externe / Konzeptionelle Abb. A Externe / Konzeptionelle Abbildung B Konzeptionelles Schema Konzeptionelle Sicht DBMS Data Base Management Konzeptionelle / Interne Abbildung System Speicherstruktur definition (Internes Schema) * Benutzerschnittstelle Gespeicherte Datenbank (interne Sicht) mit DML 5 Das Relationen Modell L L# L1 L2 L3 NAME STATUS STADT Smith 20 London Jones 10 Paris Blake 30 Paris LIEF T T# T1 T2 T3 T4 TNAME Mutter Bolzen Schraube Schraube FARBE Rot Grün Blau Rot GEWICHT 12 17 17 14 6 STADT London Paris Rom London L# L1 L1 L1 L2 L2 L3 T# T1 T2 T3 T1 T2 T2 ANZ 300 200 400 300 400 200 Das Netzwerkmodell L1 Smith 20 London 300 200 T1│Mutter│Rot│12│London L2 Jones 10 Paris 400 300 L3 Blake 30 Paris 400 200 T2│Bolzen│Grün│17│Paris T3│Schraube│Blau │17│Rom T4│Schraube│Rot │14 │London 7 Das hierarchische Modell T1 Mutter Rot L2 Jones 10 12 London Paris 300 L1 Smith 20 London 300 T2 Bolzen Grün 17 Paris L3 Blake 30 Paris 200 L2 Jones 10 Paris 400 L1 Smith 20 London 200 T3 Schraube Blau 17 Rom T4 Schraube Rot 14 L1 Smith London 20 London 400 8 Q1: Finde alle L# von Lieferanten, die Teil Teilen, die Lieferant T2 liefern L2 liefert hierarchisches Modell Relationenmodell do until no more Lief. Netzwerkmodell Q2: Finde alle T# von get next Lieferung do until no more Lieferung get next Lieferung where T# = T2; print L#; end; where L# = L2 print T#; end; get [next] Teil where T# = T2; do until no more Lieferanten under this Teil; get next Lieferant under this Teil; print L#; end; do until no more Teile; get next Teil; get [next] Lieferant under this Teil where L# = L2; if found then print T#; end; get [next] Teil where T# = T2; do until no more connectors under this Teil; get next connector under this Teil; get Lieferant over this connector; print L#; end; get [next] Lieferant where L# = L2; do until no more connectors under this Lieferant; get next connector under this Lieferant; get Teil over this connector; print T#; end; 9 Netzdatenbanken - relationale Datenbanken ● Netzdatenbanken - halten die Struktur einer Anwendungsumgebung in der Datenbank als Netz fest. Dadurch sind die Zugriffszeiten bei Standardanwendungen kurz (z.B. beim Anzeigen eines Arbeitsplans etwa 5% der Plattenzugriffe gegenüber einer relationalen Organisation). Auch die Konsistenz der Datenbank ist einfacher zu gewährleisten, denn wenn ein Wurzelknoten gelöscht wird, dann entfallen automatisch auch alle abhängigen Knoten. ● Relationale Datenbanken - sind demgegenüber für universelle Anwendungen geeignet, da die Struktur der Anwendung im Anwendungsprogramm und nicht in der Datenbank steckt. Der Suchaufwand und der Speicherbedarf für Schlüssel sind größer. Der größte Vorteil besteht aber darin, dass mächtige Abfragesprachen zur Verfügung stehen, die es auch dem Laien gestatten, komplexe Suchfragen an die Datenbank zu stellen. Zusammenfassung: Netzartige Datenbanken (entwickelt nach dem Bericht der DBTG der CODASYL aus dem Jahr 1971) sind für komplexe, anwendungsspezifische, verarbeitungsintensive Fälle wie z.B. Nettobedarfsermittlung oder Netzplantechnik, ideal geeignet. Relationale Datenbanken (Codd 1970-71) eignen sich für Abfragesysteme besser. 10 Relationale Datenbanksprachen 1. Einfachheit aufgrund „relationaler Vollständigkeit“. d.h. ≈ jede in der DB enthaltene Information kann mit einer einzigen Abfrage gefunden werden (Hilfe: built-in Funktionen). 2. Mengenorientierte Verarbeitung Ein Abfragebefehl betrifft alle Zeilen einer oder mehrerer Tabellen, die den im Abfragebefehl definierten Bedingungen genügen. ( ≠ satzorientierte Abfragesprachen) 3. „Nichtprozedurale“ Sprache Der Benutzer gibt nur an, welche Daten er möchte und nicht eine Prozedur wie diese Daten aufzufinden sind. („optimale Wahl des Zugriffspfads“, „automatische Navigation“) Aufgrund „Data Dictionary“ Festlegung des Zugriffs. 4. Einheitlichkeit der Sprache In jeder Betriebsart die gleiche Syntax für alle Operationen: „direkt“ vom Bildschirm (interaktiv), aus Programmen 5. Datenunabhängigkeit Anwendung ist unabhängig von physischer und logischer Datenstruktur. (Kein expliziter Bezug der Befehle darauf). 6. Unterstützung von Programmiersprachen Einbettung der Befehle in Programmiersprachen 11 I. Abstraktionsprozess Für die Erstellung des konzeptionellen Modells bedient man sich der Abstraktion. Beispiel: Bibliotheksverwaltungssystem 1. Auswahl (Selektion): Das Ziel dieses Schrittes ist, die Vielfalt von Objekten der Realwelt auf eine als relevant erachtete, leichter überschaubare Menge von Objekten des Modells zu reduzieren. Auch die interessierenden Objekte können nicht zur Gänze beschrieben werden: Die Beziehungen und Attribute einzelner selektierter Objekte sind zu vielfältig, um vollständig dargestellt zu werden. Die Selektion beschränkt sich also nicht nur auf die Auswahl von Objekten, sondern umfasst auch die Bestimmung von Attributen und Beziehungen. Bei dem Beispiel interessieren uns als Realweltobjekte Bücher, Autoren und Kunden der Bibliothek, aber nicht Städte oder Minister. Ein Buch soll durch die Attribute Inventarnummer, Titel, Verlag, Erscheinungsdatum und Ort-, Preis und zwei Stichworte, ein Autor durch die Attribute Vor- und Zuname und ein Kunde durch die Attribute Kundennummer, Vor- und Zuname und Adresse beschrieben werden. Uninteressant sind die Automarken oder die Anzahl der Zahnfüllungen der Kunden oder die Farbe der Bucheinbände. Dann werden die Beziehungen zwischen den ausgewählten Entitytypen festgelegt. 2. Benennung Jedem Objekt der Realität, jeder Beziehung und jedem Attribut wird ein eindeutiger Name, ein Bezeichner zugeordnet. Das Ergebnis ist eine Informationsstruktur, die grafisch dargestellt werden kann, z.B. in einem EntityRelationship-Diagramm. 3. Klassifikation Die inhomogene Menge der Objekte und Beziehungen wird weiter in homogene Klassen von Objekttypen unterteilt. Kriterien der Klassifikation sind entweder sachbezogener oder verarbeitungstechnischer Natur. Der Grad der Klassifikation, d.h. wie detailliert die Strukturierung vorgenommen wird, ist von Fall zu Fall verschieden. Beim Beispiel der Bibliothek: Durch die Systematisierung der Attribute durch Objekttypen wurde bereits ein Teil der Klassifikation vorweggenommen. Das Ergebnis dieses Modellierungsvorganges nennt man konzeptionelles Modell (engl. conceptual model ) 12 II. Datenbankstrukturen Nun muss noch ein geeignetes Datenmodell für die Repräsentation der Daten bestimmt werden, da die Informationsstruktur noch nicht genügend „computergerecht“ ist. Tabellen, Netze, Baumstrukturen oder ähnliches lassen sich besser im Rechner abbilden. Welches Grundelement (Tabelle, Netz, Baum) verwendet wird, bestimmt das Datenbank-Verwaltungssystem. Entscheidet man sich für ein bestimmtes DBVS, so ist damit auch das Datenmodell vorgegeben, da ein DBMS/DBVS i.d.R. nur ein Datenmodell zulässt. Das verwendete Datenmodell klassifiziert somit das Datenbanksystem und man spricht deswegen auch häufig von „Netzwerkdatenbanken“ oder „relationalen Datenbanken“. Das Datenmodell dient also dazu, die Informationsstruktur auf ein bestimmtes Datenbanksystem zugeschnitten zu beschreiben. 13 III. Schritte des Datenbankentwurfs Die Organisation der Daten in einer Datenbank muss formal beschrieben werden. Der Weg bis dorthin kann in mehrere Schritte untergliedert werden: Informationsbedarfsanalyse: ● Feststellen, welche Informationen relevant sind ● Herausfinden der zu realisierenden Funktionen ● Identifikation der zu unterstützenden Aufgaben und der betroffenen Orgeinh. ● Ermittlung der Personen, die für die Präzisierung und Realisierung der betreffenden Aufgabenlösung relevante Informationen liefern können ● Anforderungssammlung bei den Informationslieferanten ● Filterung der gesammelten Informationen ● Klassifikation der gesammelten Informationen konzeptioneller Entwurf: ● Vermeidung von Unvollständigkeiten und Inkonsistenzen ● Vereinfachung der Weiterverarbeitung ● Entwurfsmethoden formal (Normalisierung) [entwickelt im Zusammenhang mit dem Relationsmodell] - analytisch: Zusammenstellungen von Datenfeldern (gewonnen aus Formularen und Übersichten) werden durch fortgesetzte Aufspaltung (Analyse) zerlegt, bis die gewünschte Normalform erreicht ist. - synthetisch :ausgehend von Datenfeldern und deren funktionaler Abhängigkeiten werden normalisierte Relationen zusammengesetzt semantisch [nicht an eine bestimmte Datenbankstruktur bezogen ] Objekt-Beziehungsmodell: ein Modell der Realität, bei dem Bedeutung und Zusammenhänge der Daten erkennbar bleiben 14 Normalisierung ● Die Normalisierung ist eine formale Methode zur Gewinnung zweckmäßiger Relationen Hauptziele der Normalisierung sind: ◙ Analyse von Abhängigkeiten ◙ Beseitigung von Redundanzen (und somit möglichen Inkonsistenzen) ◙ Erleichterung der Datenbankoperationen Ändern, Einfügen und Löschen ● Durch Zerlegung wird eine mit Redundanz behaftete Ausgangsrelation schrittweise in kleinere Tabellen zerlegt ● Die Eigenschaften, welche die Zielrelation besitzen sollen, werden durch die Normalformen beschrieben ● Die Zerlegung muss so erfolgen, dass durch Verbund wieder die ursprüngliche Relation zu erhalten ist; außerdem müssen die Abhängigkeiten der Attribute erhalten bleiben ● Das Normalisieren kann zu kleinen und kleinsten Tabellen führen, weswegen relationale Datenbanksysteme bei der Wiedergewinnung von Information üblicherweise langsamer sind als z.B. hierarchische DBS ● Man unterscheidet heute sieben Normalformen. Ein guter Entwurf sollte auf jeden Fall bis zur 3NF durchgeführt werden Streng relationale Datenbanksysteme zweidimensionale Tabellen. verarbeiten nur flache, d.h. Alle Attribute müssen also elementar sein. Daraus ergibt sich die Definition der ersten Normalform. 15 Erste Normalform (1NF) Definition: Eine Relation ist in erster Normalform (1NF), wenn jedes Attribut elementar aus der Sicht des Datenbanksystems ist und die Tabelle eine feste Breite hat. (In einer 1NF-Relation kann es also z.B. keine vektor-, matrix-, listenoder mengenwertigen Attribute geben. Es gibt keine Wiederholungen) Aus der unnormalisierten Tabelle entsteht eine 1NF-Relation, indem durch Einführen von Redundanz jedes Attribut eines Tupels der Tabelle einen Wert zugewiesen bekommt und ein Primärschlüssel zur eindeutigen Identifizierung jedes Tupels definiert wird 1NF-Relation: BESTELLUNG(Lief_Nr, Lief_Name, Best_Nr, Best_Dat, Best_Pos, Art_Nr, Liefertermin) Probleme bei redundanten Tabellen (Mutationsanomalien) Änderungsanomalien Ändert ein Lieferant seinen Firmennamen, so muss er in allen Tupeln verändert werden, in denen er vorkommt. Löschanomalien Werden alle Zeilen mit Bestellungen bei einem bestimmten Lieferanten gelöscht, geht gleichzeitig die Information über den Lieferanten selbst verloren. Einfügeanomalien Solange ein Lieferant keine Bestellung entgegengenommen hat, ist er nicht in der Tabelle gespeichert. Funktionale Abhängigkeit Die Normalisierung beginnt mit der Untersuchung der Abhängigkeiten zwischen den Attributen einer Relation. Man unterscheidet im Wesentlichen funktionale und mehrwertige Abhängigkeiten. Definition: B heißt funktional abhängig von A (geschrieben: A→B), wenn in jedem Tupel, in dem A vorkommt, derselbe Wert für B existiert. Die funktionale Abhängigkeit B von A verlangt somit, dass jeder Wert von A eindeutig einen Wert von B bestimmt. Da alle Id-Schlüssel die Eigenschaft haben, dass die Nichtschlüsselattribute eindeutig vom Schlüssel abhängig sind, gilt somit allgemein für einen Id-Schlüssel S und für ein beliebiges Attribut B einer bestimmten Tabelle die funktionale Abhängigkeit S -> B. 16 Definition des Primärschlüssels Für einen Primärschlüssel gelten folgende Forderungen: ● Jedes Nicht-Schlüssel-Attribut ist vom Schlüssel funktional abhängig (garantiert eindeutige Identifizierung) ● Bei Verbundschlüsseln ist kein Schlüsselattribut von den übrigen Schlüsselattributen abhängig Volle funktionale Abhängigkeit (bei Verbundschlüsseln erforderlich) Definition: B heißt voll funktional abhängig von A (geschrieben A B), wenn B von allen Elementen von A abhängt und nicht nur von einem Teil von ihnen. Die Betrachtung der 1NF-Relation zeigt folgende Abhängigkeiten: Lief_Nr Lief_Name Best-Nr ist die Determinante für Lief-Nr, Lief-Name und Best-Dat (nicht voll funktional abhängig) Best_Nr Best_Dat Best_Pos Best-Nr und Best-Pos bilden die Determinante für Art-Nr und Liefertermin Art_Nr Liefertermin 17 Zweite Normalform (2NF) Definition: Eine Relation ist in zweiter Normalform, wenn sie in 1NF ist und jedes Nicht-Schlüssel-Attribut vom gesamten Schlüssel abhängt (volle funktionale Abhängigkeit) Anmerkung: Dies gilt trivialerweise für alle 1NF-Relationen deren Schlüssel nur aus einem Attribut besteht. 1NF-Relationen können gewöhnlich durch Spaltung in 2NF-Relationen überführt werden. Zerlegungsregel: Alle Attribute, die von einem Teil des Schlüssels abhängen, werden aus der ursprünglichen Relation herausgelöst und bilden eine neue Relation. Diese erhält als Schlüssel den Teil des Verbundschlüssels, von dem ihre Attribute voll funktional abhängig sind. 2-NF-Relationen: BESTELLUNG (Best_Nr, Lief_Nr, Lief_Name, Best_Dat) BESTELLPOSITION (Best_Nr, Best_Pos, Art_Nr, Liefertermin) 18 Indirekte (transitive) Abhängigkeit Definition: C ist von A transitiv abhängig, wenn es eine zwischengeschaltete Attributmenge B gibt, so dass gilt: A → C und A → B und B → C Anschaulich: In der Menge der Nicht-Schlüssel-Attribute darf es nicht selbst noch einmal funktionale Abhängigkeiten geben. In unserem Beispiel ist dies der Fall: Best-Dat Best-Nr Lief-Nr Lief-Name Indirekte Abhängigkeit Indirekte Abhängigkeiten vom Schlüssel können durch Spaltung der Relation beseitigt werden. 19 Dritte Normalform (3NF) Definition: Eine Relation ist in dritter Normalform, wenn sie in 2NF ist und kein Nicht-Schlüssel-Attribut indirekt (transitiv) vom Schlüssel abhängt. 2NF-Relationen können gewöhnlich durch Spaltung in 3NF-Relationen überführt werden. Zerlegungsregel: Transitiv vom Schlüssel abhängige Attribute (z.B. Lief-Name) werden zusammen mit ihrer Nicht-Schlüssel-Determinante (hier: Lief-Nr) herausgelöst. Die Determinante (hier: Lief-Nr) wird zum Schlüssel in der herausgelösten Relation. In der Ausgangsrelation verbleibt die Determinante (hier: Lief-Nr) als Fremdschlüssel. Da keine weiteren Zerlegungen erforderlich sind, können die Relationen mit endgültigen Namen versehen werden. 3NF-Relationen: BESTELLUNG (Best_Nr, Lief_Nr, Best_Dat) BESTELLPOSITION (Best_Nr, Best_Pos, Art_Nr, Liefertermin) LIEFERANT (Lief_Nr, Lief_Name) 20 Übungen: 1. Attribute: Ein Informationssystem soll u.a. die folgenden Objektarten enthalten: ● Personal ● Teil ● Lieferant ● Eingangsrechnung ● Eingangsrechnungsposition Stellen Sie für jede Objektart vier relevante Merkmale zusammen und wählen Sie einen (natürlichen oder künstlichen) Schlüssel. 2. Objekt-Beziehungsdiagramm Zeichnen Sie für die Objektarten Teil, Lieferant, Eingangsrechnung und Eingangsrechnungs-Position ein Objekt-Beziehungs-Diagramm. Entität E1 Beziehung Entität E2 3. Umsetzung einer Beschreibung in das OBM In einer Projekt-DB sollen Daten über Bearbeiter, Projekte und die Zuständigkeit der Bearbeiter für bestimmte Projekte gespeichert werden. Zur Organisation seien folgende Angaben gemacht: Für ein Projekt ist nur ein Bearbeiter zuständig, ein Bearbeiter kann aber für mehrere Projekte zuständig sein. Jeweils ein anderer Bearbeiter ist als Vertreter bestimmt, der bei Abwesenheit des zuständigen Bearbeiters einspringt. 21 4. Umsetzung einer Beschreibung in das OBM Werkstattmitarbeiter einer Standortverwaltung werden zur Reparatur von Maschinen in allen Liegenschaften des Verwaltungsbereichs eingesetzt. Für einen Maschinentyp ist jeweils ein bestimmter Reparateur zuständig. Jeder Maschinentyp kann in allen Liegenschaften vorkommen. Entwerfen Sie ein Objekt-Beziehungs-Modell, das folgende Informationen darstellen soll: ● Zuständigkeit der Mitarbeiter für bestimmte Maschinentypen ● Vorhandensein von Maschinen in den Liegenschaften ● Arbeitseinsätze, die die einzelnen Reparateure in den einzelnen Liegenschaften an den einzelnen Maschinen geleistet haben. ● Zugehörigkeit der einzelnen Maschinen zu Maschinentypen. 22 5. Wohnungsvermittlung Eine Agentur vermittelt Wohnungen. Um Kundenwünsche gezielt beantworten zu können, werden Mietobjekte mit gemeinsamen Merkmalen in Kategorien zusammengefasst und dort pauschal beschrieben (z.B.: Mehrfamilienhaus im Stadtzentrum, Einfamilienhaus in Vorort mit Straßenbahnanschluss, …). Von den einzelnen Gebäuden sind die Adresse und der Zustand der Bausubstanz von Interesse. Für jede Wohnung sind Informationen über die Miete, die Höhe einer möglichen Kaution und bis wann sie belegt sind, zu speichern. Darüber hinaus sind Angaben über die Räume, samt Größe und Ausstattung zu machen. Kunden der Agentur werden mit allen erforderlichen Daten gespeichert. Ein Kunde kann beliebig viele Wohnungsanfragen (Aufträge) stellen. Jeder Auftrag bezieht sich aber auf einen ganz bestimmten Wohnungstyp. Ein Auftrag wird von einem ganz bestimmten Mitarbeiter bearbeitet und resultiert schließlich in einem Vermittlungsangebot, das eine beliebige Anzahl von Wohnungen enthalten kann. 1. Ordnen Sie die folgenden Attribute so, daß ein Eindruck von den möglichen Objektarten (Entitytypen) entsteht. Kategorie, Telefon, Kaution, Name, gültig bis, Geb_Nr, PLZ, Zustand, Wohn_Nr, Miete, Beschreibung, Eigentümer, Verm_Prov, belegt_bis, Raum_Art, Größe, Ausstattung, Kd_Nr, Baujahr, Anschrift, Auftr_Nr, Straße, Datum, Bearbeiter, Angeb_Nr, Ort, Angeb_Datum. 2. Kennzeichnen Sie den jeweiligen Primärschlüssel. 3. Erstellen Sie ein Entity-Relationship-Diagramm. 4. Übertragen Sie das E-R-Diagramm in das Relationenmodell, d.h. a) zerlegen Sie ggf. komplexe Objekte in primitive Objekte b) überführen Sie n:m-Beziehungen in eigene Tabellen c) ergänzen Sie ggf. erforderliche Fremdschlüssel. 23 6. Normalisieren Gegeben sei die unnormalisierte Tabelle PRÜFUNGSGESCHEHEN Prü- Fach Prüfer Matr.- Name Geb.- Adres- Fachbe- Fachbe- Dekan Note fungsNr. Tag se reichs- reichsNr. Nr. name 3 SP Hoff 123 Huber 011068 xx 20 E-Tech Holst 3 4 5 BS Carl RO Manz 456 Maier 210869 yy 20 E-Tech Holst 2 123 Huber 011068 xx 20 E-Tech Holst 2 456 Maier 210869 yy 20 E-Tech Holst 1 123 Huber 011068 xx 20 E-Tech Holst 2 789 Bauer 130568 zz 19 Inform Abel 5 a) Entwerfen Sie auf der Basis dieser unnormalisierten Relation eine flache, also zweidimensionale, Tabelle. b) Kennzeichnen Sie in Form einer Skizze die funktionalen Abhängigkeiten. c) Bestimmen Sie einen Schlüssel für die 1NF-Relation. d) Zerlegen Sie die Relation weiter, so dass die daraus entstehenden Relationen in 2NF sind. Wie lautet die Zerlegungsregel? e) Prüfen Sie, ob bzw. welche der Relationen sich bereits in 3NF befinden. Falls erforderlich zerlegen Sie weiter, bis sich alle Relationen in 3NF befinden. Wie lautet die Zerlegungsregel? f) Erstellen Sie das Objekt-Beziehungs-Diagramm, das diesem logischen Schema entspricht. 24 Mehrbenutzerbetrieb (vgl. Meier, Andreas: Relationale Datenbanken, Springer Verlag) Der Begriff der Transaktion Die Integrität der Daten zu gewährleisten ist eine der wichtigsten Forderungen aus der Sicht der Datenbankanwender. Die Transaktionenverwaltung eines Datenbanksystems dient dazu, mehreren Benutzern ein konfliktfreies Arbeiten zu ermöglichen. Dabei dürfen Änderungen in der Datenbank nach außen erst sichtbar werden, wenn die von den Benutzern definierten Integritätsbedingungen alle respektiert sind. Unter dem Begriff der Transaktion (transaction) versteht man an Integritätsregeln gebundene Datenbankoperationen, die Datenbankzustände konsistenzerhaltend nachführen. Präziser ausgedrückt, eine Transaktion ist eine Folge von Operationen, die atomar, konsistent, isoliert und dauerhaft sein muss: Atomarität gehorcht dem Alles-oder-Nichts-Prinzip Eine Transaktion wird entweder komplett durchgeführt, oder sie hinterlässt keine Spuren ihrer Wirkung auf der Datenbank. Die von einzelnen Operationen erzeugten Zwischenzustände einer bestimmten Transaktion sind für die übrigen konkurrierenden Transaktionen nicht spürbar. In diesem Sinne bildet die Transaktion eine Einheit für die Rücksetzbarkeit nicht abgeschlossener Transaktionen. Konsistenz bedeutet Widerspruchsfreiheit der Daten Während der Transaktion mögen zwar einzelne Konsistenzbedingungen zeitweise verletzt, bei Transaktionsende müssen jedoch alle wieder erfüllt sein. Eine Transaktion bewirkt also die Überführung einer Datenbank von einem konsistenten Zustand in einen anderen und garantiert die Widerspruchsfreiheit der Daten. Sie wird als Einheit zur Konsistenzerhaltung aufgefasst. Isolation schützt vor Seiteneffekten Das Prinzip der Isolation verlangt, dass gleichzeitig ablaufende Transaktionen dieselben Resultate wie im Falle einer Einbenutzerumgebung erzeugen müssen. Falls einzelne Transaktionen isoliert von parallel ablaufenden erscheinen, bleiben diese vor ungewollten Seiteneffekten geschützt. Die Transaktion gilt damit als Einheit für Serialisierbarkeit. 25 Dauerhaftigkeit setzt Rekonstruierbarkeit voraus Datenbankzustände müssen so lange gültig und erhalten bleiben, bis sie von Transaktionen verändert werden. Bei Programmierfehlern, Systemabbrüchen oder Fehlern auf externen Speichermedien garantiert die Dauerhaftigkeit die Wirkung einer korrekt abgeschlossenen Transaktion. Von den Wiederanlauf- und Wiederherstellungsverfahren von Datenbanken her gesehen kann jede Transaktion als Recovery-Einheit aufgefasst werden. Die vier Begriffe Atomarität (Atomicity), Konsistenz (Consistency), Isolation (Isolation) und Dauerhaftigkeit (Durability) beschreiben das so genannte ACIDPrinzip einer Transaktion. Dieses ist für Datenbanksysteme grundlegend und garantiert jedem Anwender, konsistente Datenbankzustände in ebensolche überführen zu können. Zwischenzeitlich inkonsistente Zustände bleiben nach außen unsichtbar und werden im Fehlerfall rückgängig gemacht. Um eine Folge von Operationen als Transaktion zu deklarieren, muss der Anwender die Datenbankoperationen durch ein BEGIN_OF_TRANSACTION und durch ein END_OF_TRANSACTION kennzeichnen. Start und Ende einer Transaktion signalisieren dem Datenbanksystem, welche Operationen eine Einheit bilden und durch das ACID-Prinzip geschützt werden müssen. Serialisierbarkeit Bei der Beschreibung von Betriebssystemen und Programmiersprachen kommt der Koordination (Synchronisation) aktiver Prozesse und dem wechselseitigen Ausschluss konkurrierender Prozesse eine große Bedeutung zu. Auch bei Datenbanksystemen müssen konkurrierende Zugriffe auf dieselben Datenobjekte serialisiert werden, da die einzelnen Datenbankanwender unabhängig voneinander arbeiten möchten. 26 Prinzip der Serialisierbarkeit Ein System gleichzeitig ablaufender Transaktionen heißt korrekt synchronisiert, wenn es eine serielle Ausführung gibt, die denselben Datenbankzustand erzeugt. Bei parallel ablaufenden Transaktionen garantiert das Prinzip der Serialisierbarkeit, dass die Resultate auf den Datenbanken identisch sind, gleichgültig ob die Transaktionen streng nacheinander ausgeführt worden sind oder nicht. Um Bedingungen zur Serialisierbarkeit festlegen zu können, gilt bei den einzelnen Transaktionen unser Augenmerk den READ- und WRITEOperationen, die das Lesen und Schreiben von Tupeln oder Datensätzen auf der Datenbank bewerkstelligen. Das klassische Beispiel zur Illustration konkurrierender Transaktion stammt aus dem Bankbereich. Bei Buchungstransaktionen lautet die grundlegende Integritätsbedingung, dass Kontobelastungen und –gutschriften sich gegenseitig ausgleichen müssen. Die Abbildung 1 zeigt zwei parallel ablaufende Buchungstransaktionen mit ihren READ- und WRITE-Operationen in zeitlicher Abfolge. Jede Buchungstransaktion verändert für sich betrachtet die Gesamtsumme der Bestände der Konten a, b und c nicht. So schreibt die Transaktion TRX_1 dem Konto a 100 Währungseinheiten gut und belastet gleichzeitig das Gegenkonto b mit 100 Währungseinheiten. Entsprechendes gilt für die Buchungstransaktion TRX_2 mit dem Konto b und dem Gegenkonto c für den Betrag von 200 Währungseinheiten. Beide Buchungstransaktionen erfüllen somit die Integritätsbedingung der Buchführung, da sich die Salden zu Null aufheben. Bei der gleichzeitigen Ausführung der beiden Buchungstransaktionen hingegen entsteht ein Konflikt: Die Transaktion TRX_1 übersieht die von TRX_2 vorgenommene Gutschrift2 b:=b+200, da diese Wertveränderung nicht sofort zurück geschrieben wird, und liest im Konto b einen „falschen“ Wert. Nach erfolgreichem Abschluss der beiden Buchungstransaktionen enthält das Konto a den ursprünglichen Wert plus 100 Einheiten (a+100), b hat sich um 100 Einheiten verringert (b-100) und c ist um 200 Einheiten gekürzt worden (c-200). Die Summe der Belastungen und Gutschriften ist nicht konstant geblieben, und die Integritätsbedingung ist verletzt, da im Konto b der Wert b+200 von der Transaktion TRX_1 übersehen statt verrechnet worden ist. 27 BEGIN_OF_TRX_1 BEGIN_OF_TRX_2 READ (a) READ (b) a:= a + 100 WRITE (a) b:= b + 200 READ (b) WRITE (b) b:= b - 100 READ (c) WRITE (b) c:= c – 200 WRITE (c) END_OF_TRX_2 END_OF_TRX_1 ZEIT Abb. 1 Konfliktträchtige Buchungstransaktionen Wie sind nun Konfliktsituationen zu erkennen? Aus der Menge aller Transaktionen führt der Weg dieser Untersuchung jeweils über diejenigen READ- und WRITE-Operationen, die sich auf ein bestimmtes Objekt, d.h. einen einzelnen Datenwert, einen Datensatz, eine Tabelle oder im Extremfall sogar eine ganze Datenbank beziehen. Von der Granularität (der relativen Größe) dieser Objekte hängt es nämlich ab, wie gut die heraus gepflückten Transaktionen parallelisiert werden können. Je gröber die Granularität des Objektes gewählt wird, desto kleiner wird der Grad der Parallelisierung von Transaktionen und umgekehrt. Die objektwirksamen READ- und WRITE-Operationen aus unterschiedlichen Transaktionen werden deshalb im so genannten Logbuch (log) des Objektes x, im LOG(x), festgehalten. Das Logbuch LOG(x) eines bestimmten Objektes x listet in zeitlicher Abfolge alle READ- und WRITEOperationen auf, die auf das Objekt x zugreifen. Für das Beispiel der parallelen Buchungstransaktionen TRX_1 und TRX_2 wählen wir die einzelnen Konten a, b und c als Objektgrößen. Wie in Abb. 2 dargestellt, erhält das Logbuch für das Objekt b beispielsweise vier Einträge (vgl. dazu obige Abb.). Zuerst liest Transaktion TRX_2 den Datenwert b, anschließend liest TRX_1 denselben Wert, noch bevor die Transaktion TRX_2 den veränderten Datenwert b zurück schreibt. Den letzten Eintrag ins Logbuch verursacht die Transaktion TRX_1, die mit ihrem veränderten Wert b jenen der Transaktion TRX_2 in der Datenbank überschreibt. 28 Eine Auswertung der Logbücher erlaubt uns nun auf einfache Weise, Konflikte bei konkurrierenden Transaktionen zu analysieren. Der so genannte Präzedenzgraph (precedence graph) stellt die Transaktionen als Knoten und die möglichen READ_WRITE oder WRITE_WRITE_Konflikte durch gerichtete Kanten (gebogene Pfeile) dar. Bezogen auf ein bestimmtes Objekt kann nämlich ein auf ein READ oder WRITE folgendes WRITE zu einem Konflikt führen. Hingegen gilt allgemein, dass mehrmaliges Lesen nicht konfliktträchtig ist. Aus diesem Grunde hält der Präzedenzgraph keine READ_READ-Kanten fest. Logbuch Präzedenzgraph für Datenwert b TRX_2 LOG (b) TRX_2: READ TRX_1: READ READ_WRITEKante WRITE_ WRITEKante TRX_2:WRITE TRX_1 TRX_1: WRITE READ_WRITE-Kante: auf ”TRX_1: READ” folgt “TRX_2: WRITE” WRITE_WRITE-Kante: auf “TRX_2: WRITE” folgt “TRX_1: WRITE” Abb. 2 Auswertung des Logbuches durch den Präzedenzgraphen Die Abbildung zeigt für die beiden Buchungstransaktionen TRX_1 und TRX_2 neben dem Logbuch des Objektes b auch den zugehörigen Präzedenzgraphen. Gehen wir vom Knoten TRX_1 aus, so folgt auf ein READ des Objektes b ein WRITE desselben durch Transaktion TRX_2, dargestellt durch eine gerichtete Kante vom Knoten TRX_1 zum Knoten TRX_2. Vom Knoten TRX_2 aus erhalten wir gemäß Logbuch eine WRITE_WRITE-Kante zum Knoten TRX_1, da auf ein WRITE von TRX_2 ein weiteres WRITE desselben Objektes b von TRX_1 folgt. Der Präzedenzgraph ist also zyklisch oder kreisförmig, da von einem beliebigen Knoten ausgehend ein gerichteter Weg existiert, der zum Ursprung zurückführt. Diese zyklische Abhängigkeit zwischen den beiden Transaktionen TRX_1 und TRX_2 zeigt klar, dass sie nicht serialisierbar sind. 29 Serialisierbarkeitskriterium Eine Menge von Transaktionen ist serialisierbar, wenn die zugehörigen Präzedenzgraphen keine Zyklen aufweisen. Das Serialisierbarkeitskriterium besagt, dass die verschiedenen Transaktionen in einer Mehrbenutzungsumgebung dieselben Resultate liefern wie in einer Einbenutzerumgebung. Zur Gewährleistung der Serialisierbarkeit verhindern pessimistische Verfahren von vornherein, dass überhaupt Konflikte bei parallel ablaufenden Transaktionen entstehen können. Optimistische Verfahren nehmen Konflikte in Kauf, beheben diese jedoch durch Zurücksetzen der konfliktträchtigen Transaktionen im nachhinein. Pessimistische Verfahren Eine Transaktion kann sich gegenüber anderen absichern, indem sie durch Sperren die zu lesenden oder zu verändernden Objekte vor weiteren Zugriffen schützt. Exklusive Sperren (exclusive locks) sind solche, die ein bestimmtes Objekt ausschließlich von einer Transaktion bearbeiten und die übrigen konkurrierenden Transaktionen abweisen oder warten lassen. Sind solche Sperren gesetzt, müssen die übrigen Transaktionen warten, bis die entsprechenden Objekte wieder freigegeben sind. In einem Sperrprotokoll (locking protocol) wird festgehalten, auf welche Art und Weise Sperren verhängt bzw. aufgehoben werden. Falls Sperren zu früh oder leichtsinnig zurückgegeben werden, können nicht serialisierbare Abläufe entstehen. Auch muss verhindert werden, dass mehrere Transaktionen sich gegenseitig blockieren und eine so genannte Verklemmung oder Blockierung („Deadlock“) heraufbeschwören. Für das exklusive Sperren von Objekten sind die beiden Operationen LOCK und UNLOCK notwendig. Grundsätzlich muss jedes Objekt gesperrt werden, bevor eine Transaktion darauf zugreift. Falls ein Objekt x durch eine Sperre LOCK(x) geschützt ist, kann dieses von keiner anderen Transaktion gelesen oder verändert werden. Erst nach Aufheben der Sperre für Objekt x durch UNLOCK(x) kann eine andere Transaktion erneut eine Sperre erwirken. Normalerweise unterliegen Sperren einem wohldefinierten Protokoll und können nicht beliebig angefordert und zurückgegeben werden: 30 Zweiphasen-Sperrprotokoll Das Zweiphasen-Sperrprotokoll (two-phase locking protocol) untersagt einer Transaktion, nach dem ersten UNLOCK (Entsperren) ein weiteres LOCK (Sperren) zu verlangen. Mit Hilfe dieses Sperrprotokolls läuft eine Transaktion immer in zwei Phasen ab: In der Wachstumsphase werden sämtliche Sperren angefordert und errichtet, in der Schrumpfungsphase werden die Sperren sukzessive wieder freigegeben. Bei einer Transaktion mit Zweiphasen-Sperrprotokoll dürfen also innerhalb der Wachstumsphase nur LOCKs nach und nach oder alle auf einmal gesetzt, jedoch nie freigegeben werden. Erst in der Schrumpfungsphase können UNLOCKs stufenweise oder gesamthaft am Ende der Transaktion wieder ausgegeben werden. Das Zweiphasen-Sperrprotokoll verbietet somit ein Durchmischen von Errichten und Freigeben von Sperren. BEGIN_OF_TRX_1 LOCK (a) READ (a) a:=a+100 WRITE (a) Sperren LOCK (b) Entsperren UNLOCK (a) LOCK (b) READ (b) UNLOCK (a) b:= b-100 WRITE (b) LOCK (a) UNLOCK (b) UNLOCK (b) END_OF_TRX_1 Zeit Abb. 3 Beispiel für ein Zweiphasen-Sperrprotokoll der Transaktion TRX_1 31 Die voran gegangene Abbildung 3 illustriert für die Buchungstransaktion TRX_1 ein mögliches Zweiphasen-Sperrprotokoll. In der Wachstumsphase wird nacheinander das Konto a wie das Gegenkonto b gesperrt, bevor beide Konten sukzessive wieder freigegeben werden. Bei diesem Beispiel wäre auch möglich, beide Sperren gleich zu Beginn der Transaktion zu verfügen, anstatt sie im zeitlichen Ablauf nacheinander errichten zu lassen. Analog könnten die beiden Sperren auch am Ende der Transaktion TRX_1 nicht gestaffelt, sondern gesamthaft aufgehoben werden. Da die Wachstumsphase schrittweise für die Objekte a und b Sperren erwirkt, die Schrumpfungsphase diese schrittweise wieder freigibt, wird der Grad der Parallelisierung der Transaktion TRX_1 erhöht. Würden nämlich die beiden Sperren zu Beginn gesetzt und erst am Ende der Transaktion wieder zurückgegeben, müssten konkurrierende Transaktionen während der gesamten Verarbeitungszeit von TRX_1 auf die Freigabe der Objekte a und b warten. Allgemein gilt, dass das Zweiphasen- Sperrprotokoll die Serialisierbarkeit parallel ablaufender Transaktionen garantiert. Pessimistische Synchronisation (pessimistic concurrency control) Jede Menge konkurrierender Transaktionen ist dank Anwendung des Zweiphasen- Sperrprotokolls serialisierbar. Aufgrund der strikten Trennung der Wachstums- von der Schrumpfungsphase lässt sich zeigen, dass das Zweiphasen- Sperrprotokoll zyklische Abhängigkeiten in sämtlichen Präzedenzgraphen von vornherein verhindert; die konkurrierenden Transaktionen bleiben konfliktfrei. Für die beiden Buchungstransaktionen TRX_1 und TRX_2 bedeutet dies, dass sie bei geschickter Organisation von Sperren und Entsperren parallelisiert werden können, ohne dass die Integritätsbedingung verletzt wird. Abbildung 4 untermauert die Behauptung, dass die beiden Transaktionen TRX_1 und TRX_2 konfliktfrei ablaufen können. Dazu werden LOCKs und UNLOCKs nach den Regeln des Zwei-Phasen-Sperrprotokolls gesetzt. Damit kann beispielsweise das von TRX_2 gesperrte Konto b erst in der Schrumpfungsphase wieder freigegeben werden, und TRX_1 muss beim Anfordern der Sperre für b warten. Sobald TRX_2 das Konto b durch UNLOCK(b) entsperrt, fordert TRX_1 das Konto b an. Diesmal liest die Transaktion den „richtigen“ Wert von b, nämlich b+200. Die beiden Transaktionen TRX_1 und TRX_2 können somit parallel ausgeführt werden. 32 Das Zweiphasen-Sperrprotokoll bewirkt im zeitlichen Ablauf von TRX_1 zwar eine Verzögerung, aber nach Ablauf der beiden Transaktionen bleibt die Integrität erhalten. Das Konto a hat sich um 100 Einheiten erhöht (a+100), das Konto b ebenfalls (b+100), und das Konto c wurde um 200 Einheiten reduziert (c-200). Die Summe der Bestände der einzelnen Konten hat sich somit nicht verändert. BEGIN_OF_TRX_1 LOCK (a) READ (a) BEGIN_OF_TRX_2 LOCK (b) READ (b) a:=a+100 WRITE (a) LOG (b) b:=b+200 LOCK (b) READ (b) UNLOCK (a) b:=b-100 WRITE (b) UNLOCK (b) END_OF_TRX_1 TRX_2 : READ WRITE (b) TRX_2 : WRITE LOCK (c) READ (c) TRX_1 : READ UNLOCK (b) TRX_1 : WRITE c:= c-200 WRITE (c) UNLOCK ( c) END_OF_TRX_2 Zeit Abb. 4 Konfliktfreie Buchungstransaktionen Der Vergleich des in Abb. 4 gegebenen Logbuches (LOG(b) des Kontos b mit dem früher diskutierten Logbuch aus Abb. 1 zeigt einen wesentlichen Unterschied: Je ein Lesen (TRX_2:READ) und ein Schreiben (TRX_2:WRITE) wird jetzt strikt zuerst durch TRX_2 durchgeführt, bevor TRX_1 die Kontrolle über das Konto b erhält und ebenfalls lesen (TRX_1:READ) und schreiben (TRX_1:WRITE) darf. Der zugehörige Präzedenzgraph enthält weder READ_WRITE noch WRITE_WRITE-Kanten zwischen den Knoten TRX_2 und TRX_1, er bleibt also zyklenfrei. Die beiden Buchungstransaktionen erfüllen damit die Integritätsbedingung. 33 Bei vielen DB-Anwendungen verbietet die Forderung nach hoher Parallelität gleich ganze Datenbanken oder Tabellen als Sperreinheiten zu verwenden. Man definiert deshalb kleinere Sperrgrößen, wie z.B. einen DB-Ausschnitt, einen Tabellenteil, ein Tupel oder sogar einen Datenwert. Sperrgrößen werden vorteilhaft so festgelegt, dass sie bei der Sperrverwaltung hierarchische Abhängigkeiten zulassen. Sperren wir beispielsweise eine Menge von Tupeln für eine bestimmte Transaktion, so dürfen während der Sperrzeit die übergeordneten Sperreinheiten wie Tabelle oder zugehörige DB von keiner anderen Transaktion in vollem Umfang blockiert werden. Falls ein Objekt mit einer exklusiven Sperre versehen wird, können mit Hilfe einer Sperrhierarchie die übergeordneten Objekte automatisch evaluiert und entsprechend gekennzeichnet werden. Neben Sperrhierarchien sind verschiedene Sperrmodi von Bedeutung. Die einfachste Klassifizierung von Sperren beruht auf der Unterscheidung von Leseund Schreibsperren. Eine Lesesperre (shared lock) erlaubt einer Transaktion nur den lesenden Zugriff auf das Objekt. Fordert eine Transaktion hingegen eine Schreibsperre (exclusive lock) an, dann darf sie lesend und schreibend auf das Objekt zugreifen. Ein weiteres pessimistisches Verfahren, das Serialisierbarkeit gewährleistet, ist die Vergabe von Zeitstempeln, um aufgrund des Alters von Transaktionen streng geordnet die Objektzugriffe durchführen zu können. Solche Zeiterfassungsverfahren erlauben, die zeitliche Reihenfolge er einzelnen Operationen der Transaktionen einzuhalten und damit Konflikte zu vermeiden. Optimistische Verfahren Bei optimistischen Verfahren geht man davon aus, dass die Konflikte konkurrierender Transaktionen selten vorkommen. Man verzichtet von vornherein auf das Setzen von Sperren, um den Grad der Parallelität zu erhöhen und die Wartezeiten zu verkürzen. Bevor Transaktionen erfolgreich abschließen, werden rückwirkend Validierungen durchgeführt. Transaktionen mit optimist. Synchronisation durchlaufen drei Phasen, nämlich eine Lese-, eine Validierungs- und eine Schreibphase. Ohne irgendwelche präventive Sperren zu setzen, werden in der Lesephase alle benötigten Objekte gelesen und in einem transaktionseigenen Arbeitsbereich gespeichert und verarbeitet. Nach Abschluss der Verarbeitung werden in der Validierungsphase die Objekte geprüft, ob die Veränderungen nicht in Konflikt mit anderen Transaktionen stehen. Ziel dabei ist, die momentan aktiven Transaktionen auf Konfliktfreiheit zu überprüfen. Behindern sich zwei Transaktionen gegenseitig, so wird die in der Validierungsphase stehende Transaktion zurückgestellt. Im Falle einer erfolgreichen Validierung werden durch die Schreibphase die Änderungen aus dem Arbeitsbereich der Transaktion in die DB eingebracht. 34 READ_SET(TRX_1) a b c WRITE_SET(TRX_2) Abb. 5 Serialisierbarkeitsbedingung für Transaktion TRX_1 nicht erfüllt Mit Hilfe transaktionseigener Arbeitsbereiche wird bei den optimistischen Verfahren die Parallelität erhöht. Lesende Transaktionen behindern sich gegenseitig nicht. Erst wenn sie Werte zurück schreiben wollen, ist Vorsicht geboten. Die Lesephasen verschiedener Transaktionen können deshalb parallel ablaufen, ohne dass Objekte durch irgendwelche Sperren blockiert sind. Dafür muss in der Validierungsphase geprüft werden, ob die im Arbeitsbereich eingelesenen Objekte überhaupt gültig sind, also mit der Wirklichkeit in der Datenbank noch übereinstimmen. Der Einfachheit halber wird vorausgesetzt, dass sich die Validierungsphasen verschiedener Transaktionen keinesfalls überlappen. Hierfür wird der Zeitpunkt hervorgehoben, zu welchem die Transaktion in die Validierungsphase tritt. Dadurch lassen sich sowohl die Startzeiten der Validierungsphasen als auch die Transaktionen selbst zeitlich ordnen. Sobald eine Transaktion in die Validierungsphase tritt, wird die Serialisierbarkeit geprüft. Bei optimistischer Synchronisation wird betreffend Serialisierbarkeit wie folgt vorgegangen: Mit TRX_t sei die zu überprüfende Transaktion, mit TRX_1 bis TRX_k seien alle parallel zu TRX_t laufenden Transaktionen bezeichnet, die während der Lesephase von TRX_t bereits validiert haben. Alle übrigen fallen außer Betracht, da sämtliche Transaktionen streng nach der Eintrittszeit in die Validierungsphase geordnet sind. Hingegen sind die von TRX_t gelesenen Objekte zu überprüfen, sie könnten ja in der Zwischenzeit von den kritischen Transaktionen TRX_1 bis TRX_k bereits verändert worden sein. Wir bezeichnen die von TRX_t gelesenen Objektmenge mit dem Ausdruck READ_SET(TRX_t) und die von den übrigen Transaktionen geschriebene Objektmenge mit WRITE_SET(TRX_1...,TRX_k) und erhalten das folgende Serialisierbarkeitskriterium: 35 Optimistische Synchronisation (optimistic concurrency control) Bei optimistischer Synchronisation müssen die Mengen READ_SET(TRX_t) und WRITE_SET(TRX_1,...TRX_k) disjunkt sein, damit die Transaktion TRX_t serialisierbar sein kann. Als Beispiel können wir wiederum die beiden ursprünglichen Buchungstransaktionen TRX_1 und TRX_2 von Abb. 1 heranziehen und dabei voraussetzen, dass TRX_2 vor TRX_1 validiert hat. Ist in diesem Fall nun TRX_1 serialisierbar oder nicht? Um diese Frage zu beantworten, bemerken wir, (Abb. 5), dass das von TRX_1 gelesene Objekt b von der Transaktion TRX_2 bereits zurück geschrieben worden ist und in der Schreibmenge WRITE_SET(TRX_2) liegt. Die Lesemenge READ_SET(TRX_1) und die Schreibmenge WRITE_SET(TRX_2) überlappen sich aber, was das Prüfkriterium zur Serialisierbarkeit verletzt. Die Buchungstransaktion TRX_1 muss nochmals gestartet werden. Eine Verbesserung des optimistischen Verfahrens bringt die präventive Garantie von Disjunktheit der Mengen READ_SET und WRITE_SET. Dabei wird in der Validierungsphase der Transaktion TRX_t geprüft, ob diese eventuell Objekte verändert, die bereits von anderen Transaktionen gelesen worden sind. Bei dieser Prüfvariante bleibt der Validierungsaufwand auf Änderungstransaktionen beschränkt. Vermeidung von Verklemmungen Auf dem Gebiet der Betriebssysteme werden zur Sperrverwaltung Maßnahmen studiert, um Verklemmungen, d.h. gegenseitige Behinderungen oder Blockierungen (deadlocks), aufzulösen oder gar zu verhindern. Bei Datenbanksystemen mit Mehrnutzerbetrieb müssen größere Mengen von Objekten berücksichtigt werden. Zusätzlich ist von vornherein nicht bekannt, welche Ausprägungen von Objekten Änderungen erfahren. 36 Verklemmungen entstehen, wenn Transaktionen wechselseitig aufeinander warten oder wenn zyklische Abhängigkeiten vorliegen. In Abb. 6 sind einige Transaktionen durch einen so genannten Wartegraphen dargestellt. Die Transaktion TRX_2 wartet auf den erfolgreichen Abschluss der beiden Transaktionen TRX_1 und TRX_4. TRX_4 wartet auf TRX_6, TRX_6 wartet aber wiederum auf TRX_2. Die Transaktion TRX_2 kann somit erst starten oder weiterarbeiten, wenn die beiden Vorgängertransaktionen erfolgreich enden oder ihre gesperrten Objekte freigeben. Um gegenseitige Behinderungen erfassen zu können, hilft ein Algorithmus (WFG Wait for graph), der Zyklen im Wartegraphen analysiert. Erkennt er Zyklen, so wird nach Möglichkeit diejenige Transaktion zurückgestellt, die am wenigsten Veränderungen nach sich zieht und am sparsamsten Systemressourcen verbraucht. Zu diesem eher aufwendigen Prüfalgorithmus bietet sich die Alternative der systemmäßigen Festlegung von Transaktionszeiten an. Falls innerhalb ihrer vorgegebenen Zeitschranke eine Transaktion nicht erfolgreich beendet werden kann, wird sie automatisch zurückgesetzt und neu gestartet. Auf einfache Art werden dadurch Verklemmungen erzwungenermaßen aufgelöst oder ganz vermieden, was vor allem bei verteilten Datenbanken interessant ist. Zyklus im Wartegraphen TRX_1 TRX_2 TRX_4 TRX_6 Abb. 6 Verklemmung bei abhängigen Transaktionen 37 Physische Organisation Exkurs vorab: Zusammenhang: Dateiorganisation und Dateizugriff Zugriff Physikalisch fortlaufend Logisch fortlaufend Wahlfrei, direkt Speicherung Sequenziell Indiziert, indexsequenziell Relativ (gestreut) Mit direkter oder Indirekter Adressierung ++ +- +- - ++ + - +- ++ Wesentliche Kriterien zur Beurteilung: 1. Speicherplatz 2. Zugriffszeit 3. Behandlung neuer Datensätze 4. Reorganisationsnotwendigkeit 5. Zusammenhang zwischen Ordnungsbegriff und logischer Adresse 38 Physische Datenorganisation bei Datenbanken In dieser Kurseinheit befassen wir uns mit Mechanismen für die Abspeicherung von Daten und zur Beschleunigung von Datenbank-Zugriffen. Als Konsequenz aus dem enormen Unterschied zwischen Zugriffszeiten interner und externer Speichermedien muss die Datenablage so organisiert werden, dass beim Betrieb des DBMS möglichst wenige Zugriffe auf die Sekundärspeicher notwendig sind. Wir haben es also mit einem speziellen Aspekt des Datenbankentwurfs zu tun, durch den die konzeptuelle Modellierung ergänzt wird durch den Entwurf von Speicherungsstrukturen und Zugriffspfaden. Bei relationalen Datenbanksystemen ist die physische Unabhängigkeit weitgehend gewährleistet, so dass hier der konzeptionelle Entwurf zunächst eigenständig durchgeführt werden kann. Der Entwurf der Speicherungsstrukturen und Zugriffspfaden erfolgt dann in einem nachfolgenden Schritt, der insbesondere auch die Möglichkeit des ausgewählten Datenbanksystems berücksichtigen muss. Nach dem Aspekt des Entwurfsproblems werden die wichtigsten Verfahren zur Datenorganisation behandelt. Dabei geht es um die Abbildung der Entities des konzeptuellen Modells auf interne Datensätze, um Primär-Zugriffspfade, die die Organisation der Daten auf dem Speicher bestimmen, sowie um SekundärZugriffspfade, die zusätzliche Informationen zum schnellen Auffinden von gesuchten Datensätzen enthalten. Dies wäre auch Inhalt einer Vorlesung zum Thema DATENSTRUKTUREN. Im Unterschied zur dortigen Betrachtungsweise kommt es hier aber vor allem darauf an, die prinzipiellen Möglichkeiten und ihre Anwendbarkeiten bei typischen Situationen im Datenbankbereich zu beschreiben. Während die Ausführungen zum Bereich der Datenorganisation unabhängig vom konkreten Typ des Datenbanksystems gehalten sind, werden hier abschließend eingehender die in relationalen DBMS angebotenen Möglichkeiten für die physische Datenorganisation behandelt. 39 Arbeits- und Sekundärspeicher Die Daten der Datenbank liegen bei praktischen Anwendungen auf Sekundärspeichern, im allgemeinen Magnetplatten. Die Zugriffszeiten schneller Platten liegen bei ca. 3-6 msec, während die Zugriffszeiten für Arbeitsspeicher bei 10-9 -10-8 sec. liegen. Angesichts dieser „Zugriffslücke“ muss ein wesentliches Ziel der physischen Datenbankorganisation sein, die Anzahl der Plattenzugriffe klein zu halten, auch wenn dabei Aufwand innerhalb des Arbeitsspeichers entsteht. Die physikalischen Zugriffs- und Übertragungseinheiten zwischen Plattenspeicher und Arbeitspeicher sind Blöcke oder Seiten (pages) fester Länge, typischerweise 1K bis 4K Bytes (K= 1024). Beim Zugriff auf ein Datenelement der Datenbank muss das DBMS feststellen, auf welcher Seite des Sekundärspeichers die Daten liegen; es muss die Übertragung dieser Seite in den Arbeitsspeicher veranlassen; schließlich muss es aus dieser Seite die gewünschten Daten herausfinden. Dieser komplizierte Prozess wird von verschiedenen Softwareschichten übernommen. Eine wesentliche Rolle kommt in diesem Zusammenhang dem Systempuffer und seiner Verwaltung zu. Der Systempuffer ist der Speicherbereich im Hauptspeicher, der die von der Platte übertragenen Seiten aufnimmt. Diese Seiten können dann vom DBMS direkt manipuliert werden, d.h. das DBMS liest seine Daten aus dem Systempuffer und schreibt Änderungen in den Systempuffer hinein. Die Systempufferverwaltung muss die vom DBMS benötigten Seiten im Systempuffer zur Verfügung stellen. Ist bei Anforderung einer Seite kein Platz mehr im Systempuffer vorhanden, so muss die Systempufferverwaltung zunächst das Rückschreiben der Seite veranlassen. Dabei sollten die häufig benutzten Seiten nicht ausgelagert werden. Die Wahl der Größe des Systempuffers sowie der Strategien zur Verwaltung (Seitenersetzungsstrategie LRU) haben großen Einfluss auf die Leistung des Gesamtsystems. Die Größe des Systempuffers kann meist als Parameter bei der Installation des DBMS festgelegt werden. Die erforderliche Größe hängt im Wesentlichen von der Art der Anwendungsprogramme und davon ab, in welchem Maße die Anwendungsprogramme parallel arbeiten sollen. Letzteres deshalb, weil die mit der Datenbank arbeitenden Anwendungsprogramme konkurrierend auf den Systempuffer zugreifen. 40 Das Entwurfsproblem Im Sinne des prinzipiellen Aufbaus wird zunächst das konzeptuelle Modell unabhängig von der konkreten Datenbank erstellt, meist als Entity-RelationshipModell. Danach wird aus dem konzeptuellen Modell das logische Modell abgeleitet wird, das die Informationen des konzeptuellen Modells mit Hilfe der Konstrukte des ausgewählten Datenbank-Modells (Netzwerk, Relational) darstellt. Soll die Anwendung auf einer relationalen Datenbank realisiert werden, so enthält das logische Modell die Tabellen, die aus den Entity- und BeziehungsTypen des ER-Modells entstehen. Nach dieser Transformation können nun auch durch die DDL des ausgewählten relationalen DBMS die entsprechenden Relationen definiert werden, Daten eingebracht werden und die zugehörigen Programme und Anfragen ausgeführt werden. Diese Anwendungsprogramme berücksichtigen also nicht die interne Organisation der Daten, sie werden realisiert auf der Basis der logischen (Tabellen-) Strukturen. Dies ist eines der wesentlichen Verdienste der relationalen Datenbank-Technologie: Durch die deskriptiven Abfragesprachen ist die Anwendungsprogrammierung entkoppelt von der physischen Abspeicherung der Daten; sie kann sich auf die logische Struktur der Daten konzentrieren. Dies gilt nicht für hierarchische und NetzwerkSysteme; hier erfolgt der Zugriff auf Daten weitgehend durch Navigation. Auch wenn sich die Anwendung kaum um die physische Datenorganisation zu kümmern brauchen, so ist diese Organisation trotzdem wichtig, um eine gute Performance zu erreichen, d.h. um Anfragen und Änderungsaufträge in akzeptabler Zeit ausführen zu können. Daher muss der Datenbankadministrator auf der Basis des logischen Modells und notwendiger statistischer Informationen über geplante Anwendungen die physische Organisation der Datenbank festlegen. Dies geschieht in relationalen Systemen, ohne dass der Anwender das in der Logik seiner Programme merkt. Er wird allerdings schnell feststellen, dass bei einer geschickten Datenorganisation Anfragen schneller beantwortet werden, als bei einer ungeschickten Organisation. Die physische Organisation wird im internen Schema der Datenbank beschrieben. Kommerzielle DBMS bieten sehr unterschiedliche Möglichkeiten zur Gestaltung der internen Ebene. Eine wichtige Frage, die sich ein Datenbank-Administrator stellen muss, ist die folgende: Was ist die gewünschte Performance für die Datenbank? Dies kann nicht pauschal gesagt werden, sondern hängt von den Operationen ab, die gegen die Datenbank ausgeführt werden sollen. In den Begriffen des konzeptuellen 41 Modells muss der Benutzer die folgenden grundsätzlichen Operationen ausführen können: 1. 2. 3. 4. Einfügen von Entities oder Beziehungen Löschen von Entities oder Beziehungen Verändern von Entities oder Beziehungen Auswahl (Selektion) von Entities, die eine bestimmte Bedingung erfüllen. Aus der Sicht des Datenbanksystems bedeutet Selektion lesenden Zugriff auf die Datenbank; lesender Zugriff wird häufig als Retrieval bezeichnet. Alle Zugriffe auf die Datenbank, die Änderungen bewirken, werden mit Update umschrieben. Es ist die Aufgabe des Datenbank-Administrators, die Daten so zu organisieren, dass die Gesamtheit der Anwendungen möglichst gut unterstützt wird. Dabei ist sehr sorgfältig zu prüfen, welche Selektionen und welche Beziehungen zwischen Entities physisch unterstützt werden sollen. Physische Unterstützung einer Selektion heißt, dass entweder durch die Art der Abspeicherung der Daten (Primär-Organisation der Daten) oder durch zusätzliche Daten (SekundärOrganisation, etwa Indexe) das Auffinden der gewünschten Entities beschleunigt wird, so dass z. B. nicht alle Entities eines Typs durchsucht werden müssen, um ein bestimmtes Entity zu finden. Beispiel 1 Um alle Angestellten, die in Dortmund wohnen, aufzufinden, müssen wir häufig alle Angestelltendatensätze durchsuchen. Kommt diese Art der Abfrage häufiger vor, so können wir das Suchen erheblich beschleunigen, indem wir z. B. alle Sätze von Angestellten mit Wohnort Dortmund in einer Liste miteinander verketten, indem wir diese Sätze physisch zusammenhängend speichern oder aber, indem wir einen geeigneten Index einführen (Indexe werden noch ausführlich behandelt): Diejenigen Selektionen und Beziehungen, die auf der Ebene der physischen Datenorganisation unterstützt werden, bilden die Zugriffspfade der Datenbank. Je mehr Selektionen wir durch Zugriffspfade unterstützen, desto schneller wird das natürliche Retrieval. Diesen Gewinn beim Retrieval erkauft man sich jedoch mit einer Verteuerung des Update: ist z. B. ein Satz in viele Zugriffspfade eingebunden, so müssen beim Löschen dieses Satzes alle diese Zugriffspfade verändert werden. Es liegt somit ein Trade-off vor, der beim Entwurf der Zugriffspfade berücksichtigt werden muss und der es erfordert, sehr genau die Ziele der Zugriffsoptimierung zu definieren. 42 Die als Entity-Typen und Beziehungstypen beschriebenen Daten werden in der Datenbank in Form von internen Sätzen (records) realisiert und gespeichert. Die Sätze müssen auf Seiten des Externspeichers gebildet werden. Ausgehend vom Konzeptuellen Modell kann man folgende grobe Entwurfsschritte für die physische Datenorganisation unterscheiden: 1. Abbildung der Entities auf interne Sätze 2. Festlegung der Primär-Organisation der Daten, d.h. Festlegung der Art der Abspeicherung von Mengen von internen Sätzen , häufig verbunden mit der Unterstützung der Selektion bzgl. des Primärschlüssels. 3. Einrichtung von sekundären Zugriffspfaden zu internen Sätzen (Unterstützung der Selektion bzgl. beliebiger Attribute) Natürlich sind die drei Fragen beim Entwurf einer konkreten Datenorganisation nicht streng getrennt behandelbar. Außerdem können für Punkt 2 und Punkt 3 in vielen Fällen die gleichen grundsätzlichen Methoden der Datenorganisation angewandt werden. Interne Sätze Abbildung von Entities auf internen Sätzen Ebenso wie wir auf der Ebene der Entities von Entity-Typen sprechen, werden auch auf der internen Ebene Sätze zu Satztypen zusammengefasst. Es gilt nun, die Entity-Typen der konzeptuellen Ebene auf diese Satztypen der internen Ebene abzubilden. Der Datenbank-Administrator muss also festlegen, welche Attribute der konzeptuellen Entity-Typen zu Satztypen des internen Modells zusammengefasst werden und wie die Sätze dieser Typen realisiert werden. Interne Sätze werden oft auch physische Sätze genannt. Der Begriff des Entity legt es nahe, alle Attribute eines Entity auch als Felder eines Satzes zu definieren. Aus Gründen der Effizienz ist dies aber nicht immer sinnvoll. Grundsätzlich muss man es sogar zulassen, dass Attribute verschiedener konzeptueller Entity-Typen in einem Satz zusammengefasst werden. 43 Beispiel 2: Die Zusammenfassung von Attributen verschiedener Entities in einem internen Satz ist z. B. dann bei 1:n-Beziehungen angebracht, wenn diese Beziehung eine schwache Beziehung (ID-Beziehung) ist, d. h. dass die n Entities von dem einen zugehörigen Entity abhängen. Etwa: Name und Geburtsdatum der Kinder werden mit den Attributen des Entity-Typs ANGESTELLTER zu einem internen Satztyp zusammengefasst. In diesem Fall kann man davon ausgehen, dass die Informationen über die Kinder nur über das Entity ANGESTELLTER angesprochen werden. In der gleichen Weise kann es sinnvoll sein, die Attribute eines Entity-Typs in mehrere Satztypen zu zerlegen: der Entity-Typ ANGESTELLTER besitze die Attribute ANG-NR, NAME, ANSCHRIFT, FÄHIGKEITEN, BERUFLICHER WERDEGANG, GEHALT, STEUERKLASSE,.... Regelmäßig benötigt das Lohnbüro die Attribute ANG_NR, NAME, ANSCHRIFT, GEHALT, STEUERKLASSE; die restlichen Attribute werden nur sehr selten benötigt. Da die Werte der selten benötigten Attribute lang sind, ist es nicht sinnvoll, sie bei jedem Zugriff auf die häufig benötigten Attribute mit in den Arbeitsspeicher zu übertragen, d. h. es bietet sich an, zwei interne Satztypen ANGEST1 und ANGEST2 zu bilden. Übung 1 Überlegen Sie sich zu obigem Beispiel mindestens zwei Möglichkeiten, die Beziehungen zwischen den beiden Satztypen ANGEST1 mit den häufig benutzten Attributen und ANGEST2 mit den selten benutzten Attributen zu realisieren. Realisierung interner Sätze Speicherung variabel langer Sätze als Sätze fester Länge Grundsätzlich ist die Verwaltung variabel langer Sätze aufwendiger als für Sätze fester Länge. Aus diesem Grund werden in vielen Fällen auch dort interne Sätze fester Länge verwendet, wo logisch gesehen variabel lange Sätze vorliegen. Dies ist z. B. dann sinnvoll, wenn die Obergrenze für die Satzlänge bekannt ist, und wenn diese nahe bei der mittleren Satzlänge liegt. Angenommen, dass Gasthörer gleichzeitig höchstens 3 Kurse belegen dürfen und einige sicherlich weniger Kurse belegen, dann erhält man variabel lange Sätze des Typs NAME,...,KURS-NR*, 44 wobei * eine Wiederholungsgruppe (Repeating Group) anzeigt, was bedeutet, dass das Attribut KURS-NR aus mehreren Werten bestehen kann. Diese variabel langen Sätze wird man dennoch im Allgemeinen als Sätze fester Länge des folgenden Typs abspeichern: NAME,...;KURS_NR1,KURS_NR2,KURS_NR3 NAME,....,KURS-NR(3). oder KURS-NR(3) heißt wiederum Wiederholungsgruppe. Falls ein Gasthörer weniger als 3 Kurse belegt, enthalten die entsprechenden Felder so genannte Nullwerte, die anzeigen, dass kein Wert existiert. Ist ein solch spezieller Nullwert nicht verfügbar, so muss für jede Wiederholungsgruppe in den Satz ein Feld eingefügt werden, das angibt, wie viele Felder der entsprechenden Wiederholungsgruppe besetzt sind. Eine zweite Art, mit Sätzen fester Länge auszukommen, besteht darin, den logischen Satz physisch in eine Folge von Sätzen fester Länge zu zerlegen. Diese physischen Sätze werden miteinander verkettet. Der Angestelltensatz, der die Namen und Geburtstage der Kinder enthalten soll, hat logisch gesehen folgendes Format: NAME, ..., (KIND, GEBTAG)* (KIND, GEBTAG*) ist eine Wiederholungsgruppe. Eine brauchbare obere Grenze für die Kinderzahl ist jetzt nicht gegeben. Man kann jedoch auf feste Satzlänge zurückgreifen, wenn man die folgenden Satzformate anwendet: NAME, KIND, ..., PT GEBTAG, PT1 Hierin ist PT ein Zeiger auf einen Satz mit den Feldern KIND, GEBTAG, PT1; PT1 ist ein Zeiger auf einen Satz vom gleichen Typ. Das ergibt also die Datenorganisation des Bildes 1. Die skizzierten Methoden zur Vermeidung variabel langer Sätze auf physischer Ebene können beliebig kombiniert werden. Etwa können im obigen Beispiel gewählt werden: NAME, ....; (KIND,GEBTAG)(2), PT KIND, GEBTAG, PT1. 45 In diesem Falle musste auf Sätze vom zweiten Typ nur noch zugegriffen werden, wenn der Angestellte mehr als zwei Kinder hat. Bild 1: Müller ..... Peter 13.10.53 Susi 10.01.60 Verwaltung von Wiederholungsgruppen durch eine Folge von Sätzen fester Länge Direkte Implementierung variabel langer Sätze Es gibt eine Reihe unterschiedlicher Möglichkeiten, variabel lange Sätze auch als solche abzuspeichern. Sofern die Zahl der Einzelwerte eines Attributes im Satz unterschiedlich sein kann, muss auf irgendeine Weise festgehalten werden, welche Werte zu welchem Attribut gehören (wir gehen von festen Feldlängen aus). hier nur zwei skizzierte Lösungsmöglichkeiten: a) Längenangaben: in einem speziellen Feld wird angegeben, wie viel Werte das Attribut umfasst 3 Steno Masch Längenangabe Bild 2: Verwaltung variabel langer Sätze durch Satzfelder 46 Engli b) Zeiger: am Satzanfang wird für jedes Attribut (oder bei entsprechender Variation des Verfahrens für bestimmte Attribute) ein Zeigerfeld eingerichtet; jeder Zeiger weist auf das erste Feld des zugehörigen Attributes, die Zahl der Felder ergibt sich aus der Differenz zum nächsten Zeigerwert 40 55 .... Steno Masch Engli Bild 3: Verwaltung variabel langer Sätze durch Zeiger zum Attribut-Anfang Adressierung von internen Sätzen Bevor es in den folgenden Abschnitten ausführlicher um die Zugriffspfade geht, soll hier kurz auf die darunter liegende Ebene eingegangen werden, nämlich auf die Abspeicherung und Adressierung der internen Sätze. Die Übertragung von Daten zwischen Hintergrundspeicher und Hauptspeicher geschieht in Einheiten einer festen Länge, den Blöcken oder Seiten. Wenn das DBMS Daten auf die zur Verfügung stehenden Seiten abbilden will, muss es zunächst diese Seiten identifizieren können. Dies geschieht einfach durch ein Durchnummerieren aller zur Verfügung stehenden Seiten, die damit eine eindeutige Seitennummer erhalten. Die hardwaremäßige Ansteuerung einer Seite B durch das Betriebssystem geschieht durch die Angabe einer von dem speziellen Speichergerät abhängigen physischen Adresse, etwa bei plattenähnlichen Speichergeräten durch (Zylinder# , Spur# , Sektor#). Die Zuordnung Seitennummer physische Adresse wird dabei vom Betriebssystem übernommen. 47 Die Aufgabe des DBMS besteht nun darin, die internen Sätze auf die zur Verfügung stehenden Seiten zu verteilen. Üblicherweise werden alle Sätze eines Typs zu einer internen Datei zusammengefasst. Eine solche interne Datei wird auf einer wohldefinierten Menge von Seiten abgespeichert. Diese Seiten sind in einer bestimmten Reihenfolge organisiert. Dies kann entweder durch physische Nachbarschaft oder durch Verkettung erreicht werden. Im letzten Fall können die einzelnen Seiten auch verstreut über den Gesamt-Speicherraum liegen. Jedoch ist immer ein sequenzieller Durchlauf durch die Seiten möglich, die eine interne Datei beherbergen. Wird ein neuer Satz in die interne Datei eingefügt, so muss das DBMS entscheiden, in welcher Seite der Satz abgespeichert ist. Dies geschieht unter Berücksichtigung des Ordnungskriteriums der internen Datei. Die Sätze können entweder sortiert nach einem Attribut abgelegt sein, oder es werden bestimmte Organisationsformen benutzt, um die Stelle zu bestimmen, an die der Satz abgespeichert wird (Primärorganisation von Dateien). Darüber hinaus wird durch diese Organisation der Dateien auch der Zugriff auf die Sätze der Datei unterschützt: Ist die Datei z. B. nach einem Attribut sortiert, so können durch binäres Suchen einzelne Sätze schnell aufgrund ihrer Werte in diesem Attribut gefunden werden, und ebenso wird die sortierte Abarbeitung der Datei bezüglich dieses Attributes begünstigt. Um den Satz anschließend aufgrund anderer Zugriffskriterien – etwa Inhalte anderer Attribute – auffinden zu können, werden weitere Zugriffspfade angelegt (Sekundäre Zugriffspfade). Diese Sekundär-Zugriffspfade bestehen in der Regel aus zusätzlichen Datenstrukturen, in der letztendlich Zeiger auf den Satz eingetragen werden müssen. Ein solcher Zeiger beinhaltet in irgendeiner Form die Adresse des Satzes im Hintergrundspeicher. Da eine ganze Anzahl von Zugriffspfaden existieren können, ist es wichtig, die Adresse eines Satzes möglichst stabil zu halten, selbst wenn der Satz verschoben wird (z. B. wegen einer Reorganisation der Datenbank oder zur effizienten Speicherplatznutzung bei variabel langen Sätzen). Physische Adressen Prinzipiell könnte die Adresse eines Satzes als Byte-Adresse im Außenraum der Datenbank realisiert werden. Die Seite, die gelesen werden muss, um auf den Satz zugreifen zu können, lässt sich sehr leicht berechnen. Eine solche physische Adresse hat den Vorteil, dass der Zugriff auf den gesuchten Satz sehr schnell ist. 48 Die Nachteile sind jedoch schwerwiegend: der Satz kann im Speicher nicht mehr verschoben werden, ohne dass alle Zeiger, die auf ihn verweisen, geändert werden. Daher werden üblicherweise andere Adressierungstechniken benutzt. Seitenbezogene Adressen Der Zeiger besteht aus einem Paar (Seitennummer P, Position S im Zeigerfeld der Seite). P verweist auf die Seite, in der sich der Satz befindet, S auf eine Position im Zeigerfeld am Seitenanfang; der Eintrag cont(S) in dieser Feldposition gibt die Position des Satzes in der Seite an (vgl. Bild 4). Muss der Satz innerhalb der Seite verschoben werden, so muss lediglich cont(S) im Zeigerfeld verändert werden, alle Zeiger (P, S) auf den Satz bleiben unverändert. Block 120 P S Satz 120 Bild 4: 4 Zeiger als seitenbezogener Indikator (Block = Seite) Auch wenn der Satz in eine andere Seite verschoben werden muss, wird (P, S) nicht verändert: Man speichert in der Seite P statt des Satzes den Zeiger (P´, S´), der angibt, wo sich der Satz tatsächlich befindet (vgl. Bild 5). Dabei zeigt eine Kennung entweder bei der Adresse oder bereits im Zeigerfeld an, dass es sich hier um eine Adresse und nicht um einen Satz handelt. In diesem Fall erreicht man den gewünschten Satz also mit genau zwei externen Speicherzugriffen. Wird der Satz anschließend noch einmal auf eine andere Seite verschoben, so wird lediglich der Adresseintrag (P´, S´) entsprechend geändert. 49 P´ P S´ Satz S Bild 5: Verschiebung eines Satzes in eine andere Seite Logische Adressen Gegenüber Verschiebungen im Speicher völlig stabile Zeiger erhält man, wenn man die Zeiger logisch realisiert. Der Satz enthält eine logische Adresse, die nichts über die Abspeicherung des Satzes besagt. Eine solche Zeigerform kann man über indirekte Adressierungen realisieren: der Zeiger verweist auf eine Tabelle, in der dann die Position des Satzes im Speicher angegeben ist. Zuordnungstabelle Speicher Satz P Bild 6: Realisierung logischer Zeiger Wird ein Satz in einen Speicher verschoben, so bedeutet dies lediglich, dass der zugehörige Eintrag in der Zuordnungstabelle geändert werden muss; alle Zeiger P auf den Satz bleiben unverändert. Diese Realisierung bringt zwar völlige Unabhängigkeit gegenüber Verschiebungen im Speicher mit sich, hat aber den großen Nachteil, dass jeder Zugriff auf den Satz über einen Zeiger einen zusätzlichen Zugriff auf die Zuordnungstabelle kostet. Hinzu kommt, dass die Zuordnungstabelle selbst sehr groß sein kann, so dass sie oft nicht vollständig im Arbeitsspeicher gehalten werden kann. 50 Festlegung von Zugriffspfaden Um abgespeicherte Sätze wiederzufinden, besteht immer die Möglichkeit, die gesamte interne Datei zu durchlaufen. Allerdings ist dies eine recht ineffiziente Methode, da viele Sätze gelesen werden müssen, nach denen gar nicht gesucht wird. Daher wird zusammen mit der Definition eines Satztyps festgelegt, welche Möglichkeiten einzurichten sind, um auf die Sätze zugreifen zu können. Diese Zugriffspfade sollen es erlauben, gezielt auf bestimmte Sätze zugreifen zu können, wobei möglichst wenig Sätze eingelesen werden sollen, nach denen nicht gesucht wird. Prinzipiell kann man Zugriffspfade auf zwei Arten bilden: 1. Der Zugriff kann dadurch beschleunigt werden, dass auf die physische Abspeicherung der Sätze Einfluss genommen wird (Primärorganisation) 2. Der Zugriff kann beschleunigt werden durch Anlegen zusätzlicher Strukturen, die ein gezieltes Auffinden bestimmter Sätze ermöglichen (sekundäre Zugriffspfade).Die für diesen Zweck zusätzlich abgespeicherten Daten werden Sekundärdaten genannt. Im ersten Fall geht es darum, Sätze aufgrund ihres Speicherplatzes zu finden. Dies wird z. B. durch Verfahren gewährleistet, die aus dem Attributwert den Speicherplatz berechnen. Manche Verfahren unterstützen (auch) eine bestimmte Durchlaufreihenfolge durch die Sätze einer Datei. Dadurch wird erreicht, dass bei einem derartigen Durchlauf durch die Datei jede Seite nur einmal gelesen werden muss. Wird beispielsweise eine Angestelltendatei häufig alphabetisch bezüglich der Namen bearbeitet, so bietet es sich an, die Sätze der Datei alphabetisch sortiert nach den Angestelltennamen abzuspeichern. Weiterhin wird auf die physische Abspeicherung Einfluss genommen, um Sätze, die häufig zusammen gelesen werden müssen, auch möglichst nahe beieinander abzuspeichern d. h. möglichst in einer Seite. Dies bezeichnet man als Clusterung. Wird beispielsweise häufig auf alle Angestelltensätze von Angestellten zugegriffen, die in einer Abteilung arbeiten, so sollten diese Sätze auf möglichst wenigen Seiten verteilt liegen (Um entsprechend wenig Plattenspeicherzugriffe zu erzeugen). 51 Natürlich kann die Speicherorganisation einer Datei nur durch ein Kriterium bestimmt werden. Es genügt aber nicht, eine Datei so zu organisieren, dass schneller Zugriff nur nach einem Suchkriterium möglich ist. Ist dieses Kriterium etwa der Name des Angestellten, so kann man zwar schnell auf einzelne Sätze zugreifen, für die das Attribut Name bekannt ist. Zur Beantwortung der Abfrage FINDE ALLE ANGESTELLTEN MIT GEBURTSDATUM > 1949 sind aber immer noch alle Sätze der Datei zu durchsuchen. Um auch solche Abfragen zu unterstützen, müssen neben der Primär-Organisation der Datei weitere Zugriffspfade für den Zugriff über Attribute angelegt werden, die nicht bei der Primär-Organisation berücksichtigt worden sind. Diese Zugriffspfade bestehen lediglich aus Sekundärdaten, die es erlauben, aufgrund eines Attributwertes die Adresse des Satzes zu ermitteln. Diese zusätzlichen Zugriffspfade werden als sekundäre Zugriffspfade bezeichnet. In herkömmlichen Datei-Systemen wird üblicherweise die Primär-Organisation nur für den Primärschlüssel der Datei eingesetzt. Dieser Grundsatz kann in Datenbanksystemen keine Anwendung finden, da nicht notwendigerweise der Primärschlüssel das geeignete Kriterium für die Abspeicherung darstellt. Üblicherweise wird dann jedoch ein zusätzlicher Zugriffspfad für den Primärschlüssel definiert (in diesem Fall also ein sekundärer Zugriffspfad). In älteren Versionen vieler relationaler Systeme ist das allein deshalb schon notwendig, da das System nur über einen solchen Zugriffspfad die Eindeutigkeit des Schlüsselattributes sicherstellen kann. In den beiden folgenden Abschnitten werden Verfahren zur Realisierung von Zugriffspfaden behandelt. Dabei wird zunächst der Fall diskutiert, dass die Sätze gemäß dem Primärschlüssel zu organisieren sind (d. h. zunächst nur der Fall, dass die entsprechenden Attributwerte eindeutig sind). Daran sieht man, dass einige dieser Verfahren in zweifacher Hinsicht verallgemeinert werden können: Zum einen sind sie nicht nur für Schlüsselattribute einsetzbar, sondern auch für beliebige andere Attribute, und zum anderen können sie auch zur Realisierung sekundärer Zugriffspfade eingesetzt werden, bei denen kein Einfluss auf die Abspeicherung der einzelnen Sätze genommen wird. 52 Primärorganisation von Dateien Achtung: Welche Arten von Speicherungsstrukturen realisiert werden können, hängt von dem einzelnen DBMS bzw. dem darunter liegenden Dateisystem ab. Zu den wichtigsten Organisationsformen für Dateien gehören: sequenzielle Organisation index – sequenzielle Organisation Hash – Verfahren Bäume Im Folgenden werden lediglich die wesentlichen Eigenschaften dieser Organisationsformen zusammengefasst Sequenzielle Organisation Die Sätze werden, nach dem Primärschlüssel sortiert, aufeinander folgend abgespeichert. Falls binäres Suchen anwendbar ist, ist das Auffinden eines Satzes mit gegebenem Schlüssel nicht sehr aufwendig: im Mittel O(log2n) Zugriffe bei n Sätzen. Einfügen und Löschen sind allerdings sehr aufwendig, es müssen im Mittel n/2 Sätze bewegt werden. 53 Index-sequenzielle Organisation Mit der index-sequenziellen Organisation versucht man die wesentlichen Nachteile der sequenziellen Organisation zu vermeiden, ohne auf den offensichtlichen Vorteil (schnelle Verarbeitung nach Sortierreihenfolge) zu verzichten. Zwei Probleme waren zu lösen: Schneller Zugriff auf einen Satz bei gegebenem Schlüssel; bessere Möglichkeiten für das Hinzufügen von Sätzen zur Datei. Die aus diesen Überlegungen entstandene index-sequenzielle Organisation wird sehr häufig eingesetzt. Die Sätze werden wieder nach dem Primärschlüssel sortiert gespeichert. Zusätzlich wird hierzu ein Verzeichnis der Primärschlüssel, der Index, aufgebaut. Falls nur ein Satz über den Primärschlüssel gesucht wird, so erfolgt der Zugriff nicht durch Suchen in der Datei, sondern es wird zunächst in diesem Index gesucht. Der Index ist eine kleine Datei, jeder Satz dieser Datei enthält ein Paar (s, b), wobei s ein Primärschlüssel und b ein Indikator für die Seite ist, in dem der Satz mit dem Schlüssel s liegt. Der Index ist nicht dicht, d. h. er enthält nicht alle Schlüssel s der Schlüsselmenge S der Ursprungsdatei. Man kann sich den Index aller Tabellen mit Einträgen der Form (s, b) vorstellen (vgl. Bild 7). Der Index kann z. B. aus allen Paaren (sb, b) bestehen, wo sb S der höchste Schlüssel der Seite b ist. Sucht man den Satz mit Schlüssel s, so findet man den zu lesenden Block sofort im Index: man sucht den Eintrag (sb, b) für den gerade noch gilt s ≤ sb. In Bild 7: Sucht man den Satz mit Schlüssel I, so findet man im Index als kleinstes sb mit I ≤ sb den Eintrag L. Der zu L gehörige Zeiger verweist auf die Seite, die den Satz mit Schlüssel I enthält. Die so gefundene Seite wird im Allgemeinen sequenziell oder binär nach dem Satz durchsucht. 54 W E L Q W A B C D E F H I L M N O Q R S U W 2-stufiger Index Block 1 Block 2 Sätze nach Primärschlüssel Sortiert Daten Bild 7: Prinzip der index-sequenziellen Organisation bei mehrstufigem Index (Block = Seite) Wird der Index zu groß, so wird häufig ein Index für den Index angelegt; dies geschieht in gleicher Weise wie der Aufbau des Index für die Datei selbst. Auf diese Weise erhält man mehrstufige Indexe. In Bild 7 ist eine zweite Indexstufe angegeben. Durch diese zweite Stufe verkürzt sich das Suchen in der ersten Stufe erheblich, da ja auch der Index ab einer gewissen Größe auf dem Externspeicher gehalten werden muss. Probleme ergeben sich nach wie vor beim Einfügen und Löschen von Sätzen. Um beim Einfügen nicht jeweils einen großen Teil der Sätze bewegen zu müssen, kann bei der Erstabspeicherung der Sätze in jeder Seite eine Speicherreserve freigehalten werden, so dass Überläufe durch Sätze, die nicht mehr in der Seite Platz finden, mit einiger Wahrscheinlichkeit erst nach einer größeren Zahl von Einfügungen auftreten. Tritt ein Überlauf auf, so muss dieser Satz in einem so genannten Überlaufbereich abgelegt und in der Seite, wo der Überlauf auftrat, ein entsprechender Vermerk (z. B. Zeiger in den Überlaufbereich) eingetragen werden. 55 Der Überlaufbereich kann auf verschiedene Art und Weise organisiert werden. Eine Möglichkeit besteht darin, für jede übergelaufene Seite der Datei eigene Überlaufseiten anzulegen und zu verketten. Eine andere Möglichkeit besteht darin, Überlaufsätze auf dem ersten freien Platz eines gemeinsamen Überlaufbereiches abzulegen; die zu einer Seite gehörenden Überlaufsätze werden verkettet. Mit der Verlegung von Sätzen auf Überlaufseiten wird der Zugriff im Mittel immer langsamer. In gewissen Ansätzen ist deshalb eine Reorganisation erforderlich, d. h. alle vorhandenen Sätze werden in einer neuen indexsequenziellen Datei organisiert. Übung 2: Welche Vor- und Nachteile weisen die oben skizzierten Organisationsformen für Überlaufbereiche auf? Hash – Verfahren Der Grundgedanke bei Hash – Verfahren ist der, dass die Speicheradresse für einen Satz aus dessen Primärschlüssel berechnet wird. Bezeichnet man mit τ die Menge aller möglichen Primärschlüsselwerte eines Satztyps und mit N die Menge der zur Verfügung stehenden Speicheradressen (Seitennummern o. ä.), so ordnet die Hash – Funktion h: τ N jedem möglichen Primärschlüssel s τ des Satztyps eine Speicheradresse zu. Die Sätze werden auf diese Weise über einen vorgegebenen Speicherbereich verstreut, da die Speicheradresse eines Satzes über die Hash – Funktion h sehr schnell ermittelt werden kann, ergibt sich im Prinzip auch ein sehr schneller direkter Zugriff auf die Sätze. Eine sehr einfache und wohl die gebräuchlichste Hash – Funktion ist das sog. Divisions – Rest – Verfahren. Die Schlüssel seien numerisch, der verfügbare Speicher bestehe aus einer Tabelle mit n Speicherplätzen 0,..., n-1. Die Hash – Funktion lautet dann h(s) = s modulo n. (d. h. h(s) ist der Rest, der sich bei der ganzzahligen Division von s durch n ergibt.) 56 In der Literatur werden eine Reihe anderer Hash – Funktionen vorgeschlagen, die jedoch hier nicht behandelt werden sollen. Die Hash – Funktion hat natürlich großen Einfluss auf das Gesamtverhalten der Dateiorganisation und muss sehr sorgfältig den Gegebenheiten der speziellen Anwendung ausgewählt werden. Da für die Abspeicherung der Sätze ein möglicht kleiner Speicherplatz reserviert werden soll, gilt im Allgemeinen, dass die Anzahl der möglichen Schlüssel sehr viel größer ist, als die Anzahl der zur Verfügung stehenden Speicherplätze. Daher kann es vorkommen, dass durch die Hash – Funktion mehreren Primärschlüsseln dieselbe Adresse zugewiesen wird; diese Schlüssel stehen in Kollision zueinander. Die Behandlung von Kollisionen stellt ein wesentliches Unterscheidungsmerkmal der verschiedenen Hash – Funktionen dar. Bekannte Methoden sind: Abspeicherung in separaten Überlauf – Bereichen; Abspeicherung im ersten freien Speicherplatz des Hash – Bereichs nach dem durch die Hash – Funktion h bestimmten Platz h(s); Abspeicherung im ersten freien Speicherplatz nach einer Folge von Speicherplätzen, deren Adressen durch Zufallszahlen berechnet werden (der Schlüssel ist die Eingabe für den Zufallszahlengenerator); zusätzliche Verwendung einer Hash – Funktion, u.a.m. Übung 3 Hash – Verfahren ermöglichen schnellen Zugriff auf einen Satz bei gegebenem Primärschlüssel und stellen deshalb eine sehr wichtige Dateiorganisationsform dar. Sie weisen allerdings einige Nachteile auf, die in vielen Anwendungen erheblich sind. Überlegen Sie sich einige wesentliche Nachteile von Hash – Verfahren! Vergleichen Sie auch mit der index-sequenziellen Organisation. 57 Bäume Bäume verschiedenster Art spielen eine wesentliche Rolle bei einer ganzen Reihe von Anwendungen. Die überwiegende Mehrzahl der vielen Arten von Bäumen wurde unter der Annahme entwickelt, dass der gesamte zu verwaltende Datenbestand im Arbeitsspeicher Platz findet. Speziell für große Datenbestände, die auf Massenspeichern verwaltet werden müssen, wurden die sogenannten B – Bäume entwickelt. Zusammengefasst kann man einen B – Baum so charakterisieren: Die Knoten des B – Baumes sind Speicherblöcke gleicher Länge. Jeder Block kann bis zu 2k Sätze gleicher Länge aufnehmen; jeder Satz besteht aus einem Schlüssel K und einem Nicht-Schlüssel-Teil W. Im Folgenden werden nur die Schlüssel besprochen. Die Schlüssel sind in jedem Block aufsteigend sortiert. Der Vaterknoten im Baum entspricht einem Index für seine Söhne. Enthält ein Knoten (der nicht Blatt ist) m Schlüssel, so besitzt er m+1 Söhne, auf die durch Zeiger verwiesen wird. Der Aufbau eines Blockes ist dabei der folgende: P0 P1 K1 W1 P2 K2 W2 Pm Km Wm freier Speicher - platz Bild 8: Knoten eines B – Baumes Po zeigt auf einen Teilbaum, dessen Schlüssel alle kleiner sind als K1; pi (i = 1, ..., m-1) weist auf einen Teilbaum mit Schlüsseln zwischen Ki und Ki+1; pm weist auf einen Teilbaum mit Schlüsseln größer Km. in den Blattknoten sind diese Zeiger nicht definiert. 58 7 4 1 Bild 9: 3 6 8 9 12 10 11 13 14 Beispiel für einen B – Baum mit K=1 Die Operationen Einfügen und Löschen für B – Bäume sind so definiert, dass immer gilt: der Baum ist ausgeglichen(alle Blätter haben die selbe Höhe h) jeder der Knoten enthält außer der Wurzel mindestens k und höchstens 2k Schlüssel die Wurzel des Baumes hat entweder keinen Sohn oder mindestens 2 Söhne jeder Knoten außer den Blättern hat m+1 – Söhne (m = Zahl der Schlüssel im Knoten) Das Suchen eines Schlüssels (bzw. des dazugehörigen Satzes) erfolgt wie bei sortierten Bäumen üblich: Durchlaufen von der Wurzel aus, bis der gesuchte Schlüssel gefunden ist oder bis feststeht, dass der Schlüssel nicht vorhanden ist; der zu durchlaufende Ast ist durch Schlüsselvergleich festgelegt. Die Suche endet entweder mit einem B – Baum – Knoten, der den Schlüssel enthält oder bei dem Blatt, das den Schlüssel enthalten müsste. 59 B* - Bäume Eine Variante des B – Baum – Konzeptes sind die sogenannten B* - Bäume. Beim B* - Baum unterscheidet man die B* - Baum – Datei, die die eigentlichen Sätze in sortierter Reihenfolge enthält, sowie den B* - Baum – Index, dessen Knoten den Zugriff auf die Sätze ermöglichen. Ein Beispiel: 7 3 1 2 3 4 5 5 6 8 7 8 10 9 10 11 . Bild 10: B* - Baum Im Unterschied zum B – Baum sind jetzt nicht mehr alle Schlüssel im Indexteil (Baum der Höhe h-1) enthalten. Für das Suchen, Einfügen und Löschen im B* Baum gelten gleichartige Algorithmen wie im B – Baum. Übung 4: Diskutieren Sie die Vor- und Nachteile der B – Baum – Organisation gegenüber der Hash – Organisation. 60 Verbindungen und Clusterung Bei den bisher vorgestellten Verfahren wird die Primärorganisation lediglich durch Attribute eines einzelnen Entities gesteuert. Manchmal ist es jedoch auch sinnvoll, bei der Primärorganisation Beziehungen zwischen Entities mit einzubeziehen. Wenn auf die in Beziehung stehenden Entities häufig gemeinsam zugegriffen wird, ist es sinnvoll, diese Entities physisch benachbart abzuspeichern. Selbst wenn zusammengehörige Entities nicht in der gleichen Seite, aber zumindest in physisch benachbarten Seiten gespeichert sind, ist die Zugriffszeit sehr viel niedriger, als bei Speicherung in beliebig auseinander liegenden Seiten. Bildung eines physischen Satzes Eine Möglichkeit, eine solche Clusterung von in Beziehung stehenden Entities zu erreichen, besteht darin, daraus einen physischen Satz zu erzeugen. Bei einer 1:1Beziehung kann man z. B. die beiden Entities auf einen physikalischen Satz abbilden, oder bei einer 1:n-Beziehung können die zu s S gehörigen Sätze t T physisch zusammenhängend (als ein physischer Satz) gespeichert werden. Allgemeine Formen der Clusterung Angenommen, dass Sätze aus mehreren Dateien miteinander in Beziehung stehen, und dass diese Beziehung durch ein Attribut ausgedrückt sei, das in allen diesen Dateien definiert ist: Wenn einzelne Sätze in diesem Attribut übereinstimmen, dann stehen sie zueinander in Beziehung. Beispiel 2: In einer Möbelfabrik wird ein Regalsystem hergestellt. Der Zusammenbau der einzelnen Regaltypen erfolgt auf der Basis von Standardteilen: Seitenwände, Regalbretter, Rückwände, Oberteile, Böden. Zur Beschreibung der Regaltypen werden nun die folgenden Dateien angelegt: Regal (Regal-Typ, <weitere Felder zur Beschreibung des Regals>) Seitenwand (Regal-Typ, Seitenwand-Typ, Höhe, Tiefe) 61 Regalbrett (Regal-Typ, Regalbrett-Typ, Breite, Tiefe, Anzahl) ..... In vielen Fällen benötigt man sicherlich alle Sätze der verschiedenen Dateien mit einem gegebenen Wert für Regal – Typ gleichzeitig. Diese von der Verarbeitungslogik her wichtige Verbindung kann nun durch geschickte Abspeicherung unterstützt werden: nämlich dadurch, dass die Sätze aller betroffenen Dateien in einer Menge von Seiten abspeichert werden (und nicht mehr getrennt für die verschiedenen Dateien), und zwar sortiert nach dem Kriterium Regal – Typ. Dadurch wird erreicht, dass die Sätze aus unterschiedlichen Dateien, die zu einem Regal – Typ gehören, nahe beieinander abgespeichert („geclustert“) werden und im günstigsten Fall bereits durch einen Sekundärspeicherzugriff in den Hauptspeicher gelangen. Sekundäre Zugriffspfade Das Problem Für Datenbanksysteme ist es typisch, dass Abfragen häufig nicht über Primärschlüssel, sondern über andere Attribute formuliert werden, z. B.: FINDE ALLE ANGESTELLTEN, DIE 30 JAHRE ALT SIND Während beim Suchen über den Primärschlüssel höchstens ein Satz gefunden wird, führt das Suchen über Nichtschlüssel – Attribute zu einer Menge von Sätzen. Das zu diskutierende Problem besteht also darin, eine Datenorganisation zu finden, die bei gegebenem Attributwert einen effizienten Zugriff auf die Menge der Sätze erlaubt, die diesen Wert besitzen. Wir können zwei grundsätzliche Vorgehensweisen bei der Implementierung von sekundären Zugriffspfaden unterscheiden: Einbettung der Zugriffspfade in die Sätze; Trennung der Zugriffspfade von den Sätzen. 62 Im ersten Fall werden die Sätze selbst durch Listen verkettet, man spricht von Multilist – Strukturen; im zweiten Fall werden Techniken der Invertierung angewandt. Invertierung über Indexe Sei A eine beliebige Attributkombination, D die Menge der Werte, die A annehmen kann. Eine Datenstruktur, die für jedes d D die Indikatoren der Sätze mit Wert (A) = d liefert, heißt dann Index für A. Falls der Index einen sekundären Zugriffspfad darstellt, heißt er Sekundärindex. Wir können uns einen Sekundärindex also vorstellen als Datei mit variabler Satzlänge. WERT (SATZID)* WERT ist ein Wert aus D, (SATZID)* ist die Menge der Indikatoren derjenigen Sätze, die diesen Wert für A besitzen. Existiert für eine Attributkombination A ein Index, so heißt die Datei invertiert bezüglich A. In einer invertierten Organisation werden also sekundäre Zugriffspfade über Indexe realisiert. Das folgende Bild gibt ein Beispiel für eine nach den Attributen ABT-NR und ORT invertierte Datei. INDEX „Abteilung“ Angestellten – Sätze ABTNR ABT1 ANG4 ANG- ABTNR NR ANG7 ABT3 KA 2 ABT2 ANG1 ANG4 ABT1 M 1 ABT3 ANG2 ANG5 ABT3 B 2 ANG1 ABT2 KA 0 ANG2 ABT3 M 2 Primärschlüssel ANG5 ANG7 INDEX „Ort“ Bild 11: Ort Primärschlüssel B ANG5 KA ANG1 ANG7 M ANG2 ANG4 Invertierte Datei 63 ORT #KINDER Eine wesentliche Eigenschaft der invertierten Organisation ist es, dass der Zugriffspfad, den ein Index realisiert, völlig getrennt ist von den Sätzen selbst. Damit kann ein Zugriffspfad unabhängig von den Sätzen aufgebaut werden. Dadurch ist eine schnelle Anpassung an Anwendungsanforderungen möglich. Zur Beantwortung von Abfragen können die Indexe der invertierten Datei sehr schnell nach den angegebenen Attributen durchsucht werden. Sofern die Datei nach allen bei der Abfrage verwendeten Attributen invertiert ist, kann allein durch Suchen in den Indexen festgestellt werden, welche Sätze vom Sekundärspeicher zu lesen sind, so dass ausschließlich solche Speicherblöcke übertragen werden müssen, die die gewünschten Informationen enthalten. Beispiel 3: FINDE DIE ANGESTELLTEN DER ABTEILUNG 3, DIE IN MÜNCHEN WOHNEN. Zur Beantwortung dieser Abfrage ermittelt das Datenbankmanagementsystem zuerst aus dem Index „ABTEILUNG“ die Liste der Angestellten in Abteilung 3 (ANG7, ANG5, ANG2), dann aus dem Index „ORT“ die Liste der Angestellten mit dem Wohnort München (ANG2, ANG4); die gemeinsamen Elemente beider Listen (hier: ANG2) sind die Verweise auf die gesuchten Sätze. Der Hauptnachteil invertierter Organisation ist der relativ große Speicherbedarf für die Indexe und der hohe Aufwand für die Verwaltung der Indexe (Ändern, Löschen, Einfügen). Suchzeiten und Änderungsaufwand hängen dabei stark von der gewählten Indexorganisation ab, die an die spezielle Anwendungssituation angepasst werden muss. Sekundärindexe können mit denselben Mechanismen realisiert werden wie die Primär – Zugriffspfade. So können z. B. Sekundärindexe als Indextabellen realisiert werden, die vergleichbar sind mit der index-sequenziellen Speicherorganisation: Eine Indextabelle ist eine Tabelle mit Einträgen der Form (Attributwerte, Zeigerliste). Diese Organisationsform war bei der obigen Prinzipskizze schon verwendet worden (vgl. Bild 11). Die Einträge in der Tabelle sind nach dem Attributwert sortiert, um schnelleres Suchen zu ermöglichen. Ist der Wertbereich des Attributs groß, so werden für diese Indextabelle wieder Indextabellen angelegt. 64 Da das Suchen in Dateien mit variabel langen Sätzen aufwendig ist, wird man nicht immer die Tabellenelemente (Attributwert, Zeigerliste) als Einheit speichern, sondern Zeigerlisten und Attributwerte getrennt führen (vgl. Bild 12). Ein Zeiger weist vom Attributwert auf die zugehörige Zeigerliste, die ihrerseits nun als variabel langes Feld zu organisieren ist. Besitzen die Attributwerte gleiche Länge, so ist damit binäres Suchen im Index möglich. Attributwerte (sortiert) Zeigerlisten Sätze W1 W2 W3 W4 Bild 12: Trennung von Attributwerten und Zeigerlisten im Index Sehr viel flexibler, insbesondere wenn häufig Schlüsselwerte eingefügt oder gelöscht werden müssen, ist die Organisation des Index als B – Baum. In diesem Fall enthält der Nichtschlüssel – Teil eines B – Baum – Satzes eine Zeigerliste auf die Sätze der Datei, in denen der zugehörige Schlüsselwert als Attributwert vorkommt. Große Indexe, die nicht vollständig im Arbeitsspeicher gehalten werden können, werden in der Regel in irgendeiner Variante eines B – Baumes realisiert. Bit – Listen, Bitmap –Indexe In einigen Fällen kann es günstig sein, Indexe als Bit –Listen der Länge #S (sie Datei umfasst #S Sätze) darzustellen. Ist das i-te Bit der Bit – Liste besetzt, so heißt dies, dass der zugeordnete Satz si den entsprechenden Attributwert besitzt. Im Index des folgenden Beispiels erkennt man, dass der Satz s1 und der Satz s3 den Schlüsselwert w1 besitzen, während der Satz s2 diesen Wert nicht besitzt. Im 65 Allgemeinen eignen sich Bit – Listen allerdings nur für Gleichheitsabfragen, nicht jedoch für allgemeine Vergleichsprädikate. Bild 13: Bit 1 2 3 #S w1 1 0 1 … 0 w2 0 0 0 … 1 w3 … Index – Aufbau mit Bit – Listen Bit – Listen können vor allem dann von Vorteil sein, wenn die Anzahl der möglichen Werte des Attributs relativ klein ist, und wenn in Abfragen häufig über eine Kombination dieser Attribute qualifiziert wird (d. h. in relationalen Systemen, es liegen komplexe WHERE – Klauseln vor), wobei die einzelnen Terme Gleichheitsprädikate darstellen. In diesen Fällen lassen sich die booleschen Operatoren in der Abfrage sehr einfach auf Bit – Listen – Operationen umsetzen. Multilist – Strukturen In Multilist – Strukturen werden sekundäre Zugriffspfade dadurch aufgebaut, dass Sätze, die dasselbe Auswahlkriterium (= Prädikat über eine Attributkombination) erfüllen, durch Zeiger zu einer Liste zusammengefasst werden. Im Unterschied zu Indexen (B – Bäume oder Bit – Listen) werden derartige Listenstrukturen also direkt in die Primärdaten eingelagert. Um alle Sätze zu finden, deren Attribut A einen gegebenen Wert w besitzt, muss die zugehörige Liste L (A, w) durchlaufen werden. Um die benötigte Liste zu finden, wird eine spezielle Tabelle der so genannten Listen – Köpfe oder Anker eingerichtet, die auf die ersten Elemente der Listen verweisen. Auf diese Weise werden bei Multilist – Strukturen alle Sätze mit einem bestimmten Attributwert w gefunden, ohne dass Sätze gelesen werden müssen, die diesen Wert nicht besitzen. 66 Listenköpfe rot Sätze 1 blau blau 2 rot .. 4 blau .. 3 rot .. 5 grün 7 blau .. 12 Bild 14: blau Multilist – Strukturen Der Hauptvorteil von Multilist – Strukturen liegt in der einfachen Verwaltung und Programmierung. Die Suchzeiten können jedoch beträchtlich ansteigen, wenn die Listen lang werden und die Listenelemente ungeschickt über die Speicherblöcke verteilt sind. Die Beantwortung komplexer Abfragen ist aufwendig, da bei jedem Suchvorgang die Sätze selbst berührt werden müssen; bei der invertierten Organisation ist häufig ein großer Teil der Aufgabe allein durch die Auswertung der Indexe lösbar. Um die Operation Einfügen und Löschen zu vereinfachen, um Suchvorgänge abkürzen zu können und aus Gründen der Wiederherstellung nach Fehlern, wird die einfache Listenform meist durch Zeiger erweitert: Rückwärtsverkettung: ein zweiter Zeiger in jedem Satz zeigt auf den Vorgänger in der Liste Ring: der Zeiger des letzten Satzes in der Liste zeigt auf den Listenanfang Übung 5: Vergleichen Sie Multilist – Strukturen und Index – Organisationen bezüglich Verwaltungsaufwand Speicherbedarf Flexibilität (Einrichtung und Entfernung von Zugriffspfaden) Unterstützung komplexer Abfragen (z.B. Alter>30 UND Wohnort=München 67 Verbindungen zwischen den Sätzen Die im konzeptionellen Schema definierten Beziehungen zwischen Entities spielen eine große Rolle für die Anfragen an eine DB. Häufig wird auf miteinander in Beziehung stehende Entities gleichzeitig zugegriffen. In relationalen Systemen werden in Beziehung stehende Tupel häufig durch Joins zusammengefasst. Wie bekannt, sind Joins sehr aufwendige Operationen, so dass häufig auszuführende Joins durch die Speicherorganisation unterstützt werden sollten. Neben den bekannten Möglichkeiten, durch Beziehungen zwischen Sätzen die Primärorganisation einer Datei zu steuern, werden auch Mechanismen benötigt, die den Zugriff auf zusammengehörige Sätze über Sekundärzugriffspfade unterstützen. Dabei können im Prinzip dieselben Techniken genutzt werden, die auch für den Zugriff auf einzelne Sätze mit bestimmten Feldwerten eingesetzt werden: Betrachten wir zwei verschiedene Satztypen S und T. S besitze ein Feld A, T ein Feld B. Eine Verbindung bestehe aus solchen Sätzen s S und t T, für die gilt: wertA(s) = wertB(t). Eine solche Verbindung (Primärschlüssel und Fremdschlüssel!) kann z. B. folgendermaßen durch eine Invertierung unterstützt werden: S wird invertiert bezüglich A, T wird invertiert bezüglich B. Dann kann zu jedem Satz s S über den Index für B sofort die zugehörige Satzmenge in T gefunden werden; dasselbe gilt für t T. Mechanismen in relationalen Systemen Abschließend soll ein Blick auf die Möglichkeiten geworfen werden, die die heutigen relationalen DBMS für die Zugriffsunterstützung bieten. Außerdem werden einige Punkte skizziert, die beim Entwurf des internen Modells für eine relationale DB zu beachten sind. Während die logischen Konzepte relationaler Systeme weitgehend standardisiert sind (SQL 92), gibt es auf der Ebene der Zugriffspfade und Speicherorganisation eine gewisse Variabilität zwischen den unterschiedlichen Systemen, vor allem bei den Details der Abspeicherung und Zugriffspfad – Organisation. Im Folgenden werden beispielhaft einige Konzepte vorgestellt, die in den DBMS ORACLE und SYBASE angeboten werden. Viele der vorgestellten Mechanismen finden sich in dieser oder ähnlicher Form auch in anderen Systemen. 68 Primärorganisation der Daten Bei der Primärorganisation der Daten werden zwei grundlegende Möglichkeiten der Datenorganisation angeboten: unsortierte Abspeicherung von einzelnen Tupeln (Heap) sortierte Abspeicherung im Zusammenhang mit einem Primärzugriffspfad (B – Baum) Bei der Heap – Speicherung werden der Tabelle Seiten zugeordnet, auf denen beim Einfügen eines Tupels eine freie Stelle gesucht wird. Da kein Sortierkriterium die Auswahl der Seite steuert, kann bei einem Zugriff auf die Tabelle auch nur mit Hilfe eines „Table Scans“ gearbeitet werden, d. h. dem sequenziellen Durchlauf durch alle Seiten dieser Tabelle (es sei denn, der Zugriff kann über einen Sekundär – Zugriffspfad unterstützt werden). Sollen die Tupel sortiert abgespeichert werden, so wird die Tabelle durch einen B – Baum organisiert. Im ORACLES DBMS wird dies beispielsweise im CREATE TABLE – Statement angegeben: CREATE TABLE Angestellter (.....Attributdefinition......, CONSTRAINT pk_Ang_Nr PRIMARY KEY (Ang-Nr) ) ORGANIZATION INDEX; 69 In der ORGANIZATION – Klausel wird festgelegt, dass die Abspeicherung der Tabelle über einen Index (B-Baum) organisiert wird. Dieser B – Baum benutzt den Primärschlüssel der Tabelle als Suchschlüssel (im Beispiel also Ang-Nr). Das SYBASE – DBMS erlaubt es, die Primärorganisation durch ein beliebiges Attribut oder Attributkombination zu steuern, die keine Duplikate enthält (UNIQUE – Constraint). Dies kann sowohl im CREATE TABLE – Statement definiert werden, als auch durch die explizite Definition des „clustered Index“. Während SYBASE (und viele andere Systeme auch) den Begriff „Cluster“ auf die tabelleninterne Clusterung anwendet, hat der Begriff „Cluster“ bei ORACLE eine allgemeinere, tabellenübergreifende Bedeutung: Ein Cluster enthält eine Menge von Tabellen, die ein Attribut (oder eine Attributkombination) gemeinsam haben. Ein Cluster kann auf zwei Arten organisiert werden: Bei einem Index – Cluster wird jeder Wert des Clusterattributs nur einmal pro Seite abgespeichert, und alle Tupel aus den Tabellen des Clusters mit dem selben Clusterattribut – Wert werden benachbart abgespeichert. Für das Clusterattribut existiert ein Index (muss allerdings durch den Benutzer explizit angelegt werden). Durch die Definition eines solchen Clusters soll die Ausführung von Joins über das Clusterattribut unterstützt werden. Bei einem Hash – Cluster werden auf einer Seite Tupel abgelegt, bei denen die Anwendung der Hash – Funktion auf denselben Wert führt. Die Hash – Funktion kann beim Ablegen des Clusters vom Benutzer definiert werden, andernfalls wird auf eine vordefinierte Hash – Funktion zurückgegriffen. 70 Sekundärindexe Alle relationalen Datenbanksysteme ermöglichen die Definition von Sekundärindexen. Dabei wird üblicherweise eine Variante des B- oder B* Baumes eingesetzt. Die Definition des Sekundärindexes für das Attribut Wohnort der Tabelle Angestellter sieht folgendermaßen aus: CREATE INDEX Index_Wohnort ON Angestellter(Wohnort); Durch das Keywort UNIQUE kann festgelegt werden, dass die Schlüsselwerte des Indexes eindeutig sein müssen, d. h. Duplikate sind nicht erlaubt. Dies lässt sich jedoch nur dadurch erreichen, dass bei der Tabellendefinition ein UNIQUE – Constraint für ein Attribut oder eine Attributgruppe definiert wird. Diese Möglichkeit ist immer vorzuziehen, da Eindeutigkeit eine semantische Bedingung darstellt und daher auf Schema – Ebene beschrieben werden muss und nicht auf der internen Ebene als Anhängsel einer Index – Definition. Die alleinige Benutzung eines UNIQUE – Indexes ohne Spezifikation eines UNIQUE – Constraints ist schlechter Entwurfsstil! Da die Indexstrukturen unabhängig von den Primärdaten als eigenständige Daten angelegt werden, können sie auch wieder gelöscht werden, ohne dass dies andere Auswirkungen als eine Veränderung der Antwortzeit hat. Somit kann der Index Index_Wohnort folgendermaßen wieder gelöscht werden: DROP INDEX Index_Wohnort; Eine zusätzliche Möglichkeit bietet ORACLE: Indexe können statt als B – Bäume auch als Bit – Listen realisiert werden. In diesem Fall werden die Sätze, die zu einem Suchschlüssel gehören, nicht über Adresslisten gefunden, sondern über eine Bit – Liste. Insbesondere boolesche Verknüpfungen von Suchbedingungen können dadurch effizient auf Bit – Listen – Operationen abgebildet werden. Entwurf des internen Modells der Datenbank In den vorherigen Abschnitten wurde schon mehrfach angesprochen, dass man sich häufig durch die Optimierung von bestimmten Operationen Nachteile bei anderen Operationen erkauft. Je mehr Zugriffspfade z. B. zur Optimierung des Retrieval angelegt werden, desto teurer wird im Allgemeinen das Ändern, Einfügen und Löschen. Der Entwurf des internen Modells als der Beschreibung dieser Strukturen will also sehr sorgfältig geplant sein. 71 Insbesondere ist zu beachten, dass das interne Modell stark vom erwarteten oder tatsächlichen Zugriffsverhalten der Anwendung abhängig ist. Für den Entwurf des internen Modells ist es daher unumgänglich, diese Informationen zunächst zu ermitteln. Dazu sollten u.a. die folgenden Analysen durchgeführt werden: Analyse der Datenmenge und ihrer Änderungstendenzen, z. B. maximale, minimale, durchschnittliche Anzahl von Tupel einer Relation Veränderung der Tupelanzahl (Unterschied zwischen Stammdaten, bei denen nur ein geringer Prozentsatz im Monat gelöscht oder eingefügt wird, und Bewegungsdaten, wie etwa Aufträge, die möglicherweise zu 90 % nach einigen Wochen erledigt sind). Analyse der Benutzung der Daten, z. B. Analyse der Anfragen/Transaktionen (welche Zugriffe werden benötigt?) Häufigkeit der Anfragen/Transaktionen (etliche Male pro Stunde, stündlich, täglich, jährlich) Anzahl der parallel laufenden Transaktionen, Identifikationen der kritischen Daten mit den meisten parallelen Zugriffen Definition von einzuhaltenden Antwortzeiten für einzelne Anwendungen bzw. von Anforderungen an die Anzahl der pro Zeiteinheit zu verarbeitenden Transaktionen Auf der Basis dieser Analysen kann dann die gewünschte Leistung der Datenbank definiert werden, d. h. es werden Prioritäten für die vielen anvisierten Antwortzeiten bzw. die definierten Durchsatz – Anforderungen aufgestellt. Nach dieser Zieldefinition können die oben beschriebenen Mechanismen angewandt werden, um die Leistungsziele zu erreichen. Zunächst geht es um die Definition der Primärspeicherstrukturen für die Tabellen. Die Zugriffe, die über den Primärindex unterstützt werden, können in der Regel am schnellsten ablaufen, da die Indirektionstufe vom (Sekundär-) Index zu den eigentlichen Dateien fehlt. Die Auswahl des Primärindexes stellt somit eine wesentliche Entscheidung dar. Hier gilt es auch abzuschätzen, ob die Organisation mit einem Hash – Verfahren einem B – Baum – Verfahren vorzuziehen ist, weil es etwas weniger auf sortierte Zugriffe, als auf Einzelzugriffe ankommt und/oder weil die Datenmenge der Tabelle relativ stabil ist. 72 Falls es von höchster Wichtigkeit ist, bestimmte Joins zu unterstützen, kann in ORACLE ein Index – Cluster eingesetzt werden, der die Tupel verschiedener Tabellen bzgl. eines Join – Attributs clustert. Falls die ausgewählte Datenbank eine solche Möglichkeit nicht anbietet, sollte der Join nach Möglichkeit über sekundäre Zugriffspfade unterstützt werden. In der Praxis wird häufig eine Clusterung durch „Denormalisierung“ angestrebt: Joins werden auf der Ebene des Tabellenschemas vorweggenommen, indem bewusst Regeln aus dem Normalisierungsprozess verletzt werden. Dies führt zu redundanten Daten, und die Probleme, die wir bei der Einführung der verschiedenen Normalformen erkannten und durch die Normalisierung eliminiert haben, kehren zurück. Daher bedarf es sehr guter Gründe, um eine solche Denormalisierung für Performance – Zwecke einzuführen, und es müssen Maßnahmen zur Wahrung der Konsistenz der redundanten Daten getroffen werden. Dies birgt Gefahren von logischen Fehlern in sich, und zum anderen muss der Aufwand für die Wiederherstellung der Konsistenz in die Performance – Überlegungen einbezogen werden. Denormalisierung kann als eine Möglichkeit gesehen werden, in relationalen Systemen logische Entities auf interne Sätze abzubilden: Relationen in 3./4. Normalform werden zusammengefasst und zu denormalen Relationen. Neben dieser Zusammenführung von Informationen verschiedener Entity –Typen in eine Relation kann es auch vorteilhaft sein, Informationen über einen Entity -. Typ, also eine Tabelle, zu splitten. Dies kann sowohl horizontal als auch vertikal erfolgen: Bei der horizontalen Partitionierung wird eine Tabelle in verschiedene Subtabellen unterteilt, die jeweils eine Teilmenge der Tupel der Gesamttabelle enthalten. Durch die Vereinigung dieser Subtabellen entsteht also wieder die Ursprungstabelle. Bei der vertikalen Partitionierung wird die Menge der Attribute auf verschiedene Tabellen verteilt, die jedoch alle den Primärschlüssel enthalten und somit durch einen Join wieder zur Ausgangstabelle zurückgeführt werden können. Die Partitionierung kann insbesondere bei großen Tabellen von Vorteil sein: Anfragen, die nur eine Partition betreffen, sind wesentlich effizienter zu beantworten, da die gesuchte Information aus weniger Daten herausgefiltert werden kann, wodurch sich auch kleinere und effizientere Zugriffspfade ergeben. Außerdem lassen sich verschiedene Partitionen auf unterschiedliche Datenträger legen, was zu einer Erhöhung der Parallelität führt und damit den Durchsatz von Transaktionen erhöht. 73 Die Partitionierung kann durch eine Definition von entsprechenden unabhängigen Tabellen vorgenommen werden. Da in diesem Fall jedoch die Information über die Zusammengehörigkeit der Tabellen verloren geht, schlägt dies bis auf die Ebene der Anwendungsprogramme und der Queries durch. Viele DBMS bieten aber inzwischen die Möglichkeit, Partitionierungen auf der internen Ebene zu definieren, so dass die Anwendungsprogramme davon nicht betroffen sind. In diesem Fall werden die Partitionierungen vom DBMS verwaltet, und das DBMS erkennt ob eine Abfrage lediglich eine oder mehrere Partitionen betrifft und kann entsprechend reagieren. Dies ist insbesondere auch von Wichtigkeit für die Verteilung von Daten in einer verteilten Datenbank. Nach der Festlegung der Speicherorganisation gilt es, für die bisher noch nicht unterstützten Anfragen Sekundärzugriffpfade anzulegen. Dafür bieten sich in relationalen Systemen im wesentlichen Invertierungen über B – Bäume an. Generell ist die Invertierung einer Tabelle nach einem Attribut A nur sinnvoll, wenn die Selektivität von A hochwertig ist, d. h. wenn die Zahl der zu lesenden Tupel zu einem bestimmten Attributwert sehr viel kleiner ist als die Anzahl der Tupel der Tabelle. Für Attribute mit niedriger Selektivität ist der Aufwand zur Verwaltung des Index nicht gerechtfertigt, da lange Adresslisten zu bearbeiten sind und die zu lesenden Tupel mit großer Wahrscheinlichkeit doch über einen großen Teil der Speicherblöcke verteilt sind, so dass gegenüber sequentiellem Durchsuchen wenig gewonnen wird. Eine nützliche Daumenregel für die Frage, ab wann Invertierung überhaupt sinnvoll sein kann, ist die folgende: Invertierung lohnt sich nur dann, wenn bei typischen Abfragen die durchschnittliche Zahl der qualifizierten Tupel in der Datenbank kleiner als 10 % der Gesamtzahl der Tupel ist. Andernfalls ist eine einfache sequentielle Organisation, bei der für jede Abfrage der gesamte Datenbestand durchsucht werden muss, zu überlegen. Allerdings kann in einzelnen Fällen der Einsatz von Bit – Listen eine Alternative darstellen (wird z. B. in ORACLE angeboten), falls nämlich im Qualifikationsausdruck von Anfragen häufig eine Kombination von Gleichheitsprädikaten über mehrere Attribute mit geringer Selektivität auftritt. 74 Recovery und Concurrency Recovery: Rekonstruktion einer Datenbank im Fehlerfall. Aufgabe ist es, verlorengegangene Informationen wiederzubeschaffen. Die Konsistenz muss gewährleistet sein. Die Art der Probleme (z.B. Rechnerausfall, Feuer, DBMSProbleme,...) darf keinen Einfluss auf die Wiederherstellbarkeit der Daten haben. Concurrency: Parallelbetrieb. Gefordert wird das Zulassen gleichzeitiger Zugriffe von mehreren Benutzern auf eine DB. Ohne entsprechende Maßnahmen können Konsistenzverletzungen und Datenverlust auftreten. Zur Verhinderung sind Synchronisationsmechanismen erforderlich. Grundsituation: Anwender kleiner Datenbanken unterschätzen die Bedeutung gern, belassen es bei einer täglichen Sicherung, Störungen werden manuell korrigiert, was mühsam und fehleranfällig sein kann. Parallelbetrieb wird nicht oder nur unzureichend unterstützt. Bei Großrechnern und mittleren Systemen müssen Daten ständig und überall verfügbar sein. Datenverluste und Inkonsistenzen müssen unter allen Umständen verhindert werden (was allerdings dem Anwender verborgen bleiben soll). Der Aufwand für Recovery steigt im Parallelbetrieb erheblich gegenüber der Einplatzlösung, Concurrency ist ohne minimale Recovery nicht denkbar. Insbesondere sind beide Begriffe eng mit der Transaktionsverarbeitung verbunden. Recovery Grobe Klassifizierung der Fehler HW-Fehler: Stromausfall, Wackelkontakte, Plattenausfall, Netzausfall, Brand, Wasserschaden SW-Fehler: Fehler der DBMS-Software, des Betriebssystems, im AW-Programm. DÜ-SW Sorgfaltspflicht des DBA, die HW und SW nach Gesichtspunkten der Zuverlässigkeit auszusuchen (RAID-Systeme!), minimiert die Ausfallrate, verhindert wird sie dadurch nicht. Mindestens einmal pro Woche eine Komplettsicherung, täglich Differenzsicherung, zusätzlich wird ein elektronisches Logbuch geführt, das alle Änderungen der DB seit der letzten Sicherung vermerkt. Bei der Rekonstruktion müssen nicht korrekt abgeschlossene Transaktionen besonders beachtet werden. Für eine performante DB müssen möglichst viele Daten im Arbeitsspeicher gehalten werden. Gerade dann ist ein Stromausfall besonders kritisch. 75 Beispiel: Flugbuchung München nach San Francisco über Frankfurt und New York. Die drei Einzelflüge müssen als eine Transaktion atomar behandelt werden. Zerlegung eines Gesamtablaufs mit dem SQL-Befehl COMMIT WORK bzw. COMMIT. Jedes COMMIT beendet die gerade laufende Transaktion, folgende Aktionen gehören zur nächsten Transaktion. UPDATE Flug SET ... UPDATE Flug SET … UPDATE Flug SET … COMMIT WORK; ; ; ; (Flug München – Frankfurt) (Flug Frankfurt – New York) (Flug New York- San Francisco) (Transaktion beendet, Buchung erfolgt) Ist im Fehlerfall eine Transaktion noch nicht abgeschlossen, so muss diese komplett zurückgesetzt werden. Ein Rechnerabsturz während des obigen Ablaufs erfordert während der Rekonstruktion die Rücknahme aller bereits durchgeführten Änderungen. Andererseits muss jedes Datum erhalten bleiben, das durch eine (mit COMMIT) beendete Transaktion geändert wurde. Erst dann ist die Zuverlässigkeit des Datenbestands gewährleistet. Nun kann es aber auch passieren, dass dem Reisenden die angebotenen Flugund Wartezeiten missfallen. Sicherheitshalber wurden die Flüge aber bereits vorreserviert. Alle Aktionen innerhalb geschlossener Transaktionen gelten als noch nicht endgültig. Jederzeitiger Widerruf ist möglich! Beispiel in C++ mit Embedded SQL EXEC SQL UPDATE Flug SET ... ; // Flug München – Frankfurt EXEC SQL UPDATE Flug SET … ; // Flug Frankfurt – New York EXEC SQL UPDATE Flug SET … ; // Flug New York- San Francisco cout <<”Wollen Sie den Gesamtflug fest buchen? (j/n):“; getchar (zeichen); if (zeichen == „j“) { EXEC SQL COMMIT WORK; // Transaktion erfolgreich beendet cout <<“der Flug ist gebucht!\n“; } else { EXEC SQL ROLLBACK WORK // Transaktion wird zurückgesetzt cout <<“der Flug wurde storniert!\n“; } 76 Mit ROLLBACK WORK werden alle durchgeführten Änderungen seit dem letzten COMMIT automatisch zurückgesetzt. Dazu wurden alle Änderungen innerhalb einer Transaktion in einem Logbuch kurz Log genannt protokolliert. Mit Hilfe der Logeinträge werden alle verlorengegangenen Daten wiederhergestellt (mit COMMIT WORK schon abgeschlossen!). Änderungen, verursacht durch noch nicht abgeschlossene Transaktionen werden zurückgesetzt. Recovery und Logdatei Allgemeine Vorrausetzungen für den Datenbankbetrieb: DB ist auf externen nichtflüchtigen Datenträgern angelegt und direkt vom Server aus zugreifbar. Logdatei steht auf einem weiteren externen nichtflüchtigen Datenträger und ist auch vom Server aus direkt zugreifbar. Zur Entlastung des E-/A-, Verkehrs und zur Beschleunigung werden Daten in einem internen ASP-Bereich (DB-Puffer, Cache) zwischengespeichert. Beim Lesezugriff wird grundsätzlich vom DB-Puffer gelesen, ist das gesuchte Datum noch nicht da, wird es von der DB in den Cache geholt. Auch das Schreiben erfolgt in den DB-Puffer. Zu einem günstigeren Zeitpunkt erfolgt die Aktualisierung der DB. Ist der DB-Puffer voll gefüllt, so werden die am längsten nicht mehr benutzten Daten freigegeben. Geänderte Daten werden auf jeden Fall vorher in die DB zurückgeschrieben. Die Informationen, welche Daten der DB im Cache liegen und welche geändert wurden, heißen Metadaten und werden in einem eigenen Bereich des Arbeitspeichers verwaltet. Dazu zählen auch die Daten über alle offenen Transaktionen und über die Synchronisation beim Puffer- und Logdateizugriff. Die Pufferung (ggf. mehrere GB) reduziert Laufzeiten und Datentransfer erheblich. Die Verwaltung übernimmt das DBMS. Die Grundidee ist es, Daten direkt und ausschließlich im Cache zu bearbeiten. Um ein Rücksetzen einer Transaktion zu garantieren, werden die zu ändernden Daten zunächst in der Logdatei persistent gespeichert. Dann erfolgt das Update der Daten und auch diese neuen Daten werden in die Logdatei geschrieben. 77 Lesen der Daten Merken der bisherigen Daten Ändern der Daten Merken der geänderten Daten Einlesen von der Platte, falls noch nicht im Puffer vorhanden Die zu ändernden Daten werden in die Logdatei geschrieben (Before Image) Ändern (Update, Delete, Insert) der Daten im Arbeitspeicher, Sperren dieser Einträge für andere Benutzer. Die geänderten Daten werden in die Logdatei geschrieben (After-Image) Mehrmalige Wdh. der obigen Schritte pro Transaktion Transaktionsende COMMIT: Schreiben evtl. noch nicht geschriebener Beforemit und After-Images und benötigter Metadaten zu dieser COMMIT oder Transaktion in die Logdatei. Transaktionsende in der Logdatei ROLLBACK vermerken, Sperren freigeben. ROLLBACK: Rücksetzen der Metadaten der Transaktion. Geänderte Daten im Arbeitsspeicher mittels Before-Images restaurieren. Alle geänderten Daten, die bereits in die DB geschrieben wurden, werden für ungültig erklärt, Sperren freigegeben. Änderungen Geänderte Daten werden asynchron (unabhängig vom speichern Transaktionsbetrieb) in die DB geschrieben. Transaktionsbetrieb mit Log und Arbeitspeicherpufferung Funktionen der Logdatei und des DB-Puffers Arbeitsspeicher Metadaten: 1 Lesen aus der Datenbank, falls Daten nicht im Cache stehen DB-Puffer (Cache) : 3 2 Schreiben in der DB, falls Platz im Cache benötigt wird Blöcke 2 1 Logdatei Datenbanken 78 3 Ständiges Sichern in die Logdatei Fallunterscheidung im Ablauf gemäß Tabelle: Fall 1: Falls Transaktion mittels Rollback zurückgesetzt wird, kann mit BeforeImage der ursprüngliche Zustand wiederhergestellt werden. Sollten die Daten bereits vorher in die Datenbank geschrieben und eventuell sogar aus dem Arbeitspeicher entfernt worden sein, so genügt ein erneutes Lesen der geänderten Daten in den Puffer, Rücksetzen mittels Before Image und ein für ungültig Erklären des betreffenden Datenbankinhalts. Fall 2: Verlorengehen von Datenbankdaten. Hier hilft das Merken mittels AfterImage weiter. Da beim Ende der Transaktion ein Vermerk in die Log geschrieben wurde, kann bei einem Ausfall erkannt werden, welche Änderungen zu einer bereits beendeten Transaktion gehören. Im schlimmsten Fall, dem Totalverlust auf der Platte, kann die letzte Sicherung eingespielt werden und anschließend alle Transaktionen mittels Logeinträgen nachvollzogen. Gleichzeitige Vernichtung der getrennten Medien für Log und DB ist unwahrscheinlich, Absicherung dagegen bringt doppelte Speicherung in getrennten Räumen. Pro Transaktion genügt im allgemeinen das Schreiben eines einzigen Blocks (mit allen Änderungsinformationen!) an Metadaten in die Logdatei im Umfang von nur wenigen Bytes! In die Logdatei wird sequenziell geschrieben. Trotzdem wird die Logdatei mit der Zeit sehr umfangreich und es sollte täglich (mindestens Differenzsicherung) gesichert werden mit anschließender Löschung der Log. Aus Sicherheitsgründen gibt es i.a. eine Zweiteilung in „normale Log“ und Archivlog, meist als kostengünstige Banddatei. Problem „Hotspots“: Blöcke die ständig gelesen und geändert werden und somit nie in die DB zurückgeschrieben werden, da kein Verdrängungsgrund besteht (im Laufe vergleichsweise „alter DB-Zustand“). Ebenso geht es mit den dazugehörigen Metadaten. Damit sammelt sich „einiges“ an, was nur zeitaufwändig wieder entfernt werden kann (falls dabei ein Fehler passiert, ist die DB länger blockiert!). Lösung „Checkpoints“: Zeitpunkte an denen gelegentlich (im Minutenbereich!) zwangsweise Blöcke in die DB geschrieben werden. Das verursacht zwar einen hohen E-/A-Verkehr und bremst die Transaktionen, verursacht sogar zwischenzeitlich inkonsistente Zustände (ggf. Daten von nicht abgeschlossenen Transaktionen!) wird aber für die damit verbesserte Recovery gerne in Kauf genommen. Jeder Checkpoint wird in der Log vermerkt. 79 Recovery und Checkpoints Trotz aller schon bekannten „Vorsichtsmaßnahmen“ (inkl. Checkpoints) müssen noch einige Probleme bedacht werden. Mögliche Fehler im Transaktionsbetrieb: Lokaler Fehler Softcrash Hardcrash Nur eine einzelne Transaktion ist betroffen (SW-Fehler wie DIV/0 oder Bereichsgrenzenüberschreitung) Ausfall der SW in größerem Umfang bis hin zum Stromausfall, sodass Daten im ASP ausgefallen oder ungültig sind und viele Transaktionen betroffen sind. Ein HW-Teil fällt aus, z.B. eine Magnetplatte Auf jeden Fehler reagiert das DBMS angemessen, bei größeren Fehlern entscheidet der DBA über die einzuleitenden Maßnahmen. Lokaler Fehler: DBMS setzt alle Änderungen der fehlerverursachenden Transaktion zurück. I.a. stehen noch alle Before-Images im ASP, Sperren werden zurückgesetzt, Meldung an DBA und an den Benutzer, der die Transaktion startete. Hardcrash: DBA stoppt DB-Betrieb. Alle noch nicht beendeten Transaktionen werden vom DBMS zurückgesetzt. Die DB-Puffer werden geleert, die Log aktualisiert, Sperren freigegeben, neue Hardware beschafft, der letzte Sicherungsstand wird eingespielt und die Änderungen mittels Logdatei nachvollzogen. Softcrash: Verlorene Daten im ASP ergeben zumeist eine inkonsistente DB (Metadaten, nicht gesicherte Before-Images oder After-Images)! Falls lokalisierbar, ist dies zu behandeln wie ein lokaler Fehler. Ansonsten wird aktualisiert mithilfe der Checkpoints. Anhand der Einträge in der Log kann nachvollzogen werden, welche Transaktionen seit dem letzten Checkpoint gestartet und beendet wurden. Das folgende Bild zeigt die fünf möglichen Fälle (T1 bis T5) wie sich Transaktionen in bezug auf den letzten Checkpoint und den Softcrash befinden können. 80 T1 T2 T3 T4 T5 t t1 Checkpoint t2 Softcrash Transaktionen T1, die zum Zeitpunkt des Checkpoints abgeschlossen waren, sind komplett in der DB gesichert, da zum Zeitpunkt des letzten Checkpoints alle Daten aktualisiert wurden. Keine weiteren Reaktionen erforderlich. Transaktionen T2 und T4 sind zwar abgeschlossen, aber es ist noch nicht sicher, dass alle Änderungen auch in die DB geschrieben wurden. Vom Zeitpunkt des letzten Checkpoints bis Transaktionsende wird die DB bezüglich dieser Transaktionen noch aktualisiert (benötigte Informationen aus Log). Reihenfolge ist genauestens zu beachten (mithilfe der Metadaten). Transaktionen T3 und T5 müssen zurückgesetzt werden, da sie in t2 noch nicht beendet waren. Alle schon erfolgten Änderungen in der DB müssen mithilfe der Log zurück genommen werden. Zusammenfassung: Erst die Logdatei ermöglicht komplette Recovery, Checkpoints reduzieren den Aufwand einer solchen Recovery, da nur Transaktionen, die zum Zeitpunkt des Checkpoints noch nicht beendet waren, restauriert werden müssen. Die Wiederherstellung liegt dann zumeist nur noch im Viertelstundenbereich. Die Häufigkeit des Checkpoints ist einstellbar und Erfahrungssache in Abhängigkeit von der Anwendung. 81 Zwei-Phasen-Commit Recovery in verteilten Datenbanken stellt zusätzliche Anforderungen. Verteilt bezieht sich in diesem Fall auf die Verteilung der Datenbank im Ganzen und nicht auf die Verteilung einzelner Elemente (zugriffstechnisch extrem komplex!). Ein typisches Beispiel ist die Verteilung bei einer Großbank mit einer DBZentrale an die mehrere Filialen bzw. Tochtergesellschaften mit eigenen lokalen DB angeschlossen sind. Falls die Transaktionen auf mehrere Datenbanken zugreifen, aber nur an einer DB Änderungen vornehmen, dann läuft die Recovery wie bekannt. Problematisch ist die datenbankübergreifende Manipulation. Dann muss zur Konsistenzerhaltung die Forderung aufgestellt werden, dass globale Transaktionen erst dann als abgeschlossen gelten, wenn die lokalen Transaktionsabschnitte in allen zugreifenden Rechnern beendet sind. Sonst passiert es, dass beim bargeldlosen Geldverkehr eine Transaktion in der einen DB als abgeschlossen gilt und in der anderen DB wegen Fehler zurückgesetzt wird. Lösung: Zwei-Phasen-Commit Jede DB arbeitet wie gewohnt im Transaktionsbetrieb mit eigener Log, eigener Metadatenverwaltung und führt nach Transaktionsende ein lokales COMMIT aus. Gleichzeitig wird einer der beteiligten Rechner als Koordinator eingesetzt. Er fährt ein systemweites Protokoll, mit eigener Logdatei und globalem COMMIT. Lokales Abarbeiten einer Transaktion Melden des Transaktionsendes Globales Transaktionsende Jede übergreifende Transaktion arbeitet in den einzelnen DB lokal, Änderungen in lokaler Logdatei protokolliert. Wurde eine Transaktion erfolgreich beendet oder zurückgesetzt erfolgt Meldung an den Koordinator. Der Koordinator sammelt alle lokalen Meldungen. Liegen erfolgreiche Rückmeldungen vor, so wird ein globales COMMIT ansonsten ein ROLLBACK eingetragen. Endgültiges lokales Das Ende der globalen Transaktion wird an alle lokalen Transaktionsende Rechner zurückgeliefert. Jeder lokale Rechner übernimmt das globale Ergebnis als endgültiges. Erst jetzt ist die Transaktion abgeschlossen. Problem, wenn der Koordinator ausfällt, dann Rücksetzungen mit Hilfe der lokalen Logdateien und Aufsetzen auf den letzten konsistenten Zustand! Zwei-Phasen-Commit ist sehr zeitintensiv (Verzehnfachung der Antwortzeiten!), deshalb wird das Inkonsistenzrisiko oft wissentlich und nicht nachahmenswert in Kauf genommen. 82 Übungsaufgaben: 1) In einem sicheren DB-Betrieb wurde gerade das Transaktionsende in die Logdatei geschrieben. Noch vor der Rückmeldung der Transaktion an den Benutzer stürzt das System ab. Wird beim nächsten Hochfahren die Transaktion deshalb zurückgesetzt? 2) Was sind Checkpoints? Beschreiben Sie den Nachteil, wenn eine DB ohne Checkpoints arbeiten würde. 3) In nicht wenigen DB-Anwendungen ist die Recovery-Unterstützung deaktiviert oder zumindest stark eingeschränkt. Woran mag das liegen? 4) Welche Schritte müssen vom Systemadministrator bzw. vom DBMS durchgeführt werden, wenn eine einzelne Transaktion wegen eines Softwarefehlers abstürzt? 5) Ein DBA merkt, dass die Magnetplatte der DB nicht mehr fehlerfrei arbeitet. Welche Maßnahmen müssen ergriffen werden, um mögliche fehlerbehaftete Schreibvorgänge seit der letzten Sicherung zu eliminieren? 6) Unter welchen Voraussetzungen kann auf ein After-Image verzichtet werden? 7) Wann wird ein Zwei-Phasen-Commit benötigt? 8) Was macht einen Zwei-Phasen-Commit so zeitintensiv? 9) Wie erkennt man Deadlocks und wie beseitigt man sie? 10) Im Parallelbetrieb kann man auch ohne Sperrmechanismen auskommen. Worum handelt es sich und warum wird das Verfahren kaum eingesetzt? 83 Verteilte Datenbanken Dezentrale oder verteilte Datenbanken (distributed databases) finden in öffentlich und privatrechtlichen Unternehmen Anwendung, in denen Daten an verschiedenen Orten gesammelt, gepflegt und verarbeitet werden sollen. Eine DB ist dezentral oder verteilt, wenn sie zwar durch ein einziges logisches DB-Schema beschrieben, aber durch mehrere physische Tabellenfragmente auf örtlich verteilten Rechnern gehalten wird. Der Anwender hat sich lediglich mit der logischen Sicht zu befassen, um die physischen Fragmente braucht er sich nicht zu kümmern. Das DBMS selbst übernimmt es, DB-Operationen lokal oder bei Bedarf verteilt auf verschiedenen Rechnern durchzuführen. Beispiel: MITARBEITER MNR Name M19 Keller M1 Meier M7 Huber M4 Becker Ort Frenkendorf Liestal Basel Liestal ABTEILUNG ANR Bezeichnung A3 Informatik A5 Personal A6 Finanz Abt A6 A3 A5 A6 Mitarbeiter aus den Abteilungen Informatik und Personal sollen in der Lokalität Basel verwaltet werden, die anderen in der Lokalität Zürich: CREATE FRAGMENT F1 AS SELECT * FROM MITARBEITER WHERE Abt IN (A3,A5) CREATE FRAGMENT F2 AS SELECT * FROM ABTEILUNG WHERE ANR IN (A3,A5) Ergebnis der horizontalen Fragmentierung der Tabellen MITARBEITER und ABTEILUNG: MNR M1 M7 F1 in Basel Name Ort Meier Liestal Huber Basel F2 in Basel ANR Bezeichnung A3 Informatik A5 Personal Abt A3 A5 F3 in Zürich F4 in Zürich 84 Ebenso wäre eine vertikale Unterteilung denkbar gewesen, also eine Aufteilung nach bestimmten Spalten. Beispielsweise könnte eine Tabelle MITARBEITER alle Elemente wie oben enthalten, aber nicht Attribute wie Gehalt, Qualifikationsstufe, Entwicklungspotenzial, die der Verwaltung der Personalabteilung unterliegen und nur in deren lokaler Datenbank liegen. Zusammengenommen sollen alle Fragmente wieder den Gesamtdatenbestand des Unternehmens ergeben (auch Mischungen zwischen horizontaler und vertikaler Fragmentierung sind denkbar). Wenn später auf alle 4 Fragmente der horizontalen Aufteilung ein Zugriff mit einer beliebigen Abteilungsnummer erfolgen müsste, stellt sich dies dem Anwender als eine logische Einheit dar, die auch im SELECT keine Aufteilung erkennen lässt: SELECT Name, Bezeichnung FROM MITARBEITER, ABTEILUNG WHERE Abt = A# Motivation: Die meisten Unternehmen werden nicht ausschließlich zentral verwaltet. Bereits die anfallenden Daten sind zumeist verteilt. Eine zentrale Datenhaltung ist dann ein Schritt zurück. Ein Vorteil dezentraler Datenhaltung liegt darin, dass häufig lokal zugegriffen wird, wie in einer Bank mit vielen Zweigstellen. Die meisten Geldbewegungen und Nachfragen erfolgen extern. Ein weiterer Vorteil liegt in der Ausfallsicherheit. Falls das System keinen zentralen Server besitzt, wird der Ausfall eines beliebigen Rechners das Netz nicht vollständig lahm legen. Der zentrale Server als Achillesferse zentraler Systeme könnte das gesamte System blockieren. Fundamentales Prinzip verteilter Datenbanken: Ein verteiltes System sollte sich dem Anwender gegenüber genauso verhalten wie ein nichtverteiltes. Die zwölf Regeln von Date (zur Garantie des fundamentalen Prinzips) 1. Lokale Eigenständigkeit jedes Rechners 2. Keine zentrale Verwaltungsinstanz 3. Ständige Verfügbarkeit 4. Lokale Unabhängigkeit 5. Unabhängigkeit gegenüber Fragmentierung 6. Unabhängigkeit gegenüber Datenreplikation 7. Optimierte verteilte Zugriffe 8. Verteilte Transaktionsverwaltung 9. Unabhängigkeit von der Hardware 10. Unabhängigkeit von Betriebssystemen 11. Unabhängigkeit vom Netz 12. Unabhängigkeit von Datenverwaltungssystemen 85 1 Lokale Eigenständigkeit jedes einzelnen Rechners Jeder einzelne Rechner im verteilten System besitzt eine maximal (!) mögliche Autonomie. Dies bedeutet insbesondere, dass ein lokaler Zugriff auf lokal gespeicherte Daten nicht misslingen sollte, weil ein anderer Rechner momentan nicht zugreifbar ist. Dieses Verhalten garantiert Ausfallsicherheit, verlangt aber, dass alle lokal gespeicherten Daten auch lokal verwaltet werden. Dies impliziert auch die lokale Garantie von Integrität, Sicherheit und Transaktionsmechanismen. 2 Keine zentrale Instanz, die das System leitet und verwaltet Aus der lokalen Eigenständigkeit folgt direkt, dass es keine zentrale Instanz geben darf, welche die verteilte Datenbank verwaltet. Doch auch wenn die Regel 1 nicht voll erfüllt sein sollte, ist eine zentrale Verwaltung nicht wünschenswert. Das Gesamtsystem ist verwundbar, sei es, dass die zentrale Instanz ausfällt oder nur, dass dieser zentrale Server zum Engpass wird. 3 Ständige Verfügbarkeit In einem verteilten System sollte es nie erforderlich sein, aus Gründen der Datenbankverwaltung das gesamte System oder auch nur Teile davon gelegentlich abzuschalten. 4 Lokale Unabhängigkeit Mit lokaler Unabhängigkeit ist gemeint, dass der Benutzer nicht wissen muss, wo die einzelnen Daten gespeichert sind. Diese Regel erleichtert die Programmierung erheblich, da die gleichen Programme auf allen Rechnern der verteilten Datenbank ohne Anpassung ablaufen können. Diese Regel impliziert weiterhin, dass alle gewünschten Daten jederzeit auf jeden beliebigen Rechner zwecks weiterer Bearbeitung geholt werden können. 5 Unabhängigkeit gegenüber Fragmentierung Fragmentierung heißt, dass auch vorgegebene Dateneinheiten, etwa Relationen auf mehrere Rechner verteilt sein können wie im Einführungsbeispiel die Personaldatenbank in Zürich und Basel. Aus Performancegründen ist es empfehlenswert, die Mitarbeiterdaten der einzelnen Werke lokal zu halten, die Relation Personal also auf mehrere Rechner zu verteilen. Genau diese Möglichkeit fordert die Regel 5. Das Wort „Unabhängigkeit“ bedeutet, dass der Benutzer nicht merken soll, ob die Daten fragmentiert sind oder nicht. 6 Unabhängigkeit gegenüber Datenreplikation Datenreplikation bedeutet, dass Kopien von Daten auf mehreren Rechnern gleichzeitig gehalten werden dürfen. Dies verbessert sowohl die Performance, falls häufig auf die gleichen Daten lokal zugegriffen wird, als auch die 86 Verfügbarkeit. Der schwerwiegende Nachteil liegt auf der Hand: Werden die Daten in einer Kopie geändert, so müssen auch alle anderen Kopien angepasst werden. Die Verwaltung der Replikate bedingt einen hohen Aufwand und dies auch als alleinige Aufgabe des verteilten DB-Systems, das sich nach Aussage dieser Regel für den Benutzer genauso zu verhalten hat wie ein System, das Replikate nicht unterstützt. 7 Optimierte verteilte Zugriffe Zugriffsoptimierung ist in einem verteilten System viel wichtiger als in einem zentralen, da die Daten über (langsame) Netze transportiert werden müssen. Optimierung heißt, dass jeder einzelne Zugriff ohne Umwege erfolgen sollte, und dass die Anzahl der Zugriffe für eine Anfrage minimiert wird. Die Minimierung erfolgt besonders einfach mit relationalen Datenbanken. Beispielsweise erfordert die Anfrage in München, welche Artikel in Hamburg vorrätig sind, nur zwei Bewegungen. Die Anfrage in Hamburg und die Rückgabe der Ergebnisrelation nach München. 8 Verteilte Transaktionsverwaltung Auch in verteilten Systemen sind Transaktionen atomare Einheiten. Recovery und Concurrency müssen ebenso unterstützt werden. Eine Lösung könnte der 2Phasen-Commit sein mit globaler Kontrolle für ein globales Commit. Dies widerspricht aber der zweiten Regel. 9 Unabhängigkeit von der verwendeten Hardware Diese Forderung ist heute bereits Alltag. PC´s kommunizieren mit UNIXRechnern, UNIX-Rechner mit Großrechnern und Großrechner mit PC´s. Alle diese Rechner besitzen eine unterschiedliche Hardware-Plattform. 10 Unabhängigkeit von den verwendeten Betriebssystemen Diese Regel ist im Wesentlichen nur ein Unterpunkt der vorhergehenden. UNIX, MVS, BS2000, Windows, LINUX arbeiten einträchtig miteinander. 11 Unabhängigkeit vom verwendeten Netzwerk Dies gilt mittlerweile erst recht. 12 Unabhängigkeit von den Datenbankverwaltungssystemen Diese Regel ist nicht ganz so selbstverständlich wie die drei vorangehenden. Doch auch hier haben die DB-Hersteller mittlerweile zusammengefunden und haben einheitliche Schnittstellen etabliert wie z.B. CORBA, ODBC, JDBC und als Kommunikationssprache zwischen den Systemen SQL! 87 Es ist alles andere als einfach, alle 12 Regeln zu erfüllen, aber die meisten davon (insbesondere 5, 7, 12) können noch am besten durch relationale Datenbanksysteme verwirklicht werden, sodass eigentlich nur diese zur Verwirklichung verteilter Systeme in Frage kommen. Zum einen ist es heute Standard, mittels SQL zwischen unterschiedlichen DB-Systemen zu kommunizieren, aber auch die Fragmentierung kann durch Projektionen und Restriktionen (siehe Einführungsbeispiel mit horizontaler und vertikaler Fragmentierung) der Relationen gut erreicht werden. Dazu dient auch die „flache Struktur“ relationaler Datenbanken. Regel 7 wird insbesondere durch den Einsatz von SQL automatisch unterstützt. Probleme verteilter Datenbanken Die schon angesprochenen Probleme haben gemeinsam, dass zum Einen die Übertragungsgeschwindigkeit im Netz erheblich niedriger ist als der Zugriff auf lokale Speichermedien. Und zum Anderen müssen sich die einzelnen Rechner koordinieren, was das Netz weiter belastet. Leistungsfähige verteilte DB müssen daher immer unter dem Gesichtspunkt gesehen werden, dass sowohl die Menge der über das Netz übertragenen Daten als auch der Datenaustausch zwischen den Rechnern zu minimieren ist. Im Folgenden werden drei besonders drastische Probleme behandelt. Problem der Datenverwaltung In verteilten DB können gesuchte Daten über mehrere Rechner gestreut sein. Regel 4 verlangt, dass Programme nicht von vornherein davon ausgehen können, auf welchen Rechnern die gewünschten Daten zu finden sind. Es muss daher eine DB-Verwaltung existieren, die darüber Auskunft gibt. Diese Datenverwaltung unterliegt einigen Zwängen: Die Datenverwaltung sollte nicht auf einem fest vorgegebenen Rechner liegen, da sonst Regel 2 verletzt wird (bei Ausfall liegt sonst das ganze System lahm) Die Datenverwaltung sollte nicht als Kopie auf jedem Rechner vorliegen, da dies den Datenaustausch enorm erhöhen würde. Die lokalen Daten jedes einzelnen Rechners sollten nicht ausschließlich lokal verwaltet werden, denn jeder Zugriff auf entfernte Daten würde eine Suche im gesamten Rechnerverbund erfordern, um diese Daten zu lokalisieren. Lösung: Jedes Datum wird dem Rechner zugeordnet, wo es erstellt wurde. Diese Information ist in jedem angeschlossenen Rechner lokal verfügbar und wird erst beim Löschen des Datums wieder entfernt. Wird dieses Datum von irgendeinem 88 Rechner angefordert, so wendet sich dieser nach der lokalen Recherche an diesen angegebenen Rechner. Sollte das Datum inzwischen auf einen dritten Rechner migriert sein, so wird dieser Rechner darüber immer Bescheid wissen (maximal zwei Zugriffe, der „Heimatrechner“ ist immer informiert). Kein Verstoß gegen Regel 2 und es werden auch Replikatprobleme performant gelöst. Im Heimatrechner steht, wo Replikate zu finden sind, Replikatänderung muss durch Heimatrechner erlaubt werden (Vermerk der Änderung, alle anderen werden für ungültig erklärt). Der Heimatrechner übernimmt auch die Sperrverwaltung zur Vermeidung unerlaubter paralleler Zugriffe. Problem des globalen Transaktionsbetriebs Das Zwei-Phasen-Commit mit globalem Koordinator widerspricht der Regel 2. Lösung: Es bietet sich an, die globale Transaktion von dem Rechner durchführen zu lassen, der die Transaktion startete. Dies löst aber auch nicht alle Probleme, denn dies verletzt die lokale Eigenständigkeit der Regel 1, da die Rechner dann vom Koordinator abhängen. Damit bleibt zwar ein gewisses Unbehagen, aber Regel 1 ist seltenst vollständig erfüllt. Deshalb wurde auch nur von einer maximal möglichen Autonomie gesprochen. Problem der Minimierung des Netzverkehrs Die übertragenen Daten und Nachrichten müssen minimiert werden. Nötig sind geschickte Abfragestrategien, optimale Verteilungen und optimierte Protokolle. Bei der Abfrage von Daten ist es immer sinnvoll, eine Aktion dort auszuführen, wo die meisten für diese Abfrage benötigten Daten zu finden sind. Dann müssen nur noch die restlichen Daten transportiert werden. Um dies aber zu erfahren, müssten wieder Nachrichten ausgetauscht werden. Lösungsansätze: Eine optimale Verteilung ist dann gegeben, wenn die lokalen Zugriffe maximal sind. Es empfiehlt sich die Selbstverwaltung des Systems durch Replikate wie im ersten Problemfall. Die Daten werden immer dorthin transportiert, wo sie am häufigsten benötigt werden. Optimierte Protokolle reduzieren die Nachrichtenströme, wie das aussehen könnte wurde auch schon beim ersten Problem der Datenverwaltung beschrieben. Auch die Locks können mit der Replikatverwaltung gelöst werden, denn statt für jedes Replikat zwei Nachrichten zu benötigen (Anfordern und Gewähren) beschränkt sich dies nur noch auf insgesamt zwei Nachrichten, Anfordern beim HeimatRechner und dessen Gewährung. Erkennung rechnerübergreifender Deadlocks kann durch eine lokale Instanz nicht erkannt werden, da zentralisierte globale Lockverwalter nicht erwünscht sind wegen Regel 2, es müssen sehr komplexe Algorithmen eingesetzt werden, was somit keine optimale Lösung darstellt. 89 Zusammenfassung: Die Vorteile einer verteilten Datenhaltung entsprechen zwar eher den realen Gegebenheiten als eine zentrale Verwaltung (inklusiver höherer Ausfallsicherheit), der Aufwand ist aber enorm hoch. Die Praxis ist von der Einhaltung aller zwölf Regeln weit entfernt, i.a. werden doch gewisse Verletzungen der Regeln 1,2, 4 oder 6 in Kauf genommen. Unter diesen Einschränkungen sind marktführende Datenbanken z.B. DB2 von IBM, SQL*Star von ORACLE und INGRES/Star von Relational Technology. Insbesondere durch leistungsfähigere Netze können einige Probleme des erhöhten Nachrichtenaustauschs immer mehr wett gemacht werden. Übungsaufgaben 1) Was wird unter Unabhängigkeit gegenüber Fragmentierung und gegenüber Replikation verstanden? 2) Wie kann das Problem des erhöhten Datenaustauschs in verteilten Systemen minimiert werden? 3) Definieren Sie den Begriff „Verteilte Datenbanken“ 4) In verteilten Systemen kann es globale Deadlocks geben, können auch lokale Deadlocks auftreten? 5) Ist unter Verwendung eines Zwei-Phasen-Commit-Protokolls die Regel 2 erfüllbar, obwohl dafür ein zentraler Koordinator benötigt wird? 6) In einem kleinen Mehrbenutzer-DBMS existiere nur ein einziger Lock (globaler Datenbanklock). Kann in diesem System ein Deadlock überhaupt entstehen? 7) In einem Parallelbetrieb ist es nicht immer leicht zu sagen, ob eine Transaktion A vor oder nach einer Transaktion B ablief. Kann dieses Problem immer entschieden werden, wenn wir mit Sperrmechanismen arbeiten? 8) Warum ist die Trennung zwischen Administrator und Anwendern in Datenbanken so wichtig? 9) Welcher Nachteil kann sich beim Baumaufbau beim häufigen Ein- und Ausfügen in Bäumen einstellen? Wie kann man den Nachteil beseitigen? Welcher neue Nachteil stellt sich dann ein? 10) Wie unterscheidet sich eine relationale DB von nicht relationalen DB? 11) Wo liegen die Stärken und Schwächen eines hierarchischen DBSystems? 12) Erklären Sie die Begriffe „referenzielle Integrität“, „transitive Abhängigkeit“, „After Image“, „S2PL“, „globales Attribut“, „Invertierte Listen“, „B*-Baum“ 90 EXKURS: 12 Regeln für relationale Datenbanken (nach Codd) 1) Die Informationsregel 2) Garantierter Zugriff 3) Systematische Behandlung von fehlenden (NULL-) Werten 4) Integrierter aktiver Datenkatalog 5) Umfassende Datensprache 6) Datenmanipulation über logische Sichten 7) Mengenoperationen für Einfügen, Löschen, Ändern 8) Physische Datenunabhängigkeit 9) Logische Datenunabhängigkeit 10) Integritätsunabhängigkeit 11) Verteilungsunabhängigkeit 12) Unumgehbarkeit der Integritätsregeln 91 Sicherheit und Integrität Um Sicherheit zu gewährleisten, wird jeder Benutzer überprüft, ob er berechtigt ist, die Dinge zu tun, die er gerade versucht. Um Integrität zu gewährleisten, wird überprüft, dass die Dinge, die gerade versucht werden, auch korrekt ablaufen. Vor jedem Zugriff wird die Zugriffsberechtigung (Sicherheit) überprüft, beim Zugriff wird die Korrektheit (Integrität) kontrolliert (Integrer Datenbestand durch integre Personen). Sicherheit Sicherheit beginnt nicht erst beim DBMS: Beispiele Physische Aufstellung des Rechners, Personenkreis mit Zutrittsberechtigung, Netzanschluss, Betriebssystem- und Netzkennung, Passwörter, Chipkarte, hardwareunterstützter Speicherschutz, Verschlüsselung DBA + DBMS-Schritte: DB-Benutzerkennungen vergeben + Passwörter (für alles oder Teile der DB) Speicherung in Systemtabellen, Kontrolle durch DBMS Bei fehlender Zugriffserlaubnis: Zugriffsabweisung und Transaktionsabbruch Hinreichende Unterstützung durch SQL: Gewährung und Entziehung von Zugriffsrechten auf Tabellen und Sichten durch GRANT und REVOKE und die Erstellung geeigneter Sichten Der Benutzer, der einen CREATE-Befehl ausführt, ist automatisch Eigentümer des neu erzeugten Datenbankelements. Der Systemverwalter legt beim Erzeugen der DB fest, welche Benutzer das Privileg zum Erzeugen von Relationen haben. Da der Benutzer alle Rechte besitzt (auch für ALTER und DROP der Relationen), vergibt er mit dem GRANT-Befehl gezielt Zugriffsrechte an andere Benutzer und entzieht sie mit dem REVOKE-Befehl (wegen dieser umfassenden Rechte wird dies i.a. der Systemverwalter selbst sein). Grundsätzlich kann der Eigentümer keine Rechte vergeben, die den Aufbau von Relationen beeinflussen, für reine Zugriffsrechte ist der GRANT-Befehl ideal. (MS-ACCESS kennt diese Befehle nicht!) 92 Mittels GRANT-Befehl wird angegeben, welcher Benutzer auf welche Relation (Sicht oder Domäne) welche Zugriffsrechte erhält. GRANT Zugriffsrecht (oder ALL PRIVILEGES) ON TABLE Tabellenname (oder Sichtname) TO Benutzer WITH GRANT OPTION (zur Weitergabe von Rechten an einen Dritten) Beispiel: GRANT Select, Update (Gehalt, Vorgesetzt) ON Personal TO Perschef WITH GRANT OPTION REVOKE (eventuell GRANT OPTION FOR) Zugriffsrecht (oder ALL PRIVILEGES) ON TABLE Tabellenname FROM Benutzer (mit Zusatz RESTRICT zur Abweisung ,wenn die zu entziehenden Rechte auch an andere weitergegeben wurden oder CASCADE, wenn auch weitergegebene Rechte entzogen werden sollen) Da es keine Möglichkeit gibt, direkt mit GRANT nur Teile einer Relation (z.B. keine Gehälter, und keine Daten von Mitarbeitern, die Vorgesetzte sind) zu sperren, muss die Kombination gewählt werden, zunächst eine VIEW zu definieren und darauf den GRANT-Befehl anzuwenden. Erst dadurch ergeben sich „maßgeschneiderte“ Zugriffsrechte. Beispiel: CREATE VIEW Vpers AS SELECT Persnr, Name, Ort, Vorgesetzt FROM Personal WHERE Vorgesetzt IS NOT NULL Trotz dieser DB-Maßnahmen, muss auch dafür gesorgt werden, dass auch von der Betriebssystemebene keine Umgehung der Sicherheitsaspekte möglich wird (z.B. dass nicht mit Editoren auf DB-Daten zugegriffen werden kann). Um auch noch weitere Querzugänge auszuschließen wird in Großrechnerdatenbanken das Audit angeboten. Eine Audit-Einrichtung ist eine Protokollierung des gesamten Datenbankverkehrs. Für jeden durchgeführten Befehl werden die ausgeführten Änderungen, Datum, Uhrzeit, Benutzer und Netzadresse protokolliert, von wo der Befehl geschickt wurde. Die Identifizierbarkeit soll einen hohen „Abschreckungsgrad“ erzeugen. Allerdings gibt auch das natürlich keine 100prozentige Sicherheit und dies wird auch durch eine deutliche Einschränkung der Rechnerleistung erkauft, sodass die Audit-Einrichtung nur in besonders zu sichernden Datenbanken eingesetzt wird. 93 Integrität Integrität wird nicht nur durch Inkonsistenzen gefährdet, sondern auch an allen Stellen der Eingabe und Weiterverarbeitung insbesondere durch fehlerhafte Software oder falsche Eingaben durch Menschen. Integrität soll also auch gewährleisten, dass die DB-Daten mit den realen Gegebenheiten übereinstimmen. Erweiterte Integritätskonstrukte, um nicht nur Referenz- und Entitäts-Integrität zu gewährleisten, sondern auch beispielsweise Eingabefehler abzuwehren, werden erst ab SQL-2 Norm (1992) unterstützt. Damit gibt es folgende Möglichkeiten, um Integrität zu erreichen: Entitäts-Integrität Referenz-Integrität Eingabeüberprüfung auf Korrektheit (semantische Integrität) Zugriffsberechtigung Transaktionsbetrieb Entitäts- und Referenz-Integrität wird durch CREATE TABLE mit PRIMARY KEY und FOREIGN KEY ... REFERENCES unterstützt (insbesondere mit ON DELETE und ON UPDATE). Dies würde zwar auch durch Maßnahmen im Anwendungsprogramm möglich sein, was allerdings aufwändig und unsicher ist. Semantische Integrität kann in folgenden Schritten erreicht werden: 1. Der Benutzer kann nur über Bildschirmmasken Daten eingeben 2. Die Eingaben werden sofort auf das korrekte Format überprüft 3. Wann immer möglich, sollten Daten automatisch generiert werden 4. Überprüfung auf Korrektheit im DB-Anwendungsprogramm 5. Überprüfung auf Korrektheit im DBMS Der erste Schritt garantiert, dass nur an bestimmten Stellen Eingabe erfolgen kann, mittels des zweiten Schritts werden nur bestimmte Tasteneingaben akzeptiert. Durch den dritten Schritt werden bei neuen Tupeln Falscheingaben automatisch vermieden. In den Schritten 4 und 5 müssen nun weitere Plausibilitätsprüfungen stattfinden, die sich aber natürlich nur auf einen Teil möglicher Eingabefehler beschränken. Um dabei den Code des AW-Programms nicht unnötig aufzublähen, arbeitet man mit Triggerprogrammierung: Trigger sind (meist kleine) Unterprogramme, die bei bestimmten Ereignissen automatisch aufgerufen werden (damit Verlagerung komplexer Betriebsabläufe in die Datenbank). Wird beispielsweise in der Bildschirmmaske ein Eingabefeld geändert, so wird beim Verlassen des Feldes der entsprechende Trigger gestartet. Moderne Maskengeneratoren und praktisch alle Datenbanken (auch MSACCESS) unterstützen diese Art der Programmierung. 94 Syntaxaspekte des Trigger-Befehls: CREATE TRIGGER Triggername trigger_zeitpunkt ::= BEFORE | AFTER | INSTEAD OF trigger_ereignis ::= DELETE | INSERT | UPDATE [OF Spaltenliste] trigger_level ::= ROW | STATEMENT (Aufruf auf einzelne Zeilen bezogen oder auf Anweisungsebene auf Tabellen) [ORDER integer] ON Tabelle (Zahl legt Reihenfolge der Abarbeitung fest) [REFERENCES [OLD AS alt_name] [NEW AS neu_name] FOR EACH trigger_level [WHEN (Suchbedingung)] Block_anweisung Beispiel: Trigger, um unsinnige Gehaltsveränderungen zu verhindern CREATE TRIGGER Gehaltstest AFTER UPDATE OF Gehalt on Pers REFERENCES OLD AS altes Gehalt NEW AS neues Gehalt WHEN (neues Gehalt < altes Gehalt) ROLLBACK Das DBMS kann wesentliche Eigenschaften von Entitäten selbständig überprüfen. In SQL wird die semantische Integrität folgendermaßen unterstützt: Spalten und Tabellenbedingungen (CHECK) Allgemeine Bedingungen (CREATE ASSERTION) Gebietsdefinitionen (CREATE DOMAIN) Sichten (zusammen mit der Option WITH CHECK OPTION) Beispiele: ALTER TABLE Personal ADD CHECK (Gehalt BETWEEN 2000 AND 6000) ALTER TABLE Personal ADD CHECK (Gehalt + Zulage <= 8000) Mit CREATE ASSERTION ist es möglich, auch Bedingungen zu formulieren, die sich auf mehr als eine Relation beziehen Beispielsweise, um zu verhindern, dass der Produktionsabteilung hausintern ein Artikel nicht teurer verrechnet werden soll, als er auf Lager kostet: CREATE ASSERTION AssertPreis CHECK (NOT EXISTS (SELECT * FROM Auftragsposten, Teilestamm WHERE Auftragsposten.Teilenr = Teilestamm.Teilenr AND Gesamtpreis > Anzahl * Preis) Da bestimmte Tupelexistenzen verhindert werden sollen, beginnt die Syntax meistens mit dem Operator NOT EXISTS. 95 Löschen mit DROP ASSERTION Bedingungsname Domaindefinitionen sollte man nicht auf die Ebene der Integer oder CharacterFelder beschränken, beispielsweise, wenn eine Firma grundsätzlich nur Niederlassungen in Hauptstädten der EU hat: CREATE DOMAIN EU_Hauptstadt AS CHARACTER (15) CHECK (VALUE IN (´Berlin´, ´London´, ´Paris´, ´Rom´, ´Madrid´, ´Dublin´, ´Lissabon´, ´Amsterdam´, ´Brüssel´, ´Luxemburg´, ´Athen´, ´Kopenhagen´, ´Wien´, Helsinki´, ´Stockholm´); Löschung mit DROP DOMAIN Gebietsname {RESTRICT | CASCADE } Bei RESTRICT misslingt die Löschung, wenn noch Verweise darauf existieren, bei CASCADE werden auch Attribute von Sichten und Tabellen- oder Spaltenbedingungen gelöscht, die dieses Attribut referenzieren (gilt nicht für Tabellenattribute, die diesen Gebietsnamen verwenden, da werden die Checkbedingungen in die Basisrelationen durchgereicht) Weder ACCESS noch ORACLE kennen CREATE ASSERTION bzw. DOMAIN Ebenso ist bei ACCESS keine CHECK-Bedingung möglich, eine komplexe CHECK-Bedingung muss also entweder im AW-Programm selbst programmiert werden oder in SQL mit einer Sicht realisiert, die die CHECK OPTION Klausel verwendet. Die Preisbeschränkung würde dann so formuliert: CREATE VIEW Auftragspreis_intern AS SELECT * FROM Auftragsposten WHERE Gesamtpreis <= (SELECT Anzahl * Preis FROM Teilestamm WHERE Auftragsposten.Teilenr = Teilestamm.Teilenr) WITH CHECK OPTION Dabei muss sichergestellt sein, dass auf die Relation Auftragsposten nur über die Sicht Auftragspreis_intern zugegriffen werden kann, was weniger elegant ist als mit CHECK-Bedingungen. Integritätskonstrukte beschreiben, für welches Attribut einer Relation bei welchen Operationen (Insert, Update, Delete) welche Regeln zu beachten sind, und welche Aktion zu geschehen hat, wenn eine Regel verletzt wird. Transaktionen sind unerlässlich für die Integrität einer DB, ist die Integrität verletzt, muss auch die laufende Transaktion abgebrochen bzw. zurückgesetzt werden. Die Transaktion ist letzten Endes die kleinste Einheit für Recovery, Concurrency und Integrität. Da alle drei Begriffe aus einem korrekt laufenden Datenbankbetrieb nicht wegzudenken sind, ist ein (korrekter) Datenbankbetrieb zwangsläufig immer auch ein Transaktionsbetrieb. 96