-
NL조인시 드라이빙테이블 100개 드리븐 1000개, 드라이빙테이블1000개 드리븐 100개가 성능 차이가 나는이유데이터베이스 2024. 10. 21. 16:16728x90반응형
겉으로 보기에는 두 경우 모두 비교 연산이 같은 수(100,000번)처럼 보이지만, 실제로는 성능 차이가 발생할 수 있습니다. 그 이유는 드라이빙 테이블이 먼저 읽힌 이후, 드리븐 테이블에서 데이터를 검색하는 방식과 그 과정에서의 인덱스 사용 여부에 있기 때문입니다. 이를 좀 더 자세히 설명해볼게요.
1. Nested Loop Join의 실행 방식
- 드라이빙 테이블: 조인 시 먼저 읽히는 테이블로, 바깥쪽 루프의 역할을 합니다.
- 드리븐 테이블: 드라이빙 테이블의 각 레코드에 대해 조회를 수행하는 테이블로, 안쪽 루프에서 사용됩니다.
2. 두 경우의 차이점
두 가지 케이스를 다시 살펴볼게요:
- 케이스 1: 드라이빙 테이블이 100개, 드리븐 테이블이 1,000개인 경우.
- 드라이빙 테이블에서 100개의 레코드를 순차적으로 가져옵니다.
- 각 레코드에 대해 드리븐 테이블을 1,000번 조회합니다.
- 각 조회 시 드리븐 테이블에서 인덱스를 사용한다면, 1,000개 중 조건에 맞는 데이터를 빠르게 가져올 수 있습니다.
- 즉, 드리븐 테이블에 인덱스가 잘 설정되어 있으면 이 케이스는 상대적으로 빠르게 수행될 수 있습니다.
- 케이스 2: 드라이빙 테이블이 1,000개, 드리븐 테이블이 100개인 경우.
- 드라이빙 테이블에서 1,000개의 레코드를 순차적으로 가져옵니다.
- 각 레코드에 대해 드리븐 테이블을 100번 조회합니다.
- 하지만 이 경우에도 인덱스가 잘 사용된다면 조회 시간은 짧을 수 있지만, 드라이빙 테이블의 크기가 크기 때문에 메모리에서 처리해야 하는 양이 많아집니다.
3. 성능 차이의 원인
두 경우의 성능 차이는 단순한 비교 횟수보다는 다음과 같은 요인들에 의해 발생합니다:
- 인덱스 사용 여부: 드리븐 테이블에 적절한 인덱스가 있는 경우, 해당 테이블에서 조건에 맞는 레코드를 빠르게 찾을 수 있습니다. 예를 들어, small_table에 인덱스가 설정되어 있다면, 큰 테이블(드라이빙 테이블)에서 조회된 값에 맞는 레코드를 드리븐 테이블에서 빠르게 찾을 수 있습니다.
- 캐시 및 메모리 사용: 드라이빙 테이블이 큰 경우에는 더 많은 데이터를 메모리에 로드하고 처리해야 하므로 메모리 부담이 커질 수 있습니다. 반대로 드라이빙 테이블이 작은 경우에는 작은 데이터 집합을 메모리에 올려놓고 반복 조회가 이루어지기 때문에 캐시 적중률이 높아질 수 있습니다.
- 디스크 I/O: 드리븐 테이블이 큰 경우, 인덱스 없이 전체 테이블 스캔을 해야 하는 상황이 발생할 수 있습니다. 이는 디스크 I/O 비용을 크게 증가시킬 수 있습니다. 반대로 인덱스가 잘 설정된 작은 테이블이라면, 인덱스를 이용해 훨씬 더 효율적으로 조회할 수 있습니다.
결론
- 단순히 조인 시 비교하는 횟수는 동일할 수 있지만, 드라이빙 테이블의 크기와 드리븐 테이블에서 인덱스를 사용하는 방식에 따라 성능 차이가 발생합니다.
- 일반적으로 드라이빙 테이블이 작고, 드리븐 테이블에 인덱스가 잘 설정된 상황이 성능에 더 유리합니다. 큰 테이블을 드라이빙 테이블로 사용하면 메모리 부담이 크고, 작은 테이블을 기준으로 효율적으로 조인을 수행하는 것이 더 낫기 때문입니다.
그래서, 단순히 비교 횟수만 보지 않고, 어떤 테이블이 드라이빙인지, 어떤 테이블에 인덱스가 있는지에 따라 성능 최적화 전략이 달라집니다.
1. Nested Loop Join의 기본 원리
- 드라이빙 테이블: 조인의 바깥쪽 루프에 해당하며, 이 테이블의 각 레코드에 대해 다른 테이블을 검색합니다.
- 드리븐 테이블: 안쪽 루프에 해당하며, 드라이빙 테이블의 각 레코드에 대해 조회 조건에 맞는 데이터를 찾기 위해 검색되는 테이블입니다.
2. 두 가지 시나리오 예시로 비교
가정을 좀 더 구체화해서 설명하겠습니다:
- Case 1: small_table이 드라이빙 테이블(100개의 레코드), large_table이 드리븐 테이블(1,000개의 레코드).
- Case 2: large_table이 드라이빙 테이블(1,000개의 레코드), small_table이 드리븐 테이블(100개의 레코드).
Case 1: 작은 테이블이 드라이빙 테이블일 때
- small_table의 첫 번째 레코드를 가져옵니다.
- 이 레코드에 대해 large_table을 조회하여 조인 조건을 만족하는 데이터를 찾습니다.
- large_table에 인덱스가 있다고 가정하면, small_id에 해당하는 값을 빠르게 찾을 수 있습니다.
- 이 과정을 small_table의 나머지 99개의 레코드에 대해 반복합니다.
이 경우 성능은 large_table에서 인덱스를 사용하여 데이터를 검색하는 속도에 크게 영향을 받습니다. 드라이빙 테이블의 레코드 수가 적기 때문에 large_table을 빠르게 여러 번 조회하는 방식으로 처리할 수 있어 효율적입니다.
Case 2: 큰 테이블이 드라이빙 테이블일 때
- large_table의 첫 번째 레코드를 가져옵니다.
- 이 레코드에 대해 small_table을 조회하여 조인 조건을 만족하는 데이터를 찾습니다.
- small_table이 작고 인덱스가 있다고 가정하면, 조회는 빠르게 이루어질 수 있습니다.
- 하지만 large_table의 나머지 999,999개의 레코드에 대해서도 동일한 작업을 반복합니다.
이 경우 성능은 large_table의 크기에 따라 더 많은 반복 작업이 필요하게 됩니다. 즉, large_table의 크기만큼 small_table을 조회하는 것이기 때문에, 메모리 사용량이 늘어나고, 결과적으로 더 많은 시스템 리소스를 소모할 수 있습니다.
3. 왜 같은 비교 횟수지만 성능 차이가 나는가?
여기서 성능 차이가 나는 핵심 이유는 드리븐 테이블의 조회 방식과 인덱스 사용의 효율성에 있습니다.
- 작은 드라이빙 테이블: 작은 테이블을 드라이빙 테이블로 사용하면, 메모리 내에서 작은 데이터셋을 사용해 여러 번 반복 작업을 수행할 수 있습니다. 따라서 캐시 적중률이 높고, 빠르게 처리될 수 있습니다.
- 큰 드라이빙 테이블: 큰 테이블을 드라이빙 테이블로 사용하면, 각 레코드에 대해 드리븐 테이블을 반복해서 조회해야 하기 때문에 메모리 사용이 증가하고, 드리븐 테이블 조회 시 디스크 I/O가 발생할 가능성이 큽니다.
4. 메모리와 디스크 I/O의 차이
- 메모리 내 처리: 작은 드라이빙 테이블을 사용하면 더 많은 데이터를 메모리에 올려놓고 작업을 할 수 있습니다. 이는 디스크 I/O를 줄이고, 캐시를 이용한 빠른 조회를 가능하게 합니다.
- 디스크 I/O의 증가: 큰 드라이빙 테이블을 사용할 경우, 해당 테이블의 많은 데이터를 메모리에 올릴 수 없기 때문에, 디스크에서 데이터를 불러와야 하는 경우가 많습니다. 이는 성능에 큰 영향을 미칩니다.
예시를 통한 비교 정리
- 드라이빙 테이블이 작으면: 드리븐 테이블을 여러 번 조회하는 비용이 적고, 메모리 내에서 효율적으로 작업할 수 있습니다.
- 드라이빙 테이블이 크면: 메모리에 올려야 할 데이터가 많아지고, 반복 작업이 많아지면서 디스크 I/O가 발생해 성능 저하를 초래할 수 있습니다.
5. 조인에 적절한 테이블 선택의 중요성
따라서 조인을 할 때, 작은 테이블을 드라이빙 테이블로 선택하고, 인덱스를 잘 설정한 큰 테이블을 드리븐 테이블로 사용하면 더 효율적인 조인이 가능합니다. 이는 PostgreSQL뿐만 아니라 대부분의 RDBMS에서 적용되는 일반적인 조인 최적화 전략입니다.
728x90반응형'데이터베이스' 카테고리의 다른 글
상관 서브쿼리 (Correlated Subquery)란? 종류들 (0) 2024.10.22 [SQL] GROUP BY와 PARTITION BY의 차이점 (0) 2024.10.14 쓰기락 for update 사용시 주의점 (mysql,postgresql) (0) 2024.07.11