sql微调

时间:2017-12-07 10:36:13

标签: sql oracle with-statement sql-tuning

  
    

在表格中,我需要根据列将2条记录合并为一条记录     (在这种情况下,列1.WORK_ORDER_NUM,2.ESN 3.PLANT 4. REMD_PART_NUM     5. REMD_PART_SERIAL)。如果这5列相等,那么我必须在其他列中使用Aggregate函数将其作为一个记录     在这种情况下,列是LLP_TRACKD_PART_IND,REMD_PART_TSN和     REMD_PART_CSN]。

  

这是我尝试过的:

SELECT decode (PLANT ,'ECL','CELMA','EDS','CELMA',PLANT)PLANT,
 COUNT(*) RECORD_COUNT,
 COUNT(DISTINCT OFF.REMD_PART_NUM) REMD_PART_NUM_COUNT,
 COUNT(DISTINCT OFF.REMD_PART_SERIAL) REMD_PART_SER_NUM_COUNT,
  COUNT(DECODE(LLP_TRACKD_PART_IND,'LL',LLP_TRACKD_PART_IND,NULL)) LL_COUNT,
 COUNT(DECODE(LLP_TRACKD_PART_IND,'LR',LLP_TRACKD_PART_IND,NULL)) LR_COUNT,
 COUNT(DECODE(LLP_TRACKD_PART_IND,'TR',LLP_TRACKD_PART_IND,NULL)) TR_COUNT,
 SUM(OFF.REMD_PART_QTY) TOTAL_REMD_PART_QTY, 
  SUM(decode(LLP_TRACKD_PART_IND,null,0,
     CASE
       WHEN REGEXP_LIKE(REMD_PART_TSN, '^-?\d+(\.\d+)?$')
            THEN CAST(REMD_PART_TSN AS NUMBER)
        ELSE 0
    END
  )) TOTAL_TSN,
 SUM(decode(LLP_TRACKD_PART_IND,null,0,
    CASE
        WHEN REGEXP_LIKE(REMD_PART_CSN, '^-?\d+(\.\d+)?$')
            THEN CAST(REMD_PART_CSN AS NUMBER)
        ELSE 0
    END
 )) TOTAL_CSN
FROM (with t as ( SELECT distinct PLANT,
WORK_ORDER_NUM,ESN,REMD_PART_NUM,REMD_PART_SERIAL,REMD_PART_IIN,
LLP_TRACKD_PART_IND,
REMD_PART_QTY,REMD_PART_TSN,REMD_PART_CSN,REMD_PART_TSO,REMD_PART_CSO
,REMD_PART_TSC,REMD_PART_CSC,REMD_CYCLE_REMAIN          
FROM <TABLE1> 
WHERE 
REMD_PART_NUM is not null 
)
select DISTINCT PLANT,WORK_ORDER_NUM,ESN,REMD_PART_NUM,REMD_PART_SERIAL 
,REMD_PART_IIN
 ,(select max(LLP_TRACKD_PART_IND) from t bb  where aa.PLANT=bb.PLANT and 
aa.WORK_ORDER_NUM=bb.WORK_ORDER_NUM 
 and aa.ESN=bb.ESN 
  and aa.REMD_PART_NUM=bb.REMD_PART_NUM
  and aa.REMD_PART_SERIAL=bb.REMD_PART_SERIAL) LLP_TRACKD_PART_IND
 ,REMD_PART_QTY
 ,(select max(REMD_PART_TSN) from t bb  where aa.PLANT=bb.PLANT and 
aa.WORK_ORDER_NUM=bb.WORK_ORDER_NUM 
 and aa.ESN=bb.ESN 
 and aa.REMD_PART_NUM=bb.REMD_PART_NUM
 and aa.REMD_PART_SERIAL=bb.REMD_PART_SERIAL) REMD_PART_TSN
 ,
(select max(REMD_PART_CSN) from t bb  where aa.PLANT=bb.PLANT and             
aa.WORK_ORDER_NUM=bb.WORK_ORDER_NUM 
  and aa.ESN=bb.ESN 
  and aa.REMD_PART_NUM=bb.REMD_PART_NUM
  and aa.REMD_PART_SERIAL=bb.REMD_PART_SERIAL) REMD_PART_CSN
  from t aa) OFF
WHERE 
REMD_PART_NUM is not null
GROUP BY decode (PLANT ,'ECL','CELMA','EDS','CELMA',PLANT) 

完成需要大约8个小时。还有其他方法可以更快地完成它。 It took 8 hours to complete

1 个答案:

答案 0 :(得分:1)

