-- create objects
SQL>drop table t1 purge;
Table dropped.
SQL>create table t1(c1 int, c2 char(1));
Table created.
SQL>insert into t1
select
level,
case
when level between 1 and 5000 then 'A'
when level between 5001 and 8000 then 'B'
when level between 8001 and 9000 then 'C'
when level between 9001 and 9800 then 'D'
when level between 9801 and 10000 then 'E'
end
from dual
connect by level <= 10000
10000 rows created.
SQL>commit;
--통계 정보 수집 (Column c1은 Histogra이 없이, Columnc c2는 Bucket크기가 5가 되게끔 Histogram을 생성)
SQL>exec dbms_stats.gather_table_stats('ghlee', 't1', method_opt=>'FOR COLUMNS C2 T');
SQL>select table_name, num_rows, blocks, sample_size, last_analyzed from user_tables;
TABLE NUM_ROWS BLOCKS SAMPLE_SIZE LAST_ANALYZED
----- ---------- ---------- ----------- -------------------
T1 10000 20 10000 2009-02-14 02:18:50
SQL>select table_name, column_name, num_distinct, num_nulls, density
2 from user_tab_columns
3 where table_name = 'T1';
TABLE COLUM NUM_DISTINCT NUM_NULLS DENSITY
----- ----- ------------ ---------- ----------
T1 C1 10000 0 .0001
T1 C2 5 0 .00005
- Column c1의 NDV = 10000, Density = 0.0001(1/10000)
- Column c2의 NDV = 5, Density = 0.00005이다. Column c2는 Histogram이 있기 때문에 Density = 1/NDV의 공식을 따르지 않는다.
- istogram이 없을 경우의 Density가 1/5 = 0.2라는 것을 감안하면 매우 낮은 값으로 게산되었다는 것을 알 수 있다.
SQL>select table_name, column_name, endpoint_number, endpoint_value
2 from user_tab_histograms
3 where table_name = 'T1'
4 order by 3
5 /
TABLE COLUM ENDPOINT_NUMBER ENDPOINT_VALUE
----- ----- --------------- --------------
T1 C1 0 1
T1 C1 1 10000
T1 C2 5000 3.3815E+35
T1 C2 8000 3.4334E+35
T1 C2 9000 3.4854E+35
T1 C2 9800 3.5373E+35
T1 C2 10000 3.5892E+35
** Column c2는 5개의 Bucket으로 이루어진 Histogram을 가지고 있다.
SQL>explain plan for
2 select * from t1;
Explained.
SQL>select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 50000 | 7 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T1 | 10000 | 50000 | 7 (0)| 00:00:01 |
--------------------------------------------------------------------------
8 rows selected.
- Table t1은 전체 Row수가 10,000건(물리적인 Row수가 아니라 통계 정보에 있는 Rwo수를 의미)
- c1=:b1이라는 조건이 주어지면 Column c1의 Density는 0.0001이다. 따라서 c1=:b1이라는 단일 조건이 주어진 경우네는 Selectivity = Density 즉, 0.0001이 된다.
따라서 Cardinality = Base Cardinality (10000) * Selectivity (0.001) =1
SQL>variable b1 number;
SQL>explain plan for
2 select * from t1
3 where c1 = :b1;
Explained.
SQL>select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 7 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 5 | 7 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("C1"=TO_NUMBER(:B1))
13 rows selected.
- c2 = :b1이라는 조건은 Column c2의 Density는 0.00005이다. 만일 Density가 Selectivity산출 근거로 사용되었다면 Cardinality = Base Cardinality (10000) * Selectivity(0.00005) = 0.5 = 1이 된다.
하지만 Cardinality = 2000의 값을 보인다. 그 이유는 Selectivity = 1/NDV = 1/5=0.2의 값으로 계산되었기 때문이다.
즉, Histogram이 존재하는 경우네는 Selectivity계산에 Density가 아닌 NDV값이 사용된다.
SQL >explain plan for
2 select * from t1
3 where c2 = 'A';
Explained.
SQL >select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5000 | 25000 | 8 (13)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 5000 | 25000 | 8 (13)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("C2"='A')
13 rows selected.
- Histogram이 존재하는 C2에 대해 Data의 정확한 분포도를 알고 있다. 따라서 c2 = 'A'조건에 해당하는 Cardinality = 5000이라는 것도 알 수 있다.
SQL>variable a1 number;
SQL>variable b2 varchar2(20);
SQL>explain plan for
2 select * from t1
3 where c1 = :b1 and c2 = :b2;
Explained.
SQL>select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 7 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 5 | 7 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("C2"=:B2 AND "C1"=TO_NUMBER(:B1))
13 rows selected.
- Selectivity(p1 and p2) = Selectivity(p1) * Selectivity(p2)공식을 이용한다.
Selectivity(c1 = :b1) = 0.001이고, Selectivity(c2 = :b2) = 0.2가 된다. Selectivity = 0.001 * 0.2* 10000 = 0.2 = 1이 된다.
SQL>explain plan for
2 select * from t1
3 where c2 like '%A%';
Explained.
SQL>select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 500 | 2500 | 7 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 500 | 2500 | 7 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("C2" LIKE '%A%')
13 rows selected.
- 강좌 URL : http://www.gurubee.net/lecture/3848
- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.