FoxPro

FoxPro Developer's Conference '94

 

Session 132
RUSHMORE & SQL

Peter Herzog


Grundsätzlich haben wir es mit zwei total verschiedenen Dingen zu tun. Aber wie es so im Leben ist, kommt man nicht herum, beide Teile gleichzeitig zu verwenden. In FoxPro ist sowohl RUSHMORE ein essentieller Teil des Systems, als auch SQL.


 

1. Was ist das eigentlich "RUSHMORE"

Ich assoziiere RUSHMORE eigentlich mehr mit einer Zigarettenwerbung, da es sich im Deutschen wie "Rauch mehr" anhört. <g>

Aber auf der anderen Seite könnte man das Wort in zwei englische Begriffe teilen, wobei der Sinn der Sache schon eher hervorkommt. "Rush" der Begriff, der auch im Wort Rush-hour vorkommt, und somit etwas mit sehr viel zur selben Zeit bedeuten kann. More bedeutet eben "Mehr".

Dies wäre schon mal eine kleine Erklärung, was RUSHMORE eigentlich sein könnte. Es geht um sehr viel, sehr schnell.

Entstanden ist der Begriff, als die Entwickler von RUSHMORE nach einem Namen gesucht hatten und im Fernsehen zur selben Zeit der Hitchcock Film ,Der dritte Mann" im Fernsehen zu sehen war. Hitchcock Fans wissen natürlich, daß sich einer der Hauptszenen auf dem Mount RUSHMORE abspielen. Den Berg, dem man die Köpfe der vier berühmtesten Männer Amerikas eingemeißelt hat.

Nun war eben der Name geboren. Aber worum handelt es sich bei RUSHMORE überhaupt ?

Gesucht wurde eine Möglichkeit auf sehr schnelle Weise aus sehr vielen Daten das Gesuchte herauszufinden. Das sollte ja nicht besonders schwer sein, wenn man schon mal mit Indizes zu tun hatte. Aber komplizierter wurde es, wenn aus verschiedenen Indizes, verschiedene Begriffe gesucht werden müssen. Und als kleines Sahnehäubchen, sollte der Zugriff auf nicht indizierte Teile das ganze nicht sonderlich bremsen.

Also ist mit der Rushmore-Technologie der Zugriff und die Optimierung auf/von Daten gemeint. Da dies so effizient gelungen war, machte man sich auch sofort daran, diese Technologie schützen zu lassen.


 

2. Wie funktioniert RUSHMORE

Jeder weiß, daß man bei NICHT indizierten Daten, die gesamte Datei durchsuchen muß, um festzustellen, ob der gewünschte Begriff vorkommt.

Habe ich als Beispiel eine Artikeldatei und suche nach allen Artikeln, welche mit dem Buchstaben A beginnen, so muß ich die gesamte Datei durchsuchen, bis ich mir sicher sein kann, daß ich alle gefunden habe.

Abhilfe schafft hier ein Index. Ein Index ist sozusagen eine kleine Kopie eines Teils der Datei. Dieser Teil, eben die Artikelnummer aller Datensätze wird nun sortiert.

Wenn ich nun den Buchstaben "A" suche, brauche ich nur in der Mitte des Indexes mit dem Suchen beginnen und taste mich an den Suchbegriff heran, indem ich entweder oberhalb oder unterhalb wieder in der Mitte suche.

Mit 11 mal suchen kann ich z.B. 2 Hoch 11 Datensätze durchsuchen, bis ich das Ergebnis gefunden habe.

Eine weitere Geschwindigkeitssteigerung, bringt das Komprimieren des Index. Der schlimmste Performance-Killer ist die Festplatte. Alles was direkt auf dem Medium gesucht werden muß, verlangsamt den Zugriff auf Daten. Noch schlimmer wird es, wenn man über ein Netzwerk Daten suchen muß. Denn da haben wir das Netzwerkkabel, als Flaschenhals. Wenn nun viele Rechner gleichzeitig auf Daten zugreifen, so müssen sich alle den engen Flaschenhals "Netzwerk" teilen.

Wenn nun der Index komprimiert wird, so müssen natürlich auch nicht mehr so viele Daten vom "Medium" geholt werden. Der Aufwand des Entkomprimierens ist im Verhältnis dazu verschwindend gering.

Das Ganze hat jedoch noch nichts mit RUSHMORE zu tun, denn diese Art der Datensuche ist bereits seit vielen Jahren (Jahrzehnten) bekannt und wird angewendet.

Das normale indexorientierte Suchen nach Daten, kann mit dem SEEK -Befehl von FoxPro verglichen werden. Da wird über den Index auf die Daten zugegriffen und ich kann mir einen Datensatz heraussuchen, der meinem Ausdruck entspricht. Mit den Einstellungen SET NEAR ON|OFF und SET EXACT ON|OFF kann nun diese Suche auch noch eingeschränkt , bzw. verbessert werden. Bei SET EXACT ON, wird der gesuchte Ausdruck nur dann gefunden, wenn er Byte für Byte genauso im Index steht. Wird EXACT auf OFF gelassen und NEAR auf ON gestellt, so wird automatisch der nächst passende Ausdruck gesucht und eventuell gefunden.

Suche ich also nach "A" dann wird das erste Aufkommen von "A" gefunden. Bei EXACT auf ON wird nur dann ein Datensatz gefunden, wenn er auch nur aus einem Buchstaben besteht und dieser "A" heißt.

Etwas komplizierter wird es wenn ich nun den Artikel "A" suche und gleichzeitig den Lieferanten "XY". Also zwei Felder in der Datei gleichzeitig.

Mit dem Seek-Befehl alleine ist dies nicht möglich. Ich muß mich beim SEEK auf einen Index beschränken und dann die restlichen Datensätze durchsuchen, bis ich auf den Lieferanten "XY" stoße. Habe ich nun 50 Lieferanten mit der Artikelnummer "A", so muß ich im schlimmsten Falle 50 mal suchen, bis ich meinen Datensatz habe.

Jetzt kommt RUSHMORE ins Spiel. Unter FoxPro gibt es den Befehl LOCATE FOR. Mit diesem Befehl kann ich gleichzeitig in mehreren Feldern der Datei suchen.

Um unser Beispiel zu benutzen: LOCATE FOR ARTIKELNR="A" AND LIEFERANT="XY".

In der Funktion "FOUND()" bekommen wir nun die Nachricht, ob ein derartiger Datensatz gefunden wurde oder nicht.

Wir könnten uns nun darauf verlassen, daß FoxPro von sich aus weiß, wie er tun muß, um die Daten auf dem schnellsten Wege zu finden. Wenn wir jedoch nicht aufpassen, bzw. vorsorgen, wird FoxPro seine Arbeit genauso langsam erledigen, als ob wir es selbst mit SEEK und SKIP erledigt hätten.

Als Regel soll gelten: Auf alle zu suchenden Begriffe ein Index.

Sobald ein Index auf den Daten liegt, kann FoxPro sehr schnell den oder die Datensätze suchen und natürlich auch finden.

Jetzt taucht natürlich die Frage auf, wie FoxPro dies so verblüffend schnell schafft. In der Theorie ist das Geheimnis "RUSHMORE" schon gelöst worden.

Wen wir für jeden zu suchenden Ausdruck einen Index haben, so können wir uns im Speicher eine Bit-Map für jeden Datensatz anlegen. Ein Bit, pro Datensatz ist nicht besonders viel, auch wenn es sich um eine Million Datensätze handelt. Natürlich ist die gesamte Technik vom Hauptspeicher abhängig. Aber mit einem 286er sollte man nicht solche Datenmengen verwalten.

Die Bitmap im Speicher ist natürlich sehr schnell angelegt und verwaltet. Wenn nun im ersten Index gesucht wird, so kann ich mir im Speicher, diejenigen Bits einschalten, wo ich einen Treffer landen werde.

Dies mache ich für jeden Index, bzw. jeden Ausdruck nach dem ich suchen möchte. Zum Schluß muß ich nur noch die verschiedenen Bitmaps, wie zwei Oberheadfolien übereinanderlegen und kann mir die Treffer heraussuchen, die bei allen Ausdrücken identisch sind.

