> For the complete documentation index, see [llms.txt](https://docs.tibero.com/tibero-manuals/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tibero.com/tibero-manuals/7.2.6.manuals/tbpsm-reference-guide/dbms_sqltune.md).

# DBMS\_SQLTUNE

DBMS\_SQLTUNE 패키지의 기본 개념과 패키지 내의 프러시저와 함수를 사용하는 방법을 설명합니다.

## **개요**

**DBMS\_SQLTUNE** 패키지는 SQL 튜닝 관련 기능을 위한 인터페이스를 제공합니다. 제공하는 기능은 다음과 같습니다.

* Real-Time SQL Monitoring
* SQL Tuning Advisor
* SQL Profile
* SQL 질의문 정규화와 식별

기능별로 사용하는 서브프로그램은 다음과 같습니다.

<table><thead><tr><th width="230">기능</th><th>서브프로그램</th></tr></thead><tbody><tr><td>Real-Time SQL Monitoring</td><td>REPORT_SQL_MONITOR</td></tr><tr><td>SQL Tuning Advisor</td><td>REPORT_SQL_ACCESS_ADVISOR, REPORT_SQL_ADVISOR, REPORT_SQL_STAT_ADVISOR, SQL_TUNE_BY_ADJUST_SELECT</td></tr><tr><td>SQL Profile</td><td>ALTER_SQL_PROFILE, DROP_SQL_PROFILE, GET_PROFILE_HINTS, GET_PROFILE_HINTS_GV, IMPORT_SQL_PROFILE, VERIFY_SQL_PROFILE</td></tr><tr><td>SQL 질의문 정규화와 식별</td><td>NORMALIZE_SQLTEXT, SQLTEXT_TO_SIGNATURE</td></tr></tbody></table>

본 패키지의 서브프로그램은 정의자 권한(AUTHID DEFINER)으로 수행되므로 항상 SYS 권한으로 딕셔너리에 접근합니다. 패키지에는 PUBLIC 시노님과 PUBLIC EXECUTE 권한이 부여되어 있어 별도 권한 없이도 모든 사용자가 호출할 수 있습니다.

SQL Profile은 세션이 아니라 **딕셔너리에 영속**하며 DBA\_SQL\_PROFILES 뷰로 조회합니다. 생성, 변경, 삭제는 각 서브프로그램 내부에서 커밋되므로 호출한 세션에서 롤백할 수 없습니다.

SQL Profile의 일반적인 사용 흐름은 다음과 같습니다.

1. 원하는 실행계획을 만들어 놓은 뒤 GET\_PROFILE\_HINTS\_GV 또는 GET\_PROFILE\_HINTS로 그 플랜의 outline 힌트 목록을 얻습니다.
2. IMPORT\_SQL\_PROFILE에 대상 질의문과 outline 힌트 목록을 전달해 SQL Profile을 생성합니다.
3. 대상 질의문을 수행해 실행계획과 함께 출력되는 Note 항목으로 SQL Profile 적용 여부를 확인합니다.
4. 스키마가 바뀐 뒤에도 SQL Profile이 여전히 유효한지 VERIFY\_SQL\_PROFILE로 검사하고, 필요하면 ALTER\_SQL\_PROFILE로 속성을 변경하거나 DROP\_SQL\_PROFILE로 삭제합니다.

outline 힌트를 추출하려면 대상 플랜이 `OPTIMIZER_LOG_OUTLINE` 초기화 파라미터가 `Y`인 상태에서 하드파싱되어 있어야 합니다. 이 파라미터의 기본값은 `Y`이므로 기본 설정에서는 따로 지정하지 않아도 됩니다. 이 파라미터를 `N`으로 바꾼 상태에서 만들어진 플랜에는 outline 정보가 남지 않으므로 GET\_PROFILE\_HINTS와 GET\_PROFILE\_HINTS\_GV가 빈 컬렉션을 반환합니다.

## **타입**

본 절에서는 DBMS\_SQLTUNE 패키지의 서브프로그램이 사용하는 타입을 설명합니다.

### **SQLPROF\_ATTR**

outline 힌트를 목록으로 관리하기 위한 컬렉션 타입입니다. GET\_PROFILE\_HINTS와 GET\_PROFILE\_HINTS\_GV의 반환 타입이고, IMPORT\_SQL\_PROFILE의 profile 파라미터가 받는 타입입니다.

이 타입은 패키지 안에 선언된 타입이 아니라 **SYS 소유의 독립 타입**입니다. PUBLIC 시노님과 PUBLIC EXECUTE 권한이 부여되어 있으므로 패키지 이름을 앞에 붙이지 않고 `SQLPROF_ATTR(...)` 형태로 바로 사용합니다.

SQLPROF\_ATTR 타입의 세부 내용은 다음과 같습니다.

* 프로토타입

```
CREATE OR REPLACE TYPE SQLPROF_ATTR AS VARRAY(2000) OF VARCHAR2(500);
```

원소는 최대 2,000개까지 담을 수 있고 원소 하나의 길이는 최대 500바이트입니다.

## **프러시저와 함수**

본 절에서는 DBMS\_SQLTUNE 패키지에서 제공하는 프러시저와 함수를 알파벳 순으로 설명합니다.

### **ALTER\_SQL\_PROFILE**

생성되어 있는 SQL Profile의 속성을 변경하는 프러시저입니다. 변경할 수 있는 속성은 CATEGORY, DESCRIPTION, NAME, STATUS 네 가지이며, 그 외의 내용을 바꾸려면 SQL Profile을 삭제한 뒤 다시 생성해야 합니다.

attribute\_name과 value는 대소문자를 구분합니다. 속성 이름을 소문자로 전달하면 인식하지 못하고 TBR-14313 오류가 발생합니다.

네 가지 속성 이름이 아닌 값을 전달했을 때 발생하는 오류는 그 값의 길이에 따라 달라집니다. 길이가 11바이트 이하이면 TBR-14313 오류가 발생하고, 11바이트를 넘으면 TBR-15115 오류가 발생합니다. DBA\_SQL\_PROFILES 뷰에는 있지만 이 프러시저로 바꿀 수 없는 FORCE\_MATCHING 컬럼 이름을 전달하는 경우가 후자에 해당합니다.

name에 존재하지 않는 SQL Profile 이름을 주면 TBR-14312 오류가 발생합니다.

변경할 수 있는 속성은 다음과 같습니다.

<table><thead><tr><th width="150">속성</th><th>설명</th></tr></thead><tbody><tr><td>CATEGORY</td><td><ul><li>SQL Profile의 분류</li><li>지정한 분류를 이미 사용하고 있는 SQL Profile이 하나라도 있으면 TBR-14311 오류가 발생함. 자기 자신이 쓰고 있는 분류를 다시 지정하는 경우도 오류에 해당함</li></ul></td></tr><tr><td>DESCRIPTION</td><td>SQL Profile에 대한 설명. 최대 500바이트까지 작성할 수 있음</td></tr><tr><td>NAME</td><td><ul><li>SQL Profile의 이름</li><li>같은 이름을 쓰는 SQL Profile이 이미 있으면 TBR-14311 오류가 발생함. 자기 자신의 이름을 다시 지정하는 경우도 오류에 해당함</li></ul></td></tr><tr><td>STATUS</td><td>SQL Profile의 활성화 여부. ENABLED와 DISABLED 중 한 가지 값으로만 설정할 수 있으며 다른 값을 주면 TBR-14314 오류가 발생함</td></tr></tbody></table>

ALTER\_SQL\_PROFILE 프러시저의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.ALTER_SQL_PROFILE
(
    name           IN VARCHAR2,
    attribute_name IN VARCHAR2,
    value          IN VARCHAR2
)
```

* 파라미터

<table><thead><tr><th width="223">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>name</td><td><ul><li>속성을 변경하고자 하는 SQL Profile의 이름</li><li>존재하지 않는 이름을 주면 TBR-14312 오류가 발생함</li></ul></td></tr><tr><td>attribute_name</td><td><ul><li>SQL Profile에서 변경하고자 하는 속성의 이름</li><li>CATEGORY, DESCRIPTION, NAME, STATUS 중 한 가지여야 함. 그 외의 값은 길이가 11바이트 이하이면 TBR-14313, 11바이트를 넘으면 TBR-15115 오류가 발생함</li></ul></td></tr><tr><td>value</td><td><ul><li>변경할 SQL Profile 속성의 값</li><li>NULL이면 TBR-14314 오류가 발생함</li><li>500바이트를 넘으면 TBR-15115 오류가 발생함</li></ul></td></tr></tbody></table>

* 예제

다음은 SQL Profile의 설명, 활성화 여부, 이름을 차례로 변경하는 예제입니다. 대상 SQL Profile은 IMPORT\_SQL\_PROFILE 항목의 예제로 생성한 것입니다.

```
select name, description, status from dba_sql_profiles where name = 'ST11_PROF2';

NAME         DESCRIPTION                STATUS
------------ -------------------------- --------
ST11_PROF2                              ENABLED

1 row selected.

BEGIN
    DBMS_SQLTUNE.ALTER_SQL_PROFILE(
        NAME           => 'ST11_PROF2'
      , ATTRIBUTE_NAME => 'DESCRIPTION'
      , VALUE          => 'altered by example'
    );
END;
/

PSM completed.

select name, description, status from dba_sql_profiles where name = 'ST11_PROF2';

NAME         DESCRIPTION                STATUS
------------ -------------------------- --------
ST11_PROF2   altered by example         ENABLED

1 row selected.

BEGIN
    DBMS_SQLTUNE.ALTER_SQL_PROFILE('ST11_PROF2', 'STATUS', 'DISABLED');
END;
/

PSM completed.

select name, description, status from dba_sql_profiles where name = 'ST11_PROF2';

NAME         DESCRIPTION                STATUS
------------ -------------------------- --------
ST11_PROF2   altered by example         DISABLED

1 row selected.

BEGIN
    DBMS_SQLTUNE.ALTER_SQL_PROFILE('ST11_PROF2', 'NAME', 'ST11_PROF3');
END;
/

PSM completed.

select name, description, status from dba_sql_profiles where name = 'ST11_PROF3';

NAME         DESCRIPTION                STATUS
------------ -------------------------- --------
ST11_PROF3   altered by example         DISABLED

1 row selected.
```

### **DROP\_SQL\_PROFILE**

생성되어 있는 SQL Profile을 삭제하는 프러시저입니다. 삭제와 함께 대상 SQL의 Physical Plan Cache 항목을 무효화하므로 다음 수행에서는 SQL Profile이 적용되지 않은 플랜이 다시 만들어집니다.

DROP\_SQL\_PROFILE 프러시저의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.DROP_SQL_PROFILE
(
    name    IN VARCHAR2,
    ignore  IN BOOLEAN DEFAULT FALSE
)
```

* 파라미터

<table><thead><tr><th width="208">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>name</td><td>삭제하고자 하는 SQL Profile의 이름</td></tr><tr><td>ignore</td><td><ul><li>지정한 SQL Profile이 없을 때 오류를 무시할지 여부</li><li>FALSE(기본값): TBR-14312 오류가 발생함</li><li>TRUE: 아무 것도 삭제하지 않고 정상 종료함</li></ul></td></tr></tbody></table>

* 예제

```
select name, sql_text from dba_sql_profiles order by name;

NAME         SQL_TEXT
------------ --------------------------------------------------
ST11_PROF1   select /*+ full(t) */ * from st11_t t where c1 = 1
ST11_PROF3   select /*+ full(t) */ * from st11_t t where c1 = 2

2 rows selected.

BEGIN
    DBMS_SQLTUNE.DROP_SQL_PROFILE(NAME => 'ST11_PROF3');
END;
/

PSM completed.

select name, sql_text from dba_sql_profiles order by name;

NAME         SQL_TEXT
------------ --------------------------------------------------
ST11_PROF1   select /*+ full(t) */ * from st11_t t where c1 = 1

1 row selected.
```

다음은 이미 삭제된 SQL Profile을 다시 삭제하는 예제입니다. ignore를 생략하면 오류가 발생하고, TRUE를 주면 정상 종료합니다.

```
BEGIN
    DBMS_SQLTUNE.DROP_SQL_PROFILE('ST11_PROF3');
END;
/
TBR-14312: SQL Profile doesn't exist.
...
TBR-15104: No matching data found.

BEGIN
    DBMS_SQLTUNE.DROP_SQL_PROFILE('ST11_PROF3', TRUE);
END;
/

PSM completed.
```

### **GET\_PROFILE\_HINTS**

TPR(Tibero Performance Repository)에 저장되어 있는 플랜에 대해, 해당 플랜을 생성하기 위한 outline 힌트의 목록을 반환하는 함수입니다.

대상 플랜은 `OPTIMIZER_LOG_OUTLINE` 초기화 파라미터가 `Y`인 상태에서 하드파싱되어 outline 정보가 함께 저장되어 있어야 합니다. 조건에 맞는 플랜을 찾지 못하면 오류가 발생하지 않고 원소가 없는 컬렉션을 반환합니다.

GET\_PROFILE\_HINTS 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.GET_PROFILE_HINTS
(
    in_sql_id          IN VARCHAR2,
    in_plan_hash_value IN NUMBER
)
RETURN SQLPROF_ATTR;
```

* 파라미터

<table><thead><tr><th width="230">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>in_sql_id</td><td>Outline 힌트를 추출할 플랜의 SQL ID</td></tr><tr><td>in_plan_hash_value</td><td>Outline 힌트를 추출할 플랜의 Plan hash value</td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="249">반환값</th><th>설명</th></tr></thead><tbody><tr><td>SQLPROF_ATTR 데이터</td><td>대상 플랜으로부터 추출한 outline 힌트의 목록을 반환</td></tr></tbody></table>

* 예제

다음은 outline 정보가 함께 저장된 플랜을 찾아 그 중 하나의 outline 힌트를 조회하는 예제입니다. 반환되는 목록에는 optimizer 파라미터를 기록한 OPT\_PARAM 힌트가 함께 들어 있으므로 예제에서는 조인 방법과 접근 경로를 지정하는 `USE_`로 시작하는 힌트만 걸러 냈습니다. SQL ID와 Plan hash value는 인스턴스마다 다릅니다.

```
select sql_id, plan_hash_value from
    (select sql_id, plan_hash_value from dba_hist_sql_plan where other_xml is not null)
 where rownum <= 5;

SQL_ID        PLAN_HASH_VALUE
------------- ---------------
f3qyamyzjr9tu      4121709479
9zthxmb0fxu0m      1229391174
9h1j83g1chd12      4121709479
7qwq2174y2a32      4070056454
7c5k4jv99f35r      3289779723

5 rows selected.

select column_value as outline_hint
  from table(dbms_sqltune.get_profile_hints('7c5k4jv99f35r', 3289779723))
 where column_value like 'USE_%';

OUTLINE_HINT
--------------------------------------------
USE_NL@LPN$16(LPN$16 LPN$20)
USE_INDEX@LPN$16(LPN$16 LPN$22)
USE_INDEX@LPN$16(LPN$16 LPN$21)
USE_INDEX@LPN$16(LPN$16 LPN$18)
USE_INDEX@LPN$16(LPN$17 LPN$19)
USE_INDEX@LPN$7(LPN$9 LPN$8)
USE_INDEX@LPN$13(LPN$15 LPN$14)

7 rows selected.
```

### **GET\_PROFILE\_HINTS\_GV**

Physical Plan Cache에 등록되어 있는 플랜에 대해, 해당 플랜을 생성하기 위한 outline 힌트의 목록을 반환하는 함수입니다. GET\_PROFILE\_HINTS와 달리 Child number까지 지정해 플랜 하나를 정확히 가리킵니다.

대상 플랜은 `OPTIMIZER_LOG_OUTLINE` 초기화 파라미터가 `Y`인 상태에서 하드파싱되어 있어야 합니다. 조건에 맞는 플랜을 찾지 못하면 오류가 발생하지 않고 원소가 없는 컬렉션을 반환합니다.

GET\_PROFILE\_HINTS\_GV 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.GET_PROFILE_HINTS_GV
(
    in_sql_id          IN VARCHAR2,
    in_plan_hash_value IN NUMBER,
    in_child_number    IN NUMBER
)
RETURN SQLPROF_ATTR;
```

* 파라미터

<table><thead><tr><th width="247">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>in_sql_id</td><td>Outline 힌트를 추출할 플랜의 SQL ID</td></tr><tr><td>in_plan_hash_value</td><td>Outline 힌트를 추출할 플랜의 Plan hash value</td></tr><tr><td>in_child_number</td><td>Outline 힌트를 추출할 플랜의 Child number</td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="257">반환값</th><th>설명</th></tr></thead><tbody><tr><td>SQLPROF_ATTR 데이터</td><td>대상 플랜으로부터 추출한 outline 힌트의 목록을 반환</td></tr></tbody></table>

* 예제

다음은 인덱스를 사용하는 플랜을 하드파싱한 뒤 그 플랜의 outline 힌트를 조회하는 예제입니다. 반환 목록에 함께 들어 있는 OPT\_PARAM 힌트는 걸러 냈습니다. SQL ID, Plan hash value, Child number는 인스턴스와 수행 시점에 따라 달라집니다. `OPTIMIZER_LOG_OUTLINE`은 기본값이 `Y`이므로 예제의 `alter session` 문장은 전제 조건을 명시하기 위해 넣은 것입니다.

```
create table st11_t (c1 number, c2 varchar2(20));

Table 'ST11_T' created.

insert into st11_t select level, 'v' || level from dual connect by level <= 1000;

1000 rows inserted.

commit;

Commit completed.

create index st11_idx on st11_t (c1);

Index 'ST11_IDX' created.

exec dbms_stats.gather_table_stats(user, 'ST11_T', cascade=>TRUE);

PSM completed.

alter session set optimizer_log_outline=y;

Session altered.

set autot traceonly exp
select /*+ index_rs(t st11_idx) */ * from st11_t t where c1 = 1;

SQL ID: 9quphx8w78gk0
Child number: 2968
Plan hash value: 838298852

Execution Plan
----------------------------------------------------------------------------------------------------
   1  TABLE ACCESS (ROWID): ST11_T (Cost:3, %%CPU:0, Rows:1)
   2    INDEX (RANGE SCAN): ST11_IDX (Cost:2, %%CPU:0, Rows:1)


Predicate Information
----------------------------------------------------------------------------------------------------
   2 - access: ("T"."C1" = 1) (0.001)

set autot off
select column_value as outline_hint
  from table(dbms_sqltune.get_profile_hints_gv('9quphx8w78gk0', 838298852, 2968))
 where column_value not like 'OPT_PARAM%';

OUTLINE_HINT
------------------------------------------------------------
ROWID@LPN$3(ST11_T)
INDEX_RS@LPN$3(ST11_IDX)

2 rows selected.
```

### **IMPORT\_SQL\_PROFILE**

SQL Profile을 생성하는 프러시저입니다. SQL Profile을 생성한 뒤 대상 SQL 질의를 수행하면 해당 질의에 기재되어 있는 힌트는 무시되고, 대신 SQL Profile에 명시되어 있는 outline 힌트가 적용됩니다.

같은 SQL Profile이 이미 있는지는 '질의문의 signature + 분류' 조합과 이름 두 가지로 판정합니다. 둘 중 하나라도 겹치는 SQL Profile이 있으면 replace가 FALSE일 때 TBR-14311 오류가 발생합니다.

replace가 TRUE인 경우에 갱신되는 것은 **signature와 분류가 모두 일치하는 기존 항목**의 설명과 outline 힌트 목록입니다. 따라서 다음 두 가지 경우를 주의해야 합니다.

* signature와 분류가 일치하고 이름만 다른 경우: 기존 항목이 갱신되고 name에 지정한 이름은 무시됩니다. 지정한 이름을 가진 SQL Profile은 만들어지지 않습니다.
* 이름만 겹치고 질의문이나 분류가 다른 경우: 오류가 발생하지 않는데도 갱신이 일어나지 않고, 새 SQL Profile도 만들어지지 않습니다.

replace를 쓸 때는 대상 질의문과 분류가 기존 항목과 같은지 먼저 확인해야 합니다.

name을 생략하면 `SYS_SQLPROF_` 뒤에 **대상 질의문과 분류를 공백 하나로 이어 붙인 문자열**의 signature를 16진수로 붙인 이름이 자동으로 만들어집니다. 이 16진수 값은 DBA\_SQL\_PROFILES의 SIGNATURE 컬럼 값과 다릅니다. 질의문만으로 얻은 signature를 16진수로 바꿔 자동 생성 이름을 예측할 수는 없습니다.

IMPORT\_SQL\_PROFILE 프러시저의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.IMPORT_SQL_PROFILE
(
    sql_text      IN CLOB,
    profile       IN SQLPROF_ATTR,
    category      IN VARCHAR2 DEFAULT 'DEFAULT',
    name          IN VARCHAR2 DEFAULT NULL,
    description   IN VARCHAR2 DEFAULT NULL,
    replace       IN BOOLEAN DEFAULT FALSE,
    force_match   IN BOOLEAN DEFAULT FALSE
)
```

* 파라미터

<table><thead><tr><th width="143">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_text</td><td>생성할 SQL Profile의 대상 SQL 질의문</td></tr><tr><td>profile</td><td>생성할 SQL Profile의 대상 SQL 질의에 적용하고자 하는 outline 힌트의 목록</td></tr><tr><td>category</td><td>생성할 SQL Profile의 분류</td></tr><tr><td>name</td><td><ul><li>생성할 SQL Profile의 이름</li><li>생략하면 대상 질의문과 분류를 이어 붙인 문자열의 signature로부터 이름이 자동으로 만들어짐</li><li>replace가 TRUE이고 signature와 분류가 일치하는 항목이 이미 있으면 이 값은 무시됨</li></ul></td></tr><tr><td>description</td><td>생성할 SQL Profile에 대한 설명. 최대 500바이트</td></tr><tr><td>replace</td><td><p>동일한 이름 또는 동일한 ‘SQL 질의 + 분류’ 조합의 SQL Profile이 이미 존재하는 경우, 현재 생성하고자 하는 내용으로 대체할지 여부</p><ul><li>FALSE(기본값): TBR-14311 오류가 발생함</li><li>TRUE: signature와 분류가 모두 일치하는 항목만 갱신됨. 이름만 겹치는 경우에는 오류도 갱신도 일어나지 않음</li></ul></td></tr><tr><td>force_match</td><td><p>생성할 SQL Profile의 적용 범위</p><ul><li>TRUE: 대상 SQL 질의와 리터럴만 다른 형태의 질의에 대해서도 SQL Profile을 적용(CURSOR_SHARING=FORCE에 대응). DBA_SQL_PROFILES의 FORCE_MATCHING 컬럼이 YES가 됨</li><li>FALSE: 대상 SQL 질의와 리터럴까지 같은 질의에 대해서만 SQL Profile을 적용(CURSOR_SHARING=EXACT에 대응). 키워드와 식별자의 대소문자 차이, 질의문 안쪽의 연속된 공백과 개행 차이는 무시되지만 질의문 앞뒤의 공백은 무시되지 않음</li></ul></td></tr></tbody></table>

* 예제

다음은 튜닝 플랜으로부터 outline 힌트를 추출해 SQL Profile을 생성하는 예제입니다. GET\_PROFILE\_HINTS\_GV 항목의 예제에서 확보한 플랜을 그대로 사용합니다. SQL Profile을 생성한 뒤에는 질의문에 기재한 FULL 힌트가 무시되고 인덱스를 사용하는 플랜이 선택됩니다.

```
BEGIN
    DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
        SQL_TEXT     => 'select /*+ full(t) */ * from st11_t t where c1 = 1'
      , PROFILE      => DBMS_SQLTUNE.GET_PROFILE_HINTS_GV('9quphx8w78gk0', 838298852, 2968)
      , NAME         => 'ST11_PROF1'
      , DESCRIPTION  => 'index_rs plan for st11_t'
    );
