SlideShare une entreprise Scribd logo
1  sur  161
Télécharger pour lire hors ligne
1
Function 수행과 SQL성능
개발자 교육자료
2013.03.02
DA팀 : 유재근
2
CONTENTS
• Warming Up
• Clustering Factor
• 스칼라 서브쿼리의 이해와 활용
- 스칼라 서브쿼리의 특성
- 조인이 유리한 경우
- 스칼라 서브쿼리가 유용한 경우
• Function수행과 SQL성능 문제
3
What is your DB management
level?
• Level 1
DB에 이상이 발생하면 조치한다.
• Level 2
주기적으로 모니터링 한다.
• Level 3
DB를 평소에 건강하게 관리한다.
- ACCESS PATH를 관리한다.
 실행계획을 관리한다.
4
Warming Up with some stretches
 ACCESS PATH
- Index Stretegy, partition
 JOIN METHOD
- NL JOIN, HASH JOIN, SORT MERGE JOIN, HASH_SJ, HASH_AJ……
 JOIN ORDER
- emp  dept, dept  emp
 Transformer (Logical Optimizer)
- Huristic Transformer / Cost Based Query Transformer
 ETC
- null, not null, buffer pinning, OWI, filtering optimization, function,
case, decode, nvl, pagenation, ….
5
DATA Modeling & Business Rule
INDEX현황 employees : (JOB_ID)
orders : (EMPLOYEE_ID, ORDER_DATE)
위 SQL을 어떻게 최적화 해야 할까?
6
DATA Modeling & Business Rule
• 요구사항
Employees 테이블의 job_id=‘J04’이면서 주문날짜(order_date)가
2012년01월01일 부터 2012년06월01일 범위 이며 주문상태
(order_status)가 ‘10’인 employee_id와 last_name을 출력하시오.
• Data modeling과 Business Rule을 모르면 최적의 SQL 작성 불가
능하다.
7
DATA Modeling & Business Rule
튜닝포인트
1. Employees 테이블에서 employee_id는 unique하다.
2. Orders 테이블 데이터(N개)를 모두 join할 필요가 없다.
3. 조건절을 만족하는 데이터 하나만 만나면 Join을 중단하자.
8
DATA Modeling & Business Rule
아쉽지만 11g에서는 Transformer가 위와 같이 튜닝전 SQL을 변경하지는 못한
다. 양심적인 개발자(인간)가 SQL을 잘 만들어야 한다.
9
OPTIMIZER BASICS
• Three main questions you should ask when
looking for an efficient execution plan:
1. How much data? How many rows? Volume?
2. How scattered / clustered is the data?
3. Caching?
=> Know your data!
10
OPTIMIZER BASICS
• Why are these questioins so important?
 Two main strategies:
1. One “Big Job”
=>How much data, volume?
2. Few/many “Small Jobs”
=>How many times / rows ?
=>Effort per iteration? Clustering/Caching
11
OPTIMIZER BASICS
• Optimizer’s cost estimate is based on:
 How much data? How many rows?
 How scattered / clustered ?(partially)
 (Caching?) Not at all : 11g
12
SUMMARY
• Cardinality and Clustering determine
whether the “Big Job” or “Small Job”
strategy should be preferred
• If the optimizer gets these estimates rigtht,
the resulting execution plan will be
efficient within the boundaries of the given
access paths
• Know your data and business questions
• Help your optimizer. (Oracle doesn’t know
the data the way you know it.)
13
Today’s LEMA
 Oracle doesn’t know the
data the way you know it!!
 Inefficient Execution Plan
50% Oracle Does not know the data.
50% SQL writers Do not know the
optimizer.
14
AGENDA
 Clustering Factor
 Statistics / Histograms
 Datatype issues
15
HOW SCATTERED / CLUSTERED?
• INDEX SCAN  TABLE BLOCK
• Worst Case
1,000 rows => visit 1,000 table blocks:
1,000 * 5ms = 5s
• Good Case
1,000 rows => visit 10 table blocks: 10*5ms = 50ms
16
HOW SCATTERED / CLUSTERED?
• There is only a single measure of clustering
in Oracle:
The index clustering factor
• The index clustering factor is represented
by a single value
• The logic measuring the clustering factor by
default does not cater for data clustered
across few blocks(ASSM!)
17
HOW SCATTERED / CLUSTERED?
 Challenges
 Getting the index clustering factor right
 There are various reasons why the index
clustering factor measured by Oracle might not
be representative
- Multiple freelists / freelist groups
- ASSM (automatic space segment management)
- Partitioning
- SHRINK SPACE effores
18
HOW SCATTERED / CLUSTERED?
19
HOW SCATTERED / CLUSTERED?
• ASSM에서는 동시에 여러 세션이 입력 시
clustering이 나빠진다.
• ASSM에서는 동시에 같은 block에 데이터
를 insert하는 것을 피한다.
(freelist관리)
• 이런 경우에는 clustering factor가 나빠서
많은 read block이 발생해도 성능이 나빠
지지 않는다.(?)
20
• The CF in case of an index range scan
with table access involved represents the
largest fraction of the cost associated
with the operation. (See 10053 trace file)
HOW SCATTERED / CLUSTERED?
21
STATISTICS
• Basic Statics:
- Table Statistics: Blocks, Rows,
AvgRowLen
- Basic Column Statistics:Low/High Value,
Num Distinct, Num Nulls
22
Statistics
• Controlling column statistics via METHOD_OPT
 FOR ALL INDEXED COLUMNS SIZE > 1:
 Nonsense, without basic column
statistics
 Default from 10g on:
FOR ALL COLUMNS SIZE AUTO:
basic column statistics for all coumns,
histograms if Oracle determines so
23
HISTOGRAMS
• Basic column statistics get generated
along with table statistics in a single pass
• Each histogram requires a separate pass
• Therefore Oracle resorts to aggressive
sampling if allowed =>AUTO_SAMPLE_SIZE
• This limits the quality of histograms and
their significance
(basic column statistics는 거의 모든 row를 대상으로 하
나, histogram은 극히 일부 row를 sampling)
user_tab_col_statistics 참조
24
HISTOGRAMS
• Limited resolution of 255 value pairs
maximum
• Less than 255 distinct column values =>
Frequency Histogram
• More than 255 distinct column values
=>Height Balanced Histogram
• Height Balanced is always a sampling of
data, even when computing statistics!
25
HISTOGRAMS
• Aggressive sampling
• Oracle doesn’t trust its own histogram
information when caculating estimated
cardinality.
• Very bad cardinality estimation 
inefficient execution plan
26
Frequency Histograms
• When it consists of only a few popular
values
• Very popular and nonpopular values
• Dynamic sampling also is not
representative
• Statistics is sometimes inconsistent
27
Height Histograms
• Rounding effects
• They cannot cover all values.
• Histogram values are unstable.
(when you gather histograms, the values
can be different.)
• Oracle doesn’t know the data the way
you know it.
28
Height Histograms
5000 is considered unpopular, even though it is a very popular
value.
29
Height Balanced Histograms
INDEX range scan, height balanced histograms can be very useful.
30
SUMMARY
• Check the correctness of the CF for your
critical indexes
• Oracle does not know the questions you
ask about the data
• You may want to use FOR ALL COLUMNS
SIZE 1 as default and only generate
histograms where really necessary
• You may get better results with the old
histogram behavior, but not always
31
SUMMARY
• There are data patterns that don’t work well
with histograms
• => You may need to manullay generate
histograms using
DBMS_STATS.SET_COLUMN_STATS for
critical columns
• Don’t forget about Dynamic
Sampling/FBI/Virtual Columns/Extended
Statistics
• Know your data and business questions!
32
10053 Trace File
• SYSTEM Statistics Information
- CPU SPEED, SBRDTime, MBRDTime, MBRC
• 테이블/인덱스 Statistical Information
- Base Cardinality, Density, CLUF
• Cardinality Estimation
• Cost Estimation
- Access Type, Join Type, Join Order
• 예측은 틀릴 수 밖에 없다.
33
COST?
• Jonathan Lewis
• The cost represents (and has always
represented) the optimizer’s best
estimate of the time it will take to
execute the statement.
• Query의 예상 수행 시간(Time)
34
Time으로서의 Cost
• Total Time = CPU Time + I/O time + Wait Time
• Estimated Time
= Estimated CPU time + Estimated I/O time
= Estimated CPU time + Single Block I/O time
+ Multi Block I/O time
35
Time으로서의 Cost
• Oracle은 COST에 정규화(인위적인 가공)을 수행
• 모든 Time의 합을 평균 Single Block I/O Time으로 나눈다.
• 왜 그럴까? Oracle Optimizer의 역사에 대한 이해가 필요
• 과거 System Statistics 개념이 소개되기 전에는 I/O Model이 Cost계산의 기본
Model이었다. 즉, Cost란 곧 I/O Count였다.
• I/O Count를 Time으로 변환하는 것이 불가능하기 때문에 역으로 Time을 I/O
Count기준으로 정규화하는 방법을 선택했다.
36
Time으로서의 Cost
• Total Time = CPU Time + I/O time + Wait Time
• Estimated Time
= Estimated CPU time + Estimated I/O time
= Estimated CPU time + Single Block I/O time +
Multi Block I/O time
• COST = (Estimated Time / Single Block I/O Time)
cost가 높다 = 수행시간이 길다
= Single Block I/O count + 보정Multi Block I/O count + 보
정CPU count
 모든 예상 수행 시간을 single block I/O time에 대한 가중치
를 고려한 count값으로 변환
 I/O Cost 방식보다 진보
