From 73a446d85b9a36c2664f0912dd453ba100ba695d Mon Sep 17 00:00:00 2001 From: ahmed-zubair-1998 <41994834+ahmed-zubair-1998@users.noreply.github.com> Date: Tue, 16 Jan 2024 23:41:15 +0500 Subject: [PATCH] perf: Reduce database calls when generating problem responses report (#33940) During the process of generatinng report for problem responses, there are two places where N + 1 query problem exist. In both cases, `StudentModule` objects are fetched and looped over where `student.username` field for each object is accessed. This result in a seperate database call to get the username for each student response. This problem is fixed by creating a join to fetch the related table in the original query using `select_related`. In a test conducted on report having 5000 `StudentModule` objects, the number of queries for the request reduced from 8363 to 29. The total time taken for the task reduced from 23764 ms to 7394 ms. --- lms/djangoapps/courseware/user_state_client.py | 2 +- lms/djangoapps/instructor_analytics/basic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/courseware/user_state_client.py b/lms/djangoapps/courseware/user_state_client.py index b893200c21d1..b85f20175ce8 100644 --- a/lms/djangoapps/courseware/user_state_client.py +++ b/lms/djangoapps/courseware/user_state_client.py @@ -600,7 +600,7 @@ def iter_all_for_block(self, block_key, scope=Scope.user_state): if scope != Scope.user_state: raise ValueError("Only Scope.user_state is supported") - results = StudentModule.objects.order_by('id').filter(module_state_key=block_key) + results = StudentModule.objects.order_by('id').filter(module_state_key=block_key).select_related('student') p = Paginator(results, settings.USER_STATE_BATCH_SIZE) for page_number in p.page_range: diff --git a/lms/djangoapps/instructor_analytics/basic.py b/lms/djangoapps/instructor_analytics/basic.py index afce0620aab0..c7bc6ca6da4c 100644 --- a/lms/djangoapps/instructor_analytics/basic.py +++ b/lms/djangoapps/instructor_analytics/basic.py @@ -349,7 +349,7 @@ def list_problem_responses(course_key, problem_location, limit_responses=None): smdat = StudentModule.objects.filter( course_id=course_key, module_state_key=problem_key - ) + ).select_related('student') smdat = smdat.order_by('student') if limit_responses is not None: smdat = smdat[:limit_responses]