Oracle函数的优化
Optimization of Oracle function
我在oracle数据库中写了一个函数,计算saldo,找到运行的日期。
运作方式如下:
- 他会收到
- 开始从 vSumm 中减去 TURNOVER_DEBIT 列的第一个单元格并保存。
- 然后,从保存的数字中,再次减去下一个单元格
- 依此类推,直到vSumm小于等于0。
- 当 vSumm <= 0 时,它会抓取并 return OPER_DAY 记录。
用了 20 多分钟。因为每个客户的平均 saldo 记录是 70-80 并且它正在循环 140 000 个客户。
如何优化我的查询?任何帮助将非常感激!谢谢。
create function get_date_overdue
(iAccount varchar2, iSaldo number, iDate date := get_operday())
return date
is
version CONSTANT char(14) := '->>26112020<<-';
vDate date;
vSumm number(22) := iSaldo;
vSign integer := 0;
begin
for r in (
select --+ index_desc(s UK_SALDO_ACCOUNT_DAY)
*
from ibs.Saldo@iabs s
where s.ACCOUNT_CODE = iAccount
and s.OPER_DAY between date '2015-01-01' and iDate
) loop
vSumm := vSumm - r.TURNOVER_DEBIT;
if vSign = 0 and vSumm <= 0 then
vDate := r.OPER_DAY;
vSign := 1;
end if;
EXIT WHEN vSign = 1;
end loop;
return vDate;
exception
when NO_DATA_FOUND then return null;
end;
您可以使用单个查询来获取具有上述要求的 OPER_DAY
,然后从函数中 return 获取它,如下所示:
SELECT OPER_DAY INTO vDate
FROM (SELECT SUM(S.TURNOVER_DEBIT)
OVER(ORDER BY OPER_DAY DESC NULLS LAST) AS SUM_TURNOVER_DEBIT,
OPER_DAY
FROM IBS.SALDO@IABS S
WHERE S.ACCOUNT_CODE = IACCOUNT
AND S.OPER_DAY BETWEEN DATE '2015-01-01' AND IDATE)
WHERE SUM_TURNOVER_DEBIT >= ISALDO
ORDER BY OPER_DAY DESC
FETCH FIRST ROW ONLY;
在这里,我考虑到您想从最高 OPER_DAY
扫描到最低 OPER_DAY
以对 TURNOVER_DEBIT
求和,一旦 TURNOVER_DEBIT
的总和相等或超过 ISALDO
,扫描应该停止,您必须 return OPER_DAY
.
与遍历 table 的每条记录相比,单个查询可以更快地给出结果,进行一些计算,然后根据该计算做出决定。
我在oracle数据库中写了一个函数,计算saldo,找到运行的日期。 运作方式如下:
- 他会收到
- 开始从 vSumm 中减去 TURNOVER_DEBIT 列的第一个单元格并保存。
- 然后,从保存的数字中,再次减去下一个单元格
- 依此类推,直到vSumm小于等于0。
- 当 vSumm <= 0 时,它会抓取并 return OPER_DAY 记录。
用了 20 多分钟。因为每个客户的平均 saldo 记录是 70-80 并且它正在循环 140 000 个客户。
如何优化我的查询?任何帮助将非常感激!谢谢。
create function get_date_overdue
(iAccount varchar2, iSaldo number, iDate date := get_operday())
return date
is
version CONSTANT char(14) := '->>26112020<<-';
vDate date;
vSumm number(22) := iSaldo;
vSign integer := 0;
begin
for r in (
select --+ index_desc(s UK_SALDO_ACCOUNT_DAY)
*
from ibs.Saldo@iabs s
where s.ACCOUNT_CODE = iAccount
and s.OPER_DAY between date '2015-01-01' and iDate
) loop
vSumm := vSumm - r.TURNOVER_DEBIT;
if vSign = 0 and vSumm <= 0 then
vDate := r.OPER_DAY;
vSign := 1;
end if;
EXIT WHEN vSign = 1;
end loop;
return vDate;
exception
when NO_DATA_FOUND then return null;
end;
您可以使用单个查询来获取具有上述要求的 OPER_DAY
,然后从函数中 return 获取它,如下所示:
SELECT OPER_DAY INTO vDate
FROM (SELECT SUM(S.TURNOVER_DEBIT)
OVER(ORDER BY OPER_DAY DESC NULLS LAST) AS SUM_TURNOVER_DEBIT,
OPER_DAY
FROM IBS.SALDO@IABS S
WHERE S.ACCOUNT_CODE = IACCOUNT
AND S.OPER_DAY BETWEEN DATE '2015-01-01' AND IDATE)
WHERE SUM_TURNOVER_DEBIT >= ISALDO
ORDER BY OPER_DAY DESC
FETCH FIRST ROW ONLY;
在这里,我考虑到您想从最高 OPER_DAY
扫描到最低 OPER_DAY
以对 TURNOVER_DEBIT
求和,一旦 TURNOVER_DEBIT
的总和相等或超过 ISALDO
,扫描应该停止,您必须 return OPER_DAY
.
与遍历 table 的每条记录相比,单个查询可以更快地给出结果,进行一些计算,然后根据该计算做出决定。