END;
/

PSM completed.

set autot traceonly exp
select /*+ full(t) */ * from st11_t t where c1 = 1;

SQL ID: 78z135mcx1rgy
Child number: 2971
Plan hash value: 838298852

Execution Plan
----------------------------------------------------------------------------------------------------
   1  TABLE ACCESS (ROWID): ST11_T (Cost:3, %%CPU:0, Rows:1)
   2    INDEX (RANGE SCAN): ST11_IDX (Cost:2, %%CPU:0, Rows:1)


Predicate Information
----------------------------------------------------------------------------------------------------
   2 - access: ("T"."C1" = 1) (0.001)


Note
----------------------------------------------------------------------------------------------------
   0 - SQL profile "ST11_PROF1" was used

set autot off
```

다음은 outline 힌트를 직접 작성해 SQL Profile을 생성하는 예제입니다.

```
BEGIN
    DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
        SQL_TEXT => 'select /*+ full(t) */ * from st11_t t where c1 = 2'
      , PROFILE  => SQLPROF_ATTR('ROWID@LPN$3(ST11_T)'
                               , 'INDEX_RS@LPN$3(ST11_IDX)')
      , NAME     => 'ST11_PROF2'
    );
END;
/

PSM completed.

set autot traceonly exp
select /*+ full(t) */ * from st11_t t where c1 = 2;

