60. delete from MY_TABLE;
drop table MY_TABLE;
select *
from
EMPLOYEE
where EMPNO > 1234;
cursors
declare
cursor C(p number) is
select * from DEPT
where DEPTNO = p;
begin
for rec in C loop
…
end loop;
end;
begin
MY_PROCEDURE(1,2,3);
end;
86. can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
spinning
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
can I have the latch ?
86
112. SQL> select name, gets
2 from v$latch
3 where name like 'library%' or name like 'shared%';
NAME
GETS
------------------------------ ---------shared pool
333937
library cache load lock
0
shared pool simulator
7191
shared pool sim alloc
133
shared server configuration
6
shared server info
1
113. SQL> select name, gets
2 from v$latch
3 where name like 'library%' or name like 'shared%';
NAME
GETS
------------------------------ ---------shared pool
333937
library cache load lock
0
shared pool simulator
7191
shared pool sim alloc
133
shared server configuration
6
shared server info
1
SQL> select 0 from dual;
0
---------0
114. SQL> select name, gets
2 from v$latch
3 where name like 'library%' or name like 'shared%';
NAME
GETS
------------------------------ ---------shared pool
333937
library cache load lock
0
shared pool simulator
7191
shared pool sim alloc
133
shared server configuration
6
shared server info
1
GETS
---------333991
0
7196
135
6
1
= 54
= 5
= 2
SQL> select 0 from dual;
0
---------0
total = 945 !
123. parse this...
select surname, firstname from emp where empno = ?
binding
now run it with ? = 7362
now run it with ? = 123
124. library
cache
select surname, firstname from emp where empno = ?
select * from dept where deptno = ?
select * from customer where locality = ?
select prno from property where reference = ?
select * from dept where deptno = ?
select surname, firstname from emp where empno = ?
select * from customer where locality = ?
select * from organisation where officer = ?
select surname, firstname from emp where empno = ?
select * from dept where deptno = ?
select offender from crimes where crno = ?
125. library
cache
select surname, firstname from emp where empno = ?
select * from dept where deptno = ?
select * from customer where locality = ?
select prno from property where reference = ?
select * from dept where deptno = ?
select surname, firstname from emp where empno = ?
select * from customer where locality = ?
select * from organisation where officer = ?
select surname, firstname from emp where empno = ?
select * from dept where deptno = ?
select offender from crimes where crno = ?
Five full parses avoided
129. SQL> declare
2
c number := dbms_sql.open_cursor;
3 begin
4
for i in 1 .. 10000 loop
5
dbms_sql.parse(c,'
6
select * from dba_objects o, dba_segments s
7
where object_id = '||i||'
8
and o.owner = s.owner
9
and o.object_name = s.segment_name' ,
10
dbms_sql.native);
12
end loop;
12
dbms_sql.close_cursor(c);
13 end;
more complex = more parsing
Elapsed: 00:36:07.71
we aren’t even running the thing !
160. procedure MY_PROC is
begin
select *
into
…
from
dept
where …
end;
procedure MY_PROC is
cursor c_emp is
select * from emp;
begin
open c_emp;
fetch c_emp
into …;
close c_emp;
end;
select * from dept …
161. procedure MY_PROC is
begin
select *
into
…
from
dept
where …
end;
procedure MY_PROC is
cursor c_emp is
select * from emp;
begin
open c_emp;
fetch c_emp
into …;
close c_emp;
end;
select * from dept …
select * from emp
162. the future looks bleak
Statement s = "select * from emp where empno = " + nEmpno
218. "give me a row"
• Get latch
• Search along list of blocks in
memory (or "chain")
• Read block
• Extract row of interest
• Release latch
• Give row back to client
218
223. •
•
•
•
•
•
Get latch
Walk along chain
Get block
Extract single row
Release latch
Give row back to client
Row #1
OPEN c_emp_list
LOOP
FETCH c_emp_list INTO ...
insert into EMP_COPY
( . . . )
values
( . . . );
END LOOP;
223
224. •
•
•
•
•
•
OPEN c_emp_list
LOOP
FETCH c_emp_list INTO ...
insert into EMP_COPY
( . . . )
values
( . . . );
Get latch
Walk along chain
Get block
Extract single row
Release latch
Give row back to client
Row #1
•
•
•
•
•
•
Get latch (again)
Walk along chain (again)
Get block (again)
Extract single row
Release latch (again)
Give row back to client (again)
Row #2
END LOOP;
224
225. •
•
•
•
•
•
OPEN c_emp_list
LOOP
FETCH c_emp_list INTO ...
insert into EMP_COPY
( . . . )
values
( . . . );
END LOOP;
Get latch
Walk along chain
Get block
Extract single row
Release latch
Give row back to client
Row #1
•
•
•
•
•
•
Get latch (again)
Walk along chain (again)
Get block (again)
Extract single row
Release latch (again)
Give row back to client (again)
Row #2
•
•
•
•
•
•
Get latch (again)
Walk along chain (again)
Get block (again)
Extract single row
Release latch (again)
Give row back to client (again)
Row #3
etc
etc
etc
225
228. "give me a row"
“by the way, I’ll
be wanting
several rows
from this block”
229. "give me a row"
“by the way, I’ll
be wanting
several rows
from this block”
•
•
•
•
•
•
•
•
•
•
•
•
Get latch
Walk along chain
Get block
Pin the block
Release latch
Give row 1 back to client
Give row 2 back to client
…
Give row n to client
Get latch
Walk along chain
Remove my pin on the block
Release latch
241. SQL>
2
3
4
5
6
7
8
9
10
11
12
13
declare
cursor c is
select empno, hiredate
from
big_emp;
type c_list is table of c%rowtype;
r c_list;
begin
open c;
fetch c
bulk collect into r;
close c;
end;
/
PL/SQL procedure successfully completed.
Elapsed: 00:00:10.02
245. SQL> select * from v$mystats
2 where name like '%pga%'
3 /
NAME
VALUE
------------------------------ ---------session pga memory
101534672
session pga memory max
101534672
252. SQL> begin
2
for i in 1 .. 50000 loop
3
insert into t1 values ( i );
4
end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:11.03
252
253. SQL>
2
3
4
5
6
7
8
9
10
11
12
declare
type num_list is table of number;
n num_list := num_list();
begin
n.extend(50000);
for i in 1 .. 50000 loop
n(i) := i;
end loop;
forall i in 1 .. 50000
insert into t1 values ( n(i) );
end;
/
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.76
256. SQL> insert into T
2 select owner, object_name
insert into T
3 from
all_objects
select owner, object_name
4 all_objects rownum <= 10000;
where
from
where
rownum <= 10000
call
cpu
elapsed
10000 count ------- ---------rows created.
------- -----Parse
1
Execute
1
Fetch
0
------- -----total
2
disk
query
current
-------- --------- ---------0
0
0
88
123
10642
0
0
0
-------- --------- ---------88
123
10642
rows
---------0
10000
0
---------10000
cpu
elapsed
disk
query
current
------- ---------- -------- --------- ---------0.00
0.00
0
0
0
0.79
0.97
2
109
10845
0.00
0.00
0
0
0
------- ---------- -------- --------- ---------0.79
0.97
2
109
10845
rows
---------0
10000
0
---------10000
0.01
0.00
3.10
3.05
0.00
0.00
------- ---------3.12
3.06
INSERT INTO T_AUDIT
VALUES (SYSDATE ,:B3 ,:B1 ,:B2 )
call
count
------- -----Parse
1
Execute 10000
Fetch
0
------- -----total
10001
213
257. create or replace
package T_PKG is
type each_row is record ( action varchar2(1),
owner varchar2(30),
object_name varchar2(30)
);
type row_list is table of each_row
index by pls_integer;
g
row_list;
end;
/
214
257
261. create or replace
trigger AUDIT_TRG2
after insert or update or delete on T
for each row
begin
if updating or inserting then
t_pkg.g(t_pkg.g.count+1).owner
t_pkg.g(t_pkg.g.count).object_name
else
t_pkg.g(t_pkg.g.count).owner
t_pkg.g(t_pkg.g.count).object_name
end if;
end;
/
:= :new.owner;
:= :new.object_name;
:= :old.owner;
:= :old.object_name;
216
263. create or replace
trigger AUDIT_TRG3
after insert or update or delete on T
declare
v_action varchar2(1) :=
case when updating then 'U'
when deleting then 'D'
else 'I' end;
begin
forall i in 1 .. t_pkg.g.count
insert into T_AUDIT
values (
sysdate,
v_action,
t_pkg.g(i).owner,
t_pkg.g(i).object_name);
t_pkg.g.delete;
end;
/
217
271. SQL> set autotrace traceonly stat
SQL> set arraysize 100
SQL> select object_type
2 from
T;
89405 rows selected.
Statistics
--------------------------------------------4 recursive calls
0 db block gets
2452 consistent gets
0 physical reads
0 redo size
1198478 bytes sent via SQL*Net to client
271
272. SQL> select object_type
2 from
T
3 order by object_type;
89405 rows selected.
Statistics
-------------------------------------------14 recursive calls
0 db block gets
1507 consistent gets
0 physical reads
0 redo size
618820 bytes sent via SQL*Net to client
291. create or replace
trigger PROD_MAN_CHECK
before insert or update on PRODUCT
for each row
declare
l_man_id number;
begin
select man_id
into
l_man_id
from
manufacturer
where man_id = :new.man_id;
exception
when no_data_found then
raise_application_error(-20000,
'Manufacturer is not valid');
end;
292. create or replace
trigger MAN_PROD_CHECK
before delete on MANUFACTURERS
for each row
declare
l_prd_cnt number;
begin
select count(*)
into
l_prd_cnt
from
product
where prd_id = :old.prd_id;
if l_prd_cnt > 0 then
raise_application_error(-20001,
'Manufacturer in use by product records');
end if;
end;
294. SQL> insert into PRODUCT (...,MAN_ID,...)
2 values (...,100, ...);
1 row created.
SQL> insert into PRODUCT (...,MAN_ID,...)
2 values (...,101,...);
ERROR at line 1:
ORA-20000: Manufacturer is not valid
SQL> delete from MANUFACTURER
2 where man_id = 5768;
ERROR at line 1:
ORA-20001: Manufacturer in use by product records
299. delete MAN=7
Trigger fires
- any PRD with MAN=7
- "No" (not yet)
- OK
commit
Time
create PRD with MAN=7
Trigger fires
- does MAN=7 exist?
- "Yes"
- OK
commit
303. beware the module spec
"When creating a product...
validate registration date – ensure not in the future,
validate …
validate …
validate manufacturer ID – must exist in Manufacturer table"
321. SQL> create table T ( processed date );
Table created.
SQL>
2
3
4
5
6
7
8
9
insert into T
select
case when mod(rownum,20) != 0 then
to_date('01-JAN-11')+rownum/10
else
null
end
from dual
connect by level <= 10000;
10000 rows created.
321
322. SQL> select min(processed), max(processed), count(*)
2 from t;
MIN(PROCE MAX(PROCE
COUNT(*)
--------- --------- ---------01-JAN-11 26-SEP-13
10000
10 rows per day
across ~3 years
322
323. SQL> select *
2 from
T
3 where processed between
4
'01-JUN-13' and '01-JUL-13';
-------------------------------------------| Id | Operation
| Name | Rows |
-------------------------------------------|
0 | SELECT STATEMENT
|
|
287 |
|* 1 | FILTER
|
|
|
|* 2 |
TABLE ACCESS FULL| T
|
287 |
--------------------------------------------
323
324. SQL> select *
2 from
T
3 where processed between
4
'01-JUN-13' and '01-JUL-13';
-------------------------------------------| Id | Operation
| Name | Rows |
-------------------------------------------|
0 | SELECT STATEMENT
|
|
287 |
|* 1 | FILTER
|
|
|
|* 2 |
TABLE ACCESS FULL| T
|
287 |
--------------------------------------------
reality = 285
324