SQL 레벨업 - 3장 SQL 조건 분기 (2/2)
10강 그래도 UNION이 필요한 경우
1. UNION을 사용할 수 밖에 없는 경우
여러 개의 테이블에서 검색한 결과를 머지하는 경우가 대표적이다.
-- 다른 테이블의 결과를 머지
SELECT col_1
FROM table_A
WHERE col_2 = 'A'
UNION ALL
SELECT col_3
FROM table_B
WHERE col_4 = 'B';
FROM 구에서 테이블을 결합하면 CASE 식을 사용해 원하는 결과를 구할 수 있다. 하지만 필요없는 결합이 발생해 성능적으로 악영향이 발생한다. 따라서 실행 계획 등을 확인해서 어떤 것이 더 좋은지 명확하게 확인해줘야 한다.
2. UNION을 사용하는 것이 성능적으로 더 좋은 경우
UNION을 사용했을 때 좋은 인덱스 를 사용하지만, 이외의 경우에 테이블 풀 스캔이 발생한다면, UNION을 사용한 방법이 더 성능적으로 좋을 수 있다.
- UNION을 사용한 방법
SELECT key,name
date_1, flg_1,
date_2, flg_2,
date_3, flg_3
FROM ThreeElements
WHERE date_1 = '2013-11-01'
AND flg_1 = 'T'
UNION
SELECT key,name
date_1, flg_1,
date_2, flg_2,
date_3, flg_3
FROM ThreeElements
WHERE date_2 = '2013-11-01'
AND flg_2 = 'T'
UNION
SELECT key,name
date_1, flg_1,
date_2, flg_2,
date_3, flg_3
FROM ThreeElements
WHERE date_3 = '2013-11-01'
AND flg_3 = 'T'
머지되는 3개의 SELECT 구문에서 다른것은 WHERE 뿐이다. 쿼리는 원하는 결과를 만들지만 중요한건 성능과 실행계획이다.
이때 중요한것은 인덱스 이다. 이 쿼리를 최적의 성능으로 수행하려면 다음과 같은 필드 조합에 인덱스가 필요하다.
CREATE INDEX IDX_1 ON ThreeElements (date_1, flg_1);
CREATE INDEX IDX_2 ON ThreeElements (date_2, flg_2);
CREATE INDEX IDX_3 ON ThreeElements (date_3, flg_3);
이렇게 인덱스가 존재한다면 UNION을 사용했을 경우 실행 계획은 TABLEE ACCESS BY INDEX 를 통해 테이블 풀 스캔보다 더 빠른 접근 속도를 기대할 수 있다.
- OR을 이용한 방법
SELECT key,name
date_1, flg_1,
date_2, flg_2,
date_3, flg_3
FROM ThreeElements
WHERE (date_1 = '2013-11-01' AND flg_1 = 'T')
OR (date_2 = '2013-11-01' AND flg_2 = 'T')
OR (date_3 = '2013-11-01' AND flg_3 = 'T')
위 쿼리는 결과 값은 같지만 실행 계획이 다르다. SELECT 구문이 하나로 줄었기 때문에 테이블에 접근하는 회수는 1회로 줄어들었지만 인덱스가 사용되지 않았기 때문에 테이블 풀 스캔을 하게 된다. 이렇게 WHERE 구문에서 OR을 사용하면 해당 필드에 부여된 인덱스를 사용할 수 없다.
결론
이러한 경우에 UNION과 OR의 성능 비교는 결국 3회의 인덱스 스캔 VS 1회의 데이블 풀 스캔 의 구도가 된다. 이는 테이블 크기와 검색 조건에 따른 선택(레코드 히트율)에 따라 답이 달라진다.
11강 절차 지향형과 선언형
SQL 초보자는 절차 지향적인 세계에 살고 있다. 처음 접하는 프로그래밍 언어가 절차 지향형 언어이기 때문이다. 그 세계에서 생각의 기본 단위는 ‘구문(Statement)’다. 하지만 SQL 중급자 이상은 선언적인 세계에서 살고 있다. 여기서의 기본 단위는 ‘식(Expression)’ 이다.
초보자가 UNION을 사용해 조건 분기를 하는 이유는 간단하다. UNION 자체가 구문을 바탕으로 하는 절차 지향적인 체계를 사용하기 때문이다. 실제로 UNION 으로 연결하는 대상은 SELECT 구문이다. 따라서 절차형 프로그래밍 언어에 익숙한 방식이다.
하지만 SQL의 기본적인 체계는 선언형이다. 이 세계의 주인은 ‘구문’ 이 아니라 ‘식’ 이다.
SQL 구문의 각 부분 (SELECT, FROM , WHERE , GROUP BY, HAVING, ORDER BY)에 작성하는것은 모두 식이다. SQL구문 내부에서는 식을 작성하지 구문을 작성하지 않는다.