案例分析总结:
sql优化的四点:
1、对象的进入方式
2、对象的关联方式
3、每一步的代价与基数
4、执行计划的注释部分
该案例是由于对象的统计信息收集有误,而导致sql执行使用错误的执行计划。
因此统计信息的及时收集,正确的收集,对sql的运行是灰常重要的。
对于直方图统计信息的收集,我们的建议是:
若之前有直方图信息,则继续收集,若没有就不要多余的收集直方图信息(按照默认就好),除非可以证明有直方图信息更好。
案例分析过程:
DBA发现一条sql执行了超长时间,还有没执行完(超过10小时),经分析该sql是一个定时job每天凌晨5点执行存储过程发起的。
sql及试图定义不再提供,我们只关注核心部分。
6m37jw4kj0XXX:
Plan hash value: 2496417X94

基于表上的索引信息:

相关的统计信息:

sql那么长,其实我们只用看 核心部分:
select * from (SELECT CUXXXXXX_NO,
REVSAL_FLAG,
CANCEL_FLAG,
SXXXXX_DATE,
TXX_TXXX,
TXX_AMT,
TXX_CHANNEL,
(CASE
WHEN H.CUSXXXXX_CITY_COXX IN ('999900', '999901') THEN
'999901'
ELSE
CUSXXXXX_CITY_COXX
END) CUSXXXXX_CITY_COXX
FROM V_TXX_LXX_HIS H) A
WHERE A.CANCEL_FLAG IS NULL
AND A.CUSXXXXX_CITY_COXX IS NOT NULL
AND A.REVSAL_FLAG IS NULL
AND A.CUXXXXXX_NO LIKE '86%'
AND A.SXXXXX_DATE = '20151120';
执行计划:2497803424:

在上面的执行计划里面,我们看到4后 优化器估算的基数为9009;
实际呢:
SELECT count(*) FROM T_XXX_XXXX_XX_HIS t where CUXXXXXX_NO LIKE '86%'; --44914604
(到此我们可以猜测是统计信息的问题)
为什么没有用到这个索引I_OXX_XXX_SXXX:
SELECT count(*) FROM T_XXX_XXXX_XX_HIS a where A.SXXXXX_DATE = '20151120';--3701210
强制使用:
select *+ index(a I_OXX_XXX_SXXX)*/ count(*)
from T_XXX_XXXX_XX_HIS a
where CUXXXXXX_NO LIKE '86%'
AND CASE "CUSXXXXX_CITY_COXX"
WHEN '999900' THEN
'999901'
WHEN '999901' THEN
'999901'
ELSE
"CUSXXXXX_CITY_COXX"
END IS NOT NULL
AND CANCEL_FLAG IS NULL
AND REVSAL_FLAG IS NULL
AND SXXXXX_DATE = '20151120';

于是对统计信息重新收集:
begin
DBMS_STATS.GATHER_TABLE_STATS ('BTUPXXXXXX','T_XXX_XXXX_XX_HIS',degree=>8);
end;
现在执行:
select * from (SELECT CUXXXXXX_NO,
REVSAL_FLAG,
CANCEL_FLAG,
SXXXXX_DATE,
TXX_TXXX,
TXX_AMT,
TXX_CHANNEL,
(CASE
WHEN H.CUSXXXXX_CITY_COXX IN ('999900', '999901') THEN
'999901'
ELSE
CUSXXXXX_CITY_COXX
END) CUSXXXXX_CITY_COXX
FROM V_TXX_LXX_HIS H) A
WHERE A.CANCEL_FLAG IS NULL
AND A.CUSXXXXX_CITY_COXX IS NOT NULL
AND A.REVSAL_FLAG IS NULL
AND A.CUXXXXXX_NO LIKE '86%'
AND A.SXXXXX_DATE = '20151120';

若还按照之前的执行计划:

现在的统计信息:

我们可以发现新收集的统计信息与旧的相比:1: 数据量不对 2:直方图信息也不对
于是继续做下面的实验:(排除直方图的影响)
begin
DBMS_STATS.GATHER_TABLE_STATS ('BTUPXXXXXX','T_XXX_XXXX_XX_HIS',degree=>8,method_opt=>'for columns SXXXXX_DATE size 1 CUXXXXXX_NO size 1');
end;
再执行:

===============================================================================
对比这3个执行计划:


再启动job:观察

因此统计信息的及时收集,正确的收集,对sql的运行是灰常重要的。
对于直方图统计信息的收集,我们的建议是:
若之前有直方图信息,则继续收集,若没有就不要多余的收集直方图信息(按照默认就好),除非可以证明有直方图信息更好




