SQL 游标需要很长时间才能完成

问题描述 投票:0回答:1
DECLARE
  orderid NUMBER;
  customerid NUMBER;
  channel VARCHAR2(20);
  amount NUMBER;

  CURSOR orders_cursor IS
    SELECT
      order_id,
      customer_id,
      channel,
      FINAL_PROFIT(order_id) AS amount
    FROM temp_orders
     FOR UPDATE ;
BEGIN
  OPEN orders_cursor;
    LOOP
    FETCH orders_cursor INTO orderid, customerid, channel, amount;
    EXIT WHEN orders_cursor%NOTFOUND;

    IF amount < 0 THEN
      INSERT INTO deficit (orderid, customerid, channel, amount)
        VALUES (orderid, customerid, channel, -amount);
    ELSE
      INSERT INTO profit (orderid, customerid, channel, amount)
        VALUES (orderid, customerid, channel, amount);
    END IF;
  END LOOP;
  CLOSE orders_cursor;
END;

我有一个游标,它从函数 FINAL_PROFIT 中获取 order_id、customer_id、channel 和一个值,然后检查金额是正数还是负数并将其放入右侧表中。游标可以工作,但需要很长时间才能完成(30+分钟)。我需要它更快。 这是FINAL_PROFIT函数

create or replace FUNCTION FINAL_PROFIT (o_id NUMBER)
RETURN NUMBER 
IS  
    f_profit FLOAT := 0;
    v_delay NUMBER := 0;
BEGIN
    v_delay := MAX_DELAY(o_id);

    SELECT SUM(o.price - o.cost - (v_delay * (0.001 * TO_NUMBER(p.list_price,'9999.99')))) as FINAL_PROFT
    INTO f_profit  
    FROM ORDERS o 
    JOIN PRODUCTS p ON o.product_id = p.product_id 
    WHERE o_id = o.order_id
    GROUP BY o_id ;
    
    RETURN f_profit;  
END FINAL_PROFIT;

我尝试更新,因为我想让它更快,但我没有注意到时间上有任何差异

sql optimization plsql oracle-sqldeveloper database-cursor
1个回答
0
投票

您很少会遇到需要在循环内运行 SQL 的情况,因此您几乎可以制定一条规则,如果您发现自己在想“我可以在循环中运行此 SQL”,那么您可以立即想到“所以我一定是想错了”。

相反,两个插入语句将处理这个问题:

INSERT INTO deficit (orderid, customerid, channel, amount)
SELECT
  order_id,
  customer_id,
  channel,
  FINAL_PROFIT(order_id) * -1 AS amount
FROM temp_orders
WHERE amount < 0;

INSERT INTO deficit (orderid, customerid, channel, amount)
SELECT
  order_id,
  customer_id,
  channel,
  FINAL_PROFIT(order_id) AS amount
FROM temp_orders
WHERE amount >= 0

该函数也可以更改为 SQL 的一部分,这样您就不会一次又一次地调用 sql 函数。

© www.soinside.com 2019 - 2024. All rights reserved.