5. 옵티마이저와 실행계획

Quill_Kim_13·2023년 11월 6일
0

sql 공부

목록 보기
7/7

옵티마이저란

  • 사용자가 질의한 SQL 문에 대한 최적의 실행방법을 결정하는 역할을 수행한다. 이러한 최적의 실행방법을 실행 계획이라고 한다.
  • 사용자의 요구사항을 만족하는 결과를 추출할 수 있는 다양한 실행 방법이 존재함
  • 다양한 실행 방법들 중에서 최적의 실행방법을 결정하는 것이 옵티마이저의 역할이다.

비용기반 옵티마이저

  • SQL 문을 처리하는데 비용이 가장 적게 드는 실행계획을 선택하는 방식이다. 비용이란 SQL 문을 처리하는데 예상되는 시간 또는 자원 의미한다.
  • 테이블, 인덱스 등의 통계 정보와 시스템 통계정보를 이용하여 최적의 실행계획을 도출한다.
  • 인덱스를 사용하는 비용이 전체 테이블 스캔 비용보다 크다고 판단되면 테이블 풀 스캔을 유도 하게 된다.

옵티마이저의 구성요소

  • 구성요소
    ◼ 질의 변환기
    ◆ 사용자가 작성한 SQL 문을 처리하기에 보다 용이한 형태로 변환

    ◼ 비용 예측기
    ◆ 대안 계획 생성시에 의해서 생성된 대안 계획의 비용을 예측하는 모듈
    ◆ 대안 계획의 정확한 비용을 측정하기 위해서 연산의 중간 집합의 크기 및 결과 집합의 크기, 분포도 등의 예측을 함, 보다 나은 예측을 위해서 정확한 통계 정보가 필요함

    ◼ 대안계획생성기
    ◆ 동일한 결과를 생성하는 다양한 대안 계획을 생성하는 모듈
    ◆ 대안 계획은 연산의 적용 순서, 연산방법변경, 조인 순서 변경 등을 통해서 생성
    ◆ 동일한 결과를 생성하는 가능한 모든 대안 계획을 생성해야 보다 나은 최적화를 수행할 수 있음

인덱스란?

  • 인덱스는 원하는 데이터를 쉽게 찾을 수 있도록 돕는 책의 찾아보기와 유사한 개념이다.
  • 검색조건에 부합하는 데이터를 효과적으로(빠르게) 검색할 수 있도록 돕는다.
  • 한 테이블은 0 개~N 개의 인덱스를 가질 수 있다.
  • 한 테이블에 과도하게 많은 인덱스가 존재하면 INSERT, UPDATE, DELETE 와 같은 DML 작업 시 부하가 발생한다

트리기반 인덱스 란?

  • DBMS 에서 널리 사용되는 가장 일반적인 인덱스이다.
  • 루트 블록, 브랜치 블록, 리프 블록으로 구성된다.
  • 가장 상위에 존재하는 블록이 루트 블록이고 브랜치 블록은 분기를 목적으로 하는 블록이다.
  • 리프 블록은 트리의 가장 아래 단계에 존재하는 블록이다.
  • 리프 블록은 인덱스를 구성하는 칼럼의 데이터와 해당 데이터를 가지고 있는 행의 위치를 가리키는 레코드 식별자 인 ROWID 로 구성되어 있다.

인덱스 구조 상세

  • 루프와 브랜치 블록에 있는 각 레코드는 하위 블록에 대한 주소 값을 갖는다. 키 값은 하위 블록에 저장된 키 값의 범위를 나타낸다.
  • LMC 가 가리키는 주소로 찾아간 블록에는 키 값을 가진 첫번째 레코드보다 작거나 같은 레코드가 저장돼 있다.
  • 리프 블록에 저장된 각 레코드는 키 값 순으로 정렬돼 있을 뿐만 아니라 테이블 레코드를 가리키는 주소값 즉 Rowid 를 갖는다.
  • 인덱스 키 값이 같으면 Rowid 순으로 정렬된다.
  • 인덱스를 스캔하는 이유는 검색조건을 만족하는 소량의 데이터를 빨리 찾고 거기서 Rowid 를 얻기 위해서이다

