Link Search Menu Expand Document

결합

기능적 관점으로 구분하는 결합의 종류

크로스 결합 - 모든 결합의 모체

  • 데카르트 곱이라고 불리는 연산으로, 2개 테이블의 레코드에서 가능한 모든 조합을 구하는 연산
  • 크로스 결합이 실무에서 사용되지 않는 이유
    • 이러한 결과가 필요한 경우가 없음
    • 비용이 매우 많이 드는 연산
  • 실수로 사용한 크로스 결합
    SELECT *
    FROM Employees, Departments;
    
    • 결합 조건이 없으므로 DBMS는 두 개의 테이블에서 나올 수 있는 모든 조합을 생성
    • 이러한 실수를 막으려면 표준 SQL에 맞게 결합 구문을 사용하는 것이 좋음

      내부 결합 - 왜 ‘내부’라는 말을 사용할까?

  • 내부는 ‘데카르트 곱의 부분 집합’이라는 의미
  • 기능적으로 상관 서브쿼리를 사용해 대체 가능한 경우가 많음
    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;
    
  • 내부 결합과 상관 서브쿼리 중 내부 결합을 사용하는 것이 좋음
    • 상관 서브쿼리를 이용하면 결과 레코드 수만큼 상관 서브쿼리를 실행하므로 내부 결합보다 비용이 높음

      외부 결합 - 왜 ‘외부’라는 말을 사용할까?

  • 내부 결합과 외부 결합은 배타적인 연산
  • 외부 결합은 ‘데카르트 곱의 부분 집합’이 아니라는 읨
  • 외부 결합의 종류
    • 왼쪽 외부 결합
    • 오른쪽 외부 결합
    • 완전 외부 결합
  • 마스터 테이블 쪽에만 존재하는 키가 있을 때 해당 키를 제거하지 않고 결과에 남김

    내부 결합과 외부 결합의 차이

  • 외부 결합은 마스터 테이블의 정보를 모두 보존하기 위해 NULL을 생성
  • 크로스 결합과 내부 결합은 NULL을 생성하지 않음

    자기 결합 - ‘자기’란 누구일까?

  • 자기 자신과 결합하는 연산으로 같은 테이블 (또는 같은 뷰)을 사용해 결합
  • 같은 테이블에 별칭을 붙여 마치 다른 테이블인 것처럼 취급

    결합 알고리즘과 성능

  • 옵티마이저가 어떤 결합 알고리즘을 선택할지 여부는 데이터 크기 또는 결합 키의 분산에 의존

    Nested Loops

Nested Loops

  1. 결합 대상 테이블(Table_A, driving table or outer table)에서 레코드를 하나씩 반복해가며 스캔
  2. Driving table의 레코드 하나마다 내부 테이블(Table_B, Inner table)의 레코드를 하나씩 스캔해서 결합 조건에 맞으면 리턴
  3. 이러한 작동을 Driving Table의 모든 레코드에 반복
  • 특징
    • 접근하는 레코드 수는 결합 대상인 두 테이블 레코드 수의 곱
    • 한 번의 단계에서 처리하는 레코드 수가 적으므로 Hash 또는 Sort Merge에 비해 메모리 소비가 적음
    • 모든 DBMS에서 지원
    • 구동 테이블이 작을수록 Nested Loops의 성능이 좋음
  • 구동 테이블의 중요성
    • 내부 테이블의 결합 키 필드에 인덱스가 존재할 경우 내부 테이블의 반복을 줄일 수 있음
    • 구동 테이블이 작고 내부 테이블의 결합 키에 인덱스가 존재하는 것이 SQL 튜닝의 기본
  • Nested Loops의 단점
    • 결합 키가 내부 테이블에 대해 유일하지 않은 경우 반복이 발생하므로 성능이 낮아짐
      • 이러한 경우 구동 테이블로 큰 테이블을 선택할 수 있음
      • 내부 테이블에 대한 구동 테이블의 접근이 기본 키로 수행되므로 항상 하나의 레코드로 접근하는 것이 보장됨

        Hash

