Oracle-SQL优化案例一

前言:

近期做了3条Oracle数据库的慢SQL优化,把慢SQL优化的过程记录了下来分享给大家,希望对大家有所帮助。

案例1:

sql_text:

select  cc.*   
from CIF_XXX cc       
where 1=1
AND cc.ch_XXX_name like '%刘璐%'
AND cc.XXX_no in (select XXX_no from cif_XXX_document where iss_country =  :1 )
order by cc.XXX_no ASC;

执行计划:

执行计划问题分析:

1 CIF_XXX进行了全表扫描,因为列ch_xxx_name有索引,但由于ch_xxx_name采用双边的模糊匹配%xxx%,这导致条件减少了走索引的可能,即使走索引也走索引全扫描。

2 索引CIF_XXX_DOCUMENT_IND1以及PK_CIF_XXX_DOCUMENT进行了快速索引全扫描(index fast full index )消耗较大,这是因为where条件列iss_country以及xxx_no只有单列索引没有组合索引,导致进行索引hash连接。

优化建议:

1 可以强制ch_xxx_name走全索引扫描,因为列的可选择率较大回表的消耗较小

2 对iss_country以及xxx_no创建组合索引,避免进行两次index fast full index 以及hash join

create index xxxx.CIF_XXX_DOCUMENT_IND2 on CIF_CLIENCIF_XXX_DOCUMENT(ISS_COUNTRY,XXX_NO) online;

优化后的提升:​

优化后的执行计划,时间从原来是1.2s 减少为0.21秒

优化后的执行计划:

案例2:

sql_text:

​SELECT /*太长内容省略 */ '',  
CASE WHEN T1.AAAA_NUM IN (SELECT A.AAAA_NUM FROM XXXXODS.XXXX_MB_ACCT_INFO A WHERE A.CLOSE_DT IS NULL) THEN '0' ELSE '1' END,  'C',  
NULL,  NULL 
FROM XXXXODS.XXXX_AAAA_INFO T1 
LEFT JOIN XXXXODS.XXXX_AAAA_ADDIT_INFO T4 ON T1.AAAA_NUM=T4.AAAA_NUM 
LEFT JOIN (SELECT * FROM 
(SELECT AAAA_NUM, ISSUE_DT, BBBB_TYPE_CD, MATURE_DT, BBBB_NO, ISSUE_GROUND,  ROW_NUMBER()OVER (PARTITION BY AAAA_NUM ORDER BY BBBB_NO ) U 
FROM XXXXODS.XXXX_AAAA_BBBB
) 
WHERE U=1
) T2 ON T1.AAAA_NUM=T2.AAAA_NUM 
LEFT JOIN CCXX_CHANGE_CODE T3 ON T3.ODSMZ=T1.COMN_INDU_CODE 
LEFT JOIN CCXX_CHANGE_CODE T9 ON T9.ODSMZ=T4.LP_BBBB_TYPE_CD 
LEFT JOIN CCXX_CHANGE_CODE T11 ON T11.ODSMZ=T2.BBBB_TYPE_CD 
LEFT JOIN (SELECT * FROM (SELECT CBK_AAAA_NUM,  ROW_NUMBER()OVER(PARTITION BY CBK_AAAA_NUM ORDER BY AAAA_SEQ_NUM) RM 
FROM XXXXODS.F_CBANK_CTM_AAAA_INFO) 
WHERE RM =1
) T5 ON T1.AAAA_NUM=T5.CBK_AAAA_NUM 
LEFT JOIN (SELECT * FROM XXXXODS.XXXX_AAAA_CONT_INFO WHERE CONT_TYPE_CD='02') T8 ON T1.AAAA_NUM=T8.AAAA_NUM 
LEFT JOIN (SELECT * FROM XXXXODS.XXXX_AAAA_CONT_INFO WHERE CONT_TYPE_CD='04') T10 ON T1.AAAA_NUM=T10.AAAA_NUM 
LEFT JOIN (SELECT * FROM XXXXODS.XXXX_AAAA_CONT_INFO WHERE CONT_TYPE_CD='06') T12 ON T1.AAAA_NUM=T12.AAAA_NUM 
WHERE T1.AAAA_TYPE_CD != '01' 
;

执行计划:

执行计划问题分析:

 查询select里面存在标量子查询"CASE WHEN T1.AAAA_NUM IN (SELECT A.AAAA_NUM FROM XXXXODS.XXXX_MB_ACCT_INFO A WHERE A.CLOSE_DT IS NULL)",访问路径类似for循环导致进行了1418次对表XXXX_MB_ACCT_INFO的全表扫描

优化建议:

对标量子查询进行改写为外部连接,走hash join

改写后的SQL