풀 테이블 스캔과 인덱스 스캔

풀테이블 스캔

  • 테이블에 존재하는 모든 데이터를 읽어가면서 조건에 맞으면 결과로 추출하고 조건에 맞지 않으면 버리는 방식
  • HIGH WATER MARK 는 테이블에 데이터가 쓰여졌던 블록 상의 최상위 위치로써 테이블 풀 스캔 시는 HWM 까지의 블록에 있는 모든 데이터를 읽어야 하기 때문에 시간이 오래 걸릴 수 있다.
  • 풀 테이블 스캔으로 읽은 블록은 재 사용성이 낮다고 보고 메모리 버퍼 캐시에서 금방 제거될 수 있도록 관리한다.
  • 옵티마이저가 풀 테이블 스캔을 선택하는 경우
    ◼ SQL 문에 조건이 존재하지 않는 경우
    ◼ SQL 문의 조건을 기준으로 사용 가능한 인덱스가 없는 경우
    ◼ 옵티마이저의 판단으로 풀 테이블 스캔이 유리하다고
    판단하는 경우
    ◼ 전체 테이블 스캔을 하도록 강제로 힌트를 지정한 경우

인덱스 스캔

  • 인덱스 스캔은 인덱스를 구성하는 칼럼의 값을 기반으로 데이터를 추출하는 액세스 기법
  • 인덱스 리프 블록은 인덱스를 구성하는 칼럼과 ROWID 로 구성
  • 인덱스의 리프 블록을 읽으면 인덱스 구성 칼럼의 값과 ROWID 를 알 수 있음
  • 즉 인덱스를 읽어서 대상 ROWID 를 찾으면 해당 ROWID 로 다시 테이블을 찾아 가야함
  • 하지만 SQL 문에서 필요로 하는 칼럼이 모두 인덱스 구성칼럼이라면 테이블을 찾아갈 필요 없음
  • 일반적으로 인덱스 스캔을 통해 데이터를 추출하면 해당 결과는 인덱스의 칼럼의 순서로 정렬된 상태로 반환됨

인덱스 스캔 유형

  • 인덱스 범위 스캔
    ◼ 인덱스를 이용하여 한건 이상의 데이터를 추출하는 방식
    ◼ 인덱스 스캔으로 특정 범위를 스캔하면서 대상 레코드를 하나하나 리턴하는 방식임
  • 인덱스 유일 스캔
    ◼ 인덱스를 사용하여 단 하나의 데이터를 추출하는 방식
    ◼ 유일인덱스는 중복 레코드를 허용하지 않음
    ◼ 유일인덱스는 반드시 '='조건으로 조회 해야 됨(그렇게 할 수 밖에 없음)
  • 인덱스 전체 스캔
    ◼ 인덱스를 처음부터 끝까지 전체를 읽으면서 조건에 맞는 데이터를 추출함
    ◼ 데이터를 추출 시 리프 블록에 있는 ROWID 로 테이블의 레코드를 찾아가서 조건에 부합하는지 판단하고
    ◼ 조건에 부합되면 해당 행을 리턴 함
  • 인덱스 스킵 스캔
    ◼ 인덱스 선두 컬럼이 조건절에 없어도 인덱스를 활용하는 스캔 방식이다.
    ◼ 조건절에 빠진 인덱스 선두 컬럼(성별)의 Distinct Value 의 개수가 적고, 후행 컬럼(연봉)의 Distinct Value 의 개수가 많을 때 유용
    ◼ Index Skip Scan 은 루트 또는 브랜치에서 읽은 컬럼 값 정보를 이용해 조건절에 부합하는 레코드를 포함할 가능성이 있는 리프 블록만 액세스 한다.
  • 인덱스 고속 전체 스캔
    ◼ Index Fast Full Scan 은 물리적으로 디스크에 저장된 순서대로 인덱스 리프 블록들을 Multi Block I/O 방식으로 읽어 들인다. 또한 병렬 인덱스 스캔도 가능하다.
  • 인덱스 역순 범위 스캔
    ◼ 인덱스 리프 블록은 Doubly Linked List 방식으로 저장되어 있음
    ◼ 즉 이 성질을 이용하여 인덱스를 역순으로(거꾸로) 읽을 수 있음
    ◼ 인덱스를 뒤에서부터 앞쪽으로 스캔하기 때문에 내림차순으로 정렬된 결과 집합을
    얻을 수 있다. (스캔 순서를 제외 하고는 Range Scan 과 동일함)

