优化计划查询避免 N+1 数据库访问
This commit is contained in:
@@ -203,11 +203,13 @@
|
|||||||
|
|
||||||
## 可重构/可优化项(非阻塞,但收益高)
|
## 可重构/可优化项(非阻塞,但收益高)
|
||||||
|
|
||||||
### R1 计划查询存在 N+1 查询模式
|
### R1 计划查询存在 N+1 查询模式【已完成】
|
||||||
|
- 修复状态:✅ 已完成(2026-03-03)
|
||||||
|
- 修复内容:
|
||||||
|
- `getPendingPlans`、`getHistoryPlans` 改为在 `weekendPlan.findMany` 中直接 `select room { name, code }`;
|
||||||
|
- 移除逐条 `findUnique` 查房间的 N+1 查询路径。
|
||||||
- 证据:
|
- 证据:
|
||||||
- `src/lib/planQueries.ts:30-36`、`63-68`(每条计划单独查房间)
|
- `src/lib/planQueries.ts` 已由“逐条房间查询”改为“单次查询带房间关系”。
|
||||||
- 建议:
|
|
||||||
- 使用 `include` / 批量映射一次性拉取房间信息,减少 DB 往返。
|
|
||||||
|
|
||||||
### R2 `atomicUpdateRoom` 对 likes 的“全删全建”策略成本较高
|
### R2 `atomicUpdateRoom` 对 likes 的“全删全建”策略成本较高
|
||||||
- 证据:
|
- 证据:
|
||||||
|
|||||||
+39
-41
@@ -1,5 +1,4 @@
|
|||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { ApiError } from "@/lib/api";
|
|
||||||
|
|
||||||
export async function getLatestPlan(roomId: string, userId: string) {
|
export async function getLatestPlan(roomId: string, userId: string) {
|
||||||
const plan = await prisma.weekendPlan.findFirst({
|
const plan = await prisma.weekendPlan.findFirst({
|
||||||
@@ -23,28 +22,27 @@ export async function getPendingPlans(userId: string) {
|
|||||||
endTime: { not: null, lt: new Date() },
|
endTime: { not: null, lt: new Date() },
|
||||||
},
|
},
|
||||||
orderBy: { createdAt: "desc" },
|
orderBy: { createdAt: "desc" },
|
||||||
select: { id: true, planData: true, roomId: true, createdAt: true },
|
select: {
|
||||||
|
id: true,
|
||||||
|
planData: true,
|
||||||
|
createdAt: true,
|
||||||
|
room: { select: { name: true, code: true } },
|
||||||
|
},
|
||||||
take: 5,
|
take: 5,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await Promise.all(
|
const result = plans.map((p) => {
|
||||||
plans.map(async (p) => {
|
const parsed = JSON.parse(p.planData);
|
||||||
const room = await prisma.blindBoxRoom.findUnique({
|
const days = parsed.days as { date: string; items: { activity: string }[] }[];
|
||||||
where: { id: p.roomId },
|
return {
|
||||||
select: { name: true, code: true },
|
id: p.id,
|
||||||
});
|
roomName: p.room?.name ?? "未知房间",
|
||||||
const parsed = JSON.parse(p.planData);
|
roomCode: p.room?.code ?? "",
|
||||||
const days = parsed.days as { date: string; items: { activity: string }[] }[];
|
date: days.map((d) => d.date).join(" + "),
|
||||||
return {
|
activities: days.flatMap((d) => d.items.map((i) => i.activity)),
|
||||||
id: p.id,
|
createdAt: p.createdAt,
|
||||||
roomName: room?.name ?? "未知房间",
|
};
|
||||||
roomCode: room?.code ?? "",
|
});
|
||||||
date: days.map((d) => d.date).join(" + "),
|
|
||||||
activities: days.flatMap((d) => d.items.map((i) => i.activity)),
|
|
||||||
createdAt: p.createdAt,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return { pending: result };
|
return { pending: result };
|
||||||
}
|
}
|
||||||
@@ -56,30 +54,30 @@ export async function getHistoryPlans(userId: string) {
|
|||||||
status: { in: ["completed", "expired"] },
|
status: { in: ["completed", "expired"] },
|
||||||
},
|
},
|
||||||
orderBy: { createdAt: "desc" },
|
orderBy: { createdAt: "desc" },
|
||||||
select: { id: true, planData: true, status: true, roomId: true, createdAt: true },
|
select: {
|
||||||
|
id: true,
|
||||||
|
planData: true,
|
||||||
|
status: true,
|
||||||
|
createdAt: true,
|
||||||
|
room: { select: { name: true, code: true } },
|
||||||
|
},
|
||||||
take: 50,
|
take: 50,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await Promise.all(
|
const result = plans.map((p) => {
|
||||||
plans.map(async (p) => {
|
const parsed = JSON.parse(p.planData);
|
||||||
const room = await prisma.blindBoxRoom.findUnique({
|
const days = parsed.days as { date: string; items: { activity: string }[] }[];
|
||||||
where: { id: p.roomId },
|
return {
|
||||||
select: { name: true, code: true },
|
id: p.id,
|
||||||
});
|
status: p.status,
|
||||||
const parsed = JSON.parse(p.planData);
|
roomName: p.room?.name ?? "未知房间",
|
||||||
const days = parsed.days as { date: string; items: { activity: string }[] }[];
|
roomCode: p.room?.code ?? "",
|
||||||
return {
|
date: days.map((d) => d.date).join(" + "),
|
||||||
id: p.id,
|
dayCount: days.length,
|
||||||
status: p.status,
|
activities: days.flatMap((d) => d.items.map((i) => i.activity)),
|
||||||
roomName: room?.name ?? "未知房间",
|
createdAt: p.createdAt,
|
||||||
roomCode: room?.code ?? "",
|
};
|
||||||
date: days.map((d) => d.date).join(" + "),
|
});
|
||||||
dayCount: days.length,
|
|
||||||
activities: days.flatMap((d) => d.items.map((i) => i.activity)),
|
|
||||||
createdAt: p.createdAt,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return { history: result };
|
return { history: result };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user