~/notes / django-orm-select-prefetch

2026-02-24🐍 Python1 мин0 просм.

Django ORM: select_related vs prefetch_related

В чём разница

Оба метода решают проблему N+1 запросов, но работают по-разному. select_related делает JOIN на уровне SQL, prefetch_related — отдельный запрос с WHERE id IN (...).

select_related

Используй для ForeignKey и OneToOne — там всегда один объект на другой стороне:

# Один SQL запрос с JOIN
notes = Note.objects.select_related('category').all()
for note in notes:
    print(note.category.name)  # нет дополнительных запросов

prefetch_related

Для ManyToMany и обратных ForeignKey — там может быть много объектов:

# Два SQL запроса: один для notes, один для tags
notes = Note.objects.prefetch_related('tags').all()
for note in notes:
    print([t.name for t in note.tags.all()])  # нет N+1

Комбинирование

Можно и нужно комбинировать:

notes = Note.objects.select_related('category').prefetch_related('tags')

Когда что выбирать

  • ForeignKey → select_related
  • ManyToMany → prefetch_related
  • Обратный FK (related_name) → prefetch_related
  • Глубокие цепочки (author__profile__city) → select_related

Профилировка

Используй django-debug-toolbar или django.db.connection.queries чтобы убедиться что запросов действительно меньше. Иногда prefetch_related с большим IN-списком медленнее чем N+1 для маленьких выборок.