Django Rest Framework 性能优化:解决 N+1 查询问题
在开发测试平台的“用例管理”列表页时,我发现当用例数量超过 100 条时,接口响应时间竟然高达 2秒。经过排查,这是一个典型的 N+1 SQL 查询问题。
1. 问题分析
我们的数据模型是这样的:一个 TestCase(测试用例)属于一个 Project(项目),并且有多个 Tag(标签)。
在使用 Django ORM 查询列表时,代码原本是这样写的:
# ❌ 错误写法
cases = TestCase.objects.all()
serializer = TestCaseSerializer(cases, many=True)
这就导致了:查询出 100 个用例后,序列化器在遍历每个用例时,又分别去查询了关联的 Project 和 Tag 表。最终导致了 1 + 100 + 100 = 201 次 SQL 查询!
2. 解决方案:select_related 与 prefetch_related
Django 提供了非常强大的预查询机制。对于外键(ForeignKey),使用 select_related;对于多对多(ManyToMany),使用 prefetch_related。
# ✅ 优化后的写法
cases = TestCase.objects.select_related('project').prefetch_related('tags').all()
3. 验证优化结果
使用 django-debug-toolbar 再次查看 SQL 面板:
- 优化前:查询次数 201 次,耗时 2100ms
- 优化后:查询次数 3 次,耗时 120ms
性能提升了近 20 倍。这也让我深刻理解了 ORM 懒加载机制的双刃剑特性。