SQL ID: 238buzhzqc0fu
Child number: 2974
Plan hash value: 838298852

Execution Plan
----------------------------------------------------------------------------------------------------
   1  TABLE ACCESS (ROWID): ST11_T (Cost:3, %%CPU:0, Rows:1)
   2    INDEX (RANGE SCAN): ST11_IDX (Cost:2, %%CPU:0, Rows:1)


Predicate Information
----------------------------------------------------------------------------------------------------
   2 - access: ("T"."C1" = 2) (0.001)


Note
----------------------------------------------------------------------------------------------------
   0 - SQL profile "ST11_PROF2" was used

set autot off
```

### **NORMALIZE\_SQLTEXT**

대상 SQL 질의문으로부터 SIGNATURE를 얻을 때의 질의문 형태를 반환하는 함수입니다. 반환되는 질의문은 키워드와 식별자가 대문자로 바뀐 형태이며, force\_match에 0이 아닌 값을 주면 리터럴이 바인드 변수로 치환됩니다.

force\_match에는 **기본값이 없으므로 항상 인자로 전달해야 합니다.** 생략하면 호출 문장이 컴파일되지 않고 TBR-15146 오류와 TBR-15039 오류가 차례로 출력됩니다.

NORMALIZE\_SQLTEXT 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.NORMALIZE_SQLTEXT
(
    sql_text     IN CLOB,
    force_match  IN BINARY_INTEGER
)
RETURN CLOB;
```

