背景:
接同事问题协助,在用户现场做SPA的性能比对,在源端通过AWR历史信息收集sqlset时,dbms_sqltune.select_workload_repository执行一直未完成,取消尝试多次依然没有解决。
问题:
SPA在源端通过AWR历史信息收集sqlset时,select_workload_repository执行一直未完成
DECLARE
cur sys_refcursor;
BEGIN
open cur for
select value(p) from table(dbms_sqltune.select_workload_repository(begin_snap => 39369, end_snap => 40838)) p;
dbms_sqltune.load_sqlset('sql_test', cur);
close cur;
END;
/
问题分析:
查看执行收集sqlset的会话,会话执行语句卡在SQL_ID:aamdkbbaajjgz,当前等待事件为控制文件读control file sequential read
使用sqlhc收集了SQL_ID:aamdkbbaajjgz的相关信息,语句主要是通过输入的AWR快照ID收集历史的sql执行性能信息
SELECT /*+ first_rows(1) */ sql_id, force_matching_signature, sql_text,...., cast (NULL as SQL_BINDS) bind_list
FROM ((SELECT
t1.sql_id, xxxxx,
FROM (SELECT sql_id, xxx
FROM (SELECT s.snap_id, xxx
FROM DBA_HIST_SQLSTAT s, DBA_HIST_SQLTEXT t,
DBA_HIST_OPTIMIZER_ENV e, V$DATABASE d
WHERE s.sql_id = t.sql_id and s.dbid = t.dbid and
s.dbid = e.dbid(+) and
s.optimizer_env_hash_value = e.optimizer_env_hash_value(+) and
s.dbid = d.dbid and
/* only capture sqls with the full set of execution stats */
bitand(nvl(s.flag, 0), 1) = 0)) T1,--------------------------------------T1
(SELECT sql_id, xxx,
MAX(INSTANCE_NUMBER) KEEP (DENSE_RANK LAST
ORDER BY ELAPSED_TIME) AS instance_number
FROM (SELECT s.snap_id, xxx
FROM DBA_HIST_SQLSTAT s, DBA_HIST_SQLTEXT t,
DBA_HIST_OPTIMIZER_ENV e, V$DATABASE d
WHERE s.sql_id = t.sql_id and s.dbid = t.dbid and
s.dbid = e.dbid(+) and
s.optimizer_env_hash_value = e.optimizer_env_hash_value(+) and
s.dbid = d.dbid and
/* only capture sqls with the full set of execution stats */
bitand(nvl(s.flag, 0), 1) = 0) WHERE snap_id > :begin_snap and
snap_id <= :end_snap AND command_type in (1, 2, 3, 6, 7, 189) GROUP BY sql_id, plan_hash_value) T2 ----------------T2
WHERE T1.sql_id = T2.sql_id AND
T1.plan_hash_value = T2.plan_hash_value AND
T1.snap_id = T2.snap_id AND
T1.instance_number = T2.instance_number)) S
查看当前语句涉及的表信息,里面涉及大表主要为WRH$_SQLSTAT
查看语句的执行计划,结合语句的主要等待control file sequential read在X$KCCDI2表,我们可以初步推断,语句的执行计划主要问题在于视图的谓词推入,由于执行计划发生了视图的谓词推入,使用了nest loop嵌套,并且外层有大表WRH$_SQLSTAT,导致内层需要多次扫描X$KCCDI2表
X$KCCDI2表是内核表,这里我暂时没有从官网资料找到表的具体作用,但我们从字段里面列以及调用他的字典视图,可以推断该表可能是用于维护数据库的信息表,包括数据库的创建时间,数据库名等等,所以每一次的扫描X$KCCDI2表,都需要去读取控制文件,导致发生等待control file sequential read
--里面字段包含创建数据库的时间,名称
SQL> select inst_id,DI2AB_DAY,DI2AB_MON,DI2AB_YEAR,DI2AB_NUM,DI2DBUN
2 from X$KCCDI2;
INST_ID DI2AB_DAY DI2AB_MON DI2AB_YEAR DI2AB_NUM DI2DBUN
---------- ---------- ---------- ---------- ---------- ------------------------------
1 25 9 2019 0 xxdb
SQL> select CREATED,name from v$database;
CREATED NAME
------------ ---------
25-SEP-19 xxDB
问题解决:
而接下来对于语句的优化,我们要做的就是要让执行计划避免发生视图的谓词推入,让大表WRH$_SQLSTAT走hash join,所以,可以在执行收集sqlset前,通过会话级别禁用视图谓词推入,关闭视图谓词推入隐含参数"_push_join_predicate"
alter session set "_push_join_predicate"=false;
禁用视图谓词推入之后,sqlset收集dbms_sqltune.select_workload_repository执行几秒就可以完成
查看禁用视图谓词推入之后的执行计划大表WRH$_SQLSTAT走了hash join,视图内部也hash join,表X$KCCDI2的扫描次数也得以减少,执行效率大大提高