python - 如何诊断 django 渲染速度问题?
问题描述
我一直在试图弄清楚是什么减慢了我的请求,我所能弄清楚的是响应的呈现速度有所放缓。
我对查询、序列化程序和 JSON 渲染进行了一些测试,如下所示:
client = Client.objects.get(user__username="pugdog")
start = parse("2021-09-01T00:00:00-04:00")
end = parse("2021-10-01T00:00:00-04:00")
db_test_start_time = time()
events = Event.objects.filter(client=client, start__gt=start, end__lt=end)
list(events)
db_test_end_time = time()
factory = APIRequestFactory()
request = factory.get('/')
serializer_context = {'request': Request(request), }
output = []
for event in events:
serializer = EventReadSerializer(instance=event, context=serializer_context)
output.append(serializer.data)
renderer = JSONRenderer()
json_output = renderer.render(output)
serializer_test_end_time = time()
print(f"query speed: {db_test_end_time - db_test_start_time}")
print(f"serializer speed: {serializer_test_end_time - db_test_end_time}")
print(f"Total time: {serializer_test_end_time - db_test_start_time}")
输出是:
query speed: 0.006450176239013672
serializer speed: 2.926229238510132
Total time: 2.9326794147491455
这是处理查询并将其转换为 JSON 所需的时间,但是当我尝试使用 API REST 客户端“Insomnia”提取这些数据时,大约需要 43.8 秒,这意味着我在某处出现了大幅减速。我正在开发的同一台机器上运行 Insomnia,所以应该没有网络问题。
这个测试是在我用 100 个事件对象填充数据库时进行的。我决定用不同数量的对象进行测试,看看数据量和响应时间之间的关系是否是线性的,这可能有助于找出问题,例如我的授权/身份验证是否有问题,它与特定查询无关。当我做 20 个事件时,在 Insomnia 中获得响应所需的时间大约是 9 秒,而上面的测试大约是 0.6 秒。在这两个方面,这几乎与速度呈线性关系。
我的大部分 API 响应速度都相当快,但是这个特定的部分非常慢。我还能测试什么来弄清楚是什么让事情变慢了?
编辑 这里是 EventReadSerializer
class EventReadSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()
resourceIds = ResourceIdsSerializer(source="resources", many=True)
rrule = RRuleReadSerializer(many=True)
customer = SimplifiedCustomerSerializer(many=False)
class Meta:
model = Event
fields = [
"id",
"all_day",
"title",
"start",
"end",
"background_color",
"border_color",
"text_color",
"duration",
"resourceIds",
"rrule",
"customer",
]
这是渲染后伪造事件的示例:
{
"id": 1,
"all_day": false,
"title": "Suddenly this mouth take.",
"start": "2021-09-26T11:02:25Z",
"end": "2021-09-26T12:02:25Z",
"background_color": null,
"border_color": null,
"text_color": null,
"duration": "01:00:00",
"resourceIds": [
2
],
"rrule": [],
"customer": {
"id": 1,
"user": {
"first_name": "Craig",
"last_name": "Johnson"
},
"custom_data": [],
"notes": [],
"first_name": "Craig",
"last_name": "Johnson"
}
}
这实际上是原始版本的精简版EventSerializer
,它返回了更多信息。它减少到只有我正在使用的日历所需的数据。这对最终渲染速度没有明显差异。我还以类似的方式将我的 CustomerSerializer 更改为 SimplifiedCustomerSerializer,以减少返回的数据量。
无论如何,考虑到当我运行脚本来测试速度时,它运行序列化程序的时间大约是呈现页面的 1/15。
我尝试过的另一件事是删除所有我能看到的中间件,看看事情是如何变化的。虽然我确实看到了速度上的小幅提升,但它将呈现页面所需的时间减少了大约 2 秒至 42.8 秒,与运行查询和序列化数据所需的 2.9 秒相比,这似乎仍然是完全不可接受的.
解决方案
您的序列化器不仅序列化 的数据instance
,而且还序列化相关对象的数据。这意味着序列化器将对相关模型进行查询。
我们可以通过使用.select_related(…)
[Django-doc]和.prefetch_related(…)
[Django-doc]来提高性能:
events = Event.objects.filter(
client=client, start__gt=start, end__lt=end
).prefetch_related(
'resources', 'rrule'
).select_related('customer', 'customer__user')
可能Customer
还会进行查询以查找custom_data
和notes
。如果您共享相应的Customer
模型和SimplifiedCustomerSerializer
序列化程序,我们可能也可以减少对这些项目的查询次数。
推荐阅读
- django - 如何自定义 Django-Jazzmin 登录页面
- php - 我收到类似 mail.myserver.in 的 TLS/SSL 失败的通知:意外的 TCP 输入断开连接
- django - Django Ajax:响应呈现在另一个页面不同的页面
- android - 在 exoplayer 中播放动态 url
- python - AttributeError:模块“torchtext.datasets”没有属性“text_classification”
- java - 如何知道用户没有给我们的应用程序提供互联网访问权限?
- php - 将两个小时添加到从 MySQL 数据库中获取的数据
- node.js - 如何在 Nativescript 8 和 Angular 中生成组件
- python - django / ajax 表单提交收到 405 错误但有效吗?
- php - 将静态数据从一个 php 发送到另一个