Contents

(1) 범위 스캔

  • 인덱스 : 대용량 테이블에서 필요한 데이터만 빠르고 효율적으로 엑세스할 목적으로 사용하는 오브젝트.
  • 범위 스캔
    • 인덱스는 키 컬럼 순으로 정렬돼 있기 때문에 특정 위치에서 스캔을 시작해, 검색 조건에 일치하지 않는 값는 만나는 순간 멈춘다.
    • 반면, 테이블은 처음부터 끝까지 모든 레코드를 읽어야 완전한 결과집합을 얻을 수 있다.

 

(2) 인덱스 기본 구조

  • B\*tree 인덱스 구조
  • 루트(Root)를 포함한 브랜치(Branch) 블록에 저장된 엔트리에는 하위 노드 블록을 찾아가기 위한 DBA(Data Block Address) 정보를 갖는다.
  • 리프(Leaf) 블록에는 인덱스 키 컬럼과 함께 해당 테이블 레코드를 찾아가기 위한 주소정보(rowid)를 갖는다.
  • 리프 블록은 항상 키 컬럼 순으로 정렬되어 있어 '범위스캔'이 가능하다.
  • 키 값이 같을 때는 rowid 순으로 정렬된다.
  • 오라클은 인덱스 구성 컬럼이 모두 null인 레코드는 저장하지 않는다.
  • 인덱스와 테이블 레코드 간에는 서로 1:1 대응 관계를 갖는다.(클러스터 인덱스는 1:M관계)
  • 브랜치에 저장된 레코드 개수는 바로 하위 레벨 블록 개수와 일치한다.
  • 테이블 레코드에서 값이 갱신되면 리프 노드 인덱스 키 값도 같이 갱신된다.
  • 반면, 리프 노드상의 엔트리 키 값이 갱신되더라도 브랜치 노드까지 값이 바뀌지는 않는다.

 

(3) 인덱스 탐색

  • 수평적 탐색 : 리프 블록을 인덱스 레코드 간 논리적 순서에 따라 좌에서 우, 또는 우에서 좌로 스캔.
  • 수직적 탐색 : 루트에서 리프 블록까지 아래로 진행. (수평적 탐색을 위한 시작 지점을 찾는 과정)

 

  • <그림 1-1 에서 'CLARK'을 찾는 과정>
  1. 루트 블록 스캔
    lmc는 KI보다 작은 값을 의미하고, KI는 KI보다 같거나 큰 값을 의미하기 때문에 왼쪽브랜치 블록으로 이동
  2. 찾아 간 브랜치블록을 스캔하면서 그 다음 찾아 갈 인덱스 블록을 탐색한다.
    'CLARK'이 'BER' 보다 크고 'FO'보다 작으므로 두번째 레코드가 가리키는 블록주소(18000A7)로 찾아간다.
  3. 도착한 리프블록에서 'CLARK'을 찾으면 수평적 탐색과정을 하고, 못 찾으면 인덱스 탐색을 마친다.
    ('CLARK'을 찾았으므로 수평적탐색을 진행한다.)
  4. 인덱스 리프 블록을 스캔하면서 값이 'CLARK'인지 확인한다.
  5. rowid(00000B1C.001E.0004)를 이용해 해당 레코드를 찾아간다.
  6. 4,5번 과정을 반복하다가 검색조건을 만족하지 못하는 레코드를 만나는 순간 멈춘다,

&nbsp;

브랜치 블록 스캔

  • 위의 과정 중, 1번과 2번에서 브랜치 블록을 스캔할 때는 뒤에서부터 스캔하는 방식이 유리하다.
  • 뒤에서부터 스캔할 때는 'CLARK' 보다 작은 첫번째 레코드('BER')를 만나는 순간 바로 하위 블록으로 내려간다.
  • 하지만, 앞에서부터 스캔 할 때는 'CLARK' 보다 크거나 같은 첫 번째 레코드('FO')를 만나는 순간 한칸 뒤로 이동해서 하위 블록으로 내려간다.
  • * But, 실제로 뒤쪽부터 스캔하는지는 알 수가 없다.(가정)

  1. 1번 루트 블록에서 lmc가 가리키는 2번 브랜치 노드로 따라 내려 감 (정확히 같은 값이면 왼쪽 브랜치로 이동)
    만약 같은 값인 3을 따라 3번 브랜치로 내려가면 2번 브랜치 끝에 놓인 3을 놓치게 되기 대문에 2번으로 감
  2. 2번 브랜치에서 맨 뒤쪽 3부터 거꾸로 스캔하다가 2를 만나는 순간 리프 블록으로 내려감
  3. 거기서 키 값이 3인 첫 번째 레코드를 찾아 오른쪽으로 리프 블록을 스캔해 나가면 조회 조건을 만족하는 값을 모두 찾을 수 있음

&nbsp;

결합 인덱스 구조와 탐색

  • emp 테이블에 deptno + sal 컬럼 순으로 생성한 결합 인덱스
  • deptno=20 and sal >=2000' 조건으로 쿼리할 경우, deptno가 20인 첫 번째 레코드가 아닌 두번째 리프 블록의 두번째 레코드부터 스캔이 시작
    수직적 탐색 과정에서 deptno뿐만 아니라 sal값에 대한 필터링도 같이 이루어 지기 때문
    마지막 블록 첫 번째 레코드에서 스캔을 멈추게 될 것

&nbsp;

(4) ROWID 포맷

  • 테이블 레코드의 물리적 위치정보를 포함한다.(데이터파일 번호, 블록 번호, 로우 번호)
  • 테이블 자체에 저장되는 것이 아니라 인덱스에 저장된다.
  • pseudo 컬럼이다. (필요하면 rowid를 출력해 볼 수 있지만 그 값이 실제로 테이블에 저장되어 있지는 않다.)
  • 인덱스의 저장되는 rowid의 공간
    • 오라클 7 까지 : 6 바이트(파일번호, 블록번호, 로우번호)
    • 오라클 8 이후
      \- 6 바이트 : 파티션되지 않은 일반 테이블에 생성한 인덱스
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;파티션된 테이블에 생성한 로컬 파티션(Local Partitioned) 인덱스
      \- 10바이트 : 파티션 테이블에 생성한 글로벌 파티션(Global Partitioned) 인덱스
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;파티션 테이블에 생성한 비파티션(Non Partitioned) 인덱스

&nbsp;

  • <제한 rowid 포맷>
  • 오라클 7버전까지 사용
  • 3개 구성요소로 이루어짐
    • 데이터파일 번호(4자리) : 로우가 속한 데이터파일, 데이터베이스 내에서 유일한 값
    • 블록 번호(8자리) : 해당 로우가 저장된 데이터 블록 번호
    • 로우 번호(4자리) : 블록 내에서 각 로우에 붙여진 일련번호
      &nbsp;
  • <확장 rowid 포맷>
  • 오라클 8버전부터 사용
  • 4개 구성요소로 이루어짐
    • 데이터 오브젝트 번호(6자리) : 데이터베이스 세그먼트를 식별하기 위해 사용되는 데이터 오브젝트 번호
    • 데이터파일 번호(3자리)
    • 블록 번호(6자리)
    • 로우 번호(3자리)
  • 순서 : (데이터오브젝트)(데이터파일)(블록)(로우)
  • rowid를 자릿수만큼 잘라서 디코딩(Decoding)하면 각 구성요소에 대한 정보 출력 (혹은 dbms_rowid패키지 사용)