diff options
| author | Olivier Dony <odo@openerp.com> | 2012-08-21 15:02:02 +0200 |
|---|---|---|
| committer | Olivier Dony <odo@openerp.com> | 2012-08-21 15:02:02 +0200 |
| commit | eec2708f48b4e4c90f7f30dc7131a5aeb44bc4fc (patch) | |
| tree | 8d11335701b7a6b747938d6bc7f25f94a739cfd0 | |
| parent | 29e49980751fd9c607e22c730b0922cdc9a20a9e (diff) | |
[FIX] OPW 577963: ir_attachment: speed up ir.attachment search for large databases
Frequents calls to list.remove() were being a bottleneck for large
document lists (100k+). Using a set make remove() calls much faster.
Also turned a read() into a pure SQL command, as its high-level
features were unnecessary (security checks performed before and
after it anyways) and it was 50% slower than the direct SQL version.
This commit has a corresponding addons patch in order to use a set
instead of a list in the document module as well.
bzr revid: odo@openerp.com-20120821130202-71z83drt347lf45n
| -rw-r--r-- | openerp/addons/base/ir/ir_attachment.py | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index a0418be0e5a..14fa675c647 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -64,10 +64,17 @@ class ir_attachment(osv.osv): return 0 return [] + # Work with a set, as list.remove() is prohibitive for large lists of documents + # (takes 20+ seconds on a db with 100k docs during search_count()!) + ids = set(ids) + # For attachments, the permissions of the document they are attached to # apply, so we must remove attachments for which the user cannot access # the linked document. - targets = super(ir_attachment,self).read(cr, uid, ids, ['id', 'res_model', 'res_id']) + # Use pure SQL rather than read() as it is about 50% faster for large dbs (100k+ docs), + # and the permissions are checked in super() and below anyway. + cr.execute("""SELECT id, res_model, res_id FROM ir_attachment WHERE id = ANY(%s)""", (list(ids),)) + targets = cr.dictfetchall() model_attachments = {} for target_dict in targets: if not (target_dict['res_id'] and target_dict['res_model']): @@ -92,9 +99,10 @@ class ir_attachment(osv.osv): for res_id in disallowed_ids: for attach_id in targets[res_id]: ids.remove(attach_id) + if count: return len(ids) - return ids + return list(ids) def read(self, cr, uid, ids, fields_to_read=None, context=None, load='_classic_read'): self.check(cr, uid, ids, 'read', context=context) |
