8. 비트맵 인덱스

조회 수 3231 추천 수 0 2010.02.03 20:38:20
ZoneWorker2 *.223.251.56

CHAPTER 8. 비트맵 인덱스

발표/총정리 - 위충환





시작하면서 222 / 위충환


   테스트 테이블

  • 비트맵 인덱스 사용의 비용에 영향을 미치는 주요 포인트 발견 목적
  • 테이블스페이스 : 8KB 블록
  • 될 수 있으면 1MB의 동일 익스텐트를 가진 LMT(Local Management Tablespace)를 사용
  • 교재와 같은 결과를 얻고싶을 시 ASSM이 아니어야 함
  • 온라인 코드집 init.ora 정의를 사용하지 않을 경우 db_file_multiblock_read_count = 8 설정 확인
  • CPU Costing = Disabled
  • PCTFREE 90


   bitmap_cost_01.sql

  • 테이블의 6개의 중요 컬럼 (각 개별적 인덱스 존재)

    • n1 : 20개의 distinct 값이 골고루 흩어있음 (비트맵 인덱스)
    • n2 : 20개의 distinct 값 중 특정 값의 모든 로우가 500개 그룹에 모여있음 (비트맵 인덱스)

      ☞ 데이터 클러스터링의 변화가 통계정보에 어떤 영향을 미치는가?

    • n3 : 25개의 distinct 값이 골고루 흩어있음 (비트맵 인덱스)
    • n4 : 25개의 distinct 값 중 특정 값의 모든 로우가 400개 그룹에 모여있음 (비트맵 인덱스)

      ☞ 옵티마이저가 비트맵 인덱스 결합 시 비용을 어떻게 산출하는가?

    • n5 : 25개의 distinct 값이 골고루 흩어있음 (B-tree 인덱스)
    • n6 : 25개의 distinct 값 중 특정 값의 모든 로우가 400개 그룹에 모여있음 (B-tree 인덱스)

      ☞ 비트맵 인덱스와 B-tree 인덱스 크기 변화는?


   ▼ 표 8-1. 비트맵과 B-tree 인덱스의 통계정보 차이

 통계항목

 t1_i1
  (비트맵)  

t1_i2
  (비트맵)  

t1_i3
  (비트맵) 

t1_i4
  (비트맵) 

t1_i5
  (B-tree)  

 t1_i6

  (B-tree)  

 blevel

 1

 1

 1

 1

 1

 1

 leaf_blocks

 60

 10

 63

 9

 217

 217

 distinct_keys

 20

 20

 25

 25

 25

 25

 num_rows

 120

 20

 125

 25

 10,000

 10,000

 clustering_factor

 120

 20

 125

 25

 10,000

 1,112

 avg_leaf_blocks_per_key            

 3

 1

 2

 1

 8

 8

 avg_data_blocks_per_key

 6

 1

 5

 1

 400

 44


결과

  • 데이터클러스팅 : 비트맵 인덱스 내 리프 블록 개수에 영향 (n1 & n2 차이 有, n3 & n4 차이 有, n5 & n6 차이 無)

     ☞ 비트맵 인덱스 : 흩어진 데이터 > 모아진 데이터

         B-tree 인덱스 : 흩어진 데이터 = 모아진 데이터

  • 직관적이지 못한 비트맵 인덱스 크기와 관련된 세부항목

    • t1_i1 과 t1_i3 비교 시 distinct 와 리프블록은 정비례

    • but t1_i2 과 t1_i4 비교 시 distinct 와 리프블록은 반대 효과

  • 테이블이 아주 크지 않을 시, 비트맵 인덱스의 distinct_keys = num_rows

     (규칙이 아닌 우연, 8i 이하는 distinct_keys = num_rows 성립 )

     Q. 데이터가 군집한 비트맵 인덱스 경우에만 해당되는가?? 흩어진 경우는 아래와 같은 규칙이 나옴.

  • 데이터가 흩어진 경우(t1_i1, t1_i3)  num_rows > distinct_keys

    ∵ 각 키의 비트 문자열이 리프 블록에 맞도록 여러조각으로 쪼개짐

  • 비트맵 인덱스의 clustering_factor는 인덱스에 대한 num_rows의 복사본

    ☞ 테이블 내 데이터의 흩어짐과 직접적 연관성

        데이터의 흩어짐 ▶ 비트맵 인덱스 엔트리의 크기에 영향

  • avg_leaf_blocks_per_key = round(leaf_blocks / distinct_keys)

     ☞ 비트맵 인덱스와 관계

  • avg_data_blocks_per_key = round(clustering_factor / distinct_keys)

     ☞ 비트맵 인덱스와 관계    ∵ 비트맵 인덱스의 clustering_factor가 테이블을 표현하지 않음


    ▼ 인덱스 사용의 추정 비용에 영향을 미치는 것을 알기 위한 테스트

    (테스트 환경 : n3~n6 까지 각 컬럼에 대하여 '컬럼 = 상수' 쿼리 수행, autotrace 실행)


