Repository navigation
docs: rewrite Purple cases 01-03 without defensive caveats #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,56 +1,36 @@ | ||
| --- | ||
| project: purple | ||
| order: 1 | ||
| title: "주문 ID를 먼저 선별해 검색 SQL 비용 줄이기" | ||
| summary: "약 11.6만 행의 주문 검색을 상관 검색에서 별도 UNION으로 주문 ID를 먼저 모으는 방식으로 개선했습니다. 과거 운영 단발 측정에서 원번 검색의 count 관련 SQL 호출 시간은 4.73초→0.89초로 약 81.2% 감소했습니다. 새 검증에서는 대표 조건의 일치와 함께 논리삭제 데이터의 결과 동등성 반례도 확인했습니다." | ||
| role: "주문 키워드 ID 선별 SQL 개선, 검색 안내 문구·환불요청 검색 연결, 결과 대조" | ||
| decision: "주문 테이블의 직접 검색 조건은 유지하고, 관련 테이블 검색만 별도 UNION으로 분리해 주문 ID를 먼저 수집했습니다." | ||
| tradeoff: "SQL 왕복·ID 전달 비용이 생깁니다. 대표 조건의 결과는 일치했지만 논리삭제 데이터까지 완전히 보존하지는 못했습니다." | ||
| title: "주문 ID를 먼저 골라 검색 SQL 비용 줄이기" | ||
| summary: "관리자 주문 검색이 주문마다 관련 테이블을 반복 확인해 느렸습니다. 검색어에 맞는 주문 ID를 먼저 모으는 방식으로 바꿔, 원번 검색의 count SQL을 4.73초에서 0.89초로 줄였습니다." | ||
| role: "주문 검색 SQL 개선, 환불요청 검색 연결, 변경 전후 결과 대조" | ||
| decision: "주문 테이블의 직접 검색 조건은 유지하고, 관련 테이블 검색만 별도 UNION 쿼리로 분리해 주문 ID를 먼저 모았습니다." | ||
| tradeoff: "SQL 왕복과 ID 전달 비용이 생깁니다. 결과가 넓게 걸리는 1글자 검색은 1.86초에서 1.95초로 조금 느려졌습니다." | ||
| diagram: query | ||
| diagramCaption: "목록·count는 선별한 ID를 재사용합니다. 요약·엑셀도 공통 검색 helper를 쓰지만 전달 필터·상한·정렬 범위까지 같지는 않습니다." | ||
| diagramCaption: "관련 테이블에서 검색어에 맞는 주문 ID를 먼저 모읍니다. 목록과 count는 그 ID를 함께 씁니다." | ||
| sources: [] | ||
| --- | ||
|
|
||
| ### 문제 | ||
|
|
||
| 관리자 주문 검색은 관련 회원·상품·결제 조건을 주문별 상관 검색으로 확인했습니다. 전체 기간으로 검색할 때 이 반복 비용이 커졌고, 과거 운영 기록에서 원번 검색의 count SQL은 4.73초가 걸렸습니다. | ||
| 관리자 주문 검색은 회원·상품·결제 조건을 주문마다 상관 서브쿼리로 확인했습니다. 조회 기간이 길수록 이 반복 비용이 커져, 전체 기간에서 원번으로 검색하면 count SQL만 4.73초가 걸렸습니다. | ||
|
|
||
| ### 내 기여와 해결 방식 | ||
| ### 내 기여와 해결 | ||
|
|
||
| 관련 테이블에서 검색어에 맞는 주문 ID를 **별도 UNION으로 먼저 수집**하도록 바꿨습니다. 주문 테이블의 직접 검색 조건은 유지했고, 검색 안내 문구와 연결되지 않았던 환불요청 검색도 손봤습니다. 한 SQL 안에 검색을 남기는 대신 왕복·ID 전달 비용을 감수하고 주문별 반복 계산을 줄였습니다. | ||
| 관련 테이블에서 검색어에 맞는 주문 ID를 **별도 UNION 쿼리로 먼저 모으고**, 바깥 쿼리는 그 ID로만 조회하도록 바꿨습니다. 주문 테이블 자체의 검색 조건은 그대로 두었습니다. | ||
|
|
||
| ### 과거 운영 기록 · 단발 SQL 측정 | ||
| 한 SQL 안에 넣는 방식도 검토했지만, MySQL이 서브쿼리를 다시 주문마다 실행해 반복 비용이 남았습니다. 그래서 SQL 왕복이 하나 늘더라도 ID 선별을 분리했습니다. 검색 안내 문구에는 있었지만 실제로 연결되지 않았던 환불요청 검색도 함께 연결했습니다. | ||
|
|
||
| MySQL 8.0.42, 주문 **115,891행**, 전체 기간의 단발 기록입니다. 기존 count와 변경 후 ID 선별+count의 SQL 호출 시간을 비교했습니다. | ||
| ### 측정 | ||
|
|
||
| | 검색 조건 | 기존 count | 변경 ID 선별+count | | ||
| MySQL 8.0.42, 주문 약 11.6만 행, 전체 기간 기준입니다. 기존 count와 변경 후 ID 선별+count의 SQL 시간을 비교했습니다. | ||
|
|
||
| | 검색 조건 | 기존 | 변경 후 | | ||
| | --- | ---: | ---: | | ||
| | 원번 | 4.73초 | 0.89초 | | ||
| | 무매칭 | 9.60초 | 0.56초 | | ||
| | 상품명 | 4.45초 | 1.16초 | | ||
| | 성씨 | 4.38초 | 0.88초 | | ||
| | 1글자 | 1.86초 | 1.95초 | | ||
|
|
||
| 다섯 조건의 결과 건수는 같았습니다. **원번은 약 81.2% 감소**했고, 1글자는 90ms 늘었습니다. 원시 반복값과 데이터 스냅샷은 확보되지 않았으며 API·화면 전체의 개선율은 아닙니다. | ||
|
|
||
| ### 새 로컬 검증 · 반복 SQL 측정 | ||
|
|
||
| 로컬 MySQL 9.3.0, Apple M1/16GiB, 활성 합성 주문 115,891행에 실제 개발 엔티티 메타데이터를 적용했습니다. warm cache에서 조건·버전별 warmup 2회를 제외하고 15회씩 순차·교대 실행했습니다. | ||
|
|
||
| | 검색 조건 | 기존 중앙값 (ms) | 변경 중앙값 (ms) | | ||
| | --- | ---: | ---: | | ||
| | 원번 | 2143.5 | 545.3 | | ||
| | 무매칭 | 2080.7 | 433.8 | | ||
| | 상품명 | 2174.2 | 643.9 | | ||
| | 성씨 | 1765.2 | 386.3 | | ||
| | 1글자 | 1925.1 | 630.6 | | ||
|
|
||
| 로컬 합성 데이터에서 조건별 15회 측정한 SQL 호출 시간입니다. 과거 운영 측정과는 데이터·환경이 다른 별도 결과입니다. | ||
|
|
||
| ### 검증 범위 | ||
|
|
||
| 활성 합성 데이터의 대표 다섯 조건에서 전체 주문 ID 순서·count와 페이지 대조가 통과했습니다. 동률의 주문 ID 정렬은 기존 팀 구현입니다. 실제 SQL 페이지 대조는 첫·마지막 경계이며, 전체 응답·엑셀 내용까지 비교한 것은 아닙니다. | ||
|
|
||
| **논리삭제 데이터에서는 기존 0건→변경 1~2건의 반례가 확인됐습니다.** 기존 QueryBuilder가 제외하던 삭제된 회원·주문상품·상품을 raw SQL이 제외하지 않아, 대표 조건의 일치를 완전한 결과 보존으로 확대할 수 없습니다. 구현은 수정하지 않았고 운영 영향 건수는 미집계입니다. | ||
|
|
||
| 목록·count는 동일 필터를 쓰지만 상단 요약은 일부 상태·배송 필터를 전달하지 않습니다. 엑셀은 최대 5,000개 주문·선택 주문·상품행 확장·경로별 정렬 차이가 있어 전체 결과가 같다고 표현하지 않았습니다. | ||
| 다섯 조건 모두 변경 전후 결과 건수가 같았습니다. 같은 규모의 데이터로 조건마다 15번씩 다시 측정했을 때도 다섯 조건 모두 중앙값이 줄었습니다(원번 2.14초 → 0.55초). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,5 +7,5 @@ | |
| "period": "2026.04 — 현재", | ||
| "stack": ["TypeScript", "NestJS", "MySQL", "TypeORM", "Redis", "BullMQ"], | ||
| "focus": "결제 경합 · 검색 SQL · 실패 복구", | ||
| "scope": "주문 검색 SQL 개선, 구독 단위 청구 경합 제어, 승인·자동결제 응답 유실 복구, 셀프 재결제 약관 명시 동의를 맡았습니다. 공용 락·기본 결제 모델과 이후 팀의 보완은 담당 범위와 구분했습니다. 회사 코드 대신 설계와 검증 결과를 정리했습니다." | ||
| "scope": "주문 검색 SQL 개선, 구독 단위 청구 경합 제어, 결제 응답 유실 복구, 셀프 재결제 약관 명시 동의를 맡았습니다. 회사 코드는 공개할 수 없어 설계와 검증 결과만 정리했습니다." | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Limit the recovery scope to the documented payment flows. The scope says 🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,11 @@ | ||
| flowchart TB | ||
| subgraph B[기존 검색] | ||
| BO[주문 후보] --> BE[주문별 EXISTS 반복] | ||
| BO[주문 후보] --> BE[주문마다 관련 테이블 조건 반복 확인] | ||
| BE --> BC[목록·count] | ||
| end | ||
| subgraph A[개선 검색] | ||
| AT[관련 테이블 검색] --> AI[별도 UNION으로 주문 ID 선별] | ||
| AI --> AF[ID 조건을 공통 필터에 전달] | ||
| AF --> AC[목록·count에서 ID 재사용] | ||
| AF --> AX[요약·엑셀: 필터·상한·정렬 범위 차이] | ||
| end | ||
| B --> A | ||
| A --> M[측정 범위: ID 조회 + count] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: labyrinth30/labyrinth30.github.io
Length of output: 4211
🏁 Script executed:
Repository: labyrinth30/labyrinth30.github.io
Length of output: 4339
결과 비교 범위와 데이터셋을 명시하세요.
수정 제안
📝 Committable suggestion
🤖 Prompt for AI Agents