来自 Cursor Oracle 的确定性函数调用不起作用
Deterministic function call from Cursor Oracle not working
我创建了一个简单的确定性函数,我在游标中使用 select 查询调用它
如下图
CREATE TABLE TEMP
(dt DATE);
INSERT INTO TEMP
SELECT SYSDATE FROM DUAL CONNECT BY LEVEL<=3;
INSERT INTO TEMP
SELECT SYSDATE+1 FROM DUAL CONNECT BY LEVEL<=3;
COMMIT;
--2 distinct values
SELECT DISTINCT dt from TEMP;
包函数
CREATE OR REPLACE PACKAGE dummy_fun
AUTHID CURRENT_USER
IS
FUNCTION get_data(
p_date IN DATE)
RETURN DATE
DETERMINISTIC;
END dummy_fun;
/
CREATE OR REPLACE PACKAGE BODY dummy_fun
IS
FUNCTION get_data(
p_date IN DATE)
RETURN DATE
DETERMINISTIC
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('get_data with input (p_date=>'||p_date||' called)');
RETURN p_date+1;
END get_data;
END dummy_fun;
/
FUNCTION CALL - 期望 get_data 在 2 个不同的日期仅被调用两次,而如果我仅调用此 SQL,它 运行 仅被调用两次
DECLARE
CURSOR get_date
IS
SELECT dummy_fun.get_data (
dt) from
TEMP;
rec get_date%ROWTYPE;
v_date date;
BEGIN
OPEN get_date;
LOOP
FETCH get_date INTO rec;
EXIT WHEN get_date%NOTFOUND;
NULL;
END LOOP;
CLOSE get_date;
END;
/
输出
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
**经过以下更改,它可以在光标中工作**
CHANGE 1 - IF THE FUNCTION IS CALLED IN THE WHERE CLAUSE
CURSOR get_date
IS
SELECT 1 from
TEMP
WHERE trunc(sysdate+1)= trunc(ae9_common_code.dummy_fun.get_data (
dt))
CHANGE 2 - Kind of Scalar subquery
CURSOR get_date
IS
SELECT * FROM (
SELECT ae9_common_code.dummy_fun.get_data (
dt) from
TEMP
WHERE 1=1)
CHANGE 3 - BULK COLLECT
SELECT ae9_common_code.dummy_fun.get_data (
dt) BULK COLLECT INTO v_dates from
TEMP
WHERE 1=1;
##OUTPUT FOR ALL THE ABOVE CHANGES ARE##
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
简而言之,确定性函数缓存取决于获取大小(数组大小)——结果仅在一次获取调用中缓存,ssc(标量子查询缓存)没有此限制。
请阅读我关于确定性函数的系列文章:
- http://orasql.org/2013/03/13/deterministic-function-vs-scalar-subquery-caching-part-3/
- http://orasql.org/2013/02/11/deterministic-function-vs-scalar-subquery-caching-part-2/
- http://orasql.org/2013/02/10/deterministic-function-vs-scalar-subquery-caching-part-1/
- 还有更多:http://orasql.org/tag/deterministic-functions/
当你有:
open cur;
loop
fetch cur into ...
end loop;
数据库一次只提取一行。正如@SayanMalakshinov 所指出的,数据库不会缓存 deterministic
跨提取的结果。
使用 bulk collect
限制一次获取 1、2 或更多行可能有助于使这一点更清楚:
create or replace procedure fetch_rows ( num_rows int ) as
cursor get_date is
select dummy_fun.get_data ( dt )
from temp;
type rec_tab is table of get_date%rowtype
index by pls_integer;
rws rec_tab;
begin
open get_date;
loop
fetch get_date
bulk collect into rws
limit num_rows;
exit when get_date%notfound;
end loop;
close get_date;
end;
/
exec fetch_rows ( 1 );
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
exec fetch_rows ( 2 );
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
exec fetch_rows ( 3 );
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
限制为 1,每一行都是新的提取,因此没有缓存。将它设置为 2 并且(可能)每隔一行被缓存。最多三个,每次提取最多缓存 2 行,等等。
由于一大堆其他原因,单行提取也很慢,所以实际上你应该考虑使用 bulk collect 无论如何限制至少为 100。
请注意,PL/SQL 引擎优化了 cursor-for 循环以一次获取 100 行,因此您也可以通过这样编写循环来获得缓存效果:
begin
for rws in (
select dummy_fun.get_data ( dt )
from temp
)
loop
null;
end loop;
end;
/
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
我创建了一个简单的确定性函数,我在游标中使用 select 查询调用它 如下图
CREATE TABLE TEMP
(dt DATE);
INSERT INTO TEMP
SELECT SYSDATE FROM DUAL CONNECT BY LEVEL<=3;
INSERT INTO TEMP
SELECT SYSDATE+1 FROM DUAL CONNECT BY LEVEL<=3;
COMMIT;
--2 distinct values
SELECT DISTINCT dt from TEMP;
包函数
CREATE OR REPLACE PACKAGE dummy_fun
AUTHID CURRENT_USER
IS
FUNCTION get_data(
p_date IN DATE)
RETURN DATE
DETERMINISTIC;
END dummy_fun;
/
CREATE OR REPLACE PACKAGE BODY dummy_fun
IS
FUNCTION get_data(
p_date IN DATE)
RETURN DATE
DETERMINISTIC
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('get_data with input (p_date=>'||p_date||' called)');
RETURN p_date+1;
END get_data;
END dummy_fun;
/
FUNCTION CALL - 期望 get_data 在 2 个不同的日期仅被调用两次,而如果我仅调用此 SQL,它 运行 仅被调用两次
DECLARE
CURSOR get_date
IS
SELECT dummy_fun.get_data (
dt) from
TEMP;
rec get_date%ROWTYPE;
v_date date;
BEGIN
OPEN get_date;
LOOP
FETCH get_date INTO rec;
EXIT WHEN get_date%NOTFOUND;
NULL;
END LOOP;
CLOSE get_date;
END;
/
输出
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
**经过以下更改,它可以在光标中工作**
CHANGE 1 - IF THE FUNCTION IS CALLED IN THE WHERE CLAUSE
CURSOR get_date
IS
SELECT 1 from
TEMP
WHERE trunc(sysdate+1)= trunc(ae9_common_code.dummy_fun.get_data (
dt))
CHANGE 2 - Kind of Scalar subquery
CURSOR get_date
IS
SELECT * FROM (
SELECT ae9_common_code.dummy_fun.get_data (
dt) from
TEMP
WHERE 1=1)
CHANGE 3 - BULK COLLECT
SELECT ae9_common_code.dummy_fun.get_data (
dt) BULK COLLECT INTO v_dates from
TEMP
WHERE 1=1;
##OUTPUT FOR ALL THE ABOVE CHANGES ARE##
get_data with input (p_date=>14-APR-21 called)
get_data with input (p_date=>24-APR-21 called)
简而言之,确定性函数缓存取决于获取大小(数组大小)——结果仅在一次获取调用中缓存,ssc(标量子查询缓存)没有此限制。
请阅读我关于确定性函数的系列文章:
- http://orasql.org/2013/03/13/deterministic-function-vs-scalar-subquery-caching-part-3/
- http://orasql.org/2013/02/11/deterministic-function-vs-scalar-subquery-caching-part-2/
- http://orasql.org/2013/02/10/deterministic-function-vs-scalar-subquery-caching-part-1/
- 还有更多:http://orasql.org/tag/deterministic-functions/
当你有:
open cur;
loop
fetch cur into ...
end loop;
数据库一次只提取一行。正如@SayanMalakshinov 所指出的,数据库不会缓存 deterministic
跨提取的结果。
使用 bulk collect
限制一次获取 1、2 或更多行可能有助于使这一点更清楚:
create or replace procedure fetch_rows ( num_rows int ) as
cursor get_date is
select dummy_fun.get_data ( dt )
from temp;
type rec_tab is table of get_date%rowtype
index by pls_integer;
rws rec_tab;
begin
open get_date;
loop
fetch get_date
bulk collect into rws
limit num_rows;
exit when get_date%notfound;
end loop;
close get_date;
end;
/
exec fetch_rows ( 1 );
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
exec fetch_rows ( 2 );
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
exec fetch_rows ( 3 );
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)
限制为 1,每一行都是新的提取,因此没有缓存。将它设置为 2 并且(可能)每隔一行被缓存。最多三个,每次提取最多缓存 2 行,等等。
由于一大堆其他原因,单行提取也很慢,所以实际上你应该考虑使用 bulk collect 无论如何限制至少为 100。
请注意,PL/SQL 引擎优化了 cursor-for 循环以一次获取 100 行,因此您也可以通过这样编写循环来获得缓存效果:
begin
for rws in (
select dummy_fun.get_data ( dt )
from temp
)
loop
null;
end loop;
end;
/
get_data with input (p_date=>14-APR-2021 10:32:36 called)
get_data with input (p_date=>15-APR-2021 10:32:36 called)