2009년 9월 3일 목요일

ORACLE_014. Understanding Access Path : Index Table Scans

Understanding Access Path : Index Table Scans                                  

INDEX SCAN

 이 방법은 구문에서 사용하는 컬럼의 인덱스를 이용하여 행을 뽑아오는 방법입니다. 인덱스 스켄은 인덱스의 하나 혹은 그 이상의 컬럼값에 기초하여 데이터를 추출합니다. 인덱스 스켄을 수행하면 구문에 사용되는 컬럼중 인덱스가 있는 컬럼이 있는지를 우선적으로 찾습니다. 인덱스가 존재하면 인덱스가 있는 컬럼 값을 인덱스에서 바로 읽어옵니다.

 인덱스는 인덱싱 된 값 뿐만 아니라 행의 Rowid도 가지고 있습니다. 따라서 인덱스된 컬럼 외에 다른 컬럼값 역시 한번에 가져올 수 있습니다.

INDEX UNIQUE SCAN
 UNIQUE 나 PRIMARY KEY 로 제약조건이 걸려있는 컬럼에 대하여 접근할때 UNIQUE SCAN을 사용합니다.

 When the optimizer Uses Index Unique Scans
 이 접근경로는 동등한 조건식에 Unique Index 가 모든 컬럼에 정의되어 있을때 사용합니다.

 Index Unique Scan Hints
 일반적으로, Unique Scan 수행시 따로 Hint절을 달 필요는 없습니다. 힌트절 INDEX(alias index_name)는 인덱스를 사용함을 결정합니다만 접근 경로까지 결정하지는 않습니다.

INDEX RANGE SCAN
 Index Range Scan 은 일반적으로 선택된 데이터에 접근하는 가장 평범한 방법입니다. 결과는 인덱스 컬럼의 오름차순으로 정렬되어 반환됩니다. 동등한 값의 여러개의 행은 rowid에 의해 오름차순으로 정렬됩니다.

 데이터가 반드시 정렬되어야 한다면 ORDER BY 구문을 이용하고 인덱스의 정렬에  너무 의지하지 마십시요. 인덱스가 ORDER BY 문에 적용될 수 있게 정렬된 상태면 옵티마이저는 인덱스 정렬을 사용합니다.

 EXAMPLE_Index Range Scan                           
 SELECT order_status, order_id
  FROM   orders
 WHERE order_date = :b1;
 

 
 상기 쿼리는 분명 선택적인 쿼리 입니다. 행을 가져오기 위해 컬럼의 인덱스를 사용하는 것을 확인 할 수 있습니다. 반환된 데이터는 order_date 컬럼의 rowid 에 의해 오름차순으로 정렬됩니다. 이는 order_date 의 인덱스 컬럼이 여기서 선택된 행들과 같기때문에 데이터는 rowid로 정렬됩니다.

 When the Optimizer Uses Index Range Scans
 옵티마이저는 다음과 같은, 쿼리의 주가 되는 조건에 인덱스가 있는 컬림이 하나 혹은 그 이상의 컬럼이 있으면 옵티마이저는 Index Range Scan을 수행합니다.

 - col1 = :b1
 - col1 < :b1
 - col1 > :b1
 - 위 조건들이 인덱스에서 주가 되는 컬럼이고 이러한 조건들의 조합

 Range Scans는 unique 혹은 nonunique 인덱스를 사용합니다. Range Scan은 인덱스 컬럼이 ORDER BY/GROUP BY 와 구성되어 있으면 정렬을 수행하지 않습니다.

 Index Range Scan Hint
 옵티마이저가 풀테이블 스켄이나 다른 인덱스를 사용하려 할때 hint절을 사용할 수 있습니다. 힌트절 HINT(table_alias index_name)은 사용할 인덱스를 정할 수 있습니다. order_id 라는 컬럼이 비대칭(skew) 분포를 이루고 있다고 가정합시다. 컬럼은 히스토그램을 가지고 있고,  옵티마이저는 그 컬럼의 분포도를 알고 있습니다. 하지만 바인드 변수(Bind Variable) 옵티마이저는 값을 알 수 없거니와 테이블 스켄을 수행할 수 있습니다. 두가지 옵션이 있습니다.

 - nonsharing SQL 동안 문제를 야기시킬 수 있는 바인드 변수를 제거하고 명확한 값을 넣으세요
 - 힌트절을 사용합니다.

 EXAMPLE_Before Using Index INDEX hint                
 SELECT l.line_item_id, order_id, l.unit_price * l.quantity
    FROM order_items
 WHERE l.order_id = :b1
 

 

 EXAMPLE_Using Bind Variable and INDEX hint                                  
 SELECT /*+ INDEX(l item_order_ix) */ l.line_item_id, order_id, l. unit_price * l.quantity
   FROM order_items l
 WHERE l.order_id = :b1


