研发协作
在审查 Django 代码性能、查找 N+1 查询、无界…
适用于对 Django 项目做性能代码审查,定位并验证 ORM/queryset/数据库性能问题,避免误报。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
在审查 Django 代码性能、查找 N特定
解决思路
- 审查前先研究:追踪数据流,检查已有优化,验证数据量。
- 报告前先验证:模式匹配不是验证。
- 接受零发现:不要为了显得全面而制造问题。
- 严重性必须匹配影响:如果写的是 CRITICAL 却想标为 minor,就降级或跳过。
- 按影响优先级聚焦:P1 N+1 Queries 为 CRITICAL,P2 Unbounded Querysets 为 CRITICAL,P3 Missing Indexes 为 HIGH,P4 Write Loops 为 HIGH,P5 Inefficient Patterns 为 LOW,重点检查 CRITICAL 和 HIGH。
- P1 N+1 规则:对循环中访问的关联数据,在视图/queryset 中使用 select_related 或 prefetch_related;验证方式是追踪 View → Queryset → Template/Serializer → Loop access。
- P1 N+1 规则:在 serializer 中也要做预取,不只是视图;DRF 中 SerializerMethodField 逐对象查询如 obj.orders.count() 改为在 viewset 的 get_queryset 中 annotate(order_count=Count('orders')),serializer 用 IntegerField(read_only=True)。
- P1 N+1 规则:模型中会触发查询的 property 在循环中危险;用 Prefetch 自定义 queryset,或 annotate。
- P1 N+1 验证清单:追踪 view 到 template/serializer 的数据流。
- P1 N+1 验证清单:确认关联字段在循环内被访问。
- P1 N+1 验证清单:搜索代码库中已有的 select_related/prefetch_related。
- P1 N+1 验证清单:验证表有显著行数(1000+)。
- P1 N+1 验证清单:确认是热路径(不是 admin,不是罕见操作)。
- P2 Unbounded Querysets 规则:列表端点总是分页,例如 ListView 设置 paginate_by = 25。
- P2 Unbounded Querysets 规则:大批量处理使用 iterator(),例如 User.objects.iterator(chunk_size=1000)。
- P2 Unbounded Querysets 规则:不要对无界 queryset 调用 list();保留为 queryset,需要时切片,例如 User.objects.all()[:100]。
- P2 Unbounded Querysets 验证清单:表很大(10k+ 行)或会无界增长。
- P2 Unbounded Querysets 验证清单:没有 pagination class、paginate_by 或 slicing。
- P2 Unbounded Querysets 验证清单:运行在用户请求路径(不是带分块的后台任务)。
- P3 Missing Indexes 规则:大表上用于 WHERE 的字段加索引,例如 email = models.EmailField(db_index=True)。
- P3 Missing Indexes 规则:大表上用于 ORDER BY 的字段加索引,例如 created = models.DateTimeField(db_index=True)。
- P3 Missing Indexes 规则:常见查询模式用复合索引,例如 Meta.indexes 中 models.Index(fields=['user', 'status']) 和 models.Index(fields=['status', '-created'])。
- P3 Missing Indexes 验证清单:表有 10k+ 行。
- P3 Missing Indexes 验证清单:字段在热路径的 filter() 或 order_by() 中使用。
- P3 Missing Indexes 验证清单:检查模型,没有 db_index=True 或 Meta.indexes 条目。
- P3 Missing Indexes 验证清单:不是外键(外键已自动索引)。
- P4 Write Loops 规则:循环中用 bulk_create 替代 create()。
- P4 Write Loops 规则:循环中用 update() 替代 save()(所有对象相同值),例如 queryset.update(status='done')。
- P4 Write Loops 规则:循环中用 bulk_update 替代 save()(不同值),例如 Model.objects.bulk_update(objects, ['status'], batch_size=500)。
- P4 Write Loops 规则:循环中用 queryset.delete() 替代逐个 delete()。
- P4 Write Loops 验证清单:循环迭代 100+ 项或无限。
- P4 Write Loops 验证清单:每次迭代调用 create()、save() 或 delete()。
- P4 Write Loops 验证清单:运行在用户请求路径(不是一次性迁移脚本)。
- P5 Inefficient Patterns 通常跳过,仅在已在报告真实问题时作为 minor notes。
- P5 count() vs exists():if queryset.count() > 0 可改为 if queryset.exists(),但通常跳过,差异 <1ms。
- P5 len(queryset) vs count():仅当 queryset 大且尚未求值时才标记;可改为 queryset.count()。
- P5 get() in small loops:仅当循环大或在非常热的路径时才标记。
- 报告任何问题前验证:追踪数据流,从 queryset 创建到消费。
- 报告任何问题前验证:搜索已有优化,grep select_related、prefetch_related、pagination。
- 报告任何问题前验证:验证数据量,检查表是否真的很大。
- 报告任何问题前验证:确认热路径,追踪调用点,验证是否频繁运行。
- 报告任何问题前验证:排除缓解措施,检查缓存、限流。
- 如果无法验证所有步骤,不要报告。
- 输出格式:使用 markdown 模板,包含 ## Django Performance Review: [File/Component Name]、### Summary(Validated issues: X (Y Critical, Z High))、### Findings。
- 每个发现包含 [PERF-001] 标题、Location、Issue、Validation(追踪、搜索、表行数、热路径)、Evidence、Fix。
- 无问题时输出 No performance issues identified after reviewing [files] and validating [what you checked].。
- 提交前 sanity check 每个发现:严重性是否匹配实际影响;是真实性能问题还是风格偏好;修复是否能可测量地改善性能;任一为否则移除。
适用边界 · 注意事项
- 不要审查测试文件、admin-only 视图、管理命令、迁移文件、一次性脚本、禁用 feature flags 后的代码、<1000 行且不会增长的表、冷路径中的模式、微优化(exists vs count、无证据的 only/defer)。
- 不要把风格偏好、queryset 变量赋值、单次查询、单对象缺少 select_related 当作 N+1/CRITICAL/HIGH 报告。
- 若无法完成数据流追踪、已有优化搜索、数据量验证、热路径确认、缓解措施排除,则不要报告。