Django rest framework的ModelSerializer运行速度太慢

3
我们希望为我们的Django项目提供API,因此我们使用DRF(Django Rest Framework)。 我们使用ModelSerializer,它提供了一种快捷方式,可以自动创建一个Serializer类,其中包含与Model字段对应的字段。 我们的问题是它运行得非常慢。换句话说,序列化过程大约需要40秒才能检索到响应。 我们该如何减少这种延迟?
视图
class MyObjViewSet(viewsets.ModelViewSet):

    pagination_class = LargeResultsSetPagination

    def get_queryset(self):
        queryset = MyObj.objects.all().order_by('time')
        return queryset

    serializer_class = MyObjSerializer

我的 Obj 模型

class MyObj(models.Model):
    id = models.BigIntegerField(primary_key=True)
    time = models.DateTimeField()
    type = models.CharField(max_length=5)
    user = models.ForeignKey('User', related_name='myobj')

我的对象用户模型

class User(models.Model):
    id = models.IntegerField(primary_key=True)
    username = models.CharField(max_length=80)

我的对象序列化器
class MyObjSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyObj
        fields = ('id', 'type', 'time', 'user')

我的问题是当我想要检索我的对象列表时,需要大约40秒钟的时间!


1
@KevinBrown:不,这不是我的问题! - Haydar Ghasemi
你确定吗?它看起来非常相似(使用另一个模型的外键),这也在这里解释了https://ses4j.github.io/2015/11/23/optimizing-slow-django-rest-framework-performance/。 - PerroVerd
我仍然欢迎对这个问题的新回答,我相信Django序列化器很慢。 :/ 而且这不是一个数据库问题。 - EralpB
3个回答

8
实际上,这是drf的一个真正的问题。
如果查询集返回了大量对象,则需要执行以下几个步骤:
1. 检查是否使用了many=True,这将产生显著的性能提升。
2. 避免在大型对象集上使用ModelSerializer。事实上,值得注意的是要避免任何类型的rest_framework.Serializer
3. 尝试使用serpy库进行序列化。但是您不应忘记它与rest_framework.Serializer不完全兼容。
4. 使用.values()DictSerializer。这将大大加快序列化速度。
5. 不要忘记在数据库中使用索引。 6. 在使用ForeignKey时使用诸如prefetch_relatedselect_related等强大的功能。
7. 最后一种方式是使用简单的dict。否则,我没有得到明显的结果:与使用serpyDictSerializer相比,只有10%的差距。

我曾遇到这样的情况,需要序列化许多对象(约3-5k),而来自drf序列化器的开销至少为2.5秒(不包括sql的时间)。优化后,我得到了约200-300毫秒。

希望drf的开发人员能在框架中进行一些性能改进。


1

小伙子,不要使用"MyObj.objects.all().order_by('time')",如果你有上百条数据,这样做会非常耗时......这并不是序列化程序的问题,而是排序问题。你可以限制搜索时间,使用:

1、gt:大于

now = datetime.datetime.now()
#yesterday
start = now – datetime.timedelta(hours=23, minutes=59, seconds=59)
a=yourobject.objects .filter(youdatetimcolumn__gt=start)

2、gte:大于或等于

a=yourobject.objects .filter(youdatetimcolumn__gte=start)

3、lt:小于
a=yourobject.objects .filter(youdatetimcolumn__lt=start)

4、lte:小于等于

a=yourobject.objects .filter(youdatetimcolumn__lte=start)

5、range:一个时间范围

start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

6、year:其中的一年

Entry.objects.filter(pub_date__year=2005)

7、month:一个月份

Entry.objects.filter(pub_date__month=12)

8、day:一天

Entry.objects.filter(pub_date__day=3)

9、week_day:一个工作日

Entry.objects.filter(pub_date__week_day=2)

来源: https://www.cnblogs.com/linjiqin/p/3821914.html

如果需要使用 get.all,那么不要使用 "order_by_time",通常情况下,不使用 order_by_time 可以使您的请求更快,您只需要在获取这些数据后进行排序即可。


0
这不是序列化器的问题,问题出在查询上。
你获取了所有对象,我假设它们数量很大,因为有分页,而且你希望它们按时间排序。问题在于模型定义没有提示数据库在时间字段上创建索引。
尝试添加提示,在数据库中创建索引,速度会提高。
  class MyObj(models.Model):
      id = models.BigIntegerField(primary_key=True)
      time = models.DateTimeField(db_index=True)
      type = models.CharField(max_length=5)
      user = models.ForeignKey('User', related_name='myobj')

谢谢,我已经做了,但问题仍然存在! - Haydar Ghasemi
1
看看这个 https://dev59.com/wV8e5IYBdhLWcg3wFnLm 关于迁移,但是正如你所说,查询时间看起来很正常,所以我没有线索。 - PerroVerd
查询时间正常!我猜我的问题与DRF逻辑有关,而不是数据库。但我找不到解决方案。我的意思是找到和检索查询集的过程很重要... - Haydar Ghasemi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接