[MERGE] mail: improve record creation with batch operations

PURPOSE

Optimize record creation in mail module by adding batch operations.

SPECIFICATIONS

Compute default followers once at creation for all created records. As the
same value is computed for each new record computing it once is sufficient.

Log default creation message in batch when having no specific subtype at
create. It allows to speedup record creation. For 1000 records, these specific
lines take
  * 2.1s before the commit
  * 1.2s after the commit

LINKS

PR #36654
Task 2070602

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2019-09-13 10:44:22 +02:00
committed by GitHub
2 changed files with 46 additions and 42 deletions
+11 -7
View File
@@ -260,9 +260,10 @@ class MailThread(models.AbstractModel):
# subscribe uid unless asked not to
if not self._context.get('mail_create_nosubscribe'):
default_followers = self.env['mail.followers']._add_default_followers(self._name, [], self.env.user.partner_id.ids, customer_ids=[])[0][0]
for values in vals_list:
message_follower_ids = values.get('message_follower_ids') or []
message_follower_ids += [(0, 0, fol_vals) for fol_vals in self.env['mail.followers']._add_default_followers(self._name, [], self.env.user.partner_id.ids, customer_ids=[])[0][0]]
message_follower_ids += [(0, 0, fol_vals) for fol_vals in default_followers]
values['message_follower_ids'] = message_follower_ids
threads = super(MailThread, self).create(vals_list)
@@ -280,13 +281,16 @@ class MailThread(models.AbstractModel):
# automatic logging unless asked not to (mainly for various testing purpose)
if not self._context.get('mail_create_nolog'):
doc_name = self.env['ir.model']._get(self._name).name
body = _('%s created') % doc_name
threads_no_subtype = self.env[self._name]
for thread in threads:
subtype = thread._creation_subtype()
body = _('%s created') % doc_name
if subtype: # if we have a sybtype, post message to notify users from _message_auto_subscribe
if subtype: # if we have a subtype, post message to notify users from _message_auto_subscribe
thread.sudo().message_post(body=body, subtype_id=subtype.id, author_id=self.env.user.partner_id.id)
else:
thread._message_log(body=body)
threads_no_subtype += thread
if threads_no_subtype:
threads_no_subtype._message_log_batch(bodies={t.id: body for t in threads_no_subtype})
# post track template if a tracked field changed
if not self._context.get('mail_notrack'):
@@ -554,8 +558,9 @@ class MailThread(models.AbstractModel):
def _creation_subtype(self):
""" Give the subtypes triggered by the creation of a record
:returns: a subtype browse record or False if no subtype is trigerred
:returns: a subtype browse record (empty if no subtype is triggered)
"""
return self.env['mail.message.subtype']
def _track_subtype(self, init_values):
""" Give the subtypes triggered by the changes on the record according
@@ -1019,8 +1024,7 @@ class MailThread(models.AbstractModel):
message_dict.pop('parent_id', None)
thread = ModelCtx.message_new(message_dict, custom_values)
thread_id = thread.id
subtype = thread._creation_subtype()
subtype_id = subtype.id if subtype else False
subtype_id = thread._creation_subtype().id
# replies to internal message are considered as notes, but parent message
# author is added in recipients to ensure he is notified of a private answer
+35 -35
View File
@@ -65,7 +65,7 @@ class TestMailPerformance(BaseMailPerformance):
records = self.env['test_performance.mail'].search([])
self.assertEqual(len(records), 5)
with self.assertQueryCount(__system__=3, demo=3): # test_mail only: 3 - 3
with self.assertQueryCount(__system__=3, demo=3):
records.write({'name': 'X'})
@users('__system__', 'demo')
@@ -75,7 +75,7 @@ class TestMailPerformance(BaseMailPerformance):
records = self.env['test_performance.mail'].search([])
self.assertEqual(len(records), 5)
with self.assertQueryCount(__system__=5, demo=5): # test_mail only: 5 - 5
with self.assertQueryCount(__system__=3, demo=3):
records.write({'value': 42})
@users('__system__', 'demo')
@@ -89,7 +89,7 @@ class TestMailPerformance(BaseMailPerformance):
'partner_id': self.env.ref('base.res_partner_12').id,
})
with self.assertQueryCount(__system__=4, demo=4): # test_mail only: 4 - 4
with self.assertQueryCount(__system__=3, demo=3):
record.track = 'X'
@users('__system__', 'demo')
@@ -98,27 +98,27 @@ class TestMailPerformance(BaseMailPerformance):
""" Create records inheriting from 'mail.thread' (without field tracking). """
model = self.env['test_performance.mail']
with self.assertQueryCount(__system__=3, demo=3): # test_mail only: 3 - 3
with self.assertQueryCount(__system__=2, demo=2):
model.with_context(tracking_disable=True).create({'name': 'X'})
@users('__system__', 'demo')
@warmup
def test_create_mail_with_tracking(self):
""" Create records inheriting from 'mail.thread' (with field tracking). """
with self.assertQueryCount(__system__=8, demo=8): # test_mail only: 8 - 8
with self.assertQueryCount(__system__=7, demo=7):
self.env['test_performance.mail'].create({'name': 'X'})
@users('__system__', 'emp')
@warmup
def test_create_mail_simple(self):
with self.assertQueryCount(__system__=6, emp=6): # test_mail only: 6 - 6
with self.assertQueryCount(__system__=6, emp=6):
self.env['mail.test.simple'].create({'name': 'Test'})
@users('__system__', 'emp')
@warmup
def test_write_mail_simple(self):
rec = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=1, emp=1): # test_mail only: 1 - 1
with self.assertQueryCount(__system__=1, emp=1):
rec.write({
'name': 'Test2',
'email_from': 'test@test.com',
@@ -150,7 +150,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_adv_activity(self):
model = self.env['mail.test.activity']
with self.assertQueryCount(__system__=7, emp=6): # test_mail only: 7 - 6
with self.assertQueryCount(__system__=6, emp=6):
model.create({'name': 'Test'})
@users('__system__', 'emp')
@@ -162,7 +162,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
'default_res_model': 'mail.test.activity',
})
with self.assertQueryCount(__system__=10, emp=13): # com runbot: 10 - 13 // test_mail only: 10 - 13
with self.assertQueryCount(__system__=6, emp=6):
activity = MailActivity.create({
'summary': 'Test Activity',
'res_id': record.id,
@@ -172,7 +172,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
#voip module read activity_type during create leading to one less query in enterprise on action_feedback
category = activity.activity_type_id.category
with self.assertQueryCount(__system__=24, emp=31): # com runbot: 24 - 31 // test_mail only: 24 - 31
with self.assertQueryCount(__system__=19, emp=22):
activity.action_feedback(feedback='Zizisse Done !')
@users('__system__', 'emp')
@@ -181,7 +181,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_adv_activity_mixin(self):
record = self.env['mail.test.activity'].create({'name': 'Test'})
with self.assertQueryCount(__system__=10, emp=14): # com runbot: 10 - 14 // test_mail only: 10 - 14
with self.assertQueryCount(__system__=7, emp=7):
activity = record.action_start('Test Start')
#read activity_type to normalize cache between enterprise and community
#voip module read activity_type during create leading to one less query in enterprise on action_close
@@ -189,7 +189,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
record.write({'name': 'Dupe write'})
with self.assertQueryCount(__system__=26, emp=31): # com runbot: 26 - 31 // test_mail only: 26 - 31
with self.assertQueryCount(__system__=20, emp=22):
record.action_close('Dupe feedback')
self.assertEqual(record.activity_ids, self.env['mail.activity'])
@@ -200,7 +200,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_message_assignation_email(self):
self.user_test.write({'notification_type': 'email'})
record = self.env['mail.test.track'].create({'name': 'Test'})
with self.assertQueryCount(__system__=52, emp=54): # com runbot: 52 - 54 // test_mail only: 52 - 54
with self.assertQueryCount(__system__=39, emp=40):
record.write({
'user_id': self.user_test.id,
})
@@ -209,7 +209,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
@warmup
def test_message_assignation_inbox(self):
record = self.env['mail.test.track'].create({'name': 'Test'})
with self.assertQueryCount(__system__=32, emp=37): # test_mail only: 32 - 37
with self.assertQueryCount(__system__=27, emp=29):
record.write({
'user_id': self.user_test.id,
})
@@ -219,7 +219,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_message_log(self):
record = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=1, emp=1): # test_mail only: 1 - 1
with self.assertQueryCount(__system__=1, emp=1):
record._message_log(
body='<p>Test _message_log</p>',
message_type='comment')
@@ -229,7 +229,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_message_log_with_post(self):
record = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=6, emp=7): # test_mail only: 6 - 7
with self.assertQueryCount(__system__=5, emp=6):
record.message_post(
body='<p>Test message_post as log</p>',
subtype='mail.mt_note',
@@ -240,7 +240,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_message_post_no_notification(self):
record = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=6, emp=7): # test_mail only: 6 - 7
with self.assertQueryCount(__system__=5, emp=6):
record.message_post(
body='<p>Test Post Performances basic</p>',
partner_ids=[],
@@ -253,7 +253,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_message_post_one_email_notification(self):
record = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=44, emp=47): # com runbot: 44 - 47 // test_mail only: 44 - 47
with self.assertQueryCount(__system__=32, emp=33):
record.message_post(
body='<p>Test Post Performances with an email ping</p>',
partner_ids=self.customer.ids,
@@ -265,7 +265,7 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_message_post_one_inbox_notification(self):
record = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=29, emp=34): # com runbot 29 - 34 // test_mail only: 29 - 34
with self.assertQueryCount(__system__=23, emp=25):
record.message_post(
body='<p>Test Post Performances with an inbox ping</p>',
partner_ids=self.user_test.partner_id.ids,
@@ -278,10 +278,10 @@ class TestAdvMailPerformance(BaseMailPerformance):
def test_message_subscribe_default(self):
record = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=6, emp=6): # test_mail only: 6 - 6
with self.assertQueryCount(__system__=6, emp=6):
record.message_subscribe(partner_ids=self.user_test.partner_id.ids)
with self.assertQueryCount(__system__=3, emp=3): # test_mail only: 3 - 3
with self.assertQueryCount(__system__=3, emp=3):
record.message_subscribe(partner_ids=self.user_test.partner_id.ids)
@mute_logger('odoo.models.unlink')
@@ -291,10 +291,10 @@ class TestAdvMailPerformance(BaseMailPerformance):
record = self.env['mail.test.simple'].create({'name': 'Test'})
subtype_ids = (self.env.ref('test_mail.st_mail_test_simple_external') | self.env.ref('mail.mt_comment')).ids
with self.assertQueryCount(__system__=5, emp=5): # test_mail only: 5 - 5
with self.assertQueryCount(__system__=5, emp=5):
record.message_subscribe(partner_ids=self.user_test.partner_id.ids, subtype_ids=subtype_ids)
with self.assertQueryCount(__system__=2, emp=2): # test_mail only: 2 - 2
with self.assertQueryCount(__system__=2, emp=2):
record.message_subscribe(partner_ids=self.user_test.partner_id.ids, subtype_ids=subtype_ids)
@@ -362,7 +362,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
'recipient_ids': [(4, pid) for pid in self.partners.ids],
})
mail_ids = mail.ids
with self.assertQueryCount(__system__=16, emp=21): # test_mail only: 16 - 21
with self.assertQueryCount(__system__=7, emp=7):
self.env['mail.mail'].browse(mail_ids).send()
self.assertEqual(mail.body_html, '<p>Test</p>')
@@ -375,7 +375,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
self.umbrella.message_subscribe(self.user_portal.partner_id.ids)
record = self.umbrella.with_user(self.env.user)
with self.assertQueryCount(__system__=82, emp=85): # com runbot: 82 - 85 // test_mail only: 82 - 85
with self.assertQueryCount(__system__=71, emp=72):
record.message_post(
body='<p>Test Post Performances</p>',
message_type='comment',
@@ -392,7 +392,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
record = self.umbrella.with_user(self.env.user)
template_id = self.env.ref('test_mail.mail_test_tpl').id
with self.assertQueryCount(__system__=98, emp=103): # com runbot: 98 - 103 // test_mail only: 98 - 103
with self.assertQueryCount(__system__=81, emp=82):
record.message_post_with_template(template_id, message_type='comment', composition_mode='comment')
self.assertEqual(record.message_ids[0].body, '<p>Adding stuff on %s</p>' % record.name)
@@ -417,7 +417,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
self.assertEqual(rec.message_channel_ids, self.env['mail.channel'])
# subscribe new followers with forced given subtypes
with self.assertQueryCount(__system__=8, emp=8): # test_mail only: 8 - 8
with self.assertQueryCount(__system__=8, emp=8):
rec.message_subscribe(
partner_ids=pids[:4],
channel_ids=cids,
@@ -428,7 +428,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
self.assertEqual(rec.message_channel_ids, self.channel)
# subscribe existing and new followers with force=False, meaning only some new followers will be added
with self.assertQueryCount(__system__=6, emp=6): # test_mail only: 6 - 6
with self.assertQueryCount(__system__=6, emp=6):
rec.message_subscribe(
partner_ids=pids[:6],
channel_ids=cids,
@@ -439,7 +439,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
self.assertEqual(rec.message_channel_ids, self.channel)
# subscribe existing and new followers with force=True, meaning all will have the same subtypes
with self.assertQueryCount(__system__=7, emp=7): # test_mail only: 7 - 7
with self.assertQueryCount(__system__=7, emp=7):
rec.message_subscribe(
partner_ids=pids,
channel_ids=cids,
@@ -461,7 +461,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
'user_id': self.env.uid,
})
self.assertEqual(rec.message_partner_ids, self.partners | self.env.user.partner_id)
with self.assertQueryCount(__system__=52, emp=53): # com runbot: 51 - 53 // test_mail only: 51 - 53
with self.assertQueryCount(__system__=39, emp=40):
rec.write({'user_id': self.user_portal.id})
self.assertEqual(rec.message_partner_ids, self.partners | self.env.user.partner_id | self.user_portal.partner_id)
# write tracking message
@@ -481,7 +481,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
customer_id = self.customer.id
user_id = self.user_portal.id
with self.assertQueryCount(__system__=146, emp=149): # com runbot: 146 - 149 // test_mail only: 146 - 149
with self.assertQueryCount(__system__=121, emp=122):
rec = self.env['mail.test.full'].create({
'name': 'Test',
'umbrella_id': umbrella_id,
@@ -508,7 +508,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
})
self.assertEqual(rec.message_partner_ids, self.user_portal.partner_id | self.env.user.partner_id)
self.assertEqual(len(rec.message_ids), 1)
with self.assertQueryCount(__system__=100, emp=106): # com runbot: 100 -106 // test_mail only: 100 - 106
with self.assertQueryCount(__system__=84, emp=85):
rec.write({
'name': 'Test2',
'umbrella_id': self.umbrella.id,
@@ -544,7 +544,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
})
self.assertEqual(rec.message_partner_ids, self.user_portal.partner_id | self.env.user.partner_id)
with self.assertQueryCount(__system__=105, emp=111): # test_mail only: 105 - 111
with self.assertQueryCount(__system__=92, emp=93):
rec.write({
'name': 'Test2',
'umbrella_id': umbrella_id,
@@ -576,7 +576,7 @@ class TestHeavyMailPerformance(BaseMailPerformance):
})
self.assertEqual(rec.message_partner_ids, self.partners | self.env.user.partner_id | self.user_portal.partner_id)
with self.assertQueryCount(__system__=50, emp=63): # test_mail only: 50 - 63
with self.assertQueryCount(__system__=33, emp=35):
rec.write({
'name': 'Test2',
'customer_id': customer_id,
@@ -713,7 +713,7 @@ class TestMailPerformancePost(BaseMailPerformance):
]
self.attachements = self.env['ir.attachment'].with_user(self.env.user).create(self.vals)
attachement_ids = self.attachements.ids
with self.assertQueryCount(emp=175): # com runbot 154 // test_mail only: 132
with self.assertQueryCount(emp=118): # runbot 118 // test_mail only: 110
self.cr.sql_log = self.warm and self.cr.sql_log_count
record.with_context({}).message_post(
body='<p>Test body <img src="cid:cid1"> <img src="cid:cid2"></p>',