안녕하세요, 코딩하는곰입니다! 오늘은 MySQL과 MariaDB에서 자주 묻는 질문 중 하나인 “FULL OUTER JOIN은 왜 안 되나요?”라는 주제로 깊이 있게 알아보겠습니다. 많은 개발자들이 다른 데이터베이스에서는 지원하는 FULL OUTER JOIN을 MySQL과 MariaDB에서 사용하려다가 에러를 만나곤 합니다. 이번 포스팅에서는 FULL OUTER JOIN이 지원되지 않는 이유와 이를 효과적으로 대체하는 UNION 방법을 상세히 설명드리겠습니다. 데이터베이스 쿼리 최적화에 관심이 많으신 분들께 특히 유용한 내용이 될 거예요.
FULL OUTER JOIN은 SQL에서 두 테이블의 모든 레코드를 결합하는 조인 방식입니다. LEFT OUTER JOIN과 RIGHT OUTER JOIN의 결과를 합친 개념으로, 두 테이블 간에 매칭되는 레코드가 없더라도 모든 데이터를 포함시킵니다. 일반적으로 다음과 같은 상황에서 사용됩니다:
-- 다른 DBMS에서의 FULL OUTER JOIN 예시SELECT *FROM table1FULL OUTER JOIN table2 ON table1.id = table2.id;
MySQL은 처음부터 단순성과 성능에 중점을 둔 데이터베이스로 개발되었습니다. FULL OUTER JOIN은 구현이 복잡하고 자원 소모가 큰 연산이기 때문에 초기 설계에서 제외되었습니다. 이 결정은 MySQL의 경량 아키텍처와 빠른 처리 속도를 유지하는 데 기여했습니다.
FULL OUTER JOIN은 대용량 데이터 처리 시 성능 저하를 일으킬 수 있습니다. MySQL은 대체 구현 방법을 통해 동일한 결과를 더 효율적으로 얻을 수 있다고 판단했습니다. 특히 인덱스 활용과 쿼리 실행 계획 최적화 측면에서 UNION을 통한 구현이 더 나은 성능을 보이는 경우가 많습니다.
실제 프로덕션 환경에서 FULL OUTER JOIN의 사용 빈도는 다른 조인 방식에 비해 상대적으로 낮습니다. 대부분의 비즈니스 시나리오에서 LEFT JOIN, RIGHT JOIN, INNER JOIN으로 충분히 요구사항을 만족시킬 수 있습니다.
조인 방식을 단순화함으로써 쿼리의 예측 가능성과 유지보수성을 높일 수 있습니다. 복잡한 FULL OUTER JOIN 대신 명시적인 UNION을 사용하면 쿼리의 의도를 더 명확하게 표현할 수 있습니다.
💻 프로그래밍에 관심이 많다면, (Java 기초) 전위 증감 연산자(++i)와 후위 증감 연산자(i++)의 차이 완벽 정리 - 코딩하는곰를 참고해보세요.
MySQL과 MariaDB에서 FULL OUTER JOIN을 구현하는 가장 일반적이고 효율적인 방법은 LEFT JOIN, RIGHT JOIN, UNION을 조합하는 것입니다. 이 방법은 명시적이고 이해하기 쉬우며 성능도 우수합니다.
가장 기본적인 FULL OUTER JOIN 대체 패턴은 다음과 같습니다:
SELECTt1.id as t1_id,t1.name as t1_name,t2.id as t2_id,t2.name as t2_nameFROM table1 t1LEFT JOIN table2 t2 ON t1.id = t2.idUNIONSELECTt1.id as t1_id,t1.name as t1_name,t2.id as t2_id,t2.name as t2_nameFROM table1 t1RIGHT JOIN table2 t2 ON t1.id = t2.idWHERE t1.id IS NULL;
이 패턴은:
SELECTCOALESCE(t1.id, t2.id) as combined_id,t1.name as table1_name,t2.name as table2_name,t1.other_data,t2.other_dataFROM table1 t1LEFT JOIN table2 t2 ON t1.id = t2.idUNIONSELECTCOALESCE(t1.id, t2.id) as combined_id,t1.name as table1_name,t2.name as table2_name,t1.other_data,t2.other_dataFROM table1 t1RIGHT JOIN table2 t2 ON t1.id = t2.idWHERE t1.id IS NULL;
-- 특정 조건을 가진 FULL OUTER JOINSELECTt1.*,t2.*FROM table1 t1LEFT JOIN table2 t2 ON t1.id = t2.id AND t2.status = 'active'UNIONSELECTt1.*,t2.*FROM table1 t1RIGHT JOIN table2 t2 ON t1.id = t2.id AND t2.status = 'active'WHERE t1.id IS NULL;
SELECTt1.id,t1.name,t2.department,t3.salaryFROM employees t1LEFT JOIN departments t2 ON t1.dept_id = t2.idLEFT JOIN salaries t3 ON t1.id = t3.emp_idUNIONSELECTt1.id,t1.name,t2.department,t3.salaryFROM employees t1RIGHT JOIN departments t2 ON t1.dept_id = t2.idLEFT JOIN salaries t3 ON t1.id = t3.emp_idWHERE t1.id IS NULLUNIONSELECTt1.id,t1.name,t2.department,t3.salaryFROM employees t1LEFT JOIN departments t2 ON t1.dept_id = t2.idRIGHT JOIN salaries t3 ON t1.id = t3.emp_idWHERE t1.id IS NULL AND t2.id IS NULL;
-- 중복 제거가 필요할 때 (성능 저하 가능성)SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.idUNIONSELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.id WHERE table1.id IS NULL;-- 중복 제거가 필요없을 때 (더 빠른 성능)SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.idUNION ALLSELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.id WHERE table1.id IS NULL;
성능을 우선시한다면 가능한 UNION ALL을 사용하는 것이 좋습니다.
유튜브, 블로그, 커뮤니티용 닉네임을 쉽게 만들고 싶다면 이력 확인 및 카테고리 설정이 가능한 닉네임 생성기를 추천합니다.
-- 고객 테이블과 주문 테이블의 FULL OUTER JOINSELECTCOALESCE(c.customer_id, o.customer_id) as customer_id,c.customer_name,c.join_date,o.order_id,o.order_date,o.total_amountFROM customers cLEFT JOIN orders o ON c.customer_id = o.customer_idWHERE o.order_date >= '2024-01-01'UNIONSELECTCOALESCE(c.customer_id, o.customer_id) as customer_id,c.customer_name,c.join_date,o.order_id,o.order_date,o.total_amountFROM customers cRIGHT JOIN orders o ON c.customer_id = o.customer_idWHERE c.customer_id IS NULLAND o.order_date >= '2024-01-01';
-- 현재 재고와 입출고 기록 통합 조회SELECTCOALESCE(s.product_id, t.product_id) as product_id,p.product_name,s.current_stock,t.transaction_type,t.quantity,t.transaction_dateFROM stock sLEFT JOIN transactions t ON s.product_id = t.product_idAND t.transaction_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)UNIONSELECTCOALESCE(s.product_id, t.product_id) as product_id,p.product_name,s.current_stock,t.transaction_type,t.quantity,t.transaction_dateFROM stock sRIGHT JOIN transactions t ON s.product_id = t.product_idAND t.transaction_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)LEFT JOIN products p ON COALESCE(s.product_id, t.product_id) = p.product_idWHERE s.product_id IS NULL;
-- 조인 컬럼에 인덱스 생성CREATE INDEX idx_table1_id ON table1(id);CREATE INDEX idx_table2_id ON table2(id);-- 복합 인덱스가 필요한 경우CREATE INDEX idx_table1_composite ON table1(id, status, created_date);CREATE INDEX idx_table2_composite ON table2(id, category, active_flag);
-- EXPLAIN으로 쿼리 실행 계획 확인EXPLAINSELECT t1.*, t2.*FROM table1 t1LEFT JOIN table2 t2 ON t1.id = t2.idUNIONSELECT t1.*, t2.*FROM table1 t1RIGHT JOIN table2 t2 ON t1.id = t2.idWHERE t1.id IS NULL;
-- 비효율적인 서브쿼리SELECT * FROM (SELECT t1.*, t2.* FROM table1 t1 LEFT JOIN table2 t2 ON t1.id = t2.idUNIONSELECT t1.*, t2.* FROM table1 t1 RIGHT JOIN table2 t2 ON t1.id = t2.id WHERE t1.id IS NULL) AS combinedWHERE combined.some_column = 'value';-- 최적화된 쿼리SELECT t1.*, t2.* FROM table1 t1 LEFT JOIN table2 t2 ON t1.id = t2.idWHERE t1.some_column = 'value' OR t2.some_column = 'value'UNIONSELECT t1.*, t2.* FROM table1 t1 RIGHT JOIN table2 t2 ON t1.id = t2.idWHERE t1.id IS NULL AND t2.some_column = 'value';
| 방법 | 장점 | 단점 | 사용 시나리오 |
|---|---|---|---|
| UNION + LEFT/RIGHT JOIN | 명확한 syntax, 이해하기 쉬움 | 중복 제거로 인한 성능 저하 가능 | 일반적인 FULL OUTER JOIN 대체 |
| UNION ALL + LEFT/RIGHT JOIN | 빠른 성능, 중복 허용 | 중복 데이터 발생 가능 | 성능이 중요한 대용량 데이터 |
| 서브쿼리 + CASE 문 | 복잡한 조건 처리 가능 | 가독성 저하, 성능 이슈 | 특수한 비즈니스 로직 |
쇼핑, 가계부 정리, 간단한 수치 계산 등이 필요할 때는 기록 기능 포함 계산기가 편리합니다.
MySQL과 MariaDB에서 FULL OUTER JOIN이 공식적으로 지원되지 않지만, UNION을 활용한 대체 방법으로 동일한 기능을 완벽하게 구현할 수 있습니다. 이 방법은 성능 면에서도 우수하고 가독성도 좋으며, 복잡한 비즈니스 로직에도 유연하게 대응 가능합니다. 데이터베이스 쿼리를 작성할 때는 단순히 기능 구현에만 집중하기보다는 성능, 가독성, 유지보수성을 종합적으로 고려하는 것이 중요합니다. FULL OUTER JOIN 대체 패턴을 잘 익혀두시면 실제 프로젝트에서 다양한 데이터 통합 요구사항을 효과적으로 해결하실 수 있을 거예요. 다음 포스팅에서는 MySQL과 MariaDB의 다른 고급 조인 기법과 성능 최적화 팁에 대해 더 깊이 있게 다루어 보겠습니다. 궁금한 점이 있으시면 언제든지 댓글로 질문해 주 세요! 코딩하는곰이었습니다. 감사합니다!
QR코드로 간편하게 번호를 확인하고 싶다면, AI 번호 추천과 최근 당첨번호까지 제공하는 지니로또AI 앱을 다운로드하세요.
