Django 1.8复杂查询优化求助:耗时36秒无改善
优化Django ORM慢查询的解决方案
我之前也碰到过类似的Django ORM查询性能坑,你的核心问题是当前查询生成了低效的嵌套子查询,再加上可能缺失关键索引,才导致count操作耗时飙升。下面是具体的优化步骤:
1. 重构查询,用JOIN替代IN子查询
你原来的代码先查询Job的pk列表,再用job__in做子查询,这种方式会让数据库先执行子查询再匹配Candidate,大数据量下效率极低。直接通过关联字段过滤,Django会生成更高效的JOIN语句:
# 先获取当前用户对应的Employee对象(无需先提取pk) emp = Employee.objects.filter(user=self.request.user, firm=obj).first() if not emp: candidate_count = 0 else: # 直接通过Job的关联字段过滤Candidate,避免子查询 _candidates = Candidate.objects.filter( Q(job__hiring_manager=emp) | Q(job__followers=emp), apply_date__range=[date_initial, date_end] ).order_by('-apply_date') candidate_count = _candidates.count()
这样生成的SQL会用JOIN替代IN子查询,数据库优化器能更好地利用索引加速查询。
2. 检查并添加关键索引
慢查询90%以上的原因是索引缺失,针对你的场景,需要确保以下索引存在:
- Job表:
hiring_manager_id的索引(Django外键默认会自动创建,可通过数据库工具确认) - 多对多表
combo_job_followers:user_id和job_id的联合索引(Django自动生成的多对多中间表默认会有,但自定义中间表需要手动添加) - Candidate表:
job_id和apply_date的联合索引(这是核心!你的查询同时过滤这两个字段,联合索引能让数据库直接定位符合条件的记录)
在Candidate模型中添加联合索引的示例:
class Candidate(models.Model): job = models.ForeignKey(Job, on_delete=models.CASCADE) apply_date = models.DateTimeField() # 其他字段... class Meta: indexes = [ models.Index(fields=['job', 'apply_date'], name='candidate_job_apply_date_idx'), ]
3. 用explain()分析查询计划
调整后可以用Django的explain()方法查看查询计划,确认索引是否被正确使用:
print(_candidates.explain(verbose=True))
如果输出中出现Using index或Using where; Using index,说明索引生效了;如果出现Using filesort或Using temporary,则需要进一步调整索引或查询语句。
4. 额外优化点
- 避免不必要的中间变量:原代码中的
job_list完全可以省略,直接通过关联字段过滤 - 如果
apply_date的范围很大,可以考虑分批次统计,但你的场景下优先优化索引和查询结构
内容的提问来源于stack exchange,提问作者GustavoNogueira
相关产品推荐
相关产品推荐

