-
[SQL] Union과 Union all 차이DB 2016. 10. 12. 15:27
먼저 각 데이터베이스마다 다르겠지만 여기서는 postgresql 기준으로 설명하겠습니다.
UNION집합 연산은 다음처럼 두 가지가 있습니다.
- UNION ALL
- UNION DISTINCT
일반적으로 사용하는 UNION은 UNION DISTINCT의 줄임입니다.
UNION ALL과 UNION DISTINCT의 차이
UNION ALL은 중복을 제거하지 않고 그대로 합집합 연산을 해 결과를 보여주는 반면, UNION DISTINCT는 중복을 제거하여 결과를 보여줍니다.
여기서 중복을 처리하는 기준이 무엇인지 다음과 같은 질문이 발생합니다.
- primary key
- 전체 테이블의 모든 필드
- select 절에서 나오는 튜플에 대한 필드
여기서 UNION은 이미 SELECT된 결과를 가지고 UNION하기 때문에 SELECT되기 전의 테이블이나 레코드에 대한 정보는 알 수 없습니다. 그래서, 중복 여부의 판단은 SELECT된 튜플들에 속해있는 모든 컬럼의 값들 자체가 중복 체크의 기준이 되는 것입니다.
UNION 처리과정
- 최종 UNION [ALL | DISTINCT] 결과에 적합한 임시 테이블(Temporary table)을 메모리 테이블로 생성
- UNION 또는 UNION DISTINCT 의 경우, Temporary 테이블의 모든 컬럼으로 Unique Hash 인덱스 생성
- 서브쿼리1 실행 후 결과를 Temporary 테이블에 복사
- 서브쿼리2 실행 후 결과를 Temporary 테이블에 복사
- 만약 3,4번 과정에서 Temporary 테이블이 특정 사이즈 이상으로 커지면 Temporary 테이블을 Disk Temporary 테이블로 변경 (이때 Unique Hash 인덱스는 Unique B-Tree 인덱스로 변경됨)
- Temporary 테이블을 읽어서 Client에 결과 전송
- Temporary 테이블 삭제
UNION 두 가지의 차이는 2번 과정 딱 하나입니다. 중복 제거를 위해서 Temporary 테이블에 인덱스를 생성하는지 안하는지 입니다. 별로 중요하지 않은 것 같지만, 이 인덱스로 인해서 3,4번 과정의 작업이 작지 않은 성능 차이가 만들어 내게 됩니다. 실제 UNION을 실행하는 데이터의 건수에 따라서 다르겠지만, 1.5 ~ 4배 가량의 성능 차이로 UNION ALL이 빠르게 처리된다. 만약 처리중 데이터의 크기가 작아서 5번 과정을 거치지 않는다면 메모리 Temporary 테이블에 Hash 인덱스를 사용하기 때문에 속도 차이가 아주 미세할 것입니다.
하지만 데이터량이 커져서 5번 과정을 거치게 되면 Disk Temporary 테이블에 B-Tree 인덱스를 사용하기 때문에 큰 성능 차이를 보이게 됩니다. 이 성능 차이는 UNION 하는 두 집합에 중복되는 레코드가 있든 없든 관계 없이 발생합니다. 위에서 잠깐 알아보았던, "중복의 기준"을 생각하면, UNION 하는 컬럼들의 수가 많아지고 레코드의 사이즈가 커질수록 두 작업 모두에게 불리하겠지만, UNION ALL보다는 UNION에 더 악영향이 클 것이다.
결론
UNION 이든지 UNION ALL이든지 사실 그리 좋은 SQL 작성은 아님
UNION이 필요하다는 것은 사실 두 엔터티(테이블)가 하나의 엔터티(테이블)로 통합이 되었어야 할 엔터티들이었는데, 알 수 없는 이유로 분리 운영되었다는 경우임. 즉 모델링 차원에서 엔터티를 적절히 통합하여 UNION의 요건을 모두 제거하자
두 집합에 절대 중복된 튜플(레코드)가 발생할 수 없다는 보장이 있다면 UNION ALL을 꼭 사용하자. 두 집합에서 모두 각각의 PK를 조회하는데, 그 두 집합의 PK가 절대 중복되지 않는 형태
중복이 있다 하더라도 그리 문제되지 않는다면 UNION 보다는 UNION ALL을 사용하자.
만약 UNION이나 UNION ALL을 사용해야 한다면, 최소 필요 컬럼만 SELECT 하자.