perf(core): assets/ledgers 列表 defer 掉 AITask 巨型 payload 列,根治取全部资产 60s+ 慢查询

- /api/assets/ 列表 select_related('origin_task__project') 为解析资产归属商品,
  会把每个资产关联 AITask 的 request_payload/response_payload(完整 AI 请求/响应 JSON)
  整行拖出 → 取全部 200 资产实测 >60s 超时,数据越多越慢(用户报的「刷新越来越卡」)。
  加 .defer 这两列后 0.76s,product 仍正常解析、序列化 0 额外查询。
- billing/ledgers 同模式补 .defer(task payload)。ai/billing.summary 早已 defer,assets/ledgers 本是漏网。
- 附 qa/function-audit/perf-probe.mjs 性能验证闸 + PERF-GATE.md(API 确定性断言+浏览器功能守护)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-17 16:48:15 +08:00
co-authored by Claude Opus 4.8
parent 9bdd0683f8
commit 1ff7be2b56
4 changed files with 379 additions and 3 deletions
+10 -2
View File
@@ -28,8 +28,16 @@ class AssetPagination(PageNumberPagination):
class AssetViewSet(TeamScopedViewSetMixin, ModelViewSet):
# select_related 回溯链:asset → origin_task → project,供序列化器解析资产归属商品(避免 N+1)
queryset = Asset.objects.prefetch_related("files").select_related("origin_task__project").all()
# select_related 回溯链:asset → origin_task → project,供序列化器解析资产归属商品(避免 N+1)
# ★ defer 掉 AITask 的两个巨型 JSON 列(request/response payload):列表序列化只需 project.product_id,
# 不 defer 的话 select_related 会把每个资产关联 AITask 的完整 AI 请求/响应 payload 全拖出来,
# 200 个资产实测 100s+(数据越多越慢);defer 后 <1s、product 仍正常解析、无额外查询。
queryset = (
Asset.objects.prefetch_related("files")
.select_related("origin_task__project")
.defer("origin_task__request_payload", "origin_task__response_payload")
.all()
)
serializer_class = AssetSerializer
pagination_class = AssetPagination
search_fields = ["name", "description"]
+8 -1
View File
@@ -49,7 +49,14 @@ def summary(request):
@permission_classes([IsAuthenticated])
def ledgers(request):
team = get_current_team(request.user)
queryset = CreditLedger.objects.filter(team=team).select_related("user", "project", "task").order_by("-created_at")
# defer task 的两个巨型 payload 列:流水只展示金额/类型/关联,不需要 AI 请求/响应 payload。
# 与 assets/billing.summary 同一惯例,避免 select_related("task") 把大 JSON 拖出来。
queryset = (
CreditLedger.objects.filter(team=team)
.select_related("user", "project", "task")
.defer("task__request_payload", "task__response_payload")
.order_by("-created_at")
)
project_id = request.query_params.get("project")
user_id = request.query_params.get("user")
if project_id: