You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django千万级Task数据集加载缓慢,寻求优化方案

解决Django中800万条Task_Submitted数据的视图与Admin加载缓慢问题

问题背景

我有一个包含超800万条数据的Task_Submitted模型,访问Django Admin的对象页面和自定义视图时加载极慢,有时甚至超时。项目部署在AWS Elastic Beanstalk上,已经把数据库从db.t2.medium升级到db.t3.medium,但问题依旧。我把数据同步到本地后用Django Debug Tool分析,还是找不到明确的优化方向——哪怕是按status字段常规过滤数据,速度依然很慢。

慢加载代码片段

def view():
    context['total_task_amount'] = Task_Submitted.objects.all().count()
    context['total_task_approved_amount'] = Task_Submitted.objects.filter(status = 'approved').count()
    context['total_task_pending_amount'] = Task_Submitted.objects.filter(status = 'pending').count()
    context['total_task_rejected_amount'] = Task_Submitted.objects.filter(status = 'rejected').count()
    context['total_task_cancel_amount'] = Task_Submitted.objects.filter(status = 'cancel').count()

def s_view(): 
    tasks_approved_objects = tasks_submited_query.filter(status = 'approved')
    tasks_rejected_objects = tasks_submited_query.filter(status = 'rejected')
    tasks_cancel_objects = tasks_submited_query.filter(status = 'cancel')
    tasks_pending_objects = tasks_submited_query.filter(status = 'pending').order_by('date_submitted')

优化方案

1. 合并统计查询,减少数据库交互

原来的5次count()查询可以合并成一次聚合查询,直接从数据库拿到所有统计结果,避免多次连接数据库的开销:

from django.db.models import Count, Case, When, IntegerField

def view():
    # 一次查询获取所有统计数据
    stats = Task_Submitted.objects.aggregate(
        total=Count('id'),
        approved=Count(Case(When(status='approved', then=1), output_field=IntegerField())),
        pending=Count(Case(When(status='pending', then=1), output_field=IntegerField())),
        rejected=Count(Case(When(status='rejected', then=1), output_field=IntegerField())),
        cancel=Count(Case(When(status='cancel', then=1), output_field=IntegerField()))
    )
    # 给context赋值
    context['total_task_amount'] = stats['total']
    context['total_task_approved_amount'] = stats['approved']
    context['total_task_pending_amount'] = stats['pending']
    context['total_task_rejected_amount'] = stats['rejected']
    context['total_task_cancel_amount'] = stats['cancel']

2. 给高频过滤/排序字段加索引

  • 给status字段加普通索引:因为大量过滤和统计都依赖这个字段,直接在模型里配置:
class Task_Submitted(models.Model):
    status = models.CharField(max_length=20, db_index=True)
    # 其他字段...
  • 给status + date_submitted加联合索引:s_view里过滤status='pending'后还要按date_submitted排序,联合索引能让数据库直接用索引完成排序,避免额外的排序操作:
class Task_Submitted(models.Model):
    status = models.CharField(max_length=20, db_index=True)
    date_submitted = models.DateTimeField()

    class Meta:
        indexes = [
            models.Index(fields=['status', 'date_submitted']),
        ]

如果数据库支持,还可以创建覆盖索引(包含查询所需的所有字段),避免回表查询,进一步提升速度。

3. 优化查询集处理

  • 在s_view里,避免多次过滤同一个基础查询集,如果需要遍历大量数据,用iterator()减少内存占用:
def s_view(): 
    # 若需遍历对象,用iterator()分批加载,避免一次性把800万条数据读进内存
    tasks_pending_objects = tasks_submited_query.filter(status='pending').order_by('date_submitted').iterator()
    # 其他状态的查询同理,按需处理
  • 不要在视图中直接返回全部对象列表,尤其是Admin页面,一定要分页。

4. 缓存统计类数据

统计数据不会实时变化的话,用Django缓存(比如Redis/Memcached)缓存结果,不用每次请求都查数据库:

from django.core.cache import cache

def view():
    cache_key = 'task_submitted_stats'
    stats = cache.get(cache_key)
    if not stats:
        stats = Task_Submitted.objects.aggregate(
            total=Count('id'),
            approved=Count(Case(When(status='approved', then=1), output_field=IntegerField())),
            pending=Count(Case(When(status='pending', then=1), output_field=IntegerField())),
            rejected=Count(Case(When(status='rejected', then=1), output_field=IntegerField())),
            cancel=Count(Case(When(status='cancel', then=1), output_field=IntegerField()))
        )
        # 缓存5分钟,可根据业务调整过期时间
        cache.set(cache_key, stats, 300)
    # 赋值到context

5. Django Admin页面专项优化

  • 在Task_SubmittedAdmin里限制每页显示数量,禁用不必要的功能:
from django.contrib import admin

class Task_SubmittedAdmin(admin.ModelAdmin):
    list_per_page = 20  # 减少每页加载的数据量
    list_display = ('id', 'status', 'date_submitted')  # 只显示必要字段
    # 禁用不需要的批量操作
    actions = None
    # 外键字段用raw_id_fields,避免加载大量选项
    raw_id_fields = ('related_model',)
  • 避免使用低效的list_filter,如果必须加过滤器,用RelatedOnlyFieldListFilter或者自定义基于索引的过滤器。

6. 数据库层面优化

  • 开启AWS RDS的查询缓存,调整连接池参数,避免连接耗尽;
  • 查看数据库慢查询日志,用EXPLAIN分析慢SQL的执行计划,确认是否存在全表扫描、索引未命中的情况;
  • 若数据量持续增长,可考虑分表或分区(比如按日期分区),把历史数据迁移到单独的表,减少单表数据量。

内容的提问来源于stack exchange,提问作者Shittu Abdulrasheed Ayomide

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:52:52