From 77186433827bdbfc0f360b6adc2afb7182fd6b7f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 4 Sep 2026 21:26:15 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[=EC=84=B1=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0]=20Prisma=20=EB=82=B4=EB=B3=B4=EB=82=B4?= =?UTF-8?q?=EA=B8=B0=20=EA=B4=80=EA=B3=84=20=EC=A1=B0=ED=9A=8C=20=EC=86=8D?= =?UTF-8?q?=EB=8F=84=20=EC=B5=9C=EC=A0=81=ED=99=94=20O(N*C*E)=20->=20O(N*C?= =?UTF-8?q?=20+=20E)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `exportPrisma` 함수 내부의 컬럼 루프 안에 있던 모든 엣지 순회 로직(O(E))을 미리 계산된 O(1) Map 참조 방식으로 대체했습니다. 대규모 다이어그램 내보내기 시 O(N * C * E)의 심각한 성능 병목 현상을 해결합니다. --- .jules/bolt.md | 3 +++ frontend/src/erd/prisma.ts | 17 ++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index f1a8c1466..3040df4b3 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -77,3 +77,6 @@ Optimized metric route processing to O(N) by creating a mapping of routes direct ## 2024-07-13 - [Optimize Export Dictionary FK lookups] **Learning:** Found O(N * C * E) performance bottleneck in ERD export dictionaries due to repeated array searching with `edges.some()` inside a nested loop over nodes and columns. **Action:** Replace repeated linear array scans for edges by precomputing O(1) Set lookups of foreign key column handles per node before looping. +## 2024-09-04 - Prisma Export O(N*C*E) Bottleneck Optimization +**Learning:** In the Prisma ERD exporter, iterating over all edges inside the nested loop of nodes and columns (`for (const [_, edgeInfo] of edgesProcessed)`) created an O(N * C * E) performance bottleneck. +**Action:** Pre-compute an O(1) lookup Map keyed by `${sourceModel}:${sourceField}` to resolve the relation directly, reducing the complexity to O(N * C + E). diff --git a/frontend/src/erd/prisma.ts b/frontend/src/erd/prisma.ts index 211dfdd8d..696a9ca39 100644 --- a/frontend/src/erd/prisma.ts +++ b/frontend/src/erd/prisma.ts @@ -59,7 +59,7 @@ export function exportPrisma( const fkNodeColumnPairs = new Set(); const fkNodesWithoutHandles = new Set(); const incomingRelationsByNode = new Map>(); - const edgesProcessed = new Map(); + const edgesProcessedByField = new Map(); for (const edge of edges) { const sourceNode = nodesById.get(edge.source); @@ -93,7 +93,7 @@ export function exportPrisma( }); incomingRelationsByNode.set(edge.target, relList); - edgesProcessed.set(edge.id, { + edgesProcessedByField.set(`${sanitizeName(sourceNode.data.title)}:${sanitizeName(sourceField)}`, { sourceModel: sanitizeName(sourceNode.data.title), targetModel: sanitizeName(targetNode.data.title), sourceFields: [sanitizeName(sourceField)], @@ -136,13 +136,12 @@ export function exportPrisma( // Determine if there is a relation defined on this field let relationDef = ""; - for (const [_, edgeInfo] of edgesProcessed) { - if (edgeInfo.sourceModel === modelName && edgeInfo.sourceFields.includes(fieldName)) { - // This field is a foreign key, but in Prisma, we typically define the relation object field - // alongside the scalar field. We will add the relation object field here. - const relField = sanitizeName(edgeInfo.targetModel) + "_" + fieldName; - relationDef = `\n ${relField} ${edgeInfo.targetModel}${optional} @relation("${edgeInfo.relationName}", fields: [${fieldName}], references: [${edgeInfo.targetFields[0]}])`; - } + const edgeInfo = edgesProcessedByField.get(`${modelName}:${fieldName}`); + if (edgeInfo && edgeInfo.sourceFields.includes(fieldName)) { + // This field is a foreign key, but in Prisma, we typically define the relation object field + // alongside the scalar field. We will add the relation object field here. + const relField = sanitizeName(edgeInfo.targetModel) + "_" + fieldName; + relationDef = `\n ${relField} ${edgeInfo.targetModel}${optional} @relation("${edgeInfo.relationName}", fields: [${fieldName}], references: [${edgeInfo.targetFields[0]}])`; } output += ` ${fieldName} ${prismaType}${optional}${attributes}${relationDef}\n`; From 3e39f568f9b849965f7b27836fbd11b74fbf3458 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 07:02:08 +0900 Subject: [PATCH 2/2] chore(perf): restore canonical Bolt doctrine --- .jules/bolt.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 3040df4b3..f1a8c1466 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -77,6 +77,3 @@ Optimized metric route processing to O(N) by creating a mapping of routes direct ## 2024-07-13 - [Optimize Export Dictionary FK lookups] **Learning:** Found O(N * C * E) performance bottleneck in ERD export dictionaries due to repeated array searching with `edges.some()` inside a nested loop over nodes and columns. **Action:** Replace repeated linear array scans for edges by precomputing O(1) Set lookups of foreign key column handles per node before looping. -## 2024-09-04 - Prisma Export O(N*C*E) Bottleneck Optimization -**Learning:** In the Prisma ERD exporter, iterating over all edges inside the nested loop of nodes and columns (`for (const [_, edgeInfo] of edgesProcessed)`) created an O(N * C * E) performance bottleneck. -**Action:** Pre-compute an O(1) lookup Map keyed by `${sourceModel}:${sourceField}` to resolve the relation directly, reducing the complexity to O(N * C + E).