暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Odoo中的性能优化思路2

Odoo哥 2021-11-15
1464

上一篇文章(Odoo中的性能优化思路)讲到了性能优化中关于静态资源的部分,今天我们继续来看看关于业务处理逻辑代码的优化。

在Odoo的环境中,业务代码的执行环境有三种:

  1. JS代码在浏览器环境执行;

  2. Python代码在odoo Server环境执行;

  3. SQL代码在PostgreSQL环境执行。

不同的环境下使用的程序语言不一样,所以各个优化的思路也不尽相同。关于JS代码,我们自己开发的业务中,并不会涉及很多。就算是需要对Odoo的界面风格进行一些增强,一般我们也大多使用第三方的js库,这部分的代码性能主要是由odoo官方和第三方的js库维护方进行掌控。我们大致只要知道js的效率提升主要有几点:

  • 代码符合JS体系标准;

  • 使用异步请求;

  • 减少DOM操作,避免频繁的HTML渲染。

最新的OWL前端框架就是大量采用了异步的处理机制,并加入了虚拟DOM的概念,所以我们在Odoo14以后明显感到前端的处理速度有提升。


在讲PG优化之前,我们再插入一个小话题。目前在Odoo应用中,有些是把Odoo和PG安装在同一台主机,有些是分开安装在不同的主机。这里有一个问题需要了解,如果odoo与PG在同一台主机上,则odoo连接数据库使用的是进程间通信协议,如果在不同的主机,则odoo连接数据库使用的是TCP/IP协议。所以在连接成本开销上,在同一台主机上会更快一些。如果企业硬件够好,连接数还允许的话,建议可以放在同一台主机。只是要做好灾难还原机制就好。如果是分开不同主机的情况,那odoo主机和PG主机要在同一个局域网内,通过内网ip来连接。个人不建议外网IP和域名连接PG数据库。


三、PG配置优化

在数据库端,我们需关注的是参数配置,因为默认安装好PG以后,相关的参数配置并不是最优的。我们需要根据当前主机的内存、CPU做调整,这个没有统一的标准参数。大致需要关注是:

  • 设置共享缓存大小、进程排序内存大小,提高SQL查询的命中率;

  • 设置SQL超时预警,找出耗时的SQL语法;

  • 更新PG统计数据,确保正确的SQL执行计划;

  • 定期清理、回收废旧的数据空间;

  • 数据异动时,尽快提交,避免长时间的等待锁;

  • 有条件的采用高性能的硬盘,提高IO吞吐量。

因为在Odoo中,都是通过ORM来与PG通信,一般开发人员比较少接触数据库底层的东西,但一些概念我们还是要有所了解。

  1. 数据库的性能瓶颈在IO上,如果大部分的数据在缓存中,则可以提高查询速度;

  2. SQL语句会由PG进行分析,找到一个最优的执行计划,再根据计划来查询数据,这个执行计划是根据数据库的统计信息自动得出的,所以PG中的统计信息很重要,当然这个你不能改变,只要即时更新就行;

  3. INDEX不是越多越好,太多的索引会增加Create、Update、Delete的成本,占用更多的存储空间,或者会引起错误的执行计划;

  4. 使用INDEX的字段值尽量不重复,如果某字段(如性别)大部分是重复值,则常规的INDEX意义不大;

  5. 不是所有的条件式都能使用索引,一般只有'='、'>'、'<'才会走索引的执行计划;

  6. PG中的INDEX类型有很多种,Odoo的ORM只是使用了常规单列的一种(btree),其它类型需要我们自己手工来创建;

  7. PG数据块只有APPEND方式,所有修改、删除的记录,只做标识,PG不会回收已经占用的文件数据块,频繁有数据异动的Table需要定期回收缩表,否则严重影响执行速度;

  8. 开发报表业务时, 一般由开发人员写SQL生成视图,SQL的写法很重要,虽然条条大道通罗马,但一天到罗马和一年到罗马还是有区别的,如果数据实时性没那么高,可以尝试使用物化视图。


四、Odoo代码优化
这个部分主要就是我们开发的python代码,关于odoo代码的性能分析,可以参考之前的文章<分析odoo代码性能>,找出了性能瓶颈才能有针对性的进行优化。

首先在定义字段的时候,可以通过增加index属性,来建立某字段的索引,如果想对多个字段建立一个多列INDEX,则可以参考如下语法:

这个多列索引的字段顺序有一定的讲究,像上图这个三个字段的索引,只有SQL条件中包含有user_id或user_id、team_id或者user_id、team_id、type时才会使用,如果条件中只有team_id或team_id、type,则不会使用该索引。

Odoo除了数据模型定义需要注意以外,剩下的主要就是我们自己写的业务代码了,这部分代码的执行效率也直接影响用户操作界面时的加载速度。

在这里再插入一个小话题,因为在odoo中可以设置记录级的权限,所以也有很多地方通过这个功能来处理一些业务,但是!这个记录级的权限计算生成的SQL非常耗时,尤其是设置的domain条件比较复杂(child_of)的时候,你去追踪后台实际的SQL语法,where条件长得吓人。所以我们一是通过其它设计方法来避免复杂的记录级权限设置,二是在业务代码中,无关权限的时候,尽量在search、write前面加个sudo(),用管理员身份跳过权限部分的计算。

最后,我们再说几点python代码书写时的注意事项:

  1. 在自定义业务方法的时候,尽量保持self是一个结果集,不要只处理单条记录;

  2. 如果是需要重复使用某个方法的返回值,则可以用tools.ormcache方法装饰;

  3. 在一个循环中,不要放跟循环变量无关的代码;

  4. 尽量少用for循环,可以用列表的[x for x in [1,2]]格式;

  5. 结果集批次操作时,可以使用filtered、mapped内置方法;

  6. python的成员符'.'在读取属性时需要遍历对象的字典查找,所以避免在循环中大量使用;

  7. 对于不需要反馈结果的方法,可以采用线程在后台处理。


五、终极大法

如果真的是业务量大,用户数量多,则就要考虑采用集群的方式了。集群的话一般通过nginx进行负载均衡,后面跟多台odoo服务器,可以连一个PG数据库,也可以采用PG数据库集群。


上面主要是我个人理解的关于优化的思路,并没有提供太多的具体操作,一是因为具体方法需要针对个案进行具体分析,二是每一个优化主题都差不多可以写一本书了,细节太多,一下子搞不完,大家只要确定好方向了,再找找资料也是基本可以解决的。

文章转载自Odoo哥,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论