Database/Oracle2012. 3. 18. 10:48

Actual Cardinality 란?
 
Oracle이 실행계획을 수립하는데 있어서 가장 중요한 요소이며, 굳이 용어를 번역하면 "예상 로우(ROW)수" 가 된다.

Cardinality기본 개념

Cardinality는 특정 집합에 속한 원소(element)의 를 의미한다.

Oracle에서 Cardinality의 의미 네가지

 Base Cardinality           [기반]  특정 Table의 전체 Row 수를 의미한다.
 Calculated Cardinality   [산출]  Predicate(특정조건), 즉 조건절에 의해 Filtering된 Row 수를 의미한다.  
EX> [Table t1의 전체 Row 수가 1000 건이고 t1.c1 > 100 조건을 만족하는 Row 수가 100건이라고 가정]
Cardinality(t1) = 1000 이되며, Calculated Cardinality(t1.c1 > 100) = 100 이 된다.
 Estimated Cardinality    [추측]  Base Cardinality 이건, Calculated Cardinality이건 Oracle이 실행 계획을 세우는 단계에서 사용하는 모든 Cardinality[집합원의 개수]는 예측치이다. 혹은 Estimated Row Count라고도 한다.
 Actual Cardinality         [실제]  Query를 수행한 후 계산된 실제 Row 수를 의미한다.
Estimated Cardinality은 실행 계획 수립단계에서 알수 있으나, Actual Cardinality 은 실제 실행 후에만 알 수 있다.


Actual Cardinality에 사용하는 용어

 Density  특정Column의 농도. 즉 분포도가 얼마나 진한가를 나타낸다.
Distinct Count와  Skewness에 의해 결정된다.
 Distinct Count  NDV라고도하며, Distinct Count가 작을수록 column의 농도는 진하다. 반면 Distinct Count가 높으면 농도가 묽다.
Distinct Count = 1/NDV의 공식으로 계산된다.
 Skewness Data가 특정 값들에 편향되어 있는 경우를 Skewness가 높다라고 표현한다.
 Selectivity  특정조건(Predicate)의 선택도를 의미한다.
 *조동욱님 O3. 333~327page 참조*

Density 와 Selectivity의 차이

 Density는 특정 Column의 고정된 속성이다. 하지만 Selectivitys는 컬럼값이 아닌 Predcate에 따라 변하는 속성이다.

예를 들어 column c1의 Density 가 0.1 인 경우 [c1 = :b1] predicate의 selectivity는 0.1 이지만,
[c1 > : b1] Predicate의 selectivity는 0.05 이다. 
[c1 > 1] 의 Predicate의 selectivity 는? Column의 최대값과 최소값에 의해 결정된다.


Cardinality 예측 실습 [O3. 325페이지]

http://sites.google.com/site/ukja/books-cbo-in-depth/chapter5/01--cardinalities-sql 

조동욱님의 O3 325페이지를 보면서 위 조동욱님의 실습을 함께 하였다. 한번 한 이것을 다 나열하는 것보다는
TEXT 파일을 펼쳐서 직접 하나 하나 해보면서 결과를 보면 큰 도움이 된다.


출처 방형욱 oracle 강사님의 실습파일


주의 : O3교제와 함께 보며, 실습에 나오는 스크립을 알고 아래
 "[예측]실습 카페 정리 본" 은 위의 파일을 받아 "한번이라도 하고 하고 하길 바란다!'


Cardinality 예측 실습  

 카페 : http://cafe.naver.com/gseducation/469                                                       간편보기 "클릭" >>>>>>>>

생성하기

 drop table t1 purge;
 create table t1(c1 int, c2 int);
 create index t1_n1 on t1(c1+1);

 insert into t1
 select 1, mod(level, 2)+1
 from dual
 connect by level <= 10000
 union all
 select 2, mod(level, 300)+1
 from dual
 connect by level <= 1000
 union all
 select 3, mod(level, 50)+1
 from dual
 connect by level <= 100
 union all
 select 4, mod(level, 5)+1
 from dual
 connect by level <= 10;

commit;


 select c1, count(*) from t1 group by c1 order by 1;
 select c2, count(*) from t1 group by c2 order by 1;

 1. Histogram 없는 경우

  SQL> exec dbms_stats.gather_table_stats(user, 't1', method_opt=>'for all columns size 1');

 SQL> @tab_stat t1
  -----------------
 TABLE_NAME                   : T1
 NUM_ROWS                      : 11110
 -----------------
 TABLE_NAME                    : T1
 COLUMN_NAME                : C1
 NUM_DISTINCT                  : 4
 DENSITY                           : .25
 -----------------
 TABLE_NAME                    : T1
 COLUMN_NAME                 : C2
 NUM_DISTINCT                  : 300
 DENSITY                           : .00333333333333333
 -----------------

          set autot traceonly explain
          variable b1 number
  
