From 5a4e7b711ec1964fcd914ed2ff5f8f1e92db6cef Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Mon, 29 Mar 2021 14:56:22 +0000 Subject: [PATCH] [FIX] core,account: avoid useless recomputations in res.config User may use Settings menu just to click "Manage Users" buttons. Such simple navigation sends ``create`` request, which may trigger a chain of recomputations. To avoid that we redefine ``create`` method to check if a value is really changed. The previous explicit implementation lacks in v14 two fields at least: * from module `account` ``` qr_code = fields.Boolean(string='Display SEPA QR-code', related='company_id.qr_code', readonly=False) ``` * from module `enterprise/account_reports` ``` account_tax_fiscal_country_id = fields.Many2one(string="Fiscal Country", related="company_id.account_tax_fiscal_country_id", readonly=False) ``` Performance Tests ================= In this test we click "Manage users" and check stats for ``res.config.settings/create`` request. Demo database with eCommerce and Accounting app installed: ``` | | Number of queries | Query time, sec | Remaining time, sec | |--------+-------------------+-----------------+---------------------| | Before | 707 | 0.325 | 0.215 | | After | 382 | 0.283 | 0.174 | ``` The same, but with extra 1400 invoices: ``` | | Number of queries | Query time, sec | Remaining time, sec | |--------+-------------------+-----------------+---------------------| | Before | 715 | 0.459 | 0.349 | | After | 382 | 0.176 | 0.107 | ``` --- opw-2489335 closes odoo/odoo#68620 X-original-commit: 5e3f37191a4687b305e2337780c7f10278f6a7aa Signed-off-by: Ivan Yelizariev // IEL Signed-off-by: Raphael Collet (rco) --- addons/account/models/res_config_settings.py | 12 -------- odoo/addons/base/models/res_config.py | 32 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/addons/account/models/res_config_settings.py b/addons/account/models/res_config_settings.py index 91bd1685f2e..a6efcb1ac34 100644 --- a/addons/account/models/res_config_settings.py +++ b/addons/account/models/res_config_settings.py @@ -193,15 +193,3 @@ class ResConfigSettings(models.TransientModel): # We display the preview button only if the terms_type is html in the setting but also on the company # to avoid landing on an error page (see terms.py controller) setting.preview_ready = self.env.company.terms_type == 'html' and setting.terms_type == 'html' - - @api.model - def create(self, values): - # Optimisation purpose, saving a res_config even without changing any values will trigger the write of all - # related values, including the currency_id field on res_company. This in turn will trigger the recomputation - # of account_move_line related field company_currency_id which can be slow depending on the number of entries - # in the database. Thus, if we do not explicitly change the currency_id, we should not write it on the company - if ('company_id' in values and 'currency_id' in values): - company = self.env['res.company'].browse(values.get('company_id')) - if company.currency_id.id == values.get('currency_id'): - values.pop('currency_id') - return super(ResConfigSettings, self).create(values) diff --git a/odoo/addons/base/models/res_config.py b/odoo/addons/base/models/res_config.py index d0443942ed3..a7805b865b0 100644 --- a/odoo/addons/base/models/res_config.py +++ b/odoo/addons/base/models/res_config.py @@ -749,3 +749,35 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin) if (action_id): return RedirectWarning(msg % values, action_id, _('Go to the configuration panel')) return UserError(msg % values) + + @api.model + def create(self, values): + # Optimisation: saving a res.config.settings even without changing any + # values will trigger the write of all related values. This in turn may + # trigger chain of further recomputation. To avoid it, delete values + # that were not changed. + for field in self._fields.values(): + if not (field.name in values and field.related and not field.readonly): + continue + # we write on a related field like + # qr_code = fields.Boolean(related='company_id.qr_code', readonly=False) + fname0 = field.related[0] + if fname0 not in values: + continue + + # determine the current value + field0 = self._fields[fname0] + old_value = field0.convert_to_record( + field0.convert_to_cache(values[fname0], self), self) + for fname in field.related[1:]: + old_value = next(iter(old_value), old_value)[fname] + + # determine the new value + new_value = field.convert_to_record( + field.convert_to_cache(values[field.name], self), self) + + # drop if the value is the same + if old_value == new_value: + values.pop(field.name) + + return super(ResConfigSettings, self).create(values)