Opened 15 years ago
Closed 10 years ago
#15020 closed Bug (fixed)
Redundant joins generated when using reverse foreign key
| Reported by: | Andy Durdin | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | me@… | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
A query using a reverse foreign key generates a left outer join to a related table and a second, redundant left outer join to the original table.
Tested in Django 1.1 and trunk r15147, and found to be an issue in both.
Using these models:
from django.db import models
class Original(models.Model):
pass # Don't need anything more for this test
class Reference(models.Model):
original = models.ForeignKey(Original, primary_key=True)
Background: the Reference model is used for storing and testing set membership; an Original instance is a member of the set iff its PK is in the Reference table.
Incorrect query was generated for this queryset:
Original.objects.filter(reference__pk__isnull=True)
Generated SQL:
SELECT `fkpk_original`.`id` FROM `fkpk_original` LEFT OUTER JOIN `fkpk_reference` ON (`fkpk_original`.`id` = `fkpk_reference`.`original_id`) LEFT OUTER JOIN `fkpk_original` T3 ON (`fkpk_reference`.`original_id` = T3.`id`) WHERE T3.`id` IS NULL
Expected SQL:
SELECT `fkpk_original`.`id` FROM `fkpk_original` LEFT OUTER JOIN `fkpk_reference` ON (`fkpk_original`.`id` = `fkpk_reference`.`original_id`) WHERE `fkpk_reference`.`original_id` IS NULL
Notes
An incorrect query is also generated for the following queryset; however this seems to be covered by #14056:
Original.objects.filter(reference__pk__isnull=False)
Change History (7)
comment:1 by , 15 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
| Triage Stage: | Unreviewed → Accepted |
comment:2 by , 15 years ago
To clarify: I found incorrect queries when I was using the two variations on this queryset, ...isnull=True, and ...isnull=False. I presumed that they were related, since it was only a parameter to the queryset that I was changing. I found #14056 when searching to see if this was a reported issue, and found that its description and patch matched and fixed only the second of the two incorrect queries. That could be coincidental; I wasn't able to follow the query generation well enough to know.
comment:3 by , 15 years ago
| Owner: | changed from to |
|---|---|
| Status: | assigned → new |
Not sure how this got assigned to me
comment:4 by , 15 years ago
| Severity: | → Normal |
|---|---|
| Type: | → Bug |
comment:7 by , 10 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
Seems to be fixed in Django 1.6.
I'm not sure I see the connection with #14056, but this certainly appears to be a problem. I'm going to guess that it's the primary_key=True on a ForeignKey that is causing the confusion.