아래 CREATE INDEX 옵션들은 2008 기준입니다. 2008 이전 버전과는 사용법의 차이가 있으니 주의하세요.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<relational_index_option> ::=
{
    PAD_INDEX = { ON | OFF }
    | FILLFACTOR = fillfactor
    | SORT_IN_TEMPDB = { ON | OFF }
    | IGNORE_DUP_KEY = { ON | OFF }
    | STATISTICS_NORECOMPUTE = { ON | OFF }
    | DROP_EXISTING = { ON | OFF }
    | ONLINE = { ON | OFF }
    | ALLOW_ROW_LOCKS = { ON | OFF }
    | ALLOW_PAGE_LOCKS = { ON | OFF }
    | MAXDOP = max_degree_of_parallelism
    | DATA_COMPRESSION = { NONE | ROW | PAGE}
    [ ON PARTITIONS ( { <partition_number_expression> | <range> }
    [ , ...n ] ) ]
}

cs

1.     PAD_INDEX & FILLFACTOR

-  PAD_INDEX는 FILLFACTOR에서 지정한 인덱스의 채우기 비율을 사용할 것인지 여부를 결정합니다.

-  FILLFACTOR는 1과 100 사이를 사용합니다.

 

 혹 어떤 분들은 FILLFACTOR를 얼마나 사용해야 하는지 물어보시는 분들이 많은데요, 이것은 분석 여부에 따라 달라질 수 있습니다. 데이터 변경이 자주 일어난다면 숫자를 낮게 주고, 그렇지 않다면 높게 주어도 될 것입니다.


 참고로, Oracle의 PCT_FREE와는 정 반대의 개념입니다. PCT_FREE 는 얼마나 남겨둘 지를 결정하고, FILLFACTOR는 얼마나 채워둘 것인지를 결정합니다.

2.     SORT_IN_TEMPDB

- 간단히 말해서 인덱스 생성을 tempdb에서 하고 그 최종본만 실제 인덱스에 반영하는 것입니다.

- 장점은 인덱스 생성속도가 적게 걸린다는 것이고, 단점은 tempdb 가 커진다는 것입니다.

3.     IGNORE_DUP_KEY

- UNIQUE INDEX를 생성할 때 키 중복(UNIQUE)에 대한 검사 여부를 지정합니다.

- 사실 이 기능을 ON으로 하면 UNIQUE하지 않은 행만 실패하게 되므로… 사용하시지 않는 것을 권장합니다.

4.     STATICS_NORECOMPUTE

- 통계를 다시 생성할 지 여부를 결정합니다. 기본값이 OFF인데요. 

굳이 ON으로 해서 통계를 생성하지 않을 필요는 거의 없습니다.

5.     DROP_EXISTING

- 인덱스를 전체적으로 삭제하고 다시 작성할 지 여부를 결정합니다. 기본값은 OFF입니다만,  

인덱스 명명 규칙이 있을 경우 이미 기존 명칭이 있을 것이므로, 

삭제하고 다시 생성하기 위애 ON 으로 주어야 합니다.

6.     ONLINE

- 단순하게 바라보면, 인덱스 생성 중에 테이블을 사용할 수 있는지 여부를 지정하는 것이지만, 

다시 말하자면, 인덱스를 작성하면서 TABLE LOCK을 걸지 않도록 합니다.

- SQL 2005부터 지원되면서 DBA들에겐 큰 힘을 주었던 옵션이며 기본값이 OFF이므로 사용하려면 ON 으로 

별도 지정해 주어야 합니다.

7.     ALLOW_ROW_LOCKS & ALLOW_PAGE_LOCKS

- 행이나 페이지 LOCK 여부를 결정하며 기본값이 ON입니다. 많이 사용하는 옵션은 아닙니다.

8.     MAXDOP

- 테이블의 크기가 클 경우 부하를 줄이기 위해 CPU 병렬작업을 수행할 지 결정하며 

CPU 개수 64라는 값까지 줄 수 있습니다.

- 참고로 Standard Edition은 지원하지 않습니다. \

엄밀히 따지면 평가판을 빼면 Enterprise Edition만 된다고 하는 편이 낫겠네요. ㅋ.

9.     DATA_COMPRESSION / ON PARTITIONS

- DATA_COMPRESSION은 테이블을 압축하는 것과 같이 데이터 압축 여부를 선택합니다.

- ON PARTITIONS 옵션은 DATA_COMPRESSION 옵션을 사용할 때에만 적용됩니다.

- DATA_COMPRESSION 옵션은 NONE / ROW / PAGE 등의 옵션이 있습니다.



출처 : http://www.sqler.com/322711#1

'SQL > SQL 튜닝' 카테고리의 다른 글

쿼리변환  (0) 2017.10.26
클러스터링 팩터  (0) 2017.10.26
옵티마이저 이해하기 - 2  (0) 2017.10.26
MSSQL LOOKUP  (0) 2017.10.24
클러스터인덱스와 넌클러스터인덱스  (0) 2017.10.24

쿼리변환

비용기반 옵티마이저의 서브엔진으로서 Query Transformer, Estimator, Plan Generator가 있다고 설명했는데, 이 중 Query Transformer가 그런 역할을 담당한다.


서브쿼리 Unnesting

중첩된 서브쿼리를 풀어내는 것

뷰 Merging 

인라인뷰에서 쿼리를 풀어내는 것

조건절 Pushing

