이때 SELECT 구문에 서브쿼리를 넣어도 괜찮을까? 라고 생각할 수 있지만,
dept_id는 부서 테이블의 PK이므로, 레코드가 한 개로 한정되어 스칼라 서브쿼리로 사용할 수 있다.
SELECT E.emp_id, E.emp_name, E.dept_id,
(SELECT D.dept_name
FROM Departments D
WHERE E.dept_id = D.dept_id) AS dept_name
FROM Employees E;
상관 서브쿼리 vs inner join
상관 서브 쿼리를 스칼라 서브쿼리로 사용하면, 결과 레코드 수만큼 상관 서브쿼리를 실행하기 때문에 실행 비용이 너무 높다
self join은 outer join, inner join 과는 약간 다른 분류이다.
생성되는 결과를 기준으로 분류하는 것이 아닌, 연산에 대상으로 무엇을 사용하는 지에 따른 분류이다.
따라서 self join을 하기 위한 방식으로는 self + cross, self + outer 가 있다.
digit |
---|
0 |
1 |
2 |
3 |
4 |
SELECT D1.digit + (D2.digit * 10) AS seq
FROM Digits D1 CROSS JOIN Digits D2;
0
1
2
3
4
사실 물리 레벨에서 보면 같은 테이블과 결합하지만, 논리적으론 서로 다른 두 개의 테이블을 결합한다고 생각해도 된다.
MySQL은 Nested Loops와 그 파생 버전만 지원, Hash 또는 Sort Merge 사용 X
DBMS 버전이 오르면 알고리즘이 바뀌는 경우가 있으므로, DBMS의 최신 동향에 유의하자.
‘구동 테이블(외부 테이블)’로는 작은 테이블을 선택하자’
❗️내부 테이블의 결합 키 필드에 인덱스가 존재한다면❗️
위 ‼️조건을 만족하지 못한다면, 구동 테이블의 크기가 작아도소용이 없다.
이렇게 내부 테이블(B)에 인덱스가 존재한다면, 모든 레코드를 탐색하지 않아도 된다.
위의 개선 방법으로 개선한다 해도, 내부 테이블의 결합 키가 유일한 값이 아니라면 결국 히트되는 레코드가 많기 때문에 많은 반복이 발생 → 지연 발생
예를 들어, 점포 테이블과 주문 테이블이 있다고 가정하자. 점포 하나당 여러 개의 주문 데이터가 있을테니 크기는 점포 테이블이 작다.
점포 테이블을 구동 테이블(외부 테이블)로 선택 (테이블의 크기가 더 작기 때문)
대처하는 방법
왜 작은 테이블부터 스캔할까?
→ 작은 테이블의 결합 키를 이용해 해시테이블을 만들면 그만큼 작은 해시 테이블을 만들 수 있어, 워킹 메모리를 그나마 조금 사용
용어 정리
Nested Loops가 비효율적일 때, 또 다른 선택지
결합 대상 테이블을 결합 키로 정렬 후, 매칭시키는 방법
테이블 정렬에 많은 시간과 리소스를 요구하는 방법이기 때문에,
테이블 정렬을 생략할 수 있는 경우에만 고려하자
크로스 조인을 실무에서 사용할 일은 거의 없지만, 의도치 않게 발생하는 경우가 있다.
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;
결합 조건은 A와 B, A와 C에만 존재
→ 이때, Table_B와 Table_C는 결합 조건이 없으므로, 크로스 조인을 할 수 밖에 없다.
Table_B와 Table_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;
이름 | 장점 | 단점 |
---|---|---|
Nested Loops | - 작은 구동 테이블 + 내부 테이블의 인덱스 ⇒ 굉장히 빠르다 |
장단점에 맞춰 선택하자
사용자가 SQL 구문에 직접 힌트를 작성해 옵티마이저 조종하기
데이터의 양과 카디널리티는 DB를 운영하면서 바뀌기 떄문에, 항상 지금의 실행 계획이 효율적이라고는 장담 못한다.
따라서 시간에 따라 어떻게 데이터가 변할 지 유추하고, 테스트 해봐야 한다.
시간에 따라 효율적인 실행 계획 변동이 발생한다면, 골치아프다..
따라서 SQL 성능 변동 위험을 줄이려면 join을 피해야 한다!