I am currently trying to optimize a view, that wasn't written by me. It is really complex, with a lot views using function that use views and so on. So, playing around with what I can optimize I have something I can't really understand: I have this function:
create or replace FUNCTION at_get_tourenrechnungssumme_br (in_rechnr IN rechnungen.rechnr%TYPE)
RETURN NUMBER
IS
CURSOR c1 (
int_rechnr IN rechnungen.rechnr%TYPE)
IS
SELECT (ROUND (
verrechnung.get_betrag (bt.buchid, bt.betrag_euro)*(1+b.mwst/100),
2))
betrag
FROM buchungen_touren bt, v_buchkz b
WHERE bt.rechnr = int_rechnr
AND bt.storniert_jn = 0
AND bt.buchid = b.ID;
int_return NUMBER (11, 2) := 0;
BEGIN
FOR c1_rec IN c1 (in_rechnr)
LOOP
int_return := (int_return + c1_rec.betrag);
END LOOP;
RETURN NVL (int_return, 0);
END at_get_tourenrechnungssumme_br;
I just thought: loops are bad, you can do the same with sum:
create or replace FUNCTION at_get_tourenrechnungssumme_br (in_rechnr IN rechnungen.rechnr%TYPE)
RETURN NUMBER
IS
int_return NUMBER (11, 2) := 0;
BEGIN
SELECT sum(ROUND (
verrechnung.get_betrag (bt.buchid, bt.betrag_euro)*(1+b.mwst/100),
2))
betrag
into int_return
FROM buchungen_touren bt, v_buchkz b
WHERE bt.rechnr = in_rechnr
AND bt.storniert_jn = 0
AND bt.buchid = b.ID;
RETURN NVL (int_return, 0);
END at_get_tourenrechnungssumme_br;
The strange thing is, that it good actually slower, by the factor of ~2. Does sum
just don't like functions?
Can someone explain this?
Edit: This is more of an theoretical question. The obvious solution is: avoid using functions(which I mostly do, when I optimize views, someone else wrote), which I did, but I think, the question is still interesting.
The difference in run time is down to PL/SQL / SQL context switching. When embedding a PL/SQL function into a SQL statement Oracle needs to switch back and forth between the two engines. Consider this very simplistic test which nevertheless illustrates the difference.
Create a Simple Function
SQL> CREATE OR REPLACE FUNCTION test (a IN number, b in NUMBER) RETURN NUMBER
2 AS
3
4 BEGIN
5 return a+b;
6 END;
7 /
Function created.
Simple Query performing addition and aggregation in pure SQL
1 WITH
2 row_gen
3 AS (
4 SELECT LEVEL as a, level as b
5 FROM DUAL
6 CONNECT BY LEVEL < 1000000
7 )
8 SELECT SUM(a+b)
9* FROM row_gen
SQL> /
SUM(A+B)
----------
1.0000E+12
Elapsed: 00:00:00.36
Simple Query Performing Aggregation with PL/SQL function call
1 WITH
2 row_gen
3 AS (
4 SELECT LEVEL as a, level as b
5 FROM DUAL
6 CONNECT BY LEVEL < 1000000
7 )
8 SELECT SUM(test(b,b))
9* FROM row_gen
SQL> /
SUM(TEST(B,B))
--------------
1.0000E+12
Elapsed: 00:00:00.87
So the pure SQL example takes 0.36 of a second whilst the one with the SQL / PLSQL context switch takes slightly more than twice the time at 0.87 seconds.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With