INDEX RANGE SCANS DESCENDING
 Index range scan descending 은 내림차순으로 정렬되어 데이터가 반환되는 것을 제외하고는 Index range scan과 같습니다. 기본적으로 인덱스는 오름차순으로 저장됩니다. Index range scan descending은 가장 최근의 데이터를 얻거나 특정 값보다 적은 값을 찾을때 사용합니다.

 EXAMPLE_Index Range Scan Descending Using Two-Column Unique Index                  
 SELECT line_item_id, order_id
  FROM order_items

 WHERE order_id < :b1
 ORDER BY order_id DESC;
 

 

 데이타에서 선택된 행은 order_id, line_item, rowid 에 의해 내림차순 정렬이 됩니다.

 When the Optimizer Uses Index Range Scans Descending
 order by descending 단서가 인덱스를 만족하면 옵티마이저는 index range scan descending 을 수행합니다.

 Index Range Scan Descending Hints
 힌트절 INDEX_DESC(table_alias index_name) 는 이 접근경로를 사용하는데 사용됩니다.

INDEX SKIP SCAN
 Index Skip Scan은 nonprefix 컬럼을 읽는데 인덱스의 성능을 향상시킵니다. 자주, 인덱스 블럭을 읽는것은 테이블 블럭을 읽는것 보다 빠릅니다.

 Skip Scan은 여러개의 컬럼을 가진 인덱스를 논리적으로 작게 서브인덱스로 나눕니다.  Skip Scan에서 다열 인덱스의 이니셜 컬럼은 쿼리에서 정의되지 않습니다. 즉 무시(skip) 합니다.

 수개의 논리적 서브인덱스는 이니셜 컬럼에서 중복된 값의 갯수에 의해 정의됩니다. Skip Scan은 복잡한 인덱스의 리딩컬럼에 중복되는 값이 거의 없거나 리딩컬럼이 아닌 컬럼에 많은 수의 중복된 값이 있을때 효과적입니다.

 EXAMPLE_Index Skip Scan
 Employee(sex, employee_id, address) 테이블이 다열 인덱스 (sex, employee_id) 를 가지고 있다고 가정하도록 하겠습니다. 이 인덱스는 두개의 논리 서브인덱스로 나뉩니다. 하나는 M 하나는 F.

 이 예제에서 다음의 인덱스 값을 가지고 있다고 가정합니다.
 ('F', 98)
 ('F',100)
 ('F',102)
 ('F',104)
 ('F',101)
 ('M',101)
 ('M',103)

 ('M',105)

 인덱스는 다음과 같은 두 논리 서브인덱스로 나뉩니다.

  - 첫번째 서브 인덱스는 키값을 'F'를 갖습니다.
  - 두번째 서브 인덱스는 키값을 'M'을 갖습니다.

 

 다음과 같은 쿼리에서 sex 컬럼은 무시됩니다.
 SELECT * FROM employees WHERE employee_id = 101;

 완전한 Index 스켄은 일어나지 않습니다. 하지만 'F'값을 가진 서브 인덱스가 우선 수행됩니다. 다음 'M'값을 가진 서브 인덱스가 수행됩니다.

FULL INDEX SCANS
 만약 술부(predicate)가 인덱스가 있는 하나의 컬럼만을 참조하면 Full Scan 이 일어납니다. 술부는 index driver가 필요치 않습니다. 또한 술부가 존재하지 않거나 다음 두가지의 경우 full scan을 수행합니다.

 - 쿼리에서 사용하는 모든 컬럼에 인덱스가 존재할 경우
 - 최소 하나의 인덱스 컬럼이 Null 이 아닐 경우

 Full Scan은 정렬 과정을 생략할 수 있는데 데이터가 index key에 의해 정렬되어 있기 때문입니다.

