先说结论
Odoo 一直鼓励你用 recordset 和批量思维写代码,不是为了代码看起来“更 Odoo”,而是因为 ORM 的性能机制本来就是围绕批量优化设计的。
这背后最关键的两个概念通常就是:
- recordset
- prefetch
你只要理解它们,很多“为什么官方源码老不按单条写”的问题就通了。
为什么新手总喜欢按单条记录思维写
因为这最符合直觉。
很多人自然会写成:
- 拿一条记录
- 查一点字段
- 处理一下
- 再拿下一条
这在少量数据时看起来没问题。
但一旦数据量上来,这种写法很容易变成:
- 查询很多次
- 重复读很多字段
- 循环里不断触发 ORM 开销
最后你会感觉 Odoo 很慢,实际上很多时候是写法把 ORM 的批量优势浪费掉了。
recordset 为什么这么核心
因为 Odoo 的很多 API 天然就是按“一批记录”来思考的,而不是按“当前这一条”来思考。
这意味着:
self经常本来就可能是多条- 你可以对整批记录一起过滤、映射、写入
- ORM 也更容易在这个层面做优化
所以 recordset 不是“好像有点高级的集合对象”,它是 Odoo 代码风格的基本单位。
prefetch 本质上在帮你做什么
最通俗地说,prefetch 在做的是:
既然你已经在处理这批记录了,那相关字段我尽量一起读,别你每碰一次都单独查。
这就是为什么批量拿记录、再按字段访问时,性能通常会比你一条条零碎处理更稳。
因为 ORM 会尽量把“这批记录大概率会用到的数据”提前组织得更高效。
为什么循环里乱访问关系字段特别容易慢
因为每次你在循环里继续追关联对象、再拿关联字段,如果写法不稳,就很容易不断触发额外查询。
典型现象是:
- 外层循环产品
- 内层去读供应商
- 再去读公司
- 再去读分类
逻辑上很顺,性能上却可能层层放大。
所以 Odoo 性能优化里,一个特别重要的习惯就是:
先用批量思维把要用的数据范围组织好,再做业务处理。
为什么官方源码经常喜欢“先收集、再统一处理”
因为这样更符合 ORM 优势。
你会经常看到类似套路:
- 先筛出一批记录
- 先 map 出一批关联对象
- 先 regroup / 分组
- 再统一 create / write / confirm
这不是写法绕,而是因为一旦流程走到批量层,ORM、缓存和数据库都更容易协同优化。
什么叫“不要总按单条记录思维写”
不是说单条永远不行。
而是说你应该先问自己:
- 这段逻辑是不是本来就面对一批记录
- 我是不是在循环里重复做相同查询
- 我能不能先把相关数据批量拿出来
- 我能不能把 write / create 合并成批操作
只要这些问题开始出现,说明你已经该从“单条脑回路”切到“recordset 脑回路”了。
实战里最容易踩的 5 个坑
1. 方法天然支持多记录,却默认按一条写
很容易丢掉批量优势。
2. 循环里频繁 search / browse / 追关系
性能最容易炸在这里。
3. 可以一次 write,却拆成很多次写
数据库和 ORM 开销都会放大。
4. 不理解 prefetch,就误以为“访问字段很便宜”
字段访问不是总无成本的。
5. 只在小数据量下测试
上线后才暴露慢的问题。
一句话记忆法
把这套机制记成一句话:
recordset 是 Odoo 处理业务对象的基本批量单位,prefetch 是 ORM 为这批对象提前组织数据的性能机制,所以很多代码都应该先按“整批记录”思考,而不是一条条硬循环。
理解这一句,很多 Odoo ORM 性能问题都会顺很多。
DISCUSSION
评论区