perf: CTE任务树加载器 + MOM跨库查询缓存
消除两个核心N+1性能瓶颈: 1. CTE任务树加载器 (task_tree_loader.py) - PostgreSQL Recursive CTE一次性加载完整任务树 - 无论树深度多大,仅2条SQL(CTE + records selectinload) - set_committed_value安全注入,避免Session脏数据 - 修复add_task_record双重加载问题 - 移除get_all_tasks中冗余的selectinload(child_tasks) 2. MOM跨库查询缓存 (mom_cache.py) - 零依赖TTL内存缓存(threading.RLock + time.monotonic) - 参数化ANY(:user_ids)替代OR拼接LIKE(防注入) - get_all_products中3次调用共享缓存,2h TTL内零跨库查询
This commit is contained in:
@ -125,39 +125,9 @@ async def _get_task_or_404(db: AsyncSession, task_id: uuid.UUID) -> Task:
|
||||
|
||||
|
||||
async def _get_task_with_children_recursive(db: AsyncSession, task_id: uuid.UUID) -> Task:
|
||||
"""递归加载任务及其所有子孙任务"""
|
||||
result = await db.execute(
|
||||
select(Task)
|
||||
.options(
|
||||
selectinload(Task.child_tasks),
|
||||
selectinload(Task.records),
|
||||
)
|
||||
.where(Task.id == task_id)
|
||||
)
|
||||
task = result.scalar_one_or_none()
|
||||
if not task:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"任务不存在: {task_id}",
|
||||
)
|
||||
|
||||
# 递归加载每一层子任务
|
||||
async def _load_children(t: Task):
|
||||
for child in t.child_tasks:
|
||||
child_result = await db.execute(
|
||||
select(Task)
|
||||
.options(
|
||||
selectinload(Task.child_tasks),
|
||||
selectinload(Task.records),
|
||||
)
|
||||
.where(Task.id == child.id)
|
||||
)
|
||||
refreshed_child = child_result.scalar_one()
|
||||
t.child_tasks[t.child_tasks.index(child)] = refreshed_child
|
||||
await _load_children(refreshed_child)
|
||||
|
||||
await _load_children(task)
|
||||
return task
|
||||
"""使用 PostgreSQL Recursive CTE 一次性加载任务及其所有子孙任务(消除 N+1)"""
|
||||
from app.services.task_tree_loader import load_task_tree_by_root
|
||||
return await load_task_tree_by_root(db, task_id)
|
||||
|
||||
|
||||
def _to_flat_response(task: Task) -> TaskResponse:
|
||||
@ -326,7 +296,6 @@ async def get_all_tasks(
|
||||
) -> TaskListResponse:
|
||||
"""获取任务列表,可按产品/负责人筛选"""
|
||||
stmt = select(Task).options(
|
||||
selectinload(Task.child_tasks),
|
||||
selectinload(Task.records),
|
||||
selectinload(Task.product),
|
||||
)
|
||||
@ -1085,5 +1054,6 @@ async def add_task_record(
|
||||
await db.commit()
|
||||
await db.refresh(record)
|
||||
|
||||
# 重新加载 task 带上新 record
|
||||
return await get_task(db, task_id)
|
||||
# 手动追加新 record,避免二次加载整棵树(task 已在 L1051 由 CTE 完整加载)
|
||||
task.records.append(record)
|
||||
return _to_response(task)
|
||||
|
||||
Reference in New Issue
Block a user