FAST FULL INDEX SCANS
 Fast full scan 은 인덱스에 쿼리에 필요한 모든 컬럼에 대한 정보를 가지고 있을때와 최소 하나의 컬럼에 NOT NULL 제약조건을 가지고 있을때 full table scan을 할지 말지를 결정해야 합니다. Fast full scan 은 테이블에 접근할 필요 없이 인덱스에서 데이터에 접근합니다. 데이터는 인덱스 키에 의해 정렬되어 있지 않기 때문에 정렬 과정을 피할 수 없습니다. Full index scan과는 다르게 다중 블럭을 읽어들여 모든 인덱스를 읽어들입니다.

 Fast full scan은 오직 CBO에서만 작동합니다. OPTIMIZER_FEATURES_ENABLE 초기화 파라메터나 INDEX_FFS 힌트를 이용하여 정의할 수 있습니다. Fast full index scan은 비트맵 인덱스(bitmap index)에 대항하여 수행할 수 없습니다.

 Fast full index scan은 일반 full index scan 보다 멀티블락 I/O를 사용할때 보다 더 빠르며 테이블 스켄처럼 병렬처리가 가능합니다.

Fast Full Index Scan Hints
 Fast Full Index Scan은 특별한 인덱스 힌트를 가지고 있습니다. INDEX_FFS. 정규 INDEX 힌트와 같은 인수와 표현식을 사용합니다.
 
Fast Full Index Scan Restrictions
 Fast full index scan은 다음과 같은 제약이 있습니다.
 - 최소 한개의 컬럼이 NOT NULL 제약조건을 가지고 있어야 합니다.
 - 병렬로 Fast full index scan을 사용하기 위해 인덱스에 parallel 단서를 달아야 합니다.
 - 인덱스를 반드시 Anlalyze 해야합니다. 그렇지 않으면 옵티마이저는 FFS를 수행하지 않습니다.

INDEX JOINS
 Index Join은 쿼리에서 참조하는 테이블의 모든 컬럼을 가지고 있는 몇몇 인덱스의 Hash Join 입니다. Index join은 테이블에 접근할 필요가 없는데, 이는 index에서 필요한 데이터를 모두 얻을 수 있기 때문입니다. 정렬 과정을 거쳐야 하며 오직 CBO에서만 수행이 가능합니다.

Index Join Hints
 OPTIMIZER_FEATURES_ENABLE 초기화 파라메터와 INDEX_JOIN힌트절을 사용할 수 있습니다.

BITMAP JOINS
 Bitmap join이란 키값을 위해 비트맵을 사용하고 rowid 에 각각의 비트를 변환하여 위치시킵니다. 비트맵은 where 단서에서 AND나 OR 같은 Boolean Operation 같은 몇몇 조건에서 인덱스를 합치는데 매우 효율적입니다.

 Bitmap Access 는 CBO에서만 가능합니다.
 *Oracle 9i Enterprise Edition 이상의 버전에서만 Bitmap Index 혹은 Bitmap join index 사용 가능

CLUSTER SCANS
 Cluster scan은 index cluster로 저장된 테이블에서 같은 클러스터 키 값을 갖는 모든 행을 얻는데 사용합니다. Index cluster 에서 같은 클러스터 키 값을 가지고 있는 모든 행은 같은 데이터 블럭안에 저장됩니다. Cluster scan 을 수행하기 위해서는 Cluster index 스케닝을 통해 얻은 한개의 행의 rowid를 획득합니다. 그후 이 rowid를 가지고 행들을 가져다 놓습니다.

HASH SCANS
 해시값을 기초로한 해쉬 클러스터에 있는 행을 가져가기 위해 사용됩니다. 해쉬 클러스터에서 해시 값이 같은 모든 데이터는 같은 데이터 블럭에 위치합니다. Hash scan을 수행하면 오라클은 해시값을  얻고, 얻은 해시값을 가지고 있는 행을 포함하고 있는 데이터 블럭을 스켄합니다.

SAMPLE TABLE SCANS
 무작위로 테이블에서 샘플 데이터를 수집합니다. FROM 단서에 SAMPLE 혹은 SAMPLE BLOCK 단서가 존재하면 이 접근방법을 사용합니다. 행단위 샘플링(SAMPLE clause)을 통한 Sample table scan을 수행하면 테이블의 일정 %만큼의 행을 읽습니다. 블럭 단위의 샘플링을 수행하면 (SAMPLE BLOCK clause), 특정 %의 테이블 블럭을 읽습니다.

 쿼리에 Join 혹은 원격 테이블이 포함되어 있따면 Sample table scan을 수행하지 않습니다.

 EXAMPLE_Sample Table Scan                                                       
 SELECT * FROM employees SAMPLE BLOCK (1);


Hints for access pat(영문)


 

FIN
REF) Oracle Documents (Server .920)/a96533 "Introduction to the Optimizer"

        Oracle Documents (Server .920)/a96533 "Optimizer Hints"

댓글 없음:

댓글 쓰기