Der Trick bei der ganzen Sache ist, daß ich auch Ausdrücke suchen kann, die nicht in einem Index stehen. FoxPro ist so clever, daß es zuerst mal alle Ausdrücke sucht, die für ihn voll optimierbar sind, also am schnellsten gehen. Erst für die letzten Datensätze wird dann physikalisch auf der Datei gesucht.

Nun müssen wir sicherstellen, daß FoxPro den Indexausdruck auch richtig interpretieren kann. Wenn ich auf UPPER(artikelnr) indiziere und dann nach artikelnr suche, stimmen die Ausdrücke nicht überein und FoxPro wird sich daranmachen, die Datei zu durchsuchen. Also die ganze Indizierung umsonst.

Als Regel soll gelten: Alle Indexausdrucke und deren Abfrage müssen genau übereinstimmen.

Wenn ich mit INDEX ON LEFT(ARTIKELNR,5) TAG ARTNR indiziert habe, so muß ich bei der Abfrage mit LOCATE auch den selben Ausdruck verwenden. LOCATE FOR LEFT(ARTIKELNR,5)="A".

Die umgekehrte Schreibweise LOCATE FOR ARTIKELNR=Left(ARTIKELNR,5) wird zu KEINER Rushmoreoptimierung führen.

Es ist auch noch anzumerken, daß der Indexausdruck immer links vom Operator stehen muß. (Bsp.: Variable = "Ausdruck")

Ein kleines Problem macht uns nun der Aufbau einer dBase-Datei, die FoxPro verwendet. In jeder dBase-Datei gibt es im ersten Byte eines jeden Datensatzes ein Kennzeichen, welches zeigt, ob ein Datensatz gelöscht ist oder nicht.

Mit dem Befehl SET DELETED ON|OFF können wir entscheiden, ob wir die gelöschten Daten sehen wollen, oder nicht.

Bei jeder Abfrage muß FoxPro also entscheiden, ob gelöschte Daten gesucht werden oder nicht. Bei SET DELETED ON wird automatisch an jede Abfrage AND NOT DELETED() angefügt.

Wie wir bereits gelernt haben, muß jedoch für jeden zu suchenden Ausdruck ein Index vorhanden sein, damit die Abfrage voll optimierbar ist.

Es genügt nun für FoxPro, wenn solch ein Ausdruck in einem Index vorhanden ist. Der Name unter dem der Index angelegt ist, hat hier keine Bedeutung. FoxPro legt ja automatisch für jeden vorhandenen Index, der gesucht wird, eine Bitmap im Speicher an.

Es genügt nun einen Index auf DELETED() anzulegen.

Bsp.: INDEX ON DELETED() TAG GELOESCHT.

Als Regel soll gelten: Immer einen Index auf DELETED() legen.

FoxPro kann ich zwingen, eine bestimmte Reihenfolge einzuhalten. Dies mache ich mit dem Befehl SET ORDER TO tagname.

Diese ORDER-Setzung zwingt FoxPro auch bei einer Abfrage danach vorzugehen. Jetzt kann sich FoxPro die Suche sozusagen nicht mehr selbst am besten einrichten, sondern muß sich nach Ihren Wünschen richten. Da dies bei mengenorientierten Suchvorgängen eher nebensächlich ist, (es geht ja darum, die Daten so schnell wie möglich zu finden) sollte die Order mit SET ORDER TO ausgeschaltet werden. Das Endprodukt der Abfrage kann man ja später auch noch in die richtige Reihenfolge bringen.

Als Regel soll gelten: Mit SET ORDER TO die Indexreihenfolge ausschalten.

Nun zum Thema, der deutschen Umlaute.

Seit FoxPro 2.5 können wir uns für eine andere Sortiersequenz entscheiden.

Nach dem Installieren von FoxPro 2.5 oder 2.6 wird standardmäßig GENERAL als Sortierreihenfolge verwendet. Leider hat es sich herausgestellt, daß diese Sortierung nicht mehr voll zu optimieren ist. Das heißt, daß FoxPro auf alle Fälle für Unterabfragen physikalisch in der Datei suchen muß.