Hash Join

  • 결합 과정
    1. 작은 테이블을 스캔하고 결합 키에 해시함수를 적용해서 해시값으로 반환
    2. 큰 테이블을 스캔하고 결합 키가 해시값에 존재하는지 확인
  • 특징
    • 결합 테이블로부터 해시 테이블을 만들어서 활용하므로, Nested Loops에 비해 메모리를 크게 소모
    • 메모리가 부족하면 저장소를 사용하므로 지연 발생
    • 출력되는 해시값은 입력값의 순서를 알지 못하므로 등치 결합에만 사용할 수 있음
  • Hash가 유용한 경우
    • Nested Loops에서 적절한 구동 테이블(상대적으로 충분히 작은 테이블)이 존재하지 않는 경우
    • 구동 테이블로 사용할만한 작은 테이블은 있지만, 내부 테이블에서 히트되는 레코드 수가 너무 많은 경우
    • Nested Loops의 내부 테이블에 인덱스가 존재하지 않는 (또는 여러 가지 사정에 의해 인덱스를 추가할 수 없는) 경우
  • 주의할 사항
    • 초기에 해시 테이블을 만들어야 하므로 Nested Loops에 비해 소비하는 메모리 양이 많음
      • OLTP(Online Transaction Processing) 처리를 할 때 사용하면 안됨
      • 야간 배치 또는 BI(Business Intelligence)/DWH(Data Warehouse)와 같은 시스템에 한해 사용
    • 양쪽 테이블의 레코드를 전부 읽어야 하므로 풀 스캔에 걸리는 시간 고려

      Sort Merge

  • 결합 대상 테이블들을 각각 결합 키로 정렬하고 일치하는 결합 키를 찾으면 결합

  • 특징
    • 대상 테이블을 모두 정렬하므로 Nested Loops보다 많은 메모리를 소비
    • 동치 결합 뿐만 아니라 부등호를 사용한 결합에도 사용할 수 있음
    • 테이블이 결합 키로 정렬되어 있다면 정렬을 생략할 수 있지만 이는 구현 의존적
    • 한 쪽 테이블을 모두 스캔한 시점에 결합을 완료함
  • Sort Merge가 유용한 경우
    • 테이블 정렬을 생략할 수 있는 경우에만 고려

      의도하지 않은 크로스 결합

  • 삼각 결합에서 결합 조건이 존재하지 않는 두 테이블을 먼저 결합할 경우 크로스 결합이 발생
  • 비교적 큰 테이블끼리 크로스 결합을 할 경우 성능 문제 발생
  • 크로스 결합이 발생하는 두 테이블의 결합 조건을 설정할 수 있고, 그 결합 조건이 결과에 아무런 영향도 주지 않을 경우 크로스 결합 회피 가능

    결합이 느리다면

    상황에 따른 최적의 결합 알고리즘

    |이름 |장점 |단점 | |–|–|–| |Nested Loops |’작은 구동 테이블’ + ‘내부 테이블의 인덱스’라는 조건이 있다면 굉장히 빠름
    메모리 또는 디스크 소비가 적으므로 OLTP에 적합
    비동기 결합에서도 사용 가능 |대규모 테이블들의 결합에는 부적합
    내부 테이블의 인덱스가 사용되지 않거나, 내부 테이블의 선택률이 높으면 느리다 | |Hash |대규모 테이블들을 결합할 때 적합 |메모리 소비량이 큰 OLTP에는 부적합
    메모리 부족이 일어나면 TEMP 탈락 발생
    등가 결합에서만 사용 가능 | |Sort Merge |대규모 테이블들을 결합할 때 적합
    비등가 결합에서도 사용 가능 |메모리 소비량이 큰 OLTP에는 부적합
    메모리 부족이 일어나면 TEMP 탈락 발생
    데이터가 정렬되어 있지 않다면 비효율적 |

  • 결합 대상 레코드 수에 따른 최적의 결합 알고리즘
    • 소규모 - 소규모: 어떤 알고리즘을 사용해도 성능 차이가 크지 않음
    • 소규모 - 대규모: 대규모 테이블의 결합 키에 인덱스를 만들어 Nested Loops를 사용. 하지만 내부 테이블의 결합 대상 레코드가 너무 많다면 구동 테이블과 내부 테이블을 바꾸거나 Hash 사용
    • 대규모 - 대규모: Hash 사용. 처음부터 결합 키로 정렬이 되어 있는 상태라면 Sort Merge 사용

실행 계획 제어

  • RDB에서는 원칙적으로 통계 정보를 바탕으로 옵티마이저가 실행 계획을 자동으로 수립
  • 실행 계획을 사용자가 제어할 때의 리스크
    • 데이터 양과 카디널리티는 데이터베이스를 운용하는 동안 계속 바뀌므로 어떤 시점에는 적절했던 실행 계획이 또 다른 시점에는 적절하지 않을 수 있음
    • 따라서, 사용자가 실행 계획을 제어할 때는 이러한 위험을 충분히 검토하고, 시스템의 미래 상황도 예측해서 적절한 실행 계획을 선택해야 함

      흔들리는 실행 계획

  • 데이터 양의 증가 등에 따라 통계 정보가 변했을 때 일정한 역치를 넘으면 ‘옵티마이저의 실패’가 발생할 수 있음
  • SQL 성능의 변동 위험을 줄이려면 되도록 결합을 피해야 함