Eu tenho esta consulta:
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;
O problema que estou tendo é que essa consulta demora muito para ser executada. Não sei se é possível executar isso em paralelo, ou seria mais fácil atualizar um cursor em uma função de pipeline.
O que você sugeriria?
Esta é toda a informação que eu acredito que seja relevante.
Este é o plano de execução da seleção interna:
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
Dados da tabela:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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 |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Este é o script da tabela histórica:
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)
);
Esta é a outra tabela:
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
)
A tabela temporária é o resultado de FEE_SCHEDULE_HISTORICAL menos FEE_SCHEDULE
..AND EXISTS (SELECT NULL..
sempre retornaria falso? Isso..AND NOT EXISTS (SELECT 1..
faria mais sentido?SELECT NULL...
é confuso e não deve ser usado (a menos que você esteja usando aUNION
).fee_schedule (universe, fund_id, feetype_name, breakpoint_type, breakpoint_qty, low_breakpoint_amt)
. Talvez umuniverse, fund_id
já esteja bom o suficiente para transformar esse STF em uma verificação de índice.Respostas:
Estou assumindo que sua
FEE_SCHEDULE
tabela é muito menor que aFEE_SCHEDULE_HISTORICAL
tabela, então você pode querer explorarEXISTS
um pouco mais. Mergulhar naFEE_SCHEDULE
tabela linha a linha pode ser uma operação relativamente barata em comparação com a união a todas as linhas naFEE_SCHEDULE_HISTORICAL
.Como a
ETL_FEE_SCH_TMP
tabela é oFEE_SCHEDULE_HISTORICAL
menosFEE_SCHEDULE
, é possível realizar a atualização com apenas algumasEXISTS
instruções, sem todas as junções e poupando o trabalho de criar a tabela temporária. Você realmente não precisa da tabela temporária.Acho que vale a pena dar uma olhada:
Além disso, considere adicionar um índice à
FEE_SCHEDULE
tabela, semelhante ao da tabelaFEE_SCHEDULE_HISTORICAL
. Isso realmente ajuda a explicar o plano.fonte
Você tentou executar o SQL Tuning Advisor para sua instrução? Geralmente encontra índices ausentes, estatísticas, operações caras, etc. Isso é bastante fácil de usar usando o desenvolvedor do SQL, por exemplo. consulte http://www.oracle.com/webfolder/technetwork/tutorials/obe/db/sqldev/r30/TuningAdvisor/TuningAdvisor.htm
fonte