SQL访问顾问SAA(SQL Access Advisor)针对多条sql优化实践之一:从SQL Cache中加载
看过这个的同行,请点赞、关注本博客
create table testobj as select * from dba_objects;
exec dbms_stats.gather_table_stats(ownname => 'TEST',tabname => 'TESTOBJ',cascade => true);
一、加载sql进入sqlcache
二、 saa从sqlcache加载分析,开始执行任务
DECLARE
l_taskname VARCHAR2(30) := 'test_sql_access_task';
l_task_desc VARCHAR2(128) := 'Test SQL Access Task';
l_wkld_name VARCHAR2(30) := 'test_work_load';
l_saved_rows NUMBER := 0;
l_failed_rows NUMBER := 0;
l_num_found NUMBER;
BEGIN
-- Create an SQLAccess Advisor task.
DBMS_ADVISOR.create_task(
advisor_name => DBMS_ADVISOR.sqlaccess_advisor,
task_name => l_taskname,
task_desc => l_task_desc);
-- Reset the task.
DBMS_ADVISOR.reset_task(task_name => l_taskname);
-- Create a workload.
SELECT COUNT(*)
INTO l_num_found
FROM user_advisor_sqlw_sum
WHERE workload_name = l_wkld_name;
IF l_num_found = 0 THEN
DBMS_ADVISOR.create_sqlwkld(workload_name => l_wkld_name);
END IF;
-- Link the workload to the task.
SELECT count(*)
INTO l_num_found
FROM user_advisor_sqla_wk_map
WHERE task_name = l_taskname
AND workload_name = l_wkld_name;
IF l_num_found = 0 THEN
DBMS_ADVISOR.add_sqlwkld_ref(
task_name => l_taskname,
workload_name => l_wkld_name);
END IF;
-- Set workload parameters.
DBMS_ADVISOR.set_sqlwkld_parameter(l_wkld_name,
'ACTION_LIST',
DBMS_ADVISOR.ADVISOR_UNUSED);
DBMS_ADVISOR.set_sqlwkld_parameter(l_wkld_name,
'MODULE_LIST',
DBMS_ADVISOR.ADVISOR_UNUSED);
DBMS_ADVISOR.set_sqlwkld_parameter(l_wkld_name,
'SQL_LIMIT',
DBMS_ADVISOR.ADVISOR_UNLIMITED);
DBMS_ADVISOR.set_sqlwkld_parameter(l_wkld_name,
'ORDER_LIST',
'PRIORITY,OPTIMIZER_COST');
DBMS_ADVISOR.set_sqlwkld_parameter(l_wkld_name,
'USERNAME_LIST',
DBMS_ADVISOR.ADVISOR_UNUSED);
DBMS_ADVISOR.set_sqlwkld_parameter(l_wkld_name,
'VALID_TABLE_LIST',
DBMS_ADVISOR.ADVISOR_UNUSED);
--
DBMS_ADVISOR.import_sqlwkld_sqlcache(l_wkld_name,
'REPLACE',
2,
l_saved_rows,
l_failed_rows);
-- Set task parameters.
DBMS_ADVISOR.set_task_parameter(l_taskname,
'_MARK_IMPLEMENTATION',
'FALSE');
DBMS_ADVISOR.set_task_parameter(l_taskname,
'EXECUTION_TYPE',
'INDEX_ONLY');
DBMS_ADVISOR.set_task_parameter(l_taskname, 'MODE', 'COMPREHENSIVE');
DBMS_ADVISOR.set_task_parameter(l_taskname,
'STORAGE_CHANGE',
DBMS_ADVISOR.ADVISOR_UNLIMITED);
DBMS_ADVISOR.set_task_parameter(l_taskname, 'DML_VOLATILITY', 'TRUE');
DBMS_ADVISOR.set_task_parameter(l_taskname,
'ORDER_LIST',
'PRIORITY,OPTIMIZER_COST');
DBMS_ADVISOR.set_task_parameter(l_taskname, 'WORKLOAD_SCOPE', 'PARTIAL');
DBMS_ADVISOR.set_task_parameter(l_taskname,
'DEF_INDEX_TABLESPACE',
DBMS_ADVISOR.ADVISOR_UNUSED);
DBMS_ADVISOR.set_task_parameter(l_taskname,
'DEF_INDEX_OWNER',
DBMS_ADVISOR.ADVISOR_UNUSED);
DBMS_ADVISOR.set_task_parameter(l_taskname,
'DEF_MVIEW_TABLESPACE',
DBMS_ADVISOR.ADVISOR_UNUSED);
DBMS_ADVISOR.set_task_parameter(l_taskname,
'DEF_MVIEW_OWNER',
DBMS_ADVISOR.ADVISOR_UNUSED);
-- Execute the task.
DBMS_ADVISOR.execute_task(task_name => l_taskname);
END;
/
DBMS_ADVISOR.import_sqlwkld_sqlcache(l_wkld_name,
'REPLACE',
2,
l_saved_rows,
l_failed_rows);这个属于sqlcache加载;
参考:
加载SQL Cache工作量
可以使用dbms_advisor.import_sqlwkld_sqlcache过程来获得SQL Cache工作量。在调用这个过程的 时候,SQL Cache中的当前内容将会被分析并且加载到工作量中。 dbms_advisor.import_sqlwkld_sqlcache过程从SQL Cache中加载SQL工作量,语法如下:
dbms_advisor.import_sqlwkld_sqlcache (
workload_name in varchar2,
import_mode in varchar2,
priority in number := 2,
saved_rows out number,
failed_rows out number);
下面的例子从SQL Cache中加载之前创建的工作量MYWORKLOAD。加载工作量语句的优先级为2:
variable saved_stmts number;
variable failed_stmts number;
execute dbms_advisor.import_sqlwkld_sqlcache('MYWORKLOAD', 'APPEND', 2, :saved_stmts, :failed_stmts);
SQL Access Advisor可以从SQL Cache中检索工作量信息。如果收集的数据是从实例参数 cursor_sharing设置为similar或force的服务器中所检索到的,那么使用文本值的查询将会被转换为 包含系统生成变量的语句。如果使用SQL Access Advisor来建议物化视图,那么服务器应该将参数 cursor_sharing设置为exact,因此有where子句的物化视图会被建议。
三、查看分析建议
SQL> SET LONG 100000
SQL> SET PAGESIZE 50000
SQL> SELECT DBMS_ADVISOR.get_task_script('test_sql_access_task') AS script FROM dual;
SCRIPT
--------------------------------------------------------------------------------
Rem SQL 访问指导: 版本 18.0.0.0.0 - 正式版
Rem
Rem 用户名: TEST
Rem 任务: test_sql_access_task
Rem 执行日期:
Rem
CREATE INDEX "TEST"."TESTOBJ_IDX$$_002D0000"
ON "TEST"."TESTOBJ"
("OBJECT_NAME")
COMPUTE STATISTICS;
CREATE INDEX "TEST"."TESTOBJ_IDX$$_002D0001"
ON "TEST"."TESTOBJ"
("OBJECT_ID")
COMPUTE STATISTICS;
四、查看分析提高情况,提高有改善的两个sqlid就是对应的两个create index之后的sql的
SQL> select a.owner,
2 a.task_id,
3 a.task_name,
4 execution_start,
5 a.status_message,
6 b.command from dba_advisor_log a,
7 dba_advisor_actions b where a.task_id = b.task_id and b.task_name = 'test_sql_access_task';
OWNER TASK_ID TASK_NAME EXECUTION_START STATUS_MESSAGE COMMAND
-------------------------------------------------------------------------------- ---------- -------------------------------------------------------------------------------- --------------- -------------------------------------------------------------------------------- ----------------------------------------------------------------
TEST 45 test_sql_access_task 2018/12/13 16:2 访问指导执行完毕 CREATE INDEX
TEST 45 test_sql_access_task 2018/12/13 16:2 访问指导执行完毕 CREATE INDEX
SQL> SELECT sql_id,
2 precost 优化前cost,
3 postcost 优化后cost,
4 (precost / postcost) cost提升倍数,decode(PRIORITY, 1, '高', 2, '中', 3, '低') 重要性
5 FROM dba_advisor_sqla_wk_stmts
6 WHERE
7 task_name='test_sql_access_task';
SQL_ID 优化前COST 优化后COST COST提升倍数 重要性
------------- ---------- ---------- ------------ ------
3qpb0nj36qxvs 45 45 1 中
bsxmbc4z76ry5 391 391 1 中
31j9fzrraqs2m 389 5 77.8 中
1hv9axpnydt07 12 12 1 中
16km2m1f85nk5 45 45 1 中
agffxdv97kvp7 30 30 1 中
2dxcvzt5phbz2 297 297 1 中
2vn85au9ffaun 389 3 129.66666666 中
320mymhry8p1v 48 48 1 中
2pkf91r1mcd6w 21 21 1 中
at2h5x34yj2c4 24 24 1 中
cs5wf87un48p9 99 99 1 中
12 rows selected
这个太牛叉了,感觉可以傻瓜式的应用于生产中,随时检查,傻瓜式优化
五、别忘了删除
exec dbms_advisor.delete_task('test_sql_access_task');