Odoo インスタンスが遅いと、生産性が失われ、ユーザーがイライラするため、コストがかかります。良いニュース: Odoo のパフォーマンスの問題のほとんどは、ハードウェアをアップグレードしなくても解決できます。悪いニュース: 根本原因を診断するには、Python、PostgreSQL、Nginx、Redis、ネットワーク層といったスタック全体を理解する必要があります。
パフォーマンスとスケーラビリティシリーズの一部
完全ガイドを読むOdoo インスタンスが遅いと、生産性が失われ、ユーザーがイライラするため、コストがかかります。良いニュース: Odoo のパフォーマンスの問題のほとんどは、ハードウェアをアップグレードしなくても解決できます。悪いニュース: 根本原因を診断するには、Python、PostgreSQL、Nginx、Redis、ネットワーク層といったスタック全体を理解する必要があります。
このガイドでは、ボトルネックの特定、PostgreSQL のチューニング、Odoo サーバー設定の最適化、Nginx キャッシュの構成、ユーザー数とトランザクション量に合わせたインフラストラクチャの適切なサイジングなど、Odoo 19 Enterprise のパフォーマンス最適化ライフサイクル全体について説明します。
重要なポイント
- PostgreSQL のチューニングにより、最大のパフォーマンス向上が実現します (一般的なインストールでは 50 ~ 300%)。
- 共有バッファは開始点として利用可能な RAM の 25% に設定する必要があります
- Odoo の ORM は、pg_stat_statements でキャッチできる N+1 クエリを生成します
- 頻繁にフィルターされるフィールド (company_id、state、date) のインデックスは必須です
- Nginx プロキシ キャッシュは、Odoo サーバーにアクセスせずに静的アセットを提供します
- ワーカー構成は同時ユーザー容量に直接影響します
- Redis セッションのキャッシュにより、認証のためのデータベースの負荷が軽減されます
- バキュームと分析のスケジュールは、書き込み量の多い Odoo ワークロードに合わせて調整する必要があります
パフォーマンスのボトルネックを診断する
何かを調整する前に、実際に時間が費やされている部分を特定します。やみくもな最適化は労力を無駄にします。
Odoo クエリのログを有効にする:
# odoo.conf
[options]
log_level = info
logfile = /var/log/odoo/odoo.log
# For SQL query logging (development/staging only):
log_handler = odoo.sql_db:DEBUG
PostgreSQL の低速クエリのログを有効にする:
# /etc/postgresql/15/main/postgresql.conf
log_min_duration_statement = 1000 # Log queries taking > 1 second
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_connections = on
log_lock_waits = on
pg_stat_statements (最も価値のある PostgreSQL 拡張機能) をインストールします:
-- Enable the extension
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Find the top 20 slowest queries
SELECT
round(total_exec_time::numeric, 2) AS total_ms,
calls,
round(mean_exec_time::numeric, 2) AS mean_ms,
round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 2) AS pct,
left(query, 100) AS query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
-- Reset statistics after tuning to measure improvement
SELECT pg_stat_statements_reset();
Odoo で N+1 クエリを特定する:
Odoo がレコードのリストをロードし、レコードごとに 1 つのクエリを作成して関連データをフェッチすると、N+1 クエリが発生します。 pg_stat_statements で次のようなパターンを探します。
-- This query appearing 500 times in a single page load = N+1 problem
SELECT * FROM res_partner WHERE id = $1
修正するには、Odoo の prefetch_ids メカニズムを使用するか、ORM クエリに select を追加します。
# Bad: triggers N+1 for partner on each order
for order in orders:
print(order.partner_id.name) # One query per order
# Good: prefetch partner data in one query
orders = self.env['sale.order'].search([...])
orders.mapped('partner_id') # Forces prefetch
for order in orders:
print(order.partner_id.name) # No additional queries
PostgreSQL 構成のチューニング
PostgreSQL は、あらゆるハードウェアで実行できるように設計された保守的なデフォルトで出荷されます。 Odoo 運用サーバーの場合、これらのデフォルトを調整する必要があります。
メモリ設定 (32 GB RAM サーバーの場合):
# /etc/postgresql/15/main/postgresql.conf
# Shared buffers: 25% of RAM
shared_buffers = 8GB
# Work memory: per-operation memory for sorts/joins
# Start conservative, increase if you see disk sorts
work_mem = 64MB
# Maintenance work memory: for VACUUM, CREATE INDEX
maintenance_work_mem = 2GB
# Effective cache size: tells planner how much OS cache is available
# Set to 75% of total RAM
effective_cache_size = 24GB
# WAL settings for better write performance
wal_buffers = 256MB
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min
max_wal_size = 4GB
min_wal_size = 1GB
接続設定:
# Maximum connections (Odoo workers × 2 + headroom)
max_connections = 200
# For connection pooling with PgBouncer
# If using PgBouncer, reduce to 50-100
クエリ プランナーの設定:
# Enable parallel query execution
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
max_worker_processes = 16
# SSD storage: random_page_cost should equal seq_page_cost
random_page_cost = 1.1 # Default is 4.0 (for spinning disk)
seq_page_cost = 1.0
# Increase statistics target for better query plans on Odoo's large tables
default_statistics_target = 200
書き込み量の多いワークロード向けの自動バキューム チューニング:
Odoo のインベントリ、アカウンティング、およびメッセージング モジュールは、大量の INSERT/UPDATE トラフィックを生成します。デフォルトの自動バキューム設定では不十分です:
autovacuum = on
autovacuum_max_workers = 5
autovacuum_naptime = 30s
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
autovacuum_vacuum_scale_factor = 0.01 # Vacuum when 1% of rows are dead
autovacuum_analyze_scale_factor = 0.005 # Analyze when 0.5% of rows change
autovacuum_vacuum_cost_delay = 2ms # Reduce I/O throttling
重要なデータベースのインデックス
インデックスの欠落は、不適切な構成に次いで Odoo のパフォーマンスの問題の 2 番目に多い原因です。 Odoo は主キーと一部の外部キーのインデックスを作成しますが、一般的にフィルターされるフィールドの多くにはインデックスがありません。
pg_missing_fk_indexes ビューを使用して、欠落しているインデックスを確認します。
-- Find foreign keys without indexes
SELECT
tc.table_name,
kcu.column_name,
ccu.table_name AS foreign_table_name,
pg_relation_size(tc.table_name::regclass) AS table_size
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu
ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY'
AND NOT EXISTS (
SELECT 1 FROM pg_indexes pi
WHERE pi.tablename = tc.table_name
AND pi.indexdef LIKE '%' || kcu.column_name || '%'
)
ORDER BY table_size DESC;
Odoo 19 の必須インデックス:
-- Sale orders (most queried table)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_state
ON sale_order(state);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_company_date
ON sale_order(company_id, date_order DESC);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sale_order_partner
ON sale_order(partner_id) WHERE state != 'cancel';
-- Account moves (invoicing)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_state_type
ON account_move(state, move_type);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_company_date
ON account_move(company_id, invoice_date DESC);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_partner
ON account_move(partner_id) WHERE state = 'posted';
-- Account move lines (most queried for reconciliation)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_line_account_reconcile
ON account_move_line(account_id, reconciled, date);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_account_move_line_move_date
ON account_move_line(move_id, date);
-- Stock moves (inventory)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_stock_move_state_product
ON stock_move(state, product_id);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_stock_quant_product_location
ON stock_quant(product_id, location_id);
-- Mail messages (can grow very large)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_mail_message_res_model_id
ON mail_message(res_model, res_id);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_mail_message_date
ON mail_message(date DESC);
-- IR rule performance (access control)
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_ir_rule_model_groups
ON ir_rule(model_id);
Odoo ワーカーの構成
Odoo ワーカーの数によって、サーバーが処理できる同時リクエストの数が決まります。
ワーカー数の計算式:
Workers = (CPU_cores × 2) + 1
Memory per worker: 256MB - 512MB depending on workload
Example for 8 CPU cores, 32GB RAM:
Workers = (8 × 2) + 1 = 17
Memory check: 17 × 512MB = 8.5GB (well within 32GB)
odoo.conf ワーカー設定:
[options]
# Worker processes
workers = 17
# Limits to prevent runaway workers
limit_memory_hard = 2684354560 # 2.5GB hard limit (kills worker)
limit_memory_soft = 2147483648 # 2GB soft limit (triggers gc)
limit_time_cpu = 600 # CPU seconds per request
limit_time_real = 1200 # Wall clock seconds per request
limit_request = 8192 # Requests before worker restart
# Long polling (for live notifications)
longpolling_port = 8072
ワーカーのタイプを理解する:
Odoo は 2 種類のワーカーを使用します。
- HTTP ワーカー (
workers構成): すべての Web リクエストを処理します - Cron ワーカー (1 予約): スケジュールされたアクションをバックグラウンドで実行します
cron ワーカーは常に実行されていますが、HTTP 容量にはカウントされません。ピーク負荷時でも少なくとも 1 つの cron ワーカーが利用可能であることを確認してください。
パフォーマンスのための Nginx 構成
Nginx は Odoo の前に位置し、TLS 終端、静的ファイルの提供、およびオプションでキャッシュを処理します。
高性能 Nginx 構成:
upstream odoo {
server 127.0.0.1:8069 weight=1 fail_timeout=0;
}
upstream odoochat {
server 127.0.0.1:8072 weight=1 fail_timeout=0;
}
# Cache zone for static assets
proxy_cache_path /var/cache/nginx/odoo
levels=1:2
keys_zone=odoo_cache:100m
max_size=1g
inactive=60m
use_temp_path=off;
server {
listen 443 ssl http2;
server_name your-odoo.com;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
gzip_comp_level 6;
# Static file caching
location /web/static/ {
proxy_cache odoo_cache;
proxy_cache_valid 200 7d;
proxy_cache_use_stale error timeout updating
http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status;
expires 7d;
proxy_pass http://odoo;
}
# Long polling for live chat/notifications
location /web/longpolling {
proxy_pass http://odoochat;
proxy_read_timeout 3600s;
proxy_connect_timeout 300s;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Main application
location / {
proxy_pass http://odoo;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 720s;
proxy_connect_timeout 300s;
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy strict-origin-when-cross-origin;
}
}
セッションとキャッシュ用の Redis
Redis は、セッション管理と Odoo の ORM キャッシュのデータベース負荷を大幅に軽減します。
Redis をインストールして構成します:
# Install Redis
sudo apt install redis-server
# Configure Redis for Odoo (max 4GB memory, LRU eviction)
sudo nano /etc/redis/redis.conf
# redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru
save "" # Disable persistence for pure cache
tcp-keepalive 300
Redis を使用するように Odoo を構成します:
# odoo.conf
[options]
# Redis for session storage
session_redis_host = 127.0.0.1
session_redis_port = 6379
session_redis_prefix = odoo_session_
# Redis for IR rules and ORM cache
cache_redis_host = 127.0.0.1
cache_redis_port = 6379
モニタリングと継続的なパフォーマンス管理
PostgreSQL ログ分析用に pgBadger をセットアップします:
# Install pgBadger
sudo apt install pgbadger
# Generate report from PostgreSQL logs
pgbadger /var/log/postgresql/postgresql-15-main.log \
-o /var/www/html/pgbadger/index.html \
--format html \
--top 20
監視すべき主要な指標:
| メトリック | 警告しきい値 | クリティカルしきい値 |
|---|---|---|
| ページの読み込み時間 | > 2 秒 | > 5 秒 |
| DB クエリ時間 | > 100ms 平均 | 平均 500 ミリ秒以上 |
| 労働者の記憶 | > 制限の 80% | > 制限の 95% |
| PostgreSQL 接続 | > 最大値の 70% | > 最大値の 90% |
| ディスク IOPS | > プロビジョニング済みの 80% | > プロビジョニング済みの 95% |
| キャッシュ ヒット率 | < 95% | < 90% |
よくある質問
50 人の同時 Odoo ユーザーに対する最小サーバー仕様はどれくらいですか?
中程度のトランザクション量を持つ 50 人の同時ユーザーの場合: 8 vCPU、32 GB RAM、500 GB SSD (NVMe を推奨)。 Odoo の PostgreSQL データベースは主な I/O ボトルネックであるため、CPU 速度よりも高速ストレージが重要です。 13 ワーカー (ヘッドルーム用に 8×2 ~ 3)、8 GB のshared_buffers を構成し、データベースが SSD ボリューム上にあることを確認します。
Odoo の遅さが Python によるものか PostgreSQL によるものかを診断するにはどうすればよいですか?
Odoo の組み込みプロファイラー (開発者モードでは [設定] → [テクニカル] → [パフォーマンス] → [プロファイラー]) を使用して、遅い操作を記録します。フレームグラフには、時間が Python コードに費やされているか、SQL 結果の待機に費やされているかが表示されます。 SQL クエリが大半を占める場合は、PostgreSQL のチューニングとインデックスに焦点を当てます。 Python が優勢な場合は、欠落している @api.depends キャッシュやカスタム コードの非効率性を探します。
接続プーリングには PgBouncer を使用する必要がありますか?
はい、30 を超える Odoo ワーカーまたは大量の API トラフィックを含むデプロイメントの場合。トランザクション モード プーリングの PgBouncer により、多くの Odoo ワーカーが実際の PostgreSQL 接続のより小さなプールを共有できるようになり、接続ごとのオーバーヘッドが削減されます。 PgBouncer を使用する場合は、PostgreSQL の max_connections を 50 ~ 100 に設定し、PgBouncer の pool_size を Odoo ワーカー数と一致するように設定します。
Odoo データベースで VACUUM ANALYZE を実行する頻度はどれくらいですか?
Autovacuum が正しく設定されていれば、これを自動的に処理します。上記のチューニング (積極的なスケール係数、より多くのワーカー) の後、自動バキュームはアクティブなテーブルで継続的に実行されるはずです。 SELECT schemaname, tablename, last_vacuum, last_autovacuum, last_analyze, last_autoanalyze FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20; を実行して、テーブルが頻繁にバキューム処理されていることを確認します。
Odoo ワーカーが多すぎるとどのような影響がありますか?
各 Odoo ワーカーは最低 256 ~ 512 MB の RAM を消費します。ワーカーが多すぎるとメモリが枯渇し、ワーカーがクラッシュし (limit_memory_hard)、ユーザーに HTTP 500 エラーが発生します。さらに、PostgreSQL 接続 (ワーカー × max_db_connections) が多すぎると、データベースが過負荷になる可能性があります。式 (CPU×2+1) から始めて、負荷がかかっているメモリを監視し、必要に応じて下方調整します。
次のステップ
Odoo のパフォーマンス チューニングは反復的なプロセスです。 1 回のチューニング セッションで大幅な向上が得られますが、パフォーマンスを維持するには、継続的なモニタリング、定期的なインデックス分析、データ量の増加に伴う構成の調整が必要です。
ECOSIRE は、エンタープライズ展開向けの Odoo パフォーマンス監査を提供し、特定のワークロード、トランザクション パターン、およびインフラストラクチャに最も大きな影響を与える最適化を特定します。当社のエンジニアは、10 ユーザーの中小企業から 500 ユーザーの企業展開まで Odoo インストールを調整しました。
ECOSIRE に Odoo パフォーマンス監査をリクエスト →
現在のサーバー仕様、ユーザー数、発生している症状を共有していただければ、当社のチームが根本原因を特定し、優先順位の高い最適化計画を提供します。
執筆者
ECOSIRE Research and Development Teamテクニカルライティング
ECOSIRE のテクニカルライティングチームは、Odoo ERP、Shopify による EC、AI エージェント、Power BI による分析、GoHighLevel による自動化、そしてエンタープライズソフトウェアのベストプラクティスを扱っています。私たちのガイドは、企業が十分な情報に基づいてテクノロジーを判断できるよう支援します。
関連記事
AI を活用した顧客セグメンテーション: RFM から予測クラスタリングまで
AI が顧客セグメンテーションを静的な RFM 分析から動的な予測クラスタリングにどのように変換するかを学びます。 Python、Odoo、および実際の ROI データを使用した実装ガイド。
サプライチェーン最適化のための AI: 可視性、予測、自動化
AI を使用してサプライ チェーンの運用を変革します。需要の検知、サプライヤーのリスク スコアリング、ルートの最適化、倉庫の自動化、混乱の予測などです。 2026年のガイド。
B2B卸売Eコマースガイド:バイヤーポータル・掛け払い・顧客別価格
バイヤーが実際に使うB2B卸売ポータルの作り方:顧客別価格、掛け払いと与信限度、発注書と承認付きチェックアウト、注文履歴からの再注文。
パフォーマンスとスケーラビリティのその他の記事
Webhook のデバッグと監視: 完全なトラブルシューティング ガイド
障害パターン、デバッグ ツール、再試行戦略、監視ダッシュボード、セキュリティのベスト プラクティスを網羅したこの完全なガイドを利用して、Webhook デバッグをマスターしてください。
k6 負荷テスト: 起動前に API のストレス テストを行う
Node.js API の k6 負荷テストをマスターします。仮想ユーザーの増加、しきい値、シナリオ、HTTP/2、WebSocket テスト、Grafana ダッシュボード、CI 統合パターンをカバーします。
Nginx 実稼働構成: SSL、キャッシュ、およびセキュリティ
Nginx 実稼働構成ガイド: SSL 終端、HTTP/2、キャッシュヘッダー、セキュリティヘッダー、レート制限、リバースプロキシセットアップ、Cloudflare 統合パターン。
本番環境での AI エージェントのテストと監視
実稼働環境で AI エージェントをテストおよび監視するための完全なガイド。 OpenClaw 導入の評価フレームワーク、可観測性、ドリフト検出、インシデント対応について説明します。
OpenClaw を使用したコンプライアンス監視エージェント
継続的なコンプライアンス監視のために OpenClaw AI エージェントを導入します。規制チェック、ポリシーの適用、監査証跡の生成、コンプライアンスレポートを自動化します。
AI エージェントのコストの最適化: トークンの使用とキャッシュ
トークンの最適化、キャッシュ、モデルのルーティング、使用状況の監視を通じて AI エージェントの運用コストを削減するための実践的な戦略。本番環境の OpenClaw 導入による実質的な節約。