Vor einiger Zeit haben wir uns bereits Gedanken gemacht, warum eine Notes-Anwedung langsam sein kann, welche Lösungsansätze es generell gibt und wie man als Entwickler auf Masken- und Ansichtsebene korrigierend eingreifen kann. Nun soll ein genauerer Blick auf weitere Bestandteile von Notes-Datenbanken, insbesondere auf den Programmcode, folgen. Masken und Ansichten können noch so performant sein, wenn der Benutzer bei allen anwendungsspezischen Aktionen, die er ausführt, trotzdem warten muss.
Agenten
Aufwändige Prozesse, die nicht direkt während einer Nutzeraktion ausgeführt werden müssen, lassen sich an zeitgesteuerte Agenten auslagern. Dazu muss möglicherweise nur ein entsprechendes Flag gesetzt werden und alles weitere passiert dann im Hintergrund, ohne dass der Nutzer unnötig warten muss.
Arbeitet der Nutzer auf einer Server-Datenbank und ist seine Anbindung nicht optimal, können aufwändige Berechnungen sehr lange dauern. Ist (im Gegensatz zum vorigen Absatz) eine sofortige Berechnung nötig, kann man diese in einen Agenten auslagern und diesen per RunOnServer
ausführen. Erst, wenn der Agent fertig ist, überträgt er die Ergebnisse an den Client, sodass nur wirklich relevante Datenströme fließen.
Innerhalb von zeitgesteuerten Agenten kommt es häufig nicht auf die allerbeste Optimierung an, da diese im Hintergrund meistens genügend Zeit haben, ihren Dienst zu verrichten. Bei aufwändigen Operationen wie dem Vergleich großer Datenmengen kann man dem Agenten die Arbeit jedoch per Hashes (= nahezu eindeutige Schlüsselwerte) deutlich vereinfachen. Dazu bildet man beispielsweise über ganze Textabsätze oder die Kombination vieler Feldwerte einen Hashwert (z. B. beim Speichern eines Dokumentes per @Password
). Dann muss der Agent nur noch einen einzigen, kurzen String vergleichen, um zu entscheiden, ob weitere Operationen nötig sind.
Bei der Bearbeitung großer Dokumentmengen ist zudem darauf zu achten, dass nur notwendige Operationen durchgeführt werden. Besonders kostspielige Operationen sind:
- Speichern von Dokumenten: Statt in jedem Agentendurchlauf jedes Dokument zu speichern, sollte man dies nur tun, wenn sich tatsächlich relevante Feldwerte geändert haben
ComputeWithForm
: Je mehr Felder sich ändern, desto mehr hat der Domino-Server zu tun. Wenn also nur einige wenige Felder wirklich ein Update benötigen, sollten diese punktuell durch den Programmcode vorgenommen werden.- Löschen von Dokumenten: Unnötige Deletions Stubs sind, wie in Teil 1 beschrieben, zu vermeiden. Insbesondere sollte man deshalb bei Agenten darauf achten, bestehende Dokumente zu aktualisieren, statt sie "der Einfachheit halber" zu löschen und neu anzulegen.
- Verschachtelte Schleifen: Ihre Verarbeitungzeit wächst mit der Menge der zu verarbeitenden Informationen. Oft gibt es bessere Algorithmen oder kreative Wege, solche Konstrukte zu vermeiden.
LotusScript
Einige der obigen Anmerkungen zu Agenten gelten natürlich auch allgemein für LotusScript.
Bei der Suche nach Dokumenten ist die FTSearch der einfachen Search und der Suche per NotesNoteCollection vorzuziehen. Natürlich sollte die Datenbank in dem Fall volltextindiziert sein.
Der Zugriff auf bestimmte/bekannte Dokumente wird am schnellsten per GetDocumentByUNID
ausgeführt. Gerade wenn man nacheinander auf viele Dokumente zugreifen möchte, kann es sich lohnen, zunächst die UNIDs aus einer Ansicht/DocumentCollection
in eine Liste einzulesen und dann statt einzelner Lookups einfach die UNID aus der Liste zu holen. Wenn man hingegen nur wenige Lookups durchführen möchte, tun es auch die relativ schnellen GetAllDocumentsByKey
- und GetDocumentByKey
-Methoden.
Benötigt man nur Zugriff auf einzelne Werte aus der Ansicht statt auf das ganze Dokument, ist es noch besser, GetAllEntriesByKey
bzw. GetEntryByKey
zu verwenden und dann bei Bedarf die ColumnValues
auszulesen.
Generell sollte man vor dem Durchlaufen ganzer Ansichten die Eigenschaft AutoUpdate
auf False
setzen, da sonst jedes Mal, wenn ein neues Dokument angesprochen wird, die Ansicht aktualisiert wird. Besonders effizient durchläuft man große Dokument(-teil-)mengen in Ansichten mittels NotesViewNavigator
:
Call view.Refresh()
view.AutoUpdate = False
Set vwn = view.CreateViewNavFromCategory("MyCategory") REM specify your navigator, e. g. by category
vwn.BufferMaxEntries = 400
vwn.EntryOptions = VN_ENTRYOPT_NOCOUNTDATA
Set vwe = vwn.GetFirst()
Do Until vwe Is Nothing
REM do here what you must do
Set vwe = vwn.GetNext(vwe)
Loop
view.AutoUpdate = True
Einige kleinere LotusScript-Tipps für alle Lebenslagen
Die Rangfolge der Schleifengeschwindigkeiten lautet ForAll
> For Next
> Do Until
/Do While
Immer Option Declare
verwenden und keine Mehrfach-Statements nutzen. Bei Dim i, j As Integer
ist i
ein Variant!
If
-Abfragen in LotusScript hintereinander ausführen: If a Then If b Then
ist schneller als If a And b Then
. Anders als bei anderen Programmiersprachen wird b immer ausgewertet, auch wenn a False ist.
doc.GetItemValue("x")
ist schneller (und meines Erachtens besser lesbar) als doc.x
. Das gleiche gilt für ReplaceItemValue
.
Array mit fester Größe lassen sich etwas schneller verarbeiten als dynamische Arrays.
Datenbankeigenschaften
Spätestens zum Abschluss der (Um-)Programmierung einer Datenbank sollte man die Datenbankeigenschaften beachten. Einige der Optionen sind definitiv bei jeder Anwendung einen Blick wert.
- Keine Ungelesen-Markierungen verwalten: Aktivieren, sofern den Anwendern nicht angezeigt werden muss, ob sie Dokumente bereits gelesen haben.
- Dokumententabelle in Ansicht optimieren: Aktivieren, falls sich der Form-Wert von Masken in der Datenbank nicht ändert.
- Freien Platz nicht überschreiben: Aktivieren
- LastAccessed-Eigenschaft verwalten: Deaktivieren, sofern nicht verwaltet werden muss, wann ein Dokument zuletzt geöffnet wurde.
- Spezielle Antworthierarchie nicht unterstützen: Aktivieren, falls @AllChildren und @AllDescendants nicht verwendet wird.
- LZ1-Komprimierung für Anhänge verwenden: Aktivieren
- Mehr Felder in der Datenbank zulassen: Aktivieren
- Einträge in $UpdatedBy-Feldern begrenzen/Einträge in $Revisions-Feldern begrenzen: Auf geringe Werte oder 0 setzen, wenn Änderungen an Dokumenten nicht/in geringem Umfang dokumentiert werden sollen oder bereits anderweitig dokumentiert werden.
Zusammenfassung
Damit haben wir die wichtigsten Punkte zu diesem Thema besprochen. Natürlich gibt es noch eine Menge weiterer anwendbarer Kniffe. Nach Umsetzung all dieser Ideen wird Ihre Anwendung jedoch schon spürbar flotter laufen.
Wir unterstützen Sie natürlich gerne, Ihre Anwendungen auf höchste Performance zu optimieren. Sprechen Sie uns hierzu einfach unter +49 4307 900 408 oder per Mail an kontakt@assono.de an.