Given the following table
create table tmp_test as
select mod(level, 5) as n
from dual
connect by level <= 10
;
and this function
create or replace function test_deterministic (Pn in number
) return number deterministic is
begin
dbms_output.put_line(Pn);
dbms_lock.sleep(1);
return Pn;
end;
It executes 6 times, taking 6 seconds:
SQL> select test_deterministic(n) from tmp_test;
TEST_DETERMINISTIC(N)
---------------------
1
2
3
4
0
1
2
3
4
0
10 rows selected.
1
2
3
4
0
1
Elapsed: 00:00:06.02
I would have expected this to execute 5 times. If I run this SELECT statement in SQL Developer or PL/SQL Developer it only executes 5 times. Equally, if I run this in Pl/SQL it executes 5 times:
SQL> begin
2 for i in ( select test_deterministic(n) from tmp_test ) loop
3 null;
4 end loop;
5 end;
6 /
1
2
3
4
0
Elapsed: 00:00:05.01
Why is this function executed 6 times when called in SQL from SQL*Plus? I expected it to execute 5 times instead.
I'm on version 11.2.0.3.5 and the SQL*Plus client is release 11.2.0.1.0 (64bit).
SQL functions in SQLite can be either "deterministic" or "non-deterministic". A deterministic function always gives the same answer when it has the same inputs. Most built-in SQL functions in SQLite are deterministic. For example, the abs(X) function always returns the same answer as long as its input X is the same.
Nondeterministic functions may return different results each time they're called with a specific set of input values even if the database state that they access remains the same.
Deterministic functions : Deterministic functions always result in the same output every time they are called with a fixed set of input values and given the same condition of the database.
From mysql : 'A routine is considered “deterministic” if it always produces the same result for the same input parameters, and “not deterministic” otherwise. ' Definitions of 'deterministic function' from other sources also have "always returns the same result for same parameters".
Blame SQL*Plus, Ben. Your function works, in this situation, correctly. The extra value(1
) you see is there because of arraysize
value, and, mostly because of the way how SQL*Plus fetches rows. It first fetches first row and only then it starts to use arraysize
for subsequent fetches. Every new fetch is a new database call, which forces your deterministic function to be evaluated. Try to set the arraysize
to 1 or 2(same effect) and execute your select
statement. The first row returns, and then, arraysize
comes to play and each subsequent fetch will return couple of rows:
Arraysize
is set to 1(two in fact)
SQL> set arraysize 1;
SQL> select test_deterministic(n) from tmp_test;
TEST_DETERMINISTIC(N)
---------------------
1
2
3
4
0
1
2
3
4
0
10 rows selected.
1
2
3
4
0
1
2
3
4
0
Elapsed: 00:00:10.10
The same query with much larger arraysize
:
SQL> set arraysize 50;
SQL> select test_deterministic(n) from tmp_test;
TEST_DETERMINISTIC(N)
---------------------
1
2
3
4
0
1
2
3
4
0
10 rows selected.
1
2
3
4
0
1
Elapsed: 00:00:06.06
SQL> spool off;
Any other client, whether it's SQL Developer or PL/SQL Developer lacks such behavior and gives correct output.
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