2025. 8. 1. 23:33ㆍTools & Skills/SQL
최근 SQL을 튜닝을 공부하면 할수록 느끼는 건데,
단순히 문법을 외우는 걸 넘어서 생각의 체계 자체를 바꾸는게 필요한 것 같다.
절차 지향형 vs 선언형 사고

SQL을 작성하면서 statement 중심의 절차 지향형 사고에 머무를 때가 많다.
쿼리를 작성하다 보면, “어떻게 이걸 구현하지?”에 초점이 맞춰진다.
근데 중급자 이상으로 가려면 반드시 넘어야 할 벽이 있다고 한다.
바로 expression 중심의 선언형 사고이다.
SQL은 프로그래밍 언어가 아니라, 질의(Query) 언어다.
무엇을 원하는지를 말하면, DB가 어떻게든 해준다.
UNION 쓰지 말자 (웬만하면)
- 조건 분기 때문에 UNION을 여러 번 쓰고 있다면?
- CASE 식으로 훨씬 자연스럽고 깔끔하게 표현할 수 있다.
- UNION은 성능적 안티 패턴이 될 가능성이 큼 → Table Scan도 증가할 수 있음
SQL 집약(Aggregation)의 기본기
SQL은 결국 집합 지향 언어다.
GROUP BY, 집약 함수, CASE WHEN 조합만 제대로 써도 대부분의 문제를 해결할 수 있다.
CREATE TABLE NonAggTb1 (
id VARCHAR(32) NOT NULL, -- 고유 식별자
data_type CHAR(1) NOT NULL, -- A, B, C 등의 타입 구분
data_1 INTEGER,
data_2 INTEGER,
data_3 INTEGER,
data_4 INTEGER,
data_5 INTEGER,
data_6 INTEGER
);
이런 비집약 테이블이 있을 때, 각 data_type에 따라 다른 필드를 집계하고 싶다면?
잘못된 방식 예시
SELECT
id,
CASE WHEN data_type = 'A' THEN data_1 ELSE NULL END AS data_1,
...
FROM NonAggTb1
GROUP BY id;
집계 함수 없이 GROUP BY를 쓰면 오류가 난다.
MAX + CASE WHEN 활용
SELECT id,
MAX(CASE WHEN data_type = 'A' THEN data_1 ELSE NULL END) AS data_1,
...
FROM NonAggTb1
GROUP BY id;
→ 이게 바로 Pivot 기법
CASE WHEN을 통해 조건 분기하고, MAX로 하나의 값으로 수렴시켜주는 구조이다.
같은 id 내에 여러 행이 있어도 MAX()는 그 중 하나를 대표값으로 만들어줌
실행계획과 메모리 이야기
GROUP BY는 내부적으로 어떻게 작동할까?
- 최근 대부분의 DBMS는 Hash 알고리즘 기반 집계를 우선 사용
- 경우에 따라 Sort 기반 집계도 사용됨
정렬(Sort) vs 해시(Hash)
| 구분 | 설명 |
| 정렬 (Sort) | 모든 데이터를 정렬해 같은 그룹끼리 모은 뒤 집계 |
| 해시 (Hash) | 해시 키를 기준으로 같은 그룹을 빠르게 모아서 집계 |
→ GROUP BY 대상의 유일성이 높을수록 해시 방식이 더 유리
하지만
❗ 워킹 메모리가 부족하면?
- 정렬이든 해시든 메모리 많이 씀
- 워킹 메모리가 부족하면 → 스왑 발생
- 디스크를 메모리처럼 사용
- 성능 급격히 저하
SQL 성능 = 결국 I/O 줄이기 싸움
→ 집합 사고 + 워킹 메모리 감각이 중요
합쳐서 하나, 부분의 합이 전체를 커버하는가?
이런 사고도 SQL에서는 자주 등장한다.
SELECT
product_id
FROM PriceByAge
GROUP BY product_id
HAVING SUM(high_age - low_age + 1) = 101;
→ 이 상품이 0~100세까지 모든 연령을 커버하고 있는지를 합산으로 판단
이건 단순한 수치 계산을 넘어서, “집합의 완전성”을 판별하는 방법이다.
마무리하며
- SQL은 선언형 언어
- 생각 자체를 바꿔야 성장 가능
- CASE WHEN, GROUP BY, MAX, HAVING 등의 조합을 자유자재로 다루는 게 핵심
- 성능은 결국 불필요한 I/O 줄이기의 싸움
- 메모리 부족으로 인한 스왑도 성능 병목의 핵심 원인
'Tools & Skills > SQL' 카테고리의 다른 글
| 트러블슈팅: MySQL 대용량 CSV 파일 LOAD DATA로 넣기 (2) | 2025.08.11 |
|---|---|
| 반복문 의존증 (5) | 2025.08.03 |
| 신규 가입자의 2주차 재방문율 감소 문제 (4) | 2025.07.22 |
| [SQL] 프로그래머스 Lv.4 보호소에서 중성화한 동물 (0) | 2025.04.05 |
| [SQL] LeetCode #511 - Game Play Analysis (0) | 2025.03.19 |