SQL优化一例:懂得去除累赘,还你一身轻松
1,805 total views, 2 views today
在生产库发现了一条奇葩SQL,下面进行分析。
1 2 3 4 5 6 7 8 9 |
select count(*) from ORD_MDA_CALL_INFO_D T, PRD_PRD_M P WHERE T.PRD_ID = P.PRD_ID(+) and (T.EMP_NO = :1 OR T.EMP_NO = :2) and T.MDA_CNVR_PTR_CD = :3 and T.INST_DTM > to_date(:4, 'yyyy-mm-dd hh24:mi:ss') and T.INST_DTM < to_date(:5, 'yyyy-mm-dd hh24:mi:ss') AND (T.BIZ_UNT_CD = :6 or T.BIZ_UNT_CD = 'TV') order by T.INST_DTM desc; |
问题1:count()统计行数的时候,排序操作是多余的。
问题2:left join连接中,以左表为主表,和右表通过关联条件连接,A表满足条件的数据都会被返回,而B表中没有的数据则以NULL表示。上面的SQL中T表left join P表,但是SQL中P表并没有任何过滤条件,所有过滤都是T表在做,那么P表完全没有必要写上。写在这里完全没有作用,这一点可以通过执行计划证明,执行计划中没有任何P表的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------- Plan hash value: 3235109976 ------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 23 | 132 (0)| 00:00:02 | | 1 | SORT AGGREGATE | | 1 | 23 | | | |* 2 | FILTER | | | | | | | 3 | INLIST ITERATOR | | | | | | |* 4 | TABLE ACCESS BY INDEX ROWID| ORD_MDA_CALL_INFO_D | 1 | 23 | 132 (0)| 00:00:02 | |* 5 | INDEX RANGE SCAN | IX_ORD_MDA_CALL_INFO_D_04 | 129 | | 5 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter(TO_DATE(:5,'yyyy-mm-dd hh24:mi:ss')>TO_DATE(:4,'yyyy-mm-dd hh24:mi:ss')) 4 - filter("T"."MDA_CNVR_PTR_CD"=:3 AND ("T"."BIZ_UNT_CD"=:6 OR "T"."BIZ_UNT_CD"='TV')) 5 - access(("T"."EMP_NO"=:1 OR "T"."EMP_NO"=:2) AND "T"."INST_DTM">TO_DATE(:4,'yyyy-mm-dd hh24:mi:ss') AND "T"."INST_DTM"<TO_DATE(:5,'yyyy-mm-dd hh24:mi:ss')) 20 rows selected. |
优化后的SQL,去除order by,去除P表。
1 2 3 4 5 6 7 |
select count(*) from chgshs.ORD_MDA_CALL_INFO_D T WHERE (T.EMP_NO = :1 OR T.EMP_NO = :2) and T.MDA_CNVR_PTR_CD = :3 and T.INST_DTM > to_date(:4, 'yyyy-mm-dd hh24:mi:ss') and T.INST_DTM < to_date(:5, 'yyyy-mm-dd hh24:mi:ss') AND (T.BIZ_UNT_CD = :6 or T.BIZ_UNT_CD = 'TV'); |