-
Notifications
You must be signed in to change notification settings - Fork 167
Constant number of db queries in contributor index #2715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
94bd66f
61ffe81
ab818d4
f31e0c8
dfa0923
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -740,6 +740,24 @@ def can_be_seen_by(self, user): | |
| ) | ||
| return True | ||
|
|
||
| @staticmethod | ||
| def can_be_seen_by_Q(user): | ||
| if user.is_manager: | ||
| return Q() | ||
|
|
||
| if user.is_reviewer: | ||
| return ~Q(state=Evaluation.State.NEW) & ~Q(course__semester__results_are_archived=True) | ||
|
|
||
| base_q = ~Q(state=Evaluation.State.NEW) | ||
| if user.is_external: | ||
| return base_q & Evaluation.user_is_responsible_or_contributor_or_delegate_Q(user) | Q(participants=user) | ||
|
|
||
| return base_q & ( | ||
| ~Q(course__is_private=True) | ||
| | Evaluation.user_is_responsible_or_contributor_or_delegate_Q(user) | ||
| | Q(participants=user) | ||
| ) | ||
|
Comment on lines
+743
to
+759
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no way to evaluate a One approach that should always work is: Fetch a list of instances (e.g. evaluations visible to the user) without any prefetching (should be a few milliseconds), and then generate a list of IDs in python and pass that to follow-up queries (which now do "heavy" prefetching) |
||
|
|
||
| def can_results_page_be_seen_by(self, user): | ||
| if user.is_manager: | ||
| return True | ||
|
|
@@ -751,6 +769,27 @@ def can_results_page_be_seen_by(self, user): | |
| return self.is_user_responsible_or_contributor_or_delegate(user) | ||
| return self.can_be_seen_by(user) | ||
|
|
||
| @staticmethod | ||
| def can_results_page_be_seen_by_Q(user): | ||
| if user.is_manager: | ||
| return Q() | ||
|
|
||
| if user.is_reviewer: | ||
| return ~Q(course__semester__results_are_archived=True) | ||
|
|
||
| base_q = Q(state=Evaluation.State.PUBLISHED) | ||
| threshold = settings.VOTER_COUNT_NEEDED_FOR_PUBLISHING_RATING_RESULTS | ||
|
|
||
| archived_or_insufficient_q = Q(course__semester__results_are_archived=True) | Q(num_voters__lt=threshold) | ||
| restricted_q = ( | ||
| base_q & archived_or_insufficient_q & Evaluation.user_is_responsible_or_contributor_or_delegate_Q(user) | ||
| ) | ||
|
|
||
| not_archived_and_sufficient_q = ~Q(course__semester__results_are_archived=True) & Q(num_voters__gte=threshold) | ||
| available_q = base_q & not_archived_and_sufficient_q & Evaluation.can_be_seen_by_Q(user) | ||
|
|
||
| return restricted_q | available_q | ||
|
|
||
| @property | ||
| def can_reset_to_new(self): | ||
| return Evaluation.State.PREPARED <= self.state <= Evaluation.State.REVIEWED | ||
|
|
@@ -996,6 +1035,19 @@ def is_user_editor_or_delegate(self, user): | |
| or self.course.responsibles.filter(pk__in=represented_users).exists() | ||
| ) | ||
|
|
||
| @staticmethod | ||
| def user_is_editor_or_delegate_Q(user): | ||
| represented_users = user.represented_users.all() | UserProfile.objects.filter(pk=user.pk) | ||
| return Q( | ||
| Q(contributions__contributor__in=represented_users, contributions__role=Contribution.Role.EDITOR) | ||
| | Q(course__responsibles__in=represented_users) | ||
| ) | ||
|
|
||
| @staticmethod | ||
| def user_is_responsible_or_contributor_or_delegate_Q(user): | ||
| represented_users = user.represented_users.all() | UserProfile.objects.filter(pk=user.pk) | ||
| return Q(Q(contributions__contributor__in=represented_users) | Q(course__responsibles__in=represented_users)) | ||
|
|
||
| def is_user_responsible_or_contributor_or_delegate(self, user): | ||
| # early out that saves database hits since is_responsible_or_contributor_or_delegate is a cached_property | ||
| if not user.is_responsible_or_contributor_or_delegate: | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(random line): What is the struggle with the 200x10 case? We would fetch 2000 evaluation instances, and we'd have to prefetch 200 courses, ~20 course types, ~10 programs, ~400 evaluations(instances are already in memory), 1 semester, ~200 responsible. All of this are toy numbers. I suspect the total database query run time for the main query and all the prefetch queries is in the single to two-digit milliseconds.
None of this justifies almost a minute of runtime. Touching on the discussion in #2235: For all test_data.json, we render all result rows for all evaluations (thousands) in a few seconds. There is nothing fancy in the code for that. How can fetching and rendering a few hundred evaluations possibly be slower than that?