옵티마이저가 뷰를 처리함에 있어 1차적으로 뷰 Merging을 고려하지만, 조건절(Predicate) Pushing을 시도할 수도 있다. 이는 뷰를 참조하는 쿼리 블록의 조건절을 뷰 쿼리 블록 안으로 밀어 넣는 기능을 말한다. 조건절이 가능한 빨리 처리되도록 뷰 안으로 밀어 넣는다면, 뷰 안에서의 처리 일량을 최소화하게 됨은 물론 리턴되는 결과 건수를 줄임으로써 다음 단계에서 처리해야 할 일량을 줄일 수 있다. 조건절 Pushing과 관련해 DBMS가 사용하는 기술로는 다음 3가지가 있다.

조건절 Pushdown

group by절을 포함한 아래 뷰를 처리할 때, 쿼리 블록 밖에 있는 조건절을 쿼리 블록 안쪽에 밀어 넣을 수 있다면 group by 해야 할 데이터량을 줄일 수 있다. 인덱스 상황에 따라서는 더 효과적인 인덱스 선택이 가능해지기도 한다.

조건절 Pullup

조건절을 쿼리 블록 안으로 밀어 넣을 뿐만 아니라 안쪽에 있는 조건들을 바깥 쪽으로 끄집어 내기도 하는데, 이를 ‘조건절(Predicate) Pullup’이라고 한다. 그리고 그것을 다시 다른 쿼리 블록에 Pushdown 하는 데 사용한다. 아래 실행계획을 보자.

조인조건 Pushdown

말 그대로 조인 조건절을 뷰 쿼리 블록 안으로 밀어 넣는 것으로서, NL Join 수행 중에 드라이빙 테이블에서 읽은 조인 칼럼 값을 Inner 쪽(=right side) 뷰 쿼리 블록 내에서 참조할 수 있도록 하는 기능이다. 아래 실행계획에서 group by절을 포함한 뷰를 액세스하는 단계에서 ‘view pushed predicate’ 오퍼레이션(id=3)이 나타났다. 그 아래 쪽에 emp_deptno_idx 인덱스가 사용된 것을 볼 수 있는데, 이는 dept 테이블로부터 넘겨진 deptno에 대해서만 group by를 수행함을 의미한다.

조건절이행

「(A = B)이고 (B = C)이면 (A = C)이다」 라는 추론을 통해 새로운 조건절을 내부적으로 생성해 주는 쿼리변환이다. 「(A > B)이고 (B > C)이면 (A > C)이다」와 같은 추론도 가능하다. 예를 들어, A 테이블에 사용된 필터 조건이 조인 조건절을 타고 반대편 B 테이블에 대한 필터 조건으로 이행(移行)될 수 있다. 한 테이블 내에서도 두 칼럼간 관계정보(예를 들어, col1 >= col2)를 이용해 조건절이 이행된다.


불필요한조인제거

1:M 관계인 두 테이블을 조인하는 쿼리문에서 조인문을 제외한 어디에서도 1쪽 테이블을 참조하지 않는다면, 쿼리 수행 시 1쪽 테이블은 읽지 않아도 된다. 결과집합에 영향을 미치지 않기 때문이다. 옵티마이저는 이 특성을 이용해 M쪽 테이블만 읽도록 쿼리를 변환하는데, 이를 ‘조인 제거(Join Elimination)’ 또는 ‘테이블 제거(Table Elimination)’라고 한다.

OR조건은 Union으로 변환

아래 쿼리가 그대로 수행된다면 OR 조건이므로 Full Table Scan으로 처리될 것이다. (아니면, job 칼럼 인덱스와 deptno 칼럼 인덱스를 결합하고 비트맵 연산을 통해 테이블 액세스 대상을 필터링하는 Index Combine이 작동할 수도 있다.)


select * 

 from emp 

where job = 'CLERK'

     or deptno = 20

만약 job과 deptno에 각각 생성된 인덱스를 사용하고 싶다면 아래와 같이 union all 형태로 바꿔주면 된다.

select * from emp where job = 'CLERK' 

union all 

select * from emp where deptno = 20 

                           and LNNVL(job='CLERK')

사용자가 쿼리를 직접 바꿔주지 않아도 옵티마이저가 이런 작업을 대신해 주는 경우가 있는데, 이를 ‘OR-Expansion’이라고 한다. 

힌트 USE_CONCAT : OR-EXPANSION을 유도

       NO_EXPAND : OR-EXPANSION을 막음


기타 쿼리변환

집합연산을 조인으로 변환
조인칼럼에 IS NOT NULL조건 추가
필터조건추가
조건절비교순서



출처 : http://www.dbguide.net/db.db?cmd=view&boardUid=148219&boardConfigUid=9&categoryUid=216&boardIdx=139&boardStep=1

'SQL > SQL 튜닝' 카테고리의 다른 글

mssql 2008 인덱스옵션  (0) 2017.10.27
클러스터링 팩터  (0) 2017.10.26
옵티마이저 이해하기 - 2  (0) 2017.10.26
MSSQL LOOKUP  (0) 2017.10.24
클러스터인덱스와 넌클러스터인덱스  (0) 2017.10.24

클러스터링 팩터

클러스터링 팩터는 우리말로 하자면 군집성 계수 즉 데이터가 모여있는 정도라고 번역할수 있다. 

인덱스 로우의 순서와 데이터 로우의 순서가 얼마나 비슷한 순서로 저장되어 있느냐의 정도를 나타낸다


B-Tree 인덱스를 사용한 Range Scan 비용 계산식 의 중요한 요소이며, 비용계산 결과에 오차를 일으키는 가장 큰 원인이 될 수 있다. 

클러스터링 팩터는 데이터가 테이블 전체에 무작위로 분산된 정도를 나타내는 하나의 숫자이다.

(테이블 내 데이터의 흩어짐(Scatter)을 표현할 수 있는 숫자를 만든 발상은 매우 훌륭하다.)