37
System Statistics
• 10g 이후 부터는 DBA가 통계정보를 수집
하지 않아도 CPU mode 사용
38
Cost 정보 예
• Column C1 하나만 fetch하는 것과 C1, C2
를 fetch하는 것은 비용이 다르다.
• Predicate이 추가되거나 복잡해져도 CPU
비용이 증가한다.
39
DB_FILE_MULTIBLOCK_READ_COU
NT
• Cost 계산 시에는 System Statistics의
mbrc값을 사용한다.
• 하지만, 실제 Query를 수행할 때는
DFMBRC값을 사용한다.
40
Time Model 한계
• Mreadtim 과 sreadtim 값의 부정확성
• Enterprise 환경의 Storage는 sreadtim이
mreadtim보다 더 높은 다소 비현실적인
현상 발생
• dbms_stats.set_system_stats procedure를
이용해 강제로 값을 조작
41
CBO의 기본 흐름
SQL
Statement
Parse
Transformation
(logical optimization)
Optimization
(Physical Optimization)
Exexution
Plan
Result Set
42
Basic Terminalogy
• Density : 밀도, 분포도
가. Histogram이 없는 경우 : 1/NDV
나. Histogram이 있는 경우 : unknown
• Cardinalty : 조건을 만족하는 집합의 수
Cardinality = Base Cardinality * Selectivity
• Selectivity : 특정조건(predicate)을 만족할
확률
• Histogram : 분포도, 막대그래프
43
Cardinality 계산
-C2 컬럼만 histogram 수집함
-C2 컬럼의 density는 1/NDV보다 훨씬 작은 값
44
• C2 = :b 조건 : Histogram(frequency
histogram)이 존재하면 selectivity계산에
Density가 아닌 NDV값이 사용된다.
• C2= ‘A’ 조건 : 상수값이 입력되면
Histogram덕분에 조건에 해당하는
cardinality를 알 수 있다.
45
Cardinality계산
C2= :b1 조건이라면 cardinality를 얼마로 예상할까?
Cardinality = base cardinality * selectivity
즉, C2=:b1 의 selectivity는 얼마일까?
46
Cardinality 계산
즉, C2=:b1 의 selectivity는 얼마일까?
Frequency hostogram이 존재하는 경우 selectivity 계산에 density가 아닌
NDV를 사용한다.
따라서 selectivity = 1/5 = 0.2 이다.
그럼 C2=‘B’라고 하면 cardinality를 얼마로 예상할까?
47
Cardinality 계산
CBO는
Frequency Histogram 덕분에 Data의 정확한 분포를 알고 있다.
그렇다면,
C2 like ‘%A%’ 조건은 어떻게 cardinality를 예상할까?
48
Cardinality
그렇다면,
C2 like ‘%A%’ 조건은 어떻게 cardinality를 예상할까?
어떻게 해서 cardinality를 500로 계산해 냈을까?
(Magic Number **% RULE)
Googling 해봐라.
49
Index Scan Cost
• 전체 Row수 중 얼마를 읽어야 Index
Scan이 Table Full Scan보다 효율적일까?
• CBO는 Index Scan과 Full Table Scan의
Cost를 기계적으로 계산
• 10053 Trace file 내용
• Cost계산 방식 이해  CBO가 왜 Index
Scan/Full Table Scan하는지 이해할 수 있
다.
50
Table Full Scan Cost 계산 예제
• 다음과 같은 데이터를 가정
Blocks = 100
MBRC = 4
sreadtim = 5
mreadtim = 10
• COST = Single Block I/O Count +보정 Multi Block I/O Count + 보정
CPU Count
• 보정Multi Block I/O Count
= MBI/OC * 가중치
= (Blocks/MRC) * (mreadtim / sreadtim)
= (100/4) * (10/5) = 50
• 보정CPU Count = small value
• COST = 0 + 50 + <CPU> = 50.xxx.
• Table Full Scan의 COST = f (Table Block수, MBRC, multi block read 가
중치)
• 한번에 읽을 것으로 예상되는 Block수(MBRC)가 클수
록 Cost는 작아진다.
51
Index Scan Cost
• 조건을 만족하는 최초의 Index Leaf Block까
지 찾아간다.
• 조건을 만족하는 Index Key를 순서대로 fetch
하면서
• Rowid를 이용해 Table Block을 하나씩 읽으
면서
• 조건에 해당하는 Row를 Fetch한다.
• Cost = root block에서 leaf block까지 찾아가는 Cost
+조건에 맞는 Index Leaf Block을 읽는 Cost
+조건에 맞는 Table Block을 읽는 Cost
52
Index Scan Cost
• Cost = root block에서 leaf block까지 찾아가는 Cost
+조건에 맞는 Index Leaf Block을 읽는 Cost
+조건에 맞는 Table Block을 읽는 Cost
• root block에서 leaf block까지 찾아가는 Cost
= Blevel = Index Height -1
• 조건에 맞는 Index Leaf Block을 읽는 Cost
= 전체 Leaf Block * (Index) Selectivity
• 조건에 맞는 Table Block을 읽는 Cost
= Clustering Factor * (Table) Selectivity
- CF : Index Key에 해당하는 Table Block을 매번 새로 읽어야 하는 회수
53
Index Scan Cost
• Cost = root block에서 leaf block까지 찾아가는 Cost
+조건에 맞는 Index Leaf Block을 읽는 Cost
+조건에 맞는 Table Block을 읽는 Cost
= Blevel +
Leaf Blocks * Index Selectivity +
CF * Table Selectivity +
보정 CPU count
Index Height, Selectivity, Leaf Block수, CF에 의해 결정
테이블 data block수 <=CF =< 테이블 row count이므로
CF는 상당히 큰 숫자로 COST에서 차지하는 비중이 크다.
54
Index Scan Cost
• Cost = root block에서 leaf block까지 찾아가는 Cost
+조건에 맞는 Index Leaf Block을 읽는 Cost
+조건에 맞는 Table Block을 읽는 Cost
= Blevel +
Leaf Blocks * Index Selectivity +
CF * Table Selectivity +
보정 CPU count
넓은 범위(leaf block이 많다)의 Data는 Index를 경유하
지 말라.
55
Clustering Factor
• A measure of the orderedness of an
index in comparison to the table that it
is based upon. It is used as an indicator
for computing the estimated cost of the
table lookup following an index access.
• Index Key가 Table Row에 대해 얼마나 비
슷한 순서로 저장되어 있는가
56
Clustering Factor
• Good Clustering Factor
Index = 1,2,3,4,5,6,7,8,9,10,….
Table = 1,2,3,4,5,6,7,8,9,10,….
• Bad Clustering Facotr
Index = 1,2,3,4,5,6,7,8,9,10,…
Table = 3,8,7,1,4,5,10,2,6,9,…
Index = 1,2,3,4,5,6,7,8
Table = 8,7,6,5,4,3,2,1 Good or Bad?
57
CF 측정 방법
• The CF records the number of data
blocks that will be accessed when
scanning an index.
• 전제조건
1. 단 하나의 Table Data Block만을
Memory에 Cache할 수 있다.
2. CF는 Physical Reads, 즉 Cache에 존재하
지 않아 Disk에서 읽는 경우만 증가한다.
58
CF 특정 방법
1 2 3
1 2 3
INDEX
TABLE
Index
Block
Table
Block
59
CF 특정 방법
1 2 3
1 3
INDEX
TABLE
Index
Block
2
60
위에서 CF는 얼마일까?
CF의 최소값 : Table의 Data Block 수
CF의 최소값
61
CF의 최대값
위에서 CF는 얼마일까?
CF의 최대값 : Table의 Row 수
62
CF and Performance
Histogram 수집 X
통계정보 수집
63
CF and Performance
왜 c2 컬럼에 있는 index를 경유하지 않을까?
64
CF and Performance
왜 c2 컬럼에 있는 index를 경유하지 않을까?
COST =
Blevel +
Leaf blocks * Index Selectivity +
CF * Table Selectivity + 보정된 CPU count
Blevel + Leaf blocks* Index Selectivity 부분은 Cost가 ‘2’에 불과하지
만, CF*Table Sectivity를 합해보니 cost가 97로 커졌다.
Table의
Selectivity
는 얼마일
까?
65
CF and Performance
• CF가 Selectivity 못지 않게 Index Lookup
의 Cost를 결정짓는 중요한 요소
• 앞의 예제는 row count가 10000건에 불과
하다. Selectivity가 1%임에도 불구하고,
Index Lookup 비용이 더 높다.
• 그럼 실제 성능 차이가 있다면 그 정도는
얼마일까?
66
CF and Performance
67
• 위에서 logical reads 횟수는 얼마일까?
CF and Performance
68
Buffer Pinning
• 한 번의 fetch에서 두 번 연속 방문하는 Block에 대해서
Pinning을 수행한다.
• Pinned Block에 대해서는 cache buffers chains latch를 획
득하는 일련의 과정을 거치지 않고 Memory Address를 이용
해 직접 읽는다.
• Buffer Pinning에 의해서 읽기작업의 오버헤드가 완전히 없어
지지는 않는다.
69
Cache Buffers Chains Latch
• 한 세션에서 bad SQL문이 수행 될 경우 다량의 버퍼를 접근하게 되며 특정 cache buffers chains
latch를 자주 획득하게 된다.
70
Buffer Pinning
• 위에서 T_CLSF_I1 인덱스를 경유하여 Table을
access시에 logical reads는 (4-3)1이다.
• T_CLF_I2 인덱스를 경유하여 Table을 access
시에 logical reads는 95-3=92이다. CF는 나
쁘지만 약 8개 정도는 buffer pinning이 발생
했음을 알 수 있다. 완전히 random했다면, 방
문 buffer수가 100개가 되었을 것이다.
71
CF를 줄이는 방법
• Index 통계에 있는 clustering factor 값이 row
count에 가까울 경우, CF값을 줄일 수 있는
방법은 무엇일까?
• 넓은 범위의 Index Scan을 최대한 피하라.
• 넓은 범위의 Index Scan이 필요한 경우에는
가능한 Index Fast Full Scan을 사용하라.
72
Controlling Index Scan Cost
• Optimizer_index_caching : default 0
• Oracle은 Index가 Memory에 Caching되어
있지 않다는 전제하에 Cost를 계산한다.
• Cost 계산의 한계
• ‘0’보다 크게 지정 : Index Scan이 저렴하다
는 가정을 세우고 이를 Cost계산에 반영
73
Controlling Index Scan Cost
• Optimizer_index_cost_adj : default 100
• 100은 Index Scan Cost를 기본 공식 그대
로 100% 계산
• 50은 Index Cost를 50% 감소시킨다.
74
Parameter vs. System Statistics
• System Statistics 값 중 sreadtim값과
mreadtim값이 파라미터를 대신하는 역할
을 한다.
System Statistics값
에 mbrc값이 존재하
면,
DB_FILE_MULTBLOCK
_READ_COUNT 파라
미터는 더 이상 Cost
계산에 사용되지 않
는다.
75
Buffer Read 횟수
76
Index Range Scan Cost = Root Block I/O Count + Leaf Block I/O Count
Fetch Call 단위가 바뀔 때마다 매번 Block을 새로 읽어야 한다.
Buffer Read 횟수
Cost 20은 어떻게 계산해서 나온 것일까?
Buffer Read 횟수 118은 어떻게 계산해서 나온 것일까?
77
Buffer Read 횟수
C1 컬럼을 추출하지 않고 Count값만 가져오는 경우는 Logical Read가 20
이다. 이 값은 Index의 Root Block + Leaf Block수와 일치한다.
한번의 Fetch만으로 Leaf Block을 Range Scan하는 경우는 Leaf Block의 수
만큼만 Read가 발생한다.
즉, Fetch Call단위가 바뀔 때마다 매번 Block을 새로 읽어야 한다.
Fetch Call의 횟수,
즉 Fetch Array Size가 Index Range Scan의 Leaf Block 방문 회
수를 결정한다.
하지만, Cost 계산에는 Fetch Call횟수는 고려되지 않는다. Index Range
Scan의 Cost는 방문해야 할 Block의 수에 의해 결정된다.
78
INDEX Range Scan 특성
• Index Key를 삭제(Delete)해도 Leaf Block의
수는 동일하다.
• 읽어야 할 Index Leaf Block의 수도 동일하다.
(Index Key를 아무리 삭제해도 모든 Leaf
Block들이 다 탐색 대상이 된다.)
 Oracle은 Leaf Block을 방문하지 않고서
는 key의 삭제 여부를 알 수 없다.
• Key가 삭제된 경우 실제 “Fetch”가 발생하지
않으므로 Fetch Call 회수가 줄어든다.
 Leaf Block을 줄이려면 rebuild, coalesce,
shrink 명령을 수행하라.
79
INDEX Leaf Block 줄이기
모든 데이터가 없는데도 오라클은 20개의 Block을 방문한다.
방문하는 Leaf Block 수를 줄이려면 어떻게 해야 할까?
80
INDEX Leaf Block 줄이기
Coalesce or Rebuild 후 성능향상을 기대할 수 있다.
81
용어 정의
• 스칼라 서브쿼리
• 인라인 뷰
• 서브쿼리
Select t1.c1, t2.c2, (select fun_nm(c1) from t2)
From t1,
(select t3.c1 from t3),
Where t1.c1 = t2.c1
and t2.c2 not in (select c2
from t1);
82
테스트 테이블(T1)
83
테스트테이블(T2)
84
테스트테이블(T3)
85
스칼라 서브쿼리의 특성
작성자 의도 : T1 테이블에서 c1, c2 컬럼으로 정렬하여 10개만 추출한다.
단, T2테이블의 c3컬럼은 T1 테이블의 c1값과 T2테이블의 c1값이 같을 경
우에만 추출하고, 동일한 데이터가 없으면 NULL을 추출해야 한다.
select rownum rnum, x.*
from ( select c1, c2, c3, (select t2.c3
from scalar_t2 t2
where t2.c1 = t1.c1) as c2_c3
from scalar_t1 t1
order by c1, c2
) x
where rownum <= 10;
위 SQL의 실행계획은 어떻게 될 것인가?
미리 비효율을 예상해 보시오.
86
10건을 추출하는데 T2 테이블은 50만번 반복 access했다.
비효율적이다.
위 쿼리를 효율적으로 바꿀 수 있을까?
특징1. 스칼라 서브쿼리는 결과 건수만큼
반복적으로 수행된다.
87
스칼라서브쿼리 수행 위치를 변경했다.
Index access 수가 50만번에서 10번으로 줄었고,
Buffer cache access 수가 15만개에서 1천개로 줄었다.
만약 위에서 rownum<=10 조건이 없다면 1번쿼리? 2번쿼리 어느 것이 유리할까?
88
스칼라 서브쿼리의 특성
• Deterministic 속성
• 입력 값에 대한 결과 값을 multi buffer에
저장
• 서브쿼리의 filter optimization과 같은 원
리
• Multi buffer size : default 64K
_query_execution_cache_max_size
89
스칼라 서브쿼리와 조인의 관계
select /*+ gather_plan_statistics */ t1.c2, t1.c1, t1.c3,
(select t2.c3
from scalar_t2 t2
where t2.c1 = t1.c1) t2_c3,
(select t3.c3
from scalar_t3 t3
where t3.c1 = t1.c1) t3_c3
from scalar_t1 t1
order by t1.c1, t1.c2;
위 쿼리문에서 어떤 비효율이 있을지 예상해 보시오.
그리고 그 비효율을 없앨려면 어떻게 어떻게 해야 할까?
정답
90
91
배치프로그램vs스칼라서브쿼리
• 배치프로그램(많은 데이터추출)은 스
칼라 서브쿼리를 사용하지 말자.
• 배치프로그램에서는 스칼라서브쿼리를
Outer Join으로 변경하고, Hash Join으로
변경하자.
• 제약사항
1) Outer Join으로 변경(항상 조인에 성공하면
Outer Join으로 처리하지 않아도 됨)
2) 조인 연결 컬럼의 값은 항상 Unique해야 한다.
92
조인방식으로 개선 후
Outer join시 T1이 driving되어야 하나, 위에서는 Right는 driving테이블이 변
경되었음을 의미함
93
조인vs. 스칼라 서브쿼리
Q: Compared to the join method, are
sacalar subqueries always inefficient?
A : No, sometimes scalar subqueries are
more desirable.
Q : When subqueries are more efficient?
94
조인 vs. scalar subquery
select rownum rnum, x.*
from (select /*+ leading(T1) USE_NL(T1 T2 T3) */
t1.c1, t1.c2, t1.c3,
t2.c3 as t2_c3,
t3.c3 as t3_c3
from scalar_t1 t1, scalar_t2 t2, scalar_t3 t3
where t1.c1 = t2.c1(+)
and t1.c1 = t3.c1(+)
order by t1.c1, t1.c2) x
where rownum <= 10;
위 쿼리의 실행계획을 보지도 않고, 어디서 비효율이 발생할지 예상할 수
있으면, 당신은 진정한 GURU다.
95
반복적인 INDEX SCAN으로 I/O 과다 발생
 반복적인 INDEX SCAN 줄이기 위해 HASH로 유도
96
아래의 실행계획이 HASH JOIN으로 유도한 실행계획임
아래 실행계획이 위 NL JOIN보다 효율적인 이유를 설명하시오.
아래 실행계획에는 어떤 비효율이 있을까?
97
조인연결 컬럼이 Unique
T1테이블에서 10건 추출 후 T2테이블, T3테이블 조인해도 무결성 유지
개선방안
1) T1테이블에서 10건 추출 후, T2와 T3 테이블을 **조인 방법으로 수행하도
록 변경
2) 스칼라 서브쿼리로 변경
위 쿼리문을 스칼라 서브쿼리를 활용하도록 변경하시오.
98
99
스칼라서브쿼리vs조인 사용기준
• 추출 데이터가 적은 경우(Online 프로그램)
 스칼라서브쿼리 OK
 조인을 스칼라 서브쿼리로 변경 고려
• 추출 데이터가 많은 경우(Batch 프로그램)
 스칼라서브쿼리 NO!
 스칼라서브쿼리를 조인으로 변경 후
