关于 sale.py 中 _amount_all 几天折腾的结果
-
在写个模块,是动态计算生成 sale_order 的 order_line 的,写好后没一时发现什么问题。
后来又完成了 从老系统 直接导入的功能后, 就导入了一个 1000 多行的订单 进行测试,
结果发现有严重的性能问题,计算过程长达几小时。
查了很久,一步步跟踪后,发现时间耗在
sale.py 中 _amount_all 中。
这是 amount_untaxed,amount_tax,amount_total 三个 function 字段的 计算函数。
原因是这样的。
我是逐行生成 sale.order.line 的,order_lines_id = order_lines_obj.create(cr, uid, order_lines_values, context=context)
OE 会在你每create 一行的时候,就调用 _amount_all,进行计算,这函数还要计算 税 等等 东西,耗时挺长,且随着 sale.order.line 行数的增多,性能急剧下降。这样 几个 循环一套, 造成了 计算几小时也不能完成的结果。
显然,理想的方式 是 当 create sale.order.line 的时候,不要立即 进行 _amount_all 的计算。
问题发到 群里 请教后,
给出了几种方案:
1. 我自己提出的暴力方案,添加一个 全局变量设置, 开始计算前,设置一下,然后在 _amount_all 判断状态,不要计算的话,直接返回
2. buke 提出的 @bzrcache ,对计算结果进行缓存,避免重复计算
3. 总监提出的 试试 不要 每行 create,试试在 sale.order 对象上面 write (0, 0,order_lines_values)这样的方式一次写入
显然,总监的方案 最吸引人了,尝试后发现,虽然语句上是在 sale.order 一次写入了,但是 实际上 OE 会对 每一个 (0, 0,order_lines_values)调用一次 sale.order.line 的create 的。我测试了两行, _amount_all 被调用了两次, 然后 我犯了最大的错误, 就是 想当然地以为 依旧是逐行调用 _amount_all , 跟现有状况无差别。于是 放弃。
于是,开始我自己 流氓方案,加了全局变量,这里就不多说了,总之,初步解决了问题,性能从几小时 提高到了二十几分钟。方案当然不太理想了,因为要直接 改 sale.py ,试着改成了模块,折腾了2天,决定这是 最后的解决方案。
下面又尝试了 buke 的,@bzrcache, python基础差,bzrcache 的代码虽不多,也没完全看懂和理解, 就是照着bzrerp 依样画葫芦抄了一遍。很不幸报错了,因为也要改 sale.py ,又没读懂,心里有点 抗拒这个方案了。
又回到 最早 总监的方案里,
前面测试说了, 插入 两行,调用了两次 _amount_all , 想当然地认为,插入n行 就是调用 n次。
结果这是个错误,进一步测试发现, 插入n次,调用 _amount_all 依旧是2次而已
这就是我要的结果 sale_order_obj.write(cr,uid,[order_id],{'order_line':order_lines,'sale_order_contract_details':contract_details},context)<br />
这里面的 order_lines 会比较大,我写到文件里看了一下, 订单大的时候(2000行)大约有10M。
这里面还有一个插曲,因为考虑到 多次计算的问题,第二次计算时,要求先清除上一次的结果,
原先我是调用 unlike 删除的,后面 觉得 既然 写入能用 (0, 0,order_lines_values),删除应该也用 (2,contract_details_id) ,结果再次进入噩梦中,OE 会为 每一个 (2,contract_details_id) 调用一次 unlike,并且还会逐个调用一次 _amount_all 。
好在 这时 我一看就知道问题了。
改回这样order_lines_obj.unlink(cr, uid, delete_order_lines_ids, context=None)<br />
并且 不是每行调用一次, 而是 先 把要删除的 id 全部合并到一个 list 中,最后 调用一次。
这算是我一次“优化”的过程吧,反反复复 有一周了,又学到不少东西
谢谢 buke、总监、jeff、joshua ,谢谢 cctv