Django外键关联序列化查询耗时90秒性能问题排查求助
问题根因
你遇到的是典型的Django ORM N+1查询问题:
- 未序列化外键详情时,仅需查询1次Cost表即可拿到所有数据,耗时300-400ms
- 嵌套序列化外键后,默认惰性查询的ORM会为每条Cost记录单独触发5次数据库查询(查employee、job1~job4关联记录),如果返回1万条Cost记录,就会触发5万次额外查询,耗时自然飙升到数十秒。
解决方案
仅需1行代码修改即可解决性能问题:在视图的queryset中使用select_related预加载所有关联外键,一次性将Cost表和关联的员工、工作项数据全部查出,避免重复查询。
如果不需要嵌套的返回结构,还可以简化序列化器配置,直接返回字段值而非嵌套对象。
代码示例
1. 保留原嵌套返回结构(性能优化版)
仅修改视图的queryset即可,序列化器无需改动:
class JoinedFilterCostList(generics.ListAPIView): # 预加载所有关联外键,消除N+1查询 queryset = Cost.objects.select_related('employee', 'job1', 'job2', 'job3', 'job4').all() serializer_class = CostModelSerializer filter_backends = [DjangoFilterBackend] filterset_class = CostListFilter
修改后查询耗时会回到300-500ms区间,和未关联外键时的性能基本一致。
2. 简化为扁平返回结构(可选)
如果不需要嵌套的对象结构,直接返回字段值,可以修改序列化器,无需额外嵌套序列化器:
class CostModelSerializer(serializers.ModelSerializer): employee = serializers.CharField(source='employee.employee_name') job1 = serializers.CharField(source='job1.No') job2 = serializers.CharField(source='job2.No') job3 = serializers.CharField(source='job3.No') job4 = serializers.CharField(source='job4.No') class Meta: model = Cost fields = '__all__'
返回结果示例:
{ "id": 12, "employee": "Person 1", "job1": "30201", "job2": "N/A", "job3": "N/A", "job4": "N/A", "hours1": 10, "hours2": 0, "hours3": 0, "hours4": 0, "date": "2021-07-12" }
关于to_field参数返回null的说明
to_field是外键定义阶段的参数,用于指定关联表的关联字段(默认关联主键ID),你在序列化阶段使用该参数自然无法拿到正确值,返回null属于预期结果,序列化阶段取关联字段值请使用source参数即可。
内容的提问来源于stack exchange,提问作者cmob
相关产品推荐
相关产品推荐

