본문 바로가기

카테고리 없음

📝 TIL – JOIN + OR + DISTINCT 쿼리에서 Full-Text 인덱스와 성능

📌 배경

  • 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 기반 검색이 실속 있는 선택