【Oracle优化】通过SQL_PROFILE固化执行计划

在生产环境中,随着数据量的变化、查询条件的不同,有时执行计划发生了突变而导致SQL性能急剧下降。此时如果调整代码,或者修改业务逻辑,一方面时间上可能来不及,另一方面可能成本较高,那么有没有办法,可以在不调整代码或业务逻辑的情况下,让SQL语句使用计划突变之前的执行计划呢?本篇将介绍通过SQL_PROFILE来固化执行计划的三种方法。

一 绑定已存在的执行计划

DECLARE

v_ar_profile_hints sys.sqlprof_attr;

v_clsql_text CLOB;

BEGIN

SELECT extractvalue(VALUE(d), '/hint') AS outline_hints

BULK COLLECT

INTO v_ar_profile_hints

FROM xmltable('/*/outline_data/hint' passing

(SELECT xmltype(other_xml) AS xmlval

FROM dba_hist_sql_plan

WHERE sql_id = 'fzbu6pashquvv'

AND plan_hash_value = '116091679'

AND other_xml IS NOT NULL)) d;



SELECT sql_text

INTO v_clsql_text

FROM dba_hist_sqltext

WHERE sql_id = 'fzbu6pashquvv';



dbms_output.put_line(v_clsql_text);



dbms_sqltune.import_sql_profile(sql_text => v_clsql_text,

profile => v_ar_profile_hints,

NAME => 'test_sql',

force_match => TRUE,

REPLACE => TRUE);

END;

select * FROM dba_sql_profiles;

select * FROM v$sql;

二 手动绑定Outline信息

1 下面的SQL执行全表扫描;

2 强制使用索引执行该语句,然后通过v_sqlarea找到其对应的SQL_ID;

select /*+ index(t IDX_TEST_OWNER)*/ sum(t.object_id) FROM t_test t

where t.owner='PUBLIC';

3 查看器执行计划

SELECT *

FROM TABLE(dbms_xplan.display_cursor(sql_id => '8ctw5gjz6z75g',

cursor_child_no => NULL,

format => 'outline'));

4 绑定Outline

DECLARE

v_ar_profile_hints sys.sqlprof_attr;

v_clsql_text CLOB;

BEGIN

v_ar_profile_hints := sys.sqlprof_attr('OUTLINE_LEAF(@"SEL$1")',

'INDEX_RS_ASC(@"SEL$1" "T"@"SEL$1" ("T_TEST"."OWNER"))');

SELECT t.sql_text

INTO v_clsql_text

FROM v$sqlarea t

WHERE t.sql_id = 'dtzdyatm69v0f';

dbms_output.put_line(v_clsql_text);

dbms_sqltune.import_sql_profile(sql_text => v_clsql_text,

profile => v_ar_profile_hints,

NAME => 'test_sql',

force_match => TRUE,

REPLACE => TRUE);

END;

注:需要DBA权限。

5 查看绑定后的执行计划

SELECT t.name, t.sql_text, t.status

FROM dba_sql_profiles t

WHERE t.name = 'test_sql';

SELECT t.sql_text, t.sql_id, t.sql_profile

FROM v$sql t

WHERE t.sql_id = 'dtzdyatm69v0f';

三 借助自动优化任务

1 查看优化建议

DECLARE

v_tuning_task VARCHAR2(100);

v_sql_id v$session.prev_sql_id%TYPE := 'dtzdyatm69v0f';

v_task VARCHAR2(30);



v_report CLOB;

BEGIN

v_task := dbms_sqltune.create_tuning_task(sql_id => v_sql_id);



dbms_output.put_line('Task is ' || v_task);

v_tuning_task := v_task;



dbms_sqltune.execute_tuning_task(v_task);



dbms_output.put_line('Tuning task is ' || v_tuning_task);



SELECT dbms_sqltune.report_tuning_task(task_name => v_task)

INTO v_report

FROM dual;

dbms_output.put_line('Report is ' || v_report);

END;

2 接受优化建议

BEGIN

dbms_sqltune.accept_sql_profile(task_name => v_tuning_task,

REPLACE => TRUE,

force_match => TRUE);

END;
原文地址:https://www.cnblogs.com/alen-liu-sz/p/12975608.html