인덱스 클러스터링 팩터가 좋다라고 한다면 인덱스의 정렬순서와 테이블의 정렬순서가 비슷하여 디스크 I/O비용이 적게 드는것을 말한다. 즉 우리가 액세스하고자 하는 데이터가 모여 있는 것을 의미하게 된다.


Index를 거쳐서 데이터를 찾을 때, 접근하게 되는 블록의 개수가 적을수록 클러스터링 팩터가 좋은 것이라 할 수 있고, 접근하게 되는 블록의 개수가 많을수록 클러스터링 팩터가 나쁜 것이라고 할 수 있다. 


클러스터링팩터는 인덱스 스캔시의 비용(cost)에 영향을 미치며, dba_indexes, all_indexes, user_indexes의 인덱스뷰의 클러스터링 팩터라는 컬럼을 통해 확인할수 있다.


참고 : http://mypledge.tistory.com/9



출처 :

http://up730.tistory.com/entry/%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%A7%81-%ED%8C%A9%ED%84%B0%EB%9E%80

http://wiki.gurubee.net/pages/viewpage.action?pageId=3080204


http://whale.oceanmate.co.kr/3

'SQL > SQL 튜닝' 카테고리의 다른 글

mssql 2008 인덱스옵션  (0) 2017.10.27
쿼리변환  (0) 2017.10.26
옵티마이저 이해하기 - 2  (0) 2017.10.26
MSSQL LOOKUP  (0) 2017.10.24
클러스터인덱스와 넌클러스터인덱스  (0) 2017.10.24

옵티마이저

SQL을 가장 빠르고 효율적으로 수행할 최적의 처리경로를 생성해주는 DBMS의 내부의 핵심엔진

사용자가 SQL로 결과집합을 요구하면 이를 생성하는데 필요한 처리경로는 옵티마이저가 자동으로 생성해준다.


1. 사용자가 던진 쿼리수행을 위해, 후보군이 될만한 실행계획을 찾는다.

2. 데이터 딕셔너리에 미리 수집해 놓은 오브젝트 통계 및 시스템 통계정보를 이용해 각 실행 계획의 예상 비용을 산정한다.

3. 각 실행계획을 비교해서 최저비용을 갖는 실행계획을 선택한다.


옵티마이저의 종류

1. 규칙기반 옵티마이저(Rule- Based Optimizer, RBO) - 액세스 경로별 우선순위로서, 인덱스 구조, 연산자, 조건절형태가 순위를 결정짓는 요인이다.

2. 비용기반 옵티마이저(Cost-Based Optimizer, CBO) - 비용기반으로 최적화를 수행한다.


최적화목표

1. 전체 처리속도 최적화 - 시스템리소스(I/O, CPU, 메모리 등)를 가장 적게 사용하는 실행계획을 선택한다.

2. 최초 응답속도 최적화 - 일부만 읽다락 멈추는 것을 전제로, 가장빠른 속도를 낼 수 있는 실행계획을 선택한다.

옵티마이저에 영향을 미치는 요소

  • SQL과 연산자형태
옵티마이징 팩터인덱스, IOT, 클러스터링, 파티셔닝, MV등을 어떻게 구성했는지에 따라 달라진다.
  • DBMS제약
PK, FK, CHECK, NOT NULL등의 제약조건은 쿼리성능을 최적화하는데 중요한 정보 제공
  • 옵티마이저 힌트
  • 통계정보
CBO의 모든 판단 기준은 통계정보에서 나온다.
  • 옵티마이저 관련 파라미터의 추가 또는 변경
  • DBMS버전과 종류


옵티마이저의 한계

현재로선 해결하기 어려운 문제나, 통계정보 수집량과 최적화를 위해 허락된 시간때문에 옵티마이저의 한계가 드러남

  • 옵티마이징 팩터의 부족
  • 통계정보의 부정확성
  • 바인드 변수 사용시 균등분포 가정
조건절에 바인드 변수를 사용하면 옵티마이저가 균등분포를 가정하고 비용을 계산한다.
  • 비현실적인 가정 
  • 규칙에 의존하는 CBO
부분적으로는 규칙에 의존한다.
  • 하드웨어 성능옵티마이저는 기본적으로 옵티마이저 개발팀이 사용한 하드웨어 사양에 맞춰져있다.

통계정보를 이용한 비용계산 원리

옵티마이저가 참조하는 통계정보의 종류
sql가이드

데이터 딕셔너리에 미리 수집해 둔 통계정보가 옵티마이저에 의해 구체적으로 어떻게 활용될까.

선택도 

전체 대상 레코드 중에서 특정 조건에 의해 선택될 것으로 예상되는 레코드 비율을 말한다. 선택도를 가지고, 카디털리티를 구하고, 다시 비용을 구해 인덱스 사용여부, 조인 순서와 방법을 결정한다.

선택도 → 카디널리티 → 비용 → 액세스 방식, 조인 순서, 조인 방법 등 결정 히스토그램이 있으면 그것으로 선택도를 산정하며, 단일 칼럼에 대해서는 비교적 정확한 값을 구한다. 히스토그램이 없거나, 있더라도 조건절에 바인드 변수를 사용하면 옵티마이저는 데이터 분포가 균일하다고 가정한 상태에서 선택도를 구한다. 히스토그램 없이 등치(=) 조건에 대한 선택도를 구하는 공식은 다음과 같다.

sql가이드

카디널러티 

특정액세스 단계를 거치고 난 후 출력될 것으로 예상되는 결과 건수

행의 수 * 선택도


히스토그램 - 미리 저장된 히스토그램 정보가 있으면, 옵티마이저는 그것을 사용해 더 정확하게 카디널리티를 구할 수 있다. 분포가 균일하지 않은 컬럼은 히스토그램으로 더 정확한 카디널리티를 산출할 수있다.


