주문 ID를 먼저 골라 검색 SQL 비용 줄이기
관리자 주문 검색이 주문마다 관련 테이블을 반복 확인해 느렸습니다.검색어에 맞는 주문 ID를 먼저 모으는 방식으로 바꿔, 원번 검색의 count SQL을 4.73초에서 0.89초로 줄였습니다.
- 내가 맡은 범위
- 주문 검색 SQL 개선, 환불요청 검색 연결, 변경 전후 결과 대조
- 선택과 이유
- 실행 계획과 측정으로 정렬은 병목이 아님을 확인해 인덱스는 추가하지 않았습니다.대신 검색어에 맞는 주문 ID를 별도 쿼리로 먼저 모아, 바깥 쿼리가 PK 조회만 하게 바꿨습니다.
- 트레이드오프
- SQL 왕복과 ID 전달 비용이 생깁니다.결과가 넓게 걸리는 1글자 검색은 1.86초에서 1.95초로 조금 느려졌습니다.
문제
관리자 주문 검색은 회원·상품·결제 조건을 주문마다 상관 서브쿼리로 확인했습니다. 조회 기간이 길수록 이 반복 비용이 커져, 전체 기간에서 원번으로 검색하면 count SQL만 4.73초가 걸렸습니다.
해결 과정
1. 실행 계획 확인
먼저 EXPLAIN을 돌렸습니다. 주문 테이블 전체를 훑으면서(type: ALL), 관련 테이블 조건마다 DEPENDENT SUBQUERY가 7개 붙어 있었습니다. 주문 한 건마다 서브쿼리가 다시 실행되는 구조였습니다.
2. 인덱스 확인
주문 테이블에 생성일·유형 인덱스가 없어 정렬(filesort)이 생기는 것도 보였습니다. 하지만 정렬 없는 count(0.55초)와 정렬한 목록 20건(0.49초)이 거의 같아, 정렬은 병목이 아니라고 보고 인덱스는 추가하지 않았습니다.
3. 한 SQL 안에서 ID 먼저 고르기
o.id IN (SELECT … UNION …) 형태로 바꿔 봤습니다. 그런데 MySQL이 이를 다시 DEPENDENT SUBQUERY/DEPENDENT UNION으로 실행해 실행 계획이 원래와 같았고, 시간도 4.55초로 그대로였습니다.
4. 쿼리를 둘로 나누기
검색어에 맞는 주문 ID를 별도 쿼리로 먼저 모으고, 바깥 쿼리는 그 ID로 PK 조회만 하게 했습니다. SQL 왕복은 한 번 늘었지만 원번 검색은 0.33초 + 0.56초 = 0.89초가 됐습니다.
주문 테이블 자체의 검색 조건은 그대로 두었고, 검색 안내 문구에는 있었지만 실제로 연결되지 않았던 환불요청 검색도 함께 연결했습니다.
측정
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초 |
다섯 조건 모두 변경 전후 결과 건수가 같았습니다. 같은 규모의 데이터로 조건마다 15번씩 다시 측정했을 때도 다섯 조건 모두 중앙값이 줄었습니다(원번 2.14초 → 0.55초).