Understanding Bind Variables
Understanding Bind Variables
co.uk
Stuck in a bind…bind variables
au.fujitsu.com / www.oracledba.co.uk
Presented by
CONNOR MCDONALD
Senior Consultant
Fujitsu Consulting, Asia Pacific
Mar 2004
OracleDBA
co.uk
OracleDBA
co.uk
AVAILABLE NOW COMING SOON
Connor McDonald
April 2004 2
www.oracledba.co.uk
OracleDBA
co.uk
Which of these is cursor?
?
where VEH_ID > 1234;
declare
cursor C(p number) is
select * from NOMINAL
where nom_id = p;
begin
begin
MY_PROCEDURE(1,2,3);
for rec in C loop
end;
…
end loop;
end;
Connor McDonald
April 2004 3
www.oracledba.co.uk
OracleDBA
Answer
co.uk
All of them!
Cursors merely a handle (pointer) to an area to run database
commands
Memory
Server
Connor McDonald
April 2004 4
www.oracledba.co.uk
OracleDBA
Cursor mechanics
co.uk
All cursors have three phases
OPEN
Please allocate me some memory and return me a pointer to it
PROCESS
Process the command associated with this cursor
CLOSE
Release the memory for re-use
Connor McDonald
April 2004 5
www.oracledba.co.uk
OracleDBA
co.uk
Latching
Semaphoring operation to control access to complex memory structures
Connor McDonald
April 2004 6
www.oracledba.co.uk
OracleDBA
co.uk
Latching
Semaphoring operation to control access to complex memory structures
Connor McDonald
April 2004 7
www.oracledba.co.uk
OracleDBA
co.uk
Latching
Semaphoring operation to control access to complex memory structures
Connor McDonald
April 2004 8
www.oracledba.co.uk
OracleDBA
co.uk
Latching
Semaphoring operation to control access to complex memory structures
Get latch
1
Connor McDonald
April 2004 9
www.oracledba.co.uk
OracleDBA
co.uk
Latching
Semaphoring operation to control access to complex memory structures
Get latch 2
Operation 1
Connor McDonald
April 2004 10
www.oracledba.co.uk
OracleDBA
co.uk
Latching
Semaphoring operation to control access to complex memory structures
Get latch
Operation
Release latch
Connor McDonald
April 2004 11
www.oracledba.co.uk
OracleDBA
co.uk
Latching
Competition means someone must wait
"wait"
Connor McDonald
April 2004 12
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
open cursor
Syntax check
Semantics check
Optimization process cursor
Row source generation
Execution
Fetch
close cursor
Connor McDonald
April 2004 13
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
open cursor
Syntax check
Semantics check
Optimization process cursor
Row source generation
SQL> select *
Execution 2 frmo emp;
Fetch frmo emp
*
ERROR at line 2:
close
ORA-00923: FROM keyword not cursor
found where expected
Connor McDonald
April 2004 14
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
open cursor
Syntax check
Semantics check
Optimization process cursor
SQL> select nom_idd
Row source generation 2 from nominal;
select nom_idd
Execution *
Fetch ERROR at line 1:
ORA-00904: invalid column name
close cursor
Connor McDonald
April 2004 15
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
PLAN
open cursor
-------------------------------------
SELECT STATEMENT
Syntax check TABLE ACCESS BY INDEX ROWID NOMINAL
Semantics check INDEX RANGE SCAN NOM_PK
close cursor
Connor McDonald
April 2004 16
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
open cursor
Syntax check
Semantics check
Optimization process cursor
Row source generation
Execution
Fetch
close cursor
NOM_PK NOMINAL
Connor McDonald
April 2004 17
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
open cursor
Syntax check
Semantics check close cursor
Optimization process cursor
Row source generation
Execution
Fetch
close cursor
Connor McDonald
April 2004 18
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
open cursor
Syntax check
Semantics check close cursor
Optimization process cursor
Row source generation
Execution
Fetch
close cursor
Connor McDonald
April 2004 19
www.oracledba.co.uk
OracleDBA
Processing SQL
co.uk
What we really wanted to do
Execute
(maybe) Fetch
A lot of preliminary overhead to do this
This is PARSING
If execution times are short, parsing might be the dominant factor for
CPU consumption
Response time
Latching problems
Lookup objects definitions, privileges, synonym translation etc
Connor McDonald
April 2004 20
www.oracledba.co.uk
OracleDBA
co.uk
SQL> select name, gets
2 from v$latch
3 where name like 'library%' or name like 'shared%';
NAME GETS
------------------------------ ----------
library cache 10619
library cache pin 6271
library cache pin allocation 3204
shared pool 14321
0
----------
0
NAME GETS
------------------------------ ----------
library cache 10675 = 56
library cache pin 6288 = 17
library cache pin allocation 3216 = 12
shared pool 14363 = 42
Connor McDonald
April 2004 21
www.oracledba.co.uk
OracleDBA
Impossible to avoid?
co.uk
If I need to run 11 SQL's
surely must parse 11 times ?
Connor McDonald
April 2004 22
www.oracledba.co.uk
OracleDBA
co.uk
Memory structure
Records previously executed SQL
Optimizer information
Row source information
Reused with LRU algorithm
Exact pattern matching
Other checks still needed
Optimizer settings
Memory parameters
Synonym translation
etc
Connor McDonald
April 2004 23
www.oracledba.co.uk
OracleDBA
co.uk
Program Library Cache
Connor McDonald
April 2004 24
www.oracledba.co.uk
OracleDBA
co.uk
Likelihood of reuse appears quite low
Some queries by definition should be run the same
eg Primary key lookup
select surname, firstname from nominal where nom_id = 123
Connor McDonald
April 2004 25
www.oracledba.co.uk
OracleDBA
co.uk
Program Library Cache
Connor McDonald
April 2004 26
www.oracledba.co.uk
OracleDBA
co.uk
Will two identical statements always be shared?
No!
Resolution differences
User1: select * from nominal;
User2: select * from nominal;
Bind variable differences
Number
User1: select * from nominal where nom_id = :v1
User2: select * from nominal where nom_id = :v1
varchar2(6)
Connor McDonald
April 2004 27
www.oracledba.co.uk
OracleDBA
co.uk
Hard Soft
Parse Parse
Syntax check
Semantics check
Library cache check
Optimization
Row source generation
Execution
Fetch
Connor McDonald
April 2004 28
www.oracledba.co.uk
OracleDBA
co.uk
SQL> set timing on
SQL> declare
2 c number;
3 begin
4 c := dbms_sql.open_cursor;
5 for i in 1 .. 1000 loop Hard
6 dbms_sql.parse(c,'select * from vw_ims_crime
7 where add_id = '||i , dbms_sql.native); Parse
8 end loop;
9 dbms_sql.close_cursor(c);
10 end;
11 /
Elapsed: 00:01:31.00
SQL> declare
2 c number;
3 begin
4 c := dbms_sql.open_cursor;
5 for i in 1 .. 1000 loop
6 dbms_sql.parse(c,'select * from vw_ims_crime Soft
7 where add_id = :x' , dbms_sql.native);
8 dbms_sql.bind_variable(c,':x',i); Parse
9 end loop;
10 dbms_sql.close_cursor(c);
11 end;
12 /
Elapsed: 00:00:00.02
Connor McDonald
April 2004 29
www.oracledba.co.uk
OracleDBA
Can we do better?
co.uk
A soft parse is good but
Still does syntax, semantic check = LATCHING
Idea?
When we close a cursor,
the next time we run it, the SQL may no longer be valid – must reparse
Why not when we process a cursor
Hold onto cursor handle ("pseudo-close")
Create a local map of all cursors used so far in in this session
Whenever a cursor reused, don't even parse, just re-run
Track dependencies from cursor to objects in library cache
Issues
How to keep track of every cursor we've ever run in session?
Might run out of memory?
How to be informed when dependencies change?
Connor McDonald
April 2004 30
www.oracledba.co.uk
OracleDBA
Theoretical solution
co.uk
Process Library Cache
cursor1 object1
cursor2 object2
Program
cursor3
object3
cursor4
object4
cursor5
object5
Connor McDonald
April 2004 31
www.oracledba.co.uk
OracleDBA
Sounds hard…but
co.uk
It comes for free!!!
begin
select *
into …
from vw_ims_crime
where add_id = ln_my_plsql_variable
end;
Connor McDonald
April 2004 32
www.oracledba.co.uk
OracleDBA
co.uk
Session 1 Session 2
declare begin
cursor c_emp is select *
select * from emp; into …
begin from nominal
open c_emp; where …
fetch c_emp end;
into …;
close c_emp;
end;
open_cursors = 1000
(database setting)
Connor McDonald
April 2004 33
www.oracledba.co.uk
OracleDBA
co.uk
In its simplest form (concatenation)
High probability of HARD PARSE every time
execute immediate 'select * from nominal
where nom_id = '||my_var;
Connor McDonald
April 2004 34
www.oracledba.co.uk
OracleDBA
co.uk
No!
Recall the motivation for bind variables
Encourage sharing of nearly the same cursors in library cache
The aim is to reduce parsing overheads
If a query takes
0.5 seconds to parse
200 seconds to run
then parsing (and hence bind variables) are not the issue
Connor McDonald
April 2004 35
www.oracledba.co.uk
OracleDBA
co.uk
lc_sql := 'select nom_date_from
from nominal
where nom_id = ' || ln_nom_id
Connor McDonald
April 2004 36
www.oracledba.co.uk
OracleDBA
co.uk
lc_sql := 'select nom_date_from
from nominal
where surname = '|| lc_search_name
Connor McDonald
April 2004 37
www.oracledba.co.uk
OracleDBA
co.uk
lc_sql := 'select nom_date_from
from nominal
where current_ind = ''Y''
and nom_id = ' || ln_nom_id
Connor McDonald
April 2004 38
www.oracledba.co.uk
OracleDBA
SQL Examples
co.uk
select …
from gen_links g, ims_incident i
where g.rc_mast_table_id = 41156
and i.mast_id = i.inc_id
No changes required
41156 is a constant
never changes for this query
does not impact capacity for sharing
RC_MAST_TABLE_ID
skewed distribution
different access paths might be appropriate
Connor McDonald
April 2004 39
www.oracledba.co.uk
OracleDBA
SQL Examples
co.uk
lc_sql := 'select '||lc_snap_date_col
'from '||lc_snap_tab_name
'where '||lc_snap_col||' = :n';
Connor McDonald
April 2004 40
www.oracledba.co.uk
OracleDBA
Summary
co.uk
Use static SQL
Avoid dynamic SQL unless absolutely necessary
"Dynamically build static SQL"
For high use, fast execution SQL
Must use bind variables
Take advantage of PL/SQL cursor caching
(no SQL in triggers)
For long running, low frequency SQL
Bind variables not required
Give optimizer maximum information
Examples: searches, ad-hoc query, data warehouses etc
Connor McDonald
April 2004 41
www.oracledba.co.uk