[FIX] hr_recruitment: Improve application_count field computation time
From 120 seconds to 0.5 seconds for 10000 applicants on odoo.com closes odoo/odoo#151303 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
@@ -119,6 +119,10 @@ class Applicant(models.Model):
|
||||
ON hr_applicant(job_id, stage_id)
|
||||
WHERE active IS TRUE
|
||||
""")
|
||||
self.env.cr.execute("""
|
||||
CREATE INDEX IF NOT EXISTS hr_applicant_email_partner_phone_mobile
|
||||
ON hr_applicant(email_normalized, partner_mobile_sanitized, partner_phone_sanitized);
|
||||
""")
|
||||
|
||||
@api.onchange('job_id')
|
||||
def _onchange_job_id(self):
|
||||
@@ -150,19 +154,42 @@ class Applicant(models.Model):
|
||||
else:
|
||||
applicant.delay_close = False
|
||||
|
||||
@api.depends('email_from', 'partner_phone', 'partner_mobile')
|
||||
@api.depends('email_from', 'partner_mobile_sanitized', 'partner_phone_sanitized')
|
||||
def _compute_application_count(self):
|
||||
"""
|
||||
The field application_count is only used on the form view.
|
||||
Thus, using ORM rather then querying, should not make much
|
||||
difference in terms of performance, while being more readable and secure.
|
||||
"""
|
||||
if not any(self._ids):
|
||||
for applicant in self:
|
||||
domain = applicant._get_similar_applicants_domain()
|
||||
if domain:
|
||||
applicant.application_count = max(0, self.env["hr.applicant"].with_context(active_test=False).search_count(domain) - 1)
|
||||
else:
|
||||
applicant.application_count = 0
|
||||
return
|
||||
self.flush_recordset(['email_normalized', 'partner_phone_sanitized', 'partner_mobile_sanitized'])
|
||||
self.env.cr.execute("""
|
||||
SELECT
|
||||
id,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM hr_applicant AS sub
|
||||
WHERE a.id != sub.id
|
||||
AND ((a.email_normalized <> '' AND sub.email_normalized = a.email_normalized)
|
||||
OR (a.partner_mobile_sanitized <> '' AND a.partner_mobile_sanitized = sub.partner_mobile_sanitized)
|
||||
OR (a.partner_mobile_sanitized <> '' AND a.partner_mobile_sanitized = sub.partner_phone_sanitized)
|
||||
OR (a.partner_phone_sanitized <> '' AND a.partner_phone_sanitized = sub.partner_mobile_sanitized)
|
||||
OR (a.partner_phone_sanitized <> '' AND a.partner_phone_sanitized = sub.partner_phone_sanitized))
|
||||
) AS similar_applicants
|
||||
FROM hr_applicant AS a
|
||||
WHERE id IN %(ids)s
|
||||
""", {'ids': tuple(self._origin.ids)})
|
||||
query_results = self.env.cr.dictfetchall()
|
||||
mapped_data = {result['id']: result['similar_applicants'] for result in query_results}
|
||||
for applicant in self:
|
||||
domain = applicant._get_similar_applicants_domain()
|
||||
if domain:
|
||||
applicant.application_count = self.env["hr.applicant"].with_context(active_test=False).search_count(domain) - 1
|
||||
else:
|
||||
applicant.application_count = 0
|
||||
applicant.application_count = mapped_data.get(applicant.id, 0)
|
||||
|
||||
def _get_similar_applicants_domain(self):
|
||||
"""
|
||||
|
||||
@@ -76,4 +76,3 @@ class TestRecruitment(TransactionCase):
|
||||
self.assertEqual(D.application_count, 3) # A, B, C
|
||||
self.assertEqual(E.application_count, 0) # Should not match with G
|
||||
self.assertEqual(F.application_count, 1) # B
|
||||
|
||||
|
||||
Reference in New Issue
Block a user