히스토그램 생성은 컬럼 통계수집시 버킷을 2개 이상으로 지정한다.

dba_tab_columns.histogram설명
FREQUENCY값별로 빈도수를 저장하는 도수분포 히스토그램 (값의 수 = 버킷 수)
HEIGHT-BALANCED버킷의 높이가 동일한 높이균형 히스토그램 (값의 수 > 버킷 수)
NONE히스토그램 없음

도수분포 히스토그램

값별로 빈도수를 저장하는 히스토그램

dba_histograms


컬럼의미
endpoint_value버킷에 할당된 컬럼 값
endpoint_numberendpoint_value 정렬 기준 누적 수량


높이 균형 히스토그램

컬럼이 가진 값의 수가 아주 많아 각각 하나의 버킷을 할당하기 어려울때 사용된다.

dba_histograms
컬럼의미
endpoint_number버킷 번호
endpoint_value버킷이 담당하는 가장 큰 값


비용

쿼리를  수행하는데 소요되는 일량, 시간

I/O비용모델

예상되는 I/O요청 횟수만큼 쿼리 수행 비용으로 간주해 실행계획을 평가


인덱스를 경유한 테이블 액세스비용

- I/O 비용 모델에서의 비용은 디스크 I/O Call 횟수(논리적/물리적으로 읽은 블록 개수가 아닌 I/O Call 횟수)를 의미한다. 그리고 인덱스를 경유한 테이블 액세스 시에는 Single Block I/O 방식이 사용된다. 이는 디스크에서 한 블록을 읽을 때마다 한 번의 I/O Call을 일으키는 방식이므로 읽게 될 물리적 블록 개수가 I/O Call 횟수와 일치한다. 따라서 인덱스를 이용한 테이블 액세스 비용은 아래와 같은 공식으로 구할 수 있다. 


비용 = blevel                                                 -- 인덱스 수직적 탐색 비용 

         + (리프 블록 수 × 유효 인덱스 선택도)        -- 인덱스 수평적 탐색 비용

         + (클러스터링 팩터 × 유효 테이블 선택도)   -- 테이블 Random 액세스 비용 

sql가이드


Full Scan에 의한 테이블 액세스비용

Full Scan에 대해서는, 테이블 전체를 순차적으로 읽어 들이는 과정에서 발생하는 I/O Call 횟수로 비용을 계산한다. Full Scan할 때는 한 번의 I/O Call로써 여러 블록을 읽어 들이는 Multiblock I/O 방식을 사용하므로 총 블록 수를 Multiblock I/O 단위로 나눈 만큼 I/O Call이 발생한다. 예를 들어, 100블록을 8개씩 나누어 읽는다면 13번의 I/O Call이 발생하고, I/O Call 횟수로써 Full Scan 비용을 추정한다. 따라서 Multiblock I/O 단위가 증가할수록 I/O Call 횟수가 줄고 예상비용도 줄게 된다.



CPU비용모델 - I/O + 시간











출처 : http://www.dbguide.net/db.db?cmd=view&boardUid=148218&boardConfigUid=9&categoryUid=216&boardIdx=139&boardStep=1

http://wiki.gurubee.net/pages/viewpage.action?pageId=29065610

'SQL > SQL 튜닝' 카테고리의 다른 글

쿼리변환  (0) 2017.10.26
클러스터링 팩터  (0) 2017.10.26
MSSQL LOOKUP  (0) 2017.10.24
클러스터인덱스와 넌클러스터인덱스  (0) 2017.10.24
Nested Loop, Sort Merge, Hash JOIN  (0) 2017.10.23

클러스터드 인덱스가 있는 테이블의 경우 데이터는 클러스터드 인덱스의 키로 정렬이됩니다.

이 키로 데이터를 찾을 경우 "Clustered Index Seek"가 발생하게 됩니다.

클러스터드 인덱스가 없는 테이블의 경우 데이터는 추가된 순서대로 쌓이게 됩니다. 그래서 힙이라고 하죠.


이때 넌클러스터드 인덱스를 만들게 되면 넌클러스터드 인덱스의 리프레벨에는 데이타의 위치를 가르키는 RID가 기록됩니다. 넌클러스터드 인덱스로 데이터를 찾을 경우에는 그래서 "RID Lookup"이 발생하게 됩니다. 


근데 클러스터드 인덱스가 있는 테이블에 넌클러스터드 인덱스를 만들면 이 인덱스의 리프레벨에는 RID가 아닌 클러스터드 인덱스의 키가 기록됩니다. 그래서 이 넌클러스터드 인덱스로 데이터를 찾을 경우에는 넌클러스터드 인덱스의 리프레벨에서 클러스터드 인덱스의 키를 확인한 후 이 키를 이용해서 데이터를 찾는 "Key Lookup"이 발생합니다.


"Index Scan"이란 이런겁니다. 

주소록 테이블에 전화번호로 인덱스를 만들었습니다.

근데 찾고 싶은 데이터는 전화번호의 4번째가 7이고 다섯번째와 여섯번째의 차가 3인 그런 데이타입니다. -_-;;

우리가 전화번호부를 이용해서 이런 데이터를 찾으려고 해도... 결국 전화번호부 책을 몽땅 뒤질수밖에 없죠.

SQL SERVER도 마찬가지입니다. 인덱스를 이용해서 저런 데이타를 찾을 수가 없습니다.

그래서 결국 테이블을 몽땅 스캔합니다. 이것이 "Clustered Index Scan" 또는 "Table Scan" 라고 합니다.

근데 찾으려는 데이타가 인덱스의 키에 포함되어 있을 경우 테이블을 몽땅 뒤지는것보다 인덱스를 뒤지는게 더 빠릅니다.

