Skip to content

Commit 5bd5d92

Browse files
committed
make some DB queries more efficient
The queries to build the home page timeline, and to get the lists of extensions and custom part types in the question editor, were doing outer joins. The problem is this pattern: Model.objects.filter(a) | related_model.models.all() This produces an outer join, which is slow. Instead, these queries could be written as: Model.objects.filter(Q(a) | pk__in=related_model.models.all()) This does an inner join, which is fast.
1 parent 8311ea1 commit 5bd5d92

2 files changed

Lines changed: 9 additions & 11 deletions

File tree

accounts/models.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,22 @@ def projects(self):
7878

7979
def all_timeline(self):
8080
nonsticky_broadcasts = SiteBroadcast.objects.visible_now().exclude(sticky=True)
81-
nonsticky_broadcast_timelineitems = TimelineItem.objects.filter(object_content_type=ContentType.objects.get_for_model(SiteBroadcast), object_id__in=nonsticky_broadcasts)
81+
nonsticky_broadcast_timelineitems_filter = Q(object_content_type=ContentType.objects.get_for_model(SiteBroadcast), object_id__in=nonsticky_broadcasts)
8282

8383
projects = Project.objects.filter(Q(owner=self.user) | Q(pk__in=self.user.individual_accesses.for_model(Project).values('object_id')) | Q(watching_non_members=self.user)).values('pk')
8484
editoritems = EditorItem.objects.filter(Q(author=self.user) | Q(pk__in=self.user.individual_accesses.for_model(EditorItem).values('object_id'))).values('pk')
8585
queues = ItemQueue.objects.filter(Q(owner=self.user) | Q(pk__in=self.user.individual_accesses.for_model(ItemQueue).values('object_id'))).values('pk')
8686

8787
items = TimelineItem.objects.filter(
88+
nonsticky_broadcast_timelineitems_filter |
8889
Q(editoritems__in=editoritems) |
8990
Q(editoritems__project__in=projects) |
9091
Q(projects__in=projects) |
9192
Q(item_queue_entries__queue__project__in = projects) |
9293
Q(item_queue_entries__queue__in = queues) |
9394
Q(item_queue_entry__queue__project__in = projects) |
9495
Q(item_queue_entry__queue__in = queues)
95-
)
96-
97-
items = (items | nonsticky_broadcast_timelineitems).order_by('-date')
96+
).order_by('-date')
9897

9998
return items
10099

editor/views/question.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def pre_save(self, form):
142142
def get_context_data(self, **kwargs):
143143
context = super(UpdateView, self).get_context_data(**kwargs)
144144

145-
extensions = Extension.objects.filter(Extension.filter_can_be_viewed_by(self.request.user)) | self.object.extensions.all()
145+
extensions = Extension.objects.filter(Extension.filter_can_be_viewed_by(self.user) | Q(pk__in=self.object.extensions.all()))
146146
extensions = extensions.distinct().order_by(Lower('name'))
147147
self.item_json['numbasExtensions'] = context['extensions'] = [e.as_json() for e in extensions]
148148

@@ -155,16 +155,15 @@ def get_context_data(self, **kwargs):
155155
self.item_json['editing_history_used'] = self.object.editoritem.comments.exists() or self.object.editoritem.restore_points.exists()
156156

157157
# get publicly available part types first
158-
custom_part_types = CustomPartType.objects.filter(public_availability='always')
158+
cpt_query = Q(public_availability='always')
159159
if not self.request.user.is_anonymous:
160160
# add in the user's own part types
161-
users = [self.request.user]+self.object.editoritem.project.members()
162-
custom_part_types |= CustomPartType.objects.filter(CustomPartType.filter_can_be_viewed_by(self.request.user))
161+
cpt_query |= CustomPartType.filter_can_be_viewed_by(self.request.user)
163162
# only show part types ready to use
164-
custom_part_types = custom_part_types.filter(ready_to_use=True)
163+
cpt_query &= Q(ready_to_use=True)
165164
# also include part types already in use in this question
166-
custom_part_types = custom_part_types | self.object.custom_part_types.all()
167-
custom_part_types = custom_part_types.distinct()
165+
cpt_query |= Q(pk__in=self.object.custom_part_types.all())
166+
custom_part_types = CustomPartType.objects.filter(cpt_query)
168167
self.item_json['custom_part_types'] = context['custom_part_types'] = [c.as_json() for c in custom_part_types]
169168

170169
self.item_json['resources'] = [r.as_json() for r in self.object.resources.all()]

0 commit comments

Comments
 (0)