* 파라미터

<table><thead><tr><th width="166">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_text</td><td>형태를 변환할 SQL 질의문</td></tr><tr><td>force_match</td><td><ul><li>0이 아닌 값: 질의문의 리터럴을 바인드 변수로 치환(CURSOR_SHARING=FORCE에 대응)</li><li>0: 질의문의 리터럴을 바인드 변수로 치환하지 않음(CURSOR_SHARING=EXACT에 대응)</li></ul></td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="192">반환값</th><th>설명</th></tr></thead><tbody><tr><td>CLOB 데이터</td><td>변환된 SQL 질의문을 반환</td></tr></tbody></table>

* 예제

```
set serveroutput on
DECLARE
    ret1 CLOB;
    ret2 CLOB;
BEGIN
    ret1 := DBMS_SQLTUNE.NORMALIZE_SQLTEXT('select c2 from st11_t where c1 = 1', 0);
    ret2 := DBMS_SQLTUNE.NORMALIZE_SQLTEXT('select c2 from st11_t where c1 = 2', 0);
    DBMS_OUTPUT.PUT_LINE(ret1);
    DBMS_OUTPUT.PUT_LINE(ret2);
    ret1 := DBMS_SQLTUNE.NORMALIZE_SQLTEXT('select c2 from st11_t where c1 = 1', 1);
    ret2 := DBMS_SQLTUNE.NORMALIZE_SQLTEXT('select c2 from st11_t where c1 = 2', 1);
    DBMS_OUTPUT.PUT_LINE(ret1);
    DBMS_OUTPUT.PUT_LINE(ret2);
END;
/
SELECT C2 FROM ST11_T WHERE C1 = 1
SELECT C2 FROM ST11_T WHERE C1 = 2
SELECT C2 FROM ST11_T WHERE C1 = :"SYS_B_0"
SELECT C2 FROM ST11_T WHERE C1 = :"SYS_B_0"

PSM completed.
```