1) select * from t1 where c1 = 1;      select 1/4  * 11110 from dual;
2) select * from t1 where c1 = :b1;   select 1/4  * 11110 from dual; 
3) select * from t1 where c1 > :b1;   select 0.05 * 11110 from dual;
4) select * from t1 where c1 = 0;           select (1/4 * 11110) - (1/4 * 11110 / (4-1)) from dual;
          select * from t1 where c1 = 5;     select (1/4 * 11110) - (1/4 * 11110 / (4-1)) from dual;
          select * from t1 where c1 = -1;    select (1/4 * 11110) - (1/4 * 11110 / (4-1)) - (1/4 * 11110 / (4-1)) from dual;
          select * from t1 where c1 = 6;     select (1/4 * 11110) - (1/4 * 11110 / (4-1)) - (1/4 * 11110 / (4-1)) from dual; 


  2. Histogram 있는 경우

 SQL> exec dbms_stats.gather_table_stats(user, 't1', method_opt=>'for all columns size skewonly');


 SQL> @tab_stat t1

 -----------------
 TABLE_NAME                    : T1
 COLUMN_NAME                : C1
 NUM_DISTINCT                 : 4
 NUM_NULLS                     : 0
 DENSITY                          : .000045004500450045
 LOW_VALUE                     : C102
 HIGH_VALUE                    : C105
 HISTOGRAM                     : FREQUENCY
 -----------------
 TABLE_NAME                   : T1
 COLUMN_NAME                : C2
 NUM_DISTINCT                 : 300
 NUM_NULLS                     : 0
 DENSITY                       : .406332971731016
 LOW_VALUE                     : C102
 HIGH_VALUE                    : C204
 HISTOGRAM                     : HEIGHT BALANCED
 -----------------

 TABLE_NAME           COLUMN_NAME          ENDPOINT_NUMBER ENDPOINT_VALUE
 -------------------- -------------------- --------------- --------------------
 T1                   C1                             10000 1()
 T1                   C1                             11000 2()
 T1                   C1                             11100 3()
 T1                   C1                             11110 4()
 T1                   C2                               113 1()
 T1                   C2                               228 2()
 T1                   C2                               229 4()
 ... 생략 ...
 T1                   C2                               253 286()
 T1                   C2                               254 300()


 
 
 Frequency : -> Density = (1/전체 Row의 개수) / 2

 1) select * from t1 where c1 = 1;     10000
 2) select * from t1 where c1 = :b1;   select 1/4 * 11110 from dual;  
 3) select * from t1 where c1 > :b1;   select 0.05 * 11110 from dual;
 4) select * from t1 where c1 = 5;     1
     select * from t1 where c1 = 6;     1

 
 Height-balanced : -> Density = sum of the square of the frequency of the nonpopular values /
                                    (number of nonnull rows * number of nonpopular nonull rows) (10.2.0.2 이후 버전 기준)

 1) select * from t1 where c2 = 1;     select 113/254 * 11110 from dual;
      select * from t1 where c2 = 4;     select .406332971731016 * 11110 from dual;
 2) select * from t1 where c2 = :b1;   select .406332971731016 * 11110 from dual;   
 3) select * from t1 where c2 > :b1;   select 0.05 * 11110 from dual; 
 4) select * from t1 where c2 = 301;   select (.406332971731016 * 11110) - (.406332971731016 * 11110 / (300 - 1))
                                                     from dual; 
   
    select * from t1 where c2 = 302;  
    select (.406332971731016 * 11110) - (.406332971731016 * 11110 / (300 - 1)) -(.406332971731016 * 11110 / (300 - 1))
    from dual; 














출처 : http://baind.tistory.com/entry/Cardinality

'Database > Oracle' 카테고리의 다른 글

[펌] SQL 바인딩 변수와 리터럴 상수 테스트  (0) 2012.03.18
[펌] granularity 란?  (0) 2012.03.18
[펌] Lock 과 Latch 분류표  (0) 2012.03.18
[펌] Latch 란 무엇인가  (0) 2012.03.18
[펌] Lock 개요  (0) 2012.03.18
Posted by 아로나