优化Django API查询以减少数据库访问次数的方案咨询
Django API数据库查询优化方案
1. CustomUser表查询优化
你可以使用Django ORM的Subquery+OuterRef实现关联过滤,无需单独查询CustomUser表,直接在Product查询中嵌入用户范围的判断逻辑,将两次独立查询合并为单次查询:
from django.db.models import Subquery, OuterRef, F from django.contrib.gis.measure import D # 直接在Product过滤逻辑中关联CustomUser表,无需单独拉取用户对象 query_of_set = queryset_list.filter( point__distance_lte=( Subquery(CustomUser.objects.filter(uid=uid).values("point")[:1]), D(km=Subquery(CustomUser.objects.filter(uid=uid).values("discovery_range")[:1])) ) )
该写法会把CustomUser的查询转为子查询嵌入SQL,不会产生独立的CustomUser查询请求。
2. 避免count()额外查询的方案
有两种常用方案可选,可根据你的业务逻辑选择:
- 提前求值方案:如果你后续需要返回该查询集的结果,可以先将查询集转为列表完成一次数据库请求,再用
len()判断长度,全程只会产生1次查询:range_result = list(query_of_set) if len(range_result) < 3: # 不足3条时走fallback逻辑 if query and len(query) > 0: query_of_set = queryset_list.filter(lookups).distinct() else: query_of_set = queryset_list else: # 数量足够时直接使用已查询到的结果 query_of_set = range_result - 轻量统计方案:如果不想提前求值,可以用切片限制count的统计范围,数据库只会扫描到符合条件的3条记录就终止统计,比全量count()性能提升数倍:
if query_of_set[:3].count() < 3: # 执行fallback逻辑
3. prefetch_related之外的优化空间
除了prefetch_related外,还有以下优化方向:
- 对于正向外键/一对一关联,优先使用
select_related代替prefetch_related,select_related通过JOIN合并查询,只会产生1次数据库请求,比prefetch_related的独立IN查询效率更高 - 自定义预取逻辑:使用
Prefetch对象指定预取的过滤条件、排序规则,只拉取业务需要的关联数据,减少数据传输量:from django.db.models import Prefetch # 示例:仅预取已审核的商品评论 queryset = Product.objects.active().prefetch_related( Prefetch("comments", queryset=Comment.objects.filter(is_approved=True), to_attr="approved_comments") ) - 索引优化:你当前的搜索逻辑用了多个
icontains模糊匹配,建议对搜索字段加全文索引,比如PostgreSQL的GIN索引配合Django内置的全文搜索功能,大幅提升查询速度 - 缓存优化:如果商品、评论等数据更新频率不高,可以对查询结果或者序列化后的接口返回结果加缓存,高频请求直接走缓存,无需访问数据库
内容的提问来源于stack exchange,提问作者LearnToday
相关产品推荐
相关产品推荐

