DRF大型GET请求触发504网关超时,如何无分页获取百万级数据?
解决300万条记录无分页加载的方案
针对你遇到的大数量级数据加载导致服务器崩溃、超时问题,从数据库查询、后端接口、前端加载三个维度给出优化方案,全程无需分页或过滤:
1. 数据库查询层面砍数据量
- 只拉取必要字段:别用
Model.objects.all()加载完整模型实例,改用values()或only()仅获取前端需要的字段,能大幅减少传输的数据体积。比如:# 只取id、name、data三个字段 YourModel.objects.values('id', 'name', 'data') - 用原生查询替代ORM:Django ORM虽然方便,但处理超大量数据时会有额外开销。直接用原生SQL查询,通过游标逐行读取:
from django.db import connection def get_raw_records(): with connection.cursor() as cursor: cursor.execute("SELECT id, name, data FROM your_table_name") columns = [col[0] for col in cursor.description] # 逐行生成字典,避免一次性加载全部数据 for row in cursor: yield dict(zip(columns, row)) - 关闭不必要的关联与信号:如果模型有外键且前端不需要关联数据,别用
select_related/prefetch_related;临时关闭模型的post_save等信号,减少额外的处理逻辑消耗资源。
2. 后端接口优化,避免超时
- 弃用DRF,用轻量级响应:DRF的序列化器、权限校验等中间件会增加响应时间,直接用Django原生的
StreamingHttpResponse返回流式JSON,跳过不必要的开销:import json from django.http import StreamingHttpResponse from .models import YourModel def stream_all_records(request): def generate_stream(): yield '[' first_item = True # 用iterator()逐行从数据库取数据,不占内存 for item in YourModel.objects.values('id', 'name', 'data').iterator(): if not first_item: yield ',' yield json.dumps(item) first_item = False yield ']' return StreamingHttpResponse(generate_stream(), content_type='application/json') - 调整服务器超时配置:Apache默认超时时间较短,修改
httpd.conf里的Timeout参数(比如设为300秒),同时调整WSGI模块的process-timeout参数,给足够时间完成数据传输;条件允许的话换成uWSGI+Nginx的组合,处理大请求的性能比Apache好很多。 - 关闭Django调试模式:生产环境务必把
DEBUG设为False,调试模式下的额外检查会大幅增加资源消耗。
3. 前端流式接收,避免内存溢出
前端直接接收全量JSON容易导致内存崩溃,用Fetch API的流式处理逐步接收并解析数据:
fetch('/api/stream-all-records/') .then(res => { const reader = res.body.getReader(); const decoder = new TextDecoder(); let partialData = ''; function processChunk({ done, value }) { if (done) { // 最后一块数据处理完,解析完整JSON const fullData = JSON.parse(partialData); // 在这里渲染全部数据 return; } // 解码当前块并拼接 partialData += decoder.decode(value, { stream: true }); // 可选:这里可以先渲染已接收的部分数据 return reader.read().then(processChunk); } return reader.read().then(processChunk); });
内容的提问来源于stack exchange,提问作者Casey
相关产品推荐
相关产品推荐

