考虑确定性函数,如:
CREATE OR REPLACE FUNCTION SCHEMA.GET_NAME(ss_id nvarchar2
) RETURN nvarchar2 DETERMINISTIC IS
tmpVar nvarchar2(500);
BEGIN
select name into tmpvar from logistics.organization_items
where id = ss_id ;
return tmpvar ;
END ss_name;
使用Toad我调用SCHEMA.GET_NAME(1)
并返回A
。然后,我将表格中的值从A
更改为B
,并回顾SCHEMA.GET_NAME(1)
返回的B
。
这是一个好结果。但是我害怕根据this page in the documentation没有更新的价值,{{3}}说:
当Oracle数据库在其中一个上下文中遇到确定性函数时,它会尝试在可能的情况下使用先前计算的结果,而不是重新执行该函数。如果随后更改了函数的语义,则必须手动重建所有依赖于函数的索引和物化视图。
GET_NAME(1)
的值在什么情况下会返回旧的缓存值(A
而不是B
)?
答案 0 :(得分:6)
如果您从表中选择,那么您的函数结果不确定性。给定相同的初始条件,deterministic system是始终生成相同输出的那个。
可以更改表中的信息,因此从表中选择的函数不是确定性的。引用PL/SQL Language Reference:
不要指定此子句来定义使用包变量的函数,或以任何可能影响函数返回结果的方式访问数据库的函数。如果数据库选择不重新执行该功能,则不会捕获这样做的结果。
换句话说,Oracle并不保证函数的结果是准确的(它们可能就是这样)。如果你的表是静态的,并且不太可能改变,那么它应该没问题,但这不是我想要依赖的东西。要回答您的问题,请不要假设Oracle将在同一事务/会话中返回除缓存值以外的任何内容。
如果你需要加快速度,有两种方法。首先,检查您是否有ID
的索引!
只需加入此表即可。如果你的功能只是这个,那么就不需要存在这个功能。
使用scalar sub-query caching(不一定可能,但值得一试)。
select ( select get_name(:id) from dual )
from your_table
Oracle将创建函数结果的内存中散列,就像结果缓存一样。如果您多次执行相同的功能,那么Oracle将点击缓存而不是功能。
答案 1 :(得分:1)
Ben的答案很好地总结了,我想补充说你在函数中使用DETERMINISTIC
关键字的方式不对 - 保持你从表中读取值然后返回与用户相同。
在您通过固定输入计算表达式的情况下,应使用确定性函数,例如,当您需要返回子字符串或输入字符串的大写/小写时。以编程方式,您知道对于相同的输入,小写函数将始终返回相同的值,因此您希望缓存结果(使用确定性关键字)。
当你从表中读取一个值时,Oracle无法知道列中的值没有改变,因此它更喜欢重新执行该函数而不依赖于缓存的结果(这是有意义的)
答案 2 :(得分:0)
您可以在函数中添加时间戳参数吗?然后将sysdate传递给你调用它的函数。
这样,您可以有效地缓存结果,并且当它通常在给定事务中返回相同的值时,可以避免反复运行该函数。
答案 3 :(得分:0)
Erez的评论是我一直在寻找的答案。 在执行查询或plsql-unit之前,您可以使用此解决方案强制在重新设置函数的ret值后再次执行该函数(例如,更改包var)。 我用它来: 选择 ... 来自big_table_vw;
,其中
创建视图big_table_vw 如 选择...(分析功能) 来自big_table 其中last_mutated> = get_date();
在我的例子中,big_table_vw包含阻止Oracle将谓词推入视图的窗口函数。
答案 4 :(得分:0)
这是对一个长期回答的问题的后续跟进,但我只想补充一点,Oracle确实为具有可变依赖性的函数提供了缓存机制。 RESULT_CACHE
是DETERMINISTIC
的替代方法,允许Oracle在修改引用对象时放弃缓存的函数结果。
通过这种方式,人们可以对很少更新的对象缓存昂贵的计算,并确信缓存的结果不会返回错误的结果。
这是一个使用神话怪物的例子:
CREATE TABLE MONSTER (
MONSTER_NAME VARCHAR2(100) NOT NULL PRIMARY KEY
);
INSERT INTO MONSTER VALUES ('Chthulu');
INSERT INTO MONSTER VALUES ('Grendel');
INSERT INTO MONSTER VALUES ('Scylla');
INSERT INTO MONSTER VALUES ('Nue');
COMMIT;
CREATE OR REPLACE PACKAGE MONSTER_PKG
IS
FUNCTION IS_THIS_A_MONSTER(P_MONSTER_NAME IN VARCHAR2)
RETURN BOOLEAN RESULT_CACHE;
END MONSTER_PKG;
/
CREATE OR REPLACE PACKAGE BODY MONSTER_PKG
IS
FUNCTION IS_THIS_A_MONSTER(P_MONSTER_NAME IN VARCHAR2)
RETURN BOOLEAN
RESULT_CACHE RELIES_ON (MONSTER)
IS
V_MONSTER_COUNT NUMBER(1, 0) := 0;
BEGIN
SELECT COUNT(*)
INTO V_MONSTER_COUNT
FROM MONSTER
WHERE MONSTER_NAME = P_MONSTER_NAME;
RETURN (V_MONSTER_COUNT > 0);
END;
END MONSTER_PKG;
/
当出现如下情况时,任何现有缓存都将失效,然后可以重建新缓存。
BEGIN
DBMS_OUTPUT.PUT_LINE('Is Kraken initially a monster?');
IF MONSTER_PKG.IS_THIS_A_MONSTER('Kraken')
THEN
DBMS_OUTPUT.PUT_LINE('Kraken is initially a monster');
ELSE
DBMS_OUTPUT.PUT_LINE('Kraken is not initially a monster');
END IF;
INSERT INTO MONSTER VALUES ('Kraken');
COMMIT;
DBMS_OUTPUT.PUT_LINE('Is Kraken a monster after update?');
IF MONSTER_PKG.IS_THIS_A_MONSTER('Kraken')
THEN
DBMS_OUTPUT.PUT_LINE('Kraken is now a monster');
ELSE
DBMS_OUTPUT.PUT_LINE('Kraken is not now a monster');
END IF;
END;
/
Kraken最初是怪物吗? 海妖最初不是怪物 更新后Kraken是怪物吗? 海妖现在是一个怪物