You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 13:55:28