From c90edab169f950f2e0ba0ab4e34852462c7fe831 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Fri, 5 Oct 2018 09:35:22 -0400 Subject: [PATCH] Bundle an SQL query for performance We were doing many individual SQL queries for certificates when awarding program certs. It's possible this was contributing to high SQL load. Instead, let's bundle those queries up into a larger one. LEARNER-6490 --- openedx/core/djangoapps/programs/utils.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/openedx/core/djangoapps/programs/utils.py b/openedx/core/djangoapps/programs/utils.py index 4ec7f4e55b..aa1aaf8a17 100644 --- a/openedx/core/djangoapps/programs/utils.py +++ b/openedx/core/djangoapps/programs/utils.py @@ -284,17 +284,25 @@ class ProgramProgressMeter(object): Returns a dict of {uuid_string: available_datetime} """ + # Query for all user certs up front, for performance reasons (rather than querying per course run). + user_certificates = GeneratedCertificate.eligible_certificates.filter(user=self.user) + certificates_by_run = {cert.course_id: cert for cert in user_certificates} + completed = {} for program in self.programs: - available_date = self._available_date_for_program(program) + available_date = self._available_date_for_program(program, certificates_by_run) if available_date: completed[program['uuid']] = available_date return completed - def _available_date_for_program(self, program_data): + def _available_date_for_program(self, program_data, certificates): """ Calculate the available date for the program based on the courses within it. + Arguments: + program_data (dict): nested courses and course runs + certificates (dict): course run key -> certificate mapping + Returns a datetime object or None if the program is not complete. """ program_available_date = None @@ -305,7 +313,7 @@ class ProgramProgressMeter(object): key = CourseKey.from_string(course_run['key']) # Get a certificate if one exists - certificate = GeneratedCertificate.eligible_certificates.filter(user=self.user, course_id=key).first() + certificate = certificates.get(key) if certificate is None: continue