Execution Plan - (n6: B-tree index on clustered column)
----------------------------------------------------------
   0     SELECT STATEMENT Optimizer=ALL_ROWS (Cost=54 Card=400 Bytes=5600)
   1   0    TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=54 Card=400 Bytes=5600)
   2   1       INDEX (RANGE SCAN) OF 'T1_I6' (NON-UNIQUE) (Cost=9 Card=400)


Execution Plan - (n5: B-tree index on scattered column)
----------------------------------------------------------
   0     SELECT STATEMENT Optimizer=ALL_ROWS (Cost=170 Card=400 Bytes=5600)
   1  0     TABLE ACCESS (FULL) OF 'T1' (Cost=170 Card=400 Bytes=5600)


Execution Plan - (n4: bitmap index on clustered column)
----------------------------------------------------------
   0     SELECT STATEMENT Optimizer=ALL_ROWS (Cost=114 Card=400 Bytes=5600)
   1  0     TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=114 Card=400 Bytes=5600)
   2  1        BITMAP CONVERSION (TO ROWIDS)
   3  2        BITMAP INDEX (SINGLE VALUE) OF 'T1_I4'


Execution Plan - (n3: bitmap index on scattered column)
----------------------------------------------------------
   0     SELECT STATEMENT Optimizer=ALL_ROWS (Cost=117 Card=400 Bytes=5600)
   1  0     TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=117 Card=400 Bytes=5600)
   2  1        BITMAP CONVERSION (TO ROWIDS)
   3  2        BITMAP INDEX (SINGLE VALUE) OF 'T1_I3'


결과

  • B-tree 인덱스를 소유한 컬럼 중, 군집된 데이터 실행계획과 흩어진 데이터 실행계획이 다름

    • 군집된 데이터 : 인덱스가 효율적 -> 비용이 적음
    • 사용흩어진 데이터 : 인덱스의 공간 낭비 -> 비용이 높음
  • 비트맵 인덱스를 소유한 컬럼의 군집된 데이터와 흩어진 데이터 실행계획은 차이 없고 비용이 비슷함

☞ 두 가지 경로에 대한 비용은 비슷하나 leaf_blocks은 7배까지 차이를 보임

    ∵ 테스트 예제 생성시 여유공간을 인위적으로 90% 선언



인덱스 컴포넌트 227 / 위충환


  ▼ event 10053 트레이스 활성화 후 상세내용


For the query n3 = 2 bitmap on scattered data
---------------------------------------------
Access path: index (equal)
      Index: T1_I3
   TABLE: T1
      RSC_CPU: 0 RSC_IO: 3
   IX_SEL: 4.0000e-002 TB_SEL: 4.0000e-002
******** Bitmap access path accepted ********
Cost: 117 Cost_io: 117 Cost_cpu: 0.000000 Selectivity: 0.040000
Not believed to be index-only.
   BEST_CST: 116.54 PATH: 20 Degree: 1


For the query n4 = 2 bitmap on clustered data
---------------------------------------------
Access path: index (equal)
      Index: T1_I4
   TABLE: T1
      RSC_CPU: 0 RSC_IO: 1
   IX_SEL: 4.0000e-002 TB_SEL: 4.0000e-002
******** Bitmap access path accepted ********
Cost: 114 Cost_io: 114 Cost_cpu: 0.000000 Selectivity: 0.040000
Not believed to be index-only.
   BEST_CST: 114.34 PATH: 20 Degree: 1


  • BEST_CST : 소수점 2자리까지 나타낸 후 가장 가까운 정수로 반올림
  • RSC_IO : 인덱스 비용 = ceiling(leaf_blocks * 유효 인덱스 선택도) + blevel의 0(단, blevel = 1 일때 생략)
  • 최종 비용 : 기술된 인덱스 컴포넌트 비용 * 1.1  
           ☞ 비트맵 인덱스보다 B-tree 인덱스가 약간 유리 ▶ B-tree to Bitmap conversion 위험성 감소 목적

   

  • 인덱스 t1_i3 사용 : 인덱스 비용 = 3 ☞ 3.3으로 증가, Best_cst = 116.54 적용

    ∴ 실제 테이블 블록 액세스 비용 = 116.54 - 3.3 = 113.24 추정

  • 인덱스 t1_i4 사용 : 인덱스 비용 = 1 ☞ 1.1로 증가, Best_cst = 114.34 적용

    ∴ 실제 테이블 블록 액세스 비용 = 114.34 - 1.1 = 113.24 추정


