Odoo ist langsam: Ursachen finden und beheben
Kurz gesagt
Langsames Odoo hat drei Schichten: die Darstellung im Browser, die Arbeit der Odoo-Prozesse und die Abfragen in PostgreSQL. Messen Sie zuerst Antwortzeit und Auslastung, grenzen Sie die Aktion mit dem Profiler ein und prüfen Sie danach die Abfrage mit EXPLAIN (ANALYZE, BUFFERS). Odoo-Online-Datenbanken lassen sich nicht profilieren; auf einer eigenen Installation zählen zusätzlich Worker, Arbeitsspeicher und die Grenzwerte je Worker.
Das Wichtigste
- Erst messen: Antwortzeit, abgelehnte Anfragen und Auslastung je Hostingmodell, nicht die Zahl der Konten.
- Odoo 20.0 bringt einen Profiler; Odoo-Online-Datenbanken lassen sich laut Dokumentation nicht profilieren.
- Ein Worker trägt rund sechs gleichzeitige Nutzer; zusätzliche Worker beheben keinen langsamen Vorgang.
- Auf Odoo.sh stehen im Reiter Logs die Datei pg_slow_queries.log und im Reiter Monitor die Lastkurven.
- EXPLAIN (ANALYZE, BUFFERS) vergleicht Schätzung und Wirklichkeit und zeigt, ob eine Sortierung auf die Platte ging.
Langsamkeit ist ein Befund, keine Ursache: Derselbe Satz „die Rechnungsliste ist langsam” kann zu wenige Prozesse für die gleichzeitigen Zugriffe meinen, eine geplante Aktion um dieselbe Zeit, eine Abfrage ohne Index oder ungebündelte Dateien im Browser. Dieses Vorgehen trennt die drei Schichten und ordnet jedem Symptom eine Messung zu.
Was Sie vorab brauchen
- Die Zugänge Ihres Hostingmodells: eigene Installation — Konfigurationsdatei, Protokoll, PostgreSQL-Zugang, Serverkennzahlen; Odoo.sh — Reiter Monitor und Logs, Webshell; Odoo Online — Verwaltung im Odoo-Konto.
- Einen wiederholbaren Fall: Aktion, Nutzerkreis, Tag und Uhrzeit in UTC, weil die technischen Protokolle von Odoo.sh in UTC laufen.
- Einen Ausgangswert als Zahl, etwa die durchschnittliche Antwortzeit aus dem Monitor von Odoo.sh.
- Rechte für
EXPLAIN; für Summen über alle Abfragen das Modulpg_stat_statementsinshared_preload_libraries(Neustart nötig).
Diagnosebaum: vom Symptom zur Ursache
Der Baum ist die Prüfreihenfolge dieser Redaktion, keine Aussage über Häufigkeiten.
| Symptom | Erste Messung | Mögliche Ursache | Weiter bei |
|---|---|---|---|
| Alle Seiten langsam, alle Nutzer betroffen | Antwortzeit, abgelehnte Anfragen, Prozessorlast | zu wenige Prozesse oder Kerne, Mehrthread-Betrieb | Schritt 2 und 3 |
| Eine Liste, ein Bericht oder das Speichern ist langsam | Profiler auf diese Aktion | Abfrage oder QWeb-Bericht aus einem Modul | Schritt 4 und 7 |
| Die Seite braucht lange bis zu den Daten | Antwortzeit, Adresszeile im Browser | ungebündelte Dateien (debug=assets), Odoo liefert statische Dateien selbst | Schritt 8 |
| Jeden Tag zur selben Minute | Lastkurve und Protokoll um diese Zeit | geplante Aktion, Mail, Import oder Sicherung | Schritt 5 |
| Ein Vorgang bricht ab, danach läuft es wieder | Protokoll um den Abbruch, Speicher je Worker | Zeit- oder Speichergrenze, Worker beendet | Schritt 3 und 8 |
| Mit der Datenmenge schleichend langsamer | Dauer der Abfrage, EXPLAIN (ANALYZE, BUFFERS) | fehlender Index, veraltete Statistik, Sortierung auf die Platte | Schritt 6 und 7 |
Schritt für Schritt: messen, eingrenzen, beheben
Schritt 1: Fall und Zeitpunkt festhalten
Schreiben Sie auf, was langsam ist und was nicht: eine bestimmte Liste, ein Bericht, das Speichern, die Anmeldung oder die gesamte Oberfläche. Halten Sie fest, ob ein Nutzer oder alle betroffen sind, ob es dauerhaft oder zu bestimmten Zeiten auftritt und seit wann. Ergebnis: eine Notiz wie „14.10.2026, 09:12 UTC, Verkaufsaufträge, Liste mit 20.000 Zeilen, alle Nutzer, seit dem Datenimport am 13.10.”
Schritt 2: Antwortzeit und Auslastung messen
Bei Odoo.sh liefert der Reiter Monitor die Lastkurven: Arbeitsspeicher der Worker und der Datenbank, Prozessorlast getrennt nach HTTP-Workern, geplanten Aktionen und Datenbankprozessen, dazu Anfragen je Sekunde, abgelehnte Anfragen und die durchschnittliche Antwortzeit in Millisekunden. Ältere Abschnitte sind verdichtet; Einzelheiten zeigt der jüngere Verlauf.
Auf einer eigenen Installation messen Sie Prozessorlast, Arbeitsspeicher und Antwortzeit selbst. Das Konfigurationsbeispiel der Bereitstellungsseite rechnet mit vier Prozessorkernen und acht Threads und prüft die CPU-Last zwischen 7 und 7,5.
Schritt 3: Anfragen und Kapazität vergleichen
Für eine eigene Installation gelten die Faustregeln der Bereitstellungsseite: Prozesse = Prozessorkerne × 2 + 1, ein Worker trägt rund sechs gleichzeitige Nutzer. Prüfen Sie, ob die Option workers gesetzt ist: Auf dem Vorgabewert 0 läuft der Mehrthread-Server, den die Dokumentation für Entwicklung und Demonstrationen nennt; wegen der Python-Beschränkung (GIL) nutzt er die Hardware nicht aus.
Mehr Prozesse beheben einen langsamen Vorgang nicht: Die Odoo.sh-Dokumentation hält fest, dass zusätzliche Worker nur die Zahl gleichzeitiger Verbindungen erhöhen; bleibt es langsam und liegt es nicht an Ihren Anpassungen, nennt sie den Odoo-Support. Für die Größenwahl siehe Odoo-Server dimensionieren.
Schritt 4: Die langsame Aktion mit dem Profiler isolieren
Odoo 20.0 enthält einen Profiler, der ausgeführte Abfragen und Aufrufketten aufzeichnet (die Dokumentation beschriftet ihn englisch). Er wird zuerst datenbankweit freigeschaltet — im Entwicklermodus über die Schaltfläche Enable profiling oder unter Einstellungen (Settings) im Bereich Performance im Feld Enable profiling until — und danach für die eigene Sitzung eingeschaltet. Standardmäßig zeichnen die Sammler Record sql und Record traces auf; der SQL-Sammler nimmt jede Abfrage im laufenden Thread samt Aufrufkette auf, der periodische Sammler in kurzen Abständen die Aufrufkette. Die Aufnahmen liegen als Datensätze des Modells ir.profile je Sitzung vor; die Ansichten Combined, sql (no gap) und sql (density) trennen den SQL-Anteil vom Python-Anteil.
Zwei Grenzen nennt dieselbe Seite: Odoo-Online-Datenbanken lassen sich nicht profilieren, und das Profiling kostet selbst Ausführungszeit.
Schritt 5: Zeitgesteuerte Last prüfen
Last entsteht auch ohne Nutzeraktion. Bei Odoo.sh trennt die Prozessorkurve geplante Aktionen und eingehende Mails von den HTTP-Workern. Sehen Sie dort eine Spitze zur gemeldeten Uhrzeit, prüfen Sie die geplanten Aktionen im technischen Menü sowie die Zeitpunkte von Importen, Sicherungen und Serienmails.
Bei Odoo.sh laufen geplante Aktionen nach bestem Bemühen, und nach der Dokumentation ist nicht mit einer Ausführung häufiger als alle fünf Minuten zu rechnen; lange Aktionen sollen in kleinen Stapeln arbeiten und nach jedem Stapel festschreiben. Auf einer eigenen Installation bestimmt die Option max-cron-threads (Vorgabe 2), wie viele Threads oder Prozesse für Cron-Aufgaben bereitstehen — Threads im Mehrthread-Betrieb, Prozesse im Mehrprozess-Betrieb; im Mehrprozess-Betrieb kommen sie zu den HTTP-Workern hinzu. Welche Regeln zeitgesteuert laufen, beschreibt Automatisierungsregeln in Odoo.
Schritt 6: Die Datenbank messen und die langsame Abfrage finden
Sie brauchen zuerst die Abfrage, die Zeit kostet. Auf Odoo.sh führt der Reiter Logs die Datei pg_slow_queries.log mit Abfragen, die ungewöhnlich lange brauchen. Auf einer eigenen Installation setzen Sie log_min_duration_statement in der postgresql.conf auf einen Wert in Millisekunden; -1 (Vorgabe) schaltet die Protokollierung ab, 0 protokolliert jede Anweisung. pg_stat_activity zeigt je Serverprozess den Zustand, die laufende Abfrage und mit den Spalten wait_event_type und wait_event das Warteereignis. Lock ist nur einer von mehreren Wartetypen (daneben etwa IO, LWLock und Client), und eine Sperre auf eine Tabelle zeigt sich als Warteereignis vom Typ Lock (etwa wait_event relation). Eine Sperre ist erst dann die Ursache und nicht Rechenzeit, wenn ein Prozess nachweislich auf eine solche Sperre wartet; dass mehrere Prozesse auf dieselbe Tabelle warten, belegt sie allein nicht.
Für Summen über alle Abfragen dient pg_stat_statements (Laden über shared_preload_libraries, Neustart nötig, Spalte total_exec_time). Pläne langsamer Abfragen schreibt auto_explain mit, sobald auto_explain.log_min_duration gesetzt ist; auto_explain.log_analyze ist standardmäßig aus.
Schritt 7: Die Abfrage mit EXPLAIN erklären
Mit EXPLAIN (ANALYZE, BUFFERS) führt PostgreSQL die Abfrage aus und stellt den geschätzten Werten die tatsächlichen gegenüber. Weichen die Zeilenzahlen stark voneinander ab, passen die Statistiken nicht zur Verteilung; dann hilft ANALYZE, für korrelierte Spalten zusätzlich eine erweiterte Statistik. Ein sequenzieller Scan über eine große Tabelle (im Plan Seq Scan) kann auf einen fehlenden Index hinweisen; fehlt jeder Index, ist er die einzige Möglichkeit. Er ist aber kein Beweis: PostgreSQL wählt ihn auch dann, wenn eine Abfrage viele Zeilen braucht, weil das separate Holen der Zeilen über den Index teurer ist als das Lesen der Seiten der Reihe nach. Die Kosten im Plan sind willkürliche Einheiten und keine Zeitangabe; vergleichen Sie die geschätzten mit den tatsächlichen Zeilenzahlen, bevor Sie einen Index anlegen. Der Sort-Knoten nennt die Sortiermethode und ob sie im Arbeitsspeicher oder auf der Platte lief; ging sie auf die Platte, ist work_mem der Anhaltspunkt (Vorgabe 4 MB, je Sortier- oder Hash-Operation und je Sitzung mehrfach möglich).
In eigenen Modulen setzen Felder einen Index über index=True. Die Dokumentation warnt zugleich, jedes Feld zu indizieren: Indizes kosten Platz und belasten jeden Einfüge-, Änderungs- und Löschvorgang.
Schritt 8: Wartung, Grenzwerte und statische Dateien prüfen
- Datenbankwartung. Ein
UPDATEoderDELETEgibt den Platz einer Zeile nicht sofort frei;VACUUMmacht ihn für neue Zeilen nutzbar, sonst wächst die Tabelle. In der Vorgabekonfiguration ist autovacuum eingeschaltet; für partitionierte Tabellen führt es keinANALYZEder Elterntabelle aus. - Arbeitsspeicher der Datenbank.
shared_bufferssteht voreingestellt auf 128 MB. Als Startwert nennt die PostgreSQL-Dokumentation ein Viertel des Arbeitsspeichers, und zwar für einen ausschließlich als Datenbankserver genutzten Rechner mit mindestens 1 GB Arbeitsspeicher; läuft Odoo auf demselben Server, muss dessen Arbeitsspeicher davon abgehen. Unter 1 GB empfiehlt dieselbe Stelle einen kleineren Anteil, damit Platz für das Betriebssystem bleibt, und mehr als 40 % bringen nach ihrer Einschätzung kaum mehr. Der Wert ändert sich nur beim Start des Servers. - Grenzwerte je Worker (Mehrprozess-Betrieb,
workersungleich 0). Auf einer eigenen Installation beendet der Prozessverwalter einen Worker, der länger als 120 Sekunden Wanduhrzeit braucht (Vorgabelimit_time_real), und einen Worker über 2048 MiB weichem beziehungsweise 2560 MiB hartem Arbeitsspeicher. Prüfen Sie, welche Werte in Ihrer Konfigurationsdatei stehen. - Statische Dateien. Odoo liefert Dateien aus den Modulen und Anhänge selbst aus; die Dokumentation nennt das für die Leistung nicht ideal und empfiehlt, statische Dateien vom Webserver auszuliefern und Anhänge über X-Sendfile oder X-Accel (
--x-sendfile) zu übergeben. - Browser. JavaScript und Stilvorlagen werden gebündelt und minifiziert, außer im Modus
debug=assets; steht?debug=assetsin der Adresszeile, lädt der Browser ungebündelte Dateien. Setzen Sie vor der Beurteilung?debug=0.
So prüfen Sie das Ergebnis
Messen Sie dieselbe Kennzahl wie am Anfang, mit derselben Aktion und zur gleichen Tageszeit: die durchschnittliche Antwortzeit, die Dauer einer Abfrage oder die Zeilenzahlen im Plan. Schalten Sie den Profiler vorher ab.
shared_buffers wirkt erst nach einem Start des Datenbankservers; log_min_duration_statement und work_mem lassen sich für eine Sitzung setzen. Prüfen Sie einen neuen Index mit EXPLAIN (ANALYZE, BUFFERS) derselben Abfrage. Solche Änderungen gehören zuerst in eine Kopie der Datenbank, siehe Testumgebung für Odoo.
Wenn etwas nicht klappt
| Beobachtung | Ursache | Was tun |
|---|---|---|
| Die Schaltfläche Enable profiling fehlt | Entwicklermodus nicht aktiv oder Datenbank auf Odoo Online | Entwicklermodus einschalten; auf Odoo Online ist Profiling ausgeschlossen |
| Das Profiling zeigt fast nur den SQL-Sammler | Der SQL-Sammler von Odoo kostet bei vielen kleinen Abfragen selbst Zeit | Für die Daueranalyse den periodischen Sammler nutzen |
| Ein Index ist angelegt, der Plan nutzt ihn nicht | Für diese Abfrage kann der sequenzielle Scan billiger sein, etwa wenn sie viele Zeilen braucht; die Kostenschätzung ist keine Zeitangabe | Plan mit EXPLAIN (ANALYZE, BUFFERS) prüfen, geschätzte und tatsächliche Zeilenzahlen vergleichen, Statistik aktualisieren |
| EXPLAIN ANALYZE verändert Daten | Die Option ANALYZE führt die Anweisung aus | Schreibende Anweisungen in der Testumgebung prüfen |
Wann Sie Hilfe holen sollten
Bei Odoo.sh nennt die Dokumentation den Odoo-Support, wenn Vorgänge langsam bleiben und Ihre Anpassungen nicht die Ursache sind; die Webshell des Zweigs enthält psql. Liegt die Ursache in eigenen oder gekauften Modulen, sind der Entwickler oder Ihr Odoo-Partner die richtige Stelle.
Bei Odoo Online lässt sich nicht profilieren. Die Dokumentation 20.0 beschreibt für Odoo Online die Verwaltung im Datenbankmanager; wo er nicht weiterhilft — etwa bei einer Sicherung, die zu groß zum Herunterladen ist, bei einer zusätzlichen Kopie über der Grenze von fünf Duplikaten oder bei einer Eigentumsübertragung — verweist dieselbe Seite auf den Odoo-Support und ein Support-Ticket. Für die laufende Beobachtung siehe Odoo überwachen.