Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 1/2006.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Zusammenfassung

Erstellen Sie ein Add-In zum Messen und Vergleichen der Performance von Funktionen.

Techniken

Formuare, Add-Ins, VBA, Klassen

Voraussetzungen

Access 2000 und höher

Beispieldateien

Beispieldatenbank.mdb
Performance.mda

Performance-Tester als Access-Add-In

André Minhorst, Duisburg

Die Performance einer Datenbankanwendung ist mithin ein entscheidender Faktor für die Akzeptanz beim Benutzer. Muss dieser bei bestimmten Aktionen länger als ein paar Sekunden auf die Anwendung warten, stellt sich schnell Unzufriedenheit ein. Nun dreht es sich in diesem Beitrag nicht um die Optimierung der Performance, sondern um die Messung der Resultate von Performance-Optimierungen. Und dabei erfahren Sie, wie Sie sich ein nützliches Add-In zur Messung der Performance bauen.

Das A und O: Die Zeitmessung

Die Performance einer Anwendung hängt in der Regel von vielen kleinen Faktoren und Bereichen ab, die man getrennt optimiert und entsprechend messen möchte. Für die Messung wird normalerweise die Zeit ermittelt, die die Anwendung für die Erledigung einer bestimmten Aufgabe benötigt.

Das ist auch bei dem Add-In der Fall, das Sie in diesem Beitrag kennen lernen: Es erwartet die Angabe zweier Funktionen mit der gleichen Aufgabe und ermittelt die von den Funktionen benötigte Zeit.

Zeit messen per API

Unter VBA gibt es verschiedene, unterschiedlich genaue Möglichkeiten zur Zeitmessung. Im hier verwendeten Tool kommen zwei API-Funktion namens QueryPerformanceCounter und QueryPerformanceFrequency zum Zuge, die man folgendermaßen deklariert (jeweils in einer Zeile):

Declare Function QueryPerformanceCounter Lib "Kernel32" (X As Currency) As Long

Declare Function QueryPerformanceFrequency Lib "Kernel32" (Y As _Currency) As Long

Die erste Funktion weist der als Parameter angegebenen Variablen den Zählerstand eines Prozessor-Counters zu. Wird dieser durch die mit QueryPerformanceFrequency ermittelte Counter-Frequenz geteilt, so erhält man in einer vom jeweiligen Rechner abhängigen Auflösung die Zeit in Sekunden. Um die Zeit zu messen, die eine Funktion benötigt, speichert man einmal den so ermittelten Wert in einer Currency-Variablen, ruft die Funktion auf und berechnet dann aus der Differenz des aktuellen Wertes und dem gespeicherten Wert die benötigten Sekunden.

Objekt der Messung

Üblicherweise möchte man mit einer Performance-Messung zwei oder mehr verschiedene Varianten einer Funktion vergleichen. Bevor man hier loslegt, sollte man sich zunächst im Klaren darüber sein, wo sich Optimierungen und damit auch Messungen überhaupt lohnen. Es gibt sicher viele Beispiele für kleine Code-Optimierungen, die eine Änderung der benötigten Zeit im Bereich von Sekundenbruchteilen bewirken. Hier kann man den Hebel ansetzen, wenn diese Funktionen sehr, sehr oft aufgerufen werden oder wenn man die Anwendung wirklich bis ins Letzte auf Performance tunen möchte.

Abb. 1: Das Performance-Test-Tool im Einsatz

Wer suchet, der findet

Zunächst sollten Sie sich jedoch auf die Suche nach den wirklichen Performance-Schluckern machen und diesen auf den Leib rücken. Bei dieser Suche hilft Ihnen das nachfolgend beschriebene Tool nicht. Sie sollen aber dennoch nicht ohne einen Tipp zu diesem Thema weiterlesen: Verwenden Sie doch einfach die QueryPerformanceCounter-Funktion an verschiedenen Stellen der Anwendung, die Ihnen verdächtig vorkommen.

Schauen Sie zunächst, welche Funktionen viel Zeit kosten, und verfeinern Sie die Suche anschließend, bis Sie optimalerweise die Zeile gefunden haben, die für unerwünscht hohen Zeitverbrauch verantwortlich sind.

Optimieren mit System

