【发布时间】:2017-01-17 10:24:41
【问题描述】:
我在 PL/SQL 中编写了一个函数,它使用一些参数调用 Web 服务,解析答案并返回一个值。效果很好。
但是,有时响应可能会很慢。由于参数通常位于所有可能值的一个很小的子集中,因此我想到了将答案缓存在表格中。 该函数如下所示
CREATE OR REPLACE FUNCTION myfct(p1 IN VARCHAR2, p2 IN VARCHAR2)
RETURN VARCHAR2
IS
cache_hit NUMBER ;
res VARCHAR2(200) ;
BEGIN
SELECT COUNT(*) INTO cache_hit FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;
IF( cache_hit = 1 )
THEN
SELECT MYCACHE.result INTO res FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;
RETURN res ;
END IF ;
-- complex operations
res := p1 || p2 ;
INSERT INTO MYCACHE(param1, param2, result) VALUES(p1, p2, res) ;
RETURN res ;
END ;
当我尝试这个功能时:
SELECT myfct('ABC', 'DEF') FROM DUAL ;
我得到了错误:
ORA-14551: cannot perform a DML operation inside a query
试图将 DML 部分包装在一个过程中并在函数中调用此过程没有帮助
我找到了 PRAGMA AUTONOMOUS_TRANSACTION 和 COMMIT 的解决方法:
CREATE OR REPLACE FUNCTION myfct(p1 IN VARCHAR2, p2 IN VARCHAR2)
RETURN VARCHAR2
IS
PRAGMA AUTONOMOUS_TRANSACTION;
cache_hit NUMBER ;
res VARCHAR2(200) ;
BEGIN
SELECT COUNT(*) INTO cache_hit FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;
IF( cache_hit = 1 )
THEN
SELECT MYCACHE.result INTO res FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;
RETURN res ;
END IF ;
-- complex operations
res := p1 || p2 ;
INSERT INTO MYCACHE(param1, param2, result) VALUES(p1, p2, res) ;
COMMIT ;
RETURN res ;
END ;
但我想知道这是否真的是个好主意。提到这种解决方法的人说这可能很危险,但没有说明具体原因。
我的函数是 PRAGMA AUTONOMOUS_TRANSACTION 的一个很好用的例子,还是有更好更安全的方法来做我想做的事?
【问题讨论】:
-
如果您在 PL/SQL 中将 select 与您的函数一起使用可能会更好地将结果保存到某个全局集合中,然后使用 forall 将值插入表中。
-
我考虑过,但是对于所有可能的组合,我们将有几百万行要存储,并且我们计划定期仅使用约 10 000 个组合。这种带有缓存表的混合解决方案允许我们回答任何组合,但只存储最相关的组合。
-
是否可以使结果保持最新?如果您的复杂选择的基础数据发生变化,会发生什么?也许您可以通过
materialized view解决您的性能问题?