我们有售货亭供客户查看两种不同类别商品的购买量。他们将输入他们的手机号码,它会将OTP发送到他们的手机号码,他们会将其输入以进行身份验证,系统必须检查数据并显示它们。作为开发人员,自助服务终端供应商为我们提供了一个有限的功能开发工具包,通过该工具包,我们可以在数据库上执行select语句并在自助服务终端上显示返回的值。
我创建了一个对象类型,如下所示:
CREATE OR REPLACE TYPE rebate_values
AS
OBJECT (ASales_total number,
ACurrent_Rebate_Percent number,
ANeeded_Sales number,
ANext_Rebate_Percent number,
BSales_total number,
BCurrent_Rebate_Percent number,
BNeeded_Sales number,
BNext_Rebate_Percent number);
我将通过客户的功能'移动获取他们的销售和折扣信息:
CREATE OR REPLACE FUNCTION AA_rebate_function (P_phone IN NUMBER)
RETURN rebate_values
IS
A_P_Sales_total NUMBER;
A_P_Current_Rebate_Percent NUMBER;
A_P_Needed_Sales NUMBER;
A_P_Next_Rebate_Percent NUMBER;
B_P_Sales_total NUMBER;
B_P_Current_Rebate_Percent NUMBER;
B_P_Needed_Sales NUMBER;
B_P_Next_Rebate_Percent NUMBER;
P_CODE VARCHAR (10);
BEGIN
SELECT CC_CODE
INTO P_CODE
FROM CUSTOMERS
WHERE C_MOBILE = P_phone;
FOR OUTDATA
IN (
--My Query to retrieve the data
Select ................
)
LOOP
IF OUTDATA.CLASS = 'X'
THEN
A_P_Sales_total := OUTDATA.SALES_TOTAL;
A_P_Current_Rebate_Percent := OUTDATA.CURRENT_REBATE_PERCENT;
A_P_Needed_Sales := OUTDATA.NEEDED_SALES_FOR_HIGHER_REBATE;
A_P_Next_Rebate_Percent := OUTDATA.NEXT_HIGHER_REBATE_PERCENT;
END IF;
IF OUTDATA.CLASS = 'Y'
THEN
B_P_Sales_total := OUTDATA.SALES_TOTAL;
B_P_Current_Rebate_Percent := OUTDATA.CURRENT_REBATE_PERCENT;
B_P_Needed_Sales := OUTDATA.NEEDED_SALES_FOR_HIGHER_REBATE;
B_P_Next_Rebate_Percent := OUTDATA.NEXT_HIGHER_REBATE_PERCENT;
END IF;
END LOOP;
RETURN rebate_values (A_P_Sales_total,
A_P_Current_Rebate_Percent,
A_P_Needed_Sales,
A_P_Next_Rebate_Percent,
B_P_Sales_total,
B_P_Current_Rebate_Percent,
B_P_Needed_Sales,
B_P_Next_Rebate_Percent);
END;
/
查询需要27秒才能检索每个客户的值。每个客户都有2行,这就是我使用LOOP收集价值的原因。
当我执行该功能时:
SELECT AA_rebate_function (XXXXXXXXXX) FROM DUAL;
我在27秒内在一个列中获得如下数据:
(XXXX, X, XXXX, X, XXXX, X, XXXX, X)
但是当我执行函数以获取不同列中的值时,需要27 x 8秒= 216秒,即大约3.6分钟,这是一个大问题,因为客户不能在服务终端上等待3.6分钟查看数据。
SELECT x.c.ASales_total,
x.c.ACurrent_Rebate_Percent,
x.c.ANeeded_Sales,
x.c.ANext_Rebate_Percent,
x.c.BSales_total,
x.c.BCurrent_Rebate_Percent,
x.c.BNeeded_Sales,
x.c.BNext_Rebate_Percent
FROM (SELECT AA_rebate_function (XXXXXXXXXX) c FROM DUAL) x;
我尝试使用带有OUT
值的存储过程,但它不适合我的环境,因为我无法编程从kiosk开发工具包执行存储过程,因为它只支持select语句,使用供应商,他们没有任何计划在不久的将来增加这种支持。
我尝试使用REGEXP_SUBSTR
将单个字段转换为多个列,但我得到了类型转换错误,因为它是一个数组。
查询非常复杂,必须计算过去10年的数据并且有数百万行,27秒实际上是获得所需结果的最佳时间。
答案 0 :(得分:0)
有趣!我没有意识到当你查询一个返回一个对象的函数时,它会为你引用该对象的每一列运行一次该函数。这很尴尬。
我能找到的最简单的解决方案是将您的功能切换为PIPELINED。您需要创建嵌套表类型才能执行此操作。
create type rebate_values_t is table of rebate_values;
/
CREATE OR REPLACE FUNCTION AA_rebate_function (P_phone IN NUMBER)
RETURN rebate_values_t PIPELINED
IS
... your code here ...
PIPE ROW (rebate_values (A_P_Sales_total,
A_P_Current_Rebate_Percent,
A_P_Needed_Sales,
A_P_Next_Rebate_Percent,
B_P_Sales_total,
B_P_Current_Rebate_Percent,
B_P_Needed_Sales,
B_P_Next_Rebate_Percent));
RETURN;
END;
/
SELECT x.ASales_total,
x.ACurrent_Rebate_Percent,
x.ANeeded_Sales,
x.ANext_Rebate_Percent,
x.BSales_total,
x.BCurrent_Rebate_Percent,
x.BNeeded_Sales,
x.BNext_Rebate_Percent
FROM TABLE(AA_rebate_function (XXXXXXXXXX)) x;
出于某种原因,这应该只执行一次,并需要27秒。