Schnelle Domänenfunktionen

Die Domänenfunktionen von Access sind nicht gerade als Performance-Wunder bekannt. In manchen Konstellationen sind sie zwar ausreichend schnell, in der Regel lohnt sich jedoch der Einsatz von Ersatzfunktionen – mit dem Vorteil, dass man diese auch noch den eigenen Bedürfnissen anpassen kann. Dieser Artikel stellt Alternativen zu Funktionen wie DLookup, DMax und Co. vor.

DLookup

Die DLookup-Funktion ist ein einfach zu bedienendes Werkzeug zum Ermitteln einzelner Werte aus Tabellen oder Abfragen. Sie erwartet schlicht und einfach den Namen des Feldes, der den Wert liefern soll, die Bezeichnung der Tabelle oder Abfrage und eine Bedingung, deren Syntax dem Teil hinter dem WHERE-Schlüsselwort einer Abfrage entspricht. Ein einfacher Aufruf sieht beispielsweise so aus:

DLookup("Nachname", "tblKontakte", µ
"KontaktID = 1")

Dieser Aufruf gibt den Wert des Feldes Nachname des Datensatzes der Tabelle tblKontakte zurück, dessen Feld KontaktID den Wert 1 aufweist.

Wenn Sie diesen Ausdruck beispielsweise hinter einer Debug.Print-Anweisung in das Direktfenster eingeben und mit der Eingabetaste ausführen, erscheint postwendend der gewünschte Wert. Dies ist zum Beispiel ein Einsatzzweck, für den die DLookup-Funktion ausreichend schnell ist beziehungsweise wo die gegenüber anderen Varianten schlechtere Performance nicht auffällt – wenn sie überhaupt schlechter ist, denn gerade bei einfachen Aufrufen ist DLookup oft sogar die schnellste Möglichkeit.

Es hapert eher an Stellen, wo DLookup oft aufgerufen werden soll, also etwa innerhalb einer Schleife oder als Bestandteil einer Abfrage, oder wo große Tabellen im Spiel sind. Dies liegt daran, dass DLookup im Hintergrund gründlich arbeitet: Die Funktion öffnet eine Instanz der aktuellen Datenbank, erstellt ein Snapshot-Recordset, filtert dieses auf Basis der übergebenen Parameter und liefert schließlich den Wert zurück. Überdies stehen die Domänenfunktionen im Verdacht, die erzeugten Objekte anschließend nicht sauber zu entsorgen.

FLookup

All dies erledigen wir mit einer Ersatzfunktion namens FLookup. Es gibt im Web eine Menge solcher Ersatzfunktionen, die mitunter auch andere Namen wie beispielsweise ELookup tragen. Einige ersetzen die Domänenfunktionen schlichtweg, andere erweitern deren Funktion – darauf kommen wir später zurück.

Die FLookup-Funktion aus Listing 1 bildet die Funktionsweise der DLookup-Funktion ab. Sie erwartet die gleichen Parameter und setzt diese zu einem geeigneten SQL-Ausdruck zusammen. Um diesen auszuführen, erzeugt die Funktion ein Database– und ein Recordset-Objekt auf Basis der SQL-Anweisung. Genau wie DLookup liefert auch diese Funktion den Wert Null zurück, wenn kein passender Datensatz gefunden werden kann.

Listing 1: FLookup, Version 1

Function FLookup(ByVal sFieldName As String, _
    ByVal sSource As String, _
    Optional ByVal sCriteria As String = vbNullString) _
    As Variant
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim strSQL As String
    Set db = CurrentDb
    strSQL = "SELECT " & sFieldName & " FROM " & sSource
    If Len(sCriteria) > 0 Then
        strSQL = strSQL & " WHERE " & sCriteria
    End If
    Set rst = db.OpenRecordset(strSQL, dbOpenDynaset)
    If rst.EOF Then
        FLookup = Null
    Else
        FLookup = rst.Fields(0).Value
    End If
    rst.Close
    Set rst = Nothing
    Set db = Nothing
End Function

Wenn Sie sich die Performance dieser Funktion einmal genau ansehen, stellen Sie schnell fest, dass DLookup nicht unbedingt langsamer als FLookup ist. Kein Wunder: FLookup erledigt ja auch genau die gleichen Schritte wie DLookup und es räumt sogar noch die verwendeten Objektvariablen auf.

Wie also können Sie auch noch die Performance dieser Routine verbessern Nun: Wenn Sie nur einen einzigen Aufruf von FLookup tätigen, sind die Möglichkeiten stark eingeschränkt.

Einzelne Aufrufe machen aber den Braten nicht fett, daher konzentriert sich die folgende Optimierung auf den mehrfachen Aufruf der Funktion FLookup.

Welche der enthaltenen Schritte könnte man auslagern Die Parameter für den SQL-Ausdruck wechseln beim mehrfachen Aufruf – zumindest aber sollte dies für die WHERE-Bedingung der Fall sein. Es finden aber in der Regel alle Aufrufe im Kontext mit der aktuellen Datenbank statt – und die wird innerhalb der Funktion durch die Objektvariable db repräsentiert. Diese brauchen Sie also nur einmal vor dem ersten Aufruf zu füllen und könnten dann im weiteren Verlauf darauf zurückgreifen.

Es liegt nahe, das Database-Objekt in einer öffentlichen Variablen zu speichern und diese etwa beim Start der Datenbankanwendung zu füllen. Wenn diese Variable aber durch einen Fehler oder aus anderen Gründen geleert wird, löst die Verwendung der Variablen in FLookup einen Fehler aus.

Also muss eine andere Methode her, wobei der Verweis auf das Database-Objekt zwar auch in einer Variablen gespeichert, aber nicht direkt von dort ausgelesen wird. Die Deklaration der Variablen fügen Sie einem Standardmodul hinzu:

Private m_Database As DAO.Database

Der Zugriff erfolgt über eine benutzerdefinierte Funktion namens dbs. Diese prüft, ob m_Database gefüllt ist. Falls nicht, holt sie dies nach und in beiden Fällen wird der Verweis auf das Database-Objekt als Funktionswert zurückgeliefert:

Public Function dbs() As DAO.Database
    If m_Database Is Nothing Then
        Set m_Database = CurrentDb
    End If
    Set dbs = m_Database
End Function

Danach wird FLookup erstens ein wenig leichtgewichtiger und zweitens viel schneller (s. Listing 2). Die Variable db fällt weg, stattdessen verwenden Sie die oben beschriebene Funktion dbs. Diese liefert jeweils den Verweis auf die aktuelle Datenbank zurück. Und dies spart schon mächtig Zeit, wenn Sie FLookup oft hintereinander aufrufen.

FLookup erweitern

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar