Funktionale Abhängigkeiten in PostgreSQL

Werbung
TECHNISCHE UNIVERSITÄT CAROLO-WILHELMINA ZU BRAUNSCHWEIG
Bachelorarbeit
Funktionale Abhängigkeiten in
PostgreSQL-Datenbanken Informationssystem
Julian Timpner
4. September 2009
Institut für Informationssysteme
Prof. Dr. Wolf-Tilo Balke
betreut durch:
PD Dr. habil. Karl Neumann
Eidesstattliche Erklärung
Hiermit erkläre ich an Eides statt, dass ich die vorliegende Arbeit selbstständig verfasst und keine anderen als die angegebenen Hilfsmittel verwendet habe.
Braunschweig, 4. September 2009
Zusammenfassung
Funktionale Abhängigkeiten sind ein wesentliches Konzept der relationalen Datenbanktheorie und der Normalisierung. Daher ist es für Studierende besonders wichtig,
funktionale Abhängigkeiten trotz ihres hohen Abstraktionsgrades zu verstehen und
ihren Nutzen für qualitativ hochwertige Datenbankentwürfe zu verinnerlichen. Zu
diesem Zweck wird ein Informationssystem entwickelt, das funktionale Abhängigkeiten in einer Datenbank darstellen und manipulieren kann, um Studierenden ein
interaktives Werkzeug für den Lernprozess zur Verfügung zu stellen. Darüber hinaus
unterstützt das entwickelte System die Bewertung und automatische Normalisierung
von Datenbankschemata durch geeignete Algorithmen. Diese Bachelorarbeit liefert
die theoretischen Grundlagen der für das Verständnis nötigen Konzepte, sowie zu ausgewählten Aspekten der Implementierungssprache Java und JDBC. Relevante Problemstellungen für das Informationssystem werden aufgezeigt und Lösungsstrategien
entwickelt, die in einem systematischen Entwurfsprozess umgesetzt und dokumentiert
werden.
Stichwörter Funktionale Abhängigkeiten, Normalisierung, Zerlegungsalgorithmus, Synthesealgorithmus, Informationssystem, Trigger, Integritätsbedingungen, PostgreSQL, Java,
SQL, JDBC.
Inhaltsverzeichnis
Verzeichnis der Tabellen
ix
Verzeichnis der Abbildungen
x
Listings
xi
Verzeichnis der Abkürzungen
xii
1. Einleitung
1
2. Allgemeine Grundlagen
2.1. Das relationale Modell
2.2. SQL . . . . . . . . . .
2.3. Java . . . . . . . . . .
2.4. JDBC . . . . . . . . .
.
.
.
.
3
3
4
5
6
3. Funktionale Abhängigkeiten
3.1. Grundlegende Definitionen . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Normalisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
11
14
4. Konzeptioneller Entwurf
4.1. Ziele . . . . . . . . . . . . . . . . . . .
4.2. Leistungsumfang . . . . . . . . . . . .
4.3. Lösungsansätze . . . . . . . . . . . . .
4.3.1. Darstellung von FAen (/F110/)
4.3.2. FA hinzufügen (/F200/) . . . .
4.3.3. Normalisierung (/F300/) . . . .
.
.
.
.
.
.
17
17
17
21
21
24
25
.
.
.
.
.
.
.
28
28
28
29
29
31
32
32
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5. Systementwurf
5.1. Projektdetails . . . . . . . . . . . .
5.2. Analyse der Produktfunktionen . .
5.3. Analyse von Funktionalität /F100/
5.3.1. Grobanalyse . . . . . . . . .
5.3.2. Feinanalyse . . . . . . . . .
5.4. Komponentenspezifikation . . . . .
5.5. Technische Produktumgebung . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
vii
Inhaltsverzeichnis
6. Implementierung
6.1. Model-View-Controller . . . . . . . . . . . . . . . .
6.2. Klassendiagramme . . . . . . . . . . . . . . . . . .
6.2.1. Implementierung von Komponente Control
6.2.2. Implementierung von Komponente DBTools
6.2.3. Implementierung von Komponente FD . . . .
6.2.4. Implementierung von Komponente GUI . . .
6.3. User Interface Design . . . . . . . . . . . . . . . . .
6.4. Externe Bibliotheken . . . . . . . . . . . . . . . . .
6.4.1. Swing Application Framework . . . . . . . .
6.4.2. SwingLabs SwingX . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
34
34
34
35
35
37
38
38
42
42
43
7. Zusammenfassung und Ausblick
7.1. Bewertung . . . . . . . . . . .
7.1.1. Szenario 1: Anzahl von
7.1.2. Szenario 2: Anzahl von
7.2. Fazit . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
44
44
44
45
47
. . . . . . .
Relationen
Attributen
. . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Literatur
48
Sachwortregister
50
A. Detaillierter UML-Entwurf
A.1. Analyse von /F110/ und /F120/ .
A.2. Analyse von /F200/ . . . . . . .
A.3. Analyse von /F210/ . . . . . . .
A.4. Analyse von /F300/ . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
52
52
53
55
59
B. Bedienungsanleitung
62
C. Schnittstellenspezifikation
66
viii
Verzeichnis der Tabellen
7.1. Laufzeit in Abhängigkeit der Relationen . . . . . . . . . . . . . . . .
7.2. Laufzeit in Abhängigkeit der Attribute . . . . . . . . . . . . . . . . .
45
45
C.1. Schnittstellenspezifikation Normalizable . . . . . . . . . . . . . . . .
C.2. Schnittstellenspezifikation IStatement . . . . . . . . . . . . . . . . .
66
67
ix
Verzeichnis der Abbildungen
x
2.1. Java Runtime Environment . . . . . . . . . . . . . . . . . . . . . . .
2.2. JDBC Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
7
4.1. Anwendungsfälle des Informationssystems . . . . . . . . . . . . . . .
4.2. fd_catalog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
24
5.1.
5.2.
5.3.
5.4.
Statechart Projektdetails . . .
Verteilung von /F100/ . . . .
Sequenzdiagramm für /F100/
Komponentenentwurf . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
29
30
31
32
6.1.
6.2.
6.3.
6.4.
6.5.
Klassendiagramm Control
Klassendiagramm DBTools
Klassendiagramm FD . . .
Klassendiagramm GUI . .
GUI . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
36
37
39
40
41
7.1. Heap Dump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2. Objekt-Allokation . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
46
A.1.
A.2.
A.3.
A.4.
A.5.
A.6.
A.7.
A.8.
Verteilung von /F110/ und /F120/ . . . .
Sequenzdiagramm für /F110/ und /F120/
Verteilung von /F200/ . . . . . . . . . . .
Sequenzdiagramm für /F200/ . . . . . . .
Verteilung von /F210/ . . . . . . . . . . .
Sequenzdiagramm für /F210/ . . . . . . .
Verteilung von /F300/ . . . . . . . . . . .
Sequenzdiagramm für /F300/ . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
52
53
54
56
57
58
59
61
B.1.
B.2.
B.3.
B.4.
Systemstart . . . . . . . . . . .
Verbindungsaufbau . . . . . . .
Hinzufügen/Entfernen von FAen
Normalisierung . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
62
63
64
65
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Listings
2.1.
2.2.
2.3.
2.4.
Definition einer Relation in SQL
SQL-Beispielanfrage . . . . . .
Vorkompilierte SQL-Anfrage . .
Transaktionen in SQL . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
8
9
10
3.1. Closure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Kanonische Überdeckung . . . . . . . . . . . . . . . . . . . . . . . . .
13
13
4.1. SQL-Assertion zur Realisierung einer FA . . . . . . . . . . . . . . . .
4.2. Member . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3. SQL-Query zum dynamischen Kopieren . . . . . . . . . . . . . . . . .
22
25
25
7.1. Heap Space Exception . . . . . . . . . . . . . . . . . . . . . . . . . .
45
xi
Verzeichnis der Abkürzungen
API
BSD
DBMS
FA
FD
GUI
JDBC
JRE
JSP
JSR
MVC
MVD
NF
SQL
xii
Application Programming Interface
Berkeley Software Distribution
Datenbankmanagementsystem
Funktionale Abhängigkeit
Functional Dependency
Graphical User Interface
Java Database Connectivity
Java Runtime Environment
JavaServer Pages
Java Specification Request
Model-View-Controller
Multivalued Dependencies
Normalform
Structured Query Language
1 Einleitung
Relationale Datenbanken wurden bereits 1970 von Edgar F. Codd in [Cod70] als ein
Modell elektronischer Datenverwaltung vorgeschlagen. Im Gegensatz zu den damals
vorherrschenden Datenmodellen, nämlich dem Netzwerkmodell und dem hierarchischen Modell, ist das relationale Modell sehr einfach strukturiert und vergleichsweise
flexibel zu handhaben. Dies ist darauf zurückzuführen, dass nur einfache Tabellen
(Relationen) verwendet werden, in denen die Zeilen die Datenobjekte definieren. Die
gespeicherten Daten werden durch entsprechende Operatoren mengenorientiert verknüpft. Die Einfachheit dieses Ansatzes führte zu einer starken Verbreitung relationaler Datenbanken und heute sind diese ein etablierter Standard mit einer nahezu
marktbeherrschenden Stellung.
Daher verwundert es nicht, dass das relationale Modell in der Informatik ein integraler Bestandteil der Hochschulausbildung ist. In der relationalen Entwurfstheorie,
die sich mit dem konzeptionellen Entwurf der Datenschemata beschäftigt, spielen
dabei insbesondere die funktionalen Abhängigkeiten eine wichtige Rolle. Mit ihrer
Hilfe lassen sich sogenannte Normalformen definieren, die die Grundlage für einen
qualitativ hochwertigen Datenbankentwurf bilden.
Die Konzepte der funktionalen Abhängigkeiten und der Normalisierung dürfen
daher während der Ausbildung nicht vernachlässigt werden. Da sie jedoch relativ
abstrakt sind, fällt ihre Vermittlung an Studierende oft nicht leicht. Besonders für
Studierende am Anfang ihrer Ausbildung, die abstraktes Arbeiten nicht gewohnt
sind, ist es daher wichtig, die Bedeutung der funktionalen Abhängigkeiten praktisch
und zielorientiert vermittelt zu bekommen.
Im Rahmen dieser Bachelorarbeit wird daher ein Werkzeug entwickelt, mit dem
bestehende funktionale Abhängigkeiten in Datenbanken ausgelesen und angezeigt
werden können. Auf dieser Basis bestimmt das Werkzeug den Normalisierungsgrad
der Datenbank und ermöglicht es, durch Manipulation (d. h. Hinzufügen und Entfernen) der funktionalen Abhängigkeiten die Auswirkungen auf den Normalisierungsgrad zu verfolgen und so leichter nachzuvollziehen. Außerdem kann der Benutzer
eine gewünschte (in der Regel höhere als die aktuelle) Normalform auswählen und
diese durch geeignete Normalisierungsverfahren herstellen. Die Theorie und Implementierung dieser Verfahren sind Gegenstand von [Mei09]. Insgesamt bietet sich das
Werkzeug somit neben dem Einsatz als computergestütztes Trainingssystem auch für
die Beurteilung und Verbesserung von Datenbankschemata an. Im Folgenden wird
dieses Werkzeug als Informationssystem bezeichnet.
Die Art der Implementierung des entwickelten Informationssystems in Java bietet
1
1. Einleitung
außerdem die Möglichkeit, Studierenden das Konzept der relationalen Anfragesprache
SQL im Allgemeinen und ihren praktischen Einsatz über die Programmierschnittstelle JDBC1 im Speziellen zu vermitteln. Zu diesem Zweck lässt sich der Programmcode
als Dokumentation heranziehen.
Das Informationssystem arbeitet plattformunabhängig und ist im Wesentlichen in
der Lage, mit einer Vielzahl von Datenbanksystemen verschiedener Hersteller zusammenzuarbeiten, sofern diese den SQL-99-Standard umsetzen. Da jedoch alle Datenbankhersteller jeweils spezifische Besonderheiten in ihren Systemen implementieren
und nur teilweise zum SQL-Standard konform sind, kann nur für ein ausgewähltes
Datenbanksystem, nämlich PostgreSQL, volle Unterstützung gewährleistet werden.
PostgreSQL ist ein unter BSD-Lizenz stehendes, und damit freies, objektrelationales
Datenbankmanagementsystem. Es wurde ursprünglich ab 1977 an der University of
California, Berkeley von Michael Stonebraker als eines der ersten relationalen Datenbanksysteme (damals unter dem Namen Ingres) entwickelt. Heute ist PostgreSQL
quelloffen und wird von einer aktiven Entwicklergemeinschaft fortwährend weiterentwickelt. PostgreSQL gilt als besonders standardkonform zu ANSI-SQL-92 und -99,
und wurde nicht zuletzt deshalb ausgewählt.
Der Aufbau dieser Arbeit stellt sich nach Kapiteln wie folgt dar: eine Einführung
in die theoretischen Grundlagen des relationalen Modells, der Anfragesprache SQL
sowie der verwendeten Implementierungssprache Java (inklusive der benutzen Datenbankschnittstelle JDBC) erfolgt zu Beginn der Arbeit in Kapitel 2.
In Kapitel 3 wird die Theorie der funktionalen Abhängigkeiten sowie die darauf
aufbauende Normalisierung ausführlich behandelt.
In Kapitel 4 erfolgt der konzeptionelle Entwurf des Informationssystems, bestehend aus einer Beschreibung des Funktionsumfangs und Lösungsansätzen für die
sich daraus ergebenden Fragestellungen.
Die Analyse des Funktionsumfangs und die Ableitung der Komponenten des Informationssystem wird in Kapitel 5 vorgenommen.
Kapitel 6 beschreibt daraufhin die resultierende Software-Architektur, verwendete
Bibliotheken sowie den Entwurf der grafischen Benutzeroberfläche.
In Kapitel 7 erfolgt ein abschließendes Resümee mit kritischer Beurteilung und ein
Ausblick auf mögliche Weiterentwicklungen.
1
2
Java Database Connectivity
2 Allgemeine Grundlagen
Dieses Kapitel führt in die Themen ein, die für das Verständnis der funktionalen
Abhängigkeiten sowie der im Entwurf und der Implementierung eingesetzten Konzepte wichtig sind. Zuerst wird das relationale Modell vorgestellt, das die Grundlage
für alle in dieser Arbeit behandelten Konzepte und Fragestellungen ist. Anschließend
erfolgt eine Beschreibung der Anfragesprache SQL zum Auslesen und Manipulieren
von Datensätzen. Schließlich wird gezeigt, wie die Datenbankschnittstelle JDBC der
Java-Plattform eine einheitliche und herstellerunabhängige Realisierung von SQLAnfragen bietet.
2.1. Das relationale Modell
Das Relationenmodell ist das heute am weitesten verbreitete Datenbankmodell, obwohl seine Ursprünge bereits auf eine Veröffentlichung von Codd aus dem Jahr 1970
[Cod70] zurückgehen. Diese Tatsache lässt sich auf seine Einfachheit und Exaktheit
zurückführen, weshalb es sowohl in der Praxis etabliert, als auch seit langem Gegenstand weitreichender Forschungen ist. Aufgrund seines Bekanntheitsgrades soll hier
nicht ausführlich darauf eingegangen werden, sondern nur die wesentlichen Aspekte
und Definitionen für die weitere Arbeit vorgestellt werden. Somit kann eine einheitliche Schreibweise eingeführt und unterschiedlichen Interpretationen entgegengewirkt
werden.
Eine relationale Datenbank besteht aus einer Sammlung von Relationen mit eindeutigem Namen. Seien n Wertebereiche (auch Domänen genannt) D1 , D2 , . . . , Dn
gegeben. Im Folgenden wird vorausgesetzt, dass diese Domänen nur atomare Werte
enthalten. Praktische Beispiele hierfür sind Standarddatentypen wie integer, boolean
oder string. Dann ist eine Relation R definiert als Teilmenge des kartesischen Produkts dieser n Domänen:
R ⊆ D1 × D2 × · · · × Dn
Ein Element der Menge R wird als Tupel bezeichnet. Ein Tupel besteht aus einer Menge von Attributwerten. Den Attributen werden die oben genannten Wertebereiche, die Domänen, zugeordnet. Für eine Relation R legt sein Relationenschema R die Anzahl und den Typ (d. h. die Domänen) der Attribute fest. R bezeichnet somit das Schema der Relation und R deren momentane Ausprägung (Instanz). Mit dom(A) wird die Domäne eines Attributs A bezeichnet. Eine Menge
S = {R1 , R2 , . . . , Rm } , m ∈ ℕ heißt Datenbankschema.
3
2. Allgemeine Grundlagen
Das Relationenschema R lässt sich um eine Menge B von Integritätsbedingungen
erweitern, die festlegen, welche Tupel zulässig sind und welche nicht. Das Paar (R, B)
wird als erweitertes Relationenschema bezeichnet. Ein Beispiel für Integritätsbedingungen sind Schlüssel, die als Spezialfall von funktionalen Abhängigkeiten in Kapitel
3 vorgestellt werden.
2.2. SQL
SQL (Structured Query Language) ist die Datenbanksprache zur Definition, Manipulation und Abfrage in relationalen Datenbanksystemen. Sie ist von der internationalen Normungsorganisation ISO (International Standardization Organization) und
der amerikanischen Normungsorganisation ANSI (American National Standards Institute) standardisiert und wird heute von allen großen kommerziellen und freien
relationalen Datenbanksystemen unterstützt.
SQL zeichnet sich durch eine einfache, der englischen Umgangssprache angelehnten
Syntax aus und umfasst vier unterschiedliche Sprachteile: einen Daten- und Sichtdefinitionsteil, einen Anfrageteil, einen Datenänderungsteil und einen Teil, der für die
Rechteverwaltung verantwortlich zeichnet.
An dieser Stelle werden die genannten Sprachteile beispielhaft erläutert. Für weitergehende Informationen zum SQL-Sprachumfang siehe [SSH08, SKS05].
Data Definition Language Als sogenannte Datendefinitionssprache (engl. Data
Definition Language, kurz DDL) stellt SQL eine Reihe von Anweisungen zur Verfügung, mit denen die Struktur von Daten definiert werden kann. Diese lassen sich
nach der Drei-Ebenen-Schemaarchitektur folgendermaßen ordnen:
• Auf der externen Ebene können mittels CREATE VIEW Sichten definiert werden.
• Auf der konzeptionellen Ebene werden mit CREATE TABLE Relationen angelegt.
Eine typische Anweisung, die die (fiktive) Relation Student mit den Attributen
MatrNr und Name erstellt und im Katalog der Datenbank ablegt, ist in Listing
2.1 zu sehen. Dort werden hinter den Namen der Attribute deren Domänen,
d. h. ihre Datentypen, sowie weitere Integritätsbedingungen (PRIMARY KEY, NOT
NULL) angegeben.
1
2
3
4
CREATE TABLE Student (
MatrNr int NOT NULL PRIMARY KEY,
Name varchar(50) NOT NULL
)
Listing 2.1: Definition einer Relation in SQL
4
2.3. Java
• Mit CREATE INDEX können auf der internen Ebene Zugriffspfade angelegt werden.
Data Manipulation Language Die Data Manipulation Language, kurz DML, ist
für die Manipulation der Daten (hinzufügen, ändern oder löschen von Datensätzen)
zuständig. Das Einfügen eines Tupels in die zuvor erstellte Relation Student erfolgt
beispielsweise mit:
INSERT INTO Student(289000, ’Albert Einstein’);
Data Query Language Die Data Query Language, kurz DQL, dient der Datenabfrage. So gibt der folgende Befehl den Namen des Studenten mit der Matrikelnummer
289000 aus:
SELECT Name FROM Student WHERE MatrNr = 289000;
Data Control Language Als letzter Teil dient die Data Control Language, kurz
DCL, dazu, Zugriffsrechte an Benutzer zu vergeben, zurückzunehmen usw.
REVOKE SELECT,UPDATE ON TABLE Student FROM einstein;
Dieser Befehl entzieht dem Benutzer einstein das Recht, den Inhalt der Relation
Student zu lesen oder zu verändern.
2.3. Java
Die Implementierung dieser Arbeit ist in Java Version 6 geschrieben. Java ist eine
objektorientierte Programmiersprache, die 1995 von Sun Microsystems als Kernkomponente der Java-Plattform veröffentlicht wurde. Obwohl sie seit Veröffentlichung
kostenlos zu beziehen ist, steht sie seit Mai 2007 auch als freie Software unter der
GNU General Public License zur Verfügung.
In Java geschriebene Programme werden typischerweise in sogenannten Bytecode
kompiliert. Dieser kann in einer speziellen Umgebung, der Java Runtime Environment (JRE) ausgeführt werden. Deren wichtigster Bestandteil ist die Java Virtual
Machine (JVM), die die Programme ausführt, indem der Bytecode interpretiert wird.
Die Java Runtime Environment schirmt Java-Programme dabei gegen die unterliegende Betriebssystem- und Hardware-Architektur ab, sodass sie ohne Anpassungen
auf jedes beliebige System portierbar sind, sofern für dieses System eine JRE existiert. Neben der JVM beinhaltet die JRE auch eine umfangreiche Klassenbibliothek,
womit Programmierern eine gut dokumentierte API (Programmierschnittstelle, engl.
Application Programming Interface) angeboten wird. Abbildung 2.1 verdeutlicht die
genannten Zusammenhänge. Ausführlichere Informationen zur Java-Programmierung
sind in [SK08, Ull09], sowie unter http://java.sun.com zu finden.
5
2. Allgemeine Grundlagen
Abbildung 2.1.: Java Runtime Environment
2.4. JDBC
Ein Bestandteil der Standard-API von Java ist die Java Database ConnectivitySchnittstelle, kurz JDBC. Dieses ist eine einheitliche Schnittstelle zu relationalen
Datenbanken verschiedener Hersteller und in ihrer Funktion vergleichbar mit ODBC
unter Windows oder DBI unter Perl. Zu ihren Aufgaben gehört es, Datenbankverbindungen aufzubauen, zu verwalten und SQL-Anfragen an die Datenbank weiterzuleiten. Die zurückgelieferten Ergebnisse werden entgegengenommen und in eine für Java
nutzbare Form umgewandelt. Dies ist insbesondere wichtig, da SQL und die meisten
Programmiersprachen im Allgemeinen auf unterschiedlichen Verarbeitungsparadigmen beruhen: während SQL mengenorientiert arbeitet, fehlt den meisten Hochsprachen ein solches Konzept. Sie arbeiten hauptsächlich satz- oder objektorientiert. Dies
führt zu einer umständlichen Anwendungsprogrammierung, im Englischen auch Impedance Mismatch genannt. JDBC versucht, diesen so gering wie möglich zu halten,
indem es Programmierschnittstellen auf hohem Abstraktionsniveau bereitstellt.
Um eine Datenbankverbindung via JDBC herzustellen, sind Datenbank-spezifische
Treiber erforderlich, die meist vom Hersteller des jeweiligen Systems geliefert werden.
Es existieren vier verschiedene Typen von Treibern, die in Abbildung1 2.2 dargestellt
sind. Der in dieser Arbeit verwendete Treiber ist vom Typ 4, d. h. er ist komplett
in Java geschrieben und bietet somit größtmögliche Plattformunabhängigkeit. Der
Treiber wandelt die JDBC-API-Befehle direkt in Befehle des unterliegenden DBMS,
in diesem Fall PostgreSQL, um und überträgt diese an den Datenbankserver, ohne
beispielsweise auf eine Middleware-Schicht aufzubauen.
JDBC besteht aus einer Vielzahl von Klassen und Schnittstellen, die im Package
java.sql zusammengefasst sind. Die wichtigsten Klassen zur Anwendungsprogram1
6
Abbildung in Anlehnung an http://java.sun.com/products/jdbc/overview.html
2.4. JDBC
Abbildung 2.2.: JDBC Architektur
mierung sind dabei:
• java.sql.DriverManager lädt die Treiber und stellt Verbindungen her.
• java.sql.Connection repräsentiert eine Verbindung zum Datenbankserver.
• java.sql.Statement ermöglich es, SQL-Anfragen über eine Verbindung auszuführen.
• java.sql.ResultSet verwaltet die Ergebnis-Tupel einer Anfrage und stellt Zugriffsmethoden auf diese zur Verfügung.
Im Folgenden werden die wesentlichen Aspekte der JDBC-Programmierung demonstriert (vgl. [SSH08, KE06]) und deutlich gemacht, welche Konstrukte in der
Implementierung dieser Arbeit eine besondere Rolle spielen.
Verbindungsaufbau Bevor ein Java-Programm mit der Datenbank kommunizieren
kann, muss zunächst eine Verbindung aufgebaut werden. Im Java-Package java.sql
ist hierfür der DriverManager enthalten, der die JDBC-Treiber verwaltet. Damit der
DriverManager eine Verbindung aufbauen kann, muss der notwendige JDBC-Treiber
(in diesem Fall für PostgreSQL) geladen werden. Dies erfolgt über den Ausdruck:
Class.forName("org.postgresql.Driver");
7
2. Allgemeine Grundlagen
Danach kann die Verbindung (vom Typ Connection) hergestellt werden. Zu diesem
Zweck stellt der DriverManager die Methode getConnection zur Verfügung, die als
Parameter eine URL für die Adresse der Datenbank, einen Benutzernamen und ein
Passwort erwartet. Der Aufruf dieser Methode liefert im Erfolgsfall ein ConnectionObjekt zurück:
Connection con = DriverManager.getConnection(url, user, password);
Anfrageausführung Mit dem erstellten Connection-Objekt kann nun eine SQLAnweisung erzeugt und abgesetzt werden. Dies soll anhand des folgenden kleinen
Beispiels erläutert werden.
1
2
3
4
5
6
7
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (rs.next()) {
int x = rs.getInt("a");
String s = rs.getString("b");
float f = rs.getFloat("c");
}
Listing 2.2: SQL-Beispielanfrage
Zunächst muss man ein Statement-Objekt generieren, wofür Connection die Methode createStatement bereitstellt. Das so erzeugte Statement-Objekt stellt nun
Methoden für Anfrage- und Änderungsoperationen zur Verfügung. Die Methode
executeQuery erwartet als Argument einen SQL-Ausdruck und erzeugt ein Objekt
vom Typ ResultSet. Das ResultSet stellt eine Iterator-Schnittstelle für den Zugriff
auf die Menge der Ergebnistupel der übergebenen SQL-Anfrage dar, und bietet neben
dem Zugriff mittels next() auf das nächste Element auch weitergehende Mechanismen an. Hierzu gehören u. a. erweiterte Möglichkeiten zur Navigation in der Ergebnismenge, z. B. durch frei positionierbare ResultSets. Dies mildert das beschriebene
Problem des Impedance Mismatch etwas ab.
In Listing 2.2 erfolgt zu Demonstrationszwecken der Funktionsweise nur eine einfache Iteration durch die Ergebnismenge in einer while-Schleife. Mit rs.getInt(“a“)
greift man auf den Integer-Wert des Attributs a des derzeit aktuellen Ergebnistupels
zu. Analog erfolgt der Zugriff auf die Attribute b und c, nur dass diese unterschiedliche Datentypen haben. Statt über den Namen des Attributs kann ein Zugriff auch
über die Position des Attributs stattfinden, z. B. mit rs.getInteger(“1“). In diesem Fall erfolgt die Nummerierung in der Reihenfolge, in der die Attribute in der
Select-Klausel der SQL-Anweisung angegeben sind.
Nach der Verarbeitung der Ergebnismenge sollte noch sowohl das Statement, als
auch die Verbindung mittels close() geschlossen werden, um den reservierten Speicher wieder freizugeben und die Performance zu verbessern.
8
2.4. JDBC
Metadaten Das Informationssystem, das im Rahmen dieser Arbeit entwickelt wurde, hat die Besonderheit, dass es mit beliebigen und insbesondere vorher nicht bekannten Relationenschemata zusammenarbeiten muss. In diesen Fällen können die
Attributnamen und -typen nicht fest kodiert werden, sondern müssen dynamisch aus
dem Datenbankkatalog ausgelesen werden. Deshalb bietet das ResultSet auch Methoden, um auf die Metadaten zuzugreifen und so die Struktur der Ergebnistupel zu
erfragen, die in einem ResultSetMetaData-Objekt zur Verfügung gestellt wird:
ResultSetMetaData rsm = rs.getMetaData();
Über dieses Objekt lassen sich etwa die Anzahl der Attribute einer Relation als
rsm.getColumCount() oder der Typ des i-ten Attributs als rsm.getColumnType(i)
abfragen.
Vorkompilierte SQL-Anweisungen Um die Effizienz der Bearbeitung von SQLAnweisungen zu erhöhen, ist es möglich, häufig auszuwertende Anfragen nur einmal
zu übersetzen und wiederzuverwenden. Denn im Regelfall werden Anweisungen jedesmal von neuem übersetzt und optimiert, was zu Leistungseinbußen führen kann.
Wenn Anweisungen mehrfach, jedoch mit unterschiedlichen Parametern aufgerufen
werden, können PreparedStatements eingesetzt werden, um dieses Problem zu vermeiden. PreparedStatements enthalten statt Parameterwerten nur Platzhalter, die
mit einem ? notiert werden.
1
2
3
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET SALARY
= ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00);
pstmt.setInt(2, 110592);
Listing 2.3: Vorkompilierte SQL-Anfrage
Listing 2.3 zeigt diese Vorgehen.2 Das PreparedStatement wird nur einmal deklariert und über set-Methoden, die für jeden Datentyp existieren, können die einzufügenden Parameterwerte angegeben und ausgetauscht werden. Dabei entspricht
der erste Parameter der set-Methode der relativen Position der ?-Zeichen im SQLAusdruck.
Transaktionen Transaktionen sind ein wesentliches Konzept zur Sicherstellung der
Integrität einer Datenbank. JDBC ist standardmäßig im sogenannten Auto-CommitModus, d. h. dass jedes einzelne SQL-Statement als Transaktion aufgefasst und committed wird, sobald es abgeschlossen ist. Häufig ist es jedoch notwendig, mehrere
Statements in einer Transaktion zusammenzufassen und diese entweder vollständig
oder überhaupt nicht auszuführen. Zu diesem Zweck lässt sich der Auto-CommitModus ausschalten, sodass der Commit explizit erfolgen muss. Nach Beendigung
2
vgl. http://java.sun.com/javase/6/docs/api/java/sql/PreparedStatement.html
9
2. Allgemeine Grundlagen
der Transaktion sollte der Auto-Commit-Modus wieder eingeschaltet werden, um
das Standardverhalten wiederherzustellen. Listing 2.4 zeigt dieses Vorgehen exemplarisch.
1
2
3
4
con.setAutoCommit(false);
// Beliebige SQL-Statements
con.commit();
con.setAutoCommit(true);
Listing 2.4: Transaktionen in SQL
10
3 Funktionale Abhängigkeiten
Funktionale Abhängigkeiten sind ein wesentliches Konzept der relationalen Entwurfstheorie und der Schwerpunkt dieser Arbeit. Dieses Kapitel enthält daher alle Definitionen und Algorithmen, die zum weiteren Verständnis notwendig sind, und stellt
Normalformen als Gütekriterien eines relationalen Entwurfs vor.
3.1. Grundlegende Definitionen
Sei R ein Relationenschema und α, β ⊆ R Mengen von Attributen. Eine funktionale
Abhängigkeit (im Folgenden FA, oder FAen für den Plural) über R ist ein Ausdruck
der Form:
α→β
Die FA stellt dabei eine Bedingung an die möglichen gültigen Ausprägungen (Instanzen) des Relationenschemas dar. Eine Instanz R erfüllt die FA α → β genau
dann, wenn für alle Tupel t1 , t2 ∈ R gilt, dass
∀A ∈ α : t1 .A = t2 .A ⇒ ∀B ∈ β : t1 .B = t2 .B.
In anderen Worten: wenn die Tupel t1 und t2 für alle Attribute in α die gleichen Werte
besitzen, dann müssen sie auch in den Werten der Attribute in β übereinstimmen,
um die FA α → β zu erfüllen. Im Folgenden bezeichnen griechische Buchstaben (α,
β, . . . ) stets Mengen von Attributen, während lateinische Großbuchstaben (A, B,
. . . ) für individuelle Attribute stehen.
Ableitungsregeln und Hüllenbildung Sei F eine Menge von FAen über R, dann
lässt sich zeigen, dass u. U. neben F auch bestimmte andere FAen gelten. Man sagt,
F impliziert weitere FAen oder weitere FAen lassen sich aus F herleiten. Eine FA
A → B mit A, B ∈ R wird von F genau dann impliziert, wenn jede Instanz R von
R, die F erfüllt, auch A → B erfüllt. Man schreibt dann F |= A → B. Weiterhin ist
die Hülle (engl. closure) F + von F definiert als Menge aller FAen α → β, die von F
impliziert werden:
F + = {F |= α → β}
Um die Hülle F + einer Menge F zu bestimmen, können Herleitungs- oder Inferenzregeln angewendet werden. Die dabei mindestens benötigten Inferenzregeln sind die
sogenannten Armstrong-Axiome. Seien α, β, γ ⊆ R:
11
3. Funktionale Abhängigkeiten
• Reflexivität: β ⊆ α ⇒ α → β
• Verstärkung: α → β ⇒ αγ → βγ
• Transitivität: α → β ∧ β → γ ⇒ α → γ
Armstrong konnte in [Arm74] beweisen, dass diese Axiome korrekt und vollständig
sind. Korrektheit bedeutet, dass sie keine falschen FAen herleiten. Vollständig sind sie
deshalb, weil sich mit ihrer Hilfe alle FAen, die F impliziert, herleiten lassen. Dennoch
ist es in vielen Fällen hilfreich, einige weitere Regeln zur Verfügung zu haben. Deren
Korrektheit lässt sich mittels der Armstrong-Axiome beweisen.
• Vereinigungsregel: α → β ∧ α → γ ⇒ α → βγ
• Dekompositionsregel: α → βγ ⇒ α → β ∧ α → γ
• Pseudotransitivität: α → β ∧ γβ → δ ⇒ αγ → δ
Kanonische Überdeckung Sei eine Menge F von FAen auf einem Relationenschema gegeben. Dann müssen bei jeder Aktualisierungsoperation auf dem Schema die
Einhaltung aller FAen in F überprüft werden. Erfüllt die aktualisierte Relation nicht
alle FAen, muss die Operation rückgängig gemacht werden. Unmittelbar einleuchtend
ist, dass für große Mengen F der Aufwand der Überprüfung stark anwächst. Dieser
lässt sich jedoch reduzieren, indem nicht alle FAen in F überprüft werden, sondern
alle FAen in einer Menge G, die äquivalent zu F ist und weniger Elemente besitzt.
Zwei Mengen F und G von FAen heißen äquivalent (Schreibweise F ≡ G), wenn ihre
Hüllen gleich sind, d. h. wenn F + = G+ . Insbesondere ist in diesem Zusammenhang
die kleinste noch äquivalente Menge FC interessant. FC wird kanonische Überdeckung
von F genannt, falls folgende Eigenschaften erfüllt sind:
• FC ≡ F
• Keine FA in FC enthält überflüssige Attribute.
• Jede linke Seite einer FA in FC ist einzigartig. Das bedeutet, dass es keine zwei
FAen α1 → β1 und α2 → β2 in FC gibt, sodass α1 = α2 .
Wann ein Attribut als überflüssig gilt, ist wie folgt definiert. F sei dabei wieder
eine Menge von FAen und α → β eine FA in F .
• Ein Attribut A ist überflüssig in α, falls A ∈ α und F impliziert (F −{α → β})∪
({(α − A) → β}).
• Ein Attribut A ist überflüssig in β, falls A ∈ β und die FAen (F − {α → β}) ∪
({(α → (β − A)}) implizieren F .
12
3.1. Grundlegende Definitionen
Die Überprüfung, ob ein Attribut überflüssig ist oder nicht, kann effizient mit
dem Algorithmus Closure aus [SKS05] in Listing 3.1 geschehen. Dieser nimmt eine
Menge F von FAen und eine Menge von Attributen α als Eingabe und berechnet
daraus die vollständige Menge von Attributen α+ , die von α gemäß F funktional
bestimmt werden. Diese transitive Hülle einer Attributmenge α ist formal definiert
als:
n
o
α+ = β : α → β ∈ F +
Wie genau überflüssige Attribute mit Hilfe von Closure identifiziert werden, ist dem
Algorithmus der kanonischen Überdeckung in Listing 3.2 zu entnehmen. Der Beweis
der Korrektheit und eine Laufzeitanalyse von Closure sind in [SKS05] zu finden
und werden hier aus Platzgründen nicht geführt. Es sei jedoch festgehalten, dass im
schlechtesten Fall eine quadratische Laufzeit in der Größe von F erreicht wird.
Closure(F,α) {
result := α;
while (Änderungen an result) do
foreach FA β → γ in F do
if β ⊆ result then result := result ∪ γ ;
end for
end while
α+ = result;
}
Listing 3.1: Closure
Die Funktionsweise von Closure ist wie folgt: zunächst wird eine Menge result
mit der Menge α initialisiert. Dann wird in der inneren Schleife jede FA daraufhin
überprüft, ob ihre linke Seite in result enthalten ist, d. h. ob die linksseiten Attribute der FA bereits impliziert werden. Wenn das der Fall ist, müssen ihre rechtsseitigen
Attribute zu result hinzugefügt werden, da sie auch aus result abgeleitet werden
können. Dieser Schritt wird solange wiederholt, bis sich keine Änderungen an result
mehr ergeben. Nun wird result als transitive Hülle der durch F bestimmten Attribute zurückgegeben.
Mit Hilfe des vorgestellten Algorithmus Closure lässt sich nun ein Verfahren zur
Herleitung der kanonischen Überdeckung zu einer Menge F von FAen angeben (vgl.
[KE06]):
13
3. Funktionale Abhängigkeiten
1. Linksreduktion für jede FA α → β ∈ F : Überprüfe für alle A ∈ α, ob A
überflüssig ist, d. h. ob
β ⊆ Closure(F, α − A)
gilt. Falls dies der Fall ist, ersetze α → β durch (α - A) → β .
2. Rechtsreduktion für jede (verbliebene) FA α → β , d. h. überprüfe für
alle B ∈ β , ob
B ∈ Closure(F − (α → β) ∪ (α → (β − B)), α)
gilt. Falls dies der Fall ist, ist B auf der rechten Seite überflüssig.
Dann wird α → β ersetzt durch α → (β − B).
3. Entferne die FAen der Form α → ∅, die im 2. Schritt möglicherweise
entstanden sind.
4. Fasse mittels der Vereinigung FAen der Form α → β1 , . . . , α → βn zusammen,
sodass α → (β1 ∪ · · · ∪ βn ) verbleibt.
Listing 3.2: Kanonische Überdeckung
Schlüssel Mit Hilfe der eingeführten Begriffe lässt sich nun auch der in Kapitel
1 bereits erwähnte Begriff des Schlüssels definieren. Schlüssel sind Spezialfälle von
FAen und spielen in der Implementierung des Informationssystems und in Datenbanken allgemein eine entscheidende Rolle. Ist eine Menge α ∈ R gegeben, heißt α
Superschlüssel, falls gilt:
α→R
Das bedeutet, dass α alle anderen Attributwerte in R eindeutig bestimmt. Falls R
sogar voll funktional abhängig von α ist, d. h., dass es keine überflüssigen Attribute
in α gibt, dann heißt α Schlüsselkandidat. Unter den Schlüsselkandidaten wird ein
(beliebiger) als Primärschlüssel ausgezeichnet. Attribute, die nicht Bestandteil eines
Schlüsselkandidaten sind, nennt man Nichtschlüsselattribute oder auch nicht-prim.
Schlüsselattribute sind entsprechend prim.
3.2. Normalisierung
Mit Hilfe der funktionalen Abhängigkeiten lassen sich nun einige Datenbankschemaeigenschaften definieren, die im Allgemeinen beim relationalen Datenbankentwurf
angestrebt werden. Dazu gehört, dass
14
3.2. Normalisierung
• ausschließlich semantisch sinnvolle, konsistente Daten gespeichert werden und
• die Daten nach Möglichkeit nicht-redundant gehalten werden.
Redundante Datenhaltung ist unerwünscht, da sie schwerwiegende Nachteile mit
sich bringt. Zum einen belegen redundant gespeicherte Informationen unnötig viel
Speicherplatz, zum anderen führen Änderungsoperationen auf redundanten Daten
zu Leistungseinbußen und Konsistenzproblemen. Leistungseinbußen entstehen dadurch, dass die Änderung an mehreren Einträgen vorgenommen werden muss, was
gleichzeitig zu einem hohen Aufwand an Konsistenzsicherungsmaßnahmen führt.
Schlechte Entwürfe können zu drei Arten von Anomalien führen:
Updateanomalien Existieren Informationen mehrfach, kann es bei Änderungen (Updates) dazu kommen, dass einige Einträge übersehen werden.
Einfügeanomalien Werden Informationen, die zu verschiedenen Aspekten der realen
Welt (sog. Entitytypen) gehören, in einem Relationenschema vermischt, ergeben sich Probleme, sobald Informationen eingefügt werden, die nur zu einem
der Entitytypen gehören. Die Attribute, die zu dem anderen Entitytyp gehören,
müssen dann ggf. mit NULL-Werten aufgefüllt werden.
Löschanomalien Beim Löschen eines von zwei miteinander vermischten Entitytypen
können die Informationen über den anderen Entitytyp ebenfalls verloren gehen.
Um den genannten Anomalien zu begegnen, müssen Mechanismen eingesetzt werden, die Relationen mit nicht zusammengehörenden Informationen aufspalten und
redundante Daten vermeiden helfen. Diese Mechanismen fasst man unter dem Begriff
Normalisierung zusammen. Dabei wird ein Relationenschema R in die Relationenschemata R1 , . . . , Rn aufgespalten, sodass Ri ⊆ R für 1 ≤ i ≤ n. Bei einer solchen
Zerlegung müssen zwei wesentliche Kriterien eingehalten werden:
1. Verlustlosigkeit: Die in der Instanz R von R enthaltenen Informationen müssen aus den Instanzen R1 , . . . , Rn der neuen Schemata R1 , . . . , Rn rekonstruierbar sein.
2. Abhängigkeitserhaltung: Die für R geltenden FAen müssen auf die Schemata R1 , . . . , Rn übertragbar sein.
Unter Einhaltung dieser Kriterien überführen geeignete Normalisierungsverfahren
(Synthese- und Zerlegungsalgorithmus) das Relationenschema in eine Normalform
(NF abgekürzt). Um einer bestimmten Normalform zu genügen, muss das Relationenschema die Kriterien dieser Normalform erfüllen. Man unterscheidet folgende Normalformen:
15
3. Funktionale Abhängigkeiten
• Erste Normalform (1NF): Jedes Attribut der Relation muss einen atomaren
Wertebereich besitzen.
• Zweite Normalform (2NF): Die Relation ist in 1NF und jedes Nichtschlüsselattribut A ∈ R ist voll funktional abhängig von jedem Schlüsselkandidaten
von R.
• Dritte Normalform (3NF): Die Relation ist in 2NF und kein Nichtschlüsselattribut ist transitiv abhängig von einem Schlüsselkandidaten.
• Boyce-Codd-Normalform (BCNF): Die Relation ist in 3NF und für jede FA
α → β gilt:
◦ β ⊆ α, d. h. die FA ist trivial oder
◦ α ist Superschlüssel von R.
Es existieren weitere Normalformen, etwa 4NF und 5NF, die in der Praxis jedoch
keine große Bedeutung haben und daher in dieser Arbeit nicht weiter behandelt
werden. Aus diesem Grund wird auch nicht auf mehrwertige Abhängigkeiten (engl.
multivalued dependencies, abgekürzt MVD), die eine Verallgemeinerung funktionaler
Abhängigkeiten darstellen, eingegangen.
Unter bestimmten Bedingungen ist es sinnvoll, nicht den höchsten möglichen Grad
an Normalisierung anzustreben. Insbesondere Performance-Überlegungen können zu
einer bewussten Denormalisierung führen. Diese Erwägungen lassen sich jedoch nicht
verallgemeinern und sind daher nicht Aufgabe des entwickelten Informationssystems.
Vielmehr muss dessen Einsatz eine gezielte und wohlüberlegte Entscheidung des Datenbankdesigners sein.
Die Normalisierung, insbesondere die Algorithmen zur Herstellung der Normalformen, ist Gegenstand der mit dieser Arbeit verbundenen Bachelorarbeit [Mei09] und
wird dort detailliert erläutert.
16
4 Konzeptioneller Entwurf
In diesem Kapitel wird erläutert, welche Ziele beim Entwurf des Informationssystems verfolgt wurden und was der daraus abgeleitete Leistungsumfang beinhaltet.
Im Rahmen der Konzeption eines Lösungsansatzes werden außerdem die Designentscheidungen, die der Implementierung zugrunde liegen, dargelegt.
4.1. Ziele
Wie bereits einleitend erwähnt, ist es die Aufgabe des entwickelten Informationssystems, funktionale Abhängigkeiten aus PostgreSQL-Datenbanken auszulesen und in
einer übersichtlichen Form darzustellen. Neben der Präsentation bereits vorhandener
FAen muss auch deren Manipulation möglich sein, d. h. bestehende FAen sollen gelöscht oder neue FAen hinzugefügt werden können. Aus den vorhandenen FAen soll
der Grad der Normalisierung berechnet und angezeigt werden. Zudem soll der Benutzer eine Normalform, die sinnvollerweise höher ist, als die momentane, auswählen
und automatisch herstellen lassen können.
Das Use-Case-Diagramm in Abbildung 4.1 umreißt die beschriebenen Funktionen
des Informationssystems. Da es keine Interaktion zwischen mehreren Benutzern gibt,
existiert in dem Diagramm nur eine Art von Benutzer. Alle Operationen, die eine
Veränderung der Datenbank nach sich ziehen können, also die Normalisierung, als
auch die Manipulation der FAen, beinhalten ausdrücklich eine Vorschaufunktion, um
die Konsequenzen der gewählten Operation(-en) abschätzen zu können.
4.2. Leistungsumfang
Aus Abbildung 4.1 lassen sich die Produktfunktionen des Informationssystems ableiten. Jede Funktion erhält einen eindeutigen Bezeichner der Form /F100/, um sie
später referenzieren zu können. Die Nummerierung der Funktionen erfolgt im Allgemeinen in Hunderterschritten. In Fällen, in denen die Funktionen starken Bezug
zueinander haben, wird die Nummerierung in Zehnerschritten erhöht und die Hunderterstelle festgehalten. Für jede Funktion werden neben ihren Vor- und Nachbedingungen auch die zu lösenden Probleme spezifiziert.
17
4. Konzeptioneller Entwurf
Abbildung 4.1.: Anwendungsfälle des Informationssystems
/F100/
Geschäftsprozess: Darstellen eines Datenbankschemas.
Ziel: Eine Verbindung zu einer Datenbank wird hergestellt und deren Relationen
werden angezeigt.
Vorbedingung: Verbindung zur Datenbank konnte hergestellt werden.
Nachbedingung Erfolg: Alle Relationen der Datenbank werden dargestellt.
Nachbedingung Fehlschlag: Es konnte keine Datenbankverbindung hergestellt werden und eine Fehlermeldung wird ausgegeben.
Auslösendes Ereignis: Auswählen des Menüpunktes „Verbindung herstellen“.
Probleme Keine.
/F110/
Geschäftsprozess: Darstellung von FAen.
Ziel: Zu einer ausgewählten Relation werden die FAen bestimmt und angezeigt.
18
4.2. Leistungsumfang
Vorbedingung: /F100/ erfolgreich.
Nachbedingung Erfolg: Alle FAen der Relation werden angezeigt.
Nachbedingung Fehlschlag: FAen konnten nicht bestimmt werden und eine Fehlermeldung wird ausgegeben.
Auslösendes Ereignis: Auswahl einer Relation.
Probleme
1. Woraus ergeben sich FAen bzw. wie sind diese implementiert?
2. Welche FAen werden angezeigt? Mögliche Alternativen sind alle implementierten FAen, eine kanonische Überdeckung oder die transitive Hülle.
3. Gewährleistung einer übersichtlichen Darstellungsform, auch für eine große
Anzahl von FAen.
/F120/
Geschäftsprozess: Darstellung des Normalisierungsgrades.
Ziel: Zu einer ausgewählten Relation wird ihre Normalform bestimmt und angezeigt.
Vorbedingung: /F110/ erfolgreich.
Nachbedingung Erfolg: Der Normalisierungsgrad der Relation wird angezeigt.
Nachbedingung Fehlschlag: Aufgrund von nicht erfüllten Vorbedingungen kann die
Normalform nicht bestimmt werden.
Auslösendes Ereignis: Auswahl einer Relation.
Probleme Keine.
/F200/
Geschäftsprozess: FAen hinzufügen.
Ziel: Zu einer ausgewählten Relation wird eine neue FA spezifiziert und implementiert.
Vorbedingung: /F100/ ist erfolgreich und die FA ist noch nicht vorhanden bzw.
nicht herleitbar und die Instanz der Relation verstößt nicht gegen die FA.
Nachbedingung Erfolg: Die spezifizierte FA wird implementiert.
19
4. Konzeptioneller Entwurf
Nachbedingung Fehlschlag: Aufgrund von nicht erfüllten Vorbedingungen kann die
FA nicht hinzugefügt werden.
Auslösendes Ereignis: Spezifikation einer FA durch den Benutzer.
Probleme
1. FA darf nicht implementiert werden, wenn die Ausprägung der Relation
gegen die FA verstößt.
2. FAen, die von bestehenden FAen impliziert werden, sollen nicht doppelt
gespeichert werden.
/F210/
Geschäftsprozess: FAen entfernen.
Ziel: Von einer ausgewählten Relation wird eine bestehende FA entfernt.
Vorbedingung: /F100/ ist erfolgreich und die FA ist nicht durch einen Schlüssel
implementiert.
Nachbedingung Erfolg: Die spezifizierte FA wird entfernt.
Nachbedingung Fehlschlag: Aufgrund von nicht erfüllten Vorbedingungen kann die
FA nicht entfernt werden.
Auslösendes Ereignis: Auswahl einer bestehenden FA.
Probleme
1. Sicherstellung, dass keine FAen gelöscht werden können, die durch einen
Schlüsselconstraint implementiert sind.
/F300/
Geschäftsprozess: Normalisierung.
Ziel: Eine ausgewählte Relation wird normalisiert. Mögliche Alternativen sind 2NF
und 3NF.
Vorbedingung: /F110/ ist erfolgreich.
Nachbedingung Erfolg: Die Relation wird in die gewählte Normalform überführt.
Nachbedingung Fehlschlag: Probleme beim Durchführen der Algorithmen oder bei
der Änderung des Datenbankschemas führen zu einer Fehlermeldung.
20
4.3. Lösungsansätze
Auslösendes Ereignis: Auswahl einer herzustellenden Normalform.
Probleme
1. Normalisierung u. U. nicht möglich, wenn Inhalte in der Relation vorhanden
sind.
2. Wenn im Zuge der Normalisierung Relationen aufgespalten werden, wie ergeben sich die Namen der neuen Relationen?
3. Behandlung von Fremdschlüsselbeziehungen auf zu normalisierenden Relationen.
4. Behandlung von Check- und Not-Null-Constraints.
5. Behandlung externer Trigger und Views.
4.3. Lösungsansätze
In diesem Abschnitt werden Strategien vorgestellt, um die in Abschnitt 4.2 beschriebenen Probleme bzw. Aufgaben zu lösen. Sofern es mehrere sinnvolle Herangehensweisen zur Lösung eines Problems gibt, erfolgt eine begründete Auswahl der verfolgten
Strategie.
4.3.1. Darstellung von FAen (/F110/)
Bestimmung von FAen Als wesentliches Problem ergibt sich aus /F110/ die Frage, wie sich in einer beliebigen relationalen Datenbank die FAen bestimmen lassen.
Dieses Problem ist nicht trivial und stellt einen Schwerpunkt der in dieser Arbeit
entwickelten Überlegungen dar.
Eine Möglichkeit besteht darin, Data-Mining-Techniken anzuwenden, um aus den
in einer Relation enthaltenen Daten FAen abzuleiten. In [MR92a] ist dieses sogenannte dependency inference problem definiert als: Sei eine Relation R gegeben, so finde
eine Menge von FAen, die genau die FAen implizieren, die in R gelten.
Ein möglicher Algorithmus dafür wäre, durch alle möglichen FAen zu iterieren und
jede einzelne daraufhin zu prüfen, ob sie in R gilt oder nicht. Jedoch ist diese Vorgehensweise sehr ineffizient, da der Aufwand der Überprüfung exponentiell mit den
Attributen steigt. In [MR92b] wurde gezeigt, dass dieses Problem grundsätzlich nur
exponentiell, also nicht effizient, lösbar ist. Zwar existieren einige Verbesserungen
für diesen Algorithmus, doch viele davon arbeiten direkt auf den Daten und nutzen
nicht die Schnittstellen der DBMS, worunter die Portabilität stark leidet. Weiterhin
existieren auch einige SQL-basierte Algorithmen [BB95], die das inference problem
plattformunabhängig und relativ einfach lösen, jedoch weisen alle diese Verfahren
einige schwerwiegende Nachteile auf. Zum einen ist der Berechnungsaufwand nach
wie vor exponentiell, zum anderen lassen sich Data-Mining-Techniken offensichtlich
21
4. Konzeptioneller Entwurf
nur einsetzen, wenn (ausreichend) Daten in der Relation gespeichert sind. Im Rahmen dieser Arbeit kann davon jedoch nicht ausgegangen werden, da das entwickelte Informationssystem hauptsächlich in der Lehre eingesetzt werden soll. Dort ist
es wahrscheinlicher, dass nur die Relationenschemata angelegt werden und auf das
Einfügen zahlreicher Datensätze eher verzichtet wird, da diese für die Veranschaulichung relevanter Konzepte unerheblich sind. Als einen weiteren Kritikpunkt lässt
sich aufführen, dass FAen semantische Integritätsbedingungen darstellen und dass
die genannten Verfahren dies grundsätzlich unberücksichtigt lassen.
Somit erscheinen Data-Mining-Ansätze als für diese Arbeit ungeeignet und werden
nicht weiter verfolgt. Es muss stattdessen eine Möglichkeit gefunden werden, FAen
ausschließlich aus dem Relationenschema abzuleiten. Dabei sollte auch die Semantik des vom Datenbankdesigners entworfenen Schemas berücksichtigt werden. Die
einzigen Informationen, die im Normalfall zu diesem Zweck zur Verfügung stehen,
sind der im erweiterten Relationenschema implementierte Primärschlüssel und die
Schlüsselkandidaten. Diese stellen als Spezialfälle die einzigen auch im allgemeinen
Fall verfügbaren FAen dar. Weitere FAen lassen sich ohne semantisches Wissen nicht
ableiten. Wenn weitere FAen existieren, müssen diese daher vom Benutzer des Informationssystems manuell spezifiziert werden. Das Informationssystem übernimmt
dann die Implementierung der FAen und deren Speicherung, um diese Informationen
auch zu einem späteren Zeitpunkt respektive einem anderen Benutzer zur Verfügung stellen zu können. Wie diese Speicherung umgesetzt wird, ist Gegenstand des
nächsten Abschnitts.
Der Prozess der Bestimmung der FAen stellt sich somit wie folgt dar: stellt der
Benutzer eine erstmalige Verbindung zu einer Datenbank her, existieren neben den
Schlüsseln der ausgewählten Relation(-en) keine weiteren Informationen. Daher werden als FAen nur die Schlüssel angezeigt. Nun kann der Benutzer weitere FAen spezifieren, deren Umsetzung und Speicherung dann vom Informationssystem übernommen werden. Bei einer späteren Verbindung zu ebendieser Datenbank stehen dann
als FAen sowohl die Schlüssel als auch die manuell spezifizierten Abhängigkeiten zur
Verfügung.
Realisierung von FAen Es stellt sich nun die Frage, wie allgemeine FAen, d. h. solche, die nicht zwingend einen Schlüssel darstellen, umgesetzt werden. Die Definition
der FAen macht deutlich, dass diese als spezielle statische Integritätsbedingungen
angesehen werden können, da sie in jedem Zustand der Datenbank gültig sein müssen. Wie in Kapitel 3 beschrieben, bedeutet z. B. die FA A → B nichts anderes als
∀x, y ∈ R : x.A = y.A ⇒ x.B = y.B. Dies lässt sich nach einigen simplen Logiktransformationen elegant als SQL-Assertion ausdrücken:
1
2
3
22
CREATE ASSERTION FD(A,B)
CHECK NOT EXISTS
( SELECT *
4.3. Lösungsansätze
4
5
6
7
8
9
10
11
FROM TABLE1 AS X
WHERE EXISTS
( SELECT *
FROM TABLE1 AS Y
WHERE
( X.A = Y.A
AND NOT
X.B = Y.B ) )
Listing 4.1: SQL-Assertion zur Realisierung einer FA
Doch obwohl Assertions bereits im SQL-92-Standard vorhanden sind, werden diese bislang von PostgreSQL (wie auch von anderen, kommerziellen DBMS) nicht
unterstützt. Eine umformulierte (und weniger elegante) Konstruktion von CheckConstraints mit eingebetteten Anfragen ist aus demselben Grund nicht möglich,
weshalb eine andere Lösung gefunden werden muss.
Eine relativ simple Möglichkeit hierfür bieten Trigger. Diese sind Bestandteil des
SQL-Standards und werden von PostgreSQL unterstützt, wenn auch nicht völlig standardkonform. Ein Trigger spezifiziert, dass die Datenbank nach bestimmten Operationen eine spezielle Prozedur, die sogenannte Triggerfunktion, aufrufen soll. Trigger
können sowohl bevor, als auch nach einer INSERT-, UPDATE- oder DELETE-Operation
ausgelöst werden. Die Triggerfunktion kann dann ähnlich wie in Listing 4.1 überprüfen, ob die negierte Bedingung der FA erfüllt ist. Wenn dies der Fall ist, muss
die Aktualisierung zurück gesetzt und eine Fehlermeldung ausgegeben werden. Dadurch wird sichergestellt, dass die FA in der Relation immer gültig ist. Wie im Detail
aus einer FA ein Trigger und eine zugehörige Triggerfunktion generiert werden, ist
Gegenstand von [Mei09].
Speicherung von FAen Es lässt sich somit festhalten, dass es (im Rahmen dieser
Arbeit) günstig ist, FAen aus den Schlüsseln einer Relation abzuleiten und zusätzliche FAen als Trigger zu implementieren. Somit stellt sich aber die Frage, wie die
zugehörigen Informationen persistent gemacht werden können. Um eine FA α → β
zu speichern, werden folgende Daten benötigt:
• die Relation, auf die sich die FA bezieht,
• die bestimmende Attributmenge α,
• die Attributmenge β,
• Informationen darüber, ob die FA sich aus einem Schlüssel ergibt oder sie als
Trigger implementiert ist,
• ggf. der Triggername und die zugehörige Triggerfunktion.
23
4. Konzeptioneller Entwurf
Um eine größtmögliche Portabilität des Informationssystems zu erreichen, bietet
es sich an, diese Informationen direkt in der betreffenden Datenbank zu hinterlegen.
Gegenüber einer Lösung, die diese Informationen etwa auf dem Dateisystem des
Arbeitsplatzrechners speichert, können somit zum einen die Funktionen des DBMS,
etwa Transaktionen und Sicherungsmechanismen, genutzt werden, und zum anderen
können mehrere Benutzer unabhängig voneinander auf den gleichen Datenbestand
zugreifen, was für Lehrzwecke vorteilhaft ist. Daher wird eine Menge von Relationen
entworfen, die im Folgenden als fd_catalog bezeichnet wird und für die Speicherung
aller relevanten Daten für FAen (engl. functional dependencies, kurz fd) zuständig
ist. Der zugehörige UML-Entwurf ist in Abbildung 4.2 dargestellt. Die abgebildeten
Klassen entsprechen den oben genannten Basisinformationen, wobei LHS und RHS
für left-hand side bzw. right-hand side stehen.
Abbildung 4.2.: fd_catalog
Darstellung Die Fragen nach einer übersichtlichen Darstellungsform der FAen werden im Rahmen der Konzeption einer grafischen Benutzeroberfläche in Abschnitt 6.3
behandelt. Festzuhalten ist jedoch, dass genau die FAen dargestellt werden, die tatsächlich in der Datenbank implementiert sind, da die transitive Hülle zu umfangreich
(und daher unübersichtlich) und eine kanonische Überdeckung verwirrend ist, da der
Benutzer andere FAen angezeigt bekäme, als die die er hinzugefügt hat.
4.3.2. FA hinzufügen (/F200/)
Unerfüllbarkeit von FAen Gemäß /F200/ stellt sich die Frage, was geschieht, wenn
versucht wird, eine FA zu implementieren, die von der Instanz R nicht erfüllbar ist, da
z. B. Tupel existieren, die gegen die FA verstoßen. Die Antwort darauf lässt sich nicht
allgemeingültig angeben, weshalb in diesem Fall eine Rückmeldung an den Benutzer
am sinnvollsten ist. Dieser kann sich dann entweder entscheiden, die FA zu verwerfen
oder die Relation manuell zu leeren, um so die Realisierung der FA zu ermöglichen.
24
4.3. Lösungsansätze
Membership-Problem Ein komplizierteres Problem, das sich aus /F200/ ergibt,
ist es, sicherzustellen, dass FAen nicht doppelt gespeichert werden. Wird eine neue
FA α → β spezifiziert, so muss zunächst überprüft werden, ob sie sich aus der bereits
vorhandenen Menge F ableiten lässt, d. h. ob sie von F impliziert wird. Dies ist das
sogenannte Membership-Problem
α → β ∈ F +?
Eine intuitive Vorgehensweise wäre es, die Hülle F + mit Hilfe der Armstrong-Axiome
zu berechnen und dann auf Mengeninklusion zu überprüfen. Da die Größe der Hülle jedoch exponentiell wachsen kann, ist diese Vorgehensweise nicht effizient. Ein
schnelleres Verfahren besteht darin, auf die Berechnung von F + zu verzichten und
das Membership-Problem durch Berechnung der transitiven Hülle der Attributmenge
α bezüglich F zu lösen. Das umformulierte Problem lautet dann
β ⊆ α+
und kann effizient gelöst werden. Der simple Algorithmus Member in Listing 4.2 führt
unter Verwendung der Funktion Closure(F,α) (Listing 3.1) den Test auf Membership durch und prüft also, ob β ⊆ α+ gilt. Ist dies der Fall, wird α → β durch die
FAen in F impliziert und braucht nicht mehr gespeichert zu werden.
Member(F,α → β )
return β ∈ Closure(F,α);
Listing 4.2: Member
4.3.3. Normalisierung (/F300/)
Tupel in der Relation Wird eine Relation normalisiert und dabei in mehrere Relationen zerlegt, stellt sich die Frage, wie mit potentiellen Tupeln in der zu zerlegenden
Relation verfahren wird. Die einfachste Realisierung wäre es, eine Normalisierung zu
verbieten, wenn tatsächlich Daten in der Relation enthalten sind. Dies wäre für den
Benutzer jedoch sehr unkomfortabel und würde den Nutzwert des Informationssystems erheblich mindern. Die hier eingesetzte Lösung besteht daher darin, die Daten
der zu zerlegenden Relation entsprechend der Aufteilung ihrer Attribute auf die neu
entstehenden Relationen in ebendiese zu kopieren. Dazu wird dynamisch SQL-Code
generiert, der pro entstehender Relation einen Query wie in Listing 4.3 erzeugt. Dieser selektiert alle Inhalte aus der alten Relation und projeziert auf die Attribute, die
in der neuen Relation ebenfalls vorhanden sind.
INSERT INTO NEW_TABLE SELECT ATTRIBUTE1,ATTRIBUTE2 FROM OLD_TABLE;
Listing 4.3: SQL-Query zum dynamischen Kopieren
25
4. Konzeptioneller Entwurf
Da die Namen der neuen Relationen nicht semantisch sinnvoll durch das Informationssystem bestimmt werden können, ergeben sich diese zunächst aus dem alten
Relationennamen mit einem Suffix der Form „_i“, wobei i ∈ ℕ die neuen Relationen
aufsteigend durchnummeriert. Durch die Vorschaufunktion bietet sich dem Benutzer
dann die Möglichkeit, die Relationen beliebig umzubenennen, bevor die Änderungen
an der Datenbank durchgeführt werden.
Fremdschlüssel Eine Besonderheit, die bei der Normalisierung beachtet werden
muss, sind eventuell bestehende Fremdschlüsselbeziehungen. Diese werden wie im
Folgenden beschrieben behandelt:
• Existieren Relationen mit Fremdschlüsseln, die die zu normalisierende Relation referenzieren, so müssen diese Fremdschlüssel zum einen gelöscht werden,
um das Entfernen der Relation zu ermöglichen. Zum anderen sollten die zusätzlichen Integritätsbedingungen, welche die Fremdschlüssel darstellen, nicht
verloren gehen, da es sonst zu Inkonsistenzen kommen kann. In der Konsequenz
sollten solche Fremdschlüssel also nicht gelöscht, sondern durch andere ersetzt
werden, die nicht mehr die zu normalisierende Relation referenzieren, sondern
eine der neu entstehenden. Welche das ist, ergibt sich daraus, in welcher (neuen) Relation die Attribute, die der Fremdschlüssel referenziert, Primärschlüssel
sind.
• Besitzt die zu normalisierende Relation selbst einen (oder mehrere) Fremdschlüssel, so müssen alle neuen Relationen mit den entsprechenden Attributen
ebenfalls diesen Fremdschlüssel implementieren.
Check- und Not-Null-Constraints Wenn auf der zu normalisierenden Relation
Check- oder Not-Null-Constraints existieren, muss entschieden werden, wie mit diesen zu verfahren ist. Während Not-Null-Constraints ohne weiteres auf jede Relation
mit den entsprechenden Attributen übernommen werden können, muss bei CheckConstraints überprüft werden, ob und in welcher der neuen Relationen der Constraint
implementierbar ist. Nur wenn weiterhin eine Relation mit allen Attributen des Constraints existiert ist dieser implementierbar und wird auf die entsprechende Relation
übertragen. Andernfalls wäre eine aufwändige Generierung tabellenübergreifender
Constraints notwendig, worauf im Rahmen dieser Arbeit verzichtet wird.
Views Sollten Views existieren, die die zu normalisierende Relation referenzieren,
müssen diese im Rahmen der Normalisierung entweder entfernt oder modifiziert werden, sodass die Referenz aufgehoben und die Relation entfernt werden kann. Eine
Modifikation der Views ist jedoch nur in sehr einfachen Fällen, etwa wenn diese
nicht relationenübergreifend definiert ist, mit vertretbarem Aufwand möglich. Selbst
dann können jedoch die Attribute, die von der View referenziert werden, auf mehrere
26
4.3. Lösungsansätze
neue Relationen aufgeteilt werden, sodass aufwändig eine neue Definition der View
bestimmt werden müsste. Da Views für den Schwerpunkt dieser Arbeit, die Manipulation und Visualisierung funktionaler Abhängigkeiten, nicht wesentlich sind, wird
daher auf eine Behandlung verzichtet. Stattdessen wird beim Versuch, eine Relation
zu normalisieren, die von einer oder mehrerer Views referenziert wird, eine Fehlermeldung mit dem Hinweis auf die Namen der Views ausgegeben, sodass der Benutzer
die Problematik extern behandeln kann.
Externe Trigger Externe Trigger, d. h. solche, die nicht durch das Informationssystem erstellt wurden, gehen bei einer Normalisierung der zugehörigen Relation
verloren. Dies ist darauf zurückzuführen, dass für eine Anpassung dieser Trigger die
aufgerufenen Triggerfunktionen analysiert werden müssten, um zu untersuchen, ob
die dort spezifizierten Bedingungen weiterhin erfüllbar sind. Da z. B. die Attribute
auf mehrere Relationen aufteilt werden könnten, ist dies im Allgemeinen nicht ohne
weiteres entscheidbar, weshalb auf eine Behandlung verzichtet wird. Stattdessen wird
dem Benutzer ggf. eine Fehlermeldung mit dem Hinweis auf die Namen der externen
Trigger ausgegeben.
Information Schema Zu verschiedenen Zwecken, etwa der beschriebenen Behandlung der Fremdschlüsselproblematik, ist es nötig, auf den PostgreSQL-Systemkatalog
zuzugreifen, um Metadaten über die gespeicherten Relationen, Attribute, Prozeduren und Constraints abzurufen. Der Systemkatalog ist PostgreSQL-spezifisch und
mit Rücksicht auf Implementierungsaspekte angelegt. Er kann sich daher mit jedem
Versionssprung der Datenbank grundlegend ändern, was aus Kompatibilitätsgründen
für das entwickelte Informationssystem nicht akzeptabel ist.
Abhilfe schafft das sogenannte Information Schema, eine Menge von im SQLStandard beschriebenen Views mit allen nötigen Metadaten über die Objekte in
der Datenbank. Das Information Schema bleibt stabil und ist portabel, da es keine
Informationen über PostgreSQL-spezifische Konstrukte enthält. Detaillierte Informationen über die verschiedenen Views sind [Pos09] zu entnehmen.
27
5 Systementwurf
In diesem Kapitel wird die Systemarchitektur festgelegt. Dazu werden die Produktfunktionen in Subsysteme aufgebrochen und das Verhalten des Gesamtsystems auf
Interaktionen zwischen diesen Subsystemen abgebildet.
5.1. Projektdetails
Das Verhalten des entwickelten Systems wird durch den Statechart in Abbildung 5.1
spezifiziert und im Folgenden detailliert beschrieben.
Nachdem das Informationssystem gestartet wurde, ist das Programm bereit und
wartet auf Aktionen des Anwenders. Dieser kann nun eine Datenbankverbindung herstellen und das Datenbankschema laden. Ist dies erfolgt, werden alle Relationen der
Datenbank angezeigt. Von diesen kann der Benutzer eine auswählen, zu der dann alle
zugehörigen FAen sowie die momentane Normalform angezeigt werden. Nun besteht
die Möglichkeit, bestehende FAen zu entfernen oder neue hinzuzufügen. In beiden
Fällen wird zunächst eine Vorschau auf die Konsequenzen der Manipulation angezeigt. Insbesondere wird nach jeder Änderungsoperation der neue Normalisierungsgrad bestimmt. Dieser Zustand wird so lange beibehalten, bis sich der Benutzer dazu
entscheidet, die Änderungen festzuschreiben oder zu verwerfen (Transitionen Commit
bzw. Rollback in Abbildung 5.1). Außerdem hat der Benutzer die Möglichkeit, eine
Normalform auszuwählen, die hergestellt werden soll. In diesem Fall wird ebenfalls
eine Vorschau generiert, die entweder festgeschrieben oder verworfen werden kann.
Das Programm lässt sich jederzeit beenden, sofern keine Vorschau angezeigt wird.
5.2. Analyse der Produktfunktionen
Die in Abschnitt 4.2 beschriebenen Produktfunktionen werden für dieses Projekt wie
folgt analysiert:
1. Die Verteilung in der Architektur und somit die resultierende Komponentenstruktur wird mittels eines Aktivitätsdiagrammes dargestellt. Die in den Sequenzdiagrammen aufgeführte Komponente Control wird hierbei unberücksichtigt bleiben, da sie keine Aktivität im eigentlichen Sinne darstellt, sondern
als Vermittler zwischen den anderen Akteuren auftritt.
28
5.3. Analyse von Funktionalität /F100/
Abbildung 5.1.: Statechart Projektdetails
2. Die Realisierung der Funktion als Interaktion von Objekten des zu entwickelnden Systems wird durch ein Sequenzdiagramm dargestellt. Hierbei wird lediglich ein Weg durch den Entscheidungsbaum der Funktion dargestellt und auf
die in den Aktivitätsdiagrammen beschriebenen Fallunterscheidungen verzichtet. Andernfalls würde die Anzahl der gegenseitigen Aufrufe überproportional
ansteigen und der zur Verfügung stehenden Platz würde nicht für eine übersichtliche Darstellung ausreichen.
Während die Funktion /F100/ exemplarisch im nächsten Abschnitt untersucht
wird, ist die Analyse aller weiteren Funktionen aus Platzgründen in Anhang A zu
finden.
5.3. Analyse von Funktionalität /F100/
5.3.1. Grobanalyse
Der Benutzer kann ein bereits gespeichertes Datenbankprofil auswählen oder ein
neues anlegen, zu dem dann versucht wird, eine Verbindung herzustellen. Im Erfolgsfall liest die Komponente FD das Datenbankschema aus, woraufhin die Komponente
29
5. Systementwurf
DBTools überprüft, ob der fd_catalog bereits existiert. Ist dies nicht der Fall, so
werden die zugehörigen Relationen angelegt und die Schlüssel aller Relationen des
Schemas als FAen in den fd_catalog aufgenommen. Schließlich werden aus diesem
die FAen pro Relation ausgelesen und im von FD erstellten Schema-Objekt gespeichert. Nachdem die Verbindung zur Datenbank geschlossen wurde, wird das Schema
von der Komponente GUI angezeigt.
Abbildung 5.2.: Verteilung von /F100/
30
5.3. Analyse von Funktionalität /F100/
5.3.2. Feinanalyse
Geht über die View der Aufruf zum Laden eines Datenbankschemas ein, stellt der
ConnectionManager eine Verbindung zur Datenbank her. Der SchemaManager erstellt
nun ein DbSchema-Objekt, in dem alle Relationen mit ihren Attributen gespeichert
sind. Dieses Objekt übergibt er an den CatalogManager, der prüft, ob der fd_catalog
existiert. Da der entsprechende Funktionsaufruf false liefert, wird der fd_catalog
angelegt und die Schlüssel der Relationen werden als FAen dort eingetragen. Die
gespeicherten FAen werden als Menge von FDep-Objekten im übergebenen DbSchema
hinterlegt, woraufhin dieses entlang der Aufrufkette zurückgegeben und angezeigt
wird.
Abbildung 5.3.: Sequenzdiagramm für /F100/
31
5. Systementwurf
5.4. Komponentenspezifikation
Aus der Analyse der Produktfunktionen in Abschnitt 5.3 und Anhang A ergibt sich
die Komponentenstruktur in Abbildung 5.4, die die grobe Kommunikation zwischen
den einzelnen Komponenten des Produkts beschreibt.
Abbildung 5.4.: Komponentenentwurf
5.5. Technische Produktumgebung
Dieser Abschnitt beschreibt die technischen Anforderungen für die Umgebung, in der
das entwickelte Informationssystem zum Einsatz kommt, bzw. für die es entwickelt
wurde und zu der es daher kompatibel ist.
Software
Das Informationssystem ist vorrangig Linux-kompatibel (z. B. Ubuntu, Debian), arbeitet jedoch plattformübergreifend auch unter Windows-Betriebssystemen der Fa.
Microsoft. Mindestvoraussetzung für den Einsatz ist eine Java Runtime Environment
(JRE) Version 6. Entwickelt wird das System für PostgreSQL-Datenbanken ab Version 8.3.7-1.
Hardware
Das Produkt sollte auf einem Rechner ausgeführt werden, der den Mindestanforderungen der JRE entspricht. Laut Herstellerangabe gemäß [Sun09] liegen diese für
32
5.5. Technische Produktumgebung
einen Desktop-Rechner mit Linux-Betriebssystem (beispielsweise Red Hat Linux 9.0)
und 32-Bit-Architektur bei:
• Arbeitsspeicher: min. 64 MB (unter Windows Vista 128 MB)
• Festplattenspeicher: min. 58 MB (unter Windows Vista 98 MB)
33
6 Implementierung
Gegenstand dieses Kapitels ist die Implementierung des vorgestellten Systementwurfs, sowie eine Beschreibung der grafischen Benutzeroberfläche und der eingesetzten Bibliotheken.
6.1. Model-View-Controller
Die Implementierung des Informationssystems ist nach dem Model-View-ControllerArchitekturmuster (MVC, „Modell/Präsentation/Steuerung“) strukturiert. Ziel des
Musters ist es, durch größtmögliche Entkopplung von GUI und Geschäftslogik einen
flexiblen Programmentwurf zu realisieren, sodass eine spätere Änderung oder Erweiterung erleichtert und eine Wiederverwendbarkeit der einzelnen Komponenten
ermöglicht wird. Insbesondere ein Austausch des GUI beispielsweise gegen eine JSPbasierte Web-Oberfläche ist so ohne eine aufwändige Umgestaltung der internen Programmstruktur möglich.
MVC unterscheidet drei Komponenten:
• Model trägt die Verantwortung für die Verwaltung der Daten. Im Informationssystem übernimmt das Paket FD, genauer gesagt, die darin enthaltenen Klassen,
diese Rolle.
• View übernimmt die sichtbare Darstellung. Die Views befinden sich im Paket
GUI.
• Controller sorgt für die interne Regelung aller ablaufenden Prozesse und ist
somit die zentrale Schnittstelle zwischen Model und View. Der Controller (im
gleichnamigen Paket) übersetzt die Benutzerinteraktionen mit der View in Operationen, die das Model ausführt.
Die Aktualisierung der Darstellung bzw. der Daten erfolgt gemäß MVC, indem sich
eine oder mehrere Views beim Model als Beobachter registrieren. Sobald Änderungen an den Daten vorliegen, benachrichtigt das Model alle registrierten Beobachter,
woraufhin die Views ihre Darstellung aktualisieren.
6.2. Klassendiagramme
Dieser Abschnitt beschreibt die Implementierung der in Kapitel 5 entworfenen Komponenten. Jede Komponente entspricht einem Java-Package, dessen Klassen hier in
34
6.2. Klassendiagramme
vereinfachter Form vorgestellt werden. Dabei wird aus Gründen der Übersichtlichkeit
auf Methoden und Attribute, die für die Belange des Informationssystems irrelevant
sind, verzichtet. Dazu gehören insbesondere Getter- und Setter-Methoden, sowie Methoden, die Java-Klassen von Object oder anderen allgemeinen Oberklassen erben.
6.2.1. Implementierung von Komponente Control
Control (s. Abbildung 6.1) besteht im Wesentlichen aus der abstrakten Oberklasse
AbstractController und deren Implementierung DefaultController. Diese reali-
sieren die Controller-Komponente des MVC-Architekturmusters, wie in Abschnitt 6.1
beschrieben. AbstractController beinhaltet zwei ArrayList-Objekte, um die registrierten Models und Views zu verwalten. Wenn ein Model registriert wird, registriert
sich der Controller selbst ebenfalls als ein PropertyChangeListener auf dem Model. Somit ruft jede Zustandsänderung des Models die propertyChange()-Methode
auf, woraufhin der Controller dieses Event an die entsprechenden Views weiterleitet. Die setModelProperty()-Methode bedient sich der Java Reflection API, um
eine vollständige Entkopplung der Models vom Controller zu realisieren. Dazu wird,
wenn eine Zustandsänderung des Models erfolgen soll, jede registrierte Model-Klasse
daraufhin untersucht, ob sie die zu ändernde Eigenschaft besitzt und ggf. wird der
entsprechende Setter dynamisch aufgerufen.
Die DefaultController-Klasse besteht aus Property-Konstanten und Methoden,
die dazu dienen, Aufrufe der GUI an die Models weiterzuleiten. FDISApp enthält die
main()-Methode und ist für den Programmstart verantwortlich.
6.2.2. Implementierung von Komponente DBTools
DBTools (s. Abbildung 6.2) ist verantwortlich für alle Aufgaben, die in einem en-
geren Zusammenhang mit der Verwaltung der Datenbank stehen. Dies umfasst zum
einen den Verbindungsaufbau und die Verwaltung der Zugangsdaten. Letztere werden
in Credentials-Objekten erfasst und serialisiert. Der ConnectionManager ist dafür
verantwortlich, die gewählten Credentials zu laden, zu bearbeiten oder auf die Festplatte zu schreiben. Er stellt anderen Klassen die Methode getConnection() zur
Verfügung, die ein Connection-Objekt zurückliefert, auf dem Datenbankoperationen
ausgeführt werden können. Da für das Informationssystem kein Mehrbenutzerbetrieb
vorgesehen ist, ist getConnection() nach dem Singleton-Muster implementiert, sodass immer höchstens eine offene Verbindung existiert. Mittels closeConnection()
wird die momentane Verbindung wieder geschlossen.
Zum anderen übernimmt der CatalogManager alle Lese- und Schreiboperationen
auf dem fd_catalog, d. h. dass er beim Laden eines Schemas für die Erstellung bzw.
das Auslesen des fd_catalog, sowie für das Hinzufügen und Entfernen von FAen verantwortlich ist. Bei der Erstellung der Trigger greift er auf den StatementGenerator
35
6. Implementierung
Abbildung 6.1.: Klassendiagramm Control
36
6.2. Klassendiagramme
zurück, der das Interface IStatement implementiert. IStatement definiert Methoden zur SQL-Codegenerierung für Trigger, Triggerfunktionen sowie zum Erstellen
von Relationen und Fremdschlüsselbeziehungen.
Abbildung 6.2.: Klassendiagramm DBTools
6.2.3. Implementierung von Komponente FD
FD (s. Abbildung 6.3) realisiert die Model-Komponente des MVC-Architekturmusters,
sowie die das Model bearbeitenden Klassen. Alle Model-Klassen erben von der abstrakten Oberklasse AbstractModel, welche die Klasse PropertyChangeSupport aus
dem Paket javax.beans benutzt, um an Zustandsänderungen des Models interessierte Beobachter zu registrieren, deregistrieren und zu benachrichtigen.
Die DbSchema-Klasse repräsentiert ein Datenbankschema und enthält eine Menge
von Relation-Objekten, die die Relationen des Schemas darstellen. Die RelationKlasse besitzt neben einem Namen und einer Menge von Attributen (columns) auch
eine Menge von in ihr gültigen FAen (fdeps). Ferner implementiert Relation das
Normalizable-Interface, welches die notwendigen Methoden zur Bestimmung der
Normalform einer Relation und zur Durchführung einer Normalisierung nach 2NF
37
6. Implementierung
oder 3NF (normalize(form)) definiert. Während der Normalisierung entsteht eine
Menge von SynRelation-Objekten, die von Relation abgeleitet sind und diese um
weitere Attribute, etwa eine Ursprungsrelation, erweitern.
FAen sind ihrerseits durch die Klasse FDep vertreten, die jeweils eine Menge von
links- und von rechtsseitigen Attributen aufweist.
Die SchemaManager-Klasse übernimmt die Verwaltung des Models, d. h. sie ist für
das Auslesen des Datenbankschemas und das Laden von Relationen verantwortlich.
Sie bietet Funktionalität für das Hinzufügen und Entfernen von FAen und delegiert
Normalisierungsoperationen an die entsprechenden Relationen. Ferner übernimmt sie
den Ableich von Relation- bzw. FDep-Objekten mit deren tatsächlichen Entitäten in
der Datenbank.
6.2.4. Implementierung von Komponente GUI
GUI (s. Abbildung 6.4) übernimmt die grafische Darstellung des Models und bie-
tet dem Benutzer Operationen auf dem Model an. An zentraler Stelle steht dabei
FDISView, die die Haupt-Oberfläche (s. Abschnitt 6.3) realisiert, indem sie einen
JFrame implementiert. Um sich als View beim Controller registrieren zu können,
implementiert FDISView das Interface IView, welches die modelPropertyChange()Methode zur Verfügung stellt. Diese wird automatisch vom Controller aufgerufen,
sobald das Model eine Zustandsänderung meldet.
Für die Darstellung, insbesondere der FAen, bedient sich FDISView einer Reihe
von manuell erweiterten Swing-Komponenten, der FDTable, dem FDTableModel und
dem SchemaTreeCellRenderer. Diese sind reine Hilfsklassen und werden daher nicht
näher erläutert.
Eine weitere Klasse, die IView implementiert, ist NfDialog, welche eine Vorschaufunktion auf eine Normalisierung umsetzt. NfDialogConsole erweitert diese Vorschau
um eine Textkonsole, die auf Wunsch die Zwischenschritte bei der Normalisierung anzeigt. ServerDialog realisiert eine Darstellung der gespeicherten Datenbankprofile
und bietet Eingabefelder für die Erstellung neuer Profile. AboutBox dient der Darstellung von Hintergrundinformationen über das Programm und die Entwickler. Alle vier
genannten Klassen sind von JDialog abgeleitet und werden bei Bedarf von FDISView
erzeugt und dargestellt.
6.3. User Interface Design
Abbildung 6.5 zeigt den Entwurf der grafischen Benutzeroberfläche. Die Oberfläche
ist nach den Windows User Experience Interaction Guidelines gestaltet, so dass sie auf
die meisten Benutzer vertraut wirken und den Umgang mit der Software erleichtern
sollte.
38
6.3. User Interface Design
Abbildung 6.3.: Klassendiagramm FD
39
6. Implementierung
Abbildung 6.4.: Klassendiagramm GUI
40
6.3. User Interface Design
l
8
l
4l
5l
3
l
l
1
2
l
6
l
7
Abbildung 6.5.: GUI
l
Auf der linken Seite befindet sich der Relationenbaum 1 , der dazu dient, alle in
der geladenen Datenbank vorhandenen Relationen übersichtlich darzustellen. Eine
Relation kann aufgeklappt werden, so dass ihre Attribute sichtbar sind. Wird eine
Relation selektiert, dann werden im Zentrum der Oberfläche die zugehörigen funktionalen Abhängigkeiten in Tabellenform 2 angezeigt. Die Spalte LHS (left-hand side)
steht dabei für die linke und die Spalte RHS (right-hand side) für die rechte Seite
einer FA.
Im oberen rechten Teil der Anwendung befindet sich ein Panel mit Informationen
zum Normalisierungsgrad der ausgewählten Relation, sowohl im aktuellen Zustand
3 (wie er in der Datenbank vorhanden ist), als auch nach einem potentiellen Commit
4 , welcher temporäre Änderungen an den FAen festschreiben würde. Direkt darunter
bieten zwei Listen 5 die Möglichkeit, aus den Attributen der Relation neue FAen
zu spezifizieren und temporär hinzuzufügen. Dies wird durch die grüne Hintergrundfarbe der neuen FA im mittleren Teil der Oberfläche hervorgehoben. Wird dort eine
Zeile selektiert, kann durch den Button Remove 6 die entsprechende FA (zunächst
wieder temporär) entfernt werden, welches durch eine rote Hintergrundfarbe signalisiert wird. Im unteren rechten Teil der Oberfläche wird diese Farbcodierung durch
l
l
l
l
l
41
6. Implementierung
l
l
eine Legende 7 erläutert.
Wenn Änderungen an den FAen durchgeführt wurden, werden in der Toolbar 8 die
Buttons Commit und Rollback aktiv, die die Änderungen entweder in die Datenbank
festschreiben oder aber verwerfen.
Alle Operationen können auch über den Menüpunkt Normalization im Hauptmenü aufgerufen werden. Für fortgeschrittene Benutzer wurde jeder Operation zudem
ein Tastaturkürzel zugewiesen, um die Arbeit zu beschleunigen.
6.4. Externe Bibliotheken
Im Rahmen der Entwicklung des Informationssystems wurden einige externe Bibliotheken eingesetzt, die in diesem Abschnitt kurz vorgestellt werden.
6.4.1. Swing Application Framework
Name appframework-1.0.3.jar
Version 1.0.3
URL http://appframework.dev.java.net
Das im JSR-296 (Java Specification Request)1 spezifizierte Swing Application Framework definiert eine gemeinsame, wiederverwendbare Infrastruktur für Swing-Anwendungen, um den Entwicklungsprozess von Desktop-Anwendungen zu vereinheitlichen und zu vereinfachen.
Das Framework stellt dabei insbesondere folgende Funktionalität zur Verfügung:
• Lebenszyklusmanagement, besonders für den Start und das Beenden von GUIs.
• Ressourcenmanagement, z. B. für Icons, Farben, Fonts und formatierte Nachrichten.
• Vereinfachung des Event-Handlings durch Definition von Actions und Tasks,
die auch asynchron zum Hauptthread laufen können.
• Anwendungszustand sichern: Positionen von Fenstern, Tabellenspaltenbreiten,
usw. von einer Programmsitzung in die nächste übernehmen.
Das JSR-296 wird von Sun Microsystems, Oracle und Google unterstützt und soll
voraussichtlich in Java Version 7 integriert werden.
In dieser Arbeit wurde intensiver Gebrauch von dem Framework gemacht, was eine
deutliche Verringerung der Komplexität, besonders im Bereich des Event-Handling,
1
Eine Anforderung einer neuen Java-Spezifikation im Rahmen des Java Community Process.
42
6.4. Externe Bibliotheken
zur Folge hatte. So konnten zahlreiche Klassen, die sonst für GUI-Listener nötig
gewesen wären, eingespart werden, wodurch die Pflege und Weiterentwicklung des
Programmcodes vereinfacht wird.
6.4.2. SwingLabs SwingX
Name swingx-1.0.jar
Version 1.0
URL http://swingx.dev.java.net
SwingX ist ein SwingLabs2 -Projekt, das diverse Erweiterungen des Standard-GUIToolkits beinhaltet. Dazu gehören u. a.:
• Sortier-, Filter- und Highlighting-Funktionen für Tables, Trees und Listen
• Auto-Vervollständigung
• Finden/Suchen
• Neue Komponenten, wie TreeTable
Erfolgreiche Projektkomponenten, z. B. Desktop, SystemTray und GroupLayout,
werden schließlich in die Swing-Bibliothek übernommen.
Eine zentrale Komponente der entwickelten Oberfläche, nämlich die Tabelle zur
Darstellung der FAen, ist eine SwingX-Klasse. Sie bietet gegenüber der herkömmlichen JTable-Klasse komfortablere Highlighting-Mechanismen und erweiterte Funktionen, wie das Ausblenden von Spalten.
2
Ein Open-Source-Projekt von Sun Microsystems, das sich mit der Verbesserung von Swing beschäftigt.
43
7 Zusammenfassung und Ausblick
In diesem Kapitel erfolgt zunächst eine kritische Beurteilung des entwickelten Informationssystems, insbesondere unter Performance-Gesichtspunkten. Schließlich erfolgt ein zusammenfassendes Fazit und ein Ausblick.
7.1. Bewertung
Für den praktischen Einsatz des Informationssystems ist die Performance der Software auch unter Last interessant. Daher wurden die Laufzeiten von zwei Szenarien,
unter denen große zu verarbeitende Datenmengen auftreten können, genauer untersucht. Die für eine hohe Last entscheidenden Kriterien sind:
1. Anzahl der Relationen in der Datenbank
2. Anzahl der Attribute in einer Relation
Die folgenden Evaluationen fanden auf einem Desktop-PC mit folgenden Merkmalen statt:
• CPU: Intel Core2Duo E6400 @ 2.13 GHz
• RAM: 3,0 GB
7.1.1. Szenario 1: Anzahl von Relationen
Die Anzahl der Relationen einer Datenbank wirkt sich auf die Laufzeit des Ladeprozesses aus, da für jede vorhandene Relation entsprechende Einträge im fd_catalog
angelegt werden müssen. Somit tritt diese Ladeverzögerung nur beim erstmaligen Verbinden zu einer Datenbank auf. Bei jeder weiteren Verbindung ist der fd_catalog
bereits angelegt und muss nur noch ausgelesen werden. Für das untersuchte Maximum von 1000 Relationen liegt die Zeit für das Auslesen des fd_catalog noch
unter 8 Sekunden. Tabelle 7.1 stellt die Laufzeit des (erstmaligen) Ladeprozesses in
Abhängigkeit der in der Datenbank vorhandenen Relationen dar. Als Ergebnis lässt
sich festhalten, dass auch bei sehr großen Datenbanken (die für das Einsatzgebiet
des Informationssystems eher untypisch sind) der Ladevorgang in akzeptabler Zeit
abgeschlossen wird.
44
7.1. Bewertung
Anz. Relationen
Laufzeit
3
15
≤ 2s ≤ 2s
50
≤ 2s
200
500
≤ 5s ≤ 8s
1000
≤ 15s
Tabelle 7.1.: Laufzeit in Abhängigkeit der Relationen
7.1.2. Szenario 2: Anzahl von Attributen
Die Anzahl der Attribute einer Relation hat Auswirkungen auf die Laufzeit der Bestimmung der Normalform, als auch der Normalisierungsalgorithmen. Um die Normalform zu bestimmen, muss u. a. überprüft werden, ob Attribute von einem Schlüsselkandidaten partiell abhängig sind. Die Berechnung der Schlüsselkandidaten ist
NP-vollständig (s. [RG03], vgl. [Mei09]). Sie erfordert die Bestimmung der Potenzmenge der n Attribute, sodass hier also der Speicherverbrauch bereits in O(2n ) liegt.
Tabelle 7.2 stellt die Laufzeit der Bestimmung der Normalform in Abhängigkeit der
vorhandenen Attribute dar.
Anz. Attribute
Laufzeit
3
6
11
13
≤ 1s ≤ 1s ≤ 2s ≤ 4s
14
≤ 5s
15
16
17
≤ 11s ≤ 25s kritisch
Tabelle 7.2.: Laufzeit in Abhängigkeit der Attribute
Bei einer Kardinalität der Attributmenge von n ≥ 17 wird folgende Exception
geworfen:
1
2
3
4
5
6
7
8
9
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java
heap space
at java.util.LinkedHashMap.createEntry(LinkedHashMap.java:424)
at java.util.LinkedHashMap.addEntry(LinkedHashMap.java:406)
at java.util.HashMap.put(HashMap.java:385)
at java.util.HashSet.add(HashSet.java:200)
at fd.Relation.powerset(Relation.java:927)
at fd.Relation.determineKeys(Relation.java:283)
at fd.Relation.is2NF(Relation.java:683)
at fd.Relation.getNormalform(Relation.java:207)
Listing 7.1: Heap Space Exception
Dieser Fehler ist offensichtlich auf eine Erschöpfung des Heap-Speichers der JVM
durch die Größe der Potenzmenge, die in der Methode powerset der Klasse Relation
berechnet wird, zurückzuführen. Die Standard-Heap-Größe auf 32-Bit-Systemen ist
64 MB, die durch die Berechnung der Potenzmenge für n = 17 offenbar schnell erreicht werden, wie der Speicherauszug in Abbildung 7.1 zeigt. Eine Analyse der allozierten Objekte (vgl. Abbildung 7.2) ergibt zudem, dass das Problem durch zuviele
LinkedHashMap-Einträge entsteht, die wiederum die interne Implementierung der in
powerset() verwendeten LinkedHashSet-Objekte sind.
45
7. Zusammenfassung und Ausblick
Abhilfe schafft hier die Anpassung des für die JVM verfügbaren Heaps mit den
Optionen -Xms256m -Xmx256m. Jedoch sollte durch die hauptsächliche Anwendung in
der Lehre die erwartete durchschnittliche Attributmenge einzelner Relationen deutlich unter der problematischen Größe liegen.
Abbildung 7.1.: Heap Dump
Abbildung 7.2.: Objekt-Allokation
46
7.2. Fazit
7.2. Fazit
Im Rahmen dieser Arbeit wurde ein Informationssystem für funktionale Abhängigkeiten in PostgreSQL-Datenbanken entwickelt, welches die Visualisierung und Manipulation funktionaler Abhängigkeiten, sowie eine automatische Normalisierung relationaler Datenbankschemata ermöglicht. Dazu wurde zunächst eine Einführung in
die relationale Entwurfstheorie gegeben (s. Kapitel 3) und Lösungsstrategien für die
wesentlichen Problemstellungen entwickelt (s. Kapitel 4.3). Daraufhin erfolgte eine
Beschreibung der resultierenden Softwarearchitektur (Kapitel 5) und der Entwurf
einer grafischen Benutzeroberfläche. Eines der Hauptanliegen während der Entwicklung war es, die GUI möglichst benutzerfreundlich und robust zu gestalten, um das
Informationssystem auch in der Praxis einsetzbar zu machen.
Dabei eignet es sich insbesondere für den Einsatz in der Lehre, um Studierenden
die wesentlichen Konzepte der Datenbanktheorie interaktiv und anschaulich zu vermitteln. Außerdem wird Lehrenden ein Werkzeug zur Verfügung gestellt, mit dem
auf einfache Weise Übungsaufgaben gestellt und überprüft werden können.
Ein weiteres Anwendungsgebiet findet sich in der gezielten Bewertung und Verbesserung von Datenbankschemata. Denn anders als ähnliche Systeme, die zu reinen
Lehrzwecken entwickelt wurden und daher nur theoretisch bzw. modellbasierte Zerlegungen durchführen können (vgl. [Sel05]), ist das in dieser Arbeit entwickelte System
in der Lage, beliebige bestehende Relationenschemata zu normalisieren und die Änderungen, d. h. die Zerlegung, in der Datenbank zu implementieren.
Wie mittels Performanceanalyse in Kapitel 7.1 gezeigt werden konnte, läuft das
System auch bei relativ großen Datenbanken bzw. Relationen schnell und stabil. Dass
bei Relationen mit Attributmengen einer bestimmten Größe der Speicherverbrauch
stark ansteigt, ist aufgrund der NP-Vollständigkeit der Bestimmung der Schlüsselkandidaten nicht zu vermeiden (vgl. [RG03]). Dies sollte bei den typischen Anwendungsszenarien jedoch zu vernachlässigen sein.
Ein konsequenter nächster Schritt in der Weiterentwicklung wäre es, ein Normalisierungsverfahren für BCNF zu implementieren. Durch den modularen Aufbau des
Systems und die klare Aufgabentrennung sollte dies keine Probleme bereiten, da nur
ein weiterer Zerlegungsalgorithmus zu realisieren wäre. Die Erweiterung auf 4NF hingegen würde die Implementierung neuer Datenstrukturen und Algorithmen, die auch
MVDs unterstützen, erfordern. Für den Einsatz in der Lehre sind die höheren Normalformen jedoch uninteressant und auch ihre praktische Bedeutung ist relativ gering,
sodass hier wenig Weiterentwicklungsbedarf besteht. Eine weitere mögliche Richtung
für zukünftige Entwicklungen ist die Unterstützung von graphischen Verfahren zur
Darstellung von FAen. In dieser Arbeit wurde bewusst darauf verzichtet, neben der
tabellarischen weitere Darstellungsformen zu unterstützen, da bei einer großen Zahl
von FAen graphische Darstellungen schnell unübersichtlich werden, wohingegen die
tabellarische für beliebige Größen gut skaliert.
47
Literatur
[Arm74] Armstrong, William W.: Dependency Structures of Data Base Relationships. In: IFIP Congress, 1974, S. 580–583
[BB95] Bell, Siegfried ; Brockhausen, Peter: Discovery of Constraints and Data
Dependencies in Databases (Extended Abstract). In: ECML ’95: Proceedings of the 8th European Conference on Machine Learning. London, UK :
Springer-Verlag, 1995. – ISBN 3–540–59286–5, S. 267–270
[Cod70] Codd, E. F.: A relational model of data for large shared data banks. In:
Commun. ACM 13 (1970), Nr. 6, S. 377–387. – ISSN 0001–0782
[KE06] Kemper, Alfons ; Eickler, André: Datenbanksysteme - Eine Einführung,
6. Auflage. Oldenbourg, 2006. – ISBN 3–486–57690–9
[Mei09] Meine, Matthias: Funktionale Abhängigkeiten in PostgreSQL-Datenbanken
- Normalisierungsverfahren. Bachelorarbeit, Institut für Informationssysteme, Technische Universität Braunschweig. Deutschland, September 2009
[MR92a] Mannila, Heikki ; Räihä, Kari-Jouko: The design of relational databases.
Boston, MA, USA : Addison-Wesley Longman Publishing Co., Inc., 1992. –
ISBN 0–201–56523–4
[MR92b] Mannila, Heikki ; Räihä, Kari-Jouko: On the complexity of inferring
functional dependencies. In: Discrete Appl. Math. 40 (1992), Nr. 2, S. 237–
243. – ISSN 0166–218X
[Pos09] PostgreSQL Global Development Group: The Information Schema. Website, 2009. – Verfügbar online unter: http://www.postgresql.org/
docs/current/interactive/information-schema.html; abgerufen am 14.
Juni 2009.
[RG03] Ramakrishnan, Raghu ; Gehrke, Johannes: Database Management Systems. New York, NY, USA : McGraw-Hill, Inc., 2003. – ISBN 0072465638,
9780072465631
[Sel05] Selikoff, Scott: Database Normalization Tool. Website, 2005. – Cornell
University. Dept. of Computer Science. http://dbtools.cs.cornell.edu;
abgerufen am 01. Mai 2009.
48
Literatur
[SK08] Stark, Thomas ; Krüger, Guido: Handbuch der Java-Programmierung.
Standard Edition Version 6. Inkl. DVD (Programmer’s Choice): Standard
Edition Version 6. 5. Auflage. Addison-Wesley, Muenchen, 2008. – ISBN
9783827328151
[SKS05] Silberschatz, Abraham ; Korth, Henry F. ; Sudarshan, S.: Database
System Concepts. 5. McGraw-Hill Science/Engineering/Math, 2005. – ISBN
0072958863
[SSH08] Saake, Gunter ; Sattler, Kai-Uwe ; Heuer, Andreas: Datenbanken:
Konzepte und Sprachen, 3. Auflage. mitp-Verlag, Redline GmbH, 2008. –
ISBN 978–3–8266–1664–8
[Sun09] Sun Microsystems: What are the system requirements for Java 6? Website, 2009. – Verfügbar online unter: http://www.java.com/en/download/
help/6000011000.xml; abgerufen am 18. April 2009.
[Ull09] Ullenboom, Christian: Java ist auch eine Insel. Programmieren mit der
Java Standard Edition Version 6 (Galileo Computing). 8. Auflage. Galileo
Press, 2009. – ISBN 9783836213714
49
Sachwortregister
– Symbole –
≡ ................................
R ................................
→ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11,
1NF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2NF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3NF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
–F–
12
11
23
16
16
16
–A–
Anomalie . . . . . . . . . . . . . . . . . . . . . . . . .
Armstrong-Axiome . . . . . . . . . . . 11,
Assertion . . . . . . . . . . . . . . . . . . . . . . . . .
Attributhülle . . . . . . . . . . . . . . . . . 13,
–G–
GUI . . . . . . . . . . . . . . . . . . . . . . 24, 34, 38
–H–
15
25
22
25
–B–
BCNF . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Bytecode . . . . . . . . . . . . . . . . . . . . . . . . . . 5
–C–
Codd . . . . . . . . . . . . . . . . . . . . . . . . . . . 1, 3
Constraints . . . . . . . . . . . . . . . . . . . 21, 26
–D–
Data Mining . . . . . . . . . . . . . . . . . . . . . 21
Datenbankkatalog . . . . . . . . . . . . . 9, 27
Denormalisierung . . . . . . . . . . . . . . . . . 16
Domäne . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
–E–
Entwurfstheorie . . . . . . . . . . . . . . . . . . . 1
50
FA . . . . . . . . . . . . . . . . . . . . 11, 17, 21, 25
Fremdschlüssel . . . . . . . . . . . . . . . . 21, 26
funktionale Abhängigkeit . . . siehe FA
hierarchisches Modell . . . . . . . . . . . . . . 1
Hülle . . . . . . . . . . . . . . . . . . . . . . . . . 11, 25
–I–
Impedance Mismatch . . . . . . . . . . . . . . 6
Inferenzregeln . . . . . . . . . . . . . . . . . . . . 11
Information Schema . . . . . . . . . . . . . . 27
Instanz . . . . . . . . . . . . . . . . . . . . . . . 11, 24
Integritätsbedingung . . . . . . . . . . . 4, 22
–J–
Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Java Database Connectivity . . . . siehe
JDBC
Java Runtime Environment . . . . siehe
JRE
Java Virtual Machine . . . . siehe JVM
JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
JRE . . . . . . . . . . . . . . . . . . . . . . . . . . . 5, 32
JVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
–K–
kanonische Überdeckung . . . . . . . . . . 12
Sachwortregister
Relationenmodell . . . . . . . . . . . . . . . . . . 3
–M–
mehrwertige Abhängigkeit . . . . . . . .
Membership-Problem . . . . . . . . . . . . .
Metadaten . . . . . . . . . . . . . . . . . . . . . 9,
MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
25
27
34
–N–
Netzwerkmodell . . . . . . . . . . . . . . . . . . . 1
Normalform . . . . . . . . . . . . . . . . . . . . . . 15
Boyce-Codd- . . . . . . . . . . . . . . . . . 16
Dritte . . . . . . . . . . . . . . . . . . . . . . . . 16
Erste . . . . . . . . . . . . . . . . . . . . . . . . . 16
Zweite . . . . . . . . . . . . . . . . . . . . . . . . 16
Normalisierung . . . . . . . . 15, 17, 20, 25
–P–
PostgreSQL . . . . . . . . . . . . . . . . . 2, 7, 32
Produktfunktionen . . . . . . . . . . . . . . . 17
–R–
Redundanz . . . . . . . . . . . . . . . . . . . . . . . 15
–S–
Schlüsselkandidat . . . . . . . . . . . . . . . . 14
Schlüssel . . . . . . . . . . . . . . . . . . . . . . . . . 14
SQL . . . . . . . . . . . . . . . . . . . . . . . . . . 2, 4, 7
Synthesealgorithmus . . . . . . . . . . . . . . 15
–T–
Transaktion . . . . . . . . . . . . . . . . . . . . . . . 9
Trigger . . . . . . . . . . . . . . . . . . . . 21, 23, 27
-funktion . . . . . . . . . . . . . . . . . . . . . 23
Tupel . . . . . . . . . . . . . . . . . . 3, 11, 24, 25
–V–
View . . . . . . . . . . . . . . . . . . . . . . . . . 21, 26
–Z–
Zerlegungsalgorithmus . . . . . . . . . . . . 15
51
A Detaillierter UML-Entwurf
A.1. Analyse von /F110/ und /F120/
Grobanalyse: Abbildung A.1
Von den angezeigten Relationen kann der Benutzer eine selektieren, die dann von FD
geladen wird. Dabei wird die Normalform der Relation bestimmt und zusammen mit
den FAen von der GUI angezeigt.
Abbildung A.1.: Verteilung von /F110/ und /F120/
Feinanalyse: Abbildung A.2
Wenn über die View der Befehl zum Laden einer Relation ausgelöst wird, leitet
der Controller diesen Aufruf an den SchemaManager weiter. Dieser lädt die übergebene Relation, woraufhin ein PropertyChangeEvent ausgelöst wird, der über den
Controller zurück an die View gesendet wird und eine Aktualisierung der Anzeige
veranlasst.
52
A.2. Analyse von /F200/
Abbildung A.2.: Sequenzdiagramm für /F110/ und /F120/
A.2. Analyse von /F200/
Grobanalyse: Abbildung A.3
Entscheidet sich der Benutzer dazu, eine neue FA zu spezifizieren, zeigt die GUI die
in der Relation vorhandenen Attribute an. Aus diesen stellt der Benutzer die gewünschte FA zusammen. Die Komponente FD prüft darauf hin, ob die FA gültig
ist, d. h. noch nicht impliziert wird und nicht gegen die Ausprägung der Relation
verstößt. Sind beide Bedingungen erfüllt, werden die Änderungen an der Normalform berechnet und von der GUI in einer Vorschau angezeigt; andernfalls erfolgt eine
Fehlermeldung. Wenn der Benutzer die Vorschau prüft, kann er sich entscheiden,
weitere FAen zu spezifizieren, die Änderungen zurückzusetzen oder aber einen Commit durchzuführen. Bei letzterem stellt DBTools zunächst eine Datenbankverbindung
her und implementiert die FA durch einen Trigger. Der fd_catalog wird ebenfalls
aktualisiert und die Verbindung wieder geschlossen. Die GUI übernimmt dann die
durchgeführten Änderungen.
Feinanalyse: Abbildung A.4
Spezifiziert der Benutzer eine neue FA, wird ein FDep-Objekt angelegt, das von der
View über den Controller an den SchemaManager übergeben wird. Die Funktion
isInClosure(FDep) prüft zunächst, ob die FA bereits von den vorhandenen FAen
impliziert wird. Ist dies nicht der Fall, wird über den ConnectionManager eine Ver-
53
A. Detaillierter UML-Entwurf
Abbildung A.3.: Verteilung von /F200/
54
A.3. Analyse von /F210/
bindung hergestellt. Mit deren Hilfe überprüft checkInstance(FDep), ob die FA
gegen die momentane Ausprägung der Relation verstößt. Wenn dies nicht der Fall
ist, fügt addAdditionalFdep(FDep) die FA zur Menge der temporären FAen hinzu.
Ein ausgelöster PropertyChangeEvent veranlasst dann die View dazu, die Anzeige
zu aktualisieren und eine Vorschau auf die Auswirkungen der neuen FA zu erstellen.
Entscheidet sich der Benutzer dann für einen Commit, wird in einer Schleife für jede
temporär hinzugefügte FA der CatalogManager aufgerufen, der diese jeweils durch
einen Trigger implementiert und den fd_catalog aktualisiert. Nach dem Schließen
der Verbindung wird die Anzeige auf den aktuellen Zustand gebracht.
A.3. Analyse von /F210/
Grobanalyse: Abbildung A.5
Wenn eine selektierte FA entfernt werden soll, prüft FD zunächst, ob diese durch
einen Schlüsselconstraint implementiert ist. Ist dies nicht der Fall, wird die Normalform der Relation nach Entfernen der FA berechnet und von der GUI angezeigt. Der
Benutzer kann dann weitere FAen entfernen, die Änderungen zurücksetzen oder aber
einen Commit durchführen. Für den Commit wird von DBTools eine Datenbankverbindung hergestellt und die entsprechenden FAen und die sie implementierenden
Trigger werden entfernt. Nach dem Schließen der Verbindung wird die Anzeige mit
der veränderten Relation aktualisiert.
Feinanalyse: Abbildung A.6
Spezifiziert der Benutzer eine zu löschende FA, wird deren ID von der View über den
Controller an den SchemaManager übergeben. Dieser lässt über den CatalogManager
eine Verbindung herstellen und alle Informationen der zu dieser ID gehörenden FA
aus dem fd_catalog auslesen, die dann in einem FDep-Objekt gespeichert werden.
Das resultierende Objekt wird dann mittels addRemovedFdep(FDep) zur Menge der
temporär gelöschten FAen hinzugefügt. Ein ausgelöster PropertyChangeEvent veranlasst dann die View dazu, die Anzeige zu aktualisieren und eine Vorschau auf die Auswirkungen der neuen FA zu erstellen. Entscheidet sich der Benutzer dann für einen
Commit, wird in einer Schleife für jede temporär entfernte FA der CatalogManager
aufgerufen, der diese und den jeweils implementierenden Trigger löscht und den
fd_catalog aktualisiert. Nach dem Schließen der Verbindung wird die Anzeige auf
den aktuellen Zustand gebracht.
55
A. Detaillierter UML-Entwurf
Abbildung A.4.: Sequenzdiagramm für /F200/
56
A.3. Analyse von /F210/
Abbildung A.5.: Verteilung von /F210/
57
A. Detaillierter UML-Entwurf
Abbildung A.6.: Sequenzdiagramm für /F210/
58
A.4. Analyse von /F300/
A.4. Analyse von /F300/
Grobanalyse: Abbildung A.7
Wenn der Benutzer eine gewünschte Normalform auswählt, berechnet die Komponente FD die daraus resultierende Zerlegung der Relation. Eine Vorschau darauf wird von
der GUI angezeigt. Ein Rollback verwirft die Zerlegung, während ein Commit dazu
führt, dass FD die Änderungen am Datenbankschema vornimmt und DBTools daraufhin den fd_catalog aktualisiert. Nach dem Schließen der benutzen Verbindung wird
die Anzeige aktualisiert.
Abbildung A.7.: Verteilung von /F300/
Feinanalyse: Abbildung A.8
Eine Normalisierung wird durch den Benutzer ausgelöst, woraufhin die gewünschte
Normalform von der View über den Controller an den SchemaManager übergeben
59
A. Detaillierter UML-Entwurf
wird. Dieser führt (im Falle von 3NF) auf der geladenen Relation den Synthesealgorithmus aus, der eine Menge von neuen Relationen zurückliefert. Durch einen
PropertyChangeEvent wird die View veranlasst, eine Vorschau dieser Zerlegung anzuzeigen. Wird dann vom Benutzer ein Commit ausgeführt, erstellt der SchemaManager
mittels createTables() die neuen Relationen in der Datenbank, kopiert die Inhalte
der Originalrelation in ebendiese (copyContents()) und behandelt eventuell vorhandene Fremdschlüsselbeziehungen und Check-Constraints durch den Aufruf von
addConstraints(). In einer Schleife werden dann alle FAen der Originalrelation mit
removeFdep(id,table) gemäß /F210/ entfernt und schließlich die Relation selbst
aus der Datenbank gelöscht. In einer weiteren Schleife fügt addFdep(FDep) die auf
die neuen Relationen aufgeteilten FAen wieder hinzu. Schließlich wird die Verbindung
geschlossen und ein PropertyChangeEvent ausgelöst, der die View aktualisiert.
60
A.4. Analyse von /F300/
Abbildung A.8.: Sequenzdiagramm für /F300/
61
B Bedienungsanleitung
Bei der Entwicklung des Informationssystems wurde darauf geachtet, die Bedienung
möglichst einfach und effizient zu gestalten. Zur Unterstützung des Benutzers wird
in diesem Anhang zusätzlich ein kurzer Abriß über die Funktionalität geboten, um
so die Einarbeitungszeit zu minimieren.
Programmstart Direkt nach Programmstart ist der größte Teil der Oberfläche deaktiviert (s. Abbildung B.1), da keine Informationen zur Anzeige vorhanden sind.
Über das Serversymbol in der Toolbar oder das Hauptmenü File | Connect lässt
sich nun eine Verbindung erstellen oder auswählen.
Abbildung B.1.: Systemstart
62
l
Verbindungsauswahl Der Verbindungsmanagerdialog (s. 1 in Abbildung B.2) bietet die Möglichkeit, Profile für Datenbankverbindungen zu definieren, die auf der
Festplatte abgespeichert werden. So müssen die zugehörigen Verbindungsdaten nur
einmal eingegeben werden und das Wechseln zwischen verschiedenen Servern/Datenbanken ist problemlos möglich. Bestehende Profile können geändert oder entfernt
werden. Wird ein Profil gewählt, kann mittels Connect eine Verbindung hergestellt
werden.
l
1
Abbildung B.2.: Verbindungsaufbau
l
FA-Manipulation Wurde eine Verbindung hergestellt, wird das Datenbankschema
ausgelesen und im Relationenbaum (s. 1 in Abbildung B.3) auf der linken Seite
dargestellt. Die Relationen können aufgeklappt werden, woraufhin ihre Attribute
sichtbar werden. Wird eine Relation selektiert, werden im mittleren Bereich 2 die
zugehörigen FAen in Tabellenform angezeigt. Im rechten Bereich der Oberfläche lassen sich durch Selektion von Listeneinträgen 3 weitere FAen spezifizieren, die dann
ebenfalls in der zentralen Tabelle erscheinen, jedoch grün hinterlegt sind, um deutlich
zu machen, dass sie sich insofern von den anderen FAen unterscheiden, als dass sie
noch nicht in die Datenbank festgeschrieben wurden. Das Festschreiben kann über
l
l
63
B. Bedienungsanleitung
l
das Diskettensymbol in der Toolbar 4 erfolgen, wohingegen das Warnsymbol dazu
führt, dass die Änderungen zurückgesetzt werden.
Wird eine Zeile in der Tabelle und somit die entsprechende FA ausgewählt, kann
diese über den Button Remove 5 entfernt werden. Die FA verschwindet darauf hin
nicht aus der Tabelle, sondern wird rot hinterlegt. Natürlich können sowohl mehrere
neue FAen spezifiziert werden, als auch mehrere bestehende FAen entfernt werden,
bevor die Änderungen in die Datenbank festgeschrieben werden. Die Auswirkungen
der Änderungen auf den Normalisierungsgrad werden im oberen rechten Bereich dargestellt, wo sowohl die momentane Normalform 6 , als auch jene nach einem Commit
7 angezeigt wird.
l
l
l
l
4
l
7l
6
l
1
l
l
3
2
l
5
Abbildung B.3.: Hinzufügen/Entfernen von FAen
l
Normalisierung Soll gezielt eine bestimmte Normalform, d. h. 2NF oder 3NF, hergestellt werden, kann diese über die Radio-Buttons (s. 1 in Abbildung B.4) ausgewählt und mittels Preview die entsprechende Vorschau angezeigt werden. Die Checkbox Steps ermöglicht es, optional die Berechnungsschritte, die zum Ergebnis der
Normalisierung führen, mit anzuzeigen. Die Vorschau, wie in Abbildung B.4 2 zu
sehen, beinhaltet die neu entstehenden Relationen und ihre Attribute, sowie Infor-
l
64
mationen darüber, wie die FAen der zu normalisierenden Relation aufgeteilt werden.
Der Vorschaudialog ist dabei an die Oberfläche des Hauptprogramms angelehnt und
erleichtert somit die Bedienung. Neu zu erstellende Relationen können umbenannt
werden, etwa um sprechende Namen zu vergeben. Commit schreibt die Änderungen
in die Datenbank fest, Cancel führt keine Änderungen durch, sondern verwirft die
Änderungen.
l
1
l
2
Abbildung B.4.: Normalisierung
65
C Schnittstellenspezifikation
Die in den Tabellen C.1 und C.2 beschriebenen Interfaces definieren die Schnittstellen
dieser Arbeit zu [Mei09]. Detailliertere Informationen sind dem Javadoc dieser Arbeit
zu entnehmen.
Operation
getNormalform(boolean preview) :
String
normalize(NF form) :
SortedSet<SynRelation>
isKey(Set<String> candidate) :
boolean
xPlus(boolean preview, Set<String>
attributes) : Set<String>
getColumns() : SortedSet<String>
setColumns(SortedSet<String>
columns) : void
getRelationName() : String
getAdditionalFdeps() : Set<FDep>
setAdditionalFdeps(Set<FDep>
additionalFdeps) : void
addAdditionalFdep(FDep fd) : void
getRemovedFdeps() : Set<FDep>
setRemovedFdeps(Set<FDep>
removedFdeps) : void
addRemovedFdep(FDep fd) : void
getFdeps() : SortedSet<FDep>
addFdep(FDep fd) : void
Beschreibung
Bestimmt die Normalform der Relation.
preview gibt an, ob temporäre Änderungen an den FAen berücksichtigt werden
sollen.
Zerlegt die Relation in eine Menge von
Relationen, die in der durch form bestimmten Normalform sind.
Liefert true, wenn candidate ein Schlüsselkandidat der Relation ist.
Berechnet die transitive Attributhülle.
preview gibt an, ob auch temporäre FAen
berücksichtigt werden.
Gibt die Attribute der Relation zurück.
Setzt die Attribute der Relation auf
columns.
Gibt den Relationennamen zurück.
Gibt alle temporär hinzugefügten FAen
zurück.
Setzt die Menge der temporär hinzugefügten FAen auf additionalFdeps.
Fügt eine FA fd temporär hinzu.
Gibt alle als gelöscht markierten FAen zurück.
Setzt die Menge der als gelöscht markierten FAen auf removedFdeps.
Markiert fd temporär als gelöscht.
Gibt alle dauerhaften FAen zurück.
Fügt eine FA fd dauerhaft hinzu.
Tabelle C.1.: Schnittstellenspezifikation Normalizable
66
Operation
generateAddConstraint(
String referencedTable,
String referencingTable,
Map<String, String> refMap,
String onUpdate, String onDelete) :
String
generateCreateTable(
Map<String, String> typeMap,
SynRelation srel) : String
generateTFunction(FDep fd,
String rname, String fname) :
String
generateTFunctionName(int id,
String rname) : String
generateTrigger(int id, String rname,
String fname) : String
generateTriggerName(int id,
String rname) : String
generateIntraFKeys(
Set<SynRelation> newRelations,
Connection con) : Set<String>
Beschreibung
Generiert SQL-Code zum Hinzufügen von
Fremdschlüsseln zu einer Relation.
Generiert SQL-Code zum Erstellen einer
Relation.
Generiert SQL-Code für eine Triggerfunktion.
Generiert einen eindeutigen Namen für eine Triggerfunktion.
Generiert SQL-Code für einen Trigger.
Generiert einen eindeutigen Namen für
einen Trigger.
Generiert SQL-Code für eine Menge von
internen Fremdschlüsselbeziehungen.
Tabelle C.2.: Schnittstellenspezifikation IStatement
67
Herunterladen