Skip to content

N+1 when using a prefetch_related without explicit ordering #772

@taobojlen

Description

@taobojlen

Describe the Bug

When using prefetch_related on a resolver, unless you explicitly define an ordering, there's an N+1.

@strawberry_django.type(MyModel)
class MyModelType(strawberry.relay.Node):
    # this causes an N+1 on MyModel.foo_set when it's resolved
    @strawberry.django.field(prefetch_related=[Prefetch("foo_set", queryset=Foo.objects.filter(bar="baz")])
    def my_resolver(self) -> list[Foo]:
        # do something

    # this causes an N+1 on MyModel.bar_set
    @strawberry.django.field(prefetch_related=["bar_set"])
    def other_resolver(self) -> list[Bar]:
        # do something

    # no N+1 here
    @strawberry.django.field(prefetch_related=[Prefetch("foo_set", queryset=Foo.objects.filter(bar="baz").order_by("pk")])
    def third_resolver(self) -> list[Foo]:
        # do something

We have a number of resolvers with prefetch_related. When I updated from strawberry-django 0.54.0 to 0.62.0, I started getting N+1 errors (via django-zeal, a library to detect N+1s). I also saw some of my tests failing because the DB query count was higher than expected.

Using git bisect, I tracked this down to a specific change in strawberry-django: #715

Since then, if using custom querysets in your prefetches, it seems you have to add an explicit .order_by() clause to avoid N+1s.

System Information

  • Operating system: MacOS 15.5
  • Python version: 3.12.8
  • Strawberry version (if applicable): 0.275.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions