Whether the occurrence of LEFT OUTER JOIN is an issue in itself, I cannot say, but, in any case, it may be interesting to note in which cases these outer joins actually occur.
This is a naive attempt to illustrate the above, using some example queries.
Suppose we have some models using multi-table inheritance as follows:
from django.db import models class Parent(models.Model): parent_field = models.CharField(max_length=10) class ChildOne(Parent): child_one_field = models.CharField(max_length=10) class ChildTwo(Parent): child_two_field = models.CharField(max_length=10)
By default, the child instances get a parent_ptr and parent instances can access child objects (if they exist) using childone or childtwo. Note that parent_ptr represents a one-to-one relation which is used as the primary key (the actual child tables have no id column).
Here's a quick-and-dirty unit test with some naive Django query examples, showing the corresponding number of occurrences of INNER JOIN and OUTER JOIN in the SQL:
import re from django.test import TestCase from inheritance.models import (Parent, ChildOne, ChildTwo) def count_joins(query, inner_outer): """ Count the occurrences of JOIN in the query """ return len(re.findall('{} join'.format(inner_outer), str(query).lower())) class TestMultiTableInheritance(TestCase): def test_queries(self): # get children (with parent info) query = ChildOne.objects.all().query self.assertEqual(1, count_joins(query, 'inner')) self.assertEqual(0, count_joins(query, 'outer')) # get parents query = Parent.objects.all().query self.assertEqual(0, count_joins(query, 'inner')) self.assertEqual(0, count_joins(query, 'outer')) # filter children by parent field query = ChildOne.objects.filter(parent_field=parent_value).query self.assertEqual(1, count_joins(query, 'inner')) self.assertEqual(0, count_joins(query, 'outer')) # filter parents by child field query = Parent.objects.filter(childone__child_one_field=child_value).query self.assertEqual(1, count_joins(query, 'inner')) self.assertEqual(0, count_joins(query, 'outer')) # get child field values via parent query = Parent.objects.values_list('childone__child_one_field').query self.assertEqual(0, count_joins(query, 'inner')) self.assertEqual(1, count_joins(query, 'outer')) # get multiple child field values via parent query = Parent.objects.values_list('childone__child_one_field', 'childtwo__child_two_field').query self.assertEqual(0, count_joins(query, 'inner')) self.assertEqual(2, count_joins(query, 'outer')) # get child-two field value from child-one, through parent query = ChildOne.objects.values_list('parent_ptr__childtwo__child_two_field').query self.assertEqual(1, count_joins(query, 'inner')) self.assertEqual(1, count_joins(query, 'outer')) # get parent field value from parent, but through child query = Parent.objects.values_list('childone__parent_field').query self.assertEqual(0, count_joins(query, 'inner')) self.assertEqual(2, count_joins(query, 'outer')) # filter parents by parent field, but through child query = Parent.objects.filter(childone__parent_field=parent_value).query self.assertEqual(2, count_joins(query, 'inner')) self.assertEqual(0, count_joins(query, 'outer'))
Note, not all of these queries make sense: they are just for illustrative purposes.
Also note that this test code is not DRY, but that is on purpose.
What are the alternatives to multi-table inheritance when I need to reference a base class in another model?Could you clarify what you mean by this?