2장에서는 조건 분기를 할 때 CASE 식을 설명했죠. 사실 이외에도 사용할 수 있는 구문이 있습니다. 바로 UNION입니다. 하지만 이는 좋은 일이 아닙니다. UNION은 조건 분기를 위해 만들어진 것이 아니기 때문입니다. 많은 사람들이 어떻게 작동할지 쉽게 예측할 수 있다는 이유로 사용하는데, 이번 장에서는 UNION을 사용하지 않고 CASE 방식이라는 SQL의 원래 조건 분기 기능을 몸에 밸 수 있게 하는 것이 목표입니다.
8강 UNION을 사용한 쓸데없이 긴 표현
UNION 방식은 성능적인 측면에서 단점을 가지고 있습니다. 외부적으로는 하나의 SQL 구문을 실행하는 것처럼 보이지만, 내부적으로는 여러 개의 SELECT 구문을 실행하는 실행 계획으로 해석되기 때문이죠. 테이블에 접근하는 횟수가 많아져 I/O 비용이 크게 늘어납니다.
1. UNION을 사용한 조건 분기
간단하게 레코드 집합을 합칠 수 있다는 점에서 UNION은 편리한 도구입니다. 하지만 정확한 판단 없이 SELECT 구문 전체를 여러 번 사용해서 코드를 길게 만드는 것은 쓸데없는 테이블 접근을 발생시켜 SQL 성능을 나쁘게 만들고, 물리 자원(저장소의 I/O 비용)도 쓸데없이 소비하게 만듭니다.
2. WHERE 구에서 조건 분기를 하는 사람은 초보자
SQL 격언 중 "조건 분기를 WHERE 구로 하는 사람들은 초보자다. 잘하는 사람은 SELECT 구만으로 조건 분기를 한다" 라는 말이 있습니다. UNION을 사용했을 때보다 SELECT 구를 사용했을 때 Items 테이블에 대한 접근이 1회로 줄어듭니다. 구문의 성능이 좋은지 나쁜지는 반드시 실행 계획 레벨에서 판단해야 합니다.
사실 이는 좋은 것이 아닙니다. "사용자가 데이터에 접근 경로라는 물리 레벨의 문제를 의식하지 않도록 하고 싶다"라는 것이 RDB와 SQL이 가진 컨셉이기 때문이죠. 하지만 아직 이 뜻을 이루기에는 역부족입니다. 재밌는 것이 하나 있는데, UNION을 사용한 분기는 SELECT '구문'을 기본 단위로 분기합니다. 구문을 기본 단위로 사용하고 있다는 점에서, 아직 절차 지향형의 발상을 벗어나지 못한 방법이라고 말할 수 있습니다. 반면 CASE 식을 사용한 분기는 문자 그대로 '식'을 바탕으로 하는 사고입니다. '구문'에서 '식'으로 사고를 변경하는 것이 SQL을 마스터하는 열쇠 중 하나입니다.
9강 집계와 조건분기
(1) 집약 대상으로 조건 분기
지역별로 남녀 인구를 기록하는 Population 테이블을 생각해보죠.
1) UNION을 사용한 방법
절차 지향적인 사고방식을 가진다면, 남성의 인구를 지역별로 구하고, 여성의 인구를 지역별로 머지하는 방법을 생각할 것입니다. 하지만 이런 쿼리의 가장 큰 문제는 WHERE 구에서 성별 필드로 분기를 하고, 결과를 UNION으로 머지한다는 절차 지향적인 구성에 있습니다.
실행 계획을 보면 Population 테이블에 풀 스캔이 2회 수행되는 것을 확인할 수 있습니다.
2) 집계의 조건 분기도 CASE 식을 사용
CASE 식을 집약 함수 내부에 포함시켜서 '남성 인구', '여성 인구' 필터를 만듭니다. 실행 계획을 보면, 중요한 것은 외관이 1) 보다 간단해진다는 것 뿐만 아니라 성능도 향상된다는 것입니다. 실행 계획도 간단한데, 풀 스캔이 1회로 감소하죠. I/O 비용이 절반으로 감소한다는 의미가 되죠.
(2) 집약 결과로 조건 분기
집약 결과에 조건 분기를 실행하는 경우가 있습니다. 예로 직원과 직원이 소속된 팀을 관리하는 테이블 Employees(직원)이 있습니다.
[1] 소속된 팀이 1개라면 해당 직원은 팀의 이름을 그대로 출력
[2] 소속된 팀이 2개라면 해당 직원은 '2개를 겸무'라는 문자열 출력
[3] 소속된 팀이 3개라면 해당 직원은 '3개 이상을 겸무'라는 문자열 출력
1) UNION을 사용한 조건 분기
SELECT emp_name,
MAX(team) AS team
FROM Employees
GROUP BY emp_name
HAVING COUNT(*) = 1
UNION
SELECT emp_name,
'2개를 겸무' AS team
FROM Employees
GROUP BY emp_name
HAVING COUNT(*) = 2
UNION
SELECT emp_name,
'3개 이상을 겸무' AS team
FROM Employees
GROUP BY emp_name
HAVING COUNT(*) >= 3;
조건 분기가 레코드값이 아닌, 집합의 레코드 수에 적용된다는 것이죠. 조건 분기가 WHERE 구가 아니라 HAVING 구에 지정되었습니다. 하지만 UNION으로 머지하고 있
'독서 > SQL 레벨업' 카테고리의 다른 글
5장 반복문 (0) | 2024.11.24 |
---|---|
4장 집약과 자르기 (0) | 2024.11.23 |
2장 SQL 기초 (0) | 2024.11.21 |
1장 DBMS 아키텍처 (0) | 2024.11.20 |