Environment:
Django=="2.2"
Python=="3.6.8"
debug_toolbar=="1.11"
rest_framework=="3.8.2"
Background:
In switching away from function based DRF endpoints to class-based views / viewsets I am finding that class-based views perform slightly better without nested relations and much worse with nested relations.
Pseudocode Model Context:
Creator:
ForeignKey.Shipments[]
Unit:
ForeignKey.Shipments[]
Shipment:
ForeignKey.Addresses[]
ForeignKey.Creator
ForeignKey.Unit
Address:
Street
City
State
Noteworthy Serializer Context:
Unit:
Meta:
Depth = 1
Creator:
Meta:
Depth = Infinite
When comparing Viewsets of the above structure to the equivalent @apiview
, I'm finding:
/addresses
performs slightly better on SQL querycount (0.9x), with 1.1x CPU overhead (expected)/creators
performs slightly worse on SQL querycount (1.1x), with 3.9x CPU overhead (expected)/creators/1
with a Read-Only Viewset performs slightly better on SQL querycount (0.9x), with 3.4x CPU overhead (unexpected)/creators/1
with a Writeable Viewset performs significantly worse on SQL querycount (3.3x), with significant 5.9x CPU overhead (unexpected)/units/1
with a Writeable Viewset performs profoundly worse on SQL querycount (4.4x), with a massive 7.9x CPU overhead (VERY unexpected)- Both forms of viewsets do not benefit from / disregard
prefetch_related
usage fromget_queryset
entirely (VERY unexpected)
Breakdown of retrieve against @apiview
:
(240 queries including 235 similar and 120 duplicates)
Breakdown of retrieve against viewsets.ReadOnlyModelViewSet
:
(208 queries including 200 similar and 78 duplicates )
Breakdown of retrieve against viewsets.ModelViewSet
:
(803 queries including 801 similar and 801 duplicates )
All of this seems very unintuitive.
How is it possible for two types of endpoints using the exact same serializer to perform so much differently?
In comparison to Function based views it seems that Classviews and Viewsets incur a massive CPU and SQL performance hit where foreignkeys are involved for no real reason that I can find.
I expect N+1 queries to perform poorly, what I don't expect is for them to perform more poorly depending on which style of DRF endpoint serves them.
Is there an explanation for why this happens?