Odoo中文社区可以通过以下两个域名访问:shine-it.net , odoo.net.cn

由于系统升迁的原因,本论坛部分较早期的内容存在格式和链接损坏失效的问题,并非本论坛系统本身的缺陷,望谅解

本社区没有维护任何QQ群讨论组,任何与本社区同名的QQ群讨论组的言论与本社区无关!

开发人员可以登录gitter讨论组: http://gitter.im/odoo-china/Talk, 需要github账号

如果您登录系统碰到问题,请在微信公众号留言:

关于 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次而已


    这就是我要的结果

    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sale_order_obj.write(cr,uid,[order_id],{&#039;order_line&#039;:order_lines,&#039;sale_order_contract_details&#039;: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



  • 嗯. 那就是删除 与添加分开做 就OK了.

    删除也是将 [(2, ID1), (2,ID2)....] 组合后 write 一次? 然后  添加是 [(0,0,{...}),(0,0,{...}),...] 这样组合后 write 一次吧?



  • 删除也是将 [(2, ID1), (2,ID2)....] 组合后 write 一次?~

    ~~~~~~~~ 删除这样做以后,反而真正变成了, 一个个  删除
    要把 id1,id2 组合成 ids 然后 调用 unlike,

    而添加则反之, 要 [(0,0,{...}),(0,0,{...}),...] 这样组合后 write 一次



  • 总监威武,ccdos进步神速,buke奇招迭出,我看看热闹,少看cctv多向诸位学习!


Log in to reply