Oracleの更新をより高速に実行するように変更する方法は?


8

私はこのクエリを持っています:

UPDATE   (
    SELECT   h.valid_through_dt, h.LAST_UPDATE_TMSTMP
    FROM   ETL_FEE_SCH_TMP d, FEE_SCHEDULE_HISTORICAL h
    WHERE       h.FUND_ID = d.FUND_ID
    AND h.FEETYPE_NAME = d.FEETYPE_NAME
    AND h.BREAKPOINT_TYPE = d.BREAKPOINT_TYPE
    AND h.BREAKPOINT_QTY = d.BREAKPOINT_QTY
    AND h.LOW_BREAKPOINT_AMT = d.LOW_BREAKPOINT_AMT
    AND h.VALID_THROUGH = TO_DATE ('31-DEC-9999', 'dd-mon-yyyy')
    AND h.universe = 'DC'
    AND h.universe = d.universe
    AND EXISTS
    (
        SELECT 1
        FROM FEE_SCHEDULE s
        WHERE s.FUND_ID = h.FUND_ID
        AND s.FEETYPE_NAME = h.FEETYPE_NAME
        AND s.BREAKPOINT_TYPE = h.BREAKPOINT_TYPE
        AND s.BREAKPOINT_QTY = h.BREAKPOINT_QTY
        AND s.LOW_BREAKPOINT_AMT = h.LOW_BREAKPOINT_AMT
        AND s.universe = 'DC'
    )
) updateTable
SET     updateTable.VALID_THROUGH = (SYSDATE - 1),
updateTable.LAST_UPDATE_TMSTMP = SYSTIMESTAMP;

私が抱えている問題は、このクエリの実行に長い時間がかかることです。これを並列で実行できるかどうか、パイプライン関数でカーソルを更新する方が簡単かどうかはわかりません。

あなたは何を提案しますか?

これは関連があると私が思うすべての情報です。

これは、内部選択の実行計画です。

