📌 배경
- store와 menu 테이블에서 store.name 또는 menu.name에 대해 키워드 기반 검색을 구현 중
- 현재는 %LIKE% 연산을 사용하고 있고, 향후 성능 개선을 위해 Full-Text 인덱스를 고려함
🤔 문제 상황
기존 쿼리 예시:
SELECT DISTINCT s.* FROM store s JOIN menu m ON s.id = m.store_id WHERE s.name LIKE '%치킨%' OR m.name LIKE '%치킨%';
- JOIN + OR 조합이 복잡한 조건을 만들어서 옵티마이저가 인덱스를 제대로 활용하지 못함
- DISTINCT는 중복 제거를 위한 추가 연산을 수행 → 성능 저하
- Full-Text 인덱스를 적용해도 위 구조에서는 성능 개선이 제한적일 수 있음
🔍 실험: UNION으로 쿼리 분리
SELECT s.id FROM store s WHERE MATCH(s.name) AGAINST ('치킨') UNION SELECT s.id FROM store s JOIN menu m ON s.id = m.store_id WHERE MATCH(m.name) AGAINST ('치킨');
- OR 대신 UNION을 사용하면 각 서브쿼리에서 Full-Text 인덱스를 독립적으로 사용할 수 있음
- 단순 조회에는 효과적, 하지만...
⚠️ 중요한 인사이트: COUNT 성능은 여전히 병목
SELECT COUNT(DISTINCT s.id) FROM ( -- Full-Text 검색 + UNION ) AS results;
- UNION 자체도 중복 제거 연산을 수행
- 여기에 COUNT(DISTINCT)가 추가되면 이중 중복 제거 발생
- Full-Text 인덱스는 빠르지만, 최종 집계 단계에서 병목 발생
⚠️ 실험 결과(최종)
❌ Full-Text (MATCH ... AGAINST)
SELECT s.* FROM store s WHERE MATCH(s.name) AGAINST ('치킨' IN BOOLEAN MODE)
- 기대한 것보다 느림
- JOIN + UNION + DISTINCT와 결합 시 오히려 더 느려짐
- MATCH는 앞부분 prefix 매칭이 아니라 자연어 기반 연산이기 때문에 오히려 비쌀 수 있음
✅ LIKE '%키워드%'
SELECT DISTINCT s.* FROM store s JOIN menu m ON s.id = m.store_id WHERE s.name LIKE '%치킨%' OR m.name LIKE '%치킨%';
- 단순한 LIKE '%keyword%' 기반 쿼리가 더 빠름
- 특히 작은 데이터셋(수천~수만 row)에서는 LIKE가 디스크 I/O 없이 메모리에서 빠르게 수행됨
- Full-Text는 큰 텍스트 필드 + 대량 데이터에 더 적합
🤔 왜 이런 결과가 나왔을까?
항목Full-TextLIKE
인덱스 기반 | 별도 Full-Text 인덱스 필요 | 인덱스 미사용, Full Scan |
비용 | 자연어 분석 + 점수 계산 | 단순 문자열 비교 |
데이터 크기 | 작을 경우 오히려 느림 | 작을 때 매우 빠름 |
OR, JOIN과 조합 | 복잡해질수록 성능 저하 | 단일 쿼리에서도 일정 수준 성능 보장 |
✅ 결론
- ✔️ 현재 데이터 규모와 사용 패턴에서는 LIKE '%키워드%'가 Full-Text보다 빠르다
- ❌ Full-Text는 작은 텍스트, JOIN, COUNT, OR과 섞이면 오히려 병목 요인
- ✅ 현 시점에서는 복잡한 인덱스 전략보다 단순한 LIKE 기반 검색이 실속 있는 선택