※ 비트맵 인덱스에서는 특정 양 데이터에 대해 실제 테이블을 액세스하는 '계산된 비용'이 데이터 군집성과 흩어짐과 상관없음

    ∵ 비용기반 옵티마이저는 실제 데이터의 흩어짐에 대해 전혀 모름


  • 일반적 비용 전략

   옵티마이저가 예상한 일이 일어나고, 옵티마이저가 예측한 횟수만큼의 I/O 요청 발생 기대

   But 옵티마이저가 무시한 B-tree 인덱스를 → Bitmap 인덱스로 변경 시 발생


  • 비트맵 인덱스와 B-tree 인덱스 사이 적절한 테스트 수행 시, 예상 비용과 무관하게 수행된 일량은 둘다 같음

(요청된 테이블 블록 읽기 수가 같음)


  • 옵티마이저가 테이블 내 데이터 흩어짐에 대한 중요 정보를 읽어버릴 시, 대체 방법 필요

상황 : B-tree 인덱스를 비트맵 인덱스로 변경


* 낮은 비용의 B-tree 인덱스 시작 시 :  동등 비트맵 인덱스는 높은 비용

test ☞  t1_i6 (cost 54) → t1_i4 (cost 114)


* 높은비용의 B-tree 인덱스 시작 시 :  동등 비트맵 인덱스는 낮은 비용

test ☞  t1_i5 (비용이 너무 높아 사용되지 않음) → t1_i3 (cost 117, 비용이 매우 낮아 사용)




테이블 컴포넌트 229 / 이태경


80/20 규칙

where n1 = {constant}
where n2 = {constant}

테이블 방문 비용 137.99
500 로우 리턴

where n3 = {constant}
where n4 = {constant}
테이블 방문 비용 113.23
400 로우 리턴
137.99 ≒ 113.24*(500/400)
옵티마이저는 대상 데이터의 80%가 빈틈없이 모여있고 나머지 20%는 넓게 흩어져 있다고 가정(Oracle Wait Interface)

표 8-2. 비트맵 계산 - 80/20 분할의 확인
항목
n1과 n2 컬럼의 인덱스
n3과 n4 컬럼의 인덱스
테이블 내 로우 수
10,000
10,000
테이블 내 블록 수
1,112
1,112
블록 당 로우 수
8.993
8.993
한 값(=equal)에 해당하는 로우 수
500
400
모여있는 로우 수
0.8*500=400
0.8*400=320
모여있는 로우에 필요한 블록 수
400/8.993=44.48
320/8.993=35.58
남은 블록 수
1,112-44.48=1,067
1,112-35.55=1,076
흩어진 로우 수(20%)
0.2*500=100
0.2*400=80
흩어진 로우에 필요한 블록 수
100
80
필요한 전체 블록 수
100+44.48=144.48
80+35.58=115.58
보고된 테이블 비용(10053 트레이스로부터)
137.99
113.24

db_file_multiblock_read_count 값 변경에 따른 쿼리의 비용
        80        201
        81        199
        82        200
        83        202
        84        200
        85        201
        86        203
        87        204

db_file_multiblock_read_count           COST
----------------------------           ----------
        88        202
        89        203
        90        205
        91        206
        92        204
        93        205
        94        206
        95        207
        96        205
        97        206
*db_file_multiblock_read_count가 올라갈수록 비용이 일반적으로 증가하지만, 패턴이 안정적이지 않다.


비트맵 결합 231 / 이태경

select
    mod((rownum-1),20)            n1,        -- 20 values, scattered
    trunc((rownum-1)/500)         n2,        -- 20 values, clustered
    mod((rownum-1),25)            n3,        -- 25 values, scattered
    trunc((rownum-1)/400)         n4,        -- 25 values, clustered
    lpad(rownum,10,'0')        small_vc,
    rpad('x',220)            padding
from
    all_objects
where
    rownum  <= 10000
;
create bitmap index t1_i1 on t1(n1)
nologging
pctfree 90
;
create bitmap index t1_i2 on t1(n2)
nologging
pctfree 90
;
create bitmap index t1_i3 on t1(n3)
nologging
pctfree 90
;
create bitmap index t1_i4 on t1(n4)
nologging
pctfree 90
;

USER_INDEXES 정보

NAME      BLEVEL LEAF_BLOCKSDISTINCT_KEYSNUM_ROWSCLUSTERING_FACTORAVG_LEAF_BLOCKS_PER_KEYAVG_DATA_BLOCKS_PER_KEY
T1_I11
60
20
120
120
3
6
T1_I21
10
202020
1
1
T1_I31
63
20125
125
2
5
T1_I41
9
2025
25
1
1

select

   small_vc
from
   t1