Execution Plan
----------------------------------------------------------
Plan hash value: 57376096
---------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                     | Rows  | Bytes| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                          |     1 |   306 |  8427   (1)| 00:01:42 |
|   1 |  NESTED LOOPS                |                          |       |       |            |          |
|   2 |   NESTED LOOPS               |                          |     1 |    306|  8427   (1)| 00:01:42 |
|   3 |    MERGE JOIN CARTESIAN      |                          |     1 |    192|  8426   (1)| 00:01:42 |
|*  4 |     INDEX RANGE SCAN         | SYS_C000666              |     1 |     96|     2   (0)| 00:00:01 |
|   5 |     BUFFER SORT              |                          |  3045K|   278M|  8425   (1)| 00:01:42 |
|   6 |      SORT UNIQUE             |                          |  3045K|   278M|  8425   (1)| 00:01:42 |
|*  7 |       TABLE ACCESS FULL      | FEE_SCHEDULE             |  3045K|   278M|  8425   (1)| 00:01:42 |
|*  8 |    INDEX RANGE SCAN          | FEE_SCHDL_IDX1           |     1 |       |     1   (0)| 00:00:01 |
|*  9 |   TABLE ACCESS BY INDEX ROWID| FEE_SCHEDULE_HISTORICAL  |     1 |   114 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("D"."UNIVERSE"='DC')
   7 - filter("S"."UNIVERSE"='DC')
   8 - access("H"."UNIVERSE"='DC' AND "S"."FUND_ID"="H"."FUND_ID" AND
              "S"."FEETYPE_NAME"="H"."FEETYPE_NAME" AND
              "S"."BREAKPOINT_TYPE"="H"."BREAKPOINT_TYPE" AND
              "S"."BREAKPOINT_QTY"="H"."BREAKPOINT_QTY" AND
              "S"."LOW_BREAKPOINT_AMT"="H"."LOW_BREAKPOINT_AMT")
       filter("H"."FUND_ID"="D"."FUND_ID" AND
              "H"."FEETYPE_NAME"="D"."FEETYPE_NAME" AND
              "H"."BREAKPOINT_TYPE"="D"."BREAKPOINT_UNIT_TY

テーブルデータ:

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
UNIVERSE|FUND_ID   |FEETYPE_NAME |BREAKPOINT_TYPE|BREAKPOINT_QTY|LOW_BREAKPOINT_AMT|HIGH_BREAKPOINT_AMT|FEE_PCT|FEE_SCHDL_SEQ_ID|GROUP_ID|LAST_UPDATE_TMSTMP  |VALID_FROM|VALID_THROUGH|INSERT_TMSTMP        |JOB_ID|
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DC      |DC9ZTPLPHO|DeferLoad    |Percentage     |4             |10000             |300000             |3.14   |780250          |null    |1/4/2012  3:59:54 PM|6/23/2012 |12/31/9999   |1/5/2011   3:59:54 PM|666   |
DC      |DCE86Y8XFU|RedemptionFee|Percentage     |9             |  100             |100500             |7.67   |780251          |null    |6/4/2012  4:49:54 PM|11/12/2011|12/31/9999   |8/17/2011  2:00:54 PM|666   |
DC      |DCAYL0KONA|FrontLoad    |Percentage     |2             |50000             |601500             |5.00   |780252          |null    |4/25/2012 4:49:54 PM|8/2/2012  |12/31/9999   |12/19/2012 9:59:00 PM|666   |
DC      |DC9ZTPLPHO|DeferLoad    |Percentage     |7             |80000             |900000             |2.24   |780252          |null    |4/25/2012 4:49:54 PM|8/2/2012  |12/31/9999   |12/19/2012 9:59:00 PM|666   |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

これは、履歴テーブルのスクリプトです。

CREATE TABLE FEE_SCHEDULE_HISTORICAL
(
  UNIVERSE                        VARCHAR2(2 BYTE) NOT NULL,
  FUND_ID                         VARCHAR2(10 BYTE) NOT NULL,
  FEETYPE_NAME                    VARCHAR2(75 BYTE),
  BREAKPOINT_TYPE                 VARCHAR2(50 BYTE),
  BREAKPOINT_QTY                  VARCHAR2(10 BYTE),
  LOW_BREAKPOINT_AMT              NUMBER(19,6),
  HIGH_BREAKPOINT_AMT             NUMBER(19,6),
  FEE_PCT                         NUMBER(19,6),
  FEE_SCHDL_SEQ_ID                NUMBER        NOT NULL,
  GROUP_ID                        NUMBER,
  LAST_UPDATE_TMSTMP              DATE          NOT NULL,
  VALID_FROM                      DATE          NOT NULL,
  VALID_THROUGH                   DATE          NOT NULL,
  INSERT_TMSTMP                   DATE          NOT NULL,
  JOB_ID                          NUMBER        NOT NULL
);

CREATE UNIQUE INDEX FEE_SCHDL_PK ON FEE_SCHEDULE_HISTORICAL(FEE_SCHDL_SEQ_ID);

CREATE UNIQUE INDEX FEE_SCHDL_HST_IDX ON FEE_SCHEDULE_HISTORICAL (
    UNIVERSE,
    FUND_ID,
    FEETYPE_NAME,
    BREAKPOINT_TYPE,
    BREAKPOINT_QTY, 
    LOW_BREAKPOINT_AMT,
    VALID_FROM,
    JOB_ID
)

CREATE INDEX FEE_SCHEDULE_HST_IDX2 ON FEE_SCHEDULE_HISTORICAL(LAST_UPDATE_TMSTMP)

CREATE INDEX FEE_SCHEDULE_HST_IDX3 ON FEE_SCHEDULE_HISTORICAL(VALID_THROUGH)

ALTER TABLE FEE_SCHEDULE_HISTORICAL ADD (
    CONSTRAINT FEE_SCHDL_PK
    PRIMARY KEY
    (FEE_SCHDL_SEQ_ID)
);

これは他のテーブルです:

CREATE TABLE FEE_SCHEDULE
(
  UNIVERSE                        VARCHAR2(2 BYTE) NOT NULL,
  FUND_ID                         VARCHAR2(10 BYTE) NOT NULL,
  FEETYPE_NAME                    VARCHAR2(75 BYTE),
  BREAKPOINT_TYPE                 VARCHAR2(50 BYTE),
  BREAKPOINT_QTY                  VARCHAR2(10 BYTE),
  LOW_BREAKPOINT_AMT              NUMBER(19,6),
  HIGH_BREAKPOINT_AMT             NUMBER(19,6),
  FEE_PCT                         NUMBER(19,6),
  JOB_RUN_ID                      NUMBER        NOT NULL,
  FILE_DATE                       DATE          NOT NULL,
  CYCLE_DATE                      DATE          NOT NULL
)

一時テーブルは、FEE_SCHEDULE_HISTORICALからFEE_SCHEDULEを引いた結果です。


これは本当にDBAスタックにあるはずです。
2012年

..AND EXISTS (SELECT NULL..常にfalseを返すとは限りませんか?これは- ..AND NOT EXISTS (SELECT 1..より意味がありますか?
AnBisw 2012年

2
@Annjawnこんにちは。このforums.oracle.com/forums/thread.jspa?threadID=353014によると、NULLまたは1は「シンボリック」名のみです(副選択以外では使用されません)。

はい、そうです。私はそれを認識しています。しかし、それは私が尋ねたものではありませんか?SELECT NULL...わかりにくいので、使用しないでください(を使用している場合を除くUNION)。
AnBisw 2012年

3
あなたは上のインデックスを追加しようとしましたfee_schedule (universe, fund_id, feetype_name, breakpoint_type, breakpoint_qty, low_breakpoint_amt)。たぶん、1つuniverse, fund_id はそのFTSをインデックススキャンに変えるのにすでに十分です。
a_horse_with_no_name 2012年

回答:


2

私はあなたのFEE_SCHEDULEテーブルがテーブルよりもずっと小さいと仮定しているFEE_SCHEDULE_HISTORICALので、あなたはEXISTSもう少し活用したいと思うかもしれません。FEE_SCHEDULE行ごとにテーブルにディップすることは、テーブルをのすべての行に結合することに比べて、比較的安価な操作FEE_SCHEDULE_HISTORICALです。

ETL_FEE_SCH_TMPテーブルはFEE_SCHEDULE_HISTORICALマイナスなので、すべての結合を行わずに一時テーブルを作成する手間を省いて、FEE_SCHEDULEわずか2つのEXISTSステートメントで実際に更新を実行できます。一時テーブルは本当に必要ありません。

これは一見の価値があると思います:

update FEE_SCHEDULE_HISTORICAL H
set H.VALID_THROUGH = (sysdate - 1), H.LAST_UPDATE_TMSTMP = SYSTIMESTAMP
where 
    H.VALID_THROUGH = TO_DATE ('31-DEC-9999', 'dd-mon-yyyy')
    AND H.universe = 'DC'
    AND NOT EXISTS
    (
    SELECT 1
        FROM FEE_SCHEDULE F
        WHERE 
            F.universe = H.Universe
            AND F.FUND_ID = H.FUND_ID
            AND F.FEETYPE_NAME = H.FEETYPE_NAME
            AND F.BREAKPOINT_TYPE = H.BREAKPOINT_TYPE
            AND F.BREAKPOINT_QTY = H.BREAKPOINT_QTY
            AND F.LOW_BREAKPOINT_AMT = H.LOW_BREAKPOINT_AMT
            AND F.HIGH_BREAKPOINT_AMT = H.HIGH_BREAKPOINT_AMT
            AND F.FEE_PCT = H.FEE_PCT
    )
    AND EXISTS
        (
        SELECT 1
        FROM FEE_SCHEDULE FF
        WHERE 
            FF.universe = 'DC'
            AND FF.FUND_ID = h.FUND_ID
            AND FF.FEETYPE_NAME = h.FEETYPE_NAME
            AND FF.BREAKPOINT_TYPE = h.BREAKPOINT_TYPE
            AND FF.BREAKPOINT_QTY = h.BREAKPOINT_QTY
            AND FF.LOW_BREAKPOINT_AMT = h.LOW_BREAKPOINT_AMT
  )

また、のインデックスとFEE_SCHEDULE同様に、テーブルにインデックスを追加することを検討してくださいFEE_SCHEDULE_HISTORICAL。これは、説明の計画に役立ちます。

CREATE UNIQUE INDEX FEE_SCHDL_IDX ON FEE_SCHEDULE (
    UNIVERSE,
    FUND_ID,
    FEETYPE_NAME,
    BREAKPOINT_TYPE,
    BREAKPOINT_QTY, 
    LOW_BREAKPOINT_AMT
);

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.