我是靠谱客的博主 清爽花卷,最近开发中收集的这篇文章主要介绍Oracle 12C 某电信公司 优化一个12小时跑不出来的SQL,最后6分钟就跑完了,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

      今天一个网友找我帮他优化他负责数据库的SQL,客服反映这个SQL 跑很久,跑了12个小时,最后跑出ORA-01555 ,以报错结束了这个慢SQL的生命。找我帮他优化,OK ,义不容辞。

      


     他们那边数据库环境是Oracle 12C的:

    



原SQL 及其执行计划为:

<span style="font-size:10px;">explain plan for
select count(*)
  from (select A.service_code,
               A.accNo,
               A.phone_no,
               A.account_type,
               nvl(B.mtNo, 0) mt
          from ((select service_code,
                        decode(account_type,
                               '1',
                               super_account_no,
                               account_no) accNo,
                        phone_no,
                        account_type
                   from t_service_order T1
                  where province_code = '44'
                    and add_months(process_time, free_month) <
                        add_months(sysdate, -12)
                    and charge_type = '2'
                    and exists
                  (select T2.super_account_no,
                                max(T2.commit_date),
                                count(T2.super_account_no) cn
                           from t_pkk_fail T2
                          where T2.super_account_no = T1.super_account_no
                            and T2.phone_no = T1.phone_no
                            and T2.service_code = T1.service_code
                            and T2.charge_type = '2'
                          group by T2.super_account_no
                         having(count(T2.super_account_no) > round((sysdate - add_months(T1.process_time, T1.free_month)) / 365) and count(T2.super_account_no) > 1))) A left join
                (select account_no, count(*) mtNo
                   from t_mail_info_mt1 M
                  where province_code = '44'
                    and to_char(trade_date,'YYYYMMDD') >= '20160401'
                    and to_char(trade_date,'YYYYMMDD') < '20160501'
                  group by account_no) B on A.accno = B.account_no)) X
 where X.mt = 0;


PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2939529741

----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation			       | Name		 | Rows  | Bytes |TempSpc| Cost (%CPU)| Time	 | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT		       |		 |     1 |   141 |	 |   529M  (1)| 05:44:37 |	 |	 |
|   1 |  SORT AGGREGATE 		       |		 |     1 |   141 |	 |	      | 	 |	 |	 |
|*  2 |   FILTER			       |		 |	 |	 |	 |	      | 	 |	 |	 |
|*  3 |    FILTER			       |		 |	 |	 |	 |	      | 	 |	 |	 |
|*  4 |     HASH JOIN OUTER		       |		 |  4752K|   639M|   489M|  1864K  (1)| 00:01:13 |	 |	 |
|   5 |      JOIN FILTER CREATE 	       | :BF0000	 |  4752K|   435M|	 |   184K  (1)| 00:00:08 |	 |	 |
|   6 |       PARTITION LIST SINGLE	       |		 |  4752K|   435M|	 |   184K  (1)| 00:00:08 |    19 |    19 |
|*  7 |        TABLE ACCESS FULL	       | T_SERVICE_ORDER |  4752K|   435M|	 |   184K  (1)| 00:00:08 |    19 |    19 |
|   8 |      VIEW			       |		 |    64M|  2767M|	 |  1481K  (1)| 00:00:58 |	 |	 |
|   9 |       HASH GROUP BY		       |		 |    64M|  2583M|  4301M|  1481K  (1)| 00:00:58 |	 |	 |
|  10 |        JOIN FILTER USE		       | :BF0000	 |    86M|  3462M|	 |   701K  (1)| 00:00:28 |	 |	 |
|  11 | 	PARTITION RANGE ITERATOR       |		 |    86M|  3462M|	 |   701K  (1)| 00:00:28 |     4 |    30 |
|  12 | 	 PARTITION LIST SINGLE	       |		 |    86M|  3462M|	 |   701K  (1)| 00:00:28 |    19 |    19 |
|* 13 | 	  TABLE ACCESS FULL	       | T_MAIL_INFO_MT1 |    86M|  3462M|	 |   701K  (1)| 00:00:28 |   KEY |   KEY |
|* 14 |    FILTER			       |		 |	 |	 |	 |	      | 	 |	 |	 |
|  15 |     SORT GROUP BY NOSORT	       |		 |     1 |    59 |	 |   111   (0)| 00:00:01 |	 |	 |
|  16 |      PARTITION LIST ALL 	       |		 |     1 |    59 |	 |   111   (0)| 00:00:01 |     1 |    35 |
|* 17 |       TABLE ACCESS BY LOCAL INDEX ROWID| T_PKK_FAIL	 |     1 |    59 |	 |   111   (0)| 00:00:01 |     1 |    35 |
|* 18 |        INDEX RANGE SCAN 	       | SUPER_ACCT_INDX |     5 |	 |	 |   106   (0)| 00:00:01 |     1 |    35 |
----------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter( EXISTS (SELECT 0 FROM "T_PKK_FAIL" "T2" WHERE "T2"."SUPER_ACCOUNT_NO"=:B1 AND "T2"."PHONE_NO"=:B2 AND
	      "T2"."CHARGE_TYPE"=2 AND "T2"."SERVICE_CODE"=:B3 GROUP BY "T2"."SUPER_ACCOUNT_NO" HAVING
	      COUNT(*)>ROUND((SYSDATE@!-ADD_MONTHS(:B4,:B5))/365) AND COUNT(*)>1))
   3 - filter(NVL("B"."MTNO",0)=0)
   4 - access("B"."ACCOUNT_NO"(+)=DECODE("ACCOUNT_TYPE",'1',"SUPER_ACCOUNT_NO","ACCOUNT_NO"))
   7 - filter("CHARGE_TYPE"=2 AND ADD_MONTHS(INTERNAL_FUNCTION("PROCESS_TIME"),INTERNAL_FUNCTION("FREE_MONTH"))<ADD_MONTHS
	      (SYSDATE@!,-12))
  13 - filter(SYS_OP_BLOOM_FILTER(:BF0000,"ACCOUNT_NO"))
  14 - filter(COUNT(*)>ROUND((SYSDATE@!-ADD_MONTHS(:B1,:B2))/365) AND COUNT(*)>1)
  17 - filter("T2"."PHONE_NO"=:B1 AND "T2"."CHARGE_TYPE"=2 AND "T2"."SERVICE_CODE"=:B2)
  18 - access("T2"."SUPER_ACCOUNT_NO"=:B1)</span>



