이 장의 목적
왜 Oracle은 기존의 I/O 기준의 Cost Model을 버리고 CPU(Time) 기준의 Cost Model을 소개했는가?
Time 기반의 Cost Model은 어떤 장점이 있고, I/O 기반의 Cost Model은 어떤 단점이 있는가?
I/O Cost Model의 단점은 I/O 회수를 기반으로 한 계산 방식이다.
( Cost = Single Block I/O Count + Multi Block I/O Count )
OPTIMIZER_INDEX_COST_ADJ
이현석 작성 : http://wiki.gurubee.net/pages/viewpage.action?pageId=1507599
박혜은 작성 : http://wiki.gurubee.net/display/DBSTUDY/OPTIMIZER_INDEX_CACHING+vs+OPTIMIZER_INDEX_COST_ADJ
Single Block I/OTime과 Multi Block I/O Time의 현실적인 비교가 가능해진다.
CPU오버헤드를 Cost 계산에 고려할 수 있다.
sreadtim과 mreadtime이 중요한 이유?
중요한 것은 이런 가중치가 우리가 임의로 지정하는 값에 따라 결정되는 것이 아니라 Oracle이 실제로 일을 수행하는(Workload)상황에서 실제 데이터에 기반해서 결정된다.즉, 시스템의 성능을 고려한 현실적인 가중치가 도출된다
예제) I/O Cost Model과 CPU Cost Model에서 Single Block I/O와 Multi Block I/O 비용이 어떻게 처리되는지 알아보자.
I/O Cost Model
select * from t1
where c1 between 1 and 1000;
---------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
---------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 985 | 198K| 32 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 985 | 198K| 32 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 985 | | 3 |
---------------------------------------------------------------------
select * from t1
where c1 between 1 and 2000;
---------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
---------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1986 | 399K| 64 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1986 | 399K| 64 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 1986 | | 5 |
---------------------------------------------------------------------
select * from t1
where c1 between 1 and 10000;
----------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 9988 | 2009K| 292 |
|* 1 | TABLE ACCESS FULL| T1 | 9988 | 2009K| 292 |
----------------------------------------------------------
Noworkload System Statistics
select * from t1
where c1 between 1 and 1000;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 985 | 198K| 32 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 985 | 198K| 32 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 985 | | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
select * from t1
where c1 between 1 and 2000;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1986 | 399K| 64 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1986 | 399K| 64 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 1986 | | 5 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
select * from t1
where c1 between 1 and 10000;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9988 | 2009K| 315 (0)| 00:00:04 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 9988 | 2009K| 315 (0)| 00:00:04 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 9988 | | 21 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
select /*+ full(t1) */ * from t1
where c1 between 1 and 10000;
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9988 | 2009K| 664 (1)| 00:00:08 |
|* 1 | TABLE ACCESS FULL| T1 | 9988 | 2009K| 664 (1)| 00:00:08 |
--------------------------------------------------------------------------
^script_io_cost_model.sql
^io_cost_model.sql
^script_Noworkload_System_Statistics.sql
^Noworkload_System_Statistics.sql
위의 테스트 결과에서 주목할 점
1. Time Cost Model 에서는 1~10000범위에서도 INDEX RANGE SCAN을 선택한다.
2. Plan의 결과에 추가적인 정보들이 기록된다.
Workload System Statistics
alter session set "_optimizer_cost_model"=cpu;
--set system statistics manually
begin
dbms_stats.set_system_stats('cpuspeed', 1680);
dbms_stats.set_system_stats('sreadtim', 5);
dbms_stats.set_system_stats('mreadtim', 10);
dbms_stats.set_system_stats('mbrc', 8);
end;
/
select * from t1
where c1 between 1 and 1000;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 985 | 198K| 32 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 985 | 198K| 32 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 985 | | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
select * from t1
where c1 between 1 and 2000;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1986 | 399K| 64 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1986 | 399K| 64 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 1986 | | 5 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
select * from t1
where c1 between 1 and 10000;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9988 | 2009K| 316 (1)| 00:00:02 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 9988 | 2009K| 316 (1)| 00:00:02 |
|* 2 | INDEX RANGE SCAN | T1_N1 | 9988 | | 21 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
select /*+ full(t1) */ * from t1
where c1 between 1 and 10000;
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9988 | 2009K| 761 (1)| 00:00:04 |
|* 1 | TABLE ACCESS FULL| T1 | 9988 | 2009K| 761 (1)| 00:00:04 |
--------------------------------------------------------------------------
^script_Workload_System_Statistics
^Workload_System_Statistics.sql
Manual로 설정한 System Statistics의 영향으로 table Full Scan비용이 664에서 761로 증가하였다.
System Statistics를 사용하는 경우 부정확한 mreadtim과 sreadtim이 목격될 수 있으므로, 필요하다면 DBMS_STATS.SET_SYSTEM_STATS procedure를 이용해 강제로 값을 조작해야 할 경우도 있다.