JOIN의 종류와 주의사항 (TIL)

2024. 4. 21. 20:52데이터베이스 & SQL/데이터베이스

1. 크로스 조인(CROSS JOIN)

 

 크로스 조인은 테이블 두 개의 카테시안 곱을 결과로 만들어주는 조인이다. 이미지로 보는 게 더 이해가 빠르다. 크로스 조인을 하면 다음과 같이 두 개의 테이블 컬럼을 결합해서 가져온다. 만약 사원의 테이블의 레코드가 3, 부서 테이블의 레코드가 2이면 총 6개의 데이터가 나온다.

 

 

 데이터의 내용을 보면 알 수 있듯이 결과가 의미가 없고, 모든 테이블의 내용을 곱 연산으로 가져오기 때문에 비용이 많이 들어서 거의 사용할 일이 없다. 따라서, 크로스 조인은 되도록 피해야 하는 조인이다. 하지만 SQL을 잘못 작성하게 되면 크로스 조인이 의도하지 않게 나오게 된다.

 

[ 의도하지 않은 크로스 조인 - 결합 조건이 없는 경우 ]

 잘 일어나지 않겠지만 테이블 두 개로 조인을 할 때에 실수로 일어날 수 있는 상황은 아무런 결합 조건을 주지 않은 채로 테이블을 조인하는 것이다.

SELECT *
  FROM Employees, Departments;

 

 이러한 경우는 대부분이 쉽게 인지하고 넘어갈 것이라고 생각을 한다. 하지만 테이블의 개수가 많아지면 그 땐 실수를 할 수 있음에 주의하자.

 

[ 의도하지 않은 크로스 조인 - 테이블이 3개 ]

 다음의 경우는 테이블 3개를 조인하는 경우로 SQL 레벨업에 있는 구문을 가져왔다. 아래의 경우는 개별 테이블의 크기에 따라, 쿼리 옵티마이저 내부에서 조인할 순서를 결정한다.일반적으로 이렇게 SQL 쿼리를 짰다면 A 테이블과 B테이블이 내부 조인하고 그 이후 조인된 테이블 결과에 C테이블이 내부 조인되기를 기대했을 것이다.

SELECT A.col_a, B.col_b, C.col_c
  FROM Table_A A
       INNER JOIN Table_B B
          ON A.col_a = B.col_b
       INNER JOIN Table_C C
          ON A.col_a = C.col_c;

 

 

 하지만, 만약에 아래와 같은 상황이라고 해보자. 정규화 과정으로 보조 테이블 크기는 매우 작은데, 내부 구성인원이 매우 많아서 이런 경우가 발생할 수 있다. 이런 경우에는 쿼리 옵티마이저가 B와 C를 먼저 조인하고 그 이후 A 테이블과 조인하는 게 비용이 작을 수 있다고 판단할 수도 있다. 그런데, 문제는 B와 C 사이에서는 아무런 조인 조건이 존재하지 않는다. 따라서, 둘 사이엔 크로스 조인이 발생하게 된다.

 

 

 

 이 문제를 해결하는 방법은 B 테이블과 C 테이블에 대한 결합 조건을 추가해주는 것이다. 그러면, 테이블의 크기가 위의 이미지처럼 돼서 B 테이블과 C 테이블 사이의 조인이 먼저 일어나더라도 크로스 조인이 회피가 가능하다.

SELECT A.col_a, B.col_b, C.col_c
  FROM Table_A A
       INNER JOIN Table_B B
          ON A.col_a = B.col_b
       INNER JOIN Table_C C
          ON A.col_a = C.col_c
         AND C.col_c = B.col_b;

2. 내부 조인(INNER JOIN)

 

 내부 조인은 카테시안 곱의 일부 결과로 조인 중에서는 엄격한 편에 속하는 조인이라고 생각한다. 내부 조인은 테이블끼리 조인을 할 때에, ON 절에 명시한 필드에 대해 참을 반환하는 경우만 인정한다. 사원, 부서 테이블 예시로 하면 아래와 같이 dept_id가 같은 값을 가지는 경우에만 결과가 나온다.

 

 

  위의 결과를 확인할 수 있는 SQL문은 다음과 같으며, INNER JOIN 명령어를 JOIN으로 바꾸어도 똑같이 INNER JOIN으로 인식한다. 

 

