이 글은 SQL 레벨업(한빛 미디어, 미크)를 참고하여 작성하였습니다.
SQL을 잘 사용하기 위해서는 "구문"에서 "식"으로 사고를 전환해야 한다고 한다.
아래에 작성되어 있는 쿼리는 동일한 결과를 출력한다.
그러나, 두 가지의 쿼리는 성능 상 큰 차이를 보이고 있다. 어떤 쿼리가 좋은 쿼리일까?
-- 쿼리1. UNION을 이용한 조건 분기
SELECT item_name, year, price_tax_ex as price
FROM items
WHERE year <= 2001
UNION ALL
SELECT item_name, year, price_tax_in as price
FROM items
WHERE year > 2001 ;
-- 쿼리2. SELECT 구문에서 CASE 식을 사용한 조건 분기
SELECT item_name
, year
, CASE
WHEN year <= 2001 then price_tax_ex
WHEN year >= 2002 then price_tax_in
END as price
FROM items ;
2개의 쿼리는 아래의 조건을 만족하는 데이터를 출력한다.
(1) 2001년을 포함하여 그 이전은 세금을 매기기 전 가격을 출력한다.
(2) 2002년을 포함하여 그 이후는 세금을 매긴 가격을 출력한다.
이를 위해, 1번 쿼리는 UNION
을 사용하여 조건 분기를 했고 2번 쿼리는 SELECT 구문에서 CASE
식을 사용하여 조건 분기를 수행했다.
결론부터 이야기하면, 2번 쿼리가 성능 상 우위에 있다. 이유는 다음과 같다.
먼저, 1번 UNION
을 사용하여 조건 분기를 한 케이스를 보면 쿼리가 불필요하게 길어져있다. 쿼리가 긴 것 자체는 문제가 크지 않지만, 성능에 영향을 주는 것은 실행 계획을 보면 알 수 있다.
실행 계획을 보게되면, 1번 쿼리는 items 테이블에 Table Access Full 방식으로 2회 접근하고 있다.
반면, 2번 CASE
를 이용한 쿼리는 items 테이블에 1회만 접근하며 가독성도 좋다.
SQL 격언에 이런 말이 있다고 한다.
"조건 분기를 WHERE 구로 하는 사람은 초보다.
잘 하는 사람은 SELECT 구만으로 조건 분기를 한다"
이 말을 뜯어보면, "구문"에서 "식"으로 사고를 전환해야 성능에 우위에 있는 쿼리를 작성하게 된다는 말로 풀이된다.
위 예시에서 확인한 문제를 실무에서 받게되면, 직관적으로 떠오르는 방법은 1번 쿼리에 가깝다. WHERE 절의 조건을 바꿔가며, 여러개의 SELECT 구문을 합쳐서, 복수 조건에 일치하는 하나의 결과 집합을 얻고 싶을 때 사용하게 된다.
그러나, 앞서 살펴보았듯이 UNION
을 이요한 조건 분기는 외부적으로는 하나의 SQL 실행처럼 보이지만, 내부적으로는 여러개의 SELECT 구문을 실행하는 실행 계획을 가지게 되고 이에 따라 테이블 접근 횟수 증가로, I/O 비용이 크게 늘어나게 된다.
따라서, 쿼리를 작성할 때 아래와 같은 생각과 습관을 가지도록 노력하면 좋겠다.