📘 MySQL 데이터베이스 학습 정리 — 집계 함수, GROUP BY, 서브쿼리, 조인, 실무 활용까지
현재 제가 공부하고 있는 교재는 **「MySQL 데이터베이스 개론과 실습 2판」**입니다.
이 책은 단순히 SQL 문법만 나열하는 것이 아니라, 실습 예제 중심으로 진행되기 때문에 직접 쿼리를 작성하고 실행해보면서 학습할 수 있다는 장점이 있습니다.
특히 실무에서 필수적으로 쓰이는 집계 함수, GROUP BY, 서브쿼리, 조인 같은 주제를 집중적으로 다루고 있어, 회사 전산 관리나 데이터 분석, 코딩 테스트 문제 풀이에도 큰 도움이 됩니다.

1️⃣ 집계 함수와 GROUP BY
집계 함수는 데이터를 요약하는 가장 기본적인 도구입니다.
- COUNT: 행 개수
- SUM: 합계
- AVG: 평균
- MAX / MIN: 최대, 최소
예제: 고객별 총 주문 건수와 매출액
SELECT custid, COUNT(*) cnt, SUM(saleprice) total
FROM orders
GROUP BY custid
HAVING SUM(saleprice) >= 10000
ORDER BY total DESC;

실무에서 중요한 포인트:
- GROUP BY에 없는 비집계 컬럼을 SELECT에 올리는 것은 비표준 → 결과가 DB 엔진마다 달라질 수 있으므로 피해야 함.
- 대량 데이터에서 집계를 자주 한다면 집계 전용 인덱스나 OLAP 시스템 도입도 고려.
2️⃣ 서브쿼리 (Subquery)
단일행 서브쿼리
SELECT * FROM book WHERE price = (SELECT MAX(price) FROM book);
하나의 값만 반환하는 경우.

다중행 서브쿼리
SELECT * FROM customer
WHERE custid IN (SELECT DISTINCT custid FROM orders);
집합에 속하는지 확인할 때 유용.

상관 서브쿼리
SELECT *
FROM book b1
WHERE b1.price > (
SELECT AVG(b2.price)
FROM book b2
WHERE b2.publisher = b1.publisher
);
메인쿼리의 컬럼을 참조. 행마다 실행되므로 직관적이지만 성능은 불리.

3️⃣ 조인 (JOIN)
조인은 여러 테이블을 가로로 합치는 방법입니다.
상관 서브쿼리로도 해결 가능한 문제를 JOIN + GROUP BY로 바꾸면 보통 더 효율적입니다.
SELECT b1.*
FROM book b1
JOIN (
SELECT publisher, AVG(price) avg_price
FROM book
GROUP BY publisher
) t ON b1.publisher = t.publisher
WHERE b1.price > t.avg_price;

4️⃣ 서브쿼리 vs 조인 — 차이와 선택 기준
구분 서브쿼리 조인
| 직관성 | 읽기 쉬움 (특히 상관 서브쿼리) | SQL 구조가 복잡해질 수 있음 |
| 성능 | 상관 서브쿼리는 행마다 실행 → 느릴 수 있음 | 옵티마이저가 효율적으로 실행 → 보통 빠름 |
| 사용 목적 | 값 비교, 존재 여부 확인 (IN, EXISTS) | 두 테이블을 동시에 출력하거나 집계 비교 |
| 리스크 | NOT IN + NULL → 예기치 않은 결과 | NULL 처리 문제 적음 |
| 실무 권장 | 단순 비교/조건 확인 시 | 대량 데이터 분석, 집계, 컬럼 다중 출력 시 |
👉 핵심:
- “값 비교” → 서브쿼리
- “결과를 합쳐서 보여줘야” → 조인
- 성능이 중요하면 항상 조인 우선 고려
5️⃣ EXISTS vs IN vs JOIN
- IN (subquery) : 서브쿼리 결과 집합에 포함 여부 검사
- EXISTS (subquery) : 조건 만족 행이 존재하는지만 확인 → 보통 상관 서브쿼리
- JOIN : 실제 데이터를 합쳐서 출력
실무에서는 단순 존재 여부 확인은 EXISTS가 효율적인 경우가 많습니다.
NOT IN은 NULL이 있으면 결과가 꼬이므로 NOT EXISTS로 바꾸는 습관을 들이는 것이 안전합니다.
6️⃣ UPDATE / DELETE 에서의 서브쿼리와 조인
-- 서브쿼리 방식
UPDATE orders o
SET o.bname = (SELECT b.bookname FROM book b WHERE b.bookid = o.bookid);
-- 조인 방식 (권장)
UPDATE orders o
JOIN book b ON o.bookid = b.bookid
SET o.bname = b.bookname;
DELETE도 마찬가지입니다. 실무에서는 JOIN 기반 UPDATE/DELETE가 더 명확하고 성능도 안정적입니다.

7️⃣ UNION vs UNION ALL
SELECT name FROM customer WHERE address LIKE '대한%'
UNION ALL
SELECT name FROM customer WHERE custid IN (SELECT custid FROM orders);
- UNION : 중복 제거 → 비용 발생
- UNION ALL : 단순 합치기, 빠름

실무에서는 불필요한 중복 제거를 하지 않는 UNION ALL이 선호됩니다.
8️⃣ 실무에서 자주 부딪히는 문제들
- NULL 처리 : NOT IN은 NULL 때문에 항상 false가 될 수 있음 → 반드시 NOT EXISTS 고려
- 상관 서브쿼리 성능 : 소량 데이터 → 괜찮음, 대량 데이터 → 반드시 JOIN으로 리팩터링 검토
- 인덱스 활용 : JOIN, WHERE, GROUP BY 컬럼은 인덱스가 없으면 쿼리가 급격히 느려짐
- OLTP vs OLAP : 실시간 트랜잭션 시스템에서는 복잡한 서브쿼리/집계보다 단순 쿼리 + 사전 집계 테이블을 두는 경우가 많음
✍️ 오늘의 정리
- 집계 함수 + GROUP BY : 데이터를 요약하는 핵심
- HAVING : 그룹화된 결과에 조건을 주는 유일한 방법
- 서브쿼리 : 단일행, 다중행, 상관 서브쿼리
- 조인 : 실무에서 가장 많이 쓰이고, 성능상 유리
- 서브쿼리 vs 조인 : 직관성 vs 성능 → 상황에 맞게 선택
- 실무 팁 : NOT IN 대신 NOT EXISTS, UPDATE/DELETE 조인 사용, UNION ALL 권장
👉 오늘은 단순 문법을 넘어서, 왜 JOIN이 권장되는지, NULL과 NOT IN의 위험성, 집계 시 성능 이슈까지 배웠습니다. 이런 내용들은 실제 회사 전산실이나 백엔드 개발자가 쿼리를 작성할 때 반드시 부딪히는 문제이기도 해서 매우 중요한 학습이었습니다.