向Odoo导入海量数据时的服务器超时问题
Odoo批量导入数据触发实时限制的解决方案
问题核心
从外部API获取73076条完整数据后,通过request.env[MODEL].sudo().create()仅能创建约18538条记录,剩余数据因Odoo触发**服务器虚拟实时限制(limit_time_real)**失败。调整Odoo内存/时间配置、PostgreSQL参数、拆分路由批次均未解决问题。
关键原因分析
create()方法会为每条记录触发完整的模型生命周期(字段计算、触发器、约束校验等),批量处理时资源占用累积过快,超出实时限制。- 拆分路由若未实现完全独立的请求/事务隔离,仍会在同一worker进程内累积内存占用,无法彻底规避限制。
- 未正确释放Odoo环境缓存、未及时提交事务,导致内存泄漏持续增加。
具体解决方案
1. 替换create()为load()批量导入(最优方案)
Odoo内置的BaseModel.load()方法专为批量导入设计,通过直接生成SQL插入语句、跳过部分模型生命周期逻辑,大幅降低资源占用与耗时:
@http.route('/import/batch-data', type='http', auth='user', methods=['POST']) def import_batch_data(self, **kwargs): # 从外部API获取完整数据列表 data_list = self._fetch_external_api_data() model = request.env['your.model.name'].sudo() # 定义字段映射(需与模型字段名完全匹配) fields = list(data_list[0].keys()) # 转换数据格式:二维数组,每个子数组对应一条记录的字段值 values = [list(item.values()) for item in data_list] # 执行批量导入 import_result = model.load(fields, values) # 处理导入结果 if import_result['ids']: return json.dumps({ 'status': 'success', 'created_count': len(import_result['ids']), 'failed_count': len(import_result['messages']) }) else: return json.dumps({ 'status': 'failed', 'errors': import_result['messages'] })
2. 优化批次处理逻辑(若需保留create())
若必须使用create(),需严格控制批次大小,并在每个批次后提交事务、清除环境缓存,彻底释放资源:
@http.route('/import/data-by-batch', type='http', auth='user', methods=['POST']) def import_data_by_batch(self, **kwargs): data_list = self._fetch_external_api_data() model = request.env['your.model.name'].sudo() batch_size = 1000 # 根据服务器配置调整,建议500-2000条/批次 total_count = len(data_list) created_count = 0 for i in range(0, total_count, batch_size): batch_data = data_list[i:i+batch_size] # 创建当前批次记录 model.create(batch_data) created_count += len(batch_data) # 提交事务并清除环境缓存,释放内存 request.env.cr.commit() request.env.clear() return json.dumps({ 'status': 'success', 'total_count': total_count, 'created_count': created_count })
3. 彻底隔离批次请求(拆分路由的正确姿势)
若采用多路由拆分,需确保每个批次为独立HTTP请求(而非同一请求内调用多个路由):
- 前端按批次分多次调用导入接口,每次传入批次起始/结束索引
- 后端接口仅处理当前批次数据,处理完成后立即释放资源
4. 调整Odoo与PostgreSQL核心配置
Odoo配置(odoo.conf)
# 增大实时超时时间(单位:秒,建议设为3600即1小时) limit_time_real = 3600 # 增大软/硬内存限制(根据服务器内存调整,如8G) limit_memory_soft = 8589934592 limit_memory_hard = 8589934592 # 增加worker数量(建议=2*CPU核心数+1) workers = 5 # 调整worker超时时间 limit_time_cpu = 600
PostgreSQL配置(postgresql.conf)
# 增大单操作内存限制(建议64MB) work_mem = 64MB # 增大维护操作内存(建议2GB) maintenance_work_mem = 2GB # 增大WAL日志大小,减少切换频率 max_wal_size = 16GB # 增大连接数(根据worker数量调整) max_connections = 100
5. 临时禁用模型冗余逻辑
若模型包含大量计算字段、触发器或约束,可临时禁用以降低导入开销:
@http.route('/import/data-with-disabled-logic', type='http', auth='user') def import_data_with_disabled_logic(self, **kwargs): model = request.env['your.model.name'].sudo() # 临时禁用计算字段方法 original_compute = model._compute_some_field model._patch_method('_compute_some_field', lambda self: None) # 临时移除特定约束 original_constraints = model._constraints model._constraints = [c for c in original_constraints if c[0] != '_check_some_constraint'] try: # 执行批量导入逻辑(参考方案1或2) data_list = self._fetch_external_api_data() # ... 导入代码 ... finally: # 恢复原逻辑 model._revert_method('_compute_some_field') model._constraints = original_constraints return json.dumps({'status': 'success'})
内容的提问来源于stack exchange,提问作者Andromeda
相关产品推荐
相关产品推荐

