- Can this function be improved for faster loading?
I made this function for calculating quantities of products per customer after deduction of a certain amount of stock in the warehouses if it exists. This function goes in a View, which is in turn used to calculate material needs by another final query, which is displayed in a page in an APEX v19.2 application.
So the page normally took 15 - 20 secs to load and by adding the function in question as well as a couple of calculations in the View, those are the sum of the warehouses with subqueries and a division of the returned amount from the function (I will post the View's query as well), it now takes a minute give or take. The function:
create or replace FUNCTION fadjust_final_order_qnt(pProd NUMBER) RETURN ADJUST_FINAL_ORDER_QNT_OBJ PIPELINED AS TYPE cus_n_prods_rec IS RECORD ( cus_id number--, --product_id number ); TYPE cus_n_prods_tbl IS TABLE OF cus_n_prods_rec; lcus_n_prods_tbl cus_n_prods_tbl; lwrh NUMBER := 0;BEGIN SELECT NVL(SUM(CASE WHEN wrh_gr > 0 THEN wrh_gr ELSE 0 END),0) + NVL(SUM(CASE WHEN wrh_bg > 0 THEN wrh_bg ELSE 0 END),0) INTO lwrh -- get warehouses FROM ( SELECT aop.product_id as prod_id, NVL((SELECT SUM(gr.balance) FROM MV_PROD_WH_GR gr, eba_products_mapping mg, eba_cust_products eg WHERE gr.fitemgid = mg.gid AND mg.product_id = eg.id AND mg.origin = 'GR' AND eg.id = ecp.id), 0) wrh_gr, NVL((SELECT SUM(bg.balance) FROM MV_PROD_WH_BG bg, eba_products_mapping mb, eba_cust_products eb WHERE bg.fitemgid = mb.gid AND mb.product_id = eb.id AND mb.origin = 'BG' AND eb.id = ecp.id), 0) wrh_bg, (SELECT epcv.descr FROM eba_prod_category_val epcv WHERE epcv.id = ecp.epc_1 AND epcv.epc_id = 1) Production FROM APT_ORDERS_PRODUCTS aop JOIN APT_ORDERS aor ON aor.id = aop.order_id JOIN eba_cust_products ecp ON aop.product_id = ecp.id JOIN eba_cust_customers ecc ON aor.cus_id = ecc.id WHERE ecc.status_id != 5 AND --aor.status_id != 24 AND aor.created_by NOT IN (4425, 239, 945, 1813, 598) AND aor.status_id NOT IN (24, 41) AND aor.invoice_number IS NULL AND aor.created >= TO_DATE('01/01/2022', 'dd/mm/yyyy') ) WHERE Production IS NOT NULL AND prod_id = pProd AND ROWNUM = 1; select distinct cus_id--, --product_id BULK COLLECT INTO lcus_n_prods_tbl -- For performance from( SELECT (Select epcv.descr from eba_prod_category_val epcv where epcv.id= ecp.epc_1 and epcv.epc_id=1 ) Production, aor.cus_id, aop.product_id FROM APT_ORDERS_PRODUCTS aop JOIN APT_ORDERS aor ON aor.id = aop.order_id JOIN eba_cust_products ecp ON aop.product_id = ecp.id JOIN eba_cust_customers ecc ON aor.cus_id = ecc.id WHERE ecc.status_id != 5 --AND aor.status_id != 24 AND aor.created_by NOT IN (4425, 239, 945, 1813, 598) AND aor.status_id NOT IN (24, 41) AND aor.invoice_number IS NULL AND aor.created >= TO_DATE('01/01/2022', 'dd/mm/yyyy') -- AND (SELECT epcv.descr FROM eba_prod_category_val epcv WHERE epcv.id = ecp.epc_1 AND epcv.epc_id = 1) IS NOT NULL ) where Production is not null AND product_id = pProd; FOR i IN 1 .. lcus_n_prods_tbl.COUNT LOOP DECLARE lamt NUMBER := 0; BEGIN FOR k IN ( SELECT SUM(quantity) qnt FROM ( SELECT aop.quantity, aop.product_id prod_id, aor.cus_id, (SELECT epcv.descr FROM eba_prod_category_val epcv WHERE epcv.id = ecp.epc_1 AND epcv.epc_id = 1) Production FROM APT_ORDERS_PRODUCTS aop JOIN APT_ORDERS aor ON aor.id = aop.order_id JOIN eba_cust_products ecp ON aop.product_id = ecp.id JOIN eba_cust_customers ecc ON aor.cus_id = ecc.id WHERE ecc.status_id != 5 AND --aor.status_id != 24 AND aor.created_by NOT IN (4425, 239, 945, 1813, 598) AND aor.status_id NOT IN (24, 41) AND aor.invoice_number IS NULL AND aor.created >= TO_DATE('01/01/2022', 'dd/mm/yyyy') --(SELECT epcv.descr FROM eba_prod_category_val epcv WHERE epcv.id = ecp.epc_1 AND epcv.epc_id = 1) IS NOT NULL AND ) WHERE Production IS NOT NULL and prod_id = pProd--lcus_n_prods_tbl(i).product_id and cus_id = lcus_n_prods_tbl(i).cus_id ) LOOP lamt := lamt + k.qnt; END LOOP; FOR j IN (select det_id, cus_id, prod_id, order_id from( SELECT aop.id det_id, aor.cus_id, aop.product_id prod_id, aor.id order_id, (SELECT epcv.descr FROM eba_prod_category_val epcv WHERE epcv.id = ecp.epc_1 AND epcv.epc_id = 1) Production FROM APT_ORDERS_PRODUCTS aop JOIN APT_ORDERS aor ON aor.id = aop.order_id JOIN eba_cust_products ecp ON aop.product_id = ecp.id JOIN eba_cust_customers ecc ON aor.cus_id = ecc.id WHERE ecc.status_id != 5 AND --aor.status_id != 24 AND aor.created_by NOT IN (4425, 239, 945, 1813, 598) AND aor.status_id NOT IN (24, 41) AND aor.invoice_number IS NULL AND aor.created >= TO_DATE('01/01/2022', 'dd/mm/yyyy') --(SELECT epcv.descr FROM eba_prod_category_val epcv WHERE epcv.id = ecp.epc_1 AND epcv.epc_id = 1) IS NOT NULL AND )where Production is not null and prod_id = pProd--lcus_n_prods_tbl(i).product_id and cus_id = lcus_n_prods_tbl(i).cus_id ) LOOP if lwrh > 0 then select decode(sign(lamt - lwrh),-1,0,lamt - lwrh),lwrh - lamt into lamt,lwrh from dual; PIPE ROW (ADJUST_FINAL_ORDER_QNT_REC(lamt, pProd/*j.prod_id*/, j.cus_id, j.det_id)); else PIPE ROW (ADJUST_FINAL_ORDER_QNT_REC(lamt, pProd/*j.prod_id*/, j.cus_id, j.det_id)); end if; END LOOP; END; END LOOP; RETURN;END;
The View query:
select sum_qnt, code, prod_id, description, wrh_gr, wrh_bg, (select Amt from Table(fadjust_final_order_qnt(prod_id))where Prd = prod_id and Cus = cus_id and Id = det_id )/count(prod_id)over(partition by prod_id,cus_id) final_order_quantity, cat_id, cus_id, order_idfrom ( select sum(quantity) sum_qnt, code , prod_id, case when wrh_gr <= 0 then 0 when wrh_gr is null then 0 else wrh_gr end wrh_gr_v, case when wrh_bg <= 0 then 0 else wrh_bg end wrh_bg_v , nvl(wrh_gr,0) wrh_gr, nvl(wrh_bg,0) wrh_bg, description, cus_id, order_id, cat_id, det_id from ( SELECT aop.id det_id, aor.id order_id, ecp.product_name code, nvl(ecp.global_descr, ecp.description) description, aop.quantity quantity, (Select epcv.descr from eba_prod_category_val epcv where epcv.id= ecp.epc_1 and epcv.epc_id=1 ) Production , (select sum(gr.balance) from MV_PROD_WH_GR gr, eba_products_mapping mg , eba_cust_products eg where gr.fitemgid = mg.gid and mg.product_id = eg.id and mg.origin = 'GR' and eg.id =ecp.id ) wrh_gr, (select sum(bg.balance) from MV_PROD_WH_BG bg, eba_products_mapping mb , eba_cust_products eb where bg.fitemgid = mb.gid and mb.product_id = eb.id and mb.origin = 'BG' and eb.id =ecp.id ) wrh_bg, aop.product_id as prod_id, aor.cus_id cus_id, ecp.prod_cat_id cat_id FROM APT_ORDERS_PRODUCTS aop , APT_ORDERS aor, eba_cust_products ecp, eba_cust_customers ecc WHERE AOR.ID = AOP.ORDER_ID and aor.cus_id = ecc.id and ecc.status_id != 5 and aop.product_id = ecp.id and aor.status_id!=24 and aor.created_by not in (4425,239,945,1813,598) and aor.status_id not in (24,41) and aor.invoice_number is null and aor.created >= to_date('01/01/2022','dd/mm/yyyy') )where Production is not null group by code, wrh_gr, wrh_bg, description, prod_id, cat_id, cus_id, order_id, det_id )
I managed to improve it by adding Bulk Collect Into and by reducing Select Into clauses as much as possible. I also created some more indexes for the columns used in the Where clause of the queries. Pagination didn't work in the Interactive Report in APEX page, although I didn't believe it would do anything I gave it a try.
With all the above I gained 5 - 10 seconds.