【问题标题】:Django-rest-framework performance issuesDjango-rest-framework 性能问题
【发布时间】:2020-11-15 22:53:54
【问题描述】:

大家好,这是我的视图类

class ModuleViewSet(mixins.CreateModelMixin,
                    mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.ListModelMixin,
                    viewsets.GenericViewSet):
    queryset = models.Module.objects.all()
    permission_classes = [ModuleViewPermission]
    serializer_class = serializers.ModuleSerializer

我已将 django.db 记录器转为 INFO 级别,以查看正在执行的实际数据库查询。以下是我的发现:

  1. 获取模块列表:
2020-07-26 19:22:18,062 DEBUG utils:110 e70f16f5c7494c8783ca9f5a6bea22c4 (0.013) SELECT "courses_module"."id", "courses_module"."course_id", "courses_module"."name", "courses_module"."number" FROM "courses_module"; args=() django.db.backends
2020-07-26 19:22:18,090 INFO basehttp:154 e70f16f5c7494c8783ca9f5a6bea22c4 "GET /api/courses/modules/ HTTP/1.1" 200 99 django.server
  1. 获取单个对象:
2020-07-26 19:23:26,143 DEBUG utils:110 f1332e4a5e2247709dc784dc2f8b6d19 (0.005) SELECT "courses_module"."id", "courses_module"."course_id", "courses_module"."name", "courses_module"."number" FROM "courses_module"; args=() django.db.backends
2020-07-26 19:23:27,331 DEBUG utils:110 f1332e4a5e2247709dc784dc2f8b6d19 (0.003) SELECT "courses_module"."id", "courses_module"."course_id", "courses_module"."name", "courses_module"."number" FROM "courses_module" WHERE "courses_module"."id" = 1; args=(1,) django.db.backends
2020-07-26 19:23:27,342 DEBUG utils:110 f1332e4a5e2247709dc784dc2f8b6d19 (0.006) SELECT "courses_course"."id", "courses_course"."name", "courses_course"."description", "courses_course"."price_group_id" FROM "courses_course" WHERE "courses_course"."id" = 1; args=(1,) django.db.backends
2020-07-26 19:23:27,359 DEBUG utils:110 f1332e4a5e2247709dc784dc2f8b6d19 (0.015) SELECT "user_user"."id", "user_user"."password", "user_user"."last_login", "user_user"."is_superuser", "user_user"."username", "user_user"."is_staff", "user_user"."is_active", "user_user"."date_joined", "user_user"."email", "user_user"."first_name", "user_user"."last_name" FROM "user_user" INNER JOIN "courses_course_authors" ON ("user_user"."id" = "courses_course_authors"."user_id") WHERE "courses_course_authors"."course_id" = 1; args=(1,) django.db.backends
2020-07-26 19:23:27,375 INFO basehttp:154 f1332e4a5e2247709dc784dc2f8b6d19 "GET /api/courses/modules/1/ HTTP/1.1" 200 45 django.server

对于 1,选择所有可能是正确的,但根据文档查询集是 cached 用于即将到来的请求。但是在 get_queryset() 方法中我们可以看到我们是re-evaluating queryset

除了这个矛盾。 获取单个对象 (pt 2) 的结果更令人担忧。因为我们首先选择所有对象,然后再次通过 Id 选择模块对象。最后 2 个查询用于检查对象的用户权限(可接受)。

如果我的观点有问题,或者这是 django rest 框架的已知性能问题,请告诉我。也提过这个问题here

如果表中有数百万条记录,这可能是一个主要问题。

谢谢

【问题讨论】:

    标签: django django-rest-framework django-queryset


    【解决方案1】:

    我已经找到了这种杂项行为背后的原因。查询集是惰性的,只要我们期望得到结果就会计算它们。当我调试并悬停在查询集上时,查询正在执行,因为调试器正在期待结果。我可能错了。但是当我在非调试模式下运行它时,我无法重现上面的输出。以下是日志: 获取列表:

    
    2020-07-26 23:00:06,697 DEBUG utils:110 1c8a250d8f784aff9c4e5056e446ddf9 (0.004) SELECT "courses_module"."id", "courses_module"."course_id", "courses_module"."name", "courses_module"."number" FROM "courses_module"; args=() django.db.backends
    2020-07-26 23:00:06,706 INFO basehttp:154 1c8a250d8f784aff9c4e5056e446ddf9 "GET /api/courses/modules/ HTTP/1.1" 200 99 django.server
    
    

    获取对象:

    2020-07-26 22:59:47,120 DEBUG utils:110 018f23ade3774a44a7cd423c80f6fe59 (0.005) SELECT "courses_module"."id", "courses_module"."course_id", "courses_module"."name", "courses_module"."number" FROM "courses_module" WHERE "courses_module"."id" = 1; args=(1,) django.db.backends
    2020-07-26 22:59:47,125 DEBUG utils:110 018f23ade3774a44a7cd423c80f6fe59 (0.004) SELECT "courses_course"."id", "courses_course"."name", "courses_course"."description", "courses_course"."price_group_id" FROM "courses_course" WHERE "courses_course"."id" = 1; args=(1,) django.db.backends
    2020-07-26 22:59:47,137 DEBUG utils:110 018f23ade3774a44a7cd423c80f6fe59 (0.011) SELECT "user_user"."id", "user_user"."password", "user_user"."last_login", "user_user"."is_superuser", "user_user"."username", "user_user"."is_staff", "user_user"."is_active", "user_user"."date_joined", "user_user"."email", "user_user"."first_name", "user_user"."last_name" FROM "user_user" INNER JOIN "courses_course_authors" ON ("user_user"."id" = "courses_course_authors"."user_id") WHERE "courses_course_authors"."course_id" = 1; args=(1,) django.db.backends
    2020-07-26 22:59:47,168 INFO basehttp:154 018f23ade3774a44a7cd423c80f6fe59 "GET /api/courses/modules/1/ HTTP/1.1" 200 45 django.server
    

    仍然没有确认缓存 1(列表)的查询集。现在我们可以使用 2。

    谢谢 阿尼克特

    【讨论】:

    • cached_queryset = Model.objects.all() #第一个查询 --> 切片不会导致像 cached_queryset[0] 这样的查询不会命中数据库 ---> 但以防万一详细视图,它执行 .get() 即 cached_queryset.get(id=1) 将通过查询访问数据库。
    猜你喜欢
    • 2013-02-01
    • 1970-01-01
    • 2020-12-27
    • 2018-07-31
    • 2017-03-24
    • 2021-03-06
    • 2019-02-03
    • 2021-06-17
    • 2013-01-03
    相关资源
    最近更新 更多