이유는 인덱스 페이지가 더 작을것이기 때문이죠. 이때 발생하는것이 "Index Scan"이라고 합니다.


책을 예로 설명해보면

보통 기술서적들 보면 맨 뒤에 키워드를 인덱스로 만들어놨습니다.

SQL 관련 서적을 예로 들면 "클러스터드 인덱스"에 대해 설명해놓은 페이지를 찾으려면

"ㅋ"섹션에서 "클러스터드 인덱스" 키워드를 찾은 후 517페이지 (<- 이게 RID) 에 있다는 걸 확인한 후 517페이지를 펼치게 됩니다.

이런게 "Index Seek"


근데 키워드 중에 중간에 "덱"이 들어간 페이지를 찾고 싶으면??

인덱스 a~z ㄱ~ㅎ까지 몽땅 확인해야죠? 중간에 "덱"이런거 들어간 키워드가 있나...

이런 동작이 "Index Scan"입니다.

"Index Seek"동작이나 "Index Scan"동작은 어쨋든 인덱스 페이지에서 인덱스 키를 찾는 동작입니다.

이 동작후에는 데이터 페이지로 이동하기 위해 "RID Lookup"이나 "Key Lookup"을 하게 되죠.

클러스터드 인덱스가 있을때는 Key Lookup 넌클러스터드만 있다면 RID Lookup을 하게 됩니다.



근데 만약에 원하는 데이타가 인덱스 키 안에 모두 포함되어 있다면

말하자면 전화번호부 테이블에서 "전화번호, 이름"으로 인덱스가 만들어져 있는데


select 전화번호, 이름 

  from 전화번호부

where 전화번호 = '010-9999-8888' 


이런 쿼리를 날린다면

전화번호와 이름이 모두 인덱스 페이지에 있기 때문에 더 이상 데이터 페이지로 이동하지 않아도 모든 데이터를 확인 할 수 있습니다. 그러면 Lookup 동작 자체를 안하게 됩니다. 인덱스 이외에 같은 행에 있는 데이터를 가져올 필요가 없기 때문이죠. 이런걸 "커버드 인덱스"라고 합니다.


따로 룩업을 안하고 인덱스 페이지에서 모든 데이터를 가져가는것이 마치 클러스터드 인덱스의 동작과 비슷합니다.

그래서 성능이 클러스트드 인덱스에 필적한다고 하죠.

사실 커버드 인덱스란 인덱스의 종류가 따로 있는 것이 아니라 어떤 쿼리가 인덱스 컬럼 내에서만 select 할때

그때 사용된 인덱스가 쿼리를 커버하는 것이죠.

요약

클러스터 인덱스는 테이터에 바로 접근이 가능하다. 리프노드가 데이터 페이지에 있기 때문이다. 하지만 넌클러스터 인덱스는 데이터를 가져오기위해서는 데이터 페이지까지 찾아서 데이터를 가져와야하는데, 이때 RID를 참조해서, 데이터를 LOOK UP해오는 과정을 RID LOOKUP이라한다.

RID

행식별자로서 넌 클러스터 인덱스의 데이터 페이지 번호, 슬롯번호, 파일번호를 16진수 값으로 변환한 값을 말한다.


LOOKUP

인덱스의 리프레벨에 없는 컬럼을 읽어야 한다면, 실제 데이터가 저장된 위치를 찾아가서 읽어오는 작업을 말한다.


RID LOOKUP

RID(데이터페이지변호, 슬롯번호, 파일번호)를 가지고 HEAP에 저장된 실제 데이터를 찾아오는 것.


KEY LOOKUP

클러스터 인덱스가 잡혀있는 테이블에서 넌클러스터인덱스를 만들경우 RID에는 클러스터인덱스의 KEY가 저장된다. 이 KEY를 이용해서 실제 데이터를 찾아오는 과정

특징

RID LOOKUP은 HEAP TABLE에서만 일어난다. 

HEAP TABLE이란 클러스터 인덱스가 없는 테이블을 말한다.

테이블에 클러스터 인덱스가 있으면 그 테이블은 RID LOOKUP이 일어날 수가 없다. KEY LOOKUP이 발생한다.

RID LOOKUP은 항상 NL JOIN과 함께 사용된다.


RID LOOKUP을 발생시키기위한조건

1. 클러스터 인덱스의 부재

2. 넌클러스터 인덱스가 유니크 하지않으면 테이블 스캔이 일어난다.





출처 : http://www.sqler.com/612541 댓글

그림출처 : https://blogs.msdn.microsoft.com/craigfr/2006/06/30/bookmark-lookup/

'SQL > SQL 튜닝' 카테고리의 다른 글

클러스터링 팩터  (0) 2017.10.26
옵티마이저 이해하기 - 2  (0) 2017.10.26
클러스터인덱스와 넌클러스터인덱스  (0) 2017.10.24
Nested Loop, Sort Merge, Hash JOIN  (0) 2017.10.23
옵티마이저 이해하기 - 1  (0) 2017.10.23

인덱스란

책에서 원하는 내용을 빨리 찾으려면 인덱스를 이용해서 찾으면 편리하다.

이와 같이 DB에서도 인덱스를 만들어 놓으면 데이터를 빨리 찾을수 있게 데이터의 위치 정보를 모아 놓은 데이터 베이스 내의 객체이다.


인덱스는 정렬되어있다.

sql server의 실행계획에 보면table scan, index seek 라는 말을 볼수있는데, 각각 테이블을 전체 검색하는 것과 인덱스를 찾아서 검색하는 것을 뜻한다.

포인트쿼리(Point Query)

조회되는 값이 한 행인 쿼리



범위쿼리(Range Query)

조회되는 값이 여러 행인 쿼리


커버드쿼리(Covered Query)

