다수의 테이블에서 조인을 수행할 때는 동시에 여러 개의 테이블에 접근할 수 없는 만큼 접근하는 우선순위를 정하게 된다.
다수의 테이블에서 첫 번째로 접근할 테이블, 두 번째로 접근할 테이블, 세 번째로 접근할 테이블 등 내부적으로 순번을 정하고, 차례로 테이블에 접근한 결과를 다음 순번의 테이블로 전달한다.
SELECT 학생.학번, 학생.이름,
비상연락망.관계, 비상연락망.연락처
FROM 학생
JOIN 비상연락망
ON 학생.학번 = 비상연락망.학번
WHERE 학생.학번 IN (1,100)
이 예제에서는 학생.학번(1,100) 조건이 있으므로 학생 테이블의 데이터를 먼저 찾아볼 것이다.
학생 테이블에서 찾은 결과로 비상연락망 테이블에서 학번 1과 100을 검색한다.
이처럼, 먼저 접근하는 테이블을 드라이빙 테이블(driving table)이라고 하고, 그 결과를 이용하여 뒤늦게 데이터를 검색하는 테이블을 드리븐 테이블(driven table)이라고 한다.
위의 예제에서는 드라이빙 테이블이 학생, 드리븐 테이블이 비상연락망이 된다.
중요한 점❗️
드라이빙 테이블에서 많은 건수가 반환되면 해당 결과를 가지고 드리븐 테이블에 접근하게 되기 때문에, 사실상 드라이빙 테이블을 무엇으로 선정할지는 매우 중요한 문제이다.
가능하면 적은 결과가 반환될 것으로 예상되는 드라이븐 테이블을 선정하고, 조인 조건절의 열이 인덱스로 설정되도록 구성해야 한다.
기본적으로 Mysql에서 사용하는 조인 방식이다.
NL(Nested Loop) 조인은 드라이빙 테이블의 데이터 1건당 드리븐 테이블을 반복해 검색하며 최종적으로는 양쪽 테이블에 공통된 데이터를 출력한다. 마치 2중 for문을 떠올리면 좋을 것 같다.
중첩 로프 조인의 과정을 더 잘 이해해보기 위해 시나리오를 설정해서 이해해보자.
시나리오
학생 데이터: 100개
비상 연락망 데이터: 1000개
1번 학생: 2개의 비상연락망(아버지, 어머니)를 가지고 있음
100번 학생: 1개의 비상연락망을 가지고 있음
이처럼 학번 1데이터(100 + 1000)와 학번 100데이터(100 + 1000)를 찾기 위해 대략 2,200건의 데이터에 접근하였다.
결론: 매우 비효율적인 것을 알 수 있다. 우선 인덱스를 걸고 생각해봐야 할 것 같다.
학생 테이블: 학번이 고유 인덱스
비상연락망 테이블: 학번이 비고유 인덱스(즉, 하나의 학생이 여러 비상연락망을 가질 수 있음)
학번 1인 데이터(1 + 2)와 학번 100인 데이터(1 + 1)를 찾기 위해 6번의 데이터에 접근하게 된다.
❗️하지만 인덱스를 통해 테이블의 데이터를 찾아가는 과정에서 발생하는 Random Access를 고려해야 한다.
결론: Random Access를 고려하더라도, 위의 2,200번의 데이터 접근과 비교해 봤을때 6번은 훨씬 효율적이라는 생각이 든다.
하지만 드라이븐 테이블(학생테이블)에서 조회하고자하는 학생의 수만큼 학생 테이블을 접근해야 한다.(마치 for문과 같다). 버퍼를 이용해 학생테이블 자체 조회를 한번만 할 수 있으면 더 좋을것 같다는 생각이 든다.
다음 시간에 NL 조인보다 더 좋은 성능을 보이는 조인 방식에 대해 공부해 보도록 하자.