Odoo 11 ORM按单ID查询生成where id in语句的性能问题优化咨询
一、结论:可以调整ORM的查询生成逻辑
Odoo 11 Enterprise的ORM查询构造逻辑支持自定义重写,可针对单条记录的场景将WHERE id IN [id]调整为WHERE id = id,但需先确认两个前提:
- 排除RDS层面的基础问题:多数PostgreSQL优化器会自动将单值IN条件等价转换为等值条件,若耗时异常先排查RDS参数、统计信息、索引缓存等问题,再修改ORM逻辑
- 评估修改风险:全局修改ORM核心逻辑可能影响批量操作、权限过滤等原生能力,优先推荐局部场景的低风险调整方案
二、具体调整方案
2.1 局部场景优化(低风险,推荐)
仅针对高频慢查询的特定业务场景调整,不修改全局ORM逻辑:
- 替代写法:单记录ORM操作时,使用等值domain的search方法替代直接browse的方式,避免ORM自动生成IN条件
- 原写法(生成
WHERE id IN ([id])):# 直接browse单条记录,触发IN条件生成 record = self.env['target.model'].browse(record_id) record.read(['field1', 'field2']) - 优化写法(生成
WHERE id = [id]):# 手动构造等值domain,ORM会生成等值条件 record = self.env['target.model'].search([('id', '=', record_id)], limit=1) record.read(['field1', 'field2'])
- 原写法(生成
- 原生SQL适配:对性能要求极高的单记录操作,可直接通过
env.cr执行手写原生SQL,完全绕过ORM的IN逻辑拼接
2.2 全局ORM逻辑重写(高风险,需充分测试)
若需全局所有单记录ORM操作都生成等值条件,可重写BaseModel的查询构造逻辑,示例参考(Odoo 11适用,兼容Python2/3):
- 新建自定义抽象模型继承
base,重写_fetch_query方法 - 判断当前Recordset长度为1时,替换查询语句中的id IN条件为等值条件
示例代码片段:
from odoo import models, api class BaseModelOrmExtend(models.AbstractModel): _inherit = 'base' @api.model def _fetch_query(self, query, field_names): # 仅处理单条记录的查询场景 if len(self._ids) == 1: table_name = self._table # 替换where子句中的IN条件为等值条件 query.where_clause = query.where_clause.replace( '"{}"."id" IN (%s)'.format(table_name), '"{}"."id" = %s'.format(table_name) ) return super()._fetch_query(query, field_names)
注意:上述代码为简化示例,需根据实际的where子句拼接格式调整,需在测试环境充分验证权限过滤、批量操作、多表关联查询等逻辑的兼容性,避免影响Enterprise模块的正常运行
三、AWS RDS场景额外优化建议
针对你的AWS部署架构,可搭配以下优化降低查询耗时:
- 检查RDS参数组:确保PostgreSQL的
enable_in_equals参数为开启状态,强制优化器自动转换单值IN为等值条件 - 定期更新统计信息:对高频查询的表定期执行
ANALYZE,确保优化器生成正确的执行计划 - 调整缓冲池配置:根据RDS实例规格合理设置
shared_buffers参数,确保id主键索引常驻内存,减少磁盘IO - 读写分离分流:若业务读多写少,可将单条查询类的读请求分流到RDS只读副本,降低主库的负载压力
内容的提问来源于stack exchange,提问作者Daim Sayed
相关产品推荐
相关产品推荐