### **REPORT\_SQL\_ACCESS\_ADVISOR**

대상 플랜의 수행 결과를 기반으로, SQL 질의의 성능 향상에 기여할 수 있는 인덱스 생성을 추천하는 함수입니다. 추천 결과는 텍스트 형태로 확인할 수 있습니다.

리포트는 `Recommendation to create one or more indices` 항목 하나로 구성됩니다. 추천할 인덱스가 없으면 `No recommendation exists.`가 출력됩니다.

추천 대상은 전체 스캔으로 처리된 테이블 중 플랜 노드별 수행 통계가 수집되어 있고 인덱스를 사용하는 편이 유리하다고 판정된 것으로 한정됩니다. **기본 설정에서는 이 조건을 만족하는 대상이 만들어지지 않으므로 항상 `No recommendation exists.`만 출력됩니다.**

REPORT\_SQL\_ACCESS\_ADVISOR 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.REPORT_SQL_ACCESS_ADVISOR
(
    sql_id       IN VARCHAR,
    child_number IN NUMBER
)
RETURN CLOB;
```

* 파라미터

<table><thead><tr><th width="198">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_id</td><td>인덱스 추천에 참조할 플랜의 SQL ID</td></tr><tr><td>child_number</td><td>인덱스 추천에 참조할 플랜의 Child number</td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="206">반환값</th><th>설명</th></tr></thead><tbody><tr><td>CLOB 데이터</td><td>인덱스 추천 결과가 기재되어 있는 문자열을 CLOB 형태로 반환</td></tr></tbody></table>

* 예제

다음은 통계를 수집하지 않은 테이블을 전체 스캔하는 플랜을 대상으로 리포트를 생성하는 예제입니다.

```
create table st11_nostat (c1 number, c2 varchar2(20));

Table 'ST11_NOSTAT' created.

insert into st11_nostat select level, 'v' || level from dual connect by level <= 5000;

5000 rows inserted.

commit;

Commit completed.

set autot traceonly exp
select count(*) from st11_nostat where c1 > 10;

SQL ID: 56ppmv1uu2tnv
Child number: 3008
Plan hash value: 3390603163

Execution Plan
----------------------------------------------------------------------------------------------------
   1  COLUMN PROJECTION (Cost:12, %%CPU:0, Rows:1)
   2    SORT AGGR (Cost:12, %%CPU:0, Rows:1)
   3      TABLE ACCESS (FULL): ST11_NOSTAT (Cost:12, %%CPU:0, Rows:4990)


Predicate Information
----------------------------------------------------------------------------------------------------
   3 - filter: ("ST11_NOSTAT"."C1" > 10) (0.998)


Note
----------------------------------------------------------------------------------------------------
   3 - dynamic sampling used for this table (13 blocks)

set autot off
set long 1000000
col report for a100
select dbms_sqltune.report_sql_access_advisor('56ppmv1uu2tnv', 3008) as report from dual;

REPORT
----------------------------------------------------------------------------------------------------
--------------------------------------------
Recommendation to create one or more indices
--------------------------------------------
No recommendation exists.

1 row selected.
```

### **REPORT\_SQL\_ADVISOR**

대상 플랜의 수행 결과를 기반으로, SQL 질의의 성능 향상에 기여할 수 있는 인덱스 생성 및 통계 수집을 추천하는 함수입니다. 추천 결과는 텍스트 형태로 확인할 수 있습니다.

리포트는 REPORT\_SQL\_ACCESS\_ADVISOR의 인덱스 추천 항목과 REPORT\_SQL\_STAT\_ADVISOR의 통계 수집 추천 항목을 차례로 이어 붙인 형태입니다.

REPORT\_SQL\_ADVISOR 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.REPORT_SQL_ADVISOR
(
    sql_id       IN VARCHAR,
    child_number IN NUMBER
)
RETURN CLOB;
```

* 파라미터

<table><thead><tr><th width="176">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_id</td><td>인덱스 및 통계 수집 추천에 참조할 플랜의 SQL ID</td></tr><tr><td>child_number</td><td>인덱스 및 통계 수집 추천에 참조할 플랜의 Child number</td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="153">반환값</th><th>설명</th></tr></thead><tbody><tr><td>CLOB 데이터</td><td>인덱스 및 통계 수집 추천 결과가 기재되어 있는 문자열을 CLOB 형태로 반환</td></tr></tbody></table>

* 예제

다음은 REPORT\_SQL\_ACCESS\_ADVISOR 항목의 예제에서 만든 플랜을 대상으로 리포트를 생성하는 예제입니다.

```
set long 1000000
col report for a100
select dbms_sqltune.report_sql_advisor('56ppmv1uu2tnv', 3008) as report from dual;

REPORT
----------------------------------------------------------------------------------------------------
--------------------------------------------
Recommendation to create one or more indices
--------------------------------------------
No recommendation exists.
-------------------------------------
Tables which need more bucket in stat
-------------------------------------
-------------------------------------
Tables which need to gather stat
-------------------------------------
SYS.ST11_NOSTAT

1 row selected.
```

### **REPORT\_SQL\_MONITOR**

특정 SQL 수행에 대해서 실시간 SQL 모니터링 기능에 의해 수집된 성능 관련 정보를 보고서 형태로 돌려주는 함수입니다. 보고서 형식은 텍스트 형식입니다.

모니터링 대상이 된 SQL 수행만 보고서로 만들 수 있습니다. 대상 질의에 MONITOR 힌트를 기재하면 그 수행을 모니터링 대상으로 만들 수 있고, 모니터링된 수행 목록은 V$SQL\_MONITOR 뷰로 조회합니다.

보고서는 다음 항목으로 구성됩니다.

<table><thead><tr><th width="270">항목</th><th>설명</th></tr></thead><tbody><tr><td>SQL Text</td><td>대상 SQL의 질의문</td></tr><tr><td>Global Information</td><td>수행 상태, 세션 식별자, SQL ID, SQL Execution ID, 수행 시작 시각, 클라이언트 프로그램 이름</td></tr><tr><td>Binds</td><td>바인드 변수의 이름, 위치, 타입, 값. 바인드 변수가 없으면 이 항목은 출력되지 않음</td></tr><tr><td>Global Stats</td><td>소요 시간, CPU 시간, 패치 횟수, buffer get 수 등 수행 전체의 통계</td></tr><tr><td>SQL Plan Monitoring Details</td><td>플랜 노드별 예측값과 실제 처리 row 수, 사용 메모리 등</td></tr></tbody></table>