where      n1      = 2     -- one in 20, scattered data
and        n3      = 2     -- one in 25, scattered data
;
Execution Plan
----------------------------------------------------------
Plan hash value: 885960881

----------------------------------------------------------------------
| Id  | Operation                    | Name  | Rows  | Bytes | Cost  |
----------------------------------------------------------------------
|   0 | SELECT STATEMENT             |       |    20 |   340 |    13 |
|   1 |  TABLE ACCESS BY INDEX ROWID | T1    |    20 |   340 |    13 |
|   2 |   BITMAP CONVERSION TO ROWIDS|       |       |       |       |
|   3 |    BITMAP AND                |       |       |       |       |
|*  4 |     BITMAP INDEX SINGLE VALUE| T1_I3 |       |       |       |
|*  5 |     BITMAP INDEX SINGLE VALUE| T1_I1 |       |       |       |
----------------------------------------------------------------------
비트맵 인덱스 Scan 비용 = { ceiling(60/20) + ceiling(63/25) } * 비트맵 비율(1.1) = 6.6

bitmap and 인덱스의 distinct 한 값 = 각 인덱스의 distinct_key를 크로스 체크 = 20*25 = 500  
∴ 전체 로우의 1/500 을 리턴한다. 즉 20개의 로우를 리턴.

그럼 80/20 추정에 근거
row 개수
row의 분산 성격차지하는 블록 갯수
16
clustered
2 block(1block per 9 row)
4
scattered4 block(흩어져 있으므로 1 block per row)
인덱스에 필요한 총 블록의 갯수 = 2+4 = 6
∴ 비용 = round(6.6+6) = 13
실제 트레이스 파일에는 12.87 (필자는 옵티마이저의 테이블 방문 비용을 6.27로 예상)

select
    small_vc
from
    t1
where    n2 = 2 -- one in 20, clustered data
and      n4 = 2 -- one in 25, clustered data
;
Execution Plan
----------------------------------------------------------
Plan hash value: 2751833032

----------------------------------------------------------------------
| Id  | Operation                    | Name  | Rows  | Bytes | Cost  |
----------------------------------------------------------------------
|   0 | SELECT STATEMENT             |       |    20 |   340 |     9 |
|   1 |  TABLE ACCESS BY INDEX ROWID | T1    |    20 |   340 |     9 |
|   2 |   BITMAP CONVERSION TO ROWIDS|       |       |       |       |
|   3 |    BITMAP AND                |       |       |       |       |
|*  4 |     BITMAP INDEX SINGLE VALUE| T1_I4 |       |       |       |
|*  5 |     BITMAP INDEX SINGLE VALUE| T1_I2 |       |       |       |
----------------------------------------------------------------------
선택도가 제일 좋은(Row를 가장 많이 제거하는) 인덱스를 먼저 처리
    ==> 전개하고 비교해야 할 비트맵 인덱스 조각(Fragment)의 개수↓
인덱스 방문 비용 = 1(
인덱스의 크기가 작아)
비용 = 6.27(테이블 비용) + 1(인덱스 방문 비용)*2(인덱스 총 갯수) = ceiling(8.47) = 9

낮은 카디널리티 234 / 박우창

? 오라클은 언제 비트맵 인덱스를 하나 더 사용해도 이득이 없다고 결정할까?

-> 비트맵 인덱스의 리프 블록 세트를 하나 더 스캔하는 비용이 조회해야 할 테이블 블록 개수의 감소량 보다 클 때 사용한다. 소수의 distinct 값을 가지는 속성은 비트맵인덱스에 적합지 않다.

? 예제 - (bitmap_cost_03.sql)

- 3천6백만 로우, 800M(107,543블록), 6가지의 속성 및 비트맵 인덱스를 가지는 테이블

(속성) 성별 : 2가지, 눈의 색 : 3가지, 머리카락 색 : 7가지,

거주지 : 31가지,연령대 : 47가지, 직업분류 : 79가지

(질의 조건)

sex= 1 and eyes= 1 and hair= 1

and town= 15 and age= 25 and work= 40

(인덱스 통계 정보)

Column

blevel

leaf_

blocks

distinct_

keys

leaf_blocks/distinct_keys

(blevel 포함)

sex_code

2

1,340

2

670(672)

eye_code

2

2,010

3

670(672)

hair_code

2

4,690

7

670(672)

town_code

2

5,022

31

162(164)

age_code

2

5,241

47

112(114)

work_code

2

5,688

79

72(74)

(질의 결과) 6개 비트맵 조건을 다 사용하지 않고 정밀도가 높은 3개의 인덱스를 사용

(실행계획)

Execution Plan

----------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost |

----------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 18 | 314 |

| 1 | SORT AGGREGATE | | 1 | 18 | |