从更好的查询格式开始,它可以让您轻松理解代码并注意重复的模式:

SELECT decode (PLANT ,'ECL','CELMA','EDS','CELMA',PLANT)PLANT,
    COUNT(*) RECORD_COUNT,
    COUNT(DISTINCT OFF.REMD_PART_NUM) REMD_PART_NUM_COUNT,
    COUNT(DISTINCT OFF.REMD_PART_SERIAL) REMD_PART_SER_NUM_COUNT,
    COUNT(DECODE(LLP_TRACKD_PART_IND,'LL',LLP_TRACKD_PART_IND,NULL)) LL_COUNT,
    COUNT(DECODE(LLP_TRACKD_PART_IND,'LR',LLP_TRACKD_PART_IND,NULL)) LR_COUNT,
    COUNT(DECODE(LLP_TRACKD_PART_IND,'TR',LLP_TRACKD_PART_IND,NULL)) TR_COUNT,
    SUM(OFF.REMD_PART_QTY) TOTAL_REMD_PART_QTY, 
    SUM(decode(LLP_TRACKD_PART_IND,null,0,
            CASE
                WHEN REGEXP_LIKE(REMD_PART_TSN, '^-?\d+(\.\d+)?$')
                THEN CAST(REMD_PART_TSN AS NUMBER)
                ELSE 0
            END
        )) TOTAL_TSN,
    SUM(decode(LLP_TRACKD_PART_IND,null,0,
            CASE
                WHEN REGEXP_LIKE(REMD_PART_CSN, '^-?\d+(\.\d+)?$')
                THEN CAST(REMD_PART_CSN AS NUMBER)
                ELSE 0
            END
        )) TOTAL_CSN
FROM (
    with t as ( 
        SELECT distinct PLANT, WORK_ORDER_NUM,ESN,REMD_PART_NUM,REMD_PART_SERIAL,REMD_PART_IIN,
                LLP_TRACKD_PART_IND,
                REMD_PART_QTY,REMD_PART_TSN,REMD_PART_CSN,REMD_PART_TSO,REMD_PART_CSO
                ,REMD_PART_TSC,REMD_PART_CSC,REMD_CYCLE_REMAIN          
        FROM <TABLE1> 
        WHERE REMD_PART_NUM is not null 
    )
    select DISTINCT PLANT,WORK_ORDER_NUM,ESN,REMD_PART_NUM,REMD_PART_SERIAL 
            ,REMD_PART_IIN
            ,(  select max(LLP_TRACKD_PART_IND) 
                from t bb  
                where aa.PLANT=bb.PLANT 
                    and aa.WORK_ORDER_NUM=bb.WORK_ORDER_NUM 
                    and aa.ESN=bb.ESN 
                    and aa.REMD_PART_NUM=bb.REMD_PART_NUM
                    and aa.REMD_PART_SERIAL=bb.REMD_PART_SERIAL
            ) LLP_TRACKD_PART_IND
            ,REMD_PART_QTY
            ,(  select max(REMD_PART_TSN) from t bb  
                where aa.PLANT=bb.PLANT 
                    and aa.WORK_ORDER_NUM=bb.WORK_ORDER_NUM 
                    and aa.ESN=bb.ESN 
                    and aa.REMD_PART_NUM=bb.REMD_PART_NUM
                    and aa.REMD_PART_SERIAL=bb.REMD_PART_SERIAL
            ) REMD_PART_TSN
            ,
            (   select max(REMD_PART_CSN) from t bb  
                where aa.PLANT=bb.PLANT 
                    and aa.WORK_ORDER_NUM=bb.WORK_ORDER_NUM 
                    and aa.ESN=bb.ESN 
                    and aa.REMD_PART_NUM=bb.REMD_PART_NUM
                    and aa.REMD_PART_SERIAL=bb.REMD_PART_SERIAL
            ) REMD_PART_CSN
    from t aa
) OFF
WHERE REMD_PART_NUM is not null
GROUP BY decode (PLANT ,'ECL','CELMA','EDS','CELMA',PLANT)
;

您将看到以下模式重复3次(3个几乎相同的子查询):

select max( some_field ) 
from t bb  
where aa.PLANT=bb.PLANT 
  and aa.WORK_ORDER_NUM=bb.WORK_ORDER_NUM 
  and aa.ESN=bb.ESN 
  and aa.REMD_PART_NUM=bb.REMD_PART_NUM
  and aa.REMD_PART_SERIAL=bb.REMD_PART_SERIAL

您还可以轻松地看到此查询中有3个非常昂贵的排序操作 - 最内层子查询中的一个DISTINCT,然后是另一个子查询中的另一个DISTINCT,最后是顶级查询中的GROUP BY操作(一种DISTINCT)