보고서의 시각, 세션 식별자, 통계값은 인스턴스와 수행 시점에 따라 달라집니다.

REPORT\_SQL\_MONITOR 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.REPORT_SQL_MONITOR
(
    sql_id         IN VARCHAR  DEFAULT NULL,
    session_id     IN NUMBER   DEFAULT NULL,
    session_serial IN NUMBER   DEFAULT NULL,
    sql_exec_start IN DATE     DEFAULT NULL,
    sql_exec_id    IN NUMBER   DEFAULT NULL
)
RETURN CLOB;
```

* 파라미터

<table><thead><tr><th width="185">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_id</td><td><ul><li>보고서를 생성할 SQL 수행의 SQL 식별자</li><li>여기에 NULL을 명시하면 현재 시스템에서 가장 최근에 모니터링된 SQL 수행에 대한 보고서를 생성</li></ul></td></tr><tr><td>session_id</td><td><ul><li>이 값이 NULL이 아니면 해당 세션에서 수행된 SQL 수행에 한정하여 보고서를 생성할 수 있음</li><li>만약 이 파라미터에 NULL이 아닌 값을 명시하고 sql_id 파라미터에 NULL을 명시할 경우, 해당 세션에서 가장 최근에 모니터링된 SQL 수행에 대한 보고서를 생성</li></ul></td></tr><tr><td>session_serial</td><td><ul><li>원하는 특정 세션을 확실히 한정하고 싶을 때 추가적으로 명시할 수 있음</li><li>단, session_id 파라미터가 NULL일 경우 이 파라미터는 무시됨</li></ul></td></tr><tr><td>sql_exec_start</td><td><ul><li>sql_id 파라미터를 명시했을 때만 이 파라미터를 사용할 수 있음</li><li>모니터링된 SQL 수행 중에서 해당 sql_id를 가진 것 중 sql_exec_start 값이 일치하는 모니터링 정보를 찾아 보고서를 생성</li></ul></td></tr><tr><td>sql_exec_id</td><td><ul><li>sql_id 파라미터를 명시했을 때만 이 파라미터를 사용할 수 있음</li><li>모니터링된 SQL 수행 중에서 해당 sql_id를 가진 것 중 sql_exec_id 값이 일치하는 모니터링 정보를 찾아 보고서를 생성</li></ul></td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="192">반환값</th><th>설명</th></tr></thead><tbody><tr><td>CLOB 데이터</td><td>보고서 형식으로 생성된 문자열을 CLOB 형태로 반환</td></tr></tbody></table>

* 예제

다음은 MONITOR 힌트를 기재한 질의를 수행한 뒤 그 수행에 대한 보고서를 생성하는 예제입니다.

```
select /*+ monitor */ count(*) from st11_nostat a, st11_nostat b where a.c1 = b.c1 and a.c1 < 100;

  COUNT(*)
----------
        99

1 row selected.

select sql_id, sql_exec_id, status from v$sql_monitor
 where sql_text like 'select /*+ monitor */ count(*) from st11_nostat%';

SQL_ID        SQL_EXEC_ID STATUS
------------- ----------- -------------------
0dqggbhdbwf5z           1 DONE (ALL ROWS)

1 row selected.

set line 160
set long 1000000
col report for a150
select dbms_sqltune.report_sql_monitor(sql_id => '0dqggbhdbwf5z') as report from dual;

REPORT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
select /*+ monitor */ count(*) from st11_nostat a, st11_nostat b where a.c1 = b.c1 and a.c1 < 100

Global Information
------------------------------
 Status             :  DONE (ALL ROWS)
 Session            :  SYS (204:22091)
 SQL ID             :  0dqggbhdbwf5z
 SQL Execution ID   :  1
 Execution Started  :  2026/08/03 16:37:53
 Program            :  tbsql

Global Stats
======================================
| Elapsed |   Cpu   | Fetch | Buffer |
| Time(s) | Time(s) | Calls |  Gets  |
======================================
|    0.00 |    0.00 |     1 |     35 |
======================================

