.ds RH \f3Datenbank\f1 .ds CH - % - .ds LH Anwendung .bp .NH 2 .ft B Arbeit mit Datenbanken * .ft R .LP .sp 10 .NH 3 .ft B Vorbemerkung * .ft R .LP In diesem Abschnitt wird beschrieben, wie die Relationen der Datenbank erzeugt, strukturiert und verwaltet werden. Es wird davon ausgegangen, dass der Leser etwas vertraut ist und die Anfragesprache QUEL von \*(yy\ versteht. .sp 1 Um eine neue Datenbank zu gr\o'u"'nden, m\o'u"'ssen sie ein g\o'u"'ltiger (eingetragener) \*(yy\-Nutzer sein und die .ft B creatdb .ft R \-Erlaubnis haben. Diese Erlaubnis wird vom \*(yy\-Sy\%stem\%ad\%mi\%ni\%stra\%tor verliehen. Wenn sie beide Bedingungen erf\o'u"'llen, k\o'o"'nnen sie eine Datenbank unter Verwendung des \*(xx\-Shell-Kommandos .sp 1 .ft B % creatdb meindb .ft R .sp 1 gr\o'u"'nden, wobei .ft B meindb .ft R der Name der Datenbank ist. Sie werden Datenbankadministrator (DBA) f\o'u"'r "meindb". Als DBA haben sie spezielle Berechtigungen. .sp .IP 1. Alle von ihnen erzeugten Relationen k\o'o"'nnen von allen anderen, .ft B meindb .ft R verwendenden, Nutzern benutzt werden. Erzeugt aber dagegen ein beliebiger Nutzer eine Relation, so ist sie strikt privat und auf sie kann weder vom DBA noch von einem anderen Nutzer zugegriffen werden. .RE .sp .IP 2. Sie k\o'o"'nnen das .ft B -u .ft R \-Flag in .ft B quel .ft R und .ft B printr .ft R verwenden. Das bef\o'a"'higt sie, \*(yy\ auf .ft B meindb .ft R als ein anderer Nutzer laufen zu lassen. Schlagen sie im \*(yy\-Referenz- Manual unter den Kapiteln .ft B quel(unix) .ft R und .ft B users(files) .ft R wegen detaillierten Angaben nach. .RE .sp .IP 3. Sie k\o'o"'nnen mit .ft B sysmod .ft R , .ft B restore .ft R , .ft B creatdb .ft R , .ft B destroydb .ft R und .ft B purge .ft R auf .ft B meindb .ft R arbeiten. .RE .sp .IP 4. Eine Datenbank, die ohne Angabe von Flags gegr\o'u"'ndet wurde, gestattet mehrere mitwirkende Nutzer. Wenn jeweils nur ein Nutzer die Datenbank zu bestimmter Zeit verwenden m\o'o"'chte, kann der Datenbankadministrator die Gleichzeitigkeitskontrolle ausschalten. Schlagen sie unter .ft B creatdb(unix) .ft R im \*(yy\- Referenz-Manual nach. .RE .sp 1 Wenn eine Datenbank gegr\o'u"'ndet ist, sollten sie sofort .sp 1 .ft B % sysmod meindb .ft R .sp 1 geben. Dieses Kommando konvertiert die Systemrelationen in die g\o'u"'nstigste Struktur zur Verwendung in \*(yy\. .ft B sysmod .ft R wird sp\o'a"'ter ausf\o'u"'hrlich erkl\o'a"'rt. .sp 1 Als DBA oder als ein Nutzer k\o'o"'nnen sie neue Relationen in jeder Datenbank erzeugen, zu der sie Zugriffsrecht haben. Die vorliegenden Ausf\o'u"'hrungen beschreiben, wie das gemacht werden muss. .NH 3 .ft B Erzeugung neuer Relationen mit QUEL .ft R .LP Es gibt zwei Wege um neue Relationen mit QUEL zu erzeugen. .sp 1 .IP create .br retrieve into .RE .sp 1 .ft B retrieve into .ft R wird verwendet, um eine neue Relation aus einer oder mehreren existierenden Relationen zu formieren. .ft B create .ft R wird verwendet, um eine neue Relation ohne Tupel (leer) zu erzeugen. .sp 1 Beispiel 1: .sp 1 .DS range of t is teile range of l is lieferung retrieve into neuliefrg( nummer = l.lnum, t.tname, l.liefdat) where l.tnum = t.tnum .DE .sp 1 Beispiel 2: .sp 1 .DS create neuliefrg( nummer = i2, tname = c20, liefdat = c8) .DE .sp 1 Im Beispiel 1 erzeugt QUEL eine neue Relation, genannt "neuliefrg". Das Format der Dom\o'a"'nen wird berechnet. Die Query wird bearbeitet und "neuliefrg" modifiziert zu "cheapsort". (Dies wird ausf\o'u"'hrlicher im Abschitt 2.2.4. erkl\o'a"'rt.) .sp 1 Im Beispiel 2 wird "neuliefrg" erzeugt und der Name sowie das Format f\o'u"'r jede Dom\o'a"'ne angegeben. Die zugelassenen Formattypen sind: .sp 1 .DS I i1 1 Byte Integer i2 2 " " i4 4 " " f4 4 Byte Gleitkommazahl f8 8 " " " " c1,c2,..,c255 1,2,..,255 Byte Zeichenkette .DE .sp 1 Im Beispiel 2 betr\o'a"'gt die L\o'a"'nge eines einzelnen Tupel 30 Byte (2 + 20 + 8). Die Relation hat drei Dom\o'a"'nen. Es ist klar, dass \*(yy\ Grenzen hat. Eine Relation kann installationsabh\o'a"'ngig 49 bzw. 128 Dom\o'a"'nen und eine Tupell\o'a"'nge von \o'u"'ber 498 bzw. 1010 Byte haben. .sp 1 \*(xx\ stellt den Speicherplatz auf der Platte in Bl\o'o"'cken von 512 Byte, 1KByte bzw. 4KByte bereit. Datens\o'a"'tze werden in \*(yy\ in Seiten (pages) abgelegt, deren Gr\o'o"'ssen beim Anlegen einer Datenbank eingestellt werden. Die maximale Seitengr\o'o"'sse ist generierungsabh\o'a"'ngig. .br \*(yy\ teilt ein Tupel nicht \o'u"'ber zwei Seiten, so kann es vorkommen, dass Speicherplatz vergeudet wird. In einer Seite werden f\o'u"'r den .ft B overhead .ft R 12 Bytes zuz\o'u"'glich je 2 Byte pro Tupel f\o'u"'r Verwaltungsaufgaben genutzt. Die Berechnungsvorschriften sind: .sp 1 .DS L Anzahl der Tupel pro Seite = (Seitengr\o'o"'sse-12)/(Tupell\o'a"'nge + 2) .sp 1 Verschwendeter (oder verschenkter) Speicherplatz = (Seitengr\o'o"'sse-12) - (Anzahl der Tupel pro Seite) * * (Tupell\o'a"'nge + 2) .sp 1 .DE F\o'u"'r unser Beispiel und 512-Byte-Seitengr\o'o"'sse ergibt das .sp 1 .IP 15 = 500 / (30 + 2) .br .sp 1 20 = 500 - 15 * (30 + 2) .RE .sp 1 15 Tupel pro Seite und 20 Bytes unbelegter Platz. Diese Berechnung gilt nicht f\o'u"'r komprimierte Relationen. Wir werden auf dieses Problem im Weiteren zur\o'u"'ckkommen, wenn Tupelkompression diskutiert wird. .sp 1 Wenn sie einen Dom\o'a"'nenname oder ein Format vergessen haben, benutzen sie das "help"-Kommando. Geben sie auf das Beispiel bezogen das QUEL- Kommando .sp 1 .IP help neuliefrg .RE .sp 1 wird folgendes gedruckt: .DS Relation: neuliefrg ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Owner: bob Tuple width: 30 Saved until: Thu Nov 10 08:35:06 1988 Number of tuples: 0 Storage structure: heap Relation type: user relation attribute name type length keyno. nummer i 2 tname c 20 liefdat c 8 .DE Merken sie sich, dass jede Relation ein Verfallsdatum hat. Es wird ausgehend vom Erzeugungsdatum der Relation auf eine Woche festgesetzt. Das .ft B save .ft R \-Kommando kann verwendet werden, um diesen Zeitraum zu verl\o'a"'ngern. Beachten sie dazu .ft B save(quel) .ft R und .ft B purge(unix) .ft R im \*(yy\-Referenz- Manual. .NH 3 .ft B Das Kopieren von Daten aus und in eine .ft R .br .ft B Datenbank .ft R .LP .NH 4 .ft B Allgemeine M\o'o"'glichkeiten .ft R .LP Wenn eine Relation gegr\o'u"'ndet wurde, gibt es folgende M\o'o"'glichkeiten, neue Daten einzuf\o'u"'gen: .sp .IP append-Kommando .br copy-Kommando .RE .sp .ft B append .ft R wird zum Einf\o'u"'gen eines einzelnen Tupel zu irgend\%einem Zeitpunkt oder zum F\o'u"'llen einer Relation aus anderen Relationen verwendet. .sp .ft B copy .ft R wird zum Kopieren von Daten aus einem \*(xx\-File in eine Relation benutzt. Es ist anzuwenden, um Daten von einem anderen Programm oder von einem anderen System zu kopieren. Es ist auch gebr\o'a"'uchlich, um gr\o'o"'ssere Datenmengen zu kopieren. .sp Wir wollen nun eine einfache Relation erzeugen und Daten dort einbringen. .sp Beispiel: .sp .DS create abgabe (name = c10, wert = f4, ext = i2) .DE Jetzt sollen zwei Personen eingegeben werden. Die einfachste M\o'o"'glichkeit ist nat\o'u"'rlich, diese Eingabe unter Verwendung des QUEL-Kommandos .ft B append .ft R zu vollziehen. .sp .DS append to abgabe (name="frank",wert = 5,ext = 204) append to abgabe (name="harry",ext = 209,wert = 4.50) .DE .sp \*(yy\ erkennt die Dom\o'a"'nen an ihren Namen, unabh\o'a"'ngig von ihrer aufgelisteten Reihenfolge. Die Relation .ft B abgabe .ft R sieht jetzt so aus: .DS abgabe relation |name |wert |ext | |----------------------------| |frank |5.000 |204 | |harry |4.500 |209 | |----------------------------| .DE .sp Wir haben zwei Personen in die .ft B abgabe .ft R \-Relation eingegeben. Doch was ist, wenn wir weitere f\o'u"'nfzig einzugeben h\o'a"'tten. Die Verwendung des "append"-Kommandos ist aufgrund der umfangreichen Angaben f\o'u"'r jedes Tupel nicht geeignet. Das .ft B copy .ft R \-Kommando entspricht besser unseren Anforderungen. .sp .ft B copy .ft R kann Daten von einem regul\o'a"'ren \*(xx\-File in verschiedenen Formaten \o'u"'bernehmen und sie in die Relation einf\o'u"'gen. Um das "copy"-Kommando zu verwenden, ist vorher ein \*(xx\-File (\o'u"'blicherweise mit "ed") zu erzeugen, das die Daten enth\o'a"'lt. .sp Als Beispiel wollen wir f\o'u"'nf neue Namen in das File unter Verwendung des Editor's eintragen. .LP .DS L % ed a bill,3.50,302 sam,10.00,410 susan,,100 sally,.5,305 george,4.00,302 w newdom 68 q % .DE Das Format des obenstehenden Files ist ein Name gefolgt von einem Komma, gefolgt von einem Wert (wert), dann ein Komma, dann die Erweiterung (extension) und schliesslich ein Newline. Es ist zulaessig, Werte nicht anzugeben, wie zum Beispiel "wert" bei "susan". Solche Leerwerte werden bei numerischen Dom\o'a"'nen zu Null (0) und bei Zeichenketten auf blanks (Leerzeichen) gesetzt. .LP Um zu kopieren, starten wir \*(yy\ und geben das "copy"-Kommando. .LP .DS L copy abgabe (name = c0, wert = c0, ext = c0) from "/mnt/bob/newdom" .DE .LP Das "copy"-Kommando arbeitet folgendermassen: .LP .DS L copy relname (Liste, was zu kopieren ist) from "voller pathname" .DE .LP Obwohl "wert" und "ext" in der Relation als f4 (Gleitkomma) und i2 (Integer) gespeichert sind, haben wir sie im \*(xx\-File aber als Zeichenketten eingegeben. Zur Spezifizierung des Formats der Dom\o'a"'ne akzeptiert .ft B copy: .ft R .IP domain = format .LP wobei .ft B domain .ft R der Dom\o'a"'nenname und .ft B format .ft R im \*(xx\-File einer der folgenden Werte ist: .LP .DS L i1, i2, i4 (Integer der L\o'a"'nge 1, 2, oder 4) f4, f8 (Gleitkommazahl der L\o'a"'nge 4 oder 8) c1, c2, c3,...c255 (Zeichenkette mit fester L\o'a"'nge) c0 (Zeichenkette mit variabler L\o'a"'nge, begrenzt durch Komma, Tabulator oder Newline) .DE Im Beispiel verwenden wir: .IP name = c0, wert = c0, extension = c0 .LP Das bedeutet, dass jede Dom\o'a"'ne im \*(xx\-File als Zeichen\%kette mit variabler L\o'a"'nge gespeichert war. .ft B copy .ft R verwendet das erste Komma-, Tabulator- oder Newline-Zeichen als Ende der Zeichenkette. Das ist ungef\o'a"'hr die gebr\o'a"'uchlichste Nutzung von .ft B copy .ft R , wenn neue Daten erstmalig in eine Relation eingebracht werden. .LP .ft B copy .ft R kann auch benutzt werden, um Daten aus einer Relation in ein \*(xx\-File zu kopieren. Zum Beispiel: .LP .DS L copy abgabe (name = c10, wert = c10, ext = c5) into "/mnt/bob/data" .DE .LP Folgendes ereignet sich: .IP 1. Wenn das File /mnt/bob/data bereits existiert, wird es zerst\o'o"'rt. .IP 2. Das File wird im Modus 600 (nur read/write-Erlaubnis f\o'u"'r den Nutzer) erzeugt. .IP 3. "name" wird als ein 10-Zeichenfeld kopiert, unmittelbar gefolgt von "wert", unmittelbar gefolgt von "ext". "wert" wird konvertiert in eine Zeichenkette der L\o'a"'nge 10. "ext" wird konvertiert in eine Zeichenkette der L\o'a"'nge 5. .LP Das File .ft B /mnt/bob/data .ft R wird eine Folge von Zeichen, die folgendermassen aussieht: .DS L frank``````````5.000``204harry``````````4.500 209bill ```````````3.500``302sam```````````10.000 410susan``` ```````0.000``100sally``````````0.500``305george`````` ```4.000``302 .DE .LP Dabei steht "`" f\o'u"'r . Die Ausgabe wurde zur Darstellung entsprechend des vorliegenden Papierformates in vier Zeilen geteilt. In Wirklichkeit ist das File eine einzige Zeile. Ein anderes Beispiel: .sp .DS copy (name = c0, colon = d1, ext = c0, comma = d1, wert = c0, nl = d1) into "/mnt/bob/data" .DE .sp In diesem Beispiel wird .ft B c0 .ft R interpretiert als "nutze das festgelegte Zeichenketten-Format". F\o'u"'r Zeichenketten-Dom\o'a"'nen ist das die L\o'a"'nge der Dom\o'a"'ne. Numerische Dom\o'a"'nen werden konvertiert in Zeichenketten entsprechend dem \*(yy\-Standardformat (siehe quel(unix)). .sp Die Statements: .IP colon = d1 .br comma = d1 .br nl = d1 .LP werden benutzt um einen Doppelpunkt, ein Komma oder ein Newline in das File einzuf\o'u"'gen. Das Format .ft B d1 .ft R wird als Pseudo-Zeichen (dummy) interpretiert. W\o'a"'hrend des Kopierens in ein \*(xx\-File kann eine ausgew\o'a"'hlte Menge von Zeichen in das File unter Verwendung der .ft B dummy domain .ft R \-Spezifikation eingef\o'u"'gt werden. So w\o'u"'rde das File "/mnt/bob/data" aussehen: .DS L frank : 204, 5.000 harry : 209, 4.500 bill : 302, 3.500 sam : 410, 10.000 susan : 100, 0.000 sally : 305, 0.500 george : 302, 4.000 .DE .LP Wenn sie ein File mit der wirklichen Bin\o'a"'rdarstellung der Zahlen w\o'u"'nschen, ist zu verwenden: .IP copy (name = c10, wert = f4, ext = i2) into "..." .LP Dies w\o'u"'rde ein File mit einer exakten Kopie von jedem Tupel, eins nach dem anderen, erzeugen. Es ist h\o'a"'ufig w\o'u"'nschenswert und das wird hier bezweckt, f\o'u"'r tempor\o'a"'re Backups die Garantie zu haben, dass die Gleitkomma-Dom\o'a"'nen exakt abgebildet sind. .NH 4 .ft B Typische Fehler .ft R .LP Es gibt 17 verschiedene Fehler die bei "copy" auftreten k\o'o"'nnen. Wir wollen einige der h\o'a"'ufigsten durchgehen. .LP Angenommen sie haben ein File mit .sp 1 bill,3.5,302 .br sam,10,410, .br susan,3,100 .sp 1 und arbeiten das "copy"-Kommando .LP .DS copy abgabe (name = c0, wert = c0, ext = c0) from "/mnt/bob/data" .DE .sp 1 ab, dann erhalten sie die Fehlermitteilung .sp 1 .DS L 5809: COPY: Bad input String for Domain wert. Input was "susan".There were 2 tuples sucessfully copied from /mnt/bob/data into abgabe. .DE .LP Folgendes hat sich ereignet: .IP Zeile 2 hat ein extra Komma, die ersten beiden Tupel wurden richtig kopiert, das n\o'a"'chste Tupel ergibt sich dann zu name = "" (blank), wert = "susan", and ext = "3". Aber "susan" ist keine erlaubte Gleitkommazahl, ein Fehler wird generiert und der Prozess wird nach zwei Tupel gestoppt. .LP Wenn sie versuchen ein solches File wie .sp 1 nancy,5.0,35000 .sp 1 zu kopieren erhalten sie die Fehlermitteilung .DS L 5809: COPY: Bad input String for Domain ext. Input was "35000". There were 0 Tuples successfully copied from /mnt/bob/data into abgabe. .DE .LP Hier gilt "ext" als eine i2 (Integer)-Dom\o'a"'ne, Sie kann den Wert 32767 nicht \o'u"'berschreiten. .LP Es gibt weitere "numerische" Fehlermitteilungen, die meisten sind selbsterkl\o'a"'rend. .LP Hinzuzuf\o'u"'gen sind drei, nicht verh\o'a"'ngnisvolle Warnungen, die bei .ft B copy from .ft R auftreten k\o'o"'nnen. .LP Wenn sie von einem File in eine Relation der Art .ft B isam .ft R oder .ft B hash .ft R kopieren, wird die Anzahl der doppelten Tupel mitgeteilt (, sofern welche enthalten sind). Das kann bei .ft B heap .ft R nicht geschehen, weil auf doppelte Tupel nicht gepr\o'u"'ft wird. .LP \*(yy\ ist nicht in der Lage .ft B control characters .ft R (solche wie .ft B bell .ft R etc.) zu speichern. Wenn .ft B copy .ft R ein .ft B control character .ft R liest, konvertiert es dieses in .ft B blank .ft R und teilt die Anzahl der Dom\o'a"'nen mit, in denen diese Zeichen enthalten waren. .LP Wenn sie mit der c0 -Option kopieren, wird "copy" ihnen mitteilen, wieviele Zeichen\%ketten l\o'a"'nger als ihre zugeh\o'o"'rigen Dom\o'a"'nen waren und gek\o'u"'rzt werden. Die Zeichenkette wird abgeschnitten. .NH 4 .ft B Spezielle M\o'o"'glichkeiten .ft R .LP Es gibt einige spezielle Funktionen, die .ft B copy .ft R in der Handhabung etwas erleichtern. .NH 5 .ft B Physische Kopie (bulk copy) .ft R .LP Wenn sie .DS I copy relname () from "file" oder copy relname () into "file" .DE geben, erweitert "copy" das Statement in folgender Bedeutung: .IP Kopiere jede Dom\o'a"'ne in ihrer genauen Reihenfolge entsprechend ihres festgelegten Formats. .LP Wenn sie sagen w\o'u"'rden .IP copy abgabe () into "/mnt/bob/abgabe" .LP w\o'a"'re es dasselbe wie: .DS I copy abgabe (name = c10, wert = f4, ext = i2) into "/mnt/bob/abgabe" .DE Dies verschafft ihnen einen bequemen Weg, um ganze Relationen von und nach \*(yy\ zu kopieren, bspw. aber auch von einer Datenbank in die andere. .NH 5 .ft B Pseudodom\o'a"'nen (Dummy Domains) .ft R .LP Wenn sie Daten von einem anderen Computer oder einem anderen Programm kopieren wollen, kann es vorkommen, dass ein Teil der Daten ignoriert werden soll. Das k\o'o"'nnen sie unter Verwendung der .ft B dummy domain .ft R \-Spezifikation d0, d1, d2 ... d511 realisieren. Zum Beispiel .DS I copy rel (dom1 = c5, dummy = d2, dom2 = i4, dumb = d0) from "/mnt/me/data" .DE Die ersten f\o'u"'nf Zeichen werden in dom1 abgelegt, die n\o'a"'chsten zwei werden ignoriert. Die n\o'a"'chsten vier Bytes geh\o'o"'ren zum Typ i4 (Integer) und gehen zu dom2, und die verbleibende begrenzte Zeichenkette wird ignoriert. Der Name der .ft B dummy .ft R \-Dom\o'a"'ne wird \o'u"'berlesen, die Dom\o'a"'ne muss nicht unbedingt .ft B dummy .ft R heissen, wie das bei .ft B dumb = d0 .ft R der Fall ist. .LP Wie schon erw\o'a"'hnt, k\o'o"'nnen "dummy"-Dom\o'a"'nen verwendet werden, um bei einem "copy into" auf ein \*(xx\-File Spezialzeichen ("special characters") einzuf\o'u"'gen. Die Liste der zugelassenen Dom\o'a"'nen enth\o'a"'lt: .DS I nl newline tab tab character sp space nul a zero byte null a zero byte comma , dash - colon : lparen ( rparen ) .DE .sp 1 .NH 5 .ft B Abschneiden (Truncation) .ft R .LP Es ist nicht ungew\o'o"'hnlich, dass nach einem aufgetretenen Fehler nochmals gestartet werden muss. Der einfachste Weg, das zu tun, ist das L\o'o"'schen der alten Relation. Es wird mit dem Kommando .IP modify relname to truncated .LP realisiert und hat den Effekt des L\o'o"'schens aller Tupel in .ft B relname .ft R , bei gleichzeitiger Freigabe des belegten Plattenspeicherbereichs und der Umwandlung von .ft B relname .ft R zur\o'u"'ck zu .ft B heap .ft R \&. Es ist das logische \o'A"'quivalent zum .ft B destroy .ft R gefolgt von .ft B create .ft R (aber mit etwas weniger Eingabearbeit). .LP Da in den verwendeten Files Formatfehler nicht auszuschliessen sind, ist es im Allgemeinen keine gute Idee mit .ft B copy .ft R Daten in eine Relation mit bereits gepr\o'u"'ften Daten zu transportieren. Die g\o'u"'nstigste Verfahrensweise ist, eine tempor\o'a"'re Relation mit den selben Dom\o'a"'nen zu erzeugen, wie sie die existierende Relation besitzt. Ko\%pieren sie die Daten in die tempor\o'a"'re Relation und dann h\o'a"'ngen ("append") sie diese an die echte Relation an. Zum Beispiel: .DS I create tempdom(name=c10,wert=f4,ext=i2) copy tempdom(name=c0,wert=c0,ext=c0) from "/mnt/bob/data" range of td is tempdom append to abgabe(td.all) .DE .sp 1 .NH 5 .ft B Spezielle Begrenzer (Specifing Delimitors) .ft R .LP Manchmal ist es w\o'u"'nschenswert das Zeichen zu spezifizieren, welches die Zeichenfolge bei "copy from file" begrenzen soll. Das ist mit der Angabe .IP domain = c0delim .LP m\o'o"'glich, wobei .ft B delim .ft R ein g\o'u"'ltiger Begrenzer (delimitor) aus der Liste der zugelassenen Namen oder ein beliebiges Zeichen ist. Diese Liste wurde weiter oben unter .ft B dummy domains .ft R aufgef\o'u"'hrt. Bei den Zeichen muss beachtet werden, dass der beliebige Delimitor ein Zeichen sein muss, welches der interaktive Terminal-Monitor annimmt und der Parser nicht als Operator interpretiert. (Diese Interpretationsart kann umgangen werden, indem die Angabe .ft B c0delim .ft R als String gequotet wird. Das heisst, der gew\o'u"'nschte Delimitor m\o'u"'sste in der Form " .ft B c0) .ft R "geschrieben werden. Zum Beispiel: .IP copy abgabe (name = c0nl) from "/mnt/me/data" .LP kopiert "name" des Files in die Relation. Nur ein Newline begrenzt die Namen richtig, weil Kommas oder Tabulatoren eventuell als Teil eines Namens auftreten k\o'o"'nnen. .LP Bei .ft B copy into file .ft R wird .ft B delim .ft R immer sofort in das File geschrieben, so dass bei .ft B copy into .ft R die Spezifikation lautet: .IP copy abgabe (name = c0nl) into "/mnt/me/file" .LP Genauer gesagt, "name" wird unmittelbar gefolgt von Newline. .NH 5 .ft B Aufhebung der Begrenzer (Quoting) .ft R .LP Soll in einem Wert einer Dom\o'a"'ne der g\o'u"'ltige Begrenzer Verwendung finden, so muss er kaschiert (aufgehoben) werden. Dies geschieht durch das Voranstellen eines backslash .ft B \e .ft R vor dem Begrenzer. .br So kann z.B. das Tupel .IP donald\e, mc, 6.0, 403 .LP korrekt mittels .DS I copy abgabe (name = c0, wert = c0, ext = c0) from "/mnt/bob/data" .DE kopiert werden, wobei "name" den Wert "donald, mc", "wert" den Wert "6.0" neu erh\o'a"'lt. .NH 3 .ft B Speicherstrukturen f\o'u"'r Relationen .ft R .LP .NH 4 .ft B Einf\o'u"'hrung .ft R .LP Wenden wir uns nun den Problemen der Effizienz zu. Haben sie erst einmal eine Relation erzeugt und Ihre Daten unter Verwendung von .ft B copy .ft R oder .ft B append .ft R eingef\o'u"'gt, kann \*(yy\ jede beliebige Query (Kommando aus QUEL) in der Relation ausf\o'u"'hren. Es gibt mehrere M\o'o"'glichkeiten, zur Erh\o'o"'hung der Geschwindigkeit, mit der \*(yy\ die Query ausf\o'u"'hrt. .LP \*(yy\ kann eine Relation in drei verschiedenen internen Strukturen speichern. Sie werden .ft B heap .ft R , .ft B isam .ft R und .ft B hash .ft R genannt. Zuerst wollen wir jede Struktur genauer beschreiben und sp\o'a"'ter unsere Betrachtung ausdehnen. .NH 4 .ft B Heap .ft R .LP Wird eine Relation erstmalig erzeugt, ist sie vom Typ "heap". Es gibt zwei wichtige Feststellungen zu .ft B heap: .ft R doppelte Tupel werden nicht gel\o'o"'scht und die Lokalisierung der Tupel ist unbekannt. Wenn sie die folgende Query ausf\o'u"'hren .IP range of a is abgabe .br retrieve (a.wert) where a.name = "bill" .LP muss \*(yy\ jedes Tupel lesen und pr\o'u"'fen, ob der Name "bill" dort auftritt. Bei kleinen Relationen ist das nicht schlimm, aber bei sehr grossen Relationen kann das Minuten (oder eben bei Computern mit kleinen Hauptspeichern Stunden!) dauern. .NH 4 .ft B Hash .ft R .LP Bei einer Relation, deren Struktur .ft B hash .ft R ist, kann ein schneller Zugriff auf Tupel gew\o'a"'hrt werden, wenn die Suche (Recherche) durch bestimmte Dom\o'a"'nen gesteuert wird. Diese Dom\o'a"'nen werden gew\o'o"'hnlich als .ft B keyed domains .ft R (Schl\o'u"'ssel bzw. Schl\o'u"'sseldom\o'a"'nen) bezeichnet. Weiterhin enthalten, .ft B hash .ft R \-Relationen keine doppelten Tupel. Nehmen wir beispielsweise an, dass die "abgabe"-Relation als .ft B hash .ft R auf die Dom\o'a"'ne "name" gespeichert ist. In der Query .IP retrieve (a.wert) where a.name = "bill" .LP wird \*(yy\ schnell herausbekommen, wo sich das Tupel ann\o'a"'hernd auf der Platte befindet. Wenn die Relation nur einige wenige Tupel enth\o'a"'lt, k\o'o"'nnen sie den Unterschied zwischen .ft B heap .ft R \-und .ft B hash .ft R \-Struktur nicht bemerken. Aber wenn die Relation gr\o'o"'sser wird, ist die Zugriffszeit von sp\o'u"'rbarer Bedeutung. .NH 4 .ft B Isam .ft R .LP Eine .ft B isam .ft R \-Struktur liegt dann vor, wenn die Relation nach einer oder mehreren Dom\o'a"'nen sortiert ist (auch .ft B keyed domains .ft R genannt). Doppelte Tupel treten bei "isam"-Relationen nicht auf. Wenn ein neues Tupel angef\o'u"'gt wird, wird es "ann\o'a"'hernd" an der Stelle platziert, die der Sortierposition in der Relation entspricht. (Das "ann\o'a"'hernd" wird etwas sp\o'a"'ter erl\o'a"'utert.) .LP Angenommen "abgabe" hat die Struktur .ft B isam .ft R auf die Dom\o'a"'ne "name". Die Ausf\o'u"'hrung der Query .IP retrieve (a.wert) where a.name = "bill" .LP wird \*(yy\ veranlassen, festzustellen, wo in der sortierten Folge der Name "bill" steht und nur dieser Teil der Relation wird gelesen. .LP Wenn die Relation ann\o'a"'hernd sortiert ist, ist eine .ft B isam .ft R \-Struktur auch effizient zur Ausf\o'u"'hrung der Query: .IP retrieve (a.wert) where a.name >= "b" and a.name < "g" .LP Diese Query zeigt alle Namen, die mit "b" bis "f" beginnen. Es ist nicht n\o'o"'tig, die gesamte Relation zu durchsuchen, da sie eine isam \-Struktur \o'u"'ber "name" besitzt. .NH 4 .ft B Spezifizierung der Speicherstruktur .ft R .LP Eine von einem Nutzer erzeugte Relation kann durch Anwendung des .ft B modify .ft R \-Kommandos in eine der Speicherstrukturen konvertiert werden. Zum Beispiel .DS I modify abgabe to hash on name oder modify abgabe to isam on name oder eben modify abgabe to heap .DE .sp 1 .NH 4 .ft B Haupt-(primary) und .br \o'U"'berlauf-(overflow) Seiten .ft R .LP An dieser Stelle ist es notwendig auf das Konzept der Haupt- und \o'U"'berlauf-Seiten bei .ft B hash .ft R \-und .ft B isam .ft R \-Strukturen einzugehen. Beide, .ft B hash .ft R und .ft B isam .ft R , sind Techniken der Zuweisung von Tupeln zu festen Seiten einer Relation, basierend auf den Schl\o'u"'sseldom\o'a"'nen der Tupel. So enth\o'a"'lt jede Seite nur eine bestimmte Untermenge der Relation. .LP Wenn ein neues Tupel in eine .ft B hash .ft R \-oder .ft B isam .ft R \-Relation eingef\o'u"'gt wird, stellt \*(yy\ zuerst fest, in welche Seite es geh\o'o"'rt und \o'u"'berpr\o'u"'ft dann den verf\o'u"'gbaren Platz dieser Seite. Wenn dort noch Platz ist, wird das Tupel in dieser Seite untergebracht. Wenn kein Platz ist, wird eine \o'U"'berlauf-Seite erzeugt und das Tupel dort platziert. .LP Die \o'U"'berlauf-Seite wird mit der Originalseite verbunden. Die Originalseite wird als Haupt-Seite bezeichnet. Wenn die \o'U"'berlauf-Seite voll wird, dann er\o'o"'ffnet \*(yy\ eine \o'U"'berlauf-Seite zu dieser. Wir haben dann eine Haupt-Seite, die mit einer \o'U"'berlauf-Seite verbunden ist, welche wiederum mit einer anderen \o'U"'berlauf-Seite verbunden ist. \o'U"'berlauf-Seiten werden dynamisch so hinzugef\o'u"'gt, wie sie gebraucht werden. .sp 2 .NH 4 .ft B Spezifizierung des Freiraumes .br auf einer Seite (free space) .ft R .LP Beim .ft B modify .ft R \-Statement k\o'o"'nnen sie angeben, wieviel Platz zum Wachsen der Relation frei gehalten werden soll. Wie schon erw\o'a"'hnt, ist eine Relation in Seiten gegliedert. Der F\o'u"'llungsfaktor ( .ft B fillfactor .ft R ) spezifiziert, wie weit jede Haupt-Seite belegt werden soll. Diese Festlegung sollte n\o'a"'herungsweise darauf basieren, wieviele Tupel in die Relation noch einzuf\o'u"'gen sind. Zum Beispiel: .IP modify abgabe to isam on name where fillfactor = 100 .LP Hier wird "modify" mitgeteilt, dass jede Seite m\o'o"'glichst mit 100% gef\o'u"'llt werden soll. .IP modify abgabe to isam on name where fillfactor = 25 .LP bewirkt, dass jede Seite zu 25% gef\o'u"'llt, oder mit anderen Worten, zu 75% leer ist. Wir w\o'u"'rden so vorgehen, wenn wir etwa 1/4 der Daten geladen h\o'a"'tten und annehmen, dass sie gleichm\o'a"'ssig \o'u"'ber das Alphabet verteilt sind. .LP Merken sie sich, wenn der .ft B fillfactor .ft R nicht spezifiziert ist, wird \*(yy\ einen vern\o'u"'nftigen Standardwert einsetzen. Auch dann, wenn eine Seite gef\o'u"'llt ist, erzeugt \*(yy\ automatisch eine \o'U"'berlauf-Seite, so dass niemals der Fall eintritt, dass eine Relation nicht erweitert werden kann. .LP Wenn eine Relation zu .ft B hash .ft R modifiziert wird, kann ein Parameter .ft B minpages .ft R (minimale Seitenanzahl) spezifiziert werden. .ft B modify .ft R garantiert, dass mindestens .ft B minpage .ft R als Anzahl der Haupt-Seiten der Relation zugewiesen wird. .LP .ft B modify .ft R berechnet, wieviele Haupt-Seiten ben\o'o"'tigt werden, um die bestehenden Tupel unter Ber\o'u"'cksichtigung des spezifizierten .ft B fillfactor .ft R so unterzubringen, dass keine \o'U"'berlauf-Seiten im Original notwendig sind. Wenn die Zahl kleiner als .ft B minpages .ft R ist, dann wird .ft B minpages .ft R statt dieses Wertes verwendet. .LP Zum Beispiel: .DS modify abgabe to hash on name where fillfactor = 50, minpages = 1 modify abgabe to hash on name where minpages = 150 .DE Im ersten Fall garantieren wir, dass nicht mehr Seiten als notwendig, bei 50% Belegung, benutzt werden. Der zweite Fall ist typisch f\o'u"'r die Modifizierung einer leeren oder fast leeren Relation. Wenn n\o'a"'herungsweise die maximale Gr\o'o"'sse einer Relation bei ihrer Erstellung bekannt ist, kann .ft B minpages .ft R dazu benutzt werden, von Anfang an die Gr\o'o"'sse der Relation auf dem Speicher freizuhalten. .LP Es ist noch eine andere Option f\o'u"'r .ft B hash .ft R zul\o'a"'ssig, die sogenannte .ft B maxpages .ft R . Ihre Syntax ist die gleiche, wie f\o'u"'r .ft B minpages .ft R . Sie kann benutzt werden, um die maximale Anzahl der Haupt-Seiten festzulegen. .NH 4 .ft B Verdichtung (compression) .ft R .LP Die drei Speicherstrukturen ("heap", "hash", "isam") k\o'o"'nnen zus\o'a"'tzlich durch .ft B compression .ft R erg\o'a"'nzt werden. Das geschieht, indem die Speicherstrukturen als .ft B cheap .ft R , .ft B chash .ft R und .ft B cisam .ft R geschrieben werden. Verdichtung reduziert intern den Speicherplatz f\o'u"'r jedes Tupel. Die gegenw\o'a"'rtige "compression"-Technik unterdr\o'u"'ckt nachlaufende .ft B blanks .ft R (Leerzeichen) in den Zeichenkettten-Dom\o'a"'nen. Die Verwendung von .ft B compression .ft R verlangt niemals mehr Platz und normalerweise wird Speicherplatz gewonnen und k\o'o"'nnen die Ausf\o'u"'hrungszeit verk\o'u"'rzt. Dazu ein Beispiel: .IP modify abgabe to cisam on name where fillfactor = 100 .LP Es wird .ft B abgabe .ft R in eine komprimierte .ft B isam .ft R \-Struktur ver\o'a"'ndert und jede Seite so weit als m\o'o"'glich gef\o'u"'llt. Mit .ft B compression .ft R kann jedes Tupel eine verschiedene, komprimierte L\o'a"'nge erhalten. Dadurch muss die Zahl der Tupel, die in einer Seite untergebracht werden k\o'o"'nnen, davon abh\o'a"'ngen, wie erfolgreich die Verdichtung ausgef\o'u"'hrt werden konnte. .LP Verdichtete Relationen sind aufwendiger zu aktualisieren. Wenn ein .ft B replace .ft R auf eine oder mehrere Dom\o'a"'nen ausgef\o'u"'hrt wird und das komprimierte Tupel war k\o'u"'rzer, dann muss \*(yy\ einen neuen Platz f\o'u"'r das Tupel finden. .NH 4 .ft B Zwei Varianten zu einem Problem .ft R .LP Zur Erinnerung, doppelte Tupel werden bei einer .ft B heap .ft R \-Relation nicht gel\o'o"'scht. Verschiedentlich ist es w\o'u"'nschenswert, sie zu l\o'o"'schen und eine .ft B heap .ft R \-Relation zu sortieren. Ein Weg dazu ist, die Relation zu .ft B isam .ft R unter Angabe der Ordnungsmerkmale ( .ft B keyed domains .ft R ) zu modifizieren. Eine Alternative dazu ist entweder die Verwendung von .ft B heapsort .ft R oder .ft B cheapsort. .ft R Zum Beispiel: .DS I modify abgabe to heapsort on name, ext .DE .LP Damit wird die Relation nach "name" und dann nach "ext" sortiert. Die Tupel werden zus\o'a"'tzlich nach den restlichen Dom\o'a"'nen, in der Reihenfolge ihrer urspr\o'u"'nglichen Angabe beim .ft B create .ft R \-Statement, sortiert, so dass in diesem Fall die Relation nach "name", dann "ext" und dann "wert" sortiert wird. Doppelte Tupel werden entfernt. Die Relation wird als .ft B heap .ft R verlassen. .ft B heapsort .ft R und .ft B cheapsort .ft R sind vorgesehen zum Sortieren von tempor\o'a"'ren Relationen, bevor sie gedruckt und gel\o'o"'scht werden. Dies ist wesentlich effektiver, als die Modifizierung zu "isam", da \*(yy\ kein "directory" erzeugt, in dem die Schl\o'u"'sselinformationen f\o'u"'r jede Seite enthalten sind. Die Relation wird .ft B nicht .ft R in der Sortierung gehalten, wenn anschliessend \o'A"'nderungen erfolgen. .LP Beispiele: .br Hier ist eine Sammlung von Beispielen und Erl\o'a"'uterungen zur Abarbeitungseffizienz jeder Query. Die Queries basieren auf den Relationen: .DS I teile(tnum, tname, farbe, gewicht, menge) lieferung(lnum, pnum, jnum, liefdat, menge) range of t is teile range of l is lieferung modify teile to hash on tnum modify lieferung to hash on lnum,jnum retrieve (t.all) where t.tnum = 10 .DE \*(yy\ erkennt, dassteile auf .ft B tnum .ft R via .ft B hash .ft R geschl\o'u"'sselt ist und geht direkt auf die Seite, in der "teile" mit der Nummer 10 gespeichert ist. .IP retrieve (t.all) where t.tname = "magnetband" .LP \*(yy\ liest die vollst\o'a"'ndige Relation und sucht den angegebenen "tname". .IP retrieve (t.all) where t.tnum < 10 and t.tnum > 5 .LP \*(yy\ liest die vollst\o'a"'ndige Relation, weil kein exakter Wert f\o'u"'r "tnum" gegeben war. .IP retrieve (l.liefdat) where l.lnum = 471 and l.jnum = 1008 .LP \*(yy\ erkennt, dass .ft B lieferung .ft R auf die Kombination von .ft B lnum .ft R und .ft B jnum .ft R via .ft B hash .ft R geschl\o'u"'sselt ist und geht direkt zur richtigen Seite. .DS I retrieve (l.liefdat) where l.lnum = 471 .DE .LP \*(yy\ liest die gesamte Relation. .ft B lieferung .ft R ist auf die Kombination von .ft B lnum .ft R und .ft B jnum .ft R via .ft B hash .ft R geschl\o'u"'sselt. Jedoch wurde \*(yy\ nur ein Wert von beiden gegeben, es kann den Vorteil der Speicherstruktur nicht nutzen. .DS I retrieve (t.tname, l.liefdat) where t.tnum = l.tnum and l.lnum = 471 and l.jnum = 1008 .DE .LP \*(yy\ nutzt den Vorteil beider Speicherstrukturen. Es findet zuerst alle Tupel .ft B l.tnum .ft R und .ft B l.liefdat .ft R , bei denen l.lnum = 471 und l.jnum = 1008 ist. Danach \o'u"'berpr\o'u"'ft es alle Tupel t.tname, bei denen t.tnum gleich dem korrekten Wert ist. .LP Dieses Beispiel illustriert, dass es manchmal eine gute Idee ist, eine Relation mit den Dom\o'a"'nen auf .ft B hash .ft R zu modifizieren, die mit einer anderen Relation verbunden ( .ft B joined .ft R ) sind. In diesem Fall w\o'a"'re das die Frage nach t.tnum = l.tnum. .LP .ft B Zusammengefasst: .ft R .LP Um den Vorteil einer .ft B hash .ft R \-Struktur nutzen zu k\o'o"'nnen, ben\o'o"'tigt \*(yy\ einen exakten Wert f\o'u"'r jede Schl\o'u"'sseldom\o'a"'ne. Ein exakter Wert ist soetwas wie: .IP l.lnum = 471 .br l.tnum = t.tnum .LP Ein exakter Wert ist aber nicht: .IP l.lnum >= 471 .br (l.lnum = 10 or l.lnum = 20) .LP Wir wollen nun unsere Aufmerksamkeit einigen F\o'a"'llen zur Anwendung von "isam" widmen: .DS I modify lieferung to isam on lnum,liefdat retrieve (l.all) where l.lnum = 471 and l.liefdat > "75-12-31" and l.liefdat < "77-01-01" .DE .LP Da .ft B lieferung .ft R auf .ft B lnumund .ft R dann auf .ft B liefdat .ft R sortiert ist, kann \*(yy\ den ganzen Vorteil einer .ft B isam .ft R \-Struktur zur Lokalisierung des Bereichs von .ft B lieferung .ft R , der die Query befriedigt, nutzen. .IP retrieve (l.all) where l.lnum = 471 .LP Im Gegensatz zu .ft B hash .ft R , kann eine .ft B isam .ft R \-Struktur noch verwendet werden, wenn nur der erste Schl\o'u"'ssel beschafft wird. .IP retrieve (l.all) where l.lnum > 400 and l.lnum < 500 .LP Wieder wird \*(yy\ den Vorteil der Struktur nutzen. .DS I retrieve (l.all) where l.liefdat >= "75-12-31" and l.liefdat <= "77-01-01" .DE .LP Hier wird \*(yy\ die vollst\o'a"'ndige Relation lesen. Das geschieht, weil der erste Schl\o'u"'ssel (lnum) nicht in der Query vorgeschlagen wurde. .LP .ft B Zusammengefasst: .ft R .LP .ft B isam .ft R gestattet die Beschleunigung des Zugriffs sowohl zu exakten Werten, als auch zu Wertebereichen. Das funktioniert solange, wie wenigstens der erste Schl\o'u"'ssel vom Nutzer vorgegeben wird. .LP Um festzustellen, wo die Tupel in einer "isam"-Relation stehen, durchsucht \*(yy\ das "isam-directory" dieser Relation. Wenn eine Relation nach .ft B isam .ft R modifiziert wird, werden die Tupel zuerst sortiert und dabei die doppelten Tupel gel\o'o"'scht. Als n\o'a"'chstes wird die Relation (unter Verwendung des .ft B fillfactor .ft R ), beginnend mit Block 0, 1, 2... und so weiter, entsprechend der ben\o'o"'tigten Seitenanzahl gef\o'u"'llt. .LP Jetzt wird das .ft B directory .ft R aufgebaut. Die Schl\o'u"'sseldom\o'a"'nen des ersten Tupels jeder Seite werden eingesammelt und in ein .ft B directory .ft R (in der Relation auf Platte gespeichert) gebracht. Das .ft B directory .ft R wird nicht eher ge\o'a"'ndert, als bis die n\o'a"'chste Modifizierung angewiesen wurde. .LP Wann immer ein Tupel zu einer Relation hinzugef\o'u"'gt wird, wird das .ft B directory .ft R durchsucht, um die Seite zu finden, in der das neue Tupel untergebracht werden muss. Damit bleiben in dieser Seite die einzelnen Tupel .ft B nicht .ft R genau sortiert. Das ist auch mit der n\o'a"'herungsweisen ( .ft B approximately .ft R ) Sortierung im obigen Kapitel gemeint. .NH 4 .ft B Vergleich von heap, hash und isam .ft R .LP Wir wollen einmal die Vor- und Nachteile der einzelnen Speicherstrukturen vergleichen. Eine Relation wird immer als .ft B heap .ft R erzeugt. .ft B heap .ft R ist die g\o'u"'nstigste Struktur f\o'u"'r das erstmalige Auff\o'u"'llen einer Relation bei Verwendung von .ft B copy .ft R oder .ft B append. .ft R .LP Der Platz von gel\o'o"'schten Tupeln bei .ft B heap .ft R wird nur in der letzten Seite wiederverwendet. Ein Test auf doppelte Tupel wird bei .ft B heap .ft R \-Relationen nicht ausgef\o'u"'hrt. .LP "hash" ist vorteilhaft f\o'u"'r die Lokalisierung von Tupeln, sofern sie in der Qualifikation ( .ft B where .ft R \-Klausel) durch einen exakten Wert referenziert werden. Die Haupt-Seite von Tupeln kann mit einem vorgegebenen Wert leicht ermittelt werden. .LP .ft B isam .ft R ist gebr\o'a"'uchlich f\o'u"'r exakte Werte und Wertebereiche. Weil das "isam-directory" durchsucht werden muss, um die Tupel zu lokalisieren, ist .ft B isam .ft R nicht so effektiv wie .ft B hash. .ft R .NH 4 .ft B \o'U"'berlauf-Seiten .ft R .LP Wenn ein Tupel eingef\o'u"'gt wird und sich kein freier Raum mehr auf der Haupt-Seite einer Relation befindet, dann wird eine \o'U"'berlauf-Seite erzeugt. Wenn mehr Tupel eingef\o'u"'gt werden, als eine \o'U"'berlauf-Seite aufnimmt, werden weitere Seiten angeh\o'a"'ngt. Obwohl \o'U"'berlauf-Seiten notwendig sind, vermindern sie die Geschwindigkeit des Systems bei Ausf\o'u"'hrung von Recherchen und .ft B update .ft R 's. .LP Beispielsweise wollen wir annehmen das "lieferung" auf .ft B lnum .ft R via .ft B hash .ft R geschl\o'u"'sselt wird und 10 Haupt- Seiten hat. Angenommen der Wert lnum = 3 f\o'a"'llt auf Seite 7. Um alle Tupel mit lnum = 3 zu finden, bezieht \*(yy\ in die Suche die Haupt-Seite 7 und alle zu Seite 7 geh\o'o"'rigen \o'U"'berlauf- Seiten ein (, sofern es welche gibt). Je mehr \o'U"'berlauf-Seiten einbezogen werden m\o'u"'ssen, um so mehr Zeit wird ben\o'o"'tigt, um nach lnum = 3 zu recherchieren. Um doppelte Tupel bei .ft B isam .ft R und .ft B hash .ft R l\o'o"'schen zu k\o'o"'nnen, muss ebenfalls bei .ft B append .ft R und .ft B replace .ft R die Suche \o'u"'ber alle Seiten ausgef\o'u"'hrt werden. .LP Wenn eine .ft B hash .ft R \- oder .ft B isam .ft R \-Relation zu viele \o'U"'berlauf- Seiten hat, empfiehlt es sich, sie erneut zu .ft B hash .ft R oder .ft B isam .ft R zu modifizieren. Damit wird die Relation bereinigt und es werden soviele \o'U"'berlauf-Seiten als m\o'o"'glich eli\%miniert. .NH 4 .ft B Eindeutige Schl\o'u"'ssel .ft R .LP Bei der Wahl des Schl\o'u"'ssels ( .ft B keyed domain .ft R ) einer Relation ist es w\o'u"'nschenswert, weitgehende Eindeutigkeit zu erreichen. Beispielsweise treten bei Personalnummern keine doppelten Nummern auf, w\o'a"'hrend bei solchen Begriffen, wie "Farbe" nur einige wenige verschiedene Werte und manchmal, wie bei "Geschlecht" bekanntermassen nur zwei Werte auftreten k\o'o"'nnen. .LP Wenn eine Relation auf die Dom\o'a"'ne "geschlecht" via .ft B hash .ft R geschl\o'u"'sselt wird, k\o'o"'nnen sie erwarten, dass alle m\o'a"'nnlichen Objekte auf einer Haupt-Seite und dazugeh\o'o"'rigen \o'U"'berlauf-Seiten untergebracht werden, ebenso auch alle weiblichen. Mit einer .ft B hash .ft R \-Relation gibt es keine L\o'o"'sung dieses Problems. Es muss ein Kompromiss zwischen den in der Qualifikation am h\o'a"'ufigsten verwendeten Schl\o'u"'sseln und der Eindeutigkeit der Schl\o'u"'sselwerte gefunden werden. .LP Da der Vorteil der .ft B isam .ft R \-Struktur solange genutzt werden kann, als zumindest der erste Schl\o'u"'ssel vorgegeben wird, k\o'o"'nnen unter Umst\o'a"'nden weitere Dom\o'a"'nen zum Schl\o'u"'ssel hinzugef\o'u"'gt werden, um die Eindeutigkeit desselben zu erh\o'o"'hen. Nehmen wir beispielsweise an, dass die Relation "lieferung" nur 10 verschiedene Lieferanten, aber tausende Tupel hat. Die Wahl einer .ft B isam .ft R \-Struktur, mit den Schl\o'u"'sseln .ft B lnum .ft R und .ft B jnum .ft R wird wahrscheinlich viel mehr eindeutige Schl\o'u"'ssel ergeben. Wie auch immer, die Gr\o'o"'sse des "directories" wird zunehmen und folglich dauert die Suche immer l\o'a"'nger. Wenn sie zur Erh\o'o"'hung der Eindeutigkeit des Schl\o'u"'ssels weitere Dom\o'a"'nen zu Schl\o'u"'ssel hinzuf\o'u"'gen, versuchen sie m\o'o"'glichst die k\o'u"'rzesten auszuw\o'a"'hlen. .NH 4 .ft B Systemkataloge .ft R .LP \*(yy\ verwendet sieben Kataloge ( .ft B relation .ft R , .ft B references .ft R , .ft B attribute .ft R , .ft B indexes .ft R , .ft B tree .ft R , .ft B protect .ft R und .ft B intgrities .ft R ), um Datenbanken zu verwalten und zu organisieren. Der .ft B relation .ft R \-Katalog hat ein Tupel f\o'u"'r jede Relation in der Datenbank. Der .ft B attribute .ft R \-Katalog hat ein Tupel f\o'u"'r jedes Attribut in jeder Relation. Der .ft B indexes .ft R \-Katalog hat ein Tupel f\o'u"'r jeden Sekund\o'a"'rindex. .LP \*(yy\ greift auf diese Kataloge in einer bestimmten Art und Weise zu. Das Programm .ft B sysmod .ft R sollte verwendet werden, um diese Kataloge auf vordefinierten Dom\o'a"'nen via .ft B hash .ft R zu modifizieren. Um .ft B sysmod .ft R anzuwenden, gibt der Datenbankadministrator ein .sp 1 % sysmod Datenbankname .sp 1 .ft B sysmod .ft R sollte unmittelbar nach der Gr\o'u"'ndung einer Datenbank abgearbeitet werden, bzw. nachdem die Relationen erzeugt wurden. Die Datenbank ist nun aufgebaut. Es ist nicht ausreichend, .ft B sysmod .ft R einmal zu starten und es dann zu vergessen. Ein wiederholter Start von .ft B sysmod .ft R \o'u"'berarbeitet die Systemkataloge. Durch die Anwendung werden die meisten \o'U"'berlauf-Seiten gel\o'o"'scht und die Systemantwortzeit in vielerlei Hinsicht verbessert. .NH 3 .ft B Sekund\o'a"'rindizes .ft R .LP Die Verwendung einer .ft B isam .ft R - oder .ft B hash .ft R \-Struktur gestattet, schnell die Tupel einer Relation zu finden und die Werte entsprechend der Schl\o'u"'seldom\o'a"'nen zu \o'u"'bergeben. Manchmal ist das aber nicht genug. Nehmen wir beispielsweise an, wir h\o'a"'tten die "abgabe"-Relation .IP abgabe(name, wert, ext) .LP auf .ft B name .ft R via .ft B hash .ft R geschl\o'u"'sselt. Es ergibt sich ein schneller Zugriff f\o'u"'r Queries mit einem exakten Wert f\o'u"'r .ft B name .ft R in der Qualifikation ( .ft B where .ft R \-Klausel). Doch was ist, falls wir den Queries einen exakten Wert f\o'u"'r .ft B ext .ft R \o'u"'bergeben wollen? .LP .ft B abgabe .ft R kann entweder f\o'u"'r .ft B name .ft R oder .ft B ext .ft R auf .ft B hash .ft R gesetzt werden, wir k\o'o"'nnen w\o'a"'hlen, was anwendungsfreundlicher ist und .ft B abgabe .ft R auf diese Dom\o'a"'ne setzen. Die andere Dom\o'a"'ne (sagen wir "ext") kann einen Sekund\o'a"'rindex (secondary index) haben. Ein Sekund\o'a"'rindex ist eine Relation, die die exakte Position der Tupel zu jedem .ft B ext .ft R in der Relation .ft B abgabe .ft R enth\o'a"'lt. .LP Das Kommando zur Erzeugung eines Sekund\o'a"'rindexes ist: .IP index on abgabe is abgext (ext) .LP Die allgemeine Form lautet: .br .sp 1 index on relation_name is secondary_index_name (domains) .sp 1 Nun beauftragen wir \*(yy\, einen Sekund\o'a"'rindex in der Relation .ft B abgabe .ft R zu erzeugen. Die Dom\o'a"'ne die indiziert werden soll, ist .ft B ext. .ft R Indizes werden in drei Schritten gebildet: .IP 1. .ft B abgext .ft R erzeugt ein .ft B heap. .ft R .IP 2. F\o'u"'r jedes Tupel in .ft B abgabe .ft R , wird ein Tupel mit dem Wert f\o'u"'r .ft B ext .ft R und der genauen Position des korrespondierenden Tupels in .ft B abgabe .ft R in .ft B abgext .ft R eingef\o'u"'gt. .IP 3. Standardm\o'a"'ssig wird .ft B abgext .ft R zu .ft B isam .ft R modifiziert. .LP Wenn wir jetzt die Query .DS range of a is abgabe retrieve(a.wert) where a.ext = 207 .DE starten, wird \*(yy\ automatisch zuerst in .ft B abgext .ft R nachsehen, um ext = 207 zu finden. Wenn es dort ein Tupel findet, geht es direkt zum Tupel in der .ft B abgabe .ft R \-Relation. Da .ft B abgext .ft R auf .ft B isam .ft R f\o'u"'r .ft B ext .ft R gesetzt wurde, wird die Suche nach ext = 207 nat\o'u"'rlich ebenfalls schnell erledigt sein. .LP Wenn sie die Query .IP retrieve(a.wert) where a.name = "frank" .LP starten, dann wird \*(yy\ in der .ft B hash .ft R \-Struktur der Relation .ft B abgabe .ft R versuchen fortzufahren, um die qualifizierten Tupel zu lokalisieren. .LP Da Sekund\o'a"'rindizes eigenst\o'a"'ndige Relationen sind, k\o'o"'nnen sie auch (entweder) .ft B hash, isam, chash .ft R oder .ft B cisam .ft R sein. Es ist nicht vern\o'u"'nftig, einen Sekund\o'a"'rindex auf .ft B heap .ft R zu setzen. .LP Die Beurteilung, welche Struktur geeignet ist, ergibt sich aus den Erkenntnissen, die zuvor diskutiert wurden: .sp 1 Werden die Dom\o'a"'nen durch exakte Werte referenziert? .br Werden sie durch Wertebereiche referenziert? .br etc. .LP In dem Fall, wo die .ft B ext .ft R \-Dom\o'a"'ne durch exakte Werte referenziert und die Relation beinahe gef\o'u"'llt ist, k\o'o"'nnen wir folgendes tun: .DS I modify abgext to hash on ext where fillfactor = 100 and minpages = 1 .DE Sekund\o'a"'rindizes stellen in \*(yy\ einen Weg dar, \o'u"'ber Dom\o'a"'nen auf Tupel zuzugreifen, die keine Schl\o'u"'ssel sind. Eine Relation kann eine beliebige Anzahl von Sekund\o'a"'rindizes haben und ausserdem kann jeder Sekund\o'a"'rindex ein Index auf bis zu sechs Dom\o'a"'nen einer Prim\o'a"'rrelation sein. .LP Wenn ein Tupel in einer Prim\o'a"'rrelation ersetzt (replaced), gel\o'o"'scht (deleted) oder angeh\o'a"'ngt (appended) wird, m\o'u"'ssen alle Sekund\o'a"'rindizes auch aktualisiert werden, die Indizes kosten was. Sie erh\o'o"'hen den Aufwand zur Aktualisierung der Prim\o'a"'rrelation, aber sie k\o'o"'nnen den Aufwand zum Auffinden von Tupel in der Prim\o'a"'rrelation erheblich senken. .LP Ob ein Sekund\o'a"'rindex die Geschwinigkeit der Recherche erh\o'o"'ht oder nicht, h\o'a"'ngt von der Eindeutigkeit der Werte der indizierten Dom\o'a"'nen ab. Die Hauptfrage bleibt, ob eine indirekte Suche \o'u"'ber den Index effizienter als das Durch\%suchen der gesamten Prim\o'a"'rrelation ist. Allgemein ist es effektiver, wenn die Anzahl der Tupel, die die Qualifikation ( where \-Klausel) erf\o'u"'llen, kleiner ist, als die Gesamtzahl der Seiten (Haupt- und \o'U"'berlauf-Seiten) der Prim\o'a"'rrelation. .LP Beispielsweise wollen wir h\o'a"'ufig alle Personen wissen, die weniger als f\o'u"'nf Mark verdienen, dann beachten sie den erzeugten Index .IP index on abgabe is abgwert (wert) .LP Standardm\o'a"'ssig wird .ft B abgwert .ft R eine .ft B isam .ft R -Struktur auf .ft B wert. .ft R Wenn \*(yy\ die Query .IP retrieve(a.name) where a.wert < 5.0 .LP ausf\o'u"'hrt, wird auf a.wert < 5.0 im Sekund\o'a"'rindex lokalisiert und f\o'u"'r jedes Tupel das gefunden wird, das korrespondierende Tupel in .ft B abgabe .ft R geholt. Die Tupel in .ft B abgwert .ft R sind nach wert sortiert, die Tupel in .ft B abgabe .ft R jedoch nicht. Damit wird im Allgemeinen jedes Tupel von .ft B abgabe .ft R \o'u"'ber .ft B abgwert .ft R adressiert, die sich aber auf verschiedenen Seiten befinden. Solche Recherchen \o'u"'ber einen Sekund\o'a"'rindex erfordern mehr Seitenleseoperationen (IO's), als wenn die Prim\o'a"'rrelation .ft B abgabe .ft R sequentiell gelesen worden w\o'a"'re. In solchen F\o'a"'llen ist die Erzeugung eines Sekund\o'a"'rindex' nicht zu empfehlen. .NH 3 .ft B Wiederherstellung (Recovery) und .br Aktualisierung (Update) .ft R .LP .NH 4 .ft B Einf\o'u"'hrung .ft R .LP \*(yy\ wurde sorgf\o'a"'ltig entworfen, um die Integrit\o'a"'t der Datenbank bei bestimmten Arten von Systemfehlern zu sch\o'u"'tzen. Um das \*(yy\ zu erm\o'o"'glichen, wird bei der Ausf\o'u"'hrung von Aenderungen mit dem sogenannten .ft B deferred update .ft R (verz\o'o"'gerte Aktualisierung) oder .ft B batchfile update .ft R (gepufferte Dateiaktualisierung) gearbeitet. Weiterhin gibt es in \*(yy\ zwei Programme .ft B restore .ft R (wiederherstellen) und .ft B purge .ft R (reinigen), die verwendet werden k\o'o"'nnen, um nach aufgetretenen Systemfehlern die Datenbank zu testen und wieder in Ordnung zu bringen. Wir wollen zuerst diskutieren, wie "deferred updates" erzeugt und ausgef\o'u"'hrt werden und uns danach mit der Verwendung von .ft B purge .ft R und .ft B restore .ft R besch\o'a"'ftigen. .NH 4 .ft B Deferred Update und Batch Update .ft R .LP .NH 5 .ft B \o'U"'bersicht .ft R .LP .ft B deferred update .ft R kann man mit verz\o'o"'gerter Aktualisierung \o'u"'bersetzen. .IP Ein .ft B append .ft R \-, .ft B replace .ft R \- oder .ft B delete .ft R \-Kommando wird in vier Schritten ausgef\o'u"'hrt: .IP 1. Ein leeres .ft B batchfile .ft R (Pufferfile) wird erzeugt. .IP 2. Das Kommando wird ausgef\o'u"'hrt und jede Aenderung der Relation wird in das .ft B batchfile .ft R geschrieben. .IP 3. Das .ft B batchfile .ft R wird gelesen und die Relation und ihre Sekund\o'a"'rindizes (falls vorhanden) werden aktualisiert. .IP 4. Das .ft B batchfile .ft R wird zerst\o'o"'rt und \*(yy\ kehrt zum Nutzer zur\o'u"'ck. .LP Das .ft B deferred update .ft R verz\o'o"'gert die wirkliche \o'A"'nderung bis zum tats\o'a"'chlichen Ende der Query. Diese Vorgehensweise hat drei Vorteile: .NH 5 .ft B Beseitigung der Auswirkung von Systemfehlern .ft R .LP Falls das System w\o'a"'hrend einer Aktualisierung zusammenbricht ( .ft B crash .ft R ), kann das \*(yy\-Recovery-Programm entscheiden, entweder die \o'A"'nderung zu Ende auszuf\o'u"'hren oder durch .ft B back out .ft R (Ablehnung) die \o'A"'nderung zur\o'u"'ckzusetzen und die Relation in dem Zustand zu belassen, in dem sie sich vorher befand. .NH 4 .ft B Die Verhinderung endloser Queries .ft R .LP Falls .ft B abgabe .ft R ein .ft B heap .ft R w\o'a"'re und die Query .DS range of a is abgabe append to abgabe(a.all) .DE w\o'u"'rde ohne .ft B deferred update .ft R ausgef\o'u"'hrt, dann wird die Ausf\o'u"'hrung erst bei \o'U"'berlauf des Plattenspeichers bzw. wenn kein freier Platz mehr vorhanden ist, beendet! Das geschieht deshalb, weil \*(yy\ mit dem Lesen der Relation vorn anf\o'a"'ngt und jedes Tupel an das Ende angeh\o'a"'ngt (append) wird. Es w\o'u"'rde bald beginnen, die Tupel zu lesen, die kurz vorher angeh\o'a"'ngt worden sind und unendlich fortsetzen, um das Ende zu erhaschen, das immer wieder entschwindet. .LP Obwohl diese Query sicherlich nicht typisch ist, illu\%striert sie das Problem. Es gibt bestimmte Klassen von Queries, bei denen Probleme durch aktualisierte Ablagen ber\o'u"'hrt werden, die nicht pr\o'a"'zise definiert sind. Mit dem .ft B deferred update .ft R kann garantiert werden, dass die Ergebnisse konsistent und logisch sind. .NH 5 .ft B Beschleunigung der \o'A"'nderungszeiten .br von Sekund\o'a"'rindizes .ft R .LP Sekund\o'a"'rindizes k\o'o"'nnen schneller aktualisiert werden, wenn alle \o'A"'nderungen auf einmal ausgef\o'u"'hrt werden, anstatt jede \o'A"'nderung einzeln. Das schliesst auch den Schutz ein, dass der Sekund\o'a"'rindex die Uebereinstimmung mit der Prim\o'a"'rrelation beh\o'a"'lt. .NH 5 .ft B Abschalten des deferred update .ft R .LP Wenn sie von diesen Argumenten nicht \o'u"'berzeugt wurden, ge\%stattet \*(yy\ auch, das "deferred update" abzuschalten! Tats\o'a"'chlich gibt es sicher F\o'a"'lle, wo es angebracht ist (aber nat\o'u"'rlich nicht notwendig), die \o'A"'nderung direkt auszuf\o'u"'hren, d.h. die Relation wird w\o'a"'hrend der Query ge\o'a"'ndert. .LP Um die direkte \o'A"'nderung anzuwenden, m\o'u"'ssen sie die Erlaubnis des \*(yy\- Systemadministrators haben. Wenn sie das .ft B -b .ft R \-Flag beim Start von \*(yy\ verwenden, wird das .ft B deferred update .ft R ausgeschaltet. .sp 1 % quel -b meindb .sp 1 \*(yy\ verwendet die direkte \o'A"'nderung nur f\o'u"'r Relationen ohne Sekund\o'a"'rindizes. Die Anwendung des .ft B deferred update .ft R wird f\o'u"'r Relationen mit Sekund\o'a"'rindex stillschweigend immer benutzt. Bei Nutzung des .ft B -b .ft R \-Flag m\o'u"'ssen sie auf die oben genannten Vorteile der verzichten. In den meisten F\o'a"'llen sollte man das .ft B -b .ft R \-Flag .ft B nicht anwenden. .ft R .sp 1 Wenn sie \*(yy\ so benutzen, dass sie interaktiv nur ein Tupel eingeben oder \o'a"'ndern, ist es etwas g\o'u"'nstiger das .ft B deferred update .ft R abzuschalten. Wenn das System w\o'a"'hrend einer \o'A"'nderung zusammenbricht, ist die eingebende Person in der Lage, festzustellen, ob das Tupel ge\o'a"'ndert wurde oder nicht. .NH 4 .ft B Restore .ft R .LP \*(yy\ ist so entworfen, dass nach fast allen Typen von Systemabst\o'u"'rzen ein Recovery m\o'o"'glich ist, falls das \*(xx\-File-System konsistent geblieben ist. Das betrifft die \o'A"'nderungskommandos, das .ft B update .ft R \-, .ft B create .ft R \-, .ft B destroy .ft R \-, .ft B modify .ft R \- und auch das .ft B index .ft R \-Kommando. .LP \*(yy\ wurde auf .ft B perfekte Sicherheit .ft R entworfen. Wenn irgend\%eine Nicht\o'u"'bereinstimmung entdeckt oder irgendein Mangel von \*(xx\ zur\o'u"'ckgegeben wurde, generiert \*(yy\ eine System-Error-Mitteilung (SYSERR) und bricht ab. .LP Wenn \*(xx\ zusammenbricht, w\o'a"'hrend \*(yy\ arbeitet, oder ein \*(yy\-SYSERR auftritt, ist es generell sinnvoll, dass der Datenbankadministrator das Kommando .sp 1 % restore data_base_name .sp 1 gibt. Das Restore-Programm erf\o'u"'llt folgende Funktionen: .IP 1. Es pr\o'u"'ft die .ft B "batchfiles". .ft R Wenn es eins findet, pr\o'u"'ft es jedes, um festzustellen, ob es komplett ist. Wenn der System-crash auftrat, w\o'a"'hrend das .ft B batchfile .ft R gerade gelesen und auf die Datenbank ausgegeben wurde, dann holt .ft B restore .ft R die \o'A"'nderung nach. Falls andererseits das .ft B batchfile .ft R noch nicht vollst\o'a"'ndig war, wird es einfach zerst\o'o"'rt, damit ist es so, als w\o'a"'re die Query noch nicht ausgef\o'u"'hrt. .IP 2. Test auf unvollst\o'a"'ndige .ft B modify .ft R \-Kommandos. Dieser Schritt ist entscheidend. Er garantiert, dass sie entweder die Relation so vorfinden, wie vor der Modifikation, oder .ft B restore .ft R ist in der Lage das .ft B modify .ft R -Kommando zu vervollst\o'a"'ndigen. .ft B modify .ft R arbeitet so, dass es eine neue Kopie der Relation in der neuen Struktur erzeugt. Wenn es dann fertig ist, ersetzt es die alte Relation, es speichert die neuen Informationen in ein .ft B modify batchfile .ft R (modifiziertes Pufferfile). Das bef\o'a"'higt .ft B restore .ft R den Stand unfertiger Modifizierungen festzustellen. .IP 3. Test auf die Uebereinstimmung der Systemrelationen. Dieser Test wird verwendet, um .ft B destroy .ft R \-Kommandos zu vervollst\o'a"'ndigen, .ft B create .ft R \-Kommandos zur\o'u"'ckzusetzen und .ft B index .ft R \-Kommandos zur\o'u"'ckzusetzen oder zu vervollst\o'a"'ndigen, die durch einen System-crash unterbrochen wurden. .IP 4. Bereinigung tempor\o'a"'rer Relationen und Files. .ft B restore .ft R f\o'u"'hrt das .ft B purge .ft R \-Programm aus, um tempor\o'a"'re Relationen und tempor\o'a"'re Files, die vom System erzeugt wurden, zu l\o'o"'schen. .ft B purge .ft R wird etwas sp\o'a"'ter detaillierter diskutiert. .LP .ft B restore .ft R kann dem Nutzer nicht sagen, welche Queries ausgef\o'u"'hrt wurden und welche nicht. Es kann nur die Queries erkennen, die gerade liefen, als der crash erfolgte. Falls Queries auch gerettet werden sollen, ist es am besten, sie in ein File auszugeben. Gegebenenfalls kann der Monitor jede Query oder eine Folge von Queries ausgeben und der Nutzer sp\o'a"'ter erkennen, welche Queries ausgef\o'u"'hrt wurden. .LP .ft B restore .ft R hat mehrere Optionen zur Erweiterung seiner Anwendbarkeit, die durch Flags spezifiziert werden. Die Optionen erm\o'o"'glichen: .IP -a fragt vor der Ausf\o'u"'hrung .IP -f verwendet f\o'u"'r .ft B purge .ft R ; l\o'o"'scht tempor\o'a"'re Files; .IP -p verwendet f\o'u"'r .ft B purge .ft R ; l\o'o"'scht verfallene Relationen; .IP no_database erneuert alle Datenbanken, f\o'u"'r die sie DBA sind; .LP Von diesen Optionen ist .ft B -a .ft R die wichtigste. Es kann geschehen, dass durch einen \*(xx\-crash eine Seite des Systemkataloges besch\o'a"'digt wird. Das kann dazu f\o'u"'hren, dass .ft B restore .ft R eine Relation austr\o'a"'gt (zerst\o'o"'rt). In Wirklich\%keit wollen sie lieber zur Beseitigung des Problems die Systemkataloge flicken ( .ft B patch .ft R ), um korrekt weiterarbeiten zu k\o'o"'nnen. Aber kein .ft B restore .ft R \-Programm kann f\o'u"'r alle M\o'o"'glichkeiten eingerichtet werden. Es ist deshalb kein Ersatz (gl\o'u"'cklicherweise !) f\o'u"'r den Menschen. .LP Wenn .ft B -a .ft R spezifiziert ist, teilt .ft B restore .ft R mit, was es tun w\o'u"'rde und fragt dazu nach der Erlaubnis. Es liest von Standard-Input und akzeptiert .ft B y .ft R als Anweisung zur Ausf\o'u"'hrung und die \o'u"'brigen Zeichen als Ablehnung. Beispielsweise, wenn bei .ft B restore .ft R vor Ausf\o'u"'hrung gefragt werden soll, geben sie .IP restore -a meindb .LP Wenn sie auf alle Fragen .ft B nein .ft R antworten wollen, so geben sie .IP restore -a meindb