Lade...
 

Query und Index auf Collections

Suchen in Collections

Collections können mittels Queries nach Objekten mit bestimmten Eigenschaften durchsucht werden. ClassiX und ObjectStore

unterstützen dies mit einer einfachen aber mächtigen Abfragesprache. Die Befehle

zum Durchsuchen einer Collection sind

  • Find
  • FindFirst
  • FindExist

FindAll ist ein weiterer "Such"-Befehl, der allerdings keinen Suchausdruck benötigt, da er alle Objekte einer REP-Collection liefert. Find liefert alle Objekte mit bestimmten Eigenschaften, FindFirst nur das erste

gefundene.

Query mit Find oder FindFirst

Die Abfragesprache ist beschrieben in: Query-Syntax

Querys werden verwendet um Objekte mit bestimmten Eigenschaften zu suchen.

Das bedeutet, für jedes Objekt in der Collection wird geprüft, ob es einer Bedingung entspricht. Der Suchausdruck ist also immer eine Bedingung in der Regel mit meinem Vergleich (z.B. =, >, <, ~, @) oder der Abfrage, ob ein Slot existiert (Operator ?). In der Bedingung wird auf eine Eigenschaft eines Objektes Bezug genommen, die mit einem anderen Wert verglichen wird. Die Eigenschaft des Objektes wird durch einen Zugriffsausdruck beschrieben. Ein Zugriffsausdruck ist der Weg vom Objekt über beliebig viele andere Objekte oder Collections zu einem bestimmten anderen Objekt oder Wert (z.B. einem String).

Auf diesem Weg können Member, Slots oder Funktionsaufrufe liegen.

Das Ziel des Zugriffsausdrucks wird mit etwas anderem verglichen. Dieses

andere kann eine andere Objekteigenschaft sein (wieder durch einen Zugriffsausdruck beschrieben), oder eine Konstante oder eine Variable. Im Suchausdruck wird eine Variable durch einen Platzhalter (%...) gekennzeichnet. Vor der Ausführung muss für jeden Platzhalter eine entsprechendes Objekt auf dem Stack liegen. Konstanten können Zahlen, Zeichenketten (in Anführungsstrichen) oder Werte (Zahl + Einheit, siehe CX_VALUE)

sein.

Die Suchausdrücke in ClassiX weichen von der ObjectStore-Schreibweise ab:

ObjectStore verwendet eine sehr technische Syntax, die z.T. sehr schwer zu verstehen ist (u.a. kennt ObjectStore selbst auch keine Slots). Daher wurde in ClassiX eine vereinfachte Form implementiert (beide Suchausdrücke können über den Query-Manager angesehen werden). Bei der Ausführung einer Query wird daher zunächst der InstantView-Queryausdruck übersetzt. ObjectStore selber übersetzt wiederum den Suchausdruck in eine interne Darstellung. Um diesen Vorgang zu beschleunigen werden alle Queries in ClassiX gecached (nur die Abfragen, nicht die Ergebnisse). Um eine Query im Cache wiederzufinden wird der InstantView-Queryausdruck verwendet. Variablen (Platzhalter) sind daher zusammengesetzten Ausdrücken mit Konstanten vorzuziehen, wenn häufig

unterschiedliche Werte abgefragt werden sollen.

Zur Information: Da ObjectStore keine Slots kennt werden die in ClassiX-Queries mithilfe von

Funktionen abgebildet. Slots haben eine interne Nummer, und in der Übersetzung der Query wird der Slotname durch einen Funktionsaufruf übersetzt. Es gibt die globalen Funktionen "f1()", "f2()", "f4()", "f8()", "f16()" und "f32()" für die verschiedenen Slot-Typen (int, String, Object, ...), die die Slotnummer

übergeben bekommen und den Slot zurückliefern.

Beschleunigen einer Query mithilfe eines Index

Für eine detailierte Beschreibung, wie ein Index gebaut wird, siehe hier.

