Opened 46 minutes ago
Last modified 46 minutes ago
#37344 new Cleanup/optimization
Document that FETCH_PEERS does not apply to instances loaded by select_related()
| Reported by: | Mykhailo Havelia | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 6.1 |
| Severity: | Normal | Keywords: | fetch_mode, FETCH_PEERS, select_related, peers |
| Cc: | Mykhailo Havelia | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Description
Combining select_related() with FETCH_PEERS silently disables peer batching one level below the join, turning an intended optimization into an N+1 and making the query count *worse* than not calling select_related() at all.
Given Species -> Genus -> Family:
# 3 queries: species, batch of genus, batch of family
for species in Species.objects.fetch_mode(FETCH_PEERS):
species.genus.family.name
# 4 queries: the join, then ONE QUERY PER FAMILY
for species in Species.objects.select_related("genus").fetch_mode(FETCH_PEERS):
species.genus.family.name
The second form emits:
SELECT ... FROM species INNER JOIN genus ON (species.genus_id = genus.id); SELECT ... FROM family WHERE family.id = 1 LIMIT 21; SELECT ... FROM family WHERE family.id = 2 LIMIT 21; SELECT ... FROM family WHERE family.id = 3 LIMIT 21;
Was it intended to be this way? If so, I think it’s worth mentioning in the documentation.
Note:
See TracTickets
for help on using tickets.