SQL 왕초보 가이드

[SQL 03-1] 서브쿼리 최적화 | 성능을 10배 높이는 실전 가이드 🚀

devnewsletter 2025. 2. 6. 12:03
반응형

SQL 서브쿼리를 빠르고 효율적으로 최적화하는 방법을 배워보세요! 서브쿼리 vs JOIN 비교, 실행 속도 개선, 성능 최적화 전략까지 실전 예제로 설명합니다. SQL 실행 속도를 10배 높이는 비법, 지금 확인하세요! 🚀


SQL 왕초보 가이드 - 3단계: 서브쿼리 최적화 🎯

📢 SQL 성능을 높이는 마법을 배워보자!

"데이터는 잘 불러오는데, 실행 시간이 너무 길어요!" 🤯
"부서별 최고 급여를 받는 직원을 찾고 싶은데, 어떻게 해야 하죠?" 🤔
이런 고민을 해결할 수 있도록, 오늘은 SQL 서브쿼리 최적화 기법을 배워볼 거예요! 🚀


1️⃣ 서브쿼리(Subquery)란?

서브쿼리는 "필요한 데이터를 찾기 위해 쿼리를 한 번 더 실행하는 방식"입니다. 📦🔍

🛠 서브쿼리 작동 방식

1️⃣ 서브쿼리가 먼저 실행되어 특정 데이터를 찾습니다.
2️⃣ 그 결과를 메인 쿼리가 다시 사용해서 최종 데이터를 검색합니다.

🚦 예제

SELECT employee_name, salary  
FROM employees  
WHERE salary = (SELECT MAX(salary) FROM employees);

서브쿼리 실행MAX(salary)를 찾아서 최고 급여를 반환.
메인 쿼리 실행 → 반환된 급여와 일치하는 직원 검색.


2️⃣ 부서별 최고 급여 직원 조회 (서브쿼리 활용)

목표:

  • 부서별 최고 급여(MAX(salary))를 받는 직원(employee_name) 조회! 💰

📌 예제 테이블 스키마

CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    employee_name VARCHAR(50),
    department_id INT,
    salary INT
);

CREATE TABLE departments (
    department_id INT PRIMARY KEY,
    department_name VARCHAR(50)
);

📌 예제 데이터

INSERT INTO employees VALUES 
(1, 'Alice', 1, 7000), (2, 'Bob', 1, 6000), 
(3, 'Charlie', 2, 8000), (4, 'David', 2, 7500);
INSERT INTO departments VALUES (1, 'HR'), (2, 'IT');

📌 기대 결과

department_name employee_name max_salary
HR Alice 7000
IT Charlie 8000

📌 SQL 정답

SELECT d.department_name, e.employee_name, e.salary AS max_salary
FROM employees e
JOIN departments d ON d.department_id = e.department_id
WHERE e.salary = (
    SELECT MAX(salary)
    FROM employees e2
    WHERE e2.department_id = e.department_id
);

🚀 서브쿼리가 작동하는 방식

1️⃣ 서브쿼리 실행! 🏃‍♂️ → department_idMAX(salary)를 찾아줍니다.
2️⃣ 메인 쿼리 실행! 🎯 → 각 직원의 급여와 서브쿼리 결과(MAX(salary))를 비교해서 딱 맞는 사람만 출력!

🤔 근데… GROUP BY는 필요 없을까?

보통 MAX(salary) 같은 집계 함수를 쓰려면 GROUP BY가 따라오는 게 자연스러운데, 이 쿼리는 왜 GROUP BY 없이도 돌아갈까요?

📌 이유는 간단해요!

  • 서브쿼리는 department_id별로 하나의 값을 반환하는 스칼라 값(단일 값)을 주기 때문이에요.
  • 만약 GROUP BY를 추가하면 여러 개의 값이 나올 수도 있어서 = 조건과 충돌할 가능성이 있습니다.

💡 정리하자면,
서브쿼리에서 특정 부서의 최고 급여 1개만 반환하니까 GROUP BY 필요 없음!
GROUP BY를 쓰려면 메인 쿼리에서 서브쿼리 대신 JOIN을 활용하는 방법도 가능!

GROUP BY를 추가하면 왜 문제가 될까?

처음 보면 "GROUP BY가 있으면 좋은 거 아닌가?" 싶을 수 있어요. 하지만 서브쿼리에서 GROUP BY를 잘못 쓰면 메인 쿼리와 충돌할 수 있는 위험이 있어요! 😵

🚀 현재 서브쿼리 다시 보기!

WHERE e.salary = (
    SELECT MAX(salary)
    FROM employees e2
    WHERE e2.department_id = e.department_id
)

✅ 이 서브쿼리는 각 부서(department_id)에서 최고 급여(MAX(salary))를 딱 하나만 반환해요.
✅ 즉, WHERE e.salary = (서브쿼리 결과)단 하나의 값(스칼라 값)과 비교하기 때문에 문제가 없죠!

