如何在Django中更快速地统计PostgreSQL库中模型对象的数量?
Django 大表计数查询优化方案
1. 新增联合索引(最根本的优化手段)
你当前的查询慢核心原因是没有针对user_id和create_date两个过滤字段建立联合索引,导致查询时需要扫描全表700万行数据。
在你的Prospect模型中增加联合索引配置:
from django.db import models class Prospect(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) create_date = models.DateTimeField(auto_now_add=True) # 其他字段... class Meta: indexes = [ models.Index(fields=['user_id', 'create_date']), ]
执行makemigrations和migrate后,该索引会在数据库层面生效,PostgreSQL可以直接通过索引定位到符合条件的记录,不需要扫描全表,查询耗时通常可以降到毫秒级。
2. 优化查询写法(避免不必要的性能损耗)
你当前的查询写法逻辑是正确的,但可以做两处小优化:
- 优先用Django带时区的时间方法,避免时区不匹配导致的索引失效:
from django.utils import timezone date_example = timezone.now() - timezone.timedelta(days=1) count_total_today_prospects = Prospect.objects.filter( user_id='user_id_example', create_date__gte=date_example ).count()
- 可以打印生成的SQL确认没有多余关联查询:
print(Prospect.objects.filter(user_id='user_id_example', create_date__gte=date_example).query),如果出现不必要的JOIN,可以用.values('id')提前限定字段避免关联。
3. 高频查询场景补充优化
如果这个查询的调用频率很高,可以叠加以下优化:
- 增加缓存:用Redis等缓存组件存储每个用户的24小时创建数,缓存有效期根据业务对数据实时性的要求设置为1-5分钟,大幅降低数据库访问压力。
- 增加冗余计数字段:在
User模型中新增daily_prospect_count整数字段,每创建一条Prospect记录时用F("daily_prospect_count") + 1原子更新该字段,每日零点定时重置所有用户的计数,查询时直接读取该字段即可,完全不需要访问大表。
内容的提问来源于stack exchange,提问作者RobZ
相关产品推荐
相关产品推荐

