如何在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堆栈上。
pst 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)。也许universe, fund_id 已经足够好,可以将FTS转换为索引扫描。
a_horse_with_no_name 2012年

Answers:


2

我假设您的FEE_SCHEDULE表比FEE_SCHEDULE_HISTORICAL表小得多,因此您可能想多利用EXISTS一些表。FEE_SCHEDULE与将其连接到中的所有行相比,逐行浸入表中可能是相对便宜的操作FEE_SCHEDULE_HISTORICAL

由于该ETL_FEE_SCH_TMP表是FEE_SCHEDULE_HISTORICAL减号FEE_SCHEDULE,因此您实际上只需执行几条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
);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.