메뉴 건너뛰기

bysql.net

8. 비트맵 인덱스

2009.12.28 10:18

ZoneWorker2 조회 수:7952


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 / 위충환




번호 제목 글쓴이 날짜 조회 수
17 Front Page file 운영자 2009.12.21 130111
16 1. 비용(COST)이란? ZoneWorker2 2009.12.28 17925
15 12. 해시 조인 file 헌쓰 2009.12.28 16890
14 13. 정렬과 머지 조인 실천하자 2009.12.28 15945
13 9. 쿼리 변환 헌쓰 2009.12.28 14965
12 5. 클러스터링 팩터 balto 2009.12.28 14694
11 2. 테이블 스캔 balto 2009.12.28 13119
10 11. NL(Nested Loops) 조인 휘휘 2009.12.28 11783
9 14. 10053 트레이스 파일 file 휘휘 2009.12.28 10199
8 7. 히스토그램 ZoneWorker2 2009.12.28 9999
7 4. 단순 B-tree 액세스 file 휘휘 2009.12.28 8800
6 10. 조인 카디널리티 휘휘 2009.12.28 8758
5 3. 단일 테이블 선택도 ZoneWorker2 2009.12.28 8297
» 8. 비트맵 인덱스 ZoneWorker2 2009.12.28 7952
3 진행기록 운영자 2010.04.11 7622
2 6. 선택도 이슈 ZoneWorker2 2009.12.28 7524
1 비용기반의 오라클 원리 첫 모임 [4] 운영자 2010.01.04 5747