是什么导致DRF视图集执行低效的SQL查询?

时间:2019-06-05 21:18:19

标签: python django postgresql django-rest-framework

环境:

Django=="2.2"
Python=="3.6.8"
debug_toolbar=="1.11"
rest_framework=="3.8.2"

背景:

从基于函数的DRF端点切换到基于类的视图/视图集时,我发现基于类的视图在没有嵌套关系的情况下表现稍好,而在嵌套关系的情况下则差很多。

伪代码模型上下文:

Creator:
  ForeignKey.Shipments[]

Unit:
  ForeignKey.Shipments[]

Shipment:
  ForeignKey.Addresses[]
  ForeignKey.Creator
  ForeignKey.Unit

Address:
  Street
  City
  State

值得注意的序列化器上下文:

Unit:
  Meta:
    Depth = 1

Creator:
  Meta:
    Depth = Infinite

将上述结构的Viewset与等效的@apiview进行比较时,我发现:

  • /addresses在SQL查询计数(0.9x)上性能稍好,CPU开销为1.1倍(预期)
  • /creators在SQL查询计数(1.1x)上表现稍差,CPU开销为3.9x(预期)
  • 具有只读视图集的/creators/1在SQL查询计数(0.9x)和3.4x CPU开销(意外)上的执行效果略好
  • 具有可写视图集的
  • /creators/1在SQL查询计数(3.3x)上的性能明显较差,而CPU开销却高达5.9x(意料之外)
  • /units/1具有可写的视图集,在SQL查询计数(4.4x)上表现非常差,CPU开销却高达7.9x(非常意外)
  • 两种视图集都无法完全受益于/完全忽略prefetch_related中的get_queryset使用(非常意外)

针对@apiview的检索失败:

(240 queries including 235 similar and 120 duplicates)

针对viewsets.ReadOnlyModelViewSet的检索失败:

(208 queries including 200 similar and 78 duplicates )

针对viewsets.ModelViewSet的检索失败:

(803 queries including 801 similar and 801 duplicates )

所有这些似乎很不直观。

使用完全相同的序列化器的两种类型的端点如何有很大不同?

与基于函数的视图相比,Classviews和Viewsets似乎在涉及外键的情况下会导致 mass CPU和SQL性能下降,而我找不到真正的原因。

我希望N + 1个查询的执行效果很差,我不希望它们根据不同的DRF终结点样式为它们执行更多效果不佳。

为什么会发生这种情况?

2 个答案:

答案 0 :(得分:0)

此处的统计信息用词不当,这是因为DRF可浏览API对端点接受的每种方法都执行了额外的请求。

相应地,如果您仅以1倍的参考速度执行GET @apiview,则由于执行了3个附加请求,具有GET,PUT,PATCH,DELETE的端点的执行速度似乎会降低4倍。

当端点上有多个请求方法可用时,DRF的可浏览API掩盖了真实的速度/查询计数,为了查看端点的真实性能,您应该以编程方式请求它或使用?format=json

当我通过分析发现权限类被击中6次时,我发现了这一点:

https://stackoverflow.com/a/52731612/784831

答案 1 :(得分:-1)

看看这个答案Optimizing database queries in Django REST framework。 DRf不会自动优化您的查询,您仍然需要自己执行此操作。

如果您想进一步提高性能,请查看此应用https://github.com/K0Te/drf-serializer-cache