首页 > 解决方案 > 优化 Django Rest ORM 查询

问题描述

我是一个反应前端,django 后端(用作 REST 后端)。我继承了该应用程序,它使用许多模型和序列化加载所有用户数据。它加载非常缓慢。它使用过滤器来查询单个成员,然后将其传递给序列化器:

found_account = Accounts.objects.get(id='customer_id')
AccountDetailsSerializer(member, context={'request': request}).data

然后有这么多各种嵌套的序列化器:

AccountDetailsSerializers(serializers.ModelSerializer):
   Invoices = InvoiceSerializer(many=True)
   Orders = OrderSerializer(many=True)
   ....

通过查看日志,看起来 ORM 发出了如此多的查询,这太疯狂了,对于某些端点,我们最终会收到 50 到 60 个查询。

  1. 我应该尝试研究使用 select_related 和 prefetch 还是跳过所有这些并尝试编写一个 sql 查询来执行多个连接并以 json 格式一次获取所有数据?

  2. 当我传入单个对象(get 的结果)而不是序列化程序的查询集时,如何定义预取/select_related?

  3. 一些 db 实体之间没有链接,这意味着不是 fk 或多对多关系,只是持有一个与另一个有 id 的字段,但在数据库中没有强制执行这种关系?这对我来说会是个问题吗?这是否再次意味着我应该跳过 select_related 方法并编写一个客户 sql 来获取?

  4. 您如何建议对这个噩梦般的查询进行性能调整?

标签: djangoperformancedjango-modelsdjango-rest-frameworkquery-performance

解决方案


我建议您先看看您会得到什么效果prefetch_related。它可能对加载时间产生重大影响,并且实施起来相当简单。按照上面的例子,这样的事情可以单独显着减少加载时间:

AccountDetailsSerializers(serializers.ModelSerializer):

    class Meta:
        model = AccountDetails
        fields = (
            'invoices',
            'orders',
        )

    invoices = serializers.SerializerMethodField()
    orders = serializers.SerializerMethodField()

    def get_invoices(self, obj):
        qs = obj.invoices.all()\
            .prefetch_related('invoice_sub_object_1')\
            .prefetch_related('invoice_sub_object_2')
        return InvoiceSerializer(qs, many=True, read_only=True).data

    def get_orders(self, obj):
        qs = obj.orders.all()\
            .prefetch_related('orders_sub_object_1')\
            .prefetch_related('orders_sub_object_2')
        return OrderSerializer(qs, many=True, read_only=True).data 

至于您的架构问题,我认为很多其他因素都在影响您是否应该重构代码库以及重构代码库的程度。不过总的来说,如果您与 Django 和 DRF 结合,如果您能够接受这些框架的习惯用法和模式,而不是试图通过自己的修复来购买它们,那么您将获得更好的开发人员体验。


推荐阅读