网友QQ发来如下信息,问我下面这个SQL是否能有性能提升的地方,他们监控到这个SQL磁盘读很高
SQL> set autotrace on SQL> select * from( select GRDL_ID qyid,KHMC nsrmc,KHBM nsrsbh,KHBM six_nsrsbh,'' six_dssh,gjc,fzgs_dm,'2' khlx from khgl_grdlxx 2 union all 3 select dwkh_id qyid, khmc nsrmc,nvl(nsrsbh,dssh) nsrsbh,nvl(six_nsrsbh,six_dssh) six_nsrsbh,six_dssh,gjc,fzgs_dm,'0' khlx from KHGL_DWKH_COREINFO 4 union all 5 select DLS_BM qyid,DLS_MC nsrmc,DLS_BM nsrsbh,DLS_BM six_nsrsbh,'' six_dssh,gjc,fzgs_dm,'1' khlx from KHGL_DLSJBXX 6 ) 7 where (six_nsrsbh = '706773' or six_dssh = '706773') and rownum<11; QYID NSRMC -------------------------------- ------------------------------------------------------------------------------------- a4af925f2a224bc4a8ac42dc87bb5192 农一师塔里木广告信息公司 b59f82aa67ae4b88b331a4042e1ced43 保定市丽景园林绿化有限公司 6db2f2cc8d8446a2b80f190fffd1ff72 保定市绿景园林绿化有限公司 执行计划 ---------------------------------------------------------- Plan hash value: 112825667 ------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10 | 1320 | 18 (0)| 00:00:01 | |* 1 | COUNT STOPKEY | | | | | | | 2 | VIEW | | 32 | 4224 | 18 (0)| 00:00:01 | | 3 | UNION-ALL | | | | | | |* 4 | TABLE ACCESS FULL| KHGL_GRDLXX | 11 | 803 | 5 (0)| 00:00:01 | |* 5 | TABLE ACCESS FULL| KHGL_DWKH_COREINFO | 11 | 1144 | 7 (0)| 00:00:01 | |* 6 | TABLE ACCESS FULL| KHGL_DLSJBXX | 10 | 380 | 6 (0)| 00:00:01 | ------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<11) 4 - filter(''='706773' OR "KHBM"='706773') 5 - filter(NVL("SIX_NSRSBH","SIX_DSSH")='706773' OR "SIX_DSSH"='706773') 6 - filter(''='706773' OR "DLS_BM"='706773') 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 27226 consistent gets 26937 physical reads 0 redo size 1288 bytes sent via SQL*Net to client 469 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 3 rows processed
根据SQL的执行计划和统计信息可以看出,这个SQL效率确非常低下,3个表都采用了全表扫描,这个必然导致物理读高。
仔细分析执行计划以及SQL语句,我真的无语了,这个SQL语句写得之烂让我情何以堪,于是我做如下改写
select * from (select GRDL_ID qyid, KHMC nsrmc, KHBM nsrsbh, KHBM six_nsrsbh, '' six_dssh, gjc, fzgs_dm, '2' khlx from khgl_grdlxx where KHBM = '706773' union all select dwkh_id qyid, khmc nsrmc, nvl(nsrsbh, dssh) nsrsbh, nvl(six_nsrsbh, six_dssh) six_nsrsbh, six_dssh, gjc, fzgs_dm, '0' khlx from KHGL_DWKH_COREINFO where (six_nsrsbh = '706773' or six_dssh = '706773') union all select DLS_BM qyid, DLS_MC nsrmc, DLS_BM nsrsbh, DLS_BM six_nsrsbh, '' six_dssh, gjc, fzgs_dm, '1' khlx from KHGL_DLSJBXX where DLS_BM = '706773') where rownum < 11;
改写之后,SQL执行计划如下:
执行计划 ---------------------------------------------------------- Plan hash value: 1863808260 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 8 | 1056 | 12 (0)| 00:00: |* 1 | COUNT STOPKEY | | | | | | 2 | VIEW | | 8 | 1056 | 12 (0)| 00:00: | 3 | UNION-ALL | | | | | | 4 | TABLE ACCESS BY INDEX ROWID | KHGL_GRDLXX | 1 | 73 | 2 (0)| 00:00: |* 5 | INDEX UNIQUE SCAN | IDX_GRDLXX_KHBM | 1 | | 1 (0)| 00:00: | 6 | TABLE ACCESS BY INDEX ROWID | KHGL_DWKH_COREINFO | 6 | 624 | 8 (0)| 00:00: | 7 | BITMAP CONVERSION TO ROWIDS | | | | | | 8 | BITMAP OR | | | | | | 9 | BITMAP CONVERSION FROM ROWIDS| | | | | |* 10 | INDEX RANGE SCAN | IDX_DWKHCORE_SIX_DSSH | | | 3 (0)| 00:00: | 11 | BITMAP CONVERSION FROM ROWIDS| | | | | |* 12 | INDEX RANGE SCAN | IDX_DWKHCORE_SIXNSRSBH | | | 3 (0)| 00:00: | 13 | TABLE ACCESS BY INDEX ROWID | KHGL_DLSJBXX | 1 | 38 | 2 (0)| 00:00: |* 14 | INDEX UNIQUE SCAN | PK_KHGL_DLSJBXX | 1 | | 1 (0)| 00:00: ---------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<11) 5 - access("KHBM"='706773') 10 - access("SIX_DSSH"='706773') 12 - access("SIX_NSRSBH"='706773') 14 - access("DLS_BM"='706773') 统计信息 ---------------------------------------------------------- 15 recursive calls 0 db block gets 17 consistent gets 0 physical reads 0 redo size 1288 bytes sent via SQL*Net to client 469 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 3 rows processed
为什么要这么改写呢? 因为不改写的执行计划里面有''='706773' 这个会限制使用索引
其实这里ORACLE用到的CBO转换技术有1个,叫做Pushing Predicate(谓词推入),但是在第一个SQL语句中,由于有这样的SELECT 条件'' six_dssh
导致谓词推入的时候过滤也成了''='706773' ,从这里也知道CBO还是不够智能,如果能智能一点,帮我们把''='706773' 这样的过滤省略了岂不是更好