본문 바로가기
SQL

[SQL] 어쩔 수 없는 UNION

by UnoCode 2020. 9. 1.

이전 포스팅에서 UNION을 사용하면 않좋다 라고 말씀드렸습니다.

 

반대로 UNION을 써야 성능이 좋아지는 경우도 있습니다. 이번 포스팅은 이와 관련해서 작성했습니다.

 

SELECT col_1
FROM Table_A
WHERE col_2= "A"
UNION ALL
SELECT col_3
FROM Table_B
WHERE col_4= "B"

여러 개의 테이블에서 검색한 결과를 머지하는 경우 UNION이 효율이 좋다.

 

 

이 예외를 설명하기 앞서 테이블을 먼저 정의 하겠습니다.

key name date_1 flg_1 date_2 flg_2 date_3 flg_3
1 a 2013-11-01 T        
2 b     2013-11-01 T    
3 c     2013-11-01 F    
4 d     2013-12-30 T    
5 e         2013-11-01 T
6 f         2013-12-01 F

조금 억지 스러운 테이블이지만 예제를 위해 하는거니 이해하시기 바랍니다.

 

UNION

SELECT name,
	date_1,flg_1,
    date_2,flg_2,
    date_3,flg_3
FROM ThreeElements
WHERE date_1 = '2013-11-01'
		AND flg_1=true
UNION
SELECT name,
	date_1,flg_1,
    date_2,flg_2,
    date_3,flg_3
FROM ThreeElements
WHERE date_2 = '2013-11-01'
		AND flg_2=true
UNION
SELECT name,
	date_1,flg_1,
    date_2,flg_2,
    date_3,flg_3
FROM ThreeElements
WHERE date_3 = '2013-11-01'
		AND flg_3=true

INDEX 지정하기

 

CREATE INDEX IDX_1 ON ThreeElements (date_1,flg_1(50));
CREATE INDEX IDX_2 ON ThreeElements (date_2,flg_2(50));
CREATE INDEX IDX_3 ON ThreeElements (date_3,flg_3(50));

이러한 인덱스가 WHERE 구에서 (date_n,flg_n)라는 필드 조합을 사용할 때 빠르게 만들어 줍니다.

 

인덱스 확인

 SHOW INDEXES IN ThreeElements

실행 계획

    - system

    테이블에 오직 하나의 row만 있어 테이블에매칭되는 row가 무조건 1건인 경우, Const 타입의 특별한 케이스

    - const

    매칭되는 row가 오직 1건인 경우

    가장 빠른 경우이며, 옵티마이저가 row을 찾기 위해 Unique/Primary Key 사용

    각 컬럼 값은 나머지 연산에서 상수로 간주, 처음한번만 읽어 들이면 되므로 매우 빠름

    - eq_ref

    이전 테이블에서 공급받은 값으로 조인 처리시 단 하나의row만이 조인되는 테이블에 존재하는 경우

    조인 타입 중 거의 최상의 경우이며, 조인되는테이블의 Unique/Primary Key를 사용 (1:1 관계)

    - ref

    이전 테이블에서 공급받은 값으로 조인 처리시 하나 이상의row가 조인되는 테이블에 존재하는 경우

    조인을 처리할 때 Unique/Primary Key 100% 사용하지 못하거나 Non-Unique 인덱스를 사용 (1:n 관계)

    단일 쿼리인 경우 WHERE 조건 처리를 위해 Non-Unique 인덱스를 사용

    인덱스를 사용하지만 제공되는 값에 매칭되는 row가많지 않은 경우 나쁘지 않은 타입임

 

인텍스 조회가 3회 일어난걸 볼 수 있습니다.

 

OR을 사용한 해결

 

SELECT name,
	date_1,flg_1,
    date_2,flg_2,
    date_3,flg_3
FROM ThreeElements
WHERE (date_1 = '2013-11-01' AND flg_1 = true)
	OR (date_2 = '2013-11-01' AND flg_2 = true)
    OR (date_3 = '2013-11-01' AND flg_3 = true)

 

중요한건 실행 계획입니다. (이점을 항상 상기해 두세요)

 

 

ALL : 풀스캔을 하고 있습니다.

 

여기서 의문을 가지는 분이 계실거라 봅니다.

 

인텍스 조회 3회 VS 풀스캔 1회

 

이는 테이블 크기와 검색 조건에 따른 석택 비율에 따라 답이 달라집니다.

하지만 테이블이 크고, WHERE 조건으로 선택되는 레코드의 수가 충분히 작다면 UNION이 더욱 빠릅니다.

 

IN을 사용한 해결

SELECT name,
	date_1,flg_1,
    date_2,flg_2,
    date_3,flg_3
FROM ThreeElements
WHERE ('2013-11-01',true)
		IN((date_1,flg_1),
		  (date_2,flg_2),
          	(date_3,flg_3));

이는 다중 필드(multiple fields) 라는 기능입니ㅏㄷ.

IN의 매개변수로는 단순한 스칼라뿐만 아니라, 이렇게 (a,b,c)와 같은 배열을 입력 할 수 도 있습니다.

 

CASE를 이용한 해결

 

SELECT name,
	date_1,flg_1,
    date_2,flg_2,
    date_3,flg_3
FROM ThreeElements
WHERE CASE WHEN date_1 = '2013-11-01' THEN flg_1
		   WHEN date_2 = '2013-11-01' THEN flg_2
		   WHEN date_3 = '2013-11-01' THEN flg_3
           ELSE NULL END = true

 

'SQL' 카테고리의 다른 글

[SQL] 자르기  (0) 2020.09.03
[SQL] 집약  (0) 2020.09.02
[SQL] 조건 분기 CASE,UNION 차이  (0) 2020.08.31
[SQL] SQL 조건 분기, 집합 연산, 윈도우 함수, 갱신  (0) 2020.08.30
[SQL] DBMS 아키텍처 Part 2  (0) 2020.08.29

댓글