GROUP BY를 넣어버린다면... (문제 발생! ⚠️)

누군가 서브쿼리를 이렇게 수정했다고 해볼게요:

WHERE e.salary IN (
    SELECT MAX(salary)
    FROM employees e2
    GROUP BY e2.department_id
)

🚨 이렇게 되면 문제가 생깁니다! 🚨

GROUP BY e2.department_id를 추가하면, 서브쿼리는 부서별 여러 개의 값을 반환하게 돼요.
✔ 하지만 WHERE e.salary = (서브쿼리 결과)단 하나의 값과만 비교해야 하는데, 여러 개가 나오면 충돌이 발생해요!

📌 비유하자면?

  • 정상 동작하는 기존 서브쿼리:
    👉 "이 부서에서 제일 높은 급여가 얼마야?" → "7000!" (정확히 1개 값 반환!)
  • GROUP BY를 추가한 서브쿼리:
    👉 "각 부서별 제일 높은 급여를 모두 가져와!" → "7000, 8000!" (여러 개 나옴!)

🔹 이렇게 되면 WHERE e.salary = (여러 개의 값)이 되면서, SQL이 어떤 값과 비교해야 할지 몰라서 오류가 발생할 가능성이 커집니다! 🚨


3️⃣ 서브쿼리의 단점? 속도가 느릴 수도 있어요! 🐢

이 방식, 간단하고 깔끔하긴 하지만… 큰 데이터셋에서 느릴 수도 있습니다! 🐌
왜냐하면? 각 직원마다 서브쿼리가 한 번씩 실행되기 때문이에요.

🔥 예를 들어 볼까요?
✔ 직원이 10명이면? 서브쿼리 10번 실행!
✔ 직원이 100만 명이면? 🏃‍♂️ 100만 번 실행! (헉😱)

📌 더 빠른 방법은? JOIN 활용! 🚀


4️⃣ CTE(WITH)를 활용한 성능 개선! 🚀

📌 CTE(Common Table Expression)란?

WITH 키워드는 임시 테이블을 만들어 쿼리를 더 읽기 쉽게 정리하는 기능이에요.
일반적으로 서브쿼리를 대체하는 용도로 사용되며, 쿼리 실행이 끝나면 자동으로 사라지는 임시 테이블 역할을 합니다.

 

CTE를 쓰면 좋은 점!
가독성 UP → 복잡한 서브쿼리를 깔끔하게 정리!
재사용 가능 → 한 번 정의한 CTE를 여러 번 활용할 수 있음
성능 최적화 → 일부 데이터베이스에서는 실행 계획을 더 효율적으로 짤 수 있음

 

🔥 CTE를 활용한 최적화된 SQL 예제!

WITH max_salaries AS (
    SELECT department_id, MAX(salary) AS max_salary
    FROM employees
    GROUP BY department_id
)
SELECT d.department_name, e.employee_name, e.salary AS max_salary
FROM employees e
JOIN max_salaries ms ON e.department_id = ms.department_id AND e.salary = ms.max_salary
JOIN departments d ON d.department_id = e.department_id;

 

🔎 이렇게 하면 뭐가 좋아질까요?
1️⃣ 서브쿼리 대신 CTE 활용 → 쿼리 구조가 깔끔해짐!

  • 기존 방식은 MAX(salary)를 계산할 때마다 서브쿼리를 실행해야 했어요.
  • 하지만 CTE(max_salaries)를 사용하면 부서별 최대 급여를 먼저 구한 후 이를 활용해 메인 쿼리를 실행할 수 있어요.

2️⃣ 불필요한 연산 최소화 → 성능 개선!

  • max_salaries CTE에서 부서별 최대 급여한 번만 계산하니까,
    같은 연산을 반복하는 비효율적인 구조를 줄일 수 있어요.

3️⃣ 조인(Join) 최적화 → 실행 속도 향상!

  • employees 테이블과 max_salariesdepartment_idsalary로 조인해, 부서별 최고 연봉자만 추출!
  • 추가로 departments 테이블을 조인해서 부서 이름까지 함께 조회할 수 있어요.

💡 결론:
CTE(WITH 키워드)를 활용하면 SQL 쿼리가 더 깔끔하고, 성능도 좋아질 수 있다! 🚀
특히 반복 연산이 많은 서브쿼리를 최적화할 때 강력한 효과를 발휘하니, SQL 성능 튜닝할 때 꼭 활용해 보세요! 😎


🎯 서브쿼리 최적화 마무리!

오늘 배운 개념들 정리해볼까요? 🚀

서브쿼리

  • SQL 안에서 또 다른 SQL을 실행하는 방식
  • 결과를 가져와서 다시 필터링할 때 유용하지만 성능 저하 가능

WITH를 활용한 최적화

  • 서브쿼리보다 효율적인 방식으로 실행 속도 개선 가능!

📌 다음 가이드에서는 윈도우 함수를 활용한 성능 최적화 방법을 배워볼 거예요! 🚀

반응형