仅查看您的查询,可以通过这种方式轻松地使用分析函数消除一种类型(DISTINCT):

SELECT * FROM (
    SELECT PLANT,WORK_ORDER_NUM,ESN,REMD_PART_NUM,REMD_PART_SERIAL,
           REMD_PART_IIN, REMD_PART_QTY,
           max( LLP_TRACKD_PART_IND ) over 
              (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL) 
           as LLP_TRACKD_PART_IND,
           max( REMD_PART_TSN )       over 
              (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL) 
           as REMD_PART_TSN,
           max( REMD_PART_CSN )       over 
              (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL) 
           as REMD_PART_CSN,
           row_number() over 
              (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL, REMD_PART_IIN, REMD_PART_QTY 
                   order by PLANT) as Rn
    FROM TABLE1
    WHERE REMD_PART_NUM is not null 
)
WHERE rn = 1

所以最终的查询可能是:

SELECT decode (PLANT ,'ECL','CELMA','EDS','CELMA',PLANT)PLANT,
    COUNT(*) RECORD_COUNT,
    COUNT(DISTINCT OFF.REMD_PART_NUM) REMD_PART_NUM_COUNT,
    COUNT(DISTINCT OFF.REMD_PART_SERIAL) REMD_PART_SER_NUM_COUNT,
    COUNT(DECODE(LLP_TRACKD_PART_IND,'LL',LLP_TRACKD_PART_IND,NULL)) LL_COUNT,
    COUNT(DECODE(LLP_TRACKD_PART_IND,'LR',LLP_TRACKD_PART_IND,NULL)) LR_COUNT,
    COUNT(DECODE(LLP_TRACKD_PART_IND,'TR',LLP_TRACKD_PART_IND,NULL)) TR_COUNT,
    SUM(OFF.REMD_PART_QTY) TOTAL_REMD_PART_QTY, 
    SUM(decode(LLP_TRACKD_PART_IND,null,0,
            CASE
                WHEN REGEXP_LIKE(REMD_PART_TSN, '^-?\d+(\.\d+)?$')
                THEN CAST(REMD_PART_TSN AS NUMBER)
                ELSE 0
            END
        )) TOTAL_TSN,
    SUM(decode(LLP_TRACKD_PART_IND,null,0,
            CASE
                WHEN REGEXP_LIKE(REMD_PART_CSN, '^-?\d+(\.\d+)?$')
                THEN CAST(REMD_PART_CSN AS NUMBER)
                ELSE 0
            END
        )) TOTAL_CSN
FROM (
    SELECT PLANT,WORK_ORDER_NUM,ESN,REMD_PART_NUM,REMD_PART_SERIAL,REMD_PART_IIN, REMD_PART_QTY,
           max( LLP_TRACKD_PART_IND ) over (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL) as LLP_TRACKD_PART_IND,
           max( REMD_PART_TSN )       over (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL) as REMD_PART_TSN,
           max( REMD_PART_CSN )       over (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL) as REMD_PART_CSN,
           row_number()               over (partition by PLANT, WORK_ORDER_NUM, ESN, REMD_PART_NUM, REMD_PART_SERIAL, REMD_PART_IIN, REMD_PART_QTY 
                                            order by PLANT) as Rn
    FROM TABLE1
    WHERE REMD_PART_NUM is not null 
)
WHERE rn = 1
GROUP BY decode (PLANT ,'ECL','CELMA','EDS','CELMA',PLANT)

我觉得这个查询可以进一步优化,但需要深入了解表格结构和业务需求知识。

尽管如此,仍有一些微观优化可能 这种模式:

SUM(decode(LLP_TRACKD_PART_IND,null,0,
        CASE
            WHEN REGEXP_LIKE(REMD_PART_TSN, '^-?\d+(\.\d+)?$')
            THEN CAST(REMD_PART_TSN AS NUMBER)
            ELSE 0
        END
    )) TOTAL_TSN,

可以替换为:

coalesce( 
    SUM( 
        CASE
            WHEN REGEXP_LIKE(REMD_PART_TSN, '^-?\d+(\.\d+)?$')
            THEN CAST(REMD_PART_TSN AS NUMBER)
            ELSE 0
        END
    ), 0
)

由于SUM忽略空值,因此检查每条记录的NULL值是一种浪费。对于少量记录(<1百万)而言并不重要,但对于数以亿计的记录,您可以达到规模效果 - 比如0.05 ms用于检查每条记录乘以10.000.000记录可以给出500秒。