2017-12-07 38 views
1

、私は列 (この場合は、列1.WORK_ORDER_NUM、2.ESN 3.PLANT 4. REMD_PART_NUM 5. REMD_PART_SERIALに基づいて、一つのレコードに2つのレコードを結合する必要があります)。これら5つの列が等しい場合、1つのレコードにするには、他の列の集計関数を使用する必要があります。 この場合、列はLLP_TRACKD_PART_IND、REMD_PART_TSN、 REMD_PART_CSNです。SQL微調整

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

+0

微調整? MySQLまたはOracleを使用していますか? (含まれていない製品にタグを付けないでください) – jarlh

+0

@jarlh Oracleです。 –

+0

これはオラクルです。 @jarlh –

答えて

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つの非常に高価なソート操作があることもわかります。最下位の副問合せに1つのDISTINCT、次に別の副問合せに別のDISTINCT、次に最上位の問合せにGROUP BY操作(DISTINCTの一種)があります。簡単に1つのソート(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 

は、最終的なクエリが可能migh:

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) 

私はこのクエリをさらに最適化できると思っていますが、テーブルの構造と知識が必要ですビジネス要件のge。


ただし、まだ可能なマイクロオプティマイゼーションはあります。
このパターン:

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, 

はこの1に置き換えることができます:

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

SUMはNULL値を無視するので、その後、各レコードにNULL値をチェックすることは無駄です。少数のレコード(< 1百万)の場合、それは問題ではありませんが、数億のレコードに対して、スケールの効果を達成することができます。たとえば、各レコードに10.000.000レコードを掛けたものをチェックすると、

関連する問題