«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 — так. Спрямуйте дашборди й експорти на репліку, щоб аналітики не сповільнювали операційну роботу.

Джерела

  1. Odoo. Deploying Odoo on-premise: воркери і пам'ять.
  2. Odoo. Performance and profiling.
  3. PostgreSQL. Resource consumption settings.
  4. PostgreSQL. pg_stat_statements.
  5. PostgreSQL Global Development Group (2025). PostgreSQL 18 released.