Hash Join 유도하는 것을 고려
100
WITH절 이해와 효율적인 SQL
• 동일한 데이터를 반복적으로 읽어야 하는
SQL의 성능을 개선하기 위한 방법으로 사
용
• /*+ MATERIALIZE */
• /*+ INLINE */ with절의 결고 셋을 1회만 수행
101
MATERIALIZE 동작 방식
1. Global temporary table 생성
2. Global temporary table에 with절에서 추
출한 데이터 insert
3. Global temporary table 조회하여 데이터
처리
102
SQL에서 with절이 1회만 수행되므로 INLINE동작방식을 선택
T_T1 with절은 힌트때문에 Materialize 동작 방식
103
Outer join이므로 어쩔수 없이 T1 테이블을 드라이빙해서 T2테이블과 조인수행
조인한 결과를 T3 테이블(추출건수가 많으므로)과 HASH JOIN수행
위 실행계획에는 어떤 비효율이 있는가?
어떤 실행계획이 되어야 효율적으로 데이터를 추출할 수 있을까?
힌트 : T1 테이블의 추출 데이터 건수가 적다.
104
실행계획 제안
1. T1.C1 = T3.C1(+) 조건이 T3 인라인뷰 내부로 침투하도록 한다.
그러면, T3의 access 량이 대폭 줄어들 것이다.
2. T1 테이블에서 추출한 값을 인라인 뷰로 만든 후 인라인뷰T3 안에 강제로 추
가한다.
3. With절을 선언하여 필요한 데이터를 미리 추출한 후, 필요할 때마다 재사용한
다.
105
T1 테이블을 2회 access
위 실행계획의 비효율은 무엇일까?
개선후1
106
개선후2
개선후1 보다 일량이 많지만, 동일한 데이터를 2번 처리하는 비효율은 개선
107
WITH절 주의사항
• 동시성이 높은 경우 materialize방식 지양
- DISK I/O 발생하면서 control file
sequential read Wait Event 빈번 발생
• 추출건수가 많으면, materialize방식 사용
시 DISK I/O 다량 발생 발생
• WITH절 적당한 동작방식 힌트 부여
108
초급개발자가 만든 SQL문
109
User Defined Function의 이해
Is this execution plan efficient?
At the end of this workship you
will be able to raise questions.
110
2) SQL 수정 후 실행계획 및 일량
111
FUNCTION 기본내용
• 리턴 값이 있다.
• 데이터베이스 객체로 저장, 컴파일 된 상
태에서 수행된다.
• 예외처리가 가능하다.
• 모듈화된 프로그램이 가능하다.
• 변수 및 다양한 제어문 사용이 가능하다.
• WAS서버와 Network 부하를 줄일 수 있다.
• 유지보수 측면에서 매우 효율적이다.
112
FUNCTION 기본내용
• Deterministic Function
- 입력 값이 같다면, 리턴 값도 항상 같음을
선언하는 Function
- 입력값이 같으면 Function을 매번 수행하지
않고 메모리 내에 Cache된 결과 값을 바로 가
져와 사용 (fetch call 내에서만 유효)
• Not Deterministic Function
- 입력값을 가져와 결과 값을 리턴
- 캐싱효과를 얻으려고 함부로 deterministic
선언하는 것은 위험한 일
113
Function 생성 예제
114
TT테이블에
YAMHHA값이 없
으므로 함수 수행
결과는 no row여
야 하나, 1 row가
출력됨
Deterministic 선언 위험성
Fun_lookup 함수 생성
--TT테이블을 읽어서
value컬럼값을 출력함
Test테이블에서 NO컬럼을 읽어서
함수를 수행한 결과가 ‘YAMHHA’
인 row를 출력
115
User Defined Function vs. Bulit-In
함수
116
User Defined Function vs. Bulit-In
함수
함수 내에 recursive call이 없어도 속도가 느려졌다.
Recursive call이 함수 내에 있으면 속도가 더 느려진다.
USER DEFINED FUNCTION을 남용하지 말아야 하는 이유
다음 slide참조
117
User Defined Function vs. Bulit-In
함수
I/O가 전혀 발생하지 않는 function(Dual테이블은 I/O가 없다)을 수행했
을 뿐인데도 elapsed time이 2.56초에서 18.88초로 9배 증가
원인 : 10046 Trace file  DB call이 2백만번 발생
parse 1회, execute 1백만, fetch 1백만
118
함수와 읽기 일관성
• 문장수준 읽기일관성을 보장하지 않는다.
• 함수 내에서 수행되는 recursive쿼리는 메인
쿼리의 시작 시점과 무관하게 그 쿼리가 수행
되는 시점을 기준으로 블록을 읽는다.
• 함수 내에 쿼리 문장을 포함하고 있다면 그
함수는 일관성이 보장되지 않는다.
select fun_dept_nm(c1) from emp;
 위 SQL수행중인데, dept테이블의 부서명
