8강. UNION을 사용한 쓸데없이 긴 표현
•
UNION을 사용한 조건 분기는 일반적으로 조건이 다른 WHERE 구문을 합쳐서, 복수의 조건에 일치하는 결과 집합을 얻고자 사용한다.
◦
하지만, UNION을 사용한 조건 분기는 외부적으로는 하나의 SQL 구문을 실행하는 것처럼 보이지만, 내부적으로는 여러 개의 SELECT 구문을 실행함으로, I/O 비용이 크게 증가한다.
◦
일부 예외적인 경우를 제외하면, 조건 분기를 할 때 UNION을 사용해서는 안된다.
•
UNION으로 조건 분기를 하는 경우의 문제
1.
SQL 구문이 길어진다.
2.
테이블에 자주 접근하게 되므로 I/O 비용이 크다. → 테이블의 크기가 커질수록 비용이 선형적으로 커진다.
•
CASE식을 사용한 조건 분기로 성능과 가독성이 좋아졌다.
•
SQL 구문의 성능을 실행 계획 레벨에서 판단해야 한다.
→ SQL 구문에는 어떻게 데이터를 검색할지를 나타내는 “접근 경로”가 드러나있지 않기 때문
•
UNION과 CASE의 차이
◦
UNION을 사용한 조건 분기는 SELECT ‘구문’을 기본 단위로 분기 → 절차 지향형의 방식
◦
CASE 식을 사용한 조건 분기는 ‘식’을 바탕으로 하는 분기
9강. 집계와 조건 분기
1.
집계 대상으로 조건 분기
•
UNION을 사용한 절차 지향적인 방식의 집계
→ SQL 구문이 복잡하고 길다.
→ 테이블에 2번 접근한다.
•
CASE 식을 사용한 방식
→ SQL 구문이 간단하다.
→ UNION 방식에 비해 I/O 비용이 감소한다.
표측/표두 레이아웃 이동 문제
2.
집약 결과로 조건 분기
•
UNION을 사용한 방식
◦
WHERE구가 아니라, HAVING 구에 조건 지정 → 조건 분기가 레코드값이 아닌, 집합의 레코드 수에 적용된다.
◦
하지만, 여전히 구문 레벨의 분기이다. → WHERE 구를 사용할 때와 비용이 크게 다르지 않다.
•
CASE 식을 사용한 방식
◦
UNION 방식에 비해 테이블 접근 비용과 GROUP BY를 하기 위한 HASH 연산이 모두 1/3로 줄었다.
10강. 그래도 UNION이 필요한 경우
1.
UNION을 사용할 수밖에 없는 경우
•
여러개의 테이블에 대한 SQL 구문의 결과를 합치는 경우
2.
UNION을 사용하는 것이 성능적으로 더 좋은 경우
•
UNION을 사용했을 때 성능 좋은 (압축을 잘하는) 인덱스를 사용하는 경우, table full scan이 발생하는 경우보다 성능적으로 좋을 수 있다.
◦
원본 테이블
◦
만들고자 하는 테이블
•
UNION을 사용한 방법
→ 위의 쿼리를 최적의 성능으로 수행하려면 다음과 같은 필드 조합에 대한 인덱스가 필요하다.
→ 위의 실행 계획에서는 모든 SELECT 구문이 각각의 인덱스를 사용하고 있다.
→ 인덱스 스캔의 경우, 테이블의 레코드 수가 많고 WHERE 구에서 레코드 수를 많이 압축할수록(조건에서 많이 걸러질수록) 성능이 좋아진다.
→ 주. 위의 예시처럼 레코드 수가 적은 경우는 table full scan과 index scan의 성능 차이가 크지 않아서 옵티마이저가 table full scan을 선택할 수도 있다.
•
OR를 사용한 방법
→ 위 쿼리의 결과는 UNION을 사용한 경우와 같다.
→ 하지만 실행 계획을 보면, 테이블에 대한 접근이 1번으로 줄어든 반면 인덱스 스캔 대신 table full scan이 사용되었다.
→ 3번의 인덱스 스캔과 1번의 테이블 풀 스캔 중에서 어떤 것이 더 성능이 좋은지는 테이블의 크기와 검색 조건에 따른 레코드 히트율에 따라 다르다.
•
IN을 사용한 방법
→ 다중 필드 혹은 행식(row expression)이라는 기능을 사용한 방법
→ IN의 매개변수로는 스칼라뿐만 아니라 값의 리스트(배열)를 입력할 수도 있다.
→ OR을 사용한 방법과 실행 계획이 같다.
다중 필드
•
CASE 식을 사용한 방법
→ OR와 IN을 사용한 경우와 실행 계획이 같다.
11강. 절차 지향형과 선언형
•
결론 : 일반적으로 조건 분기는 UNION이 아닌 CASE 식을 사용하는 것이 가독성과 성능적으로 좋다.
1.
구문 기반과 식 기반
•
SQL의 기본적인 체계는 선언형으로, 구문이 아니라 식이 중심이다.
•
SELECT, FROM, WHERE와 같은 SQL 구문의 각 부분에 작성하는 것은 모두 식이다.
•
필드 명, 상수만 기술하는 경우에도 마찬가지
→ 필드 명만 있다면 ‘연산자가 없는 식’ , 상수만 있다면 ‘변수와 연산자가 없는 식’이다.
정리
•
SQL의 성능은 저장소의 I/O 비용을 얼마나 감소시킬수 있는지가 관건
•
UNION으로 조건 분기를 표현할 때는 가독성에 대해 생각해볼것.
•
IN 또는 CASE 식으로 조건 분기를 표현할 수 있다면, 테이블에 대한 접근 비용을 감소시킬 수 있다.
•
구문보다는 식
연습문제
•
UNION과 IN, OR의 결과가 같고, CASE 식을 사용한 경우 결과가 다르다.
→ CASE 식의 WHEN 구문은 단락 평가를 수행하기 때문에, 특정 조건이 TRUE라면 거기서 평가가 중단되며, 나머지 조건 분기에 대한 평가는 생략한다.
→ 반면, UNION과 IN, OR는 모든 조건 분기를 평가하므로 결과가 같다.
→ UNION과 결과적으로 동치인 방식은 IN 구문