SQL Plan Monitoring Details (Plan Hash Value=967196727)
===========================================================================================================================================
| Id |       Operation        |    Name     |  Rows   | Cost |   Time    | Start  | Execs |   Rows   |  Mem  | Activity | Activity Detail |
|    |                        |             | (Estim) |      | Active(s) | Active |       | (Actual) | (Max) |   (%)    |   (# samples)   |
===========================================================================================================================================
|    1 | column projection      |             |       1 |   25 |         0 |      0 |       |        1 |       |          |                 |
|    2 |  sort aggr             |             |       1 |   25 |         0 |      0 |       |        1 | 66784 |          |                 |
|    3 |   hash join            |             |      99 |   25 |         0 |      0 |       |       99 | 80856 |          |                 |
|    4 |    table access (full) | ST11_NOSTAT |      98 |   12 |         0 |      0 |       |       99 |       |          |                 |
|    5 |    table access (full) | ST11_NOSTAT |      98 |   12 |         0 |      0 |       |       99 |       |          |                 |
===========================================================================================================================================


1 row selected.
```

### **REPORT\_SQL\_STAT\_ADVISOR**

대상 플랜의 수행 결과를 기반으로, SQL 질의의 성능 향상에 기여할 수 있는 통계 수집을 추천하는 함수입니다. 추천 결과는 텍스트 형태로 확인할 수 있습니다.

리포트는 다음 두 항목으로 구성되며, 각 항목 아래에 대상 테이블 이름이 `스키마.테이블` 형태로 나열됩니다.

<table><thead><tr><th width="330">항목</th><th>설명</th></tr></thead><tbody><tr><td>Tables which need more bucket in stat</td><td>optimizer가 예측한 row 수와 실제 처리한 row 수의 차이가 큰 테이블. 히스토그램 버킷을 늘려 통계를 다시 수집할 대상</td></tr><tr><td>Tables which need to gather stat</td><td>통계를 수집한 적이 없거나, 마지막 수집 이후 변경된 row 수가 전체 row 수의 10%를 넘는 테이블</td></tr></tbody></table>

REPORT\_SQL\_STAT\_ADVISOR 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.REPORT_SQL_STAT_ADVISOR
(
    sql_id       IN VARCHAR,
    child_number IN NUMBER
)
RETURN CLOB;
```

* 파라미터

<table><thead><tr><th width="204">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_id</td><td>통계 수집 추천에 참조할 플랜의 SQL ID</td></tr><tr><td>child_number</td><td>통계 수집 추천에 참조할 플랜의 Child number</td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="207">반환값</th><th>설명</th></tr></thead><tbody><tr><td>CLOB 데이터</td><td>통계 수집 추천 결과가 기재되어 있는 문자열을 CLOB 형태로 반환</td></tr></tbody></table>

* 예제

다음은 REPORT\_SQL\_ACCESS\_ADVISOR 항목의 예제에서 만든 플랜을 대상으로 리포트를 생성하는 예제입니다. 통계를 수집하지 않은 ST11\_NOSTAT 테이블이 추천 목록에 나타납니다.

```
set long 1000000
col report for a100
select dbms_sqltune.report_sql_stat_advisor('56ppmv1uu2tnv', 3008) as report from dual;

REPORT
----------------------------------------------------------------------------------------------------
-------------------------------------
Tables which need more bucket in stat
-------------------------------------
-------------------------------------
Tables which need to gather stat
-------------------------------------
SYS.ST11_NOSTAT

1 row selected.
```

### **SQLTEXT\_TO\_SIGNATURE**

SQL 질의문을 SIGNATURE로 변환하여, 그 값을 반환하는 함수입니다.

SIGNATURE는 DBA\_SQL\_PROFILES에서 SQL 질의문을 식별하는 데 사용됩니다. 같은 질의문에 force\_match를 같은 값으로 주면 항상 같은 SIGNATURE가 나오므로, SQL Profile이 어떤 질의문에 대한 것인지 확인할 때 이 함수를 사용합니다.

force\_match에는 기본값이 선언되어 있지만 **기본값에 의존하지 말고 항상 인자로 전달해야 합니다.** 인자를 생략하거나 NULL을 전달하면 TBR-14002 오류가 발생합니다.

SQLTEXT\_TO\_SIGNATURE 함수의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE
(
    sql_text     IN CLOB,
    force_match  IN BINARY_INTEGER DEFAULT 0
)
RETURN NUMBER;
```

* 파라미터

<table><thead><tr><th width="174">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_text</td><td>SIGNATURE로 변환할 SQL 질의문</td></tr><tr><td>force_match</td><td><ul><li>0이 아닌 값: 질의문의 리터럴을 바인드 변수로 치환한 뒤 SIGNATURE로 변환<br>(CURSOR_SHARING=FORCE에 대응)</li><li>0: 질의문의 리터럴을 치환하지 않은 채 SIGNATURE로 변환<br>(CURSOR_SHARING=EXACT에 대응)</li><li>기본값이 선언되어 있지만 인자를 생략하거나 NULL을 전달하면 TBR-14002 오류가 발생함</li></ul></td></tr></tbody></table>

* 반환값

<table><thead><tr><th width="190">반환값</th><th>설명</th></tr></thead><tbody><tr><td>NUMBER 데이터</td><td>SQL 질의문의 signature를 반환</td></tr></tbody></table>

* 예제

다음은 리터럴만 다른 두 질의문의 SIGNATURE를 force\_match 값에 따라 비교하는 예제입니다. force\_match가 0이면 서로 다른 값이 나오고, 0이 아니면 같은 값이 나옵니다.

```
set serveroutput on
DECLARE
    ret1 NUMBER;
    ret2 NUMBER;
BEGIN
    ret1 := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE('select c2 from st11_t where c1 = 1', 0);
    ret2 := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE('select c2 from st11_t where c1 = 2', 0);
    DBMS_OUTPUT.PUT_LINE(ret1);
    DBMS_OUTPUT.PUT_LINE(ret2);
    ret1 := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE('select c2 from st11_t where c1 = 1', 1);
    ret2 := DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE('select c2 from st11_t where c1 = 2', 1);
    DBMS_OUTPUT.PUT_LINE(ret1);
    DBMS_OUTPUT.PUT_LINE(ret2);
END;
/
4858013100579603831
4840174378499101675
15139934590709800885
15139934590709800885

PSM completed.
```

다음은 IMPORT\_SQL\_PROFILE 항목의 예제로 생성한 SQL Profile의 SIGNATURE가 대상 질의문의 SIGNATURE와 같은지 확인하는 예제입니다.

```
col sig for a22
select name, to_char(signature, 'FM99999999999999999999') as sig
  from dba_sql_profiles where name = 'ST11_PROF1';

NAME         SIG
------------ ----------------------
ST11_PROF1   13090854738629211987

1 row selected.

set serveroutput on
BEGIN
    DBMS_OUTPUT.PUT_LINE(
        DBMS_SQLTUNE.SQLTEXT_TO_SIGNATURE('select /*+ full(t) */ * from st11_t t where c1 = 1', 0));
END;
/
13090854738629211987

PSM completed.
```

### **SQL\_TUNE\_BY\_ADJUST\_SELECT**

대상 플랜의 수행 결과를 기반으로, 인덱스 컬럼에 대한 조건문의 selectivity를 보정하는 프러시저입니다.

조건문의 selectivity 보정을 통해 더욱 성능이 좋은 플랜을 유도할 수 있게 됩니다. 프러시저를 호출하면 대상 SQL을 보정된 selectivity로 다시 최적화한 플랜을 Physical Plan Cache에 새 Child로 등록하고, 기존 Child는 더 이상 사용하지 않도록 표시합니다.

대상 플랜은 Physical Plan Cache에 있어야 합니다. sql\_id의 길이가 13이 아니거나, sql\_id 또는 pp\_id가 NULL이거나, 지정한 플랜이 Physical Plan Cache에 없으면 TBR-14002 오류가 발생합니다.

SQL\_TUNE\_BY\_ADJUST\_SELECT 프러시저의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.SQL_TUNE_BY_ADJUST_SELECT
(
    sql_id         IN VARCHAR,
    pp_id          IN NUMBER,
    create_outline IN VARCHAR
)
```

* 파라미터

<table><thead><tr><th width="202">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>sql_id</td><td>selectivity를 보정할 플랜의 SQL ID. 길이가 13이어야 함</td></tr><tr><td>pp_id</td><td>selectivity를 보정할 플랜의 Child number</td></tr><tr><td>create_outline</td><td>selectivity 보정 결과를 outline 힌트로 생성할지 여부. Y 또는 y를 주면 생성하고 그 외의 값은 생성하지 않음</td></tr></tbody></table>

* 예제

다음은 REPORT\_SQL\_ACCESS\_ADVISOR 항목의 예제로 만든 ST11\_NOSTAT 테이블에 대해 새 질의를 하드파싱한 뒤 selectivity를 보정하는 예제입니다. 보정된 플랜이 새 Child로 등록됩니다. SQL ID와 Child number는 인스턴스와 수행 시점에 따라 달라집니다.

```
set autot traceonly exp
select count(*) from st11_nostat where c2 = 'v20';

SQL ID: d410gux3d4jqn
Child number: 3039
Plan hash value: 3390603163

Execution Plan
----------------------------------------------------------------------------------------------------
   1  COLUMN PROJECTION (Cost:12, %%CPU:0, Rows:1)
   2    SORT AGGR (Cost:12, %%CPU:0, Rows:1)
   3      TABLE ACCESS (FULL): ST11_NOSTAT (Cost:12, %%CPU:0, Rows:1)


Predicate Information
----------------------------------------------------------------------------------------------------
   3 - filter: ("ST11_NOSTAT"."C2" = 'v20') (0.000)


Note
----------------------------------------------------------------------------------------------------
   3 - dynamic sampling used for this table (13 blocks)

set autot off
select distinct child_number, plan_hash_value from v$sql_plan
 where sql_id = 'd410gux3d4jqn' order by 1;

CHILD_NUMBER PLAN_HASH_VALUE
------------ ---------------
        3039      3390603163

1 row selected.

BEGIN
    DBMS_SQLTUNE.SQL_TUNE_BY_ADJUST_SELECT('d410gux3d4jqn', 3039, 'Y');
END;
/

PSM completed.

select distinct child_number, plan_hash_value from v$sql_plan
 where sql_id = 'd410gux3d4jqn' order by 1;

CHILD_NUMBER PLAN_HASH_VALUE
------------ ---------------
        3039      3390603163
        3042      3390603163

2 rows selected.
```

### **VERIFY\_SQL\_PROFILE**

생성되어 있는 SQL Profile이 유효한지 검사하는 프러시저입니다. VERIFY\_SQL\_PROFILE 프러시저에서 SQL Profile의 유효성을 검사하는 과정은 다음과 같습니다.

1. SQL Profile의 대상 SQL 질의문을 하드파싱합니다.
2. 하드파싱을 통해 얻은 플랜으로부터 outline 힌트를 추출한 뒤, SQL Profile의 outline 힌트 목록과 비교합니다.
3. 플랜의 outline 힌트와 SQL Profile의 outline 힌트 목록이 일치하는 경우, 해당 SQL Profile이 유효한 것으로 간주합니다.

플랜의 outline 힌트와 SQL Profile의 outline 힌트 목록이 일치하지 않거나, 대상 SQL 질의문을 하드파싱할 수 없는 경우, 해당 SQL Profile이 유효하지 않은 것으로 간주합니다.

프러시저 수행이 종료되면 다음의 결과가 출력됩니다. SERVEROUTPUT이 켜져 있는 상태여야 합니다.

* SQL Profile의 유효성(verify success 또는 verify failure)
* 대상 SQL 질의문을 하드파싱한 사용자 정보 (대상 SQL의 하드파싱에는 성공하였으나, SQL Profile이 유효하지 않은 경우)
* 대상 SQL 질의문 정보 (SQL Profile이 유효하지 않은 경우)
* SQL Profile과 플랜 간 outline 힌트 비교 (대상 SQL의 하드파싱에는 성공하였으나, SQL Profile이 유효하지 않은 경우)
* 대상 SQL 질의문의 Logical Plan 정보 (대상 SQL의 하드파싱에는 성공하였으나, SQL Profile이 유효하지 않은 경우)

outline 힌트 비교 결과에서 각 줄 앞에 붙는 기호의 뜻은 다음과 같습니다.

<table><thead><tr><th width="150">기호</th><th>설명</th></tr></thead><tbody><tr><td>없음</td><td>SQL Profile과 실제 플랜에 모두 있는 힌트</td></tr><tr><td>빼기 기호</td><td>SQL Profile에만 있고 실제 플랜에는 없는 힌트. Expected Outline Hints 항목에만 나타남</td></tr><tr><td>더하기 기호</td><td>실제 플랜에만 있고 SQL Profile에는 없는 힌트. Actual Outline Hints 항목에만 나타남</td></tr></tbody></table>

name에 존재하지 않는 SQL Profile 이름을 주면 TBR-15104 오류가 발생합니다.

VERIFY\_SQL\_PROFILE 프러시저의 세부 내용은 다음과 같습니다.

* 프로토타입

```
DBMS_SQLTUNE.VERIFY_SQL_PROFILE
(
    name        IN VARCHAR2 DEFAULT NULL,
    schema_name IN VARCHAR2 DEFAULT NULL
)
```

* 파라미터

<table><thead><tr><th width="158">파라미터</th><th>설명</th></tr></thead><tbody><tr><td>name</td><td><ul><li>검사하고자 하는 SQL Profile의 이름</li><li>NULL일 경우 생성되어 있는 모든 SQL Profile을 검사</li></ul></td></tr><tr><td>schema_name</td><td><ul><li>SQL Profile의 대상 SQL 질의문을 하드파싱할 스키마의 이름. 내부에서 대문자로 변환하므로 소문자로 전달해도 됨</li><li>NULL일 경우, 데이터베이스의 모든 사용자를 차례로 시도하여 대상 질의문을 하드파싱할 수 있는 첫 번째 스키마로 검사</li></ul></td></tr></tbody></table>

* 예제

다음은 IMPORT\_SQL\_PROFILE 항목의 예제로 생성한 SQL Profile이 유효한 경우의 예제입니다.

```
set serveroutput on
BEGIN
    DBMS_SQLTUNE.VERIFY_SQL_PROFILE('ST11_PROF1', USER);
END;
/
----------------------------------------
SQL Profile "ST11_PROF1" verify success
----------------------------------------

PSM completed.
```

다음은 SQL Profile이 참조하는 인덱스를 삭제해 SQL Profile이 유효하지 않게 된 경우의 예제입니다. Expected Outline Hints와 Actual Outline Hints의 OPT\_PARAM 힌트는 양쪽에 동일하게 나열되므로 모두 생략했습니다.

```
drop index st11_idx;

Index 'ST11_IDX' dropped.

set serveroutput on
BEGIN
    DBMS_SQLTUNE.VERIFY_SQL_PROFILE('ST11_PROF1', USER);
END;
/
----------------------------------------
SQL Profile "ST11_PROF1" verify failure
SQL Profile cannot be applied as expected
----------------------------------------

---------- User Information ----------
SYS

---------- SQL Information ----------
select /*+ full(t) */ * from st11_t t where c1 = 1

---------- Expected Outline Hints ----------
  ...
- ROWID@LPN$3(ST11_T)
- INDEX_RS@LPN$3(ST11_IDX)

---------- Actual Outline Hints ----------
  ...
+ FULL@LPN$3

---------- Logical Plan Information ----------
QB  LP_IDX  DEPTH  P_IDX  LPN_TYPE      DETAIL
 0       1      0         LPN_PROJ      --
 0       2      1      1  LPN_SEL       - filter -
("T"."C1" = 1)
 0       3      2      2  LPN_TBL       --

PSM completed.
```

다음은 대상 SQL 질의문을 어느 스키마에서도 하드파싱할 수 없는 경우의 예제입니다. 이때는 outline 힌트 비교와 Logical Plan 정보가 출력되지 않습니다.

```
BEGIN
    DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
        SQL_TEXT => 'select * from st11_missing'
      , PROFILE  => SQLPROF_ATTR('FULL@LPN$3')
      , NAME     => 'ST11_PROF9'
    );
END;
/

PSM completed.

set serveroutput on
BEGIN
    DBMS_SQLTUNE.VERIFY_SQL_PROFILE('ST11_PROF9');
END;
/
----------------------------------------
SQL Profile "ST11_PROF9" verify failure
The target SQL cannot be hardparsed!
----------------------------------------

---------- SQL Information ----------
select * from st11_missing


PSM completed.

BEGIN
    DBMS_SQLTUNE.DROP_SQL_PROFILE('ST11_PROF9', TRUE);
END;
/

PSM completed.
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.tibero.com/tibero-manuals/7.2.6.manuals/tbpsm-reference-guide/dbms_sqltune.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
