I've heard that using bind variables is (can be) more efficient, because for subsequent calls with a different bind value, the query itself is still the same, so it doesn't need to be parsed anymore.
I understand why this is the case for fixed values. In the cursor below, the value is fixed on 1. If I have a different cursor that is the same, except the 1 becomes 2, it is a diffent query. Clear so far.
declare
cursor C_CURSOR is
select * from TESTTABLE pt where pt.ID = 1;
But I wondered if this is also the case when using PL/SQL variables inside the cursor. Are they expanded as if it's a fixed value, or are they interpreted as bind variables.
I've searched far and wide, but everywhere I find examples about literals, as in the case above, but no clear explanation about the use of PL/SQL variables.
In other words, of the two snippets below, is the second one potentially more efficient, or are they essentially the same?
With a PL/SQL variable directly in the cursor:
declare
V_TEST integer := 1;
cursor C_CURSOR is
select *
from
TESTTABLE pt
where
pt.ID = V_TEST;
begin
for r in C_CURSOR loop
null;
end loop;
end;
With a bind variable:
declare
V_TEST int := 1;
cursor C_CURSOR(B_TEST int) is
select *
from
TESTTABLE pt
where
pt.ID = B_TEST;
begin
for r in C_CURSOR(V_TEST) loop
null;
end loop;
end;
First of all, good question.
I would like to make a small quote:
Every reference to a PL/SQL variable is in fact a bind variable.
Having said that,
PL/SQL itself takes care of most of the issues to do with bind variables, to the point where most code that you write already uses bind variables without you knowing. Take, for example, the following bit of PL/SQL:
create or replace procedure dsal(p_empno in number)
as
begin
update emp
set sal=sal*2
where empno = p_empno;
commit;
end;
/
Now you might be thinking that you've got to replace the p_empno with a bind variable. However, the good news is that every reference to a PL/SQL variable is in fact a bind variable.
Source
Reading the fine manual: PL/SQL Static SQL
A PL/SQL static SQL statement can have a PL/SQL identifier wherever its SQL counterpart can have a placeholder for a bind variable. The PL/SQL identifier must identify either a variable or a formal parameter.
Both of your example snippets are equivalent from SQL engine point of view and perform equally well.
Reading more the same fine manual:
Generally, PL/SQL parses an explicit cursor only the first time the session opens it and parses a SQL statement (creating an implicit cursor) only the first time the statement runs.
All parsed SQL statements are cached. A SQL statement is reparsed only if it is aged out of the cache by a new SQL statement. Although you must close an explicit cursor before you can reopen it, PL/SQL need not reparse the associated query. If you close and immediately reopen an explicit cursor, PL/SQL does not reparse the associated query.
So changing the bind variable requires no SQL statement parsing.
From code readability (i.e. maintenance) point of view the second snippet that is using parameters is superior. It's not obvious in small snippets but in large PL/SQL programs it's a headache if cursors directly use package or subroutine variables. When reading code one needs every time check what is the state the cursor depends on. With cursor parameters one sees that immediatelly.