The trivial answer (very probably valid guess) is a missing index on FLOW(CONTRACT_ID)
.
This leads to a FULL TABLE SCAN
in each function call.
Note, that in case the column CONTRACT_ID
is not very selective, you may need to add some other column from the predicated used in the query in the function (e.g. REVERSAL_STATUS
).
But you may do even better - you need only to left behind the PL/SQL cursor row by row logik and enter the SQL approach.
This will solve the two additional problems that remains after adding the index:
PL/SQL context swich is costly in case of large number of function calls
You implemented an OUTER JOIN with DIY
matter, which is far slower that done by Oracle.
What you need id to get for each contract_id
from CONTRACT_TEMP
the minimum EXPECTED_DT
from FLOW
if exists, filtered with the WHERE predicate in the function.
This can be done in two steps:
1) Precalculate for each CONTRACT_ID
the minimum EXPECTED_DT
- see subquery below. Note, that using GROUP BY
you calculates the result for each contract in one step.
2) LEFT OUTER JOIN
the table CONTRACT_TEMP
to the result of 1)
The query - that is equivalent to yours initial query:
SELECT f.EXPECTED_DT
FROM CONTRACT_TEMP c
LEFT OUTER JOIN
(SELECT CONTRACT_ID, MIN(EXPECTED_DT) EXPECTED_DT
FROM FLOW
WHERE REVERSAL_STATUS = 4200
AND FLOW_TYPE IN(1003,1006,1027)
AND IS_CASH = 1
AND AMOUNT > 0
AND AMOUNT > NVL(AMT_MATCHED,0)
GROUP BY CONTRACT_ID) f
on c.CONTRACT_ID = f.CONTRACT_ID