Eine Suche in einer sortierten Liste ist immer schneller als in einer unsortierten. Eine Collection selbst kann ihre Elemente nur in einer bestimmten Reihenfolge halten. Um trotzdem die Objekte nach verschiedenen Kriterien schnell suchen zu können, werden Indizes eingerichtet. Ein Index ist sozusagen eine virtuelle Sortierung einer Collection.

Ein Index wird in ClassiX über den Index-Manager verwaltet (angelegt,

gelöscht, verändert, ...) und durch einen Index-Descriptor repräsentiert. Eine Query kann einen Index verwenden, um durch die Sortierung schneller zu einem Ergebnis zu kommen. Ein Index beschreibt ausgehend von den Elementen einer Collection einen Zugriffspfad. Damit eine Query durch einen Index beschleunigt werden kann muss der Zugriffspfad im Index dem Zugriffspfad im Query-Ausdruck entsprechen. Dabei gilt dasselbe wie oben beschrieben: Der "einfache" Zugriffsausdruck in ClassiX wird in den technischen ObjectStore-Zurgiffsausdruck

übersetzt.

Für Funktionen in ObjectStore-Indizes gilt eine Besonderheit: Es sind keine

Funktionen mit Parametern erlaubt. Daher können die in Querys verwendeten Funktionen zum Erreichen der Slots nicht verwendet werden. Stattdessen werden spezielle Funktionen verwendet, die über den Funktionsnamen die Slotnummer und den Typ des Slots kodiert haben: z.B. SlotFuncStr34(). Um die Zuordnung zwischen Slot und Index-Funktion herzustellen, muss in der Datei "classix.dic" (bzw.

einer der aus der ".ini"-inkludierten Datei) der Eintrag

Slot(<Slotname>, <Typ>, ...)

...

Index(<Slotname>, <Slotnummer>)

eingetragen werden. Der Slotname entspricht dem vorher definierten Slot.

Der Zugriffsausdruck, der im Index beschrieben wird, muss immer der

Vollständige von den Objekten in der Collection bis zum Zielwert sein. Darin können beliebige Slots vorkommen, die mit dem .ini-Eintrag Index(...) definiert worden sind. Normalerweise sortiert der Index nach dem Wert der Zielobjekte (also z.B. nach dem Wert eines CX_VALUE Objektes oder eines Strings). In einigen Fällen ist der Wert bzw. die Reihenfolge schwer zu bestimmen (z.B. wie soll eine Liste von CX_PERSON-Objekten sortiert werden). In diesen Fällen wird häufig nach der Identität eines Objektes gefragt und in der Query auch mit dem Identitäts-Operator '@' verglichen. Im Zugriffsausdruck für den Index  muss zur Unterscheidung, dass die Addresse (Identität) verwendet werden soll, dem gesamten Zugriffsausdruck ein '@' vorangestellt werden. Nur dann kann der Index in einer Query mit einem '@'-Operator auch verwendet werden.

 

Der '@' am Anfang des Zugriffausdruck im Index sorgt dafür, dass als letzte Slot-Funktion

im ObjectStore-Index "SlotFuncPtr<Nr>()" anstelle "SlotFuncObj<Nr>()" verwendet wird und dadurch ein Pointer auf das Objekt anstelle des Objekts

selber mit seinem Vergleichsoperator zum Vergleich verwendet wird.

Prüfen, ob ein Index verwendet wird

Um die Anwendung zu beschleunigen ist es für viele Queries empfehlenswert

einen Index anzulegen. Dazu ist es hilfreich zu sehen, welche Queries überhaupt

ausgeführt, und welche Indizes dabei verwendet werden.

Um dies zu erreichen kann über den Query-Manager mit der Funktion "StartMonitoringIndexUsage()"

das Monitoring eingeschaltet werden. Dafür wird ein Dateiname übergeben. In diese Datei protokolliert ObjectStore, welche Queries ausgeführt werden, und welche Indizes dabei herangezogen werden. Dadurch kann auch geprüft werden, ob ein neu angelegter Index auch tatsächlich die Query beschleunigt, für die er

gedacht war.