Запрос order_by в Django выполняется невероятно медленно в Python, но быстро в DB

У меня есть следующие модели:

class Shelf(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField(max_length=200, editable=False)
    games = models.ManyToManyField(Game, blank=True, through='SortedShelfGames')
    objects = ShelfManager()
    description = models.TextField(blank=True, null=True)

class SortedShelfGames(models.Model):
    game = models.ForeignKey(Game, on_delete=models.CASCADE)
    shelf = models.ForeignKey(Shelf, on_delete=models.CASCADE)
    date_added = models.DateTimeField()
    order = models.IntegerField(blank=True, null=True)
    releases = models.ManyToManyField(Release)
    objects = SortedShelfGamesManager.as_manager()

class Game(models.Model):
    name = models.CharField(max_length=300, db_index=True)
    sort_name = models.CharField(max_length=300, db_index=True)
    ...

У меня есть представление, в котором я хочу получить все игры пользователя SortedShelfGames, отличающиеся по отношению Game. Затем я хочу иметь возможность сортировать этот список SortedShelfGames по нескольким различным полям. Поэтому сейчас я делаю следующее внутри SortedShelfGamesManager (который наследует от models.QuerySet), чтобы получить список:

games = self.filter(
   pk__in=Subquery(
      self.filter(shelf__user=user).distinct('game').order_by('game', 'date_added').values('pk') # The order_by statement in here is to get the earliest date_added field for display
   )
)

Это работает так, как должно. Однако, когда я пытаюсь сделать order_by('game__sort_name'), запрос выполняется вечно в моем python. Когда я пытаюсь использовать его на сайте, он просто завершается. Если я беру сгенерированный SQL и просто запускаю его в своей базе данных, он возвращает все результаты за доли секунды. Я не могу понять, что я делаю не так. В таблице SortedShelfGames миллионы записей, если это имеет значение.

Думаю, для этого не нужно Subquery.

Вот что я сделал, чтобы решить эту проблему. Вместо использования подзапроса я создал список первичных ключей, оценив то, что я использовал в качестве подзапроса, а затем ввел это в свой запрос. Это выглядит следующим образом:

pks = list(self.filter(shelf__user=user).distinct('game').values_list('pk', flat=True))
games = self.filter(
   pk__in=pks)
)
games = games.order_by('game__sort_name')

В итоге это оказалось довольно быстро. По сути, это то же самое, что и метод Subquery, но все, что происходило под капотом в python/Django, замедляло этот процесс.

Вернуться на верх