From e1256b9d9db1e71ce846df3cdf7f39021230dbf1 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:41:28 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[=EC=84=B1=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0]=20ERD=20=EB=85=B8=EB=93=9C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=8B=9C=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=B3=91?= =?UTF-8?q?=ED=95=A9=20=EB=B0=8F=20WeakMap=20=EC=BA=90=EC=8B=B1=EC=9D=84?= =?UTF-8?q?=20=ED=86=B5=ED=95=9C=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ’‘ What: ERD 검색 μ‹œ λ…Έλ“œμ˜ λͺ¨λ“  λ¬Έμžμ—΄ ν•„λ“œλ₯Ό ν•˜λ‚˜λ‘œ 합쳐 `WeakMap`에 μΊμ‹±ν•˜λ„λ‘ 검색 λ‘œμ§μ„ μˆ˜μ •ν–ˆμŠ΅λ‹ˆλ‹€. 🎯 Why: κΈ°μ‘΄ 방식은 타이핑 μ‹œλ§ˆλ‹€ λ…Έλ“œμ˜ λͺ¨λ“  컬럼 λ¬Έμžμ—΄μ„ 맀번 `.toLocaleLowerCase()`둜 λ³€ν™˜ν•˜μ—¬ κ³Όλ„ν•œ 객체 ν• λ‹Ήκ³Ό GC λΆ€ν•˜λ₯Ό μœ λ°œν–ˆμŠ΅λ‹ˆλ‹€. πŸ“Š Impact: 타이핑 μ‹œλ§ˆλ‹€ λ°œμƒν•˜λŠ” λ¬Έμžμ—΄ 할당을 O(C)μ—μ„œ O(1)둜 λŒ€ν­ κ°μ†Œμ‹œν‚€κ³ , C++ μˆ˜μ€€μ˜ 단일 λ¬Έμžμ—΄ `.includes()`둜 검색 속도λ₯Ό ν–₯μƒμ‹œν‚΅λ‹ˆλ‹€. πŸ”¬ Measurement: 수백 개의 ν…Œμ΄λΈ”κ³Ό 컬럼이 μžˆλŠ” λŒ€κ·œλͺ¨ ERDμ—μ„œ 타이핑 μ‹œ λ°œμƒν•˜λŠ” ν”„λ ˆμž„ λ“œλžμ΄ ν˜„μ €νžˆ κ°μ†Œν•˜κ³  λ°˜μ‘μ„±μ΄ κ°œμ„ λ©λ‹ˆλ‹€. --- .jules/bolt.md | 4 ++++ frontend/src/erd/search.ts | 30 ++++++++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index f1a8c1466..9a89d7d23 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -77,3 +77,7 @@ 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-08-25 - [Search Performance] λ…Έλ“œ ν…μŠ€νŠΈ 톡합 및 WeakMap 캐싱을 ν†΅ν•œ ERD 검색 μ΅œμ ν™” +**Learning:** λ‹€μˆ˜μ˜ λ¬Έμžμ—΄ ν•„λ“œλ₯Ό κ°œλ³„μ μœΌλ‘œ `.toLocaleLowerCase()` ν˜ΈμΆœν•˜μ—¬ κ²€μƒ‰ν•˜λ©΄, 검색어 μž…λ ₯λ§ˆλ‹€ μˆ˜λ§Žμ€ λ¬Έμžμ—΄ 객체가 μƒμ„±λ˜μ–΄ GC λΆ€ν•˜μ™€ ν”„λ ˆμž„ λ“œλžμ΄ λ°œμƒν•©λ‹ˆλ‹€. V8의 단일 λ¬Έμžμ—΄ 탐색이 JS 루프보닀 훨씬 λΉ λ¦…λ‹ˆλ‹€. +**Action:** λ…Έλ“œμ˜ λͺ¨λ“  검색 λŒ€μƒ ν…μŠ€νŠΈλ₯Ό ν•˜λ‚˜μ˜ λ¬Έμžμ—΄λ‘œ κ²°ν•©ν•œ λ’€ μ†Œλ¬Έμžλ‘œ λ³€ν™˜ν•˜κ³ , 이λ₯Ό μ•ˆμ •μ μΈ `node.data` 객체λ₯Ό ν‚€λ‘œ ν•˜λŠ” `WeakMap`에 μΊμ‹±ν•˜μ—¬ O(1) 쑰회둜 μ΅œμ ν™”ν•΄μ•Ό ν•©λ‹ˆλ‹€. diff --git a/frontend/src/erd/search.ts b/frontend/src/erd/search.ts index 51806947a..69c3bb053 100644 --- a/frontend/src/erd/search.ts +++ b/frontend/src/erd/search.ts @@ -2,21 +2,25 @@ import type { Node } from "@xyflow/react"; import type { TableNodeData } from "./convert"; -function fieldIncludes(value: string | null | undefined, term: string): boolean { - return Boolean(value && value.toLocaleLowerCase().includes(term)); -} +const nodeSearchTextCache = new WeakMap(); + +function getNodeSearchText(node: Node): string { + let text = nodeSearchTextCache.get(node.data); + if (text !== undefined) return text; -function nodeIncludesTerm(node: Node, term: string): boolean { - if (fieldIncludes(node.data.title, term)) return true; - if (fieldIncludes(node.data.comment, term)) return true; + const parts: string[] = []; + if (node.data.title) parts.push(node.data.title); + if (node.data.comment) parts.push(node.data.comment); - for (const column of node.data.columns) { - if (fieldIncludes(column.column_name, term)) return true; - if (fieldIncludes(column.data_type, term)) return true; - if (fieldIncludes(column.column_comment, term)) return true; + for (const col of node.data.columns) { + if (col.column_name) parts.push(col.column_name); + if (col.data_type) parts.push(col.data_type); + if (col.column_comment) parts.push(col.column_comment); } - return false; + text = parts.join(" ").toLocaleLowerCase(); + nodeSearchTextCache.set(node.data, text); + return text; } export function tableNodeMatchesSearch( @@ -29,7 +33,9 @@ export function tableNodeMatchesSearch( new Set(search.trim().toLocaleLowerCase().split(/\s+/).filter(Boolean)), ); if (terms.length === 0) return false; - return terms.every((term) => nodeIncludesTerm(node, term)); + + const nodeText = getNodeSearchText(node); + return terms.every((term) => nodeText.includes(term)); } export function findSearchMatchedNodeIds(