을 바꾸면 결과값은 어떻게 될까?
119
읽기 일관성 문제 해결방안
• 프로시져, 패키지, 트리거를 잘못 사용하면
정합성이 깨진다.
• 일반 조인문을 사용하라.
(다른 트랜잭션에 의해 데이터 값이 변경되
어도 UNDO 블록에서 일관된 데이터를 읽
는다.)
120
Function동작방식 예제테이블
121
122
123
select c1, fn_c1_codenm(c1), c3
from functioin_table;
위 쿼리에서 fn_c1_codenm 함수는 몇 번 수행될까?
Function이 있는 SQL은 10046 trace file 분석 시 Main SQL 수행결과만 보
아서는 안된다.
Function의 수행 결과를 보아야 한다.
124
select c1, fn_c1_codenm(c1), c3
from functioin_table
where c2 = 0 and c3 =‘A’;
위 쿼리에서 fn_c1_codenm 함수는 몇 번 수행될까?
Function이 있는 SQL은 10046 trace file 분석 시 Main SQL 수행결과만 보
아서는 안된다.
Function의 수행 결과를 보아야 한다.
125
위 trace 결과만으로는 블록 I/O가 효율적으로 처리된 것으로 보일
수 있다.
반드시 Function의 수행결과를 확인해야 한다.
126
수행횟수가 3846번
으로 크게 감소했
다.
Function의 수행횟
수와 SQL의 총 추
출건수는 일치한다.
127
select c1, fn_c1_codenm(c1), c3
from functioin_table
where c2 = 0 and c3 =‘A’
and rownum <= 1;
위 SQL에서는 function을 몇 번 수
행할까?
128
정답 : 1건
1. Select절에 사용되는 Function은 데
이터 Fetch시에 수행된다.
2. 추출 건수만큼 반복 수행된다.
Select절의 함수 동작방식
select c1, fn_c1_codenm(c1), c3
from functioin_table
where c2 = 0 and c3 =‘A’
and rownum <= 1;
129
Where절의 함수 동작방식
select /*+ gather_plan_statistics */
t1.*, t2.*
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c3 = 'A'
and t1.c1 = t2.c1
and t2.c3 = FN_C2_CODENM(t2.c4);
위와같이 실행계획이 만들어졌을 경우 fn_c2_codenm 함수는 몇 번 수행
되었을까? 최종 결과건수(768건)만큼 반복 수행되었을까?
T1테이블에서 추출된 데이터건수(3846건)만큼 반복 수행되었을까?
T2테이블에서 추출된 데이터건수(15000건)만큼 반복 수행되었을까?
T2테이블의 예측 row수 5000은 어떻게 해서 나온 숫자인가?
130
정확한 수행횟수는 10046 trace 파일을 보면 된다.
위 실행계획을 보면 T1 테이블 조건절로 filtering해서 3846건이 추출되었
고, T2테이블은 FN_C2_CODENM함수 수행한 결과로 filtering해서 15000
건이 추출되었다.
따라서 FN_C2_CODENM함수는 ***회 수행되었음을 알 수 있다.
Hash Join은 선행테이블에 대해 상수 조건으로 데이터 걸러낸 후 조인 키
컬럼으로 hash map을 만든다. 그 다음 후행테이블을 수행하는데 상수 조
건이 있다면, 먼저 상수조건으로 대상을 줄인다. 그 이후 선탱 테이블이 생
성해 놓은 hash map에 있는 데이터 중에서 조인에 성공한 데이터를 추출
한다.
131
select /*+ gather_plan_statistics */
t1.*, t2.*
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c3 = 'A'
and t1.c1 = t2.c1
and t2.c4 in (2, 4)
and t2.c3 = FN_C2_CODENM(t2.c4);
Where절의 함수 동작방식
아래의 질문에 답할 수 있으면 당신은 기초가 강한 사람이며 발전 가능성
이 많다. 1) t2.c4 조건이 추가되었는데 왜 join 순서가 바뀌었을까?
2) 예측 cardinality 2000은 어떻게 계산되어 나온 것일까?
10046 trace에서 FN_C2_CODENM함수 수행횟수를 보기 전에, 우리는 쿼
리를 날려서 수행횟수를 계산해낼 수 있다. 어떻게 수행횟수를 알아낼 수
있을까?
132
T2.C3 = FN_C2_CODENM(T2.T4)를 수행하기 전에 추출되는 4만건에 대
해서만 추가적으로 function을 수행한다.
10046 trace를 보면 함수 40000번 수행에 총 2.42초가 소요된다.
함수 1회는 0.0000605초이지만 4만번이 쌓여서 elpased time이 2.42초
가 된다.
즉 함수 여러 번 수행하면
1) elpased time 길어진다.
2) buffer cache를 많이 읽게된다.
3) buffer cache가 부족해진다.
4) 과도한 soft parsing수행
5) CPU부하 증가
등등의 비효율이 발생한다.
133
조인방법 NESTED LOOP인 경우
select /*+ gather_plan_statistics USE_NL(T1 T2)*/
t1.*, t2.*
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c3 = 'A'
and t1.c1 = t2.c1
and t2.c3 = FN_C2_CODENM(t2.c4);
조인방법이 변경되었다. 위에서 함수는 몇 번 수행되었을까?
134
select /*+ gather_plan_statistics USE_NL(T1 T2)*/
t1.*, t2.*
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c3 = 'A'
and t1.c1 = t2.c1
and t2.c3 = FN_C2_CODENM(t2.c4);
Nested Loop Join은 선행테이블을 액세스한 후 조인 조건으로 후행 테이블
을 반복 탐색하며 조인을 수행하는데, 이때 선행테이블에서 추출된 건수만큼
반복 수행하게 된다.
위에서 FN_CE_CODENM함수는 3846번 수행되었으며, t2.c3 = 의 filter조건
으로 처리되어 T2테이블에서 결국 768건의 row가 추출되었다.
135
T2에 상수 조건을 부여한 경우
select /*+ gather_plan_statistics USE_NL(T1 T2)*/
t1.*, t2.*
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c3 = 'A'
and t1.c1 = t2.c1
and t2.c4 in (2, 4)
and t2.c3 = FN_C2_CODENM(t2.c4);
T2.c4 컬럼 조건이 추가되었는데 실행계획과 결과 건수는 앞 slide와 동일한
다. 그렇다면 함수 수행횟수는 어떨까?
함수 수행횟수가 같아면 왜 같은걸까?
다르다면 몇 번 수행되었는지 10046 trace file을 보지 않고도 알 수 있을까?
136
정답
1538번 수행되었다. 10046 trace 파일 내용
Nested Loops Join이 성공되자마자 Function이 수행되지 않는다.
조인 조건으로 조인 성공이 이루어지더라도 후행테이블에 상수조건이 있다
면, 조건을 수행하고 만족하는 데이터 건에 대해서만, Function을 수행하여
추출한다.
Function을 수행하면서 Function이 사용된 조건을 처리하고 나면 최종적으
로 384건을 추출하게 된다.
137
조인 순서를 바꾼 경우
select /*+ gather_plan_statistics USE_NL(T2 T1)*/
t1.*, t2.*
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c3 = 'A'
and t1.c1 = t2.c1
and t2.c4 in (2, 4)
and t2.c3 = FN_C2_CODENM(t2.c4);
위 쿼리는 앞의 slide 쿼리에서 조인 순서만 변경하였다.
그러면 function 수행 횟수는 얼마나 될까?
수행횟수가 변경된다면, 10046 trace file을 보지 않고도 몇 번 수행되었는지
알 수 있을까?
138
select /*+ gather_plan_statistics USE_NL(T2 T1)*/
t1.*, t2.*
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c3 = 'A'
and t1.c1 = t2.c1
and t2.c4 in (2, 4)
and t2.c3 = FN_C2_CODENM(t2.c4);
상수 조건이 있다면, Functioin이 존재하는 조건을 처리하기 전에 데이터를 줄여 놓
는다. 즉, T2를 먼저 수행할 때 T2.C4 in (2, 4) 조건을 처리하여 데이터를 걸러낸 후,
4만건에 대해서만 T2.C3 = FN_C2_CODENM(T2.C4) 조건을 처리하여 5000건이 최종
추출된 것이다.
139
Where절에 사용하는 function동작
방식
• 조인방법(NL, HASH), 조인순서, 상수조건
에 따라서 Function 수행횟수가 다르다.
• SQL의 Where절에 Function이 있다면, 조
인방법 및 조인순서를 고려해 Function 수
행횟수를 최적화하라.
• 실행계획은 효율적이라도 Function수행횟
수 때문에 elapsed time, buffer block read
수가 많을 수 있다.
140
지금까지 배운 개념 응용1
Select *
From (
select rownum no, a.*
from (
select memb_nm(매도회원번호) 매도회원이름,
memb_nm(매수회원번호) 매수회원이름,
매도계좌번호, 매수계좌번호, 체결시각, 체결수량, 체결가
from 체결
where 종목코드 = :종목코드
and 체결일자 = :체결일자
and 체결시각 between sysdate -10/24 and sysdate
order by 체결시각 desc
) a
where rownum <= 30
)
)
Where no between 21 and 30
)
위 쿼리문에는 비효율 요소는 무엇인가?
141
지금까지 배운 개념 응용1
위 쿼리문에서 조건을 만족하는 row count가 10만건이면, 10만건을 체결시각
기준으로 sorting한 후 memb_nm함수는 10만번 수행한다. Sorting된 데이터
에서 상위 30개를 추출후 21번째에서 30번째 row만을 출력한다. 아래와 같이
수정하면, 결과는 같으면서도 함수 수행 횟수는 10회로 줄일 수 있다.
Select memb_nm(매도회원번호) 매도회원이름,
memb_nm(매수회원번호) 매수회원이름,
매도계좌번호, 매수계좌번호, 체결시간 체결수량, 체결가
From (
select rownum no, a.*
from (
select 매도회원번호, 매수회원번호
매도계좌번호, 매수계좌번호, 체결시각, 체결수량, 체결가
from 체결
where 종목코드 = :종목코드
and 체결일자 = :체결일자
and 체결시각 between sysdate -10/24 and sysdate
order by 체결시각 desc
) a
where rownum <= 30
)
)
Where no between 21 and 30
)
142
앞 slide에서는 최종 추출건수가 적어서, Function 수행 위치를 변경하여 쉽게
성능 문제를 해결할 수 있었다. 앞 slide에서 최종 추출 결과가 많다면
function 수행 위치를 변경하는 것으로는 개선이 어렵다.
Main SQL에서 추출한 데이터 중 Function을 수행하는 입력 값의 종류
가 적은 경우, 스칼라서브쿼리에서 Function을 수행하도록 변경하면,
multi buffer를 이용해 성능을 개선시킬 수 있다.
• 스칼라 서브쿼리의 캐싱효과 이용
• 스칼라서브쿼리를 사용하면 오라클은 그 수행횟수를 최소화하려고
입력 값과 출력 값을 Query Execution Cache에 저장해 둔다.
• 서브쿼리가 수행될 때마다 입력값을 캐시에서 찾아보고 거기 있으면
저장된 출력 값을 리턴하고, 없으면 쿼리를 수행한 후 입력 값과 출력
값을 캐시에 저장한다.
• 이 기능을 함수 호출 횟수를 줄이는데 사용
• multi buffer의 size는 _query_execution_cache_max_size로 조절
• default 64K  변경 주의!!
• 입력 값의 종류가 소수인 경우만 적용, 그렇지 않을 경우 도리어 CPU
부하만 커짐
SQL의 최종 추출 결과가 많은 경우
143
SQL의 최종 추출 결과가 많은 경우
위 쿼리문 성능을 향상하는 방법은?
(1가지만 생각해 내는 사람은 초급개발자이고, 2가지 생각해내면 중급개발자)
1번쿼리에서 함수는 몇 번 수행될까?
2번쿼리에서 함수는 몇 번 수행될까?
144
10046 trace file 확인
1번 쿼리에서는 function이 10만번,
2번 쿼리에서는 function이 3번
Function의 입력 값으로 사용되는 컬럼의 NUM_DISTINCT가 적을 때,
Function수행을 스칼라 서브쿼리로 변경하면
큰 효과가 있다.
반대의 경우는 오히려 multi buffer를 check하기 위한
1) CPU부하가 올라간다.
2) Function수행을 위한 소프트파싱 및 I/O에 대한 비효율 발생
방안1. 함수가 스칼라서브쿼리에서
수행되도록 변경
145
방안2. Function을 조인문으로 변경
NUM_DISTINCT가 매우 많은 경우 방안1. 은 무용지물이고 오히려 더 비용이
증가한다.
위와 같이 Function을 조인으로 변경하면 성능을 개선할 수 있다.
조인문으로 변경하니 elapsed time이 0.2초로 줄었다.
변경 전에는 elapsed time이 6초
아래 dbms_xplan package결과만으로는 확인 불가, 10046 trace file 확인할것
146
방안2. Function을 조인문으로 변경
• Outer Join은 Select절의 Function을 조인으로 변경할 때 적용해야 하는 제약
• Hash Join은 From절에서 추출된 데이터 건수만큼 반복 수행(인덱스 스캔)시
발생하는 비효율을 제거하기 위한 조인 방식
결론
많은 데이터를 처리하는 Function이 성능문제 개선 방안
1. Function을 스칼라 서브쿼리로 변경
2. Function을 조인으로 변경
147
Where절의 function을 select절로
옮기기
위에서 T1테이블은 조건절 filter결과 16667건 추출되었고,
T2테이블은 조건절 t2.c3 in (‘A’) 와 fu_c2_codenm(t2.c4) ~ 로 filtering
해서 5000건 추출되었다.
그렇다면 위에서 fn_c2_codenm 함수는 몇 번 수행되었을까?
10046 trace file을 보면 쉽게 알 수 있지만, 몇 번 수행되었는지 알아내는 SQL
을 작성해 보라.
148
Where절의 function을 select절로
옮기기
LO는 BETWEEN 조건을 아래와 같이 변겨한다.
T2.c3 in (‘A’) and FN_C2_CODENM(t2.c4) >= ‘A’ and FN_C2_CODENM(t2.c4)
<=‘B’
따라서 함수 수행횟수는 10000회이다.
그런데 위 실행계획 결과를 보면 T2 테이블은 모든 조건을 filter해서 5000건
이 추출되었다. 즉 FN_C2_CODENM으로는 한 건도 걸러지지 않았다.
Where절에 있는 Function을 select절에서 값을 추출한 후, 인라인 뷰로 만들고
Function을 수행하여, 추출한 값을 가지고, 인라인뷰 밖에서 조건을 수행하도
록 SQL을 재작성해야 한다.
149
위와 같이 SQL을 변경하면 어떤 장점이 있을까?
FN_C2_CODENM이 몇 번 수행되리라 예상하는가?
150
실행계획을 보면 VIEW가 만들어진 이력이 없다.
즉 우리의 의도(인라인 뷰 내에서 function을 먼저 수행된다)대로 실행계획이
풀리지 않았다. Elapsed time도 줄지 않았다.
위와같은 실행계획에서 함수 수행횟수를 100046 trace file에서 분석했다.
151
10046 trace file을 보니 함수 수행횟수가 20000회이다.
10000회에서 줄일려고 SQL을 수정했는데, 더 늘어나 버렸다.
이거 원인 알아낼려면 10053 trace file을 열어보아야 하고 Logical Optimizer
의 원리를 알아야 한다.
152
VIEW merging 방지
153
VIEW merging 방지
View merging을 막아보았으나 함수 수행횟수는 여전히 20000번이다.
Logical Optimizer의 원리를 알아야 한다.
154
In a nutshell
select /*+ NO_MERGE(K) */ K.c3, K.c4
from ( select /*+ gather_plan_statistics leading(t1 t2) USE_HASH(T1 T2) */
t1.c3, t2.c4,
fn_c2_codenm(t2.c4) as ft2c4
from function_table t1, c1_code_nm t2
where t1.c2 = 0
and t1.c4 = 2
and t1.c1 = t2.c1
and t2.c3 in ('A')
and FN_C2_CODENM(t2.c4) >= ‘A’
and FN_C2_CODENM(t2.c4) <= ‘B’ ) K
10053 trace file 분석하면 위 SQL이 보인다.
우리의 현명한 optimizer께서는 위와 같이 마지막에 수행될 Filter조건을
View안으로 침투시키면 더 성능이 좋아질것이라고 판단하고 조건을 View
안으로 집어 넣으신다. (Filter Push Down)
하지만 위와 같이 SQL이 수행되면 t2.c3 in(‘A’) 조건을 만족하는 건수
(5000rows)만큼 함수가 반복 수행된다.
Logical Optimizer의 원리를 알아야 우리의 현명하신
Optimizer를 올바른 길로 인도할 수 있다.
155
To make a long story short
HASH JOIN에서 1667row가 추
출되었고, 1667row에 대해서
함수를 check조건으로 사용하
여 최종적으로 1667 row가 추
출되었다. Elapsed time 확 줄
었다.
위에서 fn_c2_codnm(t2.c4)함수는 최대 몇 번 수행되었을까?
실제 수행횟수는 10046 trace file을 보기 전에 어떻게 알아낼 수 있을까?
156
To make a long story short
Function이 수행되기 전의 t2.c4의 추출건수 및 distinct number를 조사하니 ‘0’ 값
만 1667건 추출되었다. 함수를 스칼라서브쿼리로 만들었으므로 multi buffer를 사
용하여 결국 함수는 1회만 수행한다. (10046 trace file 내용과 일치)
만약 위의 예제에서 t2.c4 컬럼의 값이 unique했다면 함수는 몇 번 수행되었을까?
정답을 말한다면, 당신은 고급개발자의 자질이 있는 것이다.
157
1. 함수를 Join문으로 변경
2. 함수를 스칼라서브쿼리로 만든다.
지금까지 배운 개념 응용2
select memb_nm(매도회원번호) 매도회원이름,
memb_nm(매수회원번호) 매수회원이름,
매도계좌번호, 매수계좌번호, 체결시각, 체결수량, 체결가
from 체결
where 종목코드 = :종목코드
and 체결일자 = :체결일자
and 체결시각 between sysdate -10/24 and sysdate;
위 SQL의 결과 건수가 10만건이라면, 어떻게 해야 성능을 향상시킬 수 있을까?
Brainstorming
Presenter의 답변은 : 문제 뒤에 있음
158
User Defined Funtion 결론
• 소량의 데이터 조회시에만 사용
• 대용량 조회시에는 부분범위처리가 가능
한 상황에서 제한적으로 사용
• 가급적 조인 또는 스칼라서브쿼리 형태로
변환
• 데이터 일관성이 깨지지 않도록 설계하고
개발
• 함수를 사용해야 한다면 호출 횟수를 최소
화 할 수 있는 방법을 강구
159
함수 호출횟수 최소화 방안
• 페이지 처리 또는 부분범위처리 활용
• Decode함수 또는 Case문으로 변환
• View Merge 방지
• 스칼라서브쿼리 캐싱효과을 이용
• Deterministic함수의 캐싱 효과 이용
• Result Cache 이용
• 복잡한 함수 로직을 풀어 SQL로 구현
160
초급개발자가 만든 SQL문
왼쪽의 실행계획을 보
니 access path, join
method, join order 모
두 효율적이라고 가정
하자. 그럼 어떤걸 더
조사해야 할까?
161
초급 개발자 SQL의 효율성 분석
• 총 row count
• 각 function의 수행 횟수
• 각 function 입력 값의 number of distinct
value
• Function을 Join으로 변경
• Function 수행 중 base table의 데이터가
변경될 가능성 : integrity 깨질 가능성
• ………

Contenu connexe

Similaire à SQL performance and UDF

MySQL_MariaDB-성능개선-202201.pptx
MySQL_MariaDB-성능개선-202201.pptxMySQL_MariaDB-성능개선-202201.pptx
MySQL_MariaDB-성능개선-202201.pptxNeoClova
 
SQL Server Access Patterns
SQL Server Access PatternsSQL Server Access Patterns
SQL Server Access PatternsSung wook Kang
 
SQream DB, GPU-accelerated data warehouse
SQream DB, GPU-accelerated data warehouseSQream DB, GPU-accelerated data warehouse
SQream DB, GPU-accelerated data warehouseNAVER Engineering
 
실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6HyeonSeok Choi
 
분석과 설계
분석과 설계분석과 설계
분석과 설계Haeil Yi
 
Db 진단 및 튜닝 보고 (example)
Db 진단 및 튜닝 보고 (example)Db 진단 및 튜닝 보고 (example)
Db 진단 및 튜닝 보고 (example)중선 곽
 