Dieses Manko hat sich leider auch bei der, für Deutsche interessante, Sortierreihenfolge UNIQWT herausgestellt. Eigentlich sollte UNIQWT nur die SYS(15) Funktion ersetzen, mit der zu 2.0er Zeiten noch Umlaute einsortiert wurden. Leider hat sich gerade in jüngster Vergangenheit herausgestellt, daß diese Sortierung bis zu 5 mal langsamer ist, als die Ersetzung eines Umlautes mit der SYS(15) Funktion.

Voll optimierbar ist nur die MACHINE-Sortierung. Wenn nun doch mit Umlauten gearbeitet werden muß, so wird inzwischen empfohlen, zum Zeitpunkt, bei dem ich die ordentliche Einsortierung von Umlauten brauche, auf GENERAL umzuschalten. (SET COLLATE = "GENERAL")

Unter welcher Sortierung sie im Moment arbeiten, können Sie entweder im Umgebungsfenster (SET) sehen, oder lassen sich mit ? SET("COLLATE") die aktuelle Sortierung ausgeben.

Auf den Index hinterläßt eine andere Sortierung einen besonderen Eindruck. Wenn nämlich ein Index mit SET COLLATE = "GENERAL" erzeugt wird, so bekommt er auch die Sortierreihenfolge GENERAL zugewiesen. Wenn Sie nun umschalten auf MACHINE und wiederum einen anderen Index erzeugen, so bekommt dieser MACHINE zugeordnet.

Dies ist allgemein eine tolle Sache, da Sie verschiedene Sortierungen im Index haben können. Auf der anderen Seite ist aber RUSHMORE von der Sortierung abhängig unter der Sie sich im Moment befinden. Wenn Sie also Ihre Indizes unter GENERAL erzeugt haben und später mit MACHINE darauf zugreifen, so wird RUSHMORE automatisch ausgeschalten.

Besonders bemerkbar wird dieses, wenn Sie versuchen von ACCESS auf GENERAL - Sortierte FoxPro Indizes zuzugreifen. Sie werden keinen Rushmoreeffekt bemerken.

Es hat sich als bester Tip herausgestellt, daß man grundsätzlich MACHINE sortiert, um optimal RUSHMORE auszunutzen. Wenn jedoch Umlaute benötigt werden, (Matchcodes, Ortsnamen usw.) explizit auf die richtige Collatesequenz umgeschaltet.

Als Regel soll gelten: Immer auf die Sortiersequenz achten.

Ein ganz schlimmer Finger ist FoxPro, wenn es darum geht einen Index auf eine andere Sortierung umzustellen. Ein REINDEX genügt NICHT. Sie müssen mit DELETE INDEX ... den oder die Indizes herauslöschen und komplett neu aufbauen.

Um überhaupt zu sehen, welche Sortierung im Index steckt, können Sie entweder den Befehl IDXCOLLATE(Indexnummer) oder indem Sie sich mit DISPLAY STATUS die Datenbanken mit den Indizes anzeigen lassen.

Als Regel soll gelten: Indizes immer NEU aufbauen.

Ein weiteres Problem machen Negierungen. Wobei zu unterscheiden ist, ob man den Ausdruck den Indexes egiert oder eine Negierung in der Abfrage verwendet.

Ein INDEX ON NOT DELETED() TAG NOTDEL ist NICHT optimierbar. Eine Abfrage wie: LOCATE FOR ARTIKELNR <> "A" wird funktionieren.

Als Regel soll gelten: Kein NOT in den Indexausdruck

FoxPro bietet uns die Möglichkeit mittels FOR-Klausel einen Teilindex zu erzeugen. Also als Beispiel: INDEX ON ARTIKELNR TAG ARTIKELNR FOR ARTIKELNR="A"

Obwohl obiges Beispiel keinen direkten Sinn ergeben würde, so ist es doch möglich eine Untermenge eines Datenbestandes als Index zu verwenden. Ein SET ORDER TO <Ausdruck> wirkt nun wie ein Filter. Leider ist solch ein Index ebenfalls nicht optimierbar.

