Django多表关联优化查询:特定店铺月度Deal分性别浏览量统计
优化Django查询:高效统计店铺当月Deal的分性别浏览次数
嘿,我来帮你搞定这个查询优化的问题!你的当前代码确实存在N+1数据库查询的问题——嵌套循环里每次访问seg.deal_view和x.client都会触发新的数据库请求,当Deal或浏览量多的时候,性能会直线下降。咱们用Django ORM的聚合查询来一次性搞定所有统计,只需要一次数据库访问。
问题分析
原代码的逻辑是:先获取店铺→获取店铺下的Deal→过滤当月的浏览记录→循环每个Deal→再循环每个浏览记录获取用户性别。这会导致:
- 每个Deal都要单独查询对应的浏览记录
- 每个浏览记录又要单独查询用户的性别
- 大量重复的数据库请求,性能极低
优化方案:一次性聚合统计
根据你的需求,分两种场景给出优化代码:
场景1:统计整个店铺当月所有Deal的总浏览量(按性别分组)
如果需要知道整个店铺里,男性、女性、其他性别的用户分别浏览了多少次Deal,用这个查询:
from django.db.models import Count from datetime import datetime, timedelta # 计算近30天的日期范围(和原代码逻辑一致) end_date = datetime.now().date() start_date = end_date - timedelta(days=30) # 一次性查询并统计分性别浏览次数 gender_view_stats = deals_view.objects.filter( # 关联到目标店铺的Deal deal__store_id=storeid, # 筛选当月的浏览记录 date_added__range=(start_date, end_date) ).values( # 按用户性别分组 'client__gender' ).annotate( # 统计每个性别的浏览次数 view_count=Count('id') ).order_by('-view_count') # 可选:按浏览次数降序排列
返回的gender_view_stats是一个QuerySet,每个元素是类似这样的字典:
[ {'client__gender': 'M', 'view_count': 45}, {'client__gender': 'F', 'view_count': 32}, {'client__gender': 'O', 'view_count': 8} ]
场景2:统计每个Deal的分性别浏览次数
如果需要知道店铺里每个具体Deal对应的不同性别浏览量,用这个查询:
deal_gender_stats = deals_view.objects.filter( deal__store_id=storeid, date_added__range=(start_date, end_date) ).values( # 按Deal和性别分组,带上Deal的ID和标题方便识别 'deal__id', 'deal__title', 'client__gender' ).annotate( view_count=Count('id') ).order_by('deal__id')
返回结果示例:
[ {'deal__id': 1, 'deal__title': "夏季促销", 'client__gender': 'M', 'view_count': 18}, {'deal__id': 1, 'deal__title': "夏季促销", 'client__gender': 'F', 'view_count': 12}, {'deal__id': 2, 'deal__title': "新品折扣", 'client__gender': 'F', 'view_count': 20} ]
处理性别为Null的情况
如果有些用户没有设置性别(gender字段为null),可以用Coalesce将null转为统一的标识(比如'Unknown'):
from django.db.models.functions import Coalesce gender_view_stats = deals_view.objects.filter( deal__store_id=storeid, date_added__range=(start_date, end_date) ).annotate( # 将null性别转为'Unknown' normalized_gender=Coalesce('client__gender', 'Unknown') ).values( 'normalized_gender' ).annotate( view_count=Count('id') )
为什么这个优化有效?
- 原代码是多次零散查询,而优化后的查询利用Django ORM的JOIN操作,一次性关联
deals_view、deals、client_profile、stores四张表,筛选+分组统计一步完成。 - 只需要一次数据库请求就能拿到所有统计数据,彻底解决N+1问题,性能提升非常明显,尤其是数据量较大的时候。
内容的提问来源于stack exchange,提问作者Kheshav Sewnundun
相关产品推荐
相关产品推荐