SELECT   /*太长内容省略 */ '',  
CASE WHEN T1.AAAA_NUM =  A.AAAA_NUM THEN '0' ELSE '1' END,  'C',  NULL,  NULL 
FROM XXXXODS.XXXX_AAAA_INFO T1 
  LEFT JOIN XXXXODS.XXXX_AAAA_ADDIT_INFO T4 ON T1.AAAA_NUM=T4.AAAA_NUM 
  LEFT JOIN (SELECT * FROM 
      (SELECT AAAA_NUM, ISSUE_DT, BBBB_TYPE_CD, MATURE_DT, BBBB_NO, ISSUE_GROUND,  ROW_NUMBER()OVER (PARTITION BY AAAA_NUM ORDER BY BBBB_NO ) U 
        FROM XXXXODS.XXXX_AAAA_BBBB
      ) 
        WHERE U=1
      ) T2 ON T1.AAAA_NUM=T2.AAAA_NUM 
  LEFT JOIN CCXX_CHANGE_CODE T3 ON T3.ODSMZ=T1.COMN_INDU_CODE 
  LEFT JOIN CCXX_CHANGE_CODE T9 ON T9.ODSMZ=T4.LP_BBBB_TYPE_CD 
  LEFT JOIN CCXX_CHANGE_CODE T11 ON T11.ODSMZ=T2.BBBB_TYPE_CD 
  LEFT JOIN (SELECT * FROM (SELECT CBK_AAAA_NUM,  ROW_NUMBER()OVER(PARTITION BY CBK_AAAA_NUM ORDER BY AAAA_SEQ_NUM) RM 
        FROM XXXXODS.F_CBANK_CTM_AAAA_INFO) 
        WHERE RM =1
      ) T5 ON T1.AAAA_NUM=T5.CBK_AAAA_NUM 
  LEFT JOIN (SELECT * FROM XXXXODS.XXXX_AAAA_CONT_INFO WHERE CONT_TYPE_CD='02') T8 ON T1.AAAA_NUM=T8.AAAA_NUM 
  LEFT JOIN (SELECT * FROM XXXXODS.XXXX_AAAA_CONT_INFO WHERE CONT_TYPE_CD='04') T10 ON T1.AAAA_NUM=T10.AAAA_NUM 
  LEFT JOIN (SELECT * FROM XXXXODS.XXXX_AAAA_CONT_INFO WHERE CONT_TYPE_CD='06') T12 ON T1.AAAA_NUM=T12.AAAA_NUM 
  ---改写的子查询
  LEFT join (SELECT distinct AAAA_NUM FROM XXXXODS.XXXX_MB_ACCT_INFO  WHERE CLOSE_DT IS NULL) A on T1.AAAA_NUM=A.AAAA_NUM
  WHERE T1.AAAA_TYPE_CD != '01' 
;

优化后的提升:

优化后的执行计划,时间从原来是4分钟减少为2秒

优化后的执行计划:

案例3:

sql_text:

insert into tmp_cccc_282001_02( aaaa_id,bbb_cell, count_bbb ) 
  select s.aaaa_id, s.bbb_cell, s.count_bbb 
  from (select t.aaaa_id, t1.bbb_cell, count(t.aaaa_id) over(partition by
    t1.bbb_cell) as count_bbb 
  from t2a_aaaa_i t, (select distinct bbb_cell from tmp_cccc_282001_01) t1 
  where (t.office_bbb = t1.bbb_cell or t.home_bbb = t1.bbb_cell or t.mobile_phone = t1.bbb_cell) )s 
  where s.count_bbb >= 3

执行计划:

执行计划问题分析:

tmp_cccc_282001_01执行计划由于统计信息不正确估算只有1行数据,导致走了nested loop,导致对大表T2A_aaaa_I进行了2753次扫描,正常应该是走hash join

优化建议:

对表进行统计信息收集

BEGIN 
	DBMS_STATS.GATHER_TABLE_STATS(ownname => 'XXXXAML', 
	tabname => 'TMP_cccc_282001_01', 
	estimate_percent => 100, 
	method_opt => 'for all columns size skewonly',
	no_invalidate => FALSE, 
	degree => 8, 
	cascade => TRUE); 
END; 
 / 
 
 
BEGIN 
	DBMS_STATS.GATHER_TABLE_STATS(ownname => 'XXXXAML', 
	tabname => 'T2A_aaaa_I', 
	estimate_percent => 100, 
	method_opt => 'for all columns size skewonly',
	no_invalidate => FALSE, 
	degree => 8, 
	cascade => TRUE); 
END; 
 /

优化后的提升:

优化后的执行计划,时间从原来是25秒减少为0.38秒

优化后的执行计划:

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值