From d7210f525716efdb6393db06ea2834d1a928330e Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 17 Aug 2018 17:32:08 +0200 Subject: [PATCH] [IMP] api, models: _write performances on import Followup from the previous commit: before this, _write takes 32% of total runtime, of which 13.7% is ultimately assignable to add_todo. Turns out for the test case we mostly keep adding records to recorsets where they're already present, so the 13.7% of runtime in add_todo are mostly spent creating orderedsets (11.17) then converting those back into recordsets (1.75%) with some time spent creating lists and appending records (already present) in them. Checking if the records are already present before merging them in decreases add_todo's runtime cost to 0.5%, and ultimately _write to 20%. As many of the ignorable calls were merging a singleton or an empty recorset into the parent recordset, optimising for these cases was added to BaseModel's <= and >=. --- odoo/api.py | 6 +++++- odoo/models.py | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/odoo/api.py b/odoo/api.py index 688b301cf02..22b82d17147 100644 --- a/odoo/api.py +++ b/odoo/api.py @@ -955,7 +955,11 @@ class Environment(Mapping): recs_list = self.all.todo.setdefault(field, []) for i, recs in enumerate(recs_list): if recs.env == records.env: - recs_list[i] |= records + # only add records if not already in the recordset, much much + # cheaper in case recs is big and records is a singleton + # already present + if not records <= recs: + recs_list[i] |= records break else: recs_list.append(records) diff --git a/odoo/models.py b/odoo/models.py index ab6f04fe060..0ca056286dc 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -4963,6 +4963,11 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): def __le__(self, other): if not isinstance(other, BaseModel) or self._name != other._name: raise TypeError("Mixing apples and oranges: %s <= %s" % (self, other)) + # these are much cheaper checks than a proper subset check, so + # optimise for checking if a null or singleton are subsets of a + # recordset + if not self or self in other: + return True return set(self._ids) <= set(other._ids) def __gt__(self, other): @@ -4973,6 +4978,8 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): def __ge__(self, other): if not isinstance(other, BaseModel) or self._name != other._name: raise TypeError("Mixing apples and oranges: %s >= %s" % (self, other)) + if not other or other in self: + return True return set(self._ids) >= set(other._ids) def __int__(self):