넌클러스터 인덱스에서 조회되는 값이 인덱스가 걸려있으면서, where절과 같은 쿼리

클러스터 인덱스의 속도를 낸다.

클러스터인덱스

  • 테이블당 1개씩만 허용된다.
  • 범위쿼리와 포인트쿼리 둘다에서 성능을 발휘한다.
  • PK설정시 그 컬럼은 자동으로 클러스터드 인덱스가 마늘어진다.
  • 테이블 자체가 인덱스이다. (따로 인덱스 페이지를 만들지 않는다.)
  • 데이터 입력, 수정, 삭제시 항상 정렬상태를 유지한다.


넌클러스터인덱스

  • 인덱스 페이지를 따로만들기 때문에 용량을 더 차지한다.
  • 인덱스 페이지는 로그파일에 저장된다.
  • 레코드의 원본은 정렬되지 않고, 인덱스 페이지만 정렬된다.
  • 테이블당 240개의 인덱스를 만들수있다.
  • 포인트쿼리는 성능을 발휘하나, 범위쿼리는 성능을 보장할 수 없다.


결론

클러스터 인덱스는 데이터 위치를 바로 알기때문에 그 데이터로 바로 접근할 수 있고, 

넌클러스터 인덱스는 인덱스 페이지를 한번 거져서 데이터에 접근하는 방식이다.



그러면 어떤 컬럼에 인덱스를 걸어야할까.

  • WHERE절 뒤에 자주 사용되는 컬럼
  • LIKE '%A'는 TABLE SCAN을 탄다.
  • ORDER BY에 자주사용되는 컬럼
  • JOIN으로 자주사용되는 컬럼
  • NOT연산자는 긍정문으로 바꿔서 쓴다.
  • 삽입과 삭제가 빈번한 컬럼은 인덱스로 좋지않다. (인덱스를 만드는데 사용되는 공간과, 정렬하는데 걸리는 시간등이 추가적으로 필요하다.)



'SQL > SQL 튜닝' 카테고리의 다른 글

옵티마이저 이해하기 - 2  (0) 2017.10.26
MSSQL LOOKUP  (0) 2017.10.24
Nested Loop, Sort Merge, Hash JOIN  (0) 2017.10.23
옵티마이저 이해하기 - 1  (0) 2017.10.23
INDEX 튜닝  (0) 2017.10.23

방 법

설 명

중첩 반복 조인

(Nested Loop join)

선행테이블(드라이빙 테이블)의 처리범위를 하나씩 액세스하면서 그 추출된 값으로 연결할 테이블(후행 테이블)을 조인하는 방식

색인된 중첩 반복 조인, 단일 반복 조인

(single loop join)

-후행(Driven) 테이블의 조인 속성에 인덱스가 존재할 경우 사용

- 선행 테이블의 각 레코드들에 대하여 후행 테이블의 인덱스 접근 구조를 사용하여 직접 검색 후 조인하는 방식

정렬 합병 조인

(Sort Merge join)

양쪽 테이블의 처리범위를 각자 액세스하여 정렬한 결과를 차례로 scan하면서 연결고리의 조건으로 merge해 가는 방식

해시 조인

(Hash join)

해시(Hash)함수를 사용하여 두 테이블의 자료를 결합하는 조인 방식

 

※ 아래의 조인 알고리즘들은 R  A=B S 를 기준으로 설명함

( 릴레이션 R과 S의 각 튜플들이 R의 A애트리뷰트와, S의 B 애트리뷰트 값이 일치하면 결합)

 

중첩 반복 조인(Nested Loop Join)

  가. Nested Loop Join 알고리즘

- 2개 이상의 테이블에서 하나의 집합을 기준으로 순차적으로 상대방 Row를 결합하여 원하는 결과를 추출.

- R(외부, 선행 테이블)의 각각의 레코드에 대해 S(내부, 후행 테이블)의 모든 레코드를 검색하여, 두 레코드가 조인 조건(A=B)을 만족하는지 확인하여 만족하면 조인하는 방법

    

  나. 색인된 중첩 반복 조인(=단일 반복 조인, single loop join) 알고리즘

         - S(내부 테이블)의 B에 인덱스가 존재할 경우 사용

- R의 각 레코드들에 대하여 S의 인덱스 접근 구조를 사용하여 S의 레코드들 중에서 조인조건을 만족하는 레코드를 직접 검색

  다. 사용법 및 사용예제

    힌트: /*+ USE_NL(A B) */

    select /*+ use_nl(b,a) */ a.dname, b.ename, b.sal

    from emp b, dept a

    where a.loc = 'NEW YORK'

    and b.deptno = a.deptno

  라. Nested Loop의 특징

    - 주로 좁은 범위에 유리

    - 순차적으로 처리하며, Random Access 위주

    - 후행(Driven) 테이블에는 조인을 위한 인덱스가 생성되어 있어야 함

    - 실행속도 = 선행 테이블 사이즈 * 후행 테이블 접근횟수

  마. Nested Loop사용 시 주의사항

    - 데이터를 랜덤으로 액세스하기 때문에 결과 집합이 많으면 수행속도가 저하됨

    - 선행(Driving) 테이블의 크기가 작거나, Where절 조건을 통해 결과 집합을 제한할 수 있어야 함

    - 조인 연결고리 인덱스가 없거나, 조인 집합을 구성하는 검색조건이 조인 범위를 줄여주지 못할 경우 비효율적임

 

- Loop 개수를 줄이기 위해 조인에 참여하는 테이블 중 Row수가 적은 쪽을 Driving으로 설정하고, inner 테이블의 연결고리를 결합인덱스를 이용해 최적화함

 

  바. Nested Loop사용 예

 

 

 

 

정렬 합병 조인(Sort Merge Join)

  가. Sort Merge Join 알고리즘