Als Regel soll gelten: Keine FOR-Klauseln im Index

Wenn man in einem Index eine genaue Suche durchführen möchte, also exact die selbe Zeichenkette sucht, dann gibt es zwei Möglichkeiten. Einerseits kann man mit SET EXACT ON arbeiten. Dies wirkt sich auf das gesamte System aus, hat aber den Vorteil, daß es optimierbar ist, wobei die kürzere Zeichenkette automatisch mit Blanks gefüllt wird.

Der andere Weg, um exakte Vergleiche zu erlangen ist die Verwendung der doppelten Gleichheitszeichen (==). Dies zwingt jedoch FoxPro einen exakten Vergleich der Daten auf der Platte zu machen, womit dies nun wieder nicht optimierbar ist.

Als Regel soll gelten: SET EXACT OFF und keine Binären Vergleiche

Weiter oben wurde erklärt, daß man bei Umlautsortierungen mächtig viele Fehler machen kann. Um das ganze Problem noch ein bißchen zu vergrößern, hat man sich bei Windows für den ANSI-Zeichensatz entschieden, der leider die deutschen Umlaute an einer anderen Stelle eingeordnet hat, als der unter DOS verwendete ASCII-Zeichensatz.

FoxPro mußte auf dieses Problem reagieren und hat die Codepages eingeführt. In einer FoxPro-Datei wird im Byte 29 hinterlegt, welche Codepage die Datei besitzt.

Aufgrund dieser Codepage wird festgelegt, wie FoxPro die Umlaute ansehen soll. Findet FoxPro in der Datei eine andere Nummer (1 für 437, 2 für 850, 3 für 1252 Windows usw.) als die unter der die Anwendung gerade läuft, so wird automatisch eine Umwandlung der Daten durchgeführt.

Grundsätzlich wird RUSHMORE durch eine andere Codepage nicht beeinflußt, jedoch braucht die Umwandlung der Zeichen eine gewisse Zeit und kann deshalb auf Abfragen Auswirkungen haben.

Auf Dateiebene ist das Codepage-Problem wunderbar gelöst worden. Leider gibt es jedoch in einem Index keine Möglichkeit, eine Codepage zu verankern. Das bedeutet, daß eine mit einer Codepage versehenen Datei, nur unter der selben Umgebung neu indiziert werden darf. Ansonsten wird der Index mit falschen Zeichen gefüttert. RUSHMORE wird zwar nicht "aussteigen" jedoch werden falsche Suchergebnisse geliefert.

RUSHMORE verleitet nun zum wilden herumindizieren. Es muß jedoch darauf hingewiesen werden, daß jeder Index beim INSERT oder APPEND mitgeführt werden muß. Und je mehr Indizes Sie in der Datei haben, desto mehr muß bei INSERT, UPDATE und DELETE gearbeitet werden.

Am besten ist, wenn Sie auf Ihre "Allerweltsfelder" einen Index legen und alle anderen Abfragen Teiloptimiert erledigen.

Teiloptimiert bedeutet, daß FoxPro sich über den Index die schnellste Arbeit erledigt und den Rest auf der physikalischen Datei "durchzählt".

Wo wirkt sich RUSHMORE aus:

Grundsätzlich bei allen Befehlen, bei denen eine FOR-Klausel vorkommt.

Dies wären:

AVERAGE Bilde dem Mittelwert numerischer Ausdrücke
INDEX Erstellt einen Index
BROWSE Zeigt Daten als Fenster an
LABEL Ausdruck von Etiketten
CALCULATE Mathematische Berechnung über Massendaten
LIST Ausgabe von Daten auf Datei, Drucker, Schirm
CHANGE Anzeige von Daten zur Bearbeitung
LOCATE Suchen eines Datensatzes
COUNT Zähle Datensätze
RECALL Wiederherstellen gelöschter Datensätze
COPY TO Kopieren von Daten
REPLACE Ändern von Massendaten
COPY TO ARRAY Kopieren von Daten in den Speicher
REPORT Ausdruck eines Berichtes
SCAN SCAN-ENDSCAN eine Schleifenbedingung
DELETE Löschen von Datensätzen
SORT Sortieren von Datensätzen
DISPLAY Anzeige von Daten
SUM Aufsummierung von Daten
EDIT Gleich wie CHANGE
TOTAL Summierung von Daten und Erstellen neuer Datei
EXPORT Ausgabe der Daten in anderem Format