Haben Sie eine einzelne oder mehrere zusammenhängende Zeilen gefunden, die für schlechte Performance (mit)verantwortlich sind, haben Sie einen Ansatzpunkt für eine Optimierung. Manchmal lässt sich der Optimierungshebel genau an der gefundenen Stelle ansetzen, manchmal sind aber auch Operationen erforderlich, die sich auf weit größere Teile des Quellcodes beziehen.

Optimierungen quantitativ bewerten

Hier kommt nun endlich das Performance-Test-Tool zum Einsatz. Es sieht wie in Abb. 1 aus und lässt sich wie folgt bedienen: Zunächst wählen Sie das Standardmodul oder das Formular aus, in dem sich die zu testende Routine befindet. Nach dem Auswählen des Objekts werden die weiteren Kombinationsfelder mit den im ausgewählten Modul enthaltenen Routinen gefüllt. Ganz wichtig: Die Routinen müssen als öffentliche Routinen deklariert sein! Sonst hat das Tool keine Möglichkeit, die Routinen aufzurufen.

Legen Sie nun zunächst fest, wie oft die Funktionen jeweils aufgerufen werden sollen. Das ist sinnvoll, wenn eine Routine sehr schnell abläuft - also beispielsweise schneller als eine Millisekunde -, aber in der eigentlichen Anwendung etwa in einer Schleife viele Male aufgerufen wird. Beginnen Sie einfach mit einer kleinen Zahl wie 1 oder 10 und arbeiten Sie sich dann in größere Dimensionen vor, wenn das Messergebnis nicht befriedigend ist. Anschließend legen Sie die zu vergleichenden Routinen fest. Hierbei ist Folgendes zu beachten:

  • Die Messung von Routinen in Formular-Modulen ist mit Sub- und Function-Prozeduren möglich.
  • In Klassenmodulen befindliche Methoden können Sie nicht direkt messen! Eine alternative Möglichkeit finden Sie allerdings weiter unten.
  • Wenn Sie die benötigten Daten eingegeben haben, klicken Sie einfach auf die Schaltfläche Test starten. Das Tool arbeitet die angegebenen Funktionen so oft wie angegeben ab und gibt im Formular die gemessene Zeit sowie die absoluten und relativen Abweichungen von der jeweils anderen Routine aus. Außerdem kennzeichnet es die schnellere und die langsamere Variante mit entsprechenden Symbolen (s. Abb. 1).

    Wie testet man Methoden aus Klassenmodulen?

    Auf die Methoden von Klassenmodulen kann das Tool nicht direkt zugreifen. Der Grund ist, dass die Klasse dazu deklariert und instanziert werden müsste, was zwar prinzipiell möglich ist, aber nur, wenn der Name der Klasse zuvor bekannt ist. Das Tool soll aber als Add-In in beliebigen Datenbanken eingesetzt werden; somit müsste es zur Laufzeit zuvor nicht bekannte Klassen instanzieren. Das funktioniert mit VBA leider nicht, daher müssen Sie zur Messung der Performance von in Klassen verborgenen Methoden einen kleinen Umweg gehen.

    Dazu legen Sie in einem Standardmodul eine öffentliche Function-Routine an, die die gewünschte Klasse deklariert und instanziert und die entsprechende Methode aufruft. Das kann beispielsweise wie in Quellcode 1 aussehen.

    clsZeitmessungBeispiele ist eine Klasse mit den zwei Methoden EarlyBinding und LateBinding, die in Quellcode 2 abgedruckt sind.

    Die erste Funktion TestKlasse1 deklariert und instanziert ein Objekt der Klasse clsZeitmessungBeispiele und ruft die Methode EarlyBinding auf, die Funktion TestKlasse2 erledigt selbiges für die Methode LateBinding.

    Um zu vergleichen, welche der beiden Methoden schneller ist, wählen Sie einfach das Standardmodul mdlZeitmessungBeispiele und die beiden Funktionen TestKlasse1 und Testklasse2 im Performance-Mess-Tool aus und starten den Test. Die absolute Differenz zwischen den gemessenen Zeiten ist sicher aussagekräftig, bezieht sich jedoch auf den kompletten Aufruf inklusive Wrapper-Funktion und der eigentlich zu testenden Methode.

    Um den relativen Unterschied zwischen den beiden Methoden zu ermitteln, müssen Sie freilich noch einen draufsetzen: Das Tool bietet die Möglichkeit, eine Referenzfunktion anzugeben. Diese Funktion sollte alle Elemente bis auf die eigentlich zu testenden Anweisungen enthalten.

    Quellcode 1: Aufruf von in Klassen befindlichen
    Methoden

    Public Function TestKlasse1()

        Dim obj As clsZeitmessungBeispiele

        Set obj = New clsZeitmessungBeispiele

        obj.EarlyBinding

        Set obj = Nothing

    End Function

    Public Function TestKlasse2()

        Dim obj As clsZeitmessungBeispiele

        Set obj = New clsZeitmessungBeispiele

        obj.LateBinding

        Set obj = Nothing

    End Function

    Public Function TestKlasseReferenz()

        Dim obj As clsZeitmessungBeispiele

        Set obj = New clsZeitmessungBeispiele

        'obj.LateBinding

        Set obj = Nothing

    End Function

    Quellcode 2: Methoden der Klasse
    clsZeitmessungBeispiele

    Public Sub EarlyBinding()

        Dim cbr As CommandBar

        Dim strName As String

        For Each cbr In Application.CommandBars

            strName = cbr.Name

        Next cbr

        Set cbr = Nothing

    End Sub

    Public Sub LateBinding()

        Dim strName As String

        Dim cbr As Object

        For Each cbr In Application.CommandBars

            strName = cbr.Name

        Next cbr

        Set cbr = Nothing

    End Sub

    Abb. 2: Genaueres Messen der relativen Differenz durch Verwenden einer Referenzfunktion

    Abb. 3: Einträge des Kombinationsfeldes cboModule

    In Quellcode 1 ist dies die dritte Funktion namens TestKlasseReferenz, die zwar ein Objekt der Klasse clsZeitmessungBeispiele erzeugt, aber keine Methode aufruft.

    Die Differenz der gemessenen Zeiten für die Funktionen mit den eigentlichen Aufrufen und des Referenzaufrufs liefert so einen wesentlich genaueren Wert für den relativen Unterschied beim Aufrufen der zu testenden Methoden.

    Abb. 2 zeigt, wie der Aufruf und das Messergebnis aussehen könnten. Die vorderen Werte für die erste und die zweite Funktion liefern die um die von der Referenzfunktion benötigten Zeit reduzierten Ergebnisse.

    Die Zahlen in Klammern sind die Werte ohne Betrachtung der Referenzfunktion.

    Technische Hintergründe

    Das Tool beinhaltet ein Formular, ein Standard- sowie ein Klassenmodul.

    Das Formular frmPerformance

    Das Formular aus Abb. 2 ist das einzige sichtbare Objekt dieser Anwendung. Es dient zum Eingeben aller relevanten Daten und zeigt die Ergebnisse der Performance-Messung an.

    Obwohl das Formular relativ simpel aussieht, steckt in seinen Funktionen einiges an Know-how. Das Ganze beginnt mit dem Füllen der Kombinationsfelder.

    Auswahl der Module

    Das erste Kombinationsfeld cboModule wird beim Öffnen des Formulars mit den in der Datenbank enthaltenen Modulen gefüllt.

    Dafür sorgt die Ereignisprozedur Beim Öffnen des Formulars (s. Quellcode 3).

    Sie weist der Eigenschaft RowSource des Kombinationsfeldes cboModule das Ergebnis der Funktion ModuleEinlesen zu. Diese Funktion liefert eine Zeichenkette mit einer Auflistung der Module und deren Eigenschaften in der Form <Modulname>; <Modultyp-Bezeichnung>; <Modultyp-ID>; <Projektname>; zurück.

    Ein Beispieleintrag lautet etwa wie folgt:

    mdlZeitmessungBeispiele;
    Standardmodul;
    1;Beispielprojekt;

    Damit das Kombinationsfeld die Einträge wie in Abb. 3 anzeigt, stellen Sie die Eigenschaften Spaltenanzahl und Spaltenbreiten auf die Werte 4 beziehungsweise 5cm;5cm;0cm;
    0cm ein.

    Außerdem wählen Sie für die Eigenschaft Herkunftstyp den Eintrag Wertliste aus.

    Quellcode 4: Einlesen der Module

    Private Function ModuleEinlesen() As String

        Dim i As Integer

        Dim intVBComponentsCount As Integer

        Dim objVBComponent As VBComponent

        Dim strModulename As String

        Dim strModuletype As String

        Dim strModules As String

        Dim objVBProjekt As VBProject

        For Each objVBProjekt In VBE.VBProjects

            If Not objVBProjekt.Name = "Performance-Tester" Then

                intVBComponentsCount = objVBProjekt.VBComponents.Count

                For i = 1 To intVBComponentsCount

                    Set objVBComponent = objVBProjekt.VBComponents.Item(i)

                    strModulename = objVBComponent.Name

                    Select Case objVBComponent.Type

                        Case vbext_ct_StdModule

                            strModuletype = "Standardmodul"

                        Case vbext_ct_Document

                            strModuletype = "Formular- oder Berichtsmodul"

                    End Select

                    If objVBComponent.Type = 1 Or objVBComponent.Type = 100 Then

                        strModules = strModules & strModulename & ";" & strModuletype & ";" _
                            & objVBComponent.Type & ";" & objVBProjekt.Name & ";"

                    End If

                Next i

            End If

        Next objVBProjekt

        ModuleEinlesen = strModules

        Set objVBComponent = Nothing

    End Function

    Für das eigentliche Einlesen ist die Routine aus Quellcode 4 verantwortlich. Sie greift über das VBE-Objekt auf die im VBA-Projekt enthaltenen Elemente zu (hierfür ist im Übrigen ein Verweis auf die Bibliothek Microsoft Visual Basic for Applications Extensibility 5.3 erforderlich).

    Da das Tool später als Add-In ausgelegt werden soll, ist es wichtig, festzulegen, dass dabei nicht das eigene VBA-Projekt, sondern das VBA-Projekt der Datenbank, die das Tool aufruft, referenziert wird. Dies wird dadurch sichergestellt, dass die Routine alle aktuell enthaltenen VBA-Projekte durchläuft und nur diejenigen berücksichtigt, die nicht den Namen Performance-Tester haben.

    Alles Weitere ist Fleißarbeit; genauere Informationen über die hier verwendeten VBA-Anweisungen finden Sie im Beitrag Per VBA auf VBA-Code zugreifen (s. Shortlink 278).

    Quellcode 3: Aufruf der Funktion zum Füllen des Kombinationsfeldes mit den Modulen

    Private Sub Form_Open(Cancel As Integer)

        Me!cboModule.RowSource = ModuleEinlesen

    End Sub

    Auswahl der Funktionen

    Bevor der Benutzer die zu vergleichenden Funktionen auswählen kann, müssen Sie für das Füllen der entsprechenden Kombinationsfelder sorgen. Hier tritt die Ereignisprozedur auf den Plan, die nach dem Aktualisieren des Kombinationsfeldes cboModule ausgelöst wird. Diese ermittelt zunächst den Namen des Moduls und des Projekts, deren Routinen aufgelistet werden sollen. Die Funktion RoutinenEinlesen ermittelt - ähnlich wie die Routine ModuleEinlesen - die in dem angegebenen Modul enthaltenen Routinen.

    Quellcode 5: Nach dem Aktualisieren des Kombinationsfeldes cboModule werden die übrigen Kombinationsfelder mit den Routinennamen des ausgewählten Moduls gefüllt.

    Private Sub cboModule_AfterUpdate()

        Dim strModulname As String

        Dim strProjektname As String

        Dim strRoutinen As String

        strModulname = Me!cboModule

        strProjektname = Me!cboModule.Column(3)

        strRoutinen = RoutinenEinlesen(strProjektname, strModulname)

        Me!cboRoutine1.RowSource = strRoutinen

        Me!cboRoutine1 = ""

        Me!cboRoutine2.RowSource = strRoutinen

        Me!cboRoutine2 = ""

        Me!cboRoutineReferenz.RowSource = strRoutinen

        Me!cboRoutineReferenz = ""

    End Sub

    Quellcode 6: Performance-Messung und Auswertung (1. Teil)

    Private Sub cmdTestStarten_Click()

        Dim objZeitmessung As clsZeitmessung

        Dim strModulename As String

        Dim lngModuleType As Long

        Dim obj As Object

        DoCmd.Hourglass True

        'Validierungsfunktionen aus Platzgründen nicht abgedruckt

        Set objZeitmessung = New clsZeitmessung

        strModulename = Me!cboModule.Column(0)

        lngModuleType = Me!cboModule.Column(2)

        With objZeitmessung

            .AnzahlDurchgaenge = Me.txtAnzahlDurchgaenge

            Select Case lngModuleType

                Case 1 'Standardmodul

                    .ErsteProzedur = Me!cboRoutine1 & "()"

                    .ZweiteProzedur = Me!cboRoutine2 & "()"

                    If Me.chkReferenzfunktion = True Then

                        .Referenzprozedur = _
                            Me!cboRoutineReferenz & "()"

                        .MitReferenzzeit = True

                    End If

                    .Performancetest_Standard

                Case 100 'Formular oder Bericht

                    .ErsteProzedur = Me!cboRoutine1

                    .ZweiteProzedur = Me!cboRoutine2

                    If Me.chkReferenzfunktion = True Then

                        .Referenzprozedur = Me!cboRoutineReferenz

                        .MitReferenzzeit = True

                    End If

                    If Left(strModulename, 4) = "Form" Then

                        DoCmd.OpenForm Mid(strModulename, 6)

                        Set .Objekt = Forms(Mid(strModulename, 6))

                        .Performancetest_Objekt

                        DoCmd.Close acForm, Mid(strModulename, 6)

                    End If

                Case Else

                    MsgBox "Modultyp nicht identifizierbar.", _
                        vbExclamation Or vbOKOnly

                    Exit Sub

            End Select

    Aus Platzgründen kann der Inhalt dieser Funktion hier nicht abgebildet werden. Sie finden den Quellcode jedoch in der Beispieldatenbank. Die Zeichenkette mit der Liste der Routinen wird nach dem Einlesen in der Variablen strRoutinen gespeichert und anschließend der Eigenschaft RowSource der drei übrigen Kombinationsfelder zugewiesen. Deren Eigenschaften Spaltenanzahl, Spaltenbreiten und Herkunftsart stellen Sie auf 2, 5cm;5cm und Wertliste ein.

    Mit oder ohne
    Referenzfunktion?

    Mit dem Kontrollkästchen chkMitReferenzfunktion legt der Benutzer fest, ob er eine Referenzfunktion verwenden möchte. Das Aktivieren oder Deaktivieren dieser Option bewirkt das Auslösen des Ereignisses Nach Aktualisierung. Diese wiederum sorgt dafür, dass die für die Eingabe der Referenzfunktion notwendigen Steuerelemente je nach dem Wert des Optionsfeldes entweder aktiviert oder deaktiviert werden.

    Starten der
    Performance-Messung

    Fehlt nur noch die eigentliche Funktion des Formulars: das Aufrufen und Ausführen der Performance-Messung. Diese Funktion teilen sich die Routine, die durch das Anklicken der Schaltfläche cmdTestStarten ausgelöst wird, sowie die Klasse clsZeitmessung.

    Betrachten Sie zunächst die durch den Klick auf die Schaltfläche cmdTestStarten ausgelöste Prozedur (s. Quellcode 6). Diese validiert zunächst die Eingaben im Formular frmPerformance (aus Platzgründen nicht abgedruckt).

    Quellcode 6: Performance-Messung und Auswertung (Fortsetzung)

            If Me.chkReferenzfunktion = False Then

                Me!txtZeit1 = .ErsteZeit

                Me!txtZeit2 = .ZweiteZeit

                Me!txtAbsoluteDifferenz1 = .ZweiteZeit - .ErsteZeit

                Me!txtRelativeDifferenz1 = Format((.ZweiteZeit - .ErsteZeit) / .ZweiteZeit, "0.00%")

                Me!txtAbsoluteDifferenz2 = .ErsteZeit - .ZweiteZeit

                Me!txtRelativeDifferenz2 = Format((.ErsteZeit - .ZweiteZeit) / .ErsteZeit, "0.00%")

            Else

                Me!txtZeit1 = .ErsteZeit - .Referenzzeit & " (" & .ErsteZeit & ")"

                Me!txtZeit2 = .ZweiteZeit - .Referenzzeit & " (" & .ZweiteZeit & ")"

                Me.txtZeitReferenz = .Referenzzeit

                Me!txtAbsoluteDifferenz1 = .ZweiteZeit - .ErsteZeit

                Me!txtRelativeDifferenz1 = Format((.ZweiteZeit - .ErsteZeit - 2 * .Referenzzeit) _
                    / (.ZweiteZeit - .Referenzzeit), "0.00%") _
                    & " (" & Format((.ZweiteZeit - .ErsteZeit) / .ZweiteZeit, "0.00%") & ")"

                Me!txtAbsoluteDifferenz2 = .ErsteZeit - .ZweiteZeit

                Me!txtRelativeDifferenz2 = Format((.ErsteZeit - .ZweiteZeit - 2 * .Referenzzeit) _
                    / (.ErsteZeit - .Referenzzeit), "0.00%") _
                        & " (" & Format((.ErsteZeit - .ZweiteZeit) / .ErsteZeit, "0.00%") & ")"

            End If

            Me!picGreen1.Visible = .ErsteZeit < .ZweiteZeit

            Me!picGreen2.Visible = .ErsteZeit > .ZweiteZeit

            Me!picRed1.Visible = .ErsteZeit > .ZweiteZeit

            Me!picRed2.Visible = .ErsteZeit < .ZweiteZeit

            Me!picRedGreen1.Visible = .ErsteZeit = .ZweiteZeit

            Me!picRedGreen2.Visible = .ErsteZeit = .ZweiteZeit

        End With

        DoCmd.Hourglass False

    End Sub

    Anschließend instanziert die Prozedur ein Objekt der Klasse clsZeitmessung. Das Objekt stellt einige Eigenschaften für das Zuweisen von Informationen wie der Anzahl der Durchgänge, der Namen der zu testenden Routinen und des Moduls, zu dem diese Routinen gehören, zur Verfügung.

    In einem Select Case-Konstrukt prüft die Prozedur, ob die Routinen aus einem Standardmodul oder einem Formular-Klassenmodul stammen und ruft die entsprechende Methode zum Messen der Performance auf. Dabei berücksichtigt die Prozedur auch eine gegebenenfalls angegebene Referenzfunktion.

    Die Ergebnisse der Messung können anschließend aus den drei Eigenschaften ErsteZeit, ZweiteZeit und Referenzzeit der Klasse clsZeitmessung ausgelesen werden.

    Die Prozedur gibt die für die einzelnen Funktionen ermittelten Zeiten aus und berechnet weitere Ergebnisse wie die absolute und die relative Differenz zwischen den Ergebnissen.

    Falls eine Referenzfunktion angegeben ist, wird diese in die Berechnung mit einbezogen.

    Das Klassenmodul clsZeitmessung

    Das Klassenmodul kapselt die Funktionen zur Zeitmessung. Es enthält die Deklaration der hierbei verwendeten API-Funktion QueryPerformanceCounter, einige Member-Variablen, die Property-Prozeduren zum Setzen und Lesen der Eigenschaften der Klasse sowie die beiden Methoden zum Ermitteln der für das Ausführen von zwei verschiedenen Funktionen zuzüglich einer optionalen Referenzfunktion benötigten Zeiten (s. Quellcode 7).

    Quellcode 7: Die Klasse clsZeitmessung

    Private Declare Function QueryPerformanceCounter Lib _
        "kernel32.dll" (ByRef lpPerformanceCount As Currency) _
        As Long

    Private Declare Function QueryPerformanceFrequency Lib _
        "kernel32.dll" (ByRef lpFrequency As Currency) _
    As Long

    'Deklaration - aus Platzgründen nicht abgedruckt

    'Property-Prozeduren - aus Platzgründen nicht abgedruckt

    Private Sub Class_Initialize()

        'Ermitteln der rechnerspezifischen Counter-Frequenz

        QueryPerformanceFrequency mFreq

    End Sub

    Private Sub Starten()

        QueryPerformanceCounter curStartzeit

    End Sub

    Private Sub Stoppen()

        Dim curStop As Currency

        QueryPerformanceCounter curStop

        'Umrechnung Counter in Millisekunden über Counterfrequenz

        mZeit = (curStop - curStartzeit) / mFreq * 1000

    End Sub

    Public Sub Performancetest_Standard()

        Dim l As Long

        Starten

        For l = 1 To mAnzahlDurchgaenge

            Application.Run mErsteProzedur

        Next l

        Stoppen

        mErsteZeit = mZeit

        Starten

        For l = 1 To mAnzahlDurchgaenge

            Application.Run mZweiteProzedur

        Next l

        Stoppen

        mZweiteZeit = mZeit

        If mErsteZeit = 0 Or mZweiteZeit = 0 Then

            Debug.Print "###Zeit nicht messbar, " _
                & "AnzahlDurchgaenge erhöhen."

        Else

            mAbsoluteDifferenz = (mZweiteZeit - mErsteZeit)

            mRelativeDifferenz = AbsoluteDifferenz / _
                mZweiteZeit * 100

        End If

    End Sub

    Public Sub Performancetest_Objekt()

        Dim l As Long

        Starten

        For l = 1 To mAnzahlDurchgaenge

            CallByName mObjekt, mErsteProzedur, VbMethod

        Next l

        Stoppen

        mErsteZeit = mZeit

        Starten

        For l = 1 To mAnzahlDurchgaenge

            CallByName mObjekt, mZweiteProzedur, VbMethod

        Next l

        Stoppen

        mZweiteZeit = mZeit

        If mErsteZeit = 0 Or mZweiteZeit = 0 Then

            Debug.Print "###Zeit nicht messbar, " _
                & "AnzahlDurchgaenge erhöhen."

        Else

            mAbsoluteDifferenz = (mZweiteZeit - mErsteZeit)

            mRelativeDifferenz = AbsoluteDifferenz / _
                mZweiteZeit * 100

        End If

    End Sub

    Die Deklaration der Variablen sowie die Property-Prozeduren wurden nicht abgedruckt; Sie finden diese allerdings im Klassenmodul clsZeitmessung der Beispieldatenbank. Interessanter sind die Methoden Performancetest_Standard und Performancetest_Object sowie die beiden Routinen zum Ermitteln der Start- und Endzeit.

    Aufruf der zu testenden
    Funktionen

    Die beiden Methoden weisen als einzigen Unterschied die Art des Aufrufs der Funktion auf. Wenn es sich um eine öffentliche Funktion in einem Standardmodul handelt, kann man diese einfach ausführen. Eine Routine in einem Formular muss hingegen unter Angabe eines Objektverweises auf das geöffnete Formular mit der Anweisung CallByName aufgerufen werden. Die Zeitmessung erfolgt in drei Schritten:

  • Starten der Messung (Speichern des Startzeitpunktes mit der Prozedur Starten)
  • Aufrufen der Funktion in der gewünschten Anzahl
  • Stoppen der Messung (Speichern des Endzeitpunktes mit der Prozedur Stoppen).
  • Von der Datenbank zum Add-In

    Damit das Tool von anderen Datenbanken aus als Add-In aufgerufen werden kann, sind folgende Schritte notwendig (s. Beitrag Assistenten und Add-Ins selbst gebaut, Shortlink 101):

    Abb. 4: Die Tabelle USysRegInfo mit den Registry-Informationen für das neue Add-In

    Quellcode 8: Diese Funktion wird beim Aufrufen des Add-Ins gestartet.

    Public Function StartPerformanceTest()

        DoCmd.OpenForm "frmPerformance"

    End Function

    Zusammenfassung und Ausblick

    Wenn Sie den Eindruck haben, dass Ihre Anwendung keine optimale Performance aufweist, sollten Sie die Gründe dafür finden und die Probleme beheben. Ob sich die Änderungen und die damit verbundene Arbeit lohnen, sollten Sie nur in Ausnahmefällen "nach Gefühl" entscheiden - knallharte Zahlen sind hier der bessere Berater. Und mit dem hier vorgestellten Add-In haben Sie sogar ein Tool zur Hand, das Ihnen schnell Ergebnisse liefert.

    Seien Sie allerdings vorsichtig bei der Interpretation der Messergebnisse: Sorgen Sie für gleiche Voraussetzungen für die zu vergleichenden Optionen und testen Sie vor allem unter realen Bedingungen - es hilft Ihnen nicht weiter, wenn Sie verschiedene Varianten des Aufrufs einer Abfrage mit wenigen Datensätzen testen, aber in der Praxis Millionen von Datensätzen zu durchforsten sind. Das Schaffen idealer Voraussetzungen für Performance-Tests würde Stoff für einen eigenen Beitrag liefern und an dieser Stelle den Rahmen sprengen, daher wird Access im Unternehmen dieses Thema gegebenenfalls in einem der nachfolgenden Magazine aufgreifen.

    Kompletten Artikel lesen?

    Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

    E-Mail:

    Download

    Download

    Die .zip-Datei enthält folgende Dateien:

    PerformanceTester.zip

    Beispieldateien downloaden

    © 2003-2015 André Minhorst Alle Rechte vorbehalten.