[PERF] product: Improve name_search performance
Issue: The name_search performance was highly inefficient with a high number of records. Analyze: The bottleneck came from the NOT IN search on the product_template. Fix: As a NOT IN is not efficient, an not exists must be used. Note: The ORM has to be bypassed has no "not exists" feature has been implemented yet. Benchmark: | # Input data | Before PR | After PR | |:-------------:|:----------:|:---------:| | 182386 | 15+ min | ~100 ms | | 29 | ~29 ms | ~28 ms | Related task: opw-3554133 closes odoo/odoo#145095 X-original-commit: 955d28a485d569569af2792fa014b52c1829d178 Signed-off-by: Benjamin Hanquin (beha) <beha@odoo.com>
This commit is contained in:
@@ -546,14 +546,22 @@ class ProductTemplate(models.Model):
|
||||
searched_ids = set(templates.ids)
|
||||
# some product.templates do not have product.products yet (dynamic variants configuration),
|
||||
# we need to add the base _name_search to the results
|
||||
# FIXME awa: this is really not performant at all but after discussing with the team
|
||||
# we don't see another way to do it
|
||||
tmpl_without_variant = self.browse()
|
||||
if not limit or len(searched_ids) < limit:
|
||||
tmpl_with_variant_ids = self._search([('product_variant_ids.active', '=', True)])
|
||||
tmpl_without_variant = self.search([('id', 'not in', tmpl_with_variant_ids)])
|
||||
if tmpl_without_variant:
|
||||
domain2 = expression.AND([domain, [('id', 'in', tmpl_without_variant.ids)]])
|
||||
tmpl_without_variant_ids = []
|
||||
# Useless if variants is not set up as no tmpl_without_variant_ids could exist.
|
||||
if self.env.user.has_group('product.group_product_variant') and (not limit or len(searched_ids) < limit):
|
||||
# The ORM has to be bypassed because it would require a NOT IN which is inefficient.
|
||||
self.env['product.product'].flush_model(['product_tmpl_id', 'active'])
|
||||
tmpl_without_variant_ids = self.env['product.template']._search([], order='id')
|
||||
tmpl_without_variant_ids.add_where("""
|
||||
NOT EXISTS (
|
||||
SELECT product_tmpl_id
|
||||
FROM product_product
|
||||
WHERE product_product.active = true
|
||||
AND product_template.id = product_product.product_tmpl_id
|
||||
)
|
||||
""")
|
||||
if tmpl_without_variant_ids:
|
||||
domain2 = expression.AND([domain, [('id', 'in', tmpl_without_variant_ids)]])
|
||||
searched_ids |= set(super()._name_search(name, domain2, operator, limit, order))
|
||||
|
||||
# re-apply product.template order + display_name
|
||||
|
||||
@@ -29,3 +29,28 @@ class TestName(TransactionCase):
|
||||
res = self.env['product.template'].name_search(name='PTN', operator='not ilike')
|
||||
res_ids = [r[0] for r in res]
|
||||
self.assertNotIn(self.product.id, res_ids)
|
||||
|
||||
def test_product_template_search_name_no_product_product(self):
|
||||
color_attr = self.env['product.attribute'].create({'name': 'Color', 'create_variant': 'dynamic'})
|
||||
color_attr_value_r = self.env['product.attribute.value'].create({'name': 'Red', 'attribute_id': color_attr.id})
|
||||
color_attr_value_b = self.env['product.attribute.value'].create({'name': 'Blue', 'attribute_id': color_attr.id})
|
||||
template_dyn = self.env['product.template'].create({
|
||||
'name': 'Test Dynamical',
|
||||
'attribute_line_ids': [(0, 0, {
|
||||
'attribute_id': color_attr.id,
|
||||
'value_ids': [(4, color_attr_value_r.id), (4, color_attr_value_b.id)],
|
||||
})]
|
||||
})
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'Dynamo Lamp',
|
||||
'default_code': 'Dynamo',
|
||||
})
|
||||
self.assertTrue(template_dyn.has_dynamic_attributes())
|
||||
# Ensure that template_dyn hasn't any product_product
|
||||
self.assertEqual(len(template_dyn.product_variant_ids), 0)
|
||||
# Ensure that Dynam search return Dynamo and Test Dynamical as this
|
||||
# last have no product_product
|
||||
res = self.env['product.template'].name_search(name='Dynam', operator='ilike')
|
||||
res_ids = [r[0] for r in res]
|
||||
self.assertIn(template_dyn.id, res_ids)
|
||||
self.assertIn(product.product_tmpl_id.id, res_ids)
|
||||
|
||||
Reference in New Issue
Block a user