Zusätzlich darf erwähnt werden, daß der SET FILTER Befehl ebenfalls optimierbar ist.


 

2. SQL

Dies bedeutet Struktured Query Language. Also Strukturierte Abfrage Sprache. Als die Zeit der Datenbanken kam, mußte für die Anwender ein Tool geschaffen werden, mit dem sie Ihre eingegeben Daten auf elegante Art und Weise in welcher Art auch immer wieder herausholen können.

Wie es manchmal so kommt, waren die Erfinder von SQL keine Anwender, sondern Programmierer. Und so wurde aus der anfänglich leichten Abfragesprache eine ziemlich aufwendige und komplizierte Geschichte.

Inzwischen hat sich herausgestellt, daß es wesentlich leichter geht, im Dialog mit dem RQBE oder unter ACCESS dem Abfrageassistenten, die Maschine eine solche Anweisung erstellen zu lassen.

Im FoxPro selber sind nur wenige SQL-Befehle verwirklicht worden. Dies wären:

SELECT, INSERT, CREATE TABLE und CREATE CURSOR.

Da die Abfrage hier das Thema sein soll, so wird nun auf den SELECT -Befehl näher eingegangen. INSERT und die CREATE befehle sind in Ihrem Aufbau so einfach, so daß ich auf die FoxPro-Handbücher oder die Online-Hilfe verweisen darf.

Den Select-Befehl verwenden Sie entweder in Verbindung mit dem RQBE, mit dem Sie Programmunterstützt Ihre Abfrage definieren können, oder Schreiben den Befehl "zu Fuß" wobei Sie hier auch alle zur Verfügung stehenden Optionen ausnutzen können.

Unterabfragen mit UNION sind nämlich mit dem RQBE NICHT möglich.

Wenn SET TALK auf ON steht, wird angezeigt, wie lange FoxPro für die Abfrage benötigt hat und in der Systemvariable _TALLY steht dann die Anzahl der gefundenen Datensätze.

Setzen Sie beim "Ausprobieren" auf alle Fälle ODOMETER auf einen sehr niedrigen Wert und ESCAPE auf ON, damit Sie bei einem eventuellen Fehler den Rechner nicht neu booten müssen, weil Sie ihn eine Stunde zum Arbeiten geschickt haben.

Grundsätzlich kann man den SELECT in folgende Teile unterteilen

SELECT das Keyword
ALL oder DISTINCT ALL wird defaultmäßig verwendet.
<Alias.>Spaltenbegriff [AS Name] Das "WAS" ich selektieren möchte und unter welchem Namenes mir zur Verfügung gestellt wird.
FROM <Tabelle> [,<Tabelle>] Woher die Daten kommen sollen.
INTO <Ziel> Wohin die Daten geschrieben werden sollen.
WHERE <Bedingung> Die Einschränkung, der Daten
GROUP BY <Gruppenspalte> Wenn Daten zusammengefaßt werden sollen
HAVING <Filterbedingung> Filter auf die gruppierten Daten
UNION <Selectbefehl> Wenn mehrere Selectbefehle in das selbe Ergebnis geschrieben werden sollen.
ORDER BY <Sortierung> Wie die Daten Sortiert sein sollen.

Bewirkt, daß keine doppelten Datensätze erzeugt werden. Wenn zum Beispiel in einer Kundendatenbank mehrere Datensätze mit dem Namen "SCHMITT" kann mit DISTINCT angegeben werden, daß nur ein "SCHMITT" im Ergebnis erscheint.

Bsp.: SELECT DISTINCT Name FROM Kunden

Dem SELECT-Befehl muß angeben werden, welche Felder es aus der Datei bereitstellen soll. Wenn man alle Datenfelder haben möchte so kann dies mittels Stern (*) geschehen.

Bsp.: SELECT * FROM Kunden

