From a7b9b6e3096e5fa93adaf06b279259c6ed3b928f Mon Sep 17 00:00:00 2001 From: Kevin Baptiste Date: Fri, 1 Apr 2022 08:38:49 +0000 Subject: [PATCH] [FIX] hr_recruitment: fix perf of new_application_count On large databases, the method `_compute_new_application_count` could take up to 80% of the total loading time of the Job positions as each job was generating 2 queries. closes odoo/odoo#87862 Taskid: 2812400 X-original-commit: 147f6a933f106fea540bd62522b941a855fffda2 Signed-off-by: Kevin Baptiste --- addons/hr_recruitment/models/hr_job.py | 31 +++++++++++++++++-- .../hr_recruitment/models/hr_recruitment.py | 4 +-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/addons/hr_recruitment/models/hr_job.py b/addons/hr_recruitment/models/hr_job.py index 38b2d2b7a0e..5bbc994ecd8 100644 --- a/addons/hr_recruitment/models/hr_job.py +++ b/addons/hr_recruitment/models/hr_job.py @@ -145,10 +145,35 @@ class Job(models.Model): ('job_ids', '=', self.id)], order='sequence asc', limit=1) def _compute_new_application_count(self): + self.env.cr.execute( + """ + WITH job_stage AS ( + SELECT DISTINCT ON (j.id) j.id AS job_id, s.id AS stage_id, s.sequence AS sequence + FROM hr_job j + LEFT JOIN hr_job_hr_recruitment_stage_rel rel + ON rel.hr_job_id = j.id + JOIN hr_recruitment_stage s + ON s.id = rel.hr_recruitment_stage_id + OR s.id NOT IN ( + SELECT "hr_recruitment_stage_id" + FROM "hr_job_hr_recruitment_stage_rel" + WHERE "hr_recruitment_stage_id" IS NOT NULL + ) + WHERE j.id in %s + ORDER BY 1, 3 asc + ) + SELECT s.job_id, COUNT(a.id) AS new_applicant + FROM hr_applicant a + JOIN job_stage s + ON s.job_id = a.job_id + AND a.stage_id = s.stage_id + GROUP BY s.job_id + """, [tuple(self.ids), ] + ) + + new_applicant_count = dict(self.env.cr.fetchall()) for job in self: - job.new_application_count = self.env["hr.applicant"].search_count( - [("job_id", "=", job.id), ("stage_id", "=", job._get_first_stage().id)] - ) + job.new_application_count = new_applicant_count.get(job.id, 0) def _compute_applicant_hired(self): hired_stages = self.env['hr.recruitment.stage'].search([('hired_stage', '=', True)]) diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py index 85f6e52bdf0..de37dbbd150 100644 --- a/addons/hr_recruitment/models/hr_recruitment.py +++ b/addons/hr_recruitment/models/hr_recruitment.py @@ -150,7 +150,7 @@ class Applicant(models.Model): date_open = fields.Datetime("Assigned", readonly=True) date_last_stage_update = fields.Datetime("Last Stage Update", index=True, default=fields.Datetime.now) priority = fields.Selection(AVAILABLE_PRIORITIES, "Appreciation", default='0') - job_id = fields.Many2one('hr.job', "Applied Job", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) + job_id = fields.Many2one('hr.job', "Applied Job", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True, index=True) salary_proposed_extra = fields.Char("Proposed Salary Extra", help="Salary Proposed by the Organisation, extra advantages", tracking=True, groups="hr_recruitment.group_hr_recruitment_user") salary_expected_extra = fields.Char("Expected Salary Extra", help="Salary Expected by Applicant, extra advantages", tracking=True, groups="hr_recruitment.group_hr_recruitment_user") salary_proposed = fields.Float("Proposed Salary", group_operator="avg", help="Salary Proposed by the Organisation", tracking=True, groups="hr_recruitment.group_hr_recruitment_user") @@ -257,7 +257,7 @@ class Applicant(models.Model): @api.depends('meeting_ids', 'meeting_ids.start') def _compute_meeting_display(self): applicant_with_meetings = self.filtered('meeting_ids') - (self - applicant_with_meetings).write({ + (self - applicant_with_meetings).update({ 'meeting_display_text': _('No Meeting'), 'meeting_display_date': '' })