2016-11-29 7 views
0

約700,000件のレコードがあるテーブルに対して一括更新を実行しようとしています。実効開始日を前のレコードの有効終了日で更新する必要があります。サブクエリを使用しているときに、更新ステートメントのパフォーマンスに問題があります。日付(7/1/2016-7/15/2016、約2kレコード)のフィルターでも1時間以上実行されます。私は単純な更新ステートメントとして、挿入として、そしてループで試しました。 account_dim_key(テーブルのPK)の代わりにROWIDを使用するEXPLAIN PLANははるかに最適ですが、サブクエリが複数の行を返すというエラーが発生します。なぜ私はROWIDでそれが起こっているのか分かりません。一括更新の開始日は前の終了日を基準にします

IDは、テーブル上の自然なキーですが、account_dim_keyはPKで一意です。両方とも索引付けされます。表はタイプ2のSCDです。私は

  • が、FORALLの更新を使用する方が最適だろうもしそうなら、私は書くでしょうかROWID
  • を使用して更新ステートメントを変更するにはどうすればよい

    1. その
    (アレイとSQLとunfamliarをPLに新しいです)エラー単一行サブクエリを返すROWIDを使用して

    UPDATEステートメントは、複数の行を返すが、最適とNとacocunt_dim_key使用

    UPDATE DEXWHS.D_ACCOUNT_VEEVA 
        SET effective_end_dt = 
          (SELECT prev_dt 
          FROM (SELECT LAG (
              effective_end_dt, 
              1, 
              effective_start_dt) 
              OVER (PARTITION BY account_dim_key 
               ORDER BY effective_start_dt) 
              AS prev_dt, 
              ROWID AS rid 
            FROM dexwhs.d_account_veeva ac2) a 
          WHERE a.rid = ROWID) 
    

    UPDATEステートメントプラン説明しますaccount_dim_keyが主キーである場合に最適な、それは全体のテーブルを更新しているので、クエリはいくつかの時間を取る必要がありますMERGE

    MERGE INTO dexwhs.d_account_veeva a 
    USING (
        SELECT account_dim_key, 
          LAG (effective_end_dt, 1, effective_start_dt) 
          OVER (PARTITION BY account_dim_key 
           ORDER BY effective_start_dt) 
          AS prev_dt 
        FROM dexwhs.d_account_veeva 
    ) b 
    ON (a.account_dim_key = b.account_dim_key) 
    WHEN MATCHED THEN UPDATE SET a.effective_end_dt = b.prev_dt 
    

    を試し、その後、ループ

    CREATE OR REPLACE PROCEDURE PREV_UPDT 
    IS 
        CURSOR c1 
        IS 
         SELECT account_dim_key, 
           id, 
           active_flag, 
           effective_end_dt, 
           effective_start_dt, 
           created_date, 
           last_modified_date, 
           (SELECT prev_dt 
            FROM (SELECT LAG (
                effective_end_dt, 
                1, 
                effective_start_dt) 
               OVER (
                PARTITION BY id 
                ORDER BY effective_start_dt, account_dim_key) 
                AS prev_dt, 
               account_dim_key AS rid 
              FROM dexwhs.d_account_veeva ac2) a 
           WHERE a.rid = src.account_dim_key) 
          FROM dexwhs.d_account_veeva src 
         ORDER BY id, effective_start_dt, account_dim_key; 
        r1 c1%ROWTYPE; 
    BEGIN 
        OPEN c1; 
    
        LOOP 
         FETCH c1 INTO r1; 
    
         EXIT WHEN c1%NOTFOUND; 
         DBMS_OUTPUT.PUT_LINE ('id=' || r1.id); 
    
         UPDATE dexwhs.D_ACCOUNT_VEEVA trgt 
         SET trgt.effective_start_dt = r1.prev_date, 
          trgt.audit_last_update_dt = SYSDATE, 
         WHERE trgt.account_dim_key = r1.account_dim_key; 
    
         DBMS_OUTPUT.PUT_LINE ('r1.id_found'); 
        END LOOP; 
    
        CLOSE c1; 
    END 
    

    答えて

    0

    と計画

    UPDATE DEXWHS.D_ACCOUNT_VEEVA 
        SET effective_end_dt = 
          (SELECT prev_dt 
          FROM (SELECT LAG (
              effective_end_dt, 
              1, 
              effective_start_dt) 
              OVER (PARTITION BY id 
               ORDER BY effective_start_dt, account_dim_key) 
              AS prev_dt, 
              account_dim_key AS rid 
            FROM dexwhs.d_account_veeva ac2) a 
          WHERE a.rid = account_dim_key) 
    

    アップデートを説明OT 。

    おそらくLAG ... (PARTITION BY account_dim_key ORDER BY effective_start_dt)の部分を(account_dim_key, effective_start_dt)列の複合インデックスを使用して高速化することができます。

    ただし、Oracleはこの索引を無視して、副問合せが表全体に対して行われるため、全表スキャンを優先します。

    関連する問題