[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4
[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4
[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4Seok-joon Yun
 
MySQL Performance Tuning (In Korean)
MySQL Performance Tuning (In Korean)MySQL Performance Tuning (In Korean)
MySQL Performance Tuning (In Korean)OracleMySQL
 
ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기
ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기
ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기Kenu, GwangNam Heo
 
SQL-on-Hadoop with Apache Tajo, and application case of SK Telecom
SQL-on-Hadoop with Apache Tajo,  and application case of SK TelecomSQL-on-Hadoop with Apache Tajo,  and application case of SK Telecom
SQL-on-Hadoop with Apache Tajo, and application case of SK TelecomGruter
 
Spark machine learning & deep learning
Spark machine learning & deep learningSpark machine learning & deep learning
Spark machine learning & deep learninghoondong kim
 
[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영NAVER D2
 
MariaDB 마이그레이션 - 네오클로바
MariaDB 마이그레이션 - 네오클로바MariaDB 마이그레이션 - 네오클로바
MariaDB 마이그레이션 - 네오클로바NeoClova
 
5일차.map reduce 활용
5일차.map reduce 활용5일차.map reduce 활용
5일차.map reduce 활용주영 송
 
Index Analysis
Index AnalysisIndex Analysis
Index Analysislactrious
 
[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2
[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2
[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2Seok-joon Yun
 
데이터 분석 프로세스
데이터 분석 프로세스데이터 분석 프로세스
데이터 분석 프로세스Lee Seungeun
 
From MSSQL to MySQL
From MSSQL to MySQLFrom MSSQL to MySQL
From MSSQL to MySQLI Goo Lee
 
Image data augmentatiion
Image data augmentatiionImage data augmentatiion
Image data augmentatiionSubin An
 
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3Seok-joon Yun
 

Similaire à SQL performance and UDF (20)

MySQL_MariaDB-성능개선-202201.pptx
MySQL_MariaDB-성능개선-202201.pptxMySQL_MariaDB-성능개선-202201.pptx
MySQL_MariaDB-성능개선-202201.pptx
 
SQL Server Access Patterns
SQL Server Access PatternsSQL Server Access Patterns
SQL Server Access Patterns
 
SQream DB, GPU-accelerated data warehouse
SQream DB, GPU-accelerated data warehouseSQream DB, GPU-accelerated data warehouse
SQream DB, GPU-accelerated data warehouse
 
실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6
 
분석과 설계
분석과 설계분석과 설계
분석과 설계
 
Db 진단 및 튜닝 보고 (example)
Db 진단 및 튜닝 보고 (example)Db 진단 및 튜닝 보고 (example)
Db 진단 및 튜닝 보고 (example)
 
[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4
[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4
[2015 07-06-윤석준] Oracle 성능 최적화 및 품질 고도화 4
 
MySQL Performance Tuning (In Korean)
MySQL Performance Tuning (In Korean)MySQL Performance Tuning (In Korean)
MySQL Performance Tuning (In Korean)
 
ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기
ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기
ecdevday8 웹개발자의 약한고리 SQL 뛰어넘기
 
SQL-on-Hadoop with Apache Tajo, and application case of SK Telecom
SQL-on-Hadoop with Apache Tajo,  and application case of SK TelecomSQL-on-Hadoop with Apache Tajo,  and application case of SK Telecom
SQL-on-Hadoop with Apache Tajo, and application case of SK Telecom
 
Spark machine learning & deep learning
Spark machine learning & deep learningSpark machine learning & deep learning
Spark machine learning & deep learning
 
[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영
 
MariaDB 마이그레이션 - 네오클로바
MariaDB 마이그레이션 - 네오클로바MariaDB 마이그레이션 - 네오클로바
MariaDB 마이그레이션 - 네오클로바
 
5일차.map reduce 활용
5일차.map reduce 활용5일차.map reduce 활용
5일차.map reduce 활용
 
Index Analysis
Index AnalysisIndex Analysis
Index Analysis
 
[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2
[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2
[2015-06-19] Oracle 성능 최적화 및 품질 고도화 2
 
데이터 분석 프로세스
데이터 분석 프로세스데이터 분석 프로세스
데이터 분석 프로세스
 
From MSSQL to MySQL
From MSSQL to MySQLFrom MSSQL to MySQL
From MSSQL to MySQL
 
Image data augmentatiion
Image data augmentatiionImage data augmentatiion
Image data augmentatiion
 
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
 

SQL performance and UDF

  • 1. 1 Function 수행과 SQL성능 개발자 교육자료 2013.03.02 DA팀 : 유재근
  • 2. 2 CONTENTS • Warming Up • Clustering Factor • 스칼라 서브쿼리의 이해와 활용 - 스칼라 서브쿼리의 특성 - 조인이 유리한 경우 - 스칼라 서브쿼리가 유용한 경우 • Function수행과 SQL성능 문제
  • 3. 3 What is your DB management level? • Level 1 DB에 이상이 발생하면 조치한다. • Level 2 주기적으로 모니터링 한다. • Level 3 DB를 평소에 건강하게 관리한다. - ACCESS PATH를 관리한다.  실행계획을 관리한다.
  • 4. 4 Warming Up with some stretches  ACCESS PATH - Index Stretegy, partition  JOIN METHOD - NL JOIN, HASH JOIN, SORT MERGE JOIN, HASH_SJ, HASH_AJ……  JOIN ORDER - emp  dept, dept  emp  Transformer (Logical Optimizer) - Huristic Transformer / Cost Based Query Transformer  ETC - null, not null, buffer pinning, OWI, filtering optimization, function, case, decode, nvl, pagenation, ….
  • 5. 5 DATA Modeling & Business Rule INDEX현황 employees : (JOB_ID) orders : (EMPLOYEE_ID, ORDER_DATE) 위 SQL을 어떻게 최적화 해야 할까?
  • 6. 6 DATA Modeling & Business Rule • 요구사항 Employees 테이블의 job_id=‘J04’이면서 주문날짜(order_date)가 2012년01월01일 부터 2012년06월01일 범위 이며 주문상태 (order_status)가 ‘10’인 employee_id와 last_name을 출력하시오. • Data modeling과 Business Rule을 모르면 최적의 SQL 작성 불가 능하다.
  • 7. 7 DATA Modeling & Business Rule 튜닝포인트 1. Employees 테이블에서 employee_id는 unique하다. 2. Orders 테이블 데이터(N개)를 모두 join할 필요가 없다. 3. 조건절을 만족하는 데이터 하나만 만나면 Join을 중단하자.
  • 8. 8 DATA Modeling & Business Rule 아쉽지만 11g에서는 Transformer가 위와 같이 튜닝전 SQL을 변경하지는 못한 다. 양심적인 개발자(인간)가 SQL을 잘 만들어야 한다.
  • 9. 9 OPTIMIZER BASICS • Three main questions you should ask when looking for an efficient execution plan: 1. How much data? How many rows? Volume? 2. How scattered / clustered is the data? 3. Caching? => Know your data!
  • 10. 10 OPTIMIZER BASICS • Why are these questioins so important?  Two main strategies: 1. One “Big Job” =>How much data, volume? 2. Few/many “Small Jobs” =>How many times / rows ? =>Effort per iteration? Clustering/Caching
  • 11. 11 OPTIMIZER BASICS • Optimizer’s cost estimate is based on:  How much data? How many rows?  How scattered / clustered ?(partially)  (Caching?) Not at all : 11g
  • 12. 12 SUMMARY • Cardinality and Clustering determine whether the “Big Job” or “Small Job” strategy should be preferred • If the optimizer gets these estimates rigtht, the resulting execution plan will be efficient within the boundaries of the given access paths • Know your data and business questions • Help your optimizer. (Oracle doesn’t know the data the way you know it.)
  • 13. 13 Today’s LEMA  Oracle doesn’t know the data the way you know it!!  Inefficient Execution Plan 50% Oracle Does not know the data. 50% SQL writers Do not know the optimizer.
  • 14. 14 AGENDA  Clustering Factor  Statistics / Histograms  Datatype issues
  • 15. 15 HOW SCATTERED / CLUSTERED? • INDEX SCAN  TABLE BLOCK • Worst Case 1,000 rows => visit 1,000 table blocks: 1,000 * 5ms = 5s • Good Case 1,000 rows => visit 10 table blocks: 10*5ms = 50ms
  • 16. 16 HOW SCATTERED / CLUSTERED? • There is only a single measure of clustering in Oracle: The index clustering factor • The index clustering factor is represented by a single value • The logic measuring the clustering factor by default does not cater for data clustered across few blocks(ASSM!)
  • 17. 17 HOW SCATTERED / CLUSTERED?  Challenges  Getting the index clustering factor right  There are various reasons why the index clustering factor measured by Oracle might not be representative - Multiple freelists / freelist groups - ASSM (automatic space segment management) - Partitioning - SHRINK SPACE effores
  • 18. 18 HOW SCATTERED / CLUSTERED?
  • 19. 19 HOW SCATTERED / CLUSTERED? • ASSM에서는 동시에 여러 세션이 입력 시 clustering이 나빠진다. • ASSM에서는 동시에 같은 block에 데이터 를 insert하는 것을 피한다. (freelist관리) • 이런 경우에는 clustering factor가 나빠서 많은 read block이 발생해도 성능이 나빠 지지 않는다.(?)
  • 20. 20 • The CF in case of an index range scan with table access involved represents the largest fraction of the cost associated with the operation. (See 10053 trace file) HOW SCATTERED / CLUSTERED?
  • 21. 21 STATISTICS • Basic Statics: - Table Statistics: Blocks, Rows, AvgRowLen - Basic Column Statistics:Low/High Value, Num Distinct, Num Nulls
  • 22. 22 Statistics • Controlling column statistics via METHOD_OPT  FOR ALL INDEXED COLUMNS SIZE > 1:  Nonsense, without basic column statistics  Default from 10g on: FOR ALL COLUMNS SIZE AUTO: basic column statistics for all coumns, histograms if Oracle determines so
  • 23. 23 HISTOGRAMS • Basic column statistics get generated along with table statistics in a single pass • Each histogram requires a separate pass • Therefore Oracle resorts to aggressive sampling if allowed =>AUTO_SAMPLE_SIZE • This limits the quality of histograms and their significance (basic column statistics는 거의 모든 row를 대상으로 하 나, histogram은 극히 일부 row를 sampling) user_tab_col_statistics 참조
  • 24. 24 HISTOGRAMS • Limited resolution of 255 value pairs maximum • Less than 255 distinct column values => Frequency Histogram • More than 255 distinct column values =>Height Balanced Histogram • Height Balanced is always a sampling of data, even when computing statistics!
  • 25. 25 HISTOGRAMS • Aggressive sampling • Oracle doesn’t trust its own histogram information when caculating estimated cardinality. • Very bad cardinality estimation  inefficient execution plan
  • 26. 26 Frequency Histograms • When it consists of only a few popular values • Very popular and nonpopular values • Dynamic sampling also is not representative • Statistics is sometimes inconsistent
  • 27. 27 Height Histograms • Rounding effects • They cannot cover all values. • Histogram values are unstable. (when you gather histograms, the values can be different.) • Oracle doesn’t know the data the way you know it.
  • 28. 28 Height Histograms 5000 is considered unpopular, even though it is a very popular value.
  • 29. 29 Height Balanced Histograms INDEX range scan, height balanced histograms can be very useful.
  • 30. 30 SUMMARY • Check the correctness of the CF for your critical indexes • Oracle does not know the questions you ask about the data • You may want to use FOR ALL COLUMNS SIZE 1 as default and only generate histograms where really necessary • You may get better results with the old histogram behavior, but not always
  • 31. 31 SUMMARY • There are data patterns that don’t work well with histograms • => You may need to manullay generate histograms using DBMS_STATS.SET_COLUMN_STATS for critical columns • Don’t forget about Dynamic Sampling/FBI/Virtual Columns/Extended Statistics • Know your data and business questions!
  • 32. 32 10053 Trace File • SYSTEM Statistics Information - CPU SPEED, SBRDTime, MBRDTime, MBRC • 테이블/인덱스 Statistical Information - Base Cardinality, Density, CLUF • Cardinality Estimation • Cost Estimation - Access Type, Join Type, Join Order • 예측은 틀릴 수 밖에 없다.
  • 33. 33 COST? • Jonathan Lewis • The cost represents (and has always represented) the optimizer’s best estimate of the time it will take to execute the statement. • Query의 예상 수행 시간(Time)
  • 34. 34 Time으로서의 Cost • Total Time = CPU Time + I/O time + Wait Time • Estimated Time = Estimated CPU time + Estimated I/O time = Estimated CPU time + Single Block I/O time + Multi Block I/O time
  • 35. 35 Time으로서의 Cost • Oracle은 COST에 정규화(인위적인 가공)을 수행 • 모든 Time의 합을 평균 Single Block I/O Time으로 나눈다. • 왜 그럴까? Oracle Optimizer의 역사에 대한 이해가 필요 • 과거 System Statistics 개념이 소개되기 전에는 I/O Model이 Cost계산의 기본 Model이었다. 즉, Cost란 곧 I/O Count였다. • I/O Count를 Time으로 변환하는 것이 불가능하기 때문에 역으로 Time을 I/O Count기준으로 정규화하는 방법을 선택했다.
  • 36. 36 Time으로서의 Cost • Total Time = CPU Time + I/O time + Wait Time • Estimated Time = Estimated CPU time + Estimated I/O time = Estimated CPU time + Single Block I/O time + Multi Block I/O time • COST = (Estimated Time / Single Block I/O Time) cost가 높다 = 수행시간이 길다 = Single Block I/O count + 보정Multi Block I/O count + 보 정CPU count  모든 예상 수행 시간을 single block I/O time에 대한 가중치 를 고려한 count값으로 변환  I/O Cost 방식보다 진보
  • 37. 37 System Statistics • 10g 이후 부터는 DBA가 통계정보를 수집 하지 않아도 CPU mode 사용
  • 38. 38 Cost 정보 예 • Column C1 하나만 fetch하는 것과 C1, C2 를 fetch하는 것은 비용이 다르다. • Predicate이 추가되거나 복잡해져도 CPU 비용이 증가한다.
  • 39. 39 DB_FILE_MULTIBLOCK_READ_COU NT • Cost 계산 시에는 System Statistics의 mbrc값을 사용한다. • 하지만, 실제 Query를 수행할 때는 DFMBRC값을 사용한다.
  • 40. 40 Time Model 한계 • Mreadtim 과 sreadtim 값의 부정확성 • Enterprise 환경의 Storage는 sreadtim이 mreadtim보다 더 높은 다소 비현실적인 현상 발생 • dbms_stats.set_system_stats procedure를 이용해 강제로 값을 조작
  • 41. 41 CBO의 기본 흐름 SQL Statement Parse Transformation (logical optimization) Optimization (Physical Optimization) Exexution Plan Result Set
  • 42. 42 Basic Terminalogy • Density : 밀도, 분포도 가. Histogram이 없는 경우 : 1/NDV 나. Histogram이 있는 경우 : unknown • Cardinalty : 조건을 만족하는 집합의 수 Cardinality = Base Cardinality * Selectivity • Selectivity : 특정조건(predicate)을 만족할 확률 • Histogram : 분포도, 막대그래프
  • 43. 43 Cardinality 계산 -C2 컬럼만 histogram 수집함 -C2 컬럼의 density는 1/NDV보다 훨씬 작은 값
  • 44. 44 • C2 = :b 조건 : Histogram(frequency histogram)이 존재하면 selectivity계산에 Density가 아닌 NDV값이 사용된다. • C2= ‘A’ 조건 : 상수값이 입력되면 Histogram덕분에 조건에 해당하는 cardinality를 알 수 있다.
  • 45. 45 Cardinality계산 C2= :b1 조건이라면 cardinality를 얼마로 예상할까? Cardinality = base cardinality * selectivity 즉, C2=:b1 의 selectivity는 얼마일까?
  • 46. 46 Cardinality 계산 즉, C2=:b1 의 selectivity는 얼마일까? Frequency hostogram이 존재하는 경우 selectivity 계산에 density가 아닌 NDV를 사용한다. 따라서 selectivity = 1/5 = 0.2 이다. 그럼 C2=‘B’라고 하면 cardinality를 얼마로 예상할까?
  • 47. 47 Cardinality 계산 CBO는 Frequency Histogram 덕분에 Data의 정확한 분포를 알고 있다. 그렇다면, C2 like ‘%A%’ 조건은 어떻게 cardinality를 예상할까?
  • 48. 48 Cardinality 그렇다면, C2 like ‘%A%’ 조건은 어떻게 cardinality를 예상할까? 어떻게 해서 cardinality를 500로 계산해 냈을까? (Magic Number **% RULE) Googling 해봐라.
  • 49. 49 Index Scan Cost • 전체 Row수 중 얼마를 읽어야 Index Scan이 Table Full Scan보다 효율적일까? • CBO는 Index Scan과 Full Table Scan의 Cost를 기계적으로 계산 • 10053 Trace file 내용 • Cost계산 방식 이해  CBO가 왜 Index Scan/Full Table Scan하는지 이해할 수 있 다.
  • 50. 50 Table Full Scan Cost 계산 예제 • 다음과 같은 데이터를 가정 Blocks = 100 MBRC = 4 sreadtim = 5 mreadtim = 10 • COST = Single Block I/O Count +보정 Multi Block I/O Count + 보정 CPU Count • 보정Multi Block I/O Count = MBI/OC * 가중치 = (Blocks/MRC) * (mreadtim / sreadtim) = (100/4) * (10/5) = 50 • 보정CPU Count = small value • COST = 0 + 50 + <CPU> = 50.xxx. • Table Full Scan의 COST = f (Table Block수, MBRC, multi block read 가 중치) • 한번에 읽을 것으로 예상되는 Block수(MBRC)가 클수 록 Cost는 작아진다.
  • 51. 51 Index Scan Cost • 조건을 만족하는 최초의 Index Leaf Block까 지 찾아간다. • 조건을 만족하는 Index Key를 순서대로 fetch 하면서 • Rowid를 이용해 Table Block을 하나씩 읽으 면서 • 조건에 해당하는 Row를 Fetch한다. • Cost = root block에서 leaf block까지 찾아가는 Cost +조건에 맞는 Index Leaf Block을 읽는 Cost +조건에 맞는 Table Block을 읽는 Cost
  • 52. 52 Index Scan Cost • Cost = root block에서 leaf block까지 찾아가는 Cost +조건에 맞는 Index Leaf Block을 읽는 Cost +조건에 맞는 Table Block을 읽는 Cost • root block에서 leaf block까지 찾아가는 Cost = Blevel = Index Height -1 • 조건에 맞는 Index Leaf Block을 읽는 Cost = 전체 Leaf Block * (Index) Selectivity • 조건에 맞는 Table Block을 읽는 Cost = Clustering Factor * (Table) Selectivity - CF : Index Key에 해당하는 Table Block을 매번 새로 읽어야 하는 회수
  • 53. 53 Index Scan Cost • Cost = root block에서 leaf block까지 찾아가는 Cost +조건에 맞는 Index Leaf Block을 읽는 Cost +조건에 맞는 Table Block을 읽는 Cost = Blevel + Leaf Blocks * Index Selectivity + CF * Table Selectivity + 보정 CPU count Index Height, Selectivity, Leaf Block수, CF에 의해 결정 테이블 data block수 <=CF =< 테이블 row count이므로 CF는 상당히 큰 숫자로 COST에서 차지하는 비중이 크다.
  • 54. 54 Index Scan Cost • Cost = root block에서 leaf block까지 찾아가는 Cost +조건에 맞는 Index Leaf Block을 읽는 Cost +조건에 맞는 Table Block을 읽는 Cost = Blevel + Leaf Blocks * Index Selectivity + CF * Table Selectivity + 보정 CPU count 넓은 범위(leaf block이 많다)의 Data는 Index를 경유하 지 말라.
  • 55. 55 Clustering Factor • A measure of the orderedness of an index in comparison to the table that it is based upon. It is used as an indicator for computing the estimated cost of the table lookup following an index access. • Index Key가 Table Row에 대해 얼마나 비 슷한 순서로 저장되어 있는가
  • 56. 56 Clustering Factor • Good Clustering Factor Index = 1,2,3,4,5,6,7,8,9,10,…. Table = 1,2,3,4,5,6,7,8,9,10,…. • Bad Clustering Facotr Index = 1,2,3,4,5,6,7,8,9,10,… Table = 3,8,7,1,4,5,10,2,6,9,… Index = 1,2,3,4,5,6,7,8 Table = 8,7,6,5,4,3,2,1 Good or Bad?
  • 57. 57 CF 측정 방법 • The CF records the number of data blocks that will be accessed when scanning an index. • 전제조건 1. 단 하나의 Table Data Block만을 Memory에 Cache할 수 있다. 2. CF는 Physical Reads, 즉 Cache에 존재하 지 않아 Disk에서 읽는 경우만 증가한다.
  • 58. 58 CF 특정 방법 1 2 3 1 2 3 INDEX TABLE Index Block Table Block
  • 59. 59 CF 특정 방법 1 2 3 1 3 INDEX TABLE Index Block 2
  • 60. 60 위에서 CF는 얼마일까? CF의 최소값 : Table의 Data Block 수 CF의 최소값
  • 61. 61 CF의 최대값 위에서 CF는 얼마일까? CF의 최대값 : Table의 Row 수
  • 62. 62 CF and Performance Histogram 수집 X 통계정보 수집
  • 63. 63 CF and Performance 왜 c2 컬럼에 있는 index를 경유하지 않을까?
  • 64. 64 CF and Performance 왜 c2 컬럼에 있는 index를 경유하지 않을까? COST = Blevel + Leaf blocks * Index Selectivity + CF * Table Selectivity + 보정된 CPU count Blevel + Leaf blocks* Index Selectivity 부분은 Cost가 ‘2’에 불과하지 만, CF*Table Sectivity를 합해보니 cost가 97로 커졌다. Table의 Selectivity 는 얼마일 까?
  • 65. 65 CF and Performance • CF가 Selectivity 못지 않게 Index Lookup 의 Cost를 결정짓는 중요한 요소 • 앞의 예제는 row count가 10000건에 불과 하다. Selectivity가 1%임에도 불구하고, Index Lookup 비용이 더 높다. • 그럼 실제 성능 차이가 있다면 그 정도는 얼마일까?
  • 67. 67 • 위에서 logical reads 횟수는 얼마일까? CF and Performance
  • 68. 68 Buffer Pinning • 한 번의 fetch에서 두 번 연속 방문하는 Block에 대해서 Pinning을 수행한다. • Pinned Block에 대해서는 cache buffers chains latch를 획 득하는 일련의 과정을 거치지 않고 Memory Address를 이용 해 직접 읽는다. • Buffer Pinning에 의해서 읽기작업의 오버헤드가 완전히 없어 지지는 않는다.
  • 69. 69 Cache Buffers Chains Latch • 한 세션에서 bad SQL문이 수행 될 경우 다량의 버퍼를 접근하게 되며 특정 cache buffers chains latch를 자주 획득하게 된다.
  • 70. 70 Buffer Pinning • 위에서 T_CLSF_I1 인덱스를 경유하여 Table을 access시에 logical reads는 (4-3)1이다. • T_CLF_I2 인덱스를 경유하여 Table을 access 시에 logical reads는 95-3=92이다. CF는 나 쁘지만 약 8개 정도는 buffer pinning이 발생 했음을 알 수 있다. 완전히 random했다면, 방 문 buffer수가 100개가 되었을 것이다.
  • 71. 71 CF를 줄이는 방법 • Index 통계에 있는 clustering factor 값이 row count에 가까울 경우, CF값을 줄일 수 있는 방법은 무엇일까? • 넓은 범위의 Index Scan을 최대한 피하라. • 넓은 범위의 Index Scan이 필요한 경우에는 가능한 Index Fast Full Scan을 사용하라.
  • 72. 72 Controlling Index Scan Cost • Optimizer_index_caching : default 0 • Oracle은 Index가 Memory에 Caching되어 있지 않다는 전제하에 Cost를 계산한다. • Cost 계산의 한계 • ‘0’보다 크게 지정 : Index Scan이 저렴하다 는 가정을 세우고 이를 Cost계산에 반영
  • 73. 73 Controlling Index Scan Cost • Optimizer_index_cost_adj : default 100 • 100은 Index Scan Cost를 기본 공식 그대 로 100% 계산 • 50은 Index Cost를 50% 감소시킨다.
  • 74. 74 Parameter vs. System Statistics • System Statistics 값 중 sreadtim값과 mreadtim값이 파라미터를 대신하는 역할 을 한다. System Statistics값 에 mbrc값이 존재하 면, DB_FILE_MULTBLOCK _READ_COUNT 파라 미터는 더 이상 Cost 계산에 사용되지 않 는다.
  • 76. 76 Index Range Scan Cost = Root Block I/O Count + Leaf Block I/O Count Fetch Call 단위가 바뀔 때마다 매번 Block을 새로 읽어야 한다. Buffer Read 횟수 Cost 20은 어떻게 계산해서 나온 것일까? Buffer Read 횟수 118은 어떻게 계산해서 나온 것일까?
  • 77. 77 Buffer Read 횟수 C1 컬럼을 추출하지 않고 Count값만 가져오는 경우는 Logical Read가 20 이다. 이 값은 Index의 Root Block + Leaf Block수와 일치한다. 한번의 Fetch만으로 Leaf Block을 Range Scan하는 경우는 Leaf Block의 수 만큼만 Read가 발생한다. 즉, Fetch Call단위가 바뀔 때마다 매번 Block을 새로 읽어야 한다. Fetch Call의 횟수, 즉 Fetch Array Size가 Index Range Scan의 Leaf Block 방문 회 수를 결정한다. 하지만, Cost 계산에는 Fetch Call횟수는 고려되지 않는다. Index Range Scan의 Cost는 방문해야 할 Block의 수에 의해 결정된다.
  • 78. 78 INDEX Range Scan 특성 • Index Key를 삭제(Delete)해도 Leaf Block의 수는 동일하다. • 읽어야 할 Index Leaf Block의 수도 동일하다. (Index Key를 아무리 삭제해도 모든 Leaf Block들이 다 탐색 대상이 된다.)  Oracle은 Leaf Block을 방문하지 않고서 는 key의 삭제 여부를 알 수 없다. • Key가 삭제된 경우 실제 “Fetch”가 발생하지 않으므로 Fetch Call 회수가 줄어든다.  Leaf Block을 줄이려면 rebuild, coalesce, shrink 명령을 수행하라.
  • 79. 79 INDEX Leaf Block 줄이기 모든 데이터가 없는데도 오라클은 20개의 Block을 방문한다. 방문하는 Leaf Block 수를 줄이려면 어떻게 해야 할까?
  • 80. 80 INDEX Leaf Block 줄이기 Coalesce or Rebuild 후 성능향상을 기대할 수 있다.
  • 81. 81 용어 정의 • 스칼라 서브쿼리 • 인라인 뷰 • 서브쿼리 Select t1.c1, t2.c2, (select fun_nm(c1) from t2) From t1, (select t3.c1 from t3), Where t1.c1 = t2.c1 and t2.c2 not in (select c2 from t1);
  • 85. 85 스칼라 서브쿼리의 특성 작성자 의도 : T1 테이블에서 c1, c2 컬럼으로 정렬하여 10개만 추출한다. 단, T2테이블의 c3컬럼은 T1 테이블의 c1값과 T2테이블의 c1값이 같을 경 우에만 추출하고, 동일한 데이터가 없으면 NULL을 추출해야 한다. select rownum rnum, x.* from ( select c1, c2, c3, (select t2.c3 from scalar_t2 t2 where t2.c1 = t1.c1) as c2_c3 from scalar_t1 t1 order by c1, c2 ) x where rownum <= 10; 위 SQL의 실행계획은 어떻게 될 것인가? 미리 비효율을 예상해 보시오.
  • 86. 86 10건을 추출하는데 T2 테이블은 50만번 반복 access했다. 비효율적이다. 위 쿼리를 효율적으로 바꿀 수 있을까? 특징1. 스칼라 서브쿼리는 결과 건수만큼 반복적으로 수행된다.
  • 87. 87 스칼라서브쿼리 수행 위치를 변경했다. Index access 수가 50만번에서 10번으로 줄었고, Buffer cache access 수가 15만개에서 1천개로 줄었다. 만약 위에서 rownum<=10 조건이 없다면 1번쿼리? 2번쿼리 어느 것이 유리할까?
  • 88. 88 스칼라 서브쿼리의 특성 • Deterministic 속성 • 입력 값에 대한 결과 값을 multi buffer에 저장 • 서브쿼리의 filter optimization과 같은 원 리 • Multi buffer size : default 64K _query_execution_cache_max_size
  • 89. 89 스칼라 서브쿼리와 조인의 관계 select /*+ gather_plan_statistics */ t1.c2, t1.c1, t1.c3, (select t2.c3 from scalar_t2 t2 where t2.c1 = t1.c1) t2_c3, (select t3.c3 from scalar_t3 t3 where t3.c1 = t1.c1) t3_c3 from scalar_t1 t1 order by t1.c1, t1.c2; 위 쿼리문에서 어떤 비효율이 있을지 예상해 보시오. 그리고 그 비효율을 없앨려면 어떻게 어떻게 해야 할까? 정답
  • 90. 90
  • 91. 91 배치프로그램vs스칼라서브쿼리 • 배치프로그램(많은 데이터추출)은 스 칼라 서브쿼리를 사용하지 말자. • 배치프로그램에서는 스칼라서브쿼리를 Outer Join으로 변경하고, Hash Join으로 변경하자. • 제약사항 1) Outer Join으로 변경(항상 조인에 성공하면 Outer Join으로 처리하지 않아도 됨) 2) 조인 연결 컬럼의 값은 항상 Unique해야 한다.
  • 92. 92 조인방식으로 개선 후 Outer join시 T1이 driving되어야 하나, 위에서는 Right는 driving테이블이 변 경되었음을 의미함
  • 93. 93 조인vs. 스칼라 서브쿼리 Q: Compared to the join method, are sacalar subqueries always inefficient? A : No, sometimes scalar subqueries are more desirable. Q : When subqueries are more efficient?
  • 94. 94 조인 vs. scalar subquery select rownum rnum, x.* from (select /*+ leading(T1) USE_NL(T1 T2 T3) */ t1.c1, t1.c2, t1.c3, t2.c3 as t2_c3, t3.c3 as t3_c3 from scalar_t1 t1, scalar_t2 t2, scalar_t3 t3 where t1.c1 = t2.c1(+) and t1.c1 = t3.c1(+) order by t1.c1, t1.c2) x where rownum <= 10; 위 쿼리의 실행계획을 보지도 않고, 어디서 비효율이 발생할지 예상할 수 있으면, 당신은 진정한 GURU다.
  • 95. 95 반복적인 INDEX SCAN으로 I/O 과다 발생  반복적인 INDEX SCAN 줄이기 위해 HASH로 유도
  • 96. 96 아래의 실행계획이 HASH JOIN으로 유도한 실행계획임 아래 실행계획이 위 NL JOIN보다 효율적인 이유를 설명하시오. 아래 실행계획에는 어떤 비효율이 있을까?
  • 97. 97 조인연결 컬럼이 Unique T1테이블에서 10건 추출 후 T2테이블, T3테이블 조인해도 무결성 유지 개선방안 1) T1테이블에서 10건 추출 후, T2와 T3 테이블을 **조인 방법으로 수행하도 록 변경 2) 스칼라 서브쿼리로 변경 위 쿼리문을 스칼라 서브쿼리를 활용하도록 변경하시오.
  • 98. 98
  • 99. 99 스칼라서브쿼리vs조인 사용기준 • 추출 데이터가 적은 경우(Online 프로그램)  스칼라서브쿼리 OK  조인을 스칼라 서브쿼리로 변경 고려 • 추출 데이터가 많은 경우(Batch 프로그램)  스칼라서브쿼리 NO!  스칼라서브쿼리를 조인으로 변경 후 Hash Join 유도하는 것을 고려
  • 100. 100 WITH절 이해와 효율적인 SQL • 동일한 데이터를 반복적으로 읽어야 하는 SQL의 성능을 개선하기 위한 방법으로 사 용 • /*+ MATERIALIZE */ • /*+ INLINE */ with절의 결고 셋을 1회만 수행
  • 101. 101 MATERIALIZE 동작 방식 1. Global temporary table 생성 2. Global temporary table에 with절에서 추 출한 데이터 insert 3. Global temporary table 조회하여 데이터 처리
  • 102. 102 SQL에서 with절이 1회만 수행되므로 INLINE동작방식을 선택 T_T1 with절은 힌트때문에 Materialize 동작 방식
  • 103. 103 Outer join이므로 어쩔수 없이 T1 테이블을 드라이빙해서 T2테이블과 조인수행 조인한 결과를 T3 테이블(추출건수가 많으므로)과 HASH JOIN수행 위 실행계획에는 어떤 비효율이 있는가? 어떤 실행계획이 되어야 효율적으로 데이터를 추출할 수 있을까? 힌트 : T1 테이블의 추출 데이터 건수가 적다.
  • 104. 104 실행계획 제안 1. T1.C1 = T3.C1(+) 조건이 T3 인라인뷰 내부로 침투하도록 한다. 그러면, T3의 access 량이 대폭 줄어들 것이다. 2. T1 테이블에서 추출한 값을 인라인 뷰로 만든 후 인라인뷰T3 안에 강제로 추 가한다. 3. With절을 선언하여 필요한 데이터를 미리 추출한 후, 필요할 때마다 재사용한 다.
  • 105. 105 T1 테이블을 2회 access 위 실행계획의 비효율은 무엇일까? 개선후1
  • 106. 106 개선후2 개선후1 보다 일량이 많지만, 동일한 데이터를 2번 처리하는 비효율은 개선
  • 107. 107 WITH절 주의사항 • 동시성이 높은 경우 materialize방식 지양 - DISK I/O 발생하면서 control file sequential read Wait Event 빈번 발생 • 추출건수가 많으면, materialize방식 사용 시 DISK I/O 다량 발생 발생 • WITH절 적당한 동작방식 힌트 부여
  • 109. 109 User Defined Function의 이해 Is this execution plan efficient? At the end of this workship you will be able to raise questions.
  • 110. 110 2) SQL 수정 후 실행계획 및 일량
  • 111. 111 FUNCTION 기본내용 • 리턴 값이 있다. • 데이터베이스 객체로 저장, 컴파일 된 상 태에서 수행된다. • 예외처리가 가능하다. • 모듈화된 프로그램이 가능하다. • 변수 및 다양한 제어문 사용이 가능하다. • WAS서버와 Network 부하를 줄일 수 있다. • 유지보수 측면에서 매우 효율적이다.
  • 112. 112 FUNCTION 기본내용 • Deterministic Function - 입력 값이 같다면, 리턴 값도 항상 같음을 선언하는 Function - 입력값이 같으면 Function을 매번 수행하지 않고 메모리 내에 Cache된 결과 값을 바로 가 져와 사용 (fetch call 내에서만 유효) • Not Deterministic Function - 입력값을 가져와 결과 값을 리턴 - 캐싱효과를 얻으려고 함부로 deterministic 선언하는 것은 위험한 일
  • 114. 114 TT테이블에 YAMHHA값이 없 으므로 함수 수행 결과는 no row여 야 하나, 1 row가 출력됨 Deterministic 선언 위험성 Fun_lookup 함수 생성 --TT테이블을 읽어서 value컬럼값을 출력함 Test테이블에서 NO컬럼을 읽어서 함수를 수행한 결과가 ‘YAMHHA’ 인 row를 출력
  • 115. 115 User Defined Function vs. Bulit-In 함수
  • 116. 116 User Defined Function vs. Bulit-In 함수 함수 내에 recursive call이 없어도 속도가 느려졌다. Recursive call이 함수 내에 있으면 속도가 더 느려진다. USER DEFINED FUNCTION을 남용하지 말아야 하는 이유 다음 slide참조
  • 117. 117 User Defined Function vs. Bulit-In 함수 I/O가 전혀 발생하지 않는 function(Dual테이블은 I/O가 없다)을 수행했 을 뿐인데도 elapsed time이 2.56초에서 18.88초로 9배 증가 원인 : 10046 Trace file  DB call이 2백만번 발생 parse 1회, execute 1백만, fetch 1백만
  • 118. 118 함수와 읽기 일관성 • 문장수준 읽기일관성을 보장하지 않는다. • 함수 내에서 수행되는 recursive쿼리는 메인 쿼리의 시작 시점과 무관하게 그 쿼리가 수행 되는 시점을 기준으로 블록을 읽는다. • 함수 내에 쿼리 문장을 포함하고 있다면 그 함수는 일관성이 보장되지 않는다. select fun_dept_nm(c1) from emp;  위 SQL수행중인데, dept테이블의 부서명 을 바꾸면 결과값은 어떻게 될까?
  • 119. 119 읽기 일관성 문제 해결방안 • 프로시져, 패키지, 트리거를 잘못 사용하면 정합성이 깨진다. • 일반 조인문을 사용하라. (다른 트랜잭션에 의해 데이터 값이 변경되 어도 UNDO 블록에서 일관된 데이터를 읽 는다.)
  • 121. 121
  • 122. 122
  • 123. 123 select c1, fn_c1_codenm(c1), c3 from functioin_table; 위 쿼리에서 fn_c1_codenm 함수는 몇 번 수행될까? Function이 있는 SQL은 10046 trace file 분석 시 Main SQL 수행결과만 보 아서는 안된다. Function의 수행 결과를 보아야 한다.
  • 124. 124 select c1, fn_c1_codenm(c1), c3 from functioin_table where c2 = 0 and c3 =‘A’; 위 쿼리에서 fn_c1_codenm 함수는 몇 번 수행될까? Function이 있는 SQL은 10046 trace file 분석 시 Main SQL 수행결과만 보 아서는 안된다. Function의 수행 결과를 보아야 한다.
  • 125. 125 위 trace 결과만으로는 블록 I/O가 효율적으로 처리된 것으로 보일 수 있다. 반드시 Function의 수행결과를 확인해야 한다.
  • 126. 126 수행횟수가 3846번 으로 크게 감소했 다. Function의 수행횟 수와 SQL의 총 추 출건수는 일치한다.
  • 127. 127 select c1, fn_c1_codenm(c1), c3 from functioin_table where c2 = 0 and c3 =‘A’ and rownum <= 1; 위 SQL에서는 function을 몇 번 수 행할까?
  • 128. 128 정답 : 1건 1. Select절에 사용되는 Function은 데 이터 Fetch시에 수행된다. 2. 추출 건수만큼 반복 수행된다. Select절의 함수 동작방식 select c1, fn_c1_codenm(c1), c3 from functioin_table where c2 = 0 and c3 =‘A’ and rownum <= 1;
  • 129. 129 Where절의 함수 동작방식 select /*+ gather_plan_statistics */ t1.*, t2.* from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c3 = 'A' and t1.c1 = t2.c1 and t2.c3 = FN_C2_CODENM(t2.c4); 위와같이 실행계획이 만들어졌을 경우 fn_c2_codenm 함수는 몇 번 수행 되었을까? 최종 결과건수(768건)만큼 반복 수행되었을까? T1테이블에서 추출된 데이터건수(3846건)만큼 반복 수행되었을까? T2테이블에서 추출된 데이터건수(15000건)만큼 반복 수행되었을까? T2테이블의 예측 row수 5000은 어떻게 해서 나온 숫자인가?
  • 130. 130 정확한 수행횟수는 10046 trace 파일을 보면 된다. 위 실행계획을 보면 T1 테이블 조건절로 filtering해서 3846건이 추출되었 고, T2테이블은 FN_C2_CODENM함수 수행한 결과로 filtering해서 15000 건이 추출되었다. 따라서 FN_C2_CODENM함수는 ***회 수행되었음을 알 수 있다. Hash Join은 선행테이블에 대해 상수 조건으로 데이터 걸러낸 후 조인 키 컬럼으로 hash map을 만든다. 그 다음 후행테이블을 수행하는데 상수 조 건이 있다면, 먼저 상수조건으로 대상을 줄인다. 그 이후 선탱 테이블이 생 성해 놓은 hash map에 있는 데이터 중에서 조인에 성공한 데이터를 추출 한다.
  • 131. 131 select /*+ gather_plan_statistics */ t1.*, t2.* from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c3 = 'A' and t1.c1 = t2.c1 and t2.c4 in (2, 4) and t2.c3 = FN_C2_CODENM(t2.c4); Where절의 함수 동작방식 아래의 질문에 답할 수 있으면 당신은 기초가 강한 사람이며 발전 가능성 이 많다. 1) t2.c4 조건이 추가되었는데 왜 join 순서가 바뀌었을까? 2) 예측 cardinality 2000은 어떻게 계산되어 나온 것일까? 10046 trace에서 FN_C2_CODENM함수 수행횟수를 보기 전에, 우리는 쿼 리를 날려서 수행횟수를 계산해낼 수 있다. 어떻게 수행횟수를 알아낼 수 있을까?
  • 132. 132 T2.C3 = FN_C2_CODENM(T2.T4)를 수행하기 전에 추출되는 4만건에 대 해서만 추가적으로 function을 수행한다. 10046 trace를 보면 함수 40000번 수행에 총 2.42초가 소요된다. 함수 1회는 0.0000605초이지만 4만번이 쌓여서 elpased time이 2.42초 가 된다. 즉 함수 여러 번 수행하면 1) elpased time 길어진다. 2) buffer cache를 많이 읽게된다. 3) buffer cache가 부족해진다. 4) 과도한 soft parsing수행 5) CPU부하 증가 등등의 비효율이 발생한다.
  • 133. 133 조인방법 NESTED LOOP인 경우 select /*+ gather_plan_statistics USE_NL(T1 T2)*/ t1.*, t2.* from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c3 = 'A' and t1.c1 = t2.c1 and t2.c3 = FN_C2_CODENM(t2.c4); 조인방법이 변경되었다. 위에서 함수는 몇 번 수행되었을까?
  • 134. 134 select /*+ gather_plan_statistics USE_NL(T1 T2)*/ t1.*, t2.* from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c3 = 'A' and t1.c1 = t2.c1 and t2.c3 = FN_C2_CODENM(t2.c4); Nested Loop Join은 선행테이블을 액세스한 후 조인 조건으로 후행 테이블 을 반복 탐색하며 조인을 수행하는데, 이때 선행테이블에서 추출된 건수만큼 반복 수행하게 된다. 위에서 FN_CE_CODENM함수는 3846번 수행되었으며, t2.c3 = 의 filter조건 으로 처리되어 T2테이블에서 결국 768건의 row가 추출되었다.
  • 135. 135 T2에 상수 조건을 부여한 경우 select /*+ gather_plan_statistics USE_NL(T1 T2)*/ t1.*, t2.* from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c3 = 'A' and t1.c1 = t2.c1 and t2.c4 in (2, 4) and t2.c3 = FN_C2_CODENM(t2.c4); T2.c4 컬럼 조건이 추가되었는데 실행계획과 결과 건수는 앞 slide와 동일한 다. 그렇다면 함수 수행횟수는 어떨까? 함수 수행횟수가 같아면 왜 같은걸까? 다르다면 몇 번 수행되었는지 10046 trace file을 보지 않고도 알 수 있을까?
  • 136. 136 정답 1538번 수행되었다. 10046 trace 파일 내용 Nested Loops Join이 성공되자마자 Function이 수행되지 않는다. 조인 조건으로 조인 성공이 이루어지더라도 후행테이블에 상수조건이 있다 면, 조건을 수행하고 만족하는 데이터 건에 대해서만, Function을 수행하여 추출한다. Function을 수행하면서 Function이 사용된 조건을 처리하고 나면 최종적으 로 384건을 추출하게 된다.
  • 137. 137 조인 순서를 바꾼 경우 select /*+ gather_plan_statistics USE_NL(T2 T1)*/ t1.*, t2.* from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c3 = 'A' and t1.c1 = t2.c1 and t2.c4 in (2, 4) and t2.c3 = FN_C2_CODENM(t2.c4); 위 쿼리는 앞의 slide 쿼리에서 조인 순서만 변경하였다. 그러면 function 수행 횟수는 얼마나 될까? 수행횟수가 변경된다면, 10046 trace file을 보지 않고도 몇 번 수행되었는지 알 수 있을까?
  • 138. 138 select /*+ gather_plan_statistics USE_NL(T2 T1)*/ t1.*, t2.* from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c3 = 'A' and t1.c1 = t2.c1 and t2.c4 in (2, 4) and t2.c3 = FN_C2_CODENM(t2.c4); 상수 조건이 있다면, Functioin이 존재하는 조건을 처리하기 전에 데이터를 줄여 놓 는다. 즉, T2를 먼저 수행할 때 T2.C4 in (2, 4) 조건을 처리하여 데이터를 걸러낸 후, 4만건에 대해서만 T2.C3 = FN_C2_CODENM(T2.C4) 조건을 처리하여 5000건이 최종 추출된 것이다.
  • 139. 139 Where절에 사용하는 function동작 방식 • 조인방법(NL, HASH), 조인순서, 상수조건 에 따라서 Function 수행횟수가 다르다. • SQL의 Where절에 Function이 있다면, 조 인방법 및 조인순서를 고려해 Function 수 행횟수를 최적화하라. • 실행계획은 효율적이라도 Function수행횟 수 때문에 elapsed time, buffer block read 수가 많을 수 있다.
  • 140. 140 지금까지 배운 개념 응용1 Select * From ( select rownum no, a.* from ( select memb_nm(매도회원번호) 매도회원이름, memb_nm(매수회원번호) 매수회원이름, 매도계좌번호, 매수계좌번호, 체결시각, 체결수량, 체결가 from 체결 where 종목코드 = :종목코드 and 체결일자 = :체결일자 and 체결시각 between sysdate -10/24 and sysdate order by 체결시각 desc ) a where rownum <= 30 ) ) Where no between 21 and 30 ) 위 쿼리문에는 비효율 요소는 무엇인가?
  • 141. 141 지금까지 배운 개념 응용1 위 쿼리문에서 조건을 만족하는 row count가 10만건이면, 10만건을 체결시각 기준으로 sorting한 후 memb_nm함수는 10만번 수행한다. Sorting된 데이터 에서 상위 30개를 추출후 21번째에서 30번째 row만을 출력한다. 아래와 같이 수정하면, 결과는 같으면서도 함수 수행 횟수는 10회로 줄일 수 있다. Select memb_nm(매도회원번호) 매도회원이름, memb_nm(매수회원번호) 매수회원이름, 매도계좌번호, 매수계좌번호, 체결시간 체결수량, 체결가 From ( select rownum no, a.* from ( select 매도회원번호, 매수회원번호 매도계좌번호, 매수계좌번호, 체결시각, 체결수량, 체결가 from 체결 where 종목코드 = :종목코드 and 체결일자 = :체결일자 and 체결시각 between sysdate -10/24 and sysdate order by 체결시각 desc ) a where rownum <= 30 ) ) Where no between 21 and 30 )
  • 142. 142 앞 slide에서는 최종 추출건수가 적어서, Function 수행 위치를 변경하여 쉽게 성능 문제를 해결할 수 있었다. 앞 slide에서 최종 추출 결과가 많다면 function 수행 위치를 변경하는 것으로는 개선이 어렵다. Main SQL에서 추출한 데이터 중 Function을 수행하는 입력 값의 종류 가 적은 경우, 스칼라서브쿼리에서 Function을 수행하도록 변경하면, multi buffer를 이용해 성능을 개선시킬 수 있다. • 스칼라 서브쿼리의 캐싱효과 이용 • 스칼라서브쿼리를 사용하면 오라클은 그 수행횟수를 최소화하려고 입력 값과 출력 값을 Query Execution Cache에 저장해 둔다. • 서브쿼리가 수행될 때마다 입력값을 캐시에서 찾아보고 거기 있으면 저장된 출력 값을 리턴하고, 없으면 쿼리를 수행한 후 입력 값과 출력 값을 캐시에 저장한다. • 이 기능을 함수 호출 횟수를 줄이는데 사용 • multi buffer의 size는 _query_execution_cache_max_size로 조절 • default 64K  변경 주의!! • 입력 값의 종류가 소수인 경우만 적용, 그렇지 않을 경우 도리어 CPU 부하만 커짐 SQL의 최종 추출 결과가 많은 경우
  • 143. 143 SQL의 최종 추출 결과가 많은 경우 위 쿼리문 성능을 향상하는 방법은? (1가지만 생각해 내는 사람은 초급개발자이고, 2가지 생각해내면 중급개발자) 1번쿼리에서 함수는 몇 번 수행될까? 2번쿼리에서 함수는 몇 번 수행될까?
  • 144. 144 10046 trace file 확인 1번 쿼리에서는 function이 10만번, 2번 쿼리에서는 function이 3번 Function의 입력 값으로 사용되는 컬럼의 NUM_DISTINCT가 적을 때, Function수행을 스칼라 서브쿼리로 변경하면 큰 효과가 있다. 반대의 경우는 오히려 multi buffer를 check하기 위한 1) CPU부하가 올라간다. 2) Function수행을 위한 소프트파싱 및 I/O에 대한 비효율 발생 방안1. 함수가 스칼라서브쿼리에서 수행되도록 변경
  • 145. 145 방안2. Function을 조인문으로 변경 NUM_DISTINCT가 매우 많은 경우 방안1. 은 무용지물이고 오히려 더 비용이 증가한다. 위와 같이 Function을 조인으로 변경하면 성능을 개선할 수 있다. 조인문으로 변경하니 elapsed time이 0.2초로 줄었다. 변경 전에는 elapsed time이 6초 아래 dbms_xplan package결과만으로는 확인 불가, 10046 trace file 확인할것
  • 146. 146 방안2. Function을 조인문으로 변경 • Outer Join은 Select절의 Function을 조인으로 변경할 때 적용해야 하는 제약 • Hash Join은 From절에서 추출된 데이터 건수만큼 반복 수행(인덱스 스캔)시 발생하는 비효율을 제거하기 위한 조인 방식 결론 많은 데이터를 처리하는 Function이 성능문제 개선 방안 1. Function을 스칼라 서브쿼리로 변경 2. Function을 조인으로 변경
  • 147. 147 Where절의 function을 select절로 옮기기 위에서 T1테이블은 조건절 filter결과 16667건 추출되었고, T2테이블은 조건절 t2.c3 in (‘A’) 와 fu_c2_codenm(t2.c4) ~ 로 filtering 해서 5000건 추출되었다. 그렇다면 위에서 fn_c2_codenm 함수는 몇 번 수행되었을까? 10046 trace file을 보면 쉽게 알 수 있지만, 몇 번 수행되었는지 알아내는 SQL 을 작성해 보라.
  • 148. 148 Where절의 function을 select절로 옮기기 LO는 BETWEEN 조건을 아래와 같이 변겨한다. T2.c3 in (‘A’) and FN_C2_CODENM(t2.c4) >= ‘A’ and FN_C2_CODENM(t2.c4) <=‘B’ 따라서 함수 수행횟수는 10000회이다. 그런데 위 실행계획 결과를 보면 T2 테이블은 모든 조건을 filter해서 5000건 이 추출되었다. 즉 FN_C2_CODENM으로는 한 건도 걸러지지 않았다. Where절에 있는 Function을 select절에서 값을 추출한 후, 인라인 뷰로 만들고 Function을 수행하여, 추출한 값을 가지고, 인라인뷰 밖에서 조건을 수행하도 록 SQL을 재작성해야 한다.
  • 149. 149 위와 같이 SQL을 변경하면 어떤 장점이 있을까? FN_C2_CODENM이 몇 번 수행되리라 예상하는가?
  • 150. 150 실행계획을 보면 VIEW가 만들어진 이력이 없다. 즉 우리의 의도(인라인 뷰 내에서 function을 먼저 수행된다)대로 실행계획이 풀리지 않았다. Elapsed time도 줄지 않았다. 위와같은 실행계획에서 함수 수행횟수를 100046 trace file에서 분석했다.
  • 151. 151 10046 trace file을 보니 함수 수행횟수가 20000회이다. 10000회에서 줄일려고 SQL을 수정했는데, 더 늘어나 버렸다. 이거 원인 알아낼려면 10053 trace file을 열어보아야 하고 Logical Optimizer 의 원리를 알아야 한다.
  • 153. 153 VIEW merging 방지 View merging을 막아보았으나 함수 수행횟수는 여전히 20000번이다. Logical Optimizer의 원리를 알아야 한다.
  • 154. 154 In a nutshell select /*+ NO_MERGE(K) */ K.c3, K.c4 from ( select /*+ gather_plan_statistics leading(t1 t2) USE_HASH(T1 T2) */ t1.c3, t2.c4, fn_c2_codenm(t2.c4) as ft2c4 from function_table t1, c1_code_nm t2 where t1.c2 = 0 and t1.c4 = 2 and t1.c1 = t2.c1 and t2.c3 in ('A') and FN_C2_CODENM(t2.c4) >= ‘A’ and FN_C2_CODENM(t2.c4) <= ‘B’ ) K 10053 trace file 분석하면 위 SQL이 보인다. 우리의 현명한 optimizer께서는 위와 같이 마지막에 수행될 Filter조건을 View안으로 침투시키면 더 성능이 좋아질것이라고 판단하고 조건을 View 안으로 집어 넣으신다. (Filter Push Down) 하지만 위와 같이 SQL이 수행되면 t2.c3 in(‘A’) 조건을 만족하는 건수 (5000rows)만큼 함수가 반복 수행된다. Logical Optimizer의 원리를 알아야 우리의 현명하신 Optimizer를 올바른 길로 인도할 수 있다.
  • 155. 155 To make a long story short HASH JOIN에서 1667row가 추 출되었고, 1667row에 대해서 함수를 check조건으로 사용하 여 최종적으로 1667 row가 추 출되었다. Elapsed time 확 줄 었다. 위에서 fn_c2_codnm(t2.c4)함수는 최대 몇 번 수행되었을까? 실제 수행횟수는 10046 trace file을 보기 전에 어떻게 알아낼 수 있을까?
  • 156. 156 To make a long story short Function이 수행되기 전의 t2.c4의 추출건수 및 distinct number를 조사하니 ‘0’ 값 만 1667건 추출되었다. 함수를 스칼라서브쿼리로 만들었으므로 multi buffer를 사 용하여 결국 함수는 1회만 수행한다. (10046 trace file 내용과 일치) 만약 위의 예제에서 t2.c4 컬럼의 값이 unique했다면 함수는 몇 번 수행되었을까? 정답을 말한다면, 당신은 고급개발자의 자질이 있는 것이다.
  • 157. 157 1. 함수를 Join문으로 변경 2. 함수를 스칼라서브쿼리로 만든다. 지금까지 배운 개념 응용2 select memb_nm(매도회원번호) 매도회원이름, memb_nm(매수회원번호) 매수회원이름, 매도계좌번호, 매수계좌번호, 체결시각, 체결수량, 체결가 from 체결 where 종목코드 = :종목코드 and 체결일자 = :체결일자 and 체결시각 between sysdate -10/24 and sysdate; 위 SQL의 결과 건수가 10만건이라면, 어떻게 해야 성능을 향상시킬 수 있을까? Brainstorming Presenter의 답변은 : 문제 뒤에 있음
  • 158. 158 User Defined Funtion 결론 • 소량의 데이터 조회시에만 사용 • 대용량 조회시에는 부분범위처리가 가능 한 상황에서 제한적으로 사용 • 가급적 조인 또는 스칼라서브쿼리 형태로 변환 • 데이터 일관성이 깨지지 않도록 설계하고 개발 • 함수를 사용해야 한다면 호출 횟수를 최소 화 할 수 있는 방법을 강구
  • 159. 159 함수 호출횟수 최소화 방안 • 페이지 처리 또는 부분범위처리 활용 • Decode함수 또는 Case문으로 변환 • View Merge 방지 • 스칼라서브쿼리 캐싱효과을 이용 • Deterministic함수의 캐싱 효과 이용 • Result Cache 이용 • 복잡한 함수 로직을 풀어 SQL로 구현
  • 160. 160 초급개발자가 만든 SQL문 왼쪽의 실행계획을 보 니 access path, join method, join order 모 두 효율적이라고 가정 하자. 그럼 어떤걸 더 조사해야 할까?
  • 161. 161 초급 개발자 SQL의 효율성 분석 • 총 row count • 각 function의 수행 횟수 • 각 function 입력 값의 number of distinct value • Function을 Join으로 변경 • Function 수행 중 base table의 데이터가 변경될 가능성 : integrity 깨질 가능성 • ………