- R과 S의 레코드들이 각각 조인 애트리뷰트 A, .B 값에 따라 물리적으로 정렬되어 있는 경우, 두 파일을 모두를 조인 애트리뷰트의 순서에 따라 동시에 스캔하면서 A, B 값이 동일한 레코드를 검색

- 정렬되어 있지 않은 경우는 우선 외부 정렬을 사용하여 정렬 후 조인

-조인의 대상범위가 넓을 때 발생하는 랜덤 액세스를 줄이기 위한 경우나 연결고리에 마땅한 인덱스가 존재하지 않을 때 해결하기 위한 대안

 

  나. 사용법 및 사용예제

     힌트: /* USE_MERGE(A B) */

select /*+ use_merge(a b) */a.dname, b.empno, b.ename
from   dept a,emp b
where  a.deptno = b.deptno
and    b.sal > 1000 ;

  다. Sort Merge Join의 특징

- 연결을 위해 랜덤 액세스를 하지 않고 스캔을 하면서 이를 수행

- 정렬을 위한 영역(Sort Area Size)에 따라 효율에 큰 차이가 남

조인 연결고리의 비교 연산자가 범위 연산(‘>’,’< ‘)인 경우 Nested Loop 조인보다 유리

  라. Sort Merge Join사용시 주의사항

두 결과집합의 크기가 차이가 많이 나는 경우에는 비효율적

- Sorting 메모리에 위치하는 대상은 join key뿐만 아니라 Select list도 포함되므로 필요한 select 항목 제거

  마. Sort Merge Join사용 예

 

해시 조인(Hash Join)

  가. Hash Join 알고리즘

- 해싱 함수(Hashing Function) 기법을 활용하여 조인을 수행하는 방식으로 해싱 함수는 직접적인 연결을 담당하는 것이 아니라 연결될 대상을 특정 지역(partition)에 모아두는 역할만을 담당함

- R의 애트리뷰트 A와 S의 애트리뷰트 B를 해시 키로 하고, 동일한 해시 함수를 사용하여 해시

- 1단계(분할 단계, partitioning phase):  더 적은 수의 레코드를 가진 화일(R )의 레코드들을 해시 파일 버켓들로 해시

- 2단계(조사 단계, probing Phase): 다른 파일(S)의 각 레코드를 해시하여 R에서 동일한 해시 주소를 갖는 버켓 내의 레코드들이 실제로 조인 조건을 만족하면 두 레코드를 결합

 

  나. 사용법 및 사용예제

    힌트: /*+ USE_HASH(A B) */

select /*+ use_hash(a b) */ a.dname, b.empno, b.ename
from dept a, emp b
where a.deptno = b.deptno
and a.deptno between 10 and 20;

 

  다. Hash Join의 특징

  1. Nested Loop 조인과 Sort Merge 조인의 문제점을 해결
  2.  대용량 처리의 선결조건인 랜덤 액세스와 정렬에 대한 부담을 해결할 수 있는 대안으로 등장
  3. Hash 조인만을 이용하는 것보다 parallel processing을 이용한 hash 조인은 대용량 데이터를 처리하기 위한 최적의 솔루션 제공
  4. 2개의 조인 테이블 중 small rowset을 가지고 hash_area_size에 지정된 메모리 내에서 hash table 생성
  5. Hash bucket이 조인집합에 구성되어 Hash 함수 결과를 저장하여야 하는데, 이러한 처리에 많은 메모리와 CPU자원이 소모됨
  6. CBO(Cost Based Optimizer) 모드에서 옵티마이저가 판단가능하며, 테이블의 통계정보가 있어야 함
  7. Hash table 생성 후 Nested Loop처럼 순차적인 처리 형태로 수행함

  라. Hash Join사용시 주의사항

  1. 대용량 데이터 처리에서는 상당히 큰 hash area를 필요로 함으로, 메모리의 지나친 사용으로 오버헤드 발생 가능성
  2. 연결조건 연산자가 ‘=’인 동치조인인 경우에만 가능

 

  마. Hash Join정리

    1) 수행순서

           - 두 테이블을 스캔하여 사이즈가 작은 테이블을 선행 테이블로 결정

           - 선행 테이블을 이용하여 해쉬 테이블을 구성한다(Build Input)

           - 후행 테이블은 해쉬 값을 이용하여 선행 테이블과 조인한다(Prove Input)

     2) Build Input 크기

           -  Hash Area 만으로 Hash Table 생성이 불충분하다면 Hash Table Overflow가 발생

             내Hash Area 사이즈를 증가 필요함

     3) 이용

           - 대용량 데이터 엑세스, 배치처리, 전체 테이블을 조인할 때 유리하다

           - 양쪽 테이블의 조건으로 각각 범위를 줄일 수 있을 때 유리하다

           - 병행 처리로 수행속도 향상이 가능하다

           - Hash Area 사이즈 조정으로 수행속도 향상이 가능하다

 

조인 연산 비교

  가. Nested Loop와 Hash Join의 비교

구분

Nested loop join

Hash join

대량의 범위

인덱스를 랜덤 액세스에 걸리는 부하가 가장 큰 문제점으로, 최악의 경우 하나의 ROW를 액세스하기 위해 Block단위로 하나하나 액세스를 해야 함.

적은 집합에 대하여 먼저 해시 값에 따른 Hash Bucket정보를 구성한 후 큰 집합을 읽어 해시 함수를 적용하여 Hash Bucket에 담기 전에 먼저 호가인해 볼 수 있기 때문에 해시조인이 효율적인 수행이 가능

대량의 자료

다량의 랜덤 액세스 수행으로 인해 수행 속도가 저하