|* 2 | TABLE ACCESS BY INDEX ROWID | T1 | 7 | 126 | 314 |

| 3 | BITMAP CONVERSION TO ROWIDS| | | | |

| 4 | BITMAP AND | | | | |

|* 5 | BITMAP INDEX SINGLE VALUE| I6 | | | |

|* 6 | BITMAP INDEX SINGLE VALUE| I5 | | | |

|* 7 | BITMAP INDEX SINGLE VALUE| I4 | | | |

----------------------------------------------------------------------

? 옵티마이저의 판단 과정

- town_code, age_code, work_code를 지정하여 식별한 로우의 평군 개수를 산출하면, 옵티마이저가 이들 세 컬럼만으로 테이블 방문을 36,000,000/(31*47*79) = 313 로우로 제한하기에 충분하다고 결정할 것이다. 최악으로 흩어져 있어도 313개 테이블 블록을 방문하는 정도이다.

 

- 차선책에 해당하는 hair_code 인덱스가 테이블 방문 횟수를 313에서 0으로 감소시킬지라도 672개의 인덱스 블록을 방문해야 하므로 인덱스를 사용하는 것은 별 가치가 없다.

 

- 위의 조건의 경우 실제로, 정밀도가 높은 세 개의 인덱스 만을 사용한다. 쿼리의 총 비용은 314로 보고되었다. 그러나 이들 인덱스에 대해서 (blevel+leaf_blocks*유효 인덱스 선택도)의 합계를 보면, 352(=164+114+74)가 된다. 314는 1.1의 배율을 곱해서 테이블 방문 비용을 더하기 전의 값이다.

 

- 최종적으로 보고된 비용은 두 인덱스의 통계정보를 무시하고 가장 비용이 낮은 인덱스의 값을 세 번 사용하는 것으로 생각된다.

추측비용 (목표치는 314) =

      74 * 1.1 * 3 + (가장 비용이 낮은 인덱스를 1.1배 증가시켜서 세 번 사용)

    0.8 * 313 / 355 + (로우의 80%는 블록 당 335개씩 모여있음)

    0.2 * 313 = (로우의 20%는 개별 블록에 흩어져 있음)

    244.2 + 62.6 + 0.75 = 307.55 (에러율 2.1%)

 

- hair 컬럼을 정렬하여 테스트 사례를 재생성한 후 다시 실행해 보면 4개의 인덱스를 선택한다. (비용 336)

 

- 옵티마이저는 언제나 비용이 가장 낮은 실행계획을 선택해야 한다. 위의 결과에서는 비용이 더 높은 경우(314 -> 336)에도 비트맵 인덱스를 사용하였다. 비트맵 인덱스 비용을 계산하는 코드에 약간의 문제가 있는 것이 분명하다.

? 비트맵인덱스는 테이블에 비하여 크기가 작다. 따라서 비트맵인덱스를 메모리에서 액세스하는 논리적 I/O를 높이더라도 테이블을 읽는 물리적 I/O를 줄이는 것도 좋은 방법이다.


NULL 컬럼 238 / 박우창

? 오라클에게 데이터에 대해서 가능한 많은 정보를 알려주는 것은 언제나 중요하다.
  NOT NULL 컬럼은 특히 중요한데, 이것은 옵티마이저에게 허용되는 여러 가능성에 큰 차이를 만들 수 있다.

? 예제(! 조건 포함)

   alter table t1 modify n1 not null;

   select  small_vc

   from   t1

   where   n1 != 2 and n3= 3

(실행계획)

-----------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost |

-----------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 380 | 6460 | 113 |

| 1 | TABLE ACCESS BY INDEX ROWID | T1 | 380 | 6460 | 113 |

| 2 | BITMAP CONVERSION TO ROWIDS | | | | |

| 3 | BITMAP MINUS | | | | |

| 4 | BITMAP MINUS | | | | |

|* 5 | BITMAP INDEX SINGLE VALUE| T1_I3 | | | |

|* 6 | BITMAP INDEX SINGLE VALUE| T1_I1 | | | |

|* 7 | BITMAP INDEX SINGLE VALUE | T1_I1 | | | |

-----------------------------------------------------------------------

- 실행계획에 bitmap minus 연산이 두번 나타남. 비트맵 인덱스는 모든 키가 NULL인 엔트리를 포함하기 때문에, 두 번의 minus 연산이 나타난다. n1이 NOT NULL 임을 알고있다면 BITMAP MINUS 가 1번만 나타나도 된다. 해당 컬럼이 절대 NULL이 되지 않음을 알고 있다면, 이런 이유에서라도 테이블 정의에 사소한 정보를 더 포함해야 한다.

