已知SQL更好执行计划的调优

1.创建测试表及数据

CREATE TABLE T01(ID NUMBER,NAME VARCHAR2(20));
CREATE INDEX IDX_T01_ID ON T01(ID);
INSERT INTO T01 VALUES (1,'MONKEY');
INSERT INTO T01 VALUES (2,'MONKEY');
INSERT INTO T01 VALUES (3,'MONKEY');
INSERT INTO T01 VALUES (4,'MONKEY');
INSERT INTO T01 VALUES (5,'MONKEY');
COMMIT;

2.根据ID查询测试表并查看执行计划

SELECT * FROM MONKEY.T01 WHERE ID = 2;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'Advanced'))

3.自己加hint,生成更好的执行计划

SELECT /*+FULL(A)*/* FROM MONKEY.T01 A WHERE ID = 2;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'Advanced'))

4.提取对应的执行计划

/* Formatted on 2021-05-20 下午 02:51:45 (QP5 v5.163.1008.3004) */
SELECT    'q''['
       || REPLACE (EXTRACTVALUE (VALUE (d), '/hint'), '', '''')
       || ']'','
          AS outline_hints
  FROM XMLTABLE (
          '/*/outline_data/hint'
          PASSING (SELECT xmltype (other_xml) AS xmlval
                     FROM v$sql_plan
                    WHERE     sql_id = '4ym6mvwvuduha' ------sql_Id is which you get profile
                          AND child_number = 0
                          AND other_xml IS NOT NULL)) d;

在实践过程中,可能会出现隔得太久,执行计划已经被踢出sharepool的情况,此时就需要从DBA_HIST_SQL_PLAN抓取执行计划

SELECT    'q''['
       || REPLACE (EXTRACTVALUE (VALUE (d), '/hint'), '', '''')
       || ']'','
          AS outline_hints
  FROM XMLTABLE (
          '/*/outline_data/hint'
          PASSING (SELECT xmltype (other_xml) AS xmlval
                     FROM DBA_HIST_SQL_PLAN
                    WHERE     sql_id = '4x90hmraqdjf9' ------sql_Id is which you get profile
                          AND PLAN_HASH_VALUE = 3651047320     --这里需要用PLAN_HASH_VALUE
                          AND other_xml IS NOT NULL)) d;

5.用生成的执行计划替换原有的计划

/* Formatted on 2021-05-20 下午 02:56:44 (QP5 v5.163.1008.3004) */
DECLARE
   V_SQLID_1            V$SQL.SQL_ID%TYPE := '2a7npa11xs7st'; -------------sql_Id is which you want to change
   V_CHILDNO_1          V$SQL.CHILD_NUMBER%TYPE := 0;
   v_sqlprofile         SYS.sqlprof_attr;
   v_new_profile_name   VARCHAR2 (255);
   v_sql_text           V$SQL.SQL_FULLTEXT%TYPE;
BEGIN
   SELECT sql_fulltext
     INTO v_sql_text
     FROM v$sql
    WHERE sql_id = V_SQLID_1 AND child_number = V_CHILDNO_1;

   SELECT 'coe_' || DBMS_RANDOM.STRING ('A', 24)
     INTO v_new_profile_name
     FROM DUAL;

   DBMS_SQLTUNE.import_sql_profile (
      sql_text      => v_sql_text,
      name          => v_new_profile_name,
      profile       => sqlprof_attr (q'[IGNORE_OPTIM_EMBEDDED_HINTS]',
                                     q'[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]',
                                     q'[DB_VERSION('11.2.0.4')]',
                                     q'[ALL_ROWS]',
                                     q'[OUTLINE_LEAF(@"SEL$1")]',
                                     q'[FULL(@"SEL$1" "A"@"SEL$1")]'),
      REPLACE       => TRUE,
      force_match   => TRUE);
END;
/

6.查看是否替换成功

SELECT A.EXECUTIONS,A.SQL_PROFILE FROM V$SQLAREA A WHERE A.SQL_ID='2a7npa11xs7st';

再次执行sql后,SQL_PROFILE栏位会有数据。

/*+
PUSH_PRED(X 2)
OUTLINE_LEAF()
*/

7.其他

删除sql profile

exec dbms_sqltune.drop_sql_profile('SYS_SQLPROF_014b39f084c88000'); 
posted @ 2021-05-20 15:08  monkey6  阅读(119)  评论(0编辑  收藏  举报