【问题标题】:Django rest framework extremly slow (recursive relations)Django rest 框架极慢(递归关系)
【发布时间】:2019-01-31 23:59:17
【问题描述】:

对于我的项目,我开始使用 Laravel 作为 api,而不是切换到 Django / django rest 框架,我这样做是为了获得更快的速度,因为我需要查询大数据。

现在我遇到了以下情况: 我有一个“组”,它有“主题”并且有递归关系。

现在一个组可以有 2000 多个科目(包括后代科目),而父科目有 +/- 30 个科目。

这是我的代码:

序列化器

class RecursiveField(serializers.Serializer):
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data

class SubjectSerializer(serializers.ModelSerializer):
    parent_of = RecursiveField(many=True, read_only=True)

    class Meta:
        model = Subject
        fields = ("id", "name", "parent_of", "parent")

class GroupSerializer(serializers.ModelSerializer):
    subjects = SubjectSerializer(many=True, read_only=True)

    class Meta:
        model = Group
        fields = ("id", "name", "subjects")

    def setup_eager_loading(cls, queryset):
        return queryset.prefetch_related("subjects")

观看次数

class GroupViewSet(ModelViewSet):

    class Paginator(BasePaginator):
        model = Group

    queryset = Group.objects.all()
    serializer_class = serializers.GroupSerializer
    pagination_class = Paginator

    def get_queryset(self):
        return self.get_serializer().setup_eager_loading(GroupViewSet.queryset)

我用 laravel api 测试了相同的请求,它的速度要快得多,仍然明显慢,但没问题(5-10 秒)。使用 django rest 框架太慢(1 分钟 +/-),而这只是一个包含 1 个组的页面,该组有 2500 个主题。

我确实知道 RecursiveField 类需要很长时间,因为当我删除时,查询会在不到 2 秒的时间内完成。所以我的问题是主要原因是什么,因为它创建了递归关系(我怀疑)?还是因为我没有预取?

当然,最好的方法是什么?

谢谢

【问题讨论】:

标签: django django-rest-framework


【解决方案1】:

你有几个选择,但我认为没有一个很好。 Django 不太支持递归查询。

  1. 重新设计您的数据模型,以防止需要使用递归从数据库中获取主题。您可以将 root ForeignKey 添加到 Subject on Subject 以识别根主题。这将允许您相当轻松地抓取树中的所有主题。然后你必须在你的视图/视图集中排列它们以适应顺序(如果有必要的话)。
  2. 使用raw() 和数据库的递归功能来获取模型。这将需要原始 SQL,而且维护起来会很痛苦。
  3. 使用django_cte。我已经在我的一个项目中使用它进行了一些查询,但我不是它的忠实粉丝。它破坏了一些功能,update() 在空查询集上被调用。但是,它会起作用,并且不需要您使用原始 SQL。

【讨论】:

  • 我仍然相信递归关系在数据结构中是正常的。但是我已经改变了数据结构,它似乎没有帮助,我不知道 django rest 框架在做什么,但它在处理完全没有关系的大数据时非常慢......例如,如果我想检索一个组的所有主题,加载大约需要 20-30 秒...
  • 添加 Django 调试工具栏,看看它在做什么。
【解决方案2】:

问题不在于 DRF,而在于数据结构本身。

django 递归查询所有祖先/后代非常慢,您应该使用更高效的数据结构。

出于同样的原因,我写了django-treenode,它执行树操作而不查询数据库。 你可以在这里阅读文档:https://github.com/fabiocaccamo/django-treenode

【讨论】:

    猜你喜欢
    • 2012-10-25
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多