SQL 레벨업이라는 도서를 정리한 내용입니다.
6장에서는 SQL의 결합과 결합이 어떤식으로 동작하는지 설명합니다.
크로스 결합, 내부 결합, 외부 결합의 관계를 그림으로 표현하면 위 그림과 같습니다.
이름 그대로 중접 반복을 사용하는 알고리즘이다.
1.결합 대상 테이블(Table_A)에서 레코드를 하나씩 반복하며 스캔한다. 이 테이블을 구동 테이블(driving table) 또는 외부 테이블(outer_table)이라고 한다. 다른 테이블(Table_B)은 내부 테이블(inner table)이라고 부른다.
2. 구동 테이블이 레코드를 하나마다 내부 테이블의 레코드를 스캔해서 결합 조건에 맞으면 리턴한다.
3. 2를 구동 테이블의 모든 레코드에 반복한다.
NL 결합에서 구동 테이블으로 작은 테이블을 선택하는 것이 성능 개선이 된다는 말이 있다. 하지만 이 말에는 한 가지 조건이 필요하다. 바로 '내부 테이블의 결합 키 필드에 인덱스가 존재해야 한다'는 것이다.
위 조건이 충족되면 DBMS는 내부 테이블을 완전히 순환하지 않아도 된다. 민약 구동 테이블의 한 레코드에 내부 테이블의 한 레코드가 대응하고 이를 인덱스로 찾을 수 있다면, 접근하는 레코드 수는 R(A) x N(리프 노느까지의 거리)가 된다.
다만 한 레코드가 여러 레코드에 대응하는 경우 여러개의 레코드에 반복을 적용해야 한다. ( index range scan )
내부 테이블의 선택률이 높으면 성능이 악화된다.
작은 테이블에서 해시 테이블을 만드는 이유는 해시 테이블이 DBMS의 워킹 메모리에 저장되기 때문이다.
Sort Merge은 결합 자체에 걸리는 시간은 나쁘지 않은 편이지만, 정렬에 많은 시간과 리소스를 소모할 가능성이 있으므로 테이블 정렬을 생략할 수 있는(매우 예외적인) 상황을 제외하고는 Nested Loops나 Hash를 우선적으로 고려하는게 좋다.
의도하지 않는 크로스 결합이 일어나는 경우는 대부분 작성자의 실수 때문이고, 대부분 '삼각 결합'이라 부르는 패턴에서 문제가 발생한다.
이러한 형태의 삼각 결합에서 Table_B와 Table_C의 결합이 일어난다면, 둘 사이에는 아무런 결합조건이 없기에 크로스 결합이 일어난다.
사실 작은 테이블 사이의 크로스 결합은 자주 일어나며, 크게 두려워할 필요는 없다. 하지만 비교적 큰 테이블 끼리의 크로스 결합이 일어나는 경우는 큰 성능 저하가 일어난다.
이처럼 불필요한 결합 조건을 추가해서 크로스 결합을 회피하는 것이다. 이렇게 된다면 실행 계획이 변경되어도 크로스 결합이 일어날 걱정을 할 필요가 없다.
어떤 알고리즘을 사용해도 큰 차이가 없습니다.
소규모 테이블을 구동 테이블로 하는 경우 Nested Loops를 사용한다. 하지만 내부 테이블의 결합 대상 레코드가 너무 많다면 구동 테이블과 내부 테이블을 바꾸거나, Hash를 사용하는 것을 검토해 보아라.
Hash를 사용한다. 결합키로 정렬이 되어 있다면 Sort Merge를 사용한다.
실행 계획을 바꾸는 것은 DBMS 마다 다르다.
사용자가 실행 계획을 제어하는 것은 큰 리스크가 따른다. 데이터와 카디널리티는 데이터베이스를 운용하면서 계속 바뀌기 때문에 어떨때는 적절한 실행계획이 다른 시점에는 좋지 않은 실행계획이 될 수도 있다.
그러므로 사용자가 실행 계획을 제어할 때는 시스템의 미래 상황을 예측하고, 이러한 위험을 충분히 검토하여야 한다.
옵티마이저에게 실행계획을 맡겨도 최적의 실행 결과가 선택되지 않는 경우가 있다.
대표적으론 장기적인 운용 중에 실행 계획이 안좋은 방향으로 변화하는 것이다. 이는 사전에 예측하기 어렵고 돌발적인 슬로다운을 일으키는데, 데이터양의 증가나 통계 정보의 변화로 인하여 옵티마이저가 실행 계획을 변경하면서 발생한다.
결합은 여러 알고리즘을 선택할 수 있기 때문에 실행 계획 변동이 가장 일어나기 쉬운 부분이다.
따라서 SQL 성능 변동을 줄이기 위해서는 결합의 수를 줄여야 한다.