4.10 CA*(Cost Annotation)이란 무엇인가

  • CA란 State Space 내부에서 사용되는 세밀한 메모리 공간으로써 SQL을 쿼리블럭으로 나누어 각 쿼리블럭의 Cost값을 저장하는 용도
  • CBQT 발생시 각 Iteration마다 CA가 사용되므로 아주 중요한 개념
  • CA의 주된 용도는 쿼리블럭의 Cost를 재사용 하기 위함.
  • 쿼리블럭의 Cost를 구하는 일은 Cost Estimator와 Plan Generator를 Call 해야 하기 때문에 무척 비싼 연산
  • 쿼리블럭이 한번 최적화되어 쿼리블럭명과 Cost가 CA에 저장되면 이후에 해당 쿼리블럭의 Cost가 다시 필요할 때 CA를 메모리상에서 이용
{panel:title = 어떻게 사용되나?}
SQL에서 서브쿼리가 2개인 SQL을 실행하면 2개의 서브쿼리가 CSU(Complex Subquery Unnesting)를 수행하며 가능한 모든 경우의수는 아래와 같다.
※숫자표기법의 오른쪽의 정보는 참여한 쿼리블럭명, NEW라는 표시는 CSU에 의해서 새로 생성된 쿼리블럭
CBQT는 특성상 하나의 쿼리블럭과 또 다른 쿼리블럭이 만나 Transformaion이 수행되므로 쿼리블럭이 새로 생성된다
(1,1)NEW(SUBQ2), NEW(SUBQ1)
(1,0)NEW(SUBQ2), SUBQ1 --> NEW(SUBQ2)가 재사용되었다.
(0,1)SUBQ2, NEW(SUBQ1) --> NEW(SUBQ1)이 재사용되었다.
(0,0)SUBQ2, SUBQ1 --> SUBQ2와 SUBQ1이 재사용되었다.

만약 CA가 없다면?

위의 예를 보면 각 쿼리블럭이 2번씩 사용되었다.
CA의 기능이 없다면 Cost를 구하는 연산을 두 번씩 실행해야 하지만 CA의 기능으로 부하를 감소시킬 수 있다.

중요한질문

Iteration에서 Transformation이 완료되고 변경된 SQL의 Cost만 구하면 되지않나?
왜 각각의 Iteration에서 전체SQL이 아닌 SQL의 특정부분(서브쿼리블럭)의 Cost를 구해야하나?

{panel:title = 중요한답변}
각 Iteration에서 개별 쿼리블럭의 Cost를 구하는 이유는 쿼리블럭의 Cost를 이용하여 Cut-off를 하기 위함.
ex)
Iteration1에서 Transformation이 끝나고 완성된 전체 SQL의 Cost가 100이라고 가정.
Iteration2에서 전체 SQL이 아닌 서브쿼리블럭하나의 Cost가 200이라면 Iteration2의 Physical Optimization을 진행할 필요가 없어진다.
바로 Iteration2를 Skip하고 Iteration3으로 넘어갈 수 있다. Hard Parsing시 시간단축

|

{code:SQLtitle= 10053 Trace에서 Cost Annotation이 사용되는 부분borderStyle=solid}
*****************************
Cost-Based Subquery Unnesting
*****************************
SU: Unnesting query blocks in query block MAIN (#1) that are valid to unnest.
Subquery Unnesting on query block MAIN (#1)SU: Performing unnesting that does not require costing.
SU: Considering subquery unnest on query block MAIN (#1). --> SU가 가능한지 Check함
SU: Checking validity of unnesting subquery SUBQ1 (#3) --> Costing 이 필요한 CSU 가 발생함
SU: Passed validity checks, but requires costing.
SU: Checking validity of unnesting subquery SUBQ2 (#2)
SU: Passed validity checks, but requires costing.
SU: Using search type: exhaustive
SU: Starting iteration 1, state space = (2,3) : (1,1)
SU: Unnesting subquery query block SUBQ1 (#3)Subquery removal for query block SUBQ1 (#3)
RSW: Not valid for subquery removal SUBQ1 (#3)
Subquery unchanged.
Registered qb: SEL$9F3C0132 0x805f7410 (SUBQ INTO VIEW FOR COMPLEX UNNEST SUBQ1) --> SEL$9F3C0132 : 새로만들어진 쿼리블록명
--> Iteration1에서 SUBQ1이 Unnestig 되어 서브쿼리가 VIew로 변환
{code}
{code:SQL
title= traceborderStyle=solid}
SU: Costing transformed query.
CBQT: Looking for cost annotations for query block SEL$9F3C0132,key=SEL$9F3C0132_00001002_3 --> View로 변환된 QB(SEL$9F3C0132)에 대해 Costing을 시도
CBQT: Could not find stored cost annotations. --> 위의 Key 값으로 CA를 찾지 못함
...중간생략
kkoqbc: optimizing query block SEL$9F3C0132 (#3) --> CA를 찾지못했으므로 Costing(kkoqbc)이 진행
...중간생략
Transfer Optimizer annotations for query block SEL$9F3C0132 (#3) --> 결과를 CA에 Key값으로저장(Transfer)
Final cost for query block SEL$9F3C0132 (#3) - All Rows Plan:
Best join order: 1
Cost: 515.3201 Degree: 1 Card: 918843.0000 Bytes: 7350744
...중간생략
kkoqbc: finish optimizing query block SEL$9F3C0132 (#3) --> Costing을 마침
{code}
{code:SQL
title= traceborderStyle=solid}나
CBQT: Saved costed qb# 3 (SEL$9F3C0132), key = SEL$9F3C0132_00001002_3 --> 한번 저장된CA는 저장된 Cost를 이용하거나
...중간생략 CA를 재사용하기위해서 Key값으로 CA주소를 찾아
CBQT: Looking for cost annotations for query block SEL$9F3C0132, key = SEL$9F3C0132_00001002_3 메모리 공간을 지울 수 있다
CBQT: Replaced cost annotations in query block SEL$9F3C0132.
{code}
* CA기능을 Control 하는 파라미터 : _optimizer_reuse_cost_annotations(default=true)