SELECT E.emp_id, E.emp_name, E.dept_id, D.dept_name
  FROM Employees E INNER JOIN Departments D
    ON E.dept_id = D.dept_id;

 

 그런데, NATURAL JOIN이라는 단어도 들어보았을 것이다. NATURAL JOIN은 INNER JOIN에 대해 자동화를 해주는 조인으로 같은 이름을 가진 모든 필드에 대하여 각각의 필드가 모두 일치해야지 값을 가져온다. SQL 상에서의 조인되는 필드를 명확하게 알기 위해서, 내부 테이블 사정을 모르면 곤란하므로 쓰지 않는 걸 권장한다.


3. 외부 조인(OUTER JOIN)

 

 외보 조인은 내부 결합과 함께 자주 사용된다. 내부 조인과 외부 조인의 차이는 NULL 값을 어떻게 처리하느냐에 달려있다. 내부 조인에서는 NULL과 NULL의 AND 조건은 UNKNOWN이기 때문에 무시한다. 따라서 NULL 값이 조인 조건 컬럼에 있는 경우 결과에 출력되지 않는다. 하지만 외부 조인에서는 NULL 값에 대해서도 결과에 출력을 한다.

 

 특히 외부 조인이 사용되는 상황은 무엇이 정해지지 않은 혹은 무엇을 하지 않은 인원의 수, 인원의 명단을 뽑고 싶다는 상황에서 많이 사용된다. 앞의 사원, 부서에서 다음과 같이 데이터를 추가하였다. 개발 부서가 새로 생겼고 개발 부서에는 아직 사람이 없다. 또한 도우너 사원이 새로 입사하였는데, 도우너 사원의 부서는 아직 미정이다.

 

 

 이 때, 왼쪽 외부 조인을 이용해서 아래처럼 SQL을 작성하게 되면 결과는 어떻게 나올까? 왼쪽 테이블인 부서 테이블에서 아직 개발 부서에는 사람이 존재하지 않는다. 그런데, 외부 조인에서는 이런 내용까지 함께 출력이 된다.  그러니, 개발 부서에서 사원 번호와 사원 명은 NULL인 레코드가 하나 나온다.

SELECT E.emp_id, E.emp_name, D.dept_id, D.dept_name
  FROM Departments D LEFT OUTER JOIN Employees E
    ON D.dept_id = E.dept_id;

 

 

 그럼 이번엔 오른쪽 외부 조인을 이용해서 아래처럼 SQL을 작성하게 되면 결과는 어떻게 나올까? 이번에는 우측 테이블인 사원 테이블에서 도우너 사원은 아직 부서가 정해지지 않았다. 그렇기 때문에 도우너 사원의 부서 정보는 NULL로 출력돼서 결과가 나오게 된다.

SELECT E.emp_id, E.emp_name, D.dept_id, D.dept_name
  FROM Departments D RIGHT OUTER JOIN Employees E
    ON D.dept_id = E.dept_id;

 

 

 결과는 아래와 같이 나온다. 직접 테이블을 생성해보고 꼭 눈으로 확인해보았으면 좋겠다.

 

 

 

 완전 외부 조인이라는 의미로 FULL OUTER JOIN도 있는데 이는 잘 안 쓰는 것 같아서 생략한다.  위의 예시가 확인용으로는 좋겠지만 의미는 없는 것 같아서 아래의 예시를 추가한다. 아래의 예시는 아직 부서가 정해지지 않은 사원의 사원 번호와 사원 명을 출력한다.

SELECT E.emp_id, E.emp_name
  FROM Departments D RIGHT OUTER JOIN Employees E
    ON D.dept_id = E.dept_id
 WHERE E.dept_id IS NULL;

  간단하게 SQL에서 일어날 수 있는 JOIN과 상황예시에 관해서 알아보았으며 조인에 대해서 이해하는 것은 이후 배울 결합 알고리즘과 성능 부분에서도 매우 중요하니 이해하고 넘어갔으면 좋겠다!

[ 참고 자료 ]

 SQL 레벨업 - 미크