300 80 4MB
German Pages 695 [696] Year 2014
Rainer Unland, Günther Pernul Datenbanken im Einsatz
Weitere empfehlenswerte Titel IT-Sicherheit Konzepte – Verfahren – Protokolle Claudia Eckert, 2014, 9. Auflage ISBN 978-3-486-77848-9, e-ISBN (PDF) 978-3-486-85916-4, e-ISBN (EPUB) 978-3-11-039910-3 Data Mining Jürgen Cleve, Uwe Lämmel, 2014 ISBN 978-3-486-71391-6, e-ISBN (PDF) 978-3-486-72034-1, e-ISBN (EPUB) 978-3-486-99071-3
Datenbanksysteme Eine Einführung Alfons Kemper, André Eickler, 2013, 9. Auflage ISBN 978-3-486-72139-3
Übungsbuch Datenbanksysteme Alfons Kemper, Martin Wimmer, 2011, 3. Auflage ISBN 978-3-486-70823-3
Rainer Unland, Günther Pernul
Datenbanken im Einsatz Analyse, Modellbildung und Umsetzung
Autoren Prof. Dr. Rainer Unland Universität Duisburg-Essen Fakultät für Wirtschaftswissenschaften Schützenbahn 70 45127 Essen [email protected] Prof. Dr. Günther Pernul Universität Regensburg Wirtschaftswissenschaftliche Fakultät Universitätsstr. 31 93053 Regensburg [email protected]
ISBN 978-3-486-72141-6 e-ISBN (PDF) 978-3-486-78129-8 e-ISBN (ePUB) 978-3-486-98970-0 Bibliografische Information der Deutschen Nationalbibliothek Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.dnb.de abrufbar. © 2015 Walter de Gruyter GmbH, Berlin/München/Boston Einbandabbildung: dreams3d/Shutterstock Druck und Bindung: CPI books GmbH, Leck ♾ Gedruckt auf säurefreiem Papier Printed in Germany www.degruyter.com
Rainer Unland möchte sich bei allen ehemaligen und aktuellen Mitarbeitern, insbesondere auch Herrn Dr. Hanenberg, für ihre angenehme und aufopferungsvolle Mitarbeit bedanken, ohne die der Lehrstuhl nie das hätte werden können, was er heute darstellt. Günther Pernul bedankt sich bei allen ehemaligen Mitarbeitern, die zur Entstehung des Buches beitragen konnten und den aktuellen Mitarbeitern Sabri Hassan und Stefan Meier, die auf Fehler in der 2. Auflage des Buches „Datenbanken im Unternehmen“ hingewiesen haben.
Vorwort Auch wenn Datenbankmanagementsysteme in der Forschungswelt zwischenzeitlich etwas in den Hintergrund gerückt sind, spielen sie in der Unternehmenswelt nach wie vor eine Schlüsselrolle. Unternehmen können sich nur dann am Markt behaupten, wenn sie eine straffe und gut organisierte Datenhaltung vorweisen. Zur Verwaltung des Datenbestandes kommt in der Regel moderne Datenbanksoftware zum Einsatz. Das vorliegende Lehrbuch bietet eine anwendungsorientierte Einführung in die Datenmodellierung und Datenbanktechnologie unter besonderer Berücksichtigung der Anforderungen von Unternehmen. Schwerpunkte des Buches sind deshalb hauptsächlich die Methoden, Konzepte, Sprachen und Komponenten, die einen effizienten Datenbankeinsatz gewährleisten. Das Buch setzt sich allumfänglich mit der Datenhaltung auseinander, was bedeutet, dass es mit der Analyse, der Modellbildung und den systemunabhängigen Entwurf von Datenbankanwendungen beginnt, um sich dann intensiv dem Einsatz und der Technologie von vorwiegend relationalen Datenbanksystemen zu widmen. Der Entwurf einer Datenbank (DB) wird typischerweise in mehrere Phasen unterteilt, die selbst wiederum durch unterschiedliche Aktivitäten strukturiert sind. In Kapitel 1 wird eine übliche Vorgehensweise für den Entwurfsprozess dargestellt. Seine einzelnen Phasen werden anhand des Lebenszyklus einer Datenbank identifiziert. Die systemunabhängigen Aktivitäten, die in diesen Phasen durchzuführen sind, werden in jeweils einem nachfolgenden Kapitel genau beschrieben. Des weiteren werden noch die wichtigsten Datenbankbegriffe eingeführt. Eine sorgfältige Erhebung und nachfolgende Analyse der Anforderungen der potenziellen Nutzer stellt die Grundvoraussetzung für die Entwicklung einer effizienten DB dar. Das Kapitel 2 beginnt mit einer Abgrenzung der Datenbankmanagementsysteme (DBMS) von Dateisystemen. Anschließend werden die unterschiedlichen Methoden der Anforderungserhebung erläutert. Ähnlich wichtig wie die sorgfältige und vollständige Erhebung der Anforderungen ist ihre übersichtliche Darstellung und die Analyse der Ergebnisse der Erhebung im Anforderungsdokument. Wir klassifizieren Anforderungen hinsichtlich ihrer Eigenschaften in die vier Typen Informationsanforderungen, funktionale Anforderungen, dynamische Anforderungen und Bearbeitungsanforderungen, zeigen unterschiedliche Methoden der Analyse und erläutern die Dokumentation der Anforderungen im Anforderungsdokument. Die im Anforderungsdokument enthaltenen Aufgaben und Vorgaben bilden die Grundlage für den konzeptuellen Datenbankentwurf. Das Kapitel 3 stellt den Schwerpunkt des 1. Teiles des Buches dar und widmet sich den unterschiedlichen Paradigmen des konzeptuellen Entwurfs einer Datenbank. Das Kapitel beginnt mit der Darstellung der strukturorientierten Modellbildung, einer Technik, die ausschließlich Informationsanforderungen nutzt. Weiter Raum wird dem Entity-Relationship-Modell (ERM) als De-facto-Standard für die konzeptuelle Modellbildung gewidmet. Neben den Basiskon-
VIII
Vorwort
strukten werden einige wichtige Erweiterungen sowie prominente Vertreter von „erweiterten“ ERM vorgestellt. Alle Modelle dieser Klasse beinhalten jedoch die Einschränkung, dass sie den Schwerpunkt der Analyse auf die Struktur der Daten legen und damit die funktionalen Anforderungen an die Datenbank überwiegend vernachlässigen. Es liegt also nahe, Informationsund funktionale Anforderungen aus dem Anforderungsdokument gemeinsam zu betrachten und in eine einheitliche Methode zu integrieren. Als zweites Paradigma der konzeptuellen Modellbildung betrachten wir die Kombination von struktur- und funktionsorientierter Modellbildung. Diese Vorgehensweise basiert auf einer schrittweisen Verfeinerung eines Funktions- und eines Datenmodells und hat den Vorteil, dass das konzeptuelle Datenmodell aus diesen beiden Sichten stufenweise herausgearbeitet werden kann. Dies führt dazu, dass die Struktur der Datenbank und die auf sie zugreifenden funktionsorientierten Programme sehr gut aufeinander abgestimmt sind und die Schnittstelle zwischen Datenbanksystem und Anwendungsprogrammen klein und übersichtlich gehalten werden kann. Aus objektorientierter Sichtweise sind die Komponenten eines informationstechnischen Systems seine Daten, seine Zustände und die Ereignisse, die Änderungen an Zuständen initiieren. Bei der objektorientierten Modellbildung werden alle drei Merkmale gleichberechtigt betrachtet und dem zentralen Konzept „Objekt“ zugeordnet. In Unterkapitel 3.3 diskutieren wir die wesentlichen Eigenschaften einer objektorientierten Vorgehensweise und erarbeiten ein integriertes Objektmodell, das neben den Aspekten, die bereits in den klassischen Modellen beinhaltet sind, auch Konzepte zur Modellierung von Verhalten zur Verfügung stellt. Objektmodelle nutzen daher auch dynamische Anforderungen aus dem Anforderungsdokument. Die Struktur des Kapitel 3 wurde nicht zufällig gewählt, sondern reflektiert die chronologische Reihenfolge, in der sich Wissenschaftler und Unternehmen gleichermaßen mit Methoden zur Analyse von betrieblichen Informationssystemen beschäftigt haben. Die Entwicklung von Methoden und Techniken scheint auch heute noch nicht vollständig abgeschlossen zu sein. Es entwickeln sich weiterhin neue Denkansätze. So rückte z. B. in den letzten Jahren die Analyse und Modellierung von Geschäftsprozessen als Basis für den Datenbankentwurf zunehmend in den Mittelpunkt der Betrachtung. Unterkapitel 3.4 fasst aktuelle Trends und weitere Ansätze zur konzeptuellen Modellbildung zusammen. Das Kapitel 3 wird noch durch zwei weitere Unterkapitel abgerundet: In Unterkapitel 3.5 wird das Gebiet der Sichtenintegration behandelt. Sichtenintegration wird notwendig, wenn ein unternehmensweites Datenmodell nicht als Ganzes, sondern durch Integration und Konsolidierung mehrerer Bereichsdatenmodelle entwickelt wird. Das Kapitel wird mit dem formalen Datenbankentwurf (Unterkapitel 3.6) abgeschlossen, einer Entwurfsmethode, die hauptsächlich zum Entwurf relationaler Datenbanken verwendet wird. Neben der Einführung des relationalen Datenbankmodells werden noch dessen Grundlagen erklärt. Für Leser, die in diese Materie tiefer einsteigen möchten, schließen wir das Themengebiet mit einer komprimierten Darstellung der Normalisierung relationaler Datenbanken ab. In den bisher geschilderten Phasen der Modellbildung war es möglich, ein konzeptuelles Datenmodell losgelöst von seiner späteren Implementation zu entwerfen. In Kapitel 4 behandeln wir den logischen Datenbankentwurf, eine Entwurfsphase, in der nun erstmals ein systemabhängiges Zielmodell entwickelt wird. Darunter wird die Repräsentation des Realweltausschnitts mit den Methoden und Techniken des zu Grunde liegenden Datenbankmodells
Vorwort
IX
verstanden. Als Ergebnis entsteht das konzeptuelle Datenbankschema. Wir werden uns in diesem Buch auf das relationale Datenbankmodell beschränken und zeigen, wie ein ERM in ein auf dem relationalen Datenbankmodell beruhendes konzeptuelles Datenbankschema transformiert werden kann. Ab Kapitel 5 widmet sich das Buch dem Datenbankeinsatz. Dabei geht es weniger um die interne Umsetzung und Arbeitsweise eines DBMS als vielmehr um die Frage, wie ein Benutzer bzw. eine Anwendung mit einem DBMS arbeiten kann. Die wichtigste Schnittstelle zur Anwendung stellen dabei zweifelsohne die Datenbanksprachen dar, zu deren wichtigsten Vertretern die Datendefinitions-, die Datenmanipulations- und die Anfragesprache gehören. Dementsprechend werden sie auch ausführlich und praxisnahe anhand des De-facto-Standards für relationale Datenbanksysteme, dem SQL-Standard diskutiert. Kapitel 5 gibt eine knappe Einführung in die grundsätzliche Architektur und Arbeitsweise eines DBMS. Dabei werden die einzelnen Punkte nur in so weit diskutiert, wie sie für das Verständnis des Hauptteils des Buches von Nutzen sind. Kapitel 6 widmet sich den Grundlagen von Anfragesprachen, wobei insbesondere auch Wert auf eine solide Theoriebildung gelegt wird. Erst das Verständnis der formalen Grundlagen einer Sprache wird es einem ermöglichen, die Qualität einer Sprache und damit ihre Stärken und Schwächen auch fundiert beurteilen zu können. Einem kurzen formalen Ausflug in die Welt der Typsysteme und Hilfsmittel zur Datenmodellierung folgt eine intensive Diskussion der Entwurfsprinzipien für (Datenbank-)Sprachen allgemein und Anfragesprachen im Besonderen. Obwohl entsprechende Entwurfsprinzipien schon seit einigen Jahrzehnten bekannt sind und diskutiert werden, werden manchmal immer noch gravierende Designfehler gemacht, die sich im praktischen Einsatz einer Sprache dann böse rächen können. Hier muss man schon zugeben, dass der Informatik gelegentlich noch die fundierte, nach festen Regeln erfolgende ingenieurwissenschaftliche Vorgehensweise beim Entwurf komplexer Systeme fehlt. Nach einer kurzen Diskussion von Sprachansätzen werden die beiden formalen Basisansätze vieler Anfragesprachen, die Relationenalgebra und die Relationenkalküle eingeführt. In diesem Kapitel wird einerseits Wert auf eine saubere Einführung der formalen Basiskonstrukte dieser Sprachen gelegt, andererseits wird aber auch versucht, dies so verständlich wie nur möglich zu tun, indem beispielsweise statt formaler mathematischer Notationen eine etwas sprechendere Formulierungsweise bei Anfragen gewählt wurde. Kapitel 7 widmet sich dem Einsatz von SQL, dem De-facto-Standard beim Zugriff auf relationale Datenbanksysteme. SQL feiert zwischenzeitlich auch schon je nach Sichtweise sein 45-jähriges Bühnenjubiläum (ursprüngliche Vorstellung der Idee durch Knuth Ende der 60er) oder zumindest aber fast 35-jähriges Bühnenjubiläum (erste Verfügbarkeit eines Produkte mit SQL im Namen durch IBM (SQL/DS 1981)), weshalb man dieser Sprache auch alle Höhen und Tiefen eines Sprachenlebens ansehen kann. Dem ersten noch vom Forschergeist angehauchten Prototypen folgte eine an den Pragmatismus der Praxis angepasste kommerzielle Variante, der einiges von der konzeptuellen Klarheit des Prototyps abhanden gekommen war. Zwischenzeitlich haben die Standardisierungsbemühungen um SQL zwar auch die Sprache wieder konzeptuell sauberer werden lassen, aufgrund von nicht mehr einfach auszuräumenden Altlasten konnte eine Sanierung aber nicht in voller Konsequenz gelingen. Das Buch präsentiert die für den Nutzer von SQL relevanten Konzepte dieser Sprache vergleichsweise ausführlich, wobei im Kern zunächst bewusst eine Abstützung auf den SQL-92
X
Vorwort
Standard erfolgt. Kommerzielle SQL-Dialekte weichen alle etwas mehr oder weniger von diesem Standard ab, sind andererseits aber in Bezug auf die Klarheit und Sauberkeit der Sprache am ehesten geeignet, den Ansprüchen einer nicht produktbezogenen Hochschulausbildung gerecht zu werden. Die drei Hauptteile dieses Kapitels widmen sich den wichtigsten Teilsprachen von SQL, der Datendefinitions-, der Datenanfrage- und der Datenmanipulationssprache, und zwar in dieser Reihenfolge. Gerade bei der Datendefinition wird sehr ausführlich auf das Typkonzept eingegangen, weil dieses erheblichen Einfluss auf eine sauber und konsistent modellierte Datenbank hat. Der Anfrageteil musste aufgrund seiner Mächtigkeit auch am längsten geraten. Es wurde versucht, die Darstellung durch möglichst viele Beispiele lesbar zu gestalten. Manchmal hilft ein Beispiel eher, ein Konzept zu beschreiben, als eine ausführliche verbale Diskussion. Zugriffsstrukturen sowie Datensicherheit, Datenintegrität und Datenschutz werden in diesem Buch nur sehr knapp behandelt. Der Grund liegt darin, dass diese Teile noch nicht oder erst teilweise standardisiert wurden. Eine Diskussion der grundsätzlichen Konzepte liegt aber außerhalb der Intention dieses Buches und soll daher anderer Literatur überlassen bleiben. Zum Abschluss dieses Kapitels wird noch kurz auf die Bearbeitung und Optimierung von Anfragen eingegangen. Auch wenn SQL eine deskriptive Anfragesprache ist, bei der eigentlich nur angegeben werden soll, was man gerne wissen möchte, sieht die Realität doch anders aus. Unterschiedliche Formulierungen des gleichen Sachverhaltes werden normalerweise auch zu unterschiedlich effizienter Ausführung einer Anfrage führen, so dass es sehr wohl immer noch wichtig ist, die Grundlagen einer Anfrageoptimierung zu verstehen. Spätestens mit der Einführung von Java hat die Objektorientierung massiv Einzug gehalten in die EDV. SQL und Objektorientierung sind jedoch zwei unterschiedliche Welten. Mit der Einführung von SQL-1998 Standards wurde der Versuch unternommen, auch die Objektorientierung in SQL umzusetzen. Der Standard hat hier einen großen Schritt nach vorne gemacht. In der Praxis hinken alle Dialekte aber mehr oder weniger stark hinterher. Vor allem Oracle hat aber bereits einen erheblichen Schritt in Richtung der Integration von objektorientierten Konzepten gemacht. Die immer komplexer werdenden Daten schreien auch nach angepassteren und effizienten Umsetzungskonzepten, so dass angenommen werden kann, dass mächtigere Datenbankmodelle zunehmend den Markt erobern werden. Das achte Kapitel widmet sehr ausführlich den objektrelationalen Erweiterungen von SQL, wie sie vor allem mit dem SQL1998 Standard eingeführt wurden. Zudem geht dieses Kapitel noch intensiver auf weitere wesentliche Änderungen ein, die seit dem SQL-92-Standard in der Sprache enthalten sind. Der aktuelle Standard ist die Version SQL:2011. Datenbanksysteme stehen einer Vielzahl von Benutzern und Anwendungen für eine parallele, aber voneinander isolierte Nutzung zur Verfügung. Die Parallelarbeit auf einem gemeinsamen Datenbestand muss aber korrekt synchronisiert werden, will man keine möglicherweise in Konsistenzverletzungen der Datenbank mündende Probleme in Kauf nehmen. Dieser Thematik und dem so wichtigen Gebiet der Fehlertoleranz widmet sich Kapitel 9. Auch hier trifft wieder zu, dass die dem Transaktionsmanagement zu Grunde liegenden Konzepte nur teilweise an der Schnittstelle des DBMS zu Tage treten. Viel läuft mehr oder weniger unsichtbar auf der internen Ebene ab. Trotzdem gilt auch hier, dass ein grundsätzliches Verständnis dieser Problematik den Umgang mit Datenbanksystemen erheblich vereinfachen und insbesondere auch sicherer machen kann. Neben den klassischen Themen wie die Synchronisation und das
Vorwort
XI
Recovery widmet sich dieses Kapitel am Ende noch weitgehenderen Konzepten, die langsam in kommerzielle Systeme Eingang finden, wie z. B. geschachtelten Transaktionen. Auch wenn sie wegen ihrer scheinbaren Komplexität nicht sehr beliebt ist – das solide Verständnis der einem Konzept oder allgemein einem System zu Grunde liegenden Theorie kann erheblich helfen, mit dem System effizient und zielgerichtet zu arbeiten. Deshalb haben wir uns in diesem Buch bemüht, trotz oder gerade wegen seines anwendungsorientierten Charakters auch immer dann Theorie einzustreuen, wenn sie zum Verständnis des Stoffes signifikant von Nutzen ist. Alle Kapitel folgen einem einheitlichen Aufbauschema. Jedes Kapitel wird mit einer Zusammenfassung und Angaben zu weiterführender Literatur abgeschlossen. Einige Kapitel und Unterkapitel, die uns als sehr wichtig erscheinen, sind am Ende mit Kontrollaufgaben ausgestattet. Da es sich um ein Lehrbuch handelt, wurde auch besonderer Wert auf viele und didaktisch sinnvolle Beispiele gelegt. Obwohl das Buch als eine Einheit konzipiert wurde, können die Teile Analyse und Modellbildung sowie Datenbankeinsatz auch unabhängig voneinander studiert werden. Das Buch richtet sich an Studierende, die als Unterstützung zu einer anwendungsorientierten Datenbankvorlesung eine Darstellung von relevanten Themen zum Datenbankeinsatz diskutieren möchten. Es richtet sich aber auch an interessierte Praktiker, die mit Datenbanken arbeiten (wollen) und/oder lernen möchten, wie man ein Datenbankschema als ein redundanzfreies Abbild eines Realweltausschnittes entwerfen kann. Durch seine konsequente Anwendungsorientierung ist das Buch insbesondere auf Vorlesungen zugeschnitten, wie sie in modernen Studienplänen des Studienganges Wirtschaftsinformatik, Wirtschaftsingenieurwesen oder der angewandten und praktischen Informatik angesiedelt sind. Dozenten, die dieses Buch als Grundlage für ihre Lehrveranstaltung in Erwägung ziehen, können von den Autoren Folienvorlagen bzw. Lösungen zu ausgewählten Kontrollaufgaben anfordern. Es gibt bereits eine Vielzahl von Büchern, die sich mit der Thematik Datenmodellierung und Datenbankmanagementsysteme beschäftigen. Viele dieser Bücher haben ihre eigenen Stärken, weshalb sie auch sehr empfehlenswert sind. Die Stärke des vorliegenden Buches ist seine Anwendungsorientiertheit und seine Zielrichtung hin zu Methoden und Techniken, die den effizienten Einsatz der Datenbanktechnik ermöglichen. Danksagung Das Schreiben eines Buches ist nicht nur eine Einzelleistung der Autoren, sondern die Leistung einer ganzen Gruppe von mit unterschiedlichsten Aufgaben befassten Personen. Die Autoren möchten sich bei allen Beteiligten recht herzlich für die angenehme und engagierte Mitarbeit bedanken und auch dafür, dass die weniger erquicklichen Stressphasen des Buchschreibens mit Humor und Verständnis beantwortet wurden. Zu den unverzagt engagierten konstruktiven Kritikern gehören vor allem unsere (ehemaligen) und aktuellen Mitarbeiter(innen). Besonders bedanken möchte sich Günther Pernul bei seiner Familie für die Geduld und das Verständnis für die diesem Buch geopferten Abende und Wochenenden. Beide Autoren gemeinsam möchten sich bei den Mitarbeitern von De Gruyter Oldenbourg für die Umsetzung des Buches und die jederzeit tatkräftige und hilfreiche Unterstützung bedanken.
XII
Vorwort
Kontakt Die inhaltliche Verantwortung für dieses Werk aber tragen alleine die Autoren. An sie möge man sich wenden, wenn Dinge zu kritisieren, Fehler zu bemängeln oder einfach nur Verbesserungsvorschläge zu machen sind. Wie in der heutigen Zeit üblich, gibt es auch zu diesem Buch eine WWW-Adresse (siehe unten). Hier werden Fehler unter Nennung der „Entdecker“ abgelegt. Geplant ist auch die Bereitstellung von Folien, Übungsaufgaben und Lösungen sowie weiterer Informationen und Dienste, die im Umfeld des Buches von Nutzen sein können. Essen und Regensburg im Oktober 2014 Rainer Unland und Günther Pernul WWW-Seiten • www.dawis.wiwi.uni-due.de • www-ifs.uni-r.de E-mail • [email protected] (Rainer Unland) • [email protected] (Günther Pernul)
Inhalt 1
Einleitung und Übersicht
1
1.1
Anforderungserhebung und -analyse .............................................................. 6
1.2
Konzeptuelle Modellbildung ......................................................................... 7
1.3
Logischer Entwurf ....................................................................................... 9
1.4
Implementationsphase.................................................................................. 9
1.5
Allgemeine Datenbankbegriffe.....................................................................10
1.6
Zusammenfassung ......................................................................................12
1.7
Literatur ....................................................................................................13
1.8
Kontrollaufgaben........................................................................................13
2
Anforderungserhebung und -analyse
2.1 2.1.1 2.1.2 2.1.3
Dateisystem vs. Datenbankmanagementsystem ..............................................18 Isolierte Dateiverwaltung.............................................................................19 Integrierte Dateiverwaltung..........................................................................19 Architektur von Datenbankmanagementsystemen...........................................21
2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6
Anforderungserhebung................................................................................26 Dokumentenanalyse....................................................................................26 Fragebogentechnik .....................................................................................28 Interviewmethode .......................................................................................29 Berichtsmethode ........................................................................................30 Selbstaufschreibung ....................................................................................30 Beobachtungsmethode ................................................................................30
2.3 2.3.1 2.3.2 2.3.3
Anforderungsdokument...............................................................................31 Informationsanforderungen..........................................................................33 Funktionale Anforderungen .........................................................................42 Bearbeitungsanforderungen und dynamische Aspekte .....................................57
2.4
Zusammenfassung ......................................................................................60
2.5
Literatur ....................................................................................................62
2.6
Kontrollaufgaben........................................................................................62
15
XIV
Inhalt
3
Konzeptueller Datenbankentwurf
65
3.1 3.1.1 3.1.2 3.1.3 3.1.4
Strukturorientierte Modellbildung ................................................................68 Grundlagen des Entity-Relationship-Modells .................................................69 Weiterentwicklungen des Entity-Relationship-Modells ...................................78 Literatur ....................................................................................................86 Kontrollaufgaben........................................................................................86
3.2 3.2.1 3.2.2 3.2.3
Struktur- und funktionsorientierte Modellbildung ...........................................89 Gründe für die Verwendung der Kombinationsmethode...................................89 Kombination von ERM und DFD .................................................................90 Kontrollaufgaben........................................................................................96
3.3 3.3.1 3.3.2
Objektorientierte Modellbildung ..................................................................96 Konzepte der Objektorientierung ..................................................................98 Unified Modeling Language (UML) ...........................................................101
3.4 3.4.1
Weitere Formen der Modellbildung ............................................................114 Geschäftsprozessorientierte Modellbildung..................................................115
3.5 3.5.1 3.5.2
Sichtenintegration und Schemakonsolidierung .............................................120 Prozess der Sichtenintegration....................................................................123 Kontrollaufgaben......................................................................................133
3.6 3.6.1 3.6.2 3.6.3 3.6.4
Formaler Datenbankentwurf ......................................................................134 Das relationale Datenbankmodell ...............................................................135 Grundlagen des formalen Datenbankentwurfs ..............................................141 Relationentheorie und Normalisierung ........................................................147 Kontrollaufgaben......................................................................................160
3.7
Zusammenfassung ....................................................................................165
3.8
Literatur ..................................................................................................166
4
Logischer Entwurf
4.1
Transformation von Entitytypen .................................................................170
4.2 4.2.1 4.2.2 4.2.3
Transformation von Beziehungstypen .........................................................171 Transformation rekursiver Beziehungstypen ................................................171 Transformation binärer Beziehungstypen.....................................................172 Transformation n-ärer Beziehungstypen ......................................................176
4.3
Transformation von Generalisierung und Subtypenhierarchie.........................178
4.4
Zusammenfassung ....................................................................................182
4.5
Literatur ..................................................................................................183
4.6
Kontrollaufgaben......................................................................................183
169
Inhalt
XV
5
Einführung in Datenbankmanagementsysteme
187
5.1 5.1.1 5.1.2
Architektur eines Datenbankmanagementsystems.........................................187 Die Schemaarchitektur ..............................................................................187 Die Systemarchitektur...............................................................................189
5.2
Die Verwaltung von Metadaten ..................................................................192
5.3
Literatur ..................................................................................................195
6
Grundlagen von Anfragesprachen
6.1
Formale Grundlagen von Datenbankmodellen..............................................197
6.2
Typen von Relationen ...............................................................................205
6.3
Anforderungen an Anfragesprachen............................................................207
6.4
Sprachansätze ..........................................................................................211
6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6
Relationale Algebra ..................................................................................214 Mengenoperationen ..................................................................................215 Zusätzliche relationale Operationen ............................................................219 Beispiele .................................................................................................232 Eigenschaften der Relationenalgebra ..........................................................234 Zusammenfassung ....................................................................................235 Literatur ..................................................................................................235
6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5
Relationenkalkül ......................................................................................237 Tupelkalkül..............................................................................................239 Bereichskalkül .........................................................................................249 Mächtigkeit der Relationenkalküle .............................................................254 Zusammenfassung ....................................................................................255 Literatur ..................................................................................................255
6.7
Funktionen auf Mengen von Tupeln............................................................256
6.8
Zusammenfassung ....................................................................................257
6.9
Kontrollaufgaben......................................................................................258
7
Die relationale Datenbanksprache SQL
7.1
Einführung in SQL ...................................................................................261
7.2 7.2.1 7.2.2 7.2.3 7.2.4 7.2.5 7.2.6
Die Datendefinitionssprache (DDL) ............................................................271 Anlegen einer Datenbank ..........................................................................271 Datentypen in SQL-92 ..............................................................................272 Anlegen einer Tabelle ...............................................................................295 Integritätsbedingungen ..............................................................................296 Umgang mit Beziehungstypen....................................................................311 Ändern des Datenbankschemas ..................................................................314
197
261
XVI
Inhalt
7.2.7 7.2.8
Beispiel eines Datenbankschemas für eine Unternehmung .............................317 Kontrollaufgaben......................................................................................324
7.3 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.3.7 7.3.8 7.3.9
Die Datenbankanfragesprache (DRL)..........................................................326 Die SELECT-Klausel (Projektion) ..............................................................327 Die FROM-Klausel (Ausgangstabelle) .........................................................339 Die WHERE-Klausel (Selektion) .................................................................364 Die GROUP BY-Klausel (Bilden von Untertabellen) ......................................373 Geschachtelte Anfragen ............................................................................385 Mengenoperationen in SQL .......................................................................401 Die ORDER BY-Klausel (Sortieren der Ergebnistabelle) ...............................404 Zusammenfassung ....................................................................................405 Kontrollaufgaben......................................................................................408
7.4 7.4.1 7.4.2 7.4.3
Die Datenmanipulationssprache (DML) ......................................................412 Einfügen von Zeilen .................................................................................413 Ändern von Zeilen ....................................................................................415 Löschen von Zeilen ..................................................................................417
7.5 7.5.1 7.5.2 7.5.3 7.5.4
Datensichten ............................................................................................418 Motivation ...............................................................................................418 Vorteile von Sichten..................................................................................423 Probleme mit Sichten ................................................................................424 Änderungen auf Sichten ............................................................................426
7.6
Die Datenkontrollsprache (DCL) ................................................................429
7.7
Die Speicherungsstrukturdefinitionssprache (SSL) .......................................436
7.8
Datenschutz, Datensicherung und Datenkonsistenz.......................................437
7.9
Kritische Würdigung von SQL-92 ..............................................................445
7.10
Charakteristika relationaler DBMS .............................................................448
7.11
Einbettung von SQL in Wirtssprachen (Embedded SQL)...............................450
7.12
Programmgeneratoren ...............................................................................454
7.13 7.13.1 7.13.2
Anfragebearbeitung und -optimierung.........................................................456 Anfragebearbeitung ..................................................................................457 Anfrageoptimierung..................................................................................460
7.14
Zusammenfassung ....................................................................................464
7.15
Literatur ..................................................................................................465
7.16
Kontrollaufgaben......................................................................................466
Inhalt 8
XVII Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
469
8.1
Struktur von SQL:2011 .............................................................................470
8.2 8.2.1 8.2.2 8.2.3 8.2.4
Datentypen und Typkonstruktoren ..............................................................473 Vordefinierte Datentypen ...........................................................................474 Typkonstruktoren .....................................................................................477 Individualisierte Datentypen (distinct data type) ...........................................493 Benutzerdefinierte strukturierte Datentypen bzw. benannte Zeilentypen ..........495
8.3 8.3.1 8.3.2 8.3.3 8.3.4 8.3.5 8.3.6 8.3.7 8.3.8 8.3.9 8.3.10
Objektorientierte Konzepte in SQL:2011 .....................................................502 Komplexe Objekte ....................................................................................503 Objektidentität .........................................................................................510 Datentypen / Klassen ................................................................................516 Datenabstraktion / Kapselung ....................................................................517 Vererbung ................................................................................................528 Polymorphismus.......................................................................................541 Anfragen im objektrelationalen SQL...........................................................544 Anmerkungen zu komplexen Objekten im objektrelationalen SQL .................550 Beispiel eines objektrelationalen Datenbankschemas für eine Unternehmung ..550 Zusammenfassung ....................................................................................559
8.4
Trigger ....................................................................................................560
8.5 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.5.6 8.5.7 8.5.8 8.5.9
Weitere Neuerungen im Überblick ..............................................................564 Benennung von SFW-Blöcken ....................................................................564 Rekursion ................................................................................................565 Datenschutz und Datensicherheit................................................................566 Online Analytical Processing (OLAP) .........................................................566 Sicherungspunkte .....................................................................................569 SQL/MM (Multimedia-Unterstützung) ........................................................569 SQL/MED (Management of External Data) .................................................570 Java Sprachanbindung...............................................................................571 Einbindung von XML-Dokumenten............................................................574
8.6
Literatur ..................................................................................................574
9
Transaktionsverarbeitung und Fehlertoleranz
9.1 9.1.1 9.1.2 9.1.3 9.1.4
Transaktionsmanagement ..........................................................................577 Probleme bei der Parallelarbeit auf der DB ..................................................578 Das Transaktionskonzept...........................................................................582 Serialisierbarkeit ......................................................................................584 Literatur ..................................................................................................592
9.2 9.2.1
Synchronisationsverfahren.........................................................................593 Klassifikation ...........................................................................................593
577
XVIII
Inhalt
9.2.2 9.2.3 9.2.4 9.2.5 9.2.6 9.2.7
Sperrverfahren .........................................................................................594 Zeitstempelverfahren ................................................................................607 Optimistische Synchronisationsverfahren ....................................................608 Synchronisation in SQL-92........................................................................613 TP-Monitor..............................................................................................615 Literatur ..................................................................................................618
9.3 9.3.1 9.3.2 9.3.3
Fehlertoleranz ..........................................................................................618 Fehler in Transaktionssystemen..................................................................620 Maßnahmen zur Fehlerbehandlung .............................................................622 Literatur ..................................................................................................637
9.4 9.4.1 9.4.2 9.4.3 9.4.4
Geschachtelte Transaktionen......................................................................637 Geschlossen geschachtelte Transaktion .......................................................641 Offen geschachtelte Transaktion .................................................................642 Entwicklungstransaktion ...........................................................................643 Literatur ..................................................................................................643
9.5
Kontrollaufgaben......................................................................................644
Literaturverzeichnis
647
Sachverzeichnis
663
1
Einleitung und Übersicht
Eine sorgfältige Erhebung der Anforderungen, ihre Analyse und eine nachfolgende Modellbildung ist eine Grundvoraussetzung für den Entwurf einer effizienten Datenbank (DB). Die während dieser Tätigkeiten durchzuführenden Aufgaben sind in der Regel komplexe, zeitaufwändige und somit auch kostenintensive Angelegenheiten. Dies ist darauf zurückzuführen, dass die geplante DB als Datenspeicher für unterschiedlichste Anwendungen fungieren wird und die Anforderungen verschiedenster, oft sehr heterogener Benutzergruppen erfüllen soll. Die Komplexität des Designvorganges ist des Weiteren darin begründet, dass die Entwurfsphase der DB ganz am Anfang des Lebenszyklus der Datenbankanwendung steht und daher bereits in einer so frühen Phase neben allen bekannten Anforderungen alle zukünftig wichtigen Anforderungen an das System erahnt werden müssen, um in Entwurfsentscheidungen entsprechend einfließen zu können. Auf alle Fälle ist es notwendig, beim Entwurf einer DB ausreichend technische Kompetenz zu besitzen und Sorgfalt walten zu lassen, da falsche Entwurfsentscheidungen oft starke Auswirkungen auf die Leistungsfähigkeit der DB haben und später nur mit sehr hohem Aufwand korrigiert werden können. Analyse und Modellbildung für die Entwicklung einer Datenbankanwendung beginnen mit der Erstellung einer Machbarkeitsstudie (Durchführbarkeitsstudie). Ergibt diese Studie, dass der Einsatz eines Datenbanksystems (DBS) zielführend ist, so erfolgt vorerst eine sorgfältige Anforderungserhebung und -analyse. Anforderungen werden in Anforderungsdokumenten festgeschrieben, die die Aufgabe haben, als Grundlage für die Erstellung einer gemeinsamen abstrakten Darstellung, einer Konzeptualisierung aller Daten (konzeptuelles Datenmodell), die eventuell in der DB verwaltet werden, zu dienen. Für eine bestimmte Datenbankanwendung kann es unterschiedliche konzeptuelle Modelle geben, da verschiedene Entwerfer in einem Entwurfsteam die Realität möglicherweise unterschiedlich sehen und ihre Schwerpunkte auf unterschiedliche Ereignisse legen oder zur Modellbildung verschiedene Konzepte verwenden können. Anforderungsanalyse und die Erstellung eines konzeptuellen Modells einer DB sind systemunabhängige Aktivitäten. Darunter verstehen wir, dass es für diese Phasen des Datenbankentwurfes vollkommen unerheblich ist, welche Datenbanksoftware später zum Einsatz kommen wird. Die nächste Entwurfsphase wird als logisches Design bezeichnet und besteht aus der Transformation des konzeptuellen Datenmodells in ein Zielmodell, das so genannte Implementationsmodell oder auch das logische Datenmodell. Diese Aktivität ist bereits teilweise systemabhängig, da sie vom Datenmodell der ausgewählten Datenbanksoftware beeinflusst ist. Fast alle am Markt befindlichen Datenbankprodukte bieten die Funktionalität, mit einfachen Methoden die Beschreibung des logischen Datenmodells einer DB zu implementieren, physische Optimierung am Implementationsmodell vorzunehmen und das physische Datenbankschema auf die Anwendungen abzustimmen. Dieser Vorgang wird in der Regel als physisches Design bezeichnet und führt zu einem physischen Datenmodell.
2
1 Einleitung und Übersicht
Der Begriff „Datenmodell“ wurde jetzt bereits mehrmals erwähnt und es erscheint notwendig, auf diesen Begriff näher einzugehen (siehe auch unter 1.6). Unter einem Modell versteht man ein immaterielles Abbild einer Realität unter Verwendung vorgegebener Strukturierungsprinzipien. Ein Datenmodell ermöglicht es, für alle Anwendungen eine gemeinsame Basis zu schaffen und damit die Datenorganisation sämtlicher Anwendungen eines Unternehmens zu vereinheitlichen. Unter Verwendung der vom Datenbankmodell zur Verfügung gestellten Strukturierungsprinzipien ist vom Datenbankentwerfer während der Analyse und Modellbildung der Aufgaben des zu entwickelnden DBS im Einzelnen festzulegen: • Was bedeuten die Begriffe des betrachteten Realitätsausschnittes? Welche Beziehungen bestehen zwischen Begriffen? Wie sind bestehende Daten strukturiert? • Welche gemeinsamen Eigenschaften kennzeichnen die Objekte, die mittels der eingeführten Begriffe benannt werden? Wie sind diese Eigenschaften beschrieben? • Welche Begriffe bilden zentrale Komponenten einer Anwendung und können zu Objekttypen oder Beziehungstypen zusammengefasst werden? • Welche konsistenzgewährleistenden Einschränkungen (Integritätsbedingungen) sind bekannt und können zur Vervollständigung der Datendefinition formuliert werden? Welche Operationen können auf Objekttypen ausgeführt werden, welche Zustände und Ereignisse sind bekannt, welche betrieblichen Vorgänge sollen modelliert werden? Ein konzeptuelles Datenmodell wird verwendet, um eine gemeinsame abstrakte Beschreibung aller Daten, die eventuell in der DB verwaltet werden, zu erreichen. Konzeptuelle Datenbankmodelle werden auch semantische Datenbankmodelle genannt, da sie die Mächtigkeit besitzen, einen Großteil der Semantik des zu modellierenden Realitätsausschnittes im Modell abzubilden. Im Gegensatz dazu stehen Implementationsmodelle oder logische Datenbankmodelle. Hierbei handelt es sich um Modelle, die von Datenbankprodukten als Schnittstelle zum Nutzer hin zur Verfügung gestellt werden. Zielführend ist es jedoch stets, für konzeptuelle Modellbildung ein mächtiges semantisches Datenbankmodell mit einer Vielzahl von Strukturierungsmöglichkeiten einzusetzen und sich nicht bereits vorab zwingend für ein bestimmtes logisches Datenbankmodell zu entscheiden. Während ein Datenmodell ausschließlich die Beschreibung der Struktur der Daten enthält, bietet ein Funktionsmodell Mechanismen zur Modellierung von betrieblichen Abläufen und Prozessen, die die Abläufe steuern. Einen Schritt weiter gehen integrierte Modelle. So wird z. B. in integrierten Objektmodellen die strukturorientierte und die funktionsorientierte Sichtweise auf ein betriebliches Informationssystem in einem einheitlichen Modell integriert. Objektmodelle bieten darüber hinaus auch noch die Möglichkeit, für Objekte bestimmte Zustände und Bedingungen für Zustandsübergänge zu formulieren. Der Entwurf einer DB ist gewöhnlich ein iterativer Prozess, der oft auf „trial and error“ beruht. In der wissenschaftlichen Literatur gibt es keine einheitliche Meinung darüber, wie der Entwurfsprozess einer DB exakt in einheitliche Teilaktivitäten gegliedert werden kann. Vielmehr ist es der Fall, dass einzelne Entwurfsaktivitäten nicht streng sequenziell abgearbeitet werden, sondern eng miteinander verzahnt sind. In der gängigen Praxis hat sich eingebürgert, den Designvorgang in vier Hauptaktivitäten zu gliedern:
1 Einleitung und Übersicht
3
1. Anforderungserhebung und -analyse 2. Konzeptuelle Modellbildung 3. Logischer Entwurf 4. Implementationsphase (physisches Design) Begleitend zu den Entwurfsaktivitäten sollen ständig Verifikations- und Validationstechniken eingesetzt werden. Das bedeutet, dass das Ergebnis eines Entwurfsschrittes auf Korrektheit geprüft, also verifiziert werden soll, bzw. dass es validiert wird, d. h. es sollte geprüft werden, ob es als Spezifikation auch tatsächlich alle Anforderungen korrekt und vollständig wiedergibt. Diese phasenbegleitenden Aktivitäten zur Qualitätssicherung sind meist bewährte Methoden aus dem Bereich des Software Engineerings. Hier können zum Einsatz kommen: 1. Formale Verifikation Die eingesetzten Datenbankmodelle basieren meist auf einer klaren mathematischen Semantik, die es ermöglicht, sowohl manuelle als auch computerunterstützte Verfahren zur formalen Spezifikation und nachfolgender Verifikation einzusetzen. 2. Experimentelles Prototyping Vor der endgültigen Implementierung sollen potenzielle Nutzer unter Verwendung von realen Daten an einem eingeschränkten Prototyp die Richtigkeit des Systementwurfs evaluieren. 3. Statistisches Testen Unter Verwendung künstlich erzeugter oder realer Testdaten kann am Prototyp eine Überprüfung der Richtigkeit des Entwurfs mit Hilfe statistischer Testverfahren erfolgen. Ähnlich wie die Verifikation und die Validation ist auch die Dokumentation des Entwurfsprozesses sowie die Erstellung der Dokumentation des DBS eine Aktivität, die parallel zum gesamten Datenbankentwicklungsprozess erfolgen sollte. Eine gute Dokumentation ist für den laufenden Betrieb und die nachfolgende Wartung der DB von großer Bedeutung, da die in dieser Phase anfallenden Kosten die ursprünglichen Entwurfskosten in der Regel übersteigen. Es ist ratsam, schon in der Entwurfsphase durch saubere Dokumentation aller Entwurfsentscheidungen für die Möglichkeit einer leichten Modifikation des DBS vorzusorgen. In Abbildung 1.1 zeigen wir den Entwicklungszyklus einer Datenbankanwendung. Er beginnt mit der Durchführbarkeitsstudie, einer Vorstudie, die Kosten- und Effizienzüberlegungen, Entscheidungen zu verschiedenen Systemkomponenten und weitere Grundlagenentscheidungen enthält, aus denen hervorgeht, dass der Einsatz eines DBS das richtige technische Realisierungskonzept für die Problemstellung darstellt. Während der Anforderungserhebung und -analyse werden in Zusammenarbeit mit Benutzern Tätigkeitsfelder und zu lösende Probleme des Informationssystems analysiert und in einem Anforderungsdokument zusammengefasst. Dem folgt die eigentliche Modellbildung, die zentrale Aufgabe während des Datenbankentwurfs. Mittels Tools kann im Rahmen des Entwurfsprozesses ein vereinfachter, ineffizienter Prototyp der gewünschten DB werkzeugunterstützt erstellt und vom Benutzer evaluiert werden. Herrscht Konsens über den Systementwurf, folgt die Implementation der DB und nach
4
1 Einleitung und Übersicht
Abb. 1.1: Entwicklungszyklus einer Datenbankanwendung
einer Testphase der Datenbankeinsatz. Eine nachfolgende Wartungsphase umfasst neben der Fehlerbehandlung auch die Anpassung der DB an veränderte Bedingungen. Jede der Hauptphasen des Datenbankentwurfsprozesses besteht wiederum aus mehreren unterschiedlichen Schritten, von denen jeder für sich allein betrachtet in der Literatur mehr oder weniger gut dokumentiert ist. Aus mehreren Gründen ist es jedoch nicht einfach, eine systemunabhängige, durchgängige Methode für alle vier Hauptaktivitäten und die involvierten Schritte zu entwickeln:
• Unterschiedliche Entwurfsphasen verwenden oft verschiedene Datenmodelle. Eine durchgängige Methode muss daher Abbildungsvorschriften von Modell A nach Modell B beinhalten.
1 Einleitung und Übersicht
5
Abb. 1.2: Phasen des Datenbankentwurfs
• Jedes Datenbankmodell unterstützt möglicherweise unterschiedliche Modellierungskonzepte und -mechanismen, und es ist schwierig, die unterschiedlichen Konzepte in verschiedenen Modellen zu vereinheitlichen. • Logischer Entwurf und physisches Design der DB sind systemabhängig. Während der logische Entwurf vom Typ der ausgewählten Datenbanksoftware abhängig ist, ist das physische Design in vielen Fällen sogar produktabhängig. Die Bindung an bestimmte Produkte macht es fast unmöglich, für die späten Phasen der Datenbankentwicklung allgemein gültige Aussagen zu treffen und eine einheitliche Entwurfsmethode vorzuschlagen. Beim Entwurf einer DB müssen zumindest zwei unterschiedliche Sichtweisen auf ein Anwendungssystem berücksichtigt werden. Wie in Abbildung 1.2 dargestellt ist, besteht der Entwurf einer DB vorerst aus zwei parallelen Aktivitäten. Die beiden Aktivitätsstränge repräsentieren zwei unterschiedliche Sichtweisen auf die in der DB abzubildende Realität. Die eine Sichtweise bezieht sich hauptsächlich auf die Struktur der Daten. Die zweite Sichtweise sieht ein DBS aus dem Blickwinkel der Anwendungen und stellt die gewünschte Funktionalität des Systems in den Vordergrund. Abhängig davon, welche der beiden Sichtweisen favori-
6
1 Einleitung und Übersicht
siert wird, bezeichnet man den Datenbankentwurfsvorgang als eher „strukturorientiert“ oder als eher „funktionsorientiert“. Beide Aspekte sollten bei der Entwicklung einer DB jedoch gleichrangige Bedeutung besitzen, was der Forderung nach einer integrierten Entwurfsmethode eindringlich Nachdruck verleiht. Der Entwurf einer DB wird von einem Datenbankentwurfsteam oft in Zusammenarbeit mit Domänenexperten durchgeführt. In der Folge wollen wir auf die durchzuführenden Aktivitäten im Rahmen der Datenbankentwicklung ein wenig genauer eingehen.
1.1
Anforderungserhebung und -analyse
Die Erhebung und Analyse der Anforderungen an die DB kann als Spezialfall einer generellen Anforderungsanalyse beim Softwareentwurf betrachtet werden. In dieser Phase erfolgt die Abgrenzung des Anwendungsbereiches der DB. Die Anforderungserhebung und -analyse orientiert sich vor allem am Informationsbedarf der zukünftigen Nutzer. Sie beginnt mit der Befragung ausgewählter Nutzer, der Niederschrift ihrer Anforderungen und der Analyse des Informationsbedarfs. Während dieser Entwurfsphase erstellt der Datenbankentwerfer ein Anforderungsdokument, in dem sowohl Anforderungen an die Struktur der Daten, Bearbeitungsanforderungen als auch Anforderungen, die an das Eintreten bestimmter Ereignisse geknüpft sind, eingetragen werden. Jeweils abhängig vom betrachteten Sachverhalt, lassen sich die folgenden unterschiedlichen Teilschritte der Erstellung eines Anforderungsdokumentes feststellen: • Strukturanalyse Die benötigten Daten und Informationseinheiten (gekennzeichnet durch eng miteinander in Bezug stehende Daten) werden erarbeitet. Danach folgen ihre Gruppierung in Klassen, die Bestimmung ihrer Eigenschaften und die Aufstellung von Beziehungen zwischen Informationseinheiten. • Funktionsanalyse Die Funktionssicht eines Anwendungssystems kann auf unterschiedlichen Abstraktionsebenen betrachtet werden. Oberste Verdichtungsstufe sind Geschäftsprozesse, während elementare Bearbeitungsfunktionen den höchsten Detaillierungsgrad einer entsprechenden Vorgangskette beschreiben. • Transaktionsanalyse Sofern bereits bekannt, werden die Bearbeitungsanforderungen der wichtigsten Transaktionen beschrieben. Dazu gehören ihr Ein- und Ausgabeverhalten, die Häufigkeit ihrer Anwendung sowie Querverweise auf ihre Bezugsdaten. Viele der wichtigen Datenbankanfragen und Datenmanipulationsoperationen (Transaktionen) sind bereits zum Entwurfszeitpunkt der DB bekannt. Während der frühen Phasen im Entwurfslebenszyklus einer DB gilt es, diese Sachverhalte genau zu spezifizieren und die funktionalen Eigenschaften zu Grunde liegender Transaktionen zu analysieren. Die Analyse der möglichen
1.2 Konzeptuelle Modellbildung
7
Transaktionen ist für die Erstellung des konzeptuellen Datenmodells nur von geringer Bedeutung, liefert aber für den physischen Entwurf und die physische Organisation der DB wertvolle Informationen. Die Analyse der Bearbeitungsanforderungen und der Entwurf des physischen Datenbankschemas sind systemabhängige Aufgaben, die oft auch durch die Auswahl eines bestimmten Datenbankproduktes beeinflusst sind. Im Rahmen dieses Buches werden wir auf Bearbeitungsanforderungen und den physischen Entwurf eines Datenbankschemas aus diesem Grund nur am Rande eingehen. Angesichts der Menge der erhobenen Eigenschaften der Realität ist bei der Anforderungserhebung und -analyse Rechnerunterstützung wünschenswert oder sogar notwendig. Das Ergebnis der Anforderungsanalyse ist eine Anzahl individueller Anforderungsdokumente. Jedes Dokument spezifiziert die Anforderungen einer bestimmten Benutzergruppe und besteht hauptsächlich aus Anforderungen an die Struktur der Daten sowie aus allgemeinen Anforderungen zur Realisierung der Geschäftsprozesse des betrachteten Unternehmens. Die individuellen Anforderungen der einzelnen Nutzergruppen können sehr unterschiedlich sein. Alle Anforderungen zusammen repräsentieren das unternehmensweite Anforderungsdokument. Der Vorgang der Anforderungserhebung und -analyse ist völlig systemunabhängig. In Kapitel 2 schildern wir unterschiedliche Techniken der Anforderungserhebung und zeigen, wie unterschiedliche Formen von Anforderungen im Anforderungsdokument dargestellt werden können. Ebenso werden in diesem Kapitel die wesentlichen Unterschiede zwischen Dateiverwaltungssystemen und DBS dargestellt, um im Rahmen einer Vorstudie festzustellen, ob ein DBS oder ein Dateisystem zur Realisierung der Anwendung eingesetzt werden soll.
1.2
Konzeptuelle Modellbildung
Die Hauptaufgabe der konzeptuellen Modellbildung ist es, alle individuellen Anforderungen aus den Anforderungsdokumenten in einer einheitlichen Spezifikation zu repräsentieren. Dazu bedient man sich der Beschreibungsmittel eines semantischen Datenmodells. Das Ergebnis der konzeptuellen Modellbildung ist ein semantisches oder konzeptuelles Datenbankschema, das systemunabhängig und allgemein gehalten ist und daher in den meisten Fällen nicht direkt unter Verwendung eines DMBS implementiert werden kann. Um ein konzeptuelles Datenmodell zu entwerfen, reicht es nicht aus, alle Anforderungen zu sammeln und direkt im konzeptuellen Schema zu repräsentieren. Die Sachlage ist um einiges komplizierter, da einerseits Benutzer gleiche oder ähnliche Dinge der Realität unterschiedlich sehen und somit im Anforderungsdokument unterschiedlich beschreiben und andererseits unterschiedliche Entwerfer denselben Sachverhalt unterschiedlich modellieren. Es gibt noch weitere Konfliktursachen, auf die wir in Kapitel 3 näher eingehen werden. Folgende Vorgehensweise bei der Erstellung eines konzeptuellen Datenmodells ist zielführend: Zuerst wird jedes individuelle Anforderungsdokument in ein semantisches Schema transformiert. Dieses Schema repräsentiert für jede Anwendergruppe eine ihr gemäße Sicht auf die Datenbasis. Ein Schema, das eine lokale Sicht beschreibt, wird auch als externes Datenbankschema oder externe Sicht bezeichnet. In einem zweiten Schritt werden die
8
1 Einleitung und Übersicht
unterschiedlichen Sichten zu einem konzeptuellen Schema zusammengefasst, wobei Überlappungen konsolidiert, Konflikte zwischen externen Schemata und Homonyme (ein und derselbe Bezeichner für unterschiedliche Sachverhalte) sowie Synonyme (ein Sachverhalt der Realität trägt unterschiedliche Bezeichner) in Bezug auf die Benennungen bereinigt werden. Diesen Vorgang bezeichnet man auch als Sichtenintegration. In manchen Entwurfsprojekten ist man sich schon im Vorhinein darüber im Klaren, dass als Ergebnis des Datenbankentwurfs eine relationale DB entstehen soll. Für kleinere und übersichtliche Anwendungen ist es möglich, ohne Verwendung eines semantischen Datenmodells ein relationales Datenbankschema direkt zu entwerfen. Die relationale Datenbanktheorie kennt den Vorgang der Normalisierung, mit dem ein relationales Datenmodell entworfen werden kann, die Güte eines Entwurfs überprüft und ein relationales Datenbankmodell, falls notwendig, verbessert werden kann. Obwohl das Verfahren der Normalisierung ausschließlich für relationale DB entwickelt wurde und daher in unserer Klassifikation eine systemabhängige Tätigkeit darstellt, reihen wir dieses Modellierungsverfahren unter konzeptuelle Modellbildung ein, da es möglich ist, dieses Konzept in leicht abgeänderter Form im Kontext anderer Datenmodelle ebenfalls anzuwenden. Kapitel 3 ist ausschließlich der konzeptuellen Modellbildung gewidmet. Dort werden wir uns hauptsächlich mit dem wichtigsten Vertreter der semantischen Datenmodelle, dem EntityRelationship-Modell (ERM) und seinen Erweiterungen beschäftigen. Die ausschließliche Verwendung des ERM zur konzeptuellen Modellbildung bevorzugt die strukturorientierte Sicht auf die Datenbankanwendung. Die Funktionssicht eines Anwendungssystems kann unter Verwendung der Modellierungskonzepte des ERM nicht dargestellt werden. Da die funktionalen Aspekte beim Datenbankentwurf jedoch nicht vernachlässigt werden dürfen, stellen wir nach der rein statischen Modellbildung (strukturorientierte Modellbildung) eine Entwurfsmethode vor, die sowohl die statischen als auch die funktionalen Aspekte einer Anwendung beim Entwurf eines konzeptuellen Datenbankschemas berücksichtigt. Obwohl diese Methode viele Vorteile gegenüber einer rein statischen Analyse besitzt, ist sie nur als eine Art Zwischenschritt hin zur Verwendung integrierter Objektmodelle zu sehen, da Verhaltensfragen und Ereignisabläufe mit ihr nur bedingt modelliert werden können. In diesem Kapitel schlagen wir dann noch als dritte Entwurfsmethode die Verwendung integrierter Objektmodelle vor, die auch die dynamischen Aspekte einer Datenbankanwendung in ein konzeptuelles Modell integrieren. Die Entwicklung von Methoden und Techniken zum konzeptuellen Datenbankentwurf ist noch nicht abgeschlossen. Des Weiteren kommen in diesem Bereich auch „allgemeine“ Methoden der Systemplanung und -analyse zum Einsatz, da es nicht möglich ist, eine genaue Abgrenzung zwischen den Methoden zum konzeptuellen Datenbankentwurf und denen einer allgemeinen Systemplanung vorzunehmen. In diesem Kapitel weisen wir auf aktuelle Trends hin, wie z. B. die Entwicklung unternehmensweiter Datenmodelle aufgrund der Analyse bestehender Geschäftsprozesse. Abschließend behandeln wir noch ausführlich die Methode der Sichtenintegration und die des formalen Datenbankentwurfs unter Verwendung der Normalisierungstheorie.
1.3 Logischer Entwurf
1.3
9
Logischer Entwurf
Ein konzeptuelles Datenmodell kann nur in den wenigsten Fällen direkt in das Datenbankmodell des zur Verfügung stehenden DBS implementiert werden. Der logische Entwurf einer DB hat die Übersetzung des semantischen Schemas der konzeptuellen Modellbildung in ein logisches Datenmodell zur Aufgabe. Das Ergebnis eines logischen Entwurfs sollte möglichst nahe der Datendefinitionssprache (data definition language, DDL) des ausgewählten Datenbankproduktes sein. In Kaptitel 4 werden wir uns bei den logischen Datenmodellen auf das relationale Datenmodell beschränken und zeigen, wie ein ERM in ein relationales Datenmodell transformiert werden kann.
1.4
Implementationsphase
Liegt das logische Datenmodell vor, so kann unter Verwendung der Datendefinitionssprache des eingesetzten DBS das Datenmodell implementiert und die DB erstellt werden. Datenbankdefinitionssprachen unterscheiden sich von Produkt zu Produkt in Syntax, Semantik und Benutzerschnittstelle. Jedoch ist ihre Funktionalität immer ähnlich. Sobald die Relationenschemata angelegt sind, wird der Datenbankadministrator die Zugriffsrechte für einzelne Nutzer (-gruppen) festlegen und möglicherweise auch virtuelle Tabellen (views) anlegen, um für bestimmte Benutzer den Zugriff auf sensitive Daten zu verhindern oder aber auch, um komplexere Abfragen zu vereinfachen. Viele Datenbankprodukte lassen ihr Leistungsverhalten optimieren. Das Dilemma der Benutzer und Systemadministratoren besteht jedoch oft darin, die Werte der Einstellparameter festlegen zu müssen, ohne tiefere Kenntnisse von der Systemrealisierung zu besitzen. Oft ist es notwendig, die gewählten Einstellparameter nach einer gewissen Probephase und nach Beobachtung des Leistungsverhaltens der DB zu korrigieren. Das Erzielen der gewünschten Antwortzeit ist auch oft eine Gratwanderung zwischen einer guten Antwortzeit für bestimmte Transaktionen und einem akzeptablen Arbeiten aus der Sicht der Gemeinschaft aller Nutzer. Während der Implementationsphase legt der Datenbankadministrator Primärindizes an, um Eindeutigkeit zu gewährleisten oder Sekundärindizes, um Zugriffspfade vorzubereiten und damit die Antwortzeit bestimmter Abfragen zu beschleunigen. In dieser Phase werden auch die Anwendungsprogramme geschrieben, die die geforderte Funktionalität der Datenbankanwendungen gewährleisten. Der letzte Schritt vor der ersten Inbetriebnahme der DB besteht im Laden oder Erfassen der Daten. In den meisten Fällen sind bereits Datenbestände vorhanden, die noch in ein bestimmtes Datenformat konvertiert werden müssen. Die meisten Datenbankprodukte bieten dazu Hilfsprogramme an. Sobald die Daten geladen sind und eine Testphase durchlaufen wurde, kann mit dem Benutzerbetrieb begonnen werden. Danach beginnt bereits die Wartungsphase, in der versucht wird, etwaige Entwurfsfehler zu korrigieren bzw. die DB aufgrund einer sich geänderten Realität für neue Anforderungen zu adaptieren. Auf die Wartungsphase und die damit in Zusammenhang stehenden Methoden des Reverse- bzw. Re-Engineerings von DB kann in diesem Buch aus Platzgründen nicht eingegangen werden.
10
1 Einleitung und Übersicht
Abb. 1.3: Entwurfsphasen, Daten- und Datenbankmodelle
Abbildung 1.3 zeigt in grafischer Form den Zusammenhang zwischen den unterschiedlichen Entwurfsphasen und gibt exemplarisch Modelle an, die die Aktivitäten während dieser Phasen unterstützen.
1.5
Allgemeine Datenbankbegriffe
Um zu einem ersten einheitlichen Verständnis der in diesem Buch verwendeten Terminologie zu gelangen, werden wir in diesem Abschnitt in loser Reihenfolge häufig verwendete Begriffe voneinander abgrenzen und in kurzer Form erklären. Eine detaillierte Definition der Begriffe folgt in den Kapiteln, in denen die entsprechenden Themengebiete genauer behandelt werden. Datenmodell1 Hierbei handelt es sich um eine formale Beschreibung des zu modellierenden Ausschnittes der 1 Leider ist der Begriff Datenmodell semantisch überladen. Einerseits wird damit das mit den gegebenen Mitteln eines spezifischen Werkzeuges zusammengesetzte Modell von etwas Gegebenen bezeichnet, andererseits aber eben auch das Werkzeug selber, also die Beschreibung der grundlegenden Konzepte, mit deren Hilfe das „Vorbild“ modelliert werden kann. Hier wird der Begriff Datenmodell immer im eigentlichen Sinne des Wortes verwendet,
1.5 Allgemeine Datenbankbegriffe
11
Realität, wobei die strukturorientierte Betrachtungsweise dominiert. Gegenstand der Betrachtung sind die Struktur der Daten, Beziehungen innerhalb der Daten, Klassenbildung, gültige Wertebereiche und weitere Integritätsbedingungen. Funktionsmodell Ein Funktionsmodell beschreibt eine Datenbankanwendung aus der Sicht der Datenbankfunktionen und der involvierten Prozesse auf unterschiedlichen Abstraktionsniveaus. Auf dem obersten Niveau werden Geschäftsprozesse betrachtet, die im Einklang mit den betrieblichen Zielen einen oft komplexen Ablauf, von seiner Entstehung bis zu seiner Beendigung, beschreiben. Ist ein hoher Detaillierungsgrad erwünscht, so erfolgt eine Zerlegung der einzelnen Abläufe in Teilfunktionen bzw. bis hin zu elementaren Bearbeitungsfunktionen. Funktionsmodelle unterstützen die funktionsorientierte Sicht auf ein Anwendungssystem. Integriertes Objektmodell In einem integrierten Objektmodell findet eine gemeinsame Betrachtung von Daten und der auf den Daten ausführbaren Funktionen statt. Neben der Modellierung von statischen Strukturen erfolgt hier auch die Verhaltensmodellierung. Dabei werden die nötigen Abläufe und Ereignisse beschrieben, die Objekte des Informationssystems zur Veränderung ihres Zustandes veranlassen. Datenbank (DB) Unter einer DB versteht man einen logisch integrierten Datenbestand, der unter Verwendung eines DBMS verwaltet wird und mit Hilfe eines Datenmodells beschrieben ist. Datenbankmodell Ein Datenbankmodell besteht aus einer vorgegebenen Menge genau festgelegter Modellierungskonzepte, mit denen ein Datenmodell einer Anwendung erstellt werden kann. Jedes DBMS unterstützt ein Datenbankmodell. Das heute gebräuchlichste Datenbankmodell ist das relationale Datenmodell. Datenbankschema Ein Datenbankschema ist eine maschinell verarbeitbare Formulierung eines Datenmodells. Datenbankmanagementsystem (DBMS) Ein DBMS (auch Datenbanksoftware) ist eine Sammlung von Programmen zur Erzeugung und Instandhaltung einer DB. Die Hauptaufgabe eines DBMS besteht in der Verwaltung der Daten, der Sicherung der Integrität, der Gewährleistung von Systemsicherheit und Fehlertoleranz und der Synchronisation konkurrierender Zugriffe im Mehrbenutzerbetrieb. Datenbanksystem (DBS) Ein DBS besteht aus einem DBMS und einer konkreten DB. Die Formulierung des Schemas dieser DB ist das Ziel des Datenbankentwurfsprozesses. Involvierte Berufsgruppen Datenbankdesigner sind für den Entwurf einer DB verantwortlich. In den frühen Entwurfsphasen werden sie durch Systemanalytiker unterstützt. Systemanalytiker erheben die Benutzeranforderungen und spezifizieren die Funktionalität von Datenbankoperationen. Systemanalytiker arbeiten eng mit den Datenbankprogrammierern zusammen. Diese erstellen aufgrund also im Sinne der ersten Definition. Ist das Werkzeug gemeint, spezifizieren wir den Begriff weiter, sprechen also beispielsweise von dem relationalen Datenmodell.
12
1 Einleitung und Übersicht
der Spezifikation der Systemanalytiker Programme, die dann die erhobenen Benutzeranforderungen erfüllen sollen. Datenbankadministratoren übernehmen die technische Verwaltung des DBS. Sie sind für die Abstimmung von logischem Datenmodell und physischer Datenorganisation verantwortlich, legen Benutzer an, vergeben Zugriffsrechte und führen die Datensicherung durch. Datenbanknutzer Bei den eigentlichen Nutzern des DBS kann man schließlich auch unterschiedliche Klassen feststellen. Gelegentliche Nutzer benutzen das DBS eher selten. Sie haben in den meisten Fällen unterschiedliche, aber oft recht komplexe Anfragen an die DB, die oft von Datenbankprogrammierern vorbereitet werden. Bei gelegentlichen Nutzern handelt es sich meist um Mitarbeiter aus dem mittleren bis höheren Management einer Organisation. Der Großteil der Nutzer greift jedoch auf vorgefertigte Transaktionen zurück (parametrische Nutzer), die ausschließlich auf einem vordefinierten Datenbereich operieren. Die Transaktionen werden wiederholt in unveränderter Form, aber mit sich ändernden Eingabeparametern ausgeführt. Ein Beispiel für diese Kategorie von Nutzern sind z. B. Schalterbeamte in Banken, Reisebüromitarbeiter an Flugreservierungssystemen oder Autovermieter. Erfahrene Benutzer haben meist recht komplexe Anforderungen an die DB und sind im Umgang mit dem interaktiven Teil der Datenbankabfragesprache geübt. Sie sind ständig darauf bedacht sich weiterzubilden und besitzen Detailwissen über die Struktur der DB. Oft haben sie auch Programmierkenntnisse. Datenbanksprache Die Datendefinitionssprache (data definition language, DDL) wird zur Definition des logischen Schemas einer DB verwendet. Die Datenmanipulationssprache (data manipulation language, DML) unterstützt Kommandos für die Durchführung von Abfrage-, Einfüge-, Löschund Datenveränderungsoperationen. Es gibt Systeme, in denen die DML in eine Abfragesprache (data retrieval language, DRL) und die eigentliche Manipulationssprache gegliedert ist. Des Weiteren existieren DBMS, die über DDL und DML hinaus noch über eine weitere Subsprache zur Definition des internen Datenbankschemas (storage definition language, SDL) oder über eine Sichten-Definitions-Sprache (view definition language, VDL) zur Definition externer Datenbanksichten verfügen. Gelegentlich ordnet man auch noch die Vergabe von Zugriffsrechten einer eigenen Sprache (data control language, DCL) zu. Transaktion Darunter versteht man eine Folge von Datenbankoperationen, die logisch eine Einheit bilden und als Einheit vollständig und fehlerfrei ausgeführt werden müssen. Können sie das nicht, muss das DBMS die von der Transaktion durchgeführten Änderungen zurücksetzen.
1.6
Zusammenfassung
Der Entwurf einer DB ist ein iterativer Vorgang, der aus mehreren eng miteinander verzahnten Teilaktivitäten besteht. Er beginnt mit der Erstellung einer Durchführbarkeitsstudie und einer nachfolgenden sorgfältigen Anforderungserhebung und -analyse. Daran schließt sich die konzeptuelle Modellbildung an, die eine Konzeptualisierung aller vom DBMS verwalteten Daten zum Ziel hat. Die nächste Phase besteht aus dem logischen Entwurf, einer Abbildung des konzeptuellen Datenmodells in das Zielmodell. Bevor das Datenmodell und die Anwen-
1.7 Literatur
13
dungsprogramme implementiert werden, soll die Güte des Entwurfs anhand eines Prototypen evaluiert werden. Nach der Implementation und einer Testphase kommt es zum Datenbankeinsatz, an den unmittelbar die Wartungsphase anschließt. Begleitend zu allen Phasen des Entwurfs sollen Verifikations- und Validationstechniken zum Einsatz kommen und alle Entwurfsentscheidungen vollständig dokumentiert werden.
1.7
Literatur
Zur Beschreibung einer sinnvollen Vorgehensweise für den Datenbankentwurf und der Beschreibung des Entwicklungszyklus einer DB wird in der Literatur auf Vorgehensmodelle für den Softwareentwicklungsprozess zurückgegriffen. Die meisten dieser Ansätze gehen auf Boehm [Boeh76] zurück, der die Phasen Analyse, Design, Implementierung, Test und Wartung vorschlägt. Die Phasen müssen sequenziell durchlaufen werden, und jede Phase endet mit der Erstellung eines Abschlussberichtes. In den frühen Versionen dieses als Wasserfallmodell bekannten Ansatzes waren Rückkopplungen zwischen aufeinander folgenden Entwicklungsphasen noch nicht vorgesehen. Als eine Erweiterung des Wasserfallmodells wurde 1986 wiederum von Boehm [Boeh86] das Spiralmodell vorgeschlagen, das eine iterative Vorgehensweise beinhaltet, in der die unterschiedlichen Entwurfsphasen mehrere Male durchlaufen werden. Schleifen im Entwicklungsprozess werden immer dann notwendig, wenn Anforderungen sich nachträglich verändern oder wenn durchgeführte Entwicklungsschritte nicht zu zufrieden stellenden Ergebnissen geführt haben. Ein Beispiel für ein Vorgehensmodell, das Entwicklungszyklen für den gesamten Entwicklungsprozess vorsieht, ist die prototypingorientierte Softwareentwicklung, wie sie z. B. in [PoBl96] vorgeschlagen wird. Vorschläge für weitere Phasenmodelle, insbesondere solche zur objektorientierten Entwicklung von Informationssystemen, können aus den Büchern entnommen werden, die in den Quellenangaben zu Kapitel 2 und Kapitel 3 angeführt sind. Bücher bzw. Übersichtsartikel, die den früheren Phasen im Lebenszyklus einer DB entsprechend Raum widmen, sind in der Datenbankliteratur nicht sehr zahlreich vorhanden. Empfehlenswerte Ausnahmen sind z. B. [BaCN92], [LaLo95], [MaDL87], [Teor98] oder [NaPe92]. Von besonderer Bedeutung für die Wirtschaftsinformatik sind u. a. [BöFP96], [MBKP00], [MMMO93], [FeSi98], [Rauh90] oder [RaSt97]. Zu den Begriffen „Modell“, „Modellbildung“ und „Daten“ siehe [LeHM95].
1.8
Kontrollaufgaben
Aufgabe 1.1: Motivation für die Modellbildung Warum besitzen Analyse und Modellbildung im Rahmen der Entwicklung einer Datenbankanwendung so große Bedeutung? Geben Sie Beispiele für die Wichtigkeit einer unternehmensweit konsolidierten Datenbasis an. Aufgabe 1.2: Aktivitäten beim Datenbankentwurf Nennen Sie die Hauptaktivitäten sowie alle Ihnen bekannten begleitenden Aktivitäten, die im Rahmen des Entwurfs einer DB durchgeführt werden sollen. Welche weiteren Phasen sind noch im Entwurfszyklus einer DB enthalten?
14
1 Einleitung und Übersicht
Aufgabe 1.3: Systemabhängige und -unabhängige Entwurfsphasen Welche der Entwurfsphasen einer DB sind systemunabhängig, welche sind systemabhängig und welche Phasen sind durch den Einsatz bestimmter Datenbankprodukte bestimmt (produktabhängig)? Aufgabe 1.4: Abgrenzung wichtiger Entwurfsphasen Grenzen Sie die Entwurfsphasen „konzeptuelle Modellbildung“ und „logisches Design“ voneinander ab. Geben Sie Modelle an, die in diesen Phasen eingesetzt werden können. Aufgabe 1.5: In die Datenbanknutzung involvierte Berufsgruppen Nennen Sie unterschiedliche Berufsgruppen, die in die Erstellung und Nutzung einer DB involviert sind. Aufgabe 1.6: Abgrenzung wichtiger Datenbankbegriffe Grenzen Sie die Begriffe Datenmodell, Datenbankmodell, DB, Datenbankschema, DBS und DBMS voneinander ab.
2
Anforderungserhebung und -analyse
Der Realisierung einer Datenbankanwendung geht zuallererst eine Durchführbarkeitsstudie (Vorstudie) voraus, in der geklärt werden muss, ob der Einsatz eines DBMS zielführend ist, oder ob die Anwendung unter Verwendung eines anderen technischen Realisierungsmittels erstellt werden soll. Bevor diese Frage geklärt werden kann, ist es notwendig, zumindest einen Teil der Nutzeranforderungen zu erheben und einer ersten Analyse zu unterziehen. Während der Anforderungserhebung und -analyse werden in Zusammenarbeit mit den zukünftigen Nutzern Tätigkeitsfelder und zu lösende Probleme des Informationssystems analysiert und in einem Anforderungsdokument niedergeschrieben. Eine wesentliche Voraussetzung für eine erfolgreiche Anforderungserhebung und -analyse ist ein gemeinsames Vorgehen von Systemanalytikern und ausgewählten Nutzervertretern (partizipative Systemanalyse), und damit verbunden eine starke Einbindung der vom Systemeinsatz Betroffenen am eigentlichen Entwicklungsprozess. Dies empfiehlt sich aus folgenden Gründen: • Der partizipative Systemansatz führt bei den zukünftigen Anwendern zur Akzeptanzsteigerung, da sie unmittelbar in den Entwurfsprozess eingebunden sind und Entwurfsentscheidungen aktiv mitbestimmen können. • Das Fachwissen der Anwender fließt in Entwurfsentscheidungen ein. Expertenwissen muss nicht extern eingekauft werden. • Die Kommunikation zwischen Systemanalytikern und Anwendern wird vereinfacht. Anforderungen an ein DBS können auf verschiedene Art und Weise klassifiziert werden. Mögliche Klassifikationskriterien für Anforderungen sind z. B. die Benutzergruppe (Programmierer, Sachbearbeiter, Topmanagement usw.), die sie aufgestellt hat oder der Grad der Abhängigkeit einer Anforderung von einem bestimmten System (Betriebssystem, Informationssystem, Kommunikationssystem). Klassifiziert man nach der Art der Anforderung, kann man zumindest vier Arten von Anforderungen unterscheiden: • Informationsanforderungen Hierunter fallen alle statischen Informationsbeschreibungen, welche das betreffende DBS im späteren Betrieb verwalten wird. Informationsanforderungen umfassen z. B. Angaben über Daten, Realweltobjekte und deren Typen, die Daten charakterisierenden Eigenschaften bzw. Attribute und deren Wertebereiche, Beziehungen und Abhängigkeiten zwischen
16
2 Anforderungserhebung und -analyse Daten und Objekten sowie allgemeine Integritätsbedingungen, über welche die Konsistenz einer DB definiert wird.
• Funktionale Anforderungen Sie beschreiben betriebliche Vorgänge und involvierte Datenflüsse auf unterschiedlichen Verdichtungsstufen. Oberste Verdichtungsstufe und damit Ausgangspunkt der Betrachtung sind Geschäftsprozesse, die einen komplexeren betrieblichen Ablauf von seiner Entstehung bis hin zu seiner Beendigung auf einem hohen Abstraktionsniveau beschreiben. Auf einer tieferen Abstraktionsebene werden betriebliche Abläufe in elementare Arbeitsschritte (Prozesse) gegliedert und der Input- und Outputdatenfluss zwischen Prozessen beschrieben. • Dynamische Anforderungen Realweltobjekte durchleben während der Existenz ihrer Entsprechung in der DB (Datenbankobjekt) unterschiedliche Zustände. Der Wechsel von einem Zustand in einen anderen ist an das Eintreten bestimmter Ereignisse gebunden (Auslösebedingungen). Dynamische Anforderungen repräsentieren den Lebenszyklus von Datenbankobjekten in Form von Zuständen und Ereignissen. Wenn sich ein Datenbankobjekt in einem bestimmten Zustand befindet, und ein Ereignis eintritt, so kann es zu einem Zustandswechsel kommen. Dynamische Anforderungen bringen Ereignisse und Zustände zueinander in Relation. • Bearbeitungsanforderungen Sie beinhalten die verfügbaren Informationen über Transaktionen, die auf den Daten des DBS ausgeführt werden sollen, z. B. Operationen wie Anfragen oder Updates, Auswertungen oder Berichterstellungen. Daneben sind Informationen darüber zu sammeln, wie häufig die Transaktionen ausgeführt werden sollen, ob zwischen einzelnen Operationen gewisse Reihenfolgen einzuhalten sind, oder allgemeiner, welche Abhängigkeiten zwischen den Transaktionen bestehen (z. B. Prioritäten), und welches Datenvolumen von den einzelnen Prozessen benötigt wird. Zu den Bearbeitungsanforderungen gehören insbesondere auch Aussagen über die Anzahl der zu erwartenden Nutzer, Informationen hinsichtlich des Grades ihrer unterschiedlichen Anforderungsprofile und damit verbunden auch Aussagen über die Verfügbarkeit oder die Sicherheit der Daten in der DB.
Beispiel 2.1: Unterschiedliche Arten von Anforderungen Wir betrachten unterschiedliche Arten von Anforderungen aus dem Anwendungsgebiet Einkauf und Lagerhaltung eines typischen Handelsbetriebes. Informationsanforderungen beschreiben die statischen Eigenschaften z. B. eines Lagerartikels. Von Interesse sind u. a. die Artikelnummer, die Artikelbezeichnung, Daten über den Lieferanten, die physische Lokation des Artikels im Hochregallager, der aktuelle Lagerbestand, die kritische Lagermenge, etwaige Ersatzlieferanten (falls der bisherige Lieferant in Lieferverzug kommt), preis- und kostenbezogene Informationen, Termine, Lieferbedingungen und möglicherweise weitere Informationen mit Bezug zum Einkauf und zur Lagerhaltung. Funktionale Anforderungen beschreiben betriebliche Vorgänge, wie z. B. die Auswahl eines neuen Lieferanten. So könnte es sein, dass bevor ein Auftrag an einen neuen Lie-
2 Anforderungserhebung und -analyse
17
feranten vergeben wird, die Qualifikation, der Service und die Liefersicherheit des Lieferanten geprüft und mit Konkurrenzangeboten verglichen wird. Funktionale Anforderungen beschreiben die einzelnen Vorgänge im Detail, die innerhalb des Geschäftsprozesses „Lieferantenwahl“ anfallen. Nehmen wir an, es kommt zu einem Geschäftsabschluss, und wir bestellen bei dem neu gewählten Lieferanten. Die einzelnen Zustände von Objekten des Typs „Bestellung“ und Ereignisse, die Zustandsübergänge verursachen, werden als dynamische Anforderungen beschrieben. Die Geschäftsbeziehung zwischen dem betrachteten Handelsbetrieb und dem Lieferanten wird vorerst im Zustand „Angebot“ sein. Wenn man sich zur Bestellung entschlossen hat (das Ereignis tritt ein), wird das Objekt „Angebot“ seinen Zustand in der DB ändern und in den Zustand „Bestellung“ übergehen. Abhängig von bestimmten Ereignissen wird die Bestellung die Zustände „bestätigte Bestellung“, „Bestellung in Bearbeitung“ usw. annehmen, um schließlich nach dem Ereignis „Beladen des LKW abgeschlossen“ in den Zustand „Lieferung“ überzugehen. Auch im Zustand „Lieferung“ wird es wieder unterschiedliche Subzustände und entsprechende Ereignisse geben, die als Teil der dynamischen Anforderungen im Anforderungsdokument spezifiziert werden. Als Beispiel einer Bearbeitungsanforderung betrachten wir das Aktualisieren des Lagerbestandes nach Eintreffen der Lieferung. Diese Datenbankoperation ist Teil einer komplexen Transaktion, die u. a. den Bereich Wareneingangsprüfung der Einkaufsabteilung, die Bereiche Wareneingang, Verbindlichkeiten-Lieferant der Finanzbuchhaltung und diverse Kostenstellen im Lager betrifft. Für die Operation „Erhöhe Lagerbestand“ sind folgende Teile der Bearbeitungsanforderungen von Bedeutung: eine detaillierte Beschreibung der Eingaben (Artikelnummer, Liefermenge, Datum der Lieferung, Lieferantenbezeichnung), der Ausgabedaten (Lagerbestand), der anfallenden Rechenoperationen (Lagerbestand = Lagerbestand + Liefermenge), die Häufigkeit der Anwendung der Operation (z. B. fünfmal täglich) und Querverweise zu Bezugsdaten (Artikelnummer muss bereits in der DB existieren, Lieferantenbezeichnung muss in der Lieferantendatei bereits eingetragen sein).
Abbildung 2.1 zeigt eine grafische Darstellung der unterschiedlichen Arten von Anforderungen. Die Zuordnung einer Anforderung zu einer bestimmten Anforderungsklasse ist nicht immer eindeutig. Insbesondere die Grenzen zwischen funktionalen und dynamischen Anforderungen sind fließend und hängen vom subjektiven Betrachtungsstandpunkt des jeweiligen Analytikers ab. Informationsanforderungen und funktionale Anforderungen stellen die wichtigsten Klassen von Anforderungen dar, die den systemunabhängigen Teil des Entwurfs einer Datenbankanwendung beeinflussen. Dynamische Anforderungen zeigen das zeitabhängige Verhalten der DB und sind für den Entwurf des statischen Datenbankschemas von untergeordneter Bedeutung. Für die Erstellung von Programmen, die auf die Daten zugreifen, ist das dynamische Modell dagegen sehr wichtig, da es die Reihenfolge von Interaktionen und damit den zeitlichen Ablauf von Operationen festlegt. Die Auswertung von Bearbeitungsanforderungen liefert die Grundlage für den physischen Entwurf der DB und soll helfen, zwei prinzipielle Fragen zu klären. Einerseits soll entschieden werden, ob sich die Datenbankanwendung mit der zur Verfügung stehenden Hardware und dem ausgewählten DBMS überhaupt innerhalb des vorgegebenen Zeitrahmens implementieren lässt und andererseits muss abgeklärt werden,
18
2 Anforderungserhebung und -analyse
Abb. 2.1: Unterschiedliche Anforderungstypen im Anforderungsdokument
ob Hardware und DBMS ausreichen, um die Bearbeitungsanforderungen bestehender und zukünftig geplanter Geschäftsprozesse ausreichend zu unterstützen. Das Ergebnis der Analyse von Bearbeitungsanforderungen spielt eine wichtige Rolle für die Auswahl von physischen Zugriffsstrukturen zur Leistungsoptimierung. Auch sind Simulationsmodelle, analytische Modelle oder Datenbank-Benchmark-Verfahren zur Leistungsvorhersage von der Qualität der erhobenen Bearbeitungsanforderungen abhängig. Eine erste oberflächliche Erhebung und Analyse der Anforderungen wird vorerst in eine Durchführbarkeitsstudie einfließen. Ziel dieser Studie ist es, festzustellen, ob sich die Aufgabenstellung mit den zur Verfügung stehenden Ressourcen realisieren lässt bzw. ob die Entwicklung eines DBS überhaupt zielführend ist.
2.1
Dateisystem vs. Datenbankmanagementsystem
Die Anzahl und die Komplexität der betrieblichen Aufgaben, die durch ein unternehmensweites DBS unterstützt werden sollen, sind in vielen Fällen sehr groß und schwer überschaubar. Bevor man mit einer detaillierten Anforderungserhebung und -analyse beginnt, ist zunächst anhand einer Vorstudie festzustellen, welche Art von Datenverwaltungssystem grundsätzlich zur Unterstützung der Aufgaben eingesetzt werden kann. Die Vorstudie soll in relativ kurzer Zeit und möglichst geringem Ressourceneinsatz Aussagen darüber liefern, ob der Ist-Zustand überhaupt verändert werden soll, und, sofern dieses der Fall ist, welches technische Realisie-
2.1 Dateisystem vs. Datenbankmanagementsystem
19
rungskonzept das geeignetste ist. Die Erstellung einer Vorstudie ist nicht ausschließlich eine systemunabhängige Tätigkeit, da mit ihr entschieden werden soll, ob der Einsatz von Datenbanktechnologie angebracht ist. Diese Entscheidung beeinflusst jedoch die nachfolgende detaillierte Anforderungserhebung und Anforderungsanalyse nicht maßgeblich, was an dieser Stelle wiederum berechtigt, einen Exkurs in die unterschiedlichen Entwicklungsstufen von DBS zu machen. Die historische Entwicklung von DBMS wird üblicherweise in drei Stufen beschrieben. Die erste Stufe kann man als isolierte Dateiverwaltung, die zweite Stufe als integrierte Dateiverwaltung und erst die dritte Stufe schließlich als Datenbankmanagementsystem bezeichnen.
2.1.1
Isolierte Dateiverwaltung
Isolierte Dateisysteme haben ihren Ursprung im Beginn der Massendatenverarbeitung. Daten werden in elementaren Dateien abgelegt, die Struktur der Dateien ist im jeweiligen Anwendungsprogramm festgelegt und jedes Programm verwendet ausschließlich die ihm zugeordneten Dateien. Aus der engen Bindung von Anwendungsprogrammen an Dateien ergeben sich folgende Nachteile: Abhängigkeit zwischen Programmlogik und physischer Datenstruktur (physische Datenabhängigkeit). Dadurch bedingt erfordern Änderungen oder Erweiterungen an den Dateien Veränderungen an der Struktur der Anwendungsprogramme. Daten gleicher Bedeutung werden mehrfach gespeichert. Die redundante Datenhaltung birgt die Gefahr von Inkonsistenzen in sich. Durch die anwendungsspezifische Datenorganisation ist die gleichzeitige Verwendung von Dateien in unterschiedlichen Anwendungsprogrammen nur schwer möglich. Beispiel 2.2: Isolierte Dateiverwaltung In Abbildung 2.2 geben wir eine grafische Beschreibung eines isolierten Dateiverwaltungssystems anhand der zwei Anwendungen „Gehaltsabrechnung“ und „Projektberichte“. Während „Gehaltsabrechnung“ ausschließlich die Datei ANGESTELLTE benutzt, greift „Projektberichte“ auf die Dateien PROJEKTE und PROJEKTBETEILIGTE zu. Daten aus ANGESTELLTE und PROJEKTE sind in PROJEKTBETEILIGTE redundant gehalten. Aufgrund der existierenden physischen Datenabhängigkeit existiert zwischen Dateien und Anwendungsprogrammen eine sehr enge Bindung. So würde z. B. eine physische Änderung an der Datei ANGESTELLTE (z. B. Aufnahme eines Datenfeldes TelefonNr.) eine Änderung im Programmcode von „Gehaltsabrechnung“ bedingen.
2.1.2
Integrierte Dateiverwaltung
Die zweite Entwicklungsstufe ist durch die Verwendung zentraler Dateiverwaltungssysteme charakterisiert. Alle Dateien werden unter Verwendung des Dateiverwaltungssystems an zentraler Stelle gesammelt. Eine allgemein zugängliche Referenzdatei enthält die Strukturbeschreibung aller Dateien. Die Weiterentwicklung gegenüber isolierter Dateiverwaltung liegt darin begründet, dass nunmehr unerwünschte Redundanz von Daten weitgehend vermieden
20
2 Anforderungserhebung und -analyse
Abb. 2.2: Isolierte Dateiverwaltung
wird und somit die Konsistenz des Datenbestandes leichter gewährleistet werden kann. Des Weiteren liegt keine Abhängigkeit zwischen Programmlogik und den physischen Dateien vor. Einige Einschränkungen existieren jedoch weiterhin. So erfordern Änderungen oder Erweiterungen an den Dateien weiterhin Änderungen an den Programmen. Diesmal zwar nicht mehr an den Anwendungsprogrammen, sondern jetzt an den Abbildungsprogrammen, die relevante Dateiauszüge für Anwendungsprogramme erzeugen. Im Modell der integrierten Dateiverwaltung können über den indirekten Weg der Dateiauszüge mehrere Anwendungsprogramme auf eine Datei greifen. Beispiel 2.3: Integrierte Dateiverwaltung Wir betrachten die Situation aus Beispiel 2.2 und zeigen die Struktur eines integrierten Dateiverwaltungssystems. Kontrollierte Datenredundanz ergibt sich aus der Tatsache, dass Redundanz ausschließlich auf der Ebene der Dateiverwaltungssysteme vorliegt und die zentralen Dateien keinen redundanten Datenbestand mehr aufweisen. Aus Abbildung 2.3 ist ersichtlich, dass die zentralen Dateien eines integrierten Dateiverwaltungssystems bereits einen direkten semantischen Bezug zu Objektbeschreibungen der Realität besitzen. Datei PERSONAL beschreibt ausschließlich Eigenschaften von Objekten vom Typ Person, Datei PROJEKTE enthält ausschließlich Informationen zu Projekten und Datei PROJEKTBETEILIGUNG enthält Informationen darüber, welche Personen an welchen Projekten arbeiten. Die individuellen Sichten der einzelnen Anwendungsprogramme werden
2.1 Dateisystem vs. Datenbankmanagementsystem
21
Abb. 2.3: Integrierte Dateiverwaltung
über spezielle Abbildungsprogramme erzeugt. Dies ist ein entscheidender Vorteil gegenüber isolierten Dateisystemen, macht aber eine sorgfältige Planung der Struktur der einzelnen Dateien notwendig. Wir werden im Kapitel 3 Techniken der konzeptuellen Datenmodellierung beschreiben, die zur Strukturierung der Dateien erfolgreich eingesetzt werden können.
2.1.3
Architektur von Datenbankmanagementsystemen
Im Modell der integrierten Dateiverwaltung sind keine Abbildungsvorschriften von Dateien auf Dateiverwaltungssysteme vorgegeben. Im Prinzip kann also jedes Dateiverwaltungssystem seine eigenen Strukturierungsregeln und Dienstfunktionen vereinbaren bzw. seine logische Struktur verändern. Eine Änderung hätte dann zur Folge, dass die Anwendungsprogramme, die Dateiauszüge verwenden, geändert werden müssen. In DBMS verlangt man nun neben physischer Datenunabhängigkeit auch logische Datenunabhängigkeit, also Immunität von Anwendungsprogrammen gegenüber Änderungen der logischen Struktur der DB. Erreicht wird dies durch vereinheitlichte Strukturierungsregeln und festgelegte Dienstfunktionen, die einem bestimmten Datenmodell genügen müssen. Eine zentrale Idee in DBMS ist die Trennung der in Dateisystemen existenten Einheit Dateien-Programme in zwei unterschiedliche Schichten: der logischen und der physischen Beschreibung von Daten. Das bedeutet, dass Programme ausschließlich mit „logischen Dateien“
22
2 Anforderungserhebung und -analyse
Abb. 2.4: Externes und internes Modell einer Datenbankverarbeitung
arbeiten und dass die physische Realisierung der Dateien (die Dateiorganisation) für Benutzer nicht sichtbar ist. Die Trennung der Beschreibung der Daten in zwei separate Ebenen hat neben dem Vorteil der kontrollierbaren Datenredundanz und der damit einhergehenden Konsistenz des Datenbestandes noch einen weiteren gravierenden Vorteil. So ist für Anwendungsprogramme eine gesteigerte Flexibilität gegeben, da über die logische Beschreibung der Daten zum einen für jede Anwendung eine eigene Sicht (externes Modell) auf die mit anderen Anwendungen gemeinsam genutzten Daten zur Verfügung gestellt werden kann und zum anderen Belange der physischen Speicherung der Daten (internes oder physisches Modell) für Anwendungsprogramme ohne Bedeutung ist. Aus letzterem ergibt sich auch die physische Datenunabhängigkeit, nämlich, dass eine Änderung an den physischen Speicherstrukturen keine Änderung an auf die Dateien zugreifenden Programmen bedingt. Beispiel 2.4: Architektur eines DBMS (zweischichtiger Aufbau) Abbildung 2.4 zeigt einen zweischichtigen Aufbau und die Gliederung in externes und internes Modell eines DBS anhand der beiden bekannten Anwendungen. Die zweischichtige Architektur eines DBS stellt jedoch nur einen Zwischenschritt hin zu der Architektur der heute gängigen DBS dar. Wie aus Abbildung 2.4 ersichtlich ist, ist die Ebene des externen Modells durch voneinander unabhängige logische Dateien beschrieben. Dies entspricht nicht unbedingt der Realität, denn Angestellte und Projekte stehen ja über die Datei PROJEKTBETEILIGUNG miteinander in Beziehung und können nicht isoliert voneinander betrachtet werden. Zur Darstellung dieser „unternehmensweiten“ Sicht
2.1 Dateisystem vs. Datenbankmanagementsystem
23
Abb. 2.5: ANSI/SPARC Architekturmodell
hat man zwischen externer und interner Schicht eine dritte Schicht, die so genannte konzeptuelle Schicht aufgenommen. Dieses Drei-Schichten-Konzept einer Datenbankarchitektur ist auch als ANSI/X3/SPARC-Architekturmodell1 bekannt (siehe Abbildung 2.5).
Feststellung 2.1: Architekturmodell DBMS mit heute üblicher Technologie sind also in drei Schichten realisiert. Das interne Datenbankschema beschreibt die physischen Speicherstrukturen und Zugriffspfade. Das externe Datenbankschema beschreibt die unterschiedlichen Sichten einzelner Anwendungen (bzw. auch Datenbanknutzer) auf die Datenbasis. Dazwischen liegt das konzeptuelle Datenbankschema. Es repräsentiert eine gesamtheitliche Sicht der Datenbasis, indem es die externen Sichten aller Anwender in ein einheitliches konzeptuelles Modell integriert. Bevor man nun aufgrund der Erkenntnisse aus der Vorstudie entscheiden kann, ob ein DBMS zum Einsatz kommen soll oder nicht, muss man sich auch überlegen, welche Dienstfunktionen zur Realisierung der Anwendung bereits im DBMS inkludiert sind und somit nicht mehr in den Anwendungsprogrammen realisiert werden müssen. Die nachfolgend dargestellten Dienstfunktionen werden üblicherweise von DBMS angeboten. Auf die meisten dieser Funktionen werden wir in den späteren Kapiteln noch näher eingehen. 1 Vom Standards Planning and Requirements Committee (SPARC) of the American Standards Committee on Computers and Information Processing (ANSI/X3) wurde 1975 diese Drei-Schichten-Architektur für DBS vorgeschlagen.
24
2 Anforderungserhebung und -analyse
• Persistenz Im Unterschied zur Verarbeitung von Daten mit Programmiersprachen „überleben“ diese das Ende von Datenbanktransaktionen und werden automatisch auf Sekundärspeicher abgelegt. • Speichermanagement Datenbankanwendungen sind ein- und ausgabeintensiv. Große Datenmengen werden üblicherweise auf Plattenspeicher ausgelagert. Das DBMS unterstützt spezifische Techniken zur Erhöhung der Performanz, z. B. Hauptspeicherpufferung, Indizierung, Clusterbildung oder Abfrageoptimierung. • Mehrbenutzerbetrieb Mehrere Benutzer können gleichzeitig mit den Daten arbeiten. Das DBMS sorgt dafür, dass keine unerwünschten Wechselwirkungen durch gleichzeitige Manipulation derselben Daten eintreten können. Etwaige Konfliktsituationen müssen durch Synchronisationsverfahren überwacht und reguliert werden (sog. concurrency control). • Konsistenzüberwachung Die Überwachung der Konsistenz des Datenbestandes wird auch als Integritätssicherung bezeichnet. Das DBMS übernimmt die Gewährleistung der korrekten Ausführung von Transaktionen. Kommt es zu Systemfehlern (z. B. Fehler in der Zentraleinheit, Hauptspeicher, Platte oder Stromausfall), kann der letzte gültige Datenbankzustand wiederhergestellt werden. • Datensicherheit Das DBMS unterstützt die Vergabe und Verwaltung von Zugriffsrechten für unterschiedliche Benutzer, da in vielen Anwendungen nicht jeder Benutzer alles mit den Daten tun darf. Oft wird auch die Benutzeridentifikation (Eingabe einer Benutzer-ID) und nachfolgende Authentifikation (z. B. durch Passwortverfahren) unterstützt. • Anfragesprache Das DBMS stellt eine Anfragesprache zur Ad-hoc-Formulierung von Datenbankanfragen sowie zur Veränderung des Datenbestandes zur Verfügung. • Dienstprogramme Die bisher angeführten Dienstfunktionen werden noch durch eine Reihe von Dienstprogrammen erweitert. Viele DBS beinhalten Programmgeneratoren zur raschen Anwendungsentwicklung, Reportgeneratoren zur Erstellung von Berichten, Konvertierungsprogramme zur Änderung von Datenformaten oder auch Backup-Utilities zur Unterstützung der Datensicherung. Das Einsatzgebiet von DBMS ist äußerst breit gefächert. DBS stellen einen Basisdienst sowohl in vielen Standardanwendungen als auch in kaufmännischen wie technischen Spezialanwendungen dar. Als Beispiele seien für unterschiedliche Anwendungen Buchungs- und Auskunftssysteme wie sie von Fluglinien, Reisebüros oder Mietwagenunternehmen eingesetzt werden, geografische Informationssysteme, wie z. B. das automatisierte Grundbuch oder geografische Umweltinformationssysteme, und DBS als zentrale Komponente einer rechnerintegrierten Fertigung genannt. Aufgrund der vielfältigen Möglichkeiten des Einsatzes von
2.1 Dateisystem vs. Datenbankmanagementsystem
25
DBMS ist es verständlich, dass Produkte sehr allgemein gehalten sind und erst über bestimmte Einstellparameter für bestimmte Anwendungen getuned werden müssen. In den meisten Fällen muss man hier jedoch Kompromisse zwischen optimalem Leistungsverhalten einer Anwendung und dem Nutzen aus den Dienstfunktionen des DBS eingehen. Wann soll man nun ein Dateisystem einsetzen, und wann ist der Einsatz eines DBS angebracht? Auf diese Frage kann man keine allgemein gültige Anwort geben, denn ihre Beantwortung wird immer von der gegenwärtigen Situation und der individuellen Anwendung abhängen. Einige Hinweise zur Entscheidungsfindung können jedoch gegeben werden. DBS eignen sich besonders für Anwendungen mit den folgenden Eigenschaften: • Heterogene Benutzergruppen mit gemeinsamer integrierter Datenhaltung. • Keine bzw. kontrollierte Datenredundanz wird gewünscht. • Benutzerverwaltung und Autorisierung ist notwendig. • Unterschiedliche Schnittstellen für unterschiedlich geschulte Benutzer sollen zur Verfügung gestellt werden. • Der Datenbestand ist integriert. Daten stehen miteinander in Beziehung. • Die Integritätsmechanismen des DBS sollen genutzt werden. • Backup und Fehlerbehandlung bei Systemfehlern sind gewünschte Eigenschaften. • Anwendungsprogramme können sich ändern und geringere Entwicklungskosten durch den Einsatz von Programmgeneratoren sind erwünscht. Durch die eher allgemeine Ausrichtung der Datenbanksoftware und dem Overhead, der durch die Vielzahl der Dienstfunktionen entstanden ist, ist der Einsatz von Standard-DBMS für zeitkritische Anwendungen kritisch zu prüfen. Der Einsatz von Dateisystemen kann vorteilhaft sein, wenn • Echtzeitanforderungen bestehen, • der Overhead für Benutzerverwaltung, Backup, Fehlerbehandlung und Synchronisation nicht benötigt wird, • Anwendungen sich nicht oder sich nur sehr wenig ändern und • nur geringe Investitionskosten eingeplant sind. Hier ist zu bedenken, dass die Preise für DBMS gerade in der letzten Zeit beträchtlich gesenkt wurden und die Kosten der Entwicklung komplexerer Anwendungen unter Verwendung von Dateisystemen erfahrungsgemäß weit höher als bei Verwendung von Datenbanksystemen liegen.
26
2.2
2 Anforderungserhebung und -analyse
Anforderungserhebung
Die Erhebung von Anforderungen umfasst die quantitative und qualitative Erfassung des IstZustandes eines abgegrenzten betrieblichen Aufgabensystems. Grundsätzlich kann zwischen einer Primär- und einer Sekundärerhebung unterschieden werden. Bei der Primärerhebung werden die Informationen erstmalig und primär für den Erhebungszweck erhoben, während bei der Sekundärerhebung auf bereits vorhandene Dokumentationen zurückgegriffen wird. Die Anforderungserhebung kann sowohl von den betroffenen Benutzern als auch von den Systemanalytikern erstellt werden – in den meisten Fällen ist jedoch eine Kooperation von beiden (partizipative Systemanalyse) am sinnvollsten. Die am häufigsten in der Literatur genannten und in der Praxis eingesetzten Methoden zur Erhebung der Anforderungen sind: • Dokumentenanalyse • Fragebogentechniken • Interviews • Selbstaufschreibung • Beobachtung • Berichtsmethode Welche Methode im einzelnen eingesetzt wird, hängt vom Untersuchungsgegenstand und Untersuchungsziel ab. Die beste Methode gibt es leider nicht. In der Praxis hat sich auch bewährt, unterschiedliche Methoden miteinander zu kombinieren. So kann z. B. die Interviewmethode mit allen anderen Methoden kombiniert werden, um mit ihr erlangte Erkenntnisse einer ersten Validation zu unterziehen. In Abbildung 2.6 beschreiben wir den Einsatz der unterschiedlichen Erhebungstechniken. Der obere Bereich des Bildes beschreibt Inputfaktoren und Anwendungsbereiche der sechs Erhebungstechniken. Die Kanäle in der Mitte der Abbildung zeigen den unterstützenden Charakter der Dokumentenanalyse, Fragebogentechnik, Selbstaufschreibung, Berichtsmethode und Beobachtung. Der untere Teil der Abbildung zeigt die Output-Informationen der Erhebungstechniken.
2.2.1
Dokumentenanalyse
Viele neu zu entwickelnde Informationssysteme basieren teilweise oder vollständig auf bereits bestehenden Systemen. Sofern die vorhandenen Unterlagen korrekt und aktuell sind, stellen sie einen guten Ausgangspunkt zur Anforderungserhebung dar. Solche Unterlagen können z. B. sein: • Organisationshandbücher, Stellen- und Arbeitsplatzbeschreibungen, Ausbildungsunterlagen, Aufgabenpläne, Stellenbesetzungspläne. • Geschäftsberichte, Bilanzen, Kennzahlen, Statistiken, Revisionsberichte, Inventurverzeichnisse.
2.2 Anforderungserhebung
27
Dokumente, Dateien, anderer Text
Einer großen Personengruppe bekannte Information
Spezialwissen des Interviewten
Aktivitäten einer typischen Zeitspanne
Beobachtbare Situationen, Verfahren, Verhaltensmuster
Dokumentenanalyse
Fragebogen
Berichtsmethode
Selbstaufschreibung
Beobachtung
Info über Aufgaben, Arbeitsablauf und -methoden, Kommunikation
quantitative Angaben
Überblick über Aufgaben, Aktivitäten und Kommunikation
Anstrengungen, Arbeitsmethoden, Schwachstellen
standardisiertes Interview
Info über Aufgaben, Arbeitsablauf und -methoden, Kommunikation
quantitative Angaben
qualitative Informationen, Ursachen, Motive
Überblick über Aufgaben, Aktivitäten und Kommunikation
Anstrengungen, Arbeitsmethoden, Schwachstellen
Abb. 2.6: Auswahl von Erhebungstechniken (nach [Hane84])
• Betriebs- und Arbeitsablaufpläne, technische Verfahrensbeschreibungen, Materialflusspläne, Stücklisten, Datenflusspläne. • Kunden- und Lieferantenverzeichnisse, Telefonverzeichnisse, Raumpläne, Produktbeschreibungen. • Vorhandene Programme, Programmdokumentationen und Handbücher, Eingabemasken und Reports, Dateibeschreibungen. • Formulare, ausgefüllte Vordrucke und Datenträger, Listen und Berichte. Das Studium der vorhandenen Unterlagen sollte zu Beginn der Erhebung stattfinden. Die Analyse vorhandener Dokumente hat den Vorteil, rasch eine breite Informationsbasis zu liefern und den bestehenden Betriebsablauf nicht zu stören. Sie zeichnet sich zudem durch einen geringen Erfassungsaufwand aus. Als wesentlicher Nachteil der Methode ist zu nennen, dass die Qualität der erhobenen Informationen stark von der Richtigkeit und Aussagekraft der untersuchten Dokumente abhängig ist. Des Weiteren beschreiben die dokumentierten Daten das Aufgabensystem ausschließlich zum Erfassungszeitpunkt, und es ist zu beurteilen, ob die in
28
2 Anforderungserhebung und -analyse
der Vergangenheit dokumentierten Sachverhalte auch noch in der Zukunft Gültigkeit haben werden.
2.2.2
Fragebogentechnik
Ein Weg um möglichst effektiv Informationen von einer Vielzahl potenzieller Datenbanknutzer zu erhalten, ist der Gebrauch von Fragebögen. Ein Fragebogen besteht aus einer Menge von unterschiedlichen Fragen, die von den Befragten schriftlich beantwortet werden müssen. Um Auffassungsunterschiede und Verständnisprobleme einzuschränken, empfiehlt sich vor der endgültigen Formulierung des Fragebogens die Erprobung an mehreren Testpersonen. Fragebögen sollten so beschaffen sein, dass die Antworten kurz, einfach auszuwerten und eindeutig sind, z. B. durch eine Auswahl von vorgegebenen Antworten. Um eine hohe Beantwortungsrate zu erreichen, sollte ein Fragebogen nicht zu lang, gut strukturiert und an spezielle Benutzer gerichtet sein. Nach folgenden Gesichtspunkten werden verschiedene Fragebogentypen unterschieden: • Standardfragebogen oder differenzierter Fragebogen • Fragebogen mit offenen bzw. geschlossenen Fragen • Individual- oder Gruppenfragebogen Während beim Standardfragebogen alle Befragten dieselben Fragen beantworten, wird beim differenzierten Fragebogen zwischen z. B. Befragten aus unterschiedlichen Fachabteilungen oder Befragten mit unterschiedlichem Ausbildungsniveau unterschieden. Bei offenen Fragen sind keine Alternativantworten vorgegeben. Der Befragte muss mit eigenen Worten eine Antwort auf die Fragen formulieren. Bei geschlossenen Fragen werden mehrere Antwortalternativen vorgegeben und der Befragte muss nur mehr auswählen. Bei Verwendung geschlossener Fragen hat man den Vorteil einer vollständigen Beantwortung der Fragen und einer vereinfachten Auswertung. Offene Fragen ermöglichen meist spontane Antworten und lassen auch Antwortalternativen zu, die bei geschlossenen Fragen möglicherweise nicht berücksichtigt wurden. Ein Individualfragebogen wird an alle Mitglieder einer Gruppe verteilt, während ein Gruppenfragebogen von einzelnen Befragten stellvertretend für eine Gruppe beantwortet wird. Im Allgemeinen ist bei Erstellung von Fragebögen darauf zu achten, dass verschiedene Arten von Fragen gestellt werden sollten. Überblicksfragen erleichtern den Einstieg und schaffen ein Gesamtbild der Aufgabenstellung. Detailfragen schaffen Monotonie und Unlust, sie sollten durch Unterbrechungsfragen aufgelockert werden. Anregungsfragen schaffen einen Freiraum, in dem Befragte eigene Vorschläge unterbreiten oder wichtige Anregungen geben können. Fragebögen sollen auch unauffällige Kontrollfragen enthalten, anhand derer die Richtigkeit der gemachten Angaben überprüft werden kann. Die Fragebogenmethode hat den Vorteil einer leichteren statistischen Auswertung und der geringen Kosten. Sie eignet sich besonders für geografisch verteilte Erhebungen und bei gleichförmigem und ähnlichem Informationsbedarf unterschiedlicher Nutzer. Als Nachteile sind vor allem der hohe Aufwand der Auswertung von offenen Fragen und die Möglichkeit einer subjektiven Färbung von Antworten zu nennen. Werden Arbeitsmengen oder -zeiten erhoben, sind die Ergebnisse der Erhebung mit besonderer Vorsicht zu genießen.
2.2 Anforderungserhebung
2.2.3
29
Interviewmethode
Das Interview ist die am häufigsten verwendete und ergiebigste Erhebungstechnik. Ein Interview ist eine persönliche Befragung potenzieller Datenbanknutzer. Es sollte einerseits strukturiert sein und nach einer schriftlichen Vorlage ablaufen und andererseits für unvorhergesehene Antworten flexibel genug sein. Interviews können nach folgenden Gesichtspunkten gestaltet werden: • standardisiertes bzw. nichtstandardisiertes Interview, • Einzel-, Gruppenbefragung bzw. Konferenzmethode, • offenes bzw. verdecktes Interview. Bei einem standardisierten Interview ist die Reihenfolge der Fragen fest vorgegeben, während beim nichtstandardisierten Interview Fragen in beliebiger Reihenfolge gestellt werden und auch Zusatzfragen zulässig sind. Bei der Einzelbefragung wird jeder potenzielle Nutzer einer Gruppe einzeln befragt. Im Gegensatz dazu werden bei der Gruppenbefragung mehrere Gruppenmitglieder gleichzeitig befragt. Bei der Konferenzmethode erfolgt die Befragung über unterschiedliche Gruppengrenzen hinweg. Mitglieder unterschiedlicher Fachabteilungen diskutieren hier gemeinsam Antworten zu den einzelnen Fragen des Interviews. Bei einem offenen Interview ist der Befragte über Sinn und Zweck des Interviews informiert, während bei verdeckten Interviews die Befragung versteckt ohne das Wissen des Befragten stattfindet. Bei der Gestaltung der Fragen sind im Wesentlichen dieselben Aspekte zu berücksichtigen wie bei der Fragebogenmethode. Auch was die Vorbereitung der Fragen und die Auswertung der Antworten anbelangt, sind die Interviewmethode und die Fragebogentechnik sehr ähnlich zueinander. Die Interviewmethode besteht aus fünf nacheinander anfallenden Phasen: 1. Bestimmen der Interviewpartner, 2. Erstellen des Fragenkataloges, 3. Durchführung des Interviews, 4. Dokumentation der Ergebnisse, 5. Aufarbeiten des Interviews. Die Dokumentation der Ergebnisse des Interviews sollte schon während der Befragung begonnen und unmittelbar nach dem Interview abgeschlossen werden. Unter dem Aufarbeiten des Interviews versteht man die Mitteilung der Ergebnisse an die Befragten und ihr Feedback auf die Dokumentation des Interviews. Oft werden in dieser Phase Fehler ausgeräumt, und manchmal wird es auch notwendig sein, einzelne Phasen des Interviews zu wiederholen. Die Interviewmethode hat den Vorteil, die Vertiefung der Befragung durch Zusatzfragen leicht zu ermöglichen, einen persönlichen Kontakt zwischen Systemanalytikern und potenziellen Datenbanknutzern herzustellen und qualitativ sehr gute Erhebungsergebnisse zu ermöglichen. Demgegenüber stehen jedoch der hohe Zeitaufwand einer Befragung, die Störung des Betriebsablaufs durch die Befragung und die notwendige hohe Qualifikation des Interviewers im Anwendungsbereich, die eine Voraussetzung für ein erfolgreiches Interview darstellt.
30
2.2.4
2 Anforderungserhebung und -analyse
Berichtsmethode
Die Berichtsmethode ist eine Tätigkeit, die allein vom Aufnahmeteam ohne Hinzuziehung Dritter vorgenommen wird. Sie eignet sich besonders zur Aufnahme von Aktivitäten innerhalb einer für die Anwendung typischen Zeitspanne und liefert einen Überblick über Aufgaben, Aktivitäten und Kommunikation potenzieller Datenbanknutzer. Die Berichtsmethode wird oft mit einer Dokumentenanalyse gemeinsam durchgeführt und durch ein standardisiertes Interview ergänzt. Der Vorteil der Berichtsmethode liegt in der geringen Beeinträchtigung des Arbeitsablaufs. Diesem Vorteil steht jedoch der hohe Zeitaufwand, der für die Berichterstellung durch das Aufnahmeteam notwendig ist, entgegen.
2.2.5
Selbstaufschreibung
Bei der Aufschreibung der Anforderungen durch die zukünftigen Datenbanknutzer wird der Informationsbedarf von den Fachexperten der beteiligten Abteilungen (den Datenbanknutzern) niedergeschrieben. Nach der Form des entstehenden Dokumentes unterscheidet man in Berichte mit völliger Formfreiheit und solche, in denen gewisse Richtlinien (z. B. Strukturierung, Mengengerüst, Mindestbestandteile) eingehalten werden müssen. Werden hinsichtlich der Form des Berichtes keine Vorgaben gemacht, kann jeder Mitarbeiter die Schwerpunkte seiner Tätigkeit nach eigenem Ermessen darstellen. Dies hat den Vorteil, dass zumindest die aus der Sicht des Mitarbeiters wichtigen Aufgabengebiete besondere Berücksichtigung finden können, während Bereiche, die für die Tätigkeit des Mitarbeiters unwesentlich sind, vernachlässigt werden können. Wird bei der Erstellung des Berichtes auf völlige Formfreiheit verzichtet und sind feste Richtlinien vorgegeben, so wird dadurch die Auswertung der Berichte erheblich erleichtert. Der Vorteil der Selbstaufschreibung liegt in der genauen Beschreibung der unterschiedlichen Arbeitsbereiche. Zusätzlich dazu können die einzelnen Mitarbeiter ihre Vorstellungen und Lösungsansätze in den Entwurfsprozess sehr gut einbringen. Als Nachteile dieser Erhebungsmethode sind zu nennen, dass die Selbstaufschreibung durch den Zeitaufwand, der zur Erstellung des Berichtes notwendig ist, gestört wird, und dass Berichte durch die subjektive Darstellung der Mitarbeiter mit besonderer Vorsicht zu genießen sind. Dies bezieht sich insbesondere auf Mengen- und Zeitangaben.
2.2.6
Beobachtungsmethode
Als Beobachtung bezeichnet man die Aufnahme von Anforderungen unmittelbar an der Quelle ihres Entstehens durch optische Aufnahme und ihre nachfolgende Interpretation durch den Systemanalytiker. Nach den folgenden Kriterien können verschiedene Formen der Beobachtung unterschieden werden: • offene und verdeckte Beobachtung, • strukturierte und unstrukturierte Beobachtung, • Einzelbeobachtung, Dauerbetrachtung oder unterbrochene Beobachtung, • direkte und indirekte Beobachtung.
2.3 Anforderungsdokument
31
Von offener Beobachtung spricht man, wenn für alle Beteiligten ersichtlich ist, dass eine Erhebung stattfindet. Bei einer verdeckten Beobachtung werden die Beiteiligten nicht über die Erhebung informiert. Bei einer strukturierten Beobachtung erfolgt die Beobachtung nach im Vorhinein festgelegten Richtlinien. Bei einer Einzelbeobachtung wird der Beobachtungsgegenstand ein einziges Mal erhoben, während im Rahmen einer Dauerbetrachtung die Beobachtung ohne Unterbrechung über eine längere Zeitdauer hinweg stattfindet. Bei einer unterbrochenen Beobachtung werden bestimmte Zeitpunkte einer Tätigkeit zur Beobachtung (Multimomentverfahren) ausgewählt. Von direkter Beobachtung spricht man, wenn die Beobachtung vom Aufnahmeteam direkt durchgeführt wird. Eine indirekte Beobachtung findet statt, wenn Ereignis und Beobachtung zeitversetzt stattfinden, z. B. durch den Einsatz technischer Hilfsmittel wie der Videoaufzeichnung. Die Beobachtungsmethode zeichnet sich dadurch aus, dass der Arbeitsablauf nicht beeinträchtigt wird und dass quantitative und zeitbezogene Anforderungen leicht erhoben werden können. Die Beobachtungsmethode (zumindest in der Form der direkten Beobachtung) ist sehr zeitaufwändig, da der Beobachter für die Dauer der Beobachtung seinen Platz nicht verlassen darf. Bei der Anforderungserhebung handelt es sich um einen häufig langwierigen Systemanalyseprozess, in dem alle beschriebenen Methoden zum Einsatz kommen können. Ebenso wichtig wie die sorgfältige Erhebung des Ist-Zustandes ist die übersichtliche Darstellung und Auswertung der Ergebnisse der Erhebung im Anforderungsdokument. Im folgenden Unterkapitel werden wir unterschiedliche Klassen von Anforderungen kennen lernen und zeigen, wie die erhobenen Anforderungen analysiert und im Anforderungsdokument entsprechend repräsentiert werden können.
2.3
Anforderungsdokument
Ähnlich wichtig wie die sorgfältige und vollständige Erhebung der Anforderungen ist die übersichtliche Darstellung und die Analyse der Ergebnisse der Erhebung im Anforderungsdokument. Im Idealfall ist das Anforderungsdokument eine Spezifikation des zu entwickelnden Systems, die alle Informationen enthält, die notwendig sind, um die DB erstellen zu können. Prinzipiell kann zwischen den zwei Typen unternehmensweite Anforderungsspezifikation und individuelle Anforderungsspezifikation unterschieden werden. Beim unternehmensweiten Anforderungsdokument werden alle Nutzeranforderungen und erhobenen Sachverhalte in einem einzigen Anforderungsdokument festgehalten. Diese Vorgehensweise empfiehlt sich nur für übersichtliche und einfache Anwendungen. In der Vielzahl der Fälle wird hingegen je ein Anforderungsdokument für jede Benutzergruppe und jeden Funktionsbereich (eine individuelle Anforderungsspezifikation) im Unternehmen erstellt. Ein Vorteil des unternehmensweiten Anforderungsdokumentes liegt in der Möglichkeit, Redundanzen, Homonyme und Synonyme, Inkonsistenzen und Fehler vorzeitig zu erkennen. In komplexen und umfangreichen Anwendungsgebieten werden unternehmensweite Anforderungsdokumente jedoch sehr rasch unübersichtlich. Hier empfiehlt sich die Erstellung von mehreren Anforderungsdokumenten, die jedoch in späteren Entwurfsphasen zu einem unternehmensweiten Datenmodell konsolidiert werden müssen. In Unterkapitel 3.5 werden wir auf die Sichtenintegration und Schemakonsolidierung genauer eingehen. Für beide Vorgehensweisen gilt jedoch, dass Anforderungsdokumente die folgenden Eigenschaften aufweisen müssen:
32
2 Anforderungserhebung und -analyse
• Korrektheit Eine Spezifikation ist korrekt, wenn durch sie die Realität wahrheitsgetreu beschrieben wird. • Vollständigkeit Anforderungsdokumente sind vollständig, wenn sie alle erhobenen Anforderungen enthalten und diese Anforderungen ausreichen, die DB zur Zufriedenheit der Nutzer zu erstellen. • Konsistenz Ein Anforderungsdokument ist konsistent, wenn es keine Anforderungen enthält, die miteinander in Konflikt stehen. Beispiele für Konflikte sind widersprüchliche Begriffe, Konzepte und Konsequenzen. • Eindeutigkeit Alle Anforderungen sind eindeutig, wenn sie nur eine einzige Interpretation erlauben. • Einfachheit Anforderungen sollten verständlich und so einfach wie nur möglich formuliert sein. Gegebenenfalls sollten Anforderungen durch Kommentare ergänzt werden. Die beste Möglichkeit diese Forderungen zu erfüllen besteht darin, Anforderungsdokumente hinsichtlich des Typs der Anforderungen in die vier unterschiedlichen Teile Informationsanforderungen, funktionale Anforderungen, Bearbeitungsanforderungen und dynamische Anforderungen zu strukturieren. Es gibt eine Reihe verfügbarer Darstellungstechniken für die erhobenen Anforderungen, die entweder eine textuelle, grafische oder tabellarische Darstellungsform wählen. Welche Darstellungsform im Einzelnen eingesetzt werden soll, hängt sowohl vom Untersuchungsziel als auch von der Art der dokumentierten Anforderungen ab. Informationsanforderungen werden häufig textuell beschrieben. Funktionale Anforderungen werden meist durch grafische Darstellung und ergänzenden Text beschrieben. Dynamische Anforderungen eignen sich ebenfalls gut zur Darstellung in grafischer Form, während Bearbeitungsanforderungen, wie z. B. erhobene Transaktionsfrequenzen, oft in Tabellenform dargestellt werden. In der Praxis hat sich auch bewährt, die einzelnen Darstellungsformen miteinander zu kombinieren. Oft ist es sinnvoll, zu allererst eine textuelle Analyse der vorliegenden Anforderungen vorzunehmen und erst danach eine detaillierte Beschreibung zu erstellen und ein grafisches Beschreibungsmittel einzusetzen. Die grafischen Konzepte und tabellarischen Darstellungen werden oft auch mit ergänzendem Text beschrieben. Bevor wir auf die unterschiedlichen Typen von Anforderungen näher eingehen werden, geben wir einige Hinweise zur Strukturierung des ergänzenden Textes. Während der textuellen Analyse, d. h. während der Analyse der in natürlicher Sprache vorliegenden Anforderungsbeschreibung, müssen Mehrdeutigkeiten entlarvt und ein einheitliches Verständnis von Beschreibungsdetails gewährleistet werden. Dies ist insbesondere dann nicht immer einfach, wenn Texte von unterschiedlichen Personen erstellt wurden und aus Interviews, Diskussionen oder direkt von den zukünftigen Datenbanknutzern stammen und dadurch nur wenig strukturiert sind. Die Analyse von natürlichsprachigem Text setzt ein hohes Anwendungswissen des Systemanalytikers voraus. Man kann jedoch einige Regeln beachten, mit denen Ungenauigkeiten und Mehrdeutigkeiten entdeckt und eliminiert werden können:
2.3 Anforderungsdokument
33
• Begriffe sollen in einem korrekten Abstraktionsniveau benutzt werden. So sollte anstelle von allgemeinen Bezeichnern wie z. B. „Name“ eine genauere Bezeichnung wie „Projektname“, anstelle von „Datum“ „Geburtsdatum“ oder anstelle von „Stadt“ der Begriff „Ort“ gewählt werden. Zu genaue Beschreibungen sind jedoch auch nicht immer sinnvoll. Anstelle von Ausprägungen oder Instanzen von Begriffen sollen eher Überbegriffe als Bezeichner gewählt werden. Ein Beispiel dafür wäre die Verwendung des allgemeinen Konzeptes „Wertpapier“ anstelle von „Aktie“. Begriffe müssen einen eindeutigen Zeitbezug haben. Ein allgemeiner Begriff wie z. B. „Umsatz“ kann sich auf einen Tag, auf eine Woche, einen Monat oder eine andere Abrechnungsperiode beziehen. Eine richtige Begriffswahl wäre z. B. „Jahresumsatz“. • Mehrdeutige Wörter und umschreibende Ausdrücke sollten vermieden werden. So sollte z. B. die Bezeichnung „Student“ in textuellen Anforderungsbeschreibungen anstelle von „sich in akademischer Ausbildung befindliche Person“ gewählt werden. Mehrdeutigkeiten entstehen, wenn Referenzen zwischen Begriffen nicht spezifiziert sind. Ein Beispiel dafür wäre eine „Telefonnummer“, wobei nicht hervorgeht, ob es sich um einen Privatanschluss oder die Firmennummer handelt. • Verwendung von strukturiertem Text. Die Strukturierung des Textes ergibt sich durch einen Standardsatzbau und durch eingerückte Sätze und Absätze. Zur Beschreibung von Arbeitsabläufen empfiehlt es sich, eine einfache Art von Pseudocode und eine Strukturierung des Textes wie Bedingung „dann“ Aktion „ansonsten“ „falls“ Bedingung „dann“ Aktion usw. zu verwenden. • Vermeidung von Homonymen und Synonymen. Synonyme sind verschiedene Worte mit der gleichen Bedeutung, wie z. B. „Rechner“ und „Computer“, während mit Homonymen unterschiedliche Bedeutungen eines Wortes gemeint sind, z. B. „Name“ einmal als Projektbezeichnung und ein anderes Mal als Ortsname. • Die Erstellung eines Stichwortverzeichnisses ist sinnvoll. Es sollen nur Bezeichner verwendet werden, die im Stichwortverzeichnis aufgeführt sind. Für jeden Bezeichner sollten eine kurze Erklärung und mögliche Synonyme im Stichwortverzeichnis angegeben sein. Nach dieser ersten Analyse der vorliegenden Anforderungsbeschreibung ist es nun an der Zeit, mit der Erstellung des Anforderungsdokumentes zu beginnen. Jedes Anforderungsdokument sollte zumindest aus vier Teilen bestehen, je einen Teil für jede Anforderungsform. In den folgenden Unterkapiteln wollen wir auf die Darstellung und Analyse der Anforderungen näher eingehen.
2.3.1
Informationsanforderungen
Informationsanforderungen beschreiben die Struktur und die Art der anfallenden Daten und eignen sich daher vorzüglich zur Durchführung einer strukturellen Analyse. Neben einer vollständigen Datenbeschreibung sind hier Angaben über die Integrität der Daten, Referenzen zwischen den Daten, gültige Wertebereiche sowie Abschätzungen über die Minimal- und Maximalkapazitäten der Datenelemente von Interesse.
34
2 Anforderungserhebung und -analyse
Informationsanforderungen beschreiben eine zeitunabhängige und damit rein statische Sicht auf die betrachtete Diskurswelt. Man geht davon aus, dass die erhobenen Anforderungen direkt aus den Erfordernissen der Realität entwickelt wurden, die aus ihnen abgeleiteten Datenstrukturen über einen längeren Zeitraum hinweg Bestand haben werden und für das Unternehmen daher eine bleibende Ressource darstellen. Aus diesem Grund kommt der strukturellen Analyse der erhobenen Anforderungen beim Datenbankentwurf eine zentrale Bedeutung zu. 2.3.1.1
Analyse der Informationsanforderungen
Aus den erhobenen Informationsanforderungen können drei grundlegende Konzepte hergeleitet werden: Gegenstand, Attribut, Beziehung. Ein Gegenstand ist ein reales oder abstraktes „Ding“ (z. B. eine Person, ein Ereignis, ein Lagerartikel), das im DBS gespeichert werden soll und für den Betreiber der DB von Interesse ist. Ein Attribut ist eine elementare Eigenschaft eines Gegenstandes, die unterschiedliche Werte annehmen kann. Eine Beziehung beschreibt eine Assoziation zwischen Gegenständen. In der Folge werden wir auf diese grundlegenden Konzepte zur Strukturierung und Analyse statischer Informationsanforderungen genauer eingehen. Da in diesem Bereich eine große Begriffsvielfalt herrscht, werden wir bei der Erklärung der einzelnen Konzepte Synonyme, ähnlich verwendete Begriffe oder auch oft die englischsprachigen Bezeichnungen jeweils in Klammern angeben. Ein Entity (Gegenstand, Entität, Instanz, Objekt, Ausprägung) ist das zentrale Strukturierungskonzept einer Informationsanforderung und stellt eine Informationseinheit innerhalb der Diskurswelt dar. Jedes Entity hat beschreibende Eigenschaften, die Attribute (Eigenschaften, Merkmale, Charakteristika) genannt werden. Ein Entity aus der Diskurswelt eines KFZUnternehmens ist z. B. der Lagerartikel „Zylinderkopfdichtung“, der durch die Merkmale Artikelnummer, Artikelbezeichnung, Einstandspreis, Motortyp usw. beschrieben wird. 2.3.1.1.1
Attribut
Attribute sind die kleinsten Informationseinheiten und den Entities zugeordnet. Ein Entity besitzt für jedes seiner Attribute einen bestimmten Wert (value). Einige der erhobenen Attribute können möglicherweise noch weiter zerlegt werden. Ein Beispiel dafür ist ein Attribut „Lieferantenanschrift“, das aus Straße, Hausnummer, Postleitzahl und Ort zusammengesetzt ist. Attribute, die aus mehreren Komponenten bestehen, heißen zusammengesetzte Attribute (composite attributes). Attribute, die nicht weiter zerlegt und jeweils nur einen einzigen Wert annehmen können, heißen atomare oder einwertige Attribute (single-valued attributes), während Attribute mit mehreren möglichen Werten für ein bestimmtes Entity mehrwertige Attribute (multi-valued attributes) heißen. Ein Beispiel für ein einwertiges Attribut ist z. B. das Merkmal „Einstandspreis“ von Artikeln. Ein bestimmter Lagerartikel hat genau einen Einstandspreis. Ein Beispiel für ein mehrwertiges Attribut eines Entitytyps „Zylinderkopfdichtung“ ist z. B. die Eigenschaft „Motortyp“, sofern die Zylinderkopfdichtung in mehrere Motortypen (z. B. E30, E31, E33) eingebaut werden kann. Es kann auch vorkommen, dass ein bestimmtes Entity für ein Attribut keinen Wert besitzt. Das kann bedeuten, dass es nie einen Wert für dieses Attribut haben wird, oder dass dieser Wert zur Zeit nicht bekannt ist. In diesem Fall wird dem Attribut ein spezieller Wert, die so genannte „Nullmarke“ (null-valued attribute) zugeordnet. Wird ein Attributwert in Abhängigkeit von bestimmten Ereignissen berechnet (wie z. B. Alter von Geburtsdatum und aktuellem Tagesdatum), oder von Werten anderer Attribute abgeleitet (z. B. Brutto von Netto und MwSt-Satz), so
2.3 Anforderungsdokument
35
Abb. 2.7: Strukturierungsmerkmale für Attribute
spricht man von abgeleiteten Attributen (derived attributes). Jedes Attribut besitzt einen zugeordneten Wertebereich (domain), der die Menge der Werte definiert, die für einen bestimmten Attributwert zulässig sind. Bestimmte Attribute können ausreichen, um ein Entity von allen anderen Entities zu unterscheiden. Solche Attribute besitzen eine identifizierende Eigenschaft (identifizierende Attribute). Abbildung 2.7 fasst die einzelnen Strukturierungsmerkmale für Attribute nochmals zusammen. 2.3.1.1.2
Entitytyp
Entities mit ähnlichen Eigenschaften werden zu einem Entitytyp (Gegenstandstyp, Objekttyp, Entitätsklasse) zusammengefasst. Ein Entity ist somit eine Ausprägung oder Instanz eines bestimmten Entitytyps. Ein Entitytyp besteht aus n unterschiedlichen Attributen, während ein Entity dieses Typs durch n Attributwerte beschrieben wird. Beispiel 2.5: Typ vs. Ausprägungsebene (Entitytyp) Wir betrachten einen Entitytyp „Lagerartikel“ mit den Eigenschaften Artikelnummer (Artikel-Nr), Bezeichung (A-Bezeichnung), Standort und Fahrzeugtyp. Abbildung 2.8 zeigt das unterschiedliche Abstraktionsniveau anhand exemplarischer Ausprägungen. Eine wichtige Eigenschaft von Entities eines bestimmten Typs ist Eindeutigkeit und damit verbunden Unterscheidbarkeit von anderen Entities desselben Typs und Identität von Entities. Ein Gegenstand oder ein Ereignis der Diskurswelt sollte als genau ein Entity eines
Abb. 2.8: Entitytyp mit Ausprägungen
36
2 Anforderungserhebung und -analyse
bestimmten Typs dargestellt sein. Diese Forderung bildet die Grundlage für eine der wichtigsten Eigenschaften von DB, nämlich dass ein identifizierbares Ereignis der Realität nur mit einem einzigen Identifikator in der DB gespeichert sein darf (1:1-Abbildung zwischen Diskurswelt und seiner Repräsentation in der DB). Da wir in der Realwelt zwischen Gegenständen unterscheiden können (sie besitzen quasi eine Identität), ist diese Unterscheidbarkeit zur Gewährleistung einer eindeutigen Abbildung auch für Datenbankobjekte gefordert. In der Realwelt unterscheiden wir zwischen unterschiedlichen Gegenständen aufgrund unterschiedlicher Eigenschaften (z. B. den Lieferanten aus Essen von dem aus Düsseldorf, das Cabrio vom Mini-Van, das rote Auto von dem Auto mit grüner Farbe). Um diese Unterscheidung auch in der DB zu gewährleisten, muss jeder Entitytyp über identifizierende Attribute verfügen. Werte identifizierender Attribute (Schlüsselattribute) sind immer für alle Entities eines bestimmten Typs unterschiedlich. Manchmal bilden erst mehrere Attribute gemeinsam die identifizierende Eigenschaft, und manchmal gibt es auch verschiedene Attribute, die Entities eindeutig bestimmen. Identifizierende Eigenschaften sind in den meisten Datenbankmodellen von zentraler Bedeutung. Wir werden im Unterkapitel 3.6 nochmals auf sie zurückkommen und ihre Eigenschaften aus einem formaleren Blickwinkel betrachten. 2.3.1.1.3
Beziehungstyp
Beziehungstypen (relationship types, Assoziationstypen) beschreiben Beziehungen und Zusammenhänge zwischen Entitytypen. Eine Beziehung (relationship, Assoziation) ist eine bestimmte Instanz eines Beziehungstyps und beschreibt die individuellen Zusammenhänge zwischen Entities. Beispiel 2.6: Typ- vs. Ausprägungsebene (Beziehungstyp) In Abbildung 2.9 zeigen wir den Unterschied zwischen der Typ- und der Ausprägungsebene für Beziehungstypen. Über den Beziehungstyp „liefert“ werden Lieferanten zu Artikeln (und umgekehrt) in Beziehung gesetzt. Jede Ausprägung des Beziehungstyps beschreibt eine Zuordnung eines spezifischen Lieferanten zu allen Artikeln, die er liefert bzw. für einen bestimmten Artikel zu allen Lieferanten, die diesen Artikel im Programm haben. Beziehungstypen können auch Eigenschaften besitzen, wie in dem Beispiel das Attribut „Preis“, das den Preis eines ausgewählten Artikels bei einem bestimmten Lieferanten beinhaltet. Als den Grad (degree, Stelle) eines Beziehungstypen bezeichnet man die Anzahl der an der Beziehung beteiligten Entitytypen. Beziehungstyp „liefert“ aus Abbildung 2.9 ist vom Grad 2 (binäre Beziehung). Beziehungen können auch vom Grad 1 (rekursive Beziehung) oder n-äre Beziehungen (n Entitytypen sind an der Beziehung beteiligt) sein. Abhängig von der Art der Teilnahme der Entities an der Beziehung kann ein Beziehungstyp eine optionale oder eine totale Teilnahme festlegen. Bei einem totalen Beziehungstyp müssen alle Entities eines bestimmten Typs an einer Beziehung teilnehmen, während bei einem optionalen Beziehungstyp die Teilnahme an einer Beziehung für Ausprägungen des betroffenen Entitytyps freigestellt ist. Bei optionalen Beziehungstypen hatten wir den Fall, dass ein Entity entweder einmal oder eben keinmal an der entsprechenden Beziehung teilnimmt. Diesen Fall kann man verallge-
2.3 Anforderungsdokument
37
Abb. 2.9: Beziehungstyp „liefert“ mit Ausprägungen
meinern, indem man die Kardinalität (cardinality ratio, Komplexität) von Beziehungstypen einführt. Typische Kardinalitätsangaben sind 1:1, 1:N, N:1 oder N:M und beschreiben die Anzahl von Entities, die maximal an einer Beziehung teilnehmen können. Ein Beispiel für eine Beziehung der Form 1:1 ist Artikelart : Verpackungsart mit der Semantik, dass ein Artikel eines bestimmten Typs immer genau die Verpackung einer bestimmten Art bekommt, und dass zwei Artikel unterschiedlichen Typs nie eine Verpackung desselben Typs haben können. Eine Beziehung der Form 1:N stellt z. B. die Zuordnung zwischen Abteilung und Mitarbeiter dar. Ein bestimmter Mitarbeiter ist genau einer Abteilung zugeordnet, aber eine Abteilung besteht aus mehreren Mitarbeitern. Der in Abbildung 2.9 dargestellte Beziehungstyp „liefert“ besitzt die Kardinalität N:M, da ein bestimmter Artikel von unterschiedlichen Lieferanten bezogen werden kann und ein Lieferant mehrere Artikel in seinem Programm hat. Jeder Entitytyp, der an einem Beziehungstyp teilnimmt, nimmt an der Beziehung in einer entsprechenden Rolle teil. Die Zuordnung von Rollenbezeichnungen ist nicht immer einfach, da eine sinnvolle Rollenbezeichnung von der Leserichtung der Beziehung abhängig ist. Entities eines bestimmten Typs können miteinander auch in mehrfachen Beziehungen stehen. Ein Beispiel dafür sind die zwei Beziehungen „ist-zugeordnet“ und „leitet“ zwischen den Entitytypen „Mitarbeiter“ und „Abteilung“. Der erste Beziehungstyp repräsentiert die Semantik, welche Mitarbeiter welchen Abteilungen zugeordnet sind, und der zweite Beziehungstyp setzt den Mitarbeiter, der die betrachtete Abteilung leitet, in Relation zur Abteilung. Die unterschiedlichen Strukturierungsmerkmale für Beziehungstypen sind in Abbildung 2.10 zusammengefasst. In einer ersten Analyse der Informationsanforderungen (siehe dazu auch Kapitel 3.1) werden Kandidaten für Entitytypen, Beziehungstypen und Attribute ermittelt. In einem nachfolgenden Schritt werden die Integritätsbedingungen festgelegt. Integritätsbedingungen sind Prädikate, die die Menge der Ausprägungen eines bestimmten Typs einschränken. Beispiele für mögliche Integritätsbedingungen auf der Ebene der Attribute sind das Festlegen bestimmter Wertebereiche, Existenzabhängigkeiten (gültige Werte eines Attributes müssen als Attributwert bereits in
38
2 Anforderungserhebung und -analyse
Abb. 2.10: Strukturierungsmerkmale für Beziehungstypen
einem anderen Entity existieren) und Beziehungen zwischen Attributwerten innerhalb eines Entities. Beispiele für Integritätsbedingungen auf der Ebene der Entitytypen sind Schlüsselbedingungen für die Gewährleistung von Eindeutigkeit, Existenzabhängigkeiten von Entities unterschiedlicher Typen oder Sicherheitseinschränkungen. Integritätsbedingungen für Beziehungstypen werden durch den Grad, die Kardinalität und die Art der Teilnahme beteiligter Entities an der Beziehung beschrieben. Um die definierten Begriffe zu verdeutlichen, betrachten wir zunächst eine vereinfachte Darstellung der Informationsanforderungen eines typischen Bestellvorganges. Auf dieses Beispiel werden wir später wieder zurückkommen.
Beispiel 2.7: Informationsanforderungen an einen Bestellvorgang Ein Handelsunternehmen vergibt Bestellaufträge an Lieferanten. Aufträge bestehen aus Auftragspositionen, die wiederum genau einem bestellten Artikel entsprechen. Nach Durchführung der Lieferung schickt der Lieferant eine Rechnung, die unterschiedliche Rechnungspositionen aufweist. In der hier verwendeten vereinfachten Darstellung sind Aufträge durch eine eindeutige Auftragsnummer (Auftrags-Nr) und durch das AuftragsDatum beschrieben. Jede Auftragsposition bezeichnet den bestellten Artikel über seine eindeutige Artikel-Nr, die Artikel-Bezeichnung und seinen Preis. Des Weiteren enthält jede Auftragsposition noch die Bestellmenge (Anzahl). Über Lieferanten soll in der DB der Name (Lief-Name), eine fortlaufende Nummer als Identifikator (Lief-Nr), ihre Anschrift und ihre Kontonummer (Konto-Nr) gespeichert werden. Rechnungen haben eine eindeutige Rechnungsnummer (Rech-Nr), weisen einen Endbetrag (Rech-Betrag) und einen Steuersatz auf und geben eine Zahlungsart vor. Jede Rechnungsposition muss einer Auftragsposition entsprechen. Über die bestellten Artikel soll die Artikelnummer (Artikel-Nr), ihre Bezeichnung und der Standort des Artikels im Lager gespeichert werden. Aus diesen Informationsanforderungen lassen sich Kandidaten für Entitytypen und Beziehungstypen wie folgt herleiten (siehe Abbildung 2.11):
Um zu einer besseren Darstellungsform zu gelangen, werden die Eigenschaften von Entitytypen und Beziehungstypen in einem Datenanforderungsformular (Entitykatalog) als Teil des Anforderungsdokumentes eingetragen. In der Praxis geht die Analyse der erhobenen Informationsanforderungen mit der strukturorientierten Modellbildung (siehe Unterkapitel 3.1) einher. Die Informationen aus den Datenanforderungsformularen werden in ein ERM übertragen, und
2.3 Anforderungsdokument
39
Kandidaten für Entitytypen: Auftrag: Auftrags-Nr,Auftrags-Datum Auftragsposition: Lieferant: Rechnung:
Artikel-Nr,Artikel-Bezeichnung,Anzahl, Preis Lief-Nr, Lief-Name,Anschrift, Konto-Nr Rech-Nr, Rech-Betrag, Steuersatz, Zahlungsart
Rechnungsposition: Artikel:
Artikel-Nr,Artikel-Bezeichnung,Anzahl, Preis Artikel-Nr,Artikel-Bezeichnung, Standort
Kandidaten für Beziehungstypen: "Geht-an": Auftrag : Lieferant ÄN:1Ô
"Enthält":
Ein Auftrag geht an einen bestimmten Lieferanten und ein Lieferant kann mehrere Aufträge erhalten. Auftrag :Auftragsposition, Ä1:NÔ
"Verweist-auf":
Ein Auftrag besteht aus mehreren Auftragspositionen. Eine Auftragsposition ist genau einemAuftrag zugeordnet. Auftragsposition :Artikel, ÄN:1Ô
"Legt":
"Besteht-aus":
"Entspricht":
JedeAuftragsposition verweist auf genau einenArtikel. Ein bestimmterArtikel kann jedoch in mehreren Positionen vorkommen. Lieferant : Rechnung, Ä1:NÔ Jede Rechnung ist genau einem Lieferanten zugeordnet. Es können jedoch von einem Lieferanten mehrere Rechnungen existieren. Rechnung : Rechnungsposition, Ä1:N Ô Jede Rechnung besteht aus mehreren Rechnungspositionen und jede Position ist genau einer Rechnung zugeordnet. Rechnungsposition :Auftragsposition, Ä1:1Ô Jeder Rechnungsposition ist genau eine Auftragsposition zugeordnet und
Abb. 2.11: Teil der Informationsanforderungen an Entitytyp „Auftrag“
die Entitykataloge dienen der näheren Beschreibung der Entity-Relationship-Diagramme. Abbildung 2.11 zeigt anhand einer Auswahl der Anforderungen an den Entitytyp „Auftrag“ eine mögliche Strukturierung eines Datenanforderungsformulars. Die Entscheidung, ob ein Ereignis der Realität als Entitytyp, als Beziehungstyp oder als Attribut dargestellt werden soll, ist nicht immer einfach und hängt oft von der subjektiven Einschätzung des Systemanalytikers ab. Das bedeutet, dass es oft die alleinig richtige Lösung nicht gibt, und dass ein Ereignis der Realwelt unterschiedlich modelliert werden kann. Bevor wir einige informelle Richtlinien zur Herleitung von Entitytypen, Beziehungstypen und Attributen besprechen werden, wollen wir auf Beispiel 2.7 noch einmal kurz eingehen, um unsere Entwurfsentscheidungen zu argumentieren. Dem Leser könnten bei der Analyse der Informationsanforderungen folgende Fragen durch den Kopf gegangen sein: • Warum kommt das betrachtete Handelsunternehmen nicht vor? Weder in Form eines Entitytyps noch als Attribut wird auf das betrachtete Unternehmen eingegangen.
40
2 Anforderungserhebung und -analyse
1. Beschreibung des Entitytyps: Name: Geschätzte Anzahl: Integritätsbedingungen: Beschreibung: 2. Beschreibung der Attribute: Attributname: Beschreibung: Wertebereich: Wertebereichseinschränkungen: Wertemenge: Prädikate: Referentielle Abhängigkeiten: Null-Wert erlaubt? Wiederholungsfaktor der Werte des Entitytyps: Anzahl eindeutiger Werte im Entitytyp: Primärschlüssel (Ja/Nein): Abhängigkeiten mit weiteren Attributen:
Auftrag 10.000 eingehende Aufträge Auftrags-Nr Eindeutige Nummer 1 - 99999 Ganze Zahlen Keine Nein Keine Wdh. Ja Auftrags-Datum
3. Beschreibung der Beziehungstypen: Beziehungsname: Beschreibung des Beziehungstyps: Teilnehmende Entitytypen: Kardinalität der Beziehung: Verbindung (mit allen Beteiligten Entitytypen): Obligatorisch / Optional: Attribute des Beziehungstyps: Attributname: Beschreibung: Wertebereich: Einschränkungen des Wertebereichs: Wertemenge: Prädikate: Referentielle Abhängigkeiten: Null-Wert erlaubt? Wiederholungsfaktor der Werte des Beziehungstyps: Anzahl eindeutiger Werte des Beziehungstyps:
Geht-an Auftrag geht an Lieferanten Auftrag; Lieferant N:1 Kunde Obligatorisch Keine -
Abb. 2.11: Teil der Informationsanforderungen an Entitytyp „Auftrag“ (Fortsetzung)
Das Unternehmen kommt nicht vor, da wir ein einziges Unternehmen betrachten, dessen Einkaufsabteilung Bestellungen zentral vornimmt. Würden wir in das Beispiel Filialen aufnehmen, die selbstständig Bestellungen durchführen können, so wäre die Aufnahme eines Entitytyps „Filiale“ mit für Filialen spezifischen Eigenschaften sinnvoll. • Warum reicht es aus, den Standort eines Artikels im Lager über ein einziges Attribut abzubilden? Wäre es nicht sinnvoll, einen eigenen Entitytyp zu erzeugen und ihm zusätzliche Eigenschaften zu geben? Das wäre eine sinnvolle Lösung, wenn das betrachtete Handelsunternehmen mehrere Lagerstätten hätte und jedes Lager mit individuellen Eigenschaften beschrieben ist. In unserer vereinfachten Darstellung gehen wir jedoch nur von einem einzigen Lager aus, und in diesem Lager hat jeder Artikel ausschließlich einen Standort. Des Weiteren gibt es keine
2.3 Anforderungsdokument
41
zusätzlichen Hinweise über Eigenschaften, die den Standort betreffen (wie z. B. die Kapazität). • Ist es notwendig, Auftrag und Auftragsposition bzw. Rechnung und Rechnungsposition als jeweils einzelne Entitytypen zu modellieren? Würde es nicht ausreichen, Auftrag und Auftragsposition als einen einzigen Entitytyp (z. B. als Bestellung) zusammenzufassen? Dies wäre nur dann sinnvoll, wenn die Auftrags-Nr und das Auftrags-Datum direkt der Bestellung zugeordnet wären. Wäre dies nicht der Fall, dann müssten sie für n Auftragspositionen (n − 1)-mal redundant mitgeführt werden. • Warum war es notwendig, einen Entitytyp „Auftrag“ einzuführen? Wäre es nicht sinnvoller gewesen, zwischen dem Entitytyp „Lieferant“ und dem Entitytyp „Lagerartikel“ einen Beziehungstyp „liefert“ einzuführen? Der Beziehungstyp könnte die relevanten Attribute wie Auftrags-Nr, Auftrags-Datum, Artikel-Nr, Artikel-Bezeichnung, Anzahl und Preis beinhalten? Das wäre durchaus eine akzeptable Lösung, die jedoch zwei wesentliche Probleme beinhalten würde. Erstens würde die Information über Auftrags-Datum wieder redundant für mehrere Auftragspositionen gespeichert werden, und zweitens wäre es nicht mehr möglich, Auftragspositionen direkt Rechnungspositionen zuzuordnen. Dies ist dann sinnvoll, wenn man die Bezahlung von Teillieferungen vorsieht, die fällig werden, bevor der Rest des Auftrags zu bezahlen ist. In diesem Beispiel könnten dem sorgfältigen Leser möglicherweise auch unerwünschte Redundanzen aufgefallen sein: • Warum wird Anzahl und Preis in den Entitytypen „Auftragsposition“ und in „Rechnungsposition“ und Artikel-Bezeichnung in Entitytypen „Auftragsposition“, „Rechnungsposition“ und „Artikel“ geführt? Auch das könnte zumindest zwei Ursachen haben. Zum einen könnte es sich um abgeleitete Attribute handeln, zum anderen könnte es der Fall sein, dass die Bezeichnungen in den Produktkatalogen des Lieferanten mit den Bezeichnungen, wie sie im betrachteten Handelsunternehmen verwendet werden, nicht übereinstimmen. 2.3.1.2
Vorgehensweisen für die statische Analyse
Zur Analyse von Informationsanforderungen (Strukturanalyse, statische Analyse) sind prinzipiell zwei Vorgehensstrategien möglich: Top-down und Bottom-up. Die Top-down-Strategie geht von im Problemraum erkannten Entitytypen aus, denen Attribute und Beziehungstypen hinzugefügt werden. Die Bottom-up-Strategie geht von bekannten Informationseinheiten aus, aus denen dann Entitytypen und Beziehungstypen gebildet werden. Wie wir bereits gesehen haben, ist die Entscheidung für ein bestimmtes Strukturierungskonzept oft von der subjektiven Einschätzung des Systemanalytikers abhängig und nicht immer leicht nachvollziehbar. Aus der Literatur sind jedoch einige Regeln und Ratschläge bekannt, die neben der Erfahrung des Analytikers mithelfen, aus den Anforderungsspezifikationen Entitytypen, Beziehungstypen und Attribute zu erkennen.
42
2 Anforderungserhebung und -analyse
Bevor man für die Darstellung eines erhobenen Sachverhaltes die endgültige Entscheidung für ein bestimmtes Strukturierungsprinzip vornimmt, ist es oft sinnvoll, vorerst Kandidaten aufzustellen und die Wahl durch typische Beispiele zu belegen. Entitytypkandidaten sind meist Entitytypen, wenn sie entweder reale oder abstrakte Objekte des betrachteten Problemraumes (wie z. B. Unternehmen, Abteilungen, Kostenstellen, Konten, Artikel), natürliche Personen (wie z. B. Mitarbeiter, Kunden, Lieferanten), wichtige Ereignisse (wie z. B. Rechnungsabschluss, Inventur, Bilanz, Geschäftsberichte) oder allgemein gültige Grundsätze und Gepflogenheiten (wie z. B. Zahlungsbedingungen, Rechtsvorschriften, Handelswaren, . . . ) darstellen. Entitytypkandidaten sind Entitytypen, wenn sie eine eigene Bedeutung besitzen, d. h. wenn sie durch weitere Eigenschaften beschrieben sind und sich ihre Ausprägungen voneinander unterscheiden. Entitytypkandidaten werden nicht zu Entitytypen, wenn sie das Ergebnis von Berechnungen oder Funktionen darstellen (wie z. B. Auswertungen oder Statistiken) und nur als Ergebnis und nicht als eigenständiges Objekt im Realitätsausschnitt Bedeutung finden. Sind einmal Entitytypen identifiziert, kennt man in vielen Fällen bereits auch die meisten Attribute, die den jeweiligen Entitytyp näher charakterisieren. Nichtidentifizierende Attribute besitzen keine Identität. Darunter verstehen wir, dass die Existenz eines Attributwertes nur nach Zuordnung zu einem Entity Sinn macht, und dass die Attribute auch nicht durch weitere Eigenschaften näher beschrieben werden. Beziehungstypen kann man erkennen, indem man die gefundenen Entitytypen einander gegenüberstellt und nach in der Realität existierenden Verknüpfungsaussagen untersucht. Das Herleiten von binären Beziehungstypen ist so über paarweise Betrachtungen von Entitytypen leicht möglich, das Herleiten von n-ären Beziehungstypen gestaltet sich schwieriger. Da Beziehungstypen auch Attribute besitzen können, die Beziehungen näher spezifizieren, ist genau abzuwägen, ob die Attribute nun Eigenschaften des Beziehungstyps oder Eigenschaften der an der Beziehung beteiligten Entitytypen darstellen. Auch hier ist schließlich die Erfahrung des Systemanalytikers gefordert. In der Praxis geht die Analyse der statischen Anforderungen mit der strukturorientierten Modellbildung (siehe Unterkapitel 3.1) einher. Für eine detailliertere Analyse und weiterführende Modellbildung wird dann sehr oft das ERM eingesetzt, das auf die hier beschriebenen Konzepte aufbaut.
2.3.2
Funktionale Anforderungen
Funktionale Anforderungen spezifizieren die betrieblichen Funktionen, die ein System oder eine Systemkomponente erfüllen bzw. zur Verfügung stellen muss. Dabei werden betriebliche Vorgänge algorithmisch beschrieben. Der besondere Schwerpunkt liegt auf der Transformation von Eingabegrößen durch Prozesse in Ausgabegrößen. Im Rahmen der Analyse der funktionalen Anforderungen (funktionsorientierte Modellbildung) ist es erwünscht, einen Überblick über die Prozessaktivitäten im geplanten System zu gewinnen. Dabei interessiert vorerst nicht die zeitliche Reihenfolge der Abarbeitung unterschiedlicher Prozesse sondern eher die Frage „Was leistet der Prozess?“ oder die Frage „Wie erreicht ein Prozess sein Ziel?“. Um komplexe Systeme analysieren und besser beschreiben zu können, unterstützen die meisten Verfahren zur Analyse funktionaler Anforderungen unterschiedliche Abstraktionsebenen (Verdichtungsebenen), auf denen unter Verwendung un-
2.3 Anforderungsdokument
43
terschiedlicher Detaillierungsgrade betriebliche Abläufe von ihrer Entstehung bis hin zu ihrer Beendigung beschrieben werden können. Die Analyse der funktionalen Anforderungen ist im Rahmen des Datenbankentwurfes aus zwei Gründen von Bedeutung: Zum einen fließen funktionale Anforderungen in eine strukturund funktionsorientierte Modellbildung (siehe Unterkapitel 3.2) direkt ein, zum anderen bilden funktionale Anforderungen für viele implementationstechnische und physische Entwurfsentscheidungen eine wichtige Grundlage. 2.3.2.1
Analyse mit Datenflussdiagrammen
Funktionale Anforderungen werden als Funktionsmodell beschrieben. Funktionsmodelle bestehen i.a. aus einem oder mehreren Datenflussdiagrammen, die den Datenfluss beginnend von externen Eingaben über unterschiedliche Prozesse und interne Datenspeicher bis hin zu externen Ausgaben zeigen. Ein Datenflussdiagramm (DFD) ist eine grafische Darstellungsform funktionaler Anforderungen. Es besteht aus vier grundlegenden Konzepten: Prozesse, die Daten transformieren, Datenflüsse, die Daten bewegen, Datenspeicher, die anzeigen, dass Daten auf externe Speicher abgelegt werden, und Akteure, die Daten generieren und konsumieren. Die verwendete Notation in DFD weicht bei verschiedenen Autoren voneinander ab. Prozesse werden entweder als Kreise, Ellipsen oder Rechtecke mit abgerundeten Ecken dargestellt. Einige Autoren unterscheiden explizit zwischen Datenfluss, Materialfluss und Kontrollfluss und verwenden für ihre Darstellung unterschiedliche Arten von Pfeilen. Andere Autoren treffen diese Unterscheidung nicht und sprechen allgemein von „Wertfluss“. Datenspeicher werden entweder durch zwei parallele Linien oder durch Rechtecke mit offenen rechten Seiten dargestellt. Akteure werden meist in Form von Rechtecken gezeichnet. Die in diesem Buch gewählte Notation zur Darstellung von DFD wird in Abbildung 2.12 zusammengefasst.
Abb. 2.12: Elemente im Datenflussdiagramm
Prozesse sind für die Datentransformation verantwortlich. In Abhängigkeit vom gewählten Detaillierungsgrad wird ein Prozesssymbol entweder zur Darstellung einer Folge von Arbeitsschritten benutzt, die innerhalb einer Funktionseinheit anfallen, oder jeder einzelne Arbeitsschritt wird selbst als ein eigener Prozess dargestellt. Gezeichnet werden Prozesse als Rechtecke mit abgerundeten Ecken. Jeder Prozess hat eine Nummer, die auf eine nicht im Diagramm enthaltene detaillierte Prozessbeschreibung verweist und den Prozess näher erläutert, eine Bezeichnung und einen Vermerk, wer den Prozess ausführt. Die ausführende Stelle
44
2 Anforderungserhebung und -analyse
kann entweder eine Person in einer bestimmten Funktion, ein Anwendungsprogramm oder aber auch eine Organisationseinheit sein. Die Nummerierung der Prozesse kann ein Hinweis auf eine zeitliche Abfolge sein. Jeder Prozess hat eine feste Anzahl einmündender und entspringender gerichteter Kanten, die Datenflüsse beschreiben und von denen jeder einen Wert eines bestimmten Typs befördert. Jede Kante kann beschriftet sein und somit die Rolle der über diese Kante fließenden Daten bei der Transformation bezeichnen. Beispiel 2.8: Prozess im Datenflussdiagramm In Abbildung 2.13 zeigen wir die grafische Darstellung von Prozessen in DFD. Im Prozess „Erhöhe Lagerbestand“ wird ausgehend von einem bestehenden Lagerbestand, einem Lieferumfang (Anzahl) und einer Artikelnummer (Artikel-Nr) der aktualisierte Lagerbestand des bezeichneten Artikels berechnet.
Abb. 2.13: Prozess im Datenflussdiagramm
Datenspeicher sind die passiven Elemente in einem DFD. Sie führen Operationen nicht selbstständig aus, sondern reagieren ausschließlich auf Anforderungen zum Speichern und Einlesen von Daten. Über Datenspeicher ist es möglich, auf Daten in beliebiger Reihenfolge zuzugreifen. Datenspeicher können z. B. Karteien, Verzeichnisse oder aber auch Tabellen in DB sein. Die geplante technische Realisierung eines Datenspeichers ist zu diesem Zeitpunkt noch nicht von Bedeutung. Datenspeicher werden durch ein auf der rechten Seite offenes Rechteck dargestellt und mit einer Bezeichnung und einer Nummer gekennzeichnet. Die Nummer verweist auf beschreibenden Text, der nicht in die grafische Darstellung des DFD aufgenommen wird. Am Datenspeicher entspringende gerichtete Kanten geben die Richtung an, in die der Datenfluss stattfindet. Einmündende Kanten deuten Schreiboperationen im Datenspeicher an, mit denen abgelegte Informationen ergänzt oder verändert werden. Ausgehende Kanten weisen auf Leseoperationen hin, mit denen Informationen aus dem Speicher gelesen werden. Beispiel 2.9: Datenspeicher im Datenflussdiagramm Zwei Beispiele für die Verwendung von Datenspeichern in Datenflussdiagrammen sind in Abbildung 2.14 dargestellt. In Abbildung 2.14(a) wird ein DFD zur Berechnung des aktuellen Lagerbestandes angegeben, in dem der alte Lagerbestand aus dem Artikelverzeichnis
2.3 Anforderungsdokument
45
gelesen wird, Prozess P1 den neuen Lagerbestand berechnet und diesen im Artikelverzeichnis ablegt, um ihn dann noch an weitere Prozesse (z. B. Kostenrechnung) zur Weiterverarbeitung zu übergeben. Abbildung 2.14(b) zeigt das Eintragen von Außenständen in ein Datenverzeichnis für offene Rechnungen. Prozess P2 „Rechnung erstellen“ erzeugt aus Bestelldaten und Kundendaten Rechnungen und schreibt sie in den Datenspeicher D2.
Abb. 2.14: Datenspeicher im Datenflussdiagramm
Akteure stellen die aktiven Komponenten in einem DFD dar. Sie aktivieren einen Datenfluss im System, indem sie Werte erzeugen, und beenden einen Datenfluss, indem sie Werte verbrauchen. Aus diesem Grund sind die Bezeichnungen Quelle und Senke bzw. Initiatoren und Terminatoren für Akteure ebenso gebräuchlich. Akteure sind somit Sender und Empfänger von Informationseinheiten und folglich an den Ein- und Ausgängen von DFD angeordnet. Grafisch werden sie als Rechtecke dargestellt. Pfeile zwischen Akteuren und dem DFD bezeichnen Eingaben an und Ausgaben durch das Diagramm. Beispiel 2.10: Akteure im Datenflussdiagramm Wir betrachten Lieferanten als Akteure, weil sie jedes Mal, wenn sie neue Lieferungen anbringen, einen Datenfluss in Form von Artikel-Nr und der gelieferten Stückzahl initiieren. In Abbildung 2.15 ist eine entsprechende Situation dargestellt.
Abb. 2.15: Akteure im Datenflussdiagramm
46
2 Anforderungserhebung und -analyse
Datenflüsse verbinden Prozesse, Datenspeicher und Akteure und werden üblicherweise als gerichtete Kanten zwischen Erzeuger und Verbraucher im Datenflussgraph dargestellt. Die Kanten sind mit der Bezeichnung der Daten markiert. Oft wird auch zwischen Datenfluss und Materialfluss unterschieden. Ein Datenfluss kann an mehrere Verbraucher gehen, bzw. aus unterschiedlichen Werten kann ein Datentyp einer höheren Aggregationsstufe erzeugt werden. Daten können während des Datenflusses jedoch nicht verändert werden.
Beispiel 2.11: Formen von Wertfluss im Datenflussdiagramm In Abbildung 2.16 zeigen wir (a) das Kopieren, (b) das Verzweigen und (c) das Bilden eines Datenaggregates in Datenflüssen. In (d) unterscheiden wir explizit zwischen Materialfluss und Datenfluss, indem wir für ihre Darstellung unterschiedliche Pfeiltypen verwenden.
Abb. 2.16: Formen von Wertfluss im Datenflussdiagramm
Für die Analyse großer und komplexer Systeme werden in der Literatur unterschiedliche Strategien und Vorgehensweisen vorgeschlagen. Auch hier gibt es keine optimale Strategie. Für jedes Problem ist neu zu prüfen, welche die geeignetste Vorgehensweise ist. Prinzipiell unterscheidet man zwischen Vorgehensweisen, die von einem ersten Grobentwurf ausgehen und in mehreren Verfeinerungsschritten ein Feinkonzept entwickeln (Top-down-Verfahren), die von bekannten Elementprozessen ausgehen und daraus ein funktionales Modell auf hohem Abstraktionsniveau erzeugen (Bottom-up-Verfahren), Mischformen aus Top-down- und Bottom-up-Vorgehensweisen und Inside-out-Strategien, die innerhalb einer Aufgabenstellung beginnen und versuchen, alle nötigen Prozesse, Datenspeicher, Datenflüsse und Terminatoren, die zur Lösung des Problems notwendig sind, herzuleiten. Alle Strategien bestehen aus einer Menge von Schematransformationen, die ein Ausgangsschema in ein Ergebnisschema transformieren. Bevor wir auf die unterschiedlichen Vorgehensweisen zur funktionalen Analyse eingehen werden, fassen wir in Abbildung 2.17 die wichtigsten Schematransformationen für DFD zusammen:
2.3 Anforderungsdokument
Abb. 2.17: Schematransformationen in Datenflussdiagrammen nach [BaCN92]
47
48
2 Anforderungserhebung und -analyse
• Schematransformation T1 spaltet einen Prozess in zwei Prozesse auf. Dies ist notwendig, wenn festgestellt wird, dass innerhalb eines Prozesses eine detailliertere Darstellung gewünscht wird und der Datenfluss zwischen Subprozessen dargestellt werden soll. • Schematransformation T2 verfeinert einen Prozess durch Aufspaltung in zwei Prozesse und einen Datenspeicher. Dies wird notwendig, wenn zwei Teilprozesse Daten zu einem unterschiedlichen Zeitpunkt benötigen und daher zwischenspeichern müssen. • Schematransformation T3 verfeinert einen Prozess durch Aufspaltung in zwei unabhängige Prozesse, die nicht über einen Datenaustausch in Beziehung stehen. • Schematransformation T4 spaltet einen Datenfluss in mehrere unabhängige Datenflüsse. Diese Transformation wird angewendet, wenn festgestellt wird, dass die über die Kante fließenden Daten voneinander unabhängige Informationseinheiten darstellen. • Schematransformation T5 verfeinert einen Datenfluss in zwei Datenflüsse und einen Prozess. Sie wird notwendig, wenn festgestellt wird, dass der Datenfluss im Ausgangsschema eine verdeckte Transformation beinhaltet. • Schematransformation T6 verfeinert einen Datenspeicher in mehrere unabhängige Datenspeicher. Sie wird notwendig, wenn festgestellt wird, dass unterschiedliche Prozesse auf voneinander unabhängige Teile des Datenspeichers im Ausgangsschema zugreifen. • Schematransformation T7 verfeinert einen Datenspeicher durch Aufspaltung in mehrere Datenspeicher und einen weiteren Prozess. Sie wird notwendig, wenn festgestellt wird, dass im Datenspeicher des Ausgangsschemas verdeckte Datentransformationen stattfinden. 2.3.2.2
Vorgehensweisen für die funktionale Analyse
Ähnlich wie bei der Analyse von Informationsanforderungen können bei der Analyse funktionaler Anforderungen unterschiedliche Vorgehensweisen angewendet werden. Wir wollen drei dieser Vorgehensweisen anhand eines Beispiels genauer betrachten. 2.3.2.2.1
Top-down-Vorgehensweise
Das Top-down-Verfahren ist die am häufigsten zur Anwendung kommende Vorgehensweise. Man beginnt mit einem so genannten Kontextdiagramm, das die betriebliche Aufgabenstellung auf einem sehr hohen Abstraktionsniveau zeigt. In den meisten Fällen besteht das Kontextdiagramm aus einem zentralen Prozess und seinen Schnittstellen nach außen. Zumindest ein Initiator und ein Terminator sind notwendig. In weiteren Schritten wird der Elementarprozess in Teilprozesse zerlegt. Dabei sollte man so vorgehen, dass zuerst jene Prozesse gespalten werden, die die wenigsten Datenströme referenzieren. Der Schritt der Verfeinerung wird so lange fortgesetzt, bis der gewünschte Abstraktionsgrad erreicht bzw. bis keine Zerlegung der Prozesse mehr möglich ist. Beispiel 2.12: Top-down-Analyse einer Auftragsbearbeitung Wir betrachten die Top-down-Strategie anhand einer Analyse der Auftragsbearbeitung in einem Produktionsunternehmen. Ein Kunde informiert sich über ein Produkt. Sind alle
2.3 Anforderungsdokument
49
Produktionsfaktoren vorrätig, bestellt der Kunde, und der Auftrag geht in die Fertigung. Kann das Produkt nicht oder nicht zeitgerecht erzeugt werden, wird der Auftrag nicht angenommen, und der Kunde erhält eine Absage. Eine entsprechende Top-down-Analyse der funktionalen Anforderungen ist in Abbildung 2.18 dargestellt.
Abb. 2.18a,b: Top-down-Vorgehensweise, Schritt 1 und 2
In Abbildung 2.18(a) beginnen wir mit einem Kontextdiagramm, bestehend aus einem Prozess, mit dem die Auftragsbearbeitung auf höchstem Abstraktionsniveau beschrieben ist. Im nächsten Schritt (b) prüft die Auftragsbearbeitung den Auftrag, gibt ihn entweder an die Fertigung weiter oder informiert den Kunden über die Ablehnung. Im dritten Schritt (c) erfolgt eine weitere Verfeinerung. Die Auftragsprüfung registriert den Kunden, falls er noch nicht in der Kundendatenbank vorhanden ist. Danach wird überprüft, ob alle notwendigen Produktionsfaktoren verfügbar sind. Wenn nicht, geht eine Absage an den Kunden. Sonst wird der Auftrag angenommen. In diesem Arbeitsschritt sind nun mehrere Verfeinerungen durchgeführt worden. Zuerst wird „Auftrag prüfen“ durch drei Prozesse („Kunden aufnehmen“, „Produktionsmittel prüfen“, „Absage schreiben“) ersetzt. Zwei dieser Prozesse benötigen einen Datenspeicher. Prozess „Kunden aufnehmen“ sucht zuerst den Kunden in der Kundendatei. Wird der Kunde nicht gefunden, legt der Prozess die Daten im Speicher ab. Prozess „Produktionsmittel prüfen“ liest Daten aus der Arbeitsvorbereitung, um zu prüfen, ob alle Produktionsfaktoren noch verfügbar sind, und der Auftrag angenommen werden kann. In Schritt 4 wird nochmals verfeinert. Den Auftrag anzunehmen bedeutet, ihn abzuspeichern und einen Fertigungsauftrag auszustellen. Für den Fertigungsauftrag werden Kundendaten benötigt. In Abbildung 2.18(d) haben wir zwischen den Prozessen „Produktionsmittel prüfen“ und „Auftrag erstellen“ eine Zwischenspeicherung in einem Datenspeicher vorgenommen. Um einen Auftrag an die Fertigung weiterzugeben, sind noch die Kun-
50
2 Anforderungserhebung und -analyse
Abb. 2.18c,d: Top-down-Vorgehensweise (Fortsetzung)
dendaten notwendig. In Schritt 3 wurde durch Prozess „Kunde aufnehmen“ ein entsprechender Datenspeicher bereits definiert. Aufgrund der schrittweisen Verfeinerung und der Top-down-Vorgehensweise und der damit verbundenen Trennung von Datenspeichern unterschiedlicher Abstraktionsniveaus ist es jedoch nicht möglich, diesen Datenspeicher auf der Ebene 4 zu benutzen. Zwangsläufig muss aufgrund dieser Einschränkung im Funktionsmodell redundante Datenhaltung vorgesehen werden. Die Inhalte des Datenspeichers „Kundendatei“ sind in Schritt 3 und in Schritt 4 möglicherweise unterschiedlich.
2.3 Anforderungsdokument
51
Bei der Top-down-Zerlegung kann jeder Prozess durch ein neues DFD genauer spezifiziert werden. Als Konsistenzregel ist einzuhalten, dass alle in den Prozess einmündenden Datenflüsse auch in das DFD einmünden, das diesen Prozess verfeinert. Wann soll nun die hierarchische Verfeinerung beendet werden? Die Antwort auf diese Frage hängt sicherlich von der Komplexität des betrachteten Prozesses ab. Als allgemeiner Richtwert wird von einigen Autoren als optimales Ende einer Verfeinerung ein Zustand angegeben, in dem jeder Prozess auf der „untersten“ Hierarchieebene auf etwa einer Textseite durch Pseudocode, ein Struktogramm oder eine Spezifikation in natürlicher Sprache beschrieben werden kann. Für die meisten Problemstellungen ist die Top-down-Vorgehensweise zur Erstellung eines DFDs die vorteilhafteste Alternative. Bei Verwendung dieser Strategie kann es jedoch auch zu Problemen kommen. Datenredundanzen können auftreten, wenn zwei Prozesse aus unterschiedlichen Abstraktionsebenen einen Datenspeicher benötigen. Bei enger Auslegung einer Top-down-Vorgehensweise führt das unweigerlich zu zwei eigenständigen Speichern. Bei einem System mit vielen unterschiedlichen Datenstrukturen und Routineprozessen, die in unterschiedlichen Teilbereichen angesiedelt sind, sollte man von der Verwendung der Topdown-Strategie Abstand nehmen und eher eine Bottom-up-Vorgehensweise wählen. 2.3.2.2.2
Bottom-up-Vorgehensweise
Die Bottom-up-Vorgehensweise ist eine Umkehrung der Top-down-Vorgehensweise, bei der, ausgehend von allen Elementarprozessen, durch Aggregation und Zusammenfassung ein Kontextdiagramm auf hohem Abstraktionsniveau entwickelt wird. Die Strategie geht davon aus, dass sämtliche Prozesse bereits bekannt sind. Beispiel 2.13: Bottom-up-Analyse einer Auftragsbearbeitung Wenn wir die Bottom-up-Strategie auf das Beispielszenario aus der Auftragsbearbeitung anwenden, ergibt sich das in Abbildung 2.19 dargestellte Bild. Wir beginnen mit der Aufstellung aller elementaren Prozesse, die in der Auftragsbearbeitung vorkommen können (siehe Abbildung 2.19(a)). Danach werden Initiatoren und Terminatoren sowie Datenflüsse von und zu den Prozessen, die direkt mit Initiatoren und Terminatoren interagieren, eingetragen (Schritt (b)). Im nächsten Schritt (c) werden alle weiteren Datenflüsse eingetragen. Die Reihenfolge der Analyse der Datenflüsse ist nicht von Bedeutung, da wir ja ausschließlich auf einem einzigen Abstraktionsniveau modellieren. Im abschließenden vierten Schritt (Abbildung 2.19(d)) werden alle Datenspeicher eingetragen. Aus der Lösung von Beispiel 2.13 wird erstmals der wesentliche Vorteil der Bottom-upMethode, nämlich die mehrfache Verwendung von Datenspeichern, ersichtlich. Da wir bei der Analyse des Prozesses „Auftrag erstellen“ feststellen, dass wir Daten aus einem Datenspeicher „Kundendatei“ auslesen und dieser Datenspeicher bereits existiert, können wir den bereits vorliegenden Speicher neuerlich verwenden. Bei Anwendung der Top-down-Vorgehensweise war das nicht möglich, da der Datenspeicher auf unterschiedlichen Verfeinerungsstufen angesprochen wurde. Bei der Bottom-up-Vorgehensweise operieren wir auf einer einheitlichen Ebene und können somit bestehende Datenspeicher mehrfach nutzen.
52
2 Anforderungserhebung und -analyse
Nachdem das DFD vollständig vorliegt, müsste man anfangen, die bestehenden Prozesse zusammenzufassen und unter Verwendung von Zwischendiagrammen ein Kontextdiagramm herzuleiten. Wir werden diesen Aggregationsschritt jedoch vernachlässigen, da die Besonderheiten der Bottom-up-Vorgehensweise in der Anfangsphase liegen und die einzelnen Zwischenschritte hin zum Kontextdiagramm aus der Darstellung in Abbildung 2.18 leicht abgeleitet werden können. Die reine Bottom-up-Vorgehensweise wird nur bei der Analyse kleinerer Systeme zum Einsatz kommen, da dem Entwickler im Vorhinein klar sein muss, wie das System funktioniert. Alle
Abb. 2.19a,b: Bottom-up-Vorgehensweise, Schritt 1 und 2
2.3 Anforderungsdokument
53
Elementarprozesse müssen bekannt sein. Neben der Vermeidung von Datenredundanz durch mehrere Datenspeicher mit ähnlichem Inhalt auf unterschiedlichen Abstraktionsniveaus ist als weiterer Vorteil der Bottom-up-Vorgehensweise bei der Erstellung eines DFD zu nennen, dass der Analysevorgang sehr schnell und effizient durchzuführen ist, da es sich bei den einzelnen Verfeinerungsschritten ausschließlich um Ergänzungen und nicht um Ersetzungen wie beim Top-down-Verfahren handelt.
Abb. 2.19c,d: Bottom-up-Vorgehensweise (Fortsetzung)
54
2 Anforderungserhebung und -analyse
2.3.2.2.3
Mischform aus Top-down und Bottom-up
In der Praxis wird die Top-down- und Bottom-up-Vorgehensweise zur Erstellung eines DFD oft miteinander kombiniert. Bei der Anwendung der Mischform ist es dem Entwickler überlassen, mit welcher Verfahrensweise er die Analyse beginnt. Bei komplexeren Anwendungen ist es angeraten, top-down zu beginnen und für alle Prozesse des Kontextdiagramms eigene individuelle DFD zu entwickeln. In einer nachfolgenden Analysephase werden die individuellen DFD bottom-up zu einem einzigen DFD zusammengefasst. Hat der Entwickler die Aufgabe, bereits existierende Prozesse in ein neues System zu integrieren, wird er den Bottom-up-Ansatz wählen und mit diesen Prozessen und zumindest je einem Initiator und Terminator beginnen. Bevor das System unübersichtlich wird, kann bei dieser Mischform auf die Top-down-Methode umgeschwenkt und auf einem höheren Abstraktionsniveau mit der Analyse fortgesetzt werden. Die Mischform zwischen Top-down- und Bottom-up-Verfahrensweise ist die am häufigsten angewendete Strategie, da sie aus beiden Strategien die Vorteile enthält. Die Anwendung der Methode setzt jedoch große Erfahrung voraus, da man den Wechsel zwischen den beiden Methoden zum richtigen Zeitpunkt durchführen muss. 2.3.2.2.4
Inside-out-Vorgehensweise
Eine interessante Variante, die einen völlig anderen Ansatz verfolgt, stellt die Inside-outStrategie dar. Im Gegensatz zu den vorher beschriebenen Ansätzen versucht man, ein Problem direkt zu lösen, ohne dabei ein Komplettsystem entwickeln zu wollen. Diese Strategie ist zur Analyse kleinerer Anwendungen geeignet, in denen rasch eine unkomplizierte Lösung für zumindest ein Teilproblem gewünscht wird. Die Methode beginnt mit einem Terminator und einer gezielten Aufgabenstellung. Mit der Aufgabenstellung im Hinterkopf verfolgt man den Datenfluss und ergänzt alle Prozesse, Datenspeicher, Datenflüsse und Terminatoren, die mit der Aufgabenstellung in Zusammenhang stehen. Alle diese Aktionen geschehen auf der untersten Hierarchieebene. Sobald das Teilproblem analysiert ist, endet diese Methode. Beispiel 2.14: Inside-out-Analyse einer Auftragsbearbeitung Die Inside-out-Strategie wird in Abbildung 2.20 dargestellt. In diesem Beispiel entwickeln wir für die schon bekannte Auftragsverwaltung ein Subsystem, das die Kommunikation mit dem Kunden beschreibt. In Abbildung 2.20(a) beginnen wir mit der Registrierung des Kunden. Dabei muss auf die Kundendaten zugegriffen werden und bei Neukunden ein Eintrag vorgenommen werden. Wenn wir die Analyse fortsetzen (Abbildung 2.20(b)) ersehen wir, dass die Produktionsmittel überprüft werden. Ergibt die Überprüfung, dass der Auftrag nicht übernommen werden kann, wird dem Kunden eine Absage geschrieben. Eine Auftragsbestätigung erfolgt nicht. Die Inside-out-Strategie endet an dieser Stelle, denn der Kunde hat auf seine Anfrage hin eine Antwort bekommen. In diesem Beispiel ist Kunde sowohl Initiator als auch Terminator des Datenflusses.
2.3 Anforderungsdokument
55
Abb. 2.20: Beispiel einer Inside-out-Vorgehensweise
Der Vorteil der Inside-out-Vorgehensweise gegenüber den anderen Methoden liegt darin, dass die Analyse auf die gleiche Art und Weise vorgenommen wird, wie das Diagramm später gelesen wird. Als Nachteil ist zu nennen, dass wir nur ein Teilsystem analysieren mit der Folge, dass später eine Integration von Teilsystemen notwendig wird, um zum Gesamtsystem zu gelangen. Die Anwendung dieser Vorgehensweise ist nur zu empfehlen, wenn das Teilsystem eine isolierte Aufgabe innerhalb des Gesamtsystems darstellt. 2.3.2.3
Ausgewählte Beispielmethoden
Die hier erwähnten Beispielmethoden zur Dokumentation und Analyse funktionaler Anforderungen stellen eine Auswahl aus der großen Zahl von publizierten Methoden und Verfahren dar. Die bekanntesten Methoden basieren auf dem Prinzip der funktionalen Zerlegung und dem Datenflussansatz. Sie gehen von einer Hauptfunktion aus und zerlegen diese in entsprechende Unterfunktionen. SADT, SA/SD und HIPO sind die am häufigsten verwendeten Verfahren. Alle drei Methoden unterstützen eine grafische Darstellungsform, die auch in einigen CASE-Werkzeugen (Computer Aided Software Engineering) zur automationsunterstützten funktionalen Analyse integriert ist. SA/SD (Structured Analysis, Structured Design) Die strukturierte Analyse (SA) wurde ebenfalls Ende der 70er Jahre entwickelt und ist heute der bekannteste datenflussorientierte Ansatz zur Darstellung und Analyse funktionaler Anforderungen. SA verwendet im Wesentlichen drei unterschiedliche Darstellungsformen:
56
2 Anforderungserhebung und -analyse
• Datenflussdiagramme • Datenverzeichnisse Sie dienen zur genauen Beschreibung aller im DFD enthaltenen Daten, Datenflüsse und Akteure • Prozessspezifikationen Sie dienen zur Beschreibung aller Prozesse, die am untersten Abstraktionsniveau eines DFDs angesiedelt sind. Prozessspezifikationen werden in einer Art Pseudocode dargestellt. Eine Ergänzung zu SA stellt der strukturierte Entwurf (SD) dar, der zusätzlich zu den in SA inkludierten Darstellungsformen Strukturpläne vorsieht, die zur Zerlegung eines Anwendungssystems in Module verwendet werden können. SADT (Structured Analysis and Design Technique) Der Grundgedanke in SADT besteht in der strukturierten Aufteilung aller Aktivitäten einer Organisation in einen funktionalen Bereich (Aktivitätsmodell) und einen strukturellen Teil (Datenmodell). SADT unterstützt ein Vorgehensmodell sowie eine grafische Notation aus beschrifteten, rechteckigen Kästchen und Pfeilen. Die Kästchen eines SADT-Diagramms können in hierarchisch tiefer liegenden Ebenen weiter verfeinert werden, wobei jedoch auf einer Hierarchieebene ausschließlich ein Kästchen liegen darf. Die Verfeinerung wird solange fortgeführt, bis der gewünschte Detaillierungsgrad vorliegt. Auf jeder Abstraktionsebene soll ein System auf zwei Arten dargestellt werden: zum einen als Datenmodell und zum anderen als Aktivitätsmodell. Diese duale Darstellung soll die wechselseitige Überprüfung des Modells auf Vollständigkeit und Konsistenz ermöglichen. Die meisten CASE-Werkzeuge auf der Basis von SADT beschränken sich jedoch meist auf die Aktivitätsdiagramme und ersetzen die Darstellung des strukturellen Teils der Anwendung durch Entity-Relationship-Diagramme. HIPO (Hierarchical Input, Process, Output) HIPO wurde von der Firma IBM Mitte der 70er Jahre entwickelt und beruht auf der Zerlegung einer Anforderung in die Komponenten Dateneingabe, Verarbeitung und Datenausgabe. Die Methode unterstützt ein grafisches Beschreibungsverfahren, das im Wesentlichen aus drei unterschiedlichen Formen von Diagrammen besteht. Das Hierarchiediagramm enthält die Hauptfunktionen und zeigt die hierarchische Zerlegung in Unterfunktionen. Aus diesem Diagramm kann man eine gute Gesamtübersicht eines Systems erhalten und den Zusammenhang unterschiedlicher Funktionen ersehen. Das Übersichtsdiagramm beschreibt für wichtige Funktionen die Dateneingaben, die einzelnen Verarbeitungsschritte sowie die durch die Funktion erzeugten Datenausgaben. Das Detaildiagramm unterscheidet sich vom Übersichtsdiagramm durch einen höheren Detaillierungsgrad und beschreibt jeden elementaren Verarbeitungsschritt mit seinen Ein- und Ausgabewerten. Zusätzlich zur grafischen Darstellung gibt es im Detaildiagramm die Möglichkeit, textuelle Beschreibungen, Entscheidungstabellen oder Ablaufdiagramme aufzunehmen. Die Methode HIPO eignet sich vornehmlich zur Dokumentation von funktionalen Anforderungen. Die Möglichkeit zur statischen Analyse der Anforderungen ist eingeschränkt. Eine
2.3 Anforderungsdokument
57
weitere Einschränkung stellt das Fehlen von Möglichkeiten zur genaueren Spezifikation der Eingabe- und Ausgabeflüsse von Daten in Funktionen dar. Einige Autoren stellen auch fest, dass sich Funktionsstrukturen im Unternehmen im Zeitablauf wesentlich rascher ändern als Datenstrukturen, und daher eine Analyse aufgrund der Zerlegung von Funktionen isoliert von der strukturellen Analyse der Anforderungen durchgeführt werden soll. Die funktionale Zerlegung besitzt als eigenständige Analysemethode daher heute kaum noch praktische Bedeutung.
2.3.3
Bearbeitungsanforderungen und dynamische Aspekte
Die Bearbeitungsanforderungen und die dynamischen Aspekte der Anwendung sind für die Erstellung eines konzeptuellen Datenmodells von untergeordneter Bedeutung, stellen aber für die Implementierung der DB und die Spezifikation der Programme, die auf die DB zugreifen, eine wichtige Grundlage dar. Dynamische Anforderungen zeigen das zeitabhängige Verhalten von Datenbankobjekten. Während der statischen Analyse werden die erhobenen Anforderungen zeitpunktbezogen analysiert. Das bedeutet, dass die Anforderungen eine auf einen bestimmten Zeitpunkt (den Erhebungszeitpunkt) bezogene Aussage darstellen. Viele der erhobenen Informationseinheiten (Entity- oder Beziehungstypen) können jedoch im Laufe ihrer Existenz verschiedene Zustände und damit verbunden verschiedene Werte annehmen. Ein Zustand einer Informationseinheit ist durch gleich bleibende Attributwerte und sich nicht verändernde Verknüpfungen zu in Beziehung stehenden Informationseinheiten charakterisiert. Ändert sich eine für die Anwendung relevante Eigenschaft, so wechselt z. B. ein Entity seinen Zustand. Unterschiedliche Zustände eines Entities vom Typ „Bestellung“ können z. B. vom Attribut „Status“ abhängig sein, das z. B. die Werte „erfasst“, „geliefert“, „teilgeliefert“, „storniert“, „offen“ u. a. annehmen kann. Zustandsveränderungen werden durch das Eintreten vordefinierter Ereignisse verursacht. Die Reaktion auf ein eingetretenes Ereignis hängt wieder vom aktuellen Zustand der Informationseinheit ab. Der Zyklus der Zustandsänderungen einer Informationseinheit wird auch als ihr Lebenszyklus bezeichnet. Im Zuge einer Analyse der dynamischen Aspekte der erhobenen Anforderungen werden zunächst Ereignisfolgen identifiziert, die in vielen Vorgehensmodellen als Szenarios bezeichnet werden. Ein Szenario erhält man, indem man ein existierendes System ausführt und die Ereignisfolgen notiert, oder indem man ein geplantes System gedanklich nachvollzieht und alle Ereignisabfolgen Schritt für Schritt zu einem Szenario zusammenfügt. Wenn ein Szenario feststeht, werden im nächsten Schritt die beteiligten Objekte identifiziert und in einem Ereignisabfolgediagramm dargestellt. Wir werden auf die Analyse der dynamischen Aspekte einer Datenbankanwendung im Zuge der objektorientierten Modellbildung (Unterkapitel 3.3) noch genauer eingehen. Beispiel 2.15: Szenario und Ereignisabfolgediagramm „Bestellvorgang“ Abbildung 2.21 enthält ein Beispiel für ein mögliches Szenario eines Bestellvorganges und ein entsprechendes Ereignisabfolgediagramm, das die Kommunikation zwischen Kunde und Lieferant darstellt und damit den Zustand der Bestellung widerspiegelt. Bearbeitungsanforderungen werden während der Analyse der geplanten Transaktionen untersucht. Dabei geht man davon aus, dass ein Großteil der wichtigsten Datenbanktransaktionen
58
2 Anforderungserhebung und -analyse
Abb. 2.21: Szenario und Ereignisabfolgediagramm „Bestellvorgang“
bereits zum Entwurfszeitpunkt der DB bekannt ist. Das Ziel der Transaktionsanalyse ist eine genaue Darstellung der systembedingten Eigenschaften der Transaktionen (Bearbeitungsanforderungen) im Hinblick auf eine spätere Implementierung der DB und der auf sie zugreifenden Programme zu erhalten. Da während der Transaktionsanalyse bereits gewisse Kenntnisse über die Struktur der Daten notwendig sind, erfolgt die Transaktionsanalyse gegen Ende der Analysephase oder oft erst auch als Teil des physischen Entwurfs der DB. Die erste Aktivität innerhalb der Transaktionsanalyse ist die Unterscheidung der Transaktionen in Datenbankanfragen und Datenbankmanipulationen. Eine Datenbankanfrage (database query) ist eine Transaktion, die ausschließlich die Ausgabe von Informationen beinhaltet. Eine Datenbankmanipulation ändert den Inhalt der DB durch Anwendung eines oder mehrerer der folgenden Operationstypen: • delete (Datensätze werden aus der DB entfernt), • insert (Datensätze werden in die DB eingefügt), • update (Datensätze werden verändert). Im Rahmen der Analyse der Bearbeitungsanforderungen ist es nun notwendig, die folgenden Eigenschaften der wichtigsten Transaktionen zu spezifizieren:
2.3 Anforderungsdokument
59
1. Transaktionstyp (delete, insert, update oder query), 2. Erwartete Frequenz der Transaktion (z. B. fünfmal täglich), 3. Zeitbeschränkung (z. B. max. Laufzeit zehn Sekunden), 4. Informationseinheiten, die von der Transaktion berührt werden, 5. Attribute, die zur Auswahl der Datensätze (Selektion) benutzt werden, 6. Attribute, deren Werte zur Verknüpfung von Informationseinheiten verwendet werden, 7. Attribute, deren Werte durch eine Datenmanipulation verändert werden. In der Praxis ist es meist nicht notwendig, alle Transaktionen bis ins kleinste Detail vorauszuplanen, da es im Allgemeinen nur wenige Transaktionen sind, die die meiste Bearbeitungszeit beanspruchen. Dieser Sachverhalt wird oft als „80-20-Regel“ bezeichnet, wobei damit ausgedrückt werden soll, dass lediglich 20% der Transaktionen bereits etwa 80% der Bearbeitungszeit aller Transaktionen verbrauchen. Bei den verbleibenden 80% der Transaktionen handelt es sich dann meistens um interaktive Anfragen, während die wichtigen bekannten Transaktionen meistens durch vorgefertigte Prozeduren realisiert werden. Die Ergebnisse der Transaktionsanalyse sind für die systemunabhängigen Entwurfsphasen von untergeordneter Bedeutung, sie spielen aber für den physischen Entwurf der DB eine große Rolle. Insbesondere die Spezifikation der in den Punkten 5 bis 7 genannten Attribute bilden oft die Grundlage für physische Entwurfsentscheidungen. Diese Entscheidungen, die sich im Allgemeinen auf die Performanz der DB auswirken, werden unter dem Begriff Datenbanktuning zusammengefasst. Die wohl wichtigste Aktivität zur Verbesserung der Zeiteffizienz ist das Erstellen von Indizes, durch die ein wesentlich schnellerer Zugriff auf die Daten ermöglicht wird. Kandidaten für solche Indizes sind die unter Punkt 5 und 6 beschriebenen Attribute. Insbesondere Anfragen, die eine Verknüpfung von Informationseinheiten (z. B. von zwei Entitytypen über einen gemeinsamen Beziehungstyp) beinhalten, sind sehr zeitintensiv. Beim Anlegen von Indizes muss jedoch bedacht werden, dass bei Datenbankmanipulationen auch die Indexstruktur aktualisiert werden muss und deshalb für Attribute, die während der Transaktion verändert werden (das sind solche, die im Punkt 7 genannt sind), mit diesem Hilfsmittel eher sparsam umgegangen werden sollte. Beispiel 2.16: Transaktionsanalyse „Bestellung erstellen“ Um die Vorgehensweise bei der Transaktionsanalyse zu verdeutlichen, betrachten wir das nachfolgende Beispiel: Ein Handelsunternehmen kontrolliert einmal am Tag den Lagerbestand. Hierbei wird für jeden Artikel der Ist-Bestand mit dem Meldebestand verglichen. Falls der Meldebestand unterschritten wurde, soll automatisch ein Bestellformular erzeugt werden, das für jede Bestellung die Bestellmenge, die Artikelnummer, die Lieferantennummer sowie weitere für die Bestellung relevante Daten enthält. Eine die Bestellung realisierende Transaktion (vgl. dazu Abbildung 2.22) ist wie folgt aufgebaut: Während der Transaktion werden sequenziell alle Artikel auf eine Unterschreitung des Meldebestandes kontrolliert (Schritt 1) und falls dieses zutrifft, wird durch eine Verknüpfung von Lieferant, liefert und Artikel (Schritt 2) festgestellt, von wem der Artikel bezogen wird. Schlussendlich wird jede Bestellung in das Bestellformular eingetragen (Schritt 3).
60
2 Anforderungserhebung und -analyse
Abb. 2.22: Transaktion „Bestellungen erstellen“
Kommen für einen Artikel mehrere Lieferanten in Frage, so könnte die Auswahl des Lieferanten aufgrund einer Prioritätsregel erfolgen, die den niedrigsten Bezugspreis oder aber auch die kürzeste Lieferzeit als Entscheidungsgrundlage beinhaltet. Anforderungen dieser Art beeinflussen die Bearbeitung der Transaktion nur in geringem Rahmen und finden daher ausschließlich während der funktionalen Analyse Berücksichtigung. Das in Abbildung 2.23 dargestellte Anforderungsformular stellt die notwendigen Eigenschaften der Transaktion in strukturierter Form dar und bietet eine Möglichkeit, die Bearbeitungsanforderungen in das Anforderungsdokument aufzunehmen.
2.4
Zusammenfassung
Das Ziel der Anforderungserhebung und -analyse ist die Erstellung eines Anforderungsdokumentes. Im Idealfall ist das Anforderungsdokument eine vollständige Spezifikation aller Sachverhalte, die in den Entwurfsprozess einer DB einfließen müssen. Das Anforderungsdokument kann eine „unternehmensweite“ Sicht der Anforderungen an die DB darstellen oder den individuellen Ausschnitt eines bestimmten Funktionsbereiches im Unternehmen repräsentieren.
2.4 Zusammenfassung
61
Beschreibung:
Überprüfung des Lagerbestandes und Erstellen der Bestellungen
Transaktionstyp:
Insert
Häufigkeit:
Einmal täglich
Zeitbeschränkung:
keine (erfolgt nach Geschäftsschluss automatisch)
Informationseinheit
Attribut
Verknüpfung
Lieferant
Lief_Nr
X
liefert
Lief_Nr
X
Artikel_Nr
X
Artikel_Nr
X
Artikel
Bestellung
Selektion
Ist_Best
X
M_Best
X
Manipulation
Lief_Nr
X
Artikel_Nr
X
Bestellmenge
X
Abb. 2.23: Anforderungsformular der Transaktion „Bestellungen erstellen“
Bevor erhobene Anforderungen in das Anforderungsdokument übertragen werden, empfiehlt sich eine textuelle Analyse der Anforderungsspezifikationen. Anforderungsdokumente enthalten zumindest vier unterschiedliche Typen von Anforderungen: Informationsanforderungen beschreiben die Struktur und die Art der anfallenden Daten. Darunter fallen Angaben über Realweltobjekte, ihre Gruppierung in Typen, die Daten charakterisierenden Eigenschaften bzw. Attribute und ihre Wertebereiche, Beziehungen und Abhängigkeiten zwischen Daten und Objekten sowie allgemeine Integritätsbedingungen, die die Konsistenz der DB beschreiben. Funktionale Anforderungen beschreiben betriebliche Vorgänge auf unterschiedlichen Verdichtungsstufen. Die oberste Verdichtungsstufe stellt Geschäftsprozesse dar, die einen bestimmten betrieblichen Ablauf von seiner Entstehung bis hin zu seiner Beendigung auf hohem Abstraktionsniveau beschreiben. Auf einer unteren Verdichtungsstufe erfolgt die Darstellung in Form elementarer Arbeitsschritte (Prozesse) und ihrer Input- und Outputdatenflüsse. Dynamische Anforderungen beschreiben gültige Zustände und Bedingungen für Zustandsübergänge, die Objekte während ihrer Existenz in der DB durchleben können. Im Rahmen der Transaktionsanalyse werden Bearbeitungsanforderungen erhoben, die für die wichtigsten bereits bekannten Datenbankoperationen ihre Häufigkeit, das involvierte Datenvolumen, Prioritäten und Reihenfolgen oder ähnliche Nutzeranforderungen enthalten. Informationsanforderungen und funktionale Anforderungen stellen die wichtigste „Klasse“ von Anforderungen dar, die den systemunabhängigen Teil des Entwurfs einer DB beeinflussen. Die im Anforderungsdokument enthaltenen Aufgaben und Vorgaben bilden die Grundlage für den konzeptuellen Datenbankentwurf.
62
2.5
2 Anforderungserhebung und -analyse
Literatur
Eine umfassende Darstellung der Planung von Softwaresystemen mit besonderer Berücksichtigung der Erstellung einer Vorstudie ist in [Hei96a] enthalten. Viele Bücher über die Grundlagen der Wirtschaftsinformatik beinhalten umfangreiche Darstellungen der Methoden der Anforderungserhebung und -analyse. Als Beispiel dafür seien [StHa97], [Kral96] oder [Hans96] genannt. Arbeiten, die sich vorwiegend mit der Analyse der Informationsanforderungen beschäftigen, sind meistens Bücher, die die frühen Phasen des Entwurfszyklus einer DB in den Vordergrund stellen. Als Beispiel dafür seien [BaCN92], [RaSt97] oder [MMMO93] genannt. Die Darstellung einer Vorgehensweise für funktionale Analyse ist in [MaMc75] für SADT, [DeMa79] für strukturierte Analyse, [YoCo79] für strukturiertes Design, [Stay76] für HIPO und in [GaSa79] für eine allgemeine Datenflussmodellierung enthalten. [Balz82] enthält einen sehr guten Überblick der unterschiedlichen Methoden. Die Methoden der Analyse der dynamischen Aspekte der Anforderungen sind in vielen Büchern über objektorientierte Analyse und Design enthalten. Auf sie wird im nächsten Kapitel hingewiesen werden. Die Analyse der Bearbeitungsanforderungen wird in vielen Datenbankbüchern vernachlässigt. Lobenswerte Ausnahmen stellen [LaLo95] und [MaDL87] dar. Eine Darstellung neuer Entwicklungen, insbesondere des Einsatzes von Szenarien, ist in dem Sonderheft [Soft98] enthalten.
2.6
Kontrollaufgaben
Aufgabe 2.1: Charakteristika für den Einsatz von DBMS Welche Charakteristika müssen betriebliche Aufgaben besitzen, so dass DBMS ein geeignetes technisches Realisierungskonzept darstellen? Aufgabe 2.2: Techniken zur Anforderungserhebung Diskutieren Sie Vor- und Nachteile der wichtigsten Techniken zur Erhebung von Nutzeranforderungen an das zu entwickelnde DBS. Welche Techniken ergänzen sich gegenseitig und können gemeinsam eingesetzt werden? Aufgabe 2.3: Datei- vs. Datenbanksystem Beschreiben Sie anhand frei gewählter Aufgabenstellungen in den drei Funktionsbereichen „Einkauf“, „Lagerhaltung“ und „Verkauf“ die historischen Entwicklungsstufen von DB. Gehen Sie auf die wesentlichen Unterschiede zwischen Dateisystemen und DBS ein und geben Sie an, wie in den einzelnen Systemen Datenredundanz kontrolliert werden kann. Aufgabe 2.4: Unterschiedliche Klassen von Anforderungen Ordnen Sie nachfolgende Anforderungen den vier unterschiedlichen Anforderungsklassen zu. Begründen Sie Ihre Antworten und führen Sie eine erste Anforderungsanalyse durch. • Applikation „Vorbereitung-Bestellung“ registriert den Kunden und trägt Neukunden in die Kundendatei ein. • Besitzt der Kunde eine gute Bonität und ist die Höhe der Bestellung über Euro 10.000, so wird ein Rabatt in Höhe von 3% in Abzug gebracht.
2.6 Kontrollaufgaben
63
• Ein bestimmtes Produkt kann unter Verwendung bestimmter Maschinen vom Typ A gefertigt werden. Jede dieser Maschinen besitzt eine eindeutige Maschinenkennnummer, einen Standort und einen individuellen Belegungsplan. Alle Maschinen vom Typ A haben die gleiche PS-Leistung, dasselbe Gewicht, aber ein individuelles Kaufdatum. • Die Entleihung eines Buches aus der Universitätsbibliothek kann wie folgt beschrieben werden: Ist das Buch nicht verfügbar, so ist die Entleihung im Zustand „Reservierung“. Wird das Buch nach Fälligkeit nicht retourniert, wird dem Entleiher eine Mahnung geschickt. Ist das Buch verfügbar und nicht vorgemerkt, kann es entliehen werden. • Nachdem ein Mietwagen retourniert ist, werden der Retourschein erfasst und die Rechnung erstellt. Der Rechnungsbetrag errechnet sich aus der gewählten Wagenkategorie, den gefahrenen Kilometern, der Rabattgruppe des Kunden, der Mietdauer und aus dem Tankinhalt nach Rückgabe. Aufgabe 2.5: Eigenschaften von Attributen und Beziehungstypen Diskutieren Sie Strukturierungsmerkmale für Attribute und Beziehungstypen. Geben Sie für jedes Ihnen bekannte Merkmal zumindest ein Beispiel an. Aufgabe 2.6: Anforderungsanalyse Sportverein Identifizieren Sie im nachfolgenden Text alle Entitytypen, Attribute und Beziehungstypen und diskutieren Sie ihre Eigenschaften. Ein professioneller Sportverein (mit mehreren Mannschaften) möchte seine Mitgliederverwaltung automatisieren. Mitglieder des Sportvereins sind ausschließlich aktive Mitglieder oder Förderer. Für Mitglieder soll ihre Mitgliedsnummer, Name, Anschrift und Eintrittsdatum gespeichert werden. Für Förderer des Sportvereins soll zusätzlich noch die Höhe ihres Beitrags und ein Textfeld für weitere Anmerkungen geführt werden. Aktive Mitglieder sind entweder Trainer, Spieler in einer Mannschaft oder können auch beides sein. Für Trainer wird das Datum ihrer Lizenz, die Art der Lizenz und das Gehalt gespeichert. Spieler werden durch das Attribut Eigenschaft und ebenfalls durch ihr Gehalt beschrieben. Ein Trainer kann mehrere Mannschaften trainieren. Jede Mannschaft hat jedoch zu einem Zeitpunkt nur einen Trainer. Es soll aufgezeichnet werden, wann (Datum) der Trainer die Mannschaft übernommen hat, wie oft (Anzahl) in der Woche ein Training stattfindet und welche Trainer diese Mannschaft bisher schon trainiert haben. Maximal 16 Spieler können einer Mannschaft angehören. Jeder Spieler kann zu einem Zeitpunkt nur einer Mannschaft angehören, kann aber während seiner Zugehörigkeit zum Verein schon für andere Mannschaften gespielt haben. Für jeden Spieler soll das Eintrittsdatum in eine Mannschaft, seine Spielposition und ein eventuelles Austrittsdatum aus der Mannschaft gespeichert werden. Jede Mannschaft hat einen Mannschaftskapitän. Er muss Spieler dieser Mannschaft sein und für ihn sollen seine Telefonnummer und eine Prämienzulage gespeichert werden. Jede Mannschaft wird eindeutig durch ihren Namen bestimmt und hat als weitere Eigenschaft die Bezeichnung der Liga, in der die Mannschaft spielt. Aufgabe 2.7: Anforderungsanalyse Kursverwaltung Die Kursverwaltung der Firma „ABC Ltd.“ soll rechnerunterstützt durchgeführt werden. Führen Sie aufgrund der nachfolgenden Angaben eine funktionale und statische Analyse des Realweltausschnittes durch.
64
2 Anforderungserhebung und -analyse
Das betrachtete Unternehmen unterhält eine Ausbildungsabteilung, deren Aufgabe es ist, unterschiedliche Kurse durchzuführen. Jeder Kurs findet innerhalb des Unternehmens an verschiedenen Orten statt. Die zu erstellende DB enthält aktuelle Kurse, die bereits abgehaltenen Kurse, und auch Kurse, deren Abhaltung erst geplant ist. Folgende Details sollen modelliert werden: • Für jeden Kurs: Kursnummer (eindeutig), Kursbezeichnung, Kursbeschreibung, vorausgesetzte Kurse (falls vorhanden), Zeitbezug (durchgeführt, geplant). • Für jeden vorausgesetzten Kurs seine Kursnummer und Kursbezeichnung. • Für jedes Kursangebot: Datum, Ort (Bezeichnung, Raumkapazität), Art (z. B. ganztägig, halbtägig), beteiligte Leiter, beteiligte Teilnehmer. • Für jeden Kursleiter eines angebotenen Kurses: Mitarbeiternummer und Name. • Für jeden Kursteilnehmer an einem angebotenen Kurs: Mitarbeiternummer, Name, Gehalt. Kursteilnehmer müssen die Teilnahme an Kursen beantragen. Die Vergabe erfolgt in der Reihenfolge der Anmeldung, wobei die maximale Raumkapazität der Teilnehmerobergrenze für den jeweiligen Kurs entspricht. Vor der Zuordnung wird überprüft, ob der Kandidat für den jeweiligen Kurs alle Voraussetzungen erfüllt. Aufgabe 2.8: Schematransformationen Erklären Sie anhand eines frei gewählten Beispiels mögliche Schematransformationen in Datenflussdiagrammen. Aufgabe 2.9: Top-down-Verfeinerung „Wareneingangsprüfung“ Verfeinern Sie den in Abbildung 2.16(d) dargestellten Vorgang „Wareneingangsprüfung“. Wenden Sie im Zuge der Verfeinerung ausschließlich die in Abbildung 2.17 dargestellten Transformationsregeln an. Aufgabe 2.10: Formen der funktionalen Analyse Erklären Sie die wesentlichen Unterschiede der Top-down-, der Bottom-up-, der Kombinationsmethode und der Inside-out-Vorgehensweisen zur Durchführung einer funktionalen Analyse. Wie können diese unterschiedlichen Ansätze miteinander kombiniert werden? Aufgabe 2.11: Wichtige Transaktionen Nennen Sie die wichtigsten Eigenschaften von Transaktionen, die im Zuge der Anforderungserhebung und -analyse dokumentiert werden sollen. Aufgabe 2.12: Zusammenhänge unterschiedlicher Anforderungstypen Diskutieren Sie Zusammenhänge zwischen Informationsanforderungen und dynamischen Anforderungen.
3
Konzeptueller Datenbankentwurf
Beim Entwurf einer DB kommt der konzeptuellen Modellbildung des zu beschreibenden Realitätsausschnittes eine zentrale Bedeutung zu. Die Hauptaufgabe dieser Entwurfsphase ist es, alle individuellen Anforderungen aus den Anforderungsdokumenten in einer einheitlichen Spezifikation, dem unternehmensweiten Datenmodell, zu repräsentieren und damit für alle Anwendungen eine einheitliche Schnittstelle für den Zugriff auf die DB zu schaffen. In diesem Kapitel sollen die wesentlichen Schritte der konzeptuellen Modellbildung näher betrachtet werden. Eine DB muss den aus der Sicht der zu bedienenden Anwendungsklassen relevanten Realweltausschnitt abdecken. Nun ist die Realwelt allerdings zu komplex und vielschichtig aufgebaut, als dass sie sich einfach so auf einem Rechner abbilden ließe. Daher braucht man Ausdrucksmittel, mit denen die Realwelt so vereinfacht dargestellt werden kann, dass die resultierende Darstellung abstrakt genug ist, um die aus der Sicht der Anwendungsklassen unwichtigen Details kaschieren zu können, gleichzeitig aber ausdrucksstark genug ist, um alle erwünschten Merkmale und Beziehungen auch ausdrücken zu können. Als Werkzeuge zur Modellierung einer solchen Darstellung werden aussagekräftige und mächtige Datenmodelle eingesetzt. Die Ergebnisse der Anforderungserhebung liegen in den meisten Fällen in sehr informeller Form vor. Für den konzeptuellen Entwurf einer DB benötigt man ein Beschreibungsmittel, mit dem die Spezifikationen aus den Anforderungsdokumenten einheitlich und systemunabhängig dargestellt werden können. Die „semantische“ Informationsbeschreibung ist Gegenstand der konzeptuellen Modellbildung und wird von so genannten semantischen Datenmodellen, die für den konzeptuellen Datenbankentwurf eingesetzt werden, unterstützt. Ein semantisches Datenmodell erlaubt es, den relevanten Ausschnitt der Realität unter Verwendung der Strukturierungsprinzipien des Modells präzise, wahrheitsgetreu und möglichst umfassend darzustellen. Es zwingt zu einem gründlicheren und vollständigeren Analysieren des Informationsbedarfs und hilft dabei, Lücken in den Anforderungsspezifikationen aufzudecken. Von einem semantischen Datenmodell wird in der Regel gesprochen, wenn es das relationale Datenbankmodell an semantischer Aussagekraft übertrifft. Seit dem Ende der 60er Jahre hat man sich Gedanken darüber gemacht, wie Daten in eine „normale“ Form gebracht und entsprechend dargestellt werden könnten. In den letzten 30 Jahren wurde eine Vielfalt von Modellierungsarten und Darstellungstechniken bekannt, aus denen man einige Meilensteine der Entwicklung identifizieren und einige Trends herleiten kann.
66
3 Konzeptueller Datenbankentwurf
Einer der ersten, der sich mit der Konzeptualisierung von Daten befasst hat, war C. W. Bachmann.1 Etwas später entwickelte E. F. Codd2 sein relationales Datenbankmodell, mit dem er versuchte, die Beschreibung von Daten mengentheoretisch vorzunehmen und Normalformen zu entwickeln, mit denen die Güte einer relationalen DB beurteilt werden kann. Die zu jener Zeit geprägten Grundsätze und Regeln besitzen heute noch Gültigkeit. Die nächsten Jahre wurden durch die Entwicklung von Modellen geprägt, mit denen versucht wurde, die semantische Aussagekraft der Daten zu erhöhen. Einen ersten Meilenstein in der Entwicklung von semantischen Datenmodellen stellt das Entity-Relationship-Modell durch Peter P. Chen [Chen76] dar, das in den Folgejahren um viele Aspekte erweitert wurde und heute einen Quasi-Standard für den konzeptuellen Datenbankentwurf darstellt. Entity-Relationship-Modelle legen ihren Schwerpunkt auf die strukturelle Analyse der Anforderungen und beschreiben vornehmlich die Struktur der Daten. Parallel zu ihrer Entwicklung entstanden Ende der 70er Jahre Funktionsmodelle, die eher eine funktionsorientierte Sichtweise auf die Anwendung favorisieren, jedoch die Struktur der Daten vernachlässigen. Wir haben die Idee hinter diesen Modellen in Unterkapitel 2.3.2 bei der Analyse der funktionalen Anforderungen vorgestellt. Die späten 70er Jahre und der Beginn der 80er Jahre wurden durch Arbeiten und Entwicklungen mit dem Ziel geprägt, diese beiden unterschiedlichen Denkweisen in eine einheitliche Vorgehensweise zur konzeptuellen Modellbildung zu integrieren. Die Mitte und das Ende der 80er Jahre waren der Entwicklung von objektorientierten Modellen gewidmet. Inzwischen war das methodische Modellieren der Daten und Funktionen weit verbreitet und man war zur Überzeugung gekommen, dass eine ganzheitliche und objektorientierte Sichtweise auf ein betriebliches Informationssystem auch dynamische Aspekte, also die Modellierung von Objektklassen durch Struktur und Verhalten, beinhalten sollte. Die Entwicklung von Methoden und Techniken zum konzeptuellen Datenbankentwurf scheint auch heute noch nicht vollständig abgeschlossen zu sein. Es entwickeln sich weiterhin neue Denkansätze. So rückte z. B. die Analyse und Modellierung von Geschäftsprozessen als Basis für den Datenbankentwurf in den letzten Jahren zunehmend in den Mittelpunkt der Betrachtung. Die Struktur dieses Kapitels spiegelt die einzelnen Phasen der Entwicklung von Methoden zum konzeptuellen Datenbankentwurf wider und ist in Abbildung 3.1 zusammengefasst. Wir beginnen das Kapitel mit der Darstellung des Entity-Relationship-Ansatzes, einer Methode zur ausschließlich strukturorientierten Modellbildung (Unterkapitel 3.1). In Unterkapitel 3.2 erweitern wir diesen Ansatz und stellen eine Methode vor, in der Daten- und Funktionsmodelle gleichberechtigt zur Erstellung eines konzeptuellen Datenmodells herangezogen werden. Bei der objektorientierten Vorgehensweise wird zwischen einer Struktur- und einer Verhaltensmodellierung unterschieden. In Unterkapitel 3.3 wird ein integriertes Objektmodell erarbeitet, das neben den Aspekten der klassischen Modelle auch Konzepte zur Modellierung von Verhalten beinhaltet. Das Unterkapitel 3.4 widmet sich den aktuellen Forschungstrends und fasst einen weiteren Ansatz zur konzeptuellen Modellbildung, die geschäftsprozessorientierte Modellbildung, zusammen. Dieser Ansatz kann jedoch aus Kapazitätsgründen nicht mehr im Detail behandelt werden. Das Kapitel 3 wird durch zwei weitere Unterkapitel ergänzt: In Unterkapitel 3.5 wird das Gebiet der Schemaintegration behandelt. Schemaintegration wird 1 siehe 2 siehe
[Bach69] [Codd70]
3 Konzeptueller Datenbankentwurf
67
Abb. 3.1: Ansätze zur konzeptuellen Modellbildung
notwendig, wenn ein konzeptuelles Datenmodell nicht als Ganzes, sondern durch Integration und Konsolidierung mehrerer Bereichsdatenmodelle entwickelt wird. Kapitel 3 wird mit der Normalisierung abgeschlossen, einer Entwurfsmethode, die vorwiegend zum Entwurf relationaler DB eingesetzt wird. Es gilt noch die allgemeine Frage zu beantworten, welche generellen Gestaltungsempfehlungen für konzeptuelle Modellbildungen existieren, deren Anwendung die Qualität eines Modells erhöhen. Dabei ist es sehr schwierig, eine Metrik zur Gewichtung einer Qualität in einer festen und objektiven Weise vorzugeben. In den meisten Fällen beruht solch ein Maß auf subjektiver Einschätzung. Ein erster Ansatz wurde in [BeRS95] entwickelt, einer Arbeit, in der Grundsätze ordnungsgemäßer Modellbildung aufgestellt werden, denen als Vorbild die im Rechnungswesen geltenden Grundsätze ordnungsgemäßer Buchführung nach Leffson dienen. Dabei werden insbesondere betrachtet: • Grundsatz der Richtigkeit Dieser Grundsatz gliedert sich in zwei Aspekte: Die syntaktische Richtigkeit wird eingehalten, wenn ein Modell den Notationsregeln der gewählten Modellierungsmethode entspricht. Die semantische Richtigkeit bewertet den „Inhalt“ des Modells, also inwieweit das Modell dem entsprechenden abzubildenden Realweltausschnitt entspricht. Hierzu müssen alle sachlogischen Gegebenheiten und Zusammenhänge des relevanten Realitätsausschnitts im Modell abgebildet sein. • Grundsatz der Relevanz Das Modell sollte keine überflüssigen Informationen enthalten noch sollten relevante Informationen fehlen. Im Modell dargestellte Sachverhalte gelten dann als relevant, wenn
68
3 Konzeptueller Datenbankentwurf der Nutzeneffekt des Modells sinken würde, falls man Informationen entfernen oder hinzufügen würde.
• Grundsatz der Wirtschaftlichkeit Dieser Grundsatz stellt den betriebswirtschaftlichen Wirtschaftlichkeitsaspekt dar. Die Wirtschaftlichkeit eines Modells lässt sich nur sehr schwer bewerten, weil sich Kosteneinsparungen am Modell erst in den späteren Phasen des Datenbankentwurfs rächen. • Grundsatz der Klarheit In diesem Grundsatz werden die Aspekte der Strukturiertheit, der Übersichtlichkeit und der Lesbarkeit zusammengefasst. Sie betreffen folglich die Anschaulichkeit eines Modells. • Grundsatz der Vergleichbarkeit Dieser Grundsatz gliedert sich ebenfalls in zwei Aspekte: Die syntaktische Vergleichbarkeit stellt die Kompatibilität von Modellen dar, die mit verschiedenen Modellierungstechniken (Methoden) erstellt wurden. Die semantische Vergleichbarkeit beschreibt die inhaltliche Vergleichbarkeit von Modellen. Auf diesen Grundsatz werden wir im Unterkapitel 3.5 nochmals näher eingehen. • Grundsatz des systematischen Aufbaus Bei der Erstellung eines Modells sollte eine systematische Vorgehensweise gewählt werden. So sollten z. B. Bereichsdatenmodelle schon im Hinblick auf eine spätere Integration in ein unternehmensweites Datenmodell erstellt werden. Bei allen Grundsätzen wird sehr deutlich, wie wichtig der Einbezug der subjektiven Beurteilung der einzelnen Personengruppen, die bei Analyse, Modellbildung und Einsatz eines DBS involviert sind, in die Bewertungsansätze ist. So hat z. B. ein Anwendungsprogrammierer sicherlich andere Anforderungen und Erwartungen an ein Modell als ein Endbenutzer. Dementsprechend unterschiedlich wird auch der Begriff „Nutzen“ bei beiden Nutzergruppen definiert sein.
3.1
Strukturorientierte Modellbildung
Bei der strukturorientierten (datenorientierten) Modellbildung stehen die Daten und ihre Beschreibung in einem semantischen Datenmodell im Mittelpunkt der Betrachtung. Semantische Datenmodelle eignen sich hervorragend zur Analyse der im Anforderungsdokument enthaltenen statischen Informationsanforderungen. Vorwiegend zwischen 1975 und 1985 wurde eine Vielzahl an semantischen Datenmodellen erarbeitet, die sich zwar in Detailaspekten und ihrer Begriffswahl unterscheiden, aber sich inhaltlich in ihren Grundkonzepten durchaus ähnlich sind. Alle Modelle haben gemeinsam, dass sie die Welt als eine Menge von Systemkomponenten (reale oder abstrakte Gegenstände), Eigenschaften von Systemkomponenten und unterschiedlichen Formen von Beziehungen zwischen Systemkomponenten beschreiben und Abstraktionsprinzipien verwenden, um elementare Eigenschaften der Realität zu aggregieren und zu Informationseinheiten eines höheren Abstraktionsniveaus zusammenzufassen. Zu den wichtigsten Abstraktionsprinzipien, die in den meisten Modellen enthalten sind, gehören:
3.1 Strukturorientierte Modellbildung
69
• Klassifikation Objekte mit ähnlichen Eigenschaften werden als Instanzen einer Objektklasse betrachtet. Ein Objekttyp besitzt alle Eigenschaften, durch die Instanzen der Objektklasse beschrieben werden. • Assoziationen Objekte bzw. Objekttypen können miteinander in Beziehung stehen. Beziehungen können selbst wieder Objekte sein und daher auch Eigenschaften besitzen. • Aggregation Aggregation kann es auf verschiedensten Hierarchieebenen eines semantischen Datenmodells geben. Sie beschreibt, wie bestimmte Informationseinheiten zu einem Objekt einer höheren Informationseinheit zusammengefasst werden können. So werden z. B. Werte von Attributen eines Objekttyps zu einem individuellen Objekt aggregiert, bestimmte Objekte zu einer Unterklasse des Objekttyps zusammengefasst oder zwei Objekte, die miteinander in Beziehung stehen, zu einem Datenaggregat verbunden. • Generalisierung Ähnliche Objekte werden aufgrund unterschiedlicher Eigenschaften zu Spezialisierungen zusammengefasst. In Spezialisierungen redundant geführte Attribute bilden einen generischen Objekttyp. Das wohl bekannteste semantische Datenmodell ist das Entity-Relationship-Modell (ERM) von Peter P. Chen [Chen76]. Dieses Modell erfreut sich heute einer sehr großen Beliebtheit. Man kann im Zusammenhang mit diesem Modell durchaus von einem De-facto-Standard für den konzeptuellen Datenbankentwurf sprechen. Das ERM wurde in den letzten zwei Jahrzehnten in vielfältige Varianten abgeändert, so dass man heute auch von der „Familie“ der ERM spricht.
3.1.1
Grundlagen des Entity-Relationship-Modells
In seiner Urform unterstützt das ERM ausschließlich die Konzepte Entity, Beziehung und Attribut und hat sich hauptsächlich an den zum Zeitpunkt seiner Entwicklung üblichen Datenbankmodellen, dem hierarchischen und dem relationalen Datenbankmodell orientiert. Die grafischen Konzepte sind sehr einfach gehalten und leicht zu verstehen, was sicher mit ein Grund dafür ist, dass dieses Modell sich gegen eine Vielzahl anderer Modelle durchgesetzt und in der Praxis einen breiten Siegeszug angetreten hat. Das Modell ist in vielen CASEWerkzeugen und Vorgehensmodellen zur konzeptuellen Modellbildung integriert und wird nicht nur für den Datenbankentwurf, sondern zur Modellierung und Analyse vieler Fragestellungen einer allgemeinen Systemanalyse verwendet. Die Anschaulichkeit und leichte Lesbarkeit des ERM mag der Grund für seine weite Verbreitung sein. Durch seine Einfachheit und die Orientierung an den eher traditionellen Datenbankmodellen ist das ursprüngliche ERM nicht sehr mächtig und vermag die Semantik der Realität nur sehr eingeschränkt widerzuspiegeln. Schon bald nach seiner Publikation haben sich zahlreiche Forschungsprojekte zum Ziel gesetzt, einerseits das ERM um verschiedenste Aspekte zu erweitern und die formalen und theoretischen Grundlagen eines exakten ERM zu
70
3 Konzeptueller Datenbankentwurf
erarbeiten bzw. andererseits Modelle aus der Familie des ERM für unterschiedlichste Modellierungszwecke anzuwenden. Heute sind die wichtigsten Fragestellungen im Zusammenhang mit dem ERM in den wissenschaftlichen Journalen und Tagungsbänden vieler Datenbank- und Wirtschaftsinformatikkonferenzen publiziert und es gibt eine eigene wissenschaftliche Konferenzreihe die jährlich tagt (1998 bereits zum 17. Mal) und sich ausschließlich mit Forschungsund Anwendungsfragen im Zusammenhang mit dem ERM beschäftigt. Das ERM wird hauptsächlich zur Beschreibung und Analyse der Struktur der als Informationsanforderungen erhobenen Daten verwendet. Im ERM werden gleichartige Entities zu einem Entitytyp und gleichartige Beziehungen zu einem Beziehungstyp zusammengefasst. Die Beschreibung der Eigenschaften von Entity- und Beziehungstypen erfolgt durch Attribute. Einem Entitytyp müssen, einem Beziehungstyp können Eigenschaften zugeordnet werden. Alle Attribute werden durch Zuordnung eines Wertebereiches typisiert. Feststellung 3.1: ERM zur Analyse der Informationsanforderungen Die Struktur der Informationsanforderungen eines betrachteten Realitätsausschnittes kann durch Herleiten von Entitytypen, Beziehungstypen und Attributen durch ein ERM sehr gut analysiert und durch ein Entity-Relationship-Diagramm (ERD) visualisiert werden. In einem ERD werden Entitytypen durch Rechtecke, Beziehungstypen durch Rauten und Eigenschaften durch Ellipsen symbolisiert. Die verschiedenen Symbole werden durch ungerichtete (in den meisten Darstellungsformen) Kanten zu einem ERD zusammengefasst. Abbildung 3.2 zeigt die grundlegenden Konzepte eines ERDs in der für dieses Buch gewählten Notation. Bevor wir die einzelnen Konzepte des ERM im Detail betrachten, wollen wir vorerst ein einfaches Beispiel modellieren. Beispiel 3.1: ERD einer Kursverwaltung Relevante Entitytypen sind Kurs, Kursleiter, Teilnehmer, Buch und Abteilung, die miteinander in einem semantischen Zusammenhang stehen. Alle Kurse müssen einen Kursleiter haben, und ein Leiter kann mehrere Kurse abhalten. Da in dem ERM kein Zeitbezug dargestellt ist, können mehrere Kurse eines bestimmten Leiters zum selben Zeitpunkt (z. B. im gleichen Semester) stattfinden. Außerdem lässt die Beziehung „leitet“ auch Kursleiter zu, die keinen Kurs anbieten. Für bestimmte Kurse sind möglicherweise andere Kurse Voraussetzung, und jeder Kurs kann wiederum Voraussetzung für andere Kurse sein. Für bestimmte Kurse wird das Studium gewisser Bücher empfohlen. Ein bestimmtes Buch kann möglicherweise für mehrere Kurse genutzt werden. Kursleiter müssen, Teilnehmer an Kursen können Abteilungen zugeordnet sein. Kurse können nur stattfinden, wenn sie zugeordnete Teilnehmer haben. Die Beziehung „nimmt_teil“ besitzt die qualifizierenden Attribute Beitrag und Note. Kursteilnehmer können an mehreren Kursen teilnehmen. Ein ERD, das diesen Sachverhalt abbildet, ist in Abbildung 3.3 dargestellt. Schon dieses kleine und einfache Beispiel konnte den Eindruck vermitteln, dass man mit den wenigen Konzepten des ERM recht rasch komplexe und umfangreiche Analysen einer Anwendung durchführen kann. Häufige Fehlerquellen bei Aufstellung eines ERM sind die richtige
3.1 Strukturorientierte Modellbildung
71
Abb. 3.2: ERD-Notation
Unterscheidung von Konzepten der Realität in Entitytypen oder Beziehungstypen, die Benennung der richtigen Kardinalität für Beziehungstypen bzw. die richtige Modellierung von optionalen und totalen Beziehungstypen. Oft ist die Wahl eines bestimmten Konzeptes auch durch die subjektive Einschätzung des Entwerfers geprägt. So wäre es in Beispiel 3.1 durchaus möglich, anstelle des Beziehungstypen „nimmt-teil“ einen eigenen Entitytypen „Kursteilnahme“ einzuführen, der in 1:N-Beziehung mit Teilnehmer und Kurs steht. Dies könnte gerechtfertigt werden, da sowohl Teilnehmer als auch Kurs verpflichtend an der Beziehung teilnehmen (daher gäbe es in Kursteilnahme keine Nullmarken) und der Beziehungstyp eigene Eigenschaften besitzt. Allerdings müsste in Kursteilnahme eine identifizierende Eigenschaft aufgenommen werden (z. B. eine eindeutige fortlaufende Nummer für alle Teilnahmen), über die alle individuellen Teilnahmen eindeutig identifiziert werden können. Ein großes Problem beim Erstellen eines ERDs ist der mangelnde Platz, der für die Darstellung des Modells zur Verfügung steht. Sind keine Softwarewerkzeuge zur Unterstützung vorhanden, wird man sehr schnell an die Grenzen der grafischen Darstellungsmöglichkeiten
72
3 Konzeptueller Datenbankentwurf
Abb. 3.3: Kursverwaltung
eines ERDs gelangen. Um die Übersichtlichkeit nicht zu verlieren, und um etwas Platz einzusparen, werden Attribute in der grafischen Darstellung oft weggelassen und zu jedem ERD wird ein Entitykatalog erstellt, der für jeden Entity- und Beziehungstyp die erhobenen Attribute mit den entsprechenden Wertebereichen enthält. Eine mögliche Strukturierung eines Entitykataloges wurde bereits in Abbildung 2.11 vorgeschlagen. Die folgende Darstellung der Grundkonzepte des ERM ist sehr an die Darstellung der Merkmale von Informationsanforderungen (siehe Unterkapitel 2.3.1) angelehnt und erfolgt daher in straffer Form: Ein Entitytyp beschreibt unter Verwendung von Attributen eine Menge von Entities mit ähnlichen Eigenschaften. Einige der Attribute (oder auch Attributkombinationen) stellen identifizierende Eigenschaften von Entities dar, die es erlauben, über ihren Wert genau ein Entitydes jeweiligen Typs eindeutig zu identifizieren. Die Kardinalität und der Grad eines Beziehungstyps definieren das Verhältnis, in welchem Entities der beteiligten Entitytypen zueinander in Beziehung stehen. Abbildung 3.4 enthält Beispiele unterschiedlicher Formen von Beziehungstypen. Der Grad und die Kardinalität eines Beziehungstyps definieren das Verhältnis, in dem Entities der beteiligten Entitytypen zueinander in Beziehung stehen. Der Grad (auch Stelligkeit) einer Assoziation beschreibt die Anzahl der beteiligten Entitytypen. Ein Grad kann jede beliebige Größe annehmen. In den meisten Fällen treten jedoch lediglich Beziehungen mit binärem Grad (zweistellige Beziehungstypen) auf. Zum besseren Verständnis mancher Beziehungstypen in einem Modell wird gelegentlich auf die Bezeichnung durch Rollennamen zurückgegriffen. Eine Rolle definiert die Art und Weise, in der Entities an der Beziehung teil-
3.1 Strukturorientierte Modellbildung
Abb. 3.4: Beispiele unterschiedlicher Beziehungstypen
73
74
3 Konzeptueller Datenbankentwurf
nehmen. Zwingend vorgeschrieben ist die Verwendung von Rollennamen, wenn Entities eines bestimmten Typs mehr als nur einmal an einer Beziehung teilnehmen und dabei in verschiedenen Rollen auftreten können. Ein weiteres Beispiel für die Notwendigkeit von Rollennamen ist ein rekursiver Beziehungstyp, für den Rollennamen erforderlich sind, um die jeweilige Rolle der Entities in der Beziehung zu definieren. Ein Beispiel eines rekursiven Beziehungstyps ist „vorausgesetzt“ aus der Kursverwaltung (siehe Abbildung 3.3), in der Kurse entweder in der Rolle „setzt voraus“ bzw. „ist Voraussetzung für“ auftreten können. In der grafischen Darstellung werden Rollenbezeichnungen an jene Kanten gesetzt, die die entsprechende Beziehung beschreiben. Die Kardinalität eines Beziehungstyps beschreibt die Anzahl von Entities, die an entsprechenden Beziehungen teilnehmen können. Beziehungstypen binären Grades besitzen in der Regel Kardinalitäten von 1:1, 1:N oder N:M. Abhängig von der Art der Teilnahme von Entities an einer Beziehung, kann man zwischen einer totalen und einer optionalen Teilnahme unterscheiden. Bei einer totalen Teilnahme müssen alle Entities eines bestimmten Typs an der Beziehung teilnehmen. Eine totale Beziehung impliziert eine Existenzabhängigkeit, da die Existenz eines Entities von seiner Beziehung zu einem anderen Entity abhängig ist. Bei einer optionalen Teilnahme müssen nicht unbedingt alle Entities eines Typs an der Beziehung teilnehmen, sondern lediglich ein Teil von ihnen. Im Beispielmodell der Kursverwaltung (siehe Abbildung 3.3) sind Entities vom Typ „Teilnehmer“ in zwei Beziehungen unterschiedlicher Form involviert. Entities vom Typ „Teilnehmer“ können nur existieren, wenn sie zumindest einem Kurs zugeordnet sind (totale Teilnahme). Ob eine Zuordnung zu einer Abteilung existiert, ist nicht spezifiziert. Für diesen Fall kann eine optionale Teilnahme angenommen werden. Eine weitere Methode, die Art der Teilnahme von Entities an einer Beziehung und die Kardinalität eines Beziehungstyps festzulegen, besteht darin, jeden Beziehungstyp mit einem Paar von Integerzahlen (min, max) zu belegen. Hierbei stehen die Zahlen in dieser Min-MaxSchreibweise für die jeweils minimale und maximale Anzahl von Beziehungen, an denen Entities der beteiligten Typen teilzunehmen haben (0 ≤ min ≤ max ≥1). Der Vorteil dieser Methode ist, dass sie wesentlich präziser ist, da Zuordnungen jeglichen Grades und jeglicher Kardinalität sowie eine optionale Beziehung mit min = 0 und totale Beziehungen mit min > 0 ausgedrückt werden können. Als Nachteil ist anzusehen, dass die grafische Darstellung im ERD mehr Platz benötigt. Wir legen uns in diesem Buch auf keine Darstellungsform fest und verwenden die Doppelstrich- und die Zahlenpaarnotation synonym zur Unterscheidung totaler/optionaler Beziehungstypen. Oft gibt es semantisch zusammengehörende Attribute, die einen eigenen Entitytyp bilden, aber nicht ausreichen, um durch ihre Ausprägungen alle Entities dieses Typs eindeutig zu identifizieren, oder es gibt Situationen, in denen die Existenz eines Entities an die Existenz eines Entities eines anderen Typs gebunden ist. Im ersten Fall existieren für den Entitytyp keine Attribute mit Schlüsseleigenschaft. Im zweiten Fall existiert zwischen den Entitytypen eine Existenzabhängigkeit. Um beide Sachverhalte im ERM darstellen zu können, verwendet man das Konzept des schwachen Entitytyps (abhängiger Entitytyp). Voraussetzung für die Modellierung eines schwachen Entitytypen ist eine 1:N-Beziehung oder 1:1-Beziehung zwischen einem entsprechenden „starken“ Entitytyp und dem schwachen Entitytyp. Im ERD wird ein schwacher Entitytyp durch ein doppelt umrandetes Rechteck und die dazu gehörende identifizierende Beziehung durch eine doppelt umrandete Raute dargestellt. Eine zweite Möglichkeit, schwache Entitytypen in ein ERD einzubinden, besteht darin, sie als zusammen-
3.1 Strukturorientierte Modellbildung
75
Abb. 3.5: Beispiel Bestellvorgang (Fortsetzung)
gesetzte oder mehrwertige Attribute darzustellen. Im Allgemeinen ist die Art der Darstellung dem Modelldesigner überlassen. Grundsätzlich sollte jedoch die Darstellung als Entitytyp bevorzugt werden, wenn der schwache Entitytyp über viele Attribute verfügt und/oder selbstständig an weiteren Beziehungen teilnimmt. Abbildung 3.5 illustriert das Konzept des schwachen Entitytyps anhand der Analyse der Informationsanforderungen des Bestellvorganges, wie er im Beispiel 2.7 dargestellt ist. Da in unterschiedlichen Methoden und CASE-Tools oft unterschiedliche grafische Konzepte gewählt werden, fassen wir in Abbildung 3.6 die gebräuchlichsten Darstellungsformen für ERD zusammen.
Beispiel 3.2: Beispiel Bestellvorgang (Fortsetzung) Siehe dazu die Analyse der Informationsanforderungen aus Beispiel 2.7. Ein entsprechendes ERM ist in Abbildung 3.5 dargestellt.
Die korrekte Verwendung n-stelliger Beziehungstypen in einem ERM ist nicht immer ganz einfach und von der Beantwortung zweier Fragestellungen beeinflusst: Wie wird die Kardinalität des Beziehungstyps ermittelt und lässt sich die n-stellige Beziehung unter Verwendung binärer Beziehungstypen äquivalent ausdrücken? Diese Fragen sind auch von großer praktischer Bedeutung, da einige Vorgehensmodelle und Entwurfswerkzeuge ausschließlich binäre Beziehungstypen zulassen. Wir werden diese Problematik anhand eines Beispiels diskutieren.
76
3 Konzeptueller Datenbankentwurf
Abb. 3.6: Gegenüberstellung von Darstellungsformen für ERD, nach [Teor98]
3.1 Strukturorientierte Modellbildung
77
Beispiel 3.3: Dreistellige Beziehungstypen In diesem Beispiel wollen wir unterschiedliche Interpretationen dreistelliger Beziehungstypen untersuchen. Wir betrachten eine Beziehung zwischen Produkt, Teil und Lieferant mit der Semantik, dass für unterschiedliche Produkte Teile benötigt werden, die über Lieferanten bezogen werden. Bei der Bestimmung der Kardinalität eines n-stelligen Beziehungstyps müssen immer (n-1) der an der Beziehung beteiligten Entitytypen zusammengefasst werden, um die Anzahl der Entities des verbleibenden Typs zu bestimmen. Für den Beziehungstyp „liefert“ aus Abbildung 3.7 ergeben sich somit folgende Situationen: In Abbildung 3.7(a) bezieht das betrachtete Unternehmen von einem Lieferanten ein Teil, das genau in ein Produkt einfließt. Ein bestimmtes Teil in einem Produkt kann ausschließlich von einem Lieferanten stammen und ein Lieferant kann nicht mehr als ein bestimmtes Teil zum Produkt beisteuern. In der Situation, die in Abbildung 3.7(b) beschrieben ist, wird diese Einschränkung aufgehoben, indem ein bestimmter Lieferant für ein Produkt auch mehrere Teile liefern kann. Es gilt jedoch weiterhin, dass jedes Teil dieses Lieferanten ausschließlich für ein Produkt verwendet werden kann und dass für jedes Teil im Produkt ein einziger Lieferant als Bezugsquelle existieren kann. Diese Einschränkung ist in Abbildung 3.7(c) aufgehoben. Hier kann ein bestimmtes Teil eines Produktes auch von unterschiedlichen Lieferanten bezogen werden. Es gilt aber weiterhin die Einschränkung, dass ein Teil, das bei einem bestimmten Lieferanten bezogen wird, nur in ein Produkt eines bestimmten Typs eingebaut werden darf. Wird dieses Teil auch von anderen Lieferanten bezogen, so kann es auch für Produkte eines anderen Typs verwendet werden. Abbildung 3.7(d) enthält die Darstellung einer Situation, in der keine Einschränkungen hinsichtlich der Verwendung von Teilen in Produkten bestehen. Es kann jetzt ein Lieferant ein Teil liefern, das auch in unterschiedlichen Produkten Verwendung finden kann. Die semantische Aussagekraft dreistelliger Beziehungstypen kann noch erhöht werden, wenn für Entities bestimmter Typen eine verpflichtende Teilnahme an der Beziehung vorgeschrieben wird.
Beispiel 3.3: Dreistellige Beziehungstypen (Fortsetzung) In Abbildung 3.7(e) wird eine Situation beschrieben, in der eine Eigenproduktion ausgeschlossen wird, und alle Teile, die Bestandteil von Produkten sind, über Lieferanten bezogen werden. Unter Verwendung von dreistelligen Beziehungstypen kann mehr an Information dargestellt werden als mit drei binären Beziehungstypen möglich ist. In Abbildung 3.7(f) wird eine Situation beschrieben, die nicht mit der Situation, wie sie in Abbildung 3.7(d) dargestellt ist, übereinstimmt. Stellt ein Lieferant l ein bestimmtes Teil t her t, l und ist t in einem Produkt p enthalten t, p, das somit Teile enthält, die vom Lieferanten l bezogen werden p, l, so bedeutet das nicht notwendigerweise, dass die Beziehung auch in „liefert“ von Abbildung 3.7(d) enthalten sein muss. Eine äquivalente Darstellung (mit derselben semantischen Aussagekraft) zu Abbildung 3.7(d) kann erreicht werden, wenn man in das Datenmodell einen zusätzlichen Entitytyp „Lieferung“
78
3 Konzeptueller Datenbankentwurf
Abb. 3.7a–d: Beispiele dreistelliger Beziehungstypen
aufnimmt. Die Existenz von Entities vom Typ „Lieferung“ ist dann von der Existenz von Instanzen in allen anderen beteiligten Entitytypen abhängig. Abbildung 3.7(g) zeigt eine entsprechende Darstellung.
3.1.2
Weiterentwicklungen des Entity-Relationship-Modells
Ohne Anspruch auf Vollständigkeit sollen in diesem Unterkapitel die wichtigsten der in der umfangreichen Literatur genannten Erweiterungen des ERM genannt werden. Am Ende des Unterkapitels werden auch zwei prominente Vertreter von „erweiterten“ ERM vorgestellt. Die Aggregation wird verwendet, wenn durch Zusammenfassen bestehender Konzepte ein neues Objekt eines höheren Abstraktionsniveaus erzeugt werden soll. Aggregation gibt es auf unterschiedlichstem Niveau. So ist bereits im ursprünglichen ERM vorgesehen, dass Attribute zu zusammengesetzten Attributen aggregiert werden können, oder dass eine Attributmenge
3.1 Strukturorientierte Modellbildung
79
Abb. 3.7e–g: Beispiele dreistelliger Beziehungstypen (Fortsetzung)
zu einem Entitytyp zusammengefasst werden kann. Erweiterungen des ERM schlagen vor, Aggregation auch zur Vereinigung unterschiedlicher Typen zu einem neuen Entitytypen zuzulassen.
Beispiel 3.4: Aggregation im ERM In Abbildung 3.8 geben wir Beispiele für unterschiedliche Formen von Aggregation. Im ersten Beispiel werden mehrere Attribute zu einem komplexen Attribut aggregiert. Darunter zeigen wir die Aggregation von Attributen zu einem Objekt eines höheren Abstraktionsniveaus, einem Entitytyp. Das dritte Beispiel zeigt die Aggregation von in Beziehung stehenden Entitytypen zu einem neuen Entitytyp. Eine Vorgehensweise, die von einigen Varianten des ERM unterstützt wird.
80
3 Konzeptueller Datenbankentwurf
Abb. 3.8: Aggregation im ERM
Ein Erweiterungsvorschlag, der in vielen Modellen inkludiert ist, ist das Konzept der Generalisierung (Generalisation). Unter Generalisierung versteht man, dass Entities eines Typs aufgrund gemeinsamer Merkmalsausprägungen in Unterklassen (Sub-Klassen) zusammengefasst werden. Es entsteht somit eine Super-Klasse/Sub-Klassen-Hierarchie, wobei die Generalisierung vorschreibt, dass jedes Mitglied der Sub-Klasse ebenso ein Mitglied der übergeordneten Super-Klasse sein muss. Für die Super-Klasse hat sich auch die Bezeichnung generischer Objekttyp und für eine Sub-Klasse die Bezeichnung Spezialisierung eingebürgert. Der generische Objekttyp beinhaltet alle Attribute, die in allen Spezialisierungen gemeinsam gelten. Dies gilt auch für jenes Attribut, aufgrund dessen Werte die Zuteilung der Entities zu den einzelnen Spezialisierungen erfolgt. Solche Attribute werden auch als Diskriminatoren bezeichnet und im ERD als flaches Sechseck dargestellt. Die Generalisierung definiert eine IS-A-Beziehung (Ist-vom-Typ) zwischen Spezialisierung und generischem Objekttyp und impliziert eine Vererbung von Attributen von Super-Klassen zu Sub-Klassen. Es werden zwei Arten von Generalisierung unterschieden: Bei der Generalisierungshierarchie müssen die Entitymengen der Spezialisierungen disjunkt sein, während bei der Subtypenhierarchie Spezialisierungen auch überlappen können. Beispiel 3.5: Generalisierungs- und Subtypenhierarchie In Abbildung 3.9 zeigen wir ein Beispiel für eine Generalisierungs- und eine Subtypenhierarchie. Entities vom Typ „Person“ werden aufgrund von Werten ihres Attributes „Status“ den disjunkten Klassen „Geschäftspartner“ bzw. „Mitarbeiter“ zugeordnet. Der Entitytyp
3.1 Strukturorientierte Modellbildung
81
Abb. 3.9: Generalisierungs- und Subtypenhierarchie
„Person“ enthält alle gemeinsamen Attribute, die sowohl im Entitytyp „Mitarbeiter“ als auch im Entitytyp „Geschäftspartner“ gelten. Beide Spezialisierungen erben diese Attribute und werden noch zusätzliche Attribute haben, für die ausschließlich Entities des entsprechenden Typs Werte aufweisen können. In dem Beispiel ist Typ „Geschäftspartner“ auch in eine Subtypenhierarchie involviert. Das bedeutet, dass Entities existieren können, die sowohl vom Typ „Lieferant“ als auch vom Typ „Kunde“ sein können. Das Prinzip der Vererbung gilt auch für die Subtypenhierarchie. In dem Beispiel bedeutet dies, dass z. B. „Kunde“ alle Eigenschaften von „Person“ und „Geschäftspartner“ enthält und möglicherweise noch weitere eigene Eigenschaften zugeordnet hat. In den folgenden Unterkapiteln werden wir zwei prominente Vertreter von „erweiterten“ ERM vorstellen. Beide Ansätze haben das ursprüngliche ERM um unterschiedliche Aspekte erweitert. Unsere Darstellung beschränkt sich jedoch jeweils nur auf die wichtigsten Konzepte und ist sehr kurz gehalten. Für ein genaueres Studium muss auf die Originalliteratur verwiesen werden. 3.1.2.1
Strukturiertes Entity-Relationship-Modell (SERM)
Das strukturierte Entity-Relationship-Modell (SERM) [Sinz88], [Sinz93] zielt darauf ab, sowohl die Analysemöglichkeiten als auch die grafische Darstellungsform eines ERM für große Modellierungsprojekte zu verbessern. Unter Beachtung von Existenzabhängigkeiten ordnet das Modell die Entitytypen geometrisch so an, dass der Grad der Abhängigkeit von links nach rechts zunimmt. Alle Paare von in Beziehung stehenden Entitytypen werden nach dem Kriterium originär/abhängig geordnet, so dass ein SER-Diagramm, die grafische Darstellung eines SERM-Datenschemas, die Struktur eines gerichteten azyklischen Graphen aufweist. Durch
82
3 Konzeptueller Datenbankentwurf
Abb. 3.10: Konzepte des SERM [FeSi98]
die implizite Einführung einer „Leserichtung“ wird es dem Betrachter erleichtert, geeignete Einstiegsknoten zur Analyse des Diagramms zu finden. Das SERM unterscheidet drei unterschiedliche Arten von Objekttypen: Den E-Typ als Äquivalent zum Entitytyp, den R-Typ als Äquivalent zum Beziehungstyp sowie den ER-Typ (Entity-Relationship-Typ), welcher zur Modellierung eines Entitytyps und einer 1:1-Beziehung verwendet wird. Aus der Sicht des ursprünglichen ERMs entstehen ER-Typen durch das Zusammenfassen eines E- und eines zugehörigen 1:1-R-Typen zu einer Einheit. Jede Objekttypart besitzt innerhalb eines SER-Diagramms ein spezielles Rechtecksymbol. Beziehungen zwischen Objekttypen werden als Kanten dargestellt. Abbildung 3.10 zeigt die für SERDiagramme gewählte Notation. Für den Aufbau eines SER-Diagramms gelten folgende Darstellungsregeln, die die quasihierarchische Struktur des Diagramms festlegen: 1. Jede Kante wird gerichtet interpretiert und verläuft vom Gegenstandsanteil eines Objekttyps (Rechteck) zum Beziehungsanteil eines Objekttyps (Raute). Somit können als Startknoten einer Kante nur E- und ER-Symbole, als Zielknoten ER- und R-Symbole verwendet werden. 2. Jede Kante wird von links nach rechts dargestellt, so dass der Startknoten einer Kante geometrisch links vom Zielknoten angeordnet ist. Die Modellierung eines SERM-Datenschemas läuft auf zwei Ebenen ab. Die erste Ebene umfasst die Aufstellung eines SER-Diagramms, die zweite die Zuordnung von Attributen zu den Objekttypen. Abbildung 3.11 zeigt die SERM-Notation anhand der Struktur des Bestellvorganges. Eine Vergleichsmöglichkeit mit einer äquivalenten Darstellung in der in diesem Buch gewählten Notation bietet Abbildung 3.5. Beispiel 3.6: Beispiel Bestellvorgang als SERM (Abbildung 3.11) Siehe dazu die Analyse der Informationsanforderungen aus Beispiel 2.7. Im Beispiel 3.6 sind Lieferant und Artikel nicht existenzabhängige Objekttypen und daher im SERM-Diagramm ganz links anzuordnen. An einen Lieferanten können ein Auftrag oder
3.1 Strukturorientierte Modellbildung
83
Abb. 3.11: Bestellvorgang in SERM (nach [FeSi98])
mehrere Aufträge ergehen, jeder Auftrag bezieht sich jedoch auf genau einen Lieferanten. Ähnlich ist die Situation mit Rechnung. Ein Lieferant legt eine Rechnung oder mehrere Rechnungen vor, und jede Rechnung bezieht sich auf genau einen Lieferanten. Da Lieferanten ohne zugehörige Rechnung zulässig sind, besteht eine einseitige Existenzabhängigkeit zwischen Lieferant und Rechnung. Eine wechselseitige Existenzabhängigkeit besteht z. B. zwischen Rechnung und Rechnungsposition, da jede Rechnung zumindest eine Rechnungsposition haben muss und die Existenz einer Rechnungsposition von der Existenz einer entsprechenden Rechnung abhängt. Als Konsequenz der Anordnungsvorschriften in SERM ist es nicht möglich, eine zyklische Existenzabhängigkeit zwischen Objekttypen zu modellieren. Dies kann als Vorteil der Methode gegenüber dem ursprünglichem ERM gewertet werden, da Zyklen oft die Ursache für semantische Inkonsistenzen darstellen. Zusätzliche, in SERM inkludierte Erweiterungen des ERM stellen Generalisierung und Aggregation dar. Des Weiteren beinhaltet das Modell eine Methode zur Überführung von SER-Diagrammen in das relationale Datenbankmodell. 3.1.2.2
Entity-Category-Relationship-Modell (ECR-Modell)
Das ECR-Modell geht auf Elmasri et al. [ElWH85] zurück. Die Konzepte des Modells sind ähnlich den in den Unterkapiteln 3.1.1 und 3.1.2 dargestellten Konzepten. Eine besondere Beachtung verdienen die Strukturierung von Entitytypen in Super- und Subklassen und die damit in Beziehung stehenden Konzepte der Spezialisierung, Generalisierung und Kategorisierung.
84
3 Konzeptueller Datenbankentwurf
Im ECR-Modell wird unter einer Superklasse ein Entitytyp verstanden, der über mehrere „Untergruppierungen“ (Subklassen) verfügt. Jede Ausprägung einer Subklasse ist auch Entity der Superklasse, wodurch automatisch eine IS-A-Beziehung zwischen Sub- und Superklassen definiert wird. Bei einem Entity einer Subklasse und dem entsprechenden Entity der Superklasse handelt es sich also um dasselbe real existierende Objekt. Aus diesem Grund besitzt ein Entity einer Subklasse nicht nur Werte für Attribute der Subklasse, sondern „erbt“ die entsprechenden Attributwerte für Attribute der Superklassen. Im ECR-Modell wird unter dem Begriff der Spezialisierung der Prozess der Definition von Subklassen eines Entitytyps unter Berücksichtigung eines speziellen Charakteristikums der betroffenen Entities verstanden. Hierbei handelt es sich um eine Top-down-Vorgehensweise. Unter der Generalisierung hingegen versteht man den Umkehrprozess der Spezialisierung, bei der kleinere Unterschiede zwischen ähnlichen Entitytypen vernachlässigt werden, um die Entitytypen aufgrund ihrer sonstigen Übereinstimmungen zu einer generischen Superklasse zusammenzufassen. Die Generalisierung ist dabei durch eine Bottom-up-Vorgehensweise gekennzeichnet. Für Spezialisierungen und Generalisierungen können im ECR-Modell bestimmte Einschränkungen (constraints) definiert werden. Unter Verwendung der definition constraint kann der Designer festlegen, aufgrund der Werte welcher Attribute der Superklasse eine Zuordnung von Entities zu Subklassen erfolgt. Die disjointness constraint einer Spezialisierung bzw. Generalisierung gibt an, ob die Subklassen einer Superklasse disjunkt (disjoint) oder aber überlappend (overlapping) sind. Die completeness constraint gibt an, in welchem Maß und Umfang die Entities einer Superklasse einer untergeordneten Subklasse zugeordnet werden. Unterschieden wird dabei zwischen einer totalen Teilnahme, bei der jedes Entity der Superklasse Mitglied mindestens einer Subklasse sein muss und einer optionalen Teilnahme, bei der ein Entity der Superklasse nicht zwingend auch ein Mitglied einer Subklasse sein muss. Bisher wurde bei Super-/Subklassen-Beziehungen immer von einer einzigen Superklasse ausgegangen. Im ECR-Modell sind IS-A-Beziehungen höherer Komplexität vorgesehen, an denen mehrere Superklassen beteiligt sind. Eine Kategorie ist eine Subklasse mit stets zwei oder mehreren Superklassen. Im Gegensatz zur Attributsvererbung innerhalb von IS-A-Beziehungen bei Generalisierung und Spezialisierung geht die Vererbung im Falle von Kategorien wesentlich genauer vor. Ein Entity einer Kategorie erbt nur jene Attribute einer Superklasse, in der es auch Mitglied ist. Da für unterschiedliche Entities einer Kategorie somit unterschiedliche Attribute geerbt werden können, spricht man in diesem Fall auch von selektiver Vererbung. Die für das ECR-Modell gewählte grafische Notation unterscheidet sich nur durch die schematische Darstellung der neuen Konzepte von der in diesem Buch bisher verwendeten Notation. Da Super- und Subklassen Entitytypen darstellen, werden sie durch Rechtecke im ERD symbolisiert. IS-A-Beziehungen werden durch eine Kante zwischen Super- und Subklasse dargestellt, wobei das Untermengensymbol (⊂) die Richtung der Mengeninklusion angibt. Mehrfache Spezialisierungen werden durch zusätzliche Kreise in der IS-A-Beziehung dargestellt. Der Kreis steht in diesem Zusammenhang für die Angabe der disjointness constraint. Sind die Subklassen disjunkt, so wird dies durch ein „d“ im Kreis, ansonsten durch ein „o“ gekennzeichnet. Handelt es sich um totale Teilnahme, so wird dies durch einen Doppelstrich ausgedrückt.
3.1 Strukturorientierte Modellbildung
85
Um eine Kategorie in einem ERD auszudrücken, werden alle Superklassen über eine IS-ABeziehung und einen Kreis mit dem Entitytyp, der die Kategorie darstellt, verbunden. Das Untermengensymbol wird wiederum verwendet, um die Mengeninklusion auszudrücken und in den Kreis wird ein „u“ (union) eingetragen, um die Mengenvereinigung der Superklassen zu symbolisieren. Im Fall der Kategorisierung können IS-A-Beziehungen ein Prädikat enthalten, das zur selektiven Vererbung genutzt werden kann. Ebenso wie bei der Generalisierung und Spezialisierung wird eine totale Teilnahme an der Kategorisierung durch einen Doppelstrich ausgedrückt. Beispiel 3.7: Kategorisierung im ECR-Modell In Abbildung 3.12 zeigen wir die grafische Notation der Kategorisierung anhand zweier Beispiele. Entities vom Typ Eigentümer erben Attributwerte entweder von Person, Bank oder Firma. Ähnlich ist die Situation bei Zulassung. Abhängig vom Typ des betrachteBName
BAdresse Bank
Adresse
FAdresse
Name
FName Person
SVNr
Firma
Führerschein-Nr
Eigentümer
M Kaufdatum besitzt N Zulassungs-Nr Zulassung
FBaujahr FModell
LHersteller
Pkw
FHersteller
Lkw Fahrzeug-Nr
LModell
Fahrzeug-Nr
FTyp
Abb. 3.12: Kategorisierung im ER-Modell, nach [ElNa94]
LBaujahr
LGesGewicht
86
3 Konzeptueller Datenbankentwurf ten Fahrzeugs erbt ein Entity vom Typ Zulassung entweder Attributwerte von PKW oder LKW.
3.1.3
Literatur
Das ERM ist nunmehr seit vielen Jahren Gegenstand einer eigenen wissenschaftlichen Konferenzreihe. Um dem interessierten Leser einen raschen Zugang zu Originalarbeiten zu ermöglichen, wollen wir an dieser Stelle einen Quellenhinweis auf die seit 1990 erschienenen Berichte dieser Reihe geben ([ElKT94], [EmGo97], [Kang90], [Louc94], [Papa95], [PeTj92], [Teor91], [Thal96]). Allgemeine Literaturhinweise zum ERM finden sich unter den Quellenangaben am Ende dieses Kapitels.
3.1.4
Kontrollaufgaben
Aufgabe 3.1: Konzepte des ERM Beschreiben Sie anhand eines frei gewählten Beispiels die unterschiedlichen Konzepte des ERM. Gehen Sie auf die verschiedenen grafischen Darstellungsformen ein und geben Sie an, welche Konzepte bereits im ursprünglichen Modell nach Chen enthalten waren und welche später neu hinzu gekommen sind. Aufgabe 3.2: Eigenschaften für Attribute und Beziehungstypen Zeigen Sie anhand eines frei gewählten Beispiels, wie die in Abbildung 2.7 und Abbildung 2.10 gezeigten Strukturierungsmerkmale für Attribute und Beziehungstypen aus dem Anforderungsdokument in einem ERD ausgedrückt werden können. Aufgabe 3.3: Weiterentwicklungen des ERM Beschreiben Sie die wesentlichen Einschränkungen im ERM und zeigen Sie, wie im SERM und ECR-Modell versucht wurde, diese Einschränkungen zu umgehen. Aufgabe 3.4: ERM des Sportvereins Erstellen Sie aufgrund der in Aufgabe 2.6 durchgeführten Analyse der Informationsanforderungen des Sportvereins ein ERM. Aufgabe 3.5: ERM zur Verwaltung von Umweltschutzprojekten Entwerfen Sie ein ERD als Grundlage für eine zu erstellende DB zur Verwaltung von Umweltschutzprojekten. Projekte können nicht eindeutig in Kategorien eingeteilt werden. Es gibt Projekte mit Zielsetzung 1) Verringerung von Schadstoffemissionen, 2) Entwicklung von alternativen Verpackungsformen, 3) Energiesparmaßnahmen, 4) Entwicklung von alternativen Energieformen. Jede dieser Projektkategorien wird durch unterschiedliche Eigenschaften charakterisiert. Alle Projekte gemeinsam haben eine eindeutige Projektnummer, einen Projektträger (entweder eine natürliche oder eine juristische Person), einen Standort, einen Projektbeginn und ein voraussichtliches Abschlussdatum. Bei Projekten, die ihren Standort im Ausland haben, wird obige Einteilung in Kategorien nicht vorgenommen. Dafür wird zusätzlich zum Standort noch die Anschrift einer Kontaktperson mitgeführt. Inlandsprojekte werden entweder vom Fonds zur Förderung der wissenschaftlichen Forschung, vom Wirtschaftsförderungsfonds oder von
3.1 Strukturorientierte Modellbildung
87
beiden gemeinsam gefördert. Es soll pro Projekt und beteiligter Förderungsstelle die Höhe der Förderung, die Zahlungsart und das Datum der ersten Geldüberweisung gespeichert werden. Für jedes Projekt werden die Mitarbeiter am Projekt gespeichert. Ein Mitarbeiter darf nur an einem Projekt arbeiten. Für ein Auslandsprojekt darf es nicht mehr als zehn Projektmitarbeiter geben. Einer davon, der Leiter des Auslandsprojektes, muss die Sprache des Landes beherrschen, in dem das Projekt, das er leitet, angesiedelt ist. Außerdem wird für alle Mitarbeiter an Auslandsprojekten eine Ortszulage gewährt (sie kann für jeden Mitarbeiter individuell verschieden hoch sein). Mitarbeiter an Inlandsprojekten können einen Dienstwagen (Kennzeichen, Typ, Baujahr) haben. Aufgabe 3.6: ERM Autoverleihfirma Beschreiben Sie durch ein ERD folgenden Ausschnitt aus den Anforderungen an ein Informationssystem einer Autoverleihfirma: Es sollen Daten über Angestellte, Kunden und Fahrzeuge verwaltet werden. Angestellte (Anr, Name, Adresse, Gehalt) werden nach ihrer Verwendung in die zwei Gruppen Verwaltungsangestellte und KFZ-Mechaniker eingeteilt. Für Verwaltungsangestellte wird eine Liste ihrer speziellen Fähigkeiten geführt (z. B. Maschineschreiben, Englisch, Excel, . . . ). Mechaniker werden zu Teams zu jeweils fünf Leuten zusammengefasst. Jedem Team ist ein Leiter zugeteilt, er muss die KFZ-Meisterprüfung abgelegt haben. Jedes Fahrzeug des Unternehmens ist genau einem Mechanikerteam zugeordnet. Fahrzeuge sind in Kategorien eingeteilt. Mögliche Kategorien sind: Nutzfahrzeuge, Personenkraftwagen, Kombi, Fun-Car, Motorräder. Die Einteilung in Kategorien ist nicht eindeutig, so wird z. B. ein Cabrio sowohl in der Kategorie Fun-Car als auch in der Kategorie Personenkraftwagen geführt. Über Fahrzeuge sollen folgende Daten gespeichert werden: Kennzeichen, Anschaffungsdatum, Typenbezeichnung, PS. Für jede der angegebenen Kategorien sollen unterschiedliche Eigenschaften gespeichert werden. Wird ein Fahrzeug von einem Mechanikerteam repariert bzw. gewartet, sollen die Daten der Reparatur oder Wartung ebenfalls aufgezeichnet werden. Dabei ist relevant, welches Fahrzeug betroffen war, welches Team die Arbeit ausgeführt hat, wann die Arbeit ausgeführt wurde, wieviel Zeit benötigt wurde und welche Ersatzteile in welcher Menge verwendet wurden. Im Ersatzteillager wird ein Verzeichnis geführt, in dem für jedes Ersatzteil die Ersatzteilbezeichnung, die lagernde Menge und ein Meldebestand verwaltet werden. Über die Kunden des Unternehmens werden folgende Daten verwaltet: Kundennummer, Name, Adresse. Beim Abschluss eines Mietvertrages werden Datum, Zeit und Ort der Fahrzeugausgabe und der Fahrzeugrückgabe vereinbart. Es wird der Kilometerstand zum Zeitpunkt der Vergabe und zum Zeitpunkt der Rückgabe im Mietvertrag verzeichnet. Jeder Mietvertrag wird eindeutig durch den Kunden, das Fahrzeug und das Abschlussdatum bestimmt. Aufgabe 3.7: ERM Krankenhausinformationssystem Erstellen Sie für nachfolgende Anforderungen an ein Krankenhausinformationssystem (KIS) ein ERD. Eine Station wird durch die Stat-Nr, Stat-Bezeichnung und die Bettenanzahl beschrieben. Jede Station hat einen leitenden Arzt und eine Menge an zugeteilten Ärzten. Ein Arzt kann nur eine Station leiten, kann aber mehreren Stationen zugeteilt sein. Ärzte werden durch
88
3 Konzeptueller Datenbankentwurf
ihre SVNr eindeutig beschrieben und besitzen die Eigenschaften Name, Fachgebiet und Gehalt. KIS soll ein Verzeichnis aller bekannten Krankheiten und aller in der EU zugelassenen Medikamente beinhalten. Krankheiten werden eindeutig durch ICD sowie durch ihre Bezeichnung und die Therapie beschrieben. Für Medikamente sollen die Codex-Nr (eindeutig), die M-Bezeichnung, die Erzeugerfirma und die bekannten Nebenwirkungen aufgezeichnet werden. Ein Medikament kann mehrere Nebenwirkungen haben und Medikamente können sich hinsichtlich ihrer Wirkung gegenseitig beeinflussen. Für den Fall einer Beeinflussung soll ein Textfeld „Art der Beeinflussung“ vorgesehen werden. Medikamente heilen Krankheiten. Für Patienten soll eine Patienten-Nr, die SVNr, der Name und das Geb-Datum gespeichert werden. Patienten leiden unter bestimmten Krankheiten (auch mehrere möglich), liegen auf einer Station und bekommen von einem bestimmten Arzt Medikamente in unterschiedlicher Dosierung verabreicht. Für bestimmte Patienten soll Information über Verwandte gespeichert werden können. Verwandte sollen durch ihren Namen, das Verwandtschaftsverhältnis und das Geburtsdatum beschrieben werden. Es soll aus dem ERD ersichtlich sein, dass Ausprägungen von Verwandte nur so lange in der DB gespeichert bleiben, solange zugehörige Patienten im KIS enthalten sind. Aufgabe 3.8: ERM Kursverwaltung Stellen Sie den nachfolgend dargestellten Sachverhalt als ERD dar. Das betrachtete Unternehmen unterhält eine Ausbildungsabteilung, deren Aufgabe es ist, unterschiedliche Kurse durchzuführen. Jeder Kurs findet innerhalb des Unternehmens an verschiedenen Orten statt. Die zu erstellende DB enthält sowohl Kurse, die bereits abgehalten wurden, als auch Kurse, deren Abhaltung erst geplant ist. Folgende Details sollen modelliert werden: • Für jeden Kurs: Kursnummer (eindeutig), Kursbezeichnung, Kursbeschreibung, vorausgesetzte Kurse (falls vorhanden), Zeitbezug (durchgeführt, geplant). • Für jeden vorausgesetzen Kurs seine Kursnummer und Kursbezeichnung. • Für jedes Kursangebot: Datum, Ort, Art (z. B. ganztägig, halbtägig), beteiligte Leiter, beteiligte Teilnehmer. • Für jeden Kursleiter eines angebotenen Kurses: Mitarbeiternummer und Name • Für jeden Kursteilnehmer an einem angebotenen Kurs: Mitarbeiternummer, Name, Gehalt. Aufgabe 3.9: ERM Flughafeninformationssystem Die zu erstellende DB soll einen Ausschnitt der Anforderungen an ein Flughafeninformationssystem darstellen. Eine umfangreiche Anforderungsanalyse hat zu folgender informellen Beschreibung der Anforderungen geführt: Die DB soll zur Verwaltung von Informationen über Flugzeuge, ihre Eigner, Angestellte des Flughafens (Piloten, Techniker) und Wartungsarbeiten verwendet werden. Jedes Flugzeug hat eine Registriernummer, gehört zu einem bestimmten Typ und ist einem Hangar zugeordnet. Jeder Flugzeugtyp hat eine bestimmte Modellbezeichnung, Passagierkapazität und Gewicht. Ein Hangar wird durch eine Nummer, seine Kapazität und seinen
3.2 Struktur- und funktionsorientierte Modellbildung
89
Standort charakterisiert. Eigner von Flugzeugen sind entweder natürliche Personen oder Firmen. Sie haben Flugzeuge zu einem bestimmten Zeitpunkt erworben. Techniker sind für Wartungsarbeiten an bestimmten Flugzeugtypen geschult und führen Wartungen durch. Für jede Wartung wird ein Servicebuch geführt, wobei das Datum, Arbeitsstunden und die Art der Arbeit eingetragen werden. Wartungen konsumieren Ersatzteile. Piloten besitzen Lizenzen und dürfen davon abhängig Flugzeuge fliegen. Modellieren Sie den dargestellten Sachverhalt unter Verwendung des ERM.
3.2
Struktur- und funktionsorientierte Modellbildung
3.2.1
Gründe für die Verwendung der Kombinationsmethode
Die klassischen Spezifikations- und Entwurfsmethoden nutzen als Entwurfsgrundlage vornehmlich die Funktionen, die ein System oder eine Systemkomponente zur Verfügung stellen muss. Als Beschreibungsmittel werden meist Datenflussdiagramme (siehe Unterkapitel 2.3.2) eingesetzt, die die Eingabe, Ausgabe und Transformation von Daten durch Prozesse und den Datenfluss zwischen Prozessen auf unterschiedlichem Abstraktionsniveau darstellen. In den letzten Jahren hat sich die rein funktionsorientierte Vorgehensweise beim Datenbankentwurf als nicht zweckmäßig herausgestellt, da eine ausschließliche Betrachtung von Funktionen zwangsläufig zu wenig integrierten und oft starke Redundanz aufweisenden Datenbeständen führt. Außerdem verfügen Funktionsmodelle über klar definierte Systemgrenzen, die Erweiterungen bzw. Veränderungen eines Systems nur schwer ermöglichen. Die Funktionsmodellierung ist als Spezifikations- und Entwurfsmethode nur für Anwendungen geeignet, in denen die zu verarbeitenden Daten eine viel geringere Bedeutung als die darauf zugreifenden Funktionen besitzen. Der funktionsorientierten Vorgehensweise beim Datenbankentwurf steht die rein strukturorientierte Vorgehensweise gegenüber. Bei der strukturorientierten Vorgehensweise stehen die Daten und ihre Beschreibung in einem Datenmodell im Mittelpunkt der Betrachtung. Das Datenmodell ist sowohl Ausgangspunkt für den technischen Entwurf der DB als auch für die Spezifikation der Funktionen. Es ist statisch, d. h. es beschreibt keine Abläufe zur Verarbeitung der Daten, sondern ausschließlich eine zeitpunktunabhängige Darstellung der Struktur der Daten. Die strukturorientierte Vorgehensweise ist eine wichtige Voraussetzung für die Integration betrieblicher Informationssysteme, da die Daten hier so strukturiert werden, dass sie von den Funktionen und Programmen weitgehend unabhängig sind. Es lassen sich so Redundanzen und Inkonsistenzen in den Datenbeständen weitgehend vermeiden. Aufgrund der Einschränkungen der funktionsorientierten Modellbildung wird in vielen Entwurfsprojekten das Datenmodell gegenüber dem Funktionsmodell favorisiert. Dies wird auch dadurch gerechtfertigt, dass die relevanten Daten einer Unternehmung leichter zu erheben sind als die Funktionen. Des Weiteren weisen die Daten in den meisten Fällen eine längere Lebensdauer auf und haben eher eine statische Struktur, während sich Funktionen häufiger ändern. Allerdings kann eine Überbewertung der Daten zu einer Vernachlässigung der funktionalen Aspekte führen, d. h. es werden nur die konzeptuellen Datenstrukturen ermittelt und
90
3 Konzeptueller Datenbankentwurf
dargestellt, aus denen sich dann später die funktionalen Zusammenhänge jedoch nicht mehr ableiten lassen. Feststellung 3.2: Kombination von Daten- und Funktionsmodellen Bei einer getrennten Analyse von Daten und Funktionen sind Datenstrukturen und funktionsorientierte Programme nur schwer aufeinander abstimmbar. Werden Funktions- und Datenmodelle eigenständig entwickelt, entsteht zwischen DBS und auf die Daten zugreifenden Programmen eine sehr breite und pflegebedürftige Schnittstelle. Es liegt daher nahe, Daten- und Funktionsmodelle zu kombinieren, um diese Nachteile zu vermeiden und die Vorteile beider Methoden in eine einheitliche Methode zu integrieren. Welche Möglichkeiten dafür in Frage kommen, soll in diesem Unterkapitel untersucht werden. Es sind verschiedene Vorgehensweisen denkbar, um Daten- und Funktionsmodelle zu kombinieren. So kann z. B. erst eine Funktionsanalyse mit anschließender Datensynthese erfolgen. Bei dieser Vorgehensweise werden die Funktionen eines Systems schrittweise zerlegt und für die so entstandenen elementaren Funktionen werden dann Datenmodelle entworfen, die in einer Synthese zu einem unternehmensweiten Datenmodell integriert werden. Eine andere Vorgehensweise wäre, das Datenmodell ähnlich wie das Funktionsmodell direkt top-down schrittweise zu verfeinern. Diese Vorgehensweise hätte den Vorteil, dass Daten- und Funktionsmodellierung parallel durchgeführt werden können und das Informationssystem aus diesen beiden Sichten stufenweise herausgearbeitet werden kann. Im folgenden Unterkapitel wird die Kombination aus struktur- und funktionsorientierter Modellbildung anhand der zweiten Alternative genauer besprochen.
3.2.2
Kombination von ERM und DFD
Die integrierte Methode für die Daten- und Funktionsanalyse wurde von Batini, Ceri und Navathe [BaCN92] vorgeschlagen und beruht auf einer integrierten Top-down-Verfeinerung eines Funktions- und eines Datenmodells. Die Methode führt zu einem unternehmensweiten Datenmodell, in dem Verfeinerungen, Verdichtungen und Ergänzungen zu beiden Modellen in einem iterativen und nicht in einem ausschließlich phasenbezogenen Prozess vorgenommen werden. Die Methode soll zuerst vorgestellt und dann anhand eines Beispiels näher erläutert werden. Ausgangspunkt der Methode ist die Vorstellung vom zu entwickelnden Informationssystem oder eines ausgewählten Funktionsbereiches einer bestimmten Nutzergruppe (externe Sicht auf das DBS). Im nächsten Schritt werden die Schnittstellen zwischen den einzelnen Funktionsbereichen im Unternehmen sowie die Schnittstellen zwischen Informationssystem und seiner Umwelt (z. B. bestehende Applikationen, Nutzer . . . ) charakterisiert. Dies führt zu einer ersten Festlegung der Input-/Outputflüsse und damit verbunden der Hauptprozesse des Informationssystems, die die zuvor gefundenen Schnittstellen nutzen. Aus den Hauptprozessen ergibt sich ein erstes funktionales Kontextdiagramm, das so genannte F-Grundschema. Aus dem F-Grundschema wird ein erstes Datenmodell entwickelt, das die Struktur der Daten auf dem hohen Abstraktionsniveau des Kontextdiagrammes repräsentiert. Das Datenmodell wird als D-Grundschema bezeichnet. Während des Entwurfs des D-Grundschemas muss geprüft
3.2 Struktur- und funktionsorientierte Modellbildung
91
werden, ob auch alle Initiatoren und Terminatoren des F-Grundschemas im Informationssystem enthalten sein sollen. Dies ist ein schwieriger Vorgang, weil es nicht immer eindeutig ist, ob entsprechende Entities im Informationssystem eine Rolle spielen oder lediglich eine Informationsquelle für das System von außen darstellen. Sind im D-Grundschema die ersten Entitytypen identifiziert, muss überprüft werden, ob sie auf demselben Abstraktionsniveau wie die entsprechenden Komponenten des F-Grundschemas liegen. Ist dies nicht der Fall, müssen Aggregationen und Generalisierungen verwendet werden, um das Abstraktionsniveau des D-Schemas dem des F-Schemas anzugleichen. Nach den vorbereitenden Schritten ist die Bestimmung des D- und F-Grundschemas abgeschlossen. Beide Schemata zeigen eine anfängliche Darstellung der Daten bzw. der Funktionen, die in den folgenden Phasen nach und nach weiter verfeinert werden. Die eigentliche Modellbildung entsteht durch eine fortschreitende Verfeinerung von F- und D-Schema. Das F-Schema kann entweder durch Anwendung der Top-down-Vorgehensweise verfeinert werden, indem jeder Prozess in mehrere Teilprozesse untergliedert wird, oder es kann die Inside-Out-Strategie zur Anwendung kommen. Dabei wird der Datenfluss zwischen Initiator und einem Prozess betrachtet, der die Ursache dafür sein kann, dass der Prozess in Teilprozesse gegliedert werden kann. Für die so entstandenen neuen Prozesse im F-Schema werden Datenspeicher und Prozesse bestimmt, aus denen Informationen ausgelesen oder an die Daten weitergegeben werden. Danach wird wieder geprüft, ob die Datenspeicher und Prozesse Informationen von noch nicht im F-Schema enthaltenen Komponenten erhalten bzw. weitergeben. Ist dies der Fall, werden solche Komponenten in das F-Schema aufgenommen. Das D-Schema wird verfeinert, indem geprüft wird, ob alle Komponenten des F-Schemas eine Entsprechung im D-Schema besitzen. Ist das nicht der Fall, so werden in das D-Schema neue Entity- und Beziehungstypen aufgenommen bzw. durch Bildung von Generalisierungen und Aggregationen Verfeinerungen vorgenommen. Das D-Schema ist schließlich komplett in Bezug auf das F-Schema, wenn die Struktur aller Initiatoren, Terminatoren und Datenspeicher aus dem F-Schemas auch im D-Schema beschrieben ist. Das F-Schema ist komplett in Bezug auf das D-Schema, wenn auch jeder Entitytyp aus dem D-Schema zumindest in einem Prozess im F-Schema Verwendung findet. Im Fall von gegenseitiger Vollständigkeit befinden sich D- und F-Schema auf demselben Abstraktionsniveau und eine Verfeinerungsstufe ist abgeschlossen und die nächste kann beginnen. Alle weiteren Verfeinerungsstufen beginnen wieder mit einer Verfeinerung des F-Schemas, wobei die Vorgehensweise dieselbe bleibt. Es wird mit der Top-down- oder Inside-OutVorgehensweise geprüft, ob irgendwelche Prozesse noch weiter untergliedert werden können oder weitere Datenspeicher eingeführt werden müssen. Dazu kann jetzt auch das überarbeitete D-Schema aus der vorhergegangenen Verfeinerungsstufe Hilfe leisten. Es wird geprüft, ob alle Entity- und Beziehungstypen, die in diesem verwendet wurden, durch Prozesse und Datenspeicher abgedeckt sind oder weitere hinzugefügt werden müssen. Auch die weiteren Verfeinerungen des D-Schemas entsprechen der ersten. In der letzten Verfeinerung des D-Schemas werden den Entitytypen und Beziehungstypen alle nötigen Attribute, die aus den Entitykatalogen des Anforderungsdokumentes bekannt sind, hinzugefügt. Sind beide Schemata ausreichend verfeinert, wird ein abschließender Vollständigkeitstest durchgeführt. Für das D-Schema wird dabei geprüft, ob alle Entity- und Beziehungstypen von einem oder mehreren Datenspeichern und Prozessen aus dem F-Schema benutzt werden. Für das F-Schema wird untersucht, ob es für jeden Entity- und Beziehungstyp einen Prozess gibt,
92
3 Konzeptueller Datenbankentwurf
der diese erzeugt oder benutzt. Gegenseitige Vollständigkeit ist folgendermaßen definiert: Das D-Schema ist vollständig in Bezug auf das F-Schema, wenn alle Anforderungen, die durch Datenflüsse und Datenspeicher im F-Schema ausgedrückt werden, auch im D-Schema vorkommen. Das F-Schema ist vollständig in Bezug auf das D-Schema, wenn alle Operationen, die eine Datenanfrage oder -manipulation erwirken, durch einen Prozess des F-Schemas erfolgen. Es muss also für jedes gespeicherte Datenelement einen Prozess geben, der es erzeugt, verändert und eventuell auch löscht. Die Kombination aus struktur- und funktionsorientierter Modellbildung soll nun anhand eines Fallbeispiels erörtert werden. Beispiel 3.8: Struktur- und funktionsorientierte Modellbildung Das Beispiel behandelt einen Teilbereich des Bestellwesens, nämlich die Auswahl von Lieferanten aufgrund ihrer Angebote nach einer Ausschreibung. U.a. sind in diesem Beispiel folgende Informationen von Relevanz: Für bestimmte Artikel sind vorgegebene Liefervoraussetzungen (wie z. B. Transport im Kühlwagen, Lieferservice innerhalb von zwölf Stunden, Mindestbezüge) vorgesehen und Lieferanten bieten Artikel mit unterschiedlichen Konditionen an (z. B. Mindestabnahme, Transportzuschlag, Zahlungskonditionen). In den Auswahlprozess werden auch subjektive Einflussgrößen (wie z. B. bisherige Erfahrungen mit diesem Lieferanten oder seine Reputation) einbezogen. Die struktur- und funktionsorientierte Modellbildung des Funktionsbereiches „Lieferanten-Auswahl“ ist in Abbildung 3.13 dargestellt. Der Vorgang „Lieferanten-Auswahl“ wird von einem Initiator „Lieferant“ angestoßen, der für bestimmte Artikel ein Angebot vorlegt. Diese Situation ist im F-Grundschema (Abbildung 3.13(a)) dargestellt. Der Prozess 1 wird von einem Lieferanten initiiert, trifft nach Zugriff auf Artikeldaten eine Entscheidung und informiert den Lieferanten über das Ergebnis. Aus diesem ersten Kontextdiagramm kann bereits ein D-Grundschema (Abbildung 3.13(b)) entwickelt werden. Der Datenspeicher „Artikel“ und der Initiator „Lieferant“ werden vorerst als Entitytyp abgebildet. Da Artikel von Lieferanten angeboten werden, wird zur Darstellung dieses Sachverhaltes ein Beziehungstyp vorgesehen. Das Fund D-Grundschema beschreiben den Funktionsbereich „Lieferantenwahl“ auf der höchstmöglichen Abstraktionsebene. In der ersten Verfeinerung des F-Schemas wird der Prozess „Lieferanten-Auswahl“ aus dem F-Grundschema genauer analysiert und im Rahmen einer Top-down-Zerlegung durch ein neues DFD genauer spezifiziert. Aus Abbildung 3.13(c) ist ersichtlich, dass alle eingegangenen Angebote in einem Datenspeicher „Angebote“ abgelegt werden. Dies ist notwendig geworden, da das D-Schema eine Beziehung „bietet-an“ vorsieht, die im F-Schema bisher keine Entsprechung hat. In einem weiteren Bearbeitungsschritt wird der Lagerbestand für in Angeboten genannte Artikel geprüft. Weitere Details sind aus dieser ersten Verfeinerung nicht ersichtlich. Das F-Schema bildet nun wieder die Grundlage zur Überarbeitung des D-Schemas aus dem vorhergegangenen Analyseschritt. Die bisherige Version des D-Schemas differenziert nicht zwischen Angeboten und Artikeln. Diese Darstellung im Datenmodell ist nun nicht mehr konsistent mit der dargestellten Situation im Funktionsmodell und eine Verfeinerung des D-Schemas ist angebracht.
3.2 Struktur- und funktionsorientierte Modellbildung
Abb. 3.13a–d: Struktur- und funktionsorientierte Modellbildung
93
94
3 Konzeptueller Datenbankentwurf
Abb. 3.13e,f: Struktur- und funktionsorientierte Modellbildung (Fortsetzung)
3.2 Struktur- und funktionsorientierte Modellbildung
95
In Abbildung 3.13(d) haben wir uns zur Differenzierung für einen Entitytyp „Angebot“ und einen Beziehungstyp „wird_bezogen“ entschieden. In bestimmten Situationen hätte man den Sachverhalt durchaus auch anders modellieren können, z. B. Angebote als Beziehungstypen zwischen Lieferant und Artikel oder Angebote als Spezialisierung von Artikel im Rahmen einer Generalisierungshierarchie. In einem weiteren Verfeinerungsschritt wird das F-Schema einer neuerlichen Analyse unterzogen, und der Prozess „Weiterverarbeitung“ wird in seine Teilprozesse aufgespalten. In Abbildung 3.13(e) ist die Verfeinerung wie folgt dargestellt: Prozess „Voraussetzung prüfen“ greift auf einen Datenspeicher „Artikel“ zu und prüft, ob für die im Angebot genannten Artikel besondere Liefervoraussetzungen existieren. Prozess „Bedingungen prüfen“ prüft die im Angebot angeführten Lieferbedingungen anhand der für die Artikel bestehenden Liefervoraussetzungen. Prozess „Erfahrungen auswerten“ greift auf den Datenspeicher „Lieferant“ zu, um eventuell vorhandene Informationen über den Angebotleger zu eruieren. Im Prozess „Entscheidung treffen“ werden die erhobenen Daten miteinander verglichen und es wird entschieden, ob eine Bestellung vorgenommen wird oder nicht. Im Falle einer Bestellung erfolgt die Zuordnung von „Lieferant“ zum Terminator „Artikel“ und die Benachrichtigung des Angebotlegers. Im Fall einer Ablehnung erfolgt eine Mitteilung an den Angebotleger. Die Abbildung 3.13(e) enthält das endgültige funktionale Modell der Lieferantenwahl. Aufgrund der Top-down-Vorgehensweise und der mehrmaligen Verwendung ähnlicher Datenspeicher auf unterschiedlichen Modellierungsebenen weist das DFD Datenredundanzen auf, die bei der Ermittlung des endgültigen D-Schemas vermieden werden sollen. Zur Erstellung des endgültigen D-Schemas wird vorerst das bisherige Datenmodell herangezogen und anhand des F-Schemas auf Vollständigkeit überprüft. Eine mögliche Lösung für das endgültige D-Schema ist in Abbildung 3.13(f) dargestellt. In einem abschließenden Entwurfsschritt werden beide Schemata gegenseitig auf Übereinstimmung und Vollständigkeit geprüft und das D-Schema um Attribute erweitert. In dem Beispiel sind Attribute nur exemplarisch angegeben. Die dargestellte Kombinationsmethode aus struktur- und funktionsorientierter Vorgehensweise zur Bildung eines Datenmodells zeichnet sich dadurch aus, dass zwischen Daten- und Funktionsmodellierung eine starke Interaktion herrscht. Änderungen am F-Schema können Änderungen am D-Schema verursachen und Änderungen am D-Schema können wiederum Auswirkungen auf das F-Schema haben. Wird z. B. bei einer Verfeinerung des F-Schemas ein Prozess in mehrere Teilprozesse gegliedert, so kann das zu drei unterschiedlichen Auswirkungen im D-Schema führen: Bezieht sich jeder der Teilprozesse auf eine disjunkte Untermenge eines Entitytyps, so kann im D-Schema eine Generalisierung des Entitytyps vorgenommen werden. Bezieht sich nur einer der Teilprozesse auf eine Teilmenge der Entities eines bestimmten Typs, so kann im Datenmodell eine Untermengenhierarchie gebildet werden. Die letzte Möglichkeit besteht darin, dass sich alle Teilprozesse weiterhin auf alle Entities eines bestimmten Typs beziehen. Ist dies der Fall, so kann keine Verfeinerung am Datenmodell vorgenommen werden. Verfeinerungen am D-Schema können jedoch auch Auswirkungen auf das F-Schema haben. Wird z. B. im D-Schema eine Generalisierung vorgenommen, so kann das Auswirkungen im F-Schema haben. Aus einem Prozess können weitere entstehen und jeder Teilprozess wirkt sich auf eine Spezialisierung im Datenmodell aus. Die Teilprozesse können unabhängig voneinander sein oder durch Datenfluss oder über Datenspeicher miteinander verbunden werden.
96
3 Konzeptueller Datenbankentwurf
Um ein vollständiges und konsistentes System zu erhalten, ist es wichtig, sowohl funktionale als auch die Datenstruktur betreffende Aspekte in den Entwurfsprozess zu integrieren. Dabei ist wichtig, dass Daten- und Funktionsmodelle nicht getrennt voneinander entwickelt werden, sondern dass beide Aspekte im Laufe der gesamten Entwicklung nebeneinander berücksichtigt werden. Dies ist insbesondere darin begründet, dass zwischen den unterschiedlichen Modellen eine strenge Bindung herrscht und Hinzufügungen oder Änderungen in dem einen Modell durchaus Auswirkungen auf das andere Modell haben können. Die in diesem Unterkapitel dargestellte Modellierungstechnik basiert auf diesen Überlegungen.
3.2.3
Kontrollaufgaben
Aufgabe 3.10: struktur- vs. funktionsorientierte Modellbildung Erklären Sie anhand eines freigewählten Beispieles den Unterschied zwischen strukturorientierter und funktionsorientierter Modellbildung. Wie können sich beide Vorgehensweisen zur Anwendungsentwicklung ergänzen? Aufgabe 3.11: Kursverwaltung Die Kursverwaltung der Firma „ABC Ltd“ soll rechnerunterstützt durchgeführt werden. Führen Sie aufgrund der Angaben aus Aufgabe 2.7 eine funktions- und eine strukturorientierte Analyse unter Verwendung der Kombinationsmethode durch.
3.3
Objektorientierte Modellbildung
Aus objektorientierter Sicht sind die wesentlichen Merkmale eines informationstechnischen Systems seine Objekte, ihre Zustände und die Ereignisse, die Zustandsübergänge von Objekten initiieren. Bei den bisher diskutierten Methoden der Modellbildung werden abhängig vom Zweck des Systems die Schwerpunkte bei seiner Entwicklung auf diese drei Merkmale unterschiedlich gesetzt. Liegt der Schwerpunkt des Systems auf seinen Prozessen und Verfahren, so ist es sinnvoll, das Gesamtsystem in einer Top-down-Vorgehensweise in Funktionen zu zerlegen, die dann auf der untersten Ebene beschrieben und implementiert werden. Diese Vorgehensweise haben wir bereits bei der funktionsorientierten Modellbildung kennen gelernt. Beim Entwurf von DB stehen die vom System verwalteten Informationseinheiten, also die Daten, im Vordergrund. Wie wir zu Beginn dieses Kapitels gesehen haben, eignen sich zur Analyse der Struktur der Informationseinheiten am besten semantische Datenmodelle. Für DB sind von weiterer Bedeutung, jedoch nicht mehr im eigentlichen Zentrum des Interesses, die Prozesse, die Daten transformieren und die möglichen Zustände der Informationseinheiten, die durch Integritätsbedingungen vom DBS oder den Anwendungsprogrammen geprüft werden sollen. Bei der Entwicklung von Systemen mit zeitkritischen und dynamischen Eigenschaften liegt der Schwerpunkt auf der Analyse der Ereignisse, auf die das System reagieren muss. Diese Eigenschaften spielen in Standarddatenbankanwendungen nur eine untergeordnete Rolle. Die Methoden zur objektorientierten Modellbildung werden nicht ausschließlich zum Datenbankentwurf eingesetzt. Da sie sehr allgemein gehalten sind und eine umfassende Sichtweise auf ein System unterstützen, werden sie für Analyse und Modellbildung unterschiedlicher komplexer Problemstellungen für Softwaresysteme allgemeiner Art eingesetzt.
3.3 Objektorientierte Modellbildung
97
Feststellung 3.3: Objektorientierte Modellbildung Bei der objektorientierten Modellbildung werden alle drei Merkmale eines informationstechnischen Systems (Objekte, Zustände und Ereignisse) gleichberechtigt betrachtet und dem zentralen Konzept „Objekt“ zugeordnet. Das wesentliche Charakteristikum der objektorientierten Modellbildung sind also die ganzheitliche Vorgehensweise bei der Analyse des Systems und das zentrale Konzept des Objektes, das alle Eigenschaften der Informationseinheiten beinhaltet. Ausgangspunkt einer objektorientierten Analyse sind weiterhin die Informationseinheiten des Systems. Sie werden zunächst in einem statischen Modell zeitpunktbezogen untersucht. Im Anschluss daran werden für alle Informationseinheiten Verhaltensweisen, Zustände und zulässige Operationen analysiert und zu einem integrierten Objektmodell zusammengefasst. Im Allgemeinen bestehen objektorientierte Ansätze zur Modellbildung zumindest aus folgenden Komponenten: Objektmodell Zur Analyse der Struktur der Informationseinheiten und Darstellung der ganzheitlichen Sicht auf das Informationssystem. Dynamisches Modell Jeder Objekttyp wird während seiner Existenz in der DB unterschiedliche Zustände durchlaufen. Die Ereignisse, die zu einem Zustandswechsel führen können, werden im dynamischen Modell beschrieben. Funktionales Modell Analog zur funktionsorientierten Modellbildung werden hier Funktionen und Prozesse, Datenflüsse und Verfahren analysiert. Ausgangspunkt einer objektorientierten Modellbildung bildet eine strukturorientierte Analyse, während der die identifizierten Objekte des Problembereiches und ihre Struktur ermittelt werden. Die Ergebnisse dieser Analyse werden dann in ein Objektmodell eingetragen. Neben den strukturellen Eigenschaften beinhalten Objekte auch eine Menge an zulässigen Operationen und besitzen Beziehungen zu anderen Objekten. Operationen sind die einzige Möglichkeit, auf die Attributwerte von Objekten zuzugreifen. Die wichtigsten Operationen jeder Objektklasse werden unter Verwendung eines funktionalen Modells (z. B. Datenflussdiagramm im Rahmen einer funktionsorientierten Modellbildung) analysiert und in das Objektmodell aufgenommen. Das Verhalten von Objekten ist über Datenwerte oder Beziehungen zu anderen Objekten charakterisiert, die sich im Laufe der Existenz eines Objektes ändern. Tritt ein Ereignis ein, das zu einer Änderung eines solchen Datenwertes oder zur Änderung einer entsprechenden Beziehung führt, so muss eine entsprechende Operation ausgeführt werden und der Zustand des Objektes ändert sich. Diese zeitlichen Aspekte, die auch den Lebenszyklus eines Objektes beschreiben, werden gewöhnlich durch Zustandsdiagramme erfasst, die zu jedem Objekttyp des Objektmodells angefertigt werden.
98
3 Konzeptueller Datenbankentwurf
Die Methoden der objektorientierten Modellbildung wurden sehr stark von der Entwicklung objektorientierter Programmiersprachen beeinflusst. In diesem Bereich wurde schon sehr früh erkannt, dass die Analyse der Zustände von Realweltobjekten sehr wichtig für das betrachtete System ist. So wurde am Norwegian Computing Center bereits in den 60er Jahren zur ereignisund prozessorientierten Simulation die Sprache SIMULA (Simulation Language) entwickelt, die wohl als älteste objektorientierte Programmiersprache betrachtet werden kann. In den 80er Jahren wurden dann einige objektorientierte Programmiersprachen wie C++, Smalltalk oder Eiffel vorgestellt. Die ersten Verfahren zur objektorientierten Analyse und Modellbildung gehen auf das Ende der 80er und den Beginn der 90er Jahre zurück. Wie schon in der Einleitung zu Kapitel 3 festgestellt wurde, ist die objektorientierte Modellbildung keinesfalls eine gänzlich neue Entwicklung, sondern stellt eher einen evolutionären Schritt in der Systemanalyse dar und baut auf der semantischen Datenmodellierung, der dynamischen Modellbildung sowie der objektorientierten Programmierung auf. Die objektorientierte Betrachtungsweise eines Systems ermöglicht es, die Funktionalität des Systems durch interagierende Objekte darzustellen und dabei auch die sich ändernden Zustände zu berücksichtigen, die wiederum auf das Eintreten von vordefinierten Ereignissen zurückzuführen sind. Auf diese Weise wird erreicht, dynamische Anforderungen und Bearbeitungsanforderungen aus dem Anforderungsdokument in die Modellbildung zu integrieren. Mit den bisher bekannten Methoden war es nur möglich, Informationsanforderungen und funktionale Anforderungen in einem Modell zu vereinen, um so die Konsistenz und Verständlichkeit des Systems zu erhöhen. Neben der Integration unterschiedlicher Betrachtungsweisen auf ein System bietet die Methode der objektorientierten Modellbildung den zusätzlichen Vorteil, dass in einem umfangreichen Projekt auf der Basis einer gemeinsamen Vorgehensweise gearbeitet werden kann, da das objektorientierte Paradigma auf viele Bereiche Einfluss genommen hat. So kann ausgehend von der Systemanalyse, über die Modellbildung, die Gestaltung der Benutzerschnittstelle, die Implementation oder aber auch für das Datenbankmodell auf objektorientierte Konzepte zugegriffen werden. Im nun folgenden Teil des Unterkapitels wollen wir die wichtigsten objektorientierten Konzepte darstellen, um dann aus der großen Anzahl von bekannten Methoden zur objektorientierten Modellbildung auf eine der neuesten und aussichtsreichsten Methoden näher einzugehen.
3.3.1
Konzepte der Objektorientierung
Es soll nicht Aufgabe diese Abschnitts sein, die Konzepte des objektorientierten Paradigmas gänzlich zu beschreiben. Wir wollen hier nur die wichtigsten betrachten, denn für eine detaillierte Übersicht sei dem interessierten Leser die Lektüre weiterführender Literatur empfohlen. 3.3.1.1
Objekttyp und Objektklasse
Das Konzept des Objekttyps hat sich aus dem aus Programmiersprachen bekannten Konzept des abstrakten Datentyps (ADT) entwickelt. Wie beim Konzept der Typisierung in semantischen Datenmodellen werden „ähnliche“ Objekte der Realität in einem gemeinsamen Objekttyp klassifiziert. Ähnlichkeit bedeutet in diesem Zusammenhang, dass alle Objekte eines Typs durch gleiche Charakteristiken, nämlich die gleiche Struktur, gleichförmiges Verhalten und eine gemeinsame Menge möglicher Zustände beschrieben sind. Ein Objekttyp ist somit ein
3.3 Objektorientierte Modellbildung
99
Muster, das als Vorlage zur Erzeugung neuer Objekte genutzt wird. Die im Typ definierten Attribute bilden die Struktur der Objekte, die dem Objekttyp zugeordneten Operationen implementieren das Verhalten von Objekten. Die Operationen sind dem Typ zugeordnet, werden jedoch von allen Objekten (Exemplaren, Instanzen eines Objekttyps) gemeinsam genutzt, um die Objektdaten (Attributwerte) zu manipulieren. Weitere Kriterien zur Klassifikation von Objekten zu einem gemeinsamen Objekttyp sind gemeinsame Beziehungen zu anderen Objekten oder ihre Verwendung zur Erreichung eines gemeinsamen Ziels. Besonders das zweite Kriterium wird oft in der Literatur vernachlässigt, obwohl es von entscheidender Bedeutung ist. Es kann durchaus sinnvoll sein, dass individuelle Objekte vom Typ „Software“, „Gebäude“ und „Maschinen“, die auf den ersten Blick nur wenig oder gar keine Gemeinsamkeiten aufweisen, in einem Objekttyp enthalten sind, wenn z. B. die Aufgabe besteht, Vermögensgegenstände eines Unternehmens in die Modellbildung mit einzubeziehen. Über den Begriff Objektklasse existieren in der Literatur unterschiedliche Ansichten. Die wohl häufigste Interpretation verwendet die Begriffe Objekttyp und Objektklasse synonym. Eine vorteilhaftere Sichtweise sieht den Objekttyp als Spezifikation von Objekten mit gleicher Struktur und gleichem Verhalten, während die Objektklassse eine Menge von Objekten beschreibt, die gleiche Struktur und gleiches Verhalten aufweisen. 3.3.1.2
Objekte
Bei einem Objekt handelt es sich um eine strukturierte Informationseinheit, die ein bestimmtes Verhalten aufweist und verschiedene Zustände annehmen kann. Jedes Objekt ist eindeutig durch den Objektidentifikator identifizierbar, der während der gesamten Lebenszeit des Objektes nicht geändert wird. Ein Zustand eines Objektes wird durch die Attributwerte und die strukturellen Beziehungen des Objektes zu anderen Objekten definiert. Das dynamische Verhalten eines Objektes ist durch den Wechsel seiner Zustände gegeben, die durch Ereignisse initiiert und durch Operationen ausgeführt werden. 3.3.1.3
Attribute
Die Struktur eines Objektes wird durch die Attribute des entsprechenden Objekttyps bestimmt, seine Attributwerte gemeinsam mit den aktuellen Beziehungen des Objektes definieren seinen Zustand. Die Namen der Attribute sowie ihre Wertebereiche sind für alle Objekte eines Objekttyps identisch. Der Wertebereich eines Attributes kann entweder ein elementarer Datentyp oder selbst wieder ein komplex strukturierter Objekttyp sein. In einem solchen Fall stehen entsprechende Objekte durch einen Assoziationstyp in Verbindung. 3.3.1.4
Operationen und Methoden
Eine Operation ist die einzige Möglichkeit, die Attributwerte von Objekten zu beeinflussen. Das Konzept der Operationen ist ähnlich der Funktionen in prozeduralen Programmiersprachen. Operationen können jedoch nur auf dem dazugehörigen Objekt ausgeführt werden. Operationen sind Objekttypen zugeordnet und alle Objekte eines Typs nutzen dieselben Operationen. Jedes Objekt kennt seinen Objekttyp, wodurch auch Operationen mit gleichem Namen für unterschiedliche Objekttypen existieren können (siehe Polymorphismus). Die Operation erhält das Objekt, auf das diese angewendet wird, als implizites Argument und kann weitere explizite Argumente erhalten, die die Methode parametrisieren. Der Name der Operation ein-
100
3 Konzeptueller Datenbankentwurf
schließlich der Argumente und evtl. einem Rückgabewert bilden zusammen die Signatur der Operation. Operationen können wie folgt klassifiziert werden: • Konstruktoren (erzeugen ein Objekt) • Destruktoren (löschen ein Objekt) • Selektoren (lesen die Informationen eines Objektes) • Modifikatoren (ändern von Werten eines Objektes) • Iteratoren (eine Operation wird auf mehrere Objekte angewendet) Für Operationen und Methoden gilt dasselbe wie für Objekttypen und Objektklassen. Auch hier sind die Begriffsdefinitionen in der Literatur nicht eindeutig. Meist werden die Begriffe Operation und Methode synonym benutzt. Bei einigen Autoren ist die Methode die Implementierung der Operation (z. B. für eine Operation Drucken können verschiedene Methoden existieren, z. B. Rechnung drucken oder Lieferschein drucken). 3.3.1.5
Nachrichten
Objekte kommunizieren ausschließlich über das Senden von Nachrichten miteinander. Mit anderen Worten, die Operation eines Objektes (Sender) ruft die Operation eines anderen Objektes (Empfänger) auf. Die Nachricht ist dabei aus einem Selektor (der Name der Operation) und einer optionalen Liste mit Argumenten zusammengesetzt. Der Name des Empfängerobjektes ist implizit gegeben, da die Operation nur mit diesem zusammen aufgerufen werden kann. Durch den Erhalt einer Nachricht wird also eine Operation beim Empfängerobjekt ausgeführt. Der Empfänger könnte nun seinerseits anderen Objekten Nachrichten schicken, dem Sender seine Zustandsinformationen melden oder seinen Zustand durch Änderung der Attributwerte verändern. Dieser Umstand ist auch die Ursache dafür, dass Objekte miteinander in Kollaboration stehen, d. h. sie benutzen Dienste anderer Objekte, um ihre Aufgaben zu erfüllen. 3.3.1.6
Vererbung
Das Konzept der Vererbung ist ähnlich den IS-A-Beziehungen aus den semantischen Datenmodellen, wo es in Form von Generalisierung bzw. Spezialisierung Verwendung findet. Für die Objektorientierung ist es von wesentlicher Bedeutung, da es die Erzeugung von Varianten eines Objekttyps ermöglicht, ohne die Struktur des bereits bestehenden Objekttyps zu modifizieren oder redundante Kopien zu erzeugen. Dadurch wird nicht nur der Wartungsaufwand des Systems verringert, sondern auch die Übersichtlichkeit und Verständlichkeit erheblich erhöht. Unter Vererbung versteht man, dass Merkmale (Attribute und Operationen) eines Objekttyps von der Basisklasse (Oberklasse, Superklasse, generische Klasse) an die abgeleitete Klasse (Unterklasse, Subklasse, Spezialisierung) vererbt werden. Sollte es notwendig sein, das Verhalten der Exemplare des abgeleiteten Objekttyps zu verändern, können neue Operationen implementiert oder bestehende abgeändert werden (siehe Polymorphismus). Eine Besonderheit bildet das Konzept der abstrakten Basisklassen, da sie nur der Vererbung und nicht der Objekterzeugung dienen. Ein Beispiel hierfür wäre der Artikelbestand eines Computerherstellers. Von einer abstrakten Basisklasse Artikel würden die Klassen Monitor, Tastatur, Gehäuse
3.3 Objektorientierte Modellbildung
101
usw. abgeleitet, wobei diese die Attribute (z. B. Preis) und Operationen (z. B. Preisänderung) der Basisklasse erben. Erfolgt die Vererbung wie in diesem Beispiel in mehrere Subklassen, so wird ein Diskriminator verwendet, dessen Wert die Zuordnung von Objekten in die Subklassen bestimmt. In manchen Systemen können Subklassen auch mehrere Oberklassen haben. In diesem Fall spricht man von Mehrfachvererbung und besonderes Augenmerk ist auf die Konflikterkennung und -vermeidung bei Vererbung gleichlautender Merkmale aus unterschiedlichen Oberklassen zu legen. 3.3.1.7
Polymorphismus
Auch wenn es vielen vielleicht nicht bewusst ist, so sind die meisten Leser mit großer Wahrscheinlichkeit schon mit Polymorphismus in Berührung gekommen. Polymorphie (griechisch: „Auftreten in mehreren Modifikationen“) bedeutet, dass ein Konzept mit unterschiedlicher Implementierung existieren kann, dabei aber immer dieselbe Semantik besitzt. Ein Beispiel ist das Zeichen "+", das wohl immer zur Addition benutzt wird, jedoch in unterschiedlichen Implementierungen vorkommen kann (z. B. für Operanden vom Typ integer, real, oder auch Zeichenketten). Polymorphismus kommt in der Objektorientierung besondere Bedeutung zu, da es durch das Vererbungsprinzip möglich ist, Operationen einer Basisklasse über mehrere Ebenen hinweg beizubehalten und erst sehr tief in der Vererbungshierarchie die Implementierung einer Operation zu modifizieren. 3.3.1.8
Objektorientierte Assoziation
Eine Assoziation entspricht einem Beziehungstypen in einem ERM und beschreibt eine Relation zwischen Objekttypen. Da in einem objektorientierten Modell Attribute von komplexen Objekttypen selbst wieder Objekttypen sein können, wird die Assoziation in einem Objektmodell nicht immer explizit dargestellt. Aus Gründen der besseren Aussagekraft und der Flexibilität des Modells ist es jedoch wünschenswert, dass Assoziationen auch als solche modelliert werden. Dies hat den zusätzlichen Vorteil, dass Assoziationen aus beliebiger Richtung betrachtet werden und eigene Attribute haben können.
3.3.2
Unified Modeling Language (UML)
Im Oktober 1994 begannen die Methodenautoren Grady Booch und Jim Rumbaugh von der Rational Software Corporation ihre bis dahin sehr verbreiteten Methoden zur objektorientierten Modellbildung zusammenzuführen und um bewährte Ansätze aus unterschiedlichsten Bereichen zu erweitern. Durch die Vereinigung von OOD (Object Oriented Design, Booch) und OMT (Object Modeling Technique, Rumbaugh) entstand im Oktober 1995 die erste Version von UML. Zu dieser Zeit wurde das Entwicklerteam um Ivar Jacobson, dem Entwickler von OOSE (Object-Oriented Software Engineering) erweitert. Das Ergebnis der ersten Zusammenarbeit war die Entwicklung der Version UML 0.9 und kurz darauf UML 0.91, in der nun use cases (begründet durch Jacobson) enthalten waren. Die Entwicklung der UML ist noch nicht abgeschlossen. Die zum Zeitpunkt der Erstellung dieses Buches aktuelle Version ist UML 2.4.1 (veröffentlicht im August 2011). Die historische Entwicklungsgeschichte der Unified Modeling Language UML ist in Abbildung 3.14 zusammengefasst. Im Zuge der Entwicklung von UML wurden unnötige Unterschiede in der Notation und Terminologie der Methoden der beteiligten Autoren beseitigt und Elemente, die sich in der Praxis
102
3 Konzeptueller Datenbankentwurf
Oktober 1994
Grady Booch OOD
Oktober 1995
Jim Rumbaugh OMT
Unified Method 0.8
Juni/Oktober 1996
Andere Methoden
Ivar Jacobson OOSE
UML Partners Expertise
UML 0.90/0.91
Januar 1997
UML 1.0
September 1997
UML 1.1
Abb. 3.14: Entwicklungsgeschichte der Unified Modeling Language UML
nicht bewährt haben, aus den Methoden entfernt. Im Gegenzug wurden Konzepte aus anderen Methoden, die besser geeignet schienen Sachverhalte der Realwelt zu modellieren, in UML integriert. Es versteht sich von selbst, dass UML nicht sämtliche Konzepte aus Methoden, die im Laufe der Jahre entwickelt wurden, berücksichtigen kann. Aber insbesondere die Abwesenheit von Datenflussdiagrammen wird dem Leser auffallen. Diese Tatsache wird kontrovers diskutiert und von den Entwicklern damit erklärt, dass es nicht möglich ist, Konzepte der funktionsorientierten Modellbildung einwandfrei in ein konsistentes objektorientiertes Paradigma zu integrieren. In diesem Buch kann nur ein grober Überblick von UML gegeben werden. Obwohl eine der Zielsetzungen von UML das Auskommen mit nur wenigen grafischen Konstrukten war, besitzen diese eine so umfangreiche Gestaltungsvielfalt, dass ein ganzes Buch notwendig wäre, um sie vollständig zu beschreiben. UML verwendet eine Vielfalt an Modellen, um alle Aspekte eines Systems auf dem gewünschten Abstraktionsniveau zu beschreiben. Dadurch soll erreicht werden, dass das System aus unterschiedlichen Blickwinkeln betrachtet werden kann, um zu einem umfassenden Verständnis des geplanten Systems zu gelangen. Jedes der unterschiedlichen Modelle wird durch ein Diagramm repräsentiert, das, ohne auf andere Informationsquellen zurückgreifen zu müssen, selbstständig einen bestimmten Sachverhalt des geplanten Systems beschreibt. Zwischen den einzelnen Modellen bestehen bestimmte Schnittstellen, die zur Konsistenzprüfung genutzt werden. Beispielsweise stellen Operationen im Klassendiagramm Ereignisse des dynamischen
3.3 Objektorientierte Modellbildung
103
Modells dar, für ein Sequenzdiagramm muss auch ein entsprechender Anwendungsfall vorhanden sein und zu einem Zustandsdiagramm gehört auch eine Klasse des Klassendiagramms. Die folgenden Diagramme sind in UML enthalten: • Klassendiagramm (Objektmodell) • Anwendungsfalldiagramm • Verhaltensdiagramme (Dynamisches Modell) – Zustandsdiagramm – Aktivitätsdiagramm – Sequenzdiagramm – Kollaborationsdiagramm • Implementationsdiagramm – Komponentendiagramm – Entwicklungsdiagramm In den meisten Diagrammen können zu den unterschiedlichen Konzepten Einschränkungen (constraints) formuliert werden, die in geschweiften Klammern dargestellt werden und entweder in einer Kontrollsprache (OCL, object control language) oder in natürlicher Sprache
Klassendarstellung
Klasse
Angestellter
Attribut:Typ = Init {Einschränkung}
name:String strasse:String
Operation(Parameter):Rückgabewert {Einschränkung}
gehaltserhoehung(summe) {summe>0}
Objektdarstellung
objekt:Klasse
Attribut:Typ = Init {Einschränkung}
Operation(Parameter):Rückgabewert {Einschränkung}
Abb. 3.15: Klassen und Objekte in UML
o1:Angestellter name = Müller strasse = Musterstr. 1
104
3 Konzeptueller Datenbankentwurf
formuliert werden. In Abbildung 3.15 ist die Einschränkung {summe > 0} einer Operation zugewiesen worden und bedeutet in diesem Kontext, dass der Parameter der Operation einen Wert größer als 0 haben muss. Bei der Beschreibung der unterschiedlichen Modelle werden wir auf die Formulierung von Einschränkungen zurückkommen, um zu verdeutlichen, welch hohen semantischen Informationsgehalt dieses Konstrukt bereitstellt. 3.3.2.1
Klassendiagramm
Im Klassendiagramm (Objektmodell) werden alle Objekte erfasst, die in dem System, das es zu modellieren gilt, von Bedeutung sind. Außer der Darstellung der eigentlichen Objekte wird auch deren Struktur abgebildet, d. h. ihre Attribute und Operationen sowie die Beziehungen zu anderen Objekten. Klassen und Objekte werden in UML als Rechtecke dargestellt, die in drei Abschnitte eingeteilt werden können (vgl. Abbildung 3.15). Der erste Abschnitt beschreibt den Namen der Klasse bzw. des Objektes und zusätzliche Informationen, auf die wir in diesem Buch aber nicht weiter eingehen wollen. Der zweite Abschnitt enthält die Attribute der Klasse, die mit einem Typ, einem Initialisierungswert und einer Einschränkung versehen werden können. Der dritte Abschnitt ist für die Operationen vorgesehen, die Parameter übergeben bekommen, einen Rückgabewert besitzen können und ebenfalls mit Einschränkungen versehen werden können. Die Sichtbarkeit von Attributen und Operationen erfolgt in Anlehnung an die Programmiersprache C++ und kann als public, protected und private dargestellt werden. Eine Assoziation stellt, wie schon im Abschnitt Konzepte beschrieben, Beziehungen zwischen Objekttypen dar. Binäre Assoziationen werden als direkte Verbindung zwischen den Klassen dargestellt. Assoziationen sind mit einer Richtung versehen, wobei die Richtung durch ein kleines Dreieck angezeigt wird. Assoziationen können analog zu Klassen Attribute und Operationen besitzen, die in einem Klassensymbol (Assoziationsklasse) durch eine gestrichelte Linie mit der Assoziationslinie verbunden sind. Dreistellige Assoziationen und solche mit höherer Ordnung werden in UML nicht durch direkte Verbindungen der beteiligten Klassen, sondern durch eine Raute dargestellt. In diesem Fall gibt es keine Unterschiede zu der in diesem Buch für die Darstellung in Entity-Relationship-Diagrammen gewählten Notation. Die Multiplizität (Kardinalität) einer Assoziation legt fest, wie viele Exemplare einer Klasse mit einem Exemplar der in Beziehung stehenden Klasse verknüpft sein dürfen. Die Festlegung einer zu geringen Multiplizität würde die Flexibilität einschränken, eine Überschätzung der Multiplizität würde jedoch den Aufwand für Programmierung und Verwaltung in der Implementierung erhöhen. Die Multiplizität wird in einzelnen Werten oder als Intervall angegeben und kann mehrere durch Kommata getrennte Bereiche umfassen. Ein * steht dabei für 0 oder mehrere. Objekte können an Assoziationen unter Ausübung unterschiedlicher Rollen beteiligt sein. Dies wird durch Aufnahme eines Rollennamens an die die Assoziation darstellende Kante im Diagramm gekennzeichnet. Durch die Angabe einer Qualifikation innerhalb einer Assoziation wird ein Attribut ausgezeichnet, das in 1:M- oder N:M-Assoziationen eine besondere Bedeutung einnimmt. Eine qualifizierte Assoziation ist ähnlich einer mehrstelligen Assoziation und primär dazu gedacht, die semantische Aussagekraft des Modells zu verbessern ohne einen zusätzlichen Objekttyp in die Darstellung aufnehmen zu müssen. Eine Qualifikationsangabe wird als kleines Rechteck neben der Klasse, die sie qualifiziert, dargestellt.
3.3 Objektorientierte Modellbildung
105
UML kennt die Aggregation als einen Spezialfall der Assoziation. Eine Aggregation repräsentiert die Zusammensetzung eines Objektes aus Einzelteilen. Sie sollte immer dann der „normalen“ Assoziation vorgezogen werden, wenn eine enge Verbindung (oder auch eine Existenzabhängigkeit) zwischen beteiligten Objekttypen besteht. Grafisch wird die Aggregation durch eine Raute dargestellt. Die Raute ist ausgefüllt, wenn es sich um eine Wertaggregation handelt. Bei Referenzaggregationen wird die Raute hingegen nicht ausgefüllt. Einschränkungen haben auch im Kontext der Assoziation eine große Bedeutung. Einschränkungen können verwendet werden, um eine Assoziation mit Bedingungen oder Eigenschaften zu versehen. In UML existieren aber auch eine Reihe vordefinierter Einschränkungen für Assoziationen. Eine davon ist die Einschränkung {ordered}, die explizite Reihenfolge der Exemplare einer Assoziation hervorhebt und daher nur bei einer Multiplizität größer als 1 auftreten kann. Im folgenden Beispiel wollen wir die unterschiedlichen Ausprägungsformen der Assoziation in UML darstellen. Beispiel 3.9: Formen der Assoziationen in UML Wir beginnen mit dem einfachsten Fall einer binären Assoziation. In Abbildung 3.16(a) zeigen wir die binäre Assoziation „beschäftigt“, der die Attribute „Gehalt“ und „Einstellungsdatum“ zugewiesen sind. Des Weiteren ist die Semantik dargestellt, dass eine Abteilung mehrere Mitarbeiter beschäftigen kann, aber für jede Abteilung zumindest ein Mitarbeiter vorhanden sein muss. Ein Mitarbeiter darf ausschließlich in einer Abteilung beschäftigt sein. Eine Einschränkung vom Typ {or} ist in Abbildung 3.16(b) dargestellt. Sie legt fest, dass ein Exemplar der Klasse „Artikel“ zu einem Zeitpunkt nur mit einer der beiden Klassen „Abteilung“ oder „Lieferant“ verbunden sein kann. Dieses Beispiel repräsentiert die Semantik, dass es sich bei einem Artikel entweder um eine Eigenfertigung oder um einen Fremdbezug handelt. Eine qualifizierte Assoziation ist in Abbildung 3.16(c) dargestellt. Durch die Qualifikation „Lieferant“ kann im Zusammenhang mit einem bestimmten Produkt das Teil eines bestimmten Lieferanten identifiziert werden. Diese Assoziation stellt in etwa den gleichen Informationsgehalt dar, wie durch eine dreistellige Beziehung zwischen Objekttypen „Produkt“, „Lieferant“ und „Teil“ ausgedrückt werden könnte. Allerdings handelt es sich bei dem Lieferanten in Abbildung 3.16(c) nicht um einen Objekttyp, sondern lediglich um ein Attribut. Eine rekursive Assoziation wird in Abbildung 3.16(d) gezeigt. Objekte vom Typ „Mitarbeiter“ werden durch die Rollen „Vorgesetzter“ und „Angestellter“ unterschieden. In Abbildung 3.16(e) sind zwei Aggregationen dargestellt, die bedeuten, dass ein Unternehmen aus Abteilungen zusammengesetzt ist, die wiederum aus zugeordneten Mitarbeitern bestehen. Das Beispiel zeigt auch die unterschiedliche Darstellung von Wertaggregation (ausgefüllte Raute) und Referenzaggregation (Raute ist nicht ausgefüllt). Eine Vererbungshierarchie wird in UML durch einen Pfeil von der Unterklasse zur Oberklasse dargestellt. Dabei erbt die Unterklasse alle Eigenschaften der Oberklasse. Zwei unterschied-
106
3 Konzeptueller Datenbankentwurf
a)
b) Abteilung
1
beschäftigt
1..*
Mitarbeiter
Abteilung
1 fertigt 0..*
{or} Lieferant
liefert
1..*
Artikel
1
Beschäftigt Gehalt Einstelldatum
d)
c)
Angestellter 1 Produkt
*
Lieferant
Mitarbeiter
Teil
Vorgesetzter
e) 1
hat
1..*
Unternehmen
1
beschäftigt
1..*
Abteilung
Mitarbeiter
Abb. 3.16: Assoziation in UML
liche Notationen sind zulässig (siehe Abbildung 3.17). Hinsichtlich der Spezialisierungen können folgende vordefinierte Einschränkungen formuliert werden: • overlapping (Exemplare können in mehreren Unterklassen sein) • disjoint (ein Exemplar kann zur selben Zeit nur in einer Unterklasse sein) • complete (es bestehen keine weiteren Unterklassen) • incomplete (es sind noch weitere Unterklassen vorhanden) Die unterschiedliche Darstellung der Generalisierung und die Verwendung von Einschränkungen wird im nachfolgenden Beispiel erläutert. Beispiel 3.10: Generalisierung in UML In Abbildung 3.17 zeigen wir die unterschiedlichen Darstellungsformen für Generalisierungen. Von der Klasse „Person“ werden die Klassen „Kunde“, „Lieferant“ und „Angestellter“ abgeleitet. In Abbildung 3.17(b) sind die Einschränkungen {overlapping, incomplete} dargestellt. Durch {overlapping} wird ausgedrückt, dass ein Exemplar der Klasse „Person“ durchaus auch gleichzeitig in der Unterklasse „Angestellter“ und „Kunde“ sein kann. Die Einschränkung {incomplete} stellt klar, dass es auch Exemplare der Klasse „Person“ geben kann, die in keiner der drei Spezialisierungen enthalten sind.
3.3 Objektorientierte Modellbildung
107
a)
b) Person
Person
{overlapping, incomplete}
Kunde
Lieferant
Angestellter
Kunde
Lieferant
Angestellter
Abb. 3.17: Generalisierung in UML
3.3.2.2
Anwendungsfalldiagramm
Ein Anwendungsfalldiagramm (use case diagram) bildet die Beziehungen der Akteure außerhalb des Systems zu den verschiedenen Anwendungsfällen (use cases) innerhalb der Systemgrenzen ab. Welche Anwendungsfälle modelliert werden, hängt davon ab, auf welche Vorgänge das System reagieren soll. Alle Anwendungsfälle gemeinsam beschreiben das Verhalten des Gesamtsystems. Das Anwendungsfalldiagramm repräsentiert somit die externe Funktionalität eines Systems oder einer Klasse, wie sie sich dem Akteur darstellt und ist als geschlossene Transaktion von Nachrichten zwischen Akteuren und Anwendungsfällen definiert. Ein physisches Objekt der Realität kann dabei mehrere Rollen übernehmen und deshalb auch als verschiedene Akteure modelliert werden. Grafisch werden Anwendungsfalldiagramme wie folgt dagestellt: „Strichmännchen“ symbolisieren externe Akteure, die Systemgrenzen werden durch abgerundete Rechtecke und die Anwendungsfälle durch Ellipsen dargestellt. Die Verbindungen zwischen den Akteuren und den Anwendungsfällen beschreiben die Kommunikation des Anwendungssystems mit seiner Umwelt. Akteure können zu Anwendungsfällen und zu anderen Akteuren eine Beziehung aufweisen. Die Assoziation zwischen einem Anwendungsfall und einem Akteur kann ebenfalls eine Multiplizitätsangabe aufweisen. Assoziationen zwischen Akteuren (bspw. eine Generalisierung) befinden sich zwar außerhalb des System, können jedoch das Verständnis des Modells erheblich erhöhen. Für die Anwendungsfälle untereinander werden drei Beziehungstypen unterschieden, nämlich include für die Darstellung hierarchischer Verknüpfungen zwischen Anwendungsfällen und extends für eine Erweiterungsbeziehung zwischen Anwendungsfällen. Eine Erweiterungsbeziehung kann auch als eine optionale include-Beziehung betrachtet werden. Des Weiteren besteht die Möglichkeit einer Generalisierung zwischen Anwendungsfällen. Anwendungsfalldiagramme können bis zum gewünschten Detaillierungsgrad hierarchisch verschachtelt und dann durch Interaktionsdiagramme beschrieben werden. Zudem kann jeder Anwendungsfall durch ein Szenario oder mehrere Szenarios genauer dargestellt werden. Diese Szenarios bilden dann später die Grundlage für Sequenzdiagramme.
108
3 Konzeptueller Datenbankentwurf Einkauf Warenlieferung
Lieferant
Warenannahme Qualitätskontrolle
Bestellung Beschaffung
Bestellung
Lieferantenauswahl «extends»
«uses» «uses»
Lagerabgleich
Produkte bestellen
Abb. 3.18: Anwendungsfalldiagramm in UML
Beispiel 3.11: Anwendungsfalldiagramm in UML In Abbildung 3.18 ist ein Wareneinkauf als Anwendungsfalldiagramm modelliert. Am Wareneinkauf sind die externen Akteure „Beschaffung“, die „Warenannahme“ und ein „Lieferant“ beteiligt. Des Weiteren sind die Anwendungsfälle „Warenlieferung“, „Qualitätskontrolle“ und „Bestellung“ dargestellt. Die Assoziation des Lieferanten zeigt an, dass ein Lieferant an mehreren Warenlieferungen beteiligt sein kann. Der Anwendungsfall „Bestellung“ ist weiter in seine Bestandteile strukturiert und nutzt über eine includeBeziehung die Anwendungsfälle „Lagerabgleich“ und „Produkte bestellen“, d. h. diese beiden Anwendungsfälle werden ebenfalls ausgelöst, sobald ein Anwendungsfall „Bestellung“ eintritt. Der Anwendungsfall „Lieferantenauswahl“ ist als eine Erweiterung des Anwendungsfalles „Bestellung“ dargestellt. Dies bedeutet, dass für Produkte, die bisher noch von keinem Lieferanten bezogen wurden, der Anwendungsfall „Lieferantenauswahl“ erfolgen muss. Das statische Modell bildet die Struktur des Systems ab. Die Veränderungen, die das System und dessen Objekte mit der Zeit erfahren, werden durch das dynamische Modell erfasst. Ein
3.3 Objektorientierte Modellbildung
109
Objekt kann im Laufe seiner Existenz in der DB eine ganze Reihe unterschiedlicher Zustände „erleben“, die jeweils durch seine Attributwerte und den zu einem bestimmten Zeitpunkt existenten Beziehungen des Objektes zu anderen Objekten charakterisiert sind. Es ist jedoch eine sehr schwierige Aufgabe, diese zeitlichen Aspekte des Systems zu analysieren. Durch ein statisches Modell wird eine zeitpunktbezogene Momentaufnahme ausgeführt und dabei werden Objekttypen, die zu dem Zeitpunkt Relevanz besitzen, analysiert. Im dynamischen Modell wird untersucht, ob der Objekttyp einen wesentlichen dynamischen Aspekt für das Gesamtsystem aufweist, und welche Zustände er mit der Zeit durchläuft. Zunächst wollen wir die wichtigsten Begriffe der dynamische Modellbildung definieren, um zu einem einheitlichen Verständnis zu gelangen und dann später auf die unterschiedlichen Diagrammtypen eingehen zu können. Ein Ereignis ist ein zeitpunktbezogener Vorfall, der die Attribute und somit den Zustand eines Objektes verändern kann. Ereignisse können zeitgleich auftreten. Ereignisse, die in einem Kausalzusammenhang stehen, müssen jedoch eine logische Reihenfolge besitzen. Ein Kausalzusammenhang existiert immer dann, wenn sich Ereignisse aufeinander auswirken. Ein Beispiel dafür ist eine Bestellung durch einen Kunden: Sie könnte nicht bearbeitet werden, bevor der Kunde die Bestellung aufgegeben hat. Ereignisse ohne Kausalzusammenhang bezeichnet man als parallele Ereignisse. Der Zustand eines Objektes wird durch seine Attributwerte und seine Beziehungen zu anderen Objekten zu einem bestimmten Zeitpunkt definiert. Nicht jede Änderung eines Wertes führt auch zu einer Änderung eines Zustandes. Es können auch Wertemengen zusammengefasst und einem Zustand zugeordnet werden. Ein Zustand besitzt im Gegensatz zum Ereignis eine Zeitspanne, in der er besteht. Die Menge der möglichen Zustände eines Objektes beschreibt sein Verhalten. Ein Szenario stellt eine Aneinanderreihung von Ereignissen dar, die für eine bestimmte Operation eines Systems benötigt werden. Bei der Erzeugung von Szenarios wird im Allgemeinen der Ablauf einer Operation eines existierenden Systems beobachtet oder die Ausführung für ein geplantes System simuliert. Ereignisse und Zustände werden in den meisten Fällen mit Hilfe von Zustandsdiagrammen zueinander in Relation gebracht. D. h. zu jedem Objekttyp, der ein für das System wichtiges Verhalten aufweist, wird im Zuge einer objektorientierten Modellbildung ein Zustandsdiagramm erzeugt. Auf diese Weise wird sichtbar, auf welche Ereignisse Objekte dieses Typs reagieren müssen, und welche Zustände sie annehmen können. In UML ist das dynamische Modell aber nicht auf die Anwendung von Zustandsdiagrammen beschränkt. Es existieren noch weitere Diagramme, die dynamische Zusammenhänge des Systems abbilden. Insbesondere das Sequenz- und das Kollaborationsdiagramm weisen überwiegend dynamische Aspekte auf. Sequenz- und Kollaborationsdiagramm bilden jeweils ähnliche Sachverhalte ab, setzen dabei jedoch unterschiedliche Schwerpunkte. Während ein Sequenzdiagramm den zeitlichen Verlauf des Nachrichtenaustauschs zwischen den Objekten in den Vordergrund stellt, bildet ein Kollaborationsdiagramm die Beziehung zwischen den Objekttypen ab. Nachfolgend soll auf beide Diagrammarten näher eingegangen werden.
110
3 Konzeptueller Datenbankentwurf
3.3.2.3
Sequenzdiagramm
Das Sequenzdiagramm (sequence diagram) leitet sich von Szenarios ab und stellt eine Weiterentwicklung so genannter Ereignispfaddiagramme dar, die in OMT3 Verwendung fanden. Die Ereignisfolge, die für eine bestimmte Operation des Systems durchlaufen wird, kann mit Hilfe von Sequenzdiagrammen sehr detailliert wiedergegeben werden. Grafisch werden die Objekttypen, die von einer Operation des Systems betroffen sind, als senkrechte Linien, und die Nachrichten, die zwischen den Objekten ausgetauscht werden, als Pfeile zwischen diesen dargestellt. Der zeitliche Verlauf nimmt im Diagramm nach unten zu. Zusätzlich kann auch eine metrische Zeitachse angegeben werden, falls diese z. B. für Angabe von Realzeiten nötig sein sollte. Die Achsen des Sequenzdiagramms sind austauschbar, d. h. die zeitliche Komponente kann auch horizontal von links nach rechts aufgetragen und die Objekte können vertikal angeordnet werden. Labels, wie Zeitmarken oder Beschreibungen, können an der Seite des Sequenzdiagramms oder in der Nähe der Übergänge angegeben werden. Beispiel 3.12: Sequenzdiagramm in UML In Abbildung 3.19 ist ein Szenario eines Ausschnittes aus einem typischen Bestellvorgang dargestellt. Folgende Semantik wird repräsentiert: Zuerst werden für die einzelnen Bestellpositionen die Artikel und deren Anzahl ermittelt. Danach wird geprüft, ob der gewünschte Artikel in der entsprechenden Anzahl im Lager verfügbar ist. Ist dies der Fall, können die Artikel kommissioniert werden. Ansonsten müssen diese bei einem Lieferanten bestellt werden.
:Lagerabgleich
:Bestellung
:BestellPos
:Lager
:Lieferant
:Kommissionierung
getPos Position getArticle(Position) article getItems(Position) count available(article, count) av [av == -1] order(article, count) [av == 1] reserve(article, count)
Abb. 3.19: Sequenzdiagramm in UML
3 OMT ist eine Vorgängermethode von UML, deren wesentlichen Komponenten in UML eingeflossen sind. Siehe dazu auch Abbildung 3.14.
3.3 Objektorientierte Modellbildung 3.3.2.4
111
Kollaborationsdiagramm
Bei einem Kollaborationsdiagramm (collaboration diagram) werden in erster Linie die Beziehungen der einzelnen Objekte betrachtet, auf eine separate Dimension für die Zeit wird verzichtet. Ein Kollaborationsdiagramm enthält folgende zwei Aspekte: • strukturelle Beschreibung (die Objekte und deren Beziehungen zueinander) und • dynamische Beschreibung (der notwendige Nachrichtenaustausch, um eine Operation auszuführen). Die Objekte und ihre Beziehungen zueinander werden als Kollaboration bezeichnet und der mit ihr in Verbindung stehende Nachrichtenaustausch als Interaktion. Um verschiedene Interaktionen zu modellieren, müssen alle Nachrichten einer Kollaboration analysiert werden. Kollaborationsdiagrmme haben den großen Vorteil, dass mit ihrer Hilfe die Implementierung einer Operation veranschaulicht werden kann. Die Namen der Objekte repräsentieren ihre Rollen innerhalb der Kollaboration und zu jeder dieser Rollen muss ein Objekt existieren, das die Operation unterstützt. Die Verbindungen der Objekte können verschiedene Ursachen haben. Im klassischen Fall existiert eine Assoziation oder Aggregation im statischen Modell. Alle Objekte, die direkt oder indirekt an der Ausführung der Operation beteiligt sind, werden im Kollaborationsdiagramm dargestellt und können unter anderem mit folgenden „Marken“ versehen werden: • {new} (Objekt wird durch die Operation erzeugt) • {destroyed} (Objekt wird durch die Operation zerstört) • {transient} (Objekt existiert nur während dieser Operation) Werden alle Kollaborationen einer Klasse zusammengefasst, so erhält man den Bezugsrahmen zur Implementierung der Klasse. Interaktionen können auch durch die zuvor beschriebenen Sequenzdiagramme dargestellt werden. Kollaborationsdiagramme stellen jedoch ein mächtigeres Konzept dar, da sie neben dem involvierten Nachrichtenaustausch auch die Beziehungen zwischen den Objekttypen explizit beinhalten. Die Nachrichten in Kollaborationsdiagrammen können unterschiedlich dargestellt werden. Ein kleiner Pfeil zeigt dabei die Richtung der Nachricht an. Die Verarbeitungsart der Nachricht wird durch die verschiedenen Pfeilspitzen (wie in Abbildung 3.20 dargestellt) wiedergegeben. Der Aufbau der Nachricht setzt sich folgendermaßen zusammen: Vorgänger Bedingung Sequenzausdruck Rückgabe := Nachricht (Argumente) Vorgänger, Bedingung und Sequenzausdruck legen gemeinsam fest, wann eine Nachricht gesendet wird. Bei Vorgänger handelt es sich um eine Liste von Sequenznummern, die vorgekommen sein müssen, bevor die Nachricht aktiviert werden kann. Bedingung stellt einen logischen Ausdruck dar, der erfüllt sein muss und Sequenzausdruck stellt die Reihenfolge der Nachrichten her. Beispielsweise erfolgt die Nachricht 1.5.6 im Anschluss an die Nachricht
112
3 Konzeptueller Datenbankentwurf
sequenziell (Nachricht wird vom Empfänger vollständig verarbeitet) synchron (Sender wartet auf den Empfänger) asynchron (Nachricht wird in die Warteschlange des Empfängers gestellt)
:Bestellung
1: check(order)
1.1*[i:=1..n]: p:=getPos(i)
1.1.1a: article:=getArticle(p) :BestellPos
1.1.1b: count:=getItems(p)
1.1.2: av:=available(article, count) :Lagerabgleich
:Lager
1.1.4[av == -1]: Deliverer:=find(article)
1.1.3[av == 1]: reserve(article, count)
1.1.5: order(article, count)
:Kommissionierung
:Lieferant
:Lieferant
Abb. 3.20: Kollaborationsdiagramm in UML
1.5.5 innerhalb von 1.5. Die Verwendung von Kollaborationsdiagrammen soll anhand eines Beispiels veranschaulicht werden. Beispiel 3.13: Kollaborationsdiagramm in UML Im Kollaborationsdiagramm in Abbildung 3.20 ist dargestellt, wie die Operation „Abgleichen des Lagers“ nach Aufnahme der Bestellung vollzogen wird. Zunächst wird aus der Bestellung jede einzelne Position extrahiert, um den bestellten Artikel und dessen Anzahl zu ermitteln. Dabei wird die Abarbeitungsreihenfolge der Nachrichten 1.1.1a+b nicht festgelegt, da es für die Operation ohne Belang ist, welche dieser Nachrichten zuerst gesendet wird. Anschließend wird geprüft, ob der Artikel in der gewünschten Anzahl im Lager verfügbar ist (Nachricht 1.1.2). Die Verfügbarkeit wird vom Lager mit der Zahl 1 beantwortet. Für den positiven Fall ist die Bedingung [av == 1] der Nachricht 1.1.3 erfüllt und die Artikel können reserviert bzw. kommissioniert werden. Im negativen Fall ist die Antwort des Lagers –1. Für diesen Fall wird aus der Menge der Lieferanten einer ausgewählt (Nachricht 1.1.4), der diesen Artikel in seinem Sortiment führt, und der Artikel wird bei dem gewählten Lieferanten bestellt (Nachricht 1.1.5).
3.3.2.5
Zustandsdiagramm
Wir haben bereits festgestellt, dass alle Objekte eines Objekttyps dasselbe Verhalten aufweisen. In UML wird das mögliche Verhalten von Objekten mit Zustandsdiagrammen (state chart diagrams) illustriert, die einzelnen Objekttypen zugeordnet sind. Es ist nicht notwendig, für alle Objekttypen des Systems ein Zustandsdiagramm zu entwickeln. Von Bedeutung sind
3.3 Objektorientierte Modellbildung
113
ausschließlich Typen, die ein wichtiges Verhalten in Bezug auf das System aufweisen. Bei einem Zustandsdiagramm handelt es sich um einen gerichteten Graphen, dessen Knoten die potenziellen Zustände eines Objektes während seiner Lebenszeit abbilden. Die Transitionen (Zustandsübergänge) werden durch Kanten dargestellt. Die Objekte bewegen sich nun unabhängig voneinander durch diesen Graphen, je nachdem welche Ereignisfolge eintritt. Folglich ist außer dem Ereignis und einer möglichen Bedingung auch der aktuelle Zustand eines Objektes maßgebend für den Folgezustand. Oft ist der Zustand eines Objektes mit ausführbaren Aktionen verbunden. Aktionen sind immer atomar und die ihnen vorausgehenden Ereignisse werden in einem separaten Abschnitt des Zustandes im Zustandsdiagramm dargestellt. Attribute für einen Zustand können ebenfalls in einem Abschnitt hinterlegt werden. Der Aufbau der Abschnitte ist analog zu dem von Klassen und Objekten. Die Angabe der einzelnen Abschnitte ist optional. Wird der Name eines Zustandes ausgelassen, so handelt es sich um einen anonymen Zustand. Zwei besondere Zustände in Zustandsdiagrammen sind der Start- und Endzustand. Der Startzustand wird als ausgefüllter Kreis dargestellt, dem kein Zustand vorausgehen kann. Der Endzustand erhält zusätzlich noch einen weiteren Kreis. Es können durchaus auch mehrere Endzustände in einem Zustandsdiagramm auftreten. Ereignisse und Aktionen werden wie folgt dargestellt: Ereignis (Argumente) [Bedingung] / Aktion Innerhalb eines Zustandes existieren drei vordefinierte Ereignisse, die mit Aktionen belegt werden können: • do / Aktion (wird wiederholt ausgeführt, solange der Zustand besteht) • entry / Aktion (wird ausgeführt, wenn das Objekt in diesen Zustand eintritt) • exit / Aktion (wird beim Verlassen des Zustandes ausgeführt) Die Verwendung von Zustandsdiagrammen soll nun auch an einem Beispiel veranschaulicht werden. Beispiel 3.14: Zustandsdiagramm in UML Im Zustandsdiagramm in Abbildung 3.21 sind die veschiedenen Zustände abgebildet, die eine Bestellung in einem bestimmten Problembereich durchlaufen kann. Folgende Semantik wird dargestellt: Nachdem der Artikelbestand geprüft wurde, werden die Artikel bestellt, deren Bestand nicht ausreicht, die Nachfrage zu decken. Sobald das Ereignis „Bestellung vollständig“ eintritt, befindet sich die Bestellung im Zustand „Terminüberwachung“. Werden die Artikel geliefert, überführt das die Bestellung in den Zustand „Qualitätsprüfung“. Wird der Termin jedoch nicht eingehalten oder weisen die gelieferten Artikel Qualitätsmängel auf, ändert sich der Zustand der Bestellung in „Reklamation“. Sollte eine Nachlieferung der Artikel möglich sein, so wird die Bestellung erneut in den Zustand „Terminüberwachung“ transformiert. Andernfalls terminiert das Objekt Bestellung (wird aus der DB gelöscht). Diese Situation tritt auch ein, wenn nach Zustand „Qualitätsprüfung“ eine zufrieden stellende Qualität festgestellt werden konnte.
114
3 Konzeptueller Datenbankentwurf
bestelle Artikel
Lagerabgleich Bestand zu gering
Artikel bestellen
do / Artikelbestand prüfen
Bestellung vollständig
Nachlieferung möglich
Terminüberwachung Termin nicht eingehalten Artikel geliefert
Reklamation
Lieferung nicht möglich
Qualitätsmängel / Nachlieferung fordern
Qualitätsprüfung
Qualität zufriedenstellend / Artikel einlagern
Abb. 3.21: Zustandsdiagramm in UML
Einige abschließende Aussagen über die objektorientierte Modellbildung sind noch angebracht. Objektorientierte Analyse und Entwurf sind „allgemeine“ Methoden der Systemplanung und -entwicklung und werden deshalb für viele unterschiedliche Fragestellungen beim Entwurf von Software eingesetzt. Steht die Entwicklung einer Datenbankanwendung im Vordergrund, so stellen die Informationsanforderungen aus dem Objektmodell die wichtigste Klasse an Informationen dar, die den systemunabhängigen Teil des Entwurfs einer DB beeinflussen. Ein Objektmodell kann jedoch nur konfliktfrei und vollständig sein, wenn die Designer eine Vorstellung von der zu entwickelnden Anwendung besitzen und neben den statischen Aspekten die beteiligten Akteure aus den Anwendungsfalldiagrammen, die Analyse der Ereignisse aus Sequenzdiagrammen, die Interaktionen zwischen Objekten aus den Kollaborationsdiagrammen und das Verhalten von Objekten aus den Zustandsdiagrammen in ihre Entwurfsentscheidungen einbeziehen. Anforderungen, die das zeitabhängige Verhalten der DB betreffen, besitzen beim Entwurf des statischen Datenbankschemas eine untergeordnete Bedeutung. Sie sind jedoch für die Erstellung von Programmen, die auf die DB zugreifen, von essenzieller Wichtigkeit, da sie die Reihenfolge von Interaktionen und damit den zeitlichen Ablauf von Operationen festlegen.
3.4
Weitere Formen der Modellbildung
Der Aufbau der vorherigen Abschnitte wurde nicht zufällig gewählt, sondern reflektiert die chronologische Reihenfolge, in der sich Wissenschaftler und Unternehmen gleichermaßen mit
3.4 Weitere Formen der Modellbildung
115
Methoden zur Analyse von betrieblichen Informationssystem beschäftigt haben. Im folgenden Unterkapitel wollen wir die Grundlagen und die wesentlichen Ideen der geschäftsprozessorientierten Modellbildung vorstellen. Das Unterkapitel wird mit einer kurzen Darstellung zweier konkreter Ansätze, die geschäftsprozessorientierte Modellbildung unterstützen, abgeschlossen. Ähnlich wie auch schon bei der objektorientierten Modellbildung ist die Zielrichtung der in diesem Unterkapitel dargestellten Methoden nicht mehr ausschließlich die Unterstützung des Datenbankentwurfsprozesses. Vielmehr sind die Methoden sehr allgemein gehalten, unterstützen unterschiedliche Sichtweisen auf Anwendungen und können für die Repräsentation und Analyse komplexer Systeme in unterschiedlichsten Bereichen zum Einsatz kommen.
3.4.1
Geschäftsprozessorientierte Modellbildung
Für die permanente Entwicklung neuer Methoden ist außer dem technischen Fortschritt auch der immer stärker werdende Wettbewerb, dem sich die Unternehmen ausgesetzt sehen, verantwortlich. Es ist offensichtlich, dass im Zuge der Globalisierung der Wirtschaft die Konkurrenz sehr groß geworden ist, so dass sich ein Unternehmen sehr schnell an die sich ändernden Märkte anpassen muss, um überlebensfähig zu bleiben. Aus diesem Umstand heraus haben sich in den letzten Jahren eine Vielzahl von Reorganisationsansätzen entwickelt, die unter dem Oberbegriff „Business Process Reengineering“ (BPR) subsumiert werden. BPR steht für eine Erneuerung der Unternehmensstruktur, mehr Flexibilität in den betrieblichen Abläufen und eine Fokussierung auf die wichtigsten Geschäftsprozesse, deren Optimierung und schnelle Adjustierung auf geänderte Rahmenbedingung notwendig geworden ist. Der Wunsch nach mehr Flexibilität erfordert eine kontinuierliche und umfassende Modellbildung, die nicht ein statisches System betrachtet, sondern von einem ganzheitlichen Unternehmensmodell mit sich ständig verändernden Prozessen ausgeht. Die geschäftsprozessorientierte Modellbildung verfolgt einen primär betriebswirtschaftlichen Ansatz, indem sie sich von vorwiegend informationstechnischen Elementen löst und die Aufgaben, Ereignisse und Organisationseinheiten des Unternehmens im Hinblick auf eine mögliche Neugestaltung der existierenden Geschäftsprozesse analysiert. Bereits die objektorientierte Modellbildung unterstützt einen ganzheitlichen Modellbegriff, indem sie zumindest Konzepte zur statischen, funktionalen und dynamischen Analyse beinhaltet. Ähnlich den davor diskutierten klassischen Ansätzen geht sie jedoch weiterhin von den zu modellierenden Funktionsbereichen im Unternehmen aus und versucht durch Analyse dieser drei Aspekte ein Realweltmodell zu entwickeln. Bei der geschäftsprozessorientierten Modellbildung ist dies nun anders. Feststellung 3.4: Geschäftsprozessorientierte Modellbildung Die geschäftsprozessorientierte Modellbildung geht von den existierenden Geschäftsprozessen aus und versucht quer durch alle betrieblichen Funktionsbereiche, alle relevanten Aspekte von aufeinander folgenden Aktivitäten (Geschäftsvorgängen) darzustellen. Des Weiteren berücksichtigt sie die Aufgabenträger, die in die Ausführung der Geschäftsprozesse involviert sind und setzt ihren Schwerpunkt auf die Erneuerung (Reorganisation) bestehender Prozesse.
116
3 Konzeptueller Datenbankentwurf
In seiner allgemeinsten Form besteht ein Geschäftsprozess aus einer Folge von aufeinander folgenden und logisch zusammengehörenden Aktivitäten, die innerhalb der Wertschöpfungskette eines Unternehmens verschiedene Aufgaben realisieren. Die Wertschöpfungskette eines Unternehmens bildet die direkt an der Wertschöpfung4 beteiligten Funktionen ab und könnte durchaus selbst als ein Geschäftsprozess auf der höchsten betrieblichen Ebene dargestellt werden. In der Literatur gibt es unterschiedliche Definitionen des Begriffs Geschäftsprozess. Als charakteristische Merkmale von Geschäftsprozessen werden dabei insbesondere genannt [FeSi98]: (a) Sammlung von Aktivitäten, die anhand gemeinsamer Merkmale abgrenzbar sind, (b) ereignisgesteuerter Ablauf von Aktivitäten, (c) Übernahme von Inputs und Erzeugung von Outputs als Beitrag zur Wertschöpfung, (d) Zuordnung und Nutzung von Ressourcen. Wichtig erscheint dabei noch die Motivation für eine geschäftsorientierte Modellbildung – nämlich die Analyse bestehender Strukturen hinsichtlich einer möglichen Reorganisation. Wie aus den bisherigen Ausführungen zu schließen ist, ist es nicht möglich, die Geschäftsprozesse eines Unternehmens mit allen vorhandenen Aspekten in einem einzigen Modell adäquat zu repräsentieren und zu analysieren. Deshalb verwenden die meisten Verfahren, die die geschäftsprozessorientierte Modellbildung unterstützen, unterschiedliche Sichten auf das Gesamtsystem, um so die Komplexität zu reduzieren. Zwei dieser Ansätze wollen wir im Folgenden kurz vorstellen. Für ein genaueres Studium wird auf die jeweiligen Originalarbeiten verwiesen. 3.4.1.1
Architektur integrierter Informationssysteme
Ziel der Architektur integrierter Informationssysteme (ARIS) [Sche98a], [Sche98b] ist es, einen Orientierungsrahmen für die Entwicklung betrieblicher Informationssysteme zur Verfügung zu stellen. Die ARIS-Architektur sieht eine ganzheitliche Beschreibung von Unternehmensprozessen vor und liefert dafür verschiedene Zerlegungssichten, die jede wiederum in weitere Beschreibungsebenen unterteilt wird (siehe Abbildung 3.22). Zerlegungssichten Die unterschiedlichen Sichten der ARIS-Architektur analysieren verschiedene Aspekte des Gesamtsystems. Die Organisationssicht erfasst organisatorische Einheiten und Aufgabenträger des Unternehmens und stellt Struktur sowie Beziehungen zwischen Aufgabenträgern dar. Die zu erfüllenden Aufgaben sowie ihre hierarchische Anordnung werden in der Funktionssicht abgebildet. Die Daten des Unternehmens sowie die durch sie repräsentierten Zustände und Ereignisse werden in der Datensicht beschrieben. Die Steuerungssicht verbindet die anderen Sichten miteinander und ermöglicht eine ganzheitliche Modellierung des Informationssystems. Zur Modellierung von Geschäftsprozessen werden in der Steuerungssicht die Methoden der erweiterten ereignisgesteuerten Prozessketten (eEPK) und Vorgangskettendiagramme (VKD) angeboten, mit denen die zeitliche und logische Reihenfolge von Aktivitäten dargestellt werden kann. 4 Als Wertschöpfung versteht man die Bewertung aller vom Unternehmen erbrachten Leistungen abzüglich aller extern bezogener Vorleistungen.
3.4 Weitere Formen der Modellbildung
Fachkonzept
117
Organisationssicht
DV-Konzept Betriebswirtschaftliche Problemstellung Implementierung
Fachkonzept (semantische Modelle) Fachkonzept
Fachkonzept
Fachkonzept
DV-Konzept
DV-Konzept
DV-Konzept
Implementierung
Implementierung
Implementierung
Datensicht
Steuerungssicht
Funktionssicht
DV-Konzept (DV-bezogene Beschreibungsebene)
Implementierung (DV-mäßige Realisierung)
Informationstechnik
Abb. 3.22: ARIS-Zerlegungssichten und -Beschreibungsebenen [nach Sch98a]
Beschreibungsebenen In ARIS wird jede Zerlegungssicht um drei weitere Beschreibungsebenen ergänzt. Die Beschreibungsebenen ermöglichen eine durchgängige Beschreibung von der betriebswirtschaftlichen Problemstellung bis hin zur technischen Realisierung. Die drei Ebenen werden als Fachkonzept, DV-Konzept und Implementierung bezeichnet. Das Fachkonzept enthält ein Modell des betriebswirtschaftlichen Anwendungsgebietes. Das DV-Konzept überträgt die Begriffe aus dem Fachkonzept in die Kategorien der informationstechnischen Umsetzung. Die Implementierung beschreibt die technische Realisierung des Fachkonzeptes. Die Beschreibungsebenen sind durch unterschiedliche Änderungszyklen charakterisiert. Das betriebswirtschaftliche Fachkonzept ändert sich eher selten, wohingegen die Implementierung eng mit der Informationstechnik verbunden ist, die sehr schnellen Innovationszyklen unterliegt. Durch die vorgenommene Unterteilung in Beschreibungsebenen wird versucht, die Fachkonzeptebene von ihrer Realisierung und der verwendeten Informationstechnologie zu abstrahieren. Innerhalb der Ebenen und Sichten können in ARIS verschiedene Modellierungstechniken zum Einsatz kommen. Die wichtigsten Modelle, die dabei zum Einsatz kommen können, sind in Abbildung 3.23 in das ARIS-Haus eingeordnet. Des Weiteren unterstützt ARIS ein Vorgehensmodell, branchenspezifische Referenzmodelle und softwaremäßige Unterstützung der Modellbildung durch das ARIS Toolset.
118
3 Konzeptueller Datenbankentwurf
Aufgabenträgerebene Organigramm
Netzdiagramm
Netztopologie
Aufgabenebene - eERM - eERM-Attributzuordnungsdiagramm
- Informationsflussdiagramm - Funktionszuordnungsdiagramm - Wertschöpfungskettendiagramm - eEPK und VKD
- Funktionsbaum - Y-Diagramm - Zieldiagramm
- Relationendiagramm - Attributzuordnungsdiagramm
- Zugriffsdiagramm
- Anwendungssystemtypendigramm
- Tabellendiagramm
- Zugriffsdiagramm (physikalisch)
- Anwendungssystemdiagramm
Abb. 3.23: Metamodelle in ARIS [nach Scha98a]
3.4.1.2
Semantisches Objektmodell
Ausgangspunkt der Betrachtung im semantischen Objektmodell SOM [FeSi90, [FeSi98] stellt eine Unternehmensarchitektur, bestehend aus dem Unternehmensplan, Geschäftsprozessmodellen und Anwendungssystemen dar. Der Unternehmensplan beinhaltet das Ergebnis der betriebswirtschaftlichen Unternehmensplanung, identifziert die Unternehmensziele, analysiert Chancen und Risiken und bestimmt unterschiedliche Strategien zur Realisierung der Unternehmensziele. SOM sieht Geschäftsprozessmodelle als Spezifikation von Lösungsverfahren für die Umsetzung des Unternehmensplans. Anwendungssysteme stellen Ressourcen zur Durchführung von Geschäftsprozessen dar. Auch SOM reduziert die Komplexität von Unternehmensmodellen durch die Einführung von Ebenen und Sichten. Im Gegensatz zu ARIS unterscheidet SOM primär drei Ebenen und sekundär eine strukturorientierte und eine verhaltensorientierte Sicht. Die einzelnen Modellsichten, ihre Beziehungen sowie die methodischen Abhängigkeiten zwischen den Modellsichten sind im Vorgehensmodell (V-Modell) des SOM-Ansatzes zusammengefasst. Die Abhängigkeiten zwischen diesen beiden Sichten innerhalb der einzelnen Modellebenen werden durch den Abstand der Schenkel im V-Modell repräsentiert (siehe Abbildung 3.24). Eine detaillierte Darstellung der Vorgehensweise bei der geschäftsprozessorientierten Modellbildung unter Verwendung von SOM findet sich in [FeSi95]. 1. Ebene: Unternehmensplan (Objektsystem und Zielsystem) Basis der Modellbildung bildet die Unterscheidung in Objekt- und Zielsystem. Das Objekt-
3.4 Weitere Formen der Modellbildung
strukturorientierte Sicht
119
verhaltensorientierte Sicht
Objektsystem
Zielsystem
Interaktionsmodell IM
Aufgabensystem AS
Vorgangsobjektschema VOS
1. Ebene: Unternehmensplan
2. Ebene: Geschäftsprozesse
3. Ebene: Anwendungssysteme
Konzeptuelles Objektschema KOS
Abb. 3.24: V-Modell des SOM-Ansatzes [nach FeSi95]
system besteht aus einer strukturorientierten Beschreibung der relevanten Teile des Unternehmensplans und aus der Abgrenzung der Diskurswelt von ihrer Umwelt. Das Zielsystem beschreibt eine verhaltensorientierte Sicht auf den Unternehmensplan. Zur Modellierung beider Komponenten wird auf informale Darstellungsformen (textuelle Beschreibung) zurückgegriffen. 2. Ebene: Geschäftsprozesse (Interaktionsmodell und Aufgabensystem) In Ebene 2 des Modells werden Lösungsverfahren zur Umsetzung des Unternehmensplans in Form eines Systems von Geschäftsprozessen beschrieben und im Rahmen der Modellbildung schrittweise verfeinert. Die strukturorientierte Sicht auf das Objektsystem wird in einem Interaktionsmodell, die verhaltensorientierte Sicht auf die Aufgaben und Ziele des Unternehmensplans durch ein Aufgabensystem spezifiziert. Während der Modellbildung werden die beiden Sichten zunehmend verfeinert, so dass sie hinsichtlich des Detaillierungsgrades korrespondieren. Durch sukzessive Zerlegung des betrieblichen Objektsystems entsteht ein Interaktionsmodell, welches aus einer Folge von Interaktionsdiagrammen mit zunehmendem Detaillierungsgrad besteht. Innerhalb eines solchen Diagramms wird das Objektsystem als Menge von Objekten modelliert, die durch Flüsse miteinander verbunden sind. Parallel zum Interaktionsmodell wird das Aufgabensystem von der Gesamtaufgabe ihres Zielsystems abgeleitet. Das Aufgabensystem besteht aus einer Folge von Aufgabenzerlegungen, die mit je einem Interaktionsdiagramm korrespondieren. Zur Beschreibung der Ebene 2 des V-Modells wird eine semiformale Darstellungsform (Diagramme) angeboten. 3. Ebene: Anwendungssysteme (KOS und VOS) Auf dieser Ebene erfolgt die Spezifikation der Geschäftsprozesse aus der Sicht von Anwendungssystemen. Das strukturorientierte konzeptuelle Objektschema (KOS) besteht aus einer Menge von miteinander in Beziehung stehenden Objekttypen und stellt eine objekt-
120
3 Konzeptueller Datenbankentwurf
orientierte Erweiterung von SERM (vgl. Unterkapitel 3.1.2.1) um Objekttypen, Nachrichten und Methoden zur Behandlung eingehender Nachrichten dar. Die Modellierung des verhaltensorientierten Vorgangsobjektschemas (VOS) stellt die abschließende Phase der Objektmodellierung im SOM dar. Es beschreibt das Zusammenwirken konzeptueller Objekttypen bei der Durchführung betrieblicher Aufgaben, die in Form von Vorgängen durchgeführt werden. Jeder Vorgang besteht aus einer Folge von Aktionen, wird durch ein auslösendes Ereignis generiert und kann seinerseits weitere Ereignisse generieren. Für die Modellierung verwendet das VOS eine Menge so genannter Vorgangsobjekttypen, die für eine oder mehrere verwandte Aufgaben das Zusammenwirken der an der Aufgabendurchführung beteiligten konzeptuellen Objekttypen des KOS beschreiben. Zur Beschreibung der Ebene 3 des V-Modells wird ebenfalls eine semiformale Darstellungsform angeboten.
3.5
Sichtenintegration und Schemakonsolidierung
Die bisher geschilderte Vorgehensweise zur Erstellung einer DB eignet sich nur für kleine und übersichtliche Entwurfsprojekte. In vielen großen Anwendungen geht die Anzahl der involvierten Entitytypen in mehrere Hunderte – dementsprechend hoch ist auch die Anzahl der erhobenen Attribute und Beziehungstypen. Um die Analyse der umfangreichen Anforderungen und damit verbunden die Komplexität des Entwurfs der DB zu beherrschen, wird in vielen Projekten die Gesamtheit aller Anforderungen in kleinere und damit übersichtlichere Bereiche (Funktionsbereiche) geteilt und von unterschiedlichen Analytikern eine getrennte Analyse der Bereiche vorgenommen. Dieser Vorgehensweise kommt entgegen, dass die Analyse der Funktionsbereiche parallel erfolgen kann und Bereichsexperten eingesetzt werden können, die durch ihre Sachkenntnis zur verbesserten Qualität des Datenbankentwurfs beitragen können. Die getrennte Vorgehensweise bei Anforderungserhebung und/oder -analyse durch mehrere Analytiker hat jedoch auch Nachteile. Unterschiedliche Personen können unterschiedliche Schwerpunkte in ihren Analysen setzen und verschiedene Aspekte unterschiedlich beurteilen und bewerten. Dies kann zur Folge haben, dass ein Sachverhalt der Realität in unterschiedlichen Analysen unterschiedlich dokumentiert wird oder aber auch zwei verschiedene Sachverhalte in zwei oder mehreren Modellen gleich bewertet werden. Dies ist darauf zurückzuführen, dass die unterschiedlichen Bereiche, die Gegenstand der Analyse sind, nicht unabhängig voneinander sind und unterschiedliche Interpretationen (Sichtweisen) auf gemeinsam genutzte Daten erlauben.
Beispiel 3.15: Sichtweisen auf Artikeldaten In Abbildung 3.25 zeigen wir unterschiedliche Sichtweisen auf Artikeldaten aus unterschiedlichen Funktionsbereichen eines Unternehmens. Für jede Abteilung sind einige Begriffe dargestellt, die während der Analyse im Zusammenhang mit Artikeln gesammelt wurden. Dieses Beispiel zeigt eine der Problematiken der getrennten Analyse, nämlich die Gefahr der Verwendung von Homonymen und Synonymen durch unterschiedliche Entwerfer. So stellen die Begriffe „Artikel“ im Einkauf und „Komponente“ in der Produktion möglicherweise den gleichen Sachverhalt dar. Der „Artikel“ aus dem Absatzbereich und das „Produkt“ in der Produktionsabteilung sind ebenfalls Synonyme. Wenn der Leiter der
3.5 Sichtenintegration und Schemakonsolidierung
Qualität
121
Artikel
Preis
Einkauf Kosten Lager
Lager
Preis
Lager Kosten
Kosten
Produkt
Absatz Qualität Artikel
Produktion Baureihe Komponente
Abb. 3.25: Sichtweisen auf Artikeldaten
Einkaufsabteilung von „Kosten“ spricht, so meint er in erster Linie die Kosten der Beschaffung, d. h. den Preis, die Kosten für eine Eingangskontrolle, Lagerhaltungskosten usw. In der Produktionsabteilung sind „Kosten“ die Produktionskosten (Betriebsmittel, Betriebsstoffe, . . . ), und im Absatzbereich handelt es sich bei „Kosten“ um Vertriebskosten (Kommissionierung, Absatzlager, . . . ). Ähnlich verhält es sich mit dem Begriff „Lager“: Hierbei handelt es sich um Beschaffungslager, Zwischenlager, Produktionslager, Kommissionierungslager, Absatzlager usw. Die „Qualität“ im Absatzbereich bezieht sich auf die eigenen Erzeugnisse und damit auf die Produktion. Im Einkauf geht es bei „Qualität“ jedoch um die Qualität der Lieferantenartikel (bsw. Rohstoffe).
Feststellung 3.5: Sichtenintegration, Schemakonsolidierung Wird die Analyse der Anforderungen bereichsbezogen vorgenommen bzw. sind unterschiedliche Analytiker mit der Analyse von Teilproblemen befasst, so ist es notwendig, das Entwicklungszyklusmodell einer DB um eine weitere Phase, die so genannte Sichtenintegration und Schemakonsolidierung, zu erweitern. Diese Phase findet üblicherweise während der konzeptuellen Modellbildung (vgl. Abbildung 1.1) statt, geht also davon aus, dass die Anforderungen der unterschiedlichen Bereiche
122
3 Konzeptueller Datenbankentwurf
individuell erhoben und analysiert wurden und als Bereichsdatenmodelle vorliegen. Die Integration erfolgt in den meisten Fällen auf der Basis zu konsolidierender ERM. Die Integration kann auch bereits nach der Anforderungserhebung erfolgen, jedoch hat das den Nachteil, dass Anforderungen noch relativ schlecht strukturiert sind, und im Zuge der Analyse noch ein besseres Verständnis der Anwendung gewonnen werden kann. Eine Integration während des logischen Entwurfs der DB wäre auch vorstellbar. Jedoch hat das den Nachteil, dass durch die eingeschränkte semantische Darstellungskraft des Relationenmodells relevante Sachverhalte in Integrationsentscheidungen ungenügend Berücksichtigung finden könnten. Bei der Integration unterschiedlicher Sichten wird immer von zumindest zwei Phasen ausgegangen. Während der ersten Phase werden unterschiedliche Bereiche bestimmt, die Benutzergruppen der Bereiche identifiziert, und eine Sicht auf die Daten erstellt, die die Anforderungen der Benutzer des jeweiligen Bereiches reflektiert (Bereichsdatenmodell). In der zweiten Phase erfolgt die eigentliche Integration der Sichten zu einem einheitlichen konzeptuellen Schema, das oft auch Unternehmensdatenmodell genannt wird und eine einheitliche Sicht auf den Datenbestand des Unternehmens repräsentiert. Da sich die Sichten der einzelnen Bereiche sehr oft überschneiden, ist es nicht möglich, das konzeptuelle Datenmodell durch einfaches Zusammenfügen von Bereichsdatenmodellen zu erzeugen. Vielmehr ist es notwendig, Konflikte zwischen der Darstellung in unterschiedlichen Bereichsmodellen zu erkennen und zu bereinigen, Konzepte mit identischer oder oft auch ähnlicher Semantik zusammenzufassen und neue Generalisierungen und Aggregationen zu bilden, um alle Sichten im konzeptuellen Modell adäquat und konsistent zu repräsentieren. Ein weiterer Aspekt der Aufteilung der Arbeit zwischen unterschiedlichen Analytikern ist der Zeitpunkt, zu dem die Analyse durchgeführt wird. In vielen Unternehmen gibt es bereits bestehende DBS, die oftmals in das neu zu schaffende System integriert werden sollen oder die nicht mehr als Insellösungen für bestimmte Bereiche betrieben werden, sondern zu einem einzigen System zusammengeführt werden sollen. In beiden Fällen liegt bereits ein Datenbankschema vor, das nun ebenfalls Gegenstand der Integration ist. Bei der Integration von Sichten geht man davon aus, dass die Zeitpunkte der Erhebung der Anforderungen der Nutzer der unterschiedlichen Bereiche nicht weit auseinander liegen. Des Weiteren erfolgte die Erhebung koordiniert und unter Verwendung einheitlicher Vorgehensmodelle. Bei der Integration unterschiedlicher DB ist dies meistens nicht der Fall. Die DB sind meist unkoordiniert entstanden und da ihre Entstehungszeitpunkte weit auseinander liegen können, kamen oft unterschiedliche Produkte, ja oft sogar Systeme, die auf unterschiedlichen Datenbankmodellen beruhen, zum Einsatz. Ist dies der Fall, so müssen die einzelnen heterogenen Datenbankschemata in einem einheitlichen Schema abgebildet und Strukturunterschiede zwischen den Datenbankmodellen ausgeglichen werden. Des Weiteren findet der Integrationsprozess nach der Population der DB mit Daten statt. Das hat zur Folge, dass Widersprüche auf der Instanzenebene auftreten können, die während der Integration auf geeignete Weise berücksichtigt werden müssen. Für die nachfolgenden Betrachtungen unterstellen wir Einheitlichkeit bezüglich der verwendeten Datenbankmodelle. Wurden während der Analyse unterschiedliche Datenmodelle eingesetzt oder basieren die zu integrierenden DB auf unterschiedlichen Modellen, so unterstellen wir, dass eventuell notwendige Transformationen bereits stattgefunden haben.
3.5 Sichtenintegration und Schemakonsolidierung
3.5.1
123
Prozess der Sichtenintegration
Bevor mit der eigentlichen Sichtenintegration begonnen werden kann, muss in einer Vorphase entschieden werden, in welcher Reihenfolge die Bereichsdatenmodelle integriert werden und welche Integrationsstrategie angewendet werden soll. Der Integrationsprozess ist mit der Entstehung vorübergehender Schemata verbunden, die ein Zwischenergebnis darstellen und zur weiteren Integration mit anderen Bereichsdatenmodellen verglichen werden. In der Frage, wie viele Schemata zu einem Zeitpunkt verglichen werden, lassen sich binäre und n-stellige Ansätze der Sichtenintegration unterscheiden. Bei der binären Integration werden schrittweise zwei Schemata zu einem teilintegrierten Schema konsolidiert, das im nächsten Schritt mit einem weiteren Bereichsdatenmodell zu einem neuen teilintegrierten Schema konsolidiert wird. Dieser Vorgang wird so lange fortgesetzt, bis das unternehmensweit konsolidierte Datenmodell entwickelt ist. Die n-stellige Integration unterliegt nicht der Einschränkung, dass nur zwei Schemata pro Schritt integriert werden können. Die „One-shot“-Methode fügt in nur einem Schritt alle Schemata zum globalen konzeptuellen Schema zusammen. Wenn innerhalb der n-stelligen Integration Zwischenschritte zugelassen sind, spricht man von iterativer Integration. Der Vorteil der n-stelligen Methode gegenüber der binären liegt in der Verfügbarkeit von mehr Informationen innerhalb eines Schrittes und in der größeren Flexibilität der Analytiker, da diese die Anzahl der zu integrierenden Schemata variieren können. Der Nachteil ergibt sich jedoch aus der größeren Komplexität, die eine Ursache für Designfehler darstellen kann. Ein wesentliches Problem des Integrationsprozesses stellt die Wahl der Reihenfolge der zu integrierenden Sichten dar. Hierzu wird in der Literatur oft eine Gewichtung der Sichten vorgeschlagen, die die Qualität und Relevanz der Sichten repräsentieren soll. Die Gewichtung wird durch die Rolle der Aufgabenträger in der Organisation und die Zuverlässigkeit, die für den vorhergegangenen Entwurfsschritt (Anforderungserhebung und -analyse) angenommen werden kann, bestimmt. Sichten mit höherer Gewichtung sollen dann früher in den Integrationsprozess aufgenommen werden, um eine höhere Stabilität und Konvergenz der teilintegrierten Schemata zu erreichen. Oft wird auch vorgeschlagen, Sichten mit einer zusätzlichen Gewichtung zu versehen, wenn die zugehörigen Benutzer „unumstrittene Experten“ in dem modellierten Bereich sind. Der eigentliche Integrationsprozess läuft in den drei Phasen Vergleichsphase, Anpassungsbzw. Vereinheitlichungsphase und Zusammenführungs- bzw. Konsolidierungsphase ab. Hierbei muss man jedoch einschränkend erwähnen, dass diese Phasen auch in Kombination durchgeführt werden können. Auch schlagen viele Autoren eine iterative Vorgehensweise der Sichtenintegration vor, mit dem Vorteil, dass einzelne Integrationsphasen wiederholt durchgeführt werden können, um eine Konsolidierungsphase zu umgehen. In den folgenden Unterkapiteln soll auf die einzelnen Phasen näher eingegangen werden. 3.5.1.1
Vergleichsphase
Nachdem die Integrationsstrategie gewählt worden ist, kann mit der eigentlichen Integration begonnen werden. Die entscheidende Aufgabe in der Vergleichsphase besteht in der Analyse und Dokumentation des Zusammenhanges zwischen den unterschiedlichen Bereichsdatenmodellen und der Identifikation möglicher Konflikte.
124
3 Konzeptueller Datenbankentwurf
Unterschiedliche Funktionsbereiche können über gemeinsam genutzte Datenbestände miteinander in Zusammenhang stehen. In der Vergleichsphase müssen die Zusammenhänge festgestellt werden, da sie Ursache möglicher Konflikte sein können. Zwei Schemata bzw. Schemakonstrukte können im Allgemeinen auf vier verschiedene Arten in Korrespondenzbeziehung stehen. • Identisch: Die Bereichsdatenmodelle stellen den gleichen Sachverhalt der Realität dar. Das verwendete Modellierungskonstrukt zur Abbildung des Sachverhaltes ist identisch. • Disjunkt: Die betrachteten Bereichsdatenmodelle referenzieren keine identischen Ereignisse der Realität. Es existiert jedoch eine Korrespondenz zwischen den Modellen über gemeinsam genutzte Bezeichner. • Überlappend: Einige Schemakonstrukte des einen Bereiches kommen auch in einem anderen vor. Die Bereichsdatenmodelle besitzen jedoch auch eigene Elemente. • Enthalten: Ein Schema (Schemakonstrukt) ist eine Teilmenge des anderen. Im nächsten Schritt muss der Designer für korrespondierende Schemakonstrukte aus unterschiedlichen Bereichen feststellen, ob (Modellierungs-)Konflikte vorliegen. Dabei lassen sich unterschiedliche Arten von Konflikten feststellen. • Namenskonflikte Sie können in zwei unterschiedlichen Varianten auftreten. Im ersten Fall verwenden verschiedene Entwickler zur Bezeichnung eines Sachverhaltes der Realität dasselbe Modellierungskonstrukt, jedoch unterschiedliche Namen. In diesem Fall spricht man von Synonymen (zwei identische Konstrukte, z. B. Entitytypen tragen unterschiedliche Namen). In der zweiten Variante werden zwei Sachverhalte der Realität mit unterschiedlicher Bedeutung mit einem identischen Bezeichner versehen. In diesem Fall spricht man von Homonymen. • Strukturkonflikte Hier tritt der Fall auf, dass in den Bereichsmodellen derselbe Sachverhalt unter Verwendung unterschiedlicher Strukturierungskonzepte dargestellt wurde. Man kann drei Arten von Strukturkonflikten unterscheiden. Ein Typkonflikt zwischen zu integrierenden Bereichsmodellen liegt vor, wenn ein Sachverhalt der realen Welt mit unterschiedlichen Modellierungskonzepten dargestellt wird. So kann z. B. ein Entitytyp der einen Sicht als Beziehungstyp oder auch als Attribut in einer anderen Sicht modelliert sein. Wenn ein Sachverhalt der realen Welt unterschiedlich modelliert werden kann, so spricht man in diesem Zusammenhang auch von semantischem Relativismus. Ein Beziehungskonflikt oder aber auch Abhängigkeitskonflikt bezieht sich auf unterschiedlich gewählte Integritätsbedingungen. Ein Beispiel dafür sind verschiedene Kardinalitäten von Beziehungstypen, die denselben Sachverhalt referenzieren. Z. B. kann in einer Sicht eine Beziehung zwischen zwei Entitytypen als N:M-Beziehungstyp definiert sein, und in einer anderen Sicht gilt eine 1:N-Einschränkung. Auch äquivalente Darstellungen identischer Sachverhalte
3.5 Sichtenintegration und Schemakonsolidierung
125
(Zur Problematik äquivalenter Darstellungen identischer Sachverhalte im ERM siehe Abbildung 3.7) können die Ursache von Beziehungskonflikten sein. Die dritte Klasse von Strukturkonflikten bilden die Schlüsselkonflikte. Diese entstehen, wenn in unterschiedlichen Bereichen für identische Sachverhalte unterschiedliche Schlüssel gewählt wurden. • Verhaltens- und Abstraktionskonflikte Von Verhaltenskonflikten sind hauptsächlich Einfüge- und Löschoperationen betroffen. Der Begriff „Verhalten“ bezieht sich hier auf die Einhaltung referenzieller Integrität. So könnte in einem Bereich spezifiziert sein, dass nach dem Löschen der letzten Referenz auf einen Sachverhalt dieser Sachverhalt auch gelöscht werden soll, während in einem anderen Bereich spezifiziert ist, dass er weiterhin gespeichert bleiben soll. Abstraktionskonflikte treten auf, wenn identische Sachverhalte in unterschiedlichen Bereichen auf unterschiedlichem Abstraktionsniveau dargestellt werden. Beispiele dafür sind unterschiedliche Detaillierungsgrade in Generalisierungs- oder Subtypenhierarchien oder 1:1-Beziehungstypen, die in einer Sicht dargestellt sind und in einer anderen Sicht zu einem einzigen Entitytyp zusammengefasst wurden. 3.5.1.2
Anpassungs- und Vereinheitlichungsphase
Die entdeckten Konflikte aus der vorherigen Phase müssen in diesem Schritt gelöst werden, um die Schemata für die Integration vorzubereiten. Dies kann dadurch erreicht werden, dass eine der beteiligten Sichten „nachgibt“, um durch Transformation der in Konflikt stehenden Teile Konsens zwischen den Sichten zu erreichen. Die Schwierigkeit liegt darin, geeignete Transformationen zwischen den Schemata zu wählen. Namenskonflikte lassen sich im Vergleich zu den anderen Konfliktarten noch relativ leicht lösen, obwohl in größeren Datenmodellen durchaus Konflikte übersehen werden können. Bestimmte Merkmale weisen jedoch auf die Existenz möglicher Konflikte hin. Haben Konstrukte mit verschiedenen Namen mehrere gemeinsame Eigenschaften und unterliegen diese auch den gleichen Einschränkungen, so deutet diese Ähnlichkeit auf ein Synonym hin. Im Gegensatz dazu weisen gleiche Namen von Konstrukten mit unterschiedlichen Eigenschaften und Einschränkungen auf ein Homonym hin. Homonyme sind offensichtlich leichter zu erkennen als Synonyme. Als Lösung von Namenskonflikten bieten sich Namensanpassungen oder -änderungen an. Nachdem Namenskonflikte gelöst worden sind, erhält man eindeutige Bezeichner für alle Konstrukte. Nach dieser Phase kann vorausgesetzt werden, dass Konstrukte mit identischem Bezeichner auch wirklich denselben Sachverhalt der realen Welt darstellen. Die anderen Konfliktarten lassen sich nicht so einfach lösen. Während der Vergleichsphase wurden vom Designer zwischen den Konstrukten unterschiedlicher Schemata Korrespondenzbeziehungen definiert. Die Korrespondenzbeziehungen beruhen jedoch auf Vermutungen, die es nun in der Vereinheitlichungsphase zu verifizieren gilt. Dies wird in den meisten Fällen durch Hinzuziehung von Bereichsexperten oder durch Konsultation der Personen, die die Bereichsdatenmodelle erstellt haben, geschehen. Die Zusammenführung der Bereichsdatenmodelle erfolgt dann abhängig von der Art der festgestellten Korrespondenzbeziehung in der nächsten Phase.
126 3.5.1.3
3 Konzeptueller Datenbankentwurf Zusammenführungs- und Konsolidierungsphase
Die abschließende Phase im Integrationsprozess gliedert sich in zwei Teilschritte. Im ersten Teil werden die vereinheitlichten Bereichsdatenmodelle in Abhängigkeit der festgestellten Korrespondenzbeziehungen integriert. Im zweiten Teil werden Restrukturierungsmaßnahmen auf dem integrierten Schema ausgeführt, um dieses zu optimieren. 3.5.1.3.1
Zusammenführung von Entitytypen
Die Zusammenführung erfolgt abhängig von der Art der in der Vergleichsphase festgestellten Korrespondenzbeziehungen zwischen Entitytypen. • Identische Entitytypen aus unterschiedlichen Bereichsdatenmodellen werden im integrierten Schema zu einem Entitytyp zusammengefasst. Dabei werden die Attribute beider Entitytypen in den integrierten Entitytyp aufgenommen. • Bei zwei Entitytypen aus unterschiedlichen Bereichsdatenmodellen mit überlappenden Attributen oder gemeinsamen Entities werden im integrierten Schema drei Entitytypen gebildet. Der Durchschnitt der Attribute der Entitytypen bildet einen generischen Entitytyp, die beiden anderen Entitytypen mit den noch verbleibenden Attributen bilden Spezialisierungen. Sind Spezialisierungen nicht disjunkt, wird der Sachverhalt als Untermengenhierarchie dargestellt. • Wenn ein Entitytyp alle Entities eines Entitytypen eines anderen Bereichsdatenmodells enthält, so werden beide Entitytypen als Klasse und zugehörige Subklasse in das integrierte Schema übernommen. • Referenzieren Entitytypen unterschiedliche Sachverhalte der realen Welt, so sind sie disjunkt und werden in das integrierte Schema als eigenständige Entitytypen aufgenommen. Wurde jedoch eine Korrespondenzbeziehung festgestellt (z. B. wegen korrespondierender Attribute), kann auch eine Integration der Entitytypen erwogen werden.
Beispiel 3.16: Korrespondierende Attribute bei disjunkten Entitytypen Wir betrachten die Entitytypen „Professor“ mit Attributen SVNr, Name, Gehalt und „Student“ mit Attributen SVNr, Name, Gehalt, Studienrichtung. Wir nehmen an, dass Entities vom Typ Professor nicht mehr studieren und beide Entitymengen daher disjunkt sind. Obwohl Korrespondenzen über gemeinsame Attribute existieren, ist es nicht notwendigerweise sinnvoll, die Entitytypen zu integrieren.
Beispiel 3.17: Integration enthaltender Entitytypen In Abbildung 3.26 betrachten wir korrespondierende Entitytypen aus den Bereichsdatenmodellen von Absatz und Produktion. Im Absatzbereich sind für jeden Artikel u. a. seine Artikelnummer (A-Nr) und sein Preis von Bedeutung. In der Produktion der Produktionsort (P-Ort), die involvierten Arbeitsstunden (Stunden) und die Maschine, auf der das
3.5 Sichtenintegration und Schemakonsolidierung
127
Preis
Preis
Artikel
Artikel A_Nr
A_Nr
P_Ort
P_Ort
Eigenfertigung
Eigenfertigung Stunden
Stunden
Maschine
Maschine
Abb. 3.26: Integration enthaltender Entitytypen
Produkt gefertigt wurde. Da jedes Produkt auch verkauft wird, ist Entitytyp „Eigenfertigung“ im Entitytyp „Artikel“ enthalten und die Integration kann über die Einführung einer Untermengenbeziehung im integrierten Schema erfolgen.
Beispiel 3.18: Integration überlappender Entitytypen In Abbildung 3.27 betrachten wir Ausschnitte aus den Bereichsdatenmodellen der Einkaufsabteilung und der Produktion. Es wird angenommen, dass es Artikel gibt, die sowohl in Eigenfertigung erstellt als auch über Lieferanten bezogen werden. Die Entitytypen Fremdbezug und Eigenfertigung sind somit überlappend, und die Darstellung im integrierten Schema erfolgt als Untermengenhierarchie.
A_Nr Preis
Preis
Fremdbezug
Artikel Konditionen
A_Nr
Lieferort
P_Ort P_Ort
Fremdbezug
Eigenfertigung
Eigenfertigung Stunden Maschine A_Nr
Preis
Abb. 3.27: Integration überlappender Entitytypen
Stunden Lieferort
Konditionen
Maschine
128
3 Konzeptueller Datenbankentwurf
3.5.1.3.2
Zusammenführung von Beziehungstypen
Mit dem Zusammenführen von Beziehungstypen kann unmittelbar nach der Zusammenführung der Entitytypen begonnen werden. Wurden zwei Entitytypen zusammengeführt, so sind alle Beziehungstypen, in die sie involviert waren, ebenfalls Kandidaten für eine Zusammenführung. In der Literatur werden acht Möglichkeiten unterschieden (vergleiche Abbildung 3.28), wie zwei Beziehungstypen miteinander zusammenhängen können. Grad der Beziehung
gleicher Grad
Rollen bei gleichem Grad
gleiche Rollen
strukturelle Einschränkungen
Fall 1: gleiche Einschränkung
Fall 2: verschiedene Einschränkung
verschiedener Grad
Fall 6: zusammenführbar
Fall 7: bedingt zusammenführbar
Fall 8: nicht zusammenführbar
verschiedene Rollen
Wertebereichseinschränkungen
Fall 3: Wertebereich enthalten
Fall 4: disjunkter Wertebereich
Fall 5: überlappender Wertebereich
Abb. 3.28: Korrespondenzen zwischen Beziehungstypen
Das Zusammenführen von Beziehungstypen ist immer dann möglich, wenn die Semantik der Beziehungstypen aus den Bereichsdatenmodellen nach der Integration im integrierten Schema adäquat repräsentiert ist. Stehen zwei Entitytypen in Bereichsdatenmodellen über unterschiedliche Rollen in Beziehung, so repräsentieren die Rollen in den meisten Fällen eine unterschiedliche Semantik. Trotz der unterschiedlichen Semantik ist jedoch oft ein Zusammenführen möglich, indem weitere Integritätsbedingungen in das integrierte Schema aufgenommen werden. Das Zusammenführen von Beziehungstypen unterschiedlichen Grades stellt den schwierigsten Fall dar, der nur unter bestimmten Voraussetzungen zu einer Integration führt. Im Folgenden sollen die unterschiedlichen Fälle im Detail besprochen werden: Fall 1: Gleicher Grad, gleiche Rollen, gleiche Kardinalität Diese Situation stellt den einfachsten Fall dar. Nach der Integration der Entitytypen existiert im integrierten Schema ein generischer Entitytyp mit zwei Spezialisierungen. Der Beziehungstyp wird dem generischen Entitytyp zugeordnet.
3.5 Sichtenintegration und Schemakonsolidierung
129
Beispiel 3.19: Integration von Beziehungstypen gleichen Grades, gleicher Rollen, gleicher Kardinalitäten Wir betrachten die beiden Entitytypen „Student der Wirtschaftsinformatik“ und „Student im Hauptstudium“ zweier unterschiedlicher Bereichsdatenmodelle. Beide Entitytypen stehen über „besucht“ mit dem Entitytyp „Vorlesung“ in N:M-Beziehung. In diesem Fall wird das integrierte Schema einen Entitytyp „Student“, zwei Subklassen („Student der Wirtschaftsinformatik“ und „Student im Hauptstudium“) sowie den Beziehungstyp „besucht“, der der Superklasse zugeordnet ist, enthalten. Fall 2: Gleicher Grad, gleiche Rollen, unterschiedliche Kardinalitäten Dieser Fall entspricht der Situation, in der eine Beziehung zwischen zwei Entitytypen in unterschiedlichen Bereichsdatenmodellen mit unterschiedlicher Kardinalität dargestellt ist. Beispiel 3.20: Integration von Beziehungstypen gleichen Grades, gleicher Rollen, unterschiedlicher Kardinalitäten Abbildung 3.29 zeigt zwei Bereichsdatenmodelle mit ähnlichen Beziehungstypen. Im Bereich (a) werden Produkte betrachtet, die entweder auf Lager sind oder eben nicht. Entities vom Typ „Produkt“ nehmen nicht verpflichtend am Beziehungstyp teil. Anders ist die Situation im Bereich (b). Hier werden ausschließlich Produkte betrachtet, die auf Lager sind. Die Zusammenführung der Entitytypen führt zu einer Generalisierungshierarchie. „Produkt“ wird zum generischen Entitytyp. Die Subklassen „Einzelanfertigung“ und „Massenprodukt“ werden in das integrierte Schema aufgenommen, um die Situation zu beschreiben, dass nicht alle Produkte (z. B. einzelgefertigte Produkte) auf Lager sind. Der Beziehungstyp „lagert“ wird der Spezialisierung „Massenprodukt“ zugeordnet. a)
b) Produkt (0, N)
Produkt
Produkt
(1, N) Art
lagert
lagert
M
M
Lager
Lager
Einzelfertigung
Massenfertigung (1, N) lagert
M
Lager
Abb. 3.29: Integration von Beziehungstypen gleichen Grades, gleicher Rollen, unterschiedlicher Kardinalitäten
Fall 3: Gleicher Grad, unterschiedliche Rollen, Untermengenbeziehung Eine Untermengenbeziehung zwischen Beziehungstypen unterschiedlicher Bereichsdatenmodelle liegt vor, wenn „ähnliche“ Entitytypen an den Beziehungen beteiligt sind und für einen
130
3 Konzeptueller Datenbankentwurf
Beziehungstyp aus einem Bereichsdatenmodell gilt, dass alle Beziehungen dieses Typs jeweils auch eine Beziehung des anderen Typs im anderen Bereichsdatenmodell darstellen. Um diesen Sachverhalt im integrierten Schema darstellen zu können, schlagen einige Autoren ein neues Strukturierungskonzept vor, nämlich den Subbeziehungstyp in das integrierte Schema aufzunehmen.
Beispiel 3.21: Integration von Beziehungstypen gleichen Grades, unterschiedlicher Rollen, Untermengenbeziehung In Abbildung 3.30 betrachten wir die Beziehung zwischen Abteilungen und zugeordneten Mitarbeitern. Im Bereich (a) werden ausschließlich Abteilungsleiter betrachtet, während im Bereich (b) eine Sicht dargestellt ist, in der alle Mitarbeiter, die einer Abteilung zugeordnet sind, in die Beziehung einfließen. Wir nehmen an, dass Abteilungsleiter immer der Abteilung zugeordnet sind, die sie leiten. Offensichtlich sind daher alle Beziehungen vom Typ „leitet“ aus Bereich (a) in „ist-zugeordnet“ aus Bereich (b) enthalten. Im integrierten Schema wird dieser Sachverhalt durch eine Subbeziehung zwischen „leitet“ und „ist-zugeordnet“ ausgedrückt.
a)
b) Mitarbeiter (0, 1)
leitet
1 Abteilung
(0, N) Mitarbeiter
Mitarbeiter
(0, 1)
(0, N) ist_ zugeordnet
ist_ zugeordnet
leitet
1 Abteilung
1
Abteilung
1
Abb. 3.30: Integration von Beziehungstypen gleichen Grades, unterschiedlicher Rollen, Untermengenbeziehung
Fall 4: Gleicher Grad, unterschiedliche Rollen, disjunkte Entityklassen Existieren zwei Beziehungstypen zwischen „ähnlichen“ Entitytypen in unterschiedlichen Bereichsdatenmodellen, in denen die Entities in unterschiedlichen Rollen auftreten und die völlig disjunkt sind, so werden beide Beziehungstypen in das integrierte Schema übernommen und eine Zusammenführung kann nicht durchgeführt werden. Fall 5: Gleicher Grad, unterschiedliche Rollen, überlappende Beziehungsmengen Beziehungstypen aus unterschiedlichen Bereichsdatenmodellen können teilweise überlappen, ohne dass eine der Beziehungen jedoch vollständig in der anderen enthalten ist. In diesem Fall ist es notwendig, im integrierten Schema Subtypenhierarchien aufzunehmen und die Beziehungstypen über Subbeziehungen miteinander zu verknüpfen.
3.5 Sichtenintegration und Schemakonsolidierung
131
Beispiel 3.22: Integration von Beziehungstypen gleichen Grades, unterschiedlicher Rollen, überlappende Beziehungsmengen In Abbildung 3.31 betrachten wir zwei Bereichsdatenmodelle, die eine Beziehung zwischen Mitarbeitern und Projekten darstellen. Im Bereich (a) werden Mitarbeiter betrachtet, die Projekten nicht unbedingt zugeordnet sind, sondern nur über die Projekte finanziert werden. Das Bereichsdatenmodell entspricht z. B. der Sichtweise der Lohnverrechnung. Bereich (b) entspricht beispielsweise der Sicht der Produktion und beinhaltet die aktuelle Zuordnung von Mitarbeitern zu Projekten ohne Berücksichtigung ihrer Finanzierung. Da Mitarbeiter jedoch auch an Projekten arbeiten können, durch die sie finanziert werden, sind die Beziehungen überlappend. Nach dem Zusammenführen der beiden Bereichsdatenmodelle ergibt sich das in Abbildung 3.31 dargestellte Bild. Das integrierte Schema wird um eine Subtypenhierarchie erweitert. Beide Beziehungstypen werden übernommen, wobei als Ausgangspunkt die Spezialisierungen der Subtypenhierarchie verwendet werden. Zusätzlich wird ein weiterer Beziehungstyp definiert, der mit beiden Beziehungstypen über eine Subbeziehung in Relation gesetzt wird.
Mitarbeiter a)
b) Mitarbeiter N
Mitarbeiter N Projektmitarbeiter
Kostenfaktor finanziert_ durch
M Projekt
arbeitet_an
M
N
N
finanziert_ durch
involviert_in
arbeitet_an
Projekt
M
Projekt
M
Abb. 3.31: Integration von Beziehungstypen gleichen Grades, unterschiedlicher Rollen, überlappende Beziehungsmengen
Fall 6: Unterschiedlicher Grad, zusammenführbar In diese Klasse fallen alle Beziehungstypen aus unterschiedlichen Bereichsdatenmodellen, die unterschiedlichen Grades sind, jedoch semantisch denselben Sachverhalt darstellen. Liegt Fall 6 vor, werden die äquivalenten Konstrukte aus den Bereichsdatenmodellen zusammengeführt, indem eine äquivalente Darstellung ausgewählt und in das integrierte Schema aufgenommen wird. Ein Beispiel für äquivalente Beziehungstypen unterschiedlichen Grades ist in Abbildung 3.7 gegeben. Fall 7: Unterschiedlicher Grad, bedingt zusammenführbar In diese Kategorie fallen Beziehungstypen aus unterschiedlichen Bereichsdatenmodellen, die einen ähnlichen Sachverhalt beschreiben, jedoch eine unterschiedliche Anzahl von beteiligten
132
3 Konzeptueller Datenbankentwurf
Entitytypen aufweisen und daher nur bedingt zusammenführbar sind. „Bedingt zusammenführbar“ bedeutet in diesem Zusammenhang, dass der Beziehungstyp niedrigeren Grades aus dem Beziehungstyp höheren Grades ableitbar ist.
Beispiel 3.23: Integration von Beziehungstypen unterschiedlichen Grades, bedingt zusammenführbar In Abbildung 3.32 betrachten wir zwei Bereichsdatenmodelle, die die Beziehung zwischen Teil und Produkt beschreiben. Der Lieferant, der ein bestimmtes Teil für ein Produkt beisteuert, ist im Bereich (a) als Attribut und im Bereich (b) als eigener Entitytyp modelliert. Abbildung 3.32 zeigt das integrierte Schema, das die Darstellung des Bereiches (b) übernommen hat, da daraus die Sicht von Bereich (a) hergeleitet werden kann.
a)
b) Produkt
Produkt
N
N
Produkt N
Lieferant bestehtAus
M Teil
Lieferant
1
liefert
liefert
M
M
Teil
1
Lieferant
Teil
Abb. 3.32: Integration von Beziehungstypen unterschiedlichen Grades, bedingt zusammenführbar
Fall 8: Unterschiedlicher Grad, nicht zusammenführbar Zwei Beziehungstypen aus unterschiedlichen Bereichsdatenmodellen können nicht zusammengeführt werden, wenn sie unterschiedliche Semantik besitzen. Dies gilt auch für den Fall, wenn die beteiligten Entities dieselben sind.
Beispiel 3.24: Integration von Beziehungstypen unterschiedlichen Grades, nicht zusammenführbar Wir betrachten in Abbildung 3.33 eine Produkt:Teil:Lieferant-Beziehung aus zwei unterschiedlichen Bereichsdatenmodellen mit unterschiedlicher Semantik. Im Bereich (a) ist modelliert, dass ein bestimmtes Teil in mehreren Produkten enthalten sein kann, jedoch immer nur von einem Lieferanten bezogen werden kann. Dies ist im Bereich (b) anders. Im Bereich (b) kann ein Teil in einem bestimmten Produkt nur von einem Lieferanten bezogen werden. Dasselbe Teil in einem anderen Produkt kann jedoch durchaus auch von anderen Lieferanten stammen. Aufgrund der unterschiedlichen Semantik ist ein Zusammenführen nicht möglich, und beide Beziehungstypen müssen in das integrierte Schema aufgenommen werden.
3.5 Sichtenintegration und Schemakonsolidierung a)
133 b)
Produkt
Produkt
N
N
bestehtAus
liefert
M Teil
1
Lieferant
M N
liefert
1
Lieferant
Teil
Abb. 3.33: Integration von Beziehungstypen unterschiedlichen Grades, nicht zusammenführbar
Nachdem die Zusammenführung von Entity- und Beziehungstypen vorgenommen und aus den Bereichsmodellen ein unternehmensweites Datenmodell entwickelt wurde, folgt die abschließende Aktivität der Sichtenintegration, nämlich die Durchführung von Restrukturierungsmaßnahmen am integrierten Schema. Bevor Restrukturierungen am Schema vorgenommen werden, ist es notwendig, alle Änderungswünsche durch Rückfragen bei den Bereichsexperten nachzufragen und nur dann eine Änderung vorzunehmen, wenn die Sicht des involvierten Bereiches erhalten bleibt. Als Hilfe dienen dazu drei Gütekriterien, die ein gutes integriertes Datenmodell kennzeichnen: 1. Vollständigkeit Ein integriertes Schema ist vollständig, wenn alle Informationen der Bereichsdatenmodelle komplett und korrekt im integrierten Schema enthalten sind. 2. Minimalität Der im Datenmodell dargestellte Sachverhalt soll redundanzfrei abgebildet sein. Eventuelle Redundanzen müssen aufgespürt und beseitigt werden, da sie zu Mehrfachspeicherung führen. 3. Verständlichkeit Durch Restrukturierung sollte die semantische und syntaktische Richtigkeit des Schemas geprüft und die Verständlichkeit des Datenmodells verbessert werden.
3.5.2
Kontrollaufgaben
Aufgabe 3.12: Fluglinie Entwickeln Sie für die Anforderungen an ein Informationssystem einer Fluglinie ein unternehmensweites Datenmodell. Erstellen Sie zuerst die Bereichsdatenmodelle der unterschiedlichen Benutzersichten und transformieren Sie diese anschließend in ein integriertes Schema. Die folgende Aufzählung ist nicht vollständig. Sie können das Beispiel um weitere Sachverhalte ergänzen. Benutzersicht 1: Flugzeugpark Man überlege sich zuerst die relevanten Attribute einzelner Flugzeuge: Hersteller, Typ, Seriennummer, Anschaffungsdatum, Länge, Gewicht, Spannweite, Maximale Flughöhe, Reichweite,
134
3 Konzeptueller Datenbankentwurf
Verwendungszweck (Cargo, Passagiermaschine), Anzahl der Flugstunden, Passagierkapazität. . . Es wird angenommen, dass die Gesellschaft alle Maschinen selbst wartet: Nach einer bestimmten Anzahl von Flugstunden ist eine Routineüberprüfung sowie in regelmäßigen Abständen eine Generalinspektion erforderlich. Jedem Maschinentyp ist ein spezielles Wartungsteam zugeordnet, das alle Inspektionen oder Reparaturen an dem betreffenden Flugzeug vornimmt. Für häufig benötigte Ersatzteile (z. B. Reifen) existiert ein eigenes Lager. Über Störfälle (z. B. Triebwerkausfall, Bruchlandung . . . ) wird Buch geführt. Störfälle werden von einem Wartungsteam behoben, das zur Behebung des Störfalls Ersatzteile verbraucht. Benutzersicht 2: Personalabteilung Über Mitarbeiter wird folgende Information gespeichert: Name, Mitarbeiter-Nummer, Adresse, Abteilung, Berufsbezeichnung und Gehalt. Es wird zwischen folgenden Gruppen von Mitarbeitern unterschieden: Gruppe 1, Gruppe 2,
Luft: Boden:
Piloten und Flugbegleiter. Verwaltungsangestellte und Techniker.
Für bestimmte Mitarbeiter sind in Abhängigkeit der zugeordneten Abteilung (Abteilungen entsprechen den einzelnen Benutzersichten) weitere Angaben erforderlich: Ein Techniker kann nur einen bestimmten Flugzeugtyp warten bzw. reparieren. Piloten dürfen nur in Abhängigkeit ihrer Fluglizenz bestimmte Flugzeuge fliegen. Zusätzlich haben Sie eine gewisse Erfahrung (gemessen in Flugstunden). Piloten und Flugbegleiter sind gewissen Flügen zugeordnet. Flugbegleiter bekommen für Langstreckenflüge Überstunden vergütet, Piloten nicht. Benutzersicht 3: Flugreservierung In dieser Abteilung fallen Daten über Passagiere an. Es sollen für jeden einzelnen Fluggast mindestens folgende Daten gespeichert werden: Name, Adresse, Telefon-Nummer, Alter. Jede Flugverbindung kann über eine Flugnummer (z. B. AW 712) eindeutig identifiziert werden. Eine Flugnummer ist jedoch nicht an ein bestimmtes Datum gebunden, so dass ein regelmäßiger Flug immer die gleiche Nummer erhält. Als weitere Daten werden Start- und Zielflughafen, Abflugs- und Ankunftszeit (jeweils die Ortszeit), Flugdauer und Entfernung benötigt. Während des Fluges werden Mahlzeiten gereicht. Bei einer Buchung wird ein Sitz in der betreffenden Maschine zugeordnet und in Abhängigkeit der Klasse (Business, Economy, First Class) ein Preis festgesetzt. Natürlich wird jedem Start Personal (Piloten, Flugbegleiter, eventuell Techniker) und ein Flugzeug zugeordnet.
3.6
Formaler Datenbankentwurf
In diesem Unterkapitel wollen wir ein Verfahren zur konzeptuellen Modellbildung vorstellen, das nicht mehr vollständig systemunabhängig durchgeführt werden kann, sondern bereits eine Schnittstelle hin zum logischen Datenbankentwurf darstellt. Als Zielmodell des formalen Datenbankentwurfs dient das relationale Datenbankmodell. Das Unterkapitel ist wie folgt gegliedert: Wir beginnen mit einer Darstellung des relationalen Datenbankmodells. Danach folgt eine Motivation für den formalen Datenbankentwurf und eine überblickartige Darstellung des
3.6 Formaler Datenbankentwurf
135
Verfahrens. Für Leser, die in diese Materie tiefer einsteigen möchten, schließen wir das Themengebiet mit einer komprimierten Darstellung der Theorie des formalen Datenbankentwurfs ab.
3.6.1
Das relationale Datenbankmodell
Die theoretischen Konzepte des relationalen Datenbankmodells (Relationenmodell) wurden 1970 von E. F. Codd [Codd70] vorgestellt. Ungefähr zehn Jahre später waren die ersten kommerziellen relationalen DBS am Markt. Heute sind DBS, die das relationale Datenbankmodell implementiert haben, die bei weitem gebräuchlichsten Systeme. Die große Akzeptanz des relationalen Datenbankmodells ist im Wesentlichen auf zwei Faktoren zurückzuführen: Zum einen verfügt das Modell über sehr einfache Grundlagen, die es erlauben, dem Nutzer eine übersichtliche und doch sehr mächtige Schnittstelle zur Verfügung zu stellen. Zum anderen basiert das Modell auf formal gut zu analysierenden Konzepten, die es in den Jahren nach der Entwicklung seiner Grundlagen vielen Forschern ermöglicht haben, eine umfangreiche Theorie des relationalen Datenbankmodells zu entwickeln und weit reichende Ergebnisse auf dem Gebiet der Datenbankforschung zu erzielen. Im Relationenmodell werden Datenbestände den Nutzern in Form von Tabellen präsentiert. Eine Tabelle entspricht der Darstellung eines Objekttyps der Realität. Die Spalten der Tabelle repräsentieren die Attribute, und jede Zeile der Tabelle entspricht einer Instanz des Objekttyps. Obwohl es nicht dem herkömmlichen Verständnis einer Tabelle entspricht, ist die Reihenfolge von Zeilen und Spalten in Tabellen einer relationalen DB nicht von Bedeutung, sofern die Zuordnung der Attributwerte einer Zeile zu den Attributnamen explizit dargestellt wird (z. B. durch eine Titelzeile mit Spaltenüberschriften). Neben diesen informellen Begriffen für die Grundlagen des Relationenmodells existieren jedoch auch genauere Begriffsdefinitionen: Ein relationales Datenbankschema besteht aus einer Menge von Relationenschemata. Einem Relationenschema R(A1 , . . . , An ) ist eine Menge von Attributen {A1 , . . ., An } zugeordnet. Jedes Attribut Ai (1 ≤ i ≤ n) beschreibt eine von n Eigenschaften eines Objektes und ist über einen Wertebereich dom (Ai ) definiert. Eine Relationr(R) mit Schema R(A1 , . . ., An ) ist eine Menge von n-attributigen Tupeln {t1 , . . . , tm } und jedes Tupel tj (1 ≤ j ≤ m) besteht aus einer Liste von n Werten . Jeder Wert vi (1 ≤ i ≤ n) muss aus dom (Ai ) sein und wird Attributwert genannt. Die Menge der Tupel bezeichnet man auch als Ausprägungsebene der relationalen DB. Relationen sind im mathematischen Sinne Mengen von Tupeln. Aufgrund der Eigenschaften von Mengen darf es in Relationen niemals zwei Tupel mit identischen Attributwerten geben. Um Tupel voneinander unterscheiden und dadurch die Mengeneigenschaft garantieren zu können, muss man Tupel identifizieren. Im Relationenmodell erfolgt dies über das Schlüsselkonzept. Eine Attributmenge SK (SK ⊆ R), die jedes Tupel einer Relation r(R) eindeutig bestimmt, heißt Oberschlüssel (super key) des Relationenschemas R. Für r(R) gilt: ∀ti , tj ∈ r : ti = tj ⇒ ti [SK] = tj [SK] Ist die identifizierende Attributmenge „minimal“, d. h. ein Oberschlüssel, aus dem keine Attribute gestrichen werden können, ohne dass die Schlüsseleigenschaft verloren geht, so handelt
136
3 Konzeptueller Datenbankentwurf
es sich um einen Schlüsselkandidaten K. Für ein Relationenschema kann es mehrere Möglichkeiten für Schlüsselkandidaten geben. Aus der Menge der Schlüsselkandidaten wird ein Schlüssel als Primärschlüssel ausgewählt und durch Unterstreichung der zugehörigen Attribute gekennzeichnet. Alle Attribute, die in einem Schlüsselkandidaten vorkommen, heißen prim, alle anderen nicht prim. Attribute werden in einem Schema Ri als Fremdschlüssel bezeichnet, wenn sie in einem Relationenschema Rj (i = j) Schlüsselkandidaten sind. An die Auswahl eines Primärschlüssels ist eine besondere Integritätsbedingung geknüpft: Primärschlüssel dürfen niemals die Nullmarke annehmen (entity integrity). Aus praktischen Gründen sollten sie außerdem hinsichtlich ihres Speicheraufwandes minimal sein. Wie wir schon festgestellt haben, werden im alltäglichen Sprachgebrauch die Relationen einer relationalen DB oft als Tabellen bezeichnet. Obwohl Ähnlichkeiten bestehen, gibt es zwischen den formalen Begriffen des Relationenmodells und häufig verwendeten informellen Begriffen der Alltagssprache Unterschiede. Ein Beispiel dafür ist die Reihenfolge von Tupeln in Relationen. Da Relationen Tupelmengen (im mathematischen Sinn einer Menge) darstellen und auf Elemente einer Menge keine Reihenfolge definiert ist, ist die Reihenfolge von Tupel einer Relation nicht definiert. Bei Tabellen ist das hingegen anders. Spricht man doch in der Alltagssprache von der ersten Zeile einer Tabelle, von der nächsten Zeile usw. Abbildung 3.34 enthält eine Gegenüberstellung formaler und informeller Begriffe zum Relationenmodell und Abbildung 3.35 ein Beispiel einer einfachen relationalen DB zur Veranschaulichung von Schema- und Ausprägungsebene sowie der unterschiedlichen Schlüsseltypen. Beispiel 3.25: Fuhrpark Fahrzeuge sind Garagen zugeordnet. Jedes Fahrzeug besitzt eine eindeutige Motornummer (Motor#) und ein Kennzeichen. Weitere Eigenschaften von Interesse sind Marke und Modell. Jede Garage wird über ihre Kennung identifiziert, besitzt eine Postanschrift, eine Kapazität und Öffnungszeiten. 3.6.1.1
Eigenschaften von Relationen
In diesem Unterkapitel sollen die Eigenschaften von Relationen nochmals explizit diskutiert werden. Eine Relation besteht aus der Menge der Tupel, die zu einem gegebenen Zeitpunkt zur Relation gehören, variiert also über der Zeit. Die zu einem bestimmten Zeitpunkt gegebene Anzahl von Tupeln einer Relation wird deren Kardinalität genannt. Eindeutigkeit von Tupeln Da Relationen im mathematischen Sinn Mengen darstellen, dürfen sie keine Duplikate enthalten. Deshalb lässt sich jedes Tupel einer Relation eindeutig über seine Attributwerte identifizieren. Als direkte Konsequenz aus dieser Aussage ergibt sich, dass jede Relation mindestens einen Schlüsselkandidaten besitzen muss, weshalb auch immer ein Primärschlüssel festgelegt werden kann. Attributwerte sind atomar Obwohl der mathematische Begriff Relation allgemeiner gefasst ist, wird dieser Begriff in
3.6 Formaler Datenbankentwurf
Abb. 3.34: Formale und informelle Begriffe des Relationenmodells
Abb. 3.35: Beispiel „Fuhrpark“
137
138
3 Konzeptueller Datenbankentwurf
konventionellen relationalen DBMS immer im Sinn einer normalisierten Relation, also einer Relation in erster Normalform, verwendet. Das bedeutet insbesondere, dass der Wertebereich eines jeden Attributes atomar sein muss. Obwohl diese Einschränkung aus mathematischer Sicht nicht notwendig ist und auch die Mächtigkeit des relationalen Datenbankmodells erheblich beschneidet, wurde sie eingeführt, da sie ein Garant für die Einfachheit des Datenbankmodells und der damit verbundenen Anfragesprachen ist. Es sei allerdings angemerkt, dass Vorschläge für neuere Datenbankmodelle, wie zum Beispiel für objektorientierte oder objektrelationale Datenbankmodelle, diese Einschränkung aufheben und auch mengenwertige Attribute zulassen. Keine Ordnung auf Tupeln oder Attributen Ein Relationenschema wird durch eine Menge von Attributen beschrieben, die durch den jeweiligen Wertebereich ergänzt werden. Eine Relation wird durch eine Menge von Tupeln beschrieben. Ein Datenbankschema schließlich besteht aus einer Menge von Relationen(schemata). Im relationalen Datenbankmodell haben wir es also im Wesentlichen mit Mengen zu tun und Mengen sind aus mathematischer Sicht ungeordnet. Daraus folgt direkt, dass weder die Attribute eines Tupels (von links nach rechts) noch die Tupel einer Relation (von oben nach unten) geordnet sind. Ohne zu sehr ins Detail gehen zu wollen, sei bereits hier erwähnt, dass diese Eigenschaften, die ein relationales Datenbankmodell wegen seiner Abstützung auf der Mengentheorie nun einmal auszeichnen, bei existierenden relationalen DBMS bzw. genauer deren Anfragesprachen häufig nicht vollständig gewährleistet werden. In den nachfolgenden Kapiteln wird noch festgestellt werden, dass bestimmte Anfragesprachen (wie z. B. SQL) in Ergebnisrelationen Duplikate zulassen. Aus Gründen des sauberen Sprachgebrauchs werden wir dann von Tabellen anstelle von Relationen sprechen. Auch wird oft unterstellt, dass Attribute geordnet sind und in der Reihenfolge angesprochen werden können, in der sie bei der Definition „ihres“ Relationenschemas angelegt wurden. Während diese Vereinfachung eher noch der Bequemlichkeit dient, ist die erste Tatsache, dass Tabellen auch Duplikate enthalten dürfen, ein offensichtlicher Verstoß gegen die mathematische Mengeneigenschaft. Wie wir noch sehen werden, ist dieser Verstoß wegen der dadurch ausgelösten Aufhebung der Gültigkeit von einigen Gesetzen der Mengentheorie nicht ganz unumstritten. 3.6.1.2
Operationen auf Relationen
Das Relationenmodell beinhaltet eine Reihe von Operationen (Relationenalgebra), mit denen die Informationen aus einer relationalen DB abgefragt werden können. Die Operationen der Relationenalgebra erlauben eine implementationsunabhängige Betrachtung von Datenbankanfragen und umfassen die Mengenoperationen, die Selektion zur Auswahl von Tupeln aus Relationen, die Projektion zur Auswahl bestimmter Attribute und das Kartesische Produkt sowie die Verbundoperation zum Verknüpfen von Relationen. Da einige Verknüpfungsoperationen identische Bezeichner für Attribute fordern, führt man oft einen Umbenennungsoperator ein, der zur Umbenennung von Attributnamen verwendet werden kann. Relationale Operatoren können miteinander verknüpft werden und ihre Anwendung auf Relationen liefert als Ergebnis wieder eine Relation, die unter Verwendung weiterer Operationen weiter verarbeitet werden kann.
3.6 Formaler Datenbankentwurf
139
In diesem Unterkapitel werden wir die implementationsunabhängige Anfragemöglichkeit Relationenalgebra in dem Ausmaß vorstellen, wie es zum Verständnis des formalen Datenbankentwurfs nötig ist. Eine detaillierte Darstellung von Datenbankanfragesprachen erfolgt ab Kapitel 6. Mengenoperationen: Vereinigung, Durchschnitt und Differenz Sind zwei Relationen über ein identisches Schema definiert, so können die Mengenoperationen ∪, ∩ und \ angewendet werden. Für zwei Relationen r(R) und s(R) ist • Vereinigung: r ∪ s = {t|t ∈ r(R) ∨ t ∈ s(R)} • Durchschnitt: r ∩ s = {t|t ∈ r(R) ∧ t ∈ s(R)} • Differenz: r\s = {t|t ∈ r(R) ∧ t ∈ / s(R)} Selektion Unter Verwendung der Selektion werden Tupel, die einem Auswahlkriterium genügen, aus Relationen ausgewählt. Die Selektion σ wählt all jene Tupel t aus einer Relation r(R) aus, die einem Selektionskriterium entsprechen. Dabei ist ein beliebiger Vergleichsoperator θ mit θ ∈ {, ≥, =} zulässig. Selektionskriterien können über boolsche Ausdrücke zu einer komplexen Selektionsbedingung kombiniert werden. Der Ausdruck t[A] bedeutet hierbei die Einschränkung eines Tupels t auf den Wert seines Attributes A. • Selektion:
σAθa r(R) = {t|t ∈ r(R) ∧ t[A]θa}
Projektion Die Projektion πX wählt aus einer Relation r(R) die Attributmenge X (X ⊆ R) aus. Duplikate Tupel in der Ergebnisrelation werden eliminiert. • Projektion:
πX r(R) = {t(X)|t ∈ r(R)} = r(R)[X].
Kartesisches Produkt Durch die Verwendung des Kartesischen Produktes werden zwei Relationen miteinander verknüpft. Das Ergebnis des Kartesischen Produktes r1 (R1 ) × r2 (R2 ) mit R1 ∩ R2 = {} entspricht allen Kombinationen je eines Tupels aus Relation r1 (R1 ) mit einem Tupel aus Relation r2 (R2 ). • Kartesisches Produkt:
r1 (R1 ) × r2 (R2 ) = {t(R1 ∪ R2 )|(t[R1 ] ∈ r1 (R1 )) ∧ (t2 [R2 ] ∈ r2 (R2 ))}.
Soll die Verknüpfung der beiden Relationen über miteinander in Verbindung stehende Tupel geschehen, so kann das über ein kartesisches Produkt und eine nachfolgende Selektion erfolgen oder aber auch unter Verwendung der Verbundoperation. Verbund (join) Die Verbundoperation tritt in mehreren Varianten auf, von denen wir ihrer Bedeutung wegen die zwei am häufigsten verwendeten betrachten wollen.
140
3 Konzeptueller Datenbankentwurf
Thetaverbund (theta join): Verknüpfung zweier Relationen r1 (R1 ) und r2 (R2 ) mit disjunkten Attributmengen (R1 ∩ R2 = {}). B1 ∈ R1 und B2 ∈ R2 sind Attribute mit Wertebereichen, die einen Vergleich mit Hilfe eines Operators θ (θ ∈{, =, =, ≤, ≥}) erlauben. Der Ausdruck [B1 θ B2 ] wird Verknüpfungsbedingung genannt. • Thetaverbund:
r1 [B1 θB2 ]r2 = {t(R1 ∪ R2 )|(t[R1 ] ∈ r1 ) ∧ (t[R2 ] ∈ r2 ) ∧ (t[B1 ]θt[B2 ])}.
Der Thetaverbund kann erweitert werden, indem die Verknüpfungsbedingung aus mehreren Vergleichen zusammengesetzt wird. Ist θ gleich „=“, so bezeichnet man die Verbundoperation als Gleichverbund (equi join). Natürlicher Gleichverbund (natural join): Um zwei Relationen r1 (R1 ) und r2 (R2 ) unter Verwendung des Natürlichen Gleichverbundes verknüpfen zu können, müssen ihre Schemata Attribute enthalten, die den gleichen Bezeichner tragen. Ist das nicht der Fall, so muss unter Verwendung des Umbenennungsoperators die gleiche Bezeichnung erzeugt werden. Die Verknüpfung erfolgt dann auf den in R1 und R2 gemeinsamen Attributen. • Natürlicher Gleichverbund:
r1 r2 = {t(R1 ∪ R2 )|(t[R1 ] ∈ r1 ) ∧ (t[R2 ] ∈ r2 )}.
Der Natürliche Gleichverbund kann auf eine beliebige Anzahl von an der Verbundoperation beteiligten Relationen ausgedehnt werden. Division Die Definition der Division wirkt auf den ersten Blick relativ kompliziert, doch ist gerade die Division eine Operation, die besonders einfache Anfragen an Attribute und Tupel ermöglicht, die bestimmte Eigenschaften bezüglich aller Tupel einer weiteren Relation aufweisen. Für die folgende Betrachtung sind zwei Relationen r1 (R1 ) und r2 (R2 ) mit R1 = X ∪ Y und R2 = Y ∪ Z und mit X ∩ Y = {} und Y ∩Z = {} gegeben. • Division:
r1 ÷ r2 = r (X) = {t(X)|t[R1 ] ∈ r1 (R1 ) und πY r2 (R2 ) ⊆ gr (X)}, mit gr (X) = πY (σX=x (r1 (R1 )).
Für jedes Tupel t(X) in der Relation πX r1 (R1 ) bestimmt man gr (X), die Menge aller diesem X−Wert in r1 (R1 ) zugehörenden Y -Werte. Ist πY r2 (R2 ) ⊆ gr (X), dann ist das Tupel t(X) in der Ergebnismenge r1 ÷ r2 enthalten. Das folgende Beispiel soll die Vorgehensweise bei Anwendung der Division bzw. die Formulierung von Datenbankanfragen unter Verwendung der relationalen Algebra verdeutlichen.
3.6 Formaler Datenbankentwurf
141
Beispiel 3.26: Division r1 ÷ r2 r1
A
B
C
D
a1
b1
c1
a2
b2
a2
r2
C
D
E
d1
c1
d1
e1
c1
d1
c1
d1
e2
b2
c2
d2
c2
d2
e3
a2
b2
c1
d2
a3
b3
c2
d2
Schritt 1: Durchführen der Projektion πX (r1 )
A
B
a1
πY (r2 )
C
D
b1
c1
d1
a2
b2
c2
d2
a3
b3
Schritt 2: Berechnen der Bildmengen gr (X) gr (a1, b1) = {c1, d1} gr (a2, b2) = {c1, d1, c2, d2, c1, d2} gr (a3, b3) = {c2, d2} Schritt 3: Beenden der Division durch Überprüfen der Untermengenbeziehung πy (r2 ) ⊆ gr (X)
r1 ÷ r2
A
B
a2
b2
3.6.2
Grundlagen des formalen Datenbankentwurfs
3.6.2.1
Vorbemerkungen
Bei der Anwendung des formalen Datenbankentwurfs wird das relationale Datenbankmodell sowohl als Ausgangsmodell als auch als Zielmodell des Datenbankentwurfs verwendet. Das Relationenmodell dient somit gleichzeitig als konzeptuelles Datenbankmodell sowie als Implementationsmodell und die Entwurfsphasen „konzeptuelle Modellbildung“ und „logisches Design“ verschmelzen zu einer Einheit. Ziel des formalen Datenbankentwurfs ist es, durch sukzessive Transformation an einem Ausgangsdatenbankschema zu einem „optimalen“ logischen Datenmodell zu gelangen. Dabei können zwei unterschiedliche Vorgehensweisen zur Anwendung kommen. Bei den Syntheseverfahren geht man von den während der Anforderungsanalyse erhobenen Attributen aus, um sie aufgrund ihrer funktionalen Zusammenhänge zu Relationenschemata zu gruppieren. Bei den Dekompensationsverfahren fasst man vorerst
142
3 Konzeptueller Datenbankentwurf
alle Attribute zu einem universellen Relationenschema zusammen, um dieses dann hinsichtlich festgelegter Gütekriterien in Subschemata zu zerlegen. In diesem Unterkapitel werden wir die Notwendigkeit von Strukturierungsmaßnahmen im Relationenmodell motivieren und eine informelle Betrachtung von Gütekriterien für Relationenschemata vornehmen. Eine detailliertere Darstellung der diskutierten Konzepte findet sich in Unterkapitel 3.6.3. Wünschenswerte Eigenschaften einer DB, die durch einen guten Entwurf erreicht werden sollen, lassen sich den drei folgenden Kategorien zuordnen: 1. Der Inhalt der DB soll den abgebildeten Realitätsausschnitt wahrheitsgetreu widerspiegeln. Das bedeutet, dass einerseits alle aufgezeichneten Informationen durch Anwendung von Datenbankanfragen realitätsgetreu hergeleitet werden können und andererseits, dass durch Änderungen an der Datenbasis keine unerwünschten Nebeneffekte auftreten können. 2. Die Integrität der Datenbasis muss gewährleistet werden. Dies erfordert sowohl die Kontrolle auf semantisch sinnvolle Dateneingaben als auch von integritätserhaltenden Änderungsoperationen. 3. Kontrolle der Datenredundanzen und Vermeidung unerwünschter Mehrfachspeicherung. Die gewünschten Eigenschaften lassen sich durch Datenbankschemata zumindest in 3. Normalform (besser noch in Boyce-Codd-Normalform) sowie durch verbund- und abhängigkeitstreue Zerlegungen erreichen. Nach der Einführung des Konzeptes der funktionalen Abhängigkeit zwischen Attributen wollen wir die wichtigsten Normalformen vorstellen. Die Normalformenlehre stellt ein anwendungsunabhängiges Gütekriterium für Relationenschemata dar, das es ermöglicht, eine objektive Bewertung eines relationalen Datenbankschemas vorzunehmen. Sind Daten redundant gespeichert bzw. Relationenschemata in einer ungünstigen Normalform, ergeben sich Probleme (Anomalien) beim Einfügen, Ändern und Löschen in Datenbeständen, die durch Kontrolle der Redundanzen und Transformation der Schemata in eine höhere Normalform vermeidbar sind. 3.6.2.2
Funktionale Abhängigkeiten, Anomalien und Normalformen
Funktionale Abhängigkeiten (functional dependencies) (FD) sind im Relationenmodell die wichtigste Klasse von Einschränkungen. Sie werden verwendet, um die Anzahl der mathematisch möglichen Tupel (Kartesisches Produkt der Attributwertebereiche) auf die Menge der semantisch sinnvollen Tupel einzuschränken. Die funktionale Abhängigkeit X → Y (Sprechweise X bestimmt Y funktional, Y hängt von X funktional ab) gilt im Schema R, falls alle beliebigen Tupel t1 , t2 aus der Relation r(R), die in ihren X-Werten übereinstimmen, auch in ihren Y -Attributen identische Werte aufweisen. Beispiel 3.27: Funktionale Abhängigkeit Die folgenden FD erlauben folgende Interpretationen: Für eine bestimmte Artikelnummer darf es immer nur eine einzige entsprechende Artikelbezeichnung geben. Das Kennzeichen eines Fahrzeuges bestimmt funktional alle anderen Eigenschaften von Fahrzeugen.
3.6 Formaler Datenbankentwurf
143
Gilt diese FD, so sind Wechselkennzeichen ausgeschlossen. Ein bestimmter Student (Matrikel#) kann eine bestimmte Lehrveranstaltung (LV#) nur mit einer einzigen Note abschließen. Artikel# →Artikelbezeichnung Kennzeichen→Fahrzeugtyp, Baujahr, Fahrzeughalter Matrikel# , LV# →Note Mit FD werden Eigenschaften der realen Welt modelliert. Sie sind unabhängig von einer zeitpunktbezogenen Ausprägung einer Relation und daher immer dem Relationenschema zugeordnet. Die einem Relationenschema zugeordneten FD implizieren vielfach weitere funktionale Abhängigkeiten, die über Anwendung eines Axiomensystems (Armstrong-Axiome) hergeleitet werden können. Alle funktionalen Abhängigkeiten eines Schemas (die explizit angegebenen und die implizit abgeleiteten) bilden die Abhängigkeitshülle, für die man eine kanonische Überdeckung mit einer minimalen Anzahl von FD berechnen kann. Alle FD der kanonischen Überdeckung können dann verwendet werden, um für ein Relationenschema die Menge der Schlüsselkandidaten zu berechnen und damit verbunden die jeweils gültige Normalform zu bestimmen. Wir werden in Unterkapitel 3.6.3 auf diese Konzepte genauer eingehen.
Feststellung 3.6: Normalformenlehre FD bilden die Grundlagen für viele theoretische Überlegungen im Relationenmodell. Ein bedeutendes Teilgebiet der relationalen Datenbanktheorie stellt die so genannte Normalformenlehre dar, innerhalb derer Abhängigkeiten zwischen Attributen analysiert werden, um Datenredundanzen als Quelle unerwünschter Anomalien zu lokalisieren. Bevor wir die wichtigsten Normalformen besprechen, werden wir anhand eines Beispiels für ein schlecht entworfenes Datenbankschema typische Datenbankanomalien diskutieren.
Beispiel 3.28: Datenbankanomalien Das Relationenschema „Zuordnung“ aus Abbildung 3.36 beschreibt Informationen über Mitarbeiter, Abteilungen und die Zuordnung von Mitarbeitern zu Abteilungen. An beteiligten Attributen sind M-Name, SVNr, Geb-Dat, ANr, A-Bezeichnung, SVNr-ALeiter von Interesse. Ein Mitarbeiter ist ausschließlich einer Abteilung zugeordnet. Zuordnung ({M-Name, SVNr, Geb-Dat, ANr, A-Bezeichnung, SVNr-ALeiter}, {SVNr→M-Name, Geb-Dat, ANr; ANr→A-Bezeichnung, SVNr-ALeiter})
Das Datenbankschema „Zuordnung“ weist Eigenschaften auf, die bei Anwendung von Einfüge-, Lösch- oder Änderungsoperationen unerwünschte Nebeneffekte verursachen können. Folgende Anomalien gelten in „Zuordnung“:
144
3 Konzeptueller Datenbankentwurf
SVNr
M_Name
Geb-Dat
ANr
A-Bezeichnung
SVNr-ALeiter
AI232452 ZJ343452 DF23452 EE23411
Müller Meier Schmidt Schulz
01.01.1959 30.03.1964 15.06.1968 31.05.1965
1 2 1 3
Einkauf Marketing Einkauf Beschaffung
AI232452 EE23411 AI232452 EE23411
Abb. 3.36: Darstellung der Relation „Zuordnung“
• Einfügeanomalie Eine unerwünschte Tatsache ergibt sich aus der Schlüsseleigenschaft des Attributes „SVNr“. Da die Werte des Primärschlüssels immer bekannt sein müssen (nie die Nullmarke annehmen dürfen), können in eine Relation mit Schema Zuordnung erst Abteilungen eingetragen werden, sofern diesen Abteilungen auch Mitarbeiter zugeordnet sind. • Löschanomalie Gibt es in einer Abteilung nur einen Mitarbeiter und dieser Mitarbeiter verlässt das Unternehmen (wird aus der DB gelöscht), so geht auch die Information verloren, dass in diesem Unternehmen die betrachtete Abteilung existiert. Beispielsweise würde bei einem Ausscheiden des Mitarbeiters Meier auch die Information gelöscht werden, dass im Unternehmen eine Marketingabteilung existiert. • Änderungsanomalie Für alle Mitarbeiter einer bestimmten Abteilung müssen Abteilungsdaten redundant gespeichert werden. Dies führt nicht nur zu einem unnötigen Verbrauch an Speicherplatz, sondern auch zu erheblichem Mehraufwand für die Konsistenzerhaltung bei Änderungen. Ändern sich Daten einer Abteilung, so müssen diese Änderungen für jeden Mitarbeiter dieser Abteilung redundant durchgeführt werden. Normalformen stellen ein Meßverfahren für die Qualität und Güte eines Relationenschemas dar. Sie helfen, Anomalien zu entdecken und damit Redundanzen zu vermeiden. In den Jahren seit der Entwicklung des relationalen Datenbankmodells wurden verschiedene Typen von Normalformen entwickelt, die unterschiedliche praktische Relevanz aufweisen. Wir werden uns auf die Darstellung der ersten drei Normalformen und der BCNF (Boyce-Codd-Normalform) beschränken, die alle auf der Analyse funktionaler Abhängigkeiten beruhen. • Erste Normalform (1NF) Die Wertebereiche aller Attribute des Relationenschemas müssen atomar sein. Die 1NF verlangt, dass alle Attributwerte aus einem unstrukturierten Wertebereich stammen. Mengen, Aufzähltypen, Wiederholungsgruppen oder komplex strukturierte Wertebereiche sind nicht zugelassen. • Zweite Normalform (2NF) Nicht prime Attribute müssen vom ganzen Schlüssel funktional abhängen.
3.6 Formaler Datenbankentwurf
145
Die 2NF bedeutet, dass es keine Teilmenge eines Schlüsselkandidaten geben darf, die ein nicht primes Attribut funktional bestimmt. Um die 2NF überprüfen zu können, muss man zuvor alle Schlüsselkandidaten ermitteln, denn nur Attribute, die in keinem Schlüsselkandidaten enthalten sind, können die 2NF verletzen. • Dritte Normalform (3NF) Nicht prime Attribute dürfen nur direkt von einem Schlüssel abhängen. Die 3NF setzt 2NF voraus und fordert zusätzlich, dass zwischen einem nicht primen Attribut und einem Schlüsselkandidaten keine transitive funktionale Abhängigkeit (siehe 3.6.3.1) existieren darf. • Boyce-Codd-Normalform (BCNF) Jede FD muss links einen Oberschlüssel haben. BCNF setzt 3NF voraus. Sie ist die einzige Normalform, die durch gültige FD und nicht durch nicht prime Attribute verletzt werden kann. In Relationenschemata in BCNF gibt es keine nennenswerten Anomalien mehr. Ist ein Relationenschema nicht in zumindest 3NF, so sollte es in Teilschemata zerlegt werden, die dem 3NF-Kriterium genügen. An eine solche Zerlegung sind zwei Bedingungen geknüpft: Abhängigkeits- und Verbundtreue. Eine Zerlegung ist abhängigkeitstreu, sofern keine FD durch die Zerlegung verloren gegangen ist. Sie ist verbundtreu, sofern durch Anwendung der Verbundoperation auf die Teilrelationen die Ausgangsrelation wieder erzeugt werden kann. Verbundtreue ist eine wichtige Bedingung, um den konsistenten Zustand der DB zu bewahren. Ist eine verbundtreue Zerlegung nicht gegeben, liefert die DB falsche Abfrageergebnisse. Das folgende Beispiel zeigt die Verletzung von Verbundtreue und daraus resultierend für eine Datenbankanfrage zusätzliche künstliche Tupel, die in der Ausgangsrelation nicht enthalten waren. Beispiel 3.29: Verletzung der Verbundtreue r
A
B
C
1 1 2
1 2 1
1 2 2
πAB (r)
πBC (r)
A
B
1 1 2
1 2 1
πAB (r) πBC (r)
A
B
C
1 1 1 2 2
1 1 2 1 1
1 2 2 1 2
B
C
1 2 1
1 2 2
Es gibt Algorithmen, mit denen man jedes Relationenschema in abhängigkeits- und verbundtreue Teilschemata in zumindest 3NF zerlegen kann. BCNF kann nicht immer aber doch
146
3 Konzeptueller Datenbankentwurf
Abb. 3.37: DB-Normalisierungsvorgang
in den meisten Fällen erreicht werden. Abbildung 3.37 zeigt den Vorgang der Normalisierung anhand zweier Beispiele von Ausgangsrelationen in 1NF bzw. in 2NF. Die Pfeilrichtung weist auf die Gültigkeit einer funktionalen Abhängigkeit hin.
Beispiel 3.30: 1NF in BCNF Betrachtet wird eine Zuordnung von Mitarbeitern zu Projekten. Von Interesse ist dabei die Projektnummer (P_Nr), die Projektbezeichnung (P-Bez), der Ort, an dem das Projekt durchgeführt wird (P_Ort), der Name des Mitarbeiters (M_Name), seine Sozialversicherungsnummer (SVNr) und die Anzahl der Stunden, die der Mitarbeiter im Projekt tätig ist. Das in Abbildung 3.37 dargestellte Relationenschema Mitarbeiter_Projekt ist in 1NF und wird in BCNF transformiert.
3.6 Formaler Datenbankentwurf
147
Beispiel 3.31: Normalisierung 2NF in BCNF Betrachtet wird die Zuordnung von Mitarbeitern zu Abteilungen. Von Interesse ist dabei die Abteilungsnummer (A_Nr), die Abteilungsbezeichnung (A-Bez), der Name des Abteilungsleiters (A-Leiter), das Geburtsdatum (Geb-Datum), der Name des Mitarbeiters (M_Name) und seine Sozialversicherungsnummer (SVNr). Das Schema Mitarbeiter_Abteilung aus Abbildung 3.37 ist in 2NF und wird in BCNF transformiert.
3.6.3
Relationentheorie und Normalisierung
Abhängigkeiten zwischen Attributen sind Einschränkungen, die die Grundlage vieler theoretischer Überlegungen im Relationenmodell bilden. Um die erhobenen Einschränkungen in das Datenmodell aufnehmen zu können, ist es notwendig, die bisher verwendete Definition eines Relationenschemas R(A1 , . . ., An ) zu erweitern. Gegeben sei eine Einschränkung e = X, p mit einem logischen Prädikat p, das auf die Attributmenge X definiert ist. Eine Relation r(R) erfüllt e, falls X ⊆ R und die Projektion r(R) [X] die Einschränkung e erfüllt, d. h. dass die Auswertung von p bezüglich r(R) [X] den logischen Wert „wahr“ ergibt. Nimmt man alle Einschränkungen auf, so ergibt sich ein Relationenschema RS(S;E) mit S einer Attributmenge und E = {e1 , . . ., en } einer Einschränkungsmenge mit ei = Xi , pi und Xi ⊆ S(i = 1. . .n). Eine Relation r(S), die alle ei ∈ E erfüllt, heißt gültige Ausprägung oder Zustand von RS(S;E). Nachdem nun Einschränkungen als Teil des Relationenschemas betrachtet werden können, wollen wir zwei für die weiteren Überlegungen wichtige Klassen von Einschränkungen aus E genauer analysieren. Definition 3.1: Funktionale Abhängigkeit Sei RS(S;E) ein Relationenschema und X, Y mit X ∪ Y ⊆ S zwei Attributmengen. Eine funktionale Abhängigkeit f : X → Y in RS(S;E) ist eine Einschränkung f = S, für je zwei Tupel ti , tj ∈ r(S) gilt: ti [X] = tj [X] ⇒ ti [Y ] = tj [Y ] . Das bedeutet, die FD X → Y ist in RS(S;E), wenn in jeder gültigen Ausprägung r(S) mit diesem Schema niemals zwei Tupel existieren können, die in ihren X-Werten, nicht jedoch aber in ihren Y -Werten übereinstimmen. Man beachte jedoch, FD sind dem Relationenschema zugeordnet und können daher nicht aus gegebenen Relationen abgeleitet werden. Aus der Definition von funktionalen Abhängigkeiten sind zwei Bedingungen ersichtlich: Es gilt für f : X → Y , dass σX=x r(S)[Y ] = {y} und |σX=x r(S)[Y ]| = 1. Einige FD heißen trivial, da sie in jedem Relationenschema gelten. Beispielsweise gilt X → Y mit Y ⊆ X in jedem Schema, das die Attributmenge X enthält. Eine FD X → Y heißt nicht trivial, sofern X\Y = {}, Y = {} und Y ⊂ X. Definition 3.2: Mehrwertige Abhängigkeit Sei RS(S;E) ein Relationenschema und X, Y mit X ∪ Y ⊆ S und Z mit Z = S\(X ∪ Y ) drei Attributmengen. Eine mehrwertige Abhängigkeit m: X →→ Y (X bestimmt Y
148
3 Konzeptueller Datenbankentwurf
mehrwertig) der Attributmenge X und Y in RS(S;E) ist eine Einschränkung m = S, für jeden X-Wert x und Z-Wert z gilt: σX=x r(S)[Y ] = σ(X=x)∧(Z=z) r(S)[Y ] . Die mehrwertige Abhängigkeit (multivalued dependency, MVD) X →→ Y ist in RS(S;E), wenn in jeder gültigen Ausprägung r(S) mit Schema RS(S;E) für jeweils zwei Tupel mit identischer „linken“ Seite X ein drittes Tupel existiert, das sich aus X, der „rechten“ Attributmenge Y aus dem ersten Tupel und der verbleibenden Attributmenge Z aus dem zweiten Tupel zusammensetzt. MVDs sind kontext-sensitiv. Das bedeutet, sie beziehen sich auf ein bestimmtes Schema. Ändert sich das Schema (und somit die Attributmenge Z), so verliert die MVD X →→ Y ihre Gültigkeit. Beispiel 3.32: Mehrwertige Abhängigkeit Es ist zu überprüfen, ob im nachfolgenden Relationenschema die MVD m gilt.
Die MVD X →→ Y mit X ∪ Y = S gilt in jedem Schema RS(S;E) und wird daher als trivial bezeichnet. MVDs sind schwächere Einschränkungen als FD. Gilt eine FD, so folgt daraus eine entsprechende MVD (X → Y ⇒ X →→ Y ). 3.6.3.1
Inferenzregeln für FD
Bei Anwendung der Methode des formalen Datenbankentwurfs ist es notwendig, alle funktionalen Abhängigkeiten zu erheben und in das Relationenschema aufzunehmen. Typischerweise wird der Designer so vorgehen, dass er mit den offensichtlich existenten FD beginnt, um aus ihnen alle weiteren existierenden FD abzuleiten. In der weiteren Folge betrachten wir ausschließlich Einschränkungen vom Typ FD, die wir in einer Abhängigkeitsmenge F zusammenfassen. Solche Abhängigkeitsmengen sind von großer Bedeutung, da sie die Grundlage
3.6 Formaler Datenbankentwurf
149
zum Auffinden von Schlüsselkandidaten, zur Bestimmung der Normalform und für die Entwicklung eines günstigen Datenbankschemas darstellen. Die Hülle F + einer Abhängigkeitsmenge F eines Schemas RS(S;F ) beinhaltet alle FD, die entweder bereits in F enthalten sind oder aus den FD aus F abgeleitet werden können (F + = {f |F ⇒ f }). Die Hülle X + einer Menge von Attributen X ⊆ S bezüglich F ist die Menge aller Attribute A, so dass X → A aus F + ist (X + = {A|(X → A) ∈ F + }). Um eine systematische Form der Ableitung zu ermöglichen, können die Armstrong-Axiome [Arms74], ein Axiomensystem, das nach seinem Erfinder benannte wurde, zur Berechnung von F + zur Anwendung kommen. Axiomensystem nach Armstrong: Es sei RS(S;F ) ein Relationenschema und W, X, Y, Z ⊆ S. FD(1): Reflexivität: Y ⊆X ⇒X→Y FD(2): Erweiterung: X → Y und Z ⊆ W ⇒ XW → Y Z FD(3): Transitivität: X → Y ∧Y → Z ⇒ X → Z Die Axiome FD1 bis FD3 sind korrekt (sound), d. h. sie leiten von F nur wirklich gültige FD ab. Sie sind auch vollständig (complete), d. h. sie erzeugen bei wiederholter Anwendung alle von F implizierten FD. Aus den Armstrong-Axiomen können die folgenden weiteren nützlichen Abteilungsregeln hergeleitet werden: FD(4): FD(5): FD(6):
Vereinigung: X → Y und X → Z ⇒ X → Y Z Pseudotransitivität: X → Y und W Y → Z ⇒ W X → Z Zerlegung: X → Y Z ⇒ X → Y und X → Z
Bei praktischen Aufgabestellungen wird sich die Frage stellen, ob eine in der Realität existente FD X → Y bereits durch bestehende Abhängigkeiten in F ausgedrückt werden kann oder ob es notwendig ist, F um X → Y zu erweitern. Eine intuitive Vorgehensweise wäre F + unter Anwendung der Armstrong-Axiome zu berechnen und danach zu überprüfen, ob X → Y ∈ F + ist. Diese Vorgehensweise erscheint einleuchtend, hat aber den Nachteil, dass die Berechnung von F + sehr aufwändig ist. Ein schnelleres Verfahren ist, die Hülle X + der Attributmenge X bezüglich F zu berechnen und danach zu überprüfen, ob Y ⊆ X + gilt. Ist dies der Fall, wird X → Y durch die Abhängigkeiten aus F impliziert (X → Y ∈ F + ) und die FD braucht nicht mehr in F aufgenommen zu werden. Algorithmus MEMBERSHIP (F , X → Y ) kann zur Anwendung kommen, um festzustellen, ob X → Y ∈ F + gilt oder nicht. Algorithmus CLOSURE (X, F ) Input: eine Attributmenge X und eine Menge F von FD. Output: X + bezüglich F . CLOSURE (X, F ) BEGIN old := {}; NEW := X; WHILE new = old DO BEGIN old := new ; FOR EACH FD W → Z ∈ F DO IF new ⊇ W THEN new := new ∪Z ; END; RETURN (new) ; END
150
3 Konzeptueller Datenbankentwurf
Algorithmus MEMBERSHIP (F , X → Y ) Input: eine Menge F von FD und eine FD X → Y . Output: TRUE falls F ⇒ X → Y , FALSE sonst. MEMBER (F , X → Y ) BEGIN IF Y ⊆ CLOSURE (X, F ) THEN RETURN (TRUE) ELSE RETURN (FALSE) END Das folgende Beispiel soll den Begriff einer Abhängigkeitsmenge verdeutlichen und die Anwendung des Membershipalgorithmus illustrieren. Beispiel 3.33: Membershipproblem Sei RS(S;F ) ein Relationenschema mit S = {A, B, C} und F = {AB→ C}. Unter Anwendung der Armstrong-Axiome soll die Hülle F + errechnet werden. Mit Hilfe des Membershipalgorithmus soll geprüft werden, ob AB→AC ∈ F + gilt. F + (S) = A → A, B → B, C → C AB→AB, AB→A, AB→B BC → BC, BC → B, BC → C AC → AC, AC → A, AC → C ABC → ABC, ABC → AB, ABC → AC ABC → BC, ABC → A, ABC → B, ABC → C AB → C, AB → AC, AB → BC, AB → ABC Aufgrund der FD(1) ergeben sich vorerst die 19 trivialen FD. AB→ C ist bereits in F enthalten. Wendet man auf AB→ C FD(2) an, so kann um A erweitert und AB→AC abgeleitet werden. Wird um B erweitert, so kann AB→BC hergeleitet werden. Erweitert man um AB, so folgt schließlich AB→ABC. Der Membershipalgorithmus liefert (AB)+ = {ABC} und da AC ⊆ ABC ist, folgt AB→AC ∈ F + . Armstrong-Axiome und Membershipalgorithmus können auch verwendet werden, um die Schlüsseleigenschaft (siehe Definition 3.6) zu prüfen. Beispiel 3.34: Überprüfung der Schlüsseleigenschaft RS(S;F ) mit S = {A, B, C, D} und F = {A → D, B → C} sei gegeben. Es soll geprüft werden, ob AB ein Schlüssel für RS ist, d. h. ob {AB}+ = S gilt. 1. 2. 3. 4. 5.
A→D AB → ABD B→C ABD → ABCD AB → ABCD
gegeben FD(2): Erweiterung von 1. um AB gegeben FD(2) Erweiterung von 3. um ABD FD(3) angewendet auf 2. und 4.
3.6 Formaler Datenbankentwurf
151
Ähnlich wie für funktionale Abhängigkeiten gibt es auch für mehrwertige Abhängigkeiten Ableitungsregeln, die angewendet werden können, um aus einer Menge von bestehenden MVDs weitere MVDs herleiten zu können. Des Weiteren gibt es „gemeinsame“ Ableitungsregeln aus denen folgt, dass aus der Kombination von FD und MVDs weitere FD folgen. Um aus einer Einschränkungsmenge bestehend aus FD und MVDs die Hülle aller FD zu ermitteln, müsste man demzufolge zuerst die Armstrong-Axiome anwenden, danach die Hülle aller MVDs berechnen und schlussendlich noch überprüfen, ob aus der Kombination der bisher ermittelten FD und MVDs noch weitere FD folgen. Ist dies der Fall, so müsste die bisher ermittelte Hülle noch um diese FD erweitert werden. 3.6.3.2
Minimale Überdeckungen
Mengen funktionaler Abhängigkeiten bilden die Grundlage für die Entwicklung von Relationenschemata, die nur geringe bzw. kontrollierte Redundanz und unwesentliche Datenbankanomalien aufweisen. Eine der Bedingungen an „gute“ Abhängigkeitsmengen ist Minimalität, d. h. die Abhängigkeitsmenge darf keine redundanten FD enthalten und für jede FD muss gelten, dass sie aus einer minimalen Anzahl involvierter Attribute besteht. Definition 3.3: Äquivalente Abhängigkeitsmengen Zwei Mengen funktionaler Abhängigkeiten F und G sind äquivalent (F ≡ G), wenn F + = G+ gilt. Äquivalenz kann geprüft werden, indem für alle g ∈ G : F ⇒ g und für alle f ∈ F : G ⇒ f ermittelt wird. Sind F und G äquivalent, so heißt G Überdeckung (cover) von F und umgekehrt. Zur Überprüfung der Äquivalenz kann man sowohl die Armstrong-Axiome als auch den Membershipalgorithmus einsetzen. Definition 3.4: Minimale Überdeckungen F1 heißt minimale Überdeckung von F , wenn F1 zu F äquivalent ist und eine Teilmenge von F1 diese Eigenschaft nicht aufweist. Um eine minimale Überdeckung einer Abhängigkeitsmenge zu ermitteln, wird man versuchen, redundante Abhängigkeiten bzw. unnötige Attribute zu eruieren und aus F zu streichen. Abhängig davon, welche Abhängigkeit redundanter FD man streicht, kann es für ein bestimmtes F mehrere unterschiedliche kanonische Überdeckungen geben, u. U. auch mit einer verschiedenen Anzahl von FD und involvierten Attributen. Enthält F eine nicht redundante Menge an FD bzw. nur FD ohne unnötige Attribute, dann kann kein Element aus F gestrichen werden, ohne dass sich die Hülle F + von F ändert. Zur Bestimmung minimaler Überdeckungen kann wieder auf die Armstrong-Axiome bzw. auf den Membershipalgorithmus zurückgegriffen werden. Algorithmus NONRED (F) entfernt aus F redundante FD und Algorithmus REDUCE (G) entfernt überflüssige Attribute aus FD. Ist die Abhängigkeitsmenge in kanonischer Form, d. h. die rechte Seite jeder FD besteht aus einem einzigen Attribut, dann ersetzt NONRED (F) den Algorithmus RIGHTRED (G).
152
3 Konzeptueller Datenbankentwurf
Algorithmus NONRED (F) Input: eine Abhängigkeitsmenge F . Output: eine nicht redundante Abhängigkeitsmenge F ’. NONRED(F) BEGIN FOR EACH FD X → Y DO IF MEMBER (F \X → Y , X → Y ) DO F = F \X → Y ; RETURN (F ) ; END Algorithmus REDUCE (G) Input: eine Menge G von FD Output: eine minimale Überdeckung von G REDUCE (G) BEGIN F := RIGHTRED (LEFTRED) (G) lösche alle FD der Form X →{} aus F ; RETURN (F ); END Algorithmus LEFTRED (G) Input: eine Menge G von FD Output: eine linksreduzierte Überdeckung F von G LEFTRED (G) BEGIN F := G FOR EACH FD X → Y ∈ G DO FOR EACH attribute A ∈ X DO IF MEMBER (F , (X\A) → Y ) THEN lösche A aus X in X → Y in F ; RETURN (F ) END Algorithmus RIGHTRED (G) Input: eine Menge G von FD Output: eine rechtsreduzierte Überdeckung F von G RIGHTRED (G) BEGIN F := G FOR EACH FD X → Y ∈ G DO FOR EACH attribute A ∈ Y DO IF MEMBER (F \{X → Y }∪{X → (Y \A)}, X → A) THEN lösche A aus Y in X → Y in F ; RETURN (F ) END
3.6 Formaler Datenbankentwurf
153
Definition 3.5: Reduzierte funktionale Abhängigkeiten, voll funktionale Abhängigkeiten Sei F eine Menge von Abhängigkeiten über einem Schema RS(S;F ) und X → Y ∈ F . a. X → Y heißt links reduzierbar, wenn es ein X’⊂ X gibt, so dass X’→ Y ∈ F + . b. X → Y heißt rechts reduzierbar, wenn es ein Y ’⊂ Y gibt, so dass X → Y ’∈ F + . c. Eine FD X → Y heißt reduziert, wenn sie links und rechts reduziert ist und Y ={}. d. Eine links reduzierte Abhängigkeit heißt voll funktionale Abhängigkeit.
Beispiel 3.35: Minimale Überdeckung Gegeben ist F = {A → BC, BCD → E, B → CD, ABD → E}. Es soll eine minimale Überdeckung entwickelt und gezeigt werden, dass die Lösung mitF äquivalent ist. Schritt 1: links reduzieren 1. A → BC 2. B → E ⇒ B → E, da B → CD bereits in F ist. 3. B → CD 4. AD → E ⇒ AD → E, da A → B bereits in F ist. Schritt 2: rechts reduzieren, Streichen von Redundanzen 1. A → B ⇒ A → B, da aus A → B und B → C (aus 3.) A → C bereits folgt. 2. B → E 3. B → C, B → D 4. AD → E fällt weg, da A → B (aus 1.) und B → E (aus 2.) AD → E bestimmen. F = {A → B, B → CDE} ist eine minimale Überdeckung von F . F ≡ F gilt, da A → B und B → CD aus F ’ direkt in F enthalten sind. B → E aus F ’ kann in F folgendermassen hergeleitet werden: B →CD (gegeben), daraus folgt aus FD(2) und Erweiterung um B: B →BCD. BCD→ E ist gegeben. B → BCD ∧BCD → E ⇒ B → E. Das bedeutet, alle FD aus F ’ sind in der Hülle von F enthalten. Auch der umgekehrte Fall gilt, wie folgende Ableitungen zeigen: • • • •
A → BC: BCD → E: B → CD: ABD → E:
A → B ∧ B → C ⇒ A → BC B → E ⇒ BCD → E in F’ direkt enthalten A→B∧B →E ⇒A→E A → E ⇒ ABD → E
(FD(3) + FD(4)) (FD(2)) (FD(3)) (FD(2))
154
3 Konzeptueller Datenbankentwurf
Im Zuge des Entwurfs eines optimalen Datenbankschemas sollte jede Abhängigkeitsmenge durch ihre kanonische Überdeckung ersetzt werden. Ist das nicht der Fall, führen die weiteren Entwurfsschritte unvermeidbar zu Datenredundanzen. Der nächste Entwurfsschritt besteht aus der Ermittlung aller Schlüsselkandidaten. Definition 3.6: Schlüssel Sei RS(S;F ) ein Relationenschema, dann ist X ⊆ S ein superkey (Oberschlüssel) für das Schema RS, falls X → S ∈ F + . Sei X → S ∈ F + , dann ist X ein key (oder candidate key) von RS, wenn kein X’⊂ X existiert, mit X’→ S. Ist X key, dann heißt X → S key dependency. Eine systematische Vorgehensweise zur Berechnung aller Schlüsselkandidaten kann in die folgenden Bearbeitungsschritte gegliedert werden: Gegeben ist RS(S;F ), S mit n Attributen. 1. Bilde alle Teilmengen X von S mit n − 1 Attributen. Überprüfe für jedes X: X → S. Ist das der Fall, ist X ein Oberschlüssel, ansonsten ein Nichtschlüssel. 2. In den weiteren i Schritten werden alle Teilmengen X von S mit (n − i) Attributen, die Teilmenge eines Oberschlüssels, aber nicht Teilmenge eines Nichtschlüssels sind, gebildet. 3. Generiere alle Schichten bis n, solange Oberschlüssel vorhanden sind. 4. Schlüsselkandidaten sind alle Attributmengen K, die selbst Oberschlüssel sind und für die gilt, dass keine Teilmenge Oberschlüssel ist. Diese systematische Vorgehensweise ist zwar zielführend – es werden alle Schlüsselkandidaten gefunden – doch auch extrem zeitaufwändig. Für kleinere Aufgabenstellungen empfiehlt sich eine intuitive Vorgehensweise, die anhand des nachfolgenden Beispiels erläutert werden soll. Beispiel 3.36: Ermittlung von Schlüsselkandidaten RS({A, B, C, D, E}; {A → BC, BC → A, BCD → E, E → C}) ist gegeben. Gesucht sind alle Schlüsselkandidaten. Eine erste Analyse der Abhängigkeitsmenge zeigt, dass BCD eventuell ein guter Startpunkt für einen Schlüssel sein könnte, da in die FD BCD → E sehr viele Attribute + des Schemas involviert sind. {BCD} ergibt alle Attribute und somit ist BCD zumindest Oberschlüssel. Wir müssen uns nun die Frage stellen, ob aus BCD Attribute gestrichen werden können, ohne dass die Schlüsseleigenschaft verloren geht? Das können nur Attribute sein, die in einer FD rechts vorkommen. Anderenfalls sind die Attribute sicher Teil eines Schlüssels. In unserem Fall sind somit nur {BC} zu prüfen. Da weder D+ , {BD}+ noch {CD}+ alle Attribute des Schemas erzeugen, ist BCD der erste gefundene Schlüsselkandidat. Im nächsten Schritt werden für den gefundenen Schlüsselkandidaten alle Teilmengen gebildet, die in FD rechts vorkommen, und durch die linke Seite dieser FD
3.6 Formaler Datenbankentwurf
155
ersetzt. In unserem Fall sind das BC und C, die durch A und E im Schlüsselkandidaten ersetzt werden. Durch diese Vorgehensweise ergeben sich zwei weitere Schlüsselkandidaten AD und BDE. Auch für die neu hinzugekommenen Schlüssel muss man nach Ersetzungsmöglichkeiten suchen. In unserem Beispiel lassen sich keine weiteren Ersetzungen finden und BCD, AD, BDE sind somit alle Schlüsselkandidaten. 3.6.3.3
Normalformenlehre und Normalisierung
Ist eine minimale Überdeckung entwickelt, und sind alle Schlüsselkandidaten bekannt, so kann mit der Bestimmung der gültigen Normalform begonnen werden. Definition 3.7: Erste Normalform Ein Relationenschema RS({A1 , . . ., An }; {F }) ist in 1NF, falls dom(Ai )(i = 1..n) atomar ist. Definition 3.8: Zweite Normalform Ein 1NF-Relationenschema RS(S;F ) ist in 2NF, falls jedes nicht prime Attribut aus S von jedem Schlüssel von RS voll funktional abhängig ist. Das Schema aus Beispiel 3.34 befindet sich beispielsweise nicht in 2NF, da eine Teilmenge des Schlüssels ein nicht primes Attribut funktional bestimmt. Definition 3.9: Strikte transitive Abhängigkeit Sei X, Y ⊆ S und A ein Attribut aus S. Attribut A ist von X über Y strikt transitiv abhängig, falls folgendes gilt: X → Y , Y ¬ → X, Y→ A, A ∈ / XY. Definition 3.10: Dritte Normalform Ein 1NF-Relationenschema RS(S;F ) ist in 3NF, falls kein nicht primes Attribut strikt transitiv vom Schlüssel abhängt. Das Schema aus Beispiel 3.36 befindet sich in 3NF. Dies kann sehr rasch festgestellt werden, da es in dem Schema ausschließlich prime Attribute gibt. Definition 3.11: Boyce-Codd-Normalform Ein 1NF-Relationenschema RS(S;F ) ist in BCNF, falls für jedes Y ⊆ S und für jedes Attribut A ∈ S\Y gilt: Y → A ⇒ Y → S. Das Schema aus Beispiel 3.36 befindet sich nicht in BCNF, da funktionale Abhängigkeiten existieren, die links keinen Oberschlüssel haben. Definition 3.12: Vierte Normalform Ein 1NF-Relationenschema RS(S;F ) ist in 4NF, falls für jede MVD der Form X →→ Y gilt: X →→ Y ist trivial oder X ist Oberschlüssel von RS.
156
3 Konzeptueller Datenbankentwurf
In der Literatur werden noch weitere höhere Normalformen diskutiert, die jedoch wegen mangelnder praktischer Relevanz in diesem Buch nicht behandelt werden sollen. Es kann gezeigt werden, dass höhere Normalformen alle niedrigeren Normalformen voraussetzen und dass ein Schema, das eine niedrige Normalform nicht erfüllt, keine höhere Normalform erfüllen kann. Die Überprüfung der jeweils gültigen Normalform soll nun anhand einiger Beispiele veranschaulicht werden. Beispiel 3.37: Bestimmung der Normalform Wir betrachten das Relationenschema RS(S; F ) mit S = {A, B, C, D, E} und F = {A → BC, BCD → E, B → CD, ABD → E} aus Beispiel 3.35. Da weniger Attribute und FD involviert sind, empfiehlt es sich, vorerst eine minimale Überdeckung von F zu entwickeln. Für dieses Beispiel ist dies bereits mit F = {A → B, B → CDE} in Beispiel 3.35 geschehen. Der einzige Schlüsselkandidat des Schemas ist AB. Die nicht primen Attribute CDE hängen von einer Teilmenge eines Schlüsselkandidaten ab. Das bedeutet, das Schema verletzt bereits die 2NF-Bedingung.
Beispiel 3.38: Bestimmung der Normalform Gegeben sei RS(S;F ) mit S = {A, B, C, D, E} und F = {AB → CE, E → AB, C → D}. Eine erste Überprüfung ergibt, dass F bereits minimal ist und AB, E die Schlüsselkandidaten des Schemas darstellen. Daraus folgt, dass die Attribute CD nicht prim sind. Da weder C noch D von einer Teilmenge eines Schlüsselkandidaten abhängen, befindet sich RS(S;F ) in 2NF. 3NF ist nicht gegeben, da das nicht prime Attribut D strikt transitiv funktional vom Schlüsselkandidaten AB abhängt.
Beispiel 3.39: Bestimmung der Normalform Gegeben sei RS(S;F ) mit S = {A, B, C, D} und F = {AC → BD, D → A, CD → A}. F kann in eine minimale Überdeckung F ‘= {AC→BD, D → A} transformiert werden. Danach werden die Schlüsselkandidaten AC und CD ermittelt. B ist das einzige nicht prime Attribut. Das Schema RS(S;F ) ist in 2NF, da B ausschließlich voll funktional von Schlüsselkandidaten abhängt. Es ist in 3NF, da B von keinem Schlüsselkandidaten strikt transitiv abhängt. Das Schema ist nicht in BCNF, da die funktionale Abhängigkeit D → A keine key dependency darstellt. Es wurde bereits mehrfach darauf hingewiesen, dass Normalformen ein Messverfahren für die Güte und Qualität eines Relationenschemas darstellen. Sie helfen, verdeckte Anomalien und Redundanzen in der Entwurfsphase zu vermeiden, deren Existenz beim späteren Einsatz der DB zu ungewollten Nebeneffekten führen kann. Es gibt Algorithmen, mit denen man jedes Relationenschema in abhängigkeits- und verbundtreue 3NF-Fragmente zerlegen kann. In vielen Fällen liefern diese Verfahren auch Teilschemata in BCNF.
3.6 Formaler Datenbankentwurf
157
Der Vorgang der Normalisierung führt ein Ausgangsschema (Universalrelationenschema) mit ungünstigen Eigenschaften in Fragmente höherer Normalform über. Dabei ist zu beachten, dass die Anzahl der Fragmente klein gehalten werden muss, da zur Erzeugung der globalen Sicht die Anwendung rechenintensiver Verbundoperationen notwendig wird. In praktischen Anwendungen ist daher oft zwischen zwei möglichen Designalternativen abzuwägen: Die erste Alternative wäre, keine Transformation vorzunehmen und mit den bekannten Anomalien zu leben. Dies wird insbesondere dann sinnvoll sein, wenn z. B. im Falle einer Updateoperation die verursachende Änderung nie oder nur äußerst selten vorkommt. Wird diese Alternative gewählt, so ist es jedoch unbedingt notwendig, alle Anomalien zu kennen, um in der Anwendung Maßnahmen vorsehen zu können, die die unerwünschten Nebeneffekte vermeiden. Die zweite Alternative wäre mit der Normalisierung fortzufahren und eine Zerlegung des Ausgangsschemas in Fragmente einer höheren Normalform vorzunehmen. Diese Designalternative ist zu wählen, wenn die bestehenden Anomalien große Auswirkungen haben bzw. Daten in Fragmenten meistens unabhängig voneinander abgefragt werden. Für eine Zerlegung eines Ausgangsschemas in Fragmente höherer Ordnung muss gewährleistet werden, dass die Semantik des Ausgangsschemas in den Fragmenten erhalten bleibt und kein Informationsverlust stattfindet. Neben dem Kriterium der Minimalität muss bei einer gültigen Zerlegung von RS(S;F ) in eine Menge von RSi (Xi ;Fi ) die Aufteilung von S in die einzelnen Xi und der Ableitung geeigneter Fi aus F Abhängigkeits- und Verbundtreue gewährleistet werden. Definition 3.13: Gültige Zerlegung Eine Zerlegung von RS(S;F ) in {RSi (Xi ; Fi )}(i = 1..n) ist gültig, wenn •
n
Xi = S (attributerhaltende Zerlegung)
i=1
• (
n
Fi )+ (S) ≡ F + (S) (abhängigkeitstreue Zerlegung)
i=1
• jede Relation r(S) mit Schema RS(S;F ) und Zerlegung {RSi (Xi ;Fi )} (i = 1..n) ern füllt die Bedingung ri (Xi ) = r(S) (verbundtreue Zerlegung) i=1
Beispiel 3.40 zeigt Zerlegungen, die a) Abhängigkeitstreue bzw. b) Verbundtreue verletzen. Der nachfolgend dargestellte Algorithmus NORMALIZATION (RS(S;F )) erzeugt eine verbund- und abhängigkeitstreue Zerlegung eines Ausgangsschemas in Fragmente in zumindest 3NF. Beispiel 3.40: Verletzung von Abhängigkeits- und Verbundtreue a. RS ({A B C D E}; {A → BCD, CD → E, AE → B}) wird zerlegt in: RS1 ({A B C D}; {A → BCD}) und RS2 ({C D E}; {CD→E}) b. RS ({A B C D}; {A → B, C → D}) wird zerlegt in: RS1 ({A B}; {A → B}) und RS2 ({C D}; {C → D})
158
3 Konzeptueller Datenbankentwurf
Algorithmus NORMALIZATION (RS(S;F )) Input: ein Relationenschema RS(S;F ) in ungünstiger Normalform Output: eine gültige 3NF-Zerlegung von RS(S;F ) in {RSi (Xi ;Fi )} (i = 1..n) NORMALIZATION (RS(S;F )) BEGIN F := REDUCE (F ) berechne die Schlüssel von RS(S;F ) FOR EACH FD X → Y ∈ F DO berechne X + ; berechne Gruppen äquivalenter FD FOR EACH Gruppe DO erzeuge ein Schema RSi (Xi ;Fi ). Xi sind alle Attribute und as Fi alle FD der Gruppe; MERGE (RSi (Xi ;Fi ), RSj (Xj ;Fj )) IF NOT verbundtreue Zerlegung THEN erzeuge ein weiteres Schema RSi (Xi ;Fi ) mit Xi Attribute eines Schlüsselkandidaten und Fi = {} END MERGE (RSi (Xi ;Fi ), RSj (Xj ;Fj )) BEGIN IF Xi ⊆ Xj and RSi (Xi ∪ Xj ;Fi ∪ Fj ) genügen der 3NF THEN mische RSi (Xi ;Fi ) undRSj (Xj ;Fj )) END
Die Arbeitsweise des Algorithmus NORMALIZATION (RS(S;F )) soll nun anhand eines Beispiels nachvollzogen werden. Beispiel 3.41: Normalisierung Ein relationales Datenbankschema enthält Informationen über folgenden Sachverhalt: Studenten (S) besuchen Übungen (U) und erreichen dort eine gewisse Punkteanzahl (P). Eine Übung wird von einem Assistenten (A) geleitet und findet zu einer gewissen Zeit in einem bestimmten Hörsaal (H) statt. Folgende funktionale Abhängigkeiten sind gültig: F = Übung → Assistent, /* Jede Übung wird von einem Assistenten betreut.*/ Übung, Student → Punkte, /*Nur eine Punkteanzahl pro Student und pro Übung.*/ Zeit, Hörsaal → Übung, /*Keine Übung teilt zur selben Zeit einen Hörsaal mit einer anderen.*/ Zeit, Student → Hörsaal, /*Ein Student kann zu einer Zeit nur in einem Hörsaal sein.*/ Zeit, Assistent → Hörsaal, /*Ein Assistent kann zu einer Zeit nur in einem Hörsaal sein.*/ Zeit, Student → Übung, /* Ein Student kann nicht gleichzeitig mehrere Übungen besuchen.*/ Zeit, Assistent → Übung /*Ein Assistent kann nicht gleichzeitig mehrere Übungen leiten.*/ Zeit, Übung → Hörsaal /*Eine Übung kann zu einer Zeit nur in einem Hörsaal stattfinden.*/ Für F ist eine kanonische Überdeckung zu bilden. Falls das Schema nicht in 3NF ist, sind daraus verbund- und abhängigkeitstreue 3NF-Fragmente herzuleiten.
3.6 Formaler Datenbankentwurf
159
Die Anwendung des Algorithmus REDUCE (F) liefert für F eine kanonische Überdeckung der Form F = {U → A, U S → P, ZH → U, ZS → U, ZA → U, ZU → H}. Im nächsten Schritt sind Gruppen äquivalenter FD zu ermitteln: {U}+ = {US}+ = {ZH}+ = {ZS}+ = {ZA}+ = {ZU}+ =
UA USP ZHUA ZSUAHP ZHUA ZHUA
Gruppe 1 Gruppe 2 Gruppe 4 Gruppe 3 Gruppe 4 Gruppe 1
Wir sehen, dass es sich bei ZH→ U , ZA→ U und ZU→ H um äquivalente FD handelt, die in die selbe Gruppe gemischt werden und dass ZS den einzigen Schlüssel dieses Schemas darstellt. Der nächste Schritt fordert, dass aus jeder Gruppe ein Relationenschema entwickelt werden soll. Dies führt zu: RS1 ({AU }; {U → A}), RS2 ({U SP }; {US→ P }) RS4 ({ZSU }; {ZS→ U }) und RS3 ({ZHU A}; { ZH→ U , ZA→ U , ZU→ H}) Es kann festgestellt werden, dass RS1 ⊆ RS3 gilt. Da ein Zusammenfügen beider Relationenschemata die 3NF-Bedingung nicht verletzt, können RS1 und RS3 zu einem Schema zusammengefasst werden. Im Schema RS4 ist der Schlüssel des Ausgangsschemas auch Schlüsselkandidat. Dadurch wird die Verbundtreue gewährleistet. Da alle Abhängigkeiten von F + in den Zerlegungen ausgedrückt werden, ist die Zerlegung auch abhängigkeitstreu. Eine mögliche Lösung der Aufgabe stellt das nachfolgend dargestellte Datenbankschema dar: Prüfung
({Übung Student Punkte}; {Übung Student → Punkte}) SK: Übung Student, BCNF
Zuordnung
({Zeit Hörsaal Übung Assistent}; {Zeit Hörsaal → Übung, Zeit Assistent → Übung, Zeit Übung → Hörsaal, Übung → Assistent}) SK: Zeit Hörsaal, Zeit Assistent, Zeit Übung, 3NF
Stundenplan
({Zeit Student Übung}; {Zeit Student → Übung}) SK: Zeit Student, BCNF
Man beachte, dass das Relationenschema Zuordnung nicht in BCNF ist. Aus diesem Grund existieren noch Anomalien, wie z. B. die Einfügeanomalie, die dafür verantwortlich ist, dass wir eine Übung erst in die DB eintragen können, sofern ihr auch ein Beginnzeitpunkt zugeordnet ist, einen Assistenten, sofern er eine Übung leitet und einen Hörsaal, sofern ihm eine Übung zugeordnet ist. Kann man mit der ersten Anomalie nicht „leben“, muss man auf das Zusammenführen verzichten und ein zusätzliches Relationenschema RS ({U A}; {U → A}) aufnehmen, das zur Verwaltung von Übungen verwendet werden kann. Die beiden anderen Anomalien sind darauf zurückzuführen, dass Assistent und Hörsaal nicht durch weitere Eigenschaften beschrieben sind.
160
3 Konzeptueller Datenbankentwurf
Abschließend wollen wir noch der öfters gestellten Frage nach der praktischen Relevanz der Normalisierungstheorie nachgehen. Macht es Sinn, große Entwurfsprojekte ausschließlich nach diesen Entwurfsrichtlinien durchzuführen? Diese Frage möchten wir vorerst verneinen, obwohl es notwendig ist, weiter zu argumentieren. Als sinnvolle praktische Vorgehensweise erscheint uns praktikabel, vorerst eine der zuvor vorgestellten Entwurfsmethoden anzuwenden, danach einen logischen Entwurf (siehe Kapitel 4) durchzuführen und daraus ein erstes relationales Datenmodell zu erzeugen. In den meisten Fällen werden die so erzeugten Relationenschemata bereits einer höheren Normalform genügen. Dies wird insbesondere dann der Fall sein, wenn das strukturorientierte Modell aus der konzeptuellen Modellbildung sorgfältig entworfen wurde. In einem nächsten Schritt soll dann die Normalformenlehre angewendet werden, um die Qualität des logischen Entwurfs zu prüfen. Genügt ein Relationenschema einer geforderten Normalform nicht, so ist eine Normalisierung vorzunehmen. In diesem Fall ist jedoch abzuwägen, ob das Vermeiden entsprechender Anomalien dem Vermeiden notwendig werdender Verbundoperationen für Abfragen vorzuziehen ist.
3.6.4
Kontrollaufgaben
Aufgabe 3.13: Ableitungssequenz Sei F = {AB → C, B → D, CD → EGH, G → A}. Geben Sie mit Hilfe der Armstrong-Axiome eine Ableitungssequenz für AB → EGH, BG → C und BC → AGH an. Aufgabe 3.14: Nicht triviale FD Gegeben sei R = {A B C} und a) F1 = {A → B, B → C}, b) F2 = {AB → C, C → B} und c) F3 = {AB → C, B → C}. Bestimmen Sie durch Anwendung der Inferenzaxiome alle nicht trivialen von a) F1, b) F2 und c) F3 implizierten FD. Aufgabe 3.15: Armstrong-Axiome Beweisen Sie unter Verwendung der Armstrong-Axiome und mittels Abteilungssequenz die nachfolgenden Aussagen: a. Y ⊆ X ⇒ X → Y c. X → Y ∧ Y Z → W ⇒ XZ → W
b. X → Y Z ⇒ X → Y ∧ X → Z d. X → Y Z ∧ Z → W ⇒ X → Y ZW
Aufgabe 3.16: Äquivalente Abhängigkeitsmengen Sind folgende Mengen von FD paarweise äquivalent? F = {A → BC, A → D, CD → E} H = {A → BCDE}
G = {A → BCE, A → ABD, CD → E} I = {A → BC, C → D, B → E}
Aufgabe 3.17: Redundante bzw. nicht redundante Überdeckungen Sind I bzw. I’ Überdeckungen bzw. nicht redundante Überdeckungen von H? H = {AB → C, A →→ B, B → C, A → C} I = {A → B, B → C}
I = {AB → C, A → B, B → C}
3.6 Formaler Datenbankentwurf
161
Aufgabe 3.18: Normalformen Gegeben sind die Relationenschemata RS1 ({Flug Datum Pilot Gate}; {Flug Datum → Pilot Gate, Flug → Gate}) RS2 ({Flug Datum Pilot_Id Name}, {Flug Datum → Pilot_Id Name, Pilot_Id → Name, Name → Pilot_Id}). In welchen Normalformen befinden sich RS1 bzw. RS2 ? Begründen Sie Ihre Antwort. Diskutieren Sie eventuell existente Speicheranomalien. Aufgabe 3.19: Normalformen Gegeben sei das Schema FABRIKATION ({Produkt# Maschine# Mitarbeiter#}; {F}). F repräsentiert die folgenden Einschränkungen: • Die Herstellung eines bestimmten Produktes erfordert eine vorgegebene Maschine. Mit jeder Maschine können jedoch mehrere Produkte erzeugt werden. • Für jedes Produkt gibt es genau einen verantwortlichen Mitarbeiter. • Jede Maschine ist einem bestimmten Mitarbeiter zugeordnet. Es gibt Mitarbeiter, die mehrere Maschinen zugeordnet haben. 1. Geben Sie die funktionalen Abhängigkeiten an und bestimmen Sie eine kanonische Überdeckung für F. 2. Bestimmen Sie die Schlüsselkandidaten für FABRIKATION. 3. In welcher Normalform befindet sich FABRIKATION? Diskutieren Sie eventuell auftretende Speicheranomalien. Aufgabe 3.20: Normalformen Gegeben seien folgende Relationenschemata in 1NF: PRÜFUNG STUDENT F1 = F2 =
({Prüfung# Fach Prüfer}; {F1 }) ({Prüfung# Matrikel# Name Geb-Dat Adr Stud-Richtung Note}; {F2 }) {Prüfung# → Fach, Prüfung# → Prüfer, Fach → Prüfung#} {Prüfung# → Matrikel#, Matrikel# → Name Geb-Dat Adr Stud-Richtung, Prüfung# Matrikel# → Note}
Bestimmen Sie die Schlüsselkandidaten für PRÜFUNG und STUDENT. In welcher Normalform befinden sich die Relationenschemata? Diskutieren Sie eventuell auftretende Speicheranomalien. Aufgabe 3.21: Normalformen Gegeben sei das Relationenschema FABRIKATION ({Produkt# Maschine# Mitarbeiter#}; {F}). F repräsentiert folgende Einschränkungen: • Ein Produkt kann nur von einem Mitarbeiter erzeugt werden. • Ein Mitarbeiter kann mit einer bestimmten Maschine nur ein Produkt erzeugen.
162
3 Konzeptueller Datenbankentwurf
Es gilt grundsätzlich, dass mit einer Maschine verschiedene Produkte erzeugt werden können. Geben Sie die funktionalen Abhängigkeiten an und bestimmen Sie eine kanonische Überdeckung für F. Bestimmen Sie die Schlüsselkandidaten. In welcher Normalform befindet sich das obige Relationenschema? Diskutieren Sie eventuell auftretende Speicheranomalien. Aufgabe 3.22: Nicht 3NF, aber in BCNF Geben Sie eine Attributmenge ATTR und eine Abhängigkeitsmenge F an, so dass RS(ATTR, F) der 3NF nicht aber der BCNF und 4NF genügt. Aufgabe 3.23: Vollfunktionale Abhängigkeit F sei eine Menge von FD, X → Y sei eine nicht vollfunktionale FD. Zeigen Sie, dass X → Y durch die entsprechende vollfunktionale FD ersetzt werden kann, ohne dass sich die Hülle von F verändert. Aufgabe 3.24: Verbundtreue Stellen Sie eine Relation auf, aus der ersichtlich ist, dass die Zerlegung aus Beispiel 3.40b) die Verbundtreue verletzt. Aufgabe 3.25: Normalisierung Für ein Apothekeninformationssystem wurden folgende Abhängigkeiten ermittelt: • Jedes Medikament wird von einem Pharmabetrieb erzeugt. • Jeder Pharmabetrieb hat seinen Sitz in einem bestimmten Land. • Medikamente sind in verschiedenen Packungstypen zu einem – abhängig von der Apotheke – bestimmten Preis erhältlich. Es wird angenommen, dass die Packungstypen für alle Medikamente europaweit genormt wurden, so dass die folgenden zwei Abhängigkeiten gelten: • Durch den Packungstyp ist die Form (z. B.: Tablette, Zäpfchen, Saft, . . . ) festgestellt. • Durch den Packungstyp wird die Menge eindeutig bestimmt. • Jedes Medikament enthält mehrere Wirkstoffe in einem bestimmten Anteil. • Jedes Medikament stammt aus einem bestimmten Land. Entwerfen Sie ein redundanzfreies Datenbankschema in 3NF.
3.6 Formaler Datenbankentwurf
163
Aufgabe 3.26: Normalisierung PROJEKTVERWALTUNG Projekt Ziel
A-Geb SVNr Name
Abteilung
Adresse
Alpha
Prototyp
A
124
Susan
Forschung Univ.-Str.
Alpha
Prototyp
A
127
Fritz
Alpha
Prototyp
A
125
Beta
Forschung
B
Beta
Forschung
Gehalt Manager 50 K
124
EDV
Comp.-Str. 50 K
124
Josef
EDV
Comp.-Str. 50 K
124
124
Susan
Forschung Univ.-Str.
B
125
Josef
EDV
Celsius Produktion C
126
Celsius Produktion C Celsius Produktion C
50 K
124
Comp.-Str. 50 K
124
Calvin Montage
CIM.-Str.
22 K
123
123
Bob
Verkauf
Sell.-Str.
80 K
123
125
Josef
EDV
Comp.-Str. 50 K
123
Relation PROJEKTVERWALTUNG soll folgenden Sachverhalt beschreiben: Projekte haben eine eindeutige Bezeichnung (z. B. Alpha), einen Projektgegenstand (P_Gegenstand), einen Auftraggeber (A_Geb) und einen Projektleiter (Manager). Projekte werden von Projektmitarbeitern durchgeführt. Diese sind eindeutig durch ihre Sozialversicherungsnummer (SVNR) beschrieben. Des weiteren wird der Name (Name) der Projektmitarbeiter, ihr Gehalt (Gehalt) und ihre Abteilung (Abteilung) samt Abteilungsadresse (Adresse) aufgezeichnet. • In welcher Normalform befindet sich PROJEKTVERWALTUNG? Welche Attribute bilden den Schlüssel? Begründen Sie Ihre Antwort! • Welche Information ist redundant gespeichert? • Diskutieren Sie eventuell existierende Anomalien. • Sollten Anomalien existieren, zerlegen Sie die angegebene Relation in „günstige“ Teilrelationen. Aufgabe 3.27: Normalisierung Bestimmen Sie für nachfolgende Relationenschemata eine minimale kanonische Überdeckung, die Menge der Schlüsselkandidaten und die jeweils höchste gültige Normalform. Ist 3NF nicht gegeben, zerlegen Sie das Relationenschema in abhängigkeits- und verbundtreue 3NF-Fragmente. RS1 RS2 RS3 RS4
({A B C D E F}; {D → E, AF → D, F → B, B → ADF, DF → C}) ({A B C D E}; {E → D, CD → BE, DE → B}) ({ABCDE}; {CA → E, AB → C, E → CD}) ({ABCDE}; {AB → C, C → ABDE, E → B})
Aufgabe 3.28: Normalisierung Relation ZOO soll folgenden Sacherverhalt beschreiben: Ein Zoo ist in geografische Bereiche geteilt. In jedem Bereich gibt es mehrere Behausungen. Alle Tiere einer bestimmten Art
164
3 Konzeptueller Datenbankentwurf
leben in derselben Behausung (siehe Beispielrelation). Jede Behausung besteht aus unterschiedlichen Boxen, von denen jede genau einem Tier zugeordnet ist. In unserem Zoo hat jede Behausung einen verantwortlichen Wärter und jeder Bereich einen Leiter. ZOO Art
Inventar#
Bereich
Behausung
Box
Wärter
Leiter
Giraffe
01
West
Weide
1
Tom
Weiss
Giraffe
02
West
Weide
2
Tom
Weiss
Löwe
01
Süd
Gehege
3
Bob
Grün
Bär
01
Ost
Käfig
6
Sam
Smith
Bär
02
Ost
Käfig
9
Sam
Smith
Zebra
01
West
Weide
8
Tom
Weiss
• In welcher Normalform befindet sich ZOO? Welche Attribute sind Schlüssel? Begründen Sie Ihre Antwort! • Welche Informationen sind in ZOO redundant gespeichert? • Diskutieren Sie in ZOO existente Speicher-Anomalien. • Leiten Sie aus dem Text funktionale Abhängigkeiten her und zerlegen Sie ZOO in abhängigkeits- und verbundtreue 3NF-Fragmente. Aufgabe 3.29: Mehrwertige Abhängigkeiten Können Sie aufgrund der unten angegebenen Ausprägungen Aussagen über die Gültigkeit der mehrwertigen Abhängigkeit Familie→→Kind in den beiden Relationen mit Schema R (Familie, Kind, Haustier) machen? Begründen Sie Ihre Antwort. Familie
Kind
Haustier
Familie
Kind
Haustier
Smith
Bob
Lessie
Smith
Bob
Lessie
Smith
Tom
Lessie
Smith
Tom
Lessie
Smith
Bob
Jumbo
Smith
Bob
Jumbo
Smith
Tom
Jumbo
Smith
Susan
Jumbo
Blau
Jim
Fido
Blau
Jim
Fido
Jones
Tom
Felix
Jones
Tom
Felix
White
Tom
Felix
White
Tom
Leo
3.7 Zusammenfassung
3.7
165
Zusammenfassung
Aufbauend auf die Erkenntnisse aus der Anforderungserhebung und -analyse soll während der konzeptuellen Modellbildung ein „unternehmensweites“ konzeptuelles Datenmodell entwickelt werden, das als einheitliche Schnittstelle für alle Anwendungen fungieren wird, die auf die in der DB gespeicherten Daten zugreifen. In diesem Kapitel haben wir die unterschiedlichen Paradigmen zur konzeptuellen Modellbildung kennen gelernt. Die Entity-Relationship-Modellierung gilt als De-facto-Standard für die konzeptuelle Modellierung, hat aber den Nachteil, dass ausschließlich eine strukturorientierte Sicht auf die Datenbankanwendung unterstützt wird und funktionale Aspekte völlig vernachlässigt werden. Ihr Fehlen kann dazu führen, dass die Struktur der DB und die auf sie zugreifenden Programme nicht gut aufeinander abgestimmt sind und die Schnittstelle zwischen DB und Anwendungsprogramm dieses Manko ausgleichen muss. Es liegt also nahe, strukturelle und funktionale Anforderungen gemeinsam zu betrachten und in eine einheitliche Datenbankentwurfsmethode zu integrieren. Als zweites Paradigma einer konzeptuellen Modellbildung haben wir eine Kombinationsmethode aus struktur- und funktionsorientierter Modellierung vorgestellt. Diese Methode basiert auf einer schrittweisen Verfeinerung eines Datenfluss- und eines ERM und hat den Vorteil, dass dabei beide Sichtweisen gleichberechtigt in Entwurfsentscheidungen berücksichtigt werden, indem das konzeptuelle Datenmodell aus beiden Sichten stufenweise herausgearbeitet werden kann. Die Methode beinhaltet eine gegenseitige Vollständigkeitsprüfung, so dass eine gewisse Konsistenz zwischen Funktions- und Datenmodell garantiert werden kann. Als drittes Paradigma haben wir die objektorientierte Modellbildung betrachtet. Die Kombinationsmethode führt schon zu einer ganzheitlichen Sicht auf ein Informationssystem hin, vernachlässigt jedoch die Analyse der unterschiedlichen Zustände der Objekte der DB und der Ereignisse, die zu einem Zustandswechsel führen. Verfolgt man eine objektorientierte Betrachtungsweise, so sind die zentralen Komponenten einer DB die in ihr gespeicherten Objekte. Objekte besitzen Struktur, „erleben“ Zustände und sind von Ereignissen beeinflusst, die Zustandsübergänge initiieren. Wir haben die wesentlichen Eigenschaften einer objektorientierten Vorgehensweise beim Datenbankentwurf erarbeitet und aus der Vielzahl der bekannten Methoden die vielversprechende Methode UML ausgewählt und vorgestellt. Die Struktur dieses Kapitels wurde nicht zufällig gewählt, sondern reflektiert die chronologische Reihenfolge, in der sich Wissenschaftler und Unternehmen gleichermaßen mit Methoden zur Analyse von Datenbankanwendungen beschäftigt haben. Die Entwicklung scheint auch heute noch nicht vollständig abgeschlossen zu sein. Es entwickeln sich weiterhin neue Denkansätze. So rückte z. B. in den letzten Jahren die Analyse und Modellierung von Geschäftsprozessen als Basis für den Datenbankentwurf zunehmend in den Mittelpunkt der Betrachtung. Alle bisher geschilderten Paradigmen zur konzeptuellen Modellbildung gehen von den zu modellierenden Funktionsbereichen im Unternehmen aus und versuchen, durch Analyse unterschiedlicher Aspekte ein Realweltmodell zu entwickeln. Bei der geschäftsprozessorientierten Modellbildung ist dies nun anders. Sie geht einen Schritt weiter, indem sie von den existierenden Geschäftsprozessen ausgeht und quer durch alle betrieblichen Funktionsbereiche alle relevanten Aspekte von aufeinander folgenden Aktivitäten darzustellen versucht. Des
166
3 Konzeptueller Datenbankentwurf
Weiteren berücksichtigt sie die Aufgabenträger, die in die Ausführung der Geschäftsprozesse involviert sind, und setzt ihren Schwerpunkt auf die Reorganisation bestehender Prozesse. Funktions-, objekt- und geschäftsprozessorientierte Modellbildung sind „allgemeine“ Methoden der Systemplanung und -entwicklung und werden deshalb für viele unterschiedliche Fragestellungen beim Entwurf von Software eingesetzt. Für den Datenbankentwurfsprozess gilt, dass ein strukturorientiertes Modell als Grundlage zur Entwicklung des Datenbankschemas nur dann vollständig sein kann, wenn die Designer eine ganzheitliche Vorstellung von der zu entwickelnden Anwendung besitzen und neben den statischen Aspekten, die funktionalen und dynamischen Anforderungen in ihre Entwurfsentscheidungen einbeziehen. Anforderungen, die das zeitabhängige Verhalten der DB betreffen, besitzen beim Entwurf des statischen Datenbankschemas eine untergeordnete Bedeutung. Sie sind jedoch für die Erstellung von Programmen, die auf die DB zugreifen, von essenzieller Wichtigkeit, da sie die Reihenfolge von Interaktionen und damit den zeitlichen Ablauf von Operationen festlegen. Bei großen Entwurfsprojekten ist es notwendig, die Arbeit auf mehrere Designteams aufzuteilen, und die Ergebnisse der unterschiedlichen Teams in eine Gesamtlösung zu integrieren. Im Subkapitel Sichtenintegration und Schemakonsolidierung wurde gezeigt, welche Konflikte dabei auftreten können, wie sie bereinigt werden sollen und welche Vorgehensweisen gewählt werden können, um aus Bereichsdatenmodellen ein integriertes unternehmensweites Datenmodell zu entwickeln. Als weiteres Paradigma zur konzeptuellen Modellbildung haben wir die Methode des formalen Datenbankentwurfs dargestellt. Diese Methode unterscheidet sich von den vorgenannten, da nun erstmals ein systemabhängiges Modell, das relationale Datenbankmodell, zum Einsatz kommt. Wir haben die Grundlagen des relationalen Datenbankmodells vorgestellt, und motiviert, warum es notwendig ist, relationale DB nach den Strukturierungsprinzipien der Normalformenlehre zu organisieren. Die Methode des formalen Datenbankentwurfs inkludiert eine umfangreiche Theorie, Gütekriterien und Entscheidungsvorschriften, mit denen relationale DB einer bestimmten Güte entworfen werden können.
3.8
Literatur
Die Wichtigkeit der konzeptuellen Datenmodellierung wird anhand von empirischen Studien, z. B. in [Maie98] oder [Gill85] belegt. Es gibt einige Bücher, die die unterschiedlichen Paradigmen zur konzeptuellen Modellbildung behandeln (z. B. [GaRö94], [Ortn97], [RaSt97], [Mert00] oder [FeSi98]. Neben den Originalarbeiten aus den Berichten der Entity-Relationship-Konferenzreihe sind dem interessierten Leser einige weitere Datenbankbücher zu empfehlen, die eine Darstellung des ERM beinhalten (z. B. [HeSa95], [LaLo95], [ElNa94], [Teor98] oder [FeSi98]). Aus der Menge der zahlreichen wissenschaftlichen Publikationen zur konzeptuellen Modellierung wollen wir auf Erfahrungsberichte gesondert hinweisen (z. B. in [Ortn91], [MeKl91]). Gute Übersichtsbeiträge sind [ScHa92], [TWBK89] oder [TeYF86]. Das Strukturierungskonzept der Aggregation und der Generalisierung geht auf [SmSm77] zurück. Die Kombinationsmethode aus struktur- und funktionsorientierter Modellbildung wurde aus [BaCN92] und [NaPe92] übernommen. Weiterführende Literatur zur objektorientierten Modellbildung stellen [ScRu96] oder [KaSc96] dar. Unterschiedliche Methoden der objektorientierten Systemanalyse sind in [Booc94], [CoYo91], [JCJÖ92] oder [RBPE93]
3.8 Literatur
167
dargestellt. Die Ausführungen zu UML sind [UML97a] und [UML97b] entnommen. Originalbeiträge zur geschäftsprozessorientierten Modellbildung mit SOM stellen [FeSi90] und [FeSi95] dar. Anwendungsentwicklung unter Verwendung von ARIS ist in [Sche98a] und [Sche98b] enthalten. Ein weiterer Ansatz der geschäftsprozessorientierten Modellbildung wird in [Öste95] verfolgt. Auch zum Themengebiet Sichtenintegration könnte man umfangreiche Literaturverweise machen. Die meisten Arbeiten gehen auf den Überblicksartikel [BaLN87] zurück. Eine umfangreiche Darstellung unterschiedlicher Integrationstechniken ist in [Eick97] enthalten. Werkzeugunterstützte Integration von Datenbankschemata wird in [SHOO95] diskutiert. [BoWi95] behandeln Verdichtungsoperationen in Datenmodellen, die zur Optimierung des integrierten Schemas angewendet werden können. Eine sehr gute Darstellung des formalen Datenbankentwurfs stellen [Lien85] oder [ViRT82] dar. Der Einsatz von deduktiven Methoden zur Datenmodellierung wird in [Neum94] untersucht.
4
Logischer Entwurf
Bis zu diesem Zeitpunkt war es möglich, ein unternehmensweites konzeptuelles Datenmodell völlig unabhängig (Normalisierungsvorgang ausgenommen) von seiner späteren Implementation in einem DBS zu entwerfen. Da ein konzeptuelles Datenbankschema nur in den wenigsten Fällen direkt in das Datenbankmodell des zur Verfügung stehenden DBS implementiert werden kann, ist ein weiterer Entwurfsschritt – der logische Datenbankentwurf – notwendig. Der logische Datenbankentwurf hat die Übersetzung des semantischen Schemas der konzeptuellen Modellbildung in ein logisches Datenbankmodell zur Aufgabe. In diesem Kaptitel werden wir uns bei den logischen Datenbankmodellen auf das relationale Datenbankmodell beschränken und zeigen, wie ein ER-Modell in ein relationales Datenbankmodell transformiert werden kann. Feststellung 4.1: Logischer Entwurf Das relationale Datenbankmodell ist in seiner semantischen Aussagekraft den semantischen Datenmodellen unterlegen. Daher ist es eine wesentliche Aufgabe des logischen Entwurfs, Abbildungsvorschriften zur Verfügung zu stellen, deren Anwendung den Verlust an semantischem Informationsgehalt im relationalen Datenbankmodell so gering als möglich halten. In Abbildung 4.1 fassen wir die wichtigsten Abstraktionsstufen, die die Ursache für den Semantikverlust zwischen Realwelt und ihrer Darstellung im Datenbankmodell darstellen, zusammen. Bei der weiteren Vorgehensweise kommt folgende Notation zum Einsatz: Die Bezeichnung von Entitytypen und Beziehungstypen aus dem ERM wird soweit wie möglich in das Relationenmodell übernommen. Im Relationenschema werden die Attribute des Primärschlüssels unterstrichen und Fremdschlüssel werden mit einer unterbrochenen Linie gekennzeichnet. Bei kursiv dargestellten Attributbezeichnungen handelt es sich um Eigenschaften, die nicht prime Attribute darstellen, aber trotzdem zu jedem Zeitpunkt einen Wert zugewiesen haben müssen, d. h. Nullmarken sind für diese Attribute nicht gestattet. Die kursive Darstellung von Attributen haben wir gewählt, um die Möglichkeit zu haben, einen totalen Beziehungstypen des ERM in die Darstellung des relationalen Datenbankmodells zu übersetzen, ohne die Information zu verlieren, dass jedes Tupel an einer Beziehung teilnehmen muss.
170
4 Logischer Entwurf
Realwelt • sehr vielschichtig • überwiegend Unikate • umfangreiche Beziehungen Realwelt Abstraktion, Typisierung
ER-Schema Abstraktion Datenbank Schema
Semantisches Datenmodell • Zusammenfassung von Entities zu Gruppen gleicher Struktur (Typisierung) • zwar schon stark abstrahierendes, aber vergleichsweise immer noch mächtiges Datenmodell • Beziehungen explizit modellierbar • komplexe Integritätsbedingungen Relationales Datenbankmodell • Abbildung auf Tupel und (normalisierte) Relationen • einfaches Datenmodell (wenige Basisdatentypen und Typkonstruktoren, eingeschränkte Einsetzbarkeit) • Beziehungen nur implizit modellierbar • einfache Integritätsbedingungen
Abb. 4.1: Abbildungsprozess Realwelt ↔ Relationales Datenbankmodell
4.1
Transformation von Entitytypen
Jeder Entitytyp wird in ein Relationenschema übersetzt. Dabei bleibt der gewählte Name des Entitytypen unverändert und alle Attribute aus dem ERM werden übernommen. Der in dem Schema geltende Primärschlüssel kann entweder direkt aus dem ERM abgeleitet werden oder er wird unter Anwendung der in Unterkapitel 3.6 dargestellten Techniken ermittelt. Er wird durch Unterstreichung der Attributbezeichnungen als solcher kenntlich gemacht. Wie im Verlauf der nachfolgenden Ausführungen zu sehen sein wird, können Attribute von Beziehungstypen, an denen der Entitytyp beteiligt ist, als Fremdschlüssel oder normale Attribute zusätzlich in das Relationenschema aufgenommen werden, wenn Beziehungstypen in das relationale Datenmodell überführt werden. Eine Sonderform stellt der schwache Entitytyp (abhängiger Entitytyp) dar. Ein schwacher Entitytyp aus dem ERM wird im Relationenmodell auch als Relationenschema dargestellt. Da ein schwacher Entitytyp jedoch keine identifizierenden Eigenschaften besitzt und seine Existenz von einem „starken“ Entitytyp abhängt, wird als Primärschlüssel des Relationenschemas ein Schlüsselkandidat des „starken“ Entitytyps gewählt. Beispiele für die Transformation von Entitytypen werden im folgenden Abschnitt bei der Abbildung von Beziehungstypen in das Relationenmodell besprochen.
4.2 Transformation von Beziehungstypen
4.2
171
Transformation von Beziehungstypen
Beziehungstypen werden im relationalen Datenbankmodell nicht zur Verfügung gestellt. Es gibt nur die Möglichkeit, sie entweder als eigenes Relationenschema oder als Attribut in das logische Datenmodell aufzunehmen. Dadurch geht die explizite Darstellung des Sachverhaltes, dass der Entitytyp in Beziehung zu einem anderen Entitytyp steht, im logischen Datenmodell verloren. Da die Anzahl der Relationenschemata aus Performancegründen so gering wie möglich gehalten werden soll, gilt es, Beziehungstypen als Attribute in einem bereits bestehenden Relationenschema darzustellen. Dies ist jedoch nur dann möglich, wenn durch das Zusammenführen von Entitytyp und Beziehungstyp keine Datenbankanomalien (Verletzung einer höheren Normalform) entstehen. Im Allgemeinen kann gesagt werden, dass rekursive und binäre Beziehungstypen mit einer Kardinalität N:M oder Beziehungstypen mit einem Grad größer als zwei immer in ein eigenes Relationenschema transformiert werden müssen und 1:1- oder 1:N-Beziehungstypen in bestehenden Relationenschemata ausgedrückt werden können.
4.2.1
Transformation rekursiver Beziehungstypen
Rekursive Beziehungstypen beschreiben eine Beziehung verschiedener Entities innerhalb eines einzigen Entitytypen. Durch diesen Sachverhalt stehen wir im Relationenmodell vor dem Problem, dass nach der Transformation die Attribute des Primärschlüssels im Relationenschema nun zweimal auftreten. Eine Forderung des relationalen Datenbankmodells ist aber Eindeutigkeit von Attributbezeichnungen. Aus diesem Grund muss eine der beiden Bezeichnungen – in Anlehnung an die Art der Beziehung – umbenannt werden. Für Beziehungstypen mit einer Kardinalität 1:1 und 1:N wird der umbenannte Primärschlüssel an das bereits bestehende Relationenschema angefügt. Bei einer Kardinalität N:M muss ein zusätzliches Relationenschema erstellt werden, das als Attribute zumindest den Primärschlüssel und den umbenannten Primärschlüssel aus dem Entitytyp-Relationenschema enthält. In dem neuen Relationenschema bilden dann beide Attributmengen gemeinsam den Primärschlüssel. Die oben dargestellte allgemeine Vorgehensweise soll allerdings nicht als zwingend angesehen werden. Insbesondere bei optionalen Beziehungstypen kann es von Vorteil sein, auch 1:1- oder 1:N-Kardinalitäten auf eigene Relationenschemata abzubilden, um Attribute mit Nullmarken zu vermeiden. Als alternative Lösung zu der in Beispiel 4.1 gewählten Lösung könnte man sich auch ein eigenes Relationenschema (z. B. Ist_verheiratet_mit (MitarbeiterNr, PartnerNr, Datum)) für den Beziehungstypen vorstellen. Da anzunehmen ist, dass nicht allzu viele Mitarbeiter miteinander verheiratet sind, hätte diese Lösung den Vorteil, dass Nullmarken für die Attribute „PartnerNr“ und „Datum“ vermieden werden könnten. Es ist jedoch zu bedenken, dass dies auf Kosten eines zusätzlichen Relationenschemas geschieht. Für jede Abfrage, die Mitarbeiter betrifft, die miteinander verheiratet sind, müsste eine zusätzliche Verbundoperation vorgesehen werden. Welche Art der Transformation man wählt, hängt vor allem von den zu erwartenden Transaktionen ab, die als Teil der Transaktionsanalyse im Anforderungsdokument dokumentiert sein sollten. Die nachfolgenden Beispiele zeigen die Transformation rekursiver Beziehungstypen der Kardinalitäten 1:1, 1:N, N.M aus dem ERM in das Relationenmodell.
172
4 Logischer Entwurf
Beispiel 4.1: Transformation unärer 1:1-Beziehungstypen Ein Mitarbeiter kann mit einem anderen Mitarbeiter verheiratet sein.
1 Mitarbeiter
1
ist_verheiratet_mit Datum
• Mitarbeiter (MitarbeiterNr, Name, . . . , PartnerNr, Datum)
Beispiel 4.2: Transformation unärer 1:N-Beziehungstypen N Mitarbeiter
1
istVorgesetzter
Ein Mitarbeiter kann Vorgesetzter mehrerer Mitarbeiter sein. Jeder Mitarbeiter hat ausschließlich einen Vorgesetzten. • Mitarbeiter (MitarbeiterNr, Name, . . . , VorgesetzterNr)
Beispiel 4.3: Transformation unärer N:M-Beziehungstypen M Artikel
N
istBauteilVon
Jeder Artikel kann verschiedene Bauteile besitzen. Ein Bauteil kann Bestandteil in mehreren Artikeln sein. • Artikel(ArtikelNr, Bezeichnung, . . . ) • ist_Bauteil_von(ArtikelNr, BauteilNr)
4.2.2
Transformation binärer Beziehungstypen
Analog zu den rekursiven Beziehungstypen werden auch binäre Beziehungstypen in Abhängigkeit ihrer Kardinalität in das Relationenmodell transformiert. Dabei hat man bei einer Kardinalität 1:1 die Wahl, welchem der beteiligten Entitytypen die Attribute des Beziehungstyps zugewiesen werden. Bei 1:N-Beziehungstypen muss der Entitytyp auf der N-Seite die Attribute des Beziehungstyps in sein Relationenschema aufnehmen. Falls bei einem binären Beziehungstyp der Kardinalität 1:1 eine totale Teilnahme eines der beteiligten Entitytypen gefordert ist (siehe Beispiel 4.5), so ist es empfehlenswert, den Primärschlüssel des Entitytypen ohne totale Teilnahme als Fremdschlüssel in das Relationenschema des Entitytypen mit totaler Teilnahme aufzunehmen. Auf diese Weise kann die Integritätsbedingung der totalen Teilnahme auch im Relationenmodell ausgedrückt werden, da für den Fremdschlüssel spezifiziert werden kann, dass er keine Nullmarken annehmen darf. Sollte eine totale Teilnahme beider Entitytypen am 1:1-Beziehungstyp gegeben sein, könnte dies auch dargestellt werden, indem beide Entitytypen zusammengefasst werden und ein einziges Relationenschema gebildet wird. In diesem Fall verliert man jedoch im Relationenmodell die
4.2 Transformation von Beziehungstypen 1
173 1
ERM-Darstellung
Abteilungsleiter
a) Transformation in zwei Tabellen
L_Nr
L_Name
...
Abt_Nr
Abt_Name
...
L_Nr
1 2 3 4
Müller Meier Schmidt Schulz
... ... ... ...
90001 90002 90003 90004
Einkauf Marketing Verkauf Beschaffung
... ... ... ...
1 2 3 4
b) Zusammenführung zu einer Tabelle
Abt_Nr
L_Name
...
Abt_Name
...
90001 90002 90003 90004
Müller Meier Schmidt Schulz
... ... ... ...
Einkauf Marketing Verkauf Beschaffung
... ... ... ...
leitet
Abteilung
Abb. 4.2: Transformation totaler 1:1-Beziehungstypen
Semantik, welche Attribute zu welchem Entitytyp gehören. In Abbildung 4.2 werden beide Designalternativen an einem Beispiel dargestellt. Man beachte, dass bei Designalternative b) die Zuordnung der Attribute zu den Objektypen der Realität verloren gegangen ist. Wie bereits erwähnt wurde, muss bei einer 1:N-Kardinalität eines Beziehungstyps der Primärschlüssel des Entitytypen der 1-Seite als Fremdschlüssel in das Relationenschema des Entitytyps auf der N-Seite aufgenommen werden. Allerdings gilt auch hier, dass der Fremdschlüssel keine Nullmarken annehmen kann, wenn die N-Seite eine totale Teilnahme am Beziehungstyp verlangt. Schwache Entitytypen sind nur im Zusammenhang mit dem „starken“ Entitytypen eindeutig identifizierbar und nehmen immer total am Beziehungstyp teil. Folglich muss der Primärschlüssel des letzteren immer in das Relationenschema des abhängigen Typs übernommen werden. Es ist nicht notwendig, totale N:M-Beziehungstypen gesondert zu optionalen N:M-Beziehungstypen zu betrachten, da beide Formen immer als eigenes Relationenschema dargestellt werden. Die Schlüsselattribute der beteiligten Entitytypen bilden gemeinsam den Primärschlüssel im Relationenschema des Beziehungstyps. In eine Relation mit einem Schema, das sich aus der Transformation eines Beziehungstyps ergibt, werden nur dann Tupel eingefügt, wenn tatsächlich eine Beziehung eintritt. Fremdschlüssel im Relationenschema des Beziehungstyps müssen folglich immer einen Wert besitzen, da sie ja Primärschlüssel in den beteiligten Entitytypen darstellen. Dies ist nicht unbedingt der Fall bei optionalen 1:N-Beziehungstypen. Dieser Sachverhalt und seine unterschiedliche Behandlung zu N:M-Beziehungstypen wird in Beispiel 4.4 verdeutlicht.
174
4 Logischer Entwurf
Mitarbeiter
1
N
leitet
Abteilung
M_Nr
M_Name
...
Abt_Nr
Abt_Name
...
M_Nr
1 2 3 4
Müller Meier Schmidt Schultz
... ... ... ...
90001 90002 90003 90004
Einkauf Marketing Verkauf Beschaffung
... ... ... ...
1
Kunde
M
N
bestellt
1
Artikel
K_Nr
K_Name
...
Art_Nr
Bezeichnung
...
1 2 3 4
Bollmann Schreiner Seewald Hamel
... ... ... ...
89342 23872 98843 43598
Getriebe Starrachse Kupplung Scheinwerfer
... ... ... ...
K_Nr
Art_Nr
3 4 3
89342 43598 98843
Null-Werte möglich
Tupel nur für tatsächliche Beziehungen, deshalb sind keine Null-Werte zulässig.
Abb. 4.3: Nullmarken bei Beziehungstypen und Entitytypen
Beispiel 4.4: Nullmarken bei Entity- und Beziehungstypen Wir zeigen den Unterschied bei der Behandlung von optionalen 1:N- und N:M-Beziehungstypen. Beim 1:N-Beziehungstyp „leitet“ zwischen Mitarbeiter und Abteilung sind Nullmarken möglich. Beim N:M-Beziehungstyp „bestellt“ zwischen Kunde und Artikel sind Nullmarken nicht möglich. Im Relationenschema, das den Beziehungstyp repräsentiert, stellen die Fremdschlüsselattribute auch gleichzeitig den Primärschlüssel dar. Siehe dazu die grafische Darstellung in Abbildung 4.3. Die nachfolgenden Beispiele zeigen jeweils unterschiedliche Situationen bei der Transformation binärer Beziehungstypen aus dem ERM in das Relationenmodell.
4.2 Transformation von Beziehungstypen
175
Beispiel 4.5: Transformation binärer 1:1-Beziehungstypen Mitarbeiter 1 leitet 1 Abteilung
Mitarbeiter 1 leitet 1 Abteilung
Nehmen beide Entitytypen optional am Beziehungstyp teil, so bedeutet dies, dass Abteilungen von einem Mitarbeiter geleitet werden können, aber durchaus auch Abteilungen existieren können, die keinen Leiter besitzen. Ebenso können Mitarbeiter existieren, die keiner Abteilung zugeordnet sind. • Mitarbeiter(MitarbeiterNr, Name, . . . AbtNr) • Abteilung(AbtNr, AbtName, . . . ) In dieser Variante ist die Teilnahme aller Abteilungen am Beziehungstyp bindend. Jede Abteilung muss von einem Mitarbeiter geleitet werden, aber nicht jeder Mitarbeiter muss auch Abteilungsleiter sein. In diesem Fall muss die MitarbeiterNr als Fremdschlüssel in das Relationenschema Abteilung aufgenommen werden und darf nicht die Nullmarke annehmen. • Mitarbeiter(MitarbeiterNr, Name, . . . ) • Abteilung(AbtNr, AbtName, . . . , MitarbeiterNr)
Beispiel 4.6: Transformation binärer 1:N-Beziehungstypen Kunde 1 erhält
Auch bei diesem Beispiel soll der Unterschied in der Transformation optionaler und totaler Teilnahmen an einem Beziehungstyp verdeutlicht werden. In der ersten Ausprägung des Beispiels kann jeder Kunde mehrere Rechnungen erhalten. Rechnungen sind dabei einem oder keinem Kunden zugeordnet. Die Transformation in das Relationenmodell ergibt folgendes Bild:
N Rechnung
• Kunde(KundenNr, Name, Vorname, . . . ) • Rechnung(RechNr, Datum, . . . , KundenNr)
Kunde 1 erhält N Rechnung
Einen realistischeren Fall beschreibt die zweite Alternative, bei der jede Rechnung einem Kunden zugeordnet sein muss, aber Kunden auch weiterhin keine Rechnung erhalten können. Für das Relationenmodell bedeutet dies, dass der Fremdschlüssel KundenNr in Rechnung keine Nullmarke annehmen darf. • Kunde(KundenNr, Name, Vorname, . . . ) • Rechnung(RechNr, Datum, . . . , KundenNr)
176
4 Logischer Entwurf
Rechnung 1 enthält N Rechnungsposition
Einen Sonderfall stellt die Transformation eines schwachen Entitytyps dar. In einem solchen Fall gehört der Fremdschlüssel mit zum Primärschlüssel des „schwachen“ Entitytyps. Zum Beispiel sind Rechnungspositionen nur im Zusammenhang mit der Rechnungsnummer eindeutig identifizierbar. • Rechnung(RechNr, Datum, . . . ) • RechnungsPos(RechNr, PosNr, Menge, . . . )
Beispiel 4.7: Transformation binärer N:M-Beziehungstypen Kunde M
Bestellmenge
bestellt N Artikel
N:M-Beziehungstypen werden grundsätzlich in ein eigenes Relationenschema transformiert. In diesem Beispiel kann ein Kunde verschiedene Artikel bestellen und jeder Artikel kann von beliebig vielen Kunden bestellt werden.
...........
• Kunde(KundenNr, Name, Vorname, . . . ) • Artikel(ArtikelNr, Abezeichnung, . . . ) • bestellt(KundenNr, ArtikelNr, Bestellmenge, . . . )
4.2.3
Transformation n-ärer Beziehungstypen
Beziehungstypen vom Grad > 2 müssen immer in ein Relationenschema überführt werden, unabhängig davon, welche Kardinalität der Beziehungstyp besitzt. Eine andere Lösung würde unweigerlich eine Verletzung der 2NF zur Folge haben und müsste zu weiterer Normalisierung führen. Die nachfolgenden Beispiele veranschaulichen die Transformation ternärer Beziehungstypen aus dem ERM in das Relationenmodell.
4.2 Transformation von Beziehungstypen
177
Beispiel 4.8: Transformation ternärer 1:1:1-Beziehungstypen Mitarbeiter 1 1
leitet
Filiale
1
Ein Mitarbeiter kann pro Filiale nur eine Abteilung leiten. Pro Filiale ist besonders zu betonen, da aus diesem Grund zwei Primärschlüssel der beteiligten Entitytypen nötig sind, um den Primärschlüssel des Beziehungstyps zu bilden. • Mitarbeiter(MitarbeiterNr, Name, . . . )
Abteilung
• Abteilung(AbtNr, AbtName, . . . ) • Filiale(FilialNr, Fbezeichnung, Ort, . . . ) Alternative Transformationen des Beziehungstyps: • leitet(MitarbeiterNr, AbtNr, FilialNr) • leitet(MitarbeiterNr, AbtNr, FilialNr) • leitet(MitarbeiterNr, AbtNr, FilialNr)
Beispiel 4.9: Transformation ternärer 1:1:N-Beziehungstypen Mitarbeiter 1 leitet N
1
Filiale
In diesem Fall kann ein Mitarbeiter mehrere Abteilungen einer Filiale leiten. Eine Abteilung kann pro Filiale weiterhin nur einen Leiter haben, aber in einer anderen Filiale kann dieselbe Abteilung von einem anderen Mitarbeiter geleitet werden.
Abteilung
• Mitarbeiter(MitarbeiterNr, Name, . . . ) • Abteilung(AbtNr, AbtName, . . . ) • Filiale(FilialNr, Fbezeichnung, Ort, . . . ) Alternative Transformationen des Beziehungstyps: • leitet(MitarbeiterNr, AbtNr, FilialNr) • leitet(MitarbeiterNr, AbtNr, FilialNr)
178
4 Logischer Entwurf
Beispiel 4.10: Transformation ternärer 1:N:M-Beziehungstypen Mitarbeiter M leitet
1
Filiale
N Abteilung
Im Gegensatz zu Beispiel 4.9 kann nun eine Abteilung auch mehrere Abteilungsleiter haben. Aber immer noch gilt die Einschränkung, dass ein Mitarbeiter eine ganz bestimmte Abteilung nur in einer Filiale leiten kann. Beispielsweise kann der Leiter der Einkaufsabteilung der Filiale in Essen nicht auch die Einkaufsabteilung einer anderen Niederlassung leiten. Er könnte jedoch durchaus einer anderen Abteilung (z. B. Beschaffung, Marketing, . . . ) der weiteren Filiale vorstehen. Die Transformation in das Relationenmodell ergibt folgendes Bild: • Mitarbeiter(MitarbeiterNr, Name, . . . ) • Abteilung(AbtNr, AbtName, . . . ) • Filiale(FilialNr, Fbezeichnung, Ort, . . . ) • leitet(MitarbeiterNr, AbtNr, FilialNr)
Beispiel 4.11: Transformation ternärer N:M:P-Beziehungstypen Mitarbeiter M leitet
P
Filiale
In diesem Beispiel existieren keine Einschränkungen mehr hinsichtlich der Beziehung der verschiedenen Tupel der beteiligten Entitytypen. Das ERM wird in die nachfolgend dargestellten Relationenschemata transformiert.
N Abteilung
• Mitarbeiter(MitarbeiterNr, Name, . . . ) • Abteilung(AbtNr, AbtName, . . . ) • Filiale(FilialNr, Fbezeichnung, Ort, . . . ) • leitet(MitarbeiterNr, AbtNr, FilialNr)
4.3
Transformation von Generalisierung und Subtypenhierarchie
Es gilt auch hier, dass für jeden beteiligten Entitytyp ein Relationenschema erstellt wird. Dabei ist zu beachten, dass Spezialisierungen die Attribute des generischen Entitytyps erben. Im Relationenmodell bedeutet dies, dass die Attribute des Primärschlüssels des Relationenschemas des generischen Entitytyps in die Relationenschemata der Spezialisierungen übertragen und alle anderen Attribute von den Spezialisierungen implizit übernommen werden. Der Primärschlüssel des Relationenschemas des generischen Entitytyps dient auch in den Spezialisie-
4.3 Transformation von Generalisierung und Subtypenhierarchie
179
rungen zur eindeutigen Identifizierung aller Tupel. Attribute, deren Werte die Grundlage zur eindeutigen Zuordnung von Tupeln zu Spezialisierungen darstellen (Diskriminatoren), können als Attribute in die Relationenschemata der Spezialisierungen übernommen werden. Im Relationenschema, das dem generischen Entitytyp entspricht, müssen diese jedoch aufgenommen werden. Bei Spezialisierungen mit nur wenigen zusätzlichen Attributen sollte erwogen werden, die Attribute der Spezialisierungen in das Relationenschema der Superklasse aufzunehmen. Dies würde zwar bedeuten, dass es unter Umständen eine größere Anzahl von Nullmarken in der Relation des generischen Entitytyps geben wird, aber die zeitaufwändigen Verbundoperationen bei Datenbankabfragen würden reduziert. Der Transformationsprozess von Generalisierungs- und Subtypenhierarchien wird in Beispiel 4.12 und Beispiel 4.13 dargestellt. Beispiel 4.12: Transformation von Generalisierungshierarchien Person
Im Falle einer Generalisierung wird der Diskriminator explizit modelliert und ist Bestandteil des generischen Entitytyps. In diesem Beispiel entscheiden seine Werte über die Zugehörigkeit eines Entities vom Typ Person zu den disjunkten Klassen Geschäftspartner und Mitarbeiter.
Status
Geschäftspartner
Mitarbeiter
• Person(PersonNr, Name, Vorname, . . . , Status) • Geschäftspartner(PersonNr, Land, MwSt, . . . ) • Mitarbeiter(PersonNr, Einstellungsdatum, Gehalt, . . . )
Beispiel 4.13: Transformation von Subtypenhierarchien Geschäftspartner
Kunde
Lieferant
Bei Subtypenhierarchien ist der Diskriminator lediglich implizit im Modell vorhanden, d. h. in dem Beispiel existieren zwar ein oder mehrere Attribute im Entitytyp Geschäftspartner, die entscheiden, ob ein Entity zum Entitytyp Kunde, Lieferant oder gar zu beiden gehört, aber diese werden nicht im ER-Diagramm dargestellt. • Geschäftspartner(PersonNr, Rabatt, MwSt, . . . ) • Kunde(PersonNr, Bonität, . . . ) • Lieferant(PersonNr, Skonto, . . . )
Im Allgemeinen gilt, dass abzuwägen ist, ob aus Spezialisierungen eigene Relationenschemata erzeugt werden sollen. Entscheidet man sich für das Zusammenlegen von generischem Entitytyp und Spezialisierungen in ein einziges Relationenschema, so müssen Nullmarken
180
4 Logischer Entwurf
bzw. Redundanzen in Kauf genommen werden. Es ergibt sich jedoch bei Datenbankabfragen der Vorteil, dass Verbundoperationen vermieden werden können. Für Beispiel 4.13 wäre die Zusammenführung der Entitytypen eine alternative Transformation. In einem Schema Geschäftspartner (PersonNr, Rabatt, . . . , Bonität, Skonto) würden jedoch für Entities vom Typ Lieferant im Attribut Bonität Nullmarken existieren und für Entities vom Typ Kunde gilt dies für das Attribut Skonto. Es entsteht jedoch nur ein Relationenschema im Gegensatz zu drei Relationenschemata bei der im Beispiel gewählten Transformation. Es ist nun an der Zeit, die bisher beschriebenen Transformationsregeln und ihre Anwendung anhand eines Beispiels zu verdeutlichen. Wir betrachten einen Ausschnitt aus dem Datenmodell eines Produktionsbetriebes. Beispiel 4.14: Logischer Entwurf Produktionsunternehmen Das Unternehmen baut aus eigenproduzierten Teilen und von Lieferanten bezogenen hochwertigen Komponenten (Teilen) ein Produkt, verwaltet Informationen über Mitarbeiter, Kunden und Lieferanten und möchte über das DBS die Geschäftsabwicklung mit den Lieferanten unterstützen. Als weitere Informationen sind festzuhalten, in welcher Abteilung die einzelnen Mitarbeiter beschäftigt sind und an welchen Produkten diese Abteilungen arbeiten. Für unterschiedliche Produkte werden von einem Lieferanten verschiedene Komponenten bezogen, die möglicherweise jedoch auch für andere Produkte eingesetzt werden können. Jedes Teil innerhalb eines Produktes wird jedoch ausschließlich von einem Lieferanten bezogen. Lieferanten erhalten im Laufe der Zeit mehrere Aufträge, die sich aus einzelnen Auftragspositionen (Menge, Artikel, . . . ), die wiederum mit Rechnungspositionen korrespondieren, zusammensetzen. Sowohl Produkte als auch Teile werden in einem speziellen Lager aufbewahrt. Ein entsprechendes ERD ist in Abbildung 4.4 dargestellt. Das Ergebnis des Transformationsprozesses ist im Anschluss daran angegeben. Auf dieses Beispiel wird in den nachfolgenden Kapiteln noch öfter eingegangen werden. Transformation von Entitytypen 1. Mitarbeiter(mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, . . . 2. Abteilung(abteilungsNr, abteilungsName, budget, mitarbeiterZahl, . . . 3. Produkt(produktNr, produktBez, produktTyp, stueckKosten, nettoPreis, . . . 4. Teil(teilNr, teilBez, . . . 5. Lager(lagerNr, lagerBez, plz, ort, strasse, hausNr, art, . . . 6. ProduktLager(lagerNr, . . . ) 7. TeileLager(lagerNr, . . . ) 8. Zulieferer(zuliefererNr, zuliefererName, plz, ort, strasse, hausNr, bank, blz, . . . ) 9. Auftrag(auftragsNr, datum, . . . ) 10. AuftragsPosition(auftragsNr, auftragsPos, menge, . . . )
4.3 Transformation von Generalisierung und Subtypenhierarchie N
1
1
Mitarbeiter
beschäftigt
bestehtAus
N Rechnungsposition
181
N Abteilung
arbeitet_an
Lager
1
Art
entspricht
1 M Rechnung
Teil lagert_in
TeileLager
ProduktLager N
N N sendet
1 1
Teil M
N
1 Zulieferer
1
verweist_auf
N
Auftragsposition N
sind Bestandteil von
M M
liefert
N
Produkt
1
M
Produkt lagert_in
N
vergibt kauft erhält M Kunde
N N
Auftrag
1
enthält
Abb. 4.4: EER-Modell des Produktionsunternehmens
11. Rechnung(rechnungsNr, datum, . . . ) 12. RechnungsPosition(rechnungsNr, rechnungsPos, menge, betrag, . . . ) 13. Kunden(kundenNr, kundenName, kundenVorname, plz, ort, strasse, hausNr, rabatt, . . . ) Transformation von Beziehungstypen mit Grad > 2 oder Kardinalität N:M 1. ArbeitetAn(abteilungsNr, produktNr) 2. Liefert(zuliefererNr, teilNr, produktNr) 3. ProduktLagerIn(produktNr, produktLagerNr, istBestand) 4. TeilLagerIn(teileLagerNr, teilNr, istBestand) 5. SindBestandteilVon(teilNr, produktNr) 6. Kauft(kundenNr, produktNr)
182
4 Logischer Entwurf
Transformation von Beziehungstypen mit Kardinalität 1:1 oder 1:N 1. Mitarbeiter(mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, geburtsDatum, plz, ort, strasse, hausNr, gehalt, einstellung, mitarbeiterStatus, abteilungsNr) 2. Abteilung(abteilungsNr, abteilungsName, budget, mitarbeiterZahl) 3. Produkt(produktNr, produktBez, produktTyp, stueckKosten, nettoPreis) 4. Zulieferer(zuliefererNr, zuliefererName, plz, ort, strasse, hausNr, bank, blz, kontoNr, ansprechpartner, ansprechpartTelNr) 5. Teil(teilNr, teilBez) 6. Lager(lagerNr, lagerBez, plz, ort, strasse, hausNr, art) 7. ProduktLager(lagerNr) 8. TeileLager(lagerNr) 9. Auftrag(auftragsNr, bearbeiterNr, datum, zuliefererNr) Auftrag[auftragsNr]=AuftragsPosition[auftragsNr] 10. AuftragsPosition(auftragsNr, auftragsPos, menge, teilNr) 11. Rechnung(rechnungsNr, datum, zuliefererNr) Rechnung[rechnungsNr]=RechnungsPosition[rechnungsNr] 12. RechnungsPosition(rechnungsNr, rechnungsPos, menge, betrag, auftragsNr, auftragsPos) 13. Kunden(kundenNr, kundenName, kundenVorname, plz, ort, strasse, hausNr, rabatt, ansprechpartner, ansprechpartTelNr)
4.4
Zusammenfassung
Im Zuge des logischen Entwurfs der DB wird das semantische Datenmodell der Anwendung (Ergebnis der konzeptuellen Modellbildung) in das Datenbankmodell des zur Verfügung stehenden DBMS transformiert. In den meisten Fällen findet bei diesem Vorgang ein Verlust der semantischen Aussagekraft des Datenmodells statt, da logische Datenbankmodelle in der Regel weniger ausdrucksstark sind als semantische Datenmodelle. Sind Konzepte des semantischen Datenmodells im logischen Datenbankmodell nicht vorgesehen, so muss die geforderte Funktionalität in den Anwendungsprogrammen realisiert werden. Betrachtet man als Mittel für die konzeptuelle Modellbildung das ERM und als Zielmodell des Entwurfs das relationale Datenbankmodell, so bietet dieses ausschließlich Attribute und Relationenschemata als Zielkonzepte an. Trotzdem hat der Entwickler in manchen Fällen die Wahl, ob er Entitytypen des ERM im Relationenmodell zusammenführt oder als eigene Schemata realisiert, oder ob er Beziehungstypen des ERM als eigenes Relationenschema oder als Attribut in einem bestehenden Schema übernimmt. Als allgemeine Regeln, die immer ein gültiges logisches Modell erzeugen, aber dabei nicht notwendigerweise die besonderen Gegebenheiten einer speziellen Anwendung betrachten, wird die folgende Vorgehensweise empfohlen:
4.5 Literatur
183
1. Entitytypen werden in ein Relationenschema transformiert. Schwache Entitytypen erben dabei den Primärschlüssel des „starken“ Entitytyps. 2. Für Beziehungstypen mit einem Grad > 2 oder einer Kardinalität N:M wird immer ein eigenes Relationenschema erstellt. 3. Bei einer 1:N-Kardinalität eines Beziehungstyps wird der Primärschlüssel der 1-Seite in das Relationenschema der N-Seite übernommen und bei einer 1:1-Kardinalität hat der Entwickler die Wahl, welchen Primärschlüssel er an das jeweils andere Relationenschema anfügt. 4. Die an Generalisierung oder Subtypenhierarchien beteiligten Entitytypen werden als eigene Relationenschema dargestellt. Dabei erben die Spezialisierungen den Primärschlüssel der Superklasse.
4.5
Literatur
Die Phase des logischen Entwurfs der DB wird in den meisten anwendungsorientierten Datenbankbüchern behandelt. Für weiteres Literaturstudium empfehlenswert sind u. a. [BaCN92], [ElNa94], [NaPe92], [RaSt97], [Teor98] oder [TeYF86].
4.6
Kontrollaufgaben
Aufgabe 4.1: Flugteilnehmer Anr
Ausgang
Pnr
1
N
fliegt_ab
Passagier
1
ist_zugeord.
1
1 Dat, Zeit
Flug
1
hat_Sitz
Fnr
N
Sitzplatz
Snr
Die Aufgabe besteht aus drei Teilen. 1. Erstellen Sie eine Abhängigkeitsmenge F, die aus allen funktionalen Abhängigkeiten besteht, die sich aus dem ER-Diagramm ableiten lassen. Entwickeln Sie für F eine minimale kanonische Überdeckung, die Menge der Schlüsselkandidaten sowie ein anomalie- und redundanzfreies Datenbankschema (Normalisierung). Involvierte Attribute: Pnr, Anr, Fnr, Snr, Dat, Zeit. 2. Entwickeln Sie aus dem ER-Diagramm ein relationales Datenbankschema (logischer Entwurf). Bilden Sie die Entitytypen in Relationenschema ab und lösen Sie die Beziehungstypen entsprechend auf. Ergänzen Sie falls notwendig um weitere Attribute.
184
4 Logischer Entwurf
3. Falls Sie für 1. und 2. unterschiedliche Lösungen entwickelt haben, diskutieren Sie die Ursache für die unterschiedlichen Lösungen und deren Vor- und Nachteile. Aufgabe 4.2: Flughafeninformationssystem Erzeugen Sie aus dem nachfolgend dargestellten ERD ein redundanzfreies relationales Datenbankschema. Beachten Sie dabei auch die Anforderungen aus Aufgabe 3.9. Mitarbeiter
N
Wartung
1
verantwortet
Techniker
1
Pilot
M
M
darf_warten
darf_fliegen N
1
vom_Typ
N
Flugzeugtyp
N 1
Service
M
Flugzeug
N
besitzt
Eigner
N M Art Lager
steht_im Nat_Person
1
Firma
Hanger
Aufgabe 4.3: Krankenhausinformationssystem Erzeugen Sie aus folgendem ERD ein redundanzfreies relationales Datenbankschema. Beachten Sie dabei auch die Anforderungen aus Aufgabe 3.7. A(A1, A2) 1
1
H(H1, H2)
N
Bez1
N
Bez2
1
Bez3
Bez9
M
B(B1, B2)
N 1
N
Bez4
1
C(C1, C2)
M
Bez8
E1 M F(F1, F2)
N
Bez5
M
N N
D(D1, D2) N
M Bez6 E2
Bez7
M
G(G1, G2)
4.6 Kontrollaufgaben
185
Aufgabe 4.4: Projektverwaltung Erzeugen Sie aus dem nachfolgend dargestellten ERD ein redundanzfreies relationales Datenbankschema. Beachten Sie dabei auch die Anforderungen aus Aufgabe 3.5. Beginn Projekt#
Projektträger
1
Ende
N
trägt
Art
natürliche Person
Projekt
Standort juristische Person
Zahlungsart Datum
Kontaktperson
Höhe Förderer
N
M
fördert
1
Inland
Ausland
1
1
ist_beteiligt
Schadstoffemission
leitet
Sprache
arbeitet_an
1
9
Energiesparmaßnahmen
P_Mitarbeiter
altern. Verpackungsformen
P_Leiter
alternative Energieformen Funktion Ortszulage N
Dienstwagen
1
erhält
1
IP_Mitarbeiter
AP_Mitarbeiter
Baujahr Kennzeichen Typ Ort
Mitarbeiter
5
Einführung in Datenbankmanagementsysteme
In diesem Kapitel wird die Architektur eines DBMS auf einer abstrakten, aber für die Zwecke dieses Buches hinreichend konkreten Ebene diskutiert. Im Mittelpunkt stehen dabei alle durch die Verarbeitung einer Anfrage1 an die DB berührten Komponenten eines DBMS. Etwas ausführlicher wird auch auf die Verwaltung und Wartung der Metadateneingegangen, also der Daten, die das konzeptuelle, das interne und die externen Schemata eines DBS beschreiben.
5.1
Architektur eines Datenbankmanagementsystems
Eine Datenbankarchitektur kann man unter verschiedenen Perspektiven betrachten, von denen hier die Schemaarchitektur und die Systemarchitektur genauer präsentiert werden sollen.
5.1.1
Die Schemaarchitektur
Bereits Anfang der 70er Jahre wurde vom American National Standard Institute (ANSI) eine so genannte Drei-Ebenen-Schemaarchitektur vorgeschlagen, die ein DBS auf einer sehr abstrakten Ebene beschreibt. Bei dieser Architektur besteht ein DBS aus drei aufeinander aufbauenden Schichten, die sich so auch in Anfragesprachen, insbesondere SQL, wiederfinden lassen (siehe Abbildung 5.1). Diese Architektur war bereits in Kapitel 2.1.3 kurz vorgestellt worden und soll hier noch etwas präzisiert werden. Internes Schema Das interne oder physische Schema legt fest, in welcher Form die Daten der DB abgespeichert werden (Speicherungsstrukturen) und welche Zugriffspfade bzw. Indexstrukturen zur Gewährleistung eines schnelleren Zugriffs auf die Daten bereit gestellt werden. Diese Ebene ist für den normalen Benutzer eines DBS nicht relevant und daher auch nicht sichtbar. Konzeptuelles Schema Das konzeptuelle Schema stellt eine auf der Basis des Datenbankmodells entwickelte logische Beschreibung des Realweltausschnittes dar, der in der DB abgelegt werden soll. Die Beschreibung findet auf einer relativ abstrakten Ebene statt, bei der von Informationen über die interne Darstellung abstrahiert wird. Das konzeptuelle Schema stellt eine anwendungsneutrale 1 Anfrage ist hier im weiteren Sinn zu verstehen, schließt also insbesondere auch die Datendefinition und -manipulation mit ein.
188
5 Einführung in Datenbankmanagementsysteme Anwendung 1
Anwendung 3 Anwendung 2 Anwendung n+1 Anwendung n externe Schemata (Sichten)
konzeptuelles Schema
internes Schema
Abb. 5.1: Drei-Ebenen-Schemaarchitektur nach ANSI
Beschreibung des Realweltausschnittes dar. Es wird in der Regel aus dem beim konzeptuellen Datenbankentwurf entwickelten ER- oder objektorientierten Modell abgeleitet und stellt dessen DBMS-spezifische Repräsentation dar. Diese Ebene ist für den Anwendungsprogrammierer relevant. Der normale Benutzer wird nur dann auf sie zurückgreifen, falls ihm kein eigenes externes Schema zur Verfügung steht. Externes Schema Das externe Schema, auch Sicht genannt, extrahiert aus dem konzeptuellen Schema einen anwendungsspezifischen Ausschnitt. Damit wird die Ebene modelliert, auf der üblicherweise die Anwendungen bzw. Benutzer arbeiten. Eine Sicht ist an die spezifischen Bedürfnisse der zu Grunde liegenden Anwendung angepasst. Dies bedeutet insbesondere, dass die Anwendung
5.1 Architektur eines Datenbankmanagementsystems
189
nur den sie interessierenden Teil des konzeptuellen Schemas sieht und dies in einer auf ihre Bedürfnisse zugeschnittenen Form. Nicht relevante Daten werden ausgeblendet, andere Daten so dargestellt, wie es die Anwendung wünscht. Zusätzlich dient das externe Schema aber auch dem Datenschutz. Die Anwendung sieht genau das, was sie auch sehen soll und darf. Während es pro DB nur ein internes und ein konzeptuelles Schema gibt, ist die Anzahl der externen Schemata nicht begrenzt. Grundsätzlich kann jede auf der DB arbeitende Anwendung ihr eigenes externes Schema besitzen. In der Regel stehen auf der Ebene des externen Schemas die gleichen Modellierungsmechanismen zur Verfügung wie auf der Ebene des konzeptuellen Schemas.
5.1.2
Die Systemarchitektur
Die Systemarchitektur eines DBMS beschreibt dessen (logische) Komponenten. Auf einer noch sehr abstrakten Ebene kann man zwischen der Anfragekomponente bzw. dem QueryProzessor und dem Speichermanager unterscheiden (siehe Abbildung 5.2). Der Benutzer, der Datenbankadministrator, der Anwendungsprogrammierer und die -programme greifen über die Anfragekomponente auf die Daten der DB zu. Die Anfragekomponente stellt mehrere Schnittstellen zur Verfügung. Der Benutzer kann direkt über die interaktive (Online-) Anfragekomponente mit der DB arbeiten. Die Anfrage wird interpretiert und direkt ausgeführt. Anwendungen greifen normalerweise aus einer konventionellen Programmiersprache heraus auf die DB zu. Die Programmiersprache ist um die Konstrukte der Anfragesprache erweitert oder, andersherum gesehen, die Anfragesprache ist in die Programmiersprache eingebettet. Dementsprechend liegt hier in der Regel ein kompilierender Ansatz vor. Bevor der eigentliche Übersetzer der Programmiersprache aufgerufen wird, filtert zunächst ein Vorübersetzer (Precompiler) die anfragesprachenspezifischen Anweisungen aus dem Programm und ersetzt sie durch programmiersprachenkonforme Ausdrücke. Normalerweise sind dies Aufrufe von Prozeduren, die der Arbeit auf der DB dienen. Die Bibliothek der Programmiersprache wird um die entsprechenden Prozedurimplementierungen erweitert, so dass die Prozeduren vom Binder in der Bindephase in das Anwendungsprogramm eingebunden werden können. Diese Diskussion zeigt schon, dass ein wesentlicher Unterschied zwischen einer Online-Anfrage und einer eingebetteten Anfrage besteht2 : Erstere wird interpretiert, Letztere kompiliert. Die Anfragebearbeitung (query evaluation engine) ist für die Abarbeitung der Anfrage verantwortlich. Sie veranlasst den Speichermanager, die gewünschten Daten aus der DB zu holen, um sie der Anwendung im datenbankspezifischen Puffer zur Verfügung zu stellen. Neben der Anfragesprache3 existiert noch eine gesonderte Sprache, die Datendefinitionssprache oder DDL. Über sie wird die DB vom Datenbankadministrator bzw. -programmierer angelegt und gewartet. Da jede Relation Rel normalerweise nur einmal angelegt wird, um später höchstens noch in ihrem Aussehen verändert oder, sofern sie nicht mehr benötigt wird, gelöscht zu werden, werden die DDL-Anweisungen häufig „nur“ interpretiert. Der Übersetzer bzw. Interpreter ist neben der Überprüfung, ob die in der Anfrage angesprochenen Datenbankobjekte (Relationen, Attribute) überhaupt existieren, auch noch für alle 2 Aus
Abbildung 5.2 ist dies nicht direkt ersichtlich. wird noch gezeigt werden, dass man die Anfragesprache noch weiter zerlegen kann.
3 Später
190
5 Einführung in Datenbankmanagementsysteme Benutzer
Ad-hoc-Benutzer
Anwendungsprogrammierer
Datenbankadministrator
Anwendung
OnlineAnfrage
programmiersprachenbezogener Vorübersetzer
Verwaltungswerkzeug
DML-Übersetzer mit Integritätsprüfung, Optimierung, Code- bzw. Ausführungsplanerstellung
DDL-Übersetzer
Anfragebearbeitung
Query-Prozessor DBMS Puffer- und Dateimanager Systemkatalog Datenwörterbuch
Synchronisation/ Recovery/Backup
Speichermanager
Dateiverwaltung
Sekundärspeicher Sekundärdaten Zugriffspfade, Indexe Logdateien
Primärdaten
Materialisierte Datenbank (Nutzdaten)
Metadaten, Datenwörterbuch
Abb. 5.2: Vereinfachte Darstellung der Systemarchitektur eines DBMS
Aspekte des Datenschutzes (Zugriffsberechtigungen), der Integritätskontrolle und der Optimierung inklusive der Einbindung von Zugriffspfaden verantwortlich. Auch wenn die Modellierungsfähigkeiten konventioneller DBMS eher bescheiden sind, bewegen sich die im Vergleich zur Bitfolgendarstellung auf der Platte mit einiger Semantik angefüllten Daten einer DB auf einer relativ hohen Ebene. Da jedoch auf der Platte nur Blöcke mit Bitfolgen abgelegt werden können, muss die Semantik auf dem Weg von der Platte zur
5.1 Architektur eines Datenbankmanagementsystems
191
Anwendung hinzugefügt werden. Daten müssen aus den Blöcken herausgelöst, inhaltlich verstanden und in eine anwendungsspezifische Darstellung überführt werden. Daten durchlaufen also diverse Transformationen. Die Dateiverwaltung, die häufig Bestandteil des Betriebssystems ist, verwaltet die Daten auf unterster Ebene. Die Überführung in die anwendungsspezifische Darstellung übernimmt der Speichermanager. Zu seinen Aufgaben gehört auch die Verwaltung der Schnittstelle zwischen DBS und Anwendungsprogramm, des so genannten Datenbankpuffers, was insbesondere heißt, dass er zu entscheiden hat, wann welche Daten aus dem Puffer entfernt werden, welche Daten in die DB zurückgeschrieben werden und welche Daten ausgelagert werden müssen, wenn der Puffer zu klein wird. Gleichzeitig ist der Speichermanager für das Transaktionsmanagement und damit für alle Aspekte der Fehlerbehandlung und der Steuerung des Parallelbetriebs auf der DB zuständig. DBS verwalten häufig riesige Datenmengen, auf die deshalb ein effizienter Zugriff möglich sein muss. Als erster Schritt zur Ermöglichung von Effizienz werden semantisch ähnliche Realweltobjekte durch eine identische Datenstruktur beschrieben. Sie werden auf vom Aufbau her identische Datensätze einer Relation abgebildet. Möchte man aus einer Relation alle Datensätze anzeigen, die eine bestimmte Bedingung erfüllen, also beispielsweise aus der Relation Mitarbeiter alle Mitarbeiter, die in Düsseldorf wohnen, so könnte dies bedeuten, dass jeder Datensatz der Relation vom Sekundärspeicher gelesen werden müsste, um zu überprüfen, ob er der gestellten Bedingung entspricht. Wenn jetzt beispielsweise eine Relation 100.000 Datensätze enthält, wovon nur 150 die Bedingung erfüllen, ist dieses sequenzielle Durchsuchen ein sehr langwieriger und kostspieliger Prozess. Um Zugriffe dieser Art zu beschleunigen, bieten DBMS die Möglichkeit, so genannte Zugriffspfade zu definieren. Ein Zugriffspfad erlaubt im Prinzip den inhaltsgesteuerten direkten Zugriff auf einen Datensatz. Ein Zugriffspfad über das Attribut Wohnort würde damit direkt alle Mitarbeiter liefern, die in Düsseldorf wohnen. Man unterscheidet Zugriffspfade auf dem Primärschlüssel, so genannte Primärindexe, und Zugriffspfade für einzelne Attribute (Einattributindexe) bzw. Attributkombinationen (Mehrattributindexe), so genannte Sekundärindexe. Umgesetzt werden Zugriffspfade über Hashverfahren und verschiedene Baumvarianten. Es ist Aufgabe des Optimierers, zu erkennen, ob bei der Abarbeitung einer Anfrage Zugriffspfade ausgenutzt werden können und wenn ja, welche. Zugriffspfade sollten insbesondere auf solchen Attributen angelegt werden, über die häufig assoziativ auf die DB zugegriffen wird. Die Idee, möglichst viele Attribute und Attributkombinationen mit Zugriffspfaden zu versehen, ist nicht immer gut, da Zugriffspfade natürlich auch einen höheren Verwaltungsaufwand mit sich bringen. Insbesondere im Fall von Änderungen müssen diese auch auf den Zugriffspfaden nachgezogen werden, wodurch sehr schnell ein zur ursprünglichen Absicht gegenteiliger Effekt eintreten kann - der Zugriff auf die DB wird bei Änderungen deutlich ineffizienter. In diesem Buch werden wir uns im Weiteren auf die Schnittstellen zur Anwendung und da insbesondere auf die Anfragesprache konzentrieren. Von den Interna eines DBMS werden lediglich noch die Synchronisation, die Recovery und das Backup behandelt, da die Entwicklung von fehlerfrei laufenden, effizienten Anwendungen ohne Kenntnis dieser Materie nicht möglich ist.
192
5.2
5 Einführung in Datenbankmanagementsysteme
Die Verwaltung von Metadaten
Ein relationales DBS stellt sich aus der Sicht des Anwenders zunächst einmal als eine Menge von Tabellen bzw. Relationen (SET OF SET OF TUPLE) dar. Jede Relation wiederum besteht aus einer Menge von Tupeln bzw. Datensätzen (SET OF TUPLE; siehe Abbildung 5.3). Alle Informationen stecken grundsätzlich in den Attributen der Datensätze. Dies ist eine sehr einfache Struktur und hat daher auch wesentlich zum Erfolg des relationalen Datenbankmodells beigetragen. Die Menge dieser aus Sicht der Anwendungen informationstragenden Datensätze bilden die (Menge der) Nutzdaten der DB. SET OF
←
SET OF
TUPLE ← Tupeltyp → ← Relation(enschema) → Datenbankschema →
Abb. 5.3: Datenstruktur eines konzeptuellen Datenbankschemas
Aus Sicht des Datenbankadministrators stellt sich eine DB etwas komplexer dar. Zu den Nutzdaten kommen die so genannten Beschreibungs- bzw. Metadaten hinzu. Sie beschreiben vor allem den Aufbau der DB, deren Speicherungsstrukturen und die aus Performanzgründen angelegten zusätzlichen Zugriffspfade auf die Daten. Zu den Metadaten gehören damit alle Daten über die Nutzdaten, also vor allem die Daten, die den logischen Aufbau und Inhalt einer DB (konzeptuelles Datenbankschema), die anwendungsspezifischen Sichten darauf (externes Datenbankschema) und die interne Repräsentation (internes Datenbankschema) beschreiben. Dazu kommen noch Informationen über die Abbildungen zwischen den einzelnen Datenbankebenen und weitere Informationen, die von spezifischen Datenbankkomponenten gebraucht werden, wie beispielsweise vom Optimierer, vom Datensicherheitsmodul oder von der Anfragekomponente. Abgelegt werden die Metadaten im so genannten Systemkatalog. Konzeptionell verbirgt sich bei relationalen DBMS hinter dem Systemkatalog allerdings nichts anderes als ein weiteres Datenbankschema. Metadaten werden also mit denselben Datenstrukturen und Operationen verwaltet wie die eigentlichen Nutzdaten. Gelegentlich wird statt von einem Systemkatalog auch von einem Data Dictionary gesprochen. Auch wenn hier nicht immer sauber differenziert wird, kann tendenziell doch eine gewisse Stufung ausgemacht werden. Unter einem Data Dictionary versteht man häufiger auch einen allgemeiner ausgelegten Systemkatalog. Bei einem Systemkatalog unterstellt man, dass er ausschließlich unter der Kontrolle des DBMS steht und insbesondere vom DBMS selbst zur Erledigung seiner Aufgaben genutzt wird. Er orientiert sich also eher an den Bedürfnissen der Datenbanksoftware. Ein Data Dictionary ist dagegen eine Art Datenkatalog, in dem vor allem Informationen über die Daten einer Unternehmung und den Datenmodellierungsprozess als solchen abgelegt werden, und zwar aus der Sicht der Datenbankdesigner, -benutzer und -administratoren. Zwar ist grundsätzlich nicht ausgeschlossen, dass auch DBS auf diese Informationen zugreifen, aber die generelle Stoßrichtung ist eher benutzerorientiert. Bei der allgemeinsten Definition eines Data Dictionary wird angenommen, dass es bereits während des Entwurfs eines (konzeptuellen) Datenbankschemas eingesetzt wird. Es enthält damit nicht nur die eigentliche Beschreibung der Daten der DB, sondern darüber hinaus
5.2 Die Verwaltung von Metadaten
193
das üblicherweise unter Zuhilfenahme eines ER-Modells entwickelte konzeptuelle Realweltschema. Diese Diskussion deutet schon darauf hin, dass das Data Dictionary oft ein eigenes Softwarepaket ist, welches separat vom DBS angelegt und verwaltet wird. Die allgemeinste Variante eines Datenkatalogs ist schließlich das Data Repository. Es ist noch allgemeiner ausgelegt als das Data Dictionary und wird dann eingesetzt, wenn sämtliche Daten und Informationen einer Unternehmung zentral verwaltet werden sollen. Ein Data Repository beschränkt sich also nicht nur auf die Verwaltung der Beschreibungen von in DB abgelegten Daten, sondern kann generell Informationen über beliebige Daten eines Unternehmens bzw. einer Organisation enthalten und zwar auf einer allgemeinen, systemunabhängigen Ebene (z. B. als ER-Diagramme). Der Systemkatalog eines relationalen DBMS wird in Form von Relationen abgelegt und verwaltet. Auch wenn teilweise eigene, optimierte Zugriffstechniken eingesetzt werden, unterscheidet sich die Verwaltung der Metadaten nicht von der der Nutzdaten. Insbesondere kann damit über die normale Anfragesprache auf den Systemkatalog zugegriffen werden. Beispielsweise werden die Beschreibungen der Relationenschemata im Normalfall in einer eigenen, speziell dafür angelegten Relation abgelegt. Diese Relation besteht aus solchen Attributen wie Relationenname, Attributname, Attributtyp, Primärschlüssel, Fremdschlüssel usw., wobei die letzten beiden Attribute als Boolesche Werte4 angesehen werden können. Sie geben Auskunft darüber, ob das durch diese Zeile beschriebene Attribut Bestandteil des Primär- bzw. eines Fremdschlüssels ist. Insgesamt wird eine DB aus der Sicht des Datenbankadministrators damit durch zwei Schemata repräsentiert, so dass zu Abbildung 5.3 mindestens noch eine weitere Ebene, nämlich SET OF SET OF SET OF TUPEL (= Menge von Datenbankschemata) hinzugefügt werden müsste. Es fällt jetzt leicht, dieses Bild insgesamt zu generalisieren, indem erlaubt wird, dass ein DBMS mehr als ein konzeptuelles Datenbankschema verwalten darf. Diese Erweiterung ist auch sinnvoll, da sie bei der Modularisierung der Datenzugriffe von Anwendungsklassen helfen kann. Anwendungsklassen, die in Bezug auf die Datennutzung keine Überschneidungen besitzen, können mit unterschiedlichen Datenbankschemata arbeiten und damit auf unterschiedlichen DB. Vorteile kann diese weitere Ebene auch in verteilten Umgebungen bringen, indem standortbezogen eigene Datenbankschemata und damit auch DB definiert und verwaltet werden können. Die Menge aller Datenbankschemata wird in SQL der Katalog der DB genannt (siehe Abbildung 5.4)5. Mit der in Abbildung 5.4 implizierten Definition einer DB mag der eine oder andere Leser jetzt Schwierigkeiten haben. Bisher waren wir davon ausgegangen, dass ein konzeptuelles Datenbankschema die Beschreibung einer DB ist. Abbildung 5.4 impliziert nun allerdings, dass erst eine Menge von konzeptuellen Datenbankschemata eine DB darstellt. Um dieser Begriffsüberladung zu entgehen, hat man beispielsweise im SQL-Standardisierungskomitee die in Abbildung 5.4 mit Datenbank bezeichnete Ebene SQL-Data6 genannt. Auch in diesem Buch soll die Überladung nur in diesem Abschnitt in Kauf genommen werden. In den fol4 Der
Boolesche Datentyp gehört nicht zu den von SQL-92 unterstützten Datentypen. Vorgriff auf den SQL-92-Standard. Die Aussagen, die in diesem Kapitel gemacht werden, beziehen sich auf den Standard und müssen deshalb nicht zwangsläufig auf beliebige kommerzielle relationale DBMS zutreffen. 6 Ob der Begriff glücklich ist, sei dahingestellt. 5 Genau genommen ist diese Diskussion schon ein kleiner
194
5 Einführung in Datenbankmanagementsysteme Die Datenbank Katalog konzeptuelles Datenbankschema Tabellen und Sichten Zeilen und Spalten
Abb. 5.4: Struktur einer Datenbank aus der Sicht von SQL7
genden Kapiteln wird mit Datenbank wieder eine Datenbank im Sinn der „alten“ Definition bezeichnet werden. Nun mag sich der gewiefte Leser fragen, ob die Existenz dieser neuen Ebene nicht eigentlich auch Auswirkungen auf die Datenmodellierung haben müsste. Grundsätzlich ist diese Frage zu bejahen. Doch gibt es praktisch keine Modellierungswerkzeuge, die die Katalogebene berücksichtigen. Es wird eher den faktischen Gegebenheiten, falls beispielsweise schon Datenbankschemata bestehen, die unter einem Katalog verwaltet werden sollen, oder der Intuition des Datenbankdesigners überlassen, hier eigene Grenzen und Regeln zu definieren. Grundsätzlich gilt nach wie vor, dass man alle Relationen aller Anwendungsklassen in ein konzeptuelles Datenbankschema stecken könnte. Anwendungsklassenspezifische Sichten würden wie üblich über externe Schemata realisiert. Diese Lösung hat nach wie vor viel für sich, insbesondere wenn die Datenüberlappungen zwischen den einzelnen Sichten nennenswert sind. Sind solche Überlappungen jedoch eher unbedeutend, kann das Aufteilen der Daten auf mehrere Datenbankschemata durchaus sinnvoll sein. Damit wäre automatisch eine kostengünstige und effiziente Isolation der einzelnen Anwendungsklassen voneinander garantiert, was sich günstig auf die Performanz des Systems auswirken wird. Ein Problem bei der Verwaltung einer DB im Sinn von Abbildung 5.4 ist die Eindeutigkeit von Namen. Es gelten folgende Regeln: Innerhalb einer Relation müssen die Attributnamen eindeutig sein, jedoch nicht über Relationen hinweg. Das Gleiche gilt für Relationennamen innerhalb eines Datenbankschemas und für Datenbankschemanamen innerhalb eines Katalogs. Bewegt man sich innerhalb eines Datenbankschemas, reicht es damit, wenn man beispielsweise eine Relation direkt über ihren Namen anspricht. Für das DBMS ist dies jedoch eine Abkürzung. Intern wird ein Relationenname durch eine Kombination aus dem Katalog, Datenbankschema- und Relationennamen dargestellt (Katalogname.Datenbankschemaname.Relationenname). Durch diese implizite Erweiterung von Namen ist sichergestellt, dass die Freiräume bei der Namengebung nicht dazu führen können, dass die Vergabe von 7 Genau genommen impliziert diese Abbildung, dass es sogar noch eine weitere Ebene, die Ebene der Menge von Katalogen gibt. Grundsätzlich gilt für diese Ebene dasselbe wie für die Ebene der Datenbankschemata. Deshalb soll diese Ebene hier auch nicht weiter diskutiert werden.
5.3 Literatur
195
identischen Namen in unterschiedlichen Relationen, Datenbankschemata oder Katalogen zu Mehrdeutigkeiten führen kann. Nach dem SQL-Standard ist es sogar möglich, aus einem Datenbankschema heraus auf ein anderes zuzugreifen. Soll beispielsweise von einer unter dem Datenbankschema Schema1 laufenden Anwendung auf eine Relation Relx von Datenbankschema Schema2 zugegriffen werden, so ist allerdings vorgeschrieben, dass die „importierte“ Relation Relx um ihren Datenbankschemanamen ergänzt werden muss, also auf Relx über den erweiterten Namen Schema2.Relx zugegriffen werden muss. Mit Abschluss dieses Kapitels soll auch der Ausflug in die „erweiterte“ Datenbankdefinition beendet sein. Zukünftig werden wir wieder so tun, als würde eine relationale DB ausschließlich durch die in Abbildung 5.3 aufgezeigte Datenstruktur beschreibbar sein.
5.3
Literatur
Auf dem Gebiet der DBMS gibt es zwischenzeitlich eine Vielzahl von Büchern, so dass eine Auflistung von Literatur zwangsläufig unvollständig sein muss. Auch hat sich hier neben den eher konzeptuell ausgerichteten Lehrbüchern ein sehr breites Spektrum an praxisbezogenen Büchern etabliert. Diese unterscheiden sich von den Lehrbüchern dadurch, dass sie sich auf spezifische Systeme konzentrieren (wie Oracle, DB/2) oder sich mit der Schnittstelle des DBMS, der Anfragesprache und damit überwiegend mit SQL auseinander setzen. Dafür fehlt bei diesen Büchern in der Regel die grundsätzliche Diskussion von Konzepten. Im Folgenden sind einige Datenbanklehrbücher aufgelistet, von denen wir glauben, dass sie als Ergänzung zu diesem Buch gut geeignet sind. Diese Bücher decken alle ein mehr oder weniger großes Spektrum an datenbankspezifischen Themen und Konzepten ab und können daher als generelle Literatur zu diesem Thema angesehen werden. Sie können daher auch immer als Ergänzung zu allen folgenden Literaturhinweisen aufgefasst werden. Auch auf dem Lehrbuchmarkt für DBMS lassen sich zwei Gruppen von Büchern erkennen. Die eine Gruppe führt das Gebiet aus dem Blickwinkel der Datenbanktheorie und damit auf der Basis eines soliden theoretischen Fundaments ein. Diese Bücher konzentrieren sich auf die formalen Grundlagen relationaler DBMS und auf die Grundlagen und Basiskonzepte von Anfragesprachen. Zu dieser Klasse gehören [AbHV95], [AtDe93], [Bisk95], [CeGT90], [CrGH94], [DeLR94], [GaMi78], [GaMN81], [GaVa89], [KaKl93], [Maie83], [PDGV89], [Ullm88+89] und [Yang86]. Die zweite Gruppe behandelt den Stoff in einer pragmatischeren und mehr auf die Praxis ausgerichteten Form. Dazu gehört auch, dass Themen wie Transaktionsmanagement, Optimierung und Speicherungsstrukturen bzw. allgemeiner gesagt Implementierungstechniken behandelt werden. Zu dieser Gruppe von Büchern gehören [Codd90], [CoMR12], [DaDa97], [Date03], [ElNa10], [GaRö95], [HaWi93], [HoRT12], [KeEi11], [KlRa05], [LaLo95], [LoSc87], [Lust03], [UnMa12], [Onei00], [Rica90], [RySm95], [SaHS12+SaSH13], [Saue02], [SiKS10], [ScSt83], [Stei02], [Voss08]. Tiefen Einblick in die Interna eines DBMS gewährt Michael Stonebraker in seinem Buch über das von seiner Gruppe entwickelte relationale DBMS INGRES [Ston86]. Wer mehr Wert auf eine systemneutrale Behandlung des Stoffes legt, ist mit dem Buch von Theo Härder und Erhard Rahm [HäRa01] oder den entsprechenden Kapiteln von Peter Lockemann, Klaus Dittrich und Theo Härder in [LoSc87] sehr gut bedient.
6
Grundlagen von Anfragesprachen
Zu den wesentlichen Errungenschaften moderner DBMS gehört, dass sie eine einfach zu handhabende Schnittstelle anbieten, über die (Ad-hoc-)Anfragen an die DB gestellt werden können. Eine gute Anfragesprache muss einige Kriterien erfüllen, die in diesem Kapitel diskutiert werden sollen. Begonnen werden soll jedoch zunächst mit einer kurzen formalen Einführung in wesentliche Konstrukte zum Datenbankdesign.
6.1
Formale Einführung der Grundlagen von Datenbankmodellen
In diesem Unterkapitel sollen die bereits im ersten Teil des Buches eingeführten Basiskonstrukte und Hilfsmittel zur Datenbankmodellierung auf einer etwas formaleren Ebene diskutiert werden. Damit soll insbesondere die Grundlage für die Diskussion der Datendefinitionssprache eines DBMS gelegt werden, da diese auf dem Datenbankmodell aufsetzen muss und damit dessen wesentliche Konstrukte widerzuspiegeln hat. Den meisten Lesern dürfte der Begriff Datentyp bereits aus der Programmiersprachenwelt bekannt sein. Ein Datentyp besteht aus einer möglicherweise unendlichen Menge von Werten, dem so genannten Wertebereich, und einer Menge von Operationen, die auf den Werten des Wertebereiches ausgeführt werden können. In Programmiersprachen kann der Compiler dann feststellen, ob in einem Programm einer Variablen immer ein Wert aus dem Wertebereich des ihr zu Grunde liegenden Typs zugewiesen wird und ob auf ihr nur solche Operationen ausgeführt werden, die auch für diesen Typ zulässig sind. Dadurch wird die Programmsicherheit erhöht, da Laufzeitfehler aufgrund von unzulässigen Zuweisungen an die Variablen oder Operationen auf den Variablen ausgeschlossen sind. Das Konzept des Datentyps dient aber auch der Effizienzsteigerung, da die Frage, welche exakte Implementierung zur angesprochenen Operation gehört, bereits zur Compilezeit entschieden wird. Verzweigungen zu dem entsprechenden Prozedurcode können deshalb „fest verdrahtet“ werden, sodass zur Laufzeit nur minimaler Overhead anfällt. Man kann eine Datentypdefinition auch als eine Integritätsbedingung ansehen, die festlegt, wie Werte dieses Datentyps auszusehen haben und welche Operationen auf ihnen ausgeführt werden dürfen. Datentypen können auf einer eher feinen oder einer eher groben Ebene spezifiziert werden. (Imperative) Programmiersprachen bieten häufig nur einen fest vorgegebenen Satz von eher grobkörnigen Datentypen an, wie INTEGER, REAL, CHARACTER und BOOLEAN. Zwar kann
198
6 Grundlagen von Anfragesprachen
mit diesen relativ flexibel umgegangen werden, andererseits wird aber viel von dem verschenkt, was eigentlich mit Datentypen erreicht werden soll: Sicherheit bzw. Konsistenz. So kann auf dieser groben Ebene beispielsweise das als INTEGER-Wert deklarierte Alter eines Menschen (versehentlich) unverhältnismäßig hoch oder sogar negativ belegt werden. Oder die ebenfalls als INTEGER-Wert deklarierte Artikelnummer eines Artikels könnte über Additions- und Multiplikationsoperationen manipuliert werden, was im Normalfall eindeutig als unzulässige Operation anzusehen ist. Auch bereitet es keine Probleme, eine Artikelnummer mit dem Alter eines Menschen zu vergleichen, eine im normalen Leben sicherlich unsinnige Operation. Aus diesen Gründen bieten manche Programmiersprachen, wie beispielsweise PASCAL, die Möglichkeit, anwendungsspezifische bzw. benutzereigene Datentypen zu deklarieren. Damit ist es möglich, den Wertebereich des neu definierten Datentyps Alter auf die ganzen Zahlen von 1 bis 150 zu beschränken. Der Vergleich von Alter und Artikelnummer wäre unmöglich, da es sich jetzt um unterschiedliche Datentypen handeln würde. Andererseits erkauft man sich die Erhöhung der Sicherheit und Konsistenz durch geringere Flexibilität. So ist es beispielsweise nicht mehr möglich, Werte aus dem einen Wertebereich mit Werten aus einem anderen Wertebereich zu vergleichen, auch wenn ein solcher Vergleich sinnvoll sein könnte. So würde sich in einem feingranularen Typsystem das Alter eines Baumes nicht mehr ohne weiteres mit dem Alter eines Hundes vergleichen lassen, wenn beide als eigene Datentypen angelegt würden (Baum: die INTEGER-Werte 1 bis 1000; Hund: die INTEGER-Werte 1 bis 20). Solche Beziehungen zwischen unterschiedlichen Datentypen könnten nur noch über explizite Kompatibilitätsregeln hergestellt werden, die festlegen, wie der Abbildungsprozess aus einem Wertebereich in den anderen zu erfolgen hat. Nach dieser kurzen Motivation sollen zunächst (Varianten von) Datentypen und dann, darauf aufbauend, der Begriff Datenbankmodell etwas formaler eingeführt werden1. Das Basiskonstrukt eines jeden Datenmodells ist der Datentyp. Definition 6.1: Datentyp (data type) Ein Datentyp wird beschrieben durch • eine möglicherweise unendliche Menge von Werten, dem so genannten Wertebereich des Typs, • die Menge aller auf diesen Werten ausführbaren Operationen und • eine Menge von Integritätsbedingungen, die das Arbeiten auf dem Datentyp reglementieren bzw. festlegen. Eine Typbeschreibung ist also eine abstrakte Beschreibung, die festlegt, wie Elemente dieses Typs aussehen müssen, welche Operationen auf ihnen anwendbar sind und welche Bedingungen beachtet werden müssen. Werte sind ausschließlich über die vorgegebenen Operationen zugreifbar und manipulierbar. 1 Wie bereits vorher erwähnt, ist der Begriff Datenmodell semantisch überladen. Einerseits wird damit das mit den vorgegebenen Mitteln eines spezifischen Werkzeuges zusammengesetzte Modell von etwas Gegebenem bezeichnet, andererseits aber eben auch das Werkzeug selber, also die Beschreibung der grundlegenden Konzepte, mit deren Hilfe das „Vorbild“ modelliert werden kann. In diesem Unterkapitel wird der Begriff ausnahmslos im Sinn von Werkzeug verwendet.
6.1 Formale Einführung der Grundlagen von Datenbankmodellen
199
Es sei noch angemerkt, dass Werte nicht atomar aufgebaut sein müssen (siehe Definition 6.3), sondern auch komplex strukturiert sein können (siehe Definition 6.5). Konkrete Vorkommen von Elementen eines Typs werden Ausprägungen oder Instanzen dieses Typs genannt. Beispiel 6.1: Datentypen Der allseits bekannte Datentyp INTEGER wird beschrieben durch: {0, 1, −1, 2, −2, 3, −3, . . .} Wertebereich {Addition, Subtraktion, Multiplikation, . . .} bzw. {+, −, ∗, . . .} Operationen Genau genommen müssten bei den Operationen mindestens noch die Ein- und Ausgabeparameter und deren Datentyp angegeben werden2 , sodass beispielsweise die Addition wie folgt definiert wäre: + (IN: int1: INTEGER, int2: INTEGER; OUT: int3: INTEGER) Während in der relationalen Datenbankwelt Typen nicht hierarchisch angeordnet werden können, können sie insbesondere in objektorientierten Umgebungen Ausgangspunkt für die Konstruktion neuer speziellerer Typen sein. Man spricht dann von Unter- und Obertypen und insgesamt von einer Typhierarchie, oft gekoppelt mit dem Konzept der Vererbung. Beide Konzepte werden durch den SQL-92-Standard noch nicht unterstützt, sind aber seit dem Nachfolgestandard SQL:1999 vertreten. Definition 6.2: Unter- und Obertyp T U ist ein Untertyp vom Obertyp T O , falls auf T U mindestens die Operationen ausgeführt werden können, die auch auf T O definiert sind. Im Normalfall wird T U noch zusätzliche Operationen unterstützen. Wie weiter unten noch gezeigt wird, gehören so genannte atomare Datentypen zu den Grundbausteinen von Datenmodellen. Definition 6.3: Atomarer Datentyp (atomic data type) Ein atomarer (einfacher, elementarer, Basis-) Datentyp ist ein Datentyp, dessen Werte sich aus der Sicht der Anwendung nicht weiter zerlegen lassen. Entscheidend für die Atomarität ist die durch die Anwendung mit dem Datentyp verbundene Semantik und nicht, ob etwas grundsätzlich noch weiter zerlegbar ist. So kann eine Zeichenkette aus der Sicht der einen Anwendung noch weiter in ihre einzelnen Zeichen zerlegbar sein, während sie aus der Sicht einer anderen Anwendung schon einen atomaren Datentyp darstellt. Aus atomaren Datentypen lassen sich mithilfe von so genannten Typkonstruktoren komplexere Datentypen zusammensetzen. 2 Wird
häufig auch Signatur einer Operation genannt.
200
6 Grundlagen von Anfragesprachen
Definition 6.4: Typkonstruktor (type constructor) Ein Typkonstruktor ist eine Art typunabhängige Schablone (Strukturbeschreibung), die genutzt werden kann, um aus (atomaren) Datentypen komplexer strukturierte Datentypen zu erstellen. Typunabhängig bedeutet dabei, dass zwar die Struktur des neuen Datentyps durch den Typkonstruktor festgelegt wird, allerdings noch nicht, mit welchen Werten welchen Datentyps diese Struktur später belegt sein wird. Erst eine Kombination aus Typkonstruktor und Datentyp(en) beschreibt einen (neuen) Datentyp. Beispiel 6.2: Typkonstruktor Array, Tupel oder Menge sind Typkonstruktoren. Sie sind typunabhängig, da sie lediglich eine Aufbauvorschrift darstellen, aber noch keine Aussage über den Inhalt liefern. Ein Array kann beispielsweise genutzt werden, um einen neuen Datentyp IntegerArray zu erstellen, dessen Instanzen aus einer Folge von bis zu zehn geordneten INTEGER-Werten bestehen können. TYPE IntegerArray: ARRAY[1:10] OF INTEGER Wenn man Typkonstruktoren und (atomare) Datentypen beliebig einsetzt, um (rekursiv) komplexere Datentypen zu erstellen, so erhält man strukturierte Datentypen. Definition 6.5: Strukturierter Datentyp (structured (composite) data type) Ein strukturierter bzw. zusammengesetzter Datentyp ist wie folgt definiert: 1. Er ist aus gleichartigen (gleicher Typ) oder unterschiedlichen (unterschiedliche Typen) Komponenten mithilfe von Typkonstruktoren zusammengesetzt worden. 2. Die über den Komponenten liegende Struktur kann eine (teilweise) Ordnung vorgeben. 3. Will ein Benutzer auf einen strukturierten Datentyp zugreifen, muss er dessen Struktur beim Zugriff berücksichtigen. Er muss also die vom Typkonstruktor bereit gestellten Operationen für die Struktur nutzen. Insgesamt muss ein strukturierter Datentyp damit (rekursiv) Operationen auf den zu Grunde liegenden (elementaren) Datentypen und Operationen zum Arbeiten auf der Datenstruktur anbieten. Beispiel 6.3: Strukturierte Datentypen 1. ARRAY IntegerArray [1:10] OF INTEGER (a) Gleichartige Komponenten; ausschließlich INTEGER-Werte, evtl. ergänzt um einen speziellen Wert für nicht belegt (b) Totale Ordnung (c) Operationen Struktur: Operationen Typ:
z. B. direkter Zugriff auf einen Wert über seine Position siehe Beispiel 6.1
6.1 Formale Einführung der Grundlagen von Datenbankmodellen
201
2. RECORD Person BEGIN name: CHARACTER STRING; größe: INTEGER; geschlecht: BOOLEAN; . . .; END; (a) Unterschiedliche Komponenten (b) Zwar gibt es eine feste Anordnung der Attribute, man unterstellt normalerweise aber keine Ordnung; beispielsweise ist ein Zugriff auf die x-te Komponente eines Records nicht möglich, da Positionen nicht festgelegt sind; es sei aber schon hier darauf hingewiesen, dass ein positionsbezogener Zugriff bei der relationalen Anfragesprache SQL in gewissen Fällen möglich ist. (c) Operationen Struktur: Operationen Typ:
z. B. direkter Zugriff auf eine Komponente über den innerhalb eines Records eindeutigen Namen sind für jeden Datentyp unterschiedlich
3. SET OF Person (a) Gleichartige Komponenten (alle Komponenten vom Datentyp Person) (b) Keine Ordnung (c) Operationen Struktur: Operationen Typ:
z. B. sequenzielles Durchlaufen der Menge, assoziativer Zugriff über den Inhalt (Selektion), Projektion Operationen auf dem Typ RECORD (siehe 2.); Operationen auf den Basisdatentypen (siehe Basisdatentypen bzw. Beispiel 6.1)
Ein im relationalen Datenbankmodell sehr wichtiger Typkonstruktor ist die Menge, mit deren Hilfe sich mengenwertige Datentypen erstellen lassen. Definition 6.6: Mengenwertiger Datentyp Ein mengenwertiger Datentyp ist ein strukturierter Datentyp, der durch (einmalige) Anwendung des Typkonstruktors Menge entstanden ist (siehe Beispiel 6.3c). Auf ihn treffen demnach alle Eigenschaften einer Menge zu, also insbesondere dass er unsortiert ist, dass alle Elemente vom selben Typ sind und dass er keine Duplikate enthält. Um mit Datentypen sauber arbeiten zu können, ist es notwendig zu wissen, unter welchen Umständen ein gegebener Datentyp mit einem anderen Datentyp kompatibel ist. Definition 6.7: Typkompatibilität Zwei Datentypen T1 und T2 sind miteinander kompatibel, falls beide entweder völlig übereinstimmen oder es eine Menge von Regeln gibt, die exakt festlegt, wie die Werte des einen Datentyps auf die Werte des anderen abgebildet werden können und umgekehrt. Auch müssen auf beiden Datentypen die gleichen Operationen anwendbar sein.
202
6 Grundlagen von Anfragesprachen
Im Zusammenhang mit Vererbung liegt Kompatibilität auch dann vor, falls der eine Typ ein Untertyp des anderen Typs ist (in diesem Fall ist der Untertyp zum Obertyp kompatibel, nicht umgekehrt).3 Kompatibilität von Datentypen ist in anderer Form schon aus manchen Programmiersprachen bekannt, wo in Ausdrücken verschiedene numerische Datentypen fast beliebig miteinander gemischt werden können, was bei strenger Typisierung verboten ist. Programmiersprachen arbeiten allerdings i. d. R. nicht mit Kompatibilitätsregeln. Stattdessen nimmt das Laufzeitsystem nötigenfalls eine implizite Typumwandlung vor (coercion genannt), wodurch beispielsweise ein INTEGER-Wert in einen REAL-Wert umgewandelt werden kann. Ein Datenbankmodell ist ein spezifisches Datenmodell, das sich dadurch auszeichnet, dass es auf die Bedürfnisse einer konsistenten Verwaltung von Datenmengen zugeschnitten ist. Es reflektiert, dass mit großen Mengen von Daten umzugehen ist, dass diese Daten im Sinn einer Kategorisierung mithilfe von möglichst wenigen unterschiedlichen Datenstrukturen dargestellt werden sollen, dass hohe Konsistenzanforderungen an Daten und -übergänge zu stellen sind und dass auf solche Daten mengenorientiert zugegriffen werden wird. Definition 6.8: Datenbankmodell Ein Datenbankmodell spezifiziert die folgenden Merkmale und Eigenschaften: 1. Die (atomaren) Datentypen und die zulässigen Typkonstruktoren, 2. die erlaubten Operationen auf Datentypen und Typkonstruktoren; insbesondere auch die Operationen zum Anlegen, Ändern, Löschen und Lesen, 3. die Regeln, die die genaue Verwendung von Datentypen und Typkonstruktoren festlegen und 4. Regeln und Konstrukte, wie Integritätsbedingungen an Daten und Datenübergänge gestellt werden können. Beispiel 6.4: Datenbankmodell eines relationalen DBMS 1. Atomare Datentypen: • (SHORT)INTEGER • CHARSTRING [Länge] • DATE
• REAL [vor Komma, nach Komma] • BYTESTRING [Länge] • TIME ...
2. Typkonstruktoren: • Tupel (Record) mit entsprechenden Operationen auf Tupeln • Set (Relation) mit entsprechenden Operationen auf Mengen 3 Vererbung wird später noch im Zusammenhang mit dem onjektrelationalen SQL diskutiert. Deshalb soll diese Definition hier so stehen bleiben.
6.1 Formale Einführung der Grundlagen von Datenbankmodellen
203
3. Operationen: Die üblichen Operationen auf den Basisdatentypen (wie z. B. in Beispiel 6.1 angegeben) und Typkonstruktoren. 4. Regelwerk: Keine geschachtelte Anwendung von Typkonstruktoren erlaubt, nur: (a) TUPEL BEGIN Liste von Attributen atomaren Typs END
/* Definition eines strukturierten Typs aus atomaren Datentypen
(b) SET OF TUPEL
/* Relationenschema
(c) SET OF SET OF TUPEL
/* Menge von Relationenschemata
(d) SET OF SET OF SET OF TUPEL
/* Menge von Datenbankschemata
Ein Datenbankschema entsteht ausschließlich durch die Anwendung der Typkonstruktoren Tupel und zweimal Set in genau dieser Reihenfolge. 5. Integritätsbedingungen: Hierzu zählen die Möglichkeiten, Schlüsseltypen (Primärschlüssel, Schlüsselkandidaten) zu definieren und die referenzielle Integrität sicherzustellen, aber auch das Konzept der Datenbankprozeduren (stored procedures). Beispiel 6.4 kann entnommen werden, dass die Definition eines Relationenschemas auf dem ersten Blick der Definition eines strukturierten Datentyps entspricht. Dementsprechend müsste man auch konsequenterweise nicht von der Definition eines Relationenschemas sprechen, sondern von der eines strukturierten Datentyps oder, da dieser Datentyp sich immer als SET OF TUPEL darstellt (siehe Abbildung 5.3), von der Definition eines Relationentyps. Wie später noch klar wird, kann man mit den aktuellen Datendefinitionssprachen herkömmlicher relationaler DBMS keine anders aufgebauten Datentypen definieren. Vielmehr wird die Einhaltung des Regelwerks aus Beispiel 6.4 implizit dadurch gewährleistet, dass nur Relationenschemata definiert werden können4, weshalb die Punkte (a) und (b) aus Beispiel 6.4 (3.) automatisch erfüllt sind. Ein Schema unterscheidet sich von einem Typ dadurch, dass bei einer Definition eines Relationenschemas nicht nur der zu Grunde liegende Typ, sondern (implizit) auch noch dessen (logischer) Speicherbehälter festgelegt wird. In diesem werden alle Objekte (Instanzen) dieses Typs abgelegt. Die aus Sicht einer sauberen Schemadefinition notwendige Möglichkeit, zunächst einen Daten- bzw. Tupeltyp TTyp definieren zu können, um dann mehrere Relationen dieses Typs anzulegen, ist bisher nicht vorgesehen5. Will man zwei Relationen gleicher Struktur anlegen, geht dies nur, indem man alle zu den Relationen gehörenden Attributdefinitionen bei der Definition der Schemata jeweils wiederholt (copy and paste). Ändert sich später etwas an der Definition dieser Relationen, sind die Änderungen in jeder Definition gesondert 4 Wie bei der Diskussion von Basisdatentypen noch näher erläutert werden wird, ist diese Aussage etwas zu relativieren. Ihr grundsätzlicher Aussagegehalt trifft jedoch zu. 5 Diese Möglichkeit wird aber seit SQL:1999 durch den objektrelationalen Teil unterstützt (und nur durch diesen Teiln).
204
6 Grundlagen von Anfragesprachen
durchzuführen. Da dies ausschließlich im Verantwortungsbereich des Anwenders liegt, besteht die Gefahr, dass notwendige Änderungen übersehen werden. Beispiel 6.5: Relationenschema und Relationentyp 1. Es sollen zwei Relationen vom Typ Person angelegt werden, eine für Mitarbeiter, die zweite für Kunden. In der später noch genauer einzuführenden relationalen Datendefinitions- und -manipulationssprache SQL würde die Definition vereinfacht wie folgt durchzuführen sein: CREATE TABLE nummer name vorname
Mitarbeiter ( INTEGER, CHARACTER(30), CHARACTER(30));
CREATE TABLE nummer name vorname
Kunden ( INTEGER, CHARACTER(30), CHARACTER(30));
2. Diese auf einen Relationentyp basierende Variante ist in SQL-926 nicht zulässig CREATE TABLE TYPE Person ( nummer INTEGER, name CHARACTER(30), vorname CHARACTER(30)); CREATE TABLE CREATE TABLE
Mitarbeiter OF TYPE Person; Kunden OF TYPE Person;
Die Konsequenz ist, dass im Fall einer Änderung nicht einfach an entsprechender Stelle eine Typdefinition geändert werden kann, wodurch diese Änderungen automatisch an alle Relationen dieses Typs durchgereicht würden. Würde beispielsweise in Variante 2. der Typ Person um die Attribute plz und ort erweitert, wären diese Änderungen direkt bei Mitarbeiter und Kunden sichtbar. Dies geht jedoch nicht. Stattdessen muss jede betroffene Relation explizit geändert werden, in Variante 1. also Mitarbeiter und Kunden. Nun mögen einige argwöhnen, dass die Vermengung von Typ- und Behälterdefinition zur Konsequenz hat, dass die Tupel der Relationen Mitarbeiter und Kunden nicht typkompatibel, mithin nicht miteinander vergleichbar sind. In Programmiersprachen wie PASCAL wäre dem auch so. In SQL wird Typkompatibilität jedoch auf der Ebene der Basisdatentypen von Attributen festgestellt. Zwei Attribute sind typkompatibel, falls sie sich auf denselben Basisdatentyp zurückführen lassen. Zwei Tupel bzw. zwei Tabellen sind typkompatibel, falls sie 6 Aber
im objektrelationalen SQL als CREATE TYPE-Statement, wie in Kapitel 8.2.4 diskutiert wird.
6.2 Typen von Relationen
205
die gleiche Anzahl von Attributen besitzen, die Attribute typkompatibel sind und die gleichen Namen haben. Sollten trotz gleichen Typs die Attribute unterschiedliche Namen besitzen, müssen diese erst durch Umbenennung angepasst werden. Schon diese Diskussion deutet an, dass streng genommen die Definition eines Relationenschemas keine Datentypdefinition ist. Wir werden auf diese Diskussion später noch zurückkommen. Aus unserer Sicht wäre es konsequenter gewesen, wenn man, wie in Variante 2. von Beispiel 6.5, Typ- und Behälterdefinition voneinander getrennt hätte und damit zwischen der reinen Definition eines Typs und dem Anlegen eines Behälters (Relation) unterschieden hätte. Dies würde der Unterscheidung zwischen dem Anlegen eines Typs und einer Variable in PASCAL ähneln. Da relationale Datenbankmodelle diese Trennung allerdings noch nicht vorsehen, werden wir auch weiterhin den allgemein eingebürgerten Begriff Relationenschema nutzen. Nur wenn explizit die Typeigenschaft im Vordergrund steht, werden wir auch den Begriff Relationentyp verwenden. Es sei noch angemerkt, dass der SQL-92-Standard zwar die Definition neuer atomarer, nicht aber strukturierter (komplexer) Wertebereiche unterstützt.
6.2
Typen von Relationen
Gerade bei der Diskussion von Anfragesprachen werden immer wieder unterschiedliche Typen von Relationen angesprochen werden, die deshalb an dieser Stelle eingeführt werden sollen (siehe Tabelle 6.1).
benannt
physisch
abgeleitet
Abgeleitete Relation
k.A.
k.A.
ja
nein
Ausgangsrelation
nein1
nein1
ja1
ja; Relation, auf der eine Anfrage ausgeführt wird
Basisrelation
ja
ja
nein
ja; alle Relationen, die zum konzeptuellen Datenbankschema gehören
Benannte Relation
ja
k.A.
k.A.
nein
nein2
nein2
ja2
ja; Ergebnis einer Anfrage
Materialisierte Relation
ja
ja
ja
nein
Schnappschussrelation
ja
ja
k.A.
nein
Sicht
ja
nein
ja
ja; Ausschnitt, den Benutzer/Anwendung von der DB sieht
Virtuelle Relation
ja
nein
ja
nein
Zwischenrelation
nein
nein
ja
ja; Zwischenergebnis einer Anfrage
Ergebnisrelation
1
kontextabhängig
Ausnahme: Die Ausgangsrelation ist exakt eine Basisrelation. Ausnahme: Die Anfrage bezieht sich genau auf eine vollständige Basisrelation. k.A.: Keine Aussage möglich, i. d. R. weil beide Möglichkeiten zutreffen können.
2
Tabelle 6.1: Typen von Relationen
206
6 Grundlagen von Anfragesprachen
• Benannte Relation Eine benannte Relation ist eine mit einem Namen versehene Relation. • Basisrelation Eine Basisrelation ist eine benannte Relation, die Bestandteil des konzeptuellen Datenbankschemas ist. Daher existiert für sie nicht nur eine logische, sondern auch eine physische Repräsentation in der DB. • Abgeleitete Relation Eine abgeleitete Relation ist eine durch Anwendung von relationalen Operatoren aus einer oder mehreren Relationen abgeleitete Relation. • Virtuelle Relation Eine virtuelle Relation ist eine benannte abgeleitete Relation, von der kein physisches Abbild in der DB existiert. • Ergebnisrelation/Anfrageergebnis Die Ergebnisrelation bzw. das Anfrageergebnis ist die Relation, die als Ergebnis der Ausführung einer Anfrage an die DB entsteht. • Ausgangsrelation Den Begriff Ausgangsrelation werden wir insbesondere im Zusammenhang mit deskriptiven Anfragesprachen verwenden. Bei solchen Sprachen kann man sich eine Anfrage so vorstellen, dass in ihr – der Aufbau der Relation beschrieben wird, auf der die Anfrage ausgeführt werden soll (Ausgangsrelation), – die Kriterien festgelegt werden, die die Tupel der Ausgangsrelation erfüllen müssen, damit sie zur Ergebnisrelation gehören und – der Aufbau der Ergebnisrelation beschrieben wird. Der Begriff Ausgangsrelation soll nicht genauer definiert werden. Er wird im Text eher intuitiv verwendet werden.7 • Zwischenrelation Eine Zwischenrelation ist eine unbenannte abgeleitete Relation, die als Zwischenschritt bei der Berechnung einer Ergebnisrelation erzeugt wird. Sie dient als Ausgangspunkt für weitere Verarbeitungsschritte. • Eine Sicht ist eine benannte abgeleitete Relation. Sie spiegelt die speziell angepasste Sicht einer Benutzergruppe oder Anwendung auf einen Teil der DB wider. Sichten stellen im Normalfall virtuelle Relationen dar. • Gespeicherte bzw. materialisierte Relation Eine materialisierte Relation stellt eine Sicht dar, die auch physisch in der DB gehalten wird. Das Materialisieren einer Sicht macht vor allem dann Sinn, wenn Änderungen auf den zu Grunde liegenden Relationen vergleichsweise selten sind, auf die Sicht jedoch häufig lesend zugegriffen wird und diese Zugriffe engen Zeitrestriktionen unterliegen. Besteht 7 Genau genommen erwarten beispielsweise Anfragen mit Mengenoperationen wie z. B. ∩, ∪, − oder ÷ als Operanden zwei oder mehr Ausgangsrelationen.
6.3 Anforderungen an Anfragesprachen
207
eine Sicht beispielsweise aus einem Verbund von drei Basisrelationen und wird durchschnittlich erst nach jedem tausendsten Zugriff eine der Basisrelationen der Sicht geändert, so bedeutet die Materialisierung der Sicht, dass der sie beschreibende Verbund nur einmal berechnet werden muss und nicht bei jeder der 1.000 Leseanfragen erneut. Dies ist deshalb sehr interessant, weil gerade die mit der Sichtenberechnung verbundenen Verbundoperationen vergleichsweise sehr teure und zeitaufwändige Operationen darstellen. Der mit einer materialisierten Sicht verbundene Nachteil liegt darin, dass die Sicht mit jeder Änderung auf einer der zu Grunde liegenden Relationen ungültig wird und an sich neu berechnet werden müsste. Insbesondere bei statistischen Auswertungen von Datenmaterial ist die absolute Aktualität aller Daten oft nicht unbedingt notwendig, sodass gerade auch sie gut auf materialisierten Sichten arbeiten könnten. Eine materialisierte Sicht entspricht in ihrem Verhalten einer Basisrelation, ist jedoch im Gegensatz zu dieser i. d. R. nur für einen begrenzten Zeitraum gültig und existent. Von einer Schnappschussrelation unterscheidet sie sich dadurch, dass letztere grundsätzlich nicht änderbar ist, während eine materialisierte Sicht bei Änderungen durchaus auch angepasst bzw. neu berechnet werden könnte. Zudem stellt ein Schnappschuss einen irgendwann einmal gültig gewesenen Zustand der DB dar, während man bei einer materialisierten Sicht üblicherweise unterstellt, dass sie einen im Wesentlichen aktuellen Zustand der DB wiedergibt. • Schnappschussrelation Eine Schnappschussrelation ist eine materialisierte Relation, die genau einen Zustand einer Relation „einfriert“. Aus logischer Sicht dokumentiert sie ein unveränderliches Abbild (Schnappschuss) eines zu irgendeinem Zeitpunkt einmal gültig gewesenen Realwelt- und damit Datenbankzustandes. Die in diesem Buch verwendeten Relationentypen sind noch einmal in Tabelle 6.1 zusammengefasst. Die erste Spalte gibt Auskunft darüber, ob die mit dem Begriff bezeichnete Relation einen Namen besitzt, über den sie angesprochen werden kann. Die zweite Spalte besagt, ob diese Art von Relation üblicherweise auch physisch existent ist. In Spalte drei wird festgehalten, ob sich eine Relation dieser Art aus (Teilen von) einer oder mehreren anderen Relationen zusammensetzt. In der vierten Spalte steht ein Ja, falls der Begriff immer in einem bestimmten Kontext Verwendung findet.
6.3
Anforderungen an Anfragesprachen
Anfragesprachen stellen die Schnittstelle des DBMS zur Außenwelt dar. Dabei ist ein breites Spektrum an potenziellen Nutzern zu bedienen, welches von relativ unbedarften gelegentlichen Benutzern eines DBS bis hin zu professionellen Programmierern reicht, die über eine mächtige Schnittstelle auf die DB zugreifen möchten. Damit ein solch breites Spektrum zuverlässig abgedeckt werden kann, sollte eine gute Anfragesprache einfach, intuitiv und mächtig ausgelegt sein. Schon Anfang der 80er Jahre wurde deshalb das Motto „Mächtigkeit durch Einfachheit und Einfachheit durch Allgemeingültigkeit“ als Richtschnur ausgegeben. Daraus lassen sich die folgenden Grundsätze ableiten:
208
6 Grundlagen von Anfragesprachen
Einfache Handhabbarkeit und Erlernbarkeit Symmetrie Ein gegebenes syntaktisches Konstrukt sollte an jeder Stelle, an der es eingesetzt wird, dieselbe Semantik abdecken. Die Operation var1 + var2 sollte auf Zahlen immer die in ihrer Semantik hinlänglich bekannte Addition darstellen, unabhängig davon, ob var1 und var2 vom Typ INTEGER, REAL, FLOAT oder einem sonstigen Zahlentyp sind. Ein gegebenes semantisches Konstrukt sollte an allen Stellen, an denen es genutzt wird, dieselbe Syntax besitzen. Es wäre sicherlich wenig benutzerfreundlich, wenn die Multiplikation von INTEGER-Zahlen durch × ausgedrückt würde (int1 × int2 ), während bei reellen Zahlen das Symbol ∗ zu benutzen wäre (real1 ∗ real2 ). Allgemein sollte alles, was symmetrisch ist, auch symmetrisch und damit vom Grundsatz her identisch gehandhabt werden können. Das bedeutet insbesondere, dass es bei Konstellationen, wo es zu einem Befehl einen inversen Befehl gibt, syntaktisch und semantisch äquivalente Befehlspaare geben muss, die insbesondere auch auf identischen Granularitätsstufen einsetzbar sein müssen. Kann man beispielsweise Zugriffsrechte auf einer bestimmten Granularitätsstufe zuweisen, z. B. auf der Ebene von Benutzergruppen, so muss es auch möglich sein, sie mit einem inversen Befehl auf derselben Ebene wieder zu entziehen. Zur Symmetrie gehört auch, dass jede Option auch explizit ausgeschrieben werden darf und zwar unabhängig davon, ob sie bereits die Defaultoption bzw. den Default darstellt. Gerade diese Punkte, obwohl sie fast selbstverständlich erscheinen, wurden und werden beim Entwurf von Sprachen häufig immer noch nicht hinreichend berücksichtigt. Wie noch gezeigt wird, tut sich auch die relationale Anfragesprache SQL sehr schwer mit diesen Prinzipien. Genau genommen erfüllt sie diese trotz diverser Überarbeitungen und Verbesserungen immer noch nicht hinreichend. Generische Operationen Der Reiz einer Anfragesprache liegt darin, dass sie einen überschaubaren, leicht erlernbaren Satz an Anfragekonstrukten bereitstellt, der einen gleichartigen Zugriff auf alle Daten der DB zulässt und zwar unabhängig davon, wie diese aufgebaut sind. Ein solcher Satz von generischen Operationen ist für den benutzerfreundlichen und fehlerfreien Umgang mit einer Anfragesprache von entscheidender Bedeutung. Deskriptive Anfragesprache Ein (gelegentlicher) Benutzer eines DBS wird i. d. R. gut beschreiben können, was er gerne wissen möchte. Er wird aber üblicherweise wenig Neigung verspüren, dem DBMS eine Berechnungsvorschrift anzugeben, die den Weg beschreibt, der abzuarbeiten ist, um das gewünschte Ergebnis zu erzielen. Eine Anfragesprache wird als deskriptiv (deklarativ, nichtprozedural) bezeichnet, falls in der Anfrage lediglich spezifiziert werden muss, was das Ergebnis sein soll, nicht aber, wie das Ergebnis berechnet werden muss. Das impliziert, dass Anfragen mengenorientiert verarbeitet werden, also alle Ergebnisdatensätze gleichzeitig geliefert werden. Dies steht im Gegensatz zu den häufig prozedural ausgelegten Anfragesprachen für Netzwerk- und hierarchische DBMS, bei denen genau zu spezifizieren ist, wie das Ergebnis berechnet werden muss. Zudem wird das Ergebnis tupelweise geliefert. Jedes Tupel muss explizit durch den Aufruf eines entsprechenden Befehls angefordert werden.
6.3 Anforderungen an Anfragesprachen
209
Anwendungsunabhängigkeit Eine allgemeine Anfragesprache darf nicht auf ein bestimmtes Anwendungsgebiet zugeschnitten sein. Sie muss vielmehr anwendungsneutral ausgelegt sein. Dies schließt nicht aus, dass es spezielle Anfragesprachen für spezielle Anwendungsgebiete geben kann. Effizienz und Optimierbarkeit Optimierbarkeit DBS enthalten normalerweise eine riesige Menge an Daten. Um trotzdem ausreichend effizient zu sein, muss das DBMS in der Lage sein, Anfragen so zu optimieren, d. h. umzuformen, dass sie effizient ausführbar sind. Bei der Optimierung spielen Semantik erhaltende Umstellungen und Umformungen und die Berücksichtigung von Heuristiken, von Zugriffspfaden und von mit den Operationen verbundenen Kostenfunktionen eine wesentliche Rolle. Eine Verfälschung des Ergebnisses durch diese Eingriffe muss dabei natürlich ausgeschlossen sein. Effizienz Aus Sicht des Benutzers bedeutet die effiziente Ausführung einer Online-Anfrage vorrangig, dass das Ergebnis in einer für ihn als annehmbar empfundenen Zeit geliefert wird. Dies verlangt neben einer intelligenten Ergebnispräsentation, beispielsweise dem Anzeigen von ersten Ergebnistupeln während die Weiteren noch berechnet werden, dass sich die Operationen der Anfragesprache auch effizient ausführen lassen. Als Daumenregel sollte dabei erwartet werden, dass die Komplexität einer Operation maximal O(n2 ) ist, wobei n die Anzahl der Tupel der beteiligten Relation darstellt. Die Relationenalgebra erfüllt dieses Kriterium und damit, wie wir später noch sehen werden, alle relationalen Anfragesprachen. Sichere Anfragesprache Das unter Effizienz Gesagte impliziert auch, dass eine syntaktisch korrekte Anfrage weder in eine Endlosschleife geraten kann, noch ein unendliches Ergebnis liefern darf. Sind diese Eigenschaften garantiert, spricht man von einer sicheren Anfragesprache. Aus diesem Kriterium kann implizit gefolgert werden, dass eine Anfragesprache nicht die Mächtigkeit einer vollständigen Programmiersprache haben kann, denn Letztere garantiert keineswegs, wie die meisten von uns vermutlich bereits aus eigener leidvoller Erfahrung wissen, die Endlichkeit von Schleifen. Formulierungsunabhängigkeit Eine höchst wünschenswerte Eigenschaft einer deskriptiven Anfragesprache stellt die Formulierungsunabhängigkeit dar. Wenn erwartet wird, dass lediglich zu spezifizieren ist, was das Ergebnis einer Anfrage ist und nicht, wie es erreicht wird, dann muss die Anfragesprache konsequenterweise auch garantieren, dass das Ergebnis zumindest in einer fast identischen Zeit geliefert wird, unabhängig davon, wie die Anfrage formuliert wurde. Gibt es also alternative Formulierungsmöglichkeiten, darf die Effizienz der Anfrageverarbeitung nicht nennenswert davon abhängen, welche dieser Möglichkeiten gewählt wurde. Man kann sich sicherlich vorstellen, dass dieses Kriterium, so wünschenswert es auch ist, schwierig umzusetzen ist, da Rechner nach wie vor nicht in der Lage sind, selbst in einem eingeschränkten Umfeld im nennenswerten Umfang Semantik zu erfassen.
210
6 Grundlagen von Anfragesprachen
Einsetzbarkeit Schlanker Sprachumfang Die Anzahl der Basiskonstrukte sollte möglichst klein ausfallen, was aber nicht heißt, dass sie minimal sein muss. Minimalität ist insbesondere dann nicht wünschenswert, wenn sie zur Formulierung umständlicher und fehleranfälliger Anfragen führen würde. Beispielsweise kann man zwar die Multiplikation von ganzen Zahlen auf die Addition zurückführen, allerdings wird ernsthaft wohl niemand erwägen, den Multiplikationsoperator aus Gründen der Minimalität nicht anzubieten. Vollständigkeit Die Anfragesprache muss alle vom Datenbankmodell unterstützten Modellierungskonzepte und -konstrukte auch abdecken. Bei den DBMS der ersten Generationen, einschließlich dem relationalen, ist dies wegen der Einfachheit des Datenbankmodells auch gewährleistet. Neuere Datenbankmodelle, insbesondere objektorientierte, tun sich da aber schon viel schwerer. Vollständigkeit stellt bei ihnen eine schwer zu überwindende Hürde dar. Orthogonalität Orthogonalität baut auf einen schlanken Sprachumfang auf. Eine Sprache ist orthogonal, wenn sie • aus einer vergleichsweise kleinen Menge von Basiskonstrukten besteht, • einen konsistenten Satz von Regeln hat, der festlegt, wie die Basiskonstrukte zu komplexeren Konstrukten zusammengesetzt werden dürfen und • wenn jede semantisch sinnvolle Kombination dieser Basiskonstrukte auch zulässig ist. Je weniger orthogonal eine Sprache ist, umso komplexer und weniger mächtig wird sie sein. Komplexer deshalb, weil Regeln, Ausnahmen und Spezialfälle definiert werden müssen, die die ansonsten unterstellte Orthogonalität einschränken. Da es Einschränkungen gibt, kann ziemlich direkt gefolgert werden, dass dies häufig auch Einschränkungen in der Mächtigkeit implizieren wird. Orthogonalität bedeutet beispielsweise, dass immer dort, wo ein Wert des Wertebereiches eines bestimmten Datentyps erwartet wird, auch ein Ausdruck stehen darf, dessen Auswertung genau einen Wert dieses Wertebereiches ergibt. Damit ist eine Schachtelung von Ausdrücken möglich. Beispiel 6.6: Orthogonalität VAR Int1 , Int2 , Int3 : INTEGER; BEGIN Int1 := Int1 + Int2 END; Anstelle von Int2 darf in einer orthogonalen Sprache auch ein Ausdruck stehen, der als Ergebnis einen INTEGER-Wert liefert, also z. B. VAR Int1 , Int2 , Int3 , Int4 , Int5 : INTEGER; BEGIN Int1 := Int1 + ((Int4 − Int5 ) ∗ Int3 ) END;
6.4 Sprachansätze
211
Abgeschlossenheit Abgeschlossenheit liegt immer dann vor, wenn jede erlaubte Anwendung von Operationen einer Anfragesprache ein Ergebnis produziert, welches Bestandteil des Datenbankmodells ist. Auf das relationale Datenbankmodell bezogen bedeutet das, dass das Ergebnis der Ausführung von Operationen auf Relationen wieder eine Relation sein muss. Ähnlich wie die Vollständigkeit stellt auch die Abgeschlossenheit bei Anfragesprachen relationaler DBMS kein wirkliches Problem dar8 , während die Situation bei Anfragesprachen für objektorientierte DBMS wiederum deutlich schlechter aussieht. Hier wird Abgeschlossenheit im strengen Sinn häufig nicht sichergestellt.
6.4
Sprachansätze
Anfragesprachen für das Relationenmodell sind abgeschlossen, was heißt, dass sich eine Anfrage grundsätzlich auf eine (Menge von) Relation(en) bezieht und als Ergebnis wieder eine Relation liefert.9 Feststellung 6.1: Generelle Funktionsweise von relationalen Anfragesprachen Jede auf dem Relationenmodell basierende Anfragesprache setzt sich im Prinzip aus den folgenden drei Teilen zusammen: 1. Beschreibung der Ausgangsrelation Aus der gegebenen Menge von (Basis)relationen (des konzeptuellen Schemas) wird eine Ausgangsrelation aufgebaut, die die Basis der Anfrage bildet. 2. Spezifikation der Selektionsbedingungen Die Selektionsbedingungen bilden den eigentlichen Inhalt der Anfrage. Über sie werden aus der Ausgangsrelation die Tupel ausgewählt, die aus der Sicht des Anfragenden gewünscht werden. 3. Beschreibung der Ergebnisrelation Die Ergebnisrelation dient der Präsentation des Ergebnisses der Anfrage. Im Prinzip muss beschrieben werden, was aus der Ausgangsrelation in welcher Form in die Ergebnisrelation übernommen werden soll. Diese drei Teile müssen sich allerdings nicht zwangsläufig als eigenständige, isolierbare Strukturteile einer Anfrage identifizieren lassen. Der wesentliche Unterschied zwischen den Anfragesprachen besteht in den Fragen, welche (generischen) Operationen zur Bildung der Ausgangsrelation, Formulierung der Selektionsbedingungen und Beschreibung des Aufbaus der Ergebnistabelle angeboten werden und in welcher Form diese eingesetzt werden dürfen und müssen. 8 Diese Aussage ist etwas zu relativieren, wie später noch diskutiert wird. SQL arbeitet nicht auf Relationen im Sinn der mathematischen Definition, sondern auf nicht zwangsläufig duplikatfreien Tabellen und verlässt damit streng genommen das relationale Datenbankmodell. 9 Wie bereits in Fußnote 8 gesagt, arbeitet SQL nicht auf Relationen im Sinn der mathematischen Definition, weshalb die Aussage eigentlich nicht ganz zutrifft - es kann auch eine Multimenge zurückgeliefert werden.
212
6 Grundlagen von Anfragesprachen
Ein Erfolg versprechender Weg, den Kriterien für eine gute Anfragesprache gerecht zu werden, ist diese auf einer formalen mathematischen Theorie aufsetzen zu lassen. Zwei Theorien drängen sich besonders auf, die Algebren, in diesem Zusammenhang Anfragealgebren genannt, und die Kalküle, in diesem Zusammenhang als Anfragekalküle bezeichnet. Kurz gesagt ist ein Kalkül eine formale logische Sprache, mit der Aussagen formuliert werden können. Insbesondere muss in einem Kalkül nur ausgedrückt werden, was zum Ergebnis gehören soll, und nicht, wie es berechnet wird. Eine Algebrahingegen definiert sich durch einen Wertebereich und den auf ihm definierten Operatoren. Den Wertebereich relationaler Anfragesprachen bilden die Relationen. Die Operationen sind dementsprechend die auf Relationen erlaubten Operationen. Es wird zwischen ein- und mehrwertigen Algebren unterschieden, je nachdem ob der Wertebereich noch in Sorten aufgeteilt wird (mehrsortig) oder nicht (einsortig). Anfragealgebren für DBMS sind üblicherweise einsortig. Wie man dieser knappen Beschreibung bereits entnehmen kann, erlauben Algebren nur eine prozedurale Beschreibung der Ergebnisfindung, das heißt, mithilfe eines algebraischen Ausdruckes kann spezifiziert werden, wie aus einer gegebenen Ausgangsmenge das Ergebnisresultat berechnet werden kann. Die folgenden beiden Tabellen geben Aufschluss über die bei der Vorstellung der Relationenalgebra und des -kalküls verwendete Notation und das den Sprachvorstellungen zu Grunde INTEGER
Schlüsselwörter einer Sprache werden in Großbuchstaben im Schrifttyp COURIER geschrieben.
Rel
Namen, die mit einem Großbuchstaben beginnen, bezeichnen eine Relation.
P
Ein Großbuchstabe bezeichnet eine (Tupel- oder Bereichs-)Variable.
attr
Namen, die mit einem Kleinbuchstaben beginnen, bezeichnen Attribute.
t
Ein Kleinbuchstabe bezeichnet ein Tupel t einer Relation Rel.
Rel(attr1 , . . ., attrn )
bezeichnet die aus den Attributen attr1 bis attrn bestehende Struktur der Relation Rel, also das Relationenschema von Rel.
Rel(attr1 , . . ., attrn )
bezeichnet eine konkrete Instanz der aus den Attributen attr1 bis attrn bestehenden Relation Rel, stellt also eine konkrete Menge von Tupeln dar.
{attr1 , . . ., attrn }Rel
bezeichnet die Menge aller zur Relation Rel gehörigen Attribute.
Rel.attr
steht für Rel(attr) und wird gelegentlich als verkürzte Schreibweise genutzt, falls nur ein Attribut einer Relation Rel angesprochen werden soll.
t(attr1 , . . ., attrn )
bezeichnet ein Tupel t aus Rel, das durch die Werte für die Attribute attr1 , . . ., attrn beschrieben wird.
w1 , . . . , wn
bezeichnet die Werte w1 , . . ., wn für die Attribute attr1 , . . ., attrn .
. . .
steht für den Tupelkonstruktor, was heißt, dass die innerhalb der spitzen Klammern stehenden Attribute und/oder Konstanten ein Tupel bilden.
Tabelle 6.2: Verwendete Notation
6.4 Sprachansätze
213
RELATION Mitarbeiter mitarbeiterNr INTEGER, mitarbeiterName CHARACTER, mitarbeiterVorname CHARACTER, gehalt DECIMAL, abteilungsNr INTEGER; RELATION produktNr produktBez produktTyp stueckKosten nettoPreis
Mitarbeiter
Kunden
Produkt INTEGER, CHARACTER, CHARACTER, DECIMAL, DECIMAL;
RELATION Kunde kundenNr INTEGER, kundenName CHARACTER, kundenVorname CHARACTER, rabatt DECIMAL; RELATION ProduktLager produktLagerNr INTEGER, produktLagerBez CHARACTER, ort CHARACTER, plz INTEGER; RELATION ProduktLagertIn produktLagerNr INTEGER, produktLagerBez CHARACTER, produktNr INTEGER, istBestand INTEGER;
mitarbeiterNr
mitarbeiterName
mitarbeiterVorname
123
Schlafnur
Kasimir
5.000,–
10
234
Verkaufnichts
Kunigund
8.000,–
10
345
Bediennicht
Eduard
3.000,–
10
456
Verdrückmich
Max
9.500,–
20
567
Verstehnicht
Moritz
6.000,–
20
678
Leo
Leo
1.500,–
15
kundenNr
kundenName
kundenVorname
gehalt
rabatt
1234
Kaufnichts
Fritz
10
2345
Zahlnie
Ede
100
123
Schlafnur
Kasimir
0
456
Verdrückmich
Max
10
5678
Schweigenie
Helmut
0
Tabelle 6.3: Beispielrelationen mit konkreten Instanzen bzw. Ausprägungen
abteilungsNr
214
6 Grundlagen von Anfragesprachen
liegende Beispielschema. Die Notation weicht in Teilen von der zum gleichen Zweck bereits im ersten Teil des Buches genutzten ab. Dies liegt daran, dass dieses Buch sich in zwei Welten bewegt, der Welt der Datenmodellierung und der Welt der DBMS. In beiden Welten haben sich unabhängig voneinander bestimmte Standardschreibweisen eingebürgert. Wir hätten uns auf eine Schreibweise einigen können, hätten dann aber eine Inkompatibilität mit der Literatur in einer der beiden Welten in Kauf nehmen müssen. Nach hitzigen Diskussionen haben wir uns für das andere Übel entschieden: Es werden zwei unterschiedliche Schreibweisen verwendet, wobei jede Schreibweise deutlich sichtbar zu Beginn des jeweils in Bezug auf den Buchteil relevanten Stoffes eingeführt wird (siehe Tabelle 6.2). Tabelle 6.3 präsentiert ein einfaches Beispielschema, welches die Basis für die Diskussion in diesem Kapitel bildet.
6.5
Relationale Algebra
Kurz nach der Präsentation des relationalen Datenbankmodells stellte Codd die Relationenalgebra als formale Basis zur Entwicklung relationaler Anfragesprachen vor. Definition 6.9: Algebra Unter einer Algebra versteht man eine Menge von Werten (Wertebereich), ergänzt um Funktionen bzw. Operatoren auf dem Wertebereich. Ein simples Beispiel für eine Algebra sind die reellen Zahlen mit den Operatoren Addition, Subtraktion, Multiplikation und Division. Eine Algebra heißt mehrsortig, falls der Wertebereich aus mehreren Sorten besteht, also der Wertebereich nicht aus atomaren Werten, sondern aus Tupeln von Werten zusammengesetzt ist. Ansonsten heißt sie einsortig. Bei einer Anfragealgebra sieht man den aktuellen Datenbankzustand als eine Menge von Werten eines gegebenen Wertebereiches (z. B. Relationen) an. Damit sind Anfragen Operationen auf diesem Wertebereich. Algebren für Anfragen sind in der Regel einsortig. Die relationale Algebra, oft auch Relationenalgebra genannt, basiert ausschließlich auf dem abstrakten Datentyp Relation, d. h. eine Anfrage ist eine Operation, die eine oder mehrere Eingaberelationen auf eine Ergebnisrelation abbildet. Dies möge der Leser im Hinterkopf behalten, auch wenn als Ergebnis einer Anfrage manchmal nur ein Tupel, ein Teil eines Tupels oder sogar nur ein Wert heraus zu kommen scheint und manchmal auch noch so getan wird, als handle es sich nur um ein Tupel, einen Teil eines Tupels oder einen Wert. Ein einzelner Wert ist in der relationalen Algebra also kein Wert, sondern eine Relation, bestehend aus einem Tupel, das nur aus einem Attribut besteht, welches diesen Wert besitzt. Der erste Vorschlag von Codd sah acht relationale Operationen vor, die sich in zwei Gruppen einteilen lassen: • die traditionellen Mengenoperationen Vereinigung, Durchschnitt, Differenz und Kartesisches Produkt und • die zusätzlich eingeführten relationalen Operationen Selektion (Restriktion), Projektion, Verbund und Division.
6.5 Relationale Algebra
6.5.1
215
Mengenoperationen
Kartesisches Produkt Gegeben seien zwei Relationen Relm und Relt beliebigen Aufbaus. Beim Kartesischen Produkt, im Zeichen ×, wird jedes Tupel der ersten Relation mit jedem Tupel der zweiten Relation konkateniert (siehe Abbildung 6.1, 3.). Besitzt die Relation Relm r Tupel mit jeweils m Attributen und die Relation Relt s Tupel mit jeweils t Attributen, so besitzt die Ergebnisrelation Relm × Relt genau r ∗ s Tupel, wobei jedes Tupel aus m + t Attributen besteht. Da Attributnamen innerhalb einer Relation eindeutig sein müssen, aber auch nur da, kann das Problem auftreten, dass in der vereinigten Menge aller Attributnamen aus Relm und Relt gleiche Namen vorkommen. Deshalb ist unabdingbare Voraussetzung für die Durchführung der Produktoperation, dass die Attribute beider Relationen unterschiedliche Namen haben. Gegebenenfalls kann dies dadurch erreicht werden, dass vor der Ausführung der Operation Umbenennungen10 vorgenommen werden. Definition 6.10: Kartesisches Produkt Das Kartesische Produkt zweier Relationen verknüpft jedes Tupel der einen Relation mit jedem Tupel der anderen Relation. Relm × Relt := w1 , . . . , wm , wm+1 , . . . , wm+t ∃tm ∈ Relm (tm (attr1 , . . . , attrm ) = w1 , . . . , wm )∧ ∃tt ∈ Relt (tt (attrm+1 , . . . , attrm+t ) = wm+1 , . . . wm+t ) Beispiel 6.7: Kartesisches Produkt Mitarbeiter × Kunden würde eine Ergebnisrelation mit folgendem Aufbau erzeugen: Ergebnisrelation (mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, gehalt, abteilungsNr, kundenNr, kundenName, kundenVorname, rabatt) Feststellung 6.2: Eigenschaften des Kartesischen Produktes Das Kartesische Produkt ist assoziativ und kommutativ, d. h. die Reihenfolge, in der Relationen miteinander verknüpft werden, hat keinen Einfluss auf das Endergebnis. Vereinigung Bei der Vereinigung wird vorausgesetzt, dass zwei typkompatible Relationen Relm und Relt gegeben sind. Die Vereinigung, im Zeichen ∪, ist dann die Zusammenführung der Tupel beider Relationen in eine Ergebnisrelation, wobei inhaltsgleiche Tupel zur Wahrung des mathematischen Konzeptes der Menge nur einmal übernommen werden dürfen (siehe Abbildung 6.1, 6.). Da beide zu vereinigenden Relationen qua definitionem denselben Aufbau besitzen, ist auch der Aufbau der Ergebnisrelation eindeutig. 10 Umbenennungen
werden in Kapitel 6.5.2 diskutiert.
216
6 Grundlagen von Anfragesprachen 1. Projektion
3. Kartesisches Produkt S
2. Selektion R
11 22
AA BB CC R×S AA BB CC AA BB CC 4. Differenz
Rel 1
5. Durchschnitt
Rel 2
Abb. 6.1: Basisoperationen der relationalen Algebra
Ergebnisrelation
11 11 11 22 22 22 6. Vereinigung
6.5 Relationale Algebra
217
7. (natürlicher) Verbund
R1
8. Division
R2 11 A 22 BB
A D1 1K BB D4 6Z CC D7 8G
R1
R1 A BB CC A BB CC
R1
R2
R2
11 A D1 22 BB D4
11 11 11 22 22 22
A BB CC
1K 6Z
/
/
R2
11 22
Abb. 6.1: Basisoperationen der relationalen Algebra (Fortsetzung)
Definition 6.11: Vereinigung Die Vereinigung zweier typkompatibler Relationen erweitert die eine Relation um alle noch nicht vorhandenen Tupel der anderen Relation. Relm ∪ Relt := t | t ∈ Relm ∨ t ∈ Relt Beispiel 6.8: Vereinigung Mitarbeiter ∪ Kunden kann so nicht direkt durchgeführt werden, da die Tabellen nicht typkompatibel sind. Es muss erst eine Anpassung stattfinden, beispielsweise indem beide Relationen auf die semantisch identischen Attribute Nummer, Name und Vorname beschränkt werden.11 ErgRel
11 Diese
nr
name
vorname
1234
Kaufnichts
Fritz
2345
Zahlnie
Ede
123
Schlafnur
Kasimir
456
Verdrückmich
Max
5678
Schweigenie
Hellmut
234
Verkaufnichts
Kunigund
345
Bediennicht
Eduard
567
Verstehnicht
Moritz
678
Leo
Leo
Operation nennt sich Projektion und wird weiter unten noch genauer eingeführt.
218
6 Grundlagen von Anfragesprachen
Die dann erhaltene Relation enthält alle Mitarbeiter und Kunden, wobei die Kunden, die gleichzeitig auch Mitarbeiter sind, nicht (noch einmal) übernommen werden.
Feststellung 6.3: Eigenschaften der Vereinigung Die Vereinigung ist kommutativ und assoziativ. Differenz Die Differenz zweier typkompatibler Relationen Relm und Relt , im Zeichen −, besteht aus all den Tupeln aus Relm , die nicht in Relt enthalten sind (siehe Abbildung 6.1, 4.). Definition 6.12: Differenz Die Differenz zweier typkompatibler Relationen entfernt aus der ersten Relation all die Tupel, die auch in der zweiten Relation enthalten sind. Relm − Relt := t | t ∈ Relm ∧ t ∈ / Relt Beispiel 6.9: Differenz Mitarbeiter − Kunden kann erst nach einer Anpassung der Relationen stattfinden. Die Ergebnisrelation enthält alle Mitarbeiter, die nicht gleichzeitig auch Kunde sind. ErgRel
nr
name
vorname
234
Verkaufnichts
Kunigund
345
Bediennicht
Eduard
567
Verstehnicht
Moritz
678
Leo
Leo
Feststellung 6.4: Eigenschaften der Differenz Die Differenz ist weder kommutativ noch assoziativ. Durchschnitt Der Durchschnitt zweier typkompatibler Relationen Relm und Relt , im Zeichen ∩, besteht aus all den Tupeln, die sowohl in der einen als auch in der anderen Relation enthalten sind. Alle anderen Tupel gehören nicht zur Ergebnisrelation (siehe Abbildung 6.1, 5.). Definition 6.13: Durchschnitt Der Durchschnitt zweier typkompatibler Relationen ergibt die Tupel, die in beiden Relationen enthalten sind, ermittelt also die gemeinsame Teilmenge beider Mengen. Relm ∩ Relt := t | t ∈ Relm ∧ t ∈ Relt
6.5 Relationale Algebra
219
Beispiel 6.10: Durchschnitt Mitarbeiter ∩ Kunden kann ebenfalls erst nach einer Anpassung der Relationen stattfinden. Die Ergebnisrelation enthält alle Mitarbeiter, die gleichzeitig auch Kunde sind. ErgRel
nr
name
vorname
123
Schlafnur
Kasimir
456
Verdrückmich
Max
Der Durchschnitt lässt sich auch durch andere Operatoren erzeugen: Relm ∩ Relt = (Relm ∪ Relt ) − ((Relm − Relt ) ∪ Relt − Relm )) oder kürzer Relm ∩ Relt = Relm − (Relm − Relt ) Feststellung 6.5: Eigenschaften des Durchschnitts Der Durchschnitt ist kommutativ und assoziativ.
6.5.2
Zusätzliche relationale Operationen
Selektion Selektion und Projektion sind einelementige Operationen. Beide dienen dazu, Teilmengen einer gegebenen Relation zu identifizieren. Bei der Selektion, im Zeichen σ, besteht die Ergebnisrelation aus den Tupeln der Ausgangsrelation, die eine bestimmte Bedingung erfüllen (siehe Abbildung 6.1, 2.). Da durch eine Selektion die gegebene Ausgangsrelation in zwei Teile zerlegt wird, dem Teil, der die Bedingung erfüllt, und dem Rest, spricht man auch von einer horizontalen Zerlegung. Definition 6.14: Selektion Eine Selektion wählt die Tupel aus einer Relation aus, bei denen ein Attribut oder mehrere Attribute eine Selektionsbedingung oder mehrere Selektionsbedingungen erfüllen. σBedingung (Rel) := t | t ∈ Rel ∧ Bedingung(t) = TRUE Bei den Bedingungen kann man dabei zwischen einer Konstantenselektion und einer Attributselektion unterscheiden. Bei der Konstantenselektion muss der Attributwert in einer bestimmten Beziehung zu einer Konstanten stehen. Die Beziehung wird durch einen Vergleichsoperator festgelegt, abstrakt mit θ bezeichnet. Die folgenden Vergleichsoperatoren sind zulässig: θ ∈ {=, =, , ≤, ≥}. Beispiel 6.11 ist ein Beispiel für eine Konstantenselektion.
220
6 Grundlagen von Anfragesprachen
Beispiel 6.11: (Konstanten-)Selektion σgehalt>5.000,00 (Mitarbeiter) liefert aus der Relation Mitarbeiter alle Tupel, bei denen das Gehaltsattribut einen Wert größer als 5.000,– C ausweist. Mitarbeiter
mitarbeiter Nr
mitarbeiter Name
mitarbeiter Vorname
gehalt
abteilungs Nr
234
Verkaufnichts
Kunigund
8.000,–
10
456
Verdrückmich
Max
9.500,–
20
567
Verstehnicht
Moritz
6.000,–
30
Bei der Attributselektion werden die Werte zweier typkompatibler Attribute des Tupels miteinander verglichen. Als Vergleichsoperatoren sind die oben genannten Operatoren erlaubt. Beispiel 6.12: Attributselektion σmitarbeiterName=mitarbeiterVorname(Mitarbeiter) liefert alle Mitarbeiter, deren Nachname mit dem Vornamen übereinstimmt. Mitarbeiter
mitarbeiterNr
mitarbeiterName
mitarbeiterVorname
gehalt
abteilungsNr
678
Leo
Leo
1.500,–
15
Eine (komplexe) Selektionsbedingung kann sich aus mehreren elementaren Bedingungen zusammensetzen (siehe Beispiel 6.13). Beispiel 6.13: Attributselektion mit komplexer Bedingung σmitarbeiterName=mitarbeiterVorname∧gehalt>5.000,00 (Mitarbeiter) = σmitarbeiterName=mitarbeiterVorname (σgehalt>5.000,00 (Mitarbeiter)) = σgehalt>5.000,00 (σmitarbeiterName=mitarbeiterVorname(Mitarbeiter)) Feststellung 6.6: Eigenschaften der Selektion Die Selektion ist sowohl assoziativ als auch kommutativ; die Reihenfolge, in der (elementare) Bedingungen abgearbeitet werden, hat keinen Einfluss auf das Endergebnis. Projektion Bei der Projektion, im Zeichen π, werden aus einer gegebenen Relation Spalten ausgeblendet. Die Ergebnisrelation entspricht dann der Ausgangsrelation, nur dass einige Spalten fehlen
6.5 Relationale Algebra
221
(siehe Abbildung 6.1, 1.). Als Konsequenz daraus kann sich aufgrund der Mengeneigenschaft ergeben, dass auch die Länge der Relation schrumpft, da aufgrund der Streichung von Spalten Tupel jetzt mehrfach vorkommen können und somit gestrichen werden müssen. Da die Projektion eine Tabelle durch einen vertikalen Schnitt in zwei Tabellen aufteilt, spricht man auch von einer vertikalen Zerlegung. Definition 6.15: Projektion Eine Projektion schneidet aus einer gegebenen Relation alle aus der Sicht der Anwendung irrelevanten Attribute aus. Gegebenenfalls entstehende Duplikate werden entfernt. π{attr1 ,...,attrm } 12 Rel := w1 , . . . , wm {attr1 , . . . , attrm } ⊆ {attr1 , . . . , attrn }Rel ∧ ∃t ∈ Rel(t = w1 , . . . , wm , . . . , wn 13 ) Beispiel 6.14: Projektion Die in Beispiel 6.8 angesprochene Anpassung der beiden Relationen Mitarbeiter und Kunden kann mithilfe der Projektion wie folgt formuliert werden: πmitarbeiterNr,mitarbeiterName,mitarbeiterVorname(Mitarbeiter), πkundenNr,kundenName,kundenVorname(Kunden) Feststellung 6.7: Eigenschaften der Projektion Die Projektion ist weder kommutativ noch assoziativ. Eine Kombination aus einer Selektions- und einer Projektionsoperation ist dann kommutativ, wenn durch die Projektion keine Attribute entfernt werden, die die Selektionsbedingung benötigt. Division Die Division, im Zeichen ÷, kann immer dann angewendet werden, wenn die Attribute des Divisors eine typkompatible Teilmenge der Attribute des Dividenden sind. Dementsprechend kann man die Attribute der Dividendenrelation in zwei Gruppen aufteilen, die Attribute, die auch in der Divisorrelation enthalten sind, im Folgenden Rel= genannt, und die Attribute, die eben nicht in der Divisorrelation enthalten sind, im Folgenden Rel= genannt. Die Divisionsoperation beruht nun auf einer „Für-alle“-Semantik, wobei man sich deren Arbeitsweise wie folgt vorstellen kann. Die Dividendenrelation wird in Unterrelationen aufgeteilt, wobei zu einer Unterrelation all die Tupel gehören, deren Attributwerte in Rel= identisch sind. Reduziert man die Betrachtung einer Unterrelation auf die Attribute, die zu Rel= gehören, also im Aufbau der Divisorrelation entsprechen, und gilt jetzt, dass alle Tupel der Divisorrelation in dieser reduzierten Unterrelation enthalten sind, so hat man mit Rel= ein Tupel entdeckt, das zur Ergebnisrelation gehört. Tupel der Ergebnisrelation bestehen dabei nur aus den Attributen aus Rel= , was heißt, dass sich pro Unterrelation höchstens ein Tupel für die Ergebnisrelation qualifizieren kann (siehe Abbildung 6.1, 8.). 12 Für die Projektion hat sich die etwas unsaubere Notation der einfachen Auflistung der Attribute ohne Mengenklammerung durchgesetzt, die wir ab jetzt auch verwenden werden. 13 Die Werte der nicht in {A , . . ., A } enthaltenen Attribute sind irrelevant. m 1
222
6 Grundlagen von Anfragesprachen
Definition 6.16: Division Die Division arbeitet auf zwei Relationen Relm und Relt , wobei gelten muss, dass alle Attribute aus Relt auch Bestandteil von Relm sind. Die Ergebnisrelation besteht nur aus = den Attributen von Rel= m . Sie enthält genau dann den =-Anteil eines Tupels (t genannt) aus Relm , wenn die Menge aller aus dem =-Anteil bestehenden Tupel von Relm , die im
=-Anteil t= entsprechen, mindestens alle Tupel aus Relt enthält. Relm ÷ Relt := πattr = (Relm ) − πattr = Relt × πattr = (Relm ) − Relm wobei attr= alle Attribute sind, die zu Relm gehören, nicht aber zu Relt . Beispiel 6.15: Division Angenommen, die beiden Relationen Produkt und ProduktLagertIn sind auf die Attribute produktNr und produktLagerNr, produktNr reduziert worden. Sollen nun die Lager ermittelt werden, in denen alle vom Unternehmen vertriebenen Produkte gelagert werden, so kann dies wie folgt über die Division berechnet werden: ProduktLagertIn ÷ Produkt ProduktLagertIn= besteht nur aus dem Attribut produktLagerNr. Ein dieses Attribut repräsentierendes Tupel qualifiziert sich dann als Ergebnistupel, falls im repräsentierten Lager alle Produkte, die das Unternehmen insgesamt vertreibt, vorhanden sind ({Produkt.produktNr} ⊆ ProduktLagertIn= .produktNr}). Verbund (Join) Die relationale Verbundoperation, im Zeichen , stellt analog zum Kartesischen Produkt eine Verknüpfung von zwei oder mehr Relationen dar. Das Kartesische Produkt kann wegen der uneingeschränkten Verknüpfung der Tupel der einen Relation mit allen Tupeln der anderen Relation zu einer enorm großen Ergebnisrelation führen. Der Verbund kann als eine Verknüpfungsoperation angesehen werden, die in ihrer Arbeitsweise dem Kartesischen Produkt entspricht, Tupel jedoch nicht grundsätzlich miteinander verbindet, sondern nur dann, falls sie eine so genannte Verbundbedingung erfüllen. Allgemein lässt sich der Verbund damit als eine Kombination aus Kartesischem Produkt, Selektion und, je nach Art des Verbundes, anschließender Projektion auffassen (siehe Abbildung 6.2, 7.). Abhängig davon, ob die Verbundbedingung selektiv14 ist oder nicht, wird die Ergebnisrelation eher klein oder ähnlich riesig wie beim Kartesischen Produkt sein. Thetaverbund und Gleichverbund Im einfachsten Fall, dem so genannten allgemeinen Verbund auf der Basis des Gleichheitsoperators (=), werden Tupel aus den jeweiligen Relationen über typkompatible Attribute miteinander verknüpft. Genauer gesagt wird ein Tupel aus der Relation Relm dann mit einem Tupel aus der Relation Relt verknüpft, falls das Tupel aus Relm beim „Verbundattribut“ den gleichen Wert aufweist wie das Gegenstück des Tupels aus Relt . Diese Art des Verbundes wird auch Equi- bzw. Gleichverbund genannt. Lässt man im Vergleichsprädikat statt des Gleichheitsoperators auch die anderen Vergleichsoperatoren (, ≥, =) zu, so spricht 14 Eine
Bedingung ist umso selektiver (auswählender), je kleiner das durch die Bedingung erzielte Ergebnis ist.
6.5 Relationale Algebra
223
man von einem Thetaverbund, abgekürzt θ-Verbund. Der Thetaverbund enthält demnach den Gleichverbund als Spezialfall (θ wird durch = ersetzt), wobei der Spezialfall in der Praxis der Regelfall ist. Definition 6.17: Theta- und Gleichverbund Ein Thetaverbund, im Zeichen θ , zwischen den Relationen Relm (attr1 , . . ., attrm ) und Relt (attr1 , . . ., attrt ) besteht aus der Anwendung des Kartesischen Produktes auf die Relationen und anschließender Selektion gemäß den Verbundbedingungen. Relm θ Relt := σ(Theta-)Verbundbedingungen (Relm × Relt ) Das Ergebnis des Verbundes ist eine Ergebnisrelation Relerg , die aus (m + t) Attributen besteht. Sie wird berechnet, indem jedes Tupel aus Relm mit jedem Tupel aus Relt verbunden wird. Anschließend wird überprüft, ob das so entstandene Tupel die (komplexe) Verbundbedingung erfüllt. Verbundbedingungen sind auf Attributen der beiden Relationen spezifiziert, wobei jeweils Attributwerte miteinander verglichen werden. Eine komplexe Verbundbedingung besitzt folgende Form: Thetaverbundbedingung:Bedingung1 ∧ Bedingung2 ∧ · · · ∧ Bedingungl Jede dieser atomaren Verbundbedingungen Bedingunga ist von der Art attri θattrj , wobei attri ein Attribut von Relm und attrj eines von Relt ist. Zudem müssen beide Attribute typkompatibel sein. Beim Gleichverbund wird θ durch = ersetzt. Relm = Relt := σGleichverbundbedingung (Relm × Relt ) . Im einfachsten Fall sind die Attributnamen der zu vergleichenden Attribute der jeweiligen Relationen identisch, sodass die Bedingung attri =attrj verkürzt durch attri dargestellt werden kann, also die Bedingung durch eine Angabe des Attributes ersetzt wird, das mit identischem Namen in beiden Relationen vorhanden ist und über das die Gleichheit festgestellt werden soll. Gleichverbundbedingung: attre = attrf ∧ attri = attrj ∧ · · · ∧ attrk = attrl ∼ = attre , attri , . . . , attrk , falls die jeweils zu vergleichenden Attributnamen identisch sind. Beispiel 6.16: Gleichverbund σmitarbeiterName=kundenName (Mitarbeiter × Kunde) liefert aus der durch die Anwendung des Kartesischen Produktes auf die Relationen Mitarbeiter und Kunde erhaltenen Ausgangsrelation alle Tupel, für die das Attribut mitarbeiterName den gleichen Wert aufweist wie das Attribut kundenName. Erg- mitarbeiRel terNr
mitarbeiterName
mitarbeiterVorname
gehalt
abteikunlungsNr denNr
kundenName
kunden- rabatt Vorname
123
Schlafnur
Fritz
5.000,–
10
123
Schlafnur
Fritz
0
456
Verdrückmich
Max
9.500,–
20
456
Verdrückmich
Max
10
224
6 Grundlagen von Anfragesprachen
Beispiel 6.17: Komplexer Gleichverbund σmitarbeiterName=kundenName∧mitarbeiterVorname=kundenVorname(Mitarbeiter × Kunde) = σmitarbeiterName=kundenName (σmitarbeiterVorname=kundenVorname(Mitarbeiter × Kunde)) = σmitarbeiterVorname=kundenVorname (σmitarbeiterName=kundenName (Mitarbeiter × Kunde)) Natürlicher Verbund Sowohl beim Theta- als auch beim Gleichverbund werden jeweils alle Attribute der Ausgangsrelationen in die Ergebnisrelation übernommen. Während dies bei dem auf Ungleichheit beruhenden Thetaverbund durchaus Sinn macht, führt es beim Gleichverbund zu Redundanzen. Die Attribute, über die verbunden wird, sind inhaltsgleich, werden aber trotzdem beide in die Ergebnisrelation übernommen. Solche Redundanzen sind nicht immer erwünscht. Oft reicht es, wenn nur eines der beiden Verbundattribute übernommen wird. Definition 6.18: Natürlicher Verbund Ein allgemeiner Verbund, bei dem die Tupel zweier Relationen Relm (attr1 , . . ., attrm ) und Relt (attr1 , . . ., attrt ) dann miteinander verbunden werden, wenn sie in allen namensgleichen Attributen den gleichen Wert aufweisen, in der Ergebnisrelation diese Attribute aber nur einmal vorkommen, nennt man einen natürlichen Verbund, im Zeichen . Ein natürlicher Verbund ist also ein um die Projektion erweiterter Gleichverbund. Durch die Projektion wird eine nur einfache Übernahme der namensgleichen Attribute bewirkt. Relm Relt :=π{attr1 ,...,attrj ,attrk ,...,attrp ,attrp+1 ,...,attrm+t } σRelm .attrk =Relt .attrk ∧Relm .attrl =Relt .attrl ∧···∧Relm .attrp =Relt .attrp (Relm × Relt )15 mit {attr1 , . . . , attrm }Relm ∩ {attr1 , . . . , attrt }Relt = {attrk , . . . , attrp } Beispiel 6.18: Natürlicher Verbund 1. Beispiel 6.16 ist auf der Basis des natürlichen Verbundes wie folgt zu formulieren: Mitarbeiter Kunden Unterstellt wird hier allerdings, dass die beiden Relationen Mitarbeiter und Kunden vorher angepasst wurden, indem die Namen der Attribute, über die verknüpft werden soll, angeglichen wurden. ErgRel
nr
name
vorname
gehalt
abteilungsNr
rabatt
123
Schlafnur
Kasimir
5.000,–
10
0
456
Verdrückmich
Max
9.500,–
20
10
15 Der Einfachheit halber wird hier vorausgesetzt, dass Attribute mit identischen Namen in beiden Relationen an denselben Stellen (k bis p) stehen. Die Gesamtzahl der Attribute der Ergebnisrelation beträgt nur dann (m + t), falls es keine namensgleichen Attribute in den Ausgangsrelationen gibt, ansonsten wegen der einfachen Übernahme identischer Attributnamen nur (m + t − (p − (k − 1))).
6.5 Relationale Algebra
225
2. „Finde alle Produkte, deren Lagerbestand in einem Lager unter 100 liegt. Gib die Produkte und das Lager aus.“ π{produktNr, produktBez, produktLagerNr, produktLagerBez} σistBestand)
?
?
äußerer eingeschränkter Thetaverbund
>
>
?
?
innerer uneingeschränkter Gleichverbund
>
(>)
−
>
>
−
innerer uneingeschränkter Thetaverbund
>
(>)
>
(>)
äußerer uneingeschränkter Thetaverbund
>
>
>
>
innerer eingeschränkter Thetaverbund
äußerer eingeschränkter Thetaverbund
innerer uneingeschränkter Thetaverbund
äußerer uneingeschränkter Thetaverbund
innerer eingeschränkter Thetaverbund
15 Kunden)) oder πmitarbeiterName, mitarbeiterVorname σmitarbeiterNr=kundenNr∧gehalt>5000∧rabatt>15 (Mitarbeiter × Kunden) oder in Einzelschritten über Umbenennung (a) ρGutverdienendeMitarbeiter (σgehalt>5000 Mitarbeiter) (b) ρGuteKunden (σrabatt>15 Kunden) (c) ρMitarbeiterUndKunde (σmitarbeiterNr=kundenNr (GutverdienendeMitarbeiter × GuteKunden) (d) ρErgebnisRelation (πmitarbeiterName, mitarbeiterVornameMitarbeiterUndKunde) 5. „Gib die Lager aus, in denen alle Produkte des Unternehmens gelagert werden.“ (πproduktLagerNr, produktLagerBez,produktNr ProduktLagertIn) ÷ (πproduktNr Produkt)21
20 Man beachte, dass über den Verbund formulierte Anfragen, die als Bedingung auf Ungleichheit von kundenNr und mitarbeiterNr basieren, ohne weitere (umständliche) Maßnahmen nicht das korrekte Ergebnis liefern. Anfragen lassen sich also nicht äquivalent zu 2. stellen. 21 Man beachte, dass die Division aus offensichtlichem Grund (Vermeidung mengenwertiger Attribute) die in beiden Ausgangsrelationen vorkommenden Attribute nicht in die Ergebnisrelation übernimmt. Die Ergebnisrelation besteht also nur aus den Attributen produktLagerNr und produktLagerBez.
234
6.5.4
6 Grundlagen von Anfragesprachen
Eigenschaften der Relationenalgebra
Obwohl sich die Relationenalgebra in der Praxis als Anfragesprache nicht durchgesetzt hat, ist sie im Zusammenhang mit relationalen DBMS doch allgegenwärtig. Einer der Gründe dafür ist ihre mathematische Basis, welche es erlaubt, die für die effiziente Anfrageverarbeitung so wichtigen logischen Optimierungen vorzunehmen. Wir werden auf diesen Aspekt noch ausführlicher zu sprechen kommen. Die Relationenalgebra weist aber noch weitere Vorteile auf, die im Folgenden kurz angesprochen werden sollen. 1. Die Relationenalgebra ist abgeschlossen, was heißt, dass das Ergebnis einer Ausführung einer Operation der Relationenalgebra immer eine Relation ist. Damit können auf das Ergebnis einer Operation in beliebiger Art und Weise wieder die Operationen der Relationenalgebra angewendet werden. 2. Die Operationen der Relationenalgebra sind effizient auswertbar. Es gilt, dass alle algebraischen Operationen in polynomieller Zeit berechnet werden können. Beispielsweise lässt sich die Projektion als relativ teure Operation in der Zeit O(n log n) berechnen, während sich die Selektion zum Beispiel in der Zeit O(n) berechnen lässt. 3. Jedes von einer Operation der relationalen Algebra gelieferte Ergebnis ist von endlicher Kardinalität, was impliziert, dass Ergebnisse in endlicher Zeit geliefert werden. Insbesondere die Punkte 1 und 2 weisen schon auf einen Nachteil der Relationenalgebra hin: Einfachheit lässt sich häufig nur durch eine eingeschränkte Ausdruckskraft erkaufen. In der Tat ist es so, dass sich in der Relationenalgebra auch einige aus Benutzersicht wesentliche Operationen nicht durchführen lassen, zu denen beispielsweise auch die Berechnung der transitiven Hülle gehört. Trotz oder vielleicht gerade wegen ihrer mäßigen Ausdruckskraft wird die relationale Algebra häufig als Bewertungsmaßstab für andere Anfragesprachen herangezogen. Definition 6.22: relationale Vollständigkeit Eine Anfragesprache AS ist relational vollständig, falls sich jede Operation der relationalen Algebra durch einen Ausdruck (nicht unbedingt eine Operation) in AS simulieren lässt. Gilt zusätzlich noch, dass zu jeder Operation der relationalen Algebra auch eine semantisch äquivalente Operation in AS existiert, so sagt man, dass AS streng relational vollständig ist. Bisher haben wir Operationen der relationalen Algebra kennen gelernt, ohne dass darüber diskutiert worden ist, in welchem Verhältnis neue Operationen zu bereits bestehenden Operationen der Algebra stehen. Insbesondere ist es beispielsweise für die Frage der relationalen Vollständigkeit wichtig zu wissen, welches eine/die minimale Menge von Operatoren ist. Umgekehrt würde das heißen, dass alle anderen Operationen sich auf diese minimale Menge zurückführen lassen und damit eher dem Ziel dienen, eine vereinfachte Darstellung eines ansonsten komplexeren Ausdruckes darzustellen (im Sinn einer Makrooperation). Für die minimale Menge der Operationen der Relationenalgebra gilt, dass keine der Operationen weggelassen werden kann, ohne die Vollständigkeit der Relationenalgebra zu verlieren.
6.5 Relationale Algebra
235
Feststellung 6.10: Minimaler Repräsentant der Relationenalgebra Die Menge, die häufig als minimaler Repräsentant der Relationenalgebra genannt wird, besteht aus den folgenden Operationen: (π, σ, ×, ∪, −, ρ) Es mag zunächst einmal überraschen, dass die Verbundoperation nicht zur minimalen Menge gehört. Das liegt daran, dass sie sich auf das Kartesische Produkt und die Selektion zurückführen lässt. Äußere und/oder natürliche Verbunde lassen sich auf die allgemeine Verbundoperation und die Projektion zurückführen. Es sei noch angemerkt, dass aus der obigen Menge die Umbenennung herausgenommen werden könnte, wenn man das Kartesische Produkt so definieren würde, dass es auch auf Relationen mit identischen Attributnamen angewendet werden kann. Dies kann zum Beispiel dadurch erreicht werden, dass vor jedem Attributnamen der Name der dazugehörigen Relation, getrennt durch einen Punkt, geschrieben würde (also z. B. Mitarbeiter.mitarbeiterNr). Da dieser Fall jedoch einer impliziten Umbenennung entspricht, erscheint es einfacher, es bei der einfachen Version des Kartesischen Produktes zu lassen und die Umbenennung explizit mit aufzunehmen.
6.5.5
Zusammenfassung
Die relationale Algebra hat wegen ihres prozeduralen Charakters und der dadurch bedingten eingeschränkten Benutzerfreundlichkeit keine große Bedeutung als Anfragesprache erlangt. Aufgrund ihrer speziell auf das relationale Modell zugeschnittenen Fähigkeiten wird sie jedoch gerne als Maßstab für die Mächtigkeit anderer Anfragesprachen genommen. Da sie zudem auf einer fundierten mathematischen Theorie beruht, werden deskriptiv ausgelegte Anfragesprachen gerne intern auf Operatoren der relationalen Algebra abgebildet. Dies erlaubt Optimierungen auf der Basis gesicherter mathematischer Gesetze.
6.5.6
Literatur
Das relationale Datenbankmodell, insbesondere dessen formale Grundlagen ([Codd70]), und die Relationenalgebra wurden von E. Codd in mehreren Papieren eingeführt ([Codd71, 72a, 72b, 74, 82]). In einem späteren Papier werden Erweiterungen vorgestellt, u. a. auch die Integration von Nullmarken22 in die Relationenalgebra ([Codd79]). Auch [Bisk81] behandelt diese Thematik. Weitere tiefgehende Diskussionen der formalen Grundlagen relationaler Datenbankmodelle und insbesondere auch der Relationenalgebra und des Relationenkalküls finden sich in [AbHV95], [AtDe93], [Bisk95], [GaVa89], [KaKl93], [Maie83], [PDGV89], [Ullm88+89] und [Yang86]. Eine sehr ausführliche, aber weniger formal aufgezogene Diskussion findet sich in [Date03]. 22 In
dem Papier allerdings null values (Nullwerte) genannt.
236
6 Grundlagen von Anfragesprachen
Operation
Zweck
Kartesisches Produkt
Erzeugt eine Ergebnisrelation, die alle Attribute von Relm und Relt umfasst und alle Tupel enthält, die sich durch Kombinationen jeweils eines Tupels beider Relationen erzeugen lassen.
Relm × Relt
Vereinigung
Erzeugt eine Ergebnisrelation, die alle Tupel umfasst, die in den beiden Ausgangsrelationen enthalten sind, jedes Tupel allerdings nur genau einmal.
Relm ∪ Relt
Differenz
Erzeugt eine Ergebnisrelation, in der nur die Tupel aus Relm enthalten sind, die nicht auch in Relt enthalten sind.
Relm − Relt
Durchschnitt
Erzeugt eine Ergebnisrelation, die nur solche Tupel aus Relm und Relt enthält, die gleichzeitig in beiden Ausgangsrelationen enthalten sind.
Relm ∩ Relt
Selektion
Erzeugt eine Ergebnisrelation, in der nur die Tupel aus Rel enthalten sind, die die spezifizierte Bedingung erfüllen.
σBedingung (Rel)
Projektion
Erzeugt eine Ergebnisrelation, die nur die m Attribute attr1 , . . ., attrm der Ausgangsrelation Rel umfasst.
π{attr1 ,...,attrm } Rel
Division
Relt bestehe aus den Attributen x und Relm aus den Attributen z, mit z = x ∪ y. Die Division erzeugt eine nur aus den y-Attributen bestehende Ergebnisrelation, wobei für jedes Tupel der Ergebnisrelation gelten muss: {ty × Relt } ⊆ Relm .
Relm ÷ Relt
Thetaverbund
Erzeugt alle (vollständigen) Kombinationen aus Tupeln von Relm und Relt , die die spezifizierte (beliebig aufgebaute) Bedingung erfüllen.
Relm θ Relt := σ(Theta-)Verbundbedingung (Relm × Relt )
Gleichverbund
Erzeugt alle (vollständigen) Kombinationen aus Tupeln von Relm und Relt , die die auf der Basis des Gleichheitsoperators spezifizierte Bedingung erfüllen.
Relm = Relt := σGleichverbundbedingung (Relm × Relt )
Natürlicher Verbund
Erzeugt alle Kombinationen aus Tupeln von Relm und Relt , die in allen typkompatiblen gleichnamigen Attributen x im Wert übereinstimmen. Die Attribute x werden nur einfach in die Ergebnisrelation übernommen.
Relm Relt
• •
Notation
Die kursiv dargestellten Operationen arbeiten nur auf typkompatiblen Relationen. Die ermittelte Ergebnisrelation enthält grundsätzlich keine Duplikate.
Tabelle 6.5: Operatoren der Relationenalgebra
6.6 Relationenkalkül
6.6
237
Relationenkalkül
Im Gegensatz zur prozedural ausgelegten relationalen Algebra sind Relationenkalküle Vertreter des deskriptiven Ansatzes. Kalküle realisieren logikbasierte Ansätze, bei denen der Datenbankinhalt durch Prädikate einer Logik beschrieben wird. Anfragen entsprechen dann abgeleiteten Prädikaten. Ein Kalkül ist eine formale, logikbasierte Sprache, die es erlaubt, Aussagen zu formulieren. Eine solche Aussage kann, wie es der Relationenkalkül tut, auch dazu genutzt werden, um das Ergebnis einer gewünschten Anfrage zu beschreiben. Der Relationenkalkül stellt eine speziell auf relationale DBMS zugeschnittene Version des Prädikatenkalküls erster Stufe dar und wurde ebenso wie die Relationenalgebra von Codd vorgestellt. Codd stellte auch gleichzeitig eine auf dem Relationenkalkül basierende Anfragesprache mit Namen ALPHA vor. Zwar wurde ALPHA nie implementiert, dafür jedoch eine von deren Design stark beeinflusste Variante mit Namen QUEL (Query Language). QUEL war die erste Anfragesprache des an der University of Berkley in Kalifornien, USA, von Michael Stonebraker entwickelten relationalen DBMS INGRES. Es gibt zwei wesentliche Varianten des Relationenkalküls, den Tupelkalkül, auf dem QUEL basiert, und den Bereichskalkül, der die Grundlage für eine weitere bekannte Anfragesprache bildet, Query-By-Example, kurz QBE. Bei beiden Varianten kann man sich den prinzipiellen Aufbau einer Anfrage so vorstellen, dass einerseits spezifiziert wird, wie die Ergebnisrelation aufgebaut sein soll, also aus welchen Attributen sie bestehen soll. Andererseits kann ein (komplexes) Selektionsprädikat spezifiziert werden, in welchem die Bedingungen festgelegt werden, denen ein Tupel genügen muss, um zur Ergebnisrelation zu gehören. Feststellung 6.11: Grundsätzlicher (informeller) Aufbau einer Anfrage im Relationenkalkül Der grundsätzliche Aufbau einer Anfrage sieht wie folgt aus: Var präd(Var∗ ) Dabei ist Var entweder eine Variable, die ein Tupel repräsentiert, also eine Tupelvariable im Tupelkalkül, oder eine Menge von Variablen, die jeweils über Wertebereiche laufen, also eine Bereichsvariable im Bereichskalkül, wobei jede Bereichsvariable ein Attribut der zu Grunde liegenden Relation(en) repräsentiert. präd(Var*) ist das Selektionsprädikat, das von der aktuellen Ausprägung von Var* erfüllt werden muss, damit das durch Var* repräsentierte Tupel sich für die Ergebnisrelation qualifiziert. Var* stellt eine Obermenge der Attribute von T dar. Auf Var* wird also zunächst eine Selektion und dann, falls die Obermengenbeziehung echt23 ist, noch eine Projektion ausgeführt. Beim Tupelkalkül kann man von einer Top-down-Sicht reden, d. h. Ausgangspunkt sind Tupel(variablen), von denen aus man auf die Attribute „heruntersteigen“ kann (siehe Beispiel 6.21 (1.)). Beim Bereichskalkül bilden die Bereichsvariablen, die elementare Attribute repräsentieren, die Basis, die man gegebenenfalls zu Tupeln „aufwerten“ kann. Dies entspricht eher einer Bottom-up-Sicht (siehe Beispiel 6.21 (2.)). 23 Eine Menge M ist eine echte Obermenge einer Menge M , falls M vollständig in M enthalten ist, M aber 1 2 2 1 1 noch weitere Elemente besitzt.
238
6 Grundlagen von Anfragesprachen
Beispiel 6.21: Einfache Anfrage im Tupel- und Bereichskalkül 1. „Gib alle Mitarbeiter aus, die mehr als 5.000,– C verdienen.“ (a) Tupelkalkül mitarbTupel mitarbTupel ∈ Mitarbeiter ∧ mitarbTupel.gehalt > 5000,00 24 ←
a
→ ←
b
→ ←
c
→
(b) Bereichskalkül mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, gehalt, abteilungsNr mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, gehalt, abteilungsNr ∈ Mitarbeiter ∧ Gehalt > 5000,00 2. „Gib die Namen aller Mitarbeiter aus, die mehr als 5.000,– C verdienen.“ (a) Tupelkalkül mitTupel.mitarbeiterName, mitTupel.mitarbeiterVorname mitTupel ∈ Mitarbeiter ∧ mitTupel.gehalt > 5000,00 25 (b) Bereichskalkül mitarbeiterName, mitarbeiterVorname mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, gehalt, abteilungsNr ∈ Mitarbeiter ∧ Gehalt > 5000,00 Wirft man in Beispiel 6.21 einen genaueren Blick auf den Bedingungsteil, so erkennt man eine Untergliederung in Wertebereichs- und Selektionsbedingung im engeren Sinn. Damit ergibt sich insgesamt eine Dreiteilung (siehe Beispiel 6.21 (1.a)). a. Spezifikation der Ergebnisrelation Vor dem | wird die Struktur der Ergebnisrelation beschrieben. b. Wertebereichsbedingungen/Ausgangsrelationen Hinter dem | steht der Bedingungsteil. Dabei werden zunächst die in der Anfrage benötigten Variablen deklariert. Insbesondere wird dabei auch (implizit) festgelegt, über welchen Wertebereich sie jeweils laufen. Dies entspricht der Spezifikation, welche (Basis)relationen in der Anfrage verwendet werden sollen. Eine Wertebereichsdeklaration wird also als Bedingung verpackt, die von der entsprechenden Variablen zu erfüllen ist. 24 x.y
steht für Attribut y des Tupels bzw. der Relation x. gleich noch gezeigt werden wird, ist diese Variante des Tupelkalküls streng genommen nicht ganz korrekt. Sie ist aber deutlich einfacher zu verstehen als die korrekte Variante. 25 Wie
6.6 Relationenkalkül
239
f. Selektionsbedingungen Der zweite Teil des Bedingungsblockes ist der eigentlichen Spezifikation der Bedingungen an die Tupel der Ergebnisrelation gewidmet. Hier muss auch festgelegt werden (über Verbundbedingungen), in welcher Form die unter 2. spezifizierten (Basis)relationen miteinander in Beziehung stehen.26 Diese vereinfachte Sicht auf die Struktur einer Anfrage lässt sich sowohl im Tupel- als auch im Bereichskalkül wiederfinden. Dabei gilt, dass die Blöcke 2. und 3. mehrfach hintereinander stehen können. Jeder Doppelblock handelt dabei im Prinzip eine der beteiligten (Basis)relationen ab (siehe Beispiel 6.23). Beide Varianten von Kalkülen sollen im Folgenden genauer vorgestellt werden.
6.6.1
Tupelkalkül
Der Tupel Relationenkalkül oder kurz Tupelkalkül arbeitet auf der Basis von Tupeln, die über Tupelvariable angesprochen werden. Definition 6.23: Tupelvariable Eine Tupelvariable ist eine Variable, deren Wertebereich eine Relation ist. Daher darf ihr als Wert nur ein dem zu Grunde liegenden Relationentyp entsprechendes Tupel zugewiesen werden. Beispiel 6.22: Einfache Anfrage im Tupelkalkül „Finde alle Produkte, deren Nettopreis unter 500,– C liegt.“ P P ∈ Produkt ∧ P.nettoPreis < 500 Das Selektionsprädikat besteht aus zwei Bedingungen. Die erste legt den Wertebereich der Tupelvariablen fest, im obigen Beispiel Produkt. Die zweite ist die eigentliche Selektionsbedingung, die in Beispiel 6.22 die Tupel auswählt, deren Verkaufspreis unter 500,– C liegt. Läuft eine Anfrage über mehrere (Basis)relationen, gibt es pro beteiligte Relation eine Variablen- und Bedingungsspezifikation (siehe Beispiel 6.23). Die Beziehung zwischen beiden Relationen wird durch eine Verbundbedingung festgelegt (P.produktNr = PLI.produktNr). Beispiel 6.23: Anfrage über mehrere (Basis)relationen im Tupelkalkül „Liste für jedes Lager die dort gelagerten Produkte mit einem Nettopreis unter 500,– C auf, sofern sie in dem Lager noch vorrätig sind.“ PLI.produktLagerNr, PLI.produktLagerBez, P.produktName P ∈ Produkt ∧ P.nettoPreis < 500 ∧ PLI ∈ ProduktLagertIn ∧ PLI.istBestand > 0 ∧ P.produktNr = PLI.produktNr 26 Als Faustregel gilt, dass für jede Variable, die eine „neue“ Basisrelation repräsentiert, festgelegt werden muss, in welcher Beziehung sie zu den anderen in der Anfrage verwendeten (Basis)relationen steht.
240
6 Grundlagen von Anfragesprachen
Für die weitere Diskussion sollen die Begriffe freie und gebundene Tupelvariable sowie Existenz- und Allquantifizierung von Tupelvariable zunächst informell eingeführt werden. Bei einer Existenzquantifizierung der Art (∃(T ∈ Rel)präd(T ))27 wird eine Aussage über eine Relation Rel der Art gemacht, dass der Ausdruck genau dann zu TRUE evaluiert, falls Rel mindestens ein Tupel enthält, welches die spezifizierte Bedingung präd(T ) erfüllt. Bei der Allquantifizierung (∀(T ∈ Rel)präd(T )) wird dies von allen Tupeln von Rel verlangt. ∃ wird Existenzquantor und ∀ Allquantor genannt. Beispiel 6.24: Existenzquantifizierung „Gib alle Lager aus, die in einem Ort mit einer Postleitzahl zwischen 40000 und 49999 liegen und die mindestens ein Produkt weniger als zehnmal enthalten.“ PL.produktLagerBez PL ∈ ProduktLager ∧ PL.plz ≥ 40000 ∧ PL.plz < 50000 ∧ (∃PLI)(PLI ∈ ProduktLagertIn ∧ PL.istBestand < 10 ∧ PL.produktLagerNr = PLI.produktLagerNr) Wenn man die Existenzquantifizierung als Prozedur einer Programmiersprache ausdrücken würde, könnte das in etwa wie folgt aussehen: PROCEDURE Existenz (Rel:Relation): BOOLEAN; BEGIN VAR T: TypRel; /*Tupelvariable T kann Tupel vom Typ Rel repräsentieren Existenz:=FALSE; T:=first(Rel); /*setzt T auf das erste Tupel von Rel WHILE NOT Existenz AND RelNochNichtVollständigDurchlaufen DO BEGIN IF präd(T) THEN Existenz:=TRUE; T:=next(Rel); /*realisiert den Durchlauf durch die Relation END; END; In obiger, die Existenzquantifizierung umsetzender Prozedur wird die Tupelvariable T als lokale Variable der Prozedur deklariert, weshalb der Gültigkeitsbereich von T auf die Prozedur beschränkt ist. Man sagt, T ist an die Prozedur gebunden. Im Tupelkalkül übernimmt der Existenz- bzw. Allquantor diese Bindungsfunktion. Dies führt zu einer eher intuitiven Definition von freien und ungebundenen Variablen. Definition 6.24: Freie und gebundene Tupelvariable Im Tupelkalkül heißt jede an einen Existenz- oder Allquantor gebundene Variable gebunden. Solche Variablen können nicht außerhalb des die Existenz- oder Allquantifizierung realisierenden Blockes angesprochen bzw. genutzt werden. Eine freie Variable ist eine (globale) Variable, die nicht an einen Existenz- oder Allquantor gebunden ist. 27 Der Deutlichkeit halber ist hier die Wertebereichsdeklaration für T (T ∈ Rel) aus dem Bedingungsblock herausgezogen und explizit aufgeführt worden. Der obige Ausdruck ist äquivalent zu folgender Schreibweise: ∃ ∈ Rel: präd(T )
6.6 Relationenkalkül 6.6.1.1
241
Formale Definition des Tupelkalküls
In Verallgemeinerung zu Feststellung 6.11 lässt sich ein Ausdruck des Tupelkalküls wie folgt darstellen: Tvari .attrr , Tvarj .attrs , . . . , Tvarn .attrx präd(Tvar1 , Tvar2 , . . . , Tvarq ) Tvarl , l ∈ {1, 2, . . . , n} sind Tupelvariable, die für die Relationen stehen, die die Ausgangsrelation ausmachen. Tvari .attrr , . . . , Tvarn .attrx mit i, . . . , n ∈ {1, 2, . . . , q} beschreiben die Struktur der Ergebnisrelation, wobei für jedes attrv , v ∈ {r, s, . . . , x} gelten muss, dass es ein Attribut der Relation ist, über die die dazugehörige Tupelvariable läuft. Im Bedingungsteil werden die Bedingungen an die Tupelvariable in Form eines wohlgeformten Prädikates, auch wohlgeformte Formel genannt (well-formed formula, abgekürzt wff) spezifiziert. Ein Prädikat setzt sich aus den Grundbausteinen des Prädikatenkalküls, den so genannten Atomen zusammen. Ein Atom kann dabei die in Definition 6.25 spezifizierte Form haben. Definition 6.25: Atom im Tupelkalkül Ein Atom entspricht in seinem Aufbau einer der folgenden drei Varianten: 1. Tvar is Rel bzw. Tvar ∈ Rel, wobei Rel ein Relationenname und Tvar eine Tupelvariable darstellt. Das Atom drückt die Aussage „Tvar repräsentiert ein Tupel der Relation Rel.“ aus. 2. Tvar1 .attrl θ Tvar2 .attrm , wobei Tvar1 und Tvar2 Tupelvariable sind, attrl und attrm Attributnamen und θ einer der üblichen Vergleichsoperatoren (, ≥, =, =) ist. Es muss gelten, dass der Wertebereich des Attributes attrl derselbe ist wie der des Attributes attrm . Schließlich muss noch gelten, dass attrl ein Attribut der Relation darstellt, über die Tvar1 läuft, und attrm dementsprechend ein Attribut der Relation, über die Tvar2 läuft. 3. Tvar1 .attrl = Konst, wobei Tvar1 und attrl definiert sind wie im Fall 2 und Konst eine Konstante darstellt, die zum Wertebereich von attrl passen muss. Auf der Basis von Definition 6.24 und Definition 6.25 kann jetzt der Aufbau einer Formel formal spezifiziert werden. Definition 6.26: Formel im Tupelkalkül Eine Formel besteht aus einem oder mehreren Atomen, die über die logischen Junktoren AND, OR und NOT miteinander verknüpft werden können, wobei folgende Regeln gelten: 1. Jedes Atom ist eine Formel. Alle in einem Atom auftretenden Tupelvariablen sind frei. 2. Falls f eine Formel ist, so sind auch (f ) und ¬f Formeln. Tupelvariablen sind frei oder gebunden, je nachdem ob sie in f frei oder gebunden sind. 3. Falls f1 und f2 Formeln sind, dann sind auch f1 ∧ f2 , f1 ∨ f2 und f1 ⇒ f2 Formeln. Tupelvariablen sind frei (gebunden), wenn sie in f1 und (oder) f2 frei (gebunden) sind.
242
6 Grundlagen von Anfragesprachen
4. Falls f eine Formel ist, sind auch (∃Tvar ∈ Rel)f (Tvar) und (∀Tvar ∈ Rel)f (Tvar) Formeln. Jedes in f auftretende Vorkommen der Tupelvariablen Tvar wird an (∃Tvar) bzw. (∀Tvar) gebunden. Der Status anderer Tupelvariablen in f ändert sich hierdurch nicht. 5. Nichts anderes ist eine Formel. Von der mathematischen Logik ist bekannt, dass ein Ausdruck mit Allquantor in einen äquivalenten Ausdruck mit Existenzquantor umgewandelt werden kann und umgekehrt. Damit ist einer der beiden Quantoren im Prinzip überflüssig, da er durch den anderen simuliert werden kann. Bei einer Umwandlung muss im Wesentlichen wie folgt vorgegangen werden: 1. Ersetze den einen Typ von Quantifizierung durch den anderen und negiere ihn, füge also vor dem Typ ein NOT (¬) ein. 2. Ersetze AND (∧) durch OR (∨) und umgekehrt. 3. Entferne bei einer negierten Formel die Negation und füge sie bei einer nicht negierten Formel hinzu. Beispiel 6.25: Umformung einer Existenzquantifizierung in eine Allquantifizierung „Gib die Mitarbeiter aus, die nicht auch Kunden des Unternehmens sind.“ Formulierung mit Existenzquantifizierung: „Gib alle Mitarbeiter aus, für die es kein Tupel in der DB gibt, das zur Relation Kunde gehört und dessen Attribut kundenNr den gleichen Wert aufweist wie das Attribut mitarbeiterNr des (konkret betrachteten) Mitarbeiter(tupel)s.“ M.mitarbeiterNr, M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter ∧ (¬∃K)(K ∈ Kunden ∧ K.kundenNr = M.mitarbeiterNr) 28 Schrittweise Umformung in eine Anfrage mit Allquantifizierung: • Schritt 1 (Zwischenergebnis): M.mitarbeiterNr, M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter∧ (∀K)(K ∈ Kunden ∧ K.kundenNr = M.mitarbeiterNr) • Schritt 2 (Zwischenergebnis): M.mitarbeiterNr, M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter∧ (∀K)(K ∈ Kunden ∨ K.kundenNr = M.mitarbeiterNr) • Schritt 3 (Endergebnis): M.mitarbeiterNr, M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter∧ (∀K)(K ∈ / Kunden ∨ K.kundenNr = M.mitarbeiterNr)29 28 Es wird vorausgesetzt, dass Mitarbeiter, die auch Kunden sind, eine identische Mitarbeiter- und Kundennummer besitzen. 29 Besser lesbare Schreibweise für: ¬(K ∈ Kunde) ∨¬ (K.kundenNr = M.mitarbeiterNr)
6.6 Relationenkalkül
243
Formulierung mit Allquantifizierung: „Gib alle Mitarbeiter aus, für die für jedes Tupel (der DB) gilt, dass das Tupel entweder nicht zur Relation Kunden gehört oder, falls doch, im Attribut kundenNr nicht den gleichen Wert aufweist wie das Attribut mitarbeiterNr des (konkret betrachteten) Mitarbeiter(tupel)s.“ Der eine oder andere Leser mag ob der Formulierung der „allquantifizierten“ Anfrage etwas verwirrt sein und nicht verstehen, warum diese so aufgebaut ist. Bei der Allquantifizierung muss etwas für alle Tupel der DB erfüllt sein. Interessiert sind wir im zweiten Teil der Bedingung allerdings nur an Tupeln, die der Relation Kunden angehören und eine bestimmte Bedingung erfüllen (K.kundenNr = M.mitarbeiterNr). Wie bekommen wir jetzt die anderen Tupel weg? Der Trick ist, dass man diese Tupel zu TRUE evaluieren lässt. Damit gehören sie jetzt zwar zur Zwischenergebnismenge. Im Sinn des Mottos „von hinten durch die Brust ins Auge“ werden sie in der auszugebenden Ergebnismenge allerdings nicht berücksichtigt (siehe Spezifikation des Aufbaus der Ergebnismenge im ersten Teil der Anfrage) und dadurch elegant ausgebremst. Damit wird noch einmal explizit gemacht, dass die Existenzquantifizierung eine Bedingung der Art „es existiert ein Tupel in der DB, das die spezifizierten Bedingungen erfüllt“ ist, während die Allquantifizierung erwartet, dass die spezifizierten Bedingungen für alle Tupel der DB erfüllt sein müssen. In Beispiel 6.26 werden weitere prägnante Beispiele für äquivalente Ausdrücke mit Existenzund Allquantor vorgestellt. Beispiel 6.26: Äquivalente Ausdrücke mit All- und Existenzquantor 1. (∀x)(präd(x)) ∼ = (¬∃x)(¬(präd(x))) 2. (∀x)(präd(x) ∧ präd(y)) ∼ = (¬∃x)(¬(präd(x)) ∨ ¬(präd(y))) 3. (∀x)(präd(x) ∨ präd(y)) ∼ = (¬∃x)(¬(präd(x)) ∧ ¬(präd(y))) 4. (∃x)(präd(x)) ∼ = ¬(∀x)(¬(präd(x))) 5. (∃x)(präd(x) ∧ präd(y)) ∼ = ¬(∀x)(¬(präd(x)) ∨ (präd(y)))) 6. (∃x)(präd(x) ∨ präd(y)) ∼ = ¬(∀x)(¬(präd(x)) ∧ (präd(y))) Zudem gelten die folgenden Aussagen: (∀x)(präd(x)) ⇒ 30 (∃x)(präd(x)) (¬∃x)(präd(x)) ⇒ ¬(∀x)(präd(x)) Die folgende Aussage gilt hingegen nicht: ¬(∀x)(präd(x)) ⇒ (¬∃x)(präd(x)) 30 P 1
⇒ P2 bedeutet, dass, falls P1 gültig ist, auch P2 gilt.
244
6 Grundlagen von Anfragesprachen
Beispiel 6.27: Anfragen in Tupelkalkül Zur besseren Vergleichbarkeit werden hier dieselben Beispiele verwendet wie in Kapitel 6.5.3. 1. „Gib die Namen aller Mitarbeiter der Abteilung 1234 aus.“ M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter ∧ M.mitarbeiterNr = ’1234’) 2. „Gib die Namen aller Mitarbeiter aus, die auch Kunden der Firma sind.“ M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter ∧ (∃K)(K ∈ Kunden ∧ M.mitarbeiterNr = K.kundenNr) 3. „Gib die Namen aller Mitarbeiter aus, die nicht Kunden der Firma sind.“ M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter ∧ (¬∃K)(K ∈ Kunden ∧ M.mitarbeiterNr = K.kundenNr) 4. „Gib die Namen aller Mitarbeiter mit einem Gehalt über 5.000,– C aus, die auch Kunden der Firma sind und einen Rabatt von mehr als 15 Prozent bekommen.“ M.mitarbeiterName, M.mitarbeiterVorname M ∈ Mitarbeiter ∧ M.gehalt > 5000 ∧ (∃K)(K ∈ Kunden ∧ M.mitarbeiterNr = K.kundenNr ∧ K.rabatt > 15) 5. „Gib die Lager aus, in denen alle Produkte des Unternehmens gelagert werden.“ PL.produktLagerNr, PL.produktLagerBez PL ∈ ProduktLager∧ (∀P)(P ∈ / Produkt ∨ ∃(PLI)(PLI ∈ ProduktLagertIn ∧ PLI.produktNr = P.produktNr ∧ PLI.produktLagerNr = PL.produktLagerNr)) 6.6.1.2
QUEL
Die auf dem Tupelkalkül basierende Anfragesprache QUEL stand in Konkurrenz zu SQL, konnte sich letztendlich aber trotz eines saubereren Ansatzes nicht durchsetzen. QUEL hat die bereits in Beispiel 6.21 angesprochene Zerlegung einer Anfrage in drei Grundblöcke aus Gründen der Übersichtlichkeit übernommen. Eine Anfrage besteht daher aus der Spezifikation des Wertebereiches der in der Anfrage verwendeten Tupelvariable (RANGE-Block), der Spezifikation des Aufbaus der Ergebnisrelation (RETRIEVE-Block) und der Spezifikation der Bedingungen an die Tupelvariable (WHERE-Block). Die formale mathematische Notation wurde aus Gründen der Lesbarkeit durch eine umgangssprachliche Syntax ersetzt. Beispiel 6.28: Einfache Anfrage in QUEL Die Anfrage von Beispiel 6.22 würde in QUEL wie folgt lauten: RANGE OF Pro IS Produkt RETRIEVE Pro WHERE Pro.nettoPreis < 500;
6.6 Relationenkalkül
245
Wertebereich einer Tupelvariable Der Wertebereich einer Tupelvariable wird in der RANGE-Klausel wie folgt definiert: RANGE OF Tvar IS RelAus1 , RelAus2 , . . ., RelAusn ; Tvar stellt die Tupelvariable dar, die definiert werden soll. RelAusi , i = 1, 2, . . ., n, ist entweder ein Relationenname (siehe Beispiel 6.29, 1.) oder ein Ausdruck des Tupelkalküls, dessen Auswertung eine Relation ergibt (siehe Beispiel 6.29, 2.). Da der Wertebereich einer Tupelvariablen eindeutig definiert sein muss, müssen alle RelAusi typkompatibel sein, was insbesondere heißt, dass für den Fall, dass RelAusi ein Ausdruck des Tupelkalküls ist, dessen Auswertung eine zu den anderen Relationen typkompatible Relation liefern muss. Tvar läuft also über die Vereinigung aller aktuellen Tupel der aus RelAus1 bis RelAusn entstandenen Relation. Sollen die Wertebereiche für mehrere Tupelvariablen spezifiziert werden, so können mehrere RANGE-Anweisungen hintereinander geschrieben werden. Beispiel 6.29: Definition mehrerer Tupelvariable 1. RANGE OF RANGE OF
Pro IS Produkt; PLI IS ProduktLagertIn;
2. RANGE OF
PLI2 IS (PLI WHERE PLI.istBestand > 500);
Mit der letzten Bereichsdeklaration wird festgelegt, dass die Tupelvariable PLI2 über die Relation läuft, die entsteht, wenn man aus der durch PLI beschriebenen Relation die Tupel auswählt, die im Attribut istBestand einen größeren Wert als 500 aufweisen. Ergebnisrelation Die Ergebnisrelation wird spezifiziert, indem in der RETRIEVE-Klausel zu jeder relevanten Tupelvariablen angegeben wird, welche Attribute der dieser Tupelvariablen zu Grunde liegenden Ausgangsrelation in die Ergebnisrelation übernommen werden sollen. Beispiel 6.30: Spezifikation der Ergebnisrelation im Tupelkalkül RANGE OF Pro IS Produkt RANGE OF PLI IS ProduktLagertIn RETRIEVE (Pro.produktNr, Pro.produktBez, Pro.produktTyp, PLI.produktLagerNr) liefert eine Ergebnisrelation, die aus den Attributen produktNr, produktBez und produktTyp der Relation Produkt und dem Attribut produktLagerNr der Relation ProduktLagertIn besteht. Der obigen Spezifikation der Ergebnisrelation kann bereits entnommen werden, dass im Bedingungsteil der Anfrage entweder ein Verbund zwischen oder das Kartesische Produkt von Produkt und ProduktLagertIn berechnet wird.
246
6 Grundlagen von Anfragesprachen
Bedingungsblock Im Bedingungsblock werden die eigentlichen Bedingungen spezifiziert, die von den Tupeln der Ausgangsrelation erfüllt sein müssen, damit sie sich für die Ergebnisrelation qualifizieren. Bedingungen werden in der WHERE-Klausel festgelegt (siehe Beispiel 6.31). Beispiel 6.31: Bedingungsspezifikation im Tupelkalkül RANGE OF RANGE OF RETRIEVE WHERE
Pro IS Produkt PLI IS ProduktLagertIn (Pro.produktNr, Pro.produktBez, PLI.produktLagerNr) Pro.produktNr=PLI.produktNr AND PLI.istBestand = 0
Diese Anfrage gibt jedes Produkt und das dazugehörige Lager aus, falls der Lagerbestand des Produktes in diesem Lager auf Null gesunken ist. Achtung 6.1: Implizite Existenzquantifizierung in QUEL in der WHERE-Klausel In QUEL wird jede Tupelvariable, die in der WHERE-, aber nicht in der RETRIEVEKlausel vorkommt, implizit mit einem Existenzquantor versehen, sodass die WHEREKlausel in Beispiel 6.31 wie folgt zu lesen ist: Es existiert ein Tupel in der Relation ProduktLagertIn, dessen Produktnummer mit der Produktnummer des gegebenen Tupels aus der Relation Produkt übereinstimmt und das im Attribut istBestand den Wert 0 aufweist. Soll der negierte Existenzquantor verwendet werden, ist er explizit anzugeben. Achtung 6.2: QUEL unterstützt die Allquantifizierung nicht explizit QUEL macht von der Tatsache Gebrauch, dass sich jede Anfrage mit einem Allquantor in eine äquivalente Anfrage mit einem Existenzquantor umformen lässt. Daher wird nur die Existenzquantifizierung explizit unterstützt. ANY(Ausdruck) = 1 steht dabei für die Existenzquantifizierung (∃) und ANY(Ausdruck) = 0 für seine negierte Variante (¬∃). Beispiel 6.32: „Allquantifizierung“ in QUEL „Gib die Lager aus, in denen alle Produkte des Unternehmens gelagert werden.“ 1. Nicht mögliche (aber intuitivere) Variante mit in QUEL nicht vorhandenem Allquantor: RANGE OF RANGE OF RANGE OF RETRIEVE WHERE
Pro IS Produkt PLI IS ProduktLagertIn PL IS ProduktLager (PL.produktLagerNr, PL.produktLagerBez) FORALL (Pro.produktNr WHERE PL.produktLagerNr = PLI.produktLagerNr AND Pro.produktNr = PLI.produktNr)
6.6 Relationenkalkül
247
Wegen Achtung 6.1 ist die WHERE-Klausel die verkürzte Variante von: WHERE
FORALL (Pro.produktNr WHERE ANY (PL.produktLagerNr WHERE ANY (PLI.produktLagerNr WHERE PL.produktLagerNr = PLI.produktLagerNr AND Pro.produktNr = PLI.produktNr) = 1) = 1)
2. In einen Ausdruck mit Existenzquantor umgewandelte zulässige Variante: WHERE ANY (Pro.produktNr WHERE ANY (PL.produktLagerNr WHERE PL.produktLagerNr = PLI.produktLagerNr AND Pro.produktNr = PLI.produktNr) = 0) = 0
Beispiel 6.33: Anfragen in QUEL Zur besseren Vergleichbarkeit werden hier dieselben Beispiele verwendet wie in Kapitel 6.5.3 und Beispiel 6.27. 1. „Gib die Namen aller Mitarbeiter der Abteilung 1234 aus.“ RANGE OF Mit IS Mitarbeiter RETRIEVE (Mit.mitarbeiterName, Mit.mitarbeiterVorname) WHERE abteilungsNr = 1234 2. „Gib die Namen aller Mitarbeiter aus, die auch Kunden der Firma sind.“ RANGE OF Mit IS Mitarbeiter RANGE OF Kun IS Kunden RETRIEVE (Mit.mitarbeiterName, Mit.mitarbeiterVorname) WHERE Mit.mitarbeiterNr = Kun.kundenNr 3. „Gib die Namen aller Mitarbeiter aus, die nicht Kunden der Firma sind.“ RANGE OF Mit IS Mitarbeiter RANGE OF Kun IS Kunden RETRIEVE (Mit.mitarbeiterName, Mit.mitarbeiterVorname) WHERE ANY (Mit.mitarbeiterNr = Kun.kundenNr) = 0 4. „Gib die Namen aller Mitarbeiter mit einem Gehalt über 5.000,– C aus, die auch Kunden der Firma sind und einen Rabatt von mehr als 15 Prozent bekommen.“ RANGE OF Mit IS Mitarbeiter RANGE OF Kun IS Kunden RETRIEVE (Mit.mitarbeiterName, Mit.mitarbeiterVorname) WHERE Mit.mitarbeiterNr = Kun.kundenNr AND Mit.gehalt > 5000 AND Kun.rabatt > 15 5. Anfrage 5 ist bereits in Beispiel 6.32 behandelt worden.
248 6.6.1.3
6 Grundlagen von Anfragesprachen Sichere Ausdrücke im Tupelkalkül
Bei der Definition der Anforderungen an Anfragesprachen hatten wir verlangt, dass diese in endlicher Zeit ein Ergebnis liefern müssen. Dies impliziert, dass das Ergebnis einer Anfrage endlich ist. Im Folgenden wollen wir eine Anfrage sicher nennen, wenn sie für jeden beliebigen Datenbankzustand ein endliches Ergebnis liefert. Der Tupelkalkül ist keine sichere Anfragesprache, wie Beispiel 6.34 beweist: Beispiel 6.34: Nicht sichere Anfrage im Tupelkalkül „Gib alle Produkte aus, die nicht in der Relation Produkte enthalten sind.“ RANGE OF Pro IS Produkt RETRIEVE Pro WHERE NOT(Pro ∈ Produkt)31 Unter der Voraussetzung, dass die potenzielle Menge an Produkten unendlich ist, wird hier ein unendliches Ergebnis geliefert, da nach allen Produkten gefragt wird, die nicht zur Menge der gegenwärtig in der DB gespeicherten Produkte gehören. Um nun garantieren zu können, dass man nur sichere Anfragen stellen kann, muss es Einschränkungen bei der Formulierung von Anfragen im Tupelkalkül geben. Um erklären zu können, wann eine Anfrage als sicher gilt, soll zunächst spezifiziert werden, was die Domäne einer Anfrage ist. Definition 6.27: Domäne einer Formel (Anfrage) Die Domäne einer Formel (Anfrage) besteht aus allen Konstanten, die in der Formel (Anfrage) vorkommen, und allen aktuell in der DB existierenden Attributwerten der Relationen, die in der Formel (Anfrage) referenziert werden.32 Würden also in einer Anfrage an die Relationen Produkt und ProduktLagertIn die Tupelvariablen Pro und PLI benutzt, würden zur Domäne der Anfrage all die Werte gehören, die mindestens einem konkreten Attribut des zum Anfragezeitpunkt gültigen Schnappschusses der Relationen Produkt und ProduktLagertIn zugewiesen sind. Intuitiv formuliert ist eine Anfrage des Tupelkalküls sicher, wenn das Ergebnis der Anfrage eine Teilmenge der Anfragedomäne ist. Da die Domäne wegen der Endlichkeit eines Schnappschusses einer DB nur aus endlich vielen Werten bestehen kann, ist auch sichergestellt, dass das Ergebnis endlich ist. Definition 6.28: Sicherer Ausdruck im Tupelkalkül Ein Ausdruck des Tupelkalküls heißt sicher, wenn jede freie Tupelvariable des Bedingungsteils an endliche Bereiche gebunden wird und das Ergebnis der Anfrage sich nur aus Werten der Anfragedomäne zusammensetzt. In Beispiel 6.30 läuft die freie Tupelvariable Pro zwar nur über alle in der DB enthaltenen Produkte, also über eine endliche Menge, allerdings ist das Ergebnis der Anfrage wegen des NOT-Operators keine Teilmenge dieser Menge. 31 Das allgemeine Tupelkalkül lässt solche Anfragen zu, QUEL aber nicht, da QUEL nur sichere Ausdrücke zulässt und deshalb den NOT-Operator nicht unterstützt. 32 Die Anfragedomäne enthält also in der Regel Werte unterschiedlicher Wertebereiche.
6.6 Relationenkalkül
6.6.2
249
Bereichskalkül
Beim Bereichskalkül werden die Tupelvariablen durch Bereichsvariable ersetzt. Bereichsvariablen bewegen sich auf der nächst tieferen Abstraktionsebene, also statt auf der Ebene der Tupel auf der Ebene der atomaren Werte. Definition 6.29: Bereichsvariable Eine Bereichsvariable ist eine Variable, die nur Werte eines ihr zugeordneten atomaren Wertebereiches annehmen kann. Bereichsvariablen werden an die Basisdatentypen des relationalen Datenbankmodells gebunden, sodass der grundsätzliche Aufbau einer Anfrage im Bereichskalkül wie folgt aussieht: Bvar1 , Bvar2 , . . . , Bvarn präd(Bvar1 , . . . , Bvarn ) Bvari (1 ≤ i ≤ n) sind die Bereichsvariablen und repräsentieren Attributwerte. präd ist die Selektionsbedingung über die freien Bereichsvariablen Bvari . Der Aufbau von Formeln im Bereichskalkül entspricht in etwa dem Aufbau von Formeln im Tupelkalkül. Der entscheidende Unterschied ist, dass ein Tupel jetzt nicht mehr durch eine einzige Tupelvariable referenziert wird, sondern durch eine Sequenz von Bereichsvariablen. Analog zum Tupelkalkül besteht eine Formel aus Atomen. Definition 6.30: Atom im Bereichskalkül Atome können im Bereichskalkül wie folgt aussehen: 1. Bvar1 , Bvar2 , . . . , Bvarm ∈ Rel, wobei Rel eine n-stellige Relation ist und Bvari (1 ≤ i ≤ n) eine Bereichsvariable ist, die das i-te Attribut der Relation Rel darstellt. Hier wird also unterstellt, dass die Attribute einer Relation geordnet sind, und zwar in der im konzeptuellen Schema vorgegebenen Reihenfolge. 2. Bvarn θ Bvarm , wobei Bvarn und Bvarm Bereichsvariablen sind und θ für einen auf den Wertebereichen von Bvarn und Bvarm anwendbaren Vergleichsoperator steht. 3. Bvarn θ Konst, wobei Konst eine Konstante ist. Ansonsten gelten die Hinweise von 2. in analoger Weise. Definition 6.31: Formel im Bereichskalkül Für eine Formel im Bereichskalkül gelten folgende Aussagen: 1. Jedes Atom ist eine Formel. 2. Falls f1 eine Formel ist, so sind auch ¬f1 und (f1 ) eine Formel. 3. Sind f1 und f2 Formeln, so sind auch f1 ∨ f2 , f1 ∧ f2 und f1 ⇒ f2 Formeln.
250
6 Grundlagen von Anfragesprachen
4. Falls f1 (Bvar) eine Formel darstellt, wobei Bvar eine freie Bereichsvariable ist, dann sind auch (∃Bvar)f1 (Bvar) und (∀Bvar)f1 (Bvar) Formeln. Aus Gründen der Lesbarkeit soll im Folgenden eine Sequenz von Quantifizierungen der Art (∃Bvar1 )((∃Bvar2 )((∃Bvar3 )(f (Bvar1 , Bvar2 , Bvar3 , )))) (∃Bvar1 , Bvar2 , Bvar3 )f (Bvar1 , Bvar2 , Bvar3 , )
durch abgekürzt werden.
Beispiel 6.35: Anfragen in Tupelkalkül Zur besseren Vergleichbarkeit werden hier dieselben Beispiele verwendet wie in Kapitel 6.5.3, Beispiel 6.27 und Beispiel 6.33. 1. „Gib die Namen aller Mitarbeiter der Abteilung 1234 aus.“ N, V (∃M)(M, N, V, G, A ∈ Mitarbeiter ∧ A = ’1234’) 2. „Gib die Namen aller Mitarbeiter aus, die auch Kunden der Firma sind.“ N, V (∃M)(M, N, V, G, A ∈ Mitarbeiter ∧ (∃K)(K, N, V, R ∈ Kunden ∧ M = K)) 33 3. „Gib die Namen aller Mitarbeiter aus, die nicht Kunden der Firma sind.“ N, V (∃M)(M, N, V, G, A ∈ Mitarbeiter ∧ (¬∃K)(K, N, V, R ∈ Kunden ∧ M = K)) 4. „Gib die Namen aller Mitarbeiter mit einem Gehalt über 5.000,– C aus, die auch Kunden der Firma sind und einen Rabatt von mehr als 15 Prozent bekommen.“ N, V (∃M, G)(M, N, V, G, A ∈ Mitarbeiter ∧ G > 5000 ∧ (∃K, R)(K, N, V, R ∈ Kunden ∧ M = K ∧ R > 15)) 5. „Gib die Lager aus, in denen alle Produkte des Unternehmens gelagert werden.“ N, B (∃N)(N, B, O, Z ∈ ProduktLager ∧ (∀P)(P, C, D, E, F ∈ / Produkt ∨ (∃G, I)(G, H, I, J ∈ ProduktLagertIn ∧ I = P ∧ G = N))) 33 Die Verknüpfung der Datensätze geschieht hier zwar über die Kunden- und Mitarbeiternummer. Allerdings müssen, da es sich um ein- und dieselbe Person handelt, zwangsläufig auch Kunden(Vor)name und Mitarbeiter(Vor)name identisch sein.
6.6 Relationenkalkül 6.6.2.1
251
Sichere Anfragen im Bereichskalkül
Auch beim Bereichskalkül zieht man sich auf die Domäne einer Anfrage zurück, um zu spezifizieren, wann eine Anfrage sicher ist. Da Bereichsvariablen an die Attribute von Relationen gebunden sind, besteht die Domäne einer Anfrage nun aus der Menge aller Konstanten, die in der Anfrage vorkommen, und aus all den Attributwerten von Relationen, die in der Anfrage angesprochen werden. Die Bedingung, wann eine Anfrage sicher ist, gestaltet sich beim Bereichskalkül allerdings etwas komplexer als beim Tupelkalkül. Der Grund liegt darin, dass beispielsweise für eine Formel der Art (∀Bvar1 )(¬(Bvar1 , Bvar2 ∈ Rel)) alle Werte von Bvar1 überprüft werden müssten, die nicht im zu Grunde liegenden Schnappschuss von Rel vorkommen. Ein Schnappschuss einer Relation enthält aber immer nur endlich viele Tupel, weshalb, Unendlichkeit des zu Grunde liegenden Wertebereiches von Bvar1 vorausgesetzt, immer unendlich viele Werte des Wertebereiches von Bvar1 nicht in Rel vorkommen. Um Tests solcher Art ausschließen zu können, wurde die Menge der Restriktionen erweitert. Definition 6.32: Sichere Anfrage im Bereichskalkül Eine Anfrage Bvar1 , Bvar2 , . . . , Bvarn präd(Bvar1 , . . . , Bvarn ) des Bereichskalküls heißt sicher, falls die folgenden Bedingungen erfüllt sind: 1. Jeder in einem Ergebnistupel vorkommende Wert muss zur Anfragedomäne gehören. Dies bedeutet insbesondere auch, dass in der Anfrage verwendete Konstanten zur Anfragedomäne gehören müssen. 2. Jede Formel der Art (∃ Bvar1 )f1 (Bvar1 ) ist dann und nur dann gültig, falls es mindestens einen Wert in der Domäne von f1 (Bvar1 ) gibt, für den f1 (Bvar1 ) gültig ist. 3. Formeln der Art (∀Bvar1 )f1 (Bvar1 ) sind analog dann und nur dann gültig, falls f1 (Bvar1 ) für alle Werte aus der Domäne von f1 (Bvar1 ) gültig ist. Die Regeln 2. und 3. wurden eingeführt, damit bei einer Quantifizierung sichergestellt ist, dass nur endlich viele Möglichkeiten getestet werden müssen. 6.6.2.2
QBE
Die relationale Anfragesprache Query-By-Example (QBE) basiert auf dem Relationenkalkül. QBE lehnt sich sowohl an den Tupel- als auch an den Bereichskalkül an, wobei Letzterer allerdings den Haupteinfluss ausgeübt hat. QBE stellt eine grafikorientierte Anfragesprache dar. Im Prinzip wird für jede Relation des der Anfrage zu Grunde liegenden Datenbankausschnittes eine leere Tabelle am Bildschirm angezeigt. Eine Anfrage wird nun gestellt, indem in den Tabellen bei den für die Selektion zu verwendenden Attributen Einträge vorgenommen werden. Ohne hier weiter ins Detail gehen zu wollen, sei angemerkt, dass wegen der Intuitivität von QBE einfache Anfragen auch von ungeübten Benutzern schnell gestellt werden können. Bei zunehmender Komplexität der Anfragen verliert QBE allerdings schnell seinen Reiz. Beispiel 6.36: Anfragen in QBE Das System stellt dem Benutzer ein leeres Skelett für alle Relationen zur Verfügung, in das an den relevanten Stellen die Bedingungen und sonstigen Informationen einzutragen sind.
252
6 Grundlagen von Anfragesprachen
1. „Gib die Identifikation aller Produkte aus, deren Stückkosten unter 300,– C liegen.“ Produkt
produktNr
produktBez
P.
P.
produktTyp
stueckKosten
nettoPreis
< 300
Einfache relationenbezogene Bedingungen werden spezifiziert, indem an der entsprechenden Stelle die Bedingung in die Beispielrelation eingetragen wird. Eine mit P. (steht für print) markierte Spalte wird ausgegeben, gehört also zur Ergebnisrelation. 2. „Gib die Identifikation aller Produkte aus, deren Stückkosten zwischen 300,– C und 800,– C liegen.“ Produkt
produktNr
produktBez
P.
P.
produktTyp
stueckKosten
nettoPreis
_stueckKosten
conditions
conditions oder
_stueckKosten = (> 300 AND < 800)
_stueckKosten > 300 _stueckKosten < 800
Konstanten werden in QBE einfach in die entsprechende Spalte eingetragen, ohne die üblichen Abgrenzungssymbole wie z. B. (meist ’) bei einer Zeichenkette. Um daher Konstanten von (Bereichs-)Variablen unterscheiden zu können, müssen Letztere grundsätzlich mit einem Unterstrich (_) beginnen. Kunde ist also die Zeichenkette ’Kunde’, während eine so lautende Variable mit Unterstrich geschrieben werden muss (_Kunde). Da innerhalb einer Spalte nur eine einfache spaltenbezogene Bedingung festgelegt werden kann, wurde die Bedingungsbox (conditions) eingeführt. In ihr können komplexe Bedingungen spezifiziert werden. 3. „Gib die Identifikation aller Produkte aus, deren Stückkosten 20 Prozent unter dem Nettoverkaufspreis liegen.“ Produkt
produktNr
produktBez
P.
P.
produktTyp
stueckKosten
nettoPreis
_stueckKosten
_nettoPreis
conditions (_stueckKosten) ∗1,2 < _nettoPreis
Bedingungen, die sich nicht ausschließlich auf eine Spalte beziehen, müssen über die Bedingungsbox formuliert werden. 4. „Gib die Identifikation aller Produkte an, die in den Lagern Essen, Frankfurt und München mindestens noch 100-mal vorhanden sind.“ ProduktLagertIn
produktLagerNr
produktLagerBez
produktNr
istBestand
Essen
P._produktNr
≥ 100
Frankfurt
_produktNr
≥ 100
München
_produktNr
≥ 100
6.6 Relationenkalkül
253
Werden mehrere Zeilen in einer Tabelle ausgefüllt, wobei dieselbe Bereichsvariable verwendet wird, entspricht dies einer konjunktiven Verknüpfung der Bedingungen. 5. „Gib die Identifikation aller Produkte an, die entweder im Lager Essen oder Frankfurt noch mindestens 100-mal vorhanden sind.“ ProduktLagertIn
produktLagerNr
produktLagerBez
produktNr
istBestand
Essen
P. _nr1
≥ 100
Frankfurt
P. _nr2
≥ 100
Eine disjunktive Verknüpfung kann über die Angabe von verschiedenen Bereichsvariablen (hier _nr1 und _nr2) in derselben Ausgabespalte formuliert werden. 6. „Bestimme die Produkte, deren Stückkosten unter 300,– C liegen und deren Lagerbestand in einem Lager unter 100 liegt. Gib die Produktidentifikation und die Lagerbezeichnung aus.“ Produkt
produktNr P. _produktNr
ProduktLagertIn
produktBez
produktTyp
nettoPreis
< 300
P.
produktLagerNr
stueckKosten
produktLagerBez
produktNr
istBestand
P.
_produktNr
< 100
Ein Verbund wird über die Bereichsvariable durchgeführt. Die Verwendung derselben Bereichsvariablen in zwei Relationen bewirkt, dass Tupel aus beiden Relationen miteinander verbunden werden, sofern sie in den Spalten, wo die Bereichsvariable steht, den gleichen Wert aufweisen. 7. „Bestimme die Produkte, deren Stückkosten nicht genau 300,– C betragen und für die in keinem Lager der Lagerbestand unter 100 liegt. Gib die Produktidentifikation und die Lagerbezeichnung aus.“ Produkt
produktNr P. _produktNr
ProduktLagertIn
produktBez
produktTyp
produktLagerNr
nettoPreis
¬300
P.
¬
stueckKosten
produktLagerBez
produktNr
istBestand
P.
_produktNr
< 100
Der Unterschied zur vorherigen Frage besteht darin, dass hier die in der Tabelle ProduktLagertIn spezifizierten Bedingungen für kein Tupel gelten dürfen, was durch die Angabe von ¬ unter dem Tabellennamen ausgedrückt wird. Die Negation realisiert das NOT EXISTS-Prädikat. Feststellung 6.12: Mächtigkeit von QBE In seiner ursprünglich von Zloof vorgestellten Variante ist QBE relational vollständig, allerdings nicht streng relational vollständig. Es gibt also Operatoren in der relationalen Algebra, zu denen es kein adäquates Gegenstück in QBE gibt. Allerdings lässt sich jeder dieser Operatoren durch eine QBE-Anfrage simulieren.
254
6 Grundlagen von Anfragesprachen
Die bekannteste Implementierung von QBE34 ist nicht relational vollständig. Insbesondere wird die Möglichkeit der Negierung von Zeilen im Allgemeinen und der negierte Existenzquantor (NOT EXISTS, siehe Beispiel 6.36, 7.) im Speziellen nicht adäquat unterstützt. Daher konnten Anfragen der Art „Gib die Lager aus, in denen alle Produkte gelagert sind.“ nicht formuliert werden. Mit dem zunehmenden Einzug grafikfähiger Bildschirme in die Praxis gewinnen grafikbasierte Oberflächen immer mehr an Bedeutung. Es ist daher zu erwarten, dass über kurz oder lang der Einsatz von grafikfähigen Anfragesprachen deutlich zunehmen wird. Insbesondere unterstützen bereits einige auf PCs lauffähige kommerzielle DBMS Varianten von QBE.
6.6.3
Mächtigkeit der Relationenkalküle
Wie bereits erwähnt, sind die Relationenalgebra, der sichere Tupelkalkül und der sichere Bereichskalkül in ihrer Ausdruckskraft äquivalent. Es gilt sogar, dass alle drei Anfragesprachen streng relational vollständig sind. Für die Beweise dieser Aussagen sei auf Ullman35 verwiesen. Es soll hier aber gezeigt werden, wie die Basisoperatoren Vereinigung, Differenz, Kartesisches Produkt, Projektion und Selektion der Relationenalgebra im Bereichskalkül ausgedrückt werden können. Dazu seien zwei Relationenschemata Rel1 (x1 , . . . , xn ) und Rel2 (y1 , . . . , ym ) gegeben. • Vereinigung: Es muss gelten: n = m Rel1 ∪ Rel2 ∼ = z1 , . . . , zn | Rel1 (z1 , . . . , zn ) ∨ Rel2 (z1 , . . . , zn ) • Differenz: Es muss gelten: n = m Rel1 − Rel2 ∼ = z1 , . . . , zn Rel1 (z1 , . . . , zn ) ∧ Rel2 (z1 , . . . , zn ) • Kartesisches Produkt: Rel1 × Rel2 ∼ = x1 , . . . , xn , y1 , . . . , ym Rel1 (x1 , . . . , xn ) ∧ Rel2 (y1 , . . . , ym ) • Projektion: Es gelte attrTMist eine Teilmenge der Attribute von Rel1 ∼ z1 , . . . , zp (∃x1 , . . . , xn )(Rel1 (x1 , . . . , xn ) πattrTM (Rel1 ) = ∧ z1 = xi1 ∧ · · · ∧ zk = xik ) • Selektion: σ(präd(Rel1 )) ∼ =
x1 , . . . , xn ) Rel(x1 , . . . , xn ) ∧ präd)
präd wird dabei aus präd hergeleitet, indem anstelle des Attributnamens attri die Variable xi eingesetzt wird. 34 Hier handelt es sich um die QBE-Implementierung in QMF (Query M anagement F acility), einem Bestandteil des von IBM vertriebenen relationalen DBMS DB2. 35 siehe [Ullm88].
6.6 Relationenkalkül
255
Alle anderen relationalen Operatoren (bis auf die Umbenennung) können, wie wir bereits gesehen haben, aus den Obigen abgeleitet werden, insbesondere auch die Verbundoperationen. Der Weg von Kalkülausdrücken zu Ausdrücken der relationalen Algebra ist komplizierter und soll hier nicht weiter diskutiert werden. Trotzdem ist diese Umsetzung ein notwendiger Schritt, um die Möglichkeiten der Anfrageoptimierung auf der Basis der relationalen Algebra ausnutzen zu können. Die relationale Algebra wird in der Literatur häufig als prozedural bezeichnet, während der Relationenkalkül als deskriptiv angesehen wird. Der Relationenkalkül ist nicht nur streng relational vollständig, sondern sogar äquivalent zur relationalen Algebra. Zu jedem Ausdruck der relationalen Algebra existiert ein äquivalenter Ausdruck des Relationenkalküls (⇒ strenge relationale Vollständigkeit) und umgekehrt (⇒ Äquivalenz). Damit könnte man auch, wie es etwa Chris Date36 tut, den Standpunkt vertreten, dass eine 1:1-Beziehung zwischen beiden Ansätzen besteht. Die unterschiedlichen Formalismen repräsentieren dann nur unterschiedliche (syntaktische) Möglichkeiten, Ausdrücke zu formulieren, weshalb man die Eingruppierung deskriptiv und prozedural eher als Verkaufsargument für den Relationenkalkül denn als wissenschaftliche Aussage ansehen sollte. In der Syntax mag die relationale Algebra jedoch eher an prozedurale Programmiersprachen erinnern, während der Relationenkalkül näher an der natürlichen Sprache ist.
6.6.4
Zusammenfassung
Relationenkalküle stellen eine formale, logikbasierte Schnittstelle zur Verfügung, die es erlaubt, Aussagen zu formulieren, die von den Ergebnissen einer Anfrage erfüllt sein müssen. Damit gehören sie zu den Vertretern des deskriptiven Ansatzes. Der Relationenkalkül unterteilt sich in den Tupel- und den Bereichskalkül. Der Tupelkalkül ist grobgranularer, da er auf dem Tupel basiert, während der Bereichskalkül auf der nächst feineren Ebene, den atomaren Werten aufsetzt. Zu den prominenten Vertretern dieser Sprachgattung gehören QUEL und QBE, zwei Sprachen, die ihren Weg in die Praxis gefunden haben. Von der Mächtigkeit sind Relationenalgebra, der sichere Tupelkalkül und der sichere Bereichskalkül in ihrer Ausdruckskraft äquivalent, ein Umstand, der insbesondere auch für die Optimierung von Wichtigkeit ist.
6.6.5
Literatur
Viele der Bücher, die bereits im Zusammenhang mit der Relationenalgebra genannt wurden, behandeln auch den Relationenkalkül sehr ausführlich. Der Tupelkalkül und die Relationenalgebra wurden von Edgar Codd in [Codd72b] eingeführt. Dieses Papier setzt sich zusätzlich mit der relationalen Vollständigkeit auseinander. Codd hat auch die auf dem Tupelkalkül basierende Anfragesprache ALPHA entwickelt ([Codd71]). ALPHA ähnelt in seinem Aufbau QUEL, wurde allerdings niemals ernsthaft in eine Implementation umgesetzt. 36 siehe
[Date03].
256
6 Grundlagen von Anfragesprachen
A. Pirotte hat sich mit dem Bereichskalkül auseinander gesetzt ([LaPi77a]). In [Piro78] diskutiert er die Unterteilung des Relationenkalküls in den Tupel- und den Bereichskalkül. [Klug82] beschäftigt sich einerseits mit der Integration von Aggregatfunktionen in den Relationenkalkül. Andererseits werden auch Äquivalenzuntersuchungen zwischen Relationenalgebra und Relationenkalkül durchgeführt. Auch Date beschreibt in seinem Buch, wie Aggregatfunktionen sauber in die relationale Algebra bzw. in den Relationenkalkül integriert werden können ([Date03]). QUEL wurde von der Gruppe um Michael Stonebraker an der University of Berkeley im Zusammenhang mit deren relationalen DBMS INGRES entwickelt. Neben den IBM-Aktivitäten (System R, welches in DB2 mündete) war INGRES eines der wichtigsten und einflussreichsten Datenbankprojekte der damaligen Zeit. INGRES und insbesondere auch QUEL werden beispielsweise in [Ston86] und [SWKH76] vorgestellt. QBE wurde von M. Zloof in [Zloo75] und [Zloo77] und weiteren Artikeln beschrieben. Da auch M. Zloof zur Forschergruppe von IBM gehörte, wurde QBE auch von IBM implementiert und vertrieben. Auch wenn viele andere Anbieter kommerzieller relationaler DBMS diesem Beispiel folgten, hat QBE doch bei weitem nicht die Bedeutung von SQL erreicht (auch wenn es vermutlich die nach SQL am häufigsten verwendete Anfragesprache für relationale DBMS ist). QUEL und QBE werden in vielen der bereits diskutierten Lehrbücher über relationale DBMS vorgestellt.
6.7
Funktionen auf Mengen von Tupeln
Sowohl die Relationenalgebra als auch der Relationenkalkül sind relational vollständig, weshalb beide Sprachen äquivalent in ihrer Ausdruckskraft sind. Allerdings bedeutet relationale Vollständigkeit nicht, dass eine Anfragesprache die volle Mächtigkeit einer Programmiersprache besitzt, also beliebige berechenbare Funktionen spezifiziert werden können. Diese fehlende prozedurale Mächtigkeit führt dazu, dass die Weiterverarbeitung von Tupeln in der Regel nicht in der Anfragesprache erfolgen kann, sondern einer (assoziierten) Programmiersprache überlassen bleiben muss. Das bedeutet aber, dass die Daten von ihrer für das Datenbankmodell spezifischen Darstellung in eine dem Datenmodell der Programmiersprache (auch Typsystem der Programmiersprache genannt) entsprechenden Repräsentation überführt werden müssen (und umgekehrt). Bei diesem Abbildungsprozess muss fast zwangsläufig Semantik verloren gehen, weshalb man in diesem Zusammenhang vom impedance mismatch spricht. Wegen dieser Problematik ist man bei neueren DBMS, insbesondere bei objektorientierten, dazu übergegangen, als Schnittstelle zur DB eine vollständige Programmiersprache zu unterstützen, beispielsweise Smalltalk, Java oder C++. Es muss allerdings angemerkt werden, dass die erheblich größere Ausdrucks- und Modellierungsmächtigkeit einer objektorientierten Programmiersprache dazu geführt hat, dass eine vollständige, auf generischen Operationen basierende Anfragesprache wegen der durch die Mächtigkeit verursachten Komplexität lange Zeit nicht angeboten wurde. Zum Teil wurde stattdessen nur eine funktional stark eingeschränkte Anfragesprache für einfache Anfragen zur Verfügung gestellt. Komplexere Anfragen mussten mit Hilfe der zu Grunde liegenden Programmiersprache formuliert werden. In jüngster Zeit hat sich jedoch die ODMG (Object
6.8 Zusammenfassung
257
Database Management Group) mit der Entwicklung eines Standards37 (OQL) für eine adäquate Anfragesprache für objektorientierte DBMS hervorgetan, sodass mittelfristig erwartet werden darf, dass das Manko der fehlenden mächtigen Anfragesprache beseitigt sein wird. Relationale Anfragesprachen federn über die Integration von häufig gewünschten Berechnungen in die Anfragesprache das Problem etwas ab. Solche integrierten Funktionen heißen Aggregatfunktionen. Sie werden auf Mengen von Tupeln angewendet und liefern als Ergebnis einen elementaren Wert; sie „aggregieren“ also, weshalb das Ergebnis einer Aggregatfunktion eine Aussage über eine Menge von Tupeln ist, jedoch nichts direkt über den Inhalt einzelner Tupel aussagt. Die Integration der Aggregatfunktionen in die relationale Algebra bzw. den Relationenkalkül ist zwar einfach möglich, soll hier aber nicht weiter diskutiert werden. Stattdessen wird auf die einschlägige Literatur verwiesen. Die Aggregatfunktionen, die von den meisten Anfragesprachen unterstützt werden, lauten COUNT, SUM, AVG, MAX, MIN. Sie besitzen die folgende Semantik: • Die COUNT-Funktion ermittelt die Anzahl der unterschiedlichen Werte einer Spalte bzw. Spaltenmenge oder, falls sie sich auf die Relation allgemein bezieht, die Anzahl der Tupel einer Relation. • Die AVG-Funktion arbeitet auf numerischen Wertebereichen und berechnet den arithmetischen Mittelwert der Werte einer spezifizierten Spalte. • Ähnlich wie die AVG-Funktion arbeitet die SUM-Funktion nur auf numerischen Wertebereichen und berechnet die Summe der Werte einer gegebenen Spalte. • Die MAX- bzw. die MIN-Funktion ermitteln den größten bzw. den kleinsten aktuellen Wert einer spezifizierten Spalte.
6.8
Zusammenfassung
Während die Relationenalgebra heute vor allem bei der Optimierung von Anfragen eine Rolle spielt, bildet der Relationenkalkül in seinen beiden Versionen die Grundlage für unterschiedlichste Varianten von Anfragesprachen. Trotz gewisser Stärken konnten sich diese Sprachansätze in der Praxis allerdings nur sehr eingeschränkt durchsetzen.
Formale Basis
Anfragesprache
Bereichskalkül
QBE
Tupelkalkül
QUEL
Relationenalgebra
SQL
Abb. 6.2: Formale Basis gängiger relationaler Anfragesprachen 37 Anfang 2000 wurde die jüngste Variante des Standards veröffentlicht (siehe [CBBE00]). Sie ist eindrucksvoll ausdrucksstark und kompakt. An dieser Sprache hat sich die SQL-Standardisierungskommission die Zähne ausgebissen.
258
6 Grundlagen von Anfragesprachen
Abbildung 6.2 gibt einen Überblick über die formale Basis wichtiger Anfragesprachen. Die mit Abstand populärste relationale Anfragesprache, SQL, die sich zwischenzeitlich zum Standard (nicht nur) für relationale DBMS entwickelt hat, hat sowohl Wurzeln in der relationalen Algebra als auch im Tupelkalkül. SQL wird im nächsten Kapitel vorgestellt.
6.9
Kontrollaufgaben
Anmerkung: In den folgenden Schemata sind die Schlüsselattribute unterstrichen. Aufgabe 6.1: Makler Gegeben sei das folgende relationale Datenbankschema: Kunden (kundenNr, kundenName, kundenAdresse, rahmen) Makler (maklerNr, maklerName, wohnort, maklerProvision) Produkt (produktNr, produktBezeichnung, produktOrt, produktPreis) Auftrag (auftragsNr, auftragsMonat, kundenNr, maklerNr, produktNr, auftragsMenge) Formulieren Sie die folgenden Anfragen in relationaler Algebra und im Bereichs- bzw. Tupelkalkül: 1. Gesucht werden alle Kunden, die bisher noch nie mit dem Makler mit der Nr. 0707 zusammengearbeitet haben. 2. Gesucht werden alle Kunden, die bisher ausschließlich mit dem Makler mit der Nr. 0707 zusammengearbeitet haben. 3. Gesucht werden alle Produkte, die bisher noch niemals von einem Kunden aus „Essen“ über einen Makler aus „Düsseldorf“ bestellt wurden. 4. Gesucht werden alle Kunden, die bereits alle Produkte unter C 10,- bestellt haben. Aufgabe 6.2: Projekte Gegeben sei das folgende relationale Datenbankschema: Projekt (projektNr, projektBezeichnung, projektOrt) Mitarbeiter (mitarbeiterNr, mitarbeiterName, wohnOrt) Zuordnung (projektNr, mitarbeiterNr, funktion) Formulieren Sie die folgenden Anfragen in relationaler Algebra und im Bereichs- bzw. Tupelkalkül: 1. Gesucht werden alle Mitarbeiter, die nur an Projekten arbeiten, die an ihrem Wohnort stattfinden. 2. Gesucht werden alle Projekte, in denen zumindest ein Mitarbeiter aus „Essen“ mitarbeitet. 3. Gesucht werden Projekte, die an einem Ort stattfinden, an dem keiner der zugeordneten Mitarbeiter wohnt.
6.9 Kontrollaufgaben
259
Aufgabe 6.3: Mannschaften Gegeben sei das folgende relationale Datenbankschema: Trainer (trainerNr, trainerName) Spieler (spielerNr, spielerName, wohnOrt) SpielerMannschaft (spielerNr, mannschaftsNr, datumZuordnung) TrainerMannschaft (trainerNr, mannschaftsNr, datumZuordnung) Mannschaft (mannschaftsNr, mannschaftsBezeichnung, liga, trainingsOrt) Formulieren Sie die folgenden Anfragen in relationaler Algebra und im Bereichs- bzw. Tupelkalkül: 1. Gesucht werden die Mannschaften (Mannschaftsnr, Bezeichnung), in denen mindestens ein Spieler mit Wohnort „Kleinhollywood“ spielt. 2. Gesucht werden alle Mannschaften, in denen mindestens ein Spieler den gleichen (Nach)namen hat wie der Trainer der Mannschaft. 3. Gesucht werden Mannschaften, die an einem Ort trainieren, an dem alle ihre Spieler wohnen. 4. Gesucht werden Trainer, die alle Mannschaften der Liga „Galaxy“ trainiert haben. Aufgabe 6.4: Kunden Gegeben ist folgendes Datenbankschema: Artikel (artikelNr, artikelBezeichnung, artikelPreis, artikelBestand, minBestand) Bestellung (bestellNr, kundenNr, bestellDatum, rechnungsBetrag) Position (bestellNr, artikelNr, bestellMenge, gesamtPreis) Kunden (kundenNr, kundenName, kundenAnschrift, letzteBestellung) Girokonto (kundenNr, iban, bic) Formulieren Sie in relationaler Algebra und im Bereichs- bzw. Tupelkalkül: 1. Welche Kunden haben kein Girokonto? Geben Sie die Kundennamen aus. 2. Welche Kunden haben noch nie bestellt? Geben Sie die Kundennamen aus. 3. Welche Kunden haben bereits alle Artikel bestellt? 4. Welche Artikel sind in welcher Menge von wem bisher bestellt worden? Erstellen Sie eine Liste mit Kundenname, Artikelbezeichnung, Bestelldatum und -menge. 5. Listen Sie alle Kunden mit den zugehörigen Bankverbindungen auf, falls es eine solche gibt.
260
6 Grundlagen von Anfragesprachen
Aufgabe 6.5: Lieferanten Gegeben ist folgendes Datenbankschema: Lager (artikelNr, lagerBezeichnung, lagerBestand) Lieferant (lieferantenNr, lieferantenName, lieferantenAnschrift) Angebot (artikelNr, lieferantenNr, preis, mindestAnzahl) Es gilt folgende Bedingung: Sofern man mindestens „mindestAnzahl“ abnimmt, kann dieser Artikel bei diesem Lieferanten zum angegeben „Preis“ bezogen werden. Formulieren Sie die folgenden Anfragen in relationaler Algebra und im Bereichs- bzw. Tupelkalkül: 1. Listen Sie alle Lieferanten (Name, Anschrift) auf, die „Reifen“ anbieten, die bei Abnahme von mindestens 100 Stück weniger als 1.000,– C kosten. 2. Listen Sie alle Lieferanten (Name, Anschrift) auf, die ausschließlich „Reifen“ anbieten. Aufgabe 6.6: Flugunternehmen Im Informationssystem eines Flugunternehmens sind folgende Relationenschemata enthalten: Anforderungen (flugzeugTyp, anforderungsKlasse) Bewerber (bewerberNr, bewerberName, flugzeugTyp, artLizenz, wohnort) Flugrouten (flugNr, flugVon, flugNach, abflugZeit, ankunftsZeit, flugzeugTyp) Es gibt mehrere Klassen von Anforderungen. Ein Pilot erfüllt eine Anforderungsklasse, wenn er alle Flugzeugtypen dieser Klasse fliegen kann. bewerberNr ist die eindeutige Identifikation jedes Bewerbers. Flugzeugtyp entspricht dem Typ, den der Pilot fliegen darf. Es gibt eine Tag- und eine Nachtfluglizenz. Der Besitz einer Nachtfluglizenz setzt eine Tagfluglizenz voraus. Ein Nachtflug ist ein Flug, der zwischen 19:30 und 7:00 Uhr stattfindet. Formulieren Sie die folgenden Anfragen in relationaler Algebra und im Bereichs- bzw. Tupelkalkül: 1. Welche Bewerber erfüllen die Anforderungsklasse 1? 2. Welche Bewerber mit Wohnort=’Berlin’ erfüllen die Anforderungsklasse 2? Welche Bewerber wohnen in einer Stadt, die von einem Flug der betrachteten Fluglinie angeflogen wird? 3. Welche Bewerber könnten den Flug Wien-Mailand, Abflugzeit 22:40 Uhr, Ankunft in Mailand um 0:30 Uhr, Type Airbus A320, übernehmen? 4. Welcher Bewerber könnte welche Flüge übernehmen? Flüge mit einer Flugdauer von über 24 Stunden werden nicht berücksichtigt.
7
Die relationale Datenbanksprache SQL The nice thing about standards is that there are so many of them to choose from.1
7.1
Einführung in SQL
Historie von SQL Fünf Jahre nach Vorstellung des relationalen Datenbankmodells durch Edgar Codd im Jahre 1969 wurde vom IBM-Forschungslabor in San José im Jahre 1974 die erste Version einer Anfragesprache vorgestellt, die deskriptive Züge besaß ([ChBo74]). SEQUEL (Structured English Query Language), so ihr Name, war die Anfragesprache von System R2 , dem ersten von IBM entwickelten Prototyp eines relationalen DBMS. SEQUEL wurde von 1975 bis zum Ende der 70er Jahre zu SEQUEL-2 weiterentwickelt. Auf der Basis der mit SEQUEL 2 gemachten Erfahrungen wurden Anfang der 80er Jahre erste kommerzielle SQL-Dialekte entwickelt. Diese setzten allerdings nur eine Untermenge der SEQUEL-2-Konzepte um. Da nicht nur der englischsprachige Markt angesprochen werden sollte, wurde SEQUEL in SQL (Structured Query Language) umbenannt. IBM präsentierte ihr erstes kommerzielles relationales DBMS SQL/DS und kurze Zeit später (1983) DB2 der Öffentlichkeit. Beide Produkte erfuhren eine starke Unterstützung aus dem damals noch marktdominierenden Hause IBM (zumindest in Bezug auf die relationale Datenbanktechnologie und den Interessen von IBM daran – hausintern lag das Interesse wesentlich massiver bei dem damals marktdominierenden hierarchischen DBMS IBM Information Management System (IMS)). Infolge dieser Unterstützung durch IBM entwickelte sich SQL trotz solcher Konkurrenz wie QUEL ([SAHR84]) oder ILL ([LaPi77b]) schnell zum Quasi-Standard für Anfragesprachen für (relationale) DBMS. So war es nicht weiter verwunderlich, dass SQL dann auch in den Jahren 1982 bis 1986 von der ANSI (American N ational Standard Institute) und dann auch von der ISO (International Standardization Organization) einem Normierungsprozess unterworfen wurde. In Anlehnung an das Abschlussjahr dieser Bemühungen wurde der erste Standard SQL-86 genannt. Trotz langer Vorüberlegungen und -arbeiten war der eigentliche Entwurf des Standards relativ schnell entstanden. 1 Das
Zitat stammt aus [EiMe98a] und wird sowohl Grace Hopper als auch Andrew S. Tanenbaum zugeschrieben. gute Beschreibung von Sytem R findet sich in [ABCE76]
2 Eine
262
7 Die relationale Datenbanksprache SQL
Schnell stellte sich heraus, dass insbesondere wichtige Konzepte zur Sicherstellung und Wahrung der Konsistenz fehlten. Daher wurde der SQL-86-Standard zwar zunächst freigegeben, allerdings mit der Absicht, ihn schnellstmöglich um die fehlende Funktionalität zu erweitern. Die Ergänzungsarbeiten dauerten dann doch drei Jahre, so dass die endgültige Version des ersten Standards erst 1989 veröffentlicht und entsprechend SQL-89 genannt wurde. Die zusätzlich definierten Integritätssicherungskonzepte wurden IEF (Integrity Enhancement F eatures) genannt. Aus strategischen Gründen wurden sie allerdings nicht als notwendige, sondern nur als optionale Eigenschaften des Standards definiert. SQL-89 unterscheidet zwei Ebenen, Level 1 und Level 2, und die optionalen IEF-Eigenschaften. Die höhere Ebene schließt die tiefere vollständig ein. Damit sollte den Entwicklern von SQL-Dialekten ein inkrementelles Herantasten an die volle Ausbaustufe schmackhaft gemacht werden. Die wesentlichen Basiskonstrukte von SQL sind vergleichsweise einfach zu verstehen, weshalb sich einfache Anfragen auch schnell formulieren lassen. In der täglichen Praxis offenbarte SQL-89 jedoch schnell ernste Schwächen, insbesondere in Bezug auf Orthogonalität. Im Jahre 1992 wurde eine deutlich verbesserte und erweiterte ANSI- bzw. ISO-Norm veröffentlicht, SQL2 bzw. SQL-92 genannt. Um den schnellen Umstieg auf SQL-92 zu ermöglichen, wurden diesmal drei Sprachebenen definiert, der Entry-, der Intermediate- und der Full-Level. Der Entry-Level ist fast identisch mit dem Level 2 von SQL-89. Damit war es für viele Hersteller einfach, die Anforderungen des neuen Standards zu erfüllen. Die zunächst einmal begrüßenswerte Idee, über den leichten Zugang den schnellen Umstieg und damit die schnelle und weitreichende Verbreitung des SQL-Standards zu forcieren, erwies sich im Nachhinein als Bumerang. Sobald die Hersteller erst einmal das werbewirksame Label „erfüllt den SQL-Standard“ erhalten hatten, sank das Interesse erheblich, auf höhere Level aufzusteigen. Grundsätzlich haben natürlich auch die SQL-Anbieter ein Interesse an einem möglichst konsistenten und allumfassenden SQL-Dialekt. Dieser muss jedoch nicht dem SQL-Standard entsprechen, sondern wird zur besseren Kunden“bindung“ i. d. R. herstellerspezifisch ausgelegt und sei es nur, indem andere Schlüsselwörter genutzt wurden. Dieser Umgang mit dem SQL-Standard zeigt das inheränte Dilemma auf, mit dem sich die Entwickler von Standards auseinander setzen müssen. Grundsätzlich gilt zunächst, dass eine Anfragesprache so einfach aufgebaut sein muss, dass auch ein unbedarfter Anwender schnell lernt, damit fehlerfrei umzugehen. Soll eine solche Sprache dann erweitert werden, so muss sich jede zusätzliche Eigenschaft so effizient implementieren lassen, dass aus der Sicht des Kunden keine Effizienzeinbußen gegenüber der vorherigen Version zu beobachten sind. Frei nach dem Motto „Never replace reliable software without convincing reasons“ muss auch sichergestellt sein, dass die Änderungen aus ökonomischer Sicht Sinn machen. Hinreichend viele aktuelle und potenzielle Kunden müssen die Ergänzungen als sinnvoll und wünschenswert erachten, so dass sie aufgrund der zusätzlichen Funktionalität auf das erweiterte DBMS „aufrüsten“ bzw. umschwenken würden. Dies bedeutet zweierlei: Einerseits darf es der Hersteller eines DBMS nicht versäumen, wesentliche Eigenschaften des Standards, also Eigenschaften, die von hinreichend vielen Kunden gewünscht werden, effizient umzusetzen. Andererseits muss man sich aber auch sichtbar von anderen Herstellern abgrenzen, indem Funktionalität angeboten wird, die andere so nicht bieten. Der übliche Weg ist dann, nur die Minimalanforderungen zur Erreichung des Labels SQL-XY-kompatibel wie vorgeschrieben umzusetzen.
7.1 Einführung in SQL
263
Bei allem, was darüber hinausgeht, mag der Geist des Standards zwar Pate stehen, die Umsetzung erfolgt aber oft herstellerspezifisch. Damit soll aktuellen Kunden ein einfacher Umstieg auf ein Konkurrenzprodukt erschwert werden. Hinzu kommt auch noch, dass es in Bezug auf den aktuellen SQL-Dialekt eines Herstellers Konzepte und Eigenschaften des Standards geben wird, die sich einfach integrieren lassen, weil sie gut verträglich zum aktuellen Implementierungskonzept sind. Andererseits wird es aber auch Funktionalität geben, die sich nur mit viel Aufwand integrieren lässt. Vor diesem Hintergrund ist es nicht verwunderlich, dass DBMSHersteller nicht freiwillig auf den vollen SQL-Standard einsteigen. Stattdessen decken die meisten SQL-Dialekte lediglich den Entry-Level ab. Darüber hinaus werden weitere wesentliche Konzepte unterstützt. Der Intermediate- oder Full-Level wird jedoch noch von keinem Dialekt voll unterstützt. Eine solche Entwicklung war schon frühzeitig vom National Institute of Standards and Technology (NIST), einem Normierungsinstitut der amerikanischen Bundesbehörden, erkannt worden. Deshalb hat es eine weitere Zwischenstufe eingeführt, Transitional SQL genannt, die zwischen dem Entry- und dem Intermediate-Level liegt. Diese Stufe erfüllen einige Dialekte. Es sei noch angemerkt, dass die Standards im Normalfall abwärtskompatibel sind. Die Ausnahmen betreffen Fälle, die in der Praxis nie oder fast nie vorkommen bzw. schon immer herstellerspezifisch gehandhabt worden sind.
SQL-87 SQL-89 Entry SQL-92 Intermediate SQL-92 Full SQL-92 SQL:1999 SQL:2003 SQL:2006 SQL:2011
Abb. 7.1: Die Entwicklung der SQL-Standards
Ironischerweise wurde trotz des Standards mit der Open Database Connectivity (ODBC)3 eine standardisierte Anwendungsprogrammschnittstelle (application program interface (API)) 3 ODBC wurde ursprünglich von Microsoft eingeführt. Deshalb ist die entsprechende Seite bei Microsoft noch eine gute Referenz: http://msdn.microsoft.com/en-us/library/ms710252(v=vs.85) (Zugriff im Aug. 2013).
264
7 Die relationale Datenbanksprache SQL
für (relationale) Datenbanksysteme entwickelt, über die Datenbanksysteme mit Hilfe eines essentiellen Kerns von SQL-Sprachkonstrukten angesprochen werden können. Damit wird es einem Programmierer erlaubt, seine Anwendung unabhängig vom verwedneten SQL-Dialekt zu entwickeln. Vorraussetzung ist allerdings, dass für das schließlich zu verwendende DBMS ein entsprechender ODBC-Treiber existiert. Gruindsätzlich kann eine Anwendung damit zwar SQL-Dialekt-unabhängig entwickelt werden. Der Preis, der zu zahlen ist, ist aber, dass der SQL-Anteil sich auf einen stark eingeschränkten Kern von SQL beschränken muss. Mithin die volle Funktionalität von SQL-Dialekten nicht zur Verfügung steht. Auch ODBC-Treiber können einen unterschiedlichen Funktionsumfang haben (Core (nur Basisfunktionalität), Level 1, Level 2). Anwendungsprogrammen wird damit auch ein einheitlicher, unkomplizierter Zugriff auf unterschiedliche DBMS ermöglicht, falls sie für ihre Arbeit auf mehrere Datenquellen zugreifen müssen. Der Datenzugriff erfolgt dabei nicht unmittelbar auf eine Datenquelle, sondern geht immer über den entsprechenden ODBC-Treiber. So ist sichergestellt, dass transparent auf jede lokale oder entfernte Datenquelle zugegriffen werden kann, für die ein entsprechender ODBS-Treiber existiert. Weitere Entwicklung von SQL DBMS haben sich gemausert. Bedingt durch immer schnellere Hardware und immer effizientere Implementierungen zieht man die Verwendung solcher Systeme zwischenzeitlich auch in Anwendungsumgebungen in Betracht, die sich traditionell eher auf maßgeschneiderte Eigenentwicklungen zur Datenhaltung verlassen haben. Parallel dazu ist der massive Trend hin zu objektorientierten Systemen unübersehbar. Viele objektorientierte Systeme stellen allerdings ebenso wie die sogenannten Nichtstandard-Anwendungen Anforderungen an die Modellierungsfähigkeiten von DBMS, die häufig erheblich über die noch vergleichsweise bescheidenen Möglichkeiten aktueller relationaler Datenbankmodelle hinausgehen. Insbesondere auch diese erheblich gestiegenen Anforderungen nimmt der im Jahre 1999 neu verabschiedete aktuelle SQL-Standard, SQL:1999 genannt, ins Visier. Die ursprünglichen sehr hochfliegenden Pläne, eine Art „eierlegende Wollmilchsau“ zu konzipieren, folgte aber recht bald die Ernüchterung. SQL kämpft mit sehr vielen Altlasten und basiert auf Grundkonzepten, die den heutigen Ansprüchen komplexer Systeme nur noch sehr bedingt gerecht werden können. Nichtstandard-Anwendungen erwarten, dass komplexe Objekte auch als Ganzes abgelegt und bearbeitet werden können. Damit rücken beispielsweise die durch die Normalisierung ausgelöste Zerlegung komplexer Objekte und die eng damit zusammenhängende Verbundoperation zwangsläufig in den Hintergrund. Andererseits muss eine adäquate Anfragesprache das Navigieren in komplexen Objekten unterstützen. Dies deutet schon an, dass eine auf die Behandlung komplexer Objekte zugeschnittene Anfragesprache ihre Akzente zwangsläufig anders gesetzt haben muss als das auf einem sehr einfachen Datenbankmodell basierende SQL. Die Schwierigkeiten, die mit dem Spagat zwischen der Altlast des (zu) einfachen Datenbankmodell einerseits und der Hinwendungen zu modernen objektorientierten Konzepten andererseits verbunden sind, mussten auch die an der Entwicklung des neuen Standards beteiligten Experten eingestehen. Deshalb ist es nicht verwunderlich, dass der auf vielen Seiten dokumentierte objektrelationale Teil des SQL-Standards nur in sehr kleinen und langsamen Schritten Einzug in die Praxis findet. Die mit ihm verbundene Komplexität wird seine vollständige Umsetzung schon aus technischen Gründen auf absehbare Zeit unmöglich machen.
7.1 Einführung in SQL
265
Die Probleme liegen dabei durchaus nicht so sehr auf der konzeptionellen Seite, sondern vielmehr bei einer effizienten Implementierung. Die konzeptuellen Neuerungen sind als so gravierend anzusehen, dass herkömmliche Implementierungen von relationalen DBMS grundlegend zu überarbeiten sind. Dabei darf nicht vergessen werden, dass die aktuellen, zwischenzeitlich sehr effizienten Implementierungen lange gebraucht haben, bis man aufgrund von Forschungsergebnissen und Erfahrungen diesen Stand erreicht hatte. Bei den jetzt notwendigen Neuimplementierungen müsste man dann allerdings teilweise wieder auf der grünen Wiese anfangen, mit allen Nachteilen für die damit zu erwartende Performanz. Der oben erwähnte sogenannte objektrelationale Teil von SQL wurde vor allem noch im Nachfolgestandard SQL:2014 überarbeitet und erweitert. Im Folgenden wird weitestgehend zunächst einmal SQL auf der Basis des 92-Standards vorgestellt. Dieser Standard bildet immer noch den Kern vieler SQL-Dialekte. Weiterhin wird der objektrelationale Teil von SQL in Kapitel 8 intensiver vorgestellt. Dieser Teil des Standards spielt allerdings in fast allen Dialekten von SQL noch keine Rolle. Eine rühmliche Ausnahme bildet hier nur Oracle und mit Abstrichen DB2 von IBM. Nach 2014 gab es noch weitere Versionen des Standards (SQL: 2006, SQL: 2008 und SQL: 2011). Hier wurden allerdings vor allem Neuerungen eingeführt, die in Bezug auf dieses Buch von sehr untergeordneter Relevanz sind und deshalb auch nicht weiter diskutiert werden. Konzeptionelle Einordnung von SQL SQL wird oft eine deskriptive Anfragesprache genannt. Auch wenn man über diese Einordnung zumindest im engeren Sinn streiten kann, ist nicht weg zu diskutieren, dass sich SQL bereits auf einer relativ implementierungsunabhängigen Ebene bewegt. Logische und vor allem physische Datenunabhängigkeit werden konsequent und weitgehend gewährleistet. SQL lässt sich nicht sauber einem „Sprachenlager“ zuordnen. Die Sprache basiert im Wesentlichen auf dem Tupelkalkül, ist aber auch mit algebraischen Elementen und anderen Erweiterungen durchsetzt. Damit ist SQL mehr als relational vollständig. Zu den darüber hinausgehenden Konstrukten gehören insbesondere die arithmetischen Operationen und Aggregatfunktionen (siehe Kapitel 7.3.1.3 und 7.3.1.4). Untergliederung von SQL Bevor mit einer DB gearbeitet werden kann, muss sie zunächst einmal eingerichtet werden. Dazu und für Änderungen am Datenbankschema gibt es die Datendefinitionssprache (Data Definition Language, abgekürzt DDL). Das Einfügen, Löschen und Verändern von Datensätzen erfolgt über die Datenmanipulationssprache (Data M anipulation Language, abgekürzt DML). Anfragen an die DB können mit Hilfe der Datenbankanfragesprache (Data Retrieval Language, abgekürzt DRL) abgesetzt werden. Gelegentlich ordnet man auch noch die Vergabe von Zugriffsrechten bzw. allgemeiner die Gewährleistung von Datensicherheit einer eigenen Sprache zu. Sie wird dann Datenkontrollsprache (Data Control Language, abgekürzt DCL) genannt.
266
7 Die relationale Datenbanksprache SQL
Die obigen vier Aufgabenfelder von SQL können der konzeptuellen Sprachebene zugeordnet werden und müssen demnach auch von einer deskriptiven Sprache abgedeckt werden. Aus diesem Grund konzentrieren sich die Standardisierungsbemühungen auch exakt auf diese Aufgaben. Zur Sicherstellung einer zufrieden stellenden Performanz ist es allerdings nach wie vor unvermeidlich, dem DBMS Hinweise zur Gestaltung der internen Ebene zu geben, insbesondere zur Verwaltung so genannter Primär- und Sekundärindexe (Zugriffspfade). Diesem Zweck dient die Speicherungsstrukturdefinitionssprache (Storage Structure Language, abgekürzt SSL bzw. Data Storage Definition Language, abgekürzt DSDL). Dieser Sprachteil von SQL unterliegt nicht den Standardisierungsbemühungen, was wegen der engen Verknüpfung mit der internen Ebene und damit mit der spezifischen Implementierung eines DBMS auch nicht zweckmäßig wäre. Im Buch soll die SSL auch nur kurz gestreift werden, indem deren wesentlichste Aufgabe, die Anlage von Zugriffspfaden, exemplarisch aufgezeigt wird. Der Name SQL suggeriert, dass es sich hier um eine reine Anfragesprache handelt. Dieser Schein trügt jedoch. SQL deckt die komplette Funktionalität der Einrichtung, der Wartung, des Arbeitens und des Veränderns der DB ab. Weiterhin ist es durchaus üblich, Datenmanipulation und -anfrage unter dem „Ober“begriff Datenmanipulation zusammenzufassen. Wir werden im Folgenden aus Gründen der Systematik jedoch die feinere Unterscheidung beibehalten. Grundsätzlicher Aufbau einer SQL-Anfrage Obwohl SQL konzeptuell in fünf Sprachteile untergliedert werden kann, wird man diese Untergliederung in der Praxis kaum wahrnehmen. Insbesondere die der DRL zurechenbaren Anfragen werden auch in anderen Sprachteilen intensiv genutzt. Da damit die Einführung von Sprachteilen ohne Kenntnis des prinzipiellen Aufbaus einer SQL-Anfrage eher schwierig ist, soll sie hier schon einmal intuitiv eingeführt werden. Abstrakt gesehen setzt sich eine Anfrage in einer deskriptiven Anfragesprache aus drei Aufgaben zusammen (siehe Abbildung 7.1). Als Erstes ist festzulegen, welches die Datenbasis für die Anfrage ist. Die zweite Aufgabe ist, die Bedingungen festzulegen, die die Daten zu erfüllen haben, damit sie zum Ergebnis gehören. Als Drittes ist schließlich noch zu spezifizieren, welche Daten in welcher Form das Ergebnis darstellen sollen. Diese Dreiteilung einer Anfrage spiegelt sich auch in der Grundstruktur einer SQL-Anfrage, dem SELECT-FROMWHERE-Block, verkürzt SFW-Block genannt, wider. In der FROM-Klausel wird die Ausgangstabelle der Anfrage aufgebaut. Da sie als virtuelle Tabelle nur im Hauptspeicher existiert, spielt Redundanz keine Rolle. Dementsprechend stellt sie eine Art Universaltabelle dar, in der alle Informationen, sprich Spalten, enthalten sind, die beim Abarbeiten der Anfrage gebraucht werden. Eine Universaltabelle entsteht immer dann, wenn alle aus der Sicht einer Anwendung relevanten Daten der Basistabellen ohne Rücksicht auf die Normalisierungstheorie in einer Tabelle vereinigt zur Verfügung gestellt werden. In der WHERE-Klausel werden die Bedingungen spezifiziert, die von den Zeilen zu erfüllen sind, damit sie in die Ergebnismenge aufgenommen werden können. Schließlich beschreibt
7.1 Einführung in SQL
267 Basistabellen
Sekundärspeicher
 Aufbau der universellen Ausgangstabelle Hauptspeicher
 Auswahl der Ergebniszeilen Hauptspeicher
 Festlegen des Aufbaus der Ergebnistabelle Hauptspeicher Abb. 7.2: Aufbau einer SQL-Anfrage
die SELECT-Klausel den exakten Aufbau der Ergebnistabelle (siehe Abbildung 7.2). Entgegen der Reihenfolge der Formulierung muss man sich die prinzipielle Abarbeitung eines SFW-Blockes in der Reihenfolge FROM-WHERE-SELECT vorstellen.
268
7 Die relationale Datenbanksprache SQL
Beispiel 7.1: Einfache SQL-Anfrage „Erstelle eine Liste mit Auftragsnummer und Datum aller Aufträge, die der Zulieferer mit der Nr. 121212 bekommen hat.“ SELECT FROM WHERE
auftragsNr, datum AuftragZulieferer zuliefererNr = 121212;
„Welche Teile werden von einem Zulieferer aus Essen geliefert?“ SELECT FROM WHERE
teilNr, teilBez Zulieferer NATURAL JOIN Liefert NATURAL JOIN Teil ort = ’Essen’;
SQL und das relationale Datenbankmodell Bisher waren wir davon ausgegangen, dass ein relationales DBMS auf einem durchgängigen relationalen Datenbankmodell beruht. Dies impliziert insbesondere, dass eine DB aus einer Menge von Relationen besteht, die sich wiederum jeweils aus einer Menge von Tupeln zusammensetzen (siehe Abschnitt 5.1). Der Zugriff auf die Daten der DB geschieht über eine Anfragesprache, meistens SQL. Eine Anfragesprache muss zwangsläufig ein bestimmtes Datenbankmodell reflektieren bzw. umsetzen. Im Fall von SQL würde man natürlich erwarten, dass dies das relationale Datenbankmodell ist. Genau genommen ist dem aber nicht so. Zwar stimmen das relationale Datenbankmodell und das durch SQL ausgedrückte Datenbankmodell in weiten Teilen überein, es gibt aber auch ein paar Unterschiede, von denen zumindest einer substantiell ist. Das Ergebnis einer SQL-Anfrage kann eine Multimenge sein. Eine Multimenge4, auch Bag genannt, darf im Gegensatz zur „normalen“ Menge Duplikate enthalten. Sie stellt also trotz des etwas irreführenden Namens keine Menge im mathematischen Sinn dar5 . Dieser Umstand mag auf den ersten Blick nicht sehr schwer wiegen, führt aber doch zu massiven Problemen. Einerseits können die der Mengentheorie zu Grunde liegenden mathematischen Gesetze nur noch eingeschränkt genutzt werden, was insbesondere die Möglichkeiten zur Optimierung von Anfragen einschränkt. Andererseits kann aber auch die intuitive Semantik von SQL-Anfragen beeinträchtigt werden, wodurch eine potenzielle Fehlerquelle entsteht, wie wir später noch anhand von Beispielen demonstrieren werden. Deshalb gibt es durchaus lautstarke Kritiker dieser Multimengeneigenschaft von SQL, zu denen so berühmte Persönlichkeiten wie Edgar Codd, Chris Date und Hugh Darwen zählen. Feststellung 7.1: Keine vollständige Unterstützung des relationalen Datenbankmodells SQL unterstützt das relationale Datenbankmodell nicht voll, da SQL statt auf Mengen nur auf einer schwächeren Variante, den Multimengen aufsetzt. 4 Englisch:
Multiset genommen muss hier differenziert werden zwischen dem DRL-Teil von SQL und dem Rest (insbesondere der DML und der DDL). Da die DDL quasi das Werkzeug ist, mit dessen Hilfe das relationale Datenbankmodell umgesetzt wird, muss dieser Teil von SQL zwangsläufig auch vollständig auf dem relationalen Datenbankmodell beruhen. Dem ist auch so, da die Basisrelationen des konzeptuellen Datenbankschemas keine Duplikate enthalten dürfen. 5 Genau
7.1 Einführung in SQL
269 Relationaler Ausdruck
SQL-Ausdruck
Relation (Menge)
Tabelle
Tupel
Zeile
Attribut
Spalte
Tabelle 7.1: Gegenüberstellung von relationalen und SQL-Ausdrücken
Die SQL-Standardisierungskommission vermeidet es auch, von Relationen, Tupeln und Attributen zu sprechen. Stattdessen werden die Ausdrücke Tabelle, Zeile und Spalte (siehe Tabelle 7.1) verwendet. Um bei einer sauberen Begriffsverwendung zu bleiben, werden wir uns in diesem Kapitel dieser Notation anschließen. Konventionen im Buch bei der Einführung von SQL Die Syntax von SQL wird exemplarisch auf der Basis einer erweiterten Backus-Naur-Notation eingeführt (siehe Tabelle 7.2) Es sei schon hier darauf hingewiesen, dass in diesem Kapitel keine vollständige Spezifikation des SQL-Standards vorgenommen werden soll. Dies soll den dafür bestimmten Büchern und Dokumentationen überlassen bleiben. Stattdessen werden wir nur die aus unserer Sicht wesentlichen Sprachkonstrukte von SQL einführen, was insbesondere auch bedeutet, dass die vorgestellten Sprachkonstrukte aus Gründen der Übersichtlichkeit gelegentlich nicht in ihrer vollen Breite eingeführt werden. Achtung 7.1: Keine reine ASCII Notation in SQL-Anfragen Aus Gründen der Lesbarkeit wird von den Fähigkeiten einer modernen Textverarbeitung Gebrauch gemacht, so dass nicht jede der angegebenen SQL-Anweisungen auch exakt so in einem realen SQL-Dialekt formuliert werden kann. Der ASCII-orientierte SQLStandard kennt beispielsweise weder Höher-/Tieferstellungen noch Sonderzeichen. So muss beispielsweise in fast allen Dialekten ≥ (≤) durch >= ( DATE ’2014-01-01’ 2. DATE ’1923-04-16’ < DATE ’1950-03-13’ 3. TIME ’11:39:40.55’ > TIME ’10:00:00.00’ Tabelle 7.4 zeigt, welche Operatoren mit welchen Datentypen harmonieren und von welchem Typ dann das Ergebnis ist. Datetime ist dabei entweder ein Datum oder ein Zeitpunkt. Zeichen- und bitbasierte Datentypen Mit Hilfe der zeichenbasierten Datentypen CHAR und CHAR VARYING (auch VARCHAR genannt) können Textsequenzen wie z. B. Briefe abgelegt und verwaltet werden. Um dabei den unterschiedlichen Zeichensätzen unterschiedlicher Nationalitäten gerecht zu werden, werden von SQL-92 länderspezifische Zeichensätze unterstützt. An Operationen stehen die typischen Operationen auf Zeichenketten zur Verfügung wie Verkettung von Zeichenketten, Extraktion von Teilen einer Zeichenkette, Längenbestimmung oder Entfernen von Leerzeichen am Anfang oder am Ende. Die bitbasierten Datentypen BIT und BIT VARYING fungieren als simple Behälter für (große) Objekte unterschiedlichster Art, die keinen Zeichenketten entsprechen. Typische Vertreter dieser Art sind Bilddaten, Filmdaten, Sprache oder geographische Objekte wie Landkarten. Bitfolgen sind aus der Sicht des DBMS nicht weiter zerleg- und interpretierbar, sie bilden quasi eine amorphe Masse. Sie werden deshalb auch häufig binary large object (abgekürzt BLOB) genannt. Interpretiert werden müssen sie in den Anwendungen, was insbesondere heißt, dass das DBS keine objektspezifischen Operationen kennt. Es gibt nur Operationen zum Lesen und Schreiben der vollständigen Folge. Sollen also alle Bilder ausgegeben werden, auf denen ein Bus oder eine Straßenbahn erkannt werden kann, so müssen alle
276
7 Die relationale Datenbanksprache SQL
potenziellen Bilder vollständig in die Anwendung geladen und dort ausgewertet werden. Da BIT VARYING und der offiziell erst mit SQL:1999 eingeführte Datentyp BLOB semantisch keinen Unterschied aufweisen, wurde mit SQL:2014 der Datentyp BIT VARYING eliminiert, ebenso wie der Datentyp BIT. Für ihn war mit SQL:1999 mit dem Datentyp BOOLEAN ein hinreichender Ersatz geschaffen worden. Bit- und Zeichenfolgen, die in den meisten Zeilen einer Tabelle eine ähnliche Größe haben, können als einfacher BIT/CHAR[(laenge)]-Datentyp angelegt werden. Die durch laenge ausgedrückte Länge der entsprechenden Folge wird dabei beim Anlegen einer Zeile direkt reserviert, so dass der entsprechende Speicherplatz von vornherein auch unmittelbar physisch zur Verfügung steht. Variiert die Größe einer solchen Spalte von Zeile zu Zeile doch beträchtlich und/oder kann die aktuelle Größe der entsprechenden Spalte während des Lebenszyklus einer Zeile erheblich schwanken, ist man mit dem BIT/CHAR VARYING[(laenge)]-Datentyp besser bedient. Eine solche Situation trifft oft bei Entwicklungsobjekten zu, die am Anfang eher einen kleinen Umfang haben und im Laufe der Zeit erheblich wachsen können. Als Beispiel möge hier eine Diplomarbeit dienen, die am Anfang nur aus Titel und Autor besteht, am Schluss aber aus taktischen Gründen mindestens noch zusätzlich ein Dankeswort an die Betreuer enthalten sollte. Der angegebene Speicherplatzbedarf von laenge Bit fungiert dabei als (logische) Obergrenze, d. h. der entsprechende Speicherplatz kann maximal zur Verfügung gestellt werden. Es wird aber zunächst immer nur so viel Speicherplatz reserviert wie aktuell benötigt wird. Die Größe solcher Objekte kann in vielen kommerziellen DBMS theoretisch bis an die Grenze des vom Rechner maximal unterstützten Adressraumes gehen. Bei 64Bit Wortlänge lässt sich also eine Maximalgröße von (theoretisch) 264 − 1 erreichen. Damit lassen sich enorme Objektgrößen verwalten. Da moderne DBMS eine mengenorientierte Verarbeitung gleichartig strukturierter Daten zulassen, ist es aus Effizienzgründen vorteilhaft, möglichst viele Objekte gleicher Struktur dicht beieinander auf dem Sekundärspeicher abzulegen, also, wie es im Fachjargon heißt, zu clustern. Da die Performanz eines Systems nicht zuletzt von der Zahl der notwendigen Sekundärspeicherzugriffe abhängt, jeder Sekundärspeicherzugriff aber ein Speicherobjekt fester Größe liest oder schreibt (eine so genannte (Speicher-) Seite), steigt bei Clusterung die Wahrscheinlichkeit, dass zukünftig zu bearbeitende Zeilen, quasi als Nebeneffekt, bereits mit den aktuellen Zeilen in den Hauptspeicher geholt werden. Unterstellt wird die durchaus realistische Annahme, dass auf jeder Speicherseite eine Vielzahl von Zeilen abgelegt sind. Diese Philosophie harmoniert nun nicht sehr gut mit großen Objekten variabler Länge, wie sie durch Spalten vom Typ BIT VARYING bzw. VARCHAR dargestellt werden. Reserviert man viel Speicherplatz für solche Objekte, gehen die Vorteile der Clusterung verloren. Reserviert man nur den notwendigen Speicherplatz, sind bei Änderungsoperationen u. U. aufwändige Reorganisationsmaßnahmen des Speichers notwendig. Hinzu kommt noch eine weitere Beobachtung, die man bei der Bearbeitung von Zeilen gemacht hat, die aus einer Kombination von konventionellen, kurzen Spalten und großen Spalten variabler Länge bestehen. Oft werden die beiden Gruppen von Spalten getrennt genutzt, d. h. Anwendungen greifen häufig eher ausschließlich auf die kurzen, konventionellen und eher beschreibend bzw. charakterisierend ausgelegten Spalten oder auf die eher inhaltsorientierten langen Spalten zu, aber weniger auf beide Gruppen gleichzeitig.
7.2 Die Datendefinitionssprache (DDL)
277
Multimediaobjekt
Speicherplatzbedarf
alphanumerisches Dokument mit Formatierungsinformationen
um 2 KB pro Seite um 6 bis 8 KB pro Seite
Postscript-Dokument
um 15 KB pro Seite
Farbfotos
ab 100 KB und mehrere MB
Audio (unkomprimiert)
100 KB bis 1 MB je Minute
Video (unkomprimiert)
um 12 MB pro Minute oder 1 GB pro Film (um 90 Minuten
Tabelle 7.5: Speicherplatzbedarf von Multimediaobjekten
Als Beispiel sei der schon seit geraumer Zeit diskutierte Video-on-demand-Service genannt. Man könnte sich vorstellen, dass die Videos und deren Beschreibung in Zukunft einmal in einer Multimediadatenbank abgelegt und so für entsprechende Kunden direkt zugreifbar gemacht werden. Ein Kunde, der nun ein Video sehen möchte, aber kein spezielles im Hinterkopf hat, wird zunächst durch die DB „browsen“ wollen, um sich einen Überblick über die angebotenen Videos zu verschaffen. Dabei werden eher die kurzen Spalten wie Titel, Regisseur, Schauspieler, Kategorie, Inhaltsverzeichnis, Laufzeit, Leihgebühr usw. von Relevanz sein. Wenn er sich dann entschieden hat, wird er vermutlich nur noch an dem Video selbst interessiert sein und nicht mehr an den beschreibenden Daten. Wegen der fehlenden Harmonie zur Clustertechnik und der obigen Beobachtung werden variable Bit- und Zeichenfolgen in DBMS häufig physisch separat von den konventionellen, kurzen Spaltenwerten einer Zeile auf eigenen Seiten abgespeichert. In manchen Systemen wird jede Folge variabler Länge auf ausschließlich für variabel lange Objektteile reservierten Seiten abgelegt, so dass variabel lange Objektteile mindestens eine Seite Speicherplatz verbrauchen. Handelt es sich dann um ein vergleichsweise (noch) kleines Objekt, bedeutet dies, dass viel Speicherplatz verschwendet wird. Man spricht dann von hoher interner Fragmentierung. Der Vorteil ist allerdings, dass Objekte nicht künstlich aufgeteilt und separat abgespeichert werden müssen, wenn sie im Laufe ihres Lebens wachsen. Mit den Bit- und Zeichenfolgen sollte natürlich auch die Tür ein wenig für Multimediaanwendungen geöffnet werden. Sie haben mit ihrem unersättlichen Speicherplatzbedarf das Potenzial, alle bisher angenommenen Speicherplatzansprüche zu sprengen. Nach dem heutigen Stand der (Komprimierungs-)Technik benötigen Multimediaobjekte ungefähr den in Tabelle 7.5 angegebenen Speicherplatz. Tabelle 7.6 fasst noch einmal die wesentlichsten von SQL-92 unterstützen Datentypen zusammen. Der eine oder andere Leser mag den Datentyp BOOLEAN vermissen, der nicht nur in der Informatik eine gewisse Relevanz besitzt. Dieser Datentyp wird aus schwer nachvollziehbaren Gründen vom SQL-92-Standard noch nicht unterstützt. Seit SQL:1999 ist dieses Manko jedoch beseitigt. Tabelle 7.7 bringt für jeden Datentyp mindestens ein Beispiel, wobei Beispiele zum gleichen Datentyp durch ein Semikolon voneinander getrennt werden.
278
7 Die relationale Datenbanksprache SQL
Klasse
Datentyp-Spezikation7
Sematik/Umsetzung
Präzise Zahlen-
SMALLINT
ganze Zahl, i. d. R. 2 Byte
darstellung
INTEGER
ganze Zahl, i. d. R. 4 Byte
DECIMAL[(l8 [,h])]
Dezimalzahl Standardgröße oder mit insgesamt l Stellen, h hinter dem Komma
NUMERIC[(l[,h])]
Dezimalzahl Standardgröße oder mit mindestens l Stellen, h hinter dem Komma
Gleitkomma-
REAL
einfache Genauigkeit
zahlen
DOUBLE PRECISION
doppelte Genauigkeit
FLOAT[(l)]
Standardgröße oder mindestens l Stellen Genauigkeit
Datum
DATE
Datum in Form von Jahr-Monat-Tag: DATE ’yyyy-mm-dd’
Uhrzeit
TIME[(l)]
Zeit in Form von Stunde-Minute-Sekunde: hh.mm.ss (Default: ohne Sekundenbruchteile) l gibt die Stellenzahl für optionale Sekundenbruchteile (b) an: TIME ’hh:mm:ss.b. . .b’
TIMESTAMP[(l)]
Kombination aus Datum und Zeit, Default 6 Stellen für Sekundenbruchteile; diese können auf l Stellen erhöht werden TIMESTAMP ’yyyy-mm-dd hh:mm:ss.b. . .b’
TIME[(l)] WITH TIME ZONE
wie TIME, mit Abweichung der lokalen Zeit zur UCT-Zeit: TIME ’hh:mm:ss±hh:mm’
TIMESTAMP[(l)] WITH TIME ZONE
wie TIMESTAMP, mit Abweichung der lokalen Zeit zur UCT-Zeit TIMESTAMP ’yyyy-mm-dd hh:mm:ss.bbbbbb±hh:mm’
Zeitintervalle Jahre, Monate
INTERVAL{YEAR[TO MONTH]| MONTH}9
relativer Zeitraum in Jahren und Monaten INTERVAL ’yy-mm’ YEAR TO MONTH
Zeitintervalle Tage, . . ., Sekunden
INTERVAL {DAY|HOUR|MINUTE|SECOND} [TO {HOUR|MINUTE|SECOND}]10
beliebige relative Zeiträume im Bereich von Tagen (über Stunden und Minuten) bis Sekunden: INTERVAL ’dd hh’ DAY TO HOUR
Zeichenketten
CHAR[(l)]
Zeichenkette mit genau l Zeichen: ’cccc’, für l = 4
VARCHAR[(l)]
variable Zeichenkette aus höchstens l Zeichen
NATIONAL CHAR[(l)]
länderspezifische Zeichenkette: N’cccc’
NATIONAL VARCHAR[(l)]
variable länderspezifische Zeichenkette
BIT[(l)]
Bitfolge aus genau l Bits: B’bbbbbbbb’, für l= 8
BIT VARYING[(l)]
variable Bitfolge aus höchsten l Bits: X’bbb’
Bitfolgen
Tabelle 7.6: Spezifikation der Datentypen in SQL-92 7 Es sei darauf hingewiesen, dass der Standard viele Schreibweisen unterstützt, die hier nicht alle aufgeführt werden können. So kann beispielsweise VARCHAR auch als CHAR VARYING oder CHARACTER VARYING geschrieben werden. 8 l steht für Länge 9 Hinter dem TO darf nur eine Zeiteinheit stehen, deren Granularität feiner ist als die Zeiteinheit vor dem TO (YEAR TO MONTH ist korrekt, während YEAR TO YEAR nicht erlaubt ist). 10 Es gilt Fußnote 7.2.2.1 sinngemäß.
7.2 Die Datendefinitionssprache (DDL)
279
Datentyp-Spezikation
Beispiele
SMALLINT
+6; −8; 4312
INTEGER
+6; −8; 4312; 67320
DECIMAL(6,2)
+12.00; −3000.95; 35.75; 3.14
NUMERIC(6,2)
+12.00; −3000.95; 35.75; 3.14
REAL
3.141592E00
DOUBLE PRECISION
3.14159292655432E00
FLOAT(10)
3.14159292E00
DATE
DATE ’2014-01-01’
TIME(2)
TIME ’11:39:40.55’
TIMESTAMP
TIMESTAMP ’2014-01-01 11:39:40.554433’
TIME(2) WITH TIME ZONE
TIME ’11:39:40.55+08:00’ Zeit in Los Angeles als UCT
TIMESTAMP WITH TIME ZONE
TIMESTAMP ’2014-01-01 11:39:40.554433+08:00’
INTERVAL YEAR TO MONTH
INTERVAL ’12-6’ YEAR TO MONTH entspricht etwa einem Intervall von 12 Jahren und 6 Monaten
INTERVAL (DAY|HOUR|MINUTE|SECOND) [TO (HOUR|MINUTE|SECOND)]
INTERVAL ’12 11:39:40’ DAY TO SECOND entspricht einem Intervall von 12 Tagen, 11 Std., 39 Min., 40 Sek. INTERVAL ’12’ Day Intervall von 12 Tagen
CHAR(4)
’vier’
VARCHAR(40000
’Dies ist eine endlose Geschichte . . .’
NATIONAL CHAR(35)
N’deutschä Sprache, schwärä Sprache ’
NATIONAL VARCHAR(400)
N’deutschä Sprache, schwärä Sprache’
BIT(8)
B’01010101’; B’1A’11
BIT VARYING(1024)
X’01010101’; X’1A’11 ; X’1A9E’11
Tabelle 7.7: Beispiele für SQL-92-Datentypen
Feststellung 7.2: Typkompatibilität in SQL In SQL sind zwei Spalten typkompatibel, falls • sie sich auf denselben Basisdatentyp beziehen oder • sich beide auf Wertebereiche des Basisdatentyps CHAR abstützen oder • beide auf (beliebigen) numerischen Basisdatentypen beruhen. 7.2.2.2
Prädikate und Datentypen
Zur Arbeit auf Datentypen werden eine Reihe von Prädikaten zur Verfügung gestellt, über die geprüft werden kann, ob ein Wert zu einem (eingeschränkten) Wertebereich gehört. 11 Die
Bitfolge ist in Hexadezimalnotation dargestellt
280
7 Die relationale Datenbanksprache SQL
Prädikat
Datentyp
Bedeutung
BETWEEN
alle Datentypen
Enthaltensein des Wertes im spezifizierten Wertebereichausschnitt
IN
alle Datentypen
Enthaltensein des Wertes in einer Menge
LIKE
alphanumerische Zeichenketten
(partielle) Übereinstimmung zweier Werte
NULL
alle Datentypen
Belegung eines Wertes mit der Nullmarke
OVERLAPS
Zeitintervalle
Überlappung zweier Zeitintervalle
Tabelle 7.8: Prädikate und ihre Aufgabe
Ein Prädikat ist ein Ausdruck, der eine Aussage über Werte macht. Die Aussage kann dabei korrekt sein, was bedeutet, dass der Ausdruck zu TRUE evaluiert. Ist die Aussage falsch, wird als Ergebnis FALSE geliefert. Die dritte Variante, dass der Wahrheitsgehalt der Aussage nicht ermittelt werden kann, kann dann auftreten, falls einer der Werte der Nullmarke entspricht. Diese Variante wird im Zusammenhang mit Nullmarken diskutiert und soll hier ebenso wie das NULL-Prädikat nicht weiter betrachtet werden. 7.2.2.2.1
Das BETWEEN-Prädikat
Um Wertebereichsüberprüfungen machen zu können, stehen das BETWEEN- und das INPrädikat zur Verfügung. Über BETWEEN wird durch die Angabe einer Unter- und Obergrenze aus einem Wertebereich ein Teilbereich ausgewählt, während über die einfache IN-Klausel12 die Menge der zulässigen Werte explizit angegeben werden kann. Syntax 7.2: BETWEEN-Prädikat BETWEEN-Prädikat ::=SpaltenWert [NOT] BETWEEN Untergrenze AND Obergrenze Beim BETWEEN-Prädikat wird FALSE zurückgeliefert, falls die Untergrenze größer ist als die Obergrenze, also das Intervall quasi in der falschen Reihenfolge spezifiziert wurde. Beispiel 7.5: BETWEEN-Prädikat „Gib alle Aufträge aus, die zwischen dem 01.01.2014 und dem 31.12.2014 akquiriert wurden.“ SELECT FROM WHERE
∗ Auftrag datum BETWEEN DATE ’2014-01-01’ AND DATE ’2014-12-31’;
12 An dieser Stelle soll nur die einfache Version des IN-Prädikates diskutiert werden. Die mit Unteranfragen arbeitende komplexere Version wird in Kapitel 7.3.5.2.1 behandelt.
7.2 Die Datendefinitionssprache (DDL)
281
Würden in der WHERE-Klausel Unter- und Obergrenze vertauscht, wäre das Prädikat unabhängig vom Wert von datum nie erfüllt. WHERE
datum BETWEEN DATE ’2014-12-31’ AND DATE ’2014-01-01’
evaluiert immer zu FALSE. Das BETWEEN-Prädikat kann auch konventionell über zwei AND-verknüpfte oder, im negierten Fall, über zwei OR-verknüpfte Prädikate formuliert werden: W BETWEEN U AND O W NOT BETWEEN U AND O
ist äquivalent zu ist äquivalent zu
W ≥ U AND W ≤ O W < U OR W > O
und
Beispiel 7.6: Simulation des BETWEEN-Prädikates aus Beispiel 7.5 SELECT FROM WHERE
7.2.2.2.2
∗ Auftrag datum ≥ DATE ’2014-01-01’ AND datum ≤ DATE ’2014-12-31’;
Das IN-Prädikat
Mit dem IN-Prädikat kann man prüfen, ob ein Wert in einer Wertemenge enthalten ist. Syntax 7.3: IN-Prädikat IN-Prädikat ::= SpaltenWert [NOT] IN {(Wertemenge) | (UnterAnfrage)} Wertemenge ist eine endliche Menge von explizit aufgelisteten Werten. Sie kann dazu dienen, den Wertebereich eines Basisdatentyps durch massive Einschränkungen exakt auf die Bedürfnisse einer Anwendung abzustimmen. Wertemenge darf aus einer beliebigen Anzahl von Konstanten bestehen, sofern sie alle vom selben Datentyp sind. Auch muss es sich um eine echte Menge handeln; Duplikate sind also nicht erlaubt. In den alten SQL-Dialekten durften nur Konstanten angegeben werden. SQL-92 erlaubt aus Gründen der Orthogonalität die Einbeziehung komplexer Ausdrücke, was von einfachen arithmetischen Berechnungen bis hin zu Unteranfragen reichen kann. Allerdings muss gewährleistet sein, dass die Auswertung des Ausdruckes eine Wertemenge des richtigen Datentyps ergibt. Ansonsten kann es zu Laufzeitfehlern kommen. Diese „dynamische“ Variante wird später noch genauer erläutert. Beispiel 7.7: IN-Prädikat 1. „Gib alle Kunden aus, deren Rabatt 5.5, 7.5 oder 10 Prozent beträgt.“ SELECT FROM WHERE
∗ Kunden rabatt IN (5.50, 7.50, 10.00);
282
7 Die relationale Datenbanksprache SQL
2. „Gib alle Kunden aus, deren Rabatt nicht 5.5, 7.5 oder 10 Prozent beträgt.“ SELECT FROM WHERE WHERE
∗ Kunden rabatt NOT IN (5.50, 7.50, 10.00); bzw. NOT rabatt IN (5.50, 7.50, 10.00);
3. „Gib alle Aufträge aus, die auf den 19.12.1919 oder genau einen Monat später datiert sind.“ SELECT FROM WHERE
∗ Auftrag datum IN (DATE ’1919-12-19’, DATE ’1919-12-19’+INTERVAL ’1’ MONTH);
Ein IN-Prädikat könnte auch über eine Folge von mit OR aneinander gereihten Prädikaten simuliert werden (siehe Beispiel 7.8). Das negierte IN-Prädikat entspricht einer Folge von mit AND verbundenen =-Prädikaten. Beispiel 7.8: Simulation des IN-Prädikates Die Anfragen entsprechen denen von Beispiel 7.7. 1. SELECT FROM WHERE
∗ Kunden rabatt=5.50 OR rabatt=7.50 OR rabatt=10.00;
2. SELECT FROM WHERE
∗ Kunden rabatt = 5.50 AND rabatt = 7.50 AND rabatt = 10.00;
3. SELECT FROM WHERE
∗ Auftrag datum=DATE ’1919-12-19’ OR datum=DATE ’1919-12-19’+INTERVAL ’1’ MONTH;
7.2.2.2.3
Das LIKE-Prädikat
Das LIKE-Prädikat arbeitet auf alphanumerischen Zeichenketten und entspricht je nach Parametrisierung einer mehr oder weniger exakten Textsuche. Syntax 7.4: LIKE-Prädikat LIKE-Prädikat ::= SpaltenWert [NOT] LIKE Textpattern Zum Auffinden von Zeichenketten, deren Inhalte nicht genau bekannt sind oder die, beispielsweise aus Bequemlichkeitsgründen, nicht vollständig ausgeschrieben werden sollen, kann die
7.2 Die Datendefinitionssprache (DDL)
283
LIKE-Klausel benutzt werden. Dabei wird der Spaltenwert, der über die LIKE-Klausel mit einem Muster verglichen werden soll, als Ganzes von links nach rechts zeichenweise verglichen (pattern matching). Im Muster können dabei so genannte Maskierungszeichen (wildcards) gesetzt werden: • % Hier können beliebig viele (auch kein) Zeichen stehen, die beim Vergleich ignoriert werden. • _ An dieser Stelle wird genau ein Zeichen ignoriert. Damit kann die genaue Länge des Ergebnisses festgelegt werden.
Beispiel 7.9: LIKE-Prädikat 1. „Gib alle Kunden aus, die Meier, Meyer, Maier oder so ähnlich heißen.“ SELECT FROM WHERE
∗ Kunden kundeName LIKE ’M_ _er’;
2. „Gib alle Kunden aus, die mit ’M’ anfangen.“ SELECT FROM WHERE
7.2.2.2.4
∗ Kunden kundeName LIKE ’M%’;
Das OVERLAPS-Prädikat
Das OVERLAPS-Prädikat arbeitet auf Zeitintervallen. Es überprüft, ob zwei gegebene Zeitintervalle sich überschneiden. Ein Zeitintervall wird dabei entweder durch einen Anfangs- und einen Endpunkt oder durch einen Anfangspunkt und eine Dauer beschrieben. Syntax 7.5: OVERLAPS-Prädikat OVERLAPS-Prädikat ::=AnfangsPunkt {EndPunkt | + Dauer} OVERLAPS AnfangsPunkt {EndPunkt | + Dauer} Im Folgenden sollen Ix .B, x ∈ {1, 2}, den Anfangs- und Ix .E den Endpunkt von Intervall x bezeichnen. Ix .E ist dabei entweder durch Endpunkt oder Anfangspunkt+Dauer definiert. Intuitiv würde man vermuten, dass ein OVERLAPS-Prädikat der Form (I1 .B, I1 .E) OVERLAPS (I2 .B, I2 .E) zu TRUE evaluieren würde, falls die folgende Bedingung erfüllt wäre: I2 .B < I1 .E AND I1 .B < I2 .E
284
7 Die relationale Datenbanksprache SQL
Diese Vermutung trifft aber nicht zu. Es wurde eine deutlich aufwändigere Definition gewählt, weil diese auch negative Intervalle zulässt. Negativ bedeutet dabei, dass der Endpunkt des Intervalls vor dessen Anfangspunkt liegt, wodurch die Semantik der beiden Begrenzer vertauscht wird (siehe erstes Intervall von Beispiel 7.10, 2.). Feststellung 7.3: Semantik des OVERLAPS-Prädikates Die Semantik des OVERLAPS-Prädikates entspricht nicht dem intuitiven Verständnis, sondern wird durch die folgenden drei Bedingungen festgelegt: 1. (I1 .B > I2 .B AND (I1 .B < I2 .E OR I1 .E < I2 .E)) OR 2. (I2 .B > I1 .B AND (I2 .B < I1 .E OR I2 .E < I1 .E)) OR 3. (I1 .B=I2 .B AND I1 .E IS NOT NULL AND I2 .E IS NOT NULL) Beispiel 7.10: OVERLAPS-Prädikat 1. (TIME ’09:00:00’, INTERVAL ’50’ MINUTE) OVERLAPS (TIME ’02:15:00’, INTERVAL ’6’ HOUR) evaluiert zu FALSE 2.
(TIME ’09:00:00’, INTERVAL ’−50’ MINUTE) OVERLAPS (TIME ’02:15:00’, INTERVAL ’6’ HOUR) evaluiert wegen Feststellung 3 Punkt 1. zu TRUE Das erste Intervall ist ein negatives Intervall und würde positiv wie folgt zu formulieren sein: (TIME ’08:10:00’, TIME ’09:00:00’) Damit kann 2. auch so formuliert werden: (TIME ’08:10:00’, TIME ’09:00:00’) OVERLAPS (TIME ’02:15:00’, TIME ’08:15:00’)
Achtung 7.3: Überschneidung in einem Punkt bei Zeitintervallen 1. (TIME ’09:00:00’, INTERVAL ’30’ MINUTE) OVERLAPS (TIME ’02:00:00’, INTERVAL ’7’ HOUR) evaluiert zu FALSE, weil ein Berühren zweier Intervalle in lediglich einem Punkt nicht als Überlappung angesehen wird. Hieraus folgt, dass ein Vergleich zweier Zeitintervalle automatisch zu FALSE evaluieren sollte, falls für mindestens ein Zeitintervall gilt, dass der Anfangsund Endpunkt identisch sind, das Intervall also eigentlich nur einen Zeitpunkt darstellt. Führt man das logisch weiter, müsste auch FALSE geliefert werden, falls beide Zeitintervalle nur einen Zeitpunkt darstellen und diese Zeitpunkte, und damit auch die beiden Zeitintervalle, identisch sind.
7.2 Die Datendefinitionssprache (DDL)
285
2. An sich wollte die SQL-92-Standardisierungskommission die Definition so auslegen, dass zwei Intervalle, die sich nur in einem Punkt berühren, als nicht überlappend eingestuft werden. Wenn man sich jedoch Feststellung 7.3 genau ansieht, wird man bemerken, dass hier der Standardisierungskommission ein Denkfehler unterlaufen ist. Wegen 3. von Feststellung 7.3 können sich ein Intervall und ein als Intervall „getarnter“ Zeitpunkt überlappen, falls sie einen identischen Anfangspunkt besitzen, nicht aber, falls ihre Endpunkte übereinstimmen. Damit sind zwei als Intervalle ausgelegte identische Zeitpunkte trotz der obigen Aussage aufgrund dieses Designfehlers doch überlappend. (TIME ’09:00:00’, INTERVAL ’0’ MINUTE) OVERLAPS (TIME ’09:00:00’, INTERVAL ’0’ HOUR) evaluiert doch zu TRUE, 3. (TIME ’09:00:00’, INTERVAL ’30’ MINUTE) OVERLAPS (TIME ’09:00:00’, INTERVAL ’-7’ HOUR) evaluiert auch zu TRUE, obwohl das zweite Intervall identisch mit dem zweiten Intervall von 1. oben ist. 7.2.2.3
Nullmarken
Eine DB soll einen aus der Sicht der zu Grunde liegenden Anwendungsklassen relevanten Realweltausschnitt widerspiegeln. Wie immer, wenn ein Abbild von etwas Realem geschaffen werden soll, sind Grenzen zu beachten, die im Folgenden diskutiert werden sollen. • Realwelt ↔ Realweltabbild Wegen der Komplexität und Vielfältigkeit der Realwelt kann die DB nur ein abstrahiertes, mehr oder weniger geglücktes, mehr oder weniger aktuelles Abbild des Realweltausschnittes darstellen. Die Einschränkungen abstrakt und mehr oder weniger implizieren, dass in einer DB immer nur (eingeschränktes) Wissen über die Realwelt, nicht aber eine wirklich originalgetreue Beschreibung abgelegt sein kann. Dies kann insbesondere bedeuten, dass Fakten der Realwelt nicht bekannt sind, weshalb die korrekte Belegung einer Spalte mit einem Wert nicht immer möglich sein wird. • Einfaches Datenbankmodell Aufgrund ihres vergleichsweise einfachen Datenbankmodells erwarten relationale DBMS, dass semantisch ähnliche Realweltobjekte in der DB durch die gleiche Datenstruktur repräsentiert werden. Eine solch abstrahierende Einordnung in Schubladen bedeutet aber, dass wesentliche Unterschiede im Detail nicht modelliert werden können. So muss eine Spalte selbst dann berücksichtigt werden, wenn für sie keine Werte bekannt sind oder aber die durch die Spalte ausgedrückte Eigenschaft des Realweltobjektes im konkreten Fall nicht vorkommen kann. Würde man beispielsweise Flugzeugtypen in einer Tabelle verwalten, so wäre bei dem konkreten Flugzeugtyp Segelflugzeug die Spalte Motortyp an sich überflüssig, kann aber nicht einfach weggelassen werden. In vielen konventionellen Anwendungen behilft man sich, indem ein ausgezeichneter Wert des Wertebereiches, der als solcher in der Realwelt nicht auftreten kann, zur Repräsentation solcher Situationen wie der Obigen „missbraucht“ wird. Das relationale Datenbankmodell stellt für solche Zwecke einen speziellen Wert, die so genannte Nullmarke NULL zur Verfügung.
286
7 Die relationale Datenbanksprache SQL
Damit ist eine einheitliche und konsistente Behandlung von unbekannten Werten über alle Anwendungen und Datentypen hinweg gewährleistet. Die Nullmarke sollte nicht verwechselt werden mit der Zahl 0 des Wertebereiches INTEGER oder mit einer leeren Zeichenfolge des Wertebereiches VARCHAR. Sie ist vielmehr ein ausgezeichneter Wert, der zu jedem Wertebereich explizit hinzugefügt wird. Ihre genaue Bedeutung kann zwangsläufig nicht exakt festliegen, da sie immer dann zum Einsatz kommt, wenn die anderen Werte eines Wertebereiches nicht verwendbar sind. Die häufigsten Interpretationen sind die folgenden: 1. Wert ist noch nicht festgelegt/bekannt Grundsätzlich besitzt dieses Objekt die mit der Spalte verbundene Eigenschaft. Allerdings trifft die Eigenschaft zum gegenwärtigen Zeitpunkt noch nicht zu. Eine solche Situation ist beispielsweise gegeben, wenn ein Student zu seinen Prüfungen antritt. Zwar wird dann bereits in der Tabelle Prüfungen ein entsprechender Datensatz eingefügt, die Spalte Note kann aber offensichtlich noch nicht bekannt sein. 2. Eigenschaft kann nicht vorkommen bzw. auftreten Das Objekt besitzt die mit der Spalte verbundene Eigenschaft (ausnahmsweise) nicht und wird sie auch in Zukunft nicht besitzen. Für diese Variante ist das bereits erwähnte Segelflugzeug ein Beispiel. 3. Wert ist nicht bekannt Es ist möglich, dass das Objekt die mit der Spalte verbundene Eigenschaft besitzt. Allerdings kann es auch sein, dass die Eigenschaft nicht zutrifft. Subsumieren kann man dies unter der abstrakten Aussage, dass der Wert der Spalte zum gegenwärtigen Zeitpunkt nicht bekannt ist. Ein Beispiel für eine solche Situation ist, wenn zwar die Adresse eines Kunden, nicht aber dessen Telefonnummer bekannt ist. Es gibt jetzt zwei Möglichkeiten: Der Kunde besitzt ein Telefon, nur ist die Nummer nicht bekannt. Möglich wäre aber auch, dass der Kunde kein Telefon besitzt. Natürlich könnte man neben den obigen Interpretationen noch beliebig viele weitere finden, die auch zutreffen könnten. Daraus lässt sich unmittelbar schließen, dass die Nullmarke keinen Wert im klassischen Sinn darstellt. Vielmehr repräsentiert sie einen allgemeinen Platzhalter für eine Vielzahl von möglichen Interpretationen, die sich im Wesentlichen alle der abstrakten Wurzel nicht zutreffend/nicht bekannt unterordnen lassen. Diese so profan klingende Aussage hat nun aber erhebliche Konsequenzen auf die Komplexität. Die Tatsache, dass Nullmarken sich unterschiedlich interpretieren lassen, bedeutet insbesondere, dass sie etwas Individuelles darstellen und damit nicht direkt miteinander vergleichbar sind. Wenn man also fragt, ob der Wert zweier Spalten gleich ist (Attr1 = Attr2 ), so muss die Antwort in dem Fall, dass beide mit der Nullmarke belegt sind, nicht ja, sondern nicht bekannt bzw. nicht feststellbar lauten. Würden wir die Spalte Motortyp eines konkreten Segelflugzeuges mit der gleichen Spalte eines konkreten Motorflugzeuges vergleichen, von dem uns der Motortyp nicht bekannt ist, so darf offensichtlich aus der Tatsache, dass beide Spalten mit der Nullmarke belegt sind, nicht geschlossen werden, dass bei ihnen der gleiche, wenn auch nicht bekannte Motortyp eingebaut ist bzw. beide keinen Motor besitzen. Die korrekte Antwort lautet vielmehr nicht bekannt, wobei der Mensch mit seinem Allgemeinwissen in diesem konkreten Fall natürlich
7.2 Die Datendefinitionssprache (DDL)
287
noch eine genauere Antwort geben könnte. Wegen dieser mit einer Nullmarke verbundenen fehlenden Eindeutigkeit nehmen wir auch Abstand davon, den gängigen Begriff Nullwert (statt Nullmarke) zu verwenden. Eine Nullmarke stellt gerade keinen klassischen Wert dar, wie auch in den folgenden Diskussionen immer wieder deutlich werden wird. Definition 7.1: Nullmarke Die Nullmarke NULL ist ein spezieller Platzhalter, der zu jedem Wertebereich automatisch hinzugefügt wird und immer dann genutzt werden kann, wenn die Spalte entweder nicht zutreffend oder ihr Wert nicht bekannt ist. Nullmarken stellen individuelle Werte dar, was insbesondere heißt, dass sie nicht ohne weiteres miteinander vergleichbar sind. Die scheinbare Selbstverständlichkeit, nicht bekannte oder nicht anwendbare Eigenschaften eines Objektes in einem Datenbankmodell auch mit dieser Semantik spezifizieren zu können, hat zu einiger, immer noch anhaltender Diskussion in der Datenbankwelt geführt. Die Befürworter von Nullmarken weisen auf die sicherlich leicht nachvollziehbare Notwendigkeit ihrer Existenz hin, während die Gegner die damit verbundene Komplexität anprangern. 7.2.2.4
Benutzerdefinierte Wertebereiche
Bereits in Kapitel 6.1 waren die Vor- und Nachteile eines grob- bzw. feingranularen Typsystems ausführlich diskutiert worden. Es war festgestellt worden, dass ein feingranulares Typsystem viele Vorteile in Bezug auf die Gewährleistung der Konsistenz der Daten besitzt, aber Nachteile in Bezug auf die Flexibilität und Einsetzbarkeit. Nun spielt die Frage des Wertebereiches und des Datentyps gerade auch in DBS eine wesentliche Rolle. In einem DBS werden nun einmal Daten abgelegt, und von diesen verlangt man, dass sie korrekt sind. Der SQL-92-Standard sieht vor, dass benutzerdefinierte bzw. anwendungsspezifische Wertebereiche über die CREATE DOMAIN-Klausel angelegt werden können. Bei der Definition von Tabellen können sie dann wie Basisdatentypen verwendet werden.13 Syntax 7.6: Anlegen eines Wertebereiches (Basissyntax) WertebereichDef ::= CREATE DOMAIN WertebereichName [AS] Datentyp WertebereichName ist der Name des neuen Wertebereiches, während Datentyp der Name des Basisdatentyps ist, auf den sich der neue Wertebereich abstützt. Beispiel 7.11: Wertebereichdefinition CREATE DOMAIN
ShortString AS CHAR(5);
Im obigen Beispiel wird ein neuer Wertebereich mit dem Namen ShortString angelegt, der auf dem Basisdatentyp CHAR aufbaut. Der neue Wertebereich ist eine Spezialisierung von 13 Die
Begriffe Wertebereich und Datentyp werden später noch voneinander abgegrenzt.
288
7 Die relationale Datenbanksprache SQL
CHAR, da die Länge einer Zeichenkette auf exakt fünf Zeichen festgeschrieben wird. ShortString könnte beispielsweise für die Definition einer Postleitzahlenspalte genutzt werden, die ja bekanntermaßen in Deutschland fünfstellig ist. Beispiel 7.12: Arbeiten mit benutzerdefinierten Wertebereichen CREATE TABLE14 Mitarbeiter ( ... plz: ShortString, ort: VARCHAR (20), strasse: VARCHAR (20), hausNr: SMALLINT, ...); Wenn man jetzt einmal außer Acht lässt, dass es nach wie vor vierstellige Postleitzahlen gibt, die allerdings um eine vorangestellte 0 ergänzt sind, könnte man den Wertebereich für Postleitzahlen noch genauer definieren, indem man ihn vom Typ INTEGER, eingeschränkt auf den Wertebereich 10000 bis 99999, definiert15 . Die CREATE DOMAIN-Klausel unterstützt die Definition solcher Wertebereichseinschränkungen, so dass sehr fein abgestimmte Wertebereiche eingerichtet werden können. Daneben besteht auch noch die Möglichkeit, einen Default festzulegen. Syntax 7.7: Anlegen eines Wertebereiches (erweiterte Syntax) WertebereichDef ::=CREATE DOMAIN WertebereichName [AS] Datentyp [DEFAULT-Klausel] [WertebereichEinschränkung] In der Default-Klausel kann eine Konstante aus dem Wertebereich der Spalte angegeben werden, die beim Anlegen einer neuen Zeile immer dann als Spaltenwert eingesetzt wird, wenn für die Spalte kein expliziter Wert angegeben wurde. Dabei kann neben den eigentlichen Werten des Wertebereiches auch die Nullmarke als Default festgelegt werden. Syntax 7.8: Default-Klausel DEFAULT-Klausel ::= DEFAULT {NULL | Konstante} Beispiel 7.13: Wertebereichdeklaration mit Default CREATE DOMAIN ShortString AS CHAR(5) DEFAULT ’99999999’; 14 Die CREATE TABLE-Anweisung dient der Definition einer neuen Tabelle. Sie wird in Kapitel 7.2.3 noch genauer eingeführt. 15 Hier soll nur das Konzept erläutert werden, nicht aber empfohlen werden, eine Postleitzahl als einen INTEGERWert darzustellen. Die führende 0 ist signifikant und sollte daher nicht weggelassen werden.
7.2 Die Datendefinitionssprache (DDL)
289
Die Möglichkeit, bei der Wertebereichspezifikation einen Default angeben zu können, spricht eher für Pragmatismus und weniger für ein sauberes Modellierungskonzept. Eine Wertebereichdefinition ist eine Definition auf einer abstrakten Ebene, die noch nicht durch direkten Anwendungsbezug gekennzeichnet ist. Ein Default hat nichts mit einem Wertebereich, sondern vielmehr etwas mit der anwendungsspezifischen Semantik einer bestimmten Spalte in einer bestimmten Tabelle zu tun. Dementsprechend sollte die Festlegung des Defaults bei der Definition von Spalten bei der Tabellendefinition vorgenommen werden. Trotzdem kann es in der Praxis hin und wieder natürlich Sinn machen, bei sehr spezifischen Datentypen bereits bei deren Definition einen Default anzugeben. In der Einschränkungsklausel können Bedingungen an den Wertebereich gestellt werden, was de facto einer Wertebereichseinschränkung gleichkommt. Das Spektrum einer Einschränkung reicht von der einfachen Angabe des kompletten und damit endlichen Wertebereiches bis hin zur Ermittlung des Wertebereiches über eine (komplexe) SQL-Anfrage. Syntax 7.9: Wertebereichseinschränkung WertebereichEinschränkung ::= [CONSTRAINT NameEinschränkung] Einschränkung Einschränkung ::=
CHECK (KomplexeBedingung1 [{AND | OR} KomplexeBedingungn]∗ ) [ZeitpunktPrüfung]
ZeitpunktPrüfung ::= [DEFERRABLE] INITIALLY {DEFERRED | IMMEDIATE} | NOT DEFERRABLE Jeder Einschränkung kann über die CONSTRAINT-Klausel ein Name zugewiesen werden. Das ist auch empfehlenswert, da dann im Fall einer Verletzung der Bedingung eine spezifische Fehlermeldung ausgegeben werden kann. Wird kein Name angegeben, vergibt das System automatisch einen. Dieser wird aber i. d. R. wenig aussagekräftig sein. Über die ZeitpunktPrüfung-Klausel kann festgelegt werden, ob die Einhaltung der Wertebereichseinschränkung immer sofort überprüft werden muss oder auch auf einen späteren Zeitpunkt verlegt werden darf. Wie später noch genauer diskutiert werden wird, können Arbeiten auf der DB grundsätzlich nur innerhalb von Transaktionen ausgeführt werden. Da mit Abschluss einer Transaktion deren Änderungen dauerhaft werden, ist klar, dass jede Wertebereichüberprüfung vor dem Ende der Transaktion ausgeführt sein muss. Mit der ZeitpunktPrüfung-Klausel kann dementsprechend nur festgelegt werden, wann innerhalb einer Transaktion der Test stattfinden kann. Bei der NOT DEFERRABLE-Variante muss ein Test immer direkt ausgeführt werden, wenn ein Datum des entsprechenden Typs verändert oder in die DB eingefügt wird. Die DEFERRABLEVariante ermöglicht grundsätzlich auch das Verschieben der Überprüfung, beispielsweise auf das Transaktionsende oder einen davor liegenden, durch den Benutzer bestimmten Zeitpunkt. Eine Verschiebung kann immer dann Sinn machen, wenn dasselbe Datum mehrmals innerhalb einer Transaktion geändert wird oder die durchgeführte Änderung nur ein Zwischen-, aber noch kein Endergebnis darstellt. Aufgrund der Transaktionsabhängigkeit wird spätestens mit der angestrebten Beendigung einer Transaktion jede aufgeschobene Überprüfung auf IMMEDIATE (sofort) gesetzt und damit noch vor dem eigentlichen Ende der Transaktion abgearbeitet.
290
7 Die relationale Datenbanksprache SQL
Während mit der [NOT] DEFERRABLE-Klausel die grundsätzliche (Nicht-)Verschiebung von Überprüfungen spezifiziert werden kann, wird über die INITIALLY-Klausel festgelegt, welches der Default bei Beginn einer Transaktion ist. Ist eine Überprüfung grundsätzlich verschiebbar, kann trotzdem festgelegt werden, dass ohne explizite Verschiebungsfestlegung (über die SET CONSTRAINTS-Klausel, siehe unten) eine Überprüfung sofort stattzufinden hat (INITIALLY IMMEDIATE16). Wurde eine Überprüfung als verschiebbar deklariert, so kann deren Default zu Beginn einer Transaktion auf „Überprüfung verschieben“ (INITIALLY DEFERRABLE) gesetzt werden. Der Zeitpunkt der Überprüfung kann dann entweder explizit über die SET CONSTRAINTS-Klausel festgelegt werden oder er wird implizit mit dem Transaktionsende gleichgesetzt. Es sei noch darauf hingewiesen, dass Einschränkungen nicht nur im Zusammenhang mit einer Wertebereichdeklaration definiert werden können, sondern allgemein im Zusammenhang mit einer Schemadefinition. Ähnlich wie bei der Default-Klausel ist es aus der Sicht einer sauberen Modellierung zu vermeiden, die Zeitpunktklausel im Zusammenhang mit einer Typ- bzw. Wertebereichdefinition einzusetzen. Eine Wertebereichdefinition legt die Menge der grundsätzlich zulässigen Werte fest und hat nichts mit Laufzeitaspekten zu tun und erst recht nichts mit der Frage, zu welchem Zeitpunkt denn eine Variable von diesem Typ korrekt sein muss. Beispielsweise sieht die DEFFERABLE INITIALLY IMMEDIATE-Deklaration in Beispiel 7.14 ohne entsprechenden Anwendungsbezug sehr willkürlich aus. Beispiel 7.14: Wertebereichdeklaration mit Integritätsbedingung CREATE DOMAIN FünfstelligeZahl AS INTEGER CONSTRAINT Fünfstellig CHECK (VALUE BETWEEN 10000 AND 99999) DEFFERABLE INITIALLY IMMEDIATE;
Ist die Überprüfung einer Wertebereichseinschränkung grundsätzlich verschiebbar, kann über die SET CONSTRAINTS-Klausel innerhalb einer Transaktion die Ausführung einer (verschobenen) Überprüfung sofort angeordnet (IMMEDIATE) oder auf einen späteren Zeitpunkt verschoben werden (DEFERRED). Syntax 7.10: Integritätsbedingung sofort/später überprüfen TestZeitpunkt ::= SET CONSTRAINTS {ALL | NameEinschränkung1 [, NameEinschränkungn]∗ } {DEFERRED | IMMEDIATE} Beispiel 7.15: SET CONSTRAINTS-Klausel SET CONSTRAINTS Fünfstellig DEFERRED; würde es erlauben, innerhalb einer Transaktion zunächst einmal eine Reihe neuer Adressen einzugeben, ohne dass die Korrektheit der Postleitzahl überprüft wird. Die Korrektheits16 Obwohl in der Syntaxnotation nicht explizit aufgeführt, ist diese Variante auch im Fall von NOT DEFFERABLE spezifizierbar; sie entspricht nur sowieso der mit NOT DEFFERABLE verbundenen Semantik und ist daher überflüssig.
7.2 Die Datendefinitionssprache (DDL)
291
überprüfung kann dann durch Eingabe des Befehls SET CONSTRAINTS Fünfstellig IMMEDIATE; zu einem beliebigen Zeitpunkt innerhalb einer Transaktion explizit ausgelöst werden. Würde der obige Befehl nicht aufgerufen, würde Fünfstellig implizit am Ende der Transaktion überprüft. Der exakte Aufbau von KomplexeBedingungn soll an dieser Stelle nicht diskutiert werden, da darauf noch in den folgenden Unterkapiteln eingegangen wird. Es sei nur angemerkt, dass diese Bedingungen keinerlei Einschränkungen unterliegen, weshalb hier grundsätzlich die vollständige Mächtigkeit von SQL-Anfragebedingungen genutzt werden kann. Damit ist es insbesondere auch möglich, über die Suchbedingung Daten aus der DB zu selektieren, durch die dann der Wertebereich beschrieben wird (siehe Beispiel 7.16). Beispiel 7.16: Dynamische Wertebereichfestlegung CREATE DOMAIN BustypDomain AS CHAR(1) DEFAULT ’S’ CONSTRAINT Typeinschränkung CHECK (VALUE IN (’D’,’G’,’M’,’R’,’S’)); Dabei steht M G
für Minibus S für Gelenkwagenbus R
für Stadtbus für Reisebus
D
für Doppelstockbus
Dieses Beispiel könnte für den Fall, dass die Beschreibung von Bustypen in einer eigenen Tabelle Busbeschreibung abgelegt ist, in der Bustyp eine Spalte bildet, auch wie folgt definiert werden: CONSTRAINT Typeinschränkung CHECK (VALUE IN (SELECT DISTINCT Bustyp FROM Busbeschreibung)17); Diese „dynamische“ Variante einer Wertebereichseinschränkung ist allerdings mit Vorsicht zu genießen, da sie dem üblichen Verständnis einer Wertebereichdefinition widerspricht. Es kann durchaus passieren, dass durch das Löschen von Zeilen in einer Tabelle (z. B. Busbeschreibung) Werte eines Wertebereiches plötzlich nicht mehr existieren (z. B. Bustyp D). Trotzdem ist nicht ausgeschlossen, dass noch Daten in der DB vorhanden sind, die entsprechend der Restriktionen des „alten“ Wertebereiches angelegt wurden. Sie besitzen jetzt einen nicht mehr erlaubten Wert, weshalb sie an sich auch nicht mehr vorhanden sein dürften. Im Extremfall könnte es sogar vorkommen, dass der Wertebereich eines Datentyps zum Zeitpunkt tx keine Übereinstimmung mit dem Wertebereich desselben Datentyps zum Zeitpunkt ty besitzt (x = y). 17 Die SELECT-FROM-Anweisung ermittelt alle aktuell in der DB vorhandenen unterschiedlichen Ausprägungen der Spalte Bustyp.
292
7 Die relationale Datenbanksprache SQL
Man beachte, dass bei der VALUE IN-Angabe von Variante 1 in Beispiel 7.16 automatisch die Nullmarke mit zum Wertebereich hinzugefügt wird. Damit besteht der Wertebereich insgesamt aus sechs statt der angegebenen fünf Werte. Möchte man das nicht, so ist dies explizit durch den Zusatz AND VALUE IS NOT NULL sicherzustellen. Wie später noch erklärt wird, kann eine Wertebereichseinschränkung auch erst bei der Definition einer Tabelle spezifiziert werden. Dann beschränkt sie nicht generell den Wertebereich eines Typs, sondern nur den Wertebereich dieser spezifischen Spalte der anzulegenden Tabelle. 7.2.2.5
Anmerkungen zu benutzerdefinierten Wertebereichen in SQL-92
Wie bereits in Kapitel 6.1 diskutiert, ist die Definition eines Typkonzepts immer ein Drahtseilakt. Definiert man das Typsystem zu grobgranular, kann die Korrektheit der entsprechenden Daten eben nur auf dieser groben Ebene gewährleistet werden. Viele Konsistenzverletzungen, insbesondere auch Tippfehler bei der Eingabe, werden vom DBMS nicht abgefangen. Definiert man es hingegen zu feingranular, kann die Flexibilität darunter leiden, da an sich „typkompatible“ Werte, die aber zu unterschiedlichen Datentypen gehören, nicht mehr ohne weiteres miteinander vergleichbar sind. In diesem Abschnitt sollen die Merkmale und Regeln des Typsystems von SQL-92 unter diesen Gesichtspunkten einer genaueren Analyse unterzogen werden. a. Keine Schachtelung von Wertebereichdefinitionen Benutzerdefinierte Wertebereiche können nur auf der Grundlage der Basisdatentypen von SQL definiert werden. Eine Schachtelung, bei der neue Wertebereiche unter Zuhilfenahme anderer, bereits definierter Wertebereiche spezifiziert werden, ist nicht erlaubt. Beispiel 7.17: Verbotene geschachtelte Wertebereichdefinition Die Definition des folgenden Wertebereiches für das Alter von Rentnern (2.) ist wegen der Abstützung auf den benutzerdefinierten Wertebereich Alter (1.) nicht möglich: 1. CREATE DOMAIN Alter AS INTEGER CONSTRAINT Altersbereich CHECK (VALUE BETWEEN 0 AND 120);
erlaubt
2. CREATE DOMAIN AlterRentner AS Alter nicht erlaubt CONSTRAINT AltersbereichRentner CHECK (VALUE BETWEEN 59 AND 120); 3. CREATE DOMAIN AlterKind AS Alter nicht erlaubt CONSTRAINT AltersbereichKind CHECK (VALUE BETWEEN 0 AND 14); Die Definitionen 2. und 3. von Beispiel 7.17 wären korrekt, wenn statt des Wertebereiches Alter der Basisdatentyp INTEGER angegeben worden wäre. Eine Schachtelung von Wertebereichdefinitionen hätte den Vorteil, dass semantisch aufeinander aufbauende Wertebereiche auch so definiert werden könnten. Dadurch würde einerseits die Lesbarkeit eines Schemas verbessert. Andererseits würde aber auch die Fehleranfälligkeit verringert, da bei der Schachtelung beim Übergang von einer Ebene zur nächsten nur die zusätzlichen Eigenschaften (Einschränkungen) anzugeben wären.
7.2 Die Datendefinitionssprache (DDL)
293
Beispiel 7.18: Vorteil der Schachtelung von Wertebereichdefinitionen Da die Lebenserwartung des Menschen in Jahren gesehen einer kleinen Zahl entspricht, wäre es in Beispiel 7.17 bereits ausreichend, Alter auf den Basisdatentyp SMALLINT abzubilden. Wenn wir diese Änderung nachträglich durchführen wollen, würde es bei geschachtelten Wertebereichdefinitionen genügen, nur die Definition von Alter, also der Wurzel des Hierarchiebaumes, entsprechend anzupassen. Die Änderung würde sich automatisch auf alle anderen, „abhängigen“ Unterwertebereiche (wie z. B. AlterRentner und AlterKind) durchschlagen. Ein solches Vorgehen würde dem Vererbungskonzept in objektorientierten Systemen entsprechen. Da SQL keine Schachtelung unterstützt, muss die Änderung in jedem betroffenen Wertebereich vorgenommen werden. Das ist einerseits umständlich, andererseits fehleranfällig, da notwendige Anpassungen übersehen werden können.
b. Keine strenge Typisierung Einer der Gründe für die Einführung von feingranularen Wertebereichen ist, dass Vergleiche und Zuweisungen von Werten, die semantisch nicht zueinander passen, auch nicht vorgenommen werden können. Bei strenger Typisierung wird vorausgesetzt, das unterschiedliche Datentypen nicht miteinander kompatibel sind, falls keine entsprechenden Regeln spezifiziert wurden. In SQL-92 werden benutzerdefinierte Wertebereiche zunächst auf ihre Basisdatentypen zurückgeführt, bevor mit ihnen gearbeitet wird. Damit lassen sich wieder Äpfel mit Birnen vergleichen, sofern Apfel und Birne auf denselben Basisdatentyp Obst zurückgeführt werden können. Beispiel 7.19: Typkompatibilität In Beispiel 7.14 respektive Beispiel 7.17 wurden die Datentypen FünfstelligeZahl zur Spezifikation von Postleitzahlen und Alter zur Darstellung des Alters eines Menschen eingeführt. Da beide auf dem Basisdatentyp INTEGER basieren, sind sie aus der Sicht des Typsystems von SQL-92 typkompatibel und können somit miteinander verglichen werden. Semantisch ergibt das sicherlich keinen Sinn. Damit ist klar, dass Wertebereichdefinitionen wie die in Beispiel 7.11 nur helfen, die Lesbarkeit eines konzeptuellen Schemas zu erhöhen. Sie stellen keine echte Definition eines neuen Datentyps dar, da bei der Definition von plz in Beispiel 7.12 auch einfach als Wertebereich CHAR(8) direkt hätte hingeschrieben werden können, ohne dass sich dadurch semantisch irgendeine Änderung ergeben hätte. c. Wertebereichspezifische Operationen können nicht definiert werden Obwohl SQL-92 die Definition neuer benutzerdefinierter Wertebereiche erlaubt, können für diese Wertebereiche keine eigenen Operationen definiert werden. Stattdessen werden die Operationen des zu Grunde liegenden Basisdatentyps übernommen. Die direkte Konsequenz daraus ist, dass man es nach wie vor nicht verhindern kann, dass auf einer Mitarbeiternummer, die vom Typ FünfstelligeZahl ist, eine Division ausgeführt wird.
294
7 Die relationale Datenbanksprache SQL
Aus b. und c. von oben folgt, dass eine Wertebereichdefinition offensichtlich eben keine Datentypdefinition ist. Vielmehr ermöglicht sie ausschließlich die Einschränkung des Spektrums der möglichen Werte eines Basisdatentyps, stellt also eine Integritätsbedingung dar. Datenbereiche können eingeschränkt werden, wo es aus der Sicht der Anwendungsklassen sinnvoll ist. Weitere Eigenschaften von Datentypen werden jedoch nicht erfüllt. Auf der anderen Seite muss festgestellt werden, dass diese Variante die Flexibilität bei der Nutzung von Datentypen nicht einschränkt, also unter dem Strich durchaus Vorteile bringt. Es sei noch angemerkt, dass bisher erst sehr wenige kommerzielle DBMS die Möglichkeit zur Definition anwendungsspezifischer Wertebereiche unterstützten. Zu den Ausnahmen gehört DB2 von IBM. 7.2.2.6
Datentypkonversion
Die Flexibilität, allerdings auch die Anfälligkeit für Konsistenzverletzungen eines Systems hängt nicht zuletzt davon ab, wie flexibel mit Datentypen umgegangen werden kann. Die Programmiersprache PASCAL ist da sehr restriktiv, da bei ihr Typen schon dann nicht mehr miteinander kompatibel sind, wenn sie unterschiedliche Namen besitzen. Das Gegenteil stellt PL/I dar, das im Prinzip ein beliebiges Zusammenspiel unterschiedlicher Datentypen erlaubt. So kann beispielsweise einer INTEGER-Variablen eine Zeichenkette zugewiesen werden, sofern die Zeichen der Zeichenkette eine Zahl darstellen. SQL liegt irgendwo dazwischen, da es automatisch eine Typkonversion vornimmt, falls die Datentypen ähnlich genug sind wie beispielsweise von REAL nach INTEGER oder von INTEGER nach SMALLINT. Daneben gibt es aber auch die Möglichkeit expliziter Typkonversionen über den CAST-Operator. Er kann immer dann eingesetzt werden, wenn eine Typkonversion theoretisch möglich und praktisch wünschenswert ist. Syntax 7.11: Explizite Datentypkonversion Datentypkonversion ::= CAST SkalarerAusdruck AS {Datentyp | Wertebereich} wobei SkalarerAusdruck ein Ausdruck ist, dessen Abarbeitung einen Wert ergibt, der in einen anderen Datentyp bzw. Wertebereich umgewandelt wird. Beispiel 7.20: Explizite Datentypkonversion 1. CAST ShortString AS INTEGER; wandelt die als Zeichenkette abgelegte Postleitzahl in einen INTEGER-Wert um. 2. WHERE plz = CAST( (SELECT plz FROM Tabelle WHERE ort=’Ilmenau’) AS INTEGER);18 selektiert aus einer Tabelle die Postleitzahl des Ortes Ilmenau in Thüringen. Es wird unterstellt, dass es genau eine Ergebniszeile gibt, deren einzige Spalte vom Typ ShortString ist. Über die CAST-Operation wird die Spalte an den Datentyp der Spalte plz (also INTEGER) angeglichen. 18 Zur
genauen Syntax und Semantik einer SQL-Anfrage wird auf Kapitel 7.2.8 verwiesen.
7.2 Die Datendefinitionssprache (DDL)
7.2.3
295
Anlegen einer Tabelle
Innerhalb des relationalen Datenbankmodells werden Daten ausschließlich als Spaltenwerte innerhalb von Zeilen abgelegt, die wiederum zu Tabellen gehören. Dabei gelten auf der Ebene des Datenbankmodells folgende Regeln: 1. Jede Zeile einer Tabelle repräsentiert ein eigenständiges, unabhängiges Objekt der DB. Dies heißt insbesondere, dass die Existenz des Objektes nicht von der Existenz anderer Zeilen (Objekte) der DB abhängt19. 2. Da zu den konzeptuellen Eigenschaften einer Menge gehört, dass deren Inhalt nicht sortiert ist, folgt, dass zumindest konzeptuell auch die Zeilen einer Tabelle keiner Ordnung unterliegen. Aus Effizienzgründen ist es allerdings unverzichtbar, dass für die interne Ebene festgelegt werden kann, in welcher Reihenfolge die Zeilen einer Tabelle auf der Platte abgelegt werden sollen (Clusterung). 3. Für die Basistabellen und nur für diese gilt, dass deren Zeilen eindeutig über ihren Inhalt identifizierbar sein müssen. Damit muss es mindestens eine Kombination von Spalten geben, deren Werte jede Zeile eindeutig identifizieren (Schlüsselkandidateigenschaft).20 4. Ebenso wie bei Zeilen gibt es aus konzeptueller Sicht auch auf der Ebene der Spalten keine Ordnung. Die Position, die einer Spalte bei der Tabellendefinition zugewiesen wird, muss als zufällig angesehen werden. Da damit nicht über die Positionsnummer auf eine Spalte zugegriffen werden kann, ist an sich die einzig mögliche Zugriffsart die über den Spaltennamen. Das erfordert natürlich, dass dieser innerhalb einer Tabelle eindeutig sein muss. In vielen SQL-Dialekten ist trotzdem in gewissen Situationen ein Zugriff auf eine Spalte über deren Positionsnummer möglich. Diese vereinfachte Schreibweise dient aber lediglich der Bequemlichkeit und sollte auf jeden Fall nur dann angewendet werden, wenn die Lesbarkeit eines SQL-Konstruktes darunter nicht leidet. 5. Der Wert einer Spalte muss atomar sein, das heißt, in SQL-92 sind mehrwertige bzw. strukturierte Spalten nicht zulässig21 . Weiterhin sind in Bezug auf eine Spalte nur Werte aus einem Wertebereich zulässig. 6. Innerhalb eines Datenbankschemas müssen Tabellennamen eindeutig sein, innerhalb einer Tabelle Spaltennamen. 19 Eine gewisse Ausnahme bildet hier die referenzielle Integrität, wie wir später noch sehen werden (siehe Kapitel 7.2.4.2). 20 Es sei noch einmal darauf hingewiesen, dass der DDL-Teil von SQL das relationale Datenbankmodell sauber umsetzt, was insbesondere heißt, dass die durch die DDL definierten Basisrelationen (hier sei der Ausdruck Relation deshalb gestattet) keine Duplikate enthalten dürfen. 21 Seit SQL:1999 ist diese Einschränkung, die aus der Sicht der Mengen- bzw. Relationentheorie nicht notwendig ist, weitestgehend aufgehoben. Allerdings realisieren viele SQL-Dialekte diesen Teil des Standards noch immer nicht.
296
7 Die relationale Datenbanksprache SQL
Die Basistabellen einer DB werden über den CREATE TABLE-Befehl angelegt. Dabei wird neben dem Namen der Basistabelle festgelegt, • aus welchen Spalten sie aufgebaut ist, • welcher elementare Datentyp oder benutzerdefinierte Wertebereich jeder Spalte zu Grunde (Spaltentyp) liegt und • ob Integritätsbedingungen oder andere verbindliche Aussagen für diese Spalte gelten. Weitere Integritätsbedingungen und Aussagen, insbesondere spalten- und tabellenübergreifende, können im Anschluss an die eigentliche Datenstrukturdefinition festgelegt werden. Der CREATE TABLE-Befehl ist implizit auch immer mit der Definition eines neuen Zeilen- (die Menge aller Spalten der Tabellendeklaration) und eines neuen Tabellentyps (da der Befehl implizit auch die Definition des Typs SET OF Zeilentyp einschließt) verbunden. Damit sieht die syntaktische Basisstruktur des CREATE TABLE-Befehls wie folgt aus: Syntax 7.12: Anlegen einer Tabelle (Basissyntax) TabellenDefinition ::= CREATE TABLE TabellenName ( SpaltenName1 : Datentyp[SpaltenBezogeneEinschränkungen] [, SpaltenNamen : Datentyp[SpaltenBezogeneEinschränkungen]]∗ [TabellenBezogeneEinschränkungen]);
Beispiel 7.21: Anlegen einer einfachen Tabelle ohne weitere Spezifikationen Entwurf zweier Tabellen Produkt(produktNr, produktBez, produktTyp, stueckKosten, nettoPreis) und ProduktLagertIn(produktLagerNr, produktLagerBez, produktNr, istBestand). CREATE TABLE produktNr produktBez produktTyp stueckKosten nettoPreis
Produkt ( CREATE TABLE ProduktLagertIn ( INTEGER, produktLagerNr INTEGER, CHAR(20), produktLagerBez VARCHAR(25), CHAR(20), produktNr INTEGER, DECIMAL(7,2), istBestand DECIMAL(9,2)); DECIMAL(7,2));
7.2.4
Integritätsbedingungen
7.2.4.1
Klassifikation von Integritätsbedingungen
DBMS dienen der Verwaltung von Massendaten. Wo immer im großen Umfang mit Daten umzugehen ist, ist die Gefahr des Auftritts von Fehlern besonders groß. So besteht auch bei DBS eine latente Gefahr, dass beispielsweise aufgrund von Flüchtigkeitsfehlern oder Unkenntnis bei der Datenerfassung und/oder -änderung inkonsistente Daten in die DB gelangen. Besondere Gefahrenquellen stellen neben Tippfehlern insbesondere die oft mannigfaltigen
7.2 Die Datendefinitionssprache (DDL)
297
Beziehungen zwischen den Daten der DB und die durch ein zu wenig ausdrucksstarkes Datenbankmodell implizierte ungenaue Darstellung von Informationen dar. Neben diesen eher technischen Aspekten treten häufig auch noch Regeln und Vorschriften auf einer höheren Ebene, vor allem Geschäftsregeln. Geschäftsregeln sind Vorgaben, die aufgrund von Modellannahmen oder betrieblichen bzw. verwaltungsbezogenen Anforderungen zu gelten haben. Beispielsweise könnte eine Geschäftsregel festlegen, dass der Einkaufspreis eines Fremdprodukts seinen Verkaufspreis um mindestens 30 Prozent unterschreiten muss. SQL-92 versucht durch ein umfangreiches Konsistenzsicherungspaket den mannigfaltigen Aspekten und hohen Anforderungen an die Integrität einer DB gerecht zu werden. Daten befinden sich dann in einem (semantisch) konsistenten Zustand, wenn sie den durch sie repräsentierten Realweltausschnitt nicht falsch wiedergeben. Dies schließt natürlich ein, dass der Datenbestand der DB keine Widersprüche aufweisen darf. Die negierte Formulierung nicht falsch wurde hier bewusst statt der positiven Formulierung korrekt gewählt. Wie im Zusammenhang mit Nullmarken später noch gezeigt wird, ist es eher unwahrscheinlich, dass die DB immer eine vollständige Beschreibung der relevanten Realweltdaten anbieten kann. Stattdessen ist zu erwarten, dass nicht alle gewünschten Informationen vollständig vorhanden sind. In einer solchen Situation darf die DB dann allerdings keine falschen, sondern nur unvollständige Daten anbieten. Ein DBMS kann nicht die vollständige Korrektheit von Daten garantieren, da Rechner immer noch viel zu wenig Semantik erfassen und verstehen können. Allerdings kann ein DBMS dabei helfen, nicht korrekte Daten oder Situationen zu erkennen bzw. zu verhindern. Zur Unterstützung der Konsistenz der DB können konsistenzsichernde Maßnahmen auf folgenden Ebenen getroffen werden22: 1. Spaltenbezogene Integritätsbedingungen Zu den spaltenbezogenen Integritätsbedingungen gehören Wertebereichseinschränkungen, Spaltenvorbelegungen und Zustandsübergänge. Je genauer der Wertebereich auf die zu repräsentierenden Daten zugeschnitten ist, desto sicherer können falsche Berechnungen, Fehleingaben oder einfache Missverständnisse aufgedeckt und beseitigt werden. Auch das automatische Belegen einer Spalte mit einem Wert, falls kein anderer Wert bekannt ist, kann spätere Operationen auf den Daten sicherer machen.23 2. Beziehungen zwischen Daten (Beziehungsintegrität) Daten stehen häufig in vielerlei Beziehungen zueinander. Bei relationalen DBS sind die Tabellen des konzeptuellen Datenbankschemas durch Anwendung der Normalisierungstheorie üblicherweise sehr kompakt und einfach aufgebaut. Daten, die aus der Sicht der Anwendung in enger Beziehung zueinander stehen, sind häufig auf verschiedene Tabellen aufgeteilt. Die ursprünglichen Beziehungen werden über Fremdschlüssel und möglicherweise über Tabellen simuliert, die Beziehungstabellen darstellen. Je genauer solche Be22 Wir werden im Folgenden etwas unsauber immer von Integritätsbedingungen sprechen, obwohl unter diesem Begriff auch Maßnahmen besprochen werden, die man nur bei sehr weiter Interpretation darunter verstehen würde (wie z. B. die Festlegung eines Defaults). 23 Wünschenswert wäre sicherlich auch, dass man dem DBMS Zustandsübergangsregeln bekannt machen könnte, damit nicht erlaubte Datenänderungen (z. B. Wechsel von verheiratet zu ledig) verhindert werden können. Dies ist aber so ohne weiteres nicht möglich. Bedingt können dazu die so genannten Zusicherungen verwendet werden (siehe Kapitel 7.8).
298
7 Die relationale Datenbanksprache SQL
ziehungen dem DBMS bekannt sind, desto eher ist es in der Lage, deren Korrektheit und Vollständigkeit sicherzustellen. 3. Tabellenbezogene Integritätsbedingungen Sind spezielle Eigenschaften von Spalten bekannt (z. B. Schlüsseleigenschaft), so sollten sie explizit formuliert werden können, damit das DBMS die Möglichkeit hat, ihre Einhaltung zu überwachen. Hierzu gehören auch Integritätsbedingungen, die zeilen- oder spaltenübergreifend ausgelegt sind. 4. Allgemeine Integritätsbedingungen Die bereits angesprochenen Geschäftsregeln sind ein Beispiel für Integritätsbedingungen, die i. d. R. tabellenübergreifend auf der Ebene des Gesamtdatenbestandes gelten sollen. Solche Bedingungen können sich auf einzelne Tabellen oder sogar über Tabellen hinweg auf Ausschnitte des konzeptuellen Datenbankschemas beziehen. 5. Ablaufintegrität bzw. operationale Integrität Diese Ebene unterscheidet sich von den anderen Ebenen dadurch, dass es sich hier nicht um Maßnahmen dreht, die im Vorfeld festgelegt und dann im laufenden Betrieb überwacht werden. Vielmehr handelt es sich um Kontroll- und Überwachungsmaßnahmen, die dafür Sorge tragen, dass das parallele Arbeiten der Anwender auf demselben Datenbestand diesen nicht korrumpiert. Die ersten vier Arten von Aussagen setzen sich vor allem mit der exakten und fehlerfreien Beschreibung des zu modellierenden Realweltausschnittes in der DB auseinander. Man spricht deshalb auch von semantischer Korrektheit bzw. Integrität der Daten. In diesem Kapitel sollen nur die ersten drei Arten besprochen werden. Da sie im Zusammenhang mit der CREATE TABLE-Definition spezifiziert werden, werden sie auch Tabellenzusicherungen (constraints) genannt. Obwohl sie grundsätzlich jederzeit im Rahmen von Schemaänderungen hinzugefügt, geändert oder gelöscht werden können, kann man sie als schlecht änderbar ansehen, insbesondere da das Hinzufügen oder Ändern von Bedingungen wegen ihrer Auswirkungen auf den bereits vorhandenen Datenbestand nur unter bestimmten, stark eingeschränkten Bedingungen möglich sein kann. Tabellenzusicherungen zählen zu den statischen Integritätsbedingungen. Sie beschreiben die Eigenschaften von Daten unabhängig von einem konkreten Kontext. Im Gegensatz dazu beschreiben dynamische Integritätsbedingungen erlaubte Übergänge von einem Zustand in einen anderen. Definition 7.2: Statische Integritätsbedingungen Bedingungen, die in einem Zustand erfüllt sein müssen, damit er gültig ist, werden statische Integritätsbedingungen genannt. Definition 7.3: Dynamische Integritätsbedingungen Bedingungen, die beim Übergang von einem in einen anderen Zustand beachtet werden müssen, heißen dynamische Integritätsbedingungen. Bei Änderungsoperationen muss darauf geachtet werden, dass sie diese Bedingung nicht verletzen.
7.2 Die Datendefinitionssprache (DDL)
299
Dynamische Integritätsbedingungen können in SQL (bisher) nicht direkt formuliert werden. Sie lassen sich nur implizit über Trigger bzw. Datenbankprozeduren (stored procedures) simulieren. Beide gehören jedoch (noch) nicht zum SQL-92-Standard, so dass die durch sie unterstützten Fähigkeiten vom SQL-Dialekt abhängen. Dieses Thema wird später behandelt (Kapitel 7.8). Allgemeine Integritätsbedingungen werden auch Schemazusicherungen genannt. Bei ihnen handelt es sich um in einer konventionellen Programmiersprache geschriebene Prozeduren, die dynamisch dem konzeptuellen Datenbankschema hinzugefügt werden können. Auf diese Integritätsbedingungen wird am Ende des SQL-Kapitels eingegangen. Etwas spezifischer gesehen kann ein Datenbankzustand aus der Sicht des DBMS als konsistent angesehen werden, wenn alle im konzeptuellen Datenbankschema spezifizierten Bedingungen und Zusicherungen erfüllt sind. Aus logischer Sicht bedeutet dies, dass die Auswertung aller konjunktiv (AND-) verknüpften Zusicherungen als Ergebnis TRUE liefert. Wie oben angedeutet, sind die Aspekte der operationalen Integrität auf einer anderen Ebene zu sehen. Sie werden im Zusammenhang mit dem Transaktionsmanagement diskutiert. 7.2.4.2
Tabellenzusicherungen
Spalten- und tabellenbezogene Integritätsbedingungen Spaltenbezogene Integritätsbedingungen lassen sich auf der Basis einer Spalte definieren und werden beim Anlegen der Spalte spezifiziert. Zu den impliziten Integritätsbedingungen gehört die Typisierung der Spalten. Sie stellt sicher, dass in einer Spalte nur Werte desselben Typs gespeichert werden können. Auch die Regel der Homogenität von Zeilen ist eine implizite Integritätsbedingung. Sie besagt, dass alle Zeilen einer Tabelle die gleiche Struktur besitzen müssen. Diese beiden impliziten Bedingungen sind die Grundvoraussetzung für eine effiziente Datenverarbeitung, da sie sicherstellen, dass große Mengen an Daten einheitlich behandelt werden können. Zu den expliziten und ausschließlich spaltenbezogenen Integritätsbedingungen gehören Wertebereichseinschränkungen und Spaltenvorbelegungen. Beide waren bereits im Zusammenhang mit benutzerdefinierten Datentypen (Kapitel 7.2.2.4) eingeführt worden. Beide Einschränkungen können sowohl auf der Ebene der Wertebereich- als auch der Tabellendefinition in analoger Wiese eingesetzt werden. Deshalb ergeben sich hier gegenüber der Diskussion in Kapitel 7.2.2.4 keine neuen Aspekte. Wertebereichseinschränkungen sind über die CHECKKlausel, Spaltenvorbelegungen über die DEFAULT-Klausel festzulegen. Auf der Ebene einer Spaltendefinition kommt als neue Möglichkeit hinzu, dass für eine Spalte festgelegt werden kann, dass sie nicht mit der Nullmarke belegt werden darf. Dies geschieht durch die NOT NULL-Spezifikation. Hiermit kann u. a. verhindert werden, dass Daten ohne Aussagekraft in die DB gelangen können. Soll beispielsweise in die Tabelle ProduktLagertIn die Lagerung eines Produktes in einem bestimmten Lager eingetragen werden, so müssen mindestens die Produktnummer und das Lager bekannt sein, während die eingelagerte Menge auch noch später nachgetragen werden könnte. Eine Mengeneintragung ohne Produkt- oder Lagernummer besitzt hingegen keine Aussagekraft und ist daher wertlos. Die NOT NULLSpezifikation kann auch als Kurzform für eine entsprechende Formulierung über die CHECKKlausel angesehen werden.
300
7 Die relationale Datenbanksprache SQL
Beispiel 7.22: Über CHECK-Klausel realisierte NOT NULL-Spezifikation produktNr
INTEGER
CHECK (VALUE IS NOT NULL)
INTEGER
NOT NULL
ist äquivalent zu produktNr
Beispiel 7.23: Wertebereichseinschränkungen und Spaltenvorbelegungen 1. CREATE TABLE produktNr
ProduktLagertIn ( INTEGER
lagerNr
SMALLINT
istBestand qualität
SMALLINT CHAR(8)
NOT NULL CHECK (VALUE BETWEEN 10000 AND 99999),24 NOT NULL CHECK (VALUE BETWEEN 100 AND 999), (CHECK VALUE ≥ 0) DEFAULT 0, CHECK (VALUE IN (’sehr gut’, ’gut’, ’mittel’, ’schlecht’)));
2. CREATE TABLE Abteilung ( abteilungsNr DreistelligeZahl PRIMARY KEY, abteilungsName VARCHAR(25) UNIQUE NOT NULL, budget PositiveReal CHECK (VALUE BETWEEN 100000 AND 10000000); Die innerhalb der Klammer angegebene Bedingung zur Wertebereichseinschränkung kann auch durchaus eine komplexe Anfrage repräsentieren. Beispiel 7.24: Anfrage als Wertebereichseinschränkung CREATE TABLE produktNr
ProduktLagertIn ( INTEGER
(CHECK VALUE IN (SELECT produktNr FROM Produkt)),
. . . ); Es besteht auch die Möglichkeit, die CHECK-Klausel zur Umsetzung von Formatierungswünschen einzusetzen. Beispiel 7.25: CHECK-Klausel als Hilfsmittel zur Formatierung CREATE TABLE mitarbeiterNr
plz
Mitarbeiter ( INTEGER ... CHAR(9)
NOT NULL CHECK (VALUE BETWEEN 1000000 AND 9999999), CHECK (VALUE LIKE ’D-_____’ OR VALUE LIKE ’NL-______’),25
. . . ); 24 Statt VALUE kann auch der Spaltenname genommen werden, also CHECK (produktNr BETWEEN 10000 AND 99999).
7.2 Die Datendefinitionssprache (DDL)
301
Wie man der folgenden Syntaxdefinition entnehmen kann, gibt es vier Arten von spaltenbezogenen Integritätsbedingungen, die in beliebiger Reihenfolge und Kombination festgelegt werden dürfen. Syntax 7.13: Spaltenbezogene Integritätsbedingungen SpaltenBezogeneEinschränkungen ::= [CONSTRAINT NameEinschränkung] [NULL|NOT NULL] [DEFAULT-Klausel] [Einschränkung26 ] [SchlüsselBedingung] Die ersten beiden Bedingungen können nur direkt bei der Definition der Spalteneigenschaften festgelegt werden, während die beiden letzten direkt bei der Spalte (siehe Beispiel 7.25) oder erst nach Abschluss aller Spaltendefinitionen in einem eigenen Block definiert werden können (siehe Beispiel 7.26).
Beispiel 7.26: CHECK-Klausel im Anschluss an die Deklarationen der Spalten CREATE TABLE mitarbeiterNr plz CHECK
Mitarbeiter ( INTEGER NOT NULL, ... CHAR(9), ... (mitarbeiterNr BETWEEN 1000 AND 9999999 AND plz LIKE ’D-_____’ OR plz LIKE ’NL-______’));
Entgegen der Formulierung in Beispiel 7.26 wird dringend angeraten, eine Einschränkung mit einem Namen zu versehen. Auch sollten grundsätzlich nur semantisch zusammengehörige Bedingungen in eine CHECK-Klausel gepackt werden (Modularisierung). Damit sind häufig mehrere CHECK-Klauseln pro Tabelle notwendig, die auch nacheinander definiert werden können. Die Interpretation entspricht immer einer AND-Verknüpfung der Bedingungen aller CHECK-Klauseln, was der in Beispiel 7.26 gewählten Aneinanderreihung aller Bedingungen in einer CHECK-Klausel entspricht. Bei Angabe von NOT NULL werden Einfüge- und Änderungsoperationen zurückgewiesen, wenn sie bei der entsprechenden Spalte die Nullmarke eintragen wollen oder trotz nicht vorgegebenem DEFAULT kein Wert spezifiziert wurde. Da solche Operationen in Transaktionen ausgeführt werden und für Transaktionen das Alles-oder-Nichts-Prinzip gilt, ist ein Transaktionsabbruch die direkte Folge (siehe Kapitel 9.1.2). Vermieden werden kann dies nur, falls spezielle Fehlerroutinen für solche Fehler vorgesehen wurden. Sollen Nullmarken erlaubt sein, braucht das NULL-Schlüsselwort üblicherweise nicht angegeben zu werden, da es den Default darstellt. 25 Diese alte Version der Darstellung einer Postleitzahl ist heute nicht mehr gültig und wird hier nur zu Demonstrationszwecken noch verwendet. 26 Einschränkung wird in Syntax 7.9 definiert und ist im Prinzip eine erweiterte CHECK-Klausel.
302
7 Die relationale Datenbanksprache SQL
Tabellenbezogene CHECK-Klausel In der CHECK-Klausel können neben speziellen Bedingungen an (den Wertebereich von) Spalten auch allgemeine Bedingungen an die Tabelle insgesamt gestellt werden. Beispielsweise könnte hier spezifiziert werden, dass das Bestelldatum einer Ware älter sein muss als das Datum, an dem die Ware ausgeliefert wird. Grundsätzlich können Bedingungen nicht nur über mehrere Spalten einer Tabelle definiert werden, sondern sogar über mehrere Tabellen hinweg. Aus Gründen einer sauberen und modularen Definition ist es sinnvoll, Bedingungen immer dort abzulegen, wo sie am ehesten hingehören, also spaltenbezogene Bedingungen bei ihren Spalten, tabellenbezogene bei den tabellenbezogenen Einschränkungen und tabellenübergreifende auf Schemaebene. Tabellenübergreifende Einschränkungen werden in der CREATE ASSERTION-Klausel spezifiziert, auf die in Kapitel 7.8 eingegangen wird. Syntax 7.14: Tabellenbezogene Integritätsbedingungen TabellenBezogeneEinschränkungen ::= {[CONSTRAINT NameEinschränkung] {[Einschränkung] | [SchlüsselBedingung]}}∗ Beispiel 7.27: Tabellenbezogene CHECK-Klausel 1. Die folgende Integritätsbedingung der Tabelle Produkt stellt sicher, dass der Preis eines Produktes mehr als 50 Prozent über seinen Herstellungskosten liegt. CONSTRAINT VerlustVermeidung CHECK (nettoPreis > (stueckKosten ∗ 1,5)); 2. Diese Integritätsbedingung der Tabelle Abteilung garantiert, dass sich das Budget einer Abteilung in einer gewissen Relation zur Anzahl der Mitarbeiter verhält. CONSTRAINT BudgetKontrolle CHECK ((budget/mitarbeiterZahl) BETWEEN 1000 AND 10000); 3. Soll in der Tabelle SindBestandteilVon sichergestellt werden, dass in der Spalte teilNr keine Nummer steht, die auch in der Spalte produktNr vorkommt, so hilft die folgende Integritätsbedingung: CONSTRAINT NrKontrolle CHECK (teilNr NOT IN (SELECT produktNr FROM SindBestandteilVon)); Betrachtet man Beispiel 7.27 genauer, kann man schnell die Probleme erkennen, die mit Integritätsbedingungen verbunden sind. Es besteht die Gefahr, dass sie sich widersprechen können. Wird beispielsweise eine neue Abteilung eingerichtet, von der man vorerst nur den Chef kennt, so ergibt sich das Problem, das die in Punkt 2. eingeführte Integritätsbedingung BudgetKontrolle festlegt, dass das Budget der Abteilung zwischen 1.000,– und 10.000,– C liegen muss (da mitarbeiterZahl erst 1 ist), andererseits die spaltenbezogene Integritätsbedingung der Spalte budget festlegt27 , dass das Budget der Abteilung nicht unter 100.000,– C liegen darf. 27 Siehe
Beispiel 7.23, Variante 2.
7.2 Die Datendefinitionssprache (DDL)
303
Ein ähnliches Problem tritt in Punkt 3. von Beispiel 7.27 auf, da die dort spezifizierte Integritätsbedingung an die falsche Tabelle gehangen wurde. Möchte man verhindern, dass es ein Teil geben kann, das dieselbe Nummer besitzt wie ein Produkt, muss dies bei der Einfügung neuer Teile in die DB geprüft werden, also innerhalb der Tabellen Teile und Produkt. Beispiel 7.28: Auf andere Tabellen zurückgreifende Integritätsbedingung Die folgende Integritätsbedingung muss in der Tabelle Teile spezifiziert werden. Sie greift bei ihrer Ausführung auf die Tabelle Produkt zu. CONSTRAINT NrKontrolle CHECK (teilNr NOT IN (SELECT produktNr FROM Produkt)); Leider ist die Frage, ob ein DBMS in der Lage ist bzw. sein könnte, sich widersprechende Integritätsbedingungen zu erkennen und damit zu vermeiden, mit nein zu beantworten. Im Allgemeinfall ist die Frage der Widerspruchsfreiheit von Integritätsbedingungen ein NPvollständiges Problem28 und damit nicht in endlicher Zeit entscheidbar. Es bleibt also dem Datenbankprogrammierer überlassen, Fehler in der Spezifikation von Integritätsbedingungen zu erkennen und zu beseitigen. Schlüsselbedingungen Der SQL-92-Standard unterstützt erstmals ausgiebig die Spezifikation verschiedener Schlüsselarten. Es können die eine Zeile eindeutig identifizierenden Spalten (Schlüsselkandidaten, Primärschlüssel) und Fremdschlüssel angegeben werden. Definition 7.4: Schlüsselkandidat Ein Schlüsselkandidat ist eine Spalte oder eine Kombination von Spalten, die jeden Datensatz einer Tabelle eindeutig identifizieren. Syntax 7.15: Schlüsselbedingungen SchlüsselBedingung ::= {IdentifizierendeSchlüsselBedingung | Fremdschlüssel} Für alle Schlüsselbedingungen gilt, dass die entsprechende Eigenschaft entweder direkt bei der Spalte spezifiziert werden kann, wenn die Spalte alleine diese Eigenschaft schon garantiert, oder im Anschluss an die Spaltenspezifikationen im Block der tabellenbezogenen Integritätsbedingungen. 28 NP-vollständig bedeutet vereinfachend gesagt, dass das Problem im allgemeinen Fall nicht in polynomieller Zeit gelöst werden kann, da die Berechnung der korrekten Problemlösung durch einen Rechner wegen der damit verbundenen Komplexität beliebig lange dauert. Solche Probleme sind trotzdem behandelbar, indem man eine hinreichende (aber eben nicht notwendige) Bedingung spezifiziert, also quasi eine Obermenge erzeugt, die die „kritischen“ Fälle sicher enthält. Dies bedeutet allerdings, dass die Lösung ungenau ist, also beispielsweise einen Konflikt „erkennt“, der real nicht existiert. Durch diese Vergröberung wird sichergestellt, dass alle existierenden Konflikte auch wirklich erkannt werden. Bei der Suche nach optimalen Lösungen kann von einer Lösung nicht gesagt werden, wie gut sie im Vergleich zur besten Lösung ist, da man ja die optimale Lösung nicht vergleichen kann und damit keinen Fixpunkt hat.
304
7 Die relationale Datenbanksprache SQL
Primärschlüssel und Schlüsselkandidaten Jede Tabelle muss genau einen Primärschlüssel besitzen, der über die PRIMARY KEY-Klausel definiert wird. Von den Schlüsselkandidaten unterscheidet sich der Primärschlüssel dadurch, dass die ihn definierenden Spalten grundsätzlich keine Nullmarken enthalten dürfen. Schlüsselkandidaten werden über die UNIQUE-Klausel definiert. Beide Schlüsselformen können aus einer oder mehreren Spalten zusammengesetzt sein. Das DBMS stellt sicher, dass bei beiden Schlüsselarten die sie ausmachenden Spalten immer identifizierenden Charakter haben, also keine identischen Spaltenwertkombinationen auftreten können. Dies mag bei Schlüsselkandidaten zunächst einmal etwas überraschend sein, da bei ihnen Spalten mit der Nullmarke belegt sein können, woraus man schließen könnte, dass bereits weniger Spalten als Schlüsselkandidat fungieren könnten. Hier ist aber zu beachten, dass Nullmarken grundsätzlich voneinander verschieden sind (siehe Kapitel 7.2.2.3), so dass aus der Sicht des DBMS zwei gleiche Spaltenwertkombinationen als unterschiedlich angesehen werden, sofern bei den Werten mindestens eine Nullmarke vorhanden ist. Definition 7.5: Primärschlüssel Der Primärschlüssel ist der Schlüsselkandidat, der aus der Menge der Schlüsselkandidaten als der Identifikator der Datensätze der Tabelle ausgewählt wurde. Davon gibt es pro Tabelle genau einen. In der Regel handelt es sich um den kürzesten Schlüsselkandidaten (mit den wenigsten Spalten). Zudem sollten die Spalten aus Sicht der Anwendung als nicht änderbar angesehen werden. Der Primärschlüssel darf keine Spalten enthalten, die die Nullmarke annehmen können. Syntax 7.16: Identifizierende Schlüssel IdentifizierendeSchlüsselBedingung ::= {PRIMARY KEY|UNIQUE} (SpaltenNameN) Beispiel 7.29: Primärschlüssel und Schlüsselkandidaten 1. CREATE TABLE mitarbeiterNr
Mitarbeiter ( AchtstelligeZahl PRIMARY KEY, ...
2. CREATE TABLE produktNr produktBez
Produkt ( FünfstelligeZahl PRIMARY KEY, VARCHAR(25) UNIQUE, ...
3. CREATE TABLE Abteilung ( abteilungsNr DreistelligeZahl PRIMARY KEY, abteilungsName VARCHAR(25) UNIQUE NOT NULL, ... In 1. wird nur der Primärschlüssel festgelegt, in 2. auch ein Schlüsselkandidat und in 3. wird für den Schlüsselkandidaten zusätzlich noch spezifiziert, dass er nicht die Nullmarke annehmen darf.
7.2 Die Datendefinitionssprache (DDL)
305
Wie man in Beispiel 7.31 und Beispiel 7.32 sehen kann, können Schlüsselbedingungen auch als separate Integritätsbedingungen am Ende der eigentlichen Spaltendefinitionen spezifiziert werden. Dies ist insbesondere auch dann notwendig, wenn der Primärschlüssel und/oder der Schlüsselkandidat aus mehreren Spalten bestehen. Beide Arten von Schlüsselbedingungen könnten auch ohne die entsprechenden Klauseln spezifiziert werden (siehe Beispiel 7.30). Die Klauseln dienen also nur der Abkürzung und vor allem der besseren Lesbarkeit29. Beispiel 7.30: Konventionelle Definition der Schlüsseleigenschaften 1. Schlüsselkandidat: CREATE TABLE produktNr
Produkt ( INTEGER UNIQUE, ...
ist äquivalent zu CREATE TABLE produktNr
Produkt ( INTEGER CHECK (produktNr NOT IN (SELECT produktNr FROM Produkt)), ...
2. Primärschlüssel: CREATE TABLE produktNr
Produkt ( INTEGER PRIMARY KEY, ...
ist äquivalent zu CREATE TABLE produktNr
Produkt ( INTEGER UNIQUE NOT NULL, ...
Beispiel 7.31: Fremdschlüssel CREATE TABLE Liefert ( zuliefererNr AchtstelligeZahl, teilNr FünfstelligeZahl, produktNr FünfstelligeZahl, CONSTRAINT LiefertPS PRIMARY KEY (zuliefererNr, teilNr), CONSTRAINT LiefertFS1 FOREIGN KEY (zuliefererNr) REFERENCES Zulieferer ON DELETE CASCADE ON UPDATE CASCADE, 29 Wenn man einmal davon absieht, dass es pro Tabelle genau einen Primärschlüssel, aber mehrere Sekundärschlüssel geben kann.
306
7 Die relationale Datenbanksprache SQL CONSTRAINT LiefertFS2 FOREIGN KEY (teilNr) REFERENCES Teil ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT LiefertFS3 FOREIGN KEY (produktNr) REFERENCES Produkt ON DELETE SET NULL ON UPDATE CASCADE);
Beispiel 7.32: Referenzielle Integrität CREATE TABLE Zulieferer ( zuliefererNr AchtstelligeZahl PRIMARY KEY, zuliefererName VARCHAR(25) NOT NULL, ort VARCHAR(25), strasse VARCHAR(25), hausNr CHAR(5), plz CHAR(5), bank VARCHAR(25), iban VARCHAR(25), bic VARCHAR(25), ansprechpartner VARCHAR(25), ansprechpartTelNr VARCHAR(15), CONSTRAINT Bankverbindung UNIQUE (iban, bic) NOT DEFERRABLE); CREATE TABLE AuftragZulieferer ( auftragsNr INTEGER PRIMARY KEY, bearbeiterNr INTEGER, datum DATE NOT NULL, zuliefererNr AchtstelligeZahl NOT NULL, CONSTRAINT AuftragZuliefererFS1 FOREIGN KEY (bearbeiterNr) REFERENCES Mitarbeiter(mitarbeiterNr) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT AuftragZuliefererFS2 FOREIGN KEY (zuliefererNr) REFERENCES Zulieferer ON DELETE RESTRICT ON UPDATE CASCADE); Fremdschlüssel Mit Hilfe der Fremdschlüsselbedingungen wird ein in Bezug auf die Konsistenz der Daten ganz wichtiges Konzept von DBMS unterstützt, das Konzept der referenziellen Integrität. Aufgrund der Normalformenlehre, also zur Vermeidung von Redundanzen, werden komplexe Realweltobjekte i. d. R. zerlegt. Dann wird ein Realweltobjekt durch mehrere Zeilen, die auf
7.2 Die Datendefinitionssprache (DDL)
307
mehrere Tabellen verteilt sind, dargestellt. Beispielsweise werden bei einer sauberen Darstellung des Realweltobjektes Mutter mindestens zwei Tabellen erzeugt werden, eine, in der die eigentlichen Daten zu jeder Mutter stehen und eine, in der die Daten über ihre Kinder abgelegt sind. Um nun die Beziehung zwischen den Kindern und der Mutter nicht zu verlieren, muss sie in irgendeiner Form festgehalten werden. Nun lassen sich Beziehungen zwischen Daten über Tabellengrenzen hinweg im relationalen Datenbankmodell nicht direkt modellieren. Dies geht nur indirekt über den Export eines Schlüsselkandidaten in die zu verbindende Tabelle. Ein solcher Schlüsselkandidat wird in der importierenden Tabelle Fremdschlüssel genannt. Ein Fremdschlüssel zeichnet sich also dadurch aus, dass er entweder der Primärschlüssel oder ein Schlüsselkandidat einer anderen Tabelle ist. Eine solche Fremdschlüsselbedingung impliziert nun offensichtlich eine Integritätsbedingung. Falls der Fremdschlüssel definiert ist, also mindestens ein Schlüsselattribut einen Wert ungleich der Nullmarke besitzt, muss in der Tabelle, auf die er sich bezieht, eine Zeile enthalten sein, deren relevante Spalten exakt den Werten des Fremdschlüssels entsprechen. Auf unser Beispiel bezogen muss also sichergestellt sein, dass zu jeder Kindzeile auch wirklich die entsprechende Mutterzeile in der Tabelle Mutter existiert. Die Erfüllung dieser Eigenschaft wird referenzielle Integrität genannt. Definition 7.6: Fremdschlüssel Ein Schlüsselkandidat (inkl. Primärschlüssel) einer Tabelle T1 , der in einer anderen Tabelle T2 genutzt wird, um eine Beziehung zu T1 zu modellieren, wird in T2 Fremdschlüssel genannt. Definition 7.7: Referenzielle Integrität Besteht zwischen zwei Tabellen T1 und T2 eine über einen Fremdschlüssel aufgebaute Beziehung, so stellt die referenzielle Integrität sicher, dass in der Fremdschlüsseltabelle T2 keine Fremdschlüssel existieren können, die nicht auch in T1 als Wert des entsprechenden Schlüsselkandidaten bzw. Primärschlüssels vorhanden sind. Syntax 7.17: Fremdschlüsselspezifikation FremdschlüsselBedingung ::= FOREIGN KEY SpaltenNameN1 REFERENCES TabellenName [(SpaltenNameN2)] [ON DELETE {NO ACTION | CASCADE | SET NULL | SET DEFAULT | RESTRICT }] [ON UPDATE {NO ACTION | CASCADE | SET NULL | SET DEFAULT | RESTRICT }] Dabei muss gelten, dass die in SpaltenNameN2 aufgelisteten Spalten zusammen einen Schlüsselkandidaten in der Tabelle TabellenName darstellen. In SpaltenNameN1 sind die Spalten aus der aktuell zu definierenden Tabelle aufgelistet, die den Fremdschlüssel darstellen. Damit ist klar, dass die Anzahl der Spalten in SpaltenNameN1 und SpaltenNameN2 identisch sein muss. Sind auch noch die Spaltennamen gleich, kann SpaltenNameN2 weggelassen werden. Obwohl der Fremdschlüssel grundsätzlich als Pendant nur einen beliebigen Schlüsselkandidaten in der anderen Tabelle benötigt, wird in der Regel der Primärschlüssel gewählt,
308
7 Die relationale Datenbanksprache SQL Haupttabelle
Fremdschlüsseltabelle (Untertabelle)
auftragsNr Fremdschlüssel auftragsNr auftragsPos Primärschlüssel Primärschlüssel
Auftrag AuftragsPosition Haupttabelle abteilungsNr
Fremdschlüsseltabelle (Untertabelle) mitarbeiterNr
Primärschlüssel Primärschlüssel Fremdschlüssel
abteilungsNr
Abteilung Mitarbeiter Abb. 7.4: Fremdschlüssel
7.2 Die Datendefinitionssprache (DDL)
309
da dieser einerseits keine Nullmarken enthält und andererseits auch häufig die kleinste Spaltenkombination darstellt, die die Eindeutigkeitseigenschaft garantiert. Die Tabelle, aus der referenziert wird (Fremdschlüsseltabelle), soll Untertabelle genannt werden, während die Tabelle, auf die verwiesen wird, also wo der Fremdschlüssel Schlüsselkandidat bzw. Primarschlüssel ist, Haupttabelle heißen soll. In Abbildung 7.4 wird der Primärschlüssel der Tabelle Auftrag als Fremdschlüssel in die Tabelle AuftragsPosition übernommen. Dort bildet er zusammen mit der Spalte auftragsPos den Primärschlüssel. Im zweiten Beispiel wird der Primärschlüssel der Tabelle Abteilung als Fremdschlüssel in die Tabelle Mitarbeiter aufgenommen. Dort stellt er eine einfache Spalte dar. Soll in eine Untertabelle ein Fremdschlüssel eingefügt werden, der in der Haupttabelle (noch) nicht angelegt ist, wird die Anweisung ignoriert. Gehörte die entsprechende Operation zu einer Einfügeoperation und ist für die entsprechende Spalte das NOT NULL-Prädikat festgelegt worden, würde ein nicht akzeptabler Zustand auftreten. Dieser muss zu einem Transaktionsabbruch führen, falls keine Fehlerroutine vorgesehen ist oder diese den Fehler nicht ausbügeln kann. In Beispiel 7.31 wurden gleich drei Fremdschlüssel importiert. Bei dieser Modellierung wird unterstellt, dass mehrere Zulieferer dasselbe Teil liefern können. Allerdings kann das Teil von diesem bestimmten Zulieferer nicht in unterschiedliche Produkte eingebaut werden, sondern immer nur in genau eines. Sollten Teile in mehrere Produkte verbaubar sein, muss der Primärschlüssel erweitert werden um produktNr. Es sei auch noch erwähnt, dass diese Form der Modellierung aus Sicht der Normalisierungstheorie Schwierigkeiten bereiten könnte, insbesondere dann, wenn ein Teil immer, also unabhängig vom konkreten Lieferanten in ein Produkt eingebaut werden kann. Dann müssten die Informationen auf zwei Tabellen aufgeteilt werden. Bei Fremdschlüsseln kann es Probleme bei zyklischen Verweisen geben (s. Beispiel 7.33). Beispiel 7.33: Zyklischer Verweis HauptTabelle ( INTEGER PRIMARY KEY, ... forKeyUnter INTEGER NOT NULL) CONSTRAINT VerweisUnterTabelle FOREIGN KEY forKeyUnter REFERENCES UnterTabelle(primKeyUnter), ...;
CREATE TABLE primKeyHaupt
UnterTabelle ( INTEGER PRIMARY KEY, ... forKeyHaupt INTEGER NOT NULL) CONSTRAINT VerweisHauptTabelle FOREIGN KEY forKeyHaupt REFERENCES HauptTabelle (primKeyHaupt), ...;
CREATE TABLE primKeyUnter
310
7 Die relationale Datenbanksprache SQL
Wenn in diese Tabellen neue Datensätze eingefügt werden sollen, beißt sich die Katze quasi in den Schwanz, falls die zu verwendenden Fremdschlüssel noch nicht in den anderen Tabellen enthalten sind. Soll beispielsweise ein neuer Datensatz in HauptTabelle eingefügt werden, der auf einen erst noch einzufügenden Datensatz in UnterTabelle verweisen soll, würde diese Einfügung wegen der Verletzung der Fremdschlüsselbedingung zurückgewiesen. Wenn zuerst die Einfügung in UnterTabelle versucht würde, hätte dies ebenfalls eine Verletzung der Fremdschlüsselbedingung zur Folge. Dieses Problem kann dadurch gelöst werden, dass bei Einfügungen zunächst die Überprüfung der Fremdschlüsselbedingung außer Kraft gesetzt wird (über die DEFERRED-Klausel). Dazu muss diese natürlich einen Namen haben (siehe Beispiel 7.34). Beispiel 7.34: Lösung für die Einfügeoperation bei zyklischen Verweisen SET CONSTRAINTS VerweisUnterTabelle DEFERRED; INSERT INTO HauptTabelle ... ... INSERT INTO HauptTabelle ... INSERT INTO UnterTabelle ... ... INSERT INTO UnterTabelle ... SET CONSTRAINTS VerweisUnterTabelle IMMEDIATE; 7.2.4.3
Behandlung von Integritätsverletzungen
Sofern keine Reparaturmaßnahmen festgelegt wurden, wird eine SQL-Anweisung, die gegen eine Zusicherung verstößt, nicht ausgeführt. Der entsprechende Verstoß kann über eine Statusvariable abgefragt werden. Wird eine Integritätsverletzung erst nach Durchführung einer entsprechenden Aktion festgestellt, beispielsweise weil die Überprüfung der Integritätsbedingungen über den DEFERRED-Befehl verzögert wurde, so wird die betroffene Transaktion über einen ROLLBACK-Befehl vollständig zurückgesetzt30 und muss gegebenenfalls von der Anwendung unter veränderten Bedingungen neu gestartet werden. Um solche Probleme zu verhindern, kann es sinnvoll sein, vor dem Transaktionsende über den entsprechenden Befehl (SET CONSTRAINTS ALL IMMEDIATE) eine explizite Überprüfung aller noch offenen Integritätsbedingungen zu erzwingen. Sollten dabei Integritätsverletzungen erkannt werden, könnten sie gegebenenfalls über den Aufruf entsprechender Fehlerprozeduren beseitigt werden. Bei Verletzung der referenziellen Integrität gibt es spezielle Reaktionsmöglichkeiten durch das System, auf die im Folgenden etwas genauer eingegangen werden soll. Die referenzielle Integrität ist vor allem dann bedroht, wenn in der Haupttabelle ein Primärschlüssel geändert oder eine komplette Zeile gelöscht wird, und zwar jeweils dann, wenn es in der Untertabelle mindestens eine Zeile gibt, welche den zu löschenden oder zu ändernden Primärschlüssel der Haupttabelle als Fremdschlüssel enthält. Die Reaktion auf solche Integritätsverletzungen kann explizit wie folgt definiert werden: 30 Auf
Transaktionen wird im entsprechenden Kapitel noch genauer eingegangen.
7.2 Die Datendefinitionssprache (DDL)
311
1. RESTRICT Es ist verboten, Zeilen zu ändern oder zu löschen, auf die noch von anderen Tabellen referenziert wird. Ein entsprechender Wunsch eines Benutzers wird vom DBMS zurückgewiesen. Konkret heißt das, dass beim Versuch, in der Haupttabelle eine Zeile zu löschen, auf die noch von einer Untertabelle verwiesen wird, keine Änderung in der Untertabelle durchgeführt wird. Da dann jedoch die referenzielle Integrität verletzt wäre – zu einem Eintrag in der Untertabelle existiert in der Haupttabelle kein Eintrag mehr –, wird auch die Operation auf der Haupttabelle zurückgewiesen. Der Benutzer hat jetzt die Chance, entweder die betroffenen Zeilen in der Untertabelle vorher „manuell“ zu löschen oder auf das Ändern bzw. Löschen in der Haupttabelle insgesamt zu verzichten. 2. CASCADE Wird eine Zeile in der Haupttabelle gelöscht, so werden automatisch (rekursiv) auch alle Zeilen in den betroffenen Untertabellen gelöscht. Dies entspricht einer sich fortpflanzenden Löschoperation. Wird ein Primärschlüssel geändert, so wird diese Änderung auch in den betroffenen Untertabellen nachgezogen. 3. SET NULL/DEFAULT In diesem Fall werden die betroffene(n) Fremdschlüsselspalte(n) entweder alle mit der Nullmarke oder mit den in der CREATE TABLE-Definition angegebenen Default(s) belegt. Vorausgesetzt wird bei der SET NULL-Option natürlich, dass für die Fremdschlüsselspalten weder die NOT NULL-Option gesetzt noch in der Tabellendeklaration ein Default für die Spalte spezifiziert wurde. 4. NO ACTION NO ACTION bedeutet, dass keine automatische Reaktion von Seiten des DBMS auf die durchgeführte Operation erfolgen soll. Es ist die Default-Reaktion, falls keine Reaktion spezifiziert wurde. Wie man Syntax 7.17 entnehmen kann, können jeweils für das Löschen und das Ändern eines Primärschlüssels einer Haupttabelle individuelle Reaktionen festgelegt werden.
7.2.5
Umgang mit Beziehungstypen
Das relationale Datenbankmodell unterstützt Beziehungstypen nicht direkt. Wie sie trotzdem (indirekt) modelliert werden können, wurde bereits ausführlich in Kapitel 4.2 diskutiert. Hier sollen diese Ausführungen deshalb nur kurz anhand von ausführlicheren Beispielen in Erinnerung gerufen werden. 1:1 Beziehung Eine 1:1-Beziehung kann grundsätzlich innerhalb einer Tabelle modelliert werden. Die Normalisierungstheorie schlägt normalerweise die Aufteilung der zwei Entitäten auf zwei Tabellen vor. Allerdings würde eine solche Aufteilung bedeuten, dass immer dann, wenn beide Entitäten im Zusammenhang gesehen werden sollen, eine kostenintensive Verbundoperation auszuführen ist. Deshalb muss in der Praxis hier manchmal ein Kompromiss gefunden werden, der bedeutet, dass dann Tabellen auch zwei Entitäten beschreiben können (siehe Beispiel 7.35 a.). Bei einer 1:1 Beziehung kann die Beziehung entweder nur in eine (siehe Beispiel 7.35 b.) oder in beide Richtungen (siehe Beispiel 7.35 c.) aufgebaut werden.
312
7 Die relationale Datenbanksprache SQL
Beispiel 7.35: Verschiedene Realisierungen von 1:1 Beziehungen a. 1:1 Beziehung innerhalb einer Tabelle realisiert In diesem Beispiel ist die 1:1 Beziehung innerhalb der Tabelle Mitarbeiter umgesetzt. CREATE TABLE mitarbeiterNr mitarbeiterName mitarbeiterVorname ..., automarke autotyp nummernschild ...;
Mitarbeiter ( AchtstelligeZahl PRIMARY KEY, VARCHAR(25) NOT NULL, VARCHAR(25), VARCHAR(25), VARCHAR(25), VARCHAR(9),
b. 1:1 Beziehung durch zwei Tabellen realisiert in eine Richtung In diesem Beispiel ist die 1:1 Beziehung nur vom Mitarbeiter zum Auto realisiert. CREATE TABLE Mitarbeiter ( mitarbeiterNr AchtstelligeZahl PRIMARY KEY, mitarbeiterName VARCHAR(25) NOT NULL, mitarbeiterVorname VARCHAR(25), auto VARCHAR(9) UNIQUE, ...) CONSTRAINT AutoFS FOREIGN KEY (auto) REFERENCES Auto(nummernschild) ON DELETE RESTRICT ON UPDATE CASCADE; ...; CREATE TABLE automarke autotyp nummernschild ...;
Auto ( VARCHAR(25), VARCHAR(25), VARCHAR(9) PRIMARY KEY,
c. 1:1 Beziehung durch zwei Tabellen realisiert in beide Richtungen In diesem Beispiel ist die 1:1 Beziehung in beide Richtungen realisiert. Die Mitarbeiter-Tabelle ist äquivalent zur Mitarbeiter-Tabelle in b. oben. CREATE TABLE automarke autotyp nummernschild mitarbeiterNr ...)
Auto ( VARCHAR(25), VARCHAR(25), VARCHAR(9) PRIMARY KEY, AchtstelligeZahl UNIQUE,
7.2 Die Datendefinitionssprache (DDL)
313
CONSTRAINT MitarbeiterFS FOREIGN KEY (mitarbeiterNr) REFERENCES Mitarbeiter ON DELETE RESTRICT ON UPDATE CASCADE;
1:n Beziehung Eine 1:n Beziehung kann grundsätzlich innerhalb der n-Tabelle über eine (Primar)schlüssel/ Fremdschüsselbeziehung in Richtung 1-Tabelle umgesetzt werden (siehe Beispiel 7.36). Soll die Richtung von der 1-Tabelle zur n-Tabelle gehen, so muss wie bei der n:m Beziehung eine Beziehungstabelle eingeführt werden. Beispiel 7.36: Realisierung einer 1:n Beziehung In diesem Beispiel wird unterstellt, dass ein Mitarbeiter genau einer Abteilung zugeordnet sein muss. Deshalb wird von Mitarbeiter auf die Abteilung verwiesen. CREATE TABLE Mitarbeiter ( mitarbeiterNr AchtstelligeZahl PRIMARY KEY, mitarbeiterName VARCHAR(25) NOT NULL, mitarbeiterVorname VARCHAR(25), ..., abteilungsNr DreistelligeZahl NOT NULL) CONSTRAINT MitarbeiterFS FOREIGN KEY (abteilungsNr) REFERENCES Abteilung ON DELETE RESTRICT ON UPDATE CASCADE; CREATE TABLE abteilungsNr abteilungsName ...;
Abteilung ( DreistelligeZahl PRIMARY KEY, VARCHAR(25) UNIQUE NOT NULL,
n:m Beziehung Bei einer n:m Beziehung muss grundsätzlich eine sogenannte Beziehungstabelle angelegt werden (siehe Beispiel 7.37). Diese Beziehungstabelle erbt die Primärschlüssel1 beider zu Grunde liegenden Tabellen und kann zusätzlich noch weitere Beziehungsattribute beinhalten. In Beispiel ist istBestand ein solches Beziehungsattribut. Beispiel 7.37: Realisierung einer n:m Beziehung In diesem Beispiel lagern n Produkte in m Produktlagern und m Produktlager enthalten n Produkte. Die Beziehungstabelle ist ProduktLagertIn. Aus ProduktLager wird der Primärschlüssel produktLagerNr übernommen, aus Produkt produktNr. produktLagerBez ist hier
314
7 Die relationale Datenbanksprache SQL
eigentlich redundant angelegt, ermöglicht es aber, bei einem Zugriff auf produktLagertIn die Lagerbezeichnung zu bekommen, ohne eine Verbundoperation mit ProduktLager durchführen zu müssen. Diese effizienzsteigernde Maßnahme hätte man auch mit produktBez durchführen können. CREATE TABLE produktNr produktBez ...;
Produkt ( FünfstelligeZahl PRIMARY KEY, VARCHAR(25) UNIQUE NOT NULL,
CREATE TABLE ProduktLagertIn ( produktLagerNr FünfstelligeZahl, produktLagerBez VARCHAR(25), produktNr FünfstelligeZahl, istBestand SMALLINTNOT NULL CHECK VALUE≥ 0) CONSTRAINT ProduktLagertInPS PRIMARY KEY (produktLagerNr, produktNr), CONSTRAINT ProduktLagertInFS1 FOREIGN KEY (produktLagerNr) REFERENCES ProduktLager ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT ProduktLagertInFS2 FOREIGN KEY (produktNr) REFERENCES Produkt ON DELETE CASCADE ON UPDATE CASCADE; CREATE TABLE produktLagerNr produktLagerBez ...;
7.2.6
ProduktLager ( FünfstelligeZahl PRIMARY KEY, VARCHAR(25) UNIQUE,
Ändern des Datenbankschemas
Da sich der einem konzeptuellen Schema zu Grunde liegende Realweltausschnitt im Laufe der Zeit ändern kann, muss es möglich sein, solche Änderungen in der DB nachzuziehen. Diesem Zweck dienen der ALTER TABLE- und der ALTER DOMAIN-Befehl. Syntax 7.18: Tabellenaufbau ändern TabelleÄndern ::= ALTER TABLE TabellenName {ADD [COLUMN] (SpaltenName: Datentyp [SpaltenBezogeneEinschränkungen]) ADD TabellenBezogeneEinschränkungen | ALTER [COLUMN] (SpaltenName: {SET Default-Klausel | DROP DEFAULT}) DROP [COLUMN] SpaltenName {CASCADE | RESTRICT} DROP CONSTRAINT NameEinschränkung {CASCADE | RESTRICT}}
7.2 Die Datendefinitionssprache (DDL)
315
Neue Spalten werden grundsätzlich am Ende der Tabelle eingefügt. Änderungen von Spalteneigenschaften sind nur sehr eingeschränkt möglich. Im Wesentlichen kann der Default neu definiert oder weggelassen werden. Über das Hinzufügen tabellenbezogener Integritätsbedingungen lassen sich zudem neue Fremdschlüssel- und/oder Schlüsselkandidaten hinzufügen. Solche Änderungen können aber nur dann durchgeführt werden, falls alle aktuellen Zeilen der Tabelle die neuen Bedingungen erfüllen. Dies bedeutet insbesondere, dass bei Einfügung eines neuen Fremdschlüssels alle Werte der entsprechenden Spalte(n) auch mindestens als Schlüsselkandidat in der Haupttabelle existieren müssen. Die CASCADE- und RESTRICT-Option werden beim DROP-Befehl erläutert. Beispiel 7.38: Tabellen ändern 1. Der folgende Befehl löscht die Spalte produktLagerBez der Tabelle ProduktLagertIn, falls produktLagerBez in keiner anderen Tabelle Fremdschlüssel oder Bestandteil eines Fremdschlüssels ist: ALTER TABLE ProduktLagertIn DROP COLUMN produktLagerBez RESTRICT; 2. Der folgende Befehl überprüft die Spalte qualität daraufhin, ob ihre Werte dem spezifizierten Wertebereich entstammen: ALTER TABLE ProduktLagertIn ALTER COLUMN qualität CHAR(8) CHECK (VALUE IN (’sehr gut’, ’gut’, ’mittel’, ’schlecht’)); 3. Der folgende Befehl fügt die Spalte qualität in die Tabelle ProduktLagertIn ein und legt dafür einen Default fest: ALTER TABLE ADD COLUMN
ProduktLagertIn qualität CHAR(8) SET DEFAULT ’mittel’;
4. Der folgende Ausdruck drückt die CHECK-Klausel von 2. durch eine eigenständige Integritätsbedingung aus: ALTER TABLE ProduktLagertIn ADD CONSTRAINT QualitätsEinschränkung CHECK (qualität IN (’sehr gut’, ’gut’, ’mittel’, ’schlecht’)); Syntax 7.19: Wertebereichdefinition ändern WertebereichÄndern ::= ALTER DOMAIN WertebereichName {SET DEFAULT-Klausel | DROP DEFAULT} ADD WertebereichEinschränkung | DROP CONSTRAINT NameEinschränkung}
316
7 Die relationale Datenbanksprache SQL
Änderungen auf einem Wertebereich sind auch nur sehr eingeschränkt möglich. Ebenso wie bei Spalten kann der Basisdatentyp eines Wertebereiches nicht verändert werden. Eine solche Änderung ist auch nicht sinnvoll, da dadurch alle Spaltenwerte, die auf dem alten Datentyp des Wertebereiches beruhen, ungültig würden. Dies entspricht einem Löschen des Wertebereiches (der Spalte) und anschließender Neuanlage. Beispiel 7.39: Wertebereichänderungen 1. Die Integritätsbedingung „Typeinschränkung“ des Wertebereiches „BustypDomain“ wird entfernt. ALTER DOMAIN BustypDomain DROP CONSTRAINT Typeinschränkung; 2. Eine neue Integritätsbedingung „NeueTypeinschränkung“ wird zum Wertebereich „BustypDomain“ hinzugefügt. ALTER DOMAIN BustypDomain ADD CONSTRAINT NeueTypeinschränkung CHECK (VALUE IN (SELECT DISTINCT Bustyp FROM Busbeschreibung)); 3. Die Festlegung eines Defaults für den Wertebereich „BustypDomain“ wird entfernt. ALTER DOMAIN DROP DEFAULT;
BustypDomain
4. Für den Wertebereich „BustypDomain“ wird ein (neuer) Default eingeführt. ALTER DOMAIN BustypDomain SET DEFAULT ’D’; Alle Objekte, die in der DB angelegt wurden, können mit Hilfe des DROP-Befehls gelöscht werden. Auch hier ist darauf zu achten, dass die referenzielle Integrität nicht verletzt wird. Soll beispielsweise eine Haupttabelle gelöscht werden, auf die über Fremdschlüssel von Untertabellen verwiesen wird, kann über die CASCADE-Option festgelegt werden, dass automatisch auch alle betroffenen Zeilen in den Untertabellen gelöscht werden31 . Ist die RESTRICTOption aktiviert, wird der DROP-Befehl zurückgewiesen, falls es noch Untertabellen gibt, die über einen Fremdschlüssel auf die zu löschende Tabelle verweisen. Analoge Ausführungen gelten für die anderen Datenbankobjekte. Lediglich eine Zusicherung kann direkt gelöscht werden, da kein Datenbankobjekt auf sie verweisen kann. Syntax 7.20: Datenbankobjekt löschen DatenbankLöschen ::= {DROP DatenbankObjekt {CASCADE | RESTRICT } | DROP ASSERTION NameZusicherung} DatenbankObjekt ::= {DOMAIN | TABLE | VIEW | SCHEMA}32 31 In der Regel werden damit auch alle Zeilen der Untertabelle gelöscht, da normalerweise jede Zeile der Untertabelle über einen Fremdschlüssel auf die Haupttabelle verweist.
7.2 Die Datendefinitionssprache (DDL)
317
Über den DROP-Befehl werden die Datenbankobjekte vollständig aus der DB entfernt, d. h. inklusive aller zum Objekt gehörenden Schemabeschreibungen. Auf eine Tabelle bezogen bedeutet das, dass der Tabelleninhalt, die Tabellendefinition und alle für die Spalten der Tabelle angelegten Zugriffspfade gelöscht werden. Beispiel 7.40: Löschen von Datenbankobjekten 1. Diese Operation entfernt den Wertebereich FünfstelligeZahl genau dann aus der DB, wenn es keine Tabellendefinition mehr gibt, die sich auf diesen Wertebereich abstützt. DROP DOMAIN
FünfstelligeZahl RESTRICT;
2. Soll eine Tabelle samt Inhalt vollständig aus der DB entfernt werden, so geschieht das auch über den DROP-Befehl. Hier ist natürlich die Angabe von CASCADE oder RESTRICT weder sinnvoll noch möglich. DROP TABLE
Mitarbeiter;
Alternativ zum DROP-Befehl existiert der DELETE-Befehl. Mit seiner Hilfe kann man nur die aktuellen Ausprägungen eines Datenbankobjektes löschen, wobei die eigentliche Strukturbeschreibung und alle anderen Informationen erhalten bleiben. Auf eine Tabelle angewendet, würde er deren Zeilen vollständig löschen, die Tabellendefinition und etwaige Zugriffspfaddefinitionen (nur die Definitionen, nicht bestehende Inhalte!) allerdings unberührt lassen. Auf diesen Befehl wird später im Zusammenhang mit der DML noch eingegangen.
7.2.7
Beispiel eines Datenbankschemas für eine Unternehmung
Das folgende konzeptuelle Datenbankschema ist eine mögliche Umsetzung des in Kapitel 4.3, Beispiel 4.12 vorgestellten ER-Modells unserer Beispielunternehmung. Man beachte, dass viele Tabellen nur verkürzt dargestellt sind, was heißt, dass sie bei einem konkreten Schema deutlich mehr Spalten enthalten würden. Auch ist das Schema insofern unvollständig, als das weder Zugriffsrechte noch Sichten noch Zugriffspfade33 spezifiziert sind. CREATE SCHEMA Unternehmensdatenbank; /* Definition von Wertebereichseinschränkungen CREATE DOMAIN Statustyp AS VARCHAR(20) CONSTRAINT Statustyp CHECK (VALUE IN (’aktiv’, ’beurlaubt’, ’freigestellt’, ’krank’, ’Mutterschaftsurlaub’)); CREATE DOMAIN DreistelligeZahl AS SMALLINT CONSTRAINT Dreistellig CHECK (VALUE BETWEEN 100 AND 999); 32 Sichten (Views) und Zusicherungen (Assertions) werden in Kapitel 7.5 bzw. 7.8 noch genauer eingeführt. Sichten stehen für eine logische (virtuelle) Tabelle, während Zusicherungen Integritätsbedingungen auf Schemaebene darstellen. 33 Diese drei Konzepte wurden noch nicht eingeführt; deshalb werden Beispiele später ergänzt.
318
7 Die relationale Datenbanksprache SQL
CREATE DOMAIN FünfstelligeZahl AS INTEGER CONSTRAINT Fünfstellig CHECK (VALUE BETWEEN 10000 AND 99999); CREATE DOMAIN AchtstelligeZahl AS INTEGER CONSTRAINT Achtstellig CHECK (VALUE BETWEEN 10000000 AND 99999999); CREATE DOMAIN PositiveReal AS DECIMAL(9,2) CONSTRAINT Positive CHECK (VALUE ≥ 0); /* Definition der Tabellen CREATE TABLE mitarbeiterNr mitarbeiterName mitarbeiterVorname geburtsDatum plz ort strasse hausNr gehalt einstellung
Mitarbeiter ( AchtstelligeZahl VARCHAR(25) VARCHAR(25), DATE CHAR(5), VARCHAR(25), VARCHAR(25), CHAR(5), PositiveReal DATE
PRIMARY KEY, NOT NULL, NOT NULL,
CHECK (VALUE BETWEEN 500 AND 10000), CHECK (einstellung>geburtsDatum + INTERVAL ’14’ YEAR), mitarbeiterStatus Statustyp DEFAULT ’aktiv’, abteilungsNr DreistelligeZahl NOT NULL) CONSTRAINT MitarbeiterFS FOREIGN KEY (abteilungsNr) REFERENCES Abteilung ON DELETE RESTRICT ON UPDATE CASCADE;
CREATE TABLE Abteilung ( abteilungsNr DreistelligeZahl PRIMARY KEY, abteilungsName VARCHAR(25) UNIQUE NOT NULL, budget PositiveReal CHECK (VALUE BETWEEN 100000 AND 10000000), mitarbeiterZahl SMALLINT CHECK (VALUE ≥ 0)) CONSTRAINT BudgetKontrolle CHECK ((budget/mitarbeiterZahl) BETWEEN 1000 AND 10000); CREATE TABLE ArbeitetAn ( abteilungsNr DreistelligeZahl, produktNr FünfstelligeZahl) CONSTRAINT ArbeitetAnPS PRIMARY KEY (abteilungsNr, produktNr), CONSTRAINT ArbeitetAnFS2 FOREIGN KEY (abteilungsNr) REFERENCES Abteilung ON DELETE RESTRICT ON UPDATE CASCADE,
7.2 Die Datendefinitionssprache (DDL)
319
CONSTRAINT ArbeitetAnFS1 FOREIGN KEY (produktNr) REFERENCES Produkt ON DELETE CASCADE ON UPDATE CASCADE; CREATE TABLE Produkt ( produktNr FünfstelligeZahl PRIMARY KEY, produktBez VARCHAR(25) UNIQUE NOT NULL, produktTyp VARCHAR(25) NOT NULL, stueckKosten PositiveReal NOT NULL, nettoPreis PositiveReal NOT NULL) CONSTRAINT VerlustVermeidung CHECK (nettoPreis>(stueckKosten∗1,5)); CREATE TABLE ProduktLagertIn ( produktLagerNr FünfstelligeZahl, produktLagerBez VARCHAR(25), produktNr FünfstelligeZahl, istBestand SMALLINT NOT NULL CHECK VALUE ≥ 0) CONSTRAINT ProduktLagertInPS PRIMARY KEY (produktLagerNr, produktNr), CONSTRAINT ProduktLagertInFS1 FOREIGN KEY (produktLagerNr) REFERENCES ProduktLager ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT ProduktLagertInFS2 FOREIGN KEY (produktNr) REFERENCES Produkt ON DELETE CASCADE ON UPDATE CASCADE); Die Spalte produktLagerBez ist ein schönes Beispiel für den Unterschied zwischen „Theorie“ und „Praxis“. Nach der Normalisierungstheorie muss sie eigentlich entfallen, da die Lagerbezeichnung in der Tabelle ProduktLager geführt wird (so wurden auch die (äquivalenten) Tabellen TeileLager und TeilLagertIn modelliert). Wenn aber häufig im Zusammenhang mit einem Zugriff auf die Tabelle ProduktLagertIn auch der Name des Lagers benötigt wird, ist es wesentlich effizienter, hier Redundanz zuzulassen (und gegen die Normalisierungstheorie zu verstoßen), als jedes Mal einen Verbund zwischen den Tabellen ProduktLagertIn und ProduktLager zu bilden. Bei solchen Entscheidungen ist natürlich auch die (potenzielle) Änderungshäufigkeit von Spaltenwerten zu berücksichtigen. Je geringer diese ist, desto eher kann auch eine redundante Speicherung in Erwägung gezogen werden. In unserem Beispiel ist die Änderungswahrscheinlichkeit sehr gering, weil Lagerbezeichnungen normalerweise nicht geändert werden. CREATE TABLE Zulieferer ( zuliefererNr AchtstelligeZahl PRIMARY KEY, zuliefererName VARCHAR(25) NOT NULL,
320
7 Die relationale Datenbanksprache SQL plz CHAR(5), ort VARCHAR(25), strasse VARCHAR(25), hausNr CHAR(5), bank VARCHAR(25), iban VARCHAR(25) NOT NULL, bic VARCHAR(12) NOT NULL, ansprechpartner VARCHAR(25), ansprechpartTelNr VARCHAR(15), CONSTRAINT Bankverbindung UNIQUE (iban, bic) NOT DEFFERABLE;
CREATE TABLE ProduktLager ( produktLagerNr FünfstelligeZahl PRIMARY KEY, produktLagerBez VARCHAR(25) UNIQUE, plz CHAR(5), ort VARCHAR(25), strasse VARCHAR(25), hausNr CHAR(5), CONSTRAINT TestProduktLager CHECK (produktLagerNr NOT IN (SELECT teileLagerNr FROM TeileLager)); CREATE TABLE Liefert ( zuliefererNr AchtstelligeZahl, teilNr FünfstelligeZahl, produktNr FünfstelligeZahl) CONSTRAINT LiefertPS PRIMARY KEY (zuliefererNr, teilNr), CONSTRAINT LiefertFS1 FOREIGN KEY (zuliefererNr) REFERENCES Zulieferer ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT LiefertFS2 FOREIGN KEY (teilNr) REFERENCES Teil ON DELETE CASCADE ON UPDATE CASCADE), CONSTRAINT LiefertFS3 FOREIGN KEY (produktNr) REFERENCES Produkt ON DELETE SET NULL ON UPDATE CASCADE; CREATE TABLE teilNr teilBez
Teil ( FünfstelligeZahl PRIMARY KEY, VARCHAR(25) UNIQUE NOT NULL);
7.2 Die Datendefinitionssprache (DDL)
321
CREATE TABLE TeilLagertIn ( teileLagerNr INTEGER, teilNr FünfstelligeZahl, istBestand SMALLINT NOT NULL CHECK VALUE ≥ 0) CONSTRAINT TeilLagertInPS PRIMARY KEY (teileLagerNr, teilNr), CONSTRAINT TeilLagertInFS1 FOREIGN KEY (teilNr) REFERENCES Teil ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT TeilLagertInFS2 FOREIGN KEY (teileLagerNr) REFERENCES TeileLager ON DELETE CASCADE ON UPDATE CASCADE; CREATE TABLE TeileLager ( teileLagerNr INTEGER PRIMARY KEY, teileLagerBez VARCHAR(25) UNIQUE, plz CHAR(5), ort VARCHAR(25), strasse VARCHAR(25), hausNr CHAR(5)) CONSTRAINT TestTeileLager CHECK (teileLagerNr NOT IN (SELECT produktLagerNr FROM ProduktLager)); CREATE TABLE SindBestandteilVon ( teilNr FünfstelligeZahl, produktNr FünfstelligeZahl) CONSTRAINT SindBestandteilVonPS PRIMARY KEY (teilNr, produktNr), CONSTRAINT SindBestandteilVonFS1 FOREIGN KEY (teilNr) REFERENCES Teil ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT SindBestandteilVonFS2 FOREIGN KEY (produktNr) REFERENCES Produkt ON DELETE CASCADE ON UPDATE CASCADE; CREATE TABLE auftragsNr bearbeiterNr datum zuliefererNr
AuftragZulieferer ( INTEGER INTEGER DATE AchtstelligeZahl
PRIMARY KEY, NOT NULL, NOT NULL, NOT NULL)
322
7 Die relationale Datenbanksprache SQL CONSTRAINT AuftragZuliefererFS1 FOREIGN KEY (bearbeiterNr) REFERENCES Mitarbeiter(mitarbeiterNr) ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT AuftragZuliefererFS2 FOREIGN KEY (zuliefererNr) REFERENCES Zulieferer ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT Position CHECK (auftragsNr IN (SELECT DISTINCT auftragsNr FROM AuftragsPosition));
Hier werden nur die Aufträge an Lieferanten spezifiziert. Äquivalent dazu müssten noch die Aufträge von Kunden modelliert werden. Das Gleiche gilt für die Rechnungen. Auch da muss unterschieden werden zwischen denen von Lieferanten und denen an Kunden. Auch hier wird nur die Lieferantenseite explizit modelliert. Die Kundenseite ist sowohl bei den Aufträgen als auch den Rechnungen äquivalent und wird hier nicht explizit aufgeführt. CREATE TABLE AuftragsPosition ( auftragsNr INTEGER NOT NULL, auftragsPos INTEGER NOT NULL, menge SMALLINT NOT NULL CHECK VALUE>0, teilNr FünfstelligeZahl NOT NULL) CONSTRAINT AuftragsPositionPS PRIMARY KEY (auftragsNr, auftragsPos), CONSTRAINT AuftragsPositionFS FOREIGN KEY (auftragsNr) REFERENCES AuftragZulieferer ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT Position CHECK (auftragsNr IN (SELECT DISTINCT auftragsNr FROM AuftragZulieferer)); CREATE TABLE LieferantenRechnung ( rechnungsNr INTEGER PRIMARY KEY, datum DATE NOT NULL, zuliefererNr AchtstelligeZahl NOT NULL) CONSTRAINT LieferantenRechnungFS FOREIGN KEY (zuliefererNr) REFERENCES Zulieferer ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT Position CHECK (rechnungsNr IN (SELECT rechnungsNr FROM RechnungsPosition));
7.2 Die Datendefinitionssprache (DDL) CREATE TABLE RechnungsPosition ( rechnungsNr INTEGER, rechnungsPos INTEGER, menge SMALLINT NOT NULL CHECK VALUE>0, betrag PositiveReal NOT NULL, auftragsNr INTEGER NOT NULL, auftragsPos INTEGER NOT NULL) CONSTRAINT RechnungsPositionPS PRIMARY KEY (rechnungsNr, rechnungsPos), CONSTRAINT RechnungsPositionFS1 FOREIGN KEY (rechnungsNr) REFERENCES LieferantenRechnung ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT RechnungsPositionFS2 FOREIGN KEY (auftragsNr, auftragsPos) REFERENCES AuftragsPosition ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT Position CHECK (rechnungsNr IN (SELECT rechnungsNr FROM LieferantenRechnung)); CREATE TABLE Kunden ( kundenNr AchtstelligeZahl PRIMARY KEY, kundenName VARCHAR(25) NOT NULL, kundenVorname VARCHAR(25), plz CHAR(5), ort VARCHAR(25), strasse VARCHAR(25), hausNr CHAR(5), rabatt DECIMAL(4,2) DEFAULT 3, ansprechpartner VARCHAR(25), ansprechpartTelNr VARCHAR(15)); CREATE TABLE Kauft ( kundenNr AchtstelligeZahl NOT NULL, produktNr FünfstelligeZahl NOT NULL) CONSTRAINT KauftPS PRIMARY KEY (kundenNr, produktNr), CONSTRAINT KauftFS1 FOREIGN KEY (kundenNr) REFERENCES Kunden ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT KauftFS2 FOREIGN KEY (produktNr) REFERENCES Produkt ON DELETE CASCADE ON UPDATE CASCADE;
323
324
7.2.8
7 Die relationale Datenbanksprache SQL
Kontrollaufgaben
Die folgenden Aufgaben orientieren sich im Wesentlichen an der Vorgehensweise im Kapitel, d. h. ihr Schwierigkeitsgrad steigt von vorne nach hinten. Die Aufgaben sollen also insbesondere helfen, den bisher unerfahrenen SQL-Nutzer sukzessive an die Thematik heranzuführen. Aufgabe 7.1: BETWEEN-Prädikat „Welche Haltestellen werden in der Zeit von 8.00 bis 9.00 Uhr angefahren?“ Aufgabe 7.2: Simulation des BETWEEN-Prädikates „Stelle die Anfrage von Aufgabe 7.1 ohne Verwendung des BETWEEN-Prädikates.“ Aufgabe 7.3: IN-Prädikat „Welche Fahrten führen an den Haltestellen 18 oder 22 vorbei?“ Aufgabe 7.4: Simulation des IN-Prädikates „Formuliere die Anfrage aus Aufgabe 7.3 ohne Verwendung des IN-Prädikates.“ Aufgabe 7.5: LIKE-Prädikat „Gib alle Fahrer aus, deren letzter Buchstabe des Nachnamens ein s ist.“ Aufgabe 7.6: Wertebereichdefinition „Definiere einen Wertebereich Geschlechtstyp, der zur Aufnahme des Geschlechtsmerkmals der Fahrer geeignet ist.“ Aufgabe 7.7: Arbeiten mit benutzerdefinierten Wertebereichen „Erstelle eine Tabelle Fahrer, die (vorerst nur) die Spalten fahrerName, fahrerVorname und geschlecht enthält.“ Aufgabe 7.8: Wertebereichdeklaration mit Default „Definiere den Wertebereich aus Aufgabe 7.6 unter Verwendung eines Defaults.“ Aufgabe 7.9: Wertebereichdeklaration mit Integritätsbedingung „Definiere den Wertebereich aus Aufgabe 7.6 unter Verwendung einer Integritätsbedingung.“ Aufgabe 7.10: Dynamische Wertebereichfestlegung „Lege den Wertebereich der Spalte busNr der Tabelle Fahrt dynamisch fest.“ Aufgabe 7.11: SET CONSTRAINTS-Klausel „Durch die dynamische Wertebereichfestlegung von Aufgabe 7.10 kommt es zu einem Fehler, wenn ein neuer Bus für eine zusätzliche Fahrtroute eingekauft wurde und innerhalb einer Transaktion zunächst die neue Fahrtroute und danach der neue Bus für diese Fahrt eingegeben wird. Vermeide den Fehler durch Angabe einer entsprechenden SET CONSTRAINTSKlausel.“ Aufgabe 7.12: Anlegen einer Tabelle ohne Integritätsbedingungen „Lege eine Tabelle FahrtenZuHaltestellen an, in der Fahrtnummer, Haltestellennummer, Uhrzeit und Wochentag gespeichert werden können.“ Aufgabe 7.13: Über CHECK-Klausel realisierte NOT NULL-Spezifikation „Lege die Tabelle aus Aufgabe 7.12 an, wobei weder die Fahrtnummer noch die Haltestellennummer eine Nullmarke aufweisen darf.“
7.2 Die Datendefinitionssprache (DDL)
325
Aufgabe 7.14: Wertebereichseinschränkungen und Spaltenvorbelegungen „Lege die Tabelle aus Aufgabe 7.12 an mit einer max. dreistelligen Fahrtnummer und Haltestellennummer. Uhrzeiten dürfen nur zwischen 6.00 und 23.59 Uhr liegen. Gefahren wird außerdem an allen Tagen außer sonntags (So).“ Aufgabe 7.15: Anfrage als Wertebereichseinschränkung „Ändere die CHECK-Klausel für fahrtNr aus Aufgabe 7.14 so ab, dass durch eine Anfrage der Wertebereich für fahrtNr geeignet eingeschränkt wird, d. h. es sollen nur Werte vorkommen können, die auch in der Tabelle Fahrt enthalten sind.“ Aufgabe 7.16: CHECK-Klausel als Hilfsmittel zur Formatierung „Lege die Tabelle aus Aufgabe 7.14 an mit genau dreistelligen Fahrtnummern und Haltestellennummern.“ Aufgabe 7.17: CHECK-Klausel im Anschluss an die Deklarationen der Spalten „Lege die Tabelle aus Aufgabe 7.16 an, wobei die Angabe der CHECK-Klauseln erst nach der Deklaration der Spalten erfolgen soll.“ Aufgabe 7.18: Tabellenbezogene CHECK-Klausel „Die Fahrer bekommen zusätzlich zum Gehalt monatlich C 200,– je Kind. Insgesamt darf dieser Wert jedoch nicht C 3.500,– übersteigen. Formuliere eine entsprechende CHECK-Klausel für die Tabelle Fahrer.“ Aufgabe 7.19: Primärschlüssel und Schlüsselkandidaten „Lege die Tabelle Fahrt unter Angabe des Primärschlüssels an.“ Aufgabe 7.20: Fremdschlüssel 1. „Lege die Tabelle Fahrt unter Angabe des Primärschlüssels und des Fremdschlüssels mit Verweis auf die Tabelle Bus an.“ 2. Was bewirkt in der obigen FOREIGN KEY-Klausel eine zusätzliche Klausel ON UPDATE CASCADE? 3. Was würde die Klausel ON UPDATE SET NULL bewirken? 4. Wie verhält es sich mit ON UPDATE RESTRICT? 5. Wie verhält es sich mit ON DELETE CASCADE? Aufgabe 7.21: Tabellen ändern Entfernen Sie die Spalte uhrzeit aus der Tabelle FahrtenZuHaltestellen. Fügen Sie die Spalte wieder in die Tabelle ein, wobei als Default 0.00 Uhr verwendet werden soll. Aufgabe 7.22: Wertebereichänderungen „Ändere den Default des Wertebereiches Geschlechtstyp von männlich auf weiblich.“ Aufgabe 7.23: Löschen von Datenbankobjekten 1. „Lösche den Wertebereich Geschlechtstyp, falls dieser nicht mehr in der DB verwendet wird.“ 2. „Lösche die Tabelle Fahrer aus der DB.“
326
7 Die relationale Datenbanksprache SQL
haltestellenName startet haltestellenNr
linieNr N
1 M
M
Haltestelle
N
stopt
1
Linie
1
N endet
uhrzeit hält
liegtAuf
tag
kinderAnzahl
gehalt
geschlecht
N N
N
Fahrt
1
fährt
Fahrer
einstellungsdatum unfälle
fahrtNr
1 busNr
fahrerNr
Bus
fahrerName
gebDatum fahrerV orname
tüv kaufdatum garantie
Abb. 7.5: ER-Diagramm Nahverkehr
Aufgabe 7.24: Schemaentwurf Entwerfen Sie auf der Basis des in Abbildung 7.5 dargestellten ER-Diagramms ein konzeptuelles Datenbankschema für den Nahverkehr. Das Schema soll dabei die Entitäten Bus, Fahrer, Fahrt, Linie und Haltestellen widerspiegeln. Dabei kann ein Bus mehreren Fahrten zugeordnet sein, wobei auch Fahrer üblicherweise mehrere Fahrten absolvieren. Auch kann es vorkommen, dass dieselbe Fahrt von mehreren, sich ablösenden Fahrern durchgeführt wird. Eine Fahrt (Linie) fährt eine Anzahl Haltestellen an, wobei Haltestellen mehreren Fahrten (Linien) zugeordnet sein können. Pro Linie gibt es eine Start- und eine Endhaltestelle, wobei eine Haltestelle Start- oder Endhaltestelle von mehreren Linien sein kann.
7.3
Die Datenbankanfragesprache (DRL)
Ähnlich wie im Tabellenkalkül bereits diskutiert, kann man sich eine einfache Anfrage an eine DB in SQL wie folgt vorstellen: 1. Spezifikation der Tabelle, auf die sich die Anfrage bezieht (Ausgangstabelle). 2. Spezifikation der Bedingungen, die die Zeilen der Ausgangstabelle erfüllen müssen, damit sie in die Ergebnistabelle übernommen werden (Selektion). 3. Auswahl der Spalten, die der Ergebnistabelle angehören sollen.
7.3 Die Datenbankanfragesprache (DRL)
327
Dies ist nur eine sehr abstrakte Betrachtung einer Anfrage. Reale Anfragen können erheblich komplexer aufgebaut sein. Trotzdem wird damit der prinzipielle Aufbau, also das Grundgerüst einer Anfrage sehr gut beschrieben. Eine SQL-Anfrage entspricht einem SELECT-FROMWHERE-Block, der verkürzt als SFW-Block bezeichnet wird. Im FROM-Teil wird die Tabelle aufgebaut, auf der die Anfrage ausgeführt werden soll. Dabei muss sich eine Anfrage keineswegs auf eine Basistabelle beziehen. Vielmehr kann über Verbundoperationen aus der Menge aller Basistabellen eine beliebig komplexe Ausgangstabelle kreiert werden. Im WHERE-Teil werden die Bedingungen festgelegt, die die Datensätze der Ausgangstabelle erfüllen müssen, damit sie in die Ergebnistabelle übernommen werden. Schließlich beschreibt die SELECTKlausel den Aufbau der Ergebnistabelle34, entspricht also in ihrer Semantik einer Projektion, ausgeführt auf der Ausgangstabelle35. Die logische Abarbeitung eines SFW-Blockes sollte man sich im Sinn dieser Diskussion in der Reihenfolge FROM-WHERE-SELECT vorstellen. Syntax 7.21: Basissyntax einer SQL-Anfrage SFW-Block ::= SELECT FROM [WHERE
ErgebnisTabelle AusgangsTabelle KomplexesPrädikat]
Beispiel 7.41: Einfache SQL-Anfrage „Welche Mitarbeiter wurden vor dem 01.01.1965 eingestellt? Gib die Mitarbeiternummer, den Namen und das Einstellungsdatum aus.“ SELECT FROM WHERE
mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, einstellung Mitarbeiter einstellung < DATE ’1965-01-01’;
7.3.1
Die SELECT-Klausel (Projektion)
7.3.1.1
Basissyntax
Die einfachste Form einer Anfrage sieht wie folgt aus: Syntax 7.22: Einfachste Form einer Anfrage EinfacherSQL-Block ::= SELECT ErgebnisTabelle FROM AusgangsTabelle 34 Die SELECT-Klausel dient also nicht, wie man vielleicht aufgrund des Namens annehmen könnte, der Spezifikation der Selektionsbedingung. 35 Diese Sichtweise des Aufbaus einer SQL-Anfrage hat als grobe Richtschnur durchaus ihre Berechtigung. Im Detail kann es allerdings auch davon abweichende Varianten geben, die im Laufe dieses Kapitels noch diskutiert werden.
328
7 Die relationale Datenbanksprache SQL
Beispiel 7.42: Einfachste Form einer Anfrage „Gib alle Informationen über alle Mitarbeiter/innen aus.“ SELECT FROM
∗ Mitarbeiter;
Eine solche Anfrage gibt alle Zeilen der Ausgangstabelle in der in ErgebnisTabelle spezifizierten Form aus. Aufgabe 7.39 stellt dabei die einfachste Form einer Anfrage dar, da die Ergebnistabelle im Aufbau (und Inhalt) der Ausgangstabelle entspricht. ∗ ist eine verkürzte Form und drückt aus, dass alle Spalten der Ausgangstabelle ausgegeben werden sollen. Damit wird das eigentlich notwendige explizite Auflisten aller Spalten vermieden. Bei einer echten Projektion wird in der SELECT-Klausel angegeben, welche Spalten der Ausgangstabelle die Ergebnistabelle ausweisen soll. Werden durch die Projektion auch Spalten der Schlüsselkandidaten und des Primarschlüssels ausgeblendet, besteht eine hohe Wahrscheinlichkeit, dass die Ergebnistabelle einige Zeilen mehrfach enthält. Syntax 7.23: Vollständige Syntax der SELECT-Klausel SELECT-Klausel ErgebnisTabelle SelectSubliste SpaltenReferenz
::= SELECT ErgebnisTabelle ::= [{ALL| DISTINCT}]{∗|SelectSubliste[, SelectSubliste]∗ } ::= {SpaltenReferenz | TabellenName.∗ } ::= {SpaltenName | SFW-Block | Ausdruck} [[AS] NeuerSpaltenName]
Ausdruck
::= {NumWertBerech | ZeichenWertBerechnung | BitketteWertBerechnung | DatumZeitWertBerechnung} ::= {Term | NumWertBerech{+ | −} Term} ::= {Faktor | Term {∗ | /} Faktor} ::= {SpaltenName | UnterAnfrage | Ausdruck | wertberechnendeFkt | AggregatFkt37 }
NumWertBerech36 Term Faktor
Eine Basistabelle einer DB darf keine Duplikate enthalten. Wie die obige Diskussion gezeigt hat, ist diese Eigenschaft für die Ergebnistabelle nicht unbedingt gewährleistet. Nur falls das Schlüsselwort DISTINCT angegeben wird, ist Duplikatfreiheit sichergestellt. Der Default ALL bewirkt, dass Duplikate erhalten bleiben, so dass standardmäßig eine Ergebnistabelle und keine -relation erzeugt wird. Aus diesem Grund gebrauchen wir im Zusammenhang mit SQL den Begriff Tabelle statt Relation. In der Literatur werden für Tabelle auch gelegentlich die Begriffe Bag oder Multimenge verwendet. 36 Die Möglichkeiten zur Berechnung eines Wertes sollen hier nur exemplarisch an numerischen Daten aufgezeigt werden. Für die anderen Datentypen wird auf entsprechende SQL-Handbücher verwiesen. Auch die weitere Verfeinerung von numerischen Ausdrücken gibt nur einen Überblick über wichtige Varianten, stellt aber keine umfassende Auflistung dar. 37 Aggregatfunktionen sind natürlich auch werterzeugende Funktionen, so dass sie eigentlich bereits unter dem entsprechenden Term subsumiert sind. Sie sind hier nur aus Gründen der Betonung noch einmal explizit aufgeführt worden.
7.3 Die Datenbankanfragesprache (DRL)
329
Wie Syntax 7.23 zu entnehmen ist, können neben der einfachen Aufzählung der auszugebenden Spaltennamen auch so genannte abgeleitete Spalten ausgegeben werden. Hierbei handelt es sich um virtuelle Spalten, die aus bestehenden Spalten durch Ausführung einer Operation berechnet werden, wobei als Ergebnis genau ein Wert eines der Basisdatentypen geliefert wird. Als Operation ist dabei neben einer normalen arithmetischen Berechnung (Ausdruck, siehe Beispiel 7.43, 2.)38 auch eine numerische Funktion39 oder sogar eine Unteranfrage (SFW-Block)40 möglich. Bei der Vorstellung der einfachen Variante der SELECT-Klausel wurde ∗ als Abkürzung für alle Spalten der Ausgangstabelle eingeführt. In Syntax 7.23 ist diese Variante noch etwas verfeinert worden. Sollen statt der gesamten Ausgangstabelle nur alle Spalten einer der daran beteiligten Basistabellen ausgegeben werden, so kann dies ausgedrückt werden, indem dem ∗ der entsprechende Tabellenname vorangestellt wird (TabellenName.∗). Bezeichnet TabellenName eine abgeleitete Ausgangstabelle41, so muss dieser in der FROM-Klausel ein Name42 zugewiesen worden sein (siehe Beispiel 7.43, 2.). Beispiel 7.43: Qualifizierter ∗ 1. „Gib die Daten aller Mitarbeiter und den Namen der Abteilung aus, in der sie arbeiten.“ SELECT FROM
Mitarbeiter.∗, abteilungsName Mitarbeiter NATURAL JOIN Abteilung;43
2. „Gib zu jedem Produkt die Produktdaten, den Lagerort und den Wert der auf Lager liegenden Menge, differenziert nach Stückkosten und Nettoverkaufswert aus.“ SELECT FROM
ProduktInformation.∗, istBestand ∗ stueckKosten AS herstellWert, istBestand ∗ nettoPreis AS verkaufsWert (Produkt NATURAL JOIN ProduktLagertIn NATURAL JOIN ProduktLager) AS ProduktInformation;
Neben dem „Qualifizierer“ gibt es noch den „Quantifizierer“ in Form des DISTINCT- und des ALL-Schlüsselwortes, über die festgelegt wird, ob Duplikate erlaubt sind. Beispiel 7.44: Ergebnistabelle mit und ohne Duplikate „Gib alle Produktbezeichnungen aus.“ 38 Diese
werden in Kapitel 7.3.1.3 noch genauer besprochen. gehören alle von SQL unterstützten Funktionen, die als Ergebnis einen numerischen Wert liefern. Beispiele sind Funktionen zur Berechnung der Länge einer Zeichen- oder Bitkette, Position einer Zeichenkette in einem Text usw. 40 Unteranfragen sind Anfragen, die in andere Anfragen eingebettet sind. Sie werden später noch genauer eingeführt (Kapitel 7.3.5). 41 Abgeleitete Tabellen sind Tabellen, die durch eine eigene Anfrage erst gebildet werden. Darauf wird noch in Kapitel 7.3.2 eingegangen. 42 Hierauf wird in Kapitel 7.3.2.7 eingegangen. 43 Auf den natürlichen Verbund wird in Kapitel 7.3.2.2 noch intensiver eingegangen. 39 Hierzu
330
7 Die relationale Datenbanksprache SQL
ALL produktTyp Produkt; ↑ ohne Duplikateliminierung
SELECT FROM
DISTINCT produktTyp Produkt; ↑ mit Duplikateliminierung
SELECT FROM
Sollten mehrere Produkte die gleiche Bezeichnung besitzen, so werden im Fall der linken Anfrage Produktbezeichnungen auch mehrfach ausgegeben, bei der rechten jedoch nur einmal.
Ein SFW-Block, der keine Duplikate zulässt, entspricht dem folgenden Ausdruck der relationalen Algebra: πattr1 ,attr2 ,...,attrn (σKomplexeBedingung (Relation1 × Relation2 × . . . . × Relationm )) Es mag vermutlich zunächst einmal etwas merkwürdig anmuten, dass Ergebnistabellen Duplikate enthalten dürfen. Es stellt sich die Frage, warum man eine solche eklatante Verletzung der Mengentheorie zulässt. Diese Frage ist nach wie vor Gegenstand hitziger Diskussionen in der Datenbankwelt. Wir werden sie später noch einmal diskutieren. Hier sollen für den Augenblick nur die beiden Pro-Argumente angeführt werden: 1. Die Abarbeitung einer Anfrage ohne Duplikateliminierung lässt sich wesentlich effizienter implementieren, da zur Duplikateliminierung die Ergebnistabelle sortiert werden müsste, was durchaus eine aufwändige Operation darstellt. 2. Wie wir noch sehen werden, unterstützt SQL die bereits im Zusammenhang mit der Relationenalgebra eingeführten Aggregatfunktionen. Diese können oft nur dann in der intendierten Art und Weise genutzt werden, wenn die Duplikate nicht entfernt werden.
Feststellung 7.4: Probleme mit der Formulierungsunabhängigkeit Bei der Diskussion der Eigenschaften, die man eigentlich von einer guten deskriptiven Anfragesprache erwarten würde (siehe Kapitel 6.3), wurde auch die Formulierungsunabhängigkeit als ein wünschenswertes Kriterium genannt. Nun besagt Punkt 1. von oben, dass eine Anfrage ohne DISTINCT-Anforderung effizienter abgearbeitet wird. Formulierungsunabhängigkeit würde nun heißen, dass der Optimierer eigentlich erkennen müsste, ob das Ergebnis einer Anfrage keine Duplikate enthalten kann, um garantieren zu können, dass trotzdem eine Anfrage mit DISTINCT-Anforderung nicht langsamer abgearbeitet wird als die äquivalente Anfrage ohne DISTINCT-Anforderung. Dies kann der Optimierer im Allgemeinen natürlich nicht leisten, weshalb Anfragen i. d. R. schneller ausgeführt werden, wenn der Benutzer das Schlüsselwort DISTINCT immer dann weg lässt, wenn er sich sicher ist, dass das Ergebnis sowieso keine Duplikate enthalten kann. Dies gilt beispielsweise immer, wenn in der Ergebnistabelle noch ein vollwertiger Schlüssel enthalten ist.
7.3 Die Datenbankanfragesprache (DRL) 7.3.1.2
331
Benennung von Spalten
Wie später noch ausführlicher gezeigt wird, erlaubt SQL den Einsatz von arithmetischen Ausdrücken und Aggregatfunktionen in der SELECT-Klausel. Dadurch können aus bereits bestehenden Spalten neue abgeleitet werden. Damit diese Spalten in der Ergebnistabelle verständlich dargestellt werden können, besteht die Möglichkeit, ihnen über die AS-Klausel einen Namen, auch Aliasname genannt, zuzuweisen. Syntax 7.24: AS-Klausel AS-KlauselBeiSpalten ::= SELECT SpaltenReferenz1 [AS] NeuerSpaltenName1 [, SpaltenReferenzn [AS] NeuerSpaltenNamen]∗ FROM AusgangsTabelle Wie man der Syntaxdefinition entnehmen kann, ist das AS-Schlüsselwort nur optional, kann also auch weggelassen werden. Beispiel 7.45: Benennung von abgeleiteten Spalten „Gib alle Mitarbeiter und ihre Betriebszugehörigkeit aus.“ Variante 1: mit AS SELECT mitarbeiterName, (CURRENT_DATE-einstellung) AS betriebszugehörigkeit FROM Mitarbeiter; Variante 2: ohne AS SELECT mitarbeiterName, (CURRENT_DATE-einstellung) betriebszugehörigkeit FROM Mitarbeiter; Wird kein Name zugewiesen, vergibt das DBMS einen. Dieser ist dann jedoch implementierungsabhängig. Als Konsequenz wird häufig eine wenig aussagekräftige Zeichenkombination präsentiert, die beim Anwender höchstens ein großes Fragezeichen hinterlässt. Natürlich ist es auch möglich, bestehende Namen durch solche zu ersetzen, die der gegebenen Situation besser entsprechen (siehe Beispiel 7.46). Der Umbenennung sind im Prinzip keine Grenzen gesetzt. Beispiel 7.46: Umbenennung von Spalten „Gib alle Mitarbeiter, die noch keine zwei Jahre im Unternehmen tätig sind, zusammen mit ihrer Betriebszugehörigkeit aus.“ SELECT FROM WHERE
mitarbeiterName AS neueMitarbeiter, (CURRENT_DATE-einstellung) AS betriebszugehörigkeit Mitarbeiter CURRENT_DATE-einstellung < INTERVAL ’24’ MONTH;
332
7 Die relationale Datenbanksprache SQL
7.3.1.3
Arithmetische Ausdrücke
Normalerweise wird die Ergebnistabelle einer Anfrage aus der Ausgangstabelle durch Anwendung der Projektionsoperation erstellt. Sie setzt sich dann aus einer Teilmenge der Spalten der Ausgangstabelle zusammen. Es besteht aber auch die Möglichkeit, die Ergebnistabelle um zusätzliche Spalten zu erweitern, die entweder • durch Anwendung von arithmetischen Operationen aus den bereits bestehenden Spalten hergeleitet • oder über eine Aggregatfunktion aus (den Spalten) einer Zwischentabelle abgeleitet • oder durch eine eigene Unteranfrage berechnet werden. Mit diesem zusätzlichen Feature kann man jeder Anwendung ihre eigene Sicht auf die Daten zugestehen. Wenn beispielsweise bei einer weltweit operierenden Handelskette die jeweiligen Landesfilialen ihre Einkaufspreise in der Landeswährung dargestellt bekommen möchten, muss der in der DB abgelegte Einkaufspreis in der Basiswährung (zum Beispiel $) mit dem gültigen Wechselkurs multipliziert werden. Berechnungen dieser Art in der SELECT-Klausel werden durch SQL unterstützt. Statt eines einfachen Spaltennamens kann ein (beliebig komplexer) arithmetischer Ausdruck formuliert werden, über den der Wert der Spalte berechnet wird. Es ist sogar auch möglich, dass sich hinter solchen Berechnungen die Ausführung einer vollständigen SQL-Anfrage verbirgt, die pro Ergebniszeile der Hauptanfrage natürlich nur einen Wert liefern darf44. Solche Spalten, die sich in dieser Form nicht direkt im konzeptuellen Datenbankschema wiederfinden, sondern aus dort abgelegten Basisspalten berechnet werden, werden auch abgeleitete Spalten genannt. Um sie in der Ergebnistabelle auch geeignet präsentieren zu können, besteht die Möglichkeit, sie über die AS-Klausel mit einem sprechenden Namen zu versehen (siehe Kapitel 7.3.1.2). Beispiel 7.47: Arithmetische Ausdrücke in der SELECT-Klausel „Gib alle Mitarbeiter und ihr Alter aus.“ SELECT FROM
Mitarbeiter.∗45, (CURRENT_DATE–geburtsDatum) AS alter Mitarbeiter;
Da arithmetische Ausdrücke pro Zeile der Ergebnistabelle einen (zeilenspezifischen) Wert liefern, können sie mit den normalen, aus der Ausgangstabelle übernommenen Spalten kombiniert werden. Wie in Kapitel 7.3.1.4 noch genauer ausgeführt wird, liefern Aggregatfunktionen im Gegensatz dazu nur einen Wert pro Tabelle. Dieser kann deshalb nicht mit den normalen, zeilenbezogenen Werten kombiniert werden. 44 In
Kapitel 7.3.5 werden dafür Beispiele vorgestellt. neben allen Spalten einer Tabelle noch weitere Spalten ausgegeben werden, so muss die Abkürzung ∗ um den Tabellennamen erweitert werden. 45 Sollen
7.3 Die Datenbankanfragesprache (DRL)
333
Beispiel 7.48: Geeignete und ungeeignete Kombinationen von Spalten Unter der Voraussetzung, dass ein Mitarbeiter 13 Monatsgehälter bezieht, 500,– C Urlaubsgeld bekommt und an 220 Tagen im Jahr jeweils acht Stunden arbeitet, kann sein Stundenlohn über die folgende Anfrage ermittelt werden: SELECT FROM
Mitarbeiter.∗, (gehalt ∗ 13 + 500.00)/(220 ∗ 8) AS stundenlohn Mitarbeiter;
Soll das Durchschnittsgehalt aller Mitarbeiter berechnet werden, macht es sicherlich keinen Sinn, dieses zusammen mit den Mitarbeiterdaten auszugeben, da es keine Eigenschaft eines Mitarbeiters beschreibt und zudem dann sehr häufig wiederholt würde. SELECT FROM
Mitarbeiter.∗, AVG(gehalt) AS ∅ gehalt Mitarbeiter;
Die Tatsache, dass in der SELECT-Klausel arithmetische Ausdrücke, Aggregatfunktionen oder sogar geschachtelte SFW-Blöcke verwendet werden können, bedeutet, dass die Spalten der Ergebnistabelle nicht zwangsläufig Bestandteil der Ausgangstabelle sein müssen. Insofern muss die zu Beginn von Kapitel 7.2.8 gegebene Definition der Ergebnistabelle etwas erweitert werden. Eine Ergebnistabelle besteht nicht (nur) aus Spalten der Ausgangstabelle, sondern kann auch Spalten beinhalten, die sich aus den Spalten der Ausgangstabelle ableiten lassen. 7.3.1.4
Aggregatfunktionen
SQL unterstützt standardmäßig alle im Zusammenhang mit der Relationenalgebra bereits diskutierten Aggregatfunktionen. Aggregatfunktionen werden abhängig vom SQL-Dialekt bzw. -Anbieter auch Mengen-, Built-in-, Gruppen- oder Spaltenfunktionen genannt. Relationale Anfragesprachen bieten aus der Sicht der Programmierung nur eine eingeschränkte Mächtigkeit, da ihnen aus den in Kapitel 6.3 diskutierten Gründen (wie Einfachheit, Optimierbarkeit und sichere Anfragesprache) so wichtige Programmierkonstrukte wie Schleifenoperatoren fehlen. Aggregatfunktionen mildern dieses Manko ein wenig ab, indem sie einige aus der Sicht der Mengendatenverarbeitung wichtige Operationen darstellen. Dabei ist ein wesentlicher Vorteil, dass diese Operationen ins DBMS integriert werden und damit genau dort umgesetzt werden können, wo sie am effizientesten eingesetzt werden können. Daten, die direkt in dem DBS verarbeitet werden können, müssen nicht sämtliche Umformungen über sich ergehen lassen und durch sämtliche Puffer laufen, die auf dem Weg von der Platte bis zum Anwendungsprogramm zu durchlaufen sind. Syntax 7.25: Aggregatfunktionen Aggregatfkt ::= {COUNT(∗) | {AVG | COUNT | MAX | MIN | SUM} ([{ALL | DISTINCT}] Ausdruck)} Mit Ausnahme der COUNT-Funktion, die auch auf einer Tabelle ausgeführt werden kann, beziehen sich die Aggregatfunktionen genau auf eine Spalte einer Tabelle (siehe Tabelle 7.9). Als Default werden bei Aggregatfunktionen Duplikate immer in die Berechnungen mit einbezogen, können aber durch Angabe von DISTINCT ausgeschlossen werden.
334
7 Die relationale Datenbanksprache SQL
Name
Bezug
erwarteter Argumenttyp
Ergebnistyp
Semantik
COUNT()
Tabelle
keiner (∗)
numerisch
Anzahl von Zeilen der Ergebnistabelle
COUNT()
Spalte
beliebig(e Spalte)
numerisch
Anzahl der Zeilen, die bei der als Argumenttyp angegebenen Spalte einen Wert ungleich der Nullmarke aufweisen
SUM()
Spalte
numerisch
numerisch
Summe aller aktuellen Werte der Spalte
AVG()
Spalte
numerisch
numerisch
Durchschnitt aller aktuellen Werte einer Spalte
MAX()
Spalte
Zeichen / numerisch / chronologisch
wie Argumenttyp
höchster der Werte einer Spalte
MIN()
Spalte
Zeichen / numerisch / chronologisch
wie Argumenttyp
niedrigster der Werte einer Spalte
Tabelle 7.9: Aggregatfunktionen und ihre Semantik
Beispiel 7.49: COUNT-Funktion „Gib die Gesamtzahl der Mitarbeiter an.“ SELECT FROM
COUNT(mitarbeiterNr) AS anzahlMitarbeiter Mitarbeiter;
Beispiel 7.50: MAX-Funktion „Gib das höchste Gehalt eines Mitarbeiters aus.“ SELECT FROM
MAX(gehalt) AS höchstesGehalt Mitarbeiter;
Beispiel 7.51: MIN-Funktion „Wann wurde der erste und wann der letzte Mitarbeiter eingestellt?“ SELECT FROM
MIN(einstellung) AS ersteEinstellung, MAX(einstellung) AS letzteEinstellung Mitarbeiter;
Beispiel 7.52: SUM-Funktion „Wie hoch sind die monatlichen Gehaltsbelastungen?“ SELECT FROM
SUM(gehalt) AS monatlicheGehaltsBelastung Mitarbeiter;
7.3 Die Datenbankanfragesprache (DRL)
335
Beispiel 7.53: AVG-Funktion 1. „Wie hoch ist die Gewinnmarge über alle Produkte in unserem Unternehmen?“46 SELECT FROM
(AVG(nettoPreis)−AVG(stueckKosten))/AVG(nettoPreis) ∗ 100 AS ∅gewinnMarge Produkt;
oder SELECT FROM
((SUM(nettoPreis)−SUM(stueckKosten))/SUM(nettoPreis)∗ 100) AS ∅gewinnMarge Produkt;
2. „Welches ist der durchschnittliche Rabatt unserer Kunden?“ SELECT FROM
AVG(rabatt) AS ∅rabatt Kunden;
Gerade bei der letzten Anfrage kann man über den Wunsch des Anfragers spekulieren: Meint er den durchschnittlichen Rabatt über alle Kunden, also unter Einbeziehung der realen Gegebenheiten, oder den durchschnittlichen Rabatt auf einer abstrakteren Ebene, nämlich der Ebene der verschiedenen Rabattabstufungen. Im ersten Fall müssen alle Duplikate berücksichtigt werden, im zweiten Fall nicht. Beispiel 7.54 deckt die zweite Variante ab. Beispiel 7.54: Aggregatfunktion mit DISTINCT-Schlüsselwort SELECT FROM
AVG(DISTINCT rabatt) AS ∅rabatt Kunden;
Für alle spaltenbezogenen Aggregatfunktionen gilt, dass vor ihrer Ausführung zunächst alle Zeilen gestrichen werden, die in der angesprochenen Spalte mit der Nullmarke belegt sind. Dies ist auch wünschenswert, da ansonsten erhebliche Ergebnisverfälschungen möglich sind. Man führe sich nur vor Augen, was als Ergebnis herauskäme, wenn der Abteilungsleiter am Ende der Woche gerne wissen möchte, wie viele Stunden seine Mitarbeiter im Durchschnitt in dieser aktuellen Woche gearbeitet haben. Falls bei den 20 Mitarbeitern der Abteilung erst bei 14 die entsprechenden Daten vorhanden sind, so würde das Ergebnis dieser Anfrage vermutlich zu einer ungerechtfertigten Standpauke für die Mitarbeiter führen, falls nicht zunächst die Mitarbeiter aus der Berechnung gestrichen würden, für die noch keine aktuelle Gesamtwochenarbeitszeit eingetragen wurde. Die COUNT(∗)-Funktion arbeitet als einzige auf der Ebene der Tabelle und nicht von Spalten. Sie ermittelt die Gesamtzahl aller Zeilen, unabhängig davon, ob irgendwelche Spalten mit 46 Natürlich kann man diese Anfrage auch so interpretieren, dass zunächst die Gewinnmarge pro Produkt und basierend auf diesen Daten die durchschnittliche Gewinnmarge berechnet wird.
336
7 Die relationale Datenbanksprache SQL
der Nullmarke belegt sind. Damit liefern die COUNT(∗)- und die COUNT(SpaltenName)Funktion immer dann unterschiedliche Ergebnisse, falls SpaltenName das Auftreten einer Nullmarke nicht nur zulässt, sondern Nullmarken in der konkreten Situation auch wirklich vorkommen. Umgekehrt, falls der Primärschlüssel einer Tabelle aus genau einer Spalte besteht, kann die COUNT(∗)-Funktion gleichwertig durch die COUNT(Primärschlüssel)Funktion ersetzt werden. Feststellung 7.5: Anwendung von Aggregatfunktionen auf eine leere Menge Wird eine Aggregatfunktion auf eine leere Menge angewendet, so wird die Nullmarke zurückgeliefert, es sei denn, es handelt sich um die COUNT-Funktion. Dann wird als Ergebnis der Wert 0 ausgegeben. Betrachten wir noch einmal die COUNT-Funktion. Gelegentlich wird man auch gerne wissen wollen, wie viele unterschiedliche Werte für diese Spalte in der Ergebnistabelle vorhanden sind (siehe Beispiel 7.54). Dies ist eine andere als die bisher zu Grunde gelegte Semantik, bei der die Zeilen, die bei dieser Spalte einen Wert ungleich der Nullmarke aufweisen, gezählt werden. Um solche Anfragen ausführen zu können, wurde für die SUM-, COUNT- und AVG-Funktionen die Möglichkeit geschaffen, nur unterschiedliche Werte zu berücksichtigen. Dies geschieht durch Angabe des DISTINCT-Schlüsselwortes und ist damit analog zur Erzwingung der Eindeutigkeit von Zeilen auf der Ebene der Ergebnistabelle realisiert. Bei der COUNT-Funktion darf DISTINCT nur dann angegeben werden, wenn auf der Basis einer Spalte gearbeitet wird. Die (nicht überzeugende) Begründung für diese Einschränkung der Orthogonalität der Sprache lautet, dass die Eindeutigkeit von Zeilen auf der Ebene der Ergebnistabelle sowieso dadurch erreicht werden kann, dass man den DISTINCT-Operator auf der Ebene der SELECT-Klausel einsetzt, wodurch SELECT COUNT(DISTINCT ∗) äquivalent zu SELECT DISTINCT COUNT(∗) wäre.47 Beispiel 7.55: Gemeinsame Verwendung von DISTINCT-Klausel und Aggregatfunktion 1. „Wie viele unterschiedliche Produkttypen gibt es insgesamt?“ SELECT FROM
COUNT(DISTINCT produktTyp) AS anzahlProdukttypen Produkt;
2. „Wie viele Kunden hat das Unternehmen? Wie viele davon bekommen einen Rabatt und in wie vielen unterschiedlichen Wohnorten wohnen sie?“ SELECT
FROM 47 Gründe
COUNT(∗)48AS gesamtzahlKunden, COUNT(rabatt)49AS gesamtzahlKundenMitRabatt, COUNT(DISTINCT ort) AS anzahlWohnorte Kunden;
dieser Art für die Einschränkung von Orthogonalität können nicht überzeugen, da sie den Sinn und die Idee hinter der Orthogonalität aushöhlen. 48 Alternativ könnte hier auch COUNT(kundenNr) stehen. 49 Unter der Voraussetzung, dass bei Kunden ohne Rabatt die Nullmarke eingetragen ist; steht stattdessen dann bei Rabatt 0, muss diese Spalte über eine eigene Unteranfrage abgedeckt werden; diese wird jedoch erst später eingeführt.
7.3 Die Datenbankanfragesprache (DRL)
337
Die COUNT-Funktion deckt zwei Extreme ab: Entweder sollen alle Zeilen einer Tabelle oder alle (unterschiedlichen) Werte einer Spalte gezählt werden. Sollen jetzt die unterschiedlichen Werte über zwei Spalten gezählt werden, so könnte man auf die Idee kommen, das wie folgt zu formulieren: Beispiel 7.56: COUNT-Funktion über mehrere Spalten (nicht korrekte Lösung) Gegeben sei die folgende Tabelle: T(attr1 , attr2 , attr3 , attr4 ). Es soll die Anzahl der Zeilen gezählt werden, die in (attr2 , attr3 ) einen unterschiedlichen Wert aufweisen. Variante 1: SELECT FROM
DISTINCT attr2 , attr3 , COUNT(∗) T;
Im obigen Beispiel wurden attr2 und attr3 nur deshalb in die SELECT-Klausel aufgenommen, damit vor der Anwendung der COUNT-Funktion erst die durch die Anfrage geforderte Projektion durchgeführt wird. Es wird aber gleich noch gezeigt, dass eine solche Kombination von Spalten mit einem einzigen Wert unzulässig ist. Damit scheidet diese Lösung aus. Die korrekte Formulierung braucht den Einsatz einer Unteranfrage (siehe Beispiel 7.57). Beispiel 7.57: COUNT-Funktion über mehrere Spalten (korrekte Lösung) SELECT FROM
COUNT(SELECT DISTINCT attr2 , attr3 FROM T) T;
Die obige Lösung ist sicherlich etwas gewöhnungsbedürftig, da sie ein Beispiel für die eher seltenen Ausnahmen ist, bei denen die FROM-Klausel an sich unnötig ist. Wie Beispiel 7.58 demonstriert, kann die Anfrage auch lesbarer gestellt werden. Beispiel 7.58: Lesbarere Variante von Beispiel 7.57 SELECT FROM
COUNT(∗) (SELECT DISTINCT attr2 , attr3 FROM T);
Achtung 7.4: Verwendung der DISTINCT-Klausel bei der AVG- bzw. SUM-Funktion Obwohl prinzipiell zulässig, sollte man mit der Anwendung der DISTINCT-Klausel bei den AVG- und SUM-Funktionen vorsichtig sein. Gerade bei diesen Funktionen kann man sich sicherlich nur sehr selten eine Situation vorstellen, bei der der Durchschnitt oder die Summe der Werte einer Spalte nur auf der Ebene der unterschiedlichen und nicht aller Werte gebildet werden soll (siehe allerdings auch Beispiel 7.54). Achtung 7.5: Nullmarken und Aggregatfunktionen Bei den Aggregatfunktionen MAX, MIN, AVG, COUNT(SpaltenName) und SUM werden Spaltenwerte, die durch die Nullmarke belegt sind, nicht berücksichtigt. Diese Regel
338
7 Die relationale Datenbanksprache SQL
ist beim Bewerten von Anfragen unbedingt zu berücksichtigen. So ist es beispielsweise nicht unerheblich, ob aus einer großen Menge sehr viele oder nur sehr wenige Werte bekannt sind. So ist die Aussage, dass der durchschnittliche Verkauf eines bestimmten Produkts in einem bestimmten Monat über alle Filialen einer Warenhauskette bei der Zahl x liegt, sicherlich wenig aussagekräftig, wenn von tausend Filialen erst zehn die Verkaufszahlen geliefert haben. Wäre das Verhältnis genau andersherum, kann der gelieferte Durchschnittsverkauf dagegen als sehr realitätsnahe angesehen werden. Ähnliche Argumente treffen auch auf die drei anderen Aggregatfunktionen zu. Die obige Anmerkung gilt nicht für die COUNT(∗)-Funktion. Bei ihr werden immer alle Zeilen aufaddiert, welche die Bedingung der Anfrage erfüllen. Deshalb spielt die konkrete Belegung von Spalten nur bei der Auswertung der eigentlichen Anfragebedingung eine Rolle, nicht aber bei der Berechnung der COUNT(∗)-Funktion. 7.3.1.4.1
Probleme mit Aggregatfunktionen
Obwohl die Aggregatfunktionen die Mächtigkeit von SQL erhöhen, hat ihre Einführung auch Probleme mit sich gebracht. Ihre Existenz ist einer der Gründe, warum SQL bei Zwischentabellen die Eigenschaft der Duplikatfreiheit aufgibt. Auch bereitet das Zusammenspiel zwischen Nullmarken und Aggregatfunktionen einige Probleme, wie bei der Diskussion der Probleme von SQL (siehe Kapitel 7.9) noch gezeigt werden wird. Schließlich sei noch erwähnt, dass die Integration der Aggregatfunktionen in SQL nicht konsistent durchgeführt wurde. Diesbezügliche Probleme waren schon anhand der fehlenden Orthogonalität des DISTINCTSchlüsselwortes in der COUNT-Funktion diskutiert worden. Weitere Probleme sollen anhand von Beispiel 7.59 diskutiert werden. Beispiel 7.59: Zusammenspiel von Aggregatfunktionen und Spalten in der SELECT-Klausel „Gib pro Lager die Anzahl der dort gelagerten Produkte aus.“ In einem ersten Ansatz könnte man die Anfrage wie folgt (falsch) formulieren: SELECT FROM
produktLagerNr AS lagerNr, COUNT(produktNr) AS #produkte ProduktLagertIn;
Diese nahe liegende Formulierung der Anfrage ist falsch. Die COUNT-Funktion bezieht sich auf die gesamte Spalte, wird also all die Zeilen zählen, deren Spaltenwert ungleich der Nullmarke ist. Das von uns gewünschte Zählen der Produktnummern pro Lager lässt sich so nicht realisieren. Als Ergebnis der COUNT-Funktion wird ein Wert geliefert. Dem stehen eine Anzahl von Lagern gegenüber. Funktionieren würde die Anfrage, wenn die Ausgangstabelle auf der Basis der Lagerbezeichnungen in Untertabellen zerlegt werden könnte, um dann die COUNT-Funktion auf jede Untertabelle anzuwenden. Allerdings ist dieses Vorgehen, wie bereits in Beispiel 7.56 gesagt wurde, nicht erlaubt. Dieses Thema wird noch einmal in Kapitel 7.3.4 aufgegriffen werden. Dort wird auch die korrekte Lösung präsentiert. Es sei noch angemerkt, dass gute SQL-Interpreter das gemeinsame Auftreten von Aggregatfunktionen und normalen Spaltenwerten in der obigen Variante verbieten.
7.3 Die Datenbankanfragesprache (DRL)
7.3.2
339
Die FROM-Klausel (Ausgangstabelle)
In der FROM-Klausel wird spezifiziert, wie die Tabelle auszusehen hat, auf der die Anfrage ausgeführt werden soll. Insgesamt kann man sich die Ausgangstabelle am besten als eine Art Universaltabelle vorstellen, in der ohne Rücksicht auf die Normalisierungstheorie und damit auf Redundanzen alle Daten hinein gepackt werden, die für die Abarbeitung der Anfrage und Präsentation des Ergebnisses von Belang sind. Im einfachsten Fall ist die Ausgangstabelle identisch mit einer Basistabelle des Datenbankschemas (siehe Beispiel 7.60). Beispiel 7.60: Einfache FROM-Klausel „Erstelle eine Übersicht über alle Mitarbeiter mit Angabe ihres Gehaltes.“ SELECT FROM 7.3.2.1
mitarbeiterName, mitarbeiterVorname, gehalt Mitarbeiter;
Das Kartesische Produkt
Bei der gegenüber der einfachen Basistabelle komplexeren Variante wird die Ausgangstabelle mit Hilfe des Kartesischen Produktes aus mehreren Basistabellen zusammengesetzt. SQL-89 kennt nur diese beiden Grundvarianten (nur eine Basistabelle und das kartesische Produkt). Weitere Operationen zur Bildung der Ausgangstabelle, beispielsweise andere Verbundoperationen, stehen nicht zur Verfügung. SQL-92 hat hier erheblich zugelegt, indem sich jede Art von Verbundoperation direkt in der FROM-Klausel formulieren lässt.50 Das Kartesische Produkt kann entweder nach der alten Variante über Kommata (,) oder nach dem neuen Vorschlag über die Schlüsselwörter CROSS JOIN gebildet werden. Die erste Variante wird auch Verbund alter Art (old-style join) genannt und ist nach wie vor der State-of-theArt in vielen kommerziellen SQL-Dialekten. Bei neuen Releases ist jedoch eine zunehmende Tendenz zur Unterstützung auch der neuen Variante zu entdecken. Beispiel 7.61: Alte und neue Variante des Kartesischen Produktes „Gib zu jedem Auftrag an einen Zulieferer den verantwortlichen Bearbeiter an.“ alte Variante: SELECT auftragsNr, mitarbeiterName, mitarbeiterVorname FROM AuftragZulieferer, Mitarbeiter WHERE bearbeiterNr = mitarbeiterNr; neue Variante:51 SELECT auftragsNr, mitarbeiterName, mitarbeiterVorname FROM AuftragZulieferer CROSS JOIN Mitarbeiter WHERE bearbeiterNr = mitarbeiterNr; 50 Leider gilt dies nur für den Standard. Viele SQL-Dialekte ignorieren diese Möglichkeit, Anfragen sauber und lesbar zu gestalten, da sie aus der Sicht der Mächtigkeit keinen Fortschritt bringt. 51 Hier handelt es sich um einen Gleichverbund (vgl. Kapitel 7.3.2.3), der sich mit Hilfe von SQL-92 noch eleganter ausdrücken lässt, wie später noch gezeigt wird.
340
7 Die relationale Datenbanksprache SQL
Syntax 7.26: Kartesisches Produkt alt: AusgangsTabelle ::=Tabelle1 [, Tabellen ]∗ neu: AusgangsTabelle ::= Tabelle1 [CROSS JOIN Tabellen ]∗ SELECT ErgebnisTabelle FROM Tabelle1 [{, | CROSS JOIN} Tabellen ]∗ Tabellex , x ∈ {1, . . . , n} können beliebige Basistabellen sein. Dabei ist es irrelevant, ob in den zu verbindenden Basistabellen gleiche Spaltennamen enthalten sind. Sie werden alle vollständig in die neue Tabelle übernommen, wobei gleiche Spaltennamen aus Gründen der Eindeutigkeit um ihren Tabellennamen ergänzt werden. Beispiel 7.62: FROM-Klausel mit Kartesischem Produkt Ohne gleiche Spaltennamen: „Unter der Voraussetzung, dass jeder Lieferant jedes Teil liefern kann, soll eine Liste aller Teile und der (potenziellen) Zulieferer ausgegeben werden.“ SELECT FROM
zuliefererName, teilNr, teilBez Teil CROSS JOIN Zulieferer;
bildet die Ausgangstabelle (teilNr, teilBez, zuliefererNr, zuliefererName, plz, ort, strasse, hausNr, bank, iban, bic, ansprechpartner, ansprechpartTelNr) Mit gleichen Spaltennamen: „Gib die Namen aller Mitarbeiter aus, zusammen mit der Abteilung, in der sie arbeiten.“ SELECT FROM WHERE
mitarbeiterName, mitarbeiterVorname, abteilungsName Mitarbeiter CROSS JOIN Abteilung Mitarbeiter.abteilungsNr=Abteilung.abteilungsNr;
bildet die Ausgangstabelle (mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, geburtsDatum, ort, strasse, hausNr, plz, gehalt, einstellung, mitarbeiterStatus, Mitarbeiter.abteilungsNr, Abteilung.abteilungsNr, abteilungsName, budget, mitarbeiterZahl) „Preis“ des Kartesischen Produktes Das Verbinden mehrerer Tabellen mit Hilfe des Kartesischen Produktes mag auf den ersten Blick etwas umständlich und aufgebläht wirken. Es wird eine unnötig große Ausgangstabelle aufgebaut, die womöglich dann in eine eher kleine Ergebnistabelle überführt wird. Die theoretischen Dimensionen, mit denen hier operiert wird, kann man sehr schön an Beispiel 7.63 sehen. Unter der Voraussetzung, dass das Unternehmen aus 100 Abteilungen besteht, die 1000 Produkte herstellen, wobei im Durchschnitt jede Abteilung an 100 Produkten arbeitet, wird
7.3 Die Datenbankanfragesprache (DRL)
341
theoretisch zunächst eine 100 ∗ 1000 ∗ (100 ∗ 100)52) = 109 Zeilen große Ausgangstabelle erzeugt. Da Abteilung vier, Produkt fünf und ArbeitetAn zwei Spalten besitzt, umfasst jede Zeile der Ausgangstabelle elf Spalten. Unterstellen wir der Einfachheit halber eine konstante Größe aller Spalten von 15 Byte. Dann werden durch die Ausgangstabelle 11 ∗ 5 ∗ 109 Byte in Anspruch genommen. Das sind selbst für heutige Verhältnisse stolze 165 Gigabyte an Daten, die theoretisch als temporäre Daten im Hauptspeicher abzulegen sind. Wenn wir uns den weiteren Verlauf der Anfrage jetzt ansehen, so werden aus diesen 165 Gigabyte durch Anwendung der Vergleiche der WHERE-Klausel riesige Datenmengen aussortiert. Nehmen wir einmal an, es gibt in unserem Unternehmen fünf verschiedene Waschmaschinenmodelle, an denen jeweils zehn Abteilungen arbeiten, so bekommen wir als Endergebnis eine Tabelle von 5 ∗ 10 = 50 Zeilen mit je zwei Spalten à 15 Byte, was sich insgesamt auf 1.500 Byte oder 1, 5 KByte aufsummiert. Diese Datenmenge wird problemlos in jeden Hauptspeicher passen, während die Ausgangstabelle sogar die normale Kapazität von so manchen Sekundärspeichern sprengen wird. Beispiel 7.63: Explodierende Datenmenge beim Kartesischen Produkt „Welche Abteilungen arbeiten an den Produkten des Typs Waschmaschine?“ SELECT FROM WHERE
DISTINCT produktBez, abteilungsName Produkt CROSS JOIN ArbeitetAn CROSS JOIN Abteilung Produkt.produktNr=ArbeitetAn.produktNr AND ArbeitetAn.abteilungsNr=Abteilung.abteilungsNr AND Produkt.produktTyp=’Waschmaschine’;
In der FROM-Klausel wird die folgende Ausgangstabelle aufgebaut:53 (Produkt.produktNr, produktBez, produktTyp, stueckKosten, nettoPreis, ArbeitetAn.abteilungsNr, ArbeitetAn.produktNr, Abteilung.abteilungsNr, abteilungsName, budget, mitarbeiterZahl) Man braucht sicherlich keine tiefgehenden SQL-Kenntnisse zu besitzen, um hier einwenden zu können, dass diese Vorgehensweise äußerst unglücklich zu sein scheint. Schließlich kennen wir von der Diskussion der Relationenalgebra noch den natürlichen Verbund und das, was in Beispiel 7.63 in den mittleren drei Zeilen passiert, ist nichts anderes als ein natürlicher Verbund über Produkt, ArbeitetAn und Abteilung. Nur ist er halt maximal umständlich ausgedrückt worden, indem scheinbar die folgende Äquivalenz „ausgenutzt“ wurde: Tab1 Bedingung Tab2 = σBedingung Tab1 × Tab2
52 Es gibt 100 Abteilungen, die jeweils an 100 Produkten arbeiten, so dass die „Verbindungstabelle“ ArbeitetAn 100*100 Zeilen umfasst. 53 Man beachte, dass der in der WHERE-Klausel über die Gleichheit der identischen Spaltennamen simulierte natürliche innere Verbund die überflüssige doppelte Auflistung dieser Spaltennamen nicht eliminiert. Dies muss gesondert in der SELECT-Klausel spezifiziert werden.
342
7 Die relationale Datenbanksprache SQL
FROM TabRef ,
[WHERE] CROSS
JOIN
JOIN
NATURAL
INNER UNION LEFT RIGHT FULL
ON USING
OUTER
( ) ,
Abb. 7.6: FROM-Klausel
Diese Äquivalenz wird jedoch glücklicherweise nur bei der Formulierung einer Anfrage genutzt. SQL ist trotz kleiner Mängel und gelegentlich geäußerten gegenteiligen Positionen im Wesentlichen eine deskriptive Anfragesprache. Der Benutzer liefert keine Abarbeitungsvorschrift, sondern eine Beschreibung des gewünschten Ergebnisses. Und das sollte er in einer ihm genehmen Weise tun können. Über das Kartesische Produkt lässt sich sehr schnell und einfach, weil absolut einheitlich, die Ausgangstabelle kreieren. Sie kann dann über die Selektion und Projektion auf die gewünschte Größe reduziert werden. Dabei wurde es als unerheblich angesehen, ob diese Ausgangstabelle viel zu groß ist oder, im Sinn des zu ermittelnden Ergebnisses, gerade so passt. Der wesentliche Aspekt war, dass es eine Obermenge ist. Es wurde berechtigterweise unterstellt, dass der Optimierer das Größenproblem schon in den Griff bekommt. Die Nachteile dieser einfachen Lösung, fehlende Orthogonalität und Fehleranfälligkeit bei dem „Nachholen“ von echten Verbundbedingungen in der WHERE-Klausel54 , führten bei der Arbeit an SQL-92 zu einer völligen Überarbeitung der FROM-Klausel. Der entscheidende Unterschied ist, dass jetzt alle Verbundoperationen direkt in der FROM-Klausel spezifiziert werden können. Man muss nicht mehr eine in ihrer Größe völlig überzogene Ausgangstabelle spezifizieren, um sie dann in der WHERE-Klausel erheblich einzuschränken. Stattdessen ist der Aufbau einer maßgeschneiderten Ausgangstabelle möglich, so dass man sich dann in der WHERE-Klausel auf das Wesentliche konzentrieren kann (siehe Syntax 7.27). 54 Bei der Diskussion der Verbundoperationen weiter unten wird noch darauf eingegangen, wie die jeweilige Verbundvariante mit den alten Techniken simuliert werden kann. Dann kann sich jeder selbst ein Bild über die Komplexität des alten Standards machen.
7.3 Die Datenbankanfragesprache (DRL)
343
Verbundoperation
Bezeichnung in SQL
Aufbau resultierende Tabelle
Kartesisches Produkt (Kreuzprodukt)
CROSS JOIN
Alle ursprünglichen Spalten
natürlicher Verbund (natürlicher Gleichverbund)
NATURAL [INNER] JOIN
Alle ursprünglichen Spalten, allerdings keine mehrfach
Spaltennamenverbund (column name join)
[INNER] JOIN . . . USING (SpaltenNameN)
Alle ursprünglichen Spalten; die, die in der USING-Klausel genannt werden, nur einfach
Thetaverbund (condition join)
[INNER] JOIN . . . ON VergleichsPrädikatE
Alle ursprünglichen Spalten
linker äußerer Verbund
LEFT [OUTER] JOIN
Alle ursprünglichen Spalten der links stehenden Tabelle
rechter äußerer Verbund
RIGHT [OUTER] JOIN
Alle ursprünglichen Spalten der rechts stehenden Tabelle
voller äußerer Verbund
FULL [OUTER] JOIN
Alle ursprünglichen Spalten
Vereinigungsverbund
UNION JOIN
Alle ursprünglichen Spalten
Tabelle 7.10: Verbundoperation und ihre Bezeichnung in SQL
Syntax 7.27: Erweiterte FROM-Klausel mit Verbundoperation FROM-KlauselMitVerbund ::= FROM TabellenRef1 [{,TabellenRef2|ÜberlappenderVerbundTabellenRef2 | VerbundMitBedingungTabellenRef2 {ON VergleichsPrädikatE USING (attr1 [, attr2 ]∗ ) }}]∗ VergleichsprädikatE ::= Vergleichsprädikat[{ANDIOR Vergleichsprädikat}]∗
Der syntaktische korrekte Aufbau einer FROM-Klausel kann der Abbildung 7.6 entnommen werden. Die einzelnen Verbundarten werden in den folgenden Kapiteln noch genauer diskutiert. Eine weitere Zerlegung und Beschreibung der nichtterminalen Symbole aus Syntax 7.27 findet in Syntax 7.28 statt. Die durch SQL-92 unterstützten Verbundoperationen und ihre Bezeichnung sind der Tabelle 7.10 zu entnehmen. Die dritte Spalte liefert Auskunft darüber, welche Spalten der Ausgangstabellen in die resultierende Tabelle übernommen werden. Die Semantik der meisten Verbundoperationen ist schon im Zusammenhang mit der relationalen Algebra eingeführt worden. Wir wollen uns hier deshalb auf die SQL-spezifischen Details konzentrieren. Die inneren Verbunde können optional noch um das Schlüsselwort INNER ergänzt werden.
344 7.3.2.2
7 Die relationale Datenbanksprache SQL Der natürliche Verbund
Die neben dem Kartesischen Produkt einfachste Verknüpfung ist der natürliche Verbund (NATURAL JOIN), bei dem Tabellen über ihre übereinstimmenden Spaltennamen verbunden werden. Dabei werden die doppelt vorkommenden Spaltennamen nur einmal in die Ausgangstabelle übernommen. Beispiel 7.64: Natürlicher Verbund Die Anfrage von Beispiel 7.63 lässt sich mit Hilfe der neuen und sauberen Variante von SQL-92 deutlich kompakter und lesbarer formulieren: SELECT FROM WHERE
DISTINCT produktBez, abteilungsName Produkt NATURAL JOIN ArbeitetAn NATURAL JOIN Abteilung Produkt.produktTyp=’Waschmaschine’;
Im alten Standard lässt sich der natürliche Verbund durch eine längliche Formulierung simulieren, die in jeder Klausel der Anfrage ihre Spuren hinterlässt. Wie üblich wird in der FROM-Klausel das Kreuzprodukt gebildet. In der WHERE-Klausel werden die eigentlichen Verbundbedingungen festgelegt. Schließlich müssen noch in der SELECT-Klausel die mehrfach vorkommenden Spalten ausgeblendet werden. Da nur spezifiziert werden kann, was angezeigt werden soll, nicht aber, was wegzulassen ist, muss explizit angegeben werden, welche Spalten zur Ergebnistabelle gehören sollen. Beispiel 7.65: Natürlicher Verbund alter Art Der reine natürliche Verbund aus Beispiel 7.64 (ohne die Selektions- und Projektionsbedingungen) ist nach altem Stil wie folgt zu formulieren:55 SELECT FROM WHERE
Produkt.∗, Abteilung.∗ Produkt, ArbeitetAn, Abteilung Produkt.produktNr=ArbeitetAn.produktNr AND ArbeitetAn.abteilungsNr=Abteilung.abteilungsNr;
oder unter Verwendung von Aliasnamen SELECT FROM WHERE
P.∗, A.∗ Produkt P, ArbeitetAn AA, Abteilung A56 P.produktNr=AA.produktNr AND AA.abteilungsNr=A.abteilungsNr;
Die Tabelle ArbeitetAn ist als reine Beziehungstabelle ohne zusätzliche eigene Spalten ausgelegt. Sie besitzt als Spalten nur jeweils den Primärschlüssel der anderen beiden Tabellen. Da damit alle Spalten von ArbeitetAn bereits in den anderen Tabellen enthalten sind, sind sie für die Ergebnistabelle des natürlichen Verbundes nicht mehr notwendig. Wie bereits erwähnt, muss dieser Wegfall jedoch explizit in der SELECT-Klauselfestgelegt werden (siehe Beispiel 7.66). 55 Es ist zu beachten, dass Beispiel 7.63 den natürlichen Verbund auch nach alter Variante formuliert. Es wurde aber bereits die neue, mit SQL-92 zusätzlich angebotene Syntax benutzt. 56 Im alten Standard existierte das Schlüsselwort AS zur Vergabe eines Aliasnamens noch nicht. Auch der neue Standard erlaubt das Auslassen dieses Wortes.
7.3 Die Datenbankanfragesprache (DRL)
345
Beispiel 7.66: Wegfall übereinstimmender Spalten beim natürlichen Verbund alter Art „Welche Teile werden im Teilelager Hochstapel gelagert?“ SELECT FROM WHERE
∗ Teil T, TeileLagertIn TLI, TeileLager TL T.teilNr=TLI.teilNr AND TLI.teileLagerNr=TL.teileLagerNr AND TL.teileLagerBez=’Hochstapel’;
Das Ergebnistabelle hätte folgenden Aufbau:57 (teilNr, teilBez, teileLagerNr, teilNr, istBestand, teileLagerNr, teileLagerBez, plz, ort, strasse, hausNr) Die Teile- und Teilelagernummer würden doppelt ausgegeben. Redundanzfrei müsste die Anfrage wie folgt spezifiziert werden: SELECT FROM WHERE
T.teilNr, T.teilBez58 Teil T, TeileLagertIn TLI, TeileLager TL T.teilNr=TLI.teilNr AND TLI.teileLagerNr=TL.teileLagerNr AND TL.teileLagerBez=’Hochstapel’;
Achtung 7.6: Extreme beim natürlichen Verbund Der natürliche Verbund kennt zwei Extreme. Besitzen die beiden zu verbindenden Tabellen keine identischen Spaltennamen, ist das Ergebnis das Kartesische Produkt beider Tabellen. Stimmen die Tabellen in ihrem Aufbau völlig überein, wird als Ergebnis der Durchschnitt59 der beiden Tabellen geliefert. Diese Aussage gilt sinngemäß auch, falls die Struktur der einen Tabelle eine echte Unterstruktur der anderen Tabelle darstellt. Während beim natürlichen Verbund und beim Kreuzprodukt feststeht, auf welcher Basis die Vereinigung geschieht, muss bei allen anderen Verbundoperationen noch die Verknüpfungsbedingung angegeben werden. Dies geschieht beim Spaltennamenverbund (implizit) in der USING-Klausel und beim Bedingungsverbund (explizit) in der ON-Klausel. 7.3.2.3
Der Spaltennamenverbund
Der Spaltennamenverbund ist im Prinzip eine Verallgemeinerung des natürlichen Verbundes. Statt den Verbund grundsätzlich über alle übereinstimmenden Spaltennamen durchzuführen, müssen bei dieser Variante über die USING-Klausel explizit die für die Verbundbedingung vorgesehenen Spalten genannt werden. Damit kann auch eine Teilmenge der übereinstimmenden Spaltennamen ausgewählt werden (siehe Beispiel 7.67). Alle Regeln des natürlichen Verbundes gelten damit auch für den Spaltennamenverbund. Der Spaltennamenverbund ähnelt sehr dem Gleichverbund. Von der Semantik sind auch beide gleich, nur übernimmt der Spaltennamenverbund die Spalten, über die verbunden wird, 57 Mehrfach
vorkommende Spalten sind kursiv dargestellt. wäre auch die Schreibweise T.∗ möglich. 59 Der Durchschnitt zweier Tabellen wird in Kapitel 7.3.6.2 eingeführt. 58 Alternativ
346
7 Die relationale Datenbanksprache SQL
nur einmal in die Ergebnistabelle, während der Gleichverbund grundsätzlich alle Spalten übernimmt. Deshalb wird hier auch der Name Spaltennamenverbund verwendet statt Gleichverbund. Beispiel 7.67: Innerer Verbund über die USING-Klausel Gegeben seien die folgenden abstrakten Tabellen: T1 (a, b, c, d, e, f) T2 (a, b, c, d, g, h, i) Der natürliche Verbund dieser beiden Tabellen SELECT FROM
∗ T1 NATURAL JOIN T2 ;
würde folgende Ausgangstabelle kreieren: (a, b, c, d, e, f, g, h, i) Die Anfrage ist identisch zur folgenden Variante: SELECT FROM
∗ T1 INNER JOIN T2 USING(a, b, c, d);
Würden allerdings in der USING-Klausel nur b und c stehen, FROM
T1 INNER JOIN T2 USING(b, c);
würde folgende Ausgangstabelle entstehen: (T1 .a, b, c, T1 .d, e, f, T2 .a, T2 .d, g, h, i) Beispiel 7.68: Einfacher Verbund über USING-Klausel „Welche Zulieferer liefern welches Teil?“ SELECT FROM
Zulieferer.∗, Teil.∗ Zulieferer INNER JOIN Liefert USING (zuliefererNr) INNER JOIN Teil USING (teilNr);
Es ist zu beachten, dass ein Spaltennamenverbund nur dann durchgeführt werden kann, wenn der Aufbau der beiden zu verbindenden Tabellen in Teilen identisch ist, was heißt, dass einige Spaltennamen übereinstimmen und die dazugehörigen Datentypen miteinander kompatibel sind. Da die in der USING-Klausel aufgeführten Spaltennamen in der Ausgangstabelle nur noch einfach vorkommen, kann nicht gesagt werden, von welcher Tabelle sie stammen. Daher dürfen diese Spaltennamen in den anderen Klauseln nicht unter Ergänzung eines Basistabellenbzw. Aliasnamens verwendet werden (siehe Beispiel 7.69 (1.)). Gibt es hingegen noch weitere, nicht in der USING-Klausel aufgeführte Übereinstimmungen zwischen den Tabellen, so muss, falls mit diesen Spalten gearbeitet werden soll, die Eindeutigkeit über die Verwendung des Basistabellen- bzw. Aliasnamens sichergestellt werden (siehe Beispiel 7.69 (2.)).
7.3 Die Datenbankanfragesprache (DRL)
347
Beispiel 7.69: USING-Klausel und Bezeichner Annahme: Die Tabellen T1 und T2 besitzen drei identische Spalten a, b und c. SELECT FROM WHERE
∗ T1 INNER JOIN T2 USING(b, c) T1 .b = . . . 1. Bezeichner ist nicht erlaubt. AND T1 .a = . . . OR T2 .a = . . .; 2. Bezeichner ist nicht nur erlaubt, sondern sogar notwendig.
Wenn man sich noch einmal Beispiel 7.65 vor Augen führt, so wird man feststellen, dass die alte Form des Verbundes das Verwenden von Aliasnamen für Verbundspalten in der WHEREund SELECT-Klausel verlangt, während die neue Variante es explizit verbietet. Ansonsten ist es so, dass bei der alten Variante der Spaltennamenverbund und der natürliche Verbund auf die gleiche Art und Weise gebildet werden (siehe Beispiel 7.65). 7.3.2.4
Der Bedingungsverbund
Der Bedingungsverbund unterscheidet sich in drei Punkten von den vorher diskutierten Verbundoperationen: Feststellung 7.6: Unterschied des Bedingungsverbundes zu anderen Verbundoperationen 1. Das Prädikat, über das der Verbund hergestellt werden soll, muss nicht ausschließlich auf dem Gleichheitstest beruhen. Stattdessen kann ein beliebiger Vergleichsoperator benutzt werden (θ-Vergleich von Spaltenwerten). 2. Es ist nicht mehr notwendig, den Verbund nur über übereinstimmende Spaltennamen abzuwickeln. Der Vergleich darf über beliebige typkompatible Spalten laufen. 3. Der Bedingungsverbund blendet keine Spalten aus. Auch die Spalten, die in der Verbundbedingung genutzt werden, bleiben (redundant) erhalten. Die Verbundbedingungen werden in der ON-Klausel spezifiziert. Sie unterscheiden sich nicht von der einfachen Variante von Bedingungen60, wie sie insbesondere auch in der WHEREKlausel gestellt werden können. Beispiel 7.70 präsentiert die einfachste Variante eines Bedingungsverbundes, der einen Spaltennamenverbund über verschieden benannte Spaltennamen darstellt.61 Beispiel 7.70: Bedingungsverbund über nicht namensgleiche Spalten „Welche Mitarbeiter kaufen auch bei uns ein?“ SELECT FROM
Mitarbeiter.∗ Mitarbeiter INNER JOIN Kunden ON (mitarbeiterNr = kundenNr);62
dem Begriff einfache Variante soll verstanden werden: SpaltenName Vergleichsoperator
SpaltenName. 61 Wobei jedoch alle Spalten in die Ergebnistabelle übernommen werden. Zudem wird Gleichheit von Werten unterschiedlicher Spaltennamen abgefragt, was der Spaltennamenverbund nicht erlaubt. 62 Unterstellt wird hier, dass ein Mitarbeiter, der auch Kunde ist, in beiden Tabellen dieselbe Nummer besitzt. 60 Unter
348
7 Die relationale Datenbanksprache SQL
Beispiel 7.70 deutet schon an, dass ein über die USING-Klausel definierter Spaltennamenverbund grundsätzlich auch über den Bedingungsverbund formuliert werden kann, der Spaltennamenverbund also die Mächtigkeit der Anfragesprache nicht erhöht (man beachte allerdings Achtung 7.7). Beispiel 7.71: „Gleich“verbund über die ON- und die USING-Klausel 1. „Welche Aufträge wurden von welchem Mitarbeiter akquiriert?“ Nur für dieses Beispiel unterstellen wir einmal, dass die Spalte bearbeiterNr in AuftragZulieferer in mitarbeiterNr umbenannt worden ist. (a) SELECT FROM
∗ Mitarbeiter AS M INNER JOIN AuftragZulieferer AS A 63 ON M.mitarbeiterNr = A.mitarbeiterNr;
(b) SELECT FROM
∗ Mitarbeiter INNER JOIN AuftragZulieferer USING (mitarbeiterNr);
2. „Welche Mitarbeiter haben direkt am Tag ihrer Einstellung einen Auftrag an einen Zulieferer vergeben?“ SELECT FROM
M.∗ Mitarbeiter AS M INNER JOIN AuftragZulieferer AS A ON (M.mitarbeiterNr = A.mitarbeiterNr AND A.datum = M.einstellung)64;
3. „Nenne alle Zulieferer, die schon vor dem Jahr 2014 Aufträge von uns bekommen haben.“ SELECT FROM WHERE
Z.∗ Zulieferer AS Z INNER JOIN AuftragZulieferer AS A ON (Z.zuliefererNr = A.zuliefererNr) datum < DATE ’2014-01-01’;
ist äquivalent zu SELECT FROM WHERE
Z.∗ Zulieferer AS Z INNER JOIN AuftragZulieferer USING (zuliefererNr) datum < DATE ’2014-01-01’;
ist äquivalent zu SELECT FROM WHERE
Z.∗ Zulieferer AS Z NATURAL JOIN AuftragZulieferer datum < DATE ’2014-01-01’;
63 Die AS-Klausel ermöglicht auch die (Um)benennung einer Tabelle, was in diesem Beispiel ausgenutzt wird. Diese Variante wird noch genauer in Kapitel 7.3.2.7 diskutiert. 64 Da die Spaltennamen eindeutig sind, könnten die Aliasnamen auch weggelassen werden.
7.3 Die Datenbankanfragesprache (DRL)
349
Achtung 7.7: Spaltennamenverbund und auf Gleichheit beruhender Bedingungsverbund Da in Beispiel 7.71, Anfrage 1., Variante 1., die Verbundbedingung über einen Gleichheitstest läuft, kann die gleiche Anfrage grundsätzlich auch über die USING-Klausel gestellt werden (siehe Variante 2.). Trotzdem unterscheiden sich beide Varianten wegen Punkt 3. von Feststellung 7.6 im Ergebnis. Bei der ersten Variante kommt die Spalte mitarbeiterNr zweimal in der Ergebnistabelle vor, bei der zweiten Variante nur einmal. Obwohl Punkt 1. von Feststellung 7.6 den Eindruck vermittelt, dass der entscheidende Unterschied zwischen dem Bedingungs- und dem Spaltennamenverbund die Verwendung eines anderen Vergleichsoperators ist, ist dies in der Praxis häufig nicht der Fall. Die Verwendung anderer Vergleichsoperatoren führt auch schnell zu einer erheblich ansteigenden Komplexität, da solche Anfragen sich nicht mehr direkt der Intuition erschließen (siehe Beispiel 7.72)65. Der wesentlich häufigere Grund für die Verwendung des Bedingungsverbundes ist seine Fähigkeit, den Verbund auch über nicht namensgleiche, jedoch typkompatible Spalten durchführen zu können (siehe Beispiel 7.71, Anfrage 2. und Beispiel 7.72). Beispiel 7.72: Nicht auf Gleichheit beruhender Bedingungsverbund „Gib die Daten aller Rechnungspositionen66 aus, bei denen Produkte unter ihren Stückkosten verkauft wurden.67“ SELECT R.∗, produktBez, stueckKosten, (betrag/menge) AS verkaufsPreis FROM Produkt AS P INNER JOIN Rechnungsposition AS R ON (P.produktNr = R.produktNr AND stueckKosten > (betrag/menge)); ist äquivalent zu SELECT FROM WHERE
R.∗, produktBez, stueckKosten, (betrag/menge) AS verkaufsPreis Produkt AS P INNER JOIN Rechnungsposition AS R ON (P.produktNr = R.produktNr) stueckKosten > (betrag/menge);
ist äquivalent zu SELECT FROM WHERE
R.∗, produktBez, stueckKosten, (betrag/menge) AS verkaufsPreis Produkt AS P INNER JOIN Rechnungsposition AS R ON (stueckKosten > (betrag/menge)) P.produktNr = R.produktNr;
ist äquivalent zu SELECT FROM WHERE
Rechnungsposition.∗, produktBez, stueckKosten, (betrag/menge) AS verkaufsPreis Produkt NATURAL JOIN Rechnungsposition stueckKosten > (betrag/menge);
65 Auch dieses Beispiel passt nur eingeschränkt, was man an der alternativen, wesentlich intuitiveren Formulierung sehen kann. An der Schwierigkeit, ein sauberes Beispiel zu finden, kann man auch die Seltenheit (oder Unwahrscheinlichkeit) ablesen, mit der eine solche Variante in der Praxis auftreten wird. 66 Wir unterstellen hier, dass es die in unserem Beispielschema nicht explizit aufgeführten Tabellen für Anträge und Rechnungen auch auf der Kundenseite gibt. 67 Der Leser mag spaßeshalber einmal versuchen, anhand unseres Beispiels eine nicht auf Gleichheit beruhende Anfrage ohne zusätzlichen Gleichheitstest (wie im Beispiel) zu formulieren.
350
7 Die relationale Datenbanksprache SQL
Der Einsatz von Bedingungsverbunden, die nicht auf Gleichheit beruhen, wird noch einmal am Ende von Kapitel 7.3.4 diskutiert. 7.3.2.5
Der äußere Verbund
An den Varianten des inneren Verbundes (siehe z. B. Beispiel 7.65) kann man sehr gut erkennen, dass diese Arten des Verbundes über die Verbundbedingung für eine sehr selektive Auswahl68 von Zeilen sorgen können. Zwar werden zunächst einmal Zeilen verbunden, über die Verbundbedingung werden aber auch Zeilen im mehr oder weniger großen Umfang aussortiert. Der äußere Verbund (OUTER JOIN) ist da grundsätzlich anders ausgelegt. Sein Ziel ist nur die geeignete Datendarstellung. Datenelimination findet nicht statt. Ein äußerer Bedingungsverbund der beiden Tabellen T1 und T2 über die Spalten a und d arbeitet wie folgt (siehe Beispiel 7.73): Im ersten Schritt wird der bereits bekannte innere Verbund zwischen beiden Tabellen erzeugt. Diese Datensätze gehören bereits zum Ergebnis. Als Zweites wird, je nachdem, ob es sich um einen linken oder einen rechten äußeren Verbund handelt, die links oder die rechts von den Verbund-Schlüsselwörtern stehende Tabelle genommen. Diese Tabelle wird im Folgenden Haupttabelle genannt. Alle Zeilen der Haupttabelle, die bereits im ersten Schritt berücksichtigt wurden, werden aussortiert. Bei den verbleibenden Zeilen werden die Spalten der anderen Tabelle hinzugefügt. Da allerdings für diese Spalten aufgrund der Tatsache, dass sie beim inneren Verbund keinen Partner gefunden haben, keine Werte bekannt sind, werden sie mit der Nullmarke belegt. Die Vereinigung aus Schritt 1 und Schritt 2 bildet schließlich die vollständige Ergebnistabelle. Ein äußerer Verbund enthält also mindestens alle um die Spalten der anderen Tabelle erweiterten Zeilen der Haupttabelle. Zusätzliche Zeilen können immer dann hinzukommen, wenn sie durch den inneren Verbund der beiden Tabellen erzeugt werden. Beispiel 7.73: Prinzipielle Arbeitsweise des äußeren Verbundes Gegeben seien wieder die abstrakten Tabellen (siehe Beispiel 7.67) mit folgenden Ausprägungen der Tabellen: T1
a
b
c
a
t1
b
T2
d
e
f
4n
b
10
xy
t5
3h
e
20
as
b
t4
6t
f
30
fg
c
t7
7u
d
20
zu
d
t2
8f
g
40
io
c
t4
2s
a
10
pp
Es soll die folgende Anfrage beantwortet werden: SELECT FROM 68 Eine
∗ T1 LEFT OUTER JOIN T2 ON (a = d);
Bedingung ist umso selektiver, je weniger Zeilen sie aus einer gegebenen Menge von Zeilen auswählt.
7.3 Die Datenbankanfragesprache (DRL)
351
Da es sich um einen linken äußeren Verbund handelt, ist die links von LEFT OUTER JOIN stehende Tabelle die Haupttabelle (hier T1 ). Schritt 1l : Berechnung des inneren Verbundes Dieser Schritt entspricht der Ausführung der folgenden Anfrage: ∗ T1 INNER JOIN T2 ON (a = d);
SELECT FROM
Ergebnis Schritt 1: Erg1
a
b
c
d
e
f
a
t1
4n
a
10
pp
b
t5
3h
b
10
xy
b
t4
6t
b
10
xy
d
t2
8f
d
20
zu
Schritt 2l : Berechnung der im ersten Schritt nicht benutzten Zeilen von T 1 Dieser Schritt entspricht der Ausführung der folgenden Anfrage: SELECT FROM WHERE
DISTINCT T1 . ∗ (, NULL AS d, NULL AS e, NULL AS f)69 T1 CROSS JOIN T2 70 a NOT IN (SELECT d FROM T2 );71
Zunächst werden alle möglichen Kombinationen der Zeilen aus T1 mit den Zeilen aus T2 gebildet (FROM-Klausel). Dann werden die Zeilen aussortiert, die bereits in Schritt 1 berechnet wurden (WHERE-Klausel). Schließlich wird die Mammuttabelle auf die Bestandteile der Haupttabelle T1 zurückgestutzt (SELECT-Klausel), wobei die durch das Kartesische Produkt verursachten massiven Wiederholungen von Zeilen entfernt werden (DISTINCT-Schlüsselwort). Schließlich wird Erg2 noch ergänzt um die mit der Nullmarke belegten Spalten von T2 . Ergebnis Schritt 2l : Ergl2
a
b
c
d
e
f
c
t7
7u
NULL
NULL
NULL
c
t4
2s
NULL
NULL
NULL
69 SQL-92 erlaubt das Einfügen von Konstanten als Spalten der Ergebnistabelle. Auch können solche Konstanten bzw. die sie repräsentierenden Spalten mit Namen versehen werden. Das Einfügen der Nullmarke wird jedoch nicht unterstützt (fehlende Orthogonalität). Deshalb ist die obige Formulierung streng genommen nicht korrekt. Es wird auch unterstellt, dass das DISTINCT alle mehrfach vorkommenden Tupel bereits entfernt hat, nachdem die Ausgangstabelle auf die Spalten von T1 reduziert wurde und bevor die Spalten d, e und f angefügt werden. 70 Alternativ könnte die FROM-Klausel auch wie folgt definiert werden: T INNER JOIN T ON(a = d). 1 2 71 Wie bei der Diskussion zu Nullmarken noch gezeigt wird, kann diese Formulierung unvollständig sein, falls a oder d mit der Nullmarke belegt sein dürfen (siehe insbesondere Beispiel 7.95). Deshalb soll hier angenommen werden, dass dies bei der Tabellendefinition ausgeschlossen wurde.
352
7 Die relationale Datenbanksprache SQL
Schritt 3l : Vereinigung von Erg1 und Ergl2 Endergebnis: Erglges
a
b
c
d
e
f
a
t1
4n
a
10
pp
b
t5
3h
b
10
xy
b
t4
6t
b
10
xy
d
t2
8f
d
20
zu
c
t7
7u
NULL
NULL
NULL
c
t4
2s
NULL
NULL
NULL
Sollte der rechte äußere Verbund berechnet werden, würde Schritt 1 dasselbe Ergebnis liefern. Schritt 2r würde die folgende Tabelle erzeugen: Schritt 2r : Berechnung der im ersten Schritt nicht benutzten Zeilen von T 2 Ergebnis Schritt 2r : Ergr2
a
b
c
d
e
f
NULL
NULL
NULL
e
20
as
NULL
NULL
NULL
f
30
fg
NULL
NULL
NULL
g
40
io
Schritt 3r : Vereinigung von Erg1 und Ergr2 Das Endergebnis sähe somit wie folgt aus: Ergrges
a
b
c
d
e
f
a
t1
4n
a
10
pp
b
t5
3h
b
10
xy
b
t4
6t
b
10
xy
d
t2
8f
d
20
zu
NULL
NULL
NULL
e
20
as
NULL
NULL
NULL
f
30
fg
NULL
NULL
NULL
g
40
io
Abgesehen von einer anderen Reihenfolge bei der Auflistung der Spalten entspricht der obige linke äußere Verbund dem folgenden rechten äußeren Verbund SELECT FROM
∗ T2 RIGHT OUTER JOIN T1 ON (a = d);
7.3 Die Datenbankanfragesprache (DRL)
353
Der äußere Verbund kann immer dann eingesetzt werden, wenn man die in einer Tabelle enthaltenen Informationen vollständig sehen möchte, allerdings da, wo vorhanden, ergänzt um Informationen aus einer anderen Tabelle. Beispiel 7.74: Äußerer Verbund „Gib alle Produkte aus und, falls bekannt, die Abteilungen, die an deren Herstellung mitwirken.“ Für den Fall, dass unser Unternehmen auch fremdproduzierte Produkte verkauft, werden einige Zeilen der Ergebnismenge bei den Abteilungsdaten nur Nullmarken aufweisen. Die folgenden drei Varianten sind im Wesentlichen unterschiedliche Formulierungen der gleichen Anfrage. Variante 1: SELECT FROM Variante 2: SELECT FROM
∗ Produkt NATURAL LEFT OUTER JOIN ArbeitetAn NATURAL LEFT OUTER JOIN Abteilung; ∗ Produkt LEFT OUTER JOIN ArbeitetAn USING (produktNr) LEFT OUTER JOIN Abteilung USING (abteilungsNr);
Variante 3:72 SELECT ∗ FROM Produkt LEFT OUTER JOIN ArbeitetAn ON (Produkt.produktNr= ArbeitetAn.produktNr) LEFT OUTER JOIN Abteilung ArbeitetAn ON (ArbeitetAn.abteilungsNr = Abteilung.abteilungsNr); Die dritte Möglichkeit eines äußeren Verbundes ist der vollständige äußere Verbund, der eine Kombination aus linkem und rechtem äußeren Verbund darstellt. Dementsprechend würde sich Schritt 1 von Beispiel 7.73 nicht ändern. Schritt 2 wäre die Vereinigung der Schritte 2l und 2r von Beispiel 7.73, so dass als Endergebnis die folgende Tabelle herauskommen würde: Ergvges
72 Man
a
b
c
d
e
f
a
t1
4n
a
10
pp
b
t5
3h
b
10
xy
b
t4
6t
b
10
xy
d
t2
8f
d
20
zu
c
t7
7u
NULL
NULL
NULL
c
t4
2s
NULL
NULL
NULL
NULL
NULL
NULL
e
20
as
NULL
NULL
NULL
f
30
fg
NULL
NULL
NULL
g
40
io
beachte jedoch Achtung 7.7 auf Seite 349.
354
7 Die relationale Datenbanksprache SQL
Ähnlich wie beim inneren Verbund werden auch beim äußeren Verbund alle Verbundmöglichkeiten unterstützt, also der natürliche, der Gleich- und der Bedingungsverbund. Beispiel 7.75: Verbundarten des äußeren Verbundes 1. „Liste alle Mitarbeiter und ihr Einstellungsdatum zusammen mit den von ihnen vergebenen Aufträgen an Zulieferer für das Jahr 2014 auf. Falls der Bearbeiter eines Zuliefererauftrages nicht bekannt sein sollte, soll dieser Auftrag trotzdem ausgegeben werden. Das Gleiche gilt für Mitarbeiter, die keinen Auftrag vergeben haben.“ SELECT mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, einstellung, auftragsNr, datum FROM Mitarbeiter FULL OUTER JOIN AuftragZulieferer ON(mitarbeiterNr = bearbeiterNr) WHERE (datum ≥ DATE ’2014-01-01’) AND (datum < DATE ’2015-01-01’); 2. „Gib alle Mitarbeiter und alle Kunden aus, wobei deutlich werden soll, welche Mitarbeiter auch Kunden sind.“ SELECT FROM
∗ Mitarbeiter FULL OUTER JOIN Kunden ON (mitarbeiterNr = kundenNr);
3. „Gib alle Mitarbeiter aus, wobei deutlich werden soll, welche Mitarbeiter auch Kunden sind.“ Variante 1: SELECT ∗ FROM Mitarbeiter LEFT OUTER JOIN Kunden ON (mitarbeiterNr = kundenNr); Variante 2: SELECT FROM
∗ Kunden RIGHT OUTER JOIN Mitarbeiter ON (kundenNr = mitarbeiterNr);
Achtung 7.8: Ergebnistabellen erben nicht die Integritätsbedingungen der involvierten Basistabellen Gerade im Zusammenhang mit dem äußeren Verbund fällt auf, dass elementare Integritätsbedingungen der Basistabellen verletzt werden können. Beispielsweise gibt es eine Bedingung, nach der der Primärschlüssel nicht mit der Nullmarke belegt werden darf. Aber gerade das bewirkt der äußere Verbund. Es soll deshalb ausdrücklich darauf hingewiesen werden, dass Integritätsbedingungen der Basistabellen nicht an durch Anfragen erzeugte Ergebnistabellen vererbt werden. Überspitzt kann man sogar sagen, dass auf der Ebene von Ergebnistabellen Anarchie herrscht, da viele Regeln des konzeptuellen Schemas und sogar des relationalen Datenbankmodells (Duplikatfreiheit) nicht mehr sichergestellt werden. Sollen allerdings Daten aus Anfragen über die DML als eigene Tabellen in die (physische) DB eingefügt werden, also materialisiert werden, so werden sie vom DBMS nur dann akzeptiert, falls sie alle Regeln des Schemas und des Datenbankmodells erfüllen.
7.3 Die Datenbankanfragesprache (DRL) 7.3.2.6
355
Der Vereinigungsverbund
Der Vereinigungsverbund (UNION JOIN) ähnelt einem vollen äußeren Verbund, wobei jedoch im Gegensatz zu diesem kein Verbund von Zeilen auf der Basis von Spaltenwerten vorgenommen wird. Stattdessen werden zunächst bei jeder Tabelle auf der Ebene der Tabellentypen die Spalten der jeweils anderen Tabelle hinzugefügt. Da für die neu hinzugekommenen Spalten keine Werte vorhanden sind, wird stattdessen jeweils die Nullmarke eingesetzt. Im Prinzip entspricht das der Vorgehensweise bei der Bildung des vollen äußeren Verbundes, nur dass Schritt 1, die Bildung des inneren Verbundes beider Tabellen (siehe Beispiel 7.73), ersatzlos entfällt: Zunächst wird die linke Tabelle komplett genommen, d. h. ohne dass irgendwelche Zeilen eliminiert wurden, und darauf Schritt 2l von Beispiel 7.73 ausgeführt. Das Gleiche wird für die rechte Tabelle mit Schritt 2r gemacht. Nachdem beide Tabellen aufgebaut wurden, können sie vereinigt werden, da der angewendete Algorithmus sicherstellt, dass beide Tabellen im Aufbau übereinstimmen. Die Ergebnismenge hat damit immer genau so viele Zeilen wie T1 und T2 zusammen an Zeilen haben. Beispiel 7.76: UNION JOIN der Tabellen von Beispiel 7.73 T1 − T2
a
b
c
d
e
f
a
t1
4n
NULL
NULL
NULL
b
t5
3h
NULL
NULL
NULL
b
t4
6t
NULL
NULL
NULL
c
t7
7u
NULL
NULL
NULL
d
t2
8f
NULL
NULL
NULL
c
t4
2s
NULL
NULL
NULL
NULL
NULL
NULL
b
10
xy
NULL
NULL
NULL
e
20
as
NULL
NULL
NULL
f
30
fg
NULL
NULL
NULL
d
20
zu
NULL
NULL
NULL
g
40
io
NULL
NULL
NULL
a
10
pp
Die vollständige Syntax aller Verbundklauseln kann Syntax 7.28 entnommen werden. Aus Gründen der Komplexität wurde die Darstellung auf einen Verbund mit zwei beteiligten Tabellen beschränkt. Syntax 7.28: Verbund VerbundTabelle
::= {TabellenRef1 , TabellenRef2 | ÜberlappenderVerbund | VerbundMitBedingung}
356
7 Die relationale Datenbanksprache SQL
ÜberlappenderVerbund ::= TabellenRef1 {CROSS | NATURAL [{INNER | ÄußererVerbund}]} JOIN TabellenRef2 VerbundMitBedingung ::= TabellenRef1 [{INNER | UNION | ÄußererVerbund}] JOIN TabellenRef2 {ON KomplexesPrädikat | USING (attr1 [, attr2 ]∗ ) }} TabellenRef ::= {Tabelle | AbgeleiteteTabelle | VerbundTabelle [, VerbundTabelle]∗ } AbgeleiteteTabelle ::= SFW-Block ÄußererVerbund ::= {LEFT | RIGHT | FULL} [OUTER] Verbundoperation über mehrere Tabellen Grundsätzlich kann eine Verbundoperationeine beliebige Anzahl von Tabellen verknüpfen, wie exemplarisch am θ-Verbund gezeigt werden soll: Syntax 7.29: Bedingungsverbund über mehrere Tabellen SELECT FROM
ErgebnisTabelle TabellenRef1 [INNER] JOIN TabellenRef2 ON VergleichsPrädikatE1 [[INNER] JOIN TabellenRefn ON VergleichsPrädikatEn−1]∗
Verbundoperationen über eine beliebige Anzahl von Tabellen werden von links nach rechts abgearbeitet. Dabei können in VergleichsPrädikatE1 nur Spalten angesprochen werden, die zu den Tabellentypen TabellenRef1 und TabellenRef2 gehören. Rekursiv fortgeführt bedeutet dies, dass in VergleichsPrädikatEn−1 die Spaltennamen der zuvor gebildeten Verbundtabelle, ergänzt um die Spaltennamen der Tabelle TabellenRefn angesprochen werden können. Beispiel 7.77: Einfacher Verbund über mehrere Tabellen 1. „Wie viele Teile hat der Zulieferer PasstNix GmbH am 01.02.2014 an uns geliefert?“ SELECT FROM WHERE
SUM(menge) Zulieferer INNER JOIN LieferantenRechnung USING (zuliefererNr) INNER JOIN RechnungsPosition USING (rechnungsNr) zuliefererName=’PasstNix GmbH’ AND datum=DATE ’2014-02-01’;
2. „Gesucht werden alle Teile, die bei der Produktion der Waschmaschine WM53 benötigt werden.“ Variante 1: SELECT FROM WHERE
Teil.∗ Teil INNER JOIN IstBestandteilVon USING (teilNr) INNER JOIN Produkt USING (produktNr) produktBez=’WM53’;
7.3 Die Datenbankanfragesprache (DRL) Variante 2: SELECT FROM WHERE
357
Teil.∗ Teil NATURAL JOIN IstBestandteilVon NATURAL JOIN Produkt produktBez=’WM53’;
Achtung 7.9: Abarbeitung von links nach rechts kann zu unerwarteten Ergebnissen führen Die Abarbeitung von links nach rechts bedeutet, dass beim natürlichen Verbund immer die zuletzt erzeugte Zwischentabelle zum natürlichen Verbund herangezogen wird. Bezogen auf Beispiel 7.78 bedeutet dies, dass folgende Schritte durchgeführt werden: 1. Es wird der natürliche Verbund zwischen Zulieferer und Liefert über zuliefererNr gebildet. Es entsteht Zwischentabelle1. 2. Es wird der natürliche Verbund zwischen Zwischentabelle1 und Teil über teilNr gebildet. Es entsteht Zwischentabelle2. 3. Es wird der natürliche Verbund zwischen Zwischentabelle2 und TeilLagertIn über teilNr gebildet. Es entsteht Zwischentabelle3. 4. Es wird der natürliche Verbund zwischen Zwischentabelle3 und TeileLager gebildet. Es entsteht die Ausgangstabelle. Wenn man jetzt die Abarbeitungsvorschrift genau betrachtet, fällt auf, dass dieser natürliche Verbund nicht wie gewünscht ausschließlich über teileLagerNr geht, sondern auch über die Spalten ort, strasse, hausNr und plz. Damit kommt hier der natürliche Verbund nur dann zum Tragen, falls die Bedingungen der umgangssprachlichen Formulierung der Anfrage von Beispiel 7.78 gelten und gleichzeitig der Zulieferer dieselbe Adresse wie das Teilelager hat. Vermutlich wird es also eine leere Ausgangstabelle und damit kein Ergebnis geben. Beispiel 7.78: Natürlicher Verbund mit unerwarteter Semantik „Bei welchen Teilen liegt der aktuelle Lagerbestand in einem Lager unter 50? Gib die Teile zusammen mit den Zulieferern und dem betroffenen Lager aus.“ SELECT FROM WHERE
teilNr, teilBez, teileLagerNr, teileLagerBez, zuliefererNr, zuliefererName Zulieferer NATURAL JOIN Liefert NATURAL JOIN Teil NATURAL JOIN TeilLagertIn NATURAL JOIN TeileLager istBestand < 50;
Dieses Beispiel zeigt, dass man mit dem natürlichen Verbund sehr vorsichtig umgehen muss. Er verbindet nicht, wie man intuitiv annehmen mag, Tabellen über den Fremdschlüssel miteinander, sondern über alle Spalten mit dem gleichen Namen. Hier kann es auch zu dem unangenehmen Nebeneffekt kommen, dass eine bis dato korrekte SQL-Anweisung nach einer Schemaänderung keine korrekten Ergebnisse mehr liefert, da beispielsweise in eine der beteiligten Tabellen eine Spalte eingefügt wurde, die bereits unter dem gleichen Namen in einer anderen Tabelle existierte.
358
7 Die relationale Datenbanksprache SQL Verbundoperation
• •
SQL-92
alter Standard
Kartesisches Produkt
FROM
Tab1 CROSS JOIN Tab2
FROM
Tab1 , Tab2
natürlicher Verbund
FROM
Tab1 NATURAL [INNER] JOIN Tab2
FROM WHERE
Tab1 , Tab2 Tab1 .attr1 = Tab2 .attr1 AND Tab1 .attr2 = Tab2 .attr2
Spaltennamenverbund
FROM
Tab1 [INNER] JOIN Tab2 USING (attr1 )
FROM WHERE
Tab1 , Tab2 Tab1 .attr1 = Tab2 .attr1
Bedingungsverbund
FROM
Tab1 [INNER] JOIN Tab2 ON attr3 = attr4
FROM WHERE
Tab1 , Tab2 Tab1 .attr3 = Tab2 .attr4
äußerer Verbund73
FROM
Tab1 NATURAL OUTER JOIN Tab2
FROM WHERE
Tab1 , OUTER Tab2 Tab1 .attr1 = Tab2 .attr1 AND Tab1 .attr2 = Tab2 .attr2
Tab1 und Tab2 sind Tabellen. attr1 , attr2 , attr3 und attr4 sind Spalten der Tabellen Tab1 und Tab2 , wobei attr1 und attr2 in beiden Tabellen vorkommen (gleicher Name, typkompatibel). attr3 stammt aus Tab1 und ist typkompatibel mit attr4 von Tab2 .
Tabelle 7.11: Vergleich der Verbundbedingung nach altem und SQL-92-Standard74
Beispiel 7.79: (Un)eingeschränkter Verbund uneingeschränkter Verbund: SELECT ... FROM Zulieferer INNER JOIN LieferantenRechnung USING (zuliefererNr) eingeschränkter Verbund: SELECT ... FROM Zulieferer INNER JOIN LieferantenRechnung USING (zuliefererNr) WHERE zuliefererName = ’PasstNix GmbH’; /* zusätzliche Einschränkung
Tabelle 7.11 vergleicht die alte Variante der Verbundbedingung, wie sie von vielen SQLDialekten noch unterstützt wird, mit der konzeptuell saubereren Variante des SQL-92-Standards. Tabelle 7.12 gibt einen vergleichenden Überblick über die mit einer Verbundoperation verbundenen Kosten. Beim Thetaverbund wird unterstellt, dass die Verbundbedingung nicht auf Gleichheit beruht, da er sonst dem Spaltennamenverbund entsprechen würde. Ein Verbund wird als eingeschränkt bezeichnet, wenn es neben der eigentlichen Verbundbedingung weitere Bedingungen gibt, die von der Ergebnistabelle des Verbundes zu erfüllen sind. Diese zusätzlichen Bedingungen stehen üblicherweise in der WHERE-Klausel. 73 Hier sind wieder alle Varianten wie beim inneren Verbund möglich. Da sie identisch zum inneren Verbund zu formulieren sind, ist hier nur beispielhaft der natürliche äußere Verbund spezifiziert worden. Die hier angegebene „alte“ Variante ist eine mögliche Formulierung. Nicht jeder SQL-Dialekt unterstützt den äußeren Verbund und die, die ihn anbieten, tun dies oft in einer anderen Form. 74 Man beachte, dass SQL-92 auch eine Formulierung von Verbunden entsprechend der „alten“ Variante erlaubt.
7.3 Die Datenbankanfragesprache (DRL)
359
innerer eingeschränkter Spaltennamenverbund
äußerer eingeschränkter Spaltennamenverbund
innerer eingeschränkter Thetaverbund
äußerer eingeschränkter Thetaverbund
innerer eingeschränkter Spaltennamenverbund
−
>
–
innerer uneingeschränkter Spaltennamenverbund
>
(>)
?
?
äußerer uneingeschränkter Spaltennamenverbund
>
>
?
?
innerer uneingeschränkter Thetaverbund
>
(>)
>
(>)
äußerer uneingeschränkter Thetaverbund
>
>
>
>
innerer uneingeschränkter Spaltennamenverbund
äußerer uneingeschränkter Spaltennamenverbund
innerer uneingeschränkter Thetaverbund
äußerer uneingeschränkter Thetaverbund
innerer eingeschränkter Spaltennamenverbund
| ≥ | < | ≤ } Beispiel 7.87: Einfaches Vergleichsprädikat produktNr = 161616 name ≥ ’L’
wahr, falls die Produktnummer ungleich 161616 ist wahr, falls der Name mit L oder einem späteren Buchstaben des Alphabets anfängt uhrzeit ≤ TIME ’10:15:00’ wahr, falls die Uhrzeit einen Wert kleiner als 10:15 aufweist Voraussetzung für einen korrekten Vergleich ist, dass auf beiden Seiten des Vergleichsoperators typkompatible Datentypen stehen. Das Ergebnis eines solchen Ausdrucks ist einer der Wahrheitswerte (TRUE, FALSE oder UNKNOWN). Beispiel 7.88: Einfache Bedingung 1. „Gib alle Mitarbeiter aus, deren Vorname dem Nachnamen entspricht.“ SELECT FROM WHERE
∗ Mitarbeiter mitarbeiterVorname=mitarbeiterName;
2. „Gib alle Produkte aus, deren Lagerbestand in einem Lager unter 100 liegt.“ SELECT FROM WHERE
produktNr ProduktLagertIn istBestand < 100;
366
7 Die relationale Datenbanksprache SQL
3. „Bei welchen Teilen ist der Mindestbestand von zehn Stück pro Lager unter- oder der Höchstbestand von 1000 Stück pro Lager überschritten?“ SELECT FROM WHERE
∗ Teil istBestand NOT BETWEEN 10 AND 1000;
4. Als guter Chef wollen Sie es nicht versäumen, Mitarbeitern zu ihrem silbernen Firmenjubiläum zu gratulieren. Mit folgender Anfrage lassen sich die entsprechenden Mitarbeiter ermitteln: SELECT FROM WHERE
mitarbeiterName, mitarbeiterVorname Mitarbeiter CURRENT_DATE-einstellung ≥ INTERVAL ’25’ YEAR AND CURRENT_DATE-einstellung < INTERVAL ’26’ YEAR83 ;
Grundsätzlich können in SQL-92 aus Gründen der Orthogonalität die Spaltenwerte arithmetische Ausdrücke darstellen, so dass Bedingungen der folgenden Art erlaubt sind: WHERE a − e ≤ b ∗ c + d 7.3.3.2
Logische Junktoren
Über die logischen Junktoren AND und OR können einfache, d. h. nicht mehr weiter zerlegbare Prädikate zu komplexeren Prädikaten zusammengesetzt werden. NOT ermöglicht die Negierung eines Prädikates. Die den Junktoren zu Grunde liegende Semantik ist die übliche und kann der Tabelle 7.13 entnommen werden. NOT
Schließt all diejenigen Zeilen aus, die die dem NOT folgende Bedingung erfüllen.
AND
Sowohl die vor als auch die nach dem AND stehende Bedingung müssen erfüllt sein.
OR
Entweder die vor oder nach dem OR stehende Bedingung muss erfüllt sein (oder beide).
Tabelle 7.13: Semantik der Booleschen Operatoren
Beispiel 7.89: Komplexe Bedingung 1. „Gib alle Mitarbeiter aus, die den gleichen Nachnamen haben.“ SELECT FROM WHERE
M1 .mitarbeiterNr, M1 .mitarbeiterName, M1 .mitarbeiterVorname, M2 .mitarbeiterNr, M2 .mitarbeiterName, M2 .mitarbeiterVorname Mitarbeiter AS M1 INNER JOIN Mitarbeiter AS M2 M1 .mitarbeiterName = M2 .mitarbeiterName AND M1 .mitarbeiterNr = M2 .mitarbeiterNr;
83 Die hier denkbare Formulierung INTERVAL ’25’ YEAR ≤ CURRENT_DATE-einstellung < INTERVAL ’26’ YEAR ist in SQL-92 nicht möglich. Sie kann nur über die BETWEEN-Klausel simuliert werden (CURRENT_DATEeinstellung BETWEEN INTERVAL ’25’ YEAR AND INTERVAL ’26’ YEAR). Wegen der bekannten Probleme mit Intervallen (nicht feingranular genug), können alle Lösungen nur als angenäherte Lösungen angesehen werden. Um eine exakte Lösung zu erhalten, müsste eigentlich mit einem tagebasierten Intervall gearbeitet werden.
7.3 Die Datenbankanfragesprache (DRL)
367
Bei dieser M1 .mitarbeiterNr = M2 .mitarbeiterNr-Variante wird immer noch jeder Datensatz zweimal ausgegeben, einmal mit dem ersten Mitarbeiter als erstes und das zweite Mal mit dem zweiten Mitarbeiter als erstes. Soll dies vermieden werden, bringt folgende Variante Abhilfe: WHERE
(M1 .mitarbeiterName = M2 .mitarbeiterName) AND (M1 .mitarbeiterNr > M2 .mitarbeiterNr);
oder (M1 .mitarbeiterNr < M2 .mitarbeiterNr); 2. „Gib alle Rechnungen des Lieferanten VersprechViel GmbH aus, die das Teil mit der Nummer 123321 enthalten und im Jahre 2014 ausgestellt wurden.“ SELECT FROM WHERE
LieferantenRechnung.∗ LieferantenRechnung NATURAL JOIN RechnungsPosition NATURAL JOIN AuftragsPosition NATURAL JOIN Zulieferer zuliefererName = ’VersprechViel GmbH’ AND datum BETWEEN DATE ’2014-01-01’ AND DATE ’2014-12-31’ AND teilNr = 123321;
Die mit den logischen Junktoren verbundenen Vorrangregeln lauten: NOT geht vor AND geht vor OR84 Beispiel 7.90: Vorrangregelung der logischen Operatoren SELECT FROM WHERE
7.3.3.3
∗ Tabelle a OR b AND NOT c OR NOT d AND e
∼ =
SELECT FROM WHERE
∗ Tabelle a OR (b AND (NOT c)) OR ((NOT d) AND e)
Nullmarken
Nullmarken waren bereits in Kapitel 7.2.2.3 eingeführt worden. In diesem Abschnitt soll erläutert werden, wie sich die Existenz von Nullmarken auf die Verarbeitung von Bedingungen, Prädikaten und arithmetischen Ausdrücken in Anfragen auswirkt. NULL-Prädikat Über das NULL-Prädikat kann festgestellt werden, ob ein Spaltenwert einer Zeile mit der Nullmarke belegt ist. Das Prädikat arbeitet auf allen Datentypen, da qua definitionem die Nullmarke automatisch zu jedem Basisdatentyp und als Default zu jedem benutzerdefinierten Wertebereich85 dazugehört. Syntax 7.34: NULL-Prädikat NULL-Prädikat ::= SpaltenName IS [NOT] NULL 84 In Tabelle 7.23 auf Seite 408 werden die Vorrangregeln der wichtigsten Prädikate und Operatoren von SQL gegenübergestellt. 85 Die Nullmarke kann jedoch explizit aus dem Wertebereich ausgeschlossen werden.
368
7 Die relationale Datenbanksprache SQL
Beispiel 7.91: NULL-Prädikat „Finde alle Mitarbeiter, die noch keiner Abteilung zugeordnet sind.“ SELECT FROM WHERE
∗ Mitarbeiter abteilungsNr IS NULL;
Achtung 7.10: Belegung einer Spalte mit der Nullmarke Die Sonderrolle, die die Nullmarke in SQL spielt, kommt auch dadurch zum Ausdruck, dass dies der einzige „Wert“ ist, dessen Existenz ausschließlich über ein speziell dafür eingeführtes Prädikat abgeprüft werden muss. Die Anfrage attr1 = NULL ist zwar syntaktisch korrekt, liefert aber unabhängig vom Wert von attr1 immer das Ergebnis FALSE86 . Das NULL-Prädikat kann grundsätzlich auch auf strukturierte Daten angewendet werden. Hierunter sind Spalten zu verstehen, die über eine Klammerung zu einer komplexeren Einheit zusammengefasst wurden, also beispielsweise die Spalten (ansprechPartner, ansprechpartTelNr) von Zulieferer. Das Prädikat liefert dabei immer nur dann den Wert TRUE, falls der Wert jeder Spalte des strukturierten Datums der Nullmarke entspricht. Auch bei der NOT NULL-Variante gilt, dass keiner der atomaren Werte der Nullmarke entsprechen darf, damit ein TRUE herauskommt. Für (ansprechPartner, ansprechpartTelNr) liefert also nur die folgende Kombination von Spaltenwerten pro Prädikatvariante den Wert TRUE. • (Nullmarke, Nullmarke) IS NULL liefert als einzige Kombination TRUE • (¬ Nullmarke, ¬ Nullmarke) IS NOT NULL liefert als einzige Kombination TRUE Jede ungleiche Kombination liefert bei beiden Varianten grundsätzlich als Ergebnis FALSE. Beispiel 7.92: Das NULL-Prädikat und strukturierte Daten „Bei welchen Zulieferern ist weder deren Ansprechpartner noch dessen Telefonnummer bekannt?“ SELECT FROM WHERE
∗ Zulieferer (ansprechPartner, ansprechpartTelNr) IS NULL;
Während die Überprüfung, ob eine Spalte mit der Nullmarke belegt ist, immer zu einem eindeutigen Ergebnis führt (TRUE oder FALSE), ist die Auswertung von Ausdrücken, in denen Nullmarken vorkommen, auf den ersten Blick nicht immer intuitiv. Das Hauptproblem liegt in der nicht eindeutigen Semantik der Nullmarke, was in der Regel dazu führt, dass das Ergebnis eines Ausdruckes nicht bestimmt werden kann, also UNKNOWN ist. 86 Etwas gewöhnungsbedürftig ist hier, dass attr = NULL immer FALSE liefert, während attr = attr UNKNOWN 1 1 2 liefert, falls attr1 oder attr2 mit der Nullmarke belegt ist.
7.3 Die Datenbankanfragesprache (DRL)
369
Nullmarken in Vergleichen Wegen der nicht eindeutigen Semantik der Nullmarke liefert ein Vergleich, bei dem einer der beteiligten Vergleichsoperanden mit der Nullmarke belegt ist, immer als Ergebnis nicht bekannt (UNKNOWN). Feststellung 7.7: Nullmarken in Vergleichen attr1 θ Konstante und attr1 θ attr2 liefern mit einer Ausnahme immer das Ergebnis UNKNOWN, sofern attr1 und/oder attr2 mit der Nullmarke belegt sind87 . Bei Ausdrücken wird als Ergebnis also nicht die Nullmarke zurückgeliefert, sondern der Wert UNKNOWN. Er soll ausdrücken, dass das Ergebnis des Ausdruckes nicht berechnet werden kann, da eine Nullmarke beteiligt ist, deren genaue Semantik aus den diskutierten Gründen nicht bekannt ist. Nullmarken in skalaren Ausdrücken Skalare Ausdrücke können nicht (eindeutig) berechnet werden, wenn Nullmarken beteiligt sind. Damit liefern auch sie das Ergebnis UNKNOWN. Feststellung 7.8: Nullmarken in skalaren Ausdrücken Bei skalaren Ausdrücken kommt als Ergebnis immer dann UNKNOWN heraus, falls die Nullmarke mindestens einmal als Operand in dem Ausdruck/der Berechnung vorkommt. Beispiel 7.93: Skalare Ausdrücke und Nullmarken 1. x + y 3. x − y 5. x/y 2. (x + y) ∗ z 4. x/y + y ∗ z 6. x − y + z/x ∗ y liefern als Ergebnis alle UNKNOWN, falls einer der Operanden mit der Nullmarke belegt ist. Obwohl Feststellung 7.8 bei den gegebenen Beispielen sicherlich schnell einleuchtet, gibt es bei näherer Betrachtung durchaus Probleme. Entsprechend der Regel ist das Resultat von 3. selbst dann nicht bekannt, wenn x = y wäre (beide mit der Nullmarke belegt) und somit x − x berechnet würde, obwohl die mathematischen Gesetze hier etwas anderes sagen (0). Hier ist wieder zu berücksichtigen, dass eine mit NULL belegte Spalte auch bedeuten kann, dass die Spalte im konkreten Fall nicht zutrifft. Falls x für Gehalt steht, könnte damit beispielsweise ein Praktikant gemeint sein, der kein Gehalt bekommt. Das DBMS kann Situationen und deren konkrete Semantik nicht kennen und damit auch nicht berücksichtigen. Es muss deshalb ein Ergebnis liefern, welches in jeder möglichen Situation korrekt ist, und das bedeutet, dass auch im obigen Fall auf UNKNOWN entschieden werden muss. Ein schwierigeres Beispiel ist die Division (5.). Sollte x mit NULL belegt sein und y den Wert 0 aufweisen, läge die Division eines numerischen Wertes durch 0 vor. Da dies nicht 87 Falls die Konstante die Nullmarke repräsentiert, würde wegen Fußnote 86 auf Seite 368 in Achtung 7.10 das Ergebnis FALSE sein.
370
7 Die relationale Datenbanksprache SQL
definiert ist, muss als Ergebnis eines solchen Versuches an sich die Fehlermeldung „Nicht erlaubte Division durch 0“ erscheinen. Da der Dividend allerdings die Nullmarke ist, ist das Ergebnis doch definiert, nämlich UNKNOWN (NULL /0 = UNKNOWN). Nullmarken in Booleschen Ausdrücken Boolesche Ausdrücke beruhen normalerweise auf einer zweiwertigen Logik, was heißt, dass das Resultat eines Ausdruckes entweder wahr oder falsch ist. Mit der Einführung der Nullmarke wird aus der zweiwertigen Logik eine dreiwertige. Damit muss auch definiert werden, was das Ergebnis eines Booleschen Ausdruckes unter der dreiwertigen Logik ist. Für die von SQL unterstützten Booleschen Operatoren AND, OR und NOT liefert Tabelle 7.14 die Ergebnisse für Wert1 AND Wert2 , Wert1 OR Wert2 und NOT Wert1 .88 Wert1 AND Wert2 TRUE FALSE UNKNOWN
TRUE
FALSE
UNKNOWN
NOT Wert1
TRUE
FALSE
UNKNOWN
FALSE
FALSE
FALSE
UNKNOWN
FALSE
UNKNOWN
Wert1
TRUE
FALSE
FALSE
TRUE
UNKNOWN
UNKNOWN
TRUE
FALSE
UNKNOWN
TRUE
TRUE
TRUE
TRUE
FALSE
TRUE
FALSE
UNKNOWN
UNKNOWN
TRUE
UNKNOWN
UNKNOWN
OR
Wert2
Tabelle 7.14: Wahrheitstabellen für die dreiwertige Logik
Die Konsistenzprobleme, die die Erweiterung der Wahrheitswerte um die Nullmarke verursacht, kann man dem folgenden simplen Beispiel entnehmen.
Beispiel 7.94: Probleme mit Nullmarken Es gelten die folgenden nicht symmetrischen Aussagen Wahrheitswert AND NOT Wahrheitswert = FALSE NULL AND NOT NULL = UNKNOWN 88 Bei den Tabellen ist UNKNOWN als Synonym für den Wert UNKNOWN und den „Wert“ NULL zu sehen. Stellt Wertx einen Spaltenwert dar, so kann er zwar mit NULL belegt sein, aber nicht mit UNKNOWN. Ist Wertx jedoch das Ergebnis der Auswertung eines Ausdruckes, so kann er nicht die Nullmarke, sondern nur den Wert UNKNOWN repräsentieren.
7.3 Die Datenbankanfragesprache (DRL)
371
Auch hier lassen sich wieder diverse Beispiele finden, wo eine auf diesen Wahrheitstabellen beruhende Anfrage an die DB zu anderen Ergebnissen führen würde, als der Benutzer es normalerweise erwarten würde. Achtung 7.11: NOT Prädikat und Prädikat IS NOT TRUE sind nicht äquivalent Wie man Tabelle 7.14 (NOT Wert1 -Tabelle)) und Tabelle 7.15 entnehmen kann, ist in SQL NOT Prädikat nicht äquivalent zu Prädikat IS NOT TRUE, ein Umstand, der sicherlich nicht ganz einfach nachzuvollziehen ist. Dabei gibt die Zeile in Tabelle 7.14 das Gesamtprädikat und die Spalte das Ergebnis der Auswertung des zu Grunde liegenden Prädikats Prädikat an. Die Auswertung von NOT Prädikat ergibt den Wert UNKNOWN, falls die Auswertung von NOT Prädikat den Wert UNKNOWN liefert. Dagegen liefert Prädikat IS NOT TRUE den Wert TRUE unter den gleichen Umständen. Prädikat
TRUE
FALSE
UNKNOWN
Prädikat IS TRUE
TRUE
FALSE
FALSE
Prädikat IS NOT TRUE
FALSE
TRUE
TRUE
Prädikat IS FALSE
FALSE
TRUE
FALSE
Prädikat IS NOT FALSE
TRUE
FALSE
TRUE
Prädikat IS UNKNOWN
FALSE
FALSE
TRUE
Prädikat IS NOT UNKNOWN
TRUE
TRUE
FALSE
Tabelle 7.15: Das Ergebnis bedingter Ausdrücke in SQL
Da die Semantik der Nullmarke sehr mannigfaltig sein kann, wird sie als ein spezieller, individueller Wert angesehen, der sich nicht mit anderen Nullmarken vergleichen lässt. Obwohl diese Regel in ihrer Tendenz sicherlich als korrekt angesehen werden kann, resultieren aus ihr doch die bereits oben angesprochenen Schwierigkeiten. Aus diesem Grund gibt es durchaus Vorschläge, die Semantik von Nullmarken noch weiter zu differenzieren. So schlägt zum Beispiel Edgar Codd vor, dass eine vierwertige Logik eingeführt werden sollte, indem die Nullmarke durch zwei Nullmarken mit den Semantiken „nicht bekannt“ und „Attribut nicht anwendbar“ ersetzt wird. Klar ist, dass jede feinere Differenzierung auch zu wesentlich mehr Komplexität und damit Fehleranfälligkeit führt. Klar ist ebenso, dass diese Differenzierung der Nullmarke nur eine von vielen möglichen ist und es noch weitere, insbesondere weitergehendere geben könnte. In der Praxis hat sich keine weitere Differenzierung durchsetzen können, so dass die dreiwertige Logik als der gegenwärtige State-of-the-Art akzeptiert werden muss. Achtung 7.12: Anfragen und Nullmarken Das Ergebnis einer Anfrage an die DB spiegelt grundsätzlich nur das Wissen der DB über die Realwelt wider. Dieses muss nicht unbedingt mit den realen Gegebenheiten (exakt) übereinstimmen. Insbesondere bei der Formulierung von Anfragen, die mit einem Vergleichsoperator arbeiten, muss die Existenz von Nullmarken berücksichtigt werden. Sonst kann es zu bösen Überraschungen kommen.
372
7 Die relationale Datenbanksprache SQL
Beispiel 7.95: Anfragen und Nullmarken Angenommen, Ihnen fällt um 23:00 Uhr abends noch ein, dass Sie Ihren Mitarbeiter Schmidt (so heißt jeder zweite in Ihrem Unternehmen) noch dringend zu einem Vorgang befragen müssen. Sie kennen leider seine Telefonnummer nicht, glauben aber, dass er in Essen wohnt, wodurch der Suchraum schon erheblich eingeschränkt wird. Da Sie sich zu helfen wissen, stellen Sie die folgende Anfrage an die DB: SELECT FROM WHERE
∗ Mitarbeiter mitarbeiterName = ’Schmidt’ AND ort = ’Essen’;
Ihre anfängliche Euphorie weicht einer gewissen Ernüchterung, als sie feststellen, dass die Anfrage nicht die erhoffte Adresse liefert. Kennen Sie Ihre Mitarbeiter doch nicht so gut, wie Sie immer gemeint haben? Nun ja, da die erste Anfrage ein Fehlschlag war, probieren Sie es jetzt mit der folgenden: SELECT FROM WHERE
∗ Mitarbeiter mitarbeiterName = ’Schmidt’ AND NOT(ort = ’Essen’);
Auch jetzt erhalten Sie nicht das gewünschte Ergebnis und denken noch so bei sich: „Ist zwar gut, dass dem Schmidt gekündigt worden ist, wo der schon so früh Feierabend macht. Aber man hätte mich doch wenigstens darüber unterrichten können.“ Zum Glück für Herrn Schmidt liegt hier der typische Denkfehler nach Achtung 7.12 vor. In Gegenwart der Nullmarke gilt die in der Realwelt üblicherweise gültige Aussage P OR NOT (P ) nicht. Dementsprechend liefert ((ort = ’Essen’) OR NOT (ort = ’Essen’)) nicht alle Mitarbeiter, sondern nur die, deren Wohnort bekannt ist. Bei drei Wahrheitswerten müssen auch drei Möglichkeiten überprüft werden, so dass unsere Anfrage noch durch OR ort IS NULL ergänzt werden müsste, um wirklich alle Mitarbeiter zu erhalten. Feststellung 7.9: Ermittlung des Ergebnisses bei Existenz von Nullmarken Bei der Auswertung einer Bedingung wird eine Zeile nur dann als gültig anerkannt, wenn die Bedingung für diese Zeile explizit zu TRUE evaluiert. Ist das Ergebnis einer Auswertung also UNKNOWN, so wird der Datensatz vom Ergebnis ausgeschlossen. Achtung 7.13: Nullmarken und die Projektion Chris Date und Hugh Darwen, die als engagierte Kritiker der Anfragesprache SQL angesehen werden können, haben auch sehr gegen die Einführung der Nullmarken gekämpft. Neben den vielen Problemen im Detail verweisen sie dabei auf das folgende, sehr grundsätzliche Problem, das man sogar so auslegen könnte, dass mit der Einführung von Nullmarken eine relationale Anfragesprache nicht mehr abgeschlossen ist. Eine Tabelle zeichnet sich durch folgende Eigenschaften aus: 1. Es gibt mindestens einen Schlüsselkandidaten. 2. Einer der Schlüsselkandidaten muss als Primärschlüssel ausgewiesen werden.
7.3 Die Datenbankanfragesprache (DRL)
373
3. Für Spalten des Primärschlüssels sind Nullmarken nicht zugelassen. 4. Spalten, die zu Schlüsselkandidaten, nicht aber zum Primärschlüssel gehören, dürfen mit der Nullmarke belegt werden. Nehmen wir nun einmal als simples Beispiel an, dass aus einer gegebenen Ausgangstabelle über die Projektion mindestens eine Spalte des Primärschlüssels entfernt wurde. Sofern eine Anfragesprache abgeschlossen ist, muss das Ergebnis jetzt wieder eine Tabelle darstellen. Eine Tabelle muss allerdings die obigen vier Bedingungen erfüllen. War nun für keine der verbliebenen Spalten der Ausgangstabelle die Nullmarke als Wert ausgeschlossen worden, so ergibt sich ein Widerspruch, da das dritte der obigen vier Kriterien verletzt ist. In der Praxis geht man diesem Problem dadurch aus dem Weg, dass man die obigen vier Bedingungen nur für Basistabellen fordert, also für Tabellen, die in dieser Form auch im konzeptuellen Datenbankschema definiert wurden und somit physisch in der DB vorhanden sind. Aus den Basistabellen abgeleitete Tabellen werden als temporäre Tabellen angesehen, an die aus pragmatischen Gründen nicht so hohe Korrektheitskriterien gestellt werden. Wie wir später bei der Diskussion der Probleme von SQL noch sehen werden, sind Nullmarken nicht das einzige Problem von abgeleiteten Tabellen.
7.3.4
Die GROUP BY-Klausel (Bilden von Untertabellen)
Bei der Diskussion der Probleme mit Aggregatfunktionen in Kapitel 7.3.1.4.1 war u. a. angemerkt worden, dass sich mit den bisher eingeführten Möglichkeiten keine Anfrage stellen lässt, bei der Aggregatfunktionen auf Untermengen einer Tabelle ausgeführt werden sollen (siehe auch Beispiel 7.59). Um Anfragen dieser Art unterstützen zu können, bietet SQL die GROUP BY-Klausel. Sie ermöglicht das Gruppieren der Zeilen einer Ergebnistabelle auf der Basis von in der GROUP BY-Klausel aufgelisteten Spaltennamen als Gruppierungskriterium. Aggregatfunktionen werden dann pro Ausprägung des Gruppierungskriteriums berechnet. Mit der GROUP BY-Klausel lässt sich Beispiel 7.59 korrekt formulieren. Syntax 7.35: GROUP BY-Klausel GROUP BY-Klausel ::= SFW-Block GROUP BY
SpaltenNameN
Beispiel 7.96: Lösung für Beispiel 7.59 „Gib pro Lager die Anzahl der dort gelagerten Produkte aus.“ SELECT FROM GROUP BY
produktLagerBez AS lager, COUNT(produktNr) AS #produkte ProduktLagertIn produktLagerBez;
374
7 Die relationale Datenbanksprache SQL ProduktLagertIn
produktNr
produktLagerBez
istBestand
1234
Essen
1.500
1234
Frankfurt
500
1234
Hamburg
5.000
1234
München
2.000
4711
Berlin
300
4711
Essen
150
4711
Frankfurt
750
5111
Hamburg
2.000
5111
München
6.000
5809
Berlin
4.500
5809
Frankfurt
350
5809
München
1.200
6574
Hamburg
240
6574
München
350
7333
Berlin
650
7333
Frankfurt
1.400
Tabelle 7.16: Beispiel einer Ausprägung der ProduktLagertIn-Tabelle
Die exakte Arbeitsweise der GROUP BY-Klausel soll im Folgenden Schritt für Schritt anhand des obigen Beispiels erläutert werden. Gegeben sei die in Tabelle 7.16 dargestellte Ausprägung der etwas modifizierten Tabelle ProduktLagertIn89. 1. Im ersten Schritt wird die Ausgangstabelle gebildet, die im Fall von Beispiel 7.96 mit der Basistabelle ProduktLagertIn übereinstimmt. 2. Als nächstes wird die GROUP BY-Klausel abgearbeitet, was heißt, dass die Tabelle aufgrund der Werte von produktLagerBez in Untertabellen zerlegt wird. 3. Der letzte Schritt besteht aus der Erstellung der Ergebnistabelle. Zu übernehmen sind produktLagerBez (umbenannt in lager) und die Anzahl der Produkte pro Lager. Letzteres geschieht, indem die COUNT-Funktion pro Untertabelle ausgewertet wird. Bei der Nutzung der GROUP BY-Klausel sind einige Dinge zu beachten. Das Ergebnis einer SQL-Anfrage muss eine Tabelle sein, die nur aus atomaren Spalten besteht90 . Eine Aufteilung der Ergebnistabelle in Untertabellen macht nur Sinn, falls auf den dadurch erzeugten Untertabellen Aggregatfunktionen ausgeführt werden sollen. Deshalb kann die Ausgabe der 89 Aus 90 Dies
Gründen der besseren Lesbarkeit wurde die hier nicht gebrauchte Spalte produktLagerNr weggelassen. gilt nur für die Ergebnistabelle, nicht aber für Zwischentabellen (siehe auch später).
7.3 Die Datenbankanfragesprache (DRL) ProduktLagertIn
375
produktNr
produktLagerBez
istBestand
Untertabelle Berlin
4711, 5809, 7333
Berlin
300, 4.500, 650
Untertabelle Essen
1234, 4711
Essen
1.500, 150
Untertabelle Frankfurt
1234, 4711,
Frankfurt
500, 750,
5809, 7333
350, 1.400
Untertabelle Hamburg
1234, 5111, 6574
Hamburg
5.000, 2.000, 240
Untertabelle München
1234, 5111,
München
2.000, 6.000,
5809, 6574
1.200, 350
Tabelle 7.17: Aufteilung der Ausgangstabelle in Untertabellen durch die GROUP BY-Klausel
Ergebnistabelle
lager
#produkte
Berlin
3
Essen
2
Frankfurt
4
Hamburg
3
München
4
Tabelle 7.18: Ergebnis einer Anfrage mit GROUP BY-Klausel
Menge aller Produktnummern pro Lager nicht über die GROUP BY-Klausel formuliert werden, sondern nur mit Hilfe der ORDER BY-Klausel91 simuliert werden. Beispiel 7.97: Sortieren über die ORDER BY-Klausel „Gib pro Lager alle dort gelagerten Produkte aus.“ SELECT produktLagerBez AS lager, produktNr FROM ProduktLagertIn ORDER BY produktLagerBez; 91 Die
ORDER BY-Klausel wird in Kapitel 7.3.7 noch genauer eingeführt.
376
7 Die relationale Datenbanksprache SQL
Ergebnistabelle
lager
produktNr
Berlin
(Fortsetzung)
lager
produktNr
4711
Frankfurt
7333
Berlin
5809
Hamburg
1234
Berlin
7333
Hamburg
5111
Essen
1234
Hamburg
6574
Essen
4711
München
1234
Frankfurt
1234
München
5111
Frankfurt
4711
München
5809
Frankfurt
5809
München
6574
Tabelle 7.19: Ergebnis einer ORDER BY-Klausel92
Das Ergebnis dieser Anfrage kann Tabelle 7.19 entnommen werden. Der aufmerksame Leser wird anmerken, dass durch die GROUP BY-Klausel die durch SQL vorgegebenen Strukturierungsrichtlinien verletzt werden, da Spalten nicht mehr atomar sein müssen. Diese Kritik ist durchaus berechtigt und der Grund dafür, warum die mengenwertigen Spalten auch nur als Zwischenergebnis, nicht aber als Endergebnis zugelassen sind. Der Benutzer, der nur die Anfrage stellt, bekommt von der scheinbaren Verletzung der Atomaritätsregel nichts mit. Es handelt sich also ausschließlich um eine Verletzung auf der Ebene von Zwischenergebnissen und das kann toleriert werden. Die in der GROUP BY-Klausel angegebene Spaltenkombination sollte keinen Schlüsselkandidaten der Ergebnistabelle enthalten. Ansonsten ist die Gruppierung ohne Wert, da jede Zeile eine eigene Gruppe bildet. Das wiederum macht die Anwendung von Aggregatfunktionen sinnlos. Beispiel 7.98 liefert noch einmal ein falsches und ein richtiges Beispiel für die Anwendung der GROUP BY-Klausel. Beispiel 7.98: GROUP BY-Klausel 1. „Gib die Mitarbeiter nach ihrer Abteilungszugehörigkeit aus.“ fehlerhafte Variante: SELECT A.abteilungsName, M.mitarbeiterName, M.mitarbeiterVorname FROM Mitarbeiter AS M NATURAL JOIN Abteilung AS A GROUP BY A.abteilungsName; 92 Wie man sieht, ist das Ergebnis wegen der Wiederholungen der Lagerbezeichnungen nicht mehr ganz so gut lesbar. Der SQL-Standard bietet hier keine Möglichkeiten, die Lesbarkeit zu verbessern. Doch unterstützen viele SQL-Dialekte Formatierungsbefehle (z. B. FORMAT), mit denen die Ergebnisausgabe optisch zumindest etwas ansehnlicher gestaltet werden kann. Auf einer professionelleren Ebene bleibt es den auf SQL aufsetzenden Reportgeneratoren, 4GL-Entwicklungswerkzeugen (Sprachen der vierten Generation) oder Wirts- bzw. (Host-) Sprachen überlassen, für eine schönere Präsentation zu sorgen.
7.3 Die Datenbankanfragesprache (DRL)
377
Die obige Variante ist nicht erlaubt, da sie pro Wert für abteilungsName eine Menge von Mitarbeitern liefern würde. Und mengenwertige Spalten werden durch den SQL92-Standard nicht unterstützt. richtige Variante: SELECT A.abteilungsName, M.mitarbeiterName, M.mitarbeiterVorname FROM Mitarbeiter AS M NATURAL JOIN Abteilung AS A ORDER BY A.abteilungsName, M.mitarbeiterName, M.mitarbeiterVorname; 2. „Die Statistikabteilung möchte wissen, wie viele Kunden es pro Produkttyp gibt.“ SELECT produktTyp, COUNT(kundenNr) AS kundenProProdukttyp FROM Kunden NATURAL JOIN Kauft NATURAL JOIN Produkt GROUP BY produktTyp; 7.3.4.1
Die HAVING-Klausel
Eng verbunden mit der GROUP BY-Klausel ist die HAVING-Klausel. Sie ist vergleichbar mit der WHERE-Klausel, darf allerdings immer nur im Zusammenhang mit der GROUP BYKlausel eingesetzt werden. Ihre Aufgabe besteht darin, aus der Menge der durch die GROUP BY-Klausel erzeugten Untertabellen die auszuwählen, die in die Ergebnistabelle eingearbeitet werden sollen. Während die WHERE-Klausel einzelne Zeilen aus einer Tabelle eliminiert, entfernt die HAVING-Klausel gleich ganze Untertabellen. Syntax 7.36: Erweiterte GROUP BY-Klausel Erweiterte GROUP BY-Klausel ::= SFW-Block GROUP BY SpaltenNameN [HAVING KomplexesPrädikat] Als Beispiel dient die etwas erweiterte Anfrage von Beispiel 7.96. Beispiel 7.99: HAVING-Klausel „Gib für die Lager München und Berlin die Anzahl der dort gelagerten Produkte aus.“ SELECT produktLagerBez AS Lager, COUNT(produktNr) AS #produkte FROM ProduktLagertIn GROUP BY produktLagerBez HAVING produktLagerBez = ’München’ OR produktLagerBez = ’Berlin’; Es ist unbedingt darauf zu achten, dass die in der HAVING-Klausel spezifizierte Bedingung auch tatsächlich Untertabellen als Ganzes betrifft. Die folgende Anfrage ist nicht erlaubt, wie man schnell anhand von Tabelle 7.17 überprüfen kann. Beispiel 7.100: HAVING-Klausel mit unerlaubter Bedingung „Gib pro Lager die Anzahl der dort gelagerten Produkte mit einem kleineren Bestand als 500 aus.“
378
7 Die relationale Datenbanksprache SQL SELECT produktLagerBez AS lager, COUNT(produktNr) AS #produkte FROM ProduktLagertIn GROUP BY produktLagerBez HAVING istBestand < 500;
In Beispiel 7.100 will man keine Untertabellen aussortieren. Stattdessen sollen innerhalb der Untertabellen in der mengenwertigen Spalte istBestand alle Werte gelöscht werden, die größer gleich 500 sind. Nur sind die Auswirkungen dieser Löschaktion auf die anderen Spalten der Untertabelle, insbesondere produktNr, nicht mehr ermittelbar, wie man unmittelbar anhand von Tabelle 7.17 nachvollziehen kann. Deshalb würde für #produkte mit hoher Wahrscheinlichkeit ein nicht korrektes Ergebnis geliefert. Achtung 7.14: HAVING-Klausel muss tabellenbezogen ausgelegt sein Die WHERE-Klausel und die HAVING-Klausel dienen beide der Selektion von Daten. In der WHERE-Klausel werden Zeilen selektiert, in der HAVING-Klausel (Unter-)Tabellen. Deshalb muss die in der HAVING-Klausel spezifizierte Bedingung so ausgelegt sein, dass sie aus der durch die GROUP BY-Klausel erzeugten Menge von Untertabellen die Gewünschten auswählt. Die obigen Ausführungen implizieren bereits die Abarbeitungsreihenfolge der Klauseln. Nach der FROM-Klausel wird zunächst die GROUP BY-Klausel und dann die HAVING-Klausel abgearbeitet. Existiert auch eine WHERE-Klausel, so wird diese vor der GROUP BY-Klausel ausgewertet. FROM-Klausel → WHERE-Klausel → GROUP BY-Klausel → HAVING-Klausel → SELECT-Klausel Die zusätzliche Bedingung von Beispiel 7.100 muss über die WHERE-Klausel abgedeckt werden, da sie zeilenbezogen arbeitet. Beispiel 7.101: Korrekte Version der Anfrage von Beispiel 7.100 „Gib pro Lager die Anzahl der dort gelagerten Produkte mit einem kleineren Bestand als 500 aus.“ SELECT produktLagerBez AS lager, COUNT(produktNr) AS #produkte FROM ProduktLagertIn WHERE istBestand < 500 GROUP BY produktLagerBez; Kommen wir noch einmal auf die Frage zurück, wann eine HAVING-Klausel korrekt formuliert ist. Die einfachste Variante ist, dass in der HAVING-Klausel ausschließlich Bedingungen an Spalten gestellt werden, die auch in der GROUP BY-Klausel genannt wurden (siehe auch Beispiel 96). Diese Variante kann auch immer durch eine Anfrage abgedeckt werden, bei der die HAVING-Klausel durch eine WHERE-Klausel mit der gleichen Bedingung ersetzt wird. Syntax 7.37: Einfachste Variante einer korrekten HAVING-Klausel Beim folgenden Beispiel wird mit zwei Spalten in der GROUP BY-Klausel gearbeitet. Im allgemeinen Fall können es beliebig viele sein.
7.3 Die Datenbankanfragesprache (DRL)
379
SELECT attr1 , attr2 , SUM(attr3 ) FROM AusgangsTabelle GROUP BY attr1 , attr2 HAVING attrx θ Wert[LogischerOperator attry θ Wert]∗ ; Die obige Formulierung ist äquivalent zu der Folgenden: SELECT attr1 , attr2 , SUM(attr3 ) FROM AusgangsTabelle WHERE attrx θ Wert [LogischerOperator attry θ Wert]∗ ; GROUP BY attr1 , attr2 ; LogischerOperator ::= { AND | OR } x, y ∈ {1, 2} Die zweite Variante ist, dass in der HAVING-Klausel eine Bedingung für eine Spalte S spezifiziert wird, die in einer 1:1-Beziehung zu der Spaltenkombination SK der GROUP BY-Klausel steht. Diese Variante deutet in vielen Fällen auf eine ungeschickte Formulierung hin, weil die Anfrage mit Sicherheit besser lesbar wäre, wenn entweder SK in der GROUP BY-Klausel durch S ersetzt oder die Bedingung in der HAVING-Klausel statt auf der Basis von S auf der Basis von SK formuliert würde. Beispielsweise hätte die Bedingung der HAVING-Klausel von Beispiel 7.99 auch über produktLagerNr formuliert werden können. Die Lesbarkeit der Anfrage würde dadurch allerdings leiden, da der durchgängige rote Faden produktLagerBez dann nicht mehr erkennbar wäre. Beispiel 7.102: HAVING-Klausel „Gib für die Lager München und Berlin die Anzahl der dort gelagerten Produkte aus.“ SELECT produktLagerBez AS lager, COUNT(produktNr) AS #produkte FROM ProduktLagertIn GROUP BY produktLagerNr HAVING produktLagerBez = ’München’ OR produktLagerBez = ’Berlin’; Die dritte Variante ist eine sehr interessante, da sie eine besondere Spezialität der HAVINGKlausel repräsentiert. Die Bedingung könnte auch über die mengenwertigen Spalten der Untertabellen gehen, sofern sie in Form einer Aggregatfunktion gestellt würde. Syntax 7.38: HAVING-Klausel mit Aggregatfunktion SELECT attr1 , attr2 , SUM(attr3 ) FROM AusgangsTabelle GROUP BY attr1 , attr2 HAVING Aggregatfkt(attrx ) [Aggregatfkt(attry )]∗ ; x, y bezeichnen mengenwertige Spalten
380
7 Die relationale Datenbanksprache SQL
Beispiel 7.103: HAVING-Klausel mit Aggregatfunktion 1 „Gib pro Lager, in dem mehr als 300 Produkte lagern, die Anzahl der dort gelagerten Produkte und deren Gesamtmenge aus, sofern die Gesamtmenge der gelagerten Produkte unter 10.000 liegt.“ produktLagerBez AS lager, COUNT(produktNr) AS #produkte, SUM(istBestand) AS gesamtMenge FROM ProduktLagertIn NATURAL JOIN ProduktLager GROUP BY produktLagerBez HAVING COUNT(produktNr) > 300 AND SUM(istBestand) < 10000;
SELECT
In der HAVING-Klausel dürfen Aggregatfunktionen verwendet werden, während dies in der WHERE-Klausel verboten ist93 . Genau genommen stellt dies auch den eigentlichen Reiz der HAVING-Klausel dar. Soll beispielsweise der Durchschnittspreis jeder Produktgruppe, außer den Geschirrspülern und Waschmaschinen, bestimmt werden, so könnte man diese Selektionsbedingung sowohl in der WHERE- als auch in der HAVING-Klausel formulieren. Beispiel 7.104: Alternative Verwendung von WHERE- und HAVING-Klausel „Ermittle den Durchschnittspreis der Produkte jedes Produkttyps mit Ausnahme der Produkttypen Geschirrspüler und Waschmaschine.“ Variante 1: SELECT produktTyp, AVG(nettoPreis) AS ∅nettoPreis FROM Produkt WHERE produktTyp NOT IN (’Geschirrspüler’, ’Waschmaschine’) GROUP BY produktTyp; Variante 2: SELECT produktTyp, AVG(nettoPreis) AS ∅nettoPreis FROM Produkt GROUP BY produktTyp HAVING produktTyp NOT IN (’Geschirrspüler’, ’Waschmaschine’); Möchte man jedoch nur die teuren Produktgruppen (Durchschnittspreis über 500,– C) mit ihrem Durchschnittspreis ausgegeben haben, so kann dies nur über die HAVING-Klausel formuliert werden. Beispiel 7.105: HAVING-Klausel mit Aggregatfunktion 2 1. „Ermittle den Durchschnittspreis der Produkttypen, sofern er über 500,– C liegt.“ SELECT produktTyp, AVG(nettoPreis) AS ∅nettoPreis FROM Produkt GROUP BY produktTyp HAVING AVG(nettoPreis) > 500;
93 Allerdings dürfen sie wohl in einer dort spezifizierten Unteranfrage benutzt werden; sie werden dann aber der Unteranfrage und nicht der WHERE-Klausel zugeordnet.
7.3 Die Datenbankanfragesprache (DRL)
381
2. „Ermittle die Anzahl von Rechnungen mit mehr als zehn Rechnungspositionen.“ SELECT COUNT(∗) AS anzahlUmfangreicherRechnungen FROM RechnungsPosition GROUP BY rechnungsNr HAVING COUNT(rechnungsPos) > 10; An den obigen Beispielen kann man sehr gut sehen, dass die WHERE- und die HAVINGKlausel gleichwertig genutzt werden können, solange bei der Formulierung der Selektionsbedingung keine Aggregatfunktion eingesetzt werden muss. Eingefleischte Programmierer mögen die SQL-Anfrage in Beispiel 7.105 wegen der doppelten Berechnung des durchschnittlichen Verkaufspreises (in Beispiel 7.105 unterstrichen) als ineffiziente Implementierung ablehnen. Es sei aber nochmals darauf hingewiesen, dass SQL eine deskriptive Anfragesprache ist und demnach nur formuliert werden muss, was man möchte. Das „Wie“ wird vom System „nach Rücksprache“ mit dem Optimierer festgelegt, und der sollte solche Redundanzen natürlich erkennen und beseitigen.94 Achtung 7.15: Spaltennamen und Aggregatfunktionen in der SELECT-Klausel Wie bereits erwähnt, deutet die gemeinsame Angabe von Spaltennamen und Aggregatfunktionen in der SELECT-Klausel auf einen Denkfehler bei der Formulierung der Anfrage hin, sofern entweder keine GROUP BY-Klausel genutzt wurde oder die Spaltennamen nicht eine Obermenge der Spaltennamen in der GROUP BY-Klausel bilden. Als Faustregel gilt, dass man in der SELECT-Klausel zusätzlich zu der (den) Aggregatfunktion(en) nur dann noch Spaltennamen dazu nehmen sollte, falls man mit der GROUP BY-Klausel gearbeitet hat. In diesem Fall wird dringend angeraten, alle in der GROUP BY-Klausel benutzten Spaltennamen auch in die SELECT-Klausel aufzunehmen. Nimmt man nur eine Teilmenge auf, so wird i. d. R. Information fehlen, so dass das Ergebnis nicht korrekt interpretiert werden kann. Der umgekehrte Fall, dass die Spaltennamen der SELECT-Klausel eine Obermenge der Spaltennamen der GROUP BY-Klausel sind, kann semantisch korrekt sein, kann aber dazu führen, dass (verbotene) mengenwertige Spalten entstehen (siehe Beispiel 7.106). Beispiel 7.106: Spaltennamen in der GROUP BY- und SELECT-Klausel (inkorrekte Formulierung); siehe auch Tabelle 7.17 SELECT produktLagerBez, produktNr, COUNT (istBestand) AS gesamtMenge FROM ProduktLagertIn GROUP BY produktLagerBez; Abstrakte Formulierung: SELECT attr1 , attr2 , COUNT(attr3 ) FROM Tabelle GROUP BY attr1 ; 94 Es soll hier nicht verschwiegen werden, dass diese Aussage zunächst nur theoretischer Natur ist. Die Qualität der Optimierer und damit deren Effizienz ist von Produkt zu Produkt noch sehr schwankend und häufig noch ein Stück vom Optimum entfernt.
382
7 Die relationale Datenbanksprache SQL
Für den Fall, dass attr2 (produktNr) nicht funktional abhängig ist von attr1 (produktLagerBez), sondern umgekehrt, kann es in der Ergebnistabelle Zeilen geben, die in attr1 denselben Wert besitzen, in attr2 aber einen unterschiedlichen (alle Produkte, die im selben Lager abgelegt sind). Da nach attr1 gruppiert werden soll, darf es in der auszugebenden Ergebnistabelle95 pro Wert von attr1 höchstens eine Zeile geben. Dies wiederum würde bedeuten, dass in dieser Zeile unter attr2 mehrere Werte abgelegt werden müssten, was attr2 auf die Ebene einer mengenwertigen Spalte hieven würde. Das steht jedoch im Widerspruch zur Forderung der ersten Normalform. Ist attr2 funktional abhängig von attr1 , gilt, dass zu jedem Wert von attr1 höchstens ein Wert von attr2 existiert. Deshalb würde die Hinzunahme von attr2 in die GROUP BY-Klausel nichts an der bereits von attr1 bewirkten Gruppierung ändern, weshalb sie überflüssig ist. Die Hinzunahme von attr2 in die SELECT-Klausel kann aus Sicht der Anwendung sinnvoll sein. Auf jeden Fall ist sie semantisch eindeutig und deshalb grundsätzlich möglich. Feststellung 7.10: Verhältnis von Spaltennamen in der GROUP BY- und SELECT-Klausel Wird eine GROUP BY-Klausel verwendet, sollten die in der SELECT-Klausel angegebenen, nicht abgeleiteten Spaltennamen nur dann eine Obermenge der in der GROUP BY-Klausel aufgeführten Spaltennamen sein, falls jede zusätzliche Spalte funktional abhängig ist von den Spalten in der GROUP BY-Klausel. Bisher war immer implizit davon ausgegangen worden, dass die durch eine GROUP BYKlausel erzeugten mengenwertigen Spalten duplikatfrei96 sind oder die Existenz der Duplikate erwünscht ist97 . Sind jedoch Duplikate möglich, aber unerwünscht, kann man diese über das DISTINCT-Schlüsselwort eliminieren. In Beispiel 7.107 wird dies zunächst einmal ohne Nutzung der GROUP BY-Klausel demonstriert. Beispiel 7.107: Mengenwertige Spalten und Duplikate 1 „Gib die Anzahl aller unterschiedlichen auf Lager befindlichen Produkte aus.“ SELECT COUNT(DISTINCT produktNr) AS #produkte FROM ProduktLagertIn; Die Lösung von Beispiel 7.107 mit dem DISTINCT-Schlüsselwort funktioniert, weil die Spalte, über die die Aggregatfunktion laufen soll, duplikatfrei sein soll. Soll die Duplikatfreiheit aber für eine andere Spalte gelten, kann es schnell unübersichtlich werden, wie die folgenden Beispiele zeigen. Beispiel 7.108: Mengenwertige Spalten und Duplikate 2 „Ermittle den durchschnittlichen Verkaufspreis aller auf Lager befindlichen Produkte.“98 95 In der zur Ermittlung der Ergebnistabelle erzeugten Zwischentabelle darf es allerdings noch mengenwertige Spalten geben, da Zwischenergebnisse für den Benutzer nicht sichtbar sind und wegen ihres vorläufigen Charakters zwangsläufig noch nicht alle Regeln des Datenbankmodells erfüllen können und müssen. 96 z. B. produktNr wegen COUNT(produktNr) in Beispiel 7.103. 97 z. B. istBestand wegen SUM(istBestand) in Beispiel 7.103. 98 Bei dieser Anfrage wird unterstellt, dass der Verkaufspreis jedes Produktes in jedem Lager identisch ist, weshalb zur Berechnung des durchschnittlichen Verkaufspreises jedes Produkt auch nur genau einmal berücksichtigt werden darf.
7.3 Die Datenbankanfragesprache (DRL)
383
Die erste, naive Lösung wendet den DISTINCT-Operator noch innerhalb der Aggregatfunktion an. SELECT FROM
AVG(DISTINCT nettoPreis) AS ∅nettoPreis ProduktLagertIn NATURAL JOIN Produkt;
Es ist klar, dass die Vorgehensweise von Beispiel 7.107 hier nicht mehr funktioniert, da der SFW-Block von Beispiel 7.108 den Durchschnitt über alle unterschiedlichen Nettopreise berechnet. Unterschiedliche Produkte können aber durchaus identische Preise haben. Die nächste Idee könnte sein, den DISTINCT-Operator auf produktNr anzuwenden. Beispiel 7.109: Mengenwertige Spalten und Duplikate 3 „Ermittle den durchschnittlichen Verkaufspreis aller auf Lager befindlichen Produkte.“ SELECT [DISTINCT] produktNr; AVG(nettoPreis) AS ∅nettoPreis FROM ProduktLagertIn NATURAL JOIN Produkt; GROUP BY produktNr; Wegen der Regel, dass in der SELECT-Klausel keine Spaltennamen genannt werden dürfen, es sei denn, sie werden auch in der GROUP BY-Klausel genannt, musste die GROUP BY-Klausel eingeführt werden. Dies macht zunächst aber die Nutzung von DISTINCT überflüssig, da die GROUP BY-Klausel in diesem Fall dieselbe Funktion übernimmt. Falsch wird die Lösung jetzt durch die Gruppierung, die dafür sorgt, dass nur noch der (unsinnige) durchschnittliche Verkaufspreis je Produkt geliefert wird. Eine korrekte Lösung für dieses Beispiel lässt sich so nicht finden. Die richtige Idee ist, schon die Ausgangstabelle so auszulegen, dass sie keine Duplikate mehr enthält. Dies geschieht dadurch, dass man Anfragen schachtelt, also innerhalb einer Anfrage erneut eine Anfrage formuliert. Dies wird im nächsten Abschnitt besprochen. Wie bereits in Kapitel 7.3.2.6 angekündigt, soll an dieser Stelle noch einmal auf den Einsatz von Bedingungsverbunden, die nicht auf Gleichheit beruhen, zurückgekommen werden. Die Problematik soll anhand der Frage von Beispiel 7.110 diskutiert werden. Beispiel 7.110: Nicht auf Gleichheit beruhender Bedingungsverbund, Lösungsversuch 1 „Gib die drei in ihrer Herstellung günstigsten Produkte aus.“ SELECT FROM
P1 .produktNr, P1 .produktBez Produkt AS P1 INNER JOIN Produkt AS P2 ON (P1 .stueckKosten ≥ P2 .stueckKosten) GROUP BY P1 .produktNr99 HAVING 3 ≥ COUNT(∗);
Es darf vermutet werden, dass der Leser trotz der Tatsache, dass er Frage und SQLFormulierung schwarz auf weiß vor sich liegen hat, enorme Probleme hat, die Lösung zu 99 Man beachte hier Feststellung 7.10 auf Seite 382. Manche SQL-Dialekte erwarten an dieser Stelle aus Konsistenzgründen auch die Nennung von P1 .produktBez, obwohl dieser Ausdruck wegen der 1:1-Beziehung zwischen produktBez und produktNr an sich unnötig ist.
384
7 Die relationale Datenbanksprache SQL
verstehen. Dieses ist ein generelles Problem von Bedingungsverbunden, die nicht auf Gleichheit beruhen. Solche Anfragen sind sehr schwer korrekt zu formulieren und zu lesen und sollten deshalb möglichst vermieden werden. Der Bedingungsverbund verknüpft immer dann zwei Produktzeilen miteinander, wenn das linke Produkt genauso teuer oder teurer ist wie das rechte. In der GROUP BY-Klausel wird dann anhand der Produktnummern der linken Seite gruppiert. Jede Gruppe, die nicht mehr als drei Zeilen enthält, gehört zur Ergebnismenge, frei nach der Logik, wenn das Produkt nur teurer als höchstens drei andere Produkte ist – und in diesen dreien ist das Produkt selber auch enthalten –, dann erfüllt es die Bedingung der Anfrage. Obwohl die Anfrage auf dem ersten Blick korrekt erscheint, ist sie es dennoch nicht. Werden in der Realität die niedrigsten Stückkosten wegen identischer Kosten von mindestens vier Produkten gleichzeitig erreicht, so würde die obige Anfrage ein leeres Endergebnis liefern, was aber bei einer nicht leeren Menge nicht sein kann. Das Problem ist, dass alle Produkte mit dem gleichen Preis in der durch die GROUP BY-Klausel gebildeten Gruppe berücksichtigt werden. Eine zweite Lösungsidee könnte sein, statt des größer gleich nur mit einem größer zu operieren. Beispiel 7.111: Nicht auf Gleichheit beruhender Bedingungsverbund, Lösungsversuch 2 „Gib die drei in ihrer Herstellung günstigsten Produkte aus.“ SELECT FROM
P1 .produktNr, P1 .produktBez Produkt AS P1 INNER JOIN Produkt AS P2 ON (P1 .stueckKosten>P2 .stueckKosten) GROUP BY P1 .produktNr HAVING 3 > COUNT(∗);
Aber auch diese Lösung bereitet Probleme, da unter der gleichen Konstellation wie oben gar nicht erst die Gruppe der Produkte mit den übereinstimmenden niedrigsten Stückkosten gebildet wird. Die richtige Lösung und eine wesentlich lesbarer formulierte Alternative können Beispiel 7.112 entnommen werden. Der neu hinzugefügte OR-Teil in der FROM-Klausel stellt sicher, dass jedes Produkt mindestens einen Partner zum Vereinigen findet und dass damit die GROUP BY- und die HAVING-Klausel auch zum Tragen kommen können. Beispiel 7.112: Nicht auf Gleichheit beruhender Bedingungsverbund, korrekte Lösungen „Gib die drei in ihrer Herstellung billigsten Produkte aus.“ P1 .produktNr, P1 .produktBez Produkt AS P1 INNER JOIN Produkt AS P2 ON (P1 .stueckKosten > P2 .stueckKosten OR P1 .produktNr = P2 .produktNr) GROUP BY P1 .produktNr HAVING 3 ≥ COUNT(∗);
SELECT FROM
7.3 Die Datenbankanfragesprache (DRL)
385
Besser lesbare Alternative: SELECT P1 .produktNr, P1 .produktBez FROM Produkt AS P1 WHERE (SELECT COUNT(∗) FROM Produkt AS P2 WHERE P1 .stueckKosten > P2 .stueckKosten) < 3; Wie schnell der nicht auf Gleichheit beruhende Bedingungsverbund auch zu Laufzeitproblemen führen kann, kann man an der folgenden abstrakten Anfrage sehen. Beispiel 7.113: Explodierender Bedingungsverbund Gegeben seien die folgenden beiden abstrakten Tabellen: T1 (a, b, c) T2 (d, e, f ) Es soll die folgende Anfrage gelöst werden: SELECT FROM
∗ T1 INNER JOIN T2 ON (a = d);
Handelt es sich bei a und d um hoch selektive Spalten, beispielsweise in beiden Fällen um den Primärschlüssel, so würde die obige Anfrage in ihrer Auswirkungen fast identisch zum Kartesischen Produkt sein. Welche Probleme das in Bezug auf erzeugte Datenvolumina verursachen kann, wurde bereits in Beispiel 60 demonstriert.
7.3.5
Geschachtelte Anfragen
Wird innerhalb eines SFW-Blockes ein weiterer SFW-Block aufgerufen, spricht man von einer geschachtelten Anfrage, wobei der eingebettete SFW-Block (rekursiv) als Unteranfrage der übergeordneten Anfrage angesehen wird. Im DRL-Teil von SQL-92 dürfen Unteranfragen in der WHERE-, HAVING-, FROM- und SELECT-Klausel eingesetzt werden. Unteranfragen in der WHERE-Klausel werden in den folgenden Kapiteln noch ausführlich diskutiert. Zunächst soll anhand eines komplexen Beispiels der Einsatz von Unteranfragen in der FROM-Klausel diskutiert werden. Beispiel 7.114: Komplexe Anfrage „Ermittle pro Produkttyp den durchschnittlichen Verkaufspreis der vorrätigen Produkte und zwar einerseits pro Lager und andererseits über alle Lager.“ Nachdem der Leser nach mehrmaligem Lesen vielleicht den Sinn der Anfrage verstanden hat, muss jetzt das Problem der Anfrageformulierung gelöst werden. Wegen der Komplexität der Anfrage empfiehlt sich deren Zerlegung in Teilprobleme. In einem ersten Schritt sollte zunächst einmal die Ausgangstabelle bestimmt werden. Wenn man die
386
7 Die relationale Datenbanksprache SQL
Anfrage nach Substantiven durchsucht, stößt man auf Verkaufspreis, Lager, Produkt und Typ. Diese lassen sich in die Spalten nettoPreis, produktTyp, produktNr und produktLagerNr der Tabellen Produkt und ProduktLagertIn übersetzen. Damit besteht die Ausgangstabelle aus dem Verbund dieser beiden Tabellen: ProduktLagertIn NATURAL JOIN Produkt Als nächstes müssten die für einen Produkttyp überhaupt vorhandenen Produkte pro Lager bestimmt werden (siehe Beispiel 7.115). Beispiel 7.115: Erstes (noch inkorrektes) Zwischenergebnis für Beispiel 7.114 „Welche Produkte eines Produkttyps sind pro Lager vorhanden.“ SELECT FROM WHERE GROUP BY
produktTyp, produktLagerNr, {produktNr}100 ProduktLagertIn NATURAL JOIN Produkt istBestand > 0 produktTyp, produktLagerNr;
In der GROUP BY-Klausel wird die in der FROM-Klausel erzeugte Ausgangstabelle in Untertabellen zerlegt. Gruppierungskriterium sind dabei Produkttyp und Lager. Für jede Kombination von Werten des Paares (produktTyp, produktLagerNr) wird eine Menge erzeugt, die die Produktnummern enthält, die von diesem Typ in diesem Lager liegen.101 Mit der Ermittlung des Durchschnittspreises pro Lager und Produkttyp wird aus der obigen inkorrekten Anfrage eine korrekte (siehe Beispiel 7.116). Beispiel 7.116: Erstes korrektes Zwischenergebnis für Beispiel 7.114 „Welches ist der durchschnittliche Verkaufspreis der vorrätigen Produkte pro Produkttyp und Lager?“ SELECT FROM WHERE GROUP BY
produktTyp, produktLagerNr, AVG(nettoPreis) AS ∅nettoPreis ProduktLagertIn NATURAL JOIN Produkt istBestand > 0 produktTyp, produktLagerNr;
Damit ist der erste Teil der Anfrage gelöst und es fehlt nur noch die Berechnung des Durchschnittspreises pro Produkttyp über alle Lager. Wenn man sich diese Anforderung genauer ansieht, fällt auf, dass zur Lösung an sich nur noch einmal eine Anfrage auf der Ergebnistabelle des ersten Teils der Anfrage gestellt werden muss. 100 Die
Mengenklammer soll ausdrücken, dass es sich um eine mengenwertige Spalte handelt. in Kapitel 7.3.4 war im Anschluss an Beispiel 7.96 festgestellt worden, dass diese Anfrage so nicht gestellt werden darf, da mit {produktNr} eine Menge und keine atomare Spalte auszugeben wäre. Die korrekte Formulierung müsste über die ORDER BY-Klausel laufen. Da unsere Anfrage aber kein End-, sondern nur ein (unsichtbares) Zwischenergebnis repräsentiert, spielt diese temporäre Regelverletzung hier keine Rolle. 101 Bereits
7.3 Die Datenbankanfragesprache (DRL)
387
Dies kann erreicht werden, indem die Anfrage einfach in eine übergeordnete Anfrage eingebettet wird. Da sie die Ausgangstabelle bilden soll, muss dies in der FROM-Klausel geschehen (siehe Beispiel 7.117). Beispiel 7.117: SQL-Anfrage für den zweiten Teil der Anfrage von Beispiel 7.114 „Ermittle den Durchschnittspreis pro Produkttyp über alle Lager.“ produktTyp, AVG(∅nettoPreis) AS ∅nettoPreisÜberAlleLager (SELECT produktTyp, produktLagerNr, AVG(nettoPreis) AS ∅nettoPreis FROM ProduktLagertIn NATURAL JOIN Produkt WHERE istBestand > 0 GROUP BY produktTyp, produktLagerNr) GROUP BY produktTyp;
SELECT FROM
Nach dem bereits bekannten Muster muss die Ausgangstabelle in Untertabellen zerlegt werden. Da in diesem Fall nur noch die Produkttypen relevant sind, bildet produktTyp das Gruppierungskriterium. Pro Produkttyp gibt es jetzt eine Anzahl von Lagern, für die jeweils der Durchschnittspreis des Produkttyps bekannt ist. Aus dieser Menge wird jetzt wiederum der Durchschnitt bestimmt, womit das Endergebnis erzielt ist. Der gewitzte Leser mag hier einwenden, warum einfach, wenn es auch kompliziert geht. Man hätte doch einfach die erste Anfrage nehmen können, sie über die AS-Klausel mit einem Namen versehen (z. B. ProdukttypLager) und die so benannte Tabelle in einer zweiten Anfrage als Ausgangstabelle wählen können (siehe Beispiel 7.118). Beispiel 7.118: Verwenden von Ergebnistabellen in anderen Anfragen (SELECT FROM WHERE GROUP BY
produktTyp, produktLagerNr, AVG(nettoPreis) AS ∅nettoPreis ProduktLagertIn NATURAL JOIN Produkt istBestand > 0 produktTyp, produktLagerNr;) AS ProdukttypLager
SELECT FROM GROUP BY
produktTyp, AVG(∅nettoPreis) AS ∅nettoPreisÜberAlleLager ProdukttypLager produktTyp;
Leider ist diese elegante Lösung mit dem SQL-92-Standard nicht vereinbar. Das Ablegen des Ergebnisses einer Anfrage in einer temporären Tabelle und die damit verbundene Möglichkeit des Zugriffes auf diese Tabelle durch nachfolgende Anfragen wird nicht unterstützt. Allerdings gibt es durchaus eine Reihe von SQL-Dialekten, die dieses nützliche Feature unterstützen. Seit SQL:1999 ist dieses Manko jedoch ausgeräumt (siehe Kapitel 8.5). Wie man den Lösungen entnehmen kann (siehe Beispiel 7.117 und Beispiel 7.118), kann die Fragestellung nicht durch eine SQL-Anfrage beantwortet werden. Stattdessen muss jeder der beiden Durchschnittspreise über eine eigene Anfrage abgedeckt werden.
388
7 Die relationale Datenbanksprache SQL
Nach der ausführlichen Diskussion der Notwendigkeit, Unteranfragen in der FROM-Klausel ausführen zu dürfen, sollen jetzt einige Beispiele für die Ausführung von Unteranfragen in den anderen Klauseln diskutiert werden. Beispiel 7.119: Unteranfrage in der WHERE-Klausel 1. „Welcher Mitarbeiter bekommt das höchste Gehalt?“ SELECT FROM WHERE
∗ Mitarbeiter gehalt = (SELECT MAX(gehalt) FROM Mitarbeiter);
2. „Welcher Mitarbeiter wohnt im selben Ort wie der Mitarbeiter mit dem niedrigsten Gehalt?“ SELECT FROM WHERE
∗ Mitarbeiter ort = (SELECT FROM WHERE
ort Mitarbeiter gehalt = (SELECT MIN(gehalt) FROM Mitarbeiter));102
3. „Finde alle Mitarbeiter, die mehr als das anderthalbfache von dem verdienen, was der Kollege mit dem niedrigsten Gehalt in der Abteilung verdient.“ SELECT FROM WHERE
∗ Mitarbeiter AS MA1 MA1 .gehalt > (SELECT MIN(gehalt) ∗ 1,5 FROM Mitarbeiter AS MA2 WHERE MA1 .abteilungsNr = MA2 .abteilungsNr);
4. „Ermittle pro Abteilung das Durchschnittsgehalt der Mitarbeiter, die mehr als der Durchschnitt ihrer Abteilung verdienen.“ abteilungsNr, AVG(gehalt) Mitarbeiter AS M1 gehalt > (SELECT AVG(gehalt) FROM Mitarbeiter AS M2 WHERE M1 .abteilungsNr = M2 .abteilungsNr) GROUP BY abteilungsNr;
SELECT FROM WHERE
102 Hier wird unterstellt, dass es nur einen Mitarbeiter mit dem niedrigsten Gehalt gibt; siehe auch die Diskussion in Kapitel 7.3.5.1.
7.3 Die Datenbankanfragesprache (DRL)
389
Ähnlich wie in imperativen Programmiersprachen, wo Variablen nur in dem Block, in dem sie definiert wurden, und dessen Unterblöcken benutzt werden dürfen, nicht aber in übergeordneten Blöcken (scoping rule), darf man Alias- und Spaltennamen einer übergeordneten Anfrage zwar in deren Unteranfragen benutzen, nicht aber umgekehrt. In Beispiel 7.119, 3. wurde der Aliasname MA1 in der Unteranfrage genutzt. MA2 dürfte allerdings nicht in der Hauptanfrage verwendet werden. Beispiel 7.120: Unteranfrage in der HAVING-Klausel 1. „Gib die Anzahl der Lager aus, in denen mehr als die Hälfte des gesamten Produktsortiments vorrätig ist.“ SELECT COUNT(produktLagerNr) FROM ProduktLagertIn GROUP BY produktLagerNr HAVING COUNT (produktNr) > ((SELECT COUNT(∗) FROM Produkt)/2); 2. „Gib die Anzahl der Lager aus, in denen mehr als die Hälfte des Produktsortiments vorrätig ist, das in der Herstellung teurer als 500,– C ist.“ SELECT COUNT(produktLagerNr) FROM ProduktLagertIn NATURAL JOIN Produkt WHERE stueckKosten > 500 GROUP BY produktLagerNr HAVING COUNT (produktNr) > ((SELECT COUNT(∗) FROM Produkt WHERE stueckKosten > 500)/2);
Beispiel 7.121: Unteranfrage in der SELECT-Klausel 1. „Gib die Mitarbeiterdaten zusammen mit dem Unterschied ihres Gehaltes zum Durchschnittsgehalt aller Mitarbeiter aus.“ SELECT
FROM
Mitarbeiter. ∗, gehalt −(SELECT AVG(gehalt) FROM Mitarbeiter) AS unterschiedZumDurchschnittsgehalt Mitarbeiter;
2. „Gib für alle Produkte den Lagerbestand über alle Lager aus.“ SELECT P.produktBez, P.produktNr, (SELECT SUM(istBestand) FROM ProduktLagertIn AS PLI GROUP BY produktNr HAVING P.produktNr = PLI.produktNr) AS lagerBestand FROM Produkt AS P;
390
7 Die relationale Datenbanksprache SQL Eine alternative Formulierung wäre: SELECT FROM
produktBez, produktNr, lagerBestand Produkt NATURAL JOIN (SELECT produktNr, SUM(istBestand) AS lagerBestand FROM ProduktLagertIn GROUP BY produktNr);
oder SELECT produktBez, produktNr, SUM(istBestand) AS lagerBestand FROM Produkt NATURAL JOIN ProduktLagertIn GROUP BY produktNr; Bei der letzten Variante ist eine Formulierung zum Zuge gekommen, die so eigentlich ausgeschlossen worden war (siehe Achtung 7.13): Die nicht berechneten Spalten der SELECT-Klausel sollten eigentlich identisch mit den Spaltennamen der GROUP BYKlausel sein. Besteht aber eine 1:1-Beziehung zwischen zwei Spalten, so würde die Hinzunahme der zweiten Spalte in die GROUP BY-Klausel nichts an der Gruppierung ändern (siehe Feststellung 7.10). Beispiel 7.122: Unteranfrage in der FROM-Klausel Als Beispiel für die Verwendung einer Unteranfrage in der FROM-Klausel sei hier die Lösung für Beispiel 7.108 aus dem letzten Abschnitt genannt: „Ermittle den durchschnittlichen Verkaufspreis aller auf Lager befindlichen Produkte.“ SELECT FROM
AVG(nettoPreis) AS ∅nettoPreis Produkt NATURAL JOIN (SELECT DISTINCT produktNr FROM ProduktLagertIn WHERE istBestand > 0);
Die Möglichkeit, einen SFW-Block in der FROM-Klausel zu spezifizieren, ist in vielen kommerziellen SQL-Dialekten noch nicht umgesetzt. Da die Unteranfrage einen ganz normalen SFW-Block darstellt, kann sie als Ergebnis auch eine Tabelle mit Duplikaten liefern. Als Konsequenz ergibt sich, dass in der FROM-Klausel nicht zwangsläufig eine Ausgangsrelation, sondern auch eine -tabelle spezifiziert sein kann. Deshalb wird im Text auch immer der Begriff Ausgangstabelle verwendet. An den obigen Beispielen kann man auch sehr schön sehen, was Orthogonalität einer Sprache bedeutet. Betrachten wir beispielsweise die FROM-Klausel. Sie dient der Spezifikation der Ausgangstabelle. Nun liefert ein SFW-Block als Ergebnis auch grundsätzlich eine Tabelle. Dementsprechend muss es in einer orthogonalen Sprache möglich sein, die Ausgangstabelle durch einen SFW-Block erzeugen zu lassen. In den alten SQL-Varianten war dies noch nicht möglich, Orthogonalität war also eher eine Nebenbedingung. Der SQL-92-Standard hat dieses Problem angepackt, indem er, wo immer möglich, Orthogonalität „nachgeschoben“ hat. Damit hat er erheblich dazu beigetragen, dass SQL nun wesentlich konsistenter und durchgängiger wirkt. Es muss aber auch angemerkt werden, dass trotz der mit der verbesserten Orthogonalität verbundenen offensichtlichen Vorteile viele SQL-Dialekte diese Verbesserungen (noch) nicht konsequent umgesetzt haben.
7.3 Die Datenbankanfragesprache (DRL) 7.3.5.1
391
Wertliefernde Unteranfragen
Die Unteranfragen in Beispiel 7.119 und Beispiel 7.120 müssen entweder exakt einen Wert vom richtigen Datentyp103 oder die leere Menge liefern, damit das Ergebnis der Unteranfrage und der Spaltenwert links vom Vergleichsoperator etwas Vergleichbares repräsentieren. Man spricht hier von einer wertliefernden Unteranfrage. Evaluiert die Unteranfrage zur leeren Menge, wird NULL als Ergebnis ausgegeben. Da SFW-Blöcke aber darauf ausgelegt sind, Mengen von Datensätzen zurück zu liefern, stellt eine solche Formulierung eine potenzielle Quelle für Fehler dar. Nur in vergleichsweise wenigen Fällen kann garantiert werden, dass das Ergebnis auch wirklich nur ein Wert ist. Die Problematik, etwas Derartiges garantieren zu können, kann man an der zweiten Anfrage von Beispiel 7.119 sehen. Ist ausgeschlossen, dass zwei Mitarbeiter des Unternehmens das Gleiche verdienen, ist die Anfrage auf jeden Fall korrekt. Andernfalls kann es zwei oder mehr Mitarbeiter mit dem niedrigsten Gehalt geben und die Anfrage würde mit einem Laufzeitfehler enden. Eine Unteranfrage liefert auf jeden Fall höchstens einen Wert, falls als Ergebnis eine einfache Aggregatfunktion (ohne GROUP BY-Klausel) spezifiziert wird (Beispiel 7.123 (1.)) oder in der Unteranfrage in der WHERE-Klausel der Primärschlüssel der Ausgangstabelle auf Gleichheit mit einem Wert überprüft wird (Beispiel 7.123 (2.)). Allgemein kann Wert auch einen strukturierten Wert darstellen (Beispiel 7.123 (3.)). Beispiel 7.123: Sichere wertliefernde Unteranfragen 1. „Finde alle Abteilungen, die mehr als das durchschnittliche Budget zur Verfügung haben.“ SELECT FROM WHERE
∗ Abteilung budget > (SELECT AVG(budget) FROM Abteilung);
2. „Finde alle Abteilungen, die ein höheres Budget als Abteilung 121212 zur Verfügung haben.“ SELECT FROM WHERE
∗ Abteilung budget > (SELECT budget FROM Abteilung WHERE abteilungsNr = 121212);
3. „Finde alle Abteilungen, die das gleiche Budget und die gleiche Mitarbeiterzahl wie Abteilung 121212 besitzen.“ 103 Genau genommen wird natürlich eine Zeile, die aus einer Spalte besteht, die einen Wert enthält zurückgeliefert. Für die weitere Verarbeitung wird diese Zeile aber entpackt und in einen Wert umgewandelt.
392
7 Die relationale Datenbanksprache SQL SELECT FROM WHERE
∗ Abteilung (budget, mitarbeiterZahl) = ( SELECT budget, mitarbeiterZahl FROM Abteilung WHERE abteilungsNr = 121212); 104
Anfrage 3. ist semantisch äquivalent zu folgender Anfrage: SELECT FROM WHERE
∗ Abteilung budget =
(SELECT FROM WHERE
budget Abteilung abteilungsNr = 121212);
AND mitarbeiterZahl = (SELECT FROM WHERE
mitarbeiterZahl Abteilung abteilungsNr = 121212);
Wegen der Problematik, sicherstellen zu müssen, dass das Ergebnis einer Unteranfrage auch wirklich nur ein Wert ist, sind wertliefernde Unteranfragen ohne Aggregatfunktionen eher selten. Wesentlich häufiger findet man die verallgemeinerte Variante, bei der ein Wert daraufhin überprüft werden kann, ob er in einer durch einen SFW-Block erzeugten Ergebnistabelle (also in einer Menge) enthalten ist. Man spricht dann von einer mengenorientierten Unteranfrage. 7.3.5.2
Mengenorientierte Unteranfragen
Zur korrekten Verarbeitung von mengenorientierten Unteranfragen in der WHERE-Klausel stellt SQL-92 eine Anzahl von Prädikaten bereit, deren Semantik Tabelle 7.20 entnommen werden kann. Semantik105 IN
Ist der Wert links vom Prädikat in der Menge rechts vom Prädikat enthalten?
EXISTS
Ergibt die Auswertung der zum Prädikat gehörenden Unteranfrage mindestens einen Wert?
θ ANY
Gilt, dass der θ-Vergleich des Wertes links vom Prädikat mit den Werten der Menge rechts vom Prädikat für mindestens einen Vergleich wahr ist?
θ SOME
Ist eine andere Bezeichnung für ANY.
θ ALL
Gilt, dass der θ-Vergleich des Wertes links vom Prädikat mit den Werten der Menge rechts vom Prädikat für alle Vergleiche wahr ist?
Tabelle 7.20: Semantik der mengenorientierten Prädikate 104 Soll vermieden werden, dass auch die Abteilung121212 als Ergebnis erscheint, muss in der WHERE-Klausel der Hauptanfrage noch die Bedingung „AND abteilungsNr = 121212“ aufgenommen werden. 105 Wert kann in dieser Tabelle auch einen zusammengesetzten Wert (Zeilenkonstruktor) darstellen.
7.3 Die Datenbankanfragesprache (DRL)
393
Die grundsätzliche Syntax der Prädikate lautet wie folgt: Syntax 7.39: Basissyntax der mengenorientierten Prädikate MPrädikat ::=
[ZeilenKonstruktor][Vergleichssymbol]PrädTyp (UnterAnfrage) PrädTyp ::= IN | EXISTS | {ANY | SOME} | ALL ZeilenKonstruktor ::= SpaltenName | (SpaltenName1[, SpaltenNamen ]*) | UnterAnfrage Das Vergleichssymbol ist nicht bei allen Prädikaten zulässig (siehe Tabelle 7.20). Auf die Prädikate wird gleich noch genauer eingegangen. Die Zeilen der in MPrädikat durch (UnterAnfrage) ermittelten Ergebnistabelle müssen typkompatibel mit ZeilenKonstruktor sein106 . Bis auf das EXISTS-Prädikat sind alle Prädikate binär, was heißt, dass links und rechts vom Prädikat Werte stehen, die miteinander verglichen werden. Als Ergebnis kommt ein Wahrheitswert heraus (TRUE, FALSE, UNKNOWN). Wie später noch gezeigt wird (z. B. in Beispiel 7.125), darf links von einem binären Prädikat statt eines einfachen Wertes auch ein strukturierter Wert (also ein Tupel bzw. eine Zeile) stehen. In der Regel wird ZeilenKonstruktor nur ein Spaltenname sein. Wie allerdings bereits in Beispiel 7.123, 3. demonstriert, darf dort auch eine Zeile (im Sinn eines Tupels) stehen. Allerdings wird diese Variante von den meisten kommerziellen SQL-Dialekten nicht unterstützt. Schließlich ist es auch noch möglich, dass ZeilenKonstruktor über eine Unteranfrage ermittelt wird. Das EXISTS-Prädikat ist das einzige unäre Prädikat. Es besitzt nur eine rechte Seite. Es evaluiert zu TRUE, falls als Ergebnis von UnterAnfrage eine nichtleere Menge bestimmt wird. Andernfalls evaluiert es zu FALSE. Der Wahrheitswert UNKNOWN kann hier nicht vorkommen. 7.3.5.2.1
Das IN-Prädikat
Über das IN-Prädikat kann getestet werden, ob der links vom IN-Prädikat stehende Wert in der rechts vom IN-Prädikat stehenden Menge (nicht) enthalten ist. Syntax 7.40: IN-Prädikat IN-Prädikat ::= ZeilenKonstruktor [NOT] IN ({Wertemenge | UnterAnfrage}) Beispiel 7.124: IN-Prädikat mit Unteranfrage Die folgende Anfrage liefert alle Rechnungen von Zulieferern aus GroßKleckersdorf. SELECT FROM WHERE
106 Falls
∗ LieferantenRechnung zuliefererNr IN (SELECT FROM WHERE
zuliefererNr Zulieferer ort = ’GroßKleckersdorf’);
Zeilenkonstruktor spezifiziert werden muss oder kann.
394
7 Die relationale Datenbanksprache SQL
Wie bereits erwähnt, kann im SQL-92-Standard der links vom Prädikat stehende Wert durchaus auch eine Zeile (im Sinne eines strukturierten Wertes bzw. Tupels) darstellen (siehe Beispiel 7.125). Beispiel 7.125: IN-Prädikat mit Wertemenge auf der Basis von Zeilen Angenommen, Sie arbeiten mit einem Kollegen, Herrn NixGeregelt, zusammen. Dieser hat heute seinen freien Tag. Wie üblich gibt es Probleme mit einer Rechnung vom Zulieferer Abzock oder Chaotikus, von der Sie nur wissen, dass sie gestern oder vorgestern eingegangen sein muss. Die Rechnung kann mit folgender Anfrage gesucht werden: SELECT FROM WHERE
LieferantenRechnung. ∗ LieferantenRechnung NATURAL JOIN Zulieferer (zuliefererName, datum) IN ((’Abzock’, CURRENT_DATE-INTERVALL ’1’ DAY), (’Abzock’, CURRENT_DATE-INTERVALL ’2’ DAY), (’Chaotikus’, CURRENT_DATE-INTERVALL ’1’ DAY), (’Chaotikus’, CURRENT_DATE-INTERVALL ’2’ DAY));
Allerdings wird die Zeilenvariante von den meisten kommerziellen SQL-Dialekten (noch) nicht unterstützt. Um eine Anfrage wie die obige trotzdem lösen zu können, könnte man die Zeile in ihre elementaren Spalten zerlegen und das IN-Prädikat für jede Spalte einzeln formulieren (siehe Beispiel 7.126). Beispiel 7.126: Simulation eines IN-Prädikates auf Zeilen SELECT FROM WHERE
7.3.5.2.2
LieferantenRechnung.∗ LieferantenRechnung NATURAL JOIN Zulieferer datum IN (CURRENT_DATE-INTERVALL ’1’ DAY, CURRENT_DATE-INTERVALL ’2’ DAY) AND zuliefererName IN (’Abzock’, ’Chaotikus’);
Quantifizierende Vergleichsprädikate
Die quantifizierenden Vergleichsprädikate ANY und ALL können als eine Verallgemeinerung des IN-Prädikates angesehen werden. Während beim IN-Prädikat grundsätzlich auf Gleichheit verglichen wird, kann bei den quantifizierenden Vergleichsprädikaten ein beliebiger Vergleichsoperator eingesetzt werden. Die Syntax lautet wie folgt: Syntax 7.41: Quantifizierendes Prädikat QuantifizierendesPrädikat ::= ZeilenKonstruktorVergleichsOperator { ALL | { SOME | ANY } }UnterAnfrage
7.3 Die Datenbankanfragesprache (DRL)
395
Das ANY- bzw. SOME-Prädikat entspricht dem bereits aus dem Relationenkalkül bekannten Existenzquantor. SOME und ANY sind dabei Synonyme. Die Semantik des Existenzquantors entspricht der Frage, ob in der Ergebnismenge, die durch UnterAnfrage berechnet wird, ein Wert enthalten ist, der dem θ-Vergleich mit Z (steht für ZeilenKonstruktor) standhält. Etwas formaler lässt sich diese Bedingung wie folgt formulieren: Z θANY UnterAnfrage ∼ = ∃ Wert ∈ {UnterAnfrage}107 : Z θWert Der Existenzquantor lässt sich in SQL auch noch durch die folgende Formulierung simulieren (Annahme: Die Auswertung von UnterAnfrage ergibt {Wert1 , . . . , Wertn }): WHERE (FALSE OR)108 Z θWert1 OR Z θWert1 OR . . . OR Z θWertn Beim Allquantor wird verlangt, dass alle Werte der Unteranfrage den θ -Vergleich mit Z erfüllen. Z θALL UnterAnfrage ∼ = ∀ Wert ∈ {UnterAnfrage}: Z θWert Die alternative SQL-Formulierung lautet: WHERE (TRUE AND)109 Z θWert1 AND Z θ Wert1 AND . . . AND Z θWertn Falls die Auswertung von UnterAnfrage die leere Menge liefert, evaluiert das ALL-Prädikat zu TRUE und das ANY-Prädikat zu FALSE. Wird als Vergleichsoperator die Gleichheit gewählt, entspricht das ANY-Prädikat dem INPrädikat. Beispiel 7.127: Äquivalenz von ANY- und IN-Prädikat „Gib alle Mitarbeiter aus, die auch Kunden sind, als solche einen Rabatt unter 10 Prozent bekommen und deren Vorname mit G anfängt.“ SELECT FROM WHERE
mitarbeiterName, mitarbeiterVorname Mitarbeiter (mitarbeiterName, mitarbeiterVorname) IN (SELECT kundenName, kundenVorname FROM Kunden WHERE rabatt < 10 AND kundenVorname LIKE ’G%’);
oder SELECT FROM WHERE
mitarbeiterName, mitarbeiterVorname Mitarbeiter mitarbeiterVorname LIKE ’G%’ AND mitarbeiterNr IN (SELECT kundenNr FROM Kunden WHERE rabatt < 10);
Mengenklammer soll ausdrücken, dass es sich hier um die Ergebnismenge von UnterAnfrage handelt. ist eine nicht notwendige Ergänzung, um die Semantik der WHERE-Klausel zu beschreiben, falls die Auswertung von UnterAnfrage die leere Menge ergeben hat. 109 siehe Fußnote 108. 107 Die
108 Dies
396
7 Die relationale Datenbanksprache SQL
oder mit ANY: SELECT FROM WHERE
mitarbeiterName, mitarbeiterVorname Mitarbeiter (mitarbeiterName, mitarbeiterVorname) = ANY (SELECT kundenName, kundenVorname FROM Kunden WHERE rabatt < 10 AND kundenVorname LIKE ’G%’);
Im Zusammenhang mit der Relationenalgebra hatten wir bereits festgestellt, dass jeder Ausdruck mit einem Existenzquantor durch einen Ausdruck mit einem Allquantor ersetzt werden kann und umgekehrt. Das IN-Prädikat entspricht dem ANY-Prädikat bei Gleichheit. Tabelle 7.21 zeigt, dass auch bei allen anderen Vergleichsoperatoren zu jedem ANY- bzw. ALLPrädikat ein äquivalenter Ausdruck gefunden werden kann. Tabelle 7.21 kann man entnehmen, dass die qualifizierenden Vergleichsprädikate an sich redundant sind, da sie sich scheinbar in jedem Fall auch durch andere Ausdrücke simulieren lassen. Bei einigen SQL-Dialekten trifft dies auch zu. ORACLE z. B. unterstützt sowohl die geschachtelte Anwendung von Aggregatfunktionen als auch das Verwenden der Ergebnisse einer Anfrage in einer anderen Anfrage. Letzteres bedeutet, dass das Ergebnis einer Anfrage in einer temporären Tabelle abgelegt werden kann und dadurch nachfolgenden Anfragen zur Verfügung steht. Der SQL-92-Standard unterstützt diese beiden Varianten nicht. Deshalb können für den Fall, dass in der SELECT-Klausel der Unteranfrage bereits eine Aggregatfunktion verwendet wird – erg also eine Aggregatfunktion enthält –, die in Tabelle 7.21 angegebenen Ersetzungen nicht vorgenommen werden. ANY/ALL
Alternative
WHERE x = ANY(SELECT erg FROM . . .)
WHERE x IN (SELECT erg FROM . . .)
WHERE x {< | ≤} ANY(SELECT erg FROM . . .)
WHERE x {< | ≤} (SELECT MAX(erg) FROM . . .)
WHERE x {> | ≥} ANY(SELECT erg FROM . . .)
WHERE x {> | ≥} (SELECT MIN(erg) FROM . . .)
WHERE x = ANY (SELECT erg FROM . . .)110
WHERE
x = (SELECT MIN (erg) FROM . . .) OR x = (SELECT MAX (erg) FROM . . .)
WHERE x = ALL(SELECT erg FROM . . .)111
WHERE
x = (SELECT MIN (erg) FROM . . .) AND x = (SELECT MAX (erg) FROM . . .)
WHERE {< | ≤} ALL(SELECT erg FROM . . .)
1. WHERE x {< | ≤} (SELECT MIN(erg) FROM . . .) 2. WHERE NOT x {≥ | >} ANY (SELECT erg FROM . . .)
WHERE {> | ≥} ALL(SELECT erg FROM . . .)
1. WHERE x {> | ≥} (SELECT MAX(erg) FROM . . .) 2. WHERE NOT x {≤ | 0 GROUP BY produktTyp, produktLagerNr) GROUP BY produktTyp;
SELECT FROM
Die innere Anfrage berechnet die Ausgangstabelle für die Hauptanfrage. Diese Formulierung ist äquivalent zu der entkoppelten, weil sequenziellen Ausführung der beiden Anfragen, wie sie in Beispiel 7.130 vorgestellt wird. 112 Außer
bei dem EXISTS-Prädikat, wo es nur TRUE oder FALSE sein kann.
7.3 Die Datenbankanfragesprache (DRL)
399
Beispiel 7.130: Simulation einer geschachtelten Anfrage durch zwei Hauptanfragen 1113 (SELECT produktTyp, produktLagerNr, AVG(nettoPreis) AS ∅nettoPreis FROM ProduktLagertIn NATURAL JOIN Produkt WHERE istBestand > 0 GROUP BY produktTyp, produktLagerNr) AS ProdukttypLager; SELECT produktTyp, AVG(∅nettoPreis) AS ∅nettoPreisÜberAlleLager FROM ProdukttypLager GROUP BY produktTyp;
Notwendig für die Sequenzialisierung der beiden Anfragen ist die durch den SQL-92-Standard (noch) nicht unterstützte Benennung von Ergebnistabellen von Anfragen zum Zweck der Nutzung in nachfolgenden Anfragen. Ein anderes Beispiel ist die Anfrage von Beispiel 7.124, die im folgenden Beispiel in sequenzieller Form dargestellt wird. Beispiel 7.131: Simulation einer geschachtelten Anfrage durch zwei Hauptanfragen 2 Die folgende Anfrage liefert alle Rechnungen von Zulieferern aus GroßKleckersdorf. (SELECT FROM WHERE
zuliefererNr Zulieferer ort = ’GroßKleckersdorf’) AS ZuliefererGroßKleckersdorf;
SELECT FROM
* LieferantenRechnung NATURAL JOIN ZuliefererGroßKleckersdorf;
oder SELECT FROM WHERE
* LieferantenRechnung zuliefererNr IN ZuliefererGroßKleckersdorf;114
Die grundsätzliche Zerlegung der geschachtelten Anfragen von den letzten beiden Beispielen in zwei Hauptanfragen ist insbesondere deshalb möglich, weil die Unteranfragen autonome Einheiten bilden. Sie müssen jeweils nur einmal berechnet werden, um die gesamte Anfrage beantworten zu können. Eine solche Anfrage wird nicht korrelierende Unteranfrage genannt. Die Bearbeitung einer so aufgebauten geschachtelten Anfrage entspricht einer sequenziellen Abarbeitung zweier Blöcke gemäß der folgenden Abarbeitungsstrategie: Berechne Unteranfrage; Berechne Hauptanfrage; 113 Der
SQL-92-Standard erlaubt diese Zerlegung im Gegensatz zu einigen SQL-Dialekten nicht. Anfrage ist so in SQL-92 nicht möglich, da hinter dem IN entweder eine Menge von Werten oder ein SFW-Block stehen muss. Ein einfacher Tabellenname ist nicht erlaubt. 114 Diese
400
7 Die relationale Datenbanksprache SQL
Im Gegensatz zu unseren letzten Beispielen lässt sich die vierte geschachtelte Anfrage von Beispiel 7.119 nicht in zwei autonome Anfragen zerlegen. Der Grund liegt darin, dass das Ergebnis der Unteranfrage u. a. von einem Wert abhängt, der von der Hauptanfrage geliefert wird. Eine ganz einfache normale Anfrage wird wie folgt abgearbeitet: Beispiel 7.132: Abarbeitung eines einfachen SFW-Blockes SELECT FROM WHERE
∗ AusgangTabelle SpaltenName θWert
1. Nimm die erste Zeile der Ausgangstabelle und überprüfe, ob für sie der Wert von SpaltenName den θ-Vergleich mit Wert erfüllt. Falls ja, übernehme die Zeile in die Ergebnistabelle. 2. Nimm die zweite Zeile der Ausgangstabelle und überprüfe, ob für sie der Wert von SpaltenName den θ-Vergleich mit Wert erfüllt. Falls ja, übernehme die Zeile in die Ergebnistabelle. ... n. Nimm die letzte Zeile der Ausgangstabelle und überprüfe, ob für sie der Wert von SpaltenName den θ-Vergleich mit Wert erfüllt. Falls ja, übernehme die Zeile in die Ergebnistabelle. Wenn Wert jetzt in einer Unteranfrage ermittelt wird, in der ein Spaltenwert aus der aktuellen Zeile der Hauptanfrage zu berücksichtigen ist, hat man es offensichtlich mit einer massiv verwobenen Anfragestruktur zu tun. Für jede Zeile der Hauptanfrage muss die Unteranfrage komplett neu ausgewertet werden, da mindestens ein Spaltenwert der Hauptanfrage in der Unteranfrage berücksichtigt wird. Jede Zeile von Beispiel 7.133 muss jetzt wie folgt lauten: Nimm die n-te Zeile der Ausgangstabelle, übertrage den (die) entsprechenden Spaltenwert(e) in die Unteranfrage und werte diese aus. Jetzt überprüfe, ob der Wert von SpaltenName den θ-Vergleich mit dem Ergebnis der Auswertung der Unteranfrage erfüllt. Falls ja, übernehme die Zeile in die Ergebnistabelle. In einem solchen Fall, wo eine semantische Beziehung zwischen der Unteranfrage und der Hauptanfrage besteht, spricht man von einer korrelierenden Unteranfrage. Beispiel 7.133: Korrelierende Unteranfrage „Gib alle Kunden aus, deren Rabatt höher als der durchschnittliche Rabatt der anderen Kunden aus demselben Wohnort ist.“ SELECT ∗ FROM Kunden AS K1 WHERE rabatt > (SELECT AVG(rabatt) FROM Kunden AS K2 WHERE K1 .ort = K2 .ort AND K1 .kundenNr = K2 .kundenNr);
7.3 Die Datenbankanfragesprache (DRL)
401
Die Abarbeitung einer korrelierenden Unteranfrage entspricht der Abarbeitung zweier geschachtelter FOR-Schleifen. FOR Durchlauf Hauptanfrage FOR Durchlauf Unteranfrage
7.3.6
Mengenoperationen in SQL
Wie im vorherigen Abschnitt bereits erläutert wurde, können innerhalb einer Hauptanfrage auch Unteranfragen gestellt werden. Es liegt also eine Schachtelung von Anfragen vor. Bei Mengenoperatoren werden auch Anfragen miteinander verbunden, allerdings auf einer gleichberechtigten Ebene, d. h. es werden Hauptabfragen über Mengenoperationen miteinander verbunden. Bei der Auswertung einer solchen, aus mehreren Hauptanfragen zusammengesetzten Anfrage wird zunächst jede Hauptanfrage für sich ausgewertet. Anschließend werden die durch die Hauptanfragen erzeugten Ergebnismengen auf der Basis der Mengenoperatoren miteinander verbunden. Syntax 7.43: Anfrage mit Mengenoperator AnfrageMitMengenoperator ::= SFW-Block [{UNION | UNION ALL | INTERSECT | EXCEPT} AnfrageMitMengenoperator] Die Mengenoperationen Vereinigung, Durchschnitt und Differenz waren bereits im Zusammenhang mit der relationalen Algebra eingeführt worden (siehe Kapitel 6.5.1). Mengenoperationen können immer dann angewendet werden, wenn die zu Grunde liegenden Tabellen typkompatibel sind. Im einfachsten Fall bedeutet das, dass sowohl Spaltennamen als auch der jeweils dazugehörige Spaltentyp identisch sind. Es ist aber auch möglich, dass Spaltennamen in den jeweiligen Tabellen mit einem anderen Namen versehen sein können. Zueinander korrespondierende Spaltennamen werden über die Reihenfolge ihres Auftretens in der SELECT-Klausel der jeweiligen Anfrage definiert. Dies bedeutet implizit, dass die Tabellen eine identische Anzahl von Spalten haben müssen und dass der Datentyp der i-ten Spalte der einen Tabelle typkompatibel mit dem Datentyp der i-ten Spalte der anderen Tabelle ist. 7.3.6.1
Vereinigung
Der UNION-Operator dient der Vereinigung zweier typkompatibler Tabellen. Wird das Schlüsselwort ALL nicht angegeben, werden bei der Vereinigung als Default Duplikate entfernt115 . Die beiden UNION-Varianten können nicht durch andere Operatoren simuliert werden, weshalb sie bereits seit Anfang an zum SQL-Standard gehören. Beispiel 7.134: Vereinigung „Für ein großes Betriebsfest sollen die Namen und Adressen aller Kunden, Zulieferer und Mitarbeiter ausgegeben werden.“ 115 Symmetrie bleibt hier gleich doppelt auf der Strecke, da im Gegensatz zur SELECT-Klausel der DISTINCTOperator den Default darstellt und außerdem DISTINCT nicht hingeschrieben werden darf (wäre ein Syntaxfehler).
402
7 Die relationale Datenbanksprache SQL SELECT FROM
kundenName AS name, plz, ort, strasse, hausNr Kunden
UNION SELECT FROM
zuliefererName AS name, plz, ort, strasse, hausNr Zulieferer
UNION SELECT FROM
mitarbeiterName AS name, plz, ort, strasse, hausNr Mitarbeiter;
Soll der Einladung noch ein Los für die auf der Betriebsfeier stattfindende Lotterie beigelegt werden, wobei alle, die in einer Mehrfachfunktion auftreten (also Mitarbeiter, die auch Kunden sind), auch mehrere Einladungen und damit mehrere Lose erhalten sollen, muss in der obigen Anfrage statt UNION jeweils UNION ALL stehen.
7.3.6.2
Durchschnitt
Über den INTERSECT-Operator kann der Durchschnitt zweier Tabellen ermittelt werden. Durchschnitt bedeutet, dass eine Zeile dann in die Ergebnistabelle übernommen wird, falls sie sowohl in der einen als auch in der anderen Ausgangstabelle enthalten ist. Eine solche Bedingung kann auch über den natürlichen Verbund der beiden Ausgangstabellen definiert werden. Da in diesem Spezialfall beide Ausgangstabellen von der Struktur her identisch sind, entspricht das Ergebnis exakt der Durchschnittsbildung. Beispiel 7.135: Durchschnitt „Gib alle Kunden aus, die gleichzeitig Mitarbeiter des Unternehmens sind.“116 SELECT FROM
kundenNr AS identifikationsNr, kundenName AS name, kundenVorname AS vorname117 Kunden
INTERSECT SELECT FROM
mitarbeiterNr AS identifikationsNr, mitarbeiterName AS name, mitarbeiterVorname AS vorname Mitarbeiter;
Diese Anfrage könnte auch wie folgt mit Hilfe des SOME- oder des EXISTS-Prädikates formuliert werden: SELECT FROM 116 Man
kundenNr, kundenName, kundenVorname Kunden
beachte Fußnote 62 auf Seite 347. zu Beginn dieses Abschnitts über Mengenoperatoren bereits erwähnt, müssen die Spaltennamen der zu vereinigenden Tabellen nicht zwangsläufig übereinstimmen. Es reicht, wenn die Spalten typkompatibel sind. Deshalb sind die Umbenennungen nicht zwangsläufig notwendig. 117 Wie
7.3 Die Datenbankanfragesprache (DRL) WHERE
EXISTS (SELECT FROM WHERE
403
∗ Mitarbeiter kundenNr = mitarbeiterNr);
oder SELECT FROM WHERE
kundenNr, kundenName, kundenVorname Kunden kundenNr = SOME (SELECT kundenNr AS identifikationsNr FROM Kunden INTERSECT SELECT mitarbeiterNr AS identifikationsNr FROM Mitarbeiter);
oder SELECT FROM WHERE
7.3.6.3
kundenNr, kundenName, kundenVorname Kunden kundenNr = SOME (SELECT mitarbeiterNr FROM Mitarbeiter);
Differenz
Die Differenz zweier Tabellen kann über den EXCEPT-Operator gebildet werden. Er entfernt aus der ersten Ausgangstabelle all diejenigen Zeilen, die auch in der zweiten Ausgangstabelle enthalten sind. Auch hier gilt, dass mit dem NOT EXISTS-Prädikat ein Konstrukt existiert, das exakt dasselbe leistet wie die Mengendifferenz. Aus diesem Grund waren der INTERSECTund der EXCEPT-Operator im SQL-89-Standard nicht definiert worden und sind auch heute in vielen SQL-Dialekten (noch) nicht verfügbar. Beispiel 7.136: Differenz „Gib alle Kunden aus, die nicht gleichzeitig Mitarbeiter des Unternehmens sind.“118 SELECT FROM
kundenNr AS identifikationsNr, kundenName AS name, kundenVorname AS vorname Kunden
EXCEPT SELECT FROM 118 Man
mitarbeiterNr AS identifikationsNr, mitarbeiterName AS name, mitarbeiterVorname AS vorname Mitarbeiter;
beachte Fußnote 62 auf Seite 347.
404
7 Die relationale Datenbanksprache SQL
Diese Anfrage könnte auch wie folgt mit Hilfe des SOME- oder des NOT EXISTSPrädikates formuliert werden: SELECT FROM WHERE
kundenNr, kundenName, kundenVorname Kunden NOT EXISTS (SELECT ∗ FROM Mitarbeiter WHERE kundenNr = mitarbeiterNr);
oder SELECT FROM WHERE
kundenNr, kundenName, kundenVorname Kunden kundenNr = ALL (SELECT mitarbeiterNr FROM Mitarbeiter);
oder SELECT FROM WHERE
kundenNr, kundenName, kundenVorname Kunden kundenNr = SOME (SELECT kundenNr AS identifikationsNr FROM Kunden EXCEPT SELECT FROM
7.3.7
mitarbeiterNr AS identifikationsNr Mitarbeiter);
Die ORDER BY-Klausel (Sortieren der Ergebnistabelle)
Sollen die Ergebniszeilen nach bestimmten Merkmalen sortiert werden, so ist dies in einer eigenen Klausel, der so genannten ORDER BY-Klausel festzulegen. Die Spezifikation von Sortierkriterien geschieht also nicht, wie man vermuten könnte, in der SELECT-Klausel. Die ORDER BY-Klausel muss grundsätzlich als letzte Klausel des SFW-Blockes platziert werden. Syntax 7.44: ORDER BY-Klausel SELECT FROM
[{ALL | DISTINCT}] {SpaltenNameN | ∗ } AusgangsTabelle
... ORDER BY
SpaltenNamel [{ASC | DESC}], [SpaltenNamem [{ASC | DESC}]]∗
SpaltenNamel bis SpaltenNamem müssen in SpaltenNameN enthalten sein. Die Sortierung geschieht entsprechend der Nennung von links nach rechts. Es wird also zunächst anhand des ersten Spaltennamens sortiert. Zeilen, die an dieser Stelle den gleichen Wert aufweisen, werden anhand des zweiten Spaltennamens sortiert usw.
7.3 Die Datenbankanfragesprache (DRL)
405
Beispiel 7.137: ORDER BY-Klausel 1. „Erstelle eine nach Namen und Vornamen sortierte Liste aller Mitarbeiter.“ SELECT mitarbeiterName, mitarbeiterVorname FROM Mitarbeiter ORDER BY mitarbeiterName, mitarbeiterVorname; 2. „Erstelle eine nach Datum und Bearbeiter sortierte Liste der Aufträge aus dem Geschäftsjahr 2014.“ datum, bearbeiterNr, auftragsNr, auftragsPos, menge AuftragZulieferer NATURAL JOIN Auftragsposition datum BETWEEN DATE ’2014-01-01’ AND DATE ’2014-12-31’ ORDER BY datum, bearbeiterNr;
SELECT FROM WHERE
7.3.8
Zusammenfassung
In diesem Kapitel wurde diskutiert, wie in SQL-92 Anfragen an die DB gestellt werden können. Die Basis einer jeden Anfrage bildet der so genannte SFW-Block. Wie gezeigt, trifft diese Abkürzung nicht ganz den Kern, da neben der SELECT-, FROM- und WHERE-Klausel noch weitere Klauseln auftreten können. Die weiteren möglichen Klauseln sind die GROUP BY-, die HAVING- und die ORDER BY-Klausel (siehe Syntax 7.45). Syntax 7.45: Vollständige Syntax eines SQL-Blockes VollständigerSQL-Block ::= SELECT ErgebnisTabelle FROM AusgangsTabelle [WHERE KomplexesPrädikat] [GROUP BY SpaltenNameN [HAVING KomplexesPrädikat]] [ORDER BY SpaltenNameN]
Die logische Abarbeitung einer (vollständigen) SQL-Anfrage hat man sich grundsätzlich in der folgenden Reihenfolge vorzustellen, unabhängig davon, ob eine oder mehrere Klauseln fehlen. FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY Die den einzelnen Klauseln zugeordnete Semantik kann man Abbildung 7.7 entnehmen.
406
7 Die relationale Datenbanksprache SQL
FROM:
Aufbau der universellen, d. h. alle notwendigen Daten umfassenden Ausgangstabelle; diese Tabelle dient als Ausgangspunkt der Anfrage. ⇓
WHERE:
Selektion der gewünschten Zeilen. ⇓
GROUP BY:
Teilt die Ergebnistabelle in eine Menge von Untertabellen gleicher Struktur auf. Dabei gehören alle diejenigen Zeilen zu derselben Untertabelle, die in den in der GROUP BY-Klausel genannten Spalten in ihren Werten übereinstimmen. ⇓
HAVING:
Wählt aus den in der GROUP BY-Klausel gebildeten Untertabellen diejenigen aus, die der in der HAVING-Klausel angegebenen Bedingung genügen. ⇓
SELECT:
Bringt die Ergebnismenge in die von der Anwendung gewünschten Form (Projektion). ⇓
ORDER BY:
Sortiert die Ergebnistabelle auf der Basis der in dieser Klausel angegebenen Spaltennamen.
Abb. 7.7: Abarbeitungsreihenfolge und Semantik der Basisklauseln von SQL
Das folgende Beispiel präsentiert die Abarbeitung einer komplexen Anfrage. Beispiel 7.138: Beispiel einer umfassenden SQL-Anfrage „Ermittle pro Lager den durchschnittlichen Verkaufspreis und die Gesamtzahl aller unterschiedlichen Produkte des Typs Geschirrspüler, deren Name mit GS anfängt, und des Typs Waschmaschine, deren Name mit WM anfängt. Die Daten sollen allerdings nur dann ausgegeben werden, falls mindestens fünf und höchstens 20 Produkte bei der Ermittlung des durchschnittlichen Verkaufspreises berücksichtigt wurden. Nicht zu berücksichtigen sind die Lager Essen und München. Das Ergebnis soll aufsteigend nach dem Verkaufspreis und dann absteigend nach dem Produkttyp sortiert werden.“ produktTyp, produktLagerBez, AVG(nettoPreis) AS ∅nettoPreis, COUNT(produktNr) AS anzahlUnterschiedlicherProdukte 1 FROM Produkt NATURAL JOIN ProduktLagertIn NATURAL JOIN ProduktLager 2 WHERE (produktTyp = ’Geschirrspüler’ AND produktBez LIKE ’GS%’ OR produktTyp = ’Waschmaschine’ AND produktBez LIKE ’WM%’) AND produktLagerBez NOT IN (’Essen’, ’München’)119 3 GROUP BY produktTyp, produktLagerBez 4 HAVING COUNT(produktNr) BETWEEN 5 AND 20 6 ORDER BY ∅nettoPreis, produktTyp DESC;120
5 SELECT
7.3 Die Datenbankanfragesprache (DRL)
407
Entsprechend der in Abbildung 7.7 beschriebenen Reihenfolge der Abarbeitung wird zunächst über die beiden natürlichen Verbundoperationen die Ausgangstabelle gebildet (1.). Im Beispiel wird dabei auf die Basistabellen Produkt, ProduktLagertIn und ProduktLager Bezug genommen. Im nächsten Schritt werden die Zeilen ausgesucht, die die WHERE-Klausel erfüllen (2.). Als Faustregel gilt, dass in der WHERE-Klausel alle Bedingungen festgelegt werden sollten, die sich ausschließlich auf der Basis von einzelnen Zeilen entscheiden lassen. Um auserwählt zu werden, muss eine Zeile entweder einen Geschirrspüler, dessen Bezeichnung mit GS anfängt, oder eine Waschmaschine, deren Bezeichnung mit WM anfängt, repräsentieren. Zusätzlich werden alle Zeilen aussortiert, die ein Lager in Essen oder München beschreiben. In der GROUP BY-Klausel findet jetzt die Gruppierung nach Produkttyp und Lager statt (3.). Es werden alle die Zeilen zu einer Untertabelle zusammengefasst, die in der Spalte Produkttyp und Lagerbezeichnung übereinstimmen121. In der anschließenden HAVING-Klausel werden jetzt die Untertabellen entfernt, die weniger als 5 oder mehr als 20 Produkte enthalten (4.). Diese Entscheidung kann nicht auf der Ebene einer Zeile gefällt werden. Vielmehr muss dazu die gesamte Untertabelle betrachtet werden. Deshalb könnte diese Bedingung auch nicht in der WHERE-Klausel gestellt werden. Diskutieren könnte man allerdings darüber, ob das Entfernen der Essener oder Münchener Lager nicht auch erst hier erfolgen könnte, da die Untertabellen nicht nur auf der Basis der Produkttypen, sondern auch auf der Basis der Lager gebildet wurden. Grundsätzlich ist dies möglich. Es bleibt daher eher dem ästhetischen Empfinden des Datenbankprogrammierers überlassen, hier eine Entscheidung zu fällen. Nach Auswertung der Bedingungen in der WHERE- und der HAVING-Klausel ist die ursprünglich enorm große Ausgangstabelle endgültig auf ein überschaubares Maß zurechtgestutzt. In der SELECT-Klausel wird die immer noch mit mengenwertigen Spalten durchsetzte bzw. aus Untertabellen bestehende Zwischentabelle wieder „flachgeklopft“, indem die auszugebenden mengenwertigen Spalten über die Aggregatfunktionen zu jeweils einem Wert zusammengefasst werden (5.). Als letztes wird schließlich noch die Sortierung in der ORDER BY-Klausel durchgeführt (6.). Da die SELECT-Klausel in der Abarbeitungsreihenfolge bereits abgearbeitet wurde, sind die dort definierten Aliasnamen jetzt auch verfügbar, weshalb die Sortierung auch über die Spalte ∅nettoPreis laufen kann. Auch hier sei noch einmal angemerkt, dass ein guter Optimierer eine deutlich andere Abarbeitungsstrategie entwickeln wird. Alle Bedingungen der WHERE-Klausel und das IN-Prädikat der HAVING-Klausel lassen sich bereits auf den Basistabellen ausführen, wodurch diese bereits vor Anwendung der Verbundoperationen ganz drastisch zusammengestrichen werden. Die ohne diese Optimierungen ansonsten unüberschaubar große Ausgangstabelle wird vermieden. Die eigentlichen Verbundoperationen werden wegen der kleinen Rest-Basistabellen sehr schnell durchgeführt werden können. Innerhalb der Klauseln können komplexe Berechnungen durchgeführt werden, in denen eine Vielzahl von Operatoren, wie beispielsweise die Operationen der Basisdatentypen, Vergleichsist äquivalent zu: produktLagerBez = ’Essen’ AND produktLagerBez = ’München’. bei ∅ nettoPreis muss nicht angegeben werden, da es den Default darstellt. 121 Hier gibt es sicherlich zwei Sichtweisen: Jede „Untertabelle“ repräsentiert logisch eine Zeile, was heißt, dass die Untertabelle zu einer Zeile zurechtgestutzt werden muss, bevor sie ausgegeben werden darf. Deshalb kann man sich eine Untertabelle als eine echte Untertabelle vorstellen, zu der eine Menge von Zeilen gehören, die das Untertabellenkriterium erfüllen. Genauso gut könnte man sich jede Untertabelle aber auch als eine Zeile vorstellen, bei der manche Spalten weiterhin atomar sind (z. B. produktTyp und produktLagerBez), während andere mengenwertig sind (z. B. produktNr, produktBez, stueckKosten, nettoPreis). Die Sichtweise ist Geschmackssache. In jedem Fall muss vor Ausgabe einer „Untertabelle“ die Umformung in eine Zeile aus ausschließlich atomaren Spalten erfolgen. 119 Dies 120 ASC
408
7 Die relationale Datenbanksprache SQL
Operator
Bedeutung
Priorität
∗, /
Multiplikation, Division
7
+, -
Addition, Subtraktion
6
=, =, >, 0;127
Wenn bei der Sichtendefinition keine Spaltennamen für die Sicht angegeben werden, werden die in der SELECT-Klausel des SFW-Blockes genannten Spaltennamen übernommen. Diese Lösung ist nur dann anwendbar, wenn die Spaltennamen in der SELECT-Klausel eindeutig sind. Jede dort spezifizierte oder berechnete Spalte muss auch einen Namen haben. Das setzt voraus, dass insbesondere Spalten, deren Werte – z. B. über eine Aggregatfunktion – berechnet werden, über die AS-Klausel einen Namen zugewiesen bekommen haben. 125 Sichten können sehr groß werden, wie man sich sicherlich aufgrund der Diskussion der Größe eines Kartesischen Produktes in Kapitel 7.3.2.1, Beispiel 7.98 lebhaft vorstellen kann. Gute Optimierer bauen deshalb nicht zwangsläufig erst die Sicht vollständig auf, um dann darauf die Anfrage auszuführen. Vielmehr behandeln sie Sichtendefinition und Anfrage als ein Paket, was als Einheit optimiert wird. Dadurch lassen sich erhebliche Performanzgewinne erzielen 126 Das Buch wurde zu den Zeiten geschrieben, da die MwSt. noch zweistellig war. 127 Ein Produkt wird in die Sicht übernommen, wenn es in mindestens einem Lager noch vorrätig ist. Ist es in mehreren Lagern noch vorhanden, wird es trotzdem nur einmal übernommen, da wegen der DISTINCT-Vereinbarung Duplikate eliminiert werden.
7.5 Datensichten
421
Beispiel 7.149: Übernahme der Spalten aus dem SFW-Block Die Statistikabteilung benötigt einen Überblick über die Anzahl der Produkte, die einem Produkttyp zugeordnet sind. CREATE VIEW ProdukteProProdukttyp AS SELECT produktTyp, COUNT (produktNr) AS anzahl FROM Produkt GROUP BY produktTyp; Im einfachsten Fall wird eine Sicht aus einer Basistabelle erzeugt, indem gewisse Spalten ausgeblendet oder umbenannt werden. Beispiel 7.150: Einfache, spaltenverändernde Sichtendefinition Es ist mal wieder Zeit, ein Betriebsfest zu feiern, da das letzte das Arbeitsklima stark verbessert hat. Zu diesem Zweck brauchen wir eine Auflistung aller Mitarbeiter und deren Adressen. CREATE VIEW AS SELECT FROM
MitarbeiterAnschrift (name, vorname, plz, ort, strasse, hausNr) mitarbeiterName, mitarbeiterVorname, plz, ort, strasse, hausNr Mitarbeiter;
Eine Sicht, die aus einer Basistabelle durch Umbenennung von Spaltennamen, Weglassen von Spalten oder Hinzufügen abgeleiteter Spalten entsteht, soll im Folgenden spaltenverändernde Sicht genannt werden. Eine andere einfache Sicht ist eine, die aus einer Basistabelle durch Ausblenden von nicht relevanten Zeilen entsteht. Im einfachsten Fall wäre der Aufbau des SFW-Blockes wie folgt: SELECT FROM WHERE
∗ Basistabelle KomplexeBedingung
Beispiel 7.151: Einfache, mengenreduzierende Sicht Um den Kundenstamm, der hauptsächlich durch Nichtbegleichen seiner Rechnungen auffällt und deshalb keinen Rabatt mehr bekommt, besser kontrollieren zu können, sollen sie in einer eigenen Sicht abgelegt werden. CREATE VIEW AS SELECT FROM WHERE
SchlechteKundenStamm ∗ Kunden Rabatt = 0;
Sichten dieser Art werden mengenreduzierende Sichten genannt. Sichten, die über die Verbundoperation aus mehreren Basistabellen zusammengesetzt werden, heißen Verbundsichten.
422
7 Die relationale Datenbanksprache SQL
Beispiel 7.152: Verbundsicht Für die wöchentliche Firmenstatistik möchte die Firmenleitung gerne wissen, wie viele Aufträge jeweils ein Zulieferer erhalten hat. Auftragsverteilung zuliefererNr, zuliefererName, COUNT(auftragsNr) AS anzahlAufträge FROM Zulieferer NATURAL JOIN AuftragZulieferer GROUP BY zuliefererNr, zuliefererName;128
CREATE VIEW AS SELECT
Die WITH CHECK-Option spielt eine besondere Rolle im Zusammenhang mit Datensichten und der Datensicherheit. Erlaubt man beispielsweise, dass bei der Arbeit auf mengenverändernden Sichten Zeilen aus dem sichtbaren in den nicht sichtbaren Teil der Basistabelle wandern können, so kann man dies als Verletzung der Datensicherheit auslegen: Implizit teilt man dem Benutzer damit mit, dass neben den Zeilen, mit denen er arbeiten darf, noch weitere Zeilen in der Basistabelle vorhanden sind (wo sollen ansonsten die nur geänderten, aber nicht gelöschten Zeilen hin verschwunden sein). Um solche Probleme zu vermeiden, wurde die WITH CHECK-Option eingeführt. Wird sie spezifiziert, werden alle Änderungsoperationen zurückgewiesen, bei denen Zeilen aus dem sichtbaren in den nicht sichtbaren Teil der DB wandern können. Die Definition einer Basistabelle schließt aus, dass sie eine Spalte enthalten kann, deren Wert aus den Werten anderer Spalten abgeleitet wird. Genau hier können sich Sichten und Basistabellen unterscheiden. In Sichten dürfen solche abgeleiteten Spalten benutzt werden. Beispiel 7.153: Sichtendefinition mit abgeleiteten Spalten Erstelle eine Produkt-/Preisübersicht (Kundenansicht). CREATE VIEW AS SELECT FROM
Kundensicht produktBez, produktTyp, nettoPreis ∗ 1,16 AS bruttoPreis Produkt;
Da Sichten virtuell sind, also nicht abgespeichert werden, spielt bei ihnen Redundanz nur eine untergeordnete Rolle129 . Daher ist es für sie nicht wichtig, ob sie normalisiert sind. Deshalb 128 Da zuliefererName funktional von zuliefererNr abhängt, ist das Nennen dieser Spalte in der GROUP BY-Klausel zur Sicherstellung der Eindeutigkeit der Ergebniszeilen nicht notwendig. Wollte man nur den Namen des Zulieferers ausgegeben haben (d. h. zuliefererNr wird nicht in der SELECT-Klausel aufgeführt), entsteht eine interessante Konstellation: zuliefererName ist nicht eindeutig. Deshalb können mehrere Datensätze mit gleichem Zulieferernamen ausgegeben werden. Die Berechnung zu den Datensätzen ist korrekt, allerdings lassen sich die Datensätze nicht eindeutig einem Zulieferer zuordnen. 129 Redundanz wirft zwei wesentliche Probleme auf: Konsistenz der redundanten Daten und Speicherplatzverbrauch. Das erste Problem ist beim Datenbankentwurf von erheblicher Relevanz, während der Speicherplatzverbrauch bei heutigen Sekundärspeicherpreisen kein wirklich relevantes Thema mehr ist. Bei virtuellen Tabellen ist es eher umgekehrt. Da sie nur temporär existieren, sind Konsistenzprobleme aufgrund von Redundanzen sehr unwahrscheinlich. Allerdings spielt der Speicherplatzverbrauch hier schon eine wesentlich größere Rolle, da Sichten im Hauptspeicher verwaltet werden und der ist nach wie vor noch eingeschränkt. Insofern muss man die obige Aussage etwas relativieren. Hohe Redundanz bei großen Ergebnismengen wird eindeutig zu spürbaren Performanzverlusten führen.
7.5 Datensichten
423
kann ein Anwendungsobjekt in einer Sicht auch als zusammenhängendes Objekt präsentiert werden und braucht nicht entsprechend der Normalisierungstheorie in eine Menge von normalisierten Tabellen zerlegt werden. Beispiel 7.154: Komplexe Sichtendefinition Auf dem bereits in Beispiel 7.150 erwähnten Betriebsfest sollen alle Jubilare geehrt werden, also die Mitarbeiter, die schon länger als 25 Jahre dem Unternehmen angehören. Sie werden in einer zweiten Sicht gehalten. Neben den Kerndaten sollen für die Ansprache noch einige Zusatzdaten, wie die Jahre der Firmenzugehörigkeit, die Anzahl der bisher abgewickelten Aufträge und der Unterschied des aktuellen Gehaltes zum Durchschnittsgehalt vorgehalten werden. Jubilare(nr, name, vorname, geburtsDatum, einstellung, firmenZugehörigkeit, bearbeiteteAufträge, unterschiedZumDurchschnittsgehalt) AS SELECT mitarbeiterNr, mitarbeiterName, mitarbeiterVorname, geburtsDatum, einstellung, einstellung-CURRENT_DATE, COUNT(auftragNr), gehalt − (SELECT AVG(gehalt) FROM Mitarbeiter)130 FROM Mitarbeiter INNER JOIN AuftragZulieferer ON (mitarbeiterNr = bearbeiterNr) GROUP BY mitarbeiterNr;
CREATE VIEW
An der Sicht Jubilare kann man schön den Vorteil von Sichten erkennen. Sie stellen virtuelle Tabellen dar, was insbesondere heißt, dass ihre Zeilen bei jedem Zugriff „frisch“ berechnet werden und somit zwangsläufig immer aktuell sind.
7.5.2
Vorteile von Sichten
Sichten sind ein wesentliches Instrument, um die logische Datenunabhängigkeit zu gewährleisten. Werden beispielsweise in Sichten verwendete Basistabellen an Stellen verändert, die die Sicht nicht betreffen, so bleibt die Sichtendefinition und damit die dahinter stehenden Anwendungen von dieser Änderung unberührt. Weiterhin kann es möglich sein, dass eine Änderung zwar auch die Sichtendefinition berührt, aber gegenüber der Anwendung verborgen bleiben kann. In diesem Fall muss nur die Sichtendefinition angepasst werden. Änderungen, die auch zu Änderungen der Anwendung führen, werden deshalb häufig solche Änderungen sein, die aus der Sicht der Anwendung notwendig und wünschenswert sind und schon aus diesem Grund mit einer Änderung des zu Grunde liegenden Anwendungsprogramms verbunden sein müssen. Sichten erlauben es, dem Benutzer die Daten so zu präsentieren, wie er sie gerne sehen möchte. Sie tragen damit erheblich zur Benutzerzufriedenheit und Fehlerreduktion bei. Insbesondere erlauben sie es, das häufig doch sehr komplexe und umfangreiche konzeptuelle 130 An diesem Beispiel kann man sehr gut erkennen, wieviel Arbeit ein guter Optimierer „wegoptimieren“ kann. Man bedenke nur, wie oft das (sich nicht ändernde) Durchschnittsgehalt der Firma berechnet werden müsste, wenn der Optimierer diese Berechnung nicht aus der Berechnung eines jeden Jubilardatensatzes herausziehen und außerhalb dieser „Schleife“ nur einmal ermitteln würde.
424
7 Die relationale Datenbanksprache SQL
Datenbankschema auf den Ausschnitt zu reduzieren, der aus der Sicht der Anwendung auch wünschenswert ist. Durch die Möglichkeit, solche Teile des konzeptuellen Datenbankschemas auszublenden, die aus Gründen der Datensicherheit für die Anwendung nicht sichtbar sein sollen, stellen Sichten auch ein wichtiges Instrument zur Gewährleistung von Datensicherheit dar. Da durch Sichten nur virtuelle Tabellen gebildet werden, muss auf die zur Minimierung von Datenredundanz notwendigen Normalformen keine Rücksicht genommen werden. Daten können genau so präsentiert werden, wie sie vom Benutzer gewünscht werden.
7.5.3
Probleme mit Sichten
Sichten stellen ein ganz wesentliches Konzept eines DBMS dar und sind damit aus modernen DBMS nicht mehr wegzudenken. Den konzeptuellen Vorteilen, die mit ihnen verbunden sind, stehen allerdings auch einige Probleme technischer Art gegenüber, die nach wie vor gültig sind und die die allgemeine Nutzbarkeit von Sichten zumindest bei Änderungsoperationen stark einschränken. Inkonsistentes Lesen Insbesondere bei mengenverändernden Sichten können Update-Operationen dazu führen, dass Zeilen aus der Sicht verschwinden oder in einer Sicht zusätzlich sichtbar werden, obwohl weder gelöscht noch neu eingefügt wurde. Dies kann immer dann auftreten, falls von parallelen Transaktionen Änderungen in den Spalten ausgeführt werden, die die Sichtenzugehörigkeit bestimmen. Aufgrund dieser fehlenden Stabilität kann es passieren, dass eine Anwendung, die während einer Programmausführung zweimal sequenziell durch die Zeilen einer Sicht läuft, unterschiedliche Ergebnisse zu sehen bekommt. Aus Sicht der Anwendung liegt ein Konsistenzproblem vor. Es ähnelt dem Phantomproblem, welches im Zusammenhang mit dem Transaktionskonzept noch erläutert wird. Beispiel 7.155: Inkonsistentes Lesen Wegen der Personalstatistik wird regelmäßig ein Überblick über die Mitarbeiter mit einem Gehalt von über 1.000.000,– Euro im Monat benötigt. Diese Mitarbeiter werden in einer eigenen Sicht verwaltet. 1. Fall: Es wurden die Gehälter von Helge S. und H. Knebel von 5.100,– C bzw. 6.700,– C auf 3.100,– C bzw. 4.700,– C gekürzt. Konsequenz: Die beiden Mitarbeiter fallen aus der Sicht heraus. 2. Fall: Das Gehalt von D.T. Heck wird von 4.900,– C auf 5.400,– C erhöht. Konsequenz: Dieser Mitarbeiter wird in unsere Sicht aufgenommen.
Orthogonalitätsprobleme In einer voll orthogonalen Sprache wäre die Definition von Sichten einfach durchführbar. Orthogonalität wird aber trotz erheblicher Fortschritte vom SQL-92-Standard noch immer nicht
7.5 Datensichten
425
vollständig gewährleistet. Beispielsweise gibt es eine Regel, die besagt, dass Aggregatfunktionen nicht geschachtelt ausgeführt werden dürfen. Die Berechnung von AVG (SFW-Block mit GROUP BY-Klausel und SUM(Spalte) als Ausdruck der SELECT-Klausel) ist nicht erlaubt. Während Regeln wie diese bei der Definition von Basistabellen für den SQL-Programmierer zwar schwer nachvollziehbar, aber immerhin handhabbar sein dürften, führen sie im Umfeld von Sichten zu erheblichen Verständnisproblemen. Wenn beispielsweise die in der Sicht angebotene Spalte y eine aus einer Basistabelle über eine Aggregatfunktion abgeleitete Spalte darstellt (siehe obiges Beispiel mit SUM), so wird einem Benutzer die Anwendung einer Aggregatfunktion auf der y-Spalte nicht erlaubt, obwohl aus seiner Sicht keine geschachtelte Ausführung von Aggregatfunktionen vorliegt. Ein ähnliches Problem ergibt sich bei der Verwendung der GROUP BY-Klausel in einer Sichtendefinition. Beispiel 7.156: GROUP BY-Klausel in einer Sicht CREATE VIEW SichtSumme (attr1 , summe) AS SELECT attr1 , SUM(attr2 ) FROM Tab1 GROUP BY attr1 ; Soll auf SichtSumme die folgende Anfrage gestellt werden, SELECT FROM WHERE
∗ SichtSumme summe > 1.000.000 ;
so wird dieser Versuch fehlschlagen, weil zur Beantwortung der Anfrage die Sichtendefinition in die Anfrage eingebunden wird, so dass folgende syntaktisch inkorrekte Anfrage entsteht: SELECT attr1 , SUM (attr2) FROM SichtSumme WHERE SUM (attr2) > 1.000.000 GROUP BY attr1 ; Diese Konstellation ist nicht erlaubt, da in einer WHERE-Klausel keine Aggregatfunktion verwendet werden darf. Trotzdem gäbe es für diese Anfrage eine legale Variante, die wie folgt aussieht: SELECT attr1 , SUM (attr2 ) FROM SichtSumme GROUP BY attr1 HAVING SUM (attr2 ) > 1.000.000 ; Auf die immer noch mangelhafte Orthogonalität in SQL-92 werden wir später noch einmal zurückkommen.
426
7.5.4
7 Die relationale Datenbanksprache SQL
Änderungen auf Sichten
Um Sichten definieren zu können, muss es eine Abbildungsvorschrift geben, die festlegt, wie aus den Basistabellen eine virtuelle Tabelle, also die Sicht, abgeleitet werden kann. Leider bedeutet die Existenz einer solchen Abbildungsvorschrift nicht, dass auch für den umgekehrten Weg, der Abbildung der Zeilen der Sicht auf die Zeilen der Basistabelle, eine eindeutige Abbildungsvorschrift gefunden werden kann. Bei der Bildung von virtuellen Tabellen kann Semantik verloren gehen, deren Fehlen eine eindeutige Rückabbildung verhindert. Am einfachsten kann man sich das Problem anhand einer Sicht vorstellen, die aus einer Basistabelle durch Projektion ausschließlich auf Nichtschlüsselspalten entstanden ist. Begonnen werden soll mit dem leichteren Fall, der zumindest formal gesehen noch eine Rückabbildung zulässt. Sichten entsprechen Anfragen. Dies hat insbesondere zur Konsequenz, dass eine ausgewertete Sicht Duplikate enthalten kann, sofern in der SELECT-Klausel des die Sicht definierenden SFW-Blockes kein DISTINCT angegeben wurde. Auf unser Beispiel bezogen heißt das, dass in diesem Fall eine auf einer Sicht durchgeführte Änderungsoperation eindeutig auf die Basistabelle übertragen werden kann. Der Grund liegt darin, dass die Sicht wegen der fehlenden Duplikateliminierung genau so viele Zeilen enthält wie die Basistabelle. Da Zeilen keine eigene Identität besitzen, kann nicht eine spezielle Zeile angesprochen werden. Stattdessen müssen zum Beispiel Zeilen, die geändert werden sollen, über ihren Inhalt (assoziativ) bestimmt werden. Damit werden bei der Änderung einer Zeile der Sicht auch sämtliche Duplikate dieser Zeile mit geändert, weshalb der Abbildungsprozess auf die Basistabelle wieder eindeutig wird. Ob damit auch die Intention der Anwendung getroffen wurde, ist eine andere Frage. Beispiel 7.157: Änderungen bei Sichten mit Duplikaten Es wird eine Sicht gehalten, in der zu jedem Kunden die Produkttypen festgehalten werden, von denen er Produkte kauft. Nun soll der Produkttyp Hometrainer in Fitnessgeräte umbenannt werden. CREATE VIEW AS SELECT FROM WHERE UPDATE SET WHERE
KundeKauftProdukttypen kundenName, kundenVorname, produktTyp Kunden NATURAL JOIN Kauft NATURAL JOIN Produkt ort = ’Essen’;
KundeKauftProdukttypen produktTyp = ’Fitnessgeräte’ produktTyp = ’Hometrainer’;
Dieses auf den ersten Blick harmlos erscheinende Beispiel birgt eine ganze Menge an Konfliktpotenzial. Wegen der nicht vorgenommenen Duplikateliminierung lässt sich zwar die Änderung sauber auf die DB abbilden, allerdings könnte der Benutzer der Meinung sein, dass er damit bei allen Datensätzen in der DB den Typnamen geändert hat. Dies ist aber nicht der Fall, da er nur Zugriff auf Kunden aus Essen hat. Es besteht daher die Gefahr, dass die DB durch diese Änderung in einen inkonsistenten Zustand gelangt. Das Problem lässt sich darauf
7.5 Datensichten
427
zurückführen, dass Sichten nur bestimmte Ausschnitte des Datenbestandes widerspiegeln, für Änderungen allerdings der Gesamtzusammenhang klar sein muss. Deshalb ist eine wichtige Aufgabe des Datenbankprogrammierers, entweder Änderungsoperationen narrensicher zu gestalten oder dafür zu sorgen, dass der Benutzer alle notwendigen Informationen auch wirklich vorliegen hat. Richtig problematisch wird es aber erst, wenn in einer an sich duplikaterzeugenden Sicht Duplikate ausgeschlossen werden. Es entsteht das Problem, dass es keine eindeutige Abbildung von der Sicht zurück auf die Basistabellen gibt. Änderungen können damit nicht eindeutig in der Basistabelle nachgezogen werden. Allgemein tritt dieses Problem bei Verbundsichten und bei spaltenverändernden Sichten auf, bei denen Duplikate zwar auftreten können, über das DISTINCT-Schlüsselwort aber ausgeschlossen wurden.
Beispiel 7.158: Änderungen auf duplikatfreien Sichten CREATE VIEW AS (SELECT FROM UNION SELECT FROM
Lager produktLagerBez AS lagerBez, plz, ort, strasse, hausNr ProduktLager teileLagerBez AS lagerBez, plz, ort, strasse, hausNr TeileLager);
In diesem Beispiel würde sich eine Änderung auf der Sicht nicht mit Sicherheit eindeutig abbilden lassen, da die UNION-Klausel in dieser Form Duplikate vernichtet, falls es gemeinsame Lager für Produkte und Teile gibt. Deshalb ist die Eindeutigkeit der Rückabbildung der Sicht auf die Basistabelle nicht mehr garantiert.
Dasselbe Problem tritt auf, falls eine Sicht über eine Aggregatfunktion gebildet wurde, da auch Aggregatfunktionen (implizit) Duplikate entfernen.
Beispiel 7.159: Änderungen bei Sichten, die über Aggregatfunktionen gebildet wurden Ausgangspunkt sei noch einmal Beispiel 7.157, allerdings mit der kleinen Änderung, dass die Sicht noch eine weitere Spalte enthält, das Aufschluss darüber gibt, wie viele Produkte von diesem Typ der jeweilige Kunde kauft. KundeKauftProdukttypen kundenName, kundenVorname, produktTyp, COUNT(produktNr) AS anzahlProdukte FROM Kunden NATURAL JOIN Kauft NATURAL JOIN Produkt GROUP BY kundenName, kundenVorname, produktTyp;
CREATE VIEW AS SELECT
UPDATE SET WHERE
KundeKauftProdukttypen produktTyp = ’Hometrainer’ produktTyp = ’Fitnessgeräte’;
428
7 Die relationale Datenbanksprache SQL
Trotz der Tatsache, dass sich aus der Sicht des Benutzers eigentlich keine wesentlichen semantischen Unterschiede zwischen den jeweiligen Sichten von Beispiel 7.157 und Beispiel 7.159 ergeben, ist die eine Sicht änderbar, die andere nicht, ein Faktum, welches man dem Benutzer sicherlich nur sehr schwer wird beibringen können. Probleme kann es aber auch bei Einfüge- und Löschoperationen auf Sichten geben. Betrachten wir dazu wieder eine spaltenverändernde Sicht. Wurden bei der Sichtendefinition Spalten weggelassen, für die in der CREATE TABLE-Anweisung die Bedingung NOT NULL spezifiziert wurde, so kann eine Einfügung schon deshalb nicht funktionieren, weil der Benutzer Werte für Spalten angeben müsste, die er gar nicht kennt. Hier könnte man sich noch dadurch retten, dass man in der CREATE TABLE-Anweisung für alle Spalten, für die die NOT NULLBedingung spezifiziert wurde, einen Default angibt. Diese Lösung versagt aber, falls unter den bei der Sichtendefinition weggelassenen Spalten eine Spalte des Primärschlüssels ist. Beispiel 7.160: Änderungen bei spaltenverändernden Sichten Da der Prototyp der neuen Waschmaschine Luxus Weiß nach langer Forschungsphase fertig geworden ist, trägt der Chefingenieur die Waschmaschinendaten in die Kundensicht ein. CREATE VIEW AS SELECT FROM
KundenSicht produktNr, produktBez, produktTyp Produkt;
INSERT INTO VALUES
KundenSicht (20107, ’Luxus Weiß’, ’Waschmaschine’);
Da die ausgeblendeten Spalten von Produkt in der Schemadefinition mit der Option NOT NULL versehen wurden, darf die obige Einfügeoperation nicht ausgeführt werden. Ähnliche Probleme treten beim Löschen auf. Wurden bei einer duplikaterzeugenden Sichtdefinition die Duplikate entfernt, so ist die Abbildung auf die zu löschende(n) Zeile(n) der Basistabelle wieder nicht eindeutig. Wurden die Duplikate nicht eliminiert, mag die Frage erlaubt sein, ob ein Benutzer mit der Entfernung einer Zeile auch wirklich gleichzeitig alle auf der Ebene der Sicht mehrfach vorkommenden Zeilen, die auf der Ebene der Basistabellen allerdings Unikate darstellen müssen, mit löschen wollte, sich also der echten Auswirkungen der Löschoperation bewusst ist. Beispiel 7.161: Löschen auf Sichten Wegen zu hoher Kosten soll das Lager in Essen (in der Sicht Lager; siehe Beispiel 7.158) geschlossen werden.131 DELETE FROM Lager WHERE ort = ’Essen’; 131 Hier mag zwar die Wahrscheinlichkeit hoch sein, dass wirklich alle Lager geschlossen werden sollen, die es in Essen gibt (unabhängig davon, ob es Teile- oder Produktlager sind), aber dies ist trotzdem nur eine Annahme.
7.6 Die Datenkontrollsprache (DCL)
429
Zusammenfassend kann festgestellt werden, dass Änderungsoperationen auf Sichten scheitern können, weil sich die Änderung nicht eindeutig auf die Basistabellen abbilden lässt oder weil durch die Änderungsoperation die Integrität von solchen Daten der Basistabellen verletzt werden, die in der Sicht nicht sichtbar sind. Beide Fälle sind aus der Sicht des Benutzers nicht nachvollziehbar, da die Menge der einem Benutzer zugeordneten Sichten für ihn sein persönliches „konzeptuelles Datenbankschema“ darstellt. Hier steckt man also in dem Dilemma, einerseits Änderungen nicht durchführen zu können, andererseits dem Benutzer aber auch keine vernünftige Erklärung dafür geben zu können. Einfüge-, Änderungs- und Löschoperationen können insbesondere bei spaltenverändernden, Sichten und Verbundsichten zu Problemen führen. Mengenverändernde Sichten sind davon nur bedingt betroffen132. Wegen der genannten Probleme gibt es in SQL-92 Sichten, auf die nur lesend zugegriffen werden kann und solche, auf denen auch geändert werden darf. Damit Änderungen sauber und eindeutig auf die Basistabellen abgebildet werden können, müssen änderbare Sichten sehr harten Restriktionen gehorchen: 1. Die FROM-Klausel des SFW-Blockes muss sich auf genau eine Tabelle beziehen. Falls diese Tabelle eine Sicht darstellt, muss die Sicht änderbar sein. 2. In dem SFW-Block darf weder die GROUP BY- noch die HAVING-Klausel verwendet werden. 3. In dem SFW-Block wurden Duplikate nicht entfernt, was heißt, dass in der SELECTKlausel das DISTINCT-Schlüsselwort nicht verwendet wurde. 4. Die WHERE-Klausel des SFW-Blockes enthält keine weiteren SFW-Blöcke. 5. Die in der SELECT-Klausel des SFW-Blockes spezifizierten Spalten der Ergebnistabelle müssen eindeutig der Basistabelle zugeordnet werden können. Die Verwendung von arithmetischen Ausdrücken oder Aggregatfunktionen ist nicht erlaubt. Eine feinere Differenzierung erlaubt SQL-92 nicht. Grundsätzlich ist es nicht unwahrscheinlich, dass Sichten, die die obigen Kriterien nicht erfüllen, dennoch sowohl die Integrität der DB wahren als auch eindeutig auf die Basistabellen der DB abbildbar sind.
7.6
Die Datenkontrollsprache (DCL)
Der Begriff „Sicherheit“ im Zusammenhang mit Computersystemen wird äußerst vielseitig verwendet und umfasst ein Spektrum von moralischen/gesellschaftlichen Fragen, gesetzlich/rechtlichen Belangen, personellen und organisatorischen Aspekten bis hin zu technischen Vorkehrungen, die vor Verlust, Zerstörung oder Missbrauch von gespeicherter Information schützen sollen. Die DCL beinhaltet Mechanismen zur Realisierung von Datensicherheit. Die Datensicherheit widmet sich der Aufgabe, sensible oder persönliche Daten vor einer (absichtlichen) Beschädigung, Veränderung, Zerstörung oder Enthüllung zu schützen. Auf die 132 siehe
dazu die Diskussion unter „Inkonsistentes Lesen“ in Kapitel 7.5.3.
430
7 Die relationale Datenbanksprache SQL
verwandten Aspekte Datenschutz und Datensicherung wird im Unterkapitel 7.8 eingegangen werden. Schutzmechanismen können auf drei Ebenen zum Einsatz kommen: Identifikation und Authentisierung Benutzer, die Zugang zu einem DBS erhalten möchten, müssen sich normalerweise zunächst identifizieren. Dies kann auf vielfältige Art geschehen, im einfachsten Fall über die Eingabe einer Benutzeridentifikation. Über die Authentisierung versucht das System festzustellen, ob der aktuelle Benutzer auch derjenige ist, als der er sich ausgibt. Das einfachste Mittel zur Authentisierung ist das Passwort. Autorisierung und Zugriffskontrolle Auch wenn ein Benutzer mit einem DBS arbeiten darf, bedeutet dies nicht, dass man ihm einen beliebigen Zugriff auf alle Daten der DB zugestehen möchte. Über die Autorisierung und die damit verbundenen Zugriffskontrollen wird festgelegt, welche Arten von Zugriff auf welche Daten des DBS einem Benutzer oder einer Benutzergruppe erlaubt sind. Relationale DBMS unterstützen üblicherweise benutzergesteuerte Zugriffskontrollen. Diese basieren auf zwei unterschiedlichen Grundprinzipien: Das eine ist das so genannte Prinzip des „Eigentums an Information“, das zweite das Prinzip der „Weitergabe von Privilegien“. Unter „Eigentum an Information“ wird verstanden, dass genau der Benutzer, der die Daten angelegt hat, diese wie sein Eigentum behandeln darf und im Rahmen des Eigentumsrechtes alle Privilegien (Rechte) im Umgang mit diesen Daten besitzt. Eines dieser Privilegien ist die Weitergabe von Rechten an andere Benutzer, das dem zweiten Grundprinzip benutzergesteuerter Zugriffkontrollsysteme entspricht. Auditing Um sicherzustellen, dass die Autorisierungsregeln auch beachtet werden und um Versuche, diese Regeln absichtlich zu umgehen, erkennen zu können, können Informationen über den Zugriff auf die DB in einer eigenen Datei festgehalten werden. Das Festhalten solcher Informationen wird Auditing genannt. Ein typischer Eintrag in eine Auditingdatei mag wie folgt aussehen: • Anfrage (Datenbankoperation) • Terminal, von dem die Anfrage gestellt wurde • Benutzer, der die Anfrage gestellt hat • Datum und Zeit des Operationsaufrufes • Betroffene Tabellen, Zeilen und Spalten • Im Fall von Änderungen: alter Wert, neuer Wert
7.6 Die Datenkontrollsprache (DCL)
431
Datensicherheit erlangt nicht zuletzt seit der massiven Verdrängung von Großrechnern durch Client/Server-Architekturen eine immer größere Bedeutung. Leider haben die Maßnahmen zur Datensicherheit nicht mit den immens gestiegenen Anforderungen an die Abschottung von DBS gegenüber dem Missbrauch durch nichtautorisierte Personen mithalten können. Hierfür gibt es drei Gründe. Datensicherheit kostet und ist lästig Jeder kennt den Frust, wenn man nur mal schnell noch etwas machen möchte und die LoginProzedur zum Feierabendfresser wird. Oder dieses ewige Genörgele des Datensicherheitsbeauftragten, weil man noch immer nicht den Namen der eigenen Frau/des eigenen Mannes als Passwort abgelöst hat. Dabei ist der Nachwuchs erst unterwegs und hat noch keinen Namen, und an sich hatte man die Scheidung auch noch nicht ins Auge gefasst. Datensicherheit hat zwei große Nachteile. Aus Sicht des gutwilligen Benutzers ist sie etwas lästiges, deren Sinn man zwar abstrakt versteht, konkret aber eben nicht mit weniger Komfort bezahlen möchte. Gute und wirkungsvolle Datensicherheit setzt aber ein aktives und verantwortungsvolles Mitwirken der Benutzer voraus. Und sie kostet Leistung. Im Zweifelsfall werden dem Vertreter eines Anbieters eines DBMS an dieser Stelle gerne und sofort seine abstrakten und vagen Beteuerungen geglaubt, dass er auch schon von Sicherheitsproblemen bei der Konkurrenz gehört habe, aber das eigene System sei in dieser Hinsicht absolut wasserdicht. Und das, ohne dass der Benutzer etwas davon merkt. Der zweite große Nachteil ist die erhebliche Komplexität, die eine effektive und differenzierte Gewährleistung von Datensicherheit mit sich bringt. Wenn man sich einmal die ernst zu nehmenden, in der Literatur beschriebenen Ansätze ansieht, dann wird man zweierlei feststellen: • Man möchte das Verfahren gar nicht verstehen, weil man sich eigentlich für die nächsten drei Wochenenden schon etwas Netteres vorgenommen hatte. • Man findet solche Verfahren häufig nicht einmal ansatzweise in der Praxis. Diese Probleme und Widersprüche können nicht einfach aus der Welt geräumt werden, weshalb Datensicherheit auch in Zukunft immer wieder in den Negativschlagzeilen auftauchen wird.133
Datensicherheit hätte frühzeitig in den Architekturentwurf eines DBMS eingehen müssen Datensicherheit hätte schon frühzeitig als zentrale Anforderung an DBMS in den Architekturentwurf eingehen müssen. Dies ist aus vielerlei Gründen nicht geschehen. Nachträglich „aufgepfropfte“ Datensicherheit ist aber nicht mehr als ein Feigenblatt. 133 Die hohe Bedeutung, die dem Datenschutz zugemessen wird, kann man nicht zuletzt auch an der intensiven Abhandlung dieser Problematik in (Lehr)büchern erkennen. Da sind schnell schon einmal zwischen drei und fünf Sätze zu diesem Thema zu finden, wobei häufig sogar ein Eintrag im Index auftaucht. Dieser Tradition verschließt sich auch dieses Buch nicht.
432
7 Die relationale Datenbanksprache SQL
DBMS setzen auf tiefere Schichten eines Rechners auf DBMS werden zwar gelegentlich zur erweiterten Systemsoftware hinzugezählt, setzen aber auf anderen Diensten auf. Zu den genutzten Diensten zählen insbesondere Betriebssystemfunktionen und im Zuge der Dezentralisierung auch immer mehr die Netzwerkdienste. Selbst die beste Datensicherheit auf der Ebene des DBMS muss versagen, wenn die darunter liegenden Dienste diese nicht, nur unzureichend oder nur unabgestimmt gewährleisten. Hieraus kann direkt geschlossen werden, dass Datensicherheit keine isolierte Aufgabe ist, sondern als zentrale und umfassende Aufgabe beim Aufbau einer EDV-Landschaft berücksichtigt werden muss. Dies sollte natürlich nicht so verstanden werden, dass das DBMS dann damit nichts zu tun hat. Ohne geeignete Unterstützung durch das DBMS muss jeder Versuch scheitern, effektive Datensicherheit einzuführen. Aber es gilt eben auch das Umgekehrte. Ohne eine harmonische und abgestimmte Weiterführung von Datensicherheitsmaßnahmen auf allen Ebenen einer EDV-Landschaft ist das Projekt „Sicherheit“ zum Scheitern verurteilt. Wie bereits angedeutet, lässt sich über die Datenkontrollsprache (Data Control Language, abgekürzt DCL) nur ein vergleichsweise bescheidenes Spektrum an Maßnahmen gegen möglichen Datenmissbrauch spezifizieren, auch wenn hier wieder gesagt werden muss, dass es neben den standardisierten SQL-Konstrukten noch herstellerspezifische Sicherheitsmaßnahmen geben kann. Im Wesentlichen beschränkt sich die DCL auf die Spezifikation von Maßnahmen, die die Zugriffsrechte von Benutzern bzw. Benutzergruppen regeln. Grundsätzlich gibt es zwei Strategien, den Zugriff auf Daten festzulegen: 1. Es ist alles erlaubt, was nicht explizit verboten ist (optimistische Variante). 2. Es ist alles verboten, was nicht explizit erlaubt ist (pessimistische Variante). SQL realisiert die pessimistische Variante, die aus der Sicht der Datensicherheit auch die einzig sinnvolle ist. Jedes Datenbankobjekt, wozu neben Tabellen auch Sichten, Spalten, Wertebereiche und Integritätsbedingungen gerechnet werden, ist einem Eigentümer zugeordnet. Das ist im Normalfall derjenige, der das Datenbankobjekt angelegt hat. Der Eigentümer kann über den GRANT-Befehl Zugriffsrechte an andere Benutzer/Benutzergruppen vergeben. Der grundsätzliche Aufbau eines GRANT-Befehls ist dabei wie folgt:
Syntax 7.51: Rechtevergabe Rechtevergabe ::= GRANT {ALL PRIVILEGES | Privileg1 [, Privilegn ]∗ } ON {Tabelle | Sicht} TO {PUBLIC | Benutzer1 [, Benutzern ]∗ } [WITH GRANT OPTION]
7.6 Die Datenkontrollsprache (DCL)
433
Operation
Bedeutung135
SELECT
Ermöglicht das Lesen aller Spalten einer Tabelle.
DELETE
Ermöglicht das Löschen von Zeilen aus einer Tabelle oder nur das Löschen von Spaltenwerten von Zeilen, falls eine Liste von Spalten angegeben wurde.
INSERT
Erlaubt das Einfügen von Zeilen, wobei festgelegt werden kann, dass nur eine vorgegebene Menge von Spalten mit Werten belegt werden darf. Für die anderen Spalten kommt der (hoffentlich) spezifizierte Default zum Tragen. Aus offensichtlichen Gründen muss in der angegebenen Spaltenliste der Primärschlüssel und jede Spalte enthalten sein, für die die NOT NULL-Option ohne Angabe eines Defaults spezifiziert wurde.
UPDATE
Ermöglicht das Ändern von Zeilen in einer Tabelle oder nur das Ändern von Spaltenwerten von Zeilen, falls eine Liste von Spalten angegeben wurde.
REFERENCES
Erlaubt die Nutzung von Spalten aus der Spaltenliste als Fremdschlüssel bei der Definition einer anderen Tabelle.
Tabelle 7.24: Rechtevergabe für Operationen in SQL-92
Dabei kann Privileg die folgenden Operationen repräsentieren:134 • • • • •
SELECT, DELETE [(SpaltenName1 [,SpaltenNamen]∗ )], INSERT [(SpaltenName1 [,SpaltenNamen]∗ )], UPDATE [(SpaltenName1 [,SpaltenNamen]∗ )], REFERENCES [(SpaltenName1 [,SpaltenNamen]∗ )]
Unter Benutzeri kann man sowohl einen speziellen Benutzer als auch eine Benutzergruppe verstehen. Die WITH GRANT OPTION-Klausel drückt aus, dass derjenige, dem die Rechte zugewiesen wurden, diese auch an andere Benutzer weitergeben darf. Fehlt diese Klausel, besteht das Recht zur Weitergabe nicht. Tabelle 7.24 erläutert die mit der jeweiligen Operation verbundenen Rechte. Beispiel 7.162: Rechtevergabe 1. Das folgende SQL-Statement vergibt alle Rechte an der Tabelle Mitarbeiter an die Benutzergruppe PersonalAngelegenheiten.136 GRANT ALL PRIVILEGES ON Mitarbeiter TO PersonalAngelegenheiten; 134 Zur
Vollständigkeit fehlt noch die USAGE-Option, die hier nicht behandelt werden soll. ist hier als Oberbegriff für eine Basistabelle oder eine Sicht zu verstehen. 136 Eine Einschränkung der Privilegien auf Spalten durch Aufzählung der Spalten ist bei Angabe von ALL PRIVILEGES nicht zulässig. Dies ist nur bei Einzelauflistungen vorgesehen. 135 Tabelle
434
7 Die relationale Datenbanksprache SQL
2. Das folgende SQL-Statement vergibt alle Zugriffs- und Änderungsrechte an der Tabelle Mitarbeiter an die Benutzergruppe PersonalAngelegenheiten, mit Ausnahme des Änderungsrechtes an der Spalte gehalt. GRANT SELECT DELETE INSERT UPDATE ON TO
(mitarbeiterNr, mitarbeiterName, . . . , hausNr, einstellung, . . . , abteilungsNr), (mitarbeiterNr, mitarbeiterName, . . . , hausNr, einstellung, . . . , abteilungsNr), (mitarbeiterNr, mitarbeiterName, . . . , hausNr, einstellung, . . . , abteilungsNr), (mitarbeiterNr, mitarbeiterName, . . . , hausNr, einstellung, . . . , abteilungsNr) Mitarbeiter PersonalAngelegenheiten;
3. Über dieses SQL-Statement wird die Verwendung der angegebenen Spalten als Fremdschlüssel in einer anderen Tabelle zugelassen (also z. B. auftragsNr bei der Definition von AuftragPosition). GRANT ON TO
REFERENCES(auftragsNr) AuftragZulieferer TuNichtGut;
Der eine oder andere Leser mag verwundert sein, dass für Anfragen an eine Tabelle keine Einschränkungen definiert werden können, wo doch gerade das Sinn machen würde. So kann jeder das Gehalt seines Chefs lesen, falls er Zugriff auf die Mitarbeitertabelle hat. Gelöst werden kann dieses Problem über die Sichtendefinition (siehe Beispiel 7.163). Beispiel 7.163: Rechtevergabe für Anfragen über die Definition von Sichten CREATE VIEW AS SELECT FROM WHERE
MitarbeiterMitHohemGehalt ∗ Mitarbeiter gehalt > 6.000.000,– ;
CREATE VIEW AS SELECT
MitarbeiterOhneGehaltsspalte (mitarbeiterNr, mitarbeiterName, plz, . . ., hausNr, einstellung, abteilungsNr) Mitarbeiter;
FROM
GRANT ALL PRIVILEGES ON MitarbeiterMitHohemGehalt TO ChefPersonalAngelegenheiten; GRANT ALL PRIVILEGES ON MitarbeiterOhneGehaltsspalte TO PersonalAngelegenheiten;
7.6 Die Datenkontrollsprache (DCL)
435
Einmal erteilte Zugriffsrechte können über den REVOKE-Befehl wieder zurückgenommen werden. Syntax 7.52: Widerruf von Rechten RechteWiderruf ::= REVOKE [GRANT OPTION FOR] {ALL PRIVILEGES | Privileg1 [,Privilegn]} ON {Tabelle | Sicht} TO {PUBLIC | Benutzer1 [, Benutzern ]∗ } {CASCADE | RESTRICT} Es können entweder nur die Rechte zum Weitergeben von Rechten (GRANT OPTION FOR) oder alle in der nachfolgenden Klausel spezifizierten Rechte vollständig entzogen werden. Über die CASCADE-Option wird festgelegt, dass für den Fall, dass das Recht vorher mit der WITH GRANT OPTION vergeben worden war, auch all denjenigen die Rechte wieder entzogen werden, denen sie irgendwann einmal durch die hinter TO genannten Benutzer(gruppen) zuerkannt worden waren. Wird die RESTRICT-Option eingeschaltet, wird das Recht nur dann entzogen, wenn entweder die hinter TO genannten Benutzer(gruppen) die Rechte nicht weitergegeben hatten oder alle Weitergaben vorher explizit wieder zurückgenommen worden waren. Dem Besitzer einer Tabelle/Sicht können seine Rechte nicht entzogen werden. Abschließend kann festgestellt werden, dass die in SQL inkludierten Mechanismen zur Realisierung von Datensicherheit für Standardanwendungen durchaus ausreichen mögen. Der Einsatz von benutzergesteuerter Zugriffskontrolle ist jedoch für sicherheitskritische Datenbankanwendungen durch die beiden folgenden fundamentalen Einschränkungen limitiert: • Grant-Privileg Durch die Möglichkeit der Weitergabe einer Autorisierung von einem Benutzer an einen anderen liegt die Einhaltung einer Sicherheitspolitik in der Verantwortung der Datenbankbenutzer selber. Diese Tatsache führt zu zwei wesentlichen Sicherheitslücken: Erhält ein Benutzer Autorisierungen für ein bestimmtes Objekt von mehreren anderen Nutzern, so kann es bei der Rücknahme der Zugriffsberechtigung zu Auflösungsproblemen im Autorisierungsgraphen kommen. Als Zweites könnten Grant-Privilegien durch Trojanische Pferde genutzt werden, um Autorisierungen ohne Wissen der beteiligten Datenbankbenutzer weiterzugeben. Unter Trojanischen Pferden versteht man Software mit verdeckter Funktionalität, die möglicherweise böswillig in das System eingebracht wurde. Beispielsweise könnte in einem von einem Kollegen erhaltenen Sortierprogramm ein versteckter GRANT-Befehl eingebaut sein, der dem Kollegen Zugang zu ihm ansonsten verwehrten Daten ermöglicht. • Informationsflusskontrolle In einem System mit hohen Sicherheitsanforderungen reicht es oft nicht aus, das System nur vor dem nichtautorisierten Benutzer zu schützen. So ist als Sicherheitsrisiko auch vorstellbar, dass autorisierte Benutzer Information an nichtautorisierte Benutzer weitergeben könnten. Dies könnte absichtlich, z. B. durch Anfertigung einer Kopie und Weitergabe
436
7 Die relationale Datenbanksprache SQL
von dieser, oder aber unabsichtlich, z. B. durch ein Trojanisches Pferd, erfolgen. Eine Weitergabe von Informationen erfordert einen Informationsfluss zwischen Nutzern. Benutzergesteuerte Kontrollen beinhalten jedoch keine Möglichkeit, eine Weitergabe von Informationen einzuschränken.
7.7
Die Speicherungsstrukturdefinitionssprache (SSL)
Die Spezifikation des Datenbankschemas sollte ausschließlich auf logischer Ebene erfolgen, was heißt, dass Angaben zur internen Repräsentation und Ablage von Daten ebenso unterbleiben sollten wie Angaben zu Zugriffspfaden. Trotzdem sind Zugriffspfade und adäquate Speicherungstechniken für ein effizientes Arbeiten auf der DB von hoher Wichtigkeit. Wird häufig auf eine bestimmte Art und Weise mit einer Tabelle gearbeitet, beispielsweise indem die Tabelle Artikel häufig in der Reihenfolge der Artikelnamen durchlaufen wird, kann es sich lohnen, Zeilen dieser Tabelle auch in dieser Reihenfolge auf der Platte abzulegen, also zu clustern. Auch wenn häufig über bestimmte Spaltenwerte assoziativ auf Tabellen zugegriffen wird, kann es vorteilhaft sein, wenn für diese Spalten Zugriffspfade angelegt wurden. Die Definition von solchen Interna gehört nicht zur Datendefinitionssprache im engeren Sinn. Aus diesem Grund gibt es hier auch keine Standardisierung. Da sich dem Argument Effizienz jedoch kein Hersteller eines DBMS entziehen kann, gibt es in allen ernst zu nehmenden SQLDialekten Möglichkeiten, Zugriffspfade zu spezifizieren, Speichertechniken festzulegen oder sonst wie auf Interna Einfluss zu nehmen. Dies geschieht mit Hilfe der so genannten Speicherungsstrukturdefinitionssprache (Storage Structure Language, abgekürzt SSL). Hier soll nur beispielhaft auf eine mögliche Syntax für das Anlegen eines Zugriffspfades eingegangen werden: Syntax 7.53: Sekundärindex Sekundärindex ::= CREATE [UNIQUE] INDEX ZugriffspfadName ON Tabelle (SpaltenName [ASC | DESC] [, SpaltenName [ASC | DESC]]∗) Die Angabe von UNIQUE in dieser Klausel ist an sich deplatziert, da dadurch auf der Ebene von Zugriffspfaden festgelegt wird, dass eine bestimmte Spaltenkombination einen Schlüsselkandidaten darstellt. Eine solche Definition gehört eindeutig auf die Ebene des konzeptuellen Datenbankschemas, mithin in die CREATE TABLE-Anweisung. Trotzdem findet man diese Option noch in vielen kommerziellen DBMS, insbesondere deshalb, weil das Primärschlüsselbzw. Schlüsselkandidatenkonzept von vielen Systemen in der Vergangenheit nicht unterstützt wurde. Durch die (unsaubere) Unterstützung auf der Ebene von Zugriffspfaden wurde der Versuch unternommen, dieses Manko auszugleichen. Über ASC bzw. DESC wird eine auf- bzw. absteigende Sortierung des Indexes festgelegt. Beispiel 7.164: Sekundärindex CREATE INDEX mitarbeiterSort ON Mitarbeiter (mitarbeiterName DESC, mitarbeiterVorname DESC);
7.8 Datenschutz, Datensicherung und Datenkonsistenz
437
Zum Abschluss sei noch angemerkt, dass durch Zugriffspfade zwar der lesende Zugriff auf die Daten der DB erheblich beschleunigt werden kann, andererseits sich aber Nachteile beim Einfügen, Löschen oder Manipulieren der Daten ergeben, da neben der Bearbeitung der eigentlichen Daten zusätzlich noch die Zugriffspfade gewartet werden müssen.
7.8
Datenschutz, Datensicherung und Datenkonsistenz
Datenintegrität im weiteren Sinn bedeutet, dass eine DB eine konsistente Abbildung der Realität darstellt, ein DBMS also so arbeitet, dass weder Daten verloren gehen noch inkorrekte oder widersprüchliche Daten entstehen können und weiterhin sichergestellt ist, dass nur diejenigen Zugriff auf die Daten erhalten, denen dieser Zugriff auch zusteht. Datenintegrität lässt sich demnach in die folgenden drei Blöcke aufteilen: 1. Datenschutz 2. Datensicherung 3. Datenkonsistenz
Datenschutz Der Datenschutz ist im Bundesdatenschutzgesetz geregelt und umfasst die informationelle Selbstbestimmung der Speicherung personenbezogener Daten über Individuen. Da es sich hierbei im Wesentlichen um gesetzliche Bestimmungen handelt, soll dieser Aspekt hier nicht weiter vertieft werden. Datensicherung Bei Datensicherungskonzepten geht es in erster Linie um Maßnahmen, über die gewährleistet werden soll, dass bei unvorhersehbaren Ereignissen wie Feuer-, Wasserschäden, Diebstahl, technischen Defekten und Systemfehlern der zuletzt gültige Datenbankzustand wiederhergestellt werden kann. Datensicherung muss über technische Maßnahmen, wozu insbesondere das regelmäßige Kopieren des Datenbestandes auf autonome Speichermedien (Backup) gehört, sichergestellt werden. Auf den letzten Aspekt werden wir noch einmal in Zusammenhang mit der Recovery zurückkommen. Datenkonsistenz Datenkonsistenz und semantische Integrität werden i. d. R. als Synonyme verwendet. Beide bezeichnen Vorkehrungen, die dafür Sorge tragen, dass die Daten in der DB einerseits widerspruchsfrei sind, andererseits den wahren (Realwelt-)Gegebenheiten möglichst nahe kommen. Da ein DBMS über kein „Allgemeinwissen“ verfügt und Rechner nach wie vor nicht als intelligent angesehen werden können, kann ein DBMS die Konsistenz von Daten nicht garantieren.
438
7 Die relationale Datenbanksprache SQL
Es kann aber wenigstens über das Abprüfen von ihm bekannt gemachten Integritätsbedingungen offensichtliche Konsistenzverletzungen bemerken und beseitigen. Edgar Codd unterscheidet fünf Typen von Integritätsbedingungen, die in einer leicht anderen Klassifikation bereits in Kapitel 7.2.4.1 diskutiert wurden: 1. Integritätsbedingungen auf Wertebereichen 2. Integritätsbedingungen auf Spalten 3. Integritätsbedingungen auf Zeilen 4. Referenzielle Integrität 5. Benutzerdefinierte bzw. allgemeine Integritätsbedingungen (Trigger) Auf die ersten vier Varianten soll hier nicht mehr eingegangen werden, da dies bereits in Kapitel 7.2.4.1 geschehen ist. Allgemeine Integritätsbedingungen (Datenbankprozeduren, Zusicherungen und Trigger) Datenbankprogrammierung war zumindest in der Vergangenheit keine gewöhnliche Programmierung, da sowohl das normale wie auch das eingebettete SQL nur eine eingeschränkte Funktionalität bereitstellen. Die eigentliche Programmierung von Funktionen muss in den Anwendungen stattfinden. Nun ist aber einerseits der „prozedurale“ Umfang von SQL erweitert worden – es gibt jetzt z. B. auch bedingte Anweisungen (CASE-Statement) – und andererseits wurden Schnittstellen zu konventionellen Programmiersprachen entwickelt, die es erlauben, beliebige, in konventionellen Programmiersprachen geschriebene Funktionen in das DBMS einzugliedern und diese so zu benutzen, als wären sie ureigene Bestandteile des DBMS. Solche Datenbankprozeduren bzw. Trigger wurden vor allem auch zur Integritätssicherung eingeführt, können aber auch wesentlich breiter genutzt werden. So ist es beispielsweise möglich, über Datenbankprozeduren objektspezifische Operationen in das DBS einzubringen und damit Funktionalität aus der Anwendung in das DBS zu verlagern. Solche Möglichkeiten werden heute von den meisten kommerziellen DBMS angeboten, gehören allerdings nicht zum SQL-92-Standard. Neben Datenbankprozeduren und Triggern gibt es noch die so genannten Zusicherungen (assertions), die allgemeine, in SQL spezifizierbare Integritätsbedingungen darstellen, also auch standardisiert sind. Im Folgenden sollen die einzelnen Varianten erläutert werden. Zusicherungen Alle bisher kennen gelernten Varianten von Integritätsbedingungen müssen direkt im Kontext von Tabellendefinitionen oder Wertebereichseinschränkungen definiert werden. Es gibt aber auch eine Variante, die Zusicherungen (assertions), die ohne direkten Kontext allgemein auf der Schemaebene definiert werden können. Zusicherungen sind mit dem Ziel eingeführt worden, tabellenübergreifende Integritätsbedingungen auf einer für sie adäquaten Ebene definieren zu können. Zusicherungen müssen feste Namen besitzen, da sie nicht über ein Vaterobjekt ansprechbar sind. Ohne Namen würden sie im luftleeren Raum hängen, da es dann keinen Einstiegspunkt gäbe, über den man sie ansprechen könnte.
7.8 Datenschutz, Datensicherung und Datenkonsistenz
439
Syntax 7.54: Zusicherungen CREATE ASSERTION NameZusicherung CHECK (KomplexeBedingung) [ZeitpunktPrüfung] Beispiel 7.165: Zusicherungen „Um Verluste zu vermeiden, soll festgeschrieben sein, dass der höchste an Kunden vergebbare Rabatt nicht die durchschnittliche Gewinnmarge über alle Produkte überschreiten darf.“ CREATE ASSERTION RabattGewinnmarge CHECK ((SELECT MAX(rabatt) FROM Kunden) < (SELECT (1 − (AVG(stueckKosten)/AVG(nettoPreis))) ∗ 100 FROM Produkt)) Zusicherungen sind nichts grundsätzlich Neues. Außer in der einleitenden Zeile unterscheiden sie sich syntaktisch nicht von einer benannten (constraint) oder unbenannten Einschränkung. Alle drei Varianten basieren auf der CHECK-Klausel. Deshalb sind sie auch in ihrer Ausdruckskraft gleich mächtig. Da die Bedingung einer CHECK-Klausel eine beliebig komplexe Anfrage darstellen kann, ist es demnach prinzipiell auch möglich, eine mehrere Tabellen betreffende Restriktion bei einer der beteiligten Tabellen anzusiedeln. Umgekehrt kann auch eine sich auf eine Tabelle beziehende Einschränkung als Zusicherung auf Schemaebene definiert werden. Die unterschiedlichen Varianten von Integritätsbedingungen sind also kein Mittel zur Verbesserung der Ausdrucksmächtigkeit, sondern sollen vor allem helfen, eine modulare, leserliche Schemadefinition zu ermöglichen, bei der Bedingungen und Aussagen dort spezifiziert werden können, wo sie auch am ehesten hingehören. An Beispiel 7.165 kann man sehr schön die Problematik ablesen, die mit Zusicherungen verbunden ist. Da sie sich nicht auf eine Tabelle oder eine Spalte beziehen, sind die mit ihnen verbundenen Auswirkungen nicht immer direkt zu übersehen. Erhöhen sich beispielsweise sukzessive aus unterschiedlichen Gründen die Stückkosten und würde dadurch die obige Zusicherung verletzt, würde (willkürlich) irgendwann quasi das Fass überlaufen, sprich die Zusicherung verletzt werden. Das hätte zur Konsequenz, dass (willkürlich) die letzte Änderung der Stückkosten zurückgewiesen wird. Ein zweites Problem, was man auch an Beispiel 7.165 gut erkennen kann, ist, dass Zusicherungen mit Overhead verbunden sind. Jede Änderung eines Rabattes oder der Nettopreise oder der Stückkosten muss die Überprüfung der Zusicherung auslösen. Wenn also mit Integritätsbedingungen und insbesondere mit Triggern und Zusicherungen zu fahrlässig umgegangen wird, kann dies zu merklichen Performanzeinbußen führen. Schließlich ist festzustellen, dass das DBMS nicht generell in endlicher Zeit die Korrektheit, Widerspruchsfreiheit und Ausführbarkeit von Zusicherungen, Triggern und Datenbankprozeduren bestimmen kann. Diese Probleme haben dazu geführt, dass diese Konzepte trotz ihrer Mächtigkeit und Sinnhaftigkeit immer nur sehr zurückhaltend von kommerziellen DBMSAnbietern angegangen wurden. Insbesondere von weniger erfahrenen Anwendern lässt sich durch Verwendung dieser Konzepte auch viel kaputt machen.
440
7 Die relationale Datenbanksprache SQL
Einschränkungen sind in einen Kontext eingebettet, da sie exakt einer Tabelle zugeordnet werden. Werden deshalb beispielsweise Spalten ohne Nennung dieser Tabelle angesprochen, so ist der Bezug trotzdem implizit dadurch gewahrt, dass die Einschränkung im Kontext dieser Tabelle entstanden ist. Bei Zusicherungen muss hingegen spezifiziert werden, auf welche Tabellen und Spalten sie sich beziehen, da sie tabellenübergreifend angelegt werden. Die Zusicherung von Beispiel 7.165 hätte auch als Einschränkung im Umfeld der Definition der Tabelle Produkt – und zwar als gebundene oder als freie Version – formuliert werden können (siehe Beispiel 7.166). Beispiel 7.166: Tabellenübergreifende Integritätsbedingungen an Tabelle gebundene Variante ohne Kontextspezifikation: CREATE TABLE nettoPreis stueckKosten
Produkt ... ...
... CONSTRAINT RabattGewinnmarge137 CHECK ((SELECT MAX(rabatt) FROM Kunden) < (1 − (AVG(stueckKosten)/AVG(nettoPreis))) ∗ 100); innerhalb einer Tabelle spezifizierte freie Variante mit Kontextspezifikation: Produkt( ... ... ...) CONSTRAINT RabattGewinnmarge CHECK ((SELECT MAX(rabatt) FROM Kunden) < (SELECT (1 − (AVG(stueckKosten)/AVG(nettoPreis)))∗ 100 FROM Produkt));
CREATE TABLE nettoPreis stueckKosten
Wie man Beispiel 7.166 entnehmen kann, muss bei einer tabellenbezogenen Integritätsbedingungen der Kontext nicht angegeben werden, sofern er durch die Tabelle bereits gegeben ist. Genau genommen kann eine Anfrage genau dann durch die ausschließliche Angabe einer Spalte oder einer einfachen Berechnung ersetzt werden, wenn nur die SELECT- und die FROM-Klausel in der Anfrage benutzt werden müssten. Die FROM-Klausel ist nicht notwendig, da sich die Anfrage auf die zu Grunde liegende Tabelle bezieht. Die SELECT-Klausel kann wegfallen, da die Spalte bzw. die Berechnung exakt dem entspricht, was ansonsten hinter dem SELECT-Schlüsselwort stehen würde. Datenbankprozeduren Datenbankprozeduren oder Stored Procedures, wie sie „eingedeutscht“ heißen, können als Bindeglied zwischen der eingeschränkten prozeduralen Mächtigkeit von SQL und der vollen prozeduralen Mächtigkeit einer Programmiersprache angesehen werden. Im Gegensatz zu 137 Die
Benennung der Einschränkung könnte auch noch weggelassen werden.
7.8 Datenschutz, Datensicherung und Datenkonsistenz
441
den schon eingeführten Zusicherungen und Einschränkungen, die ihre jeweiligen Grenzen in der eingeschränkten Ausdrucksmächtigkeit von SQL finden, kann sich hinter einer Datenbankprozedur eine beliebige138 , in einer konventionellen Programmiersprache geschriebene Prozedur verstecken. Ohne zu sehr auf die sehr rege Diskussion der Vor- und Nachteile einer vollen prozeduralen Ausdrucksmächtigkeit eingehen zu wollen, sollen hier doch wenigstens die wichtigsten Fakten angerissen werden. Datenbankprozeduren verhelfen einem DBMS zu einer wesentlich erweiterten Ausdrucksmächtigkeit, da beliebige Prozeduren integrierbar sind. Damit ist auch alles innerhalb eines DBS formulierbar, was auch in einer konventionellen Programmiersprache ausgedrückt werden könnte. Das DBMS wird turingvollständig. Grundsätzlich wäre es deshalb sogar möglich, die Anwendung vollständig in das DBMS zu integrieren, eine Handlungsalternative, die im Normalfall allerdings nicht zu empfehlen ist. Beispiel 7.167: Datenbankprozedur Es wird angenommen, dass zusätzlich zur Tabelle Teil eine Tabelle EnthältTeil mit den Spalten oberteilNr und unterteilNr eingeführt wurde, wobei beide Spalten als Fremdschlüssel auf einen Datensatz der Tabelle Teil verweisen. Über den Fremdschlüssel kann ermittelt werden, aus welchen Einzelteilen ein (übergeordnetes) Bauteil zusammengesetzt ist. Diese Einzelteile bestehen ihrerseits wiederum aus (untergeordneten) Einzelteilen usw. (Stückliste). In SQL-92 ist es nun nicht möglich, eine Anfrage zu formulieren, die zu einem bestimmten Bauteil bei beliebiger Schachtelungstiefe (rekursiv) die untergeordneten Bestandteile, deren untergeordneten Bestandteile usw. ausgibt. Eine Datenbankprozedur für dieses Problem kann in „Pseudo-PASCAL“ folgendermaßen formuliert werden: PROCEDURE AuflistungBestandteile(aktuelleTeilNr, schachtelungsTiefe: INTEGER) VAR i, j, /*Laufvariable anzahl: INTEGER; /*Anzahl der vom SQL-Aufruf zurückgegebenen Werte liste: ARRAY [1..1000] OF INTEGER; /*Liste der zurückgegebenen Werte; für den hier gegebenen Demonstrationszweck wird unterstellt, dass ein ARRAY der spezifizierten Größe immer ausreicht
BEGIN FOR i = 0 TO schachtelungsTiefe DO BEGIN WRITE(’ ’); /*Ausgabe der Teilnr des Bauteils auf den Bildschirm, entsprechend WRITELN(aktuelleTeilNr); /*der Schachtelungstiefe um einige Stellen eingerückt anzahl=EXEC SQL SELECT unterteilNr INTO liste FROM EnthältTeil WHERE EnthältTeil.oberteilNr = aktuelleTeilNr; /* Aufruf des SQL-Statements, das die Bestandteile des Teils aus der DB ausliest und in der Liste ablegt. Außerdem wird durch den Aufruf die Anzahl der selektierten Sätze bzw. beim Auftreten eines Fehlers oder bei nicht vorhandenen Datensätzen ein Wert ≤ 0 zurückgeliefert. 138 Beliebig muss insofern eingeschränkt werden, als dass die Programmiersprache auch vom entsprechenden DBMS unterstützt werden muss.
442
7 Die relationale Datenbanksprache SQL FOR j = 1 TO anzahl DO AuflistungBestandteile(liste[i], schachtelungsTiefe+1); /* Rekursiver Aufruf dieser Prozedur für alle Einzelteile, aus denen das aktuelle Bauteil besteht. Der Aufruf findet nicht mehr statt (die Rekursion bricht ab), wenn für ein Bauteil kein Bestandteil mehr existiert (anzahl ≤ 0), es also atomar ist.
END END AuflistungBestandteile;139 Die Prozedur kann über CALL AuflistungBestandteile(teilNr, 0) aufgerufen werden. Wie man der obigen Beschreibung entnehmen kann, sind Datenbankprozeduren nicht nur im Zusammenhang mit der Integritätssicherung nutzbar, sondern bieten ganz allgemein die Möglichkeit, eine (in einer beliebigen Programmiersprache geschriebene) Routine auszuführen. Eine Datenbankprozedur wird üblicherweise allgemein einem Datenbankschema zugeordnet, ist also nicht an einen bestimmten im Schema definierten Datentyp (hier im Sinne von Tabelle gemeint) gebunden. Wir haben sie hier ein wenig inkorrekt unter der zu einschränkenden Überschrift Datenschutz, -sicherheit und -konsistenz behandelt. Der Leser möge uns dies verzeihen und im Hinterkopf behalten, dass eine Datenbankprozedur eine Möglichkeit ist, beliebigen Code aus der Anwendung heraus in das DBS und unter die Kontrolle des DBS zu verlagern. Trigger Ein Trigger stellt eine besondere Form von Datenbankprozedur dar. Letztere wird immer dann ausgeführt, falls sie explizit aufgerufen wird (entspricht dem üblichen Prozeduraufruf). Ein Trigger wird dagegen durch den Auftritt eines bestimmten Ereignisses ausgelöst. Im Allgemeinen besteht ein Trigger aus vier Bestandteilen: • • • •
Name Auslöser/Ereignis Bedingung Aktion
Die grundsätzliche Arbeitsweise eines Triggers kann man sich wie folgt vorstellen: ON Ereignis IF Bedingung DO Aktion Beispiele für Ereignisse sind das Ändern, Einfügen oder Löschen von Daten oder das Aufrufen bzw. Beenden einer Transaktion. Gegebenenfalls kann zusätzlich noch spezifiziert werden, zu welchem Zeitpunkt der Trigger ausgeführt werden soll, also beispielsweise vor dem eigentlichen Abarbeiten oder Starten des Ereignisses oder danach. Soll beispielsweise ein Kundenauftrag ausgeliefert werden, könnte ein Trigger zunächst prüfen, ob bereits genügend Produkte auf Lager sind, um den Auftrag auszuführen, oder der Trigger könnte nachher überprüfen, ob ein gewisser Mindestlagerbestand des Produktes noch gewährleistet ist und falls nicht, eine Produktion oder Nachbestellung auslösen. Im Bedingungsteil können noch bestimmte Bedingungen abgeprüft werden, die zusätzlich zum Ereignisauftritt vorliegen müssen, damit der Aktionsteil ausgeführt wird. So könnte bei139 Effizienzgesichtspunkte spielen in diesem Beispiel keine Rolle, was man daran sieht, dass bei jedem Rekursionsschritt ein SQL-Aufruf stattfindet. Effizienter könnte es sein, mit einem einzigen SQL-Aufruf die gesamte Tabelle Teil einzulesen, um sie anschließend „zu Fuß“ auszuwerten.
7.8 Datenschutz, Datensicherung und Datenkonsistenz
443
spielsweise bei Unterschreitung eines Mindestlagerbestandes zunächst überprüft werden, ob auch auf den anderen Lagern der Bestand so kritisch wird, dass eine Nachbestellung bzw. Produktion Sinn macht. Solche aus einem Ereignis, einer Bedingung und einer Aktion bestehende Konstrukte werden auch unter dem Begriff ECA-Regeln (event-condition-action rules) geführt. Sie spielen eine zunehmende Rolle im Zusammenhang mit der Diskussion um aktive DBMS. Hier soll nur noch erwähnt werden, dass ECA auch zu EA schrumpfen kann und dann einen Trigger darstellt, dessen Aktion bei Auftritt eines Ereignisses auf jeden Fall ausgeführt wird. Beispiel 7.168: Trigger Bei der Einstellung eines neuen Mitarbeiters soll die Anzahl der Mitarbeiter der betroffenen Abteilung automatisch um eins erhöht werden. CREATE TRIGGER ErhoeheMitarbeiterZahl140 AFTER INSERT INTO Mitarbeiter REFERENCING NEW AS M BEGIN UPDATE Abteilung SET mitarbeiterZahl = mitarbeiterZahl + 1 WHERE M.abteilungsNr = Abteilung.abteilungsNr; END; Der Aliasname M verweist hierbei durch die Klausel REFERENCING NEW AS auf den neuen Datensatz in der Tabelle Mitarbeiter. Trigger sind ein sehr mächtiges Konzept, da sie die Modellierung und automatische Abarbeitung von sehr komplexen Aufgaben ermöglichen. Allerdings sind sie auch sehr gefährlich. Die wesentlichen Fallen sollen hier noch kurz erwähnt werden: Widersprüche und Deadlocks Trigger sind ganz allgemein Prozeduren, die unter bestimmten Bedingungen beim Auftritt bestimmter Ereignisse ausgelöst werden. Wie kann sichergestellt werden, dass Trigger sich weder widersprechen (siehe Beispiel 7.169) noch in eine gegenseitige Blockade führen? Rekursion Wie kann sichergestellt werden, dass das Ausführen eines Triggers keine unendlich währende Rekursion zur Folge hat (siehe Beispiel 7.170)? Abarbeitungsreihenfolge Bei einem Ereignis können prinzipiell mehrere Trigger feuern. Es stellt sich daher die Frage, in welcher Reihenfolge diese Trigger abgearbeitet werden. Da durch das Ausführen der Trigger wieder andere Trigger ausgelöst werden können, stellt sich hier das Problem noch einmal. Grundsätzlich ist ein Tiefendurchlauf oder ein Breitendurchlauf möglich. Beim Tiefendurch140 Dieser Trigger besteht nur aus einer Bedingung (ON-Teil, hier AFTER . . .) und einer Aktion (DO-Teil, hier UPDATE . . .); der Bedingungs(IF)-Teil fehlt.
444
7 Die relationale Datenbanksprache SQL
lauf wird zunächst der gegebene Trigger samt seiner von ihm rekursiv ausgelösten Trigger vollständig abgearbeitet, bevor der nächste Trigger bearbeitet wird. Beim Breitendurchlauf hingegen werden erst alle Trigger einer Ebene abgearbeitet, dann alle Trigger, die durch die ersten Trigger ausgelöst wurden usw. Effizienz Die Ausführung von Triggern ist nicht kostenneutral. Da sie durch bestimmte Ereignisse ausgelöst werden, muss grundsätzlich bei Auftritt von Ereignissen, die Trigger auslösen können, überprüft werden, ob ein Trigger feuert. Dies kann sehr viel Overhead verursachen und damit viel Performanz kosten. Datensicherheit Es muss sichergestellt werden, dass über Trigger nicht ein indirekter Weg geöffnet wird, über den Benutzer auf Tabellen zugreifen können, obwohl sie ansonsten nicht das Recht dazu haben. Dieses Problem ist nicht einfach zu lösen, da es aus der Sicht der Datensicherheit darauf ankommt, ob der Benutzer etwas von den zusätzlichen Aktionen mitbekommen kann – wodurch die Datensicherheit verletzt werden könnte – oder ob diese Aktionen nicht gerade zur Gewährleistung der Datensicherheit ausgeführt werden. Da die Grenzen oft fließend sind, ist eine allgemeingültige und alle Seiten befriedigende Lösung schwer zu finden. Beispiel 7.169: Sich widersprechende EA-Trigger141 CREATE TRIGGER RabattZuHoch AFTER UPDATE rabatt FROM Kunden BEGIN IF rabatt > 20 THEN rabatt = 5; END; CREATE TRIGGER RabattZuNiedrig AFTER UPDATE rabatt FROM Kunden BEGIN IF rabatt < 6 THEN rabatt = 25; END; Diese sicherlich etwas unsinnig formulierten Trigger würden zu einer Endlosschleife führen. Beispiel 7.170: Unendliche Rekursion CREATE TRIGGER RabattZuHoch AFTER UPDATE rabatt FROM Kunden BEGIN rabatt = rabatt − 1; END; Da der Trigger auch wieder eine Update-Aktion auslöst, wird er (theoretisch) zu einer unendlich laufenden Rekursion führen. 141 Diese Trigger werden mangels Standardisierungsvorschlag in einer intuitiven Form vorgestellt. Sie stützen sich auf keine reale Implementierung ab.
7.9 Kritische Würdigung von SQL-92
445
Von Kritikern wird angeführt, dass mit Datenbankprozeduren und Triggern auch dem Trojanischen Pferd das Tor geöffnet wird. Wie jede konventionelle Prozedur, deren absolute Korrektheit (im mathematischen Sinn) im Allgemeinen nicht nachgewiesen werden kann, können Datenbankprozeduren142 durch Programmierfehler oder Fehlfunktionen die Konsistenz des Datenbestandes gefährden. Der Zugriff auf die Daten geschieht nicht mehr ausschließlich von außen über die in ihrer Funktionalität sehr eingeschränkte und damit gut überschau- und überprüfbare SQL-Schnittstelle. Stattdessen kann tief im Inneren des DBS direkt auf den Daten gearbeitet werden. Damit können eingebaute Sicherheitsmechanismen, wie z. B. das Transaktionskonzept oder die Recovery, umgangen oder in ihrer Funktionalität und damit Wirkung abgeschwächt werden. Der zweite wesentliche Faktor ist, dass Allgemeinheit und Optimierbarkeit zwei Eigenschaften sind, die sich aus der Sicht der Optimierung kaum unter einen Hut bringen lassen. Die zur effizienten Massendatenverarbeitung dringend notwendige umfassende Optimierung lässt sich nur durchführen, wenn man sich auf eine sehr übersichtliche Menge von Operationen abstützen kann, deren Semantik und Eigenschaften genau bekannt sind. Wenn weder der „Preis“ einer Operation noch deren Beziehung zu anderen Operationen (beispielsweise Kommutativität oder Assoziativität) bekannt sind, kann nur sehr global und damit wenig effizient optimiert werden. Eine in konventionellen Code eingebettete SQL-Anfrage wird im Regelfall erheblich langsamer abgearbeitet werden, als ihr direkter SQL-Pendant. Dosiert und vorsichtig eingesetzt können Datenbankprozeduren durchaus helfen, die Qualität der Anwendungsunterstützung und die automatische Konsistenzüberwachung der Daten durch das DBMS substanziell zu verbessern. Die Grenzen sind allerdings fließend. Übertrieben und konzeptlos eingesetzt können sie zu massiven Problemen führen bis hin zur (teilweisen) Zerstörung (der Konsistenz) des Datenbestandes.
7.9
Kritische Würdigung von SQL-92
Während das relationale Datenbankmodell wegen seiner Einfachheit und der mathematischen Grundlage als Basis für die Ablage von einfach strukturierten Daten eine breite Anhängerschaft besitzt, gehen die Meinungen in Bezug auf SQL stärker auseinander. Hier gibt es eine durchaus ernst zu nehmende Schar von Kritikern, zu denen nicht zuletzt auch der Vater des relationalen Datenbankmodells Edgar Codd sowie Chris Date und Hugh Darwen gehören, zwei (Ex-)IBM-Mitarbeiter, die sich um die Verbreitung des relationalen Datenbankmodells sehr verdient gemacht haben. Hier scheint sich zu rächen, dass sich die Entwickler von SQL trotz der Tatsache, dass es mit der Relationenalgebra und dem Relationenkalkül bereits zwei auf einer mathematischen Grundlage beruhende Anfragesprachen gab, nicht dazu entschließen konnten, auch SQL auf einer sauberen mathematischen Theorie aufzubauen. Auch wenn einige der gröbsten Ungereimtheiten, beispielsweise die fehlende Orthogonalität von SQL, durch den SQL-92-Standard erheblich verbessert wurden, lässt sich nach wie vor nicht übersehen, dass SQL mit Problemen behaftet ist, die sich insbesondere immer wieder im Detail offenbaren. Auf diese wollen wir hier nicht weiter eingehen, da dies zum Teil bereits vorher geschehen ist. Stattdessen sollen einige grundsätzliche Kritikpunkte angesprochen werden. 142 Im
Folgenden wird zwar immer nur von Datenbankprozeduren die Rede sein, gemeint sind aber auch Trigger.
446
7 Die relationale Datenbanksprache SQL
Duplikate Die Nichteliminierung von Duplikaten wurde aus Performanzgründen und deshalb eingeführt, damit Aggregatfunktionen wie COUNT, AVG und SUM korrekt arbeiten. Würden bei der Berechnung dieser Funktionen die Duplikate nicht mit berücksichtigt werden, könnten sich erhebliche Abweichungen gegenüber dem erwarteten Ergebnis ergeben. Von den Kritikern, vor allem Edgar Codd und Chris Date, wird konstatiert, dass dieses Zugeständnis mit erheblichen Nachteilen für die anderen relationalen Operatoren bezahlt werden muss. Edgar Codd kritisiert zum Beispiel, dass die Auswirkungen auf andere relationale Operatoren nicht erst untersucht wurden, bevor man sich zur Zulassung von Duplikaten entschloss. Die Probleme traten dann erst im Nachhinein zu Tage. Während beispielsweise auf der Basis von duplikatfreien Tabellen Projektion und Verbund kommutativ sind, zumindest solange durch die Projektion keine der Spalten, über die der Verbund durchgeführt werden soll, entfernt wird, ist diese Kommutativität durch die Einführung von Tabellen mit Duplikaten nicht mehr sichergestellt. Probleme dieser Art sind nicht zuletzt dafür verantwortlich, dass trotz der altbekannten Tatsache, dass die drei wichtigsten Kriterien für jedes Softwareprodukt Performanz, Performanz und Performanz sind, die Optimierer in vielen kommerziellen relationalen DBMS immer noch sehr einfach strukturiert und damit weit von ihrer potenziellen Leistungsfähigkeit entfernt sind. Probleme mit Nullmarken Bei der Verwendung von Nullmarken in SQL muss angemerkt werden, dass insbesondere beim Einsatz von Aggregatfunktionen Ergebnisse entstehen können, die aus mathematischer Sicht nicht korrekt sind. Angenommen, es soll das Durchschnittsgehalt aller Mitarbeiter bestimmt werden. Dazu kann die AVG-Funktion eingesetzt werden, von der man erwarten würde, dass sie zunächst alle Gehälter aufsummiert und das Ergebnis dann durch die Anzahl der Mitarbeiter teilt. Dementsprechend wäre SELECT AVG(Gehalt) FROM Mitarbeiter = SELECT SUM (Gehalt) / COUNT(∗) FROM Mitarbeiter eine korrekte Annahme. Falls es in der Tabelle Mitarbeiter allerdings Zeilen geben sollte, bei denen das Gehalt mit der Nullmarke belegt ist, gilt diese mathematische Selbstverständlichkeit nicht. Die AVG-Funktion entfernt zunächst alle Zeilen, die in der Gehaltsspalte eine Nullmarke aufweisen, und berechnet auf der Basis der verbleibenden Zeilen das Durchschnittsgehalt. Die COUNT(∗)-Funktion berücksichtigt allerdings alle Zeilen, weshalb bei dieser Variante bei der Berechnung des Durchschnittsgehaltes auf jeden Fall ein niedrigerer Wert herauskommen wird. Leider kommen Inkonsistenzen dieser Art häufiger in SQL vor. Natürlich bemüht sich die Standardisierungskommission, bei bekannt werden solcher Schwachstellen, diese mit dem nächsten Standard auszuräumen. In SQL-92 kann man beispielsweise das obige Problem lösen, indem die Anfrage wie folgt gestellt wird: SELECT SUM (Gehalt) / COUNT(Gehalt) FROM Mitarbeiter Die Semantik der COUNT(Gehalt)-Funktion ist, dass die Anzahl der Zeilen der Tabelle ermittelt wird, die in der Gehaltsspalte einen Wert ungleich der Nullmarke aufweisen. Es verbleibt aber das Problem, dass in kommerziellen SQL-Varianten der SQL-92-Standard noch nicht umgesetzt wurde und es deshalb systemabhängig ist, ob Probleme dieser Art bereits beseitigt wurden.
7.9 Kritische Würdigung von SQL-92
447
Zu viele Variationsmöglichkeiten Eine weitere Schwäche von SQL ist, dass sich dieselben Sachverhalte durch zu viele Alternativen ausdrücken lassen. Dies wurde in diesem Kapitel bereits in hinlänglich vielen Beispielen durch die Angabe von Alternativen dokumentiert. Wie wir bereits gesehen haben, sind einige der vorgestellten Prädikate überflüssig sind. Bei der Entwicklung von SQL Anfang der 70er Jahre hatte sich in der IBM-Entwicklungsgruppe eine Strömung durchgesetzt, die die Meinung vertrat, dass die alternative Auswahl mehrerer Prädikate benutzerfreundlicher ist als das Anbieten nur eines Prädikates. Diese Ansicht ist sicherlich nicht unumstritten, da alternative Möglichkeiten beim Benutzer immer die Frage aufwerfen, ob sie wirklich vollständig äquivalent sind oder ob es gewisse Situationen geben kann, in denen doch semantische Unterschiede bestehen. Und dann fragt man sich häufiger, ob für die gegebene Fragestellung die richtige Alternative gewählt wurde. Obwohl man heute überwiegend der Meinung ist, dass einzelne Prädikate überflüssig sind, lässt sich dieser Fehler nicht mehr beheben. Um Altinvestitionen nicht zu gefährden, ist es notwendig, dass neue Standards zu den alten kompatibel sind. Nur in wohl begründeten Ausnahmefällen darf von einer solchen Regel abgewichen werden. Bisher war man sicherlich zu Recht der Meinung, dass ein solcher Ausnahmefall nicht gegeben sein kann, wenn es nur um die Entfernung überflüssiger Prädikate geht. Alternative Formulierungen bringen aber noch einen weiteren Nachteil mit sich. Sie tragen nicht dazu bei, die Formulierungsunabhängigkeit von Anfragen zu gewährleisten. Die Forderung nach benutzerfreundlichen, weil deklarativ formulierbaren Anfragen, wird jedoch unterlaufen, wenn die Deklarativität durch die Forderung aller Forderungen, Performanz, insofern ausgehebelt wird, als dass eine weniger intuitiv gestellte Anfrage effizienter ausgeführt wird als eine sauber formulierte Anfrage. Wenn man sich die vielen Formulierungsalternativen in Beispiel 7.121, Beispiel 7.127 oder Beispiel 7.128 ansieht, wird man (zu Recht) wenig Vertrauen in die Formulierungsunabhängigkeit von SQL setzen. Trotz Standardisierung kein Standard Bereits in der Einführung zu SQL war festgestellt worden, dass sich viele Anbieter von SQLDialekten aus ihrer Sicht in einem Dilemma befinden. Einerseits würden sie natürlich gerne mit einem Standardisierungsetikett werben wollen. Andererseits möchte man aber auch die Kunden an die eigene Firma binden. Da man nicht selbstbewusst genug ist, dies mit guter Qualität und Service tun zu wollen, muss man es mit Spezifika versuchen. Viele SQL-Dialekte sind eine deutliche Obermenge des in seiner Mächtigkeit sehr eingeschränkten Entry-Levels von SQL-92. Nutzt man also die vollen Fähigkeiten eines SQL-Dialektes, ist ein Umstieg auf ein anderes relationales DBMS nicht ohne größere Investitionen und Schwierigkeiten möglich. Hält man sich dagegen an die Minimalversion des Standards, ist die Datenbankprogrammierung sehr aufwändig, da im Durchschnitt aller proprietären Dialekte natürlich viele bequeme Features fehlen. Da hilft es auch wenig, dass so mancher Hersteller versucht, den Standard zum Standard zu definieren, wie es beispielsweise Microsoft mit ODBC (Open Database Connectivity) versucht. Einerseits kann ODBC das Durchschnittsproblem auch nicht aus der Welt räumen, andererseits ist dieser „Standard“ noch mehr „herstellergefärbt“ als der Originalstandard.
448
7.10
7 Die relationale Datenbanksprache SQL
Charakteristika relationaler DBMS
Bereits bei der kritischen Würdigung von SQL mag dem Leser aufgefallen sein, dass selbst bei der Kernmannschaft, die für die Einführung der relationalen Datenbanktechnologie verantwortlich zeichnet, keine übereinstimmende Meinung vorherrscht, welche Eigenschaften denn nun ein DBMS mindestens erfüllen muss, damit es relational genannt werden kann. Im Jahre 1986 hat deshalb der geistige Vater des relationalen Datenbankmodells, Edgar Codd, die Initiative ergriffen und zwölf Regeln definiert, die nach seiner Meinung erfüllt sein müssen. Wie es sich für einen strengen Lehrmeister gehört, sind die Regel so hart gefasst, dass sie bei strenger Auslegung von keinen System vollständig erfüllt werden. Trotzdem stellen sie einen guten Anhaltspunkt für den Grad der „Relationalität“ dar, den ein DBMS bietet. Im Folgenden sollen die wesentlichen Aussagen dieser Regeln kurz vorgestellt werden: 1. Alle Informationen eines relationalen DBMS stellen sich aus der Sicht eines Benutzers in genau derselben Art und Weise dar: als Werte in Tabellen. Im Sinn der Diskussion in Kapitel 7.1 haben wir hier bewusst den Begriff Tabelle gewählt und nicht den Begriff Relation. Die Wahl des Begriffes Information statt Daten soll darauf hinweisen, dass neben den eigentlichen Nutzdaten der DB auch alle Metadaten, wie zum Beispiel die Definition des Typs einer Relation mit Attributnamen und Wertebereich, in Relationen abgelegt und durch die normalen Operationen auf Relationen verwaltet werden. 2. Sofern die entsprechenden Zugriffsrechte vorliegen, kann auf jeden atomaren Wert des relationalen DBS über eine Kombination aus Relationenname, Primärschlüssel und Attributname zugegriffen werden. 3. Nullmarken als Darstellung nicht bekannter Werte bzw. nicht anwendbarer Spalten werden datentypunabhängig in einer systematischen Art und Weise unterstützt. Systematisch bedeutet dabei, dass Nullmarken unabhängig davon, bei welchem Datentyp sie auftreten, gleich behandelt werden. 4. Da auch die Daten, die das konzeptuelle Schema der DB beschreiben, in Tabellen abgelegt werden, kann jeder autorisierte Benutzer auf sie über eine Anfrage in einer relationalen Anfragesprache zugreifen. Es existiert also ein dynamischer Onlinekatalog, der entsprechend den Regeln des relationalen Datenbankmodells aufgebaut und gewartet wird. 5. Für ein relationales DBMS muss mindestens eine Sprache existieren, mit deren Hilfe sich Daten, Sichten, Integritätsbedingungen und Zugriffsrechte definieren, Daten manipulieren und Transaktionsgrenzen festlegen lassen. 6. Bereits in Kapitel 7.5 hatten wir gesehen, dass Sichten abgeleitete Relationen darstellen, die aus den Basisrelationen und anderen Sichten durch Anwendung der relationalen Operatoren gebildet werden. Da der Abbildungsprozess der Tupel der Basisrelationen auf die Tupel der Sicht aus mathematischer Sicht nur surjektiv sein muss, ist diese Richtung der Abbildung zwar eindeutig, der umgekehrte Weg allerdings nicht unbedingt. Daraus folgt, dass die Tupel einer Sicht sich nicht immer eindeutig auf die Tupel der Basisrelationen abbilden lassen. Wie man sich einfach klar machen kann, kann die nicht erfolgte Einbeziehung von mindestens einem Schlüsselkandidaten der jeweiligen Basisrelation bei der Bildung einer Sicht dazu führen, dass die Tupel der Sicht nicht mehr eindeutig auf die Tupel dieser Basisrelationen zurückgeführt werden können. Eine zwangsläufige Voraussetzung für die Erlaubnis, Änderungen auf Tupel der Sicht durchführen zu dürfen, ist aber,
7.10 Charakteristika relationaler DBMS
449
dass sich diese Änderungen eindeutig auf die Tupel der Basisrelationen „rückabbilden“ lassen. Die sechste Regel besagt nun, dass auf allen Datensichten, deren Tupel sich eindeutig wieder auf die Tupel der Basisrelationen abbilden lassen, Änderungen durchführbar sein müssen. Nun ist die Überprüfung, ob Sichten sich eindeutig „rückabbilden“ lassen, sehr schwierig durchzuführen, weshalb in der Praxis im Regelfall ausreichende, aber nicht notwendige Bedingungen zur Überprüfung eingesetzt werden. Dementsprechend wird diese Forderung von vermutlich allen DBMS nicht erfüllt. 7. Einfüge-, Änderungs- und Löschoperationen müssen grundsätzlich mengenorientiert ausgeführt werden können. Damit müssen sich auch Änderungsoperationen auf einer so hohen Ebene bewegen, dass kein Bezug auf die interne Darstellung und Verwaltung von Tupeln notwendig ist. 8. Änderungen auf der internen Ebene dürfen nicht auf die (Schnittstelle zu den) Anwendungen durchschlagen. Die physische Datenunabhängigkeit muss sichergestellt sein. Werden Daten also physisch anders abgelegt oder Zugriffspfade eingeführt bzw. gelöscht, so sind die Anwendungsprogramme von diesen Änderungen nicht betroffen. Diese Regel impliziert auch, dass das DBMS für die Ermittlung einer guten Zugriffsstrategie und damit für eine effiziente Anfragebearbeitung zuständig ist. Im Idealfall sollte das DBMS für semantisch identische Anfragen identische Antwortzeiten garantieren, unabhängig davon, wie die Anfrage formuliert wurde (wenn es mehrere semantisch äquivalente Formulierungsmöglichkeiten gibt). 9. Neben der physischen muss auch die logische Datenunabhängigkeit gewährleistet sein: Änderungen des konzeptuellen Datenbankschemas dürfen so lange keine Auswirkungen auf die Anwendungsprogramme haben, wie diese nicht direkt durch die Änderungen betroffen sind. Diese Eigenschaft garantiert, dass zum Beispiel beim Löschen einer Spalte bestehende Anwendungen unverändert funktionieren müssen, wenn sie dieses Attribut nicht genutzt haben. 10. Die zehnte Regel ist im Prinzip eine Verfeinerung von Teilen der fünften Regel und besagt, dass Integritätsbedingungen sich in der Anfragesprache des relationalen DBMS definieren lassen müssen. Weiterhin müssen Integritätsbedingungen in dem DBS gespeichert und abgeprüft werden. 11. Die elfte Regel bezieht sich auf eine physisch verteilte Datenverwaltung und besagt, dass die Anfragesprache eines relationalen DBMS so ausgelegt sein muss, dass Anfragen identisch formuliert werden können, unabhängig davon, ob die eigentlichen Daten physisch zentral oder verteilt abgelegt sind. Diese Regel ist natürlich trivialerweise für zentrale DBS erfüllt, verlangt aber, dass sich aus der Sicht der Anwendung keine Unterschiede ergeben, wenn mit einem verteilten DBS gearbeitet wird. 12. Wenn ein relationales DBMS neben der geforderten High-level-Anfragesprache auch noch eine so genannte Low-level-Anfragesprache unterstützt, dann muss auch diese Sprache garantieren, dass die im DBS definierten Integritätsbedingungen beachtet werden. Ein Umgehen der auf höherer Ebene spezifizierten Integritätsbedingungen durch Low-levelOperationen muss also ausgeschlossen sein. Zusammengefasst hat Edgar Codd seine Anforderungen an ein relationales DBMS noch einmal in seiner so genannten Regel 0, die besagt, dass jedes relationale DBMS in der Lage sein muss, die Verwaltung und Wartung seiner DB ausschließlich über seine relationalen Fähigkeiten abzuwickeln.
450
7.11
7 Die relationale Datenbanksprache SQL
Einbettung von SQL in Wirtssprachen (Embedded SQL)
Bei der bisherigen Diskussion von SQL mag der Leser den Eindruck gewonnen haben, dass mit SQL ein einfacher Zugriff auf Daten möglich sein kann. Nun sollen Daten aber in der Regel nicht nur gelesen, sondern auch verarbeitet werden. SQL ist eine Anfragesprache und als solche nicht berechnungs- bzw. turingvollständig. Sollen daher komplexe Berechnungen auf den Daten ausgeführt oder die Daten in Anwendungsprogrammen benutzt werden, muss eine Transformation von der datenbankinternen in die programmierspracheninterne Darstellung stattfinden, was einer Abbildung von dem Datenbankmodell auf das Typsystem der Programmiersprache entspricht. Günstiger wäre es noch, wenn man direkt aus der Programmiersprache der Anwendung auf die Daten der DB zugreifen könnte. Dieses ist die Intention beim so genannten Embedded-SQL (eingebettetes SQL), abgekürzt E-SQL. Die grundsätzliche Idee ist dabei, SQL in die Programmiersprache nach Wunsch einzubetten und somit aus der Programmiersprache heraus den vollen Zugang zur DB zu ermöglichen. Daten werden über E-SQL aus der DB in die Anwendung gelesen, dort bearbeitet und manipuliert und gegebenenfalls anschließend wieder über E-SQL in die DB zurückgeschrieben. So elegant diese Möglichkeit zunächst einmal auch aussieht, es müssen doch einige Steine aus dem Weg geräumt werden, um sie praktikabel zu machen. Der wesentlichste Punkt ist, dass man sich schwer tun würde, für jede im Einsatz befindliche Programmiersprache einen neuen Übersetzer und eine neue Entwicklungsumgebung zu schreiben. Besser wäre es sicherlich, wenn man bereits existierende Programmiersprachen einfach erweitern könnte. Dies ist die Idee bei der Vorübersetzung. Ein Vorübersetzer (Precompiler) ist ein Übersetzer, der vor dem eigentlichen Übersetzungsvorgang ein mit E-SQL angereichertes Programm durchsucht und die E-SQL-Statements in Code der zu Grunde liegenden Programmiersprache bzw. in programmiersprachenkompatible Prozeduraufrufe überführt (siehe Abbildung 7.8). Als Ergebnis der Vorübersetzung wird ein modifizierter Sourcecode geliefert, der jetzt vom eigentlichen Übersetzer der Programmiersprache übersetzt werden kann. Schließlich werden in der vom Linker durchgeführten Bindephase die E-SQL-spezifischen Prozeduraufrufe durch Hinzubinden der Prozedurimplementierungen ergänzt, so dass jetzt ein Programm entsteht, das einerseits den Regeln der Programmiersprache entspricht, andererseits aber auch mit dem DBS arbeiten kann. Um die Programmiersprachen- und Datenbankwelt miteinander verheiraten zu können, muss eine leistungsfähige Schnittstelle zwischen beiden Welten geschaffen werden. Dazu gehört auch, dass Fehler in einer Welt nicht gleich zum Absturz der gesamten Anwendung führen. Erreicht wird das über eine flexible und leistungsfähige Behandlung von Fehler- und Ausnahmezuständen (exception handling). Die Ausnahmebehandlung stellt eine genormte Pipeline zwischen beiden Welten zur Verfügung, über die Fehlermeldungen und Ausnahmebehandlungen ausgetauscht werden können. Das schwierigere Problem liegt aber in den unterschiedlichen Modellierungsfähigkeiten der beiden Welten. Ein DBMS stellt ein Datenbankmodell zur Verfügung, das sich so normalerweise nicht in der Programmiersprache wiederfindet (und umgekehrt). Damit muss eine Abbildungsvorschrift zwischen beiden Welten gefunden werden. Diese hängt natürlich sehr von den Modellierungsfähigkeiten der Wirtssprache ab und soll hier deshalb nicht weiter behandelt werden.
7.11 Einbettung von SQL in Wirtssprachen (Embedded SQL) myprog.pc
451
Sourcecode mit E-SQL-Statements
Precompiler des DBMS für die Programmiersprache
myprog.c
modifizierter Sourcecode, SQL-Statements wurden durch Prozeduraufrufe und Code der Programmiersprache ersetzt
Compiler der Programmiersprache myprog.o
übersetzter Maschinencode E-SQL-Bibliothek
Linker / Lader
myprog.exe
ausführbares Programm
Abb. 7.8: Funktionsweise des Vorübersetzers
Daneben tritt aber auch noch das Problem auf, dass Programmiersprache und DBMS auf unterschiedlichen Verarbeitungsmodellen beruhen. Ein relationales DBMS arbeitet mengenorientiert. Das Ergebnis einer Anfrage ist eine Ergebnistabelle, was i. d. R. auf eine Menge von Datensätzen hinausläuft. Eine Programmiersprache arbeitet aber sequenziell nach der One-record-at-a-time-Logik. Zur Lösung dieses Problems werden Cursor eingesetzt (siehe Abbildung 7.9). Unter einem Cursor versteht man im Prinzip einen Datenbehälter, in dem das DBMS das Ergebnis einer ausgewerteten Anfrage quasi hinein schütten kann und aus dem die Programmiersprache die Datensätze über entsprechende Befehle einen nach dem anderen wieder herausholen kann. Der Cursor dient auch dem umgekehrten Zweck, dem Übertragen von (modifizierten) Daten in die DB. Wird ein Cursor als INSENSITIVE deklariert, so werden Änderungen, die von derselben Transaktion auf den Daten der DB ausgeführt werden, die auch zum Anfrageergebnis des Cursors gehören, nicht an die veränderte Situation angepasst. Der Cursor bleibt also während seiner gesamten Lebenszeit inhaltlich stabil. Als Default kann ein Cursor nur sequenziell durchlaufen werden. Sollen auch die anderen Varianten des FETCH-Befehls anwendbar sein, muss das Schlüsselwort SCROLL angegeben werden. Über die ORDER BY-Klausel lassen sich die Datensätze des Cursors ordnen. Schließlich kann noch spezifiziert werden, ob die Daten des Cursors verändert werden dürfen. Über diesen Parameter wird die Sperrsetzung beeinflusst. Kann ein Cursor nur gelesen werden, können schwächere Sperren gesetzt werden, wodurch insgesamt eine höhere Parallelität der Arbeiten auf der DB möglich ist. Die Problematik der unterschiedlichen Modellierungsfähigkeiten und des unterschiedlichen Verarbeitungsmodells wird auch häufig unter dem Begriff impedance mismatch subsumiert.
452
7 Die relationale Datenbanksprache SQL
DECLARE
CURSOR INTENSITIVE
FOR
SCROLL
ORDER
BY INTEGER ASC DESC ,
FOR
READ
ONLY
UPDATE OF
,
Abb. 7.9: Definition eines Cursors
Die wesentlichen auf einem Cursor ausführbaren Befehle lauten OPEN, FETCH und CLOSE. Kurz gesagt wird mit dem OPEN-Befehl der Cursor geöffnet. Ein Zeiger wird auf den ersten Datensatz des Cursors gesetzt. Über den FETCH-Befehl (siehe Syntax 7.55) kann jetzt der Cursor Datensatz für Datensatz durchlaufen werden. Dabei kann der nächste, vorherige, erste, letzte, n-te und von der aktuellen Position aus gesehen n-te Datensatz gelesen werden. Nach dem Ende der Arbeiten auf dem Cursor wird dieser schließlich über den CLOSE-Befehl geschlossen. Syntax 7.55: Lesen von Datensätzen aus einem Cursor FETCH-Klausel ::= FETCH Position FROM CursorName INTO Var1 [,Varn ]∗ Position ::= { NEXT | PRIOR | FIRST | LAST | ABSOLUTE n | RELATIVE n } Dass das Arbeiten mit E-SQL doch ein wenig mehr Übung erwartet als das Arbeiten nur mit dem reinen SQL, kann man Beispiel 7.171 entnehmen. In dem Beispiel werden zwei Cursor angelegt. Der erste Cursor liefert die Haupttabelle, die einmal durchlaufen wird. Der zweite Cursor ist für die Untertabelle zuständig, wobei diese für jeden Datensatz der Haupttabelle einmal vollständig durchlaufen wird.
7.11 Einbettung von SQL in Wirtssprachen (Embedded SQL)
453
Beispiel 7.171: Beispielprogramm in E-SQL # INCLUDE-Teil Deklaration der nur im Anwendungsprogramm verwendeten Variablen EXEC SQL BEGIN DECLARE SECTION; Deklaration der gemeinsam benutzen Variablen EXEC SQL END DECLARE SECTION; MAIN() /* Anfang Hauptprogramm { EXEC SQL WHENEVER SQLERROR GOTO sqlFehler; EXEC SQL CONNECT :userid IDENTIFIED BY :passwort; EXEC SQL DECLARE cursorHaupttabelle CURSOR FOR SELECT ... FROM ... WHERE . . . ; EXEC SQL DECLARE cursorUntertabelle CURSOR FOR SELECT ... FROM ... WHERE . . . ; EXEC SQL WHENEVER NOT FOUND GOTO nichtsGefunden; EXEC SQL OPEN cursorHaupttabelle; nächstesHaupttupel: EXEC SQL WHENEVER NOT FOUND GOTO fertig; EXEC SQL FETCH NEXT FROM cursorHaupttabelle INTO :var1, :var2, . . .; Verarbeitung des gelesenen Tupels aus der Haupttabelle EXEC SQL WHENEVER NOT FOUND GOTO clsSubcursor; EXEC SQL OPEN cursorUntertabelle; WHILE (1==1) /* Endlos-Schleife { EXEC SQL FETCH NEXT FROM cursorUntertabelle INTO :varx, :vary, . . .; Verarbeitung des gelesenen Tupels aus der Untertabelle }; clsSubcursor: EXEC SQL CLOSE cursorUntertabelle; GOTO nächstesHaupttupel; nichtsGefunden: ... fertig: EXEC SQL CLOSE cursorHaupttabelle; EXEC SQL COMMIT WORK RELEASE; EXIT(0); sqlFehler: /* kein CONNECT möglich ... } Seit der Verabschiedung des SQL-92-Standards ist auch E-SQL standardisiert. Da dies jedoch verhältnismäßig spät geschah, gibt es bei den meisten SQL-Dialekten noch kleinere und größere (syntaktische) Unterschiede zum Standard.
454
7 Die relationale Datenbanksprache SQL
Dynamisches SQL Bei der bisherigen Diskussion war immer unterstellt worden, dass die SQL-Anweisungen fest vorgegeben sind, was heißt, dass sie zwar Variablen enthalten dürfen, denen dann zur Laufzeit feste Werte zugewiesen werden, ansonsten müssen die Anfragen aber bereits sauber ausformuliert sein. Dies ist natürlich die Grundvoraussetzung dafür, dass eine SQL-Anweisung mit Hilfe des (Vor-)Übersetzers bereits übersetzt werden kann. Dieses statische Konzept der Einbindung, auch statische Einbettung genannt, erweist sich in der Praxis gelegentlich als zu inflexibel. Gewünscht wird stattdessen, dass man auch beliebige SQL-Anfragen quasi dynamisch einbinden kann. Dies führt zum Konzept des dynamischen SQL (dynamic SQL). Das Hauptproblem dieser Variante ist die Frage, wie ein noch nicht ausprogrammiertes Programmkonstrukt in ein bereits übersetztes Programm eingebunden werden kann. Die Antwort lautet, dass man eine Zeichenkettenvariable definiert, der dann zur Laufzeit die SQLAnweisung als Wert zugewiesen wird. Aus Sicht des übersetzten Programms handelt es sich also nur um eine Zeichenkette, die jetzt natürlich vom DBMS als SQL-Block zu interpretieren ist. Dies geschieht, indem man dem DBMS über den PREPARE-Befehl die Zeichenkette zuschickt. Das DBMS übersetzt diese Anfrage und erzeugt einen optimierten Ausführungsplan143, der dann an das Anwendungsprogramm zurückgeliefert wird. Das Anwendungsprogramm kann jetzt über den EXECUTE-Befehl die Abarbeitung dieses Ausführungsplanes veranlassen. Naturgemäß ist der Austausch der Daten zwischen Anwendungsprogramm und DBMS etwas aufwändiger, da die Struktur der zu übermittelnden Daten wegen der zur Übersetzungszeit des Anwendungsprogrammes noch nicht bekannten SQL-Anweisung nicht bekannt war. Deshalb muss das Laufzeitsystem des Anwendungsprogrammes die Datenstrukturbeschreibung des vom DBMS gelieferten Ausführungsplanes interpretieren und dynamisch Speicherplatz für die Ergebnisdatensätze anfordern.
7.12
Programmgeneratoren
Ein DBMS stellt in einer modernen integrierten DV-Landschaft lediglich einen Baustein zur Entwicklung komplexer Anwendungen dar. Dementsprechend wird es sich erst dann kommerziell durchsetzen können, wenn es eine ganze Palette von Werkzeugen für alle möglichen Aufgaben bieten kann. Dazu gehören beispielsweise Werkzeuge, die die Migration von anderen, konzeptuell veralteten DBMS (Hierarchische oder Netzwerk-DBMS) oder von anderer Technologie (Dateisystemen) ermöglichen144. Dazu gehören aber insbesondere auch Werkzeuge, die eine benutzergerechte Eingabe, Aufbereitung und Präsentation der in der DB abgelegten Daten ermöglichen. Zur letzten Klasse gehören insbesondere auch die Programmgeneratoren, die in den 80er Jahren als zukunftsweisende Technologie zur Anwendungsentwicklung den Markt erobern wollten. Programmgeneratoren stellen einen Grenzfall zwischen Entwicklungs- und Endbenutzerwerkzeugen dar. Mit ihrer Hilfe können einfache Anwendungsprogramme ohne größeren Programmieraufwand erstellt werden. In der Regel stellt ein Programmgenerator neben einem SQL-Dialekt imperative Sprachkonstrukte, über 143 Ausführungspläne
werden im nächsten Kapitel (Kapitel 7.13) genauer vorgestellt. Begriff „konzeptuell veraltet“ wurde hier bewusst gewählt, da die Realität immer noch so aussieht, dass aufgrund der hervorragenden Performanz von „Altsystemen“ in manchen Anwendungsbereichen diese dort immer noch den State-of-the-Art darstellen. 144 Der
7.12 Programmgeneratoren
455
Ereignisse steuerbare Benutzerschnittstellen und Mechanismen zur Regeldefinition zur Verfügung. Damit können mit Triggern versehene Menüs und Masken bzw. Formulare interaktiv am Bildschirm zusammengebaut werden, die sich auch auf in der imperativen Programmiersprache geschriebene Aktionen abstützen können. Inzwischen ist der Euphorie allerdings eine gewisse Ernüchterung gefolgt, insbesondere weil viele Programmgeneratoren nicht leistungsfähig genug sind und zudem darunter leiden, dass ihnen kein einheitliches Sprachkonzept bzw. keine durchgängige Semantik zu Grunde liegt. Es werden sehr oft mengen- (SQL) und zeilenorientierte (konventionelle Sprachkonstrukte) sowie aktive und passive Konstrukte unterstützt, ohne dass eine saubere Integration stattgefunden hätte. Einfache Anwendungsprogramme können schnell und effizient zusammengebaut werden. Falls die Aufgabenstellung jedoch einen gewissen Komplexitätsgrad überschreitet, wird der Code schnell komplex und schwer durchschaubar. Die eigentliche Stärke dieser Werkzeuge ist deshalb eher deren Interaktivität. Moderne, grafikorientierte Werkzeuge zur Anwendungsentwicklung firmieren auch häufig unter dem Begriff Programmiersprachen der 4ten Generation (4GL – Fourth Generation Languages) oder einfach 4GL-Werkzeuge. Entsprechend ihrer Funktionalität kann man bei den 4GL-Werkzeugen zwei wesentliche Gruppen ausmachen, die maskenorientierten Sprachen zur Datenmanipulation und die Berichtsgeneratoren (report writer). Maskenorientierte Datenmanipulationssprache Mit Hilfe der maskenorientierten DML können die Daten der DB erfasst und gewartet werden. Im Gegensatz zur „Wie-orientierten“ Programmierung konventioneller Programmiersprachen wird die Anwendung einfach am Bildschirm entworfen und editiert. Im einfachsten Fall gibt es für jede Tabelle oder Benutzersicht eine automatisch erzeugte Standardmaske, die für jede Spalte den Spaltennamen und ein Ein-/Ausgabefeld für den Spaltenwert enthält. Damit sind schon Dateneingaben und -änderungen und einfache Abfragen möglich. Diese Standardmasken können jetzt beliebig verändert und erweitert werden. Das kann interaktiv über einen so genannten Maskeneditor durchgeführt werden – dies wird z. B. häufig bei PC-basierten relationalen DBMS unter Windows angeboten – oder über eine Maskendefinitionssprache in Form einer ASCII-Datei, die für die Standardmaske generiert wird und beliebig abgeändert werden kann. Letzteres wird häufig bei Unix- und großrechnerbasierten relationalen DBMS (zusätzlich) angeboten. Ein Maskeneditor bietet dem Anwendungsentwickler die typischen Elemente einer fensterorientierten Benutzungsoberfläche, wie Menüs, Buttons und Eingabefelder, und andere gestalterische Elemente wie Linien und Hintergrundbilder. Ist eine Maske fertig gestaltet, können den Feldern, Buttons oder auch ganzen Masken Programmsegmente, gelegentlich auch Skripte genannt, zugeordnet werden. Mit Hilfe solcher Skripte können Integritätsbedingungen wie die folgenden festgelegt werden: • „Eingabezwang“ für bestimmte Spalten, • Wertebereichseinschränkungen, • Abhängigkeiten zwischen Spalten auf Zeilenebene (Datensatzebene), • Überprüfung, ob die eingegebenen Schlüssel zulässig sind (referenzielle Integrität), • automatische Verknüpfung mit weiteren Tabellen.
456
7 Die relationale Datenbanksprache SQL
Skripte werden i. d. R. ereignisorientiert ausgelöst, beispielsweise durch Anklicken eines Buttons oder Verlassen eines Eingabefeldes oder der gesamten Maske. In der Regel besteht also eine maskenorientierte Datenmanipulationssprache aus zwei Teilen, dem eigentlichen Maskeneditor bzw. -generator und der ereignisorientierten Regelsprache, die die Definition der Skripte erlaubt. Grafische Schnittstellen können natürlich nicht nur für die Eingabe, sondern auch für die Ausgabe definiert werden. So können Ausgabedaten beispielsweise grafisch aufbereitet und komprimiert in Balken-, Stab- oder Kreisdiagrammen dargestellt werden. Der Berichtsgenerator (Report Generator) Eine Druckausgabe in Listenform wird häufig Bericht genannt. Beispiele für Berichte sind Kalkulationen, Listen mit Monatsumsatz pro Artikel oder Gehaltsaufstellungen pro Gehaltsgruppe. Ein Berichtsgenerator ermöglicht es, Vorlagen (Masken) für solche Berichte zu erstellen. Damit kann das Ergebnis einer Datenbankanfrage in übersichtlicher Form präsentiert werden. Oft ist es möglich, einen Bericht in einen Berichtskopf, der z. B. den Titel des Berichtes enthält, einen variablen Mittelteil, der zeilenweise einzelne Positionen und Zwischensummen des Berichts ausgibt, und einen Fußbereich, z. B. mit einer Gesamtsumme, zu unterteilen. Als Kontrollstruktur steht i. d. R. die Fallunterscheidung zur Verfügung sowie die Möglichkeit, bestimmte Ausgaben bei einem Gruppenwechsel, beispielsweise der Beendigung eines Zeitintervalls – wie Woche, Monat, Quartal, Jahr – oder der Änderung eines Sortierfeldes, auszugeben, z. B. Zwischensummen, Zwischenüberschriften u. ä. Weitere häufig unterstützte Leistungen eines Berichtsgenerators sind: • Formatierung von Gesamt-, Seiten-, Spaltenüberschriften und Werten • Bildung von Datengruppen mit Zwischenüberschriften und Zwischensummen Im Vergleich zu prozeduralen Sprachen unterstützten Berichtsgeneratoren oft kein explizites Schleifenkonstrukt – wenn man einmal davon absieht, dass eine Anfrage implizit eine Schleife repräsentiert – und kein Prozedurkonzept. Beispiele für Maskengeneratoren sind Oracle∗ Forms, INGRES Windows4GL, Gupta SQLWindows, NATURAL, TOTAL oder Informix 4GL. Beispiele für Berichtsgeneratoren sind MITI SQR oder der Oracle∗ Reportwriter. In einigen Werkzeugen sind Masken- und Reportgeneratoren bereits integriert, z. B. bei Oracle PowerObjects oder beim PowerBuilder.
7.13
Anfragebearbeitung und -optimierung
Anfragesprachen moderner DBMS sind deskriptiv. Dies schließt insbesondere ein, dass sie frei von Aspekten der logischen und physischen Repräsentation145 (der Daten) des konzeptuellen Schemas sind. Im Idealfall sollten sie auch noch formulierungsunabhängig sein, d. h., sie sollten insofern nicht zwischen „dummen“ und „intelligent“ gestellten Anfragen unterscheiden, als dass Anfragen in etwa immer gleich effizient ausgeführt werden sollten, unabhängig davon, wie geschickt die Anfrage formuliert wurde. Leider kann diese Eigenschaft vor allem 145 Ein
DBMS garantiert ja logische und physische Datenunabhängigkeit.
7.13 Anfragebearbeitung und -optimierung
457
aus Gründen der Komplexität (NP-vollständiges Problem) und des fehlenden semantischen „Verständnisses“ eines Rechners nicht garantiert werden. Damit nun eine auf einer relativ abstrakten Ebene formulierte Anfrage ausgeführt werden kann, muss sie von ihrer hohen logischen Ebene auf eine physische oder implementierungsnahe Ebene überführt werden. Es müssen also Umformungen und Ersetzungen vorgenommen werden. Eine beliebte Abbildungsplattform ist die relationale Algebra. Sie basiert auf einer soliden mathematischen Theorie, so dass die Korrektheit von Umformungen und Ersetzungen formal nachgewiesen werden kann. Auch gibt es effiziente Implementierungen für die relationalen Operatoren.
7.13.1
Anfragebearbeitung
Die grundsätzlichen Phasen der Anfragebearbeitung kann man Abbildung 7.10 entnehmen. Eine Anfrage wird zunächst auf syntaktische und semantische Korrektheit überprüft (Abbildung 7.10, 1 ). Neben der korrekten Syntax wird in dieser Phase auch festgestellt, ob die angesprochenen Tabellen und Spalten existieren und ob die Anfrage eindeutig formuliert ist. Bezieht sich die Anfrage auf eine Sicht, wirdderen durch deren Definition ersetzt, so dass die Anfrage sich ausschließlich auf Basistabellen bezieht. Am Schluss wird die Anfrage auf einen Ausdruck der relationalen Algebra abgebildet (Abbildung 7.10, 2 ). Mit dem Übergang von der Repräsentation einer Anfrage auf der Ebene der Anfragesprache zu einer Repräsentation auf der Ebene der relationalen Algebra findet auch der Übergang von der Was- (Was soll ausgegeben werden?) zur Wie-Beschreibung (Wie soll das Ergebnis ermittelt werden?) statt. Ein Ausdruck der relationalen Algebra kann also als eine exakte Vorschrift angesehen werden, wie die Ausgangstabelle in die Ergebnistabelle überführt werden soll. In der Optimierungsphase wird der relationale Ausdruck so umgeformt, dass eine möglichst optimale Ausführungsstrategie entsteht. Die Optimierung lässt sich dabei in zwei Phasen unterteilen, die logische bzw. konzeptuelle Optimierung und die physische bzw. interne Optimierung (Abbildung 7.10, 3 ). Die logische Optimierung stützt sich im Wesentlichen auf die Gesetze und Regeln der relationalen Algebra. Deshalb wird sie auch algebraische Optimierung genannt. Basierend auf Regeln und Heuristiken wird der relationale Ausdruck so lange umgeformt, bis eine aus der Sicht des Optimierers effiziente Ausführungsstrategie gefunden ist. In der Phase der physischen Optimierung kommen jetzt die Zugriffspfade, Indexe und die verschiedenen Implementierungen der relationalen Operatoren ins Spiel. Gerade für Verbundbedingungen gibt es diverse Implementierungskonzepte, die abhängig von der gegebenen Situation – Ist ein Index oder Zugriffspfad vorhanden? Ist die Verbundbedingung selektiv? – mehr oder weniger effizient sein können. Auch hier gilt: Je mehr Informationen über das Aussehen des konkreten Datenbestandes bekannt sind (Heuristiken), desto genauer kann die Optimierung arbeiten. Insgesamt arbeiten heutige Optimierer normalerweise schon einmal so intelligent, dass das Ergebnis der Optimierung nicht langsamer abgearbeitet wird als das „Original“. Das war durchaus nicht immer so, da in den Anfängen der Optimierung auch so mancher Fehlweg gegangen wurde. Da man zwischenzeitlich hochgradig effiziente Implementierungskonzepte für die relationalen Operatoren kennt und einige grundsätzliche Umstrukturierungsregeln
458
7 Die relationale Datenbanksprache SQL
deskriptive SQL-Anfrage
➀
Syntaktische und semantische Analyse (Scanner, Parser) Sichtenauflösung
➁
algebraischer Ausdruck bzw. Operatorbaum
➂
Anfrageoptimierung
➃
Ausführungsplan
➄
Codegenerator (Interpretations- und Übersetzungsansatz)
➅
ausführbarer Code
Laufzeitsystem (evtl. Interpretation)
Übersetzung
logische (algebraische) Optimierung, Auswahl konkreter Implementierungen der Operatoren, Enbeziehung von Sekundärindexen und Zugriffspfaden
direkte Ausführung, spätere Ausführung (Speicherung)
Ausführung
Anfrageergebnis
Abb. 7.10: Abarbeitung einer Anfrage
zu teilweise dramatischen Performanzverbesserungen führen können, springen sogar i. d. R. erhebliche Performanzgewinne heraus. Systemintern wird ein algebraischer Ausdruck gerne durch einen Operatorbaum repräsentiert. Er ermöglicht eine übersichtliche und eindeutige Darstellung eines algebraischen Ausdruckes. Damit legt er insbesondere auch eine eindeutige Reihenfolge fest, in der der algebraische Ausdruck abzuarbeiten ist (siehe Definition 7.9). Definition 7.9: Operatorbaum Ein Operatorbaum ist ein Baum, dessen • innere Knoten relationale Operatoren darstellen, wobei unäre Operatoren einen Nachfolger haben und binäre zwei, und dessen • Blätter Datenmengen bzw. Tabellen repräsentieren
7.13 Anfragebearbeitung und -optimierung
459
Die Abarbeitung eines Operatorbaumes erfolgt von unten nach oben und von links nach rechts. Beispiel 7.172: Operatorbaum „Gib die Namen aller Mitarbeiter mit einem Gehalt von über 5.000,– C aus, die auch Kunden der Firma sind und einen Rabatt von mehr als 15 Prozent bekommen.“ Eine mögliche Formulierung dieser Anfrage in der Relationenalgebra ist die Folgende: πmitarbeiterName,mitarbeiterVornameσmitarbeiterNr=kundenNr (σgehalt>5000 (σrabatt>15 (Mitarbeiter × Kunden))) Übersetzt man diese Anfrage direkt in einen Operatorbaum, so würde er dem der Abbildung 7.11 entsprechen. (mitarbeiterName, mitarbeiterVorname)
(mitarbeiterName, mitarbeiterVorname)
(mitarbeiterNr = kundenNr)
Hashverbund mitarbeiterNr = kundenNr
(gehalt > 5000) (rabatt > 15)
AuswahlÜberIndex
SequenziellerDurchlauf
gehalt > 5.000
rabatt > 15
Mitarbeiter
Kunden
Mitarbeiter Abb. 7.11: Operatorbaum
Kunden
Abb. 7.12: Ausführungsplan
Das Ergebnis der Optimierung ist ein so genannter Ausführungsplan (Abbildung 7.10, 4 ). Er stellt im Wesentlichen ein um Daten der physischen Datenorganisation, des Datenzugriffes und der Operatorauswahl erweiterten Operatorbaum (siehe Abbildung 7.12) dar. Der Ausführungsplan gibt Auskunft darüber, ob bei der Berechnung der Anfrage Zugriffspfade berücksichtigt werden können (in Abbildung 7.12 durch AuswahlÜberIndex angedeutet) oder ob zur Auswertung der Selektionsbedingung ein sequenzieller Durchlauf durch alle Datensätze notwendig ist (in Abbildung 7.12 durch SequenziellerDurchlauf angedeutet). Weiterhin hat die Berechnung der Alternativen in Abbildung 7.12 ergeben, dass die Verbundbedingung am effizientesten durch einen Hashverbund umgesetzt werden kann146. Der Ausführungsplan ist nun Basis für die eigentliche Codeerzeugung durch den Codegene5 ). Das Ergebnis der Codegenerierung ist im Fall des Übersetzungsrator (Abbildung 7.10, ansatzes ein direkt ausführbarer Code, der schon sehr weitgehend optimiert wurde. Beim 146 Die beiden bekanntesten Klassen von Implementierungskonzepten für den Verbund sind der Nested-LoopVerbund mit und ohne Index bzw. Hashzugriff und der Sort-Merge-Verbund. Da diese Thematik nicht Gegenstand dieses Buches ist, soll sie hier auch nicht vertieft werden.
460
7 Die relationale Datenbanksprache SQL
Interpretationsansatz hingegen wird eine Art Zwischencode erzeugt, der dann zur Laufzeit interpretiert wird (Abbildung 7.10, 6 ). Bei diesem Ansatz werden substanzielle Bestandteile der Optimierung nicht ausgeführt oder auf die Laufzeitphase verschoben, wodurch die Optimierung insgesamt auf einem sehr bescheidenen Niveau abläuft. Interpretiert wird insbesondere bei Onlineanfragen, während häufig sich wiederholende und daher (parametrisiert) abgespeicherte Anfragen in einen effizient abarbeitbaren (statischen) Code überführt werden. Dadurch wird die wiederholte (unnötige) Übersetzung und Optimierung der Anfrage vermieden. Parametrisierte Anfragen sind Anfragen, bei denen in der Selektionsbedingung Parameter stehen, die dann bei Aufruf der Anfrage durch konkrete Werte zu ersetzen sind. Bei der parametrisierten Variante von Beispiel 7.172 würde beispielsweise statt des konkreten Wertes 5.000,– für Gehalt bzw. 15 für Rabatt jeweils ein Parameter stehen, der dann bei jedem Aufruf der Anfrage mit dem gewünschten Wert zu belegen ist. Solche „statischen“ Anfragen haben allerdings einen Nachteil. In ihrer Optimierung wird der zum Zeitpunkt der Optimierung gültige Zustand der DB eingepflanzt. Dies betrifft Schemainformationen ebenso wie Zugriffspfade oder statistische Informationen. Insbesondere Letztere werden sich im Laufe der Zeit ändern, so dass ehemals effizient ausgeführte Anfragen immer mehr zu Zeitfressern verkommen können. Bei Schemaänderungen, wie beispielsweise dem Entfernen eines Zugriffspfades, könnte es sogar passieren, dass eine Anfrage nicht mehr lauffähig ist. Dieses Beispiel dokumentiert, dass es bei übersetzten Anfragen notwendig ist, die Abhängigkeiten von relevanten Informationen (Schema, Zugriffspfade) festzuhalten und zu überwachen, so dass, ähnlich zur Idee der referenziellen Integrität, erkannt werden kann, welche Auswirkungen Änderungen auf Anfragen haben können. Gegebenenfalls müssen Anfragen neu übersetzt werden. Der letzte Schritt der Anfrageverarbeitung besteht schließlich in der Übertragung des Ergebnisses in den Datenbankpuffer, so dass die Anwendung auf sie zugreifen kann.
7.13.2
Anfrageoptimierung
Unter Anfrageoptimierung versteht man eine systeminterne Äquivalenzumformung einer Anfrage mit dem Ziel, eine zumindest annähernd laufzeitoptimale Variante zu entwickeln. Da im Allgemeinfall die optimale Ausführungsstrategie wegen der NP-Vollständigkeit dieser Fragestellung nicht gefunden werden kann, muss die Anfrageoptimierung versuchen, aus dem vollständigen Lösungsraum eine Variante auszuwählen, die möglichst nahe an den Idealfall herankommt147. Gute heutige Anfrageoptimierer arbeiten trotz vieler Fortschritte immer noch auf einer optimierten Variante des Trial-and-Error-Verfahrens. Aus der Menge der möglichen Lösungsalternativen werden schrittweise erfolgversprechende ausgesucht und, falls die physische Optimierung Anwendung findet, auf der Basis eines Kostenmodells durchgerechnet. Diese Art von Vorauswahl liefert oft schon sehr gute Ergebnisse. Kostenmodelle stützen sich in der Regel auf statische und dynamische Informationen über die aktuelle DB ab. Zu den statischen Informationen gehören vor allem die Schemainformationen 147 Natürlich ist klar, dass es im Allgemeinfall nicht möglich ist, zu beurteilen, wie weit man vom Idealfall entfernt ist, wenn man diesen nicht kennt. Deshalb müssen hier pragmatischere Kriterien herhalten wie z. B. um wieviel besser die Lösung im Vergleich zum Original ist.
7.13 Anfragebearbeitung und -optimierung
461
und Informationen über den mit den einzelnen Implementierungskonzepten von relationalen Operatoren verbundenen Kosten. Zu den dynamischen Informationen gehören Statistiken über den aktuellen Zustand der DB wie die Größe von Relationen, die Verteilung von Spaltenwerten (Selektivität) oder Erfahrungswerte über die Anwendung konkreter Umformungen bzw. Umformungsregeln. Logische Optimierung Die logische Optimierung setzt sich normalerweise aus den folgenden (logischen) Phasen zusammen: • Erkennung und gegebenenfalls Zusammenfassung redundanter Teilausdrücke • Erkennung und Entfernung überflüssiger Teilausdrücke • Bestimmung einer laufzeitoptimalen Operationsfolge Immer dann, wenn dieselben oder sich umfassende Mengen berechnet werden, stellt sich die Frage, ob bei späteren Berechnungen die Ergebnisse der früheren berücksichtigt werden können. Im Normalfall ist dies sicherlich sinnvoll. Allerdings mag es beispielsweise aufgrund der Tatsache, dass Ergebnisse „zwischengelagert“ werden müssen, auch schon einmal vorkommen, dass eine Neuberechnung kostengünstiger ist. Wurde bereits einmal eine Obermenge eines Ausdruckes berechnet, ist die Frage, ob diese als Ausgangspunkt genommen werden sollte, auch jeweils individuell zu entscheiden. Es kann durchaus sein, dass der sequenzielle Durchlauf durch die Obermenge teurer ist als eine Neuberechnung des Ausdruckes, insbesondere dann, wenn bei der Neuberechnung Zugriffspfade ausgenutzt werden können. Bei der Bestimmung der laufzeitoptimalen Operationsfolge stützt man sich auf das mathematische Grundgerüst der relationalen Algebra ab. Man versucht, durch Ausnutzung von Regeln und mathematischen Gesetzen einen gegebenen Ausdruck in einen effizienter ausführbaren äquivalenten Ausdruck zu überführen. Tabelle 7.25 gibt einen Überblick über wesentliche Äquivalenzen in der relationalen Algebra, so wie sie von vielen Optimierern berücksichtigt werden. Als Faustregel gilt, dass volumenreduzierende Operationen, wie die Selektion oder Projektion möglichst früh zum Einsatz kommen sollen148 . Teure Operationen wie vor allem Verbund und Kartesisches Produkt sollten möglichst spät durchgeführt werden. Dieser Empfehlung liegt die Annahme zu Grunde, dass zu einem späteren Zeitpunkt die dann gültige Zwischenergebnistabelle schon erheblich kleiner geworden ist, weshalb die Operationen dann nicht mehr so zeitfressend sind. Bei den Äquivalenzumformungen müssen Nebenbedingungen natürlich beachtet werden. Wird beispielsweise eine Projektion tiefer in den Operatorbaum verlagert, so muss aufgepasst werden, dass später noch benötigte Spalten nicht eliminiert werden. In der optimierten Variante der Anfrage von Beispiel 7.172 wurde die Projektion nach unten gezogen. Da jedoch zur 148 Es sei hier nur darauf hingewiesen, dass die logische Optimierung nicht unabhängig von der physischen durchgeführt werden kann. So bringt es sicherlich nicht unbedingt etwas, wenn man eine volumenreduzierende Selektion als Erstes ausführt, sich dadurch aber den Einsatz eines Zugriffspfades in einer späteren Berechnung verbaut. Auch hieran sieht man wieder die inhärente Komplexität der Optimierung, die in dieser Diskussion nur gestreift werden kann.
462 Nr
7 Die relationale Datenbanksprache SQL Regel
Nr
Regel
Rel1 × Rel2 ∼ = Rel2 × Rel1 ∼ Rel1 ∪ Rel2 = Rel2 ∪ Rel1
13 πA (Rel1 ∪ Rel2 ) ∼ = (πA Rel1 ) ∪ (πA Rel2 )
Rel1 ∩ Rel2 ∼ = Rel2 ∩ Rel1 (Rel1 × Rel2 ) × Rel3 ∼ = Rel1 × (Rel2 × Rel3 )
15 Rel1 Rel1 ∼ = Rel1 16 Rel1 θ Rel2 ∼ = σθ (Rel1 × Rel2 )
6
(Rel1 ∪ Rel2 ) ∪ Rel3 ∼ = Rel1 ∪ (Rel2 ∪ Rel3 ) (Rel1 ∩ Rel2 ) ∩ Rel3 ∼ = Rel1 ∩ (Rel2 ∩ Rel3 )
17 Rel1 F Rel2 ∼ = Rel2 F Rel1 ∼ 18 Rel1 ∪ Rel1 = Rel1
7
σF (Rel1 ∪ Rel2 ) ∼ = (σF Rel1 ) ∪ (σF Rel2 )
19 Rel1 − Rel1 ∼ =∅
σF (Rel1 ∩ Rel2 ) ∼ = (σF Rel1 ) ∩ (σF Rel2 ) σF (Rel1 − Rel2 ) ∼ = (σF Rel1 ) − (σF Rel2 )
20 Rel1 (σF Rel1 ) ∼ = σF Rel1
1 2 3 4 5
8
14 σF 1 (σF 2 Rel1 ) ∼ = σF 2 (σF 1 Rel1 )
10 (σF 1 Rel1 ) ∪ (σF 2 Rel1 ) ∼ = σ(F 1∨F 2) Rel1
21 Rel1 ∪ σF Rel1 ∼ = Rel1 ∼ σ¬F Rel1 22 Rel1 − σF Rel1 =
11 (σF 1 Rel1 ) − (σF 2 Rel1 ) ∼ = σ(F 1∧¬F 2) Rel1
23 ¬(F1 ∧ F2 ) ∼ = ¬F1 ∧ ¬F2
12 (σF 1 Rel1 ) (σF 2 Rel1 ) ∼ = σ(F 1∧F 2) Rel1
24 ¬(F1 ∨ F 2) ∼ = ¬F1 ∨ ¬F2
9
Nr 1 2
Regel σF (πA Rel1 ) ∼ = πA (σF Rel1 ) (Rel1 F 1 Rel2 ) F 2
Rel3 ∼ =
Rel1 F 1 (Rel2 F 2 Rel3 )
Nebenbedingung ← attr(F ) ⊆ A → attr(F2 ) ⊆ (attr(Rel2 ) ∪ attr(Rel3 )) ← attr(F1 ) ⊆ (attr(Rel1 ) ∪ attr(Rel2 ))
3
πA1 Rel1 ∼ = πA1 πA2 Rel1
A1 ⊆ A2 ⊆ attr(Rel1 )
4
σF Rel1 ∼ = σF 1 σF 2 Rel1
F = F1 ∧ F2
5
σF (Rel1 × Rel2 ) ∼ = (σF 1 Rel1 ) × (σF 2 Rel2 ) → ((F = F1 ∧ F2 ) ∧ attr(F1 ) ⊆ attr(Rel1 )) ∧ (attr(F2 ) ⊆ attr(Rel2 )) ← F = F1 ∧ F2
6
7
8
σF (Rel1 F 3 Rel2 ) ∼ =
→ ((F = F1 ∧ F2 ) ∧ attr(F1 ) ⊆ attr(Rel1 )) ∧ (attr(F2 ) ⊆ attr(Rel2 ))
(σF 1 Rel1 ) F 3 (σF 2 Rel2 )
← F = F1 ∧ F2
πA (Rel1 × Rel2 ) ∼ =
→ (A1 = A ∩ attr(Rel1 )) ∧ (A2 = A ∩ attr(Rel2 ))
(πA1 Rel1 ) × (πA2 Rel2 )
← A = A1 ∪ A2
πA (Rel1 F Rel2 ) ∼ =
→ (attr(F ) ⊆ A) ∧ (A1 = A − attr(Rel2 )) ∧ (A2 = A − attr(Rel1 ))
(πA1 Rel1 ) F (πA2 Rel2 )
← A = A1 ∪ A2
F, F1 , F2 : Verbundbedingungen Tabelle 7.25: Äquivalente Ausdrücke der Relationenalgebra
7.13 Anfragebearbeitung und -optimierung
463
π (mitarbeiterName, mitarbeiterVorname) (mitarbeiterNr = kundenNr)
π (mitarbeiterNr,mitarbeiterName,mitarbeiterVorname)
π (kundenNr)
σ gehalt > 5000
σ rabatt > 15
Mitarbeiter
Kunden
Abb. 7.13: Optimierte Anfrage von Beispiel 7.172
Ausführung der Verbundoperation noch mitarbeiterNr und kundenNr gebraucht werden, müssen sie erhalten bleiben (siehe Abbildung 7.13). Eine weitere Optimierung in Abbildung 7.13 ist das Zusammenfassung des Kartesischen Produktes und der die Tabellen Mitarbeiter und Kunden verbindenden Selektionsbedingung (mitarbeiterNr = kundenNr). Damit wird das sehr teure Kartesische Produkt auf eine zwar immer noch sehr teure, aber immerhin doch erheblich schneller durchführbare Operation zurückgeführt. In der anschließenden physischen Optimierung kann jetzt noch eine günstige Implementierung des Verbundes ausgewählt werden, beispielsweise eine, die indizierte Spalten berücksichtigt. Physische Optimierung Ein Operator der relationalen Algebra kann auf eine Anzahl von unterschiedlichen Implementierungskonzepten abgebildet werden. Jedes dieser Konzepte hat seine Vor- und Nachteile, so dass die Auswahl der richtigen Implementierung von der konkreten Situation abhängt. Diese Aufgabe gehört ebenso zur physischen Optimierung wie die Einbindung von Zugriffspfaden oder anderen zugriffsbeschleunigenden Maßnahmen. Welche Aufgaben hier angepackt werden müssen, soll exemplarisch anhand der Zugriffspfadauswahl diskutiert werden. Bei der Auswahl spielt eine wesentliche Rolle, ob ein Zugriffspfad genau passt, also explizit für die Spalte(n) existiert, auf der (denen) die Selektion ausgeführt werden soll. Ist dies der Fall, macht es fast immer Sinn, den Zugriffspfad auch zu berücksichtigen. Existiert jedoch kein Index auf der „richtigen“ Spalte, wird die Entscheidung für die richtige Abarbeitungsstrategie der Operation schon schwieriger. Jetzt spielen Fragen wie die Selektivität, die Größe eines Datensatzes und die Frage der Clusterung eine Rolle. Ist die Bedingung nicht sehr selektiv, müssen sowieso relativ viele Datensätze vom Sekundärspeicher geladen werden, weshalb ein sequenzielles Durchsuchen dieser Datensätze nicht unbedingt viel Zusatzaufwand bedeutet. In die gleiche Kerbe schlägt die Frage der Clusterung und Datensatzgröße. Sind die Datensätze zusammenhängend abgelegt und/oder eher kurz, dann bewegt sich der Leseaufwand beim Übertragen der Datensätze vom Sekundärspeicher in den Hauptspeicher in einem günstigen Rahmen. Auch hier könnte ein sequenzielles Durchsuchen ins Auge gefasst werden. Nun wird sich im Normalfall ein Ausdruck nicht einem der Extreme zuordnen lassen. Deshalb kommt es darauf an, möglichst genaue Informationen über den aktuellen Zustand der DB zu haben – Wie selektiv ist eine Bedingung? Wie viele Datensätze gibt es insgesamt? –, um mit Hilfe des Kostenmodells zu genaueren Aussagen und damit zu einer fundierten Entscheidung gelangen zu können. Beispielsweise könnte es sich als günstiger erweisen, statt einer
464
7 Die relationale Datenbanksprache SQL
sequenziellen Suche den Umweg über einen Primär- oder einen Mehrattributindex zu gehen, falls eine von diesen Varianten existiert. Ein Primärindex ist ein Index, der über den Primärschlüssel einer Tabelle geht und damit einen direkten Zugriff auf einen Datensatz erlaubt. Ein Mehrattributindex ist ein Index, der über eine Gruppe von Spalten (Attributen) angelegt wurde. Damit lassen sich direkt solche Datensätze finden, die exakt die durch mehrere Spalten repräsentierten Werte aufweisen. Schon diese Diskussion macht klar, dass eine physische Optimierung sehr von der Menge und Qualität des dem Optimierer zur Verfügung gestellten Zahlenmaterials (Statistiken) abhängt. Während die logische Umformung algebraischer Ausdrücke eigentlich in allen ernst zu nehmenden kommerziellen DBMS zu finden ist, wird die weiter gehende, auf Heuristiken beruhende physische Optimierung bisher häufig erst in einer rudimentären Form unterstützt. Hier liegt noch ein hohes Potenzial an zukünftigen Verbesserungen. Es sei allerdings an dieser Stelle auch darauf hingewiesen, dass sich Optimierungs- und Ausführungsaufwand in einem gesunden Verhältnis zueinander bewegen müssen. So macht es beispielsweise wenig Sinn, eine nur einmal auszuführende Onlineanfrage mit hohem Aufwand zu optimieren, mit der Konsequenz, dass die Anfrage dann zwar schnell ausgeführt wird, aber die Summe aus Optimierungs- und Ausführungszeit die Ausführungszeit der nicht optimierten Anfrage übersteigen würde. Umgekehrt ist natürlich klar, dass sich jeder Optimierungsaufwand rechtfertigen lässt, wenn zu erwarten ist, dass die gegebene Anfrage sehr häufig in einem sich nur sehr langsam ändernden Umfeld ausgeführt wird.
7.14
Zusammenfassung
SQL setzt sich aus mehreren logischen Teilsprachen zusammen, der Datendefinitionssprache (DDL), der eigentlichen Anfragesprache (DRL), der Datenmanipulationssprache (DML), der Datenkontrollsprache (DCL) und der Speicherungsstrukturdefinitionssprache (SSL). Tabelle 7.26 fasst noch einmal die wichtigsten Sprachkonstrukte der einzelnen Teilsprachen zusammen. SQL-Befehlsklassen DCL
SSL bzw. DSDL149
DELETE (Zeilen einer Tabelle löschen)
GRANT (Zugriffsrechte gewähren)
CREATE INDEX (Index für Tabellen anlegen)
ALTER Datenbankobjekt (Den Aufbau eines Datenbankobjektes ändern)
INSERT (Zeilen in eine Tabelle einfügen)
REVOKE (Zugriffsrechte entziehen)
DROP Datenbankobjekt (Ein Datenbankobjekt löschen)
UPDATE (Daten einer Tabelle verändern)
DDL
DRL
CREATE Datenbankobjekt (Ein Datenbankobjekt erzeugen)
SELECT FROM WHERE (Anfrage)
DML
Datenbankobjekt: Wertebereich, Tabelle, Sicht, Schema, Zusicherung
Tabelle 7.26: Teilsprachen von SQL und ihre wichtigsten Basiskonstrukte
7.15 Literatur
465
Um aus konventionellen Programmiersprachen heraus auf eine DB zugreifen zu können, wurde das Konzept des Vorübersetzers eingeführt. Datenbankbezogene Statements werden in eine gewöhnliche Programmiersprache integriert und dann über den Vorübersetzer herausgefiltert und in eine programmiersprachenverträgliche Form übersetzt. Der Austausch zwischen der DB und der Programmiersprache findet über einen so genannten Cursor statt, der die mengenorientierte Arbeitsweise des DBMS von der datensatzorientierten Arbeitsweise der Programmiersprache isoliert. Die Programmiersprache arbeitet in einer navigierenden Weise auf dem Cursor.
7.15
Literatur
Der SQL-Standard wird in den ANSI-Dokumenten beschrieben ([ANSISQL]). Den SQLStandard diskutieren die folgenden Bücher: [MeSi93], [Pasc93], [UnMa12], wobei das erste Buch als das Standardwerk für SQL-92 angesehen werden kann. Bücher, die sich allgemein stark mit SQL auseinander setzen, sind z. B. die folgenden: [DaDa97], [MaFr94], [Vand92]. Kritisch mit SQL setzen sich die folgenden Bücher und Artikel auseinander: [Codd85+88+90], [Date90+94] und [DaDa92]. Auch gibt es eine Serie („According to Date“), die schon über einige Jahre hinweg im Journal „Database: Programming & Design“ erscheint und in der vor allem Chris Date sich auch kritisch mit dem aktuellen SQL-Standard auseinander setzt. In dem Artikel “Toil and Trouble”150 wird sogar als Unterüberschrift die Forderung “Why duplicate rows are – or should be – prohibited” aufgestellt. Eine intensivere Diskussion der referentiellen Integrität wird von Chris Date in [Date81] geführt. Dazu gibt es eine Reihe von Büchern, die sich mit spezifischen (kommerziellen) DBMS und/oder deren SQL-Dialekten auseinander setzen. Ein Buch, welches tiefer in die Interna eines DBMS (hier ORACLE7) einsteigt, ist beispielsweise [FrMR97]. Probleme bei der Definition von Sichten werden beispielsweise in [Conv86] und [GoPZ88] beschrieben. Für einen tieferen Einstieg in das Thema „Sicherheitsaspekte in DBS“ wird auf [CFMS94] und [Pern94] verwiesen. Anfrageoptimierung ist immer noch ein sehr dynamisches und interessantes Forschungsgebiet. Bisher wird immer noch viel statisch auf der Basis der relationalen Algebra optimiert. Eine gute Einführung dazu findet sich in [CeGo85]. Dynamische Verfahren oder die Einbindung von Heuristiken in die Optimierung ist immer noch selten anzufinden. Gute Überblicke zu dieser Thematik finden sich in [Frey87], [FrMV94], [Grae93], [JaCV86], [JaKo84], [KrBZ86], [Lehn88], [Lohm88], [Shap86] und [Swam89]. Auch Kemper und Moerkotte haben sich in vielen Artikeln dieser Thematik gewidmet, wovon hier stellvertretend nur [KeMP93], [ScMo97], [SPMK94] und [StMK93] genannt seien. Ein ganzes Buch widmet Bernhard Mitschang dieser Thematik [Mits95]. Wer sich einen tiefen Überblick, insbesondere auch über weitere Potenziale von Optimierungstechniken verschaffen möchte, ist mit diesem Buch bestens bedient. 149 Die
SSL wurde bisher nicht standardisiert; deshalb wird hier nur ein Beispielbefehl genannt. [Date94].
150 siehe
466
7 Die relationale Datenbanksprache SQL
Eine ausführliche und lehrreiche Diskussion von Implementierungstechniken für Datenbankmanagementsysteme findet man in den Büchern von Theo Härder und Erhard Rahm ([HäRa01]) sowie von Gunter Saake und Andreas Heuer ([SaHe12]). Mit dem Datenbankenentwurf setzen sich beispielsweise Heinrich C. Mayr, Klaus R. Dittrich, Peter C. Lockermann in [MaDL87] auseinander. Die zwölf Regeln, die nach Meinung von E. Codd von einem wirklich relationalen DBMS erfüllt sein müssen, werden in [Codd86] vorgestellt. Eine Vorversion findet sich in [Codd85].
7.16
Kontrollaufgaben
Die Aufgaben orientieren sich im Wesentlichen an der Vorgehensweise im Kapitel, d. h. ihr Schwierigkeitsgrad steigt von vorne nach hinten. Die Basis der folgenden Aufgaben ist das in Kapitel 7.2.8, Abbildung 7.5 eingeführte Datenbankschema. Aufgabe 7.73: Neue Zeile einfügen „Ein neuer Fahrer (Roland Wohlfahrt) wurde heute eingestellt. Er soll die Fahrernummer 333 erhalten und direkt die fünfte Fahrt übernehmen.“ Aufgabe 7.74: Neue Zeilen einfügen „Montags soll die Fahrt mit der Nummer 8 (Linie 3) durch den Einsatz eines zusätzlichen Busses mit der Nummer 44 unterstützt werden. Die zusätzliche Fahrt bekommt die Fahrtnummer 19. Von dieser Neuerung sind die Tabellen Fahrt und FahrtenZuHaltestellen betroffen.“ Aufgabe 7.75: Verfeinerung von neuen Zeilen über die UPDATE-Anweisung „Inzwischen ist das Geburtsdatum (30.5.61) und die Kinderanzahl (4) von Herrn Wohlfahrt bekannt und soll entsprechend nachgetragen werden.“ Aufgabe 7.76: Zwei Anfragen, verknüpft über eine temporäre Tabelle „Wie wir gesehen haben, war es nicht einfach, eine Anfrage zu formulieren, die die Linien mit der höchsten Haltestellenanzahl ausgibt. Diese Anfrage kann übersichtlicher durch den Einsatz einer temporären Tabelle gestellt werden.“ Aufgabe 7.77: Ändern von Zeilen „Fahrt Nummer 17 soll nicht mehr um 8:00 Uhr, sondern um 8:15 beginnen. Dadurch verschieben sich auch alle anderen Zeiten entsprechend.“ Aufgabe 7.78: Änderungsoperation und Aggregatfunktionen „Die letzte Haltestelle von Fahrt Nummer 17 soll zwei Minuten später angefahren werden.“ Aufgabe 7.79: Zeile löschen „Die Fahrt mit Nummer 18 soll ersatzlos gestrichen werden.“ Aufgabe 7.80: Löschen aller Zeilen einer Tabelle „Die temporäre Tabelle HaltestellenAnzahl beansprucht zu viel Platz auf der Festplatte. Daher sollen sämtliche Zeilen dieser Tabelle gelöscht werden.“ Aufgabe 7.81: Vollständiges Entfernen einer Tabelle „Die (temporäre) Tabelle HaltestellenAnzahl wird nicht mehr benötigt und soll daher aus der DB entfernt werden.“
7.16 Kontrollaufgaben
467
Aufgabe 7.82: Löschen mit komplexer Anfrage „Linie Nummer 7 ist unrentabel geworden und wird eingestellt. Daher müssen u. a. aus der Tabelle FahrtenZuHaltestellen alle betroffenen Zeilen entfernt werden.“ Aufgabe 7.83: Komplexe Sichtendefinition „Die Frau des Fahrers Meier (Fahrernummer 13) stellt mindestens dreimal pro Woche die Frage, von wann und bis wann ihr Mann morgen arbeiten muss. Um diese Fragen schneller beantworten zu können, soll eine Sicht FahrerMeier definiert werden, die möglichst viel über seine Fahrten zu den einzelnen Haltestellen beinhaltet. Formulieren Sie die Sicht und die Anfrage darauf.“ Aufgabe 7.84: Änderungen bei Sichten mit Duplikaten „Erstelle eine Sicht FahrtenMitUhrzeiten, auf der die Uhrzeiten aller Fahrten geändert werden können.“ Aufgabe 7.85: Änderungen bei Sichten ohne Duplikate „Erstelle eine Sicht FahrtenMitUhrzeiten, auf der die Uhrzeiten nicht geändert werden können.“ Aufgabe 7.86: Rechtevergabe „Frau Meier (Aufgabe 7.83) darf ihre Anfragen selber an die DB stellen.“ Aufgabe 7.87: Sekundärindex „Für die Tabelle FahrtenZuHaltestellen sollen Indexe über die Spalten tag, fahrtNr und uhrzeit erstellt werden.“
8
Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
1
To say that these SQL:1999 extensions are mere „extended interpretations“ of the relational data model is like saying that an intercontinental ballistic missile is merely an „extended interpretation“ of a spear. 2 In den bisherigen Kapiteln über SQL haben wir uns weitestgehend auf den SQL-Standard von 1992 bezogen und damit das „konventionelle“ SQL eingeführt, dass immer noch die Basis von vielen SQL-Dialekten ist. Im Jahre 1999 wurde mit SQL:19993 eine neue Ära eingeleitet, da mit diesem Standard der Kern des objektrelationalen SQL eingeführt wurde. Diese Einführung kann als Antwort von SQL auf die Objektorientierung angesehen werden und stellt insoweit durchaus eher einen revolutionären denn evolutionären Schritt da. Dies kann auch daran gesehen werden, dass bis heute erst sehr wenige Anbieter von relationalen DBMS diesen Weg gefolgt sind und diese auch nur teilweise. Voll umgesetzt wird der objektrelationale Teil des Standards bisher immer noch von keinem DBMS-Anbieter. Am weitesten auf diesen Weg gegangen ist bisher ORACLE, gefolgt von IBM mit einem schon erheblichen Abstand. Weitere SQL-Dialekte realisieren höchstens einen kleinen Anteil. Grundsätzlich gesehen kann der objektrelationale Teil von SQL als eine eigene Teilsprache angesehen werden, die sich nicht mit dem konventionellen Teil mischen lässt. Der objektrelationale Teil realisiert im Wesentlichen das Konzept des abstrakten Datentyps, was bedeutet, dass jedes Objekt • einen eindeutigen Objektidentifikator besitzt, der während der gesamten Lebenszeit des Objektes identisch bleibt (also nicht verändert werden kann), • aus Sicht des Nutzers ausschließlich durch die ihm zugeordneten Methoden beschrieben wird und nicht, wie bisher in SQL üblich, durch die zu Grunde liegende Datenstruktur und • komplex strukturiert sein kann, was heißt, dass es einen beliebig tief geschachtelten Aufbau besitzen kann. 1 Bei der Erstellung dieses Kapitels waren die Folien von Nelson Mattos eine sehr große Hilfe. Für die freundliche Überlassung möchten sich die Autoren bei ihm herzlich bedanken. 2 Diese mehr als zutreffende Äußerung stammt aus den Unterlagen der Whitemarsh Information Systems Corporation ([Whit00]). 3 Dieser Standard hätte konsequenterweise eigentlich SQL-99 heißen müssen. Man hat aber bereits jetzt das Problem des Jahrtausendwechsels angepackt, indem man die Jahreszahl auf vier Stellen erweitert hat.
470
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Nicht mischbar ist so zu verstehen, dass ein Datenbankschema entweder ausschließlich mit Hilfe des konventionellen SQL entworfen sein sollte oder ausschließlich unter Einbeziehung der objektrelationalen Konzepte von SQL. Eine Mischung aus beiden Varianten würde schon wegen der zu Grunde liegenden Objektbeschreibung (Datenstruktur versus Methoden) keinen Sinn machen. Es sei aber noch einmal angemerkt, dass dies auf den Standard zutrifft. Da dieser aber bisher nicht umgesetzt wurde, ist die obige Aussage nicht direkt auf einzelne SQL-Dialekte anwendbar. Hier ist die Trennung zwischen dem konventionellem und dem objektrelationalem Teil eher fließend oder nicht gegeben. Der wesentliche Teil des objektrelationalen SQLs wurde mit SQL:1999 umgesetzt. Mit SQL:2014 gab es einige Verbesserungen und Korrekturen. Als wesentliche Erweiterung aus Sicht der Objektorientierung darf hier die in 1999 wegen ihrer Komplexität verschobene Einführung des bei komplex aufgebauten Objekten sehr wesentlichen Typkonstruktors SET angesehen werden, der im 2014-Standard in seiner allgemeineren Form, dem MULTISET (Menge mit Duplikaten), eingeführt wurde. Im Folgenden werden wir daher vor allem die Neuerungen vorstellen, die durch den objektrelationalen Teil von SQL:1999 und deren Erweiterungen in SQL:2014 eingeführt wurden. Aus Sicht dieses Buches haben die nachfolgenden Standards (SQL:2006, SQL:2008 und SQL:2011) nur wenige relevante Neuerungen hervorgebracht, weshalb wir im Folgenden häufiger von SQL:1999 bzw. dem objektrelationalem SQL sprechen werden, auch wenn der aktuelle Standard ein anderer ist. Es soll damit ausgedrückt werden, dass der 1999-Standard den entscheidenden Durchbruch in Bezug auf das objektrelationale SQL gebracht hat.
8.1
Struktur von SQL:2011
Die Verabschiedung des einen Standards ist gleichzeitig auch immer der Startschuss für die Arbeiten am nächsten. Im Falle von SQL wurden die grundlegenden Arbeiten am neuen Standard im Jahre 1999 abgeschlossen, deutlich später als ursprünglich geplant. Der neue Standard, SQL:1999 genannt, ist weitestgehend aufwärtskompatibel zu SQL-92. Bei der Einführung des SQL:1999-Standards war die Integration des objektorientierten Konzepts ein zentrales Thema. Als Axiom der Weiterentwicklung war quasi vorgegeben, dass die Basis „relationales Datenbankmodell“ bleiben soll. Dies war ein schwieriger Balanceakt, wie nicht zuletzt die lange Dauer der Standardisierung bewiesen hat. Insbesondere die Integration komplexer Objekte bzw. abstrakter Datentypen bereitete Schwierigkeiten. Auch wenn der neue Standard jetzt verabschiedet ist, wird dessen Umsetzung nicht zwangsläufig und schon gar nicht schnell erfolgen. Die Gründe dafür sind offensichtlich. Viele Datenbankanwendungen haben nur einfache Anforderungen an die Datenmodellierungsfähigkeit ihres DBMS, sind also mit dem „alten“ relationalen Datenbankmodell von SQL-92 hinreichend bedient. Für solche Anwendungen sind die neu hinzugekommenen Konzepte nur Ballast, der zudem die Einfachheit des „alten“ Datenbankmodells in Frage stellt. Andersherum hatten jedoch einige DBMS-Hersteller bereits „ihre“ Version objektorientierter/-relationaler Konzepte in ihren Systemen umgesetzt, weshalb kein schnelles Einschwenken auf die Syntax (und Semantik) von SQL:2011 zu erwarten war. Diese Gründe waren auch für uns ausschlaggebend, als Basis für das Buch weiterhin den SQL-92-Standard zu nehmen.
8.1 Struktur von SQL:2011
471
Dieses Kapitel wird die wesentlichen neuen Eigenschaften von SQL:2011 vorstellen, insbesondere die, die durch die objektrelationalen Ergänzungen mit SQL:1999 eingeführt wurden. Vorrangiges Ziel ist es dabei, dem Leser ein Gefühl zu vermitteln, wohin die Reise in Bezug auf objektorientierte/-relationale Konzepte geht. Aus den in der Einleitung zu SQL bereits genannten Gründen sei jedoch darauf hingewiesen, dass der objektrelationale Standard naturgemäß einerseits neue Konzepte enthält, die bisher erst in wenigen SQL-Dialekten angeboten werden, andererseits aber auch der Realität etwas hinterher hechelt, d. h. Konzepte umsetzt, die bereits in dieser oder ähnlicher Form in manchen SQL-Dialekten umgesetzt wurden. Zu Letzterem gehört alles, was die Mächtigkeit des Datenbankmodells erhöht, wie die neuen Datentypen für große Objekte (LOB-Datentypen) und der Boolesche Datentyp, die neuen Typkonstruktoren ARRAY, ROW (Zeilentyp) und REF (Zeigertyp) und die benutzerdefinierten strukturierten Datentypen, die das Konzept des abstrakten Datentyps umsetzen. Zu dieser Gruppe gehören auch die Sicherungspunkte (savepoints) und die Trigger-Konzepte. Zu den bisher eher selten anzufindenden Features gehört die Unterstützung der Rekursion. Der SQL-Standard ist im Gegensatz zum Konkurrenzstandard OQL der ODMG4 ein Mammutwerk, welches zumindest in einem Punkt dem jetzigen Standard nacheifern wird: Alles spricht dafür, dass es von SQL:1999 nie eine vollständige Implementierung geben wird. Stattdessen wird es auch weiterhin herstellerspezifische Erweiterungen und Eigenheiten geben, die zum Ausdruck bringen, wo der jeweilige Hersteller so wichtige Marktanforderungen identifiziert zu haben, dass sich deren Umsetzung in einem Wettbewerbsvorteil niederschlagen wird. Troels Arvin wartet eine Homepage5, auf der die Unterschiede verschiedener SQL-Varianten (Oracle, DB2, MSSQL, Informix, PostgreSQL, MySQL) zum Standard aufgelistet werden. Diese Seite wird gegenwärtig permanent auf dem laufenden Stand gebracht. Der ISO/IEC 9075:2011 Standard, wie er genau heißt, setzt sich aus neun Paketen zusammen, wobei das für die folgende Diskussion mit Abstand wichtigste Paket das zweite, SQL/Foundation, ist. Ursprünglich hatten einmal auch noch andere Pakete existiert, die dann teilweise zusammengefasst oder gestrichen wurden. Deshalb ist die höchste Paktenummer 14, aber die aktuell existierenden Paketnummern weisen Lücken auf. 1. Framework (SQL/Framework) (Paket 1) dient der allgemeinen Einführung und gibt Hinweise, wie das gesamte Werk aufgebaut ist und wie es gelesen werden sollte. 2. Foundation (SQL/Foundation) (Paket 2) SQL/Foundation beschreibt den Kern des SQL-Standards, was nicht zuletzt auch daran gesehen werden kann, dass alleine dieser Teil bereits knapp 1.200 Seiten umfasst. 4 Die Object Database M anagement Group war seinerzeit ein Zusammenschluss der bedeutendsten Hersteller objektorientierter DBMS (und weiterer interessierter Unternehmen). Sie verfolgte u. a. das Ziel, einen Standard für Anfragesprachen objektorientierter DBMS zu entwickeln, der zwangsläufig eine Konkurrenz zu SQL:2011 darstellt. Der Standard wird OQL (Object Query Language) genannt. Da OQL konsequent orthogonal konzipiert wurde ist seine jetzige Version (in [CBBE00] dokumentiert) sehr kompakt (unter 100 Seiten) und leistungsstark und hat insbesondere den Vorteil, dass seine Umsetzbarkeit bereits nachgewiesen wurde (allerdings nur in dem zwischenzeitlich (nach einem Unternehmensaufkauf) nicht mehr kommerziell erwerbbaren objektorientierten DBMS O2 ). Nach der Verabschiedung der fünften Überarbeitung des Standards mit dem Namen ODMG Version 3.0 im Jahre 2001 hat sich die Kommission wieder aufgelöst. 5 http://troels.arvin.dk/db/rdbms/ (Zugriff: Aug. 2013)
472
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Hier werden die Basiskonstrukte eingeführt, wie vorgegebene und benutzerdefinierbare Datentypen, Schemaaufbau und -information, Tabellen, Sichten, Anfrage- und Manipulationsanweisungen, Sicherheitsmodell, Prädikate, Transaktionsmanagement und noch viel mehr. 3. Call-Level-Interface (SQL/CLI) (Paket 3) SQL/CLI (call-level-interface) konzentriert sich auf den standardisierten Zugriff auf unterschiedliche DBMS. Relevante Vorschläge in diese Richtung sind das Integrated Database Application P rogram Interface (IDAPI), wofür Borland International verantwortlich zeichnet, und die Open Database Connectivity (ODBC), die von Microsoft vorangetrieben wird. 4. Persistent Stored Modules (SQL/PSM) (Paket 4) SQL/PSM (persistent stored modules) trägt der Tatsache Rechnung, dass die Standardisierungskommission bei der Beschäftigung mit ADTs schnell merkte, dass es nicht ausreicht, Operationen ausschließlich auf der Ebene der Anwendungsprogramme zu implementieren. Vielmehr muss, um eine effiziente und sichere Verarbeitung von Daten zu garantieren, eine Möglichkeit bestehen, Operationen direkt innerhalb des DBS abzulegen und auszuführen. Dadurch wird einer ansonsten zu erwartenden redundanten Implementierung identischer Funktionalitäten in mehreren Anwendungsprogrammen vorgebeugt. Zudem kann besser sichergestellt werden, dass die Operationen die ihnen zugedachte Aufgabe auch wirklich sauber und effizient umsetzen. Insbesondere können sie wesentlich besser optimiert werden, was ein entscheidender Schritt in Richtung einer effizienten Datenverwaltung ist. In der Konsequenz wird diese Initiative zu einer Datenbankprogrammiersprache führen, die in ihrer Funktionalität und Leistungsfähigkeit einer konventionellen Programmiersprache entspricht (computationally complete programming language). 5. Management of External Data (SQL/MED) (Paket 9) SQL/MED (Management of External Data) beschäftigt sich mit der Verwaltung von großvolumigen Datenmengen, die nicht direkt in der DB abgelegt werden sollen, bzw. aus historischen Gründen außerhalb der DB verwaltet werden. SQL/MED wird in Kapitel 8.5.7 noch etwas intensiver behandelt. 6. Object Language Bindings (SQL/OLB) (Paket 10) Dieses Paket ersetzt das alte Paket 5: SQL/Bindings, welches die Einbindung von SQL in einige Wirtssprachen (embedded SQL) (Ada, C, COBOL, Fortran, MUMPS, Pascal, und PL/I) und das sogenannte "dynamische SQL (dynamic SQL)"behandelt hatte. Dieser Teil ist jetzt in dieses Paket gewandert. Paket 10 setzt sich aber vor allem mit der Einbindung von SQL in Java™ auseinander. Der Standard definiert dazu seine eigene Erweiterung von SQL mit dem Namen SQLJ. SQLJ kann dabei als die herstellerneutrale Alternative zu der von SUN Microsystems6 propagierten Java Database Connectivity (JDBC7 ) angesehen werden. In der Tat ist SQLJ kompatibel zu JDBC und setzt in seiner Ausführung oft auf JDBC-Implementierungen auf. Die Java-Anbindung wird in Kapitel 8.5.8 noch etwas genauer behandelt. 6 In
der Zwischenzeit von Oracle Corporation aufgekauft. hierzu http://www.oracle.com/technetwork/java/javase/jdbc/index.html (zugegriffen im August 2013) 7 Siehe
8.2 Datentypen und Typkonstruktoren
473
7. Information and Definition Schema (SQL/Schemata) (Paket 11) Der SQL/Schemata bzw. Information and Definition Schemas Teil des SQL Standards ist jetzt ausgegliedert worden als eigener Teil und beschäftigt sich im Wesentlichen mit der Definition eines Datenbankschemas, dient also dem Anlegen der Metadaten einer Datenbank. 8. SQL Routines and Types Using the Java™ Programming Language (SQL/JRT) (Paket 13) SQL/JRT bzw. SQL Routines and Types for the Java Programming Language erweitert den SQL Standard um die Fähigkeit, als Routinen ausgelegte statische Java Methoden innerhalb von SQL Anwendungen ausführen zu können. Hier wird dann auch von "Java stored procedures"gesprochen Daneben erlaubt. SQL/JRT es auch, Java Klassen als benutzerdefinierte strukturierte Datentypen (siehe Kapitel 8.2.4) in SQL einzubinden und damit direkt nutzbar zu machen. 9. XML-Related Specifications (SQL/XML) (Paket 14) SQL/XML offeriert SQL-basierte Erweiterungen, die es erlauben, XML-Dokumente in einem relationalen Datenbanksystem zu speichern. Dazu wurde SQL um den neuen Datentyp XML erweitert. Dieser Datentyp kommt mit diversen Routinen bzw. Funktionen. Daneben gibt es XML-zu-SQL und SQL-zu-XML Abbildung, welche es erlauben, aus XML-Dokumenten SQL-spezifische Dokumente zu erzeugen und umgekehrt. Damit kann die Manipulation und Speicherung von XML in einer SQL Datenbank unterstützt werden. Dabei können entweder XMLTeile relational abgelegt und mit Hilfe von in SQL eingebetteten XQuery- oder XPathAnweisungen bearbeitet werden oder es werden vollständige XML-Dokumente in der relationalen Datenbank abgelegt und über XQuery bzw. XPath verfügbar gemacht, wobei dann auch in XQuery bzw. XPath-Ausdrücken SQL-Statements eingebettet sein können. Im ersteren Fall werden in der Regel XML-Dokumente über sogenannte Shredding-Funktionen zerlegt, auf SQL-Datentypen abgebildet und dann in Tabellen abgelegt. Umgekehrt bietet SQL/XML auch Funktionen an, um neue XML Elemente aus Attributen bzw. Werten von relationalen Tabellen zu konstruieren. Funktionen wie XMLCONCAT oder XMLAGG können genutzt werden, wenn kleine XML Fragmente zu größeren zusammengeführt werden sollen. Die Funktionen von SQL/XML, die dem Benutzer erlauben, XQuery Ausdrücke in SQL Statements zu verwenden sind XMLQUERY und XMLTABLE. XMLQUERY liefert Werte vom Typ XML zurück, während XMLTABLE XML Daten als Input nutzt um eine relationale Tabelle als Ergebnis zu liefern. XML Prädikate können mit der XMLEXISTS Funktion abgeprüft werden, typischerweise in der WHERE Klausel eines SQL Statements, möglicherweise auch zusammen mit SQL-Prädikaten. Im Folgenden sollen einige wesentliche Konzepte des objektrelationalen SQLs etwas detaillierter vorgestellt werden. Hauptaugenmerk wird dabei auf die objektrelationalen Konzepte gelegt.
8.2
Datentypen und Typkonstruktoren
Das Fundament des objektrelationalen SQLs bildet nach wie vor die (erweiterte) Menge von Basisdatentypen (vordefinierte (predefined) bzw. built-in Datentypen) und Typkonstruktoren. Neu ist die Unterstützung individualisierter (distinct) und benutzerdefinierter strukturierter
474
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
(user-defined) Datentypen, auch benannte Zeilentypen genannt. Individualisierte Datentypen entsprechen den bereits in Kapitel 7.2.2.4 eingeführten benutzerdefinierten Wertebereichen, nur dass die im anschließenden Kapitel 7.2.2.5 diskutierten Nachteile der fehlenden Typisierung und der nicht möglichen Spezifikation typspezifischer Operationen beseitigt wurden. Benutzerdefinierte Datentypen schließlich setzen das Konzept des abstrakten Datentyps um. Dies bedeutet insbesondere, dass ein Datum bzw. ein Objekt komplex aufgebaut sein kann und der Zugriff auf das Objekt nur über die für das Objekt spezifizierten Methoden/Operationen erfolgen darf.
8.2.1
Vordefinierte Datentypen
Vordefinierte Datentypen kommen mit dem System, sind also bereits bzgl. des Wertebereiches und der ausführbaren Operationen vollständig spezifiziert. Sie können weder Ober- noch Untertyp eines anderen Datentyps sein. Insgesamt wurden mit SQL:1999 zwei (Gruppen von) neue(n) Datentypen eingeführt: der „Wahrheitsdatentyp“ BOOLEAN und mehrere Datentypen zur Speicherung umfangreicher Objekte (Large Object oder verkürzt LOB). Dazu kommen vier (neue) Typkonstruktoren: ARRAY, REF, ROW und MULTISET. Letzteres wurde mit SQL:2014 nachgeschoben. Der Datentyp BOOLEAN Als Korrektur vergangener Versäumnisse kann die jetzt auch offizielle Berücksichtigung des Datentyps BOOLEAN angesehen werden. Er kommt mit der aus den Programmiersprachen bereits hinlänglich bekannten Semantik und den dazugehörigen Operationen. Beispiel 8.1 liefert ein Beispiel für seine Verwendung bei der Definition einer Tabelle, während Beispiel 8.2 die Verwendung der Operatoren EVERY und SOME demonstriert. Beispiel 8.1: Nutzung des Datentyps BOOLEAN In der folgenden Tabellendefinition wird das Geschlecht über den Datentyp BOOLEAN simuliert. Dabei könnte8 TRUE für weiblich und FALSE für männlich stehen. CREATE TABLE Mitarbeiter ( mitarbeiterNr AchtstelligeZahl PRIMARY KEY, mitarbeiterName VARCHAR(25) NOT NULL, mitarbeiterVorname VARCHAR(25), geburtsDatum DATE NOT NULL, geschlecht BOOLEAN, . . . ); Beispiel 8.2: Operationen des Datentyps BOOLEAN Die folgende Anfrage liefert eine Tabelle, in der zu jedem Kunden angegeben wird, ob er ein guter oder zumindest mittelguter Kunde ist. Dabei wird unterstellt, dass ein Kunde gut ist, falls er nur Produkte kauft, die teurer als 500,– C sind, während er noch mittelgut ist, falls er zumindest einige Produkte in dieser Preiskategorie kauft. 8 ausnahmsweise
einmal lebensnah modelliert
8.2 Datentypen und Typkonstruktoren
475
kundenNr, kundenName, kundenVorname, EVERY(nettoPreis > 500) AS guterKunde, SOME(nettoPreis > 500) AS mittelguterKunde FROM Kunden NATURAL JOIN Kauft NATURAL JOIN Produkt GROUP BY kundenNr, kundenName, kundenVorname;
SELECT
Als Ergebnis dieser Anfrage wird eine Tabelle geliefert, bei der in der Spalte guterKunde (mittelguterKunde) ein TRUE steht, falls für alle (einige) Datensätze in der Untertabelle zu einem Kunden die Bedingung (nettoPreis > 500) erfüllt ist. LOB Datentypen Seit SQL:1999 werden große Zeichenobjekte (in den Varianten CLOB für character large object und NCLOB für national character large object) und Binärobjekte (BLOB) explizit unterstützt. Diese Datentypen erlauben die von Seiten des DBMS nicht oder nur sehr eingeschränkt interpretierbare Ablage von großvolumigen Daten. Beispielsweise könnte man hier ein Foto, eine Filmsequenz, einen gesprochenen Text (alles BLOB) oder ein großes Textsegment (Buch, CLOB) ablegen. Zu den auf den Daten ausführbaren Operationen gehören die üblichen auf Zeichenobjekten ausführbaren Operationen wie CONCATENATION string1 || string2, SUBSTRING(QuellText FROM StartText FOR Länge), LENGTH(Länge), POSITION(GesuchterText IN QuellText). Wie bereits erwähnt ist mit SQL:2014 der Datentyp BIT VARYING eliminiert worden, da er semantisch keinen Unterschied zum offiziell mit SQL:1999 eingeführte Datentyp BLOB aufweist. Ebenso wurde der Datentyp BIT gestrichen, da für ihn ab SQL:1999 mit dem Datentyp BOOLEAN ein hinreichender Ersatz geschaffen worden war. Beispiel 8.3: Nutzung der LOB-Datentypen Die folgende Definition ist eine erweiterte Darstellung unserer „alten“ Produkttabelle. Es können jetzt zusätzlich zu jedem Produkt maximal fünf Fotos9 (bis zu einer Größe von je 1MB), eine textuelle Beschreibung (bis zu einer Größe von 100 KB) und ein Werbefilm (bis zu einer Größe von 1G) abgelegt werden. Die Buchstaben M(ega), K(ilo) und G(iga)Byte sind „Multiplizierer“ mit der üblichen Semantik. Stattdessen können auch beliebige INTEGER-Werte angegeben werden (also 102400 statt 100K). CREATE TABLE Produkt ( produktNr FünfstelligeZahl PRIMARY KEY, produktBez VARCHAR(25) UNIQUE NOT NULL, produktTyp VARCHAR(25) NOT NULL, stueckKosten PositiveReal NOT NULL, nettoPreis PositiveReal NOT NULL, bilder BLOB(1M) ARRAY[5], beschreibung CLOB(100K), werbeFilm BLOB(1G), CONSTRAINT VerlustVermeidung CHECK (nettoPreis > (stueckKosten ∗ 1,5))); 9 Der
Typkonstruktor ARRAY wird weiter unten noch genauer eingeführt.
476
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Die Interpretation von LOB-Daten muss in der Anwendung geschehen, was im Wesentlichen heißt, dass solche Daten entweder nicht oder vollständig aus der DB gelesen werden10 (mit allen damit verbundenen Nachteilen). Da solche Datentypen also als eine Art Notlösung zur Speicherung von nicht weiter interpretierbaren Volumendaten anzusehen sind, wird man auch schnell einsehen, dass deren Nutzung gewissen Einschränkungen unterliegen muss. So dürfen sie weder als Primär- oder Fremdschlüssel genutzt noch als UNIQUE gekennzeichnet oder in GROUP BY- und ORDER BY-Klauseln bzw. in UNION, INTERSECT und EXCEPTOperationen verwendet werden. In Vergleichen darf entweder nur auf vollständige Gleichheit oder Ungleichheit geprüft werden. Viele DBMS-Anbieter sind deshalb den Weg gegangen, ihr DBMS für die Einführung neuartiger Datentypen zu öffnen. Solche data extender, data blades oder data cartridges genannten Erweiterungen erlauben dem DBMS eine interpretierte Ablage von und damit verbunden effiziente Suche in neuartigen Datentypen (wie Datentypen für Multimedia, Audio, Video/Film, Web (SGML, HTML11 ) oder Zeitreihen (time series)). Auch die SQL-Standardisierungskommission hat sich diesem Trend geöffnet. Mit SQL/MM12 und bedingt auch mit SQL/MED13 werden Ansätze in Richtung anwendungsklassenspezifischer Datentypen vorangetrieben. In Kapitel 8.5 wird noch kurz auf diese beiden Ansätze eingegangen. In der Grafik aufgeführt ist der neue Datentyp XML. Ab SQL:2014 hat sich die Standardisierungskommission intensiv mit der Integration von XML-Dokumenten in die relationale Datenbankwelt auseinandergesetzt. Auch wenn später noch kurz auf diese Erweiterungen eingegangen wird, wird dieser Datentyp nicht intensiver behandelt, da die Integration von XML in SQL in diesem Lehrbuch nicht abgedeckt wird. Locators LOBs repräsentieren häufig sehr große Datenobjekte, was zu gewissen Problemen beim Umgang mit Datensätzen führen kann, die LOBs enthalten, insbesondere wenn auf diese LOBs nicht oder noch nicht zugegriffen werden soll. Zur Abmilderung dieser Problematik wurden so genannte Locator eingeführt. Vom Grundsatz ist ein Locator nichts anderes als ein eindeutiger Identifikator, der temporär angelegt wird und über den auf den eigentlichen Datenwert verwiesen wird (siehe Beispiel 8.4). Normalerweise existiert ein Locator für die Dauer der Transaktion, innerhalb derer er angelegt wurde. Über das HOLD-Statement kann seine Lebensdauer verlängert werden, entweder bis er explizit über das FREE-Statement freigegeben wird oder bis zum Ende der SQL-Session, wo er automatisch gelöscht wird. Locators können für LOBs, benutzerdefinierte strukturierte Datentypen und Arrays angelegt werden. Beispiel 8.4: Zugriff auf LOB-Datentypen über Locator-Variablen In diesem Beispiel werden zunächst Locator-Variablen innerhalb der SQL-Session angelegt, denen dann in der SQL-Anfrage die Ergebnisse der Anfrage zugewiesen werden (dies wird in der INTO-Klausel festgelegt). Damit hat man einen Handle, über den man später jederzeit auch auf die Dateninhalte zugreifen kann. 10 Dies
soll nicht heißen, dass die Daten alle auf einmal gelesen werden müssen. Intelligente Speicherverwaltung wird ein sukzessives Auslesen unterstützen. 11 Standard Generalized M arkup Language, Hypertext M arkup Language 12 MM steht für Multimedia 13 MED steht für Management of External Data
8.2 Datentypen und Typkonstruktoren
477
Mit der SUBSTRING-Operation werden aus der Beschreibung des Produktes die Textpassagen herausgesucht, in denen die Produktdetails aufgelistet sind. Es wird unterstellt, dass es eine Überschrift ’Produktdetails:’ gibt, wobei nach den Produktdetails die Ansprechpartner im Werbetext aufgeführt werden. Mit Hilfe der POSITION-Operation werden der Startpunkt der heraus zu filternden Textpassage und deren Länge berechnet. EXEC SQL BEGIN DECLARE SECTION; SQL TYPE IS BLOB AS LOCATOR LocatorWerbefoto; SQL TYPE IS CLOB AS LOCATOR LocatorWerbetext; ... EXEC SQL END DECLARE SECTION; ... EXEC SQL SELECT produktNr, produktBez, bilder[4], SUBSTRING (beschreibung FROM (POSITION(’Produktdetails:’ IN beschreibung)) FOR (POSITION(’Ansprechpartner:’ IN beschreibung) − POSITION(’Produktdetails:’ IN beschreibung)) INTO LocatorWerbefoto, LocatorWerbetext FROM Produkt WHERE produktNr = 12345; Mit den beschriebenen Datentypen sind die wesentlichen Neuerungen auf der Ebene der vordefinierten Datentypen eingeführt. Abbildung 8.1 gibt noch einmal einen Überblick, wobei die gegenüber SQL-92 neu hinzugekommenen Typen fett und kursiv dargestellt sind.
8.2.2
Typkonstruktoren
Auf der Ebene der Typkonstruktoren kommen zu den bereits im 1992er Standard implizit vorhandenen Zeilen- (ROW) und Mengenkonstruktor (SET)14 das aus den Programmiersprachen bereits hinlänglich bekannte ARRAY und der Verweistyp REF neu hinzu. ROW und SET in seiner allgemeineren Version MULTISET15 werden jetzt explizit unterstützt. Grundsätzlich wird über den CREATE TABLE-Befehl nach wie vor ein Container für Mengen von Tupeln angelegt, also ein SET eines bestimmten Typs. Damit gibt es den SET-Typkonstruktor nach wie vor implizit. Daneben gibt es aber den MULTISET-Typkonstruktor explizit. Wie später noch genauer diskutiert wird, unterstützt das objektrelationale SQL das explizite Definieren eines neuen Tupeltyps (Typ einer Tabelle). Dies geschieht über den CREATE TYPE-Befehl. Eine Tabelle wird dann explizit über den CREATE TABLE-Befehl angelegt, wobei bei dieser Version des CREATE TABLE-Befehls nur noch der Tupeltyps der Tabelle anzugeben ist (neben einigen anderen Angaben, die später noch diskutiert werden). Damit untergliedert sich im objektrelationalem SQL das Anlegen einer Tabelle in das Anlegen des Tabellentyps (Tupeltyp, CREATE TYPE) über den und dem anschließenden Anlegen der eigentlichen Tabelle (CREATE TABLE). Diese beiden Sprachkonstrukte werden genauer erst später eingeführt. Im Folgenden werden wir die Befehle aber trotzdem bereits verwenden, um ein korrektes SQL in den Beispielen zu gewährleisten. 14 Der 15 Ein
CREATE TABLE-Befehl erzeugt implizit ein set of tuple (=Tabelle). MULTISET ist ein SET, welches Duplikate enthalten kann.
478
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
SQL:2011: Vordefinierte Datentypen XML Chronologische Typen DATE
TIME
BOOLEAN
Numerische Typen
TIMESTAMP
INTERVAL großes kleines (Jahr, Monat) (Tag, Std., Min., Sek.) Zeichenbasierte Typen CHARACTER CHARACTER NCLOB CLOB VARYING
exakte numerische Typen
angenäherte numerische Typen
NUMERIC
REAL
DECIMAL INTEGER
FLOAT DOUBLE PRECISION
SMALLINT
BIGINT Bitbasierte Typen BLOB Abb. 8.1: Basisdatentypen in SQL:2011
Da über ein SET, MULTISET oder ARRAY eine Kollektion von (gleichartigen) Daten zu einer Einheit zusammengefasst werden kann, werden im Standard Typkonstruktoren dieser Art auch Kollektionstypen (collection type) genannt. Hinter den obigen etwas lapidaren Feststellungen verbirgt sich schon eine kleine Sensation bzw. Revolution. Die Einführung dieser Typkonstruktoren und die Möglichkeit, diese orthogonal anzuwenden, bedeutet ganz klar eine Verabschiedung von der ersten Normalform. Damit wird eine der Grundsäulen des relationalen Datenbankmodells aufgegeben16, auch wenn gesagt werden muss, dass diese vor allem der Einfachheit des Datenbankmodells diente und keine Forderung der dem relationalem Datenbankmodell zu Grunde liegenden Mengentheorie widerspiegelte. Es sei hier darauf hingewiesen, dass mit dem objektrelationalem SQL der Standard eigentlich in zwei Teile zerlegt wird, dem konventionellen SQL und dem objektrelationalen. Ersteres arbeitet noch ausschließlich mit dem CREATE TABLE-Befehl alter Machart. Letzteres setzt das Konzept des abstrakten Datentyps um und nutzt dazu die beiden Befehle CREATE TYPE und CREATE TABLE. Obwohl der objektrelationale Teil von SQL noch in keinem Dialekt vollständig umgesetzt wurde, kann hier bereits gesagt werden, dass aktuelle SQL-Dialekte 16 An der Außerkraftsetzung gibt es keinen Zweifel, auch wenn es einige Stimmen gibt, die mit wenig überzeugenden Argumenten behaupten, dass die erste Normalform durch die neuen Typkonstruktoren nicht tangiert wird.
8.2 Datentypen und Typkonstruktoren
479
die Nutzung aller Typkonstruktoren, die von dem Dialekt unterstützt werden, sowohl im konventionellen als auch im erweiterten SQL-Teil17 erlauben. Insofern hätte in den folgenden Beispielen auch immer CREATE TABLE anstatt von CREATE TYPE stehen können. Dann würde es sich um konventionelle Tabellen handeln, die nicht den abstrakten Datentyp umsetzen. Da hier aber das objektrelationale SQL eingeführt werden soll, wird auch immer nur die diesem Teil entsprechende Syntax verwendet werden. 8.2.2.1
Der ARRAY-Typkonstruktor
Mit dem Kollektionstyp ARRAY kann eine in ihrer Größe beschränkte Menge von gleichartigen (atomaren) Daten in einer vom Benutzer bestimmbaren Reihenfolge abgespeichert werden. Unterstützt wird eine einfache, eindimensionale Form, bei der die Startposition mit 1 fest vorgegeben ist. Eine Erweiterung zu einer zwei- bzw. mehrdimensionalen Datenstruktur ist nicht möglich. Weiterhin ist die Obergrenze immer anzugeben; ein in seiner Größe dynamisch veränderbares Array, wie es in manchen Programmiersprachen erlaubt ist, wird nicht unterstützt. Beispiel 8.5: Nutzung des Kollektionstyps ARRAY a. Ausgangspunkt dieses Beispiels ist die „alte“ Tabelle Abteilung. Es wird jetzt angenommen, dass das Gesamtbudget einer Abteilung auf zehn Budgetposten aufgeteilt wird. Die zehn Einzelposten werden in dem ARRAY budget verwaltet. CREATE TYPE AbteilungTyp AS ( abteilungsNr DreistelligeZahl, abteilungsName VARCHAR(25), budget PositiveReal ARRAY[10], mitarbeiterZahl SMALLINT) CONSTRAINT BudgetKontrolle CHECK ((( budget[1] + budget[2] + budget[3] + budget[4] + budget[5] + budget[6] + budget[7] + budget[8] + budget[9] + budget[10]) /mitarbeiterZahl) BETWEEN 1000 AND 10000)
b. Ausgangspunkt ist hier die „alte“ Tabelle Kunden. Es sollen pro Kunden bis zu drei Telefonnummern des Ansprechpartners speicherbar sein. Außerdem können bis zu fünf Adressen des Kunden gespeichert werden18. CREATE TYPE kundenNr kundenVorname
KundenTyp AS ( AchtstelligeZahl, VARCHAR(25),
17 Da das objektrelationale SQL von keinem Dialekt vollständig umgesetzt wird, ist diese Unterscheidung in konventionelles und objektrelationales SQL in der Praxis nicht gegeben. Es gibt lediglich Dialekte, die einen Teil des objektrelationalen SQLs bereits umsetzen. Dieser Teil der Dialekte wird hier als erweiterter SQL-Teil bezeichnet. 18 Der Typ des Arrays ist ein benutzerdefinierter (strukturierter) Datentyp, der in Kapitel 8.2.2.2 bzw. 8.2.4 noch genauer eingeführt wird.
480
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen kundenName kundenAdresse
VARCHAR(25), AdresseTyp ARRAY[5], ... ansprechPartner VARCHAR(25), ansprechpartTelNr VARCHAR(15) ARRAY[3])
Wie man Beispiel 8.5 entnehmen kann, ist zunächst immer der Name des Arrays, dann dessen Datentyp und schließlich dessen Kardinalität zu spezifizieren. Das Array kann ein sehr nützlicher Konstruktor sein, vor allem, wenn ein Attribut der zu modellierenden Entität mehrere Werte besitzen kann, jedoch die Schwankungsbreite in der Anzahl der Werte pro Datensatz gering ist. In Beispiel 8.5 a. wird beispielsweise unterstellt, dass sich das Budget einer Abteilung aus mehreren Einzelbudgets zusammensetzt. Es kann davon ausgegangen werden, dass jede Abteilung dieselben Einzelposten besitzt, wobei allenfalls leichte Abweichungen möglich sind (wie, dass ein bestimmter Einzelposten für eine bestimmte Abteilung nicht zutrifft). Die Nutzung eines Arrays vermeidet die ansonsten unumgängliche Einrichtung einer neuen Tabelle AbteilungsBudgets, die dann auch noch bei jeder Anfrage an Budgets zunächst über einen Verbund eingebunden werden müsste. Man kann sich leicht klar machen, dass das Array hier eine wesentlich übersichtlichere und effizientere Lösung ist. Die gleichen Argumente gelten für Beispiel 8.5 b. Man stelle sich einmal vor, welcher Mehraufwand getrieben werden müsste, wollte man das Problem über eigene Tabellen und Verbundoperationen lösen. Dagegen würde man bei der folgenden Modifikation des Kauft-Zeilentyps (siehe Beispiel 8.6) vermutlich keine positiven Erfahrungen machen. Der Grund liegt darin, dass viele Kunden wohl deutlich weniger als 1.000 Produkte kaufen werden. Es ist aber zu vermuten, dass bei einer Umsetzung des Standards der von einem Attribut vom Typ Array benötigte maximale Speicherplatz vollständig reserviert wird. Damit würde nicht nur eine erhebliche Speicherplatzverschwendung eintreten, sondern es würde höchstwahrscheinlich auch die Verarbeitungsgeschwindigkeit leiden, da auch im Hauptspeicher viel Speicherplatz unnötig durch leere Arrayfelder blockiert würde. Dieser Speicherplatz steht dann nicht mehr für andere (performanzverbessernde) Zwecke zur Verfügung. Beispiel 8.5 zeigt mit seinen zwei Modelleirungen noch einen weiteren Punkt auf, den man bei der Nutzung von Arrays beachten muss. Wenn beispielsweise nach einer bestimmten Adresse gesucht werden soll (wenn z.B. auf Basis von Beispiel 8.5 b. die Frage geklärt werden soll, ob der Kunde eine Adresse in Köln hat), so muss in der WHERE-Klausel des SFW-Statements jede ARRAY-Position einzeln abgefragt werden. Wenn das ARRAY dann die Dimension von Beispiel 8.6 hat, wird das Niederschreiben einer äquivalenten Anfrage zu einer richtigen Qual. Deshalb sollten ARRAYs auch nur dann verwendet werden, wenn die Ordnung auch wirklich eine sinnvolle Eigenschaft in dem zu modellieren Realweltausschnitt darstellt, wie es in Beispiel 8.5 a. der Fall ist. Natürlich mag es auch hier noch alle Positionen ansprechende Fragestellungen geben, wie welche Budgets weniger als x C aufweisen, aber solche Anfragen werden eher selten sein. Trotzdem wird das ARRAY aus den hier und im Absatz davor diskutierten Gründen immer eine untergeordnete Rolle gegenüber dem MULTISET spielen.
8.2 Datentypen und Typkonstruktoren
481
Beispiel 8.6: Speicherplatzfressende Nutzung des Kollektionstypen ARRAY Im Zeilentyp Kauft sollen pro Kunde die Produkte eingetragen werden, die dieser kauft. Unter der Voraussetzung, dass es keinen Kunden geben wird, der mehr als 1.000 Produkte kauft, könnte der Zeilentyp wie folgt modelliert werden: KauftTyp AS ( AchtstelligeZahl NOT NULL, FünfstelligeZahl ARRAY[1000], ...)
CREATE TYPE kundenNr produktNr
Feststellung 8.1: ARRAYs und Datentypen Grundsätzlich kann ein Array von jedem Datentyp sein, wodurch dessen orthogonale Einsetzbarkeit gewährleistet ist. Eine Ausnahme gibt es allerdings. Ein Array darf nicht von einem Typ sein, der auch wieder direkt auf einem Array basiert. Somit können beispielsweise keine Matrizen als Attributtyp konstruiert werden (siehe Beispiel 8.7). Allerdings kann ein Array Zeilentypen (ROW) und Zeigertypen (REF) enthalten, was in sehr mächtigen Datenstrukturen münden kann, wie wir später noch sehen werden.
Beispiel 8.7: Nicht unterstützte Schachtelung von Arrays Nehmen wir einmal an, dass für jedes Lager eine Tabelle geführt werden soll, in der jeweils am Monatsende der Wert des Lagerbestandes pro Produkt eingetragen werden soll. Diese Daten sollen jeweils für 12 Monate zur Verfügung gestellt werden, wobei unterstellt wird, dass in keinem Lager mehr als 1.000 Produkte lagern. CREATE TYPE produktLagerNr produktLagerBez wertProduktMonat
ProduktLagerTyp AS ( FünfstelligeZahl, VARCHAR(25), (PositiveReal ARRAY [1000]) ARRAY[12], ... )
Im obigen Beispiel wird innerhalb der Klammer hinter wertProduktMonat ein Datentyp (unterstrichen) spezifiziert, den man in einer voll orthogonalen Sprache auch wieder als Datentyp einem Array zuweisen können dürfte. Der Zugriff auf spezifische Werte eines Arrays geschieht über deren Position (siehe Beispiel 8.8) im Array. Beispiel 8.8: Zugriff auf den Kollektionstypen ARRAY Gib alle Abteilungen und ihr Reisebudget aus, sofern dieses mehr als 100.000,– C beträgt. Es wird unterstellt, dass im zweiten Arrayfeld das Reisebudget gespeichert wird.
482
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen SELECT FROM WHERE
abteilungsName, budget[2] AS reiseBudget Abteilung budget[2] > 100000;
Die Vorteile eines Arrays liegen in der Tatsache, dass sich damit aufwändige Tabellenzerlegungen und spätere Wiederzusammenführungen über Verbundoperationen vermeiden lassen. Mehrwertige Attribute lassen sich sehr einfach umsetzen. Die Nachteile liegen auch auf der Hand. Ein zu sorgloser Umgang mit Arrays wird die Performanz des Systems erheblich beeinträchtigen. Auch steht zu befürchten, dass Arrays zu einer gewissen Speicherplatzverschwendung führen werden, da man lieber auf Nummer Sicher gehen und die Array-Kardinalität großzügig auslegen wird. Einen weiteren Nachteil kann man an Beispiel 8.8 sehen. Eigentlich steckt mehr Semantik hinter budget, als man bei der Modellierung ausdrücken kann: Jede individuelle Position im Array repräsentiert einen bestimmten Budgetposten. Diese Semantik muss aber außerhalb des Datenbanksystems in der Anwendung eingebracht werden. Dieser Umstand wird die Les- und Interpretierbarkeit des Schemas negativ beeinflussen. Wie man dieses Problem „umschiffen“ kann, werden wir bei der Behandlung des Typkonstruktors ROW sehen. 8.2.2.2
Der ROW-Typkonstruktor
Die Einfachheit des relationalen Datenbankmodells und damit auch von SQL hat nicht zuletzt darauf beruht, dass alle Realweltobjekte auf Tabellen mit Zeilen und Spalten abgebildet werden (müssen). Dabei muss die Spalte atomar sein. Und hierin liegt einerseits der Schlüssel für die Einfachheit – Einfachheit im Sinn von einfach benutzbar, Einfachheit aber auch im Sinn von einfachem Datenbankmodell – und andererseits der Grund für so manche Performanzprobleme, insbesondere im Vergleich zu objektorientierter Technologie. Dort ist es möglich, aus einem Objekt auf ein (Unter-)Objekt zu verweisen. Im relationalen Datenbankmodell muss man einen solchen Verweis über einen Fremdschlüssel und einer sich darauf abstützenden Verbundoperation nachbilden – eine sehr kostspielige Operation. Das objektrelationale SQL löst dieses Problem durch die Einführung von Tupel- (ROW-Typ) und Verweistypen (REFTyp). Über den Tupeltyp kann ein komplexes Attribut direkt eingebunden werden, während ein Verweistyp es erlaubt, direkt auf eine konkrete Zeile einer (anderen) Tabelle zu verweisen. In beiden Fällen wird die teure Verbundoperation überflüssig. Im Folgenden sollen zunächst der Tupel- und der Verweistyp grundsätzlich eingeführt werden. In Kapitel 8.2.4 werden beide dann noch intensiver diskutiert. Der Tupel- bzw. Zeilenkonstruktor ROW war bisher bereits implizit vorhanden, da jede CREATE TABLE-Anweisung implizit auch einen zeilenwertigen Datentyp spezifiziert. Jetzt gibt es zwei explizite Möglichkeiten, Zeilentypen zu spezifizieren: 1. Über den Typkonstruktor ROW kann ein Attribut als zeilenwertig definiert werden. 2. Mit dem CREATE TYPE-Befehl kann ein Zeilentyp spezifiziert werden.
8.2 Datentypen und Typkonstruktoren
483
Der CREATE TUPLE-Befehl entspricht in seiner Syntax weitgehend dem Kern des CREATE TABLE-Befehls19 , nur wird keine neue Tabelle (Container) mit dem implizit spezifizierten Zeilentyp durch ihn erzeugt, sondern nur ein neuer Zeilentyp (siehe Beispiel 8.9) ohne gleichzeitig auch einen Container von diesem Typ anzulegen. Ein solcher Zeilentyp wird benutzerdefinierter strukturierter Datentyp oder benannter Zeilentyp genannt. Dieser Zeilentyp kann dann in einem CREATE TABLE-Befehl genutzt werden, um einen Container (Tabelle) von diesem Typ zu definieren. Solche Tabellen werden typisierte Tabellen genannt. Zeilen typisierter Tabellen besitzen wesentlich mehr Eigenschaften als konventionelle. Unter anderem besitzen sie einen eindeutigen Identifizierer, der als zusätzliches Attribut angesehen werden kann und jede Zeile der Tabelle eindeutig identifiziert. Definition 8.1: Eingebetteter Zeilentyp und zeilenwertiges Attribut In Beispiel 8.9 a. wird der benannte Datentyp AdresseTyp eingeführt. In Beispiel 8.9 b. wird das Attribut kundenAdresse als von diesem Datentyp spezifiziert. kundenAdresse ist in dieser Zeilentypdefinition die erste von zwei möglichen Varianten eines eingebetteten Zeilentyps. Die zweite mögliche Variante wird in Beispiel 8.10 gezeigt. Dort wird das zeilenwertige Attribut kundenAdresse mit Hilfe des ROW-Typkonstruktors direkt angelegt. Ein Attribut, das von einem vorher eingeführten benannten Zeilentyp ist oder dessen zeilenwertige Struktur direkt bei der Definition des Attributs über den ROW-Typkonstruktor festgelegt wird, wird zeilenwertiges Attribut genannt. Der zu diesem zeilenwertigen Attribut gehörige Datentyp wird eingebetteter Zeilentyp genannt. Stellt ein Attribut einen Verweis dar (über den REF-Typkonstruktor eingeführt (siehe Kapitel 8.2.2.3)), so ist es kein zeilenwertiges Attribut. Beispiel 8.9: Spezifikation von Zeilentypen über die CREATE TYPE-Anweisung a. Erzeugen eines neuen Zeilentyps AdresseTyp: CREATE TYPE AdresseTyp AS ( strasse VARCHAR(25), hausNr CHARACTER(5), plz CHARACTER(5), ort VARCHAR(25)) REF IS SYSTEM GENERATED,
Es wird ein Zeilentyp AdresseTyp erzeugt, der dann zur Spezifikation eines Attributtyps einer benannten Zeilentypdefinition (Beispiel 8.9 b.) herangezogen werden kann. Wie wir später noch diskutieren werden, muss und kann kein Primärschlüssel für einen benannten Zeilentyp definiert werden. Erzeugen einer neuer Tabelle auf der Basis des Zeilentyps AdresseTyp: CREATE TABLE Adresse OF AdresseTyp ( REF IS AdressOID SYSTEM GENERATED); 19 Gemeint ist hier die reine Definition der Spalten, wobei viele Spalteneigenschaften (z. B. Primärschlüssel) und Integritätsbedingungen nicht formuliert werden können. Genaueres findet sich in Kapitel 8.2.4.
484
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen Hier wird unter Zuhilfenahme des Zeilentyps AdresseTyp der Typ einer Tabelle festgelegt. In der REF IS-Klausel wird festgelegt, dass AdressOID der eindeutige Identifizierer von Zeilen von Adresse ist und dass dieser vom System automatisch erzeugt wird. b. Erzeugen eines neuen Zeilentyps KundenTyp unter Nutzung eines bereits vorher definierten mehrwertigen Zeilentyps zur Definition des Attributtyps von kundenAdresse: CREATE TYPE KundenTyp AS ( kundenNr INTEGER, kundenVorname VARCHAR(25), kundenName VARCHAR(25), kundenAdresse AdresseTyp, ... ansprechpartTelNr VARCHAR(15)) REF IS SYSTEM GENERATED,
Bei dieser Variante wird die Zeilentypdefinition AdresseTyp von oben direkt zur Spezifikation des Attributtyps von kundenAdresse genutzt.
Diese Variante der Zeilentypspezifikation wird noch ausführlich im Kapitel 8.2.4 behandelt und wurde daher hier nur insoweit eingeführt, wie dies zum Verständnis dieses und des nächsten Kapitels notwendig ist. Die Standardisierungskommission hat sich dazu entschlossen, der Tatsache Rechnung zu tragen, dass man sich deutlich in Richtung Objektorientierung bewegt hat20 . So werden insbesondere Spalten von benannten Zeilentypen jetzt Attribute genannt (siehe Feststellung 8.2). Wir werden uns im Folgenden daran halten, auch wenn eine genaue Unterscheidung nicht immer ganz einfach ist und die Lesbarkeit des Textes manchmal darunter leidet. Feststellung 8.2: Spalten, Felder und Attribute Im SQL-Standard werden Elemente eines ROW-basierten Datentyps Felder (fields) genannt, die Spalten eines benannten Datentyps hingegen Attribute (attributes). Elemente von konventionellen oder typisierten Tabellen heißen weiterhin Spalten. Zusätzlich wird im Folgenden von Instanz bzw. Ausprägung geredet, wenn eine konkrete Zeile einer typisierten Tabelle bzw. ein „Objekt“ von einem benannten Zeilentyp adressiert wird. Beispiel 8.10 zeigt, wie mit dem Typkonstruktor ROW direkt innerhalb einer Zeilentypspezifikation ein zeilenwertiges Attribut angelegt werden kann. 20 Dies
wird später noch ausführlich diskutiert.
8.2 Datentypen und Typkonstruktoren
485
Beispiel 8.10: Anlegen von zeilenwertigen Attributen Definition einer modifizierten Version von KundenTyp mit eingebetteten zeilenwertigen Attributen: KundenTyp AS ( INTEGER, ROW ( kundenVorname VARCHAR(25), kundenName VARCHAR(25)), kundenAdresse ROW ( strasse VARCHAR(25), hausNr CHARACTER(5), plz CHARACTER(5), ort VARCHAR(25)), ... ansprechPartTelNr VARCHAR(15)) REF IS SYSTEM GENERATED,
CREATE TYPE kundenNr nameKunden
Es stellt sich die Frage, ob semantisch ein Unterschied besteht zwischen dieser Variante und der mit dem eingebetteten Zeilentyp AdresseTyp von Beispiel 8.9 b.) Wie später noch ausführlicher diskutiert wird, ist dies der Fall, da ein benannter Zeilentyp eine Objektidentität besitzt und damit anders zu behandeln ist als ein ROW-basierter Typ, der eine Wertesemantik besitzt. Feststellung 8.3: Unterschied zwischen einem eingebetteten und einem über ROW spezifizierten Zeilentyp Ein über ROW spezifizierter Typ einer Zeile besitzt eine Wertesemantik, d.h. es wird eine Datenstruktur für dieses Attribut festgelegt. Damit entspricht diese Definition aus Sicht der Semantik der Definition einer Tabelle im konventionellen SQL. Wenn hingegen ein Attribut von einem eingebetteten Zeilentyp ist, so realisiert es einen abstrakten Datentyp. Es ist damit nur über die ihm zugeordneten Operationen ansprechbar und besitzt automatisch eine eindeutige Objektidentität (OID). Dies wird später noch ausführlicher diskutiert. Innerhalb eines zeilenwertigen Attributs lassen sich als Felder beliebige Feldtypen21 verwenden. Dadurch können (rekursiv) Unterobjekte in Unterobjekte eingebettet werden, wodurch sich eine beliebig tief geschachtelte Struktur realisieren lässt. In Beispiel 8.11 werden innerhalb des zeilenwertigen Attributs zulieferer die Bankdaten in einem eigenen zeilenwertigen Feld abgelegt. zuliefererAdresse ist ein anderes zeilenwertiges Feld, dessen Typ bereits vorher definiert wurde. Es gibt bis zu fünf Ansprechpartner, die in einem Array abgelegt sind, wobei jeder Ansprechpartner durch ein zeilenwertiges Attribut vom Typ KontaktPersTyp beschrieben ist. 21 Ein Feldtyp entspricht einem Spaltentyp entspricht einem Attributtyp. Die Tatsache, dass hier mit Feld und Attribut zwei für SQL neue Namen eingeführt wurden, soll nicht dazu führen, dass alle Definitionen wiederholt werden.
486
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Beispiel 8.11: Schachtelungen von Datentypen In diesem Beispiel wird ein über den ROW-Typkonstruktor definiertes zeilenwertiges Feld (bankDaten) und Felder von einem benannten Zeilentyp (zuliefererAdresse und ansprechPartner) in das zeilenwertige Attribut zulieferer eingebettet22 . CREATE TYPE zulieferer
teilNr produktNr
LiefertTyp AS ( ROW ( zuliefererNr zuliefererName zuliefererAdresse bankDaten
ansprechPartner FünfstelligeZahl, FünfstelligeZahl)
AchtstelligeZahl, VARCHAR(25), AdresseTyp, ROW ( bank VARCHAR(25), iban VARCHAR(25), bic VARCHAR(12)), KontaktPersTyp ARRAY[5]),
REF IS SYSTEM GENERATED);
CREATE TYPE KontaktPersTyp AS ( kontaktpersonName VARCHAR(25), kontaktTelNr VARCHAR(15)) REF IS SYSTEM GENERATED
Im letzten Abschnitt (8.2.2.2) hatten wir eine bessere Lösung für das in Beispiel 8.5, a. gegebene Szenario versprochen. Beispiel 8.12 liefert diese übersichtlichere Lösung.
Beispiel 8.12: Übersichtlichere Lösung für das Problem von Beispiel 8.5 a. In diesem Beispiel wird gezeigt, dass es aus Sicht der Übersichtlichkeit besser ist, ein Array durch einezeilenwertiges Attribut zu ersetzen, falls jede Arrayposition eine spezifische Semantik besitzt. CREATE TYPE AbteilungTyp AS ( abteilungsNr DreistelligeZahl, abteilungsName VARCHAR(25), budget ROW ( personalmittel PositiveReal CHECK (VALUE BETWEEN 100000 AND 800000), 22 Die
Frage der Sinnhaftigkeit dieser Modellierung wird in Kapitel 8.3.1 noch diskutiert.
8.2 Datentypen und Typkonstruktoren sachmittel reisemittel
werbemittel
487 PositiveReal CHECK (VALUE BETWEEN 100000 AND 200000), PositiveReal CHECK (VALUE BETWEEN 50000 AND 150000), ... PositiveReal CHECK (VALUE BETWEEN 10000 AND 80000)) CHECK (VALUE ≥ 0))
mitarbeiterZahl SMALLINT CONSTRAINT BudgetKontrolle CHECK (( (personalmittel + sachmittel + reisemittel + . . . + werbemittel)/ mitarbeiterZahl) BETWEEN 1000 AND 10000), CONSTRAINT MitarbeiterKontrolle CHECK (VALUE ≥ 0),
Der Zugriff auf die Felder einer zeilenwertigen Spalte erfolgt über sogenannte Pfadausdrücke. Dabei navigiert man ausgehend vom eigentlichen Objekt durch die gesamte baumartig aufgebaute Datenstruktur hin zum gewünschten Objekt. In Beispiel 8.12 kann man werbemittel ansprechen, indem man in budget einsteigt und sich über die Punktnotation nach werbemittel navigiert (budget.werbemittel). Wäre werbemittel auch ein zeilenwertiges Feld, könnte man von dort weiter navigieren (budget.werbemittel.xyz), usw. 8.2.2.3
Der REF-Typkonstruktor
Zeiger, Verweise oder Referenzen sind ein sehr mächtiges Konzept, um Beziehungen zwischen Daten zu modellieren. Aus Sicht des relationalen Datenbankmodells helfen sie vor allem, die teuren Verbundoperationen zu vermeiden. Beispiel 8.13 zeigt wie dies geschehen kann. Der zu einem Konto gehörende Kunde wird nicht über eine Fremdschlüsselbeziehung, sondern direkt über einen Verweis (REF(KundenTyp)) angesprochen, wobei die eingebundene Zeile nicht automatisch in eine Abhängigkeitsbeziehung zur „Vaterzeile“ tritt, sondern eigenständig bleibt. Diese Verweissemantik ermöglicht es auch, dass von unterschiedlichen Datensätzen aus auf denselben Datensatz verwiesen werden kann. Würde ein gegebener Kunde beispielsweise noch ein zweites Konto eröffnen wollen, so ließe sich dies mit der Verweissemantik problemlos modellieren, da einfach auf denselben Kundendatensatz verwiesen werden kann. Wird jedoch ein Datensatz direkt eingebunden, wie der Datensatz des Typs AdresseTyp in Beispiel 8.9 b., so kann damit Identität nicht mehr erreicht werden, höchstens Gleichheit, indem in den jeweiligen Spalten zweier unterschiedlicher Datensätze jeweils die gleiche (aber eben nicht dieselbe) Adresse geschrieben wird. Verweise können grundsätzlich nur auf einen Datensatz innerhalb einer typisierten Tabelle verweisen, also weder auf eine Tabelle als Ganzes noch auf einzelne Attribute eines Datensatzes, auch wenn diese ein komplexes Unterobjekt darstellen.
488
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Beispiel 8.13: Nutzung des REF-Typkonstruktors zur Definition eines Attributtyps a. Erzeugen eines neuen Zeilentyps KontoTyp mit unabhängigem Unterobjekt kunde: CREATE TYPE KontoTyp AS ( iban VARCHAR(25), bic VARCHAR(12), kunde REF(KundenTyp), eroeffnung DATE, zinsSatz DOUBLE PRECISION, kontoStand DOUBLE PRECISION) REF IS SYSTEM GENERATED,
b. Hier kommt eine weitere Variante des KundenTyp-Datentyps, bei der sowohl die Adressen als auch die Ansprechpartner in einer separaten Tabelle gespeichert werden. Wie in Beispiel 8.5, 2. wird davon ausgegangen, dass bis zu fünf Adressen und drei Ansprechpartner abgelegt werden können. KundenTyp AS ( AchtstelligeZahl, VARCHAR(25), VARCHAR(25), REF(AdresseTyp) ARRAY[5], ... ansprechPartner REF(KontaktPersTyp) ARRAY[3]) REF IS SYSTEM GENERATED,
CREATE TYPE kundenNr kundenVorname kundenName kundenAdresse
Über einen Zeiger REF kann auf eine Zeile einer „referenzierbaren“ Tabelle verwiesen werden. Eine Tabelle ist referenzierbar, falls sie eine mit Hilfe eines Tabellentyps definierte Basistabelle oder Sicht darstellt. Obwohl Verweise intern auf denselben Datentyp abgebildet werden, sind sie typisiert. An der Stelle, wo ein Verweis eines bestimmten Typs erwartet wird, kann also nicht ein Verweis auf eine beliebige Zeile erfolgen, sondern es muss auf eine Zeile des zu Grunde liegenden Verweistypen verwiesen werden. In Beispiel 8.13 wird festgelegt, dass kunde nur auf Zeilen vom Typ KundenTyp verweisen kann. Vom Grundsatz her würde man sich wünschen, dass kunde auf Datensätze in beliebigen Tabellen verweisen kann, sofern diese vom Typ KundenTyp sind. Ursprünglich war auch eine gewisse diesbezügliche Flexibilität im Standard vorgesehen gewesen. Allerdings waren die damit verbundenen Probleme so gravierend, dass es zusätzliche Zeit benötigt hätte, sie aufzulösen. Daher hat man sich zunächst auf ein weniger flexibles Modell geeinigt und eine Verbesserung für die Zukunft offen gelassen. Das objektrelationale SQL verlangt, dass eine Referenz typisiert ist, also zum Zeitpunkt der Definition eines Tabellentyps oder einer Tabelle der Typ der Referenz angegeben wird. Handelt es sich um eine Tabellendefinition nach alter Machart, muss über die SCOPE-Klausel angegeben werden, auf welche konkrete (andere) Tabelle sich diese Referenz bezieht (siehe Beispiel 8.14). Die Tabelle muss bereits existieren.
8.2 Datentypen und Typkonstruktoren
489
Beispiel 8.14: Einschränkung des Wertebereiches von Verweisen I Im folgenden Beispiel wird eine neue Tabelle Konto mit unabhängigem Unterobjekt kunde erzeugt, wobei kunde auf Datensätze der Tabelle Kunden (mit Datentyp wie in Beispiel 8.9 spezifiziert) verweisen muss. CREATE TABLE Konto OF KontoTyp ( REF IS KundeOID SYSTEM GENERATED, kunde WITH OPTIONS SCOPE Kunden), ); Beispiel 8.15 liefert ein Beispiel, wie zu verfahren ist, falls eine neue Tabelle auf der Basis eines Zeilentyps erzeugt werden soll. Hier wird über die WITH OPTIONS SCOPE-Klausel der Wertebereich für den Verweis kunde auf Datensätze einer gegebenen Tabelle GuteKunden eingeschränkt. Beispiel 8.15: Einschränkung des Wertebereiches von Verweisen II Diesem Beispiel liegt die Zeilentypdefinition für KontoTyp von Beispiel 8.13 zu Grunde. CREATE TABLE KontenGuteKunden OF KontoTyp ( REF IS KtoGuteKundenOID SYSTEM GENERATED, kunde WITH OPTIONS SCOPE GuteKunden, ); Es mag etwas umständlich anmuten, dass man bei einer Verweisdefinition zunächst den Typ des Verweises angeben muss, um ihn dann auf eine konkrete, bereits existierende Tabelle einzuschränken. Da liegt es auf der Hand, die Typangabe auszulassen und nur die konkrete Tabelle anzugeben, auf die verwiesen werden darf, da dies implizit auch einer Typdefinition entspricht. Diese Logik ist sicherlich zutreffend. Das sie trotzdem keine Anwendung findet liegt daran, dass die jetzt etwas sehr restriktive Variante der Beschränkung auf eine Tabelle in Zukunft sicher durch eine flexiblere Lösung ersetzt wird23 . Ein weiterer Grund liegt darin, dass Verweise intern über die SQL-Version einer Objektidentität (OID) realisiert werden. Eine OID gibt es aber nur bei Tabellen, die auf einen benannten Zeilentyp basieren. Damit können Tabellen, die in traditioneller Weise über die CREATE TABLE-Anweisung mit anschließender Auflistung aller Spalten und der weiteren Angaben gebildet wurden, nicht referenziert werden. Hier werden Implementierungsaspekte24 mit konzeptuellen Aspekten vermischt, eine sehr unglückliche Kombination, die den Umgang mit dem objektrelationalen SQL für den Entwickler und Anwender nicht einfacher macht. 23 Man kann hieran gut die Probleme sehen, mit denen die Standardisierungskommission zu kämpfen hat. Einerseits muss eine neue Version eines Standards in endlicher Zeit verabschiedet werden. Andererseits prasseln immer wieder neue Ideen und Anforderungen auf die Kommission ein. Da ist es dann notwendig, auch mit Kompromissen zu leben. Allerdings kann davon ausgegegangen werden, dass diese in dieser Form in der Praxis eher nicht umgesetzt werden, sondern vermutlich weitergehendere, ausgereiftere Varianten. Dies bedeutet dann, dass der Standard hinterherhinkt, was er in Teilen sowieso immer tun wird. Würde man aber einen Schnellschuss wagen, der sich dann als Rohrkrepierer herausstellt, würde der Standard mit Sicherheit unter erheblichen Akzeptanzproblemen leiden. Da erscheint die vorsichtigere Lösung doch deutlich sinnvoller zu sein. 24 Würde man später einen Verweis auf eine traditionell angelegt Tabelle einfügen wollen, hätten deren Datensätze keine OID. Damit müsste ein neues Attribut zum Datensatz hinzugefügt werden. Dies ist eine äußert unangenehme Operation, wie man daran sehen kann, dass das Hinzufügen von Spalten bei vielen kommerziellen Systemen immer noch nicht bzw. lange Zeit nicht unterstützt wurde.
490
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Um die referenzielle Integrität sicherstellen zu können, kann eine entsprechende Integritätsbedingung festgelegt werden. Die REFERENCES ARE [NOT] CHECKED-Klausel stellt sicher, dass bei einer Löschung des Objektes, auf das verwiesen wird, eine vorgegebene Reaktion erfolgen kann ([ON DELETE CASCADE | SET NULL | SET DEFAULT | RESTRICT | NO ACTION])25. Es sei allerdings angemerkt, dass diese Klausel nicht bei der Beschreibung eines Attributs in einem Zeilentyp angewendet werden kann26 , sondern beim Anlegen einer Tabelle in der WITH OPTIONS-Klausel. Beispiel 8.16: Einsatz der REFERENCES ARE [NOT] CHECKED-Klausel a. Nicht erlaubte Verwendung der REFERENCES ARE [NOT] CHECKED-Klausel bei der Deklaration eines benannten Zeilentyps: CREATE TYPE iban bic kunde
KontoTyp AS ( VARCHAR(25), VARCHAR(12), REF(KundenTyp) REFERENCES ARE CHECKED ON DELETE CASCADE, eroeffnung DATE, zinsSatz DOUBLE PRECISION, kontoStand DOUBLE PRECISION) REF IS SYSTEM GENERATED,
b. Erlaubte Verwendung der Klausel in der WITH OPTIONS-Klausel bei der Tabellendefinition: CREATE TABLE KontenGuteKunden OF KontoTyp ( REF IS KtoGuteKundeOID SYSTEM GENERATED, kunde WITH OPTIONS SCOPE GuteKunden REFERENCES ARE CHECKED ON DELETE CASCADE); Auch der Zugriff auf die Spalten eines über den REF-Typkonstruktor eingebundene Unterobjektes erfolgt über Pfadausdrücke. Allerdings ist in diesem Fall die Pfeilnotation statt der Punktnotation zu verwenden. Will man also beispielsweise auf den Kundennamen eines Kontoinhabers zugreifen, ist dies wie folgt zu spezifizieren: kunde → kundenName Der Zeigertyp stellt in im objektrelationalen SQL einen Typkonstruktor dar. Dies mag etwas unlogisch erscheinen, da viele Leser mit dem Begriff Typkonstruktor ein Konstrukt verbinden, welches per se zunächst einmal „typfrei“ ist, es aber erlaubt, eine Menge von „kleineren“ Einzelbestandteilen (wie eine Menge von benannten Attributen unterschiedlicher (atomarer) Datentypen) zu einer komplexeren Einheit (einer Zeile) zusammenzufassen. Ein Verweis scheint 25 Zur
Semantik dieser Aktionen siehe Kapitel 7.2.4.3. hier nur in den wenig interessanten Varianten REFERENCES ARE NOT CHECKED bzw. REFERENCES ARE CHECKED ON DELETE NO ACTION. 26 Beziehungsweise
8.2 Datentypen und Typkonstruktoren
491
jedoch vom ihn umsetzenden Typ her immer gleich zu sein (ein CHARACTER-String oder INTEGER-Wert fester Länge) und zudem die „Einzelbestandteilvereinigung“ nicht zu erfüllen. Dass trotzdem die Bezeichnung Typkonstruktor zutrifft, liegt daran, dass im objektrelationalen SQL Verweise typisiert sind, was bedeutet, dass zwei Verweise nur dann typkompatibel sind, falls die Typen, auf die sie verweisen, mindestens in einer Typ-/Untertyp-Beziehung27 stehen (bzw. auf demselben Typ verweisen). Dann müssen sie zwangsläufig entweder auf Daten/Objekte desselben Typ verweisen oder die Typen der Daten/Objekte stehen in einer Typ-/Untertyp-Beziehung28. Diese schärfere Definition schließt aus, dass Gemüse (z. B. Kohl) mit Obst (z. B. Birnen) verglichen werden kann29. Wegen des mit der Vererbung verbundenen Konzeptes der Substituierbarkeit ist zwar nicht sichergestellt, dass nur Daten/Objekte des selben Typs miteinander verglichen werden können, aber die zur Vermeidung von Typfehlern notwendige Typkompatibilität ist garantiert. Da die Vereinigung von Einzelbestandteilen auch einschließt, dass nur ein Einzelbestandteil „vereinigt“ wird, ist damit unter der diskutierten Semantik der Zeiger ein Typkonstruktor. 8.2.2.4
Der MULTISET-Typkonstruktor
Der Typkonstruktors SET wird implizit immer dann angewandt, wenn ein CREATE TABLEBefehl ausgeführt wird. Da eine Tabelle nach wie vor keine zwei identischen Zeilen enthalten darf, ist sichergestellt, dass eine explizit angelegte Tabelle immer duplikatfrei ist30 . Neben dieser impliziten Verwendung des SET-Typkonstruktors unterstützt das objektrelationale SQL seit dem SQL:2014-Standard explizit den Typkonstruktor MULTISET. Damit kann unter anderem eine sogenannte geschachtelte Relation modelliert werden, bei der ein Attribut wiederum eine Relation/Tabelle darstellen kann. In Beispiel 8.17 wird die Beziehung zwischen einem Teil und seinen Lieferanten und den Produkten, in denen es Verwendung findet, über eine geschachtelte Relation modelliert. Beispiel 8.17: „Tabellenwertige“ Attribute In diesem Beispiel wird modelliert, dass es für ein Teil eine Vielzahl von Lieferanten geben kann und dass jedes Teil in einer Vielzahl von Produkten Verwendung finden kann. Es wird unterstellt, dass LieferantTyp (ProduktTyp) eine benannter Zeilentyp ist, der Lieferanten (Produkte) beschreibt.31 27 Typ-/Untertyp-Beziehung
werden in Kapitel 8.3.5 eingeführt. dieser Interpretation der Autoren dieses Buches spielen pragmatische Gesichtspunkte eine gewisse Rolle, da der Standard eine wesentlich unverbindlicher Formulierung vorhält: „Values of two reference types are mutually comparable if the referenced types of their declared types have some common supertype.“ Dies bedeutet, dass auch Daten typkompatibel sind, die in parallelen Ästen einer Typhierarchie angesiedelt sind (genau genommen haben alle Typen in einer solchen Hierarchie einen gemeinsamen Obertyp, wenn man, wie üblich, unterstellt, dass die Hierarchie einen Baum darstellt). Aber diese Interpretation widerspricht der aus gutem Grund bei objektorientierten Systemen genutzten Definition, weshalb zu vermuten ist, dass sie so weit ausgelegt nicht gemeint ist. 29 Etwas, was in manchen Politikerkreisen sehr begrüßt wurde. 30 Dies wird vor allem auch deshalb sichergestellt, weil jede Zeile einer typisierten Tabelle bei ihrer Erzeugung automatisch eine eindeutige Objektidentität (OID) zugewiesen bekommt. Deshalb können zwar grundsätzlich jeweils die Werte aller Spalten gleich sein – trotzdem sind die beiden Zeilen über die OID eindeutig unterscheidbar. 31 Auch hier gilt, dass die Sinnhaftigkeit dieser Modellierung bezweifelt werden muss (siehe Diskussion in Kapitel 8.3.1). 28 Bei
492
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen TeilTyp AS ( FünfstelligeZahl, VARCHAR(25), LieferantTyp MULTISET, ProduktTyp MULTISET) ... REF IS SYSTEM GENERATED,
CREATE TYPE teilNr teilBez teilLieferant teilProdukt
Erst die Einführung des MULTISET-Typkonstruktors hat die Tür zur Modellierung von wirklich komplexen, tief verschachtelten Objekten ermöglicht. Beispiel 8.18: Sinnvollere Modellierung von Beispiel In Beispiel 8.17 werden Lieferanten, die mehrere Teile liefern, und Teile, die in mehreren Produkten vorkommen, wiederholt angelegt und abgespeichert. Damit handelt es sich im Sinne der Diskussion von Kapitel 8.3.1 um gleiche und nicht identische Lieferanten (Produkte). Um hier eine semantisch korrekte Modellierung zu ermöglichen, sollten Verweise verwendet werden32 . TeilTyp AS ( FünfstelligeZahl, VARCHAR(25), REF(LieferantTyp) MULTISET, REF(ProduktTyp) MULTISET) ... REF IS SYSTEM GENERATED,
CREATE TYPE teilNr teilBez teilLieferant teilProdukt
Der MULTISET-Typkonstruktor erlaubt also, ein Attribut mengenwertig auszulegen. Im Gegensatz zu einem ARRAY ist dabei die Obergrenze der Menge nicht vorgegeben und es existiert auch keine Ordnung auf den Elementen der Menge. Soll eine Menge keine Duplikate enthalten, so ist diese Einschränkung über die Definition der entsprechenden Integritätsbedingung festzulegen33. Auf MULTISETs können die üblichen Mengenoperationen angewendet werden, wobei allerdings im Gegensatz zu diesen Mengenoperationen auf Tabellen etwaige Duplikate vollständig erhalten bleiben, also weder automatisch eliminiert werden noch eliminiert werden können. Zusammenfassung Typkonstruktoren Bisher beruhte das SQL-Datenmodell auf Zeilen, deren Werte atomar oder einwertig waren (single-value). Durch die Einführung des Arrays können nun auch mehrwertige Datenwerte (multi-value) direkt ausgedrückt werden. Mit dem ROW-Typkonstruktor lassen sich zeilenwertige Attribute bzw. Gruppen definieren. Wird eine beliebige Anzahl von zeilenwertigen Werten 32 Es
wird unterstellt, dass Lieferanten und Produkte jeweils in einer eigenen Tabelle abgelegt sind. Ergänzung von UNIQUE — z. B.: teilLieferant MULTISET (REF(LieferantTyp) UNIQUE),
33 durch
8.2 Datentypen und Typkonstruktoren
493
einwertiger Datentyp, -wert:
Inhalt stellt einen atomaren Datenwert dar.
mehrwertiger Datentyp, -wert:
Inhalt besteht aus mehreren (atomaren) Datenwerten vom selben Datentyp.
zeilenwertiger Datentyp, -wert, Gruppe:
Inhalt besteht aus mehreren (atomaren) Datenwerten, wobei die Werte von unterschiedlichen Datentypen stammen können.
Wiederholungsgruppe:
Inhalt besteht aus mehreren (atomaren) Datenwerten vom selben zeilenwertigen Datentyp.
in einem Attribut gespeichert spricht man von einer Wiederholungsgruppe. Sie wird typischerweise über die Typkonstruktoren SET und ROW definiert (also ist eine Wiederholungsgruppe eine SET OF ROW(. . .)). Eine solche Konstruktion kann so nicht explizit im objektrelationalen SQL modelliert werden. Allerdings lässt sie sich eingeschränkt durch die Konstruktion ROW Datentyp ARRAY[. . . ] simulieren. Definition 8.2: Ein-, mehrwertige Datenwerte, Gruppen, Wiederholungsgruppen Die Begriffe in folgender Tabelle legen fest, wie ein Datenwert bzw. die Ausprägung eines Datentyps aufgebaut sein kann. Alle in diesem Kapitel beschriebenen Typkonstruktoren können – allerdings mit den bereits genannten Einschränkungen – orthogonal verwendet werden. Dadurch lassen sich komplex strukturierte Datentypen erzeugen. Eine Ausnahme gilt allerdings weiterhin. In der DB selbst können nach wie vor nur Tabellen abgelegt werden, so dass jedes in der DB abzulegende komplex strukturierte Objekt bzw. Datum mit Hilfe des Zeilenkonstruktors CREATE TABLE definiert werden muss. Achtung 8.1: Das objektrelationale SQL hat die erste Normalform aufgegeben Die in diesem Kapitel diskutierten Typkonstruktoren bedeuten, dass jetzt Attribute gebildet werden können, die nicht mehr atomar sind. Damit hat das objektrelationale SQL das Einhalten der ersten Normalform abgeschafft.
8.2.3
Individualisierte Datentypen (distinct data type)
Bereits SQL-92 erlaubt das Anlegen benutzerdefinierter Wertebereiche (siehe Kapitel 7.2.2.4). Diese unterliegen jedoch nicht den Regeln der strengen Typisierung. Beim Vergleich von Werten benutzerdefinierter Wertebereiche werden diese zunächst auf die Basisdatentypen von SQL-92 zurückgeführt, aus denen sie abgeleitet wurden. Erst dann wird überprüft, ob der Vergleich typkonform ist. Ab SQL:1999 ist dieses Manko beseitigt, da die explizite Spezifikation von individualisierten Datentypen34 (distinct data types) zugelassen ist. Hierbei handelt es sich um einfache Datentypen, die z. B. über Einschränkungen direkt aus den Basisdatentypen von SQL abgeleitet werden. Ein Ableiten aus einem bereits definierten anderen individualisierten 34 Diese Datentypen werden in der Literatur häufig unter dem Begriff benutzerdefinierter Datentyp diskutiert. Wir haben uns für den anderen Namen entschieden, um diese Datentypen besser von den benutzerdefinierten strukturierten Datentyp abgrenzen zu können.
494
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Datentyp ist nicht möglich, was insbesondere auch bedeutet, dass Vererbung nicht anwendbar ist. In Beispiel 8.19 werden die beiden neuen Datentypen EuroTyp und USDollarTyp auf der Grundlage des Basisdatentyps DECIMAL neu eingeführt. Mit SQL:2011 wurde neben der Ableitung neuer individualisierter Datentypen aus den Basisdatentypen auch erlaubt, dass bei der Bildung eines neuen Datentyps Kollektionstypen verwendet werden dürfen (also z. B. ARRAY oder MULTISET). Damit könnte jetzt z. B. der ARRAY-basierte Datentyp budget als individualisierter Datentyp eingeführt werden: budget REAL ARRAY[10] oder als MULTISET-basierte Datentyp: budget REAL MULTISET. Beispiel 8.19: Definition eines individualisierten Datentyps CREATE TYPE CREATE TYPE
EuroTyp USDollarTyp
AS DECIMAL(10, 2) FINAL35 ; AS DECIMAL(10, 2) FINAL;
Unter der Voraussetzung, dass einnahmeEuro und einnahmeUSDollar Attribute vom entsprechenden Datentyp sind, würde ein Vergleich, wie er in Beispiel 8.20 vorgenommen wird, wegen der strengen Typisierung36 zu einem Typfehler führen. Beispiel 8.20: Nicht erlaubter Vergleich WHERE
... einahmeEuro>einahmeUSDollar;
Allerdings ist es weiterhin möglich, einen solchen Vergleich mit Hilfe des CAST-Operators zu ermöglichen. In Beispiel 8.21 wird der Wechselkursunterschied zwischen Euro und US$ in der SET-Anweisung ausgeglichen. SET ist hier im Sinne von „setze“ zu verstehen und hat nichts mit dem gleichnamigen (aber noch nicht eingeführten) Typkonstruktor zu tun. Beispiel 8.21: Erlaubter Vergleich über den CAST-Operator WHERE
... einahmeEuro > CAST(einahmeUSDollar AS EuroTyp); SET einahmeUSDollar = einahmeUSDollar ∗ CAST(0,75 AS USDollarTyp);37
Es sei noch angemerkt, dass die individualisierten Datentypen echte Datentypen sind, also auch mit (zusätzlichen) datentypspezifischen Operationen ausgestattet werden können. Dies kann auf zweierlei Art und Weise geschehen. Einerseits können die Operationen des Basisdatentyps neu definiert werden (überschrieben werden) und andererseits können neue Operationen eingeführt werde. Wie dies geschieht, wird bei der Behandlung der benutzerdefinierten strukturierten Datentypen vorgestellt. 35 Das Schlüsselwort FINAL besagt, dass der definierte Datentyp nicht die Basis für eine weitere Spezialisierung bilden kann, was allerdings wegen fehlender Unterstützung der Vererbung bei individualisierten Datentypen schon automatisch gegeben ist. Hierdurch wird nur sichergestellt, dass individualisierte und komplex strukturierte Datentypen (siehe später) syntaktisch gleich behandelt werden. 36 Der Vergleich auf Typgleichheit zweier Typen geschieht über deren Namen. Nur wenn der identisch ist, sind die Typen auch identisch. 37 Hier wird angenommen, dass 1,– US$ im Wechselkurs 0,75 Euro entspricht.
8.2 Datentypen und Typkonstruktoren
8.2.4
495
Benutzerdefinierte strukturierte Datentypen bzw. benannte Zeilentypen
Aufbauend auf den gegenwärtigen Stand der Technik gab es in der SQL-Standardisierungskommission massive Bestrebungen, die objektorientierten Konzepte möglichst vollständig in die neue SQL-Version zu integrieren. Der anfängliche Enthusiasmus wurde aber schnell durch die Realität eingeholt, ließen sich doch die sehr mächtigen objektorientierten Konzepte und das eher einfache relationale Modell nicht so einfach verheiraten. Insbesondere das Konzept der Kapselung (encapsulation) bereitete einige Schwierigkeiten, da es verlangt, dass auf Objekte nur über die ihnen zugeordneten Funktionen zugegriffen werden darf. Dies schließt den in DBS üblichen direkten Zugriff auf deren Datenstruktur aus. Nachdem die ursprünglichen Konzepte Ende des Jahres 1995 verworfen wurden, setzte sich eine etwas abgeschwächte Variante von Objektorientierung durch, die im Wesentlichen durch sogenannte benutzerdefinierte strukturierte Datentypen, auch benannte Zeilentypen (named row types) genannt, umgesetzt wird. Der Einfachheit halber werden wir in diesem Kapitel von Zeilentypen reden, auch wenn damit i. d. R. benannte Zeilentypen gemeint sind. Die Definition eines Zeilentyps entspricht im Wesentlichen der Definition eines abstrakten Datentyps. Ein Datentyp wird ausschließlich durch sein Verhalten, d. h. durch die ihm zugeordneten Methoden38 beschrieben. Die Datenstruktur selbst wird gekapselt. Sie ist daher von außen nicht sichtbar. Das Überraschende ist, dass das objektrelationale SQL die Definition eines abstrakten Datentyps weitestgehend unterstützt, also insbesondere auch den ausschließlichen Zugriff über Methoden. Darauf werden wir etwas später eingehen. Zunächst wollen wir uns ganz konventionell der Definition der Datenstruktur eines Zeilentyps widmen. Definition 8.3: Benannte Zeilentypen bzw. benutzerdefinierte strukturierte Datentypen Ein über den CREATE TYPE-Befehl angelegter zeilenwertiger Datentyp heißt benannter Zeilentyp bzw. benutzerdefinierter strukturierter Datentyp. Definition 8.4: Typisierte Tabelle Eine Tabelle heißt typisiert, falls sie auf der Basis eines benannten Zeilentyps definiert wurde. Typisierte Tabellen ähneln den Objekten/Klassen in objektorientierten Systemen. Durch die Einführung des CREATE TYPE-Befehls besteht jetzt die Möglichkeit, die Zeilentypdefinition sauber von der Erzeugung eines Containers für diesen Zeilentyp, also der Tabellenanlage zu trennen. Damit ist es möglich, explizit mehrere Tabellen vom selben Typ anzulegen. Vom Grundsatz ähnelt der CREATE TYPE-Befehl dem CREATE TABLE-Befehls des konventionellen SQLs. Im Wesentlichen können die zu Grunde liegende (allerdings aus Sicht des Benutzers gekapselte) Datenstruktur also Attribute und deren Datentypen, die auf den Instanzen dieses Typs ausführbaren Methoden und, als einzige Integritätsbedingungen, ein Default für Attribute festgelegt werden. Alle anderen spalten- uind tabellenspezifischen Integritätsbedingungen müssen bei der Spezifikation einer konkreten Tabelle angegeben werden. Beispiel 8.22 zeigt, wie Zeilentyp- und Tabellendefinition zusammenspielen. 38 Methoden
werden weiter unten noch genauer eingeführt.
496
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Grundsätzlich können alle bekannten Integritätsbedingungen auf Tabellenebene definiert werden. Spaltenorientierte Integritätsbedingungen können auf mehrere Arten und Weisen angelegt werden. Einerseits über die CHECK-Klausel, andererseits gibt es aber auch ein neues Sprachkonstrukt WITH OPTIONS . Grundsätzlich können nach wie vor auch die Schlüssel/Fremdschlüssel-Bedingung spezifiziert werden. Nur macht dieses Konzept keinen Sinn mehr, da Verweise direkt über die REF-Typkonstruktor modelliert werden können. Eine Modellierung über die REFRENCESKlausel ist grundsätzlich noch möglich39 , aber kein Zeichen einer guten Modellierung. Beispiel 8.22 bringt ein Beispiel, wie Zeilentyp- und Tabellendefinition zusammenspielen. Beispiel 8.22: Definition von Zeilentypen und daraus abgeleiteten typisierten Tabellen Als Basis dieses Beispiels soll die ursprüngliche Definition der Tabelle Produkt dienen: CREATE TABLE Produkt ( produktNr FünfstelligeZahl PRIMARY KEY, produktBez VARCHAR(25) UNIQUE NOT NULL, produktTyp VARCHAR(25) NOT NULL, stueckKosten PositiveReal NOT NULL, nettoPreis PositiveReal NOT NULL) CONSTRAINT VerlustVermeidung CHECK (nettoPreis > (stueckKosten ∗ 1,5)); Soll diese Tabelle zunächst als Typ spezifiziert werden, könnte das wie folgt aussehen: CREATE TYPE ProduktTyp AS ( produktNr FünfstelligeZahl, produktBez VARCHAR(25), produktTyp VARCHAR(25), stueckKosten PositiveReal, nettoPreis PositiveReal) REF IS SYSTEM GENERATED,
Die Anlage einer entsprechenden Tabelle, die der obigen entspricht, sähe dann wie folgt aus: CREATE TABLE Produkt OF ProduktTyp ( REF IS ProduktOID SYSTEM GENERATED, CONSTRAINT NotNullSpalten CHECK (NOT NULL produktBez AND NOT NULL produktTyp AND NOT NULL stueckKosten AND NOT NULL nettoPreis), CONSTRAINT UniqueSpalten CHECK (UNIQUE produktBez), CONSTRAINT VerlustVermeidung CHECK (nettoPreis > (stueckKosten ∗ 1,5))); 39 Die REFERENCES-Klausel ist quasi der Ersatz für die alte FOREIGN KEY-Klausel, die so nicht mehr im objektrelationalem SQL einsetzbar ist. Die Syntax ist REFERENCES . .
8.2 Datentypen und Typkonstruktoren
497
oder CREATE TABLE Produkt OF ProduktTyp ( REF IS ProduktOID SYSTEM GENERATED, produktBez WITH OPTIONS NOT NULL, produktTyp WITH OPTIONS NOT NULL, stueckKosten WITH OPTIONS NOT NULL, nettoPreis WITH OPTIONS NOT NULL, produktBez WITH OPTIONS UNIQUE, CONSTRAINT VerlustVermeidung CHECK (nettoPreis > (stueckKosten ∗ 1,5))) Mit der obigen Definition des benannten Zeilentyps ProduktTyp ist man noch nicht fertig. Zeilentypen sind schon sehr dicht an der üblichen Definition im objektorientierten Umfeld von Objekten dran. Deshalb ist die oben angegebene Datenstruktur aus Sicht der Benutzer gekapselt. Auf Instanzen einer Tabelle wird ausschließlich über Methoden zugegriffen. Diese Methodendefinition ist in dem obifen Beispiel allerdings noch weggelassen. Zusätzlich werden, wie bei abstrakten Datentypen üblich, auch (eine Art) Objektidentität und Vererbung unterstützt. Beide Konzepte werden in eigenen Abschnitten später besprochen. Prozeduren und Funktionen SQL:2011 unterstützt das Einbinden von Routinen in unterschiedlichen Formen. Prozeduren und Funktionen werden ebenso unterstützt wie Methoden. Letztere sind das, was aus objektorientierter Sicht wichtig ist. Da die Diskussion von Prozeduren und Funktionen aber zum Verständnis von Methoden wichtig ist, sollen diese zunächst hier eingeführt werden, auch wenn sie wenig mit objektorientierten Konzepten zu tun haben. Methoden werden dann intensiver im Zusammenhang mit der Datenabstraktion in Kapitel 8.3.4 diskutiert. Prozeduren und Funktionen Betrachtet man Programmiersprachen, so boten diese schon immer die Möglichkeit, vorgefertigte Routinen aus so genannten Programmbibliotheken in ein Programm einzubinden, wodurch die eigentliche Programmierung erheblich erleichtert werden kann. Im alten Standard ist mit den Datenbankprozeduren (stored procedures) bereits der Anfang gemacht worden. Der neue Standard hat dieses Einbinden von in diversen Programmiersprachen geschriebenen Routinen noch weiter verfeinert. Damit wird dem Datenbankprogrammierer die Möglichkeit geboten, auf die mit den Programmiersprachen kommenden Programmbibliotheken zurückzugreifen. Das reduziert den Programmier- und Testaufwand nicht nur erheblich, sondern erlaubt es auch, auf eine Sprache zurückzugreifen, die der Programmierer entsprechend gut kennt. Üblicherweise werden mindestens Ada, C, C++, Cobol, Fortran, Java und PL/1 unterstützt (dies sieht auch der Standard vor). Allerdings bietet diese vollständige Öffnung auch einige Nachteile, da in ihrer Semantik dem DBMS unbekannte Routinen nur sehr global bis überhaupt nicht optimierbar sind. Zudem kann nicht ausgeschlossen werden, dass sie, z. B. wegen fehlerhafter Programmierung, den Datenbankinhalt verfälschen oder sogar zerstören können. SQL:2011 unterstützt das Einbinden von Routinen in das DBS auf unterschiedliche Art und Weise. Zunächst einmal wird, wie bisher auch in SQL-92, das Integrieren, Verwalten und
498
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Ausführen von beliebigen Prozeduren und Funktionen innerhalb des DBS ermöglicht. Solche Routinen entsprechen den bereits bekannten Datenbankprozeduren (stored procedures), d. h. sie stellen allgemeine Routinen dar, die im DBS ausgeführt werden, aber nicht speziellen Datentypen zugeordnet sind. Der Begriff Routine wird im Folgenden als Oberbegriff für Prozeduren und Funktionen verwenden. Eine Prozedur ist eine Routine, bei deren Schnittstellenbeschreibung zwischen Eingabe- (IN), Ausgabe- (OUT) und Ein- und Ausgabeparameter (INOUT) unterschieden wird (siehe Beispiel 8.23 a.). Eine Funktion ist dagegen eine Routine, die nur Eingabeparameter besitzt (weshalb das Schlüsselwort IN entfallen kann) und höchstens einen Rückgabewert liefert, der im Anschluss an die Parameterspezifikation über das Schlüsselwort RETURNS angehangen wird (siehe Beispiel 8.23 b.). Definition 8.5: Prozedur Eine Prozedur ist eine nicht an einen bestimmten Datentyp gebundene Routine, die folgende Eigenschaften aufweist: a. Die Parameterliste kann eine beliebige Anzahl von Eingabe- (IN), Ausgabe- (OUT) und Ein- und Ausgabeparametern (INOUT) aufweisen, wobei die Parameter von einem beliebigen (bekannten) Datentyp sein können. b. Die Prozedur kann überladen werden, allerdings nur in der Form, dass derselbe Prozedurname mit einer unterschiedlichen Anzahl von Parametern verwendet wird. Die gleiche Anzahl von Parametern, wobei diese unterschiedliche Typen besitzen, reicht nicht zur Unterscheidung (es handelt sich also um eine verschärfte Form von Definition 8.7). c. Der Aufruf einer Prozedur erfolgt über die CALL Prozedurschnittstelle-Anweisung.
Definition 8.6: Funktion Eine Funktion ist eine nicht an einen bestimmten Datentyp gebundene Routine, die folgende Eigenschaften aufweist: a. Die Parameterliste besteht nur aus einer beliebigen Anzahl von Eingabeparametern, wobei das Schlüsselwort IN nicht notwendig ist. Zudem besitzt jede Funktion genau einen Ausgabewert, dessen Typ in der RETURNS-Klausel spezifiziert wird. b. Die Prozedur kann überladen werden, wobei es erlaubt ist, dass sie Anzahl der Parameter gleich ist, diese aber unterschiedlichen Typs sind. Die Bedingungen von Definition 8.7 müssen aber erfüllt sein. c. Der Aufruf einer Funktion erfolgt durch den Aufruf ihrer Schnittstelle. Deshalb und weil sie genau einen Wert zurückliefert, kann eine Funktion wie eine Spalte innerhalb einer Anfrage verwendet werden.
8.2 Datentypen und Typkonstruktoren
499
Definition 8.7: Überladen Eine Routine R2 überlädt eine andere Routine R1, falls sie a. den selben Namen wie R1 hat und b. entweder eine andere Anzahl von Parametern besitzt oder dieselbe Anzahl, wobei dann aber der Datentyp mindestens eines Parameters unterschiedlich (im Sinne von nicht kompatibel) zu dem entsprechenden Parameter in R1 sein muss. Da die Implementierung der Routine eindeutig über die Anzahl bzw. den Typ der Parameter bestimmt werden kann, kann die korrekte Methodenimplementierung bereits zur Übersetzungszeit bestimmt und an den Methodenaufruf gebunden werden. Ein dynamisches Binden40 ist deshalb nicht notwendig. SQL:2011 erlaubt das Entwerfen von Routinen, die innerhalb des DBS angelegt und vollständig in SQL geschrieben werden. Dann ist neben der Schnittstelle der Routine deren Implementierung anzugeben (Body; siehe Beispiel 8.23 a. und b.). Die durch SQL unterstützen Programmierkonstrukte wurden weiter ergänzt, so dass SQL:2011 alle in Programmiersprachen üblichen Programmierkonstrukte anbietet. Damit ist SQL:2011 nicht mehr nur eine Anfragesprache, sondern eine vollständige Programmiersprache. In SQL geschriebene Routinen haben den Vorteil, dass ihre Korrektheit unter bestimmten Voraussetzungen garantiert werden kann und dass sie erheblich besser optimiert werden können. Zudem ist keine Abbildung des Datenmodells der Programmiersprache auf das Datenmodell von SQL notwendig, weshalb der häufig mit Semantikverlust verbundene „impedance mismatch“ vermieden wird. Neben den internen Routinen werden sogenannte externe Routinen unterstützt, wobei die Tatsache, dass die Routine extern ist, impliziert, dass es sich um eine Prozedur handelt. Eine externe Prozedur kann in einer der vom DBMS unterstützten „normalen“ Programmiersprachen programmiert werden. Sie ist außerhalb des DBS abgelegt. Dem DBS muss deshalb mindestens mitgeteilt werden, in welcher Sprache die Routine geschrieben wurde (über die LANGUAGE Programmiersprache-Klausel) und wo sie gespeichert ist (über die EXTERNAL NAME Speicherort-Klausel; siehe Beispiel 8.23 c.). Neben diesen Merkmalen können u. a. noch die folgenden Klauseln spezifiziert werden: • PARAMETER STYLE-Klausel Sie legt fest, von welchem Typ die Parameter der Routine sind. Es gibt zwei Varianten. Entweder sind die Parameter alle von einem Typ, der im SQL-Schema definiert wurde bzw. dort bekannt ist (Basisdatentyp) (Ausprägung: SQL) oder eben nicht (Ausprägung: GENERAL). • (NOT) DETERMINISTIC-Klausel Ist das Ergebnis der Ausführung der Routine immer identisch, wenn unter den gleichen Bedingungen die gleichen Eingabeparameter gewählt werden, liefert die Routine ein deterministisches Ergebnis, andernfalls ein nicht-deterministisches. Die Klausel erlaubt, diese Aussage dem DBS mitzugeben. 40 Dieser
Begriff wird weiter unten unter Methoden noch genauer eingeführt.
500
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
• SQL-Klausel In dieser Klausel wird spezifiziert, wie die Implementierung der Routine aussieht. Enthält sie kein SQL (Ausprägung: NO SQL), zumindest einige SQL-Anweisungen (Ausprägung: CONTAINS SQL), liest (Ausprägung: READS SQL DATA) oder modifiziert sie SQL-Daten (Ausprägung: MODIFIES SQL DATA). Die genauen Abgrenzungen der letzten drei Ausprägungen werden dem Geschmack des jeweiligen Verantwortlichen für den SQL-Dialekt überlassen. Man beachte, dass diese Klausel nur Sinn macht bzw. Mehrwert liefert, falls in der LANGUAGE-Klausel eine andere Sprache als SQL deklariert ist. • NULL-Klausel In dieser Klausel wird festgelegt, ob das Ergebnis der Ausführung der Routine die Nullmarke liefert, falls mindestens einer der Eingabeparameter der Nullmarke entspricht (Ausprägung: RETURNS NULL ON NULL INPUT), oder ob das Ergebnis auch dann von der Ausführung der Routine abhängt (Ausprägung: CALLED ON NULL INPUT).
Beispiel 8.23: (Schnittstelle von) Funktionen und Prozeduren Die folgenden Routinen basieren auf dem in Beispiel 8.14 eingeführten Zeilentyp KontoTyp. Aufgabe der Routinen ist es, den aktuellen Gesamtkontostand über alle Konten eines Kunden zu ermitteln. Falls er negativ ist oder die Kundennummer und/oder das Konto(IBAN) nicht existiert, wird 0 ausgegeben. a. Formulierung über eine Prozedur: CREATE PROCEDURE GesKtoStand (IN kundenId INTEGER, OUT gesamtKtoStand DECIMAL(15,2)) /* Schnittstellendefinition BEGIN /* Prozedurkörper gesamtKtoStand := 0; SELECT SUM(kontoStand) INTO gesamtKtoStand FROM Konto WHERE kunde→kundenNr= kundenId GROUP BY kunde→kundenNr; IF gesamtKtoStand < 0 THEN gesamtKtoStand := 0 END IF; END; b. Formulierung über eine Funktion: CREATE FUNCTION GesKtoStand (KundenId INTEGER) RETURNS DECIMAL(15,2) BEGIN DECLARE gesamtKtoStand DECIMAL(15,2); gesamtKtoStand := 0; SELECT SUM(kontoStand) INTO gesamtKtoStand FROM Konto
/* Schnittstellendefinition /* Funktionskörper
8.2 Datentypen und Typkonstruktoren
501
WHERE kunde→kundenNr = KundenId GROUP BY kunde→kundenNr; IF gesamtKtoStand < 0 THEN gesamtKtoStand := 0 END IF; RETURN gesamtKtoStand; END; c. Realisierung über eine in einer beliebigen Programmiersprache (hier: Java) geschriebenen Prozedur (hier: KtoStandProc), die im unter EXTERNAL NAME angegebenen Verzeichnis abgelegt ist. CREATE PROCEDURE GesKtoStand (IN iban INTEGER, OUT gesamtKtoStand DECIMAL(15,2)) /* Schnittstellendefinition LANGUAGE Java EXTERNAL NAME geheim\strengGeheim\inAllerMunde\KtoStandProc.jar; Beispiele, wie Routinen aufgerufen bzw. verwendet werden können, liefert Beispiel 8.24. Die Verwendung der Funktion in Beispiel 8.24 b. unterscheidet sich nicht von der Verwendung einer Spalte als Operanden. Wie beim Arbeiten mit einer Spalte wird auch bei einer Funktion genau ein Wert eines Datentyps zurückgeliefert. Das ist der Grund, weshalb sie an jeder Stelle verwendet werden kann, an der auch eine Spalte verwendet werden darf. Und das ist der Grund, weshalb zwischen Prozeduren, die auch mehrere Ausgabeparameter besitzen dürfen, und Funktionen unterschieden wird. Deshalb wäre es ungeschickt, die genau einen Ausgabeparameter liefernde Routine GesKtoStand als Prozedur zu deklarieren, wie es in Beispiel 8.23 a. geschehen ist. Funktionen können wie Spalten innerhalb von SQL-Anfragen verwendet werden. Auf Prozeduren trifft dies nicht zu. Sie können nur losgelöst von einer Anfrage aufgerufen werden, beispielsweise in eingebettetem SQL-Code.
Beispiel 8.24: Aufruf von Funktionen und Prozeduren a. Aufruf der Prozedur GesKtoStand, wobei KundePar und GesamtKtoStandPar Variablen vom entsprechenden Parametertyp sind: CALL GesKtoStand(KundePar, GesamtKtoStandPar); b. Formulierung über eine Funktion, wobei die Funktion in eine Anfrage eingebunden ist, in der alle Kunden ermittelt werden, deren Einlage über alle ihre Konten 10.000,– C überschreitet. SELECT FROM WHERE
kunde → kundenNr, kunde → kundenName, kunde → kundenVorname Konto AS Kto GesKtoStand(Kto.kunde.kundenNr) > 10000;
502
8.3
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Objektorientierte Konzepte in SQL:2011
Objektorientierte Konzepte und Systeme haben in den letzten Jahrzehnten einen unübersehbaren Siegeszug angetreten und spielen heute in der Softwareentwicklung eine dominante Rolle. Kein Wunder also, dass sie auch die weitere Entwicklung von DBMS ganz entscheidend beeinflusst haben. Während mit den objektorientierten DBMS eine neue Generation von DBMS mit einem neuen, sehr mächtigen Datenbankmodell entstanden ist, haben sich die Anbieter relationaler DBMS bemüht, die neuen Konzepte möglichst weitgehend und harmonisch zu integrieren. Diese Integration vollzog sich vor allem mit dem SQL:1999 Standard. Genau genommen ist die Integration der sogenannten objektorientierten Konzepte der entscheidende Beitrag diese neuen Standards. Im Folgenden sollen zunächst die wesentlichen Merkmale der Objektorientierung kurz erläutert werden, um dann zu erkunden, inwieweit das objektrelationale SQL diese Konzepte erfolgreich adaptiert hat. 1. Komplexe Objekte Ein Objekt bildet eine aus Sicht der Anwendung zusammengehörige (komplexe) Entität der Realwelt. Die ein Objekt beschreibenden Attribute sind daher oft komplex strukturiert, d. h. wurden (rekursiv) aus einfacheren Komponenten zusammengebaut. Ein Attribut kann auch (einen Verweis auf) ein Objekt oder eine Menge von (Verweisen auf) Objekte(n) verkörpern. 2. Objektidentität Jedes Objekt besitzt eine Identität, also etwas, was das Objekt eindeutig auf Lebenszeit identifiziert und zwar unabhängig von anderen Faktoren, wie seinem Inhalt oder seinem Speicherungsort. 3. Datentypen / Klassen Objekte mit demselben Aufbau und Verhalten (mit derselben Menge an Operationen) werden zu Klassen zusammengefasst, wodurch der Aufbau und das Verhalten jeder Instanz einer Klasse durch den Typ der Klasse festgelegt ist. 4. Datenabstraktion / Kapselung Von Datenabstraktion bzw. Kapselung spricht man, wenn ein Objekt nicht durch die ihm zu Grunde liegende Datenstruktur beschrieben wird, sondern einzig und allein durch sein Verhalten. Das Verhalten wird bestimmt durch die Methoden, die auf dem Objekt anwendbar sind. Sie stellen dessen Schnittstelle nach außen dar. Die Datenstruktur des Objektes und die Implementierung der Methoden sind gekapselt, d. h. nicht von außen sichtbar. Dies schließt insbesondere ein, dass von außen nicht direkt auf die Datenstruktur zugegriffen werden kann. 5. Vererbung Vererbung liegt vor, falls aus einer bereits bestehenden Klasse (Oberklasse) eine speziellere Klasse (Unterklasse) abgeleitet werden kann, indem die Unterklasse alle Attribute und Methoden der Oberklasse erbt und zusätzlich eigene hinzufügen oder bestehende überschreiben kann.
8.3 Objektorientierte Konzepte in SQL:2011
503
6. Polymorphismus Von Polymorphismus spricht man immer dann, wenn eine Operation auf Objekte unterschiedlicher Klassen angewendet werden kann, was einschließt, dass sie in unterschiedlichen Klassen unterschiedliche Implementierungen besitzen darf. Im Folgenden werden diese Punkte einzeln in der oben angegebenen Reihenfolge diskutiert. Eine Ausnahme bildet nur Punkt 4, der sehr Kurz abgehandelt werden kann und deshalb als erstes behandelt wird. Die benutzerdefinierten strukturierten Datentypen stellen die in diesem Punkt angesprochenen Typen dar, während typisierte Tabellen als das Gegenstück zu Klassen angesehen werden können.
8.3.1
Komplexe Objekte
In welcher Form komplexe Datenstrukturen durch SQL:2011 unterstützt werden, wurde schon hinreichend in den Kapiteln 8.2.2 bis 8.2.4 diskutiert. Die Diskussion hier beschränkt sich deshalb auf Beziehungsarten zwischen Vaterobjekten und eingebundenen Objekten. Bei der Anlage eines benannten Zeilentyps bzw. einer Tabelle sind einige konzeptuelle Herausforderungen zu bewältigen, da es verschiedene Möglichkeiten gibt, denselben Sachverhalt zu modellieren. Die Adresse eines Kunden kann beispielsweise wie folgt modelliert werden: a. Als Menge von Attributen, wie im ursprünglichen Schema geschehen (siehe Kapitel 7.2.7), b. Als zeilenwertige Spalte in zwei unterschiedlichen Formen (eingebundener Zeilentyp, siehe Beispiel 8.9 b.; explizites zeilenwertiges Attribut, siehe Beispiel 8.10). c. Als Verweistyp, wenn man z. B. alle Adressen in einer eigenen Tabelle ablegen möchte (siehe Beispiel 8.13 b.). d. In verschiedenen Varianten eines Arrays (siehe Beispiel 8.5, b. und Beispiel 8.13, b.). Es stellt sich damit die Frage, welche Variante in welcher Situation gewählt werden sollte. Zu deren Beantwortung sollen zunächst die Begriffspaare abhängig/unabhängig und gemeinsam/exklusiv diskutiert werden. Komplexe Objekte zeichnen sich dadurch aus, dass sie eine tief geschachtelte, i. d. R. baumartige Struktur besitzen. Auf der obersten Ebene gibt es eine Menge von Attributen, die allerdings nicht atomar sein müssen, sondern selber wieder (rekursiv) eine komplexe Struktur besitzen können. Solche komplexen Attribute sollen im Folgenden Unterobjekte des Vaterobjektes genannt werden. Die obigen Begriffspaare legen nun fest, wie Objekte im DB-Umfeld gesehen werden. Da in einer Datenbank immer nur ein Realweltausschnitt abgelegt werden kann, müssen die dort herrschenden „Gesetze“ nicht unbedingt in der Realwelt anzutreffen sein.
504
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Ein eingebetteter Zeilentyp (wie kundenAdresse oder nameKunden in Beispiel 8.10 bzw. kundenAdresse in Beispiel 8.9 b.) stellt ein so genanntes abhängiges Unterobjekt dar. Das ist ein Objekt, das Bestandteil eines übergeordneten Objektes ist (hier vom Typ KundenTyp) und dessen Lebensdauer direkt mit der Lebensdauer des Vaterobjektes verknüpft ist. Wird dieses gelöscht, wird auch das Unterobjekt gelöscht. Kann ein Objekt hingegen auch existieren, wenn das (letzte) Vaterobjekt, in das es eingebettet ist, gelöscht wird, so ist es ein unabhängiges Objekt. Dies trifft beispielsweise auf das Unterobjekt kunde in Beispiel 8.13 zu. Wird das letzte Konto eines bestimmten Kunden gelöscht, so bleibt der Kunde zunächst einmal erhalten, da er beispielsweise noch von der Abteilung Kundenbeziehungen bearbeitet werden soll. Definition 8.8: Abhängiges / unabhängiges (Unter)objekt Ein (Unter)objekt heißt abhängig von einem Vaterobjekt, wenn es nur existieren kann, solange es in mindestens ein Vaterobjekt eingebunden ist. Andernfalls heißt es unabhängig. Kommen wir auf unsere Unternehmensdatenbank und deren Lagertabelle zurück. Ist Lager hier im Sinne eines Lagers für Massenprodukte zu verstehen, so können Produkte beispielsweise in verschiedenen Lagern gelagert sein41 , also Unterobjekt mehrerer Vaterobjekt vom Typ ProduktLagertIn sein. Hier handelt es sich dann um ein gemeinsames Unterobjekt. Vertreiben Sie aber gebrauchte PKW, so kann ein PKW nur in genau einem Lager stehen. In diesem Fall ist der PKW ein exklusives Objekt. Definition 8.9: Gemeinsames/exklusives (Unter)objekt Ein (Unter)objekt heißt exklusiv, falls es entweder in kein Vaterobjekt eingebunden ist, also nur über einen direkten Zugriff auf das Objekt selbst erreicht werden kann, oder exakt in ein Vaterobjekt eingebunden ist und auch nur über dieses erreicht werden kann. Andernfalls heißt es gemeinsam. Eine zweite Frage, die sich bei Beziehungen zwischen Objekten stellt, ist, von welcher Granularität die Beziehung ist: handelt es sich um eine 1:1-, 1:n- oder n:m-Beziehung. Im konventionellen relationalen Datenbankmodell kann Erstere durch direkte Einbindung in die Tabelle oder durch Ablage des Unterobjektes in einer zweiten Tabelle modelliert werden. Die 1:n-Beziehung muss von der zweiten Tabelle (für die n-Datensätze) über eine Fremdschlüsselbeziehung realisiert werden, während bei der dritten Beziehungsart eine zusätzliche Beziehungstabelle zwischen der n- und der m-Tabelle eingefügt werden muss42 . Das Auswerten von Beziehungen ist dementsprechend von links nach rechts immer aufwändiger. Ab der 1:n-Beziehung müssen Verbundoperationen ausgeführt werden. Im Folgenden sollen die einzelnen Typkonstruktoren im Lichte der obigen Dimensionen diskutiert werden. 41 Hier ist nicht das konkrete einzelne Produkt interessant, sondern nur die Tatsache, dass es solche Produkte gibt. Wenn Sie ein Fachbuch für das Selbststudium kaufen, wollen Sie in der Regel kein spezifisches Buch erwerben, sondern nur ein beliebiges (zufälliges) Exemplar dieses Buches. 42 siehe hierzu Kapitel 4.2.1
8.3 Objektorientierte Konzepte in SQL:2011
505
ROW-Typkonstruktor und benannte Zeilentypen Über den ROW-Typkonstruktor und über ein mit Hilfe eines benannten Zeilentyps definiertes Attribut kann ein einzelnes Unterobjekt in genau ein Vaterobjekt eingebunden werden. Allerdings ist zu beachten, dass diese Modellierung nur dann vorteilhaft ist, falls eine eingebettete Zeile aus Sicht des zu Grunde liegenden Realweltausschnittes als abhängiges Unterobjekt angesehen werden kann, das zudem nur exklusiv für dieses Vaterobjekt zur Verfügung stehen soll. Beispielsweise erfüllt die Konstruktion von Beispiel 8.11 diese Bedingung nicht, da zu erwarten ist, dass ein Zulieferer mehrere Teile liefert. Von daher würden die Zuliefererdaten in jedem dieser Datensätze zu wiederholen sein, mit den bekannten Problemen beim Update43 . Seitdem mit SQL:2014 das MULTISET unterstützt wird, kann durch Kombination mit dem ROW-Typkonstruktor ein Attribut wiederum eine Relation darstellen, womit sogenannte geschachtelte Relationen modelliert werden können (siehe Beispiel 8.17). Aus dem oben Gesagten folgt, dass der ROW-Typkonstruktor für sich genommen zunächst einmal nicht unbedingt die Datenmodellierungsmächtigkeit von SQL erhöht, da er sich immer auf eine etwas unübersichtlichere flachgeklopfte Definition einer Tabelle zurückführen lässt. Er erleichtert allerdings die Lesbarkeit eines Schemas. REF-Typkonstruktor Über den REF-Typkonstruktor kann ein Objekt in ein Vaterobjekt eingebunden werden. Allerdings kann nicht festgelegt werden, dass das eingebundene Objekt exklusiv ist. Es handelt sich vielmehr um ein gemeinsames Unterobjekt. Auch besteht keine Möglichkeit, zu definieren, dass das eingebundene Unterobjekt gelöscht werden soll, falls es zu keinem Vaterobjekt mehr in Beziehung steht. Insgesamt erlaubt der REF-Typkonstruktor also die Modellierung eines unabhängigen, gemeinsamen Unterobjekts. Zwar kann aus Sicht des Vaterobjektes über einen Verweis auch nur eine 1:1-Beziehung modelliert werden, aber aus umgekehrter Sicht handelt es sich um eine 1:n-Beziehung, da das eingebundene Objekt auch in andere Vaterobjekte eingebunden sein kann. Dies steht im Gegensatz zu eingebetteten Zeilentypen, bei denen im Höchstfall (zufällige) Gleichheit von Werten vorliegen kann. Über Verweistypen lässt sich hingegen Identität modellieren. Damit ist sichergestellt, dass alle Quellen, die auf das (identische) Datum verweisen, auch immer dieselben Daten zu sehen bekommen. ARRAY-Typkonstruktor Ein Array ist immer dann nützlich, falls die Ausprägung eines Attributs nicht durch einen Wert, sondern durch eine nach oben begrenzte Menge von gleichartigen Werten zu beschreiben ist. Beispiel 8.5 zeigt einige gute und typische Einsatzmöglichkeiten für Arrays. Wegen der unterstützten Orthogonalität lassen sich auch Arrays definieren, deren Datentyp auf einen mit Hilfe von Zeilen- oder Verweistypen spezifizierten Datentyp beruht. Dann gelten die unter Zeilentyp und Verweistyp (Modellierung von unabhängigen gemeinsamen Unterobjekten) gemachten Aussagen, wobei jetzt limitierte 1:n- und n:m-Beziehungen nachgebildet werden können (siehe Beispiel 8.25). 43 Alle
den Lieferanten betreffenden Zeilen aus Liefert müssten ermittelt und geändert werden!
506
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Beispiel 8.25: N:m-Beziehung, nachgebildet über Arrays Basis dieses Beispiels ist die n:m-Beziehung ArbeitetAn zwischen Abteilung und Produkt. Durch sie wird dokumentiert, dass ein Produkt von mehreren Abteilungen in Zusammenarbeit entwickelt werden kann, dass andererseits aber jede Abteilung auch an mehreren Produkten arbeitet. Nehmen wir einmal an, dass eine Abteilung an maximal 20 Produkten arbeitet und ein Produkt in der Kooperation von höchstens fünf Abteilungen entwickelt wird. Dann kann die n:m-Beziehung wie folgt direkt über Verweistypen und Arrays modelliert werden: CREATE TYPE AbteilungTyp AS ( abteilungsNr DreistelligeZahl, abteilungsName VARCHAR(25), budget PositiveReal, mitarbeiterZahl SMALLINT, arbeitetAnProdukt REF(ProduktTyp) ARRAY[20]) REF IS SYSTEM GENERATED,
CREATE TYPE ProduktTyp AS ( produktNr FünfstelligeZahl, produktBez VARCHAR(25), produktTyp VARCHAR(25), stueckKosten PositiveReal, nettoPreis PositiveReal, wirdBearbeitetVon REF(AbteilungTyp) ARRAY[5]) REF IS SYSTEM GENERATED,
CREATE TABLE Abteilung OF AbteilungTyp ( , REF IS AbteilungOID SYSTEM GENERATED, CONSTRAINT NotNullSpalten CHECK (NOT NULL produktBez AND NOT NULL produktTyp AND NOT NULL stueckKosten AND NOT NULL nettoPreis), CONSTRAINT UniqueSpalten CHECK (UNIQUE abteilungsName), CONSTRAINT MitarbeiterCheck CHECK (VALUE ≥ 0), CONSTRAINT BudgetKontrolle CHECK ((budget/mitarbeiterZahl) BETWEEN 1000 AND 10000), CONSTRAINT BudgetHöhe CHECK (VALUE BETWEEN 100000 AND 10000000),
8.3 Objektorientierte Konzepte in SQL:2011
507
arbeitetAnProdukt WITH OPTIONS SCOPE Produkt REFERENCES ARE CHECKED ON DELETE RESTRICT); CREATE TABLE Produkt OF ProduktTyp ( , REF IS ProduktOID SYSTEM GENERATED, CONSTRAINT NotNullSpalten CHECK (NOT NULL produktBez AND NOT NULL produktTyp AND NOT NULL stueckKosten AND NOT NULL nettoPreis), CONSTRAINT UniqueSpalten CHECK (UNIQUE produktBez), CONSTRAINT VerlustVermeidung CHECK (nettoPreis > (stueckKosten ∗ 1,5)), wirdBearbeitetVon WITH OPTIONS SCOPE Abteilung REFERENCES ARE CHECKED ON DELETE CASCADE); Die Frage, ob ein Unterobjekt exklusiv oder gemeinsam modelliert werden soll, ist eine wichtige Frage die allerdings nicht immer zweifelsfrei beantwortet werden kann. Als Beispiel möge die Adresse von Studenten dienen. An normalen deutschen Universitäten würde man Adresse als abhängiges, exklusives Unterobjekt modellieren, also mit Hilfe eines ROWTypkonstruktors oder über die Einbindung eines benannten Zeilentyps (siehe Beispiel 8.26 a.). An den Campusuniversitäten in Großbritannien oder den USA, wo es auf dem Campus eine Anzahl von Studentenwohnheimen gibt, in denen fast alle Studenten wohnen, könnte man jedoch auch darüber nachdenken, die Adressen als gemeinsame Unterobjekte in einer eigenen Tabelle abzulegen (siehe Beispiel 8.26, b.). Dies hätte den Vorteil, dass die ansonsten notwendige wiederholte Speicherung derselben Adresse entfallen würde44. Beispiel 8.26: Modellierungsvarianten einer Adresse a. An einer Universität, bei der fast alle Studenten in privaten Unterkünften wohnen, würde man Adresse als abhängiges, exklusives Unterobjekt über einen eingebundenen benannten Zeilentypen oder über den ROW-Typkonstruktor modellieren. CREATE TYPE StudentTyp AS ( matrikelNr AchtstelligeZahl, studentVorname VARCHAR(25), studentName VARCHAR(25), studentAdresse AdresseTyp, oder 44 Es sei nicht verschwiegen, dass dies eine aus konzeptueller Sicht geführte Diskussion ist. Die Praxis wird immer die Performanzfrage aufwerfen und da ist es sicherlich so, dass eine über einen Verweis realisierte Einbindung einer Adresse wegen des damit verbundenen Verfolgens eines Zeigers beim Lesen (zusätzlichen Ladens einer physikalischen Seite) weniger performant sein wird als eine direkte Einbindung.
508
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen studentAdresse
ROW ( strasse VARCHAR(25), hausNr CHARACTER(5), plz CHARACTER(5), ort VARCHAR(25)) ...) REF IS SYSTEM GENERATED
b. An einer Campusuniversität, bei der es nur vergleichsweise wenige Studentenwohnheime gibt, in denen die meisten Studenten wohnen, kann man hingegen die Adresse als gemeinsames Unterobjekt über den REF-Typkonstruktor modellieren. CREATE TYPE StudentTyp AS ( matrikelNr AchtstelligeZahl, studentVorname VARCHAR(25), studentName VARCHAR(25), studentAdresse REF(AdresseTyp)) ... REF IS SYSTEM GENERATED
Die Mehrfachspeicherung derselben Information ist mit den bekannten negativen Begleiterscheinungen bei Änderungsoperationen verbunden: Es muss einerseits sichergestellt werden, dass auch wirklich alle Vorkommen der Information geändert werden und andererseits ist die Operation sehr aufwändig, da an vielen Stellen geändert werden muss. Aus diesen Gründen sind die Modellierungen in Beispiel 8.11 und Beispiel 8.17 auch als wenig gelungen zu bezeichnen. Zulieferer bzw. Lieferanten und Produkte sind hier als exklusive Unterobjekte modelliert, was bedeutet, dass dieselben Daten mehrfach abzulegen sind, falls ein Lieferant mehr als ein Teil liefert und ein Teil in mehr als einem Produkt eingebaut wird. Hier wäre es angebracht, die Unterobjekte über den REF-Typkonstruktor als gemeinsam zu modellieren. MULTISET-Typkonstruktor Das MULTISET ist der Kern bei der Modellierung komplexer Objekte, da es die direkte Modellierung von n:m- oder 1:m-Beziehungen von der 1-Seite erlaubt (siehe Beispiel 8.27). Es wird also in den meisten Fällen gewählt werden, wenn Attribute mengenwertig sein können. Zudem lässt es sich im Vergleich zum ARRAY meist in Anfragen viel einfacher handhaben. Trotzdem muss in Bezug auf die zur Diskussion stehenden Beziehungsarten festgestellt werden, dass auch das MULTISET keine der noch nicht direkt modellierbaren Varianten abbilden kann.
8.3 Objektorientierte Konzepte in SQL:2011
509
Beispiel 8.27: Sinnvolle Modellierung von gemeinsamen Unterobjekten Falls Unterobjekte als gemeinsam anzusehen sind, sollten sie über den REF-Typkonstruktor eingebunden werden, wie dies im folgenden Beispiel gezeigt wird: Liefert AS ( REF(ZuliefererTyp)) MULTISET, REF(TeilTyp), REF(ProduktTyp) MULTISET, ...) REF IS SYSTEM GENERATED
CREATE TYPE lieferant teilNr produktNr
TeilTyp AS ( FünfstelligeZahl, VARCHAR(25), REF(ZuliefererTyp)) MULTISET, REF(ProduktTyp)) MULTISET, ...) REF IS SYSTEM GENERATED
CREATE TYPE teilNr teilBez teilLieferant teilProdukt
Gerade bei exklusiven Unterobjekten sträubt man sich manchmal, von einem eigenen Objekt zu reden. Gäbe es zu jedem Teil nur genau einen Lieferanten und würde dieser dann wie in Beispiel 8.11 direkt als exklusives Unterobjekt modelliert, entspricht dies dem allgemeinen Verständnis von dem, was man unter einem Objekt versteht. Anders ist die Situation schon bei Adresse. Ob diese als exklusiv oder gemeinsam modelliert wird, spielt keine Rolle. Tatsache ist, dass sich viele schwer tun werden, sie als Objekt anzusehen. (Nicht nur) deshalb wird auch gerne zwischen einer Objekt- und einer Wertesemantik unterschieden. Exklusive Unterobjekte, wie Adresse, können als komplexe Werte und Lieferanten als komplexe Unterobjekte bezeichnet werden. In der Regel wird mit einer Wertesemantik verbunden, dass Werte durch ihre Datenstruktur repräsentiert werden und keine Objektidentität besitzen, während Objekte als abstrakte Datentypen nur über ihre Methoden angesprochen werden können und eine Objektidentität besitzen. Tabelle 8.1 fasst noch einmal die Beziehungsarten zusammen, die mit Hilfe der neuen Typkonstruktoren modelliert werden können. Es stellt sich also heraus, dass weder die Kombination abhängig/gemeinsam noch die Kombination unabhängig/exklusiv direkt umgesetzt werden kann. Da solche Kombinationen in der Realwelt allerdings vorkommen, muss es eine annäherungsweise Modellierung geben. In beiden Fällen werden sie i. d. R. wie ein unabhängiges/gemeinsames Objekt modelliert, d. h. im ersten Fall wird von der Kombination abhängig/gemeinsam das gemeinsam ignoriert und im zweiten Fall die von der Kombination unabhängig/exklusiv das exklusiv. Dies bedeutet, dass die damit implizierten Integritätsbedingungen nicht direkt durch das DBS garantiert werden können und ggf. anderwärtig innerhalb der Anwendung umgesetzt werden müssen oder eben offen bleiben.
510
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen abhängig/
unabhängig/gemeinsamabhängig/exklusiv
unabhängig/
gemeinsam ROW-Typkonstruktor REF-Typkonstruktor ARRAY-Typkonstruktor MULTISET-Typkonstruktor 1 3
✕ ✕
✕
✕
: von der n-Setie : von der 1-Seite
✓ : möglich
exklusiv ✓
✕
1:1-Beziehung
✓
✕
1:1 und 1:n-Beziehung1 REF DT ARRAY
ROW DT ARRAY
1:n und n:m-Beziehung3
1:n-Beziehung2 , 3
REF DT MULTISET 1:n3 und n:m-Beziehung
ROW DT MULTISET 1:n3 und n:m-Beziehung 2
✕ ✕
✕
✕
: bei eingeschränktem n
DT: hier steht der Datentyp ✕ : nicht möglich
Tabelle 8.1: Zusammenfassung der durch die neuen Typkonstruktoren modellierbaren Beziehungsarten
8.3.2
Objektidentität
Objektidentität ist eine der Säulen eines reinen objektorientierten Datenbankmodells. Sie weist einem Objekt eine über seine Lebenszeit eindeutige, unveränderbare Identität zu. In der Regel geschieht dies über ein so genanntes Surrogat. Das ist ein eindeutiger, vom System zum Zeitpunkt der Objektentstehung vergebener Schlüssel. Er dient ausschließlich dem Ziel, die eindeutige, insbesondere auch von Objektinhalten unabhängige Identität des Datensatzes während seiner gesamten Lebenszeit (und auch eine ausreichende Zeit danach) sicher zu stellen. Ein Surrogat ist weder änderbar noch stellt es eine explizit sichtbares Attribut eines Datensatzes dar. In dieser reinen Form gibt es die Objektidentität im objektrelationalen SQL nicht. Mit dem systemvergebenen Schlüssel wird ein ähnliches Konstrukt angeboten, allerdings nur für benannte Zeilentypen. Immer wenn von diesen eine Tabelle angelegt wird, werden deren Zeilen automatisch mit einem Schlüssel versehen. Beispiel 8.28 zeigt wie dessen Art bei der Erstellung eines Zeilentyps beeinflusst werden kann. Es kann aus drei Varianten ausgewählt werden. Über die REF IS SYSTEM GENERATED-Klausel (siehe Beispiel 8.28, a.), die auch gleichzeitig den Default darstellt, wird das DBMS aufgefordert, einen eindeutigen, im weiteren „Leben“ des Datensatzes nicht mehr änderbaren Identifikator zu vergeben. Beispiel 8.28, b. ähnelt der ersten Variante, nur das hier der Datentyp des systemvergebenen Schlüssels vom Benutzer vorgegeben wird. Im konkreten Fall stellen die Schlüssel also INTEGER-Werte dar. In Beispiel 8.28, c. schließlich wird die dritte Variante demonstriert, bei der eine vom Benutzer ausgewählte Kombination von bereits existierenden Attributen den Schlüssel definiert.
8.3 Objektorientierte Konzepte in SQL:2011
511
Dies entspricht der „alten“ Definition eines Primärschlüssels. Man beachte jedoch, dass jetzt sichergestellt wird, dass die Werte der Attributkombination nicht änderbar sind, was beim Primärschlüssel zwar empfohlen, aber nicht vom System erzwungen wird. Während ein reiner Objektidentifikator nichts mit dem eigentlichen Inhalt eines Objektes zu tun hat, kann der systemvergebene Schlüssel beim objektrelationalen SQL explizit Bestandteil der Datenstruktur des Zeilentyps sein. Deshalb ist die Definition eines Objektidentifikators im engeren Sinn nicht erfüllt. Beispiel 8.28: Festlegung der Art des künstlichen Schlüssels bei der Zeilentypdefinition CREATE TYPE KundenTyp AS ( Attributdeklarationen) a. REF IS SYSTEM GENERATED b. REF USING INTEGER c. REF FROM (kundenNr)
Beispiel 8.29 zeigt, wie dann der eigentliche Schlüssel bei der Anlage der Tabelle endgültig festgelegt wird. Von der Semantik entsprechen sich die Buchstaben a bis c. Natürlich muss bei der Anlage der Tabelle dieselbe Variante gewählt werden wie bei der Definition des Zeilentyps. Hier wird nur die Möglichkeit eingeräumt, den Schlüssel mit einem Namen zu versehen (in Beispiel 8.29 KundenOID). Beispiel 8.29: Ausstatten des künstlichen Schlüssels mit einem Namen bei der Tabellenanlage CREATE TABLE Kunden OF KundenTyp ( a. REF IS KundenOID SYSTEM GENERATED), b. REF IS KundenOID USER GENERATED), c. REF IS KundenOID DERIVED), Das Konzept von OIDs stellt im objektrelationalen SQL keine zusätzliche Möglichkeit zu dem Primär-/Fremdschlüsselkonzept dar, sondern steht daneben bzw. ersetzt dieses, aber nur bei typisierten Tabellen. Tabellen alter Bauart besitzen nach wie vor keine OID. Soll auf sie verwiesen werden, kann das nur über Fremdschlüssel gehen. Auch müssen solche Tabellen nach wie vor einen Primärschlüssel besitzen. Bei typisierten Tabellen ist die Situation genau umgekehrt. Sie besitzen nicht nur keinen Primärschlüssel mehr, sondern es ist auch nicht mehr möglich, einen solchen zu definieren. Deren Aufgabe wird vollständig von der OID übernommen. Will man also von beliebigen anderen Tabellen auf Datensätze einer typisierten Tabelle verweisen,s geschieht dies über die Einbettung der OID mit Hilfe des REF-Typkonstruktors (siehe Beispiel 8.30, b.). Damit ist auch klar, dass eine typisierte Tabelle immer mit einer Objektidentität ausgestattet werden muss. Wird diese nicht vom Datenbankprogrammierer explizit benannt, erzeugt das System automatisch eine (REF IS SYSTEM GENERATED ist der Default). Man mag sich vielleicht fragen, warum es diese drei Varianten von OIDs gibt. Dafür gibt es mehrere Gründe. Die dritte Variante entspricht im Wesentlichen dem (allerdings
512
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
verbesserten, s. o.) alten Primärschlüsselkonzept. Es stellt damit die Kompatibilität zum konventionellen SQL her. Die erste Variante ist die, die aus Sicht der Effizienz die günstigste sein wird, da sie es dem DBMS ermöglicht, einige aus Sicht der Effizienz und Korrektheit notwendigen Zusatzinformationen im Schlüssel zu verstecken. Dies könnte z.B. der Datentyp der Tabelle sein oder andere Informationen, die ansonsten erst über die Metadaten bestimmt werden könnten. Bei der zweiten Variante entfällt diese Möglichkeit. Sie kann aber insbesondere dann von Interesse sein, wenn man einen eindeutigen Identifikator auf Basis eines bestimmten Datentyps automatisch erzeugen lassen möchte. Allerdings kann man damit keinen Einfluss auf den Wert des Identifikators nehmen, da er automatisch durch das System vergeben wird. Wenn man dies möchte, bleibt nur die Variante 3. Schließlich sei noch angemerkt, dass die Modellierung einer Beziehung zwischen konventionellen Tabellen nicht zwangsläufig bedeutet, dass der Primärschlüssel der anzubindenden Tabelle als Fremdschlüssel genommen werden muss. Ein beliebiger Schlüsselkandidat erfüllt auch den Zweck45 . Daraus kann zwangsläufig impliziert werden, dass Beziehungen zwischen Tabellen auch im Zeitalter der Objektidentität und des nicht definierbaren Primärschlüssels über Fremdschlüssel, die ungleich der Objektidentität sind, abgedeckt werden können. Allerdings macht es im Normalfall immer Sinn, eine Beziehung explizit (z. B. über den REFTypkonstruktor) zu modellieren, so dass das alte Schlüssel/Fremdschlüssel-Konstrukt eher die absolute Ausnahme bleiben wird. Beispiel 8.30: Objektidentität versus Primär-/Fremdschlüsselbeziehung a. Gegeben sei die Definition der Abteilungstabelle, wie sie im ursprünglichen Schema unserer Unternehmensdatenbank festgelegt wurde (siehe Kapitel 7.2.7). Auf dieser Basis wäre ein Verweis auf Tupel dieser Tabelle nur über die Einbettung eines Fremdschlüssels möglich (siehe die Spalte abteilungsNr in der Mitarbeitertabelle). CREATE TABLE Mitarbeiter ( mitarbeiterNr AchtstelligeZahl PRIMARY KEY, mitarbeiterName VARCHAR(25) NOT NULL, ... abteilungsNr DreistelligeZahl, CONSTRAINT MitarbeiterFS FOREIGN KEY (abteilungsNr) REFERENCES Abteilung ON UPDATE RESTRICT); b. Gegeben sei der benannte Zeilentyp einer Abteilung wie er in Beispiel 8.25 definiert wurde. Auf dieser Basis könnte der Mitarbeiter-Zeilentyp wie folgt spezifiziert werden: CREATE TYPE MitarbeiterTyp AS ( mitarbeiterNr AchtstelligeZahl, mitarbeiterName VARCHAR(25), ... abteilung REF(AbteilungTyp))
45 Man nimmt natürlich üblicherweise den Primärschlüssel, da er der natürliche Kandidat ist und insbesondere im Normalfall auch die kleinste Fremdschlüsselgröße garantiert (oft nur eine Spalte).
8.3 Objektorientierte Konzepte in SQL:2011
513
Objektidentität und Beziehungen Objektidentität ist offensichtlich ein probates Mittel, über das Beziehungen zwischen Tabellen modelliert werden können. Insbesondere vermeidet sie die teure Verbundoperation. Bei einer 1:1-Beziehung zwischen eigenständigen Objekten (wie sie zwischen einer Abteilung und dem Abteilungsleiter bestehen könnte46 ) kann ein auf jeder Seite eingefügter Verweis eine Verbundoperation vermeiden. Bei einer 1:n-Beziehung stellt sich die Sachlage marginal schwieriger dar. Bei herkömmlicher Modellierung über den Fremdschlüssel würde dieser in die n-Tabelle eingebunden. Ersetzt man den Fremdschlüssel jetzt durch die Objektidentität, so wäre eine Verfolgung einer Beziehung von der n-Tabelle zur 1-Tabelle weiterhin einfach durch Verfolgen des Zeigers umzusetzen. Der umgekehrte Weg, von der 1-Tabelle zur n-Tabelle kann dann über ein MULTISET von Verweisen realisiert werden. Ähnlich stellt sich der Fall bei einer n:m-Beziehung dar, wo das Verfolgen einer Beziehung von jeder Seite aus (n- wie auch m-Tabelle) über ein MULTISET von Verweisen realisiert werden kann. Verweise sind allerdings immer nur auf Zeilen von (typisierten) Tabellen möglich. Wird beispielsweise der Datentyp eines Attributs einer Zeile eines Zeilentyps als ein benannter Zeilentyp spezifiziert, so hat die erzeugte Instanz dieses Zeilentyps zwar eine OID; trotzdem kann diese aber nicht innerhalb von Verweisen genutzt werden. Oder anders ausgedrückt kann auf eine Zeile einer typisierten Tabelle verwiesen werden, nicht aber feingranularer auf eine Spalte innerhalb einer Zeile. Beispiel 8.31: N:m Beziehung, modelliert über Verweistypen und Beziehungstabelle Dieses Beispiel zeigt, wie Beispiel 8.25 auszusehen hätte, wenn die n:m-Beziehung nicht über Arrays gelöst werden soll, sondern mit Hilfe des MULTISET. Die Definition der typisierten Tabellen Abteilung und Produkt ändert sich gegenüber Beispiel 8.25 nicht. AbteilungTyp AS ( DreistelligeZahl, ... arbeitetAnProdukt REF(ProduktTyp) MULTISET) REF IS SYSTEM GENERATED
CREATE TYPE abteilungsNr
ProduktTyp AS ( FünfstelligeZahl, ... wirdBearbeitetVon REF(AbteilungTyp) MULTISET) REF IS SYSTEM GENERATED
CREATE TYPE produktNr
Feststellung 8.4: Objektidentität versus Primär-/Fremdschlüsselbeziehung Zeilen von typisierten Tabellen besitzen eine Objektidentität (OID), die insbesondere auch geeignet ist, Beziehungen zwischen Zeilen von Tabellen zu modellieren. Damit ersetzt 46 Unter der Voraussetzung, dass ein Abteilungsleiter auch nur genau eine Abteilung leiten kann und jede Abteilung genau einen Leiter hat.
514
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
die OID den Primärschlüssel, der in typisierten Tabellen auch nicht mehr erzeugt werden kann. Eine über eine OID realisierte Beziehung hat den Vorteil, dass sie direkt ausgewertet werden kann. Dies bedeutet insbesondere, dass die ansonsten notwendige Verbundoperation zur Verfolgung der Beziehung nicht mehr notwendig ist. Dies wird in vielen Fällen zu erheblichen Performanzsteigerungen führen. Die Tatsache, dass es Objektidentität gibt, bedeutet allerdings nicht, dass Fremdschlüsselbeziehungen alter Art nicht mehr existieren. Einerseits wird es sie nach wie vor für konventionelle Tabellen geben und andererseits gibt es auch keine Regel, die verbietet, dass Beziehungen zwischen beliebigen Tabellen (und damit auch typisierten) über Fremdschlüssel ungleich der OID modelliert werden. Schließlich sei noch angefügt, dass bei typisierten Tabellen zwar kein(e) Attribut(kombination) mehr als Primärschlüssel definiert werden kann. Trotzdem wird dies nicht immer zur Abschaffung des „alten“ Primärschlüssels führen, da dieser kein ausschließliches Datenbankkonzept ist, sondern sich auch in der Realwelt durchgesetzt hat. Beispielsweise ist nicht zu erwarten, dass Verwaltungen die Personalnummer abschaffen werden, nur weil es jetzt eine Objektidentität gibt. Dementsprechend kann es sein, dass Objektidentität zum Wegfall der alten künstlichen Primärschlüsselspalte(n) führt, allerdings muss dem nicht zwangsläufig so sein. Wie bereits erwähnt, kann der alte Primärschlüssel, sofern er nur aus einem Attribut besteht, weiterhin erhalten bleiben, wenn bei der OID die Variante 2 oder, bei mehreren Attributen, die Variante 3 gewählt wird. Allerdings beschreibt dann die OID auch eine Eigenschaft der Entität, was der Definition einer OID im engeren Sinn widerspricht. Während das konventionelle SQL lediglich die Gleichheit von Entitäten zu modellieren erlaubt47 , nicht aber deren Identität, ist dies jetzt mit der Einführung der OID im objektrelationalen SQL möglich. Daher muss der im konventionellen SQL ausschließlich zur Verfügung stehende Gleichheitsvergleich von Entitäten (über den =-Operator) jetzt um einen Identitätsvergleich ergänzt werden. Dies geschieht über den ==-Operator. Bei der Gleichheit wird in der Literatur zwischen flacher (shallow) und tiefer (deep) Gleichheit unterschieden. Definition 8.10: Flache und tiefe Gleichheit Gleichheit kann grundsätzlich nur vorliegen, falls zwei Entitäten denselben Aufbau haben, also dieselben Attribute besitzen und die Attribute jeweils vom selben Datentyp sind. Damit wird impliziert, dass die Entitäten vom selben Zeilen- bzw. Datentyp sind. Dann liegt flache Gleichheit vor, falls jede Spalte der Entität, die einen Wert enthält, wertgleich ist, und jede Spalte, die einen Verweis enthält, auf dieselbe Entität verweist. Tiefe Gleichheit liegt vor, falls jede Spalte der Entität, die einen Wert enthält, wertgleich ist, und jede Spalte, die einen Verweis darstellt, zunächst einmal auf eine andere Entität vom selben Typ verweisen kann. Allerdings müssen aber rekursiv alle Spalten der jeweils adressierten Entitäten, die Werte enthalten, wertgleich sein. Identität schließt flache Gleichheit und flache Gleichheit schließt tiefe Gleichheit mit ein. SQL kennt nur eine Form von Gleichheit, die flache Gleichheit. 47 Natürlich kann Identität über einen Primärschlüssel simuliert werden. Die Identitätseigenschaft wird allerdings nicht vom DBMS garantiert, sondern muss innerhalb der Anwendung sichergestellt werden. Die Semantik ist damit nur der Anwendung bekannt, nicht aber dem DBS.
8.3 Objektorientierte Konzepte in SQL:2011
515
Beispiel 8.32: Identität und Formen von Gleichheit Gegeben seien fünf Personen (OID1 –OID5 ), die jeweils ein Auto besitzen:
OID
OID
OID
(Person) name: Kai' alter: 23 auto:
(Person) name: Kai' alter: 23 auto:
(Auto) marke: VW typ: Lupo
(Auto) marke: VW typ: Lupo
OID
(Person) name: Kai' alter: 23 auto:
OID
(Person) name: Kai' alter: 19 auto:
OID1 OID2 OID3 OID4 OID5 I = Identität S = Flache Gleichheit T = Tiefe Gleichheit = weder Identität noch Gleichheit
OID1 OID2 OID3 OID4 OID5 OID1
OID2
OID3
OID4
OID5
OID1
I
I
T
T
=
OID2
I
I
T
T
=
OID3
T
T
I
S
=
OID4
T
T
S
I
=
OID5
=
=
=
=
I
I = Identität S = Flache Gleichheit T = Tiefe Gleichheit = = weder Identität noch Gleichheit
516
8.3.3
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Datentypen / Klassen
In konventionellen Programmiersprachen werden Datentypen angeboten, die durch den zu Grunde liegenden möglicherweise unendlichen Wertebereich und den Operationen darauf definiert sind. In objektorientierten Programmiersprachen spricht man dagegen von Klassen und meint damit, dass zu einer Klasse all diejenigen Objekte gehören, die exakt das Verhalten dieser Klasse widerspiegeln und auf derselben, allerdings gekapselten internen Datenstruktur beruhen (siehe Abbildung 8.2). Damit sind implizit zwei Dinge beschrieben. Einerseits ist damit ein exakter Datentyp für die Klasse festgelegt und andererseits auch die Ansprechbarkeit bzw. Sichtbarkeit von Instanzen dieser Klasse. Letzteres bedeutet, dass automatisch alle Objekte, die genau das zu dieser Klasse gehörige Verhalten und deren Datenstruktur aufweisen, als zu dieser Klasse zugehörig anzusehen sind. Indirekt könnte man sagen, dass damit eine Containereigenschaft definiert wird. Eine Klasse definiert einerseits den Datentyp aller Objekte dieser Klasse und stellt andererseits den Container zur Verfügung, in dem alle Objekte dieser Klasse abgelegt werden. Diese zweite Eigenschaft spielt in Programmiersprachen keine wesentlich Rolle, da hier die Datenverarbeitung und nicht die Datenspeicherung im Vordergrund steht. Bei Datenbanksystemen ist das anders. Dort ist die Containereigenschaft von zentraler Bedeutung, da ja gerade auf Mengen von Objekten gearbeitet werden soll. Während die Doppelfunktion einer Klasse in Programmiersprachen durchaus Sinn machen mag, ist sie in DBS zu einschränkend, da man hier durchaus gelegentlich mehrere Container zu einem Datentyp haben möchte. Deshalb wird im objektrelationalem SQL auch zwischen der Definition eines (benannten) Zeilentyps (CREATE TYPE-Anweisung) und der Anlage einer Tabelle unterschieden (CREATE TABLE-Anweisung).
personVorname
personName geburtsDatum
betriebsZugehörigkeit gehalt
Gekapselte Mitarbeiter Datenstruktur
personAdresse mitarbeiterStatus
abteilungsNr einstellung
vorgesetzter
Abb. 8.2: Klasse Mitarbeiter mit gekapselter Datenstruktur und Methoden
Während anfänglich (mit SQL:1999) noch Integritätsbedingungen sowohl in der Typ- wie auch in der Tabellendefinition angegeben werden konnten, sind diese jetzt fast ausschließlich auf die Tabellendefinition beschränkt worden. Die einzige Ausnahme ist die DEFAULTKlausel, die auch in der Typdefinition angegeben werden kann. Insgesamt hat sich an den Integritätsbedingungen immer eien wenig geändert, aber vom Grundsatz her sind alle Integritätsbedingungen möglich, die wir bereits in Kapitel 7.2.4 für das konventionelle SQL diskutiert hatten.
8.3 Objektorientierte Konzepte in SQL:2011
8.3.4
517
Datenabstraktion / Kapselung
Datenabstraktion liegt immer dann vor, wenn die Daten eines Objektes nach außen verborgen bleiben, also ein Zugriff auf das Objekt ausschließlich über vorgefertigte Methoden möglich ist (siehe Abbildung 8.2). Dies erscheint zunächst einmal etwas schizophren im Zusammenhang mit Datenbanksystemen, da diese, wie der Name schon ausdrückt, Daten verwalten und zur Verfügung stellen. Nimmt man aber eine etwas abstraktere Sicht ein, so werden Methoden durch eine Anzahl von (0 bis n) Eingabeparametern und, wie wir noch sehen werden, durch genau einen Ausgabewert beschrieben. Der Ausgabewert ist von einem bestimmten Typ und da ergibt sich die Analogie zu Spalten, die eben auch von einem bestimmten Typ sind. Dementsprechend mag es aus Sicht des Anwenders egal sein, ob eine Anweisung der Art WHERE kundenName = ’Knausrig’ bedeutet, dass die Spalte kundenName konkret existiert und den Wert ’Knausrig’ enthalten muss oder ob systemintern eine Methode ausgeführt wird, die, auf welchem Weg auch immer, überprüft, ob es in der DB einen Datensatz gibt, der das Kriterium erfüllt. Genau genommen wird auch im ersten Fall eine Methode ausgeführt, nämlich eine, die den Spaltenwert direkt liest. Diese Philosophie hat sich das objektrelationale SQL zu nütze gemacht, wie weiter unten bei den Instanzmethoden noch genauer diskutiert wird. Methoden Funktionen, die im Sinne einer abstrakten Datentypbeschreibung das Verhalten eines benutzerdefinierten strukturierten Datentyps beschreiben, heißen im objektrelationalen SQL Methoden. Im Gegensatz bzw. in Ergänzung zu Funktionen gilt für Methoden das Folgende: • Sie sind an genau einen ihnen zugeordneten Datentyp gebunden, der ihren Typ festlegt. • Sie stellen die einzige Möglichkeit dar, um auf den strukturierten (bzw. abstrakten) Datentyp zuzugreifen, für den sie geschaffen wurden. • Während Funktionen nur überladen werden können, können Methoden überschrieben werden. Dies liegt daran, dass Methoden eindeutig einem strukturierten Datentyp zugeordnet sind. Strukturierte Datentypen können jedoch im objektrelationalen SQL in einer Vererbungshierarchie angeordnet sein. Damit ist es möglich, dass es zu einer Methode innerhalb der Hierarchie mehrere Implementierungen gibt. Als Konsequenz kann in solchen Fällen erst dynamisch zur Laufzeit in Abhängigkeit von der konkreten Variablenbelegung die richtige Implementierung ermittelt und an den Methodenaufruf gebunden werden. Definition 8.11: Methode Eine Methode ist eine an einen bestimmten benannten Zeilentyp gebundene Funktion, die folgende Eigenschaften aufweist: a. Der erste Parameter der Parameterliste ist vom Datentyp des benannten Zeilentyps, zu dem die Methode gehört. Dieser Parameter (über den Namen SELF adressierbar), auch Subjektparameter genannt, ist implizit und bestimmt den Adressaten der Methode. Man sagt, dass die Methode vom Typ des Subjektparameters ist. Alle anderen Parameter sind explizit und werden zusätzliche Parameter genannt.
518
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen b. Eine Methode kann überschrieben werden. c. Die korrekte Methodenimplementierung kann im Allgemeinen erst zur Laufzeitzeit festgestellt werden, weshalb Methodenimplementierungen dynamisch an ihren Aufruf gebunden werden. Konkret heißt das, dass der konkrete Typ des Subjektparameters erst zur Laufzeit bestimmt werden kann48 , während die Datentypen aller anderen Parameter den deklarierten entsprechen müssen, also schon zur Übersetzungszeit eindeutig bestimmbar sind.
Definition 8.12: Überschreiben Eine Methode M2 überschreibt eine andere Methode M1, falls sie a. den selben Namen wie M1 hat, b. dieselbe Anzahl von Parametern mit identischen Namen besitzt, wobei der Datentyp jedes Parameters unverändert bleibt, und c. zu einem Datentyp gehört, der Untertyp des Datentyps von M1 ist. Da die Ermittlung der im konkreten Anwendungsfall zu nutzenden Methodenimplementierung von dem aktuellen Subjektparameter der Methode zur Laufzeit abhängt, muss die richtige Implementierung dynamisch zur Laufzeit ermittelt werden (dynamisches Binden). Definition 8.13: Dynamisches Binden Dynamisches Binden liegt vor, falls die konkrete Implementierung einer Methode nicht bereits zur Übersetzungszeit bestimmt werden kann, sondern erst zur Laufzeit. Eine solche Situation ist gegeben, falls es zu einer Methodenschnittstelle mehrere Implementierungen geben kann, die innerhalb einer Ober-/Untertyphierarchie existieren und entstanden sind, weil die Methode eines Obertyps durch eine modifizierte Methode eines Untertyps ersetzt wurde. Methoden können ausschließlich im Zusammenhang mit der Definition benannter Zeilentypen eingeführt werden, also nicht bei der Spezifikation von Tabellen (unabhängig davon, ob diese typisiert sind oder nicht). Wird ein Zeilentyp definiert, ist bei dessen Definition nur die Schnittstellenbeschreibung jeder Methode jeweils über die METHOD-Klausel im Methodenblock der Zeilentypspezifikation festzulegen. Die eigentliche Methodenimplementierung kann später über die CREATE METHOD-Klausel nachgeliefert werden (siehe Beispiel 8.33). Methodennamen müssen ebenso wie Attributnamen in „ihrem“ Zeilentyp eindeutig sein. Methoden und Datenabstraktion Methoden sind im objektrelationalen SQL das Mittel, um Datenabstraktion sicher zu stellen. Analog zu den Klassen in objektorientierten Systemen gibt es unterschiedliche Methoden: 48 Der aktuelle Typ des Subjektparameter kann nur von einem Untertyp des Datentyps der Methode sein (siehe hierzu das folgende Kapitel zur Vererbung).
8.3 Objektorientierte Konzepte in SQL:2011
519
1. Instanzmethode (INSTANCE METHOD), die, adressiert an genau eine Instanz bzw. Ausprägung eines benannten Datentyps, auf diesem eine Operation ausführt. 2. Statische Methode (STATIC METHOD), die auf der Ebene des Zeilentyps als Ganzes angesiedelt ist und instanzenunabhängige/-übergreifende Aufgaben erledigt, die aber trotzdem typspezifisch sind (Unterschied zur Funktion). 3. Konstruktormethode (CONSTRUCTOR METHOD), die als eine spezielle Form von statischer Methode angesehen werden kann, da es ihre Aufgabe ist, eine neue Instanz des Datentyps zu erstellen, dessen Typ sie repräsentiert. Unter einer anderen Betrachtungsweise kann eine Methode entweder original oder überschreibend sein. Eine Methode ist original, falls sie zum ersten Mal innerhalb einer Typhierarchie eingeführt wird. Im Laufe der Entwicklung einer Typhierarchie kann eine Methode durch eine andere ersetzt werden. In diesem Fall handelt es sich um eine überschreibende Methode (OVERRIDING METHOD). Die drei oben beschriebenen Methodenarten können alle entweder original oder überschreibend sein. Überschreibende Methoden werden im nächsten Kapitel unter Vererbung genauer eingeführt. Statische und Konstruktormethoden Statische und Konstruktormethoden werden in objektorientierten Systemen auch häufig Klassenmethoden genannt. Mit statischen Methoden lassen sich beispielsweise Aufgaben wie das Ermitteln der Gesamtzahl aller Produkte, die von unserem Unternehmen vertrieben werden, erledigen (siehe Beispiel 8.33). Beispiel 8.33: Anlegen einer statischen Methode Ausgangspunkt dieses Beispiels sind die Produkt- und ProduktTyp-Definition von Beispiel 8.25. Innerhalb der Typdefinition wird in diesem Beispiel die statische Methode gesamtzahlProdukte() dem System bekannt gemacht, d. h. die folgende Deklaration wird Bestandteil des Methodenblockes: STATIC METHOD gesamtzahlProdukte() RETURNS INTEGER Die eigentliche Methodenimplementierung kann dann an anderer Stelle eingeführt werden. Da die Art der Methode (hier statisch), die Parameter (hier keiner) und der Typ des Rückgabewertes (hier: INTEGER) schon festgelegt wurden, brauchen sie hier nicht wiederholt zu werden CREATE METHOD gesamtzahlProdukte FOR ProduktTyp RETURNS INTEGER BEGIN DECLARE gesZahlProd INTEGER; gesZahlProd := 0; SELECT COUNT(produktNr)49 INTO gesZahlProd FROM Produkt; RETURN gesZahlProd; END;
520
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Erzeugen neuer Instanzen eines benannten Zeilentyps Mit Hilfe von Konstruktormethoden können neue Instanzen des zu Grunde liegenden benannten Zeilentyps erzeugt werden. Dabei wird bei einer solchen Methode immer impliziert, dass das zurückgelieferte Ergebnis vom Typ der Methode ist (SELF AS RESULT), die neue Instanz eben. Eine Konstruktormethode wird über das Voranstellen der NEW-Klausel vor dem Namen aufgerufen. Es ist zu beachten, dass nur über die Konstruktormethode Instanzen eines Zeilentyps erzeugt werden können50. Dies entspricht dem üblichen Vorgehen in objektorientierten Programmiersprachen. Diese Aussage gilt auch innerhalb von Anfragen. Beispielsweise ist ein einfaches Vergleichen mit einem Tupel aus Strings beim Zeilentyp adresse wegen der damit verbundenen Datentypverletzung nicht möglich (siehe Beispiel 8.34). Stattdessen muss wie in Beispiel 8.35 verfahren werden. Beispiel 8.34: Inkorrektes Anlegen einer neuen Instanz eines Zeilentyps Ausgangspunkt dieses Beispiels sind die Typ- und Tabellendefinitionen von Beispiel 8.9. Sollen alle Kunden ermittelt werden, die an einer bestimmten Adresse wohnen, kann die Anfrage nicht wie folgt gestellt werden: SELECT FROM WHERE
kundenName, kundenVorname Kunden kundenAdresse = (’EndeDerWelt’, ’3’, ’07070’, ’FuchsUndHase’);
Beispiel 8.35: Korrektes Anlegen einer neuen Instanz eines Zeilentyps Bei dieser korrekten Lösung für das vorhergehende Beispiel wird unterstellt, dass es eine Konstruktormethode gibt, über die eine neue Instanz von AdresseTyp angelegt werden kann, wobei alle Werte der Konstruktormethode als Parameter mitgegeben werden. SELECT FROM WHERE
kundenName, kundenVorname Kunden kundenAdresse = NEW AdresseTyp (’EndeDerWelt-Str’, ’3’, ’07070’, ’FuchsUndHase’);
Erzeugen neuer Instanzen einer typisierten Tabelle Das Anlegen einer neuen Instanz einer typisierten Tabelle geschieht nach wie vor über den INSERT INTO-Befehl. Beispiel 8.36 zeigt, wie eine neue Instanz mit eingebundener zeilenwertiger Spalte kundenAdresse erzeugt werden kann. Beispiel 8.36: Anlegen einer neuen Instanz in einer typisierten Tabelle Ausgangspunkt ist hier wieder die typisierte Kundentabelle von Beispiel 8.9. Die kundenAdresse-Spalte ist vom Zeilentyp AdresseTyp. Daher muss eine neue Instanz dieses Typs über den NEW-Operator eingeführt werden. 49 Da
produktNr Schlüsselcharakter hat, braucht kein DISTINCT angeben zu werden. ist Zeilentyp eng interpretiert zu verstehen. Eine Instanz einer typisierten Tabelle ist natürlich auch eine Instanz eines Zeilentyps, aber solche Instanzen sind hier nicht gemeint, sondern nur „tabellenlose“. 50 Hier
8.3 Objektorientierte Konzepte in SQL:2011 INSERT INTO VALUES
521
Kunden (kundenNr, kundenVorname, kundenName, kundenAdresse, . . . ) (37137144, ’Willy’, ’Witzig’, 115); NEW AdresseTyp(’EndeDerWelt’, ’3’, ’07070’, ’FuchsUndHase’), . . . );
Bei der Definition eines benannten Zeilentyps wird immer automatisch eine (statische) Default Konstruktormethode angelegt. Sie besitzt den gleichen Namen wie der Zeilentyp, für den sie angelegt wird, und ist parameterlos. Sie kann nicht überschrieben werden Ihr Aufruf liefert eine neue Instanz des zu Grunde liegenden Zeilentyps zurück, wobei jede ihrer Spalten mit dem in der Zeilentypdefinition vorgegebenen Default belegt wird, falls ein solcher festgelegt wurde. Neben der vorgegebenen Konstruktormethode können bei der Zeilentypdefinition noch weitere Konstruktormethoden angelegt werden. Diese müssen sich jeweils in der Anzahl und/oder dem Typ der Parameter unterscheiden. Instanzenmethoden Instanzenmethoden übernehmen quasi die Aufgaben von Spalten in klassischen Tabellen, d. h. über sie wird auf die verborgene Datenstruktur des zu Grunde liegenden Typs zugegriffen. Deshalb können Instanzenmethoden sehr simpel sein, z. B. nur den Wert eines Attributs lesen und zurückliefern. Andererseits können sie aber auch komplexe Berechnungen durchführen, wodurch viel Anwendungssemantik inklusive Integritätssicherstellung bereits im DBS umgesetzt werden kann. Auch lässt sich über Instanzenmethoden eine Art logische Datenstruktur aufbauen, die sich durchaus von der explizit vorhandenen physischen Datenstruktur unterscheiden kann. Bevor hierauf etwas genauer eingegangen wird, soll zunächst noch einmal auf den normalen Spaltenzugriff innerhalb eines DBS eingegangen werden. Wie bereits oben gesagt, kann man auf der nächst höheren Abstraktionsebene sagen, dass ein Lesezugriff auf eine Spalte eine Funktion ist, bei der eine konkrete Spalte einer konkreten Zeile einer Tabelle auf den konkreten Wert der Spalte abgebildet wird. In konventionellen DBS entspricht diese Abbildung dem konkreten Lesen des Spaltenwerts von der Festplatte. Die obige Sichtweise erlaubt uns jetzt aber eine allgemeinere Sicht auf diesen Lesevorgang,. Er muss nicht unbedingt über das direkte Lesen eines Wertes umgesetzt werden, sondern kann auch über eine beliebige BeRechnung des Wertes umgesetzt werden, so lange das Ergebnis der BeRechnung einen gültigen Wert des Wertebereichs des Datentyps der Spalte darstellt. Genau diese Philosophie macht sich das objektrelationales SQL zu eigen. Offiziell gibt es keine Attribute mehr, sondern nur noch Instanzenmethoden für jedes Attribut, die als Ergebnis den Attributwert zurückliefern (oder ändern). Dabei können jetzt zwei Arten von Attribute unterschieden werden. Die erste Art sind die konventionellen Attribute, bei denen davon ausgegangen werden kann, dass deren Wert direkt irgendwo auf der Platte abgelegt ist und nur gelesen werden muss. Fast alle in einem DBS abgelegten Eigenschaften einer Entität sind von dieser Art. Die zweite Art sind sogenannten logischen Attribute, bei denen es einen echten Algorithmus gibt, über den dieser Wert jeweils erst berechnet wird, wenn auf ihn zugegriffen wird. Bei der ersten Art von Attributen benötigt man pro Attribut eine Methode, die diesen Wert liefert, und eine Methode, die diesen Wert schreibt bzw. ändert. Bei der zweiten Art braucht es nur eine Lesemethode, da der Wert berechnet wird und nicht explizit irgendwo abgelegt ist, also auch nicht geändert bzw. geschrieben werden kann. Die erste Art von Methoden wird beim objektrelationalen
522
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
SQL automatisch mitgeliefert. Die zweite Art muss explizit vom Datenbankprogrammierer über das Anlegen von entsprechenden Instanzenmethoden umgesetzt werden. Implizit erzeugte Methoden bei der Definition von benannten Zeilentypen Um das Konzept der Datenabstraktion sauber umsetzen zu können, wird im objektrelationalen SQL für jedes Attribut des benannten Zeilentyps automatisch sowohl eine Instanzenmethode erzeugt, die den Wert des Attributs liest und zurückliefert (get function, Observer-Methode genannt), als auch eine, die dem Attribut einen als Parameter mitgelieferten Wert zuweist (set function, Mutator-Methode genannt). Beide Methoden besitzen denselben Namen wie das Attribut, wobei die Mutator-Methode einen Eingabeparameter besitzt, die Observer-Methode nicht. Diese Methoden können nicht durch den Anwender verändert bzw. überschrieben werden. Diese Philosophie bedeutet nun, dass eine benannte Zeilentypdefinition sich nicht wesentlich von der Definition einer konventionellen Tabelle unterscheidet, da in beiden Fällen die Eigenschaften der Entität vorwiegend über explizite Attribute ausgedrückt werden und bei denen werden die Instanzenmethoden automatisch erzeugt, brauchen also in der Zeilendefinition nicht spezifiziert zu werden. Somit kann man sagen, dass beide Definitionen im Wesentlichen nur durch die Angabe von einer in der Regel sehr kleinen Menge von zusätzlichen Instanzenmethoden für logische Attribute im Falle der Definition von Zeilentypen unterscheiden. Dies ist auch der Grund, warum wir bei den vielen Beispielen für die Definition von Zeilentypen eigentlich nie Instanzenmethoden spezifizieren, obwohl genau diese aber die einzige Möglichkeit sind, auf Eigenschaften von Entitäten zuzugreifen. Damit mag bei vielen Lesern der Eindruck entstehen, als würden Methoden keine besondere Rolle spielen im objektrelationalem SQL. Die Wahrheit ist aber, dass dem nicht so ist. Sie spielen die entscheidende Rolle, nur bleibt dies verborgen, weil fast alle diese Methoden implizit durch das DBS geliefert werden. Diese automatische Generierung von Observer- und Mutator-Methoden hat allerdings auch einige Nachteile. Zum einen bedeutet insbesondere die Tatsache, dass diese automatisch generierten Methoden nicht überschrieben werden können, dass es nicht möglich ist, beispielsweise Integritätsbedingungen in diesen Methoden umzusetzen oder z. B. auch Werteverkürzungen. Mit letzterem ist gemeint, dass manchmal gerne Werte, die aus einem sehr beschränkten aber eher platzfressenden Wertebereich stammen, durch andere, kompaktere Werte umgesetzt werden. So mag beispielsweise der Wert Geschlecht nicht durch die doch sehr platzfressenden Zeichenketten männlich und weiblich umgesetzt werden, sondern durch den wesentlich kompakteren Datentyp BOOLEAN. Die Umwandlung auf die aus Sicht der Anwendung semantisch korrekten Werte könnte dann in den jeweiligen Methodenimplementierungen erfolgen. Dieses Vorgehen ist aber im objektrelationalem SQL ausgeschlossen. Der zweite Nachteil ist, dass Methoden grundsätzlich sichtbar sind. Damit ist es ausgeschlossen, dass man z. B. nur für interne BeRechnungen benötigte Attribute vor dem Benutzer versteckt (wie es beispielsweise in Java durch die Spezifikation von privat möglich ist). Dieser Weg hätte es auch ermöglicht, den ersten Nachteil zu kompensieren, da man dann die automatische Methode hätte verstecken und durch eine semantisch sinnvollere ersetzen können. Beispiel 8.37: Observer- und Mutator-Methode im objektrelationalen SQL Die folgenden Methodenbeschreibungen stammen aus dem Standardisierungsdokument. attrName ist der Name des Attributs, für das die Methode angelegt wird. Bei der Observer-Methode scheinen die CONTAINS- und die NULL-Klausel überflüssig zu sein, da
8.3 Objektorientierte Konzepte in SQL:2011
523
einerseits über die LANGUAGE-Klausel die Sprache schon definiert wurde und andererseits kein Eingabeparameter erwartet wird. SELF AS RESULT in der Mutator-Methode besagt, dass es sich um eine Methode handelt, die den Wert des Attributs verändert. Während die Oberserver-Methode den Wert des Attributs zurückliefert (ausgedrückt darüber, dass der zurückgelieferte Wert vom Typ AttrTyp ist), liefert die Mutator-Methode als Ausdruck der erfolgreichen Ausführung den Namen des Zeilentyps zurück, in dem das Attribut eingebunden ist. Observer-Methode: CREATE METHOD AttrName () RETURNS AttrTyp LANGUAGE SQL DETERMINISTIC CONTAINS SQL RETURNS NULL ON NULL INPUT
Mutator-Methode: CREATE METHOD AttrName (wert AttrTyp) RETURNS zeilentypName SELF AS RESULT LANGUAGE SQL DETERMINISTIC CONTAINS SQL RETURNS NULL ON NULL INPUT
Beispiel 8.38: Repräsentieren eines logischen Attributes über eine Methode Es wird unterstellt, dass mitarbeiterOID als Name für den (systemvergebenen) Schlüssel von Instanzen von MitarbeiterTyp gewählt wurde. CURRENT_DATE ist, wie üblich, die Methode, die das aktuelle Datum zur Methodenausführungszeit liefert. Zunächst wird wieder die Methode bei der Zeilentypdefinition bekannt gemacht. INSTANCE METHOD
betriebsZugehörigkeit() RETURNS INTERVAL YEAR TO MONTH
Der Methodenkörper könnte wie folgt aussehen: CREATE METHOD betriebsZugehörigkeit FOR MitarbeiterTyp BEGIN DECLARE Zugehörigkeit INTERVAL YEAR TO MONTH; Zugehörigkeit := INTERVAL ’0-0’ YEAR TO MONTH; SELECT (CURRENT_DATE-einstellung) INTO Zugehörigkeit FROM Mitarbeiter WHERE mitarbeiterOID = SELF; RETURN Zugehörigkeit; END;
Logische Attribute In Beispiel 8.38 wird beispielsweise eine Methode betriebsZugehörigkeit definiert, die berechnet, wie lange ein Mitarbeiter bereits dem Unternehmen angehört. Dies ist ein typisches Beispiel für ein logisches bzw. abgeleitetes Attribut, welches so vermutlich niemals als Spalte
524
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
einer konventionellen Tabelle definiert würde. Stattdessen müsste die Betriebszugehörigkeit in der Anwendung berechnet werden. Auch die Funktion GesKtoStand von Beispiel 8.23 ließe sich vermutlich besser als Instanzenmethode von KundenTyp umsetzen (siehe Beispiel 8.39). Beispiel 8.39: Die Funktion GesKtoStand realisiert als Instanzenmethode Die Instanzenmethode gesKtoStand soll die Schnittstelle von KundenTyp erweitern und wird daher zunächst in deren Methodenblock deklariert: INSTANCE METHOD
gesKtoStand() RETURNS DECIMAL(15,2)
Die Methodenimplementierung könnte dann wie folgt aussehen: CREATE METHOD gesKtoStand FOR KundenTyp BEGIN DECLARE gesamtKtoStand DECIMAL(15,2); gesamtKtoStand := 0; SELECT SUM(kontoStand) INTO gesamtKtoStand FROM Konto WHERE kunde → kundenOID = SELF; IF gesamtKtoStand < 0 THEN gesamtKtoStand := 0 END IF; RETURN gesamtKtoStand; END;
/* Schnittstellendefinition /* Funktionskörper
Beispiel 8.40: Logische Spalte in einer konventionellen Tabelle seit SQL:1999 CREATE TABLE(TYPE) Mitarbeiter(Typ) AS ( iD INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1000000 INCREMENT BY 2 MINVALUE 1000000 MAXVALUE 9999999 CYCLE) (PRIMARY KEY), name ROW (vorname VARCHAR(30), nachname VARCHAR(25)), gehalt DECIMAL(12,2), bonus DECIMAL(12,2), (total GENERATED ALWAYS AS (gehalt + bonus),) vollzeit BOOLEAN, bild BLOB(1M), fähigkeiten CLOB(50k) sprachen VARCHAR(15) ARRAY[8]) ...
8.3 Objektorientierte Konzepte in SQL:2011
525
Eine logische Spalte kann seit SQL:1999 allerdings auch direkt als eine Art Methode über das GENERATED ALWAYS AS-Sprachkonstrukt als ganz normale Spalte einer konventionellen Tabelle angelegt werden, wie in Beispiel 8.40 anhand der Spalte total gezeigt wird. In einer typisierten Tabelle ist dieses Sprachkonstrukt allerdings nicht erlaubt, da es dort direkt über eine Instanzenmethode umgesetzt werden kann und ansonsten die automatisch erzeugte Observer-Methode nicht funktionieren würde. Das Beispiel zeigt noch einige andere neue Sprachkonstrukte vorwiegend für konventionelle Tabellen. Zum einen können auch hier jetzt die neuen Typkonstruktoren eingesetzt werden, um komplexere Objektstrukturen umsetzen zu können. Eine Ausnahme bildet allerdings der REF-Typkonstruktor, da er mit OIDs arbeitet. Da konventionelle Tabellen eine OID aber nicht kennen, kann dieser Typkosntruktor nicht verwendet werden. Die iD-Spalte ist hier als Schlüsselspalte angelegt, der immer automatisch beim Erzeugen einer neuen Entität der nächste freie Schlüsselwert zugewiesen wird. Dabei fängt der Wertebereich für den Schlüssel bei 1000000 an und hört bei 9999999 auf, wobei ein neuer Wert aus dem alten durch Aufaddieren von 2 erzeugt wird. Wenn das Ende des Wertebereichs erreicht ist, wird wieder von vorne angefangen, in der Hoffnung, dass zwischenzeitlich einige Entitäten der Tabelle gelöscht wurden, womit deren Werte für eine neue Entität wieder frei sind. Dieses Sprachkonstrukt kann auch bei der Definition von benannten Zeilentypen genutzt werden. Eine logische Datenstruktur wird beschrieben durch alle lesenden Instanzenmethoden eines benannten Zeilentyps. Es sei hier angemerkt, dass das objektrelationale SQL nicht das ansonsten sehr verbreitete Sichtbarkeitskonzept von Methoden unterstützt. Es kann also nicht definiert werden, dass eine Methode PRIVATE oder PROTECTED ist, was in beiden Fällen bedeuten würde, dass diese Methoden (in unterschiedlicher Form) nur für interne Zwecke genutzt werden können, also zum Anwender hin nicht sichtbar sind. Das Fehlen dieser Unterscheidung behindert eine aus Sicht der Anwendung saubere Definition der logischen Datenstruktur eines Zeilentyps, da Hilfsmethoden nicht ausgeblendet werden können. Funktionen und insbesondere auch Methoden lassen sich äquivalent zu Spalten von konventionellen Tabellen in Anfragen verwenden (siehe Beispiel 8.41). Beispiel 8.41: Methoden und Anfragen a. In der folgenden Anfrage wird die Instanzenmethode betriebsZugehörigkeit genutzt, um alle Mitarbeiter zu ermitteln, die bereits länger als 30 Jahre zum Unternehmen gehören. SELECT FROM WHERE
mitarbeiterName, mitarbeiterVorname Mitarbeiter betriebsZugehörigkeit > INTERVAL ’30-0’ YEAR TO MONTH;
b. Diese Anfrage verwendet die in Beispiel 8.33 definierte statische Methode gesamtzahlProdukte, um zu ermitteln, welche Lager die vollständige Produktpalette vorrätig halten. Bei statischen Methoden ist statt der Punktnotation eine doppelte Doppelpunktnotation zu verwenden. SELECT FROM
produktLagerNr, produktLagerBez ProduktLager AS PL
526
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen WHERE Produkt::gesamtzahlProdukte = (SELECT COUNT(∗) FROM ProduktLagertIn WHERE produktLagerNr = PL.produktLagerNr); c. Die modifizierte Anfrage, in der alle Kunden ermittelt werden, deren Einlage über alle ihre Konten 10.000,– C überschreitet, sähe dann wie folgt aus (Basis ist die Tabelle Konto, siehe Beispiel 8.14):
FROM WHERE
kunde → kundenNr, kunde → kundenName, kunde → kundenVorname Konto kunde→gesKtoStand > 10000;
WHERE
kunde.gesKtoStand > 10000;
SELECT
oder
Wird bei der Spezifikation der Schnittstelle einer Methode keine Methodenart angegeben, so wird INSTANCE unterstellt. Behandlung von Verweis- und Zeilentypen in Anfragen Der Zugriff auf Verweise und komplexe Spalten in SQL-Anfragen erfordert eine besondere Behandlung. Bei der Spezifikation eines Verweises als Ausgabewert möchte man sicherlich nicht dessen interne Verschlüsselung sehen, sondern in der Regel das Objekt bzw. Datum, auf das verwiesen wird. Bei komplexen Spalten möchte man nicht immer auch alle Unterspalten bzw. -felder sehen, sondern möglicherweise nur eine Teilmenge. Beispiel 8.42, 1. zeigt, wie dies erreicht werden kann. In Konto existiert ein Verweis auf den zugehörigen Kunden (siehe Beispiel 8.13 bzw. Beispiel 8.14). Es soll nur der Name des Kunden, nicht aber die restlichen Spalten ausgegeben werden. Dies kann erreicht werden, indem über einen so genannten Pfadausdruck dereferenziert wird. Vom Datensatz des Kontos wird über die Spalte kunde zur Spalte kundenName des entsprechenden Datensatzes in der Tabelle Kunden navigiert (kunde → kundenName). Im gegebenen Beispiel werden die Namen aller Kunden ausgegeben, deren Konto mehr als 1.000.000,– C im Plus steht. Häufig verwendet man für solche Pfadausdrücke auch eine Punktschreibweise (kunde.kundenName). Das objektrelationale SQL sieht allerdings vor, dass der Pfeil bei Verweistypen verwendet werden muss, da hier eine Dereferenzierung auf die hinter dem Verweis liegenden Daten vorgenommen wird (siehe Beispiel 8.42, a.). Bei Methodenaufrufen kann die Pfeil-, aber auch die Punktnotation verwendet werden (siehe Beispiel 8.42, b.), während bei Zugriffen auf ROW-Felder die Punktnotation verpflichtend ist (siehe Beispiel 8.42, b. und c.). Eine Zeile, in der Verweise oder zeilenwertige Spalten vorhanden sind, stellt eine geschachtelte Struktur dar, bei der die tiefer geschachtelten Werte an sich einzeln abgerufen werden müssten. Dies kann eine sehr aufwändige Operation sein, weshalb man solche Zeilen auch dereferenzieren kann. Dies entspricht einem Flachklopfen der Zeile. In Beispiel 8.42, d. werden als Ergebnis der Anfrage nicht nur alle atomaren Konto-Daten ausgegeben, sondern auch alle Daten der zeilenwertigen Spalte kunde.
8.3 Objektorientierte Konzepte in SQL:2011
527
Beispiel 8.42: Ausgabe komplex aufgebauter Zeilen a. Die folgende Anfrage beruht auf der Tabellendefinition von Beispiel 8.14. Es soll ein Wert einer Methode ausgegeben werden, die zu einem benannten Zeilentyp gehört, der über den Verweis kunde referenziert wird. SELECT FROM WHERE
kunde → kundenName Konto kontoStand > 1000000;
b. In dieser Anfrage werden alle Zulieferer ermittelt, die das Teil mit der teilNr 12345 liefern und in JWD wohnen. Diese Anfrage arbeitet auf der Tabelle Liefert von Beispiel 8.11. Der Zugriff auf die Instanzenmethode ort des Feldes zuliefererAdresse der Spalte zulieferer kann entweder über die Punkt- oder die Pfeilnotation realisiert werden. SELECT FROM WHERE
zulieferer.zuliefererNr, zulieferer.zuliefererName Liefert teilNr = 12345 AND zulieferer.zuliefererAdresse.ort = ’JWD’;
oder alternativ mit Pfeilnotation: SELECT FROM WHERE
zulieferer.zuliefererNr, zulieferer.zuliefererName Liefert teilNr = 12345 AND zulieferer.zuliefererAdresse→ort = ’JWD’;
c. Ausgabe aller Abteilungen, deren jährliche Reisemittel höher als 125.000,– C sind. Dieses Beispiel beruht auf der Definition der Abteilungstabelle von Beispiel 8.12, die besagt, dass reisemittel ein Feld der ROW-basierten Spalte budget darstellt. SELECT FROM WHERE
abteilungsName Abteilung budget.reisemittel > 125000;
d. Ausgabe aller flachgeklopften Daten eines Datensatzes (dieses Beispiel beruht wieder auf der Tabellendefinition von Beispiel 8.14). SELECT FROM WHERE
DEREF Kto Konten AS Kto Kto.kontoStand > 1000000;
Feststellung 8.5: Zugriff auf komplexe Unterobjekte und benannte Zeilentypen Der Zugriff auf die Bestandteile komplexer Unterobjekte erfolgt über Pfadausdrücke. Dabei ist zu unterscheiden zwischen der Punkt- und der Pfeilnotation. Auf Felder von über den ROW -Typkonstruktor gebildeten Unterobjekten kann nur über die Punktnotation zugegriffen werden. Auf Spalten von über den REF-Typkonstruktor eingebundenen (gemeinsamen) Unterobjekten kann nur mit der Pfeilnotation zugegriffen werden, während Instanzenmethoden von benannten Zeilentypen sowohl über die Punkt- als auch über die Pfeilnotation aufgerufen werden können. Statische Methoden sind über die doppelte Doppelpunktnotation zu aktivieren.
528
8.3.5
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Vererbung
Vererbung und Vererbungshierarchien sind ein probates Mittel, um den Entwicklungsprozess eines Systems zu vereinfachen und übersichtlicher zu gestalten. Die Grundannahme ist, dass jedes Szenario, welches modelliert werden soll, sich aus einer Anzahl von (bestimmenden) Basisentitäten zusammensetzt, die die Gesamtstruktur und den Gesamtablauf des Systems bestimmen. Diese Basisentitäten sind dann Ausgangspunkt, um speziellere Entitäten zu entwickeln. Dabei findet Wiederverwendung statt, d. h. die speziellere Entität beruht auf derselben Datenstruktur und denselben Methoden wie die ursprüngliche. Es ist lediglich eine Ergänzung und/oder Verfeinerung möglich. Vererbung wird ausschließlich im objektrelationalen Teil von SQL unterstützt, d. h. auf der Ebene von benannten Zeilentypen. Konventionelle Tabellen können nicht in einer Vererbungshierarchie angeordnet werden. Es werden drei Arten von Vererbungshierarchien unterstützt. Die Typhierarchie, wird auf der Basis der benannten Zeilentypen gebildet. Deren Pendant auf der Ebene der typisierten Tabellen ist die Tabellenhierarchie. Dazu gibt es dann noch die Hierarchie auf der Ebene von typisierten Sichten, die Sichtenhierarchie. Alle Hierarchien sind baumartig, d. h. es wird grundsätzlich nur Einfachvererbung unterstützt. Zwar bestimmt die Typhierarchie auch die grundsätzliche Struktur der anderen Hierarchien, aber grundsätzlich sind alle drei Hierarchien unabhängig voneinander, sie stehen quasi nebeneinander. Abgrenzung der Vererbungshierarchien Die Typhierarchie ist die dominierende Sicht im objektrelationalen SQL, d.h. sie legt den eigentlichen Grundaufbau aller Vererbungshierarchien fest. Diese Hierarchie ist von ihrer Strukturvererbungssemantik her äquivalent zum Strukturvererbungskonzepr in objektorientierten Programmiersprachen. Ein Zeilentyp, der von einem Vaterzeilentyp erbt, erbt von diesem dessen Datenstruktur und Methoden. Die beiden anderen Vererbungshierarchien haben im Gegensatz dazu eine andere Aufgabe. Zwar erlauben sie auch die Festlegung weiterer tabellen- bzw. sichtenspezifischer Integritätsbedingungen51, aber ihre eigentliche Aufgabe ist die Bestimmung von Sichtbarkeit bzw. Ansprechbarkeit. Die Grundidee einer Vererbungshierarchie in objektorientierten Programmiersprachen ist die Strukturvererbung (interne Datenstruktur wie auch Methoden) und die dadurch gewonnene Wiederverwendbarkeit. Allerdings wird implizit auch die Sichtbarkeit bzw. Ansprechbarkeit von Objekten von Klassen definiert. Man kann dies auch so sehen, dass die Definition einer Klasse immer auch bedeutet, dass neben der Strukturdefinition auch eine Containererstellung stattfindet. Für diese Klasse wird ein Container erzeugt, in den alle Instanzen dieser Klasse liegen und der implizit auch alle Instanzen aller Unterklassen dieser Klasse mit zugreifbar bzw. sichtbar macht. Dies folgt direkt aus der Polymorphismuseigenschaft, die im nächsten Kapitel (Kapitel 8.3.6) noch genauer diskutiert wird. Polymorphismus impliziert, dass überall dort, wo eine Instanz eines bestimmten Datentyps (hier Zeilentyps) erwartet wird, auch eine Instanz eines beliebigen Untertyps dieses Datentyps stehen darf. Grundsätzlich sind damit auf der Ebene einer Klasse nicht nur deren direkte Instanzen ansprechbar bzw. sichtbar, sondern auch alle Instanzen von Unterklassen dieser Klasse. Somit erfüllt eine klassische 51 Die Grundidee ist, dass grundsätzliche zeilentypspezifische Integritätsabedingungen auf der Ebene der Definition eines Zeilentyps angelegt werden. Integritätsbedingungen, die nur für eine bestimmte Tabelle sinnvoll sein können, werden hingegen bei der Spezifikation von (Unter)tabellen festgelegt. Die genaue Trennung zwischen diesen beiden Arten von Integritätsbedingungen ist manchmal kaum möglich und wird hier nicht weiter diskutiert.
8.3 Objektorientierte Konzepte in SQL:2011
529
Vererbungshierarchie die Aufgabe der Struktur- und Methodenvererbung und die Aufgabe der Definition der Sichtbarkeit bzw. Ansprechbarkeit von Instanzen innerhalb dieser Hierarchie. Im objektrelationalem SQL werden diese beiden Aufgabe getrennt. Die erste Aufgabe wird von der Typhierarchie übernommen, die zweite von der Tabellen- bzw. Sichtenhierarchie. Wenn das objektrelationale SQL also die übliche Semantik einer Vererbungshierarchie direkt übernommen hätte, so würde es bedeuten, dass als Default beim Zugriff auf eine Tabelle T eines bestimmten Zeilentyps ZT auch alle Datensätze (Zeilen) von Tabellen berücksichtigt werden müssen, die von einem Untertyp von ZT sind (und damit implizit Untertabellen von T sind). Diese induzierte Sichtbarkeit wird durch eine explizit festzulegende Sichtbarkeit ersetzt. Auf der Ebene einer Tabelle sind nur dann die Datensätze von Untertabellen sichtbar, wenn diese Sichtbarkeit auch so explizit in der Tabellenhierarchie definiert wurde. Typhierarchie Die Typhierarchie beschränkt sich auf die Festlegung der Eigenschaften und der Struktur von potenziellen Instanzen von Zeilentypen. Zum Zwecke der Vererbung gibt es die UNDERKlausel, die wie in Beispiel 8.43 angegeben eingesetzt wird. Dabei wird zunächst ein allgemeiner Zeilentyp Person eingeführt, der alle allgemeinen Merkmale ausdrückt, die eine Person auszeichnen. Aus diesem wurden dann über Vererbung die spezielleren Typen KundenTyp und MitarbeiterTyp abgeleitet. Ein direkter Untertyp erbt von seinem direkten Obertyp alle Attribute und Methoden. Zusätzlich können neue Attribute und Methoden hinzugefügt und bestehende Methoden überschrieben werden. Es ist nicht möglich, den Typ der Attribute zu verändern, wie es in manchen objektorientierten Systemen möglich ist, indem beispielsweise ein speziellerer Typ als Datentyp eines Attributs/Parameters gewählt wird. Insgesamt ist die Typkompatibilität unabdingbare Voraussetzung, um Typsicherheit bei der Unterstützung von dynamischem Binden und Substituierbarkeit zu garantieren. Beispiel 8.43 zeigt, wie Vererbung realisiert wird, wobei in beiden Fällen Attribute hinzugefügt werden (und damit implizit auch zusätzliche Methoden, die Observer- und MutatorMethoden für jedes neue Attribut). Definition 8.14: Typvererbung im objektrelationalen SQL Im objektrelationalen SQL spricht man von Typvererbung, wenn ein neuer benannter Zeilentyp direkt aus einem bestehenden abgeleitet wird. Es entsteht eine Ober- / UntertypBeziehung. In der Untertyp-Deklaration können • neue Attribute und • neue Methoden hinzugefügt werden und • bestehende Methoden durch eine andere Implementierung ersetzt werden (Überschreiben von Methoden). Beispiel 8.43: Typvererbung im objektrelationalen SQL Unter Vererbung könnten die Zeilentypen MitarbeiterTyp und KundenTyp als Untertypen des Zeilentyps Person kreiert werden:
530
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen PersonTyp AS ( ROW ( personVorname VARCHAR(25), personNachname VARCHAR(25)), geburtsDatum DATE, personAdresse REF(AdresseTyp) ARRAY[3]) REF USING AchtstelligeZahl NOT INSTANTIABLE NOT FINAL INSTANCE METHOD alter() RETURNS SMALLINT,
CREATE TYPE personName
CREATE TYPE KundenTyp UNDER PersonTyp AS ( rabatt DECIMAL(4,2) DEFAULT 3, käufe REF(AuftragKundeTyp) MULTISET ansprechPartner REF(MitarbeiterTyp) ARRAY[3]) NOT INSTANTIABLE /* Eine Tabelle vom Typ PersonTyp kann nicht /* angelegt werden NOT FINAL
CREATE TYPE MitarbeiterTyp UNDER PersonTyp AS ( gehaltsKategorie VARCHAR(25), einstellung DATE, mitarbeiterStatus Statustyp DEFAULT ’aktiv’, abteilung REF(AbteilungTyp)) INSTANTIABLE NOT FINAL INSTANCEMETHOD gehalt() RETURNS DECIMAL(8,2), /*gehalt als Methode INSTANCEMETHOD betriebsZugehörigkeit() RETURNS SMALLINT,
CREATE TYPE ManagerTyp UNDER MitarbeiterTyp AS ( bonus DECIMAL(12,2), mitarbeiter REF(MitarbeiterTyp) MULTISET) INSTANTIABLE NOT FINAL INSTANCEMETHOD anzahlUntergeordnete() RETURNS DECIMAL(8,2),
Wie man an Beispiel 8.43 sehen kann, ist es nicht erlaubt, in der Untertypdeklaration die Artspezifikation der Objektidentität des Obertypen zu verändern, dass auf dem Weg nach unten keine Attributtypen verändert werden dürfen. Da die Objektidentität als ein implizites Attribut des Zeilentyps realisiert wird, würde ansonsten eine Typverletzung vorliegen.
8.3 Objektorientierte Konzepte in SQL:2011
531
Abstrakte Zeilentypen Ähnlich wie manche objektorientierte Programmiersprachen erlaubt auch das objektrelationale SQL das Anlegen von sogenannten abstrakten Zeilentypen. Hierbei handelt es sich um Zeilentypen, von denen keine Instanzen erzeugt werden dürfen. Solche Zeilentypen dienen nur der Modellierung. Soll beispielsweise sichergestellt werden, dass in unserer Unternehmensdatenbank niemals (versehentlich) eine Instanz von PersonTyp erzeugt werden kann, so wäre die PersonTyp-Deklaration um den Zusatz NOT INSTANTIABLE zu erweitern (siehe Beispiel 8.44, a.). Wird nichts spezifiziert ist INSTANTIABLE der Default. Weiterhin wird für abstrakte Zeilentypen keine Konstruktormethode angelegt, da eben keine Instanzen erzeugt werden können. Individualisierte Datentypen sind grundsätzlich INSTANTIABLE, da von ihnen keine Untertypen erzeugt werden können. Beispiel 8.44: Anlegen eines abstrakten Zeilentyps Die folgende Deklaration bewirkt, dass vom Typ PersonTyp keine Instanzen angelegt werden können. CREATE TYPE PersonTyp AS ( personName ROW ( personVorname VARCHAR(25), personNachname VARCHAR(25)), geburtsDatum DATE, personAdresse REF(AdresseTyp) ARRAY[3], REF USING AchtstelligeZahl /* PersonNr wird über die OID realisiert a. NOT INSTANTIABLE b. NOT FINAL
Schließlich kann noch spezifiziert werden, ob von einem benannten Zeilentyp weitere Untertypen ableitbar sind. Soll dies verhindert werden, ist FINAL anzugeben, ansonsten NOT FINAL (siehe Beispiel 8.44, b.), was auch den Default darstellt. Offensichtlich macht es keinen Sinn, ein Blatt der Typhierarchie (durch die Angabe von FINAL erzeugt) als NOT INSTANTIABLE zu deklarieren. Da von individualisierten Datentypen keine Untertypen abgeleitet werden dürfen, ist FINAL dort grundsätzlich zu spezifizieren. Überschreibende Methode Bei einer Untertypdeklaration können Methode von Obertypen überschrieben werde, d. h. durch eine verfeinerte Methodenimplementierung ersetzt werden. Zu diesem Zwecke ist die Beschreibung der Methodenschnittstelle um das Schlüsselwort OVERRIDING zu ergänzen (siehe Beispiel 8.45). Die eigentliche Methodenschnittstelle, also der Name, die Parametertypen und der Typ des Rückgabewertes dürfen nicht verändert werden. Beispiel 8.45: Überschreibende Methode Gegeben sei die Methode aus Beispiel 8.38. Angenommen es sei ein Untertyp ManagerTyp vom MitarbeiterTyp erzeugt worden. Für Manager soll gelten, dass ihre Betriebszugehörigkeit aufgrund der vermuteten längeren Ausbildungszeit um 6 Jahre verlängert wird. Die
532
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
damit notwendige überschreibende Methode wäre wie folgt bei der Definition von ManagerTyp einzuführen: OVERRIDING INSTANCE52 METHOD
betriebsZugehörigkeit () RETURNS INTERVAL YEAR TO MONTH
Der Methodenkörper könnte wie folgt aussehen: CREATE METHOD betriebsZugehörigkeit FOR ManagerTyp BEGIN DECLARE Zugehörigkeit INTERVAL YEAR TO MONTH; Zugehörigkeit := INTERVAL ’0-0’ YEAR TO MONTH; SELECT (CURRENT_DATE-einstellung) INTO Zugehörigkeit FROM Mitarbeiter WHERE mitarbeiterOID = SELF; Zugehörigkeit := Zugehörigkeit + INTERVAL ’6-0’ YEAR TO MONTH; RETURN Zugehörigkeit; END;
Vererbung und Verweise In Kapitel 8.2.2.3 war gesagt worden, dass der REF-Typkonstruktor typisiert ist. Dies bedeutet, dass in der CREATE TYPE-Klausel der benannte Zeilentyp angegeben wird, von dessen Typ der Verweis ist. In der CREATE TABLE-Anweisung muss dann konkretisiert werden, auf die Datensätze welcher Tabelle genau verwiesen werden darf. Im Lichte der Vererbung gilt hier die typische Semantik objektorientierter Systeme. Dort wo eine Instanz eines bestimmten Datentyps erwartet wird, darf auch eine Instanz eines Untertyps stehen. Tabellenhierarchie Die Tabellen- und Sichtenhierarchie orientieren sich in ihrem Aufbau beide an der Typhierarchie. Zu jedem Tabelleneintrag in der Tabellenhierarchie muss es einen analogen Eintrag in der Typhierarchie geben, umgekehrt aber nicht. Dies bedeutet, dass in der Tabellenhierarchie Wege verkürzt werden können, also auf dem Weg von einer Obertabelle zu einer direkten Untertabelle Tabellen ausgelassen werden können, womit in der Typhierarchie der äquivalente Untertyp kein direkter Untertyp des entsprechenden Obertyps der Obertabelle ist. Abstrakte Zeilentypen sind ein mögliches Beispiel für einen Typ, der zwar in der Typhierarchie angelegt ist, zu dem es aber kein Gegenstück in der Tabellenhierarchie geben kann. Wie bereits gesagt wird durch den CREATE TABLE-Befehl ein Container angelegt, in den Instanzen vom benannten Zeilentyp der Tabelle eingefügt werden können. Die Tabellenhierarchie gibt an, welche Tabellen von Untertypen des Tabellentyps auf der Ebene der Tabelle sichtbar sind. 52 Da die Methodenart bereits im Obertyp spezifiziert wurde, ist die INSTANCE-Aussage überflüssig, insbesondere, da die Methodenart des Obertyps nicht verändert werden darf.
8.3 Objektorientierte Konzepte in SQL:2011
533
Beispiel 8.46: Tabellenhierarchie im objektorientieren SQL Es wird zunächst eine Tabelle Person angelegt, von der die beiden Tabellen Manager und Kunden erben. Die Tabelle Mitarbeiter gibt es nicht, weshalb die Tabellenhierarchie weniger Einträge aufweist als die Typhierarchie. CREATE TABLE Person OF PersonTyp ( REF IS PersonOID SYSTEM GENERATED, Referenzauflösungen, Integritätsbedingungen) CREATE TABLE Manager OF ManagerTyp UNDER Person ( REF IS ManagerOID SYSTEM GENERATED, Referenzauflösungen, Integritätsbedingungen) CREATE TABLE Kunden OF KundenTyp UNDER Person ( REF IS KundeOID SYSTEM GENERATED, Referenzauflösungen, Integritätsbedingungen)
Die Vererbungsdefinition auf Ebene der Tabellen ist sehr simpel. Eine Tabelle kann von einer anderen Tabelle erben, wobei aber gegenüber dieser Tabelle weder neue Attribute noch neue Methoden hinzugefügt oder bestehende verändert werden dürfen. Solche Maßnahmen sind nur auf der Ebene der benannten Zeilentypen möglich. Stattdessen wird wie in Beispiel 8.46 gezeigt lediglich bei der Definition der Tabelle das UNDER-Statement hinzugefügt, durch welches festgelegt wird, unter welche Obertabelle die Instanzen der neuen Untertabelle sichtbar werden. Die Sichtbarkeit ist hier der wesentliche Faktor. Die Spezifikation von Beispiel 8.46 führt zu der in Beispiel 8.47 angegebenen Tabellenhierarchie. Sie sagt aus, dass alle in der Tabelle Manager und Kunden abgelegten Objekte als Default auch sichtbar sind, wenn z. B. eine Anfrage an die Tabelle Person gestellt wird. Die Trennung der Strukturdefinition über den CREATE TYPE-Befehl von der Containerdefinition über den CREATE TABLE-Befehl erlaubt es jetzt, dass beliebig viele Tabellen vom selben Typ angelegt werden können, so dass z. B. auch eine Tabellenhierarchie wie in Beispiel 8.48 entstehen könnte. Damit ist es auch möglich, dass ein Wald entsteht. Beispielsweise könnten mehrere Tabellen vom Typ PersonTyp angelegt werden. Dann wären mehrere Wurzeln vorhanden, die sich zu einer Menge von Bäumen entwickeln können. Grundsätzlich gilt also, dass ein Baum in der Tabellenhierarchie strukturell so aussehen muss, wie in der Typhierarchie festgelegt wurde. Allerdings kann ein Baum In der Tabellenhierarchie an einer beliebigen Stelle innerhalb der Typhierarchie starten. So könnte es in der Tabellenhierarchie auch einen Baum geben, der mit einer Tabelle vom MitarbeiterTyp als Wurzel startet. Ein Naderer Baum mag eine Tabelle vom Typ KundenTyp als Wurzel haben usw.
534
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Beispiel 8.47: Tabellen- und Typhierarchie Die Typhierarchie für Beispiel 8.43, ergänzt um den ManagerTyp sieht wie folgt aus:
PersonTyp
MitarbeiterTyp
KundenTyp
ManagerTyp Die Tabellenhierarchie für Beispiel 8.46 ist kürzer ausgefallen:
Person
Manager
Kunden
Beispiel 8.48: Tabellenhierarchie mit mehreren Tabellen vom selben Typ Bei der folgenden Tabellenhierarchie existieren drei Tabellen vom Typ ManagerTyp.
Person
ManagerProduktion
ManagerVertrieb
ManagerForschung
Kunden
Obwohl SQL:2011 nur Einfachvererbung unterstützt, könnte der eine oder andere auf die Idee kommen, diese „auszutricksen“, indem er eine Tabelle vom Zeilentyp ZT anlegt, wobei die Tabelle von einer Obertabelle T erbt, die kein Obertyp von ZT ist. Eine solche Konstruktion ist aber nicht erlaubt. Beispiel 8.49 liefert ein Beispiel für ein solches unerlaubtes Vorgehen. Es war die Absicht, die ArbeitetAn-Tabelle um die Produkt-Daten zu erweitern.
8.3 Objektorientierte Konzepte in SQL:2011
535
Beispiel 8.49: Nicht erlaubte Vererbung Die folgende Vererbung ist nicht erlaubt, da sie nicht mit der Typhierarchie konform ist. CREATE TABLE . . . );
ArbeitetAn OF ArbeitetAnTyp UNDER Produkt (
Wie bereits bei der Einführung von typisierten Tabellen diskutiert, können bei einer Tabellendefintion nur noch wenige Strukturangaben gemacht werden. Dies sind neben Integritätsbedingungen vor allem die Zielwertebereiche von Verweisen (REF), wenn sich Attribute auf den REF-Typkonstruktor abstützen. Es ist zu beachten, dass bei einer typisierten Tabelle T, die nicht vom Wurzeltyp der Typhierarchie ist, auf dem Vererbungsweg nach unten bis zum Zeilentyp ZT der Tabelle eine Anzahl von neuen Attributen in den auf den Weg liegenden Zeilentypen definiert werden können, die sich auf den Typkonstruktor REF abstützen. Bei der Tabellendefinition müssen alle diese Verweise aufgelöst werden, d.h. auf eine konkrete Tabelle ausgerichtet werden. In der Typhierarchie können abstrakte Zeilentypen festgelegt werden, also Zeilentypen, für die keine Tabelle angelegt werden kann. Auf der Ebene der Tabellen kann man so etwas nicht machen. In unserer Unternehmensdatenbank gibt es jetzt aber nur Mitarbeiter, Kunden und Manager, keine Personen. Demnach sollte es eigentlich auch keine Tabelle für Personen geben, da sie leer wäre. Aus Sichtbarkeitsgründen kann das aber trotzdem Sinn machen. Wenn es Anfragen gibt, die auf alle Mitarbeiter und Kunden ausgeführt werden sollen, wäre diese einfach auf der Tabelle von Personen zu formulieren, wenn es diese gäbe. Ansonsten müsste es eine Vereinigungsanfrage geben, die vergleichsweise komplex ist.
Mitarbeiter
Kunden
Manager
Person Mitarbeiter
Kunden
Manager a. Eigentlich nur notwendiger Wald
b. als Baum mit leerer Wurzel
Abb. 8.3: Alternative Tabellenhierarchien
Beispiel 8.50: Alternative Tabellenhierarchien Gegeben sei die folgende Anfrage: „Gib all Mitarbeiter und Kunden aus, die in Essen wohnen.“ a. Auf der Basis der Tabellenhierarchie von Abbildung 8.3 a. müsste die Anfrage wie folgt lauten:
536
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen personName.personVorname, personName.personNachname Mitarbeiter personAdresse→ort = ’Essen’;
SELECT FROM WHERE UNION SELECT FROM WHERE
personName.personVorname, personName.personNachname Kunden personAdresse→ort = ’Essen’;
Es sei hier explizit angemerkt, dass es sich hier um eine Mengenvereinigung handelt, die über die UNION-Klausel zu realisieren ist. Würde in der FROM-Klausel Mitarbeiter, Kunden stehen, würde es sich um eine Verbundoperation handeln, die eine ganz andere Semantik hat. b. Auf der Basis der Tabellenhierarchie von Abbildung 8.3 b. wäre die Anfrage deutlich einfacher zu stellen: Person
personName.personVorname, personName.personNachname Mitarbeiter personAdresse→ort = ’Essen’;
SELECT FROM WHERE
Mitarbeiter
Kunden
Manager
Beispiel 8.51: Zusammenspiel zwischen Typ- und Tabellenhierarchie
Typhierarchie
Tabellenhierarchie CREATE TABLE Einwohner OF PersonTyp
CREATE TYPE PersonTyp P
Obertyp ↑ Untertyp ↓
M CREATE TYPE MitarbeiterTyp UNDER PersonTyp
CREATE TABLE Person OF PersonTyp P
E
A
OberTabelle ↑ Untertabelle ↓
M CREATE TABLE Mitarbeiter OF MitarbeiterTyp UNDER Person CREATE TABLE Angestellter OF MitarbeiterTyp
P PersonTyp
P Person Tabelle
E Einwohner Tabelle
M MitarbeiterTyp
M Mitarbeiter Tabelle
A Angestellter Tabelle
8.3 Objektorientierte Konzepte in SQL:2011
537
Sichtenhierarchie Sichten werden gerne verwendet, um einerseits zu garantieren, dass Anwendungen nur die sie betreffenden Daten sehen, und andererseits, um den Anwendungen eine ihnen angenehme und passende Sicht auf die Daten innerhalb der DB zu geben. Letzteres bedeutet insbesondere, dass man sich von den Zwängen der Normalisierung wieder verabschiedet und Daten zusammenhängend, quasi als Objekte, der Anwendung zur Verfügung stellt. Wie bereits in Kapitel 7.5.4 diskutiert wurde, ist aus Sicht der Anwendungen ein wesentliches Problem mit Sichten die Durchführung von Änderungen auf dem darunter liegenden Datenbestand. SQL-92 hatte hier strikte Regeln definiert, mit der Konsequenz, dass oft auch Sichten dann nicht direkt geändert werden durften, wenn dies zu keinen Konsistenzproblemen geführt hätte. SQL:2011 stellt hier ein wesentlich ausgefeilteres Regelwerk zur Verfügung, welches sich auf funktionale Abhängigkeiten abstützt, ohne die eigentliche Syntax von Sichten zu ändern. Die Konsequenz ist, dass jetzt deutlich mehr Sichten änderbar sind. Genau wie typisierte Tabellen können jetzt auch typisierte Sichten spezifiziert werden. Das sind Sichten, die auf einem benannten Zeilentyp basieren. Dementsprechend müssen typisierte Sichten auch einer Vererbungshierarchie angehören. Diese Hierarchie bildet eine eigene Hierarchie, die Sichtenhierarchie. Ebenso wie die Tabellenhierarchie realisiert sie Sichtbarkeit. In einer Sichtenhierarchie werden nur typisierte Sichten aufgenommen, also Sichten, die auf einem benannten Zeilentyp aufbauen. Die Sichten alter Art können nicht in einer Hierarchie angeordnet werden. Syntax 8.1: Typisierte Sicht CREATE VIEW viewName OF StructuredType [UNDER SuperView] ( [ | WITH OPTIONS ]*) AS queryExpression [WITH CHECK OPTION])
Beispiel 8.52: Typisierte Sicht In der FROM-Klausel wird zwar jeweils das ONLY angegeben. Dies ist aber nicht nur der Default, sondern die einzige erlaubte Variante. Methoden können wie Attribute genutzt werden. Bei den langjährigen Mitarbeitern sind die Manager nicht mit in der Ergebnismenge. Bei der Sicht GutBezahlterMitarbeiter sind nach der Definition der Untersicht GutBezahlteManager auch die gut bezahlten Manager sichtbar. CREATE VIEW GutBezahlteMitarbeiter OF MitarbeiterTyp ( personAdresse WITH OPTIONS SCOPE Adresse, abteilung WITH OPTIONS SCOPE Abteilung, REF IS GutBezahlMitOID USER GENERATED) AS (SELECT * FROM ONLY(Mitarbeiter) WHERE gehalt > 10000)
538
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
GBMi
LM
GBMa
GM
GBMi: GutBezahlteMitarbeiter GBMa: GutBezahlteManager LM: LangjährigeMitarbeiter GM: GuterManager
CREATE VIEW GuterManager OF ManagerTyp ( personAdresse WITH OPTIONS SCOPE Adresse, abteilung WITH OPTIONS SCOPE Abteilung, mitarbeiter WITH OPTIONS SCOPE Mitarbeiter, REF IS GutBezahlMitOID USER GENERATED) AS (SELECT * FROM ONLY(Manager) WHERE anzahlUntergeordnet > 30)
CREATE VIEW LangjährigeMitarbeiter OF MitarbeiterTyp ( personAdresse WITH OPTIONS SCOPE Adresse, abteilung WITH OPTIONS SCOPE Abteilung, REF IS GutBezahlMitOID USER GENERATED) AS (SELECT * FROM ONLY(Mitarbeiter) WHERE betriebszugehörigkeit > 25)
GutBezahlteManager OF ManagerTyp UNDER GutBezahlteMitarbeiter ( personAdresse WITH OPTIONS SCOPE Adresse, abteilung WITH OPTIONS SCOPE Abteilung, REF IS GutBezahlMitOID USER GENERATED) AS (SELECT * FROM ONLY(Manager) WHERE gehalt > 80000)
CREATE VIEW
Für das folgende Beipiel sei angenommen, dass die zunächst angegebene Typdefinition existiert. Die Sicht GuterKunde enthält alle die Kunden, bei denen die Auswertung der Methode anzahlAufträgeLetzte12Monate einen Wert von über 20 ergibt. Es handelt sich hier also um eine Mengeneinschränkung (gegenüber Kunden). Es sei noch einmal darauf hingeweisen, dass die Typdefinition zur Sicht bereits existieren muss. CREATE TYPE ErweiterterKundenTyp UNDER KundenTyp AS ( INSTANTIABLE NOT FINAL INSTANCE METHOD anzahlAufträgeLetzte12Monate() RETURNS SMALLINT,
8.3 Objektorientierte Konzepte in SQL:2011
539
CREATE VIEW GuterKunde OF ErweiterterKundenTyp (( personAdresse WITH OPTIONS SCOPE Adresse, käufe WITH OPTIONS SCOPE AuftragKunde, ansprechPartner WITH OPTIONS SCOPE Mitarbeiter, REF IS GuterKundeNr USER GENERATED) AS (SELECT * FROM ONLY(Kunden) WHERE anzahlAufträgeLetzte12Monate > 20) Wie die Tabellenhierarchie muss sich auch die Sichtenhierarchie in ihrer Struktur nach der Typhierarchie richten. Beide bauen also auf derselben Grundlage auf. Trotzdem müssen sie streng getrennt voneinander geführt werden, Tabellen ausschließlich in der Tabellenhierarchie und Sichten ausschließlich in der Sichtenhierarchie. Nun führt eine Sicht möglicherweise einen neuen Zeilentyp ein, da Sichten Daten gerne anders darstellen. Da im Falle von Vererbung dann unklar wäre, wo dieser neue Zeilentyp in der Typhierarchie eingeordnet werden kann, wie genau sein Aufbau ist und welche Methoden und Methodenimplementierungen ihm zuzuordnen sind, muss dies vom Datenbankadministrator zunächst festgelegt werden, indem ein entsprechender benannter Zeilentyp für diese neue Sicht definiert und in die Typhierarchie eingeordnet wird. Erst dann kann eine Sicht von diesem Typ definiert werden. Die Tatsache, dass es für eine Sicht eine entsprechende Zeilentypdefinition in der Typhierarchie geben muss, impliziert schon sehr deutlich, dass typisierte Sichten nicht beliebig erstellt werden können. Da es keine Mehrfachvererbung gibt, ist es vergleichsweise schwierig, eine Zeilentypdefinition in der Typhierarchie unterzubringen, die aus einem Verbund mehrerer bereits definierter Zeilentypen hervorgeht, womöglich auch noch gepaart mit einer Projektion. Allerdings muss auch klar und deutlich gesagt werden, dass das objektrelationale SQL in seinen Anfragen und seiner Zeilentypdefinitionen auch völlig andere Schwerpunkte setzt als das konventionelle SQL. Verbünde sind eher als ganz große Ausnahme anzusehen, da Beziehungen entweder durch das direkte Einbinden von Unterobjekten realisiert werden können oder über Verweise. Insgesamt kann eine hochgradig vermaschte Datenstruktur entstehen. Eine Verbundoperation weist da schon fast auf einen Modellierungsfehler hin. Da jetzt auch mehrwertige Attribute kein Problem mehr sind, spielt auch die Normalisierungstheorie keine Rolle mehr, d.h. das „willkürliche“ Auseinanderreißen von Realobjekten in mehrere Tabellen ist nicht mehr notwendig. Die obige Diskussion macht schon klar, dass Sichten im objektrelationalen Umfeld eine ganz andere Rolle spielen als im konventionellen SQL. Genau genommen wird ihre Existenz wegen des komplexen Umgangs mit ihnen implizit ein Stück weit in Frage gestellt. Zunächst muss man sich fragen, was der Unterschied zwischen einer Tabelle und einer Sicht ist. Im konventionellen SQL dienten Sichten vielen Zwecken, konnten relativ einfach angelegt werden und stellten eine on-the-fly erzeugte und nur temporäre Datenmenge zur Verfügung. Es sollen beispielhaft einige typische Situationen durchgespeilt werden. 1. Sichten können, wie oben bereits diskutiert, den Auseinanderreiß-Effekte der Normalisierung aufheben, indem sie Objekte wieder als Ganzes zur Verfügung stellen. Da das objektrelationale SQL hier ein wesentlich mächtigeres Datenbankmodell anbietet, spielt die Normalisierung keine Rolle mehr. 2. Beim konventionellen SQL dienen Sichten auch dem Datenschutz, indem Teile der Daten ausgeblendet wurden. Grundsätzlich ist das beim objektrelationalen SQL auch noch mög-
540
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
lich. Allerdings führt das notwendige Erstellen eines entsprechenden Zeilentyps zu einem Aufblähen der Typhierarchie und damit zu mehr Unübersichtlichkeit. 3. Grundsätzlich sind Sichten im konventionellen Fall, insbesondere wenn sie als reine Lesesichten angelegt werden, auch gerne über Verbund- und Projektionsoperatoren spezifiziert worden. Solche Operatoren bieten sich aus dem oben gesagten bei objektrelationalen Sichten nicht mehr an. Wenn man sich jetzt fragt, warum es neben den Tabellen noch Sichten gibt, so gibt es vor allem noch zwei sinnvolle Anwendungsmöglichkeiten. 1. Sichten sind zunächst einmal temporär, was impliziert, dass ein Zeilentyp für eine Sicht keine neuen Attribute spezifizieren darf, da deren Werte nicht dauerhaft abgelegt werden können. Somit kann es nur sein, dass über Methoden abgeleitete Attribute hinzukommen. In diesem Fall dienen Sichten vor allem der Aufgabe, den vorhandenen Datenbestand auszubereiten und zusätzliche Informationen aus den vorhandenen abzuleiten (siehe als Beispiel die letzte Sichtendefinitionen in Beispiel 8.52). 2. Im objektorientierten Umfeld ist eine Klasse eine Unterklasse, falls sie entweder die vorhandene Struktur erweitert oder etwas anders darstellt oder falls die Klasse eine Untermenge der Objekte der Oberklasse repräsentiert. Beim objektrelationalen SQL kann dieser zweite Aspekt in der Typhierarchie keine Rolle spielen, da dort nur über die Struktur entschieden wird. Der Mengenaspekt kommt allerdings in der Tabellen- und Sichtenhierarchie zum Tragen. Eine Sicht, die auf einen bestehenden Zeilentyp basiert und nur eine Mengeneinschränkung umsetzt, kann also sehr wohl noch viel Sinn machen (siehe als Beispiel die ersten drei Sichtendefinitionen in Beispiel 8.52). Beispiel 8.53: Zusammenspiel zwischen Typ- und Sichtenhierarchie Typhierarchie
Sichtenhierarchie
CREATE TYPE PersonTyp
P
Obertyp ↑ Untertyp ↓
Mi
CREATE TYPE MitarbeiterTyp UNDER PersonTyp
Ma
Obertyp ↑ Untertyp ↓ CREATE TYPE ManagerTyp UNDER MitarbeiterTyp P
Person-
Ma ManagerTyp
Mi
CREATE VIEW LangjährigeMitarbeiter OF MitarbeiterTyp GBMi
LM
GBMa CREATE VIEW GutBezahlteMitarbeiter OF MitarbeiterTyp Obersicht ↑ Untersicht ↓ CREATE VIEW GutBezahlteManager OF ManagerTyp UNDER GutBezahlteMitarbeiter
MitarbeiterTyp
GBMi GutBezahlteMitarbeiter
LM
LangjährigeMitarbeiter
GBMa GutBezahlteManager
8.3 Objektorientierte Konzepte in SQL:2011
541
Feststellung 8.6: Sichtenhierarchie Die Sichtenhierarchie ist eine Sichtbarkeitshierarchie, die aus allen existierenden typisierten Sichten besteht und nur aus diesen. Sie existiert vollständig neben der Tabellenhierarchie. Jede typisierte Sicht muss von einem Typ sein, der in der Typhierarchie bereits vorhanden ist. Wird die Sicht über eine Anfrage erzeugt, gilt für die in der FROM-Klausel benutzte Tabelle oder Sicht, dass hier nur die Instanzen genau dieser Tabelle bzw. Sicht berücksichtigt werden. Instanzen von Untertabellen bzw. -sichten werden nicht berücksichtigt (entspricht der ONLY-Sichtbarkeitsoption (siehe Beispiel 8.55 a.)). Wird allerdings in Anfragen auf Sichten zugegriffen, gilt die übliche Sichtbarkeit, d.h. auf Ebene einer Sicht sind als Default alle Instanzen dieser Sicht und aller Untersichten dieser Sicht sichtbar. Ebenso wie bei der Tabellenhierarchie ist anzugeben, wie die OID heißen soll und auf welche Tabellen die REF-Attribute des zu Grunde liegenden Zeilentyps verweisen sollen. Verweise auf Datensätze von Sichten sind nicht möglich.
8.3.6
Polymorphismus
Polymorphismus ist einer der Begriffe, der in unterschiedlichen Umfeldern unterschiedlich definiert wird. Für uns hier von Interesse ist Polymorphismus im Zusammenhang mit der Methodenausführung. Innerhalb einer Typhierarchie kann es für dieselbe Methodenschnittstelle unterschiedliche Implementierungen geben. Polymorphismus ist eng assoziiert mit Substituierbarkeit. Letztere bedeutet, dass überall dort, wo eine Instanz von einem bestimmten Typ erwartet wird, auch eine Instanz eines Untertyps stehen darf. In Programmiersprachen war man immer sehr darauf bedacht, Typsicherheit zu garantieren. Dies bedeutet, dass bereits zur Übersetzungszeit geprüft wird, ob Zuweisungen, Ausdrücke und Methodenaufrufe typgerecht belegt sind. Damit wird sichergestellt, dass während der Laufzeit immer dann, wenn ein bestimmter Typ erwartet wird, dieser auch sicher bereitgestellt wird, ein Typfehler also nicht auftreten kann. Typsicherheit ging lange einher mit statischem Binden. Wo immer eine Routine innerhalb des Programmcodes aufgerufen wird, wurde die dazugehörige Implementierung zur Übersetzungszeit bestimmt und an den Routinenaufruf gebunden. Im Zeitalter von Polymorphismus und Substituierbarkeit ist von diesem Konzept nur die Typsicherheit geblieben. Das Ermitteln der richtigen Methodenimplementierung geschieht zur Laufzeit. Die Frage ist, wie ist es möglich, dass zur Übersetzungszeit sichergestellt werden kann, dass die Typsicherheit nicht verletzt wird, andererseits aber das Ermitteln der korrekten Methodenimplementierung im Allgemeinfall noch nicht möglich ist. Das Geheimnis liegt in der Vererbung und den Regeln, die mit dieser kommen. Auf dem Weg nach unten darf nur hinzugefügt, nicht aber weggenommen werden. Da auf einen Typ ausschließlich über seine Schnittstelle zugegriffen werden kann, ist also garantiert, dass auch alle Untertypen mindestens dieselbe Schnittstelle zur Verfügung stellen (meistens jedoch eine Obermenge). Wenn also an einer bestimmten Stelle ein bestimmter Typ erwartet wird, kann dort ohne Gefährdung der Typsicherheit auch eine Instanz eines Untertyps stehen, da sichergestellt ist, dass der Untertyp mindestens die gleichen Methoden ausführen kann wie der Obertyp. Allerdings kann wegen der Tatsache, dass Methoden auf dem Weg von oben nach unten überschrieben werden können, erst nach Feststellung des konkreten Typs die dazugehörige Methodenimplementierung bestimmt werden. Und dies ist offensichtlich erst zur Laufzeit möglich. Man spricht dann von dynamischem Binden.
542
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
PersonTyp
MitarbeiterTyp
ManagerTyp
SeniorManagerTyp
AngestellterTyp
KundenTyp
GuteKundenTyp
JuniorManagerTyp
Abb. 8.4: Erweiterte Typhierarchie
Bleibt noch eine Frage zu klären und das ist, was denn die korrekte Implementierung zu einem bestimmten Typ ist. Zur Beantwortung diese Frage betrachten wir die erweiterte Typhierarchie von Abbildung 8.4 und nehmen an, dass es dazu eine äquivalente Tabellenhierarchie mit identischen Tabellennamen (also ohne den Zusatz Typ) gibt. Angenommen zur Laufzeit wird eine Instanz vom Typ Person erwartet, da die Methode personName() aufgerufen wird. Substituierbarkeit bedeutet nun, dass an dieser Stelle eine beliebige Instanz eines Untertyps stehen darf, also z. B. eine von SeniorManagerTyp oder GuteKundenTyp. Da personName ein Attribut von PersonTyp ist, besitzt es eine nicht überschreibbare Observer-Methode53. Damit beantwortet sich die Frage von selbst, welche Methodenimplementierung abzuarbeiten ist. Nehmen wir jetzt einmal an, die folgende Anfrage sei gestellt worden: SELECT FROM
betriebszugehörigkeit Mitarbeiter;
Da keine Einschränkung bzgl. der angesprochenen Tabellenhierarchie angeben wurde, ist die gesamte Hierarchie angesprochen. Für MitarbeiterTyp und ManagerTyp gibt es eine Methodenimplementierung, die mit diesem Typ angelegt wurde (siehe Beispiel 8.38 und die überschreibende Methode in Beispiel 8.45). Bei den anderen Untertypen ist die korrekte Methodenimplementierung wie folgt zu bestimmen. Ausgehend vom Typ der konkreten Instanz suche die richtige Methodenimplementierung wie folgt: S1: Prüfe ob es in der Typspezifikation des Typs eine Methodenimplementierung zur gesuchten Methode gibt. Falls ja, nimm diese und gehe zu Ende. S2: Gehe in der Typhierarchie einen Typ hoch zum direkten Obertyp des aktuellen Typs. Gehe zu S1. Ende: 53 Da
der Aufruf der Methode ohne Parameter erfolgt, ist die Observer- und nicht die Mutator-Methode aufgerufen.
8.3 Objektorientierte Konzepte in SQL:2011
543
Bezogen auf unser Beispiel würde der Algorithmus zu folgenden Ergebnissen führen: • Für Instanzen von Angestellte würde die Methodenimplementierung von MitarbeiterTyp ausgeführt werden. • Für Instanzen von Senior- und Juniormanager würde die Methodenimplementierung von ManagerTyp ausgeführt werden. Man beachte, dass für die korrekte Auswahl einer Methode die Typhierarchie entscheidend ist. Falls also auf der Ebene der Tabellenhierarchie der Manager ausgelassen wurde (weil es nur Senior- oder Juniormanager gibt), so wird trotzdem die Methode von ManagerTyp und nicht die von MitarbeiterTyp ausgeführt. Gleiches gilt, falls es Einschränkungen bzgl. der Tabellenhierarchie gibt, die bei der Abarbeitung der Anfrage zu berücksichtigen sind. Man beachte ferner, dass die Typsicherheit garantiert, dass der Algorithmus von oben erfolgreich terminieren wird. Zusammenfassung der Merkmale benannter Zeilentypen/typisierter Tabellen Die Definition eines benannten Zeilentyps setzt sich aus seiner Datenstruktur- und seiner Methodenspezifikation zusammen. Die Datenstrukturspezifikation ist von außen nicht sichtbar, bleibt also dem Anwender/Benutzer verborgen. Die Datenstruktur kann beliebig komplex aufgebaut sein, wobei Attribute insbesondere nicht atomar sein müssen. Sie können mehrwertig (ARRAY, MULTISET) oder zeilenwertig (ROW) sein oder einen Verweis (REF) auf eine Instanz einer (meist anderen) Tabelle beinhalten. Datenabstraktion ist voll umgesetzt, was bedeutet, dass auf Instanzen einer Tabelle nur über die zur Verfügung gestellten Methoden zugegriffen werden kann. Dabei sind alle Methoden vom Datenbankprogrammierer im Methodenspezifikationsblock des zu Grunde liegenden Zeilentyps zu erstellen. Ausnahmen bilden nur die Observer- und Mutator-Methode als Lesebzw. Modifikationsmethode für jedes (atomare) Attribut des benannten Zeilentyps und die Konstruktormethode, mit der neue Instanzen des Zeilentyps kreiert werden können. Diese Methoden sind nicht überschreibbar. Jeder Instanz einer typisierten Tabelle wird ein eindeutiger Schlüssel zugewiesen. Ist nichts anderes deklariert worden, wird implizit ein systemvergebener Schlüssel zugewiesen. Der Schlüssel ist systemweit eindeutig und unveränderlich und identifiziert eine Instanz während ihrer gesamten Lebensdauer. Benannte Zeilentypen können in einer Typhierarchie und typisierte Tabellen in einer Tabellenhierarchie angeordnet werden. Beide Hierarchien sind baumartig, d. h. es wird nur Einfachvererbung unterstützt. Die Typhierarchie ist dominierend, d. h. sie legt die eigentliche Vererbungshierarchie fest. Dabei erbt ein direkter Untertyp von seinem direkten Obertyp alle Attribute und Methoden. Es können neue Attribute und Methoden hinzugefügt und bestehende Methoden überschrieben werden. Die Tabellenhierarchie ähnelt in ihrem Aufbau der Typhierarchie, d. h. zu jedem Tabelleneintrag in der Tabellenhierarchie muss es einen analogen Eintrag in der Typhierarchie geben, umgekehrt aber nicht. Dies bedeutet, dass in der Tabellenhierarchie Wege verkürzt werden können. Ähnlich den abstrakten Klassen in objektorientierten Systemen können Zeilentypen existieren, die nicht instanziierbar sind. Diese sind ein mögliches Beispiel für einen Typ, der zwar in der Typhierarchie angelegt ist, zu dem es
544
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
aber kein Gegenstück in der Tabellenhierarchie geben kann. Wie üblich bei Vererbung wird dynamisches Binden und Substituierbarkeit unterstützt. Immer dort, wo eine Instanz eines bestimmten Typs erwartet wird, kann auch eine Instanz eines Untertyps auftreten. Zur Laufzeit wird die am besten passende Methodenimplementierung zu einem Methodenaufruf bestimmt. Dies ist die Methodenimplementierung, die entweder in dem Zeilentyp definiert wurde, von dem die aktuelle Instanz ist, oder diejenige, die vom aktuellen Zeilentyp aus gesehen auf dem Weg nach oben (Obertypenpfad) als erstes erreicht wird.
8.3.7
Anfragen im objektrelationalen SQL
Grundsätzlich müssen sich die Fähigkeiten und die Mächtigkeit eines Datenbankmodells auch in seiner Anfragesprache widerspiegeln. Beim objektrelationalen SQL hat sich die Modellierungsmächtigkeit deutlich verbessert, so dass auch die Anfragesprache diese zusätzliche Mächtigkeit ausnutzen können muss. Anfragen und komplexe Objekte Ein paar Erweiterungen wurden bereits vorgestellt. So können überall dort, wo im konventionellen SQL54 Attribute eingesetzt wurden, jetzt auch Methoden verwendet werden.55 Weiterhin gilt, dass innerhalb von komplexen Objekten navigiert werden kann. Handelt es sich um direkt eingebundene Unterobjekte, geschieht dies über die Punktnotation. Bei Referenzen muss entweder mit dem DEREF-Operator und der Punktnotation gearbeitet werden oder es muss die Pfeilnotation genutzt werden. Nun ist es so, dass eine Anfrage immer eine eindeutige Interpretation zulassen muss. Solange also mit der Punkt- oder Pfeilnotation immer ein eindeutiger Pfad weiterverfolgt wird, gibt es keine Probleme – egal, wie lang der Pfad wird (siehe beispielsweise Beispiel 8.54 a. und b.). Diese Eindeutigkeit ist allerdings nur so lange gegeben, wie beim Aufbau des komplexen Objekts kein ARRAY oder MULTISET-Typkonstruktor verwendet wurde. Sobald die ins Spiel kommen, wird es mehrdeutig. Beim ARRAY kann man Eindeutigkeit noch dadurch erreichten, dass eine spezifische Position innerhalb des ARRAYs direkt angesprochen wird. Weiß man aber nicht, welche Position des ARRAYs den richtigen Wert aufweist, wird es schwieriger. Dann muss mit Mengen bzw. alternativen Pfaden umgegangen werden. Dazu gibt es zwei Möglichkeiten. Wenn es ausreicht, das Vorhandensein eines Wertes bestätigt zu bekommen, können die bereits vom konventionellen SQL bekannten mengenwertigen Operatoren IN, EXISTS, ANY oder SOME und ALL genutzt werden (siehe Beispiel 8.54 c). Wenn der Pfad weiter verfolgt werden soll, also demnach das mehrfache Vorkommen eines Wertes auch relevant ist, hilft der UNNEST-Operator (siehe Beispiel 8.54 b, zweite Variante und Beispiel 8.54 c). Vorteilhaft ist dieser insbesondere auch beim ARRAY, da er das sequentielle Durchlaufen aller ARRAY-Positionen über AND oder OR-verknüpfte Prädikate in der WHEREKlausel vermeidet, wie Beispiel c. dokumentiert. Beispiel 8.54: Anfragen auf komplexen Objekten 54 SQL
hier im engen Sinne einer Anfragesprache. hier sauber zu bleiben, sei noch einmal darauf hingewiesen, dass in Anfragen sowieso nur noch Methoden verwendet werden dürfen. Zu jedem intern angelegten Attribute werden ja automatisch die dazugehörigen Methoden angelegt. Wenn hier jetzt von Methoden die Rede ist, sind vor allem die gemeint, die in der Methodendeklaration von benannten Zeilentypen noch zusätzlich angelegt wurden. 55 Um
8.3 Objektorientierte Konzepte in SQL:2011
545
Die folgenden Beispiele beruhen auf dem in Kapitel 8.3.9 beschriebenen objektrelationalen Datenbankschema. a. „Gib den Namen aller Zulieferer aus, die ihr Konto bei der Bad Bank haben.“ SELECT zuliefererName FROM Zulieferer WHERE bankDaten.bank=’Bad Bank ’); b. „Gib den Vor- und Nachnamen aller Mitarbeiter aus, die in einer Abteilung arbeiten, die von einem Manager mit dem Vornamen Angela geführt wird.“ Hier wird unterstellt, dass es nur einen Manager gibt. SELECT personName.personVorname, personName.personNachname FROM Mitarbeiter WHERE Mitarbeiter→Abteilung→leiter.personName.personVorname=’Angela’; Falls es mehrere Manager gibt, kann die Anfrage wie folgt gestellt werden: SELECT personName.personVorname, personName.personNachname FROM Mitarbeiter AS M WHERE EXISTS (SELECT * FROM M→abteilung, UNNEST(leiter) AS L WHERE L.personName.personVorname=’Angela’); Grundsätzlich hätte man bereits im äußeren FROM-Statement ein UNNEST auf abteilung machen können. Es können dann ziemlich große Tabellen entstehen. Diese entstehen aber erst einmal nur theoretisch, da es Aufgabe des Optimierers ist, die entstehende Datenmenge durch geschickte Operationsverschiebungen möglichst klein zu halten. Man kann sich aber sicherlich vorstellen, dass dies eine höchst anspruchsvolle Aufgabe ist, die nicht immer optimal erledigt werden kann. c. „Gib den Namen aller Zulieferer aus, die eine Niederlassung in Essen haben.“ In der folgenden Anfrage wird im eingebetteten SFW-Block das ARRAY mit den Adressen des gerade in der Überprüfung befindlichen Zulieferers flach geklopft, indem eine Tabelle A aufgebaut wird, die aus allen Adressreferenzen dieses Zulieferers besteht. In der dazugehörigen WHERE-Klausel wird jetzt über den verweis der Ort überprüft. Wenn die Auswertung aller Adressen mindestens einen Treffer ergibt, wird der Name des Zulieferers ausgegeben. SELECT zuliefererName FROM Zulieferer WHERE EXISTS (SELECT FROM FROM
* UNNEST(zuliefererAdresse) AS A A→ort = ’Essen’);
546
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen Äquivalent zur obigen WHERE-Klausel sind die folgenden WHERE-Klauseln: WHERE ’Essen’ IN (SELECT FROM WHERE ’Essen’=ANY (SELECT FROM
A→ort UNNEST(zuliefererAdresse) AS A); A→ort UNNEST(zuliefererAdresse) AS A);
Anfragen und Vererbung Soll eine Anfrage an eine Tabellenhierarchie gestellt werden, so möchte man nicht immer als Ergebnis alle Datensätze bekommen, die in der in der WHERE-Klausel spezifizierten Tabelle und all ihren Untertabellen abgespeichert sind. Manchmal möchte man nur Datensätze aus genau der spezifizierten Tabelle oder höchstens noch welche aus bestimmten Untertabellen sehen. Dies kann in SQL:2011 über die ONLY-Klausel oder über die DEREF-Klausel festgelegt werden. In Beispiel 8.55 a. werden aus der um Mitarbeiter erweiterten Tabellenhierarchie von Beispiel 8.46 nur alle Mitarbeiter ausgegeben, die in der Tabelle Mitarbeiter abgelegt sind, nicht aber auch noch die Manager der Untertabelle Manager. In Beispiel 8.55 1b. wird dasselbe über die DEREF-Klausel ausgedrückt. Der Default ist, dass die Tabelle mit allen ihren Untertabellen sichtbar ist.
Beispiel 8.55: Einschränkung der abzuarbeitenden Tabellenhierarchie bei Anfragen a. Es sollen nur Mitarbeiter, die in Essen wohnen, ausgegeben werden, aber keine Manager. Es wird unterstellt, dass die Tabellenhierarchie von Beispiel 8.46 zu Grunde liegt, allerdings erweitert um Mitarbeiter, was sie identisch zur Typhierarchie macht.
Person SELECT FROM WHERE
personName, personVorname ONLY (Mitarbeiter) personAdresse[1]->ort = ’Essen’;
Mitarbeiter
Kunden
Manager b. Dieses ist die gleiche Anfrage wie in a., nur wird dieses Mal die Auswahl der richtigen Tabelle in der WHERE-Klausel vorgenommen. personOID ist die Objektidentität, die vom Zeilentyp PersonTyp geerbt wurde. SELECT FROM WHERE
personName, personVorname Mitarbeiter personAdresse[1]->ort = ’Essen’ AND DEREF (personOID) IS OF (Mitarbeiter)
Person Mitarbeiter Manager
Kunden
8.3 Objektorientierte Konzepte in SQL:2011
547
c. In diesem Beispiel werden alle Personen gesucht, die entweder in der Tabelle der Manager oder der Kunden abgelegt sind. SELECT personName, personVorname Person FROM Person WHERE personAdresse[1]->ort = ’Essen’ Mitarbeiter Kunden AND DEREF (personOID) IS OF (Manager OR Kunden) Manager
Beispiel 8.56: Anfragen und Sichtbarkeit Es sollen die Vor- und Nachnamen aller Mitarbeiter des Unternehmens ausgegeben werden, die in Essen wohnen. Auf der Basis der Tabellenhierarchie von Abbildung 8.5 würde die folgende Anfrage SELECT FROM WHERE
personName.personVorname, personName.personNachname Mitarbeiter personAdresse→ort = ’Essen’;
nur die Mitarbeiter ausgeben, die keine Manager sind. Um wirklich alle Mitarbeiter zu bekommen, müsste die Anfrage wie folgt gestellt werden: SELECT FROM
personName.personVorname, personName.personNachname Mitarbeiter
Typhierarchie
Tabellenhierarchie
CREATE TYPE PersonTyp Obertyp ↑ Untertyp ↓ CREATE TYPE MitarbeiterTyp UNDER PersonTyp
CREATE TABLE Mitarbeiter OF MitarbeiterTyp
Obertyp ↑ Untertyp ↓ CREATE TYPE ManagerTyp UNDER MitarbeiterTyp
CREATE TABLE Manager OF ManagerTyp
Abb. 8.5: Typhierarchie und unverbundene Tabellenhierarchien
548
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen Tabellenhierarchie
Typhierarchie CREATE TYPE PersonTyp Obertyp ↑ Untertyp ↓ CREATE TYPE MitarbeiterTyp UNDER PersonTyp
CREATE TABLE Mitarbeiter OF MitarbeiterTyp OberTabelle ↑ Untertabelle ↓
Obertyp ↑ Untertyp ↓ CREATE TYPE ManagerTyp UNDER MitarbeiterTyp
CREATE TABLE Manager OF ManagerTyp
Abb. 8.6: Typhierarchie und verbundene Tabellenhierarchien
WHERE UNION SELECT FROM WHERE
personAdresse→ort = ’Essen’; personName.personVorname, personName.personNachname Manager personAdresse→ort = ’Essen’;
Wenn die erste Variante der Anfrage oben auf Basis der Tabellenhierarchie von Abbildung 8.6 gestellt worden wäre, wären gleich alle Mitarbeiter inklusive aller Manager ausgegeben worden. Beispiel 8.57: Anfragen und Sichtbarkeit bei eingefügter leerer OberTabelle Es sollen die Vor- und Nachnamen aller Mitarbeiter und Kunden des Unternehmens ausgegeben werden, die in Essen wohnen. Auf der Basis der Tabellenhierarchie von Abbildung 8.7 müsste die folgende Anfrage gestellt werden: SELECT FROM WHERE UNION SELECT FROM WHERE
personName.personVorname, personName.personNachname Mitarbeiter personAdresse→ort = ’Essen’; personName.personVorname, personName.personNachname Kunden personAdresse→ort = ’Essen’;
Gerade wenn es viele Tabellen auf gleicher Ebene geben sollte, könnte es Sinn machen, eine künstliche leere Obertabelle einzufügen, da dann Anfragen deutlich kürzer und über-
8.3 Objektorientierte Konzepte in SQL:2011
549 Tabellenhierarchie
Typhierarchie CREATE TYPE PersonTyp
CTY MitarbeiterTyp UNDER PersonTyp
CTY KundenTyp UNDER PersonTyp
CTY KundenTyp UNDER PersonTyp
CTY: CREATE TYPE CTA: CREATE TABLE
CTA Mitarbeiter OF MitarbeiterTyp
CTA Kunden OF MitarbeiterTyp
CTA Manager OF ManagerTyp UNDER Mitarbeiter
Abb. 8.7: Anfragen und Sichtbarkeit ohne eingefügte leere OberTabelle
Tabellenhierarchie
Typhierarchie CREATE TYPE PersonTyp
CREATE TABLE Person OF PersonTyp
CTY MitarbeiterTyp UNDER PersonTyp
CTY KundenTyp UNDER PersonTyp
CTA Mitarbeiter OF MitarbeiterTyp UNDER Person
CTY KundenTyp UNDER PersonTyp
CTY: CREATE TYPE CTA: CREATE TABLE
CTA Kunden OF MitarbeiterTyp UNDER Person
CTA Manager OF ManagerTyp UNDER Mitarbeiter
Abb. 8.8: Anfragen und Sichtbarkeit bei eingefügter leerer OberTabelle
sichtlicher gestellt werden können. Die Anfrage von oben würde auf Basis der Tabellenhierarchie von Abbildung 8.8 wie folgt aussehen: SELECT FROM WHERE
personName.personVorname, personName.personNachname Person personAdresse→ort = ’Essen’;
550
8.3.8
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Anmerkungen zu komplexen Objekten im objektrelationalen SQL
Während das objektrelationale SQL auf der Konzeptebene noch einen übersichtlichen und umsetzbaren Eindruck hinterlässt, ist die Entwicklung der notwendigen Implementierungskonzepte noch eine wirkliche Herausforderung. Im Grunde genommen müssen viele bisherigen Konzepte komplett aufgegeben werden und völlig neue entwickelt werden. Wenn man bedenkt, dass das relationale Datenbankmodell mehr als 20 Jahre gebraucht hat, um von einer Idee zu einem auch aus Performanzsicht konkurrenzfähigen Datenbankmanagementsystem zu werden, kann man sich in etwa vorstellen, wie massiv diese Herausforderung ist. Auf der Ebene der Implementierung sind eine Anzahl von Problemen zu lösen. Eines ist, dass ein tabellenwertiges Attribut keine feste Größe hat, sondern, im Gegenteil, in ihrer Größe deutlich schwanken kann. Bis zur Einführung von LOBs galt das unumstößliche Gesetz, dass Datensätze eine feste Größe haben. Bei LOBs handelt es sich um einen sehr speziellen Datentyp, der zwar sehr groß sein kann, aber nicht weiter strukturiert ist. Deshalb kann er bei der assoziativen Suche auch nur sehr eingeschränkt eingesetzt werden. LOBs werden häufig getrennt von den anderen Daten gespeichert und verwaltet. Insbesondere werden sie auch nicht gleich vollständig an die Anwendung übergeben, falls diese auf den sie umfassenden Datensatz zugreift. Tabellenwertige Attribute verhalten sich wie normale Tabellen, weshalb deren Einführung auch mit erheblichen Revisionen der Speicherungsstrukturen und Zugriffspfade verbunden sein muss, will man auch weiterhin eine akzeptable Performanz garantieren. Ein weiteres wesentliches Implementierungsproblem ist die Frage, wie bei solch komplex strukturierten Objekten ein performanter Zugriff garantiert werden kann. Grundsätzlich ist es möglich, eine riesige Datenmenge in ein Objekt zu packen, z. B. unsere gesamte Unternehmensdatenbank. Damit müssen effiziente Zugriffsstrukturen innerhalb von Objekten angeboten werden, eine Anforderung, die nicht so einfach zu lösen ist, wie man an den entsprechenden Versuchen bei objektorientierten DBMS sehen kann56.
8.3.9
Beispiel eines objektrelationalen Datenbankschemas für eine Unternehmung
Beispiel eines objektrelationalen Datenbankschemas für eine Unternehmung Im Folgenden soll das Beispielschema von Kapitel Beispiel eines Datenbankschemas für eine Unternehmung in einer objektrelationalen Variante formuliert werden. Im Vordergrund werden dabei vor allem die objektrelationalen Besonderheiten stehen. Deshalb werden die Integritätsbedingungen auch nur beispielhaft aufgezeigt, aber nicht durchgängig formuliert. Es sei hier noch einmal darauf hingewiesen, dass mit Ausnahme der DEFAULT-Klausel Integritätsbedingungen ausschließlich innerhalb der Tabellendefinition angegeben werden müssen. Grundsätzlich haben sich bei den Integritätsbedingungen keine wesentlichen Änderungen gegenüber den in Kapitel Integritätsbedingungen für das konventionelle SQL diskutierten Integritätsbedingungen ergeben. Spaltenbasierte Integritätsbedingungen jetzt grundsätzlich über die CONSTRAINT56 Dort hat man im Laufe der Jahre erheblich dazugelernt, so dass zwischenzeitlich durchaus effiziente Zugriffsstrukturen vorhanden sind. Trotzdem tendieren sie noch dazu, für gewisse Anwendungsanforderungen gut zu sein, für andere aber nicht (keine universelle Einsetzbarkeit). Zudem wird häufig vom Datenbankadministrator ein tiefgehender Kenntnisstand erwartet, um zu gewährleisten, dass die gegebenen Möglichkeiten zur Performanzsteigerung auch wenigstens annähernd ausgeschöpft werden.
8.3 Objektorientierte Konzepte in SQL:2011
551
Klausel zu formulieren sind, da die eigentliche Attributdefinition nicht mehr in der CREATE TABLE-Klausel geschieht, sondern jetzt in der CREATE TYPE-Klausel. Grundsätzlich gibt es natürlich verschiedene alternative Formulierungsmöglichkeiten. Wir werden in unserem Beispielschema auf Adressen immer verweisen, anstatt eine Adresse direkt einzubinden. Auch wird der aus Anwendungssicht eindeutige Identifikator immer über die OID realisiert, statt ihn explizit als Attribut zu realisieren. Diese Variante hat den Nachteil, dass die OID vom System vergeben wird und deshalb die Vergabe nicht beeinflusst werden kann. Von daher mag diese Variante für einen Menschen weniger intuitiv sein. Wenn die OID-Vergabe kontrolliert werden soll, muss ein entsprechendes Attribut eingefügt werden und in der REF-Klausel die REF FROM (attribut)-Variante gewählt werden. Weiterhin werden wir bei kleinen Mengen meist mit dem MULTISET-Typkonstruktor arbeiten, statt mit dem ARRAY-Typkonstruktor. Der Grund liegt daran, dass beim Array Anfragen langwierig werden können, insbesondere wenn der gesuchte Wert an einer beliebigen Position innerhalb des Arrays abgelegt sein kann (lange OR-Reihe in der WHERE-Klausel). CREATE SCHEMA
Unternehmensdatenbank;
/* Definition von Wertebereichseinschränkungen
CREATE DOMAIN Statustyp AS VARCHAR(20) CONSTRAINT Statustyp CHECK (VALUE IN (’aktiv’, ’beurlaubt’, ’freigestellt’, ’krank’, ’Mutterschaftsurlaub’)); CREATE DOMAIN Geschlechttyp AS VARCHAR(10) CONSTRAINT Statustyp CHECK (VALUE IN (’männlich’, ’weiblich’)); CREATE DOMAIN DreistelligeZahl AS SMALLINT CONSTRAINT Dreistellig CHECK (VALUE BETWEEN 100 AND 999); CREATE DOMAIN FünfstelligeZahl AS INTEGER CONSTRAINT Fünfstellig CHECK (VALUE BETWEEN 10000 AND 99999); CREATE DOMAIN AchtstelligeZahl AS INTEGER CONSTRAINT Achtstellig CHECK (VALUE BETWEEN 10000000 AND 99999999); CREATE DOMAIN PositiveReal AS DECIMAL(9,2) CONSTRAINT Positive CHECK (VALUE>0); /* Definition der benannten Zeilentypen
PersonTyp AS ( ROW ( personVorname VARCHAR(25), personNachname VARCHAR(25)), geburtsDatum DATE, geschlecht Geschlechttyp, personAdresse REF(AdresseTyp) ARRAY[3]) /* bis zu 3 Adressen REF USING AchtstelligeZahl /* PersonNr wird über die OID realisiert NOT INSTANTIABLE /* Eine Tabelle vom Typ PersonTyp
CREATE TYPE personName
kann nicht angelegt werden
NOT FINAL INSTANCE METHOD alter() RETURNS SMALLINT, /* mitarbeiterZahl ist Methode ; CREATE TYPE MitarbeiterTyp UNDER PersonTyp AS ( gehaltsKategorie VARCHAR(25),
552
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
einstellung DATE, mitarbeiterStatus Statustyp DEFAULT ’aktiv’, abteilung REF(AbteilungTyp)) INSTANTIABLE NOT FINAL INSTANCE METHOD gehalt() RETURNS DECIMAL(8,2), /* gehalt ist Methode INSTANCE METHOD betriebsZugehörigkeit() RETURNS SMALLINT, ; CREATE TYPE KundenTyp UNDER PersonTyp AS ( rabatt DECIMAL(4,2) DEFAULT 3, käufe REF(AuftragKundeTyp) MULTISET, ansprechPartner REF(MitarbeiterTyp) ARRAY[3]) INSTANTIABLE NOT FINAL ; CREATE TYPE ManagerTyp UNDER MitarbeiterTyp AS ( bonus DECIMAL(12,2), mitarbeiter REF(MitarbeiterTyp) MULTISET) INSTANCE METHOD anzahlUntergeordnet() RETURNS DECIMAL(8,2) INSTANTIABLE NOT FINAL ; An dieser Stelle kann man gut eine Schwäche der objektorientierten/-relationalen Modellierung erkennen. Jedes Objekt muss genau einer Klasse/Tabelle zugeordnet sein. Angenommen Ansprechpartner soll wie folgt als Spezialisierung von Mitarbeiter angelegt werden, weil ihm noch weitere Eigenschaften zugeordnet werden sollen: CREATE TYPE AnsprechPartnerTyp UNDER MitarbeiterTyp AS ( Sprechzeit VARCHAR(25) ARRAY[5]) INSTANTIABLE NOT FINAL ; Wenn in einer Anfrage auf Mitarbeiter zugegriffen wird, kann bei guter Modellierung (die Tabelle AnsprechPartner ist als Untertabelle von Mitarbeiter deklariert) die Sichtbarkeit in der Tabelle Mitarbeiter gewährleistet werden. Soll aber von der Tabelle Abteilung auf deren Mitarbeiter verwiesen werden, können nur die in genau einer Tabelle abgelegten Mitarbeiter adressiert werden und deshalb weder Manager noch Ansprechpartner eingebunden werden. Daran ändert auch die Sichtbarkeit nichts, da sie hier keine Anwendung findet. Im Beispiel unten ist dieses Problem für Manager gelöst worden (für Ansprechpartner allerdings nicht), indem die Manager als eigenes Attribut (leiter) eingebunden werden. Ein ähnliches Problem ist gegeben, wenn ein Objekt mehrere Funktionen wahrnimmt. Wenn beispielsweise ein Mitarbeiter auch Kunde des Unternehmens ist, kann er an sich nur einmal angelegt werden, entweder in der Tabelle Mitarbeiter oder in der Tabelle Kunden. Da er beide Funktionen ausfüllt, muss er letztendlich in beiden Tabellen angelegt sein. Somit bekommt er
8.3 Objektorientierte Konzepte in SQL:2011
553
zwei OIDs und damit werden aus der real nur einmal existierenden Person zwei unterschiedliche Personen (aus Sicht des DBMS). Natürlich kann der Modellierer über einen künstlichen Schlüssel (wie Personalausweisnummer) aus den zwei Personen wieder eine machen. Diese Logik existiert aber nur außerhalb des DBS in der Anwendung, ist also aus Sicht des DBS nicht bekannt und damit weder nutzbar noch garantierbar. AbteilungTyp AS ( VARCHAR(25), REF(ProduktTyp) MULTISET, REF(ManagerTyp) (MULTISET), /* mehrere Manager? REF(MitarbeiterTyp)MULTISET, ROW ( personalmittel PositiveReal, sachmittel PositiveReal, reisemittel PositiveReal, ... werbemittel PositiveReal)) REF USING DreistelligeZahl /* abteilungsNr wird über die OID realisiert INSTANTIABLE NOT FINAL INSTANCE METHOD mitarbeiterZahl() RETURNS SMALLINT, ; CREATE TYPE ArtikelTyp AS ( bezeichnung VARCHAR(25), nettoPreis PositiveReal, typ VARCHAR(25), lager REF(LagerTyp) MULTISET) /* mehrere Lager möglich REF USING DreistelligeZahl /* artikelNr wird über die OID realisiert INSTANTIABLE NOT FINAL ; CREATE TYPE ProduktTyp UNDER ArtikelTyp AS ( stueckKosten PositiveReal, wirdBearbeitetVon REF(AbteilungTyp) MULTISET, wurdeGekauftVon REF(KundenTyp) MULTISET) INSTANTIABLE NOT FINAL ; CREATE TYPE TeilTyp UNDER ArtikelTyp AS ( lieferant REF(ZuliefererTyp) MULTISET, /* mehrere Teilelieferanten stueckKosten PositiveReal, /* falls die Kosten bei jedem Lieferanten gleich sind, sonst muss es über eine ROW pro Lieferant modelliert werden istBestandteilVonREF(ProduktTyp) MULTISET) /* Produkte mit diesem Teil INSTANTIABLE NOT FINAL ; CREATE TYPE abteilungsName arbeitetAn leiter mitarbeiter budget
554
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen LagerTyp ( VARCHAR(25), REF(AdresseTyp), ROW ( /* es kann mehrere Lager geben mit eigenem istBestand artikel REF(ArtikelTyp) istBestand SMALLINT) MULTISET) REF USING DreistelligeZahl /* lagerNr wird über die OID realisiert NOT INSTANTIABLE NOT FINAL ;
CREATE TYPE lagerBez lagerAdresse artikelDaten
Grundsätzlich hätte man sich hier vorstellen können, dass nur der benannte Zeilentyp Lagertyp definiert wird und dann davon jeweils eine Tabelle für Teilelager und eine für Produktlager angelegt wird. Da dann aber vom ersten Lager Verweise auf Teile und vom anderen auf Produkte realisiert werden müssten, geht diese Variante wegen der Typisierung von Verweisen nicht. Es müssen also zwei Untertypen angelegt werden, die diese unterschiedlichen Verweistypen umsetzen. Alternativ wäre es auch denkbar, nur von Teile und Produkte auf die entsprechenden Lager zu verweisen. Dann würde der Verweis nicht in beide Richtungen (von Teile/Produkte zu Lager und umgekehrt) gehen, sondern eben nur von Teile/Produkte zu Lager. Dann würde der eine Lagertyp ausreichen. Wenn dann aber Anfragen der Gestalt „Nenne mir alle Teile, die im Lager mit dem Namen xy vorhanden sind“ gestellt werden sollen, wäre die Anfragenformulierung nicht intuitiv. Der Default sollte deshalb sein, dass Verweise immer in beide Richtungen umgesetzt werden. ZuliefererTyp AS ( VARCHAR(25), REF(AdresseTyp) ARRAY[20], /* bis zu 20 Niederlassungen ROW ( bank VARCHAR(25), iban VARCHAR(25), bic VARCHAR(12)), /* mehrere Konten: MULTISET ansprechPartner ROW ( name VARCHAR(25), telNr VARCHAR(15)) MULTISET, liefert REF(TeilTyp) MULTISET) REF USING DreistelligeZahl /* zuliefererNr wird über die OID realisiert NOT INSTANTIABLE NOT FINAL ;
CREATE TYPE zuliefererName zuliefererAdresse bankDaten
An dieser Stelle lassen sich die Grenzen der objektrelationalen Modellierung wieder gut erkennen. Der Aufbau eines Auftrags und einer Rechnung ist weitgehend identisch. Wenn jetzt beispielsweise aus der Rechnung auf die entsprechende Auftragsposition verwiesen werden soll, geht dies nicht, wenn die Auftragsposition als abhängiges exklusives Unterobjekt innerhalb des Auftragstyps definiert wird. Stattdessen muss sie als eigener benannter Zeilentyp und damit als unabhängiges gemeinsames Objekt definiert werden, da auf Attribute einer Zeile innerhalb einer Tabelle nicht verwiesen werden kann, nur auf vollständige Zeilen. Eine
8.3 Objektorientierte Konzepte in SQL:2011
555
Auftragsposition kann nun entweder auf ein Teil verweisen, falls sie zu einem Auftrag an einen Lieferanten gehört, oder auf einen Kunden, falls es ein Kundenauftrag ist. Teil und Produkt wurden deshalb als Untertyp vom Typ ArtikelTyp modelliert. Es tritt damit die Situation auf, dass für viele Begrifflichkeiten „neutrale“ Namen gefunden werden mussten, was die Lesbarkeit und Interpretierbarkeit eines Schemas verschlechtert und den Umgang dadurch fehleranfälliger macht. Ein Auftrag und eine Rechnung haben in unserem Beispielszenario einen äquivalenten Aufbau und werden deshalb unter einem Zeilentyp (AufRechPositionTyp) subsummiert. Die Instanzenmethode kosten in AufRechPositionTyp ist relativ komplex in ihrer Berechnung. Sie muss auf den zu Grunde liegenden Artikel zugreifen, um dessen Nettopreis zu bekommen. Dann nutzt sie die menge-Angabe, um die Kosten für diese Position zu berechnen. Handelt es sich um einen Kunden, muss die Methode überschrieben werden, da hier bei der Berechnung noch der Rabatt des Kunden berücksichtigt werden muss. Hier wird angenommen, dass ähnliches für Lieferanten gilt, weshalb die beiden Untertypen LiefAufRechPositionTyp und KundAufRechPosTyp angelegt wurden, die sich vom Obertyp AufRechPositionTyp nur durch das Überschreiben der Instanzenmethode kosten unterscheiden. Es sei noch angemerkt, dass kosten vielleicht bei Aufträgen keine Rolle spielt. Dann kann diese Methode einfach ignoriert, allerdings nicht ausgeblendet werden, da das objektrelationale SQL keine privaten Methoden kennt. Da es nur eine Methode ist, verbraucht deren Existenz jedoch keinen Speicherplatz — im Gegensatz zu „echten“ Attributen. CREATE TYPE AufRechTyp AS ( bearbeiter REF(MitarbeiterTyp), datum DATE, vertragsPartner REF(PersonTyp), aufRechPositionen REF(AuftragsPositionTyp) MULSTISET) REF USING DreistelligeZahl /* aufRechNr wird über die OID realisiert INSTANTIABLE NOT FINAL ; CREATE TYPE AufRechPositionTyp AS ( aufRechPos INTEGER, artikel REF(ArtikelTyp), menge SMALLINT) REF USING DreistelligeZahl /* aufRechPosNr wird über die OID realisiert INSTANTIABLE NOT FINAL INSTANCE METHOD kosten() RETURNS DECIMAL(8,2), /* berechnet Kosten Position ; CREATE TYPE AufRechPositionLiefTyp UNDER AufRechPositionTyp AS () INSTANTIABLE FINAL OVERRIDING INSTANCE METHOD kosten() RETURNS DECIMAL(8,2), ; CREATE TYPE AufRechPositionKundTyp UNDER AufRechPositionTyp AS () INSTANTIABLE
556
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Typhierarchie PersonrTyp
AbteilungTyp
LagerTyp
ZuliefererTyp
MitarbeiterTyp
KundenTyp
ArtikelTyp
AdresseTyp
ManagerTyp
AnsprechPartnerTyp
ProduktTyp
TeilTyp
AufRechPositionTyp
AufRechTyp
AufRechLiefPositionTyp
AufRechKundPositionTyp
Abb. 8.9: Typhierarchie
FINAL OVERRIDING INSTANCE METHOD kosten() RETURNS DECIMAL(8,2), ; CREATE TYPE AdresseTyp AS ( plz CHAR(5), ort VARCHAR(25), strasse VARCHAR(35), hausNr CHAR(5)) REF IS SYSTEM GENERATED INSTANTIABLE FINAL ; /* Definition der Tabellen Wie bereits diskutiert, kann es durchaus Sinn machen, auch eine leere Tabelle anzulegen, um damit z. B. eine künstliche Wurzel für eine Hierarchie zu schaffen. Dies kann dann zu deutlich kürzeren und übersichtlicheren Anfragen führen. CREATE TABLE Person OF PersonTyp ( /* Diese Tabelle kann weggelassen werden personAdresse WITH OPTIONS SCOPE Adresse, REF IS personNr USER GENERATED, ); CREATE TABLE Mitarbeiter OF MitarbeiterTyp UNDER Person ( personAdresse WITH OPTIONS SCOPE Adresse, abteilung WITH OPTIONS SCOPE Abteilung,
8.3 Objektorientierte Konzepte in SQL:2011
557
REF IS mitarbeiterNr USER GENERATED, ); CREATE TABLE Kunden OF KundenTyp UNDER Person ( personAdresse WITH OPTIONS SCOPE Adresse, käufe WITH OPTIONS SCOPE AuftragKunde, ansprechPartner WITH OPTIONS SCOPE Mitarbeiter, REF IS kundenNr USER GENERATED, ); CREATE TABLE Manager OF ManagerTyp UNDER Mitarbeiter ( personAdresse WITH OPTIONS SCOPE Adresse, abteilung WITH OPTIONS SCOPE Abteilung, mitarbeiter WITH OPTIONS SCOPE Mitarbeiter, REF IS managerNr USER GENERATED, ); CREATE TABLE AnsprechPartner OF AnsprechPartnerTyp UNDER Mitarbeiter ( personAdresse WITH OPTIONS SCOPE Adresse, abteilung WITH OPTIONS SCOPE Abteilung, REF IS ansprechPartnerNr USER GENERATED, ); CREATE TABLE Abteilung OF AbteilungTyp( arbeitetAn WITH OPTIONS SCOPE Produkt, leiter WITH OPTIONS SCOPE Manager, mitarbeiter WITH OPTIONS SCOPE Mitarbeiter, REF IS abteilungsNr USER GENERATED, ); CREATE TABLE Produkt OF ProduktTyp( wirdBearbeitetVon WITH OPTIONS SCOPE Abteilung, wurdeGekauftVon WITH OPTIONS SCOPE Kunden, REF IS produktNr USER GENERATED, ); CREATE TABLE Teil OF TeilTyp( lieferant WITH OPTIONS SCOPE Zulieferer, istBestandteilVon WITH OPTIONS SCOPE Produkt, REF IS teilNr USER GENERATED, ); CREATE TABLE ProduktLager OF LagerTyp( lagerAdresse WITH OPTIONS SCOPE Adresse, artikelDaten.artikel WITH OPTIONS SCOPE Produkt, /* Verweis Tabelle Untertyp REF IS produktLagerNr USER GENERATED, ); CREATE TABLE TeilLager OF LagerTyp( lagerAdresse WITH OPTIONS SCOPE Adresse, artikelDaten.artikel WITH OPTIONS SCOPE Teil, /* Verweis auf Tabelle Untertyp REF IS TeilLagerNr USER GENERATED, ); CREATE TABLE Zulieferer OF Typ( zuliefererAdresse WITH OPTIONS SCOPE Adresse,
558
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen liefert WITH OPTIONS SCOPE Teil, REF IS personNr USER GENERATED, );
Obwohl grundsätzlich wegen des identischen Aufbaus von Auftrag und Rechnung beide in einer Tabelle abgelegt werden könnten, werden sie im Beispiel in zwei Tabellen abgelegt, eine für die Aufträge und eine für die Rechnungen. Hier wird unterstellt, dass der Bearbeiter eines Auftrages ein anderer sein kann wie der Bearbeiter einer Rechnung. Diese Aufteilung in Rechnungen und Aufträge führt zu Redundanzen, da vertragspartner und aufRechPositionen jeweils in einem Auftrag und der dazugehörigen Rechnung identisch sind. Diese Redundanz tut aber nicht weh, da die Werte nur einmal abgelegt werden, es wird lediglich zweimal darauf verwiesen. Da die Auftrags- und Rechnungspositionen jeweils für einen Auftrag identisch sind, gibt es auch nur eine Tabelle dafür, so dass diese Positionen nicht redundant abgelegt sind. Dies ist eine etwas vereinfachte Darstellung der Realwelt, da es dort sicher passieren kann, dass ein Auftrag nicht ganz bedient werden kann und somit sich die Rechnungspositionen von den Auftragspositionen unterscheiden können. CREATE TABLE AuftragKunde OF AufRechTyp ( bearbeiter WITH OPTIONS SCOPE Mitarbeiter, vertragsPartner WITH OPTIONS SCOPE Kunde, /* Verweis auf Tabelle Untertyp aufRechPositionen WITH OPTIONS SCOPE AufRechPositionKunde, REF IS auftragKundeNr USER GENERATED, ); CREATE TABLE RechnungKunde OF AufRechTyp ( bearbeiter WITH OPTIONS SCOPE Mitarbeiter, vertragsPartner WITH OPTIONS SCOPE Kunde, /* Verweis auf Tabelle Untertyp aufRechPositionen WITH OPTIONS SCOPE AufRechPositionKunde, REF IS rechnungKundeNr USER GENERATED, ); CREATE TABLE AufRechPositionKunde OF KundAufRechPositionTyp ( artikel WITH OPTIONS SCOPE Produkt, /* Verweis Tabelle Untertyp REF IS aufRechPositionsNr USER GENERATED, ); CREATE TABLE AuftragLieferant OF AufRechTyp ( bearbeiter WITH OPTIONS SCOPE Mitarbeiter, vertragsPartner WITH OPTIONS SCOPE Lieferant, /* Verweis Tabelle Untertyp aufRechPositionen WITH OPTIONS SCOPE AufRechPositionLieferant, REF IS auftragLieferantNr USER GENERATED, ); CREATE TABLE RechnungLieferant OF AufRechTyp ( bearbeiter WITH OPTIONS SCOPE Mitarbeiter, vertragsPartner WITH OPTIONS SCOPE Lieferant, /* Verweis Tabelle Untertyp aufRechPositionen WITH OPTIONS SCOPE AufRechPositionLieferant, REF IS rechnungLieferantNr USER GENERATED, ); CREATE TABLE AufRechPositionLieferant OF LiefAufRechPositionTyp ( artikel WITH OPTIONS SCOPE Produkt, /* Verweis Tabelle Untertyp
8.3 Objektorientierte Konzepte in SQL:2011
559
Tabellenhierarchie Personr
Abteilung
Produkt
Teil
Mitarbeiter
Kunden
ProduktLager
TeilLager
Manager
Ansprechpartner
AuftragLieferant
AuftragKunde
Zulieferer
RechnungLieferant
RechnungKunde
Adresse
AufRechPositionLieferant
AufRechPositionKunde
Abb. 8.10: Tabellenhierarchie
REF IS aufRechPositionsNr USER GENERATED, ); CREATE TABLE Adresse OF Typ Adresse ( REF IS AdresseOID SYSTEM GENERATED, );
8.3.10
Zusammenfassung
Das mit SQL:1999 eingeführte objektrelationale SQL ist nicht eine weitere Version des Standards, sondern stellt einen erheblichen Einschnitt in der Entwicklung von SQL dar. Es wurden die ersten mutigen Schritte hin zu einer mehr objektorientierten Anfragesprache unternommen. Diese Schritte sind teilweise noch etwas zögerlich ausgefallen, was insbesondere auch daran liegt, dass SQL aus Sicht der Informatik schon ein Dinosaurier ist. Entsprechend schwer ist die Altlast, die immer wieder mitzuschleppen ist und nicht abgeworfen werden kann, will man garantieren, dass alte Anwendungen auch problemlos unter dem neuen Standard laufen. Insofern hat die SQL-Standardisierungskommission immer einen schweren Stand. Das Alte soll gewahrt bleiben, das Neue aber auch nicht zu kurz kommen. Es ist zu vermuten, dass nicht wenige Mitglieder der Standardisierungskommission die alten Tabellen gerne über Bord geworfen hätten, um mit den neuen, typisierten Tabellen ein einheitliches und moderneres Tabellenkonzept in SQL zu haben. Die jetzige Lösung ist an vielen Stellen sehr unbefriedigend. Das gravierendste Problem ist zu erwarten, wenn in einem Schema sowohl Tabellen alter Machart als auch typisierte Tabellen definiert wurden und – aus welchem Grund auch immer57 – eine alte Tabelle zu einer typisierten werden soll. Dieser unscheinbare Akt gleicht 57 Beispielsweise weil ein bereits bestehendes Schema weiterentwickelt werden soll oder weil bei der Entwicklung eines Schemas nicht erkannt worden ist, dass eine Tabelle einmal Zeilen mit Objektcharakter enthalten könnte. Der zunächst einmal so unschuldig aussehende Versuch, eine herkömmliche Tabelle um eine benutzerdefinierte Methode zu erweitern, erfordert schon eine Umwandlung in eine typisierte Tabelle.
560
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
aus Datenbanksicht einem GAU58 . Die interne Repräsentation einer typisierten Tabelle und der Umgang mit ihr ist völlig unterschiedlich zu traditionellen Tabellen. Nicht nur ist eine weiteres Attribut zur Speicherung der OID nötig, sondern auch die Verweise auf die Tabelle über Fremdschlüssel müssten gegebenenfalls auf OID-Verweise umgestellt werden59, um nur einige der zu bewältigenden Probleme zu nennen. Der Aufwand der Umstellung wird kaum automatisch geschehen können und vermutlich eher in der Anlage einer neuen Datenbank münden, denn in der Überführung einer bestehenden in eine neue Version. Die Konsequenz daraus ist klar: Überführungen alter Tabellen in typisierte sind so gut wie ausgeschlossen und damit ist die Tür für faule Umgehungskompromisse weit geöffnet. Betrachtet man zurückblickend noch einmal die Entwicklung im DBMS-Sektor, so fällt auf, dass der Übergang von herkömmlichen Tabellen zu typisierten und die Einführung der zusätzlichen Typkonstruktoren vom Grundsatz her nichts Neues darstellen. Schon das hierarchische und das Netzwerk-Datenbankmodell kannten diese Konzepte. DBMS wie ADABAS (von der Software AG) und einige andere, die auf dem so genannten logischen Datenmodell (logical file data model) basieren, haben schon immer extensiv die Verweistechnik genutzt. Die darunter liegenden Datenbankmodelle waren schon immer mächtiger gewesen als das relationale. Auch waren diese Systeme häufig vergleichsweise schnell, da die performanzkostenden Verbundoperationen nicht ausgeführt werden mussten. Trotzdem haben die relationalen DBMS einen Siegeszug angetreten, der mehr als beachtlich ist. Dieser ist vor allem der Einfachheit des relationalem Datenbankmodells zu verdanken und der Tatsache, dass physische und logische Datenunabhängigkeit weitgehend unterstützt werden und somit die Anwendungsprogrammierung erheblich vereinfacht wurde. Diese Einfachheit wird durch das objektrelationale SQL nicht nur angekratzt, sondern weitgehend abgeschafft. Es ist deshalb zu erwarten, dass es zwei Lager geben wird. Diejenigen, die die neuen Entwicklungen in Grund und Boden verdammen werden, weil sie mit dem alten Datenbankmodell hervorragend zurechtgekommen sind und daher keinen Anlass für den durch die neue Version verursachten Overhead sehen. Und Diejenigen, die die Vorteile für ihre Anwendungen sehen, weil diese bisher nur umständlich durch das zu wenig mächtige alte Datenbankmodell bedient werden konnten. Erste Erfahrungen, die insbesondere Informix und Oracle mit ihren um data extender bzw. data cartridges erweiterten DBMS gemacht haben, belegen dies. Viele Anwender waren einfach nicht bereit, auf eine wesentlich komplexere Version umzusteigen und dafür auch noch viel Geld zu bezahlen, wo sie mit dem alten Datenbankmodell gut bedient waren. Dieser Konflikt ist nicht einfach zu lösen und wird uns mit Sicherheit noch lange beschäftigen. Und mit Sicherheit werden einige Anbieter (ehemaliger) hierarchischer, Netzwerk oder logischer DBMS sich fragen, warum sie nicht ihre Systeme konsequent weiterentwickelt haben. Dann wären sie heute vermutlich technologisch weit vor der relationalen Konkurrenz.
8.4
Trigger
Der SQL-92-Standard hatte Triggermechanismen noch nicht abgedeckt. Trotzdem fand man sie bereits in vielen modernen relationalen DBMS. Seit SQL:1999 offeriert nun auch der Stan58 Größte
anzunehmende U nglück wenn man die typisierte Tabelle sauber umsetzen möchte und sich nicht gleich von Beginn an „faule“ Kompromisse einhandeln möchte. 59 Zumindest
8.4 Trigger
561
dard ein Triggerkonzept. Trigger sind bereits in Kapitel 7.8 eingeführt worden, weshalb wir hier nur eine kurze Einführung geben werden, um dann die konkrete Umsetzung des Triggerkonzeptes in SQL:2011 zu diskutieren. Über Trigger kann ein DBS kontrolliert auf Arbeiten auf seinem Datenbestand reagieren. Da diese Reaktion automatisch ausgelöst wird, spricht man auch gerne von einem aktiven DBMS. Wie bereits diskutiert, setzen Trigger das ECA-Konzept (event-condition-action) um. Auf den Auftritt eines Ereignisses (event) reagiert das DBS mit einer Aktion (action), falls eine bestimmte Bedingung (condition) erfüllt ist. Trigger sind ein sehr mächtiges Konzept. Sie erlauben es insbesondere auch, Geschäftsprozesse in das DBS einzubringen. Als Beispiel soll hier eine B-to-C (Business-to-Consumer) Anwendung gewählt werden, eine internetbasierte Buchhandlung. Nehmen wir einmal an, Sie bestellen dort mehrere Bücher, möchten diese aber erst geliefert bekommen, sobald auch alle lieferbar sind (um Verpackungs- und Portokosten zu sparen). Da ein Buch nicht vorrätig ist, wird Ihre Bestellung zunächst notiert (in der DB abgelegt), aber noch nicht ausgeführt. Wenn jetzt später eine Modifikation auf dem Datenbestand der DB ausgeführt wird der Art, dass der Lagerbestand des fehlenden Buches auf > 0 gesetzt wird, so könnte ein Trigger ausgelöst werden, der die Ausführung Ihrer Bestellung anstößt. Einerseits wird der Lagerbestand der bestellten Bücher um die Bestellmenge reduziert, andererseits die Rechnung erstellt und möglicherweise bereits die Abbuchung von Ihrer Kreditkarte veranlasst. Schließlich wird Ihnen noch eine Benachrichtigung (z. B. eine EMail) geschickt, in der die Auslieferung der Bestellung bestätigt wird. Alle diese Vorgänge (möglicherweise inkl. des Packens und Verschickens des Paketes) werden automatisch von dem DBS ausgelöst. SQL:2011 unterstützt als Ereignisse nur den Aufruf der UPDATE-, INSERT- und DELETEÄnderungsoperationen auf Basistabellen der DB bzw. Tabellen einer Sicht60 . Andere Operationen, wie der lesende Zugriff auf den Datenbestand oder der CREATE xy-Befehl, sind noch nicht für die Nutzung von Triggern offen. Als Ausführungszeitpunkt eines Triggers kann dabei der Zeitpunkt vor (BEFORE) oder nach (AFTER) der den Trigger auslösenden Operation gewählt werden. Entsprechend wird der Trigger entweder vollständig direkt vor oder direkt nach der Operation ausgeführt. Die Triggergranularität legt fest, auf welcher Ebene ein Trigger ausgeführt wird. Trigger können entweder auf der Instanzenbasis, d. h. für jede „angefasste“ Zeile (FOR EACH ROW), oder auf der Befehlsbasis, d. h. einmal für alle „angefassten“ Zeilen eines SQL-Statements (FOR EACH STATEMENT) ausgeführt werden. Damit kann beispielsweise bei einer Gehaltserhöhung sichergestellt werden, dass entweder das Gehalt eines Mitarbeiters nicht überproportional steigt (zeilenbasierte Ausführung) oder die Gehaltssteigerung über alle Mitarbeiter mit neuem Gehalt einen bestimmten Prozentsatz nicht überschreitet (anweisungsbasierte Ausführung). Um bei Triggern dieser Art den alten Spaltenwert mit dem neuen vergleichen zu können, sind über das REFERENCING NEW AS neuer Wert OLD AS alter Wert-Statement der alte und der neue Werte mit einem Namen versehbar. In den folgenden Bedingungen können sie über diesen Namen angesprochen werden. Auf die gleiche Art und Weise kann eine Tabelle angesprochen werden. Tabelle 8.2 gibt einen Überblick über die erlaubten Kombinationen von Triggergranularität, Ausführungszeitpunkt, auslösender Aktion und erlaubten Datenbezug. 60 Sofern
darauf Änderungen erlaubt sind.
562
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
Granularität
Zeitpunkt der Aktivierung
BEFORE
auslösende Operation
zulässiger Spaltenbezug
zulässiger Tabellenbezug
INSERT
NEW
UPDATE
OLD, NEW
DELETE
OLD
INSERT
NEW
NEW_TABLE
UPDATE
OLD, NEW
OLD_TABLE, NEW_TABLE
DELETE
OLD
OLD_TABLE
keiner
keiner
keiner
ROW AFTER
INSERT BEFORE
UPDATE DELETE
STATEMENT INSERT AFTER
UPDATE
NEW_TABLE keiner
DELETE
OLD_TABLE, NEW_TABLE OLD_TABLE
Tabelle 8.2: Erlaubte Datenbezüge innerhalb von Triggern
Der optionale Bedingungsteil wird über die WHEN-Klausel spezifiziert, die im Wesentlichen mit der WHERE-Klausel vergleichbar ist. Die Bedingung kann dabei eine beliebige in SQL spezifizierte Bedingung sein, also auch eine komplexe Anfrage. Nur wenn die Bedingung erfüllt ist, wird auch die Aktion des Triggers ausgeführt. Die Aktion kann die Ausführung einer oder mehrerer SQL-Anweisungen bewirken, wobei mehrere Anweisungen durch einen BEGIN ATOMIC Anweisungen END-Block gekapselt werden. Insbesondere können im Aktionsteil auch Datenbankprozeduren, Funktionen und Methoden aufgerufen werden. Damit können beliebig komplexe Anweisungssequenzen ausgeführt werden. Der folgende Trigger stellt sicher, dass der neue Preis eines Produktes einerseits nicht unter 90 Prozent des alten Preises sinken kann und andererseits mindestens 50 Prozent über seinen Herstellungskosten liegt. Der Name des Triggers lautet VerlustVermeidung. Er wird bei jeder Änderung (wegen FOR EACH ROW) der nettoPreis-Spalte einer Zeile aus der Tabelle Produkt aufgerufen. Falls der Bedingungsteil (WHEN-Block) erfüllt ist, wird die Transaktion, die den Trigger ausgelöst hat, zurückgesetzt (ROLLBACK). Der alte Wert der nettoPreis-Spalte wird dabei über AlterWert, der neue über NeuerWert angesprochen (siehe REFERENCINGStatement). Beispiel 8.58: Trigger nach SQL:2011, Beispiel 1 CREATE TRIGGER VerlustVermeidung AFTER UPDATE OF nettoPreis ON Produkt
/* event
8.4 Trigger REFERENCING NEW AS NeuerWert OLD AS AlterWert FOR EACH ROW WHEN (NeuerWert.nettoPreis < (AlterWert.nettoPreis ∗ 0,9)) OR (nettoPreis < (stueckKosten ∗ 1,5)) ROLLBACK;
563
/* condition /* action
Unser Beispiel der Internet-Buchhandlung könnte wie in Beispiel 8.59 umgesetzt werden. Ausgangsbasis ist unser Schema der Unternehmensdatenbank. Es wird angenommen, dass es eine Tabelle VerzögerteBestellung gibt, in der die wegen nicht vorhandener Bestände noch nicht ausgeführten Bestellungen abgelegt sind (pro Buch ein Datensatz). Im Bedingungsteil wird zunächst geprüft, ob der Lagerbestand vorher 0 war, da nur dann eine Bestellung verzögert ausgeführt werden kann61 , also Kandidaten für eine Ausführung in der Tabelle VerzögerteBestellung vorhanden sein können. Als nächstes wird geprüft, ob der neue Lagerbestand > 0 ist (was logischerweise immer der Fall sein sollte). In der SQL-Klausel wird dann konkret überprüft, ob es Datensätze in VerzögerteBestellung gibt, die betroffen sind. Falls der Bedingungsteil erfüllt ist, werden im Aktionsteil die entsprechenden Datenbankprozeduren für jede betroffene Bestellung ausgeführt. Beispiel 8.59: Trigger nach SQL:2011, Beispiel 2 CREATE TRIGGER LagerAuffüllung AFTER UPDATE OF istBestand ON ProduktLagertIn /* event REFERENCING NEW AS NeuerWert OLD AS AlterWert FOR EACH ROW WHEN (AlterWert.istBestand = 0 AND NeuerWert.istBestand > 0 /* condition AND ((SELECT COUNT(buchNr) FROM VerzögerteBestellung WHERE gewünschteLagerNr62 = ProduktLagertIn.produktLagerNr GROUP BY buchNr = ProduktLagertIn.produktNr)> 0) BEGIN ATOMIC /* action pro betroffene Bestellung: (BestellungAusführen; KreditkarteBelasten; EMailSenden; VerzögerteBestellungAktualisieren); END; Ein Nachteil des SQL:2011 Triggerkonzeptes ist, dass Trigger immer direkt ausgeführt werden. Eine manchmal wünschenswerte verzögerte Ausführung, z. B. erst am Transaktionsende, lässt sich nicht definieren63. Dies ist deshalb ärgerlich, weil an sich die Transaktion (und nicht 61 Wir unterstellen, dass jedes Buch nur genau einmal geordert werden kann. Ansonsten müsste hier ein Vergleich mit der georderten Menge stattfinden. 62 In gewünschteLagerNr wird die Lagernummer des Lagers gespeichert, das die Bestellung ausführen soll. 63 Zwar scheint auf dem ersten Blick die FOR EACH STATEMENT-Anweisung eine Ausführung am Transaktionsende zu erlauben, da eine SQL-Anweisung oft einer Transaktion entspricht, aber die Intention und damit die Semantik dieser Anweisung ist offensichtlich eine andere.
564
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
die Aktion) die Einheit der Konsistenz ist. Eine Konsistenzverletzung innerhalb einer Transaktionsausführung ist gelegentlich unvermeidlich, würde sich aber durch das gegenwärtige Triggerkonzept nicht tolerieren lassen. Allerdings sei der Fairness halber auch angemerkt, dass reine Konsistenzüberprüfungen im Normalfall über Tabellenzusicherungen (constraints) realisiert werden sollten und diese lassen sich bis zum Transaktionsende verzögern. Trigger bieten weitreichende Möglichkeiten, weshalb man sie sehr bewusst einsetzen sollte. Im Aktionsteil lassen sich beliebig komplexe Anweisungen spezifizieren, deren Ausführung weitere Triggerausführungen auslösen kann. Beispielsweise wird eine Ausführung des Aktionsteils des Triggers LagerAuffüllung von Beispiel 8.59 diesen Trigger wieder aktivieren, da die Auslieferung einer Bestellung den Lagerbestand (istBestand) in ProduktLagertIn verändert. Allerdings wird der Bedingungsteil bei dieser Triggerausführung nicht erfüllt sein. Hieran kann man auch sehen, dass die Einführung des Triggerkonzeptes grundsätzlich auch die Performanz eines DBS belastet, da bei jeden Ausführung eines Ereignisses, welches theoretisch einen Trigger auslösen könnte, geprüft werden muss, ob ein oder mehrere Trigger betroffen sind. Insgesamt können alle bereits in Kapitel 7.8 besprochenen Probleme auftreten, was noch einmal unterstreicht, dass Trigger auch belastend sein können, wenn man sie nicht verantwortungsvoll einsetzt.
8.5
Weitere Neuerungen im Überblick
Im Folgenden werden noch einige weitere wesentliche Neuerungen von SQL:2011 vorgestellt. Allerdings sei angemerkt, dass diese Liste lediglich weitere aus Sicht der Diskussionen innerhalb dieses Buches wesentliche Neuerungen aufführt, aber nicht vollständig ist.
8.5.1
Benennung von SFW-Blöcken
Bereits in Kapitel 7.3.5.3 war der Vorteil der Benennung von SFW-Blöcken diskutiert worden (siehe Beispiel 7.130 und Beispiel 7.131). Seit SQL:1999 ist eine solche Benennung im Standard über die WITH NameSFW-Block AS-Klausel möglich, so dass sich z. B. Beispiel 7.130 jetzt wie in Beispiel 8.60 angegeben formulieren lässt. Beispiel 8.60: Benennung von SFW-Blöcken WITH ProdukttypLager AS ( SELECT produktTyp, produktLagerNr, AVG(nettoPreis) AS ∅ nettoPreis FROM ProduktLagertIn NATURAL JOIN Produkt WHERE istBestand > 0 GROUP BY produktTyp, produktLagerNr); SELECT produktTyp, AVG(∅ nettoPreis) AS ∅ nettoPreisÜberAlleLager FROM ProdukttypLager GROUP BY produktTyp; Solche benannten SFW-Blöcke sind insbesondere auch zur Formulierung von rekursiven Anfragen (siehe Abschnitt 8.5.2) sehr nützlich.
8.5 Weitere Neuerungen im Überblick
8.5.2
565
Rekursion
Bisher hatte der SQL-Standard keine Rekursion unterstützt, so dass beispielsweise die Ausgabe von Stücklisten (aus welchen Teilen besteht ein Auto?) nicht direkt möglich war. Ab SQL:1999 wird dieser für manche Anwendungen erhebliche Mangel behoben. Die Umsetzung der Rekursion und deren Syntax ähnelt der Schreibweise und Semantik in Datalog. Die Rekursion kann auf der Breiten- oder der Tiefensuche64 basieren. Im folgenden Beispiel wird von der oben eingeführten Benennung von SFW-Blöcken Gebrauch gemacht. Beispiel 8.61: Rekursion Für dieses Beispiel wird angenommen, dass die Tabelle SindBestandteilVon wie folgt definiert ist: CREATE TABLE SindBestandteilVon ( oberteilNr FünfstelligeZahl, unterteilNr FünfstelligeZahl, anzahlUnterteile INTEGER, . . . ); Anfragen der Art a. „Gib alle unterschiedlichen Unterteile und deren insgesamt benötigte Anzahl zum Teil 12345 aus.“ bzw. b. „Gib zum Teil 12345 (rekursiv) dessen Aufbau in der Reihenfolge einer Breitensuche aus.“ können dann wie folgt formuliert werden: WITH RECURSIVE TeilUnterteilBez(oberteilNr, unterteilNr, anzahlUnterteile) AS (SELECT oberteilNr, unterteilNr, anzahlUnterteile FROM SindBestandteilVon AS OT WHERE OT.oberteilNr = ’12345’ UNION ALL SELECT OT.oberteilNr, OT.unterteilNr, UT.anzahlUnterteile ∗ OT.anzahlUnterteile FROM TeilUnterteilBez AS UT INNER JOIN SindBestandteilVon AS OT ON (OT.oberteilNr = UT.unterteilNr); ) SEARCH BREADTH FIRST BY oberteilNr, unterteilNr SET breitensuche; 64 Bei der Breitensuche wird z. B. eine Stückliste nach Ebenen sortiert ausgegeben (also bei einem Auto wäre die erste Ebene der Motor, die Karosserie, das Getriebe, usw., sobald diese Ebene abgearbeitet ist, kommt die nächst tiefere an die Reihe (also beim Motor der Motorblock, der Vergaser, die Auspuffanlage, usw.)). Bei der Tiefensuche wird immer erst ein zusammengesetztes Teil so lange weiter zerlegt, bis es nur noch auf nicht mehr weiter zerlegbare Basisteile zurückgeführt wurde (also bei einem Auto würde zunächst der Motor, dann der Motorblock, dann die Kurbelwelle, usw. ausgegeben; ist z. B. die Kurbelwelle ein Basisteil, so würde das nächste Teil auf dieser Ebene und seine Unterteile ausgegeben, usw.).
566 1.
2.
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen SELECT unterteilNr, SUM(anzahlUnterteile) FROM TeilUnterteilBez GROUP BY unterteilNr; SELECT oberteilNr, unterteilNr FROM TeilUnterteilBez ORDER BY breitensuche;
Man beachte, dass in Beispiel 8.61 b. Ober-, Unterteil-Datensätze mehrfach ausgegeben werden können, nämlich genau dann, wenn eine Ober-/Unterteilbeziehung mehrfach vorkommt (in unterschiedlichen Ästen der Stückliste). SQL:2011 bietet im Zusammenhang mit Rekursion noch eine Reihe weiterer nützlicher Features, insbesondere auch eines, mit dem ein unendlicher Schleifendurchlauf verhindert werden kann (CYCLE-Klausel). Auf diese Features soll hier aber nicht weiter eingegangen werden.
8.5.3
Datenschutz und Datensicherheit
Im Bereich Datenschutz und Datensicherheit hat die Standardisierungskommission etwas nachgeholt, was in der Praxis schon weitgehend umgesetzt wurde: das Rollenkonzept. Unter Rollen versteht man ein Aufgabenfeld, was einer Person oder einer Gruppe von Personen zugewiesen werden kann. Dementsprechend kann man in SQL:2011 Rollen spezifizieren, denen gewisse Zugriffsrechte mitgegeben werden. Solche Rollen können dann an bestimmte Personen oder (rekursiv) an andere Rollen vergeben werden. Das Rollenkonzept hat sich in der Praxis als deutlich übersichtlicher herausgestellt als die reine Rechtevergabe auf der Basis von individuellen Personen.
8.5.4
Online Analytical Processing (OLAP)
Online Analytical P rocessing bzw. OLAP dient dem Zwecke, vorhandene Informationen zu verdichten, um ein Kompressionsniveau zu erreichen, auf dem beispielsweise Manager aus den dann gegebenen komprimierten Daten sinnvolle Rückschlüsse ziehen können. Ein typisches Beispiel für OLAP ist der Verkauf mit Fragestellungen wie den folgenden: a. „Liste den Gesamtumsatz pro Verkäufer und Region für die Monate Januar und Februar auf. Zusätzlich sollen die Gesamtumsätze pro Monat und insgesamt aufgelistet werden.“ b. „Liste den Gesamtumsatz für die Monate Januar und Februar einerseits nach Verkäufer und andererseits nach Region auf.“ c. „Liste den Gesamtumsatz pro Monat (nur Januar und Februar), Verkäufer und Region auf. Zusätzlich sollen alle daraus ableitbaren akkumulierten Ergebnisse aufgelistet werden.“ Diese Anfrage ist eine Kombination aus den ersten beiden Anfragen, wobei aber alle aus den Basisdaten ableitbaren akkumulierten Daten ebenfalls aufgelistet werden. Zur Unterstützung solcher Anfragen stellt SQL:2011 eine Reihe von Konstrukten zur Verfügung, die innerhalb der GROUP BY-Klausel eingesetzt werden können. Hier soll auf eine
8.5 Weitere Neuerungen im Überblick
567
intensivere Diskussion verzichtet werden, da insgesamt das Thema OLAP nicht weitergehend angesprochen wurde. Stattdessen zeigt Beispiel 8.62 wie die obigen Anfragen mit Hilfe der ROLLUP-, CUBE-, und GROUPING SETS-Funktionen beantwortet werden können. Unterstellt wird dabei, dass es eine Tabelle Umsatz gibt, in der die Umsätze nach Monat, Region und Verkäufer abgelegt sind. Beispiel 8.62: Beispiele für OLAP-Anfragen a. Diese Anfrage entspricht im Kern einer Anfrage mit einer reinen Gruppierung (über die GROUP BY-Klausel). Nur werden zusätzlich noch akkumulierte Ergebnisse zur Verfügung gestellt. Anfrage 1 wird mit Hilfe der ROLLUP-Funktion gelöst: SELECT monat, region, verkäufer, SUM(umsatz) FROM Umsatz WHERE monat = ’Januar’ OR monat = ’Februar’ GROUP BY ROLLUP (monat, region, verkäufer); b. Bei dieser Anfrage möchte man das Ergebnis nach verschiedenen Kriterien sortiert (Monat und Region bzw. Verkäufer) aufgelistet haben. Es entstehen damit Mengen, die nach unterschiedlichen Kriterien gruppiert werden. Die Lösung für Anfrage 2 nutzt die GROUPING SETS-Funktion: SELECT FROM WHERE GROUP BY
monat, region, verkäufer, SUM(umsatz) Umsatz monat = ’Januar’ OR monat = ’Februar’ GROUPING SETS ((monat, region) (monat, verkäufer));
c. Diese Anfrage kann man mit einem Würfel verbinden, wobei jede Seite des Würfels eine unterschiedliche Reihenfolge der Gruppierungskriterien umsetzt. Die Lösung für Anfrage 3 nutzt daher die CUBE-Funktion: SELECT FROM WHERE GROUP BY
monat, region, verkäufer, SUM(umsatz) Umsatz monat = ’Januar’ OR monat = ’Februar’ CUBE (monat, region, verkäufer)
Die Tabelle 8.3, Tabelle 8.4 und Tabelle 8.5 zeigen beispielhaft auf, wie Ergebnisse für die obigen Anfragen aussehen könnten. Die in diesem Abschnitt kurz angesprochenen Konzepte bilden den Kern von dem, was im gegenwärtigen Standard verankert ist. Es gibt eine weitergehendere Initiative, die sich ausschließlich der OLAP-Problematik widmet, um aufbauend auf diesen Basisvorschlägen weitergehendere Konzepte zu entwickeln und umzusetzen. Gemäß der neuen Politik der Standardisierungskommission werden dieser Arbeiten in einer Ergänzung zum jetzigen Standard münden (Amendment 1: Online Analytical Processing (SQL/OLAP)). Damit will man es ermöglichen, dass "heiße"Themen möglichst schnell standardisiert werden können, insbesondere ohne auf die Verabschiedung einer vollständig neuen Version des Standards warten zu müssen.
568
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
monat
region
verkäufer
SUM(umsatz)
Januar
NRW
Badman
36.000.000,–
Januar
NRW
Fireman
15.000,–
Januar
NRW
–
36.015.000,–
Januar
Bayern
Badman
23.000.000,–
Januar
Bayern
–
23.000.000,–
monat
region
verkäufer
SUM(umsatz)
Januar
–
–
59.015.000,–
Januar
NRW
–
36.015.000,–
Februar
NRW
Badman
47.000.000,–
Januar
Bayern
–
23.000.000,–
Februar
NRW
Fireman
8.000,–
Januar
–
Badman
59.000.000,–
Februar
NRW
–
47.008.000,–
Januar
–
Fireman
15.000,–
Februar
Bayern
Badman
63.000.000,–
Februar
NRW
–
47.008.000,–
Februar
Bayern
–
63.000.000,–
Februar
Bayern
–
63.000.000,–
Februar
–
–
110.008.000,–
Februar
–
Badman
110.000.000,–
–
–
–
169.023.000,–
Februar
–
Fireman
8.000,–
Tabelle 8.3: Beispielhaftes Ergebnis für Anfrage 1
Tabelle 8.4: Beispielhaftes Ergebnis für Anfrage 2
monat
region
verkäufer
SUM(umsatz)
monat
region
verkäufer
SUM(umsatz)
Januar
NRW
Badman
36.000.000,–
Februar
–
–
110.008.000,–
Januar
NRW
Fireman
15.000,–
Februar
NRW
–
47.008.000,–
Januar
NRW
–
36.015.000,–
Februar
Bayern
–
63.000.000,–
Januar
Bayern
Badman
23.000.000,–
Februar
–
Badman
110.000.000,–
Januar
Bayern
–
23.000.000,–
Februar
–
Fireman
8.000,–
Januar
–
–
59.015.000,–
–
NRW
Badman
83.000.000,–
Januar
NRW
–
36.015.000,–
–
NRW
Fireman
23.000,–
Januar
Bayern
–
23.000.000,–
–
NRW
–
83.023.000,–
Januar
–
Badman
59.000.000,–
–
Bayern
Badman
86.000.000,–
Januar
–
Fireman
15.000,–
–
Bayern
Fireman
–,–
Februar
NRW
Badman
47.000.000,–
–
Bayern
Fireman
86.000.000,–
Februar
NRW
Fireman
8.000,–
–
–
Badman
169.000.000,–
Februar
NRW
–
47.008.000,–
–
–
Fireman
23.000,–
Februar
Bayern
Badman
63.000.000,–
–
–
–
169.023.000,–
Februar
Bayern
–
63.000.000,–
Tabelle 8.5: Beispielhaftes Ergebnis für Anfrage 3
8.5 Weitere Neuerungen im Überblick
569
Die in diesem Abschnitt kurz angesprochenen Konzepte bilden den Kern von dem, was im gegenwärtigen Standard verankert ist. Es gibt eine weitergehendere Initiative, die sich ausschließlich der OLAP-Problematik widmet, um aufbauend auf diesen Basisvorschlägen weitergehendere Konzepte zu entwickeln und umzusetzen. Gemäß der neuen Politik der Standardisierungskommission werden dieser Arbeiten in einer Ergänzung zum jetzigen Standard münden (Amendment 1: Online Analytical Processing (SQL/OLAP)). Damit will man es ermöglichen, dass „heiße“ Themen möglichst schnell standardisiert werden können, insbesondere ohne auf die Verabschiedung einer vollständig neuen Version des Standards warten zu müssen.
8.5.5
Sicherungspunkte
Sicherungspunkte werden in Kapitel 9.3.2.7 noch intensiver behandelt. Vom Grundsatz her können mit ihnen geschachtelte Transaktionen realisiert werden. In einem Fehlerfall kann auf einen Sicherungspunkt zurückgesetzt werden (ROLLBACK TO SAVEPOINT), so dass nicht die gesamte bisherige Arbeit einer Transaktion zurückgesetzt wird, sondern nur die Arbeit ab dem Sicherungspunkt.
8.5.6
SQL/MM (Multimedia-Unterstützung)
Wie bereits weiter oben erwähnt, sind relationale DBMS hervorragend geeignet, um den Datenbestand für einfachere Anwendungen zu verwalten. So genannte Nichtstandard Anwendungen zeichnen sie durch hohe Anforderungen an die Datenmodellierungsfähigkeit eines DBMS aus. Ein performanter assoziativer Zugriff auf komplexe, oft großvolumige Objekte, mit denen solche Anwendungen üblicherweise arbeiten, ist nur zu realisieren, falls entsprechende Zugriffspfade und Speicherungsstrukturen von Seiten des DBMS angeboten werden. Dies ist bei den vom DBMS nicht weiter interpretierbaren LOB-Datentypen nicht gegeben. Die mit solchen Datentypen verbundene Problematik soll beispielhaft kurz an einer Landkarte von Deutschland diskutiert werden, aus der man sich einen Ausschnitt des Ruhrgebietes ansehen möchte. Ohne räumliche Zugriffspfade – die nicht zum Repertoire eines relationalen DBMS gehören – wäre ein solcher Zugriff nicht vernünftig realisierbar. Auch kann der Datentyp Landkarte nicht im DBS interpretiert und weiterverarbeitet werden, so dass die Daten zur Verarbeitung zunächst vollständig in die Anwendung hochgereicht werden müssen. Dies kann zu hohem Mehraufwand führen, wenn man sich überlegt, dass die Landkarte von Deutschland wesentlich größer ist als das Ruhrgebiet und somit sehr viele Daten nutzlos an die Anwendung weitergegeben werden müssen. Nun erlaubt SQL:2011 zwar die Definition neuer Datentypen und Routinen, diese müssen aber weiterhin mit den existierenden Speicherdatentypen und Zugriffspfaden auskommen. Damit lassen sich also nicht die notwendigen Performanzsteigerungen realisieren. Dem Trend vieler DBMS-Anbieter folgend, versucht auch der Standard, dieses Manko durch die Einführung von anwendungsklassenspezifischen Datentypen auszumerzen. Bisher wird intensiv an SQL/MM65 gearbeitet. Dahinter verbirgt sich die Unterstützung von Volltext (fulltext), zweidimensionalen räumlichen/geographischen Daten (spatial data) und Bildern (stillimage). Performanz wird erzielt, indem einerseits typspezifische Zugriffspfade und Speiche65 MM
steht für Multimedia
570
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
rungsstrukturen mitsamt den dazugehörigen Methoden zur Verfügung gestellt werden. Anderseits sind diese Datentypen als abstrakte Datentypen ausgelegt, sind also mit typspezifischen Methoden ausgestattet. Da das DBMS jetzt die Semantik des Datentyps „kennt“, können diese Methoden hochgradig effizient innerhalb des DBS ausgeführt werden. Für den Volltext sind das Methoden wie Wort-, Phrasen-, Kontext- und linguistische Suche, während für die geographischen Daten u. a. Entfernungs- und Testoperationen (enthält, überschneidet, berührt, kreuzt, . . . ) sowie Methoden zur Bestimmung des gemeinsamen Bereichs, der Differenz oder der Vereinigung von Objekten bereitgestellt werden. Bei den Bildern werden verschiedene Speicherformate unterstützt (wie JPEG) sowie einige Operationen, um Eigenschaften von bzw. Objekte in Bildern identifizieren zu können.
8.5.7
SQL/MED (Management of External Data)
SQL/MED (Management of External Data) beschäftigt sich mit der Verwaltung von großvolumigen Daten, die als zu einem Datenbestand zugehörig anzusehen sind, aber nicht direkt in der DB abgelegt werden sollen, bzw. aus historischen Gründen außerhalb der DB verwaltet werden (legacy data). Dazu werden so genannte Data Links genutzt. Dies ist ein spezieller, vom System bereit gestellter Datentyp, der es erlaubt, auf ein außerhalb des Datenbanksystems liegendes Objekt zu verweisen. Das externe Objekt befindet sich dabei ganz unter der Kontrolle des DBS, was insbesondere bedeutet, dass auch ein von extern ausgeführter Zugriff auf das Objekt vom DBS bemerkt und im Konfliktfall unterbunden wird. Dazu wird das externe Objekt quasi gekapselt. Um mit solchen externen Objekten arbeiten zu können, muss ihnen eine Tabellenstruktur aufgepfropft werden. Dies geschieht über sogenannte Wrapper für Fremddaten (foreign-data wrapper). Die „eingekapselten“ Daten bilden eine sogenannte Fremdtabelle (foreign table), während der Server, auf dem die Fremdtabellen abgelegt sind, Fremdserver (foreign server) genannt wird. Eine Anfrage wird abgearbeitet, indem sie entsprechend der von verteilten DBS bekannten Techniken in ihre (fremd)serverbezogenen Bestandteile zerlegt wird und jeder dieser Bestandteile dann vom zuständigen (Fremd)server abgearbeitet wird. Diese Architektur stellt sicher, dass die Tatsache, dass Teile der Daten des DBS extern verwaltet werden, vor dem Benutzer verborgen (transparent) bleibt. Auch erlaubt es diese Architektur, die Daten anderer DBS einzubinden, also eine verteilte Datenbank zu realisieren. Zum DBS hin arbeitet der Data Links File Manager (DLFM; siehe Abbildung 8.11.) Er bindet die Datei an eine Transaktion und löst diese Bindung spätestens mit dem Ende der Transaktion wieder auf. Außerdem überwacht er Integritätsbedingungen und koordiniert Recoveryund Backup-Maßnahmen. Externe Objekte können damit genauso fehlertolerant verwaltet werden wie Datenbankobjekte. Zu den Anwendungen hin kapselt der Data Links Filesystem Filter (DLFF). Er stellt die referenzielle Integrität sicher, so dass die Datei weder „ungenehmigt“ gelöscht noch unbenannt werden kann, und garantiert, dass nur zulässige Zugriffe (unter Transaktionskontrolle) auf dem Objekt ausgeführt werden können. Ein (assoziativer) Zugriff auf externe Objekte wird zunächst wie üblich in Form einer SQL-Anfragen ( 1 ) an das DBS gestellt. Dort werden, möglicherweise unter Zuhilfenahme von Zugriffspfaden, die logischen Namen der gesuchten Objekte (URLs) bestimmt und an die Anwendung zurückgeliefert ( 2 ). Diese greift mit Hilfe der URLs über den DLFF auf die Objekte zu ( 3 ), die dementsprechend dann von der DLFF an die Anwendung geliefert werden ( 4 ). Die Vorteile dieses Ansatzes sind,
8.5 Weitere Neuerungen im Überblick
571
Anwendungen SQLAnfragen
URL
Dateizugriff
DLFF
TABLE Angebotsmappe anschreiben CLOB
...
video
Daten
bilder
DATALINK ARRAY OF type (URL) DATALINK type (URL)
D L F M
Bilddatei
Videodatei
Abb. 8.11: Der Datentyp DATALINK zum Verwalten externer Objekte
• dass Objekte physisch bei der Anwendung abgelegt werden können, da Verweise über Rechnergrenzen hinweg möglich sind, • dass der Overhead des Datenbanksystems beim Zugriff auf das Objekt entfällt; stattdessen kann die für das Objekt günstigste Speicherform gewählt werden und • dass die Vorteile eines datenbankbasierten Einsatzes nicht verloren gehen, da Fehlertoleranz und gemeinsame Ablage von logisch zusammengehörigen Daten gewährleistet ist. Selbst der assoziative Zugriff kann sichergestellt werden, wenn von außen die entsprechenden Daten für Zugriffspfade geliefert werden können.
8.5.8
Java Sprachanbindung
Dem allgemeinen Trend folgend beschäftigt sich die Standardisierungskommission auch mit der Frage, wie SQL in Java eingebettet werden kann. Diesbezügliche Arbeiten laufen als Teil 10: Objekt Sprachanbindung (Part 10: Object Language Bindings (SQL/OLB)), sind aber auch unter dem Namen SQLJ: Part 0 bekannt. Insgesamt ist der Begriff SQLJ jedoch weiter auszulegen, da er auf eine Reihe von Aktivitäten hinweist, deren Ziel die Nutzung der Programmiersprache Java in SQL ist. SQLJ: Part0: Object Language Bindings (SQL/OLB) SQL/OLB beschreibt, wie in Java SQL-Anweisungen deklariert werden können und auf welche Datentypen von Java die Datentypen von SQL abgebildet werden können. Der jetzige Standard basiert allerdings noch auf SQL-92 und JDBC66 1.2. Es ist zu erwarten, dass die meisten Implementierungen dieser Einbindung einen Vorübersetzer (Precompiler) entwickeln 66 Java
Database Connectivity
572
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen
werden, der den eingebundenen SQL-Code in einen JDBC-Code übersetzt. Der Java-Code mit eingebundenen JDBC-Anweisungen wird dann von herkömmlichen Java-Übersetzern in ausführbaren Java-Code übersetzt. Beispiel 8.63 zeigt, wie eine eingebundene Anfrage in SQL und JDBC aussehen könnte. Beispiel 8.63: Eingebetteter SQL- und JDBC-Code Die folgende Anfrage liefert die Adresse des Kunden mit dem Namen nameVar (Parameter). Die erste Version ist in SQL, die zweite in JDBC. SQLJ: # sql [con] { SELECT INTO FROM WHERE
kundenAdresse addrKunde Kunden kundenName = nameVar };
JDBC: JAVA.SQL.PREPAREDSTATEMENT PS = CON.PREPARESTATEMENT(" SELECT kundenAdresse INTO addrKunde FROM Kunden WHERE kundenName = ? "); PS.SETSTRING(1, name); JAVA.SQL.RESULTSET names = PS.EXECUTEQUERY(); names.next(); name = names.getString(1); names.close(); SQLJ Part1: SQL Routines Using the JavaT M Programming Language Die Teile 1 und 2 bilden zusammen eine eigenständige Einheit, die den Teil 0 nicht als Basis voraussetzen, allerdings sich gegenseitig ergänzen. In Teil 1 wird beschrieben, wie statische Java Methoden als Datenbankprozeduren (stored procedures) und benutzerdefinierte Funktionen in SQL umgesetzt werden können, d. h. wie man in Java geschriebene Datenbankprozeduren und Funktionen in einem SQL-Schema nutzen kann. Damit ist hier der Ausgangspunkt genau umgekehrt zu SQL/OLB, wobei allerdings gesagt werden muss, dass es auch Überlappungen gibt, da Java-Methoden intern natürlich wieder SQL-Code ausführen können. SQLJ Part 2: SQL Types Using the JavaT M Programming Language Der zweite Teil setzt sich mit der Definition von Datentypen (Zeilentypen) auseinander. Es wird definiert, wie SQL-Zeilentypen über den CREATE TYPE-Befehl (DROP TYPE) in Java spezifiziert (gelöscht) werden können. Beispiel 8.64 zeigt, wie zunächst eine Java-Klasse Adresse angelegt und dann genutzt wird, um den SQL-Zeilentyp AdrTyp zu kreieren.
8.5 Weitere Neuerungen im Überblick
573
Beispiel 8.64: Java-Klassen mit -Methoden und SQL-Zeilentypen mit -Methoden Anlegen der Java-Klasse Adresse: PUBLIC CLASS Adresse IMPLEMENTS JAVA.IO.SERIALIZABLE, JAVA.SQL.SQLDATA { PUBLIC STRING Strasse; PUBLIC STRING Plz; PUBLIC STATIC INTEGER VorgeschlageneBreite = 25; PRIVATE STRING SQLTyp; /* Für die SQLData Schnittstelle PUBLIC Adresse ( ) { Strasse = ÜNKNOWN"; Plz = "NONE"; }; PUBLIC Adresse (STRING Str1, STRING Str2) { Strasse = Str1; Plz = Str2; };
/* Die Default Konstruktormethode
/* Eine Konstruktormethode mit Parametern
/* liefert als Ergebnis einen Adress-String PUBLIC STRING VolleAdresse ( ) { RETURN SStrasse =" + Strasse + "Plz =" + Plz; }; /* entfernt führende Leerzeichen unter PUBLIC VOID EntferneFührendeLeerzeichen( ) { Strasse = Misc.StreicheFührendeLeerzeichen(Strasse); Nutzung der statischen Methode Plz = Misc.StreicheFührendeLeerzeichen(Plz); }; Misc.StreicheFührendeLeerzeichen
/* Implementierung von SQLDATA: PUBLIC VOID LeseSQL (SQLINPUT SQLEingabe, STRING Typ) THROWS SQLEXCEPTION { SQLTyp = Typ; Strasse = SQLEingabe.LeseString(); Plz = SQLEingabe.LeseString(); }; PUBLIC VOID SchreibeSQL (SQLOUTPUT Ausgabe) THROWS SQLEXCEPTION { Ausgabe.SchreibeString(Strasse); Ausgabe.SchreibeString(Plz); }; PUBLIC STRING LiefereSQLTypName () { RETURN SQLTyp; }; }; Anlegen des SQL-Zeilentyps AdrTyp auf der Basis von SQLJ: CREATE TYPE AdrTyp EXTERNAL NAME ’Adress_Klasse_jar:Adresse’ LANGUAGE JAVA AS( StrasseAttr VARCHAR(50) EXTERNAL NAME ’Strasse’, PlzAttr CHAR (10) EXTERNAL NAME ’Plz’); STATIC METHOD VorgeschlageneBreite ( ) RETURNS INTEGER EXTERNAL VARIABLE NAME ’VorgeschlageneBreite’, METHOD AdrTyp ( ) RETURNS AdrTyp EXTERNAL NAME ’Adresse’, METHOD AdrTyp (StrasseV VARCHAR(50), PlzV CHAR (10)) RETURNS AdrTyp EXTERNAL NAME ’Adresse’,
574
8 Der objektrelationale Teil von SQL:2011 und weitere wesentliche Erweiterungen METHOD VolleAdr ( ) RETURNS VARCHAR(255) EXTERNAL NAME ’VolleAdresse’, METHOD EntferneFührendeLeerzeich ( ) RETURNS AdrTyp SELF AS RESULT EXTERNAL NAME ’EntferneFührendeLeerzeichen’,
8.5.9
Einbindung von XML-Dokumenten
Ab SQL:2014 hat sich die Standardisierungskommission intensiv mit der Integration von XML-Dokumenten in die relationale Datenbankwelt auseinandergesetzt. Auch wenn später noch kurz auf diese Erweiterungen eingegangen wird, wird dieser Datentyp nicht intensiver behandelt, da die Integration von XML in SQL in diesem Lehrbuch nicht abgedeckt wird.
8.6
Literatur
Der SQL:1999-Standard wird in den fünf ISO/IEC-Dokumenten beschrieben ([ISO0199 bis 0599], [ISO0901], [ISO1000] und [ISO1302]), sowie in diversen Artikeln von Jim Melton in der Zeitschrift „Database Programming and Design“ (z. B. ([Melt96a+b]) und zusammen mit Andrew Eisenberg in SIGMOD Record ([EiMe98a, 99a, 00]), von Krishna G. Kulkarni in [Kulk94] und in dem Kapitel von Peter Pistor und Henk Blanken ([PiBl97]). Eine hervorragende Einführung in SQL:1999 liefern die von Nelson Mattos [Matt99] erstellten über 300 Folien zu diesem Thema. Allerdings sei darauf hingewiesen, dass diese Version, ebenso wie z. B. das Kapitel von Pistor und Blanken, nicht ganz aktuell ist, so dass hier und da kleinere Abweichungen zum Standard vorhanden sind. Ein sehr gutes und weitgehend aktuelles Lehrbuch über das objektrelationale SQL ist das Buch von Can Türker und Gunter Saake ([TüSa05]). Die Diskussion und Einführung des Konzepts des abstrakten Datentyps musste in diesem Buch zurück stehen. Der interessierte Leser wird auf das Buch von Ehrich, Gogolla und Lipeck verwiesen ([EhGL89]). Den eigentlichen Standard und dessen Erweiterungen kann man käuflich erwerben und zwar entweder von der ANSI [ANSI] oder dem International Committee for Information Technology Standards INCTIS [INCIT]. Eine Warnung sei aber an diejenigen ausgesprochen, die glauben, diese Unterlagen liefern wegen ihrer Ausführlichkeit eine vollständige Einführung in SQL:2011. Vollständig ja, von Einführung kann aber keine Rede sein. Die Dokumente widmen sich einzig und allein einer Beschreibung des Standards und zwar in einer Form, dass jeder versteht, warum die Umsetzung mindestens 4 Jahre dauert, wobei dann allerdings die eigentliche Implementierung in einer Rekordzeit umgesetzt werden müsste. SQL/MM und Informationen über viele andere SQL-basierte Aktivitäten können von der Homepage der Whitemarsh Information Systems Cooperation [Whit01] abgerufen werden. Hier gibt es Informationen zu den meisten SQL-bezogenen Aktivitäten und damit auch die Drafts zu den SQL/MM Vorschlägen. SQL/MED und DataLinks werden von Judy Davis in [Davi99], Hui-I Hsiao & Inderpal Narang in [HsNa00] und Jim Melton & der verantwortlichen IBM-Gruppe in [MMJK01] vorgestellt. Die Vorschläge insgesamt stammen weitgehend aus der Feder von IBM.
8.6 Literatur
575
SQL/OLB in seiner ursprünglichen Version (nicht auf SQL:2011 und JDBC 2.0 abgestimmt) wird von Andrew Eisenberg und Jim Melton in SIGMOD Record ([EiMe98b]) beschrieben. SQLJ Part1 wird in ([EiMe99b]) eingeführt. Es kann auch unter Whitemarsh Information Systems Cooperation [Whit01] abgerufen werden. Ein gutes Einführungsbuch ist das von Gunter Saake und Kai-Uwe Sattler ([SaSa03]). Literatur zu objektorientierten Konzepten gibt es in Hülle und Fülle. Hier sollen deshalb nur einige deutschsprachige Bücher und zwei internationale aufgeführt werden, die sich weitestgehend den objektorientierten DBMS widmen. Es sind dies die Bücher von Andreas Heuer [Heue97], Alfons Kemper und Guido Moerkotte [KeMo94]. Gunter Saake, Can Türker und Ingo Schmitt ([SaTS99]) und einem der Autoren dieses Buches ([Unla95]). Wer eine auch „politisch“ etwas angereicherte Einführung in Objektbanken haben möchte, sei auf das Buch von Mikel Stonebraker, Dorothy Moore und Paul Brown [StMB98] verwiesen. Die Konkurrenz zum objektrelationalen SQL, der Object Database Standard 3.0 der OMG wird von Rick Cattell und anderen in [CBBE00] beschrieben. Dieser Standard hat sich allerdings nicht durchgesetzt. Objektorientierte Datenbankmanagementsysteme bieten in der Regel als Erweiterung der zugrundeliegenden Programmiersprache (wie Java oder C++) nur eine sehr einfache proprietäre Anfragesprache an, über die inhaltsbezogene Anfragen an eine Klasse gestellt werden können.
9
Transaktionsverarbeitung und Fehlertoleranz
9.1
Transaktionsmanagement
Eine DB stellt eine Menge von Daten zur Verfügung, auf die Anwendungen unabhängig voneinander, aber durchaus zeitgleich zugreifen können (siehe Abbildung 9.1). Eine wesentliche Aufgabe des DBMS ist es deshalb sicherzustellen, dass durch die Parallelarbeit auf der DB keine Inkonsistenzen entstehen können. In diesem Kapitel soll diskutiert werden, welche Probleme beim gleichzeitigen Zugriff auf eine DB auftreten können und welche Verfahren und Techniken entwickelt wurden, um diese Probleme in den Griff zu bekommen. Diese Thematik wird allgemein unter dem Begriff Synchronisation bzw. concurrency control zusammengefasst. Eine weitere ganz wesentliche Eigenschaft von DBMS ist ihre Fehlertoleranz, die insbesondere auch beinhaltet, dass das Ergebnis von abgeschlossenen Arbeiten auf der DB jeden nachfolgenden Fehlerfall überleben muss. Diese Thematik läuft unter dem Begriff Fehlertoleranz oder Recovery und wird nach der Synchronisation diskutiert werden.
Anwendung Anwendung
Anwendung
Anwendung
Anwendung
Daten
Abb. 9.1: Paralleler Zugriff von Anwendungen auf die DB
Anwendung
578
9.1.1
9 Transaktionsverarbeitung und Fehlertoleranz
Probleme bei der Parallelarbeit auf der DB
Bereits in Kapitel 5.1 war die grundsätzliche Funktionsweise eines DBMS diskutiert worden. Eine auf einer vergleichsweise hohen, abstrakten Ebene formulierte SQL-Anfrage wird mit Hilfe des Speichermanagers auf immer einfachere Ebenen herunter transformiert, bis sie schließlich auf eine Menge von einfachen Lese- und Schreiboperationen auf der Platte abgebildet werden kann. Auf dieser untersten Ebene reduziert sich die Arbeit eines DBMS auf das koordinierte Lesen und Schreiben von Sekundärspeicherblöcken (Sektoren) bzw. deren Äquivalent im Hauptspeicher, den Seiten. Der Begriff koordiniert wurde hier bewusst eingesetzt. In konventionellen DBMS wurde häufig auf dieser sehr tiefen Ebene die Parallelarbeit auf der DB koordiniert. Erst die jüngsten DBMS-Versionen namhafter Anbieter unterstützten bereits eine datensatzbezogene Synchronisation. Dadurch kann gegebenenfalls die Performanz des DBMS deutlich ansteigen. Bis dahin fand Synchronisation im Wesentlichen auf der grobgranularen Ebene von Seiten statt. Für die weitere Diskussion in diesem Kapitel wird unterstellt, dass Datensätze das Granulat der Synchronisation sind. Damit stellt sich ein DBMS auf dieser Ebene als System dar, welches aus der Sicht der Anwendung genau zwei atomare Datenbankoperationen zur Verfügung stellt, das Lesen (READ) und das Schreiben (WRITE) von Daten. Atomar bedeutet in diesem Zusammenhang, dass die Lese- bzw. Schreiboperation eine einzige, nicht unterbrechbare Einheit darstellt. Um die folgenden Ausführungen leicht verständlich und konsistent präsentieren zu können, soll von einem erheblich vereinfachten Modell eines DBMS ausgegangen werden, das die Grundlage aller folgenden Beispiele sein soll. Angenommen, wir wären der Betreiber eines Reisebüros für individuelle Flugreisen, welches eine Fluggesellschaft, eine Hotelkette und einen Autoverleih exklusiv vermittelt. Es gibt fünf Kundenschalter, an denen jeweils nach den Wünschen der Kunden individuelle Reisen zusammengestellt werden. Da wir sehr fortschrittlich sind, bedienen wir uns der EDV, wobei insbesondere auch eine Datenhaltung eingerichtet wurde, die sämtliche Daten verwaltet. Vereinfachend gehen wir von nur drei stark simplifizierten Tabellen (Flug, Hotel, Auto) mit folgenden Spalten aus:
CREATE TABLE nummer ort preis freiePlätze
Flug ( INTEGER, VARCHAR(25), DECIMAL(8, 2), INTEGER);
CREATE TABLE name ort preis freieZimmer
Hotel ( VARCHAR(25), VARCHAR(25), DECIMAL(6, 2), INTEGER);
/* alle Flüge gehen vom selben Flughafen ab /* Identifikator des Fluges /* Zielort des Fluges /* Preis des Fluges /* Anzahl noch freier Plätze im Flugzeug
/* Identifikator des Hotels /* Ort, in dem das Hotel liegt /* Zimmerpreis des Hotels /* Anzahl noch freier Hotelzimmer
9.1 Transaktionsmanagement CREATE TABLE typ ort preis freieKapazität
579
Auto ( INTEGER, VARCHAR(25), DECIMAL(8, 2), INTEGER);
/* Identifikator des Autos /* Ort, an dem der Wagen stationiert ist /* Mietpreis des Autos /* Anzahl noch nicht vermieteter Autos
Wäre von allen fünf Schaltern aus ein freier, nicht koordinierter Zugriff auf die Daten erlaubt, so können Situationen wie die folgenden auftreten: Situation 9.1: Verloren gegangene Änderung Ute (Schalter 1) und Elke (Schalter 3) bedienen gerade Kunden, die beide am selben Tag mit demselben Flugzeug nach Rio de Janeiro fliegen wollen (mit Flugnummer 123). Nachdem beide den richtigen Datensatz ausgewählt haben, entwickelt sich folgende Situation: Ute
Elke 1
READ Flug(123).freiePlätze
Zeitachse
(= 12)
READ Flug(123).freiePlätze (= 12) Flug(123).freiePlätze := Flug(123).freiePlätze − 2 WRITE Flug(123).freiePlätze (= 10) Flug(123).freiePlätze := Flug(123).freiePlätze − 1 WRITE Flug(123).freiePlätze (= 11)
↓
Das Resultat der Buchungen ist, dass drei Flugtickets verkauft wurden, die Anzahl der freien Sitzplätze jedoch nur um einen verringert wurde. Die Abbuchung von Elke ist offensichtlich nicht zum Tragen gekommen. Einen solchen Vorgang bezeichnet man als verloren gegangene Änderung (lost update). Situation 9.2: Inkonsistente Sicht und nicht wiederholbares Lesen Gegeben sei die gleiche Situation wie oben, mit dem Unterschied, dass beide Kunden nur dann fliegen möchten, falls Sie auch jeweils ein Zimmer im einzigen von unserem Reisebüro vermittelten Hotel (Seaside) von Rio de Janeiro bekommen. Ute
Elke
Zeitachse
READ Flug(123).freiePlätze (= 12) Flug(123).freiePlätze:=Flug(123).freiePlätze − 2 WRITE Flug(123).freiePlätze (= 10) READ Hotel(Seaside).freieZimmer (= 1) READ Hotel(Seaside).freieZimmer (= 1) Hotel(Seaside).freieZimmer:= Hotel(Seaside).freieZimmer − 1 WRITE Hotel(Seaside).freieZimmer (= 0) READ Flug(123).freiePlätze 1 Hier
(= 10)
↓
handelt es sich um eine verkürzte Notation. In SQL müsste die Anfrage korrekt wie folgt lauten: SELECT freiePlätze FROM Flug WHERE flugNr=123; eine solche informelle, abkürzende Schreibweise soll auch im Folgenden benutzt werden.
580
9 Transaktionsverarbeitung und Fehlertoleranz
Ute bietet Ihrem Kunden jetzt den Flug an, obwohl kein Hotelplatz mehr frei ist. Sie hat eine inkonsistente Sicht auf die Daten erhalten. Würde sie, nachdem Elke ihre Buchung abgeschlossen hat, noch einmal die Anzahl der freien Plätze im Hotel aus der DB lesen wollen, so würde sie dieses Mal den Wert 0 erhalten. Der Wert des ersten Lesevorganges ist, ohne dass Ute dies mitbekommen hat, während ihrer weiteren Arbeit ungültig geworden. Da beim Lesen desselben Datums unterschiedliche Werte geliefert werden, spricht man von einem nicht wiederholbaren Lesen (unrepeatable read). Situation 9.3: Inkonsistente DB Unser Autoverleih in den USA unterhält zwei Niederlassungen in Kalifornien, eine in Los Angeles (LA) und eine in San Francisco (SF). Beide Niederlassungen sollen die gleichen Preise für ihre Wagen nehmen (im Augenblick 100,– $ pro Woche). Aufgrund einer Anhebung der Steuern werden die Preise in Kalifornien generell um zehn Prozent erhöht. Gleichzeitig beschließt unser Reisebüro, grundsätzlich alle Mietwagenpreise in den USA um 50,– $ zu erhöhen, da man ab sofort aufgrund schlechter Erfahrungen ein Auto nur noch mit Vollkaskoversicherung vermieten will. Heinz (Schalter 2) führt die erste Änderung durch, Willy (Schalter 5) die zweite. Heinz
Willy READ Auto(LA).preis
Zeitachse (= 100,–)
Auto(LA).preis := Auto(LA).preis ∗ 1.1 WRITE Auto(LA).preis READ Auto(LA).preis
(= 110,–)
(= 110,–)
Auto(LA).preis := Auto(LA).preis + 50,– WRITE Auto(LA).preis
(= 160,–)
READ Auto(SF).preis
(= 100,–)
Auto(SF).preis := Auto(SF).preis + 50,– WRITE Auto(SF).preis
(= 150,–) READ Auto(SF).preis
(= 150,–)
Auto(SF).preis := Auto(SF).preis ∗ 1.1 WRITE Auto(SF).preis
(= 165,–)
↓
Nachdem beide Änderungen durchgeführt wurden, muss für einen Wagen in Los Angeles 160,– $ bezahlt werden, für den gleichen Wagen in San Francisco jedoch 165,– $. Und das, obwohl der Mietpreis in beiden Städten gleich sein soll. Situation 9.3 ist ein Beispiel dafür, wie zwei Folgen von parallel ablaufenden Änderungsoperationen einander so beeinflussen können, dass eine inkonsistente DB entsteht. Situation 9.4: Phantomproblem Elke bedient einen Kunden, der in Kalifornien Urlaub machen möchte. Da der Kunde eine kleine Rundreise plant, stellt Elke ihm zunächst alle Hotels in Kalifornien vor. Während sie mit dem Kunden die weiteren Details bespricht, fügt Willy ein neues, kürzlich in Los Angeles eröffnetes Hotel in die DB ein. Nachdem der Kunde sich für eine Route und
9.1 Transaktionsmanagement
581
damit für die diesbezüglichen Hotels entschieden hat, möchte Elke die Hotels buchen. Da der Startpunkt Los Angeles sein soll und dort mehrere Hotels angeboten werden, lässt Elke sich noch einmal alle dortigen Hotels anzeigen und erhält plötzlich gegenüber ihrer ersten Suche ein Hotel mehr angezeigt. Elke
Willy
Zeitachse
READ Hotel(CA).name (Nightmare, Worst Eastern, Die Hard) INSERT Hotel(LA)[JunkView,. . . ] ... READ Hotel(LA).name (Nightmare, JunkView)
↓
Das aufgezeigte Problem heißt Phantomproblem. Unter einem Phantom versteht man all die Objekte, die aufgrund der Schemadefinition zwar zum Wertebereich einer Datenbanktabelle gehören, also in der DB existieren könnten, aber zu einem gegebenen Zeitpunkt (noch) nicht in der DB existieren. Alle vier Situationen beschreiben Fehlerfälle, die nur deshalb auftreten konnten, weil Arbeiten auf der DB parallel ausgeführt wurden. Zwei Beobachtungen fallen ins Auge: Feststellung 9.1: Menge von semantisch zusammengehörigen Operationen Es lässt sich normalerweise eine Menge von Operationen identifizieren, die man als semantisch zusammengehörig ansehen kann. Nur wenn diese Operationen in ihrer Gesamtheit ausgeführt werden, beschreiben sie eine konsistente Handlung. In Situation 9.2 gilt beispielsweise, dass nur die vollständige Ausführung der Operationsfolge von Elke zum gewünschten Resultat führt, da der Kunde Flug und Hotel möchte. Würde eine der beiden Operationen nicht korrekt ausgeführt werden können, wäre die gesamte Transaktion in Frage gestellt. Andersherum ist aber auch klar, dass die von Elke in Situation 9.2 ausgeführten Operationen in keinen Zusammenhang zu den von ihr in Situation 9.1 getätigten Operationen stehen. Die Operationsfolge in Situation 9.2 ist also unabhängig von der Operationsfolge in Situation 9.1. Feststellung 9.2: Isolation einer zusammengehörigen Operationsfolge Eine zusammengehörige Operationsfolge muss unbeeinflusst von anderen Operationen ausgeführt werden, d. h. sie muss ablaufen, als wäre sie gegenwärtig die einzige auf der DB arbeitende Operationsfolge. Würden in den obigen Beispielen alle Operationsfolgen in beliebiger Reihenfolge, aber nacheinander ausgeführt, so wären die erzielten Resultate offensichtlich richtig. Diese Beobachtungen führen uns direkt zum Transaktionsbegriff.
582
9.1.2
9 Transaktionsverarbeitung und Fehlertoleranz
Das Transaktionskonzept
Eine Transaktion ist das Konzept, das es ermöglicht, eine Folge von Benutzeraktionen als zusammengehörig zu deklarieren. Transaktionen sind für DBS von zentraler Bedeutung und stellen eines der wesentlichen Unterscheidungsmerkmale zu konventionellen Dateisystemen dar. Definition 9.1: Transaktion Eine Transaktion stellt eine Folge von logisch zusammengehörigen Operationen auf der DB dar, die von einer Anwendung durchgeführt werden. Diese Folge repräsentiert eine konsistenzwahrende Einheit, was insbesondere heißt, dass die DB durch die Transaktion von einem konsistenten Zustand in einen nicht zwangsläufig unterschiedlichen konsistenten Zustand überführt wird. Ob Operationen als eine logische Einheit anzusehen sind, kann ohne Kenntnis des Zusammenhanges nicht entschieden werden. Wenn z. B. in Situation 9.2. Elke das Hotel für einen Kunden und das Flugzeug für einen anderen gebucht hätte, so wären die beiden Operationen sehr wohl unabhängig voneinander. Daher muss grundsätzlich die Anwendung die Klammerung von Operationen durch eine Transaktion veranlassen; das DBMS kann eine solche Entscheidung nicht fällen. Typische SQL-Statements zu diesem Zweck sind: BEGIN_OF_TRANSACTION END_OF_TRANSACTION bzw. COMMIT
(BOT) (EOT)
Es sei angemerkt, dass die explizite Definition von Transaktionsgrenzen nicht von allen kommerziellen DBMS unterstützt wird. Zum Teil wird jeder Zugriff auf die DB durch eine Anwendung implizit als Beginn einer Transaktion gewertet, so dass nur noch deren Ende festgelegt werden kann. Zum Teil wird eine Transaktion insgesamt nur implizit definiert, beispielsweise indem sie mit einem SQL- bzw. Anfrageblock gleichgesetzt wird. Dann ist es dem Anwender nicht möglich, größere Einheiten als eine zusammengehörige Folge von Operationen zu definieren, was zu solch unschönen Nebeneffekten wie dem Verlust der Konsistenz der DB führen kann. Ein Datenbankzustand ist genau dann konsistent, wenn sowohl die semantische als auch die operationale Integrität sichergestellt sind. Wie bereits in Kapitel 7.8 diskutiert wurde, kann die semantische Integrität nur eingeschränkt automatisch vom DBMS überwacht werden. Allerdings kann und muss das DBMS die Aufgabe übernehmen, die operationale Integrität sicherzustellen. Aufgrund des parallelen Ablaufs von Transaktionen dürfen keine Inkonsistenzen entstehen. Die wesentlichen Eigenschaften einer korrekt arbeitenden Transaktion werden im ACIDKriterium zusammengefasst2: Definition 9.2: ACID-Kriterium Das ACID-Kriterium legt die Eigenschaften fest, die man allgemein mit einer Transaktion verbindet: 2 Der
Name leitet sich aus den jeweils ersten Buchstaben der englischen Begriffe ab.
9.1 Transaktionsmanagement
583
A Unteilbarkeit (atomicity) Da eine Transaktion eine Folge von Operationen beschreibt, die nur in ihrer Gesamtheit ausgeführt die Konsistenz der DB garantieren, müssen sie entweder vollständig oder gar nicht ausgeführt werden. Tritt also während der Transaktionsausführung ein nicht korrigierbarer Fehler auf, so muss jede von der Transaktion durchgeführte Änderung (automatisch) rückgängig gemacht werden. C Konsistenz (consistency) Eine erfolgreich durchgeführte Transaktion überführt die DB von einem konsistenten Zustand in einen nicht zwangsläufig unterschiedlichen konsistenten Zustand. Sollten während des Ablaufes einer Transaktion inkonsistente Zwischenzustände vorkommen, müssen diese bis zum Transaktionsende beseitigt sein.3 I
Isolation (isolation) Eine Transaktion muss immer so ablaufen, als wäre sie die einzige im System. Parallele Transaktionen dürfen einander nicht beeinflussen.
D Dauerhaftigkeit (durability) Änderungen, die von einer erfolgreich abgeschlossenen Transaktion durchgeführt werden, überleben jeden nachfolgenden Fehlerfall.
Die Unteilbarkeit bedeutet, dass das DBMS in der Lage sein muss, zu jedem Zeitpunkt während einer Transaktionsausführung alle bereits durchgeführten Änderungen rückgängig zu machen. Hierfür sind geeignete Maßnahmen vorzusehen. In der Regel werden die „alten“ Zustände der Daten aufbewahrt. Die Komponente, die für das korrekte Zurücksetzen einer noch laufenden Transaktion ebenso zuständig ist wie für das Erzeugen eines korrekten Datenbankzustandes nach einem größeren Systemfehler (z. B. Systemzusammenbruch oder Plattenfehler), heißt Recoverykomponente. Sie wird in Kapitel 9.2.5 ausführlicher besprochen. Die Eigenschaft der Konsistenz schließt inkonsistente Zwischenzustände während des Ablaufes einer Transaktion nicht aus. Nur müssen diese bis zum Ende der Transaktion beseitigt sein. In Situation 3 beispielsweise ist die DB zwangsläufig während der Ausführung von jeder der Änderungstransaktionen vorübergehend in einem inkonsistenten Zustand, da die Preise für ein Auto in einigen Städten bereits erhöht wurden, in anderen aber noch nicht. Damit ist das Gebot der Einheitlichkeit des Preises in allen Städten vorübergehend nicht erfüllt. Dies spielt aber auch keine Rolle, da wegen der logischen Atomarität einer Transaktion die zwischenzeitliche Inkonsistenz von außen nicht wahrgenommen werden kann. Wichtig ist deshalb nur, dass am Ende der Transaktion wieder ein konsistenter Zustand erreicht ist. Um schnelle Antwortzeiten garantieren zu können, boten kommerzielle DBMS lange Zeit und bieten teilweise immer noch nur wenige Möglichkeiten zur Konsistenzsicherung. Damit wird die Verantwortung dafür auf die Anwendungsprogramme abgewälzt. Das DBMS wirkt dabei insofern unterstützend, als es dem Anwendungsprogrammierer erlaubt, jederzeit automatisch, als Konsequenz aus einer festgestellten Integritätsverletzung, eine noch nicht abgeschlossene Transaktion zurückzusetzen. Zwar hat sich der SQL-92-Standard sehr verdient 3 Dieses Kriterium drückt in gewisser Weise einen Wunsch aus, da, wie bereits mehrfach diskutiert, das DBMS nur sehr eingeschränkt selbständig die Korrektheit von Daten und Beziehungen zwischen Daten garantieren kann.
584
9 Transaktionsverarbeitung und Fehlertoleranz
um Integritätssicherungsmaßnahmen gemacht, deren exzessiver Einsatz wird aber immer noch zu erheblichen Performanzproblemen führen. Das Gebiet der Isolation von parallel laufenden Transaktionen hat sich zu einem sehr großen und eigenständigen Forschungsfeld in der Datenbankwelt entwickelt. Dabei sind zwei Hauptströmungen erkennbar: Die eine setzt sich mit der Theorie einer korrekten Isolation von Transaktionen auseinander (die so genannte Serialisierbarkeitstheorie), während sich die andere Richtung um (praktisch anwendbare) Verfahren zur Isolation kümmert (so genannte Synchronisationsverfahren). Wegen der großen Bedeutung der Isolationseigenschaft werden wir uns in den folgenden Abschnitten dieses Kapitels hauptsächlich mit ihr befassen. Aufgrund der Eigenschaft der Dauerhaftigkeit muss ein DBMS dafür Sorge tragen, dass Änderungen, die von einer Transaktion durchgeführt wurden, vor deren Ende auf einem nichtflüchtigen Speichermedium gesichert werden. Dabei können entweder die „neuen“ Daten abgelegt werden oder die Operationen, die zu den Änderungen geführt haben, sofern diese eindeutig wiederholbar sind. Die Tatsache, dass durch den erfolgreichen Abschluss einer Transaktion die Dauerhaftigkeit der Ergebnisse garantiert wird, bedeutet auch, dass eine abgeschlossene Transaktion vom System nicht mehr zurückgesetzt werden kann, auch dann nicht, wenn sich im Nachhinein deren Fehlerhaftigkeit herausstellt. Solche Änderungen können nur beseitigt werden, indem mit Hilfe einer weiteren Transaktion die vorher durchgeführten Änderungen wieder rückgängig gemacht werden. Transaktionen, die diese Aufgabe übernehmen, werden Kompensationstransaktionen genannt. Fehlertoleranz wird das Thema von Kapitel 9.3 sein.
9.1.3
Serialisierbarkeit
Die vier in Kapitel 9.1.1 vorgestellten Situationen zeigen, dass die parallele Abarbeitung von Transaktionen Regeln unterworfen sein muss, die von der so genannten Synchronisationskomponente überwacht werden. Offensichtlich würde in allen Situationen von Kapitel 9.1.1 genau das geschehen, was von der Aufgabenstellung her beabsichtigt ist, wenn die Transaktionen in beliebiger Reihenfolge nacheinander ausgeführt würden. Diese Überlegung gilt allgemein und führt unmittelbar zu einer Aussage darüber, wann ein System paralleler Transaktionen „korrekt“ abläuft: Definition 9.3: Serialisierbarkeit Ein paralleles System von Transaktionen ist dann korrekt synchronisiert, wenn es serialisierbar ist, d. h. wenn es mindestens eine (gedachte) serielle Ausführung derselben Transaktionen gibt, die 1. denselben Datenbankendzustand erzeugt und bei der 2. alle Transaktionen dieselben Ausgabedaten liefern (siehe Abbildung 9.2). Bemerkenswert ist, dass es lediglich irgendeine serielle Ausführung mit gleicher Wirkung geben muss; die Reihenfolge der Transaktionen unterliegt keinerlei Restriktionen, sie darf beliebig sein. Das hat zur Konsequenz, dass der Datenbankendzustand durchaus auch von Zufällen abhängen kann wie beispielsweise der aktuellen Maschinenbelegung. In Bezug auf
9.1 Transaktionsmanagement
585
Eine parallele Ausführung von Transaktionen muss T1 T3 T2
1
2
3
4
5
6
7
8
9
10
denselbenDatenbankendzustand und dieselben Ausgaben liefern wie eine beliebige sequentielleAusführung der Transaktionen T3 3
6
T2 10
2
4
T1 7
9
1
5
8
Operation Abb. 9.2: Serialisierbarkeit
unser Reisebüro wäre es demnach durchaus möglich, dass Ute dem Kunden X den letzten Flug vermitteln kann, obwohl Elke bereits vorher eine Transaktion gestartet hatte, innerhalb derer sie ihrem Kunden genau diesen Flug reservieren wollte. In der seriellen Transaktionsreihenfolge müsste dann die Transaktion von Ute offensichtlich vor der Transaktion von Elke stehen. Darüber hinaus kann die Serialisierbarkeit auch dann gewährleistet sein, wenn Transaktionen, die in der realen Zeit in einer bestimmten Reihenfolge abgelaufen sind, vom Synchronisationsverfahren so angeordnet werden, als wären sie in einer anderen Reihenfolge gestartet worden. Aus der Sicht des Systems muss also nicht unbedingt eine Integritätsverletzung vorliegen, wenn Elke zeitlich gesehen die Zahl der freien Plätze in einem Flugzeug liest, nachdem Ute den letzten Platz vermittelt hat und trotzdem den Zustand der DB vor dieser Buchung durch Ute als Ergebnis geliefert bekommt (und damit die Zahl 1). Allerdings ist es in dieser Situation natürlich nicht erlaubt, dass Ute in ihrer Transaktion die Zahl der freien Flugplätze verändert. Theoretisch wäre es also möglich, Lesetransaktionen auf einem alten Datenbankzustand laufen zu lassen. Damit würden sie nicht die aktuellen Daten zu Gesicht bekommen. Eine solche Situation ist zwar aus der Sicht der Serialisierbarkeit korrekt, in den meisten Fällen aber aus der Sicht des Benutzers inakzeptabel. Ist eine Vertauschung von nacheinander ausgeführten Transaktionen ausgeschlossen, so heißt das Transaktionssystem strikt serialisierbar. Praktisch alle heute im Einsatz befindlichen Synchronisationsverfahren garantieren strikte Serialisierbarkeit, weshalb Effekte der obigen Art ausgeschlossen sind. Die Serialisierbarkeitstheorie (serializability theory) stellt die Hilfsmittel zur Verfügung, mit deren Hilfe die Korrektheit von Synchronisationsverfahren formal nachgewiesen werden kann. Obwohl ein umfassender Einstieg in dieses Gebiet den Rahmen dieses Kapitels
586
9 Transaktionsverarbeitung und Fehlertoleranz
deutlich sprengen würde, soll hier doch zumindest ein leicht verständlicher Einblick in die Materie gegeben werden. Die mathematisch exakte Darstellung des Stoffes spielt dabei eine untergeordnete Rolle. Ausgangspunkt der folgenden Ausführungen ist ein relativ abstraktes Modell eines DBMS. Definition 9.4: Abstraktes Modell eines DBMS Ein vereinfachtes Modell eines DBMS soll aus den Komponenten DB, Transaktion und Objekt bestehen. Objekte sind die Datenbankeinheiten, die für eine Transaktion zugreifbar sind. Jeder Zugriff auf ein Objekt stellt eine Operation dar. Operationen sind atomar und können vom Typ Lesen (READ) oder Schreiben (WRITE) sein. Eine Schreiboperation kann dabei sowohl eine Einfüge-, eine Änderungs- als auch eine Löschoperation realisieren. Eine Transaktion ist in diesem Modell aus der Sicht des DBMS eine Folge von (atomaren) Operationen auf Objekten der DB. Mit oim sei die m-te Operation der Transaktion Ti bezeichnet. Oi : oi1 . . . oin sei die zu Ti gehörige Operationsfolge. Auf Oi sei die Relation vor definiert in dem Sinn, dass gilt oim vor oin , wenn oim in Oi vor oin steht. Vor bedeutet im Datenbankgeschehen, dass die Operation oim vor der Operation oin ausgeführt wird. Ist die genaue Position einer Operation innerhalb einer Transaktion nicht von Wichtigkeit, so schreiben wir Ri (x) bzw. Wi (x) und meinen damit, dass die Transaktion mit der Nummer i lesend bzw. schreibend auf das Objekt x zugreift. Definition 9.5: Schedule T ∗ = (T1 , . . . , Tn ) sei eine Menge von fest vorgegebenen Transaktionen. Eine Schedule S (auch Historie (history), log oder computation genannt) ist eine beliebige Permutation der Operationen der Transaktionen aus T ∗ mit der Einschränkung, dass die relative Reihenfolge der Operationen jeder Transaktion erhalten bleiben muss. Eine Schedule ist also eine beliebige Aneinanderreihung der Operationen aller Transaktionen, wobei aber die Operationen einer Transaktion in ihrer Reihenfolge nicht vertauscht werden dürfen. Auf S sei ebenfalls eine Relation vor definiert, so dass gilt: ojm vor oin , falls ojm in S vor oin steht, m. a. W. die Operation ojm vor der Operation oin ausgeführt wird. Mit S ∗ wird die Menge aller Schedule bezeichnet, die insgesamt über T ∗ erzeugt werden können, falls es keine Reglementierung bzgl. der Reihenfolge der Abarbeitung der Operationen zwischen den Transaktionen gibt. Offensichtlich gibt es nun in S* eine Reihe von Schedulen, die, falls sie genau so auf der DB ausgeführt würden, deren Konsistenz verletzen würden. Dazu gehören alle Schedule, die zu einer der vier Situationen aus Kapitel 9.1.1 führen können. Andere Schedule dagegen hinterlassen die DB in einem korrekten Zustand. Und genau diese Schedule interessieren uns, da ein korrekt arbeitendes Synchronisationsverfahren natürlich nur solche Schedule erzeugen bzw. akzeptieren darf. Direkt einsichtig ist sicherlich, dass diejenigen Schedule, in denen die Operationen jeder Transaktion direkt nacheinander ausgeführt werden, auf jeden Fall die operationale Integrität garantieren. Eine solche Schedule entspricht einer seriellen Ausführung aller Transaktionen und heißt deshalb auch serielle Schedule. Schwieriger ist da schon das Erkennen von
9.1 Transaktionsmanagement
587
serialisierbaren Schedulen. Das sind Schedule, die zwar nicht seriell sind, aber in ihren Auswirkungen einer seriellen Schedule entsprechen. Diese Schedule beschreiben eine parallele, aber korrekte Ausführung der Transaktionen auf der DB. Definition 9.6: Serielle und serialisierbare Schedule Werden Transaktionen sequenziell nacheinander ausgeführt, entsteht eine Schedule, in der immer erst alle Operationen einer Transaktion stehen, bevor die Operationen der nächsten Transaktion kommen. Eine solche Schedule heißt seriell. Entsprechen die Auswirkungen einer Schedule denen einer seriellen Schedule, so spricht man von einer serialisierbaren Schedule. Solche Schedule erzeugen denselben Datenbankendzustand und dieselben Ausgaben wie mindestens eine serielle Schedule. Beispiel 9.1: Schedule und Serialisierbarkeit Gegeben sei das Transaktionssystem T ∗ mit den beiden Transaktionen T1 und T2 , die die folgenden Operationen durchführen: T1 : R1 (x) W1 (x)
T2 : R2 (y) R2 (x) W2 (x)
Die Menge S* setzt sich dann aus den folgenden zehn Schedulen zusammen: 1. R1 (x) W1 (x) R2 (y) R2 (x) W2 (x) 2. R2 (y) R1 (x) R2 (x) W1 (x) W2 (x) 3. R1 (x) R2 (y) W1 (x) R2 (x) W2 (x) 4. R2 (y) R1 (x) R2 (x) W2 (x) W1 (x) 5. R1 (x) R2 (y) R2 (x) W1 (x) W2 (x) 6. R2 (y) R2 (x) R1 (x) W1 (x) W2 (x) 7. R1 (x) R2 (y) R2 (x) W2 (x) W1 (x) 8. R2 (y) R2 (x) R1 (x) W2 (x) W1 (x) 9. R2 (y) R1 (x) W1 (x) R2 (x) W2 (x) 10. R2 (y) R2 (x) W2 (x) R1 (x) W1 (x) Wie man sicherlich leicht nachvollziehen kann, sind die Schedule 1. und 10. seriell, während die Schedule 3. und 9. serialisierbar sind4 . Alle anderen Schedule können, würden sie genau so ausgeführt, zu einer inkonsistenten DB führen, da die Gefahr des Verlorengehens einer Änderung (lost update) besteht. Es wird bei der Darstellung von Schedulen grundsätzlich unterstellt, dass die letzte Aktion einer Transaktion gleichzusetzen ist mit deren Terminierung. Außerdem findet jede durch 4 Beide
entsprechen einer seriellen Ausführung nach 1.
588
9 Transaktionsverarbeitung und Fehlertoleranz
eine Transaktion durchgeführte Aktion auch direkt ihren Niederschlag in der DB. Hat also eine Transaktion eine Schreiboperation ausgeführt, so liest jede nachfolgende Leseaktion den neuen Wert. Gleichzeitig mit einer Schreiboperation wird auch die Sperre auf dem Objekt freigegeben, so dass eine Transaktion ab ihrer Schreiboperation kein neues Datum mehr aus der DB lesen darf. Etwas abstrahiert gesehen kann ein Synchronisationsverfahren (in diesem Zusammenhang häufig auch Scheduler genannt) nun als die Komponente angesehen werden, die einen beliebigen (seriellen) Ankunftsstrom von Aufforderungen zur Ausführung von Operationen (beliebige Schedule S aus S∗ , im Folgenden Ausgangsschedule genannt) auf eine serialisierbare Schedule abbildet (im Folgenden Ergebnisschedule genannt). Im Gegensatz zur bisherigen Diskussion muss man von einem praxisgerechten Scheduler allerdings erwarten, dass er nicht zunächst eine Folge von Operationen sammelt, um diese dann passend umzuordnen und zur Ausführung zu bringen, sondern er muss „Online“ arbeiten. Bei jeder eingehenden Operationsaufforderung ist direkt zu entscheiden, ob die Operation ausgeführt werden darf oder aufgrund von möglichen Zugriffskonflikten verzögert oder zurückgewiesen wird. Letzteres führt i. d. R. zum Rücksetzen der Transaktion. Ein Scheduler muss also auf jeden Fall einen Konflikt erkennen. Je nach Algorithmus kann es aber auch möglich sein, dass ein „zu vorsichtiger“ Scheduler einen Konflikt annimmt, obwohl in Wirklichkeit keiner vorliegt. Dann werden an sich mögliche Abarbeitungsreihenfolgen abgeändert. Die Qualität eines Schedulers hängt von folgenden Kriterien ab: 1. Durchlässigkeit Inwieweit ist der Scheduler in der Lage, serielle und serialisierbare Ausgangsschedule zu erkennen und inwieweit lässt er diese ohne Eingriff in den Ablauf der Operationsfolge arbeiten (Ausgangsschedule = Ergebnisschedule). Ein aus der Sicht der Durchlässigkeit optimaler Scheduler würde alle Konflikte beseitigen und alle Situationen, in denen kein Konflikt vorliegt, unverändert lassen. 2. Steuerungsvermögen Inwieweit ist der Scheduler in der Lage, nicht serialisierbare Ausgangsschedule direkt, d. h. ohne Transaktionen zurückzusetzen, in serialisierbare Ergebnisschedule umzuwandeln. 3. Aufwand Wie hoch ist der Aufwand, der durch den Scheduler verursacht wird. Hierunter fallen sowohl der direkte Aufwand, der durch die Arbeit des Schedulers verursacht wird wie z. B. die Analyse des Eingabestroms von Operationen, als auch der indirekte Aufwand. Letzteres betrifft beispielsweise Kosten, die durch die Maßnahmen entstehen, die der Scheduler anordnet, wie Wartezeiten oder Rücksetzprozesse von Transaktionen. Rücksetzprozesse können u. a. durch das Zurückweisen einer Operation dieser Transaktion ausgelöst werden. Durchlässigkeit und Steuerungsvermögen sind zwei sich in gewisser Weise widersprechende Eigenschaften. Da ein Scheduler immer direkt entscheiden muss, ob er eine Operation zulässt oder nicht, bedeutet eine hohe Durchlässigkeit, dass im Zweifelsfall eine Operation eher erlaubt wird. Damit tritt aber dann häufiger der Fall auf, das nicht serialisierbare Ausgangsschedule erst zu spät erkannt werden und nur durch das Zurücksetzen einer Transaktion in
9.1 Transaktionsmanagement
589
eine serialisierbare Ergebnisschedule umgewandelt werden können. Entsprechend ist damit das Steuerungsvermögen des Verfahrens nicht sehr gut. Umgekehrt, ein gutes Steuerungsvermögen wird normalerweise dadurch erreicht, dass eine Ausgangsschedule schon dann umgeformt wird, wenn der Verdacht auf Nichtserialisierbarkeit auftritt. Dann werden aber normalerweise auch serialisierbare Schedule umgeformt, worunter die Durchlässigkeit erheblich leidet. Wir werden später noch einmal kurz auf das Problem der Durchlässigkeit zurückkommen. Zunächst soll jedoch eine Bedingung dafür angegeben werden, wann eine Schedule serialisierbar ist. Dazu ist es notwendig, den Begriff Konflikt zu definieren. Definition 9.7: Konflikt Zwei Operationen oim und ojn verschiedener Transaktionen stehen in Konflikt zueinander, wenn sie auf dasselbe Objekt zugreifen und mindestens eine der Operationen eine Schreiboperation (WRITE) ist. Für die Frage der Serialisierbarkeit ist nur die Reihenfolge der Operationen, die in Konflikt zueinander stehen, von Bedeutung. Die Reihenfolge von Leseoperationen, die nacheinander von verschiedenen Transaktionen auf demselben Objekt(zustand) ausgeführt werden, ist unwichtig, da sie alle denselben Wert lesen und damit die Reihenfolge des Lesens unerheblich ist. Die Leseoperation ist also kommutativ. Dagegen definiert offensichtlich genau die Reihenfolge der zueinander in Konflikt stehenden Operationen eine Abhängigkeit zwischen den beteiligten Transaktionen in dem Sinn, dass eine Transaktion Tj bzgl. einer Schedule S abhängig wird von einer Transaktion Ti , falls es zwei Operationen oim ∈ Oi und ojn ∈ Oj gibt, wobei oim vor ojn in S ausgeführt wird. Es leuchtet sicherlich ein, dass eine Schedule S nicht serialisierbar ist, falls bzgl. zweier Transaktionen Ti und Tj sowohl eine Abhängigkeit von Ti von Tj besteht als auch umgekehrt von Tj von Ti . Diese gegenseitige Abhängigkeit drückt aus, dass in einem Fall Ti eine konfliktäre Operation auf einem Objekt vor Tj beendet hat und das andere Mal das Umgekehrte gilt. Damit kann es zu S keine äquivalente serielle Schedule geben, da weder Ti vor Tj ausgeführt werden kann noch umgekehrt.
Beispiel 9.2: Wechselseitige Abhängigkeit Die Schedule 2, 4, 5, 6, 7 und 8 von Beispiel 9.1 sind deshalb nicht serialisierbar, weil jede der Transaktionen T1 und T2 sowohl vor als auch nach der anderen Transaktion mit zueinander in Konflikt stehenden Operationen auf x zugreift. Damit entstehen die folgenden wechselseitigen Abhängigkeiten. Schedule 2, 5 und 6: T1 vor T2 wegen W1 (x) W2 (x) und T2 vor T1 wegen R2 (x) W1 (x) Schedule 4, 7 und 8: T1 vor T2 wegen R1 (x) W2 (x) und T2 vor T1 wegen W2 (x) W1 (x)
590
9 Transaktionsverarbeitung und Fehlertoleranz
Die zwischen Transaktionen bestehenden Abhängigkeiten lassen sich in so genannten Abhängigkeitsgraphen darstellen. Definition 9.8: Abhängigkeitsgraph Stellt man die Transaktionen einer Schedule S als Knoten eines gerichteten Graphen G und die zwischen den Transaktionen bestehenden Abhängigkeiten als gerichtete Kanten dar, so erhält man einen Abhängigkeitsgraphen (serialization graph) von S. Ein Abhängigkeitsgraph ist nun die Basis zur Überprüfung der Serialisierbarkeit eines Transaktionssystems. Enthält der Abhängigkeitsgraph keinen Zyklus, so ist die Schedule serialisierbar. Dies ist die Aussage des Serialisierbarkeitskriteriums. Definition 9.9: Serialisierbarkeitskriterium Ein Abhängigkeitsgraph G ist zyklenfrei ⇔ die Schedule S ist serialisierbar. Beispiel 9.3: Abhängigkeitsgraph Gegeben seien die drei Transaktionen T1 , T2 und T3 und die folgenden beiden Schedule: 1. R3 (y) R1 (x) R2 (y) W1 (x) R2 (x) W2 (x) R3 (x) W3 (y) 2. R1 (x) R2 (y) R3 (y) W3 (y) R3 (x) W1 (x) R2 (x) W2 (x) Wie den beiden folgenden Auflistungen der Abhängigkeiten entnommen werden kann, ist die erste Schedule serialisierbar, die Zweite nicht. Schedule 1 (serialisierbar)
Schedule 2 (nicht serialisierbar)
①
wegen W1 (x) R2 (x), W1 (x) W2 (x) und R1 (x) W2 (x)
②
wegen R2 (y) W3 (y) und W2 (x) R3 (x)
③
wegen W1 (x) R3 (x)
1
T2
T1
3
wegen R3 (x) W1 (x)
1
2
T2
T1 T3
Schedule 1 (ohne Zyklus)
3
2 T3
Schedule 2 (mit Zyklus)
Achtung 9.1: Wirkungslose Transaktionen Die angegebene Serialisierbarkeitsbedingung ist zwar hinreichend, aber nicht notwendig. Die Formulierung einer notwendigen Bedingung müsste den Fall so genannter wirkungsloser Transaktionen (dead transactions, useless transactions) berücksichtigen. Man betrachte etwa das folgende Beispiel.
9.1 Transaktionsmanagement
591
Beispiel 9.4: Wirkungslose Transaktionen Gegeben sei die folgende Schedule S: R1 (x) W2 (x) W1 (x) W3 (x) Obwohl der zu S gehörige Abhängigkeitsgraph einen Zyklus aufweist, ist S serialisierbar, da S äquivalent zur folgenden seriellen Schedule ist: R1 (x) W1 (x) W2 (x) W3 (x) Die von T2 durchgeführte Änderung hat keinen Einfluss auf den Datenbankendzustand und wurde auch nie gelesen, so dass diese Transaktion wirkungslos ist. Würde man voraussetzen, dass jede Transaktion das Objekt, das sie ändern möchte, vorher liest, so gäbe es keine wirkungslosen Transaktionen. Unter einer solchen Voraussetzung ist das Serialisierbarkeitskriterium nicht nur hinreichend, sondern auch notwendig. Praktisch relevante Synchronisationsverfahren können wirkungslose Transaktionen nicht berücksichtigen, da sie ansonsten entweder vorhersehen können müssten, um zu erkennen, dass der Widerspruch zwischen T1 und T2 später durch T3 aufgelöst wird, oder sie müssten bei einem Konflikt mit der Konfliktbeseitigung so lange warten, bis klar ist, ob der bestehende Zyklus noch durch eine hinzukommende Transaktion behoben wird. Könnte das Synchronisationsverfahren vorausschauen, so könnte es wirkungslose Transaktionen ohnehin von vornherein übergehen. Bei der zweiten Variante würde sich die Wartezeit nicht vorhersagen lassen, was dazu führt, dass Transaktionen für einen unter Umständen sehr langen Zeitraum nicht abgeschlossen werden können. Bevor die knappe Einführung in die Serialisierbarkeitstheorie abgeschlossen wird, soll noch kurz auf die Durchlässigkeit von Schedulern eingegangen werden. Die Tatsache, dass wir ein Serialisierbarkeitskriterium entwickelt haben, bedeutet nun noch nicht, dass damit der Test auf Serialisierbarkeit effizient durchführbar ist. Leider ist das Gegenteil der Fall: Das Entscheidungsproblem, ob eine Schedule S serialisierbar ist, ist NPvollständig und zwar auch dann, wenn wirkungslose Transaktionen ausgeschlossen sind. Damit ist klar, dass Algorithmen, die die Frage der Serialisierbarkeit exakt beantworten können, einen exponentiellen Zeitaufwand benötigen. In der Serialisierbarkeitstheorie musste man daher zwangsläufig Kriterien entwickeln, die etwas gröber arbeiten, dafür aber in polynomieller Zeit zu einem Ergebnis kommen. Das Thema soll hier nicht weiter vertieft werden, weshalb der interessierte Leser auf die Literatur im Bereich der Synchronisationstheorie verwiesen wird. Neben der Tatsache, dass es keine effizienten Algorithmen gibt, die alle serialisierbaren Schedule erkennen, gibt es aber auch noch andere Argumente, die gegen das Akzeptieren jeder serialisierbaren Schedule durch das Synchronisationsverfahren sprechen. Ein ganz wichtiger Aspekt ist die Atomarität. Sie bedingt nämlich, dass es jederzeit möglich sein muss, eine Transaktion zurückzusetzen, beispielsweise wegen eines Systemfehlers oder aufgrund eines Benutzerwunsches. Ein solcher Rücksetzprozess ist aber nur dann effizient und sicher möglich, wenn die von der zurückzusetzenden Transaktion durchgeführten Änderungen noch nicht von anderen Transaktionen verwertet wurden. Ansonsten müssten nämlich die betroffenen
592
9 Transaktionsverarbeitung und Fehlertoleranz
Transaktionen ebenfalls zurückgesetzt werden. Neben dem schon unschönen Prozess des damit verbundenen so genannten fortgepflanzten Rollbacks (Domino-Effekt, cascading rollback) könnte auch das Prinzip der Dauerhaftigkeit verletzt werden. Das ist dann der Fall, wenn eine vom Rücksetzprozess betroffene Transaktion bereits abgeschlossen ist. Sie darf dann nach dem ACID-Kriterium nicht mehr zurückgesetzt werden, da ihre Arbeiten bereits dauerhaft sind. Andererseits muss sie aber zurückgesetzt werden, da sie unzulässige Daten gelesen hat. Um diesen Widerspruch aufzulösen, verbieten viele Synchronisationsverfahren den Zugriff auf geänderte Objekte, bis die ändernde Transaktion abgeschlossen ist. Natürlich schränken solche Regeln die Durchlässigkeit eines Synchronisationsverfahrens ein.
9.1.4
Literatur
Transaktionskonzepte werden in unzähligen Artikeln und einigen Büchern eingeführt. Als besonders markante frühe Referenzen seien [BeSW79], [EGLT76], [GLPT76], [Gray78], [Gray81], [HäRe83], [Kelt88] und [Schl78] genannt. Besonders verdient um die Transaktionsproblematik und die Synchronisation hat sich die IBM-Datenbankforschungsgruppe gemacht und hier insbesondere Jim Gray. So legten die u. a. in [GLPT76], [Gray78] und [Gray81] dokumentierten Arbeiten den Grundstein für fast alle später einmal implementierten Techniken. Einen hervorragenden Überblick über die Synchronisationsproblematik aus praxisorientierter Sicht gibt Schlageter ([Schl78]), während [BeSW79] dasselbe aus der Sicht der Synchronisationstheorie leistet. Das ACID-Kriterium wurde in [HäRe83] eingeführt. Die Entscheidbarkeit von Serialisierbarkeit wird in [Papa79] diskutiert. Dort wird auch diskutiert, welche Teilklassen von serialisierbaren Schedulen von welchen Verfahren erkannt werden können. Die Kriterien anhand derer die Qualität eines Schedulers beurteilt werden kann, werden in [Unla85] diskutiert. Auf einer sehr implementierungsnahen Ebene haben sich vor allem die IBM Research Labs und dort vor allem C. Mohan mit dem Transaktionsmanagement auseinander gesetzt. Es wurden eine Reihe von Artikeln veröffentlicht, von denen hier die folgenden stellvertretend genannt seien: [MHLP92], [MoNa94], [MoPi91], [RoMo89]. Zwischenzeitlich gibt es bereits einige Bücher, die sich intensiv auch oder sogar ausschließlich dem Transaktionsmanagement und der Synchronisation(stheorie) widmen. Zur ersten Gruppe gehören die Bücher von Theo Härder und Erhard Rahm ([HäRa01]) sowie von Gunter Saake, Andreas Heuer und Kai Uwe Sattler ([SaHS12]). Die meisten Bücher der zweiten Kategorie sind eher formal ausgerichtet ([BeHG88], [Kelt85], [LMWF93], [Papa86] und [VoGr93]). Das Buch von Weikum ([Weik88]) widmet sich neben einer Einführung in das Transaktionsmanagement vornehmlich einem Mehrschichtentransaktion genannten Ansatz zur Erhöhung der Parallelität in Transaktionssystemen. Das Standardwerk zu dieser Thematik stammt von Gray und Reuter ([GrRe93]). Es gibt nicht nur einen umfangreichen Überblick, sondern kann als Handbuch eines jeden Datenbankadministrators für das Transaktionsmanagement angesehen werden. Sehr praxisorientiert ist auch das Buch von Philip Bernstein und Eric Newcomer ([BeNe97]), das zudem auch deutlich kompakter als das von Gray und Reuter ist. Als moderne Konkurrenz zum Buch von Gray und Reuter kann das Buch von Vossen und Weikum [VoWei01] angesehen werden, welches ebenfalls einen sehr ausführlichen und aktuellen Einblick in das Transaktionsmanagement gibt.
9.2 Synchronisationsverfahren
9.2
Synchronisationsverfahren
9.2.1
Klassifikation
593
Im letzten Kapitel waren Kriterien diskutiert worden, die erfüllt sein müssen, damit eine serialisierbare Schedule entsteht. In diesem Kapitel sollen konkrete Verfahren und Techniken zur Gewährleistung der operationalen Integrität der DB vorgestellt werden. Wie bereits erwähnt fällt dem Synchronisationsverfahren dabei die Aufgabe zu, eine beliebige Folge von eingehenden Operationsaufforderungen so anzuordnen, dass die Serialisierbarkeit gewährleistet ist. Im Prinzip lassen sich dabei zwei Vorgehensweisen denken: 1. Optimistische Vorgehensweise Die Synchronisationskomponente beobachtet den ankommenden Strom von Operationsaufforderungen und greift erst dann ein, wenn die Serialisierbarkeit vermutlich bereits verletzt wurde. Da jetzt das Kind bereits in den Brunnen gefallen ist, kann die Konsistenz der DB nur noch dadurch gewährleistet werden, dass eine problemverursachende Transaktion zurückgesetzt wird. Solche Verfahren werden verifizierende bzw. optimistische Verfahren genannt. Optimistisch deshalb, weil diese Verfahren unterstellen, dass ein Konflikt nur selten auftritt, weshalb das Rücksetzen als Mittel zur Synchronisation wegen seines seltenen Auftretens akzeptabel ist. 2. Pessimistische Vorgehensweise Die Synchronisationskomponente greift immer dann in den Strom von ankommenden Operationsaufforderungen ein, wenn aus ihrer Sicht eine Konsistenzverletzung vorliegen oder eintreten könnte. Solche Verfahren arbeiten präventiv und heißen deshalb auch präventive Verfahren. Deren bekanntester Vertreter ist die Klasse der Sperrverfahren. Wie der Name schon sagt, ist bei diesen Verfahren das Mittel zur Synchronisation die Sperre. Objekte, die von einer Transaktion bearbeitet werden, werden mit einer Sperre versehen. Die Sperren sind so ausgelegt, dass keine andere Transaktion eine Operation auf dem Objekt ausführen darf, solange diese Operation in Konflikt zu der bereits erlaubten Operation steht. Stattdessen wird die anfordernde Transaktion in einen Wartezustand versetzt, bis die arbeitende Transaktion T beendet ist, womit ein Aufheben der von T gehaltenen Sperre verbunden ist. Die Philosophie, die den präventiven Verfahren zu Grunde liegt, geht davon aus, dass Konflikte zwischen Transaktionen zumindest so häufig sind, dass sich der grundsätzlich anfallende „Vorsorgeaufwand“ zur Konfliktvermeidung auszahlt. Wegen dieser in Bezug auf Konflikthäufigkeiten eher pessimistischen Annahme werden diese Verfahren auch pessimistische Verfahren genannt. Zur letzten Kategorie gehören auch die Zeitstempelverfahren. Sie sichern die Serialisierbarkeit dadurch, dass der Zugriff auf Objekte im Konfliktfall in der Reihenfolge des Startzeitpunktes der Transaktionen erfolgt. Solche Verfahren haben vor allem bei verteilten DBS gewisse Vorteile, weshalb sie auch überwiegend in diesem Zusammenhang untersucht werden. Es sei noch angemerkt, dass optimistische Verfahren als einzige Klasse von Verfahren das Rücksetzen von Transaktionen als ausschließliches Mittel zur Synchronisation einsetzen. Andererseits gibt es aber keine relevante Klasse von Verfahren, die nicht auch, zumindest gelegentlich, auf das Mittel des Rücksetzens von Transaktionen zurückgreifen muss.
594
9 Transaktionsverarbeitung und Fehlertoleranz
In zentralen DBMS werden bislang überwiegend Sperrverfahren eingesetzt. Deshalb werden wir auf diese Verfahren etwas ausführlicher eingehen, während Zeitstempelverfahren und optimistische Verfahren nur kurz behandelt werden.
9.2.2
Sperrverfahren
Sperrverfahren gehören zur Klasse der präventiven Verfahren. Diese Einordnung ist deshalb gerechtfertigt, da bei dieser Klasse von Verfahren jede Transaktion den Teil der DB vorbeugend für sich sperrt, auf dem sie arbeitet. Durch eine solche Sperre wird verhindert, dass zueinander in Konflikt stehende Operationen parallel auf denselben Objekten ausgeführt werden. Ein auf Sperren basierender Scheduler muss also bei jeder eingehenden Operationsaufforderung klären, ob die zugehörige Transaktion eine entsprechende Sperre auf dem Objekt besitzt. Falls nicht, muss sie angefordert werden. Damit der Scheduler nun korrekt arbeiten kann, müssen folgende Fragen beantwortet werden: 1. Welche Arten von Sperren gibt es und welches sind die sperrbaren Einheiten? 2. Wann werden Sperren vergeben und wie lange müssen sie bestehen bleiben? 3. Was passiert, falls ein Objekt bereits gesperrt ist? Die erste Frage ist die Frage nach den Sperrmodi sowie den Sperrobjekten bzw. Sperrgranulaten. Die zweite Frage wird mit Hilfe von Sperrprotokollen geregelt, während im letzten Punkt die Frage einer geeigneten Kollisionsstrategie angesprochen wird. Auf diese Punkte soll im Folgenden noch etwas genauer eingegangen werden. 9.2.2.1
Sperrmodi und Sperrgranulate
Grundsätzlich kann die operationale Integrität einer DB nur durch zueinander in Konflikt stehende Operationen gefährdet werden. Die Philosophie von Sperrverfahren besteht nun darin, die parallele Ausführung solcher Operationen zu verhindern. Aus der Definition von Konflikt ergibt sich, dass Leseoperationen miteinander kompatibel sind, während eine Schreiboperation mit keiner anderen Operation kompatibel ist. Daraus kann geschlossen werden, dass mindestens zwei Sperrmodi gebraucht werden, die Lese- und die Schreibsperre. Definition 9.10: Lese-/Schreibsperre • Die Lesesperre oder gemeinsame Sperre (shared lock, abgekürzt S-Sperre) erlaubt dem „Sperrbesitzer“ das Lesen des gesperrten Objektes. Andere Transaktionen dürfen ebenfalls Lesesperren setzen, wohingegen das Setzen einer Schreibsperre verboten ist. • Die Schreibsperre oder exklusive Sperre (exclusive lock, abgekürzt X-Sperre) erlaubt dem „Sperrbesitzer“ sowohl lesenden als auch schreibenden Zugriff auf das Objekt. Anderen Transaktionen ist jeglicher Zugriff auf das Objekt verwehrt.
Tabelle 9.1: Kompatibilität der Sperrmodi
S
X
S
✓
✕
X
✕
✕
9.2 Synchronisationsverfahren
595
Die Kompatibilität der beiden Sperrmodi ist noch einmal in Tabelle 9.1 zusammengefasst, wobei ✓ für kompatibel und ✕ für nicht kompatibel steht. Die Effizienz eines Sperrverfahrens hängt aber nicht nur von den angebotenen Sperrmodi ab, sondern auch von dem Sperrgranulat. Nehmen wir einmal an, dass Ute in unserem Reisebüro die Urlaubsreise eines Kunden buchen möchte. Der Kunde hat sich seine Reise, bestehend aus Flug, Hotel und Mietwagen, mit Hilfe eines Prospektes exakt zusammengestellt. Ute muss daher nur noch die entsprechenden Wünsche buchen, indem sie aus jeder der drei Tabellen Flug, Hotel und Auto den entsprechenden Datensatz ändert. Willy stellt andere Anforderungen. Er soll die Preise fast aller ausländischen Hotels leicht nach unten korrigieren, da der Euro auf den internationalen Devisenmärkten an Stärke gewonnen hat. Willy wird bei seiner Arbeit einen Großteil der Datensätze der Hotel-Tabelle ändern. Die beiden Beispiele machen deutlich, dass Transaktionen ganz unterschiedliche Datenanforderungen haben können. Ute benötigt drei Datensätze aus drei unterschiedlichen Tabellen. Es erscheint im Sinn einer hohen Parallelität durchaus angebracht, nur genau diese Datensätze zu sperren. Willy dagegen wird im Endeffekt nachher fast jeden Datensatz der Hotel-Tabelle gesperrt haben. Ein explizites Sperren jedes einzelnen Datensatzes würde hier sehr teuer werden. Sinnvoller erscheint da schon, gleich die ganze Tabelle explizit zu sperren und die vielen Einzelsperren damit zu vermeiden. Man mache sich klar, dass wir hier nicht über marginale Verbesserungen, sondern über massive Optimierungen sprechen. Enthält eine Tabelle z. B. 10.000 Zeilen, so würden im Fall von Willy einem Sperrvorgang knapp 10.000 Sperrvorgängen gegenüber stehen. Da die Sperren aus Effizienzgründen im Hauptspeicher verwaltet werden sollten, wird auch dieser stark belastet. Umgekehrt würden im Fall von Ute 3∗10.000 Datensätze gesperrt, wovon nur drei benötigt werden. Das ist aus der Sicht einer effizienten Parallelarbeit eine Katastrophe. Man stelle sich nur einmal vor, was passieren würde, wenn die vielen Reisebüros, die die Flüge der Lufthansa direkt buchen können, bei jeder Transaktion, die einen Lufthansa-Flug einschließt, die komplette Flug-Tabelle sperren würden. Flüge wären damit de facto nicht mehr buchbar. Als Resümee aus den Beispielen kann festgehalten werden, dass die Verwendung einer einzigen Sperrebene im Allgemeinen recht ungünstig ist. Vielmehr sollten die Transaktionen in der Lage sein, entsprechend ihrer Bedürfnisse auf unterschiedlichen Ebenen zu sperren. Dies bedeutet, dass eine Transaktion, die viele Sätze einer Tabelle ändern möchte, einfach die ganze Tabelle (die Datei) sperren können sollte; eine Transaktion, die nur auf einen einzelnen Satz zugreift, sollte genau diesen sperren können usw. Sind in dieser Weise Sperren auf unterschiedlichen Ebenen setzbar, so spricht man von einer Sperrhierarchie. Definition 9.11: Sperrhierarchie Eine Sperrhierarchie ist eine hierarchische Zerlegung der Daten einer DB im Sinn einer Enthaltensseinrelation. Eine höhere Hierarchiestufe sollte immer die tieferen Hierarchiestufen enthalten. Eine häufig genutzte Sperrhierarchie ist die folgende: • DB • Area5 (oder Segment) 5 Tabellen einer DB lassen sich aus Gründen einer internen Strukturierung und der Verbesserung des Zugriffes häufig noch zu so genannten Areas bzw. Segmenten zusammenfassen. Da die Interna eines DBMS in diesem Buch nicht diskutiert werden, soll dieser Aspekt hier auch nicht weiter diskutiert werden.
596
9 Transaktionsverarbeitung und Fehlertoleranz
• Tabelle (oder Datei) • Zeile (oder Satz)6 Leider haben Sperrhierarchien einen gewissen negativen Nebeneffekt, der sich aus der Gegenläufigkeit von möglicher Parallelität und notwendigem Sperraufwand ergibt. Je feiner die Sperreinheiten sind, • desto mehr Parallelität ist zwischen den Transaktionen möglich, • desto größer ist aber auch der Verwaltungsaufwand für die Sperren. Damit hängen die Vorteile einer Sperrhierarchie erheblich von der Kenntnis der Anwendungsumgebung ab (z. B. Unterscheidung zwischen wenig genutzten und viel genutzten Daten (so genannten Hot spots), Zeiten geringer oder intensiver Nutzung des DBS). Zudem ist die Kenntnis von Transaktionsprofilen (z. B. auf welche Daten wird zugegriffen) unumgänglich. Zur effizienten Realisierung von Sperrhierarchien ist zudem ein weiterer Punkt von entscheidender Bedeutung: Wie kann ich entscheiden, ob auf einer gegebenen Ebene eine Sperre vergeben werden darf oder nicht? Da im Fall der Sperrhierarchie Sperrgranulate in anderen enthalten sein können, muss nicht nur überprüft werden, ob das zu sperrende Objekt x bereits für eine andere Transaktion gesperrt ist, sondern auch, ob ein (Objekt eines) Granulat(s) auf feinerer oder gröberer Ebene gesperrt ist. Soll also eine Tabelle gesperrt werden, muss überprüft werden, ob bereits die gesamte DB, das Segment, das die Tabelle enthält (beides gröbere Granulate) oder bereits ein Datensatz der Tabelle (feineres Granulat) inkompatibel gesperrt sind. Wegen des u. U. hohen Aufwands solcher Enthaltensein-Tests wird üblicherweise ein anderer Weg beschritten: Es werden weitere Sperren eingeführt, so genannte Warnsperren (intention locks). Definition 9.12: Warnsperren Warnsperren sind Sperren, die auf allen dem aktuellen Sperrgranulat übergeordneten Ebenen gesetzt werden. Dort drücken sie die Absicht aus, auf tieferer Ebene ein Objekt zu sperren. Mit Warnsperren ist es möglich, auf jeder Ebene zu sehen, ob irgendwo auf einer tieferen Ebene ein Objekt inkompatibel gesperrt ist. Ist dem so, darf das Objekt auf der höheren Ebene nicht gesperrt werden. Da bei Warnsperren auf unterschiedlichen Granularitätsebenen gesperrt wird, hat sich in der englischsprachigen Literatur der Begriff multiple-granularity locking (MGL) durchgesetzt. Beispiel 9.5: Warnsperren Möchte Ute ein bestimmtes Hotel für ihren Kunden reservieren, so werden zunächst Warnsperren auf Datenbankebene, Areaebene und Hoteltabellenebene gesetzt, bevor der Datensatz des entsprechenden Hotels explizit gesperrt wird. Möchte Willy die Preise der meisten ausländischen Hotels herabsetzen, so setzt seine Transaktion eine „echte“ Sperre auf der Ebene der Hotel-Tabelle und Warnsperren auf 6 Denkbar wäre auch noch das Sperrgranulat Spalte bzw. Attribut. Dieses Granulat wird aber im Allgemeinen als zu fein angesehen, weshalb es auch nicht weiter berücksichtigt wird.
9.2 Synchronisationsverfahren
597
der Datenbank- und Areaebene. Laufen beide Transaktionen parallel, so würde entweder die Transaktion von Willy beim Versuch, die Hotel-Tabelle explizit zu sperren, auf die Warnsperre der Transaktion von Ute stoßen oder, umgekehrt, die Transaktion von Ute würde beim Versuch, auf der Ebene der Hotel-Tabelle eine Warnsperre zu setzen, auf die explizite Sperre der Transaktion von Willy stoßen. In beiden Fällen wird der potenzielle Konflikt aufgrund der Warnsperren frühzeitig bemerkt, so dass eine Konfliktbereinigung (siehe Kapitel 9.2.2.3) durchgeführt werden kann. Achtung 9.2: Reihenfolge beim Setzen von Warnsperren Um Konflikten beim Setzen von Sperren aus dem Weg zu gehen, müssen Sperren immer von oben nach unten (von der DB zum Datensatz) angefordert werden. Ähnlich wie bei den „echten Sperren“ gibt es auch bei den Warnsperren noch eine feinere Unterteilung. Definition 9.13: Sperrmodi von Warnsperren Bei den Warnsperren unterscheidet man folgende Modi: IS: Erklärt die Absicht der Transaktion, auf einer tiefer liegenden Ebene mindestens ein Objekt zu lesen. Daher wird das Recht erworben, dort IS- und S-Sperren zu setzen. IX: Erklärt die Absicht der Transaktion, auf einer tiefer liegenden Ebene mindestens ein Objekt zu verändern bzw. zu schreiben. Daher wird das Recht erworben, dort IS-, S-, IX-, X- und SIX-Sperren zu setzen. SIX: Wirkt auf der gegebenen Ebene wie eine S-Sperre, indem alle Objekte auf dieser Ebene lesegesperrt werden. Zusätzlich erklärt die Transaktion die Absicht, auf einer tiefer liegenden Ebene mindestens ein Objekt zu schreiben. Für tiefer liegende Ebenen wird das Recht erworben, IX-, X- und SIX-Sperren zu setzen. Da bereits diese Ebene komplett S-gesperrt ist, sind alle tieferen Ebenen implizit mit gesperrt, weshalb das Setzen von IS- und S-Sperren auf tieferen Ebenen nicht mehr notwendig ist. Die SIX-Sperre ist beispielsweise dann sinnvoll, wenn sich Ute zunächst eine Vielzahl von Hotels ansehen (lesen) möchte, bevor sie dann in einem Hotel ein Zimmer reserviert. Tabelle 9.2 listet noch einmal auf, welche Sperren sich mit welcher anderen vertragen und deshalb gemeinsam auf einem Objekt bestehen dürfen.
IS
IX
S
SIX
X
IS
✓
✓
✓
✓
✕
IX
✓
✓
✕
✕
✕
S
✓
✕
✓
✕
✕
SIX
✓
✕
✕
✕
✕
X
✕
✕
✕
✕
✕
Tabelle 9.2: Kompatibilitätsmatrix der Warnsperrmodi
598 9.2.2.2
9 Transaktionsverarbeitung und Fehlertoleranz Sperrprotokolle
Der vorangegangene Abschnitt hat gezeigt, dass Sperren eine weit verbreitete Möglichkeit der Isolation von Transaktionen voneinander sind. Will man mit Sperren arbeiten, muss es Befehle für deren Anforderung und Freigabe geben. Wir setzen für die weitere Diskussion voraus, dass die beiden folgenden Befehle zur Verfügung stehen. • LOCK-Befehl (O): Setzt die geforderte Sperre für das Objekt O. • UNLOCK-Befehl (O): Hebt die Sperre auf dem Objekt O wieder auf. Wie das folgende Beispiel zeigt, ist es nicht ausreichend, wenn Transaktionen Sperren lediglich für die Dauer ihrer Bearbeitung auf Objekte setzen. Beispiel 9.6: Einsatz von Sperren7 Kommen wir noch einmal auf Situation 9.3 aus Kapitel 9.1.1 zurück. Ute erhöht in diesem Beispiel die Mietwagenpreise allgemein um 20,– $, während Willy sie in Kalifornien um zehn Prozent anhebt. Folgender Transaktionsablauf ergibt sich: Ute
Willy
Zeitachse
... LOCK (Auto(LA)) READ Auto(LA).preis (= 100,–) Auto(LA).preis := Auto(LA).preis ∗ 1.1 WRITE Auto(LA).preis (= 110,–) UNLOCK (Auto(LA)) ... LOCK (Auto(SF)) READ Auto(SF).preis (= 100,–) Auto(SF).preis := Auto(SF).preis + 20 WRITE Auto(SF).preis (= 120,–) UNLOCK (Auto(SF)) LOCK (Auto(LA)) READ Auto(LA).preis (= 110,–) Auto(LA).preis := Auto(LA).preis + 20 WRITE Auto(LA).preis (= 130,–) UNLOCK (Auto(LA)) ... LOCK (Auto(SF)) READ Auto(SF).preis (= 120,–) Auto(SF).preis := Auto(SF).preis ∗ 1.1 WRITE Auto(SF).preis (= 132,–) UNLOCK (Auto(SF)) ...
↓
7 Der Sperrmodus ergibt sich immer direkt aus der Semantik der Operationen, die auf den Objekten ausgeführt werden sollen. Er wird deshalb nicht explizit angegeben.
9.2 Synchronisationsverfahren
599
Man sieht, dass das Problem von Situation 9.3 aus Kapitel 9.1.1 nach wie vor ungelöst ist. Ute hat zwar die Objekte, die sie bearbeiten möchte, jeweils gesperrt, bekommt aber trotzdem für ein Auto einen falschen Preis geliefert. Das Beispiel macht deutlich, dass das Setzen und Freigeben von Sperren gewissen Regeln unterworfen werden muss, um Serialisierbarkeit zu erreichen. Das Einhalten dieser Regeln wird durch Protokolle sichergestellt. Das bekannteste Protokoll ist das so genannte Zweiphasen-Sperrprotokoll (two-phase locking)8. Definition 9.14: Zweiphasen-Sperrprotokoll Das Zweiphasen-Sperrprotokoll wird beachtet, wenn eine Transaktion wohlgeformt und zweiphasig ist. Eine Transaktion ist wohlgeformt (well formed), falls sie für jedes Objekt, das sie bearbeiten möchte, vorher eine entsprechende Sperre anfordert. Sie ist zweiphasig (two phase), falls sie kein Objekt mehr sperrt, nachdem sie zum ersten Mal eine Sperre auf einem Objekt freigegeben hat. Eine zweiphasige Transaktion besteht demnach aus einer so genannten Wachstumsphase, während der sie alle Sperren anfordert, und einer daran anschließenden Schrumpfungsphase, während der sie alle Sperren wieder freigibt, aber keine Sperren mehr anfordern darf (siehe Abbildung 9.3, Variante 1). Wenn eine Transaktion endet, werden alle noch gehaltenen Sperren automatisch freigegeben. gesetzte Sperren Wachstumsphase
gesetzte Sperren
Wachstumsphase Schrumpfungsphase
BOT Variante 1: Einfache Zweiphasigkeit
EOT Zeit
BOT Variante 3: Preclaiming
EOT Zeit
gesetzte Sperren
EOT Zeit
Schrumpfungsphase
BOT Variante 2: Strikte Zweiphasigkeit
Schrumpfungsphase
Wachstumsphase
Wachstumsphase
gesetzte Sperren
Schrumpfungsphase
EOT Zeit BOT Variante 4: Preclaiming und strikte Zweiphasigkeit
Abb. 9.3: Verschiedene Varianten des Zweiphasen-Sperrprotokolls 8 Dieses Protokoll sollte nicht mit dem Zweiphasen-Freigabeprotokoll (two-phase commit) verwechselt werden, welches in verteilten DBMS Anwendung findet.
600
9 Transaktionsverarbeitung und Fehlertoleranz
Um zu sehen, dass jedes System zweiphasiger Transaktionen serialisierbar ist, muss man zeigen, dass bei der Anwendung dieses Protokolls kein Zyklus im Abhängigkeitsgraphen G auftreten kann. Gegeben sei ein beliebiger Zyklus im Abhängigkeitsgraphen, der dann immer wie folgt aussehen muss: T1 → T2 → · · · → Tp → T1 Statt der Operationen soll aus Gründen der Einfachheit nur die Folge der LOCK-UNLOCKBefehle betrachtet werden. Tx → Ty bedeutet also, dass Tx mindestens ein Objekt in einem inkompatiblen Modus gesperrt hat, welches (später) auch von Ty genutzt wird. Der obige Zyklus sagt daher aus, dass ein LOCK von T2 auf ein UNLOCK von T1 folgte, ein LOCK von T3 auf ein UNLOCK von T2 usw. Schließlich ist ein LOCK von T1 auf ein UNLOCK von Tp gefolgt. Das bedeutet aber, dass ein LOCK von T1 auf ein UNLOCK von T1 folgt. Dies ist ein Widerspruch zur Annahme der Zweiphasigkeit. Das Zweiphasen-Sperrprotokoll in der obigen Version setzt eine idealisierte Umgebung voraus, da es Fehlerfreiheit in der Form unterstellt, dass Transaktionen weder vom Benutzer noch aufgrund von Systemfehlern während der Schrumpfungsphase zurückgesetzt werden dürfen. Wäre dem nicht so, könnte bei der bisher unterstellten simplen Schrumpfungsphase ein fortgepflanztes Rollback auftreten. Definition 9.15: Fortgepflanztes Rollback Von einem fortgepflanzten Rollback spricht man immer dann, wenn der Abbruch einer Transaktion das Zurücksetzen von anderen, von dieser Transaktion abhängigen, möglicherweise bereits beendeten Transaktionen zur Folge hat (Abbildung 9.4). Ein fortgepflanztes Rollback kann immer dann auftreten, falls eine Transaktion Ta von ihr geänderte Daten bereits vor ihrem Ende freigibt. Werden diese Daten jetzt von einer anderen Transaktion Tb genutzt, so muss auch diese zurückgesetzt werden, falls Ta , aus welchen Gründen auch immer, scheitern sollte. Diese Abhängigkeit wird dadurch hervorgerufen, dass Tb ein von Ta geändertes Datum gelesen hat. Da die Änderung von Ta jedoch zurückgesetzt wurde, hat Tb ein ungültiges Datum gelesen. Diese Situation kann sich nun fortpflanzen, indem eine Transaktion Tc zurückgesetzt werden muss, weil sie Änderungen der Transaktion Tb gelesen hat usw.
Tc Tb
Ta
Abb. 9.4: Fortgepflanztes Rollback
9.2 Synchronisationsverfahren
601
Das Problem mit fortgepflanztem Rollback ist neben dem Verlust von bereits durchgeführter Arbeit (Rücksetzen von Transaktionen) insbesondere die Tatsache, dass möglicherweise bereits abgeschlossene Transaktionen zurückgesetzt werden müssen. Das steht im Widerspruch zum D-Kriterium der ACID-Eigenschaft, welches ja gerade garantiert, dass einmal abgeschlossene Transaktionen jeden nachfolgenden Fehlerfall überleben. Um diesem Problem aus dem Weg zu gehen, wurde das strikte Zweiphasen-Sperrprotokoll entwickelt. Bei dieser Variante werden alle von einer Transaktion gesperrten Objekte auf einmal freigegeben und zwar mit Hilfe einer aus der Sicht des DBMS atomaren Operation am Ende der Transaktion (siehe Abbildung 9.3, Variante 2). Eine weitere Variante des Zweiphasensperrprotokolls ist das Preclaiming (siehe Abbildung 9.3, Variante 3). Definition 9.16: Preclaiming Preclaiming bedeutet, dass alle Objekte, die eine Transaktion möglicherweise verwenden wird, zu Beginn der Transaktion auf einem Schlag gesperrt werden. Können nicht alle Objekte im gewünschten Modus gesperrt werden, beispielsweise, weil einige Objekte bereits inkompatibel von anderen Transaktionen gesperrt wurden, wird die anfordernde Transaktion in einen Wartezustand versetzt. Nach Ablauf eines Zeitintervalls versucht sie dann erneut, ihre Objekte bzw. Sperren zu erlangen. Preclaiming sorgt dafür, dass einer Transaktion, sofern sie zur Verarbeitung kommt, alle von ihr benötigten Daten zur Verfügung stehen. Damit ist ein Rücksetzen aufgrund eines Sperrkonfliktes in Form eines Deadlocks9 (siehe nächster Abschnitt) ausgeschlossen. Ein Deadlock ist eine unschöne Erscheinung, weshalb Preclaiming zunächst einmal wie eine sehr elegante Lösung aussieht. Leider beinhaltet es aber auch Probleme. Das Gravierendste ist, dass bereits zu Beginn einer Transaktion alle benötigten Datensätze bekannt sein müssen. Das ist im Allgemeinen allerdings nicht der Fall, insbesondere dann nicht, wenn der Transaktionsablauf datenabhängig ist, d. h., wenn es von Zwischenresultaten abhängt, auf welche Objekte im Weiteren zugegriffen wird. Um trotzdem arbeiten zu können, muss dann sicherheitshalber auf einer sehr groben Ebene gesperrt werden10 . Das bedeutet natürlich, dass viel zu viele Objekte gesperrt werden, worunter die potenzielle Parallelität im System erheblich leiden kann. Die Parallelität leidet aber auch, weil Objekte schon sehr früh, nämlich zu Beginn der Transaktion gesperrt werden und nicht erst, wenn sie auch wirklich benötigt werden. Schließlich bedingt die grobgranulare Sperrweise natürlich auch, dass die Wahrscheinlichkeit, dass aufgrund der hohen Anzahl an zu sperrenden Objekten nicht alle beim Transaktionsbeginn schon zur Verfügung stehen, erheblich steigt, weshalb wiederum die durchschnittliche Verweildauer einer Transaktion im System deutlich steigen kann. Wegen der mit Preclaiming verbundenen Probleme wird es im Allgemeinen nicht eingesetzt. In speziellen Situationen, etwa wenn das Deadlockproblem besonders schwierig ist oder wenn der Parallelitätsverlust durch Preclaiming nicht ins Gewicht fällt, kann der Einsatz aber durchaus sinnvoll sein. 9 Ein Deadlock liegt immer dann vor, wenn Transaktionen wechselseitig darauf warten, dass die jeweils andere Transaktion von ihr gesperrte Objekte wieder freigibt. 10 Bei Onlinetransaktionen muss man im Prinzip die gesamte DB sperren, da man ja nicht weiß, welche Objekte durch die Transaktion angepackt werden.
602
9 Transaktionsverarbeitung und Fehlertoleranz
Die letzte Variante, strikte Zweiphasigkeit mit Preclaiming (siehe Abbildung 9.3, Variante 4), ist nur aus Gründen der Vollständigkeit noch aufgenommen worden. Zwar vermeidet diese Variante alle im Zusammenhang mit Sperrprotokollen bekannten Probleme, stellt aber auch eine extrem pessimistische Sicht dar, die die mögliche Parallelität im System so drastisch einschränkt, dass ihr Einsatz nur in ganz besonderen Spezialfällen befürwortet werden kann. Das strikte Zweiphasensperrprotokoll bietet die höchste Sicherheitsstufe (Konsistenzstufe 3), was heißt, dass die ersten drei der in Kapitel 9.1.1 beschriebenen Fehlersituationen abgefangen werden. Wie bereits erwähnt, muss das Phantomproblem bei physischen Sperren auf anderem Weg gelöst werden. In der Praxis hat sich aber aus Gründen einer erhöhten Parallelität eine etwas abgewandelte Variante des strikten Zweiphasensperrprotokolls durchgesetzt. Bei ihr gilt die Zweiphasigkeit und das Halten der Sperren bis zum Transaktionsende nur für Schreibsperren. Lesesperren dagegen werden nur solange gehalten, wie mit dem Objekt gearbeitet wird. Außerdem unterliegen sie nicht der Zweiphasigkeit. Solche Sperrprotokolle garantieren zwar die Konsistenz der DB, können aber eine inkonsistente Sicht auf die Daten (siehe Situation 9.2) nicht verhindern. In der von Jim Gray eingeführten Konsistenzstufenskala11 erfüllen sie Konsistenzstufe 2. Konsistenzstufe 0 und 1 spielen keine wesentliche Rolle und sollen hier nicht erläutert werden. 9.2.2.3
Konfliktbehandlung bei der Sperrvergabe
Da mit Hilfe von Sperren gewährleistet werden soll, dass verschiedene Transaktionen nicht gleichzeitig in einer unerwünschten Art und Weise auf denselben Objekten arbeiten können, muss festgelegt werden, was passiert, falls eine Transaktion T1 ein Objekt sperren möchte, das bereits von einer anderen Transaktion T2 inkompatibel gesperrt wurde. Die Lösung ist recht einfach: T1 wird in einen Wartezustand versetzt, d. h., T1 wartet bis T2 die von ihr gesperrten Objekte freigibt. Allerdings muss darauf geachtet werden, dass im Fall eines Wartezustandes von Transaktionen die Sperren „fair“ weitergereicht werden. Damit ist gemeint, dass verhindert werden muss, dass eine Transaktion dauerhaft auf eine Sperre wartet, da sie immer wieder von anderen Transaktionen „überholt“ wird. Besonders kritisch ist dieses so genannte Starvationproblem – in allgemeinerer Form auch Livelock genannt – bei Daten, auf die häufig zugegriffen wird. Da Lesesperren miteinander kompatibel sind, kann es passieren, dass ein sehr begehrtes Objekt (Hot spot), auf dem bereits eine Lesesperre liegt, immer wieder von anderen Transaktionen mit weiteren Lesesperren versehen wird, so dass die angeforderte Schreibsperre einer Änderungstransaktion nie zum Tragen kommt. Neben dem Starvation-Problem kann es aber insbesondere auch noch zu so genannten Deadlocks kommen, wie das Beispiel 9.7 zeigt. Beispiel 9.7: Deadlock Grundlage dieses Beispiels ist noch einmal die Situation von Beispiel 9.1. Ute möchte für einen Kunden Wagen in Los Angeles und San Francisco buchen, wohingegen Willy alle Mietwagenpreise in Kalifornien anhebt. Nehmen wir einmal an, dass die Transaktionen von Ute und Willy genau so ablaufen, wie in Beispiel 9.1 dargestellt, mit dem einen Unterschied, dass Sperren jetzt, entsprechend dem strikten Zweiphasen-Sperrprotokoll, bis zum Ende der jeweiligen Transaktion gehalten werden. Willy ändert also zunächst eini11 siehe
z. B. [Gray76].
9.2 Synchronisationsverfahren
603
ge Mietwagenpreise, u. a. auch den für Mietwagen in Los Angeles. Jetzt möchte Ute die Wagen für ihren Kunden buchen. Die Buchung eines Mietwagens in San Francisco läuft wie gewünscht, d. h. Ute erhält die notwendige exklusive Sperre auf den Mietwagen und kann die Buchung durchführen. Die Buchung des Wagens in Los Angeles stößt aber zunächst auf Schwierigkeiten: Willy hat den Mietwagen im Rahmen seiner Preisanhebung bereits exklusiv gesperrt. Die Transaktion von Ute wird deshalb in den Wartezustand versetzt. Willy hebt weiter Preise an, bis zu dem Zeitpunkt, da er den Mietwagenpreis in San Francisco erhöhen will. Dieser Datensatz ist von der Transaktion von Ute noch exklusiv gesperrt. Deshalb wird auch die Transaktion von Willy in den Wartezustand versetzt. Das Resultat ist, dass die Transaktion von Ute auf das Ende der Transaktion von Willy wartet und umgekehrt. Das obige Beispiel beschreibt eine Situation, die gemeinhin als Deadlock oder Verklemmung bezeichnet wird. Definition 9.17: Deadlock Ein Deadlock ist eine Situation, bei der Prozesse wechselseitig darauf warten, dass der jeweils andere Prozess von ihnen benötigte Betriebsmittel freigibt. Deadlocks können in allen Systemen auftreten, in denen allgemein zugängliche, exklusiv zu nutzende Betriebsmittel an parallel laufende, konkurrierende Prozesse vergeben werden und bei denen die folgenden vier Bedingungen alle erfüllt sind: 1. Bedingung des gegenseitigen Ausschlusses: Prozesse fordern und erhalten exklusive Kontrolle über von ihnen benötigte Betriebsmittel. 2. Bedingung der Nichtentziehbarkeit: Ein einmal zugeteiltes Betriebsmittel muss explizit durch den das Betriebsmittel haltenden Prozess freigegeben werden. Es kann also nicht zwangsweise entzogen werden. 3. Warte-und-Halte-Fest-Bedingung: Wenn ein beantragtes Betriebsmittel blockiert ist, also nicht zugewiesen werden kann, wird der beantragende Prozess in den Zustand „blockiert“ überführt, wobei bereits zugewiesene Betriebsmittel weiterhin festgehalten werden. 4. Bedingung der Mehrfachanforderung: Prozesse, die bereits ein Betriebsmittel besitzen, können die Zuteilung weiterer Betriebsmittel beantragen. Genau diese Voraussetzungen sind in DBS gegeben, die über Sperren synchronisieren. Zur Bewältigung der Deadlock-Problematik wurden eine Vielzahl von Verfahren entwickelt, die sich aufgrund der Vorgehensweise bei der Behandlung von Deadlocks den folgenden Gruppen zuordnen lassen: 1. 2. 3. 4.
Verhinderung (prevention) Vermeidung (avoidance) Auflösung durch Zeitbeschränkung (time-out) Erkennung und Auflösung (detection and resolution)
604
9 Transaktionsverarbeitung und Fehlertoleranz
Diese Klassifizierung stammt aus dem Bereich der Betriebssysteme, wo die gleichen Probleme zu behandeln sind. Jedoch gelten hier andere Voraussetzungen, so dass die dort vorgeschlagenen Lösungen nur sehr bedingt auf den Datenbankbereich übertragbar sind. Preclaiming ist eine Strategie zur Deadlock-Verhinderung. Die Vor- und Nachteile dieser Technik wurden bereits diskutiert. Verfahren zur Deadlock-Vermeidung erlauben nur dann die Zuteilung eines Betriebsmittels an einen Prozess, wenn sichergestellt ist, dass mindestens noch ein Weg vorhanden ist, der allen im System befindlichen Prozessen ein normales Ende ermöglicht. Wegen des mit diesen Verfahren verbundenen, sehr komplexen Analyseprozesses spielt diese Gruppe keine Rolle in der Datenbankwelt. Beim Time-out wird einem Prozess der Zugriff auf ein Betriebsmittel nach Ablauf eines Zeitintervalls entzogen und der gesamte Prozess abgebrochen. Da im Fall einer DeadlockSituation zwangsläufig irgendwann eine Transaktion das Zeitintervall überschreitet, ist eine Deadlock-Beseitigung auf jeden Fall garantiert. Der Time-out-Mechanismus hat sehr viele Vorteile, vor allem einen geringen Verwaltungsoverhead. Er weist allerdings erhebliche Schwächen bei wechselnder Systemauslastung auf. Zudem wird i. d. R. immer die teuerste, d. h. die bereits am längsten laufende Transaktion zurückgesetzt, da bei ihr das Zeitintervall am ehesten abgelaufen ist. Bei der Deadlock-Erkennung wird entweder periodisch oder bei jedem Zugriff auf ein Objekt überprüft, ob ein Deadlock aufgetreten ist. Hierzu werden i. d. R. Verfahren aus der Graphentheorie angewendet, die dem bereits eingeführten Abhängigkeitsgraphen sehr ähneln. Statt durch Operationen verursachte Abhängigkeiten zu modellieren, wird festgehalten, welche Transaktionen auf welche anderen warten. Der entstehende Graph wird dementsprechend auch Wartegraph genannt. Auch hier liegt ein Problem, also ein Deadlock vor, falls der Graph einen Zyklus enthält. Aufgelöst wird ein Deadlock durch das Abbrechen von mindestens einer der beteiligten Transaktionen. Da in diesem Fall alle an einem Deadlock beteiligten Transaktionen bekannt sind, ist es möglich, die zurückzusetzende(n) Transaktion(en) aufgrund vorgegebener Kriterien auszuwählen, z. B. die Transaktion, die bisher die wenigsten Ressourcen verbraucht hat. Als nachteilig wirkt sich der mit der Deadlock-Erkennung verbundene hohe Aufwand aus. Deadlock-Erkennung und vor allem Time-out sind gängige Verfahren in DBMS. 9.2.2.4
Der Sperrmanager
Die Instanz des DBMS, die für die Synchronisation der Transaktionen verantwortlich ist, wird üblicherweise Sperrmanager genannt. Die Aufgaben des Sperrmanagers können folgendermaßen charakterisiert werden: 1. Setzen und Freigabe von Sperren unter Beachtung des Zweiphasen-Sperrprotokolls. 2. Verhinderung von dauerhafter Blockade durch „faire“ Vergabe von Sperren an Transaktionen. 3. Verhinderung oder Entdeckung und Auflösung von Deadlocks.
9.2 Synchronisationsverfahren
605
Der Sperrmanager wird immer dann aktiviert, wenn ein Objekt gesperrt, eine bestehende Sperre verschärft oder eine Sperre aufgehoben werden soll12 . Bei einer Sperranforderung überprüft er, ob die Sperre vergeben werden kann. Falls nicht wird die aufrufende Transaktion in einen Wartezustand versetzt. Der Sperrmanager muss demzufolge Informationen darüber führen, welche Objekte für welche Transaktionen gesperrt sind und welche Transaktionen auf die Freigabe gesperrter Objekte warten. Informationen dieser Art werden in einer Sperrtabelle gehalten. Da auf eine solche Tabelle sehr häufig zugegriffen wird, sollte sie effizient und kompakt implementiert sein, damit sie möglichst vollständig im Hauptspeicher gehalten werden kann. üblicherweise werden Sperrtabellen mit Hilfe von Hashfunktionen oder über Indextabellen realisiert. Falls das eingesetzte Sperrprotokoll das Entstehen von Deadlocks zulässt, muss der Sperrmanager in periodischen Abständen Deadlock-Erkennung betreiben und gegebenenfalls das Abbrechen und Rücksetzen von Transaktionen initiieren. 9.2.2.5
Sperren über Prädikate
Bisher war immer implizit davon ausgegangen worden, dass Sperren nur auf real in der DB existierenden Objekten gesetzt werden können. Solche deshalb auch physische Sperren genannten Sperrtypen können das Phantomproblem nur über zusätzliche Maßnahmen lösen. Möchte Ute beispielsweise alle Hotels lesen, die in Florida angeboten werden, kann sie diese zwar bestimmen und sperren, das Hotel in Orlando, das Willy gerade neu einträgt, ist damit aber nicht erfasst13 . Probleme dieser Art lassen sich, zumindest auf den ersten Blick, sehr elegant durch Sperren über Prädikate (auch logische Sperren genannt) lösen. Bei logischen Sperren benennt die Transaktion nicht mehr jeden einzelnen Satz, den sie gesperrt haben möchte, sondern sie gibt ein Prädikat an, das die Eigenschaft(en) der zu sperrenden Objekte beschreibt. Definition 9.18: Prädikatsperren Prädikatsperren sind Sperren, die auf logischer Ebene dadurch gesetzt werden, dass ein Prädikat angegeben wird, welches exakt und eindeutig die Menge aller zu sperrenden Objekte beschreibt. Beispiel 9.8: Prädikatsperren Ute sucht für einen preisbewussten Kunden nur Hotels, in denen noch ein Zimmer frei ist, das weniger als 100,– C kostet. Damit würde das Prädikat P wie folgt aussehen: (Hotel.freieZimmer > 0 AND Hotel.preis < 100) Prädikatsperren werden auf logischer Ebene gesetzt, was heißt, dass nicht jeder einzelne Satz, der eine gegebene Bedingung erfüllt, gesucht und gesperrt wird. Vielmehr wird das Prädikat P 12 Eine Abschwächung einer Sperre entspricht in ihren Auswirkungen einer (eingeschränkten) Sperrfreigabe und darf deshalb nur in der Schrumpfungsphase vorgenommen werden. 13 Hierarchische Sperren können hier helfen, sind jedoch als allgemeine Lösung zu teuer. Jedes Mal wenn ein neues Objekt eingefügt wird, müsste die komplette Tabelle S-gesperrt werden. Bei physischen Sperren wird das Phantomproblem i. d. R. auf der Ebene der Zugriffspfade gelöst.
606
9 Transaktionsverarbeitung und Fehlertoleranz
in eine so genannte Prädikattabelle eingetragen, falls es keine unerlaubte Überlappung mit einem anderen Prädikat in der Tabelle gibt. Zwei Prädikate überlappen sich, falls es Objekte geben könnte, die beide Prädikate erfüllen. Überlappungen sind nicht erlaubt, falls die über die Prädikate zu sperrenden Objekte in inkompatibler Weise verarbeitet werden sollen, also mindestens eine der beteiligten Transaktionen die über das Prädikat gesperrten Objekte auch verändern oder (neue) Objekte, die das Prädikat erfüllen, in die DB einfügen möchte. Kann P in die Tabelle eingetragen werden, so sind von diesem Augenblick an alle Objekte, die P erfüllen, für die Transaktion im von ihr gewünschten Modus (S oder X) gesperrt. Beim Zugriff auf ein Objekt, insbesondere auch beim Schreiben, muss geprüft werden, ob es tatsächlich (noch) P erfüllt. Der Witz beim Prädikatsperren ist nun, dass diese Sperrvariante nicht auf der Ebene der aktuellen Datensätze der DB sperrt, sondern auf der Ebene des Wertebereiches einer Tabelle. Es werden alle aktuell in der DB befindlichen sowie alle grundsätzlich möglichen Datensätze einer Tabelle gesperrt. Dadurch erledigt sich das Phantomproblem automatisch, da es einfach keine Phantome mehr gibt. Zu beachten ist allerdings, dass Änderungen von Datensätzen, sofern sie die am Sperrprädikat beteiligten Spalten betreffen, nicht ganz unproblematisch sind, da die geänderten Datensätze durch die Änderung aus der Sperrmenge herausfallen könnten. Beispiel 9.9: Änderungen auf den am Prädikat beteiligten Spalten Falls Ute für einen Kunden alle Hotels in Los Angeles ermitteln möchte, die weniger als 100,– C kosten, während Willy die Preise aller mehr als 100,– C kostenden Hotels um zehn Prozent erniedrigen möchte, gibt es auf der Ebene der Prädikate keine Konflikte. Gab es aber ein Hotel, welches 108,– C kostete, so war es vor der Änderung durch Willy noch durch dessen Prädikat abgedeckt, danach nicht mehr. Stattdessen wird dieses Hotel jetzt plötzlich durch das Prädikat von Ute abgedeckt, was natürlich nicht sein darf. Leider haben Prädikatsperren neben den obigen (lösbaren) Problemen noch weitere erhebliche Nachteile. Der wohl Gravierendste ist, dass die Frage, ob zwei beliebige Prädikate disjunkte Objektmengen beschreiben, im allgemeinen Fall unentscheidbar ist. Möchte Elke im obigen Beispiel parallel zu Ute und Willy alle Hotels mit Sauna und Schwimmbad exklusiv sperren, so ist unklar, ob sich die beiden Prädikate überlappen. Um trotzdem eindeutige Entscheidbarkeit sicherstellen zu können, müsste entweder die Menge der erlaubten Prädikate eingeschränkt werden, was unrealistisch ist, oder eine vorsichtigere Strategie gefahren werden, die schon im Fall einer theoretischen Möglichkeit einer Überlappung die Parallelarbeit auf der DB unterbindet, was ebenfalls ein sehr harter Einschnitt wäre. Selbst wenn gegenwärtig kein Hotel mit Sauna und Schwimmbad existiert, das billiger als 100,– C ist, müssen sich die Prädikate von Elke und Ute ausschließen, sofern es keine Regel gibt (Konsistenzbedingung), nach der Hotels mit Schwimmbad und Sauna nicht für unter 100,– C angeboten werden dürfen.14 Bisher werden logische Sperren noch in keinem uns bekannten kommerziellen DBMS eingesetzt, insbesondere auch, weil noch keine effizienten Algorithmen für eine hinreichend allgemeine Klasse von Prädikaten existieren. 14 Wobei damit immer noch nicht das Problem gelöst ist, wie die Synchronisationskomponente an die Konsistenzbedingungen herankommt und ob sie diese korrekt interpretieren kann.
9.2 Synchronisationsverfahren
9.2.3
607
Zeitstempelverfahren
Insbesondere im Zusammenhang mit verteilten DBMS werden Synchronisationsverfahren diskutiert, die eine Synchronisation in der zeitlichen Reihenfolge, in der Transaktionen initiiert werden, anstreben. Solche Verfahren, die Zeitstempelverfahren (time stamping methods) genannt werden, arbeiten ohne direkte Sperren. Da diese Verfahren bisher kaum in der Praxis genutzt werden, soll hier nur deren grundsätzliche Idee skizziert werden. Jeder Transaktion T wird mit ihrem Beginn eine eindeutige Zeitmarke T S(T ) (time stamp) zugewiesen. Wichtig ist, dass Zeitmarken eindeutig sein müssen und total geordnet sind. Beispielsweise könnte der (hinreichend fein dargestellte) Startzeitpunkt einer Transaktion genommen werden. Jede Operation wird mit der Zeitmarke der sie ausführenden Transaktion versehen. Jedes Objekt O der DB besitzt eine Zeitmarke T SR (O), die angibt, welche Transaktion das Objekt zuletzt gelesen hat und eine zweite Zeitmarke T SW (O), die dasselbe für die letzte Schreiboperation auf O leistet. Beim Wunsch des Ausführens einer Lese- oder Schreiboperation auf O durch eine Transaktion T arbeitet das Zeitstempelverfahren den folgenden Algorithmus ab: 1. Leseoperation IF T S(T ) < T SW (O) THEN Abbruch T ELSE BEGIN führe Leseoperation aus T SR (O) := MAX{T SR (O), T S(T )} END; 2. Schreiboperation IF T S(T ) < MAX{T SR (O), T SW (O)} THEN Abbruch T ELSE BEGIN führe Schreiboperation aus T SW (O) := T S(T ) END; Dieser Algorithmus sorgt dafür, dass konfliktäre Operationen von Transaktionen auf denselben Daten ausschließlich in der Reihenfolge ihrer Zeitmarken ausgeführt werden, was insbesondere impliziert, dass Transaktionen in der Reihenfolge ihres Startzeitpunktes bzw. ihrer Zeitmarke „serialisiert“ werden15 . Falls dies nicht möglich ist, wird eine Transaktion abgebrochen und üblicherweise nach Ablauf eines bestimmten Zeitintervalls16 mit einer neuen Zeitmarke neu gestartet. Eine Leseoperation einer Transaktion T kann nur ausgeführt werden, wenn ihre Zeitmarke „jünger“ ist als die des letzten Schreibers, was bedeutet, dass die 15 Ein Sperrverfahren hingegen erzeugt einen Schedule, der zur seriellen Schedule auf der Basis der Beendigungsreihenfolge der Transaktionen identisch ist. 16 Der verzögerte Neustart soll vermeiden, dass die Transaktion erneut mit der für den vorherigen Abbruch verantwortlichen Transaktion „aneinander gerät“. Die Wartezeit sollte deshalb die durchschnittliche Laufzeit einer Transaktion sicher genug überschreiten.
608
9 Transaktionsverarbeitung und Fehlertoleranz
Transaktion, die als letztes das Objekt manipuliert hat, vor T gestartet wurde. Eine Schreiboperation kann nur dann ausgeführt werden, wenn kein „jüngerer“ Leser und kein „jüngerer“ Schreiber auf das Objekt zugegriffen hat, also noch keine später begonnene Transaktion das Objekt schon „besucht“ hat. Da die Operationen auf diese Weise nach den Zeitmarken angeordnet werden, wobei jede Zeitmarke exakt eine Transaktion repräsentiert, ist die entstehende Schedule zwangsläufig serialisierbar.
9.2.4
Optimistische Synchronisationsverfahren
Optimistische Synchronisationsverfahren gehen davon aus, dass die Wahrscheinlichkeit für das Entstehen nicht-serialisierbarer Schedule sehr klein ist. Deshalb ist das als Vorbeugung gedachte Sperren von Objekten ein zu hoher Preis. Optimistische Verfahren greifen dementsprechend nicht in den Ablauf von Transaktionen ein. Vielmehr erlauben sie ein beliebiges paralleles Arbeiten auf den Daten der DB. Erst mit dem Ende der eigentlichen Arbeiten auf den Daten überprüft die Transaktion, ob Konflikte zu anderen Transaktionen aufgetreten sind. Falls nicht, endet sie ordnungsgemäß, falls doch, muss eine am Konflikt beteiligte Transaktion zurückgesetzt werden. Dementsprechend untergliedert sich die Ausführung einer Transaktion in die drei in Abbildung 9.5 gezeigten Phasen.
Lese-
Validations-
Schreib-
phase
phase
phase
Transaktion T
Abb. 9.5: Phasen einer Transaktion bei optimistischer Synchronisation
Lesephase Während der Lesephase werden alle von der Transaktion benötigten Objekte aus der DB gelesen und in einen transaktionsbezogenen Puffer geschrieben. Die der Transaktion zugeordneten Operationen werden ausschließlich auf diesen internen Kopien ausgeführt, so dass sie für andere Transaktionen zunächst unsichtbar bleiben. Damit ist gewährleistet, dass jede Transaktion vor Erreichen ihrer Schreibphase einfach durch Freigabe des internen Puffers zurückgesetzt werden kann. Validationsphase Sobald eine Transaktion ihre Arbeiten vollständig durchgeführt hat, wechselt sie von der Lesein die Validationsphase. Hierin wird überprüft, ob die Transaktion das Serialisierbarkeitskriterium verletzt haben könnte. Da die Lesephase völlig uneingeschränkt abgelaufen ist, kann die Transaktion Objekte bearbeitet haben, die zwischenzeitlich von anderen parallelen Transaktionen geändert wurden. In einem solchen Fall muss eine Maßnahme zur Konfliktauflösung durchgeführt werden. Optimistische Verfahren lösen den Konflikt, indem sie eine der beteiligten Transaktionen zurücksetzen.
9.2 Synchronisationsverfahren
609
Schreibphase Wurde in der Validationsphase kein Konflikt zu anderen Transaktionen entdeckt, können die durchgeführten Änderungen allgemein freigegeben werden. Dies geschieht, indem die lokalen Kopien in die DB übertragen werden. Das Ende der Schreibphase bedeutet auch gleichzeitig das Ende der Transaktion. Die Validationsphase ist das Kernstück eines jeden optimistischen Verfahrens, da sie die Serialisierbarkeit der erzeugten Schedule gewährleistet. Dementsprechend unterscheiden sich optimistische Verfahren im Wesentlichen auch nur durch das der Validation zu Grunde liegende Regelwerk. Ohne tiefer auf die Verfahren eingehen zu wollen, sollen im Folgenden die wichtigsten Validationstechniken von ihrer Grundidee her kurz vorgestellt und anhand eines einheitlichen Beispiels erläutert werden. Im Beispiel wird grundsätzlich davon ausgegangen, dass die Transaktion TV(alidation) die beendigungswillige Transaktion ist, anhand derer die jeweilige Validationstechnik erläutert werden soll. Da eine in ihrer Validationsphase befindliche Transaktion TV noch keine von ihr geänderten Daten freigegeben hat, kann sie parallele Transaktionen noch nicht beeinflusst haben. Dementsprechend muss in der Validationsphase nur festgestellt werden, ob die von TV gelesenen Daten noch aktuell sind. Dazu wird überprüft, ob seit dem Beginn von TV irgendeine parallele Transaktion beendet wurde, die Daten modifiziert hat, auf die TV zugegriffen hat. Genauer gesagt wird das Schreibset jeder Transaktion, die in der Lesephase von TV Daten in die DB übertragen hat, mit dem Leseset von TV verglichen. Das Schreibset einer Transaktion enthält genau die Menge an Daten, die eine Transaktion geschrieben hat. Entsprechendes gilt für das Leseset. Ist die Schnittmenge nicht leer, so liegt ein Konflikt vor und TV muss zurückgesetzt werden. Dies ist die Grundidee des von Kung und Robinson vorgestellten Validationsverfahrens (siehe Abbildung 9.6).
Lesen
Val
Lesen
Schreiben
Val
Ti
Schreiben
Lesen
Tj Val
Schreiben
Lesen
TV Val
t1
t2 t3
t4
Abb. 9.6: Ursprüngliche Validation nach Kung und Robinson
t5
Schreiben
t6
Tk Zeit
610
9 Transaktionsverarbeitung und Fehlertoleranz
Die Transaktion TV muss in ihrer Validationsphase (t3 bis t4 ) gegenüber allen in ihrer Lesephase geendeten Transaktionen validieren. Im obigen Szenario sind das die Transaktion Ti (Validationstest: Schreibset(Ti ) ∩ Leseset(TV ) = ∅) und Tj (Validationstest: Schreibset(Tj ) ∩ Leseset(TV ) = ∅). Gibt es keine Konflikte, kann die Schreibphase durchgeführt werden. Damit ist TV erfolgreich abgeschlossen. Im Fall eines Konfliktes kann nur TV zurückgesetzt werden, da alle anderen beteiligten Transaktionen bereits abgeschlossen sind. Die ebenfalls parallel laufende Transaktion Tk validiert erst in ihrer Validationsphase gegenüber TV . Optimistische Synchronisationsverfahren serialisieren grundsätzlich in der Reihenfolge, in der die Transaktionen in ihre Validationsphase eintreten. Damit ist die serielle Schedule, in der alle Transaktionen in der Reihenfolge stehen, in der sie in die Validationsphase eingetreten sind, auf jeden Fall äquivalent zu der durch ein optimistisches Synchronisationsverfahren erzeugten (serialisierbaren) Schedule. Die ursprüngliche Validationstechnik wurde in den darauffolgenden Jahren noch erheblich optimiert. Dabei wurde die Beobachtung ausgenutzt, dass ein Konflikt zwischen einer bereits beendeten Transaktion Te und der validierenden Transaktion TV nur dann wesentlich ist, wenn TV das Konfliktobjekt gelesen hat, bevor es von Te geschrieben wurde (gilt für Ti in Abbildung 9.7). Andernfalls, wenn TV das Konfliktobjekt gelesen hat, nachdem es von Te geschrieben wurde, liegt kein echter Konflikt vor, da dies dem Fall entspricht, dass TV ihre Lesephase erst nach dem Ende von Te begonnen hat (gilt für Tj in Abbildung 9.7). Die Reihenfolge Te vor TV ist in der seriellen Schedule offensichtlich möglich. Da dies, wie oben bereits erläutert wurde, die grundsätzliche Reihenfolge ist, in der optimistische Verfahren Transaktionen serialisieren, liegt bei diesem zweiten Fall ein Scheinkonflikt vor. Die verbesserte Validationstechnik heißt Schnappschussvalidation. Schnappschussvalidation Die Idee ist nun, dass man, um ein Rücksetzen einer Transaktion aufgrund von solchen unechten Konflikten zu vermeiden, jeweils nach dem Ende der Lesephase einer Transaktion TV Lesen
Val
Schreiben
Te
WRITE(x, y)
Lesen
Val
Schreiben
Ti
READ(x)
Lesen
Val Schreiben READ(y)
t1
t2
Abb. 9.7: Unnötiges Zurücksetzen bei der ursprünglichen Validationstechnik
t3
Tj Zeit
9.2 Synchronisationsverfahren
611
– entweder in der Validationsphase oder nach der Schreibphase (siehe später) – überprüft, ob bereits ein Konflikt zu einer noch in der Lesephase befindlichen Transaktion TL besteht. Existiert ein solcher Konflikt, so ist bereits jetzt klar, dass TL zurückgesetzt werden muss. Demnach kann TL auch gleich jetzt abgebrochen werden und muss nicht erst bis zu ihrer Validationsphase weiterarbeiten. Existiert kein Konflikt, kann aufgrund des vorher Gesagten auch später kein Konflikt mehr zu TV auftreten. Diese Verfahren heißen Schnappschussvalidation (snapshot-validation) bzw. Vorwärtsvalidation (forward oriented validation). Schnappschussvalidation mit kritischem Abschnitt Wird die Validation ausgeführt, bevor die beendigungswillige Transaktion ihre Daten in die DB übertragen hat, kann im Konfliktfall ausgesucht werden, welche der am Konflikt beteiligten Transaktionen zurückgesetzt werden soll. Dafür ist als Preis zu zahlen, dass eine validierende Transaktion während der Validations- und Schreibphase der beendigungswilligen Transaktion nicht auf der DB arbeiten darf, da ansonsten kein stabiles bzw. korrektes Leseset für den Konflikttest zur Verfügung stünde. Eine Phase, während der nur eine Transaktion auf der DB arbeiten darf, die also aus der Sicht der DBMS eine ununterbrechbare Einheit darstellt, nennt man kritischen Abschnitt. Deshalb heißt diese Variante Schnappschussvalidation mit kritischem Abschnitt. Gegenüber dem Vorschlag von Kung und Robinson ergibt sich ein entscheidender Unterschied bzgl. der Validation. Die Transaktion TV sichert sich in ihrer Validationsphase nicht mehr gegenüber parallelen Transaktionen ab, sondern ihre Validation findet bereits kumulativ während ihrer Lesephase statt. Die eigentliche Validationsphase hat demnach jetzt den umgekehrten Zweck: Parallele Transaktionen, die ihre Validationsphase noch nicht erreicht haben, validieren jetzt gegenüber TV . Es sei aus Gründen der Korrektheit angemerkt, dass auch TV in ihrer Validationsphase noch gegenüber anderen Transaktionen validieren muss und zwar gegenüber allen Transaktionen, die bereits vor TV in ihre Validationsphase eingetreten sind, diese aber noch nicht beendet haben. Das sind Transaktionen, gegenüber denen sich TV bisher noch nicht abgesichert hat. In Abbildung 9.8 überlappen sich die Laufzeiten von TV und Ti . Deshalb könnte man der Meinung sein, dass sich TV gegenüber Ti absichern müsste. Da zum Startzeitpunkt von TV Ti allerdings schon in ihrer Validationsphase ist und diese Phase bei dieser Variante einen kritischen Abschnitt beschreibt, während dem keine Transaktion auf die Daten der DB zugreifen darf, kann TV noch keine Daten aus der DB gelesen haben. Demnach entfällt die Validation gegenüber Ti . Die Transaktionen Tj und Tk validieren nun innerhalb des Zeitraumes t4 bis t5 mit ihrem bis zum Zeitpunkt ihrer Validation entstandenen Leseset gegenüber TV . Wird ein Konflikt festgestellt, kann entweder TV oder die andere am Konflikt beteiligte Transaktion zurückgesetzt werden. Betrachtet man Abbildung 9.8 etwas genauer, so wird der entscheidende Nachteil dieser Variante sehr deutlich (obwohl er aus Gründen einer geeigneten Darstellung stark übertrieben ausfällt): Der kritische Abschnitt (für TV im obigen Bild von t4 bis t6 ) lähmt den Zugriff auf die DB erheblich. In Abbildung 9.8 wäre das Arbeiten auf der DB fast pausenlos verboten (nämlich während jeder Validations- und Schreibphase).
612
9 Transaktionsverarbeitung und Fehlertoleranz Lesen
Val Schreiben
Ti
Lesen Val Schreiben
TV Val Schreiben
Lesen
Val
Lesen
t1 Validationstest von Ti:
t2 TV:
t3 t4 t5
Tj
t6 t7
t8
t9 t10
Schreiben
t11
t12
Tk Zeit
Tj:
Abb. 9.8: Schnappschussvalidation mit kritischem Abschnitt
Schnappschussvalidation ohne kritischen Abschnitt Diese Variante entspricht vom Prinzip her der Variante der Schnappschussvalidation mit kritischem Abschnitt. Der entscheidende Unterschied liegt nur im Zeitpunkt, an dem parallele, noch in der Lesephase befindliche Transaktionen TL gegenüber der endenden Transaktion TV validieren. Bei dieser Variante geschieht das grundsätzlich nach dem Ende von TV und damit nach Übertragung aller durch TV geänderten Daten in die DB. Da nur der Teil des Lesesets von TL interessiert, der die Daten enthält, die bis zum Ende von TV gelesen wurden – und dieser Teil steht natürlich beim Ende von TV fest und ist somit unveränderlich –, dürfen alle parallelen Transaktionen TL während der Validations- und Schreibphase von TV und auch während ihrer eigenen Validation gegenüber TV weiter auf der DB arbeiten. Es entfällt der kritische Abschnitt. Der Nachteil dieser Schnappschussvalidation ohne kritischen Abschnitt genannten Variante liegt darin, dass im Konfliktfall nur die noch aktive Transaktion (TL ) zurückgesetzt werden kann, da TV bereits abgeschlossen ist. In Abbildung 9.9 validiert die Transaktion TV zum Zeitpunkt t1 (ebenso wie die Transaktionen Tj und Tk ) gegenüber Ti und zwar mit dem bis zu diesem Zeitpunkt entstandenen Leseset. Zum Zeitpunkt t5 validiert Tk gegenüber TV . Im Falle eines Konfliktes kann nur Tk zurückgesetzt werden, da TV bereits beendet ist. Die eigentliche Validationsphase einer Transaktion ist zu einer sehr knappen Phase zusammengeschrumpft, während der sich eine Transaktion nur gegenüber parallel validierenden Transaktionen absichern muss, gegenüber denen noch keine Absicherung stattgefunden hat. In Abbildung 9.9 hatte sich TV noch nicht gegenüber Tj abgesichert (auch nicht umgekehrt), so dass TV dies in ihrer Validationsphase (Zeitraum t2 bis t3 ) nachholen muss. Optimistische Verfahren auf der Basis der Schnappschussvalidation besitzen eine bessere Durchlässigkeit als Sperrverfahren, während Sperrverfahren umgekehrt ein besseres Steuerungsvermögen besitzen. Obwohl optimistische Synchronisationsverfahren also durchaus Vor-
9.2 Synchronisationsverfahren Lesen
613
Val Schreiben
Ti Val Schreiben
Lesen
Val Schreiben
Lesen
TV Validation gegenüber Tj
Val
Lesen
t1 Validationstest gegenüber Ti :
TV:
Tj:
t2
t3
t4 t5
Tj Schreiben
t6
Tk Zeit
Validationspunkt
Abb. 9.9: Schnappschussvalidation ohne kritischen Abschnitt
teile besitzen, werden sie in der Praxis bisher wenig eingesetzt. Die Gründe liegen dabei vor allem in wenig effizienten Implementierungen. Von den bekannteren DBMS setzt lediglich das objektorientierte DBMS GemStone diese Technik ein.
9.2.5
Synchronisation in SQL-92
Relationale DBMS haben in den Anfängen überwiegend implizit synchronisiert, was heißt, dass die Synchronisationsoperationen für den Programmierer unsichtbar in andere Operationen eingebunden wurden. Beispielsweise entsprach jeder SFW-Block einer Transaktion oder jede Lese- bzw. Schreiboperation hat das Setzen einer entsprechenden Sperre nach sich gezogen. Einerseits war damit der Vorteil verbunden, dass der Anwendungsprogrammierer und insbesondere auch der gelegentliche Benutzer mit Synchronisationsaspekten nichts zu tun hatte. Andererseits ist es unter diesen Umständen aber kaum möglich, logisch zusammengehörige Operationen (die ja eine Transaktion ausmachen sollen) auch wirklich flexibel zu klammern. In SQL-92 gibt es daher einige explizite Befehle, mit denen der Zugriff auf die DB gesteuert werden kann (siehe Syntax 9.1). Syntax 9.1: Transaktion in SQL-92 TransaktionsStart ::= [Konsistenzstufe] ::= TransaktionsEnde ::=
SET TRANSACTION [READ {ONLY|WRITE}] [, Konsistenzstufe][, DIAGNOSTICS SIZE n] ISOLATION LEVEL {READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE} {COMMIT|ROLLBACK} [WORK]
Nach wie vor ist das explizite Starten einer Transaktion nicht notwendig. Das DBMS wird immer dann, falls „schutzbedürftige“ Operationen auf der DB ausgeführt werden sollen (Anfragen, Einfüge- und Löschoperationen, Änderungen am Schema), implizit eine Transaktion
614
9 Transaktionsverarbeitung und Fehlertoleranz
starten. Der SET TRANSACTION-Befehl macht daher nur dann Sinn, falls auch eine der nicht als Default spezifizierten Optionen gewählt werden soll. Beispiel 9.10: Start einer Transaktion SET TRANSACTION READ ONLY ISOLATION LEVEL READ UNCOMMITTED DIAGNOSTICS SIZE 6 Es ist möglich, eine Transaktion zu starten, die als so genannte Lesetransaktion (READ ONLY) nur lesend auf der DB arbeiten darf (siehe Beispiel 9.10). Aus der Sicht des Benutzers ändert sich dadurch zwar nichts, allerdings kann der Scheduler diese Information ausnutzen, wodurch insgesamt ein verbesserter Grad an Parallelarbeit auf der DB erreicht werden kann. Zudem darf eine reine Lesetransaktion auch auf dem Datenbestand „browsen“, was bedeutet, dass die Transaktion alle Daten der DB sofort lesen darf (READ UNCOMMITTED), unabhängig davon, ob sie gerade von anderen Transaktionen verändert werden. Ein solches Lesen wird auch schmutziges Lesen (dirty read) genannt. Eine READ-WRITE-Transaktion ist die übliche Transaktion, die sowohl Lesen als auch Schreiben darf. Über den Diagnosebereich können Anwendung und DBMS Fehlerdiagnosen austauschen. Mit DIAGNOSTICS SIZE wird dabei die Größe des Diagnosebereiches festgelegt. Einer Transaktion ist als Default der höchste Schutz zugewiesen, was einer vollen Isolation dieser Transaktion von anderen Transaktionen entspricht. Daneben können aber auch noch weichere Konsistenz- bzw. Isolationsstufen festgelegt werden, deren Semantik Tabelle 9.3 entnommen werden kann. Wie bereits erwähnt ist das völlig ungeschützte Lesen (READ UNCOMMITTED) nur reinen Lesetransaktionen vorbehalten, während die anderen Optionen auch von normalen Transaktionen gewählt werden dürfen. Beim READ COMMITTED wird garantiert, dass eine Transaktion nur solche Daten zu sehen bekommt, die nicht gerade in einem Bearbeitungsprozess durch eine andere Transaktion sind.
Schmutziges Lesen
Nicht wiederholbares
Phantomproblem
Lesen READ UNCOMMITTED
kann auftreten
kann auftreten
kann auftreten
READ COMMITTED
nicht möglich
kann auftreten
kann auftreten
REPEATABLE READ
nicht möglich
nicht möglich
kann auftreten
SERIALIZABLE
nicht möglich
nicht möglich
nicht möglich
Tabelle 9.3: Konsistenz- bzw. Isolationsstufen von Transaktionen
9.2 Synchronisationsverfahren
615
Die Leseoperation selber ist allerdings mit keiner Sperrsetzung17 verbunden, weshalb ein gelesenes Datum anschließend von einer parallelen Transaktion verändert werden kann. Daraus folgt, dass die Transaktion, würde sie das Datum später noch einmal aus der DB lesen, einen anderen Wert zu Gesicht bekommen könnte.18 Gegenüber dem ungeschützten Lesen ergibt sich jedoch die Verbesserung, dass ein exklusiv gesperrtes Datum nicht gelesen werden kann. Beim wiederholbaren Lesen (REPEATABLE READ) wird volle Serialisierbarkeit gewährleistet, so lange keine neuen Datensätze in die DB eingefügt werden oder eine Transaktion Daten so ändert, dass sie jetzt das Selektionskriterium (nicht mehr) erfüllen, welches die Basis der Leseoperation gewesen ist. Das Phantomproblem ist bei dieser Variante noch nicht gelöst. Die schärfste Variante (SERIALIZABLE) schließlich garantiert, dass die Transaktion in jedem Fall so auf der DB arbeiten kann, als sei sie die einzige Aktive. Einflüsse von anderen Transaktionen, gleich welcher Art, sind ausgeschlossen. Sobald die Folge von zusammengehörigen Operationen, die der Transaktion zu Grunde liegt, auf der DB ausgeführt wurde, kann die Transaktion über den COMMIT-Befehl abgeschlossen werden. Hat es Probleme in der Transaktionsverarbeitung gegeben, die aus der Sicht der Anwendung so gravierend sind, dass die Arbeit der Transaktion besser nicht in die DB eingebracht werden soll, kann die Transaktionsausführung zu jedem Zeit durch den ROLLBACKBefehl unterbrochen werden. Die Transaktion wird vollständig zurückgesetzt, so dass keine Auswirkungen dieser Transaktion in der DB sichtbar bleiben (siehe auch das folgende Kapitel über Fehlertoleranz).
9.2.6
TP-Monitor
Ein TP-Monitor (transaction processing monitor) ist ein Middleware-Produkt, welches die in einer heterogenen, verteilten Datenverarbeitungslandschaft bestehenden Kommunikationsprobleme zwischen Anwendungen und Datenbeständen transparent, fehlertolerant und effizient überbrückt. Er gleicht damit die individuellen Schwächen der Anwendungs- und Datenverwaltungssysteme aus und erlaubt damit eine Datenverarbeitung auf einer logisch höheren Ebene. In den 80er Jahren stand TP noch als Abkürzung für Teleprocessing. Die Basisidee war seinerzeit, einen schnellen und effizienten Zugang zur DB sicherzustellen, wobei der Zugriff auf mehrere Datenressourcen noch keine wesentliche Rolle spielte. Das Problem ist, dass der Aufbau einer Verbindung zu einem DBS im Normalfall ein sehr aufwändiger und damit zeitintensiver Prozess ist. Da dies häufig auch noch die Einrichtung eines eigenen Betriebssystemprozesses zur Folge hatte, ist eine solche Verbindung auch noch teuer. Diese Nachteile fielen umso mehr ins Gewicht, je höher die Parallelarbeit auf der DB war, da viel Zeit unnütz mit dem Auf- und Abbau (Öffnen und Schließen) von Verbindungen zur DB vertan wird. Die Idee war deshalb, nur einen, dafür aber dauerhaft laufenden Serverprozess einzurichten (Single-Server-Modell, siehe Abbildung 9.10a.). Über diesen wickeln dann alle Anwendungen ihre Datenbankzugriffe ab. Der Serverprozess übernahm auch Betriebssystemfunktionen wie 17 Lediglich
der reine Lesevorgang wird als atomarer Schritt durch eine Sperre abgesichert. beachte aber, dass dieser Wert kein Zwischenwert einer ändernden Transaktion sein kann. Auf unser obiges Beispiel bezogen muss die ändernde Transaktion die Sperre auf dem Datum bereits wieder freigegeben haben, damit das Datum erneut gelesen werden kann. 18 Man
616
9 Transaktionsverarbeitung und Fehlertoleranz
Serverprozess Serverprozess Serverprozess Serverprozess
Daten
Daten Router
Serverprozess Serverprozess Serverprozess
a. Single-Server-Modell
b. Many-Server/Single-Router-Modell
Serverprozess
Router
Serverprozess
Serverprozess Router
Serverprozess
Router
Serverprozess
Serverprozess
Daten Serverprozess
Daten Router
Serverprozess Router
Daten
Serverprozess
c. Many-Server/Many-Router-Modell
Serverprozess
Daten Serverprozess
Router
Serverprozess
Daten
d. Many-Server/Many-Router/ManyData-Sources-Modell
Abb. 9.10: Architektur von TP-Monitoren
z. B. die Authentifizierung und das Multitasking. Wenn sich eine Vielzahl von Anwendungen auf einem Serverprozess abstützen, besteht die Gefahr der Blockierung, falls beispielsweise gerade eine umfangreichere Aufgabe für eine Anwendung abgearbeitet werden muss. Um dies zu vermeiden wird pro Anwendung ein leichtgewichtiger Prozess (Thread) eingerichtet. Gepaart wurde das Ganze mit einem eigenen „billigen“ Multitasking innerhalb des Serverprozesses. Mit wachsender Hauptspeichergröße und Leistungsfähigkeit der Prozessoren (CPUs) verringerte sich die Attraktivität dieses Konzept immer mehr, vor allem, da es keine Parallelisierung der Aufgaben erlaubte. Zudem hatte es den Nachteil, dass Anwendungen nicht sauber voneinander isoliert werden konnten. Eine fehlerhafte Anwendung konnte damit auch alle anderen mit in den Abgrund ziehen. Es lag auf der Hand, das Single-Server-Modell zu einem Many-Server-Modell auszubauen. Dazu wird die Architektur um einen Router erweitert, der die Aufgabe hat, die ankommenden Aufgaben möglichst ausgeglichen auf die einzelnen Serverprozesse zu verteilen. Dabei ist einer Anwendung nicht statisch ein Serverprozess zugeordnet, sondern es laufen eine Anzahl von Serverprozessen, die dynamisch und abhängig von ihrer Verfügbarkeit ankommenden Anforderungen zugeordnet werden. Damit wird eine wesentlich höhere Effizienz pro Verbindung sichergestellt, da Zeiten, während der eine Anwendung nicht direkt auf der DB arbeitet, von anderen Anwendungen genutzt werden können. Diese Variante läuft unter dem Namen Many-
9.2 Synchronisationsverfahren
617
Server/Single-Router-Architektur (siehe Abbildung 9.10b.). Gerade in verteilten Umgebungen ist diese Architektur wegen ihrer Zentrierung auf den Router zu wenig flexibel und ineffizient. Deshalb hat man statt eines Routers mehrere Router eingesetzt (siehe Abbildung 9.10c.). Nach hinten hin könnte man jetzt natürlich noch die eine Datenquelle durch eine Vielzahl von Datenquellen ersetzen, wodurch man eine für heutige Client/Server-Umgebungen typische Architektur erhält. Insgesamt ordnet man heutigen TP-Monitoren ein breites Spektrum unterschiedlichster Aufgaben zu, die weit über das oben bereits Diskutierte hinausgehen. Auch die folgende Auflistung ist durchaus nicht als vollständig anzusehen. • Das Verbergen der unterschiedlichen Darstellung von Daten vor der Anwendung bzw. dem DBMS, in dem Fall, dass das DBMS bzw. die Anwendung auf unterschiedlicher Hardware und/oder unter unterschiedlichen Betriebssystemen betrieben wird; hierzu gehört auch die spezifische Betreuung unterschiedlichster Endgeräte wie PCs, Terminals oder spezieller Hardware wie Strichcodeleser oder Geldautomaten. • Die Präsentation der Daten in der vom Endgerät gewünschten Form, auch wenn die Daten in einer anderen Form von den angesprochenen Datenverwaltungssystemen geliefert werden; beispielsweise das Ausnutzen von grafischen Darstellungsmöglichkeiten auf Workstations oder die Präsentation in ASCII-Format auf simplen Endgeräten wie ASCII-Terminals oder Geldautomaten. • Die Steuerung und Überwachung des Zugriffes auf entfernt liegende Datenbestände – i. d. R. über Remote Procedure Calls (RPCs) –, falls Daten nicht auf dem Rechner liegen, auf dem auch die Anwendung läuft. • Die Koordination von Zugriffen auf verschiedene Datenbestände – z. B. über das Zweiphasen-Freigabeprotokoll19 –, falls die Daten aus mehreren Quellen bezogen werden müssen, und die Integration und einheitliche Präsentation von deren individuellen Ergebnissen. • Die Steuerung und Überwachung der Last beim Zugriff auf Datenbestände inklusive der Durchsetzung von Vorrangregeln; beispielsweise der Art, dass Online-Transaktionen immer Vorrang vor Batchtransaktionen erhalten. • Die Überwachung und Ausführung von Aufgaben, die logisch oberhalb einer einzelnen Transaktion liegen. Hierunter fällt beispielsweise die kontrollierte Ausführung einer Folge von Transaktionen, wobei möglicherweise nicht alle Transaktionen auf derselben DB auszuführen sind. • Die Durchsetzung und Überprüfung von Authentifikations- und Autorisierungsmaßnahmen, die oberhalb der Einzelsysteme liegen. Dabei kann auch eine Abbildung auf die Anforderungen der Einzelsysteme stattfinden. 19 Diese Protokoll sollte nicht mit dem Zweiphasen-Sperrprotokoll verwechselt werden. Das Zweiphasen-Freigabeprotokoll ist ein Synchronisationsverfahren, dass innerhalb einer verteilten Umgebung sicherstellt, dass auch auf einer globalen Ebene über alle verteilten Datenbestände bzw. -banken hinweg korrekt synchronisiert wird. Solche mehrere verteilte DB ansprechende so genannte globale Transaktionen synchronisieren sich lokal (auf einer DB) wie bisher, müssen aber auf der globalen Ebene einen zweistufigen Beendigungsprozess durchlaufen, der die operationale Integrität auf der globalen Ebene garantiert.
618
9 Transaktionsverarbeitung und Fehlertoleranz
• Die Behandlung von Fehlern, die aufgetreten sind, nachdem die Daten den Arbeits- bzw. Kontrollbereich des DBMS verlassen haben, also von diesem nicht bemerkt und damit nicht mehr behandelt werden können. Darunter fällt z. B. die sichere, d. h. garantierte und korrekte Übertragung von Ergebnissen auf den Bildschirm der Anwendung. TP-Monitore spielen in der DV-Landschaft vieler Unternehmen eine ganz zentrale Rolle, da sie in der Lage sind, Heterogenität, gleich welcher Art, zu verbergen und Fehlertoleranz oberhalb eines DBMS sicherzustellen. Diese Eigenschaften vereinfachen die Implementierung der eigentlichen Anwendung spürbar, da Probleme der Parallelität (oberhalb eines DBMS), Kommunikationsprobleme, Verbindungsprobleme zwischen oder Ausfälle von Rechnern, heterogene Hardware und viele andere mehr oder weniger komplexe Probleme nicht mehr in der Anwendung gelöst werden müssen. Zu den bekanntesten kommerziell verfügbaren TP-Monitoren gehören Digital ACMSxp, IBM Customer Information Control System (CICS), Pathway, Microsoft Transaction Server (MTS) und BEA Systems Tuxedo. Diese TP-Monitore unterstützen einige oder alle der obigen Features in einer mehr oder weniger ausgeprägten Form. Sie können aber auch noch weitere Funktionalität bereitstellen.
9.2.7
Literatur
Sperrhierarchien wurden ebenso wie Warnsperren in [Gray78] präsentiert. Prädikatsperren und deren Probleme werden beispielsweise in [EGLT76] behandelt. Deadlocks und deren Wahrscheinlichkeit werden in [GHOK81] diskutiert, wobei die Abschätzungen allerdings nur auf der Basis einer Wahrscheinlichkeitsberechnung gemacht werden. Die volle Übertragbarkeit der Resultate auf die Praxis darf angezweifelt werden. In der Literatur werden verschiedene Varianten von Zeitstempelverfahren diskutiert ([BeGo81], [BeHG88], [ChBe80], [Reed83], [Thom79], um einige wesentliche Arbeiten zu nennen). In zentralen DBMS werden Zeitmarkenverfahren bislang nicht eingesetzt, wohl aber in verteilten DBMS [BRGP78]. Die in diesem Buch vorgestellten Validationstechniken von optimistischen Synchronisationsverfahren stammen aus [KuRo79], [Härd85] und [Unla85], wobei die erste Literaturstelle auf das Originalpapier zur optimistischen Synchronisation verweist, während die anderen beiden Quellen die verbesserten Validationstechniken einführen. TP-Monitore werden u. a. sehr extensiv und praxisbezogen in [GrRe93] und [Meye88] behandelt.
9.3
Fehlertoleranz
Während im vorangegangenen Kapitel vor allem die Isolation von Transaktionen im Vordergrund stand, widmet sich dieses Kapitel der Unteilbarkeit und der Dauerhaftigkeit, also dem A und dem D des ACID-Kriteriums. Beide zusammen stehen für eine der wichtigsten Eigenschaften eines DBMS, der Fehlertoleranz. Fehlertoleranz sollte nicht als eines der beliebten Marketingschlagwörter abgetan werden, hinter dem sich wenig Substanz verbirgt. Es
9.3 Fehlertoleranz
619
ist im Gegenteil ein sehr mächtiges Konzept, da ein DBMS garantiert, dass nach Auftritt eines Fehlers, gleich welcher Art, die DB (wieder) in einen eindeutigen und konsistenten Zustand zurückversetzt wird. Das A besagt nun, dass Transaktionen aus der Sicht der Fehlertoleranz als die kleinsten Einheiten des Systems angesehen werden, mithin also nicht weiter zerlegbar sind. Bei den üblicherweise von DBMS unterstützten betriebswirtschaftlich-administrativen Anwendungen decken Transaktionen i. d. R. auch nur sehr „überschaubare“ Aufgaben ab, die sich aus der Sicht des DBMS sehr häufig in weniger als einer Sekunde erledigen lassen. Wenn nun Transaktionen die feinsten Einheiten des Systems sind, muss im Fall eines Fehlers nur noch festgelegt werden, welche Transaktionen den Fehlerfall überleben und welche nicht. Aus der Sicht eines möglichst geringen Arbeitsverlustes wäre es wünschenswert, wenn all die Arbeit gerettet werden könnte, die sozusagen bereits in trockenen Tüchern ist. Das sind alle bereits abgeschlossenen Transaktionen. Umgekehrt, alle Transaktionen, die noch nicht abgeschlossenen waren, können aufgrund des Atomaritätsprinzips nicht gerettet werden. Dementsprechend wäre die bestmögliche erreichbare Situation die, bei der einerseits alle Änderungen von zum Zeitpunkt des Fehlerauftritts bereits abgeschlossenen Transaktionen überleben, andererseits jedoch alle Änderungen von solchen Transaktionen wieder aus der DB entfernt werden, die zum Fehlerzeitpunkt noch nicht offiziell beendet waren. Genau dies wird durch die Recoverykomponente eines DBMS garantiert. Definition 9.19: Recovery Unter Recovery versteht man alle Aktionen eines DBMS, die im Zusammenhang mit der Sicherung der Konsistenz der DB in einem Fehlerfall stehen. Im Idealfall wird durch die Recoveryaktion der Fehler kaschiert, bleibt also aus der Sicht der Anwendung transparent. Recovery deckt eine Vielzahl unterschiedlichster Fehler ab, die vom Zurücksetzen einer einzigen Transaktion bis hin zum Erzeugen des letzten konsistenten Datenbankzustandes aus einer Archivkopie nach Auftritt eines besonders schweren Fehlers reichen. Bevor dann im Folgenden zunächst die zu behandelnden Fehlerklassen diskutiert werden, soll zunächst das Arbeiten mit einem DBMS anhand eines einfachen, aber für die folgenden Diskussionen ausreichenden Modells erläutert werden. Jedes DBS basiert auf einer materialisierten DB, auch Primärdaten genannt, die sich im Wesentlichen aus den auf dem (nichtflüchtigen) Sekundärspeicher liegenden Basistabellen zusammensetzt (siehe Abbildung 9.11). Möchte eine Anwendung auf die DB zugreifen, setzt sie einen entsprechenden Befehl ab. Als Reaktion auf diesen Befehl stellt das DBMS die gewünschten Daten in einem vom DBMS kontrollierten Puffer zur Verfügung. Der Datenbankpuffer ist nichts anderes als ein dem DBMS zugeordneter Hauptspeicherbereich, gehört also bereits zum flüchtigen Speicher. Aus diesem Puffer kann die Anwendung die Daten in ihren eigenen Hauptspeicherbereich lesen. Will die Anwendung neue oder veränderte Daten in die DB zurückschreiben, so wird der umgekehrte Weg beschritten: Die Daten werden aus dem Hauptspeicherbereich der Anwendung in den Datenbankpuffer übertragen. Jetzt ist es Aufgabe des DBMS, die Daten endgültig zu sichern, d. h. persistent zu machen. Dies geschieht durch Übertragung zum und möglicherweise redundante Speicherung der Daten auf Sekundärspeichermedien.
620
9 Transaktionsverarbeitung und Fehlertoleranz
Anwendungsbereich
Anwendungsbereich
Anwendungsbereich
Datenbankpuffer Hauptspeicher
materialisierte Datenbank
Abb. 9.11: Arbeitsweise eines DBMS
9.3.1
Fehler in Transaktionssystemen
Da Transaktionen und die DB allgemein von Fehlern betroffen sein können, muss das DBMS entsprechend reagieren können. Dazu muss zunächst ein Fehlermodell definiert werden, aus dem die Art von Fehlern hervor geht, die vom DBMS zu beachten sind. Wir werden im Folgenden anstelle des etwas zu einschränkenden Begriffs Fehler den allgemeineren Begriff Recoveryereignis verwenden. Definition 9.20: Recoveryereignis Unter einem Recoveryereignis versteht man jedes Ereignis, das zu einem teilweisen oder vollständigen Abbruch einer laufenden Transaktion führen oder Daten der DB korrumpieren kann. Auf der nächst feineren Ebene lassen sich Recoveryereignisse in Transaktions- und in Umgebungsrecoveryereignisse zerlegen.
9.3 Fehlertoleranz
621
Transaktionsrecoveryereignisse Ein Transaktionsrecoveryereignis lässt sich direkt einer bestimmten Auslösetransaktion zuordnen, wobei seine Auswirkungen zunächst einmal primär nur diese Transaktion betreffen. Die folgenden drei Fälle lassen sich unterscheiden: 1. Anwendungsbedingte Transaktionsrecoveryereignisse Unter diese Kategorie fallen Fehler in der Anwendungslogik, beispielsweise Prozeduraufruf mit falschen Parametern, aber auch (explizit) vom Benutzer verursachte Recoveryereignisse wie Fehleingaben, Erkennung eines Irrtums seitens des Anwenders mit anschließendem bewusst herbeigeführten, expliziten Abbruch der Transaktion. Es handelt sich also insgesamt um Fehler, die außerhalb des DBMS verursacht wurden. 2. Systembedingte Transaktionsrecoveryereignisse Unter diese Kategorie fallen Recoveryereignisse, die das DBMS zu erkennen hat, beispielsweise im Rahmen der Sicherstellung der operationalen Integrität. Typische Fehlerklassen sind Synchronisationskonflikte, Deadlocks oder vom System erkennbare Fehler in der Ausführung einer Transaktion (z. B. Zugriffsrechtverletzungen). 3. Kaskadierende Transaktionsrecoveryereignisse Kaskadierende Recoveryereignisse treten immer dann als Folge anderer Transaktionsrecoveryereignisse auf, wenn deren Ausführung (rekursiv) die Ausführung weiterer Recoveryaktionen nach sich zieht. Dies ist beispielsweise der Fall, wenn Wechselwirkungen zwischen Transaktionen oder zwischen von unterschiedlichen Transaktionen bearbeiteten Objekten existieren. In der Konsequenz wird aufgrund des Zurücksetzens einer Transaktion auch das Zurücksetzen anderer Transaktionen notwendig, weshalb man hier von einem fortgepflanzten Rollback spricht. Transaktionsrecoveryereignisse stellen isolierte und damit kontrollierbare Situationen dar, da das Betriebssystem, das DBMS, der Transaktionsmanager und die Transaktionsausführung in einem definierten Zustand verbleiben. Damit können sie ohne Beeinträchtigung der anderen DBMS-Aktivitäten singulär behandelt und behoben werden. Umgebungsrecoveryereignisse Von Umgebungsrecoveryereignissen spricht man, wenn an der Ausführung einer Transaktion direkt oder indirekt beteiligte Systemressourcen in eine Fehlersituation verwickelt werden. Dabei können Systemressourcen temporär (z. B. Rechnerabsturz) oder permanent (z. B. Plattendefekt) ausfallen oder von Verfälschungen betroffen sein (z. B. fehlerhafte Speicherchips). Transaktionssysteme gehen üblicherweise von einem vereinfachten Fehlermodell aus, das nur den Ausfall von Komponenten berücksichtigt. Umgebungsrecoveryereignisse lassen sich dementsprechend anhand ihrer Auswirkungen wie folgt klassifizieren20 : 1. Hauptspeicherrecoveryereignisse Der Hauptspeicherinhalt geht verloren, z. B. durch den Absturz des Rechners. Da im Hauptspeicher üblicherweise auch alle im Zusammenhang mit der Transaktionsverwaltung 20 Gerade bei Client/Server-Systemen bzw. verteilten DBMS müssten an sich noch Kommunikationsrecoveryereignisse betrachtet werden, die solche Probleme wie die Nichtverfügbarkeit von Verbindungen oder Rechnern in einem Netzwerk (Netzwerkfehler, Rechnerausfälle) abdecken. Da solche Systeme in diesem Buch nicht explizit diskutiert wurden, soll diese Klasse von Recoveryereignissen hier auch nicht weiter behandelt werden.
622
9 Transaktionsverarbeitung und Fehlertoleranz
notwendigen Informationen und Daten gehalten werden (Sperrtabelle, Liste noch laufender Transaktionen), werden auch diese i. d. R. verloren sein. 2. Sekundärspeicherrecoveryereignisse Der Sekundärspeicherinhalt geht verloren, z. B. durch den endgültigen Ausfall einer Platte beispielsweise infolge eines Headcrashes. Derartige Recoveryereignisse können mit einem Flächenbrand verglichen werden, bei dem als Erstes zunächst der Umfang des Schadens analysiert werden muss, wobei grundsätzlich in Bezug auf den Schadenumfang alles möglich ist. Eine Lokalität der Fehlerauswirkungen wird also häufig nicht gegeben sein. Insbesondere können auch die Arbeiten bereits erfolgreich beendeter Transaktionen betroffen sein.
9.3.2
Maßnahmen zur Fehlerbehandlung
Abstrakt gesehen ist ein DBMS auch nur ein Stück Anwendungssoftware21, welches auf einem Rechner läuft und dabei die vom Betriebssystem angebotenen Funktionen nutzt. Natürlich obliegt insbesondere auch die Hauptspeicherverwaltung dem Betriebssystem, weshalb dieses zunächst einmal bestimmt, welche Seiten wann aus dem Hauptspeicher ausgelagert und auf den Sekundärspeicher zurückgeschrieben werden. Die Kriterien, nach denen das Betriebssystem einen Kandidaten für die Seitenersetzung auswählt, müssen bezogen auf die Anforderungen aller Anwendungsprogramme möglichst neutral sein. Deshalb können sie sich nicht nach den Bedürfnissen von DBMS richten. 9.3.2.1
Strategien zum Einbringen modifizierter Daten
Aus der Sicht des DBMS ist deren Recoverykomponente für die A- und D-Eigenschaft des ACID-Kriteriums verantwortlich. Die Atomarität bedeutet, dass Arbeiten, die von einer Transaktion ausgeführt wurden, grundsätzlich noch so lange wieder (freiwillig oder gezwungenermaßen) rückgängig gemacht werden können, wie die Transaktion noch nicht endgültig beendet ist. Die Dauerhaftigkeit verlangt hingegen, dass mit dem Ende einer Transaktion die von dieser ausgeführten Arbeiten jeden nachfolgenden Fehlerfall überleben. Überträgt man diese Gegebenheiten auf das DBMS-Betriebssystem Szenario, so kann sich bei einem Transaktions- bzw. Hauptspeicherrecoveryereignis grundsätzlich die folgende Situation ergeben: Da das Betriebssystem alleinig für die Hauptspeicherverwaltung zuständig ist, kann die Situation auftreten, 1. dass Seiten mit modifizierten Datensätzen von zum Fehlerzeitpunkt noch aktiven Transaktionen bereits aus dem Hauptspeicher verdrängt worden waren oder 2. dass Seiten mit modifizierten Datensätzen von zum Fehlerzeitpunkt bereits abgeschlossenen Transaktionen sich noch im Hauptspeicher befinden, ohne zusätzlich auch auf den Sekundärspeicher zurückgeschrieben worden zu sein. 21 Ein DBMS wird gelegentlich auch der Systemsoftware zugeschlagen. Wir schließen uns dieser Meinung jedoch nicht an.
9.3 Fehlertoleranz
623
Im Fall 1 bedeutet dies, dass der Sekundärspeicher Datensätze enthält, die keine Gültigkeit erlangt haben, weshalb sie keinen konsistenten Zustand widerspiegeln. Um dieses Problem beheben zu können, muss ein so genanntes UNDO ausgeführt werden. Definition 9.21: UNDO Unter einem UNDO versteht man das Zurücksetzen eines aktuellen Zustandes eines Datums auf einen früheren, konsistenten Zustand. Dabei kann zurückgesetzt werden, indem entweder der (irgendwo festgehaltene) ehemalige Zustand direkt in die DB zurückgeschrieben wird oder indem die zwischenzeitlich auf dem Datum ausgeführten Operationen durch in der richtigen (also umgekehrten) Reihenfolge ausgeführten inversen Operationen rückgängig gemacht bzw. kompensiert werden. Der Fall 2 beschreibt genau das Gegenteil. Hier finden sich gültige Änderungen nicht auf dem Sekundärspeicher wieder, weshalb ein REDO auszuführen ist. Alle von abgeschlossenen Transaktionen durchgeführten Änderungen, die noch nicht auf den Sekundärspeicher zurückgeschrieben worden waren, müssen nachgezogen werden. Definition 9.22: REDO Unter einem REDO versteht man das Wiederherstellen des verloren gegangenen aktuellen und konsistenten Zustandes eines Datums. Dies kann erreicht werden, indem entweder der (noch woanders gesicherte) letzte Zustand direkt in die DB zurückgeschrieben wird oder indem ausgehend von einem alten konsistenten Zustand die danach auf dem Datum ausgeführten Operationen erneut ausgeführt werden. In Erweiterung unserer ursprünglichen Annahme stellen viele Betriebssysteme oft sehr wohl Befehle zur expliziten Kontrolle der einer Anwendung zugewiesenen Hauptspeicherseiten zur Verfügung. Damit kann eine unerwünschte Seitenersetzung verhindert oder das Zurückschreiben von Seiten auf den Sekundärspeicher explizit veranlasst werden. Dementsprechend mag der Leser vermuten, dass es am geschicktesten wäre, wenn ein DBMS • so lange keine von einer Transaktion T modifizierten Seiten zurückschreibt, wie T noch aktiv ist, • andererseits aber alle modifizierten Seiten direkt mit dem Ende von T auch wirklich auf den Sekundärspeicher zurückschreibt. Damit wäre theoretisch niemals ein REDO oder UNDO notwendig. Theoretisch ist dies auch korrekt; praktisch gibt es aber auch eine ganze Reihe von Gründen, die gegen eine solche Strategie sprechen. Diese Gründe sollen hier nicht im Detail diskutiert werden, da dazu ein tieferer Einstieg in die Interna eines DBMS notwendig wäre. Die wesentlichsten Gründe sollen aber kurz vorgestellt werden: 1. Würden während der Laufzeit einer Transaktion keine Seiten zurückgeschrieben werden, müssten alle Seiten zum Zeitpunkt des Transaktionsendes gesichert werden. Dies wäre ein Flaschenhals, da u. U. eine Vielzahl von Seiten gleichzeitig zurückzuschreiben wären. Zusätzlich würde dies zu einer Verlängerung der Laufzeit einer Transaktion führen, da diese offiziell erst enden darf, wenn alle modifizierten Seiten auch sicher auf dem Sekundärspeicher abgelegt wurden.
624
9 Transaktionsverarbeitung und Fehlertoleranz
2. Das Zurückschreiben von modifizierten Seiten ist aus der Sicht des Betriebssystems natürlich keine atomare Einheit, so dass nicht auszuschließen ist, dass das System mitten im Rückschreibevorgang abstürzt. Eine solche Situation lässt sich nur retten, wenn man trotzdem entsprechend vorher UNDO- oder je nach Strategie REDO-Informationen abgelegt hat. Es kann also nicht wirklich auf das Speichern solcher Informationen verzichtet werden. REDO-Informationen werden zudem auch für Sekundärspeicherrecoveryereignisse benötigt, so dass sie sowieso anzulegen sind. 3. Sekundärspeicherblöcke (Sektoren) werden in Seiten des Hauptspeichers gelesen, wobei der Behälter Seite unter normalen Umständen nicht einen, sondern viele Datensätze (Zeile) enthalten wird. Würde nun auf der Ebene von Datensätzen synchronisiert, könnte man nicht verhindern, dass mit dem Zurückschreiben einer Seite auch Änderungen von anderen, noch nicht beendeten Transaktionen auf den Sekundärspeicher gelangen. Selbst in dem Fall, dass noch keine Daten auf den Sekundärspeicher zurückgeschrieben wurden, ist UNDO-Information notwendig, da eine Seite, die parallel von einer anderen Transaktion modifiziert wurde, von den Änderungen einer zurückgesetzten Transaktion bereinigt werden müsste. Der in Bezug auf mögliche Recoverymaßnahmen entscheidende Zeitpunkt einer Transaktion ist offensichtlich ihr Ende. Wurde vorher etwas auf den Sekundärspeicher zurückgeschrieben, muss ein UNDO möglich sein. Wurden bis zu diesem Zeitpunkt nicht alle Modifikation zurückgeschrieben, sind Vorkehrungen für ein REDO notwendig. Daraus lassen sich insgesamt zwei Fälle in Bezug auf das UNDO und zwei Fälle in Bezug auf das REDO identifizieren. Erstere laufen in der Literatur unter dem Stichwort steal, Letztere unter dem Stichwort force. • steal: Von einer Transaktion modifizierte Seiten können grundsätzlich jederzeit, insbesondere auch vor dem Ende einer Transaktion auf den Sekundärspeicher zurückgeschrieben werden. Es ist Vorsorge für ein UNDO zu treffen. • ¬steal: Von einer Transaktion modifizierte Seiten dürfen grundsätzlich nicht vor dem Ende einer Transaktion auf den Sekundärspeicher zurückgeschrieben werden. Eine Vorsorge für ein UNDO ist nicht notwendig. • force: Von einer Transaktion modifizierte Seiten müssen grundsätzlich spätestens bis zum Ende der Transaktion auf den Sekundärspeicher zurückgeschrieben werden. Eine Vorsorge für ein REDO ist nicht notwendig. • ¬force: Von einer Transaktion modifizierte Seiten können grundsätzlich zu einem beliebigen Zeitpunkt, also insbesondere auch erst nach dem Ende einer Transaktion auf den Sekundärspeicher zurückgeschrieben werden. Es ist Vorsorge für ein REDO zu treffen. Kombiniert man die Optionen der beiden Klassen miteinander, ergeben sich die vier in Tabelle 9.4 zusammengefassten Möglichkeiten. Man beachte allerdings, dass die in der Tabelle und davor gemachten Aussagen etwas zu relativieren sind. In der reinen Form treffen sie nur zu,
9.3 Fehlertoleranz
625
steal ¬ steal
force
¬ force
kein REDO
REDO
UNDO
UNDO
kein REDO
REDO
kein UNDO
kein UNDO
Tabelle 9.4: Strategien zum Zurückschreiben modifizierter Daten
wenn das Zurückschreiben von Daten/Seiten als atomare Operation angesehen werden kann, die sicher fehlerfrei abläuft. Auch können aus den Aussagen der Tabelle keine grundsätzlichen Rückschlüsse auf die Notwendigkeit von REDO/UNDO-Daten gezogen werden, da diese gegebenenfalls für andere Recoverymaßnahmen benötigt werden können. 9.3.2.2
Die Logdatei
Um im Fall von Recoveryereignissen eine ordnungsgemäße Recovery durchführen zu können, benötigt das DBMS Informationen, aus denen der letzte konsistente Zustand von Objekten ermittelt werden kann. Diesbezügliche Informationen müssen jeden Fehler überleben, der ein Rollback von T notwendig machen könnte. Die mit Abstand am weitesten verbreitete Methode zur Sicherung solcher Informationen ist die so genannte Logdatei. Definition 9.23: Logdatei Eine Logdatei ist vereinfacht dargestellt eine sequenzielle Datei, in der jeder Transaktionsbeginn, jedes Transaktionsende und jede (atomare) Änderungsoperation auf der DB in der richtigen, d. h. in der durch die Realität vorgegebenen Reihenfolge protokolliert wird. Ein REDO bzw. UNDO stützt sich nun auf eine solche Logdatei ab. Grundsätzlich kann es entweder auf der Basis einer logischen oder einer physischen Protokollierung durchgeführt werden. Definition 9.24: Logische Protokollierung Von einer logischen Protokollierung spricht man immer dann, wenn der Logdateieintrag dokumentiert, welche Änderungsoperation mit welchen Operanden auf welcher Spalte durchgeführt wurde. Für einen vollständigen Logdateieintrag22 muss daher mindestens die verantwortliche Transaktion, die betroffene Zeile/Spalte, die ausgeführte Operation und, falls es sich um eine binäre Operation handelt, der zweite Operand festgehalten werden. Um ein UNDO ausführen zu können, muss zudem die zur durchgeführten Operation inverse Operation angegeben werden23 . 22 Darunter ist ein Eintrag zu verstehen, der sowohl ein UNDO als auch ein REDO zulässt. Je nach gewählter Rückschreibestrategie für modifizierte Daten kann der das UNDO betreffende Eintrag entfallen. Wie bereits erwähnt braucht man den REDO-Eintrag auf jeden Fall für die Sekundärspeicherrecovery. 23 Sollten grundsätzlich nur die bekannten Standardoperationen zum Einsatz kommen, muss man die zu einer Operation inverse Operation nicht in jedem Logdateisatz erneut ablegen, da dadurch eine sehr hohe Redundanz erzeugt würde. Es würde reichen, die inversen Operationen in einer allgemein zugreifbaren Tabelle verfügbar zu machen.
626
9 Transaktionsverarbeitung und Fehlertoleranz
Ute:
Willy:
Logdateieintrag1
Wert
logische Protokollierung oder beide physische Protokollierung BOT T1 READ Auto(LA).preis Auto(LA).preis =
(T1 , BOT) (= 100,–)
Auto(LA).preis ∗1.1 BOT T2 READ Hotel(Fun).freieZimmer Hotel(Fun).freieZimmer :=
(T2 , BOT) (= 3)
Hotel(Fun).freieZimmer −1 WRITE Auto(LA).preis
(= 110,–)
(T1 , Auto(LA).preis, ∗, 1.1, /) (T1 , Auto(LA).preis, 100 , 110 )
READ Flug(123).freiePlätze WRITE Hotel(Fun).freieZimmer
(= 12) (= 2)
READ Auto(SF).preis Flug(123).freiePlätze :=
(= 100)
(T2 , Hotel(Fun).freieZimmer, −, 1, +) (T2 , Hotel(Fun).freieZimmer, 3 , 2 )
Flug(123).freiePlätze−2 WRITE Flug(123).freiePlätze
(= 10)
(T1 , Flug(123).freiePlätze, −, 2, +) (T1 , Flug(123).freiePlätze, 12, 10)
Auto(SF).preis := Auto(SF).preis + 20 WRITE Auto(SF).preis
(= 120,–)
COMMIT T2 READ Hotel(Fun).freieZimmer Hotel(Fun).freieZimmer := Hotel(Fun).freieZimmer − 1 WRITE Hotel(Fun).freieZimmer COMMIT T1 1
(T2 , Auto(SF).preis, +, 20, −) (T2 , Auto(SF).preis, 100, 120) (T2 , COMMIT)
(= 2)
(= 1)
(T1 , Hotel(Fun).freieZimmer, −, 1, +) (T1 , Hotel(Fun).freieZimmer, 2, 1) (T1 , COMMIT)
: rechte Seite (normale Schrift): Aufbau Datensatz:
logische Protokollierung verantwortliche Transaktion, betroffene Zeile/Spalte, Operation, zweiter Operand, inverse Operation
rechte Seite (kursive Schrift): Aufbau Datensatz:
physische Protokollierung verantwortliche Transaktion, betroffene Zeile/Spalte, Before-Image, After-Image
Zeilen ohne Alternativen:
gültig für beide Protokollierungsarten
Tabelle 9.5: Physische und logische Logdateieinträge für ein Reisebüroszenario
9.3 Fehlertoleranz
627
Definition 9.25: Physische Protokollierung, Before- und After-Image Bei einer physischen Protokollierung wird in der Logdatei notiert, welches der Wert einer Spalte vor seiner Änderung war und welches der Wert nach seiner Änderung ist. Ersterer wird Before-Image, Letzterer After-Image genannt. Für einen vollständigen Logdateieintrag muss daher mindestens die verantwortliche Transaktion, die betroffene Zeile/Spalte, das Before- und das After-Image abgelegt werden. Beispiel 9.11: Logischer und physischer Logdateieintrag Gegeben seien die in Tabelle 9.5 angegebenen Operationen eines Reisebüroszenarios, wobei die Sperroperationen weggelassen wurden. Das Before-Image muss grundsätzlich vor dem Übertragen der eigentlichen Modifikation in die materialisierte Datenbasis dauerhaft abgelegt sein, das After-Image spätestens mit dem Ende der zu Grunde liegenden Transaktion. Da damit die Logdateieinträge vor den eigentlichen Änderungen in der DB persistent gemacht werden, spricht man auch vom WAL-Prinzip (W rite Ahead Log). Das WAL-Prinzip stellt auch sicher, dass alle eine Transaktion T betreffenden Logdateieinträge vor deren Ende in die Logdatei geschrieben werden. Im Hauptspeicher werden die Logdateieinträge i. d. R. in einem eigenen Logpuffer verwaltet. Dieser ist in moderneren DBMS häufig als Ringpuffer ausgelegt (siehe Abbildung 9.12).
Logdateieinträge
...
Nr. 2
Nr. z
Nr. z+1
...
Logdatei-Ringpuffer
...
Nr. n-1
Nr. n
Nr. n+1
...
sichern
Logdatei
Logarchiv
Abb. 9.12: Arbeitsweise eines Logdatei-Ringpuffer
628
9 Transaktionsverarbeitung und Fehlertoleranz
Während an einem Ende ausschließlich die neuen Logdateieinträge eingefügt werden, werden sie am anderen Ende kontinuierlich in eine auf dem Sekundärspeicher liegende Logdatei geschrieben. Daneben werden sie oft noch redundant in einem so genannten Logarchiv abgelegt. Während die Logdatei nicht zuletzt aus Platzgründen lediglich mindestens so aktuell sein muss, dass ein Systemzusammenbruch mit Hauptspeicherverlust behoben werden kann, hält das Logarchiv die zur Reparatur beliebig schwerer Recoveryereignisse notwendige umfangreiche Menge an Recoverydaten vor. Es wird also i. d. R. wesentlich mehr und ältere Recoverydaten enthalten als die Logdatei. Wie bereits erwähnt darf eine Transaktion frühestens dann beendet werden, wenn alle sie betreffenden Logdateieinträge sicher in die Logdatei überführt wurden. Da die Logdatei sequenziell organisiert ist und die Daten aller Transaktionen enthält, müssen damit alle vor der letzten Aktion der beendigungswilligen Transaktion auf der DB vorgenommenen Aktionen in die Logdatei übertragen worden sein. Die relative Reihenfolge der Einträge im Logpuffer ist wesentlich und darf daher zu keinem Zeitpunkt, auch nicht beim übertragen in die Logdatei, verändert werden. Deshalb ist es nicht möglich, dass beispielsweise zunächst nur die Einträge in die Logdatei übertragen werden, die die endende Transaktion betreffen. Man beachte, dass das Sichern eines modifizierten Datums einer DB wegen der seitenorientierten Hauptspeicherverwaltung das Zurückschreiben der gesamten das Datum enthaltenden Seite auf den Sekundärspeicher verlangt. Demnach können bei einer größeren Änderungstransaktion sehr viele Seiten auf den Sekundärspeicher zu übertragen sein. Logdateieinträge sind dagegen vergleichsweise klein, da sie nur die bereits diskutierten Informationen enthalten. Deshalb werden vergleichsweise viele Logdateieinträge auf eine Seite passen. 9.3.2.3
Rollback
Von einem Rollback spricht man, wenn das DBMS im laufenden Betrieb aufgrund eines Transaktionsrecoveryereignisses eine bestimmte Transaktion T zurücksetzen muss. Damit müssen alle von T in der DB bewirkten Änderungen so rückgängig gemacht werden, als ob T nie existent gewesen wäre. Da vom Zurückrollen i. d. R. keine parallelen Transaktionen betroffen sind24 , kann das DBMS den Rücksetzprozess parallel zur Abarbeitung anderer Transaktionen vornehmen. Wird eine ¬ steal-Politik gefahren und auf der Ebene von Seiten synchronisiert, so kann ein Rollback einer Transaktion T durch einfaches Freigeben der betroffenen Hauptspeicherseiten vorgenommen werden. Schwieriger ist der steal-Fall. Da bereits Daten auf den Sekundärspeicher zurückgeschrieben sein können, müssen diese Änderungen wieder rückgängig gemacht werden. Dazu wird die Logdatei solange von hinten nach vorne gelesen, bis die Beginnmarke von T gefunden wird. Auf dem Weg dorthin wird für jedes Before-Image mit der Transaktionsidentifikation von T der alte Objektwert in die DB zurückgeschrieben. 9.3.2.4
Systemneustart
Systemneustart (system restart) wird notwendig, wenn der Rechner und damit auch die Datenbankanwendung aus irgendeinem Grund abgestürzt ist. Ein Absturz bedingt im Normalfall 24 Mit Ausnahme des fortgepflanzten Rollbacks, das aber wegen der bereits diskutierten Gründe bei vermutlich allen kommerziellen DBMS ausgeschlossen wird.
9.3 Fehlertoleranz
629
T1 T2 T3 T4 t crash Abb. 9.13: Systemzusammenbruch (crash)
den Verlust des gesamten Hauptspeicherinhaltes einschließlich aller Puffer und Verwaltungsinformationen, zu denen beispielsweise auch die Listen der aktiven Transaktionen und der vergebenen Sperren gehören. Da zum Zeitpunkt des Systemzusammenbruchs normalerweise Transaktionen aktiv gewesen sein werden, kann sich die DB in einem inkonsistenten Zustand befinden. Beim Neustart des Systems muss sie daher zunächst wieder in einen konsistenten Zustand gebracht werden. In dieser Situation kann man im Prinzip zunächst wie im Fall des Rollback vorgehen, indem die Änderungen der zum Absturzzeitpunkt noch nicht beendeten Transaktionen rückgängig gemacht werden. Beispielsweise müssten im Fall der Situation von Abbildung 9.13 die bereits von T2 und T4 durchgeführten Änderungen zurückgenommen werden. Um die Transaktionen ermitteln zu können, die zurückgesetzt werden müssen, wird die Logdatei rückwärts gelesen. Für jede BOT-Marke wird überprüft, ob für diese Transaktion auch eine entsprechende EOT-Marke in der Logdatei vorhanden ist. Ist dem nicht so, war die Transaktion offiziell noch nicht beendet, so dass deren Änderungen rückgängig gemacht werden müssen. Der Nachteil dieser Vorgehensweise ist, dass nicht ermittelt werden kann, wie weit die Logdatei rückwärts zu lesen ist. Theoretisch könnte eine Transaktion über einen sehr langen Zeitraum keine Einträge in die Logdatei geschrieben haben, weshalb dann beim Rückwärtslesen auch zunächst keine „Lebenszeichen“ dieser Transaktion gefunden werden. 9.3.2.5
Checkpoints
Um das Problem des Terminierens des Rückwärtslesens lösen zu können, bedient man sich häufig des Konzeptes der Checkpoints. Definition 9.26: Checkpoint Checkpoints sind dauerhaft gemachte Verwaltungsinformationen, die den aktuellen Zustand des Transaktionssystems beschreiben. Sie werden in regelmäßigen Abständen in die Logdatei geschrieben. Im Fall eines Systemzusammenbruchs dienen sie als Ausgangspunkt für die Recoveryaktion.
630
9 Transaktionsverarbeitung und Fehlertoleranz
Durch einen Checkpoint wird beispielsweise festgehalten, welche Transaktionen zum Zeitpunkt des Schreibens des Checkpoints aktiv waren, d. h. er enthält eine Auflistung der Transaktionsidentifikatoren (TID) der noch aktiven Transaktionen. Das DBMS muss bei einem Neustart zunächst bis zum jüngsten Checkpoint rückwärts lesen. Ab jetzt ist bekannt, welche Transaktionen zurückgesetzt werden müssen, nämlich alle die, die im Checkpoint aufgeführt oder erst danach gestartet wurden und für die bis zum Checkpoint keine Endemarke in der Logdatei gefunden wurde. Für diese Transaktionen gilt, dass die Logdatei so lange rückwärts gelesen werden muss, bis die Beginnmarke jeder noch nicht abgeschlossenen Transaktion gefunden wurde, wobei jeweils die entsprechenden UNDO-Operationen auszuführen sind25 . Logisch gesehen muss die Logdatei also von hinten nach vorne abgearbeitet werden. Um ein effizientes UNDO ausführen zu können, werden beim Rückwärtslesen immer gleich alle Aktionen zurückgesetzt, die zu Transaktionen gehören, von denen man bisher noch keine Endemarke gefunden hat. So erspart man sich ein mehrfaches Lesen der Logdatei. Im Fall einer Force-Politik wäre nach erfolgreicher Ausführung dieser Maßnahmen die DB wieder in einem konsistenten Zustand. Deutlich schwieriger gestaltet sich das Recovery bei einer ¬ Force-Strategie. Hier ist bei einem Systemabsturz nicht klar, welche von bereits abgeschlossenen Transaktionen durchgeführten Änderungen sich auch wirklich bereits in der DB wiederfinden. Noch nicht „materialisierte“ Änderungen26 müssen noch einmal in die DB eingebracht werden. Ähnlich wie beim UNDO muss auch hier auf entsprechende Daten der Logdatei zurückgegriffen werden, in diesem Fall aber auf die After-Images. Das angewendete Verfahren muss logisch so arbeiten, als würde die Logdatei von vorne nach hinten abgearbeitet. Das Problem ist jedoch, ein sicheres Verfahren zu finden, über das festgestellt werden kann, welche Transaktionen zu wiederholen sind, da grundsätzlich jede bereits abgeschlossene Transaktion noch betroffen sein kann. Die einfachste Möglichkeit ist, mit dem Anlegen eines Checkpoints das Hinausschreiben aller bis dahin durch abgeschlossene Transaktionen veränderten Daten zu erzwingen. In diesem Fall müssen Transaktionen, die vor dem Checkpoint beendet wurden, nicht wiederholt werden, wohl aber die, die danach beendet wurden. Man beachte, dass sowohl das UNDO als auch das REDO immun gegenüber bereits teilweise (noch nicht) eingebrachten Änderungen sind. War bei einem UNDO/REDO der zurückzusetzende/wiederherzustellende Wert noch nicht/bereits in die DB eingebracht, so ist die UNDO/REDO-Operation wegen ihrer Kontextunabhängigkeit höchstens überflüssig, erzeugt aber keine inkonsistente DB. 9.3.2.6
Varianten von Checkpoints
Wesentlichen Einfluss auf den Recoveryaufwand hat die gewählte Checkpointstrategie. Man unterscheidet transaktions-, aktionskonsistente und unscharfe Checkpoints. Checkpoint mit Stillstand des Systems (transaktionskonsistenter Checkpoint) Diese Checkpointart verlangt, dass zum Zeitpunkt des Schreibens des Checkpoints keine Transaktion aktiv sein darf. Daher müssen immer erst alle gerade aktiven Transaktionen abgearbeitet werden, bevor der Checkpoint geschrieben werden darf. In Abbildung 9.14 wurde zum 25 Was
im Konkreten heißt, dass über die Before-Images der alte Wert wieder installiert wird. versteht man Änderungen, die bereits auf den Sekundärspeicher übertragen und damit dauerhaft gemacht wurden. 26 Hierunter
9.3 Fehlertoleranz
631
T1 T2 T3 T4 t Checkpoint
crash
Abb. 9.14: Checkpoint mit Stillstand
Beispiel zunächst auf das Ende der Transaktionen T1 und T3 gewartet, bevor der Checkpoint geschrieben wurde. Während dieser Wartezeit dürfen keine neuen Transaktionen begonnen werden. Dies ist erst wieder nach erfolgreicher Beendigung des Checkpointvorganges erlaubt. Diese Art des Checkpoints ist aus der Sicht der Recovery die Unkomplizierteste, da sie einen logisch konsistenten Zustand der DB beschreibt27 . Rollback über den Checkpoint hinaus ist deshalb nie notwendig. Eine minimal gehaltene Logdatei braucht nicht weiter als bis zum jüngsten Checkpoint reichen. Der große Nachteil dieser Variante ist, dass das System so lange zum Stillstand gezwungen wird, bis auch die letzte Transaktion beendet ist und die durch sie geänderten Daten auf persistenten Speicher zurückgeschrieben wurden. Dies kann zu inakzeptablen Wartezeiten führen. Checkpoint im laufenden Betrieb (aktionskonsistenter Checkpoint) Bei dieser Variante wird jeweils nach fest vorgegebenen Zeitintervallen ein Checkpoint geschrieben, und zwar unabhängig von und parallel zu den anderen Aktivitäten des Systems. Unterstellt wird lediglich, dass die in der Logdatei notierten Operationen atomar sind, d. h. aus der Sicht des Verfahrens muss jede dieser Aktionen vollständig abgeschlossen sein; die DB befindet sich in einem speicherkonsistenten Zustand, bei dem alle Zeiger, Verwaltungsinformationen usw. korrekt sind. Nach dem Abschluss aller gerade laufenden Operationen schreibt das System den Checkpoint und nimmt dann direkt wieder die weitere Verarbeitung der Transaktionen auf. In Abbildung 9.15 sind die Transaktionen T3 und T4 zum Zeitpunkt des Schreibens des Checkpoints noch aktiv, was aber ohne Rückwirkung auf das Checkpointverfahren ist. Da lediglich Operationen, nicht aber ganze Transaktionen beendet sein müssen, vermeidet diese Art des Checkpoints merkbare Stillstandzeiten oder Unterauslastung des Systems. Unter der Voraussetzung, dass mit dem Schreiben eines Checkpoints auch alle Änderungen bereits abgeschlossener Transaktionen zurückgeschrieben werden, ist ein REDO über den jüngsten Checkpoint hinaus nicht notwendig. Dies gilt allerdings nicht für das UNDO, bei dem alle 27 Hier wird unterstellt, dass Abschluss aller Transaktionen auch bedeutet, dass alle von diesen geänderten Daten auf den Sekundärspeicher „hinausgezwungen“ wurden.
632
9 Transaktionsverarbeitung und Fehlertoleranz
T1 T2 T3 T4 t Checkpoint crash Abb. 9.15: Checkpoint ohne Stillstand
zum Absturzzeitpunkt noch nicht abgeschlossenen Transaktionen vollständig zurückgesetzt werden müssen. Unscharfer Checkpoint Auch wenn der aktionsorientierte Checkpoint nicht die Arbeit auf der DB unterbricht, so verlangt er doch das Zurückschreiben der relevanten Daten auf den Sekundärspeicher. Da dies das Zurückschreiben einer großen Zahl von Seiten erfordern kann, kann auch in diesem Fall ein künstlicher Flaschenhals erzeugt werden, der die normale Arbeit auf der DB stark behindern kann. Effizienter wäre es deshalb, wenn die Daten kontinuierlich gesichert werden könnten. Das Verfahren der unscharfen Checkpoints setzt voraus, dass die Datensätze der Logdatei zusätzlich über einen monoton aufsteigenden eindeutigen Identifizierer total, d. h. sequenziell durchnummeriert werden. Wenn jetzt ein Checkpoint gesetzt werden soll, wird nur noch in der Logdatei festgehalten, welche Seiten noch nicht auf den Sekundärspeicher zurückgeschrieben wurden, aber Daten von bereits beendeten Transaktionen enthalten. Die Liste dieser „schmutzigen“ Seiten wird zusammen mit der übrigen Checkpointinformation in die Logdatei geschrieben. Für diese Seiten muss über den eindeutigen Identifizierer 1. der älteste Logdateieintrag in Bezug auf die zum Checkpointzeitpunkt noch aktiven Transaktionen (IDakt ) und 2. der älteste Logdateieintrag in Bezug auf die zum Checkpointzeitpunkt bereits abgeschlossenen Transaktionen gefunden werden (IDcom )28 . Im Fall eines Systemabsturzes muss dann in der Logdatei bis zum jeweils für das UNDO bzw. REDO relevanten Identifizierer zurückgegangen werden, um die ab diesem Zeitpunkt aufgezeichneten UNDO/REDO-Informationen in die DB einzubringen. Natürlich muss dies nur für solche Aktionen getan werden, die auf schmutzigen Seiten operiert haben. 28 Wie
diese beiden Identifizierer effizient bestimmt werden können, soll hier nicht weiter diskutiert werden.
9.3 Fehlertoleranz
633
Das Verfahren arbeitet relativ effizient, wenn sichergestellt ist, dass es keine so genannten Hot spot-Daten29 gibt, die selten oder nie auf die Platte zurückgeschrieben werden. Deshalb sollte sichergestellt sein, dass auch solche Daten in angemessenen Zeitintervallen auf den Sekundärspeicher gezwungen werden. Insgesamt ist das Schreiben eines Checkpoints mit einem gewissen Aufwand verbunden, der durchaus auch spürbare Auswirkungen auf die Performanz des DBS haben kann. Deshalb ist die Frage, in welchen Abständen denn ein Checkpoint zu setzen ist, nicht einfach zu beantworten. Wird er häufig gesetzt, wird der laufende Betrieb gestört. Wird er selten gesetzt, ist der Aufwand im Fall einer Recoveryaktion entsprechend groß. 9.3.2.7
Sicherungspunkte
Insbesondere im Zusammenhang mit so genannten langen Transaktionen (long lived transaction), die statt nur Sekunden schon einmal Stunden, Tage oder sogar Wochen dauern können, wurden so genannte Sicherungspunkte (savepoints) eingeführt. Sie bieten dem Anwendungsprogrammierer die Möglichkeit, Rücksetzpunkte innerhalb einer Transaktion festzulegen, 1. auf die dann gezielt zurückgesetzt werden kann (partielles Rollback (partial rollback)) oder 2. auf die nach einem Recoveryereignis wieder aufgesetzt werden kann. Zu diesem Zweck wird während des Ablaufs einer Transaktion der aktuelle Zustand der Transaktion gesichert. Die Sicherung kann im Hauptspeicher (nur Abdeckung von Fall 1. von oben) oder auf Sekundärspeicher erfolgen (Abdeckung beider Fälle). Die Konstruktion eines Sicherungspunktes ist analog zur Durchführung eines Commit, wobei jedoch die Transaktion nicht terminiert wird und außerdem zusätzliche Informationen (z. B. über gesetzte Sperren) aufgezeichnet werden. Im weiteren Ablauf der Transaktion besteht dann die Möglichkeit, die Transaktion auf einen bestimmten Sicherungspunkt zurückzusetzen und von dort aus die Verarbeitung fortzusetzen. Um eine Fortsetzung des Anwendungsprogramms zu ermöglichen, müssen gegebenenfalls weitere Informationen aufgezeichnet werden, z. B. der aktuelle Programmzustand, Fensterinhalte usw. Dies ist jedoch nicht Aufgabe der Transaktionsverwaltung, da diese Daten anwendungsabhängig sind. Abbildung 9.16 demonstriert in seiner oberen Hälfte die konventionelle Vorgehensweise. Die linke Seite zeigt eine erfolgreich und damit vollständig durchgeführte Transaktion, während die rechte Seite das Vorgehen im Fall eines Fehlers bzw. Rollbacks zeigt, bei dem die Transaktion vollständig zurückgesetzt wird. Als Konsequenz zieht die gescheiterte Hotelbuchung auch eine Stornierung des Fluges nach sich. Als negativer Nebeneffekt kann es passieren, dass ein erneutes Buchen des Fluges scheitert, da eine andere, parallele Transaktion mit ihrer Buchung den letzten Platz reserviert hat. Die untere Hälfte zeigt das Vorgehen, falls Sicherungspunkte eingesetzt werden. Die gescheiterte Hotelbuchung tangiert die Flugbuchung nicht, so dass diese autonom behandelt werden kann. Im Fall des Beispiels endet die Transaktion nach Buchung eines neuen Hotels erfolgreich. 29 Das
sind Daten, auf die deutlich überproportional zugegriffen wird.
634
9 Transaktionsverarbeitung und Fehlertoleranz
Erfolgreiche Transaktion
Rollback
BOT T1 READ Flug(123).freiePlätze Flug(123).freiePlätze := Flug(123).freiePlätze – 2
BOT T1 READ Flug(123).freiePlätze Flug(123).freiePlätze := Flug(123).freiePlätze – 2
WRITE Flug(123).freiePlätze READ Hotel(Fun).freieZimmer Hotel(Fun).freieZimmer := Hotel(Fun).freieZimmer –1
WRITE Flug(123).freiePlätze READ Hotel(Fun).freieZimmer Hotel(Fun).freieZimmer := Hotel(Fun).freieZimmer –1
WRITE Hotel(Fun).freieZimmer COMMIT T1
WRITE Hotel(Fun).freieZimmer ROLLBACK
Rollback auf Sicherungspunkt BOT T1 READ Flug(123).freiePlätze Flug(123).freiePlätze := Flug(123).freiePlätze – 2 WRITE Flug(123).freiePlätze SAVE READ Hotel(Surprise).freieZimmer Hotel(Surprise).freieZimmer := Hotel(Surprise).freieZimmer –1 WRITE Hotel(Surprise).freieZimmer ROLLBACK
READ Hotel(Fun).freieZimmer Hotel(Fun).freieZimmer := Hotel(Fun).freieZimmer –1 WRITE Hotel(Fun).freieZimmer COMMIT T1
Abb. 9.16: Erfolgreiche und zurückgesetzte Transaktion
Der SQL-92-Standard kennt noch keine Sicherungspunkte. Ab SQL:1999 werden aber neben einem expliziten Befehl zum Starten einer Transaktion auch Befehle zum Einrichten und Entfernen von Sicherungspunkten sowie zum Rücksetzen auf Sicherungspunkte (ROLLBACK TO SAVEPOINT) unterstützt. Auch verkettete Transaktionen (chained transactions) werden jetzt unterstützt (über den CHAIN-Befehl). 9.3.2.8
Rekonstruktion
Im Fall von Sekundärspeicher-Recoveryereignissen sind Teile der persistenten DB, beispielsweise aufgrund eines Plattenproblems, nicht mehr lesbar. In solchen Fällen muss aus alten Sicherungsbeständen der korrekte Datenbankzustand rekonstruiert werden, wobei wie bisher auch exakt alle Änderungen von zum Fehlerzeitpunkt bereits beendeten Transaktionen in dem
9.3 Fehlertoleranz
635
rekonstruierten Datenbankzustand enthalten sein müssen. Dazu nutzt die Recovery die Rekonstruktion, indem sie auf einer alten Kopie der DB aufsetzt, oft Dump genannt. Definition 9.27: Dump Unter einem Dump versteht man eine Sicherungskopie der kompletten DB auf einem nichtflüchtigen Medium. Dumps müssen von Zeit zu Zeit angelegt und möglichst sicher und an unterschiedlichen Orten verwahrt werden. Insbesondere sollte die Sicherung nicht auf demselben Medium gehalten werden wie die originale DB. Üblicherweise werden für Dumps Bandlaufwerke verwendet, was impliziert, dass es sich um eine sehr lang andauernde Operation handelt, da die für den Dump benötigte Laufzeit wegen der vollständigen Sicherung des kompletten Datenbestandes erheblich sein kann. Grundsätzlich hat man es bei Dumps mit denselben Problemen zu tun wie bei Checkpoints, d. h. man kann analog zwischen transaktions-, aktionskonsistenten und unscharfen Dumps unterscheiden. Damit sind auch die mit der jeweiligen Variante verbundenen Probleme und Problemlösungen grundsätzlich identisch, weshalb sie hier nicht erneut diskutiert werden sollen. Für die weitere Diskussion wollen wir unterstellen, dass transaktionskonsistente Dumps angelegt werden. Um von einem Dump ausgehend einen korrekten Datenbankzustand erreichen zu können, ist bei einem transaktionskonsistenten Dump lediglich ein REDO, aber kein UNDO notwendig, d. h. es müssen alle seit der letzten „DumpZiehung“ abgeschlossenen Transaktionen wiederholt werden. Da die Logdatei im Normalfall nicht genügend „alte“ Informationen enthalten wird, wird man mit dem Logarchiv arbeiten müssen. Die Vorgehensweise entspricht der beim Checkpointing bereits diskutierten REDOStrategie. Im Widerspruch zur Anforderung der Dauerhaftigkeit werden Dumps gelegentlich auch dazu verwendet, die DB in einen alten konsistenten Zustand zurückzuversetzen. Dies kann insbesondere dann sinnvoll sein, wenn ein fehlerhaft arbeitendes Anwendungsprogramm auf der DB gearbeitet hat und dessen Inhalt teilweise zerstört oder inkonsistent gemacht hat. Viele DBMS erlauben es, einen Zeitpunkt anzugeben, bis zu dem zurückgesetzt werden kann. Allerdings sind dann natürlich auch die Arbeiten der danach beendeten korrekten Transaktionen verloren. 9.3.2.9
Kompensation
Bisher waren wir (implizit) davon ausgegangen, dass Transaktionen sehr kurz sind (maximal im Sekundenbereich). Nun gibt es aber auch eine Reihe von Anwendungen, die über einen langen Zeitraum (Stunden oder Tage) auf der DB arbeiten möchten. Dazu gehören beispielsweise Transaktionen, die statistische Daten liefern oder die Daten einer DB komprimiert wiedergeben, z. B. Summe der Guthaben auf allen Konten einer Bank. Da solche Transaktionen nicht nur sehr lange auf den Daten arbeiten, sondern zudem möglicherweise einen großen Datenbestand anpacken, können sie die Performanz negativ beeinflussen. Parallele kurze Transaktionen können plötzlich auch zu langen Transaktionen mutieren, da sie auf Daten warten müssen, die von einer langen Transaktion gesperrt sind. Bei langen Transaktionen steigt auch das Deadlock-Risiko gewaltig (nach Jim Gray mit der vierten Potenz der Transaktionsgröße30). Generell lassen sich die mit langen Transaktionen 30 siehe
[GHOK81].
636
9 Transaktionsverarbeitung und Fehlertoleranz
verbundenen Probleme nicht so ohne weiteres lösen. Auch z. B. die Verwendung optimistischer Verfahren bringt keine Lösung, da auch hier die Wahrscheinlichkeit eines Konfliktes zu anderen Transaktionen mit der Länge der Transaktion zunehmen muss. Damit steigt auch hier das Rücksetzrisiko. Wenn es also schon keine generelle Lösung gibt, so kann wenigstens versucht werden, das Problem zu lindern. In einigen Anwendungsumgebungen ist das dadurch möglich, dass man das Prinzip, dass die (lange) Transaktion die Einheit der Recovery ist, also entweder vollständig ausgeführt wird oder gar nicht, aufgibt. Stattdessen wird die Transaktion in eine Reihe von untergeordneten Transaktionen zerlegt, so genannte Subtransaktionen, die jeweils nur abgeschlossene Teilaspekte des Gesamtproblems lösen. Subtransaktionen dieser Art werden wie eigenständige Transaktionen behandelt und können deshalb die von ihnen gesperrten Daten jeweils mit ihrem Ende sofort allgemein freigeben. Damit stehen die genutzten Daten bereits frühzeitig parallelen Transaktionen wieder zur Verfügung. Diesem sicherlich erheblichen Vorteil steht allerdings auch ein schwerwiegender Nachteil gegenüber. Die Gesamtaufgabe stellte eine logisch zusammengehörige Folge von Operationen dar, weshalb sie einer (langen) Transaktion zugeordnet wurde. Damit muss für die Menge der Subtransaktionen trotz der Eigenständigkeit und trotz der frühen Freigabe von gesperrten Daten nach wie vor das Alles-oder-Nichts-Prinzip gelten. Es muss also insbesondere möglich sein, eine bereits abgeschlossene Subtransaktion zurückzusetzen. Nun führt ein solcher Vorgang zum bereits diskutierten Problem des fortgepflanzten Rollbacks. Gerade das aber sollte unbedingt vermieden werden. Deshalb scheidet das einfache Zurücksetzen einer Subtransaktion als Recoverykonzept aus. Stattdessen greift man auf so genannte Kompensationstransaktionen zurück. Eine Kompensationstransaktion ist das Gegenstück einer regulären Transaktion T S . Sie ist in der Lage, die von T S durchgeführten Handlungen wieder rückgängig zu machen, und zwar nicht durch das Einbringen der alten Werte, sondern durch die Ausführung von die ursprünglichen Operationen kompensierenden (inversen) Operationen. Wurde mit T S beispielsweise ein bestimmter Flug gebucht, der doch nicht gebraucht wird, so kann die Buchung nicht dadurch ungeschehen gemacht werden, dass die Anzahl der Plätze im Flugzeug wieder auf den alten Wert vor der Buchung gesetzt wird. Bei einem solchen Vorgehen würden nämlich, als unerwünschter Nebeneffekt, alle Buchungen ebenfalls storniert, die von anderen Transaktionen nach dem Ende von T S durchgeführt wurden. Stattdessen wird kompensiert, indem eine zur Buchungsoperation inverse Operation durchgeführt wird, die die Anzahl freier Plätze im Flugzeug um die Anzahl der stornierten Plätze erhöht. Kompensation lässt sich also unter zwei Voraussetzungen durchführen: 1. Die lange Transaktion lässt sich in eine Menge von abgeschlossenen, eigenständigen Untereinheiten zerlegen. 2. Zu jeder dieser untergeordneten Transaktion TS existiert eine Kompensationstransaktion, die in der Lage ist, die von TS durchgeführten Änderungen logisch rückgängig zu machen. Man beachte, dass Kompensation keine echte Serialisierbarkeit garantiert. Der Grund dafür liegt darin, dass eine Kompensationstransaktion zwar die Änderungen in der DB wieder kompensieren kann, nicht aber eventuell erfolgte Ausgaben an den Benutzer. Hatte T S z. B. den
9.4 Geschachtelte Transaktionen
637
letzten Platz in einem Flugzeug reserviert, so kann zwischenzeitlich ein anderer Kunde, der auch diesen Flug buchen wollte, endgültig abgewiesen worden sein.
9.3.3
Literatur
Die Arbeiten zur Recovery sind sehr zahlreich. Wir verweisen auf [BhLi81], [Gray78+81], [HäRa83], [Reut80], [LoSc87] und der dort zitierten Literatur. Sicherungspunkte wurden in [Gray78] bzw. [GMBL81] eingeführt und in [KSUW85] weiter verfeinert. In [GaSa87] werden das Konzept der Kompensation und mögliche Realisierungen in Zusammenhang mit geschachtelten Transaktionen ausführlich diskutiert. Kompensation allgemein wird in [KoLS90] und [Levy91] eingeführt, aber beispielsweise auch intensiv in [WäRe90+92] diskutiert. [WeSe84] setzt sich mit dem diskutierten Kompensationsproblem auseinander und schlägt zu dessen Lösung so genannte semantische Synchronisationsverfahren vor.
9.4
Geschachtelte Transaktionen
In den letzten Jahren sind die Anwendungsgebiete der Informatik wesentlich vielfältiger und komplexer geworden. Dies hat auch massive Auswirkungen auf die Datenbanktechnologie. Neben den klassischen Formen der Datenverarbeitung treten immer mehr sogenannte Nichtstandard-Anwendungen. Dazu zählt man insbesondere Entwicklungsumgebungen wie CAD 31 , VLSI32 und CASE33 , wissensbasierte Anwendungen und Expertensysteme, komplexe, integrierte Anwendungen wie CIM34 , die Bild- und Sprachverarbeitung, die geometrische Datenverarbeitung, multimediale Anwendungen, Umweltinformationssysteme und auch wissenschaftliche und statistische Anwendungen. Solchen Anwendungen widmen sich insbesondere die neueren DBMS wie die objektorientierten und die objektrelationalen DBMS. Trotz vielfältiger Unterschiede haben diese Anwendungen auch einige Gemeinsamkeiten, durch die sie sich fundamental von der klassischen Datenverarbeitung abheben. Hierzu gehören die Notwendigkeit einer adäquaten Datenmodellierung, die Verwaltung großer, komplex strukturierter Datenmengen, die Realisierung langlebiger, strukturierter Arbeitsabläufe und die Unterstützung interaktiver Arbeitstechniken. Insbesondere die letzten drei Punkte haben auch starke Auswirkungen auf das Transaktionsmanagement. Die den konventionellen Transaktionen zu Grunde liegende Philosophie, dass Transaktionen kurzlebig sind, aus der Sicht der Anwendung isoliert ablaufen sollen und auf einfach strukturierte Daten zugreifen, trifft nicht mehr zu. In diesem Kapitel werden wir die Anforderungen an neue Transaktionsmodelle im Wesentlichen nur unter dem Gesichtspunkt der Unterstützung lang andauernder Aktivitäten behandeln, was zu Modellen für lange und aus Gründen der Strukturierung geschachtelte Transaktionen führt. Das Gebiet neuerer Synchronisationsverfahren, die insbesondere auch auf eine Unterstützung kooperativer Arbeitsweisen ausgelegt sind, soll nicht behandelt werden, da die Techniken sich noch nicht so weit gesetzt haben, als dass sie nennenswerten Einfluss auf die Praxis gewonnen hätten. 31 Computer
Aided Design. Large Scale Integration. 33 Computer Aided Software Engineering. 34 Computer Integrated Manufacturing. 32 Very
638
9 Transaktionsverarbeitung und Fehlertoleranz
Bereits im Jahre 1973 wurde mit den so genannten Kontrollsphären (spheres of control) erstmals eine Idee veröffentlicht, die dem Konzept der geschachtelten Transaktionen ähnelt. Kontrollsphären bieten die Möglichkeit, komplexe Systeme in atomare Einheiten zu zerlegen und die dynamisch entstehenden Abhängigkeiten zwischen diesen Sphären aufzuzeichnen. Anfang der 80er Jahre griff Eliot Moss diese Idee auf und entwickelte aus ihr geschachtelte Transaktionen. Hauptmotivation für die Einführung von geschachtelten Transaktionen ist, wie oben bereits erwähnt, dass immer offensichtlicher wurde, dass sogenannte NichtstandardAnwendungen so komplexe Anforderungen an ein DBMS stellen, dass neben vielen anderen Auswirkungen auch das Konzept der kurzen Transaktionen als nicht mehr adäquat anzusehen war. Nichtstandard-Anwendungen erwarten, dass ihre komplexen Aufgabenstellungen auch effizient auf einer DB ausführbar sind. Will man solche lang andauernden, komplexen und zum Teil interaktiven Anwendungen mit traditionellen Transaktionen abdecken, so treten unter anderem die folgenden Probleme auf: 1. Konventionelle Transaktionen lassen sich nicht oder nur sehr eingeschränkt über Sicherungspunkte strukturieren. 2. Infolge des Alles-oder-Nichts-Prinzips wird bei einem Transaktionsfehler immer die gesamte Transaktion zurückgesetzt. Damit kann sehr viel Arbeit verloren gehen. Geschachtelte Transaktionen bieten hier eine Lösung an, da sie eine Zerlegung einer komplexen Aufgabenstellung in eine Menge von in sich abgeschlossenen Teilschritten ermöglichen (Modularisierung). Während also eine konventionelle Transaktion durch eine Folge von atomaren Operationen beschrieben wird, von denen entweder alle oder keine ausgeführt werden, besteht eine geschachtelte Transaktion aus einer Menge von Operationen und „untergeordneten“ Transaktionen35, so genannten Subtransaktionen (sub transactions), die wiederum aus einer Menge von Subtransaktionen bestehen können usw. Damit ist die Definition rekursiv. Zudem impliziert sie, dass die Menge aller geschachtelten Transaktionen einen Baum bildet (siehe Abbildung 9.17). Die Wurzel des Baumes wird Top-level-Transaktion (top-level transaction) genannt. Eine Transaktion, die aus Subtransaktionen besteht, heißt Elterntransaktion (parent transaction), die Subtransaktionen heißen auch Kindtransaktionen (child transaction). Durch eine solche Schachtelung wird zunächst zweierlei erreicht: 1. Die Transaktion wird modularisiert. 2. Es werden feinere Einheiten der Recovery definiert. Nicht mehr die Transaktion als Ganzes bildet die Einheit der Recovery, sondern jede Subtransaktion. Damit kann beim Scheitern einer Subtransaktion entschieden werden, ob diese Subtransaktion • unter den gleichen Voraussetzungen erneut gestartet wird, • mit modifizierter Aufgabenstellung versehen und dann wiederholt wird, • in einem anderen Umfeld erneut gestartet wird (z. B. bei verteilten DBS auf einem anderen Knoten) oder • einfach ganz weggelassen wird, beispielsweise wenn die Aufgaben der Subtransaktion nur bedingt zur Erreichung des Gesamtziels der Transaktion von Relevanz sind. 35 Es sei angemerkt, dass viele Modelle geschachtelter Transaktionen aus Gründen der korrekten Isolation das Ausführen von Operationen nur in den Blättern des Transaktionsbaumes erlauben, wodurch eine Mischung von Operationen und Subtransaktionen innerhalb einer (Sub-)Transaktion nur eingeschränkt im Sinn eines sequenziellen Ablaufes möglich ist.
9.4 Geschachtelte Transaktionen
639
Abb. 9.17: Aufbau einer geschachtelten Transaktion T
Natürlich kann auch beschlossen werden, die komplette geschachtelte Transaktion oder auch nur eine höhere Ebene (z. B. die direkte Elterntransaktion der gescheiterten Subtransaktion) zurückzusetzen. Insgesamt ergibt sich eine deutlich verbesserte Flexibilität in Bezug auf eine Reaktion auf Fehler, auch gegenüber dem Konzept der Sicherungspunkte. Eine dynamische bzw. fehlerabhängige Reaktion ist möglich, was insbesondere dazu führt, dass die Handlungen einer Transaktion nicht mehr exakt vorherbestimmt sein müssen, sondern dynamisch angepasst werden können. Damit ist sowohl der Weg zum Ziel als auch das Ergebnis einer Transaktion dynamisch konfigurierbar (siehe Abbildung 9.18). Beispiel 9.12 beschreibt ein einfaches Beispiel für eine geschachtelte Transaktion. Beispiel 9.12: Geschachtelte Transaktion Das bereits vorgestellte Beispiel eines Reisebüros beschreibt eine Umgebung, innerhalb derer geschachtelte Transaktionen erhebliche Vorteile bieten. Nehmen wir einmal an, Ute
640
9 Transaktionsverarbeitung und Fehlertoleranz T
T
T
T Aktionen e.
T: Transaktion
TS: Subtransaktion
Aktionen (Subtransaktionen) sind Einheit der Recovery
f. Subtransaktion bildet einen Schutzwall gegen Fehler Falls die Subtransaktion scheitert, kann die Elterntransaktion wie folgt weiterarbeiten 1. sich selbst zurücksetzen, 2. eine Alternative ausprobieren, 3. die gescheiterte Subtransaktion ignorieren, 4. die Subtransaktion erneut starten. Viele Wege zum möglicherweise
Aufgabe
Ziel
nicht exakt vorgegebenen Ziel
Abb. 9.18: Mögliche Reaktionen im Fehlerfall
bucht für einen Kunden eine komplette Reise, d. h. einen Flug, einen Mietwagen und ein Hotel. Obwohl nur alle drei Buchungen zusammen eine sinnvolle Einheit ergeben, kann jede Buchung für sich als ein Arbeitsschritt aufgefasst werden, der unabhängig von den anderen Buchungen ausgeführt werden kann. In der Realität wird diese Sichtweise auch dadurch noch unterstützt, dass Unternehmen (Fluggesellschaft, Mietwagenfirma, Hotelkette) häufig eigene Buchungssysteme unterhalten, die auf eigener Hardware laufen. Der Vorteil der Schachtelung der Transaktion liegt nun darin, dass jede Buchung als eigene Subtransaktion auch die Einheit der Recovery ist. Ist z. B. ein Hotel bereits besetzt, so wird nicht die gesamte Transaktion, inklusive der eventuell bereits durchgeführten Flugund Mietwagenbuchungen, zurückgesetzt, sondern es scheitert zunächst einmal nur die Hotelbuchung. Der Kunde kann nun entscheiden, ob er auch mit einem anderen Hotel zufrieden wäre, seinen Urlaub lieber in einer anderen Gegend verbringen möchte oder ganz auf die Reise verzichtet. Im ersten Fall wird nur die Subtransaktion zur Hotelbuchung wiederholt, während in den beiden anderen Fällen auch die anderen bereits durchgeführten Buchungen zurückgesetzt werden müssen. Ein Beispiel für eine rekursiv fortgeführte Schachtelung ist die Zerlegung der Flugbuchung in mehrere Teilflüge, beispielsweise bei einer Weltreise. Teilflüge können dann bei unterschiedli-
9.4 Geschachtelte Transaktionen
641
chen Fluggesellschaften gebucht werden. Somit würde der Arbeitsschritt Flugbuchung wieder aus einer Menge von Arbeitsschritten „Teilflugbuchungen“ bestehen, die damit wiederum als eigene Subtransaktionen gestartet werden können. Jede Subtransaktion T S beschreibt aus der Sicht ihrer Elterntransaktion T E eine atomare Einheit, d. h. sie wird entweder (aus der Sicht von TE ) ganz oder gar nicht ausgeführt. Auf der nächst tieferen Ebene (Kindebene) von T S kann T S nun wiederum aus einer Menge von Kindtransaktionen bestehen. T S hat dabei jederzeit das Recht (auch bereits beendete) Kindtransaktionen zurückzusetzen. Wird T S zurückgesetzt, beispielsweise auf eigenen Wunsch oder auf Veranlassung von T E , so werden natürlich auch alle Kinder von T S und die Kinder der Kinder usw. zurückgesetzt, d. h. der komplette durch T S gebildete Unterbaum wird zurückgesetzt. Daraus folgt, dass die Ergebnisse von T S auf jeden Fall erst mit dem Ende der Top-level-Transaktion dauerhaft werden. Eine Transaktion auf einer bestimmten Ebene darf erst beendet werden, wenn alle von ihr initiierten Kindtransaktionen beendet sind, also der von ihr aufgespannte (Sub-)Transaktionsbaum vollständig abgearbeitet wurde. Beispiel 9.13: Isolierte Fehlerbehebung Beispiel 9.12 sei auch die Grundlage dieses Beispiels. Nehmen wir einmal an, der Kunde wohnt in Frankfurt und möchte möglichst preiswert nach San Diego/Kalifornien fliegen. Nehmen wir weiter an, dass die billigste Möglichkeit von Europa ab Amsterdam zunächst nach Los Angeles und dann von Los Angeles nach San Diego geht. Beide Flüge werden als Koppelflug von einer Fluggesellschaft angeboten, stellen aber zwei getrennte Buchungen dar. Demnach unterteilt sich die Flugbuchung Frankfurt–San Diego in zwei Teilbuchungen: Frankfurt–Amsterdam und Amsterdam-San Diego. Die Transatlantikbuchung wiederum unterteilt sich in die Einheiten Amsterdam–Los Angeles und Los Angeles-San Diego. Ist z. B. der Anschlussflug Los Angeles–San Diego bereits ausgebucht (Misserfolg dieser Subtransaktion), so kann dieser Flug durch einen anderen (späteren oder von einer anderen Fluggesellschaft) ersetzt werden (Starten einer neuen Subtransaktion). Ist der Kunde jedoch mit dem Transatlantikflug insgesamt nicht einverstanden, so kann dieser zurückgesetzt werden, was dann zum Rücksetzen der Flüge Amsterdam-Los Angeles und Los Angeles–San Diego führt. Möchte der Kunde schließlich lieber ab Luxemburg fliegen, so ist die gesamte Flugbuchung (Top-level-Transaktion) zurückzusetzen, was wiederum automatisch mit dem Rücksetzen aller Subtransaktionen verbunden ist.
9.4.1
Geschlossen geschachtelte Transaktion
Wenn man nun schon einmal den Schritt zu einer Aufteilung einer Transaktion in Subtransaktionen gemacht hat, so bietet es sich an, Subtransaktionen parallel auszuführen, sofern dies von der Anwendung her möglich ist. Ein gutes Beispiel für eine solche so genannte Intratransaktionsparallelität bietet die Welt der verteilten DBS. Dort kann sich eine Transaktion in eine Menge von Subtransaktionen unterteilen, die auf unterschiedlichen Rechnern des verteilten DBS ausgeführt werden müssen. Unter der Voraussetzung, dass die Subtransaktionen nicht auf gemeinsamen Datenbeständen arbeiten oder nicht voneinander reihenfolgeabhängig sind, können sie problemlos parallel ausgeführt werden. Auch unser obiges Beispiel zeichnet Möglichkeiten für eine Intratransaktionsparallelität auf, da die Flug-, Hotel- und Mietwagenbuchungen problemlos parallel ausgeführt werden können.
642
9 Transaktionsverarbeitung und Fehlertoleranz
Ist eine solche Parallelität zugelassen, so muss innerhalb einer geschachtelten Transaktion synchronisiert werden. Soll wie bei konventionellen Transaktionen auch über Sperren synchronisiert werden, muss das (strikte) Zweiphasen-Sperrprotokoll erweitert werden. Üblicherweise werden alle Sperren bis zum Ende der jeweiligen Subtransaktion gehalten und dann an die direkte Elterntransaktion „vererbt“. Damit bleiben alle durch Subtransaktionen durchgeführten Änderungen zunächst einmal intern. Erst mit dem Ende der Top-level-Transaktion werden Änderungen nach außen sichtbar. Aus der Sicht paralleler Anwender bleibt die Schachtelung einer Transaktion also transparent, da sie sich nicht anders verhält wie eine konventionelle Transaktion. Deshalb wird diese Variante geschachtelter Transaktionen geschlossen geschachtelt (closed nested transaction) genannt.
9.4.2
Offen geschachtelte Transaktion
Kommen wir noch einmal auf unser Buchungsbeispiel zurück. Würden wir eine komplette Buchung über eine geschlossen geschachtelte Transaktion ausführen, so hätte das zur Konsequenz, dass jeder benötigte Datensatz bis zum Ende der Transaktion gesperrt bleibt. Auf unsere kleine Beispieldatenbank (siehe Kapitel 9.4.1, Beispiel 9.12) bezogen würde das heißen, dass z. B. das Datum freiePlätze der Flug-Tabelle bis zum Ende der Buchungstransaktion gesperrt ist. Damit wäre es keiner anderen Transaktion erlaubt, parallel einen Platz in diesem Flugzeug zu buchen. Da eine Buchungstransaktion wegen der Rücksprachen mit den Kunden unter Umständen sehr lange dauern kann, kann eine solche Blockade die Geduld anderer Kunden überstrapazieren. Eine Lösung bieten hier die so genannten offen geschachtelten Transaktionen (open nested transactions). Bei dieser Variante bildet jede Subtransaktion im Prinzip eine eigenständige Transaktion, weshalb sie ihre Sperren mit ihrem Ende nicht mehr an die Elterntransaktion vererben muss, sondern direkt endgültig freigegeben werden kann. Änderungen sind damit nicht mehr alleine im Transaktionsbaum sichtbar, sondern können von jeder anderen parallelen Transaktion gesehen werden. Diese Variante heißt „offen“, da Änderungen offen für jeden sichtbar sind und nicht nur für die direkte Elterntransaktion. Zwar ist damit die strikte Zweiphasigkeit auf der Ebene der Top-level-Transaktionen aufgehoben, allerdings bleibt eine Subtransaktion nach wie vor die Einheit der Recovery. So kann eine bereits beendete Subtransaktion T S trotz der Tatsache, dass sie ihre Daten bereits allgemein freigegeben hat, jederzeit von ihrer Elterntransaktion zurückgesetzt werden. Möglich wird dies, weil eine offene Schachtelung nur erlaubt ist, falls Kompensation als Recoverymaßnahme möglich ist. Kompensation darf in diesem Zusammenhang ruhig etwas breiter ausgelegt werden, und zwar in dem Sinn, dass über die Recoverymaßnahme eine Situation erreicht werden muss, die aus der Sicht der Anwendung akzeptabel ist, die DB in einem konsistenten Zustand hinterlässt und keine parallele Transaktion negativ beeinflusst bzw. beeinflusst hat. Bei einer Flugbuchung könnte Kompensation nicht nur die Stornierung der Buchung bedeuten, sondern beispielsweise auch das Abtreten des Fluges an einen gerade anwesenden anderen Kunden. Da damit nicht zwangsläufig auf einen alten „logischen“ Zustand zurückgesetzt wird, nennt sich diese Form der Recovery auch Vorwärtsrecovery (forward recovery).
9.4 Geschachtelte Transaktionen
9.4.3
643
Entwicklungstransaktion
Gehen wir jetzt noch einen Schritt weiter, d. h. nutzen wir geschachtelte Transaktionen nicht nur zum Zweck der Modularisierung und Parallelitätssteigerung, sondern auch zur kontrollierten Unterstützung von kooperativer Arbeitsweise, so kommen wir zu den Entwicklungstransaktionen. Eine Entwicklungstransaktion soll den Entwurfsprozess eines sehr komplexen Objektes wie z. B. eines VLSI-Chips oder eines komplexen CAD-Objektes (z. B. eines Automotors) unterstützen. Da in einer solchen Umgebung in der Regel eine Vielzahl von Entwicklern gemeinsam an der Lösung des Problems arbeiten, muss diese gemeinsame, kooperative Arbeitsweise durch den Transaktionsbegriff abgedeckt werden. Dies geht nur über die Aufweichung der strengen Isolation. Eine Entwicklungstransaktion ist hierarchisch strukturiert in dem Sinn, dass sich der durch sie insgesamt abzudeckende Aufgabenkomplex in Teilaufgaben zerlegen lässt, die wiederum in Teilaufgaben zerlegt werden können usw. Im einfachsten Fall kann man sich dabei vorstellen, dass die inneren Knoten des Transaktionsbaumes nur die für die dazugehörige Teilaufgabe notwendigen Daten zur Verfügung stellen. Die eigentliche Arbeit auf den Objekten wird dann nur in den Blatttransaktionen (von einzelnen Designern) durchgeführt. Jeder innere Knoten wirkt demnach wie eine private DB für die unterhalb dieser Transaktion angesiedelten Designer(gruppen). Insoweit kann eine Entwicklungstransaktion noch durch eine geschlossen geschachtelte Transaktion nachgebildet werden. Was jetzt neu hinzukommt, ist der kooperative Aspekt. In einer Entwicklungsumgebung muss es möglich sein, dass Entwickler Objekte (Daten) von anderen Entwicklern ausleihen können, dass Objekte weitergegeben oder auch ausgetauscht werden können. In Bezug auf den Transaktionsbegriff heißt das, dass innerhalb einer solchen geschlossenen Transaktionshierarchie die Eigenschaft der Isolation von Subtransaktionen untereinander aufgeweicht werden muss. Kurz gesagt muss nach innen hin Kooperation möglich sein, nach außen hin aber nach wie vor eine strenge Abschirmung bestehen. Allerdings muss sichergestellt werden, dass die Anwendung bzw. der Entwickler eine gewisse Verantwortung für ein korrektes Arbeiten auf den Daten übernimmt, m. a. W. die Anwendung muss garantieren, dass durch die Aufhebung der Isolation keine Konsistenzprobleme aufgrund der gemeinsamen Arbeit unterschiedlicher Transaktionen auf denselben Objekten entstehen. Solche Anforderungen können einerseits durch die Abschwächung der Kriterien des Sperrprotokolls (z. B. Aufhebung der Zweiphasigkeit), andererseits aber auch durch angepasste Synchronisationsverfahren (wie semantische Synchronisation) abgedeckt werden. Hierauf soll in diesem Buch aber nicht weiter eingegangen werden.
9.4.4
Literatur
Der Vorgänger der geschachtelten Transaktionen, die so genannten Kontrollsphären, wurden in [Davi73+78] vorgestellt. Die Erweiterung dieses Konzeptes in Richtung geschachtelte Transaktionen findet sich in [Moss81+86]. Diese Arbeit stellt auch Erweiterungen des Zweiphasen-Sperrprotokolls vor, so dass Subtransaktionen parallel ausgeführt werden können. Die verschiedenen Varianten von geschachtelten Transaktionen werden beispielsweise in [Trai83] diskutiert.
644
9 Transaktionsverarbeitung und Fehlertoleranz
In [GaSa87] wird die SAGA eingeführt, die eine lange Transaktion darstellt, die sich in eigenständige Einheiten aufteilen lässt, wobei für jede dieser Einheiten eine Kompensationstransaktion existiert. Es handelt sich also um eine spezielle Art von geschachtelter Transaktion, bei der die Schachtelungstiefe auf zwei begrenzt ist. Modelle für Entwicklungstransaktionen werden in vielen Arbeiten vorgestellt. Zu den Richtungsweisenden gehören [BaKK85], [HäRo86+87], [Katz84], [KLMP84], [KoKB85] und [KSUW85]. Das Standardwerk für Nichtstandard-Transaktionsmanagement ist [Elma92].
9.5
Kontrollaufgaben
Aufgabe 9.1: Serialisierbare Schedule Gegeben seien die folgenden Schedule: 1. R3 (y)R1 (x)W3 (z)R2 (z)W3 (y)R4 (y)R1 (y)W1 (x)W4 (x)R2 (y)R5 (z)W2 (z) 2. R4 (y)R1 (x)R1 (y)R3 (y)R2 (z)W4 (x)W1 (x)R2 (y)W2 (z)W3 (z)R5 (z)W3 (y)W5 (z) 3. R4 (y)R5 (z)R1 (x)R3 (y)W3 (z)W5 (z)W3 (y)R2 (z)W4 (x)R1 (y)W1 (x)R2 (y)W2 (z) 1. Erstellen Sie für diese Schedule den Abhängigkeitsgraphen. Welche Schedule erfüllen das Serialisierbarkeitskriterium? Welche Schedule würden es erfüllen, falls wirkungslose Transaktionen ausgeklammert würden? 2. Welche Ergebnisschedule würden von den folgenden Verfahren erzeugt und welche Verfahren würden eine korrekte Ergebnisschedule erzeugen, ohne eine Transaktion zurückzusetzen? (a) Striktes Zweiphasen-Sperrprotokoll (b) Zweiphasen-Sperrprotokoll mit Preclaiming (c) Zeitstempelverfahren (d) Optimistische Synchronisationsverfahren mit kritischem Abschnitt (e) Optimistische Synchronisationsverfahren ohne kritischen Abschnitt 3. Wie viele serielle Schedule gibt es jeweils und auf welche serielle(n) Schedule würde sich die durch das jeweilige Synchronisationsverfahren erzeugte Ergebnisschedule abbilden lassen? Aufgabe 9.2: Durchlässigkeit von Synchronisationsverfahren Die Durchlässigkeit gibt an, ob ein Synchronisationsverfahren serialisierbare Ausgangsschedule ohne Änderung in denselben Ergebnisschedule überführt. 1. Wie steht es mit der Durchlässigkeit der diskutierten Synchronisationsverfahren (Zweiphasen-Sperrprotokoll, Zeitstempelverfahren, Optimistische Synchronisationsverfahren)? Gibt es Schedule, die von dem einen Verfahren „durchgelassen“ werden, von dem anderen Verfahren jedoch verändert werden?
9.5 Kontrollaufgaben
645
2. Wie verhält es sich mit dem Steuerungsvermögen der Verfahren, d. h. gibt es Schedule, die von dem jeweiligen Verfahren direkt, d. h. ohne das Zurücksetzen einer Transaktion auf eine korrekte Ergebnisschedule abgebildet werden? Aufgabe 9.3: Deadlock Gegeben seien noch einmal die Situation 9.3 aus Kapitel 9.1.1, bei der jetzt Heinz und Willy die jeweils aufgeführten Operationen auf der DB ausführen wollen (s. u.). Der Ablauf einer Transaktion kann jeweils nach vollständiger Ausführung einer Operation unterbrochen und die Kontrolle einer der anderen Transaktion übergeben werden. Heinz: READ Auto(LA).preis Auto(LA).preis := Auto(LA).preis + 50,– READ Auto(SF).preis Auto(SF).preis := Auto(SF).preis + 50,– WRITE Auto(SF).preis WRITE Auto(LA).preis
Willy: READ Auto(SF).preis READ Auto(LA).preis Auto(LA).preis := Auto(LA).preis ∗ 1.1 WRITE Auto(LA).preis Auto(SF).preis := Auto(SF).preis ∗ 1.1 WRITE Auto(SF).preis
1. Bauen Sie in die obigen Operationsfolgen zunächst die Sperroperationen (jeweils direkt Schreibsperren, da alle Objekte geändert werden) ein, wobei unterstellt wird, dass eine Sperre immer erst zum spätest möglichen Zeitpunkt gesetzt wird. 2. Kann es eine Mischung der beiden Operationsfolgen geben, die in einem Deadlock endet, und wenn ja, welche ist das? 3. Wäre ein Deadlock möglich, falls Heinz auch zuerst die Autos in San Francisco bearbeiten würde? 4. Wird eine Sperre sehr früh gesetzt, blockiert man eine mögliche Parallelarbeit auf den Objekten. Deshalb arbeiten Synchronisationsverfahren manchmal so, dass zunächst immer nur genau die mindestens notwendige Sperre gesetzt wird (im Beispiel oben jeweils erst die Lesesperre). Nötigenfalls wird dann später eine Sperrverschärfung versucht, indem die Schreibsperre angefordert wird. (a) Setzen Sie im obigen Beispiel wieder zunächst die notwendigen Sperroperationen. (b) Ist jetzt ein Deadlock möglich unter der Originalsequenz oder der geänderten Leseoperationsfolge von Heinz (nach 4.)? (c) Welche Vor- und Nachteile sind grundsätzlich mit dieser „Sperre nur was wirklich notwendig ist“-Politik verbunden? Aufgabe 9.4: Hierarchisches Sperren Gegeben sei noch einmal die Situation von Aufgabe 9.3, nur mit dem Unterschied, dass Heinz weiterhin nur die Preise der Autos in Los Angeles und San Francisco ändert, während Willy die Preise aller Vermietstationen in Kalifornien ändert, wobei wir annehmen, dass es eine größere Anzahl solcher Stationen gibt (z. B. 15).
646
9 Transaktionsverarbeitung und Fehlertoleranz
1. Welche Sperren müssten gesetzt werden, wenn hierarchisches Sperren realisiert wäre und wie wären mögliche parallele Abläufe der beiden konfliktbehafteten Transaktionen, d. h. bei welcher Sperranforderung würde welches Problem in welcher Situation erkannt? 2. Wäre auch unter dem hierarchischen Sperren noch in einer der obigen Situationen ein Deadlock möglich? Aufgabe 9.5: Recovery In Aufgabe 9.1 hat es unter den jeweiligen Synchronisationsverfahren Situationen gegeben, die zu einem Rollback mindestens einer Transaktion geführt haben. Angenommen, es wird eine Steal-Politik gefahren, die dazu führt, dass die durch zurückgesetzte Transaktionen durchgeführten Änderungen wieder rückgängig gemacht werden müssen. 1. Wie sähe die Logdatei für die in Aufgabe 9.1 gegebenen Transaktionsfolgen unter logischer und unter physischer Protokollierung aus? 2. Führen Sie auf der Basis der jeweiligen Logdatei die notwendigen Rollbackprozesse für die jeweiligen Transaktionen durch. Aufgabe 9.6: Kompensation Geben Sie für die in Aufgabe 9.3 gegebenen Operationen von Willy und Heinz Kompensationsoperationen an. Lassen sich immer Kompensationsoperationen im Voraus festlegen bzw. welche Bedingungen müssen gelten, damit eine Kompensation erfolgreich sein kann? Aufgabe 9.7: Vererbung in geschachtelten Transaktionen Unter der Voraussetzung, dass innerhalb einer geschachtelten Transaktion eine parallele Ausführung von Subtransaktionen möglich ist, wobei die Arbeit von Subtransaktionen aber voneinander isoliert werden soll, hat sich die Vererbung durchgesetzt. Unter Vererbung versteht man die direkte und ausschließliche Weitergabe der Sperren einer Kindtransaktion an ihre direkte Elterntransaktion. Warum kann es Probleme geben, wenn eine Kindtransaktion (Teile) ihre(r) Sperren an einen anderen Vorfahren (z. B. die „Großelterntransaktion“) weitergeben würde? Aufgabe 9.8: Parallelität in einem inneren Knoten einer geschachtelten Transaktion Viele neuere Transaktionsmodelle fordern, dass innere Transaktion einer geschachtelten Transaktion nicht direkt auf ihren Daten operieren dürfen (nur Blätter dürfen Operationen ausführen). Warum wird diese Restriktion verlangt? Aufgabe 9.9: Transaktionsbaum Sollen Subtransaktionen innerhalb von geschachtelten Transaktionen isoliert voneinander arbeiten, wird erwartet, dass die geschachtelte Transaktion einen Transaktionsbaum darstellt. Warum ist die Bildung eines Transaktionsgraphen nicht möglich?
Literaturverzeichnis [ABCE76]
Astrahan, M. M.; Blasgen, M. W.; Chamberlin, D. D.; Eswaran, K. P.; Gray, J.; Griffiths, P. P.; King, W. F.; Lorie, R. A.; McJones, P. R.; Mehl, J. W.; Putzolu, G. R.; Traiger, I. L.; Wade, B. W.; Watson, V.: System R: A Relational Approach to Database Management; ACM Transactions on Database Systems (TODS), 1(2):97–137; 1976.
[AbHV95]
Abiteboul, S.; Hull, R.; Vianu, V.: Foundations of Databases; Addison Wesley Publishing Company, Reading, MA; 1995.
[ANSI86]
Database Language SQL; Document ANSI X3.135-1986; Auch verfügbar als: International Standards Organization Document ISO/TC 97/SC 21/WG 3 N 117; 1986.
[ANSI89]
Database Language SQL With Integrity Enhancement; Document ANSI X3.135-1989; Auch verfügbar als: International Standards Organization Document ISO/IEC 9075:1989.
[ANSI92]
Database Language SQL; Document ANSI X3.135-1992; Also available as: International Standards Organization Document ISO/IEC 9075:1992.
[Arms74]
Armstrong, W. W.: Dependency structures of database relationships; In: Porc. IFIP Congress, pp. 580–583.
[AtDe93]
Atzeni, P.; De Antonellis, V.: Relational Database Theory; Benjamin/ Cummings, Redwood City, CA, USA; 1993.
[Bach69]
Bachmann, C. W.: Data Structure Diagrams; Database (2); S. 4–19, 1969.
[BaCN92]
Batini, C.; Ceri S.; Navathe, S.B.: Conceptual Database Design; Redwood City: The Benjamin/Cummings Publishing Company, Inc. 1992.
[BaKK85]
Bancilhon, F.; Kim, W.; Korth, H.: A Model of CAD Transactions; Proc. Int. Conf. on Very Large Data Bases (VLDB), Stockholm; 1985.
[BaLN87]
Batini, C.; Lenzerini, M.; Navathe, S.: Comparison of Methodologies for Database Schema Integration; In: ACM Computing Surveys 18, No. 4, Dec 1986: S. 323–364.
[Balz82]
Balzert, H.: Die Entwicklung von Software-Systemen; B. I.-Wissenschaftsverlag, Mannheim; 1982.
[BeGo81]
Bernstein, P.; Goodman, N.: Concurrency Control in Distributed Database Systems; ACM Computing Surveys; Vol. 13, No. 2; June 1981.
648
Literaturverzeichnis
[BeHG88]
Bernstein, P.; Hadzilacos, V.; Goodman, N.: Concurrency Control and Recovery in Database Systems; Addison Wesley Publishing Company, Reading, MA; 1988.
[BeNe97]
Bernstein, P.; Newcomer, E.: Principles of Transaction Processing for the Systems Professional; Morgan Kaufmann Publishers, Inc., San Mateo, CA; 1997.
[BeRS95]
Becker, J.; Rosemann, M.: Grundsätze ordnungsgemäßer Modellierung; In: Wirtschaftsinformatik 37 (1995) 5, S. 435–455.
[BeSW79]
Bernstein, P.A.; Shipman, D.W.; Wong, W.S.: Formal aspects of Serializability in Database Concurrency Control; In: IEEE Transactions on Software Engineering, Vol. 5, Nr. 3 (1979), S. 203–216.
[Bisk81]
Biskup, J.: A Formal Approach to Null Values in Database Relations; In:[GaMN81]; S. 299–341; 1981.
[Bisk95]
Biskup, J.: Grundlagen von Informationssystemen; Vieweg Verlag, Braunschweig, Wiesbaden; 1995.
[Boeh76]
Boehm, B.: Software Engineering; In: IEEE Transactions on Computers, Vol. 25, Nr.12 (1976), S. 1226–1241.
[Boeh86]
Boehm, B.: A Spiral Model of Software Development and Enhancement; In: ACM SIGSOFT Software Engineering Notes, Vol. 11, Nr. 4 (1986), S. 22–42.
[BöFP96]
Böhm, R.; Fuchs, E.; Pacher, G.: System-Entwicklung in der Wirtschaftsinformatik; 4. überarb. u. erweiterte Auflage. Zürich: vdf Hochschulverlag AG; 1996.
[Booc94]
Booch, G.: Object-Oriented Analysis and Design with Applications; 2nd Edition, The Benjamin/Cummings Publishing Company, Inc., Redwood City, CA, USA; 1994.
[BoWi95]
Boßhammer, M.; Winter, R.: Formale Validierung von Verdichtungsoperationen in konzeptionellen Datenmodellen; In: König, W. (Hrsg.): Wirtschaftsinformatik ’95, Heidelberg, S. 223–242, 1995.
[BRGP78]
Bernstein, P.; Rothnie, J.; Goodman, N.; Papadimitriou, C.: The Concurrency Control Mechanism of SDD-1: A System for Distributed Databases (The Fully Redundant Case); In: IEEE Transactions on Software Engineering; SE-4 (1978), S. 154–168.
[CAEG76]
Chamberlin, D.; Astrahan, M. M.; Eswaran, K. P.; Griffiths, P. P.; Lorie, R. A.; Mehl, J. W.; Reisner, P.; Wade, B. W.: SEQLUEL 2: A unified approach to data definition, manipulation and control; In: IBM Journal of Research and Development, 20(6):560–575, Nov. 1976.
[Catt00]
Cattel, R. (Hrsg.): The Object Database Standard: ODMG 3.0; Morgan Kaufmann Publishers, Inc., San Mateo, CA; 2000.
Literaturverzeichnis
649
[CeGo85]
Ceri, S.; Gottlob, G.: Translating SQL into relational algebra: Optimization, semantics, and equivalence of SQL queries; In: IEEE Transactions on Software Engineering, Vol. 11 (1985), S. 324–345.
[CeGT90]
Ceri, S.; Gottlob, G.; Tanca, L.: Logic Programming and Databases; Surveys in Computer Science; Springer-Verlag Berlin, Heidelberg, New York; 1990.
[CFMS94]
Castano, S.; Fugini, M.; Martella G.; Samarati, P.: Database Security; AddisonWesley Publishing Company, Reading u.a., MA; 1994.
[ChBe80]
Cheng, W. K.; Belford, G. G.: Update Synchronization in Distributed Databases; Proc. Int. Conf. on Very Large Data Bases (VLDB); Montreal; 1980.
[ChBo74]
Chamberlin, D. D.; Boyce, R. F.: Sequel: A Structured English Query Language; In: ACM SIGMOD Workshop on Data Description, Access and Control; S. 49– 64, Ann Arbor, Mich., USA; 1974.
[Chen76]
Chen, P. P.: The Entity Relationship Model – Toward a unified view of Data; ACM Trans. on Database Systems (TODS). Bd. 1, Nr. 1, S. 9ff.; 1976.
[Codd70]
Codd, E. F.: A relational model for large shared data banks; Communications of the ACM; 13(6):377–387; 1970.
[Codd71]
Codd, E. F.: ALPHA: A Data Base Sublanguage Founded on the Relational Calculus of the Data Base Relational Model; In: Proc. ACM SIGFIDET Workshop on Data Description, Access and Control, San Diego, CA; Nov. 1971.
[Codd72a]
Codd, E. F.: Further Normalization of the Data Base Relational Model; In:[Rust72]; S. 33–64; 1972.
[Codd72b]
Codd, E. F.: Relational Completeness of Data Base Sublanguages; In:[Rust72]; S. 65–98; 1972.
[Codd74]
Codd, E. F.: Recent Investigations in Relational Database Systems; Proc. of the IFIP World Congress; 1974.
[Codd79]
Codd, E. F.: Extending the Database Relational Model to Capture More Meaning; In: ACM Transactions on Database Systems (TODS), 4(4); 1979.
[Codd82]
Codd, E. F.: Relational Database: A Practical Foundation for Productivity; In: Communications of the ACM, 25(2):109–117; Feb. 1982.
[Codd85]
Codd, E. F.: How Relational is Your Database Management Systems; Computerworld; Oct. 14 and 21; 1985.
[Codd86]
Codd, E. F.: The Twelve Rules for Relational DBMS; The Relational Institute, San Jose; Technical Report ECF-6; 1986.
[Codd88]
Codd, E. F.: Fatal Flaws in SQL; Datamation, Aug. 1988, S. 45–48 und Sept., S. 71–74; 1988.
[Codd90]
Codd, E. F.: The Relational Model for Databases Management, Version 2; Addison-Wesley Publishing Company, Reading u.a., MA; 1990.
650
Literaturverzeichnis
[Conv86]
Convent, B.: Unsolvable Problems Related to the View Integration Approach; In: Intl. Conf. on Database Theory; Bd. 243 der Reihe Lecture Notes in Computer Science, Springer-Verlag Berlin, Heidelberg, New York, S. 141–156; 1986.
[CoYo91]
Coad P.; Yourdan, E.: Object-Oriented Analysis; 2nd Edition, Yourdan Press, Prentice Hall, Englewood Cliffs, NJ, USA; 1991.
[CrGH94]
Cremers, A.; Griefahn, U.; Hinze, R.: Deduktive Datenbanken- Eine Einführung aus der Sicht der logischen Programmierung; Vieweg Verlag; 1994.
[DaDa92]
Date, C. J.; Darwen, H.: Relational Database Writings 1989–1991; AddisonWesley Publishing Company, Reading u.a., MA; 1992.
[DaDa97]
Date, C. J.; Darwen, H.: A Guide to the SQL Standard; Addison-Wesley Publishing Company, Reading u.a., MA; 4. Auflage; 1997.
[Date81]
Date, C. J.: Referential Integrity; In: Proc. of the 7th Int. Conf. on Very Large Data Bases (VLDB), S. 2–12, Cannes, France; 1981.
[Date90]
Date, C. J.: Relational Database Writings 1985–1989; Addison-Wesley Publishing Company, Reading u.a., MA; 1990.
[Date94a]
Date, C. J.: Toil and Trouble; In: Database Programming & Design; Vol. 7, No. 1, S. 15–18; Jan. 1994.
[Date94b]
Date, C. J.: An Introduction to Database Systems, Volume 1; The Systems Programming Series, Addison-Wesley Publishing Company, Reading u.a., MA; 6. Auflage; 1994.
[Davi73]
Davies, C.T.: Recovery Semantics for a DB/DC System; In: Proc. ACM National Conf. 28; S. 136–141; 1973.
[Davi78]
Davies, C.T.: Data processing spheres of control; In: IBM Systems Journal, S. 179–199; 1978.
[DeLR94]
Delobel, C.; Lecluse, C.; Richard, P.: Databases: From Relational to ObjectOriented Systems; International Thomson Publishing, London; 1994.
[DeMa79]
DeMarco, T.: Structured Analysis and System Specification; Prentice Hall, Englewood Cliffs/N.J. 1979.
[DüRa90]
Dürr, M.; Radermacher, K.: Einsatz von Datenbanksystemen; Informationstechnik und Datenverarbeitung; Springer-Verlag Berlin, Heidelberg, New York; 1990.
[EGLT76]
Eswaran, K.; Gray, J.; Lorie, R.; Traiger, I.: The Notions of Consistency and Predicate Locks in a Database System; In: Communications of the ACM, Vol. 19, Nr. 11 (1976), S. 624–633.
[EhGL89]
Ehrich, H.-D.; Gogolla, M.; Lipeck, U.: Algebraische Spezifikation abstrakter Datentypen; Leitfäden und Monographien der Informatik; Teubner-Verlag, Stuttgart; 1989.
Literaturverzeichnis
651
[EhMa92]
Ehrig, H.; Mahr, B.: Fundamentals of Algebraic Specification: 1. Equations und Initial Semantics; Springer-Verlag Berlin, Heidelberg, New York; 1992.
[Eick97]
Eicker, S.: Management der Ressource „Daten“ im Unternehmen unter besonderer Berücksichtigung der integrationsorientierten Datendokumentation; Habilitationsschrift an der Universität Viadrina, Frankfurt/Oder; 1996.
[ElKT94]
Elmasri, R.; Kouramajian, V.; Thalheim B. (Eds.): Entity-Relationship Approach – ER’93, 12. Int. Conf. on the Entity-Relationship Approach, Arlington, Texas, USA, December 15–17, 1993. Proceedings: Lecture Notes in Computer Science, Vol. 823, Springer-Verlag Berlin, Heidelberg, New York; 1994.
[Elma92]
Elmagarmid, A. K. (Hrsg.): Database Transaction Models For Advanced Applications; The Morgan Kaufmann Series in Data Management Systems; MorganKaufmann Publishers, San Mateo, CA, USA; 1992.
[ElNa99]
Elmasri, R.; Navathe, S. B.: Fundamentals of Database Systems; Redwood City: 3. überarb. Auflage. The Benjamin/Cummings Publishing Company, Inc. 1999.
[ElWH85]
Elmasri, R.; Weeldreyer, J.; Hevner, A.: The Category Concept: An Extension to the Entity-Relationship Model; Int. Journal on Data and Knowledge Engineering, Bd. 1, Nr. 1, May 1985.
[EmGo97]
Embley, D.; Goldstein R. (Eds.): Conceptual Modeling – ER’97. 16. Int. Conf. on Conceptual Modeling, Los Angeles, CA, USA. Proceedings: Lecture Notes in Computer Science, Vol. 1331, Springer-Verlag London, Berlin, Heidelberg, New York; 1997.
[FeSi90]
Ferstl O. K.; Sinz, E. J.: Objektmodellierung betrieblicher Informationssysteme im Semantischen Objektmodell (SOM); In: Wirtschaftsinformatik 32 (1990) 6, S. 566–581; 1990.
[FeSi95]
Ferstl O. K.; Sinz E. J.: Der Ansatz des Sematischen Objektmodells (SOM) zur Modellierung von Geschäftsprozessen; In: Wirtschaftsinformatik 37 (1995) 3, S. 209–220; 1995.
[FeSi98]
Ferstl, O. K.; Sinz, E. J.: Grundlagen der Wirtschaftsinformatik; Bd. 1. 3. überarbeitete Auflage. Oldenbourg Verlag GmbH, München; 1998.
[FMRW94] Froese, J.; Moazzami, M.; Rautenstrauch, C.; Welter, H.: Effiziente Systementwicklung mit Oracle 7; Addison-Wesley Publishing Company, Bonn u.a.; 1994. [Frey87]
Freytag, J. C.: A rule-based view of query optimization; In: Proc. ACM Int. Conf. on Management of Data (SIGMOD); S. 173–180, San Francisco, USA; 1987.
[GaMi78]
Galaire, H.; Minker, J.; Hrsg.: Logic and Databases; Plenum Publishing Co., New York, NY, USA; 1978.
[GaMN81] Gallaire, H.; Minker, J.; Nicolas, J. (Hrsg.): Advances in Data Base Theory; Bd. 1, Plenum Press, New York; 1981.
652
Literaturverzeichnis
[GaRö95]
Gabriel, R.; Röhrs, H.-P.: Datenbanksysteme, Konzeptionelle Datenmodellierung und Datenbankarchitekturen; Springer-Verlag Berlin, Heidelberg, New York; 2. Auflage; 1995.
[GaSa79]
Gane, C.; Sarson, T.: Structured System Analysis. Tools and Techniques; Improved System Technologies, New York, 1979.
[GaSa87]
Garcia-Molina, H.; Salem, K.: SAGAS; Proc. ACM Int. Conf. on Management of Data (SIGMOD), San Francisco, CA; 1987.
[GaVa89]
Gardarin, G.; Valduriez, P.: Analysis and Comparison of Relational Database Systems; Addison-Wesley Publishing Company, Reading u.a., MA; 1989.
[GHOK81] Gray, J.; Homan, P.; Obermarck, R.; Korth, H.: A Straw Man Analysis of Probability of Waiting and Deadlock; IBM Research Report RJ3066, IBM Research Laboratory, San Jose, CA; 1981. [Gill85]
Gillenson, M. L.: Trends in Data Administration; In: MIS Quarterly 9; 1985.
[GLPT76]
Gray, J.; Lorie, R.; Putzolu, G. R.; Traiger, I.: Granularity of Locks and Degrees of Consistency in a Large Shared Data Base; In: Modelling in Data Base Management Systems, North Holland; 1976.
[GMBL81] Gray, J.; MacJones, P. R.; Blasgen, M. W.; Lindsay, B.; Lorie, R.; Price, T. G.; Putzolu, G. R.; Traiger, I.: The Recovery Manager of the System R Database Manager; In: ACM Computing Surveys, Vol. 13, Nr. 2 (1981). [GoPZ88]
Gottlob, G.; Paolini, P.; Zicari, R.: Properties and Update Semantics of Consistent Views; In: ACM Transactions on Database Systems (TODS), Vol. 13, Nr. 4 (1988), S. 486–524.
[Grae93]
Graefe, G.: Query Evaluation Techniques for Large Databases; In: ACM Computing Surveys, Vol. 25, Nr. 2 (1993), S. 73–170.
[Gray78]
Gray, J.: Notes on Database Operating Systems; In: R. Bayer, R. M. Graham, G. Seegmüller, (editors): Operating Systems: An Advanced Course, S. 393–481. Springer-Verlag London, Berlin, Heidelberg, New York; 1978.
[Gray81]
Gray, J.: The Transaction Concept: Virtues and Limitations; In: Proc. 7th Int. Conf. on Very Large Data Bases (VLDB), S. 144–154; September 1981.
[GrRe93]
Gray, J.; Reuter, A.: Transaction Processing: Concepts and Techniques; Morgan Kaufmann Publishers, Inc., San Mateo, CA; 1993.
[Hane84]
Haneke, W.: Büroanalysemethoden; In: Angewandte Informatik 10 (1984), S. 399–409.
[Hans96]
Hansen, H. R.: Wirtschaftsinformatik I; Verlag Lucius & Lucius, Stuttgart, 7. Auflage; 1996.
[HäRa99]
Härder, Th.; Rahm, E.: Datenbanksysteme: Konzepte und Techniken der Implementierung. Springer-Verlag Berlin Heidelberg; 1999.
Literaturverzeichnis
653
[Härd85]
Härder, T.: Observations on Optimistic Concurrency Control; In: Information Systems, Vol. 9, Nr. 2 (1985).
[HäRe83]
Härder, T.; Reuter, A.: Principles of Transaction-Oriented Database Recovery; In: ACM Computing Surveys, Vol. 15, Nr. 4 (1983).
[HäRo86]
Härder, Th.; Rothermel, K.: Concurrency Control Issues in Nested Transactions. In: IBM Almaden Research Report, San Jose; 1986 und VLDB Journal, Vol. 2, Nr. 1 (1993), S. 39–74.
[HäRo87]
Härder, Th.; Rothermel, K.: Concepts for Transaction Recovery in Nested Transactions; Proc. ACM Int. Conf. on Management of Data (SIGMOD); San Francisco, CA; 1987.
[HaWi93]
Hagen, M.; Will, L.: Relationale Datenbanken in der Praxis; Verlag Technik, Berlin/München; 1993.
[Hei96a]
Heinrich, L. J.: Systemplanung; Bd. 1., 7. Auflage; Oldenbourg Verlag, München, Wien; 1996.
[HeSa00]
Heuer, A.; Saake, G.: Datenbanken: Konzepte und Sprachen, International Thomson Publishing; 2. Auflage; 2000.
[HiKa99]
Hitz, M.; Kappel, G.: UML @@ Work: Von der Analyse zur Realisierung, dpunkt.Verlag; 1999.
[ISO199]
ISO-ANSI: Information Technology – Database Languages – SQL – Part 1: Framework (SQL/Framework); ISO/IEC 9075-1: 1999.
[ISO299]
ISO-ANSI: Information Technology – Database Languages – SQL – Part 2: Foundation (SQL/Foundation); ISO/IEC 9075-2:1999.
[ISO399]
ISO-ANSI: Information Technology – Database Languages – SQL – Part 3: Call-level interface (SQL/CLI); ISO/IEC 9075-3:1999.
[ISO499]
ISO-ANSI: Information Technology – Database Languages – SQL – Part 4: Persistent Stored Modules (SQL/PSM); ISO/IEC 9075-4:1999.
[ISO599]
ISO-ANSI: Information Technology – Database Languages – SQL – Part 5: Host language bindings (SQL/Bindings); ISO/IEC 9075-5:1999.
[JaCV86]
Jarke, M.; Clifford, J.; Vassiliou, Y.: An optimizing Prolog front end to a relational query system; In: Proc. ACM Int. Conf. on Management of Data (SIGMOD), S. 296–306, Washington, USA; 1986.
[JaKo84]
Jarke, M.; Koch, J.: Query optimization in database systems; In: ACM Computing Surveys, Vol. 16, Nr. 2 (1984), S. 111–152.
[JCJÖ92]
Jacobson, I.; Christerson, M.; Jonsson, P.; Övergaard, G:: Object-Oriented Software Engineering: A Case Driven Approach; Addison-Wesley Publishing Company, Wokingham u.a., MA; 1992.
654
Literaturverzeichnis
[KaKl93]
Kandzia, P.; Klein, H.-J.: Theoretische Grundlagen relationaler Datenbanksysteme; B. I.-Wissenschaftsverlag, Mannheim; 1993.
[Kang90]
Kangassalo, H. (Ed.): Conceptual Modeling – ER’90; Proc. 9. Int. Conf. on Entity-Relationship Approach (ER ’90): The Core of Conceptual Modelling; North-Holland, Amsterdam; 1991.
[KaSc96]
Kappel, G.; Schrefl, M.: Objektorientierte Informationssysteme: Konzepte, Darstellungsmittel, Methoden; Springer-Verlag Berlin, Heidelberg, New York; 1996.
[Katz84]
Katz, R.H.: Transaction Management in the Design Environment; in ‚New Applications of Data Bases‘, G. Gardarin, E. Gelenbe (Hrsg), Academic Press; 1984.
[KeEi99]
Kemper, A.; Eickler, A.: Datenbanksysteme, Eine Einführung, Oldenbourg Verlag GmbH, München; 3. Auflage; 1999.
[Kelt85]
Kelter, U.: Parallele Transaktionen in Datenbanksystemen; B. I.-Wissenschaftsverlag, Zürich; 1985.
[Kelt88]
Kelter, U.: Transaktionskonzepte für Nicht-Standard Datenbanksysteme; Informationstechnik it, R. Oldenbourg Verlag, Vol. 30, No. 1; 1988.
[KLMP84] Kim, W.; Lorie, R.; McNabb, D.; Plouffe, W.: A Transaction Mechanism for Engineering Design Databases; Proc. Int. Conf. on Very Large Data Bases (VLDB); Singapore; 1984. [KlRa97]
Kleinschmidt, P.; Rank, C.: Relationale Datenbanksysteme, Eine praktische Einführung; Springer Verlag Berlin, Heidelberg, New York; 1997.
[Klug82]
Klug, A.: Equivalence of relational algebra and relational calculus query languages having aggregate functions; In: Journal of the ACM, Vol. 29, Nr. 3 (1982), S. 699–717.
[KoKB85]
Korth, H.F.; Kim, W.; Bancilhon, F.: A Model of CAD Transactions, Proc. Int. Conf. on Very Large Data Bases (VLDB); Stockholm, Sweden; 1985.
[KoLS90]
Korth, H.F.; Levy, E.; Silberschatz, A.: A Formal Approach to Recovery by Compensating Transactions; In: Proc. 16th Int. Conf. on Very Large Data Bases (VLDB); S. 95–106; August 1990.
[Kral96]
Krallmann, H.: Systemanalyse im Unternehmen; 2. Auflage, Oldenbourg Verlag GmbH, München; 1996.
[KrBZ86]
Krishnamurti, R.; Boral H.; Zaniolo, C.: Optimization of Nonrecursive Queries; Proc. of the Conf. on Very Large Data Bases (VLDB), S. 128–137, Kyoto, Japan, 1986.
[KSUW85] Klahold, P.; Schlageter, G.; Wilkes, W.; Unland, R.: A Transaction Model Supporting Complex Applications in Integrated Information Systems; Proc. ACM Int. Conf. on Management of Data (SIGMOD), Austin, Texas; 1985.
Literaturverzeichnis
655
[Kulk94]
Kulkarni, K. G.: Object-oriented extensions in SQL3: A status report; Proc. ACM Int. Conf. on Management of Data (SIGMOD), S. 478, Minneapolis, MI, USA; 1994.
[KuRo79]
Kung, H. T.; Robinson, J. T.: On Optimistic Methods for Concurrency Control; Proc. 5th Int. Conf. on Very Large Databases (VLDB); Rio de Janeiro, Brazil; 1979 und ACM Transactions on Database Systems (TODS), 6(2):231–226; June 1981.
[LaLo95]
Lang, S. M.; Lockemann, P. C.: Datenbankeinsatz; Springer-Verlag Berlin, Heidelberg, New York; 1995.
[LaPi77a]
Lacroix, M.; Pirotte, A.: Domain-Oriented Relational Languages; In: Proc. of the 3rd Int. Conf. on Very Large Data Bases (VLDB), Tokyo, Japan; 1977.
[LaPi77b]
Lacroix, M.; Pirotte, A.: ILL: An English Structured Query Language for Relational Data Bases; In: Nijssen, G. (Hrsg.): Architecture and Models in Data Base Management Systems; North-Holland; 1977.
[LeHM95]
Lehner, F.; Hildebrand, K.; Maier, R.: Wirtschaftsinformatik: Theoretische Grundlagen, München et al. 1995.
[Lehn88]
Lehnert, K.: Regelbasierte Beschreibung von Optimierungsverfahren für relationale Datenbankanfragesprachen; Dissertation, Technische Universität München; 1988.
[Levy91]
Levy, E.: Semantics-Based Recovery in Transaction Management Systems; Dissertation TR-91-29, University of Texas at Austin; August 1991.
[Lien85]
Lien, Y. E.: Relational Database Design; In:[Yao85].
[LMWF93] Lynch, N.; Merritt, M.; Weihl, W.; Fekete, A.; Yager, R.: Atomic Transactions; Morgan Kaufmann Publishers, Inc., San Mateo, CA; 1993. [Lohm88]
Lohman, G. M.: Grammar-like functional rules for representing query optimization alternatives; Proc. ACM Int. Conf. on Management of Data (SIGMOD); S. 18–27, Chicago, IL, USA; 1988.
[LoSc87]
Lockemann, P. C.; Schmidt, J. W.; Hrsg.: Datenbank-Handbuch; SpringerVerlag Berlin, Heidelberg, New York; 1987.
[Louc94]
Loucopoulos, P. (Ed.): Entity-Relationship Approach – ER’94, Business Modelling and Re-Engineering. 13. Int. Conf. on the Entity-Relationship Approach, Manchester, U.K. Proceedings: Lecture Notes in Computer Science, Vol. 881, Springer-Verlag London, Berlin, Heidelberg, New York; 1994.
[Lust97]
Lusti, M.: Dateien und Datenbanken, Eine anwendungsorientierte Einführung; Springer-Verlag Berlin, Heidelberg, New York; 1997.
[MaDL87]
Mayr, H. C.; Dittrich K. R.; Lockemann P. C.: Datenbankentwurf ; In:[LoSc87].
656
Literaturverzeichnis
[MaFr94]
Marsch, J.; Fritze, J.: SQL, Eine praxisorientierte Einführung; Vieweg Verlag, Braunschweig, Wiesbaden; 2. Auflage; 1994.
[Maie83]
Maier, D.: The Theory of Relational Databases; Computer Science Press, Rockville, MD, USA; 1983.
[Maie98]
Maier, R.: Nutzen und Qualität der Datenmodellierung – Ergebnisse einer empirischen Studie; In: Wirtschaftsinformatik 40 (1998) 2.
[MaMc75]
Marca, D. A.; McGowan, C. L.: SADT. Structured Analysis and Design Technique; McGraw-Hill Book Company, New York u.a., USA; 1975.
[MaUn00]
Matthiessen, G.; Unterstein, M.: Relationale Datenbanken und SQL: Konzepte der Entwicklung und Anwendung; Addison-Wesley Publishing Company, Bonn u.a.; 2. Auflage 2000.
[MBKP00] Mertens, P.; Bodendorf, F.; König, W.; Picot, A.; Schumann, M.: Grundzüge der Wirtschaftsinformatik; Springer-Verlag Berlin, Heidelberg, New York; 2000. [McHP99]
McFadden, F.; Hoffer, J., Prescott, M.: Modern Database Management; Addison-Wesley Publishing Company; 5. Auflage; 1999.
[MeKl91]
Mertes, H.; Klonki, U.: Vorgehensweise für die Erstellung eines unternehmensweiten Datenmodells bei der Hoesch AG; In: Wirtschaftsinformatik 33 (1991) 4, S. 308–315.
[Melt96a]
Melton, J. (ed.): Database Languages SQL – Part 2: SQL/Foundations ISO/IEC JTC1/SC21 N10489 committee draft; July edition; 1996.
[Melt96a]
Melton, J.: A Shift in the Landscape; In: Database Programming & Design; Vol. 9, No. 8, S. 51–54; Aug. 1996.
[Melt96b]
Melton, J. (ed.): Database Languages SQL – Part 5: Host Language Bindings (SQL/Bindings) ISO/IEC JTC1/SC21 N10490 committee draft; june edition; 1996.
[Melt96b]
Melton, J.: The „What’s What“ of SQL3; In: Database Programming & Design; Vol. 9, No. 12, S. 66–69; Dez. 1996.
[Melt96c]
Melton, J. (ed.): Database Languages SQL – Part 8: SQL/Object ISO/IEC JTC1/SC21 N10491 committee draft; July edition; 1996.
[Mert00]
Mertens, P.: Integrierte Informationsverarbeitung. Band 1, Administrations- und Dispositionssysteme in der Industrie; 12. Auflage; Gabler-Verlag, Wiesbaden; 2000.
[MeSi93]
Melton, J.; Simon, A. R.: Understanding the New SQL: A Complete Guide; Morgan-Kaufmann Publishers, San Mateo, CA, USA; 1993.
[Meye88]
Meyer-Wegener, K.: Transaktionssysteme; B.G. Teubner-Verlag, Stuttgart; 1988.
Literaturverzeichnis [Mits95]
657
Mitschang, B.: Anfrageverarbeitung in Datenbanksystemen; Vieweg Verlag, Braunschweig, Wiesbaden; 1995.
[MMMO93] Müller-Ettrich, G.; Mistelbauer, H.; Münzenberger, H.; Ortner, E.; Sinz, E.J.; Thoma, H.: Fachliche Modellierung von Informationssystemen; AddisonWesley Publishing Company, Bonn u.a.; 1993. [Moss81]
Moss, E.: Nested Transactions: An Approach to Reliable Distributed Computing; Ph. D. thesis, M.I.T. Dept. of Elec. and Comp. Sci., Technical Report; 1981.
[Moss86]
Moss, J.E.B.: An Introduction to Nested Transactions; COINS Technical Report 86-41, University of Massachusetts at Amherst; Sept. 1986.
[NaPe92]
Navathe, S. B.; Pernul, G.: Conceptual and Logical Design of Relational Databases; In: Advances in Computers. Bd. 35; Yovits, C., Marshall. (Hrsg.); Academic Press, Inc., Boston u.a., S. 1–78; 1992.
[Neum94]
Neumann, G.: Datenmodellierung mit deduktiven Techniken; Beiträge zur Wirtschaftsinformatik 9, Physica Verlag; 1994.
[Onei00]
O’Neil, P.: Database: Principles, Programming, and Performance, Morgan Kaufmann Publishers, San Francisco, CA, USA; 2. Auflage; 2000.
[Ortn91]
Ortner, E.: Erfahrungen mit der Datenmodellierung zur Organisation der Daten-Ressourcen in der Unternehmung, In: Czap, H.; Galinski, Ch. (Eds.). Proc. International Congress on Terminology and Knowledge Engineering, pp. 291–307; 1987.
[Ortn97]
Ortner, E.: Methodenneutraler Fachentwurf ; Teubner-Verlag, Reihe Wirtschaftsinformatik, Stuttgart, Leipzig 1997.
[Öste95]
Österle, H.: Business Engineering: Prozess- und Systementwicklung; Bd. 1., 2. Auflage. Springer-Verlag Berlin, Heidelberg, New York; 1995.
[Papa79]
Papadimitriou, C.: The Serializability of Concurrent Database Updates; In: Journal of the ACM, Vol. 26, Nr. 4 (1979).
[Papa86]
Papadimitriou, C.: The Theory of Database Concurrency Control; Computer Science Press, Rockville, MD, USA; 1986.
[Papa95]
Papazoglou, M. (Ed.): OOER’95: Object-Oriented and Entity-Relationship Modelling. 14. Int. Conf., Gold Coast, Australia. Proceedings: Lecture Notes in Computer Science, Vol. 1021, Springer-Verlag London, Berlin, Heidelberg, New York; 1995.
[Pasc93]
Pascal, F.: Understanding Relational Databases with Examples in SQL-92; John Wiley & Sons, New York, USA; 1993.
[PDGV89]
Paredaens, J.; Bra, P. D.; Gyssens, M.; Gucht, D. V.: The Structure of the Relational Database Model; EATCS Monographs on Theoretical Computer Science; Springer-Verlag Berlin, Heidelberg, New York; 1989.
658
Literaturverzeichnis
[Pern94]
Pernul, G.: Database Security; In: Advances in Computers. Bd. 38; Yovits, C., Marshall. (Hrsg.); Academic Press, Inc., Boston u.a., S. 1–72; 1994.
[PeTj92]
Pernul, G.; Tjoa, M. (Eds.): Entity-Relationship Approach – ER’92; In: 11. Int. Conf. on the Entity-Relationship Approach, Karlsruhe, Germany, October 7–9; Lecture Notes in Computer Science, Vol. 645, Springer-Verlag London, Berlin, Heidelberg, New York; 1992.
[PiBl97]
Pistor, P.; Blanken, H.: The SQL3 Server Interface; In: Multimedia Databases in Perspective; P. Apers, H. Blanken, M. Houtsma (eds.); Springer-Verlag London, Berlin, Heidelberg; 1997.
[Piro78]
Pirotte, A.: High Level Data Base Query Languages; In:[GaMi78]; S. 409–436; 1978.
[PoBl96]
Pomberger, G.; Blaschek, G.: Software Engineering-Prototyping und objektorientierte Software-Entwicklung; 2. Auflage, Hanser Verlag; 1996.
[RaSt97]
Rauh, O.; Stickel, E.: Konzeptuelle Datenmodellierung; Teubner-Verlag, Reihe Wirtschaftsinformatik, Stuttgart, Leipzig; 1997.
[Rauh90]
Rauh, O.: Informationsmanagement im Industriebetrieb; Verlag Neue Wirtschafts-Briefe, Herne, Berlin; 1990.
[RBPE93]
Rumbaugh, J.; Blaha, M.; Premerlani W.; Eddy, F.; Lorensen, W.: Objektorientiertes Modellieren und Entwerfen; Hanser Verlag, München, Wien; 1993.
[Reed83]
Reed, D.: Implementing Atomic Actions on Decentralized Data; ACM Trans. on Comp. Syst., 1(1):3–23; 1983.
[Rica90]
Ricardo, C.: Database Systems: Principles, Design and Implementation; Macmillan Publishing Company; Englewood Cliffs, NJ; 1990.
[RoCo99]
Rob, P.; Coronel, C.: Database Systems – Design, Implemetation, and Management; Boyd & Fraser Publishing Company; 4. Auflage; 1999.
[Rust72]
Rustin, R. (Hrsg.): Courant Computer Science Symposia 6, Database Systems; Prentice Hall, Englewood Cliffs, NJ, USA; 1972.
[RySm95]
Ryan, N.; Smith, D.: Database Systems Engineering; International Thomson Publishing Company, London u.a.; 1995.
[SaHe99]
Saake, G.; Heuer, A.: Datenbanken: Implementierungstechniken, International Thomson Publishing; 1999.
[Saue98]
Sauer, H.: Relationale Datenbanken: Theorie und Praxis inklusive SQL-3; 4. Auflage; Addison-Wesley Publishing Company, Bonn u.a.; 1998.
[ScHa92]
Scheer, A.-W.; Hars, A.: Extending Data Modeling to Cover the Whole Enterprise; In: Communications of the ACM, Vol. 35, Nr. 9 (1992), S. 166–172.
[Sche98a]
Scheer, A.-W.: ARIS – Modellierungsmethoden Metamodelle Anwendungen; 3. Auflage, Springer-Verlag Berlin, Heidelberg, New York; 1998.
Literaturverzeichnis
659
[Sche98b]
Scheer, A.-W.: ARIS – Vom Geschäftsprozess zum Anwendungssystem; 3. Auflage, Springer-Verlag Berlin, Heidelberg, New York; 1998.
[Schl78]
Schlageter, G.: Process Synchronization in Database Systems; In: ACM Transactions on Database Systems (TODS), Vol. 3, Nr. 3 (1978), S. 248–271.
[Schü95]
Schüngel, M.: Stand der Unternehmensdatenmodellierung in der Praxis: Eine empirische Untersuchung; Diplomarbeit, Institut für Wirtschaftsinformatik; Universität Münster; 1995
[ScRu96]
Schader, M.; Rundshagen, M.: Objektorientierte Systemanalyse: Eine Einführung; 2. Auflage, Springer-Verlag Berlin, Heidelberg, New York; 1996.
[ScSt83]
Schlageter, G.; Stucky, W.: Datenbanksysteme: Konzepte und Modelle, Teubner Studienbücher Informatik, Stuttgart; 1983.
[SHOO95]
Stickel, E.; Hunstock, J.; Ortmann, A.; Ortmann, J.: Verfahren zur werkzeuggestützten Integration von Datenbankschemata; In: König, W. (Hrsg.): Wirtschaftsinformatik ’95. Wettbewerbsfähigkeit, Innovation, Wirtschaftlichkeit, Heidelberg, S. 205–222; 1995.
[SiKS98]
Silberschatz, A.; Korth, H. F.; Sudarshan, S.: Database System Concepts; 3 Auflage; McGraw-Hill, Inc., New York, USA; 1998.
[Sinz88]
Sinz, J. Elmar: Das Strukturierte Entity-Relationship-Modell; In: Angewandte Informatik. 5 (1988), S. 191–202.
[Sinz93]
Sinz, J. Elmar: Datenmodellierung im Strukturierten Entity-RelationshipModell; In: Fachliche Modellierung von Informationssystemen. G. MüllerEttrich (Hrsg.), Addison-Wesley Publishing Company, Bonn u.a., S. 64–126; 1993.
[SmSm77]
Smith, J. M.; Smith, D. C. P.: Database Abstractions: Aggregation and Generalizations; In: ACM Transactions on Database Systems (TODS), Vol. 2, Nr. 2, (1977), S. 195–133.
[Soft98]
Sonderheft „Requirements Engineering“; IEEE Software; March/April 1998.
[Stay76]
Stay, J. F.: HIPO and Integrated Program Design; IBM Systems Journal 15; 1976.
[Stei99]
Steiner, R.: Theorie und Praxis relationaler Datenbanken, Eine grundlegende Einführung für Studenten und Datenbankentwickler; 3. Auflage, Vieweg Verlag, Braunschweig, Wiesbaden; 1999.
[StHa99]
Stahlknecht, P.; Hasenkamp, U.: Einführung in die Wirtschaftsinformatik; 9. Auflage, Springer-Verlag Berlin, Heidelberg, New York; 1999.
[Ston86]
Stonebraker, M. (Hrsg.): The INGRES Papers: Anatomy of a Relational Database System; Addison-Wesley Publishing Company, Reading u.a., MA; 1986.
660
Literaturverzeichnis
[Swam89]
Swami, A.: Optimization of Large Join Queries: Combining Heuristics and Combinational Techniques; Proc. ACM Int. Conf. on Management of Data (SIGMOD), S. 367–376, Portland, OR, USA; 1989.
[Teor91]
Teorey, T. (Ed.): Conceptual Modeling – ER’91; Proc. 10. Int. Conf. on EntityRelationship Approach (ER’91). ER Institute, Pittsburgh (CA), Participants’ Proceedings (dieser Konferenzband ist im Eigenverlag erschienen.) 1991.
[Teor98]
Teorey, T.: Database Modeling and Design: The Fundamental Principles. 3. Auflage; Morgan Kaufmann Publishers, Inc., San Mateo, CA; 1998.
[TeYF86]
Teorey, T.J.; Yang, D.; Fry, J. P.: A Logical Design Methodology for Relational Databases Using the Extended Entity-Relationship Model; In: ACM Computing Surveys, Vol. 18, Nr. 2 (1986), S. 197–222.
[Thal96]
Thalheim, B. (Ed.): Conceptual Modeling – ER’96. 15. Int. Conf. on Conceptual Modeling, Cottbus, Germany. Proceedings: Lecture Notes in Computer Science, Vol. 1157, Springer-Verlag Berlin, Heidelberg, New York; 1996.
[Thal00]
Thalheim, B.: Entity-Relationship Modeling. Foundations of Database Technology. Springer Verlag, Heidelberg 2000.
[Thom79]
Thomas, R. H.: A Majority Consensus Approach to Concurrency Control for Multiple Copy Databases; In: ACM Transactions on Database Systems (TODS), Vol. 4, Nr. 2 (1979).
[Trai83]
Traiger, I.: Trends in System Aspects of Database Management; Proc. 2nd Int. Conf. on Databases (ICOD-2), Cambridge; 1983.
[TWBK89] Teorey, T.J.; Wei, G.; Bolten, D.L.; Koenig, J.A.: ER Model Clustering as an Aid for User Communication and Documentation in Database Design; In: Communications of the ACM, Vol. 32, Nr. 8 (1989), S. 975–987. [Ullm88]
Ullman, J. D.: Principles of Data and Knowledge-Base Systems; Bd. I; Computer Science Press, Woodland Hills, CA, USA; 1988.
[Ullm89]
Ullman, J. D.: Principles of Data and Knowledge Bases; Bd. II; Computer Science Press, Woodland Hills, CA, USA; 1989.
[UML97a]
Unified Modeling Language, UML Semantics; version 1.1, alpha R6, July 1997. http://www.rational.com.
[UML97b]
Unified Modeling Language, Notation guide; version 1.1, alpha 6, (1.1 c) July 1997. http://www.rational.com.
[Unla85]
Unland, R.: Optimistische Synchronisationsverfahren und ihre Leistungsfähigkeit im Vergleich zu Sperrverfahren; Dissertation, FernUniversität Hagen; 1985.
[Vand88]
van der Lans, R.: Das SQL Lehrbuch; Addison-Wesley Publishing Company, Reading u.a., MA; 1988.
Literaturverzeichnis
661
[ViRT82]
Vinek, G.; Rennert, P. F.; Tjoa, M.: Datenmodellierung: Theorie und Praxis des Datenbankentwurfs; Physica-Verlag, Würzburg; 1982.
[VoGr93]
Vossen, G.; Groß-Hardt, M.: Grundlagen der Transaktionsverarbeitung; Addison-Wesley Publishing Company, Bonn u.a.; 1993.
[Voss00]
Vossen, G.: Datenbankmodelle, Datenbanksprachen und Datenbankmanagementsysteme; 4. Auflage; Oldenbourg-Verlag München Wien; 2000.
[VoWei01]
Vossen, G.; Weikum, G.: Fundamentals of Transactional Information Systems; Morgan Kaufmann; 2001.
[WäRe90]
Wächter, H.; Reuter, A.: Grundkonzepte und Realisierungsstrategien des ConTract-Modells; In: Informatik Forschung und Entwicklung, 5 (1990), S. 202–212.
[WäRe92]
Wächter, H.; Reuter, A.: The ConTract Model; In[Elma92]; 1992.
[Weik88]
Weikum, G.: Transaktionen in Datenbanksystemen; Addison-Wesley Publishing Company, Bonn u.a.; 1988.
[Yang86]
Yang, C.: Relational Databases; Prentice Hall, Englewood Cliffs, NJ, USA; 1972.
[Yao85]
Yao, S. Bing: Principles of Database Design; Bd. 1.; Prentice Hall, Englewood Cliffs, NJ, USA; 1985.
[YoCo79]
Yourdan, E.; Constantine, L.: Structured Design. Fundamentals of a Discipline of Computer Program and Systems Design; 3. Ed., Prentice Hall, Englewood Cliffs, NJ, USA; 1979.
[Zloo75]
Zloof, M. M.: Query-By-Example; In: Proc. of the National Computer Conference, S. 431–437; Arlington, VA; AFIPS Press; 1975.
[Zloo77]
Zloof, M. M.: Query-By-Example: A Database Language; In: IBM Systems Journal, Vol. 16, Nr. 4 (1977), S. 324–343.
Sachverzeichnis 4GL, siehe Programmiersprache der 4ten Generation ==-Operator, siehe Identitätsvergleich =-Operator, siehe Gleichheitsvergleich abgeleitete Relation, siehe Relation, abgeleitete abgeleitete Spalte, siehe Spalte, abgeleitete Abgeschlossenheit, 211, 234 abhängiges Objekt, 504 abhängiges Unterobjekt, siehe Unterobjekt, abhängiges Abhängigkeit funktionale, 142, 147 mehrwertige, 147 voll funktionale, 153 von Transaktionen, 589 wechselseitige, 589 Abhängigkeitsgraph, 590, 591, 600 Abhängigkeitsmenge, 149 Abhängigkeitstreue, 145 Ablaufintegrität, siehe Integrität, operationale Abschnitt kritischer, 611 Abstrakter Zeilentyp, 531 Abtraktionskonflikt bei der Sichtenintegration, 125 ACID-Kriterium, 582, 592, 618, 622 ADD-Befehl, 314 After-Image, 627, 630 Aggregatfunktion, 257, 333, 334, 373, 379, 396 Probleme mit, 338 Aggregation, 69, 79 im ERM, 78 Akteure im DFD, 45
Aktion eines Triggers, 442 Aktivitätsdiagramm, 103 Algebra, 212, 214 einsortige, 212, 214 mehrsortige, 212, 214 relationale, siehe Relationenalgebra Algorithmus CLOSURE, 149 LEFTRED, 152 MEMBERSHIP, 149 MERGE, 157 NONRED, 152 NORMALIZATION, 157 REDUCE, 152, 159 RIGHTRED, 152 Aliasname, 331, 346, 360, 389 Alles-oder-Nichts-Prinzip, 636, 638 ALL-Option, 328 Allquantifizierung, 240, 242, 246 Allquantor, 240 ALPHA, 237 ALTER COLUMN-Befehl, 314 ALTER DOMAIN-Befehl, 314 ALTER TABLE-Befehl, 314 Analyse Bottom-Up, 51 Inside-out, 54 Mischform, 54 mit Datenflussdiagrammen, 43 statische, 6, 41 Top-down, 48 Änderung verloren gegangene, 579 Anforderung Bearbeitungs-, 17 dynamische, 16, 61 funktionale, 16, 42 Informations-, 15, 16, 33, 37, 38
664 Anforderungsanalyse, 6 Anforderungsdokument, 15, 31, 32, 60 eindeutiges, 31 einfaches, 31 konsistentes, 31 korrektes, 31 vollständiges, 31 Anforderungserhebung, 6 Beobachtungsmethode, 30 Berichtsmethode, 30 Dokumentenanalyse, 26 Fragebogentechnik, 28 Interviewmethode, 29 Selbstaufschreibung, 30 Anfrage, 244 Abarbeitung einer, 458 geschachtelte, 385 parametrisierte, 460 sichere, 248 sichere im Bereichskalkül, 251 Anfragealgebra, 212, 214 Anfragebearbeitung, 189, 457 Anfrageergebnis, 206 Anfragekalkül, 212 Anfragekomponente, 189 interaktive, 189 Anfrageoptimierung, 460 Anfrageprozessor, siehe Anfragekomponente Anfragesprache, 24, 197, 207, 211, 212, 257 Anforderungen an, 207 deklarative, 208 deskriptive, 208 Funktionsweise, 211 für objektorientierte DBMS, 211 nichtprozedurale, 208 prozedurale, 208 sichere, 209, 248 Anomalie, 142 Änderungs-, 144 Einfüge-, 144 Lösch-, 144 ANSI/X3/SPARC-Architekturmodell, 23 Anwendungsfalldiagramm, 103, 108 in UML, 107 Anwendungsneutralität, 418
Sachverzeichnis Anwendungsunabhängigkeit, 209 ANY-Prädikat, siehe Prädikat, ANY Äquivalenz von Abhängigkeitsmengen, 151 Architektur eines DBMS, siehe Datenbankmanagementsystem, Architektur von Architektur integrierter Informationssysteme, 116 Area einer DB, 595 ARIS, 116 arithmetischer Ausdruck, 332 Armstrong-Axiome, 143, 149 ARRAY-Typkonstruktor, 479, 505 AS-Klausel, 331 assertions, siehe Zusicherung Assoziation, 36, 69, 101 Atom im Bereichskalkül, 249 im Tupelkalkül, 241 Atomarität, 591, 619, 622 Attribut, 34, 72, 99, 135, 269 identifizierendes, 36 in SQL 1999, 484 -menge, identifizierende, 135 -wert, 34, 135 Attributselektion, 220 Attributtyp, 485 Auditing, 430 Ausdruck bedingter, siehe Prädikat logischer, siehe Prädikat sicherer im Tupelkalkül, 248 Ausführungsplan, 459 Ausgangsrelation, 206, 211, 238 Ausgangsschedule, 588 Ausgangstabelle, 326, 333, 339 abgeleitete, 329 Ausprägung, 199, 484 Aussage in der Aussagenlogik, 364 Aussagenlogik, 364 Ausschluss gegenseitiger, 603 äußerer Verbund, siehe Verbund, äußerer Authentisierung, 430
Sachverzeichnis Autorisierung, 430 AVG-Funktion, 257, 333, 409 Backus-Naur Syntaxnotation, 270 Bag, siehe Multimenge Basisrelation, 206 BCNF, 145 Bearbeitungsanforderung, 6, 16, 57 bedingter Ausdruck, siehe Prädikat Bedingung komplexe, siehe Prädikat selektive, 350 Bedingungsblock, 246 Bedingungsteil eines Triggers, 442 Bedingungsverbund, 347, 349 Before-Image, 627 benannte Relation, 206 benannter Tupeltyp, siehe Zeilentyp, benannter benannter Zeilentyp, siehe Zeilentyp, benannter benutzerdefinierter strukturierter Datentyp, siehe Zeilentyp, benannter Benutzungsoberfläche, 455 Beobachtungsmethode, 30 Bereichskalkül, 237, 249 Bereichsvariable, 249 Bericht, 456 Berichtsgenerator, 456 Berichtsmethode, 30 Beschreibungsebene in ARIS, 117 BETWEEN-Prä¬di¬kat, siehe Prädikat, BETWEEN Beziehungsarten zwischen Objekten, 503 Beziehungsintegrität, 297 Beziehungstyp, 36, 70 binärer, 75, 172 Grad, 36, 72 Kardinalität, 37, 74 optionaler, 36 rekursiver, 36, 171 total, 71 totaler, 36
665 Transformation von, 171 Zusammenführung von, 128 Binary Large Object, siehe BLOBDatentyp Binden dynamisches, 518, 541 statisches, 541 Bindephase, 189 Binder, 189 BIT VARYING-Datentyp, 275 bitbasierter Datentyp, 272, 275 BIT-Datentyp, 275 BLOB-Datentyp, 275, 475 BOOLEAN, 277 BOOLEAN-Datentyp, 197, 474 Bottom-Up-Analyse, 51 Breitendurchlauf, 444 Breitensuche, 565 Built-in Funktion, siehe Aggregatfunktion Business Process Reengineering, 115 CAST-Operator, 294 Character Large Object, siehe CLOBDatentyp CHARACTER VARYING-Datentyp, 275 CHARACTER-Datentyp, 197, 275 Checkpoint, 629 aktionskonsistenter, 630, 631 transaktionskonsistenter, 630 unscharfer, 630, 632 Varianten von, 630 chronologischer Datentyp, 272, 273 Client-Server-System, 621 CLOB-Datentyp, 475 CLOSE-Befehl, 452 Clusterung, 276, 295, 436 Codd Regeln von, 448 Coercion, 202, 231 Compiler, siehe Übersetzer concurrency control, siehe Synchronisation constraints, siehe Tabellenzusicherungen COUNT-Funktion, 257, 333 Crash (Systemzusammenbruch), 628, 629 CREATE DATABASE-Befehl, 272 CREATE DOMAIN-Befehl, 287
666 CREATE INDEX-Befehl, 436 CREATE SCHEMA-Befehl, 272 CREATE TABLE-Befehl, 296, 482, 493, 495 CREATE TRIGGER-Befehl, 443, 562, 563 CREATE TUPLE-Befehl, 482, 495 CREATE VIEW-Befehl, 420, 434 CROSS JOIN-Klausel, 339 Cursor, 451 data blades, 476 data cartridges, 476 Data Dictionary, 192 data extender, 476 Data Link, 570 Data Links File Manager, 570 Data Links Filesystem Filter, 570 Data Repository, 193 data type distinct, siehe Datentyp, individualisierter DATE-Datentyp, 273, 274 Dateisystem, 18, 25 Dateiverwaltung, 191 integrierte, 19 isolierte, 19 Datenabhängigkeit logische, 21 physische, 19, 21 Datenabstraktion, 502, 517, 518, 543 Datenbank, 11 inkonsistente, 580, 587 materialisierte, 354, 619 relationale, 192 verteilte, 570 Datenbankanfragesprache, 326 Datenbankanomalie, 143 Datenbankentwurf formaler, 134, 141 konzeptueller, 65 Datenbankmanagementsystem, 11, 18 aktives, 561 Architektur von, 21, 187 Datenbankmodell, 11, 202, 210 relationales, 8, 135, 169, 192, 202, 211
Sachverzeichnis Datenbanknutzer, 12 Datenbankprogrammiersprache, 472 Datenbankprozedur, 203, 299, 438, 440, 497, 498, 572 Datenbankpuffer, 191, 619 Datenbankschema, 11 Ändern des, 314 externes, siehe Sicht internes, 187, 192 konzeptuelles, 187, 192, 418 Datenbanksprache, 12, IX relationale, 261 Datenbanksystem, 11 Datenbankzustand konsistenter, 299, 582, 631, 634 Datendefinitionssprache, 189, 271 Datenfluss, 43, 46, 92 Datenflussdiagramm, 43 Datenspeicher im, 45 Prozess im, 44 Wertfluss im, 46 Datenintegrität, 437 Datenkonsistenz, 437 Datenkontrollsprache, 429 Datenmanipulationssprache, 412 maskenorientierte, 455 Datenmodell, 10 konzeptuelles, 1, 67, 165 logisches, 1, 9 physisches, 1 sematisch, 66 sematisches, 68 Datenredundanz, 20 Datenschutz, 437 Datensicherheit, 265, 419, 422, 424, 429, 431, 432, 444, 566 Datensicherheit und Fehlertoleranz, 24 Datensicherung, 437 Datensicht, siehe Sicht Datenspeicher im DFD, 44 Datenstruktur logische, 521 Datentyp, 197, 198, 473 abstrakter, 471, 474 abstrakter in SQL:1999, 495, 517 atomarer, 199
Sachverzeichnis benutzerdefinierter, 493 benutzerdefinierter strukturierter, siehe Zeilentyp, benannter bitbasierter, 272, 275 BLOB, 275 BOOLEAN, 474 built-in, 473, siehe Datentyp, vordefinierter chronologischer, 272, 273 Datetime-, 275 individualisierter, 473, 493, 531 komplexer, 482 LOB, siehe LOB-Datentyp mengenwertiger, 201 numerischer, 272 strukturierter, 200, 495 vordefinierter, 473 zeichenbasierter, 272, 275 Zeit-, 273 Zeitintervall-, 274 Zeitstempel-, 273 Datentypkonversion, 294 Datenunabhängigkeit logische, 419, 423, 449 physische, 449 Datenwert einwertiger, 492 mehrwertiger, 492 Datetime-Datentyp, 275 Dauerhaftigkeit, 583, 622 DBMS, siehe Datenbankmanagementsystem DBS, siehe Datenbanksystem DCL, siehe Datenkontrollsprache DDL, siehe Datendefinitionssprache Deadlock, 602, 603, 635 Auflösung, 603 Erkennung, 604 Verhinderung, 603 Vermeidung, 603 DECIMAL-Datentyp, 272 DEFAULT-Klausel, 288 Dekompensationsverfahren, 141 DELETE-Befehl, 307, 317, 412, 417, 433 Dereferenzierung, 526 Destruktor, 100 DETERMINISTIC-Klausel, 499
667 DFD, 43 D-Grundschema, 90 Dienstprogramm, 24 Differenz, 139, 218, 254, 403 Diskriminator, 101 distinct data type, siehe Datentyp, individualisierter DISTINCT-Option, 328, 336 Division, 140, 221 DML, siehe Datenmanipulationssprache Dokumentenanalyse, 26 Domäne einer Formel, 248 Domino-Effekt, siehe Rollback DOUBLE PRECISION, 272 Drei-Ebenen-Schemaarchitektur, 187 DRL, siehe Anfragesprache DROP COLUMN-Befehl, 314 DROP CONSTRAINT-Befehl, 314 DROP DATABASE-Befehl, 272 DROP SCHEMA-Befehl, 272 DROP-Befehl, 316 DSDL, siehe Speicherungsstrukturdefinitionssprache Dump, 635 aktionskonsistenter, 635 transaktionskonsistenter, 635 unscharfer, 635 Duplikate, 446 Duplikateliminierung, 330 Durchführbarkeitsstudie, 15 Durchlässigkeit eines Schedulers, 588, 591, 612 Durchschnitt, 139, 218, 402 dynamisches Binden, 518, 541, 544 Dynamisches SQL, 454 ECA-Regel, 443, 561 ECR-Modell, 83 Effizienz, 209 Einattributindex, 191 Einbettung statische, siehe SQL, statische Einbettung Einfachvererbung, 528, 543 Einschränkung, 147 einwertiger Datenwert, 492
668 Elterntransaktion, 638 Embedded SQL, 450 encapsulation, siehe Kapselung Entity, 34, 72 Entity-Category-Relationship-Modell, 83 Entity-Relationship-Modell, 8, 66 Grundlagen des, 69 Entitytyp, 35, 72 schwacher, 74 Transformation von, 170 Entitytypen Zusammenführung von, 126 Entwicklungsdiagramm, 103 Entwicklungstransaktion, 643 Entwurf logischer, 9, 169, 180 Equiverbund, siehe Gleichverbund Ereignis, 96, 97, 99, 113 eines Triggers, 442 Ereignisabfolgediagramm, 57 Ergebnisrelation, 206, 211, 238, 245 Ergebnisschedule, 588 Ergebnistabelle, 326 ERM, 78 E-SQL, siehe Embedded SQL EVERY-Operator, 474 exception handling, 450 EXECUTE-Befehl, 454 Existenzquantifizierung, 240, 242 Existenzquantor, 240 EXISTS-Prädikat, siehe Prädikat, EXISTS exklusives Objekt, 504 externe Routine, 499 externes Schema, siehe Schema, externes FD, 142 Fehlerbehandlung, 622 Fehlertoleranz, 24, 577, 583, 618 Feld in SQL:1999, 484 Feldtyp, 485 FETCH-Befehl, 452 F-Grundschema, 90 FINAL-Klausel, 494, 531 FLOAT-Datentyp, 272 force, 624 FOREIGN KEY-Klausel, 307
Sachverzeichnis Formel im Bereichskalkül, 249 im Tupelkalkül, 241 wohlgeformte, siehe Prädikat, wohlgeformtes Formulierungsunabhängigkeit, 209, 456 Probleme mit, 330 von SQL, 447 fortgepflanztes Rollback, siehe Rollback, fortgepflanztes Fourth Generation Languages, siehe Programmiersprache der 4ten Generation Fragebogentechnik, 28 Fragmentierung interne, 277 FREE-Statement, 476 Fremdschlüssel, 136, 306, 315 Fremdschlüsselkonzept in SQL:1999, 511 Fremdserver, 570 Fremdtabelle, 570 FROM-Klausel, 385 Unteranfrage in der, 390 Funktion, 498 in SQL:1999, 497 Funktionsanalyse, 6 Funktionsmodell, 2, 11, 43, 66 gemeinsames Objekt, 504 Generalisierung, 69, 80 in UML, 106 Geschäftsprozess, 115, 116 Geschäftsregel, 297 geschlossen geschachtelte Transaktion, siehe Transaktion, geschlossen geschachtelte Gleichheit, 487 von Werten/Objekten, 505 Gleichverbund, 222, 223, 227, 230, 343, 358 Grad eines Beziehungstyps, 36, 72 GRANT-Befehl, 432 GROUP BY-Klausel, 373, 390 Grundsatz der Klarheit, 68
Sachverzeichnis der Relevanz, 67 der Richtigkeit, 67 der Vergleichbarkeit, 68 der Wirtschaftlichkeit, 68 des systematischen Aufbaus, 68 Gruppe, siehe Spalte, zeilenwertige Gruppenfunktion, siehe Aggregatfunktion Hauptspeicherrecoveryereignis, siehe Recoveryereignis, HauptspeicherHaupttabelle, 309, 452 HAVING-Klausel, 377 Unteranfrage in der, 389 Hierarchical Input, Process, Output, 56 HIPO, 56 Historie, siehe Schedule HOLD-Statement, 476 Host-Sprache, siehe Wirtssprache Hot spot, 596 Hülle von FD, 149 Identifikation, 430 Identität, 487 von Werten/Objekten, 505 impedance mismatch, 256, 451, 499 Implementationsdiagramm, 103 Implementationsphase, 9 individualisierter Datentyp, siehe Datentyp, individualisierter Inferenzregeln für FD, 148 INGRES, 237 inkonsistente Datenbank, siehe Datenbank, inkonsistente innerer Verbund, 346 IN-Prädikat, siehe Prädikat, IN INSERT-Befehl, 413, 433 Inside-out-Analyse, 54 INSTANTIABLE-Klausel, 531 Instanz, 199, 484 Instanzmethode, 519 INTEGER-Datentyp, 197, 272 Integrität operationale, 298, 582, 586, 593, 594, 621 referenzielle, 303, 306, 307, 310, 311, 316, 438, 455 semantische, 298, 437, 582
669 Integritätsbedingung, 198, 299, 302, 305, 307, 310, 315, 324, 354, 413, 416, 438, 448, 449, 455 allgemeine, 298, 438 dynamische, 298 spaltenbezogene, 297 statische, 298 tabellenbezogene, 298, 302, 315, 440 tabellenübergreifende, 440 Integritätsverletzung, 310, 583 Behandlung von, 310 interne Optimierung, siehe Optimierung, interne interne Routine, 499 internes Schema, siehe Datenbankschema, internes Interpreter, 189 INTERSECT-Operator, 402 INTERVAL, 273, 274 Interviewmethode, 29 INTO-Klausel, 476 Intratransaktionsparallelität, 641 IS-A-Beziehung, 80 ISOLATION, 613 Isolation, 581, 583, 598, 614, 643 Isolationsstufe, siehe Konsistenzstufen Iterator, 100 Java Database Connectivity, siehe JDBC Java Sprachanbindung, 571 JDBC, 571 Join, siehe Verbund Junktor logischer, siehe Operator, logischer Kalkül, 237 Kapselung, 502, 517 in SQL 1999, 495 Kardinalität, 37, 72, 74 von Beziehungstypen, 74 Kartesisches Produkt, siehe Produkt, Kartesisches kaskadierendes Recoveryereignis, siehe Recoveryereignis, kaskadierendes Katalog, 193
670 Kindtransaktion, 638 Klasse, 502 Klassendiagramm in UML, 104 Klassenmethode, 519 in SQL:2011, siehe statische Methode Klassifikation, 69, 99 Kollaborationsdiagramm in UML, 111 Kollektionstyp, 478 Kommunikations-Recoveryereignis, 621 Kompensation, 635, 642 Kompensationstransaktion, 584, 636, 644 komplexer Datentyp, 482 komplexer Zeilentyp, 504 Komponentendiagramm, 103 Konflikt, 589 bei Operationen, 589 Konsistenz, 22, 583 Konsistenzstufen, 602, 614 Konsistenzüberwachung, 24 Konsolidierungsphase bei der Sichtenintegration, 126 Konstantenselektion, 219 Konstruktor, 100 Konstruktor-Methode, 519 Kontextdiagramm, 48, 90 Kontrollsphäre, 638 konzeptuelle Optimierung, siehe Optimierung, konzeptuelle konzeptueller Datenbankentwurf, 65 konzeptuelles Schema, siehe Schema, konzeptuelles kooperative Arbeitsweise, 643 Korrektheit semantische, 298 Kostenmodelle, 460 kritischer Abschnitt, siehe Abschnitt, kritischer Large Object, siehe LOB-Datentyp legacy data, 570 Lesen nicht wiederholbares, 579, 580, 614 schmutziges, 614 wiederholbares, 615
Sachverzeichnis Lesephase, 608 Leseset, 609 Lesesperre, 594 Lesetransaktion, 614 Livelock, 602, siehe Starvationproblem LOB-Datentyp, 471, 474, 569 Locator, 476 LOCK, 598 Logarchiv, 628, 635 Logdatei, 625, 628 Logdateieintrag logischer, 627 physischer, 627 Logfile, siehe Logdatei logischer Ausdruck, siehe Prädikat logischer Entwurf, 169 Logpuffer, 627 lost update, siehe Änderung, verloren gegangene Mächtigkeit, 255, 256 Maskeneditor, 455 Maskengenerator, siehe Maskeneditor materialisierte Datenbank, siehe Datenbank, materialisierte MAX-Funktion, 257, 333 Mehrattributindex, 191, 464 Mehrbenutzerbetrieb, 24 Mehrfachanforderung, 603 mehrwertiger Datenwert, 492 Mengenfunktion, siehe Aggregatfunktion Mengenoperation, 214 in SQL, 401 Mengenoperationen, 215 Metadaten, 187, 192 Methode, 99, 517 in SQL:1999, 497, 517 Instanzen-, 519 Konstruktor-, 519 originale, 519 PRIVATE, 525 PROTECTED, 525 statische, 519 überschreibende, 519, 531 METHOD-Klausel, 518 MIN-Funktion, 257, 333 minimale Überdeckung, 151
Sachverzeichnis Modellbildung funktionsorientierte, 42 geschäftsprozessorientierte, 115 objektorientierte, 96 struktur- und funktionsorientierte, 89 strukturorientierte, 68 Modifikator, 100 Multimedia, 569 Multimenge, 268, 328 multiple-granularity locking, 596 Nachricht, 100 Namenskonflikt bei der Sichtenintegration, 124 NATURAL JOIN-Klausel, 344 natürlicher Verbund, siehe Verbund, natürlicher NCLOB-Datentyp, 475 NEW-Klausel, 520 Nichtentziehbarkeit, 603 Normalform, 142 Bestimmung der, 156 Boyce-Codd, 145, 155 dritte (3NF), 145, 155 erste (1NF), 144, 155, 478 vierte (4NF), 155 zweite (2NF), 144, 155 Normalisierung, 146, 147, 155 NP-vollständiges Problem, 303, 457, 460, 591 Nullmarke, 285, 287 in Booleschen Ausdrücken, 370 in skalaren Ausdrücken, 369 in Vergleichen, 369 Probleme mit, 446 NULL-Prädikat, 367, siehe Prädikat, NULL Nullwert, 287, siehe Nullmarke NUMERIC-Datentyp, 272 numerischer Datentyp, 272 Nutzdaten, 192 Oberklasse, 502 Oberschlüssel, 154 Obertyp, 199 Object Query Language (OQL), 257, 471 Objekt, 34, 99, 502
671 abhängiges/unabhängiges, 504 gemeinsames/exklusives, 504 komplexes, 502 komplexes im objektrelationalen SQL, 550 Objekte externe, 571 komplexe, 503 Objektidentität, 489, 502 in SQL:1999, 510 Objektmodell, 97 integriertes, 11 Objektorientierte Konzepte in SQL:2011, 502 Objektsemantik, 509 Objekttyp, 35, 97, 98 generischer, 80 ODBC, 447 ODMG, 256 offen geschachtelte Transaktion, siehe Transaktion, offen geschachtelte OLAP, 566 ON-Klausel, 345, 347 Online Analytical Processing, siehe OLAP OPEN-Befehl, 452 Operation, 44, 97, 99 atomare, 578 auf Datentyp, 197, 198 auf Relationen, 138 generische, 208 operationale Integrität, siehe Integrität, operationale Operator logischer, 366 Operatorbaum, 458 Optimierbarkeit, 209 Optimierung, 209, 235, 460 algebraische, siehe Optimierung, logische interne, siehe Optimierung, physische konzeptuelle, siehe Optimierung, logische logische, 234, 457, 461 physische, 457, 463
672 über dynamische Informationen, 460 über statische Informationen, 460 OQL, 257, 471 ORDER BY-Klausel, 375, 404 originale Methode, 519 Orthogonalität, 210 OUTER JOIN-Klausel, 350 OVERLAPS-Prädikat, siehe Prädikat, OVERLAPS Overloading, siehe Überladen, einer Routine OVERRIDING METHOD, 519, 531 Parallelarbeit Probleme der, 578 Parameter zusätzlicher, 517 PARAMETER STYLE-Klausel, 499 parametrisierte Anfrage, 460 partielles Zurücksetzen, siehe Rollback, partielles partizipative Systemanalyse, 15 Persistenz, 24 Pfadausdruck, 487, 490, 526, 527 Pfeilnotation, 490, 527 Phantom, 581 Phantomproblem, 580, 581, 602, 605, 606, 614, 615 physische Optimierung, siehe Optimierung, physische physisches Schema, siehe Datenbankschema, internes Polymorphismus, 100, 101, 503, 541 POSITION-Operation, 477 Prädikat, 280, 356, 364, 365, 392 ANY, 395 BETWEEN, 280 binäres, 393 EXISTS, 253, 393, 397, 403 IN, 281, 393 LIKE, 282 mengenorientiertes, 392 NULL, 367 OVERLAPS, 283 quantifizierendes, 394 SOME, 395
Sachverzeichnis unäres, 393 Vergleichs-, 394 wohlgeformtes, 241 Prädikatsperren, 605 Prädikattabelle, 606 Preclaiming, 601 Precompiler, siehe Vorübersetzer PREPARE-Befehl, 454 Primärdaten, 619 Primärindex, 191, 464 Primärschlüssel, 136, 304, 372 Primärschlüsselkonzept in SQL:1999, 511 PRIMARY KEY-Klausel, 304 Produkt Kartesisches, 139, 215, 254, 339, 340, 358 Programmbibliothek, 497 Programmgenerator, 454 Programmiersprache vollständige, 499 Programmiersprache der 4ten Generation, 455 Programmsegment, siehe Skript Projektion , 139, 220, 234, 235, 254, 327 Protokollierung logische, 625 physische, 627 Prototyping, 3 Prozedur, 498 externe, 499 in SQL:1999, 497 Prozess, 16, 43, 96 Pseudotransitivität, 149 Puffer, siehe Datenbankpuffer Punktnotation, 527 QBE, 255 QUEL, 237, 244, 255, 257 Query By Example, siehe QBE query evaluation engine, (Anfrageverarbeitung), 189, 209, 234 Query-Prozessor, siehe Anfragekomponente RANGE-Block in QUEL, 244
Sachverzeichnis read unrepeatable, siehe Lesen, nicht wiederholbares REAL-Datentyp, 197, 272 Rechte Weitergabe von, 435 Widerruf von, 435 Rechtevergabe, 432 Recovery, 619, siehe auch Fehlertoleranz Recoveryereignis, 620, 622, 625 Hauptspeicher-, 621 kaskadierendes, 621 Kommunikations-, 621 Sekundärspeicher-, 622, 624, 634 Transaktions-, 621 Umgebungs-, 621 Recoverykomponente, 583, 619, 622 Recoverymaßnahme, 624, 642 REDO, 623, 630, 631, 635 Redundanz, 19, 20 REF IS . . . -Klausel, 510 REFERENCES-Klausel, 433 Referenzielle Integrität, siehe Integrität, referenzielle referenzierbare Tabelle, siehe Tabelle, referenzierbare Reflexivität, 149 REF-type, siehe REF-Typkonstruktor REF-Typkonstruktor, 471, 481, 482, 487, 502, 505 Rekonstruktion, 634 Rekursion, 471, 565 Relation, 192, 269 abgeleitete, 206, 448 Ausgangs-, 206 Basis-, 206 benannte, 206 Ergebnis-, 206 gespeicherte, 206 materialisierte, 206 Operationen auf, 138 Schnappschuss-, 207 Typ von, 205 virtuelle, 206 Zwischen-, 206 relational vollständig, 234
673 relationale Algebra, siehe Relationenalgebra relationale DBMS Charakteristika, 448 Relationen Eigenschaften von, 136 -modell, 135 -schema, 135 Relationenalgebra, 138, 214, 234, 235, 255 Basisoperationen, 216, 217 Eigenschaften der, 234 minimaler Repräsentant, 235 zusätzliche Operationen, 219 Relationenkalkül, 237 Mächtigkeit, 254 Relationenschema, 203, 204 Relationentheorie, 147 Relationentyp, 203–205 Report Generator, siehe Berichtsgenerator RESTRICT-Option, 314 RETRIEVE-Block in QUEL, 244 RETURNS-Klausel, 498 REVOKE-Befehl, 435 Rollback, 628 fortgepflanztes, 592, 600, 621 partielles, 633 Rolle, 37, 72, 104 Rollenkonzept in SQL:1999, 566 Router, 616 Routine, 498 externe, 499 interne, 499 ROW-Typkonstruktor, 471, 481, 482, 502, 505 Rücksetzpunkt, 633 SA/SD, 55 SADT, 56 SAGA, 644 savepoint, siehe Sicherungspunkt Schedule, 586 serialisierbare, 587 serielle, 586 Scheduler, 588, 594, 614 Schema, siehe Datenbankschema
674 externes, 188, 192, siehe Sicht konzeptuelles, siehe Datenbankschema, konzeptuelles physisches, siehe Datenbankschema, internes Schemaarchitektur, 187 Schemakonsolidierung, 120 Schematransformation, 46, 141, 157, 170 Schemazusicherung, 299 Schichtenarchitektur, 23 Schlüssel, 154 identifizierender, 304 systemvergebener, 510, 511 Schlüsselattribut, 36 Schlüsselkandidat, 136, 154, 295, 304, 315, 372, 436 Schnappschussrelation, 207 Schnappschussvalidation, 610 mit kritischem Abschnitt, 611 ohne kritischen Abschnitt, 612 Schreibphase, 609 Schreibset, 609 Schreibsperre, 594 Schrumpfungsphase, 599 SCOPE-Klausel, 489 Segment einer Datenbank, 595 Sekundärindex, 191, 436 Sekundärspeicherrecoveryereignis, siehe Recoveryereignis, SekundärspeicherSelbstaufschreibung, 30 Selbstverbund, 360 SELECT-FROM-WHERE-Block, siehe SFW-Block SELECT-Klausel, 327, 344, 381, 397, 407, 433 Unteranfrage in der, 389 Selektion, 138, 139, 219, 234, 254, 326, 364 WHERE-Klausel, 364 Selektionsbedingung, 211, 239 selektiv, 350 Selektivität, 222, 225 Selektor, 100 SELF-Parameter, 517 semantische Integrität, siehe Integrität, semantische
Sachverzeichnis semantische Korrektheit, siehe Integrität, semantische Semantisches Objektmodell, 118 Semiverbund, siehe Verbund, SemiSEQUEL, 261 Sequenzdiagramm in UML, 110 serialisierbar, 584 strikt, 585 Serialisierbarkeit, 584, 593, 599 Serialisierbarkeitskriterium, 590 Serialisierbarkeitstheorie, 584, 585 SERM, 81 SET-Klausel, 415 SFW-Block, 266, 327 Benennung von, 564 Sicherungspunkt, 471, 569, 633 Sicht, 188, 194, 206, 317, 418, 419, 426, 448 Änderungen auf, 426 inkonsistente, 579, 602 Löschen auf, 428 mengenreduzierende, 421 Probleme mit, 424 spaltenverändernde, 421 Verbund-, siehe Verbundsicht Vorteile von, 423 Sichtbarkeitskonzept von Methoden, 525 Sichtenintegration, 8, 120 Signatur, 199 Single-Server-Modell, 616 Skript, 455 SMALLINT-Datentyp, 272 SOM, 118 SOME-Operator, 474 Spalte, 269 abgeleitete, 329, 331, 332, 425 Benennung von, 331 Umbenennung von, 331 virtuelle, 329 zeilenwertige, 492 Spaltenfunktion, siehe Aggregatfunktion Spaltennamenverbund, 345, 348, 349 Speichermanager, 24, 189, 191 Speicherungsstrukturdefinitionssprache, 436
Sachverzeichnis Speicherungsstrukturen, 187 Sperre exklusive, siehe Schreibsperre gemeinsame, siehe Lesesperre IS, 597 IX, 597 Lese-, siehe Lesesperre logische, siehe Prädikatsperren physische, 605 Schreib-, siehe Schreibsperre SIX, 597 über Prädikate, siehe Prädikatsperren Sperrgranulat, 594 Sperrhierarchie, 595 Sperrmanager, 604 Sperrmodus, 594 Sperrprotokoll, 598 Sperrtabelle, 605 Sperrverfahren, 593, 594 Sprachanbindung Java, 571 Sprachansätze, 211 Sprachumfang schlanker, 210 SQL, 261 1999, 264, 470 Dynamisches, siehe Dynamisches SQL Einordnung, 265 Embedded, 450, siehe Embedded SQL Entwicklung, 264 Historie, 261 statische Einbettung, 450 Untergliederung, 265 SQL/MED, 570 SQL/MM, 569 SQL-92 kritische Würdigung von, 445 SSL (Speicherungsstrukturdefinitionssprache), 260, 436, 464 S-Sperre, siehe Lesesperre Standardmaske, 455 Starvationproblem, 602 statische Analyse Vorgehensweise, 41
675 statische Einbettung, siehe SQL, statische Einbettung statische Methode, 519 statisches Binden, 541 steal, 624 Stored Procedure, siehe Datenbankprozedur streng relational vollständig, 234 strikt serialisierbar, siehe serialisierbar, strikt Structured Analysis and Design Technique, 56 Structured Analysis, Structured Design, 55 Structured Query Language, siehe SQL Strukturanalyse, 6 strukturierter Datentyp, siehe Datentyp, strukturierter Strukturiertes Entity-Relationship-Modell (SERM), 81 Strukturkonflikt bei der Sichtenintegration, 124 Subjektparameter, 517 Substituierbarkeit, 491, 541, 544 SUBSTRING-Operation, 477 Subtransaktion, 636, 638, 640–643 Subtypenhierarchie, 80, 81 SUM-Funktion, 257, 333 superkey, 154 Surrogat, 510 Symmetrie, 208 Synchronisation, 577 in SQL-92, 613 Synchronisationsverfahren, 584, 593 optimistisches, 593, 608 pessimistisches, 593 präventives, siehe Synchronisationsverfahren, pessimistisches verifizierendes, siehe Synchronisationsverfahren, optimistisches Systemanalyse partizipative, 26 Systemarchitektur, 189 Systemkatalog, 192 Systemneustart, 628
676 systemvergebener Schlüssel, siehe Schlüssel, systemvergebener Szenario, 57, 109 Tabelle, 269 abgeleitete, 373 ändern, 315 Anlegen einer, 295 Benennung von, 360 referenzierbare, 488 typisierte, 483, 495, 503, 543 virtuelle, 419, 426 Tabellenhierarchie, 532, 543 in SQL:1999, 528 Tabellentypspezifikation in SQL:2011, siehe ROW-Typkonstruktor Tabellenzusicherung, 298 Tabellenzusicherungen, 564 Terminator, 45 Testen statistisches, 3 Thetaverbund, siehe Verbund, ThetaThread, 616 Tiefendurchlauf, 443 Tiefensuche, 565 TIME-Datentyp, 273 Time-out, 604 TIMESTAMP-Datentyp, 273, 274 Top-level-Transaktion, 638 TP-Monitor, 615 transaction processing monitor, siehe TPMonitor Transaktion, 12, 57, 582 geschachtelte, 569, 637 geschlossen geschachtelte, 641, 642 globale, 617 lange, 633 offen geschachtelte, 642 wirkungslose, 590 wohlgeformte, 599 zweiphasige, 599, 602, 642 Transaktionen verkettete, 634 Transaktionsanalyse, 6, 58 Transaktionskonzept, 582 Transaktionsmanagement, 191, 577
Sachverzeichnis Transaktionsprofil, 596 Transaktions-Recoveryereignis, siehe Recoveryereignis, TransaktionsTransaktionssystem Fehler im, 620 Transitivität, 149 Trigger, 438, 442, 471 in SQL 1999, 560 Triggergranularität, 561 Tupel, 135, 269 Tupelkalkül, 237, 239 formale Definition, 241 Tupelkonstruktor, siehe auch ROWTypkonstruktor Tupelrelationenkalkül, siehe Tupelkalkül Tupelspezifikation, siehe ROW-Typkonstruktor Tupeltyp, siehe ROW-Typkonstruktor benannter, siehe Zeilentyp, benannter Tupelvariable, 239, 245 freie, 240 gebundene, 240 Typfehler, 541 Typhierarchie, 199, 529, 532, 543 in SQL:1999, 528 typisierte Sicht, 537–541 typisierte Tabelle, siehe Tabelle, typisierte typkompatibel, siehe Typkompatibilität Typkompatibilität, 201, 204, 229, 231 Typkonstruktor, 200, 201, 477 ARRAY, 479, 505 in SQL:1999, 477 REF, 487 ROW, 482 Typsicherheit, 541 Typsystem, 256 Typumwandlung, 202 Überdeckung minimale, 151 Überladen einer Routine, 499 Überschreiben einer Routine, 518 überschreibende Methode, 519, 531 Übersetzer, 189
Sachverzeichnis Umbenennung, 229, 232 Umgebungs-Recoveryereignis, siehe Recoveryereignis, UmgebungsUML, 101 unabhängiges Objekt, 504 UNDER-Klausel, 529 UNDO, 623, 630, 631, 635 Unified Modeling Language, 101 UNION, siehe Vereinigung UNION JOIN, siehe Vereinigungsverbund UNIQUE-Klausel, 304 Universaltabelle, 266 UNLOCK, 598 unrepeatable read, siehe Lesen, nicht wiederholbares Unteilbarkeit, 583 Unteranfrage, 337, 360, 361, 385, 388, 393, 395, 397, 398, 400 korrelierende, 398, 400 mengenorientierte, 392 nicht korrelierende, 399 wertliefernde, 391 Unterklasse, 502 Unterobjekt, 503 abhängiges, 504 Untertabelle, 309, 338, 373, 386, 407, 452 Untertyp, 199 UPDATE-Befehl, 307, 415, 433 USING-Klausel, 345, 349 Validationsphase, 608 VALUES-Klausel, 413 Vaterobjekt, 503, 504 Verbund, 139, 222, 343, 355 alter Art, 339, 358 äußerer, 225, 350, 358 äußerer Semi-, 227 eingeschränkter, 229 linker äußerer, 226, 227, 343 natürlicher, 140, 224, 227, 343, 344, 358 rechter äußerer, 226, 227, 343 Semi-, 227 Theta-, 140, 223, 227, 230, 343 über mehrere Tabellen, 356
677 uneingeschränkter, 229 vollständiger äußerer, 226, 227, 343, 353 Verbundbedingung selektive, 222, 225 Verbundsicht, 421 Verbundtreue, 145 Verletzung von, 145 Vereinigung, 139, 149, 215, 254, 401 Vereinigungsverbund, 343, 355 Vererbung, 80, 100, 199, 494, 502, 528, 529, 541 selektive, 84 Vererbungshierarchie in SQL:1999, 528 Vergleichsphase bei der Sichtenintegration, 123 Vergleichsprädikat, 365, 394 quantifizierendes, 394 Verhalten eines Objektes, 502 Verhaltensdiagramme, 103 Verhaltenskonflikt bei der Sichtenintegration, 125 Verifikation formale, 3 Verklemmung, siehe Deadlock verteilte Datenbank, 570 Verweis typisierter, 488, 491 Verweistyp, siehe REF-Typkonstruktor in Anfragen, 526 virtuelle Relation, siehe Relation, virtuelle Vollständigkeit, 210 relationale, 234 streng relationale, 234 Vorrangregeln der SQL-Operatoren, 408 Vorübersetzer, 189, 450 Vorwärtsrecovery, 642 Vorwärtsvalidation, 611 Wachstumsphase, 599 Wahrheitsdatentyp, siehe BOOLEANDatentyp WAL-Prinzip, 627
678 Warnsperre, 596 Sperrmodi von, 597 Wartegraph, 604 Warte-und-Halte-Fest, 603 Weak-Entitytyp, 74 Wertebereich, 197, 198, 205, 212, 287 anwendungsspezifischer, siehe Wertebereich, benutzerdefinierter benutzerdefinierter, 287, 493 einer Tupelvariablen, 245 Wertebereichdefinition ändern, 315 Wertebereichsbedingung, 238 Wertebereichseinschränkung, 289 Wertesemantik, 485, 509 wff, siehe Prädikat, wohlgeformtes WHERE-Block in QUEL, 244 WHERE-Klausel, 341, 351, 362, 364 Unteranfrage in der, 388 Wiederholungsgruppe, 493 Wiederverwendung, 528 Wirtssprache, 376 Einbettung in, siehe Embedded SQL WITH OPTIONS SCOPE-Klausel, 489 Wohlgeformtheit, 599 Wrapper für Fremddaten, 570 X-Sperre, siehe Schreibsperre zeichenbasierter Datentyp, 272, 275 Zeigertyp, 471 Zeile, 269 Ändern von, 415 Einfügen von, 413 Löschen von, 417 Zeilenkonstruktor, 393, 493 Zeilentyp, 296, 471, 481 abstrakter, 531 benannter, 474, 483, 495, 505, 518, 529, 543 Definition eines, 483 in Anfragen, 526 komplexer, 504 zeilenwertige Spalten, 492 Zeit-Datentyp, 274 Zeitintervall-Datentyp, 274
Sachverzeichnis Zeitmarke, 607 Zeitstempel-Datentyp, 273 Zeitstempelverfahren, 593, 607 Zerlegung, 149 abhängigkeitstreue, 157 attributerhaltende, 157 gültige, 157 horizontale, 219 verbundtreue, 157 vertikale, 221 Zerlegungssichten in ARIS , 116 Zugriffskontrolle, 430 Zugriffspfad, 187, 191, 436 Zugriffsrecht, 448 Zurücksetzen einer Transaktion, siehe Rollback Zusammenführungsphase bei der Sichtenintegration, 126 Zusicherung, 438 Zustandsdiagramm in UML, 112 Zweiphasen-Freigabeprotokoll, 617 Zweiphasen-Sperrprotokoll, 599, 604, 642, 643 striktes, 601 Zweiphasensperrprotokoll striktes, 602 zweiphasig, 599, 602, 642 Zwischenrelation, 206 Zwischentabelle, 407