Friday, 3 December 2021

Speed up order_by and pagination in Django

Currently I have this result:

Silky sql

That's not bad (I guess), but I'm wondering if I can speed things up a little bit.

I've looked at penultimate query and don't really know how to speed it up, I guess I should get rid off join, but don't know how:

query

I'm already using prefetch_related in my viewset, my viewset is:


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)

Join is happening because I'm ordering on a related field?

My models looks like:

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()

And my serializers:

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)

Also results of profling:

        166039 function calls (159016 primitive calls) in 3.226 seconds

   Ordered by: internal time
   List reduced from 677 to 100 due to restriction <100>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
20959/20958    0.206    0.000    0.283    0.000 {built-in method builtins.isinstance}
     2700    0.123    0.000    0.359    0.000 fields.py:62(is_simple_callable)
   390/30    0.113    0.000    1.211    0.040 serializers.py:493(to_representation)
8943/8473    0.098    0.000    0.307    0.000 {built-in method builtins.getattr}
     2700    0.096    0.000    0.650    0.000 fields.py:85(get_attribute)
       14    0.068    0.005    0.130    0.009 traceback.py:388(format)
     7653    0.065    0.000    0.065    0.000 {method 'append' of 'list' objects}
       28    0.064    0.002    0.072    0.003 {method 'execute' of 'psycopg2.extensions.cursor' objects}
      390    0.062    0.000    0.153    0.000 base.py:406(__init__)
     3090    0.060    0.000    0.257    0.000 serializers.py:359(_readable_fields)
     3090    0.059    0.000    0.093    0.000 _collections_abc.py:760(__iter__)
     6390    0.055    0.000    0.055    0.000 {built-in method builtins.hasattr}
     1440    0.054    0.000    0.112    0.000 related.py:652(get_instance_value_for_fields)
     2749    0.052    0.000    0.078    0.000 abc.py:96(__instancecheck__)
      388    0.052    0.000    0.107    0.000 query.py:303(clone)
     2700    0.049    0.000    0.072    0.000 inspect.py:158(isfunction)
     2700    0.048    0.000    0.699    0.000 fields.py:451(get_attribute)
     2702    0.048    0.000    0.071    0.000 inspect.py:80(ismethod)
     2701    0.047    0.000    0.070    0.000 inspect.py:285(isbuiltin)
       14    0.047    0.003    0.189    0.014 traceback.py:321(extract)
3786/3426    0.043    0.000    0.123    0.000 {built-in method builtins.setattr}
 4445/247    0.038    0.000    1.936    0.008 {built-in method builtins.len}
      360    0.035    0.000    0.374    0.001 related_descriptors.py:575(_apply_rel_filters)
     2247    0.034    0.000    0.088    0.000 traceback.py:285(line)
     3203    0.029    0.000    0.029    0.000 {method 'copy' of 'dict' objects}
       12    0.028    0.002    1.836    0.153 query.py:1831(prefetch_one_level)
     2749    0.026    0.000    0.026    0.000 {built-in method _abc._abc_instancecheck}
     2700    0.024    0.000    0.024    0.000 serializer_helpers.py:154(__getitem__)
     2780    0.024    0.000    0.024    0.000 {method 'get' of 'dict' objects}
      360    0.023    0.000    0.069    0.000 related_lookups.py:26(get_normalized_value)
      720    0.022    0.000    0.458    0.001 related_descriptors.py:615(get_queryset)
      744    0.022    0.000    0.087    0.000 related_descriptors.py:523(__get__)
      360    0.022    0.000    0.057    0.000 related_descriptors.py:203(__set__)
      470    0.022    0.000    0.081    0.000 local.py:46(_get_context_id)
      749    0.020    0.000    0.048    0.000 linecache.py:15(getline)
      720    0.019    0.000    0.031    0.000 lookups.py:252(resolve_expression_parameter)
    361/1    0.018    0.000    1.211    1.211 serializers.py:655(to_representation)
   296/14    0.018    0.000    0.084    0.006 copy.py:128(deepcopy)
      470    0.018    0.000    0.106    0.000 local.py:82(_get_storage)
      732    0.017    0.000    0.043    0.000 related_descriptors.py:560(__init__)
      720    0.017    0.000    0.040    0.000 related_descriptors.py:76(__set__)
