LibreOffice Calc-Makros werden bei großen Tabellenblättern oft langsam, und zwar aus einem einfachen Grund: Das Makro verbringt mehr Zeit mit dem Überschreiten der UNO-Objektgrenze als mit der eigentlichen Berechnung. Das tausendfache Lesen, Ändern und Zurückschreiben einer Zelle kann deutlich aufwändiger sein als das Verschieben derselben Daten in größeren Blöcken.
Ziel ist es nicht, jedes Makro abstrakt „schnell“ zu machen. Eine sinnvolle Optimierung sollte dasselbe Ergebnis liefern, bei gleichem Datensatz in kürzerer Zeit fertig sein, Calc für den Arbeitsablauf ausreichend reaktionsschnell halten und keine neuen Korrektheits- oder Speicherprobleme verursachen. Die folgenden Techniken konzentrieren sich auf diese messbaren Ergebnisse.
Die aktuelle LibreOffice SDK-Dokumentation (Stand: Oktober 2026) identifiziert die hier verwendeten Tabellenkalkulationsschnittstellen in der LibreOffice 26.8 API-Referenz. Die Kernmethoden sind etablierte UNO-Schnittstellen und keine neu eingeführte Leistungsfunktion.
1. Messen Sie das Makro, bevor Sie es ändern.
Beginnen Sie mit einer reproduzierbaren Baseline. LibreOffice Basic bietet GetSystemTicks()die Möglichkeit, Systemtaktzeiten zu messen und Prozesse zu optimieren. Verwenden Sie für die Messung der Systemtaktzeiten und -prozesse die Funktion `time`, die Sie tatsächlich verbessern möchten. Umschließen Sie stattdessen den Teil des Makros, den Sie optimieren möchten, anstatt die Zeit für das Öffnen der Arbeitsmappe, Benutzereingaben oder andere Einrichtungsschritte zu messen.
Dim t0 As Long, elapsed As Long
t0 = GetSystemTicks()
' Run the work you want to measure here.
elapsed = GetSystemTicks() - t0
MsgBox "Elapsed ticks: " & elapsed
Führen Sie denselben Vorgang mehrmals mit derselben Dateikopie aus. Das Ergebnis des ersten Durchlaufs kann aufgrund von Dateisystemcaches, Formelstatus oder anderen einmaligen Vorgängen abweichen. Notieren Sie die Datensatzgröße, den verarbeiteten Bereich und ob die automatische Berechnung aktiviert war, damit Ihre Vergleiche aussagekräftig bleiben.
Ein gutes Ergebnis bedeutet nicht nur eine niedrigere Laufzeit. Überprüfen Sie, ob Zeilenanzahlen, Summen, Formeln, Textwerte, Datumsangaben und alle Ausgabebereiche weiterhin dem Ausgangswert entsprechen.
Offizielle Referenz: LibreOffice-Hilfe: GetSystemTicks-Funktion .
2. Zuerst die zellenweisen Lese- und Schreibvorgänge entfernen.
Wenn ein Makro einen großen Bereich durchläuft und wiederholt Methoden wie `get` aufruft getCellByPosition(), ist dieses Muster meist der erste Ansatzpunkt. Die UNO-API stellt `get` XCellRangeData.getDataArray()und setDataArray()`get` speziell für das Verschieben eines kompletten Zellbereichs als Array bereit.
Die offizielle API gibt an, dass getDataArray()eine Sequenz von Zeilen zurückgegeben wird, wobei jede Zeile Spalten enthält. Werte werden als Zeichenketten oder Gleitkommazahlen zurückgegeben. setDataArray()schreibt ein Array in einen Bereich zurück, und die Dimensionen des Arrays müssen mit diesem Bereich übereinstimmen.
Angenommen, die Spalten A bis E enthalten die Eingabedaten, die Ihr Makro transformiert. Anstatt jede Zelle einzeln zu lesen, wählen Sie den gesamten Bereich einmalig aus:
Dim doc As Object
Dim sheet As Object
Dim sourceRange As Object
Dim data As Variant
doc = ThisComponent
sheet = doc.Sheets.getByName("Data")
' Example only: A2:E50001.
sourceRange = sheet.getCellRangeByPosition(0, 1, 4, 50000)
data = sourceRange.getDataArray()
Die Verarbeitung erfolgt dataim Basisspeicher, anschließend wird das Ergebnis-Array in einem einzigen Vorgang in den entsprechenden Zielbereich geschrieben. Dadurch wird die Anzahl der UNO-Aufrufe im Vergleich zu Tausenden einzelner Lese- und Schreibvorgänge drastisch reduziert.
Offizielle Referenzen: LibreOffice SDK: XCellRangeData und LibreOffice SDK: XCellRange .
3. Verarbeiten Sie nur den tatsächlich benötigten Bereich.
Der Zugriff auf große Arrays ist zwar hilfreich, doch die Umwandlung eines unnötig großen Tabellenblatts in ein Array kann den Flaschenhals lediglich in den Arbeitsspeicher verlagern. Vermeiden Sie es, ganze Spalten oder das gesamte Calc-Grid fest zu kodieren, wenn die Aufgabe nur eine definierte Tabelle betrifft.
Ermitteln Sie die letzte relevante Zeile anhand der in Ihrer Arbeitsmappe bereits vorhandenen Informationen: Anzahl der importierten Zeilen, Größe des Datenbankergebnisses, eine festgelegte Schlüsselspalte oder ein vom Programm erstellter Bereich. Fordern Sie anschließend nur die vom Makro benötigten Zeilen und Spalten an.
Dies ist besonders wichtig, wenn das Arbeitsblatt Formatierungen weit unterhalb der eigentlichen Daten enthält oder wenn ältere Inhalte den scheinbar genutzten Bereich vergrößert haben. Große Speicherbereiche verbrauchen viel RAM, und eine einzige übermäßige Speicherzuweisung kann sogar schädlicher sein als die Verarbeitung mittelgroßer Blöcke.
Wann sollte man auf Chunking umstellen?
Wenn ein einzelnes Array den Speicherverbrauch sprunghaft ansteigen lässt, lange Pausen vor dem Verarbeitungsbeginn verursacht oder an die praktischen Grenzen des Rechners stößt, sollten die Daten blockweise verarbeitet werden. Beispielsweise können mehrere tausend Zeilen verarbeitet, die Ergebnisse geschrieben und anschließend mit dem nächsten Block fortgefahren werden. Es gibt keine allgemeingültige ideale Blockgröße; testen Sie daher mit der tatsächlichen Arbeitsmappe und Hardware.
4. Bildschirmaktualisierungsbenachrichtigungen bei hoher Arbeitsbelastung unterdrücken.
Ein Calc-Dokument implementiert die LibreOffice- XModelSchnittstelle. Seine lockControllers()Methode pausiert bestimmte Controller-Benachrichtigungen, die für Anzeigeaktualisierungen verwendet werden, und unlockControllers()setzt sie anschließend fort. Dadurch kann unnötige visuelle Arbeit reduziert werden, während ein Makro viele Änderungen durchführt.
Dim doc As Object
doc = ThisComponent
doc.lockControllers()
' Perform bulk changes here.
doc.unlockControllers()
Die offizielle API schreibt ausdrücklich vor, dass Controller-Sperren und -Entsperren einander zugeordnet sein müssen. Das bedeutet, dass Produktionsmakros eine Fehlerbehandlung enthalten sollten, die sicherstellt, dass die entsprechende Funktion unlockControllers()auch bei einem Verarbeitungsfehler ausgeführt wird. Das Sperren des Dokuments ist keine Leistungsoptimierung, sondern ein fehlerhafter Bereinigungspfad.
Offizielle Referenz: LibreOffice SDK: XModel .
5. Automatische Neuberechnung steuern, wenn Formeln die Laufzeit dominieren
Wenn das Makro wiederholt Zellen ändert, die viele Formeln speisen, kann Calc viel Zeit mit der Neuberechnung verbringen, während das Makro noch Zwischenwerte aktualisiert. Das Tabellendokument stellt die XCalculatableSchnittstelle bereit, einschließlich isAutomaticCalculationEnabled(), enableAutomaticCalculation(), calculate()und calculateAll().
Ein sichereres Vorgehen besteht darin, den aktuellen Berechnungsmodus des Benutzers zu speichern, die automatische Berechnung nur während des Updates zu deaktivieren und anschließend den ursprünglichen Zustand wiederherzustellen:
Dim doc As Object
Dim wasAutoCalc As Boolean
doc = ThisComponent
wasAutoCalc = doc.isAutomaticCalculationEnabled()
doc.enableAutomaticCalculation(False)
' Perform bulk updates.
doc.enableAutomaticCalculation(wasAutoCalc)
If wasAutoCalc Then
doc.calculate()
End If
calculate()Berechnet geänderte Zellen neu. calculateAll()Berechnet jede Zelle neu, was selbst rechenintensiv sein kann. Rufen Sie diese Funktion daher nicht automatisch auf, nur weil ein Makro abgeschlossen ist. Führen Sie die vollständige Neuberechnung nur dann durch, wenn die Logik der Arbeitsmappe dies tatsächlich erfordert.
Wie bei der Controller-Sperre sollte der Berechnungsstatus in einem Fehlerbereinigungspfad wiederhergestellt werden. Ein Makro sollte die Arbeitsmappe eines Benutzers nicht stillschweigend im manuellen Berechnungsmodus belassen.
Offizielle Referenz: LibreOffice SDK: XCalculatable .
6. Die Optimierungen sicher kombinieren.
Die effektivste Struktur ist in der Regel folgende: einen genauen Bereich festlegen, diesen einmal einlesen, die Werte im Speicher verarbeiten, die Ergebnisse gesammelt schreiben und vermeidbare UI- oder Neuberechnungsarbeiten nur für die Dauer dieses Vorgangs unterdrücken.
Ein praktisches Aufräummuster in LibreOffice Basic sieht folgendermaßen aus:
Sub ProcessLargeData
Dim doc As Object
Dim sheet As Object
Dim dataRange As Object
Dim data As Variant
Dim wasAutoCalc As Boolean
On Error GoTo CleanUp
doc = ThisComponent
sheet = doc.Sheets.getByName("Data")
dataRange = sheet.getCellRangeByPosition(0, 1, 4, 50000)
wasAutoCalc = doc.isAutomaticCalculationEnabled()
doc.lockControllers()
doc.enableAutomaticCalculation(False)
data = dataRange.getDataArray()
' Transform data in memory here.
' Build an output array with dimensions matching its target range.
CleanUp:
doc.enableAutomaticCalculation(wasAutoCalc)
If doc.hasControllersLocked() Then
doc.unlockControllers()
End If
If wasAutoCalc Then
doc.calculate()
End If
End Sub
Das Beispiel lässt die Transformationslogik absichtlich ungenau, da diese von Ihrer Arbeitsmappe abhängt. Die wichtige Optimierung liegt in der Struktur des Workflows, nicht in einer fiktiven Geschäftsberechnung.
7. Ziehen Sie die in Calc integrierten Funktionen in Betracht, bevor Sie sie neu implementieren.
LibreOffice Basic kann Calc-Funktionen über den com.sun.star.sheet.FunctionAccessDienst aufrufen. Wenn Ihr Makro eine Suche, Aggregation oder eine andere Operation manuell implementiert, die Calc bereits bereitstellt, kann die Verwendung der integrierten Funktion den Code vereinfachen und benutzerdefinierte Schleifen reduzieren.
Das ist keine Garantie dafür, dass jede integrierte Funktion jeden benutzerdefinierten Algorithmus übertrifft. Testen Sie die tatsächliche Arbeitslast. Die offizielle Hilfe zeigt, wie Calc-Funktionen aus Basic aufgerufen werden, und weist darauf hin, dass die Funktionsnamen in Englisch angegeben werden.
Offizielle Referenz: LibreOffice-Hilfe: Verwendung von Calc-Funktionen in Makros .
Wie man beurteilt, ob die Optimierung gut genug ist
| Überprüfen | Gutes Zeichen | Wann sollte man den Ansatz ändern? |
| Laufzeit | Wiederholte Läufe sind durchweg kürzer als der Ausgangswert. | Der größte Teil der Zeit wird immer noch in einem Abschnitt verbracht; beschreiben Sie diesen Abschnitt separat. |
| Richtigkeit | Summen, Zeilenanzahlen, Formeln und repräsentative Datensätze stimmen mit dem ursprünglichen Makro überein. | Die Konvertierung von Arrays ändert Datentypen oder Ausgabedimensionen. |
| Erinnerung | Das Sortiment für große Mengen passt problemlos ohne Umpacken oder lange Zuteilungspausen. | Verwenden Sie kleinere Abschnitte, wenn ein Array über den gesamten Bereich zu groß wird. |
| Neuberechnung | Die Formelverarbeitung erfolgt einmalig nach dem Hauptupdate und nicht nach jedem Schreibvorgang. | Formelabhängigkeiten erfordern berechnete Zwischenwerte. |
| UI-Verhalten | Das Dokument kehrt nach Abschluss oder Fehler in den normalen Anzeige- und Berechnungszustand zurück. | Füge eine stärkere Bereinigungs-/Fehlerbehandlung hinzu, falls der Zustand geändert bleiben kann. |
Häufige Fehler, die den Nutzen zunichtemachen
- Ein ganzes Arbeitsblatt in den Speicher einlesen, obwohl nur wenige Spalten benötigt werden.
- Ich verwende die Methode,
getDataArray()schreibe aber trotzdem jedes Ergebnis Zelle für Zelle zurück.
- Die automatische Berechnung wurde deaktiviert und vergessen, die vorherige Einstellung wiederherzustellen.
- Sperren von Steuerungen ohne zuverlässigen Bereinigungspfad.
- Nach jeder kleinen Charge anrufen
calculateAll(), selbst wenn nur verschmutzte Zellen neu berechnet werden müssen.
- Die Geschwindigkeit wird anhand eines einzelnen Laufs anstatt durch wiederholte Messungen an denselben Daten beurteilt.
- Die Leistung wird optimiert, ohne zu überprüfen, ob die Ausgabe identisch bleibt.
Wo diese Techniken nicht mehr helfen
Array-Transfers reduzieren hauptsächlich den Zugriffsaufwand für Tabellenkalkulationsobjekte. Sie beheben jedoch keine intrinsisch aufwändigen Algorithmen. Ein verschachtelter Vergleich jeder Zeile mit jeder anderen kann beispielsweise selbst dann langsam bleiben, wenn alle Werte im Speicher vorhanden sind. In diesem Fall sollte der Algorithmus angepasst werden: Verwenden Sie Dictionaries oder Indizes, sortieren Sie nur einmal statt wiederholt, vermeiden Sie redundante Arbeitsschritte oder verlagern Sie die Verarbeitung auf ein besser geeignetes Datenverarbeitungstool, wenn die Tabellenkalkulation nicht mehr die optimale Ausführungsumgebung darstellt.
Dasselbe gilt für Makros, die von Netzwerkaufrufen, Datenbankabfragen, Datei-E/A oder externen Diensten dominiert werden. Messen Sie zuerst, um den tatsächlichen Engpass zu optimieren und nicht nur die sichtbare Tabellenkalkulationsschleife.
Empfohlene Optimierungsreihenfolge
- Messen Sie das aktuelle Makro mit einem reproduzierbaren Datensatz.
- Wiederholte Lese- und Schreibvorgänge von Zellen werden durch Bereichsarrays ersetzt.
- Beschränken Sie die Verarbeitung auf die exakt benötigten Zeilen und Spalten.
- Verwenden Sie Chunking, wenn das Bulk-Array für eine komfortable Speichernutzung zu groß ist.
- Sperren Sie die Steuerungen bei großen Chargen, mit garantierter Reinigung.
- Die automatische Berechnung sollte vorübergehend ausgesetzt werden, wenn sich wiederholte Formelneuberechnungen als Engpass erweisen.
- Berechnen Sie nur so viel neu wie nötig, stellen Sie den Anwendungsstatus wieder her und überprüfen Sie die Ausgabe.
- Erneute Messung. Falls die Laufzeit weiterhin von der Berechnung und nicht vom UNO-Zugriff dominiert wird, sollte stattdessen der Algorithmus verbessert werden.
Bei großen Calc-Datensätzen ist die Reduzierung der Aufrufe zwischen Basic- und Tabellenkalkulationsobjekten meist die wichtigste strukturelle Verbesserung. Jede zusätzliche Optimierung sollte messbar sein und nicht als bloße Routine betrachtet werden. Ein schnelleres Makro ist nur dann nützlich, wenn es korrekt, vorhersehbar und wartungsfreundlich bleibt.