Ускорение order_by и пагинации в Django

В настоящее время я имею следующий результат:

Silky sql

Это неплохо (я думаю), но мне интересно, могу ли я немного ускорить процесс.

Я просмотрел предпоследний запрос и не знаю, как его ускорить, я думаю, мне нужно избавиться от join, но не знаю как:

query

Я уже использую prefetch_related в своем наборе представлений, мой набор представлений:


class GameViewSet(viewsets.ModelViewSet):
    queryset = Game.objects.prefetch_related(
        "timestamp",
        "fighters",
        "score",
        "coefs",
        "rounds",
        "rounds_view",
        "rounds_view_f",
        "finishes",
        "rounds_time",
        "round_time",
        "time_coef",
        "totals",
    ).all()
    serializer_class = GameSerializer
    permission_classes = [AllowAny]
    pagination_class = StandardResultsSetPagination

    @silk_profile(name="Get Games")
    def list(self, request):
        qs = self.get_queryset().order_by("-timestamp__ts")
        page = self.paginate_queryset(qs)
        if page is not None:
            serializer = GameSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(qs, many=True)
        return Response(serializer.data)

Соединение происходит потому, что я делаю заказ по связанному полю?

Мои модели выглядят следующим образом:

class Game(models.Model):
    id = models.AutoField(primary_key=True)

...
class Timestamp(models.Model):
    id = models.AutoField(primary_key=True)
    game = models.ForeignKey(Game, related_name="timestamp", on_delete=models.CASCADE)
    ts = models.DateTimeField(db_index=True)
    time_of_day = models.TimeField()

И мои сериализаторы:

class TimestampSerializer(serializers.Serializer):
    ts = serializers.DateTimeField(read_only=True)
    time_of_day = serializers.TimeField(read_only=True)



class GameSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    timestamp = TimestampSerializer(many=True)
    fighters = FighterSerializer(many=True)
    score = ScoreSerializer(many=True)
    coefs = CoefsSerializer(many=True)
    rounds = RoundsSerializer(many=True)
    rounds_view = RoundsViewSerializer(many=True)
    rounds_view_f = RoundsViewFinishSerializer(many=True)
    finishes = FinishesSerializer(many=True)
    rounds_time = RoundTimesSerializer(many=True)
    round_time = RoundTimeSerializer(many=True)
    time_coef = TimeCoefsSerializer(many=True)
    totals = TotalsSerializer(many=True)

Также результаты профилирования:

И визуальное представление:

enter image description here

Итак, мои вопросы: как я могу ускорить это?

На стороне базы данных вы можете создать материализованное представление для вашего запроса и запускать обновление при добавлении новой временной метки (или при любом другом событии в вашем приложении, требующем обновления). Таким образом, результаты будут предварительно рассчитаны для вашего поиска. Однако я полагаю, что могут быть граничные случаи, когда при одновременном обновлении и поиске вы получаете предварительно обновленный результат? Это будет компромисс, и только вы знаете, стоит ли это того...

В любом случае, не я это придумал, посмотрите, например, https://hashrocket.com/blog/posts/materialized-view-strategies-using-postgresql

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