From 1ff0113d2eba8fd8662daf72446d5e5bc6556e23 Mon Sep 17 00:00:00 2001 From: kimarakov Date: Sun, 7 Jan 2018 14:18:29 -0800 Subject: [PATCH] Index all generic foreign keys to improve query performance 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. --- schedule/migrations/0008_gfk_index.py | 30 +++++++++++++++++++++++++++ schedule/models/calendars.py | 5 +++-- schedule/models/events.py | 7 ++++--- 3 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 schedule/migrations/0008_gfk_index.py diff --git a/schedule/migrations/0008_gfk_index.py b/schedule/migrations/0008_gfk_index.py new file mode 100644 index 0000000..a80824d --- /dev/null +++ b/schedule/migrations/0008_gfk_index.py @@ -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')}, + ), + ] diff --git a/schedule/models/calendars.py b/schedule/models/calendars.py index a59e424..559c100 100644 --- a/schedule/models/calendars.py +++ b/schedule/models/calendars.py @@ -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 @@ -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) @@ -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) diff --git a/schedule/models/events.py b/schedule/models/events.py index 857731e..241a2ff 100644 --- a/schedule/models/events.py +++ b/schedule/models/events.py @@ -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=''): @@ -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) @@ -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)