Oracle/Tuning2019. 1. 9. 08:38

긴급 튜닝에 활용할 수 있는 SQL Profile 기능을 살펴보자.


테스트를 위해 아래와 같이 쿼리를 수행하고, 각각의 SQL Id를 확인하자.

-- 1-1 : 7qyp0y3qquxqy
SELECT /*+ ORDERED USE_NL(B) */
       *
  FROM dept a, emp b
 WHERE b.deptno = a.deptno;

-----------------------------------------------
| Id  | Operation                    | Name   |
-----------------------------------------------
|   0 | SELECT STATEMENT             |        |
|   1 |  NESTED LOOPS                |        |
|   2 |   NESTED LOOPS               |        |
|   3 |    TABLE ACCESS FULL         | DEPT   |
|*  4 |    INDEX RANGE SCAN          | EMP_X1 |
|   5 |   TABLE ACCESS BY INDEX ROWID| EMP    |
-----------------------------------------------

-- 1-2 : 86y83gmzgmdj7
SELECT /*+ ORDERED USE_HASH(B) */
       *
  FROM dept a, emp b
 WHERE b.deptno = a.deptno;

-----------------------------------
| Id  | Operation          | Name |
-----------------------------------
|   0 | SELECT STATEMENT   |      |
|*  1 |  HASH JOIN         |      |
|   2 |   TABLE ACCESS FULL| DEPT |
|   3 |   TABLE ACCESS FULL| EMP  |
-----------------------------------

아래는 SQL Profile을 적용하는 PL/SQL 블록이다. NL 조인으로 수행되던 쿼리가 HASH 조인으로 수행되어, 원래 실행 계획이었던 NL 조인으로 복구하는 시나리오다. force_match 옵션은 해당 SQL에 대해 cursor_sharing을 force로 설정한다.

-- 2
DECLARE
    l_profile    SYS.SQLPROF_ATTR;
BEGIN
    FOR c1 IN (SELECT   a.sql_id
                      , a.sql_fulltext
                      , b.other_xml
                   FROM v$sql a
                      , v$sql_plan b
                  WHERE 1 = 1
                    AND a.sql_id = '86y83gmzgmdj7' -- AS-IS
                    AND a.child_number = 0
                    AND b.sql_id = '7qyp0y3qquxqy' -- TO-BE
                    AND b.child_number = 0
                    AND b.other_xml IS NOT NULL)
    LOOP
        SELECT a.hint
          BULK COLLECT
          INTO l_profile
          FROM XMLTABLE ('other_xml/outline_data/hint'
                         PASSING XMLPARSE (CONTENT c1.other_xml)
                         COLUMNS hint VARCHAR2 (4000) PATH 'text()') a;

        DBMS_SQLTUNE.IMPORT_SQL_PROFILE (
            sql_text    => c1.sql_fulltext
          , profile     => l_profile
          , name        => 'profile_' || c1.sql_id
          , replace     => TRUE
          , force_match => TRUE);
    END LOOP;
END;
/

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL Profile 적용 후 실행 계획이 NL 조인으로 변경된 것을 확인할 수 있다. outline에 포함된 IGNORE_OPTIM_EMBEDDED_HINTS 힌트에 의해 SQL에 기술된 힌트가 무시된다. 적용된 SQL Profile을 Note에서 확인할 수 있다.

-- 3
EXPLAIN PLAN FOR
SELECT /*+ ORDERED USE_HASH(B) */ * FROM dept a, emp b WHERE b.deptno = a.deptno;

-----------------------------------------------
| Id  | Operation                    | Name   |
-----------------------------------------------
|   0 | SELECT STATEMENT             |        |
|   1 |  NESTED LOOPS                |        |
|   2 |   NESTED LOOPS               |        |
|   3 |    TABLE ACCESS FULL         | DEPT   |
|*  4 |    INDEX RANGE SCAN          | EMP_X1 |
|   5 |   TABLE ACCESS BY INDEX ROWID| EMP    |
-----------------------------------------------

Note
-----
   - SQL profile "profile_86y83gmzgmdj7" used for this STATEMENT

dba_sql_profiles 뷰와 sys.dbmshsxp_sql_profile_attr 뷰에서 SQL Profile 정보를 확인할 수 있다.

-- 4-1
SELECT name, status, force_matching FROM dba_sql_profiles;

NAME                  STATUS  FORCE_MATCHING
--------------------- ------- --------------
profile_86y83gmzgmdj7 ENABLED YES

1개의 행이 선택되었습니다.

-- 4-2
SELECT * FROM sys.dbmshsxp_sql_profile_attr;

PROFILE_NAME          COMP_DATA
--------------------- -----------------
profile_86y83gmzgmdj7 <outline_data>...

1개의 행이 선택되었습니다.

DBMS_SQLTUNE.DROP_SQL_PROFILE 프로시저로 SQL Profile을 삭제할 수 있다.

-- 5
EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE ('profile_86y83gmzgmdj7');

PL/SQL 처리가 정상적으로 완료되었습니다

SQL Profile이 삭제되어 원래의 실행 계획이 적용된 것을 확인할 수 있다.

-- 6
EXPLAIN PLAN FOR
SELECT /*+ ORDERED USE_HASH(B) */ * FROM dept a, emp b WHERE b.deptno = a.deptno;

-----------------------------------
| Id  | Operation          | Name |
-----------------------------------
|   0 | SELECT STATEMENT   |      |
|*  1 |  HASH JOIN         |      |
|   2 |   TABLE ACCESS FULL| DEPT |
|   3 |   TABLE ACCESS FULL| EMP  |
-----------------------------------

SQL Profile은 임시처방이다. 비정상적인 실행 계획에 대한 원인를 찾아 해결하고, SQL Profile을 삭제한 후 실행 계획이 정상적으로 수립되는지 확인해야 한다.


'Oracle > Tuning' 카테고리의 다른 글

사용자 정의 함수의 수행 횟수  (0) 2019.01.30
SQL Patch  (0) 2019.01.09
다중 행 다중 열 스칼라 서브 쿼리의 부분 범위 처리  (0) 2019.01.09
파티션 인덱스와 소트  (0) 2019.01.08
조인이 포함된 Top-N 쿼리  (0) 2019.01.07
Posted by 정희락_