Django Lazy Querysets优化:销售仪表板页面加载缓慢求助
优化销售仪表板数据库查询性能的方案
看起来你遇到的是典型的重复数据库查询导致的性能问题,我来给你几个针对性的优化方案,应该能大幅提升页面加载速度:
1. 批量聚合查询,一次获取所有指标
你现在每个指标单独过滤查询的方式会导致多次数据库往返,最有效的解决办法是用Django的aggregate结合filter,一次查询计算出所有需要的统计值。这样不管有多少个指标,只需要一次数据库请求就能拿到结果。
示例代码:
from django.db.models import Count, Q from datetime import timedelta from django.utils import timezone # 定义时间范围(替换成你的X、Y值) x_days_ago = timezone.now() - timedelta(days=7) y_days_ago = timezone.now() - timedelta(days=14) # 一次查询聚合所有指标 dashboard_metrics = Opportunities.objects.aggregate( # 近X天赢单机会数 recent_won_count=Count('id', filter=Q(status='won', created_at__gte=x_days_ago)), # Y天无活动的待跟进机会数 inactive_followup_count=Count('id', filter=Q(status='pending', last_activity__lte=y_days_ago)), # 其他指标可以继续在这里添加,比如总待跟进数、本月新增数等 total_pending_count=Count('id', filter=Q(status='pending')) ) # 使用时直接取字典里的对应值 won_count = dashboard_metrics['recent_won_count'] inactive_count = dashboard_metrics['inactive_followup_count']
2. 检查QuerySet是否被重复求值
你提到提前获取了QuerySet再传入各函数,但如果每个函数里对这个QuerySet做过滤后又触发了求值(比如调用len()、遍历或者转成列表),每个过滤后的QuerySet还是会单独执行一次SQL查询。这种情况下,批量聚合依然是最优解,因为它直接在数据库层面完成所有统计,不需要拉取大量数据到内存。
3. 给过滤字段添加数据库索引
你的查询用到了status、created_at、last_activity这些字段,给这些字段组合添加索引能大幅提升数据库的查询效率。
在你的Opportunities模型中添加索引:
class Opportunities(models.Model): # 你的其他字段定义 status = models.CharField(max_length=50) created_at = models.DateTimeField(auto_now_add=True) last_activity = models.DateTimeField(auto_now=True) class Meta: indexes = [ # 针对赢单指标的组合索引 models.Index(fields=['status', 'created_at']), # 针对无活动待跟进指标的组合索引 models.Index(fields=['status', 'last_activity']), ]
添加后记得运行python manage.py makemigrations和python manage.py migrate来应用索引。
4. 给统计结果添加缓存
销售仪表板的统计指标通常不需要实时更新(比如5-10分钟更新一次就足够),可以用Django的缓存框架把聚合结果缓存起来,避免每次请求都查数据库。
示例代码:
from django.core.cache import cache def get_dashboard_metrics(): cache_key = 'sales_dashboard_metrics' # 先尝试从缓存获取 metrics = cache.get(cache_key) if not metrics: # 如果缓存不存在,执行聚合查询 x_days_ago = timezone.now() - timedelta(days=7) y_days_ago = timezone.now() - timedelta(days=14) metrics = Opportunities.objects.aggregate( recent_won_count=Count('id', filter=Q(status='won', created_at__gte=x_days_ago)), inactive_followup_count=Count('id', filter=Q(status='pending', last_activity__lte=y_days_ago)) ) # 缓存5分钟(根据你的业务需求调整过期时间) cache.set(cache_key, metrics, 60*5) return metrics
5. 验证查询次数(可选)
可以安装django-debug-toolbar来直观查看页面请求触发的数据库查询次数,确认优化后是否减少了查询。安装后,页面会显示每个请求的SQL查询列表,你能清楚看到优化前后的变化。
内容的提问来源于stack exchange,提问作者jvanheijzen
相关产品推荐
相关产品推荐