Sollen nur bestimmte Felder verwendet werden, so werden diese einfach durch Komma getrennt geschrieben.

Bsp.: SELECT Name, Branche, Strasse, Plz FROM KUNDEN

Wenn man mehrere Dateien gleichzeitig im Zugriff hat, so kann natürlich durch Angabe des ALIAS bestimmt werden, welches Feld verwendet wird. Wenn ein oder mehrere gleiche Felder in zwei Dateien selektiert werden müssen, so muß mindestens eines davon umbenannt werden. Dies kann mit der AS Option erledigt werden.

Bsp.: SELECT Kunden.Name, Kunden.Strasse, Kunden.Vertreter,

Vertreter.Name FROM Kunden,Vertreter

Jeder SELECT-Befehl muß wissen woher er die Daten holen soll. Mit der FROM-Klausel geben Sie den lokalen Alias an. Wenn mehrere Dateien verwendet werden, so müssen diese mit Komma getrennt werden.

Sollte eine der Dateien nicht geöffnet sein, so versucht FoxPro diese zu öffnen. Wenn die Dateien bereits geöffnet sind und eine Relation zwischen den Dateien besteht, so wird diese ignoriert.

Achten Sie darauf, daß auf KEINER der Dateien eine Order liegt, da Sie den Suchvorgang enorm verlangsamen kann. Auf müssen Sie alle Regeln der Rushmoreoptimierung befolgen, damit aus einer Abfrage, die normalerweise 2 Sekunden dauert, nicht 2 Stunden werden.

Hier geben Sie an, wo die Daten hingehören. Wenn Sie nichts angeben, so wird automatisch ein Cursor Mit dem Namen "Abfrage" erzeugt. Ansonsten können Sie hier ein ARRAY, einen CURSOR, eine TABLE (DBF), oder ein FILE, TO PRINTER oder TO SCREEN angeben.

Hier geben Sie die Beschränkungen an, nach denen Sie die Daten eingrenzen möchten. Hier ist auch der Punkt, wo Sie am meisten falsch machen können. RUSHMORE kann natürlich hier am besten oder eben gar nicht eingesetzt werden. Wenn Sie in der WHERE Klausel Fehler machen, so wird RUSHMORE nicht zur Anwendung kommen und Ihre Abfrage wird weitaus länger dauern.

An dieser Stelle sind alle Bedingungen erlaubt, die auch in den anderen Befehlen mit der FOR Klausel erlaubt sind. Hier können nun natürlich auch Verknüpfungen zwischen mehreren Dateien gemacht werden, indem Sie die Schlüssel der Dateien miteinander verknüpfen.

Bsp.: WHERE Kunden.vertreter=Vertreter.Nummer

Es muß natürlich gewährleistet sein, daß die "gejointe" Datenbank den richtigen Schlüssel aufweist, welcher auch optimierbar ist. Ansonsten wird nämlich zu jedem Datensatz des "Vaters" jeder Datensatz des "Kindes" durchsucht.

Wenn Sie Daten zusammenfassen wollen, (Bsp.: Alle Postleitzahlen) so können Sie dies hier angeben. Im Grunde genommen funktioniert diese Klausel, wie die DISTINCT Klausel, wobei sich GROUP BY nur auf die angebenden Felder bezieht.

Bei der Angabe von HAVING wird die GROUP BY Klausel kontrolliert. Das heißt, daß nur Datensätze aus der GROUP BY Gruppierung aufgenommen werden, die der Filterbedingung entsprechen, die bei HAVING angegeben wird.

Wenn Sie zwei oder mehrere Abfragen miteinander verknüpfen wollen, so können Sie dies mit der UNION Klausel erledigen. Mit der UNION Klausel können Sie sogenannte OUTER JOINS definieren.

Normalerweise werden bei der Verknüpfung von zwei Tabellen nur die zusammenpassenden, also in beiden Tabellen vorkommenden, Datensätze in das Endergebnis einbezogen. Manchmal kann es jedoch vorkommen, daß es Datensätze gibt, die nur in einer der Tabellen vorkommt und ebenfalls in der Ergebnisstabelle aufgeführt werden sollen. Mit UNION können Sie nun einen zweiten SELECT Befehl angeben, der die fehlenden Datensätze sucht und im Endergebnis mit aufnimmt.

