diff --git a/.jules/bolt.md b/.jules/bolt.md index f1a8c146..63d801d9 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. +## 2023-10-27 - [Dictionary Lookup over sum() in DBML Import] +**Learning:** In the backend `dbml_import.py` logic, utilizing `sum(1 for c in columns if c["relation_oid"] == oid) + 1` inside an iteration loops dynamically allocated lists causing a heavy O(N^2) overhead, especially noticeable with wide tables or lots of fields. Also, always add a descriptive comment as Bolt. +**Action:** Always prefer initializing a dictionary prior to the loop and use `O(1)` dict lookups like `pos = col_count_by_oid.get(oid, 0) + 1` to process sequences where frequency tracking is required within loops. diff --git a/backend/app/spec/dbml_import.py b/backend/app/spec/dbml_import.py index b93454a9..a37a60d2 100644 --- a/backend/app/spec/dbml_import.py +++ b/backend/app/spec/dbml_import.py @@ -135,6 +135,7 @@ def parse_dbml(text: str) -> dict[str, Any]: current: tuple[str, str] | None = None in_ignored_block = 0 in_indexes = False + col_count_by_oid: dict[int, int] = {} for raw_line in text.splitlines(): # ReDoS guard: no legitimate DBML line approaches this length; capping @@ -207,11 +208,17 @@ def parse_dbml(text: str) -> dict[str, Any]: settings = (cm.group("settings") or "").lower() oid = oid_by_table[current] is_pk = bool(re.search(r"\bpk\b|primary\s+key", settings)) + + # ⚡ Bolt: Performance Optimization + # Use an O(1) dictionary counter instead of an O(N^2) sum(...) loop + # to calculate column positions efficiently for large DBML files. + pos = col_count_by_oid.get(oid, 0) + 1 + col_count_by_oid[oid] = pos columns.append( { "relation_oid": oid, "column_name": col_name, - "column_position": sum(1 for c in columns if c["relation_oid"] == oid) + 1, + "column_position": pos, "data_type": cm.group("type"), "is_not_null": is_pk or "not null" in settings, "has_default": "default:" in settings,