为什么这个查询需要很长时间才能完成?
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
我有一个功能。当我在我的查询中使用这个函数时,它总是需要很长时间,比如 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