«Odoo гальмує» зазвичай означає одне з чотирьох: замало воркерів для кількості користувачів, база PostgreSQL на налаштуваннях за замовчуванням, кастомний код, що робить тисячі запитів там, де вистачило б десяти, або заплановані задачі та інтеграції, що змагаються з користувачами за ресурси. Рішення рідко полягає в потужнішому залізі. У гайді — як ми діагностуємо і виправляємо продуктивність Odoo на власних серверах і на Odoo.sh: розрахунок воркерів і пам'яті, налаштування PostgreSQL, вбудований профайлер і патерни коду, що дають найбільший ефект.
Почніть з вимірювань, а не здогадок
Перш ніж щось змінювати, з'ясуйте, куди йде час:
- Які сторінки чи дії повільні — відкриття списку, валідація відвантаження, проведення рахунків, checkout на сайті.
- Метрики сервера — CPU і пам'ять на воркер, load average, swap.
- Метрики бази даних — повільні запити, блокування, частка влучань у кеш, роздутість таблиць. Розширення
pg_stat_statementsпоказує запити, що сумарно забирають найбільше часу (PostgreSQL: pg_stat_statements). - Профайлер Odoo — записує кожен SQL-запит і Python stack trace запиту та показує їх як flame graph (Odoo: продуктивність і профілювання).
Профайлер вмикається в режимі розробника для вебзапитів або використовується як контекстний менеджер у коді й тестах. Зверніть увагу: бази на Odoo Online профілювати не можна, на Odoo.sh та on-premise — можна.
Крок 1: Правильно розрахуйте воркери і пам'ять
У продакшені Odoo має працювати в мультипроцесному режимі з пулом воркерів. Документація Odoo з розгортання дає емпіричні правила (Odoo: розгортання on-premise):
- Максимум воркерів ≈ (кількість ядер CPU × 2) + 1.
- Один воркер обслуговує приблизно 6 одночасних користувачів.
- Близько 20% запитів важкі (приблизно 1 ГБ RAM на воркер), 80% — легкі (приблизно 150 МБ).
Приклад із самої документації: серверу з 4 ядрами і 60 одночасними користувачами теоретично потрібно 10 воркерів, але CPU обмежує їх до 9, тож конфігурація має 8 HTTP-воркерів плюс 1 cron-воркер і приблизно 3 ГБ RAM для Odoo:
[options]
workers = 8
max_cron_threads = 1
limit_memory_soft = 629145600 ; 600 МБ: воркер перезапускається після запиту
limit_memory_hard = 1677721600 ; 1,6 ГБ: воркер завершується негайно
limit_time_cpu = 600
limit_time_real = 1200
limit_request = 8192
proxy_mode = True ; за Nginx чи іншим reverse proxy
Типові помилки: робота з workers = 0 (потоковий режим для розробки), набагато більше воркерів, ніж ядер CPU, і такі жорсткі ліміти пам'яті, що важкі звіти обриваються посеред запиту. Коли одночасних користувачів стає кілька десятків, винесіть PostgreSQL на окремий сервер або явно зарезервуйте для нього ресурси.
Крок 2: Налаштуйте PostgreSQL
За замовчуванням PostgreSQL налаштований під невелику машину. Найважливіші параметри (PostgreSQL: споживання ресурсів):
| Параметр | Відправна точка | Навіщо |
|---|---|---|
shared_buffers |
~25% RAM на виділеному сервері БД | Власний кеш PostgreSQL |
effective_cache_size |
50–75% RAM | Допомагає планувальнику обирати індексні скани |
work_mem |
16–64 МБ, за вимірюваннями | Пам'ять на одне сортування чи хешування; завелике значення множиться на кількість з'єднань |
maintenance_work_mem |
512 МБ–2 ГБ | Швидші vacuum і побудова індексів |
random_page_cost |
1,1 на SSD/NVMe | Значення за замовчуванням розраховане на HDD |
Також:
- Стежте за autovacuum. Таблиці Odoo на кшталт
mail_message,stock_moveіaccount_move_lineростуть швидко. Моніторте мертві кортежі й за потреби налаштовуйте autovacuum для окремих таблиць. - Використовуйте пулер з'єднань або обмежте їх кількість. Кожен воркер Odoo відкриває з'єднання з БД;
db_maxconnтримає їх у межах. - Оновлюйтеся. У PostgreSQL 18 з'явився асинхронний ввід-вивід із прискоренням читання до 3× для послідовних і bitmap-сканів, а також skip scan для багатоколонкових індексів (реліз PostgreSQL 18). Перед оновленням перевірте, які версії підтримує ваш реліз Odoo.
Надійні бекапи — частина тієї самої розмови, що й продуктивність; див. Бекапи PostgreSQL і аварійне відновлення.
Крок 3: Виправте код — антипатерни ORM
У більшості повільних інстансів Odoo, які ми аудитуємо, основна частина проблем — у кастомних модулях. Звичні підозрювані:
Запити всередині циклів. Виклик search чи browse для кожного запису перетворює один запит на тисячі.
# Повільно: окремий search на кожен рядок замовлення
for line in order.order_line:
stock = self.env["stock.quant"].search([("product_id", "=", line.product_id.id)])
# Швидко: один згрупований запит для всіх товарів
quants = self.env["stock.quant"]._read_group(
[("product_id", "in", order.order_line.product_id.ids)],
groupby=["product_id"], aggregates=["quantity:sum"],
)
qty_by_product = {product.id: qty for product, qty in quants}
Запис по одному. create приймає список значень, а write на recordset оновлює багато записів одним запитом. Відповідно пакетуйте імпорти й синхронізації.
Незбережені обчислювані поля у списках і фільтрах. Обчислюване поле у списку чи в домені обчислюється для кожного запису при кожному завантаженні. Зберігайте його, якщо його читають значно частіше, ніж змінюються залежності, і точно оголошуйте залежності.
Відсутні індекси. Поля, що часто використовуються в доменах, особливо на великих таблицях, потребують index=True або власного індексу. Підтверджуйте через EXPLAIN ANALYZE на реальному запиті.
Важка логіка в onchange і constraints. Вони виконуються інтерактивно — тримайте їх легкими.
Гайд з продуктивності також описує assertQueryCount для тестів: можна зафіксувати кількість запитів критичного методу і ловити регресії в CI (Odoo: продуктивність).
Крок 4: Приборкайте cron-задачі та інтеграції
Заплановані дії й зовнішні API — часта прихована причина денних гальмувань:
- Запускайте важкі задачі поза піковими годинами і обробляйте записи пакетами з комітами між ними, щоб один збій не відкотив години роботи.
- Не викликайте повільні зовнішні API всередині запиту користувача, якщо можна цього уникнути. Ставте роботу в чергу й обробляйте асинхронно; задавайте таймаути й повтори. Класичний приклад — інтеграції з перевізниками і платежами, як у статті Інтеграція Odoo з Новою Поштою та monobank.
- Стежте за конкуренцією за блокування. Довгі транзакції на
stock_quantчи послідовностях можуть блокувати користувачів, що валідують відвантаження чи рахунки.
Крок 5: Архівуйте і чистіть дані
Роки повідомлень у чатері, вкладень, логів і старих записів сповільнюють усе. Архівуйте або видаляйте те, що нікому не потрібно: технічні логи, застарілі черги листів, старі вкладення, перенесені в об'єктне сховище. Легші таблиці — це швидші vacuum, бекапи й оновлення; останнє важливо, коли плануєте наступний перехід на нову версію, див. Odoo 17 vs Odoo 18.
Діагностичний чек-лист
- Odoo працює в мультипроцесному режимі з воркерами, розрахованими під CPU і користувачів
- Ліміти пам'яті дозволяють важкі звіти без завершення воркерів
- PostgreSQL налаштований під сервер, увімкнено
pg_stat_statements - Autovacuum встигає на найбільших таблицях
- Повільні сторінки профільовано профайлером Odoo
- У кастомних модулях немає запитів у циклах; create і write пакетні
- Є індекси для частих доменів на великих таблицях
- Cron-задачі пакетні й заплановані поза піком; інтеграції асинхронні
- Старі логи і вкладення заархівовано
Симптоми і ймовірні причини
| Симптом | Ймовірна причина | Що перевірити спершу |
|---|---|---|
| Усе гальмує в певні години | Cron-задачі чи імпорти конкурують із користувачами | Заплановані дії, що виконуються в цей час |
| Повільний один список, решта нормальні | Незбережене обчислюване поле чи відсутній індекс | Профайлер на цьому списку, EXPLAIN ANALYZE |
| Зависає валідація відвантажень | Конкуренція за блокування складських таблиць | Довгі транзакції в pg_stat_activity |
| Випадкові помилки 502 | Воркери завершуються через ліміти пам'яті чи часу | Логи Odoo щодо limit_memory_hard чи таймаутів |
| Гальмує після місяців роботи | Роздуті таблиці, зростання таблиць листів і логів | Статистика autovacuum, розміри таблиць |
| Повільний checkout на сайті | Виклики зовнішніх API в запиті | Час викликів перевізника чи платежів |
FAQ
Чи швидший Odoo.sh за власний хостинг? Не сам по собі. Odoo.sh прибирає інфраструктурну роботу і дозволяє легко додати воркери, але повільний кастомний код повільний будь-де.
Скільки користувачів витримає один сервер? За емпіричним правилом Odoo, сервер на 4 ядра обслуговує приблизно 50–60 одночасних користувачів за якісного коду. Загальна кількість іменних користувачів може бути в рази більшою, бо всі одночасно не працюють.
Чи покращує продуктивність оновлення Odoo? Часто так — нові версії принесли покращення ORM та інтерфейсу. Але оновлення не виправить неефективні кастомні модулі.
Чи варто додати репліку для читання? Для важкої звітності й BI — так. Спрямуйте дашборди й експорти на репліку, щоб аналітики не сповільнювали операційну роботу.
Джерела
- Odoo. Deploying Odoo on-premise: воркери і пам'ять.
- Odoo. Performance and profiling.
- PostgreSQL. Resource consumption settings.
- PostgreSQL. pg_stat_statements.
- PostgreSQL Global Development Group (2025). PostgreSQL 18 released.