Overall performance issue of BaseModel.fields_view_get - binary fields should not be prefetched
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Odoo Server (MOVED TO GITHUB) |
Fix Released
|
Low
|
OpenERP Publisher's Warranty Team |
Bug Description
This bug is expressed by a general slowdown of the web client through all the
application. Display any view may take several seconds.
It does not happen on all the users. Some are afflicted, some are not. More
weirdly, this happens in our production database, but not on the replication I
did on my machine.
According to my analysis, I guess that it happens only when report_webkit is
installed (however a similar issue could probably happen without)
Example of the issue:
- I connect with lmaurer
- I click on Sales > Customers
- It takes 8 seconds to display the list
See the attached screenshot.
Most of the times is spent on the fields_view_get of the tree view (I attached
the request and the response). fields_view_get is called 2 times (is it normal
BTW?) and each times it takes ~3.10 seconds to achieve.
I dived deep in the code to find out what actually happens.
I will try to summarize that below.
Finding from where comes the slowness:
=======
-> BaseModel.
Most of the time is spent when it builds the toolbar, precisely at the line
2274 when it gets the print actions:
resprint = ir_values_
-> ir_values.get()
Forward to ir_values.
-> ir_values.
Most of the time is spent when it reads the action at line 404:
action_def = self.pool.
Here, `fields` contains all the columns of the action, excepted a list of
fields which are blacklisted in
openerp.
It appears that the field `webkit_header` is in the list of the fields to read,
but is not filtered out. This is a fields.property and it takes nearly 1.5
seconds to compute. (as we have few actions, it is multiplied by the number of
actions).
An easy fix would be to add this field in the `EXCLUDED_FIELDS` list,
but that's only a part of the solution, it would mask the root cause.
The real problem is the read on ir_actions_
1.5 seconds to achieve.
Finding why the read of the fields.property is so slow:
=======
Note that I was now able to know that the slowness does not comes from the
client nor from fields_view_get (directly). Just by doing a
ir_actions_
`webkit_header`, I'm able to reproduce the issue, it takes between 1.5 to 3
seconds to compute.
So I dived more deeply in the call stack
-> fields.
Most of the time here is spent when it gets the property, at line 1447:
value = prop.get(cr, uid, prop_name, obj._name, res_id=
-> ir_property.get()
Most of the time is spent when it builds the search domain at line 159:
domain = self._get_
-> ir_property.
Most of the time is spent when it gets the default company at line 185:
cid = company.
-> res_company.
Here is an extract of this method:
user = self.pool.
for rule in proxy.browse(cr, uid, ids, context):
if eval(rule.
return rule.company_
return user.company_id.id
It appears that the returned value is the thing which consumes all that time.
It takes ~0.7s, but seems to be called a couple of time.
I replaced it by a read like that:
user_obj = self.pool.
user = user_obj.browse(cr, SUPERUSER_ID, uid, context=context)
for rule in proxy.browse(cr, uid, ids, context):
if eval(rule.
return rule.company_
return user_obj.read(cr, SUPERUSER_ID,
And it was fast again.
I did not dived more deeply to see why the browse of the company take as much
time because I was running out of time. Could it be related to function fields
or _inherits? I cannot explain neither why it happens on a server and not on
another. I cannot figure out neither why for some users that's really slower
than others (the same fields_view_get on my user takes ~500 ms, lmaurer 3s,
some users 80ms).
I didn't check if the search_read which lasts 1.17 seconds is normal, but it
seems less shocking as it returns all the data of the records, including the
function fields.
Conclusion
==========
* I think that `webkit_header` should be added to openerp.
when the report_webkit addon is installed because it is probably not necessary to compute it, however
that's not a fix for the root cause.
* I think that we should replace the browse by a read in res_company.
it takes way too much time. Alternatively this method could be cached but I could be a problem
if the context is necessary.
* I think that further analysis should be done on the browse because it seems not normal to me that
user.
b
Related branches
- Guewen Baconnier @ Camptocamp (community): Approve
- Naresh(OpenERP): Pending requested
-
Diff: 24 lines (+3/-2)1 file modifiedopenerp/addons/base/res/res_company.py (+3/-2)
- OpenERP Core Team: Pending requested
-
Diff: 525549 lines (+338109/-2276) (has conflicts)150 files modifieddebian/changelog (+9/-0)
debian/po/ar.po (+41/-0)
debian/po/bg.po.OTHER (+42/-0)
debian/po/ca.po.OTHER (+43/-0)
debian/po/cs.po.OTHER (+41/-0)
debian/po/da.po (+42/-0)
debian/po/de.po.OTHER (+42/-0)
debian/po/el.po.OTHER (+42/-0)
debian/po/en_GB.po.OTHER (+42/-0)
debian/po/es.po.OTHER (+43/-0)
debian/po/es_CL.po.OTHER (+42/-0)
debian/po/es_EC.po.OTHER (+42/-0)
debian/po/fa.po.OTHER (+41/-0)
debian/po/fi.po.OTHER (+41/-0)
debian/po/fr.po.OTHER (+41/-0)
debian/po/gl.po.OTHER (+41/-0)
debian/po/he.po.OTHER (+39/-0)
debian/po/hr.po.OTHER (+42/-0)
debian/po/hu.po.OTHER (+42/-0)
debian/po/is.po (+41/-0)
debian/po/it.po.OTHER (+41/-0)
debian/po/ja.po.OTHER (+39/-0)
debian/po/ko.po.OTHER (+40/-0)
debian/po/lv.po.OTHER (+39/-0)
debian/po/mk.po (+42/-0)
debian/po/mn.po.OTHER (+41/-0)
debian/po/nb.po.OTHER (+41/-0)
debian/po/nl.po.OTHER (+42/-0)
debian/po/pl.po.OTHER (+41/-0)
debian/po/pt.po.OTHER (+41/-0)
debian/po/pt_BR.po.OTHER (+42/-0)
debian/po/ro.po.OTHER (+41/-0)
debian/po/ru.po.OTHER (+42/-0)
debian/po/sk.po.OTHER (+42/-0)
debian/po/sl.po (+41/-0)
debian/po/sq.po.OTHER (+42/-0)
debian/po/sr.po.OTHER (+41/-0)
debian/po/sv.po.OTHER (+41/-0)
debian/po/tr.po.OTHER (+41/-0)
debian/po/uk.po.OTHER (+42/-0)
debian/po/vi.po.OTHER (+42/-0)
debian/po/zh_CN.po.OTHER (+38/-0)
debian/po/zh_TW.po.OTHER (+40/-0)
history/Changelog (+619/-0)
openerp/addons/base/base_data.xml (+626/-0)
openerp/addons/base/i18n/ab.po (+9239/-0)
openerp/addons/base/i18n/af.po (+1614/-21)
openerp/addons/base/i18n/am.po (+1705/-20)
openerp/addons/base/i18n/ar.po (+5333/-88)
openerp/addons/base/i18n/bg.po (+1583/-18)
openerp/addons/base/i18n/bn.po (+9239/-0)
openerp/addons/base/i18n/bs.po (+4580/-91)
openerp/addons/base/i18n/ca.po (+1635/-18)
openerp/addons/base/i18n/cs.po (+3166/-40)
openerp/addons/base/i18n/da.po (+3006/-47)
openerp/addons/base/i18n/de.po (+3215/-49)
openerp/addons/base/i18n/el.po (+1565/-18)
openerp/addons/base/i18n/en_GB.po (+2725/-30)
openerp/addons/base/i18n/es.po (+1776/-19)
openerp/addons/base/i18n/es_AR.po (+6236/-119)
openerp/addons/base/i18n/es_BO.po (+9239/-0)
openerp/addons/base/i18n/es_CL.po (+2062/-27)
openerp/addons/base/i18n/es_CR.po (+9597/-0)
openerp/addons/base/i18n/es_DO.po (+9487/-0)
openerp/addons/base/i18n/es_EC.po (+1678/-18)
openerp/addons/base/i18n/es_HN.po (+9295/-0)
openerp/addons/base/i18n/es_MX.po (+9246/-0)
openerp/addons/base/i18n/es_PA.po (+9295/-0)
openerp/addons/base/i18n/es_PE.po (+9239/-0)
openerp/addons/base/i18n/es_VE.po (+9251/-0)
openerp/addons/base/i18n/et.po (+2156/-29)
openerp/addons/base/i18n/eu.po (+1550/-18)
openerp/addons/base/i18n/fa.po (+3255/-65)
openerp/addons/base/i18n/fa_AF.po (+1550/-18)
openerp/addons/base/i18n/fi.po (+2186/-28)
openerp/addons/base/i18n/fr.po (+2078/-26)
openerp/addons/base/i18n/fr_CA.po (+9248/-0)
openerp/addons/base/i18n/gl.po (+2583/-37)
openerp/addons/base/i18n/gu.po (+9292/-0)
openerp/addons/base/i18n/he.po (+2211/-32)
openerp/addons/base/i18n/hi.po (+9239/-0)
openerp/addons/base/i18n/hr.po (+1946/-23)
openerp/addons/base/i18n/hu.po (+4826/-40)
openerp/addons/base/i18n/hy.po (+2685/-33)
openerp/addons/base/i18n/id.po (+1624/-20)
openerp/addons/base/i18n/is.po (+2573/-28)
openerp/addons/base/i18n/it.po (+1692/-22)
openerp/addons/base/i18n/ja.po (+5598/-101)
openerp/addons/base/i18n/ka.po (+9505/-0)
openerp/addons/base/i18n/kab.po (+9300/-0)
openerp/addons/base/i18n/kk.po (+9239/-0)
openerp/addons/base/i18n/ko.po (+5358/-98)
openerp/addons/base/i18n/lt.po (+2721/-47)
openerp/addons/base/i18n/lv.po (+2192/-30)
openerp/addons/base/i18n/mk.po (+4789/-83)
openerp/addons/base/i18n/mn.po (+2681/-38)
openerp/addons/base/i18n/nb.po (+1869/-9)
openerp/addons/base/i18n/nl.po (+2324/-30)
openerp/addons/base/i18n/nl_BE.po (+1554/-18)
openerp/addons/base/i18n/pl.po (+3247/-37)
openerp/addons/base/i18n/pt.po (+4373/-74)
openerp/addons/base/i18n/pt_BR.po (+2728/-33)
openerp/addons/base/i18n/ro.po (+5276/-71)
openerp/addons/base/i18n/ru.po (+1699/-18)
openerp/addons/base/i18n/sk.po (+1599/-18)
openerp/addons/base/i18n/sl.po (+4980/-100)
openerp/addons/base/i18n/sq.po (+1550/-18)
openerp/addons/base/i18n/sr.po (+1570/-18)
openerp/addons/base/i18n/sr@latin.po (+5821/-114)
openerp/addons/base/i18n/sv.po (+1908/-25)
openerp/addons/base/i18n/ta.po (+9295/-0)
openerp/addons/base/i18n/th.po (+3948/-67)
openerp/addons/base/i18n/tlh.po (+2209/-19)
openerp/addons/base/i18n/tr.po (+2519/-35)
openerp/addons/base/i18n/uk.po (+1630/-21)
openerp/addons/base/i18n/ur.po.OTHER (+9239/-0)
openerp/addons/base/i18n/vi.po (+2458/-43)
openerp/addons/base/i18n/zh_CN.po (+1903/-22)
openerp/addons/base/i18n/zh_HK.po (+9239/-0)
openerp/addons/base/i18n/zh_TW.po (+2239/-25)
openerp/addons/base/ir/ir_actions.py (+5/-0)
openerp/addons/base/ir/ir_filters.py (+7/-0)
openerp/addons/base/ir/ir_model.py (+17/-0)
openerp/addons/base/ir/ir_rule.py (+18/-0)
openerp/addons/base/ir/ir_values.py (+136/-0)
openerp/addons/base/publisher_warranty/publisher_warranty.py.OTHER (+362/-0)
openerp/addons/base/report/corporate_sxw_header.xml (+20/-2)
openerp/addons/base/res/res_config.py (+35/-0)
openerp/addons/base/res/res_currency.py (+32/-1)
openerp/addons/base/res/res_log.py.OTHER (+96/-0)
openerp/addons/base/res/res_partner.py (+217/-0)
openerp/addons/base/res/res_partner_report_address.xml (+14/-0)
openerp/addons/base/res/res_partner_view.xml (+5/-0)
openerp/addons/base/res/res_users.py (+56/-1)
openerp/addons/base/tests/test_osv_expression.yml (+17/-0)
openerp/modules/loading.py (+13/-0)
openerp/osv/expression.py (+121/-0)
openerp/osv/fields.py (+69/-0)
openerp/osv/orm.py (+797/-16)
openerp/osv/osv.py (+394/-0)
openerp/release.py (+6/-0)
openerp/report/interface.py (+8/-0)
openerp/report/printscreen/ps_list.py (+11/-0)
openerp/report/render/rml2pdf/trml2pdf.py (+20/-0)
openerp/report/report_sxw.py (+10/-0)
openerp/sql_db.py (+17/-0)
openerp/tools/convert.py (+18/-0)
openerp/tools/misc.py (+251/-1)
openerp/tools/safe_eval.py (+18/-1)
openerp/tools/translate.py (+73/-0)
Changed in openobject-server: | |
assignee: | nobody → OpenERP Publisher's Warranty Team (openerp-opw) |
tags: | added: maintenance |
no longer affects: | openobject-server/trunk |
summary: |
- Overall performance issue of BaseModel.fields_view_get + Overall performance issue of BaseModel.fields_view_get - binary fields + should not be prefetched |
I did some investigations again, and it appears that the real cause is the browse of the `_inherits'ed` partner of the user.
The partner ID of the user lmaurer has the ID 649.
In openerp. osv.orm. BaseModel. _read_flat, at line 3657, there is a simple query on the res_partner:
for sub_ids in cr.split_ for_in_ conditions( ids):
cr.execute( query, [tuple(sub_ids)] + rule_params)
results = cr.dictfetchall()
The query being executed:
SELECT res_partner. "ean13" ,res_partner. "zip_id" ,res_partner. "tz",res_ partner. "opt_out" ,res_partner. "title" ,res_partner. "parent_ id",res_ partner. "last_reconcili ation_date" ,res_partner. "employee" ,res_partner. "fax",res_ partner. "image_ medium" ,res_partner. "name", res_partner. "debit_ limit", res_partner. "signup_ token", res_partner. "street" ,res_partner. "bank_statement _label" ,res_partner. "country_ id",res_ partner. "notification_ email_send" ,res_partner. "supplier" ,res_partner. "ref",res_ partner. "email" ,res_partner. "street2" ,res_partner. "signup_ expiration" ,res_partner. "zip",res_ partner. "comment" ,res_partner. "color" ,res_partner. "image" ,res_partner. "city", res_partner. "user_id" ,res_partner. "type", res_partner. "function" ,res_partner. "phone" ,res_partner. "customer" ,res_partner. "image_ small", res_partner. "birthdate" ,res_partner. "vat",res_ partner. "state_ id",res_ partner. "website" ,res_partner. "use_parent_ address" ,res_partner. "signup_ type",res_ partner. "date", res_partner. "is_company" ,res_partner. "vat_subjected" ,res_partner. "section_ id",res_ partner. "lang", res_partner. "credit_ limit", res_partner. "mobile" ,res_partner. id FROM "res_partner" WHERE res_partner.id IN (649) ORDER BY name
And the time it takes to do the cr.execute:
cr.execute: 0:00:00.716974
I had to delve way too far in the server to find the cause of this issue, but I finally found the root cause.
The query took a lot of time to execute because a very big image was uploaded on the partner.
As the partner is inherits'ed by the user, each time OpenERP needed to do a browse on the current user, it took nearly 1 second to read the image from the database.
I removed the image and OpenERP is fast again.
The work around is simple.
However, that revealed an issue which I think is really important: the images should not be prefetched, they should be read from the database only if they are really necessary (display on the views, ...), because:
- images are used in more and more objects (user, partner, products, ...)
- we do browse on the records much more often than we need their image
- this is a true but insidious performance killer, even if we limit the size of the images, each browse will take significantly more time, and this will be more noticeable on loops
Example, this simple loop:
for partner in self.pool. get('res. partner' ).browse( cr, uid, ids, context=context):
print partner.name
Would take a lot of time to read all the images from the database just to print the name.