[IMP] product: product & template name_get performance

By prefetching only the fields required for the `name_get`

`product.product` & `product.template`
have a huge number of fields,
and prefetching them just to compute
the name is overkill.

Especially, as the browse was done using
sudo, the prefetch was a bit useless as
it was stored in the sudo user cache,
which was most-likely not used afterwards
by the callee of name_get

For a database with 50.000 products,
this reduce the processing time
by 15 (from 60 seconds to 4 seconds measured)
This commit is contained in:
Denis Ledoux
2018-12-17 15:00:45 +01:00
parent 8373bafbc2
commit a91ffcf1a7
2 changed files with 24 additions and 3 deletions
+22 -3
View File
@@ -395,17 +395,36 @@ class ProductProduct(models.Model):
self.check_access_rule("read")
result = []
# Prefetch the fields used by the `name_get`, so `browse` doesn't fetch other fields
# Use `load=False` to not call `name_get` for the `product_tmpl_id`
self.sudo().read(['name', 'default_code', 'product_tmpl_id', 'attribute_value_ids'], load=False)
product_template_ids = [product.product_tmpl_id.id for product in self]
if partner_ids:
supplier_info = self.env['product.supplierinfo'].sudo().search([
('product_tmpl_id', 'in', product_template_ids),
('name', 'in', partner_ids),
])
# Prefetch the fields used by the `name_get`, so `browse` doesn't fetch other fields
# Use `load=False` to not call `name_get` for the `product_tmpl_id` and `product_id`
supplier_info.sudo().read(['product_tmpl_id', 'product_id', 'product_name', 'product_code'], load=False)
supplier_info_by_template = {}
for r in supplier_info:
supplier_info_by_template.setdefault(r.product_tmpl_id, []).append(r)
for product in self.sudo():
# display only the attributes with multiple possible values on the template
variable_attributes = product.attribute_line_ids.filtered(lambda l: len(l.value_ids) > 1).mapped('attribute_id')
variable_attributes = product.attribute_value_ids.filtered(lambda v: len(v.attribute_id.value_ids) > 1).mapped('attribute_id')
variant = product.attribute_value_ids._variant_name(variable_attributes)
name = variant and "%s (%s)" % (product.name, variant) or product.name
sellers = []
if partner_ids:
sellers = [x for x in product.seller_ids if (x.name.id in partner_ids) and (x.product_id == product)]
product_supplier_info = supplier_info_by_template.get(product.product_tmpl_id, [])
sellers = [x for x in product_supplier_info if x.product_id and x.product_id == product]
if not sellers:
sellers = [x for x in product.seller_ids if (x.name.id in partner_ids) and not x.product_id]
sellers = [x for x in product_supplier_info if not x.product_id]
if sellers:
for s in sellers:
seller_variant = s.product_name and (
@@ -306,6 +306,8 @@ class ProductTemplate(models.Model):
@api.multi
def name_get(self):
# Prefetch the fields used by the `name_get`, so `browse` doesn't fetch other fields
self.read(['name', 'default_code'])
return [(template.id, '%s%s' % (template.default_code and '[%s] ' % template.default_code or '', template.name))
for template in self]