我改写的SQL 以及执行计划为:


select count(*)
  from (select A.service_code,
               A.accNo,
               A.phone_no,
               A.account_type,
               nvl(B.mtNo, 0) mt
          from ((select T1.service_code,
                        decode(T1.account_type,
                               '1',
                               T1.super_account_no,
                               T1.account_no) accNo,
                        T1.phone_no,
                        T1.account_type
                   from t_service_order T1
		   inner join 
		   (
                  select /*+ parallel(T2,36) full(T2) */
                    distinct
                    T2.super_account_no,T2.phone_no,T2.service_code, count(T2.super_account_no) cn
                    from t_pkk_fail T2
                   group by T2.super_account_no,T2.phone_no,T2.service_code
                  having count(T2.super_account_no) > 1
		   )
		   rs
		   on (rs.super_account_no = T1.super_account_no
                      and rs.phone_no = T1.phone_no
                      and rs.service_code = T1.service_code
		      and rs.cn > round((sysdate - add_months(T1.process_time, T1.free_month)) / 365)
		      )
                  where province_code = '44'
                    and add_months(process_time, free_month) <
                        add_months(sysdate, -12)
                    and charge_type = '2'
		    )) A left join
                (select /*+ index(M,T_MT1_ACCOUNT_NO) */ account_no, count(account_no) mtNo
                   from t_mail_info_mt1 M
                  where province_code = '44'
		    and account_no is not null
                    and trade_date >= to_date('20160401','YYYYMMDD')
                    and trade_date <  to_date('20160501','YYYYMMDD')
                  group by account_no)
                  B on A.accno = B.account_no) X
 where X.mt = 0;


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation					    | Name	       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |    TQ	|IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT				    |		       |     1 |   178 |       |   424K  (1)| 00:00:17 |       |       |	|      |	    |
|   1 |  SORT AGGREGATE 				    |		       |     1 |   178 |       |	    |	       |       |       |	|      |	    |
|   2 |   PX COORDINATOR				    |		       |       |       |       |	    |	       |       |       |	|      |	    |
|   3 |    PX SEND QC (RANDOM)				    | :TQ10003	       |     1 |   178 |       |	    |	       |       |       |  Q1,03 | P->S | QC (RAND)  |
|   4 |     SORT AGGREGATE				    |		       |     1 |   178 |       |	    |	       |       |       |  Q1,03 | PCWP |	    |
|*  5 |      FILTER					    |		       |       |       |       |	    |	       |       |       |  Q1,03 | PCWC |	    |
|   6 |       NESTED LOOPS OUTER			    |		       |  1780 |   309K|       |   424K  (1)| 00:00:17 |       |       |  Q1,03 | PCWP |	    |
|*  7 |        HASH JOIN				    |		       |  1780 |   283K|       |   423K  (1)| 00:00:17 |       |       |  Q1,03 | PCWP |	    |
|   8 | 	BUFFER SORT				    |		       |       |       |       |	    |	       |       |       |  Q1,03 | PCWC |	    |
|   9 | 	 PX RECEIVE				    |		       |   633K|    57M|       |   184K  (1)| 00:00:08 |       |       |  Q1,03 | PCWP |	    |
|  10 | 	  PX SEND HYBRID HASH			    | :TQ10000	       |   633K|    57M|       |   184K  (1)| 00:00:08 |       |       |	| S->P | HYBRID HASH|
|  11 | 	   STATISTICS COLLECTOR 		    |		       |       |       |       |	    |	       |       |       |	|      |	    |
|  12 | 	    PARTITION LIST SINGLE		    |		       |   633K|    57M|       |   184K  (1)| 00:00:08 |    19 |    19 |	|      |	    |
|* 13 | 	     TABLE ACCESS FULL			    | T_SERVICE_ORDER  |   633K|    57M|       |   184K  (1)| 00:00:08 |    19 |    19 |	|      |	    |
|  14 | 	PX RECEIVE				    |		       |    18M|  1163M|       |   238K  (1)| 00:00:10 |       |       |  Q1,03 | PCWP |	    |
|  15 | 	 PX SEND HYBRID HASH			    | :TQ10002	       |    18M|  1163M|       |   238K  (1)| 00:00:10 |       |       |  Q1,02 | P->P | HYBRID HASH|
|  16 | 	  VIEW					    |		       |    18M|  1163M|       |   238K  (1)| 00:00:10 |       |       |  Q1,02 | PCWP |	    |
|* 17 | 	   FILTER				    |		       |       |       |       |	    |	       |       |       |  Q1,02 | PCWC |	    |
|  18 | 	    HASH GROUP BY			    |		       |    18M|   816M|    20G|   238K  (1)| 00:00:10 |       |       |  Q1,02 | PCWP |	    |
|  19 | 	     PX RECEIVE 			    |		       |    18M|   816M|       |   238K  (1)| 00:00:10 |       |       |  Q1,02 | PCWP |	    |
|  20 | 	      PX SEND HASH			    | :TQ10001	       |    18M|   816M|       |   238K  (1)| 00:00:10 |       |       |  Q1,01 | P->P | HASH	    |
|  21 | 	       HASH GROUP BY			    |		       |    18M|   816M|    20G|   238K  (1)| 00:00:10 |       |       |  Q1,01 | PCWP |	    |
|  22 | 		PX BLOCK ITERATOR		    |		       |   364M|    15G|       |   119K  (1)| 00:00:05 |     1 |    35 |  Q1,01 | PCWC |	    |
|  23 | 		 TABLE ACCESS FULL		    | T_PKK_FAIL       |   364M|    15G|       |   119K  (1)| 00:00:05 |     1 |    35 |  Q1,01 | PCWP |	    |
|  24 |        VIEW PUSHED PREDICATE			    |		       |     1 |    15 |       |    22	 (0)| 00:00:01 |       |       |  Q1,03 | PCWP |	    |
|  25 | 	SORT GROUP BY				    |		       |     1 |    42 |       |    22	 (0)| 00:00:01 |       |       |  Q1,03 | PCWP |	    |
|  26 | 	 PARTITION RANGE ITERATOR		    |		       |     1 |    42 |       |    22	 (0)| 00:00:01 |     4 |     6 |  Q1,03 | PCWP |	    |
|  27 | 	  PARTITION LIST SINGLE 		    |		       |     1 |    42 |       |    22	 (0)| 00:00:01 |    19 |    19 |  Q1,03 | PCWP |	    |
|  28 | 	   TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| T_MAIL_INFO_MT1  |     1 |    42 |       |    22	 (0)| 00:00:01 |   KEY |   KEY |  Q1,03 | PCWP |	    |
|* 29 | 	    INDEX RANGE SCAN			    | T_MT1_ACCOUNT_NO |     1 |       |       |    10	 (0)| 00:00:01 |   KEY |   KEY |  Q1,03 | PCWP |	    |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - filter(NVL("B"."MTNO",0)=0)
   7 - access("RS"."SUPER_ACCOUNT_NO"="T1"."SUPER_ACCOUNT_NO" AND "RS"."PHONE_NO"="T1"."PHONE_NO" AND "RS"."SERVICE_CODE"="T1"."SERVICE_CODE")
       filter("RS"."CN">ROUND((SYSDATE@!-ADD_MONTHS(INTERNAL_FUNCTION("T1"."PROCESS_TIME"),INTERNAL_FUNCTION("T1"."FREE_MONTH")))/365))
  13 - filter("T1"."CHARGE_TYPE"=2 AND ADD_MONTHS(INTERNAL_FUNCTION("T1"."PROCESS_TIME"),INTERNAL_FUNCTION("T1"."FREE_MONTH"))<ADD_MONTHS(SYSDATE@!,-12))
  17 - filter(COUNT(SYS_OP_CSR(SYS_OP_MSR(COUNT(*)),0))>1)
  29 - access("ACCOUNT_NO"=DECODE("T1"."ACCOUNT_TYPE",'1',"T1"."SUPER_ACCOUNT_NO","T1"."ACCOUNT_NO"))

Note
-----
   - dynamic statistics used: dynamic sampling (level=AUTO)
   - Degree of Parallelism is 36 because of table property

51 rows selected.


最终优化成功:



最终6分钟跑完了哈!

最后

以上就是清爽花卷为你收集整理的Oracle 12C 某电信公司 优化一个12小时跑不出来的SQL,最后6分钟就跑完了的全部内容,希望文章能够帮你解决Oracle 12C 某电信公司 优化一个12小时跑不出来的SQL,最后6分钟就跑完了所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部