? 2개의 비트맵 인덱스가 OR로 같이 사용되면 비트맵 컬럼 내에 NULL의 개수를 놓쳐버릴 수 있다.(bitmap_or.sql 참조)

- 1,000,000개 튜플중 n1 컬럼이 NOT NULL인 로우는 정확히 1,000개, 1,000개의 distinct 값, density는 1/1,000이므로 옵티마이저는 카디널리티가 1이라고 결정할 것이다. n1을 n2로 변경해도 마찬가지이다.

  select small_vc

  from t1

  where n1 = 50000 orn2 = 50000

- 계산된 카디널리티 = 1,999 : 오라클은 NULL을 고려하지 않고 테이블 내 전체 로우의 개수에 density를 적용한 것으로 보인다. 이것은 두 조건의 and 연산에 대한 표준공식을 사용하여 n1 조건에 의한 1,000개(1,000,000 * 1/1,000)의 로우에 n2 조건에 의한 1,000개의 로우를 더한 후, 서로 겹치는 한 개의 로우를 뺀 값이다.

 

- is not null 조건을 하나 추가하면, 계산된 카디널리티가 1,000으로 떨어진다.

(n1 = 50000 and n1 is not null)

- is not null 조건을 하나 더 추가하면, 카디널리티가 정확히 1까지 떨어진다.

(n2 = 50000 and n2 is not null)




CPU costing 242 / 이창헌

 

alter session set "_optimizer_cost_model"=cpu

 

begin

       dbms_stats.set_system_stats('MBRC',8);

       dbms_stats.set_system_stats('MREADTIM',20);

       dbms_stats.set_system_stats('SREADTIM',10);

       dbms_stats.set_system_stats('CPUSPEED',350);

exception

       when others then null;

end

설정 bitmap_cost_05.sql

 

1.    실제 cup 비용이 대략 배가

2.       비트맵 인덱스의 i/o비용을 계산하는 코드는  cpu costing 활성화되면 다른 i/o수치를 제공함.


 

재미있는 사례들 244 / 이창헌


  비트맵 인덱스에서 약간 더 애매모호한 부분 몇 가지를  다중 컬럼 인덱스, 비트맵 변환에서 소개 합니다.


다중 컬럼 인덱스 244 / 남송휘

  •  필요예
  •  컬럼에 대한 distinct 값이 테이블 전체에 분산된 방식에 따라
  •  두컬럼에 대한 단일 비트맵 인덱스가 개별적인 두개의 비트맵 인덱스 크기의 합보다 실제로 더 작을 수있음


비트맵 조인 인덱스 (9i이상부터 추가)
    • 다른 테이블에서 가져운 키 값을 가짐

create bitmap index fct_dim_name on fact_table(dim.dim_name)
from
    dim_table    dim,
    fact_table    fct
where
    dim.id = fct.dim_id
;


매우 큰 팩트 테이블에 긴 디멘션명을 사용하는 인덱스를 생성하지만 디멘션명이 팩트 테이블에 수백만건 저장되지 않음

create bitmap index fct_dim_par on fact_table(dim.par_name)
from
    dim_table    dim,
    fact_table    fct
where
    dim.id = fct.dim_id
;

디멘션 테이블의 속성( 디멘션 ID보다 아주적은 distinct값을 가짐) 에 대한 쿼리를 통해서 팩트 테이블 액세스
(인덱스가 매우 작으며 유용- 사용자가 이런 속성을 빈번하게 사용한다고 가정)





bitmap_cost_06.sql



TABLE_NAME               BLOCKS   NUM_ROWS
-------------------- ---------- ----------
DIM_TABLE                    58      10000
FACT_TABLE            30526    1000000

2 rows selected.

Elapsed: 00:00:00.06

TABLE_NAME COLUMN_NAME   NUM_NULLS NUM_DISTINCT    DENSITY LOW_VALUE               HIGH_VALUE
---------- ------------ ---------- ------------ ---------- ------------------------ ------------------------
DIM_TABLE  DIM_NAME              0        10000      .0001 44696D656E73696F6E5F3030 44696D656E73696F6E5F3030
                                                           30303030                39393939

           ID                    0        10000      .0001 80                      C26464
           PAR_NAME              0          100        .01 506172656E745F303030     506172656E745F303939

FACT_TABLE DIM_ID                0        10000      .0001 80                      C26464
           ID                    0      1000000    .000001 C102                    C402
           PADDING               0            1          1 782020202020202020202020 782020202020202020202020
                                                           202020202020202020202020 202020202020202020202020
                                                           2020202020202020        2020202020202020




