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

Django搜索结果优化:序列化对象缓存方案及响应提速问题

问题分析与优化方案

一、解决序列化时的额外查询问题

你已经用了prefetch_related但仍有额外查询,大概率是这几个原因,对应解决方法如下:

  • 检查Serializer字段是否匹配prefetch层级:如果TripListSerializer里嵌套了子Serializer(比如TripValuesSerializer),且子Serializer用到了operator_trip_field__trip_field这类深层关联,要确保prefetch_related覆盖了所有用到的关联路径。可以用Prefetch对象精准控制预取的查询集,减少冗余查询:
    from django.db.models import Prefetch
    
    trips = (
        Trip.objects.filter(filter_query)
        .prefetch_related(
            Prefetch(
                "trip_values",
                queryset=TripValue.objects.select_related("operator_trip_field__trip_field")
            ),
            "operator_service_day",
            "trip_occurrences",
            "trip_locations",
            "assigned_vehicle_formation",
        )
    )
    
  • 区分select_related和prefetch_related:如果是正向一对一/外键关联(比如Trip到某个单对象的关联),用select_related替代prefetch_related,它会用JOIN语句一次性拉取数据,比预取更高效。
  • 排查SerializerMethodField:如果Serializer里用了SerializerMethodField,要确保方法内部没有触发新的数据库查询,比如提前预取所需数据,或者把逻辑移到数据库层面处理。

二、批量缓存优化方案

不要逐个查询缓存,改用批量获取+批量缓存的方式,把N次缓存查询降到1次:

# 1. 先拿到所有trip的ID列表
trip_ids = list(trips.values_list('id', flat=True))
# 2. 构造批量缓存key
cache_keys = [f"trip:{trip_id}" for trip_id in trip_ids]
# 3. 一次性获取所有缓存数据
cached_data = cache.get_many(cache_keys)
# 4. 分离已缓存和未缓存的ID
cached_ids = {int(key.split(':')[1]) for key in cached_data.keys()}
uncached_ids = [tid for tid in trip_ids if tid not in cached_ids]

# 5. 仅查询未缓存的trip并序列化
uncached_trips = Trip.objects.filter(id__in=uncached_ids).prefetch_related(
    "trip_values",
    "trip_values__operator_trip_field__trip_field",
    # 其他需要的关联...
)
uncached_serialized = TripListSerializer(uncached_trips, many=True).data

# 6. 批量缓存未命中的结果
cache_batch = {f"trip:{tid}": data for tid, data in zip(uncached_ids, uncached_serialized)}
cache.set_many(cache_batch, timeout=3600)

# 7. 按原顺序合并缓存与新查询结果
final_data = []
for tid in trip_ids:
    if tid in cached_ids:
        final_data.append(cached_data[f"trip:{tid}"])
    else:
        idx = uncached_ids.index(tid)
        final_data.append(uncached_serialized[idx])

三、Response阶段提速方法

序列化时间短但总请求时长占比大,主要优化方向是减少数据传输和JSON序列化耗时:

  • 替换高效JSON序列化库:用ujson替代Django默认的JSON编码器,速度提升明显。可以直接在Response中使用:
    import ujson
    return HttpResponse(ujson.dumps(final_data), content_type='application/json')
    
  • 开启Gzip压缩:在Django的settings.py中添加Gzip中间件,大幅减少传输的数据量:
    MIDDLEWARE = [
        'django.middleware.gzip.GZipMiddleware',
        # 其他中间件...
    ]
    
  • 分页返回结果:200+条数据一次性返回压力大,改用分页,比如每页20条,既减少单次传输的数据量,也降低前端渲染压力:
    from django.core.paginator import Paginator
    
    paginator = Paginator(trips, 20)
    page = request.GET.get('page', 1)
    current_page = paginator.get_page(page)
    serialized = TripListSerializer(current_page, many=True)
    return Response({
        'data': serialized.data,
        'page': current_page.number,
        'total': paginator.count
    })
    
  • 缓存整个查询结果:如果查询条件重复率高,直接缓存整个查询的序列化结果。用查询条件的哈希值作为缓存key,避免重复查询和序列化:
    import hashlib
    
    # 生成查询唯一标识(比如结合filter参数和请求参数)
    query_signature = str(filter_query) + str(request.GET.dict())
    cache_key = hashlib.md5(query_signature.encode()).hexdigest()
    cached_result = cache.get(cache_key)
    
    if cached_result:
        return Response(cached_result)
    
    # 执行查询、序列化并缓存
    serialized = TripListSerializer(trips, many=True).data
    cache.set(cache_key, serialized, timeout=3600)
    return Response(serialized)
    

内容的提问来源于stack exchange,提问作者AlxVallejo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:12:08