Skip to content

Commit

Permalink
Index all generic foreign keys to improve query performance
Browse files Browse the repository at this point in the history
It is generally recommended that relationship fields should be indexed.
It is considered a misfeature that Django's GFKs do not created indexes
by default. For example, see the discussion at:

https://code.djangoproject.com/ticket/23435

To avoid this performance pitfall, add the necessary indexes.
  • Loading branch information
kimarakov committed Jan 7, 2018
1 parent 55b59fe commit 1ff0113
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 5 deletions.
30 changes: 30 additions & 0 deletions schedule/migrations/0008_gfk_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('schedule', '0007_merge_text_fields'),
]

operations = [
migrations.AlterField(
model_name='calendarrelation',
name='object_id',
field=models.IntegerField(db_index=True),
),
migrations.AlterField(
model_name='eventrelation',
name='object_id',
field=models.IntegerField(db_index=True),
),
migrations.AlterIndexTogether(
name='calendarrelation',
index_together={('content_type', 'object_id')},
),
migrations.AlterIndexTogether(
name='eventrelation',
index_together={('content_type', 'object_id')},
),
]
5 changes: 3 additions & 2 deletions schedule/models/calendars.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def get_calendars_for_object(self, obj, distinction=''):
dist_q = Q(calendarrelation__distinction=distinction)
else:
dist_q = Q()
return self.filter(dist_q, calendarrelation__object_id=obj.id, calendarrelation__content_type=ct)
return self.filter(dist_q, calendarrelation__content_type=ct, calendarrelation__object_id=obj.id)


@python_2_unicode_compatible
Expand Down Expand Up @@ -226,7 +226,7 @@ class CalendarRelation(with_metaclass(ModelBase, *get_model_bases('CalendarRelat

calendar = models.ForeignKey(Calendar, on_delete=models.CASCADE, verbose_name=_("calendar"))
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.IntegerField()
object_id = models.IntegerField(db_index=True)
content_object = fields.GenericForeignKey('content_type', 'object_id')
distinction = models.CharField(_("distinction"), max_length=20)
inheritable = models.BooleanField(_("inheritable"), default=True)
Expand All @@ -237,6 +237,7 @@ class Meta(object):
verbose_name = _('calendar relation')
verbose_name_plural = _('calendar relations')
app_label = 'schedule'
index_together = [('content_type', 'object_id')]

def __str__(self):
return '%s - %s' % (self.calendar, self.content_object)
7 changes: 4 additions & 3 deletions schedule/models/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,13 +506,13 @@ def get_events_for_object(self, content_object, distinction='', inherit=True):
if inherit:
inherit_q = Q(
cal_dist_q,
calendar__calendarrelation__object_id=content_object.id,
calendar__calendarrelation__content_type=ct,
calendar__calendarrelation__object_id=content_object.id,
calendar__calendarrelation__inheritable=True,
)
else:
inherit_q = Q()
event_q = Q(dist_q, eventrelation__object_id=content_object.id, eventrelation__content_type=ct)
event_q = Q(dist_q, eventrelation__content_type=ct, eventrelation__object_id=content_object.id)
return Event.objects.filter(inherit_q | event_q)

def create_relation(self, event, content_object, distinction=''):
Expand Down Expand Up @@ -547,7 +547,7 @@ class EventRelation(with_metaclass(ModelBase, *get_model_bases('EventRelation'))
'''
event = models.ForeignKey(Event, on_delete=models.CASCADE, verbose_name=_("event"))
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.IntegerField()
object_id = models.IntegerField(db_index=True)
content_object = fields.GenericForeignKey('content_type', 'object_id')
distinction = models.CharField(_("distinction"), max_length=20)

Expand All @@ -557,6 +557,7 @@ class Meta(object):
verbose_name = _("event relation")
verbose_name_plural = _("event relations")
app_label = 'schedule'
index_together = [('content_type', 'object_id')]

def __str__(self):
return '%s(%s)-%s' % (self.event.title, self.distinction, self.content_object)
Expand Down

0 comments on commit 1ff0113

Please sign in to comment.