NAME             BLEVEL LEAF_BLOCKS       KEYS   NUM_ROWS    CLU_FAC LEAF_PER_KEY DATA_PER_KEY
------------ ---------- ----------- ---------- ---------- ---------- ------------ ------------
DIM_PK                1          20      10000      10000         52           1     1
FCT_DIM_NAME          2         625      10000      10000      10000           1     1
FCT_DIM_PAR           2         450        100        900        900           4     9


인덱스 생성후 실행


Execution Plan

-----------------------------------------------------------------------------
| Id  | Operation                     | Name        | Rows  | Bytes | Cost  |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |     1 |     9 |  2222 |
|   1 |  SORT AGGREGATE               |             |     1 |     9 |       |
|   2 |   TABLE ACCESS BY INDEX ROWID | FACT_TABLE  | 10000 | 90000 |  2222 |
|   3 |    BITMAP CONVERSION TO ROWIDS|             |       |       |       |
|*  4 |     BITMAP INDEX SINGLE VALUE | FCT_DIM_PAR |       |       |       |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("FCT"."SYS_NC00005$"='Parent_001')


  • 80/20 분할을 적용하면
  • 2000개는 넓게 흩어져 있고 8000개는 빈틈없이 모여있는것으로 추측
  • 2,000 + 8,000 / 32 ( 1,000,000 개의 로우 30526의 블록)
  • 약 2250 오차있음




인덱스 사용안했을경우
/*+ no_index(fct) */ 사용





Execution Plan
----------------------------------------------------------
Plan hash value: 1564920903

------------------------------------------------------------------
| Id  | Operation           | Name       | Rows  | Bytes | Cost  |
------------------------------------------------------------------
|   0 | SELECT STATEMENT    |            |     1 |    24 |  2947 |
|   1 |  SORT AGGREGATE     |            |     1 |    24 |       |
|*  2 |   HASH JOIN         |            | 10000 |   234K|  2947 |
|*  3 |    TABLE ACCESS FULL| DIM_TABLE  |   100 |  1500 |     7 |
|   4 |    TABLE ACCESS FULL| FACT_TABLE |  1000K|  8789K|  2937 |
------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("FCT"."DIM_ID"="DIM"."ID")
   3 - filter("DIM"."PAR_NAME"='Parent_001')


인덱스를 사용하고 db_file_multiblock_read_count 를 증가시킨후
alter session set db_file_multiblock_read_count = 20;


Execution Plan
----------------------------------------------------------
Plan hash value: 3000870606

-----------------------------------------------------------------------------
| Id  | Operation                     | Name        | Rows  | Bytes | Cost  |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |     1 |     9 |  2249 |
|   1 |  SORT AGGREGATE               |             |     1 |     9 |       |
|   2 |   TABLE ACCESS BY INDEX ROWID | FACT_TABLE  | 10000 | 90000 |  2249 |
|   3 |    BITMAP CONVERSION TO ROWIDS|             |       |       |       |
|*  4 |     BITMAP INDEX SINGLE VALUE | FCT_DIM_PAR |       |       |       |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("FCT"."SYS_NC00005$"='Parent_001')


값이 계산 결과에 근접





비트맵 변환 247  /남송휘

  • bitmap conversion (to rowids)  : 배열의 엔트리를 테이블 엔트리로 변환하는 계산
  • bitmap conversion (from rowids) : b-tree to bitmap conversion (bitmap_cost_07.sql)



bitmap_cost_07.sql


  NUM_ROWS     BLOCKS
---------- ----------
   1000000      18032


INDEX_NAME               BLEVEL LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR
-------------------- ---------- ----------- ------------- -----------------
T1_I1                         2        1951            50            604587
T1_I2                         2        1951            50            604886


Hinted bitmap combine
/*+ index_combine(t1 t1_i1 t1_i2) */

Execution Plan
----------------------------------------------------------
Plan hash value: 2658754337

--------------------------------------------------------------------------
| Id  | Operation                        | Name  | Rows  | Bytes | Cost  |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |       |   400 |  6800 |   188 |
|   1 |  TABLE ACCESS BY INDEX ROWID     | T1    |   400 |  6800 |   188 |
|   2 |   BITMAP CONVERSION TO ROWIDS    |       |       |       |       |
|   3 |    BITMAP AND                    |       |       |       |       |
|   4 |     BITMAP CONVERSION FROM ROWIDS|       |       |       |       |
|*  5 |      INDEX RANGE SCAN            | T1_I1 |       |       |    42 |
|   6 |     BITMAP CONVERSION FROM ROWIDS|       |       |       |       |
|*  7 |      INDEX RANGE SCAN            | T1_I2 |       |       |    42 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - access("N1"=33)
   7 - access("N2"=21)



Unhinted

Execution Plan
----------------------------------------------------------
Plan hash value: 2658754337