Mit ORDER BY können Sie die Sortierung des Endergebnisses angeben. Vergessen Sie jedoch nicht, daß bei einem großen Endergebnis, das Produkt sortiert werden muß.

Bei ein paar Datensätzen aus einer Million macht dies nichts aus. Wenn Sie jedoch 100000 Datensätze als Ergebnis bekommen, so wird eine Sortierung ebenfalls etwas länger dauern können.


 

TIPS

Hier noch ein paar Tips und Tricks, wie Sie am besten mit SQL-SELECT zurechtkommen sollen.

Beim SELECT brauchen Sie die Tabelle nicht geöffnet haben, SELECT öffnet diese für Sie. Aber bedenken Sie, daß ein Öffnen wiederum Zeit in Anspruch nimmt.

Vergessen Sie nicht, alle SET ORDER auszuschalten, ansonsten können Sie unangenehme Performanceprobleme bekommen, da Sie FoxPro zwingen in einer bestimmten Reihenfolge auf die Daten loszugehen.

RUSHMORE wird so weit wie möglich eingesetzt, automatisch.

SELECT bewegt weder den Satzzeiger einer bereits geöffneten Datei, noch verändert es die Sortierung.

SELECT bewegt auch nicht die Selectebene, solange nicht eine andere Tabelle oder ein Cursor erzeugt wird.

Verwenden Sie die GROUP BY Klausel, anstelle von DISTINCT, da GROUP BY nur auf die angebenden Felder wirkt und nicht die gesamte Datei beachtet werden muß.

Verwenden Sie am besten ein SELECT INTO CURSOR, da es der beste und schnellste Weg ist, Ihre Daten zu selektieren.

Verwenden Sie die Klausel WHERE anstelle von HAVING, da HAVING wesentlich langsamer ist.

Vermeiden Sie Zeichenkettenoperationen wie $, AT() oder ATC() da sie nicht optimierbar sind.

Schreiben Sie das Datenbankfeld in der WHERE Klausel immer links vom Operanden, da ansonsten die Abfrage NICHT optimiert wird.

Wenn Sie die Abfrage in einen CURSOR leiten, so ist dieser READ ONLY. Mit dem Befehl DBF() können Sie sich jedoch den echten Namen des CURSORS ermitteln lassen. Diese Datei können Sie in einem anderen Arbeitsbereich neu öffnen und dort weiterverarbeiten.

Wenn es FoxPro möglich ist, so erstellt es keinen Cursor, sondern zeigt Ihnen die Original-Datenbank unter dem Namen des Cursors.

Wenn man nun nicht aufpasst, diesen (falschen) Cursor noch einmal öffnet und dann Daten manipuliert, so werden ECHTE Daten eventuell überschrieben.

Um dies zu vermeiden, müssen Sie sichergehen, daß FoxPro IMMER einen temporären Cursor erzeugt. Dies kann man erzwingen, indem man ein berechnetes Feld in den Cursor mitaufnimmt.

Wenn Sie einen temporären CURSOR Indizieren wollen, so müssen Sie die OF Klausel beim INDEX Befehl mit angeben.

Bsp.: INDEX ON <Feldname> TAG <Tagname> OF <Cursor>

Nun noch zu guter letzt: RUSHMORE ausschalten.

Es gibt Situationen, in denen eine Optimierung falsch am Platz ist. Nicht, weil es langsamer gehen soll, sondern weil FoxPro die Arbeit mit dem Daten in die Hand nimmt.

Wenn Sie einen Indexausdruck mit REPLACE ALL bearbeiten wollen, so verändern Sie während des Befehls die Sortierung, was sich wiederum auf die Arbeit von FoxPro auswirken kann.

Auszuschalten ist die Optimierung durch den Befehl SET OPTIMIZE OFF oder durch die Zusatzklausel NOOPTIMIZE beim Befehl.


Rushmore & SQL
(c)1994 Peter Herzog