[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 >=.
This commit is contained in:
Xavier Morel
2018-09-11 16:43:55 +02:00
committed by xmo-odoo
parent c3216db4c1
commit d7210f5257
2 changed files with 12 additions and 1 deletions
+5 -1
View File
@@ -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)
+7
View File
@@ -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):