为什么这个查询需要很长时间才能完成?

Why is this query taking a long time to finish?

我有一个功能。当我在我的查询中使用这个函数时,它总是需要很长时间,比如 1 到 2 小时才能完成。这是我的第一个查询...

SELECT GET_DAYSNS_SF(CONTRACT_ID) 
FROM   CONTRACT_TEMP;

和函数...

CREATE OR REPLACE FUNCTION GET_DAYSNS_SF
    (CONTRACT_ID IN NUMBER)
    RETURN DATE
AS
    CONTRACT_ID1 NUMBER(16) := CONTRACT_ID;
    DAYSNS DATE;

BEGIN
  BEGIN
    SELECT MIN(EXPECTED_DT)
    INTO DAYSNS
    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)
    AND CONTRACT_ID = CONTRACT_ID1;
 EXCEPTION 
    WHEN NO_DATA_FOUND THEN
       DAYSNS := NULL;
  END;
  RETURN DAYSNS;
END;

您可以删除条件 AND AMOUNT > 0,因为查询已经有一个类似的条件 AMOUNT > NVL(AMT_MATCHED,0)

简单的答案(很可能是有效的猜测)是 FLOW(CONTRACT_ID) 上的缺失索引。

这导致在每个函数调用中出现 FULL TABLE SCAN

请注意,如果列 CONTRACT_ID 不是很有选择性,您可能需要从函数查询中使用的谓词中添加一些其他列(例如 REVERSAL_STATUS)。

但你可能会做得更好 - 你只需要留下 PL/SQL cursor row by row logik进入SQL方法

这将解决 添加索引后仍然存在的两个额外问题

  • PL/SQL 上下文切换在大量函数调用的情况下成本很高

  • 你用 DIY 实现了一个 OUTER JOIN,这比 Oracle 做的慢得多。

你需要什么 id 来获取 for each contract_id from CONTRACT_TEMP the minimum EXPECTED_DT from FLOW if exists, filtered with the WHERE predicate在函数.

这可以分两步完成:

1) 为每个 CONTRACT_ID 预先计算最小值 EXPECTED_DT - 请参阅下面的子查询。请注意,使用 GROUP BY 您可以一步计算每份合约的结果。

2) LEFT OUTER JOIN table CONTRACT_TEMP 到 1)

的结果

查询 - 相当于您的初始查询:

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