테이블 스캔 VS 인덱스 스캔

풀 테이블 스캔 인덱스 스캔
항상 이용가능 인덱스가 존재해야만 이용가능
한번에 여러 개의 block을 읽음 한번에 한 개의 블록만을 읽음
많은 데이터를 조회 시 성능 상 유리 극히 일부분의 데이터를 조회 시 유리
table random access 부하 없음 table random access에 의한 부하가 발생됨
읽었던 블록을 반복해서 읽는 경우 없음 읽었던 블록을 반복해서 읽는 비효율 발생(논리적인 블록 I/O의 개수도 많아짐)

조인 수행 원리

조인이란

  • 조인이란 두개 이상의테이블을 하나의 집합으로 만드는 연산이다.
  • SQL 문의 FROM 절에 두개 이상의 테이블 혹은 집합이 존재할 경우 조인이 수행된다.
  • 조인은 3 개 이상의 테이블을 조인한다고 하더라도 특정 시점에 2 개의 테이블 단위로 조인이 된다.
  • A, B, C 집합을 조인한다면 A, B 조인 후 해당 결과 집합을 C 와 조인 하는 방식이다.
  • 각각의 조인 단계에서는 서로 다른 조인 기법이 사용될 수 있다.
  • 즉 A, B 조인 시에는 NL 조인을 수행하고 A, B 조인의 결과와 C 를 조인 시에는 해시 조인이 수행될 수 있다.

NL 조인

NL 조인은 작은 집합이 Driving 되어야 하고, Inner 테이블의 인덱스 스캔이 매우 중요하다.

  • RANDOM 액세스 위주(인덱스구성이 완벽 해도 대량 데이터 조인 시 불리)
  • 한 레코드 씩 순차 진행(부분 범위 처리를 유도해야 효율적 수행)
  • DRIVING 테이블 처리 범위에 의해 전체 성능이 결정됨
  • 인덱스 유무, 인덱스 구성에 크게 영향 받음
  • 소량의 데이터를 처리하거나 부분범위처리가 가능한 OLTP 환경에 적합

소트 머지 조인

정렬 작업을 생략할 수 있는 인덱스가 존재하는 경우 사용

  • 실시간 인덱스 생성 : 양쪽 집합을 정렬한 다음에는 NL 조인과 같은 오퍼레이션
  • 인덱스 유무에 영향을 받지 않음 : 미리 정렬된 인덱스가 있으면 좀 더 빠르게 수행할 수는 있음
  • 양쪽 집합을 개별적으로 읽고 나서 조인 : 조인 컬럼에 인덱스가 없는 상황에서 두 테이블을 독립적으로 읽어 조인 대상 집합을 줄일 수 있을 때 아주 유리
  • 스캔(Scan) 위주의 액세스 방식 : 양쪽 소스 집합에서 정렬 대상 레코드를 찾는 작업은 인덱스를 이용 Random 액세스 방식으로 처리될 수 있음

해시 조인

작은 집합을 Build Input 으로 하고 큰집합을 probe input 으로 하는 것이 중요

  • 대량의 데이터 처리가 필요하고 쿼리 수행 시간이 오래 걸리는 대용량 테이블을 조인할 때(배치 프로그램, DW, OLAP 성 쿼리) 사용
  • NL 조인처럼 Random 액세스 부하 없음
  • 소트 머지 조인처럼 정렬 부하 없음
  • 해시 테이블을 생성하는 비용에 따라서 Build Input 이 (Hash Area 에 담을 수 있을 정도로
    충분히) 작을 때라야 효과적
profile
미친개발자를향해

0개의 댓글

관련 채용 정보