--------------------------------------------------------------------------
| Id  | Operation                        | Name  | Rows  | Bytes | Cost  |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |       |   400 |  6800 |   188 |
|   1 |  TABLE ACCESS BY INDEX ROWID     | T1    |   400 |  6800 |   188 |
|   2 |   BITMAP CONVERSION TO ROWIDS    |       |       |       |       |
|   3 |    BITMAP AND                    |       |       |       |       |
|   4 |     BITMAP CONVERSION FROM ROWIDS|       |       |       |       |
|*  5 |      INDEX RANGE SCAN            | T1_I1 |       |       |    42 |
|   6 |     BITMAP CONVERSION FROM ROWIDS|       |       |       |       |
|*  7 |      INDEX RANGE SCAN            | T1_I2 |       |       |    42 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - access("N1"=33)
   7 - access("N2"=21)


/*+ and_equal(t1 t1_i1 t1_i2) */


Execution Plan
----------------------------------------------------------

---------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows  | Bytes | Cost  |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |   400 |  6800 |   477 |
|*  1 |  TABLE ACCESS BY INDEX ROWID| T1    |   400 |  6800 |   477 |
|   2 |   AND-EQUAL                 |       |       |       |       |
|*  3 |    INDEX RANGE SCAN         | T1_I1 | 20000 |       |    42 |
|*  4 |    INDEX RANGE SCAN         | T1_I2 | 20000 |       |    42 |
---------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("N1"=33 AND "N2"=21)
   3 - access("N1"=33)
   4 - access("N2"=21)




  • 비트맵 엔트리와 rowid를 서로 변환할수 있다면 실행계획의 어떤 지점에서도 이 변환을 수행할수 있음(bitmap_cost_08.sql)



bitmap_cost_08.sql



select
    to_char(trunc(sysdate),'dd-mon-yyyy') today,
    to_char(trunc(sysdate) + 3,'dd-mon-yyyy') future
from dual;


TODAY       FUTURE
----------- -----------
24-jan-2010 27-jan-2010



TABLE_NAME               BLOCKS   NUM_ROWS
-------------------- ---------- ----------
T1                        32490    1000000


COLUMN_NAME           NUM_NULLS NUM_DISTINCT    DENSITY LOW_VALUE               HIGH_VALUE
-------------------- ---------- ------------ ---------- ------------------------ ------------------------
D1                            0         1000       .001 786E0118010101          78700A13010101
N1                            0            5         .2 80                      C105
PADDING                       0            1          1 782020202020202020202020 782020202020202020202020
                                                        202020202020202020202020 202020202020202020202020
                                                        2020202020202020        2020202020202020

V1                            0      1000000    .000001 30303030303030303031    30303031303030303030



NAME      BLEVEL LEAF_BLOCKS DISTINCT_KEYS   NUM_ROWS CLUSTERING_FACTOR AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY
----- ---------- ----------- ------------- ---------- ----------------- ----------------------- -----------------------
T1_D1          1          32          1000       1000              1000              1                1
T1_N1          1         140             5        280               280             28               56




select
    d1,
    count(*)
from
    t1
where
    n1 = 2
and    d1 between to_date('&m_today', 'DD-MON-YYYY')
           and to_date('&m_future','DD-MON-YYYY')
group by
    d1
;


Execution Plan
----------------------------------------------------------

-----------------------------------------------------------------------------------
| Id  | Operation                      | Name             | Rows  | Bytes | Cost  |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                  |     4 |    44 |    44 |
|   1 |  HASH GROUP BY                 |                  |     4 |    44 |    44 |
|*  2 |   VIEW                         | index$_join$_001 |   801 |  8811 |    41 |
|*  3 |    HASH JOIN                   |                  |       |       |      |
|   4 |     BITMAP CONVERSION TO ROWIDS|                  |   801 |  8811 |    2 |
|*  5 |      BITMAP INDEX RANGE SCAN   | T1_D1            |       |       |      |
|   6 |     BITMAP CONVERSION TO ROWIDS|                  |   801 |  8811 |    28 |
|*  7 |      BITMAP INDEX SINGLE VALUE | T1_N1            |       |       |      |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("N1"=2 AND "D1">=TO_DATE('2010-01-24 00:00:00', 'yyyy-mm-dd
              hh24:mi:ss') AND "D1"<=TO_DATE('2010-01-27 00:00:00', 'yyyy-mm-dd
              hh24:mi:ss'))
   3 - access(ROWID=ROWID)
   5 - access("D1">=TO_DATE('2010-01-24 00:00:00', 'yyyy-mm-dd
              hh24:mi:ss') AND "D1"<=TO_DATE('2010-01-27 00:00:00', 'yyyy-mm-dd
              hh24:mi:ss'))
   7 - access("N1"=2)








요약 250 / 위충환




테스트 스크립트 251 / 위충환