summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2020-10-09 09:36:53 +0000
committerRaphael Collet <rco@odoo.com>2020-10-12 12:24:09 +0000
commitec50c426d7c2a17c7b72e64adab65eda6328e163 (patch)
treec0dabe05574d825bf0a191996ee91168518e25da /odoo
parent5c0fca662279702115b5e61c8227f82086693e38 (diff)
[FIX] core: optimize first snaphot in onchange
This patch speeds up the performance of method `onchange`. Our use-case is an invoice with 300 lines, where we modify the unit price or quantity on several lines. Each modification triggers a call to `onchange` on the invoice itself. The latter call went from 1.3 to 0.8 seconds, which represents a speedup of 30% to 40%. In the implementation of `onchange`, the first snapshot is preceded by a "prefetching" phase, where the lines of x2many fields are read, so that the fields of unmodified lines are in cache. This is useful because the fields of those lines are not sent by the client, which only sends ids. This prefetching represents more than 40% of the duration of `onchange`, in our use-case. The prefetching is inefficient for several reasons. First, it uses `mapped`, which formats data that is actually never used. Second, it accesses new records that have the actual lines as origin. And on those records, computed stored fields are not taken from the origin record, but are (uselessly) computed instead. We have optimized the prefetching in the following way. It now reads stored fields on the actual lines (using `_read` to avoid formatting), then copies the cache of those fields on the corresponding new lines (to avoid useless computations). This makes the prefetching about 10 times faster! closes odoo/odoo#59744 X-original-commit: d39d61d763f4cb3019a78b202f7981c4f2e14d60 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Diffstat (limited to 'odoo')
-rw-r--r--odoo/models.py26
1 files changed, 20 insertions, 6 deletions
diff --git a/odoo/models.py b/odoo/models.py
index 59590aac48a..0150fd6ee01 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -6063,20 +6063,34 @@ Fields:
if name not in values
]))
- # prefetch x2many lines without data (for the initial snapshot)
+ # prefetch x2many lines: this speeds up the initial snapshot by avoiding
+ # to compute fields on new records as much as possible, as that can be
+ # costly and is not necessary at all
for name, subnames in nametree.items():
if subnames and values.get(name):
- # retrieve all ids in commands
+ # retrieve all line ids in commands
line_ids = set()
for cmd in values[name]:
if cmd[0] in (1, 4):
line_ids.add(cmd[1])
elif cmd[0] == 6:
line_ids.update(cmd[2])
- # build corresponding new lines, and prefetch fields
- new_lines = self[name].browse(NewId(id_) for id_ in line_ids)
- for subname in subnames:
- new_lines.mapped(subname)
+ # prefetch stored fields on lines
+ lines = self[name].browse(line_ids)
+ fnames = [subname
+ for subname in subnames
+ if lines._fields[subname].base_field.store]
+ lines._read(fnames)
+ # copy the cache of lines to their corresponding new records;
+ # this avoids computing computed stored fields on new_lines
+ new_lines = lines.browse(map(NewId, line_ids))
+ cache = self.env.cache
+ for fname in fnames:
+ field = lines._fields[fname]
+ cache.update(new_lines, field, [
+ field.convert_to_cache(value, new_line, validate=False)
+ for value, new_line in zip(cache.get_values(lines, field), new_lines)
+ ])
# Isolate changed values, to handle inconsistent data sent from the
# client side: when a form view contains two one2many fields that