대용량 처리의 선결조건인 ‘랜덤 액세스’와 ‘정렬’에 대한 문제 개선과 H/W의 성능 개선을 통해 각 조인 집합을 한번 스캔하여 처리하기 때문에 디스크 액세스 면에서 훨씬 효율적


나. sort merge와 Hash join의 비교

구 분

Sort merge join

Hash join

조인이 되는 두 테이블의 크기가 다를 경우

조인이 되는 두 테이블의 크기가 다르다면 정렬되는 시간이 동일하지 않아 시간에 대한 손실이 발생

조인에 대한 알고리즘을 구현하기 때문에 두 집합의 크기가 차이가 나도 대기 시간이 발생치 않음

대용량 데이터의 경우

정렬에 대한 부담 때문에 sort merge조인은 제 기능을 발휘하지 못하는 경우가 발생. 즉 메모리 내의 지정한 정렬 영역보다 정렬할 크기가 지나치게 큰 경우 정렬할 범위가 넓어질수록 효율성을 하락

대용량 처리의 선결 조건인 ‘랜덤 액세스’와 ‘정렬’에 대한 문제 개선과 H/W의 성능 개선을 통해 각 조인 집합을 한 번 스캔하여 처리하기 때문에 디스크 액세스 면에서도 훨씬 효율적



출처 : http://www.jidum.com/jidums/view.do?jidumId=167

'SQL > SQL 튜닝' 카테고리의 다른 글

MSSQL LOOKUP  (0) 2017.10.24
클러스터인덱스와 넌클러스터인덱스  (0) 2017.10.24
옵티마이저 이해하기 - 1  (0) 2017.10.23
INDEX 튜닝  (0) 2017.10.23
쿼리튜닝팁  (0) 2017.09.20

SQL의 구문분석 절차

1. 동일한 SQL의 수행여부 확인

2. 문법/절차 확인

3. SEMANTIC확인

4. 권한 확인


1. 동일한 SQL의 수행여부확인

 - Soft Parsing : 동일한 SQL이 이전에 수행되었고, 실행계획등의 실행정보가 메모리에 저장되어있다.

 - Hard Parsing : 실행정보가 존재하지않아 구문 분석을 새로 시작해야한다.


2. 문법/ 절차 확인

 - 문법이 맞는지 확인. 틀리면 SYNTAX 에러 메시지 발생


3. SEMANTIC

 - Database Resolution단계, SQL에 사용된 테이블과 테이블 컬럼이 실제 DB에 존재하는지 확인


4. 권한 확인

  - 해당 SQL을 실행 할수 있는지 권한 확인


Query Transformation

- 구문 분석을 수행하는 중간단계에서 SQL을 변경하는 단계(Query Transformation)가 발생
- 옵티마이저가 단독으로 수행하는 과정
- 결과적으로 Query Tranformation은 처리범위를 감소시키는 조건을 찾아내어 처리범위를 감소시키는(SQL의 성능을 최적화 하기위한) 옵티마이저의 노력

- Transitivity
- View Merging
- Sub query Merging
- Or Expansion
- Query Rewrite

Transitivity

- 논리적으로 이상이 없는 조건을 추가하여 처리범위를 감소시켜 성능을 최적화 하고자 하는 옵티마이저의 노력
- WHERE절에 존재하는 A테이블의 상수 조건에 대해 논리적으로 타당하다면 B테이블에도 해당 상수 조건을 옵티마이저가 추가시켜 주는것

특징

- 점(=) 조건은 가능
- 선분 조건은 불가능
- 조인 조건은 불가능

View Merging

- 말그대로 뷰가 머징되는것
- Query Transformation에서 중요요소이다
- 뷰머징은 말로 표현하기 힘들정도로 심하게 발생한다.
- 인라인뷰는 주 쿼리의 조건을 받으므로, 처리범위를 더욱 감소시킬수 있게된다. 물론 인라인뷰의 추가된 조건이 해당 테이블의 인덱스로 걸려있어야만 처리범위가 감소하게 된다.

View Merging 종류

- 주 쿼리의 조건(WHERE)이 인라인 뷰 안으로 삽인 되는 뷰 머징
- 인라인 뷰 또는 뷰의 SQL이 주 쿼리로 합쳐지는 뷰머징

인라인뷰

인라인 뷰에서 괄호는 표현한부분 부터 연산을 수행하는 수학적인 괄호가 아니다. 단지 문법적인 구분의 역할만을 수행하게 된다. 그렇기 때문에 괄호를 사용하는 인라인 뷰는 언제든 변할 수있게 된다.

인라인뷰의 종류

- Mergeable 인라인 뷰 : 뷰가 해체되거나 뷰 안으로 조건이 삽입되는 인라인 뷰
- 주 쿼리의 조건(WHERE)이 인라인 뷰 안으로 삽인 되는 뷰
- 인라인 뷰 또는 뷰의 SQL이 주 쿼리로 합쳐지는 뷰
- Non-Mergeable인라인 뷰 : 뷰가 수학의 괄호처럼 별도로 수행되는 뷰

Non-Mergeable인라인 뷰확인하기

- UNION ALL
- UNION
- DISTINCT
- GROUP BY
- ROWNUM
- 집합 함수

Non-Mergeable 인라인뷰가 될 가능성이 높다.
완벽하게 확인하기 위해서는 SQL의 실행계획을 확인해보아야 한다.






'SQL > SQL 튜닝' 카테고리의 다른 글

클러스터인덱스와 넌클러스터인덱스  (0) 2017.10.24
Nested Loop, Sort Merge, Hash JOIN  (0) 2017.10.23
INDEX 튜닝  (0) 2017.10.23
쿼리튜닝팁  (0) 2017.09.20
쿼리실행순서  (0) 2017.09.01

+ Recent posts