카테고리 없음

오늘의 TIL: My SQL로 배우는 데이터 베이스 (3) 서브쿼리

superpark 2026. 5. 13. 20:44

오늘 SQL 수업은 진짜 역대급이었어. 단순히 SELECT 하는 걸 넘어서, 1억 건의 데이터 앞에서도 당당할 수 있는 성능 중심의 쿼리 짜는 법을 배웠거든. 재밌기도,, 어렵기도,, 아직 많이 헷갈리지만 잊어버리기 전에 반말로 빡세게 정리한다!

1. 기초 다지기: Group By & Join

  • Group By: 부서별 평균 급여 같은 집계 데이터를 만들 때 필수야. 집계함수(AVG, SUM 등)랑 찰떡궁합이지.
  • Join: 흩어진 테이블을 하나로 합쳐.
    • Self Join: 특히 중요! 네이버 면접에도 나왔던 전날보다 온도 높은 날 찾기처럼 같은 테이블 내에서 시간이나 선후 관계를 비교할 때 최고의 무기야.
    • + 추가 join 상세한 설명은 이 전에 올려놓은 join설명을 보면 도움이 될거야!  https://superpark.tistory.com/9

2. 서브쿼리(Subquery)의 3가지 얼굴

서브쿼리는 위치에 따라 이름도, 성격도 달라.

① 스칼라 서브쿼리 (Scalar Subquery)

  • 위치: SELECT 절
  • 특징: 한 칸에 들어갈 단일 값(1행 1열)만 뱉어야 해. 엑셀의 VLOOKUP 같은 느낌!

② 인라인 뷰 (Inline View) - 중요!

  • 위치: FROM 절
  • 특징: 서브쿼리 결과를 임시 테이블로 취급해.
  • 꿀팁: 여기서 별칭(Alias) 안 붙이면 무조건 에러 나. 컴퓨터가 이 임시 덩어리를 뭐라고 불러야 할지 모르거든. AS는 생략 가능하지만, 이름표 자체는 절대 빼먹지 마!

③ 상관 서브쿼리 (Correlated Subquery)

  • 특징: 메인 쿼리 한 줄 읽을 때마다 서브쿼리가 계속 실행돼.
  • 용도: 내 부서의 평균처럼 기준이 행마다 바뀔 때 사용해.

3. 성능 대결: EXISTS vs IN

데이터가 1억 건쯤 되면 여기서 승부가 갈려.

  • EXISTS: 있나 없나만 봐. 하나라도 찾으면 그 즉시 멈추고 True를 반환하니까 대용량 데이터에서 엄청 빨라.
  • IN: 리스트를 일단 다 뽑아서 비교해. 서브쿼리 쪽 데이터가 많으면 EXISTS보다 훨씬 무거워져.

데이터가 100만 건이 넘어가면 여기서 실력이 갈려.

연산자 특징 비유
IN 서브쿼리 결과를 메모리에 다 올리고 비교 전단지 명단을 다 들고 다니며 대조
EXISTS 조건에 맞는 거 하나라도 찾으면 즉시 중단 "있나?" 확인하고 발견하면 바로 복귀 (가장 빠름)
ALL 모든 값보다 만족해야 함 (> ALL = 최대값보다 큼) 반에서 제일 큰 애보다 커야 함
ANY 하나만 만족해도 됨 (> ANY = 최소값보다 큼) 반에서 제일 작은 애보다만 크면 됨

4. 인덱스(Index)와 시간 복잡도의 비밀

왜 인덱스, 인덱스 하는 걸까?

  • 인덱스: 책 뒤의 찾아보기야. 이게 없으면 처음부터 다 뒤지는 Full Scan(시간 복잡도 N)을 해야 해.
  • 자동 인덱스: PK(기본키)나 FK(외래키)는 DB가 알아서 인덱스를 깔아줘. 자주 쓰는 길이니까 미리 닦아두는 거지.
  • log N의 마법: 인덱스를 타면 데이터가 100만 배 늘어나도 찾는 속도는 아주 조금만 느려져. 강사님이 말한 N log N은 메인 테이블은 다 훑어도(N), 연결된 서브쿼리는 인덱스로 빠르게 찾는다(log N)는 뜻이야!

 

  • Full Table Scan (O(n)): 인덱스 없이 처음부터 끝까지 다 뒤지는 것. 데이터가 늘어날수록 속도가 정비례해서 느려짐.
  • Index Range Scan (O(log n)): 인덱스(B-Tree)를 타고 필요한 부분만 골라 읽는 것. 데이터가 1,000배 늘어나도 읽는 횟수는 몇 번 안 늘어남.
  • SARGable Query (인덱스를 탈 수 있는 쿼리):
    • X WHERE DATE_FORMAT(reg_date, '%Y') = '2025' (컬럼 가공 시 인덱스 파괴)
    • O WHERE reg_date >= '2025-01-01' AND reg_date < '2026-01-01' (원본 유지)

 

5. 집합 연산 (Set Operations)

  • UNION: 중복 제거하고 합치기.
  • INTERSECT(교집합) & MINUS(차집합): MySQL 구버전은 이걸 직접 지원 안 해.
  • 해결책: 당황하지 말고 우리가 배운 INNER JOIN이나 NOT EXISTS로 똑같이 구현하면 돼. 결국 서브쿼리가 본체라는 소리!

@ 오늘의 최종 결론

쿼리를 잘 짠다는 건 단순히 결과가 나오는 게 아니야. 어디에 인덱스가 걸려 있지?, 이건 EXISTS가 빠를까, JOIN이 빠를까?를 고민하며 컴퓨터의 노가다를 줄여주는 전략가가 되는 거야! 댕 어렵다.. 난 다시 처음부터 공부하러 가볼게 !