如何优化Django视图性能?复杂薪资计算视图加载超90秒
Django调度员工资计算视图性能优化方案
优先优化慢查询(见效最快)
- 用
django-debug-toolbar定位那两条耗时最长的查询,导出对应的SQL语句,检查是否存在全表扫描、嵌套子查询冗余的问题。 - 给高频过滤/关联的字段加数据库索引:比如
Load表的date字段、Dispatcher的location_id、BonusCustomer的dispatcher_id和customer_id,能大幅提升查询速度。 - 把Python层面的计算逻辑尽量移到数据库端:
- 基本工资的近2周平均周里程,用Django ORM的
TruncWeek按周分组聚合,再取近2周的平均值,不要拉取所有里程数据到Python里计算。 - 奖金的工单数量判断,用
Case+When在数据库里直接完成“公司费率vs客户费率”的逻辑,一次性筛选出符合条件的工单数量,避免先拉所有工单再在Python里过滤。
- 基本工资的近2周平均周里程,用Django ORM的
- 用
select_related/prefetch_related提前关联依赖表:比如查询Dispatcher时,直接关联Location获取BaseRate;查询BonusCustomer时,批量预取关联的Load数据,避免N+1查询。
重构计算逻辑,降低视图复杂度
- 不要把所有计算逻辑堆在视图里,抽成单独的服务类/函数(比如
salary_calculator.py),视图只负责接收请求、调用计算函数、返回结果,这样代码更清晰,也方便单独测试优化。 - 把重复使用的计算逻辑(比如获取公司近2周费率、客户上周费率)封装成模型方法或自定义管理器,避免重复写查询语句。
缓存:适合非实时计算的最优解
- 薪资计算基于历史数据,不需要实时更新,直接用Django缓存框架缓存计算结果:
- 单个调度员的薪资,缓存键设为
dispatcher_salary_{dispatcher_id}_{today},缓存时长设为1天(每天凌晨更新一次即可)。 - 如果是批量计算多个调度员,缓存整个结果集或者按地区分组缓存,避免重复计算。
- 单个调度员的薪资,缓存键设为
- 可以用Django的
cache_page装饰器缓存整个视图的响应,但要注意如果不同用户看到的内容不同,需要结合用户ID或调度员ID做缓存键。
异步计算:适合批量/超复杂场景
- 如果经过查询优化和缓存后,单次计算还是很慢(比如批量生成所有调度员的月度薪资),可以用Celery把计算任务放到后台异步执行:
- 视图接收请求后立即返回“计算中,请稍后查看”的提示,后台任务完成后把结果存到数据库或缓存,用户刷新页面就能看到。
- 单个调度员的薪资计算没必要用异步,缓存足够解决问题。
是否拆分视图?没必要
拆分视图会增加前端请求次数和后端维护成本,反而降低效率。应该把计算逻辑从视图中剥离,而不是拆分视图本身。
内容的提问来源于stack exchange,提问作者Valeriu
相关产品推荐
相关产品推荐

