Django与Polars组合响应异常缓慢问题排查求助
问题描述
使用Django REST Framework结合Polars生成报表,返回约3500条数据时,Postman显示响应耗时超1分钟,但终端打印的数据处理总耗时仅约1秒。测试发现:完成数据构建后返回空字典,耗时仍超1分钟;直接返回本地JSON文件中的相同数据,耗时不到1秒。相关视图代码如下:
class TaskViewSet(SearchViewSet): """Task view set""" queryset = Task.objects.all() serializer_class = TaskSerializer search_vector = SearchVector("id", "name") permission_classes = [D7896DjangoModelPermissions] filter_backends = [ filters.DjangoFilterBackend, ] filter_class = TaskFilter pagination_class = None def list(self, request, *args, **kwargs): start_time = datetime.now() branch = request.GET.get("branch", None) orders = request.query_params.getlist("order", []) events = request.query_params.getlist("event", []) production_orders = request.query_params.getlist("production_order", []) start_date = request.GET.get("date__gte", None) start_date = ( datetime.strptime(start_date, "%Y-%m-%d").date() if start_date else start_date ) end_date = request.GET.get("date__lte", None) end_date = ( datetime.strptime(end_date, "%Y-%m-%d").date() if end_date else end_date ) # Validate branch is present if not branch: raise ValidationError("The 'branch' field is missing.") _, tasks = WorkOrderManager.get_work_orders( branch, start_date, end_date, orders, events, production_orders ) if not tasks.is_empty(): tasks = tasks.filter(pl.col("unused_components_task") == False).drop( ["unused_components_task"] ) tasks = tasks.with_columns( tasks['date'].dt.strftime('%Y-%m-%d'), tasks['supply_date'].dt.strftime('%Y-%m-%d') ) data = tasks.to_dicts() json_data = json.dumps(data) end_time = datetime.now() total_time = end_time - start_time print(total_time) return Response(json_data, content_type='application/json')
可能的原因
- 手动调用
json.dumps()生成JSON字符串后传给Response,Django后续会把该字符串当作普通响应内容处理,触发不必要的编码、解析操作,大字符串场景下会产生显著额外开销。 - 项目中的某些中间件(比如日志、监控类)会在响应阶段遍历或处理整个响应内容,返回空字典时仍触发了这些耗时逻辑,而直接返回文件时中间件的处理路径不同。
- WSGI/ASGI服务器(如Gunicorn)或反向代理(如Nginx)的配置不合理,比如缓冲区过小,导致大响应被多次拆分传输,拉长了整体耗时。
解决思路
- 直接返回字典,让DRF处理序列化:去掉
json_data = json.dumps(data),直接返回Response(data)。DRF的Response内置了优化的JSON编码器,适配Django的响应流程,比手动序列化更高效。 - 改用流式响应减少内存压力:对于大体积数据,使用
StreamingHttpResponse分批返回内容,避免一次性加载所有数据到内存:from django.http import StreamingHttpResponse import json def stream_json(items): yield '[' is_first = True for item in items: if not is_first: yield ',' yield json.dumps(item) is_first = False yield ']' # 替换原return语句 return StreamingHttpResponse(stream_json(data), content_type='application/json') - 排查中间件:逐个禁用项目中的中间件,测试响应耗时,定位到在响应阶段执行耗时操作的中间件,调整其逻辑(比如跳过对大响应的内容处理)。
- 优化服务器配置:如果使用Gunicorn,调整
--workers数量、--timeout参数;如果使用Nginx,检查proxy_buffering、client_max_body_size等配置,确保大响应能高效传输。 - 排除数据库查询隐患:虽然数据处理计时显示快,但可以确认
WorkOrderManager.get_work_orders中的数据库查询是否存在N+1问题,是否添加了合适的索引(此可能性较低,但可作为排除项)。
内容的提问来源于stack exchange,提问作者Yoni Shen
相关产品推荐
相关产品推荐