1185/1151    0.017    0.000    0.032    0.000 {method 'join' of 'str' objects}
     1501    0.017    0.000    0.017    0.000 {method 'format' of 'str' objects}
      732    0.016    0.000    0.026    0.000 manager.py:26(__init__)
      372    0.016    0.000    0.414    0.001 query.py:951(_filter_or_exclude)
       14    0.016    0.001    0.028    0.002 traceback.py:369(from_list)
      759    0.015    0.000    0.040    0.000 query.py:178(__init__)
      387    0.015    0.000    0.143    0.000 query.py:1308(_clone)
      732    0.015    0.000    0.022    0.000 manager.py:20(__new__)
     1710    0.015    0.000    0.015    0.000 {built-in method __new__ of type object at 0x7fa87d9ad940}
      720    0.015    0.000    0.034    0.000 __init__.py:1818(get_prep_value)
      470    0.014    0.000    0.033    0.000 sync.py:469(get_current_task)
      390    0.014    0.000    0.174    0.000 base.py:507(from_db)
     1365    0.014    0.000    0.014    0.000 {method 'update' of 'dict' objects}
      749    0.013    0.000    0.022    0.000 linecache.py:37(getlines)
      744    0.013    0.000    0.044    0.000 lookups.py:266()
       12    0.013    0.001    0.054    0.004 lookups.py:230(get_prep_lookup)
      749    0.013    0.000    0.020    0.000 linecache.py:147(lazycache)
      720    0.013    0.000    0.066    0.000 related.py:646(get_local_related_value)
      720    0.013    0.000    0.071    0.000 related.py:649(get_foreign_related_value)
      720    0.013    0.000    0.019    0.000 __init__.py:824(get_prep_value)
     1506    0.013    0.000    0.013    0.000 {method 'strip' of 'str' objects}
   372/12    0.013    0.000    0.026    0.002 query.py:1088(resolve_lookup_value)
      638    0.013    0.000    0.018    0.000 threading.py:1306(current_thread)
      732    0.013    0.000    0.021    0.000 reverse_related.py:200(get_cache_name)
      720    0.013    0.000    0.018    0.000 base.py:573(_get_pk_val)
      360    0.012    0.000    0.021    0.000 __init__.py:543(__hash__)
      470    0.011    0.000    0.117    0.000 local.py:101(__getattr__)
       28    0.011    0.000    0.089    0.003 compiler.py:199(get_select)
      385    0.011    0.000    0.857    0.002 query.py:265(__iter__)
      320    0.011    0.000    0.019    0.000 __init__.py:515(__eq__)
      387    0.011    0.000    0.120    0.000 query.py:354(chain)
      780    0.011    0.000    0.021    0.000 dispatcher.py:159(send)
      360    0.010    0.000    0.031    0.000 related.py:976(get_prep_value)
      387    0.010    0.000    0.157    0.000 query.py:1296(_chain)
      372    0.010    0.000    0.014    0.000 query.py:151(__init__)
      403    0.010    0.000    0.914    0.002 query.py:45(__iter__)
     1204    0.010    0.000    0.010    0.000 {built-in method builtins.iter}
      360    0.010    0.000    0.016    0.000 :1017(_handle_fromlist)
      372    0.010    0.000    0.434    0.001 query.py:935(filter)
      360    0.010    0.000    0.023    0.000 query.py:1124(check_query_object_type)
      360    0.009    0.000    0.017    0.000 mixins.py:21(is_cached)
     1152    0.009    0.000    0.009    0.000 query.py:194(query)
      104    0.009    0.000    0.017    0.000 fields.py:323(__init__)
      732    0.009    0.000    0.009    0.000 manager.py:120(_set_creation_counter)
      470    0.009    0.000    0.013    0.000 :389(parent)
      470    0.009    0.000    0.014    0.000 tasks.py:34(current_task)
      459    0.009    0.000    0.013    0.000 deconstruct.py:14(__new__)
      870    0.009    0.000    0.009    0.000 fields.py:810(to_representation)
      322    0.009    0.000    0.019    0.000 linecache.py:53(checkcache)
  318/266    0.009    0.000    0.145    0.001 compiler.py:434(compile)
      763    0.008    0.000    0.008    0.000 traceback.py:292(walk_stack)
      494    0.008    0.000    0.014    0.000 compiler.py:417(quote_name_unless_alias)
      396    0.008    0.000    0.019    0.000 related.py:710(get_path_info)
      374    0.008    0.000    0.011    0.000 utils.py:237(_route_db)
      796    0.008    0.000    0.008    0.000 tree.py:21(__init__)
      322    0.008    0.000    0.008    0.000 {built-in method posix.stat}
  413/365    0.008    0.000    1.938    0.005 query.py:1322(_fetch_all)
       12    0.008    0.001    1.244    0.104 related_descriptors.py:622(get_prefetch_queryset)
      732    0.008    0.000    0.008    0.000 reverse_related.py:180(get_accessor_name)

And visual representation:

enter image description here

So, my questions is, how can I speed it up?



from Speed up order_by and pagination in Django

No comments:

Post a Comment