[FIX] mail, sms, snailmail: fix perf of fetching failures of user
We are currently lacking an index with (author, failure) due to the information being spread out in two different tables which are both rather big (there are a lot of non-failure messages for the current user, as well as a lot of failure messages for other users), so the fetch of failures for the current user can become extremely slow (> 20s). With this new index, the query takes less than 1ms. task-2742946 closes odoo/odoo#83451 Related: odoo/upgrade#3204 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
@@ -16,6 +16,7 @@ class MailNotification(models.Model):
|
||||
_description = 'Message Notifications'
|
||||
|
||||
# origin
|
||||
author_id = fields.Many2one('res.partner', 'Author', ondelete='set null')
|
||||
mail_message_id = fields.Many2one('mail.message', 'Message', index=True, ondelete='cascade', required=True)
|
||||
mail_mail_id = fields.Many2one('mail.mail', 'Mail', index=True, help='Optional mail_mail ID. Used mainly to optimize searches.')
|
||||
# recipient
|
||||
@@ -57,7 +58,10 @@ class MailNotification(models.Model):
|
||||
def init(self):
|
||||
self._cr.execute("""
|
||||
CREATE INDEX IF NOT EXISTS mail_notification_res_partner_id_is_read_notification_status_mail_message_id
|
||||
ON mail_notification (res_partner_id, is_read, notification_status, mail_message_id)
|
||||
ON mail_notification (res_partner_id, is_read, notification_status, mail_message_id);
|
||||
CREATE INDEX IF NOT EXISTS mail_notification_author_id_notification_status_failure
|
||||
ON mail_notification (author_id, notification_status)
|
||||
WHERE notification_status IN ('bounce', 'exception');
|
||||
""")
|
||||
self.env.cr.execute(
|
||||
"""CREATE UNIQUE INDEX IF NOT EXISTS unique_mail_message_id_res_partner_id_if_set
|
||||
|
||||
@@ -219,12 +219,18 @@ class MailThread(models.AbstractModel):
|
||||
def _compute_message_has_error(self):
|
||||
res = {}
|
||||
if self.ids:
|
||||
self._cr.execute(""" SELECT msg.res_id, COUNT(msg.res_id) FROM mail_message msg
|
||||
RIGHT JOIN mail_notification rel
|
||||
ON rel.mail_message_id = msg.id AND rel.notification_status in ('exception','bounce')
|
||||
WHERE msg.author_id = %s AND msg.model = %s AND msg.res_id in %s AND msg.message_type != 'user_notification'
|
||||
GROUP BY msg.res_id""",
|
||||
(self.env.user.partner_id.id, self._name, tuple(self.ids),))
|
||||
self.env.cr.execute("""
|
||||
SELECT msg.res_id, COUNT(msg.res_id)
|
||||
FROM mail_message msg
|
||||
INNER JOIN mail_notification notif
|
||||
ON notif.mail_message_id = msg.id
|
||||
WHERE notif.notification_status in ('exception', 'bounce')
|
||||
AND notif.author_id = %(author_id)s
|
||||
AND msg.model = %(model_name)s
|
||||
AND msg.res_id in %(res_ids)s
|
||||
AND msg.message_type != 'user_notification'
|
||||
GROUP BY msg.res_id
|
||||
""", {'author_id': self.env.user.partner_id.id, 'model_name': self._name, 'res_ids': tuple(self.ids)})
|
||||
res.update(self._cr.fetchall())
|
||||
|
||||
for record in self:
|
||||
@@ -2187,6 +2193,7 @@ class MailThread(models.AbstractModel):
|
||||
inbox_pids = [r['id'] for r in recipients_data if r['notif'] == 'inbox']
|
||||
if inbox_pids:
|
||||
notif_create_values = [{
|
||||
'author_id': message.author_id.id,
|
||||
'mail_message_id': message.id,
|
||||
'res_partner_id': pid,
|
||||
'notification_type': 'inbox',
|
||||
@@ -2313,6 +2320,7 @@ class MailThread(models.AbstractModel):
|
||||
'mail_mail_id': new_email.id,
|
||||
})
|
||||
notif_create_values += [{
|
||||
'author_id': message.author_id.id,
|
||||
'mail_message_id': message.id,
|
||||
'res_partner_id': recipient_id,
|
||||
'notification_type': 'email',
|
||||
|
||||
@@ -126,14 +126,14 @@ class Partner(models.Model):
|
||||
"""Returns all messages, sent by the current partner, that have errors, in
|
||||
the format expected by the web client."""
|
||||
self.ensure_one()
|
||||
messages = self.env['mail.message'].search([
|
||||
('has_error', '=', True),
|
||||
notifications = self.env['mail.notification'].search([
|
||||
('author_id', '=', self.id),
|
||||
('res_id', '!=', 0),
|
||||
('model', '!=', False),
|
||||
('message_type', '!=', 'user_notification')
|
||||
('notification_status', 'in', ('bounce', 'exception')),
|
||||
('mail_message_id.message_type', '!=', 'user_notification'),
|
||||
('mail_message_id.model', '!=', False),
|
||||
('mail_message_id.res_id', '!=', 0),
|
||||
])
|
||||
return messages._message_notification_format()
|
||||
return notifications.mail_message_id._message_notification_format()
|
||||
|
||||
def _get_channels_as_member(self):
|
||||
"""Returns the channels of the partner."""
|
||||
|
||||
@@ -737,6 +737,7 @@ class MailCase(MockEmail):
|
||||
n.is_read == nis_read
|
||||
)
|
||||
self.assertTrue(partner_notif, 'Mail: not found notification for %s (type: %s, state: %s, message: %s)' % (partner, ntype, nstatus, message.id))
|
||||
self.assertEqual(partner_notif.author_id, partner_notif.mail_message_id.author_id, 'Mail: Message and notification should have the same author')
|
||||
|
||||
# prepare further asserts
|
||||
if ntype == 'email':
|
||||
|
||||
@@ -24,10 +24,11 @@ class MailResendCancel(models.TransientModel):
|
||||
FROM mail_notification notif
|
||||
JOIN mail_message mes
|
||||
ON notif.mail_message_id = mes.id
|
||||
WHERE notif.notification_type = 'email' AND notif.notification_status IN ('bounce', 'exception')
|
||||
AND mes.model = %s
|
||||
AND mes.author_id = %s
|
||||
""", (wizard.model, author_id))
|
||||
WHERE notif.notification_type = 'email'
|
||||
AND notif.author_id = %(author_id)s
|
||||
AND notif.notification_status IN ('bounce', 'exception')
|
||||
AND mes.model = %(model_name)s
|
||||
""", {'model_name': wizard.model, 'author_id': author_id})
|
||||
res = self._cr.fetchall()
|
||||
notif_ids = [row[0] for row in res]
|
||||
messages_ids = list(set([row[1] for row in res]))
|
||||
|
||||
@@ -20,12 +20,19 @@ class MailThread(models.AbstractModel):
|
||||
def _compute_message_has_sms_error(self):
|
||||
res = {}
|
||||
if self.ids:
|
||||
self._cr.execute(""" SELECT msg.res_id, COUNT(msg.res_id) FROM mail_message msg
|
||||
RIGHT JOIN mail_notification rel
|
||||
ON rel.mail_message_id = msg.id AND rel.notification_type = 'sms' AND rel.notification_status in ('exception')
|
||||
WHERE msg.author_id = %s AND msg.model = %s AND msg.res_id in %s AND msg.message_type != 'user_notification'
|
||||
GROUP BY msg.res_id""",
|
||||
(self.env.user.partner_id.id, self._name, tuple(self.ids),))
|
||||
self.env.cr.execute("""
|
||||
SELECT msg.res_id, COUNT(msg.res_id)
|
||||
FROM mail_message msg
|
||||
INNER JOIN mail_notification notif
|
||||
ON notif.mail_message_id = msg.id
|
||||
WHERE notif.notification_type = 'sms'
|
||||
AND notif.notification_status = 'exception'
|
||||
AND notif.author_id = %(author_id)s
|
||||
AND msg.model = %(model_name)s
|
||||
AND msg.res_id in %(res_ids)s
|
||||
AND msg.message_type != 'user_notification'
|
||||
GROUP BY msg.res_id
|
||||
""", {'author_id': self.env.user.partner_id.id, 'model_name': self._name, 'res_ids': tuple(self.ids)})
|
||||
res.update(self._cr.fetchall())
|
||||
|
||||
for record in self:
|
||||
@@ -331,6 +338,7 @@ class MailThread(models.AbstractModel):
|
||||
existing_numbers.append(n.sms_number)
|
||||
|
||||
notif_create_values = [{
|
||||
'author_id': message.author_id.id,
|
||||
'mail_message_id': message.id,
|
||||
'res_partner_id': sms.partner_id.id,
|
||||
'sms_number': sms.number,
|
||||
|
||||
@@ -218,6 +218,7 @@ class SMSCase(MockSMS):
|
||||
|
||||
notif = notifications.filtered(lambda n: n.res_partner_id == partner and n.sms_number == number and n.notification_status == state)
|
||||
self.assertTrue(notif, 'SMS: not found notification for %s (number: %s, state: %s)' % (partner, number, state))
|
||||
self.assertEqual(notif.author_id, notif.mail_message_id.author_id, 'SMS: Message and notification should have the same author')
|
||||
|
||||
if state not in ('sent', 'ready', 'canceled'):
|
||||
self.assertEqual(notif.failure_type, recipient_info['failure_type'])
|
||||
|
||||
@@ -100,6 +100,7 @@ class SnailmailLetter(models.Model):
|
||||
notification_vals = []
|
||||
for letter in letters:
|
||||
notification_vals.append({
|
||||
'author_id': letter.message_id.author_id.id,
|
||||
'mail_message_id': letter.message_id.id,
|
||||
'res_partner_id': letter.partner_id.id,
|
||||
'notification_type': 'snail',
|
||||
|
||||
@@ -26,6 +26,7 @@ class TestSMSActionsCommon(TestMailFullCommon, TestMailFullRecipients):
|
||||
'state': 'error',
|
||||
})
|
||||
cls.notif_p1 = cls.env['mail.notification'].create({
|
||||
'author_id': cls.msg.author_id.id,
|
||||
'mail_message_id': cls.msg.id,
|
||||
'res_partner_id': cls.partner_1.id,
|
||||
'sms_id': cls.sms_p1.id,
|
||||
@@ -43,6 +44,7 @@ class TestSMSActionsCommon(TestMailFullCommon, TestMailFullRecipients):
|
||||
'state': 'error',
|
||||
})
|
||||
cls.notif_p2 = cls.env['mail.notification'].create({
|
||||
'author_id': cls.msg.author_id.id,
|
||||
'mail_message_id': cls.msg.id,
|
||||
'res_partner_id': cls.partner_2.id,
|
||||
'sms_id': cls.sms_p2.id,
|
||||
|
||||
Reference in New Issue
Block a user